From: Sasha Levin Date: Mon, 18 May 2026 11:51:28 +0000 (-0400) Subject: Fixes for all trees X-Git-Tag: v6.6.141~73 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=90b037e9e9cda63e8f8eb90eeef46eeb8badcea5;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/6pack-propagage-new-tty-types.patch b/queue-5.10/6pack-propagage-new-tty-types.patch new file mode 100644 index 0000000000..ddc0ae6f1e --- /dev/null +++ b/queue-5.10/6pack-propagage-new-tty-types.patch @@ -0,0 +1,136 @@ +From 781aa33365451ea0de0210ea6409fb57f4c87d80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 12:35:47 +0200 +Subject: 6pack: propagage new tty types + +From: Jiri Slaby (SUSE) + +[ Upstream commit 1241b384efa53f4b7a95fe2b34d69359bb3ae1b5 ] + +In tty, u8 is now used for data, ssize_t for sizes (with possible +negative error codes). Propagate these types to 6pack. + +Signed-off-by: Jiri Slaby (SUSE) +Cc: Greg Kroah-Hartman +Cc: Andreas Koensgen +Cc: David S. Miller +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: linux-hams@vger.kernel.org +Cc: netdev@vger.kernel.org +Reviewed-by: Jeremy Kerr +Link: https://lore.kernel.org/r/20240808103549.429349-12-jirislaby@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bf9a38803b26 ("net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf") +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 83dc1c2c3b84b..1964ccbb62c6f 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -94,8 +94,8 @@ struct sixpack { + unsigned char *xhead; /* next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + +- unsigned char raw_buf[4]; +- unsigned char cooked_buf[400]; ++ u8 raw_buf[4]; ++ u8 cooked_buf[400]; + + unsigned int rx_count; + unsigned int rx_count_cooked; +@@ -112,8 +112,8 @@ struct sixpack { + unsigned char slottime; + unsigned char duplex; + unsigned char led_state; +- unsigned char status; +- unsigned char status1; ++ u8 status; ++ u8 status1; + unsigned char status2; + unsigned char tx_enable; + unsigned char tnc_state; +@@ -127,7 +127,7 @@ struct sixpack { + + #define AX25_6PACK_HEADER_LEN 0 + +-static void sixpack_decode(struct sixpack *, const unsigned char[], int); ++static void sixpack_decode(struct sixpack *, const u8 *, size_t); + static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); + + /* +@@ -337,7 +337,7 @@ static void sp_bump(struct sixpack *sp, char cmd) + { + struct sk_buff *skb; + int count; +- unsigned char *ptr; ++ u8 *ptr; + + count = sp->rcount + 1; + +@@ -435,7 +435,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) + { + struct sixpack *sp; +- int count1; ++ size_t count1; + + if (!count) + return; +@@ -830,9 +830,9 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, + + /* decode 4 sixpack-encoded bytes into 3 data bytes */ + +-static void decode_data(struct sixpack *sp, unsigned char inbyte) ++static void decode_data(struct sixpack *sp, u8 inbyte) + { +- unsigned char *buf; ++ u8 *buf; + + if (sp->rx_count != 3) { + sp->raw_buf[sp->rx_count++] = inbyte; +@@ -858,9 +858,9 @@ static void decode_data(struct sixpack *sp, unsigned char inbyte) + + /* identify and execute a 6pack priority command byte */ + +-static void decode_prio_command(struct sixpack *sp, unsigned char cmd) ++static void decode_prio_command(struct sixpack *sp, u8 cmd) + { +- int actual; ++ ssize_t actual; + + if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ + +@@ -908,9 +908,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd) + + /* identify and execute a standard 6pack command byte */ + +-static void decode_std_command(struct sixpack *sp, unsigned char cmd) ++static void decode_std_command(struct sixpack *sp, u8 cmd) + { +- unsigned char checksum = 0, rest = 0; ++ u8 checksum = 0, rest = 0; + short i; + + switch (cmd & SIXP_CMD_MASK) { /* normal command */ +@@ -956,10 +956,10 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd) + /* decode a 6pack packet */ + + static void +-sixpack_decode(struct sixpack *sp, const unsigned char *pre_rbuff, int count) ++sixpack_decode(struct sixpack *sp, const u8 *pre_rbuff, size_t count) + { +- unsigned char inbyte; +- int count1; ++ size_t count1; ++ u8 inbyte; + + for (count1 = 0; count1 < count; count1++) { + inbyte = pre_rbuff[count1]; +-- +2.53.0 + diff --git a/queue-5.10/alsa-compress-drop-unused-functions.patch b/queue-5.10/alsa-compress-drop-unused-functions.patch new file mode 100644 index 0000000000..dfd8a2ed4a --- /dev/null +++ b/queue-5.10/alsa-compress-drop-unused-functions.patch @@ -0,0 +1,126 @@ +From ee7f8e5821ae37f151707a2b17c8756f5a356750 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Jul 2021 18:24:23 +0200 +Subject: ALSA: compress: Drop unused functions + +From: Takashi Iwai + +[ Upstream commit fc93c96fe34e10b873fef73e80cee52503f3a679 ] + +snd_compress_register() and snd_compress_deregister() API functions +have been never used by in-tree drivers. +Let's clean up the dead code. + +Acked-by: Vinod Koul +Reviewed-by: Peter Ujfalusi +Link: https://lore.kernel.org/r/20210714162424.4412-2-tiwai@suse.de +Signed-off-by: Takashi Iwai +Stable-dep-of: 796e119e9b14 ("ALSA: core: Validate compress device numbers without dynamic minors") +Signed-off-by: Sasha Levin +--- + include/sound/compress_driver.h | 2 - + sound/core/compress_offload.c | 68 --------------------------------- + 2 files changed, 70 deletions(-) + +diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h +index 70cbc5095e725..c74bf9931fb33 100644 +--- a/include/sound/compress_driver.h ++++ b/include/sound/compress_driver.h +@@ -161,8 +161,6 @@ struct snd_compr { + }; + + /* compress device register APIs */ +-int snd_compress_register(struct snd_compr *device); +-int snd_compress_deregister(struct snd_compr *device); + int snd_compress_new(struct snd_card *card, int device, + int type, const char *id, struct snd_compr *compr); + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index c1fec932c49d1..8d1f71a621787 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -47,8 +47,6 @@ + * driver should be able to register multiple nodes + */ + +-static DEFINE_MUTEX(device_mutex); +- + struct snd_compr_file { + unsigned long caps; + struct snd_compr_stream stream; +@@ -1170,72 +1168,6 @@ int snd_compress_new(struct snd_card *card, int device, + } + EXPORT_SYMBOL_GPL(snd_compress_new); + +-static int snd_compress_add_device(struct snd_compr *device) +-{ +- int ret; +- +- if (!device->card) +- return -EINVAL; +- +- /* register the card */ +- ret = snd_card_register(device->card); +- if (ret) +- goto out; +- return 0; +- +-out: +- pr_err("failed with %d\n", ret); +- return ret; +- +-} +- +-static int snd_compress_remove_device(struct snd_compr *device) +-{ +- return snd_card_free(device->card); +-} +- +-/** +- * snd_compress_register - register compressed device +- * +- * @device: compressed device to register +- */ +-int snd_compress_register(struct snd_compr *device) +-{ +- int retval; +- +- if (device->name == NULL || device->ops == NULL) +- return -EINVAL; +- +- pr_debug("Registering compressed device %s\n", device->name); +- if (snd_BUG_ON(!device->ops->open)) +- return -EINVAL; +- if (snd_BUG_ON(!device->ops->free)) +- return -EINVAL; +- if (snd_BUG_ON(!device->ops->set_params)) +- return -EINVAL; +- if (snd_BUG_ON(!device->ops->trigger)) +- return -EINVAL; +- +- mutex_init(&device->lock); +- +- /* register a compressed card */ +- mutex_lock(&device_mutex); +- retval = snd_compress_add_device(device); +- mutex_unlock(&device_mutex); +- return retval; +-} +-EXPORT_SYMBOL_GPL(snd_compress_register); +- +-int snd_compress_deregister(struct snd_compr *device) +-{ +- pr_debug("Removing compressed device %s\n", device->name); +- mutex_lock(&device_mutex); +- snd_compress_remove_device(device); +- mutex_unlock(&device_mutex); +- return 0; +-} +-EXPORT_SYMBOL_GPL(snd_compress_deregister); +- + MODULE_DESCRIPTION("ALSA Compressed offload framework"); + MODULE_AUTHOR("Vinod Koul "); + MODULE_LICENSE("GPL v2"); +-- +2.53.0 + diff --git a/queue-5.10/alsa-core-validate-compress-device-numbers-without-d.patch b/queue-5.10/alsa-core-validate-compress-device-numbers-without-d.patch new file mode 100644 index 0000000000..d65a647824 --- /dev/null +++ b/queue-5.10/alsa-core-validate-compress-device-numbers-without-d.patch @@ -0,0 +1,81 @@ +From 432c883278935d6a6feadcf7bbfcde967c4f4015 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 02:24:04 -0300 +Subject: ALSA: core: Validate compress device numbers without dynamic minors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 796e119e9b14763be905ad0d023c71a14bc2e931 ] + +Without CONFIG_SND_DYNAMIC_MINORS, ALSA reserves only two fixed minors +for compress devices on each card: comprD0 and comprD1. + +snd_find_free_minor() currently computes the compress minor as +type + dev without validating dev first, so device numbers greater than +1 spill into the HWDEP minor range instead of failing registration. + +ASoC passes rtd->id to snd_compress_new(), so this can happen on real +non-dynamic-minor builds. + +Add a dedicated fixed-minor check for SNDRV_DEVICE_TYPE_COMPRESS in +snd_find_free_minor() and reject out-of-range device numbers with +-EINVAL before constructing the minor. + +Also remove the stale TODO in compress_offload.c that still claims +multiple compress nodes are missing. + +Fixes: 3eafc959b32f ("ALSA: core: add support for compressed devices") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-alsa-compress-static-minors-v1-1-0628573bee1c@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 7 ------- + sound/core/sound.c | 7 +++++++ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 8d1f71a621787..222ea652edf37 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -40,13 +40,6 @@ + #define COMPR_CODEC_CAPS_OVERFLOW + #endif + +-/* TODO: +- * - add substream support for multiple devices in case of +- * SND_DYNAMIC_MINORS is not used +- * - Multiple node representation +- * driver should be able to register multiple nodes +- */ +- + struct snd_compr_file { + unsigned long caps; + struct snd_compr_stream stream; +diff --git a/sound/core/sound.c b/sound/core/sound.c +index b75f78f2c4b8e..93266542e318b 100644 +--- a/sound/core/sound.c ++++ b/sound/core/sound.c +@@ -213,9 +213,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev) + case SNDRV_DEVICE_TYPE_RAWMIDI: + case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: + case SNDRV_DEVICE_TYPE_PCM_CAPTURE: ++ if (snd_BUG_ON(!card)) ++ return -EINVAL; ++ minor = SNDRV_MINOR(card->number, type + dev); ++ break; + case SNDRV_DEVICE_TYPE_COMPRESS: + if (snd_BUG_ON(!card)) + return -EINVAL; ++ if (dev < 0 || ++ dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS) ++ return -EINVAL; + minor = SNDRV_MINOR(card->number, type + dev); + break; + default: +-- +2.53.0 + diff --git a/queue-5.10/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch b/queue-5.10/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch new file mode 100644 index 0000000000..905c81f32f --- /dev/null +++ b/queue-5.10/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch @@ -0,0 +1,45 @@ +From 550e727986b97e37af3436fe973cc212e405abdc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 15:54:05 +0800 +Subject: ALSA: hda/realtek: fix code style (ERROR: else should follow close + brace '}') + +From: Lei Huang + +[ Upstream commit d1888bf848ade6a9e71c7ba516fd215aa1bd8d65 ] + +Fix checkpatch code style errors: + + ERROR: else should follow close brace '}' + #2300: FILE: sound/hda/codecs/realtek/alc269.c:2300: + + } + + else + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Lei Huang +Link: https://patch.msgid.link/20260331075405.78148-1-huanglei814@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 4eddc032b3d9a..31cf426f026c9 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -5954,9 +5954,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } +- else ++ } else { + alc_fixup_headset_mode(codec, fix, action); ++ } + } + + static void alc288_update_headset_jack_cb(struct hda_codec *codec, +-- +2.53.0 + diff --git a/queue-5.10/alsa-hda-realtek-whitespace-fix.patch b/queue-5.10/alsa-hda-realtek-whitespace-fix.patch new file mode 100644 index 0000000000..58ea1ee152 --- /dev/null +++ b/queue-5.10/alsa-hda-realtek-whitespace-fix.patch @@ -0,0 +1,37 @@ +From 66d81470882215ce59d687f6c617d25f273eb4c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jul 2023 16:46:19 +1200 +Subject: ALSA: hda/realtek: Whitespace fix + +From: Luke D. Jones + +[ Upstream commit 72cea3a3175b50a4875b3c112fb13df20c6218a5 ] + +Remove an erroneous whitespace. + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Luke D. Jones +Link: https://lore.kernel.org/r/20230704044619.19343-6-luke@ljones.dev +Signed-off-by: Takashi Iwai +Stable-dep-of: d1888bf848ad ("ALSA: hda/realtek: fix code style (ERROR: else should follow close brace '}')") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index d673e8934b775..4eddc032b3d9a 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -5954,7 +5954,7 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } ++ } + else + alc_fixup_headset_mode(codec, fix, action); + } +-- +2.53.0 + diff --git a/queue-5.10/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch b/queue-5.10/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch new file mode 100644 index 0000000000..97e4792676 --- /dev/null +++ b/queue-5.10/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch @@ -0,0 +1,46 @@ +From fac9a93c54dc17a4921a087acb8e2aa53e5412d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 09:25:41 +0100 +Subject: ARM: dts: mediatek: mt7623: fix efuse fallback compatible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafał Miłecki + +[ Upstream commit 5978ff33cc6f0988388a2830dc5cd2ea4e81f36a ] + +Fix following validation error: +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: compatible: 'oneOf' conditional failed, one must be fixed: + ['mediatek,mt7623-efuse', 'mediatek,mt8173-efuse'] is too long + 'mediatek,mt8173-efuse' was expected + 'mediatek,efuse' was expected + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: Unevaluated properties are not allowed ('compatible' was unexpected) + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# + +Fixes: 43c7a91b4b3a ("arm: dts: mt7623: add efuse nodes to the mt7623.dtsi file") +Signed-off-by: Rafał Miłecki +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/mt7623.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index c267fc1f83579..290527c9711ec 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -329,7 +329,7 @@ sysirq: interrupt-controller@10200100 { + + efuse: efuse@10206000 { + compatible = "mediatek,mt7623-efuse", +- "mediatek,mt8173-efuse"; ++ "mediatek,efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; +-- +2.53.0 + diff --git a/queue-5.10/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch b/queue-5.10/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch new file mode 100644 index 0000000000..68927283e2 --- /dev/null +++ b/queue-5.10/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch @@ -0,0 +1,44 @@ +From 478f38530c6079804b9052dd4e2b394fcb77ca59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:51:11 +0800 +Subject: arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number + +From: Jun Yan + +[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ] + +Correct the interrupt number assigned to the Realtek PHY in the p230 + +following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm: +fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY +interrupt improvements [1]. + +[1] https://lore.kernel.org/all/20171202214037.17017-1-martin.blumenstingl@googlemail.com/ + +Fixes: b94d22d94ad2 ("ARM64: dts: meson-gx: add external PHY interrupt on some platforms") +Signed-off-by: Jun Yan +Reviewed-by: Martin Blumenstingl +Link: https://patch.msgid.link/20260330145111.115318-1-jerrysteve1101@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +index b2ab05c220903..67c952fe8abc1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +@@ -86,7 +86,8 @@ external_phy: ethernet-phy@0 { + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; +- interrupts = <29 IRQ_TYPE_LEVEL_LOW>; ++ /* MAC_INTR on GPIOZ_15 */ ++ interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + eee-broken-1000t; + }; + }; +-- +2.53.0 + diff --git a/queue-5.10/arm64-dts-qcom-sdm845-xiaomi-beryllium-add-dsi-and-p.patch b/queue-5.10/arm64-dts-qcom-sdm845-xiaomi-beryllium-add-dsi-and-p.patch new file mode 100644 index 0000000000..f4f94aac68 --- /dev/null +++ b/queue-5.10/arm64-dts-qcom-sdm845-xiaomi-beryllium-add-dsi-and-p.patch @@ -0,0 +1,131 @@ +From 3d3c3e2db25f4d5197506604a00b96189bde0434 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Apr 2021 01:14:37 +0530 +Subject: arm64: dts: qcom: sdm845-xiaomi-beryllium: Add DSI and panel bits + +From: Sumit Semwal + +[ Upstream commit 0e5a6f27036e93110d3710d489fcc1408a674e62 ] + +Enabling the Display panel for beryllium requires DSI +labibb regulators and panel dts nodes to be added. +It is also required to keep some of the regulators as +always-on. + +Signed-off-by: Sumit Semwal +Signed-off-by: Amit Pundir +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20210404194437.537011-1-amit.pundir@linaro.org +Signed-off-by: Bjorn Andersson +Stable-dep-of: 3b0dd81eea6b ("arm64: dts: qcom: sdm845-xiaomi-beryllium: Mark l1a regulator as powered during boot") +Signed-off-by: Sasha Levin +--- + .../boot/dts/qcom/sdm845-xiaomi-beryllium.dts | 71 +++++++++++++++++++ + 1 file changed, 71 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +index 86cbae63eaf7b..7d029425336e4 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +@@ -157,6 +157,14 @@ vreg_l13a_2p95: ldo13 { + regulator-initial-mode = ; + }; + ++ vreg_l14a_1p8: ldo14 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-initial-mode = ; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ + vreg_l17a_1p3: ldo17 { + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; +@@ -191,6 +199,7 @@ vreg_l26a_1p2: ldo26 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + }; + }; +@@ -200,6 +209,43 @@ &cdsp_pas { + firmware-name = "qcom/sdm845/cdsp.mdt"; + }; + ++&dsi0 { ++ status = "okay"; ++ vdda-supply = <&vreg_l26a_1p2>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ panel@0 { ++ compatible = "tianma,fhd-video"; ++ reg = <0>; ++ vddi0-supply = <&vreg_l14a_1p8>; ++ vddpos-supply = <&lab>; ++ vddneg-supply = <&ibb>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>; ++ ++ port { ++ tianma_nt36672a_in_0: endpoint { ++ remote-endpoint = <&dsi0_out>; ++ }; ++ }; ++ }; ++}; ++ ++&dsi0_out { ++ remote-endpoint = <&tianma_nt36672a_in_0>; ++ data-lanes = <0 1 2 3>; ++}; ++ ++&dsi0_phy { ++ status = "okay"; ++ vdds-supply = <&vreg_l1a_0p875>; ++}; ++ + &gcc { + protected-clocks = , + , +@@ -215,6 +261,31 @@ zap-shader { + }; + }; + ++&ibb { ++ regulator-min-microvolt = <4600000>; ++ regulator-max-microvolt = <6000000>; ++ regulator-over-current-protection; ++ regulator-pull-down; ++ regulator-soft-start; ++ qcom,discharge-resistor-kohms = <300>; ++}; ++ ++&lab { ++ regulator-min-microvolt = <4600000>; ++ regulator-max-microvolt = <6000000>; ++ regulator-over-current-protection; ++ regulator-pull-down; ++ regulator-soft-start; ++}; ++ ++&mdss { ++ status = "okay"; ++}; ++ ++&mdss_mdp { ++ status = "okay"; ++}; ++ + &mss_pil { + status = "okay"; + firmware-name = "qcom/sdm845/mba.mbn", "qcom/sdm845/modem.mdt"; +-- +2.53.0 + diff --git a/queue-5.10/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch b/queue-5.10/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch new file mode 100644 index 0000000000..2071e71b5a --- /dev/null +++ b/queue-5.10/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch @@ -0,0 +1,38 @@ +From b2c77eb193a8cbe8f48da3defb0eee191aadc081 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 18:33:11 +0100 +Subject: arm64: dts: qcom: sdm845-xiaomi-beryllium: Mark l1a regulator as + powered during boot + +From: David Heidelberg + +[ Upstream commit 3b0dd81eea6b7a239fce456ce4545af76f1a9715 ] + +The regulator must be on, since it provides the display subsystem and +therefore the bootloader had turned it on before Linux booted. + +Fixes: 77809cf74a8c ("arm64: dts: qcom: Add support for Xiaomi Poco F1 (Beryllium)") +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260320-beryllium-booton-v2-1-931d1be21eae@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +index 7d029425336e4..b38b3bcdf429e 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +@@ -131,6 +131,7 @@ vreg_l1a_0p875: ldo1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l5a_0p8: ldo5 { +-- +2.53.0 + diff --git a/queue-5.10/asoc-codecs-ab8500-fix-casting-of-private-data.patch b/queue-5.10/asoc-codecs-ab8500-fix-casting-of-private-data.patch new file mode 100644 index 0000000000..5bf85caf49 --- /dev/null +++ b/queue-5.10/asoc-codecs-ab8500-fix-casting-of-private-data.patch @@ -0,0 +1,56 @@ +From fbebf49c11c009d53b0411bc3dbb1466f043e9b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 21:22:49 +0200 +Subject: ASoC: codecs: ab8500: Fix casting of private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian A. Ehrhardt + +[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ] + +ab8500_filter_controls[i].private_value is initialized using + + .private_value = (unsigned long)&(struct filter_control) + {.count = xcount, .min = xmin, .max = xmax} + +thus it's a pointer to a struct filter_control casted to unsigned long. + +So to get back that pointer .private_data must be cast back, not its +address. + +Fixes: 679d7abdc754 ("ASoC: codecs: Add AB8500 codec-driver") +Signed-off-by: Christian A. Ehrhardt +Signed-off-by: Uwe Kleine-König (The Capable Hub) +Link: https://patch.msgid.link/20260428192255.2294705-2-u.kleine-koenig@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/ab8500-codec.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c +index 31a8c4162d209..b4bf411124fa0 100644 +--- a/sound/soc/codecs/ab8500-codec.c ++++ b/sound/soc/codecs/ab8500-codec.c +@@ -2505,13 +2505,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) + return status; + } + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; + drvdata->anc_fir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; + drvdata->anc_iir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; + drvdata->sid_fir_values = (long *)fc->value; + + snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); +-- +2.53.0 + diff --git a/queue-5.10/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch b/queue-5.10/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch new file mode 100644 index 0000000000..80bc74e073 --- /dev/null +++ b/queue-5.10/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch @@ -0,0 +1,189 @@ +From 57c34e324a34d8158f063bccb1a035ce454f9461 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:26 +0800 +Subject: ASoC: fsl_easrc: Change the type for iec958 channel status controls + +From: Shengjiu Wang + +[ Upstream commit 47f28a5bd154a95d5aa563dde02a801bd32ddb81 ] + +Use the type SNDRV_CTL_ELEM_TYPE_IEC958 for iec958 channel status +controls, the original type will cause mixer-test to iterate all 32bit +values, which costs a lot of time. And using IEC958 type can reduce the +control numbers. + +Also enable pm runtime before updating registers to make the regmap cache +data align with the value in hardware. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-12-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 118 +++++++++++++++++++++++++++----------- + 1 file changed, 84 insertions(+), 34 deletions(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 0670ab194e4ec..46d9c112c093c 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -78,17 +78,47 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + return 0; + } + ++static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ + static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; +- unsigned int regval; ++ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ int ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]); ++ if (ret) ++ return ret; + +- regval = snd_soc_component_read(component, mc->regbase); ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]); ++ if (ret) ++ return ret; + +- ucontrol->value.integer.value[0] = regval; ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]); ++ if (ret) ++ return ret; + + return 0; + } +@@ -100,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); +- unsigned int regval = ucontrol->value.integer.value[0]; +- bool changed; ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ bool changed, changed_all = false; + int ret; + +- ret = regmap_update_bits_check(easrc->regmap, mc->regbase, +- GENMASK(31, 0), regval, &changed); +- if (ret != 0) ++ ret = pm_runtime_resume_and_get(component->dev); ++ if (ret) + return ret; + +- return changed; ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase), ++ GENMASK(31, 0), regval[0], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase), ++ GENMASK(31, 0), regval[1], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase), ++ GENMASK(31, 0), regval[2], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase), ++ GENMASK(31, 0), regval[3], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase), ++ GENMASK(31, 0), regval[4], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase), ++ GENMASK(31, 0), regval[5], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++err: ++ pm_runtime_put_autosuspend(component->dev); ++ ++ if (ret != 0) ++ return ret; ++ else ++ return changed_all; + } + + #define SOC_SINGLE_REG_RW(xname, xreg) \ + { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ +- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ ++ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \ + .put = fsl_easrc_set_reg, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ +@@ -146,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { + SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), + SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), + +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), ++ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0), ++ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1), ++ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2), ++ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3), + }; + + /* +-- +2.53.0 + diff --git a/queue-5.10/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch b/queue-5.10/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch new file mode 100644 index 0000000000..9fac2c1317 --- /dev/null +++ b/queue-5.10/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch @@ -0,0 +1,39 @@ +From bc07382a74d263f6d88642aaa72c6f1f36ea85ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:24 +0800 +Subject: ASoC: fsl_easrc: Check the variable range in + fsl_easrc_iec958_put_bits() + +From: Shengjiu Wang + +[ Upstream commit 00541b86fb578d4949cfdd6aff1f82d43fcf07af ] + +Add check of input value's range in fsl_easrc_iec958_put_bits(), +otherwise the wrong value may be written from user space. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-10-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 6e9b9cc98284d..a267ca941d943 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, + unsigned int regval = ucontrol->value.integer.value[0]; + int ret; + ++ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT) ++ return -EINVAL; ++ + ret = (easrc_priv->bps_iec958[mc->regbase] != regval); + + easrc_priv->bps_iec958[mc->regbase] = regval; +-- +2.53.0 + diff --git a/queue-5.10/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch b/queue-5.10/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch new file mode 100644 index 0000000000..e71ae6691b --- /dev/null +++ b/queue-5.10/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch @@ -0,0 +1,37 @@ +From 82b966dd1a06ef888645e380ce2043b114d43307 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:25 +0800 +Subject: ASoC: fsl_easrc: Fix value type in fsl_easrc_iec958_get_bits() + +From: Shengjiu Wang + +[ Upstream commit aa21fe4a81458cf469c2615b08cbde5997dde25a ] + +The value type of controls "Context 0 IEC958 Bits Per Sample" should be +integer, not enumerated, the issue is found by the mixer-test. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-11-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index a267ca941d943..0670ab194e4ec 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -73,7 +73,7 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + +- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; ++ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; + } +-- +2.53.0 + diff --git a/queue-5.10/asoc-sti-return-errors-from-regmap_field_alloc.patch b/queue-5.10/asoc-sti-return-errors-from-regmap_field_alloc.patch new file mode 100644 index 0000000000..ad91b1b38a --- /dev/null +++ b/queue-5.10/asoc-sti-return-errors-from-regmap_field_alloc.patch @@ -0,0 +1,50 @@ +From ddf514461af0d399a378b1eab9eb14dfdd56cc03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:33 +0100 +Subject: ASoC: sti: Return errors from regmap_field_alloc() + +From: Sander Vanheule + +[ Upstream commit 272aabef50bc3fe58edd26de000f4cdd41bdbe60 ] + +When regmap_field_alloc() fails, it can return an error. Specifically, +it will return PTR_ERR(-ENOMEM) when the allocation returns a NULL +pointer. The code then uses these allocations with a simple NULL check: + + if (player->clk_sel) { + // May dereference invalid pointer (-ENOMEM) + err = regmap_field_write(player->clk_sel, ...); + } + +Ensure initialization fails by forwarding the errors from +regmap_field_alloc(), thus avoiding the use of the invalid pointers. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-2-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index dd9013c476649..e5c4e5245b255 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1029,7 +1029,12 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + } + + player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ if (IS_ERR(player->clk_sel)) ++ return PTR_ERR(player->clk_sel); ++ + player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ if (IS_ERR(player->valid_sel)) ++ return PTR_ERR(player->valid_sel); + + return 0; + } +-- +2.53.0 + diff --git a/queue-5.10/asoc-sti-use-managed-regmap_field-allocations.patch b/queue-5.10/asoc-sti-use-managed-regmap_field-allocations.patch new file mode 100644 index 0000000000..595d01c6ce --- /dev/null +++ b/queue-5.10/asoc-sti-use-managed-regmap_field-allocations.patch @@ -0,0 +1,45 @@ +From 1b3cf77154b687de0989fbaae60587beee183ceb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:34 +0100 +Subject: ASoC: sti: use managed regmap_field allocations + +From: Sander Vanheule + +[ Upstream commit 1696fad8b259a2d46e51cd6e17e4bcdbe02279fa ] + +The regmap_field objects allocated at player init are never freed and +may leak resources if the driver is removed. + +Switch to devm_regmap_field_alloc() to automatically limit the lifetime +of the allocations the lifetime of the device. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-3-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index e5c4e5245b255..da07f825f3c5f 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1028,11 +1028,11 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + return PTR_ERR(regmap); + } + +- player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]); + if (IS_ERR(player->clk_sel)) + return PTR_ERR(player->clk_sel); + +- player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]); + if (IS_ERR(player->valid_sel)) + return PTR_ERR(player->valid_sel); + +-- +2.53.0 + diff --git a/queue-5.10/backlight-sky81452-backlight-check-return-value-of-d.patch b/queue-5.10/backlight-sky81452-backlight-check-return-value-of-d.patch new file mode 100644 index 0000000000..b943887923 --- /dev/null +++ b/queue-5.10/backlight-sky81452-backlight-check-return-value-of-d.patch @@ -0,0 +1,46 @@ +From 2b29d1e246749d3b75e4d93adabfaa9067dedd54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:16:25 +0800 +Subject: backlight: sky81452-backlight: Check return value of + devm_gpiod_get_optional() in sky81452_bl_parse_dt() + +From: Chen Ni + +[ Upstream commit 797cc011ae02bda26f93d25a4442d7a1a77d84df ] + +The devm_gpiod_get_optional() function may return an ERR_PTR in case of +genuine GPIO acquisition errors, not just NULL which indicates the +legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the call in sky81452_bl_parse_dt(). On +error, return the error code to ensure proper failure handling rather +than proceeding with invalid pointers. + +Fixes: e1915eec54a6 ("backlight: sky81452: Convert to GPIO descriptors") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260203021625.578678-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/sky81452-backlight.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c +index 8268ac43d54f7..5375dc7d7cd95 100644 +--- a/drivers/video/backlight/sky81452-backlight.c ++++ b/drivers/video/backlight/sky81452-backlight.c +@@ -204,6 +204,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( + pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode"); + pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift"); + pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); ++ if (IS_ERR(pdata->gpiod_enable)) ++ return dev_err_cast_probe(dev, pdata->gpiod_enable, ++ "failed to get gpio\n"); + + ret = of_property_count_u32_elems(np, "led-sources"); + if (ret < 0) { +-- +2.53.0 + diff --git a/queue-5.10/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch b/queue-5.10/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch new file mode 100644 index 0000000000..2d5b20d02a --- /dev/null +++ b/queue-5.10/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch @@ -0,0 +1,60 @@ +From 6aca6c113a88717398a5b488d2399455071904eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 09:53:51 -0700 +Subject: bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst() + +From: Weiming Shi + +[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ] + +bareudp_fill_metadata_dst() passes bareudp->sock to +udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. +The socket is only created in bareudp_open() and NULLed in +bareudp_stop(), so calling this function while the device is down +triggers a NULL dereference via sock->sk. + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) + Call Trace: + + bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) + do_execute_actions (net/openvswitch/actions.c:901) + ovs_execute_actions (net/openvswitch/actions.c:1589) + ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) + genl_rcv_msg (net/netlink/genetlink.c:1209) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths +in the same driver. + +Fixes: 571912c69f0e ("net: UDP tunnel encapsulation module for tunnelling different protocols like MPLS, IP, NSH etc.") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426165350.1663137-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index d5210b5b8cbf8..b3ed3447c84cb 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -512,6 +512,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + ++ if (!sock) ++ return -ESHUTDOWN; ++ + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, + &saddr, info, IPPROTO_UDP, + use_cache); +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch b/queue-5.10/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch new file mode 100644 index 0000000000..b45a5a5f30 --- /dev/null +++ b/queue-5.10/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch @@ -0,0 +1,52 @@ +From a9c572cc1ea08232f8d2887ed3e195d317cdc636 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:42:59 +0300 +Subject: Bluetooth: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER + +From: Pauli Virtanen + +[ Upstream commit 5c7209a341ff2ac338b2b0375c34a307b37c9ac2 ] + +When protocol sets HCI_PROTO_DEFER, hci_conn_request_evt() calls +hci_connect_cfm(conn) without hdev->lock. Generally hci_connect_cfm() +assumes it is held, and if conn is deleted concurrently -> UAF. + +Only SCO and ISO set HCI_PROTO_DEFER and only for defer setup listen, +and HCI_EV_CONN_REQUEST is not generated for ISO. In the non-deferred +listening socket code paths, hci_connect_cfm(conn) is called with +hdev->lock held. + +Fix by holding the lock. + +Fixes: 70c464256310 ("Bluetooth: Refactor connection request handling") +Signed-off-by: Pauli Virtanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 6310f4f9890eb..a2995dcb0ffeb 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -2786,8 +2786,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) + + memcpy(conn->dev_class, ev->dev_class, 3); + +- hci_dev_unlock(hdev); +- + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; +@@ -2821,7 +2819,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) + hci_connect_cfm(conn, 0); + } + +- return; + unlock: + hci_dev_unlock(hdev); + } +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch b/queue-5.10/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch new file mode 100644 index 0000000000..f2f22b1af0 --- /dev/null +++ b/queue-5.10/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch @@ -0,0 +1,49 @@ +From 2248a2244dce663a1382c629ff7a2ebf4adc9f04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:20 +0100 +Subject: Bluetooth: hci_ldisc: Clear HCI_UART_PROTO_INIT on error + +From: Jonathan Rissanen + +[ Upstream commit 68d39ea5e0adc9ecaea1ce8abd842ec972eb8718 ] + +When hci_register_dev() fails in hci_uart_register_dev() +HCI_UART_PROTO_INIT is not cleared before calling hu->proto->close(hu) +and setting hu->hdev to NULL. This means incoming UART data will reach +the protocol-specific recv handler in hci_uart_tty_receive() after +resources are freed. + +Clear HCI_UART_PROTO_INIT with a write lock before calling +hu->proto->close() and setting hu->hdev to NULL. The write lock ensures +all active readers have completed and no new reader can enter the +protocol recv path before resources are freed. + +This allows the protocol-specific recv functions to remove the +"HCI_UART_REGISTERED" guard without risking a null pointer dereference +if hci_register_dev() fails. + +Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization") +Signed-off-by: Jonathan Rissanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ldisc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index 436d82a7f5871..b1e036bb682f8 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -691,6 +691,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device"); ++ percpu_down_write(&hu->proto_lock); ++ clear_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ percpu_up_write(&hu->proto_lock); + hu->proto->close(hu); + hu->hdev = NULL; + hci_free_dev(hdev); +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch b/queue-5.10/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch new file mode 100644 index 0000000000..d8d69ceae0 --- /dev/null +++ b/queue-5.10/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch @@ -0,0 +1,48 @@ +From 1b144ce12f4ea61efa65b1787e7fb4170c92caa3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 23:47:41 +0800 +Subject: Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp + +From: Dudu Lu + +[ Upstream commit 42776497cdbc9a665b384a6dcb85f0d4bd927eab ] + +l2cap_ecred_reconf_rsp() calls l2cap_chan_del() without holding +l2cap_chan_lock(). Every other l2cap_chan_del() caller in the file +acquires the lock first. A remote BLE device can send a crafted +L2CAP ECRED reconfiguration response to corrupt the channel list +while another thread is iterating it. + +Add l2cap_chan_hold() and l2cap_chan_lock() before l2cap_chan_del(), +and l2cap_chan_unlock() and l2cap_chan_put() after, matching the +pattern used in l2cap_ecred_conn_rsp() and l2cap_conn_del(). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 24ee019c0b696..45e1e8192e3b6 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6439,7 +6439,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + if (chan->ident != cmd->ident) + continue; + ++ l2cap_chan_hold(chan); ++ l2cap_chan_lock(chan); ++ + l2cap_chan_del(chan, ECONNRESET); ++ ++ l2cap_chan_unlock(chan); ++ l2cap_chan_put(chan); + } + + return 0; +-- +2.53.0 + diff --git a/queue-5.10/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch b/queue-5.10/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch new file mode 100644 index 0000000000..98a96c687a --- /dev/null +++ b/queue-5.10/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch @@ -0,0 +1,38 @@ +From 2623d4e6a2b15e17fafb26f1cf14fbc44dc371b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 14:34:13 -0400 +Subject: Bluetooth: L2CAP: Fix printing wrong information if SDU length + exceeds MTU + +From: Luiz Augusto von Dentz + +[ Upstream commit 15bf35a660eb82a49f8397fc3d3acada8dae13db ] + +The code was printing skb->len and sdu_len in the places where it should +be sdu_len and chan->imtu respectively to match the if conditions. + +Link: https://lore.kernel.org/linux-bluetooth/20260315132013.75ab40c5@kernel.org/T/#m1418f9c82eeff8510c1beaa21cf53af20db96c06 +Fixes: e1d9a6688986 ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU") +Signed-off-by: Luiz Augusto von Dentz +Reviewed-by: Paul Menzel +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index a6efb5b42f9b3..24ee019c0b696 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7686,7 +7686,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + + if (sdu_len > chan->imtu) { + BT_ERR("Too big LE L2CAP SDU length: len %u > %u", +- skb->len, sdu_len); ++ sdu_len, chan->imtu); + l2cap_send_disconn_req(chan, ECONNRESET); + err = -EMSGSIZE; + goto failed; +-- +2.53.0 + diff --git a/queue-5.10/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch b/queue-5.10/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch new file mode 100644 index 0000000000..6290037724 --- /dev/null +++ b/queue-5.10/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch @@ -0,0 +1,96 @@ +From 2db066cff70d85a3c5e9918ba40ee83a99a56185 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 07:33:52 -0700 +Subject: bpf, arm32: Reject BPF-to-BPF calls and callbacks in the JIT + +From: Puranjay Mohan + +[ Upstream commit e1d486445af3c392628532229f7ce5f5cf7891b6 ] + +The ARM32 BPF JIT does not support BPF-to-BPF function calls +(BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does +not reject them either. + +When a program with subprograms is loaded (e.g. libxdp's XDP +dispatcher uses __noinline__ subprograms, or any program using +callbacks like bpf_loop or bpf_for_each_map_elem), the verifier +invokes bpf_jit_subprogs() which calls bpf_int_jit_compile() +for each subprogram. + +For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT +silently emits code using the wrong address computation: + + func = __bpf_call_base + imm + +where imm is a pc-relative subprogram offset, producing a bogus +function pointer. + +For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and +loads the immediate as a normal 64-bit value without error. + +In both cases, build_body() reports success and a JIT image is +allocated. ARM32 lacks the jit_data/extra_pass mechanism needed +for the second JIT pass in bpf_jit_subprogs(). On the second +pass, bpf_int_jit_compile() performs a full fresh compilation, +allocating a new JIT binary and overwriting prog->bpf_func. The +first allocation is never freed. bpf_jit_subprogs() then detects +the function pointer changed and aborts with -ENOTSUPP, but the +original JIT binary has already been leaked. Each program +load/unload cycle leaks one JIT binary allocation, as reported +by kmemleak: + + unreferenced object 0xbf0a1000 (size 4096): + backtrace: + bpf_jit_binary_alloc+0x64/0xfc + bpf_int_jit_compile+0x14c/0x348 + bpf_jit_subprogs+0x4fc/0xa60 + +Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL +handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling +through to the existing 'notyet' path. This causes build_body() +to fail before any JIT binary is allocated, so +bpf_int_jit_compile() returns the original program unjitted. +bpf_jit_subprogs() then sees !prog->jited and cleanly falls +back to the interpreter with no leak. + +Acked-by: Daniel Borkmann +Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs") +Reported-by: Jonas Rebmann +Closes: https://lore.kernel.org/bpf/b63e9174-7a3d-4e22-8294-16df07a4af89@pengutronix.de +Tested-by: Jonas Rebmann +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417143353.838911-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm/net/bpf_jit_32.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c +index 1214e39aad5ec..1b3cccd1060bb 100644 +--- a/arch/arm/net/bpf_jit_32.c ++++ b/arch/arm/net/bpf_jit_32.c +@@ -1609,6 +1609,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + { + u64 val = (u32)imm | (u64)insn[1].imm << 32; + ++ if (insn->src_reg == BPF_PSEUDO_FUNC) ++ goto notyet; ++ + emit_a32_mov_i64(dst, val, ctx); + + return 1; +@@ -1801,6 +1804,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + const s8 *r5 = bpf2a32[BPF_REG_5]; + const u32 func = (u32)__bpf_call_base + (u32)imm; + ++ if (insn->src_reg == BPF_PSEUDO_CALL) ++ goto notyet; ++ + emit_a32_mov_r64(true, r0, r1, ctx); + emit_a32_mov_r64(true, r1, r2, ctx); + emit_push_r64(r5, ctx); +-- +2.53.0 + diff --git a/queue-5.10/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch b/queue-5.10/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch new file mode 100644 index 0000000000..af245e3180 --- /dev/null +++ b/queue-5.10/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch @@ -0,0 +1,47 @@ +From c50350e384d8c395f354bcda79bbe8baffa314ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 21:29:50 +0800 +Subject: bpf: fix end-of-list detection in cgroup_storage_get_next_key() + +From: Weiming Shi + +[ Upstream commit 5828b9e5b272ecff7cf5d345128d3de7324117f7 ] + +list_next_entry() never returns NULL -- when the current element is the +last entry it wraps to the list head via container_of(). The subsequent +NULL check is therefore dead code and get_next_key() never returns +-ENOENT for the last element, instead reading storage->key from a bogus +pointer that aliases internal map fields and copying the result to +userspace. + +Replace it with list_entry_is_head() so the function correctly returns +-ENOENT when there are no more entries. + +Fixes: de9cbbaadba5 ("bpf: introduce cgroup storage maps") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Sun Jian +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260403132951.43533-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/local_storage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c +index b139247d2dd33..5c12b4d130333 100644 +--- a/kernel/bpf/local_storage.c ++++ b/kernel/bpf/local_storage.c +@@ -261,7 +261,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, + goto enoent; + + storage = list_next_entry(storage, list_map); +- if (!storage) ++ if (list_entry_is_head(storage, &map->list, list_map)) + goto enoent; + } else { + storage = list_first_entry(&map->list, +-- +2.53.0 + diff --git a/queue-5.10/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch b/queue-5.10/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch new file mode 100644 index 0000000000..74fca48c22 --- /dev/null +++ b/queue-5.10/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch @@ -0,0 +1,46 @@ +From a416181904c6302c2e54c9309a0c916cc6feca3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:27:19 +0200 +Subject: bpf: Fix precedence bug in convert_bpf_ld_abs alignment check + +From: Daniel Borkmann + +[ Upstream commit e5f635edd393aeaa7cad9e42831d397e6e2e1eed ] + +Fix an operator precedence issue in convert_bpf_ld_abs() where the +expression offset + ip_align % size evaluates as offset + (ip_align % size) +due to % having higher precedence than +. That latter evaluation does +not make any sense. The intended check is (offset + ip_align) % size == 0 +to verify that the packet load offset is properly aligned for direct +access. + +With NET_IP_ALIGN == 2, the bug causes the inline fast-path for direct +packet loads to almost never be taken on !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +platforms. This forces nearly all cBPF BPF_LD_ABS packet loads through +the bpf_skb_load_helper slow path on the affected archs. + +Fixes: e0cea7ce988c ("bpf: implement ld_abs/ld_ind in native bpf") +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260416122719.661033-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 7002368d1592a..b8d891f79b983 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -489,7 +489,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp) + ((unaligned_ok && offset >= 0) || + (!unaligned_ok && offset >= 0 && + offset + ip_align >= 0 && +- offset + ip_align % size == 0))) { ++ (offset + ip_align) % size == 0))) { + bool ldx_off_ok = offset <= S16_MAX; + + *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H); +-- +2.53.0 + diff --git a/queue-5.10/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch b/queue-5.10/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch new file mode 100644 index 0000000000..8793b1fab3 --- /dev/null +++ b/queue-5.10/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch @@ -0,0 +1,72 @@ +From 100b45dd4be0710639ab2a6f4a21a619c5273204 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 11:46:22 +0800 +Subject: bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb + +From: Sun Jian + +[ Upstream commit 12bec2bd4b76d81c5d3996bd14ec1b7f4d983747 ] + +bpf_prog_test_run_skb() calls eth_type_trans() first and then uses +skb->protocol to initialize sk family and address fields for the test +run. + +For IPv4 and IPv6 packets, it may access ip_hdr(skb) or ipv6_hdr(skb) +even when the provided test input only contains an Ethernet header. + +Reject the input earlier if the Ethernet frame carries IPv4/IPv6 +EtherType but the L3 header is too short. + +Fold the IPv4/IPv6 header length checks into the existing protocol +switch and return -EINVAL before accessing the network headers. + +Fixes: fa5cb548ced6 ("bpf: Setup socket family and addresses in bpf_prog_test_run_skb") +Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc +Signed-off-by: Sun Jian +Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 027d6ba8c154c..e97e09a424e5f 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -611,19 +611,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + switch (skb->protocol) { + case htons(ETH_P_IP): +- sk->sk_family = AF_INET; +- if (sizeof(struct iphdr) <= skb_headlen(skb)) { +- sk->sk_rcv_saddr = ip_hdr(skb)->saddr; +- sk->sk_daddr = ip_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct iphdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET; ++ sk->sk_rcv_saddr = ip_hdr(skb)->saddr; ++ sk->sk_daddr = ip_hdr(skb)->daddr; + break; + #if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +- sk->sk_family = AF_INET6; +- if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { +- sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; +- sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET6; ++ sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; ++ sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + break; + #endif + default: +-- +2.53.0 + diff --git a/queue-5.10/brcmfmac-support-chipsets-with-different-core-enumer.patch b/queue-5.10/brcmfmac-support-chipsets-with-different-core-enumer.patch new file mode 100644 index 0000000000..e9a1644290 --- /dev/null +++ b/queue-5.10/brcmfmac-support-chipsets-with-different-core-enumer.patch @@ -0,0 +1,214 @@ +From d47ffc89341ea7a286ce53d303ffa2510912284c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jul 2021 22:50:34 +0200 +Subject: brcmfmac: support chipsets with different core enumeration space + +From: Arend van Spriel + +[ Upstream commit 1ce050c159528ee74e31498411dfed8e0935d10c ] + +Historically the broadcom wifi chipsets always had enumeration +space containing all core information at same place. However, for +new chipsets the ASIC developers moved away from that given fact. +So we have to accommodate that it can differ per chipset. + +Reviewed-by: Hante Meuleman +Reviewed-by: Pieter-Paul Giesberts +Reviewed-by: Franky Lin +Signed-off-by: Arend van Spriel +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1627505434-9544-5-git-send-email-arend.vanspriel@broadcom.com +Stable-dep-of: dd8592fc6007 ("wifi: brcmfmac: Fix error pointer dereference") +Signed-off-by: Sasha Levin +--- + .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 3 ++- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 16 ++++++++++++---- + .../wireless/broadcom/brcm80211/brcmfmac/chip.h | 5 ++++- + .../wireless/broadcom/brcm80211/brcmfmac/pcie.c | 3 ++- + .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 12 ++++++++---- + .../wireless/broadcom/brcm80211/include/soc.h | 2 +- + 6 files changed, 29 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +index 75dc7904a4bd6..106804b93f1a4 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -128,7 +128,8 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) + + if (sdiodev->bus_if->chip == BRCM_CC_43362_CHIP_ID) { + /* assign GPIO to SDIO core */ +- addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol); ++ addr = brcmf_chip_enum_base(sdiodev->func1->device); ++ addr = CORE_CC_REG(addr, gpiocontrol); + gpiocontrol = brcmf_sdiod_readl(sdiodev, addr, &ret); + gpiocontrol |= 0x2; + brcmf_sdiod_writel(sdiodev, addr, gpiocontrol, &ret); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 5bf11e46fc49a..a0097ffe33590 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -893,7 +893,8 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) + u32 base, wrap; + int err; + +- eromaddr = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, eromptr)); ++ eromaddr = ci->ops->read32(ci->ctx, ++ CORE_CC_REG(ci->pub.enum_base, eromptr)); + + while (desc_type != DMP_DESC_EOT) { + val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type); +@@ -941,6 +942,11 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) + return 0; + } + ++u32 brcmf_chip_enum_base(u16 devid) ++{ ++ return SI_ENUM_BASE_DEFAULT; ++} ++ + static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + { + struct brcmf_core *core; +@@ -953,7 +959,8 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + * For different chiptypes or old sdio hosts w/o chipcommon, + * other ways of recognition should be added here. + */ +- regdata = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, chipid)); ++ regdata = ci->ops->read32(ci->ctx, ++ CORE_CC_REG(ci->pub.enum_base, chipid)); + ci->pub.chip = regdata & CID_ID_MASK; + ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; + socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; +@@ -973,7 +980,7 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + ci->resetcore = brcmf_chip_sb_resetcore; + + core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, +- SI_ENUM_BASE, 0); ++ SI_ENUM_BASE_DEFAULT, 0); + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, + BCM4329_CORE_BUS_BASE, 0); +@@ -1087,7 +1094,7 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip) + return ret; + } + +-struct brcmf_chip *brcmf_chip_attach(void *ctx, ++struct brcmf_chip *brcmf_chip_attach(void *ctx, u16 devid, + const struct brcmf_buscore_ops *ops) + { + struct brcmf_chip_priv *chip; +@@ -1112,6 +1119,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, + chip->num_cores = 0; + chip->ops = ops; + chip->ctx = ctx; ++ chip->pub.enum_base = brcmf_chip_enum_base(devid); + + err = ops->prepare(ctx); + if (err < 0) +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +index 8fa38658e727a..d69f101f58344 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +@@ -15,6 +15,7 @@ + * + * @chip: chip identifier. + * @chiprev: chip revision. ++ * @enum_base: base address of core enumeration space. + * @cc_caps: chipcommon core capabilities. + * @cc_caps_ext: chipcommon core extended capabilities. + * @pmucaps: PMU capabilities. +@@ -27,6 +28,7 @@ + struct brcmf_chip { + u32 chip; + u32 chiprev; ++ u32 enum_base; + u32 cc_caps; + u32 cc_caps_ext; + u32 pmucaps; +@@ -70,7 +72,7 @@ struct brcmf_buscore_ops { + }; + + int brcmf_chip_get_raminfo(struct brcmf_chip *pub); +-struct brcmf_chip *brcmf_chip_attach(void *ctx, ++struct brcmf_chip *brcmf_chip_attach(void *ctx, u16 devid, + const struct brcmf_buscore_ops *ops); + void brcmf_chip_detach(struct brcmf_chip *chip); + struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); +@@ -85,5 +87,6 @@ void brcmf_chip_set_passive(struct brcmf_chip *ci); + bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec); + bool brcmf_chip_sr_capable(struct brcmf_chip *pub); + char *brcmf_chip_name(u32 chipid, u32 chiprev, char *buf, uint len); ++u32 brcmf_chip_enum_base(u16 devid); + + #endif /* BRCMF_AXIDMP_H */ +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 721d587425c7a..0f5431e4ac208 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -1860,7 +1860,8 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) + + devinfo->pdev = pdev; + pcie_bus_dev = NULL; +- devinfo->ci = brcmf_chip_attach(devinfo, &brcmf_pcie_buscore_ops); ++ devinfo->ci = brcmf_chip_attach(devinfo, pdev->device, ++ &brcmf_pcie_buscore_ops); + if (IS_ERR(devinfo->ci)) { + ret = PTR_ERR(devinfo->ci); + devinfo->ci = NULL; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +index 3c0d5c68eaca2..68fbb38c63d5c 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -3903,7 +3903,7 @@ static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr) + * It can be identified as 4339 by looking at the chip revision. It + * is corrected here so the chip.c module has the right info. + */ +- if (addr == CORE_CC_REG(SI_ENUM_BASE, chipid) && ++ if (addr == CORE_CC_REG(SI_ENUM_BASE_DEFAULT, chipid) && + (sdiodev->func1->device == SDIO_DEVICE_ID_BROADCOM_4339 || + sdiodev->func1->device == SDIO_DEVICE_ID_BROADCOM_4335_4339)) { + rev = (val & CID_REV_MASK) >> CID_REV_SHIFT; +@@ -3939,12 +3939,15 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) + int reg_addr; + u32 reg_val; + u32 drivestrength; ++ u32 enum_base; + + sdiodev = bus->sdiodev; + sdio_claim_host(sdiodev->func1); + +- pr_debug("F1 signature read @0x18000000=0x%4x\n", +- brcmf_sdiod_readl(sdiodev, SI_ENUM_BASE, NULL)); ++ enum_base = brcmf_chip_enum_base(sdiodev->func1->device); ++ ++ pr_debug("F1 signature read @0x%08x=0x%4x\n", enum_base, ++ brcmf_sdiod_readl(sdiodev, enum_base, NULL)); + + /* + * Force PLL off until brcmf_chip_attach() +@@ -3963,7 +3966,8 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) + goto fail; + } + +- bus->ci = brcmf_chip_attach(sdiodev, &brcmf_sdio_buscore_ops); ++ bus->ci = brcmf_chip_attach(sdiodev, sdiodev->func1->device, ++ &brcmf_sdio_buscore_ops); + if (IS_ERR(bus->ci)) { + brcmf_err("brcmf_chip_attach failed!\n"); + bus->ci = NULL; +diff --git a/drivers/net/wireless/broadcom/brcm80211/include/soc.h b/drivers/net/wireless/broadcom/brcm80211/include/soc.h +index 92d942b44f2c2..8249211913660 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/include/soc.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/soc.h +@@ -6,7 +6,7 @@ + #ifndef _BRCM_SOC_H + #define _BRCM_SOC_H + +-#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ ++#define SI_ENUM_BASE_DEFAULT 0x18000000 + + /* Common core control flags */ + #define SICF_BIST_EN 0x8000 +-- +2.53.0 + diff --git a/queue-5.10/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch b/queue-5.10/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch new file mode 100644 index 0000000000..cc3b7a302a --- /dev/null +++ b/queue-5.10/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch @@ -0,0 +1,48 @@ +From d89ddab6f5871b044f723278a467aac7d3996767 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:15:23 +0100 +Subject: btrfs: fix double-decrement of bytes_may_use in + submit_one_async_extent() + +From: Mark Harmstone + +[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ] + +submit_one_async_extent() calls btrfs_reserve_extent(), which decrements +bytes_may_use. If the call btrfs_create_io_em() fails, we jump to +out_free_reserve, which calls extent_clear_unlock_delalloc(). + +Because we're specifying EXTENT_DO_ACCOUNTING, i.e. +EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases +bytes_may_use again. This can lead to problems later on, as an initial +write can fail only for the writeback to silently ENOSPC. + +Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. +This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved +extents in cow_one_range()"), which is the same fix in cow_one_range(). + +Fixes: 151a41bc46df ("Btrfs: fix what bits we clear when erroring out from delalloc") +Reviewed-by: Qu Wenruo +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 6d2d799a0ed25..3631d05746073 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -918,7 +918,7 @@ static noinline void submit_compressed_extents(struct async_chunk *async_chunk) + async_extent->ram_size - 1, + NULL, EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | +- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, ++ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, + PAGE_UNLOCK | PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK | PAGE_SET_ERROR); + free_async_extent_pages(async_extent); +-- +2.53.0 + diff --git a/queue-5.10/btrfs-merge-page_clear_dirty-and-page_set_writeback-.patch b/queue-5.10/btrfs-merge-page_clear_dirty-and-page_set_writeback-.patch new file mode 100644 index 0000000000..f3b0dc40d8 --- /dev/null +++ b/queue-5.10/btrfs-merge-page_clear_dirty-and-page_set_writeback-.patch @@ -0,0 +1,164 @@ +From 5a469f51bc8d112ff58c30969d22da5993825e69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jan 2021 16:33:45 +0800 +Subject: btrfs: merge PAGE_CLEAR_DIRTY and PAGE_SET_WRITEBACK to + PAGE_START_WRITEBACK + +From: Qu Wenruo + +[ Upstream commit 6869b0a8be775e920be54ee9b69a743ca20d8332 ] + +PAGE_CLEAR_DIRTY and PAGE_SET_WRITEBACK are two defines used in +__process_pages_contig(), to let the function know to clear page dirty +bit and then set page writeback. + +However page writeback and dirty bits are conflicting (at least for +sector size == PAGE_SIZE case), this means these two have to be always +updated together. + +This means we can merge PAGE_CLEAR_DIRTY and PAGE_SET_WRITEBACK to +PAGE_START_WRITEBACK. + +Reviewed-by: Josef Bacik +Signed-off-by: Qu Wenruo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Stable-dep-of: 82323b1a7088 ("btrfs: fix double-decrement of bytes_may_use in submit_one_async_extent()") +Signed-off-by: Sasha Levin +--- + fs/btrfs/extent_io.c | 4 ++-- + fs/btrfs/extent_io.h | 12 ++++++------ + fs/btrfs/inode.c | 28 ++++++++++------------------ + 3 files changed, 18 insertions(+), 26 deletions(-) + +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 3d0b854e0c19d..38405087cc842 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -1983,10 +1983,10 @@ static int __process_pages_contig(struct address_space *mapping, + pages_locked++; + continue; + } +- if (page_ops & PAGE_CLEAR_DIRTY) ++ if (page_ops & PAGE_START_WRITEBACK) { + clear_page_dirty_for_io(pages[i]); +- if (page_ops & PAGE_SET_WRITEBACK) + set_page_writeback(pages[i]); ++ } + if (page_ops & PAGE_SET_ERROR) + SetPageError(pages[i]); + if (page_ops & PAGE_END_WRITEBACK) +diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h +index e8ab48e5f282d..03aa1e6b3d332 100644 +--- a/fs/btrfs/extent_io.h ++++ b/fs/btrfs/extent_io.h +@@ -34,12 +34,12 @@ enum { + + /* these are flags for __process_pages_contig */ + #define PAGE_UNLOCK (1 << 0) +-#define PAGE_CLEAR_DIRTY (1 << 1) +-#define PAGE_SET_WRITEBACK (1 << 2) +-#define PAGE_END_WRITEBACK (1 << 3) +-#define PAGE_SET_PRIVATE2 (1 << 4) +-#define PAGE_SET_ERROR (1 << 5) +-#define PAGE_LOCK (1 << 6) ++/* Page starts writeback, clear dirty bit and set writeback bit */ ++#define PAGE_START_WRITEBACK (1 << 1) ++#define PAGE_END_WRITEBACK (1 << 2) ++#define PAGE_SET_PRIVATE2 (1 << 3) ++#define PAGE_SET_ERROR (1 << 4) ++#define PAGE_LOCK (1 << 5) + + /* + * page->private values. Every page that is controlled by the extent +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 7e66ebb91af78..6d2d799a0ed25 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -642,8 +642,7 @@ static noinline int compress_file_range(struct async_chunk *async_chunk) + NULL, + clear_flags, + PAGE_UNLOCK | +- PAGE_CLEAR_DIRTY | +- PAGE_SET_WRITEBACK | ++ PAGE_START_WRITEBACK | + page_error_op | + PAGE_END_WRITEBACK); + +@@ -884,8 +883,7 @@ static noinline void submit_compressed_extents(struct async_chunk *async_chunk) + async_extent->start + + async_extent->ram_size - 1, + NULL, EXTENT_LOCKED | EXTENT_DELALLOC, +- PAGE_UNLOCK | PAGE_CLEAR_DIRTY | +- PAGE_SET_WRITEBACK); ++ PAGE_UNLOCK | PAGE_START_WRITEBACK); + if (btrfs_submit_compressed_write(inode, async_extent->start, + async_extent->ram_size, + ins.objectid, +@@ -921,9 +919,8 @@ static noinline void submit_compressed_extents(struct async_chunk *async_chunk) + NULL, EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | + EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, +- PAGE_UNLOCK | PAGE_CLEAR_DIRTY | +- PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK | +- PAGE_SET_ERROR); ++ PAGE_UNLOCK | PAGE_START_WRITEBACK | ++ PAGE_END_WRITEBACK | PAGE_SET_ERROR); + free_async_extent_pages(async_extent); + kfree(async_extent); + goto again; +@@ -1020,8 +1017,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode, + EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | + EXTENT_DO_ACCOUNTING, PAGE_UNLOCK | +- PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK | +- PAGE_END_WRITEBACK); ++ PAGE_START_WRITEBACK | PAGE_END_WRITEBACK); + *nr_written = *nr_written + + (end - start + PAGE_SIZE) / PAGE_SIZE; + *page_started = 1; +@@ -1143,8 +1139,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode, + out_unlock: + clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | + EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV; +- page_ops = PAGE_UNLOCK | PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK | +- PAGE_END_WRITEBACK; ++ page_ops = PAGE_UNLOCK | PAGE_START_WRITEBACK | PAGE_END_WRITEBACK; + /* + * If we reserved an extent for our delalloc range (or a subrange) and + * failed to create the respective ordered extent, then it means that +@@ -1269,9 +1264,8 @@ static int cow_file_range_async(struct btrfs_inode *inode, + unsigned clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | + EXTENT_DO_ACCOUNTING; +- unsigned long page_ops = PAGE_UNLOCK | PAGE_CLEAR_DIRTY | +- PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK | +- PAGE_SET_ERROR; ++ unsigned long page_ops = PAGE_UNLOCK | PAGE_START_WRITEBACK | ++ PAGE_END_WRITEBACK | PAGE_SET_ERROR; + + extent_clear_unlock_delalloc(inode, start, end, locked_page, + clear_bits, page_ops); +@@ -1468,8 +1462,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, + EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DO_ACCOUNTING | + EXTENT_DEFRAG, PAGE_UNLOCK | +- PAGE_CLEAR_DIRTY | +- PAGE_SET_WRITEBACK | ++ PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK); + return -ENOMEM; + } +@@ -1782,8 +1775,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, + locked_page, EXTENT_LOCKED | + EXTENT_DELALLOC | EXTENT_DEFRAG | + EXTENT_DO_ACCOUNTING, PAGE_UNLOCK | +- PAGE_CLEAR_DIRTY | +- PAGE_SET_WRITEBACK | ++ PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK); + btrfs_free_path(path); + return ret; +-- +2.53.0 + diff --git a/queue-5.10/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch b/queue-5.10/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch new file mode 100644 index 0000000000..89692d7dda --- /dev/null +++ b/queue-5.10/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch @@ -0,0 +1,237 @@ +From 786fe014afe28ee0064635647d1e2630e91690b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:01:39 +0100 +Subject: cdrom, scsi: sr: propagate read-only status to block layer via + set_disk_ro() + +From: Daan De Meyer + +[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ] + +The cdrom core never calls set_disk_ro() for a registered device, so +BLKROGET on a CD-ROM device always returns 0 (writable), even when the +drive has no write capabilities and writes will inevitably fail. This +causes problems for userspace that relies on BLKROGET to determine +whether a block device is read-only. For example, systemd's loop device +setup uses BLKROGET to decide whether to create a loop device with +LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the +loop device to the CD-ROM and fail with I/O errors. systemd-fsck +similarly checks BLKROGET to decide whether to run fsck in no-repair +mode (-n). + +The write-capability bits in cdi->mask come from two different sources: +CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE +SENSE capabilities page (page 0x2A) before register_cdrom() is called, +while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command +and were only probed by cdrom_open_write() at device open time. This +meant that any attempt to compute the writable state from the full +mask at probe time was incorrect, because the GET CONFIGURATION bits +were still unset (and cdi->mask is initialized such that capabilities +are assumed present). + +Fix this by factoring the GET CONFIGURATION probing out of +cdrom_open_write() into a new exported helper, +cdrom_probe_write_features(), and having sr call it from sr_probe() +right after get_capabilities() has populated the MODE SENSE bits. +register_cdrom() then calls set_disk_ro() based on the full +write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) +so the block layer reflects the drive's actual write support. The +feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with +RT=00) report drive-level capabilities that are persistent across +media, so a single probe before register_cdrom() is sufficient and the +redundant probe at open time is dropped. + +With set_disk_ro() now accurate, the long-vestigial cd->writeable flag +in sr can go: get_capabilities() used to set cd->writeable based on +the same four mask bits, but because CDC_MRW_W and CDC_RAM default to +"capability present" in cdi->mask and aren't touched by MODE SENSE, +the condition that gated cd->writeable was always true, making it +unconditionally 1. Replace the corresponding gate in sr_init_command() +with get_disk_ro(cd->disk), which turns a previously no-op check into +a real one and also catches kernel-internal bio writers that bypass +blkdev_write_iter()'s bdev_read_only() check. + +The sd driver (SCSI disks) does not have this problem because it +checks the MODE SENSE Write Protect bit and calls set_disk_ro() +accordingly. The sr driver cannot use the same approach because the +MMC specification does not define the WP bit in the MODE SENSE +device-specific parameter byte for CD-ROM devices. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Daan De Meyer +Reviewed-by: Phillip Potter +Reviewed-by: Martin K. Petersen +Signed-off-by: Phillip Potter +Link: https://patch.msgid.link/20260427210139.1400-2-phil@philpotter.co.uk +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- + drivers/scsi/sr.c | 11 ++----- + drivers/scsi/sr.h | 1 - + include/linux/cdrom.h | 1 + + 4 files changed, 51 insertions(+), 35 deletions(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index 0c271b9e3c5b7..9a04e1083fca1 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -636,6 +636,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) + + WARN_ON(!cdo->generic_packet); + ++ /* ++ * Propagate the drive's write support to the block layer so BLKROGET ++ * reflects actual write capability. Drivers that use GET CONFIGURATION ++ * features (CDC_MRW_W, CDC_RAM) must have called ++ * cdrom_probe_write_features() before register_cdrom() so the mask is ++ * complete here. ++ */ ++ set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | ++ CDC_CD_RW)); ++ + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + mutex_lock(&cdrom_mutex); + list_add(&cdi->list, &cdrom_list); +@@ -747,6 +757,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) + return 0; + } + ++/* ++ * Probe write-related MMC features via GET CONFIGURATION and update ++ * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE ++ * capabilities page (e.g. sr) should call this after those MODE SENSE bits ++ * have been set but before register_cdrom(), so that the full set of ++ * write-capability bits is known by the time register_cdrom() decides on the ++ * initial read-only state of the disk. ++ */ ++void cdrom_probe_write_features(struct cdrom_device_info *cdi) ++{ ++ int mrw, mrw_write, ram_write; ++ ++ mrw = 0; ++ if (!cdrom_is_mrw(cdi, &mrw_write)) ++ mrw = 1; ++ ++ if (CDROM_CAN(CDC_MO_DRIVE)) ++ ram_write = 1; ++ else ++ (void) cdrom_is_random_writable(cdi, &ram_write); ++ ++ if (mrw) ++ cdi->mask &= ~CDC_MRW; ++ else ++ cdi->mask |= CDC_MRW; ++ ++ if (mrw_write) ++ cdi->mask &= ~CDC_MRW_W; ++ else ++ cdi->mask |= CDC_MRW_W; ++ ++ if (ram_write) ++ cdi->mask &= ~CDC_RAM; ++ else ++ cdi->mask |= CDC_RAM; ++} ++EXPORT_SYMBOL(cdrom_probe_write_features); ++ + static int cdrom_media_erasable(struct cdrom_device_info *cdi) + { + disc_information di; +@@ -899,33 +947,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) + */ + static int cdrom_open_write(struct cdrom_device_info *cdi) + { +- int mrw, mrw_write, ram_write; + int ret = 1; + +- mrw = 0; +- if (!cdrom_is_mrw(cdi, &mrw_write)) +- mrw = 1; +- +- if (CDROM_CAN(CDC_MO_DRIVE)) +- ram_write = 1; +- else +- (void) cdrom_is_random_writable(cdi, &ram_write); +- +- if (mrw) +- cdi->mask &= ~CDC_MRW; +- else +- cdi->mask |= CDC_MRW; +- +- if (mrw_write) +- cdi->mask &= ~CDC_MRW_W; +- else +- cdi->mask |= CDC_MRW_W; +- +- if (ram_write) +- cdi->mask &= ~CDC_RAM; +- else +- cdi->mask |= CDC_RAM; +- + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index 62a1bf81f7e47..1a35c392e2c66 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -438,7 +438,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) + + switch (req_op(rq)) { + case REQ_OP_WRITE: +- if (!cd->writeable) ++ if (get_disk_ro(cd->disk)) + goto out; + SCpnt->cmnd[0] = WRITE_10; + cd->cdi.media_written = 1; +@@ -776,6 +776,7 @@ static int sr_probe(struct device *dev) + error = -ENOMEM; + if (get_capabilities(cd)) + goto fail_minor; ++ cdrom_probe_write_features(&cd->cdi); + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -991,14 +992,6 @@ static int get_capabilities(struct scsi_cd *cd) + /*else I don't think it can close its tray + cd->cdi.mask |= CDC_CLOSE_TRAY; */ + +- /* +- * if DVD-RAM, MRW-W or CD-RW, we are randomly writable +- */ +- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != +- (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { +- cd->writeable = 1; +- } +- + kfree(buffer); + return 0; + } +diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h +index 339c624e04d86..ea8a69b04da53 100644 +--- a/drivers/scsi/sr.h ++++ b/drivers/scsi/sr.h +@@ -38,7 +38,6 @@ typedef struct scsi_cd { + struct scsi_device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ +- unsigned writeable : 1; + unsigned use:1; /* is this device still supportable */ + unsigned xa_flag:1; /* CD has XA sectors ? */ + unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ +diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h +index f48d0a31deaec..43108f24fb42b 100644 +--- a/include/linux/cdrom.h ++++ b/include/linux/cdrom.h +@@ -107,6 +107,7 @@ extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, + extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing); + ++extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); + extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); + extern void unregister_cdrom(struct cdrom_device_info *cdi); + +-- +2.53.0 + diff --git a/queue-5.10/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch b/queue-5.10/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch new file mode 100644 index 0000000000..0f88a1ca50 --- /dev/null +++ b/queue-5.10/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch @@ -0,0 +1,47 @@ +From 0aa68eff4199e3db2fa82f679973ee6606065e80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 09:53:27 +0800 +Subject: cgroup/rdma: fix integer overflow in rdmacg_try_charge() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: cuitao + +[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ] + +The expression `rpool->resources[index].usage + 1` is computed in int +arithmetic before being assigned to s64 variable `new`. When usage equals +INT_MAX (the default "max" value), the addition overflows to INT_MIN. +This negative value then passes the `new > max` check incorrectly, +allowing a charge that should be rejected and corrupting usage to +negative. + +Fix by casting usage to s64 before the addition so the arithmetic is +done in 64-bit. + +Fixes: 39d3e7584a68 ("rdmacg: Added rdma cgroup controller") +Signed-off-by: cuitao +Reviewed-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c +index ae042c347c640..b52ee28be3455 100644 +--- a/kernel/cgroup/rdma.c ++++ b/kernel/cgroup/rdma.c +@@ -281,7 +281,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, + ret = PTR_ERR(rpool); + goto err; + } else { +- new = rpool->resources[index].usage + 1; ++ new = (s64)rpool->resources[index].usage + 1; + if (new > rpool->resources[index].max) { + ret = -EAGAIN; + goto err; +-- +2.53.0 + diff --git a/queue-5.10/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch b/queue-5.10/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch new file mode 100644 index 0000000000..1f53c7ece3 --- /dev/null +++ b/queue-5.10/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch @@ -0,0 +1,58 @@ +From b8ccc20f722628a4d9323d289d9501f5c8de0cac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:58 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in + of_assigned_ldb_sels() + +From: Felix Gu + +[ Upstream commit 9faf207208951460f3f7eefbc112246c8d28ff1b ] + +The function of_assigned_ldb_sels() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing a memory +leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 5d283b083800 ("clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-2-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index 1a262b9b56e53..89400f4312252 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -183,9 +183,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + } + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: parent clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + parent = clkspec.args[0]; ++ of_node_put(clkspec.np); + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); +@@ -193,9 +195,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + return; + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: child clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + child = clkspec.args[0]; ++ of_node_put(clkspec.np); + + if (child != IMX6QDL_CLK_LDB_DI0_SEL && + child != IMX6QDL_CLK_LDB_DI1_SEL) +-- +2.53.0 + diff --git a/queue-5.10/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch b/queue-5.10/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch new file mode 100644 index 0000000000..e01503e624 --- /dev/null +++ b/queue-5.10/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch @@ -0,0 +1,56 @@ +From e1350270930a329fa10504ca0dba484b4cd1be21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:57 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in pll6_bypassed() + +From: Felix Gu + +[ Upstream commit 4b84d496c804b470124cd3a08e928df6801d8eae ] + +The function pll6_bypassed() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing +a memory leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 3cc48976e9763 ("clk: imx6q: handle ENET PLL bypass") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-1-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index 7d07dd92a7b44..1a262b9b56e53 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -233,8 +233,11 @@ static bool pll6_bypassed(struct device_node *node) + return false; + + if (clkspec.np == node && +- clkspec.args[0] == IMX6QDL_PLL6_BYPASS) ++ clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { ++ of_node_put(clkspec.np); + break; ++ } ++ of_node_put(clkspec.np); + } + + /* PLL6 bypass is not part of the assigned clock list */ +@@ -244,6 +247,9 @@ static bool pll6_bypassed(struct device_node *node) + ret = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + ++ if (!ret) ++ of_node_put(clkspec.np); ++ + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) + return true; + +-- +2.53.0 + diff --git a/queue-5.10/clk-imx8mq-correct-the-csi-phy-sels.patch b/queue-5.10/clk-imx8mq-correct-the-csi-phy-sels.patch new file mode 100644 index 0000000000..1f5f8d8cc1 --- /dev/null +++ b/queue-5.10/clk-imx8mq-correct-the-csi-phy-sels.patch @@ -0,0 +1,49 @@ +From 295a238717f02813d882ce346de4b18805126dee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 00:47:21 +0100 +Subject: clk: imx8mq: Correct the CSI PHY sels + +From: Sebastian Krzyszkowiak + +[ Upstream commit d16f57caa78776e6e8a88b96cb2597797b376138 ] + +According to i.MX 8M Quad Reference Manual (Section 5.1.2 Table 5-1) +MIPI_CSI1_PHY_REF_CLK_ROOT and MIPI_CSI2_PHY_REF_CLK_ROOT have +SYSTEM_PLL2_DIV3 available as their second source, which corresponds +to sys2_pll_333m rather than sys2_pll_125m. + +Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") +Signed-off-by: Sebastian Krzyszkowiak +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260128-imx8mq-csi-clk-v1-1-ac028ed26e8c@puri.sm +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index 89313dd7a57f6..0ae1c24eecfcf 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " + static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +@@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", + static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +-- +2.53.0 + diff --git a/queue-5.10/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch b/queue-5.10/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch new file mode 100644 index 0000000000..9477469bf9 --- /dev/null +++ b/queue-5.10/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch @@ -0,0 +1,59 @@ +From 0aa44fe24ddfb11f3deafef9e24f39be15fa9fb5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:26 +0100 +Subject: clk: qcom: dispcc-sc7180: Add missing MDSS resets + +From: Konrad Dybcio + +[ Upstream commit b0bc6011c5499bdfddd0390262bfa13dce1eff74 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: dd3d06622138 ("clk: qcom: Add display clock controller driver for SC7180") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Taniya Das +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-2-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc7180.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c +index f487515701e36..11bbf1dd83880 100644 +--- a/drivers/clk/qcom/dispcc-sc7180.c ++++ b/drivers/clk/qcom/dispcc-sc7180.c +@@ -16,6 +16,7 @@ + #include "clk-regmap-divider.h" + #include "common.h" + #include "gdsc.h" ++#include "reset.h" + + enum { + P_BI_TCXO, +@@ -634,6 +635,11 @@ static struct gdsc mdss_gdsc = { + .flags = HW_CTRL, + }; + ++static const struct qcom_reset_map disp_cc_sc7180_resets[] = { ++ [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, ++ [DISP_CC_MDSS_RSCC_BCR] = { 0x4000 }, ++}; ++ + static struct gdsc *disp_cc_sc7180_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, + }; +@@ -685,6 +691,8 @@ static const struct qcom_cc_desc disp_cc_sc7180_desc = { + .config = &disp_cc_sc7180_regmap_config, + .clks = disp_cc_sc7180_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sc7180_clocks), ++ .resets = disp_cc_sc7180_resets, ++ .num_resets = ARRAY_SIZE(disp_cc_sc7180_resets), + .gdscs = disp_cc_sc7180_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sc7180_gdscs), + }; +-- +2.53.0 + diff --git a/queue-5.10/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch b/queue-5.10/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..e55b005b85 --- /dev/null +++ b/queue-5.10/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,48 @@ +From ba9847ab90f6cef55935354ddd20323975d6ccd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:13 -0300 +Subject: clk: qcom: dispcc-sm8250: Enable parents for pixel clocks + +From: Val Packett + +[ Upstream commit acf7a91d0b0e9e3ef374944021de62062125b7e4 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-9-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index 4e29004a7e44b..7ef1d9559f487 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -392,7 +392,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -406,7 +406,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-5.10/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch b/queue-5.10/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch new file mode 100644 index 0000000000..7cb16046ac --- /dev/null +++ b/queue-5.10/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch @@ -0,0 +1,45 @@ +From 824bab3ed09f97ca87bf7f0dc53ea0657270be79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:12 -0300 +Subject: clk: qcom: dispcc-sm8250: Use shared ops on the mdss vsync clk + +From: Val Packett + +[ Upstream commit 8c522da70f0c2e5148c4c13ccb1c64cca57a6fdb ] + +mdss_gdsc can get stuck on boot due to RCGs being left on from last boot. +As a fix, commit 01a0a6cc8cfd ("clk: qcom: Park shared RCGs upon +registration") introduced a callback to ensure the RCG is off upon init. +However, the fix depends on all shared RCGs being marked as such in code. + +For SM8150/SC8180X/SM8250 the MDSS vsync clock was using regular ops, +unlike the same clock in the SC7180 code. This was causing display to +frequently fail to initialize after rebooting on the Surface Pro X. +Fix by using shared ops for this clock. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-8-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index bbdd27946bf1f..4e29004a7e44b 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -446,7 +446,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-5.10/clk-qoriq-avoid-format-string-warning.patch b/queue-5.10/clk-qoriq-avoid-format-string-warning.patch new file mode 100644 index 0000000000..7f24cdf9cc --- /dev/null +++ b/queue-5.10/clk-qoriq-avoid-format-string-warning.patch @@ -0,0 +1,86 @@ +From 718df1da1e03bbe705697183248f39066ca2cda1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:18:49 +0100 +Subject: clk: qoriq: avoid format string warning + +From: Arnd Bergmann + +[ Upstream commit 096abbb6682ee031a0f5ce9f4c71ead9fa63d31e ] + +clang-22 warns about the use of non-variadic format arguments passed into +snprintf(): + +drivers/clk/clk-qoriq.c:925:39: error: diagnostic behavior may be improved by adding the + 'format(printf, 7, 8)' attribute to the declaration of 'create_mux_common' [-Werror,-Wmissing-format-attribute] + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + | __attribute__((format(printf, 7, 8))) + 911 | struct mux_hwclock *hwc, + 912 | const struct clk_ops *ops, + 913 | unsigned long min_rate, + 914 | unsigned long max_rate, + 915 | unsigned long pct80_rate, + 916 | const char *fmt, int idx) + 917 | { + 918 | struct clk_init_data init = {}; + 919 | struct clk *clk; + 920 | const struct clockgen_pll_div *div; + 921 | const char *parent_names[NUM_MUX_PARENTS]; + 922 | char name[32]; + 923 | int i, j; + 924 | + 925 | snprintf(name, sizeof(name), fmt, idx); + | ^ +drivers/clk/clk-qoriq.c:910:28: note: 'create_mux_common' declared here + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + +Rework this to pass the 'int idx' as a varargs argument, allowing the +format string to be verified at the caller location. + +Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") +Signed-off-by: Arnd Bergmann +Reviewed-by: Kees Cook +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-qoriq.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c +index 585b9ac118818..6775e128592d4 100644 +--- a/drivers/clk/clk-qoriq.c ++++ b/drivers/clk/clk-qoriq.c +@@ -880,13 +880,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg, + return &cg->pll[pll].div[div]; + } + +-static struct clk * __init create_mux_common(struct clockgen *cg, +- struct mux_hwclock *hwc, +- const struct clk_ops *ops, +- unsigned long min_rate, +- unsigned long max_rate, +- unsigned long pct80_rate, +- const char *fmt, int idx) ++static struct clk * __init __printf(7, 8) ++create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, ++ const struct clk_ops *ops, unsigned long min_rate, ++ unsigned long max_rate, unsigned long pct80_rate, ++ const char *fmt, ...) + { + struct clk_init_data init = {}; + struct clk *clk; +@@ -894,8 +892,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg, + const char *parent_names[NUM_MUX_PARENTS]; + char name[32]; + int i, j; ++ va_list args; + +- snprintf(name, sizeof(name), fmt, idx); ++ va_start(args, fmt); ++ vsnprintf(name, sizeof(name), fmt, args); ++ va_end(args); + + for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) { + unsigned long rate; +-- +2.53.0 + diff --git a/queue-5.10/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch b/queue-5.10/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch new file mode 100644 index 0000000000..aafa7be1a0 --- /dev/null +++ b/queue-5.10/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch @@ -0,0 +1,37 @@ +From 6684b5126987d169f1db746c3dc2ab6c3fc35d90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:11:16 +0100 +Subject: clk: xgene: Fix mapping leak in xgene_pllclk_init() + +From: Geert Uytterhoeven + +[ Upstream commit f520a492e07bc6718e26cfb7543ab4cadd8bb0e2 ] + +If xgene_register_clk_pll() fails, the mapped register block is never +unmapped. + +Fixes: 308964caeebc45eb ("clk: Add APM X-Gene SoC clock driver") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-xgene.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c +index 3fd53057c01fe..fca5ce22611ca 100644 +--- a/drivers/clk/clk-xgene.c ++++ b/drivers/clk/clk-xgene.c +@@ -187,6 +187,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); ++ } else { ++ iounmap(reg); + } + } + +-- +2.53.0 + diff --git a/queue-5.10/crypto-ccp-copy-iv-using-skcipher-ivsize.patch b/queue-5.10/crypto-ccp-copy-iv-using-skcipher-ivsize.patch new file mode 100644 index 0000000000..f075e09e20 --- /dev/null +++ b/queue-5.10/crypto-ccp-copy-iv-using-skcipher-ivsize.patch @@ -0,0 +1,47 @@ +From a8c41e1b45937cc0b605c652add3b0c421367381 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 03:07:49 -0500 +Subject: crypto: ccp - copy IV using skcipher ivsize + +From: Paul Moses + +[ Upstream commit a7a1f3cdd64d8a165d9b8c9e9ad7fb46ac19dfc4 ] + +AF_ALG rfc3686-ctr-aes-ccp requests pass an 8-byte IV to the driver. + +ccp_aes_complete() restores AES_BLOCK_SIZE bytes into the caller's IV +buffer while RFC3686 skciphers expose an 8-byte IV, so the restore +overruns the provided buffer. + +Use crypto_skcipher_ivsize() to copy only the algorithm's IV length. + +Fixes: 2b789435d7f3 ("crypto: ccp - CCP AES crypto API support") +Signed-off-by: Paul Moses +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-crypto-aes.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c +index e6dcd8cedd53e..b03ed5e83c3e9 100644 +--- a/drivers/crypto/ccp/ccp-crypto-aes.c ++++ b/drivers/crypto/ccp/ccp-crypto-aes.c +@@ -28,8 +28,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) + if (ret) + return ret; + +- if (ctx->u.aes.mode != CCP_AES_MODE_ECB) +- memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE); ++ if (ctx->u.aes.mode != CCP_AES_MODE_ECB) { ++ size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); ++ ++ memcpy(req->iv, rctx->iv, ivsize); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-5.10/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch b/queue-5.10/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch new file mode 100644 index 0000000000..52ba6f9f34 --- /dev/null +++ b/queue-5.10/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch @@ -0,0 +1,47 @@ +From ec53ab83cf893b35e78381ecfada6ab1f977ca03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 20:06:58 +0530 +Subject: crypto: sa2ul - Fix AEAD fallback algorithm names + +From: T Pratham + +[ Upstream commit 8451ab6ad686ffdcdf9ddadaa446a79ab48e5590 ] + +For authenc AEAD algorithms, sa2ul is trying to register very specific +-ce version as a fallback. This causes registration failure on SoCs +which do not have ARMv8-CE enabled/available. Change the fallback +algorithm from the specific driver name to generic algorithm name so +that the kernel can allocate any available fallback. + +Fixes: d2c8ac187fc92 ("crypto: sa2ul - Add AEAD algorithm support") +Signed-off-by: T Pratham +Reviewed-by: Manorit Chawdhry +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/sa2ul.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c +index 0888f4489a765..6fa1a5b414ee5 100644 +--- a/drivers/crypto/sa2ul.c ++++ b/drivers/crypto/sa2ul.c +@@ -1754,13 +1754,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, + static int sa_cra_init_aead_sha1(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha1", +- "authenc(hmac(sha1-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha1),cbc(aes))"); + } + + static int sa_cra_init_aead_sha256(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha256", +- "authenc(hmac(sha256-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha256),cbc(aes))"); + } + + static void sa_exit_tfm_aead(struct crypto_aead *tfm) +-- +2.53.0 + diff --git a/queue-5.10/dev_printk-add-new-dev_err_probe-helpers.patch b/queue-5.10/dev_printk-add-new-dev_err_probe-helpers.patch new file mode 100644 index 0000000000..a61816e168 --- /dev/null +++ b/queue-5.10/dev_printk-add-new-dev_err_probe-helpers.patch @@ -0,0 +1,47 @@ +From 65b2412f134ab05ce7ee5dbe96f0ca5ff6a38c62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2024 09:22:37 +0200 +Subject: dev_printk: add new dev_err_probe() helpers + +From: Nuno Sa + +[ Upstream commit dbbe7eaf0e4795bf003ac06872aaf52b6b6b1310 ] + +This is similar to dev_err_probe() but for cases where an ERR_PTR() or +ERR_CAST() is to be returned simplifying patterns like: + + dev_err_probe(dev, ret, ...); + return ERR_PTR(ret) +or + dev_err_probe(dev, PTR_ERR(ptr), ...); + return ERR_CAST(ptr) + +Signed-off-by: Nuno Sa +Link: https://patch.msgid.link/20240606-dev-add_dev_errp_probe-v3-1-51bb229edd79@analog.com +Signed-off-by: Jonathan Cameron +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/dev_printk.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h +index 6a6a6baa10bac..7d467d5426576 100644 +--- a/include/linux/dev_printk.h ++++ b/include/linux/dev_printk.h +@@ -244,4 +244,12 @@ do { \ + + __printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); + ++/* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */ ++#define dev_err_ptr_probe(dev, ___err, fmt, ...) \ ++ ERR_PTR(dev_err_probe(dev, ___err, fmt, ##__VA_ARGS__)) ++ ++/* Simple helper for dev_err_probe() when ERR_CAST() is to be returned. */ ++#define dev_err_cast_probe(dev, ___err_ptr, fmt, ...) \ ++ ERR_PTR(dev_err_probe(dev, PTR_ERR(___err_ptr), fmt, ##__VA_ARGS__)) ++ + #endif /* _DEVICE_PRINTK_H_ */ +-- +2.53.0 + diff --git a/queue-5.10/devres-fix-missing-node-debug-info-in-devm_krealloc.patch b/queue-5.10/devres-fix-missing-node-debug-info-in-devm_krealloc.patch new file mode 100644 index 0000000000..e2867493e0 --- /dev/null +++ b/queue-5.10/devres-fix-missing-node-debug-info-in-devm_krealloc.patch @@ -0,0 +1,37 @@ +From 7a9d56c76f17a08736a70cb74ed80ef80abe6f1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 00:48:14 +0100 +Subject: devres: fix missing node debug info in devm_krealloc() + +From: Danilo Krummrich + +[ Upstream commit f813ec9e84b4d0ca81ec1da94ab07bfb4a29266c ] + +Fix missing call to set_node_dbginfo() for new devres nodes created by +devm_krealloc(). + +Fixes: f82485722e5d ("devres: provide devm_krealloc()") +Reviewed-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/20260202235210.55176-2-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/base/devres.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index e3a735d0213a8..4bfc7f670ab0c 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -911,6 +911,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) + if (!new_dr) + return NULL; + ++ set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size); ++ + /* + * The spinlock protects the linked list against concurrent + * modifications but not the resource itself. +-- +2.53.0 + diff --git a/queue-5.10/dissector-do-not-set-invalid-ppp-protocol.patch b/queue-5.10/dissector-do-not-set-invalid-ppp-protocol.patch new file mode 100644 index 0000000000..a57e49763c --- /dev/null +++ b/queue-5.10/dissector-do-not-set-invalid-ppp-protocol.patch @@ -0,0 +1,46 @@ +From d1bff24e41c421e0633a85bcd83c112564bc6c9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Sep 2021 14:32:23 +0300 +Subject: dissector: do not set invalid PPP protocol + +From: Boris Sukholitko + +[ Upstream commit 2e861e5e97175dfa7b7bc055c45acdc06d2301d3 ] + +The following flower filter fails to match non-PPP_IP{V6} packets +wrapped in PPP_SES protocol: + +tc filter add dev eth0 ingress protocol ppp_ses flower \ + action simple sdata hi64 + +The reason is that proto local variable is being set even when +FLOW_DISSECT_RET_OUT_BAD status is returned. + +The fix is to avoid setting proto variable if the PPP protocol is unknown. + +Signed-off-by: Boris Sukholitko +Signed-off-by: David S. Miller +Stable-dep-of: cc1ff87bce1c ("pppoe: drop PFC frames") +Signed-off-by: Sasha Levin +--- + net/core/flow_dissector.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index cc9c63987dc36..8fe8b3afacd04 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -1197,9 +1197,8 @@ bool __skb_flow_dissect(const struct net *net, + break; + } + +- proto = hdr->proto; + nhoff += PPPOE_SES_HLEN; +- switch (proto) { ++ switch (hdr->proto) { + case htons(PPP_IP): + proto = htons(ETH_P_IP); + fdret = FLOW_DISSECT_RET_PROTO_AGAIN; +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-fix-concurrent-write-failure-in-passthrough.patch b/queue-5.10/dm-cache-fix-concurrent-write-failure-in-passthrough.patch new file mode 100644 index 0000000000..1a957a3a03 --- /dev/null +++ b/queue-5.10/dm-cache-fix-concurrent-write-failure-in-passthrough.patch @@ -0,0 +1,84 @@ +From 67eb994420d80c385f0a4d52ad7df76bff11a72c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:09 +0800 +Subject: dm cache: fix concurrent write failure in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit e4f66341779d0cf4c83c74793753a84094286d9e ] + +When bio prison cell lock acquisition fails due to concurrent writes to +the same block in passthrough mode, dm-cache incorrectly returns an I/O +error instead of properly handling the concurrency. This can occur in +both process and workqueue contexts when invalidate_lock() is called for +exclusive access to a data block. Fix this by deferring the write bios +to ensure proper block device behavior. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently. Sometimes one of the + processes will receive I/O errors. + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + + + fio-3.41 + fio: io_u error on file /dev/mapper/cache: Input/output error: write offset=4096, buflen=4096 + fio: pid=106, err=5/file:io_u.c:2008, func=io_u error, error=Input/output error + test: (groupid=0, jobs=1): err= 0: pid=105 + test: (groupid=0, jobs=1): err= 5 (file:io_u.c:2008, func=io_u error, error=Input/output error): pid=106 + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 28a1444328566..b659fa412a7ad 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1594,6 +1594,15 @@ static int invalidate_lock(struct dm_cache_migration *mg) + READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell); + if (r < 0) { + free_prison_cell(cache, prealloc); ++ ++ /* Defer the bio for retrying the cell lock */ ++ if (mg->overwrite_bio) { ++ struct bio *bio = mg->overwrite_bio; ++ ++ mg->overwrite_bio = NULL; ++ defer_bio(cache, bio); ++ } ++ + invalidate_complete(mg, false); + return r; + } +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch b/queue-5.10/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch new file mode 100644 index 0000000000..b19ebef53d --- /dev/null +++ b/queue-5.10/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch @@ -0,0 +1,151 @@ +From 62840b7c531102dd6e6e29f0d5b9f0a5dec0155e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:10 +0800 +Subject: dm cache: fix dirty mapping checking in passthrough mode switching + +From: Ming-Hung Tsai + +[ Upstream commit 322586745bd1a0e5f3559fd1635fdeb4dbd1d6b8 ] + +As mentioned in commit 9b1cc9f251af ("dm cache: share cache-metadata +object across inactive and active DM tables"), dm-cache assumed table +reload occurs after suspension, while LVM's table preload breaks this +assumption. The dirty mapping check for passthrough mode was designed +around this assumption and is performed during table creation, causing +the check to fail with preload while metadata updates are ongoing. This +risks loading dirty mappings into passthrough mode, resulting in data +loss. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty mappings + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Preload a table in passthrough mode + +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" + +3. Write to the first cache block to make it dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +4. Resume the inactive table. Now it's possible to load the dirty block + into passthrough mode. + +dmsetup resume cache + +Fix by moving the checks to the preresume phase to support table +preloading. Also remove the unused function dm_cache_metadata_all_clean. + +Fixes: 2ee57d587357 ("dm cache: add passthrough mode") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 11 ----------- + drivers/md/dm-cache-metadata.h | 5 ----- + drivers/md/dm-cache-target.c | 25 ++++++++----------------- + 3 files changed, 8 insertions(+), 33 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 2ecd0db0f2945..715ff419b63ba 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1749,17 +1749,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * + return r; + } + +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) +-{ +- int r; +- +- READ_LOCK(cmd); +- r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); +- READ_UNLOCK(cmd); +- +- return r; +-} +- + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) + { + WRITE_LOCK_VOID(cmd); +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 179ed5bf81a3e..79747130a48f7 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -137,11 +137,6 @@ void dm_cache_dump(struct dm_cache_metadata *cmd); + */ + int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p); + +-/* +- * Query method. Are all the blocks in the cache clean? +- */ +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); +- + int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); + int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index e7931a8204f48..770bccd1fbb98 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2540,23 +2540,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) + goto bad; + } + +- if (passthrough_mode(cache)) { +- bool all_clean; +- +- r = dm_cache_metadata_all_clean(cache->cmd, &all_clean); +- if (r) { +- *error = "dm_cache_metadata_all_clean() failed"; +- goto bad; +- } +- +- if (!all_clean) { +- *error = "Cannot enter passthrough mode unless all blocks are clean"; +- r = -EINVAL; +- goto bad; +- } +- ++ if (passthrough_mode(cache)) + policy_allow_migrations(cache->policy, false); +- } + + spin_lock_init(&cache->lock); + bio_list_init(&cache->deferred_bios); +@@ -2883,6 +2868,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + struct cache *cache = context; + + if (dirty) { ++ if (passthrough_mode(cache)) { ++ DMERR("%s: cannot enter passthrough mode unless all blocks are clean", ++ cache_device_name(cache)); ++ return -EBUSY; ++ } ++ + set_bit(from_cblock(cblock), cache->dirty_bitset); + atomic_inc(&cache->nr_dirty); + } else +@@ -3120,7 +3111,7 @@ static int cache_preresume(struct dm_target *ti) + load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- if (r != -EFBIG) ++ if (r != -EFBIG && r != -EBUSY) + metadata_operation_failed(cache, "dm_cache_load_mappings", r); + return r; + } +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch b/queue-5.10/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch new file mode 100644 index 0000000000..fe14bd31cd --- /dev/null +++ b/queue-5.10/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch @@ -0,0 +1,86 @@ +From a019e65690c7edb9767de216e9206112a338f195 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:05 +0800 +Subject: dm cache: fix null-deref with concurrent writes in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 7d1f98d668ee34c1d15bdc0420fdd062f24a27c0 ] + +In passthrough mode, when dm-cache starts to invalidate a cache +entry and bio prison cell lock fails due to concurrent write to +the same cached block, mg->cell remains NULL. The error path in +invalidate_complete() attempts to unlock and free the cell +unconditionally, causing a NULL pointer dereference: + +KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +CPU: 0 UID: 0 PID: 134 Comm: fio Not tainted 6.19.0-rc7 #3 PREEMPT +RIP: 0010:dm_cell_unlock_v2+0x3f/0x210 + +Call Trace: + invalidate_complete+0xef/0x430 + map_bio+0x130f/0x1a10 + cache_map+0x320/0x6b0 + __map_bio+0x458/0x510 + dm_submit_bio+0x40e/0x16d0 + __submit_bio+0x419/0x870 + + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + +Fix by checking if mg->cell is valid before attempting to unlock it. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index fc6ad47c08b58..a3cb0a68dc1fa 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1518,8 +1518,10 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + struct cache *cache = mg->cache; + + bio_list_init(&bios); +- if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) +- free_prison_cell(cache, mg->cell); ++ if (mg->cell) { ++ if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) ++ free_prison_cell(cache, mg->cell); ++ } + + if (!success && mg->overwrite_bio) + bio_io_error(mg->overwrite_bio); +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch b/queue-5.10/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch new file mode 100644 index 0000000000..9383747bd5 --- /dev/null +++ b/queue-5.10/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch @@ -0,0 +1,85 @@ +From 24d75a8e95119f009fbcdfd16310a36a4cbb3a3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:06 +0800 +Subject: dm cache: fix write path cache coherency in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 0c5eef0aad508231d8e43ff8392692925e131b68 ] + +In passthrough mode, dm-cache defers write bio submission until cache +invalidation completes to maintain existing coherency, requiring the +target map function to return DM_MAPIO_SUBMITTED. The current map_bio() +returns DM_MAPIO_REMAPPED, violating the required ordering constraint. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into the cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first data block, and check io ordering using ftrace + +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_queue/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_complete/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_rq_complete/enable +fio --filename=/dev/mapper/cache --name=test --rw=write --bs=64k \ +--direct=1 --size 64k + +5. ftrace logs show that write operations to the cache origin (252:2) + and metadata operations (252:0) are unsynchronized: the origin write + occurs before metadata commit. + + + fio-146 [000] ..... 420.139562: block_bio_queue: 252,3 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149395: block_bio_queue: 252,2 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149763: block_bio_queue: 8,32 WS 262144 + 128 [fio] + fio-146 [000] dNh1. 420.151446: block_rq_complete: 8,32 WS () 262144 + 128 be,0,4 [0] + fio-146 [000] dNh1. 420.152731: block_bio_complete: 252,2 WS 0 + 128 [0] + fio-146 [000] dNh1. 420.154229: block_bio_complete: 252,3 WS 0 + 128 [0] + kworker/0:0-9 [000] ..... 420.160530: block_bio_queue: 252,0 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.161641: block_bio_queue: 8,32 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162533: block_bio_queue: 252,0 W 416 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162821: block_bio_queue: 8,32 W 416 + 8 [kworker/0:0] + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index a3cb0a68dc1fa..28a1444328566 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1754,6 +1754,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, + bio_drop_shared_lock(cache, bio); + atomic_inc(&cache->stats.demotion); + invalidate_start(cache, cblock, block, bio); ++ return DM_MAPIO_SUBMITTED; + } else + remap_to_origin_clear_discard(cache, bio, block); + } else { +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch b/queue-5.10/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch new file mode 100644 index 0000000000..a17813fe00 --- /dev/null +++ b/queue-5.10/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch @@ -0,0 +1,121 @@ +From 45fe9de3ee67b8beee027b75aeadc7ac3bc4f780 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:56:28 +0800 +Subject: dm cache metadata: fix memory leak on metadata abort retry + +From: Ming-Hung Tsai + +[ Upstream commit 044ca491d4086dc5bf233e9fcb71db52df32f633 ] + +When failing to acquire the root_lock in dm_cache_metadata_abort because +the block_manager is read-only, the temporary block_manager created +outside the root_lock is not properly released, causing a memory leak. + +Reproduce steps: + +This can be reproduced by reloading a new table while the metadata +is read-only. While the second call to dm_cache_metadata_abort is +caused by lack of support for table preload in dm-cache, mentioned +in commit 9b1cc9f251af ("dm cache: share cache-metadata object across +inactive and active DM tables"), it exposes the memory leak in +dm_cache_metadata_abort when the function is called multiple times. +Specifically, dm-cache fails to sync the new cache object's mode during +preresume, creating the reproducer condition. + +This issue could also occur through concurrent metadata_operation_failed +calls due to races in cache mode updates, but the table preload scenario +below provides a reliable reproducer. + +1. Create a cache device with some faulty trailing metadata blocks + +dmsetup create cmeta < +unreferenced object 0xffff8880080c2010 (size 16): + comm "dmsetup", pid 132, jiffies 4294982580 + hex dump (first 16 bytes): + 00 38 b9 07 80 88 ff ff 6a 6b 6b 6b 6b 6b 6b a5 ... + backtrace (crc 3118f31c): + kmemleak_alloc+0x28/0x40 + __kmalloc_cache_noprof+0x3d9/0x510 + dm_block_manager_create+0x51/0x140 + dm_cache_metadata_abort+0x85/0x320 + metadata_operation_failed+0x103/0x1e0 + cache_preresume+0xacd/0xe70 + dm_table_resume_targets+0xd3/0x320 + __dm_resume+0x1b/0xf0 + dm_resume+0x127/0x170 + + +Fixes: 352b837a5541 ("dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 715ff419b63ba..43d271c358858 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1017,6 +1017,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd) + return; \ + } while(0) + ++#define WRITE_LOCK_OR_GOTO(cmd, label) \ ++ do { \ ++ if (!cmd_write_lock((cmd))) \ ++ goto label; \ ++ } while (0) ++ + #define WRITE_UNLOCK(cmd) \ + up_write(&(cmd)->root_lock) + +@@ -1815,11 +1821,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, + CACHE_MAX_CONCURRENT_LOCKS); + +- WRITE_LOCK(cmd); +- if (cmd->fail_io) { +- WRITE_UNLOCK(cmd); +- goto out; +- } ++ /* cmd_write_lock() already checks fail_io with cmd->root_lock held */ ++ WRITE_LOCK_OR_GOTO(cmd, out); + + __destroy_persistent_data_objects(cmd, false); + old_bm = cmd->bm; +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch b/queue-5.10/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch new file mode 100644 index 0000000000..ba242b1d86 --- /dev/null +++ b/queue-5.10/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch @@ -0,0 +1,91 @@ +From 4d76e3d5d842c95c10fdee86bb2b5869296fb4d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:08 +0800 +Subject: dm cache policy smq: fix missing locks in invalidating cache blocks + +From: Ming-Hung Tsai + +[ Upstream commit 2d1f7b65f5deedd2e6b09fdc6ea27f8375f24b45 ] + +In passthrough mode, the policy invalidate_mapping operation is called +simultaneously from multiple workers, thus it should be protected by a +lock. Otherwise, we might end up with data races on the allocated blocks +counter, or even use-after-free issues with internal data structures +when doing concurrent writes. + +Note that the existing FIXME in smq_invalidate_mapping() doesn't affect +passthrough mode since migration tasks don't exist there, but would need +attention if supporting fast device shrinking via suspend/resume without +target reloading. + +Reproduce steps: + +1. Create a cache device consisting of 1024 cache entries + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Populate the cache, and record the number of cached blocks + +fio --name=populate --filename=/dev/mapper/cache --rw=randwrite --bs=4k \ +--size=64m --direct=1 +nr_cached=$(dmsetup status cache | awk '{split($7, a, "/"); print a[1]}') + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the passthrough cache. By setting multiple jobs with I/O + size equal to the cache block size, cache blocks are invalidated + concurrently from different workers. + +fio --filename=/dev/mapper/cache --name=test --rw=randwrite --bs=64k \ +--direct=1 --numjobs=2 --randrepeat=0 --size=64m + +5. Check if demoted matches cached block count. These numbers should + match but may differ due to the data race. + +nr_demoted=$(dmsetup status cache | awk '{print $12}') +echo "$nr_cached, $nr_demoted" + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 859073193f5b4..95b0670c32acd 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1584,14 +1584,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + { + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); ++ unsigned long flags; + + if (!e->allocated) + return -ENODATA; + ++ spin_lock_irqsave(&mq->lock, flags); + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ spin_unlock_irqrestore(&mq->lock, flags); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-5.10/dm-cache-support-shrinking-the-origin-device.patch b/queue-5.10/dm-cache-support-shrinking-the-origin-device.patch new file mode 100644 index 0000000000..01059ab014 --- /dev/null +++ b/queue-5.10/dm-cache-support-shrinking-the-origin-device.patch @@ -0,0 +1,197 @@ +From b226d028dede57a4aeaa84bf4a55b416da32ffcc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 16:41:51 +0800 +Subject: dm cache: support shrinking the origin device + +From: Ming-Hung Tsai + +[ Upstream commit c2662b1544cbd8ea3181381bb899b8e681dfedc7 ] + +This patch introduces formal support for shrinking the cache origin by +reducing the cache target length via table reloads. Cache blocks mapped +beyond the new target length must be clean and are invalidated during +preresume. If any dirty blocks exist in the area being removed, the +preresume operation fails without setting the NEEDS_CHECK flag in +superblock, and the resume ioctl returns EFBIG. The cache device remains +suspended until a table reload with target length that fits existing +mappings is performed. + +Without this patch, reducing the cache target length could result in +io errors (RHBZ: 2134334), out-of-bounds memory access to the discard +bitset, and security concerns regarding data leakage. + +Verification steps: + +1. create a cache metadata with some cached blocks mapped to the tail + of the origin device. Here we use cache_restore v1.0 to build a + metadata with one clean block mapped to the last origin block. + +cat <> cmeta.xml + + + + + +EOF +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +cache_restore -i cmeta.xml -o /dev/mapper/cmeta --metadata-version=2 +dmsetup remove cmeta + +2. bring up the cache whilst shrinking the cache origin by one block: + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" +dmsetup create corig --table "0 524160 linear /dev/sdc 262144" +dmsetup create cache --table "0 524160 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +3. check the number of cached data blocks via dmsetup status. It is + expected to be zero. + +dmsetup status cache | cut -d ' ' -f 7 + +In addition to the script above, this patch can be verified using the +"cache/resize" tests in dmtest-python: + +./dmtest run --rx cache/resize/shrink_origin --result-set default + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Stable-dep-of: 322586745bd1 ("dm cache: fix dirty mapping checking in passthrough mode switching") +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 72 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 69 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index b659fa412a7ad..e7931a8204f48 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -475,6 +475,12 @@ struct cache { + mempool_t migration_pool; + + struct bio_set bs; ++ ++ /* ++ * Cache_size entries. Set bits indicate blocks mapped beyond the ++ * target length, which are marked for invalidation. ++ */ ++ unsigned long *invalid_bitset; + }; + + struct per_bio_data { +@@ -1988,6 +1994,9 @@ static void __destroy(struct cache *cache) + if (cache->discard_bitset) + free_bitset(cache->discard_bitset); + ++ if (cache->invalid_bitset) ++ free_bitset(cache->invalid_bitset); ++ + if (cache->copier) + dm_kcopyd_client_destroy(cache->copier); + +@@ -2576,6 +2585,13 @@ static int cache_create(struct cache_args *ca, struct cache **result) + } + clear_bitset(cache->discard_bitset, from_dblock(cache->discard_nr_blocks)); + ++ cache->invalid_bitset = alloc_bitset(from_cblock(cache->cache_size)); ++ if (!cache->invalid_bitset) { ++ *error = "could not allocate bitset for invalid blocks"; ++ goto bad; ++ } ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + cache->copier = dm_kcopyd_client_create(&dm_kcopyd_throttle); + if (IS_ERR(cache->copier)) { + *error = "could not create kcopyd client"; +@@ -2879,6 +2895,24 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + return 0; + } + ++static int load_filtered_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, ++ bool dirty, uint32_t hint, bool hint_valid) ++{ ++ struct cache *cache = context; ++ ++ if (from_oblock(oblock) >= from_oblock(cache->origin_blocks)) { ++ if (dirty) { ++ DMERR("%s: unable to shrink origin; cache block %u is dirty", ++ cache_device_name(cache), from_cblock(cblock)); ++ return -EFBIG; ++ } ++ set_bit(from_cblock(cblock), cache->invalid_bitset); ++ return 0; ++ } ++ ++ return load_mapping(context, oblock, cblock, dirty, hint, hint_valid); ++} ++ + /* + * The discard block size in the on disk metadata is not + * neccessarily the same as we're currently using. So we have to +@@ -3033,6 +3067,24 @@ static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size) + return 0; + } + ++static int truncate_oblocks(struct cache *cache) ++{ ++ uint32_t nr_blocks = from_cblock(cache->cache_size); ++ uint32_t i; ++ int r; ++ ++ for_each_set_bit(i, cache->invalid_bitset, nr_blocks) { ++ r = dm_cache_remove_mapping(cache->cmd, to_cblock(i)); ++ if (r) { ++ DMERR_LIMIT("%s: invalidation failed; couldn't update on disk metadata", ++ cache_device_name(cache)); ++ return r; ++ } ++ } ++ ++ return 0; ++} ++ + static int cache_preresume(struct dm_target *ti) + { + int r = 0; +@@ -3057,11 +3109,25 @@ static int cache_preresume(struct dm_target *ti) + } + + if (!cache->loaded_mappings) { ++ /* ++ * The fast device could have been resized since the last ++ * failed preresume attempt. To be safe we start by a blank ++ * bitset for cache blocks. ++ */ ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + r = dm_cache_load_mappings(cache->cmd, cache->policy, +- load_mapping, cache); ++ load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ if (r != -EFBIG) ++ metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ return r; ++ } ++ ++ r = truncate_oblocks(cache); ++ if (r) { ++ metadata_operation_failed(cache, "dm_cache_remove_mapping", r); + return r; + } + +@@ -3511,7 +3577,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 2, 0}, ++ .version = {2, 3, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-5.10/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch b/queue-5.10/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch new file mode 100644 index 0000000000..4f99c06f00 --- /dev/null +++ b/queue-5.10/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch @@ -0,0 +1,81 @@ +From a215e38e22f8718e24d036bcc180bb3720cd1584 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:05:48 +0800 +Subject: dm log: fix out-of-bounds write due to region_count overflow + +From: Junrui Luo + +[ Upstream commit c20e36b7631d83e7535877f08af8b0af72c44b1a ] + +The local variable region_count in create_log_context() is declared as +unsigned int (32-bit), but dm_sector_div_up() returns sector_t (64-bit). +When a device-mapper target has a sufficiently large ti->len with a small +region_size, the division result can exceed UINT_MAX. The truncated +value is then used to calculate bitset_size, causing clean_bits, +sync_bits, and recovering_bits to be allocated far smaller than needed +for the actual number of regions. + +Subsequent log operations (log_set_bit, log_clear_bit, log_test_bit) use +region indices derived from the full untruncated region space, causing +out-of-bounds writes to kernel heap memory allocated by vmalloc. + +This can be reproduced by creating a mirror target whose region_count +overflows 32 bits: + + dmsetup create bigzero --table '0 8589934594 zero' + dmsetup create mymirror --table '0 8589934594 mirror \ + core 2 2 nosync 2 /dev/mapper/bigzero 0 \ + /dev/mapper/bigzero 0' + +The status output confirms the truncation (sync_count=1 instead of +4294967297, because 0x100000001 was truncated to 1): + + $ dmsetup status mymirror + 0 8589934594 mirror 2 254:1 254:1 1/4294967297 ... + +This leads to a kernel crash in core_in_sync: + + BUG: scheduling while atomic: (udev-worker)/9150/0x00000000 + RIP: 0010:core_in_sync+0x14/0x30 [dm_log] + CR2: 0000000000000008 + Fixing recursive fault but reboot is needed! + +Fix by widening the local region_count to sector_t and adding an +explicit overflow check before the value is assigned to lc->region_count. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-log.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c +index fe3a9473f3387..ade7e9a2b11b1 100644 +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -368,7 +368,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + + struct log_c *lc; + uint32_t region_size; +- unsigned int region_count; ++ sector_t region_count; + size_t bitset_size, buf_size; + int r; + char dummy; +@@ -397,6 +397,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + } + + region_count = dm_sector_div_up(ti->len, region_size); ++ if (region_count > UINT_MAX) { ++ DMWARN("region count exceeds limit of %u", UINT_MAX); ++ return -EINVAL; ++ } + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) { +-- +2.53.0 + diff --git a/queue-5.10/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch b/queue-5.10/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch new file mode 100644 index 0000000000..3c506ec5e4 --- /dev/null +++ b/queue-5.10/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch @@ -0,0 +1,37 @@ +From adcec1a201b46bcb57c7da89d88b5030d49fd79c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:41:38 -0500 +Subject: dmaengine: mxs-dma: Fix missing return value from + of_dma_controller_register() + +From: Frank Li + +[ Upstream commit ab2bf6d4c0a0152907b18d25c1b118ea5ea779df ] + +Propagate the return value of of_dma_controller_register() in probe() +instead of ignoring it. + +Fixes: a580b8c5429a6 ("dmaengine: mxs-dma: add dma support for i.MX23/28") +Signed-off-by: Frank Li +Link: https://patch.msgid.link/20260225-mxsdma-module-v3-2-8f798b13baa6@nxp.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mxs-dma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c +index dc147cc2436e9..5d34440b9e127 100644 +--- a/drivers/dma/mxs-dma.c ++++ b/drivers/dma/mxs-dma.c +@@ -827,6 +827,7 @@ static int mxs_dma_probe(struct platform_device *pdev) + if (ret) { + dev_err(mxs_dma->dma_device.dev, + "failed to register controller\n"); ++ return ret; + } + + dev_info(mxs_dma->dma_device.dev, "initialized\n"); +-- +2.53.0 + diff --git a/queue-5.10/documentation-fix-a-hugetlbfs-reservation-statement.patch b/queue-5.10/documentation-fix-a-hugetlbfs-reservation-statement.patch new file mode 100644 index 0000000000..b7d44a39e4 --- /dev/null +++ b/queue-5.10/documentation-fix-a-hugetlbfs-reservation-statement.patch @@ -0,0 +1,63 @@ +From b56ccdfdec7f5b99d4fc56841880f6bdf7c381df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 13:10:15 -0700 +Subject: Documentation: fix a hugetlbfs reservation statement + +From: Jane Chu + +[ Upstream commit 7a197d346a44384a1a858a98ef03766840e561d4 ] + +Documentation/mm/hugetlbfs_reserv.rst has + if (resv_needed <= (resv_huge_pages - free_huge_pages)) + resv_huge_pages += resv_needed; +which describes this code in gather_surplus_pages() + needed = (h->resv_huge_pages + delta) - h->free_huge_pages; + if (needed <= 0) { + h->resv_huge_pages += delta; + return 0; + } +which means if there are enough free hugepages to account for the new +reservation, simply update the global reservation count without +further action. + +But the description is backwards, it should be + if (resv_needed <= (free_huge_pages - resv_huge_pages)) +instead. + +Link: https://lkml.kernel.org/r/20260302201015.1824798-1-jane.chu@oracle.com +Fixes: 70bc0dc578b3 ("Documentation: vm, add hugetlbfs reservation overview") +Signed-off-by: Jane Chu +Cc: David Hildenbrand +Cc: Hillf Danton +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Oscar Salvador +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/vm/hugetlbfs_reserv.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/vm/hugetlbfs_reserv.rst b/Documentation/vm/hugetlbfs_reserv.rst +index f143954e0d056..1c238b10e1772 100644 +--- a/Documentation/vm/hugetlbfs_reserv.rst ++++ b/Documentation/vm/hugetlbfs_reserv.rst +@@ -157,7 +157,7 @@ are enough free huge pages to accommodate the reservation. If there are, + the global reservation count resv_huge_pages is adjusted something like the + following:: + +- if (resv_needed <= (resv_huge_pages - free_huge_pages)) ++ if (resv_needed <= (free_huge_pages - resv_huge_pages) + resv_huge_pages += resv_needed; + + Note that the global lock hugetlb_lock is held when checking and adjusting +-- +2.53.0 + diff --git a/queue-5.10/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch b/queue-5.10/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch new file mode 100644 index 0000000000..5e03028ae9 --- /dev/null +++ b/queue-5.10/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch @@ -0,0 +1,59 @@ +From 156dd4d53c67dcd6a55c1d29e3b0445e52fcfe01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:40:54 -0700 +Subject: drbd: Balance RCU calls in drbd_adm_dump_devices() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bart Van Assche + +[ Upstream commit 2b31e86387e60b3689339f0f0fbb4d3623d9d494 ] + +Make drbd_adm_dump_devices() call rcu_read_lock() before +rcu_read_unlock() is called. This has been detected by the Clang +thread-safety analyzer. + +Tested-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Cc: Andreas Gruenbacher +Fixes: a55bbd375d18 ("drbd: Backport the "status" command") +Signed-off-by: Bart Van Assche +Link: https://patch.msgid.link/20260326214054.284593-1-bvanassche@acm.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_nl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index 54f77b4a0b494..71326e6fb6177 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -3424,8 +3424,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + cb->args[0] = (long)resource; + } + } +@@ -3674,8 +3676,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + } + cb->args[0] = (long)resource; + } +-- +2.53.0 + diff --git a/queue-5.10/driver-core-device.h-remove-extern-from-function-pro.patch b/queue-5.10/driver-core-device.h-remove-extern-from-function-pro.patch new file mode 100644 index 0000000000..9219fae641 --- /dev/null +++ b/queue-5.10/driver-core-device.h-remove-extern-from-function-pro.patch @@ -0,0 +1,39 @@ +From 69454370e3ec53866ee73df2203e0ed1a5e97b8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Mar 2023 13:27:06 +0100 +Subject: driver core: device.h: remove extern from function prototypes + +From: Greg Kroah-Hartman + +[ Upstream commit f43243c66e5e9ad839d235f82a58e73a7e7612af ] + +The kernel coding style does not require 'extern' in function prototypes +in .h files, so remove them from include/linux/device.h as they are not +needed. + +Acked-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/20230324122711.2664537-1-gregkh@linuxfoundation.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/device.h | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/include/linux/device.h b/include/linux/device.h +index b2a2109b170c5..11709e3ee811f 100644 +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -1032,8 +1032,7 @@ void device_links_supplier_sync_state_pause(void); + void device_links_supplier_sync_state_resume(void); + void device_link_wait_removal(void); + +-extern __printf(3, 4) +-int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); ++__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); + + /* Create alias, so I can be autoloaded. */ + #define MODULE_ALIAS_CHARDEV(major,minor) \ +-- +2.53.0 + diff --git a/queue-5.10/driver-core-move-dev_err_probe-to-where-it-belogs.patch b/queue-5.10/driver-core-move-dev_err_probe-to-where-it-belogs.patch new file mode 100644 index 0000000000..77db2edb6b --- /dev/null +++ b/queue-5.10/driver-core-move-dev_err_probe-to-where-it-belogs.patch @@ -0,0 +1,54 @@ +From 17b8de30b72d51afe55643ab7dd4f4f89acae140 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Jul 2023 16:13:09 +0300 +Subject: driver core: Move dev_err_probe() to where it belogs + +From: Andy Shevchenko + +[ Upstream commit 9e0cace7a6254070159ebd86497eadc29ea307ca ] + +dev_err_probe() belongs to the printing API, hence +move the definition from device.h to dev_printk.h. + +There is no change to the callers at all, since: +1) implementation is located in the same core.c; +2) dev_printk.h is guaranteed to be included by device.h. + +Signed-off-by: Andy Shevchenko +Reviewed-by: Andi Shyti +Link: https://lore.kernel.org/r/20230721131309.16821-1-andriy.shevchenko@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/dev_printk.h | 2 ++ + include/linux/device.h | 2 -- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h +index 6f009559ee540..6a6a6baa10bac 100644 +--- a/include/linux/dev_printk.h ++++ b/include/linux/dev_printk.h +@@ -242,4 +242,6 @@ do { \ + WARN_ONCE(condition, "%s %s: " format, \ + dev_driver_string(dev), dev_name(dev), ## arg) + ++__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); ++ + #endif /* _DEVICE_PRINTK_H_ */ +diff --git a/include/linux/device.h b/include/linux/device.h +index 11709e3ee811f..77d6493c26a48 100644 +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -1032,8 +1032,6 @@ void device_links_supplier_sync_state_pause(void); + void device_links_supplier_sync_state_resume(void); + void device_link_wait_removal(void); + +-__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); +- + /* Create alias, so I can be autoloaded. */ + #define MODULE_ALIAS_CHARDEV(major,minor) \ + MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) +-- +2.53.0 + diff --git a/queue-5.10/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch b/queue-5.10/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch new file mode 100644 index 0000000000..a5737085f1 --- /dev/null +++ b/queue-5.10/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch @@ -0,0 +1,45 @@ +From 507e865833c5d0ecf564dcf00420d96f6e69ef4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:41 +0200 +Subject: drm/amd/display: Allow DCE link encoder without AUX registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ] + +Allow constructing the DCE link encoder without DDC, +which means the AUX registers array will be NULL. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 87f30b101af62590faf6020d106da07efdda199b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index 48bc459009547..f9d30fcfd052c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -994,7 +994,9 @@ void dce110_link_encoder_hw_init( + ASSERT(result == BP_RESULT_OK); + + } +- aux_initialize(enc110); ++ ++ if (enc110->aux_regs) ++ aux_initialize(enc110); + + /* reinitialize HPD. + * hpd_initialize() will pass DIG_FE id to HW context. +-- +2.53.0 + diff --git a/queue-5.10/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch b/queue-5.10/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch new file mode 100644 index 0000000000..0cee532e2c --- /dev/null +++ b/queue-5.10/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch @@ -0,0 +1,137 @@ +From 9fce47e58015d712f5bc34e28e5c0cb1d58e1d17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:44 +0200 +Subject: drm/amd/display: Read EDID from VBIOS embedded panel info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ] + +Some board manufacturers hardcode the EDID for the embedded +panel in the VBIOS. This EDID should be used when the panel +doesn't have a DDC. + +For reference, see the legacy non-DC display code: +amdgpu_atombios_encoder_get_lcd_info() + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364) +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ + .../display/include/grph_object_ctrl_defs.h | 4 ++ + 2 files changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index bd9c50b5e5ad3..d37ee8277480d 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1212,6 +1212,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( + return BP_RESULT_FAILURE; + } + ++static enum bp_result get_embedded_panel_extra_info( ++ struct bios_parser *bp, ++ struct embedded_panel_info *info, ++ const uint32_t table_offset) ++{ ++ uint8_t *record = bios_get_image(&bp->base, table_offset, 1); ++ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; ++ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ++ ++ while (*record != ATOM_RECORD_END_TYPE) { ++ switch (*record) { ++ case LCD_MODE_PATCH_RECORD_MODE_TYPE: ++ record += sizeof(ATOM_PATCH_RECORD_MODE); ++ break; ++ case LCD_RTS_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_RTS_RECORD); ++ break; ++ case LCD_CAP_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); ++ break; ++ case LCD_FAKE_EDID_PATCH_RECORD_TYPE: ++ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; ++ if (fake_edid_record->ucFakeEDIDLength) { ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength; ++ else ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength * 128; ++ ++ info->fake_edid = fake_edid_record->ucFakeEDIDString; ++ ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ info->fake_edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; ++ } ++ break; ++ case LCD_PANEL_RESOLUTION_RECORD_TYPE: ++ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; ++ info->panel_width_mm = panel_res_record->usHSize; ++ info->panel_height_mm = panel_res_record->usVSize; ++ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); ++ break; ++ default: ++ return BP_RESULT_BADBIOSTABLE; ++ } ++ } ++ ++ return BP_RESULT_OK; ++} ++ + static enum bp_result get_embedded_panel_info_v1_2( + struct bios_parser *bp, + struct embedded_panel_info *info) +@@ -1328,6 +1382,10 @@ static enum bp_result get_embedded_panel_info_v1_2( + if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) + info->lcd_timing.misc_info.API_ENABLED = true; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +@@ -1453,6 +1511,10 @@ static enum bp_result get_embedded_panel_info_v1_3( + (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & + lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +index 7a06e3914c004..9dabe372c4fd5 100644 +--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h ++++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +@@ -153,6 +153,10 @@ struct embedded_panel_info { + uint32_t drr_enabled; + uint32_t min_drr_refresh_rate; + bool realtek_eDPToLVDS; ++ uint16_t panel_width_mm; ++ uint16_t panel_height_mm; ++ uint16_t fake_edid_size; ++ const uint8_t *fake_edid; + }; + + struct dc_firmware_info { +-- +2.53.0 + diff --git a/queue-5.10/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch b/queue-5.10/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch new file mode 100644 index 0000000000..aa8489dbde --- /dev/null +++ b/queue-5.10/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch @@ -0,0 +1,38 @@ +From 3810b327f3fa8f119d8724d2071b6e746346d001 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:03 +0200 +Subject: drm/amd/pm/ci: Clear EnabledForActivity field for memory levels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 5facfd4c4c67e8500116ffec0d9da35d92b9c787 ] + +Follow what radeon did and what amdgpu does for other GPUs with SMU7. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 04e2e7e44e7ce..fbca5e798b851 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1216,7 +1216,7 @@ static int ci_populate_single_memory_level( + } + + memory_level->EnabledForThrottle = 1; +- memory_level->EnabledForActivity = 1; ++ memory_level->EnabledForActivity = 0; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; + memory_level->VoltageDownH = 0; +-- +2.53.0 + diff --git a/queue-5.10/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch b/queue-5.10/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch new file mode 100644 index 0000000000..6af9388989 --- /dev/null +++ b/queue-5.10/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch @@ -0,0 +1,67 @@ +From 1a75e05951acb78c2907b49024ac823b818e9527 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:59 +0200 +Subject: drm/amd/pm/ci: Disable MCLK DPM on problematic CI ASICs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9851f29cb06c09f7dad3867d8b0feec3fc71b6c8 ] + +There are two known cases where MCLK DPM can causes issues: + +Radeon R9 M380 found in iMac computers from 2015. +The SMU in this GPU just hangs as soon as we send it the +PPSMC_MSG_MCLKDPM_Enable command, even when MCLK switching is +disabled, and even when we only populate one MCLK DPM level. +Apply workaround to all devices with the same subsystem ID. + +Radeon R7 260X due to old memory controller microcode. +We only flash the MC ucode when it isn't set up by the VBIOS, +therefore there is no way to make sure that it has the correct +ucode version. + +I verified that this patch fixes the SMU hang on the R9 M380 +which would previously fail to boot. This also fixes the UVD +initialization error on that GPU which happened because the +SMU couldn't ungate the UVD after it hung. + +Fixes: 86457c3b21cb ("drm/amd/powerplay: Add support for CI asics to hwmgr") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +index f48fdc7f0382e..974a17a953249 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -108,6 +108,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) + PP_GFXOFF_MASK); + hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; ++ switch (hwmgr->chip_id) { ++ case CHIP_BONAIRE: ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM ++ * R7 260X cards with old MC ucode: MCLK DPM is unstable ++ */ ++ if (adev->pdev->subsystem_vendor == 0x106B || ++ adev->pdev->device == 0x6658) { ++ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); ++ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; ++ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; ++ } ++ break; ++ default: ++ break; ++ } + smu7_init_function_pointers(hwmgr); + break; + case AMDGPU_FAMILY_CZ: +-- +2.53.0 + diff --git a/queue-5.10/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch b/queue-5.10/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch new file mode 100644 index 0000000000..ee11bbe7d2 --- /dev/null +++ b/queue-5.10/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch @@ -0,0 +1,48 @@ +From fbeb606cb0f2729216ea63e1050c14251aa19e1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:04 +0200 +Subject: drm/amd/pm/ci: Fill DW8 fields from SMC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit baf28ec5795c077406d6f52b8ad39e614153bce6 ] + +In ci_populate_dw8() we currently just read a value from the SMU +and then throw it away. Instead of throwing away the value, +we should use it to fill other fields in DW8 (like radeon). + +Otherwise the value of the other fiels is just cleared when +we copy this data to the SMU later. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index fbca5e798b851..b135e4a1f8ee2 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -542,12 +542,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) + { + struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); + const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; +- uint32_t temp; + + if (ci_read_smc_sram_dword(hwmgr, + fuse_table_offset + + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), +- (uint32_t *)&temp, SMC_RAM_END)) ++ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) + PP_ASSERT_WITH_CODE(false, + "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", + return -EINVAL); +-- +2.53.0 + diff --git a/queue-5.10/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch b/queue-5.10/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch new file mode 100644 index 0000000000..4a4c9a3f9a --- /dev/null +++ b/queue-5.10/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch @@ -0,0 +1,41 @@ +From 7d787b94469788e93ce1a41a7bad5ef5ed8ebb56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:02 +0200 +Subject: drm/amd/pm/ci: Fix powertune defaults for Hawaii 0x67B0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit d784759c07924280f3c313f205fc48eb62d7cb71 ] + +There is no AMD GPU with the ID 0x66B0, this looks like a typo. +It should be 0x67B0 which is actually part of the PCI ID list, +and should use the Hawaii XT powertune defaults according to +the old radeon driver. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 581ade4111426..04e2e7e44e7ce 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -244,7 +244,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) + smu_data->power_tune_defaults = &defaults_hawaii_pro; + break; + case 0x67B8: +- case 0x66B0: ++ case 0x67B0: + smu_data->power_tune_defaults = &defaults_hawaii_xt; + break; + case 0x6640: +-- +2.53.0 + diff --git a/queue-5.10/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch b/queue-5.10/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch new file mode 100644 index 0000000000..5005de7142 --- /dev/null +++ b/queue-5.10/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch @@ -0,0 +1,47 @@ +From f1bbc425846c528a612eb962ab717d8f553c08a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:58 +0200 +Subject: drm/amd/pm/ci: Use highest MCLK on CI when MCLK DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 894f0d34d66cb47fe718fe2ae5c18729d22c5218 ] + +When MCLK DPM is disabled for any reason, populate the MCLK +table with the highest MCLK DPM level, so that the ASIC can +use the highest possible memory clock to get good performance +even when MCLK DPM is disabled. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index a6096b65168e9..581ade4111426 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1321,6 +1321,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) + return result; + } + ++ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { ++ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ ++ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { ++ levels[i] = levels[dpm_table->mclk_table.count - 1]; ++ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; ++ } ++ } ++ + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; + + dev_id = adev->pdev->device; +-- +2.53.0 + diff --git a/queue-5.10/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch b/queue-5.10/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch new file mode 100644 index 0000000000..fe2948f86a --- /dev/null +++ b/queue-5.10/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch @@ -0,0 +1,146 @@ +From 1a4ef04aef3e674c1a44d108bc7a31c8655da9a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:33 +0200 +Subject: drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ] + +This commit fixes amdgpu to work on the Radeon HD 7870 XT +which has never worked with the Linux open source drivers before. + +Some boards have "harvested" chips, meaning that some parts of +the chip are disabled and fused, and it's sold for cheaper and +under a different marketing name. +On a harvested chip, any of the following can be disabled: +- CUs (Compute Units) +- RBs (Render Backend, aka. ROP) +- Memory channels (ie. the chip has a lower bandwidth) +- TCCs (ie. less L2 cache) + +Handle chips with harvested TCCs by patching the registers +that configure how TCCs are mapped. + +If some TCCs are disabled, we need to make sure that +the disabled TCCs are not used, and the remaining TCCs +are used optimally. + +TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. + +Note that the TCC configuration is highly relevant to performance. +Suboptimal configuration (eg. CHAN_STEER=0) can significantly +reduce gaming performance. + +For optimal performance: +- Rely on the CHAN_STEER from the golden registers table, + only skip disabled TCCs but keep the mapping order. +- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, + which performs better than using the same TCC twice. + +v2: +- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs. + +Link: https://bugs.freedesktop.org/show_bug.cgi?id=60879 +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2664 +Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 00218d15528fab9f6b31241fe5904eea4fcaa30d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index d447b2416b98b..5e23c717279d6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -1568,6 +1568,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) + mutex_unlock(&adev->grbm_idx_mutex); + } + ++/** ++ * gfx_v6_0_setup_tcc() - setup which TCCs are used ++ * ++ * @adev: amdgpu_device pointer ++ * ++ * Verify whether the current GPU has any TCCs disabled, ++ * which can happen when the GPU is harvested and some ++ * memory channels are disabled, reducing the memory bus width. ++ * For example, on the Radeon HD 7870 XT (Tahiti LE). ++ * ++ * If some TCCs are disabled, we need to make sure that ++ * the disabled TCCs are not used, and the remaining TCCs ++ * are used optimally. ++ * ++ * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. ++ * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. ++ * ++ * For optimal performance: ++ * - Rely on the CHAN_STEER from the golden registers table, ++ * only skip disabled TCCs but keep the mapping order. ++ * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, ++ * which performs better than using the same TCC twice. ++ */ ++static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) ++{ ++ u32 i, tcc, tcp_addr_config, num_active_tcc = 0; ++ u64 chan_steer, patched_chan_steer = 0; ++ const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; ++ const u32 dis_tcc_mask = ++ amdgpu_gfx_create_bitmask(num_max_tcc) & ++ (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), ++ CGTS_TCC_DISABLE, TCC_DISABLE) | ++ REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), ++ CGTS_USER_TCC_DISABLE, TCC_DISABLE)); ++ ++ /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ ++ if (!dis_tcc_mask) ++ return; ++ ++ /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ ++ chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); ++ ++ /* Patch the TCP to TCC mapping to skip disabled TCCs */ ++ for (i = 0; i < num_max_tcc; ++i) { ++ tcc = (chan_steer >> (u64)(4 * i)) & 0xf; ++ ++ if (!((1 << tcc) & dis_tcc_mask)) { ++ /* Copy enabled TCC indices to the patched register value. */ ++ patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); ++ ++num_active_tcc; ++ } ++ } ++ ++ WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); ++ ++ /* Patch number of TCCs used by TCPs */ ++ tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), ++ TCP_ADDR_CONFIG, NUM_TCC_BANKS, ++ num_active_tcc - 1); ++ ++ WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); ++ WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); ++ WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); ++} ++ + static void gfx_v6_0_config_init(struct amdgpu_device *adev) + { + adev->gfx.config.double_offchip_lds_buf = 0; +@@ -1726,6 +1791,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) + gfx_v6_0_tiling_mode_table_init(adev); + + gfx_v6_0_setup_rb(adev); ++ gfx_v6_0_setup_tcc(adev); + + gfx_v6_0_setup_spi(adev); + +-- +2.53.0 + diff --git a/queue-5.10/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch b/queue-5.10/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch new file mode 100644 index 0000000000..73dc460ec4 --- /dev/null +++ b/queue-5.10/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch @@ -0,0 +1,60 @@ +From df48fa28f9ec9d44a2d69319c2b8d7cdeeeec21a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:48:46 +0300 +Subject: drm/komeda: fix integer overflow in AFBC framebuffer size check + +From: Alexander Konyukhov + +[ Upstream commit 779ec12c85c9e4547519e3903a371a3b26a289de ] + +The AFBC framebuffer size validation calculates the minimum required +buffer size by adding the AFBC payload size to the framebuffer offset. +This addition is performed without checking for integer overflow. + +If the addition oveflows, the size check may incorrectly succed and +allow userspace to provide an undersized drm_gem_object, potentially +leading to out-of-bounds memory access. + +Add usage of check_add_overflow() to safely compute the minimum +required size and reject the framebuffer if an overflow is detected. +This makes the AFBC size validation more robust against malformed. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 65ad2392dd6d ("drm/komeda: Added AFBC support for komeda driver") +Signed-off-by: Alexander Konyukhov +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://lore.kernel.org/r/20260203134907.1587067-1-Alexander.Konyukhov@kaspersky.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +index 170f9dc8ec19c..9ca65f94503fb 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +@@ -4,6 +4,8 @@ + * Author: James.Qian.Wang + * + */ ++#include ++ + #include + #include + #include +@@ -92,7 +94,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file, + kfb->afbc_size = kfb->offset_payload + n_blocks * + ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, + AFBC_SUPERBLK_ALIGNMENT); +- min_size = kfb->afbc_size + fb->offsets[0]; ++ if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) { ++ goto check_failed; ++ } + if (min_size > obj->size) { + DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n", + obj->size, min_size); +-- +2.53.0 + diff --git a/queue-5.10/drm-msm-a6xx-fix-hlsq-register-dumping.patch b/queue-5.10/drm-msm-a6xx-fix-hlsq-register-dumping.patch new file mode 100644 index 0000000000..4badc57c5a --- /dev/null +++ b/queue-5.10/drm-msm-a6xx-fix-hlsq-register-dumping.patch @@ -0,0 +1,39 @@ +From 26e532d1100eb99a31e96b167c402ad45f802e52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:40:42 -0700 +Subject: drm/msm/a6xx: Fix HLSQ register dumping + +From: Rob Clark + +[ Upstream commit c289a6db9ba6cb974f0317da142e4f665d589566 ] + +Fix the bitfield offset of HLSQ_READ_SEL state-type bitfield. Otherwise +we are always reading TP state when we wanted SP or HLSQ state. + +Reported-by: Connor Abbott +Suggested-by: Connor Abbott +Fixes: 1707add81551 ("drm/msm/a6xx: Add a6xx gpu state") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714236/ +Message-ID: <20260325184043.1259312-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 0db27699025ab..6e9a3f843b3f5 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -642,7 +642,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, + u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; + int i, regcount = 0; + +- in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); ++ in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); + + for (i = 0; i < regs->count; i += 2) { + u32 count = RANGE(regs->registers, i); +-- +2.53.0 + diff --git a/queue-5.10/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch b/queue-5.10/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch new file mode 100644 index 0000000000..5a6cc61f61 --- /dev/null +++ b/queue-5.10/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch @@ -0,0 +1,72 @@ +From e3a31ce954e169117d0c2cd7772950c977924d46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:50 +0530 +Subject: drm/msm/a6xx: Use barriers while updating HFI Q headers + +From: Akhil P Oommen + +[ Upstream commit dc78b35d5ec09d1b0b8a937e6e640d2c5a030915 ] + +To avoid harmful compiler optimizations and IO reordering in the HW, use +barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI +queue index variables. + +Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714653/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-1-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +index 8bcf87726ec66..9c3f88959b8c5 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +@@ -29,7 +29,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + struct a6xx_hfi_queue_header *header = queue->header; + u32 i, hdr, index = header->read_index; + +- if (header->read_index == header->write_index) { ++ if (header->read_index == READ_ONCE(header->write_index)) { + header->rx_request = 1; + return 0; + } +@@ -55,7 +55,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + if (!gmu->legacy) + index = ALIGN(index, 4) % header->size; + +- header->read_index = index; ++ /* Ensure all memory operations are complete before updating the read index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->read_index, index); + return HFI_HEADER_SIZE(hdr); + } + +@@ -67,7 +70,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + + spin_lock(&queue->lock); + +- space = CIRC_SPACE(header->write_index, header->read_index, ++ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), + header->size); + if (space < dwords) { + header->dropped++; +@@ -86,7 +89,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + queue->data[index] = 0xfafafafa; + } + +- header->write_index = index; ++ /* Ensure all memory operations are complete before updating the write index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->write_index, index); + spin_unlock(&queue->lock); + + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); +-- +2.53.0 + diff --git a/queue-5.10/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch b/queue-5.10/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch new file mode 100644 index 0000000000..e7720954b4 --- /dev/null +++ b/queue-5.10/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch @@ -0,0 +1,62 @@ +From d137329f0c1a0e2ff7a38feedb2203df0fa74ada Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:48:27 +0000 +Subject: drm/msm/dsi: rename MSM8998 DSI version from V2_2_0 to V2_0_0 + +From: Alexander Koskovich + +[ Upstream commit 913a709dea0eff9c7b2e9470f8c8594b9a0114ab ] + +The MSM8998 DSI controller is v2.0.0 as stated in commit 7b8c9e203039 +("drm/msm/dsi: Add support for MSM8998 DSI controller"). The value was +always correct just the name was wrong. + +Rename and reorder to maintain version sorting. + +Fixes: 7b8c9e203039 ("drm/msm/dsi: Add support for MSM8998 DSI controller") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Alexander Koskovich +Patchwork: https://patchwork.freedesktop.org/patch/713717/ +Link: https://lore.kernel.org/r/20260324-dsi-rgb101010-support-v5-3-ff6afc904115@pm.me +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_cfg.c | 4 ++-- + drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +index 73f066ef6f406..310b568c38664 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +@@ -258,10 +258,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { + &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, + &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, ++ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, ++ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, + &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, +- {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, +- &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +index ade9b609c7d98..89386b10dc48b 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +@@ -18,8 +18,8 @@ + #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 + #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 + #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 ++#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 +-#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 + #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 + #define MSM_DSI_6G_VER_MINOR_V2_4_0 0x20040000 +-- +2.53.0 + diff --git a/queue-5.10/drm-panel-simple-correct-g190ean01-prepare-timing.patch b/queue-5.10/drm-panel-simple-correct-g190ean01-prepare-timing.patch new file mode 100644 index 0000000000..d619c92658 --- /dev/null +++ b/queue-5.10/drm-panel-simple-correct-g190ean01-prepare-timing.patch @@ -0,0 +1,41 @@ +From 54a7a27857f0f2763f05e21aa8a3f66afe7c97cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 16:25:26 +0200 +Subject: drm/panel: simple: Correct G190EAN01 prepare timing + +From: Sebastian Reichel + +[ Upstream commit f1080f82570b797598c1ba7e9c800ae9e94aafc6 ] + +The prepare timing specified by the G190EAN01 datasheet should be +between 30 and 50 ms. Considering it might take some time for the +LVDS encoder to enable the signal, we should only wait the min. +required time in the panel driver and not the max. allowed time. + +Fixes: 2f7b832fc992 ("drm/panel: simple: Add support for AUO G190EAN01 panel") +Signed-off-by: Sebastian Reichel +Signed-off-by: Ian Ray +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260217142528.68613-1-ian.ray@gehealthcare.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-simple.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index d4bd72347245a..a59adc08267f5 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1140,7 +1140,7 @@ static const struct panel_desc auo_g190ean01 = { + .height = 301, + }, + .delay = { +- .prepare = 50, ++ .prepare = 30, + .enable = 200, + .disable = 110, + .unprepare = 1000, +-- +2.53.0 + diff --git a/queue-5.10/drm-sun4i-backend-fix-error-pointer-dereference.patch b/queue-5.10/drm-sun4i-backend-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..474614469d --- /dev/null +++ b/queue-5.10/drm-sun4i-backend-fix-error-pointer-dereference.patch @@ -0,0 +1,43 @@ +From 91464409909869841167e338c078f758fa3efd6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 19:48:01 -0600 +Subject: drm/sun4i: backend: fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit 06277983eca4a31d3c2114fa33d99a6e82484b11 ] + +The function drm_atomic_get_plane_state() can return an error pointer +and is not checked for it. Add error pointer check. + +Detected by Smatch: +drivers/gpu/drm/sun4i/sun4i_backend.c:496 sun4i_backend_atomic_check() error: +'plane_state' dereferencing possible ERR_PTR() + +Fixes: 96180dde23b79 ("drm/sun4i: backend: Add a custom atomic_check for the frontend") +Signed-off-by: Ethan Tidmore +Reviewed-by: Chen-Yu Tsai +Link: https://patch.msgid.link/20260217014801.60760-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index 55960cbb10190..c65b10d413879 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -507,6 +507,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, + drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); ++ if (IS_ERR(plane_state)) ++ return PTR_ERR(plane_state); ++ + struct sun4i_layer_state *layer_state = + state_to_sun4i_layer_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; +-- +2.53.0 + diff --git a/queue-5.10/drm-sun4i-fix-resource-leaks.patch b/queue-5.10/drm-sun4i-fix-resource-leaks.patch new file mode 100644 index 0000000000..7140bbc870 --- /dev/null +++ b/queue-5.10/drm-sun4i-fix-resource-leaks.patch @@ -0,0 +1,41 @@ +From cd4e2102b49970ed04fa85756b81207975e5d232 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:38:36 -0600 +Subject: drm/sun4i: Fix resource leaks + +From: Ethan Tidmore + +[ Upstream commit 127367ad2e0f4870de60c6d719ae82ecf68d674c ] + +Three clocks are not being released in devm_regmap_init_mmio() error +path. + +Add proper goto and set ret to the error code. + +Fixes: 8270249fbeaf0 ("drm/sun4i: backend: Create regmap after access is possible") +Signed-off-by: Ethan Tidmore +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260226163836.10335-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index c65b10d413879..b3741827c6c3a 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -900,7 +900,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, + &sun4i_backend_regmap_config); + if (IS_ERR(backend->engine.regs)) { + dev_err(dev, "Couldn't create the backend regmap\n"); +- return PTR_ERR(backend->engine.regs); ++ ret = PTR_ERR(backend->engine.regs); ++ goto err_disable_ram_clk; + } + + list_add_tail(&backend->engine.list, &drv->engine_list); +-- +2.53.0 + diff --git a/queue-5.10/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch b/queue-5.10/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch new file mode 100644 index 0000000000..193be99fea --- /dev/null +++ b/queue-5.10/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch @@ -0,0 +1,52 @@ +From b5e9445692173edb7518e60823118bfbeaf6514b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:25 +0100 +Subject: dt-bindings: clock: qcom,dispcc-sc7180: Define MDSS resets + +From: Konrad Dybcio + +[ Upstream commit fc6e29d42872680dca017f2e5169eefe971f8d89 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: 75616da71291 ("dt-bindings: clock: Introduce QCOM sc7180 display clock bindings") +Signed-off-by: Konrad Dybcio +Reviewed-by: Taniya Das +Acked-by: Krzysztof Kozlowski +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-1-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: b0bc6011c549 ("clk: qcom: dispcc-sc7180: Add missing MDSS resets") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,dispcc-sc7180.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/dt-bindings/clock/qcom,dispcc-sc7180.h b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +index b9b51617a335d..0705103060748 100644 +--- a/include/dt-bindings/clock/qcom,dispcc-sc7180.h ++++ b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +@@ -6,6 +6,7 @@ + #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + ++/* Clocks */ + #define DISP_CC_PLL0 0 + #define DISP_CC_PLL0_OUT_EVEN 1 + #define DISP_CC_MDSS_AHB_CLK 2 +@@ -40,7 +41,11 @@ + #define DISP_CC_MDSS_VSYNC_CLK_SRC 31 + #define DISP_CC_XO_CLK 32 + +-/* DISP_CC GDSCR */ ++/* Resets */ ++#define DISP_CC_MDSS_CORE_BCR 0 ++#define DISP_CC_MDSS_RSCC_BCR 1 ++ ++/* GDSCs */ + #define MDSS_GDSC 0 + + #endif +-- +2.53.0 + diff --git a/queue-5.10/e1000e-unroll-ptp-in-probe-error-handling.patch b/queue-5.10/e1000e-unroll-ptp-in-probe-error-handling.patch new file mode 100644 index 0000000000..d00c82c8cb --- /dev/null +++ b/queue-5.10/e1000e-unroll-ptp-in-probe-error-handling.patch @@ -0,0 +1,41 @@ +From 0c2e36e5d7447a55fa8f44d6379b0210c601d90b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:36 -0700 +Subject: e1000e: Unroll PTP in probe error handling + +From: Matt Vollrath + +[ Upstream commit aa3f7fe409350857c25d050482a2eef2cfd69b58 ] + +If probe fails after registering the PTP clock and its delayed work, +these resources must be released. + +This was not an issue until a 2016 fix moved the e1000e_ptp_init() call +before the jump to err_register. + +Fixes: aa524b66c5ef ("e1000e: don't modify SYSTIM registers during SIOCSHWTSTAMP ioctl") +Signed-off-by: Matt Vollrath +Tested-by: Avigail Dahan +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-12-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 902ada6a3b06c..8f1c6f08be00e 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -7642,6 +7642,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + err_register: + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000e_release_hw_control(adapter); ++ e1000e_ptp_remove(adapter); + err_eeprom: + if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) + e1000_phy_hw_reset(&adapter->hw); +-- +2.53.0 + diff --git a/queue-5.10/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch b/queue-5.10/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch new file mode 100644 index 0000000000..723c4ecee7 --- /dev/null +++ b/queue-5.10/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch @@ -0,0 +1,52 @@ +From 0c19d077dc567043c7c56bc1b8f27dba5811195b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:46:37 +0200 +Subject: efi/capsule-loader: fix incorrect sizeof in phys array reallocation + +From: Thomas Huth + +[ Upstream commit 48a428215782321b56956974f23593e40ce84b7a ] + +The krealloc() call for cap_info->phys in __efi_capsule_setup_info() uses +sizeof(phys_addr_t *) instead of sizeof(phys_addr_t), which might be +causing an undersized allocation. + +The allocation is also inconsistent with the initial array allocation in +efi_capsule_open() that allocates one entry with sizeof(phys_addr_t), +and the efi_capsule_write() function that stores phys_addr_t values (not +pointers) via page_to_phys(). + +On 64-bit systems where sizeof(phys_addr_t) == sizeof(phys_addr_t *), this +goes unnoticed. On 32-bit systems with PAE where phys_addr_t is 64-bit but +pointers are 32-bit, this allocates half the required space, which might +lead to a heap buffer overflow when storing physical addresses. + +This is similar to the bug fixed in commit fccfa646ef36 ("efi/capsule-loader: +fix incorrect allocation size") which fixed the same issue at the initial +allocation site. + +Fixes: f24c4d478013 ("efi/capsule-loader: Reinstate virtual capsule mapping") +Assisted-by: Claude:claude-sonnet-4-5 +Signed-off-by: Thomas Huth +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + drivers/firmware/efi/capsule-loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c +index 97bafb5f70389..c6a8bdbcae71b 100644 +--- a/drivers/firmware/efi/capsule-loader.c ++++ b/drivers/firmware/efi/capsule-loader.c +@@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) + cap_info->pages = temp_page; + + temp_page = krealloc(cap_info->phys, +- pages_needed * sizeof(phys_addr_t *), ++ pages_needed * sizeof(phys_addr_t), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-5.10/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch b/queue-5.10/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch new file mode 100644 index 0000000000..a50cdcbc39 --- /dev/null +++ b/queue-5.10/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch @@ -0,0 +1,71 @@ +From f7e5545739c47e42def711d1ff6c733e8f55eeb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 15:36:46 +0100 +Subject: fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build + break + +From: Andy Shevchenko + +[ Upstream commit caf6144053b4e1c815aa56afb54745a176f999df ] + +Clang is not happy about set but unused variable: + +drivers/video/fbdev/matrox/g450_pll.c:412:18: error: variable 'mnp' set but not used + 412 | unsigned int mnp; + | ^ +1 error generated. + +Since the commit 7b987887f97b ("video: fbdev: matroxfb: remove dead code +and set but not used variable") the 'mnp' became unused, but eliminating +that code might have side-effects. The question here is what should we do +with 'mnp'? The easiest way out is just mark it with __maybe_unused which +will shut the compiler up and won't change any possible IO flow. So does +this change. + +A dive into the history of the driver: + +The problem was revealed when the #if 0 guarded code along with unused +pixel_vco variable was removed. That code was introduced in the original +commit 213d22146d1f ("[PATCH] (1/3) matroxfb for 2.5.3"). And then guarded +in the commit 705e41f82988 ("matroxfb DVI updates: Handle DVI output on +G450/G550. Powerdown unused portions of G450/G550 DAC. Split G450/G550 DAC +from older DAC1064 handling. Modify PLL setting when both CRTCs use same +pixel clocks."). + +NOTE: The two commits mentioned above pre-date Git era and available in +history.git repository for archaeological purposes. + +Even without that guard the modern compilers may see that the pixel_vco +wasn't ever used and seems a leftover after some debug or review made +25 years ago. + +The g450_mnp2vco() doesn't have any IO and as Jason said doesn't seem +to have any side effects either than some unneeded CPU processing during +runtime. I agree that's unlikely that timeout (or heating up the CPU) has +any effect on the HW (GPU/display) functionality. + +Fixes: 7b987887f97b ("video: fbdev: matroxfb: remove dead code and set but not used variable") +Signed-off-by: Andy Shevchenko +Reviewed-by: Jason Yan +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/matrox/g450_pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c +index ff8e321a22cef..b2d3f7328ea83 100644 +--- a/drivers/video/fbdev/matrox/g450_pll.c ++++ b/drivers/video/fbdev/matrox/g450_pll.c +@@ -407,7 +407,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, + case M_VIDEO_PLL: + { + u_int8_t tmp; +- unsigned int mnp; ++ unsigned int mnp __maybe_unused; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); +-- +2.53.0 + diff --git a/queue-5.10/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch b/queue-5.10/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch new file mode 100644 index 0000000000..f62904512e --- /dev/null +++ b/queue-5.10/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch @@ -0,0 +1,52 @@ +From def3b1fd6ab707c75bfcd393cd6385961a8548f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:01:18 -0400 +Subject: fbdev: offb: fix PCI device reference leak on probe failure + +From: Yuho Choi + +[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ] + +offb_init_nodriver() gets a referenced PCI device with pci_get_device(). +If pci_enable_device() fails, the function returns without dropping that +reference. + +Release the PCI device reference before returning from the +pci_enable_device() failure path. + +Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/offb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c +index 4501e848a36f2..593aad22248e6 100644 +--- a/drivers/video/fbdev/offb.c ++++ b/drivers/video/fbdev/offb.c +@@ -643,8 +643,13 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) + vid = be32_to_cpup(vidp); + did = be32_to_cpup(didp); + pdev = pci_get_device(vid, did, NULL); +- if (!pdev || pci_enable_device(pdev)) ++ if (!pdev) + return; ++ ++ if (pci_enable_device(pdev)) { ++ pci_dev_put(pdev); ++ return; ++ } + } + #endif + /* kludge for valkyrie */ +-- +2.53.0 + diff --git a/queue-5.10/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch b/queue-5.10/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch new file mode 100644 index 0000000000..a723506367 --- /dev/null +++ b/queue-5.10/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch @@ -0,0 +1,63 @@ +From 4b2fc7245a7d1b3a88789824c6050d073bae0b32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 08:10:20 -0600 +Subject: firmware: dmi: Correct an indexing error in dmi.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit c064abc68e009d2cc18416e7132d9c25e03125b6 ] + +The entries later in enum dmi_entry_type don't match the SMBIOS +specification¹. + +The entry for type 33: `64-Bit Memory Error Information` is not present and +thus the index for all later entries is incorrect. + +Add it. + +Also, add missing entry types 43-46, while at it. + + ¹ Search for "System Management BIOS (SMBIOS) Reference Specification" + + [ bp: Drop the flaky SMBIOS spec URL. ] + +Fixes: 93c890dbe5287 ("firmware: Add DMI entry types to the headers") +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Jean Delvare +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20260307141024.819807-2-superm1@kernel.org +Signed-off-by: Sasha Levin +--- + include/linux/dmi.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/dmi.h b/include/linux/dmi.h +index 927f8a8b7a1dd..2eedf44e68012 100644 +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -60,6 +60,7 @@ enum dmi_entry_type { + DMI_ENTRY_OOB_REMOTE_ACCESS, + DMI_ENTRY_BIS_ENTRY, + DMI_ENTRY_SYSTEM_BOOT, ++ DMI_ENTRY_64_MEM_ERROR, + DMI_ENTRY_MGMT_DEV, + DMI_ENTRY_MGMT_DEV_COMPONENT, + DMI_ENTRY_MGMT_DEV_THRES, +@@ -69,6 +70,10 @@ enum dmi_entry_type { + DMI_ENTRY_ADDITIONAL, + DMI_ENTRY_ONBOARD_DEV_EXT, + DMI_ENTRY_MGMT_CONTROLLER_HOST, ++ DMI_ENTRY_TPM_DEVICE, ++ DMI_ENTRY_PROCESSOR_ADDITIONAL, ++ DMI_ENTRY_FIRMWARE_INVENTORY, ++ DMI_ENTRY_STRING_PROPERTY, + DMI_ENTRY_INACTIVE = 126, + DMI_ENTRY_END_OF_TABLE = 127, + }; +-- +2.53.0 + diff --git a/queue-5.10/flow_dissector-add-number-of-vlan-tags-dissector.patch b/queue-5.10/flow_dissector-add-number-of-vlan-tags-dissector.patch new file mode 100644 index 0000000000..fa3491357a --- /dev/null +++ b/queue-5.10/flow_dissector-add-number-of-vlan-tags-dissector.patch @@ -0,0 +1,119 @@ +From ebccb8401494e2a2226addf79b803cb919aa1548 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Apr 2022 11:14:32 +0300 +Subject: flow_dissector: Add number of vlan tags dissector + +From: Boris Sukholitko + +[ Upstream commit 34951fcf26c59e78ae430fba1fce7c08b1871249 ] + +Our customers in the fiber telecom world have network configurations +where they would like to control their traffic according to the number +of tags appearing in the packet. + +For example, TR247 GPON conformance test suite specification mostly +talks about untagged, single, double tagged packets and gives lax +guidelines on the vlan protocol vs. number of vlan tags. + +This is different from the common IT networks where 802.1Q and 802.1ad +protocols are usually describe single and double tagged packet. GPON +configurations that we work with have arbitrary mix the above protocols +and number of vlan tags in the packet. + +The goal is to make the following TC commands possible: + +tc filter add dev eth1 ingress flower \ + num_of_vlans 1 vlan_prio 5 action drop + +From our logs, we have redirect rules such that: + +tc filter add dev $GPON ingress flower num_of_vlans $N \ + action mirred egress redirect dev $DEV + +where N can range from 0 to 3 and $DEV is the function of $N. + +Also there are rules setting skb mark based on the number of vlans: + +tc filter add dev $GPON ingress flower num_of_vlans $N vlan_prio \ + $P action skbedit mark $M + +This new dissector allows extracting the number of vlan tags existing in +the packet. + +Signed-off-by: Boris Sukholitko +Signed-off-by: David S. Miller +Stable-dep-of: cc1ff87bce1c ("pppoe: drop PFC frames") +Signed-off-by: Sasha Levin +--- + include/net/flow_dissector.h | 9 +++++++++ + net/core/flow_dissector.c | 20 ++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h +index 4036063d047c2..6826309631cb3 100644 +--- a/include/net/flow_dissector.h ++++ b/include/net/flow_dissector.h +@@ -269,6 +269,14 @@ struct flow_dissector_key_hash { + u32 hash; + }; + ++/** ++ * struct flow_dissector_key_num_of_vlans: ++ * @num_of_vlans: num_of_vlans value ++ */ ++struct flow_dissector_key_num_of_vlans { ++ u8 num_of_vlans; ++}; ++ + enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ + FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ +@@ -298,6 +306,7 @@ enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_META, /* struct flow_dissector_key_meta */ + FLOW_DISSECTOR_KEY_CT, /* struct flow_dissector_key_ct */ + FLOW_DISSECTOR_KEY_HASH, /* struct flow_dissector_key_hash */ ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS, /* struct flow_dissector_key_num_of_vlans */ + + FLOW_DISSECTOR_KEY_MAX, + }; +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index 8fe8b3afacd04..146f24c53c660 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -1032,6 +1032,16 @@ bool __skb_flow_dissect(const struct net *net, + memcpy(key_eth_addrs, ð->h_dest, sizeof(*key_eth_addrs)); + } + ++ if (dissector_uses_key(flow_dissector, ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS)) { ++ struct flow_dissector_key_num_of_vlans *key_num_of_vlans; ++ ++ key_num_of_vlans = skb_flow_dissector_target(flow_dissector, ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS, ++ target_container); ++ key_num_of_vlans->num_of_vlans = 0; ++ } ++ + proto_again: + fdret = FLOW_DISSECT_RET_CONTINUE; + +@@ -1155,6 +1165,16 @@ bool __skb_flow_dissect(const struct net *net, + nhoff += sizeof(*vlan); + } + ++ if (dissector_uses_key(flow_dissector, ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS)) { ++ struct flow_dissector_key_num_of_vlans *key_nvs; ++ ++ key_nvs = skb_flow_dissector_target(flow_dissector, ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS, ++ target_container); ++ key_nvs->num_of_vlans++; ++ } ++ + if (dissector_vlan == FLOW_DISSECTOR_KEY_MAX) { + dissector_vlan = FLOW_DISSECTOR_KEY_VLAN; + } else if (dissector_vlan == FLOW_DISSECTOR_KEY_VLAN) { +-- +2.53.0 + diff --git a/queue-5.10/flow_dissector-add-pppoe-dissectors.patch b/queue-5.10/flow_dissector-add-pppoe-dissectors.patch new file mode 100644 index 0000000000..47f0e26e8d --- /dev/null +++ b/queue-5.10/flow_dissector-add-pppoe-dissectors.patch @@ -0,0 +1,178 @@ +From fe085d4de2ed65e40377c3e92bcd158ebb3e006b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Jul 2022 14:18:10 +0200 +Subject: flow_dissector: Add PPPoE dissectors + +From: Wojciech Drewek + +[ Upstream commit 46126db9c86110e5fc1e369b9bb89735ddefdae4 ] + +Allow to dissect PPPoE specific fields which are: +- session ID (16 bits) +- ppp protocol (16 bits) +- type (16 bits) - this is PPPoE ethertype, for now only + ETH_P_PPP_SES is supported, possible ETH_P_PPP_DISC + in the future + +The goal is to make the following TC command possible: + + # tc filter add dev ens6f0 ingress prio 1 protocol ppp_ses \ + flower \ + pppoe_sid 12 \ + ppp_proto ip \ + action drop + +Note that only PPPoE Session is supported. + +Signed-off-by: Wojciech Drewek +Acked-by: Guillaume Nault +Signed-off-by: Tony Nguyen +Stable-dep-of: cc1ff87bce1c ("pppoe: drop PFC frames") +Signed-off-by: Sasha Levin +--- + include/linux/ppp_defs.h | 14 ++++++++++ + include/net/flow_dissector.h | 13 +++++++++ + net/core/flow_dissector.c | 53 +++++++++++++++++++++++++++++++----- + 3 files changed, 73 insertions(+), 7 deletions(-) + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index 9d2b388fae1a4..b7e57fdbd4139 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -11,4 +11,18 @@ + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) ++ ++/** ++ * ppp_proto_is_valid - checks if PPP protocol is valid ++ * @proto: PPP protocol ++ * ++ * Assumes proto is not compressed. ++ * Protocol is valid if the value is odd and the least significant bit of the ++ * most significant octet is 0 (see RFC 1661, section 2). ++ */ ++static inline bool ppp_proto_is_valid(u16 proto) ++{ ++ return !!((proto & 0x0101) == 0x0001); ++} ++ + #endif /* _PPP_DEFS_H_ */ +diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h +index 6826309631cb3..af0918a676211 100644 +--- a/include/net/flow_dissector.h ++++ b/include/net/flow_dissector.h +@@ -277,6 +277,18 @@ struct flow_dissector_key_num_of_vlans { + u8 num_of_vlans; + }; + ++/** ++ * struct flow_dissector_key_pppoe: ++ * @session_id: pppoe session id ++ * @ppp_proto: ppp protocol ++ * @type: pppoe eth type ++ */ ++struct flow_dissector_key_pppoe { ++ __be16 session_id; ++ __be16 ppp_proto; ++ __be16 type; ++}; ++ + enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ + FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ +@@ -307,6 +319,7 @@ enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_CT, /* struct flow_dissector_key_ct */ + FLOW_DISSECTOR_KEY_HASH, /* struct flow_dissector_key_hash */ + FLOW_DISSECTOR_KEY_NUM_OF_VLANS, /* struct flow_dissector_key_num_of_vlans */ ++ FLOW_DISSECTOR_KEY_PPPOE, /* struct flow_dissector_key_pppoe */ + + FLOW_DISSECTOR_KEY_MAX, + }; +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index 146f24c53c660..c3d64e2d59295 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -891,6 +891,11 @@ bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, + return result == BPF_OK; + } + ++static bool is_pppoe_ses_hdr_valid(struct pppoe_hdr hdr) ++{ ++ return hdr.ver == 1 && hdr.type == 1 && hdr.code == 0; ++} ++ + /** + * __skb_flow_dissect - extract the flow_keys struct and return it + * @net: associated network namespace, derived from @skb if NULL +@@ -1211,26 +1216,60 @@ bool __skb_flow_dissect(const struct net *net, + struct pppoe_hdr hdr; + __be16 proto; + } *hdr, _hdr; ++ u16 ppp_proto; ++ + hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); + if (!hdr) { + fdret = FLOW_DISSECT_RET_OUT_BAD; + break; + } + +- nhoff += PPPOE_SES_HLEN; +- switch (hdr->proto) { +- case htons(PPP_IP): ++ if (!is_pppoe_ses_hdr_valid(hdr->hdr)) { ++ fdret = FLOW_DISSECT_RET_OUT_BAD; ++ break; ++ } ++ ++ /* least significant bit of the most significant octet ++ * indicates if protocol field was compressed ++ */ ++ ppp_proto = ntohs(hdr->proto); ++ if (ppp_proto & 0x0100) { ++ ppp_proto = ppp_proto >> 8; ++ nhoff += PPPOE_SES_HLEN - 1; ++ } else { ++ nhoff += PPPOE_SES_HLEN; ++ } ++ ++ if (ppp_proto == PPP_IP) { + proto = htons(ETH_P_IP); + fdret = FLOW_DISSECT_RET_PROTO_AGAIN; +- break; +- case htons(PPP_IPV6): ++ } else if (ppp_proto == PPP_IPV6) { + proto = htons(ETH_P_IPV6); + fdret = FLOW_DISSECT_RET_PROTO_AGAIN; +- break; +- default: ++ } else if (ppp_proto == PPP_MPLS_UC) { ++ proto = htons(ETH_P_MPLS_UC); ++ fdret = FLOW_DISSECT_RET_PROTO_AGAIN; ++ } else if (ppp_proto == PPP_MPLS_MC) { ++ proto = htons(ETH_P_MPLS_MC); ++ fdret = FLOW_DISSECT_RET_PROTO_AGAIN; ++ } else if (ppp_proto_is_valid(ppp_proto)) { ++ fdret = FLOW_DISSECT_RET_OUT_GOOD; ++ } else { + fdret = FLOW_DISSECT_RET_OUT_BAD; + break; + } ++ ++ if (dissector_uses_key(flow_dissector, ++ FLOW_DISSECTOR_KEY_PPPOE)) { ++ struct flow_dissector_key_pppoe *key_pppoe; ++ ++ key_pppoe = skb_flow_dissector_target(flow_dissector, ++ FLOW_DISSECTOR_KEY_PPPOE, ++ target_container); ++ key_pppoe->session_id = hdr->hdr.sid; ++ key_pppoe->ppp_proto = htons(ppp_proto); ++ key_pppoe->type = htons(ETH_P_PPP_SES); ++ } + break; + } + case htons(ETH_P_TIPC): { +-- +2.53.0 + diff --git a/queue-5.10/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch b/queue-5.10/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch new file mode 100644 index 0000000000..3a720e1ef9 --- /dev/null +++ b/queue-5.10/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch @@ -0,0 +1,48 @@ +From 877c0708f7de8eb72580282a91de8e333a06cfc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 13:45:02 +0900 +Subject: fs/adfs: validate nzones in adfs_validate_bblk() + +From: Bae Yeonju + +[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ] + +Reject ADFS disc records with a zero zone count during boot block +validation, before the disc record is used. + +When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) +which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to +dm[-1], causing an out-of-bounds write before the allocated buffer. + +adfs_validate_dr0() already rejects nzones != 1 for old-format +images. Add the equivalent check to adfs_validate_bblk() for +new-format images so that a crafted image with nzones == 0 is +rejected at probe time. + +Found by syzkaller. + +Fixes: f6f14a0d71b0 ("fs/adfs: map: move map-specific sb initialisation to map.c") +Signed-off-by: Bae Yeonju +Signed-off-by: Russell King (Oracle) +Signed-off-by: Sasha Levin +--- + fs/adfs/super.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/adfs/super.c b/fs/adfs/super.c +index bdbd26e571ed3..7da236fd7a119 100644 +--- a/fs/adfs/super.c ++++ b/fs/adfs/super.c +@@ -343,6 +343,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, + if (adfs_checkdiscrecord(dr)) + return -EILSEQ; + ++ if ((dr->nzones | dr->nzones_high << 8) == 0) ++ return -EILSEQ; ++ + *drp = dr; + return 0; + } +-- +2.53.0 + diff --git a/queue-5.10/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch b/queue-5.10/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch new file mode 100644 index 0000000000..3b1362741b --- /dev/null +++ b/queue-5.10/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch @@ -0,0 +1,55 @@ +From da884ad22526deaecdc130e22dfb7ce85585a854 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:48:27 +0900 +Subject: fs/omfs: reject s_sys_blocksize smaller than OMFS_DIR_START + +From: HyungJung Joo + +[ Upstream commit 0621c385fda1376e967f37ccd534c26c3e511d14 ] + +omfs_fill_super() rejects oversized s_sys_blocksize values (> PAGE_SIZE), +but it does not reject values smaller than OMFS_DIR_START (0x1b8 = 440). + +Later, omfs_make_empty() uses + + sbi->s_sys_blocksize - OMFS_DIR_START + +as the length argument to memset(). Since s_sys_blocksize is u32, +a crafted filesystem image with s_sys_blocksize < OMFS_DIR_START causes +an unsigned underflow there, wrapping to a value near 2^32. That drives +a ~4 GiB memset() from bh->b_data + OMFS_DIR_START and overwrites kernel +memory far beyond the backing block buffer. + +Add the corresponding lower-bound check alongside the existing upper-bound +check in omfs_fill_super(), so that malformed images are rejected during +superblock validation before any filesystem data is processed. + +Fixes: a3ab7155ea21 ("omfs: add directory routines") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054827.1822061-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/omfs/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c +index ce93ccca86392..5abd152406f51 100644 +--- a/fs/omfs/inode.c ++++ b/fs/omfs/inode.c +@@ -515,6 +515,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) + goto out_brelse_bh; + } + ++ if (sbi->s_sys_blocksize < OMFS_DIR_START) { ++ printk(KERN_ERR "omfs: sysblock size (%d) is too small\n", ++ sbi->s_sys_blocksize); ++ goto out_brelse_bh; ++ } ++ + if (sbi->s_blocksize < sbi->s_sys_blocksize || + sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { + printk(KERN_ERR "omfs: block size (%d) is out of range\n", +-- +2.53.0 + diff --git a/queue-5.10/hid-asus-do-not-abort-probe-when-not-necessary.patch b/queue-5.10/hid-asus-do-not-abort-probe-when-not-necessary.patch new file mode 100644 index 0000000000..3c9aab0975 --- /dev/null +++ b/queue-5.10/hid-asus-do-not-abort-probe-when-not-necessary.patch @@ -0,0 +1,65 @@ +From 0f520d9ffe8d4ef920c0a985ed301d7c765f7dfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:09 +0100 +Subject: HID: asus: do not abort probe when not necessary + +From: Denis Benato + +[ Upstream commit 7253091766ded0fd81fe8d8be9b8b835495b06e8 ] + +In order to avoid dereferencing a NULL pointer asus_probe is aborted early +and control of some asus devices is transferred over hid-generic after +erroring out even when such NULL dereference cannot happen: only early +abort when the NULL dereference can happen. + +Also make the code shorter and more adherent to coding standards +removing square brackets enclosing single-line if-else statements. + +Fixes: d3af6ca9a8c3 ("HID: asus: fix UAF via HID_CLAIMED_INPUT validation") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 31d76cef4b73f..af9dc04793d7d 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1034,22 +1034,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + * were freed during registration due to no usages being mapped, + * leaving drvdata->input pointing to freed memory. + */ +- if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { +- hid_err(hdev, "Asus input not registered\n"); +- ret = -ENOMEM; +- goto err_stop_hw; +- } +- +- if (drvdata->tp) { +- drvdata->input->name = "Asus TouchPad"; +- } else { +- drvdata->input->name = "Asus Keyboard"; +- } ++ if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) { ++ if (drvdata->tp) ++ drvdata->input->name = "Asus TouchPad"; ++ else ++ drvdata->input->name = "Asus Keyboard"; + +- if (drvdata->tp) { +- ret = asus_start_multitouch(hdev); +- if (ret) +- goto err_stop_hw; ++ if (drvdata->tp) { ++ ret = asus_start_multitouch(hdev); ++ if (ret) ++ goto err_stop_hw; ++ } + } + + return 0; +-- +2.53.0 + diff --git a/queue-5.10/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch b/queue-5.10/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch new file mode 100644 index 0000000000..48dca3d449 --- /dev/null +++ b/queue-5.10/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch @@ -0,0 +1,37 @@ +From dcac016f7c710626791dedd92a4b6d25d454feb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:07 +0100 +Subject: HID: asus: make asus_resume adhere to linux kernel coding standards + +From: Denis Benato + +[ Upstream commit 51d33b42b8ae23da92819d28439fdd5636c45186 ] + +Linux kernel coding standars requires functions opening brackets to be in +a newline: move the opening bracket of asus_resume in its own line. + +Fixes: 546edbd26cff ("HID: hid-asus: reset the backlight brightness level on resume") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 9d425f81d6224..31d76cef4b73f 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -901,7 +901,8 @@ static int asus_start_multitouch(struct hid_device *hdev) + return 0; + } + +-static int __maybe_unused asus_resume(struct hid_device *hdev) { ++static int __maybe_unused asus_resume(struct hid_device *hdev) ++{ + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + int ret = 0; + +-- +2.53.0 + diff --git a/queue-5.10/hid-usbhid-fix-deadlock-in-hid_post_reset.patch b/queue-5.10/hid-usbhid-fix-deadlock-in-hid_post_reset.patch new file mode 100644 index 0000000000..7641fc4fb1 --- /dev/null +++ b/queue-5.10/hid-usbhid-fix-deadlock-in-hid_post_reset.patch @@ -0,0 +1,42 @@ +From 662454eb714de271f2d7ce57d102f9103ff0c0a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:24:54 +0100 +Subject: HID: usbhid: fix deadlock in hid_post_reset() + +From: Oliver Neukum + +[ Upstream commit 8df2c1b47ee3cd50fd454f75c7a7e2ae8a6adf72 ] + +You can build a USB device that includes a HID component +and a storage or UAS component. The components can be reset +only together. That means that hid_pre_reset() and hid_post_reset() +are in the block IO error handling. Hence no memory allocation +used in them may do block IO because the IO can deadlock +on the mutex held while resetting a device and calling the +interface drivers. +Use GFP_NOIO for all allocations in them. + +Fixes: dc3c78e434690 ("HID: usbhid: Check HID report descriptor contents after device reset") +Signed-off-by: Oliver Neukum +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index 03eecfd3692df..7d0eb6c85d851 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1538,7 +1538,7 @@ static int hid_post_reset(struct usb_interface *intf) + * configuration descriptors passed, we already know that + * the size of the HID report descriptor has not changed. + */ +- rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); ++ rdesc = kmalloc(hid->dev_rsize, GFP_NOIO); + if (!rdesc) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-5.10/i3c-master-fix-error-codes-at-send_ccc_cmd.patch b/queue-5.10/i3c-master-fix-error-codes-at-send_ccc_cmd.patch new file mode 100644 index 0000000000..33c3db3647 --- /dev/null +++ b/queue-5.10/i3c-master-fix-error-codes-at-send_ccc_cmd.patch @@ -0,0 +1,126 @@ +From 4488ef80b2ce1710582c0868ae33f3a1c565bcff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:32 +0100 +Subject: i3c: master: Fix error codes at send_ccc_cmd + +From: Jorge Marques + +[ Upstream commit ef8b5229348f0719aca557c4ca5530630ae4d134 ] + +i3c_master_send_ccc_cmd_locked() would propagate cmd->err (positive, +Mx codes) to the ret variable, cascading down multiple methods until +reaching methods that explicitly stated they would return 0 on success +or negative error code. For example, the call chain: + + i3c_device_enable_ibi <- i3c_dev_enable_ibi_locked <- + master->ops.enable_ibi <- i3c_master_enec_locked <- + i3c_master_enec_disec_locked <- i3c_master_send_ccc_cmd_locked + +Fix this by returning the ret value, callers can still read the cmd->err +value if ret is negative. + +All corner cases where the Mx codes do need to be handled individually, +are resolved in previous commits. Those corner cases are all scenarios +when I3C_ERROR_M2 is expected and acceptable. +The prerequisite patches for the fix are: + + i3c: master: Move rstdaa error suppression + i3c: master: Move entdaa error suppression + i3c: master: Move bus_init error suppression + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-iio/aYXvT5FW0hXQwhm_@stanley.mountain/ +Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-4-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 32 +++++++++++++------------------- + 1 file changed, 13 insertions(+), 19 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index f3fc7fe3779fe..7539e7d563032 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -700,11 +700,17 @@ static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id, + cmd->err = I3C_ERROR_UNKNOWN; + } + ++/** ++ * i3c_master_send_ccc_cmd_locked() - send a CCC (Common Command Codes) ++ * @master: master used to send frames on the bus ++ * @cmd: command to send ++ * ++ * Return: 0 in case of success, or a negative error code otherwise. ++ * I3C Mx error codes are stored in cmd->err. ++ */ + static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd) + { +- int ret; +- + if (!cmd || !master) + return -EINVAL; + +@@ -722,15 +728,7 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + !master->ops->supports_ccc_cmd(master, cmd)) + return -ENOTSUPP; + +- ret = master->ops->send_ccc_cmd(master, cmd); +- if (ret) { +- if (cmd->err != I3C_ERROR_UNKNOWN) +- return cmd->err; +- +- return ret; +- } +- +- return 0; ++ return master->ops->send_ccc_cmd(master, cmd); + } + + static struct i2c_dev_desc * +@@ -834,8 +832,7 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_entdaa_locked(struct i3c_master_controller *master) + { +@@ -887,8 +884,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -908,8 +904,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -934,8 +929,7 @@ EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_defslvs_locked(struct i3c_master_controller *master) + { +-- +2.53.0 + diff --git a/queue-5.10/i40e-don-t-advertise-iff_supp_nofcs.patch b/queue-5.10/i40e-don-t-advertise-iff_supp_nofcs.patch new file mode 100644 index 0000000000..f0fd69f49f --- /dev/null +++ b/queue-5.10/i40e-don-t-advertise-iff_supp_nofcs.patch @@ -0,0 +1,53 @@ +From 198251a773523e4f3b6b571da8a56724d93bfcdb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:33 -0700 +Subject: i40e: don't advertise IFF_SUPP_NOFCS + +From: Kohei Enju + +[ Upstream commit a24162f18825684ad04e3a5d0531f8a50d679347 ] + +i40e advertises IFF_SUPP_NOFCS, allowing users to use the SO_NOFCS +socket option. However, this option is silently ignored, as the driver +does not check skb->no_fcs, and always enables FCS insertion offload. + +Fix this by removing the advertisement of IFF_SUPP_NOFCS. + +This behavior can be reproduced with a simple AF_PACKET socket: + + import socket + s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) + s.setsockopt(socket.SOL_SOCKET, 43, 1) # SO_NOFCS + s.bind(("eth0", 0)) + s.send(b'\xff' * 64) + +Previously, send() succeeds but the driver ignores SO_NOFCS. +With this change, send() fails with -EPROTONOSUPPORT, as expected. + +Fixes: 41c445ff0f48 ("i40e: main driver core") +Signed-off-by: Kohei Enju +Reviewed-by: Aleksandr Loktionov +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-9-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index 3d3816de72ec8..56bbaefbcbb7a 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -13192,7 +13192,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) + netdev->neigh_priv_len = sizeof(u32) * 4; + + netdev->priv_flags |= IFF_UNICAST_FLT; +- netdev->priv_flags |= IFF_SUPP_NOFCS; + /* Setup netdev TC information */ + i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); + +-- +2.53.0 + diff --git a/queue-5.10/ima-check-return-value-of-crypto_shash_final-in-boot.patch b/queue-5.10/ima-check-return-value-of-crypto_shash_final-in-boot.patch new file mode 100644 index 0000000000..82e6d7ac7b --- /dev/null +++ b/queue-5.10/ima-check-return-value-of-crypto_shash_final-in-boot.patch @@ -0,0 +1,41 @@ +From a07edfeb81edd183c5b311a41c4cb7f07d77dbbf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 18:40:15 -0800 +Subject: ima: check return value of crypto_shash_final() in boot aggregate + +From: Daniel Hodges + +[ Upstream commit 870819434c8dfcc3158033b66e7851b81bb17e21 ] + +The return value of crypto_shash_final() is not checked in +ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the +function returns success and a corrupted boot aggregate digest could +be used for IMA measurements. + +Capture the return value and propagate any error to the caller. + +Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash") +Signed-off-by: Daniel Hodges +Reviewed-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index b1e5e7749e416..4ce45910b0fd0 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -837,7 +837,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, + } + } + if (!rc) +- crypto_shash_final(shash, digest); ++ rc = crypto_shash_final(shash, digest); + return rc; + } + +-- +2.53.0 + diff --git a/queue-5.10/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch b/queue-5.10/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch new file mode 100644 index 0000000000..e0015399e6 --- /dev/null +++ b/queue-5.10/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch @@ -0,0 +1,145 @@ +From 73cc5e49d5e1da64e96c96371bb2cfa5243bc3a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:22 +0200 +Subject: ipv4: add new arguments to udp_tunnel_dst_lookup() + +From: Beniamino Galvani + +[ Upstream commit 72fc68c6356b663a8763f02d9b0ec773d59a4949 ] + +We want to make the function more generic so that it can be used by +other UDP tunnel implementations such as geneve and vxlan. To do that, +add the following arguments: + + - source and destination UDP port; + - ifindex of the output interface, needed by vxlan; + - the tos, because in some cases it is not taken from struct + ip_tunnel_info (for example, when it's inherited from the inner + packet); + - the dst cache, because not all tunnel types (e.g. vxlan) want to + use the one from struct ip_tunnel_info. + +With these parameters, the function no longer needs the full struct +ip_tunnel_info as argument and we can pass only the relevant part of +it (struct ip_tunnel_key). + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 11 +++++++---- + include/net/udp_tunnel.h | 8 +++++--- + net/ipv4/udp_tunnel_core.c | 26 +++++++++++++------------- + 3 files changed, 25 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 1ed25e1afd246..5c8412d835792 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -317,8 +317,10 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, +- use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, &info->key, ++ 0, 0, key->tos, ++ use_cache ? ++ (struct dst_cache *)&info->dst_cache : NULL); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -497,8 +499,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct rtable *rt; + __be32 saddr; + +- rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, +- info, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, ++ &info->key, 0, 0, info->key.tos, ++ use_cache ? &info->dst_cache : NULL); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index 4d4f1a67d4b26..ad92ae0dd9863 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -155,9 +155,11 @@ void udp_tunnel_sock_release(struct socket *sock); + + struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- bool use_cache); ++ struct net *net, int oif, ++ __be32 *saddr, ++ const struct ip_tunnel_key *key, ++ __be16 sport, __be16 dport, u8 tos, ++ struct dst_cache *dst_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 50c83f90487db..4b6f44c481abf 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -224,31 +224,31 @@ EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + + struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- bool use_cache) ++ struct net *net, int oif, ++ __be32 *saddr, ++ const struct ip_tunnel_key *key, ++ __be16 sport, __be16 dport, u8 tos, ++ struct dst_cache *dst_cache) + { +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif + struct rtable *rt = NULL; + struct flowi4 fl4; +- __u8 tos; + + #ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { ++ if (dst_cache) { + rt = dst_cache_get_ip4(dst_cache, saddr); + if (rt) + return rt; + } + #endif ++ + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; + fl4.flowi4_proto = IPPROTO_UDP; +- fl4.daddr = info->key.u.ipv4.dst; +- fl4.saddr = info->key.u.ipv4.src; +- tos = info->key.tos; ++ fl4.flowi4_oif = oif; ++ fl4.daddr = key->u.ipv4.dst; ++ fl4.saddr = key->u.ipv4.src; ++ fl4.fl4_dport = dport; ++ fl4.fl4_sport = sport; + fl4.flowi4_tos = RT_TOS(tos); + + rt = ip_route_output_key(net, &fl4); +@@ -262,7 +262,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + return ERR_PTR(-ELOOP); + } + #ifdef CONFIG_DST_CACHE +- if (use_cache) ++ if (dst_cache) + dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); + #endif + *saddr = fl4.saddr; +-- +2.53.0 + diff --git a/queue-5.10/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch b/queue-5.10/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch new file mode 100644 index 0000000000..dc185dc60c --- /dev/null +++ b/queue-5.10/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch @@ -0,0 +1,83 @@ +From 532bfc4419bd59ee39bf8a44110ce6a328b04301 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:21 +0200 +Subject: ipv4: remove "proto" argument from udp_tunnel_dst_lookup() + +From: Beniamino Galvani + +[ Upstream commit 78f3655adcb52412275f282267ee771421731632 ] + +The function is now UDP-specific, the protocol is always IPPROTO_UDP. + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 4 ++-- + include/net/udp_tunnel.h | 2 +- + net/ipv4/udp_tunnel_core.c | 4 ++-- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index dc1a551e6346a..1ed25e1afd246 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -318,7 +318,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + return -ESHUTDOWN; + + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, +- IPPROTO_UDP, use_cache); ++ use_cache); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -498,7 +498,7 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + __be32 saddr; + + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, +- info, IPPROTO_UDP, use_cache); ++ info, use_cache); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index efcaa114360b7..4d4f1a67d4b26 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -157,7 +157,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, __be32 *saddr, + const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); ++ bool use_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 356ef25481a83..50c83f90487db 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -226,7 +226,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, __be32 *saddr, + const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache) ++ bool use_cache) + { + #ifdef CONFIG_DST_CACHE + struct dst_cache *dst_cache; +@@ -245,7 +245,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + #endif + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; +- fl4.flowi4_proto = protocol; ++ fl4.flowi4_proto = IPPROTO_UDP; + fl4.daddr = info->key.u.ipv4.dst; + fl4.saddr = info->key.u.ipv4.src; + tos = info->key.tos; +-- +2.53.0 + diff --git a/queue-5.10/ipv4-rename-and-move-ip_route_output_tunnel.patch b/queue-5.10/ipv4-rename-and-move-ip_route_output_tunnel.patch new file mode 100644 index 0000000000..850ca8c12b --- /dev/null +++ b/queue-5.10/ipv4-rename-and-move-ip_route_output_tunnel.patch @@ -0,0 +1,211 @@ +From 4f992acc8e448775cc42a62d61482377bc831d13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:20 +0200 +Subject: ipv4: rename and move ip_route_output_tunnel() + +From: Beniamino Galvani + +[ Upstream commit bf3fcbf7e7a08015d3b169bad6281b29d45c272d ] + +At the moment ip_route_output_tunnel() is used only by bareudp. +Ideally, other UDP tunnel implementations should use it, but to do so +the function needs to accept new parameters that are specific for UDP +tunnels, such as the ports. + +Prepare for these changes by renaming the function to +udp_tunnel_dst_lookup() and move it to file +net/ipv4/udp_tunnel_core.c. + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 8 +++---- + include/net/route.h | 6 ----- + include/net/udp_tunnel.h | 6 +++++ + net/ipv4/route.c | 48 -------------------------------------- + net/ipv4/udp_tunnel_core.c | 48 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 58 insertions(+), 58 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 826f912ea820d..dc1a551e6346a 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -317,8 +317,8 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, info, +- IPPROTO_UDP, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, ++ IPPROTO_UDP, use_cache); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -497,8 +497,8 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct rtable *rt; + __be32 saddr; + +- rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, +- info, IPPROTO_UDP, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, ++ info, IPPROTO_UDP, use_cache); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/route.h b/include/net/route.h +index 2551f3f03b37e..c6557fdcde2c4 100644 +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -128,12 +128,6 @@ static inline struct rtable *__ip_route_output_key(struct net *net, + + struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp, + const struct sock *sk); +-struct rtable *ip_route_output_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); +- + struct dst_entry *ipv4_blackhole_route(struct net *net, + struct dst_entry *dst_orig); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index 97a739c21f1f8..efcaa114360b7 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -153,6 +153,12 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + + void udp_tunnel_sock_release(struct socket *sock); + ++struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, __be32 *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache); ++ + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, + int md_size); +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index f260253fed8d3..cee8580cbbe08 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -2827,54 +2827,6 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4, + } + EXPORT_SYMBOL_GPL(ip_route_output_flow); + +-struct rtable *ip_route_output_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache) +-{ +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif +- struct rtable *rt = NULL; +- struct flowi4 fl4; +- __u8 tos; +- +-#ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { +- rt = dst_cache_get_ip4(dst_cache, saddr); +- if (rt) +- return rt; +- } +-#endif +- memset(&fl4, 0, sizeof(fl4)); +- fl4.flowi4_mark = skb->mark; +- fl4.flowi4_proto = protocol; +- fl4.daddr = info->key.u.ipv4.dst; +- fl4.saddr = info->key.u.ipv4.src; +- tos = info->key.tos; +- fl4.flowi4_tos = RT_TOS(tos); +- +- rt = ip_route_output_key(net, &fl4); +- if (IS_ERR(rt)) { +- netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); +- return ERR_PTR(-ENETUNREACH); +- } +- if (rt->dst.dev == dev) { /* is this necessary? */ +- netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); +- ip_rt_put(rt); +- return ERR_PTR(-ELOOP); +- } +-#ifdef CONFIG_DST_CACHE +- if (use_cache) +- dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); +-#endif +- *saddr = fl4.saddr; +- return rt; +-} +-EXPORT_SYMBOL_GPL(ip_route_output_tunnel); +- + /* called with rcu_read_lock held */ + static int rt_fill_info(struct net *net, __be32 dst, __be32 src, + struct rtable *rt, u32 table_id, struct flowi4 *fl4, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index d70f683d3c495..356ef25481a83 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -222,4 +222,52 @@ struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + } + EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + ++struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, __be32 *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache) ++{ ++#ifdef CONFIG_DST_CACHE ++ struct dst_cache *dst_cache; ++#endif ++ struct rtable *rt = NULL; ++ struct flowi4 fl4; ++ __u8 tos; ++ ++#ifdef CONFIG_DST_CACHE ++ dst_cache = (struct dst_cache *)&info->dst_cache; ++ if (use_cache) { ++ rt = dst_cache_get_ip4(dst_cache, saddr); ++ if (rt) ++ return rt; ++ } ++#endif ++ memset(&fl4, 0, sizeof(fl4)); ++ fl4.flowi4_mark = skb->mark; ++ fl4.flowi4_proto = protocol; ++ fl4.daddr = info->key.u.ipv4.dst; ++ fl4.saddr = info->key.u.ipv4.src; ++ tos = info->key.tos; ++ fl4.flowi4_tos = RT_TOS(tos); ++ ++ rt = ip_route_output_key(net, &fl4); ++ if (IS_ERR(rt)) { ++ netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); ++ return ERR_PTR(-ENETUNREACH); ++ } ++ if (rt->dst.dev == dev) { /* is this necessary? */ ++ netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); ++ ip_rt_put(rt); ++ return ERR_PTR(-ELOOP); ++ } ++#ifdef CONFIG_DST_CACHE ++ if (use_cache) ++ dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); ++#endif ++ *saddr = fl4.saddr; ++ return rt; ++} ++EXPORT_SYMBOL_GPL(udp_tunnel_dst_lookup); ++ + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-5.10/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch b/queue-5.10/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch new file mode 100644 index 0000000000..1cb34b1039 --- /dev/null +++ b/queue-5.10/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch @@ -0,0 +1,71 @@ +From 64d6c358712c08458cb64f9d63458f32c707b0be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 10:35:05 +0000 +Subject: ipv6: fix possible UAF in icmpv6_rcv() + +From: Eric Dumazet + +[ Upstream commit f996edd7615e686ada141b7f3395025729ff8ccb ] + +Caching saddr and daddr before pskb_pull() is problematic +since skb->head can change. + +Remove these temporary variables: + +- We only access &ipv6_hdr(skb)->saddr and &ipv6_hdr(skb)->daddr + when net_dbg_ratelimited() is called in the slow path. + +- Avoid potential future misuse after pskb_pull() call. + +Fixes: 4b3418fba0fe ("ipv6: icmp: include addresses in debug messages") +Signed-off-by: Eric Dumazet +Reviewed-by: Fernando Fernandez Mancera +Reviewed-by: Joe Damato +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260416103505.2380753-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/icmp.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index 65846f4451894..35e99974aa882 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -867,7 +867,6 @@ static int icmpv6_rcv(struct sk_buff *skb) + struct net *net = dev_net(skb->dev); + struct net_device *dev = icmp6_dev(skb); + struct inet6_dev *idev = __in6_dev_get(dev); +- const struct in6_addr *saddr, *daddr; + struct icmp6hdr *hdr; + u8 type; + bool success = false; +@@ -894,12 +893,10 @@ static int icmpv6_rcv(struct sk_buff *skb) + + __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS); + +- saddr = &ipv6_hdr(skb)->saddr; +- daddr = &ipv6_hdr(skb)->daddr; +- + if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { + net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + goto csum_error; + } + +@@ -972,7 +969,8 @@ static int icmpv6_rcv(struct sk_buff *skb) + break; + + net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + + /* + * error of unknown type. +-- +2.53.0 + diff --git a/queue-5.10/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch b/queue-5.10/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch new file mode 100644 index 0000000000..c8a4474c8e --- /dev/null +++ b/queue-5.10/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch @@ -0,0 +1,262 @@ +From bb0beca3e419681a5becd11e14c6aadd27c5029f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 13:55:25 +0200 +Subject: ipv6: rename and move ip6_dst_lookup_tunnel() + +From: Beniamino Galvani + +[ Upstream commit fc47e86dbfb75a864c0c9dd8e78affb6506296bb ] + +At the moment ip6_dst_lookup_tunnel() is used only by bareudp. +Ideally, other UDP tunnel implementations should use it, but to do so +the function needs to accept new parameters that are specific for UDP +tunnels, such as the ports. + +Prepare for these changes by renaming the function to +udp_tunnel6_dst_lookup() and move it to file +net/ipv6/ip6_udp_tunnel.c. + +This is similar to what already done for IPv4 in commit bf3fcbf7e7a0 +("ipv4: rename and move ip_route_output_tunnel()"). + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 10 +++--- + include/net/ipv6.h | 6 ---- + include/net/udp_tunnel.h | 7 ++++ + net/ipv6/ip6_output.c | 68 -------------------------------------- + net/ipv6/ip6_udp_tunnel.c | 69 +++++++++++++++++++++++++++++++++++++++ + 5 files changed, 81 insertions(+), 79 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 5c8412d835792..d5210b5b8cbf8 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -385,8 +385,8 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, &saddr, info, +- IPPROTO_UDP, use_cache); ++ dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, &saddr, info, ++ IPPROTO_UDP, use_cache); + if (IS_ERR(dst)) + return PTR_ERR(dst); + +@@ -512,9 +512,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + +- dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, +- &saddr, info, IPPROTO_UDP, +- use_cache); ++ dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, ++ &saddr, info, IPPROTO_UDP, ++ use_cache); + if (IS_ERR(dst)) + return PTR_ERR(dst); + +diff --git a/include/net/ipv6.h b/include/net/ipv6.h +index d7b0710d0d9c1..c597596738754 100644 +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -1025,12 +1025,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, st + struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, + const struct in6_addr *final_dst, + bool connected); +-struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, struct socket *sock, +- struct in6_addr *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); + struct dst_entry *ip6_blackhole_route(struct net *net, + struct dst_entry *orig_dst); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index ad92ae0dd9863..6a296bb88b974 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -160,6 +160,13 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + const struct ip_tunnel_key *key, + __be16 sport, __be16 dport, u8 tos, + struct dst_cache *dst_cache); ++struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, ++ struct socket *sock, ++ struct in6_addr *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 99ee18b3a953e..764c003f98249 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1262,74 +1262,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, + } + EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); + +-/** +- * ip6_dst_lookup_tunnel - perform route lookup on tunnel +- * @skb: Packet for which lookup is done +- * @dev: Tunnel device +- * @net: Network namespace of tunnel device +- * @sock: Socket which provides route info +- * @saddr: Memory to store the src ip address +- * @info: Tunnel information +- * @protocol: IP protocol +- * @use_cache: Flag to enable cache usage +- * This function performs a route lookup on a tunnel +- * +- * It returns a valid dst pointer and stores src address to be used in +- * tunnel in param saddr on success, else a pointer encoded error code. +- */ +- +-struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, +- struct socket *sock, +- struct in6_addr *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, +- bool use_cache) +-{ +- struct dst_entry *dst = NULL; +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif +- struct flowi6 fl6; +- __u8 prio; +- +-#ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { +- dst = dst_cache_get_ip6(dst_cache, saddr); +- if (dst) +- return dst; +- } +-#endif +- memset(&fl6, 0, sizeof(fl6)); +- fl6.flowi6_mark = skb->mark; +- fl6.flowi6_proto = protocol; +- fl6.daddr = info->key.u.ipv6.dst; +- fl6.saddr = info->key.u.ipv6.src; +- prio = info->key.tos; +- fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); +- +- dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, +- NULL); +- if (IS_ERR(dst)) { +- netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); +- return ERR_PTR(-ENETUNREACH); +- } +- if (dst->dev == dev) { /* is this necessary? */ +- netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); +- dst_release(dst); +- return ERR_PTR(-ELOOP); +- } +-#ifdef CONFIG_DST_CACHE +- if (use_cache) +- dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); +-#endif +- *saddr = fl6.saddr; +- return dst; +-} +-EXPORT_SYMBOL_GPL(ip6_dst_lookup_tunnel); +- + static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, + gfp_t gfp) + { +diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c +index cdc4d4ee24206..7aef559e60ec5 100644 +--- a/net/ipv6/ip6_udp_tunnel.c ++++ b/net/ipv6/ip6_udp_tunnel.c +@@ -1,3 +1,4 @@ ++ + // SPDX-License-Identifier: GPL-2.0-only + #include + #include +@@ -111,4 +112,72 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + } + EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); + ++/** ++ * udp_tunnel6_dst_lookup - perform route lookup on UDP tunnel ++ * @skb: Packet for which lookup is done ++ * @dev: Tunnel device ++ * @net: Network namespace of tunnel device ++ * @sock: Socket which provides route info ++ * @saddr: Memory to store the src ip address ++ * @info: Tunnel information ++ * @protocol: IP protocol ++ * @use_cache: Flag to enable cache usage ++ * This function performs a route lookup on a UDP tunnel ++ * ++ * It returns a valid dst pointer and stores src address to be used in ++ * tunnel in param saddr on success, else a pointer encoded error code. ++ */ ++ ++struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, ++ struct socket *sock, ++ struct in6_addr *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, ++ bool use_cache) ++{ ++ struct dst_entry *dst = NULL; ++#ifdef CONFIG_DST_CACHE ++ struct dst_cache *dst_cache; ++#endif ++ struct flowi6 fl6; ++ __u8 prio; ++ ++#ifdef CONFIG_DST_CACHE ++ dst_cache = (struct dst_cache *)&info->dst_cache; ++ if (use_cache) { ++ dst = dst_cache_get_ip6(dst_cache, saddr); ++ if (dst) ++ return dst; ++ } ++#endif ++ memset(&fl6, 0, sizeof(fl6)); ++ fl6.flowi6_mark = skb->mark; ++ fl6.flowi6_proto = protocol; ++ fl6.daddr = info->key.u.ipv6.dst; ++ fl6.saddr = info->key.u.ipv6.src; ++ prio = info->key.tos; ++ fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); ++ ++ dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, ++ NULL); ++ if (IS_ERR(dst)) { ++ netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); ++ return ERR_PTR(-ENETUNREACH); ++ } ++ if (dst->dev == dev) { /* is this necessary? */ ++ netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); ++ dst_release(dst); ++ return ERR_PTR(-ELOOP); ++ } ++#ifdef CONFIG_DST_CACHE ++ if (use_cache) ++ dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); ++#endif ++ *saddr = fl6.saddr; ++ return dst; ++} ++EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup); ++ + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-5.10/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch b/queue-5.10/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch new file mode 100644 index 0000000000..972707779f --- /dev/null +++ b/queue-5.10/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch @@ -0,0 +1,97 @@ +From 7dfb9225fbdb942652d9474bc1fa56751b09a891 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:40:29 +0800 +Subject: ipvs: fix MTU check for GSO packets in tunnel mode + +From: Yingnan Zhang <342144303@qq.com> + +[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ] + +Currently, IPVS skips MTU checks for GSO packets by excluding them with +the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel +mode encapsulates GSO packets with IPIP headers. + +The issue manifests in two ways: + +1. MTU violation after encapsulation: + When a GSO packet passes through IPVS tunnel mode, the original MTU + check is bypassed. After adding the IPIP tunnel header, the packet + size may exceed the outgoing interface MTU, leading to unexpected + fragmentation at the IP layer. + +2. Fragmentation with problematic IP IDs: + When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments + is fragmented after encapsulation, each segment gets a sequentially + incremented IP ID (0, 1, 2, ...). This happens because: + + a) The GSO packet bypasses MTU check and gets encapsulated + b) At __ip_finish_output, the oversized GSO packet is split into + separate SKBs (one per segment), with IP IDs incrementing + c) Each SKB is then fragmented again based on the actual MTU + + This sequential IP ID allocation differs from the expected behavior + and can cause issues with fragment reassembly and packet tracking. + +Fix this by properly validating GSO packets using +skb_gso_validate_network_len(). This function correctly validates +whether the GSO segments will fit within the MTU after segmentation. If +validation fails, send an ICMP Fragmentation Needed message to enable +proper PMTU discovery. + +Fixes: 4cdd34084d53 ("netfilter: nf_conntrack_ipv6: improve fragmentation handling") +Signed-off-by: Yingnan Zhang <342144303@qq.com> +Acked-by: Julian Anastasov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index f82834349ca2c..9e199f00eea73 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -103,6 +103,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest) + return dest_dst; + } + ++/* Based on ip_exceeds_mtu(). */ ++static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) ++{ ++ if (skb->len <= mtu) ++ return false; ++ ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) ++ return false; ++ ++ return true; ++} ++ + static inline bool + __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + { +@@ -112,10 +124,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + */ + if (IP6CB(skb)->frag_max_size > mtu) + return true; /* largest fragment violate MTU */ +- } +- else if (skb->len > mtu && !skb_is_gso(skb)) { ++ } else if (ip_vs_exceeds_mtu(skb, mtu)) + return true; /* Packet size violate MTU size */ +- } ++ + return false; + } + +@@ -240,7 +251,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, + return true; + + if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && +- skb->len > mtu && !skb_is_gso(skb) && ++ ip_vs_exceeds_mtu(skb, mtu) && + !ip_vs_iph_icmp(ipvsh))) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); +-- +2.53.0 + diff --git a/queue-5.10/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch b/queue-5.10/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch new file mode 100644 index 0000000000..f6f1664218 --- /dev/null +++ b/queue-5.10/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch @@ -0,0 +1,48 @@ +From 079423ba5d5517a0f11cbe3146465af6f2b06b3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Feb 2026 18:43:44 -0500 +Subject: irqchip/irq-pic32-evic: Address warning related to wrong printf() + formatter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 86be659415b0ddefebc3120e309091aa215a9064 ] + +This driver is currently only build on 32 bit MIPS systems. When building +it on x86_64, the following warning occurs: + + drivers/irqchip/irq-pic32-evic.c: In function ‘pic32_ext_irq_of_init’: + ./include/linux/kern_levels.h:5:25: error: format ‘%d’ expects argument of type + ‘int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] + +Update the printf() formatter in preparation for allowing this driver to +be compiled on all architectures. + +Fixes: aaa8666ada780 ("IRQCHIP: irq-pic32-evic: Add support for PIC32 interrupt controller") +Signed-off-by: Brian Masney +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260222-irqchip-pic32-v1-1-37f50d1f14af@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-pic32-evic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c +index 34c4b4ffacd15..5c40ec5e55f1d 100644 +--- a/drivers/irqchip/irq-pic32-evic.c ++++ b/drivers/irqchip/irq-pic32-evic.c +@@ -199,7 +199,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain) + + of_property_for_each_u32(node, pname, prop, p, hwirq) { + if (i >= ARRAY_SIZE(priv->ext_irqs)) { +- pr_warn("More than %d external irq, skip rest\n", ++ pr_warn("More than %zu external irq, skip rest\n", + ARRAY_SIZE(priv->ext_irqs)); + break; + } +-- +2.53.0 + diff --git a/queue-5.10/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch b/queue-5.10/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch new file mode 100644 index 0000000000..5bdbeb16d0 --- /dev/null +++ b/queue-5.10/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch @@ -0,0 +1,49 @@ +From bcb075f466258c8c1b3678dd87b5ef36d3ab1da9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:56 -0300 +Subject: ktest: Avoid undef warning when WARNINGS_FILE is unset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit 057854f8a595160656fe77ed7bf0d2403724b915 ] + +check_buildlog() probes $warnings_file with -f even when WARNINGS_FILE is +not configured. Perl warns about the uninitialized value and adds noise to +the test log, which can hide the output we actually care about. + +Check that WARNINGS_FILE is defined before testing whether the file exists. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-1-565d412f4925@suse.com +Fixes: 4283b169abfb ("ktest: Add make_warnings_file and process full warnings") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 512a3cc586fdd..a5c1871d3c8e7 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -2419,7 +2419,7 @@ sub check_buildlog { + my $save_no_reboot = $no_reboot; + $no_reboot = 1; + +- if (-f $warnings_file) { ++ if (defined($warnings_file) && -f $warnings_file) { + open(IN, $warnings_file) or + dodie "Error opening $warnings_file"; + +-- +2.53.0 + diff --git a/queue-5.10/ktest-honor-empty-per-test-option-overrides.patch b/queue-5.10/ktest-honor-empty-per-test-option-overrides.patch new file mode 100644 index 0000000000..823da21e94 --- /dev/null +++ b/queue-5.10/ktest-honor-empty-per-test-option-overrides.patch @@ -0,0 +1,79 @@ +From fec2b38e11b4a6c46bbff3323651d13e9aba637b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:59 -0300 +Subject: ktest: Honor empty per-test option overrides +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit a2de57a3c8192dcd67cccaff6c341b93748d799b ] + +A per-test override can clear an inherited default option by assigning an +empty value, but __set_test_option() still used option_defined() to decide +whether a per-test key existed. That turned an empty per-test assignment +back into "fall back to the default", so tests still could not clear +inherited settings. + +For example: + + DEFAULTS + (...) + LOG_FILE = /tmp/ktest-empty-override.log + CLEAR_LOG = 1 + ADD_CONFIG = /tmp/.config + + TEST_START + TEST_TYPE = build + BUILD_TYPE = nobuild + ADD_CONFIG = + +This would run the test with ADD_CONFIG[1] = /tmp/.config + +Fix by checking whether the per-test key exists before falling back. If it +does exist but is empty, treat it as unset for that test and stop the +fallback chain there. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-4-565d412f4925@suse.com +Fixes: 22c37a9ac49d ("ktest: Allow tests to undefine default options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index a5c1871d3c8e7..a54ad3115dc17 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -4195,7 +4195,8 @@ sub __set_test_option { + + my $option = "$name\[$i\]"; + +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + +@@ -4203,7 +4204,8 @@ sub __set_test_option { + if ($i >= $test && + $i < $test + $repeat_tests{$test}) { + $option = "$name\[$test\]"; +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + } +-- +2.53.0 + diff --git a/queue-5.10/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch b/queue-5.10/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch new file mode 100644 index 0000000000..6d9382f1aa --- /dev/null +++ b/queue-5.10/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch @@ -0,0 +1,105 @@ +From 3ec248e8a840d3d8fa0dac571a8ce1be09adcae0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:08:03 -0300 +Subject: ktest: Run POST_KTEST hooks on failure and cancellation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit bc6e165a452da909cef0efbc286e6695624db372 ] + +PRE_KTEST can be useful for setting up the environment and POST_KTEST to +tear it down, however POST_KTEST only runs on the normal end-of-run path. +It is skipped when ktest exits through dodie() or cancel_test(). Final +cleanup hooks are skipped. + +Factor the final hook execution into run_post_ktest(), call it from the +normal exit path and from the early exit paths, and guard it so the hook +runs at most once. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-8-565d412f4925@suse.com +Fixes: 921ed4c7208e ("ktest: Add PRE/POST_KTEST and TEST options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index a54ad3115dc17..cadeaa54a71be 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -98,6 +98,7 @@ my $test_type; + my $build_type; + my $build_options; + my $final_post_ktest; ++my $post_ktest_done = 0; + my $pre_ktest; + my $post_ktest; + my $pre_test; +@@ -1477,6 +1478,24 @@ sub get_test_name() { + return $name; + } + ++sub run_post_ktest { ++ my $cmd; ++ ++ return if ($post_ktest_done); ++ ++ if (defined($final_post_ktest)) { ++ $cmd = $final_post_ktest; ++ } elsif (defined($post_ktest)) { ++ $cmd = $post_ktest; ++ } else { ++ return; ++ } ++ ++ my $cp_post_ktest = eval_kernel_version($cmd); ++ run_command $cp_post_ktest; ++ $post_ktest_done = 1; ++} ++ + sub dodie { + + # avoid recursion +@@ -1538,6 +1557,7 @@ sub dodie { + if (defined($post_test)) { + run_command $post_test; + } ++ run_post_ktest; + + die @_, "\n"; + } +@@ -4313,6 +4333,7 @@ sub cancel_test { + send_email("KTEST: Your [$name] test was cancelled", + "Your test started at $script_start_time was cancelled: sig int"); + } ++ run_post_ktest; + die "\nCaught Sig Int, test interrupted: $!\n" + } + +@@ -4524,11 +4545,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { + success $i; + } + +-if (defined($final_post_ktest)) { +- +- my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; +- run_command $cp_final_post_ktest; +-} ++run_post_ktest; + + if ($opt{"POWEROFF_ON_SUCCESS"}) { + halt; +-- +2.53.0 + diff --git a/queue-5.10/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch b/queue-5.10/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch new file mode 100644 index 0000000000..cdf177bbdf --- /dev/null +++ b/queue-5.10/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch @@ -0,0 +1,51 @@ +From 93f41d63be9d7d183c5958708ba05d0bd6d441a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 17:21:43 +0200 +Subject: lib/hexdump: print_hex_dump_bytes() calls print_hex_dump_debug() + +From: Geert Uytterhoeven + +[ Upstream commit 36776b7f8a8955b4e75b5d490a75fee0c7a2a7ef ] + +print_hex_dump_bytes() claims to be a simple wrapper around +print_hex_dump(), but it actally calls print_hex_dump_debug(), which +means no output is printed if (dynamic) DEBUG is disabled. + +Update the documentation to match the implementation. + +Fixes: 091cb0994edd20d6 ("lib/hexdump: make print_hex_dump_bytes() a nop on !DEBUG builds") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Petr Mladek +Link: https://patch.msgid.link/3d5c3069fd9102ecaf81d044b750cd613eb72a08.1774970392.git.geert+renesas@glider.be +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + include/linux/printk.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 344f6da3d4c36..c3f1f7be301db 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -609,7 +609,8 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + #endif + + /** +- * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params ++ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default ++ * params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none +@@ -617,7 +618,7 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + * @buf: data blob to dump + * @len: number of bytes in the @buf + * +- * Calls print_hex_dump(), with log level of KERN_DEBUG, ++ * Calls print_hex_dump_debug(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ + #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ +-- +2.53.0 + diff --git a/queue-5.10/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch b/queue-5.10/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch new file mode 100644 index 0000000000..302b4dcba6 --- /dev/null +++ b/queue-5.10/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch @@ -0,0 +1,75 @@ +From 0fdf9a984e7a5236df18efba749fc31582cb6674 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:15:07 -0700 +Subject: locking: Fix rwlock support in + +From: Bart Van Assche + +[ Upstream commit 756a0e011cfca0b45a48464aa25b05d9a9c2fb0b ] + +Architecture support for rwlocks must be available whether or not +CONFIG_DEBUG_SPINLOCK has been defined. Move the definitions of the +arch_{read,write}_{lock,trylock,unlock}() macros such that these become +visbile if CONFIG_DEBUG_SPINLOCK=n. + +This patch prepares for converting do_raw_{read,write}_trylock() into +inline functions. Without this patch that conversion triggers a build +failure for UP architectures, e.g. arm-ep93xx. I used the following +kernel configuration to build the kernel for that architecture: + + CONFIG_ARCH_MULTIPLATFORM=y + CONFIG_ARCH_MULTI_V7=n + CONFIG_ATAGS=y + CONFIG_MMU=y + CONFIG_ARCH_MULTI_V4T=y + CONFIG_CPU_LITTLE_ENDIAN=y + CONFIG_ARCH_EP93XX=y + +Fixes: fb1c8f93d869 ("[PATCH] spinlock consolidation") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260313171510.230998-2-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/spinlock_up.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h +index 0ac9112c1bbe3..a406655c1fbd1 100644 +--- a/include/linux/spinlock_up.h ++++ b/include/linux/spinlock_up.h +@@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + lock->slock = 1; + } + +-/* +- * Read-write spinlocks. No debug version. +- */ +-#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) +- + #else /* DEBUG_SPINLOCK */ + #define arch_spin_is_locked(lock) ((void)(lock), 0) + /* for sched/core.c and kernel_lock.c: */ +@@ -69,4 +59,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + + #define arch_spin_is_contended(lock) (((void)(lock), 0)) + ++/* ++ * Read-write spinlocks. No debug version. ++ */ ++#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) ++ + #endif /* __LINUX_SPINLOCK_UP_H */ +-- +2.53.0 + diff --git a/queue-5.10/mailbox-add-sanity-check-for-channel-array.patch b/queue-5.10/mailbox-add-sanity-check-for-channel-array.patch new file mode 100644 index 0000000000..13607abb6d --- /dev/null +++ b/queue-5.10/mailbox-add-sanity-check-for-channel-array.patch @@ -0,0 +1,40 @@ +From 76823ade9c44bf42856a6fde5c5373d085a0a69f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:42:38 +0200 +Subject: mailbox: add sanity check for channel array + +From: Wolfram Sang + +[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ] + +Fail gracefully if there is no channel array attached to the mailbox +controller. Otherwise the later dereference will cause an OOPS which +might not be seen because mailbox controllers might instantiate very +early. Remove the comment explaining the obvious while here. + +Fixes: 2b6d83e2b8b7 ("mailbox: Introduce framework for mailbox") +Signed-off-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index 090795c1b65db..363eaf3c962ec 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -484,8 +484,7 @@ int mbox_controller_register(struct mbox_controller *mbox) + { + int i, txdone; + +- /* Sanity check */ +- if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) ++ if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) + return -EINVAL; + + if (mbox->txdone_irq) +-- +2.53.0 + diff --git a/queue-5.10/mailbox-mailbox-test-don-t-free-the-reused-channel.patch b/queue-5.10/mailbox-mailbox-test-don-t-free-the-reused-channel.patch new file mode 100644 index 0000000000..3cb87a604f --- /dev/null +++ b/queue-5.10/mailbox-mailbox-test-don-t-free-the-reused-channel.patch @@ -0,0 +1,46 @@ +From 07a43d3b6d0090de866104b046a952f0170d7947 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:34 +0200 +Subject: mailbox: mailbox-test: don't free the reused channel + +From: Wolfram Sang + +[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ] + +The RX channel can be aliased to the TX channel if it has a different +MMIO. This special case needs to be handled when freeing the channels +otherwise a double-free occurs. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 1d546cae922ce..247e83af060e3 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -423,7 +423,7 @@ static int mbox_test_probe(struct platform_device *pdev) + err_free_chans: + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + return ret; + } +@@ -436,7 +436,7 @@ static int mbox_test_remove(struct platform_device *pdev) + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + + return 0; +-- +2.53.0 + diff --git a/queue-5.10/mailbox-mailbox-test-free-channels-on-probe-error.patch b/queue-5.10/mailbox-mailbox-test-free-channels-on-probe-error.patch new file mode 100644 index 0000000000..bce11faa65 --- /dev/null +++ b/queue-5.10/mailbox-mailbox-test-free-channels-on-probe-error.patch @@ -0,0 +1,60 @@ +From f14eb5fdd5f3791053e3796f6d8b0d07fad3b312 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 14:53:00 +0200 +Subject: mailbox: mailbox-test: free channels on probe error + +From: Wolfram Sang + +[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ] + +On probe error, free the previously obtained channels. This not only +prevents a leak, but also UAF scenarios because the client structure +will be removed nonetheless because it was allocated with devm. + +Link: https://sashiko.dev/#/patchset/20260327151217.5327-2-wsa%2Brenesas%40sang-engineering.com +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 29c04157b5e88..1d546cae922ce 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -405,18 +405,27 @@ static int mbox_test_probe(struct platform_device *pdev) + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +- if (!tdev->rx_buffer) +- return -ENOMEM; ++ if (!tdev->rx_buffer) { ++ ret = -ENOMEM; ++ goto err_free_chans; ++ } + } + + ret = mbox_test_add_debugfs(pdev, tdev); + if (ret) +- return ret; ++ goto err_free_chans; + + init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; ++ ++err_free_chans: ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ if (tdev->rx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ return ret; + } + + static int mbox_test_remove(struct platform_device *pdev) +-- +2.53.0 + diff --git a/queue-5.10/mailbox-mailbox-test-initialize-struct-earlier.patch b/queue-5.10/mailbox-mailbox-test-initialize-struct-earlier.patch new file mode 100644 index 0000000000..b52365416c --- /dev/null +++ b/queue-5.10/mailbox-mailbox-test-initialize-struct-earlier.patch @@ -0,0 +1,64 @@ +From 086782d3765e93fbb9b7e45501baa62d6ea57710 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:35 +0200 +Subject: mailbox: mailbox-test: initialize struct earlier + +From: Wolfram Sang + +[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ] + +The waitqueue must be initialized before the debugfs files are created +because from that time, requests from userspace can already be made. +Similarily, drvdata and spinlock needs to be initialized before we +request the channel, otherwise dangling irqs might run into problems +like a NULL pointer exception. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 247e83af060e3..41efe64976598 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -365,6 +365,12 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev) + return -ENOMEM; + ++ tdev->dev = &pdev->dev; ++ spin_lock_init(&tdev->lock); ++ mutex_init(&tdev->mutex); ++ init_waitqueue_head(&tdev->waitq); ++ platform_set_drvdata(pdev, tdev); ++ + /* It's okay for MMIO to be NULL */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); +@@ -396,12 +402,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) + tdev->rx_channel = tdev->tx_channel; + +- tdev->dev = &pdev->dev; +- platform_set_drvdata(pdev, tdev); +- +- spin_lock_init(&tdev->lock); +- mutex_init(&tdev->mutex); +- + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +@@ -415,7 +415,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (ret) + goto err_free_chans; + +- init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-5.10/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch b/queue-5.10/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch new file mode 100644 index 0000000000..a0ca229de5 --- /dev/null +++ b/queue-5.10/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch @@ -0,0 +1,73 @@ +From 92d3215a313e79656858c6f5056a8cdf8d66c832 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:36 +0200 +Subject: mailbox: mailbox-test: make data_ready a per-instance variable + +From: Wolfram Sang + +[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ] + +While not the default case, multiple tests can be run simultaneously. +Then, data_ready being a global variable will be overwritten and the +per-instance lock will not help. Turn the global variable into a +per-instance one to avoid this problem. + +Fixes: e339c80af95e ("mailbox: mailbox-test: don't rely on rx_buffer content to signal data ready") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 41efe64976598..113858fe168c3 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -27,8 +27,6 @@ + #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ + (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) + +-static bool mbox_data_ready; +- + struct mbox_test_device { + struct device *dev; + void __iomem *tx_mmio; +@@ -41,6 +39,7 @@ struct mbox_test_device { + spinlock_t lock; + struct mutex mutex; + wait_queue_head_t waitq; ++ bool data_ready; + struct fasync_struct *async_queue; + struct dentry *root_debugfs_dir; + }; +@@ -161,7 +160,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); +- data_ready = mbox_data_ready; ++ data_ready = tdev->data_ready; + spin_unlock_irqrestore(&tdev->lock, flags); + + return data_ready; +@@ -226,7 +225,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, + *(touser + l) = '\0'; + + memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); +- mbox_data_ready = false; ++ tdev->data_ready = false; + + spin_unlock_irqrestore(&tdev->lock, flags); + +@@ -296,7 +295,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) + message, MBOX_MAX_MSG_LEN); + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); + } +- mbox_data_ready = true; ++ tdev->data_ready = true; + spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); +-- +2.53.0 + diff --git a/queue-5.10/memory-tegra124-emc-fix-dll_change-check.patch b/queue-5.10/memory-tegra124-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..8bd847c50d --- /dev/null +++ b/queue-5.10/memory-tegra124-emc-fix-dll_change-check.patch @@ -0,0 +1,38 @@ +From 8678cba7757d3c1e643db97c4f9c9887b587f9dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:42 +0900 +Subject: memory: tegra124-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 9597ab9a8296ab337e6820f8a717ff621078b632 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: 73a7f0a90641 ("memory: tegra: Add EMC (external memory controller) driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-1-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra124-emc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c +index dae816e840a96..f5218fea69ed9 100644 +--- a/drivers/memory/tegra/tegra124-emc.c ++++ b/drivers/memory/tegra/tegra124-emc.c +@@ -578,7 +578,7 @@ int tegra_emc_prepare_timing_change(struct tegra_emc *emc, + + if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; +-- +2.53.0 + diff --git a/queue-5.10/memory-tegra30-emc-fix-dll_change-check.patch b/queue-5.10/memory-tegra30-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..4547fc5481 --- /dev/null +++ b/queue-5.10/memory-tegra30-emc-fix-dll_change-check.patch @@ -0,0 +1,47 @@ +From 70705820b253dfe04958eaa1fd8d60f799f8c9d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:43 +0900 +Subject: memory: tegra30-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 0a93f2355cf4922ad2399dbef5ea1049fef116d4 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: e34212c75a68 ("memory: tegra: Introduce Tegra30 EMC driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-2-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra30-emc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c +index 1bd6d3d827aa9..464cdc702754c 100644 +--- a/drivers/memory/tegra/tegra30-emc.c ++++ b/drivers/memory/tegra/tegra30-emc.c +@@ -513,14 +513,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) + emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG); + emc_dbg = readl_relaxed(emc->regs + EMC_DBG); + +- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1)) ++ if (emc->dll_on == !(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; + +- emc->dll_on = !!(timing->emc_mode_1 & 0x1); ++ emc->dll_on = !(timing->emc_mode_1 & 0x1); + + if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL)) + emc->zcal_long = true; +-- +2.53.0 + diff --git a/queue-5.10/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch b/queue-5.10/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch new file mode 100644 index 0000000000..25e32d9235 --- /dev/null +++ b/queue-5.10/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch @@ -0,0 +1,37 @@ +From 7c310c40e6c163d36364a762bac123ae6472e5a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:56:20 +0530 +Subject: mfd: mc13xxx-core: Fix memory leak in mc13xxx_add_subdevice_pdata() + +From: Abdun Nihaal + +[ Upstream commit a5a65a7fb2f7796bbe492cd6be59c92cb64377d1 ] + +The memory allocated for cell.name using kmemdup() is not freed when +mfd_add_devices() fails. Fix that by using devm_kmemdup(). + +Fixes: 8e00593557c3 ("mfd: Add mc13892 support to mc13xxx") +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20260120102622.66921-1-nihaal@cse.iitm.ac.in +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mc13xxx-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c +index e281a9202f110..a2b016a9eeae6 100644 +--- a/drivers/mfd/mc13xxx-core.c ++++ b/drivers/mfd/mc13xxx-core.c +@@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return -E2BIG; + +- cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); ++ cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL); + if (!cell.name) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-5.10/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch b/queue-5.10/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch new file mode 100644 index 0000000000..87339aaa08 --- /dev/null +++ b/queue-5.10/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch @@ -0,0 +1,41 @@ +From 6ad00f9210d29485a903fe36ecd2f63a652124da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:43:36 +0800 +Subject: mtd: physmap_of_gemini: Fix disabled pinctrl state check + +From: Chen Ni + +[ Upstream commit b7c0982184b0661f5b1b805f3a56f1bd3757b63e ] + +The condition for checking the disabled pinctrl state incorrectly checks +gf->enabled_state instead of gf->disabled_state. This causes misleading +error messages and could lead to incorrect behavior when only one of the +pinctrl states is defined. + +Fix the condition to properly check gf->disabled_state. + +Fixes: 9d3b5086f6d4 ("mtd: physmap_of_gemini: Handle pin control") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/maps/physmap-gemini.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c +index d4a46e159d38f..8d5b791dd08d4 100644 +--- a/drivers/mtd/maps/physmap-gemini.c ++++ b/drivers/mtd/maps/physmap-gemini.c +@@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev, + dev_err(dev, "no enabled pin control state\n"); + + gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled"); +- if (IS_ERR(gf->enabled_state)) { ++ if (IS_ERR(gf->disabled_state)) { + dev_err(dev, "no disabled pin control state\n"); + } else { + ret = pinctrl_select_state(gf->p, gf->disabled_state); +-- +2.53.0 + diff --git a/queue-5.10/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch b/queue-5.10/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch new file mode 100644 index 0000000000..b308f08b34 --- /dev/null +++ b/queue-5.10/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch @@ -0,0 +1,66 @@ +From 72b9f21813712d6660878e91805d8636c244d8fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:24:30 +0100 +Subject: mtd: rawnand: sunxi: fix sunxi_nfc_hw_ecc_read_extra_oob + +From: Richard Genoud + +[ Upstream commit 848c13996c55fe4ea6bf5acc3ce6c8c5c944b5f6 ] + +When dumping the OOB, the bytes at the end where actually copied from +the beginning of the OOB instead of current_offset. + +That leads to something like: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +instead of: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +(example with BCH16, user data [8,0], no scrambling) + +*cur_off (offset from the beginning of the page) was compared to offset +(offset from the beginning of the OOB), and then, the +nand_change_read_column_op() sets the current position to the beginning +of the OOB instead of OOB+offset + +Fixes: 15d6f118285f ("mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode") +Reviewed-by: Jernej Skrabec +Signed-off-by: Richard Genoud +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/sunxi_nand.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c +index 782190531f2f0..7ace279778db1 100644 +--- a/drivers/mtd/nand/raw/sunxi_nand.c ++++ b/drivers/mtd/nand/raw/sunxi_nand.c +@@ -887,9 +887,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, + if (len <= 0) + return; + +- if (!cur_off || *cur_off != offset) +- nand_change_read_column_op(nand, mtd->writesize, NULL, 0, +- false); ++ if (!cur_off || *cur_off != (offset + mtd->writesize)) ++ nand_change_read_column_op(nand, mtd->writesize + offset, ++ NULL, 0, false); + + if (!randomize) + sunxi_nfc_read_buf(nand, oob + offset, len); +-- +2.53.0 + diff --git a/queue-5.10/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch b/queue-5.10/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch new file mode 100644 index 0000000000..c43b74106c --- /dev/null +++ b/queue-5.10/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch @@ -0,0 +1,50 @@ +From 83f83a3c2b09da65f0eb21f284e26e8a87f0e420 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:54 -0700 +Subject: net: bcmgenet: fix off-by-one in bcmgenet_put_txcb + +From: Justin Chen + +[ Upstream commit 57f3f53d2c9c5a9e133596e2f7bc1c50688a6d38 ] + +The write_ptr points to the next open tx_cb. We want to return the +tx_cb that gets rewinded, so we must rewind the pointer first then +return the tx_cb that it points to. That way the txcb can be correctly +cleaned up. + +Fixes: 876dbadd53a7 ("net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()") +Signed-off-by: Justin Chen +Reviewed-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-2-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 2fc21aae1004e..8a68384383f7d 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1696,15 +1696,15 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + { + struct enet_cb *tx_cb_ptr; + +- tx_cb_ptr = ring->cbs; +- tx_cb_ptr += ring->write_ptr - ring->cb_ptr; +- + /* Rewinding local write pointer */ + if (ring->write_ptr == ring->cb_ptr) + ring->write_ptr = ring->end_ptr; + else + ring->write_ptr--; + ++ tx_cb_ptr = ring->cbs; ++ tx_cb_ptr += ring->write_ptr - ring->cb_ptr; ++ + return tx_cb_ptr; + } + +-- +2.53.0 + diff --git a/queue-5.10/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch b/queue-5.10/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch new file mode 100644 index 0000000000..0b80659691 --- /dev/null +++ b/queue-5.10/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch @@ -0,0 +1,71 @@ +From a1ed74df39e019672e6de150864c052b82885e70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:31:01 +0800 +Subject: net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf + +From: Mashiro Chen + +[ Upstream commit bf9a38803b2626b01cc769aaf13485d8650f576f ] + +sixpack_receive_buf() does not properly skip bytes with TTY error flags. +The while loop iterates through the flags buffer but never advances the +data pointer (cp), and passes the original count (including error bytes) +to sixpack_decode(). This causes sixpack_decode() to process bytes that +should have been skipped due to TTY errors. The TTY layer does not +guarantee that cp[i] holds a meaningful value when fp[i] is set, so +passing those positions to sixpack_decode() results in KMSAN reporting +an uninit-value read. + +Fix this by processing bytes one at a time, advancing cp on each +iteration, and only passing valid (non-error) bytes to sixpack_decode(). +This matches the pattern used by slip_receive_buf() and +mkiss_receive_buf() for the same purpose. + +Reported-by: syzbot+ecdb8c9878a81eb21e54@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ecdb8c9878a81eb21e54 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Mashiro Chen +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260407173101.107352-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 1964ccbb62c6f..36521f260971a 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -435,7 +435,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) + { + struct sixpack *sp; +- size_t count1; + + if (!count) + return; +@@ -445,16 +444,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, + return; + + /* Read the characters out of the buffer */ +- count1 = count; +- while (count) { +- count--; ++ while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) + sp->dev->stats.rx_errors++; ++ cp++; + continue; + } ++ sixpack_decode(sp, cp, 1); ++ cp++; + } +- sixpack_decode(sp, cp, count1); + + sp_put(sp); + tty_unthrottle(tty); +-- +2.53.0 + diff --git a/queue-5.10/net-phy-dp83869-fix-setting-clk_o_sel-field.patch b/queue-5.10/net-phy-dp83869-fix-setting-clk_o_sel-field.patch new file mode 100644 index 0000000000..38c46d94ee --- /dev/null +++ b/queue-5.10/net-phy-dp83869-fix-setting-clk_o_sel-field.patch @@ -0,0 +1,64 @@ +From 48fdf37bc250069cf2d0406b78525eb457f555d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 05:13:39 +0200 +Subject: net: phy: dp83869: fix setting CLK_O_SEL field. + +From: Heiko Schocher + +[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ] + +Table 7-121 in datasheet says we have to set register 0xc6 +to value 0x10 before CLK_O_SEL can be modified. No more infos +about this field found in datasheet. With this fix, setting +of CLK_O_SEL field in IO_MUX_CFG register worked through dts +property "ti,clk-output-sel" on a DP83869HMRGZR. + +Signed-off-by: Heiko Schocher +Reviewed-by: Simon Horman +Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") +Link: https://patch.msgid.link/20260425031339.3318-1-hs@nabladev.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83869.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c +index e2fe89c8059ea..93f453ac242bb 100644 +--- a/drivers/net/phy/dp83869.c ++++ b/drivers/net/phy/dp83869.c +@@ -30,6 +30,7 @@ + #define DP83869_RGMIICTL 0x0032 + #define DP83869_STRAP_STS1 0x006e + #define DP83869_RGMIIDCTL 0x0086 ++#define DP83869_ANA_PLL_PROG_PI 0x00c6 + #define DP83869_RXFCFG 0x0134 + #define DP83869_RXFPMD1 0x0136 + #define DP83869_RXFPMD2 0x0137 +@@ -791,12 +792,22 @@ static int dp83869_config_init(struct phy_device *phydev) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ +- if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) ++ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { ++ /* ++ * Table 7-121 in datasheet says we have to set register 0xc6 ++ * to value 0x10 before CLK_O_SEL can be modified. ++ */ ++ ret = phy_write_mmd(phydev, DP83869_DEVADDR, ++ DP83869_ANA_PLL_PROG_PI, 0x10); ++ if (ret) ++ return ret; ++ + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); ++ } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, +-- +2.53.0 + diff --git a/queue-5.10/net-rds-optimize-rds_ib_laddr_check.patch b/queue-5.10/net-rds-optimize-rds_ib_laddr_check.patch new file mode 100644 index 0000000000..b43827ed77 --- /dev/null +++ b/queue-5.10/net-rds-optimize-rds_ib_laddr_check.patch @@ -0,0 +1,189 @@ +From 59cdb2b3822444a96f3dce9be0fd11937741fd88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:19 -0700 +Subject: net/rds: Optimize rds_ib_laddr_check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 236f718ac885965fa886440b9898dfae185c9733 ] + +rds_ib_laddr_check() creates a CM_ID and attempts to bind the address +in question to it. This in order to qualify the allegedly local +address as a usable IB/RoCE address. + +In the field, ExaWatcher runs rds-ping to all ports in the fabric from +all local ports. This using all active ToS'es. In a full rack system, +we have 14 cell servers and eight db servers. Typically, 6 ToS'es are +used. This implies 528 rds-ping invocations per ExaWatcher's "RDSinfo" +interval. + +Adding to this, each rds-ping invocation creates eight sockets and +binds the local address to them: + +socket(AF_RDS, SOCK_SEQPACKET, 0) = 3 +bind(3, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 4 +bind(4, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 5 +bind(5, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 6 +bind(6, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 7 +bind(7, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 8 +bind(8, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 9 +bind(9, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 10 +bind(10, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 + +So, at every interval ExaWatcher executes rds-ping's, 4224 CM_IDs are +allocated, considering this full-rack system. After the a CM_ID has +been allocated, rdma_bind_addr() is called, with the port number being +zero. This implies that the CMA will attempt to search for an un-used +ephemeral port. Simplified, the algorithm is to start at a random +position in the available port space, and then if needed, iterate +until an un-used port is found. + +The book-keeping of used ports uses the idr system, which again uses +slab to allocate new struct idr_layer's. The size is 2092 bytes and +slab tries to reduce the wasted space. Hence, it chooses an order:3 +allocation, for which 15 idr_layer structs will fit and only 1388 +bytes are wasted per the 32KiB order:3 chunk. + +Although this order:3 allocation seems like a good space/speed +trade-off, it does not resonate well with how it used by the CMA. The +combination of the randomized starting point in the port space (which +has close to zero spatial locality) and the close proximity in time of +the 4224 invocations of the rds-ping's, creates a memory hog for +order:3 allocations. + +These costly allocations may need reclaims and/or compaction. At +worst, they may fail and produce a stack trace such as (from uek4): + +[] __inc_zone_page_state+0x35/0x40 +[] page_add_file_rmap+0x57/0x60 +[] remove_migration_pte+0x3f/0x3c0 [ksplice_6cn872bt_vmlinux_new] +[] rmap_walk+0xd8/0x340 +[] remove_migration_ptes+0x40/0x50 +[] migrate_pages+0x3ec/0x890 +[] compact_zone+0x32d/0x9a0 +[] compact_zone_order+0x6d/0x90 +[] try_to_compact_pages+0x102/0x270 +[] __alloc_pages_direct_compact+0x46/0x100 +[] __alloc_pages_nodemask+0x74b/0xaa0 +[] alloc_pages_current+0x91/0x110 +[] new_slab+0x38b/0x480 +[] __slab_alloc+0x3b7/0x4a0 [ksplice_s0dk66a8_vmlinux_new] +[] kmem_cache_alloc+0x1fb/0x250 +[] idr_layer_alloc+0x36/0x90 +[] idr_get_empty_slot+0x28c/0x3d0 +[] idr_alloc+0x4d/0xf0 +[] cma_alloc_port+0x4d/0xa0 [rdma_cm] +[] rdma_bind_addr+0x2ae/0x5b0 [rdma_cm] +[] rds_ib_laddr_check+0x83/0x2c0 [ksplice_6l2xst5i_rds_rdma_new] +[] rds_trans_get_preferred+0x5b/0xa0 [rds] +[] rds_bind+0x212/0x280 [rds] +[] SYSC_bind+0xe6/0x120 +[] SyS_bind+0xe/0x10 +[] system_call_fastpath+0x18/0xd4 + +To avoid these excessive calls to rdma_bind_addr(), we optimize +rds_ib_laddr_check() by simply checking if the address in question has +been used before. The rds_rdma module keeps track of addresses +associated with IB devices, and the function rds_ib_get_device() is +used to determine if the address already has been qualified as a valid +local address. If not found, we call the legacy rds_ib_laddr_check(), +now renamed to rds_ib_laddr_check_cm(). + +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Somasundaram Krishnasamy +Signed-off-by: Gerd Rausch +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-2-achender@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: ebf71dd4aff4 ("net/rds: Restrict use of RDS/IB to the initial network namespace") +Signed-off-by: Sasha Levin +--- + net/rds/ib.c | 20 ++++++++++++++++++-- + net/rds/ib.h | 1 + + net/rds/ib_rdma.c | 2 +- + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 24c9a9005a6fb..dbc63493ade70 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -403,8 +403,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len, + * allowed to influence which paths have priority. We could call userspace + * asserting this policy "routing". + */ +-static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, +- __u32 scope_id) ++static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) + { + int ret; + struct rdma_cm_id *cm_id; +@@ -489,6 +489,22 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + return ret; + } + ++static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) ++{ ++ struct rds_ib_device *rds_ibdev = NULL; ++ ++ if (ipv6_addr_v4mapped(addr)) { ++ rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); ++ if (rds_ibdev) { ++ rds_ib_dev_put(rds_ibdev); ++ return 0; ++ } ++ } ++ ++ return rds_ib_laddr_check_cm(net, addr, scope_id); ++} ++ + static void rds_ib_unregister_client(void) + { + ib_unregister_client(&rds_ib_client); +diff --git a/net/rds/ib.h b/net/rds/ib.h +index 2ba71102b1f1f..d6c1197731c1c 100644 +--- a/net/rds/ib.h ++++ b/net/rds/ib.h +@@ -384,6 +384,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, + __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) + + /* ib_rdma.c */ ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr); + int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, + struct in6_addr *ipaddr); + void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); +diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c +index 30fca2169aa7a..468fd60d818ff 100644 +--- a/net/rds/ib_rdma.c ++++ b/net/rds/ib_rdma.c +@@ -47,7 +47,7 @@ struct rds_ib_dereg_odp_mr { + + static void rds_ib_odp_mr_worker(struct work_struct *work); + +-static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) + { + struct rds_ib_device *rds_ibdev; + struct rds_ib_ipaddr *i_ipaddr; +-- +2.53.0 + diff --git a/queue-5.10/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch b/queue-5.10/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch new file mode 100644 index 0000000000..487fc95a39 --- /dev/null +++ b/queue-5.10/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch @@ -0,0 +1,86 @@ +From 78ab15307835e9412d48936233dc202c8000a6bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:20 -0700 +Subject: net/rds: Restrict use of RDS/IB to the initial network namespace + +From: Greg Jumper + +[ Upstream commit ebf71dd4aff46e8e421d455db3e231ba43d2fa8a ] + +Prevent using RDS/IB in network namespaces other than the initial one. +The existing RDS/IB code will not work properly in non-initial network +namespaces. + +Fixes: d5a8ac28a7ff ("RDS-TCP: Make RDS-TCP work correctly when it is set up in a netns other than init_net") +Reported-by: syzbot+da8e060735ae02c8f3d1@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=da8e060735ae02c8f3d1 +Signed-off-by: Greg Jumper +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-3-achender@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/af_rds.c | 10 ++++++++-- + net/rds/ib.c | 4 ++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c +index 0ec0ae1483492..ca1b52372ab29 100644 +--- a/net/rds/af_rds.c ++++ b/net/rds/af_rds.c +@@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen) + return ret; + } + +-static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) ++static int rds_set_transport(struct net *net, struct rds_sock *rs, ++ sockptr_t optval, int optlen) + { + int t_type; + +@@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) + if (t_type < 0 || t_type >= RDS_TRANS_COUNT) + return -EINVAL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + rs->rs_transport = rds_trans_get(t_type); + + return rs->rs_transport ? 0 : -ENOPROTOOPT; +@@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) + { + struct rds_sock *rs = rds_sk_to_rs(sock->sk); ++ struct net *net = sock_net(sock->sk); + int ret; + + if (level != SOL_RDS) { +@@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + break; + case SO_RDS_TRANSPORT: + lock_sock(sock->sk); +- ret = rds_set_transport(rs, optval, optlen); ++ ret = rds_set_transport(net, rs, optval, optlen); + release_sock(sock->sk); + break; + case SO_TIMESTAMP_OLD: +diff --git a/net/rds/ib.c b/net/rds/ib.c +index dbc63493ade70..ec45664f38767 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -494,6 +494,10 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + { + struct rds_ib_device *rds_ibdev = NULL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (!net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + if (ipv6_addr_v4mapped(addr)) { + rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); + if (rds_ibdev) { +-- +2.53.0 + diff --git a/queue-5.10/net-rds-zero-per-item-info-buffer-before-handing-it-.patch b/queue-5.10/net-rds-zero-per-item-info-buffer-before-handing-it-.patch new file mode 100644 index 0000000000..5d44b2b524 --- /dev/null +++ b/queue-5.10/net-rds-zero-per-item-info-buffer-before-handing-it-.patch @@ -0,0 +1,111 @@ +From 72285006b373dcafc1859ea5ba3c4fc3fc72feb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 10:10:47 -0400 +Subject: net/rds: zero per-item info buffer before handing it to visitors + +From: Michael Bommarito + +[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ] + +rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a +caller-allocated on-stack u64 buffer to a per-connection visitor and +then copy the full item_len bytes back to user space via +rds_info_copy() regardless of how much of the buffer the visitor +actually wrote. + +rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only +write a subset of their output struct when the underlying +rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl +and the two GIDs via explicit memsets). Several u32 fields +(max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, +cache_allocs) and the 2-byte alignment hole between sl and +cache_allocs remain as whatever stack contents preceded the visitor +call and are then memcpy_to_user()'d out to user space. + +struct rds_info_rdma_connection and struct rds6_info_rdma_connection +are the only rds_info_* structs in include/uapi/linux/rds.h that are +not marked __attribute__((packed)), so they have a real alignment +hole. The other info visitors (rds_conn_info_visitor, +rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of +their packed output struct today and are not known to be vulnerable, +but a future visitor that adds a conditional write-path would have +the same bug. + +Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y: +a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, +binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on +any netdev is sufficient), sendto()'s any peer on the same subnet +(fails cleanly but installs an rds_connection in the global hash in +RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, +RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 +bytes of stack garbage including kernel text/data pointers: + + 0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2 + 8..39 00 ... gids (memset-zeroed) + 40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr) + 48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max) + 56..59 01 00 08 00 rdma_mr_size (garbage) + 60..61 00 00 tos, sl + 62..63 00 00 alignment padding + 64..67 18 00 00 00 cache_allocs (garbage) + +Fix by zeroing the per-item buffer in both rds_for_each_conn_info() +and rds_walk_conn_path_info() before invoking the visitor. This +covers the IPv4/IPv6 IB visitors and hardens all current and future +visitors against the same class of bug. + +No functional change for visitors that fully populate their output. + +Changes in v2: +- retarget at the net tree (subject prefix "[PATCH net v2]", + net/rds: prefix in the title) +- pick up Reviewed-by tags from Sharath Srinivasan and + Allison Henderson + +Fixes: ec16227e1414 ("RDS/IB: Infiniband transport") +Signed-off-by: Michael Bommarito +Reviewed-by: Sharath Srinivasan +Reviewed-by: Allison Henderson +Assisted-by: Claude:claude-opus-4-7 +Link: https://patch.msgid.link/20260418141047.3398203-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/connection.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index 98c0d5ff9de9c..cd41f83863c89 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -673,6 +673,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, + i++, head++) { + hlist_for_each_entry_rcu(conn, head, c_hash_node) { + ++ /* Zero the per-item buffer before handing it to the ++ * visitor so any field the visitor does not write - ++ * including implicit alignment padding - cannot leak ++ * stack contents to user space via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no c_lock usage.. */ + if (!visitor(conn, buffer)) + continue; +@@ -722,6 +729,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, + */ + cp = conn->c_path; + ++ /* Zero the per-item buffer for the same reason as ++ * rds_for_each_conn_info(): any byte the visitor ++ * does not write (including alignment padding) must ++ * not leak stack contents via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no cp_lock usage.. */ + if (!visitor(cp, buffer)) + continue; +-- +2.53.0 + diff --git a/queue-5.10/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch b/queue-5.10/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch new file mode 100644 index 0000000000..87519a8c68 --- /dev/null +++ b/queue-5.10/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch @@ -0,0 +1,130 @@ +From bd54594469d10ec3bac6dbf10fd34cd802511c22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:16:27 -0400 +Subject: net/sched: act_ct: Only release RCU read lock after ct_ft + +From: Jamal Hadi Salim + +[ Upstream commit f462dca0c8415bf0058d0ffa476354c4476d0f09 ] + +When looking up a flow table in act_ct in tcf_ct_flow_table_get(), +rhashtable_lookup_fast() internally opens and closes an RCU read critical +section before returning ct_ft. +The tcf_ct_flow_table_cleanup_work() can complete before refcount_inc_not_zero() +is invoked on the returned ct_ft resulting in a UAF on the already freed ct_ft +object. This vulnerability can lead to privilege escalation. + +Analysis from zdi-disclosures@trendmicro.com: +When initializing act_ct, tcf_ct_init() is called, which internally triggers +tcf_ct_flow_table_get(). + +static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + +{ + struct zones_ht_key key = { .net = net, .zone = params->zone }; + struct tcf_ct_flow_table *ct_ft; + int err = -ENOMEM; + + mutex_lock(&zones_mutex); + ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); // [1] + if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) // [2] + goto out_unlock; + ... +} + +static __always_inline void *rhashtable_lookup_fast( + struct rhashtable *ht, const void *key, + const struct rhashtable_params params) +{ + void *obj; + + rcu_read_lock(); + obj = rhashtable_lookup(ht, key, params); + rcu_read_unlock(); + + return obj; +} + +At [1], rhashtable_lookup_fast() looks up and returns the corresponding ct_ft +from zones_ht . The lookup is performed within an RCU read critical section +through rcu_read_lock() / rcu_read_unlock(), which prevents the object from +being freed. However, at the point of function return, rcu_read_unlock() has +already been called, and there is nothing preventing ct_ft from being freed +before reaching refcount_inc_not_zero(&ct_ft->ref) at [2]. This interval becomes +the race window, during which ct_ft can be freed. + +Free Process: + +tcf_ct_flow_table_put() is executed through the path tcf_ct_cleanup() call_rcu() +tcf_ct_params_free_rcu() tcf_ct_params_free() tcf_ct_flow_table_put(). + +static void tcf_ct_flow_table_put(struct tcf_ct_flow_table *ct_ft) +{ + if (refcount_dec_and_test(&ct_ft->ref)) { + rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params); + INIT_RCU_WORK(&ct_ft->rwork, tcf_ct_flow_table_cleanup_work); // [3] + queue_rcu_work(act_ct_wq, &ct_ft->rwork); + } +} + +At [3], tcf_ct_flow_table_cleanup_work() is scheduled as RCU work + +static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) + +{ + struct tcf_ct_flow_table *ct_ft; + struct flow_block *block; + + ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, + rwork); + nf_flow_table_free(&ct_ft->nf_ft); + block = &ct_ft->nf_ft.flow_block; + down_write(&ct_ft->nf_ft.flow_block_lock); + WARN_ON(!list_empty(&block->cb_list)); + up_write(&ct_ft->nf_ft.flow_block_lock); + kfree(ct_ft); // [4] + + module_put(THIS_MODULE); +} + +tcf_ct_flow_table_cleanup_work() frees ct_ft at [4]. When this function executes +between [1] and [2], UAF occurs. + +This race condition has a very short race window, making it generally +difficult to trigger. Therefore, to trigger the vulnerability an msleep(100) was +inserted after[1] + +Fixes: 138470a9b2cc2 ("net/sched: act_ct: fix lockdep splat in tcf_ct_flow_table_get") +Reported-by: zdi-disclosures@trendmicro.com +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260410111627.46611-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/act_ct.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index d75f4b2b97daa..adb421684440a 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -289,9 +289,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + int err = -ENOMEM; + + mutex_lock(&zones_mutex); +- ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); +- if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) ++ rcu_read_lock(); ++ ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params); ++ if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) { ++ rcu_read_unlock(); + goto out_unlock; ++ } ++ rcu_read_unlock(); + + ct_ft = kzalloc(sizeof(*ct_ft), GFP_KERNEL); + if (!ct_ft) +-- +2.53.0 + diff --git a/queue-5.10/net-sched-choke-remove-unused-variables-in-struct-ch.patch b/queue-5.10/net-sched-choke-remove-unused-variables-in-struct-ch.patch new file mode 100644 index 0000000000..2197954900 --- /dev/null +++ b/queue-5.10/net-sched-choke-remove-unused-variables-in-struct-ch.patch @@ -0,0 +1,42 @@ +From 15342668165ce0a1d3b2f50935e659295aca554c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Aug 2022 17:22:54 +0800 +Subject: net: sched: choke: remove unused variables in struct choke_sched_data + +From: Zhengchao Shao + +[ Upstream commit 38af11717b386560f10f2891350933fc5200aeea ] + +The variable "other" in the struct choke_sched_data is not used. Remove it. + +Signed-off-by: Zhengchao Shao +Signed-off-by: Jakub Kicinski +Stable-dep-of: d3aeb889dcbd ("net/sched: sch_choke: annotate data-races in choke_dump_stats()") +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index f3805bee995bb..e38cf34287018 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -60,7 +60,6 @@ struct choke_sched_data { + u32 forced_drop; /* Forced drops, qavg > max_thresh */ + u32 forced_mark; /* Forced marks, qavg > max_thresh */ + u32 pdrop; /* Drops due to queue limits */ +- u32 other; /* Drops due to drop() calls */ + u32 matched; /* Drops to flow match */ + } stats; + +@@ -464,7 +463,6 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + .early = q->stats.prob_drop + q->stats.forced_drop, + .marked = q->stats.prob_mark + q->stats.forced_mark, + .pdrop = q->stats.pdrop, +- .other = q->stats.other, + .matched = q->stats.matched, + }; + +-- +2.53.0 + diff --git a/queue-5.10/net-sched-gred-red-remove-unused-variables-in-struct.patch b/queue-5.10/net-sched-gred-red-remove-unused-variables-in-struct.patch new file mode 100644 index 0000000000..d2249baeee --- /dev/null +++ b/queue-5.10/net-sched-gred-red-remove-unused-variables-in-struct.patch @@ -0,0 +1,69 @@ +From 57d75ec7b4f06d73f176defd6819417bbd643830 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Aug 2022 17:22:55 +0800 +Subject: net: sched: gred/red: remove unused variables in struct red_stats + +From: Zhengchao Shao + +[ Upstream commit 4516c873e3b55856012ddd6db9d4366ce3c60c5d ] + +The variable "other" in the struct red_stats is not used. Remove it. + +Signed-off-by: Zhengchao Shao +Signed-off-by: Jakub Kicinski +Stable-dep-of: a8f5192809ca ("net/sched: sch_red: annotate data-races in red_dump_stats()") +Signed-off-by: Sasha Levin +--- + include/net/red.h | 1 - + net/sched/sch_gred.c | 3 --- + net/sched/sch_red.c | 1 - + 3 files changed, 5 deletions(-) + +diff --git a/include/net/red.h b/include/net/red.h +index cc9f6b0d7f1e9..2fc217a07ade4 100644 +--- a/include/net/red.h ++++ b/include/net/red.h +@@ -122,7 +122,6 @@ struct red_stats { + u32 forced_drop; /* Forced drops, qavg > max_thresh */ + u32 forced_mark; /* Forced marks, qavg > max_thresh */ + u32 pdrop; /* Drops due to queue limits */ +- u32 other; /* Drops due to drop() calls */ + }; + + struct red_parms { +diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c +index f4132dc25ac05..db3b695d072be 100644 +--- a/net/sched/sch_gred.c ++++ b/net/sched/sch_gred.c +@@ -817,7 +817,6 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) + opt.Wlog = q->parms.Wlog; + opt.Plog = q->parms.Plog; + opt.Scell_log = q->parms.Scell_log; +- opt.other = q->stats.other; + opt.early = q->stats.prob_drop; + opt.forced = q->stats.forced_drop; + opt.pdrop = q->stats.pdrop; +@@ -883,8 +882,6 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) + goto nla_put_failure; + if (nla_put_u32(skb, TCA_GRED_VQ_STAT_PDROP, q->stats.pdrop)) + goto nla_put_failure; +- if (nla_put_u32(skb, TCA_GRED_VQ_STAT_OTHER, q->stats.other)) +- goto nla_put_failure; + + nla_nest_end(skb, vq); + } +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index 063431a5ae1dd..a2c1db8ac3945 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -463,7 +463,6 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + } + st.early = q->stats.prob_drop + q->stats.forced_drop; + st.pdrop = q->stats.pdrop; +- st.other = q->stats.other; + st.marked = q->stats.prob_mark + q->stats.forced_mark; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-5.10/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch b/queue-5.10/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch new file mode 100644 index 0000000000..c3dcc30de1 --- /dev/null +++ b/queue-5.10/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch @@ -0,0 +1,67 @@ +From 6a93646c10d5857a774edfba4bae7f3b2b5645a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:39 -0700 +Subject: net/sched: netem: fix probability gaps in 4-state loss model + +From: Stephen Hemminger + +[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ] + +The 4-state Markov chain in loss_4state() has gaps at the boundaries +between transition probability ranges. The comparisons use: + + if (rnd < a4) + else if (a4 < rnd && rnd < a1 + a4) + +When rnd equals a boundary value exactly, neither branch matches and +no state transition occurs. The redundant lower-bound check (a4 < rnd) +is already implied by being in the else branch. + +Remove the unnecessary lower-bound comparisons so the ranges are +contiguous and every random value produces a transition, matching +the GI (General and Intuitive) loss model specification. + +This bug goes back to original implementation of this model. + +Fixes: 661b79725fea ("netem: revised correlated loss generator") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-2-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index cbd7f3032fccf..1f47711cb1667 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -219,10 +219,10 @@ static bool loss_4state(struct netem_sched_data *q) + if (rnd < clg->a4) { + clg->state = LOST_IN_GAP_PERIOD; + return true; +- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { ++ } else if (rnd < clg->a1 + clg->a4) { + clg->state = LOST_IN_BURST_PERIOD; + return true; +- } else if (clg->a1 + clg->a4 < rnd) { ++ } else { + clg->state = TX_IN_GAP_PERIOD; + } + +@@ -239,9 +239,9 @@ static bool loss_4state(struct netem_sched_data *q) + case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; +- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { ++ else if (rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; +- } else if (clg->a2 + clg->a3 < rnd) { ++ } else { + clg->state = LOST_IN_BURST_PERIOD; + return true; + } +-- +2.53.0 + diff --git a/queue-5.10/net-sched-netem-fix-queue-limit-check-to-include-reo.patch b/queue-5.10/net-sched-netem-fix-queue-limit-check-to-include-reo.patch new file mode 100644 index 0000000000..a2ea7365ec --- /dev/null +++ b/queue-5.10/net-sched-netem-fix-queue-limit-check-to-include-reo.patch @@ -0,0 +1,42 @@ +From 1c6895281bd0ffd46c3901eec7bbd852c813fed8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:40 -0700 +Subject: net/sched: netem: fix queue limit check to include reordered packets + +From: Stephen Hemminger + +[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ] + +The queue limit check in netem_enqueue() uses q->t_len which only +counts packets in the internal tfifo. Packets placed in sch->q by +the reorder path (__qdisc_enqueue_head) are not counted, allowing +the total queue occupancy to exceed sch->limit under reordering. + +Include sch->q.qlen in the limit check. + +Fixes: f8d4bc455047 ("net/sched: netem: account for backlog updates from child qdisc") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-3-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 1f47711cb1667..64542c9c15340 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -512,7 +512,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + 1<<(prandom_u32() % 8); + } + +- if (unlikely(q->t_len >= sch->limit)) { ++ if (unlikely(sch->q.qlen >= sch->limit)) { + /* re-link segs, so that qdisc_drop_all() frees them all */ + skb->next = segs; + qdisc_drop_all(skb, sch, to_free); +-- +2.53.0 + diff --git a/queue-5.10/net-sched-netem-validate-slot-configuration.patch b/queue-5.10/net-sched-netem-validate-slot-configuration.patch new file mode 100644 index 0000000000..a469782bbd --- /dev/null +++ b/queue-5.10/net-sched-netem-validate-slot-configuration.patch @@ -0,0 +1,86 @@ +From 50e8c3f39451cdfac7ecc194e3d76dabca141acd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:42 -0700 +Subject: net/sched: netem: validate slot configuration + +From: Stephen Hemminger + +[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ] + +Reject slot configurations that have no defensible meaning: + + - negative min_delay or max_delay + - min_delay greater than max_delay + - negative dist_delay or dist_jitter + - negative max_packets or max_bytes + +Negative or out-of-order delays underflow in get_slot_next(), +producing garbage intervals. Negative limits trip the per-slot +accounting (packets_left/bytes_left <= 0) on the first packet of +every slot, defeating the rate-limiting half of the slot feature. + +Note that dist_jitter has been silently coerced to its absolute +value by get_slot() since the feature was introduced; rejecting +negatives here converts that silent coercion into -EINVAL. The +abs() can be removed in a follow-up. + +Fixes: 836af83b54e3 ("netem: support delivering packets in delayed time slots") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 64542c9c15340..3e3bced82c564 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -815,6 +815,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) ++{ ++ const struct tc_netem_slot *c = nla_data(attr); ++ ++ if (c->min_delay < 0 || c->max_delay < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); ++ return -EINVAL; ++ } ++ if (c->min_delay > c->max_delay) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); ++ return -EINVAL; ++ } ++ if (c->dist_delay < 0 || c->dist_jitter < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); ++ return -EINVAL; ++ } ++ if (c->max_packets < 0 || c->max_bytes < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1030,6 +1053,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_SLOT]) { ++ ret = validate_slot(tb[TCA_NETEM_SLOT], extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch b/queue-5.10/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch new file mode 100644 index 0000000000..df01cf0c9b --- /dev/null +++ b/queue-5.10/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch @@ -0,0 +1,62 @@ +From 3aa764de1467593c6300c28bcdd1f909c0dedea1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:06 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (V) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations +for cparams.target and cparams.interval. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 96bd0d36d8c12..2be03c8d13cb0 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -2313,10 +2313,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + + byte_target_ns = (byte_target * rate_ns) >> rate_shft; + +- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); +- b->cparams.interval = max(rtt_est_ns + +- b->cparams.target - target_ns, +- b->cparams.target * 2); ++ WRITE_ONCE(b->cparams.target, ++ max((byte_target_ns * 3) / 2, target_ns)); ++ WRITE_ONCE(b->cparams.interval, ++ max(rtt_est_ns + b->cparams.target - target_ns, ++ b->cparams.target * 2)); + b->cparams.mtu_time = byte_target_ns; + b->cparams.p_inc = 1 << 24; /* 1/256 */ + b->cparams.p_dec = 1 << 20; /* 1/4096 */ +@@ -2933,9 +2934,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); + + PUT_TSTAT_U32(TARGET_US, +- ktime_to_us(ns_to_ktime(b->cparams.target))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); + PUT_TSTAT_U32(INTERVAL_US, +- ktime_to_us(ns_to_ktime(b->cparams.interval))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); + + PUT_TSTAT_U32(SENT_PACKETS, b->packets); + PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch b/queue-5.10/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch new file mode 100644 index 0000000000..7631cfbc5b --- /dev/null +++ b/queue-5.10/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch @@ -0,0 +1,64 @@ +From bcb875abeb0ea91047ef22e3c8ad37cb203d6cd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:00:41 +0800 +Subject: net/sched: sch_cake: fix NAT destination port not being updated in + cake_update_flowkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit f9e40664706927d7ae22a448a3383e23c38a4c0b ] + +cake_update_flowkeys() is supposed to update the flow dissector keys +with the NAT-translated addresses and ports from conntrack, so that +CAKE's per-flow fairness correctly identifies post-NAT flows as +belonging to the same connection. + +For the source port, this works correctly: + keys->ports.src = port; + +But for the destination port, the assignment is reversed: + port = keys->ports.dst; + +This means the NAT destination port is never updated in the flow keys. +As a result, when multiple connections are NATed to the same destination, +CAKE treats them as separate flows because the original (pre-NAT) +destination ports differ. This breaks CAKE's NAT-aware flow isolation +when using the "nat" mode. + +The bug was introduced in commit b0c19ed6088a ("sch_cake: Take advantage +of skb->hash where appropriate") which refactored the original direct +assignment into a compare-and-conditionally-update pattern, but wrote +the destination port update backwards. + +Fix by reversing the assignment direction to match the source port +pattern. + +Fixes: b0c19ed6088a ("sch_cake: Take advantage of skb->hash where appropriate") +Signed-off-by: Dudu Lu +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260413110041.44704-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index edf9a6e328d22..96bd0d36d8c12 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -619,7 +619,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys, + } + port = rev ? tuple.src.u.all : tuple.dst.u.all; + if (port != keys->ports.dst) { +- port = keys->ports.dst; ++ keys->ports.dst = port; + upd = true; + } + } +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch b/queue-5.10/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch new file mode 100644 index 0000000000..25a9db7613 --- /dev/null +++ b/queue-5.10/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch @@ -0,0 +1,97 @@ +From 94f428bc41da7c0f303dcda2950e2e3fc684715b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:28:39 +0000 +Subject: net/sched: sch_choke: annotate data-races in choke_dump_stats() + +From: Eric Dumazet + +[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ] + +choke_dump_stats() only runs with RTNL held. +It reads fields that can be changed in qdisc fast path. +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423062839.2524324-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index e38cf34287018..7283f96dead62 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + /* Draw a packet at random from queue and compare flow */ + if (choke_match_random(q, skb, &idx)) { +- q->stats.matched++; ++ WRITE_ONCE(q->stats.matched, q->stats.matched + 1); + choke_drop_by_idx(sch, idx, to_free); + goto congestion_drop; + } +@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + qdisc_qstats_overlimit(sch); + if (use_harddrop(q) || !use_ecn(q) || + !INET_ECN_set_ce(skb)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + } else if (++q->vars.qcount) { + if (red_mark_probability(p, &q->vars, q->vars.qavg)) { + q->vars.qcount = 0; +@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + qdisc_qstats_overlimit(sch); + if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + } + } else + q->vars.qR = red_random(p); +@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + } + +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); + return qdisc_drop(skb, sch, to_free); + + congestion_drop: +@@ -460,10 +464,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct choke_sched_data *q = qdisc_priv(sch); + struct tc_choke_xstats st = { +- .early = q->stats.prob_drop + q->stats.forced_drop, +- .marked = q->stats.prob_mark + q->stats.forced_mark, +- .pdrop = q->stats.pdrop, +- .matched = q->stats.matched, ++ .early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop), ++ .marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark), ++ .pdrop = READ_ONCE(q->stats.pdrop), ++ .matched = READ_ONCE(q->stats.matched), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch b/queue-5.10/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch new file mode 100644 index 0000000000..e2b5bf5671 --- /dev/null +++ b/queue-5.10/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch @@ -0,0 +1,47 @@ +From 68c04c5b2bfb08cc4bc7d361820561094a7c4674 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:25:09 +0000 +Subject: net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats() + +From: Eric Dumazet + +[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill st.qdisc_stats with live data. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142509.3967231-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_codel.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 3c1efe360defa..10bdc0de394cc 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -559,6 +559,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + }; + struct list_head *pos; + ++ sch_tree_lock(sch); ++ + st.qdisc_stats.maxpacket = q->cstats.maxpacket; + st.qdisc_stats.drop_overlimit = q->drop_overlimit; + st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; +@@ -567,7 +569,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + st.qdisc_stats.memory_usage = q->memory_usage; + st.qdisc_stats.drop_overmemory = q->drop_overmemory; + +- sch_tree_lock(sch); + list_for_each(pos, &q->new_flows) + st.qdisc_stats.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch b/queue-5.10/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch new file mode 100644 index 0000000000..ac96103008 --- /dev/null +++ b/queue-5.10/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch @@ -0,0 +1,62 @@ +From 300cf012a2e1d3a74ae06841271ff216108dd19c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:35:27 +0000 +Subject: net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill tc_fq_pie_xstats with live data. + +Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, +but the spinlock is needed anyway to scan q->new_flows and q->old_flows. + +Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423063527.2568262-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_pie.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index d4bfa3382e118..b62a1c0c4817f 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -499,18 +499,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb) + static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct fq_pie_sched_data *q = qdisc_priv(sch); +- struct tc_fq_pie_xstats st = { +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .overmemory = q->overmemory, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, +- .new_flow_count = q->new_flow_count, +- .memory_usage = q->memory_usage, +- }; ++ struct tc_fq_pie_xstats st = { 0 }; + struct list_head *pos; + + sch_tree_lock(sch); ++ ++ st.packets_in = q->stats.packets_in; ++ st.overlimit = q->stats.overlimit; ++ st.overmemory = q->overmemory; ++ st.dropped = q->stats.dropped; ++ st.ecn_mark = q->stats.ecn_mark; ++ st.new_flow_count = q->new_flow_count; ++ st.memory_usage = q->memory_usage; ++ + list_for_each(pos, &q->new_flows) + st.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_netem-refactor-code-in-4-state-loss-ge.patch b/queue-5.10/net-sched-sch_netem-refactor-code-in-4-state-loss-ge.patch new file mode 100644 index 0000000000..99b33b8389 --- /dev/null +++ b/queue-5.10/net-sched-sch_netem-refactor-code-in-4-state-loss-ge.patch @@ -0,0 +1,89 @@ +From 84a425151092ca9122bd7ca7a26cc04575c1372f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Nov 2021 13:36:47 -0800 +Subject: net: sched: sch_netem: Refactor code in 4-state loss generator + +From: Harshit Mogalapalli + +[ Upstream commit cb3ef7b00042479277cda7871d899378ad91f081 ] + +Fixed comments to match description with variable names and +refactored code to match the convention as per [1]. + +To match the convention mapping is done as follows: +State 3 - LOST_IN_BURST_PERIOD +State 4 - LOST_IN_GAP_PERIOD + +[1] S. Salsano, F. Ludovici, A. Ordine, "Definition of a general +and intuitive loss model for packet networks and its implementation +in the Netem module in the Linux kernel" + +Fixes: a6e2fe17eba4 ("sch_netem: replace magic numbers with enumerate") +Signed-off-by: Harshit Mogalapalli +Acked-by: Stephen Hemminger +Signed-off-by: David S. Miller +Stable-dep-of: 732b463449fd ("net/sched: netem: fix probability gaps in 4-state loss model") +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 951156d7e5485..cbd7f3032fccf 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -210,17 +210,17 @@ static bool loss_4state(struct netem_sched_data *q) + * next state and if the next packet has to be transmitted or lost. + * The four states correspond to: + * TX_IN_GAP_PERIOD => successfully transmitted packets within a gap period +- * LOST_IN_BURST_PERIOD => isolated losses within a gap period +- * LOST_IN_GAP_PERIOD => lost packets within a burst period +- * TX_IN_GAP_PERIOD => successfully transmitted packets within a burst period ++ * LOST_IN_GAP_PERIOD => isolated losses within a gap period ++ * LOST_IN_BURST_PERIOD => lost packets within a burst period ++ * TX_IN_BURST_PERIOD => successfully transmitted packets within a burst period + */ + switch (clg->state) { + case TX_IN_GAP_PERIOD: + if (rnd < clg->a4) { +- clg->state = LOST_IN_BURST_PERIOD; ++ clg->state = LOST_IN_GAP_PERIOD; + return true; + } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { +- clg->state = LOST_IN_GAP_PERIOD; ++ clg->state = LOST_IN_BURST_PERIOD; + return true; + } else if (clg->a1 + clg->a4 < rnd) { + clg->state = TX_IN_GAP_PERIOD; +@@ -229,24 +229,24 @@ static bool loss_4state(struct netem_sched_data *q) + break; + case TX_IN_BURST_PERIOD: + if (rnd < clg->a5) { +- clg->state = LOST_IN_GAP_PERIOD; ++ clg->state = LOST_IN_BURST_PERIOD; + return true; + } else { + clg->state = TX_IN_BURST_PERIOD; + } + + break; +- case LOST_IN_GAP_PERIOD: ++ case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; + else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; + } else if (clg->a2 + clg->a3 < rnd) { +- clg->state = LOST_IN_GAP_PERIOD; ++ clg->state = LOST_IN_BURST_PERIOD; + return true; + } + break; +- case LOST_IN_BURST_PERIOD: ++ case LOST_IN_GAP_PERIOD: + clg->state = TX_IN_GAP_PERIOD; + break; + } +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch b/queue-5.10/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch new file mode 100644 index 0000000000..233375e4ca --- /dev/null +++ b/queue-5.10/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch @@ -0,0 +1,160 @@ +From 458ce7b34256b753510f9372e369f54e7faf3f38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:29:44 +0000 +Subject: net/sched: sch_pie: annotate data-races in pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ] + +pie_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_pie_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142944.4009941-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/pie.h | 2 +- + net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/include/net/pie.h b/include/net/pie.h +index 3fe2361e03b46..f6fd51e2b7daa 100644 +--- a/include/net/pie.h ++++ b/include/net/pie.h +@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) + vars->dq_tstamp = DTIME_INVALID; + vars->accu_prob = 0; + vars->dq_count = DQCOUNT_INVALID; +- vars->avg_dq_rate = 0; ++ WRITE_ONCE(vars->avg_dq_rate, 0); + } + + static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb) +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index 47f5d4adb5a33..7a8b05174ebf7 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -89,7 +89,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + bool enqueue = false; + + if (unlikely(qdisc_qlen(sch) >= sch->limit)) { +- q->stats.overlimit++; ++ WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1); + goto out; + } + +@@ -101,7 +101,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + /* If packet is ecn capable, mark it if drop probability + * is lower than 10%, else drop it. + */ +- q->stats.ecn_mark++; ++ WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1); + enqueue = true; + } + +@@ -111,15 +111,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + if (!q->params.dq_rate_estimator) + pie_set_enqueue_time(skb); + +- q->stats.packets_in++; ++ WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1); + if (qdisc_qlen(sch) > q->stats.maxq) +- q->stats.maxq = qdisc_qlen(sch); ++ WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch)); + + return qdisc_enqueue_tail(skb, sch); + } + + out: +- q->stats.dropped++; ++ WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1); + q->vars.accu_prob = 0; + return qdisc_drop(skb, sch, to_free); + } +@@ -263,11 +263,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, + count = count / dtime; + + if (vars->avg_dq_rate == 0) +- vars->avg_dq_rate = count; ++ WRITE_ONCE(vars->avg_dq_rate, count); + else +- vars->avg_dq_rate = ++ WRITE_ONCE(vars->avg_dq_rate, + (vars->avg_dq_rate - +- (vars->avg_dq_rate >> 3)) + (count >> 3); ++ (vars->avg_dq_rate >> 3)) + (count >> 3)); + + /* If the queue has receded below the threshold, we hold + * on to the last drain rate calculated, else we reset +@@ -377,7 +377,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + if (delta > 0) { + /* prevent overflow */ + if (vars->prob < oldprob) { +- vars->prob = MAX_PROB; ++ WRITE_ONCE(vars->prob, MAX_PROB); + /* Prevent normalization error. If probability is at + * maximum value already, we normalize it here, and + * skip the check to do a non-linear drop in the next +@@ -388,7 +388,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + } else { + /* prevent underflow */ + if (vars->prob > oldprob) +- vars->prob = 0; ++ WRITE_ONCE(vars->prob, 0); + } + + /* Non-linear drop in probability: Reduce drop probability quickly if +@@ -399,7 +399,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + /* Reduce drop probability to 98.4% */ + vars->prob -= vars->prob / 64; + +- vars->qdelay = qdelay; ++ WRITE_ONCE(vars->qdelay, qdelay); + vars->backlog_old = backlog; + + /* We restart the measurement cycle if the following conditions are met +@@ -494,21 +494,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + struct pie_sched_data *q = qdisc_priv(sch); + struct tc_pie_xstats st = { + .prob = q->vars.prob << BITS_PER_BYTE, +- .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / ++ .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) / + NSEC_PER_USEC, +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .maxq = q->stats.maxq, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, ++ .packets_in = READ_ONCE(q->stats.packets_in), ++ .overlimit = READ_ONCE(q->stats.overlimit), ++ .maxq = READ_ONCE(q->stats.maxq), ++ .dropped = READ_ONCE(q->stats.dropped), ++ .ecn_mark = READ_ONCE(q->stats.ecn_mark), + }; + + /* avg_dq_rate is only valid if dq_rate_estimator is enabled */ + st.dq_rate_estimating = q->params.dq_rate_estimator; + + /* unscale and return dq_rate in bytes per sec */ +- if (q->params.dq_rate_estimator) +- st.avg_dq_rate = q->vars.avg_dq_rate * ++ if (st.dq_rate_estimating) ++ st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) * + (PSCHED_TICKS_PER_SEC) >> PIE_SCALE; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch b/queue-5.10/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch new file mode 100644 index 0000000000..7242ec608b --- /dev/null +++ b/queue-5.10/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch @@ -0,0 +1,112 @@ +From 111fd45be15feaf4ead6a3646d66df7ad559b290 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:23:09 +0000 +Subject: net/sched: sch_red: annotate data-races in red_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ] + +red_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_red_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142309.3964322-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_red.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index a2c1db8ac3945..779f8779c762a 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -89,17 +89,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_PROB_MARK: + qdisc_qstats_overlimit(sch); + if (!red_use_ecn(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +@@ -109,17 +112,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_HARD_MARK: + qdisc_qstats_overlimit(sch); + if (red_use_harddrop(q) || !red_use_ecn(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +@@ -133,7 +139,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->qstats.backlog += len; + sch->q.qlen++; + } else if (net_xmit_drop_count(ret)) { +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, ++ q->stats.pdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -461,9 +468,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, + &hw_stats_request); + } +- st.early = q->stats.prob_drop + q->stats.forced_drop; +- st.pdrop = q->stats.pdrop; +- st.marked = q->stats.prob_mark + q->stats.forced_mark; ++ st.early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop); ++ ++ st.pdrop = READ_ONCE(q->stats.pdrop); ++ ++ st.marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark); + + return gnet_stats_copy_app(d, &st, sizeof(st)); + } +-- +2.53.0 + diff --git a/queue-5.10/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch b/queue-5.10/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch new file mode 100644 index 0000000000..cf41d6b84a --- /dev/null +++ b/queue-5.10/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch @@ -0,0 +1,169 @@ +From 5391eafb1224ba3c1291835c0bb5d08f7dad1cb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:16:55 +0000 +Subject: net/sched: sch_sfb: annotate data-races in sfb_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ] + +sfb_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_sfb_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260421141655.3953721-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 22 deletions(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index 9ded56228ea10..1b04e760e47d6 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen < 0xFFFF) +- b[hash].qlen++; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen > 0) +- b[hash].qlen--; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) + + static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_minus(b->p_mark, q->decrement); ++ WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement)); + } + + static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_plus(b->p_mark, q->increment); ++ WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment)); + } + + static void sfb_zero_all_buckets(struct sfb_sched_data *q) +@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da + const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0]; + + for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) { +- if (qlen < b->qlen) +- qlen = b->qlen; +- totalpm += b->p_mark; +- if (prob < b->p_mark) +- prob = b->p_mark; ++ u32 b_qlen = READ_ONCE(b->qlen); ++ u32 b_mark = READ_ONCE(b->p_mark); ++ ++ if (qlen < b_qlen) ++ qlen = b_qlen; ++ totalpm += b_mark; ++ if (prob < b_mark) ++ prob = b_mark; + b++; + } + *prob_r = prob; +@@ -294,7 +297,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(sch->q.qlen >= q->limit)) { + qdisc_qstats_overlimit(sch); +- q->stats.queuedrop++; ++ WRITE_ONCE(q->stats.queuedrop, ++ q->stats.queuedrop + 1); + goto drop; + } + +@@ -347,7 +351,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(minqlen >= q->max)) { + qdisc_qstats_overlimit(sch); +- q->stats.bucketdrop++; ++ WRITE_ONCE(q->stats.bucketdrop, ++ q->stats.bucketdrop + 1); + goto drop; + } + +@@ -373,7 +378,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + if (sfb_rate_limit(skb, q)) { + qdisc_qstats_overlimit(sch); +- q->stats.penaltydrop++; ++ WRITE_ONCE(q->stats.penaltydrop, ++ q->stats.penaltydrop + 1); + goto drop; + } + goto enqueue; +@@ -388,14 +394,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + * In either case, we want to start dropping packets. + */ + if (r < (p_min - SFB_MAX_PROB / 2) * 2) { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } + if (INET_ECN_set_ce(skb)) { +- q->stats.marked++; ++ WRITE_ONCE(q->stats.marked, ++ q->stats.marked + 1); + } else { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } +@@ -408,7 +417,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->q.qlen++; + increment_qlen(&cb, q); + } else if (net_xmit_drop_count(ret)) { +- q->stats.childdrop++; ++ WRITE_ONCE(q->stats.childdrop, ++ q->stats.childdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -597,12 +607,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct sfb_sched_data *q = qdisc_priv(sch); + struct tc_sfb_xstats st = { +- .earlydrop = q->stats.earlydrop, +- .penaltydrop = q->stats.penaltydrop, +- .bucketdrop = q->stats.bucketdrop, +- .queuedrop = q->stats.queuedrop, +- .childdrop = q->stats.childdrop, +- .marked = q->stats.marked, ++ .earlydrop = READ_ONCE(q->stats.earlydrop), ++ .penaltydrop = READ_ONCE(q->stats.penaltydrop), ++ .bucketdrop = READ_ONCE(q->stats.bucketdrop), ++ .queuedrop = READ_ONCE(q->stats.queuedrop), ++ .childdrop = READ_ONCE(q->stats.childdrop), ++ .marked = READ_ONCE(q->stats.marked), + }; + + st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q); +-- +2.53.0 + diff --git a/queue-5.10/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch b/queue-5.10/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch new file mode 100644 index 0000000000..b6471524eb --- /dev/null +++ b/queue-5.10/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch @@ -0,0 +1,47 @@ +From 7dd62296fa36bdb27a1434e581a762f0c93db47a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:27 +0200 +Subject: net/sched: taprio: continue with other TXQs if one dequeue() failed + +From: Vladimir Oltean + +[ Upstream commit 1638bbbe4ececa615b273497d347d59ad71060a2 ] + +This changes the handling of an unlikely condition to not stop dequeuing +if taprio failed to dequeue the peeked skb in taprio_dequeue(). + +I've no idea when this can happen, but the only side effect seems to be +that the atomic_sub_return() call right above will have consumed some +budget. This isn't a big deal, since either that made us remain without +any budget (and therefore, we'd exit on the next peeked skb anyway), or +we could send some packets from other TXQs. + +I'm making this change because in a future patch I'll be refactoring the +dequeue procedure to simplify it, and this corner case will have to go +away. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 62251ae4f4407..8fe4dea86ad98 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -618,7 +618,7 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + + skb = child->ops->dequeue(child); + if (unlikely(!skb)) +- goto done; ++ continue; + + skb_found: + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-5.10/net-sched-taprio-fix-use-after-free-in-advance_sched.patch b/queue-5.10/net-sched-taprio-fix-use-after-free-in-advance_sched.patch new file mode 100644 index 0000000000..06620b0f96 --- /dev/null +++ b/queue-5.10/net-sched-taprio-fix-use-after-free-in-advance_sched.patch @@ -0,0 +1,60 @@ +From b98d2233738c1bdaab32daa72fbda2be1c497d84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 18:57:57 -0700 +Subject: net/sched: taprio: fix use-after-free in advance_sched() on schedule + switch + +From: Vinicius Costa Gomes + +[ Upstream commit 105425b1969c5affe532713cfac1c0b320d7ac2b ] + +In advance_sched(), when should_change_schedules() returns true, +switch_schedules() is called to promote the admin schedule to oper. +switch_schedules() queues the old oper schedule for RCU freeing via +call_rcu(), but 'next' still points into an entry of the old oper +schedule. The subsequent 'next->end_time = end_time' and +rcu_assign_pointer(q->current_entry, next) are use-after-free. + +Fix this by selecting 'next' from the new oper schedule immediately +after switch_schedules(), and using its pre-calculated end_time. +setup_first_end_time() sets the first entry's end_time to +base_time + interval when the schedule is installed, so the value +is already correct. + +The deleted 'end_time = sched_base_time(admin)' assignment was also +harmful independently: it would overwrite the new first entry's +pre-calculated end_time with just base_time. + +Fixes: a3d43c0d56f1 ("taprio: Add support adding an admin schedule") +Reported-by: Junxi Qian +Signed-off-by: Vinicius Costa Gomes +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 9174cdd0aa74b..85812bad227bc 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -731,11 +731,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + end_time = min_t(ktime_t, end_time, oper->cycle_end_time); + + if (should_change_schedules(admin, oper, end_time)) { +- /* Set things so the next time this runs, the new +- * schedule runs. +- */ +- end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); ++ /* After changing schedules, the next entry is the first one ++ * in the new schedule, with a pre-calculated end_time. ++ */ ++ next = list_first_entry(&oper->entries, struct sched_entry, list); ++ end_time = next->end_time; + } + + next->end_time = end_time; +-- +2.53.0 + diff --git a/queue-5.10/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch b/queue-5.10/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch new file mode 100644 index 0000000000..e3a9fdb36e --- /dev/null +++ b/queue-5.10/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch @@ -0,0 +1,168 @@ +From 42dd9e7f8d612f41b6312c238f59aa38b7786cfb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:28 +0200 +Subject: net/sched: taprio: refactor one skb dequeue from TXQ to separate + function + +From: Vladimir Oltean + +[ Upstream commit 92f966674f6a257eddfa60a85f9b6741d6087ccb ] + +Future changes will refactor the TXQ selection procedure, and a lot of +stuff will become messy, the indentation of the bulk of the dequeue +procedure would increase, etc. + +Break out the bulk of the function into a new one, which knows the TXQ +(child qdisc) we should perform a dequeue from. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 121 +++++++++++++++++++++-------------------- + 1 file changed, 63 insertions(+), 58 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 8fe4dea86ad98..b876b950c62e8 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -543,6 +543,66 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + atomic64_read(&q->picos_per_byte))); + } + ++static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, ++ struct sched_entry *entry, ++ u32 gate_mask) ++{ ++ struct taprio_sched *q = qdisc_priv(sch); ++ struct net_device *dev = qdisc_dev(sch); ++ struct Qdisc *child = q->qdiscs[txq]; ++ struct sk_buff *skb; ++ ktime_t guard; ++ int prio; ++ int len; ++ u8 tc; ++ ++ if (unlikely(!child)) ++ return NULL; ++ ++ if (TXTIME_ASSIST_IS_ENABLED(q->flags)) { ++ skb = child->ops->dequeue(child); ++ if (!skb) ++ return NULL; ++ goto skb_found; ++ } ++ ++ skb = child->ops->peek(child); ++ if (!skb) ++ return NULL; ++ ++ prio = skb->priority; ++ tc = netdev_get_prio_tc_map(dev, prio); ++ ++ if (!(gate_mask & BIT(tc))) ++ return NULL; ++ ++ len = qdisc_pkt_len(skb); ++ guard = ktime_add_ns(taprio_get_time(q), length_to_duration(q, len)); ++ ++ /* In the case that there's no gate entry, there's no ++ * guard band ... ++ */ ++ if (gate_mask != TAPRIO_ALL_GATES_OPEN && ++ ktime_after(guard, entry->close_time)) ++ return NULL; ++ ++ /* ... and no budget. */ ++ if (gate_mask != TAPRIO_ALL_GATES_OPEN && ++ atomic_sub_return(len, &entry->budget) < 0) ++ return NULL; ++ ++ skb = child->ops->dequeue(child); ++ if (unlikely(!skb)) ++ return NULL; ++ ++skb_found: ++ qdisc_bstats_update(sch, skb); ++ qdisc_qstats_backlog_dec(sch, skb); ++ sch->q.qlen--; ++ ++ return skb; ++} ++ + /* Will not be called in the full offload case, since the TX queues are + * attached to the Qdisc created using qdisc_create_dflt() + */ +@@ -568,64 +628,9 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + goto done; + + for (i = 0; i < dev->num_tx_queues; i++) { +- struct Qdisc *child = q->qdiscs[i]; +- ktime_t guard; +- int prio; +- int len; +- u8 tc; +- +- if (unlikely(!child)) +- continue; +- +- if (TXTIME_ASSIST_IS_ENABLED(q->flags)) { +- skb = child->ops->dequeue(child); +- if (!skb) +- continue; +- goto skb_found; +- } +- +- skb = child->ops->peek(child); +- if (!skb) +- continue; +- +- prio = skb->priority; +- tc = netdev_get_prio_tc_map(dev, prio); +- +- if (!(gate_mask & BIT(tc))) { +- skb = NULL; +- continue; +- } +- +- len = qdisc_pkt_len(skb); +- guard = ktime_add_ns(taprio_get_time(q), +- length_to_duration(q, len)); +- +- /* In the case that there's no gate entry, there's no +- * guard band ... +- */ +- if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- ktime_after(guard, entry->close_time)) { +- skb = NULL; +- continue; +- } +- +- /* ... and no budget. */ +- if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- atomic_sub_return(len, &entry->budget) < 0) { +- skb = NULL; +- continue; +- } +- +- skb = child->ops->dequeue(child); +- if (unlikely(!skb)) +- continue; +- +-skb_found: +- qdisc_bstats_update(sch, skb); +- qdisc_qstats_backlog_dec(sch, skb); +- sch->q.qlen--; +- +- goto done; ++ skb = taprio_dequeue_from_txq(sch, i, entry, gate_mask); ++ if (skb) ++ goto done; + } + + done: +-- +2.53.0 + diff --git a/queue-5.10/net-sched-taprio-rename-close_time-to-end_time.patch b/queue-5.10/net-sched-taprio-rename-close_time-to-end_time.patch new file mode 100644 index 0000000000..701e8377a7 --- /dev/null +++ b/queue-5.10/net-sched-taprio-rename-close_time-to-end_time.patch @@ -0,0 +1,205 @@ +From 42fd7abad2bc6c7bcb6f16d8b28c7848089360ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:32 +0200 +Subject: net/sched: taprio: rename close_time to end_time + +From: Vladimir Oltean + +[ Upstream commit e5517551112ff2395611e552443932152f83672d ] + +There is a confusion in terms in taprio which makes what is called +"close_time" to be actually used for 2 things: + +1. determining when an entry "closes" such that transmitted skbs are + never allowed to overrun that time (?!) +2. an aid for determining when to advance and/or restart the schedule + using the hrtimer + +It makes more sense to call this so-called "close_time" "end_time", +because it's not clear at all to me what "closes". Future patches will +hopefully make better use of the term "to close". + +This is an absolutely mechanical change. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 52 +++++++++++++++++++++--------------------- + 1 file changed, 26 insertions(+), 26 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index b876b950c62e8..9174cdd0aa74b 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -36,11 +36,11 @@ static DEFINE_SPINLOCK(taprio_list_lock); + struct sched_entry { + struct list_head list; + +- /* The instant that this entry "closes" and the next one ++ /* The instant that this entry ends and the next one + * should open, the qdisc will make some effort so that no + * packet leaves after this time. + */ +- ktime_t close_time; ++ ktime_t end_time; + ktime_t next_txtime; + atomic_t budget; + int index; +@@ -53,7 +53,7 @@ struct sched_gate_list { + struct rcu_head rcu; + struct list_head entries; + size_t num_entries; +- ktime_t cycle_close_time; ++ ktime_t cycle_end_time; + s64 cycle_time; + s64 cycle_time_extension; + s64 base_time; +@@ -583,7 +583,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, + * guard band ... + */ + if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- ktime_after(guard, entry->close_time)) ++ ktime_after(guard, entry->end_time)) + return NULL; + + /* ... and no budget. */ +@@ -645,7 +645,7 @@ static bool should_restart_cycle(const struct sched_gate_list *oper, + if (list_is_last(&entry->list, &oper->entries)) + return true; + +- if (ktime_compare(entry->close_time, oper->cycle_close_time) == 0) ++ if (ktime_compare(entry->end_time, oper->cycle_end_time) == 0) + return true; + + return false; +@@ -653,7 +653,7 @@ static bool should_restart_cycle(const struct sched_gate_list *oper, + + static bool should_change_schedules(const struct sched_gate_list *admin, + const struct sched_gate_list *oper, +- ktime_t close_time) ++ ktime_t end_time) + { + ktime_t next_base_time, extension_time; + +@@ -662,18 +662,18 @@ static bool should_change_schedules(const struct sched_gate_list *admin, + + next_base_time = sched_base_time(admin); + +- /* This is the simple case, the close_time would fall after ++ /* This is the simple case, the end_time would fall after + * the next schedule base_time. + */ +- if (ktime_compare(next_base_time, close_time) <= 0) ++ if (ktime_compare(next_base_time, end_time) <= 0) + return true; + +- /* This is the cycle_time_extension case, if the close_time ++ /* This is the cycle_time_extension case, if the end_time + * plus the amount that can be extended would fall after the + * next schedule base_time, we can extend the current schedule + * for that amount. + */ +- extension_time = ktime_add_ns(close_time, oper->cycle_time_extension); ++ extension_time = ktime_add_ns(end_time, oper->cycle_time_extension); + + /* FIXME: the IEEE 802.1Q-2018 Specification isn't clear about + * how precisely the extension should be made. So after +@@ -692,7 +692,7 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + struct sched_gate_list *oper, *admin; + struct sched_entry *entry, *next; + struct Qdisc *sch = q->root; +- ktime_t close_time; ++ ktime_t end_time; + + spin_lock(&q->current_entry_lock); + entry = rcu_dereference_protected(q->current_entry, +@@ -711,41 +711,41 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + * entry of all schedules are pre-calculated during the + * schedule initialization. + */ +- if (unlikely(!entry || entry->close_time == oper->base_time)) { ++ if (unlikely(!entry || entry->end_time == oper->base_time)) { + next = list_first_entry(&oper->entries, struct sched_entry, + list); +- close_time = next->close_time; ++ end_time = next->end_time; + goto first_run; + } + + if (should_restart_cycle(oper, entry)) { + next = list_first_entry(&oper->entries, struct sched_entry, + list); +- oper->cycle_close_time = ktime_add_ns(oper->cycle_close_time, +- oper->cycle_time); ++ oper->cycle_end_time = ktime_add_ns(oper->cycle_end_time, ++ oper->cycle_time); + } else { + next = list_next_entry(entry, list); + } + +- close_time = ktime_add_ns(entry->close_time, next->interval); +- close_time = min_t(ktime_t, close_time, oper->cycle_close_time); ++ end_time = ktime_add_ns(entry->end_time, next->interval); ++ end_time = min_t(ktime_t, end_time, oper->cycle_end_time); + +- if (should_change_schedules(admin, oper, close_time)) { ++ if (should_change_schedules(admin, oper, end_time)) { + /* Set things so the next time this runs, the new + * schedule runs. + */ +- close_time = sched_base_time(admin); ++ end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); + } + +- next->close_time = close_time; ++ next->end_time = end_time; + taprio_set_budget(q, next); + + first_run: + rcu_assign_pointer(q->current_entry, next); + spin_unlock(&q->current_entry_lock); + +- hrtimer_set_expires(&q->advance_timer, close_time); ++ hrtimer_set_expires(&q->advance_timer, end_time); + + rcu_read_lock(); + __netif_schedule(sch); +@@ -1007,8 +1007,8 @@ static int taprio_get_start_time(struct Qdisc *sch, + return 0; + } + +-static void setup_first_close_time(struct taprio_sched *q, +- struct sched_gate_list *sched, ktime_t base) ++static void setup_first_end_time(struct taprio_sched *q, ++ struct sched_gate_list *sched, ktime_t base) + { + struct sched_entry *first; + ktime_t cycle; +@@ -1019,9 +1019,9 @@ static void setup_first_close_time(struct taprio_sched *q, + cycle = sched->cycle_time; + + /* FIXME: find a better place to do this */ +- sched->cycle_close_time = ktime_add_ns(base, cycle); ++ sched->cycle_end_time = ktime_add_ns(base, cycle); + +- first->close_time = ktime_add_ns(base, first->interval); ++ first->end_time = ktime_add_ns(base, first->interval); + taprio_set_budget(q, first); + rcu_assign_pointer(q->current_entry, NULL); + } +@@ -1564,7 +1564,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, + if (admin) + call_rcu(&admin->rcu, taprio_free_sched_cb); + } else { +- setup_first_close_time(q, new_admin, start); ++ setup_first_end_time(q, new_admin, start); + + /* Protects against advance_sched() */ + spin_lock_irqsave(&q->current_entry_lock, flags); +-- +2.53.0 + diff --git a/queue-5.10/net-sched-taprio-replace-safety-precautions-with-com.patch b/queue-5.10/net-sched-taprio-replace-safety-precautions-with-com.patch new file mode 100644 index 0000000000..7c4e9d1ec6 --- /dev/null +++ b/queue-5.10/net-sched-taprio-replace-safety-precautions-with-com.patch @@ -0,0 +1,96 @@ +From 712fbac3afd324a6dd5de4b6735a4d2bf8a577db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Sep 2022 13:50:46 +0300 +Subject: net/sched: taprio: replace safety precautions with comments + +From: Vladimir Oltean + +[ Upstream commit 2c08a4f898d0a8e08f431709a1ae728a6fddaabd ] + +The WARN_ON_ONCE() checks introduced in commit 13511704f8d7 ("net: +taprio offload: enforce qdisc to netdev queue mapping") take a small +toll on performance, but otherwise, the conditions are never expected to +happen. Replace them with comments, such that the information is still +conveyed to developers. + +Signed-off-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index b3b62ee6093d2..62251ae4f4407 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -434,6 +434,9 @@ static int taprio_enqueue_one(struct sk_buff *skb, struct Qdisc *sch, + return qdisc_enqueue(skb, child, to_free); + } + ++/* Will not be called in the full offload case, since the TX queues are ++ * attached to the Qdisc created using qdisc_create_dflt() ++ */ + static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct sk_buff **to_free) + { +@@ -441,11 +444,6 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct Qdisc *child; + int queue; + +- if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { +- WARN_ONCE(1, "Trying to enqueue skb into the root of a taprio qdisc configured with full offload\n"); +- return qdisc_drop(skb, sch, to_free); +- } +- + queue = skb_get_queue_mapping(skb); + + child = q->qdiscs[queue]; +@@ -491,6 +489,9 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return taprio_enqueue_one(skb, sch, child, to_free); + } + ++/* Will not be called in the full offload case, since the TX queues are ++ * attached to the Qdisc created using qdisc_create_dflt() ++ */ + static struct sk_buff *taprio_peek(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); +@@ -500,11 +501,6 @@ static struct sk_buff *taprio_peek(struct Qdisc *sch) + u32 gate_mask; + int i; + +- if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { +- WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n"); +- return NULL; +- } +- + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN; +@@ -547,6 +543,9 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + atomic64_read(&q->picos_per_byte))); + } + ++/* Will not be called in the full offload case, since the TX queues are ++ * attached to the Qdisc created using qdisc_create_dflt() ++ */ + static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); +@@ -556,11 +555,6 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + u32 gate_mask; + int i; + +- if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { +- WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n"); +- return NULL; +- } +- + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + /* if there's no entry, it means that the schedule didn't +-- +2.53.0 + diff --git a/queue-5.10/net-sched-taprio-stop-going-through-private-ops-for-.patch b/queue-5.10/net-sched-taprio-stop-going-through-private-ops-for-.patch new file mode 100644 index 0000000000..b759edb249 --- /dev/null +++ b/queue-5.10/net-sched-taprio-stop-going-through-private-ops-for-.patch @@ -0,0 +1,161 @@ +From f8ab9d0a2392f2cf3c2118643ee2d7d0ae211c7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Sep 2022 13:50:44 +0300 +Subject: net/sched: taprio: stop going through private ops for dequeue and + peek + +From: Vladimir Oltean + +[ Upstream commit 25becba6290bc34e369a0e1a76db9ca88bad87aa ] + +Since commit 13511704f8d7 ("net: taprio offload: enforce qdisc to netdev +queue mapping"), taprio_dequeue_soft() and taprio_peek_soft() are de +facto the only implementations for Qdisc_ops :: dequeue and Qdisc_ops :: +peek that taprio provides. + +This is because in full offload mode, __dev_queue_xmit() will select a +txq->qdisc which is never root taprio qdisc. So if nothing is enqueued +in the root qdisc, it will never be run and nothing will get dequeued +from it. + +Therefore, we can remove the private indirection from taprio, and always +point Qdisc_ops :: dequeue to taprio_dequeue_soft (now simply named +taprio_dequeue) and Qdisc_ops :: peek to taprio_peek_soft (now simply +named taprio_peek). + +Signed-off-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 58 +++++++++--------------------------------- + 1 file changed, 12 insertions(+), 46 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index a92dab2fa6ff4..b3b62ee6093d2 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -77,8 +77,6 @@ struct taprio_sched { + struct sched_gate_list __rcu *admin_sched; + struct hrtimer advance_timer; + struct list_head taprio_list; +- struct sk_buff *(*dequeue)(struct Qdisc *sch); +- struct sk_buff *(*peek)(struct Qdisc *sch); + u32 txtime_delay; + }; + +@@ -493,7 +491,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return taprio_enqueue_one(skb, sch, child, to_free); + } + +-static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) ++static struct sk_buff *taprio_peek(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); +@@ -502,6 +500,11 @@ static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) + u32 gate_mask; + int i; + ++ if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { ++ WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n"); ++ return NULL; ++ } ++ + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN; +@@ -537,20 +540,6 @@ static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) + return NULL; + } + +-static struct sk_buff *taprio_peek_offload(struct Qdisc *sch) +-{ +- WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n"); +- +- return NULL; +-} +- +-static struct sk_buff *taprio_peek(struct Qdisc *sch) +-{ +- struct taprio_sched *q = qdisc_priv(sch); +- +- return q->peek(sch); +-} +- + static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + { + atomic_set(&entry->budget, +@@ -558,7 +547,7 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + atomic64_read(&q->picos_per_byte))); + } + +-static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) ++static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); +@@ -567,6 +556,11 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) + u32 gate_mask; + int i; + ++ if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { ++ WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n"); ++ return NULL; ++ } ++ + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + /* if there's no entry, it means that the schedule didn't +@@ -646,20 +640,6 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) + return skb; + } + +-static struct sk_buff *taprio_dequeue_offload(struct Qdisc *sch) +-{ +- WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n"); +- +- return NULL; +-} +- +-static struct sk_buff *taprio_dequeue(struct Qdisc *sch) +-{ +- struct taprio_sched *q = qdisc_priv(sch); +- +- return q->dequeue(sch); +-} +- + static bool should_restart_cycle(const struct sched_gate_list *oper, + const struct sched_entry *entry) + { +@@ -1563,17 +1543,6 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, + q->advance_timer.function = advance_sched; + } + +- if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { +- q->dequeue = taprio_dequeue_offload; +- q->peek = taprio_peek_offload; +- } else { +- /* Be sure to always keep the function pointers +- * in a consistent state. +- */ +- q->dequeue = taprio_dequeue_soft; +- q->peek = taprio_peek_soft; +- } +- + err = taprio_get_start_time(sch, new_admin, &start); + if (err < 0) { + NL_SET_ERR_MSG(extack, "Internal error: failed get start time"); +@@ -1689,9 +1658,6 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt, + hrtimer_init(&q->advance_timer, CLOCK_TAI, HRTIMER_MODE_ABS); + q->advance_timer.function = advance_sched; + +- q->dequeue = taprio_dequeue_soft; +- q->peek = taprio_peek_soft; +- + q->root = sch; + + /* We only support static clockids. Use an invalid value as default +-- +2.53.0 + diff --git a/queue-5.10/net-taprio-offload-enforce-qdisc-to-netdev-queue-map.patch b/queue-5.10/net-taprio-offload-enforce-qdisc-to-netdev-queue-map.patch new file mode 100644 index 0000000000..f873c9476a --- /dev/null +++ b/queue-5.10/net-taprio-offload-enforce-qdisc-to-netdev-queue-map.patch @@ -0,0 +1,170 @@ +From da57916c2c86d3509552c104f5725026b73c78b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 May 2021 19:18:29 +0200 +Subject: net: taprio offload: enforce qdisc to netdev queue mapping + +From: Yannick Vignon + +[ Upstream commit 13511704f8d7591faf19fdb84f0902dff0535ccb ] + +Even though the taprio qdisc is designed for multiqueue devices, all the +queues still point to the same top-level taprio qdisc. This works and is +probably required for software taprio, but at least with offload taprio, +it has an undesirable side effect: because the whole qdisc is run when a +packet has to be sent, it allows packets in a best-effort class to be +processed in the context of a task sending higher priority traffic. If +there are packets left in the qdisc after that first run, the NET_TX +softirq is raised and gets executed immediately in the same process +context. As with any other softirq, it runs up to 10 times and for up to +2ms, during which the calling process is waiting for the sendmsg call (or +similar) to return. In my use case, that calling process is a real-time +task scheduled to send a packet every 2ms, so the long sendmsg calls are +leading to missed timeslots. + +By attaching each netdev queue to its own qdisc, as it is done with +the "classic" mq qdisc, each traffic class can be processed independently +without touching the other classes. A high-priority process can then send +packets without getting stuck in the sendmsg call anymore. + +Signed-off-by: Yannick Vignon +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 85 ++++++++++++++++++++++-------------------- + 1 file changed, 45 insertions(+), 40 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 66348b1083ed5..a92dab2fa6ff4 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -443,6 +443,11 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct Qdisc *child; + int queue; + ++ if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { ++ WARN_ONCE(1, "Trying to enqueue skb into the root of a taprio qdisc configured with full offload\n"); ++ return qdisc_drop(skb, sch, to_free); ++ } ++ + queue = skb_get_queue_mapping(skb); + + child = q->qdiscs[queue]; +@@ -534,23 +539,7 @@ static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) + + static struct sk_buff *taprio_peek_offload(struct Qdisc *sch) + { +- struct taprio_sched *q = qdisc_priv(sch); +- struct net_device *dev = qdisc_dev(sch); +- struct sk_buff *skb; +- int i; +- +- for (i = 0; i < dev->num_tx_queues; i++) { +- struct Qdisc *child = q->qdiscs[i]; +- +- if (unlikely(!child)) +- continue; +- +- skb = child->ops->peek(child); +- if (!skb) +- continue; +- +- return skb; +- } ++ WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n"); + + return NULL; + } +@@ -659,27 +648,7 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) + + static struct sk_buff *taprio_dequeue_offload(struct Qdisc *sch) + { +- struct taprio_sched *q = qdisc_priv(sch); +- struct net_device *dev = qdisc_dev(sch); +- struct sk_buff *skb; +- int i; +- +- for (i = 0; i < dev->num_tx_queues; i++) { +- struct Qdisc *child = q->qdiscs[i]; +- +- if (unlikely(!child)) +- continue; +- +- skb = child->ops->dequeue(child); +- if (unlikely(!skb)) +- continue; +- +- qdisc_bstats_update(sch, skb); +- qdisc_qstats_backlog_dec(sch, skb); +- sch->q.qlen--; +- +- return skb; +- } ++ WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n"); + + return NULL; + } +@@ -1774,6 +1743,37 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt, + return taprio_change(sch, opt, extack); + } + ++static void taprio_attach(struct Qdisc *sch) ++{ ++ struct taprio_sched *q = qdisc_priv(sch); ++ struct net_device *dev = qdisc_dev(sch); ++ unsigned int ntx; ++ ++ /* Attach underlying qdisc */ ++ for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { ++ struct Qdisc *qdisc = q->qdiscs[ntx]; ++ struct Qdisc *old; ++ ++ if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { ++ qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; ++ old = dev_graft_qdisc(qdisc->dev_queue, qdisc); ++ if (ntx < dev->real_num_tx_queues) ++ qdisc_hash_add(qdisc, false); ++ } else { ++ old = dev_graft_qdisc(qdisc->dev_queue, sch); ++ qdisc_refcount_inc(sch); ++ } ++ if (old) ++ qdisc_put(old); ++ } ++ ++ /* access to the child qdiscs is not needed in offload mode */ ++ if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { ++ kfree(q->qdiscs); ++ q->qdiscs = NULL; ++ } ++} ++ + static struct netdev_queue *taprio_queue_get(struct Qdisc *sch, + unsigned long cl) + { +@@ -1800,8 +1800,12 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + if (dev->flags & IFF_UP) + dev_deactivate(dev); + +- *old = q->qdiscs[cl - 1]; +- q->qdiscs[cl - 1] = new; ++ if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { ++ *old = dev_graft_qdisc(dev_queue, new); ++ } else { ++ *old = q->qdiscs[cl - 1]; ++ q->qdiscs[cl - 1] = new; ++ } + + if (new) + new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; +@@ -2035,6 +2039,7 @@ static struct Qdisc_ops taprio_qdisc_ops __read_mostly = { + .change = taprio_change, + .destroy = taprio_destroy, + .reset = taprio_reset, ++ .attach = taprio_attach, + .peek = taprio_peek, + .dequeue = taprio_dequeue, + .enqueue = taprio_enqueue, +-- +2.53.0 + diff --git a/queue-5.10/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch b/queue-5.10/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch new file mode 100644 index 0000000000..9e4b55da91 --- /dev/null +++ b/queue-5.10/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch @@ -0,0 +1,89 @@ +From 699c2d66ce07f83ec1b517ce4561445259f03e8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 08:49:12 +0800 +Subject: net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit() + +From: Zhan Jun + +[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ] + +syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() +when accessing skb->len for tx statistics after usb_submit_urb() has +been called: + + BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760 + drivers/net/usb/rtl8150.c:712 + Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226 + +The URB completion handler write_bulk_callback() frees the skb via +dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU +in softirq context before usb_submit_urb() returns in the submitter, +so by the time the submitter reads skb->len the skb has already been +queued to the per-CPU completion_queue and freed by net_tx_action(): + + CPU A (xmit) CPU B (USB completion softirq) + ------------ ------------------------------ + dev->tx_skb = skb; + usb_submit_urb() --+ + |-------> write_bulk_callback() + | dev_kfree_skb_irq(dev->tx_skb) + | net_tx_action() + | napi_skb_cache_put() <-- free + netdev->stats.tx_bytes | + += skb->len; <-- UAF read + +Fix it by caching skb->len before submitting the URB and using the +cached value when updating the tx_bytes counter. + +The pre-existing tx_bytes semantics are preserved: the counter tracks +the original frame length (skb->len), not the ETH_ZLEN/USB-alignment +padded "count" value that is handed to the device. Changing that +would be a user-visible accounting change and is out of scope for +this UAF fix. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+3f46c095ac0ca048cb71@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e69ee7.050a0220.24bfd3.002b.GAE@google.com/ +Closes: https://syzkaller.appspot.com/bug?extid=3f46c095ac0ca048cb71 +Reviewed-by: Andrew Lunn +Signed-off-by: Zhan Jun +Link: https://patch.msgid.link/809895186B866C10+20260423004913.136655-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 185b8c8b19ba3..51bd522fada53 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + rtl8150_t *dev = netdev_priv(netdev); ++ unsigned int skb_len; + int count, res; + + /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ +@@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + ++ skb_len = skb->len; ++ + netif_stop_queue(netdev); + dev->tx_skb = skb; + usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), +@@ -711,7 +714,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + } + } else { + netdev->stats.tx_packets++; +- netdev->stats.tx_bytes += skb->len; ++ netdev->stats.tx_bytes += skb_len; + netif_trans_update(netdev); + } + +-- +2.53.0 + diff --git a/queue-5.10/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch b/queue-5.10/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch new file mode 100644 index 0000000000..559ee50565 --- /dev/null +++ b/queue-5.10/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch @@ -0,0 +1,61 @@ +From 1a8c751491fe344229ebf13c79a3f7d8f3b01850 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 09:55:17 +0800 +Subject: net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit + +From: Morduan Zang + +[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ] + +When rtl8150_start_xmit() fails to submit the tx URB, the URB is never +handed to the USB core and write_bulk_callback() will not run. The +driver returns NETDEV_TX_OK, which tells the networking stack that the +skb has been consumed, but nothing actually frees the skb on this +error path: + + dev->tx_skb = skb; + ... + if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { + ... + /* no kfree_skb here */ + } + return NETDEV_TX_OK; + +This leaks the skb on every submit failure and also leaves dev->tx_skb +pointing at memory that the driver itself may later free, which is +fragile. + +Free the skb with dev_kfree_skb_any() in the error path and clear +dev->tx_skb so no stale pointer is left behind. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reviewed-by: Andrew Lunn +Signed-off-by: Morduan Zang +Link: https://patch.msgid.link/E7D3E1C013C5A859+20260424015517.9574-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 51bd522fada53..a992253000c85 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -712,6 +712,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } ++ /* ++ * The URB was not submitted, so write_bulk_callback() will ++ * never run to free dev->tx_skb. Drop the skb here and ++ * clear tx_skb to avoid leaving a stale pointer. ++ */ ++ dev->tx_skb = NULL; ++ dev_kfree_skb_any(skb); + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb_len; +-- +2.53.0 + diff --git a/queue-5.10/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch b/queue-5.10/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch new file mode 100644 index 0000000000..902d7f7b1f --- /dev/null +++ b/queue-5.10/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch @@ -0,0 +1,92 @@ +From b1d12357d6d177e9ffbb76c6cc988e83f7445707 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:33:49 +0000 +Subject: net_sched: sch_hhf: annotate data-races in hhf_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ] + +hhf_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421143349.4052215-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_hhf.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index 433bddcbc0c72..73cabb4451ce7 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash, + return NULL; + list_del(&flow->flowchain); + kfree(flow); +- q->hh_flows_current_cnt--; ++ WRITE_ONCE(q->hh_flows_current_cnt, ++ q->hh_flows_current_cnt - 1); + } else if (flow->hash_id == hash) { + return flow; + } +@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + } + + if (q->hh_flows_current_cnt >= q->hh_flows_limit) { +- q->hh_flows_overlimit++; ++ WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); + return NULL; + } + /* Create new entry. */ +@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + if (!flow) + return NULL; + +- q->hh_flows_current_cnt++; ++ WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); + INIT_LIST_HEAD(&flow->flowchain); + list_add_tail(&flow->flowchain, head); + +@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) + return WDRR_BUCKET_FOR_NON_HH; + flow->hash_id = hash; + flow->hit_timestamp = now; +- q->hh_flows_total_cnt++; ++ WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); + + /* By returning without updating counters in q->hhf_arrays, + * we implicitly implement "shielding" (see Optimization O1). +@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + + prev_backlog = sch->qstats.backlog; +- q->drop_overlimit++; ++ WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); + /* Return Congestion Notification only if we dropped a packet from this + * bucket. + */ +@@ -681,10 +682,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct hhf_sched_data *q = qdisc_priv(sch); + struct tc_hhf_xstats st = { +- .drop_overlimit = q->drop_overlimit, +- .hh_overlimit = q->hh_flows_overlimit, +- .hh_tot_count = q->hh_flows_total_cnt, +- .hh_cur_count = q->hh_flows_current_cnt, ++ .drop_overlimit = READ_ONCE(q->drop_overlimit), ++ .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), ++ .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), ++ .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-5.10/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch b/queue-5.10/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch new file mode 100644 index 0000000000..64980f590a --- /dev/null +++ b/queue-5.10/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch @@ -0,0 +1,43 @@ +From f73c0610732fb1f79009826a210d79fae94a2a2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 23:14:34 +0300 +Subject: netdevsim: zero initialize struct iphdr in dummy sk_buff + +From: Nikola Z. Ivanov + +[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ] + +Syzbot reports a KMSAN uninit-value originating from +nsim_dev_trap_skb_build, with the allocation also +being performed in the same function. + +Fix this by calling skb_put_zero instead of skb_put to +guarantee zero initialization of the whole IP header. + +Closes: https://syzkaller.appspot.com/bug?extid=23d7fcd204e3837866ff +Fixes: da58f90f11f5 ("netdevsim: Add devlink-trap support") +Signed-off-by: Nikola Z. Ivanov +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426201434.742030-1-zlatistiv@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netdevsim/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c +index bcf354719745c..c8834ea84732b 100644 +--- a/drivers/net/netdevsim/dev.c ++++ b/drivers/net/netdevsim/dev.c +@@ -514,7 +514,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) + skb->protocol = htons(ETH_P_IP); + + skb_set_network_header(skb, skb->len); +- iph = skb_put(skb, sizeof(struct iphdr)); ++ iph = skb_put_zero(skb, sizeof(struct iphdr)); + iph->protocol = IPPROTO_UDP; + iph->saddr = in_aton("192.0.2.1"); + iph->daddr = in_aton("198.51.100.1"); +-- +2.53.0 + diff --git a/queue-5.10/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch b/queue-5.10/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch new file mode 100644 index 0000000000..4a42884732 --- /dev/null +++ b/queue-5.10/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch @@ -0,0 +1,126 @@ +From fab2656972fdde4a935c2d9e10e48f098ca33529 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:15:32 +0200 +Subject: netfilter: arp_tables: fix IEEE1394 ARP payload parsing + +From: Pablo Neira Ayuso + +[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ] + +Weiming Shi says: + +"arp_packet_match() unconditionally parses the ARP payload assuming two +hardware addresses are present (source and target). However, +IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address +field, and arp_hdr_len() already accounts for this by returning a +shorter length for ARPHRD_IEEE1394 devices. + +As a result, on IEEE1394 interfaces arp_packet_match() advances past a +nonexistent target hardware address and reads the wrong bytes for both +the target device address comparison and the target IP address. This +causes arptables rules to match against garbage data, leading to +incorrect filtering decisions: packets that should be accepted may be +dropped and vice versa. + +The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already +handles this correctly by skipping the target hardware address for +ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()." + +Mangle the original patch to always return 0 (no match) in case user +matches on the target hardware address which is never present in +IEEE1394. + +Note that this returns 0 (no match) for either normal and inverse match +because matching in the target hardware address in ARPHRD_IEEE1394 has +never been supported by arptables. This is intentional, matching on the +target hardware address should never evaluate true for ARPHRD_IEEE1394. + +Moreover, adjust arpt_mangle to drop the packet too as AI suggests: + +In arpt_mangle, the logic assumes a standard ARP layout. Because +IEEE1394 (FireWire) omits the target hardware address, the linear +pointer arithmetic miscalculates the offset for the target IP address. +This causes mangling operations to write to the wrong location, leading +to packet corruption. To ensure safety, this patch drops packets +(NF_DROP) when mangling is requested for these fields on IEEE1394 +devices, as the current implementation cannot correctly map the FireWire +ARP payload. + +This omits both mangling target hardware and IP address. Even if IP +address mangling should be possible in IEEE1394, this would require +to adjust arpt_mangle offset calculation, which has never been +supported. + +Based on patch from Weiming Shi . + +Fixes: 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.") +Reported-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- + net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 5823e89b8a734..d5f3b6260da0c 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, + arpptr += dev->addr_len; + memcpy(&src_ipaddr, arpptr, sizeof(u32)); + arpptr += sizeof(u32); +- tgt_devaddr = arpptr; +- arpptr += dev->addr_len; ++ ++ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { ++ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, ++ sizeof(arpinfo->tgt_devaddr.mask)))) ++ return 0; ++ ++ tgt_devaddr = NULL; ++ } else { ++ tgt_devaddr = arpptr; ++ arpptr += dev->addr_len; ++ } + memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); + + if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, + arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, +- dev->addr_len)) || ++ dev->addr_len))) ++ return 0; ++ ++ if (tgt_devaddr && + NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, + arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, + dev->addr_len))) +diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c +index a4e07e5e9c118..f65dd339208e8 100644 +--- a/net/ipv4/netfilter/arpt_mangle.c ++++ b/net/ipv4/netfilter/arpt_mangle.c +@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += pln; + if (mangle->flags & ARPT_MANGLE_TDEV) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_DEV_ADDR_LEN_MAX < hln || + (arpptr + hln > skb_tail_pointer(skb))) + return NF_DROP; +@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += hln; + if (mangle->flags & ARPT_MANGLE_TIP) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_MANGLE_ADDR_LEN_MAX < pln || + (arpptr + pln > skb_tail_pointer(skb))) + return NF_DROP; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-conntrack-remove-sprintf-usage.patch b/queue-5.10/netfilter-conntrack-remove-sprintf-usage.patch new file mode 100644 index 0000000000..71a49b61ff --- /dev/null +++ b/queue-5.10/netfilter-conntrack-remove-sprintf-usage.patch @@ -0,0 +1,182 @@ +From f15610c30abcc08b1c4158d6587b07ce521ff853 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 19:13:46 +0200 +Subject: netfilter: conntrack: remove sprintf usage + +From: Florian Westphal + +[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ] + +Replace it with scnprintf, the buffer sizes are expected to be large enough +to hold the result, no need for snprintf+overflow check. + +Increase buffer size in mangle_content_len() while at it. + +BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 +Write of size 1 at addr [..] + vsnprintf+0xea5/0x1270 + sprintf+0xb1/0xe0 + mangle_content_len+0x1ac/0x280 + nf_nat_sdp_session+0x1cc/0x240 + process_sdp+0x8f8/0xb80 + process_invite_request+0x108/0x2b0 + process_sip_msg+0x5da/0xf50 + sip_help_tcp+0x45e/0x780 + nf_confirm+0x34d/0x990 + [..] + +Fixes: 9fafcd7b2032 ("[NETFILTER]: nf_conntrack/nf_nat: add SIP helper port") +Reported-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_nat_amanda.c | 2 +- + net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c +index 3bc7e0854efe4..41c30065dae12 100644 +--- a/net/netfilter/nf_nat_amanda.c ++++ b/net/netfilter/nf_nat_amanda.c +@@ -62,7 +62,7 @@ static unsigned int help(struct sk_buff *skb, + return NF_DROP; + } + +- sprintf(buffer, "%u", port); ++ snprintf(buffer, sizeof(buffer), "%u", port); + if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, + protoff, matchoff, matchlen, + buffer, strlen(buffer))) { +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index f0a735e868518..15d4267cf49ff 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, + } + + static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, bool delim) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4", &addr->ip); ++ return scnprintf(buffer, size, "%pI4", &addr->ip); + else { + if (delim) +- return sprintf(buffer, "[%pI6c]", &addr->ip6); ++ return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); + else +- return sprintf(buffer, "%pI6c", &addr->ip6); ++ return scnprintf(buffer, size, "%pI6c", &addr->ip6); + } + } + + static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, u16 port) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4:%u", &addr->ip, port); ++ return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port); + else +- return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); ++ return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); + } + + static int map_addr(struct sk_buff *skb, unsigned int protoff, +@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, + if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) + return 1; + +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, true) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.dst.u3, + true); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, false) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.src.u3, + false); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +- buflen = sprintf(buffer, "%u", ntohs(p)); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle rport"); +@@ -430,7 +432,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, + + if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), ++ &newaddr, port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle packet"); +@@ -450,8 +453,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++ char buffer[sizeof("4294967295")]; + unsigned int matchoff, matchlen; +- char buffer[sizeof("65536")]; + int buflen, c_len; + + /* Get actual SDP length */ +@@ -466,7 +469,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + return 0; + +- buflen = sprintf(buffer, "%u", c_len); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -503,7 +506,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, + char buffer[INET6_ADDRSTRLEN]; + unsigned int buflen; + +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, + sdpoff, type, term, buffer, buflen)) + return 0; +@@ -521,7 +524,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + +- buflen = sprintf(buffer, "%u", port); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) + return 0; +@@ -541,7 +544,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, + SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) + return 0; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch b/queue-5.10/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch new file mode 100644 index 0000000000..7898a8591e --- /dev/null +++ b/queue-5.10/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch @@ -0,0 +1,352 @@ +From c1e0e4059945b4f5fd7a20bb3542a9b5b69ba4a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 02:19:11 +0200 +Subject: netfilter: nf_conntrack_sip: don't use simple_strtoul +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Florian Westphal + +[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ] + +Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), +and ct_sip_parse_request() with a new sip_parse_port() helper that +validates each digit against the buffer limit, eliminating the use of +simple_strtoul() which assumes NUL-terminated strings. + +The previous code dereferenced pointers without bounds checks after +sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated +skb data. A port that reaches the buffer limit without a trailing +character is also rejected as malformed. + +Also get rid of all simple_strtoul() usage in conntrack, prefer a +stricter version instead. There are intentional changes: + +- Bail out if number is > UINT_MAX and indicate a failure, same for + too long sequences. + While we do accept 05535 as port 5535, we will not accept e.g. + 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, + we should restrict this to not waste cycles when presented with + malformed packets with 64k '0' characters. + +- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch + 'expire=' and 'rports='; both are expected to use base-10. + +- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k + range. + +- epaddr_len now returns 0 if the port is invalid, as it already does + for invalid ip addresses. This is intentional. nf_conntrack_sip + performs lots of guesswork to find the right parts of the message + to parse. Being stricter could break existing setups. + Connection tracking helpers are designed to allow traffic to + pass, not to block it. + +Based on an earlier patch from Jenny Guanni Qu . + +Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper") +Reported-by: Klaudia Kloc +Reported-by: Dawid Moczadło +Reported-by: Jenny Guanni Qu . +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- + net/netfilter/nf_nat_sip.c | 1 + + 2 files changed, 119 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index dcb0a5e592775..4326d5ea0400d 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, + return 1; + } + ++/* Parse optional port number after IP address. ++ * Returns false on malformed input, true otherwise. ++ * If port is non-NULL, stores parsed port in network byte order. ++ * If no port is present, sets *port to default SIP port. ++ */ ++static bool sip_parse_port(const char *dptr, const char **endp, ++ const char *limit, __be16 *port) ++{ ++ unsigned int p = 0; ++ int len = 0; ++ ++ if (dptr >= limit) ++ return false; ++ ++ if (*dptr != ':') { ++ if (port) ++ *port = htons(SIP_PORT); ++ if (endp) ++ *endp = dptr; ++ return true; ++ } ++ ++ dptr++; /* skip ':' */ ++ ++ while (dptr < limit && isdigit(*dptr)) { ++ p = p * 10 + (*dptr - '0'); ++ dptr++; ++ len++; ++ if (len > 5) /* max "65535" */ ++ return false; ++ } ++ ++ if (len == 0) ++ return false; ++ ++ /* reached limit while parsing port */ ++ if (dptr >= limit) ++ return false; ++ ++ if (p < 1024 || p > 65535) ++ return false; ++ ++ if (port) ++ *port = htons(p); ++ ++ if (endp) ++ *endp = dptr; ++ ++ return true; ++} ++ + /* skip ip address. returns its length. */ + static int epaddr_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, + return 0; + } + +- /* Port number */ +- if (*dptr == ':') { +- dptr++; +- dptr += digits_len(ct, dptr, limit, shift); +- } ++ if (!sip_parse_port(dptr, &dptr, limit, NULL)) ++ return 0; + return dptr - aux; + } + +@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, + return epaddr_len(ct, dptr, limit, shift); + } + ++/* simple_strtoul stops after first non-number character. ++ * But as we're not dealing with c-strings, we can't rely on ++ * hitting \r,\n,\0 etc. before moving past end of buffer. ++ * ++ * This is a variant of simple_strtoul, but doesn't require ++ * a c-string. ++ * ++ * If value exceeds UINT_MAX, 0 is returned. ++ */ ++static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) ++{ ++ const unsigned int max = sizeof("4294967295"); ++ unsigned int olen = len; ++ const char *s = cp; ++ u64 result = 0; ++ ++ if (len > max) ++ len = max; ++ ++ while (olen > 0 && isdigit(*s)) { ++ unsigned int value; ++ ++ if (len == 0) ++ goto err; ++ ++ value = *s - '0'; ++ result = result * 10 + value; ++ ++ if (result > UINT_MAX) ++ goto err; ++ s++; ++ len--; ++ olen--; ++ } ++ ++ if (endp) ++ *endp = (char *)s; ++ ++ return result; ++err: ++ if (endp) ++ *endp = (char *)cp; ++ return 0; ++} ++ + /* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF +@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, + { + const char *start = dptr, *limit = dptr + datalen, *end; + unsigned int mlen; +- unsigned int p; + int shift = 0; + + /* Skip method and following whitespace */ +@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, + + if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) + return -1; +- if (end < limit && *end == ':') { +- end++; +- p = simple_strtoul(end, (char **)&end, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(end, &end, limit, port)) ++ return -1; + + if (end == dptr) + return 0; +@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + union nf_inet_addr *addr, __be16 *port) + { + const char *c, *limit = dptr + datalen; +- unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, +@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + + if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) + return -1; +- if (*c == ':') { +- c++; +- p = simple_strtoul(c, (char **)&c, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(c, &c, limit, port)) ++ return -1; + + if (dataoff) + *dataoff = c - dptr; +@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + return 0; + + start += strlen(name); +- *val = simple_strtoul(start, &end, 0); ++ *val = sip_strtouint(start, limit - start, (char **)&end); + if (start == end) + return -1; + if (matchoff && matchlen) { +@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { ++ char *end; ++ + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) +@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + mediaoff += t->len; + medialen -= t->len; + +- port = simple_strtoul(*dptr + mediaoff, NULL, 10); +- if (port == 0) ++ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); ++ if (port == 0 || *dptr + mediaoff == end) + continue; + if (port < 1024 || port > 65535) { + nf_ct_helper_log(skb, ct, "wrong port %u", port); +@@ -1254,7 +1335,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, +@@ -1354,7 +1435,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + while (1) { + unsigned int c_expires = expires; +@@ -1414,10 +1495,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen, matchend; + unsigned int code, cseq, i; ++ char *end; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; +- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); ++ code = sip_strtouint(*dptr + strlen("SIP/2.0 "), ++ *datalen - strlen("SIP/2.0 "), NULL); + if (!code) { + nf_ct_helper_log(skb, ct, "cannot get code"); + return NF_DROP; +@@ -1428,8 +1511,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1478,6 +1561,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; ++ char *end; + + handler = &sip_handlers[i]; + if (handler->request == NULL) +@@ -1494,8 +1578,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1571,7 +1655,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + break; + +- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); ++ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); + if (dptr + matchoff == end) + break; + +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index 15d4267cf49ff..390ff2d3c6bce 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, + "rport=", &poff, &plen, + &n) > 0 && ++ n >= 1024 && n <= 65535 && + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch b/queue-5.10/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch new file mode 100644 index 0000000000..e37a26fbf8 --- /dev/null +++ b/queue-5.10/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch @@ -0,0 +1,67 @@ +From 80c30aa896175f3ee33b71adbd3ec7e37abe6e30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:14:01 -0700 +Subject: netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO + +From: Xiang Mei + +[ Upstream commit 2195574dc6d9017d32ac346987e12659f931d932 ] + +nf_osf_match_one() computes ctx->window % f->wss.val in the +OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A +CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a +subsequent matching TCP SYN divides by zero and panics the kernel. + +Reject the bogus fingerprint in nfnl_osf_add_callback() above the +per-option for-loop. f->wss is per-fingerprint, not per-option, so +the check must run regardless of f->opt_num (including 0). Also +reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that +as "should not happen". + +Crash: + Oops: divide error: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) + Call Trace: + + nf_osf_match (net/netfilter/nfnetlink_osf.c:220) + xt_osf_match_packet (net/netfilter/xt_osf.c:32) + ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) + nf_hook_slow (net/netfilter/core.c:622) + ip_local_deliver (net/ipv4/ip_input.c:265) + ip_rcv (include/linux/skbuff.h:1162) + __netif_receive_skb_one_core (net/core/dev.c:6181) + process_backlog (net/core/dev.c:6642) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7945) + handle_softirqs (kernel/softirq.c:622) + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Weiming Shi +Suggested-by: Florian Westphal +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Xiang Mei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index a2d7bfb4c1a69..be9bf079aeddf 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -321,6 +321,10 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl, + if (f->opt_num > ARRAY_SIZE(f->opt)) + return -EINVAL; + ++ if (f->wss.wc >= OSF_WSS_MAX || ++ (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) ++ return -EINVAL; ++ + for (i = 0; i < f->opt_num; i++) { + if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch b/queue-5.10/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch new file mode 100644 index 0000000000..e02edbe67b --- /dev/null +++ b/queue-5.10/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch @@ -0,0 +1,100 @@ +From 2e44ad114b3cb41084ce9c4a3f856fd83352b33a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:56 +0200 +Subject: netfilter: nfnetlink_osf: fix out-of-bounds read on option matching + +From: Fernando Fernandez Mancera + +[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ] + +In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once +and passed by reference to nf_osf_match_one() for each fingerprint +checked. During TCP option parsing, nf_osf_match_one() advances the +shared ctx->optp pointer. + +If a fingerprint perfectly matches, the function returns early without +restoring ctx->optp to its initial state. If the user has configured +NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. +However, because ctx->optp was not restored, the next call to +nf_osf_match_one() starts parsing from the end of the options buffer. +This causes subsequent matches to read garbage data and fail +immediately, making it impossible to log more than one match or logging +incorrect matches. + +Instead of using a shared ctx->optp pointer, pass the context as a +constant pointer and use a local pointer (optp) for TCP option +traversal. This makes nf_osf_match_one() strictly stateless from the +caller's perspective, ensuring every fingerprint check starts at the +correct option offset. + +Fixes: 1a6a0951fc00 ("netfilter: nfnetlink_osf: add missing fmatch check") +Suggested-by: Florian Westphal +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index be9bf079aeddf..22d5d72d8250b 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx { + static bool nf_osf_match_one(const struct sk_buff *skb, + const struct nf_osf_user_finger *f, + int ttl_check, +- struct nf_osf_hdr_ctx *ctx) ++ const struct nf_osf_hdr_ctx *ctx) + { +- const __u8 *optpinit = ctx->optp; ++ const __u8 *optp = ctx->optp; + unsigned int check_WSS = 0; + int fmatch = FMATCH_WRONG; + int foptsize, optnum; +@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { +- if (f->opt[optnum].kind == *ctx->optp) { ++ if (f->opt[optnum].kind == *optp) { + __u32 len = f->opt[optnum].length; +- const __u8 *optend = ctx->optp + len; ++ const __u8 *optend = optp + len; + + fmatch = FMATCH_OK; + +- switch (*ctx->optp) { ++ switch (*optp) { + case OSFOPT_MSS: +- mss = ctx->optp[3]; ++ mss = optp[3]; + mss <<= 8; +- mss |= ctx->optp[2]; ++ mss |= optp[2]; + + mss = ntohs((__force __be16)mss); + break; +@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + break; + } + +- ctx->optp = optend; ++ optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + +@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + } + } + +- if (fmatch != FMATCH_OK) +- ctx->optp = optpinit; +- + return fmatch == FMATCH_OK; + } + +-- +2.53.0 + diff --git a/queue-5.10/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch b/queue-5.10/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch new file mode 100644 index 0000000000..d45939f3f3 --- /dev/null +++ b/queue-5.10/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch @@ -0,0 +1,74 @@ +From 2437bda2f006c6be8b8dd0eba8a90a4b65b2e9a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:57 +0200 +Subject: netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check + +From: Fernando Fernandez Mancera + +[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ] + +The nf_osf_ttl() function accessed skb->dev to perform a local interface +address lookup without verifying that the device pointer was valid. + +Additionally, the implementation utilized an in_dev_for_each_ifa_rcu +loop to match the packet source address against local interface +addresses. It assumed that packets from the same subnet should not see a +decrement on the initial TTL. A packet might appear it is from the same +subnet but it actually isn't especially in modern environments with +containers and virtual switching. + +Remove the device dereference and interface loop. Replace the logic with +a switch statement that evaluates the TTL according to the ttl_check. + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Kito Xu (veritas501) +Closes: https://lore.kernel.org/netfilter-devel/20260414074556.2512750-1-hxzene@gmail.com/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 22d5d72d8250b..eee87713420dc 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); + static inline int nf_osf_ttl(const struct sk_buff *skb, + int ttl_check, unsigned char f_ttl) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + const struct iphdr *ip = ip_hdr(skb); +- const struct in_ifaddr *ifa; +- int ret = 0; + +- if (ttl_check == NF_OSF_TTL_TRUE) ++ switch (ttl_check) { ++ case NF_OSF_TTL_TRUE: + return ip->ttl == f_ttl; +- if (ttl_check == NF_OSF_TTL_NOCHECK) +- return 1; +- else if (ip->ttl <= f_ttl) ++ break; ++ case NF_OSF_TTL_NOCHECK: + return 1; +- +- in_dev_for_each_ifa_rcu(ifa, in_dev) { +- if (inet_ifa_match(ip->saddr, ifa)) { +- ret = (ip->ttl == f_ttl); +- break; +- } ++ case NF_OSF_TTL_LESS: ++ default: ++ return ip->ttl <= f_ttl; + } +- +- return ret; + } + + struct nf_osf_hdr_ctx { +-- +2.53.0 + diff --git a/queue-5.10/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch b/queue-5.10/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch new file mode 100644 index 0000000000..d8931dbd04 --- /dev/null +++ b/queue-5.10/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch @@ -0,0 +1,49 @@ +From bb86692a35ba2395443a4e0c970b7b8a50a7bc15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:30:41 +0200 +Subject: netfilter: nft_fwd_netdev: check ttl/hl before forwarding + +From: Florian Westphal + +[ Upstream commit 1dfd95bdf4d18d263aa8fad06bfb9f4d9c992b18 ] + +Drop packets if their ttl/hl is too small for forwarding. + +Fixes: d32de98ea70f ("netfilter: nft_fwd_netdev: allow to forward packets via neighbour layer") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_fwd_netdev.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c +index 7730409f6f091..09aff403884b5 100644 +--- a/net/netfilter/nft_fwd_netdev.c ++++ b/net/netfilter/nft_fwd_netdev.c +@@ -113,6 +113,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + iph = ip_hdr(skb); ++ if (iph->ttl <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip_decrease_ttl(iph); + neigh_table = NEIGH_ARP_TABLE; + break; +@@ -129,6 +134,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + ip6h = ipv6_hdr(skb); ++ if (ip6h->hop_limit <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip6h->hop_limit--; + neigh_table = NEIGH_ND_TABLE; + break; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-nft_osf-restrict-it-to-ipv4.patch b/queue-5.10/netfilter-nft_osf-restrict-it-to-ipv4.patch new file mode 100644 index 0000000000..70b0c473b5 --- /dev/null +++ b/queue-5.10/netfilter-nft_osf-restrict-it-to-ipv4.patch @@ -0,0 +1,47 @@ +From cc7a3b8c859becc980fcc4f6575fba5fc40d0b4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 13:06:38 +0200 +Subject: netfilter: nft_osf: restrict it to ipv4 + +From: Pablo Neira Ayuso + +[ Upstream commit b336fdbb7103fb1484e1dcb6741151d4b5a41e35 ] + +This expression only supports for ipv4, restrict it. + +Fixes: b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf") +Acked-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_osf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c +index 720dc9fba6d4f..81207c172bbfd 100644 +--- a/net/netfilter/nft_osf.c ++++ b/net/netfilter/nft_osf.c +@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, + struct nf_osf_data data; + struct tcphdr _tcph; + ++ if (nft_pf(pkt) != NFPROTO_IPV4) { ++ regs->verdict.code = NFT_BREAK; ++ return; ++ } ++ + if (pkt->tprot != IPPROTO_TCP) { + regs->verdict.code = NFT_BREAK; + return; +@@ -119,7 +124,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx, + + switch (ctx->family) { + case NFPROTO_IPV4: +- case NFPROTO_IPV6: + case NFPROTO_INET: + hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | +-- +2.53.0 + diff --git a/queue-5.10/netfilter-skip-recording-stale-or-retransmitted-init.patch b/queue-5.10/netfilter-skip-recording-stale-or-retransmitted-init.patch new file mode 100644 index 0000000000..9b2592613f --- /dev/null +++ b/queue-5.10/netfilter-skip-recording-stale-or-retransmitted-init.patch @@ -0,0 +1,63 @@ +From 91c6404d12b4264d66d40f90044b8a3de099a499 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:40 -0400 +Subject: netfilter: skip recording stale or retransmitted INIT + +From: Xin Long + +[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ] + +An INIT whose init_tag matches the peer's vtag does not provide new state +information. It indicates either: + +- a stale INIT (after INIT-ACK has already been seen on the same side), or +- a retransmitted INIT (after INIT has already been recorded on the same + side). + +In both cases, the INIT must not update ct->proto.sctp.init[] state, since +it does not advance the handshake tracking and may otherwise corrupt +INIT/INIT-ACK validation logic. + +Allow INIT processing only when the conntrack entry is newly created +(SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer +vtag. + +Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in +nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it +set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag. + +Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") +Signed-off-by: Xin Long +Reviewed-by: Marcelo Ricardo Leitner +Acked-by: Florian Westphal +Link: https://patch.msgid.link/ee56c3e416452b2a40589a2a85245ac2ad5e9f4b.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index 2a1d00e702d1b..4a376c9a6c73c 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -484,9 +484,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + if (!ih) + goto out_unlock; + +- if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) +- ct->proto.sctp.init[!dir] = 0; +- ct->proto.sctp.init[dir] = 1; ++ /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ ++ if (old_state == SCTP_CONNTRACK_NONE || ++ ct->proto.sctp.vtag[!dir] != ih->init_tag) { ++ if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) ++ ct->proto.sctp.init[!dir] = 0; ++ ct->proto.sctp.init[dir] = 1; ++ } + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); + ct->proto.sctp.vtag[!dir] = ih->init_tag; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch b/queue-5.10/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch new file mode 100644 index 0000000000..c7be2559f2 --- /dev/null +++ b/queue-5.10/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch @@ -0,0 +1,47 @@ +From 3beb8dc08c50d719130118bc3f9a4350d5f09174 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:25:06 +0800 +Subject: netfilter: xt_policy: fix strict mode inbound policy matching + +From: Jiexun Wang + +[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ] + +match_policy_in() walks sec_path entries from the last transform to the +first one, but strict policy matching needs to consume info->pol[] in +the same forward order as the rule layout. + +Derive the strict-match policy position from the number of transforms +already consumed so that multi-element inbound rules are matched +consistently. + +Fixes: c4b885139203 ("[NETFILTER]: x_tables: replace IPv4/IPv6 policy match by address family independant version") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Acked-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c +index cb6e8279010a4..b5fa65558318f 100644 +--- a/net/netfilter/xt_policy.c ++++ b/net/netfilter/xt_policy.c +@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, + return 0; + + for (i = sp->len - 1; i >= 0; i--) { +- pos = strict ? i - sp->len + 1 : 0; ++ pos = strict ? sp->len - i - 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; +-- +2.53.0 + diff --git a/queue-5.10/netfilter-xtables-restrict-several-matches-to-inet-f.patch b/queue-5.10/netfilter-xtables-restrict-several-matches-to-inet-f.patch new file mode 100644 index 0000000000..2f3eb07574 --- /dev/null +++ b/queue-5.10/netfilter-xtables-restrict-several-matches-to-inet-f.patch @@ -0,0 +1,208 @@ +From e7707d5c3f746ca01235cc15344db327445e2a95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 12:21:00 +0200 +Subject: netfilter: xtables: restrict several matches to inet family + +From: Pablo Neira Ayuso + +[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ] + +This is a partial revert of: + + commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") + +to allow ipv4 and ipv6 only. + +- xt_mac +- xt_owner +- xt_physdev + +These extensions are not used by ebtables in userspace. + +Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 +specific. + +Fixes: ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") +Reported-by: "Kito Xu (veritas501)" +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- + net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ + net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- + net/netfilter/xt_realm.c | 2 +- + 4 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index 81649da57ba5d..bd2354760895d 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + return ret; + } + +-static struct xt_match mac_mt_reg __read_mostly = { +- .name = "mac", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .match = mac_mt, +- .matchsize = sizeof(struct xt_mac_info), +- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | +- (1 << NF_INET_FORWARD), +- .me = THIS_MODULE, ++static struct xt_match mac_mt_reg[] __read_mostly = { ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV4, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV6, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init mac_mt_init(void) + { +- return xt_register_match(&mac_mt_reg); ++ return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + static void __exit mac_mt_exit(void) + { +- xt_unregister_match(&mac_mt_reg); ++ xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + module_init(mac_mt_init); +diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c +index 50332888c8d23..7be2fe22b067e 100644 +--- a/net/netfilter/xt_owner.c ++++ b/net/netfilter/xt_owner.c +@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + +-static struct xt_match owner_mt_reg __read_mostly = { +- .name = "owner", +- .revision = 1, +- .family = NFPROTO_UNSPEC, +- .checkentry = owner_check, +- .match = owner_mt, +- .matchsize = sizeof(struct xt_owner_match_info), +- .hooks = (1 << NF_INET_LOCAL_OUT) | +- (1 << NF_INET_POST_ROUTING), +- .me = THIS_MODULE, ++static struct xt_match owner_mt_reg[] __read_mostly = { ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV4, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV6, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ } + }; + + static int __init owner_mt_init(void) + { +- return xt_register_match(&owner_mt_reg); ++ return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + static void __exit owner_mt_exit(void) + { +- xt_unregister_match(&owner_mt_reg); ++ xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + module_init(owner_mt_init); +diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c +index ec6ed6fda96c5..6a596878d611f 100644 +--- a/net/netfilter/xt_physdev.c ++++ b/net/netfilter/xt_physdev.c +@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) + return 0; + } + +-static struct xt_match physdev_mt_reg __read_mostly = { +- .name = "physdev", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .checkentry = physdev_mt_check, +- .match = physdev_mt, +- .matchsize = sizeof(struct xt_physdev_info), +- .me = THIS_MODULE, ++static struct xt_match physdev_mt_reg[] __read_mostly = { ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV4, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV6, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init physdev_mt_init(void) + { +- return xt_register_match(&physdev_mt_reg); ++ return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + static void __exit physdev_mt_exit(void) + { +- xt_unregister_match(&physdev_mt_reg); ++ xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + module_init(physdev_mt_init); +diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c +index 6df485f4403d0..61b2f1e58d150 100644 +--- a/net/netfilter/xt_realm.c ++++ b/net/netfilter/xt_realm.c +@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { + .matchsize = sizeof(struct xt_realm_info), + .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), +- .family = NFPROTO_UNSPEC, ++ .family = NFPROTO_IPV4, + .me = THIS_MODULE + }; + +-- +2.53.0 + diff --git a/queue-5.10/nexthop-emit-a-notification-when-a-nexthop-group-is-.patch b/queue-5.10/nexthop-emit-a-notification-when-a-nexthop-group-is-.patch new file mode 100644 index 0000000000..bf5cb82206 --- /dev/null +++ b/queue-5.10/nexthop-emit-a-notification-when-a-nexthop-group-is-.patch @@ -0,0 +1,100 @@ +From 7c72acab5e19b8696dc0ed9a394ed5322ea912a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:30:32 +0200 +Subject: nexthop: Emit a notification when a nexthop group is modified + +From: Ido Schimmel + +[ Upstream commit f17bc33d7412bcca58825273d9f4abf84a87c4cb ] + +When a single nexthop is replaced, the configuration of all the groups +using the nexthop is effectively modified. In this case, emit a +notification in the nexthop notification chain for each modified group +so that listeners would not need to keep track of which nexthops are +member in which groups. + +The notification can only be emitted after the new configuration (i.e., +'struct nh_info') is pointed at by the old shell (i.e., 'struct +nexthop'). Before that the configuration of the nexthop groups is still +the same as before the replacement. + +Signed-off-by: Ido Schimmel +Reviewed-by: David Ahern +Signed-off-by: Jakub Kicinski +Stable-dep-of: 29c95185ba32 ("nexthop: fix IPv6 route referencing IPv4 nexthop") +Signed-off-by: Sasha Levin +--- + net/ipv4/nexthop.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c +index 75e1c8d3bd835..29f95987b68d5 100644 +--- a/net/ipv4/nexthop.c ++++ b/net/ipv4/nexthop.c +@@ -1014,7 +1014,9 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + struct nexthop *new, + struct netlink_ext_ack *extack) + { ++ u8 old_protocol, old_nh_flags; + struct nh_info *oldi, *newi; ++ struct nh_grp_entry *nhge; + int err; + + if (new->is_group) { +@@ -1044,18 +1046,29 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + newi->nh_parent = old; + oldi->nh_parent = new; + ++ old_protocol = old->protocol; ++ old_nh_flags = old->nh_flags; ++ + old->protocol = new->protocol; + old->nh_flags = new->nh_flags; + + rcu_assign_pointer(old->nh_info, newi); + rcu_assign_pointer(new->nh_info, oldi); + ++ /* Send a replace notification for all the groups using the nexthop. */ ++ list_for_each_entry(nhge, &old->grp_list, nh_list) { ++ struct nexthop *nhp = nhge->nh_parent; ++ ++ err = call_nexthop_notifiers(net, NEXTHOP_EVENT_REPLACE, nhp, ++ extack); ++ if (err) ++ goto err_notify; ++ } ++ + /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially + * update IPv4 indication in all the groups using the nexthop. + */ + if (oldi->family == AF_INET && newi->family == AF_INET6) { +- struct nh_grp_entry *nhge; +- + list_for_each_entry(nhge, &old->grp_list, nh_list) { + struct nexthop *nhp = nhge->nh_parent; + struct nh_group *nhg; +@@ -1066,6 +1079,21 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + } + + return 0; ++ ++err_notify: ++ rcu_assign_pointer(new->nh_info, newi); ++ rcu_assign_pointer(old->nh_info, oldi); ++ old->nh_flags = old_nh_flags; ++ old->protocol = old_protocol; ++ oldi->nh_parent = old; ++ newi->nh_parent = new; ++ list_for_each_entry_continue_reverse(nhge, &old->grp_list, nh_list) { ++ struct nexthop *nhp = nhge->nh_parent; ++ ++ call_nexthop_notifiers(net, NEXTHOP_EVENT_REPLACE, nhp, extack); ++ } ++ call_nexthop_notifiers(net, NEXTHOP_EVENT_REPLACE, old, extack); ++ return err; + } + + static void __nexthop_replace_notify(struct net *net, struct nexthop *nh, +-- +2.53.0 + diff --git a/queue-5.10/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch b/queue-5.10/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch new file mode 100644 index 0000000000..41d803543e --- /dev/null +++ b/queue-5.10/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch @@ -0,0 +1,69 @@ +From 0a563c153045feca788bdc331017a400b70e681e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:19 +0800 +Subject: nexthop: fix IPv6 route referencing IPv4 nexthop + +From: Jiayuan Chen + +[ Upstream commit 29c95185ba32b621fbc3800fb86e7dc3edf5c2be ] + +syzbot reported a panic [1] [2]. + +When an IPv6 nexthop is replaced with an IPv4 nexthop, the has_v4 flag +of all groups containing this nexthop is not updated. This is because +nh_group_v4_update is only called when replacing AF_INET to AF_INET6, +but the reverse direction (AF_INET6 to AF_INET) is missed. + +This allows a stale has_v4=false to bypass fib6_check_nexthop, causing +IPv6 routes to be attached to groups that effectively contain only AF_INET +members. Subsequent route lookups then call nexthop_fib6_nh() which +returns NULL for the AF_INET member, leading to a NULL pointer +dereference. + +Fix by calling nh_group_v4_update whenever the family changes, not just +AF_INET to AF_INET6. + +Reproducer: + # AF_INET6 blackhole + ip -6 nexthop add id 1 blackhole + # group with has_v4=false + ip nexthop add id 100 group 1 + # replace with AF_INET (no -6), has_v4 stays false + ip nexthop replace id 1 blackhole + # pass stale has_v4 check + ip -6 route add 2001:db8::/64 nhid 100 + # panic + ping -6 2001:db8::1 + +[1] https://syzkaller.appspot.com/bug?id=e17283eb2f8dcf3dd9b47fe6f67a95f71faadad0 +[2] https://syzkaller.appspot.com/bug?id=8699b6ae54c9f35837d925686208402949e12ef3 +Fixes: 7bf4796dd099 ("nexthops: add support for replace") +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/nexthop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c +index 29f95987b68d5..74de86e0601d2 100644 +--- a/net/ipv4/nexthop.c ++++ b/net/ipv4/nexthop.c +@@ -1065,10 +1065,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + goto err_notify; + } + +- /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially ++ /* When replacing a nexthop with one of a different family, potentially + * update IPv4 indication in all the groups using the nexthop. + */ +- if (oldi->family == AF_INET && newi->family == AF_INET6) { ++ if (oldi->family != newi->family) { + list_for_each_entry(nhge, &old->grp_list, nh_list) { + struct nexthop *nhp = nhge->nh_parent; + struct nh_group *nhg; +-- +2.53.0 + diff --git a/queue-5.10/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch b/queue-5.10/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch new file mode 100644 index 0000000000..fe43f68692 --- /dev/null +++ b/queue-5.10/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch @@ -0,0 +1,53 @@ +From 1d6a11b4e1d5b6481481458a2abbc956b33d6299 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 12:09:30 +0200 +Subject: NFC: trf7970a: Ignore antenna noise when checking for RF field + +From: Paul Geurts + +[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ] + +The main channel Received Signal Strength Indicator (RSSI) measurement +is used to determine whether an RF field is present or not. RSSI != 0 +is interpreted as an RF Field is present. This does not take RF noise +and measurement inaccuracy into account, and results in false positives +in the field. + +Define a noise level and make sure the RF field is only interpreted as +present when the RSSI is above the noise level. + +Fixes: 851ee3cbf850 ("NFC: trf7970a: Don't turn on RF if there is already an RF field") +Signed-off-by: Paul Geurts +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Mark Greer +Link: https://patch.msgid.link/20260422100930.581237-1-paul.geurts@prodrive-technologies.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/trf7970a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c +index 081ec1105572e..4d99d4dbf817e 100644 +--- a/drivers/nfc/trf7970a.c ++++ b/drivers/nfc/trf7970a.c +@@ -311,6 +311,7 @@ + #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) ++#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 + + #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) + #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +@@ -1253,7 +1254,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) + if (ret) + return ret; + +- if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) ++ if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) + *is_rf_field = true; + else + *is_rf_field = false; +-- +2.53.0 + diff --git a/queue-5.10/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch b/queue-5.10/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch new file mode 100644 index 0000000000..9f76b255e5 --- /dev/null +++ b/queue-5.10/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch @@ -0,0 +1,107 @@ +From 2570f881752cd788d2fc067871a4bde8e71ecf84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 16:05:36 +0000 +Subject: nfp: fix swapped arguments in nfp_encode_basic_qdr() calls + +From: Alexey Kodanev + +[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ] + +There is a mismatch between the passed arguments and the actual +nfp_encode_basic_qdr() function parameter names: + + static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + int mode, bool addr40, int isld1, + int isld0) + { + ... + +But "dest_island" and "cpp_tgt" are swapped at every call-site. +For example: + + return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + mode, addr40, isld1, isld0); + +As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target +type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" +as the destination island ID, which can accidentally match or be outside +the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination). + +Since code already worked for years, also add extra pr_warn() to error +paths in nfp_encode_basic_qdr() to help identify any potential address +verification failures. + +Detected using the static analysis tool - Svace. + +Fixes: 4cb584e0ee7d ("nfp: add CPP access core") +Signed-off-by: Alexey Kodanev +Link: https://patch.msgid.link/20260422160536.61855-1-aleksei.kodanev@bell-sw.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +index 79470f198a62a..9cf19446657c6 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + + /* Full Island ID and channel bits overlap? */ + ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0); +- if (ret) ++ if (ret) { ++ pr_warn("%s: decode dest_island failed: %d\n", __func__, ret); + return ret; ++ } + + /* The current address won't go where expected? */ +- if (dest_island != -1 && dest_island != v) ++ if (dest_island != -1 && dest_island != v) { ++ pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n", ++ __func__, dest_island, v); + return -EINVAL; ++ } + + /* If dest_island was -1, we don't care where it goes. */ + return 0; +@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * the address but we can verify if the existing + * contents will point to a valid island. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + iid_lsb = addr40 ? 34 : 26; +@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + return 0; + case 1: + if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40) +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + idx_lsb = addr40 ? 39 : 31; +@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * be set before hand and with them select an island. + * So we need to confirm that it's at least plausible. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + /* Make sure we compare against isldN values +@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * iid<1> = addr<30> = channel<0> + * channel<1> = addr<31> = Index + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + isld[0] &= ~3; +-- +2.53.0 + diff --git a/queue-5.10/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch b/queue-5.10/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch new file mode 100644 index 0000000000..ce25ff17d3 --- /dev/null +++ b/queue-5.10/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch @@ -0,0 +1,58 @@ +From 6580fc9dcdf38aa24035b97cb8b9c78a36b85d50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:49 +0100 +Subject: nfs/blocklayout: Fix compilation error (`make W=1`) in + bl_write_pagelist() + +From: Andy Shevchenko + +[ Upstream commit f83c8dda456ce4863f346aa26d88efa276eda35d ] + +Clang compiler is not happy about set but unused variable +(when dprintk() is no-op): + +.../blocklayout/blocklayout.c:384:9: error: variable 'count' set but not used [-Werror,-Wunused-but-set-variable] + +Remove a leftover from the previous cleanup. + +Fixes: 3a6fd1f004fc ("pnfs/blocklayout: remove read-modify-write handling in bl_write_pagelist") +Acked-by: Anna Schumaker +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/blocklayout/blocklayout.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c +index a853711bcad27..145608a373193 100644 +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -404,14 +404,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + sector_t isect, extent_length = 0; + struct parallel_io *par = NULL; + loff_t offset = header->args.offset; +- size_t count = header->args.count; + struct page **pages = header->args.pages; + int pg_index = header->args.pgbase >> PAGE_SHIFT; + unsigned int pg_len; + struct blk_plug plug; + int i; + +- dprintk("%s enter, %zu@%lld\n", __func__, count, offset); ++ dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); + + /* At this point, header->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error +@@ -453,7 +452,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + } + + offset += pg_len; +- count -= pg_len; + isect += (pg_len >> SECTOR_SHIFT); + extent_length -= (pg_len >> SECTOR_SHIFT); + } +-- +2.53.0 + diff --git a/queue-5.10/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch b/queue-5.10/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch new file mode 100644 index 0000000000..88007ff4b0 --- /dev/null +++ b/queue-5.10/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch @@ -0,0 +1,61 @@ +From b359ea3afdf9c39b7010dbaab048f33af148c761 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:52:09 +0900 +Subject: nilfs2: reject zero bd_oblocknr in nilfs_ioctl_mark_blocks_dirty() + +From: Deepanshu Kartikey + +[ Upstream commit be3e5d10643d3be1cbac9d9939f220a99253f980 ] + +nilfs_ioctl_mark_blocks_dirty() uses bd_oblocknr to detect dead blocks +by comparing it with the current block number bd_blocknr. If they differ, +the block is considered dead and skipped. + +However, bd_oblocknr should never be 0 since block 0 typically stores the +primary superblock and is never a valid GC target block. A corrupted ioctl +request with bd_oblocknr set to 0 causes the comparison to incorrectly +match when the lookup returns -ENOENT and sets bd_blocknr to 0, bypassing +the dead block check and calling nilfs_bmap_mark() on a non-existent +block. This causes nilfs_btree_do_lookup() to return -ENOENT, triggering +the WARN_ON(ret == -ENOENT). + +Fix this by rejecting ioctl requests with bd_oblocknr set to 0 at the +beginning of each iteration. + +[ryusuke: slightly modified the commit message and comments for accuracy] + +Fixes: 7942b919f732 ("nilfs2: ioctl operations") +Reported-by: syzbot+98a040252119df0506f8@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=98a040252119df0506f8 +Suggested-by: Ryusuke Konishi +Signed-off-by: Deepanshu Kartikey +Reported-by: syzbot+466a45fcfb0562f5b9a0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=466a45fcfb0562f5b9a0 +Cc: Junjie Cao +Signed-off-by: Ryusuke Konishi +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/nilfs2/ioctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index 668c1b28a940e..e56e871927417 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -766,6 +766,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, + int ret, i; + + for (i = 0; i < nmembs; i++) { ++ /* ++ * bd_oblocknr must never be 0 as block 0 ++ * is never a valid GC target block ++ */ ++ if (unlikely(!bdescs[i].bd_oblocknr)) ++ return -EINVAL; + /* XXX: use macro or inline func to check liveness */ + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, +-- +2.53.0 + diff --git a/queue-5.10/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch b/queue-5.10/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch new file mode 100644 index 0000000000..410acca394 --- /dev/null +++ b/queue-5.10/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch @@ -0,0 +1,48 @@ +From d23057d5e91e0754209f8ec76f35b940eca52d42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:09 +0800 +Subject: ocfs2/dlm: fix off-by-one in dlm_match_regions() region comparison + +From: Junrui Luo + +[ Upstream commit 01b61e8dda9b0fdb0d4cda43de25f4e390554d7b ] + +The local-vs-remote region comparison loop uses '<=' instead of '<', +causing it to read one entry past the valid range of qr_regions. The +other loops in the same function correctly use '<'. + +Fix the loop condition to use '<' for consistency and correctness. + +Link: https://lkml.kernel.org/r/SYBPR01MB78813DA26B50EC5E01F00566AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 6881961dbde87..5201071c0080d 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1004,7 +1004,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + for (i = 0; i < localnr; ++i) { + foundit = 0; + r = remote; +- for (j = 0; j <= qr->qr_numregions; ++j) { ++ for (j = 0; j < qr->qr_numregions; ++j) { + if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { + foundit = 1; + break; +-- +2.53.0 + diff --git a/queue-5.10/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch b/queue-5.10/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch new file mode 100644 index 0000000000..737e30ac5b --- /dev/null +++ b/queue-5.10/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch @@ -0,0 +1,75 @@ +From 12193704cd19b35f5e40b4b2ae790388a46506b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:08 +0800 +Subject: ocfs2/dlm: validate qr_numregions in dlm_match_regions() + +From: Junrui Luo + +[ Upstream commit 7ab3fbb01bc6d79091bc375e5235d360cd9b78be ] + +Patch series "ocfs2/dlm: fix two bugs in dlm_match_regions()". + +In dlm_match_regions(), the qr_numregions field from a DLM_QUERY_REGION +network message is used to drive loops over the qr_regions buffer without +sufficient validation. This series fixes two issues: + +- Patch 1 adds a bounds check to reject messages where qr_numregions + exceeds O2NM_MAX_REGIONS. The o2net layer only validates message + byte length; it does not constrain field values, so a crafted message + can set qr_numregions up to 255 and trigger out-of-bounds reads past + the 1024-byte qr_regions buffer. + +- Patch 2 fixes an off-by-one in the local-vs-remote comparison loop, + which uses '<=' instead of '<', reading one entry past the valid range + even when qr_numregions is within bounds. + +This patch (of 2): + +The qr_numregions field from a DLM_QUERY_REGION network message is used +directly as loop bounds in dlm_match_regions() without checking against +O2NM_MAX_REGIONS. Since qr_regions is sized for at most O2NM_MAX_REGIONS +(32) entries, a crafted message with qr_numregions > 32 causes +out-of-bounds reads past the qr_regions buffer. + +Add a bounds check for qr_numregions before entering the loops. + +Link: https://lkml.kernel.org/r/SYBPR01MB7881A334D02ACEE5E0645801AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Link: https://lkml.kernel.org/r/SYBPR01MB788166F524AD04E262E174BEAF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 357cfc702ce36..6881961dbde87 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -982,6 +982,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + goto bail; + } + ++ if (qr->qr_numregions > O2NM_MAX_REGIONS) { ++ mlog(ML_ERROR, "Domain %s: Joining node %d has invalid " ++ "number of heartbeat regions %u\n", ++ qr->qr_domain, qr->qr_node, qr->qr_numregions); ++ status = -EINVAL; ++ goto bail; ++ } ++ + r = remote; + for (i = 0; i < qr->qr_numregions; ++i) { + mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); +-- +2.53.0 + diff --git a/queue-5.10/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch b/queue-5.10/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch new file mode 100644 index 0000000000..5e8fba052a --- /dev/null +++ b/queue-5.10/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch @@ -0,0 +1,89 @@ +From c0a86f826e2f7073ada8cd8613882c7cfc8c9fd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 12:03:39 +0800 +Subject: ocfs2: fix listxattr handling when the buffer is full + +From: ZhengYuan Huang + +[ Upstream commit d12f558e6200b3f47dbef9331ed6d115d2410e59 ] + +[BUG] +If an OCFS2 inode has both inline and block-based xattrs, listxattr() +can return a size larger than the caller's buffer when the inline names +consume that buffer exactly. + +kernel BUG at mm/usercopy.c:102! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:usercopy_abort+0xb7/0xd0 mm/usercopy.c:102 +Call Trace: + __check_heap_object+0xe3/0x120 mm/slub.c:8243 + check_heap_object mm/usercopy.c:196 [inline] + __check_object_size mm/usercopy.c:250 [inline] + __check_object_size+0x5c5/0x780 mm/usercopy.c:215 + check_object_size include/linux/ucopysize.h:22 [inline] + check_copy_size include/linux/ucopysize.h:59 [inline] + copy_to_user include/linux/uaccess.h:219 [inline] + listxattr+0xb0/0x170 fs/xattr.c:926 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x137/0x320 fs/xattr.c:988 + __do_sys_listxattr fs/xattr.c:1001 [inline] + __se_sys_listxattr fs/xattr.c:998 [inline] + __x64_sys_listxattr+0x7f/0xd0 fs/xattr.c:998 + ... + +[CAUSE] +Commit 936b8834366e ("ocfs2: Refactor xattr list and remove +ocfs2_xattr_handler().") replaced the old per-handler list accounting +with ocfs2_xattr_list_entry(), but it kept using size == 0 to detect +probe mode. + +That assumption stops being true once ocfs2_listxattr() finishes the +inline-xattr pass. If the inline names fill the caller buffer exactly, +the block-xattr pass runs with a non-NULL buffer and a remaining size of +zero. ocfs2_xattr_list_entry() then skips the bounds check, keeps +counting block names, and returns a positive size larger than the +supplied buffer. + +[FIX] +Detect probe mode by testing whether the destination buffer pointer is +NULL instead of whether the remaining size is zero. + +That restores the pre-refactor behavior and matches the OCFS2 getxattr +helpers. Once the remaining buffer reaches zero while more names are +left, the block-xattr pass now returns -ERANGE instead of reporting a +size larger than the allocated list buffer. + +Link: https://lkml.kernel.org/r/20260410040339.3837162-1-gality369@gmail.com +Fixes: 936b8834366e ("ocfs2: Refactor xattr list and remove ocfs2_xattr_handler().") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index d1409187b3fd1..be982b727facb 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -913,8 +913,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb, + total_len = prefix_len + name_len + 1; + *result += total_len; + +- /* we are just looking for how big our buffer needs to be */ +- if (!size) ++ /* No buffer means we are only looking for the required size. */ ++ if (!buffer) + return 0; + + if (*result > size) +-- +2.53.0 + diff --git a/queue-5.10/ocfs2-validate-bg_bits-during-freefrag-scan.patch b/queue-5.10/ocfs2-validate-bg_bits-during-freefrag-scan.patch new file mode 100644 index 0000000000..cbc2e42b59 --- /dev/null +++ b/queue-5.10/ocfs2-validate-bg_bits-during-freefrag-scan.patch @@ -0,0 +1,121 @@ +From c44f8df84672df3ebd059a402de387a8160784d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:42:20 +0800 +Subject: ocfs2: validate bg_bits during freefrag scan + +From: ZhengYuan Huang + +[ Upstream commit 8f687eeed3da3012152b0f9473f578869de0cd7b ] + +[BUG] +A crafted filesystem can trigger an out-of-bounds bitmap walk when +OCFS2_IOC_INFO is issued with OCFS2_INFO_FL_NON_COHERENT. + +BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:68 [inline] +BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] +BUG: KASAN: use-after-free in test_bit_le include/asm-generic/bitops/le.h:21 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 +Read of size 8 at addr ffff888031bce000 by task syz.0.636/1435 +Call Trace: + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xd1/0x650 mm/kasan/report.c:482 + kasan_report+0xfb/0x140 mm/kasan/report.c:595 + check_region_inline mm/kasan/generic.c:186 [inline] + kasan_check_range+0x11c/0x200 mm/kasan/generic.c:200 + __kasan_check_read+0x11/0x20 mm/kasan/shadow.c:31 + instrument_atomic_read include/linux/instrumented.h:68 [inline] + _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] + test_bit_le include/asm-generic/bitops/le.h:21 [inline] + ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] + ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] + ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] + ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 + ocfs2_info_handle+0x18d/0x2a0 fs/ocfs2/ioctl.c:828 + ocfs2_ioctl+0x632/0x6e0 fs/ocfs2/ioctl.c:913 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + ... + +[CAUSE] +ocfs2_info_freefrag_scan_chain() uses on-disk bg_bits directly as the +bitmap scan limit. The coherent path reads group descriptors through +ocfs2_read_group_descriptor(), which validates the descriptor before +use. The non-coherent path uses ocfs2_read_blocks_sync() instead and +skips that validation, so an impossible bg_bits value can drive the +bitmap walk past the end of the block. + +[FIX] +Compute the bitmap capacity from the filesystem format with +ocfs2_group_bitmap_size(), report descriptors whose bg_bits exceeds +that limit, and clamp the scan to the computed capacity. This keeps the +freefrag report going while avoiding reads beyond the buffer. + +Link: https://lkml.kernel.org/r/20260410034220.3825769-1-gality369@gmail.com +Fixes: d24a10b9f8ed ("Ocfs2: Add a new code 'OCFS2_INFO_FREEFRAG' for o2info ioctl.") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Heming Zhao +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/ioctl.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c +index 89984172fc4ae..b43d6c3586e0a 100644 +--- a/fs/ocfs2/ioctl.c ++++ b/fs/ocfs2/ioctl.c +@@ -438,13 +438,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + struct buffer_head *bh = NULL; + struct ocfs2_group_desc *bg = NULL; + +- unsigned int max_bits, num_clusters; ++ unsigned int max_bits, max_bitmap_bits, num_clusters; + unsigned int offset = 0, cluster, chunk; + unsigned int chunk_free, last_chunksize = 0; + + if (!le32_to_cpu(rec->c_free)) + goto bail; + ++ max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0, ++ osb->s_feature_incompat); ++ + do { + if (!bg) + blkno = le64_to_cpu(rec->c_blkno); +@@ -476,6 +479,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + continue; + + max_bits = le16_to_cpu(bg->bg_bits); ++ ++ /* ++ * Non-coherent scans read raw blocks and do not get the ++ * bg_bits validation from ++ * ocfs2_read_group_descriptor(). ++ */ ++ if (max_bits > max_bitmap_bits) { ++ mlog(ML_ERROR, ++ "Group desc #%llu has %u bits, max bitmap bits %u\n", ++ (unsigned long long)blkno, max_bits, max_bitmap_bits); ++ max_bits = max_bitmap_bits; ++ } ++ + offset = 0; + + for (chunk = 0; chunk < chunks_in_group; chunk++) { +-- +2.53.0 + diff --git a/queue-5.10/ocfs2-validate-group-add-input-before-caching.patch b/queue-5.10/ocfs2-validate-group-add-input-before-caching.patch new file mode 100644 index 0000000000..60bd821dc6 --- /dev/null +++ b/queue-5.10/ocfs2-validate-group-add-input-before-caching.patch @@ -0,0 +1,110 @@ +From f9e64c1974e8e83ce50bf11f1cc6529989c59903 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 10:02:08 +0800 +Subject: ocfs2: validate group add input before caching + +From: ZhengYuan Huang + +[ Upstream commit 70b672833f4025341c11b22c7f83778a5cd611bc ] + +[BUG] +OCFS2_IOC_GROUP_ADD can trigger a BUG_ON in +ocfs2_set_new_buffer_uptodate(): + +kernel BUG at fs/ocfs2/uptodate.c:509! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:ocfs2_set_new_buffer_uptodate+0x194/0x1e0 fs/ocfs2/uptodate.c:509 +Code: ffffe88f 42b9fe4c 89e64889 dfe8b4df +Call Trace: + ocfs2_group_add+0x3f1/0x1510 fs/ocfs2/resize.c:507 + ocfs2_ioctl+0x309/0x6e0 fs/ocfs2/ioctl.c:887 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + x64_sys_call+0x1144/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:17 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e +RIP: 0033:0x7bbfb55a966d + +[CAUSE] +ocfs2_group_add() calls ocfs2_set_new_buffer_uptodate() on a +user-controlled group block before ocfs2_verify_group_and_input() +validates that block number. That helper is only valid for newly +allocated metadata and asserts that the block is not already present in +the chosen metadata cache. The code also uses INODE_CACHE(inode) even +though the group descriptor belongs to main_bm_inode and later journal +accesses use that cache context instead. + +[FIX] +Validate the on-disk group descriptor before caching it, then add it to +the metadata cache tracked by INODE_CACHE(main_bm_inode). Keep the +validation failure path separate from the later cleanup path so we only +remove the buffer from that cache after it has actually been inserted. +This keeps the group buffer lifetime consistent across validation, +journaling, and cleanup. + +Link: https://lkml.kernel.org/r/20260410020209.3786348-1-gality369@gmail.com +Fixes: 7909f2bf8353 ("[PATCH 2/2] ocfs2: Implement group add for online resize") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/resize.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c +index 3d85d0b52034b..763aff7e2d5a4 100644 +--- a/fs/ocfs2/resize.c ++++ b/fs/ocfs2/resize.c +@@ -502,14 +502,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + goto out_unlock; + } + +- ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); +- + ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); + if (ret) { + mlog_errno(ret); + goto out_free_group_bh; + } + ++ ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh); ++ + trace_ocfs2_group_add((unsigned long long)input->group, + input->chain, input->clusters, input->frees); + +@@ -517,7 +517,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + if (IS_ERR(handle)) { + mlog_errno(PTR_ERR(handle)); + ret = -EINVAL; +- goto out_free_group_bh; ++ goto out_remove_cache; + } + + cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); +@@ -571,9 +571,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + out_commit: + ocfs2_commit_trans(osb, handle); + +-out_free_group_bh: ++out_remove_cache: + if (ret < 0) +- ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); ++ ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh); ++ ++out_free_group_bh: + brelse(group_bh); + + out_unlock: +-- +2.53.0 + diff --git a/queue-5.10/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch b/queue-5.10/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch new file mode 100644 index 0000000000..e4f224c558 --- /dev/null +++ b/queue-5.10/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch @@ -0,0 +1,132 @@ +From a476ec404f515793a1ddcf5c3511ba3e3122a706 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 19:46:54 -0700 +Subject: openvswitch: cap upcall PID array size and pre-size vport replies + +From: Weiming Shi + +[ Upstream commit 2091c6aa0df6aba47deb5c8ab232b1cb60af3519 ] + +The vport netlink reply helpers allocate a fixed-size skb with +nlmsg_new(NLMSG_DEFAULT_SIZE, ...) but serialize the full upcall PID +array via ovs_vport_get_upcall_portids(). Since +ovs_vport_set_upcall_portids() accepts any non-zero multiple of +sizeof(u32) with no upper bound, a CAP_NET_ADMIN user can install a PID +array large enough to overflow the reply buffer, causing nla_put() to +fail with -EMSGSIZE and hitting BUG_ON(err < 0). On systems with +unprivileged user namespaces enabled (e.g., Ubuntu default), this is +reachable via unshare -Urn since OVS vport mutation operations use +GENL_UNS_ADMIN_PERM. + + kernel BUG at net/openvswitch/datapath.c:2414! + Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI + CPU: 1 UID: 0 PID: 65 Comm: poc Not tainted 7.0.0-rc7-00195-geb216e422044 #1 + RIP: 0010:ovs_vport_cmd_set+0x34c/0x400 + Call Trace: + + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1116) + genl_rcv_msg (net/netlink/genetlink.c:1194) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + genl_rcv (net/netlink/genetlink.c:1219) + netlink_unicast (net/netlink/af_netlink.c:1344) + netlink_sendmsg (net/netlink/af_netlink.c:1894) + __sys_sendto (net/socket.c:2206) + __x64_sys_sendto (net/socket.c:2209) + do_syscall_64 (arch/x86/entry/syscall_64.c:63) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + + Kernel panic - not syncing: Fatal exception + +Reject attempts to set more PIDs than nr_cpu_ids in +ovs_vport_set_upcall_portids(), and pre-compute the worst-case reply +size in ovs_vport_cmd_msg_size() based on that bound, similar to the +existing ovs_dp_cmd_msg_size(). nr_cpu_ids matches the cap already +used by the per-CPU dispatch configuration on the datapath side +(ovs_dp_cmd_fill_info() serialises at most nr_cpu_ids PIDs), so the +two sides stay consistent. + +Fixes: 5cd667b0a456 ("openvswitch: Allow each vport to have an array of 'port_id's.") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Weiming Shi +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260416024653.153456-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 35 +++++++++++++++++++++++++++++++++-- + net/openvswitch/vport.c | 3 +++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index b493931433e99..1c69aa986633a 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -2032,9 +2032,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + return err; + } + ++static size_t ovs_vport_cmd_msg_size(void) ++{ ++ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); ++ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */ ++ msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */ ++ msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */ ++ ++ /* OVS_VPORT_ATTR_STATS */ ++ msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats)); ++ ++ /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + ++ * OVS_VPORT_UPCALL_ATTR_FAIL) ++ */ ++ msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) + ++ nla_total_size_64bit(sizeof(u64))); ++ ++ /* OVS_VPORT_ATTR_UPCALL_PID */ ++ msgsize += nla_total_size(nr_cpu_ids * sizeof(u32)); ++ ++ /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + ++ * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) ++ */ ++ msgsize += nla_total_size(nla_total_size(sizeof(u16)) + ++ nla_total_size(nla_total_size(0))); ++ ++ return msgsize; ++} ++ + static struct sk_buff *ovs_vport_cmd_alloc_info(void) + { +- return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL); + } + + /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ +@@ -2044,7 +2075,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, + struct sk_buff *skb; + int retval; + +- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ skb = ovs_vport_cmd_alloc_info(); + if (!skb) + return ERR_PTR(-ENOMEM); + +diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c +index 1c05d4bef3313..da733b92ae8a7 100644 +--- a/net/openvswitch/vport.c ++++ b/net/openvswitch/vport.c +@@ -340,6 +340,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids) + if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) + return -EINVAL; + ++ if (nla_len(ids) / sizeof(u32) > nr_cpu_ids) ++ return -EINVAL; ++ + old = ovsl_dereference(vport->upcall_portids); + + vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), +-- +2.53.0 + diff --git a/queue-5.10/pci-enable-atomicops-only-if-root-port-supports-them.patch b/queue-5.10/pci-enable-atomicops-only-if-root-port-supports-them.patch new file mode 100644 index 0000000000..4026ce1f94 --- /dev/null +++ b/queue-5.10/pci-enable-atomicops-only-if-root-port-supports-them.patch @@ -0,0 +1,110 @@ +From 6c6b5439bfcbd9de14c89beb00f477e34857bbe7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:09:45 +0200 +Subject: PCI: Enable AtomicOps only if Root Port supports them + +From: Gerd Bayer + +[ Upstream commit 1ae8c4ce157037e266184064a182af9ef9af278b ] + +When inspecting the config space of a Connect-X physical function in an +s390 system after it was initialized by the mlx5_core device driver, we +found the function to be enabled to request AtomicOps despite the Root Port +lacking support for completing them: + + 00:00.1 Ethernet controller: Mellanox Technologies MT2894 Family [ConnectX-6 Lx] + Subsystem: Mellanox Technologies Device 0002 + DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- + AtomicOpsCtl: ReqEn+ + +On s390 and many virtualized guests, the Endpoint is visible but the Root +Port is not. In this case, pci_enable_atomic_ops_to_root() previously +enabled AtomicOps in the Endpoint even though it can't tell whether the +Root Port supports them as a completer. + +Change pci_enable_atomic_ops_to_root() to fail if there's no Root Port or +the Root Port doesn't support AtomicOps. + +Fixes: 430a23689dea ("PCI: Add pci_enable_atomic_ops_to_root()") +Reported-by: Alexander Schmidt +Signed-off-by: Gerd Bayer +[bhelgaas: commit log, check RP first to simplify flow] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260330-fix_pciatops-v7-2-f601818417e8@linux.ibm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 41 ++++++++++++++++++++--------------------- + 1 file changed, 20 insertions(+), 21 deletions(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 115c4ce3310f1..ecac0f8d7ff51 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -3680,8 +3680,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) + */ + int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + { +- struct pci_bus *bus = dev->bus; +- struct pci_dev *bridge; ++ struct pci_dev *root, *bridge; + u32 cap, ctl2; + + if (!pci_is_pcie(dev)) +@@ -3703,35 +3702,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + return -EINVAL; + } + +- while (bus->parent) { +- bridge = bus->self; ++ root = pcie_find_root_port(dev); ++ if (!root) ++ return -EINVAL; + +- pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap); ++ pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); ++ if ((cap & cap_mask) != cap_mask) ++ return -EINVAL; + ++ bridge = pci_upstream_bridge(dev); ++ while (bridge != root) { + switch (pci_pcie_type(bridge)) { +- /* Ensure switch ports support AtomicOp routing */ + case PCI_EXP_TYPE_UPSTREAM: +- case PCI_EXP_TYPE_DOWNSTREAM: +- if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) +- return -EINVAL; +- break; +- +- /* Ensure root port supports all the sizes we care about */ +- case PCI_EXP_TYPE_ROOT_PORT: +- if ((cap & cap_mask) != cap_mask) +- return -EINVAL; +- break; +- } +- +- /* Ensure upstream ports don't block AtomicOps on egress */ +- if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) { ++ /* Upstream ports must not block AtomicOps on egress */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, + &ctl2); + if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK) + return -EINVAL; ++ fallthrough; ++ ++ /* All switch ports need to route AtomicOps */ ++ case PCI_EXP_TYPE_DOWNSTREAM: ++ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, ++ &cap); ++ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) ++ return -EINVAL; ++ break; + } + +- bus = bus->parent; ++ bridge = pci_upstream_bridge(bridge); + } + + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, +-- +2.53.0 + diff --git a/queue-5.10/pci-tegra194-disable-direct-speed-change-for-endpoin.patch b/queue-5.10/pci-tegra194-disable-direct-speed-change-for-endpoin.patch new file mode 100644 index 0000000000..9c9c608eeb --- /dev/null +++ b/queue-5.10/pci-tegra194-disable-direct-speed-change-for-endpoin.patch @@ -0,0 +1,52 @@ +From c5e50432cb2e50238d57fdf1b12cd0d65baa0f8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:48 +0530 +Subject: PCI: tegra194: Disable direct speed change for Endpoint mode + +From: Vidya Sagar + +[ Upstream commit 976f6763f57970388bcd7118931f33f447916927 ] + +Pre-silicon simulation showed the controller operating in Endpoint mode +initiating link speed change after completing Secondary Bus Reset. Ideally, +the Root Port or the Switch Downstream Port should initiate the link speed +change post SBR, not the Endpoint. + +So, as per the hardware team recommendation, disable direct speed change +for the Endpoint mode to prevent it from initiating speed change after the +physical layer link is up at Gen1, leaving speed change ownership with the +host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-8-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index ee8f25c07f2e1..e59939ec2022c 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1771,6 +1771,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); ++ val &= ~PORT_LOGIC_SPEED_CHANGE; ++ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); ++ + if (pcie->update_fc_fixup) { + val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); + val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; +-- +2.53.0 + diff --git a/queue-5.10/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch b/queue-5.10/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch new file mode 100644 index 0000000000..6261157813 --- /dev/null +++ b/queue-5.10/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch @@ -0,0 +1,47 @@ +From 2b9783da34c1b46d9abadee7c52eca98f1341324 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:47 +0530 +Subject: PCI: tegra194: Use devm_gpiod_get_optional() to parse + "nvidia,refclk-select" + +From: Vidya Sagar + +[ Upstream commit f62bc7917de1374dce86a852ffba8baf9cb7a56a ] + +The GPIO DT property "nvidia,refclk-select", to select the PCIe reference +clock is optional. Use devm_gpiod_get_optional() to get it. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-7-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index ba9fcb39ca90d..ee8f25c07f2e1 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1135,9 +1135,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) + return err; + } + +- pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, +- "nvidia,refclk-select", +- GPIOD_OUT_HIGH); ++ pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev, ++ "nvidia,refclk-select", ++ GPIOD_OUT_HIGH); + if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { + int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); + const char *level = KERN_ERR; +-- +2.53.0 + diff --git a/queue-5.10/pcmcia-fix-garbled-log-messages-for-kern_cont.patch b/queue-5.10/pcmcia-fix-garbled-log-messages-for-kern_cont.patch new file mode 100644 index 0000000000..218223f16f --- /dev/null +++ b/queue-5.10/pcmcia-fix-garbled-log-messages-for-kern_cont.patch @@ -0,0 +1,55 @@ +From 8c62f8941a085f450f3074a30914abeec610ed79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 17:42:56 +0100 +Subject: PCMCIA: Fix garbled log messages for KERN_CONT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit bfeaa6814bd3f9a1f6d525b3b35a03b9a0368961 ] + +For years the PCMCIA info messages are messed up by superfluous +newlines. While f2e6cf76751d ("pcmcia: Convert dev_printk to +dev_") converted the code to pr_cont(), dev_info enforces a \n +via vprintk_store setting LOG_NEWLINE, breaking subsequent pr_cont. + +Fix by logging the device name manually to allow pr_cont to work for +more readable and not \n distorted logs. + +Fixes: f2e6cf76751d ("pcmcia: Convert dev_printk to dev_") +Signed-off-by: René Rebe +Signed-off-by: Dominik Brodowski +Signed-off-by: Sasha Levin +--- + drivers/pcmcia/rsrc_nonstatic.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c +index ab487edec2e5b..9b3ff50cfdc6a 100644 +--- a/drivers/pcmcia/rsrc_nonstatic.c ++++ b/drivers/pcmcia/rsrc_nonstatic.c +@@ -188,7 +188,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, + int any; + u_char *b, hole, most; + +- dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1); ++ pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1); + + /* First, what does a floating port look like? */ + b = kzalloc(256, GFP_KERNEL); +@@ -410,8 +410,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + struct socket_data *s_data = s->resource_data; + u_long i, j, bad, fail, step; + +- dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:", +- base, base+num-1); ++ pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:", ++ dev_name(&s->dev), base, base+num-1); + bad = fail = 0; + step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + /* don't allow too large steps */ +-- +2.53.0 + diff --git a/queue-5.10/perf-branch-avoid-incrementing-null.patch b/queue-5.10/perf-branch-avoid-incrementing-null.patch new file mode 100644 index 0000000000..7fd3d5cefe --- /dev/null +++ b/queue-5.10/perf-branch-avoid-incrementing-null.patch @@ -0,0 +1,39 @@ +From 59bc8682d65a07c29663cabdc3d95af2f5ae8976 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:31:31 -0700 +Subject: perf branch: Avoid incrementing NULL + +From: Ian Rogers + +[ Upstream commit c969a9d7bbf46f983c4a48566b3b2f7340b02296 ] + +If the entry is NULL the value is meaningless so early return NULL to +avoid an increment of NULL. This was happening in calls from +has_stitched_lbr when running the "perf record LBR tests". The return +value isn't used in that case, so returning NULL as no effect. + +Fixes: 42bbabed09ce ("perf tools: Add hw_idx in struct branch_stack") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/branch.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h +index 17b2ccc61094b..9a20b6fc8dda2 100644 +--- a/tools/perf/util/branch.h ++++ b/tools/perf/util/branch.h +@@ -63,6 +63,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl + { + u64 *entry = (u64 *)sample->branch_stack; + ++ if (entry == NULL) ++ return NULL; ++ + entry++; + if (sample->no_hw_idx) + return (struct branch_entry *)entry; +-- +2.53.0 + diff --git a/queue-5.10/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch b/queue-5.10/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch new file mode 100644 index 0000000000..7f58faa28d --- /dev/null +++ b/queue-5.10/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch @@ -0,0 +1,55 @@ +From 101c4016838fda0b0606dbc3147fb629e2408e4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:04:47 +0100 +Subject: perf expr: Return -EINVAL for syntax error in expr__find_ids() + +From: Leo Yan + +[ Upstream commit 3a61fd866ef9aaa1d3158b460f852b74a2df07f4 ] + +expr__find_ids() propagates the parser return value directly. For syntax +errors, the parser can return a positive value, but callers treat it as +success, e.g., for below case on Arm64 platform: + + metric expr 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) for backend_bound + parsing metric: 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) + Failure to read '#slots' literal: #slots = nan + syntax error + +Convert positive parser returns in expr__find_ids() to -EINVAL, as a +result, the error value will be respected by callers. + +Before: + + perf stat -C 5 + Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Segmentation fault + +After: + + perf stat -C 5 + Failure to read '#slots'Cannot find metric or group `Default' + +Fixes: ded80bda8bc9 ("perf expr: Migrate expr ids table to a hashmap") +Signed-off-by: Leo Yan +Reviewed-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/expr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index 53482ef53c411..15f857fb0e713 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -239,5 +239,6 @@ int expr__find_other(const char *expr, const char *one, + if (one) + expr__del_id(ctx, one); + +- return ret; ++ /* A positive value means syntax error, convert to -EINVAL */ ++ return ret > 0 ? -EINVAL : ret; + } +-- +2.53.0 + diff --git a/queue-5.10/perf-tools-fix-module-symbol-resolution-for-non-zero.patch b/queue-5.10/perf-tools-fix-module-symbol-resolution-for-non-zero.patch new file mode 100644 index 0000000000..848bf4badb --- /dev/null +++ b/queue-5.10/perf-tools-fix-module-symbol-resolution-for-non-zero.patch @@ -0,0 +1,77 @@ +From 5375cb51a70f3fd1e569bb879668c92c6f984a1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 11:58:04 -0400 +Subject: perf tools: Fix module symbol resolution for non-zero .text sh_addr + +From: Chuck Lever + +[ Upstream commit 9a82bfde4775b7a87cd1a7e791f46f83ae442848 ] + +When perf resolves symbols from kernel module ELF files (ET_REL), +it converts symbol addresses to file offsets so that sample IPs +can be matched to the correct symbol. The conversion adjusts each +symbol's st_value: + + sym->st_value -= shdr->sh_addr - shdr->sh_offset; + +For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr +is the section's virtual base, so subtracting sh_addr and adding +sh_offset correctly yields a file offset. + +For kernel modules (ET_REL), st_value is a section-relative +offset. The module loader ignores sh_addr entirely and places +symbols at module_base + st_value. Converting to file offset +requires only adding sh_offset; subtracting sh_addr introduces an +error equal to sh_addr bytes. + +When .text has sh_addr == 0 -- the historical norm for simple +modules -- both formulas produce the same result and the bug is +latent. As modules gain more metadata sections before .text (.note, +.static_call.text, etc.), the linker assigns .text a non-zero +sh_addr, exposing the defect. For example, nfsd.ko on this kernel +has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90. + +The effect is that all .text symbols in affected modules +shift by sh_addr bytes relative to sample IPs, causing perf +report to attribute samples to incorrect, nearby symbols. This +was observed as 13% of LLC-load-miss samples misattributed +to nfsd_file_get_dio_attrs when the actual hot function was +nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol +table. + +Use the existing dso__rel() flag (already set for ET_REL modules) +to select the correct adjustment: add sh_offset for ET_REL, +subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN. + +Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules") +Signed-off-by: Chuck Lever +Reviewed-by: Ian Rogers +Tested-by: Thomas Richter +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/symbol-elf.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c +index b171d134ce87a..608dca7b58c57 100644 +--- a/tools/perf/util/symbol-elf.c ++++ b/tools/perf/util/symbol-elf.c +@@ -968,8 +968,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, + char dso_name[PATH_MAX]; + + /* Adjust symbol to map to file offset */ +- if (adjust_kernel_syms) +- sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ if (adjust_kernel_syms) { ++ if (dso__rel(dso)) ++ sym->st_value += shdr->sh_offset; ++ else ++ sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ } + + if (strcmp(section_name, (curr_dso->short_name + dso->short_name_len)) == 0) + return 0; +-- +2.53.0 + diff --git a/queue-5.10/perf-util-kill-die-prototype-dead-for-a-long-time.patch b/queue-5.10/perf-util-kill-die-prototype-dead-for-a-long-time.patch new file mode 100644 index 0000000000..3d3f75e991 --- /dev/null +++ b/queue-5.10/perf-util-kill-die-prototype-dead-for-a-long-time.patch @@ -0,0 +1,39 @@ +From 84b91fc2ad31f71beabe485efb8d151ab677ae98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:31:57 -0300 +Subject: perf util: Kill die() prototype, dead for a long time + +From: Arnaldo Carvalho de Melo + +[ Upstream commit e5cce1b9c82fbd48e2f1f7a25a9fad8ee228176f ] + +In fef2a735167a827a ("perf tools: Kill die()") the die() function was +removed, but not the prototype in util.h, now when building with +LIBPERL=1, during a 'make -C tools/perf build-test' routine test, it is +failing as perl likes die() calls and then this clashes with this +remnant, remove it. + +Fixes: fef2a735167a827a ("perf tools: Kill die()") +Reviewed-by: Ian Rogers +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/util.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h +index 9f0d36ba77f2d..130c68dff4ce0 100644 +--- a/tools/perf/util/util.h ++++ b/tools/perf/util/util.h +@@ -14,7 +14,6 @@ + + /* General helper functions */ + void usage(const char *err) __noreturn; +-void die(const char *err, ...) __noreturn __printf(1, 2); + + struct dirent; + struct strlist; +-- +2.53.0 + diff --git a/queue-5.10/pinctrl-abx500-fix-type-of-argument-variable.patch b/queue-5.10/pinctrl-abx500-fix-type-of-argument-variable.patch new file mode 100644 index 0000000000..8d064a9020 --- /dev/null +++ b/queue-5.10/pinctrl-abx500-fix-type-of-argument-variable.patch @@ -0,0 +1,38 @@ +From d9ae4f87c6fd4c0798ddc87f5e2830cae007dc06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 23:15:06 +0800 +Subject: pinctrl: abx500: Fix type of 'argument' variable + +From: Yu-Chun Lin + +[ Upstream commit 34006f77890d050e6d80cbee365b5d703c1140b4 ] + +The argument variable is assigned the return value of +pinconf_to_config_argument(), which returns a u32. Change its type from +enum pin_config_param to unsigned int to correctly store the configuration +argument. + +Fixes: 03b054e9696c ("pinctrl: Pass all configs to driver on pin_config_set()") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/nomadik/pinctrl-abx500.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c +index 7aa534576a459..609313d93e31a 100644 +--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c ++++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c +@@ -850,7 +850,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, + int ret = -EINVAL; + int i; + enum pin_config_param param; +- enum pin_config_param argument; ++ unsigned int argument; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); +-- +2.53.0 + diff --git a/queue-5.10/pinctrl-pinctrl-pic32-fix-resource-leak.patch b/queue-5.10/pinctrl-pinctrl-pic32-fix-resource-leak.patch new file mode 100644 index 0000000000..78fe5012b5 --- /dev/null +++ b/queue-5.10/pinctrl-pinctrl-pic32-fix-resource-leak.patch @@ -0,0 +1,72 @@ +From fcecf6f99ab19c9bbd1e99fca51f5624f79ae9e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:56:23 -0600 +Subject: pinctrl: pinctrl-pic32: Fix resource leak + +From: Ethan Tidmore + +[ Upstream commit fe5560688f3ba98364c7de7b4f8dc240ffd1ff75 ] + +Fix three possible resource leaks by using the devres version of +clk_prepare_enable(). Also, update error message accordingly. + +Detected by Smatch: +drivers/pinctrl/pinctrl-pic32.c:2211 pic32_pinctrl_probe() warn: +'pctl->clk' from clk_prepare_enable() not released on lines: 2208. + +drivers/pinctrl/pinctrl-pic32.c:2274 pic32_gpio_probe() warn: +'bank->clk' from clk_prepare_enable() not released on lines: 2264,2272. + +Fixes: 2ba384e6c3810 ("pinctrl: pinctrl-pic32: Add PIC32 pin control driver") +Signed-off-by: Ethan Tidmore +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-pic32.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c +index a6e2a4a4ca952..07dc358359e32 100644 +--- a/drivers/pinctrl/pinctrl-pic32.c ++++ b/drivers/pinctrl/pinctrl-pic32.c +@@ -2162,16 +2162,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev) + if (IS_ERR(pctl->reg_base)) + return PTR_ERR(pctl->reg_base); + +- pctl->clk = devm_clk_get(&pdev->dev, NULL); ++ pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(pctl->clk)) { + ret = PTR_ERR(pctl->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(pctl->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +@@ -2227,16 +2221,10 @@ static int pic32_gpio_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- bank->clk = devm_clk_get(&pdev->dev, NULL); ++ bank->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bank->clk)) { + ret = PTR_ERR(bank->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(bank->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +-- +2.53.0 + diff --git a/queue-5.10/platform-surface-surfacepro3_button-drop-wakeup-sour.patch b/queue-5.10/platform-surface-surfacepro3_button-drop-wakeup-sour.patch new file mode 100644 index 0000000000..9c26e76571 --- /dev/null +++ b/queue-5.10/platform-surface-surfacepro3_button-drop-wakeup-sour.patch @@ -0,0 +1,41 @@ +From 1b2893b1b15238027682acac82ee791aa5a499cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:54:08 +0100 +Subject: platform/surface: surfacepro3_button: Drop wakeup source on remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 1410a228ab2d36fe2b383415a632ae12048d4f3a ] + +The wakeup source added by device_init_wakeup() in surface_button_add() +needs to be dropped during driver removal, so update the driver to do +that. + +Fixes: 19351f340765 ("platform/x86: surfacepro3: Support for wakeup from suspend-to-idle") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/4368848.1IzOArtZ34@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/surfacepro3_button.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c +index d8afed5db94c5..17d3fc81aa6e7 100644 +--- a/drivers/platform/x86/surfacepro3_button.c ++++ b/drivers/platform/x86/surfacepro3_button.c +@@ -245,6 +245,7 @@ static int surface_button_remove(struct acpi_device *device) + { + struct surface_button *button = acpi_driver_data(device); + ++ device_init_wakeup(&device->dev, false); + input_unregister_device(button->input); + kfree(button); + return 0; +-- +2.53.0 + diff --git a/queue-5.10/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch b/queue-5.10/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch new file mode 100644 index 0000000000..d1c91472ce --- /dev/null +++ b/queue-5.10/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch @@ -0,0 +1,60 @@ +From 5801b9ebbeec1c480219e67db869a4e5b0fe780f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:42:39 +0300 +Subject: platform/x86: dell_rbu: avoid uninit value usage in + packet_size_write() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fedor Pchelkin + +[ Upstream commit f8fd138c2363c0e2d3235c32bfb4fb5c6474e4ae ] + +Ensure the temp value has been properly parsed from the user-provided +buffer and initialized to be used in later operations. While at it, +prefer a convenient kstrtoul() helper. + +Found by Linux Verification Center (linuxtesting.org) with Svace static +analysis tool. + +Fixes: ad6ce87e5bd4 ("[PATCH] dell_rbu: changes in packet update mechanism") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260403134240.604837-1-pchelkin@ispras.ru +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/dell_rbu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/dell_rbu.c b/drivers/platform/x86/dell_rbu.c +index 68a860a97f319..39c6013cad342 100644 +--- a/drivers/platform/x86/dell_rbu.c ++++ b/drivers/platform/x86/dell_rbu.c +@@ -30,6 +30,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -617,9 +618,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, + char *buffer, loff_t pos, size_t count) + { + unsigned long temp; ++ ++ if (kstrtoul(buffer, 10, &temp)) ++ return -EINVAL; ++ + spin_lock(&rbu_data.lock); + packet_empty_list(); +- sscanf(buffer, "%lu", &temp); + if (temp < 0xffffffff) + rbu_data.packetsize = temp; + +-- +2.53.0 + diff --git a/queue-5.10/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch b/queue-5.10/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch new file mode 100644 index 0000000000..7ca401ec8e --- /dev/null +++ b/queue-5.10/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch @@ -0,0 +1,36 @@ +From a2d1295617739e86f61472a608f8221df86cf744 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 20:27:47 +0800 +Subject: pmdomain: ti: omap_prm: Fix a reference leak on device node + +From: Felix Gu + +[ Upstream commit 44c28e1c52764fef6dd1c1ada3a248728812e67f ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In omap_prm_domain_attach_dev, it does not release the reference. + +Fixes: 58cbff023bfa ("soc: ti: omap-prm: Add basic power domain support") +Signed-off-by: Felix Gu +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/soc/ti/omap_prm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c +index 2ce8a8f4f0052..240426aceca4e 100644 +--- a/drivers/soc/ti/omap_prm.c ++++ b/drivers/soc/ti/omap_prm.c +@@ -345,6 +345,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, + if (pd_args.args_count != 0) + dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", + prmd->pd.name, pd_args.args_count); ++ of_node_put(pd_args.np); + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; +-- +2.53.0 + diff --git a/queue-5.10/powerpc-crash-fix-backup-region-offset-update-to-elf.patch b/queue-5.10/powerpc-crash-fix-backup-region-offset-update-to-elf.patch new file mode 100644 index 0000000000..41591adc34 --- /dev/null +++ b/queue-5.10/powerpc-crash-fix-backup-region-offset-update-to-elf.patch @@ -0,0 +1,63 @@ +From 0978245d9ac6f90a669c51d37eb3393f449d5da7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:49 +0530 +Subject: powerpc/crash: fix backup region offset update to elfcorehdr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sourabh Jain + +[ Upstream commit 789335cacdf37da93bb7c70322dff8c7e82881df ] + +update_backup_region_phdr() in file_load_64.c iterates over all the +program headers in the kdump kernel’s elfcorehdr and updates the +p_offset of the program header whose physical address starts at 0. + +However, the loop logic is incorrect because the program header pointer +is not updated during iteration. Since elfcorehdr typically contains +PT_NOTE entries first, the PT_LOAD program header with physical address +0 is never reached. As a result, its p_offset is not updated to point to +the backup region. + +Because of this behavior, the capture kernel exports the first 64 KB of +the crashed kernel’s memory at offset 0, even though that memory +actually lives in the backup region. When a crash happens, purgatory +copies the first 64 KB of the crashed kernel’s memory into the backup +region so the capture kernel can safely use it. + +This has not caused problems so far because the first 64 KB is usually +identical in both the crashed and capture kernels. However, this is +just an assumption and is not guaranteed to always hold true. + +Fix update_backup_region_phdr() to correctly update the p_offset of the +program header with a starting physical address of 0 by correcting the +logic used to iterate over the program headers. + +Fixes: cb350c1f1f86 ("powerpc/kexec_file: Prepare elfcore header for crashing kernel") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Reviewed-by: Hari Bathini +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-2-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kexec/file_load_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index cb3fc0042cc25..9b4fdb47b9ba6 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -766,7 +766,7 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) + unsigned int i; + + phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++) { ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + if (phdr->p_paddr == BACKUP_SRC_START) { + phdr->p_offset = image->arch.backup_start; + pr_debug("Backup region offset updated to 0x%lx\n", +-- +2.53.0 + diff --git a/queue-5.10/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch b/queue-5.10/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch new file mode 100644 index 0000000000..70bd62ba0c --- /dev/null +++ b/queue-5.10/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch @@ -0,0 +1,50 @@ +From 3beedb7365a084aa90cfda618572226f445b85d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:11:15 +0900 +Subject: ppp: require CAP_NET_ADMIN in target netns for unattached ioctls + +From: Taegu Ha + +[ Upstream commit 2bb6379416fd19f44c3423a00bfd8626259f6067 ] + +/dev/ppp open is currently authorized against file->f_cred->user_ns, +while unattached administrative ioctls operate on current->nsproxy->net_ns. + +As a result, a local unprivileged user can create a new user namespace +with CLONE_NEWUSER, gain CAP_NET_ADMIN only in that new user namespace, +and still issue PPPIOCNEWUNIT, PPPIOCATTACH, or PPPIOCATTCHAN against +an inherited network namespace. + +Require CAP_NET_ADMIN in the user namespace that owns the target network +namespace before handling unattached PPP administrative ioctls. + +This preserves normal pppd operation in the network namespace it is +actually privileged in, while rejecting the userns-only inherited-netns +case. + +Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2") +Signed-off-by: Taegu Ha +Link: https://patch.msgid.link/20260409071117.4354-1-hataegu0826@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index b2b5a994dd0ee..a15b3eebb6d62 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -950,6 +950,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct ppp_net *pn; + int __user *p = (int __user *)arg; + ++ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ + switch (cmd) { + case PPPIOCNEWUNIT: + /* Create a new ppp unit */ +-- +2.53.0 + diff --git a/queue-5.10/pppoe-drop-pfc-frames.patch b/queue-5.10/pppoe-drop-pfc-frames.patch new file mode 100644 index 0000000000..9adce9043a --- /dev/null +++ b/queue-5.10/pppoe-drop-pfc-frames.patch @@ -0,0 +1,112 @@ +From 49e99e6d594d1ae0b3ba4bf1af7115bd95662c2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 10:24:51 +0800 +Subject: pppoe: drop PFC frames + +From: Qingfang Deng + +[ Upstream commit cc1ff87bce1ccd38410ab10960f576dcd17db679 ] + +RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT +RECOMMENDED for PPPoE. In practice, pppd does not support negotiating +PFC for PPPoE sessions, and the current PPPoE driver assumes an +uncompressed (2-byte) protocol field. However, the generic PPP layer +function ppp_input() is not aware of the negotiation result, and still +accepts PFC frames. + +If a peer with a broken implementation or an attacker sends a frame with +a compressed (1-byte) protocol field, the subsequent PPP payload is +shifted by one byte. This causes the network header to be 4-byte +misaligned, which may trigger unaligned access exceptions on some +architectures. + +To reduce the attack surface, drop PPPoE PFC frames. Introduce +ppp_skb_is_compressed_proto() helper function to be used in both +ppp_generic.c and pppoe.c to avoid open-coding. + +Fixes: 7fb1b8ca8fa1 ("ppp: Move PFC decompression to PPP generic layer") +Signed-off-by: Qingfang Deng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415022456.141758-2-qingfang.deng@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + drivers/net/ppp/pppoe.c | 8 +++++++- + include/linux/ppp_defs.h | 16 ++++++++++++++++ + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index a15b3eebb6d62..262d9be4f449e 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2108,7 +2108,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + */ + static void __ppp_decompress_proto(struct sk_buff *skb) + { +- if (skb->data[0] & 0x01) ++ if (ppp_skb_is_compressed_proto(skb)) + *(u8 *)skb_push(skb, 1) = 0x00; + } + +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index d7f50b835050d..75114c630b1a7 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -425,7 +425,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb_mac_header_len(skb) < ETH_HLEN) + goto drop; + +- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) ++ if (!pskb_may_pull(skb, PPPOE_SES_HLEN)) + goto drop; + + ph = pppoe_hdr(skb); +@@ -435,6 +435,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb->len < len) + goto drop; + ++ /* skb->data points to the PPP protocol header after skb_pull_rcsum. ++ * Drop PFC frames. ++ */ ++ if (ppp_skb_is_compressed_proto(skb)) ++ goto drop; ++ + if (pskb_trim_rcsum(skb, len)) + goto drop; + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index b7e57fdbd4139..b1d1f46d7d3be 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -8,6 +8,7 @@ + #define _PPP_DEFS_H_ + + #include ++#include + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) +@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) + return !!((proto & 0x0101) == 0x0001); + } + ++/** ++ * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed ++ * @skb: skb to check ++ * ++ * Check if the PPP protocol field is compressed (the least significant ++ * bit of the most significant octet is 1). skb->data must point to the PPP ++ * protocol header. ++ * ++ * Return: Whether the PPP protocol field is compressed. ++ */ ++static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb) ++{ ++ return unlikely(skb->data[0] & 0x01); ++} ++ + #endif /* _PPP_DEFS_H_ */ +-- +2.53.0 + diff --git a/queue-5.10/pstore-ram-fix-resource-leak-when-ioremap-fails.patch b/queue-5.10/pstore-ram-fix-resource-leak-when-ioremap-fails.patch new file mode 100644 index 0000000000..7cca777c28 --- /dev/null +++ b/queue-5.10/pstore-ram-fix-resource-leak-when-ioremap-fails.patch @@ -0,0 +1,52 @@ +From 9e84578ca9dc6896d72d046fe28fb315609c1263 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:54:06 -0700 +Subject: pstore/ram: fix resource leak when ioremap() fails + +From: Cole Leavitt + +[ Upstream commit 2ddb69f686ef7a621645e97fc7329c50edf5d0e5 ] + +In persistent_ram_iomap(), ioremap() or ioremap_wc() may return NULL on +failure. Currently, if this happens, the function returns NULL without +releasing the memory region acquired by request_mem_region(). + +This leads to a resource leak where the memory region remains reserved +but unusable. + +Additionally, the caller persistent_ram_buffer_map() handles NULL +correctly by returning -ENOMEM, but without this check, a NULL return +combined with request_mem_region() succeeding leaves resources in an +inconsistent state. + +This is the ioremap() counterpart to commit 05363abc7625 ("pstore: +ram_core: fix incorrect success return when vmap() fails") which fixed +a similar issue in the vmap() path. + +Fixes: 404a6043385d ("staging: android: persistent_ram: handle reserving and mapping memory") +Signed-off-by: Cole Leavitt +Link: https://patch.msgid.link/20260225235406.11790-1-cole@unwrap.rs +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index ccaa138a57b7c..80bf449a695a7 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -475,6 +475,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, + else + va = ioremap_wc(start, size); + ++ /* We must release the mem region if ioremap fails. */ ++ if (!va) ++ release_mem_region(start, size); ++ + /* + * Since request_mem_region() and ioremap() are byte-granularity + * there is no need handle anything special like we do when the +-- +2.53.0 + diff --git a/queue-5.10/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch b/queue-5.10/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch new file mode 100644 index 0000000000..d2b728c59f --- /dev/null +++ b/queue-5.10/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch @@ -0,0 +1,148 @@ +From 1101525c615a125d76856a41d541b4d994a80d4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 14:22:16 +0100 +Subject: quota: Fix race of dquot_scan_active() with quota deactivation + +From: Jan Kara + +[ Upstream commit e93ab401da4b2e2c1b8ef2424de2f238d51c8b2d ] + +dquot_scan_active() can race with quota deactivation in +quota_release_workfn() like: + + CPU0 (quota_release_workfn) CPU1 (dquot_scan_active) + ============================== ============================== + spin_lock(&dq_list_lock); + list_replace_init( + &releasing_dquots, &rls_head); + /* dquot X on rls_head, + dq_count == 0, + DQ_ACTIVE_B still set */ + spin_unlock(&dq_list_lock); + synchronize_srcu(&dquot_srcu); + spin_lock(&dq_list_lock); + list_for_each_entry(dquot, + &inuse_list, dq_inuse) { + /* finds dquot X */ + dquot_active(X) -> true + atomic_inc(&X->dq_count); + } + spin_unlock(&dq_list_lock); + spin_lock(&dq_list_lock); + dquot = list_first_entry(&rls_head); + WARN_ON_ONCE(atomic_read(&dquot->dq_count)); + +The problem is not only a cosmetic one as under memory pressure the +caller of dquot_scan_active() can end up working on freed dquot. + +Fix the problem by making sure the dquot is removed from releasing list +when we acquire a reference to it. + +Fixes: 869b6ea1609f ("quota: Fix slow quotaoff") +Reported-by: Sam Sun +Link: https://lore.kernel.org/all/CAEkJfYPTt3uP1vAYnQ5V2ZWn5O9PLhhGi5HbOcAzyP9vbXyjeg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/dquot.c | 38 ++++++++++++++++++++++++++++++-------- + include/linux/quotaops.h | 9 +-------- + 2 files changed, 31 insertions(+), 16 deletions(-) + +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 525ae0f11818c..b4326fc1d90fd 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -364,6 +364,31 @@ static inline int dquot_active(struct dquot *dquot) + return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); + } + ++static struct dquot *__dqgrab(struct dquot *dquot) ++{ ++ lockdep_assert_held(&dq_list_lock); ++ if (!atomic_read(&dquot->dq_count)) ++ remove_free_dquot(dquot); ++ atomic_inc(&dquot->dq_count); ++ return dquot; ++} ++ ++/* ++ * Get reference to dquot when we got pointer to it by some other means. The ++ * dquot has to be active and the caller has to make sure it cannot get ++ * deactivated under our hands. ++ */ ++struct dquot *dqgrab(struct dquot *dquot) ++{ ++ spin_lock(&dq_list_lock); ++ WARN_ON_ONCE(!dquot_active(dquot)); ++ dquot = __dqgrab(dquot); ++ spin_unlock(&dq_list_lock); ++ ++ return dquot; ++} ++EXPORT_SYMBOL_GPL(dqgrab); ++ + static inline int dquot_dirty(struct dquot *dquot) + { + return test_bit(DQ_MOD_B, &dquot->dq_flags); +@@ -642,15 +667,14 @@ int dquot_scan_active(struct super_block *sb, + continue; + if (dquot->dq_sb != sb) + continue; +- /* Now we have active dquot so we can just increase use count */ +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqput(old_dquot); + old_dquot = dquot; + /* + * ->release_dquot() can be racing with us. Our reference +- * protects us from new calls to it so just wait for any +- * outstanding call and recheck the DQ_ACTIVE_B after that. ++ * protects us from dquot_release() proceeding so just wait for ++ * any outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (dquot_active(dquot)) { +@@ -718,7 +742,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) + /* Now we have active dquot from which someone is + * holding reference so we can safely just increase + * use count */ +- dqgrab(dquot); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + err = dquot_write_dquot(dquot); + if (err && !ret) +@@ -973,9 +997,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_LOOKUPS); + } else { +- if (!atomic_read(&dquot->dq_count)) +- remove_free_dquot(dquot); +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_CACHE_HITS); + dqstats_inc(DQST_LOOKUPS); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 4bc8ff2a66143..8a1ad23da3a11 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -43,14 +43,7 @@ int dquot_initialize(struct inode *inode); + bool dquot_initialize_needed(struct inode *inode); + void dquot_drop(struct inode *inode); + struct dquot *dqget(struct super_block *sb, struct kqid qid); +-static inline struct dquot *dqgrab(struct dquot *dquot) +-{ +- /* Make sure someone else has active reference to dquot */ +- WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); +- WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); +- atomic_inc(&dquot->dq_count); +- return dquot; +-} ++struct dquot *dqgrab(struct dquot *dquot); + + static inline bool dquot_is_busy(struct dquot *dquot) + { +-- +2.53.0 + diff --git a/queue-5.10/rdma-core-prefer-nla_nul_string.patch b/queue-5.10/rdma-core-prefer-nla_nul_string.patch new file mode 100644 index 0000000000..7f6037b615 --- /dev/null +++ b/queue-5.10/rdma-core-prefer-nla_nul_string.patch @@ -0,0 +1,56 @@ +From 30af42abfae2500faeabdea7729910b522ed0d1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:27:39 +0200 +Subject: RDMA/core: Prefer NLA_NUL_STRING + +From: Florian Westphal + +[ Upstream commit 6ed3d14fc45d3da6025e7fe4a6a09066856698e2 ] + +These attributes are evaluated as c-string (passed to strcmp), but +NLA_STRING doesn't check for the presence of a \0 terminator. + +Either this needs to switch to nla_strcmp() and needs to adjust printf fmt +specifier to not use plain %s, or this needs to use NLA_NUL_STRING. + +As the code has been this way for long time, it seems to me that userspace +does include the terminating nul, even tough its not enforced so far, and +thus NLA_NUL_STRING use is the simpler solution. + +Fixes: 30dc5e63d6a5 ("RDMA/core: Add support for iWARP Port Mapper user space service") +Link: https://patch.msgid.link/r/20260330122742.13315-1-fw@strlen.de +Signed-off-by: Florian Westphal +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwpm_msg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c +index 46686990a8271..698ec2e730510 100644 +--- a/drivers/infiniband/core/iwpm_msg.c ++++ b/drivers/infiniband/core/iwpm_msg.c +@@ -381,9 +381,9 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) + /* netlink attribute policy for the received response to register pid request */ + static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { + [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, +- [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_DEVNAME_SIZE - 1 }, +- [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, + [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } +@@ -698,7 +698,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) + + /* netlink attribute policy for the received request for mapping info */ + static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { +- [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } + }; +-- +2.53.0 + diff --git a/queue-5.10/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch b/queue-5.10/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch new file mode 100644 index 0000000000..6d4d4add32 --- /dev/null +++ b/queue-5.10/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch @@ -0,0 +1,51 @@ +From 367f0a7d313a75636714c880265019fccde6e1fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 18:00:10 +0000 +Subject: rtc: abx80x: Disable alarm feature if no interrupt attached + +From: Anthony Pighin (Nokia) + +[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ] + +Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting +alarm") exposed an issue where the rtc-abx80x driver does not clear the +alarm feature bit, but instead relies on the set_alarm operation to return +invalid. + +For example, when a RTC_UIE_ON ioctl is handled, it should abort at the +feature validation. Instead, it proceeds to the rtc_timer_enqueue(), +which used to return an error from the set_alarm call. However, +following the race condition handling, which likely should not be +discarding predecing errors, a success condition is returned to the +ioctl() caller. This results in (for example): + hwclock: select() to /dev/rtc0 to wait for clock tick timed out + +Notwithstanding the validity of the race condition handling, if an interrupt +wasn't specified, or could not be attached, the driver should clear the +alarm feature bit. + +Fixes: 718a820a303c ("rtc: abx80x: add alarm support") +Signed-off-by: Anthony Pighin +Link: https://patch.msgid.link/BN0PR08MB69510928028C933749F4139383D1A@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-abx80x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c +index 034b314fb3ec9..8d15a68eedb81 100644 +--- a/drivers/rtc/rtc-abx80x.c ++++ b/drivers/rtc/rtc-abx80x.c +@@ -843,6 +843,8 @@ static int abx80x_probe(struct i2c_client *client, + client->irq = 0; + } + } ++ if (client->irq <= 0) ++ clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); + + err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); + if (err) { +-- +2.53.0 + diff --git a/queue-5.10/rtc-introduce-features-bitfield.patch b/queue-5.10/rtc-introduce-features-bitfield.patch new file mode 100644 index 0000000000..be04e2e9ae --- /dev/null +++ b/queue-5.10/rtc-introduce-features-bitfield.patch @@ -0,0 +1,142 @@ +From 0fd1e2888b0c3f7a9e48fbdc5a7e3fa3c1981c80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Jan 2021 00:17:36 +0100 +Subject: rtc: introduce features bitfield + +From: Alexandre Belloni + +[ Upstream commit 7ae41220ef5831674f446baef19bfe1b31358260 ] + +Introduce a bitfield to allow the drivers to announce the available +features for an RTC. + +The main use case would be to better handle alarms, that could be present +or not or have a minute resolution or may need a correct week day to be set. + +Use the newly introduced RTC_FEATURE_ALARM bit to then test whether alarms +are available instead of relying on the presence of ops->set_alarm. + +Signed-off-by: Alexandre Belloni +Link: https://lore.kernel.org/r/20210110231752.1418816-2-alexandre.belloni@bootlin.com +Stable-dep-of: 0fedce7244e4 ("rtc: abx80x: Disable alarm feature if no interrupt attached") +Signed-off-by: Sasha Levin +--- + drivers/rtc/class.c | 5 +++++ + drivers/rtc/interface.c | 12 ++++++------ + include/linux/rtc.h | 2 ++ + include/uapi/linux/rtc.h | 5 +++++ + 4 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c +index b1ce3bd724b2c..81aeb7a191b5f 100644 +--- a/drivers/rtc/class.c ++++ b/drivers/rtc/class.c +@@ -234,6 +234,8 @@ static struct rtc_device *rtc_allocate_device(void) + rtc->pie_timer.function = rtc_pie_update_irq; + rtc->pie_enabled = 0; + ++ set_bit(RTC_FEATURE_ALARM, rtc->features); ++ + return rtc; + } + +@@ -404,6 +406,9 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc) + return -EINVAL; + } + ++ if (!rtc->ops->set_alarm) ++ clear_bit(RTC_FEATURE_ALARM, rtc->features); ++ + rtc->owner = owner; + rtc_device_get_offset(rtc); + +diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c +index 7c9487050b25b..7df7457d7dc13 100644 +--- a/drivers/rtc/interface.c ++++ b/drivers/rtc/interface.c +@@ -186,7 +186,7 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, + + if (!rtc->ops) { + err = -ENODEV; +- } else if (!rtc->ops->read_alarm) { ++ } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) { + err = -EINVAL; + } else { + alarm->enabled = 0; +@@ -393,7 +393,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) + return err; + if (!rtc->ops) { + err = -ENODEV; +- } else if (!rtc->ops->read_alarm) { ++ } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) { + err = -EINVAL; + } else { + memset(alarm, 0, sizeof(struct rtc_wkalrm)); +@@ -437,7 +437,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) + + if (!rtc->ops) + err = -ENODEV; +- else if (!rtc->ops->set_alarm) ++ else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) + err = -EINVAL; + else + err = rtc->ops->set_alarm(rtc->dev.parent, alarm); +@@ -475,7 +475,7 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) + + if (!rtc->ops) + return -ENODEV; +- else if (!rtc->ops->set_alarm) ++ else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) + return -EINVAL; + + err = rtc_valid_tm(&alarm->time); +@@ -555,7 +555,7 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) + /* nothing */; + else if (!rtc->ops) + err = -ENODEV; +- else if (!rtc->ops->alarm_irq_enable) ++ else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->alarm_irq_enable) + err = -EINVAL; + else + err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled); +@@ -874,7 +874,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) + + static void rtc_alarm_disable(struct rtc_device *rtc) + { +- if (!rtc->ops || !rtc->ops->alarm_irq_enable) ++ if (!rtc->ops || !test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->alarm_irq_enable) + return; + + rtc->ops->alarm_irq_enable(rtc->dev.parent, false); +diff --git a/include/linux/rtc.h b/include/linux/rtc.h +index 22d1575e4991b..5037bda2f5b08 100644 +--- a/include/linux/rtc.h ++++ b/include/linux/rtc.h +@@ -124,6 +124,8 @@ struct rtc_device { + bool nvram_old_abi; + struct bin_attribute *nvram; + ++ unsigned long features[BITS_TO_LONGS(RTC_FEATURE_CNT)]; ++ + time64_t range_min; + timeu64_t range_max; + time64_t start_secs; +diff --git a/include/uapi/linux/rtc.h b/include/uapi/linux/rtc.h +index fa9aff91cbf27..f950bff75e97e 100644 +--- a/include/uapi/linux/rtc.h ++++ b/include/uapi/linux/rtc.h +@@ -110,6 +110,11 @@ struct rtc_pll_info { + #define RTC_AF 0x20 /* Alarm interrupt */ + #define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */ + ++/* feature list */ ++#define RTC_FEATURE_ALARM 0 ++#define RTC_FEATURE_ALARM_RES_MINUTE 1 ++#define RTC_FEATURE_NEED_WEEK_DAY 2 ++#define RTC_FEATURE_CNT 3 + + #define RTC_MAX_FREQ 8192 + +-- +2.53.0 + diff --git a/queue-5.10/sched-psi-fix-race-between-file-release-and-pressure.patch b/queue-5.10/sched-psi-fix-race-between-file-release-and-pressure.patch new file mode 100644 index 0000000000..4a19614978 --- /dev/null +++ b/queue-5.10/sched-psi-fix-race-between-file-release-and-pressure.patch @@ -0,0 +1,184 @@ +From 7d4ad7f0179cb62a21386caba08dae3cccbb31b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 14:15:43 +0800 +Subject: sched/psi: fix race between file release and pressure write + +From: Edward Adam Davis + +[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ] + +A potential race condition exists between pressure write and cgroup file +release regarding the priv member of struct kernfs_open_file, which +triggers the uaf reported in [1]. + +Consider the following scenario involving execution on two separate CPUs: + + CPU0 CPU1 + ==== ==== + vfs_rmdir() + kernfs_iop_rmdir() + cgroup_rmdir() + cgroup_kn_lock_live() + cgroup_destroy_locked() + cgroup_addrm_files() + cgroup_rm_file() + kernfs_remove_by_name() + kernfs_remove_by_name_ns() + vfs_write() __kernfs_remove() + new_sync_write() kernfs_drain() + kernfs_fop_write_iter() kernfs_drain_open_files() + cgroup_file_write() kernfs_release_file() + pressure_write() cgroup_file_release() + ctx = of->priv; + kfree(ctx); + of->priv = NULL; + cgroup_kn_unlock() + cgroup_kn_lock_live() + cgroup_get(cgrp) + cgroup_kn_unlock() + if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv + +The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards +the memory deallocation of of->priv performed within cgroup_file_release(). +However, the operations involving of->priv executed within pressure_write() +are not entirely covered by the protection of cgroup_mutex. Consequently, +if the code in pressure_write(), specifically the section handling the +ctx variable executes after cgroup_file_release() has completed, a uaf +vulnerability involving of->priv is triggered. + +Therefore, the issue can be resolved by extending the scope of the +cgroup_mutex lock within pressure_write() to encompass all code paths +involving of->priv, thereby properly synchronizing the race condition +occurring between cgroup_file_release() and pressure_write(). + +And, if an live kn lock can be successfully acquired while executing +the pressure write operation, it indicates that the cgroup deletion +process has not yet reached its final stage; consequently, the priv +pointer within open_file cannot be NULL. Therefore, the operation to +retrieve the ctx value must be moved to a point *after* the live kn +lock has been successfully acquired. + +In another situation, specifically after entering cgroup_kn_lock_live() +but before acquiring cgroup_mutex, there exists a different class of +race condition: + +CPU0: write memory.pressure CPU1: write cgroup.pressure=0 +=========================== ============================= + +kernfs_fop_write_iter() + kernfs_get_active_of(of) + pressure_write() + cgroup_kn_lock_live(memory.pressure) + cgroup_tryget(cgrp) + kernfs_break_active_protection(kn) + ... blocks on cgroup_mutex + + cgroup_pressure_write() + cgroup_kn_lock_live(cgroup.pressure) + cgroup_file_show(memory.pressure, false) + kernfs_show(false) + kernfs_drain_open_files() + cgroup_file_release(of) + kfree(ctx) + of->priv = NULL + cgroup_kn_unlock() + + ... acquires cgroup_mutex + ctx = of->priv; // may now be NULL + if (ctx->psi.trigger) // NULL dereference + +Consequently, there is a possibility that of->priv is NULL, the pressure +write needs to check for this. + +Now that the scope of the cgroup_mutex has been expanded, the original +explicit cgroup_get/put operations are no longer necessary, this is +because acquiring/releasing the live kn lock inherently executes a +cgroup get/put operation. + +[1] +BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 +Call Trace: + pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 + cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 + kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 + +Allocated by task 9352: + cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 + kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 + do_dentry_open+0x83d/0x13e0 fs/open.c:949 + +Freed by task 9353: + cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 + kernfs_release_file fs/kernfs/file.c:764 [inline] + kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 + kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525 + +Fixes: 0e94682b73bf ("psi: introduce psi monitor") +Reported-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=33e571025d88efd1312c +Tested-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Reviewed-by: Chen Ridong +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 8d420e00d89a7..42d6b76208d42 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -3679,33 +3679,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) + static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, enum psi_res res) + { +- struct cgroup_file_ctx *ctx = of->priv; ++ struct cgroup_file_ctx *ctx; + struct psi_trigger *new; + struct cgroup *cgrp; + struct psi_group *psi; ++ ssize_t ret = 0; + + cgrp = cgroup_kn_lock_live(of->kn, false); + if (!cgrp) + return -ENODEV; + +- cgroup_get(cgrp); +- cgroup_kn_unlock(of->kn); ++ ctx = of->priv; ++ if (!ctx) { ++ ret = -ENODEV; ++ goto out_unlock; ++ } + + /* Allow only one trigger per file descriptor */ + if (ctx->psi.trigger) { +- cgroup_put(cgrp); +- return -EBUSY; ++ ret = -EBUSY; ++ goto out_unlock; + } + + psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi; + new = psi_trigger_create(psi, buf, nbytes, res); + if (IS_ERR(new)) { +- cgroup_put(cgrp); +- return PTR_ERR(new); ++ ret = PTR_ERR(new); ++ goto out_unlock; + } + + smp_store_release(&ctx->psi.trigger, new); +- cgroup_put(cgrp); ++ ++out_unlock: ++ cgroup_kn_unlock(of->kn); ++ if (ret) ++ return ret; + + return nbytes; + } +-- +2.53.0 + diff --git a/queue-5.10/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch b/queue-5.10/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch new file mode 100644 index 0000000000..9baec86f62 --- /dev/null +++ b/queue-5.10/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch @@ -0,0 +1,100 @@ +From 80aa6cfe9805bb5c190de82fd2709c5035e0582d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:43 +0800 +Subject: scsi: sg: Resolve soft lockup issue when opening /dev/sgX + +From: Yang Erkun + +[ Upstream commit d06a310b45e153872033dd0cf19d5a2279121099 ] + +The parameter def_reserved_size defines the default buffer size reserved +for each Sg_fd and should be restricted to a range between 0 and 1,048,576 +(see https://tldp.org/HOWTO/SCSI-Generic-HOWTO/proc.html). Although the +function sg_proc_write_dressz enforces this limit, it is possible to bypass +it by directly modifying the module parameter as shown below, which then +causes a soft lockup: + +echo -1 > /sys/module/sg/parameters/def_reserved_size +exec 4<> /dev/sg0 + +watchdog: BUG: soft lockup - CPU#5 stuck for 26 seconds! [bash:537] +Modules loaded: +CPU: 5 UID: 0 PID: 537 Command: bash, kernel version 6.19.0-rc3+ #134, +PREEMPT disabled +Hardware: QEMU Standard PC (i440FX + PIIX, 1996), BIOS version +1.16.1-2.fc37 dated 04/01/2014 +... +Call Trace: + + sg_build_reserve+0x5c/0xa0 + sg_add_sfp+0x168/0x270 + sg_open+0x16e/0x340 + chrdev_open+0xbe/0x230 + do_dentry_open+0x175/0x480 + vfs_open+0x34/0xf0 + do_open+0x265/0x3d0 + path_openat+0x110/0x290 + do_filp_open+0xc3/0x170 + do_sys_openat2+0x71/0xe0 + __x64_sys_openat+0x6d/0xa0 + do_syscall_64+0x62/0x310 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The fix is to use module_param_cb to validate and reject invalid values +assigned to def_reserved_size. + +Fixes: 6460e75a104d ("[SCSI] sg: fixes for large page_size") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-3-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index b24e80a9c8cac..3c06c035b85c0 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1647,10 +1647,35 @@ sg_remove_device(struct device *cl_dev, struct class_interface *cl_intf) + } + + module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +-module_param_named(def_reserved_size, def_reserved_size, int, +- S_IRUGO | S_IWUSR); + module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); + ++static int def_reserved_size_set(const char *val, const struct kernel_param *kp) ++{ ++ int size, ret; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtoint(val, 0, &size); ++ if (ret) ++ return ret; ++ ++ /* limit to 1 MB */ ++ if (size < 0 || size > 1048576) ++ return -ERANGE; ++ ++ def_reserved_size = size; ++ return 0; ++} ++ ++static const struct kernel_param_ops def_reserved_size_ops = { ++ .set = def_reserved_size_set, ++ .get = param_get_int, ++}; ++ ++module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, ++ S_IRUGO | S_IWUSR); ++ + MODULE_AUTHOR("Douglas Gilbert"); + MODULE_DESCRIPTION("SCSI generic (sg) driver"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-5.10/scsi-sr-add-memory-allocation-failure-handling-for-g.patch b/queue-5.10/scsi-sr-add-memory-allocation-failure-handling-for-g.patch new file mode 100644 index 0000000000..9334e55721 --- /dev/null +++ b/queue-5.10/scsi-sr-add-memory-allocation-failure-handling-for-g.patch @@ -0,0 +1,88 @@ +From a948b15f6feecbc6d5dd0085e5516ef4d6f7adfd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Apr 2022 10:56:47 +0800 +Subject: scsi: sr: Add memory allocation failure handling for + get_capabilities() + +From: Enze Li + +[ Upstream commit ebc95c790653508ad7e031cfb9de5d0fa39135e2 ] + +The function get_capabilities() has the possibility of failing to allocate +the transfer buffer but it does not currently handle this. This may lead to +exceptions when accessing the buffer. + +Add error handling when memory allocation fails. + +Link: https://lore.kernel.org/r/20220427025647.298358-1-lienze@kylinos.cn +Signed-off-by: Enze Li +Signed-off-by: Martin K. Petersen +Stable-dep-of: 0898a817621a ("cdrom, scsi: sr: propagate read-only status to block layer via set_disk_ro()") +Signed-off-by: Sasha Levin +--- + drivers/scsi/sr.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index 464418413ced0..62a1bf81f7e47 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -115,7 +115,7 @@ static int sr_open(struct cdrom_device_info *, int); + static void sr_release(struct cdrom_device_info *); + + static void get_sectorsize(struct scsi_cd *); +-static void get_capabilities(struct scsi_cd *); ++static int get_capabilities(struct scsi_cd *); + + static unsigned int sr_check_events(struct cdrom_device_info *cdi, + unsigned int clearing, int slot); +@@ -773,8 +773,9 @@ static int sr_probe(struct device *dev) + + sdev->sector_size = 2048; /* A guess, just in case */ + +- /* FIXME: need to handle a get_capabilities failure properly ?? */ +- get_capabilities(cd); ++ error = -ENOMEM; ++ if (get_capabilities(cd)) ++ goto fail_minor; + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -895,7 +896,7 @@ static void get_sectorsize(struct scsi_cd *cd) + return; + } + +-static void get_capabilities(struct scsi_cd *cd) ++static int get_capabilities(struct scsi_cd *cd) + { + unsigned char *buffer; + struct scsi_mode_data data; +@@ -920,7 +921,7 @@ static void get_capabilities(struct scsi_cd *cd) + buffer = kmalloc(512, GFP_KERNEL); + if (!buffer) { + sr_printk(KERN_ERR, cd, "out of memory.\n"); +- return; ++ return -ENOMEM; + } + + /* eat unit attentions */ +@@ -940,7 +941,7 @@ static void get_capabilities(struct scsi_cd *cd) + CDC_MRW | CDC_MRW_W | CDC_RAM); + kfree(buffer); + sr_printk(KERN_INFO, cd, "scsi-1 drive"); +- return; ++ return 0; + } + + n = data.header_length + data.block_descriptor_length; +@@ -999,6 +1000,7 @@ static void get_capabilities(struct scsi_cd *cd) + } + + kfree(buffer); ++ return 0; + } + + /* +-- +2.53.0 + diff --git a/queue-5.10/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch b/queue-5.10/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch new file mode 100644 index 0000000000..bf327ba8f1 --- /dev/null +++ b/queue-5.10/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch @@ -0,0 +1,42 @@ +From cbdad9659988bfa892c1b754093b7712863e3b5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 23:42:58 +0800 +Subject: scsi: target: core: Fix integer overflow in UNMAP bounds check + +From: Junrui Luo + +[ Upstream commit 2bf2d65f76697820dbc4227d13866293576dd90a ] + +sbc_execute_unmap() checks LBA + range does not exceed the device capacity, +but does not guard against LBA + range wrapping around on 64-bit overflow. + +Add an overflow check matching the pattern already used for WRITE_SAME in +the same file. + +Fixes: 86d7182985d2 ("target: Add sbc_execute_unmap() helper") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881593C61AD52C69FBDB0BDAF7CA@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/target/target_core_sbc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c +index f2809c44988b5..c997943efe777 100644 +--- a/drivers/target/target_core_sbc.c ++++ b/drivers/target/target_core_sbc.c +@@ -1201,7 +1201,8 @@ sbc_execute_unmap(struct se_cmd *cmd) + goto err; + } + +- if (lba + range > dev->transport->get_blocks(dev) + 1) { ++ if (lba + range < lba || ++ lba + range > dev->transport->get_blocks(dev) + 1) { + ret = TCM_ADDRESS_OUT_OF_RANGE; + goto err; + } +-- +2.53.0 + diff --git a/queue-5.10/sctp-discard-stale-init-after-handshake-completion.patch b/queue-5.10/sctp-discard-stale-init-after-handshake-completion.patch new file mode 100644 index 0000000000..aad5828a79 --- /dev/null +++ b/queue-5.10/sctp-discard-stale-init-after-handshake-completion.patch @@ -0,0 +1,49 @@ +From 9efdef4541b917eb618fdf658b31fbf033dbb4a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:41 -0400 +Subject: sctp: discard stale INIT after handshake completion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Xin Long + +[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ] + +After an association reaches ESTABLISHED, the peer’s init_tag is already +known from the handshake. Any subsequent INIT with the same init_tag is +not a valid restart, but a delayed or duplicate INIT. + +Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of +processing them as new association attempts. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/5788c76c1ee122a3ed00189e88dcf9df1fba226c.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index c91f712ce1fab..af75b94085568 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -1508,6 +1508,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( + /* Tag the variable length parameters. */ + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); + ++ if (asoc->state >= SCTP_STATE_ESTABLISHED) { ++ /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ ++ if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) ++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ } ++ + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, +-- +2.53.0 + diff --git a/queue-5.10/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch b/queue-5.10/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch new file mode 100644 index 0000000000..bbae9c9d7d --- /dev/null +++ b/queue-5.10/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch @@ -0,0 +1,68 @@ +From 6c23f1e5c9046d30ea03c2365fdf5e2beb8b4d2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 23:19:03 -0400 +Subject: sctp: fix OOB write to userspace in sctp_getsockopt_peer_auth_chunks + +From: Michael Bommarito + +[ Upstream commit 0cf004ffb61cd32d140531c3a84afe975f9fc7ea ] + +sctp_getsockopt_peer_auth_chunks() checks that the caller's optval +buffer is large enough for the peer AUTH chunk list with + + if (len < num_chunks) + return -EINVAL; + +but then writes num_chunks bytes to p->gauth_chunks, which lives +at offset offsetof(struct sctp_authchunks, gauth_chunks) == 8 +inside optval. The check is missing the sizeof(struct +sctp_authchunks) = 8-byte header. When the caller supplies +len == num_chunks (for any num_chunks > 0) the test passes but +copy_to_user() writes sizeof(struct sctp_authchunks) = 8 bytes +past the declared buffer. + +The sibling function sctp_getsockopt_local_auth_chunks() at the +next line already has the correct check: + + if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + +Align the peer variant with its sibling. + +Reproducer confirms on v7.0-13-generic: an unprivileged userspace +caller that opens a loopback SCTP association with AUTH enabled, +queries num_chunks with a short optval, then issues the real +getsockopt with len == num_chunks and sentinel bytes painted past +the buffer observes those sentinel bytes overwritten with the +peer's AUTH chunk type. The bytes written are under the peer's +control but land in the caller's own userspace; this is not a +kernel memory corruption, but it is a kernel-side contract +violation that can silently corrupt adjacent userspace data. + +Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260416031903.1447072-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index e0f608eb46902..8c7bdf01e32a1 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -6880,7 +6880,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, + + /* See if the user provided enough room for all the data */ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); +- if (len < num_chunks) ++ if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + + if (copy_to_user(to, ch->chunks, num_chunks)) +-- +2.53.0 + diff --git a/queue-5.10/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch b/queue-5.10/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch new file mode 100644 index 0000000000..f707f6cbce --- /dev/null +++ b/queue-5.10/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch @@ -0,0 +1,75 @@ +From 05d4d4f574737dc6004bd605132c36c833be221a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 16:05:26 -0400 +Subject: selftest: memcg: skip memcg_sock test if address family not supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Waiman Long + +[ Upstream commit 2d028f3e4bbbfd448928a8d3d2814b0b04c214f4 ] + +The test_memcg_sock test in memcontrol.c sets up an IPv6 socket and send +data over it to consume memory and verify that memory.stat.sock and +memory.current values are close. + +On systems where IPv6 isn't enabled or not configured to support +SOCK_STREAM, the test_memcg_sock test always fails. When the socket() +call fails, there is no way we can test the memory consumption and verify +the above claim. I believe it is better to just skip the test in this +case instead of reporting a test failure hinting that there may be +something wrong with the memcg code. + +Link: https://lkml.kernel.org/r/20260311200526.885899-1-longman@redhat.com +Fixes: 5f8f019380b8 ("selftests: cgroup/memcontrol: add basic test for socket accounting") +Signed-off-by: Waiman Long +Acked-by: Michal Koutný +Acked-by: Shakeel Butt +Cc: Johannes Weiner +Cc: Michal Hocko +Cc: Michal Koutný +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Roman Gushchin +Cc: Shuah Khan +Cc: Tejun Heo +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/cgroup/test_memcontrol.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c +index c19a97dd02d49..07ce722b2533b 100644 +--- a/tools/testing/selftests/cgroup/test_memcontrol.c ++++ b/tools/testing/selftests/cgroup/test_memcontrol.c +@@ -833,8 +833,11 @@ static int tcp_server(const char *cgroup, void *arg) + saddr.sin6_port = htons(srv_args->port); + + sk = socket(AF_INET6, SOCK_STREAM, 0); +- if (sk < 0) ++ if (sk < 0) { ++ /* Pass back errno to the ctl_fd */ ++ write(ctl_fd, &errno, sizeof(errno)); + return ret; ++ } + + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + goto cleanup; +@@ -964,6 +967,12 @@ static int test_memcg_sock(const char *root) + goto cleanup; + close(args.ctl[0]); + ++ /* Skip if address family not supported by protocol */ ++ if (err == EAFNOSUPPORT) { ++ ret = KSFT_SKIP; ++ goto cleanup; ++ } ++ + if (!err) + break; + if (err != EADDRINUSE) +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index a5227af5d4..18e3eb742b 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -293,3 +293,213 @@ bluetooth-l2cap-fix-null-ptr-deref-in-l2cap_sock_get_sndtimeo_cb.patch vsock-fix-buffer-size-clamping-order.patch vsock-virtio-fix-accept-queue-count-leak-on-transport-mismatch.patch bcache-fix-uninitialized-closure-object.patch +fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch +drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch +nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch +pstore-ram-fix-resource-leak-when-ioremap-fails.patch +devres-fix-missing-node-debug-info-in-devm_krealloc.patch +thermal-drivers-spear-fix-error-condition-for-readin.patch +irqchip-irq-pic32-evic-address-warning-related-to-wr.patch +locking-fix-rwlock-support-in-linux-spinlock_up.h.patch +firmware-dmi-correct-an-indexing-error-in-dmi.h.patch +wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch +wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch +powerpc-crash-fix-backup-region-offset-update-to-elf.patch +bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch +brcmfmac-support-chipsets-with-different-core-enumer.patch +wifi-brcmfmac-fix-error-pointer-dereference.patch +net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch +netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch +6pack-propagage-new-tty-types.patch +net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch +net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch +net-rds-optimize-rds_ib_laddr_check.patch +net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch +ppp-require-cap_net_admin-in-target-netns-for-unatta.patch +bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch +bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch +bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch +bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch +bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch +drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch +drm-sun4i-backend-fix-error-pointer-dereference.patch +asoc-sti-return-errors-from-regmap_field_alloc.patch +asoc-sti-use-managed-regmap_field-allocations.patch +dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch +dm-cache-fix-write-path-cache-coherency-in-passthrou.patch +dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch +dm-cache-fix-concurrent-write-failure-in-passthrough.patch +dm-cache-support-shrinking-the-origin-device.patch +dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch +dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch +dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch +spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch +drm-sun4i-fix-resource-leaks.patch +fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch +drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch +drm-panel-simple-correct-g190ean01-prepare-timing.patch +alsa-compress-drop-unused-functions.patch +alsa-core-validate-compress-device-numbers-without-d.patch +drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch +drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch +drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch +drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch +drm-amd-pm-ci-fill-dw8-fields-from-smc.patch +alsa-hda-realtek-whitespace-fix.patch +alsa-hda-realtek-fix-code-style-error-else-should-fo.patch +drm-msm-a6xx-fix-hlsq-register-dumping.patch +drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch +pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch +asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch +asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch +asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch +pci-enable-atomicops-only-if-root-port-supports-them.patch +documentation-fix-a-hugetlbfs-reservation-statement.patch +selftest-memcg-skip-memcg_sock-test-if-address-famil.patch +pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch +pci-tegra194-disable-direct-speed-change-for-endpoin.patch +ktest-avoid-undef-warning-when-warnings_file-is-unse.patch +ktest-honor-empty-per-test-option-overrides.patch +ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch +quota-fix-race-of-dquot_scan_active-with-quota-deact.patch +efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch +arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch +memory-tegra124-emc-fix-dll_change-check.patch +memory-tegra30-emc-fix-dll_change-check.patch +soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch +arm64-dts-qcom-sdm845-xiaomi-beryllium-add-dsi-and-p.patch +arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch +ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch +ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch +soc-qcom-aoss-compare-against-normalized-cooling-sta.patch +ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch +ocfs2-validate-bg_bits-during-freefrag-scan.patch +ocfs2-validate-group-add-input-before-caching.patch +dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch +tracing-rebuild-full_name-on-each-hist_field_name-ca.patch +ima-check-return-value-of-crypto_shash_final-in-boot.patch +hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch +hid-asus-do-not-abort-probe-when-not-necessary.patch +mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch +mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch +hid-usbhid-fix-deadlock-in-hid_post_reset.patch +bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch +bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch +pinctrl-pinctrl-pic32-fix-resource-leak.patch +perf-branch-avoid-incrementing-null.patch +pinctrl-abx500-fix-type-of-argument-variable.patch +perf-tools-fix-module-symbol-resolution-for-non-zero.patch +perf-expr-return-einval-for-syntax-error-in-expr__fi.patch +perf-util-kill-die-prototype-dead-for-a-long-time.patch +i3c-master-fix-error-codes-at-send_ccc_cmd.patch +driver-core-device.h-remove-extern-from-function-pro.patch +driver-core-move-dev_err_probe-to-where-it-belogs.patch +dev_printk-add-new-dev_err_probe-helpers.patch +backlight-sky81452-backlight-check-return-value-of-d.patch +platform-surface-surfacepro3_button-drop-wakeup-sour.patch +tty-hvc-remove-hvc_iucv_magic.patch +tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch +mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch +nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch +platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch +rdma-core-prefer-nla_nul_string.patch +scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch +scsi-target-core-fix-integer-overflow-in-unmap-bound.patch +clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch +clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch +clk-imx8mq-correct-the-csi-phy-sels.patch +clk-qoriq-avoid-format-string-warning.patch +clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch +dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch +clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch +lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch +crypto-sa2ul-fix-aead-fallback-algorithm-names.patch +crypto-ccp-copy-iv-using-skcipher-ivsize.patch +pcmcia-fix-garbled-log-messages-for-kern_cont.patch +net-sched-sch_cake-fix-nat-destination-port-not-bein.patch +nexthop-emit-a-notification-when-a-nexthop-group-is-.patch +nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch +taprio-handle-short-intervals-and-large-packets.patch +net-taprio-offload-enforce-qdisc-to-netdev-queue-map.patch +net-sched-taprio-stop-going-through-private-ops-for-.patch +net-sched-taprio-replace-safety-precautions-with-com.patch +net-sched-taprio-continue-with-other-txqs-if-one-deq.patch +net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch +net-sched-taprio-rename-close_time-to-end_time.patch +net-sched-taprio-fix-use-after-free-in-advance_sched.patch +tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch +i40e-don-t-advertise-iff_supp_nofcs.patch +e1000e-unroll-ptp-in-probe-error-handling.patch +ipv6-fix-possible-uaf-in-icmpv6_rcv.patch +sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch +dissector-do-not-set-invalid-ppp-protocol.patch +flow_dissector-add-number-of-vlan-tags-dissector.patch +flow_dissector-add-pppoe-dissectors.patch +pppoe-drop-pfc-frames.patch +openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch +netfilter-nft_osf-restrict-it-to-ipv4.patch +netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch +netfilter-conntrack-remove-sprintf-usage.patch +netfilter-xtables-restrict-several-matches-to-inet-f.patch +ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch +netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch +netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch +slip-reject-vj-receive-packets-on-instances-with-no-.patch +slip-bound-decode-reads-against-the-compressed-packe.patch +arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch +net-rds-zero-per-item-info-buffer-before-handing-it-.patch +net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch +net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch +net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch +net-sched-gred-red-remove-unused-variables-in-struct.patch +net-sched-sch_red-annotate-data-races-in-red_dump_st.patch +net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch +nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch +tipc-fix-double-free-in-tipc_buf_append.patch +vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch +fs-adfs-validate-nzones-in-adfs_validate_bblk.patch +rtc-introduce-features-bitfield.patch +rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch +fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch +mailbox-mailbox-test-free-channels-on-probe-error.patch +sched-psi-fix-race-between-file-release-and-pressure.patch +cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch +mailbox-add-sanity-check-for-channel-array.patch +mailbox-mailbox-test-don-t-free-the-reused-channel.patch +mailbox-mailbox-test-initialize-struct-earlier.patch +mailbox-mailbox-test-make-data_ready-a-per-instance-.patch +btrfs-merge-page_clear_dirty-and-page_set_writeback-.patch +btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch +tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch +netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch +drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch +netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch +netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch +scsi-sr-add-memory-allocation-failure-handling-for-g.patch +cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch +netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch +net-sched-sch_netem-refactor-code-in-4-state-loss-ge.patch +net-sched-netem-fix-probability-gaps-in-4-state-loss.patch +net-sched-netem-fix-queue-limit-check-to-include-reo.patch +net-sched-netem-validate-slot-configuration.patch +net-sched-choke-remove-unused-variables-in-struct-ch.patch +net-sched-sch_choke-annotate-data-races-in-choke_dum.patch +net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch +vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch +net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch +net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch +nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch +net-phy-dp83869-fix-setting-clk_o_sel-field.patch +asoc-codecs-ab8500-fix-casting-of-private-data.patch +netfilter-skip-recording-stale-or-retransmitted-init.patch +sctp-discard-stale-init-after-handshake-completion.patch +ipv4-rename-and-move-ip_route_output_tunnel.patch +ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch +ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch +ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch +bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch +drm-amd-display-allow-dce-link-encoder-without-aux-r.patch +drm-amd-display-read-edid-from-vbios-embedded-panel-.patch diff --git a/queue-5.10/slip-bound-decode-reads-against-the-compressed-packe.patch b/queue-5.10/slip-bound-decode-reads-against-the-compressed-packe.patch new file mode 100644 index 0000000000..affe7d1de9 --- /dev/null +++ b/queue-5.10/slip-bound-decode-reads-against-the-compressed-packe.patch @@ -0,0 +1,158 @@ +From a65e68561a0a78133b8f4dbe0310c2b1fed1560c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:01:51 +0800 +Subject: slip: bound decode() reads against the compressed packet length + +From: Weiming Shi + +[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ] + +slhc_uncompress() parses a VJ-compressed TCP header by advancing a +pointer through the packet via decode() and pull16(). Neither helper +bounds-checks against isize, and decode() masks its return with +& 0xffff so it can never return the -1 that callers test for -- those +error paths are dead code. + +A short compressed frame whose change byte requests optional fields +lets decode() read past the end of the packet. The over-read bytes +are folded into the cached cstate and reflected into subsequent +reconstructed packets. + +Make decode() and pull16() take the packet end pointer and return -1 +when exhausted. Add a bounds check before the TCP-checksum read. +The existing == -1 tests now do what they were always meant to. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Simon Horman +Closes: https://lore.kernel.org/netdev/20260414134126.758795-2-horms@kernel.org/ +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416100147.531855-5-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index f7d92bae7774d..e56f0bbc72a4f 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -80,9 +80,9 @@ + #include + + static unsigned char *encode(unsigned char *cp, unsigned short n); +-static long decode(unsigned char **cpp); ++static long decode(unsigned char **cpp, const unsigned char *end); + static unsigned char * put16(unsigned char *cp, unsigned short x); +-static unsigned short pull16(unsigned char **cpp); ++static long pull16(unsigned char **cpp, const unsigned char *end); + + /* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) +@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n) + return cp; + } + +-/* Pull a 16-bit integer in host order from buffer in network byte order */ +-static unsigned short +-pull16(unsigned char **cpp) ++/* Pull a 16-bit integer in host order from buffer in network byte order. ++ * Returns -1 if the buffer is exhausted, otherwise the 16-bit value. ++ */ ++static long ++pull16(unsigned char **cpp, const unsigned char *end) + { +- short rval; ++ long rval; + ++ if (*cpp + 2 > end) ++ return -1; + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; + } + +-/* Decode a number */ ++/* Decode a number. Returns -1 if the buffer is exhausted. */ + static long +-decode(unsigned char **cpp) ++decode(unsigned char **cpp, const unsigned char *end) + { + int x; + ++ if (*cpp >= end) ++ return -1; + x = *(*cpp)++; +- if(x == 0){ +- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ +- } else { +- return x & 0xff; /* -1 if PULLCHAR returned error */ +- } ++ if (x == 0) ++ return pull16(cpp, end); ++ return x & 0xff; + } + + /* +@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; ++ const unsigned char *end = icp + isize; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; +@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + ++ if (cp + 2 > end) ++ goto bad; + thp->check = *(__sum16 *)cp; + cp += 2; + +@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + default: + if(changes & NEW_U){ + thp->urg = 1; +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); +@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + break; + } + if(changes & NEW_I){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); +-- +2.53.0 + diff --git a/queue-5.10/slip-reject-vj-receive-packets-on-instances-with-no-.patch b/queue-5.10/slip-reject-vj-receive-packets-on-instances-with-no-.patch new file mode 100644 index 0000000000..0f4d3ea45d --- /dev/null +++ b/queue-5.10/slip-reject-vj-receive-packets-on-instances-with-no-.patch @@ -0,0 +1,98 @@ +From a187954b5df294dfaea1420d483515ead510ffea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 04:41:31 +0800 +Subject: slip: reject VJ receive packets on instances with no rstate array + +From: Weiming Shi + +[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ] + +slhc_init() accepts rslots == 0 as a valid configuration, with the +documented meaning of 'no receive compression'. In that case the +allocation loop in slhc_init() is skipped, so comp->rstate stays +NULL and comp->rslot_limit stays 0 (from the kzalloc of struct +slcompress). + +The receive helpers do not defend against that configuration. +slhc_uncompress() dereferences comp->rstate[x] when the VJ header +carries an explicit connection ID, and slhc_remember() later assigns +cs = &comp->rstate[...] after only comparing the packet's slot number +to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the +range check, and the code dereferences a NULL rstate. + +The configuration is reachable in-tree through PPP. PPPIOCSMAXCID +stores its argument in a signed int, and (val >> 16) uses arithmetic +shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 +is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because +/dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path +is reachable from an unprivileged user namespace. Once the malformed +VJ state is installed, any inbound VJ-compressed or VJ-uncompressed +frame that selects slot 0 crashes the kernel in softirq context: + + Oops: general protection fault, probably for non-canonical + address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519) + Call Trace: + + ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466) + ppp_input (drivers/net/ppp/ppp_generic.c:2359) + ppp_async_process (drivers/net/ppp/ppp_async.c:492) + tasklet_action_common (kernel/softirq.c:926) + handle_softirqs (kernel/softirq.c:623) + run_ksoftirqd (kernel/softirq.c:1055) + smpboot_thread_fn (kernel/smpboot.c:160) + kthread (kernel/kthread.c:436) + ret_from_fork (arch/x86/kernel/process.c:164) + + +Reject the receive side on such instances instead of touching rstate. +slhc_uncompress() falls through to its existing 'bad' label, which +bumps sls_i_error and enters the toss state. slhc_remember() mirrors +that with an explicit sls_i_error increment followed by slhc_toss(); +the sls_i_runt counter is not used here because a missing rstate is +an internal configuration state, not a runt packet. + +The transmit path is unaffected: the only in-tree caller that picks +rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and +slip.c always calls slhc_init(16, 16), so comp->tstate remains valid +and slhc_compress() continues to work. + +Fixes: 4ab42d78e37a ("ppp, slip: Validate VJ compression slot parameters completely") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415204130.258866-2-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index 603a29f3905ba..f7d92bae7774d 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + comp->sls_i_error++; + return 0; + } ++ if (!comp->rstate) ++ goto bad; + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. +@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + unsigned int ihl; + ++ if (!comp->rstate) { ++ comp->sls_i_error++; ++ return slhc_toss(comp); ++ } + /* The packet is shorter than a legal IP header. + * Also make sure isize is positive. + */ +-- +2.53.0 + diff --git a/queue-5.10/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch b/queue-5.10/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch new file mode 100644 index 0000000000..a8f5cc2438 --- /dev/null +++ b/queue-5.10/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch @@ -0,0 +1,41 @@ +From 13545dc991b5f2bd3eedfffbc871299f84d536e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 12:53:23 -0700 +Subject: soc: qcom: aoss: compare against normalized cooling state + +From: Alok Tiwari + +[ Upstream commit cd3c4670db3ffe997be9548c7a9db3952563cf14 ] + +qmp_cdev_set_cur_state() normalizes the requested state to a boolean +(cdev_state = !!state). The existing early-return check compares +qmp_cdev->state == state, which can be wrong if state is non-boolean +(any non-zero value). Compare qmp_cdev->state against cdev_state instead, +so the check matches the effective state and avoids redundant updates. + +Signed-off-by: Alok Tiwari +Fixes: 05589b30b21a ("soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260329195333.1478090-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/qcom_aoss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c +index 401a0be3675af..6e00a82742a14 100644 +--- a/drivers/soc/qcom/qcom_aoss.c ++++ b/drivers/soc/qcom/qcom_aoss.c +@@ -430,7 +430,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, + /* Normalize state */ + cdev_state = !!state; + +- if (qmp_cdev->state == state) ++ if (qmp_cdev->state == cdev_state) + return 0; + + snprintf(buf, sizeof(buf), +-- +2.53.0 + diff --git a/queue-5.10/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch b/queue-5.10/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch new file mode 100644 index 0000000000..dcdc7717a8 --- /dev/null +++ b/queue-5.10/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch @@ -0,0 +1,46 @@ +From 900f14f30e6af059269f680685525b7c52b4bf68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:59 +0200 +Subject: soc: qcom: ocmem: return -EPROBE_DEFER is ocmem is not available + +From: Dmitry Baryshkov + +[ Upstream commit 91b59009c7d48b58dbc50fecb27f2ad20749a05a ] + +If OCMEM is declared in DT, it is expected that it is present and +handled by the driver. The GPU driver will ignore -ENODEV error, which +typically means that OCMEM isn't defined in DT. Let ocmem return +-EPROBE_DEFER if it supposed to be used, but it is not probed (yet). + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-3-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index bfebdcaf88146..620f171bf0658 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -212,10 +212,9 @@ struct ocmem *of_get_ocmem(struct device *dev) + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +- if (!ocmem) { +- dev_err(dev, "Cannot get ocmem\n"); +- return ERR_PTR(-ENODEV); +- } ++ if (!ocmem) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n"); ++ + return ocmem; + } + EXPORT_SYMBOL(of_get_ocmem); +-- +2.53.0 + diff --git a/queue-5.10/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch b/queue-5.10/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..3d1d3fd52d --- /dev/null +++ b/queue-5.10/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 49c9aa93c649b9edeed2c740575e91da14382910 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:21 +0800 +Subject: spi: fsl-qspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 981b080a79724738882b0af1c5bb7ade30d94f24 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks could +get "lost" - use reinit_completion() in that case, but be aware of +other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: 84d043185dbe ("spi: Add a driver for the Freescale/NXP QuadSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-3-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-fsl-qspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c +index 46ae46a944c5c..2ff26027aafd2 100644 +--- a/drivers/spi/spi-fsl-qspi.c ++++ b/drivers/spi/spi-fsl-qspi.c +@@ -607,7 +607,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) + void __iomem *base = q->iobase; + int err = 0; + +- init_completion(&q->c); ++ reinit_completion(&q->c); + + /* + * Always start the sequence at the same index since we update +@@ -913,6 +913,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) + if (ret < 0) + goto err_disable_clk; + ++ init_completion(&q->c); + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { +-- +2.53.0 + diff --git a/queue-5.10/taprio-handle-short-intervals-and-large-packets.patch b/queue-5.10/taprio-handle-short-intervals-and-large-packets.patch new file mode 100644 index 0000000000..063352e1a5 --- /dev/null +++ b/queue-5.10/taprio-handle-short-intervals-and-large-packets.patch @@ -0,0 +1,151 @@ +From 527aa0f9663eccb3275d32743716dfa217528766 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Mar 2021 08:34:55 +0100 +Subject: taprio: Handle short intervals and large packets + +From: Kurt Kanzenbach + +[ Upstream commit 497cc00224cfaff89282ec8bfdfb8b797415f72a ] + +When using short intervals e.g. below one millisecond, large packets won't be +transmitted at all. The software implementations checks whether the packet can +be fit into the remaining interval. Therefore, it takes the packet length and +the transmission speed into account. That is correct. + +However, for large packets it may be that the transmission time exceeds the +interval resulting in no packet transmission. The same situation works fine with +hardware offloading applied. + +The problem has been observed with the following schedule and iperf3: + +|tc qdisc replace dev lan1 parent root handle 100 taprio \ +| num_tc 8 \ +| map 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 \ +| queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ +| base-time $base \ +| sched-entry S 0x40 500000 \ +| sched-entry S 0xbf 500000 \ +| clockid CLOCK_TAI \ +| flags 0x00 + +[...] + +|root@tsn:~# iperf3 -c 192.168.2.105 +|Connecting to host 192.168.2.105, port 5201 +|[ 5] local 192.168.2.121 port 52610 connected to 192.168.2.105 port 5201 +|[ ID] Interval Transfer Bitrate Retr Cwnd +|[ 5] 0.00-1.00 sec 45.2 KBytes 370 Kbits/sec 0 1.41 KBytes +|[ 5] 1.00-2.00 sec 0.00 Bytes 0.00 bits/sec 0 1.41 KBytes + +After debugging, it seems that the packet length stored in the SKB is about +7000-8000 bytes. Using a 100 Mbit/s link the transmission time is about 600us +which larger than the interval of 500us. + +Therefore, segment the SKB into smaller chunks if the packet is too big. This +yields similar results than the hardware offload: + +|root@tsn:~# iperf3 -c 192.168.2.105 +|Connecting to host 192.168.2.105, port 5201 +|- - - - - - - - - - - - - - - - - - - - - - - - - +|[ ID] Interval Transfer Bitrate Retr +|[ 5] 0.00-10.00 sec 48.9 MBytes 41.0 Mbits/sec 0 sender +|[ 5] 0.00-10.02 sec 48.7 MBytes 40.7 Mbits/sec receiver + +Furthermore, the segmentation can be skipped for the full offload case, as the +driver or the hardware is expected to handle this. + +Signed-off-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 64 +++++++++++++++++++++++++++++++++++------- + 1 file changed, 54 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 16ab7b1480661..66348b1083ed5 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -415,18 +415,10 @@ static long get_packet_txtime(struct sk_buff *skb, struct Qdisc *sch) + return txtime; + } + +-static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, +- struct sk_buff **to_free) ++static int taprio_enqueue_one(struct sk_buff *skb, struct Qdisc *sch, ++ struct Qdisc *child, struct sk_buff **to_free) + { + struct taprio_sched *q = qdisc_priv(sch); +- struct Qdisc *child; +- int queue; +- +- queue = skb_get_queue_mapping(skb); +- +- child = q->qdiscs[queue]; +- if (unlikely(!child)) +- return qdisc_drop(skb, sch, to_free); + + /* sk_flags are only safe to use on full sockets. */ + if (skb->sk && sk_fullsock(skb->sk) && sock_flag(skb->sk, SOCK_TXTIME)) { +@@ -444,6 +436,58 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return qdisc_enqueue(skb, child, to_free); + } + ++static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, ++ struct sk_buff **to_free) ++{ ++ struct taprio_sched *q = qdisc_priv(sch); ++ struct Qdisc *child; ++ int queue; ++ ++ queue = skb_get_queue_mapping(skb); ++ ++ child = q->qdiscs[queue]; ++ if (unlikely(!child)) ++ return qdisc_drop(skb, sch, to_free); ++ ++ /* Large packets might not be transmitted when the transmission duration ++ * exceeds any configured interval. Therefore, segment the skb into ++ * smaller chunks. Skip it for the full offload case, as the driver ++ * and/or the hardware is expected to handle this. ++ */ ++ if (skb_is_gso(skb) && !FULL_OFFLOAD_IS_ENABLED(q->flags)) { ++ unsigned int slen = 0, numsegs = 0, len = qdisc_pkt_len(skb); ++ netdev_features_t features = netif_skb_features(skb); ++ struct sk_buff *segs, *nskb; ++ int ret; ++ ++ segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); ++ if (IS_ERR_OR_NULL(segs)) ++ return qdisc_drop(skb, sch, to_free); ++ ++ skb_list_walk_safe(segs, segs, nskb) { ++ skb_mark_not_on_list(segs); ++ qdisc_skb_cb(segs)->pkt_len = segs->len; ++ slen += segs->len; ++ ++ ret = taprio_enqueue_one(segs, sch, child, to_free); ++ if (ret != NET_XMIT_SUCCESS) { ++ if (net_xmit_drop_count(ret)) ++ qdisc_qstats_drop(sch); ++ } else { ++ numsegs++; ++ } ++ } ++ ++ if (numsegs > 1) ++ qdisc_tree_reduce_backlog(sch, 1 - numsegs, len - slen); ++ consume_skb(skb); ++ ++ return numsegs > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP; ++ } ++ ++ return taprio_enqueue_one(skb, sch, child, to_free); ++} ++ + static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); +-- +2.53.0 + diff --git a/queue-5.10/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch b/queue-5.10/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch new file mode 100644 index 0000000000..337927c636 --- /dev/null +++ b/queue-5.10/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch @@ -0,0 +1,40 @@ +From 04ce27ca40f3ee1c7084dd144ee4f0bc51e55598 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:18 +0000 +Subject: tcp: annotate data-races around (tp->write_seq - tp->snd_nxt) + +From: Eric Dumazet + +[ Upstream commit 3a63b3d160560ef51e43fb4c880a5cde8078053c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() annotations to keep KCSAN happy. + +WRITE_ONCE() annotations are already present. + +Fixes: e08ab0b377a1 ("tcp: add bytes not sent to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-14-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 5998e2b6f5ec7..b5752cdefb4db 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3729,7 +3729,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +- max_t(int, 0, tp->write_seq - tp->snd_nxt)); ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt))); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, + TCP_NLA_PAD); + +-- +2.53.0 + diff --git a/queue-5.10/thermal-drivers-spear-fix-error-condition-for-readin.patch b/queue-5.10/thermal-drivers-spear-fix-error-condition-for-readin.patch new file mode 100644 index 0000000000..157387e68e --- /dev/null +++ b/queue-5.10/thermal-drivers-spear-fix-error-condition-for-readin.patch @@ -0,0 +1,42 @@ +From c813dbb9a86849d3ff9199d3bee0e31ab974cf76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:35:24 +0530 +Subject: thermal/drivers/spear: Fix error condition for reading + st,thermal-flags + +From: Gopi Krishna Menon + +[ Upstream commit da2c4f332a0504d9c284e7626a561d343c8d6f57 ] + +of_property_read_u32 returns 0 on success. The current check returns +-EINVAL if the property is read successfully. + +Fix the check by removing ! from of_property_read_u32 + +Fixes: b9c7aff481f1 ("drivers/thermal/spear_thermal.c: add Device Tree probing capability") +Signed-off-by: Gopi Krishna Menon +Signed-off-by: Daniel Lezcano +Suggested-by: Daniel Baluta +Reviewed-by: Lukasz Luba +Link: https://patch.msgid.link/20260327090526.59330-1-krishnagopi487@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/thermal/spear_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c +index ee33ed692e4f7..42d8736d5ba49 100644 +--- a/drivers/thermal/spear_thermal.c ++++ b/drivers/thermal/spear_thermal.c +@@ -94,7 +94,7 @@ static int spear_thermal_probe(struct platform_device *pdev) + struct resource *res; + int ret = 0, val; + +- if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) { ++ if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) { + dev_err(&pdev->dev, "Failed: DT Pdata not passed\n"); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-5.10/tipc-fix-double-free-in-tipc_buf_append.patch b/queue-5.10/tipc-fix-double-free-in-tipc_buf_append.patch new file mode 100644 index 0000000000..fd5cd1e411 --- /dev/null +++ b/queue-5.10/tipc-fix-double-free-in-tipc_buf_append.patch @@ -0,0 +1,60 @@ +From 969215e797682aabc15c582bb8c9d9b39e3c6503 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 13:45:26 +0100 +Subject: tipc: fix double-free in tipc_buf_append() + +From: Lee Jones + +[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ] + +tipc_msg_validate() can potentially reallocate the skb it is validating, +freeing the old one. In tipc_buf_append(), it was being called with a +pointer to a local variable which was a copy of the caller's skb +pointer. + +If the skb was reallocated and validation subsequently failed, the error +handling path would free the original skb pointer, which had already +been freed, leading to double-free. + +Fix this by checking if head now points to a newly allocated reassembled +skb. If it does, reassign *headbuf for later freeing operations. + +Fixes: d618d09a68e4 ("tipc: enforce valid ratio between skb truesize and contents") +Suggested-by: Tung Nguyen +Signed-off-by: Lee Jones +Reviewed-by: Tung Nguyen +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/msg.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/net/tipc/msg.c b/net/tipc/msg.c +index 1fcd676133eb1..721f37d301a70 100644 +--- a/net/tipc/msg.c ++++ b/net/tipc/msg.c +@@ -183,8 +183,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) + + if (fragid == LAST_FRAGMENT) { + TIPC_SKB_CB(head)->validated = 0; +- if (unlikely(!tipc_msg_validate(&head))) ++ ++ /* If the reassembled skb has been freed in ++ * tipc_msg_validate() because of an invalid truesize, ++ * then head will point to a newly allocated reassembled ++ * skb, while *headbuf points to freed reassembled skb. ++ * In such cases, correct *headbuf for freeing the newly ++ * allocated reassembled skb later. ++ */ ++ if (unlikely(!tipc_msg_validate(&head))) { ++ if (head != *headbuf) ++ *headbuf = head; + goto err; ++ } ++ + *buf = head; + TIPC_SKB_CB(head)->tail = NULL; + *headbuf = NULL; +-- +2.53.0 + diff --git a/queue-5.10/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch b/queue-5.10/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch new file mode 100644 index 0000000000..e8d362a1da --- /dev/null +++ b/queue-5.10/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch @@ -0,0 +1,69 @@ +From 553e4670a2bb6b7a07ec004f2d576d7e8d8d2107 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 06:25:09 -0700 +Subject: tracing: branch: Fix inverted check on stat tracer registration + +From: Breno Leitao + +[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ] + +init_annotated_branch_stats() and all_annotated_branch_stats() check the +return value of register_stat_tracer() with "if (!ret)", but +register_stat_tracer() returns 0 on success and a negative errno on +failure. The inverted check causes the warning to be printed on every +successful registration, e.g.: + + Warning: could not register annotated branches stats + +while leaving real failures silent. The initcall also returned a +hard-coded 1 instead of the actual error. + +Invert the check and propagate ret so that the warning fires on real +errors and the initcall reports the correct status. + +Cc: Mathieu Desnoyers +Cc: Ingo Molnar +Cc: Frederic Weisbecker +Link: https://patch.msgid.link/20260420-tracing-v1-1-d8f4cd0d6af1@debian.org +Fixes: 002bb86d8d42 ("tracing/ftrace: separate events tracing and stats tracing engine") +Signed-off-by: Breno Leitao +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_branch.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c +index eff099123aa27..363302960ba9e 100644 +--- a/kernel/trace/trace_branch.c ++++ b/kernel/trace/trace_branch.c +@@ -379,10 +379,10 @@ __init static int init_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&annotated_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "annotated branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +@@ -444,10 +444,10 @@ __init static int all_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&all_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "all branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +-- +2.53.0 + diff --git a/queue-5.10/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch b/queue-5.10/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch new file mode 100644 index 0000000000..164be959b9 --- /dev/null +++ b/queue-5.10/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch @@ -0,0 +1,56 @@ +From 3ba31b613233a36007cd17693bfae1ce40c5ae13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 19:22:23 +0800 +Subject: tracing: Rebuild full_name on each hist_field_name() call + +From: Pengpeng Hou + +[ Upstream commit 5ec1d1e97de134beed3a5b08235a60fc1c51af96 ] + +hist_field_name() uses a static MAX_FILTER_STR_VAL buffer for fully +qualified variable-reference names, but it currently appends into that +buffer with strcat() without rebuilding it first. As a result, repeated +calls append a new "system.event.field" name onto the previous one, +which can eventually run past the end of full_name. + +Build the name with snprintf() on each call and return NULL if the fully +qualified name does not fit in MAX_FILTER_STR_VAL. + +Link: https://patch.msgid.link/20260401112224.85582-1-pengpeng@iscas.ac.cn +Fixes: 067fe038e70f ("tracing: Add variable reference handling to hist triggers") +Reviewed-by: Tom Zanussi +Tested-by: Tom Zanussi +Signed-off-by: Pengpeng Hou +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index f499838d9103f..381d7e3989ada 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -1100,12 +1100,14 @@ static const char *hist_field_name(struct hist_field *field, + field->flags & HIST_FIELD_FL_VAR_REF) { + if (field->system) { + static char full_name[MAX_FILTER_STR_VAL]; ++ int len; ++ ++ len = snprintf(full_name, sizeof(full_name), "%s.%s.%s", ++ field->system, field->event_name, ++ field->name); ++ if (len >= sizeof(full_name)) ++ return NULL; + +- strcat(full_name, field->system); +- strcat(full_name, "."); +- strcat(full_name, field->event_name); +- strcat(full_name, "."); +- strcat(full_name, field->name); + field_name = full_name; + } else + field_name = field->name; +-- +2.53.0 + diff --git a/queue-5.10/tty-hvc-remove-hvc_iucv_magic.patch b/queue-5.10/tty-hvc-remove-hvc_iucv_magic.patch new file mode 100644 index 0000000000..96bcf87bf6 --- /dev/null +++ b/queue-5.10/tty-hvc-remove-hvc_iucv_magic.patch @@ -0,0 +1,77 @@ +From 9f97673ea59828c4a64ff033c0da3e85016d4d17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Sep 2022 03:55:18 +0200 +Subject: tty: hvc: remove HVC_IUCV_MAGIC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: наб + +[ Upstream commit eef7381d8134f249dc17138bb1794c249aff7f5a ] + +According to Greg, in the context of magic numbers as defined in +magic-number.rst, "the tty layer should not need this and I'll gladly +take patches" + +This stretches that definition slightly, since it multiplexes it with +the terminal number as a constant offset, but is equivalent + +Acked-by: Jiri Slaby +Signed-off-by: Ahelenia Ziemiańska +Ref: https://lore.kernel.org/linux-doc/YyMlovoskUcHLEb7@kroah.com/ +Link: https://lore.kernel.org/r/8c8a2c9dfc1bfbe6ef3f3237368e483865fc1c29.1663288066.git.nabijaczleweli@nabijaczleweli.xyz +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: f2a880e802ad ("tty: hvc_iucv: fix off-by-one in number of supported devices") +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index 796fbff623f6e..d76dff7eec521 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -29,7 +29,6 @@ + + + /* General device driver settings */ +-#define HVC_IUCV_MAGIC 0xc9e4c3e5 + #define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS + #define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4) + +@@ -131,9 +130,9 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) ++ if (num > hvc_iucv_devices) + return NULL; +- return hvc_iucv_table[num - HVC_IUCV_MAGIC]; ++ return hvc_iucv_table[num]; + } + + /** +@@ -1119,8 +1118,8 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) + priv->is_console = is_console; + + /* allocate hvc device */ +- priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ +- HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); ++ priv->hvc = hvc_alloc(id, /* PAGE_SIZE */ ++ id, &hvc_iucv_ops, 256); + if (IS_ERR(priv->hvc)) { + rc = PTR_ERR(priv->hvc); + goto out_error_hvc; +@@ -1424,7 +1423,7 @@ static int __init hvc_iucv_init(void) + + /* register the first terminal device as console + * (must be done before allocating hvc terminal devices) */ +- rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops); ++ rc = hvc_instantiate(0, IUCV_HVC_CON_IDX, &hvc_iucv_ops); + if (rc) { + pr_err("Registering HVC terminal device as " + "Linux console failed\n"); +-- +2.53.0 + diff --git a/queue-5.10/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch b/queue-5.10/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch new file mode 100644 index 0000000000..7f9e0730fe --- /dev/null +++ b/queue-5.10/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch @@ -0,0 +1,50 @@ +From f5c32d6fa3a8edbb55001a6e9550a6916e721929 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 23:29:37 -0800 +Subject: tty: hvc_iucv: fix off-by-one in number of supported devices + +From: Randy Dunlap + +[ Upstream commit f2a880e802ad12d1e38039d1334fb1475d0f5241 ] + +MAX_HVC_IUCV_LINES == HVC_ALLOC_TTY_ADAPTERS == 8. +This is the number of entries in: + static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; + +Sometimes hvc_iucv_table[] is limited by: +(a) if (num > hvc_iucv_devices) // for error detection +or +(b) for (i = 0; i < hvc_iucv_devices; i++) // in 2 places +(so these 2 don't agree; second one appears to be correct to me.) + +hvc_iucv_devices can be 0..8. This is a counter. +(c) if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + +If hvc_iucv_devices == 8, (a) allows the code to access hvc_iucv_table[8]. +Oops. + +Fixes: 44a01d5ba8a4 ("[S390] s390/hvc_console: z/VM IUCV hypervisor console support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260130072939.1535869-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index d76dff7eec521..c031f8947a935 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if (num > hvc_iucv_devices) ++ if (num >= hvc_iucv_devices) + return NULL; + return hvc_iucv_table[num]; + } +-- +2.53.0 + diff --git a/queue-5.10/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch b/queue-5.10/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch new file mode 100644 index 0000000000..29527dd840 --- /dev/null +++ b/queue-5.10/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch @@ -0,0 +1,64 @@ +From e4c6686203f599e9099da30aa8dcc3e0629f7d8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 02:30:24 +0000 +Subject: vhost_net: fix sleeping with preempt-disabled in + vhost_net_busy_poll() + +From: Kohei Enju + +[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ] + +syzbot reported "sleeping function called from invalid context" in +vhost_net_busy_poll(). + +Commit 030881372460 ("vhost_net: basic polling support") introduced a +busy-poll loop and preempt_{disable,enable}() around it, where each +iteration calls a sleepable function inside the loop. + +The purpose of disabling preemption was to keep local_clock()-based +timeout accounting on a single CPU, rather than as a requirement of +busy-poll itself: + +https://lore.kernel.org/1448435489-5949-4-git-send-email-jasowang@redhat.com + +From this perspective, migrate_disable() is sufficient here, so replace +preempt_disable() with migrate_disable(), avoiding sleepable accesses +from a preempt-disabled context. + +Fixes: 030881372460 ("vhost_net: basic polling support") +Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/ +Signed-off-by: Kohei Enju +Acked-by: Michael S. Tsirkin +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/vhost/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index c9f30aa50879d..dbc2228939265 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -544,7 +544,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + busyloop_timeout = poll_rx ? rvq->busyloop_timeout: + tvq->busyloop_timeout; + +- preempt_disable(); ++ migrate_disable(); + endtime = busy_clock() + busyloop_timeout; + + while (vhost_can_busy_poll(endtime)) { +@@ -561,7 +561,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + cpu_relax(); + } + +- preempt_enable(); ++ migrate_enable(); + + if (poll_rx || sock_has_rx_data(sock)) + vhost_net_busy_poll_try_queue(net, vq); +-- +2.53.0 + diff --git a/queue-5.10/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch b/queue-5.10/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch new file mode 100644 index 0000000000..65cd2e4ed8 --- /dev/null +++ b/queue-5.10/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch @@ -0,0 +1,115 @@ +From 85e43ba4a3d022c81a4feb37e1d4ed741b69384f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 09:36:07 +0300 +Subject: vrf: Fix a potential NPD when removing a port from a VRF + +From: Ido Schimmel + +[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ] + +RCU readers that identified a net device as a VRF port using +netif_is_l3_slave() assume that a subsequent call to +netdev_master_upper_dev_get_rcu() will return a VRF device. They then +continue to dereference its l3mdev operations. + +This assumption is not always correct and can result in a NPD [1]. There +is no RCU synchronization when removing a port from a VRF, so it is +possible for an RCU reader to see a new master device (e.g., a bridge) +that does not have l3mdev operations. + +Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE +flag. Skip this synchronization when a net device is removed from a VRF +as part of its deletion and when the VRF device itself is deleted. In +the latter case an RCU grace period will pass by the time RTNL is +released. + +[1] +BUG: kernel NULL pointer dereference, address: 0000000000000000 +[...] +RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) +[...] +Call Trace: + +l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) +__inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) +inet_bind_sk (net/ipv4/af_inet.c:469) +__sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) +__x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Fixes: fdeea7be88b1 ("net: vrf: Set slave's private flag before linking") +Reported-by: Haoze Xie +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/netdev/20260419145332.3988923-1-n05ec@lzu.edu.cn/ +Signed-off-by: Ido Schimmel +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260423063607.1208202-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vrf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index b43e8041fda34..d1a2b3dcd00c9 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -1143,6 +1143,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + + err: + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ synchronize_net(); + return ret; + } + +@@ -1162,10 +1163,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + } + + /* inverse of do_vrf_add_slave */ +-static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) ++static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, ++ bool needs_sync) + { + netdev_upper_dev_unlink(port_dev, dev); + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ /* Make sure that concurrent RCU readers that identified the device ++ * as a VRF port see a VRF master or no master at all. ++ */ ++ if (needs_sync) ++ synchronize_net(); + + cycle_netdev(port_dev, NULL); + +@@ -1174,7 +1181,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + + static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + { +- return do_vrf_del_slave(dev, port_dev); ++ return do_vrf_del_slave(dev, port_dev, true); + } + + static void vrf_dev_uninit(struct net_device *dev) +@@ -1666,7 +1673,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) + struct list_head *iter; + + netdev_for_each_lower_dev(dev, port_dev, iter) +- vrf_del_slave(dev, port_dev); ++ do_vrf_del_slave(dev, port_dev, false); + + vrf_map_unregister_dev(dev); + +@@ -1797,7 +1804,7 @@ static int vrf_device_event(struct notifier_block *unused, + goto out; + + vrf_dev = netdev_master_upper_dev_get(dev); +- vrf_del_slave(vrf_dev, dev); ++ do_vrf_del_slave(vrf_dev, dev, false); + } + out: + return NOTIFY_DONE; +-- +2.53.0 + diff --git a/queue-5.10/wifi-brcmfmac-fix-error-pointer-dereference.patch b/queue-5.10/wifi-brcmfmac-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..ac1a8b4bc3 --- /dev/null +++ b/queue-5.10/wifi-brcmfmac-fix-error-pointer-dereference.patch @@ -0,0 +1,80 @@ +From 135b4e72caa9c31698d4df7b3ba90dbac6c4ac9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 20:30:43 -0600 +Subject: wifi: brcmfmac: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit dd8592fc6007a451c3e4b9025de365e39de8178a ] + +The function brcmf_chip_add_core() can return an error pointer and is +not checked. Add checks for error pointer. + +Detected by Smatch: +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1010 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1013 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1016 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1019 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1022 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +Fixes: cb7cf7be9eba7 ("brcmfmac: make chip related functions host interface independent") +Signed-off-by: Ethan Tidmore +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260217023043.73631-1-ethantidmore06@gmail.com +[add missing wifi: prefix] +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index a0097ffe33590..e720da11e5ef9 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -981,18 +981,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + + core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, + SI_ENUM_BASE_DEFAULT, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, + BCM4329_CORE_BUS_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, + BCM4329_CORE_SOCRAM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, + BCM4329_CORE_ARM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + + core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + } else if (socitype == SOCI_AI) { + ci->iscoreup = brcmf_chip_ai_iscoreup; +-- +2.53.0 + diff --git a/queue-5.10/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch b/queue-5.10/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch new file mode 100644 index 0000000000..5a8793341d --- /dev/null +++ b/queue-5.10/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch @@ -0,0 +1,49 @@ +From 0d2af5dcf3b13e8c7df716d6d3c52b470f370ffa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 09:26:25 +0000 +Subject: wifi: mwifiex: Fix memory leak in mwifiex_11n_aggregate_pkt() + +From: Zilin Guan + +[ Upstream commit 990a73dec3fdc145fef6c827c29205437d533ece ] + +In mwifiex_11n_aggregate_pkt(), skb_aggr is allocated via +mwifiex_alloc_dma_align_buf(). If mwifiex_is_ralist_valid() returns false, +the function currently returns -1 immediately without freeing the +previously allocated skb_aggr, causing a memory leak. + +Since skb_aggr has not yet been queued via skb_queue_tail(), no other +references to this memory exist. Therefore, it has to be freed locally +before returning the error. + +Fix this by calling mwifiex_write_data_complete() to free skb_aggr before +returning the error status. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") +Signed-off-by: Zilin Guan +Reviewed-by: Jeff Chen +Link: https://patch.msgid.link/20260119092625.1349934-1-zilin@seu.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +index 46f41dbcf30dd..54662bc5bc152 100644 +--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +@@ -215,6 +215,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); ++ mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); + return -1; + } + +-- +2.53.0 + diff --git a/queue-5.10/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch b/queue-5.10/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch new file mode 100644 index 0000000000..3b7c452e08 --- /dev/null +++ b/queue-5.10/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch @@ -0,0 +1,49 @@ +From 39872212e9a312ae1d7739b289182e807420b363 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:55:22 +0800 +Subject: wifi: rtlwifi: pci: fix possible use-after-free caused by unfinished + irq_prepare_bcn_tasklet + +From: Duoming Zhou + +[ Upstream commit 039cd522dc70151da13329a5e3ae19b1736f468a ] + +The irq_prepare_bcn_tasklet is initialized in rtl_pci_init() and +scheduled when RTL_IMR_BCNINT interrupt is triggered by hardware. +But it is never killed in rtl_pci_deinit(). When the rtlwifi card +probe fails or is being detached, the ieee80211_hw is deallocated. +However, irq_prepare_bcn_tasklet may still be running or pending, +leading to use-after-free when the freed ieee80211_hw is accessed +in _rtl_pci_prepare_bcn_tasklet(). + +Similar to irq_tasklet, add tasklet_kill() in rtl_pci_deinit() to +ensure that irq_prepare_bcn_tasklet is properly terminated before +the ieee80211_hw is released. + +The issue was identified through static analysis. + +Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") +Signed-off-by: Duoming Zhou +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260223045522.48377-1-duoming@zju.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtlwifi/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index 02821588673e5..3058c8356c292 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -1675,6 +1675,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); ++ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + } + +-- +2.53.0 + diff --git a/queue-5.15/6pack-propagage-new-tty-types.patch b/queue-5.15/6pack-propagage-new-tty-types.patch new file mode 100644 index 0000000000..17f45956e0 --- /dev/null +++ b/queue-5.15/6pack-propagage-new-tty-types.patch @@ -0,0 +1,136 @@ +From 9a3b661ca79659a0ebfe51a9eeaa3f7ee658c660 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 12:35:47 +0200 +Subject: 6pack: propagage new tty types + +From: Jiri Slaby (SUSE) + +[ Upstream commit 1241b384efa53f4b7a95fe2b34d69359bb3ae1b5 ] + +In tty, u8 is now used for data, ssize_t for sizes (with possible +negative error codes). Propagate these types to 6pack. + +Signed-off-by: Jiri Slaby (SUSE) +Cc: Greg Kroah-Hartman +Cc: Andreas Koensgen +Cc: David S. Miller +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: linux-hams@vger.kernel.org +Cc: netdev@vger.kernel.org +Reviewed-by: Jeremy Kerr +Link: https://lore.kernel.org/r/20240808103549.429349-12-jirislaby@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bf9a38803b26 ("net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf") +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 36a9fbb704029..7ccf56a7f0e0c 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -94,8 +94,8 @@ struct sixpack { + unsigned char *xhead; /* next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + +- unsigned char raw_buf[4]; +- unsigned char cooked_buf[400]; ++ u8 raw_buf[4]; ++ u8 cooked_buf[400]; + + unsigned int rx_count; + unsigned int rx_count_cooked; +@@ -112,8 +112,8 @@ struct sixpack { + unsigned char slottime; + unsigned char duplex; + unsigned char led_state; +- unsigned char status; +- unsigned char status1; ++ u8 status; ++ u8 status1; + unsigned char status2; + unsigned char tx_enable; + unsigned char tnc_state; +@@ -127,7 +127,7 @@ struct sixpack { + + #define AX25_6PACK_HEADER_LEN 0 + +-static void sixpack_decode(struct sixpack *, const unsigned char[], int); ++static void sixpack_decode(struct sixpack *, const u8 *, size_t); + static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); + + /* +@@ -332,7 +332,7 @@ static void sp_bump(struct sixpack *sp, char cmd) + { + struct sk_buff *skb; + int count; +- unsigned char *ptr; ++ u8 *ptr; + + count = sp->rcount + 1; + +@@ -430,7 +430,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, + const unsigned char *cp, const char *fp, int count) + { + struct sixpack *sp; +- int count1; ++ size_t count1; + + if (!count) + return; +@@ -818,9 +818,9 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, + + /* decode 4 sixpack-encoded bytes into 3 data bytes */ + +-static void decode_data(struct sixpack *sp, unsigned char inbyte) ++static void decode_data(struct sixpack *sp, u8 inbyte) + { +- unsigned char *buf; ++ u8 *buf; + + if (sp->rx_count != 3) { + sp->raw_buf[sp->rx_count++] = inbyte; +@@ -846,9 +846,9 @@ static void decode_data(struct sixpack *sp, unsigned char inbyte) + + /* identify and execute a 6pack priority command byte */ + +-static void decode_prio_command(struct sixpack *sp, unsigned char cmd) ++static void decode_prio_command(struct sixpack *sp, u8 cmd) + { +- int actual; ++ ssize_t actual; + + if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ + +@@ -896,9 +896,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd) + + /* identify and execute a standard 6pack command byte */ + +-static void decode_std_command(struct sixpack *sp, unsigned char cmd) ++static void decode_std_command(struct sixpack *sp, u8 cmd) + { +- unsigned char checksum = 0, rest = 0; ++ u8 checksum = 0, rest = 0; + short i; + + switch (cmd & SIXP_CMD_MASK) { /* normal command */ +@@ -944,10 +944,10 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd) + /* decode a 6pack packet */ + + static void +-sixpack_decode(struct sixpack *sp, const unsigned char *pre_rbuff, int count) ++sixpack_decode(struct sixpack *sp, const u8 *pre_rbuff, size_t count) + { +- unsigned char inbyte; +- int count1; ++ size_t count1; ++ u8 inbyte; + + for (count1 = 0; count1 < count; count1++) { + inbyte = pre_rbuff[count1]; +-- +2.53.0 + diff --git a/queue-5.15/alsa-core-validate-compress-device-numbers-without-d.patch b/queue-5.15/alsa-core-validate-compress-device-numbers-without-d.patch new file mode 100644 index 0000000000..c3a4f71008 --- /dev/null +++ b/queue-5.15/alsa-core-validate-compress-device-numbers-without-d.patch @@ -0,0 +1,81 @@ +From 81d7a036679c93ac5ade8e463e89d46ac576d512 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 02:24:04 -0300 +Subject: ALSA: core: Validate compress device numbers without dynamic minors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 796e119e9b14763be905ad0d023c71a14bc2e931 ] + +Without CONFIG_SND_DYNAMIC_MINORS, ALSA reserves only two fixed minors +for compress devices on each card: comprD0 and comprD1. + +snd_find_free_minor() currently computes the compress minor as +type + dev without validating dev first, so device numbers greater than +1 spill into the HWDEP minor range instead of failing registration. + +ASoC passes rtd->id to snd_compress_new(), so this can happen on real +non-dynamic-minor builds. + +Add a dedicated fixed-minor check for SNDRV_DEVICE_TYPE_COMPRESS in +snd_find_free_minor() and reject out-of-range device numbers with +-EINVAL before constructing the minor. + +Also remove the stale TODO in compress_offload.c that still claims +multiple compress nodes are missing. + +Fixes: 3eafc959b32f ("ALSA: core: add support for compressed devices") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-alsa-compress-static-minors-v1-1-0628573bee1c@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 7 ------- + sound/core/sound.c | 7 +++++++ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index de514ec8c83d5..1ba90a87808e4 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -40,13 +40,6 @@ + #define COMPR_CODEC_CAPS_OVERFLOW + #endif + +-/* TODO: +- * - add substream support for multiple devices in case of +- * SND_DYNAMIC_MINORS is not used +- * - Multiple node representation +- * driver should be able to register multiple nodes +- */ +- + struct snd_compr_file { + unsigned long caps; + struct snd_compr_stream stream; +diff --git a/sound/core/sound.c b/sound/core/sound.c +index df5571d986295..f3bb0adf37cce 100644 +--- a/sound/core/sound.c ++++ b/sound/core/sound.c +@@ -219,9 +219,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev) + case SNDRV_DEVICE_TYPE_RAWMIDI: + case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: + case SNDRV_DEVICE_TYPE_PCM_CAPTURE: ++ if (snd_BUG_ON(!card)) ++ return -EINVAL; ++ minor = SNDRV_MINOR(card->number, type + dev); ++ break; + case SNDRV_DEVICE_TYPE_COMPRESS: + if (snd_BUG_ON(!card)) + return -EINVAL; ++ if (dev < 0 || ++ dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS) ++ return -EINVAL; + minor = SNDRV_MINOR(card->number, type + dev); + break; + default: +-- +2.53.0 + diff --git a/queue-5.15/alsa-hda-conexant-add-a-new-hda-codec-sn6140.patch b/queue-5.15/alsa-hda-conexant-add-a-new-hda-codec-sn6140.patch new file mode 100644 index 0000000000..9b7e0e3428 --- /dev/null +++ b/queue-5.15/alsa-hda-conexant-add-a-new-hda-codec-sn6140.patch @@ -0,0 +1,36 @@ +From 10a8176eef524f4636a4835eb475d64217fae8a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 May 2022 10:57:35 +0800 +Subject: ALSA: hda/conexant: add a new hda codec SN6140 + +From: bo liu + +[ Upstream commit ca348e7fe1ab9192ad7d9ff029a82a1594e0e289 ] + +The current kernel does not support the SN6140 codec chip. +Add the SN6140 codec configuration item to kernel. + +Signed-off-by: bo liu +Link: https://lore.kernel.org/r/20220506025735.17731-1-bo.liu@senarytech.com +Signed-off-by: Takashi Iwai +Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 2d653b73e6795..e5837e47aa227 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -1303,6 +1303,7 @@ static int patch_conexant_auto(struct hda_codec *codec) + + static const struct hda_device_id snd_hda_id_conexant[] = { + HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), ++ HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto), +-- +2.53.0 + diff --git a/queue-5.15/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch b/queue-5.15/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch new file mode 100644 index 0000000000..bf7c690a9a --- /dev/null +++ b/queue-5.15/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch @@ -0,0 +1,60 @@ +From e58ff0380f0fe269dc500e0457596ff5a7fdde14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:04:50 +0800 +Subject: ALSA: hda/conexant: Fix missing error check for jack detection + +From: wangdicheng + +[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ] + +In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() +is ignored. This function returns a pointer, and if it fails (e.g., due +to memory allocation failure), it returns an error pointer which must +be checked using IS_ERR(). + +If the registration fails, the driver continues to probe, but the jack +detection callback will not be registered. This can lead to a kernel +crash later when the driver attempts to handle jack events or accesses +the uninitialized structure. + +Check the return value using IS_ERR() and propagate the error via +PTR_ERR() to the probe caller. + +Fixes: 7aeb25908648 ("ALSA: hda/conexant: Fix headset auto detect fail in cx8070 and SN6140") +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428080450.108801-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 7aeaccc9189c8..82186c4364c9b 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -1199,6 +1199,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) + static int patch_conexant_auto(struct hda_codec *codec) + { + struct conexant_spec *spec; ++ struct hda_jack_callback *callback; + int err; + + codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); +@@ -1215,7 +1216,12 @@ static int patch_conexant_auto(struct hda_codec *codec) + case 0x14f11f86: + case 0x14f11f87: + spec->is_cx11880_sn6140 = true; +- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); ++ callback = snd_hda_jack_detect_enable_callback(codec, 0x19, ++ cx_update_headset_mic_vref); ++ if (IS_ERR(callback)) { ++ err = PTR_ERR(callback); ++ goto error; ++ } + break; + } + +-- +2.53.0 + diff --git a/queue-5.15/alsa-hda-conexant-fix-some-typos.patch b/queue-5.15/alsa-hda-conexant-fix-some-typos.patch new file mode 100644 index 0000000000..df1a7b0b5f --- /dev/null +++ b/queue-5.15/alsa-hda-conexant-fix-some-typos.patch @@ -0,0 +1,64 @@ +From ef5103f6d29e545c6a0d02b3f042657053052399 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 16:41:32 +0800 +Subject: ALSA: hda/conexant: fix some typos + +From: Oldherl Oh + +[ Upstream commit 73253f2fd1d0a44708735c842e37163712e3f03b ] + +Fix some typos in patch_conexant.c + +Signed-off-by: Oldherl Oh +Link: https://patch.msgid.link/20240930084132.3373750-1-me@oldherl.one +Signed-off-by: Takashi Iwai +Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index e5837e47aa227..394932123b51d 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -166,18 +166,18 @@ static void cxt_init_gpio_led(struct hda_codec *codec) + + static void cx_fixup_headset_recog(struct hda_codec *codec) + { +- unsigned int mic_persent; ++ unsigned int mic_present; + + /* fix some headset type recognize fail issue, such as EDIFIER headset */ +- /* set micbiasd output current comparator threshold from 66% to 55%. */ ++ /* set micbias output current comparator threshold from 66% to 55%. */ + snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010); +- /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias registor ++ /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register + * value adjustment trim from 2.2K ohms to 2.0K ohms. + */ + snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10); + /* fix reboot headset type recognize fail issue */ +- mic_persent = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); +- if (mic_persent & AC_PINSENSE_PRESENCE) ++ mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); ++ if (mic_present & AC_PINSENSE_PRESENCE) + /* enable headset mic VREF */ + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); + else +@@ -247,9 +247,9 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ + { + unsigned int mic_present; + +- /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled, +- * the node 19 can only be config to microphone or disabled. +- * Check hp&mic tag to process headset pulgin&plugout. ++ /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, ++ * the node 19 can only be configured to microphone or disabled. ++ * Check hp&mic tag to process headset plugin & plugout. + */ + mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); + if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ +-- +2.53.0 + diff --git a/queue-5.15/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch b/queue-5.15/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch new file mode 100644 index 0000000000..d5659b9c00 --- /dev/null +++ b/queue-5.15/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch @@ -0,0 +1,79 @@ +From d0cca811f0795ce5ec39a687070e8a2db8786d29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Jun 2025 15:43:31 +0800 +Subject: ALSA: hda/conexant: Renaming the codec with device ID 0x1f86 and + 0x1f87 + +From: wangdicheng + +[ Upstream commit 7f4c540e0859e2025675d2c5c5c6ab88eaf817e2 ] + +Due to changes in the manufacturer's plan, all 0x14f11f86 will be +named CX11880, and 0x14f11f87 will be named SN6140 + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20250616074331.581309-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 394932123b51d..7aeaccc9189c8 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -42,7 +42,7 @@ struct conexant_spec { + unsigned int gpio_led; + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; +- bool is_cx8070_sn6140; ++ bool is_cx11880_sn6140; + }; + + +@@ -195,7 +195,7 @@ static int cx_auto_init(struct hda_codec *codec) + cxt_init_gpio_led(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + +- if (spec->is_cx8070_sn6140) ++ if (spec->is_cx11880_sn6140) + cx_fixup_headset_recog(codec); + + return 0; +@@ -247,7 +247,7 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ + { + unsigned int mic_present; + +- /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, ++ /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled, + * the node 19 can only be configured to microphone or disabled. + * Check hp&mic tag to process headset plugin & plugout. + */ +@@ -1210,11 +1210,11 @@ static int patch_conexant_auto(struct hda_codec *codec) + codec->spec = spec; + codec->patch_ops = cx_auto_patch_ops; + +- /* init cx8070/sn6140 flag and reset headset_present_flag */ ++ /* init cx11880/sn6140 flag and reset headset_present_flag */ + switch (codec->core.vendor_id) { + case 0x14f11f86: + case 0x14f11f87: +- spec->is_cx8070_sn6140 = true; ++ spec->is_cx11880_sn6140 = true; + snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); + break; + } +@@ -1302,7 +1302,7 @@ static int patch_conexant_auto(struct hda_codec *codec) + */ + + static const struct hda_device_id snd_hda_id_conexant[] = { +- HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), ++ HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), +-- +2.53.0 + diff --git a/queue-5.15/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch b/queue-5.15/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch new file mode 100644 index 0000000000..5062f0cdc6 --- /dev/null +++ b/queue-5.15/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch @@ -0,0 +1,45 @@ +From 068c582643f38681758e93b335a23bd28dad1af0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 15:54:05 +0800 +Subject: ALSA: hda/realtek: fix code style (ERROR: else should follow close + brace '}') + +From: Lei Huang + +[ Upstream commit d1888bf848ade6a9e71c7ba516fd215aa1bd8d65 ] + +Fix checkpatch code style errors: + + ERROR: else should follow close brace '}' + #2300: FILE: sound/hda/codecs/realtek/alc269.c:2300: + + } + + else + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Lei Huang +Link: https://patch.msgid.link/20260331075405.78148-1-huanglei814@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index c847e9ab36b31..bd8878f4896c8 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -6011,9 +6011,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } +- else ++ } else { + alc_fixup_headset_mode(codec, fix, action); ++ } + } + + static void alc288_update_headset_jack_cb(struct hda_codec *codec, +-- +2.53.0 + diff --git a/queue-5.15/alsa-hda-realtek-whitespace-fix.patch b/queue-5.15/alsa-hda-realtek-whitespace-fix.patch new file mode 100644 index 0000000000..c7381d130e --- /dev/null +++ b/queue-5.15/alsa-hda-realtek-whitespace-fix.patch @@ -0,0 +1,37 @@ +From 44fcaef685fa319cc33b6a964f1f77a953001768 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jul 2023 16:46:19 +1200 +Subject: ALSA: hda/realtek: Whitespace fix + +From: Luke D. Jones + +[ Upstream commit 72cea3a3175b50a4875b3c112fb13df20c6218a5 ] + +Remove an erroneous whitespace. + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Luke D. Jones +Link: https://lore.kernel.org/r/20230704044619.19343-6-luke@ljones.dev +Signed-off-by: Takashi Iwai +Stable-dep-of: d1888bf848ad ("ALSA: hda/realtek: fix code style (ERROR: else should follow close brace '}')") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 9cb5705577f72..c847e9ab36b31 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -6011,7 +6011,7 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } ++ } + else + alc_fixup_headset_mode(codec, fix, action); + } +-- +2.53.0 + diff --git a/queue-5.15/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch b/queue-5.15/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch new file mode 100644 index 0000000000..62395424ac --- /dev/null +++ b/queue-5.15/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch @@ -0,0 +1,289 @@ +From f807f11d3238c9599773c4918f85e4e6bd8bf490 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:54:32 -0300 +Subject: ALSA: sc6000: Keep the programmed board state in card-private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit fb79bf127ac2577b4876132da6dba768018aad4c ] + +The driver may auto-select IRQ and DMA resources at probe time, but +sc6000_init_board() still derives the SC-6000 soft configuration from +the module parameter arrays. When irq=auto or dma=auto is used, the +codec is created with the selected resources while the board is +programmed with the unresolved values. + +Store the mapped ports and generated SC-6000 board configuration in +card-private data, build that configuration from the live probe +results instead of the raw module parameters, and keep the probe-time +board programming in a shared helper. + +This fixes the resource-programming mismatch and leaves the driver +with a stable board-state block that can be reused by suspend/resume. + +Fixes: c282866101bf ("ALSA: sc6000: add support for SC-6600 and SC-7000") +Signed-off-by: Cássio Gabriel +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260410-alsa-sc6000-pm-v1-1-4d9e95493d26@gmail.com +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 152 +++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 60 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 3115c32b4061b..4066b68a102e2 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -100,6 +100,15 @@ MODULE_PARM_DESC(joystick, "Enable gameport."); + #define PFX "sc6000: " + #define DRV_NAME "SC-6000" + ++struct snd_sc6000 { ++ char __iomem *vport; ++ char __iomem *vmss_port; ++ u8 mss_config; ++ u8 config; ++ u8 hw_cfg[2]; ++ bool old_dsp; ++}; ++ + /* hardware dependent functions */ + + /* +@@ -267,7 +276,7 @@ static int sc6000_dsp_reset(char __iomem *vport) + + /* detection and initialization */ + static int sc6000_hw_cfg_write(struct device *devptr, +- char __iomem *vport, const int *cfg) ++ char __iomem *vport, const u8 *cfg) + { + if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { + dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); +@@ -353,8 +362,7 @@ static int sc6000_init_mss(struct device *devptr, + return 0; + } + +-static void sc6000_hw_cfg_encode(struct device *devptr, +- char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, u8 *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -376,27 +384,83 @@ static void sc6000_hw_cfg_encode(struct device *devptr, + dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(struct device *devptr, +- char __iomem *vport, +- char __iomem *vmss_port, int dev) ++static void sc6000_prepare_board(struct device *devptr, ++ struct snd_sc6000 *sc6000, ++ unsigned int dev, int xirq, int xdma) ++{ ++ sc6000->mss_config = sc6000_irq_to_softcfg(xirq) | ++ sc6000_dma_to_softcfg(xdma); ++ sc6000->config = sc6000->mss_config | ++ sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); ++ sc6000_hw_cfg_encode(devptr, sc6000->hw_cfg, port[dev], mpu_port[dev], ++ mss_port[dev], joystick[dev]); ++} ++ ++static void sc6000_detect_old_dsp(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ sc6000_write(devptr, sc6000->vport, COMMAND_5C); ++ sc6000->old_dsp = sc6000_read(sc6000->vport) < 0; ++} ++ ++static int sc6000_program_board(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ int err; ++ ++ if (!sc6000->old_dsp) { ++ if (sc6000_hw_cfg_write(devptr, sc6000->vport, ++ sc6000->hw_cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); ++ return -EIO; ++ } ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ sc6000_dsp_reset(sc6000->vport); ++ ++ if (!sc6000->old_dsp) { ++ sc6000_write(devptr, sc6000->vport, COMMAND_60); ++ sc6000_write(devptr, sc6000->vport, 0x02); ++ sc6000_dsp_reset(sc6000->vport); ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ err = sc6000_init_mss(devptr, sc6000->vport, sc6000->config, ++ sc6000->vmss_port, sc6000->mss_config); ++ if (err < 0) { ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int sc6000_init_board(struct device *devptr, struct snd_sc6000 *sc6000) + { + char answer[15]; + char version[2]; +- int mss_config = sc6000_irq_to_softcfg(irq[dev]) | +- sc6000_dma_to_softcfg(dma[dev]); +- int config = mss_config | +- sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); + int err; +- int old = 0; + +- err = sc6000_dsp_reset(vport); ++ err = sc6000_dsp_reset(sc6000->vport); + if (err < 0) { + dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, sc6000->vport, GET_DSP_COPYRIGHT, ++ answer, 15); + if (err <= 0) { + dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; +@@ -408,54 +472,17 @@ static int sc6000_init_board(struct device *devptr, + if (strncmp("SC-6000", answer, 7)) + dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ if (sc6000_dsp_get_answer(devptr, sc6000->vport, ++ GET_DSP_VERSION, version, 2) < 2) { + dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } + dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + +- /* set configuration */ +- sc6000_write(devptr, vport, COMMAND_5C); +- if (sc6000_read(vport) < 0) +- old = 1; +- +- if (!old) { +- int cfg[2]; +- sc6000_hw_cfg_encode(devptr, +- vport, &cfg[0], port[dev], mpu_port[dev], +- mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { +- dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); +- return -EIO; +- } +- } +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- +- sc6000_dsp_reset(vport); +- +- if (!old) { +- sc6000_write(devptr, vport, COMMAND_60); +- sc6000_write(devptr, vport, 0x02); +- sc6000_dsp_reset(vport); +- } ++ sc6000_detect_old_dsp(devptr, sc6000); + +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); +- if (err < 0) { +- dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); +- return -ENODEV; +- } +- +- return 0; ++ return sc6000_program_board(devptr, sc6000); + } + + static int snd_sc6000_mixer(struct snd_wss *chip) +@@ -538,10 +565,10 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + + static void snd_sc6000_free(struct snd_card *card) + { +- char __iomem *vport = (char __force __iomem *)card->private_data; ++ struct snd_sc6000 *sc6000 = card->private_data; + +- if (vport) +- sc6000_setup_board(card->dev, vport, 0); ++ if (sc6000->vport) ++ sc6000_setup_board(card->dev, sc6000->vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -552,15 +579,17 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + int xirq = irq[dev]; + int xdma = dma[dev]; + struct snd_card *card; ++ struct snd_sc6000 *sc6000; + struct snd_wss *chip; + struct snd_opl3 *opl3; + char __iomem *vport; + char __iomem *vmss_port; + + err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE, +- 0, &card); ++ sizeof(*sc6000), &card); + if (err < 0) + return err; ++ sc6000 = card->private_data; + + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); +@@ -587,7 +616,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } +- card->private_data = (void __force *)vport; ++ sc6000->vport = vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +@@ -600,12 +629,15 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } ++ sc6000->vmss_port = vmss_port; + + dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(devptr, vport, vmss_port, dev); ++ sc6000_prepare_board(devptr, sc6000, dev, xirq, xdma); ++ ++ err = sc6000_init_board(devptr, sc6000); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +-- +2.53.0 + diff --git a/queue-5.15/alsa-sc6000-use-standard-print-api.patch b/queue-5.15/alsa-sc6000-use-standard-print-api.patch new file mode 100644 index 0000000000..f0e2e302a0 --- /dev/null +++ b/queue-5.15/alsa-sc6000-use-standard-print-api.patch @@ -0,0 +1,453 @@ +From e0c9e2cff0ec6fac7de1c5ba3f7ab3d30612eb22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Aug 2024 15:34:23 +0200 +Subject: ALSA: sc6000: Use standard print API + +From: Takashi Iwai + +[ Upstream commit e7c475b92043c02c3e6cd0c20e308fbb6f03ebde ] + +Use the standard print API with dev_*() instead of the old house-baked +one. It gives better information and allows dynamically control of +debug prints. + +Some functions are changed to receive a device pointer to be passed to +dev_*() calls. + +Reviewed-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20240807133452.9424-34-tiwai@suse.de +Stable-dep-of: fb79bf127ac2 ("ALSA: sc6000: Keep the programmed board state in card-private data") +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 177 +++++++++++++++++++++++---------------------- + 1 file changed, 90 insertions(+), 87 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 60398fced046b..3115c32b4061b 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -204,7 +204,7 @@ static int sc6000_read(char __iomem *vport) + + } + +-static int sc6000_write(char __iomem *vport, int cmd) ++static int sc6000_write(struct device *devptr, char __iomem *vport, int cmd) + { + unsigned char val; + int loop = 500000; +@@ -221,18 +221,19 @@ static int sc6000_write(char __iomem *vport, int cmd) + cpu_relax(); + } while (loop--); + +- snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd); ++ dev_err(devptr, "DSP Command (0x%x) timeout.\n", cmd); + + return -EIO; + } + +-static int sc6000_dsp_get_answer(char __iomem *vport, int command, ++static int sc6000_dsp_get_answer(struct device *devptr, ++ char __iomem *vport, int command, + char *data, int data_len) + { + int len = 0; + +- if (sc6000_write(vport, command)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command); ++ if (sc6000_write(devptr, vport, command)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", command); + return -EIO; + } + +@@ -265,82 +266,86 @@ static int sc6000_dsp_reset(char __iomem *vport) + } + + /* detection and initialization */ +-static int sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) ++static int sc6000_hw_cfg_write(struct device *devptr, ++ char __iomem *vport, const int *cfg) + { +- if (sc6000_write(vport, COMMAND_6C) < 0) { +- snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C); ++ if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { ++ dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); + return -EIO; + } +- if (sc6000_write(vport, COMMAND_5C) < 0) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C); ++ if (sc6000_write(devptr, vport, COMMAND_5C) < 0) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_5C); + return -EIO; + } +- if (sc6000_write(vport, cfg[0]) < 0) { +- snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]); ++ if (sc6000_write(devptr, vport, cfg[0]) < 0) { ++ dev_err(devptr, "DATA 0x%x: failed!\n", cfg[0]); + return -EIO; + } +- if (sc6000_write(vport, cfg[1]) < 0) { +- snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]); ++ if (sc6000_write(devptr, vport, cfg[1]) < 0) { ++ dev_err(devptr, "DATA 0x%x: failed!\n", cfg[1]); + return -EIO; + } +- if (sc6000_write(vport, COMMAND_C5) < 0) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5); ++ if (sc6000_write(devptr, vport, COMMAND_C5) < 0) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_C5); + return -EIO; + } + + return 0; + } + +-static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg) ++static int sc6000_cfg_write(struct device *devptr, ++ char __iomem *vport, unsigned char softcfg) + { + +- if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); ++ if (sc6000_write(devptr, vport, WRITE_MDIRQ_CFG)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); + return -EIO; + } +- if (sc6000_write(vport, softcfg)) { +- snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); ++ if (sc6000_write(devptr, vport, softcfg)) { ++ dev_err(devptr, "%s: failed!\n", __func__); + return -EIO; + } + return 0; + } + +-static int sc6000_setup_board(char __iomem *vport, int config) ++static int sc6000_setup_board(struct device *devptr, ++ char __iomem *vport, int config) + { + int loop = 10; + + do { +- if (sc6000_write(vport, COMMAND_88)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", +- COMMAND_88); ++ if (sc6000_write(devptr, vport, COMMAND_88)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", ++ COMMAND_88); + return -EIO; + } + } while ((sc6000_wait_data(vport) < 0) && loop--); + + if (sc6000_read(vport) < 0) { +- snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n", +- COMMAND_88); ++ dev_err(devptr, "sc6000_read after CMD 0x%x: failed\n", ++ COMMAND_88); + return -EIO; + } + +- if (sc6000_cfg_write(vport, config)) ++ if (sc6000_cfg_write(devptr, vport, config)) + return -ENODEV; + + return 0; + } + +-static int sc6000_init_mss(char __iomem *vport, int config, ++static int sc6000_init_mss(struct device *devptr, ++ char __iomem *vport, int config, + char __iomem *vmss_port, int mss_config) + { +- if (sc6000_write(vport, DSP_INIT_MSS)) { +- snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n", +- DSP_INIT_MSS); ++ if (sc6000_write(devptr, vport, DSP_INIT_MSS)) { ++ dev_err(devptr, "%s [0x%x]: failed!\n", __func__, ++ DSP_INIT_MSS); + return -EIO; + } + + msleep(10); + +- if (sc6000_cfg_write(vport, config)) ++ if (sc6000_cfg_write(devptr, vport, config)) + return -EIO; + + iowrite8(mss_config, vmss_port); +@@ -348,7 +353,8 @@ static int sc6000_init_mss(char __iomem *vport, int config, + return 0; + } + +-static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, ++ char __iomem *vport, int *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -367,10 +373,11 @@ static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, + cfg[0] |= 0x02; + cfg[1] |= 0x80; /* enable WSS system */ + cfg[1] &= ~0x40; /* disable IDE */ +- snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]); ++ dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(char __iomem *vport, ++static int sc6000_init_board(struct device *devptr, ++ char __iomem *vport, + char __iomem *vmss_port, int dev) + { + char answer[15]; +@@ -384,14 +391,14 @@ static int sc6000_init_board(char __iomem *vport, + + err = sc6000_dsp_reset(vport); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n"); ++ dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); + if (err <= 0) { +- snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n"); ++ dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; + } + /* +@@ -399,52 +406,52 @@ static int sc6000_init_board(char __iomem *vport, + * if we have something different, we have to be warned. + */ + if (strncmp("SC-6000", answer, 7)) +- snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); ++ dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) { +- snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n"); ++ if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } +- printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", ++ dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + + /* set configuration */ +- sc6000_write(vport, COMMAND_5C); ++ sc6000_write(devptr, vport, COMMAND_5C); + if (sc6000_read(vport) < 0) + old = 1; + + if (!old) { + int cfg[2]; +- sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev], ++ sc6000_hw_cfg_encode(devptr, ++ vport, &cfg[0], port[dev], mpu_port[dev], + mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(vport, cfg) < 0) { +- snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n"); ++ if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); + return -EIO; + } + } +- err = sc6000_setup_board(vport, config); ++ err = sc6000_setup_board(devptr, vport, config); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); + return -ENODEV; + } + + sc6000_dsp_reset(vport); + + if (!old) { +- sc6000_write(vport, COMMAND_60); +- sc6000_write(vport, 0x02); ++ sc6000_write(devptr, vport, COMMAND_60); ++ sc6000_write(devptr, vport, 0x02); + sc6000_dsp_reset(vport); + } + +- err = sc6000_setup_board(vport, config); ++ err = sc6000_setup_board(devptr, vport, config); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); + return -ENODEV; + } +- err = sc6000_init_mss(vport, config, vmss_port, mss_config); ++ err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); + if (err < 0) { +- snd_printk(KERN_ERR "Cannot initialize " +- "Microsoft Sound System mode.\n"); ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); + return -ENODEV; + } + +@@ -491,39 +498,39 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + if (!enable[dev]) + return 0; + if (port[dev] == SNDRV_AUTO_PORT) { +- printk(KERN_ERR PFX "specify IO port\n"); ++ dev_err(devptr, "specify IO port\n"); + return 0; + } + if (mss_port[dev] == SNDRV_AUTO_PORT) { +- printk(KERN_ERR PFX "specify MSS port\n"); ++ dev_err(devptr, "specify MSS port\n"); + return 0; + } + if (port[dev] != 0x220 && port[dev] != 0x240) { +- printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n"); ++ dev_err(devptr, "Port must be 0x220 or 0x240\n"); + return 0; + } + if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) { +- printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n"); ++ dev_err(devptr, "MSS port must be 0x530 or 0xe80\n"); + return 0; + } + if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) { +- printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]); ++ dev_err(devptr, "invalid IRQ %d\n", irq[dev]); + return 0; + } + if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) { +- printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]); ++ dev_err(devptr, "invalid DMA %d\n", dma[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + (mpu_port[dev] & ~0x30L) != 0x300) { +- printk(KERN_ERR PFX "invalid MPU-401 port %lx\n", ++ dev_err(devptr, "invalid MPU-401 port %lx\n", + mpu_port[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 && + !sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) { +- printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); ++ dev_err(devptr, "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); + return 0; + } + return 1; +@@ -534,7 +541,7 @@ static void snd_sc6000_free(struct snd_card *card) + char __iomem *vport = (char __force __iomem *)card->private_data; + + if (vport) +- sc6000_setup_board(vport, 0); ++ sc6000_setup_board(card->dev, vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -558,7 +565,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); + if (xirq < 0) { +- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); ++ dev_err(devptr, "unable to find a free IRQ\n"); + return -EBUSY; + } + } +@@ -566,42 +573,39 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + if (xdma == SNDRV_AUTO_DMA) { + xdma = snd_legacy_find_free_dma(possible_dmas); + if (xdma < 0) { +- snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); ++ dev_err(devptr, "unable to find a free DMA\n"); + return -EBUSY; + } + } + + if (!devm_request_region(devptr, port[dev], 0x10, DRV_NAME)) { +- snd_printk(KERN_ERR PFX +- "I/O port region is already in use.\n"); ++ dev_err(devptr, "I/O port region is already in use.\n"); + return -EBUSY; + } + vport = devm_ioport_map(devptr, port[dev], 0x10); + if (!vport) { +- snd_printk(KERN_ERR PFX +- "I/O port cannot be iomapped.\n"); ++ dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } + card->private_data = (void __force *)vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +- snd_printk(KERN_ERR PFX +- "SC-6000 port I/O port region is already in use.\n"); ++ dev_err(devptr, ++ "SC-6000 port I/O port region is already in use.\n"); + return -EBUSY; + } + vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); + if (!vmss_port) { +- snd_printk(KERN_ERR PFX +- "MSS port I/O cannot be iomapped.\n"); ++ dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } + +- snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", +- port[dev], xirq, xdma, +- mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); ++ dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", ++ port[dev], xirq, xdma, ++ mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(vport, vmss_port, dev); ++ err = sc6000_init_board(devptr, vport, vmss_port, dev); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +@@ -613,25 +617,24 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + + err = snd_wss_pcm(chip, 0); + if (err < 0) { +- snd_printk(KERN_ERR PFX +- "error creating new WSS PCM device\n"); ++ dev_err(devptr, "error creating new WSS PCM device\n"); + return err; + } + err = snd_wss_mixer(chip); + if (err < 0) { +- snd_printk(KERN_ERR PFX "error creating new WSS mixer\n"); ++ dev_err(devptr, "error creating new WSS mixer\n"); + return err; + } + err = snd_sc6000_mixer(chip); + if (err < 0) { +- snd_printk(KERN_ERR PFX "the mixer rewrite failed\n"); ++ dev_err(devptr, "the mixer rewrite failed\n"); + return err; + } + if (snd_opl3_create(card, + 0x388, 0x388 + 2, + OPL3_HW_AUTO, 0, &opl3) < 0) { +- snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n", +- 0x388, 0x388 + 2); ++ dev_err(devptr, "no OPL device at 0x%x-0x%x ?\n", ++ 0x388, 0x388 + 2); + } else { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) +@@ -645,8 +648,8 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + MPU401_HW_MPU401, + mpu_port[dev], 0, + mpu_irq[dev], NULL) < 0) +- snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", +- mpu_port[dev]); ++ dev_err(devptr, "no MPU-401 device at 0x%lx ?\n", ++ mpu_port[dev]); + } + + strcpy(card->driver, DRV_NAME); +-- +2.53.0 + diff --git a/queue-5.15/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch b/queue-5.15/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch new file mode 100644 index 0000000000..fbb510b25c --- /dev/null +++ b/queue-5.15/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch @@ -0,0 +1,46 @@ +From 72d51c24bd632f7b2d830a77b771f4ab742d6bfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 09:25:41 +0100 +Subject: ARM: dts: mediatek: mt7623: fix efuse fallback compatible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafał Miłecki + +[ Upstream commit 5978ff33cc6f0988388a2830dc5cd2ea4e81f36a ] + +Fix following validation error: +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: compatible: 'oneOf' conditional failed, one must be fixed: + ['mediatek,mt7623-efuse', 'mediatek,mt8173-efuse'] is too long + 'mediatek,mt8173-efuse' was expected + 'mediatek,efuse' was expected + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: Unevaluated properties are not allowed ('compatible' was unexpected) + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# + +Fixes: 43c7a91b4b3a ("arm: dts: mt7623: add efuse nodes to the mt7623.dtsi file") +Signed-off-by: Rafał Miłecki +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/mt7623.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 64756888fd0d1..3c2064f7e50e2 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -329,7 +329,7 @@ sysirq: interrupt-controller@10200100 { + + efuse: efuse@10206000 { + compatible = "mediatek,mt7623-efuse", +- "mediatek,mt8173-efuse"; ++ "mediatek,efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; +-- +2.53.0 + diff --git a/queue-5.15/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch b/queue-5.15/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch new file mode 100644 index 0000000000..a426f9720b --- /dev/null +++ b/queue-5.15/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch @@ -0,0 +1,44 @@ +From 6063b8c7449449adb049aa472d589f3b68432f54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:51:11 +0800 +Subject: arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number + +From: Jun Yan + +[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ] + +Correct the interrupt number assigned to the Realtek PHY in the p230 + +following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm: +fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY +interrupt improvements [1]. + +[1] https://lore.kernel.org/all/20171202214037.17017-1-martin.blumenstingl@googlemail.com/ + +Fixes: b94d22d94ad2 ("ARM64: dts: meson-gx: add external PHY interrupt on some platforms") +Signed-off-by: Jun Yan +Reviewed-by: Martin Blumenstingl +Link: https://patch.msgid.link/20260330145111.115318-1-jerrysteve1101@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +index b2ab05c220903..67c952fe8abc1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +@@ -86,7 +86,8 @@ external_phy: ethernet-phy@0 { + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; +- interrupts = <29 IRQ_TYPE_LEVEL_LOW>; ++ /* MAC_INTR on GPIOZ_15 */ ++ interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + eee-broken-1000t; + }; + }; +-- +2.53.0 + diff --git a/queue-5.15/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch b/queue-5.15/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch new file mode 100644 index 0000000000..58ca68554e --- /dev/null +++ b/queue-5.15/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch @@ -0,0 +1,38 @@ +From 499e79a58d7cf414fda273bedc611f56f16fa0b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 18:33:11 +0100 +Subject: arm64: dts: qcom: sdm845-xiaomi-beryllium: Mark l1a regulator as + powered during boot + +From: David Heidelberg + +[ Upstream commit 3b0dd81eea6b7a239fce456ce4545af76f1a9715 ] + +The regulator must be on, since it provides the display subsystem and +therefore the bootloader had turned it on before Linux booted. + +Fixes: 77809cf74a8c ("arm64: dts: qcom: Add support for Xiaomi Poco F1 (Beryllium)") +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260320-beryllium-booton-v2-1-931d1be21eae@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +index 736951fabb7a9..a4ff9e67a1684 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +@@ -133,6 +133,7 @@ vreg_l1a_0p875: ldo1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l5a_0p8: ldo5 { +-- +2.53.0 + diff --git a/queue-5.15/asoc-codecs-ab8500-fix-casting-of-private-data.patch b/queue-5.15/asoc-codecs-ab8500-fix-casting-of-private-data.patch new file mode 100644 index 0000000000..10ab2a8857 --- /dev/null +++ b/queue-5.15/asoc-codecs-ab8500-fix-casting-of-private-data.patch @@ -0,0 +1,56 @@ +From 21ff088c843e650826798dddaf038a695363243a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 21:22:49 +0200 +Subject: ASoC: codecs: ab8500: Fix casting of private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian A. Ehrhardt + +[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ] + +ab8500_filter_controls[i].private_value is initialized using + + .private_value = (unsigned long)&(struct filter_control) + {.count = xcount, .min = xmin, .max = xmax} + +thus it's a pointer to a struct filter_control casted to unsigned long. + +So to get back that pointer .private_data must be cast back, not its +address. + +Fixes: 679d7abdc754 ("ASoC: codecs: Add AB8500 codec-driver") +Signed-off-by: Christian A. Ehrhardt +Signed-off-by: Uwe Kleine-König (The Capable Hub) +Link: https://patch.msgid.link/20260428192255.2294705-2-u.kleine-koenig@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/ab8500-codec.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c +index 5525e1ccab767..eaf12c28db83b 100644 +--- a/sound/soc/codecs/ab8500-codec.c ++++ b/sound/soc/codecs/ab8500-codec.c +@@ -2498,13 +2498,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) + return status; + } + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; + drvdata->anc_fir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; + drvdata->anc_iir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; + drvdata->sid_fir_values = (long *)fc->value; + + snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); +-- +2.53.0 + diff --git a/queue-5.15/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch b/queue-5.15/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch new file mode 100644 index 0000000000..08d8e1d047 --- /dev/null +++ b/queue-5.15/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch @@ -0,0 +1,189 @@ +From 08585a5fde2f32d1c093bba7f4146dbf9c0f43b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:26 +0800 +Subject: ASoC: fsl_easrc: Change the type for iec958 channel status controls + +From: Shengjiu Wang + +[ Upstream commit 47f28a5bd154a95d5aa563dde02a801bd32ddb81 ] + +Use the type SNDRV_CTL_ELEM_TYPE_IEC958 for iec958 channel status +controls, the original type will cause mixer-test to iterate all 32bit +values, which costs a lot of time. And using IEC958 type can reduce the +control numbers. + +Also enable pm runtime before updating registers to make the regmap cache +data align with the value in hardware. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-12-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 118 +++++++++++++++++++++++++++----------- + 1 file changed, 84 insertions(+), 34 deletions(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 5c83642f29826..6422f515f37c6 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -78,17 +78,47 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + return 0; + } + ++static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ + static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; +- unsigned int regval; ++ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ int ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]); ++ if (ret) ++ return ret; + +- regval = snd_soc_component_read(component, mc->regbase); ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]); ++ if (ret) ++ return ret; + +- ucontrol->value.integer.value[0] = regval; ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]); ++ if (ret) ++ return ret; + + return 0; + } +@@ -100,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); +- unsigned int regval = ucontrol->value.integer.value[0]; +- bool changed; ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ bool changed, changed_all = false; + int ret; + +- ret = regmap_update_bits_check(easrc->regmap, mc->regbase, +- GENMASK(31, 0), regval, &changed); +- if (ret != 0) ++ ret = pm_runtime_resume_and_get(component->dev); ++ if (ret) + return ret; + +- return changed; ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase), ++ GENMASK(31, 0), regval[0], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase), ++ GENMASK(31, 0), regval[1], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase), ++ GENMASK(31, 0), regval[2], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase), ++ GENMASK(31, 0), regval[3], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase), ++ GENMASK(31, 0), regval[4], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase), ++ GENMASK(31, 0), regval[5], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++err: ++ pm_runtime_put_autosuspend(component->dev); ++ ++ if (ret != 0) ++ return ret; ++ else ++ return changed_all; + } + + #define SOC_SINGLE_REG_RW(xname, xreg) \ + { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ +- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ ++ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \ + .put = fsl_easrc_set_reg, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ +@@ -146,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { + SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), + SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), + +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), ++ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0), ++ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1), ++ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2), ++ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3), + }; + + /* +-- +2.53.0 + diff --git a/queue-5.15/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch b/queue-5.15/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch new file mode 100644 index 0000000000..8871ea6512 --- /dev/null +++ b/queue-5.15/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch @@ -0,0 +1,39 @@ +From e4a2f4583587387ea4b1bfac652383a939a97015 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:24 +0800 +Subject: ASoC: fsl_easrc: Check the variable range in + fsl_easrc_iec958_put_bits() + +From: Shengjiu Wang + +[ Upstream commit 00541b86fb578d4949cfdd6aff1f82d43fcf07af ] + +Add check of input value's range in fsl_easrc_iec958_put_bits(), +otherwise the wrong value may be written from user space. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-10-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 792884006f6bc..c144f99927705 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, + unsigned int regval = ucontrol->value.integer.value[0]; + int ret; + ++ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT) ++ return -EINVAL; ++ + ret = (easrc_priv->bps_iec958[mc->regbase] != regval); + + easrc_priv->bps_iec958[mc->regbase] = regval; +-- +2.53.0 + diff --git a/queue-5.15/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch b/queue-5.15/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch new file mode 100644 index 0000000000..5914c8469d --- /dev/null +++ b/queue-5.15/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch @@ -0,0 +1,37 @@ +From 7e14214f40392bb65b4c2185ae4f3b0877e37c6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:25 +0800 +Subject: ASoC: fsl_easrc: Fix value type in fsl_easrc_iec958_get_bits() + +From: Shengjiu Wang + +[ Upstream commit aa21fe4a81458cf469c2615b08cbde5997dde25a ] + +The value type of controls "Context 0 IEC958 Bits Per Sample" should be +integer, not enumerated, the issue is found by the mixer-test. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-11-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index c144f99927705..5c83642f29826 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -73,7 +73,7 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + +- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; ++ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; + } +-- +2.53.0 + diff --git a/queue-5.15/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch b/queue-5.15/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch new file mode 100644 index 0000000000..71891f7120 --- /dev/null +++ b/queue-5.15/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch @@ -0,0 +1,52 @@ +From 5ea21c7870cc61e8891373e0c7bed0224f0322a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:22 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_arc_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 1b61c8103c9317a9c37fe544c2d83cee1c281149 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_arc_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the arc_mode +variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-8-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index ae5960b2b6a95..7475dcf58a366 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -97,10 +97,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); ++ int ret; + +- xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]); ++ if (val < 0 || val > 1) ++ return -EINVAL; + +- return 0; ++ ret = (xcvr->arc_mode != val); ++ ++ xcvr->arc_mode = val; ++ ++ return ret; + } + + static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-5.15/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch b/queue-5.15/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch new file mode 100644 index 0000000000..afcf4d4384 --- /dev/null +++ b/queue-5.15/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch @@ -0,0 +1,59 @@ +From fe68aa3cf9ddb44ac7bf218482674384e07d26f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:23 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 64a496ba976324615b845d60739dfcdae3d57434 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the mode variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-9-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index 7475dcf58a366..446a81b1e14c7 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -205,10 +205,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); + struct snd_soc_card *card = dai->component->card; + struct snd_soc_pcm_runtime *rtd; ++ int ret; ++ ++ if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC) ++ return -EINVAL; + +- xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); ++ ret = (xcvr->mode != val); ++ ++ xcvr->mode = val; + + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_ARC)); +@@ -218,7 +225,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + rtd = snd_soc_get_pcm_runtime(card, card->dai_link); + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = + (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0); +- return 0; ++ return ret; + } + + static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-5.15/asoc-sti-return-errors-from-regmap_field_alloc.patch b/queue-5.15/asoc-sti-return-errors-from-regmap_field_alloc.patch new file mode 100644 index 0000000000..9ae81ffa81 --- /dev/null +++ b/queue-5.15/asoc-sti-return-errors-from-regmap_field_alloc.patch @@ -0,0 +1,50 @@ +From 354558cc24bd6ef923f8ceeee7feaeff8800d93e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:33 +0100 +Subject: ASoC: sti: Return errors from regmap_field_alloc() + +From: Sander Vanheule + +[ Upstream commit 272aabef50bc3fe58edd26de000f4cdd41bdbe60 ] + +When regmap_field_alloc() fails, it can return an error. Specifically, +it will return PTR_ERR(-ENOMEM) when the allocation returns a NULL +pointer. The code then uses these allocations with a simple NULL check: + + if (player->clk_sel) { + // May dereference invalid pointer (-ENOMEM) + err = regmap_field_write(player->clk_sel, ...); + } + +Ensure initialization fails by forwarding the errors from +regmap_field_alloc(), thus avoiding the use of the invalid pointers. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-2-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index dd9013c476649..e5c4e5245b255 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1029,7 +1029,12 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + } + + player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ if (IS_ERR(player->clk_sel)) ++ return PTR_ERR(player->clk_sel); ++ + player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ if (IS_ERR(player->valid_sel)) ++ return PTR_ERR(player->valid_sel); + + return 0; + } +-- +2.53.0 + diff --git a/queue-5.15/asoc-sti-use-managed-regmap_field-allocations.patch b/queue-5.15/asoc-sti-use-managed-regmap_field-allocations.patch new file mode 100644 index 0000000000..a5718d1f32 --- /dev/null +++ b/queue-5.15/asoc-sti-use-managed-regmap_field-allocations.patch @@ -0,0 +1,45 @@ +From a960e64881a60af967f4916bdb08e0a3916aa200 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:34 +0100 +Subject: ASoC: sti: use managed regmap_field allocations + +From: Sander Vanheule + +[ Upstream commit 1696fad8b259a2d46e51cd6e17e4bcdbe02279fa ] + +The regmap_field objects allocated at player init are never freed and +may leak resources if the driver is removed. + +Switch to devm_regmap_field_alloc() to automatically limit the lifetime +of the allocations the lifetime of the device. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-3-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index e5c4e5245b255..da07f825f3c5f 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1028,11 +1028,11 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + return PTR_ERR(regmap); + } + +- player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]); + if (IS_ERR(player->clk_sel)) + return PTR_ERR(player->clk_sel); + +- player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]); + if (IS_ERR(player->valid_sel)) + return PTR_ERR(player->valid_sel); + +-- +2.53.0 + diff --git a/queue-5.15/backlight-sky81452-backlight-check-return-value-of-d.patch b/queue-5.15/backlight-sky81452-backlight-check-return-value-of-d.patch new file mode 100644 index 0000000000..4abb142de6 --- /dev/null +++ b/queue-5.15/backlight-sky81452-backlight-check-return-value-of-d.patch @@ -0,0 +1,46 @@ +From 5692314c28afa9fe9b922b2be34abf91da1d61b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:16:25 +0800 +Subject: backlight: sky81452-backlight: Check return value of + devm_gpiod_get_optional() in sky81452_bl_parse_dt() + +From: Chen Ni + +[ Upstream commit 797cc011ae02bda26f93d25a4442d7a1a77d84df ] + +The devm_gpiod_get_optional() function may return an ERR_PTR in case of +genuine GPIO acquisition errors, not just NULL which indicates the +legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the call in sky81452_bl_parse_dt(). On +error, return the error code to ensure proper failure handling rather +than proceeding with invalid pointers. + +Fixes: e1915eec54a6 ("backlight: sky81452: Convert to GPIO descriptors") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260203021625.578678-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/sky81452-backlight.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c +index c95e0de7f4e70..0cf1f588a3873 100644 +--- a/drivers/video/backlight/sky81452-backlight.c ++++ b/drivers/video/backlight/sky81452-backlight.c +@@ -204,6 +204,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( + pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode"); + pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift"); + pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); ++ if (IS_ERR(pdata->gpiod_enable)) ++ return dev_err_cast_probe(dev, pdata->gpiod_enable, ++ "failed to get gpio\n"); + + ret = of_property_count_u32_elems(np, "led-sources"); + if (ret < 0) { +-- +2.53.0 + diff --git a/queue-5.15/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch b/queue-5.15/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch new file mode 100644 index 0000000000..262abc21d5 --- /dev/null +++ b/queue-5.15/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch @@ -0,0 +1,60 @@ +From 08fb3fb8dc51d35525585c40a5fd22f6c78d2703 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 09:53:51 -0700 +Subject: bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst() + +From: Weiming Shi + +[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ] + +bareudp_fill_metadata_dst() passes bareudp->sock to +udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. +The socket is only created in bareudp_open() and NULLed in +bareudp_stop(), so calling this function while the device is down +triggers a NULL dereference via sock->sk. + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) + Call Trace: + + bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) + do_execute_actions (net/openvswitch/actions.c:901) + ovs_execute_actions (net/openvswitch/actions.c:1589) + ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) + genl_rcv_msg (net/netlink/genetlink.c:1209) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths +in the same driver. + +Fixes: 571912c69f0e ("net: UDP tunnel encapsulation module for tunnelling different protocols like MPLS, IP, NSH etc.") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426165350.1663137-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 4acca20084d36..2b03967c140c1 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -513,6 +513,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + ++ if (!sock) ++ return -ESHUTDOWN; ++ + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, + &saddr, info, IPPROTO_UDP, + use_cache); +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch b/queue-5.15/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch new file mode 100644 index 0000000000..00d2f46271 --- /dev/null +++ b/queue-5.15/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch @@ -0,0 +1,52 @@ +From 6a7f7a26dc51f9db39bfe034ade5bfea0dce88cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:42:59 +0300 +Subject: Bluetooth: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER + +From: Pauli Virtanen + +[ Upstream commit 5c7209a341ff2ac338b2b0375c34a307b37c9ac2 ] + +When protocol sets HCI_PROTO_DEFER, hci_conn_request_evt() calls +hci_connect_cfm(conn) without hdev->lock. Generally hci_connect_cfm() +assumes it is held, and if conn is deleted concurrently -> UAF. + +Only SCO and ISO set HCI_PROTO_DEFER and only for defer setup listen, +and HCI_EV_CONN_REQUEST is not generated for ISO. In the non-deferred +listening socket code paths, hci_connect_cfm(conn) is called with +hdev->lock held. + +Fix by holding the lock. + +Fixes: 70c464256310 ("Bluetooth: Refactor connection request handling") +Signed-off-by: Pauli Virtanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 8d6fc3a0c9a7e..dc79a362aef7f 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -2882,8 +2882,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) + + memcpy(conn->dev_class, ev->dev_class, 3); + +- hci_dev_unlock(hdev); +- + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; +@@ -2917,7 +2915,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) + hci_connect_cfm(conn, 0); + } + +- return; + unlock: + hci_dev_unlock(hdev); + } +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch b/queue-5.15/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch new file mode 100644 index 0000000000..55c1cf4682 --- /dev/null +++ b/queue-5.15/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch @@ -0,0 +1,49 @@ +From 4d5d36be535df14a7229982a12e9a9147e40e8e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:20 +0100 +Subject: Bluetooth: hci_ldisc: Clear HCI_UART_PROTO_INIT on error + +From: Jonathan Rissanen + +[ Upstream commit 68d39ea5e0adc9ecaea1ce8abd842ec972eb8718 ] + +When hci_register_dev() fails in hci_uart_register_dev() +HCI_UART_PROTO_INIT is not cleared before calling hu->proto->close(hu) +and setting hu->hdev to NULL. This means incoming UART data will reach +the protocol-specific recv handler in hci_uart_tty_receive() after +resources are freed. + +Clear HCI_UART_PROTO_INIT with a write lock before calling +hu->proto->close() and setting hu->hdev to NULL. The write lock ensures +all active readers have completed and no new reader can enter the +protocol recv path before resources are freed. + +This allows the protocol-specific recv functions to remove the +"HCI_UART_REGISTERED" guard without risking a null pointer dereference +if hci_register_dev() fails. + +Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization") +Signed-off-by: Jonathan Rissanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ldisc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index 46b37d825d185..dfd1d4a4d9fc2 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -691,6 +691,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device"); ++ percpu_down_write(&hu->proto_lock); ++ clear_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ percpu_up_write(&hu->proto_lock); + hu->proto->close(hu); + hu->hdev = NULL; + hci_free_dev(hdev); +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch b/queue-5.15/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch new file mode 100644 index 0000000000..5c0cd8791b --- /dev/null +++ b/queue-5.15/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch @@ -0,0 +1,48 @@ +From 6ad70c4b898f1ff7f9bf292c6020d27b2a987c4b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 23:47:41 +0800 +Subject: Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp + +From: Dudu Lu + +[ Upstream commit 42776497cdbc9a665b384a6dcb85f0d4bd927eab ] + +l2cap_ecred_reconf_rsp() calls l2cap_chan_del() without holding +l2cap_chan_lock(). Every other l2cap_chan_del() caller in the file +acquires the lock first. A remote BLE device can send a crafted +L2CAP ECRED reconfiguration response to corrupt the channel list +while another thread is iterating it. + +Add l2cap_chan_hold() and l2cap_chan_lock() before l2cap_chan_del(), +and l2cap_chan_unlock() and l2cap_chan_put() after, matching the +pattern used in l2cap_ecred_conn_rsp() and l2cap_conn_del(). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 9bb9301414f8e..a5db427c13de2 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6429,7 +6429,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + if (chan->ident != cmd->ident) + continue; + ++ l2cap_chan_hold(chan); ++ l2cap_chan_lock(chan); ++ + l2cap_chan_del(chan, ECONNRESET); ++ ++ l2cap_chan_unlock(chan); ++ l2cap_chan_put(chan); + } + + return 0; +-- +2.53.0 + diff --git a/queue-5.15/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch b/queue-5.15/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch new file mode 100644 index 0000000000..a2c40c3ec1 --- /dev/null +++ b/queue-5.15/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch @@ -0,0 +1,38 @@ +From 88bee6db312305ee66ef29fe17b8489aec14cb3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 14:34:13 -0400 +Subject: Bluetooth: L2CAP: Fix printing wrong information if SDU length + exceeds MTU + +From: Luiz Augusto von Dentz + +[ Upstream commit 15bf35a660eb82a49f8397fc3d3acada8dae13db ] + +The code was printing skb->len and sdu_len in the places where it should +be sdu_len and chan->imtu respectively to match the if conditions. + +Link: https://lore.kernel.org/linux-bluetooth/20260315132013.75ab40c5@kernel.org/T/#m1418f9c82eeff8510c1beaa21cf53af20db96c06 +Fixes: e1d9a6688986 ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU") +Signed-off-by: Luiz Augusto von Dentz +Reviewed-by: Paul Menzel +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 25a6a5fe7caf9..9bb9301414f8e 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7676,7 +7676,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + + if (sdu_len > chan->imtu) { + BT_ERR("Too big LE L2CAP SDU length: len %u > %u", +- skb->len, sdu_len); ++ sdu_len, chan->imtu); + l2cap_send_disconn_req(chan, ECONNRESET); + err = -EMSGSIZE; + goto failed; +-- +2.53.0 + diff --git a/queue-5.15/bpf-af_unix-use-batching-algorithm-in-bpf-unix-iter.patch b/queue-5.15/bpf-af_unix-use-batching-algorithm-in-bpf-unix-iter.patch new file mode 100644 index 0000000000..ca6439b671 --- /dev/null +++ b/queue-5.15/bpf-af_unix-use-batching-algorithm-in-bpf-unix-iter.patch @@ -0,0 +1,265 @@ +From f26a9bcbf680711c2e6699c7955d6c981cb3f3d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 Jan 2022 09:28:46 +0900 +Subject: bpf: af_unix: Use batching algorithm in bpf unix iter. + +From: Kuniyuki Iwashima + +[ Upstream commit 855d8e77ffb05be6e54c34dababccb20318aec00 ] + +The commit 04c7820b776f ("bpf: tcp: Bpf iter batching and lock_sock") +introduces the batching algorithm to iterate TCP sockets with more +consistency. + +This patch uses the same algorithm to iterate AF_UNIX sockets. + +Signed-off-by: Kuniyuki Iwashima +Link: https://lore.kernel.org/r/20220113002849.4384-3-kuniyu@amazon.co.jp +Signed-off-by: Alexei Starovoitov +Stable-dep-of: 4d328dd69538 ("bpf, sockmap: Fix af_unix iter deadlock") +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 184 +++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 177 insertions(+), 7 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index ea8fd8eb3ebc1..12a4c1542459c 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3300,6 +3300,15 @@ static const struct seq_operations unix_seq_ops = { + }; + + #if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) ++struct bpf_unix_iter_state { ++ struct seq_net_private p; ++ unsigned int cur_sk; ++ unsigned int end_sk; ++ unsigned int max_sk; ++ struct sock **batch; ++ bool st_bucket_done; ++}; ++ + struct bpf_iter__unix { + __bpf_md_ptr(struct bpf_iter_meta *, meta); + __bpf_md_ptr(struct unix_sock *, unix_sk); +@@ -3318,24 +3327,156 @@ static int unix_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta, + return bpf_iter_run_prog(prog, &ctx); + } + ++static int bpf_iter_unix_hold_batch(struct seq_file *seq, struct sock *start_sk) ++ ++{ ++ struct bpf_unix_iter_state *iter = seq->private; ++ unsigned int expected = 1; ++ struct sock *sk; ++ ++ sock_hold(start_sk); ++ iter->batch[iter->end_sk++] = start_sk; ++ ++ for (sk = sk_next(start_sk); sk; sk = sk_next(sk)) { ++ if (sock_net(sk) != seq_file_net(seq)) ++ continue; ++ ++ if (iter->end_sk < iter->max_sk) { ++ sock_hold(sk); ++ iter->batch[iter->end_sk++] = sk; ++ } ++ ++ expected++; ++ } ++ ++ spin_unlock(&unix_table_locks[start_sk->sk_hash]); ++ ++ return expected; ++} ++ ++static void bpf_iter_unix_put_batch(struct bpf_unix_iter_state *iter) ++{ ++ while (iter->cur_sk < iter->end_sk) ++ sock_put(iter->batch[iter->cur_sk++]); ++} ++ ++static int bpf_iter_unix_realloc_batch(struct bpf_unix_iter_state *iter, ++ unsigned int new_batch_sz) ++{ ++ struct sock **new_batch; ++ ++ new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz, ++ GFP_USER | __GFP_NOWARN); ++ if (!new_batch) ++ return -ENOMEM; ++ ++ bpf_iter_unix_put_batch(iter); ++ kvfree(iter->batch); ++ iter->batch = new_batch; ++ iter->max_sk = new_batch_sz; ++ ++ return 0; ++} ++ ++static struct sock *bpf_iter_unix_batch(struct seq_file *seq, ++ loff_t *pos) ++{ ++ struct bpf_unix_iter_state *iter = seq->private; ++ unsigned int expected; ++ bool resized = false; ++ struct sock *sk; ++ ++ if (iter->st_bucket_done) ++ *pos = set_bucket_offset(get_bucket(*pos) + 1, 1); ++ ++again: ++ /* Get a new batch */ ++ iter->cur_sk = 0; ++ iter->end_sk = 0; ++ ++ sk = unix_get_first(seq, pos); ++ if (!sk) ++ return NULL; /* Done */ ++ ++ expected = bpf_iter_unix_hold_batch(seq, sk); ++ ++ if (iter->end_sk == expected) { ++ iter->st_bucket_done = true; ++ return sk; ++ } ++ ++ if (!resized && !bpf_iter_unix_realloc_batch(iter, expected * 3 / 2)) { ++ resized = true; ++ goto again; ++ } ++ ++ return sk; ++} ++ ++static void *bpf_iter_unix_seq_start(struct seq_file *seq, loff_t *pos) ++{ ++ if (!*pos) ++ return SEQ_START_TOKEN; ++ ++ /* bpf iter does not support lseek, so it always ++ * continue from where it was stop()-ped. ++ */ ++ return bpf_iter_unix_batch(seq, pos); ++} ++ ++static void *bpf_iter_unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) ++{ ++ struct bpf_unix_iter_state *iter = seq->private; ++ struct sock *sk; ++ ++ /* Whenever seq_next() is called, the iter->cur_sk is ++ * done with seq_show(), so advance to the next sk in ++ * the batch. ++ */ ++ if (iter->cur_sk < iter->end_sk) ++ sock_put(iter->batch[iter->cur_sk++]); ++ ++ ++*pos; ++ ++ if (iter->cur_sk < iter->end_sk) ++ sk = iter->batch[iter->cur_sk]; ++ else ++ sk = bpf_iter_unix_batch(seq, pos); ++ ++ return sk; ++} ++ + static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + { + struct bpf_iter_meta meta; + struct bpf_prog *prog; + struct sock *sk = v; + uid_t uid; ++ bool slow; ++ int ret; + + if (v == SEQ_START_TOKEN) + return 0; + ++ slow = lock_sock_fast(sk); ++ ++ if (unlikely(sk_unhashed(sk))) { ++ ret = SEQ_SKIP; ++ goto unlock; ++ } ++ + uid = from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)); + meta.seq = seq; + prog = bpf_iter_get_info(&meta, false); +- return unix_prog_seq_show(prog, &meta, v, uid); ++ ret = unix_prog_seq_show(prog, &meta, v, uid); ++unlock: ++ unlock_sock_fast(sk, slow); ++ return ret; + } + + static void bpf_iter_unix_seq_stop(struct seq_file *seq, void *v) + { ++ struct bpf_unix_iter_state *iter = seq->private; + struct bpf_iter_meta meta; + struct bpf_prog *prog; + +@@ -3346,12 +3487,13 @@ static void bpf_iter_unix_seq_stop(struct seq_file *seq, void *v) + (void)unix_prog_seq_show(prog, &meta, v, 0); + } + +- unix_seq_stop(seq, v); ++ if (iter->cur_sk < iter->end_sk) ++ bpf_iter_unix_put_batch(iter); + } + + static const struct seq_operations bpf_iter_unix_seq_ops = { +- .start = unix_seq_start, +- .next = unix_seq_next, ++ .start = bpf_iter_unix_seq_start, ++ .next = bpf_iter_unix_seq_next, + .stop = bpf_iter_unix_seq_stop, + .show = bpf_iter_unix_seq_show, + }; +@@ -3400,11 +3542,39 @@ static struct pernet_operations unix_net_ops = { + DEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta, + struct unix_sock *unix_sk, uid_t uid) + ++#define INIT_BATCH_SZ 16 ++ ++static int bpf_iter_init_unix(void *priv_data, struct bpf_iter_aux_info *aux) ++{ ++ struct bpf_unix_iter_state *iter = priv_data; ++ int err; ++ ++ err = bpf_iter_init_seq_net(priv_data, aux); ++ if (err) ++ return err; ++ ++ err = bpf_iter_unix_realloc_batch(iter, INIT_BATCH_SZ); ++ if (err) { ++ bpf_iter_fini_seq_net(priv_data); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void bpf_iter_fini_unix(void *priv_data) ++{ ++ struct bpf_unix_iter_state *iter = priv_data; ++ ++ bpf_iter_fini_seq_net(priv_data); ++ kvfree(iter->batch); ++} ++ + static const struct bpf_iter_seq_info unix_seq_info = { + .seq_ops = &bpf_iter_unix_seq_ops, +- .init_seq_private = bpf_iter_init_seq_net, +- .fini_seq_private = bpf_iter_fini_seq_net, +- .seq_priv_size = sizeof(struct seq_net_private), ++ .init_seq_private = bpf_iter_init_unix, ++ .fini_seq_private = bpf_iter_fini_unix, ++ .seq_priv_size = sizeof(struct bpf_unix_iter_state), + }; + + static struct bpf_iter_reg unix_reg_info = { +-- +2.53.0 + diff --git a/queue-5.15/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch b/queue-5.15/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch new file mode 100644 index 0000000000..50414489be --- /dev/null +++ b/queue-5.15/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch @@ -0,0 +1,84 @@ +From 05bd7c16ee3f5b443d440a578b69cbf94f64ad2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:01:41 +0800 +Subject: bpf: allow UTF-8 literals in bpf_bprintf_prepare() + +From: Yihan Ding + +[ Upstream commit b960430ea8862ef37ce53c8bf74a8dc79d3f2404 ] + +bpf_bprintf_prepare() only needs ASCII parsing for conversion +specifiers. Plain text can safely carry bytes >= 0x80, so allow +UTF-8 literals outside '%' sequences while keeping ASCII control +bytes rejected and format specifiers ASCII-only. + +This keeps existing parsing rules for format directives unchanged, +while allowing helpers such as bpf_trace_printk() to emit UTF-8 +literal text. + +Update test_snprintf_negative() in the same commit so selftests keep +matching the new plain-text vs format-specifier split during bisection. + +Fixes: 48cac3f4a96d ("bpf: Implement formatted output helpers with bstr_printf") +Signed-off-by: Yihan Ding +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416120142.1420646-2-dingyihan@uniontech.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/helpers.c | 17 ++++++++++++++++- + .../testing/selftests/bpf/prog_tests/snprintf.c | 3 ++- + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index b40ca025d9a44..b4abe6aefef4c 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -796,7 +796,13 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, + data->buf = buffers->buf; + + for (i = 0; i < fmt_size; i++) { +- if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { ++ unsigned char c = fmt[i]; ++ ++ /* ++ * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass ++ * through unchanged, while still rejecting ASCII control bytes. ++ */ ++ if (isascii(c) && !isprint(c) && !isspace(c)) { + err = -EINVAL; + goto out; + } +@@ -818,6 +824,15 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, + * always access fmt[i + 1], in the worst case it will be a 0 + */ + i++; ++ c = fmt[i]; ++ /* ++ * The format parser below only understands ASCII conversion ++ * specifiers and modifiers, so reject non-ASCII after '%'. ++ */ ++ if (!isascii(c)) { ++ err = -EINVAL; ++ goto out; ++ } + + /* skip optional "[0 +-][num]" width formatting field */ + while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || +diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c +index 8fd1b4b29a0e0..14419b9407281 100644 +--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c ++++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c +@@ -116,7 +116,8 @@ void test_snprintf_negative(void) + ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5"); + ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6"); + ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7"); +- ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character"); ++ ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text"); ++ ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier"); + ASSERT_ERR(load_single_snprintf("\x1"), "non printable character"); + } + +-- +2.53.0 + diff --git a/queue-5.15/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch b/queue-5.15/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch new file mode 100644 index 0000000000..4d42381dcc --- /dev/null +++ b/queue-5.15/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch @@ -0,0 +1,96 @@ +From 9be351cebb0a6b47be2bbeaad23dd1a1acf6c7c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 07:33:52 -0700 +Subject: bpf, arm32: Reject BPF-to-BPF calls and callbacks in the JIT + +From: Puranjay Mohan + +[ Upstream commit e1d486445af3c392628532229f7ce5f5cf7891b6 ] + +The ARM32 BPF JIT does not support BPF-to-BPF function calls +(BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does +not reject them either. + +When a program with subprograms is loaded (e.g. libxdp's XDP +dispatcher uses __noinline__ subprograms, or any program using +callbacks like bpf_loop or bpf_for_each_map_elem), the verifier +invokes bpf_jit_subprogs() which calls bpf_int_jit_compile() +for each subprogram. + +For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT +silently emits code using the wrong address computation: + + func = __bpf_call_base + imm + +where imm is a pc-relative subprogram offset, producing a bogus +function pointer. + +For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and +loads the immediate as a normal 64-bit value without error. + +In both cases, build_body() reports success and a JIT image is +allocated. ARM32 lacks the jit_data/extra_pass mechanism needed +for the second JIT pass in bpf_jit_subprogs(). On the second +pass, bpf_int_jit_compile() performs a full fresh compilation, +allocating a new JIT binary and overwriting prog->bpf_func. The +first allocation is never freed. bpf_jit_subprogs() then detects +the function pointer changed and aborts with -ENOTSUPP, but the +original JIT binary has already been leaked. Each program +load/unload cycle leaks one JIT binary allocation, as reported +by kmemleak: + + unreferenced object 0xbf0a1000 (size 4096): + backtrace: + bpf_jit_binary_alloc+0x64/0xfc + bpf_int_jit_compile+0x14c/0x348 + bpf_jit_subprogs+0x4fc/0xa60 + +Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL +handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling +through to the existing 'notyet' path. This causes build_body() +to fail before any JIT binary is allocated, so +bpf_int_jit_compile() returns the original program unjitted. +bpf_jit_subprogs() then sees !prog->jited and cleanly falls +back to the interpreter with no leak. + +Acked-by: Daniel Borkmann +Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs") +Reported-by: Jonas Rebmann +Closes: https://lore.kernel.org/bpf/b63e9174-7a3d-4e22-8294-16df07a4af89@pengutronix.de +Tested-by: Jonas Rebmann +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417143353.838911-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm/net/bpf_jit_32.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c +index a903b26cde409..4fd6dd29e3286 100644 +--- a/arch/arm/net/bpf_jit_32.c ++++ b/arch/arm/net/bpf_jit_32.c +@@ -1609,6 +1609,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + { + u64 val = (u32)imm | (u64)insn[1].imm << 32; + ++ if (insn->src_reg == BPF_PSEUDO_FUNC) ++ goto notyet; ++ + emit_a32_mov_i64(dst, val, ctx); + + return 1; +@@ -1800,6 +1803,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + const s8 *r5 = bpf2a32[BPF_REG_5]; + const u32 func = (u32)__bpf_call_base + (u32)imm; + ++ if (insn->src_reg == BPF_PSEUDO_CALL) ++ goto notyet; ++ + emit_a32_mov_r64(true, r0, r1, ctx); + emit_a32_mov_r64(true, r1, r2, ctx); + emit_push_r64(r5, ctx); +-- +2.53.0 + diff --git a/queue-5.15/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch b/queue-5.15/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch new file mode 100644 index 0000000000..2e2f841e1f --- /dev/null +++ b/queue-5.15/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch @@ -0,0 +1,46 @@ +From ec4af8dbc9a7d5ec5feb0fa49acf5cbf6a28069a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 May 2024 12:19:01 +0200 +Subject: bpf, devmap: Remove unnecessary if check in for loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thorsten Blum + +[ Upstream commit 2317dc2c22cc353b699c7d1db47b2fe91f54055c ] + +The iterator variable dst cannot be NULL and the if check can be removed. +Remove it and fix the following Coccinelle/coccicheck warning reported +by itnull.cocci: + + ERROR: iterator variable bound on line 762 cannot be NULL + +Signed-off-by: Thorsten Blum +Signed-off-by: Daniel Borkmann +Reviewed-by: Toke Høiland-Jørgensen +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/bpf/20240529101900.103913-2-thorsten.blum@toblux.com +Stable-dep-of: 8ed82f807bb0 ("bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path") +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 2bfdca506a4de..6274cf7011901 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -758,9 +758,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_safe(dst, next, head, index_hlist) { +- if (!dst) +- continue; +- + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-5.15/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch b/queue-5.15/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch new file mode 100644 index 0000000000..1456b28965 --- /dev/null +++ b/queue-5.15/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch @@ -0,0 +1,43 @@ +From c71b73b9bd292ebc82141acaec1b0e43638c436b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 20:23:33 +0800 +Subject: bpf: Drop task_to_inode and inet_conn_established from lsm sleepable + hooks + +From: Jiayuan Chen + +[ Upstream commit beaf0e96b1da74549a6cabd040f9667d83b2e97e ] + +bpf_lsm_task_to_inode() is called under rcu_read_lock() and +bpf_lsm_inet_conn_established() is called from softirq context, so +neither hook can be used by sleepable LSM programs. + +Fixes: 423f16108c9d8 ("bpf: Augment the set of sleepable LSM hooks") +Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/3ab69731-24d1-431a-a351-452aafaaf2a5@std.uestc.edu.cn/T/#u +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260407122334.344072-1-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_lsm.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c +index c9e785ab62cf0..02913d8610414 100644 +--- a/kernel/bpf/bpf_lsm.c ++++ b/kernel/bpf/bpf_lsm.c +@@ -211,7 +211,6 @@ BTF_ID(func, bpf_lsm_task_getsecid_subj) + BTF_ID(func, bpf_lsm_task_getsecid_obj) + BTF_ID(func, bpf_lsm_task_prctl) + BTF_ID(func, bpf_lsm_task_setscheduler) +-BTF_ID(func, bpf_lsm_task_to_inode) + BTF_ID(func, bpf_lsm_userns_create) + BTF_SET_END(sleepable_lsm_hooks) + +-- +2.53.0 + diff --git a/queue-5.15/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch b/queue-5.15/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch new file mode 100644 index 0000000000..d8e22aa72d --- /dev/null +++ b/queue-5.15/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch @@ -0,0 +1,47 @@ +From af294200c8d20e639c8564b216cca8d0bf07f948 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 21:29:50 +0800 +Subject: bpf: fix end-of-list detection in cgroup_storage_get_next_key() + +From: Weiming Shi + +[ Upstream commit 5828b9e5b272ecff7cf5d345128d3de7324117f7 ] + +list_next_entry() never returns NULL -- when the current element is the +last entry it wraps to the list head via container_of(). The subsequent +NULL check is therefore dead code and get_next_key() never returns +-ENOENT for the last element, instead reading storage->key from a bogus +pointer that aliases internal map fields and copying the result to +userspace. + +Replace it with list_entry_is_head() so the function correctly returns +-ENOENT when there are no more entries. + +Fixes: de9cbbaadba5 ("bpf: introduce cgroup storage maps") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Sun Jian +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260403132951.43533-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/local_storage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c +index 035e9e3a7132e..85e1b5fba0d57 100644 +--- a/kernel/bpf/local_storage.c ++++ b/kernel/bpf/local_storage.c +@@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, + goto enoent; + + storage = list_next_entry(storage, list_map); +- if (!storage) ++ if (list_entry_is_head(storage, &map->list, list_map)) + goto enoent; + } else { + storage = list_first_entry(&map->list, +-- +2.53.0 + diff --git a/queue-5.15/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch b/queue-5.15/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch new file mode 100644 index 0000000000..de1e055c22 --- /dev/null +++ b/queue-5.15/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch @@ -0,0 +1,46 @@ +From a77b6e17c30269134303e1aa24e500b1ee978ef3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:27:19 +0200 +Subject: bpf: Fix precedence bug in convert_bpf_ld_abs alignment check + +From: Daniel Borkmann + +[ Upstream commit e5f635edd393aeaa7cad9e42831d397e6e2e1eed ] + +Fix an operator precedence issue in convert_bpf_ld_abs() where the +expression offset + ip_align % size evaluates as offset + (ip_align % size) +due to % having higher precedence than +. That latter evaluation does +not make any sense. The intended check is (offset + ip_align) % size == 0 +to verify that the packet load offset is properly aligned for direct +access. + +With NET_IP_ALIGN == 2, the bug causes the inline fast-path for direct +packet loads to almost never be taken on !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +platforms. This forces nearly all cBPF BPF_LD_ABS packet loads through +the bpf_skb_load_helper slow path on the affected archs. + +Fixes: e0cea7ce988c ("bpf: implement ld_abs/ld_ind in native bpf") +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260416122719.661033-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 87447a7843b5a..3cab7f83fa661 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -490,7 +490,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp) + ((unaligned_ok && offset >= 0) || + (!unaligned_ok && offset >= 0 && + offset + ip_align >= 0 && +- offset + ip_align % size == 0))) { ++ (offset + ip_align) % size == 0))) { + bool ldx_off_ok = offset <= S16_MAX; + + *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H); +-- +2.53.0 + diff --git a/queue-5.15/bpf-lsm-make-bpf_lsm_userns_create-sleepable.patch b/queue-5.15/bpf-lsm-make-bpf_lsm_userns_create-sleepable.patch new file mode 100644 index 0000000000..dc24b0802b --- /dev/null +++ b/queue-5.15/bpf-lsm-make-bpf_lsm_userns_create-sleepable.patch @@ -0,0 +1,40 @@ +From afb2520fadd4c543140512b7c597dc0ecb6b09a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Aug 2022 11:20:26 -0500 +Subject: bpf-lsm: Make bpf_lsm_userns_create() sleepable + +From: Frederick Lawler + +[ Upstream commit 401e64b3a4af4c7a2f6a00337232a3cf0bb757ed ] + +Users may want to audit calls to security_create_user_ns() and access +user space memory. Also create_user_ns() runs without +pagefault_disabled(). Therefore, make bpf_lsm_userns_create() sleepable +for mandatory access control policies. + +Acked-by: Alexei Starovoitov +Acked-by: Christian Brauner (Microsoft) +Acked-by: KP Singh +Signed-off-by: Frederick Lawler +Signed-off-by: Paul Moore +Stable-dep-of: beaf0e96b1da ("bpf: Drop task_to_inode and inet_conn_established from lsm sleepable hooks") +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_lsm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c +index 06062370c3b81..c9e785ab62cf0 100644 +--- a/kernel/bpf/bpf_lsm.c ++++ b/kernel/bpf/bpf_lsm.c +@@ -212,6 +212,7 @@ BTF_ID(func, bpf_lsm_task_getsecid_obj) + BTF_ID(func, bpf_lsm_task_prctl) + BTF_ID(func, bpf_lsm_task_setscheduler) + BTF_ID(func, bpf_lsm_task_to_inode) ++BTF_ID(func, bpf_lsm_userns_create) + BTF_SET_END(sleepable_lsm_hooks) + + bool bpf_lsm_is_sleepable_hook(u32 btf_id) +-- +2.53.0 + diff --git a/queue-5.15/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch b/queue-5.15/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch new file mode 100644 index 0000000000..925843753e --- /dev/null +++ b/queue-5.15/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch @@ -0,0 +1,74 @@ +From 494dc731a5c62be99e5303f226399713fb547b33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 00:12:20 +0800 +Subject: bpf: reject negative CO-RE accessor indices in bpf_core_parse_spec() + +From: Weiming Shi + +[ Upstream commit 1c22483a2c4bbf747787f328392ca3e68619c4dc ] + +CO-RE accessor strings are colon-separated indices that describe a path +from a root BTF type to a target field, e.g. "0:1:2" walks through +nested struct members. bpf_core_parse_spec() parses each component with +sscanf("%d"), so negative values like -1 are silently accepted. The +subsequent bounds checks (access_idx >= btf_vlen(t)) only guard the +upper bound and always pass for negative values because C integer +promotion converts the __u16 btf_vlen result to int, making the +comparison (int)(-1) >= (int)(N) false for any positive N. + +When -1 reaches btf_member_bit_offset() it gets cast to u32 0xffffffff, +producing an out-of-bounds read far past the members array. A crafted +BPF program with a negative CO-RE accessor on any struct that exists in +vmlinux BTF (e.g. task_struct) crashes the kernel deterministically +during BPF_PROG_LOAD on any system with CONFIG_DEBUG_INFO_BTF=y +(default on major distributions). The bug is reachable with CAP_BPF: + + BUG: unable to handle page fault for address: ffffed11818b6626 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + Oops: Oops: 0000 [#1] SMP KASAN NOPTI + CPU: 0 UID: 0 PID: 85 Comm: poc Not tainted 7.0.0-rc6 #18 PREEMPT(full) + RIP: 0010:bpf_core_parse_spec (tools/lib/bpf/relo_core.c:354) + RAX: 00000000ffffffff + Call Trace: + + bpf_core_calc_relo_insn (tools/lib/bpf/relo_core.c:1321) + bpf_core_apply (kernel/bpf/btf.c:9507) + check_core_relo (kernel/bpf/verifier.c:19475) + bpf_check (kernel/bpf/verifier.c:26031) + bpf_prog_load (kernel/bpf/syscall.c:3089) + __sys_bpf (kernel/bpf/syscall.c:6228) + + +CO-RE accessor indices are inherently non-negative (struct member index, +array element index, or enumerator index), so reject them immediately +after parsing. + +Fixes: ddc7c3042614 ("libbpf: implement BPF CO-RE offset relocation algorithm") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Emil Tsalapatis +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260404161221.961828-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/relo_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c +index 4016ed492d0c2..5976a8e6c7d19 100644 +--- a/tools/lib/bpf/relo_core.c ++++ b/tools/lib/bpf/relo_core.c +@@ -184,6 +184,8 @@ static int bpf_core_parse_spec(const struct btf *btf, + ++spec_str; + if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1) + return -EINVAL; ++ if (access_idx < 0) ++ return -EINVAL; + if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) + return -E2BIG; + spec_str += parsed_len; +-- +2.53.0 + diff --git a/queue-5.15/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch b/queue-5.15/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch new file mode 100644 index 0000000000..48ef0b22f3 --- /dev/null +++ b/queue-5.15/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch @@ -0,0 +1,72 @@ +From 82896bdecfed3807854c02610723d5e10cdd0027 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 11:46:22 +0800 +Subject: bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb + +From: Sun Jian + +[ Upstream commit 12bec2bd4b76d81c5d3996bd14ec1b7f4d983747 ] + +bpf_prog_test_run_skb() calls eth_type_trans() first and then uses +skb->protocol to initialize sk family and address fields for the test +run. + +For IPv4 and IPv6 packets, it may access ip_hdr(skb) or ipv6_hdr(skb) +even when the provided test input only contains an Ethernet header. + +Reject the input earlier if the Ethernet frame carries IPv4/IPv6 +EtherType but the L3 header is too short. + +Fold the IPv4/IPv6 header length checks into the existing protocol +switch and return -EINVAL before accessing the network headers. + +Fixes: fa5cb548ced6 ("bpf: Setup socket family and addresses in bpf_prog_test_run_skb") +Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc +Signed-off-by: Sun Jian +Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 86c3aca9fa144..f3ae76919c71f 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -645,19 +645,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + switch (skb->protocol) { + case htons(ETH_P_IP): +- sk->sk_family = AF_INET; +- if (sizeof(struct iphdr) <= skb_headlen(skb)) { +- sk->sk_rcv_saddr = ip_hdr(skb)->saddr; +- sk->sk_daddr = ip_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct iphdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET; ++ sk->sk_rcv_saddr = ip_hdr(skb)->saddr; ++ sk->sk_daddr = ip_hdr(skb)->daddr; + break; + #if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +- sk->sk_family = AF_INET6; +- if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { +- sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; +- sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET6; ++ sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; ++ sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + break; + #endif + default: +-- +2.53.0 + diff --git a/queue-5.15/bpf-sockmap-fix-af_unix-iter-deadlock.patch b/queue-5.15/bpf-sockmap-fix-af_unix-iter-deadlock.patch new file mode 100644 index 0000000000..8a933e3b15 --- /dev/null +++ b/queue-5.15/bpf-sockmap-fix-af_unix-iter-deadlock.patch @@ -0,0 +1,101 @@ +From 3a42e6c7f578941e6840e181bcfe8a39912cd28d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:16 +0200 +Subject: bpf, sockmap: Fix af_unix iter deadlock + +From: Michal Luczaj + +[ Upstream commit 4d328dd695383224aa750ddee6b4ad40c0f8d205 ] + +bpf_iter_unix_seq_show() may deadlock when lock_sock_fast() takes the fast +path and the iter prog attempts to update a sockmap. Which ends up spinning +at sock_map_update_elem()'s bh_lock_sock(): + +WARNING: possible recursive locking detected +test_progs/1393 is trying to acquire lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: sock_map_update_elem+0xdb/0x1f0 + +but task is already holding lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + +other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(slock-AF_UNIX); + lock(slock-AF_UNIX); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + +4 locks held by test_progs/1393: + #0: ffff88814b59c790 (&p->lock){+.+.}-{4:4}, at: bpf_seq_read+0x59/0x10d0 + #1: ffff88811ec25fd8 (sk_lock-AF_UNIX){+.+.}-{0:0}, at: bpf_seq_read+0x42c/0x10d0 + #2: ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + #3: ffffffff85a6a7c0 (rcu_read_lock){....}-{1:3}, at: bpf_iter_run_prog+0x51d/0xb00 + +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_deadlock_bug.cold+0xc0/0xce + __lock_acquire+0x130f/0x2590 + lock_acquire+0x14e/0x2b0 + _raw_spin_lock+0x30/0x40 + sock_map_update_elem+0xdb/0x1f0 + bpf_prog_2d0075e5d9b721cd_dump_unix+0x55/0x4f4 + bpf_iter_run_prog+0x5b9/0xb00 + bpf_iter_unix_seq_show+0x1f7/0x2e0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-2-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 12a4c1542459c..8584dc9592e05 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3452,15 +3452,14 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + struct bpf_prog *prog; + struct sock *sk = v; + uid_t uid; +- bool slow; + int ret; + + if (v == SEQ_START_TOKEN) + return 0; + +- slow = lock_sock_fast(sk); ++ lock_sock(sk); + +- if (unlikely(sk_unhashed(sk))) { ++ if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; + goto unlock; + } +@@ -3470,7 +3469,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: +- unlock_sock_fast(sk, slow); ++ release_sock(sk); + return ret; + } + +-- +2.53.0 + diff --git a/queue-5.15/bpf-sockmap-take-state-lock-for-af_unix-iter.patch b/queue-5.15/bpf-sockmap-take-state-lock-for-af_unix-iter.patch new file mode 100644 index 0000000000..7238f81f09 --- /dev/null +++ b/queue-5.15/bpf-sockmap-take-state-lock-for-af_unix-iter.patch @@ -0,0 +1,115 @@ +From 44effb6950881baa8012e81a6f76dc3a96b3f504 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:19 +0200 +Subject: bpf, sockmap: Take state lock for af_unix iter + +From: Michal Luczaj + +[ Upstream commit 64c2f93fc3254d3bf5de4445fb732ee5c451edb6 ] + +When a BPF iterator program updates a sockmap, there is a race condition in +unix_stream_bpf_update_proto() where the `peer` pointer can become stale[1] +during a state transition TCP_ESTABLISHED -> TCP_CLOSE. + + CPU0 bpf CPU1 close + -------- ---------- +// unix_stream_bpf_update_proto() +sk_pair = unix_peer(sk) +if (unlikely(!sk_pair)) + return -EINVAL; + // unix_release_sock() + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) +sock_hold(sk_pair) // UaF + +More practically, this fix guarantees that the iterator program is +consistently provided with a unix socket that remains stable during +iterator execution. + +[1]: +BUG: KASAN: slab-use-after-free in unix_stream_bpf_update_proto+0x155/0x490 +Write of size 4 at addr ffff8881178c9a00 by task test_progs/2231 +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x170/0x4f3 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x155/0x490 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Allocated by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + __kasan_slab_alloc+0x63/0x80 + kmem_cache_alloc_noprof+0x1d5/0x680 + sk_prot_alloc+0x59/0x210 + sk_alloc+0x34/0x470 + unix_create1+0x86/0x8a0 + unix_stream_connect+0x318/0x15b0 + __sys_connect+0xfd/0x130 + __x64_sys_connect+0x72/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Freed by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + kasan_save_free_info+0x3b/0x70 + __kasan_slab_free+0x47/0x70 + kmem_cache_free+0x11c/0x590 + __sk_destruct+0x432/0x6e0 + unix_release_sock+0x9b3/0xf60 + unix_release+0x8a/0xf0 + __sock_release+0xb0/0x270 + sock_close+0x18/0x20 + __fput+0x36e/0xac0 + fput_close_sync+0xe5/0x1a0 + __x64_sys_close+0x7d/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-5-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 8584dc9592e05..a2a19c31ebddd 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3458,6 +3458,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + return 0; + + lock_sock(sk); ++ unix_state_lock(sk); + + if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; +@@ -3469,6 +3470,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: ++ unix_state_unlock(sk); + release_sock(sk); + return ret; + } +-- +2.53.0 + diff --git a/queue-5.15/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch b/queue-5.15/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch new file mode 100644 index 0000000000..74ca7364d4 --- /dev/null +++ b/queue-5.15/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch @@ -0,0 +1,71 @@ +From 8bf978219356a60e98703727965856850316d05c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 07:26:45 +0000 +Subject: bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path + +From: David Carlier + +[ Upstream commit 8ed82f807bb09d2c8455aaa665f2c6cb17bc6a19 ] + +The DEVMAP_HASH branch in dev_map_redirect_multi() uses +hlist_for_each_entry_safe() to iterate hash buckets, but this function +runs under RCU protection (called from xdp_do_generic_redirect_map() +in softirq context). Concurrent writers (__dev_map_hash_update_elem, +dev_map_hash_delete_elem) modify the list using RCU primitives +(hlist_add_head_rcu, hlist_del_rcu). + +hlist_for_each_entry_safe() performs plain pointer dereferences without +rcu_dereference(), missing the acquire barrier needed to pair with +writers' rcu_assign_pointer(). On weakly-ordered architectures (ARM64, +POWER), a reader can observe a partially-constructed node. It also +defeats CONFIG_PROVE_RCU lockdep validation and KCSAN data-race +detection. + +Replace with hlist_for_each_entry_rcu() using rcu_read_lock_bh_held() +as the lockdep condition, consistent with the rcu_dereference_check() +used in the DEVMAP (non-hash) branch of the same functions. Also fix +the same incorrect lockdep_is_held(&dtab->index_lock) condition in +dev_map_enqueue_multi(), where the lock is not held either. + +Fixes: e624d4ed4aa8 ("xdp: Extend xdp_redirect_map with broadcast support") +Signed-off-by: David Carlier +Signed-off-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260320072645.16731-1-devnexen@gmail.com +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 6274cf7011901..6ad4b068abc77 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -635,7 +635,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_rcu(dst, head, index_hlist, +- lockdep_is_held(&dtab->index_lock)) { ++ rcu_read_lock_bh_held()) { + if (!is_valid_dst(dst, xdpf)) + continue; + +@@ -717,7 +717,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + struct bpf_dtab_netdev *dst, *last_dst = NULL; + int excluded_devices[1+MAX_NEST_DEV]; + struct hlist_head *head; +- struct hlist_node *next; + int num_excluded = 0; + unsigned int i; + int err; +@@ -757,7 +756,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + } else { /* BPF_MAP_TYPE_DEVMAP_HASH */ + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); +- hlist_for_each_entry_safe(dst, next, head, index_hlist) { ++ hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) { + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-5.15/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch b/queue-5.15/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch new file mode 100644 index 0000000000..94f41ff40f --- /dev/null +++ b/queue-5.15/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch @@ -0,0 +1,48 @@ +From b07c1e306faa7393cc8c260aef67cc8a92eeb4be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:15:23 +0100 +Subject: btrfs: fix double-decrement of bytes_may_use in + submit_one_async_extent() + +From: Mark Harmstone + +[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ] + +submit_one_async_extent() calls btrfs_reserve_extent(), which decrements +bytes_may_use. If the call btrfs_create_io_em() fails, we jump to +out_free_reserve, which calls extent_clear_unlock_delalloc(). + +Because we're specifying EXTENT_DO_ACCOUNTING, i.e. +EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases +bytes_may_use again. This can lead to problems later on, as an initial +write can fail only for the writeback to silently ENOSPC. + +Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. +This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved +extents in cow_one_range()"), which is the same fix in cow_one_range(). + +Fixes: 151a41bc46df ("Btrfs: fix what bits we clear when erroring out from delalloc") +Reviewed-by: Qu Wenruo +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 27aaa5064ff7e..181c2d9041d1a 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1001,7 +1001,7 @@ static noinline void submit_compressed_extents(struct async_chunk *async_chunk) + async_extent->ram_size - 1, + NULL, EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | +- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, ++ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, + PAGE_UNLOCK | PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK | PAGE_SET_ERROR); + free_async_extent_pages(async_extent); +-- +2.53.0 + diff --git a/queue-5.15/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch b/queue-5.15/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch new file mode 100644 index 0000000000..a25f6b8eaf --- /dev/null +++ b/queue-5.15/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch @@ -0,0 +1,237 @@ +From c40a90e796030a04a98d5a40167f10dd43b07c41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:01:39 +0100 +Subject: cdrom, scsi: sr: propagate read-only status to block layer via + set_disk_ro() + +From: Daan De Meyer + +[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ] + +The cdrom core never calls set_disk_ro() for a registered device, so +BLKROGET on a CD-ROM device always returns 0 (writable), even when the +drive has no write capabilities and writes will inevitably fail. This +causes problems for userspace that relies on BLKROGET to determine +whether a block device is read-only. For example, systemd's loop device +setup uses BLKROGET to decide whether to create a loop device with +LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the +loop device to the CD-ROM and fail with I/O errors. systemd-fsck +similarly checks BLKROGET to decide whether to run fsck in no-repair +mode (-n). + +The write-capability bits in cdi->mask come from two different sources: +CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE +SENSE capabilities page (page 0x2A) before register_cdrom() is called, +while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command +and were only probed by cdrom_open_write() at device open time. This +meant that any attempt to compute the writable state from the full +mask at probe time was incorrect, because the GET CONFIGURATION bits +were still unset (and cdi->mask is initialized such that capabilities +are assumed present). + +Fix this by factoring the GET CONFIGURATION probing out of +cdrom_open_write() into a new exported helper, +cdrom_probe_write_features(), and having sr call it from sr_probe() +right after get_capabilities() has populated the MODE SENSE bits. +register_cdrom() then calls set_disk_ro() based on the full +write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) +so the block layer reflects the drive's actual write support. The +feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with +RT=00) report drive-level capabilities that are persistent across +media, so a single probe before register_cdrom() is sufficient and the +redundant probe at open time is dropped. + +With set_disk_ro() now accurate, the long-vestigial cd->writeable flag +in sr can go: get_capabilities() used to set cd->writeable based on +the same four mask bits, but because CDC_MRW_W and CDC_RAM default to +"capability present" in cdi->mask and aren't touched by MODE SENSE, +the condition that gated cd->writeable was always true, making it +unconditionally 1. Replace the corresponding gate in sr_init_command() +with get_disk_ro(cd->disk), which turns a previously no-op check into +a real one and also catches kernel-internal bio writers that bypass +blkdev_write_iter()'s bdev_read_only() check. + +The sd driver (SCSI disks) does not have this problem because it +checks the MODE SENSE Write Protect bit and calls set_disk_ro() +accordingly. The sr driver cannot use the same approach because the +MMC specification does not define the WP bit in the MODE SENSE +device-specific parameter byte for CD-ROM devices. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Daan De Meyer +Reviewed-by: Phillip Potter +Reviewed-by: Martin K. Petersen +Signed-off-by: Phillip Potter +Link: https://patch.msgid.link/20260427210139.1400-2-phil@philpotter.co.uk +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- + drivers/scsi/sr.c | 11 ++----- + drivers/scsi/sr.h | 1 - + include/linux/cdrom.h | 1 + + 4 files changed, 51 insertions(+), 35 deletions(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index bd2e5b1560f52..9ccf6abfff8db 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -636,6 +636,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) + + WARN_ON(!cdo->generic_packet); + ++ /* ++ * Propagate the drive's write support to the block layer so BLKROGET ++ * reflects actual write capability. Drivers that use GET CONFIGURATION ++ * features (CDC_MRW_W, CDC_RAM) must have called ++ * cdrom_probe_write_features() before register_cdrom() so the mask is ++ * complete here. ++ */ ++ set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | ++ CDC_CD_RW)); ++ + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + mutex_lock(&cdrom_mutex); + list_add(&cdi->list, &cdrom_list); +@@ -747,6 +757,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) + return 0; + } + ++/* ++ * Probe write-related MMC features via GET CONFIGURATION and update ++ * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE ++ * capabilities page (e.g. sr) should call this after those MODE SENSE bits ++ * have been set but before register_cdrom(), so that the full set of ++ * write-capability bits is known by the time register_cdrom() decides on the ++ * initial read-only state of the disk. ++ */ ++void cdrom_probe_write_features(struct cdrom_device_info *cdi) ++{ ++ int mrw, mrw_write, ram_write; ++ ++ mrw = 0; ++ if (!cdrom_is_mrw(cdi, &mrw_write)) ++ mrw = 1; ++ ++ if (CDROM_CAN(CDC_MO_DRIVE)) ++ ram_write = 1; ++ else ++ (void) cdrom_is_random_writable(cdi, &ram_write); ++ ++ if (mrw) ++ cdi->mask &= ~CDC_MRW; ++ else ++ cdi->mask |= CDC_MRW; ++ ++ if (mrw_write) ++ cdi->mask &= ~CDC_MRW_W; ++ else ++ cdi->mask |= CDC_MRW_W; ++ ++ if (ram_write) ++ cdi->mask &= ~CDC_RAM; ++ else ++ cdi->mask |= CDC_RAM; ++} ++EXPORT_SYMBOL(cdrom_probe_write_features); ++ + static int cdrom_media_erasable(struct cdrom_device_info *cdi) + { + disc_information di; +@@ -899,33 +947,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) + */ + static int cdrom_open_write(struct cdrom_device_info *cdi) + { +- int mrw, mrw_write, ram_write; + int ret = 1; + +- mrw = 0; +- if (!cdrom_is_mrw(cdi, &mrw_write)) +- mrw = 1; +- +- if (CDROM_CAN(CDC_MO_DRIVE)) +- ram_write = 1; +- else +- (void) cdrom_is_random_writable(cdi, &ram_write); +- +- if (mrw) +- cdi->mask &= ~CDC_MRW; +- else +- cdi->mask |= CDC_MRW; +- +- if (mrw_write) +- cdi->mask &= ~CDC_MRW_W; +- else +- cdi->mask |= CDC_MRW_W; +- +- if (ram_write) +- cdi->mask &= ~CDC_RAM; +- else +- cdi->mask |= CDC_RAM; +- + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index 529d4169b373b..e23406e025dc0 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -431,7 +431,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) + + switch (req_op(rq)) { + case REQ_OP_WRITE: +- if (!cd->writeable) ++ if (get_disk_ro(cd->disk)) + goto out; + SCpnt->cmnd[0] = WRITE_10; + cd->cdi.media_written = 1; +@@ -713,6 +713,7 @@ static int sr_probe(struct device *dev) + error = -ENOMEM; + if (get_capabilities(cd)) + goto fail_minor; ++ cdrom_probe_write_features(&cd->cdi); + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -927,14 +928,6 @@ static int get_capabilities(struct scsi_cd *cd) + /*else I don't think it can close its tray + cd->cdi.mask |= CDC_CLOSE_TRAY; */ + +- /* +- * if DVD-RAM, MRW-W or CD-RW, we are randomly writable +- */ +- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != +- (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { +- cd->writeable = 1; +- } +- + kfree(buffer); + return 0; + } +diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h +index 339c624e04d86..ea8a69b04da53 100644 +--- a/drivers/scsi/sr.h ++++ b/drivers/scsi/sr.h +@@ -38,7 +38,6 @@ typedef struct scsi_cd { + struct scsi_device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ +- unsigned writeable : 1; + unsigned use:1; /* is this device still supportable */ + unsigned xa_flag:1; /* CD has XA sectors ? */ + unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ +diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h +index c4fef00abdf38..bcc8b3c6804b5 100644 +--- a/include/linux/cdrom.h ++++ b/include/linux/cdrom.h +@@ -109,6 +109,7 @@ extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, + extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing); + ++extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); + extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); + extern void unregister_cdrom(struct cdrom_device_info *cdi); + +-- +2.53.0 + diff --git a/queue-5.15/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch b/queue-5.15/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch new file mode 100644 index 0000000000..50afc9b7ca --- /dev/null +++ b/queue-5.15/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch @@ -0,0 +1,47 @@ +From 7552775d902b26b7678ec6d21a833ad7ed1900f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 09:53:27 +0800 +Subject: cgroup/rdma: fix integer overflow in rdmacg_try_charge() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: cuitao + +[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ] + +The expression `rpool->resources[index].usage + 1` is computed in int +arithmetic before being assigned to s64 variable `new`. When usage equals +INT_MAX (the default "max" value), the addition overflows to INT_MIN. +This negative value then passes the `new > max` check incorrectly, +allowing a charge that should be rejected and corrupting usage to +negative. + +Fix by casting usage to s64 before the addition so the arithmetic is +done in 64-bit. + +Fixes: 39d3e7584a68 ("rdmacg: Added rdma cgroup controller") +Signed-off-by: cuitao +Reviewed-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c +index 3135406608c75..3265fbbbe7e29 100644 +--- a/kernel/cgroup/rdma.c ++++ b/kernel/cgroup/rdma.c +@@ -281,7 +281,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, + ret = PTR_ERR(rpool); + goto err; + } else { +- new = rpool->resources[index].usage + 1; ++ new = (s64)rpool->resources[index].usage + 1; + if (new > rpool->resources[index].max) { + ret = -EAGAIN; + goto err; +-- +2.53.0 + diff --git a/queue-5.15/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch b/queue-5.15/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch new file mode 100644 index 0000000000..7cb6e4750e --- /dev/null +++ b/queue-5.15/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch @@ -0,0 +1,58 @@ +From 9c5a377613e65dd6e0175fc15d374630eef16478 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:58 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in + of_assigned_ldb_sels() + +From: Felix Gu + +[ Upstream commit 9faf207208951460f3f7eefbc112246c8d28ff1b ] + +The function of_assigned_ldb_sels() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing a memory +leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 5d283b083800 ("clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-2-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index b14c1606466d7..a95f07718b653 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -183,9 +183,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + } + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: parent clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + parent = clkspec.args[0]; ++ of_node_put(clkspec.np); + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); +@@ -193,9 +195,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + return; + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: child clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + child = clkspec.args[0]; ++ of_node_put(clkspec.np); + + if (child != IMX6QDL_CLK_LDB_DI0_SEL && + child != IMX6QDL_CLK_LDB_DI1_SEL) +-- +2.53.0 + diff --git a/queue-5.15/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch b/queue-5.15/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch new file mode 100644 index 0000000000..0b2e2e897c --- /dev/null +++ b/queue-5.15/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch @@ -0,0 +1,56 @@ +From 6e338c199565210e5da2e92dd6f5baded506f7a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:57 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in pll6_bypassed() + +From: Felix Gu + +[ Upstream commit 4b84d496c804b470124cd3a08e928df6801d8eae ] + +The function pll6_bypassed() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing +a memory leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 3cc48976e9763 ("clk: imx6q: handle ENET PLL bypass") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-1-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index de36f58d551c0..b14c1606466d7 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -233,8 +233,11 @@ static bool pll6_bypassed(struct device_node *node) + return false; + + if (clkspec.np == node && +- clkspec.args[0] == IMX6QDL_PLL6_BYPASS) ++ clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { ++ of_node_put(clkspec.np); + break; ++ } ++ of_node_put(clkspec.np); + } + + /* PLL6 bypass is not part of the assigned clock list */ +@@ -244,6 +247,9 @@ static bool pll6_bypassed(struct device_node *node) + ret = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + ++ if (!ret) ++ of_node_put(clkspec.np); ++ + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) + return true; + +-- +2.53.0 + diff --git a/queue-5.15/clk-imx8mq-correct-the-csi-phy-sels.patch b/queue-5.15/clk-imx8mq-correct-the-csi-phy-sels.patch new file mode 100644 index 0000000000..aa82ca29bb --- /dev/null +++ b/queue-5.15/clk-imx8mq-correct-the-csi-phy-sels.patch @@ -0,0 +1,49 @@ +From 16a1a0657aa2b861f7fb2c948bcbdea90d9c94d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 00:47:21 +0100 +Subject: clk: imx8mq: Correct the CSI PHY sels + +From: Sebastian Krzyszkowiak + +[ Upstream commit d16f57caa78776e6e8a88b96cb2597797b376138 ] + +According to i.MX 8M Quad Reference Manual (Section 5.1.2 Table 5-1) +MIPI_CSI1_PHY_REF_CLK_ROOT and MIPI_CSI2_PHY_REF_CLK_ROOT have +SYSTEM_PLL2_DIV3 available as their second source, which corresponds +to sys2_pll_333m rather than sys2_pll_125m. + +Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") +Signed-off-by: Sebastian Krzyszkowiak +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260128-imx8mq-csi-clk-v1-1-ac028ed26e8c@puri.sm +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index 791f6bdd88b8a..46c4fedd4d9f7 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " + static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +@@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", + static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +-- +2.53.0 + diff --git a/queue-5.15/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch b/queue-5.15/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch new file mode 100644 index 0000000000..253fef4d3d --- /dev/null +++ b/queue-5.15/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch @@ -0,0 +1,59 @@ +From e357475aa75ba1c02183a62c753c9e1df85e4815 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:26 +0100 +Subject: clk: qcom: dispcc-sc7180: Add missing MDSS resets + +From: Konrad Dybcio + +[ Upstream commit b0bc6011c5499bdfddd0390262bfa13dce1eff74 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: dd3d06622138 ("clk: qcom: Add display clock controller driver for SC7180") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Taniya Das +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-2-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc7180.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c +index 5d2ae297e7413..040149f24d798 100644 +--- a/drivers/clk/qcom/dispcc-sc7180.c ++++ b/drivers/clk/qcom/dispcc-sc7180.c +@@ -16,6 +16,7 @@ + #include "clk-regmap-divider.h" + #include "common.h" + #include "gdsc.h" ++#include "reset.h" + + enum { + P_BI_TCXO, +@@ -635,6 +636,11 @@ static struct gdsc mdss_gdsc = { + .flags = HW_CTRL, + }; + ++static const struct qcom_reset_map disp_cc_sc7180_resets[] = { ++ [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, ++ [DISP_CC_MDSS_RSCC_BCR] = { 0x4000 }, ++}; ++ + static struct gdsc *disp_cc_sc7180_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, + }; +@@ -686,6 +692,8 @@ static const struct qcom_cc_desc disp_cc_sc7180_desc = { + .config = &disp_cc_sc7180_regmap_config, + .clks = disp_cc_sc7180_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sc7180_clocks), ++ .resets = disp_cc_sc7180_resets, ++ .num_resets = ARRAY_SIZE(disp_cc_sc7180_resets), + .gdscs = disp_cc_sc7180_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sc7180_gdscs), + }; +-- +2.53.0 + diff --git a/queue-5.15/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch b/queue-5.15/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..5b0c858fe3 --- /dev/null +++ b/queue-5.15/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,48 @@ +From 7285dac1eb528cbc2169d31de649b061161bcc5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:13 -0300 +Subject: clk: qcom: dispcc-sm8250: Enable parents for pixel clocks + +From: Val Packett + +[ Upstream commit acf7a91d0b0e9e3ef374944021de62062125b7e4 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-9-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index d9c68d1b90900..2adb38ada9bfb 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -559,7 +559,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -573,7 +573,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-5.15/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch b/queue-5.15/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch new file mode 100644 index 0000000000..b1b404daf2 --- /dev/null +++ b/queue-5.15/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch @@ -0,0 +1,45 @@ +From 23900678168167edf6763804f003784d30a49f85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:12 -0300 +Subject: clk: qcom: dispcc-sm8250: Use shared ops on the mdss vsync clk + +From: Val Packett + +[ Upstream commit 8c522da70f0c2e5148c4c13ccb1c64cca57a6fdb ] + +mdss_gdsc can get stuck on boot due to RCGs being left on from last boot. +As a fix, commit 01a0a6cc8cfd ("clk: qcom: Park shared RCGs upon +registration") introduced a callback to ensure the RCG is off upon init. +However, the fix depends on all shared RCGs being marked as such in code. + +For SM8150/SC8180X/SM8250 the MDSS vsync clock was using regular ops, +unlike the same clock in the SC7180 code. This was causing display to +frequently fail to initialize after rebooting on the Surface Pro X. +Fix by using shared ops for this clock. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-8-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index fc08c326d8026..d9c68d1b90900 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -613,7 +613,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-5.15/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-5.15/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..d479abe1f4 --- /dev/null +++ b/queue-5.15/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,94 @@ +From 97943c46bc9fb21facfc4f36313de18149a7f81a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:07 -0300 +Subject: clk: qcom: gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 3565741eb985a8a7cc6656eb33496195468cb99e ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-3-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 50 ++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index ba004281f2944..00e2e22a14175 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4200,6 +4200,51 @@ static struct gdsc usb30_mp_gdsc = { + .flags = POLL_CFG_GDSCR, + }; + ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { ++ .gdscr = 0x7d050, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { ++ .gdscr = 0x7d058, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { ++ .gdscr = 0x7d054, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { ++ .gdscr = 0x7d05c, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { ++ .gdscr = 0x7d060, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ + static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, +@@ -4500,6 +4545,11 @@ static struct gdsc *gcc_sc8180x_gdscs[] = { + [USB30_MP_GDSC] = &usb30_mp_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB30_SEC_GDSC] = &usb30_sec_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, + }; + + static const struct regmap_config gcc_sc8180x_regmap_config = { +-- +2.53.0 + diff --git a/queue-5.15/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch b/queue-5.15/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch new file mode 100644 index 0000000000..4c989e1874 --- /dev/null +++ b/queue-5.15/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch @@ -0,0 +1,74 @@ +From 9ae06153e0998f8f003d3945a3dfc77008f2a4df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:09 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for PCIe power domains + +From: Val Packett + +[ Upstream commit ccb92c78b42edd26225b4d5920847dfee3e1b093 ] + +As the PCIe host controller driver does not yet support dealing with the +loss of state during suspend, use retention for relevant GDSCs. + +This fixes the link not surviving upon resume: + + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS read failed (134) + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: Disabling device after reset failure: -19 + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260312112321.370983-5-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index e0992f280692b..94da183fad68d 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4133,7 +4133,7 @@ static struct gdsc pcie_0_gdsc = { + .pd = { + .name = "pcie_0_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4160,7 +4160,7 @@ static struct gdsc pcie_1_gdsc = { + .pd = { + .name = "pcie_1_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4169,7 +4169,7 @@ static struct gdsc pcie_2_gdsc = { + .pd = { + .name = "pcie_2_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4187,7 +4187,7 @@ static struct gdsc pcie_3_gdsc = { + .pd = { + .name = "pcie_3_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-5.15/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch b/queue-5.15/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch new file mode 100644 index 0000000000..7e2b1f7972 --- /dev/null +++ b/queue-5.15/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch @@ -0,0 +1,65 @@ +From 67e655fd4364d8e8715eedd614ddf8bc0aee94ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:08 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for USB power domains + +From: Val Packett + +[ Upstream commit 25bc96f26cd6c19dde13a0b9859183e531d6fbfc ] + +The USB subsystem does not expect to lose its state on suspend: + + xhci-hcd xhci-hcd.0.auto: xHC error in resume, USBSTS 0x401, Reinit + usb usb1: root hub lost power or was reset + +(The reinitialization usually succeeds, but it does slow down resume.) + +To maintain state during suspend, the relevant GDSCs need to stay in +retention mode, like they do on other similar SoCs. Change the mode to +PWRSTS_RET_ON to fix. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-4-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 00e2e22a14175..e0992f280692b 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4106,7 +4106,7 @@ static struct gdsc usb30_sec_gdsc = { + .pd = { + .name = "usb30_sec_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4124,7 +4124,7 @@ static struct gdsc usb30_prim_gdsc = { + .pd = { + .name = "usb30_prim_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4196,7 +4196,7 @@ static struct gdsc usb30_mp_gdsc = { + .pd = { + .name = "usb30_mp_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-5.15/clk-qoriq-avoid-format-string-warning.patch b/queue-5.15/clk-qoriq-avoid-format-string-warning.patch new file mode 100644 index 0000000000..d1c1491895 --- /dev/null +++ b/queue-5.15/clk-qoriq-avoid-format-string-warning.patch @@ -0,0 +1,86 @@ +From 03517575b8b128319156487eb225778b91e3b9f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:18:49 +0100 +Subject: clk: qoriq: avoid format string warning + +From: Arnd Bergmann + +[ Upstream commit 096abbb6682ee031a0f5ce9f4c71ead9fa63d31e ] + +clang-22 warns about the use of non-variadic format arguments passed into +snprintf(): + +drivers/clk/clk-qoriq.c:925:39: error: diagnostic behavior may be improved by adding the + 'format(printf, 7, 8)' attribute to the declaration of 'create_mux_common' [-Werror,-Wmissing-format-attribute] + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + | __attribute__((format(printf, 7, 8))) + 911 | struct mux_hwclock *hwc, + 912 | const struct clk_ops *ops, + 913 | unsigned long min_rate, + 914 | unsigned long max_rate, + 915 | unsigned long pct80_rate, + 916 | const char *fmt, int idx) + 917 | { + 918 | struct clk_init_data init = {}; + 919 | struct clk *clk; + 920 | const struct clockgen_pll_div *div; + 921 | const char *parent_names[NUM_MUX_PARENTS]; + 922 | char name[32]; + 923 | int i, j; + 924 | + 925 | snprintf(name, sizeof(name), fmt, idx); + | ^ +drivers/clk/clk-qoriq.c:910:28: note: 'create_mux_common' declared here + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + +Rework this to pass the 'int idx' as a varargs argument, allowing the +format string to be verified at the caller location. + +Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") +Signed-off-by: Arnd Bergmann +Reviewed-by: Kees Cook +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-qoriq.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c +index 5eddb9f0d6bdb..4baec1bf3557f 100644 +--- a/drivers/clk/clk-qoriq.c ++++ b/drivers/clk/clk-qoriq.c +@@ -905,13 +905,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg, + return &cg->pll[pll].div[div]; + } + +-static struct clk * __init create_mux_common(struct clockgen *cg, +- struct mux_hwclock *hwc, +- const struct clk_ops *ops, +- unsigned long min_rate, +- unsigned long max_rate, +- unsigned long pct80_rate, +- const char *fmt, int idx) ++static struct clk * __init __printf(7, 8) ++create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, ++ const struct clk_ops *ops, unsigned long min_rate, ++ unsigned long max_rate, unsigned long pct80_rate, ++ const char *fmt, ...) + { + struct clk_init_data init = {}; + struct clk *clk; +@@ -919,8 +917,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg, + const char *parent_names[NUM_MUX_PARENTS]; + char name[32]; + int i, j; ++ va_list args; + +- snprintf(name, sizeof(name), fmt, idx); ++ va_start(args, fmt); ++ vsnprintf(name, sizeof(name), fmt, args); ++ va_end(args); + + for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) { + unsigned long rate; +-- +2.53.0 + diff --git a/queue-5.15/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch b/queue-5.15/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch new file mode 100644 index 0000000000..9b71237128 --- /dev/null +++ b/queue-5.15/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch @@ -0,0 +1,37 @@ +From cc61c5869824eafc563210f94c83da661cd9fc7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:11:16 +0100 +Subject: clk: xgene: Fix mapping leak in xgene_pllclk_init() + +From: Geert Uytterhoeven + +[ Upstream commit f520a492e07bc6718e26cfb7543ab4cadd8bb0e2 ] + +If xgene_register_clk_pll() fails, the mapped register block is never +unmapped. + +Fixes: 308964caeebc45eb ("clk: Add APM X-Gene SoC clock driver") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-xgene.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c +index 857217cbcef87..7dd3aa955484a 100644 +--- a/drivers/clk/clk-xgene.c ++++ b/drivers/clk/clk-xgene.c +@@ -187,6 +187,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); ++ } else { ++ iounmap(reg); + } + } + +-- +2.53.0 + diff --git a/queue-5.15/crypto-ccp-copy-iv-using-skcipher-ivsize.patch b/queue-5.15/crypto-ccp-copy-iv-using-skcipher-ivsize.patch new file mode 100644 index 0000000000..2467f02d01 --- /dev/null +++ b/queue-5.15/crypto-ccp-copy-iv-using-skcipher-ivsize.patch @@ -0,0 +1,47 @@ +From 342637e446bcdafee11614ccc0cf3e1df47148c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 03:07:49 -0500 +Subject: crypto: ccp - copy IV using skcipher ivsize + +From: Paul Moses + +[ Upstream commit a7a1f3cdd64d8a165d9b8c9e9ad7fb46ac19dfc4 ] + +AF_ALG rfc3686-ctr-aes-ccp requests pass an 8-byte IV to the driver. + +ccp_aes_complete() restores AES_BLOCK_SIZE bytes into the caller's IV +buffer while RFC3686 skciphers expose an 8-byte IV, so the restore +overruns the provided buffer. + +Use crypto_skcipher_ivsize() to copy only the algorithm's IV length. + +Fixes: 2b789435d7f3 ("crypto: ccp - CCP AES crypto API support") +Signed-off-by: Paul Moses +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-crypto-aes.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c +index e6dcd8cedd53e..b03ed5e83c3e9 100644 +--- a/drivers/crypto/ccp/ccp-crypto-aes.c ++++ b/drivers/crypto/ccp/ccp-crypto-aes.c +@@ -28,8 +28,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) + if (ret) + return ret; + +- if (ctx->u.aes.mode != CCP_AES_MODE_ECB) +- memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE); ++ if (ctx->u.aes.mode != CCP_AES_MODE_ECB) { ++ size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); ++ ++ memcpy(req->iv, rctx->iv, ivsize); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-5.15/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch b/queue-5.15/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch new file mode 100644 index 0000000000..1e28fed1ae --- /dev/null +++ b/queue-5.15/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch @@ -0,0 +1,47 @@ +From faa255aa7d988c7f123f4e34d53ef7e24d6fab98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 20:06:58 +0530 +Subject: crypto: sa2ul - Fix AEAD fallback algorithm names + +From: T Pratham + +[ Upstream commit 8451ab6ad686ffdcdf9ddadaa446a79ab48e5590 ] + +For authenc AEAD algorithms, sa2ul is trying to register very specific +-ce version as a fallback. This causes registration failure on SoCs +which do not have ARMv8-CE enabled/available. Change the fallback +algorithm from the specific driver name to generic algorithm name so +that the kernel can allocate any available fallback. + +Fixes: d2c8ac187fc92 ("crypto: sa2ul - Add AEAD algorithm support") +Signed-off-by: T Pratham +Reviewed-by: Manorit Chawdhry +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/sa2ul.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c +index 91ab33690ccf4..05849a1c86f35 100644 +--- a/drivers/crypto/sa2ul.c ++++ b/drivers/crypto/sa2ul.c +@@ -1774,13 +1774,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, + static int sa_cra_init_aead_sha1(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha1", +- "authenc(hmac(sha1-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha1),cbc(aes))"); + } + + static int sa_cra_init_aead_sha256(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha256", +- "authenc(hmac(sha256-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha256),cbc(aes))"); + } + + static void sa_exit_tfm_aead(struct crypto_aead *tfm) +-- +2.53.0 + diff --git a/queue-5.15/debugfs-check-for-null-pointer-in-debugfs_create_str.patch b/queue-5.15/debugfs-check-for-null-pointer-in-debugfs_create_str.patch new file mode 100644 index 0000000000..30431141f9 --- /dev/null +++ b/queue-5.15/debugfs-check-for-null-pointer-in-debugfs_create_str.patch @@ -0,0 +1,52 @@ +From 45d77255c15d91164b1baf13bfaa6381df19f371 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:44 +0800 +Subject: debugfs: check for NULL pointer in debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 31de83980d3764d784f79ff1bc93c42b324f4013 ] + +Passing a NULL pointer to debugfs_create_str() leads to a NULL pointer +dereference when the debugfs file is read. Following upstream +discussions, forbid the creation of debugfs string files with NULL +pointers. Add a WARN_ON() to expose offending callers and return early. + +Fixes: 9af0440ec86e ("debugfs: Implement debugfs_create_str()") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/2025122221-gag-malt-75ba@gregkh/ +Suggested-by: Greg Kroah-Hartman +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-2-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index df5c2162e7297..e4e66bd2367e8 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -942,7 +942,7 @@ static const struct file_operations fops_str_wo = { + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write +- * from. ++ * from. This pointer and the string it points to must not be %NULL. + * + * This function creates a file in debugfs with the given name that + * contains the value of the variable @value. If the @mode variable is so +@@ -960,6 +960,9 @@ static const struct file_operations fops_str_wo = { + void debugfs_create_str(const char *name, umode_t mode, + struct dentry *parent, char **value) + { ++ if (WARN_ON(!value || !*value)) ++ return; ++ + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } +-- +2.53.0 + diff --git a/queue-5.15/dev_printk-add-new-dev_err_probe-helpers.patch b/queue-5.15/dev_printk-add-new-dev_err_probe-helpers.patch new file mode 100644 index 0000000000..ece1b3e9ff --- /dev/null +++ b/queue-5.15/dev_printk-add-new-dev_err_probe-helpers.patch @@ -0,0 +1,47 @@ +From dfda813fbb39076c08c25e927401187efa704424 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2024 09:22:37 +0200 +Subject: dev_printk: add new dev_err_probe() helpers + +From: Nuno Sa + +[ Upstream commit dbbe7eaf0e4795bf003ac06872aaf52b6b6b1310 ] + +This is similar to dev_err_probe() but for cases where an ERR_PTR() or +ERR_CAST() is to be returned simplifying patterns like: + + dev_err_probe(dev, ret, ...); + return ERR_PTR(ret) +or + dev_err_probe(dev, PTR_ERR(ptr), ...); + return ERR_CAST(ptr) + +Signed-off-by: Nuno Sa +Link: https://patch.msgid.link/20240606-dev-add_dev_errp_probe-v3-1-51bb229edd79@analog.com +Signed-off-by: Jonathan Cameron +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/dev_printk.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h +index ae80a303c216b..ca32b5bb28eb5 100644 +--- a/include/linux/dev_printk.h ++++ b/include/linux/dev_printk.h +@@ -277,4 +277,12 @@ do { \ + + __printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); + ++/* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */ ++#define dev_err_ptr_probe(dev, ___err, fmt, ...) \ ++ ERR_PTR(dev_err_probe(dev, ___err, fmt, ##__VA_ARGS__)) ++ ++/* Simple helper for dev_err_probe() when ERR_CAST() is to be returned. */ ++#define dev_err_cast_probe(dev, ___err_ptr, fmt, ...) \ ++ ERR_PTR(dev_err_probe(dev, PTR_ERR(___err_ptr), fmt, ##__VA_ARGS__)) ++ + #endif /* _DEVICE_PRINTK_H_ */ +-- +2.53.0 + diff --git a/queue-5.15/devres-fix-missing-node-debug-info-in-devm_krealloc.patch b/queue-5.15/devres-fix-missing-node-debug-info-in-devm_krealloc.patch new file mode 100644 index 0000000000..debe2779c1 --- /dev/null +++ b/queue-5.15/devres-fix-missing-node-debug-info-in-devm_krealloc.patch @@ -0,0 +1,37 @@ +From e1e76ea5d1c57fc7eca69c05f8937cc164ffac31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 00:48:14 +0100 +Subject: devres: fix missing node debug info in devm_krealloc() + +From: Danilo Krummrich + +[ Upstream commit f813ec9e84b4d0ca81ec1da94ab07bfb4a29266c ] + +Fix missing call to set_node_dbginfo() for new devres nodes created by +devm_krealloc(). + +Fixes: f82485722e5d ("devres: provide devm_krealloc()") +Reviewed-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/20260202235210.55176-2-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/base/devres.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index 58e8e2be26ac7..6e4b43c5c3075 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -907,6 +907,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) + if (!new_dr) + return NULL; + ++ set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size); ++ + /* + * The spinlock protects the linked list against concurrent + * modifications but not the resource itself. +-- +2.53.0 + diff --git a/queue-5.15/dissector-do-not-set-invalid-ppp-protocol.patch b/queue-5.15/dissector-do-not-set-invalid-ppp-protocol.patch new file mode 100644 index 0000000000..efbf4918d4 --- /dev/null +++ b/queue-5.15/dissector-do-not-set-invalid-ppp-protocol.patch @@ -0,0 +1,46 @@ +From bd8b8b61ac07f3cb2bd0baf23f04a22f25cda929 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Sep 2021 14:32:23 +0300 +Subject: dissector: do not set invalid PPP protocol + +From: Boris Sukholitko + +[ Upstream commit 2e861e5e97175dfa7b7bc055c45acdc06d2301d3 ] + +The following flower filter fails to match non-PPP_IP{V6} packets +wrapped in PPP_SES protocol: + +tc filter add dev eth0 ingress protocol ppp_ses flower \ + action simple sdata hi64 + +The reason is that proto local variable is being set even when +FLOW_DISSECT_RET_OUT_BAD status is returned. + +The fix is to avoid setting proto variable if the PPP protocol is unknown. + +Signed-off-by: Boris Sukholitko +Signed-off-by: David S. Miller +Stable-dep-of: cc1ff87bce1c ("pppoe: drop PFC frames") +Signed-off-by: Sasha Levin +--- + net/core/flow_dissector.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index ba437cfcbe90f..537dbd7fc5438 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -1207,9 +1207,8 @@ bool __skb_flow_dissect(const struct net *net, + break; + } + +- proto = hdr->proto; + nhoff += PPPOE_SES_HLEN; +- switch (proto) { ++ switch (hdr->proto) { + case htons(PPP_IP): + proto = htons(ETH_P_IP); + fdret = FLOW_DISSECT_RET_PROTO_AGAIN; +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-fix-concurrent-write-failure-in-passthrough.patch b/queue-5.15/dm-cache-fix-concurrent-write-failure-in-passthrough.patch new file mode 100644 index 0000000000..fa7883f15b --- /dev/null +++ b/queue-5.15/dm-cache-fix-concurrent-write-failure-in-passthrough.patch @@ -0,0 +1,84 @@ +From bfa48d4212db72d45b372337e65694b0f8e03dce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:09 +0800 +Subject: dm cache: fix concurrent write failure in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit e4f66341779d0cf4c83c74793753a84094286d9e ] + +When bio prison cell lock acquisition fails due to concurrent writes to +the same block in passthrough mode, dm-cache incorrectly returns an I/O +error instead of properly handling the concurrency. This can occur in +both process and workqueue contexts when invalidate_lock() is called for +exclusive access to a data block. Fix this by deferring the write bios +to ensure proper block device behavior. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently. Sometimes one of the + processes will receive I/O errors. + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + + + fio-3.41 + fio: io_u error on file /dev/mapper/cache: Input/output error: write offset=4096, buflen=4096 + fio: pid=106, err=5/file:io_u.c:2008, func=io_u error, error=Input/output error + test: (groupid=0, jobs=1): err= 0: pid=105 + test: (groupid=0, jobs=1): err= 5 (file:io_u.c:2008, func=io_u error, error=Input/output error): pid=106 + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 783722a4c3364..1498ffbcb0e03 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1524,6 +1524,15 @@ static int invalidate_lock(struct dm_cache_migration *mg) + READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell); + if (r < 0) { + free_prison_cell(cache, prealloc); ++ ++ /* Defer the bio for retrying the cell lock */ ++ if (mg->overwrite_bio) { ++ struct bio *bio = mg->overwrite_bio; ++ ++ mg->overwrite_bio = NULL; ++ defer_bio(cache, bio); ++ } ++ + invalidate_complete(mg, false); + return r; + } +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch b/queue-5.15/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch new file mode 100644 index 0000000000..7842b12ffd --- /dev/null +++ b/queue-5.15/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch @@ -0,0 +1,151 @@ +From 9155c8b669de126326137d57f278885fb9047b67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:10 +0800 +Subject: dm cache: fix dirty mapping checking in passthrough mode switching + +From: Ming-Hung Tsai + +[ Upstream commit 322586745bd1a0e5f3559fd1635fdeb4dbd1d6b8 ] + +As mentioned in commit 9b1cc9f251af ("dm cache: share cache-metadata +object across inactive and active DM tables"), dm-cache assumed table +reload occurs after suspension, while LVM's table preload breaks this +assumption. The dirty mapping check for passthrough mode was designed +around this assumption and is performed during table creation, causing +the check to fail with preload while metadata updates are ongoing. This +risks loading dirty mappings into passthrough mode, resulting in data +loss. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty mappings + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Preload a table in passthrough mode + +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" + +3. Write to the first cache block to make it dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +4. Resume the inactive table. Now it's possible to load the dirty block + into passthrough mode. + +dmsetup resume cache + +Fix by moving the checks to the preresume phase to support table +preloading. Also remove the unused function dm_cache_metadata_all_clean. + +Fixes: 2ee57d587357 ("dm cache: add passthrough mode") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 11 ----------- + drivers/md/dm-cache-metadata.h | 5 ----- + drivers/md/dm-cache-target.c | 25 ++++++++----------------- + 3 files changed, 8 insertions(+), 33 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 0f6f74e3030f7..61808d888dc45 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1749,17 +1749,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * + return r; + } + +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) +-{ +- int r; +- +- READ_LOCK(cmd); +- r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); +- READ_UNLOCK(cmd); +- +- return r; +-} +- + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) + { + WRITE_LOCK_VOID(cmd); +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 179ed5bf81a3e..79747130a48f7 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -137,11 +137,6 @@ void dm_cache_dump(struct dm_cache_metadata *cmd); + */ + int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p); + +-/* +- * Query method. Are all the blocks in the cache clean? +- */ +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); +- + int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); + int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 238d2bea41d8d..37c8740d6d996 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2470,23 +2470,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) + goto bad; + } + +- if (passthrough_mode(cache)) { +- bool all_clean; +- +- r = dm_cache_metadata_all_clean(cache->cmd, &all_clean); +- if (r) { +- *error = "dm_cache_metadata_all_clean() failed"; +- goto bad; +- } +- +- if (!all_clean) { +- *error = "Cannot enter passthrough mode unless all blocks are clean"; +- r = -EINVAL; +- goto bad; +- } +- ++ if (passthrough_mode(cache)) + policy_allow_migrations(cache->policy, false); +- } + + spin_lock_init(&cache->lock); + bio_list_init(&cache->deferred_bios); +@@ -2812,6 +2797,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + struct cache *cache = context; + + if (dirty) { ++ if (passthrough_mode(cache)) { ++ DMERR("%s: cannot enter passthrough mode unless all blocks are clean", ++ cache_device_name(cache)); ++ return -EBUSY; ++ } ++ + set_bit(from_cblock(cblock), cache->dirty_bitset); + atomic_inc(&cache->nr_dirty); + } else +@@ -3045,7 +3036,7 @@ static int cache_preresume(struct dm_target *ti) + load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- if (r != -EFBIG) ++ if (r != -EFBIG && r != -EBUSY) + metadata_operation_failed(cache, "dm_cache_load_mappings", r); + return r; + } +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch b/queue-5.15/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch new file mode 100644 index 0000000000..74d44a8863 --- /dev/null +++ b/queue-5.15/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch @@ -0,0 +1,86 @@ +From 046cde3d6968aaf21553336137cafb0660df5cd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:05 +0800 +Subject: dm cache: fix null-deref with concurrent writes in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 7d1f98d668ee34c1d15bdc0420fdd062f24a27c0 ] + +In passthrough mode, when dm-cache starts to invalidate a cache +entry and bio prison cell lock fails due to concurrent write to +the same cached block, mg->cell remains NULL. The error path in +invalidate_complete() attempts to unlock and free the cell +unconditionally, causing a NULL pointer dereference: + +KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +CPU: 0 UID: 0 PID: 134 Comm: fio Not tainted 6.19.0-rc7 #3 PREEMPT +RIP: 0010:dm_cell_unlock_v2+0x3f/0x210 + +Call Trace: + invalidate_complete+0xef/0x430 + map_bio+0x130f/0x1a10 + cache_map+0x320/0x6b0 + __map_bio+0x458/0x510 + dm_submit_bio+0x40e/0x16d0 + __submit_bio+0x419/0x870 + + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + +Fix by checking if mg->cell is valid before attempting to unlock it. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 1660d4fec7511..8571c095793b5 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1448,8 +1448,10 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + struct cache *cache = mg->cache; + + bio_list_init(&bios); +- if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) +- free_prison_cell(cache, mg->cell); ++ if (mg->cell) { ++ if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) ++ free_prison_cell(cache, mg->cell); ++ } + + if (!success && mg->overwrite_bio) + bio_io_error(mg->overwrite_bio); +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch b/queue-5.15/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch new file mode 100644 index 0000000000..2fa3ee11e9 --- /dev/null +++ b/queue-5.15/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch @@ -0,0 +1,85 @@ +From 22f49b5a0afb7e87c48f5af05b5b68c9529fafa9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:06 +0800 +Subject: dm cache: fix write path cache coherency in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 0c5eef0aad508231d8e43ff8392692925e131b68 ] + +In passthrough mode, dm-cache defers write bio submission until cache +invalidation completes to maintain existing coherency, requiring the +target map function to return DM_MAPIO_SUBMITTED. The current map_bio() +returns DM_MAPIO_REMAPPED, violating the required ordering constraint. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into the cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first data block, and check io ordering using ftrace + +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_queue/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_complete/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_rq_complete/enable +fio --filename=/dev/mapper/cache --name=test --rw=write --bs=64k \ +--direct=1 --size 64k + +5. ftrace logs show that write operations to the cache origin (252:2) + and metadata operations (252:0) are unsynchronized: the origin write + occurs before metadata commit. + + + fio-146 [000] ..... 420.139562: block_bio_queue: 252,3 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149395: block_bio_queue: 252,2 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149763: block_bio_queue: 8,32 WS 262144 + 128 [fio] + fio-146 [000] dNh1. 420.151446: block_rq_complete: 8,32 WS () 262144 + 128 be,0,4 [0] + fio-146 [000] dNh1. 420.152731: block_bio_complete: 252,2 WS 0 + 128 [0] + fio-146 [000] dNh1. 420.154229: block_bio_complete: 252,3 WS 0 + 128 [0] + kworker/0:0-9 [000] ..... 420.160530: block_bio_queue: 252,0 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.161641: block_bio_queue: 8,32 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162533: block_bio_queue: 252,0 W 416 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162821: block_bio_queue: 8,32 W 416 + 8 [kworker/0:0] + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 8571c095793b5..783722a4c3364 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1684,6 +1684,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, + bio_drop_shared_lock(cache, bio); + atomic_inc(&cache->stats.demotion); + invalidate_start(cache, cblock, block, bio); ++ return DM_MAPIO_SUBMITTED; + } else + remap_to_origin_clear_discard(cache, bio, block); + } else { +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch b/queue-5.15/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch new file mode 100644 index 0000000000..ad54b4e61f --- /dev/null +++ b/queue-5.15/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch @@ -0,0 +1,121 @@ +From 91933d9e279ee5a8272ff5604f8703462a711958 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:56:28 +0800 +Subject: dm cache metadata: fix memory leak on metadata abort retry + +From: Ming-Hung Tsai + +[ Upstream commit 044ca491d4086dc5bf233e9fcb71db52df32f633 ] + +When failing to acquire the root_lock in dm_cache_metadata_abort because +the block_manager is read-only, the temporary block_manager created +outside the root_lock is not properly released, causing a memory leak. + +Reproduce steps: + +This can be reproduced by reloading a new table while the metadata +is read-only. While the second call to dm_cache_metadata_abort is +caused by lack of support for table preload in dm-cache, mentioned +in commit 9b1cc9f251af ("dm cache: share cache-metadata object across +inactive and active DM tables"), it exposes the memory leak in +dm_cache_metadata_abort when the function is called multiple times. +Specifically, dm-cache fails to sync the new cache object's mode during +preresume, creating the reproducer condition. + +This issue could also occur through concurrent metadata_operation_failed +calls due to races in cache mode updates, but the table preload scenario +below provides a reliable reproducer. + +1. Create a cache device with some faulty trailing metadata blocks + +dmsetup create cmeta < +unreferenced object 0xffff8880080c2010 (size 16): + comm "dmsetup", pid 132, jiffies 4294982580 + hex dump (first 16 bytes): + 00 38 b9 07 80 88 ff ff 6a 6b 6b 6b 6b 6b 6b a5 ... + backtrace (crc 3118f31c): + kmemleak_alloc+0x28/0x40 + __kmalloc_cache_noprof+0x3d9/0x510 + dm_block_manager_create+0x51/0x140 + dm_cache_metadata_abort+0x85/0x320 + metadata_operation_failed+0x103/0x1e0 + cache_preresume+0xacd/0xe70 + dm_table_resume_targets+0xd3/0x320 + __dm_resume+0x1b/0xf0 + dm_resume+0x127/0x170 + + +Fixes: 352b837a5541 ("dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 61808d888dc45..c183c2fc1691c 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1017,6 +1017,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd) + return; \ + } while(0) + ++#define WRITE_LOCK_OR_GOTO(cmd, label) \ ++ do { \ ++ if (!cmd_write_lock((cmd))) \ ++ goto label; \ ++ } while (0) ++ + #define WRITE_UNLOCK(cmd) \ + up_write(&(cmd)->root_lock) + +@@ -1815,11 +1821,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, + CACHE_MAX_CONCURRENT_LOCKS); + +- WRITE_LOCK(cmd); +- if (cmd->fail_io) { +- WRITE_UNLOCK(cmd); +- goto out; +- } ++ /* cmd_write_lock() already checks fail_io with cmd->root_lock held */ ++ WRITE_LOCK_OR_GOTO(cmd, out); + + __destroy_persistent_data_objects(cmd, false); + old_bm = cmd->bm; +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch b/queue-5.15/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch new file mode 100644 index 0000000000..15cee6f4db --- /dev/null +++ b/queue-5.15/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch @@ -0,0 +1,91 @@ +From 2011cbab663388f6d814c9bb8420540025bb1e70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:08 +0800 +Subject: dm cache policy smq: fix missing locks in invalidating cache blocks + +From: Ming-Hung Tsai + +[ Upstream commit 2d1f7b65f5deedd2e6b09fdc6ea27f8375f24b45 ] + +In passthrough mode, the policy invalidate_mapping operation is called +simultaneously from multiple workers, thus it should be protected by a +lock. Otherwise, we might end up with data races on the allocated blocks +counter, or even use-after-free issues with internal data structures +when doing concurrent writes. + +Note that the existing FIXME in smq_invalidate_mapping() doesn't affect +passthrough mode since migration tasks don't exist there, but would need +attention if supporting fast device shrinking via suspend/resume without +target reloading. + +Reproduce steps: + +1. Create a cache device consisting of 1024 cache entries + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Populate the cache, and record the number of cached blocks + +fio --name=populate --filename=/dev/mapper/cache --rw=randwrite --bs=4k \ +--size=64m --direct=1 +nr_cached=$(dmsetup status cache | awk '{split($7, a, "/"); print a[1]}') + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the passthrough cache. By setting multiple jobs with I/O + size equal to the cache block size, cache blocks are invalidated + concurrently from different workers. + +fio --filename=/dev/mapper/cache --name=test --rw=randwrite --bs=64k \ +--direct=1 --numjobs=2 --randrepeat=0 --size=64m + +5. Check if demoted matches cached block count. These numbers should + match but may differ due to the data race. + +nr_demoted=$(dmsetup status cache | awk '{print $12}') +echo "$nr_cached, $nr_demoted" + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 859073193f5b4..95b0670c32acd 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1584,14 +1584,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + { + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); ++ unsigned long flags; + + if (!e->allocated) + return -ENODATA; + ++ spin_lock_irqsave(&mq->lock, flags); + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ spin_unlock_irqrestore(&mq->lock, flags); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-5.15/dm-cache-support-shrinking-the-origin-device.patch b/queue-5.15/dm-cache-support-shrinking-the-origin-device.patch new file mode 100644 index 0000000000..79550eaea6 --- /dev/null +++ b/queue-5.15/dm-cache-support-shrinking-the-origin-device.patch @@ -0,0 +1,197 @@ +From a448404fba71752baa21aed616098197a85c65c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 16:41:51 +0800 +Subject: dm cache: support shrinking the origin device + +From: Ming-Hung Tsai + +[ Upstream commit c2662b1544cbd8ea3181381bb899b8e681dfedc7 ] + +This patch introduces formal support for shrinking the cache origin by +reducing the cache target length via table reloads. Cache blocks mapped +beyond the new target length must be clean and are invalidated during +preresume. If any dirty blocks exist in the area being removed, the +preresume operation fails without setting the NEEDS_CHECK flag in +superblock, and the resume ioctl returns EFBIG. The cache device remains +suspended until a table reload with target length that fits existing +mappings is performed. + +Without this patch, reducing the cache target length could result in +io errors (RHBZ: 2134334), out-of-bounds memory access to the discard +bitset, and security concerns regarding data leakage. + +Verification steps: + +1. create a cache metadata with some cached blocks mapped to the tail + of the origin device. Here we use cache_restore v1.0 to build a + metadata with one clean block mapped to the last origin block. + +cat <> cmeta.xml + + + + + +EOF +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +cache_restore -i cmeta.xml -o /dev/mapper/cmeta --metadata-version=2 +dmsetup remove cmeta + +2. bring up the cache whilst shrinking the cache origin by one block: + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" +dmsetup create corig --table "0 524160 linear /dev/sdc 262144" +dmsetup create cache --table "0 524160 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +3. check the number of cached data blocks via dmsetup status. It is + expected to be zero. + +dmsetup status cache | cut -d ' ' -f 7 + +In addition to the script above, this patch can be verified using the +"cache/resize" tests in dmtest-python: + +./dmtest run --rx cache/resize/shrink_origin --result-set default + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Stable-dep-of: 322586745bd1 ("dm cache: fix dirty mapping checking in passthrough mode switching") +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 72 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 69 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 1498ffbcb0e03..238d2bea41d8d 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -405,6 +405,12 @@ struct cache { + mempool_t migration_pool; + + struct bio_set bs; ++ ++ /* ++ * Cache_size entries. Set bits indicate blocks mapped beyond the ++ * target length, which are marked for invalidation. ++ */ ++ unsigned long *invalid_bitset; + }; + + struct per_bio_data { +@@ -1918,6 +1924,9 @@ static void __destroy(struct cache *cache) + if (cache->discard_bitset) + free_bitset(cache->discard_bitset); + ++ if (cache->invalid_bitset) ++ free_bitset(cache->invalid_bitset); ++ + if (cache->copier) + dm_kcopyd_client_destroy(cache->copier); + +@@ -2506,6 +2515,13 @@ static int cache_create(struct cache_args *ca, struct cache **result) + } + clear_bitset(cache->discard_bitset, from_dblock(cache->discard_nr_blocks)); + ++ cache->invalid_bitset = alloc_bitset(from_cblock(cache->cache_size)); ++ if (!cache->invalid_bitset) { ++ *error = "could not allocate bitset for invalid blocks"; ++ goto bad; ++ } ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + cache->copier = dm_kcopyd_client_create(&dm_kcopyd_throttle); + if (IS_ERR(cache->copier)) { + *error = "could not create kcopyd client"; +@@ -2804,6 +2820,24 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + return policy_load_mapping(cache->policy, oblock, cblock, dirty, hint, hint_valid); + } + ++static int load_filtered_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, ++ bool dirty, uint32_t hint, bool hint_valid) ++{ ++ struct cache *cache = context; ++ ++ if (from_oblock(oblock) >= from_oblock(cache->origin_blocks)) { ++ if (dirty) { ++ DMERR("%s: unable to shrink origin; cache block %u is dirty", ++ cache_device_name(cache), from_cblock(cblock)); ++ return -EFBIG; ++ } ++ set_bit(from_cblock(cblock), cache->invalid_bitset); ++ return 0; ++ } ++ ++ return load_mapping(context, oblock, cblock, dirty, hint, hint_valid); ++} ++ + /* + * The discard block size in the on disk metadata is not + * neccessarily the same as we're currently using. So we have to +@@ -2958,6 +2992,24 @@ static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size) + return 0; + } + ++static int truncate_oblocks(struct cache *cache) ++{ ++ uint32_t nr_blocks = from_cblock(cache->cache_size); ++ uint32_t i; ++ int r; ++ ++ for_each_set_bit(i, cache->invalid_bitset, nr_blocks) { ++ r = dm_cache_remove_mapping(cache->cmd, to_cblock(i)); ++ if (r) { ++ DMERR_LIMIT("%s: invalidation failed; couldn't update on disk metadata", ++ cache_device_name(cache)); ++ return r; ++ } ++ } ++ ++ return 0; ++} ++ + static int cache_preresume(struct dm_target *ti) + { + int r = 0; +@@ -2982,11 +3034,25 @@ static int cache_preresume(struct dm_target *ti) + } + + if (!cache->loaded_mappings) { ++ /* ++ * The fast device could have been resized since the last ++ * failed preresume attempt. To be safe we start by a blank ++ * bitset for cache blocks. ++ */ ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + r = dm_cache_load_mappings(cache->cmd, cache->policy, +- load_mapping, cache); ++ load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ if (r != -EFBIG) ++ metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ return r; ++ } ++ ++ r = truncate_oblocks(cache); ++ if (r) { ++ metadata_operation_failed(cache, "dm_cache_remove_mapping", r); + return r; + } + +@@ -3460,7 +3526,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 2, 0}, ++ .version = {2, 3, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-5.15/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch b/queue-5.15/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch new file mode 100644 index 0000000000..e9895bd224 --- /dev/null +++ b/queue-5.15/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch @@ -0,0 +1,58 @@ +From 8b324b5e93b5ed50406a9091bd468b9db3f0e38d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 22:32:28 +0100 +Subject: dm init: ensure device probing has finished in dm-mod.waitfor= + +From: Guillaume Gonnet + +[ Upstream commit 99a2312f69805f4ba92d98a757625e0300a747ab ] + +The early_lookup_bdev() function returns successfully when the disk +device is present but not necessarily its partitions. In this situation, +dm_early_create() fails as the partition block device does not exist +yet. + +In my case, this phenomenon occurs quite often because the device is +an SD card with slow reading times, on which kernel takes time to +enumerate available partitions. + +Fortunately, the underlying device is back to "probing" state while +enumerating partitions. Waiting for all probing to end is enough to fix +this issue. + +That's also the reason why this problem never occurs with rootwait= +parameter: the while loop inside wait_for_root() explicitly waits for +probing to be done and then the function calls async_synchronize_full(). +These lines were omitted in 035641b, even though the commit says it's +based on the rootwait logic... + +Anyway, calling wait_for_device_probe() after our while loop does the +job (it both waits for probing and calls async_synchronize_full). + +Fixes: 035641b01e72 ("dm init: add dm-mod.waitfor to wait for asynchronously probed block devices") +Signed-off-by: Guillaume Gonnet +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-init.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c +index 6e9e73a558740..882dc385cf068 100644 +--- a/drivers/md/dm-init.c ++++ b/drivers/md/dm-init.c +@@ -302,8 +302,10 @@ static int __init dm_init_init(void) + } + } + +- if (waitfor[0]) ++ if (waitfor[0]) { ++ wait_for_device_probe(); + DMINFO("all devices available"); ++ } + + list_for_each_entry(dev, &devices, list) { + if (dm_early_create(&dev->dmi, dev->table, +-- +2.53.0 + diff --git a/queue-5.15/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch b/queue-5.15/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch new file mode 100644 index 0000000000..f20ea1ddf8 --- /dev/null +++ b/queue-5.15/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch @@ -0,0 +1,81 @@ +From 31727ae8fb1118f20b24d804ac19439e5ea1de2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:05:48 +0800 +Subject: dm log: fix out-of-bounds write due to region_count overflow + +From: Junrui Luo + +[ Upstream commit c20e36b7631d83e7535877f08af8b0af72c44b1a ] + +The local variable region_count in create_log_context() is declared as +unsigned int (32-bit), but dm_sector_div_up() returns sector_t (64-bit). +When a device-mapper target has a sufficiently large ti->len with a small +region_size, the division result can exceed UINT_MAX. The truncated +value is then used to calculate bitset_size, causing clean_bits, +sync_bits, and recovering_bits to be allocated far smaller than needed +for the actual number of regions. + +Subsequent log operations (log_set_bit, log_clear_bit, log_test_bit) use +region indices derived from the full untruncated region space, causing +out-of-bounds writes to kernel heap memory allocated by vmalloc. + +This can be reproduced by creating a mirror target whose region_count +overflows 32 bits: + + dmsetup create bigzero --table '0 8589934594 zero' + dmsetup create mymirror --table '0 8589934594 mirror \ + core 2 2 nosync 2 /dev/mapper/bigzero 0 \ + /dev/mapper/bigzero 0' + +The status output confirms the truncation (sync_count=1 instead of +4294967297, because 0x100000001 was truncated to 1): + + $ dmsetup status mymirror + 0 8589934594 mirror 2 254:1 254:1 1/4294967297 ... + +This leads to a kernel crash in core_in_sync: + + BUG: scheduling while atomic: (udev-worker)/9150/0x00000000 + RIP: 0010:core_in_sync+0x14/0x30 [dm_log] + CR2: 0000000000000008 + Fixing recursive fault but reboot is needed! + +Fix by widening the local region_count to sector_t and adding an +explicit overflow check before the value is assigned to lc->region_count. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-log.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c +index b40741bedfd43..7258e2fe00e8d 100644 +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -368,7 +368,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + + struct log_c *lc; + uint32_t region_size; +- unsigned int region_count; ++ sector_t region_count; + size_t bitset_size, buf_size; + int r; + char dummy; +@@ -397,6 +397,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + } + + region_count = dm_sector_div_up(ti->len, region_size); ++ if (region_count > UINT_MAX) { ++ DMWARN("region count exceeds limit of %u", UINT_MAX); ++ return -EINVAL; ++ } + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) { +-- +2.53.0 + diff --git a/queue-5.15/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch b/queue-5.15/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch new file mode 100644 index 0000000000..fa63a75c8c --- /dev/null +++ b/queue-5.15/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch @@ -0,0 +1,50 @@ +From 9d3f836940eab5dc15c6777d2689a62d9793d250 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 14:02:19 +0800 +Subject: dmaengine: dw-axi-dmac: Remove unnecessary return statement from void + function + +From: Khairul Anuar Romli + +[ Upstream commit 48278a72fce8a8d30efaedeb206c9c3f05c1eb3f ] + +checkpatch.pl --strict reports a WARNING in dw-axi-dmac-platform.c: + + WARNING: void function return statements are not generally useful + FILE: drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c + +According to Linux kernel coding style [Documentation/process/ +coding-style.rst], explicit "return;" statements at the end of void +functions are redundant and should be omitted. The function will +automatically return upon reaching the closing brace, so the extra +statement adds unnecessary clutter without functional benefit. + +This patch removes the superfluous "return;" statement in +dw_axi_dma_set_hw_channel() to comply with kernel coding standards and +eliminate the checkpatch warning. + +Fixes: 32286e279385 ("dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel") +Signed-off-by: Khairul Anuar Romli +Link: https://patch.msgid.link/20260202060224.12616-4-karom.9560@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index 6715ade391aa1..95b3c2ea98419 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -502,8 +502,6 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) + (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0); +- +- return; + } + + /* +-- +2.53.0 + diff --git a/queue-5.15/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch b/queue-5.15/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch new file mode 100644 index 0000000000..5b4ae4683a --- /dev/null +++ b/queue-5.15/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch @@ -0,0 +1,37 @@ +From 9e87ee13839bdd9044eefaf6dbd1c4f89cc1a685 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:41:38 -0500 +Subject: dmaengine: mxs-dma: Fix missing return value from + of_dma_controller_register() + +From: Frank Li + +[ Upstream commit ab2bf6d4c0a0152907b18d25c1b118ea5ea779df ] + +Propagate the return value of of_dma_controller_register() in probe() +instead of ignoring it. + +Fixes: a580b8c5429a6 ("dmaengine: mxs-dma: add dma support for i.MX23/28") +Signed-off-by: Frank Li +Link: https://patch.msgid.link/20260225-mxsdma-module-v3-2-8f798b13baa6@nxp.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mxs-dma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c +index dc147cc2436e9..5d34440b9e127 100644 +--- a/drivers/dma/mxs-dma.c ++++ b/drivers/dma/mxs-dma.c +@@ -827,6 +827,7 @@ static int mxs_dma_probe(struct platform_device *pdev) + if (ret) { + dev_err(mxs_dma->dma_device.dev, + "failed to register controller\n"); ++ return ret; + } + + dev_info(mxs_dma->dma_device.dev, "initialized\n"); +-- +2.53.0 + diff --git a/queue-5.15/documentation-fix-a-hugetlbfs-reservation-statement.patch b/queue-5.15/documentation-fix-a-hugetlbfs-reservation-statement.patch new file mode 100644 index 0000000000..e1a5a10591 --- /dev/null +++ b/queue-5.15/documentation-fix-a-hugetlbfs-reservation-statement.patch @@ -0,0 +1,63 @@ +From 9e324c4788eb98755b96297e706c28dc60fa60de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 13:10:15 -0700 +Subject: Documentation: fix a hugetlbfs reservation statement + +From: Jane Chu + +[ Upstream commit 7a197d346a44384a1a858a98ef03766840e561d4 ] + +Documentation/mm/hugetlbfs_reserv.rst has + if (resv_needed <= (resv_huge_pages - free_huge_pages)) + resv_huge_pages += resv_needed; +which describes this code in gather_surplus_pages() + needed = (h->resv_huge_pages + delta) - h->free_huge_pages; + if (needed <= 0) { + h->resv_huge_pages += delta; + return 0; + } +which means if there are enough free hugepages to account for the new +reservation, simply update the global reservation count without +further action. + +But the description is backwards, it should be + if (resv_needed <= (free_huge_pages - resv_huge_pages)) +instead. + +Link: https://lkml.kernel.org/r/20260302201015.1824798-1-jane.chu@oracle.com +Fixes: 70bc0dc578b3 ("Documentation: vm, add hugetlbfs reservation overview") +Signed-off-by: Jane Chu +Cc: David Hildenbrand +Cc: Hillf Danton +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Oscar Salvador +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/vm/hugetlbfs_reserv.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/vm/hugetlbfs_reserv.rst b/Documentation/vm/hugetlbfs_reserv.rst +index f143954e0d056..1c238b10e1772 100644 +--- a/Documentation/vm/hugetlbfs_reserv.rst ++++ b/Documentation/vm/hugetlbfs_reserv.rst +@@ -157,7 +157,7 @@ are enough free huge pages to accommodate the reservation. If there are, + the global reservation count resv_huge_pages is adjusted something like the + following:: + +- if (resv_needed <= (resv_huge_pages - free_huge_pages)) ++ if (resv_needed <= (free_huge_pages - resv_huge_pages) + resv_huge_pages += resv_needed; + + Note that the global lock hugetlb_lock is held when checking and adjusting +-- +2.53.0 + diff --git a/queue-5.15/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch b/queue-5.15/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch new file mode 100644 index 0000000000..2507cdc46b --- /dev/null +++ b/queue-5.15/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch @@ -0,0 +1,54 @@ +From 302f61fbfc85e6b13df5f89ee8f615db70f84872 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:06 +0000 +Subject: dpaa2: add independent dependencies for FSL_DPAA2_SWITCH + +From: Cai Xinchen + +[ Upstream commit 12589892f41c4c645c80ef9f036f7451a6045624 ] + +Since the commit 84cba72956fd ("dpaa2-switch: integrate +the MAC endpoint support") included dpaa2-mac.o in the driver, +but it didn't select PCS_LYNX, PHYLINK and FSL_XGMAC_MDIO. it +will lead to link error, such as +undefined reference to `phylink_ethtool_ksettings_set' +undefined reference to `lynx_pcs_create_fwnode' + +And the same reason as the commit d2624e70a2f53 ("dpaa2-eth: select +XGMAC_MDIO for MDIO bus support"), enable the FSL_XGMAC_MDIO Kconfig +option in order to have MDIO access to internal and external PHYs. + +Because dpaa2-switch uses fsl_mc_driver APIs, add depends on FSL_MC_BUS +&& FSL_MC_DPIO as FSL_DPAA2_SWITCH do. + +FSL_XGMAC_MDIO and FSL_MC_BUS depend on OF, thus the dependence of +FSL_MC_BUS can satisfy FSL_XGMAC_MDIO's OF requirement. + +Fixes: 84cba72956fd ("dpaa2-switch: integrate the MAC endpoint support") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-2-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/dpaa2/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig +index d029b69c3f183..36280e5d99e1f 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig ++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig +@@ -34,6 +34,10 @@ config FSL_DPAA2_SWITCH + tristate "Freescale DPAA2 Ethernet Switch" + depends on BRIDGE || BRIDGE=n + depends on NET_SWITCHDEV ++ depends on FSL_MC_BUS && FSL_MC_DPIO ++ select PHYLINK ++ select PCS_LYNX ++ select FSL_XGMAC_MDIO + help + Driver for Freescale DPAA2 Ethernet Switch. This driver manages + switch objects discovered on the Freeescale MC bus. +-- +2.53.0 + diff --git a/queue-5.15/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch b/queue-5.15/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch new file mode 100644 index 0000000000..a987b93e71 --- /dev/null +++ b/queue-5.15/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch @@ -0,0 +1,42 @@ +From 2de2f3e7baf6c02f7bdbf59a2db24535ca141aaa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:07 +0000 +Subject: dpaa2: compile dpaa2 even CONFIG_FSL_DPAA2_ETH=n + +From: Cai Xinchen + +[ Upstream commit 97daf00745f7f9f261b0e91418de6e79d7826c36 ] + +CONFIG_FSL_DPAA2_ETH and CONFIG_FSL_DPAA2_SWITCH are not +associated, but the compilation of FSL_DPAA2_SWITCH depends on +the compilation of the dpaa2 folder. The files controlled by +CONFIG_FSL_DPAA2_SWITCH in the dpaa2 folder are not controlled +by CONFIG_FSL_DPAA2_ETH, except for the files controlled by +CONFIG_FSL_DPAA2_SWITCH. Therefore, removing the restriction will +not affect the compilation of the files in the directory. + +Fixes: f48298d3fbfaa ("staging: dpaa2-switch: move the driver out of staging") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-3-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/Makefile | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile +index de7b318422330..d0a259e47960f 100644 +--- a/drivers/net/ethernet/freescale/Makefile ++++ b/drivers/net/ethernet/freescale/Makefile +@@ -22,6 +22,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o + obj-$(CONFIG_FSL_FMAN) += fman/ + obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/ + +-obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/ +- ++obj-y += dpaa2/ + obj-y += enetc/ +-- +2.53.0 + diff --git a/queue-5.15/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch b/queue-5.15/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch new file mode 100644 index 0000000000..bf75e4a03b --- /dev/null +++ b/queue-5.15/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch @@ -0,0 +1,59 @@ +From 7c13680942386f7d5db6dfc2d9fb42813b770e2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:40:54 -0700 +Subject: drbd: Balance RCU calls in drbd_adm_dump_devices() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bart Van Assche + +[ Upstream commit 2b31e86387e60b3689339f0f0fbb4d3623d9d494 ] + +Make drbd_adm_dump_devices() call rcu_read_lock() before +rcu_read_unlock() is called. This has been detected by the Clang +thread-safety analyzer. + +Tested-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Cc: Andreas Gruenbacher +Fixes: a55bbd375d18 ("drbd: Backport the "status" command") +Signed-off-by: Bart Van Assche +Link: https://patch.msgid.link/20260326214054.284593-1-bvanassche@acm.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_nl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index 69184cf17b6ad..6d2093c2c51b7 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -3424,8 +3424,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + cb->args[0] = (long)resource; + } + } +@@ -3674,8 +3676,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + } + cb->args[0] = (long)resource; + } +-- +2.53.0 + diff --git a/queue-5.15/driver-core-device.h-remove-extern-from-function-pro.patch b/queue-5.15/driver-core-device.h-remove-extern-from-function-pro.patch new file mode 100644 index 0000000000..c84ea9b025 --- /dev/null +++ b/queue-5.15/driver-core-device.h-remove-extern-from-function-pro.patch @@ -0,0 +1,39 @@ +From d344a8be13e378f1f5dde4c6ac5c713bcfd2c4a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Mar 2023 13:27:06 +0100 +Subject: driver core: device.h: remove extern from function prototypes + +From: Greg Kroah-Hartman + +[ Upstream commit f43243c66e5e9ad839d235f82a58e73a7e7612af ] + +The kernel coding style does not require 'extern' in function prototypes +in .h files, so remove them from include/linux/device.h as they are not +needed. + +Acked-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/20230324122711.2664537-1-gregkh@linuxfoundation.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/device.h | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/include/linux/device.h b/include/linux/device.h +index 18f276f4a9c01..97fb43c6d919d 100644 +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -1030,8 +1030,7 @@ void device_links_supplier_sync_state_pause(void); + void device_links_supplier_sync_state_resume(void); + void device_link_wait_removal(void); + +-extern __printf(3, 4) +-int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); ++__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); + + /* Create alias, so I can be autoloaded. */ + #define MODULE_ALIAS_CHARDEV(major,minor) \ +-- +2.53.0 + diff --git a/queue-5.15/driver-core-move-dev_err_probe-to-where-it-belogs.patch b/queue-5.15/driver-core-move-dev_err_probe-to-where-it-belogs.patch new file mode 100644 index 0000000000..dc8c7416b2 --- /dev/null +++ b/queue-5.15/driver-core-move-dev_err_probe-to-where-it-belogs.patch @@ -0,0 +1,54 @@ +From c239840507e14d2b40db26ee5a849d698ea38e98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Jul 2023 16:13:09 +0300 +Subject: driver core: Move dev_err_probe() to where it belogs + +From: Andy Shevchenko + +[ Upstream commit 9e0cace7a6254070159ebd86497eadc29ea307ca ] + +dev_err_probe() belongs to the printing API, hence +move the definition from device.h to dev_printk.h. + +There is no change to the callers at all, since: +1) implementation is located in the same core.c; +2) dev_printk.h is guaranteed to be included by device.h. + +Signed-off-by: Andy Shevchenko +Reviewed-by: Andi Shyti +Link: https://lore.kernel.org/r/20230721131309.16821-1-andriy.shevchenko@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/dev_printk.h | 2 ++ + include/linux/device.h | 2 -- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h +index 65eec5be8ccb9..ae80a303c216b 100644 +--- a/include/linux/dev_printk.h ++++ b/include/linux/dev_printk.h +@@ -275,4 +275,6 @@ do { \ + WARN_ONCE(condition, "%s %s: " format, \ + dev_driver_string(dev), dev_name(dev), ## arg) + ++__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); ++ + #endif /* _DEVICE_PRINTK_H_ */ +diff --git a/include/linux/device.h b/include/linux/device.h +index 97fb43c6d919d..2c16bc2149c20 100644 +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -1030,8 +1030,6 @@ void device_links_supplier_sync_state_pause(void); + void device_links_supplier_sync_state_resume(void); + void device_link_wait_removal(void); + +-__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); +- + /* Create alias, so I can be autoloaded. */ + #define MODULE_ALIAS_CHARDEV(major,minor) \ + MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch b/queue-5.15/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch new file mode 100644 index 0000000000..9cbe5890bf --- /dev/null +++ b/queue-5.15/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch @@ -0,0 +1,45 @@ +From 82f29c8a617ac33b4f1a5cc2f4e94749c7e14bde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:41 +0200 +Subject: drm/amd/display: Allow DCE link encoder without AUX registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ] + +Allow constructing the DCE link encoder without DDC, +which means the AUX registers array will be NULL. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 87f30b101af62590faf6020d106da07efdda199b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index fce0c5d72c1a0..55c367cf72ffd 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -994,7 +994,9 @@ void dce110_link_encoder_hw_init( + ASSERT(result == BP_RESULT_OK); + + } +- aux_initialize(enc110); ++ ++ if (enc110->aux_regs) ++ aux_initialize(enc110); + + /* reinitialize HPD. + * hpd_initialize() will pass DIG_FE id to HW context. +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch b/queue-5.15/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch new file mode 100644 index 0000000000..eedac9ce75 --- /dev/null +++ b/queue-5.15/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch @@ -0,0 +1,137 @@ +From 655f0f9a1a35a643b20b9fb303f940263351d79e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:44 +0200 +Subject: drm/amd/display: Read EDID from VBIOS embedded panel info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ] + +Some board manufacturers hardcode the EDID for the embedded +panel in the VBIOS. This EDID should be used when the panel +doesn't have a DDC. + +For reference, see the legacy non-DC display code: +amdgpu_atombios_encoder_get_lcd_info() + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364) +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ + .../display/include/grph_object_ctrl_defs.h | 4 ++ + 2 files changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index 0f686e363d308..d8982aca8ef68 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1215,6 +1215,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( + return BP_RESULT_FAILURE; + } + ++static enum bp_result get_embedded_panel_extra_info( ++ struct bios_parser *bp, ++ struct embedded_panel_info *info, ++ const uint32_t table_offset) ++{ ++ uint8_t *record = bios_get_image(&bp->base, table_offset, 1); ++ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; ++ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ++ ++ while (*record != ATOM_RECORD_END_TYPE) { ++ switch (*record) { ++ case LCD_MODE_PATCH_RECORD_MODE_TYPE: ++ record += sizeof(ATOM_PATCH_RECORD_MODE); ++ break; ++ case LCD_RTS_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_RTS_RECORD); ++ break; ++ case LCD_CAP_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); ++ break; ++ case LCD_FAKE_EDID_PATCH_RECORD_TYPE: ++ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; ++ if (fake_edid_record->ucFakeEDIDLength) { ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength; ++ else ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength * 128; ++ ++ info->fake_edid = fake_edid_record->ucFakeEDIDString; ++ ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ info->fake_edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; ++ } ++ break; ++ case LCD_PANEL_RESOLUTION_RECORD_TYPE: ++ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; ++ info->panel_width_mm = panel_res_record->usHSize; ++ info->panel_height_mm = panel_res_record->usVSize; ++ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); ++ break; ++ default: ++ return BP_RESULT_BADBIOSTABLE; ++ } ++ } ++ ++ return BP_RESULT_OK; ++} ++ + static enum bp_result get_embedded_panel_info_v1_2( + struct bios_parser *bp, + struct embedded_panel_info *info) +@@ -1331,6 +1385,10 @@ static enum bp_result get_embedded_panel_info_v1_2( + if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) + info->lcd_timing.misc_info.API_ENABLED = true; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +@@ -1456,6 +1514,10 @@ static enum bp_result get_embedded_panel_info_v1_3( + (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & + lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +index 792652236c61b..d42b61ada427e 100644 +--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h ++++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +@@ -153,6 +153,10 @@ struct embedded_panel_info { + uint32_t drr_enabled; + uint32_t min_drr_refresh_rate; + bool realtek_eDPToLVDS; ++ uint16_t panel_width_mm; ++ uint16_t panel_height_mm; ++ uint16_t fake_edid_size; ++ const uint8_t *fake_edid; + }; + + struct dc_firmware_info { +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch b/queue-5.15/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch new file mode 100644 index 0000000000..d870918bf4 --- /dev/null +++ b/queue-5.15/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch @@ -0,0 +1,38 @@ +From 8c4f160ac34dd85c9ff3fc81e0549197ccf03103 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:03 +0200 +Subject: drm/amd/pm/ci: Clear EnabledForActivity field for memory levels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 5facfd4c4c67e8500116ffec0d9da35d92b9c787 ] + +Follow what radeon did and what amdgpu does for other GPUs with SMU7. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index f898d596c6516..c88ec43bd7c6a 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1216,7 +1216,7 @@ static int ci_populate_single_memory_level( + } + + memory_level->EnabledForThrottle = 1; +- memory_level->EnabledForActivity = 1; ++ memory_level->EnabledForActivity = 0; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; + memory_level->VoltageDownH = 0; +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch b/queue-5.15/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch new file mode 100644 index 0000000000..b744fddb7d --- /dev/null +++ b/queue-5.15/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch @@ -0,0 +1,67 @@ +From d8ea68caba5a5c9642b2e9ad1c097c0b14465f89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:59 +0200 +Subject: drm/amd/pm/ci: Disable MCLK DPM on problematic CI ASICs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9851f29cb06c09f7dad3867d8b0feec3fc71b6c8 ] + +There are two known cases where MCLK DPM can causes issues: + +Radeon R9 M380 found in iMac computers from 2015. +The SMU in this GPU just hangs as soon as we send it the +PPSMC_MSG_MCLKDPM_Enable command, even when MCLK switching is +disabled, and even when we only populate one MCLK DPM level. +Apply workaround to all devices with the same subsystem ID. + +Radeon R7 260X due to old memory controller microcode. +We only flash the MC ucode when it isn't set up by the VBIOS, +therefore there is no way to make sure that it has the correct +ucode version. + +I verified that this patch fixes the SMU hang on the R9 M380 +which would previously fail to boot. This also fixes the UVD +initialization error on that GPU which happened because the +SMU couldn't ungate the UVD after it hung. + +Fixes: 86457c3b21cb ("drm/amd/powerplay: Add support for CI asics to hwmgr") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +index f2cef0930aa96..997435a50f21e 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) + PP_GFXOFF_MASK); + hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; ++ switch (hwmgr->chip_id) { ++ case CHIP_BONAIRE: ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM ++ * R7 260X cards with old MC ucode: MCLK DPM is unstable ++ */ ++ if (adev->pdev->subsystem_vendor == 0x106B || ++ adev->pdev->device == 0x6658) { ++ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); ++ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; ++ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; ++ } ++ break; ++ default: ++ break; ++ } + smu7_init_function_pointers(hwmgr); + break; + case AMDGPU_FAMILY_CZ: +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch b/queue-5.15/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch new file mode 100644 index 0000000000..d65004ccfc --- /dev/null +++ b/queue-5.15/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch @@ -0,0 +1,48 @@ +From afbf9728122d1a3cc8e191e59e245c113b2f62f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:04 +0200 +Subject: drm/amd/pm/ci: Fill DW8 fields from SMC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit baf28ec5795c077406d6f52b8ad39e614153bce6 ] + +In ci_populate_dw8() we currently just read a value from the SMU +and then throw it away. Instead of throwing away the value, +we should use it to fill other fields in DW8 (like radeon). + +Otherwise the value of the other fiels is just cleared when +we copy this data to the SMU later. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index c88ec43bd7c6a..43749010fa1eb 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -542,12 +542,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) + { + struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); + const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; +- uint32_t temp; + + if (ci_read_smc_sram_dword(hwmgr, + fuse_table_offset + + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), +- (uint32_t *)&temp, SMC_RAM_END)) ++ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) + PP_ASSERT_WITH_CODE(false, + "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", + return -EINVAL); +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch b/queue-5.15/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch new file mode 100644 index 0000000000..5e95e01311 --- /dev/null +++ b/queue-5.15/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch @@ -0,0 +1,41 @@ +From 5aaa16f61f272c986039b3576250ddb649dfad08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:02 +0200 +Subject: drm/amd/pm/ci: Fix powertune defaults for Hawaii 0x67B0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit d784759c07924280f3c313f205fc48eb62d7cb71 ] + +There is no AMD GPU with the ID 0x66B0, this looks like a typo. +It should be 0x67B0 which is actually part of the PCI ID list, +and should use the Hawaii XT powertune defaults according to +the old radeon driver. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index a6d2c6256c347..f898d596c6516 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -244,7 +244,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) + smu_data->power_tune_defaults = &defaults_hawaii_pro; + break; + case 0x67B8: +- case 0x66B0: ++ case 0x67B0: + smu_data->power_tune_defaults = &defaults_hawaii_xt; + break; + case 0x6640: +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch b/queue-5.15/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch new file mode 100644 index 0000000000..73ab2c277b --- /dev/null +++ b/queue-5.15/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch @@ -0,0 +1,47 @@ +From 0d5fed9b782fcf536626578733b659148d19c707 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:58 +0200 +Subject: drm/amd/pm/ci: Use highest MCLK on CI when MCLK DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 894f0d34d66cb47fe718fe2ae5c18729d22c5218 ] + +When MCLK DPM is disabled for any reason, populate the MCLK +table with the highest MCLK DPM level, so that the ASIC can +use the highest possible memory clock to get good performance +even when MCLK DPM is disabled. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 7cce5d200527e..a6d2c6256c347 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1321,6 +1321,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) + return result; + } + ++ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { ++ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ ++ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { ++ levels[i] = levels[dpm_table->mclk_table.count - 1]; ++ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; ++ } ++ } ++ + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; + + dev_id = adev->pdev->device; +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch b/queue-5.15/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch new file mode 100644 index 0000000000..d1f12ce71a --- /dev/null +++ b/queue-5.15/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch @@ -0,0 +1,129 @@ +From b43d65c4be13ca6f046c365a844add72592c0531 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:05 +0200 +Subject: drm/amd/pm/smu7: Add SCLK cap for quirky Hawaii board +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 4724bc5b8d78c34b993594f9406135408ccb312a ] + +On a specific Radeon R9 390X board, the GPU can "randomly" hang +while gaming. Initially I thought this was a RADV bug and tried +to work around this in Mesa: +commit 8ea08747b86b ("radv: Mitigate GPU hang on Hawaii in Dota 2 and RotTR") + +However, I got some feedback from other users who are reporting +that the above mitigation causes a significant performance +regression for them, and they didn't experience the hang on their +GPU in the first place. + +After some further investigation, it turns out that the problem +is that the highest SCLK DPM level on this board isn't stable. +Lowering SCLK to 1040 MHz (from 1070 MHz) works around the issue, +and has a negligible impact on performance compared to the Mesa +patch. (Note that increasing the voltage can also work around it, +but we felt that lowering the SCLK is the safer option.) + +To solve the above issue, add an "sclk_cap" field to smu7_hwmgr +and set this field for the affected board. The capped SCLK value +correctly appears on the sysfs interface and shows up in GUI +tools such as LACT. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 30 ++++++++++++++++--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h | 1 + + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index d78b08a3737fc..d3fe5b29c8898 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -788,7 +788,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.vddc_dependency_on_mclk; + struct phm_cac_leakage_table *std_voltage_table = + hwmgr->dyn_state.cac_leakage_table; +- uint32_t i; ++ uint32_t i, clk; + + PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, + "SCLK dependency table is missing. This table is mandatory", return -EINVAL); +@@ -805,10 +805,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + data->dpm_table.sclk_table.count = 0; + + for (i = 0; i < allowed_vdd_sclk_table->count; i++) { ++ clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); ++ + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != +- allowed_vdd_sclk_table->entries[i].clk) { ++ clk) { + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = +- allowed_vdd_sclk_table->entries[i].clk; ++ clk; + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; + data->dpm_table.sclk_table.count++; + } +@@ -2956,6 +2958,25 @@ static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr * + return 0; + } + ++static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) ++{ ++ struct amdgpu_device *adev = hwmgr->adev; ++ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); ++ ++ data->sclk_cap = 0xffffffff; ++ ++ if (hwmgr->od_enabled) ++ return; ++ ++ /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ ++ if (adev->pdev->device == 0x67B0 && ++ adev->pdev->subsystem_vendor == 0x1043) ++ data->sclk_cap = 104000; /* 1040 MHz */ ++ ++ if (data->sclk_cap != 0xffffffff) ++ dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -2967,6 +2988,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + return -ENOMEM; + + hwmgr->backend = data; ++ smu7_set_sclk_cap(hwmgr); + smu7_patch_voltage_workaround(hwmgr); + smu7_init_dpm_defaults(hwmgr); + +@@ -3868,7 +3890,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, + + /* Performance levels are arranged from low to high. */ + performance_level->memory_clock = memory_clock; +- performance_level->engine_clock = engine_clock; ++ performance_level->engine_clock = min(engine_clock, data->sclk_cap); + + pcie_gen_from_bios = visland_clk_info->ucPCIEGen; + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +index d9e8b386bd4d3..66adabeab6a3a 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +@@ -234,6 +234,7 @@ struct smu7_hwmgr { + uint32_t pcie_gen_cap; + uint32_t pcie_lane_cap; + uint32_t pcie_spc_cap; ++ uint32_t sclk_cap; + struct smu7_leakage_voltage vddc_leakage; + struct smu7_leakage_voltage vddci_leakage; + struct smu7_leakage_voltage vddcgfx_leakage; +-- +2.53.0 + diff --git a/queue-5.15/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch b/queue-5.15/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch new file mode 100644 index 0000000000..b1eaf6c30a --- /dev/null +++ b/queue-5.15/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch @@ -0,0 +1,192 @@ +From 5b3803db3527087de1609d3e438cdf1491d35e2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:00 +0200 +Subject: drm/amd/pm/smu7: Fix SMU7 voltage dependency on display clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 0138610c14130425be53423b35336561829965e0 ] + +The DCE (display controller engine) requires a minimum voltage +in order to function correctly, depending on which clock level +it currently uses. + +Add a new table that contains display clock frequency levels +and the corresponding required voltages. The clock frequency +levels are taken from DC (and the old radeon driver's voltage +dependency table for CI in cases where its values were lower). +The voltage levels are taken from the following function: +phm_initializa_dynamic_state_adjustment_rule_settings(). +Furthermore, in case of CI, call smu7_patch_vddc() on the new +table to account for leakage voltage (like in radeon). + +Use the display clock value from amd_pp_display_configuration +to look up the voltage level needed by the DCE. Send the +voltage to the SMU via the PPSMC_MSG_VddC_Request command. + +The previous implementation of this feature was non-functional +because it relied on a "dal_power_level" field which was never +assigned; and it was not at all implemented for CI ASICs. + +I verified this on a Radeon R9 M380 which previously booted to +a black screen with DC enabled (default since Linux 6.19), but +now works correctly. + +Fixes: 599a7e9fe1b6 ("drm/amd/powerplay: implement smu7 hwmgr to manager asics with smu ip version 7.") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/inc/hwmgr.h | 1 + + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 88 ++++++++++++++++++- + 2 files changed, 86 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/inc/hwmgr.h +index 8ed01071fe5ad..a82db5150de70 100644 +--- a/drivers/gpu/drm/amd/pm/inc/hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/inc/hwmgr.h +@@ -635,6 +635,7 @@ struct phm_dynamic_state_info { + struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; ++ struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; + struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; + struct phm_clock_array *valid_sclk_values; + struct phm_clock_array *valid_mclk_values; +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index e25032ad16be7..d78b08a3737fc 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -2752,6 +2752,10 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) + if (tmp) + return -EINVAL; + ++ tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ if (tmp) ++ return -EINVAL; ++ + tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); + if (tmp) + return -EINVAL; +@@ -2835,6 +2839,8 @@ static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) + { + kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); + hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; ++ kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; + kfree(hwmgr->backend); + hwmgr->backend = NULL; + +@@ -2905,6 +2911,51 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) + return ret; + } + ++static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) ++{ ++ struct phm_clock_voltage_dependency_table *table; ++ ++ if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) ++ return 0; ++ ++ table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); ++ if (!table) ++ return -ENOMEM; ++ ++ if (hwmgr->chip_id >= CHIP_POLARIS10) { ++ table->entries[0].clk = 38918; ++ table->entries[1].clk = 45900; ++ table->entries[2].clk = 66700; ++ table->entries[3].clk = 113200; ++ ++ table->entries[0].v = 700; ++ table->entries[1].v = 740; ++ table->entries[2].v = 800; ++ table->entries[3].v = 900; ++ } else { ++ if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { ++ table->entries[0].clk = 35200; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 46700; ++ table->entries[3].clk = 64300; ++ } else { ++ table->entries[0].clk = 0; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 54000; ++ table->entries[3].clk = 62500; ++ } ++ ++ table->entries[0].v = 0; ++ table->entries[1].v = 720; ++ table->entries[2].v = 810; ++ table->entries[3].v = 900; ++ } ++ ++ table->count = 4; ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = table; ++ return 0; ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -2933,6 +2984,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + smu7_get_elb_voltages(hwmgr); + } + ++ result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); ++ if (result) ++ goto fail; ++ + if (hwmgr->pp_table_version == PP_TABLE_V1) { + smu7_complete_dependency_tables(hwmgr); + smu7_set_private_data_based_on_pptable_v1(hwmgr); +@@ -3029,13 +3084,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) + return 0; + } + ++static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) ++{ ++ const struct amd_pp_display_configuration *cfg = hwmgr->display_config; ++ const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = ++ hwmgr->dyn_state.vddc_dependency_on_display_clock; ++ uint32_t i; ++ ++ if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || ++ !cfg || !cfg->num_display || !cfg->display_clk) ++ return 0; ++ ++ /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ ++ for (i = 1; i < vddc_dep_on_dispclk->count; ++i) ++ if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) ++ return vddc_dep_on_dispclk->entries[i].v; ++ ++ return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; ++} ++ ++static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) ++{ ++ uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_VddC_Request, ++ req_vddc * VOLTAGE_SCALE, ++ NULL); ++} ++ + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) + { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + +- if (hwmgr->pp_table_version == PP_TABLE_V1) +- phm_apply_dal_min_voltage_request(hwmgr); +-/* TO DO for v0 iceland and Ci*/ ++ smu7_apply_minimum_dce_voltage_request(hwmgr); + + if (!data->sclk_dpm_key_disabled) { + if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) +-- +2.53.0 + diff --git a/queue-5.15/drm-amdgpu-fix-spelling-typos.patch b/queue-5.15/drm-amdgpu-fix-spelling-typos.patch new file mode 100644 index 0000000000..b3cfc58fa5 --- /dev/null +++ b/queue-5.15/drm-amdgpu-fix-spelling-typos.patch @@ -0,0 +1,103 @@ +From 5032da219f2bde46706a16b45fead3338a5406f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 00:05:04 -0500 +Subject: drm/amdgpu: fix spelling typos + +From: Alexandre Demers + +[ Upstream commit ce43abd7ec9464cf954f90e1c69e11768b02fa0a ] + +Found some typos while exploring amdgpu code. + +Signed-off-by: Alexandre Demers +Signed-off-by: Alex Deucher +Stable-dep-of: 13e4cf116dbf ("drm/amdgpu/uvd3.1: Don't validate the firmware when already validated") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 6 +++--- + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 3 ++- + drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | 2 +- + 4 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index 259897f1ea8a4..e00d1637859fe 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -259,7 +259,7 @@ void amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc + * @adev: amdgpu device structure holding all necessary information + * @mc: memory controller structure holding memory information + * +- * Function will place try to place GART before or after VRAM. ++ * Function will try to place GART before or after VRAM. + * If GART size is bigger than space left then we ajust GART size. + * Thus function will never fails. + */ +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index e458e0d5801b0..fbfed90503868 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -98,7 +98,7 @@ static void uvd_v3_1_ring_emit_ib(struct amdgpu_ring *ring, + } + + /** +- * uvd_v3_1_ring_emit_fence - emit an fence & trap command ++ * uvd_v3_1_ring_emit_fence - emit a fence & trap command + * + * @ring: amdgpu_ring pointer + * @addr: address +@@ -242,7 +242,7 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + +- /* programm the VCPU memory controller bits 0-27 */ ++ /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; + WREG32(mmUVD_VCPU_CACHE_OFFSET0, addr); +@@ -416,7 +416,7 @@ static int uvd_v3_1_start(struct amdgpu_device *adev) + /* Set the write pointer delay */ + WREG32(mmUVD_RBC_RB_WPTR_CNTL, 0); + +- /* programm the 4GB memory segment for rptr and ring buffer */ ++ /* Program the 4GB memory segment for rptr and ring buffer */ + WREG32(mmUVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) | + (0x7 << 16) | (0x1 << 31)); + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +index c108b83817951..01d8e7d2caf97 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +@@ -298,7 +298,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) + /* enable VCPU clock */ + WREG32(mmUVD_VCPU_CNTL, 1 << 9); + +- /* disable interupt */ ++ /* disable interrupt */ + WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1)); + + #ifdef __BIG_ENDIAN +@@ -308,6 +308,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) + #endif + WREG32(mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl); + WREG32(mmUVD_MP_SWAP_CNTL, mp_swap_cntl); ++ + /* initialize UVD memory controller */ + WREG32(mmUVD_LMI_CTRL, 0x203108); + +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +index 98952fd387e73..ddbcfcc70df5c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +@@ -278,7 +278,7 @@ static int vce_v2_0_stop(struct amdgpu_device *adev) + int status; + + if (vce_v2_0_lmi_clean(adev)) { +- DRM_INFO("vce is not idle \n"); ++ DRM_INFO("VCE is not idle \n"); + return 0; + } + +-- +2.53.0 + diff --git a/queue-5.15/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch b/queue-5.15/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch new file mode 100644 index 0000000000..752232ae83 --- /dev/null +++ b/queue-5.15/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch @@ -0,0 +1,146 @@ +From 997b077f2066c8cdac5d3f49abcd172f3080d84b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:33 +0200 +Subject: drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ] + +This commit fixes amdgpu to work on the Radeon HD 7870 XT +which has never worked with the Linux open source drivers before. + +Some boards have "harvested" chips, meaning that some parts of +the chip are disabled and fused, and it's sold for cheaper and +under a different marketing name. +On a harvested chip, any of the following can be disabled: +- CUs (Compute Units) +- RBs (Render Backend, aka. ROP) +- Memory channels (ie. the chip has a lower bandwidth) +- TCCs (ie. less L2 cache) + +Handle chips with harvested TCCs by patching the registers +that configure how TCCs are mapped. + +If some TCCs are disabled, we need to make sure that +the disabled TCCs are not used, and the remaining TCCs +are used optimally. + +TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. + +Note that the TCC configuration is highly relevant to performance. +Suboptimal configuration (eg. CHAN_STEER=0) can significantly +reduce gaming performance. + +For optimal performance: +- Rely on the CHAN_STEER from the golden registers table, + only skip disabled TCCs but keep the mapping order. +- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, + which performs better than using the same TCC twice. + +v2: +- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs. + +Link: https://bugs.freedesktop.org/show_bug.cgi?id=60879 +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2664 +Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 00218d15528fab9f6b31241fe5904eea4fcaa30d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index 79074d22959b9..eecc93f8c3cd5 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -1568,6 +1568,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) + mutex_unlock(&adev->grbm_idx_mutex); + } + ++/** ++ * gfx_v6_0_setup_tcc() - setup which TCCs are used ++ * ++ * @adev: amdgpu_device pointer ++ * ++ * Verify whether the current GPU has any TCCs disabled, ++ * which can happen when the GPU is harvested and some ++ * memory channels are disabled, reducing the memory bus width. ++ * For example, on the Radeon HD 7870 XT (Tahiti LE). ++ * ++ * If some TCCs are disabled, we need to make sure that ++ * the disabled TCCs are not used, and the remaining TCCs ++ * are used optimally. ++ * ++ * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. ++ * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. ++ * ++ * For optimal performance: ++ * - Rely on the CHAN_STEER from the golden registers table, ++ * only skip disabled TCCs but keep the mapping order. ++ * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, ++ * which performs better than using the same TCC twice. ++ */ ++static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) ++{ ++ u32 i, tcc, tcp_addr_config, num_active_tcc = 0; ++ u64 chan_steer, patched_chan_steer = 0; ++ const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; ++ const u32 dis_tcc_mask = ++ amdgpu_gfx_create_bitmask(num_max_tcc) & ++ (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), ++ CGTS_TCC_DISABLE, TCC_DISABLE) | ++ REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), ++ CGTS_USER_TCC_DISABLE, TCC_DISABLE)); ++ ++ /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ ++ if (!dis_tcc_mask) ++ return; ++ ++ /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ ++ chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); ++ ++ /* Patch the TCP to TCC mapping to skip disabled TCCs */ ++ for (i = 0; i < num_max_tcc; ++i) { ++ tcc = (chan_steer >> (u64)(4 * i)) & 0xf; ++ ++ if (!((1 << tcc) & dis_tcc_mask)) { ++ /* Copy enabled TCC indices to the patched register value. */ ++ patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); ++ ++num_active_tcc; ++ } ++ } ++ ++ WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); ++ ++ /* Patch number of TCCs used by TCPs */ ++ tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), ++ TCP_ADDR_CONFIG, NUM_TCC_BANKS, ++ num_active_tcc - 1); ++ ++ WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); ++ WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); ++ WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); ++} ++ + static void gfx_v6_0_config_init(struct amdgpu_device *adev) + { + adev->gfx.config.double_offchip_lds_buf = 0; +@@ -1726,6 +1791,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) + gfx_v6_0_tiling_mode_table_init(adev); + + gfx_v6_0_setup_rb(adev); ++ gfx_v6_0_setup_tcc(adev); + + gfx_v6_0_setup_spi(adev); + +-- +2.53.0 + diff --git a/queue-5.15/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch b/queue-5.15/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch new file mode 100644 index 0000000000..20755d4024 --- /dev/null +++ b/queue-5.15/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch @@ -0,0 +1,65 @@ +From fbf120272684c0c048e2b8e8eb10b5eeff22b57a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:31 +0200 +Subject: drm/amdgpu/uvd3.1: Don't validate the firmware when already validated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ] + +UVD 3.1 firmware validation seems to always fail after +attempting it when it had already been validated. +(This works similarly with the VCE 1.0 as well.) + +Don't attempt repeating the validation when it's already done. + +This caused issues in situations when the system isn't able +to suspend the GPU properly and so the GPU isn't actually +powered down. Then amdgpu would fail when calling the IP +block resume function. + +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2887 +Fixes: bb7978111dd3 ("drm/amdgpu: fix SI UVD firmware validate resume fail") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 889a2cfd889c4a4dd9d0c89ce9a8e60b78be71dd) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index fbfed90503868..3a27bed57b4ff 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + ++ /* When the keyselect is already set, don't perturb it. */ ++ if (RREG32(mmUVD_FW_START)) ++ return; ++ + /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; +@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) + int i; + uint32_t keysel = adev->uvd.keyselect; + ++ if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { ++ dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", ++ RREG32(mmUVD_FW_START), adev->uvd.keyselect); ++ return 0; ++ } ++ + WREG32(mmUVD_FW_START, keysel); + + for (i = 0; i < 10; ++i) { +-- +2.53.0 + diff --git a/queue-5.15/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch b/queue-5.15/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch new file mode 100644 index 0000000000..fa8d93e795 --- /dev/null +++ b/queue-5.15/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch @@ -0,0 +1,60 @@ +From 858841cc080e2c5cdcb592b584e7a14589d087b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:48:46 +0300 +Subject: drm/komeda: fix integer overflow in AFBC framebuffer size check + +From: Alexander Konyukhov + +[ Upstream commit 779ec12c85c9e4547519e3903a371a3b26a289de ] + +The AFBC framebuffer size validation calculates the minimum required +buffer size by adding the AFBC payload size to the framebuffer offset. +This addition is performed without checking for integer overflow. + +If the addition oveflows, the size check may incorrectly succed and +allow userspace to provide an undersized drm_gem_object, potentially +leading to out-of-bounds memory access. + +Add usage of check_add_overflow() to safely compute the minimum +required size and reject the framebuffer if an overflow is detected. +This makes the AFBC size validation more robust against malformed. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 65ad2392dd6d ("drm/komeda: Added AFBC support for komeda driver") +Signed-off-by: Alexander Konyukhov +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://lore.kernel.org/r/20260203134907.1587067-1-Alexander.Konyukhov@kaspersky.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +index 3c372d2deb0a6..4bc2b9101354a 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +@@ -4,6 +4,8 @@ + * Author: James.Qian.Wang + * + */ ++#include ++ + #include + #include + #include +@@ -92,7 +94,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file, + kfb->afbc_size = kfb->offset_payload + n_blocks * + ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, + AFBC_SUPERBLK_ALIGNMENT); +- min_size = kfb->afbc_size + fb->offsets[0]; ++ if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) { ++ goto check_failed; ++ } + if (min_size > obj->size) { + DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n", + obj->size, min_size); +-- +2.53.0 + diff --git a/queue-5.15/drm-msm-a6xx-fix-hlsq-register-dumping.patch b/queue-5.15/drm-msm-a6xx-fix-hlsq-register-dumping.patch new file mode 100644 index 0000000000..3d29f68865 --- /dev/null +++ b/queue-5.15/drm-msm-a6xx-fix-hlsq-register-dumping.patch @@ -0,0 +1,39 @@ +From 796ecef78b749e9b25bf4fb52c10eb5fa1f494e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:40:42 -0700 +Subject: drm/msm/a6xx: Fix HLSQ register dumping + +From: Rob Clark + +[ Upstream commit c289a6db9ba6cb974f0317da142e4f665d589566 ] + +Fix the bitfield offset of HLSQ_READ_SEL state-type bitfield. Otherwise +we are always reading TP state when we wanted SP or HLSQ state. + +Reported-by: Connor Abbott +Suggested-by: Connor Abbott +Fixes: 1707add81551 ("drm/msm/a6xx: Add a6xx gpu state") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714236/ +Message-ID: <20260325184043.1259312-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 61d0bb8c2fe0b..b25395af39b29 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -642,7 +642,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, + u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; + int i, regcount = 0; + +- in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); ++ in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); + + for (i = 0; i < regs->count; i += 2) { + u32 count = RANGE(regs->registers, i); +-- +2.53.0 + diff --git a/queue-5.15/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch b/queue-5.15/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch new file mode 100644 index 0000000000..36335cfd84 --- /dev/null +++ b/queue-5.15/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch @@ -0,0 +1,72 @@ +From e62b65ecfc19b07b5a0d2c726ccbe6428508976c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:50 +0530 +Subject: drm/msm/a6xx: Use barriers while updating HFI Q headers + +From: Akhil P Oommen + +[ Upstream commit dc78b35d5ec09d1b0b8a937e6e640d2c5a030915 ] + +To avoid harmful compiler optimizations and IO reordering in the HW, use +barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI +queue index variables. + +Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714653/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-1-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +index a40ad74877623..8f1a02e199681 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +@@ -29,7 +29,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + struct a6xx_hfi_queue_header *header = queue->header; + u32 i, hdr, index = header->read_index; + +- if (header->read_index == header->write_index) { ++ if (header->read_index == READ_ONCE(header->write_index)) { + header->rx_request = 1; + return 0; + } +@@ -55,7 +55,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + if (!gmu->legacy) + index = ALIGN(index, 4) % header->size; + +- header->read_index = index; ++ /* Ensure all memory operations are complete before updating the read index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->read_index, index); + return HFI_HEADER_SIZE(hdr); + } + +@@ -67,7 +70,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + + spin_lock(&queue->lock); + +- space = CIRC_SPACE(header->write_index, header->read_index, ++ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), + header->size); + if (space < dwords) { + header->dropped++; +@@ -86,7 +89,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + queue->data[index] = 0xfafafafa; + } + +- header->write_index = index; ++ /* Ensure all memory operations are complete before updating the write index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->write_index, index); + spin_unlock(&queue->lock); + + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); +-- +2.53.0 + diff --git a/queue-5.15/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch b/queue-5.15/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch new file mode 100644 index 0000000000..7fd0a7cee4 --- /dev/null +++ b/queue-5.15/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch @@ -0,0 +1,62 @@ +From a4a4e344dde79912225b9347f251f66d4c5b0e0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:48:27 +0000 +Subject: drm/msm/dsi: rename MSM8998 DSI version from V2_2_0 to V2_0_0 + +From: Alexander Koskovich + +[ Upstream commit 913a709dea0eff9c7b2e9470f8c8594b9a0114ab ] + +The MSM8998 DSI controller is v2.0.0 as stated in commit 7b8c9e203039 +("drm/msm/dsi: Add support for MSM8998 DSI controller"). The value was +always correct just the name was wrong. + +Rename and reorder to maintain version sorting. + +Fixes: 7b8c9e203039 ("drm/msm/dsi: Add support for MSM8998 DSI controller") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Alexander Koskovich +Patchwork: https://patchwork.freedesktop.org/patch/713717/ +Link: https://lore.kernel.org/r/20260324-dsi-rgb101010-support-v5-3-ff6afc904115@pm.me +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_cfg.c | 4 ++-- + drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +index 68a3f8fea9fe6..f61ccdf2b7398 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +@@ -268,10 +268,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { + &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, + &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, ++ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, ++ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, + &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, +- {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, +- &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +index 41e99a9fb5de5..426ed4c97ae52 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +@@ -18,8 +18,8 @@ + #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 + #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 + #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 ++#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 +-#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 + #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 + #define MSM_DSI_6G_VER_MINOR_V2_4_0 0x20040000 +-- +2.53.0 + diff --git a/queue-5.15/drm-panel-simple-correct-g190ean01-prepare-timing.patch b/queue-5.15/drm-panel-simple-correct-g190ean01-prepare-timing.patch new file mode 100644 index 0000000000..6e36847152 --- /dev/null +++ b/queue-5.15/drm-panel-simple-correct-g190ean01-prepare-timing.patch @@ -0,0 +1,41 @@ +From f7e2b9a93fb1408e48ed0c02c7091013527382e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 16:25:26 +0200 +Subject: drm/panel: simple: Correct G190EAN01 prepare timing + +From: Sebastian Reichel + +[ Upstream commit f1080f82570b797598c1ba7e9c800ae9e94aafc6 ] + +The prepare timing specified by the G190EAN01 datasheet should be +between 30 and 50 ms. Considering it might take some time for the +LVDS encoder to enable the signal, we should only wait the min. +required time in the panel driver and not the max. allowed time. + +Fixes: 2f7b832fc992 ("drm/panel: simple: Add support for AUO G190EAN01 panel") +Signed-off-by: Sebastian Reichel +Signed-off-by: Ian Ray +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260217142528.68613-1-ian.ray@gehealthcare.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-simple.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 17e1aaa706f1b..539b58af565ee 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1388,7 +1388,7 @@ static const struct panel_desc auo_g190ean01 = { + .height = 301, + }, + .delay = { +- .prepare = 50, ++ .prepare = 30, + .enable = 200, + .disable = 110, + .unprepare = 1000, +-- +2.53.0 + diff --git a/queue-5.15/drm-sun4i-backend-fix-error-pointer-dereference.patch b/queue-5.15/drm-sun4i-backend-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..0b4ca5eabe --- /dev/null +++ b/queue-5.15/drm-sun4i-backend-fix-error-pointer-dereference.patch @@ -0,0 +1,43 @@ +From 86a8d29cb4e26519d48627b41e3695fe50b25b78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 19:48:01 -0600 +Subject: drm/sun4i: backend: fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit 06277983eca4a31d3c2114fa33d99a6e82484b11 ] + +The function drm_atomic_get_plane_state() can return an error pointer +and is not checked for it. Add error pointer check. + +Detected by Smatch: +drivers/gpu/drm/sun4i/sun4i_backend.c:496 sun4i_backend_atomic_check() error: +'plane_state' dereferencing possible ERR_PTR() + +Fixes: 96180dde23b79 ("drm/sun4i: backend: Add a custom atomic_check for the frontend") +Signed-off-by: Ethan Tidmore +Reviewed-by: Chen-Yu Tsai +Link: https://patch.msgid.link/20260217014801.60760-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index bf8cfefa03652..a812de372437b 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -507,6 +507,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, + drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); ++ if (IS_ERR(plane_state)) ++ return PTR_ERR(plane_state); ++ + struct sun4i_layer_state *layer_state = + state_to_sun4i_layer_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; +-- +2.53.0 + diff --git a/queue-5.15/drm-sun4i-fix-resource-leaks.patch b/queue-5.15/drm-sun4i-fix-resource-leaks.patch new file mode 100644 index 0000000000..f7ce2d8e45 --- /dev/null +++ b/queue-5.15/drm-sun4i-fix-resource-leaks.patch @@ -0,0 +1,41 @@ +From e3aab6c31893d6800e4a5b7c41f87f0e91cf3a5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:38:36 -0600 +Subject: drm/sun4i: Fix resource leaks + +From: Ethan Tidmore + +[ Upstream commit 127367ad2e0f4870de60c6d719ae82ecf68d674c ] + +Three clocks are not being released in devm_regmap_init_mmio() error +path. + +Add proper goto and set ret to the error code. + +Fixes: 8270249fbeaf0 ("drm/sun4i: backend: Create regmap after access is possible") +Signed-off-by: Ethan Tidmore +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260226163836.10335-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index a812de372437b..5f0b58be6afb8 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -879,7 +879,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, + &sun4i_backend_regmap_config); + if (IS_ERR(backend->engine.regs)) { + dev_err(dev, "Couldn't create the backend regmap\n"); +- return PTR_ERR(backend->engine.regs); ++ ret = PTR_ERR(backend->engine.regs); ++ goto err_disable_ram_clk; + } + + list_add_tail(&backend->engine.list, &drv->engine_list); +-- +2.53.0 + diff --git a/queue-5.15/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch b/queue-5.15/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch new file mode 100644 index 0000000000..cbf6d34f36 --- /dev/null +++ b/queue-5.15/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch @@ -0,0 +1,52 @@ +From cd8b18c12ae17986eaf690610ecc12776829b0e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:25 +0100 +Subject: dt-bindings: clock: qcom,dispcc-sc7180: Define MDSS resets + +From: Konrad Dybcio + +[ Upstream commit fc6e29d42872680dca017f2e5169eefe971f8d89 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: 75616da71291 ("dt-bindings: clock: Introduce QCOM sc7180 display clock bindings") +Signed-off-by: Konrad Dybcio +Reviewed-by: Taniya Das +Acked-by: Krzysztof Kozlowski +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-1-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: b0bc6011c549 ("clk: qcom: dispcc-sc7180: Add missing MDSS resets") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,dispcc-sc7180.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/dt-bindings/clock/qcom,dispcc-sc7180.h b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +index b9b51617a335d..0705103060748 100644 +--- a/include/dt-bindings/clock/qcom,dispcc-sc7180.h ++++ b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +@@ -6,6 +6,7 @@ + #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + ++/* Clocks */ + #define DISP_CC_PLL0 0 + #define DISP_CC_PLL0_OUT_EVEN 1 + #define DISP_CC_MDSS_AHB_CLK 2 +@@ -40,7 +41,11 @@ + #define DISP_CC_MDSS_VSYNC_CLK_SRC 31 + #define DISP_CC_XO_CLK 32 + +-/* DISP_CC GDSCR */ ++/* Resets */ ++#define DISP_CC_MDSS_CORE_BCR 0 ++#define DISP_CC_MDSS_RSCC_BCR 1 ++ ++/* GDSCs */ + #define MDSS_GDSC 0 + + #endif +-- +2.53.0 + diff --git a/queue-5.15/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-5.15/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..46fb21a7bd --- /dev/null +++ b/queue-5.15/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,40 @@ +From aea0f85e5993d1c51c3ce89b793724ec6da40807 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:06 -0300 +Subject: dt-bindings: clock: qcom,gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 76404ffbf07f28a5ec04748e18fce3dac2e78ef6 ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Signed-off-by: Val Packett +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20260312112321.370983-2-val@packett.cool +Signed-off-by: Bjorn Andersson +Stable-dep-of: 3565741eb985 ("clk: qcom: gcc-sc8180x: Add missing GDSCs") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,gcc-sc8180x.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/dt-bindings/clock/qcom,gcc-sc8180x.h b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +index 2569f874fe13c..be97a0ca2ade4 100644 +--- a/include/dt-bindings/clock/qcom,gcc-sc8180x.h ++++ b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +@@ -308,5 +308,10 @@ + #define USB30_MP_GDSC 8 + #define USB30_PRIM_GDSC 9 + #define USB30_SEC_GDSC 10 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 11 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 12 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 13 ++#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 14 ++#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 15 + + #endif +-- +2.53.0 + diff --git a/queue-5.15/e1000e-unroll-ptp-in-probe-error-handling.patch b/queue-5.15/e1000e-unroll-ptp-in-probe-error-handling.patch new file mode 100644 index 0000000000..29b53e7eb9 --- /dev/null +++ b/queue-5.15/e1000e-unroll-ptp-in-probe-error-handling.patch @@ -0,0 +1,41 @@ +From 7579eb71ccefe60033847d2e1bcd86d063d27fd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:36 -0700 +Subject: e1000e: Unroll PTP in probe error handling + +From: Matt Vollrath + +[ Upstream commit aa3f7fe409350857c25d050482a2eef2cfd69b58 ] + +If probe fails after registering the PTP clock and its delayed work, +these resources must be released. + +This was not an issue until a 2016 fix moved the e1000e_ptp_init() call +before the jump to err_register. + +Fixes: aa524b66c5ef ("e1000e: don't modify SYSTIM registers during SIOCSHWTSTAMP ioctl") +Signed-off-by: Matt Vollrath +Tested-by: Avigail Dahan +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-12-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 3216089642648..2154d476f9da6 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -7708,6 +7708,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + err_register: + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000e_release_hw_control(adapter); ++ e1000e_ptp_remove(adapter); + err_eeprom: + if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) + e1000_phy_hw_reset(&adapter->hw); +-- +2.53.0 + diff --git a/queue-5.15/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch b/queue-5.15/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch new file mode 100644 index 0000000000..742b3505c3 --- /dev/null +++ b/queue-5.15/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch @@ -0,0 +1,52 @@ +From 8f6baa8ab38252c19f8736a2a890fbfe0af16d05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:46:37 +0200 +Subject: efi/capsule-loader: fix incorrect sizeof in phys array reallocation + +From: Thomas Huth + +[ Upstream commit 48a428215782321b56956974f23593e40ce84b7a ] + +The krealloc() call for cap_info->phys in __efi_capsule_setup_info() uses +sizeof(phys_addr_t *) instead of sizeof(phys_addr_t), which might be +causing an undersized allocation. + +The allocation is also inconsistent with the initial array allocation in +efi_capsule_open() that allocates one entry with sizeof(phys_addr_t), +and the efi_capsule_write() function that stores phys_addr_t values (not +pointers) via page_to_phys(). + +On 64-bit systems where sizeof(phys_addr_t) == sizeof(phys_addr_t *), this +goes unnoticed. On 32-bit systems with PAE where phys_addr_t is 64-bit but +pointers are 32-bit, this allocates half the required space, which might +lead to a heap buffer overflow when storing physical addresses. + +This is similar to the bug fixed in commit fccfa646ef36 ("efi/capsule-loader: +fix incorrect allocation size") which fixed the same issue at the initial +allocation site. + +Fixes: f24c4d478013 ("efi/capsule-loader: Reinstate virtual capsule mapping") +Assisted-by: Claude:claude-sonnet-4-5 +Signed-off-by: Thomas Huth +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + drivers/firmware/efi/capsule-loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c +index 97bafb5f70389..c6a8bdbcae71b 100644 +--- a/drivers/firmware/efi/capsule-loader.c ++++ b/drivers/firmware/efi/capsule-loader.c +@@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) + cap_info->pages = temp_page; + + temp_page = krealloc(cap_info->phys, +- pages_needed * sizeof(phys_addr_t *), ++ pages_needed * sizeof(phys_addr_t), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-5.15/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch b/queue-5.15/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch new file mode 100644 index 0000000000..ceb52ffd6a --- /dev/null +++ b/queue-5.15/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch @@ -0,0 +1,71 @@ +From 5b1b5809f17b9f47e5632f669445ea327e318f66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 15:36:46 +0100 +Subject: fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build + break + +From: Andy Shevchenko + +[ Upstream commit caf6144053b4e1c815aa56afb54745a176f999df ] + +Clang is not happy about set but unused variable: + +drivers/video/fbdev/matrox/g450_pll.c:412:18: error: variable 'mnp' set but not used + 412 | unsigned int mnp; + | ^ +1 error generated. + +Since the commit 7b987887f97b ("video: fbdev: matroxfb: remove dead code +and set but not used variable") the 'mnp' became unused, but eliminating +that code might have side-effects. The question here is what should we do +with 'mnp'? The easiest way out is just mark it with __maybe_unused which +will shut the compiler up and won't change any possible IO flow. So does +this change. + +A dive into the history of the driver: + +The problem was revealed when the #if 0 guarded code along with unused +pixel_vco variable was removed. That code was introduced in the original +commit 213d22146d1f ("[PATCH] (1/3) matroxfb for 2.5.3"). And then guarded +in the commit 705e41f82988 ("matroxfb DVI updates: Handle DVI output on +G450/G550. Powerdown unused portions of G450/G550 DAC. Split G450/G550 DAC +from older DAC1064 handling. Modify PLL setting when both CRTCs use same +pixel clocks."). + +NOTE: The two commits mentioned above pre-date Git era and available in +history.git repository for archaeological purposes. + +Even without that guard the modern compilers may see that the pixel_vco +wasn't ever used and seems a leftover after some debug or review made +25 years ago. + +The g450_mnp2vco() doesn't have any IO and as Jason said doesn't seem +to have any side effects either than some unneeded CPU processing during +runtime. I agree that's unlikely that timeout (or heating up the CPU) has +any effect on the HW (GPU/display) functionality. + +Fixes: 7b987887f97b ("video: fbdev: matroxfb: remove dead code and set but not used variable") +Signed-off-by: Andy Shevchenko +Reviewed-by: Jason Yan +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/matrox/g450_pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c +index ff8e321a22cef..b2d3f7328ea83 100644 +--- a/drivers/video/fbdev/matrox/g450_pll.c ++++ b/drivers/video/fbdev/matrox/g450_pll.c +@@ -407,7 +407,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, + case M_VIDEO_PLL: + { + u_int8_t tmp; +- unsigned int mnp; ++ unsigned int mnp __maybe_unused; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); +-- +2.53.0 + diff --git a/queue-5.15/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch b/queue-5.15/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch new file mode 100644 index 0000000000..6e30ccf525 --- /dev/null +++ b/queue-5.15/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch @@ -0,0 +1,52 @@ +From 7d14e8eae0ca51454e803d70c4a8f32ca15cb4d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:01:18 -0400 +Subject: fbdev: offb: fix PCI device reference leak on probe failure + +From: Yuho Choi + +[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ] + +offb_init_nodriver() gets a referenced PCI device with pci_get_device(). +If pci_enable_device() fails, the function returns without dropping that +reference. + +Release the PCI device reference before returning from the +pci_enable_device() failure path. + +Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/offb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c +index 4501e848a36f2..593aad22248e6 100644 +--- a/drivers/video/fbdev/offb.c ++++ b/drivers/video/fbdev/offb.c +@@ -643,8 +643,13 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node) + vid = be32_to_cpup(vidp); + did = be32_to_cpup(didp); + pdev = pci_get_device(vid, did, NULL); +- if (!pdev || pci_enable_device(pdev)) ++ if (!pdev) + return; ++ ++ if (pci_enable_device(pdev)) { ++ pci_dev_put(pdev); ++ return; ++ } + } + #endif + /* kludge for valkyrie */ +-- +2.53.0 + diff --git a/queue-5.15/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch b/queue-5.15/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch new file mode 100644 index 0000000000..18e2be3299 --- /dev/null +++ b/queue-5.15/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch @@ -0,0 +1,63 @@ +From f1cdd0e06494beb45502009f4e4559dac3ecbf5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 08:10:20 -0600 +Subject: firmware: dmi: Correct an indexing error in dmi.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit c064abc68e009d2cc18416e7132d9c25e03125b6 ] + +The entries later in enum dmi_entry_type don't match the SMBIOS +specification¹. + +The entry for type 33: `64-Bit Memory Error Information` is not present and +thus the index for all later entries is incorrect. + +Add it. + +Also, add missing entry types 43-46, while at it. + + ¹ Search for "System Management BIOS (SMBIOS) Reference Specification" + + [ bp: Drop the flaky SMBIOS spec URL. ] + +Fixes: 93c890dbe5287 ("firmware: Add DMI entry types to the headers") +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Jean Delvare +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20260307141024.819807-2-superm1@kernel.org +Signed-off-by: Sasha Levin +--- + include/linux/dmi.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/dmi.h b/include/linux/dmi.h +index 927f8a8b7a1dd..2eedf44e68012 100644 +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -60,6 +60,7 @@ enum dmi_entry_type { + DMI_ENTRY_OOB_REMOTE_ACCESS, + DMI_ENTRY_BIS_ENTRY, + DMI_ENTRY_SYSTEM_BOOT, ++ DMI_ENTRY_64_MEM_ERROR, + DMI_ENTRY_MGMT_DEV, + DMI_ENTRY_MGMT_DEV_COMPONENT, + DMI_ENTRY_MGMT_DEV_THRES, +@@ -69,6 +70,10 @@ enum dmi_entry_type { + DMI_ENTRY_ADDITIONAL, + DMI_ENTRY_ONBOARD_DEV_EXT, + DMI_ENTRY_MGMT_CONTROLLER_HOST, ++ DMI_ENTRY_TPM_DEVICE, ++ DMI_ENTRY_PROCESSOR_ADDITIONAL, ++ DMI_ENTRY_FIRMWARE_INVENTORY, ++ DMI_ENTRY_STRING_PROPERTY, + DMI_ENTRY_INACTIVE = 126, + DMI_ENTRY_END_OF_TABLE = 127, + }; +-- +2.53.0 + diff --git a/queue-5.15/flow_dissector-add-number-of-vlan-tags-dissector.patch b/queue-5.15/flow_dissector-add-number-of-vlan-tags-dissector.patch new file mode 100644 index 0000000000..c4f6c07b15 --- /dev/null +++ b/queue-5.15/flow_dissector-add-number-of-vlan-tags-dissector.patch @@ -0,0 +1,119 @@ +From 02eea3dd237a695625ebabac7883a37e108b2fb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Apr 2022 11:14:32 +0300 +Subject: flow_dissector: Add number of vlan tags dissector + +From: Boris Sukholitko + +[ Upstream commit 34951fcf26c59e78ae430fba1fce7c08b1871249 ] + +Our customers in the fiber telecom world have network configurations +where they would like to control their traffic according to the number +of tags appearing in the packet. + +For example, TR247 GPON conformance test suite specification mostly +talks about untagged, single, double tagged packets and gives lax +guidelines on the vlan protocol vs. number of vlan tags. + +This is different from the common IT networks where 802.1Q and 802.1ad +protocols are usually describe single and double tagged packet. GPON +configurations that we work with have arbitrary mix the above protocols +and number of vlan tags in the packet. + +The goal is to make the following TC commands possible: + +tc filter add dev eth1 ingress flower \ + num_of_vlans 1 vlan_prio 5 action drop + +From our logs, we have redirect rules such that: + +tc filter add dev $GPON ingress flower num_of_vlans $N \ + action mirred egress redirect dev $DEV + +where N can range from 0 to 3 and $DEV is the function of $N. + +Also there are rules setting skb mark based on the number of vlans: + +tc filter add dev $GPON ingress flower num_of_vlans $N vlan_prio \ + $P action skbedit mark $M + +This new dissector allows extracting the number of vlan tags existing in +the packet. + +Signed-off-by: Boris Sukholitko +Signed-off-by: David S. Miller +Stable-dep-of: cc1ff87bce1c ("pppoe: drop PFC frames") +Signed-off-by: Sasha Levin +--- + include/net/flow_dissector.h | 9 +++++++++ + net/core/flow_dissector.c | 20 ++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h +index 8d0d0cf93a785..7d154c3f90d14 100644 +--- a/include/net/flow_dissector.h ++++ b/include/net/flow_dissector.h +@@ -269,6 +269,14 @@ struct flow_dissector_key_hash { + u32 hash; + }; + ++/** ++ * struct flow_dissector_key_num_of_vlans: ++ * @num_of_vlans: num_of_vlans value ++ */ ++struct flow_dissector_key_num_of_vlans { ++ u8 num_of_vlans; ++}; ++ + enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ + FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ +@@ -298,6 +306,7 @@ enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_META, /* struct flow_dissector_key_meta */ + FLOW_DISSECTOR_KEY_CT, /* struct flow_dissector_key_ct */ + FLOW_DISSECTOR_KEY_HASH, /* struct flow_dissector_key_hash */ ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS, /* struct flow_dissector_key_num_of_vlans */ + + FLOW_DISSECTOR_KEY_MAX, + }; +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index 537dbd7fc5438..c599bc81dfa76 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -1042,6 +1042,16 @@ bool __skb_flow_dissect(const struct net *net, + memcpy(key_eth_addrs, ð->h_dest, sizeof(*key_eth_addrs)); + } + ++ if (dissector_uses_key(flow_dissector, ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS)) { ++ struct flow_dissector_key_num_of_vlans *key_num_of_vlans; ++ ++ key_num_of_vlans = skb_flow_dissector_target(flow_dissector, ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS, ++ target_container); ++ key_num_of_vlans->num_of_vlans = 0; ++ } ++ + proto_again: + fdret = FLOW_DISSECT_RET_CONTINUE; + +@@ -1165,6 +1175,16 @@ bool __skb_flow_dissect(const struct net *net, + nhoff += sizeof(*vlan); + } + ++ if (dissector_uses_key(flow_dissector, ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS)) { ++ struct flow_dissector_key_num_of_vlans *key_nvs; ++ ++ key_nvs = skb_flow_dissector_target(flow_dissector, ++ FLOW_DISSECTOR_KEY_NUM_OF_VLANS, ++ target_container); ++ key_nvs->num_of_vlans++; ++ } ++ + if (dissector_vlan == FLOW_DISSECTOR_KEY_MAX) { + dissector_vlan = FLOW_DISSECTOR_KEY_VLAN; + } else if (dissector_vlan == FLOW_DISSECTOR_KEY_VLAN) { +-- +2.53.0 + diff --git a/queue-5.15/flow_dissector-add-pppoe-dissectors.patch b/queue-5.15/flow_dissector-add-pppoe-dissectors.patch new file mode 100644 index 0000000000..ac11d0656d --- /dev/null +++ b/queue-5.15/flow_dissector-add-pppoe-dissectors.patch @@ -0,0 +1,178 @@ +From f408b9fd62842426623fa63ca7452b0e0a3bbd47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Jul 2022 14:18:10 +0200 +Subject: flow_dissector: Add PPPoE dissectors + +From: Wojciech Drewek + +[ Upstream commit 46126db9c86110e5fc1e369b9bb89735ddefdae4 ] + +Allow to dissect PPPoE specific fields which are: +- session ID (16 bits) +- ppp protocol (16 bits) +- type (16 bits) - this is PPPoE ethertype, for now only + ETH_P_PPP_SES is supported, possible ETH_P_PPP_DISC + in the future + +The goal is to make the following TC command possible: + + # tc filter add dev ens6f0 ingress prio 1 protocol ppp_ses \ + flower \ + pppoe_sid 12 \ + ppp_proto ip \ + action drop + +Note that only PPPoE Session is supported. + +Signed-off-by: Wojciech Drewek +Acked-by: Guillaume Nault +Signed-off-by: Tony Nguyen +Stable-dep-of: cc1ff87bce1c ("pppoe: drop PFC frames") +Signed-off-by: Sasha Levin +--- + include/linux/ppp_defs.h | 14 ++++++++++ + include/net/flow_dissector.h | 13 +++++++++ + net/core/flow_dissector.c | 53 +++++++++++++++++++++++++++++++----- + 3 files changed, 73 insertions(+), 7 deletions(-) + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index 9d2b388fae1a4..b7e57fdbd4139 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -11,4 +11,18 @@ + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) ++ ++/** ++ * ppp_proto_is_valid - checks if PPP protocol is valid ++ * @proto: PPP protocol ++ * ++ * Assumes proto is not compressed. ++ * Protocol is valid if the value is odd and the least significant bit of the ++ * most significant octet is 0 (see RFC 1661, section 2). ++ */ ++static inline bool ppp_proto_is_valid(u16 proto) ++{ ++ return !!((proto & 0x0101) == 0x0001); ++} ++ + #endif /* _PPP_DEFS_H_ */ +diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h +index 7d154c3f90d14..44034e6af9387 100644 +--- a/include/net/flow_dissector.h ++++ b/include/net/flow_dissector.h +@@ -277,6 +277,18 @@ struct flow_dissector_key_num_of_vlans { + u8 num_of_vlans; + }; + ++/** ++ * struct flow_dissector_key_pppoe: ++ * @session_id: pppoe session id ++ * @ppp_proto: ppp protocol ++ * @type: pppoe eth type ++ */ ++struct flow_dissector_key_pppoe { ++ __be16 session_id; ++ __be16 ppp_proto; ++ __be16 type; ++}; ++ + enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ + FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ +@@ -307,6 +319,7 @@ enum flow_dissector_key_id { + FLOW_DISSECTOR_KEY_CT, /* struct flow_dissector_key_ct */ + FLOW_DISSECTOR_KEY_HASH, /* struct flow_dissector_key_hash */ + FLOW_DISSECTOR_KEY_NUM_OF_VLANS, /* struct flow_dissector_key_num_of_vlans */ ++ FLOW_DISSECTOR_KEY_PPPOE, /* struct flow_dissector_key_pppoe */ + + FLOW_DISSECTOR_KEY_MAX, + }; +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index c599bc81dfa76..164de39fd262c 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -902,6 +902,11 @@ bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, + return result == BPF_OK; + } + ++static bool is_pppoe_ses_hdr_valid(struct pppoe_hdr hdr) ++{ ++ return hdr.ver == 1 && hdr.type == 1 && hdr.code == 0; ++} ++ + /** + * __skb_flow_dissect - extract the flow_keys struct and return it + * @net: associated network namespace, derived from @skb if NULL +@@ -1221,26 +1226,60 @@ bool __skb_flow_dissect(const struct net *net, + struct pppoe_hdr hdr; + __be16 proto; + } *hdr, _hdr; ++ u16 ppp_proto; ++ + hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); + if (!hdr) { + fdret = FLOW_DISSECT_RET_OUT_BAD; + break; + } + +- nhoff += PPPOE_SES_HLEN; +- switch (hdr->proto) { +- case htons(PPP_IP): ++ if (!is_pppoe_ses_hdr_valid(hdr->hdr)) { ++ fdret = FLOW_DISSECT_RET_OUT_BAD; ++ break; ++ } ++ ++ /* least significant bit of the most significant octet ++ * indicates if protocol field was compressed ++ */ ++ ppp_proto = ntohs(hdr->proto); ++ if (ppp_proto & 0x0100) { ++ ppp_proto = ppp_proto >> 8; ++ nhoff += PPPOE_SES_HLEN - 1; ++ } else { ++ nhoff += PPPOE_SES_HLEN; ++ } ++ ++ if (ppp_proto == PPP_IP) { + proto = htons(ETH_P_IP); + fdret = FLOW_DISSECT_RET_PROTO_AGAIN; +- break; +- case htons(PPP_IPV6): ++ } else if (ppp_proto == PPP_IPV6) { + proto = htons(ETH_P_IPV6); + fdret = FLOW_DISSECT_RET_PROTO_AGAIN; +- break; +- default: ++ } else if (ppp_proto == PPP_MPLS_UC) { ++ proto = htons(ETH_P_MPLS_UC); ++ fdret = FLOW_DISSECT_RET_PROTO_AGAIN; ++ } else if (ppp_proto == PPP_MPLS_MC) { ++ proto = htons(ETH_P_MPLS_MC); ++ fdret = FLOW_DISSECT_RET_PROTO_AGAIN; ++ } else if (ppp_proto_is_valid(ppp_proto)) { ++ fdret = FLOW_DISSECT_RET_OUT_GOOD; ++ } else { + fdret = FLOW_DISSECT_RET_OUT_BAD; + break; + } ++ ++ if (dissector_uses_key(flow_dissector, ++ FLOW_DISSECTOR_KEY_PPPOE)) { ++ struct flow_dissector_key_pppoe *key_pppoe; ++ ++ key_pppoe = skb_flow_dissector_target(flow_dissector, ++ FLOW_DISSECTOR_KEY_PPPOE, ++ target_container); ++ key_pppoe->session_id = hdr->hdr.sid; ++ key_pppoe->ppp_proto = htons(ppp_proto); ++ key_pppoe->type = htons(ETH_P_PPP_SES); ++ } + break; + } + case htons(ETH_P_TIPC): { +-- +2.53.0 + diff --git a/queue-5.15/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch b/queue-5.15/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch new file mode 100644 index 0000000000..29acd918f4 --- /dev/null +++ b/queue-5.15/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch @@ -0,0 +1,48 @@ +From 1a1a6746a90e61bf8c1cc0455b06650fa0753e1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 13:45:02 +0900 +Subject: fs/adfs: validate nzones in adfs_validate_bblk() + +From: Bae Yeonju + +[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ] + +Reject ADFS disc records with a zero zone count during boot block +validation, before the disc record is used. + +When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) +which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to +dm[-1], causing an out-of-bounds write before the allocated buffer. + +adfs_validate_dr0() already rejects nzones != 1 for old-format +images. Add the equivalent check to adfs_validate_bblk() for +new-format images so that a crafted image with nzones == 0 is +rejected at probe time. + +Found by syzkaller. + +Fixes: f6f14a0d71b0 ("fs/adfs: map: move map-specific sb initialisation to map.c") +Signed-off-by: Bae Yeonju +Signed-off-by: Russell King (Oracle) +Signed-off-by: Sasha Levin +--- + fs/adfs/super.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/adfs/super.c b/fs/adfs/super.c +index bdbd26e571ed3..7da236fd7a119 100644 +--- a/fs/adfs/super.c ++++ b/fs/adfs/super.c +@@ -343,6 +343,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, + if (adfs_checkdiscrecord(dr)) + return -EILSEQ; + ++ if ((dr->nzones | dr->nzones_high << 8) == 0) ++ return -EILSEQ; ++ + *drp = dr; + return 0; + } +-- +2.53.0 + diff --git a/queue-5.15/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch b/queue-5.15/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch new file mode 100644 index 0000000000..712c3c3863 --- /dev/null +++ b/queue-5.15/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch @@ -0,0 +1,51 @@ +From d932c1f40cfcc36f0d8e200d8b59c7a3255741ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:19:55 +0800 +Subject: fs/ntfs3: terminate the cached volume label after UTF-8 conversion + +From: Pengpeng Hou + +[ Upstream commit a6cd43fe9b083fa23fe1595666d5738856cb261a ] + +ntfs_fill_super() loads the on-disk volume label with utf16s_to_utf8s() +and stores the result in sbi->volume.label. The converted label is later +exposed through ntfs3_label_show() using %s, but utf16s_to_utf8s() only +returns the number of bytes written and does not add a trailing NUL. + +If the converted label fills the entire fixed buffer, +ntfs3_label_show() can read past the end of sbi->volume.label while +looking for a terminator. + +Terminate the cached label explicitly after a successful conversion and +clamp the exact-full case to the last byte of the buffer. + +Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") +Signed-off-by: Pengpeng Hou +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index a9952b0321837..4ba1501119bff 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -958,8 +958,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + le32_to_cpu(attr->res.data_size) >> 1, + UTF16_LITTLE_ENDIAN, sbi->volume.label, + sizeof(sbi->volume.label)); +- if (err < 0) ++ if (err < 0) { + sbi->volume.label[0] = 0; ++ } else if (err >= sizeof(sbi->volume.label)) { ++ sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0; ++ } else { ++ sbi->volume.label[err] = 0; ++ } + } else { + /* Should we break mounting here? */ + //err = -EINVAL; +-- +2.53.0 + diff --git a/queue-5.15/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch b/queue-5.15/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch new file mode 100644 index 0000000000..9538afbd8c --- /dev/null +++ b/queue-5.15/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch @@ -0,0 +1,55 @@ +From 5335b34aca62dca1740f08efeec8f4dfdfe57461 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:48:27 +0900 +Subject: fs/omfs: reject s_sys_blocksize smaller than OMFS_DIR_START + +From: HyungJung Joo + +[ Upstream commit 0621c385fda1376e967f37ccd534c26c3e511d14 ] + +omfs_fill_super() rejects oversized s_sys_blocksize values (> PAGE_SIZE), +but it does not reject values smaller than OMFS_DIR_START (0x1b8 = 440). + +Later, omfs_make_empty() uses + + sbi->s_sys_blocksize - OMFS_DIR_START + +as the length argument to memset(). Since s_sys_blocksize is u32, +a crafted filesystem image with s_sys_blocksize < OMFS_DIR_START causes +an unsigned underflow there, wrapping to a value near 2^32. That drives +a ~4 GiB memset() from bh->b_data + OMFS_DIR_START and overwrites kernel +memory far beyond the backing block buffer. + +Add the corresponding lower-bound check alongside the existing upper-bound +check in omfs_fill_super(), so that malformed images are rejected during +superblock validation before any filesystem data is processed. + +Fixes: a3ab7155ea21 ("omfs: add directory routines") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054827.1822061-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/omfs/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c +index 2a0e83236c011..9773846daa4bc 100644 +--- a/fs/omfs/inode.c ++++ b/fs/omfs/inode.c +@@ -515,6 +515,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) + goto out_brelse_bh; + } + ++ if (sbi->s_sys_blocksize < OMFS_DIR_START) { ++ printk(KERN_ERR "omfs: sysblock size (%d) is too small\n", ++ sbi->s_sys_blocksize); ++ goto out_brelse_bh; ++ } ++ + if (sbi->s_blocksize < sbi->s_sys_blocksize || + sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { + printk(KERN_ERR "omfs: block size (%d) is out of range\n", +-- +2.53.0 + diff --git a/queue-5.15/gfs2-add-some-missing-log-locking.patch b/queue-5.15/gfs2-add-some-missing-log-locking.patch new file mode 100644 index 0000000000..6e56c953b2 --- /dev/null +++ b/queue-5.15/gfs2-add-some-missing-log-locking.patch @@ -0,0 +1,109 @@ +From 5a1df4eb622be275ea2d05643083543d4a6e9b8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 06:13:42 +0200 +Subject: gfs2: add some missing log locking + +From: Andreas Gruenbacher + +[ Upstream commit fe2c8d051150b90b3ccb85f89e3b1d636cb88ec8 ] + +Function gfs2_logd() calls the log flushing functions gfs2_ail1_start(), +gfs2_ail1_wait(), and gfs2_ail1_empty() without holding sdp->sd_log_flush_lock, +but these functions require exclusion against concurrent transactions. + +To fix that, add a non-locking __gfs2_log_flush() function. Then, in +gfs2_logd(), take sdp->sd_log_flush_lock before calling the above mentioned log +flushing functions and __gfs2_log_flush(). + +Fixes: 5e4c7632aae1c ("gfs2: Issue revokes more intelligently") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index e7867b0f6c62c..e19b09620a0b7 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -1017,14 +1017,15 @@ static void trans_drain(struct gfs2_trans *tr) + } + + /** +- * gfs2_log_flush - flush incore transaction(s) ++ * __gfs2_log_flush - flush incore transaction(s) + * @sdp: The filesystem + * @gl: The glock structure to flush. If NULL, flush the whole incore log + * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags + * + */ + +-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ++ u32 flags) + { + struct gfs2_trans *tr = NULL; + unsigned int reserved_blocks = 0, used_blocks = 0; +@@ -1032,7 +1033,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + unsigned int first_log_head; + unsigned int reserved_revokes = 0; + +- down_write(&sdp->sd_log_flush_lock); + trace_gfs2_log_flush(sdp, 1, flags); + + repeat: +@@ -1145,7 +1145,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + gfs2_assert_withdraw_delayed(sdp, used_blocks < reserved_blocks); + gfs2_log_release(sdp, reserved_blocks - used_blocks); + } +- up_write(&sdp->sd_log_flush_lock); + gfs2_trans_free(sdp, tr); + if (gfs2_withdrawing(sdp)) + gfs2_withdraw(sdp); +@@ -1168,6 +1167,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + goto out_end; + } + ++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++{ ++ down_write(&sdp->sd_log_flush_lock); ++ __gfs2_log_flush(sdp, gl, flags); ++ up_write(&sdp->sd_log_flush_lock); ++} ++ + /** + * gfs2_merge_trans - Merge a new transaction into a cached transaction + * @sdp: the filesystem +@@ -1313,19 +1319,25 @@ int gfs2_logd(void *data) + } + + if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_JFLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_JFLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) || + gfs2_ail_flush_reqd(sdp)) { + clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_start(sdp); + gfs2_ail1_wait(sdp); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; +-- +2.53.0 + diff --git a/queue-5.15/gfs2-prevent-null-pointer-dereference-during-unmount.patch b/queue-5.15/gfs2-prevent-null-pointer-dereference-during-unmount.patch new file mode 100644 index 0000000000..3771da85d0 --- /dev/null +++ b/queue-5.15/gfs2-prevent-null-pointer-dereference-during-unmount.patch @@ -0,0 +1,44 @@ +From 133fb921d79d0915b1865b301f566eb2e1902a96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 12:14:30 +0200 +Subject: gfs2: prevent NULL pointer dereference during unmount + +From: Andreas Gruenbacher + +[ Upstream commit 74b4dbb946060a3233604d91859a9abd3708141d ] + +When flushing out outstanding glock work during an unmount, gfs2_log_flush() +can be called when sdp->sd_jdesc has already been deallocated and sdp->sd_jdesc +is NULL. Commit 35264909e9d1 ("gfs2: Fix NULL pointer dereference in +gfs2_log_flush") added a check for that to gfs2_log_flush() itself, but it +missed the sdp->sd_jdesc dereference in gfs2_log_release(). Fix that. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202604071139.HNJiCaAi-lkp@intel.com/ +Fixes: 35264909e9d1 ("gfs2: Fix NULL pointer dereference in gfs2_log_flush") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index e19b09620a0b7..354362c7c4f99 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -470,8 +470,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) + { + atomic_add(blks, &sdp->sd_log_blks_free); + trace_gfs2_log_blocks(sdp, blks); +- gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= +- sdp->sd_jdesc->jd_blocks); ++ gfs2_assert_withdraw(sdp, !sdp->sd_jdesc || ++ atomic_read(&sdp->sd_log_blks_free) <= ++ sdp->sd_jdesc->jd_blocks); + if (atomic_read(&sdp->sd_log_blks_needed)) + wake_up(&sdp->sd_log_waitq); + } +-- +2.53.0 + diff --git a/queue-5.15/hid-asus-do-not-abort-probe-when-not-necessary.patch b/queue-5.15/hid-asus-do-not-abort-probe-when-not-necessary.patch new file mode 100644 index 0000000000..5fb94a752b --- /dev/null +++ b/queue-5.15/hid-asus-do-not-abort-probe-when-not-necessary.patch @@ -0,0 +1,65 @@ +From 45de041f4f2b35e0ff5360f568e02e00cb186f59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:09 +0100 +Subject: HID: asus: do not abort probe when not necessary + +From: Denis Benato + +[ Upstream commit 7253091766ded0fd81fe8d8be9b8b835495b06e8 ] + +In order to avoid dereferencing a NULL pointer asus_probe is aborted early +and control of some asus devices is transferred over hid-generic after +erroring out even when such NULL dereference cannot happen: only early +abort when the NULL dereference can happen. + +Also make the code shorter and more adherent to coding standards +removing square brackets enclosing single-line if-else statements. + +Fixes: d3af6ca9a8c3 ("HID: asus: fix UAF via HID_CLAIMED_INPUT validation") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 5c7306fb57b1d..df12b75d2fa2b 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1142,22 +1142,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + * were freed during registration due to no usages being mapped, + * leaving drvdata->input pointing to freed memory. + */ +- if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { +- hid_err(hdev, "Asus input not registered\n"); +- ret = -ENOMEM; +- goto err_stop_hw; +- } +- +- if (drvdata->tp) { +- drvdata->input->name = "Asus TouchPad"; +- } else { +- drvdata->input->name = "Asus Keyboard"; +- } ++ if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) { ++ if (drvdata->tp) ++ drvdata->input->name = "Asus TouchPad"; ++ else ++ drvdata->input->name = "Asus Keyboard"; + +- if (drvdata->tp) { +- ret = asus_start_multitouch(hdev); +- if (ret) +- goto err_stop_hw; ++ if (drvdata->tp) { ++ ret = asus_start_multitouch(hdev); ++ if (ret) ++ goto err_stop_hw; ++ } + } + + return 0; +-- +2.53.0 + diff --git a/queue-5.15/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch b/queue-5.15/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch new file mode 100644 index 0000000000..78e7b2a12b --- /dev/null +++ b/queue-5.15/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch @@ -0,0 +1,37 @@ +From 864bc3e661723b2a61fb6a87f8e596e228ccb112 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:07 +0100 +Subject: HID: asus: make asus_resume adhere to linux kernel coding standards + +From: Denis Benato + +[ Upstream commit 51d33b42b8ae23da92819d28439fdd5636c45186 ] + +Linux kernel coding standars requires functions opening brackets to be in +a newline: move the opening bracket of asus_resume in its own line. + +Fixes: 546edbd26cff ("HID: hid-asus: reset the backlight brightness level on resume") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 3be17a8b7a293..5c7306fb57b1d 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1014,7 +1014,8 @@ static int asus_start_multitouch(struct hid_device *hdev) + return 0; + } + +-static int __maybe_unused asus_resume(struct hid_device *hdev) { ++static int __maybe_unused asus_resume(struct hid_device *hdev) ++{ + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + int ret = 0; + +-- +2.53.0 + diff --git a/queue-5.15/hid-usbhid-fix-deadlock-in-hid_post_reset.patch b/queue-5.15/hid-usbhid-fix-deadlock-in-hid_post_reset.patch new file mode 100644 index 0000000000..3fe700a14d --- /dev/null +++ b/queue-5.15/hid-usbhid-fix-deadlock-in-hid_post_reset.patch @@ -0,0 +1,42 @@ +From 327863089ddc11c671f43fb8f51d4fad8b92c2dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:24:54 +0100 +Subject: HID: usbhid: fix deadlock in hid_post_reset() + +From: Oliver Neukum + +[ Upstream commit 8df2c1b47ee3cd50fd454f75c7a7e2ae8a6adf72 ] + +You can build a USB device that includes a HID component +and a storage or UAS component. The components can be reset +only together. That means that hid_pre_reset() and hid_post_reset() +are in the block IO error handling. Hence no memory allocation +used in them may do block IO because the IO can deadlock +on the mutex held while resetting a device and calling the +interface drivers. +Use GFP_NOIO for all allocations in them. + +Fixes: dc3c78e434690 ("HID: usbhid: Check HID report descriptor contents after device reset") +Signed-off-by: Oliver Neukum +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index 5faa608563814..b182b288991a6 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1544,7 +1544,7 @@ static int hid_post_reset(struct usb_interface *intf) + * configuration descriptors passed, we already know that + * the size of the HID report descriptor has not changed. + */ +- rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); ++ rdesc = kmalloc(hid->dev_rsize, GFP_NOIO); + if (!rdesc) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-5.15/i3c-master-fix-error-codes-at-send_ccc_cmd.patch b/queue-5.15/i3c-master-fix-error-codes-at-send_ccc_cmd.patch new file mode 100644 index 0000000000..2d0522c6b1 --- /dev/null +++ b/queue-5.15/i3c-master-fix-error-codes-at-send_ccc_cmd.patch @@ -0,0 +1,126 @@ +From 411df76c2c5594353799999115345f5aa86cab15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:32 +0100 +Subject: i3c: master: Fix error codes at send_ccc_cmd + +From: Jorge Marques + +[ Upstream commit ef8b5229348f0719aca557c4ca5530630ae4d134 ] + +i3c_master_send_ccc_cmd_locked() would propagate cmd->err (positive, +Mx codes) to the ret variable, cascading down multiple methods until +reaching methods that explicitly stated they would return 0 on success +or negative error code. For example, the call chain: + + i3c_device_enable_ibi <- i3c_dev_enable_ibi_locked <- + master->ops.enable_ibi <- i3c_master_enec_locked <- + i3c_master_enec_disec_locked <- i3c_master_send_ccc_cmd_locked + +Fix this by returning the ret value, callers can still read the cmd->err +value if ret is negative. + +All corner cases where the Mx codes do need to be handled individually, +are resolved in previous commits. Those corner cases are all scenarios +when I3C_ERROR_M2 is expected and acceptable. +The prerequisite patches for the fix are: + + i3c: master: Move rstdaa error suppression + i3c: master: Move entdaa error suppression + i3c: master: Move bus_init error suppression + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-iio/aYXvT5FW0hXQwhm_@stanley.mountain/ +Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-4-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 32 +++++++++++++------------------- + 1 file changed, 13 insertions(+), 19 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 5df943d25cf0a..6153f5af0b13e 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -654,11 +654,17 @@ static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id, + cmd->err = I3C_ERROR_UNKNOWN; + } + ++/** ++ * i3c_master_send_ccc_cmd_locked() - send a CCC (Common Command Codes) ++ * @master: master used to send frames on the bus ++ * @cmd: command to send ++ * ++ * Return: 0 in case of success, or a negative error code otherwise. ++ * I3C Mx error codes are stored in cmd->err. ++ */ + static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd) + { +- int ret; +- + if (!cmd || !master) + return -EINVAL; + +@@ -676,15 +682,7 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + !master->ops->supports_ccc_cmd(master, cmd)) + return -ENOTSUPP; + +- ret = master->ops->send_ccc_cmd(master, cmd); +- if (ret) { +- if (cmd->err != I3C_ERROR_UNKNOWN) +- return cmd->err; +- +- return ret; +- } +- +- return 0; ++ return master->ops->send_ccc_cmd(master, cmd); + } + + static struct i2c_dev_desc * +@@ -788,8 +786,7 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_entdaa_locked(struct i3c_master_controller *master) + { +@@ -841,8 +838,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -862,8 +858,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -888,8 +883,7 @@ EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_defslvs_locked(struct i3c_master_controller *master) + { +-- +2.53.0 + diff --git a/queue-5.15/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch b/queue-5.15/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch new file mode 100644 index 0000000000..1b6b521507 --- /dev/null +++ b/queue-5.15/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch @@ -0,0 +1,56 @@ +From 608fcf1664102c409ce929634e4c0b5b7b5bbfbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:53:23 +0800 +Subject: i3c: mipi-i3c-hci: fix IBI payload length calculation for final + status + +From: Billy Tsai + +[ Upstream commit d35a6db887eeae7c57b719521e39d64f929c6dc3 ] + +In DMA mode, the IBI status descriptor encodes the payload using +CHUNKS (number of chunks) and DATA_LENGTH (valid bytes in the last +chunk). All preceding chunks are implicitly full-sized. + +The current code accumulates full chunk sizes for non-final status +descriptors, but for the final status descriptor it only adds +DATA_LENGTH. This ignores the contribution of the preceding full +chunks described by the same final status entry. + +As a result, the computed IBI payload length is truncated whenever +the final status spans multiple chunks. For example, with a chunk +size of 4 bytes, CHUNKS=2 and DATA_LENGTH=1 should result in a total +payload size of 5 bytes, but the current code reports only 1 byte. + +Fix the calculation by adding the size of (CHUNKS - 1) full chunks +plus DATA_LENGTH for the last chunk. + +Fixes: 9ad9a52cce28 ("i3c/master: introduce the mipi-i3c-hci driver") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260407-i3c-hci-dma-v2-1-a583187b9d22@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index 28f40f805cb5a..168b21f6cf37c 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -636,7 +636,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh) + if (!(ibi_status & IBI_LAST_STATUS)) { + ibi_size += chunks * rh->ibi_chunk_sz; + } else { +- ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ if (chunks) { ++ ibi_size += (chunks - 1) * rh->ibi_chunk_sz; ++ ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ } + last_ptr = ptr; + break; + } +-- +2.53.0 + diff --git a/queue-5.15/i40e-don-t-advertise-iff_supp_nofcs.patch b/queue-5.15/i40e-don-t-advertise-iff_supp_nofcs.patch new file mode 100644 index 0000000000..520f33febe --- /dev/null +++ b/queue-5.15/i40e-don-t-advertise-iff_supp_nofcs.patch @@ -0,0 +1,53 @@ +From 78f5f53fef806f67a3a60e9b3c8bf51c6d6492d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:33 -0700 +Subject: i40e: don't advertise IFF_SUPP_NOFCS + +From: Kohei Enju + +[ Upstream commit a24162f18825684ad04e3a5d0531f8a50d679347 ] + +i40e advertises IFF_SUPP_NOFCS, allowing users to use the SO_NOFCS +socket option. However, this option is silently ignored, as the driver +does not check skb->no_fcs, and always enables FCS insertion offload. + +Fix this by removing the advertisement of IFF_SUPP_NOFCS. + +This behavior can be reproduced with a simple AF_PACKET socket: + + import socket + s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) + s.setsockopt(socket.SOL_SOCKET, 43, 1) # SO_NOFCS + s.bind(("eth0", 0)) + s.send(b'\xff' * 64) + +Previously, send() succeeds but the driver ignores SO_NOFCS. +With this change, send() fails with -EPROTONOSUPPORT, as expected. + +Fixes: 41c445ff0f48 ("i40e: main driver core") +Signed-off-by: Kohei Enju +Reviewed-by: Aleksandr Loktionov +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-9-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index 31a8217f6aa97..1cc3faf499942 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -13817,7 +13817,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) + netdev->neigh_priv_len = sizeof(u32) * 4; + + netdev->priv_flags |= IFF_UNICAST_FLT; +- netdev->priv_flags |= IFF_SUPP_NOFCS; + /* Setup netdev TC information */ + i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); + +-- +2.53.0 + diff --git a/queue-5.15/ima-check-return-value-of-crypto_shash_final-in-boot.patch b/queue-5.15/ima-check-return-value-of-crypto_shash_final-in-boot.patch new file mode 100644 index 0000000000..61218111d4 --- /dev/null +++ b/queue-5.15/ima-check-return-value-of-crypto_shash_final-in-boot.patch @@ -0,0 +1,41 @@ +From f5a4d66a2089e3f50435c5c0b9bec884d7543cf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 18:40:15 -0800 +Subject: ima: check return value of crypto_shash_final() in boot aggregate + +From: Daniel Hodges + +[ Upstream commit 870819434c8dfcc3158033b66e7851b81bb17e21 ] + +The return value of crypto_shash_final() is not checked in +ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the +function returns success and a corrupted boot aggregate digest could +be used for IMA measurements. + +Capture the return value and propagate any error to the caller. + +Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash") +Signed-off-by: Daniel Hodges +Reviewed-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 64499056648ad..c5153f0d7306d 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -837,7 +837,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, + } + } + if (!rc) +- crypto_shash_final(shash, digest); ++ rc = crypto_shash_final(shash, digest); + return rc; + } + +-- +2.53.0 + diff --git a/queue-5.15/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch b/queue-5.15/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch new file mode 100644 index 0000000000..8659632d28 --- /dev/null +++ b/queue-5.15/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch @@ -0,0 +1,145 @@ +From d84a00a1008a1f4f0c96223f3a8bfdba010dd358 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:22 +0200 +Subject: ipv4: add new arguments to udp_tunnel_dst_lookup() + +From: Beniamino Galvani + +[ Upstream commit 72fc68c6356b663a8763f02d9b0ec773d59a4949 ] + +We want to make the function more generic so that it can be used by +other UDP tunnel implementations such as geneve and vxlan. To do that, +add the following arguments: + + - source and destination UDP port; + - ifindex of the output interface, needed by vxlan; + - the tos, because in some cases it is not taken from struct + ip_tunnel_info (for example, when it's inherited from the inner + packet); + - the dst cache, because not all tunnel types (e.g. vxlan) want to + use the one from struct ip_tunnel_info. + +With these parameters, the function no longer needs the full struct +ip_tunnel_info as argument and we can pass only the relevant part of +it (struct ip_tunnel_key). + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 11 +++++++---- + include/net/udp_tunnel.h | 8 +++++--- + net/ipv4/udp_tunnel_core.c | 26 +++++++++++++------------- + 3 files changed, 25 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 21ad3a7bbbf12..91c3138c408f7 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -318,8 +318,10 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, +- use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, &info->key, ++ 0, 0, key->tos, ++ use_cache ? ++ (struct dst_cache *)&info->dst_cache : NULL); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -498,8 +500,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct rtable *rt; + __be32 saddr; + +- rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, +- info, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, ++ &info->key, 0, 0, info->key.tos, ++ use_cache ? &info->dst_cache : NULL); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index ac9a8f635a5b1..f2e015fc66ca4 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -163,9 +163,11 @@ void udp_tunnel_sock_release(struct socket *sock); + + struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- bool use_cache); ++ struct net *net, int oif, ++ __be32 *saddr, ++ const struct ip_tunnel_key *key, ++ __be16 sport, __be16 dport, u8 tos, ++ struct dst_cache *dst_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index ad5e9ae28d190..749f163d45777 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -209,31 +209,31 @@ EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + + struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- bool use_cache) ++ struct net *net, int oif, ++ __be32 *saddr, ++ const struct ip_tunnel_key *key, ++ __be16 sport, __be16 dport, u8 tos, ++ struct dst_cache *dst_cache) + { +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif + struct rtable *rt = NULL; + struct flowi4 fl4; +- __u8 tos; + + #ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { ++ if (dst_cache) { + rt = dst_cache_get_ip4(dst_cache, saddr); + if (rt) + return rt; + } + #endif ++ + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; + fl4.flowi4_proto = IPPROTO_UDP; +- fl4.daddr = info->key.u.ipv4.dst; +- fl4.saddr = info->key.u.ipv4.src; +- tos = info->key.tos; ++ fl4.flowi4_oif = oif; ++ fl4.daddr = key->u.ipv4.dst; ++ fl4.saddr = key->u.ipv4.src; ++ fl4.fl4_dport = dport; ++ fl4.fl4_sport = sport; + fl4.flowi4_tos = RT_TOS(tos); + + rt = ip_route_output_key(net, &fl4); +@@ -247,7 +247,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + return ERR_PTR(-ELOOP); + } + #ifdef CONFIG_DST_CACHE +- if (use_cache) ++ if (dst_cache) + dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); + #endif + *saddr = fl4.saddr; +-- +2.53.0 + diff --git a/queue-5.15/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch b/queue-5.15/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch new file mode 100644 index 0000000000..3e13b0ba67 --- /dev/null +++ b/queue-5.15/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch @@ -0,0 +1,83 @@ +From fa103460c69a1fc3ed2cad0cf3153cd5f739af86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:21 +0200 +Subject: ipv4: remove "proto" argument from udp_tunnel_dst_lookup() + +From: Beniamino Galvani + +[ Upstream commit 78f3655adcb52412275f282267ee771421731632 ] + +The function is now UDP-specific, the protocol is always IPPROTO_UDP. + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 4 ++-- + include/net/udp_tunnel.h | 2 +- + net/ipv4/udp_tunnel_core.c | 4 ++-- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index a2008cdcff707..21ad3a7bbbf12 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -319,7 +319,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + return -ESHUTDOWN; + + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, +- IPPROTO_UDP, use_cache); ++ use_cache); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -499,7 +499,7 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + __be32 saddr; + + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, +- info, IPPROTO_UDP, use_cache); ++ info, use_cache); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index 81fdcecde24d6..ac9a8f635a5b1 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -165,7 +165,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, __be32 *saddr, + const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); ++ bool use_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 4b1785a8cf112..ad5e9ae28d190 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -211,7 +211,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, __be32 *saddr, + const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache) ++ bool use_cache) + { + #ifdef CONFIG_DST_CACHE + struct dst_cache *dst_cache; +@@ -230,7 +230,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + #endif + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; +- fl4.flowi4_proto = protocol; ++ fl4.flowi4_proto = IPPROTO_UDP; + fl4.daddr = info->key.u.ipv4.dst; + fl4.saddr = info->key.u.ipv4.src; + tos = info->key.tos; +-- +2.53.0 + diff --git a/queue-5.15/ipv4-rename-and-move-ip_route_output_tunnel.patch b/queue-5.15/ipv4-rename-and-move-ip_route_output_tunnel.patch new file mode 100644 index 0000000000..313244ce0d --- /dev/null +++ b/queue-5.15/ipv4-rename-and-move-ip_route_output_tunnel.patch @@ -0,0 +1,211 @@ +From aa21d65d09939103e61c9a8f2b693cb6ce1d56a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:20 +0200 +Subject: ipv4: rename and move ip_route_output_tunnel() + +From: Beniamino Galvani + +[ Upstream commit bf3fcbf7e7a08015d3b169bad6281b29d45c272d ] + +At the moment ip_route_output_tunnel() is used only by bareudp. +Ideally, other UDP tunnel implementations should use it, but to do so +the function needs to accept new parameters that are specific for UDP +tunnels, such as the ports. + +Prepare for these changes by renaming the function to +udp_tunnel_dst_lookup() and move it to file +net/ipv4/udp_tunnel_core.c. + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 8 +++---- + include/net/route.h | 6 ----- + include/net/udp_tunnel.h | 6 +++++ + net/ipv4/route.c | 48 -------------------------------------- + net/ipv4/udp_tunnel_core.c | 48 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 58 insertions(+), 58 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index bec8a2c8656c0..a2008cdcff707 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -318,8 +318,8 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, info, +- IPPROTO_UDP, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, ++ IPPROTO_UDP, use_cache); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -498,8 +498,8 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct rtable *rt; + __be32 saddr; + +- rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, +- info, IPPROTO_UDP, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, ++ info, IPPROTO_UDP, use_cache); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/route.h b/include/net/route.h +index 036e3ee3b856b..d771ceb7b337b 100644 +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -128,12 +128,6 @@ static inline struct rtable *__ip_route_output_key(struct net *net, + + struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp, + const struct sock *sk); +-struct rtable *ip_route_output_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); +- + struct dst_entry *ipv4_blackhole_route(struct net *net, + struct dst_entry *dst_orig); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index b6af537abdc5a..81fdcecde24d6 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -161,6 +161,12 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + + void udp_tunnel_sock_release(struct socket *sock); + ++struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, __be32 *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache); ++ + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, + int md_size); +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 8cddfeb65872f..4a7789ac0c101 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -2926,54 +2926,6 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4, + } + EXPORT_SYMBOL_GPL(ip_route_output_flow); + +-struct rtable *ip_route_output_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache) +-{ +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif +- struct rtable *rt = NULL; +- struct flowi4 fl4; +- __u8 tos; +- +-#ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { +- rt = dst_cache_get_ip4(dst_cache, saddr); +- if (rt) +- return rt; +- } +-#endif +- memset(&fl4, 0, sizeof(fl4)); +- fl4.flowi4_mark = skb->mark; +- fl4.flowi4_proto = protocol; +- fl4.daddr = info->key.u.ipv4.dst; +- fl4.saddr = info->key.u.ipv4.src; +- tos = info->key.tos; +- fl4.flowi4_tos = RT_TOS(tos); +- +- rt = ip_route_output_key(net, &fl4); +- if (IS_ERR(rt)) { +- netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); +- return ERR_PTR(-ENETUNREACH); +- } +- if (rt->dst.dev == dev) { /* is this necessary? */ +- netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); +- ip_rt_put(rt); +- return ERR_PTR(-ELOOP); +- } +-#ifdef CONFIG_DST_CACHE +- if (use_cache) +- dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); +-#endif +- *saddr = fl4.saddr; +- return rt; +-} +-EXPORT_SYMBOL_GPL(ip_route_output_tunnel); +- + /* called with rcu_read_lock held */ + static int rt_fill_info(struct net *net, __be32 dst, __be32 src, + struct rtable *rt, u32 table_id, struct flowi4 *fl4, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 1ff5b8e30bb92..4b1785a8cf112 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -207,4 +207,52 @@ struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + } + EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + ++struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, __be32 *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache) ++{ ++#ifdef CONFIG_DST_CACHE ++ struct dst_cache *dst_cache; ++#endif ++ struct rtable *rt = NULL; ++ struct flowi4 fl4; ++ __u8 tos; ++ ++#ifdef CONFIG_DST_CACHE ++ dst_cache = (struct dst_cache *)&info->dst_cache; ++ if (use_cache) { ++ rt = dst_cache_get_ip4(dst_cache, saddr); ++ if (rt) ++ return rt; ++ } ++#endif ++ memset(&fl4, 0, sizeof(fl4)); ++ fl4.flowi4_mark = skb->mark; ++ fl4.flowi4_proto = protocol; ++ fl4.daddr = info->key.u.ipv4.dst; ++ fl4.saddr = info->key.u.ipv4.src; ++ tos = info->key.tos; ++ fl4.flowi4_tos = RT_TOS(tos); ++ ++ rt = ip_route_output_key(net, &fl4); ++ if (IS_ERR(rt)) { ++ netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); ++ return ERR_PTR(-ENETUNREACH); ++ } ++ if (rt->dst.dev == dev) { /* is this necessary? */ ++ netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); ++ ip_rt_put(rt); ++ return ERR_PTR(-ELOOP); ++ } ++#ifdef CONFIG_DST_CACHE ++ if (use_cache) ++ dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); ++#endif ++ *saddr = fl4.saddr; ++ return rt; ++} ++EXPORT_SYMBOL_GPL(udp_tunnel_dst_lookup); ++ + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-5.15/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch b/queue-5.15/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch new file mode 100644 index 0000000000..14f1023e03 --- /dev/null +++ b/queue-5.15/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch @@ -0,0 +1,71 @@ +From 1885be7afa820d41c98c6c57c740098fbbb2b599 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 10:35:05 +0000 +Subject: ipv6: fix possible UAF in icmpv6_rcv() + +From: Eric Dumazet + +[ Upstream commit f996edd7615e686ada141b7f3395025729ff8ccb ] + +Caching saddr and daddr before pskb_pull() is problematic +since skb->head can change. + +Remove these temporary variables: + +- We only access &ipv6_hdr(skb)->saddr and &ipv6_hdr(skb)->daddr + when net_dbg_ratelimited() is called in the slow path. + +- Avoid potential future misuse after pskb_pull() call. + +Fixes: 4b3418fba0fe ("ipv6: icmp: include addresses in debug messages") +Signed-off-by: Eric Dumazet +Reviewed-by: Fernando Fernandez Mancera +Reviewed-by: Joe Damato +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260416103505.2380753-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/icmp.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index 6f053874de741..fcfb0f79b07ab 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -883,7 +883,6 @@ static int icmpv6_rcv(struct sk_buff *skb) + struct net *net = dev_net(skb->dev); + struct net_device *dev = icmp6_dev(skb); + struct inet6_dev *idev = __in6_dev_get(dev); +- const struct in6_addr *saddr, *daddr; + struct icmp6hdr *hdr; + u8 type; + bool success = false; +@@ -910,12 +909,10 @@ static int icmpv6_rcv(struct sk_buff *skb) + + __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS); + +- saddr = &ipv6_hdr(skb)->saddr; +- daddr = &ipv6_hdr(skb)->daddr; +- + if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { + net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + goto csum_error; + } + +@@ -997,7 +994,8 @@ static int icmpv6_rcv(struct sk_buff *skb) + break; + + net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + + /* + * error of unknown type. +-- +2.53.0 + diff --git a/queue-5.15/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch b/queue-5.15/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch new file mode 100644 index 0000000000..9f056d3408 --- /dev/null +++ b/queue-5.15/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch @@ -0,0 +1,262 @@ +From 74737197a315da922b63bf41068cf47ce16c36de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 13:55:25 +0200 +Subject: ipv6: rename and move ip6_dst_lookup_tunnel() + +From: Beniamino Galvani + +[ Upstream commit fc47e86dbfb75a864c0c9dd8e78affb6506296bb ] + +At the moment ip6_dst_lookup_tunnel() is used only by bareudp. +Ideally, other UDP tunnel implementations should use it, but to do so +the function needs to accept new parameters that are specific for UDP +tunnels, such as the ports. + +Prepare for these changes by renaming the function to +udp_tunnel6_dst_lookup() and move it to file +net/ipv6/ip6_udp_tunnel.c. + +This is similar to what already done for IPv4 in commit bf3fcbf7e7a0 +("ipv4: rename and move ip_route_output_tunnel()"). + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 10 +++--- + include/net/ipv6.h | 6 ---- + include/net/udp_tunnel.h | 7 ++++ + net/ipv6/ip6_output.c | 68 -------------------------------------- + net/ipv6/ip6_udp_tunnel.c | 69 +++++++++++++++++++++++++++++++++++++++ + 5 files changed, 81 insertions(+), 79 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 91c3138c408f7..4acca20084d36 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -386,8 +386,8 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, &saddr, info, +- IPPROTO_UDP, use_cache); ++ dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, &saddr, info, ++ IPPROTO_UDP, use_cache); + if (IS_ERR(dst)) + return PTR_ERR(dst); + +@@ -513,9 +513,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + +- dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, +- &saddr, info, IPPROTO_UDP, +- use_cache); ++ dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, ++ &saddr, info, IPPROTO_UDP, ++ use_cache); + if (IS_ERR(dst)) + return PTR_ERR(dst); + +diff --git a/include/net/ipv6.h b/include/net/ipv6.h +index 0a1c9366cc81e..1607bfd011bf2 100644 +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -1034,12 +1034,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, st + struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, + const struct in6_addr *final_dst, + bool connected); +-struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, struct socket *sock, +- struct in6_addr *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); + struct dst_entry *ip6_blackhole_route(struct net *net, + struct dst_entry *orig_dst); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index f2e015fc66ca4..51f9e5869ac19 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -168,6 +168,13 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + const struct ip_tunnel_key *key, + __be16 sport, __be16 dport, u8 tos, + struct dst_cache *dst_cache); ++struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, ++ struct socket *sock, ++ struct in6_addr *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index acb76248cc0e4..65b3168bce31f 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1274,74 +1274,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, + } + EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); + +-/** +- * ip6_dst_lookup_tunnel - perform route lookup on tunnel +- * @skb: Packet for which lookup is done +- * @dev: Tunnel device +- * @net: Network namespace of tunnel device +- * @sock: Socket which provides route info +- * @saddr: Memory to store the src ip address +- * @info: Tunnel information +- * @protocol: IP protocol +- * @use_cache: Flag to enable cache usage +- * This function performs a route lookup on a tunnel +- * +- * It returns a valid dst pointer and stores src address to be used in +- * tunnel in param saddr on success, else a pointer encoded error code. +- */ +- +-struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, +- struct socket *sock, +- struct in6_addr *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, +- bool use_cache) +-{ +- struct dst_entry *dst = NULL; +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif +- struct flowi6 fl6; +- __u8 prio; +- +-#ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { +- dst = dst_cache_get_ip6(dst_cache, saddr); +- if (dst) +- return dst; +- } +-#endif +- memset(&fl6, 0, sizeof(fl6)); +- fl6.flowi6_mark = skb->mark; +- fl6.flowi6_proto = protocol; +- fl6.daddr = info->key.u.ipv6.dst; +- fl6.saddr = info->key.u.ipv6.src; +- prio = info->key.tos; +- fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); +- +- dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, +- NULL); +- if (IS_ERR(dst)) { +- netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); +- return ERR_PTR(-ENETUNREACH); +- } +- if (dst->dev == dev) { /* is this necessary? */ +- netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); +- dst_release(dst); +- return ERR_PTR(-ELOOP); +- } +-#ifdef CONFIG_DST_CACHE +- if (use_cache) +- dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); +-#endif +- *saddr = fl6.saddr; +- return dst; +-} +-EXPORT_SYMBOL_GPL(ip6_dst_lookup_tunnel); +- + static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, + gfp_t gfp) + { +diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c +index cdc4d4ee24206..7aef559e60ec5 100644 +--- a/net/ipv6/ip6_udp_tunnel.c ++++ b/net/ipv6/ip6_udp_tunnel.c +@@ -1,3 +1,4 @@ ++ + // SPDX-License-Identifier: GPL-2.0-only + #include + #include +@@ -111,4 +112,72 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + } + EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); + ++/** ++ * udp_tunnel6_dst_lookup - perform route lookup on UDP tunnel ++ * @skb: Packet for which lookup is done ++ * @dev: Tunnel device ++ * @net: Network namespace of tunnel device ++ * @sock: Socket which provides route info ++ * @saddr: Memory to store the src ip address ++ * @info: Tunnel information ++ * @protocol: IP protocol ++ * @use_cache: Flag to enable cache usage ++ * This function performs a route lookup on a UDP tunnel ++ * ++ * It returns a valid dst pointer and stores src address to be used in ++ * tunnel in param saddr on success, else a pointer encoded error code. ++ */ ++ ++struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, ++ struct socket *sock, ++ struct in6_addr *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, ++ bool use_cache) ++{ ++ struct dst_entry *dst = NULL; ++#ifdef CONFIG_DST_CACHE ++ struct dst_cache *dst_cache; ++#endif ++ struct flowi6 fl6; ++ __u8 prio; ++ ++#ifdef CONFIG_DST_CACHE ++ dst_cache = (struct dst_cache *)&info->dst_cache; ++ if (use_cache) { ++ dst = dst_cache_get_ip6(dst_cache, saddr); ++ if (dst) ++ return dst; ++ } ++#endif ++ memset(&fl6, 0, sizeof(fl6)); ++ fl6.flowi6_mark = skb->mark; ++ fl6.flowi6_proto = protocol; ++ fl6.daddr = info->key.u.ipv6.dst; ++ fl6.saddr = info->key.u.ipv6.src; ++ prio = info->key.tos; ++ fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); ++ ++ dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, ++ NULL); ++ if (IS_ERR(dst)) { ++ netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); ++ return ERR_PTR(-ENETUNREACH); ++ } ++ if (dst->dev == dev) { /* is this necessary? */ ++ netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); ++ dst_release(dst); ++ return ERR_PTR(-ELOOP); ++ } ++#ifdef CONFIG_DST_CACHE ++ if (use_cache) ++ dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); ++#endif ++ *saddr = fl6.saddr; ++ return dst; ++} ++EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup); ++ + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-5.15/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch b/queue-5.15/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch new file mode 100644 index 0000000000..3c933c3e0d --- /dev/null +++ b/queue-5.15/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch @@ -0,0 +1,97 @@ +From 81b13c9674eb05f17f45da88669a4dfac45cce94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:40:29 +0800 +Subject: ipvs: fix MTU check for GSO packets in tunnel mode + +From: Yingnan Zhang <342144303@qq.com> + +[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ] + +Currently, IPVS skips MTU checks for GSO packets by excluding them with +the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel +mode encapsulates GSO packets with IPIP headers. + +The issue manifests in two ways: + +1. MTU violation after encapsulation: + When a GSO packet passes through IPVS tunnel mode, the original MTU + check is bypassed. After adding the IPIP tunnel header, the packet + size may exceed the outgoing interface MTU, leading to unexpected + fragmentation at the IP layer. + +2. Fragmentation with problematic IP IDs: + When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments + is fragmented after encapsulation, each segment gets a sequentially + incremented IP ID (0, 1, 2, ...). This happens because: + + a) The GSO packet bypasses MTU check and gets encapsulated + b) At __ip_finish_output, the oversized GSO packet is split into + separate SKBs (one per segment), with IP IDs incrementing + c) Each SKB is then fragmented again based on the actual MTU + + This sequential IP ID allocation differs from the expected behavior + and can cause issues with fragment reassembly and packet tracking. + +Fix this by properly validating GSO packets using +skb_gso_validate_network_len(). This function correctly validates +whether the GSO segments will fit within the MTU after segmentation. If +validation fails, send an ICMP Fragmentation Needed message to enable +proper PMTU discovery. + +Fixes: 4cdd34084d53 ("netfilter: nf_conntrack_ipv6: improve fragmentation handling") +Signed-off-by: Yingnan Zhang <342144303@qq.com> +Acked-by: Julian Anastasov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index f82834349ca2c..9e199f00eea73 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -103,6 +103,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest) + return dest_dst; + } + ++/* Based on ip_exceeds_mtu(). */ ++static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) ++{ ++ if (skb->len <= mtu) ++ return false; ++ ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) ++ return false; ++ ++ return true; ++} ++ + static inline bool + __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + { +@@ -112,10 +124,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + */ + if (IP6CB(skb)->frag_max_size > mtu) + return true; /* largest fragment violate MTU */ +- } +- else if (skb->len > mtu && !skb_is_gso(skb)) { ++ } else if (ip_vs_exceeds_mtu(skb, mtu)) + return true; /* Packet size violate MTU size */ +- } ++ + return false; + } + +@@ -240,7 +251,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, + return true; + + if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && +- skb->len > mtu && !skb_is_gso(skb) && ++ ip_vs_exceeds_mtu(skb, mtu) && + !ip_vs_iph_icmp(ipvsh))) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); +-- +2.53.0 + diff --git a/queue-5.15/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch b/queue-5.15/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch new file mode 100644 index 0000000000..c23c9dbc5b --- /dev/null +++ b/queue-5.15/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch @@ -0,0 +1,48 @@ +From 29d506b46be368d081a93e463ea799835ba6e7c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Feb 2026 18:43:44 -0500 +Subject: irqchip/irq-pic32-evic: Address warning related to wrong printf() + formatter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 86be659415b0ddefebc3120e309091aa215a9064 ] + +This driver is currently only build on 32 bit MIPS systems. When building +it on x86_64, the following warning occurs: + + drivers/irqchip/irq-pic32-evic.c: In function ‘pic32_ext_irq_of_init’: + ./include/linux/kern_levels.h:5:25: error: format ‘%d’ expects argument of type + ‘int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] + +Update the printf() formatter in preparation for allowing this driver to +be compiled on all architectures. + +Fixes: aaa8666ada780 ("IRQCHIP: irq-pic32-evic: Add support for PIC32 interrupt controller") +Signed-off-by: Brian Masney +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260222-irqchip-pic32-v1-1-37f50d1f14af@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-pic32-evic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c +index 1d9bb28d13e5d..1a72047f3aa2e 100644 +--- a/drivers/irqchip/irq-pic32-evic.c ++++ b/drivers/irqchip/irq-pic32-evic.c +@@ -198,7 +198,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain) + + of_property_for_each_u32(node, pname, prop, p, hwirq) { + if (i >= ARRAY_SIZE(priv->ext_irqs)) { +- pr_warn("More than %d external irq, skip rest\n", ++ pr_warn("More than %zu external irq, skip rest\n", + ARRAY_SIZE(priv->ext_irqs)); + break; + } +-- +2.53.0 + diff --git a/queue-5.15/kernel-globalize-lookup_or_create_module_kobject.patch b/queue-5.15/kernel-globalize-lookup_or_create_module_kobject.patch new file mode 100644 index 0000000000..8881860e45 --- /dev/null +++ b/queue-5.15/kernel-globalize-lookup_or_create_module_kobject.patch @@ -0,0 +1,55 @@ +From 0d10780f0ff4e5e08d18ffe91d0c6618cfebe51c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 10:49:29 -0800 +Subject: kernel: globalize lookup_or_create_module_kobject() + +From: Shyam Saini + +[ Upstream commit 7c76c813cfc42a7376378a0c4b7250db2eebab81 ] + +lookup_or_create_module_kobject() is marked as static and __init, +to make it global drop static keyword. +Since this function can be called from non-init code, use __modinit +instead of __init, __modinit marker will make it __init if +CONFIG_MODULES is not defined. + +Suggested-by: Rasmus Villemoes +Signed-off-by: Shyam Saini +Link: https://lore.kernel.org/r/20250227184930.34163-4-shyamsaini@linux.microsoft.com +Signed-off-by: Petr Pavlu +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 2 ++ + kernel/params.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index 8e629b03ed1e4..440a2d08f7e02 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -162,6 +162,8 @@ extern void cleanup_module(void); + #define __INITRODATA_OR_MODULE __INITRODATA + #endif /*CONFIG_MODULES*/ + ++struct module_kobject *lookup_or_create_module_kobject(const char *name); ++ + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) + +diff --git a/kernel/params.c b/kernel/params.c +index 2c1b9559ff9b6..cedda487df96b 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -758,7 +758,7 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-static struct module_kobject * __init lookup_or_create_module_kobject(const char *name) ++struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +-- +2.53.0 + diff --git a/queue-5.15/kernel-param-rename-locate_module_kobject.patch b/queue-5.15/kernel-param-rename-locate_module_kobject.patch new file mode 100644 index 0000000000..dc11e20d69 --- /dev/null +++ b/queue-5.15/kernel-param-rename-locate_module_kobject.patch @@ -0,0 +1,62 @@ +From 7137e7d9439afe7e9ff77bb5aa5abfaa8c01239d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 10:49:27 -0800 +Subject: kernel: param: rename locate_module_kobject + +From: Shyam Saini + +[ Upstream commit bbc9462f0cb0c8917a4908e856731708f0cee910 ] + +The locate_module_kobject() function looks up an existing +module_kobject for a given module name. If it cannot find the +corresponding module_kobject, it creates one for the given name. + +This commit renames locate_module_kobject() to +lookup_or_create_module_kobject() to better describe its operations. + +This doesn't change anything functionality wise. + +Suggested-by: Rasmus Villemoes +Signed-off-by: Shyam Saini +Link: https://lore.kernel.org/r/20250227184930.34163-2-shyamsaini@linux.microsoft.com +Signed-off-by: Petr Pavlu +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + kernel/params.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/kernel/params.c b/kernel/params.c +index 1b856942d82d4..2c1b9559ff9b6 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -758,7 +758,7 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-static struct module_kobject * __init locate_module_kobject(const char *name) ++static struct module_kobject * __init lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +@@ -800,7 +800,7 @@ static void __init kernel_add_sysfs_param(const char *name, + struct module_kobject *mk; + int err; + +- mk = locate_module_kobject(name); ++ mk = lookup_or_create_module_kobject(name); + if (!mk) + return; + +@@ -871,7 +871,7 @@ static void __init version_sysfs_builtin(void) + int err; + + for (vattr = __start___modver; vattr < __stop___modver; vattr++) { +- mk = locate_module_kobject(vattr->module_name); ++ mk = lookup_or_create_module_kobject(vattr->module_name); + if (mk) { + err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); + WARN_ON_ONCE(err); +-- +2.53.0 + diff --git a/queue-5.15/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch b/queue-5.15/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch new file mode 100644 index 0000000000..a66a089fd0 --- /dev/null +++ b/queue-5.15/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch @@ -0,0 +1,71 @@ +From fb770730235d6290b07d7a69430616d7afa5adc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:54 +0900 +Subject: ksmbd: destroy tree_conn_ida in ksmbd_session_destroy() + +From: DaeMyung Kang + +[ Upstream commit c049ee14eb4343b69b6f7755563f961f5e153423 ] + +When per-session tree_conn_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from ksmbd_session_destroy() but no matching ida_destroy() +was added. The session is therefore freed with the IDA's backing +xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +enclosing session is freed. + +Also move ida_init() to right after the session is allocated so that +it is always paired with the destroy call even on the early error +paths of __session_create() (ksmbd_init_file_table() or +__init_smb2_session() failures), both of which jump to the error +label and invoke ksmbd_session_destroy() on a partially initialised +session. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/ksmbd/mgmt/user_session.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c +index 8bd18610547d9..23a0662bbfd32 100644 +--- a/fs/ksmbd/mgmt/user_session.c ++++ b/fs/ksmbd/mgmt/user_session.c +@@ -153,6 +153,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) + free_channel_list(sess); + kfree(sess->Preauth_HashValue); + ksmbd_release_id(&session_ida, sess->id); ++ ida_destroy(&sess->tree_conn_ida); + kfree(sess); + } + +@@ -382,6 +383,8 @@ static struct ksmbd_session *__session_create(int protocol) + if (!sess) + return NULL; + ++ ida_init(&sess->tree_conn_ida); ++ + if (ksmbd_init_file_table(&sess->file_table)) + goto error; + +@@ -399,8 +402,6 @@ static struct ksmbd_session *__session_create(int protocol) + if (ret) + goto error; + +- ida_init(&sess->tree_conn_ida); +- + down_write(&sessions_table_lock); + hash_add(sessions_table, &sess->hlist, sess->id); + up_write(&sessions_table_lock); +-- +2.53.0 + diff --git a/queue-5.15/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch b/queue-5.15/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch new file mode 100644 index 0000000000..d48771e229 --- /dev/null +++ b/queue-5.15/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch @@ -0,0 +1,73 @@ +From d89ff378531e15d933a76613b074f80e85edca58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 22:31:12 -0400 +Subject: ksmbd: fix use-after-free from async crypto on Qualcomm crypto engine + +From: Joshua Klinesmith + +[ Upstream commit 3e298897f41c61450c2e7a4f457e8b2485eb35b3 ] + +ksmbd_crypt_message() sets a NULL completion callback on AEAD requests +and does not handle the -EINPROGRESS return code from async hardware +crypto engines like the Qualcomm Crypto Engine (QCE). When QCE returns +-EINPROGRESS, ksmbd treats it as an error and immediately frees the +request while the hardware DMA operation is still in flight. The DMA +completion callback then dereferences freed memory, causing a NULL +pointer crash: + + pc : qce_skcipher_done+0x24/0x174 + lr : vchan_complete+0x230/0x27c + ... + el1h_64_irq+0x68/0x6c + ksmbd_free_work_struct+0x20/0x118 [ksmbd] + ksmbd_exit_file_cache+0x694/0xa4c [ksmbd] + +Use the standard crypto_wait_req() pattern with crypto_req_done() as +the completion callback, matching the approach used by the SMB client +in fs/smb/client/smb2ops.c. This properly handles both synchronous +engines (immediate return) and async engines (-EINPROGRESS followed +by callback notification). + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Link: https://github.com/openwrt/openwrt/issues/21822 +Signed-off-by: Joshua Klinesmith +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/ksmbd/auth.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c +index 647692ca78a28..8fc7a1fffd55a 100644 +--- a/fs/ksmbd/auth.c ++++ b/fs/ksmbd/auth.c +@@ -1108,6 +1108,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int rc; ++ DECLARE_CRYPTO_WAIT(wait); + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; +@@ -1194,12 +1195,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); +- aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); ++ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | ++ CRYPTO_TFM_REQ_MAY_SLEEP, ++ crypto_req_done, &wait); + +- if (enc) +- rc = crypto_aead_encrypt(req); +- else +- rc = crypto_aead_decrypt(req); ++ rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : ++ crypto_aead_decrypt(req), &wait); + if (rc) + goto free_iv; + +-- +2.53.0 + diff --git a/queue-5.15/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch b/queue-5.15/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch new file mode 100644 index 0000000000..c89a071195 --- /dev/null +++ b/queue-5.15/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch @@ -0,0 +1,59 @@ +From e762a62bc1f26299c988f41eb339a85bf7eb101b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 00:31:47 +0900 +Subject: ksmbd: scope conn->binding slowpath to bound sessions only + +From: Hyunwoo Kim + +[ Upstream commit b0da97c034b6107d14e537e212d4ce8b22109a58 ] + +When the binding SESSION_SETUP sets conn->binding = true, the flag stays +set after the call so that the global session lookup in +ksmbd_session_lookup_all() can find the session, which was not added to +conn->sessions. Because the flag is connection-wide, the global lookup +path will also resolve any other session by id if asked. + +Tighten the global lookup so that the returned session must have this +connection registered in its channel xarray (sess->ksmbd_chann_list). +The channel entry is installed by the existing binding_session path in +ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes +successfully, so this condition is a strict equivalent of "this +connection has been accepted as a channel of this session". Connections +that have not bound to a given session cannot reach it via the global +table. + +The existing conn->binding gate for entering the slowpath is preserved +so that non-binding connections keep the fast-path-only behavior, and +the session->state check is unchanged. + +Fixes: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel") +Signed-off-by: Hyunwoo Kim +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/ksmbd/mgmt/user_session.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c +index 23a0662bbfd32..b6b6572d402d3 100644 +--- a/fs/ksmbd/mgmt/user_session.c ++++ b/fs/ksmbd/mgmt/user_session.c +@@ -301,8 +301,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, + struct ksmbd_session *sess; + + sess = ksmbd_session_lookup(conn, id); +- if (!sess && conn->binding) ++ if (!sess && conn->binding) { + sess = ksmbd_session_lookup_slowpath(id); ++ if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) { ++ ksmbd_user_session_put(sess); ++ sess = NULL; ++ } ++ } + if (sess && sess->state != SMB2_SESSION_VALID) { + ksmbd_user_session_put(sess); + sess = NULL; +-- +2.53.0 + diff --git a/queue-5.15/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch b/queue-5.15/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch new file mode 100644 index 0000000000..842f612118 --- /dev/null +++ b/queue-5.15/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch @@ -0,0 +1,49 @@ +From 5ff3f8f3ae2f9039466fb3749b4b29c28d386e78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:56 -0300 +Subject: ktest: Avoid undef warning when WARNINGS_FILE is unset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit 057854f8a595160656fe77ed7bf0d2403724b915 ] + +check_buildlog() probes $warnings_file with -f even when WARNINGS_FILE is +not configured. Perl warns about the uninitialized value and adds noise to +the test log, which can hide the output we actually care about. + +Check that WARNINGS_FILE is defined before testing whether the file exists. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-1-565d412f4925@suse.com +Fixes: 4283b169abfb ("ktest: Add make_warnings_file and process full warnings") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index b1bd8be3cf666..d752c4bd0d8b3 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -2465,7 +2465,7 @@ sub check_buildlog { + my $save_no_reboot = $no_reboot; + $no_reboot = 1; + +- if (-f $warnings_file) { ++ if (defined($warnings_file) && -f $warnings_file) { + open(IN, $warnings_file) or + dodie "Error opening $warnings_file"; + +-- +2.53.0 + diff --git a/queue-5.15/ktest-honor-empty-per-test-option-overrides.patch b/queue-5.15/ktest-honor-empty-per-test-option-overrides.patch new file mode 100644 index 0000000000..d26278defc --- /dev/null +++ b/queue-5.15/ktest-honor-empty-per-test-option-overrides.patch @@ -0,0 +1,79 @@ +From a044431a240c56b9c7ab9c3b3731d8393cfd515e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:59 -0300 +Subject: ktest: Honor empty per-test option overrides +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit a2de57a3c8192dcd67cccaff6c341b93748d799b ] + +A per-test override can clear an inherited default option by assigning an +empty value, but __set_test_option() still used option_defined() to decide +whether a per-test key existed. That turned an empty per-test assignment +back into "fall back to the default", so tests still could not clear +inherited settings. + +For example: + + DEFAULTS + (...) + LOG_FILE = /tmp/ktest-empty-override.log + CLEAR_LOG = 1 + ADD_CONFIG = /tmp/.config + + TEST_START + TEST_TYPE = build + BUILD_TYPE = nobuild + ADD_CONFIG = + +This would run the test with ADD_CONFIG[1] = /tmp/.config + +Fix by checking whether the per-test key exists before falling back. If it +does exist but is empty, treat it as unset for that test and stop the +fallback chain there. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-4-565d412f4925@suse.com +Fixes: 22c37a9ac49d ("ktest: Allow tests to undefine default options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index d752c4bd0d8b3..28eebfa32621d 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -4106,7 +4106,8 @@ sub __set_test_option { + + my $option = "$name\[$i\]"; + +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + +@@ -4114,7 +4115,8 @@ sub __set_test_option { + if ($i >= $test && + $i < $test + $repeat_tests{$test}) { + $option = "$name\[$test\]"; +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + } +-- +2.53.0 + diff --git a/queue-5.15/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch b/queue-5.15/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch new file mode 100644 index 0000000000..935ddb0900 --- /dev/null +++ b/queue-5.15/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch @@ -0,0 +1,105 @@ +From 2de032a2cea4e9914fdb8ed4dce29561d524f3cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:08:03 -0300 +Subject: ktest: Run POST_KTEST hooks on failure and cancellation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit bc6e165a452da909cef0efbc286e6695624db372 ] + +PRE_KTEST can be useful for setting up the environment and POST_KTEST to +tear it down, however POST_KTEST only runs on the normal end-of-run path. +It is skipped when ktest exits through dodie() or cancel_test(). Final +cleanup hooks are skipped. + +Factor the final hook execution into run_post_ktest(), call it from the +normal exit path and from the early exit paths, and guard it so the hook +runs at most once. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-8-565d412f4925@suse.com +Fixes: 921ed4c7208e ("ktest: Add PRE/POST_KTEST and TEST options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 28eebfa32621d..df8588dadc2ca 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -98,6 +98,7 @@ my $test_type; + my $build_type; + my $build_options; + my $final_post_ktest; ++my $post_ktest_done = 0; + my $pre_ktest; + my $post_ktest; + my $pre_test; +@@ -1530,6 +1531,24 @@ sub get_test_name() { + return $name; + } + ++sub run_post_ktest { ++ my $cmd; ++ ++ return if ($post_ktest_done); ++ ++ if (defined($final_post_ktest)) { ++ $cmd = $final_post_ktest; ++ } elsif (defined($post_ktest)) { ++ $cmd = $post_ktest; ++ } else { ++ return; ++ } ++ ++ my $cp_post_ktest = eval_kernel_version($cmd); ++ run_command $cp_post_ktest; ++ $post_ktest_done = 1; ++} ++ + sub dodie { + # avoid recursion + return if ($in_die); +@@ -1589,6 +1608,7 @@ sub dodie { + if (defined($post_test)) { + run_command $post_test; + } ++ run_post_ktest; + + die @_, "\n"; + } +@@ -4223,6 +4243,7 @@ sub cancel_test { + send_email("KTEST: Your [$name] test was cancelled", + "Your test started at $script_start_time was cancelled: sig int"); + } ++ run_post_ktest; + die "\nCaught Sig Int, test interrupted: $!\n" + } + +@@ -4533,11 +4554,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { + success $i; + } + +-if (defined($final_post_ktest)) { +- +- my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; +- run_command $cp_final_post_ktest; +-} ++run_post_ktest; + + if ($opt{"POWEROFF_ON_SUCCESS"}) { + halt; +-- +2.53.0 + diff --git a/queue-5.15/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch b/queue-5.15/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch new file mode 100644 index 0000000000..318b2b216d --- /dev/null +++ b/queue-5.15/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch @@ -0,0 +1,36 @@ +From 2a4c6e1c711c8960a20ff914a34682ac214fc965 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:30:48 +0800 +Subject: leds: lgm-sso: Remove duplicate assignments for priv->mmap + +From: Chen Ni + +[ Upstream commit 7186d0330c3f3e86de577687a82f4ebd96dcb5ac ] + +Remove duplicate assignment of priv->mmap in intel_sso_led_probe(). + +Fixes: fba8a6f2263b ("leds: lgm-sso: Fix clock handling") +Signed-off-by: Chen Ni +Link: https://patch.msgid.link/20260226033048.3715915-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index fd8b7573285ad..45045c2a26574 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -808,8 +808,6 @@ static int intel_sso_led_probe(struct platform_device *pdev) + + priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk); + +- priv->mmap = syscon_node_to_regmap(dev->of_node); +- + priv->mmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(priv->mmap)) { + dev_err(dev, "Failed to map iomem!\n"); +-- +2.53.0 + diff --git a/queue-5.15/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch b/queue-5.15/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch new file mode 100644 index 0000000000..befa8a8514 --- /dev/null +++ b/queue-5.15/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch @@ -0,0 +1,51 @@ +From 7b559d1deb03eee39bd7775d8078968cc86fecda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 17:21:43 +0200 +Subject: lib/hexdump: print_hex_dump_bytes() calls print_hex_dump_debug() + +From: Geert Uytterhoeven + +[ Upstream commit 36776b7f8a8955b4e75b5d490a75fee0c7a2a7ef ] + +print_hex_dump_bytes() claims to be a simple wrapper around +print_hex_dump(), but it actally calls print_hex_dump_debug(), which +means no output is printed if (dynamic) DEBUG is disabled. + +Update the documentation to match the implementation. + +Fixes: 091cb0994edd20d6 ("lib/hexdump: make print_hex_dump_bytes() a nop on !DEBUG builds") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Petr Mladek +Link: https://patch.msgid.link/3d5c3069fd9102ecaf81d044b750cd613eb72a08.1774970392.git.geert+renesas@glider.be +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + include/linux/printk.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index c4fb84822111d..ff5062bf9b33d 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -741,7 +741,8 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + #endif + + /** +- * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params ++ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default ++ * params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none +@@ -749,7 +750,7 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + * @buf: data blob to dump + * @len: number of bytes in the @buf + * +- * Calls print_hex_dump(), with log level of KERN_DEBUG, ++ * Calls print_hex_dump_debug(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ + #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ +-- +2.53.0 + diff --git a/queue-5.15/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch b/queue-5.15/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch new file mode 100644 index 0000000000..993f6ef1da --- /dev/null +++ b/queue-5.15/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch @@ -0,0 +1,75 @@ +From 23483cd53db47a1d841bf635c793f96478a93963 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:15:07 -0700 +Subject: locking: Fix rwlock support in + +From: Bart Van Assche + +[ Upstream commit 756a0e011cfca0b45a48464aa25b05d9a9c2fb0b ] + +Architecture support for rwlocks must be available whether or not +CONFIG_DEBUG_SPINLOCK has been defined. Move the definitions of the +arch_{read,write}_{lock,trylock,unlock}() macros such that these become +visbile if CONFIG_DEBUG_SPINLOCK=n. + +This patch prepares for converting do_raw_{read,write}_trylock() into +inline functions. Without this patch that conversion triggers a build +failure for UP architectures, e.g. arm-ep93xx. I used the following +kernel configuration to build the kernel for that architecture: + + CONFIG_ARCH_MULTIPLATFORM=y + CONFIG_ARCH_MULTI_V7=n + CONFIG_ATAGS=y + CONFIG_MMU=y + CONFIG_ARCH_MULTI_V4T=y + CONFIG_CPU_LITTLE_ENDIAN=y + CONFIG_ARCH_EP93XX=y + +Fixes: fb1c8f93d869 ("[PATCH] spinlock consolidation") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260313171510.230998-2-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/spinlock_up.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h +index 0ac9112c1bbe3..a406655c1fbd1 100644 +--- a/include/linux/spinlock_up.h ++++ b/include/linux/spinlock_up.h +@@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + lock->slock = 1; + } + +-/* +- * Read-write spinlocks. No debug version. +- */ +-#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) +- + #else /* DEBUG_SPINLOCK */ + #define arch_spin_is_locked(lock) ((void)(lock), 0) + /* for sched/core.c and kernel_lock.c: */ +@@ -69,4 +59,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + + #define arch_spin_is_contended(lock) (((void)(lock), 0)) + ++/* ++ * Read-write spinlocks. No debug version. ++ */ ++#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) ++ + #endif /* __LINUX_SPINLOCK_UP_H */ +-- +2.53.0 + diff --git a/queue-5.15/macvlan-annotate-data-races-around-port-bc_queue_len.patch b/queue-5.15/macvlan-annotate-data-races-around-port-bc_queue_len.patch new file mode 100644 index 0000000000..58c0cefc25 --- /dev/null +++ b/queue-5.15/macvlan-annotate-data-races-around-port-bc_queue_len.patch @@ -0,0 +1,67 @@ +From bd41b480d76d507cbe80928186df2147abec7f93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:38:08 +0000 +Subject: macvlan: annotate data-races around port->bc_queue_len_used + +From: Eric Dumazet + +[ Upstream commit 1ef5789d9906df3771c99b7f413caaf2bf473ca5 ] + +port->bc_queue_len_used is read and written locklessly, +add READ_ONCE()/WRITE_ONCE() annotations. + +While WRITE_ONCE() in macvlan_fill_info() is not yet needed, +it is a prereq for future RTNL avoidance. + +Fixes: d4bff72c8401 ("macvlan: Support for high multicast packet rate") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401103809.3038139-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index f2fb958c1f232..86a531ffe9fc0 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -344,6 +344,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + const struct macvlan_dev *src, + struct sk_buff *skb) + { ++ u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used); + struct sk_buff *nskb; + int err = -ENOMEM; + +@@ -354,7 +355,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + MACVLAN_SKB_CB(nskb)->src = src; + + spin_lock(&port->bc_queue.lock); +- if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) { ++ if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) { + if (src) + dev_hold(src->dev); + __skb_queue_tail(&port->bc_queue, nskb); +@@ -1683,7 +1684,8 @@ static int macvlan_fill_info(struct sk_buff *skb, + } + if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) + goto nla_put_failure; +- if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) ++ if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, ++ READ_ONCE(port->bc_queue_len_used))) + goto nla_put_failure; + return 0; + +@@ -1739,7 +1741,7 @@ static void update_port_bc_queue_len(struct macvlan_port *port) + if (vlan->bc_queue_len_req > max_bc_queue_len_req) + max_bc_queue_len_req = vlan->bc_queue_len_req; + } +- port->bc_queue_len_used = max_bc_queue_len_req; ++ WRITE_ONCE(port->bc_queue_len_used, max_bc_queue_len_req); + } + + static int macvlan_device_event(struct notifier_block *unused, +-- +2.53.0 + diff --git a/queue-5.15/mailbox-add-sanity-check-for-channel-array.patch b/queue-5.15/mailbox-add-sanity-check-for-channel-array.patch new file mode 100644 index 0000000000..ae1f552f83 --- /dev/null +++ b/queue-5.15/mailbox-add-sanity-check-for-channel-array.patch @@ -0,0 +1,40 @@ +From 9b2ec8f5672214369d93a814aa5757a9cc54e50d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:42:38 +0200 +Subject: mailbox: add sanity check for channel array + +From: Wolfram Sang + +[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ] + +Fail gracefully if there is no channel array attached to the mailbox +controller. Otherwise the later dereference will cause an OOPS which +might not be seen because mailbox controllers might instantiate very +early. Remove the comment explaining the obvious while here. + +Fixes: 2b6d83e2b8b7 ("mailbox: Introduce framework for mailbox") +Signed-off-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index 090795c1b65db..363eaf3c962ec 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -484,8 +484,7 @@ int mbox_controller_register(struct mbox_controller *mbox) + { + int i, txdone; + +- /* Sanity check */ +- if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) ++ if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) + return -EINVAL; + + if (mbox->txdone_irq) +-- +2.53.0 + diff --git a/queue-5.15/mailbox-mailbox-test-don-t-free-the-reused-channel.patch b/queue-5.15/mailbox-mailbox-test-don-t-free-the-reused-channel.patch new file mode 100644 index 0000000000..39e4347a32 --- /dev/null +++ b/queue-5.15/mailbox-mailbox-test-don-t-free-the-reused-channel.patch @@ -0,0 +1,46 @@ +From 0926f2add732bec92996792cc4be87db374c8db9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:34 +0200 +Subject: mailbox: mailbox-test: don't free the reused channel + +From: Wolfram Sang + +[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ] + +The RX channel can be aliased to the TX channel if it has a different +MMIO. This special case needs to be handled when freeing the channels +otherwise a double-free occurs. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 1d546cae922ce..247e83af060e3 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -423,7 +423,7 @@ static int mbox_test_probe(struct platform_device *pdev) + err_free_chans: + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + return ret; + } +@@ -436,7 +436,7 @@ static int mbox_test_remove(struct platform_device *pdev) + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + + return 0; +-- +2.53.0 + diff --git a/queue-5.15/mailbox-mailbox-test-free-channels-on-probe-error.patch b/queue-5.15/mailbox-mailbox-test-free-channels-on-probe-error.patch new file mode 100644 index 0000000000..07145de655 --- /dev/null +++ b/queue-5.15/mailbox-mailbox-test-free-channels-on-probe-error.patch @@ -0,0 +1,60 @@ +From c44d2a05ecc0481543b93a6747d44e9022199755 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 14:53:00 +0200 +Subject: mailbox: mailbox-test: free channels on probe error + +From: Wolfram Sang + +[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ] + +On probe error, free the previously obtained channels. This not only +prevents a leak, but also UAF scenarios because the client structure +will be removed nonetheless because it was allocated with devm. + +Link: https://sashiko.dev/#/patchset/20260327151217.5327-2-wsa%2Brenesas%40sang-engineering.com +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 29c04157b5e88..1d546cae922ce 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -405,18 +405,27 @@ static int mbox_test_probe(struct platform_device *pdev) + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +- if (!tdev->rx_buffer) +- return -ENOMEM; ++ if (!tdev->rx_buffer) { ++ ret = -ENOMEM; ++ goto err_free_chans; ++ } + } + + ret = mbox_test_add_debugfs(pdev, tdev); + if (ret) +- return ret; ++ goto err_free_chans; + + init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; ++ ++err_free_chans: ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ if (tdev->rx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ return ret; + } + + static int mbox_test_remove(struct platform_device *pdev) +-- +2.53.0 + diff --git a/queue-5.15/mailbox-mailbox-test-initialize-struct-earlier.patch b/queue-5.15/mailbox-mailbox-test-initialize-struct-earlier.patch new file mode 100644 index 0000000000..262796f101 --- /dev/null +++ b/queue-5.15/mailbox-mailbox-test-initialize-struct-earlier.patch @@ -0,0 +1,64 @@ +From 0f99f9b71e7b2fb84d6f25ec992dca67af3b657b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:35 +0200 +Subject: mailbox: mailbox-test: initialize struct earlier + +From: Wolfram Sang + +[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ] + +The waitqueue must be initialized before the debugfs files are created +because from that time, requests from userspace can already be made. +Similarily, drvdata and spinlock needs to be initialized before we +request the channel, otherwise dangling irqs might run into problems +like a NULL pointer exception. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 247e83af060e3..41efe64976598 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -365,6 +365,12 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev) + return -ENOMEM; + ++ tdev->dev = &pdev->dev; ++ spin_lock_init(&tdev->lock); ++ mutex_init(&tdev->mutex); ++ init_waitqueue_head(&tdev->waitq); ++ platform_set_drvdata(pdev, tdev); ++ + /* It's okay for MMIO to be NULL */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); +@@ -396,12 +402,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) + tdev->rx_channel = tdev->tx_channel; + +- tdev->dev = &pdev->dev; +- platform_set_drvdata(pdev, tdev); +- +- spin_lock_init(&tdev->lock); +- mutex_init(&tdev->mutex); +- + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +@@ -415,7 +415,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (ret) + goto err_free_chans; + +- init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-5.15/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch b/queue-5.15/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch new file mode 100644 index 0000000000..d74f9c5e31 --- /dev/null +++ b/queue-5.15/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch @@ -0,0 +1,73 @@ +From 8336e4c9e75b63ae80f7cfcfc446797c5d35d100 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:36 +0200 +Subject: mailbox: mailbox-test: make data_ready a per-instance variable + +From: Wolfram Sang + +[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ] + +While not the default case, multiple tests can be run simultaneously. +Then, data_ready being a global variable will be overwritten and the +per-instance lock will not help. Turn the global variable into a +per-instance one to avoid this problem. + +Fixes: e339c80af95e ("mailbox: mailbox-test: don't rely on rx_buffer content to signal data ready") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 41efe64976598..113858fe168c3 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -27,8 +27,6 @@ + #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ + (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) + +-static bool mbox_data_ready; +- + struct mbox_test_device { + struct device *dev; + void __iomem *tx_mmio; +@@ -41,6 +39,7 @@ struct mbox_test_device { + spinlock_t lock; + struct mutex mutex; + wait_queue_head_t waitq; ++ bool data_ready; + struct fasync_struct *async_queue; + struct dentry *root_debugfs_dir; + }; +@@ -161,7 +160,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); +- data_ready = mbox_data_ready; ++ data_ready = tdev->data_ready; + spin_unlock_irqrestore(&tdev->lock, flags); + + return data_ready; +@@ -226,7 +225,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, + *(touser + l) = '\0'; + + memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); +- mbox_data_ready = false; ++ tdev->data_ready = false; + + spin_unlock_irqrestore(&tdev->lock, flags); + +@@ -296,7 +295,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) + message, MBOX_MAX_MSG_LEN); + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); + } +- mbox_data_ready = true; ++ tdev->data_ready = true; + spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); +-- +2.53.0 + diff --git a/queue-5.15/memory-tegra124-emc-fix-dll_change-check.patch b/queue-5.15/memory-tegra124-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..4b29b260ce --- /dev/null +++ b/queue-5.15/memory-tegra124-emc-fix-dll_change-check.patch @@ -0,0 +1,38 @@ +From aedd1cac1fdaee5d3b8bc660aa013475c6c3f713 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:42 +0900 +Subject: memory: tegra124-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 9597ab9a8296ab337e6820f8a717ff621078b632 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: 73a7f0a90641 ("memory: tegra: Add EMC (external memory controller) driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-1-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra124-emc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c +index 908f8d5392b21..6d5eb7d5b75c2 100644 +--- a/drivers/memory/tegra/tegra124-emc.c ++++ b/drivers/memory/tegra/tegra124-emc.c +@@ -608,7 +608,7 @@ static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, + + if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; +-- +2.53.0 + diff --git a/queue-5.15/memory-tegra30-emc-fix-dll_change-check.patch b/queue-5.15/memory-tegra30-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..bb9ea854e3 --- /dev/null +++ b/queue-5.15/memory-tegra30-emc-fix-dll_change-check.patch @@ -0,0 +1,47 @@ +From 6278babc4700abacc6afa1569e4f2757847e2154 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:43 +0900 +Subject: memory: tegra30-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 0a93f2355cf4922ad2399dbef5ea1049fef116d4 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: e34212c75a68 ("memory: tegra: Introduce Tegra30 EMC driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-2-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra30-emc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c +index 7e21a852f2e1f..ed4b74540714e 100644 +--- a/drivers/memory/tegra/tegra30-emc.c ++++ b/drivers/memory/tegra/tegra30-emc.c +@@ -539,14 +539,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) + emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG); + emc_dbg = readl_relaxed(emc->regs + EMC_DBG); + +- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1)) ++ if (emc->dll_on == !(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; + +- emc->dll_on = !!(timing->emc_mode_1 & 0x1); ++ emc->dll_on = !(timing->emc_mode_1 & 0x1); + + if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL)) + emc->zcal_long = true; +-- +2.53.0 + diff --git a/queue-5.15/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch b/queue-5.15/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch new file mode 100644 index 0000000000..b342b4b4f4 --- /dev/null +++ b/queue-5.15/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch @@ -0,0 +1,37 @@ +From 81c86327b757017612e43578d3386100c2b20206 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:56:20 +0530 +Subject: mfd: mc13xxx-core: Fix memory leak in mc13xxx_add_subdevice_pdata() + +From: Abdun Nihaal + +[ Upstream commit a5a65a7fb2f7796bbe492cd6be59c92cb64377d1 ] + +The memory allocated for cell.name using kmemdup() is not freed when +mfd_add_devices() fails. Fix that by using devm_kmemdup(). + +Fixes: 8e00593557c3 ("mfd: Add mc13892 support to mc13xxx") +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20260120102622.66921-1-nihaal@cse.iitm.ac.in +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mc13xxx-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c +index e281a9202f110..a2b016a9eeae6 100644 +--- a/drivers/mfd/mc13xxx-core.c ++++ b/drivers/mfd/mc13xxx-core.c +@@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return -E2BIG; + +- cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); ++ cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL); + if (!cell.name) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-5.15/module-fix-freeing-of-charp-module-parameters-when-c.patch b/queue-5.15/module-fix-freeing-of-charp-module-parameters-when-c.patch new file mode 100644 index 0000000000..9a9cb71b76 --- /dev/null +++ b/queue-5.15/module-fix-freeing-of-charp-module-parameters-when-c.patch @@ -0,0 +1,122 @@ +From 84c033e1d7600ec0d5fa5260d8d81b5da8883247 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:48:02 +0100 +Subject: module: Fix freeing of charp module parameters when CONFIG_SYSFS=n + +From: Petr Pavlu + +[ Upstream commit deffe1edba626d474fef38007c03646ca5876a0e ] + +When setting a charp module parameter, the param_set_charp() function +allocates memory to store a copy of the input value. Later, when the module +is potentially unloaded, the destroy_params() function is called to free +this allocated memory. + +However, destroy_params() is available only when CONFIG_SYSFS=y, otherwise +only a dummy variant is present. In the unlikely case that the kernel is +configured with CONFIG_MODULES=y and CONFIG_SYSFS=n, this results in +a memory leak of charp values when a module is unloaded. + +Fix this issue by making destroy_params() always available when +CONFIG_MODULES=y. Rename the function to module_destroy_params() to clarify +that it is intended for use by the module loader. + +Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs") +Signed-off-by: Petr Pavlu +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + include/linux/moduleparam.h | 11 +++-------- + kernel/module.c | 4 ++-- + kernel/params.c | 27 ++++++++++++++++++--------- + 3 files changed, 23 insertions(+), 19 deletions(-) + +diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h +index 061e19c94a6bc..f73ca4d62683b 100644 +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -392,14 +392,9 @@ extern char *parse_args(const char *name, + const char *doing, void *arg)); + + /* Called by module remove. */ +-#ifdef CONFIG_SYSFS +-extern void destroy_params(const struct kernel_param *params, unsigned num); +-#else +-static inline void destroy_params(const struct kernel_param *params, +- unsigned num) +-{ +-} +-#endif /* !CONFIG_SYSFS */ ++#ifdef CONFIG_MODULES ++void module_destroy_params(const struct kernel_param *params, unsigned int num); ++#endif + + /* All the helper functions */ + /* The macros to do compile-time type checking stolen from Jakub +diff --git a/kernel/module.c b/kernel/module.c +index 07fa34461fa2f..b6409b0032b85 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2179,7 +2179,7 @@ static void free_module(struct module *mod) + module_unload_free(mod); + + /* Free any allocated parameters. */ +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + + if (is_livepatch_module(mod)) + free_module_elf(mod); +@@ -4166,7 +4166,7 @@ static int load_module(struct load_info *info, const char __user *uargs, + mod_sysfs_teardown(mod); + coming_cleanup: + mod->state = MODULE_STATE_GOING; +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_GOING, mod); + klp_module_going(mod); +diff --git a/kernel/params.c b/kernel/params.c +index 9a76f556b898a..1233673b42ecc 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -743,15 +743,6 @@ void module_param_sysfs_remove(struct module *mod) + } + #endif + +-void destroy_params(const struct kernel_param *params, unsigned num) +-{ +- unsigned int i; +- +- for (i = 0; i < num; i++) +- if (params[i].ops->free) +- params[i].ops->free(params[i].arg); +-} +- + struct module_kobject * __init_or_module + lookup_or_create_module_kobject(const char *name) + { +@@ -971,3 +962,21 @@ static int __init param_sysfs_init(void) + subsys_initcall(param_sysfs_init); + + #endif /* CONFIG_SYSFS */ ++ ++#ifdef CONFIG_MODULES ++ ++/* ++ * module_destroy_params - free all parameters for one module ++ * @params: module parameters (array) ++ * @num: number of module parameters ++ */ ++void module_destroy_params(const struct kernel_param *params, unsigned int num) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < num; i++) ++ if (params[i].ops->free) ++ params[i].ops->free(params[i].arg); ++} ++ ++#endif /* CONFIG_MODULES */ +-- +2.53.0 + diff --git a/queue-5.15/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch b/queue-5.15/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch new file mode 100644 index 0000000000..96dbec38ef --- /dev/null +++ b/queue-5.15/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch @@ -0,0 +1,59 @@ +From 1b81537859069bf2edccc495b790f2d33ad638ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:57 +0200 +Subject: mtd: parsers: ofpart: call of_node_get() for dedicated subpartitions + +From: Cosmin Tanislav + +[ Upstream commit e882626c1747653f1f01ea9d12e278e613b11d0f ] + +In order to parse sub-partitions, add_mtd_partitions() calls +parse_mtd_partitions() for all previously found partitions. + +Each partition will end up being passed to parse_fixed_partitions(), and +its of_node will be treated as the ofpart_node. + +Commit 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in +parse_fixed_partitions()") added of_node_put() calls for ofpart_node on +all exit paths. + +In the case where the partition passed to parse_fixed_partitions() has a +parent, it is treated as a dedicated partitions node, and of_node_put() +is wrongly called for it, even if of_node_get() was not called +explicitly. + +On repeated bind / unbinds of the MTD, the extra of_node_put() ends up +decrementing the refcount down to 0, which should never happen, +resulting in the following error: + +OF: ERROR: of_node_release() detected bad of_node_put() on +/soc/spi@80007000/flash@0/partitions/partition@0 + +Call of_node_get() to balance the call to of_node_put() done for +dedicated partitions nodes. + +Fixes: 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in parse_fixed_partitions()") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 7ac5ba6edd63d..c024346df0c59 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -71,7 +71,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + dedicated = false; + } + } else { /* Partition */ +- ofpart_node = mtd_node; ++ ofpart_node = of_node_get(mtd_node); + } + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); +-- +2.53.0 + diff --git a/queue-5.15/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch b/queue-5.15/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch new file mode 100644 index 0000000000..a4ae011dfd --- /dev/null +++ b/queue-5.15/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch @@ -0,0 +1,48 @@ +From cf005b518b5565cd8f0e1d6e1c81fbac821ef5c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:56 +0200 +Subject: mtd: parsers: ofpart: call of_node_put() only in ofpart_fail path + +From: Cosmin Tanislav + +[ Upstream commit 0c87dea1aab86116211cb37387c404c9e9231c39 ] + +ofpart_none can only be reached after the for_each_child_of_node() loop +finishes. for_each_child_of_node() correctly calls of_node_put() for all +device nodes it iterates over as long as we don't break or jump out of +the loop. + +Calling of_node_put() inside the ofpart_none path will wrongly decrement +the ref count of the last node in the for_each_child_of_node() loop. + +Move the call to of_node_put() under the ofpart_fail label to fix this. + +Fixes: ebd5a74db74e ("mtd: ofpart: Check availability of reg property instead of name property") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 20af45a7270d5..7ac5ba6edd63d 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -172,11 +172,11 @@ static int parse_fixed_partitions(struct mtd_info *master, + ofpart_fail: + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", + master->name, pp, mtd_node); ++ of_node_put(pp); + ret = -EINVAL; + ofpart_none: + if (dedicated) + of_node_put(ofpart_node); +- of_node_put(pp); + kfree(parts); + return ret; + } +-- +2.53.0 + diff --git a/queue-5.15/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch b/queue-5.15/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch new file mode 100644 index 0000000000..d3380eb4bc --- /dev/null +++ b/queue-5.15/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch @@ -0,0 +1,41 @@ +From 3e76131542e6348798ddef1e92a5b32eff740d44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:43:36 +0800 +Subject: mtd: physmap_of_gemini: Fix disabled pinctrl state check + +From: Chen Ni + +[ Upstream commit b7c0982184b0661f5b1b805f3a56f1bd3757b63e ] + +The condition for checking the disabled pinctrl state incorrectly checks +gf->enabled_state instead of gf->disabled_state. This causes misleading +error messages and could lead to incorrect behavior when only one of the +pinctrl states is defined. + +Fix the condition to properly check gf->disabled_state. + +Fixes: 9d3b5086f6d4 ("mtd: physmap_of_gemini: Handle pin control") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/maps/physmap-gemini.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c +index d4a46e159d38f..8d5b791dd08d4 100644 +--- a/drivers/mtd/maps/physmap-gemini.c ++++ b/drivers/mtd/maps/physmap-gemini.c +@@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev, + dev_err(dev, "no enabled pin control state\n"); + + gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled"); +- if (IS_ERR(gf->enabled_state)) { ++ if (IS_ERR(gf->disabled_state)) { + dev_err(dev, "no disabled pin control state\n"); + } else { + ret = pinctrl_select_state(gf->p, gf->disabled_state); +-- +2.53.0 + diff --git a/queue-5.15/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch b/queue-5.15/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch new file mode 100644 index 0000000000..380c6a4a21 --- /dev/null +++ b/queue-5.15/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch @@ -0,0 +1,66 @@ +From 6958d2d9b1abfe0deb79f00f4479ee59c815143f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:24:30 +0100 +Subject: mtd: rawnand: sunxi: fix sunxi_nfc_hw_ecc_read_extra_oob + +From: Richard Genoud + +[ Upstream commit 848c13996c55fe4ea6bf5acc3ce6c8c5c944b5f6 ] + +When dumping the OOB, the bytes at the end where actually copied from +the beginning of the OOB instead of current_offset. + +That leads to something like: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +instead of: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +(example with BCH16, user data [8,0], no scrambling) + +*cur_off (offset from the beginning of the page) was compared to offset +(offset from the beginning of the OOB), and then, the +nand_change_read_column_op() sets the current position to the beginning +of the OOB instead of OOB+offset + +Fixes: 15d6f118285f ("mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode") +Reviewed-by: Jernej Skrabec +Signed-off-by: Richard Genoud +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/sunxi_nand.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c +index 11f656e9affb5..aa59b884206e0 100644 +--- a/drivers/mtd/nand/raw/sunxi_nand.c ++++ b/drivers/mtd/nand/raw/sunxi_nand.c +@@ -898,9 +898,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, + if (len <= 0) + return; + +- if (!cur_off || *cur_off != offset) +- nand_change_read_column_op(nand, mtd->writesize, NULL, 0, +- false); ++ if (!cur_off || *cur_off != (offset + mtd->writesize)) ++ nand_change_read_column_op(nand, mtd->writesize + offset, ++ NULL, 0, false); + + if (!randomize) + sunxi_nfc_read_buf(nand, oob + offset, len); +-- +2.53.0 + diff --git a/queue-5.15/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch b/queue-5.15/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch new file mode 100644 index 0000000000..a2d660ef5e --- /dev/null +++ b/queue-5.15/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch @@ -0,0 +1,38 @@ +From f3b2526f0939ae1aa4e3a3b5c58e5e992f2e2b37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 17:14:14 +0800 +Subject: mtd: spi-nor: core: correct the op.dummy.nbytes when check read + operations + +From: Haibo Chen + +[ Upstream commit 756564a536ecd8c9d33edd89f0647a91a0b03587 ] + +When check read operation, need to setting the op.dummy.nbytes based +on current read operation rather than the nor->read_proto. + +Fixes: 0e30f47232ab ("mtd: spi-nor: add support for DTR protocol") +Signed-off-by: Haibo Chen +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index e115aab7243e1..4de12532cb757 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -2160,7 +2160,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; +- if (spi_nor_protocol_is_dtr(nor->read_proto)) ++ if (spi_nor_protocol_is_dtr(read->proto)) + op.dummy.nbytes *= 2; + + return spi_nor_spimem_check_op(nor, &op); +-- +2.53.0 + diff --git a/queue-5.15/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch b/queue-5.15/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch new file mode 100644 index 0000000000..594266ee03 --- /dev/null +++ b/queue-5.15/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch @@ -0,0 +1,41 @@ +From e97b067b50def72d21f5d35c4ddde45dc3698674 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 20:42:56 +0800 +Subject: mtd: spi-nor: swp: check SR_TB flag when getting tb_mask + +From: Shiji Yang + +[ Upstream commit 94645aa41bf9ecb87c2ce78b1c3405bfb6074a37 ] + +When the chip does not support top/bottom block protect, the tb_mask +must be set to 0, otherwise SR1 bit5 will be unexpectedly modified. + +Signed-off-by: Shiji Yang +Fixes: 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support") +Reviewed-by: Michael Walle +Reviewed-by: Miquel Raynal +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/swp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c +index 8594bcbb7dbe0..f29779a761136 100644 +--- a/drivers/mtd/spi-nor/swp.c ++++ b/drivers/mtd/spi-nor/swp.c +@@ -27,8 +27,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) + { + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + return SR_TB_BIT6; +- else ++ else if (nor->flags & SNOR_F_HAS_SR_TB) + return SR_TB_BIT5; ++ else ++ return 0; + } + + static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) +-- +2.53.0 + diff --git a/queue-5.15/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch b/queue-5.15/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch new file mode 100644 index 0000000000..682aa06ce7 --- /dev/null +++ b/queue-5.15/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch @@ -0,0 +1,50 @@ +From a50212e07027c3a2e0607ab00c827a3b486453a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:54 -0700 +Subject: net: bcmgenet: fix off-by-one in bcmgenet_put_txcb + +From: Justin Chen + +[ Upstream commit 57f3f53d2c9c5a9e133596e2f7bc1c50688a6d38 ] + +The write_ptr points to the next open tx_cb. We want to return the +tx_cb that gets rewinded, so we must rewind the pointer first then +return the tx_cb that it points to. That way the txcb can be correctly +cleaned up. + +Fixes: 876dbadd53a7 ("net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()") +Signed-off-by: Justin Chen +Reviewed-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-2-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 4b8bb99b58eb2..8a7077e6903b2 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1700,15 +1700,15 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + { + struct enet_cb *tx_cb_ptr; + +- tx_cb_ptr = ring->cbs; +- tx_cb_ptr += ring->write_ptr - ring->cb_ptr; +- + /* Rewinding local write pointer */ + if (ring->write_ptr == ring->cb_ptr) + ring->write_ptr = ring->end_ptr; + else + ring->write_ptr--; + ++ tx_cb_ptr = ring->cbs; ++ tx_cb_ptr += ring->write_ptr - ring->cb_ptr; ++ + return tx_cb_ptr; + } + +-- +2.53.0 + diff --git a/queue-5.15/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch b/queue-5.15/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch new file mode 100644 index 0000000000..78d9528a0b --- /dev/null +++ b/queue-5.15/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch @@ -0,0 +1,66 @@ +From 879bbbbfb0f5628ecd0b534c6af11c4021da57ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 08:55:19 +0800 +Subject: net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master + +From: Jiayuan Chen + +[ Upstream commit 1921f91298d1388a0bb9db8f83800c998b649cb3 ] + +syzkaller reported a kernel panic in bond_rr_gen_slave_id() reached via +xdp_master_redirect(). Full decoded trace: + + https://syzkaller.appspot.com/bug?extid=80e046b8da2820b6ba73 + +bond_rr_gen_slave_id() dereferences bond->rr_tx_counter, a per-CPU +counter that bonding only allocates in bond_open() when the mode is +round-robin. If the bond device was never brought up, rr_tx_counter +stays NULL. + +The XDP redirect path can still reach that code on a bond that was +never opened: bpf_master_redirect_enabled_key is a global static key, +so as soon as any bond device has native XDP attached, the +XDP_TX -> xdp_master_redirect() interception is enabled for every +slave system-wide. The path xdp_master_redirect() -> +bond_xdp_get_xmit_slave() -> bond_xdp_xmit_roundrobin_slave_get() -> +bond_rr_gen_slave_id() then runs against a bond that has no +rr_tx_counter and crashes. + +Fix this in the generic xdp_master_redirect() by refusing to call into +the master's ->ndo_xdp_get_xmit_slave() when the master device is not +up. IFF_UP is only set after ->ndo_open() has successfully returned, +so this reliably excludes masters whose XDP state has not been fully +initialized. Drop the frame with XDP_ABORTED so the exception is +visible via trace_xdp_exception() rather than silently falling through. +This is not specific to bonding: any current or future master that +defers XDP state allocation to ->ndo_open() is protected. + +Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave device") +Reported-by: syzbot+80e046b8da2820b6ba73@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/698f84c6.a70a0220.2c38d7.00cc.GAE@google.com/T/ +Suggested-by: Daniel Borkmann +Acked-by: Daniel Borkmann +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260411005524.201200-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 87aaab182e60d..87447a7843b5a 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4031,6 +4031,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) + struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); + + master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); ++ if (unlikely(!(master->flags & IFF_UP))) ++ return XDP_ABORTED; + slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); + if (slave && slave != xdp->rxq->dev) { + /* The target device is different from the receiving device, so +-- +2.53.0 + diff --git a/queue-5.15/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch b/queue-5.15/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch new file mode 100644 index 0000000000..4b0959db73 --- /dev/null +++ b/queue-5.15/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch @@ -0,0 +1,71 @@ +From ab94b27fbc192b4e24fdd20e90cb87641027f4de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:31:01 +0800 +Subject: net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf + +From: Mashiro Chen + +[ Upstream commit bf9a38803b2626b01cc769aaf13485d8650f576f ] + +sixpack_receive_buf() does not properly skip bytes with TTY error flags. +The while loop iterates through the flags buffer but never advances the +data pointer (cp), and passes the original count (including error bytes) +to sixpack_decode(). This causes sixpack_decode() to process bytes that +should have been skipped due to TTY errors. The TTY layer does not +guarantee that cp[i] holds a meaningful value when fp[i] is set, so +passing those positions to sixpack_decode() results in KMSAN reporting +an uninit-value read. + +Fix this by processing bytes one at a time, advancing cp on each +iteration, and only passing valid (non-error) bytes to sixpack_decode(). +This matches the pattern used by slip_receive_buf() and +mkiss_receive_buf() for the same purpose. + +Reported-by: syzbot+ecdb8c9878a81eb21e54@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ecdb8c9878a81eb21e54 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Mashiro Chen +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260407173101.107352-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 7ccf56a7f0e0c..b0935a895f333 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -430,7 +430,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, + const unsigned char *cp, const char *fp, int count) + { + struct sixpack *sp; +- size_t count1; + + if (!count) + return; +@@ -440,16 +439,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, + return; + + /* Read the characters out of the buffer */ +- count1 = count; +- while (count) { +- count--; ++ while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) + sp->dev->stats.rx_errors++; ++ cp++; + continue; + } ++ sixpack_decode(sp, cp, 1); ++ cp++; + } +- sixpack_decode(sp, cp, count1); + + sp_put(sp); + tty_unthrottle(tty); +-- +2.53.0 + diff --git a/queue-5.15/net-phy-dp83869-fix-setting-clk_o_sel-field.patch b/queue-5.15/net-phy-dp83869-fix-setting-clk_o_sel-field.patch new file mode 100644 index 0000000000..be5a702d9a --- /dev/null +++ b/queue-5.15/net-phy-dp83869-fix-setting-clk_o_sel-field.patch @@ -0,0 +1,64 @@ +From 0d1bf891bb6652b714e19e53bb67cd8a55e01819 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 05:13:39 +0200 +Subject: net: phy: dp83869: fix setting CLK_O_SEL field. + +From: Heiko Schocher + +[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ] + +Table 7-121 in datasheet says we have to set register 0xc6 +to value 0x10 before CLK_O_SEL can be modified. No more infos +about this field found in datasheet. With this fix, setting +of CLK_O_SEL field in IO_MUX_CFG register worked through dts +property "ti,clk-output-sel" on a DP83869HMRGZR. + +Signed-off-by: Heiko Schocher +Reviewed-by: Simon Horman +Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") +Link: https://patch.msgid.link/20260425031339.3318-1-hs@nabladev.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83869.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c +index a76fd5f11aca0..5eb07abf16479 100644 +--- a/drivers/net/phy/dp83869.c ++++ b/drivers/net/phy/dp83869.c +@@ -30,6 +30,7 @@ + #define DP83869_RGMIICTL 0x0032 + #define DP83869_STRAP_STS1 0x006e + #define DP83869_RGMIIDCTL 0x0086 ++#define DP83869_ANA_PLL_PROG_PI 0x00c6 + #define DP83869_RXFCFG 0x0134 + #define DP83869_RXFPMD1 0x0136 + #define DP83869_RXFPMD2 0x0137 +@@ -801,12 +802,22 @@ static int dp83869_config_init(struct phy_device *phydev) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ +- if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) ++ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { ++ /* ++ * Table 7-121 in datasheet says we have to set register 0xc6 ++ * to value 0x10 before CLK_O_SEL can be modified. ++ */ ++ ret = phy_write_mmd(phydev, DP83869_DEVADDR, ++ DP83869_ANA_PLL_PROG_PI, 0x10); ++ if (ret) ++ return ret; ++ + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); ++ } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, +-- +2.53.0 + diff --git a/queue-5.15/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch b/queue-5.15/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch new file mode 100644 index 0000000000..88d24804e4 --- /dev/null +++ b/queue-5.15/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch @@ -0,0 +1,67 @@ +From 4b7bd22b46b2cdb60e587e3cff63f0ba639e3915 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:10:20 +0200 +Subject: net: phy: qcom: at803x: Use the correct bit to disable extended next + page + +From: Maxime Chevallier + +[ Upstream commit e7a62edd34b1b4bc5f979988efc2f81c075733fd ] + +As noted in the blamed commit, the AR8035 and other PHYs from this +family advertise the Extended Next Page support by default, which may be +understood by some partners as this PHY being multi-gig capable. + +The fix is to disable XNP advertising, which is done by setting bit 12 +of the Auto-Negotiation Advertisement Register (MII_ADVERTISE). + +The blamed commit incorrectly uses MDIO_AN_CTRL1_XNP, which is bit 13 as per +802.3 : 45.2.7.1 AN control register (Register 7.0) + +BIT 12 in MII_ADVERTISE is wrapped by ADVERTISE_RESV, used by some +drivers such as the aquantia one. 802.3 Clause 28 defines bit 12 as +Extended Next Page ability, at least in recent versions of the standard. + +Let's add a define for it and use it in the at803x driver. + +Fixes: 3c51fa5d2afe ("net: phy: ar803x: disable extended next page bit") +Signed-off-by: Maxime Chevallier +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260410171021.1277138-1-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/at803x.c | 2 +- + include/uapi/linux/mii.h | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c +index ba61007bfc499..6397ef527945f 100644 +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -818,7 +818,7 @@ static int at803x_config_init(struct phy_device *phydev) + * behaviour but we still need to accommodate it. XNP is only needed + * for 10Gbps support, so disable XNP. + */ +- return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); ++ return phy_modify(phydev, MII_ADVERTISE, ADVERTISE_XNP, 0); + } + + static int at803x_ack_interrupt(struct phy_device *phydev) +diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h +index 39f7c44baf535..61d6edad4b94a 100644 +--- a/include/uapi/linux/mii.h ++++ b/include/uapi/linux/mii.h +@@ -82,7 +82,8 @@ + #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ + #define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ + #define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +-#define ADVERTISE_RESV 0x1000 /* Unused... */ ++#define ADVERTISE_XNP 0x1000 /* Extended Next Page */ ++#define ADVERTISE_RESV ADVERTISE_XNP /* Used to be reserved */ + #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ + #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ + #define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +-- +2.53.0 + diff --git a/queue-5.15/net-rds-optimize-rds_ib_laddr_check.patch b/queue-5.15/net-rds-optimize-rds_ib_laddr_check.patch new file mode 100644 index 0000000000..e843257c6b --- /dev/null +++ b/queue-5.15/net-rds-optimize-rds_ib_laddr_check.patch @@ -0,0 +1,189 @@ +From e0b8440ec53770ea78f684b3e31b2177cad49ddc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:19 -0700 +Subject: net/rds: Optimize rds_ib_laddr_check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 236f718ac885965fa886440b9898dfae185c9733 ] + +rds_ib_laddr_check() creates a CM_ID and attempts to bind the address +in question to it. This in order to qualify the allegedly local +address as a usable IB/RoCE address. + +In the field, ExaWatcher runs rds-ping to all ports in the fabric from +all local ports. This using all active ToS'es. In a full rack system, +we have 14 cell servers and eight db servers. Typically, 6 ToS'es are +used. This implies 528 rds-ping invocations per ExaWatcher's "RDSinfo" +interval. + +Adding to this, each rds-ping invocation creates eight sockets and +binds the local address to them: + +socket(AF_RDS, SOCK_SEQPACKET, 0) = 3 +bind(3, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 4 +bind(4, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 5 +bind(5, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 6 +bind(6, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 7 +bind(7, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 8 +bind(8, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 9 +bind(9, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 10 +bind(10, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 + +So, at every interval ExaWatcher executes rds-ping's, 4224 CM_IDs are +allocated, considering this full-rack system. After the a CM_ID has +been allocated, rdma_bind_addr() is called, with the port number being +zero. This implies that the CMA will attempt to search for an un-used +ephemeral port. Simplified, the algorithm is to start at a random +position in the available port space, and then if needed, iterate +until an un-used port is found. + +The book-keeping of used ports uses the idr system, which again uses +slab to allocate new struct idr_layer's. The size is 2092 bytes and +slab tries to reduce the wasted space. Hence, it chooses an order:3 +allocation, for which 15 idr_layer structs will fit and only 1388 +bytes are wasted per the 32KiB order:3 chunk. + +Although this order:3 allocation seems like a good space/speed +trade-off, it does not resonate well with how it used by the CMA. The +combination of the randomized starting point in the port space (which +has close to zero spatial locality) and the close proximity in time of +the 4224 invocations of the rds-ping's, creates a memory hog for +order:3 allocations. + +These costly allocations may need reclaims and/or compaction. At +worst, they may fail and produce a stack trace such as (from uek4): + +[] __inc_zone_page_state+0x35/0x40 +[] page_add_file_rmap+0x57/0x60 +[] remove_migration_pte+0x3f/0x3c0 [ksplice_6cn872bt_vmlinux_new] +[] rmap_walk+0xd8/0x340 +[] remove_migration_ptes+0x40/0x50 +[] migrate_pages+0x3ec/0x890 +[] compact_zone+0x32d/0x9a0 +[] compact_zone_order+0x6d/0x90 +[] try_to_compact_pages+0x102/0x270 +[] __alloc_pages_direct_compact+0x46/0x100 +[] __alloc_pages_nodemask+0x74b/0xaa0 +[] alloc_pages_current+0x91/0x110 +[] new_slab+0x38b/0x480 +[] __slab_alloc+0x3b7/0x4a0 [ksplice_s0dk66a8_vmlinux_new] +[] kmem_cache_alloc+0x1fb/0x250 +[] idr_layer_alloc+0x36/0x90 +[] idr_get_empty_slot+0x28c/0x3d0 +[] idr_alloc+0x4d/0xf0 +[] cma_alloc_port+0x4d/0xa0 [rdma_cm] +[] rdma_bind_addr+0x2ae/0x5b0 [rdma_cm] +[] rds_ib_laddr_check+0x83/0x2c0 [ksplice_6l2xst5i_rds_rdma_new] +[] rds_trans_get_preferred+0x5b/0xa0 [rds] +[] rds_bind+0x212/0x280 [rds] +[] SYSC_bind+0xe6/0x120 +[] SyS_bind+0xe/0x10 +[] system_call_fastpath+0x18/0xd4 + +To avoid these excessive calls to rdma_bind_addr(), we optimize +rds_ib_laddr_check() by simply checking if the address in question has +been used before. The rds_rdma module keeps track of addresses +associated with IB devices, and the function rds_ib_get_device() is +used to determine if the address already has been qualified as a valid +local address. If not found, we call the legacy rds_ib_laddr_check(), +now renamed to rds_ib_laddr_check_cm(). + +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Somasundaram Krishnasamy +Signed-off-by: Gerd Rausch +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-2-achender@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: ebf71dd4aff4 ("net/rds: Restrict use of RDS/IB to the initial network namespace") +Signed-off-by: Sasha Levin +--- + net/rds/ib.c | 20 ++++++++++++++++++-- + net/rds/ib.h | 1 + + net/rds/ib_rdma.c | 2 +- + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 24c9a9005a6fb..dbc63493ade70 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -403,8 +403,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len, + * allowed to influence which paths have priority. We could call userspace + * asserting this policy "routing". + */ +-static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, +- __u32 scope_id) ++static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) + { + int ret; + struct rdma_cm_id *cm_id; +@@ -489,6 +489,22 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + return ret; + } + ++static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) ++{ ++ struct rds_ib_device *rds_ibdev = NULL; ++ ++ if (ipv6_addr_v4mapped(addr)) { ++ rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); ++ if (rds_ibdev) { ++ rds_ib_dev_put(rds_ibdev); ++ return 0; ++ } ++ } ++ ++ return rds_ib_laddr_check_cm(net, addr, scope_id); ++} ++ + static void rds_ib_unregister_client(void) + { + ib_unregister_client(&rds_ib_client); +diff --git a/net/rds/ib.h b/net/rds/ib.h +index 2ba71102b1f1f..d6c1197731c1c 100644 +--- a/net/rds/ib.h ++++ b/net/rds/ib.h +@@ -384,6 +384,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, + __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) + + /* ib_rdma.c */ ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr); + int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, + struct in6_addr *ipaddr); + void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); +diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c +index 30fca2169aa7a..468fd60d818ff 100644 +--- a/net/rds/ib_rdma.c ++++ b/net/rds/ib_rdma.c +@@ -47,7 +47,7 @@ struct rds_ib_dereg_odp_mr { + + static void rds_ib_odp_mr_worker(struct work_struct *work); + +-static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) + { + struct rds_ib_device *rds_ibdev; + struct rds_ib_ipaddr *i_ipaddr; +-- +2.53.0 + diff --git a/queue-5.15/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch b/queue-5.15/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch new file mode 100644 index 0000000000..51d3d5de15 --- /dev/null +++ b/queue-5.15/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch @@ -0,0 +1,86 @@ +From 3efa3f16a53d9261e9219a137ef23d27ba3a5ef4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:20 -0700 +Subject: net/rds: Restrict use of RDS/IB to the initial network namespace + +From: Greg Jumper + +[ Upstream commit ebf71dd4aff46e8e421d455db3e231ba43d2fa8a ] + +Prevent using RDS/IB in network namespaces other than the initial one. +The existing RDS/IB code will not work properly in non-initial network +namespaces. + +Fixes: d5a8ac28a7ff ("RDS-TCP: Make RDS-TCP work correctly when it is set up in a netns other than init_net") +Reported-by: syzbot+da8e060735ae02c8f3d1@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=da8e060735ae02c8f3d1 +Signed-off-by: Greg Jumper +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-3-achender@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/af_rds.c | 10 ++++++++-- + net/rds/ib.c | 4 ++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c +index 0ec0ae1483492..ca1b52372ab29 100644 +--- a/net/rds/af_rds.c ++++ b/net/rds/af_rds.c +@@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen) + return ret; + } + +-static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) ++static int rds_set_transport(struct net *net, struct rds_sock *rs, ++ sockptr_t optval, int optlen) + { + int t_type; + +@@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) + if (t_type < 0 || t_type >= RDS_TRANS_COUNT) + return -EINVAL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + rs->rs_transport = rds_trans_get(t_type); + + return rs->rs_transport ? 0 : -ENOPROTOOPT; +@@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) + { + struct rds_sock *rs = rds_sk_to_rs(sock->sk); ++ struct net *net = sock_net(sock->sk); + int ret; + + if (level != SOL_RDS) { +@@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + break; + case SO_RDS_TRANSPORT: + lock_sock(sock->sk); +- ret = rds_set_transport(rs, optval, optlen); ++ ret = rds_set_transport(net, rs, optval, optlen); + release_sock(sock->sk); + break; + case SO_TIMESTAMP_OLD: +diff --git a/net/rds/ib.c b/net/rds/ib.c +index dbc63493ade70..ec45664f38767 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -494,6 +494,10 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + { + struct rds_ib_device *rds_ibdev = NULL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (!net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + if (ipv6_addr_v4mapped(addr)) { + rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); + if (rds_ibdev) { +-- +2.53.0 + diff --git a/queue-5.15/net-rds-zero-per-item-info-buffer-before-handing-it-.patch b/queue-5.15/net-rds-zero-per-item-info-buffer-before-handing-it-.patch new file mode 100644 index 0000000000..cb8c1946ab --- /dev/null +++ b/queue-5.15/net-rds-zero-per-item-info-buffer-before-handing-it-.patch @@ -0,0 +1,111 @@ +From 4c7fd2adb10f03da652465e842fb22e89c992f68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 10:10:47 -0400 +Subject: net/rds: zero per-item info buffer before handing it to visitors + +From: Michael Bommarito + +[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ] + +rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a +caller-allocated on-stack u64 buffer to a per-connection visitor and +then copy the full item_len bytes back to user space via +rds_info_copy() regardless of how much of the buffer the visitor +actually wrote. + +rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only +write a subset of their output struct when the underlying +rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl +and the two GIDs via explicit memsets). Several u32 fields +(max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, +cache_allocs) and the 2-byte alignment hole between sl and +cache_allocs remain as whatever stack contents preceded the visitor +call and are then memcpy_to_user()'d out to user space. + +struct rds_info_rdma_connection and struct rds6_info_rdma_connection +are the only rds_info_* structs in include/uapi/linux/rds.h that are +not marked __attribute__((packed)), so they have a real alignment +hole. The other info visitors (rds_conn_info_visitor, +rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of +their packed output struct today and are not known to be vulnerable, +but a future visitor that adds a conditional write-path would have +the same bug. + +Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y: +a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, +binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on +any netdev is sufficient), sendto()'s any peer on the same subnet +(fails cleanly but installs an rds_connection in the global hash in +RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, +RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 +bytes of stack garbage including kernel text/data pointers: + + 0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2 + 8..39 00 ... gids (memset-zeroed) + 40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr) + 48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max) + 56..59 01 00 08 00 rdma_mr_size (garbage) + 60..61 00 00 tos, sl + 62..63 00 00 alignment padding + 64..67 18 00 00 00 cache_allocs (garbage) + +Fix by zeroing the per-item buffer in both rds_for_each_conn_info() +and rds_walk_conn_path_info() before invoking the visitor. This +covers the IPv4/IPv6 IB visitors and hardens all current and future +visitors against the same class of bug. + +No functional change for visitors that fully populate their output. + +Changes in v2: +- retarget at the net tree (subject prefix "[PATCH net v2]", + net/rds: prefix in the title) +- pick up Reviewed-by tags from Sharath Srinivasan and + Allison Henderson + +Fixes: ec16227e1414 ("RDS/IB: Infiniband transport") +Signed-off-by: Michael Bommarito +Reviewed-by: Sharath Srinivasan +Reviewed-by: Allison Henderson +Assisted-by: Claude:claude-opus-4-7 +Link: https://patch.msgid.link/20260418141047.3398203-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/connection.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index 98c0d5ff9de9c..cd41f83863c89 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -673,6 +673,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, + i++, head++) { + hlist_for_each_entry_rcu(conn, head, c_hash_node) { + ++ /* Zero the per-item buffer before handing it to the ++ * visitor so any field the visitor does not write - ++ * including implicit alignment padding - cannot leak ++ * stack contents to user space via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no c_lock usage.. */ + if (!visitor(conn, buffer)) + continue; +@@ -722,6 +729,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, + */ + cp = conn->c_path; + ++ /* Zero the per-item buffer for the same reason as ++ * rds_for_each_conn_info(): any byte the visitor ++ * does not write (including alignment padding) must ++ * not leak stack contents via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no cp_lock usage.. */ + if (!visitor(cp, buffer)) + continue; +-- +2.53.0 + diff --git a/queue-5.15/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch b/queue-5.15/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch new file mode 100644 index 0000000000..4c762bb0e7 --- /dev/null +++ b/queue-5.15/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch @@ -0,0 +1,130 @@ +From ca947501755b9e841ebb96bafa6b94cc9294d845 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:16:27 -0400 +Subject: net/sched: act_ct: Only release RCU read lock after ct_ft + +From: Jamal Hadi Salim + +[ Upstream commit f462dca0c8415bf0058d0ffa476354c4476d0f09 ] + +When looking up a flow table in act_ct in tcf_ct_flow_table_get(), +rhashtable_lookup_fast() internally opens and closes an RCU read critical +section before returning ct_ft. +The tcf_ct_flow_table_cleanup_work() can complete before refcount_inc_not_zero() +is invoked on the returned ct_ft resulting in a UAF on the already freed ct_ft +object. This vulnerability can lead to privilege escalation. + +Analysis from zdi-disclosures@trendmicro.com: +When initializing act_ct, tcf_ct_init() is called, which internally triggers +tcf_ct_flow_table_get(). + +static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + +{ + struct zones_ht_key key = { .net = net, .zone = params->zone }; + struct tcf_ct_flow_table *ct_ft; + int err = -ENOMEM; + + mutex_lock(&zones_mutex); + ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); // [1] + if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) // [2] + goto out_unlock; + ... +} + +static __always_inline void *rhashtable_lookup_fast( + struct rhashtable *ht, const void *key, + const struct rhashtable_params params) +{ + void *obj; + + rcu_read_lock(); + obj = rhashtable_lookup(ht, key, params); + rcu_read_unlock(); + + return obj; +} + +At [1], rhashtable_lookup_fast() looks up and returns the corresponding ct_ft +from zones_ht . The lookup is performed within an RCU read critical section +through rcu_read_lock() / rcu_read_unlock(), which prevents the object from +being freed. However, at the point of function return, rcu_read_unlock() has +already been called, and there is nothing preventing ct_ft from being freed +before reaching refcount_inc_not_zero(&ct_ft->ref) at [2]. This interval becomes +the race window, during which ct_ft can be freed. + +Free Process: + +tcf_ct_flow_table_put() is executed through the path tcf_ct_cleanup() call_rcu() +tcf_ct_params_free_rcu() tcf_ct_params_free() tcf_ct_flow_table_put(). + +static void tcf_ct_flow_table_put(struct tcf_ct_flow_table *ct_ft) +{ + if (refcount_dec_and_test(&ct_ft->ref)) { + rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params); + INIT_RCU_WORK(&ct_ft->rwork, tcf_ct_flow_table_cleanup_work); // [3] + queue_rcu_work(act_ct_wq, &ct_ft->rwork); + } +} + +At [3], tcf_ct_flow_table_cleanup_work() is scheduled as RCU work + +static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) + +{ + struct tcf_ct_flow_table *ct_ft; + struct flow_block *block; + + ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, + rwork); + nf_flow_table_free(&ct_ft->nf_ft); + block = &ct_ft->nf_ft.flow_block; + down_write(&ct_ft->nf_ft.flow_block_lock); + WARN_ON(!list_empty(&block->cb_list)); + up_write(&ct_ft->nf_ft.flow_block_lock); + kfree(ct_ft); // [4] + + module_put(THIS_MODULE); +} + +tcf_ct_flow_table_cleanup_work() frees ct_ft at [4]. When this function executes +between [1] and [2], UAF occurs. + +This race condition has a very short race window, making it generally +difficult to trigger. Therefore, to trigger the vulnerability an msleep(100) was +inserted after[1] + +Fixes: 138470a9b2cc2 ("net/sched: act_ct: fix lockdep splat in tcf_ct_flow_table_get") +Reported-by: zdi-disclosures@trendmicro.com +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260410111627.46611-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/act_ct.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index 171ebf4594793..1639cc2869ef1 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -290,9 +290,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + int err = -ENOMEM; + + mutex_lock(&zones_mutex); +- ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); +- if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) ++ rcu_read_lock(); ++ ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params); ++ if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) { ++ rcu_read_unlock(); + goto out_unlock; ++ } ++ rcu_read_unlock(); + + ct_ft = kzalloc(sizeof(*ct_ft), GFP_KERNEL); + if (!ct_ft) +-- +2.53.0 + diff --git a/queue-5.15/net-sched-choke-remove-unused-variables-in-struct-ch.patch b/queue-5.15/net-sched-choke-remove-unused-variables-in-struct-ch.patch new file mode 100644 index 0000000000..40dbe19015 --- /dev/null +++ b/queue-5.15/net-sched-choke-remove-unused-variables-in-struct-ch.patch @@ -0,0 +1,42 @@ +From 293b0672c9931e49455541bba217e5611a9a8026 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Aug 2022 17:22:54 +0800 +Subject: net: sched: choke: remove unused variables in struct choke_sched_data + +From: Zhengchao Shao + +[ Upstream commit 38af11717b386560f10f2891350933fc5200aeea ] + +The variable "other" in the struct choke_sched_data is not used. Remove it. + +Signed-off-by: Zhengchao Shao +Signed-off-by: Jakub Kicinski +Stable-dep-of: d3aeb889dcbd ("net/sched: sch_choke: annotate data-races in choke_dump_stats()") +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index f3805bee995bb..e38cf34287018 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -60,7 +60,6 @@ struct choke_sched_data { + u32 forced_drop; /* Forced drops, qavg > max_thresh */ + u32 forced_mark; /* Forced marks, qavg > max_thresh */ + u32 pdrop; /* Drops due to queue limits */ +- u32 other; /* Drops due to drop() calls */ + u32 matched; /* Drops to flow match */ + } stats; + +@@ -464,7 +463,6 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + .early = q->stats.prob_drop + q->stats.forced_drop, + .marked = q->stats.prob_mark + q->stats.forced_mark, + .pdrop = q->stats.pdrop, +- .other = q->stats.other, + .matched = q->stats.matched, + }; + +-- +2.53.0 + diff --git a/queue-5.15/net-sched-gred-red-remove-unused-variables-in-struct.patch b/queue-5.15/net-sched-gred-red-remove-unused-variables-in-struct.patch new file mode 100644 index 0000000000..dd1c453d83 --- /dev/null +++ b/queue-5.15/net-sched-gred-red-remove-unused-variables-in-struct.patch @@ -0,0 +1,69 @@ +From b35e1c5fc73cf440e25d071e82cbcee15f0dbbda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Aug 2022 17:22:55 +0800 +Subject: net: sched: gred/red: remove unused variables in struct red_stats + +From: Zhengchao Shao + +[ Upstream commit 4516c873e3b55856012ddd6db9d4366ce3c60c5d ] + +The variable "other" in the struct red_stats is not used. Remove it. + +Signed-off-by: Zhengchao Shao +Signed-off-by: Jakub Kicinski +Stable-dep-of: a8f5192809ca ("net/sched: sch_red: annotate data-races in red_dump_stats()") +Signed-off-by: Sasha Levin +--- + include/net/red.h | 1 - + net/sched/sch_gred.c | 3 --- + net/sched/sch_red.c | 1 - + 3 files changed, 5 deletions(-) + +diff --git a/include/net/red.h b/include/net/red.h +index be11dbd264920..454ac2b65d8ca 100644 +--- a/include/net/red.h ++++ b/include/net/red.h +@@ -122,7 +122,6 @@ struct red_stats { + u32 forced_drop; /* Forced drops, qavg > max_thresh */ + u32 forced_mark; /* Forced marks, qavg > max_thresh */ + u32 pdrop; /* Drops due to queue limits */ +- u32 other; /* Drops due to drop() calls */ + }; + + struct red_parms { +diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c +index 621dc6afde8f3..8caf9623f855f 100644 +--- a/net/sched/sch_gred.c ++++ b/net/sched/sch_gred.c +@@ -817,7 +817,6 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) + opt.Wlog = q->parms.Wlog; + opt.Plog = q->parms.Plog; + opt.Scell_log = q->parms.Scell_log; +- opt.other = q->stats.other; + opt.early = q->stats.prob_drop; + opt.forced = q->stats.forced_drop; + opt.pdrop = q->stats.pdrop; +@@ -883,8 +882,6 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) + goto nla_put_failure; + if (nla_put_u32(skb, TCA_GRED_VQ_STAT_PDROP, q->stats.pdrop)) + goto nla_put_failure; +- if (nla_put_u32(skb, TCA_GRED_VQ_STAT_OTHER, q->stats.other)) +- goto nla_put_failure; + + nla_nest_end(skb, vq); + } +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index 063431a5ae1dd..a2c1db8ac3945 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -463,7 +463,6 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + } + st.early = q->stats.prob_drop + q->stats.forced_drop; + st.pdrop = q->stats.pdrop; +- st.other = q->stats.other; + st.marked = q->stats.prob_mark + q->stats.forced_mark; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-5.15/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch b/queue-5.15/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch new file mode 100644 index 0000000000..1b87c86eb1 --- /dev/null +++ b/queue-5.15/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch @@ -0,0 +1,67 @@ +From b4ed6a54e5461a9d99abdaf53e79a3469086d97d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:39 -0700 +Subject: net/sched: netem: fix probability gaps in 4-state loss model + +From: Stephen Hemminger + +[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ] + +The 4-state Markov chain in loss_4state() has gaps at the boundaries +between transition probability ranges. The comparisons use: + + if (rnd < a4) + else if (a4 < rnd && rnd < a1 + a4) + +When rnd equals a boundary value exactly, neither branch matches and +no state transition occurs. The redundant lower-bound check (a4 < rnd) +is already implied by being in the else branch. + +Remove the unnecessary lower-bound comparisons so the ranges are +contiguous and every random value produces a transition, matching +the GI (General and Intuitive) loss model specification. + +This bug goes back to original implementation of this model. + +Fixes: 661b79725fea ("netem: revised correlated loss generator") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-2-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index cbd7f3032fccf..1f47711cb1667 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -219,10 +219,10 @@ static bool loss_4state(struct netem_sched_data *q) + if (rnd < clg->a4) { + clg->state = LOST_IN_GAP_PERIOD; + return true; +- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { ++ } else if (rnd < clg->a1 + clg->a4) { + clg->state = LOST_IN_BURST_PERIOD; + return true; +- } else if (clg->a1 + clg->a4 < rnd) { ++ } else { + clg->state = TX_IN_GAP_PERIOD; + } + +@@ -239,9 +239,9 @@ static bool loss_4state(struct netem_sched_data *q) + case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; +- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { ++ else if (rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; +- } else if (clg->a2 + clg->a3 < rnd) { ++ } else { + clg->state = LOST_IN_BURST_PERIOD; + return true; + } +-- +2.53.0 + diff --git a/queue-5.15/net-sched-netem-fix-queue-limit-check-to-include-reo.patch b/queue-5.15/net-sched-netem-fix-queue-limit-check-to-include-reo.patch new file mode 100644 index 0000000000..b716121dcf --- /dev/null +++ b/queue-5.15/net-sched-netem-fix-queue-limit-check-to-include-reo.patch @@ -0,0 +1,42 @@ +From 6a8a2563b5dfe5904373f411c02dfdb523f47ca3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:40 -0700 +Subject: net/sched: netem: fix queue limit check to include reordered packets + +From: Stephen Hemminger + +[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ] + +The queue limit check in netem_enqueue() uses q->t_len which only +counts packets in the internal tfifo. Packets placed in sch->q by +the reorder path (__qdisc_enqueue_head) are not counted, allowing +the total queue occupancy to exceed sch->limit under reordering. + +Include sch->q.qlen in the limit check. + +Fixes: f8d4bc455047 ("net/sched: netem: account for backlog updates from child qdisc") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-3-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 1f47711cb1667..64542c9c15340 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -512,7 +512,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + 1<<(prandom_u32() % 8); + } + +- if (unlikely(q->t_len >= sch->limit)) { ++ if (unlikely(sch->q.qlen >= sch->limit)) { + /* re-link segs, so that qdisc_drop_all() frees them all */ + skb->next = segs; + qdisc_drop_all(skb, sch, to_free); +-- +2.53.0 + diff --git a/queue-5.15/net-sched-netem-validate-slot-configuration.patch b/queue-5.15/net-sched-netem-validate-slot-configuration.patch new file mode 100644 index 0000000000..dd94ad5518 --- /dev/null +++ b/queue-5.15/net-sched-netem-validate-slot-configuration.patch @@ -0,0 +1,86 @@ +From 4caa4c1117fe2cd13a5d21f89d48868b70327daf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:42 -0700 +Subject: net/sched: netem: validate slot configuration + +From: Stephen Hemminger + +[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ] + +Reject slot configurations that have no defensible meaning: + + - negative min_delay or max_delay + - min_delay greater than max_delay + - negative dist_delay or dist_jitter + - negative max_packets or max_bytes + +Negative or out-of-order delays underflow in get_slot_next(), +producing garbage intervals. Negative limits trip the per-slot +accounting (packets_left/bytes_left <= 0) on the first packet of +every slot, defeating the rate-limiting half of the slot feature. + +Note that dist_jitter has been silently coerced to its absolute +value by get_slot() since the feature was introduced; rejecting +negatives here converts that silent coercion into -EINVAL. The +abs() can be removed in a follow-up. + +Fixes: 836af83b54e3 ("netem: support delivering packets in delayed time slots") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 64542c9c15340..3e3bced82c564 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -815,6 +815,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) ++{ ++ const struct tc_netem_slot *c = nla_data(attr); ++ ++ if (c->min_delay < 0 || c->max_delay < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); ++ return -EINVAL; ++ } ++ if (c->min_delay > c->max_delay) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); ++ return -EINVAL; ++ } ++ if (c->dist_delay < 0 || c->dist_jitter < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); ++ return -EINVAL; ++ } ++ if (c->max_packets < 0 || c->max_bytes < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1030,6 +1053,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_SLOT]) { ++ ret = validate_slot(tb[TCA_NETEM_SLOT], extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch b/queue-5.15/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch new file mode 100644 index 0000000000..4991159280 --- /dev/null +++ b/queue-5.15/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch @@ -0,0 +1,62 @@ +From d4ba42a26557acdc5f32429432a00c77fc08e315 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:06 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (V) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations +for cparams.target and cparams.interval. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 87578d05a0925..46b93e30b60be 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -2313,10 +2313,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + + byte_target_ns = (byte_target * rate_ns) >> rate_shft; + +- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); +- b->cparams.interval = max(rtt_est_ns + +- b->cparams.target - target_ns, +- b->cparams.target * 2); ++ WRITE_ONCE(b->cparams.target, ++ max((byte_target_ns * 3) / 2, target_ns)); ++ WRITE_ONCE(b->cparams.interval, ++ max(rtt_est_ns + b->cparams.target - target_ns, ++ b->cparams.target * 2)); + b->cparams.mtu_time = byte_target_ns; + b->cparams.p_inc = 1 << 24; /* 1/256 */ + b->cparams.p_dec = 1 << 20; /* 1/4096 */ +@@ -2933,9 +2934,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); + + PUT_TSTAT_U32(TARGET_US, +- ktime_to_us(ns_to_ktime(b->cparams.target))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); + PUT_TSTAT_U32(INTERVAL_US, +- ktime_to_us(ns_to_ktime(b->cparams.interval))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); + + PUT_TSTAT_U32(SENT_PACKETS, b->packets); + PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch b/queue-5.15/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch new file mode 100644 index 0000000000..f0b07b0d19 --- /dev/null +++ b/queue-5.15/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch @@ -0,0 +1,64 @@ +From 1010e8265d8e7a2a62c981f3686ad4faf8677954 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:00:41 +0800 +Subject: net/sched: sch_cake: fix NAT destination port not being updated in + cake_update_flowkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit f9e40664706927d7ae22a448a3383e23c38a4c0b ] + +cake_update_flowkeys() is supposed to update the flow dissector keys +with the NAT-translated addresses and ports from conntrack, so that +CAKE's per-flow fairness correctly identifies post-NAT flows as +belonging to the same connection. + +For the source port, this works correctly: + keys->ports.src = port; + +But for the destination port, the assignment is reversed: + port = keys->ports.dst; + +This means the NAT destination port is never updated in the flow keys. +As a result, when multiple connections are NATed to the same destination, +CAKE treats them as separate flows because the original (pre-NAT) +destination ports differ. This breaks CAKE's NAT-aware flow isolation +when using the "nat" mode. + +The bug was introduced in commit b0c19ed6088a ("sch_cake: Take advantage +of skb->hash where appropriate") which refactored the original direct +assignment into a compare-and-conditionally-update pattern, but wrote +the destination port update backwards. + +Fix by reversing the assignment direction to match the source port +pattern. + +Fixes: b0c19ed6088a ("sch_cake: Take advantage of skb->hash where appropriate") +Signed-off-by: Dudu Lu +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260413110041.44704-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index cfeda7b50cc2e..87578d05a0925 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -619,7 +619,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys, + } + port = rev ? tuple.src.u.all : tuple.dst.u.all; + if (port != keys->ports.dst) { +- port = keys->ports.dst; ++ keys->ports.dst = port; + upd = true; + } + } +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch b/queue-5.15/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch new file mode 100644 index 0000000000..e4a2277806 --- /dev/null +++ b/queue-5.15/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch @@ -0,0 +1,97 @@ +From ddc1ed8115c1afd5b0b3fa1fe7f26c5768264d45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:28:39 +0000 +Subject: net/sched: sch_choke: annotate data-races in choke_dump_stats() + +From: Eric Dumazet + +[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ] + +choke_dump_stats() only runs with RTNL held. +It reads fields that can be changed in qdisc fast path. +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423062839.2524324-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index e38cf34287018..7283f96dead62 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + /* Draw a packet at random from queue and compare flow */ + if (choke_match_random(q, skb, &idx)) { +- q->stats.matched++; ++ WRITE_ONCE(q->stats.matched, q->stats.matched + 1); + choke_drop_by_idx(sch, idx, to_free); + goto congestion_drop; + } +@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + qdisc_qstats_overlimit(sch); + if (use_harddrop(q) || !use_ecn(q) || + !INET_ECN_set_ce(skb)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + } else if (++q->vars.qcount) { + if (red_mark_probability(p, &q->vars, q->vars.qavg)) { + q->vars.qcount = 0; +@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + qdisc_qstats_overlimit(sch); + if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + } + } else + q->vars.qR = red_random(p); +@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + } + +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); + return qdisc_drop(skb, sch, to_free); + + congestion_drop: +@@ -460,10 +464,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct choke_sched_data *q = qdisc_priv(sch); + struct tc_choke_xstats st = { +- .early = q->stats.prob_drop + q->stats.forced_drop, +- .marked = q->stats.prob_mark + q->stats.forced_mark, +- .pdrop = q->stats.pdrop, +- .matched = q->stats.matched, ++ .early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop), ++ .marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark), ++ .pdrop = READ_ONCE(q->stats.pdrop), ++ .matched = READ_ONCE(q->stats.matched), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch b/queue-5.15/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch new file mode 100644 index 0000000000..d002315791 --- /dev/null +++ b/queue-5.15/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch @@ -0,0 +1,47 @@ +From cb13e895bec2f9e09778b766e5fff4b736937bbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:25:09 +0000 +Subject: net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats() + +From: Eric Dumazet + +[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill st.qdisc_stats with live data. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142509.3967231-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_codel.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index e56f80b8fefe6..5e773e5993850 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -559,6 +559,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + }; + struct list_head *pos; + ++ sch_tree_lock(sch); ++ + st.qdisc_stats.maxpacket = q->cstats.maxpacket; + st.qdisc_stats.drop_overlimit = q->drop_overlimit; + st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; +@@ -567,7 +569,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + st.qdisc_stats.memory_usage = q->memory_usage; + st.qdisc_stats.drop_overmemory = q->drop_overmemory; + +- sch_tree_lock(sch); + list_for_each(pos, &q->new_flows) + st.qdisc_stats.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch b/queue-5.15/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch new file mode 100644 index 0000000000..e459171f69 --- /dev/null +++ b/queue-5.15/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch @@ -0,0 +1,62 @@ +From 0f65b070bc91e3e3596e4cfe8fa768a080e76efa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:35:27 +0000 +Subject: net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill tc_fq_pie_xstats with live data. + +Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, +but the spinlock is needed anyway to scan q->new_flows and q->old_flows. + +Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423063527.2568262-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_pie.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index 30259c8756451..910efc0630a14 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -499,18 +499,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb) + static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct fq_pie_sched_data *q = qdisc_priv(sch); +- struct tc_fq_pie_xstats st = { +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .overmemory = q->overmemory, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, +- .new_flow_count = q->new_flow_count, +- .memory_usage = q->memory_usage, +- }; ++ struct tc_fq_pie_xstats st = { 0 }; + struct list_head *pos; + + sch_tree_lock(sch); ++ ++ st.packets_in = q->stats.packets_in; ++ st.overlimit = q->stats.overlimit; ++ st.overmemory = q->overmemory; ++ st.dropped = q->stats.dropped; ++ st.ecn_mark = q->stats.ecn_mark; ++ st.new_flow_count = q->new_flow_count; ++ st.memory_usage = q->memory_usage; ++ + list_for_each(pos, &q->new_flows) + st.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_netem-refactor-code-in-4-state-loss-ge.patch b/queue-5.15/net-sched-sch_netem-refactor-code-in-4-state-loss-ge.patch new file mode 100644 index 0000000000..aeac006131 --- /dev/null +++ b/queue-5.15/net-sched-sch_netem-refactor-code-in-4-state-loss-ge.patch @@ -0,0 +1,89 @@ +From 73e00739a8072e75d287184bc831f30c8f89ec78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Nov 2021 13:36:47 -0800 +Subject: net: sched: sch_netem: Refactor code in 4-state loss generator + +From: Harshit Mogalapalli + +[ Upstream commit cb3ef7b00042479277cda7871d899378ad91f081 ] + +Fixed comments to match description with variable names and +refactored code to match the convention as per [1]. + +To match the convention mapping is done as follows: +State 3 - LOST_IN_BURST_PERIOD +State 4 - LOST_IN_GAP_PERIOD + +[1] S. Salsano, F. Ludovici, A. Ordine, "Definition of a general +and intuitive loss model for packet networks and its implementation +in the Netem module in the Linux kernel" + +Fixes: a6e2fe17eba4 ("sch_netem: replace magic numbers with enumerate") +Signed-off-by: Harshit Mogalapalli +Acked-by: Stephen Hemminger +Signed-off-by: David S. Miller +Stable-dep-of: 732b463449fd ("net/sched: netem: fix probability gaps in 4-state loss model") +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 951156d7e5485..cbd7f3032fccf 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -210,17 +210,17 @@ static bool loss_4state(struct netem_sched_data *q) + * next state and if the next packet has to be transmitted or lost. + * The four states correspond to: + * TX_IN_GAP_PERIOD => successfully transmitted packets within a gap period +- * LOST_IN_BURST_PERIOD => isolated losses within a gap period +- * LOST_IN_GAP_PERIOD => lost packets within a burst period +- * TX_IN_GAP_PERIOD => successfully transmitted packets within a burst period ++ * LOST_IN_GAP_PERIOD => isolated losses within a gap period ++ * LOST_IN_BURST_PERIOD => lost packets within a burst period ++ * TX_IN_BURST_PERIOD => successfully transmitted packets within a burst period + */ + switch (clg->state) { + case TX_IN_GAP_PERIOD: + if (rnd < clg->a4) { +- clg->state = LOST_IN_BURST_PERIOD; ++ clg->state = LOST_IN_GAP_PERIOD; + return true; + } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { +- clg->state = LOST_IN_GAP_PERIOD; ++ clg->state = LOST_IN_BURST_PERIOD; + return true; + } else if (clg->a1 + clg->a4 < rnd) { + clg->state = TX_IN_GAP_PERIOD; +@@ -229,24 +229,24 @@ static bool loss_4state(struct netem_sched_data *q) + break; + case TX_IN_BURST_PERIOD: + if (rnd < clg->a5) { +- clg->state = LOST_IN_GAP_PERIOD; ++ clg->state = LOST_IN_BURST_PERIOD; + return true; + } else { + clg->state = TX_IN_BURST_PERIOD; + } + + break; +- case LOST_IN_GAP_PERIOD: ++ case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; + else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; + } else if (clg->a2 + clg->a3 < rnd) { +- clg->state = LOST_IN_GAP_PERIOD; ++ clg->state = LOST_IN_BURST_PERIOD; + return true; + } + break; +- case LOST_IN_BURST_PERIOD: ++ case LOST_IN_GAP_PERIOD: + clg->state = TX_IN_GAP_PERIOD; + break; + } +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch b/queue-5.15/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch new file mode 100644 index 0000000000..434cb62d33 --- /dev/null +++ b/queue-5.15/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch @@ -0,0 +1,160 @@ +From 4a0cf42984ef301d6c71b291634319ba560ff830 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:29:44 +0000 +Subject: net/sched: sch_pie: annotate data-races in pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ] + +pie_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_pie_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142944.4009941-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/pie.h | 2 +- + net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/include/net/pie.h b/include/net/pie.h +index 3fe2361e03b46..f6fd51e2b7daa 100644 +--- a/include/net/pie.h ++++ b/include/net/pie.h +@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) + vars->dq_tstamp = DTIME_INVALID; + vars->accu_prob = 0; + vars->dq_count = DQCOUNT_INVALID; +- vars->avg_dq_rate = 0; ++ WRITE_ONCE(vars->avg_dq_rate, 0); + } + + static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb) +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index 67ce65af52b5c..1e4c84535c0e3 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -89,7 +89,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + bool enqueue = false; + + if (unlikely(qdisc_qlen(sch) >= sch->limit)) { +- q->stats.overlimit++; ++ WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1); + goto out; + } + +@@ -101,7 +101,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + /* If packet is ecn capable, mark it if drop probability + * is lower than 10%, else drop it. + */ +- q->stats.ecn_mark++; ++ WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1); + enqueue = true; + } + +@@ -111,15 +111,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + if (!q->params.dq_rate_estimator) + pie_set_enqueue_time(skb); + +- q->stats.packets_in++; ++ WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1); + if (qdisc_qlen(sch) > q->stats.maxq) +- q->stats.maxq = qdisc_qlen(sch); ++ WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch)); + + return qdisc_enqueue_tail(skb, sch); + } + + out: +- q->stats.dropped++; ++ WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1); + q->vars.accu_prob = 0; + return qdisc_drop(skb, sch, to_free); + } +@@ -263,11 +263,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, + count = count / dtime; + + if (vars->avg_dq_rate == 0) +- vars->avg_dq_rate = count; ++ WRITE_ONCE(vars->avg_dq_rate, count); + else +- vars->avg_dq_rate = ++ WRITE_ONCE(vars->avg_dq_rate, + (vars->avg_dq_rate - +- (vars->avg_dq_rate >> 3)) + (count >> 3); ++ (vars->avg_dq_rate >> 3)) + (count >> 3)); + + /* If the queue has receded below the threshold, we hold + * on to the last drain rate calculated, else we reset +@@ -377,7 +377,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + if (delta > 0) { + /* prevent overflow */ + if (vars->prob < oldprob) { +- vars->prob = MAX_PROB; ++ WRITE_ONCE(vars->prob, MAX_PROB); + /* Prevent normalization error. If probability is at + * maximum value already, we normalize it here, and + * skip the check to do a non-linear drop in the next +@@ -388,7 +388,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + } else { + /* prevent underflow */ + if (vars->prob > oldprob) +- vars->prob = 0; ++ WRITE_ONCE(vars->prob, 0); + } + + /* Non-linear drop in probability: Reduce drop probability quickly if +@@ -399,7 +399,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + /* Reduce drop probability to 98.4% */ + vars->prob -= vars->prob / 64; + +- vars->qdelay = qdelay; ++ WRITE_ONCE(vars->qdelay, qdelay); + vars->backlog_old = backlog; + + /* We restart the measurement cycle if the following conditions are met +@@ -494,21 +494,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + struct pie_sched_data *q = qdisc_priv(sch); + struct tc_pie_xstats st = { + .prob = q->vars.prob << BITS_PER_BYTE, +- .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / ++ .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) / + NSEC_PER_USEC, +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .maxq = q->stats.maxq, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, ++ .packets_in = READ_ONCE(q->stats.packets_in), ++ .overlimit = READ_ONCE(q->stats.overlimit), ++ .maxq = READ_ONCE(q->stats.maxq), ++ .dropped = READ_ONCE(q->stats.dropped), ++ .ecn_mark = READ_ONCE(q->stats.ecn_mark), + }; + + /* avg_dq_rate is only valid if dq_rate_estimator is enabled */ + st.dq_rate_estimating = q->params.dq_rate_estimator; + + /* unscale and return dq_rate in bytes per sec */ +- if (q->params.dq_rate_estimator) +- st.avg_dq_rate = q->vars.avg_dq_rate * ++ if (st.dq_rate_estimating) ++ st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) * + (PSCHED_TICKS_PER_SEC) >> PIE_SCALE; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch b/queue-5.15/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch new file mode 100644 index 0000000000..7d18ac3389 --- /dev/null +++ b/queue-5.15/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch @@ -0,0 +1,112 @@ +From 84a8ded2c5372c3466355c925dbda0a35006925b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:23:09 +0000 +Subject: net/sched: sch_red: annotate data-races in red_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ] + +red_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_red_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142309.3964322-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_red.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index a2c1db8ac3945..779f8779c762a 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -89,17 +89,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_PROB_MARK: + qdisc_qstats_overlimit(sch); + if (!red_use_ecn(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +@@ -109,17 +112,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_HARD_MARK: + qdisc_qstats_overlimit(sch); + if (red_use_harddrop(q) || !red_use_ecn(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +@@ -133,7 +139,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->qstats.backlog += len; + sch->q.qlen++; + } else if (net_xmit_drop_count(ret)) { +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, ++ q->stats.pdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -461,9 +468,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, + &hw_stats_request); + } +- st.early = q->stats.prob_drop + q->stats.forced_drop; +- st.pdrop = q->stats.pdrop; +- st.marked = q->stats.prob_mark + q->stats.forced_mark; ++ st.early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop); ++ ++ st.pdrop = READ_ONCE(q->stats.pdrop); ++ ++ st.marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark); + + return gnet_stats_copy_app(d, &st, sizeof(st)); + } +-- +2.53.0 + diff --git a/queue-5.15/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch b/queue-5.15/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch new file mode 100644 index 0000000000..b4f485513b --- /dev/null +++ b/queue-5.15/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch @@ -0,0 +1,169 @@ +From 69deb23c869abdf9024e8cdd3f32c532790524b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:16:55 +0000 +Subject: net/sched: sch_sfb: annotate data-races in sfb_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ] + +sfb_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_sfb_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260421141655.3953721-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 22 deletions(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index 0490eb5b98dee..497bc022fc0c1 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen < 0xFFFF) +- b[hash].qlen++; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen > 0) +- b[hash].qlen--; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) + + static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_minus(b->p_mark, q->decrement); ++ WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement)); + } + + static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_plus(b->p_mark, q->increment); ++ WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment)); + } + + static void sfb_zero_all_buckets(struct sfb_sched_data *q) +@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da + const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0]; + + for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) { +- if (qlen < b->qlen) +- qlen = b->qlen; +- totalpm += b->p_mark; +- if (prob < b->p_mark) +- prob = b->p_mark; ++ u32 b_qlen = READ_ONCE(b->qlen); ++ u32 b_mark = READ_ONCE(b->p_mark); ++ ++ if (qlen < b_qlen) ++ qlen = b_qlen; ++ totalpm += b_mark; ++ if (prob < b_mark) ++ prob = b_mark; + b++; + } + *prob_r = prob; +@@ -294,7 +297,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(sch->q.qlen >= q->limit)) { + qdisc_qstats_overlimit(sch); +- q->stats.queuedrop++; ++ WRITE_ONCE(q->stats.queuedrop, ++ q->stats.queuedrop + 1); + goto drop; + } + +@@ -347,7 +351,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(minqlen >= q->max)) { + qdisc_qstats_overlimit(sch); +- q->stats.bucketdrop++; ++ WRITE_ONCE(q->stats.bucketdrop, ++ q->stats.bucketdrop + 1); + goto drop; + } + +@@ -373,7 +378,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + if (sfb_rate_limit(skb, q)) { + qdisc_qstats_overlimit(sch); +- q->stats.penaltydrop++; ++ WRITE_ONCE(q->stats.penaltydrop, ++ q->stats.penaltydrop + 1); + goto drop; + } + goto enqueue; +@@ -388,14 +394,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + * In either case, we want to start dropping packets. + */ + if (r < (p_min - SFB_MAX_PROB / 2) * 2) { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } + if (INET_ECN_set_ce(skb)) { +- q->stats.marked++; ++ WRITE_ONCE(q->stats.marked, ++ q->stats.marked + 1); + } else { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } +@@ -408,7 +417,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->q.qlen++; + increment_qlen(&cb, q); + } else if (net_xmit_drop_count(ret)) { +- q->stats.childdrop++; ++ WRITE_ONCE(q->stats.childdrop, ++ q->stats.childdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -597,12 +607,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct sfb_sched_data *q = qdisc_priv(sch); + struct tc_sfb_xstats st = { +- .earlydrop = q->stats.earlydrop, +- .penaltydrop = q->stats.penaltydrop, +- .bucketdrop = q->stats.bucketdrop, +- .queuedrop = q->stats.queuedrop, +- .childdrop = q->stats.childdrop, +- .marked = q->stats.marked, ++ .earlydrop = READ_ONCE(q->stats.earlydrop), ++ .penaltydrop = READ_ONCE(q->stats.penaltydrop), ++ .bucketdrop = READ_ONCE(q->stats.bucketdrop), ++ .queuedrop = READ_ONCE(q->stats.queuedrop), ++ .childdrop = READ_ONCE(q->stats.childdrop), ++ .marked = READ_ONCE(q->stats.marked), + }; + + st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q); +-- +2.53.0 + diff --git a/queue-5.15/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch b/queue-5.15/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch new file mode 100644 index 0000000000..71c3ae0c2c --- /dev/null +++ b/queue-5.15/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch @@ -0,0 +1,47 @@ +From 73fe383dfe5465e40c6e1084b9493609831f5c50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:27 +0200 +Subject: net/sched: taprio: continue with other TXQs if one dequeue() failed + +From: Vladimir Oltean + +[ Upstream commit 1638bbbe4ececa615b273497d347d59ad71060a2 ] + +This changes the handling of an unlikely condition to not stop dequeuing +if taprio failed to dequeue the peeked skb in taprio_dequeue(). + +I've no idea when this can happen, but the only side effect seems to be +that the atomic_sub_return() call right above will have consumed some +budget. This isn't a big deal, since either that made us remain without +any budget (and therefore, we'd exit on the next peeked skb anyway), or +we could send some packets from other TXQs. + +I'm making this change because in a future patch I'll be refactoring the +dequeue procedure to simplify it, and this corner case will have to go +away. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 8924b439c459d..0a4501854e4b2 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -616,7 +616,7 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + + skb = child->ops->dequeue(child); + if (unlikely(!skb)) +- goto done; ++ continue; + + skb_found: + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-5.15/net-sched-taprio-fix-use-after-free-in-advance_sched.patch b/queue-5.15/net-sched-taprio-fix-use-after-free-in-advance_sched.patch new file mode 100644 index 0000000000..52f66e0828 --- /dev/null +++ b/queue-5.15/net-sched-taprio-fix-use-after-free-in-advance_sched.patch @@ -0,0 +1,60 @@ +From 6bc48447d10e60aeb4131d86e6b2a0ed7168fb09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 18:57:57 -0700 +Subject: net/sched: taprio: fix use-after-free in advance_sched() on schedule + switch + +From: Vinicius Costa Gomes + +[ Upstream commit 105425b1969c5affe532713cfac1c0b320d7ac2b ] + +In advance_sched(), when should_change_schedules() returns true, +switch_schedules() is called to promote the admin schedule to oper. +switch_schedules() queues the old oper schedule for RCU freeing via +call_rcu(), but 'next' still points into an entry of the old oper +schedule. The subsequent 'next->end_time = end_time' and +rcu_assign_pointer(q->current_entry, next) are use-after-free. + +Fix this by selecting 'next' from the new oper schedule immediately +after switch_schedules(), and using its pre-calculated end_time. +setup_first_end_time() sets the first entry's end_time to +base_time + interval when the schedule is installed, so the value +is already correct. + +The deleted 'end_time = sched_base_time(admin)' assignment was also +harmful independently: it would overwrite the new first entry's +pre-calculated end_time with just base_time. + +Fixes: a3d43c0d56f1 ("taprio: Add support adding an admin schedule") +Reported-by: Junxi Qian +Signed-off-by: Vinicius Costa Gomes +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 189101dfbaae9..8e7c0a3034cc4 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -729,11 +729,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + end_time = min_t(ktime_t, end_time, oper->cycle_end_time); + + if (should_change_schedules(admin, oper, end_time)) { +- /* Set things so the next time this runs, the new +- * schedule runs. +- */ +- end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); ++ /* After changing schedules, the next entry is the first one ++ * in the new schedule, with a pre-calculated end_time. ++ */ ++ next = list_first_entry(&oper->entries, struct sched_entry, list); ++ end_time = next->end_time; + } + + next->end_time = end_time; +-- +2.53.0 + diff --git a/queue-5.15/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch b/queue-5.15/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch new file mode 100644 index 0000000000..eb1e9bbd84 --- /dev/null +++ b/queue-5.15/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch @@ -0,0 +1,168 @@ +From a86a33e8df328accaa1890a5618080ab1ad68927 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:28 +0200 +Subject: net/sched: taprio: refactor one skb dequeue from TXQ to separate + function + +From: Vladimir Oltean + +[ Upstream commit 92f966674f6a257eddfa60a85f9b6741d6087ccb ] + +Future changes will refactor the TXQ selection procedure, and a lot of +stuff will become messy, the indentation of the bulk of the dequeue +procedure would increase, etc. + +Break out the bulk of the function into a new one, which knows the TXQ +(child qdisc) we should perform a dequeue from. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 121 +++++++++++++++++++++-------------------- + 1 file changed, 63 insertions(+), 58 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 0a4501854e4b2..185f0bd7ed407 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -541,6 +541,66 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + atomic64_read(&q->picos_per_byte))); + } + ++static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, ++ struct sched_entry *entry, ++ u32 gate_mask) ++{ ++ struct taprio_sched *q = qdisc_priv(sch); ++ struct net_device *dev = qdisc_dev(sch); ++ struct Qdisc *child = q->qdiscs[txq]; ++ struct sk_buff *skb; ++ ktime_t guard; ++ int prio; ++ int len; ++ u8 tc; ++ ++ if (unlikely(!child)) ++ return NULL; ++ ++ if (TXTIME_ASSIST_IS_ENABLED(q->flags)) { ++ skb = child->ops->dequeue(child); ++ if (!skb) ++ return NULL; ++ goto skb_found; ++ } ++ ++ skb = child->ops->peek(child); ++ if (!skb) ++ return NULL; ++ ++ prio = skb->priority; ++ tc = netdev_get_prio_tc_map(dev, prio); ++ ++ if (!(gate_mask & BIT(tc))) ++ return NULL; ++ ++ len = qdisc_pkt_len(skb); ++ guard = ktime_add_ns(taprio_get_time(q), length_to_duration(q, len)); ++ ++ /* In the case that there's no gate entry, there's no ++ * guard band ... ++ */ ++ if (gate_mask != TAPRIO_ALL_GATES_OPEN && ++ ktime_after(guard, entry->close_time)) ++ return NULL; ++ ++ /* ... and no budget. */ ++ if (gate_mask != TAPRIO_ALL_GATES_OPEN && ++ atomic_sub_return(len, &entry->budget) < 0) ++ return NULL; ++ ++ skb = child->ops->dequeue(child); ++ if (unlikely(!skb)) ++ return NULL; ++ ++skb_found: ++ qdisc_bstats_update(sch, skb); ++ qdisc_qstats_backlog_dec(sch, skb); ++ sch->q.qlen--; ++ ++ return skb; ++} ++ + /* Will not be called in the full offload case, since the TX queues are + * attached to the Qdisc created using qdisc_create_dflt() + */ +@@ -566,64 +626,9 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + goto done; + + for (i = 0; i < dev->num_tx_queues; i++) { +- struct Qdisc *child = q->qdiscs[i]; +- ktime_t guard; +- int prio; +- int len; +- u8 tc; +- +- if (unlikely(!child)) +- continue; +- +- if (TXTIME_ASSIST_IS_ENABLED(q->flags)) { +- skb = child->ops->dequeue(child); +- if (!skb) +- continue; +- goto skb_found; +- } +- +- skb = child->ops->peek(child); +- if (!skb) +- continue; +- +- prio = skb->priority; +- tc = netdev_get_prio_tc_map(dev, prio); +- +- if (!(gate_mask & BIT(tc))) { +- skb = NULL; +- continue; +- } +- +- len = qdisc_pkt_len(skb); +- guard = ktime_add_ns(taprio_get_time(q), +- length_to_duration(q, len)); +- +- /* In the case that there's no gate entry, there's no +- * guard band ... +- */ +- if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- ktime_after(guard, entry->close_time)) { +- skb = NULL; +- continue; +- } +- +- /* ... and no budget. */ +- if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- atomic_sub_return(len, &entry->budget) < 0) { +- skb = NULL; +- continue; +- } +- +- skb = child->ops->dequeue(child); +- if (unlikely(!skb)) +- continue; +- +-skb_found: +- qdisc_bstats_update(sch, skb); +- qdisc_qstats_backlog_dec(sch, skb); +- sch->q.qlen--; +- +- goto done; ++ skb = taprio_dequeue_from_txq(sch, i, entry, gate_mask); ++ if (skb) ++ goto done; + } + + done: +-- +2.53.0 + diff --git a/queue-5.15/net-sched-taprio-rename-close_time-to-end_time.patch b/queue-5.15/net-sched-taprio-rename-close_time-to-end_time.patch new file mode 100644 index 0000000000..9b87afd224 --- /dev/null +++ b/queue-5.15/net-sched-taprio-rename-close_time-to-end_time.patch @@ -0,0 +1,205 @@ +From 384f7243232e684ec9f3c04a06da79c325527493 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:32 +0200 +Subject: net/sched: taprio: rename close_time to end_time + +From: Vladimir Oltean + +[ Upstream commit e5517551112ff2395611e552443932152f83672d ] + +There is a confusion in terms in taprio which makes what is called +"close_time" to be actually used for 2 things: + +1. determining when an entry "closes" such that transmitted skbs are + never allowed to overrun that time (?!) +2. an aid for determining when to advance and/or restart the schedule + using the hrtimer + +It makes more sense to call this so-called "close_time" "end_time", +because it's not clear at all to me what "closes". Future patches will +hopefully make better use of the term "to close". + +This is an absolutely mechanical change. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 52 +++++++++++++++++++++--------------------- + 1 file changed, 26 insertions(+), 26 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 185f0bd7ed407..189101dfbaae9 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -37,11 +37,11 @@ static DEFINE_SPINLOCK(taprio_list_lock); + struct sched_entry { + struct list_head list; + +- /* The instant that this entry "closes" and the next one ++ /* The instant that this entry ends and the next one + * should open, the qdisc will make some effort so that no + * packet leaves after this time. + */ +- ktime_t close_time; ++ ktime_t end_time; + ktime_t next_txtime; + atomic_t budget; + int index; +@@ -54,7 +54,7 @@ struct sched_gate_list { + struct rcu_head rcu; + struct list_head entries; + size_t num_entries; +- ktime_t cycle_close_time; ++ ktime_t cycle_end_time; + s64 cycle_time; + s64 cycle_time_extension; + s64 base_time; +@@ -581,7 +581,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, + * guard band ... + */ + if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- ktime_after(guard, entry->close_time)) ++ ktime_after(guard, entry->end_time)) + return NULL; + + /* ... and no budget. */ +@@ -643,7 +643,7 @@ static bool should_restart_cycle(const struct sched_gate_list *oper, + if (list_is_last(&entry->list, &oper->entries)) + return true; + +- if (ktime_compare(entry->close_time, oper->cycle_close_time) == 0) ++ if (ktime_compare(entry->end_time, oper->cycle_end_time) == 0) + return true; + + return false; +@@ -651,7 +651,7 @@ static bool should_restart_cycle(const struct sched_gate_list *oper, + + static bool should_change_schedules(const struct sched_gate_list *admin, + const struct sched_gate_list *oper, +- ktime_t close_time) ++ ktime_t end_time) + { + ktime_t next_base_time, extension_time; + +@@ -660,18 +660,18 @@ static bool should_change_schedules(const struct sched_gate_list *admin, + + next_base_time = sched_base_time(admin); + +- /* This is the simple case, the close_time would fall after ++ /* This is the simple case, the end_time would fall after + * the next schedule base_time. + */ +- if (ktime_compare(next_base_time, close_time) <= 0) ++ if (ktime_compare(next_base_time, end_time) <= 0) + return true; + +- /* This is the cycle_time_extension case, if the close_time ++ /* This is the cycle_time_extension case, if the end_time + * plus the amount that can be extended would fall after the + * next schedule base_time, we can extend the current schedule + * for that amount. + */ +- extension_time = ktime_add_ns(close_time, oper->cycle_time_extension); ++ extension_time = ktime_add_ns(end_time, oper->cycle_time_extension); + + /* FIXME: the IEEE 802.1Q-2018 Specification isn't clear about + * how precisely the extension should be made. So after +@@ -690,7 +690,7 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + struct sched_gate_list *oper, *admin; + struct sched_entry *entry, *next; + struct Qdisc *sch = q->root; +- ktime_t close_time; ++ ktime_t end_time; + + spin_lock(&q->current_entry_lock); + entry = rcu_dereference_protected(q->current_entry, +@@ -709,41 +709,41 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + * entry of all schedules are pre-calculated during the + * schedule initialization. + */ +- if (unlikely(!entry || entry->close_time == oper->base_time)) { ++ if (unlikely(!entry || entry->end_time == oper->base_time)) { + next = list_first_entry(&oper->entries, struct sched_entry, + list); +- close_time = next->close_time; ++ end_time = next->end_time; + goto first_run; + } + + if (should_restart_cycle(oper, entry)) { + next = list_first_entry(&oper->entries, struct sched_entry, + list); +- oper->cycle_close_time = ktime_add_ns(oper->cycle_close_time, +- oper->cycle_time); ++ oper->cycle_end_time = ktime_add_ns(oper->cycle_end_time, ++ oper->cycle_time); + } else { + next = list_next_entry(entry, list); + } + +- close_time = ktime_add_ns(entry->close_time, next->interval); +- close_time = min_t(ktime_t, close_time, oper->cycle_close_time); ++ end_time = ktime_add_ns(entry->end_time, next->interval); ++ end_time = min_t(ktime_t, end_time, oper->cycle_end_time); + +- if (should_change_schedules(admin, oper, close_time)) { ++ if (should_change_schedules(admin, oper, end_time)) { + /* Set things so the next time this runs, the new + * schedule runs. + */ +- close_time = sched_base_time(admin); ++ end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); + } + +- next->close_time = close_time; ++ next->end_time = end_time; + taprio_set_budget(q, next); + + first_run: + rcu_assign_pointer(q->current_entry, next); + spin_unlock(&q->current_entry_lock); + +- hrtimer_set_expires(&q->advance_timer, close_time); ++ hrtimer_set_expires(&q->advance_timer, end_time); + + rcu_read_lock(); + __netif_schedule(sch); +@@ -1016,8 +1016,8 @@ static int taprio_get_start_time(struct Qdisc *sch, + return 0; + } + +-static void setup_first_close_time(struct taprio_sched *q, +- struct sched_gate_list *sched, ktime_t base) ++static void setup_first_end_time(struct taprio_sched *q, ++ struct sched_gate_list *sched, ktime_t base) + { + struct sched_entry *first; + ktime_t cycle; +@@ -1028,9 +1028,9 @@ static void setup_first_close_time(struct taprio_sched *q, + cycle = sched->cycle_time; + + /* FIXME: find a better place to do this */ +- sched->cycle_close_time = ktime_add_ns(base, cycle); ++ sched->cycle_end_time = ktime_add_ns(base, cycle); + +- first->close_time = ktime_add_ns(base, first->interval); ++ first->end_time = ktime_add_ns(base, first->interval); + taprio_set_budget(q, first); + rcu_assign_pointer(q->current_entry, NULL); + } +@@ -1573,7 +1573,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, + if (admin) + call_rcu(&admin->rcu, taprio_free_sched_cb); + } else { +- setup_first_close_time(q, new_admin, start); ++ setup_first_end_time(q, new_admin, start); + + /* Protects against advance_sched() */ + spin_lock_irqsave(&q->current_entry_lock, flags); +-- +2.53.0 + diff --git a/queue-5.15/net-sched-taprio-replace-safety-precautions-with-com.patch b/queue-5.15/net-sched-taprio-replace-safety-precautions-with-com.patch new file mode 100644 index 0000000000..65c540fb6b --- /dev/null +++ b/queue-5.15/net-sched-taprio-replace-safety-precautions-with-com.patch @@ -0,0 +1,96 @@ +From 94280aa762b8e3e755e95923c9b6eff96ed5d432 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Sep 2022 13:50:46 +0300 +Subject: net/sched: taprio: replace safety precautions with comments + +From: Vladimir Oltean + +[ Upstream commit 2c08a4f898d0a8e08f431709a1ae728a6fddaabd ] + +The WARN_ON_ONCE() checks introduced in commit 13511704f8d7 ("net: +taprio offload: enforce qdisc to netdev queue mapping") take a small +toll on performance, but otherwise, the conditions are never expected to +happen. Replace them with comments, such that the information is still +conveyed to developers. + +Signed-off-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 9c86c8ade4853..8924b439c459d 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -432,6 +432,9 @@ static int taprio_enqueue_one(struct sk_buff *skb, struct Qdisc *sch, + return qdisc_enqueue(skb, child, to_free); + } + ++/* Will not be called in the full offload case, since the TX queues are ++ * attached to the Qdisc created using qdisc_create_dflt() ++ */ + static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct sk_buff **to_free) + { +@@ -439,11 +442,6 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + struct Qdisc *child; + int queue; + +- if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { +- WARN_ONCE(1, "Trying to enqueue skb into the root of a taprio qdisc configured with full offload\n"); +- return qdisc_drop(skb, sch, to_free); +- } +- + queue = skb_get_queue_mapping(skb); + + child = q->qdiscs[queue]; +@@ -489,6 +487,9 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return taprio_enqueue_one(skb, sch, child, to_free); + } + ++/* Will not be called in the full offload case, since the TX queues are ++ * attached to the Qdisc created using qdisc_create_dflt() ++ */ + static struct sk_buff *taprio_peek(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); +@@ -498,11 +499,6 @@ static struct sk_buff *taprio_peek(struct Qdisc *sch) + u32 gate_mask; + int i; + +- if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { +- WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n"); +- return NULL; +- } +- + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN; +@@ -545,6 +541,9 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + atomic64_read(&q->picos_per_byte))); + } + ++/* Will not be called in the full offload case, since the TX queues are ++ * attached to the Qdisc created using qdisc_create_dflt() ++ */ + static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); +@@ -554,11 +553,6 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + u32 gate_mask; + int i; + +- if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { +- WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n"); +- return NULL; +- } +- + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + /* if there's no entry, it means that the schedule didn't +-- +2.53.0 + diff --git a/queue-5.15/net-sched-taprio-stop-going-through-private-ops-for-.patch b/queue-5.15/net-sched-taprio-stop-going-through-private-ops-for-.patch new file mode 100644 index 0000000000..c8275803c3 --- /dev/null +++ b/queue-5.15/net-sched-taprio-stop-going-through-private-ops-for-.patch @@ -0,0 +1,161 @@ +From d5f1f83bcadf6cd2337064e9b2d003a8b0059db8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Sep 2022 13:50:44 +0300 +Subject: net/sched: taprio: stop going through private ops for dequeue and + peek + +From: Vladimir Oltean + +[ Upstream commit 25becba6290bc34e369a0e1a76db9ca88bad87aa ] + +Since commit 13511704f8d7 ("net: taprio offload: enforce qdisc to netdev +queue mapping"), taprio_dequeue_soft() and taprio_peek_soft() are de +facto the only implementations for Qdisc_ops :: dequeue and Qdisc_ops :: +peek that taprio provides. + +This is because in full offload mode, __dev_queue_xmit() will select a +txq->qdisc which is never root taprio qdisc. So if nothing is enqueued +in the root qdisc, it will never be run and nothing will get dequeued +from it. + +Therefore, we can remove the private indirection from taprio, and always +point Qdisc_ops :: dequeue to taprio_dequeue_soft (now simply named +taprio_dequeue) and Qdisc_ops :: peek to taprio_peek_soft (now simply +named taprio_peek). + +Signed-off-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 58 +++++++++--------------------------------- + 1 file changed, 12 insertions(+), 46 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 44b971ef343ce..9c86c8ade4853 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -78,8 +78,6 @@ struct taprio_sched { + struct sched_gate_list __rcu *admin_sched; + struct hrtimer advance_timer; + struct list_head taprio_list; +- struct sk_buff *(*dequeue)(struct Qdisc *sch); +- struct sk_buff *(*peek)(struct Qdisc *sch); + u32 txtime_delay; + }; + +@@ -491,7 +489,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return taprio_enqueue_one(skb, sch, child, to_free); + } + +-static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) ++static struct sk_buff *taprio_peek(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); +@@ -500,6 +498,11 @@ static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) + u32 gate_mask; + int i; + ++ if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { ++ WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n"); ++ return NULL; ++ } ++ + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN; +@@ -535,20 +538,6 @@ static struct sk_buff *taprio_peek_soft(struct Qdisc *sch) + return NULL; + } + +-static struct sk_buff *taprio_peek_offload(struct Qdisc *sch) +-{ +- WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n"); +- +- return NULL; +-} +- +-static struct sk_buff *taprio_peek(struct Qdisc *sch) +-{ +- struct taprio_sched *q = qdisc_priv(sch); +- +- return q->peek(sch); +-} +- + static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + { + atomic_set(&entry->budget, +@@ -556,7 +545,7 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + atomic64_read(&q->picos_per_byte))); + } + +-static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) ++static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + { + struct taprio_sched *q = qdisc_priv(sch); + struct net_device *dev = qdisc_dev(sch); +@@ -565,6 +554,11 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) + u32 gate_mask; + int i; + ++ if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) { ++ WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n"); ++ return NULL; ++ } ++ + rcu_read_lock(); + entry = rcu_dereference(q->current_entry); + /* if there's no entry, it means that the schedule didn't +@@ -644,20 +638,6 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch) + return skb; + } + +-static struct sk_buff *taprio_dequeue_offload(struct Qdisc *sch) +-{ +- WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n"); +- +- return NULL; +-} +- +-static struct sk_buff *taprio_dequeue(struct Qdisc *sch) +-{ +- struct taprio_sched *q = qdisc_priv(sch); +- +- return q->dequeue(sch); +-} +- + static bool should_restart_cycle(const struct sched_gate_list *oper, + const struct sched_entry *entry) + { +@@ -1572,17 +1552,6 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, + q->advance_timer.function = advance_sched; + } + +- if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { +- q->dequeue = taprio_dequeue_offload; +- q->peek = taprio_peek_offload; +- } else { +- /* Be sure to always keep the function pointers +- * in a consistent state. +- */ +- q->dequeue = taprio_dequeue_soft; +- q->peek = taprio_peek_soft; +- } +- + err = taprio_get_start_time(sch, new_admin, &start); + if (err < 0) { + NL_SET_ERR_MSG(extack, "Internal error: failed get start time"); +@@ -1698,9 +1667,6 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt, + hrtimer_init(&q->advance_timer, CLOCK_TAI, HRTIMER_MODE_ABS); + q->advance_timer.function = advance_sched; + +- q->dequeue = taprio_dequeue_soft; +- q->peek = taprio_peek_soft; +- + q->root = sch; + + /* We only support static clockids. Use an invalid value as default +-- +2.53.0 + diff --git a/queue-5.15/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch b/queue-5.15/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch new file mode 100644 index 0000000000..8521bee4e7 --- /dev/null +++ b/queue-5.15/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch @@ -0,0 +1,89 @@ +From 66b5d2f6c60ca65e6d9ef3d394e920e730814a94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 08:49:12 +0800 +Subject: net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit() + +From: Zhan Jun + +[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ] + +syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() +when accessing skb->len for tx statistics after usb_submit_urb() has +been called: + + BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760 + drivers/net/usb/rtl8150.c:712 + Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226 + +The URB completion handler write_bulk_callback() frees the skb via +dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU +in softirq context before usb_submit_urb() returns in the submitter, +so by the time the submitter reads skb->len the skb has already been +queued to the per-CPU completion_queue and freed by net_tx_action(): + + CPU A (xmit) CPU B (USB completion softirq) + ------------ ------------------------------ + dev->tx_skb = skb; + usb_submit_urb() --+ + |-------> write_bulk_callback() + | dev_kfree_skb_irq(dev->tx_skb) + | net_tx_action() + | napi_skb_cache_put() <-- free + netdev->stats.tx_bytes | + += skb->len; <-- UAF read + +Fix it by caching skb->len before submitting the URB and using the +cached value when updating the tx_bytes counter. + +The pre-existing tx_bytes semantics are preserved: the counter tracks +the original frame length (skb->len), not the ETH_ZLEN/USB-alignment +padded "count" value that is handed to the device. Changing that +would be a user-visible accounting change and is out of scope for +this UAF fix. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+3f46c095ac0ca048cb71@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e69ee7.050a0220.24bfd3.002b.GAE@google.com/ +Closes: https://syzkaller.appspot.com/bug?extid=3f46c095ac0ca048cb71 +Reviewed-by: Andrew Lunn +Signed-off-by: Zhan Jun +Link: https://patch.msgid.link/809895186B866C10+20260423004913.136655-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index fa69d59a309a3..3aa38524f4f38 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + rtl8150_t *dev = netdev_priv(netdev); ++ unsigned int skb_len; + int count, res; + + /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ +@@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + ++ skb_len = skb->len; ++ + netif_stop_queue(netdev); + dev->tx_skb = skb; + usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), +@@ -711,7 +714,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + } + } else { + netdev->stats.tx_packets++; +- netdev->stats.tx_bytes += skb->len; ++ netdev->stats.tx_bytes += skb_len; + netif_trans_update(netdev); + } + +-- +2.53.0 + diff --git a/queue-5.15/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch b/queue-5.15/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch new file mode 100644 index 0000000000..3ec631225e --- /dev/null +++ b/queue-5.15/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch @@ -0,0 +1,61 @@ +From e1ce832ce59a81fddb7e8826a84e973f54b8e8d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 09:55:17 +0800 +Subject: net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit + +From: Morduan Zang + +[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ] + +When rtl8150_start_xmit() fails to submit the tx URB, the URB is never +handed to the USB core and write_bulk_callback() will not run. The +driver returns NETDEV_TX_OK, which tells the networking stack that the +skb has been consumed, but nothing actually frees the skb on this +error path: + + dev->tx_skb = skb; + ... + if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { + ... + /* no kfree_skb here */ + } + return NETDEV_TX_OK; + +This leaks the skb on every submit failure and also leaves dev->tx_skb +pointing at memory that the driver itself may later free, which is +fragile. + +Free the skb with dev_kfree_skb_any() in the error path and clear +dev->tx_skb so no stale pointer is left behind. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reviewed-by: Andrew Lunn +Signed-off-by: Morduan Zang +Link: https://patch.msgid.link/E7D3E1C013C5A859+20260424015517.9574-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 3aa38524f4f38..4c7216b4c8ac2 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -712,6 +712,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } ++ /* ++ * The URB was not submitted, so write_bulk_callback() will ++ * never run to free dev->tx_skb. Drop the skb here and ++ * clear tx_skb to avoid leaving a stale pointer. ++ */ ++ dev->tx_skb = NULL; ++ dev_kfree_skb_any(skb); + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb_len; +-- +2.53.0 + diff --git a/queue-5.15/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch b/queue-5.15/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch new file mode 100644 index 0000000000..9b949faa80 --- /dev/null +++ b/queue-5.15/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch @@ -0,0 +1,92 @@ +From 003034b12e9086d28e0979a0e60f906e9234288a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:33:49 +0000 +Subject: net_sched: sch_hhf: annotate data-races in hhf_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ] + +hhf_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421143349.4052215-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_hhf.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index 433bddcbc0c72..73cabb4451ce7 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash, + return NULL; + list_del(&flow->flowchain); + kfree(flow); +- q->hh_flows_current_cnt--; ++ WRITE_ONCE(q->hh_flows_current_cnt, ++ q->hh_flows_current_cnt - 1); + } else if (flow->hash_id == hash) { + return flow; + } +@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + } + + if (q->hh_flows_current_cnt >= q->hh_flows_limit) { +- q->hh_flows_overlimit++; ++ WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); + return NULL; + } + /* Create new entry. */ +@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + if (!flow) + return NULL; + +- q->hh_flows_current_cnt++; ++ WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); + INIT_LIST_HEAD(&flow->flowchain); + list_add_tail(&flow->flowchain, head); + +@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) + return WDRR_BUCKET_FOR_NON_HH; + flow->hash_id = hash; + flow->hit_timestamp = now; +- q->hh_flows_total_cnt++; ++ WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); + + /* By returning without updating counters in q->hhf_arrays, + * we implicitly implement "shielding" (see Optimization O1). +@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + + prev_backlog = sch->qstats.backlog; +- q->drop_overlimit++; ++ WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); + /* Return Congestion Notification only if we dropped a packet from this + * bucket. + */ +@@ -681,10 +682,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct hhf_sched_data *q = qdisc_priv(sch); + struct tc_hhf_xstats st = { +- .drop_overlimit = q->drop_overlimit, +- .hh_overlimit = q->hh_flows_overlimit, +- .hh_tot_count = q->hh_flows_total_cnt, +- .hh_cur_count = q->hh_flows_current_cnt, ++ .drop_overlimit = READ_ONCE(q->drop_overlimit), ++ .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), ++ .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), ++ .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-5.15/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch b/queue-5.15/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch new file mode 100644 index 0000000000..43b3eab1f7 --- /dev/null +++ b/queue-5.15/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch @@ -0,0 +1,43 @@ +From 5e9383f616fb8a88cccdaa685fe737c01752d035 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 23:14:34 +0300 +Subject: netdevsim: zero initialize struct iphdr in dummy sk_buff + +From: Nikola Z. Ivanov + +[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ] + +Syzbot reports a KMSAN uninit-value originating from +nsim_dev_trap_skb_build, with the allocation also +being performed in the same function. + +Fix this by calling skb_put_zero instead of skb_put to +guarantee zero initialization of the whole IP header. + +Closes: https://syzkaller.appspot.com/bug?extid=23d7fcd204e3837866ff +Fixes: da58f90f11f5 ("netdevsim: Add devlink-trap support") +Signed-off-by: Nikola Z. Ivanov +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426201434.742030-1-zlatistiv@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netdevsim/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c +index d8f91bc38f406..3136ff369acd4 100644 +--- a/drivers/net/netdevsim/dev.c ++++ b/drivers/net/netdevsim/dev.c +@@ -674,7 +674,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) + skb->protocol = htons(ETH_P_IP); + + skb_set_network_header(skb, skb->len); +- iph = skb_put(skb, sizeof(struct iphdr)); ++ iph = skb_put_zero(skb, sizeof(struct iphdr)); + iph->protocol = IPPROTO_UDP; + iph->saddr = in_aton("192.0.2.1"); + iph->daddr = in_aton("198.51.100.1"); +-- +2.53.0 + diff --git a/queue-5.15/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch b/queue-5.15/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch new file mode 100644 index 0000000000..6741240503 --- /dev/null +++ b/queue-5.15/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch @@ -0,0 +1,126 @@ +From 38d2788488f465b903afc6485cc0fa89112fc183 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:15:32 +0200 +Subject: netfilter: arp_tables: fix IEEE1394 ARP payload parsing + +From: Pablo Neira Ayuso + +[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ] + +Weiming Shi says: + +"arp_packet_match() unconditionally parses the ARP payload assuming two +hardware addresses are present (source and target). However, +IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address +field, and arp_hdr_len() already accounts for this by returning a +shorter length for ARPHRD_IEEE1394 devices. + +As a result, on IEEE1394 interfaces arp_packet_match() advances past a +nonexistent target hardware address and reads the wrong bytes for both +the target device address comparison and the target IP address. This +causes arptables rules to match against garbage data, leading to +incorrect filtering decisions: packets that should be accepted may be +dropped and vice versa. + +The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already +handles this correctly by skipping the target hardware address for +ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()." + +Mangle the original patch to always return 0 (no match) in case user +matches on the target hardware address which is never present in +IEEE1394. + +Note that this returns 0 (no match) for either normal and inverse match +because matching in the target hardware address in ARPHRD_IEEE1394 has +never been supported by arptables. This is intentional, matching on the +target hardware address should never evaluate true for ARPHRD_IEEE1394. + +Moreover, adjust arpt_mangle to drop the packet too as AI suggests: + +In arpt_mangle, the logic assumes a standard ARP layout. Because +IEEE1394 (FireWire) omits the target hardware address, the linear +pointer arithmetic miscalculates the offset for the target IP address. +This causes mangling operations to write to the wrong location, leading +to packet corruption. To ensure safety, this patch drops packets +(NF_DROP) when mangling is requested for these fields on IEEE1394 +devices, as the current implementation cannot correctly map the FireWire +ARP payload. + +This omits both mangling target hardware and IP address. Even if IP +address mangling should be possible in IEEE1394, this would require +to adjust arpt_mangle offset calculation, which has never been +supported. + +Based on patch from Weiming Shi . + +Fixes: 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.") +Reported-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- + net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index a9d5a1973224a..92bc90ee76748 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, + arpptr += dev->addr_len; + memcpy(&src_ipaddr, arpptr, sizeof(u32)); + arpptr += sizeof(u32); +- tgt_devaddr = arpptr; +- arpptr += dev->addr_len; ++ ++ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { ++ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, ++ sizeof(arpinfo->tgt_devaddr.mask)))) ++ return 0; ++ ++ tgt_devaddr = NULL; ++ } else { ++ tgt_devaddr = arpptr; ++ arpptr += dev->addr_len; ++ } + memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); + + if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, + arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, +- dev->addr_len)) || ++ dev->addr_len))) ++ return 0; ++ ++ if (tgt_devaddr && + NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, + arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, + dev->addr_len))) +diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c +index a4e07e5e9c118..f65dd339208e8 100644 +--- a/net/ipv4/netfilter/arpt_mangle.c ++++ b/net/ipv4/netfilter/arpt_mangle.c +@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += pln; + if (mangle->flags & ARPT_MANGLE_TDEV) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_DEV_ADDR_LEN_MAX < hln || + (arpptr + hln > skb_tail_pointer(skb))) + return NF_DROP; +@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += hln; + if (mangle->flags & ARPT_MANGLE_TIP) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_MANGLE_ADDR_LEN_MAX < pln || + (arpptr + pln > skb_tail_pointer(skb))) + return NF_DROP; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-conntrack-remove-sprintf-usage.patch b/queue-5.15/netfilter-conntrack-remove-sprintf-usage.patch new file mode 100644 index 0000000000..a8e1bdab8d --- /dev/null +++ b/queue-5.15/netfilter-conntrack-remove-sprintf-usage.patch @@ -0,0 +1,182 @@ +From 1d1e863159e64b3a63bbc083836530eaab486b95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 19:13:46 +0200 +Subject: netfilter: conntrack: remove sprintf usage + +From: Florian Westphal + +[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ] + +Replace it with scnprintf, the buffer sizes are expected to be large enough +to hold the result, no need for snprintf+overflow check. + +Increase buffer size in mangle_content_len() while at it. + +BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 +Write of size 1 at addr [..] + vsnprintf+0xea5/0x1270 + sprintf+0xb1/0xe0 + mangle_content_len+0x1ac/0x280 + nf_nat_sdp_session+0x1cc/0x240 + process_sdp+0x8f8/0xb80 + process_invite_request+0x108/0x2b0 + process_sip_msg+0x5da/0xf50 + sip_help_tcp+0x45e/0x780 + nf_confirm+0x34d/0x990 + [..] + +Fixes: 9fafcd7b2032 ("[NETFILTER]: nf_conntrack/nf_nat: add SIP helper port") +Reported-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_nat_amanda.c | 2 +- + net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c +index 3bc7e0854efe4..41c30065dae12 100644 +--- a/net/netfilter/nf_nat_amanda.c ++++ b/net/netfilter/nf_nat_amanda.c +@@ -62,7 +62,7 @@ static unsigned int help(struct sk_buff *skb, + return NF_DROP; + } + +- sprintf(buffer, "%u", port); ++ snprintf(buffer, sizeof(buffer), "%u", port); + if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, + protoff, matchoff, matchlen, + buffer, strlen(buffer))) { +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index f0a735e868518..15d4267cf49ff 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, + } + + static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, bool delim) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4", &addr->ip); ++ return scnprintf(buffer, size, "%pI4", &addr->ip); + else { + if (delim) +- return sprintf(buffer, "[%pI6c]", &addr->ip6); ++ return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); + else +- return sprintf(buffer, "%pI6c", &addr->ip6); ++ return scnprintf(buffer, size, "%pI6c", &addr->ip6); + } + } + + static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, u16 port) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4:%u", &addr->ip, port); ++ return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port); + else +- return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); ++ return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); + } + + static int map_addr(struct sk_buff *skb, unsigned int protoff, +@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, + if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) + return 1; + +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, true) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.dst.u3, + true); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, false) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.src.u3, + false); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +- buflen = sprintf(buffer, "%u", ntohs(p)); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle rport"); +@@ -430,7 +432,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, + + if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), ++ &newaddr, port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle packet"); +@@ -450,8 +453,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++ char buffer[sizeof("4294967295")]; + unsigned int matchoff, matchlen; +- char buffer[sizeof("65536")]; + int buflen, c_len; + + /* Get actual SDP length */ +@@ -466,7 +469,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + return 0; + +- buflen = sprintf(buffer, "%u", c_len); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -503,7 +506,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, + char buffer[INET6_ADDRSTRLEN]; + unsigned int buflen; + +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, + sdpoff, type, term, buffer, buflen)) + return 0; +@@ -521,7 +524,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + +- buflen = sprintf(buffer, "%u", port); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) + return 0; +@@ -541,7 +544,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, + SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) + return 0; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch b/queue-5.15/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch new file mode 100644 index 0000000000..20667d8c3b --- /dev/null +++ b/queue-5.15/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch @@ -0,0 +1,352 @@ +From 94ca406aed5b3a37e0e7356df0d9da2201dcdf13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 02:19:11 +0200 +Subject: netfilter: nf_conntrack_sip: don't use simple_strtoul +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Florian Westphal + +[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ] + +Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), +and ct_sip_parse_request() with a new sip_parse_port() helper that +validates each digit against the buffer limit, eliminating the use of +simple_strtoul() which assumes NUL-terminated strings. + +The previous code dereferenced pointers without bounds checks after +sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated +skb data. A port that reaches the buffer limit without a trailing +character is also rejected as malformed. + +Also get rid of all simple_strtoul() usage in conntrack, prefer a +stricter version instead. There are intentional changes: + +- Bail out if number is > UINT_MAX and indicate a failure, same for + too long sequences. + While we do accept 05535 as port 5535, we will not accept e.g. + 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, + we should restrict this to not waste cycles when presented with + malformed packets with 64k '0' characters. + +- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch + 'expire=' and 'rports='; both are expected to use base-10. + +- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k + range. + +- epaddr_len now returns 0 if the port is invalid, as it already does + for invalid ip addresses. This is intentional. nf_conntrack_sip + performs lots of guesswork to find the right parts of the message + to parse. Being stricter could break existing setups. + Connection tracking helpers are designed to allow traffic to + pass, not to block it. + +Based on an earlier patch from Jenny Guanni Qu . + +Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper") +Reported-by: Klaudia Kloc +Reported-by: Dawid Moczadło +Reported-by: Jenny Guanni Qu . +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- + net/netfilter/nf_nat_sip.c | 1 + + 2 files changed, 119 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index dcb0a5e592775..4326d5ea0400d 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, + return 1; + } + ++/* Parse optional port number after IP address. ++ * Returns false on malformed input, true otherwise. ++ * If port is non-NULL, stores parsed port in network byte order. ++ * If no port is present, sets *port to default SIP port. ++ */ ++static bool sip_parse_port(const char *dptr, const char **endp, ++ const char *limit, __be16 *port) ++{ ++ unsigned int p = 0; ++ int len = 0; ++ ++ if (dptr >= limit) ++ return false; ++ ++ if (*dptr != ':') { ++ if (port) ++ *port = htons(SIP_PORT); ++ if (endp) ++ *endp = dptr; ++ return true; ++ } ++ ++ dptr++; /* skip ':' */ ++ ++ while (dptr < limit && isdigit(*dptr)) { ++ p = p * 10 + (*dptr - '0'); ++ dptr++; ++ len++; ++ if (len > 5) /* max "65535" */ ++ return false; ++ } ++ ++ if (len == 0) ++ return false; ++ ++ /* reached limit while parsing port */ ++ if (dptr >= limit) ++ return false; ++ ++ if (p < 1024 || p > 65535) ++ return false; ++ ++ if (port) ++ *port = htons(p); ++ ++ if (endp) ++ *endp = dptr; ++ ++ return true; ++} ++ + /* skip ip address. returns its length. */ + static int epaddr_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, + return 0; + } + +- /* Port number */ +- if (*dptr == ':') { +- dptr++; +- dptr += digits_len(ct, dptr, limit, shift); +- } ++ if (!sip_parse_port(dptr, &dptr, limit, NULL)) ++ return 0; + return dptr - aux; + } + +@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, + return epaddr_len(ct, dptr, limit, shift); + } + ++/* simple_strtoul stops after first non-number character. ++ * But as we're not dealing with c-strings, we can't rely on ++ * hitting \r,\n,\0 etc. before moving past end of buffer. ++ * ++ * This is a variant of simple_strtoul, but doesn't require ++ * a c-string. ++ * ++ * If value exceeds UINT_MAX, 0 is returned. ++ */ ++static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) ++{ ++ const unsigned int max = sizeof("4294967295"); ++ unsigned int olen = len; ++ const char *s = cp; ++ u64 result = 0; ++ ++ if (len > max) ++ len = max; ++ ++ while (olen > 0 && isdigit(*s)) { ++ unsigned int value; ++ ++ if (len == 0) ++ goto err; ++ ++ value = *s - '0'; ++ result = result * 10 + value; ++ ++ if (result > UINT_MAX) ++ goto err; ++ s++; ++ len--; ++ olen--; ++ } ++ ++ if (endp) ++ *endp = (char *)s; ++ ++ return result; ++err: ++ if (endp) ++ *endp = (char *)cp; ++ return 0; ++} ++ + /* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF +@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, + { + const char *start = dptr, *limit = dptr + datalen, *end; + unsigned int mlen; +- unsigned int p; + int shift = 0; + + /* Skip method and following whitespace */ +@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, + + if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) + return -1; +- if (end < limit && *end == ':') { +- end++; +- p = simple_strtoul(end, (char **)&end, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(end, &end, limit, port)) ++ return -1; + + if (end == dptr) + return 0; +@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + union nf_inet_addr *addr, __be16 *port) + { + const char *c, *limit = dptr + datalen; +- unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, +@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + + if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) + return -1; +- if (*c == ':') { +- c++; +- p = simple_strtoul(c, (char **)&c, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(c, &c, limit, port)) ++ return -1; + + if (dataoff) + *dataoff = c - dptr; +@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + return 0; + + start += strlen(name); +- *val = simple_strtoul(start, &end, 0); ++ *val = sip_strtouint(start, limit - start, (char **)&end); + if (start == end) + return -1; + if (matchoff && matchlen) { +@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { ++ char *end; ++ + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) +@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + mediaoff += t->len; + medialen -= t->len; + +- port = simple_strtoul(*dptr + mediaoff, NULL, 10); +- if (port == 0) ++ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); ++ if (port == 0 || *dptr + mediaoff == end) + continue; + if (port < 1024 || port > 65535) { + nf_ct_helper_log(skb, ct, "wrong port %u", port); +@@ -1254,7 +1335,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, +@@ -1354,7 +1435,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + while (1) { + unsigned int c_expires = expires; +@@ -1414,10 +1495,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen, matchend; + unsigned int code, cseq, i; ++ char *end; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; +- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); ++ code = sip_strtouint(*dptr + strlen("SIP/2.0 "), ++ *datalen - strlen("SIP/2.0 "), NULL); + if (!code) { + nf_ct_helper_log(skb, ct, "cannot get code"); + return NF_DROP; +@@ -1428,8 +1511,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1478,6 +1561,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; ++ char *end; + + handler = &sip_handlers[i]; + if (handler->request == NULL) +@@ -1494,8 +1578,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1571,7 +1655,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + break; + +- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); ++ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); + if (dptr + matchoff == end) + break; + +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index 15d4267cf49ff..390ff2d3c6bce 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, + "rport=", &poff, &plen, + &n) > 0 && ++ n >= 1024 && n <= 65535 && + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch b/queue-5.15/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch new file mode 100644 index 0000000000..28018be1d6 --- /dev/null +++ b/queue-5.15/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch @@ -0,0 +1,67 @@ +From e389c1e571208b336290ac9160f25534cf0823da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:14:01 -0700 +Subject: netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO + +From: Xiang Mei + +[ Upstream commit 2195574dc6d9017d32ac346987e12659f931d932 ] + +nf_osf_match_one() computes ctx->window % f->wss.val in the +OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A +CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a +subsequent matching TCP SYN divides by zero and panics the kernel. + +Reject the bogus fingerprint in nfnl_osf_add_callback() above the +per-option for-loop. f->wss is per-fingerprint, not per-option, so +the check must run regardless of f->opt_num (including 0). Also +reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that +as "should not happen". + +Crash: + Oops: divide error: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) + Call Trace: + + nf_osf_match (net/netfilter/nfnetlink_osf.c:220) + xt_osf_match_packet (net/netfilter/xt_osf.c:32) + ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) + nf_hook_slow (net/netfilter/core.c:622) + ip_local_deliver (net/ipv4/ip_input.c:265) + ip_rcv (include/linux/skbuff.h:1162) + __netif_receive_skb_one_core (net/core/dev.c:6181) + process_backlog (net/core/dev.c:6642) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7945) + handle_softirqs (kernel/softirq.c:622) + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Weiming Shi +Suggested-by: Florian Westphal +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Xiang Mei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index da9d5d6de98f4..000a5c280ef96 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, + if (f->opt_num > ARRAY_SIZE(f->opt)) + return -EINVAL; + ++ if (f->wss.wc >= OSF_WSS_MAX || ++ (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) ++ return -EINVAL; ++ + for (i = 0; i < f->opt_num; i++) { + if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch b/queue-5.15/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch new file mode 100644 index 0000000000..94827945f5 --- /dev/null +++ b/queue-5.15/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch @@ -0,0 +1,100 @@ +From d9fb57540a236691d48306452d915a8f1ca8cb50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:56 +0200 +Subject: netfilter: nfnetlink_osf: fix out-of-bounds read on option matching + +From: Fernando Fernandez Mancera + +[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ] + +In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once +and passed by reference to nf_osf_match_one() for each fingerprint +checked. During TCP option parsing, nf_osf_match_one() advances the +shared ctx->optp pointer. + +If a fingerprint perfectly matches, the function returns early without +restoring ctx->optp to its initial state. If the user has configured +NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. +However, because ctx->optp was not restored, the next call to +nf_osf_match_one() starts parsing from the end of the options buffer. +This causes subsequent matches to read garbage data and fail +immediately, making it impossible to log more than one match or logging +incorrect matches. + +Instead of using a shared ctx->optp pointer, pass the context as a +constant pointer and use a local pointer (optp) for TCP option +traversal. This makes nf_osf_match_one() strictly stateless from the +caller's perspective, ensuring every fingerprint check starts at the +correct option offset. + +Fixes: 1a6a0951fc00 ("netfilter: nfnetlink_osf: add missing fmatch check") +Suggested-by: Florian Westphal +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 000a5c280ef96..2207bda442d54 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx { + static bool nf_osf_match_one(const struct sk_buff *skb, + const struct nf_osf_user_finger *f, + int ttl_check, +- struct nf_osf_hdr_ctx *ctx) ++ const struct nf_osf_hdr_ctx *ctx) + { +- const __u8 *optpinit = ctx->optp; ++ const __u8 *optp = ctx->optp; + unsigned int check_WSS = 0; + int fmatch = FMATCH_WRONG; + int foptsize, optnum; +@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { +- if (f->opt[optnum].kind == *ctx->optp) { ++ if (f->opt[optnum].kind == *optp) { + __u32 len = f->opt[optnum].length; +- const __u8 *optend = ctx->optp + len; ++ const __u8 *optend = optp + len; + + fmatch = FMATCH_OK; + +- switch (*ctx->optp) { ++ switch (*optp) { + case OSFOPT_MSS: +- mss = ctx->optp[3]; ++ mss = optp[3]; + mss <<= 8; +- mss |= ctx->optp[2]; ++ mss |= optp[2]; + + mss = ntohs((__force __be16)mss); + break; +@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + break; + } + +- ctx->optp = optend; ++ optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + +@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + } + } + +- if (fmatch != FMATCH_OK) +- ctx->optp = optpinit; +- + return fmatch == FMATCH_OK; + } + +-- +2.53.0 + diff --git a/queue-5.15/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch b/queue-5.15/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch new file mode 100644 index 0000000000..93169feed6 --- /dev/null +++ b/queue-5.15/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch @@ -0,0 +1,74 @@ +From 4cc0012ee106efff99ac7294b5aa0fbdba9f3038 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:57 +0200 +Subject: netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check + +From: Fernando Fernandez Mancera + +[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ] + +The nf_osf_ttl() function accessed skb->dev to perform a local interface +address lookup without verifying that the device pointer was valid. + +Additionally, the implementation utilized an in_dev_for_each_ifa_rcu +loop to match the packet source address against local interface +addresses. It assumed that packets from the same subnet should not see a +decrement on the initial TTL. A packet might appear it is from the same +subnet but it actually isn't especially in modern environments with +containers and virtual switching. + +Remove the device dereference and interface loop. Replace the logic with +a switch statement that evaluates the TTL according to the ttl_check. + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Kito Xu (veritas501) +Closes: https://lore.kernel.org/netfilter-devel/20260414074556.2512750-1-hxzene@gmail.com/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 2207bda442d54..6d3dfbeb398cb 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); + static inline int nf_osf_ttl(const struct sk_buff *skb, + int ttl_check, unsigned char f_ttl) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + const struct iphdr *ip = ip_hdr(skb); +- const struct in_ifaddr *ifa; +- int ret = 0; + +- if (ttl_check == NF_OSF_TTL_TRUE) ++ switch (ttl_check) { ++ case NF_OSF_TTL_TRUE: + return ip->ttl == f_ttl; +- if (ttl_check == NF_OSF_TTL_NOCHECK) +- return 1; +- else if (ip->ttl <= f_ttl) ++ break; ++ case NF_OSF_TTL_NOCHECK: + return 1; +- +- in_dev_for_each_ifa_rcu(ifa, in_dev) { +- if (inet_ifa_match(ip->saddr, ifa)) { +- ret = (ip->ttl == f_ttl); +- break; +- } ++ case NF_OSF_TTL_LESS: ++ default: ++ return ip->ttl <= f_ttl; + } +- +- return ret; + } + + struct nf_osf_hdr_ctx { +-- +2.53.0 + diff --git a/queue-5.15/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch b/queue-5.15/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch new file mode 100644 index 0000000000..f1abfd867e --- /dev/null +++ b/queue-5.15/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch @@ -0,0 +1,49 @@ +From 552bcd12769d69b3d45768026c56f47e9e3ec584 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:30:41 +0200 +Subject: netfilter: nft_fwd_netdev: check ttl/hl before forwarding + +From: Florian Westphal + +[ Upstream commit 1dfd95bdf4d18d263aa8fad06bfb9f4d9c992b18 ] + +Drop packets if their ttl/hl is too small for forwarding. + +Fixes: d32de98ea70f ("netfilter: nft_fwd_netdev: allow to forward packets via neighbour layer") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_fwd_netdev.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c +index 7730409f6f091..09aff403884b5 100644 +--- a/net/netfilter/nft_fwd_netdev.c ++++ b/net/netfilter/nft_fwd_netdev.c +@@ -113,6 +113,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + iph = ip_hdr(skb); ++ if (iph->ttl <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip_decrease_ttl(iph); + neigh_table = NEIGH_ARP_TABLE; + break; +@@ -129,6 +134,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + ip6h = ipv6_hdr(skb); ++ if (ip6h->hop_limit <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip6h->hop_limit--; + neigh_table = NEIGH_ND_TABLE; + break; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-nft_osf-restrict-it-to-ipv4.patch b/queue-5.15/netfilter-nft_osf-restrict-it-to-ipv4.patch new file mode 100644 index 0000000000..27cb28c8b2 --- /dev/null +++ b/queue-5.15/netfilter-nft_osf-restrict-it-to-ipv4.patch @@ -0,0 +1,47 @@ +From 4e6a69c2e22e3ecb58351f211a8f485ee8580e7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 13:06:38 +0200 +Subject: netfilter: nft_osf: restrict it to ipv4 + +From: Pablo Neira Ayuso + +[ Upstream commit b336fdbb7103fb1484e1dcb6741151d4b5a41e35 ] + +This expression only supports for ipv4, restrict it. + +Fixes: b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf") +Acked-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_osf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c +index c9c124200a4db..8ee6a97fc7eeb 100644 +--- a/net/netfilter/nft_osf.c ++++ b/net/netfilter/nft_osf.c +@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, + struct nf_osf_data data; + struct tcphdr _tcph; + ++ if (nft_pf(pkt) != NFPROTO_IPV4) { ++ regs->verdict.code = NFT_BREAK; ++ return; ++ } ++ + if (pkt->tprot != IPPROTO_TCP) { + regs->verdict.code = NFT_BREAK; + return; +@@ -119,7 +124,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx, + + switch (ctx->family) { + case NFPROTO_IPV4: +- case NFPROTO_IPV6: + case NFPROTO_INET: + hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | +-- +2.53.0 + diff --git a/queue-5.15/netfilter-skip-recording-stale-or-retransmitted-init.patch b/queue-5.15/netfilter-skip-recording-stale-or-retransmitted-init.patch new file mode 100644 index 0000000000..88487a9e10 --- /dev/null +++ b/queue-5.15/netfilter-skip-recording-stale-or-retransmitted-init.patch @@ -0,0 +1,63 @@ +From 6e5951043e727671ababf6a6e6b2c15b02abbee0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:40 -0400 +Subject: netfilter: skip recording stale or retransmitted INIT + +From: Xin Long + +[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ] + +An INIT whose init_tag matches the peer's vtag does not provide new state +information. It indicates either: + +- a stale INIT (after INIT-ACK has already been seen on the same side), or +- a retransmitted INIT (after INIT has already been recorded on the same + side). + +In both cases, the INIT must not update ct->proto.sctp.init[] state, since +it does not advance the handshake tracking and may otherwise corrupt +INIT/INIT-ACK validation logic. + +Allow INIT processing only when the conntrack entry is newly created +(SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer +vtag. + +Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in +nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it +set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag. + +Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") +Signed-off-by: Xin Long +Reviewed-by: Marcelo Ricardo Leitner +Acked-by: Florian Westphal +Link: https://patch.msgid.link/ee56c3e416452b2a40589a2a85245ac2ad5e9f4b.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index 90458799324ec..ae89f3c590e8b 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -484,9 +484,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + if (!ih) + goto out_unlock; + +- if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) +- ct->proto.sctp.init[!dir] = 0; +- ct->proto.sctp.init[dir] = 1; ++ /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ ++ if (old_state == SCTP_CONNTRACK_NONE || ++ ct->proto.sctp.vtag[!dir] != ih->init_tag) { ++ if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) ++ ct->proto.sctp.init[!dir] = 0; ++ ct->proto.sctp.init[dir] = 1; ++ } + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); + ct->proto.sctp.vtag[!dir] = ih->init_tag; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch b/queue-5.15/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch new file mode 100644 index 0000000000..73b39fc153 --- /dev/null +++ b/queue-5.15/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch @@ -0,0 +1,47 @@ +From 175f07498dc61783f5d89fb6345c2201b80039ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:25:06 +0800 +Subject: netfilter: xt_policy: fix strict mode inbound policy matching + +From: Jiexun Wang + +[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ] + +match_policy_in() walks sec_path entries from the last transform to the +first one, but strict policy matching needs to consume info->pol[] in +the same forward order as the rule layout. + +Derive the strict-match policy position from the number of transforms +already consumed so that multi-element inbound rules are matched +consistently. + +Fixes: c4b885139203 ("[NETFILTER]: x_tables: replace IPv4/IPv6 policy match by address family independant version") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Acked-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c +index cb6e8279010a4..b5fa65558318f 100644 +--- a/net/netfilter/xt_policy.c ++++ b/net/netfilter/xt_policy.c +@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, + return 0; + + for (i = sp->len - 1; i >= 0; i--) { +- pos = strict ? i - sp->len + 1 : 0; ++ pos = strict ? sp->len - i - 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; +-- +2.53.0 + diff --git a/queue-5.15/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch b/queue-5.15/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch new file mode 100644 index 0000000000..0bd5cea9ea --- /dev/null +++ b/queue-5.15/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch @@ -0,0 +1,86 @@ +From f37499e20449ba8c8aa983a2fc1400426ce4d1a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 12:12:59 +0200 +Subject: netfilter: xt_socket: enable defrag after all other checks + +From: Florian Westphal + +[ Upstream commit 542be3fa5aff54210a02954c38f07e53ea9bdafd ] + +Originally this did not matter because defrag was enabled once per netns +and only disabled again on netns dismantle. When this got changed I should +have adjusted checkentry to not leave defrag enabled on error. + +Fixes: de8c12110a13 ("netfilter: disable defrag once its no longer needed") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_socket.c | 23 ++++++----------------- + 1 file changed, 6 insertions(+), 17 deletions(-) + +diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c +index 7013f55f05d1e..5ff7d00786eee 100644 +--- a/net/netfilter/xt_socket.c ++++ b/net/netfilter/xt_socket.c +@@ -168,52 +168,41 @@ static int socket_mt_enable_defrag(struct net *net, int family) + static int socket_mt_v1_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V1) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V1); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v2_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V2) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V2); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v3_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo3 *info = + (struct xt_socket_mtinfo3 *)par->matchinfo; +- int err; + +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + if (info->flags & ~XT_SOCKET_FLAGS_V3) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V3); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static void socket_mt_destroy(const struct xt_mtdtor_param *par) +-- +2.53.0 + diff --git a/queue-5.15/netfilter-xtables-restrict-several-matches-to-inet-f.patch b/queue-5.15/netfilter-xtables-restrict-several-matches-to-inet-f.patch new file mode 100644 index 0000000000..cf03f83966 --- /dev/null +++ b/queue-5.15/netfilter-xtables-restrict-several-matches-to-inet-f.patch @@ -0,0 +1,208 @@ +From 74a6e9079c97f9874d18bce03ce57514ed8d1bf4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 12:21:00 +0200 +Subject: netfilter: xtables: restrict several matches to inet family + +From: Pablo Neira Ayuso + +[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ] + +This is a partial revert of: + + commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") + +to allow ipv4 and ipv6 only. + +- xt_mac +- xt_owner +- xt_physdev + +These extensions are not used by ebtables in userspace. + +Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 +specific. + +Fixes: ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") +Reported-by: "Kito Xu (veritas501)" +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- + net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ + net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- + net/netfilter/xt_realm.c | 2 +- + 4 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index 81649da57ba5d..bd2354760895d 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + return ret; + } + +-static struct xt_match mac_mt_reg __read_mostly = { +- .name = "mac", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .match = mac_mt, +- .matchsize = sizeof(struct xt_mac_info), +- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | +- (1 << NF_INET_FORWARD), +- .me = THIS_MODULE, ++static struct xt_match mac_mt_reg[] __read_mostly = { ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV4, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV6, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init mac_mt_init(void) + { +- return xt_register_match(&mac_mt_reg); ++ return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + static void __exit mac_mt_exit(void) + { +- xt_unregister_match(&mac_mt_reg); ++ xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + module_init(mac_mt_init); +diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c +index 50332888c8d23..7be2fe22b067e 100644 +--- a/net/netfilter/xt_owner.c ++++ b/net/netfilter/xt_owner.c +@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + +-static struct xt_match owner_mt_reg __read_mostly = { +- .name = "owner", +- .revision = 1, +- .family = NFPROTO_UNSPEC, +- .checkentry = owner_check, +- .match = owner_mt, +- .matchsize = sizeof(struct xt_owner_match_info), +- .hooks = (1 << NF_INET_LOCAL_OUT) | +- (1 << NF_INET_POST_ROUTING), +- .me = THIS_MODULE, ++static struct xt_match owner_mt_reg[] __read_mostly = { ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV4, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV6, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ } + }; + + static int __init owner_mt_init(void) + { +- return xt_register_match(&owner_mt_reg); ++ return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + static void __exit owner_mt_exit(void) + { +- xt_unregister_match(&owner_mt_reg); ++ xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + module_init(owner_mt_init); +diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c +index ec6ed6fda96c5..6a596878d611f 100644 +--- a/net/netfilter/xt_physdev.c ++++ b/net/netfilter/xt_physdev.c +@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) + return 0; + } + +-static struct xt_match physdev_mt_reg __read_mostly = { +- .name = "physdev", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .checkentry = physdev_mt_check, +- .match = physdev_mt, +- .matchsize = sizeof(struct xt_physdev_info), +- .me = THIS_MODULE, ++static struct xt_match physdev_mt_reg[] __read_mostly = { ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV4, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV6, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init physdev_mt_init(void) + { +- return xt_register_match(&physdev_mt_reg); ++ return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + static void __exit physdev_mt_exit(void) + { +- xt_unregister_match(&physdev_mt_reg); ++ xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + module_init(physdev_mt_init); +diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c +index 6df485f4403d0..61b2f1e58d150 100644 +--- a/net/netfilter/xt_realm.c ++++ b/net/netfilter/xt_realm.c +@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { + .matchsize = sizeof(struct xt_realm_info), + .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), +- .family = NFPROTO_UNSPEC, ++ .family = NFPROTO_IPV4, + .me = THIS_MODULE + }; + +-- +2.53.0 + diff --git a/queue-5.15/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch b/queue-5.15/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch new file mode 100644 index 0000000000..b8a6053cf0 --- /dev/null +++ b/queue-5.15/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch @@ -0,0 +1,69 @@ +From 8c1d7f1166ba42c1aa963c691bef2ec716911b48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:19 +0800 +Subject: nexthop: fix IPv6 route referencing IPv4 nexthop + +From: Jiayuan Chen + +[ Upstream commit 29c95185ba32b621fbc3800fb86e7dc3edf5c2be ] + +syzbot reported a panic [1] [2]. + +When an IPv6 nexthop is replaced with an IPv4 nexthop, the has_v4 flag +of all groups containing this nexthop is not updated. This is because +nh_group_v4_update is only called when replacing AF_INET to AF_INET6, +but the reverse direction (AF_INET6 to AF_INET) is missed. + +This allows a stale has_v4=false to bypass fib6_check_nexthop, causing +IPv6 routes to be attached to groups that effectively contain only AF_INET +members. Subsequent route lookups then call nexthop_fib6_nh() which +returns NULL for the AF_INET member, leading to a NULL pointer +dereference. + +Fix by calling nh_group_v4_update whenever the family changes, not just +AF_INET to AF_INET6. + +Reproducer: + # AF_INET6 blackhole + ip -6 nexthop add id 1 blackhole + # group with has_v4=false + ip nexthop add id 100 group 1 + # replace with AF_INET (no -6), has_v4 stays false + ip nexthop replace id 1 blackhole + # pass stale has_v4 check + ip -6 route add 2001:db8::/64 nhid 100 + # panic + ping -6 2001:db8::1 + +[1] https://syzkaller.appspot.com/bug?id=e17283eb2f8dcf3dd9b47fe6f67a95f71faadad0 +[2] https://syzkaller.appspot.com/bug?id=8699b6ae54c9f35837d925686208402949e12ef3 +Fixes: 7bf4796dd099 ("nexthops: add support for replace") +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/nexthop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c +index 9bd72526000c4..8cd148be09c6b 100644 +--- a/net/ipv4/nexthop.c ++++ b/net/ipv4/nexthop.c +@@ -2161,10 +2161,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + goto err_notify; + } + +- /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially ++ /* When replacing a nexthop with one of a different family, potentially + * update IPv4 indication in all the groups using the nexthop. + */ +- if (oldi->family == AF_INET && newi->family == AF_INET6) { ++ if (oldi->family != newi->family) { + list_for_each_entry(nhge, &old->grp_list, nh_list) { + struct nexthop *nhp = nhge->nh_parent; + struct nh_group *nhg; +-- +2.53.0 + diff --git a/queue-5.15/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch b/queue-5.15/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch new file mode 100644 index 0000000000..d7c732b29b --- /dev/null +++ b/queue-5.15/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch @@ -0,0 +1,53 @@ +From 4c03c3d3c1120241adf8723f81ffd1c8bc2c6922 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 12:09:30 +0200 +Subject: NFC: trf7970a: Ignore antenna noise when checking for RF field + +From: Paul Geurts + +[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ] + +The main channel Received Signal Strength Indicator (RSSI) measurement +is used to determine whether an RF field is present or not. RSSI != 0 +is interpreted as an RF Field is present. This does not take RF noise +and measurement inaccuracy into account, and results in false positives +in the field. + +Define a noise level and make sure the RF field is only interpreted as +present when the RSSI is above the noise level. + +Fixes: 851ee3cbf850 ("NFC: trf7970a: Don't turn on RF if there is already an RF field") +Signed-off-by: Paul Geurts +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Mark Greer +Link: https://patch.msgid.link/20260422100930.581237-1-paul.geurts@prodrive-technologies.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/trf7970a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c +index cfc2a7e652719..bc832d7f24962 100644 +--- a/drivers/nfc/trf7970a.c ++++ b/drivers/nfc/trf7970a.c +@@ -311,6 +311,7 @@ + #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) ++#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 + + #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) + #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +@@ -1253,7 +1254,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) + if (ret) + return ret; + +- if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) ++ if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) + *is_rf_field = true; + else + *is_rf_field = false; +-- +2.53.0 + diff --git a/queue-5.15/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch b/queue-5.15/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch new file mode 100644 index 0000000000..8da7fdfb02 --- /dev/null +++ b/queue-5.15/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch @@ -0,0 +1,107 @@ +From f302a8d5c8d78eaae619c3c5284f1e8a74883bd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 16:05:36 +0000 +Subject: nfp: fix swapped arguments in nfp_encode_basic_qdr() calls + +From: Alexey Kodanev + +[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ] + +There is a mismatch between the passed arguments and the actual +nfp_encode_basic_qdr() function parameter names: + + static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + int mode, bool addr40, int isld1, + int isld0) + { + ... + +But "dest_island" and "cpp_tgt" are swapped at every call-site. +For example: + + return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + mode, addr40, isld1, isld0); + +As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target +type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" +as the destination island ID, which can accidentally match or be outside +the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination). + +Since code already worked for years, also add extra pr_warn() to error +paths in nfp_encode_basic_qdr() to help identify any potential address +verification failures. + +Detected using the static analysis tool - Svace. + +Fixes: 4cb584e0ee7d ("nfp: add CPP access core") +Signed-off-by: Alexey Kodanev +Link: https://patch.msgid.link/20260422160536.61855-1-aleksei.kodanev@bell-sw.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +index 79470f198a62a..9cf19446657c6 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + + /* Full Island ID and channel bits overlap? */ + ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0); +- if (ret) ++ if (ret) { ++ pr_warn("%s: decode dest_island failed: %d\n", __func__, ret); + return ret; ++ } + + /* The current address won't go where expected? */ +- if (dest_island != -1 && dest_island != v) ++ if (dest_island != -1 && dest_island != v) { ++ pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n", ++ __func__, dest_island, v); + return -EINVAL; ++ } + + /* If dest_island was -1, we don't care where it goes. */ + return 0; +@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * the address but we can verify if the existing + * contents will point to a valid island. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + iid_lsb = addr40 ? 34 : 26; +@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + return 0; + case 1: + if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40) +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + idx_lsb = addr40 ? 39 : 31; +@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * be set before hand and with them select an island. + * So we need to confirm that it's at least plausible. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + /* Make sure we compare against isldN values +@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * iid<1> = addr<30> = channel<0> + * channel<1> = addr<31> = Index + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + isld[0] &= ~3; +-- +2.53.0 + diff --git a/queue-5.15/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch b/queue-5.15/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch new file mode 100644 index 0000000000..4f71f9c76f --- /dev/null +++ b/queue-5.15/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch @@ -0,0 +1,58 @@ +From e011e8f21b09b3f92ef2cad0cafed0c294dd97c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:49 +0100 +Subject: nfs/blocklayout: Fix compilation error (`make W=1`) in + bl_write_pagelist() + +From: Andy Shevchenko + +[ Upstream commit f83c8dda456ce4863f346aa26d88efa276eda35d ] + +Clang compiler is not happy about set but unused variable +(when dprintk() is no-op): + +.../blocklayout/blocklayout.c:384:9: error: variable 'count' set but not used [-Werror,-Wunused-but-set-variable] + +Remove a leftover from the previous cleanup. + +Fixes: 3a6fd1f004fc ("pnfs/blocklayout: remove read-modify-write handling in bl_write_pagelist") +Acked-by: Anna Schumaker +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/blocklayout/blocklayout.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c +index 76423557f5b3d..54a18a9540aae 100644 +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -399,14 +399,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + sector_t isect, extent_length = 0; + struct parallel_io *par = NULL; + loff_t offset = header->args.offset; +- size_t count = header->args.count; + struct page **pages = header->args.pages; + int pg_index = header->args.pgbase >> PAGE_SHIFT; + unsigned int pg_len; + struct blk_plug plug; + int i; + +- dprintk("%s enter, %zu@%lld\n", __func__, count, offset); ++ dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); + + /* At this point, header->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error +@@ -448,7 +447,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + } + + offset += pg_len; +- count -= pg_len; + isect += (pg_len >> SECTOR_SHIFT); + extent_length -= (pg_len >> SECTOR_SHIFT); + } +-- +2.53.0 + diff --git a/queue-5.15/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch b/queue-5.15/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch new file mode 100644 index 0000000000..51688517ee --- /dev/null +++ b/queue-5.15/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch @@ -0,0 +1,61 @@ +From 2ab3ea2d5f46c944de266ee5ad9c6edf9d290e3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:52:09 +0900 +Subject: nilfs2: reject zero bd_oblocknr in nilfs_ioctl_mark_blocks_dirty() + +From: Deepanshu Kartikey + +[ Upstream commit be3e5d10643d3be1cbac9d9939f220a99253f980 ] + +nilfs_ioctl_mark_blocks_dirty() uses bd_oblocknr to detect dead blocks +by comparing it with the current block number bd_blocknr. If they differ, +the block is considered dead and skipped. + +However, bd_oblocknr should never be 0 since block 0 typically stores the +primary superblock and is never a valid GC target block. A corrupted ioctl +request with bd_oblocknr set to 0 causes the comparison to incorrectly +match when the lookup returns -ENOENT and sets bd_blocknr to 0, bypassing +the dead block check and calling nilfs_bmap_mark() on a non-existent +block. This causes nilfs_btree_do_lookup() to return -ENOENT, triggering +the WARN_ON(ret == -ENOENT). + +Fix this by rejecting ioctl requests with bd_oblocknr set to 0 at the +beginning of each iteration. + +[ryusuke: slightly modified the commit message and comments for accuracy] + +Fixes: 7942b919f732 ("nilfs2: ioctl operations") +Reported-by: syzbot+98a040252119df0506f8@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=98a040252119df0506f8 +Suggested-by: Ryusuke Konishi +Signed-off-by: Deepanshu Kartikey +Reported-by: syzbot+466a45fcfb0562f5b9a0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=466a45fcfb0562f5b9a0 +Cc: Junjie Cao +Signed-off-by: Ryusuke Konishi +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/nilfs2/ioctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index 6a2f779e0bad4..77e6bae7d5c97 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -751,6 +751,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, + int ret, i; + + for (i = 0; i < nmembs; i++) { ++ /* ++ * bd_oblocknr must never be 0 as block 0 ++ * is never a valid GC target block ++ */ ++ if (unlikely(!bdescs[i].bd_oblocknr)) ++ return -EINVAL; + /* XXX: use macro or inline func to check liveness */ + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, +-- +2.53.0 + diff --git a/queue-5.15/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch b/queue-5.15/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch new file mode 100644 index 0000000000..613cb799d2 --- /dev/null +++ b/queue-5.15/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch @@ -0,0 +1,48 @@ +From 7722d352d5af99abd2bda19db5b9e7ac8b3cff0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:09 +0800 +Subject: ocfs2/dlm: fix off-by-one in dlm_match_regions() region comparison + +From: Junrui Luo + +[ Upstream commit 01b61e8dda9b0fdb0d4cda43de25f4e390554d7b ] + +The local-vs-remote region comparison loop uses '<=' instead of '<', +causing it to read one entry past the valid range of qr_regions. The +other loops in the same function correctly use '<'. + +Fix the loop condition to use '<' for consistency and correctness. + +Link: https://lkml.kernel.org/r/SYBPR01MB78813DA26B50EC5E01F00566AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 5a4b0f7293fa2..45b1ae68c179a 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1002,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + for (i = 0; i < localnr; ++i) { + foundit = 0; + r = remote; +- for (j = 0; j <= qr->qr_numregions; ++j) { ++ for (j = 0; j < qr->qr_numregions; ++j) { + if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { + foundit = 1; + break; +-- +2.53.0 + diff --git a/queue-5.15/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch b/queue-5.15/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch new file mode 100644 index 0000000000..78f2ca306b --- /dev/null +++ b/queue-5.15/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch @@ -0,0 +1,75 @@ +From 422de439d5deb5bed208a6fdbd7064eb376366eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:08 +0800 +Subject: ocfs2/dlm: validate qr_numregions in dlm_match_regions() + +From: Junrui Luo + +[ Upstream commit 7ab3fbb01bc6d79091bc375e5235d360cd9b78be ] + +Patch series "ocfs2/dlm: fix two bugs in dlm_match_regions()". + +In dlm_match_regions(), the qr_numregions field from a DLM_QUERY_REGION +network message is used to drive loops over the qr_regions buffer without +sufficient validation. This series fixes two issues: + +- Patch 1 adds a bounds check to reject messages where qr_numregions + exceeds O2NM_MAX_REGIONS. The o2net layer only validates message + byte length; it does not constrain field values, so a crafted message + can set qr_numregions up to 255 and trigger out-of-bounds reads past + the 1024-byte qr_regions buffer. + +- Patch 2 fixes an off-by-one in the local-vs-remote comparison loop, + which uses '<=' instead of '<', reading one entry past the valid range + even when qr_numregions is within bounds. + +This patch (of 2): + +The qr_numregions field from a DLM_QUERY_REGION network message is used +directly as loop bounds in dlm_match_regions() without checking against +O2NM_MAX_REGIONS. Since qr_regions is sized for at most O2NM_MAX_REGIONS +(32) entries, a crafted message with qr_numregions > 32 causes +out-of-bounds reads past the qr_regions buffer. + +Add a bounds check for qr_numregions before entering the loops. + +Link: https://lkml.kernel.org/r/SYBPR01MB7881A334D02ACEE5E0645801AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Link: https://lkml.kernel.org/r/SYBPR01MB788166F524AD04E262E174BEAF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 9f90fc9551e1a..5a4b0f7293fa2 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + goto bail; + } + ++ if (qr->qr_numregions > O2NM_MAX_REGIONS) { ++ mlog(ML_ERROR, "Domain %s: Joining node %d has invalid " ++ "number of heartbeat regions %u\n", ++ qr->qr_domain, qr->qr_node, qr->qr_numregions); ++ status = -EINVAL; ++ goto bail; ++ } ++ + r = remote; + for (i = 0; i < qr->qr_numregions; ++i) { + mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); +-- +2.53.0 + diff --git a/queue-5.15/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch b/queue-5.15/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch new file mode 100644 index 0000000000..ec89ba067e --- /dev/null +++ b/queue-5.15/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch @@ -0,0 +1,89 @@ +From 15c8b7d1037bcb1392e987432f38ee071658e07b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 12:03:39 +0800 +Subject: ocfs2: fix listxattr handling when the buffer is full + +From: ZhengYuan Huang + +[ Upstream commit d12f558e6200b3f47dbef9331ed6d115d2410e59 ] + +[BUG] +If an OCFS2 inode has both inline and block-based xattrs, listxattr() +can return a size larger than the caller's buffer when the inline names +consume that buffer exactly. + +kernel BUG at mm/usercopy.c:102! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:usercopy_abort+0xb7/0xd0 mm/usercopy.c:102 +Call Trace: + __check_heap_object+0xe3/0x120 mm/slub.c:8243 + check_heap_object mm/usercopy.c:196 [inline] + __check_object_size mm/usercopy.c:250 [inline] + __check_object_size+0x5c5/0x780 mm/usercopy.c:215 + check_object_size include/linux/ucopysize.h:22 [inline] + check_copy_size include/linux/ucopysize.h:59 [inline] + copy_to_user include/linux/uaccess.h:219 [inline] + listxattr+0xb0/0x170 fs/xattr.c:926 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x137/0x320 fs/xattr.c:988 + __do_sys_listxattr fs/xattr.c:1001 [inline] + __se_sys_listxattr fs/xattr.c:998 [inline] + __x64_sys_listxattr+0x7f/0xd0 fs/xattr.c:998 + ... + +[CAUSE] +Commit 936b8834366e ("ocfs2: Refactor xattr list and remove +ocfs2_xattr_handler().") replaced the old per-handler list accounting +with ocfs2_xattr_list_entry(), but it kept using size == 0 to detect +probe mode. + +That assumption stops being true once ocfs2_listxattr() finishes the +inline-xattr pass. If the inline names fill the caller buffer exactly, +the block-xattr pass runs with a non-NULL buffer and a remaining size of +zero. ocfs2_xattr_list_entry() then skips the bounds check, keeps +counting block names, and returns a positive size larger than the +supplied buffer. + +[FIX] +Detect probe mode by testing whether the destination buffer pointer is +NULL instead of whether the remaining size is zero. + +That restores the pre-refactor behavior and matches the OCFS2 getxattr +helpers. Once the remaining buffer reaches zero while more names are +left, the block-xattr pass now returns -ERANGE instead of reporting a +size larger than the allocated list buffer. + +Link: https://lkml.kernel.org/r/20260410040339.3837162-1-gality369@gmail.com +Fixes: 936b8834366e ("ocfs2: Refactor xattr list and remove ocfs2_xattr_handler().") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 7ac7cb6117d4f..1f22ad21ae608 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -911,8 +911,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb, + total_len = prefix_len + name_len + 1; + *result += total_len; + +- /* we are just looking for how big our buffer needs to be */ +- if (!size) ++ /* No buffer means we are only looking for the required size. */ ++ if (!buffer) + return 0; + + if (*result > size) +-- +2.53.0 + diff --git a/queue-5.15/ocfs2-validate-bg_bits-during-freefrag-scan.patch b/queue-5.15/ocfs2-validate-bg_bits-during-freefrag-scan.patch new file mode 100644 index 0000000000..08246007fd --- /dev/null +++ b/queue-5.15/ocfs2-validate-bg_bits-during-freefrag-scan.patch @@ -0,0 +1,121 @@ +From fb897977994ea23eef4ec3e4782ef46581b0df2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:42:20 +0800 +Subject: ocfs2: validate bg_bits during freefrag scan + +From: ZhengYuan Huang + +[ Upstream commit 8f687eeed3da3012152b0f9473f578869de0cd7b ] + +[BUG] +A crafted filesystem can trigger an out-of-bounds bitmap walk when +OCFS2_IOC_INFO is issued with OCFS2_INFO_FL_NON_COHERENT. + +BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:68 [inline] +BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] +BUG: KASAN: use-after-free in test_bit_le include/asm-generic/bitops/le.h:21 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 +Read of size 8 at addr ffff888031bce000 by task syz.0.636/1435 +Call Trace: + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xd1/0x650 mm/kasan/report.c:482 + kasan_report+0xfb/0x140 mm/kasan/report.c:595 + check_region_inline mm/kasan/generic.c:186 [inline] + kasan_check_range+0x11c/0x200 mm/kasan/generic.c:200 + __kasan_check_read+0x11/0x20 mm/kasan/shadow.c:31 + instrument_atomic_read include/linux/instrumented.h:68 [inline] + _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] + test_bit_le include/asm-generic/bitops/le.h:21 [inline] + ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] + ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] + ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] + ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 + ocfs2_info_handle+0x18d/0x2a0 fs/ocfs2/ioctl.c:828 + ocfs2_ioctl+0x632/0x6e0 fs/ocfs2/ioctl.c:913 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + ... + +[CAUSE] +ocfs2_info_freefrag_scan_chain() uses on-disk bg_bits directly as the +bitmap scan limit. The coherent path reads group descriptors through +ocfs2_read_group_descriptor(), which validates the descriptor before +use. The non-coherent path uses ocfs2_read_blocks_sync() instead and +skips that validation, so an impossible bg_bits value can drive the +bitmap walk past the end of the block. + +[FIX] +Compute the bitmap capacity from the filesystem format with +ocfs2_group_bitmap_size(), report descriptors whose bg_bits exceeds +that limit, and clamp the scan to the computed capacity. This keeps the +freefrag report going while avoiding reads beyond the buffer. + +Link: https://lkml.kernel.org/r/20260410034220.3825769-1-gality369@gmail.com +Fixes: d24a10b9f8ed ("Ocfs2: Add a new code 'OCFS2_INFO_FREEFRAG' for o2info ioctl.") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Heming Zhao +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/ioctl.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c +index f59461d85da45..f9c66b172d304 100644 +--- a/fs/ocfs2/ioctl.c ++++ b/fs/ocfs2/ioctl.c +@@ -442,13 +442,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + struct buffer_head *bh = NULL; + struct ocfs2_group_desc *bg = NULL; + +- unsigned int max_bits, num_clusters; ++ unsigned int max_bits, max_bitmap_bits, num_clusters; + unsigned int offset = 0, cluster, chunk; + unsigned int chunk_free, last_chunksize = 0; + + if (!le32_to_cpu(rec->c_free)) + goto bail; + ++ max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0, ++ osb->s_feature_incompat); ++ + do { + if (!bg) + blkno = le64_to_cpu(rec->c_blkno); +@@ -480,6 +483,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + continue; + + max_bits = le16_to_cpu(bg->bg_bits); ++ ++ /* ++ * Non-coherent scans read raw blocks and do not get the ++ * bg_bits validation from ++ * ocfs2_read_group_descriptor(). ++ */ ++ if (max_bits > max_bitmap_bits) { ++ mlog(ML_ERROR, ++ "Group desc #%llu has %u bits, max bitmap bits %u\n", ++ (unsigned long long)blkno, max_bits, max_bitmap_bits); ++ max_bits = max_bitmap_bits; ++ } ++ + offset = 0; + + for (chunk = 0; chunk < chunks_in_group; chunk++) { +-- +2.53.0 + diff --git a/queue-5.15/ocfs2-validate-group-add-input-before-caching.patch b/queue-5.15/ocfs2-validate-group-add-input-before-caching.patch new file mode 100644 index 0000000000..aacde2ee79 --- /dev/null +++ b/queue-5.15/ocfs2-validate-group-add-input-before-caching.patch @@ -0,0 +1,110 @@ +From 5f8c1c68d10c8b6e362ae229640887acb00981bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 10:02:08 +0800 +Subject: ocfs2: validate group add input before caching + +From: ZhengYuan Huang + +[ Upstream commit 70b672833f4025341c11b22c7f83778a5cd611bc ] + +[BUG] +OCFS2_IOC_GROUP_ADD can trigger a BUG_ON in +ocfs2_set_new_buffer_uptodate(): + +kernel BUG at fs/ocfs2/uptodate.c:509! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:ocfs2_set_new_buffer_uptodate+0x194/0x1e0 fs/ocfs2/uptodate.c:509 +Code: ffffe88f 42b9fe4c 89e64889 dfe8b4df +Call Trace: + ocfs2_group_add+0x3f1/0x1510 fs/ocfs2/resize.c:507 + ocfs2_ioctl+0x309/0x6e0 fs/ocfs2/ioctl.c:887 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + x64_sys_call+0x1144/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:17 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e +RIP: 0033:0x7bbfb55a966d + +[CAUSE] +ocfs2_group_add() calls ocfs2_set_new_buffer_uptodate() on a +user-controlled group block before ocfs2_verify_group_and_input() +validates that block number. That helper is only valid for newly +allocated metadata and asserts that the block is not already present in +the chosen metadata cache. The code also uses INODE_CACHE(inode) even +though the group descriptor belongs to main_bm_inode and later journal +accesses use that cache context instead. + +[FIX] +Validate the on-disk group descriptor before caching it, then add it to +the metadata cache tracked by INODE_CACHE(main_bm_inode). Keep the +validation failure path separate from the later cleanup path so we only +remove the buffer from that cache after it has actually been inserted. +This keeps the group buffer lifetime consistent across validation, +journaling, and cleanup. + +Link: https://lkml.kernel.org/r/20260410020209.3786348-1-gality369@gmail.com +Fixes: 7909f2bf8353 ("[PATCH 2/2] ocfs2: Implement group add for online resize") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/resize.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c +index 42c0d314f95e8..acf2769f4c8c7 100644 +--- a/fs/ocfs2/resize.c ++++ b/fs/ocfs2/resize.c +@@ -500,14 +500,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + goto out_unlock; + } + +- ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); +- + ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); + if (ret) { + mlog_errno(ret); + goto out_free_group_bh; + } + ++ ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh); ++ + trace_ocfs2_group_add((unsigned long long)input->group, + input->chain, input->clusters, input->frees); + +@@ -515,7 +515,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + if (IS_ERR(handle)) { + mlog_errno(PTR_ERR(handle)); + ret = -EINVAL; +- goto out_free_group_bh; ++ goto out_remove_cache; + } + + cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); +@@ -569,9 +569,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + out_commit: + ocfs2_commit_trans(osb, handle); + +-out_free_group_bh: ++out_remove_cache: + if (ret < 0) +- ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); ++ ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh); ++ ++out_free_group_bh: + brelse(group_bh); + + out_unlock: +-- +2.53.0 + diff --git a/queue-5.15/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch b/queue-5.15/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch new file mode 100644 index 0000000000..c1668a5a9e --- /dev/null +++ b/queue-5.15/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch @@ -0,0 +1,132 @@ +From 47d162725887c8ef231a4c1d096b1192538adc61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 19:46:54 -0700 +Subject: openvswitch: cap upcall PID array size and pre-size vport replies + +From: Weiming Shi + +[ Upstream commit 2091c6aa0df6aba47deb5c8ab232b1cb60af3519 ] + +The vport netlink reply helpers allocate a fixed-size skb with +nlmsg_new(NLMSG_DEFAULT_SIZE, ...) but serialize the full upcall PID +array via ovs_vport_get_upcall_portids(). Since +ovs_vport_set_upcall_portids() accepts any non-zero multiple of +sizeof(u32) with no upper bound, a CAP_NET_ADMIN user can install a PID +array large enough to overflow the reply buffer, causing nla_put() to +fail with -EMSGSIZE and hitting BUG_ON(err < 0). On systems with +unprivileged user namespaces enabled (e.g., Ubuntu default), this is +reachable via unshare -Urn since OVS vport mutation operations use +GENL_UNS_ADMIN_PERM. + + kernel BUG at net/openvswitch/datapath.c:2414! + Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI + CPU: 1 UID: 0 PID: 65 Comm: poc Not tainted 7.0.0-rc7-00195-geb216e422044 #1 + RIP: 0010:ovs_vport_cmd_set+0x34c/0x400 + Call Trace: + + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1116) + genl_rcv_msg (net/netlink/genetlink.c:1194) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + genl_rcv (net/netlink/genetlink.c:1219) + netlink_unicast (net/netlink/af_netlink.c:1344) + netlink_sendmsg (net/netlink/af_netlink.c:1894) + __sys_sendto (net/socket.c:2206) + __x64_sys_sendto (net/socket.c:2209) + do_syscall_64 (arch/x86/entry/syscall_64.c:63) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + + Kernel panic - not syncing: Fatal exception + +Reject attempts to set more PIDs than nr_cpu_ids in +ovs_vport_set_upcall_portids(), and pre-compute the worst-case reply +size in ovs_vport_cmd_msg_size() based on that bound, similar to the +existing ovs_dp_cmd_msg_size(). nr_cpu_ids matches the cap already +used by the per-CPU dispatch configuration on the datapath side +(ovs_dp_cmd_fill_info() serialises at most nr_cpu_ids PIDs), so the +two sides stay consistent. + +Fixes: 5cd667b0a456 ("openvswitch: Allow each vport to have an array of 'port_id's.") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Weiming Shi +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260416024653.153456-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 35 +++++++++++++++++++++++++++++++++-- + net/openvswitch/vport.c | 3 +++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index c28b56c309169..16ee704bab04d 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -2110,9 +2110,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + return err; + } + ++static size_t ovs_vport_cmd_msg_size(void) ++{ ++ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); ++ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */ ++ msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */ ++ msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */ ++ ++ /* OVS_VPORT_ATTR_STATS */ ++ msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats)); ++ ++ /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + ++ * OVS_VPORT_UPCALL_ATTR_FAIL) ++ */ ++ msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) + ++ nla_total_size_64bit(sizeof(u64))); ++ ++ /* OVS_VPORT_ATTR_UPCALL_PID */ ++ msgsize += nla_total_size(nr_cpu_ids * sizeof(u32)); ++ ++ /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + ++ * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) ++ */ ++ msgsize += nla_total_size(nla_total_size(sizeof(u16)) + ++ nla_total_size(nla_total_size(0))); ++ ++ return msgsize; ++} ++ + static struct sk_buff *ovs_vport_cmd_alloc_info(void) + { +- return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL); + } + + /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ +@@ -2122,7 +2153,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, + struct sk_buff *skb; + int retval; + +- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ skb = ovs_vport_cmd_alloc_info(); + if (!skb) + return ERR_PTR(-ENOMEM); + +diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c +index cf2ce58124896..25197e14c123b 100644 +--- a/net/openvswitch/vport.c ++++ b/net/openvswitch/vport.c +@@ -342,6 +342,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids) + if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) + return -EINVAL; + ++ if (nla_len(ids) / sizeof(u32) > nr_cpu_ids) ++ return -EINVAL; ++ + old = ovsl_dereference(vport->upcall_portids); + + vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), +-- +2.53.0 + diff --git a/queue-5.15/params-replace-__modinit-with-__init_or_module.patch b/queue-5.15/params-replace-__modinit-with-__init_or_module.patch new file mode 100644 index 0000000000..3681cf622c --- /dev/null +++ b/queue-5.15/params-replace-__modinit-with-__init_or_module.patch @@ -0,0 +1,67 @@ +From 5024a0d81a74540af02b50f59965a5aaff8a6627 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Aug 2025 14:12:09 +0200 +Subject: params: Replace __modinit with __init_or_module + +From: Petr Pavlu + +[ Upstream commit 3cb0c3bdea5388519bc1bf575dca6421b133302b ] + +Remove the custom __modinit macro from kernel/params.c and instead use the +common __init_or_module macro from include/linux/module.h. Both provide the +same functionality. + +Signed-off-by: Petr Pavlu +Reviewed-by: Aaron Tomlin +Reviewed-by: Daniel Gomez +Reviewed-by: Sami Tolvanen +Signed-off-by: Sami Tolvanen +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + kernel/params.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +diff --git a/kernel/params.c b/kernel/params.c +index cedda487df96b..9a76f556b898a 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -592,12 +592,6 @@ static ssize_t param_attr_store(struct module_attribute *mattr, + } + #endif + +-#ifdef CONFIG_MODULES +-#define __modinit +-#else +-#define __modinit __init +-#endif +- + #ifdef CONFIG_SYSFS + void kernel_param_lock(struct module *mod) + { +@@ -622,9 +616,9 @@ EXPORT_SYMBOL(kernel_param_unlock); + * create file in sysfs. Returns an error on out of memory. Always cleans up + * if there's an error. + */ +-static __modinit int add_sysfs_param(struct module_kobject *mk, +- const struct kernel_param *kp, +- const char *name) ++static __init_or_module int add_sysfs_param(struct module_kobject *mk, ++ const struct kernel_param *kp, ++ const char *name) + { + struct module_param_attrs *new_mp; + struct attribute **new_attrs; +@@ -758,7 +752,8 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) ++struct module_kobject * __init_or_module ++lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +-- +2.53.0 + diff --git a/queue-5.15/pci-add-pcie_pme_to_l2_timeout_us-l2-ready-timeout-v.patch b/queue-5.15/pci-add-pcie_pme_to_l2_timeout_us-l2-ready-timeout-v.patch new file mode 100644 index 0000000000..a3ce5e72bb --- /dev/null +++ b/queue-5.15/pci-add-pcie_pme_to_l2_timeout_us-l2-ready-timeout-v.patch @@ -0,0 +1,42 @@ +From 571c4c52f79a193ba353ad03725d021ed0a1e131 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Aug 2023 14:48:13 -0400 +Subject: PCI: Add PCIE_PME_TO_L2_TIMEOUT_US L2 ready timeout value + +From: Frank Li + +[ Upstream commit e78bd50b4078b3b2d9f85d97796b7c271e7860ca ] + +Add the PCIE_PME_TO_L2_TIMEOUT_US macro to define the L2 ready timeout +as described in the PCI specifications. + +Link: https://lore.kernel.org/r/20230821184815.2167131-2-Frank.Li@nxp.com +Signed-off-by: Frank Li +Signed-off-by: Lorenzo Pieralisi +Acked-by: Manivannan Sadhasivam +Stable-dep-of: adaffed907f1 ("PCI: tegra194: Fix polling delay for L2 state") +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index adae3e04c8c30..eda82a771ab82 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -14,6 +14,12 @@ + #define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) + ++/* ++ * PCIe r6.0, sec 5.3.3.2.1 ++ * Recommends 1ms to 10ms timeout to check L2 ready. ++ */ ++#define PCIE_PME_TO_L2_TIMEOUT_US 10000 ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +-- +2.53.0 + diff --git a/queue-5.15/pci-enable-atomicops-only-if-root-port-supports-them.patch b/queue-5.15/pci-enable-atomicops-only-if-root-port-supports-them.patch new file mode 100644 index 0000000000..16d041283e --- /dev/null +++ b/queue-5.15/pci-enable-atomicops-only-if-root-port-supports-them.patch @@ -0,0 +1,110 @@ +From 99790f1bc675c2abc996c81517d73c615f2e9fb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:09:45 +0200 +Subject: PCI: Enable AtomicOps only if Root Port supports them + +From: Gerd Bayer + +[ Upstream commit 1ae8c4ce157037e266184064a182af9ef9af278b ] + +When inspecting the config space of a Connect-X physical function in an +s390 system after it was initialized by the mlx5_core device driver, we +found the function to be enabled to request AtomicOps despite the Root Port +lacking support for completing them: + + 00:00.1 Ethernet controller: Mellanox Technologies MT2894 Family [ConnectX-6 Lx] + Subsystem: Mellanox Technologies Device 0002 + DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- + AtomicOpsCtl: ReqEn+ + +On s390 and many virtualized guests, the Endpoint is visible but the Root +Port is not. In this case, pci_enable_atomic_ops_to_root() previously +enabled AtomicOps in the Endpoint even though it can't tell whether the +Root Port supports them as a completer. + +Change pci_enable_atomic_ops_to_root() to fail if there's no Root Port or +the Root Port doesn't support AtomicOps. + +Fixes: 430a23689dea ("PCI: Add pci_enable_atomic_ops_to_root()") +Reported-by: Alexander Schmidt +Signed-off-by: Gerd Bayer +[bhelgaas: commit log, check RP first to simplify flow] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260330-fix_pciatops-v7-2-f601818417e8@linux.ibm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 41 ++++++++++++++++++++--------------------- + 1 file changed, 20 insertions(+), 21 deletions(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 5233490502dd1..a67207649ce39 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -3742,8 +3742,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) + */ + int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + { +- struct pci_bus *bus = dev->bus; +- struct pci_dev *bridge; ++ struct pci_dev *root, *bridge; + u32 cap, ctl2; + + /* +@@ -3773,35 +3772,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + return -EINVAL; + } + +- while (bus->parent) { +- bridge = bus->self; ++ root = pcie_find_root_port(dev); ++ if (!root) ++ return -EINVAL; + +- pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap); ++ pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); ++ if ((cap & cap_mask) != cap_mask) ++ return -EINVAL; + ++ bridge = pci_upstream_bridge(dev); ++ while (bridge != root) { + switch (pci_pcie_type(bridge)) { +- /* Ensure switch ports support AtomicOp routing */ + case PCI_EXP_TYPE_UPSTREAM: +- case PCI_EXP_TYPE_DOWNSTREAM: +- if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) +- return -EINVAL; +- break; +- +- /* Ensure root port supports all the sizes we care about */ +- case PCI_EXP_TYPE_ROOT_PORT: +- if ((cap & cap_mask) != cap_mask) +- return -EINVAL; +- break; +- } +- +- /* Ensure upstream ports don't block AtomicOps on egress */ +- if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) { ++ /* Upstream ports must not block AtomicOps on egress */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, + &ctl2); + if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK) + return -EINVAL; ++ fallthrough; ++ ++ /* All switch ports need to route AtomicOps */ ++ case PCI_EXP_TYPE_DOWNSTREAM: ++ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, ++ &cap); ++ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) ++ return -EINVAL; ++ break; + } + +- bus = bus->parent; ++ bridge = pci_upstream_bridge(bridge); + } + + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, +-- +2.53.0 + diff --git a/queue-5.15/pci-tegra194-disable-direct-speed-change-for-endpoin.patch b/queue-5.15/pci-tegra194-disable-direct-speed-change-for-endpoin.patch new file mode 100644 index 0000000000..10762d3739 --- /dev/null +++ b/queue-5.15/pci-tegra194-disable-direct-speed-change-for-endpoin.patch @@ -0,0 +1,52 @@ +From a5ce72baa6d7fbcd18f8cf7767b018d6d97d2b73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:48 +0530 +Subject: PCI: tegra194: Disable direct speed change for Endpoint mode + +From: Vidya Sagar + +[ Upstream commit 976f6763f57970388bcd7118931f33f447916927 ] + +Pre-silicon simulation showed the controller operating in Endpoint mode +initiating link speed change after completing Secondary Bus Reset. Ideally, +the Root Port or the Switch Downstream Port should initiate the link speed +change post SBR, not the Endpoint. + +So, as per the hardware team recommendation, disable direct speed change +for the Endpoint mode to prevent it from initiating speed change after the +physical layer link is up at Gen1, leaving speed change ownership with the +host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-8-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index d5f48aa6bf5a2..3fd89a983f6d2 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1774,6 +1774,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); ++ val &= ~PORT_LOGIC_SPEED_CHANGE; ++ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); ++ + if (pcie->update_fc_fixup) { + val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); + val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; +-- +2.53.0 + diff --git a/queue-5.15/pci-tegra194-disable-ltssm-after-transition-to-detec.patch b/queue-5.15/pci-tegra194-disable-ltssm-after-transition-to-detec.patch new file mode 100644 index 0000000000..4ed6143c86 --- /dev/null +++ b/queue-5.15/pci-tegra194-disable-ltssm-after-transition-to-detec.patch @@ -0,0 +1,92 @@ +From d3e25e39c8be65c76a06ba1a011de60cac9cf176 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:44 +0530 +Subject: PCI: tegra194: Disable LTSSM after transition to Detect on surprise + link down + +From: Manikanta Maddireddy + +[ Upstream commit 9fa0c242f8d7acf1b124d4462d18f4023573ac1c ] + +After the link reaches a Detect-related LTSSM state, disable LTSSM so it +does not keep toggling between Polling and Detect. Do this by polling for +the Detect state first, then clearing APPL_CTRL_LTSSM_EN in both +tegra_pcie_dw_pme_turnoff() and pex_ep_event_pex_rst_assert(). + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-4-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 29 ++++++++++++---------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index a7ab82067d538..c32184e8e5636 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1539,14 +1539,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_PINMUX_PEX_RST; + appl_writel(pcie, data, APPL_PINMUX); + +- /* +- * Some cards do not go to detect state even after de-asserting +- * PERST#. So, de-assert LTSSM to bring link to detect state. +- */ +- data = readl(pcie->appl_base + APPL_CTRL); +- data &= ~APPL_CTRL_LTSSM_EN; +- writel(data, pcie->appl_base + APPL_CTRL); +- + err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1555,6 +1547,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); ++ ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ data = readl(pcie->appl_base + APPL_CTRL); ++ data &= ~APPL_CTRL_LTSSM_EN; ++ writel(data, pcie->appl_base + APPL_CTRL); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1636,11 +1636,6 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (pcie->ep_state == EP_STATE_DISABLED) + return; + +- /* Disable LTSSM */ +- val = appl_readl(pcie, APPL_CTRL); +- val &= ~APPL_CTRL_LTSSM_EN; +- appl_writel(pcie, val, APPL_CTRL); +- + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1651,6 +1646,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (ret) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ val = appl_readl(pcie, APPL_CTRL); ++ val &= ~APPL_CTRL_LTSSM_EN; ++ appl_writel(pcie, val, APPL_CTRL); ++ + reset_control_assert(pcie->core_rst); + + tegra_pcie_disable_phy(pcie); +-- +2.53.0 + diff --git a/queue-5.15/pci-tegra194-fix-polling-delay-for-l2-state.patch b/queue-5.15/pci-tegra194-fix-polling-delay-for-l2-state.patch new file mode 100644 index 0000000000..f0a0e8950b --- /dev/null +++ b/queue-5.15/pci-tegra194-fix-polling-delay-for-l2-state.patch @@ -0,0 +1,59 @@ +From 59f840a341d3e81cf3c88d97f3903c7a1d57adde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:42 +0530 +Subject: PCI: tegra194: Fix polling delay for L2 state + +From: Vidya Sagar + +[ Upstream commit adaffed907f14f954096555665ad6af2ae724d83 ] + +As per PCIe r7.0, sec 5.3.3.2.1, after sending PME_Turn_Off message, Root +Port should wait for 1-10 msec for PME_TO_Ack message. Currently, driver is +polling for 10 msec with 1 usec delay which is aggressive. Use existing +macro PCIE_PME_TO_L2_TIMEOUT_US to poll for 10 msec with 1 msec delay. +Since this function is used in non-atomic context only, use non-atomic poll +function. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 882e739d00128..8782ad616caa1 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -221,8 +221,6 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define PME_ACK_TIMEOUT 10000 +- + #define LTSSM_TIMEOUT 50000 /* 50ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 +@@ -1498,9 +1496,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) + val |= APPL_PM_XMT_TURNOFF_STATE; + appl_writel(pcie, val, APPL_RADM_STATUS); + +- return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val, +- val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, +- 1, PME_ACK_TIMEOUT); ++ return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, ++ val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, ++ PCIE_PME_TO_L2_TIMEOUT_US/10, ++ PCIE_PME_TO_L2_TIMEOUT_US); + } + + static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) +-- +2.53.0 + diff --git a/queue-5.15/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch b/queue-5.15/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch new file mode 100644 index 0000000000..76f7bb602e --- /dev/null +++ b/queue-5.15/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch @@ -0,0 +1,106 @@ +From f8238fe627171c1d17b2ae7ce7d077f3cf7df9e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:43 +0530 +Subject: PCI: tegra194: Increase LTSSM poll time on surprise link down + +From: Manikanta Maddireddy + +[ Upstream commit 74dd8efe4d6cead433162147333af989a568aac7 ] + +On surprise link down, LTSSM state transits from L0 -> Recovery.RcvrLock -> +Recovery.RcvrSpeed -> Gen1 Recovery.RcvrLock -> Detect. Recovery.RcvrLock +and Recovery.RcvrSpeed transit times are 24 ms and 48 ms respectively, so +the total time from L0 to Detect is ~96 ms. Increase the poll timeout to +120 ms to account for this. + +While at it, add LTSSM state defines for Detect-related states and use them +in the poll condition. Use readl_poll_timeout() instead of +readl_poll_timeout_atomic() in tegra_pcie_dw_pme_turnoff() since that path +runs in non-atomic context. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-3-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 36 +++++++++++++--------- + 1 file changed, 21 insertions(+), 15 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 8782ad616caa1..a7ab82067d538 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -134,7 +134,11 @@ + #define APPL_DEBUG_PM_LINKST_IN_L0 0x11 + #define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) + #define APPL_DEBUG_LTSSM_STATE_SHIFT 3 +-#define LTSSM_STATE_PRE_DETECT 5 ++#define LTSSM_STATE_DETECT_QUIET 0x00 ++#define LTSSM_STATE_DETECT_ACT 0x08 ++#define LTSSM_STATE_PRE_DETECT_QUIET 0x28 ++#define LTSSM_STATE_DETECT_WAIT 0x30 ++#define LTSSM_STATE_L2_IDLE 0xa8 + + #define APPL_RADM_STATUS 0xE4 + #define APPL_PM_XMT_TURNOFF_STATE BIT(0) +@@ -221,7 +225,8 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define LTSSM_TIMEOUT 50000 /* 50ms */ ++#define LTSSM_DELAY_US 10000 /* 10 ms */ ++#define LTSSM_TIMEOUT_US 120000 /* 120 ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 + +@@ -1542,15 +1547,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_CTRL_LTSSM_EN; + writel(data, pcie->appl_base + APPL_CTRL); + +- err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, +- data, +- ((data & +- APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) +- dev_info(pcie->dev, "Link didn't go to detect state\n"); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1638,12 +1642,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + appl_writel(pcie, val, APPL_CTRL); + + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, +- ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (ret) +- dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + + reset_control_assert(pcie->core_rst); + +-- +2.53.0 + diff --git a/queue-5.15/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch b/queue-5.15/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch new file mode 100644 index 0000000000..fb0be6df46 --- /dev/null +++ b/queue-5.15/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch @@ -0,0 +1,47 @@ +From d7405e082fa32118232d97221e39edb135148d92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:47 +0530 +Subject: PCI: tegra194: Use devm_gpiod_get_optional() to parse + "nvidia,refclk-select" + +From: Vidya Sagar + +[ Upstream commit f62bc7917de1374dce86a852ffba8baf9cb7a56a ] + +The GPIO DT property "nvidia,refclk-select", to select the PCIe reference +clock is optional. Use devm_gpiod_get_optional() to get it. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-7-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index c32184e8e5636..d5f48aa6bf5a2 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1146,9 +1146,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) + return err; + } + +- pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, +- "nvidia,refclk-select", +- GPIOD_OUT_HIGH); ++ pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev, ++ "nvidia,refclk-select", ++ GPIOD_OUT_HIGH); + if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { + int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); + const char *level = KERN_ERR; +-- +2.53.0 + diff --git a/queue-5.15/pcmcia-fix-garbled-log-messages-for-kern_cont.patch b/queue-5.15/pcmcia-fix-garbled-log-messages-for-kern_cont.patch new file mode 100644 index 0000000000..23e7401284 --- /dev/null +++ b/queue-5.15/pcmcia-fix-garbled-log-messages-for-kern_cont.patch @@ -0,0 +1,55 @@ +From 1be8123bb86f652f304c1ef7c0a9bb041e578fd9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 17:42:56 +0100 +Subject: PCMCIA: Fix garbled log messages for KERN_CONT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit bfeaa6814bd3f9a1f6d525b3b35a03b9a0368961 ] + +For years the PCMCIA info messages are messed up by superfluous +newlines. While f2e6cf76751d ("pcmcia: Convert dev_printk to +dev_") converted the code to pr_cont(), dev_info enforces a \n +via vprintk_store setting LOG_NEWLINE, breaking subsequent pr_cont. + +Fix by logging the device name manually to allow pr_cont to work for +more readable and not \n distorted logs. + +Fixes: f2e6cf76751d ("pcmcia: Convert dev_printk to dev_") +Signed-off-by: René Rebe +Signed-off-by: Dominik Brodowski +Signed-off-by: Sasha Levin +--- + drivers/pcmcia/rsrc_nonstatic.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c +index 58782f21a442a..50e8e8522708c 100644 +--- a/drivers/pcmcia/rsrc_nonstatic.c ++++ b/drivers/pcmcia/rsrc_nonstatic.c +@@ -188,7 +188,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, + int any; + u_char *b, hole, most; + +- dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1); ++ pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1); + + /* First, what does a floating port look like? */ + b = kzalloc(256, GFP_KERNEL); +@@ -410,8 +410,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + struct socket_data *s_data = s->resource_data; + u_long i, j, bad, fail, step; + +- dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:", +- base, base+num-1); ++ pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:", ++ dev_name(&s->dev), base, base+num-1); + bad = fail = 0; + step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + /* don't allow too large steps */ +-- +2.53.0 + diff --git a/queue-5.15/perf-branch-avoid-incrementing-null.patch b/queue-5.15/perf-branch-avoid-incrementing-null.patch new file mode 100644 index 0000000000..edda4f80ec --- /dev/null +++ b/queue-5.15/perf-branch-avoid-incrementing-null.patch @@ -0,0 +1,39 @@ +From cc753a170e25c20edd4a16f1106914c9c2716118 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:31:31 -0700 +Subject: perf branch: Avoid incrementing NULL + +From: Ian Rogers + +[ Upstream commit c969a9d7bbf46f983c4a48566b3b2f7340b02296 ] + +If the entry is NULL the value is meaningless so early return NULL to +avoid an increment of NULL. This was happening in calls from +has_stitched_lbr when running the "perf record LBR tests". The return +value isn't used in that case, so returning NULL as no effect. + +Fixes: 42bbabed09ce ("perf tools: Add hw_idx in struct branch_stack") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/branch.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h +index 17b2ccc61094b..9a20b6fc8dda2 100644 +--- a/tools/perf/util/branch.h ++++ b/tools/perf/util/branch.h +@@ -63,6 +63,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl + { + u64 *entry = (u64 *)sample->branch_stack; + ++ if (entry == NULL) ++ return NULL; ++ + entry++; + if (sample->no_hw_idx) + return (struct branch_entry *)entry; +-- +2.53.0 + diff --git a/queue-5.15/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch b/queue-5.15/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch new file mode 100644 index 0000000000..24905a22a0 --- /dev/null +++ b/queue-5.15/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch @@ -0,0 +1,57 @@ +From bbb5584443048501b565b2c5b303e665bd5675e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:04:47 +0100 +Subject: perf expr: Return -EINVAL for syntax error in expr__find_ids() + +From: Leo Yan + +[ Upstream commit 3a61fd866ef9aaa1d3158b460f852b74a2df07f4 ] + +expr__find_ids() propagates the parser return value directly. For syntax +errors, the parser can return a positive value, but callers treat it as +success, e.g., for below case on Arm64 platform: + + metric expr 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) for backend_bound + parsing metric: 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) + Failure to read '#slots' literal: #slots = nan + syntax error + +Convert positive parser returns in expr__find_ids() to -EINVAL, as a +result, the error value will be respected by callers. + +Before: + + perf stat -C 5 + Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Segmentation fault + +After: + + perf stat -C 5 + Failure to read '#slots'Cannot find metric or group `Default' + +Fixes: ded80bda8bc9 ("perf expr: Migrate expr ids table to a hashmap") +Signed-off-by: Leo Yan +Reviewed-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/expr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index a850fd0be3ee2..45e54c1caa724 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -275,7 +275,8 @@ int expr__find_other(const char *expr, const char *one, + if (one) + expr__del_id(ctx, one); + +- return ret; ++ /* A positive value means syntax error, convert to -EINVAL */ ++ return ret > 0 ? -EINVAL : ret; + } + + double expr_id_data__value(const struct expr_id_data *data) +-- +2.53.0 + diff --git a/queue-5.15/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch b/queue-5.15/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch new file mode 100644 index 0000000000..ca860e63ae --- /dev/null +++ b/queue-5.15/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch @@ -0,0 +1,115 @@ +From 1ba9c8fed681713730fe79e6b3c9eeea330731a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:36:39 +0000 +Subject: perf: tools: cs-etm: Fix print issue for Coresight debug in ETE/TRBE + trace + +From: Mike Leach + +[ Upstream commit 6c478e7b3eba3f387a2d6c749e3e3ee0f8ad1c53 ] + +Building perf with CORESIGHT=1 and the optional CSTRACE_RAW=1 enables +additional debug printing of raw trace data when using command:- +perf report --dump. + +This raw trace prints the CoreSight formatted trace frames, which may be +used to investigate suspected issues with trace quality / corruption / +decode. + +These frames are not present in ETE + TRBE trace. +This fix removes the unnecessary call to print these frames. + +This fix also rationalises implementation - original code had helper +function that unnecessarily repeated initialisation calls that had +already been made. + +Due to an addtional fault with the OpenCSD library, this call when ETE/TRBE +are being decoded will cause a segfault in perf. This fix also prevents +that problem for perf using older (<= 1.8.0 version) OpenCSD libraries. + +Fixes: 68ffe3902898 ("perf tools: Add decoder mechanic to support dumping trace data") +Reported-by: Leo Yan +Signed-off-by: Mike Leach +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 51 +++++-------------- + 1 file changed, 13 insertions(+), 38 deletions(-) + +diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +index 31fa3b45134a2..fc74a95a23faf 100644 +--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c ++++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +@@ -214,46 +214,24 @@ cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, + (void *)decoder, + cs_etm_decoder__print_str_cb); + if (ret != 0) +- ret = -1; +- +- return 0; +-} ++ return -1; + + #ifdef CS_LOG_RAW_FRAMES +-static void +-cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params, +- struct cs_etm_decoder *decoder) +-{ +- /* Only log these during a --dump operation */ +- if (d_params->operation == CS_ETM_OPERATION_PRINT) { +- /* set up a library default logger to process the +- * raw frame printer we add later +- */ +- ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); +- +- /* no stdout / err / file output */ +- ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); +- +- /* set the string CB for the default logger, +- * passes strings to perf print logger. +- */ +- ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, +- (void *)decoder, +- cs_etm_decoder__print_str_cb); +- ++ /* ++ * Only log raw frames if --dump operation and hardware is actually ++ * generating formatted CoreSight trace frames ++ */ ++ if ((d_params->operation == CS_ETM_OPERATION_PRINT) && ++ (d_params->formatted == true)) { + /* use the built in library printer for the raw frames */ +- ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, +- CS_RAW_DEBUG_FLAGS); ++ ret = ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, ++ CS_RAW_DEBUG_FLAGS); ++ if (ret != 0) ++ return -1; + } +-} +-#else +-static void +-cs_etm_decoder__init_raw_frame_logging( +- struct cs_etm_decoder_params *d_params __maybe_unused, +- struct cs_etm_decoder *decoder __maybe_unused) +-{ +-} + #endif ++ return 0; ++} + + static ocsd_datapath_resp_t + cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, +@@ -716,9 +694,6 @@ cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params, + if (ret != 0) + goto err_free_decoder; + +- /* init raw frame logging if required */ +- cs_etm_decoder__init_raw_frame_logging(d_params, decoder); +- + for (i = 0; i < decoders; i++) { + ret = cs_etm_decoder__create_etm_decoder(d_params, + &t_params[i], +-- +2.53.0 + diff --git a/queue-5.15/perf-tools-fix-module-symbol-resolution-for-non-zero.patch b/queue-5.15/perf-tools-fix-module-symbol-resolution-for-non-zero.patch new file mode 100644 index 0000000000..e1c7e1c03b --- /dev/null +++ b/queue-5.15/perf-tools-fix-module-symbol-resolution-for-non-zero.patch @@ -0,0 +1,77 @@ +From 0780b98605d915aacd141966248087f5de56c15c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 11:58:04 -0400 +Subject: perf tools: Fix module symbol resolution for non-zero .text sh_addr + +From: Chuck Lever + +[ Upstream commit 9a82bfde4775b7a87cd1a7e791f46f83ae442848 ] + +When perf resolves symbols from kernel module ELF files (ET_REL), +it converts symbol addresses to file offsets so that sample IPs +can be matched to the correct symbol. The conversion adjusts each +symbol's st_value: + + sym->st_value -= shdr->sh_addr - shdr->sh_offset; + +For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr +is the section's virtual base, so subtracting sh_addr and adding +sh_offset correctly yields a file offset. + +For kernel modules (ET_REL), st_value is a section-relative +offset. The module loader ignores sh_addr entirely and places +symbols at module_base + st_value. Converting to file offset +requires only adding sh_offset; subtracting sh_addr introduces an +error equal to sh_addr bytes. + +When .text has sh_addr == 0 -- the historical norm for simple +modules -- both formulas produce the same result and the bug is +latent. As modules gain more metadata sections before .text (.note, +.static_call.text, etc.), the linker assigns .text a non-zero +sh_addr, exposing the defect. For example, nfsd.ko on this kernel +has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90. + +The effect is that all .text symbols in affected modules +shift by sh_addr bytes relative to sample IPs, causing perf +report to attribute samples to incorrect, nearby symbols. This +was observed as 13% of LLC-load-miss samples misattributed +to nfsd_file_get_dio_attrs when the actual hot function was +nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol +table. + +Use the existing dso__rel() flag (already set for ET_REL modules) +to select the correct adjustment: add sh_offset for ET_REL, +subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN. + +Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules") +Signed-off-by: Chuck Lever +Reviewed-by: Ian Rogers +Tested-by: Thomas Richter +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/symbol-elf.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c +index bbc3a150597a4..43fee6493035d 100644 +--- a/tools/perf/util/symbol-elf.c ++++ b/tools/perf/util/symbol-elf.c +@@ -1006,8 +1006,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, + char dso_name[PATH_MAX]; + + /* Adjust symbol to map to file offset */ +- if (adjust_kernel_syms) +- sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ if (adjust_kernel_syms) { ++ if (dso__rel(dso)) ++ sym->st_value += shdr->sh_offset; ++ else ++ sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ } + + if (strcmp(section_name, (curr_dso->short_name + dso->short_name_len)) == 0) + return 0; +-- +2.53.0 + diff --git a/queue-5.15/perf-util-kill-die-prototype-dead-for-a-long-time.patch b/queue-5.15/perf-util-kill-die-prototype-dead-for-a-long-time.patch new file mode 100644 index 0000000000..9358f8ce4d --- /dev/null +++ b/queue-5.15/perf-util-kill-die-prototype-dead-for-a-long-time.patch @@ -0,0 +1,39 @@ +From 534bc2a2c0609789414a1077402b8593771046fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:31:57 -0300 +Subject: perf util: Kill die() prototype, dead for a long time + +From: Arnaldo Carvalho de Melo + +[ Upstream commit e5cce1b9c82fbd48e2f1f7a25a9fad8ee228176f ] + +In fef2a735167a827a ("perf tools: Kill die()") the die() function was +removed, but not the prototype in util.h, now when building with +LIBPERL=1, during a 'make -C tools/perf build-test' routine test, it is +failing as perl likes die() calls and then this clashes with this +remnant, remove it. + +Fixes: fef2a735167a827a ("perf tools: Kill die()") +Reviewed-by: Ian Rogers +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/util.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h +index 9f0d36ba77f2d..130c68dff4ce0 100644 +--- a/tools/perf/util/util.h ++++ b/tools/perf/util/util.h +@@ -14,7 +14,6 @@ + + /* General helper functions */ + void usage(const char *err) __noreturn; +-void die(const char *err, ...) __noreturn __printf(1, 2); + + struct dirent; + struct strlist; +-- +2.53.0 + diff --git a/queue-5.15/pinctrl-abx500-fix-type-of-argument-variable.patch b/queue-5.15/pinctrl-abx500-fix-type-of-argument-variable.patch new file mode 100644 index 0000000000..87c96c30c6 --- /dev/null +++ b/queue-5.15/pinctrl-abx500-fix-type-of-argument-variable.patch @@ -0,0 +1,38 @@ +From d1ee4b5ca1aae3b89738f81c355be5f37d76ac94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 23:15:06 +0800 +Subject: pinctrl: abx500: Fix type of 'argument' variable + +From: Yu-Chun Lin + +[ Upstream commit 34006f77890d050e6d80cbee365b5d703c1140b4 ] + +The argument variable is assigned the return value of +pinconf_to_config_argument(), which returns a u32. Change its type from +enum pin_config_param to unsigned int to correctly store the configuration +argument. + +Fixes: 03b054e9696c ("pinctrl: Pass all configs to driver on pin_config_set()") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/nomadik/pinctrl-abx500.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c +index 7aa534576a459..609313d93e31a 100644 +--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c ++++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c +@@ -850,7 +850,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, + int ret = -EINVAL; + int i; + enum pin_config_param param; +- enum pin_config_param argument; ++ unsigned int argument; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); +-- +2.53.0 + diff --git a/queue-5.15/pinctrl-pinctrl-pic32-fix-resource-leak.patch b/queue-5.15/pinctrl-pinctrl-pic32-fix-resource-leak.patch new file mode 100644 index 0000000000..659fe2b877 --- /dev/null +++ b/queue-5.15/pinctrl-pinctrl-pic32-fix-resource-leak.patch @@ -0,0 +1,72 @@ +From 41925b7fa8c187bfddc87865dea8d1d400152e68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:56:23 -0600 +Subject: pinctrl: pinctrl-pic32: Fix resource leak + +From: Ethan Tidmore + +[ Upstream commit fe5560688f3ba98364c7de7b4f8dc240ffd1ff75 ] + +Fix three possible resource leaks by using the devres version of +clk_prepare_enable(). Also, update error message accordingly. + +Detected by Smatch: +drivers/pinctrl/pinctrl-pic32.c:2211 pic32_pinctrl_probe() warn: +'pctl->clk' from clk_prepare_enable() not released on lines: 2208. + +drivers/pinctrl/pinctrl-pic32.c:2274 pic32_gpio_probe() warn: +'bank->clk' from clk_prepare_enable() not released on lines: 2264,2272. + +Fixes: 2ba384e6c3810 ("pinctrl: pinctrl-pic32: Add PIC32 pin control driver") +Signed-off-by: Ethan Tidmore +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-pic32.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c +index 748dabd8db6e8..19763697a0a42 100644 +--- a/drivers/pinctrl/pinctrl-pic32.c ++++ b/drivers/pinctrl/pinctrl-pic32.c +@@ -2162,16 +2162,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev) + if (IS_ERR(pctl->reg_base)) + return PTR_ERR(pctl->reg_base); + +- pctl->clk = devm_clk_get(&pdev->dev, NULL); ++ pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(pctl->clk)) { + ret = PTR_ERR(pctl->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(pctl->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +@@ -2227,16 +2221,10 @@ static int pic32_gpio_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- bank->clk = devm_clk_get(&pdev->dev, NULL); ++ bank->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bank->clk)) { + ret = PTR_ERR(bank->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(bank->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +-- +2.53.0 + diff --git a/queue-5.15/platform-surface-surfacepro3_button-drop-wakeup-sour.patch b/queue-5.15/platform-surface-surfacepro3_button-drop-wakeup-sour.patch new file mode 100644 index 0000000000..b9c83e5ae0 --- /dev/null +++ b/queue-5.15/platform-surface-surfacepro3_button-drop-wakeup-sour.patch @@ -0,0 +1,41 @@ +From f80a1534ea8c6246a1233487548fc31d375dc645 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:54:08 +0100 +Subject: platform/surface: surfacepro3_button: Drop wakeup source on remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 1410a228ab2d36fe2b383415a632ae12048d4f3a ] + +The wakeup source added by device_init_wakeup() in surface_button_add() +needs to be dropped during driver removal, so update the driver to do +that. + +Fixes: 19351f340765 ("platform/x86: surfacepro3: Support for wakeup from suspend-to-idle") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/4368848.1IzOArtZ34@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/surface/surfacepro3_button.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 242fb690dcaf7..892fb71d5916f 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -243,6 +243,7 @@ static int surface_button_remove(struct acpi_device *device) + { + struct surface_button *button = acpi_driver_data(device); + ++ device_init_wakeup(&device->dev, false); + input_unregister_device(button->input); + kfree(button); + return 0; +-- +2.53.0 + diff --git a/queue-5.15/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch b/queue-5.15/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch new file mode 100644 index 0000000000..cb89ddf480 --- /dev/null +++ b/queue-5.15/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch @@ -0,0 +1,99 @@ +From ae816fdcc28d627f17d53f1058e97851542d726e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:38:21 +0800 +Subject: platform/x86: dell-wmi-sysman: bound enumeration string aggregation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pengpeng Hou + +[ Upstream commit 3c34471c26abc52a37f5ad90949e2e4b8027eb14 ] + +populate_enum_data() aggregates firmware-provided value-modifier +and possible-value strings into fixed 512-byte struct members. +The current code bounds each individual source string but then +appends every string and separator with raw strcat() and no +remaining-space check. + +Switch the aggregation loops to a bounded append helper and +reject enumeration packages whose combined strings do not fit +in the destination buffers. + +Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems") +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260408084501.1-dell-wmi-sysman-v2-pengpeng@iscas.ac.cn +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + .../dell/dell-wmi-sysman/enum-attributes.c | 34 +++++++++++++++---- + 1 file changed, 28 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +index fc2f58b4cbc6e..7e44ba3015627 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +@@ -6,10 +6,32 @@ + * Copyright (c) 2020 Dell Inc. + */ + ++#include ++ + #include "dell-wmi-sysman.h" + + get_instance_id(enumeration); + ++static int append_enum_string(char *dest, const char *src) ++{ ++ size_t dest_len = strlen(dest); ++ ssize_t copied; ++ ++ if (WARN_ON_ONCE(dest_len >= MAX_BUFF)) ++ return -EINVAL; ++ ++ copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ dest_len += copied; ++ copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { + int instance_id = get_enumeration_instance_id(kobj); +@@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + if (next_obj >= enum_property_count) +@@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); +-- +2.53.0 + diff --git a/queue-5.15/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch b/queue-5.15/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch new file mode 100644 index 0000000000..79da3701c1 --- /dev/null +++ b/queue-5.15/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch @@ -0,0 +1,60 @@ +From e837bab742e2284ac107beccf8636f6dfc5866fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:42:39 +0300 +Subject: platform/x86: dell_rbu: avoid uninit value usage in + packet_size_write() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fedor Pchelkin + +[ Upstream commit f8fd138c2363c0e2d3235c32bfb4fb5c6474e4ae ] + +Ensure the temp value has been properly parsed from the user-provided +buffer and initialized to be used in later operations. While at it, +prefer a convenient kstrtoul() helper. + +Found by Linux Verification Center (linuxtesting.org) with Svace static +analysis tool. + +Fixes: ad6ce87e5bd4 ("[PATCH] dell_rbu: changes in packet update mechanism") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260403134240.604837-1-pchelkin@ispras.ru +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/dell/dell_rbu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c +index 9fc5d3e9e7934..8f7c790857015 100644 +--- a/drivers/platform/x86/dell/dell_rbu.c ++++ b/drivers/platform/x86/dell/dell_rbu.c +@@ -30,6 +30,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -617,9 +618,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, + char *buffer, loff_t pos, size_t count) + { + unsigned long temp; ++ ++ if (kstrtoul(buffer, 10, &temp)) ++ return -EINVAL; ++ + spin_lock(&rbu_data.lock); + packet_empty_list(); +- sscanf(buffer, "%lu", &temp); + if (temp < 0xffffffff) + rbu_data.packetsize = temp; + +-- +2.53.0 + diff --git a/queue-5.15/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch b/queue-5.15/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch new file mode 100644 index 0000000000..5724524234 --- /dev/null +++ b/queue-5.15/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch @@ -0,0 +1,67 @@ +From ec0806f8240f56250baea479fb03e1e452669360 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 11:31:54 +0100 +Subject: platform/x86: panasonic-laptop: Fix OPTD notifier registration and + cleanup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 8baeff2c1d33dad8572216c6ad3a7425852507d4 ] + +An ACPI notify handler is leaked if device_create_file() returns an +error in acpi_pcc_hotkey_add(). + +Also, it is pointless to call pcc_unregister_optd_notifier() in +acpi_pcc_hotkey_remove() if pcc->platform is NULL and it is better +to arrange the cleanup code in that function in the same order as +the rollback code in acpi_pcc_hotkey_add(). + +Address the above by placing the pcc_register_optd_notifier() call in +acpi_pcc_hotkey_add() after the device_create_file() return value +check and placing the pcc_unregister_optd_notifier() call in +acpi_pcc_hotkey_remove() right before the device_remove_file() call. + +Fixes: d5a81d8e864b ("platform/x86: panasonic-laptop: Add support for optical driver power in Y and W series") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2411055.ElGaqSPkdT@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/panasonic-laptop.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c +index 418cd4d781261..6728e24db1d2a 100644 +--- a/drivers/platform/x86/panasonic-laptop.c ++++ b/drivers/platform/x86/panasonic-laptop.c +@@ -1077,9 +1077,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) + } + result = device_create_file(&pcc->platform->dev, + &dev_attr_cdpower); +- pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + if (result) + goto out_platform; ++ ++ pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + } else { + pcc->platform = NULL; + } +@@ -1113,10 +1114,10 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device) + i8042_remove_filter(panasonic_i8042_filter); + + if (pcc->platform) { ++ pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); + platform_device_unregister(pcc->platform); + } +- pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + + sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); + +-- +2.53.0 + diff --git a/queue-5.15/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch b/queue-5.15/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch new file mode 100644 index 0000000000..5df0871662 --- /dev/null +++ b/queue-5.15/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch @@ -0,0 +1,38 @@ +From 1778e842c57ee2eb303e6bf11734ab8f86b4c056 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 22:17:17 +0800 +Subject: pmdomain: imx: scu-pd: Fix device_node reference leak during + ->probe() + +From: Felix Gu + +[ Upstream commit c8e9b6a55702be6c6d034e973d519c52c3848415 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In imx_sc_pd_get_console_rsrc(), it does not release the reference. + +Fixes: 893cfb99734f ("firmware: imx: scu-pd: do not power off console domain") +Signed-off-by: Felix Gu +Reviewed-by: Peng Fan +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/firmware/imx/scu-pd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c +index ff6569c4a53bd..a0fc352a79936 100644 +--- a/drivers/firmware/imx/scu-pd.c ++++ b/drivers/firmware/imx/scu-pd.c +@@ -231,6 +231,7 @@ static void imx_sc_pd_get_console_rsrc(void) + return; + + imx_con_rsrc = specs.args[0]; ++ of_node_put(specs.np); + } + + static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on) +-- +2.53.0 + diff --git a/queue-5.15/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch b/queue-5.15/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch new file mode 100644 index 0000000000..98f8c33849 --- /dev/null +++ b/queue-5.15/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch @@ -0,0 +1,36 @@ +From 95b05b9959cc53f6ce0f0152baeae8decc6245e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 20:27:47 +0800 +Subject: pmdomain: ti: omap_prm: Fix a reference leak on device node + +From: Felix Gu + +[ Upstream commit 44c28e1c52764fef6dd1c1ada3a248728812e67f ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In omap_prm_domain_attach_dev, it does not release the reference. + +Fixes: 58cbff023bfa ("soc: ti: omap-prm: Add basic power domain support") +Signed-off-by: Felix Gu +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/soc/ti/omap_prm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c +index 544e57fff96ca..f3e5eb8232314 100644 +--- a/drivers/soc/ti/omap_prm.c ++++ b/drivers/soc/ti/omap_prm.c +@@ -656,6 +656,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, + if (pd_args.args_count != 0) + dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", + prmd->pd.name, pd_args.args_count); ++ of_node_put(pd_args.np); + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; +-- +2.53.0 + diff --git a/queue-5.15/powerpc-crash-fix-backup-region-offset-update-to-elf.patch b/queue-5.15/powerpc-crash-fix-backup-region-offset-update-to-elf.patch new file mode 100644 index 0000000000..703505c984 --- /dev/null +++ b/queue-5.15/powerpc-crash-fix-backup-region-offset-update-to-elf.patch @@ -0,0 +1,63 @@ +From 742f51d0008e34db64069329092526826dd61c96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:49 +0530 +Subject: powerpc/crash: fix backup region offset update to elfcorehdr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sourabh Jain + +[ Upstream commit 789335cacdf37da93bb7c70322dff8c7e82881df ] + +update_backup_region_phdr() in file_load_64.c iterates over all the +program headers in the kdump kernel’s elfcorehdr and updates the +p_offset of the program header whose physical address starts at 0. + +However, the loop logic is incorrect because the program header pointer +is not updated during iteration. Since elfcorehdr typically contains +PT_NOTE entries first, the PT_LOAD program header with physical address +0 is never reached. As a result, its p_offset is not updated to point to +the backup region. + +Because of this behavior, the capture kernel exports the first 64 KB of +the crashed kernel’s memory at offset 0, even though that memory +actually lives in the backup region. When a crash happens, purgatory +copies the first 64 KB of the crashed kernel’s memory into the backup +region so the capture kernel can safely use it. + +This has not caused problems so far because the first 64 KB is usually +identical in both the crashed and capture kernels. However, this is +just an assumption and is not guaranteed to always hold true. + +Fix update_backup_region_phdr() to correctly update the p_offset of the +program header with a starting physical address of 0 by correcting the +logic used to iterate over the program headers. + +Fixes: cb350c1f1f86 ("powerpc/kexec_file: Prepare elfcore header for crashing kernel") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Reviewed-by: Hari Bathini +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-2-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kexec/file_load_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index bce1bef0be899..ac8160cbcf673 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -766,7 +766,7 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) + unsigned int i; + + phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++) { ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + if (phdr->p_paddr == BACKUP_SRC_START) { + phdr->p_offset = image->arch.backup_start; + pr_debug("Backup region offset updated to 0x%lx\n", +-- +2.53.0 + diff --git a/queue-5.15/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch b/queue-5.15/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch new file mode 100644 index 0000000000..1df0676efb --- /dev/null +++ b/queue-5.15/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch @@ -0,0 +1,50 @@ +From 7c6f54dd1e8cfbf0e19e63dc69ee78ef5a983386 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:11:15 +0900 +Subject: ppp: require CAP_NET_ADMIN in target netns for unattached ioctls + +From: Taegu Ha + +[ Upstream commit 2bb6379416fd19f44c3423a00bfd8626259f6067 ] + +/dev/ppp open is currently authorized against file->f_cred->user_ns, +while unattached administrative ioctls operate on current->nsproxy->net_ns. + +As a result, a local unprivileged user can create a new user namespace +with CLONE_NEWUSER, gain CAP_NET_ADMIN only in that new user namespace, +and still issue PPPIOCNEWUNIT, PPPIOCATTACH, or PPPIOCATTCHAN against +an inherited network namespace. + +Require CAP_NET_ADMIN in the user namespace that owns the target network +namespace before handling unattached PPP administrative ioctls. + +This preserves normal pppd operation in the network namespace it is +actually privileged in, while rejecting the userns-only inherited-netns +case. + +Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2") +Signed-off-by: Taegu Ha +Link: https://patch.msgid.link/20260409071117.4354-1-hataegu0826@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 91a19ed03bc7d..bf75bc6954459 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1061,6 +1061,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct ppp_net *pn; + int __user *p = (int __user *)arg; + ++ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ + switch (cmd) { + case PPPIOCNEWUNIT: + /* Create a new ppp unit */ +-- +2.53.0 + diff --git a/queue-5.15/pppoe-drop-pfc-frames.patch b/queue-5.15/pppoe-drop-pfc-frames.patch new file mode 100644 index 0000000000..2974c5cd62 --- /dev/null +++ b/queue-5.15/pppoe-drop-pfc-frames.patch @@ -0,0 +1,112 @@ +From 33edf89d0bbdecf3ff8830ee36d7cc0cdce94f31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 10:24:51 +0800 +Subject: pppoe: drop PFC frames + +From: Qingfang Deng + +[ Upstream commit cc1ff87bce1ccd38410ab10960f576dcd17db679 ] + +RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT +RECOMMENDED for PPPoE. In practice, pppd does not support negotiating +PFC for PPPoE sessions, and the current PPPoE driver assumes an +uncompressed (2-byte) protocol field. However, the generic PPP layer +function ppp_input() is not aware of the negotiation result, and still +accepts PFC frames. + +If a peer with a broken implementation or an attacker sends a frame with +a compressed (1-byte) protocol field, the subsequent PPP payload is +shifted by one byte. This causes the network header to be 4-byte +misaligned, which may trigger unaligned access exceptions on some +architectures. + +To reduce the attack surface, drop PPPoE PFC frames. Introduce +ppp_skb_is_compressed_proto() helper function to be used in both +ppp_generic.c and pppoe.c to avoid open-coding. + +Fixes: 7fb1b8ca8fa1 ("ppp: Move PFC decompression to PPP generic layer") +Signed-off-by: Qingfang Deng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415022456.141758-2-qingfang.deng@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + drivers/net/ppp/pppoe.c | 8 +++++++- + include/linux/ppp_defs.h | 16 ++++++++++++++++ + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index bf75bc6954459..2b76a8695fdbe 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2244,7 +2244,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + */ + static void __ppp_decompress_proto(struct sk_buff *skb) + { +- if (skb->data[0] & 0x01) ++ if (ppp_skb_is_compressed_proto(skb)) + *(u8 *)skb_push(skb, 1) = 0x00; + } + +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index e172743948ed7..6ce4265d84f20 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -425,7 +425,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb_mac_header_len(skb) < ETH_HLEN) + goto drop; + +- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) ++ if (!pskb_may_pull(skb, PPPOE_SES_HLEN)) + goto drop; + + ph = pppoe_hdr(skb); +@@ -435,6 +435,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb->len < len) + goto drop; + ++ /* skb->data points to the PPP protocol header after skb_pull_rcsum. ++ * Drop PFC frames. ++ */ ++ if (ppp_skb_is_compressed_proto(skb)) ++ goto drop; ++ + if (pskb_trim_rcsum(skb, len)) + goto drop; + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index b7e57fdbd4139..b1d1f46d7d3be 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -8,6 +8,7 @@ + #define _PPP_DEFS_H_ + + #include ++#include + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) +@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) + return !!((proto & 0x0101) == 0x0001); + } + ++/** ++ * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed ++ * @skb: skb to check ++ * ++ * Check if the PPP protocol field is compressed (the least significant ++ * bit of the most significant octet is 1). skb->data must point to the PPP ++ * protocol header. ++ * ++ * Return: Whether the PPP protocol field is compressed. ++ */ ++static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb) ++{ ++ return unlikely(skb->data[0] & 0x01); ++} ++ + #endif /* _PPP_DEFS_H_ */ +-- +2.53.0 + diff --git a/queue-5.15/pstore-ram-fix-resource-leak-when-ioremap-fails.patch b/queue-5.15/pstore-ram-fix-resource-leak-when-ioremap-fails.patch new file mode 100644 index 0000000000..d496731e75 --- /dev/null +++ b/queue-5.15/pstore-ram-fix-resource-leak-when-ioremap-fails.patch @@ -0,0 +1,52 @@ +From ed5834d7b62c80846845441a59491e4938692fe5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:54:06 -0700 +Subject: pstore/ram: fix resource leak when ioremap() fails + +From: Cole Leavitt + +[ Upstream commit 2ddb69f686ef7a621645e97fc7329c50edf5d0e5 ] + +In persistent_ram_iomap(), ioremap() or ioremap_wc() may return NULL on +failure. Currently, if this happens, the function returns NULL without +releasing the memory region acquired by request_mem_region(). + +This leads to a resource leak where the memory region remains reserved +but unusable. + +Additionally, the caller persistent_ram_buffer_map() handles NULL +correctly by returning -ENOMEM, but without this check, a NULL return +combined with request_mem_region() succeeding leaves resources in an +inconsistent state. + +This is the ioremap() counterpart to commit 05363abc7625 ("pstore: +ram_core: fix incorrect success return when vmap() fails") which fixed +a similar issue in the vmap() path. + +Fixes: 404a6043385d ("staging: android: persistent_ram: handle reserving and mapping memory") +Signed-off-by: Cole Leavitt +Link: https://patch.msgid.link/20260225235406.11790-1-cole@unwrap.rs +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index c0b3b9c6892d1..8a86b9928503d 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -489,6 +489,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, + else + va = ioremap_wc(start, size); + ++ /* We must release the mem region if ioremap fails. */ ++ if (!va) ++ release_mem_region(start, size); ++ + /* + * Since request_mem_region() and ioremap() are byte-granularity + * there is no need handle anything special like we do when the +-- +2.53.0 + diff --git a/queue-5.15/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch b/queue-5.15/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch new file mode 100644 index 0000000000..ed12e20f60 --- /dev/null +++ b/queue-5.15/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch @@ -0,0 +1,148 @@ +From 8889286f1a2943a237084884498e70adf9c98771 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 14:22:16 +0100 +Subject: quota: Fix race of dquot_scan_active() with quota deactivation + +From: Jan Kara + +[ Upstream commit e93ab401da4b2e2c1b8ef2424de2f238d51c8b2d ] + +dquot_scan_active() can race with quota deactivation in +quota_release_workfn() like: + + CPU0 (quota_release_workfn) CPU1 (dquot_scan_active) + ============================== ============================== + spin_lock(&dq_list_lock); + list_replace_init( + &releasing_dquots, &rls_head); + /* dquot X on rls_head, + dq_count == 0, + DQ_ACTIVE_B still set */ + spin_unlock(&dq_list_lock); + synchronize_srcu(&dquot_srcu); + spin_lock(&dq_list_lock); + list_for_each_entry(dquot, + &inuse_list, dq_inuse) { + /* finds dquot X */ + dquot_active(X) -> true + atomic_inc(&X->dq_count); + } + spin_unlock(&dq_list_lock); + spin_lock(&dq_list_lock); + dquot = list_first_entry(&rls_head); + WARN_ON_ONCE(atomic_read(&dquot->dq_count)); + +The problem is not only a cosmetic one as under memory pressure the +caller of dquot_scan_active() can end up working on freed dquot. + +Fix the problem by making sure the dquot is removed from releasing list +when we acquire a reference to it. + +Fixes: 869b6ea1609f ("quota: Fix slow quotaoff") +Reported-by: Sam Sun +Link: https://lore.kernel.org/all/CAEkJfYPTt3uP1vAYnQ5V2ZWn5O9PLhhGi5HbOcAzyP9vbXyjeg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/dquot.c | 38 ++++++++++++++++++++++++++++++-------- + include/linux/quotaops.h | 9 +-------- + 2 files changed, 31 insertions(+), 16 deletions(-) + +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 5e2cf15b82f4d..6b53db7e9d6fb 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -362,6 +362,31 @@ static inline int dquot_active(struct dquot *dquot) + return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); + } + ++static struct dquot *__dqgrab(struct dquot *dquot) ++{ ++ lockdep_assert_held(&dq_list_lock); ++ if (!atomic_read(&dquot->dq_count)) ++ remove_free_dquot(dquot); ++ atomic_inc(&dquot->dq_count); ++ return dquot; ++} ++ ++/* ++ * Get reference to dquot when we got pointer to it by some other means. The ++ * dquot has to be active and the caller has to make sure it cannot get ++ * deactivated under our hands. ++ */ ++struct dquot *dqgrab(struct dquot *dquot) ++{ ++ spin_lock(&dq_list_lock); ++ WARN_ON_ONCE(!dquot_active(dquot)); ++ dquot = __dqgrab(dquot); ++ spin_unlock(&dq_list_lock); ++ ++ return dquot; ++} ++EXPORT_SYMBOL_GPL(dqgrab); ++ + static inline int dquot_dirty(struct dquot *dquot) + { + return test_bit(DQ_MOD_B, &dquot->dq_flags); +@@ -640,15 +665,14 @@ int dquot_scan_active(struct super_block *sb, + continue; + if (dquot->dq_sb != sb) + continue; +- /* Now we have active dquot so we can just increase use count */ +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqput(old_dquot); + old_dquot = dquot; + /* + * ->release_dquot() can be racing with us. Our reference +- * protects us from new calls to it so just wait for any +- * outstanding call and recheck the DQ_ACTIVE_B after that. ++ * protects us from dquot_release() proceeding so just wait for ++ * any outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (dquot_active(dquot)) { +@@ -716,7 +740,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) + /* Now we have active dquot from which someone is + * holding reference so we can safely just increase + * use count */ +- dqgrab(dquot); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + err = dquot_write_dquot(dquot); + if (err && !ret) +@@ -971,9 +995,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_LOOKUPS); + } else { +- if (!atomic_read(&dquot->dq_count)) +- remove_free_dquot(dquot); +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_CACHE_HITS); + dqstats_inc(DQST_LOOKUPS); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 4bc8ff2a66143..8a1ad23da3a11 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -43,14 +43,7 @@ int dquot_initialize(struct inode *inode); + bool dquot_initialize_needed(struct inode *inode); + void dquot_drop(struct inode *inode); + struct dquot *dqget(struct super_block *sb, struct kqid qid); +-static inline struct dquot *dqgrab(struct dquot *dquot) +-{ +- /* Make sure someone else has active reference to dquot */ +- WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); +- WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); +- atomic_inc(&dquot->dq_count); +- return dquot; +-} ++struct dquot *dqgrab(struct dquot *dquot); + + static inline bool dquot_is_busy(struct dquot *dquot) + { +-- +2.53.0 + diff --git a/queue-5.15/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch b/queue-5.15/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch new file mode 100644 index 0000000000..ed95d848fb --- /dev/null +++ b/queue-5.15/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch @@ -0,0 +1,41 @@ +From 946e7997fcda6a4e50456497c7f863cce85575d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:39:23 +0800 +Subject: r8152: fix incorrect register write to USB_UPHY_XTAL + +From: Chih Kai Hsu + +[ Upstream commit 48afd5124fd6129c46fd12cb06155384b1c4a0c4 ] + +The old code used ocp_write_byte() to clear the OOBS_POLLING bit +(BIT(8)) in the USB_UPHY_XTAL register, but this doesn't correctly +clear a bit in the upper byte of the 16-bit register. + +Fix this by using ocp_write_word() instead. + +Fixes: 195aae321c82 ("r8152: support new chips") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Link: https://patch.msgid.link/20260326073925.32976-454-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 59baa673738b6..2837688535268 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -3741,7 +3741,7 @@ static void r8156_ups_en(struct r8152 *tp, bool enable) + case RTL_VER_15: + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL); + ocp_data &= ~OOBS_POLLING; +- ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); ++ ocp_write_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); + break; + default: + break; +-- +2.53.0 + diff --git a/queue-5.15/rdma-core-prefer-nla_nul_string.patch b/queue-5.15/rdma-core-prefer-nla_nul_string.patch new file mode 100644 index 0000000000..211055e8e0 --- /dev/null +++ b/queue-5.15/rdma-core-prefer-nla_nul_string.patch @@ -0,0 +1,56 @@ +From 37efaf9905bc9abd9c4bdf1d26a7c2c6915dcb9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:27:39 +0200 +Subject: RDMA/core: Prefer NLA_NUL_STRING + +From: Florian Westphal + +[ Upstream commit 6ed3d14fc45d3da6025e7fe4a6a09066856698e2 ] + +These attributes are evaluated as c-string (passed to strcmp), but +NLA_STRING doesn't check for the presence of a \0 terminator. + +Either this needs to switch to nla_strcmp() and needs to adjust printf fmt +specifier to not use plain %s, or this needs to use NLA_NUL_STRING. + +As the code has been this way for long time, it seems to me that userspace +does include the terminating nul, even tough its not enforced so far, and +thus NLA_NUL_STRING use is the simpler solution. + +Fixes: 30dc5e63d6a5 ("RDMA/core: Add support for iWARP Port Mapper user space service") +Link: https://patch.msgid.link/r/20260330122742.13315-1-fw@strlen.de +Signed-off-by: Florian Westphal +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwpm_msg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c +index 3c9a9869212bb..feb09008eb9ca 100644 +--- a/drivers/infiniband/core/iwpm_msg.c ++++ b/drivers/infiniband/core/iwpm_msg.c +@@ -365,9 +365,9 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) + /* netlink attribute policy for the received response to register pid request */ + static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { + [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, +- [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_DEVNAME_SIZE - 1 }, +- [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, + [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } +@@ -677,7 +677,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) + + /* netlink attribute policy for the received request for mapping info */ + static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { +- [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } + }; +-- +2.53.0 + diff --git a/queue-5.15/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch b/queue-5.15/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch new file mode 100644 index 0000000000..96e23d71c7 --- /dev/null +++ b/queue-5.15/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch @@ -0,0 +1,51 @@ +From 6d3f7d1207c76c78577ef719317c771599103041 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 18:00:10 +0000 +Subject: rtc: abx80x: Disable alarm feature if no interrupt attached + +From: Anthony Pighin (Nokia) + +[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ] + +Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting +alarm") exposed an issue where the rtc-abx80x driver does not clear the +alarm feature bit, but instead relies on the set_alarm operation to return +invalid. + +For example, when a RTC_UIE_ON ioctl is handled, it should abort at the +feature validation. Instead, it proceeds to the rtc_timer_enqueue(), +which used to return an error from the set_alarm call. However, +following the race condition handling, which likely should not be +discarding predecing errors, a success condition is returned to the +ioctl() caller. This results in (for example): + hwclock: select() to /dev/rtc0 to wait for clock tick timed out + +Notwithstanding the validity of the race condition handling, if an interrupt +wasn't specified, or could not be attached, the driver should clear the +alarm feature bit. + +Fixes: 718a820a303c ("rtc: abx80x: add alarm support") +Signed-off-by: Anthony Pighin +Link: https://patch.msgid.link/BN0PR08MB69510928028C933749F4139383D1A@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-abx80x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c +index 2ea6fdd2ae984..651270e5f1e66 100644 +--- a/drivers/rtc/rtc-abx80x.c ++++ b/drivers/rtc/rtc-abx80x.c +@@ -836,6 +836,8 @@ static int abx80x_probe(struct i2c_client *client, + client->irq = 0; + } + } ++ if (client->irq <= 0) ++ clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); + + err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); + if (err) { +-- +2.53.0 + diff --git a/queue-5.15/sched-psi-fix-race-between-file-release-and-pressure.patch b/queue-5.15/sched-psi-fix-race-between-file-release-and-pressure.patch new file mode 100644 index 0000000000..403340b9b9 --- /dev/null +++ b/queue-5.15/sched-psi-fix-race-between-file-release-and-pressure.patch @@ -0,0 +1,184 @@ +From e7e1bec8a2c28dc1f59ed17875b312dfb8de944f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 14:15:43 +0800 +Subject: sched/psi: fix race between file release and pressure write + +From: Edward Adam Davis + +[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ] + +A potential race condition exists between pressure write and cgroup file +release regarding the priv member of struct kernfs_open_file, which +triggers the uaf reported in [1]. + +Consider the following scenario involving execution on two separate CPUs: + + CPU0 CPU1 + ==== ==== + vfs_rmdir() + kernfs_iop_rmdir() + cgroup_rmdir() + cgroup_kn_lock_live() + cgroup_destroy_locked() + cgroup_addrm_files() + cgroup_rm_file() + kernfs_remove_by_name() + kernfs_remove_by_name_ns() + vfs_write() __kernfs_remove() + new_sync_write() kernfs_drain() + kernfs_fop_write_iter() kernfs_drain_open_files() + cgroup_file_write() kernfs_release_file() + pressure_write() cgroup_file_release() + ctx = of->priv; + kfree(ctx); + of->priv = NULL; + cgroup_kn_unlock() + cgroup_kn_lock_live() + cgroup_get(cgrp) + cgroup_kn_unlock() + if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv + +The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards +the memory deallocation of of->priv performed within cgroup_file_release(). +However, the operations involving of->priv executed within pressure_write() +are not entirely covered by the protection of cgroup_mutex. Consequently, +if the code in pressure_write(), specifically the section handling the +ctx variable executes after cgroup_file_release() has completed, a uaf +vulnerability involving of->priv is triggered. + +Therefore, the issue can be resolved by extending the scope of the +cgroup_mutex lock within pressure_write() to encompass all code paths +involving of->priv, thereby properly synchronizing the race condition +occurring between cgroup_file_release() and pressure_write(). + +And, if an live kn lock can be successfully acquired while executing +the pressure write operation, it indicates that the cgroup deletion +process has not yet reached its final stage; consequently, the priv +pointer within open_file cannot be NULL. Therefore, the operation to +retrieve the ctx value must be moved to a point *after* the live kn +lock has been successfully acquired. + +In another situation, specifically after entering cgroup_kn_lock_live() +but before acquiring cgroup_mutex, there exists a different class of +race condition: + +CPU0: write memory.pressure CPU1: write cgroup.pressure=0 +=========================== ============================= + +kernfs_fop_write_iter() + kernfs_get_active_of(of) + pressure_write() + cgroup_kn_lock_live(memory.pressure) + cgroup_tryget(cgrp) + kernfs_break_active_protection(kn) + ... blocks on cgroup_mutex + + cgroup_pressure_write() + cgroup_kn_lock_live(cgroup.pressure) + cgroup_file_show(memory.pressure, false) + kernfs_show(false) + kernfs_drain_open_files() + cgroup_file_release(of) + kfree(ctx) + of->priv = NULL + cgroup_kn_unlock() + + ... acquires cgroup_mutex + ctx = of->priv; // may now be NULL + if (ctx->psi.trigger) // NULL dereference + +Consequently, there is a possibility that of->priv is NULL, the pressure +write needs to check for this. + +Now that the scope of the cgroup_mutex has been expanded, the original +explicit cgroup_get/put operations are no longer necessary, this is +because acquiring/releasing the live kn lock inherently executes a +cgroup get/put operation. + +[1] +BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 +Call Trace: + pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 + cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 + kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 + +Allocated by task 9352: + cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 + kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 + do_dentry_open+0x83d/0x13e0 fs/open.c:949 + +Freed by task 9353: + cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 + kernfs_release_file fs/kernfs/file.c:764 [inline] + kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 + kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525 + +Fixes: 0e94682b73bf ("psi: introduce psi monitor") +Reported-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=33e571025d88efd1312c +Tested-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Reviewed-by: Chen Ridong +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 2048fc3e22565..f131da1a8abfa 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -3720,33 +3720,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) + static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, enum psi_res res) + { +- struct cgroup_file_ctx *ctx = of->priv; ++ struct cgroup_file_ctx *ctx; + struct psi_trigger *new; + struct cgroup *cgrp; + struct psi_group *psi; ++ ssize_t ret = 0; + + cgrp = cgroup_kn_lock_live(of->kn, false); + if (!cgrp) + return -ENODEV; + +- cgroup_get(cgrp); +- cgroup_kn_unlock(of->kn); ++ ctx = of->priv; ++ if (!ctx) { ++ ret = -ENODEV; ++ goto out_unlock; ++ } + + /* Allow only one trigger per file descriptor */ + if (ctx->psi.trigger) { +- cgroup_put(cgrp); +- return -EBUSY; ++ ret = -EBUSY; ++ goto out_unlock; + } + + psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi; + new = psi_trigger_create(psi, buf, nbytes, res); + if (IS_ERR(new)) { +- cgroup_put(cgrp); +- return PTR_ERR(new); ++ ret = PTR_ERR(new); ++ goto out_unlock; + } + + smp_store_release(&ctx->psi.trigger, new); +- cgroup_put(cgrp); ++ ++out_unlock: ++ cgroup_kn_unlock(of->kn); ++ if (ret) ++ return ret; + + return nbytes; + } +-- +2.53.0 + diff --git a/queue-5.15/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch b/queue-5.15/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch new file mode 100644 index 0000000000..d352c95338 --- /dev/null +++ b/queue-5.15/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch @@ -0,0 +1,100 @@ +From 5ecaa3e54ef1d49fa8dc855816cac71380baf3ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:43 +0800 +Subject: scsi: sg: Resolve soft lockup issue when opening /dev/sgX + +From: Yang Erkun + +[ Upstream commit d06a310b45e153872033dd0cf19d5a2279121099 ] + +The parameter def_reserved_size defines the default buffer size reserved +for each Sg_fd and should be restricted to a range between 0 and 1,048,576 +(see https://tldp.org/HOWTO/SCSI-Generic-HOWTO/proc.html). Although the +function sg_proc_write_dressz enforces this limit, it is possible to bypass +it by directly modifying the module parameter as shown below, which then +causes a soft lockup: + +echo -1 > /sys/module/sg/parameters/def_reserved_size +exec 4<> /dev/sg0 + +watchdog: BUG: soft lockup - CPU#5 stuck for 26 seconds! [bash:537] +Modules loaded: +CPU: 5 UID: 0 PID: 537 Command: bash, kernel version 6.19.0-rc3+ #134, +PREEMPT disabled +Hardware: QEMU Standard PC (i440FX + PIIX, 1996), BIOS version +1.16.1-2.fc37 dated 04/01/2014 +... +Call Trace: + + sg_build_reserve+0x5c/0xa0 + sg_add_sfp+0x168/0x270 + sg_open+0x16e/0x340 + chrdev_open+0xbe/0x230 + do_dentry_open+0x175/0x480 + vfs_open+0x34/0xf0 + do_open+0x265/0x3d0 + path_openat+0x110/0x290 + do_filp_open+0xc3/0x170 + do_sys_openat2+0x71/0xe0 + __x64_sys_openat+0x6d/0xa0 + do_syscall_64+0x62/0x310 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The fix is to use module_param_cb to validate and reject invalid values +assigned to def_reserved_size. + +Fixes: 6460e75a104d ("[SCSI] sg: fixes for large page_size") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-3-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index d74bb7b42de89..18c9c1d7107fd 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1615,10 +1615,35 @@ sg_remove_device(struct device *cl_dev, struct class_interface *cl_intf) + } + + module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +-module_param_named(def_reserved_size, def_reserved_size, int, +- S_IRUGO | S_IWUSR); + module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); + ++static int def_reserved_size_set(const char *val, const struct kernel_param *kp) ++{ ++ int size, ret; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtoint(val, 0, &size); ++ if (ret) ++ return ret; ++ ++ /* limit to 1 MB */ ++ if (size < 0 || size > 1048576) ++ return -ERANGE; ++ ++ def_reserved_size = size; ++ return 0; ++} ++ ++static const struct kernel_param_ops def_reserved_size_ops = { ++ .set = def_reserved_size_set, ++ .get = param_get_int, ++}; ++ ++module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, ++ S_IRUGO | S_IWUSR); ++ + MODULE_AUTHOR("Douglas Gilbert"); + MODULE_DESCRIPTION("SCSI generic (sg) driver"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-5.15/scsi-sr-add-memory-allocation-failure-handling-for-g.patch b/queue-5.15/scsi-sr-add-memory-allocation-failure-handling-for-g.patch new file mode 100644 index 0000000000..3e501811e1 --- /dev/null +++ b/queue-5.15/scsi-sr-add-memory-allocation-failure-handling-for-g.patch @@ -0,0 +1,88 @@ +From c336eaf9decac4fa05cd4ef6aff86959394768bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Apr 2022 10:56:47 +0800 +Subject: scsi: sr: Add memory allocation failure handling for + get_capabilities() + +From: Enze Li + +[ Upstream commit ebc95c790653508ad7e031cfb9de5d0fa39135e2 ] + +The function get_capabilities() has the possibility of failing to allocate +the transfer buffer but it does not currently handle this. This may lead to +exceptions when accessing the buffer. + +Add error handling when memory allocation fails. + +Link: https://lore.kernel.org/r/20220427025647.298358-1-lienze@kylinos.cn +Signed-off-by: Enze Li +Signed-off-by: Martin K. Petersen +Stable-dep-of: 0898a817621a ("cdrom, scsi: sr: propagate read-only status to block layer via set_disk_ro()") +Signed-off-by: Sasha Levin +--- + drivers/scsi/sr.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index af210910dadf2..529d4169b373b 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -118,7 +118,7 @@ static int sr_open(struct cdrom_device_info *, int); + static void sr_release(struct cdrom_device_info *); + + static void get_sectorsize(struct scsi_cd *); +-static void get_capabilities(struct scsi_cd *); ++static int get_capabilities(struct scsi_cd *); + + static unsigned int sr_check_events(struct cdrom_device_info *cdi, + unsigned int clearing, int slot); +@@ -710,8 +710,9 @@ static int sr_probe(struct device *dev) + + sdev->sector_size = 2048; /* A guess, just in case */ + +- /* FIXME: need to handle a get_capabilities failure properly ?? */ +- get_capabilities(cd); ++ error = -ENOMEM; ++ if (get_capabilities(cd)) ++ goto fail_minor; + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -831,7 +832,7 @@ static void get_sectorsize(struct scsi_cd *cd) + return; + } + +-static void get_capabilities(struct scsi_cd *cd) ++static int get_capabilities(struct scsi_cd *cd) + { + unsigned char *buffer; + struct scsi_mode_data data; +@@ -856,7 +857,7 @@ static void get_capabilities(struct scsi_cd *cd) + buffer = kmalloc(512, GFP_KERNEL); + if (!buffer) { + sr_printk(KERN_ERR, cd, "out of memory.\n"); +- return; ++ return -ENOMEM; + } + + /* eat unit attentions */ +@@ -876,7 +877,7 @@ static void get_capabilities(struct scsi_cd *cd) + CDC_MRW | CDC_MRW_W | CDC_RAM); + kfree(buffer); + sr_printk(KERN_INFO, cd, "scsi-1 drive"); +- return; ++ return 0; + } + + n = data.header_length + data.block_descriptor_length; +@@ -935,6 +936,7 @@ static void get_capabilities(struct scsi_cd *cd) + } + + kfree(buffer); ++ return 0; + } + + /* +-- +2.53.0 + diff --git a/queue-5.15/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch b/queue-5.15/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch new file mode 100644 index 0000000000..cc598fd02d --- /dev/null +++ b/queue-5.15/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch @@ -0,0 +1,42 @@ +From 523b759205729ba59bba364055e0753a3ad31c7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 23:42:58 +0800 +Subject: scsi: target: core: Fix integer overflow in UNMAP bounds check + +From: Junrui Luo + +[ Upstream commit 2bf2d65f76697820dbc4227d13866293576dd90a ] + +sbc_execute_unmap() checks LBA + range does not exceed the device capacity, +but does not guard against LBA + range wrapping around on 64-bit overflow. + +Add an overflow check matching the pattern already used for WRITE_SAME in +the same file. + +Fixes: 86d7182985d2 ("target: Add sbc_execute_unmap() helper") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881593C61AD52C69FBDB0BDAF7CA@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/target/target_core_sbc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c +index f6132836eb387..2d76f2f455942 100644 +--- a/drivers/target/target_core_sbc.c ++++ b/drivers/target/target_core_sbc.c +@@ -1232,7 +1232,8 @@ sbc_execute_unmap(struct se_cmd *cmd) + goto err; + } + +- if (lba + range > dev->transport->get_blocks(dev) + 1) { ++ if (lba + range < lba || ++ lba + range > dev->transport->get_blocks(dev) + 1) { + ret = TCM_ADDRESS_OUT_OF_RANGE; + goto err; + } +-- +2.53.0 + diff --git a/queue-5.15/sctp-discard-stale-init-after-handshake-completion.patch b/queue-5.15/sctp-discard-stale-init-after-handshake-completion.patch new file mode 100644 index 0000000000..961d488dc5 --- /dev/null +++ b/queue-5.15/sctp-discard-stale-init-after-handshake-completion.patch @@ -0,0 +1,49 @@ +From f143676aa3d4fecce27bef76dc397418d6b8307b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:41 -0400 +Subject: sctp: discard stale INIT after handshake completion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Xin Long + +[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ] + +After an association reaches ESTABLISHED, the peer’s init_tag is already +known from the handshake. Any subsequent INIT with the same init_tag is +not a valid restart, but a delayed or duplicate INIT. + +Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of +processing them as new association attempts. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/5788c76c1ee122a3ed00189e88dcf9df1fba226c.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index dc758ad0051e0..2f9f24b188520 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -1555,6 +1555,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( + /* Tag the variable length parameters. */ + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); + ++ if (asoc->state >= SCTP_STATE_ESTABLISHED) { ++ /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ ++ if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) ++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ } ++ + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, +-- +2.53.0 + diff --git a/queue-5.15/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch b/queue-5.15/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch new file mode 100644 index 0000000000..2ed1acd979 --- /dev/null +++ b/queue-5.15/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch @@ -0,0 +1,44 @@ +From 5953e6cedfebc31f99210dd0443a3888f8dad454 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 14:13:51 -0400 +Subject: sctp: fix missing encap_port propagation for GSO fragments + +From: Xin Long + +[ Upstream commit bf6f95ae3b8b2638c0e1d6d802d50983ce5d0f45 ] + +encap_port in SCTP_INPUT_CB(skb) is used by sctp_vtag_verify() for +SCTP-over-UDP processing. In the GSO case, it is only set on the head +skb, while fragment skbs leave it 0. + +This results in fragment skbs seeing encap_port == 0, breaking +SCTP-over-UDP connections. + +Fix it by propagating encap_port from the head skb cb when initializing +fragment skbs in sctp_inq_pop(). + +Fixes: 046c052b475e ("sctp: enable udp tunneling socks") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/ea65ed61b3598d8b4940f0170b9aa1762307e6c3.1776017631.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/inqueue.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c +index 6a434d441dc70..6dfbd35d916d4 100644 +--- a/net/sctp/inqueue.c ++++ b/net/sctp/inqueue.c +@@ -195,6 +195,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + + cb->chunk = head_cb->chunk; + cb->af = head_cb->af; ++ cb->encap_port = head_cb->encap_port; + } + } + +-- +2.53.0 + diff --git a/queue-5.15/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch b/queue-5.15/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch new file mode 100644 index 0000000000..257721753b --- /dev/null +++ b/queue-5.15/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch @@ -0,0 +1,68 @@ +From 9c82bcff4c9557b009b90d3c0d4174a4dcd0e1c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 23:19:03 -0400 +Subject: sctp: fix OOB write to userspace in sctp_getsockopt_peer_auth_chunks + +From: Michael Bommarito + +[ Upstream commit 0cf004ffb61cd32d140531c3a84afe975f9fc7ea ] + +sctp_getsockopt_peer_auth_chunks() checks that the caller's optval +buffer is large enough for the peer AUTH chunk list with + + if (len < num_chunks) + return -EINVAL; + +but then writes num_chunks bytes to p->gauth_chunks, which lives +at offset offsetof(struct sctp_authchunks, gauth_chunks) == 8 +inside optval. The check is missing the sizeof(struct +sctp_authchunks) = 8-byte header. When the caller supplies +len == num_chunks (for any num_chunks > 0) the test passes but +copy_to_user() writes sizeof(struct sctp_authchunks) = 8 bytes +past the declared buffer. + +The sibling function sctp_getsockopt_local_auth_chunks() at the +next line already has the correct check: + + if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + +Align the peer variant with its sibling. + +Reproducer confirms on v7.0-13-generic: an unprivileged userspace +caller that opens a loopback SCTP association with AUTH enabled, +queries num_chunks with a short optval, then issues the real +getsockopt with len == num_chunks and sentinel bytes painted past +the buffer observes those sentinel bytes overwritten with the +peer's AUTH chunk type. The bytes written are under the peer's +control but land in the caller's own userspace; this is not a +kernel memory corruption, but it is a kernel-side contract +violation that can silently corrupt adjacent userspace data. + +Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260416031903.1447072-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index a78bb0be8bf43..11040232ee937 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -6991,7 +6991,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, + + /* See if the user provided enough room for all the data */ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); +- if (len < num_chunks) ++ if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + + if (copy_to_user(to, ch->chunks, num_chunks)) +-- +2.53.0 + diff --git a/queue-5.15/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch b/queue-5.15/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch new file mode 100644 index 0000000000..4f8059cde4 --- /dev/null +++ b/queue-5.15/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch @@ -0,0 +1,75 @@ +From 80fa4edf79978f75be9175610ea1daa639e288bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 16:05:26 -0400 +Subject: selftest: memcg: skip memcg_sock test if address family not supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Waiman Long + +[ Upstream commit 2d028f3e4bbbfd448928a8d3d2814b0b04c214f4 ] + +The test_memcg_sock test in memcontrol.c sets up an IPv6 socket and send +data over it to consume memory and verify that memory.stat.sock and +memory.current values are close. + +On systems where IPv6 isn't enabled or not configured to support +SOCK_STREAM, the test_memcg_sock test always fails. When the socket() +call fails, there is no way we can test the memory consumption and verify +the above claim. I believe it is better to just skip the test in this +case instead of reporting a test failure hinting that there may be +something wrong with the memcg code. + +Link: https://lkml.kernel.org/r/20260311200526.885899-1-longman@redhat.com +Fixes: 5f8f019380b8 ("selftests: cgroup/memcontrol: add basic test for socket accounting") +Signed-off-by: Waiman Long +Acked-by: Michal Koutný +Acked-by: Shakeel Butt +Cc: Johannes Weiner +Cc: Michal Hocko +Cc: Michal Koutný +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Roman Gushchin +Cc: Shuah Khan +Cc: Tejun Heo +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/cgroup/test_memcontrol.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c +index c19a97dd02d49..07ce722b2533b 100644 +--- a/tools/testing/selftests/cgroup/test_memcontrol.c ++++ b/tools/testing/selftests/cgroup/test_memcontrol.c +@@ -833,8 +833,11 @@ static int tcp_server(const char *cgroup, void *arg) + saddr.sin6_port = htons(srv_args->port); + + sk = socket(AF_INET6, SOCK_STREAM, 0); +- if (sk < 0) ++ if (sk < 0) { ++ /* Pass back errno to the ctl_fd */ ++ write(ctl_fd, &errno, sizeof(errno)); + return ret; ++ } + + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + goto cleanup; +@@ -964,6 +967,12 @@ static int test_memcg_sock(const char *root) + goto cleanup; + close(args.ctl[0]); + ++ /* Skip if address family not supported by protocol */ ++ if (err == EAFNOSUPPORT) { ++ ret = KSFT_SKIP; ++ goto cleanup; ++ } ++ + if (!err) + break; + if (err != EADDRINUSE) +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index 0a7d4e7f08..5e3598209b 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -387,3 +387,269 @@ vsock-fix-buffer-size-clamping-order.patch vsock-virtio-fix-accept-queue-count-leak-on-transport-mismatch.patch drm-amdgpu-vcn3-avoid-overflow-on-msg-bound-check.patch bcache-fix-uninitialized-closure-object.patch +fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch +drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch +nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch +pstore-ram-fix-resource-leak-when-ioremap-fails.patch +devres-fix-missing-node-debug-info-in-devm_krealloc.patch +thermal-drivers-spear-fix-error-condition-for-readin.patch +debugfs-check-for-null-pointer-in-debugfs_create_str.patch +irqchip-irq-pic32-evic-address-warning-related-to-wr.patch +locking-fix-rwlock-support-in-linux-spinlock_up.h.patch +firmware-dmi-correct-an-indexing-error-in-dmi.h.patch +wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch +wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch +dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch +dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch +kernel-param-rename-locate_module_kobject.patch +kernel-globalize-lookup_or_create_module_kobject.patch +params-replace-__modinit-with-__init_or_module.patch +module-fix-freeing-of-charp-module-parameters-when-c.patch +bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch +bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch +r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch +powerpc-crash-fix-backup-region-offset-update-to-elf.patch +macvlan-annotate-data-races-around-port-bc_queue_len.patch +bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch +wifi-brcmfmac-fix-error-pointer-dereference.patch +bpf-lsm-make-bpf_lsm_userns_create-sleepable.patch +bpf-drop-task_to_inode-and-inet_conn_established-fro.patch +bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch +net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch +netfilter-xt_socket-enable-defrag-after-all-other-ch.patch +netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch +6pack-propagage-new-tty-types.patch +net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch +net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch +net-rds-optimize-rds_ib_laddr_check.patch +net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch +ppp-require-cap_net_admin-in-target-netns-for-unatta.patch +bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch +bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch +bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch +bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch +bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch +net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch +sctp-fix-missing-encap_port-propagation-for-gso-frag.patch +net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch +drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch +drm-sun4i-backend-fix-error-pointer-dereference.patch +asoc-sti-return-errors-from-regmap_field_alloc.patch +asoc-sti-use-managed-regmap_field-allocations.patch +dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch +dm-cache-fix-write-path-cache-coherency-in-passthrou.patch +dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch +dm-cache-fix-concurrent-write-failure-in-passthrough.patch +dm-cache-support-shrinking-the-origin-device.patch +dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch +dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch +dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch +spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch +drm-sun4i-fix-resource-leaks.patch +dm-init-ensure-device-probing-has-finished-in-dm-mod.patch +fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch +spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch +drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch +drm-panel-simple-correct-g190ean01-prepare-timing.patch +alsa-core-validate-compress-device-numbers-without-d.patch +drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch +drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch +drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch +drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch +drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch +drm-amd-pm-ci-fill-dw8-fields-from-smc.patch +drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch +alsa-hda-realtek-whitespace-fix.patch +alsa-hda-realtek-fix-code-style-error-else-should-fo.patch +drm-msm-a6xx-fix-hlsq-register-dumping.patch +drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch +pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch +pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch +asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch +asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch +asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch +pci-enable-atomicops-only-if-root-port-supports-them.patch +documentation-fix-a-hugetlbfs-reservation-statement.patch +selftest-memcg-skip-memcg_sock-test-if-address-famil.patch +pci-add-pcie_pme_to_l2_timeout_us-l2-ready-timeout-v.patch +pci-tegra194-fix-polling-delay-for-l2-state.patch +pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch +pci-tegra194-disable-ltssm-after-transition-to-detec.patch +pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch +pci-tegra194-disable-direct-speed-change-for-endpoin.patch +alsa-sc6000-use-standard-print-api.patch +alsa-sc6000-keep-the-programmed-board-state-in-card-.patch +ktest-avoid-undef-warning-when-warnings_file-is-unse.patch +ktest-honor-empty-per-test-option-overrides.patch +ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch +quota-fix-race-of-dquot_scan_active-with-quota-deact.patch +gfs2-add-some-missing-log-locking.patch +gfs2-prevent-null-pointer-dereference-during-unmount.patch +efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch +ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch +arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch +memory-tegra124-emc-fix-dll_change-check.patch +memory-tegra30-emc-fix-dll_change-check.patch +soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch +soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch +soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch +arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch +unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch +ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch +ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch +soc-qcom-aoss-compare-against-normalized-cooling-sta.patch +ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch +ocfs2-validate-bg_bits-during-freefrag-scan.patch +ocfs2-validate-group-add-input-before-caching.patch +dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch +dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch +tracing-rebuild-full_name-on-each-hist_field_name-ca.patch +ima-check-return-value-of-crypto_shash_final-in-boot.patch +hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch +hid-asus-do-not-abort-probe-when-not-necessary.patch +mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch +mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch +mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch +mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch +mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch +mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch +hid-usbhid-fix-deadlock-in-hid_post_reset.patch +bpf-af_unix-use-batching-algorithm-in-bpf-unix-iter.patch +bpf-sockmap-fix-af_unix-iter-deadlock.patch +bpf-sockmap-take-state-lock-for-af_unix-iter.patch +bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch +bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch +bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch +pinctrl-pinctrl-pic32-fix-resource-leak.patch +perf-branch-avoid-incrementing-null.patch +perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch +pinctrl-abx500-fix-type-of-argument-variable.patch +perf-tools-fix-module-symbol-resolution-for-non-zero.patch +perf-expr-return-einval-for-syntax-error-in-expr__fi.patch +perf-util-kill-die-prototype-dead-for-a-long-time.patch +i3c-master-fix-error-codes-at-send_ccc_cmd.patch +i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch +driver-core-device.h-remove-extern-from-function-pro.patch +driver-core-move-dev_err_probe-to-where-it-belogs.patch +dev_printk-add-new-dev_err_probe-helpers.patch +backlight-sky81452-backlight-check-return-value-of-d.patch +platform-surface-surfacepro3_button-drop-wakeup-sour.patch +leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch +tty-hvc-remove-hvc_iucv_magic.patch +tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch +platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch +mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch +nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch +fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch +platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch +platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch +rdma-core-prefer-nla_nul_string.patch +scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch +scsi-target-core-fix-integer-overflow-in-unmap-bound.patch +dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch +clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch +clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch +clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch +clk-imx8mq-correct-the-csi-phy-sels.patch +clk-qoriq-avoid-format-string-warning.patch +clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch +dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch +clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch +lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch +crypto-sa2ul-fix-aead-fallback-algorithm-names.patch +crypto-ccp-copy-iv-using-skcipher-ivsize.patch +pcmcia-fix-garbled-log-messages-for-kern_cont.patch +net-sched-sch_cake-fix-nat-destination-port-not-bein.patch +nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch +net-sched-taprio-stop-going-through-private-ops-for-.patch +net-sched-taprio-replace-safety-precautions-with-com.patch +net-sched-taprio-continue-with-other-txqs-if-one-deq.patch +net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch +net-sched-taprio-rename-close_time-to-end_time.patch +net-sched-taprio-fix-use-after-free-in-advance_sched.patch +tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch +i40e-don-t-advertise-iff_supp_nofcs.patch +e1000e-unroll-ptp-in-probe-error-handling.patch +ipv6-fix-possible-uaf-in-icmpv6_rcv.patch +sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch +dissector-do-not-set-invalid-ppp-protocol.patch +flow_dissector-add-number-of-vlan-tags-dissector.patch +flow_dissector-add-pppoe-dissectors.patch +pppoe-drop-pfc-frames.patch +openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch +netfilter-nft_osf-restrict-it-to-ipv4.patch +netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch +netfilter-conntrack-remove-sprintf-usage.patch +netfilter-xtables-restrict-several-matches-to-inet-f.patch +ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch +netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch +netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch +slip-reject-vj-receive-packets-on-instances-with-no-.patch +slip-bound-decode-reads-against-the-compressed-packe.patch +arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch +ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch +ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch +net-rds-zero-per-item-info-buffer-before-handing-it-.patch +net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch +net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch +net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch +net-sched-gred-red-remove-unused-variables-in-struct.patch +net-sched-sch_red-annotate-data-races-in-red_dump_st.patch +net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch +nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch +tipc-fix-double-free-in-tipc_buf_append.patch +vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch +fs-adfs-validate-nzones-in-adfs_validate_bblk.patch +rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch +fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch +mailbox-mailbox-test-free-channels-on-probe-error.patch +sched-psi-fix-race-between-file-release-and-pressure.patch +cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch +mailbox-add-sanity-check-for-channel-array.patch +mailbox-mailbox-test-don-t-free-the-reused-channel.patch +mailbox-mailbox-test-initialize-struct-earlier.patch +mailbox-mailbox-test-make-data_ready-a-per-instance-.patch +btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch +tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch +netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch +drm-amdgpu-fix-spelling-typos.patch +drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch +drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch +netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch +netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch +scsi-sr-add-memory-allocation-failure-handling-for-g.patch +cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch +netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch +net-sched-sch_netem-refactor-code-in-4-state-loss-ge.patch +net-sched-netem-fix-probability-gaps-in-4-state-loss.patch +net-sched-netem-fix-queue-limit-check-to-include-reo.patch +net-sched-netem-validate-slot-configuration.patch +net-sched-choke-remove-unused-variables-in-struct-ch.patch +net-sched-sch_choke-annotate-data-races-in-choke_dum.patch +net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch +vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch +net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch +net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch +nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch +net-phy-dp83869-fix-setting-clk_o_sel-field.patch +asoc-codecs-ab8500-fix-casting-of-private-data.patch +netfilter-skip-recording-stale-or-retransmitted-init.patch +sctp-discard-stale-init-after-handshake-completion.patch +ipv4-rename-and-move-ip_route_output_tunnel.patch +ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch +ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch +ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch +bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch +alsa-hda-conexant-add-a-new-hda-codec-sn6140.patch +alsa-hda-conexant-fix-some-typos.patch +alsa-hda-conexant-renaming-the-codec-with-device-id-.patch +alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch +drm-amd-display-allow-dce-link-encoder-without-aux-r.patch +drm-amd-display-read-edid-from-vbios-embedded-panel-.patch diff --git a/queue-5.15/slip-bound-decode-reads-against-the-compressed-packe.patch b/queue-5.15/slip-bound-decode-reads-against-the-compressed-packe.patch new file mode 100644 index 0000000000..e53c6a200a --- /dev/null +++ b/queue-5.15/slip-bound-decode-reads-against-the-compressed-packe.patch @@ -0,0 +1,158 @@ +From 146bb81721219dc2bf4dbb57b304fb8db0b7ad7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:01:51 +0800 +Subject: slip: bound decode() reads against the compressed packet length + +From: Weiming Shi + +[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ] + +slhc_uncompress() parses a VJ-compressed TCP header by advancing a +pointer through the packet via decode() and pull16(). Neither helper +bounds-checks against isize, and decode() masks its return with +& 0xffff so it can never return the -1 that callers test for -- those +error paths are dead code. + +A short compressed frame whose change byte requests optional fields +lets decode() read past the end of the packet. The over-read bytes +are folded into the cached cstate and reflected into subsequent +reconstructed packets. + +Make decode() and pull16() take the packet end pointer and return -1 +when exhausted. Add a bounds check before the TCP-checksum read. +The existing == -1 tests now do what they were always meant to. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Simon Horman +Closes: https://lore.kernel.org/netdev/20260414134126.758795-2-horms@kernel.org/ +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416100147.531855-5-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index 3474792a37a67..ef586ab250747 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -80,9 +80,9 @@ + #include + + static unsigned char *encode(unsigned char *cp, unsigned short n); +-static long decode(unsigned char **cpp); ++static long decode(unsigned char **cpp, const unsigned char *end); + static unsigned char * put16(unsigned char *cp, unsigned short x); +-static unsigned short pull16(unsigned char **cpp); ++static long pull16(unsigned char **cpp, const unsigned char *end); + + /* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) +@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n) + return cp; + } + +-/* Pull a 16-bit integer in host order from buffer in network byte order */ +-static unsigned short +-pull16(unsigned char **cpp) ++/* Pull a 16-bit integer in host order from buffer in network byte order. ++ * Returns -1 if the buffer is exhausted, otherwise the 16-bit value. ++ */ ++static long ++pull16(unsigned char **cpp, const unsigned char *end) + { +- short rval; ++ long rval; + ++ if (*cpp + 2 > end) ++ return -1; + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; + } + +-/* Decode a number */ ++/* Decode a number. Returns -1 if the buffer is exhausted. */ + static long +-decode(unsigned char **cpp) ++decode(unsigned char **cpp, const unsigned char *end) + { + int x; + ++ if (*cpp >= end) ++ return -1; + x = *(*cpp)++; +- if(x == 0){ +- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ +- } else { +- return x & 0xff; /* -1 if PULLCHAR returned error */ +- } ++ if (x == 0) ++ return pull16(cpp, end); ++ return x & 0xff; + } + + /* +@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; ++ const unsigned char *end = icp + isize; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; +@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + ++ if (cp + 2 > end) ++ goto bad; + thp->check = *(__sum16 *)cp; + cp += 2; + +@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + default: + if(changes & NEW_U){ + thp->urg = 1; +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); +@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + break; + } + if(changes & NEW_I){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); +-- +2.53.0 + diff --git a/queue-5.15/slip-reject-vj-receive-packets-on-instances-with-no-.patch b/queue-5.15/slip-reject-vj-receive-packets-on-instances-with-no-.patch new file mode 100644 index 0000000000..d8da2ee5b5 --- /dev/null +++ b/queue-5.15/slip-reject-vj-receive-packets-on-instances-with-no-.patch @@ -0,0 +1,98 @@ +From a40ff03c22493efb988950036f55825b08455ccc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 04:41:31 +0800 +Subject: slip: reject VJ receive packets on instances with no rstate array + +From: Weiming Shi + +[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ] + +slhc_init() accepts rslots == 0 as a valid configuration, with the +documented meaning of 'no receive compression'. In that case the +allocation loop in slhc_init() is skipped, so comp->rstate stays +NULL and comp->rslot_limit stays 0 (from the kzalloc of struct +slcompress). + +The receive helpers do not defend against that configuration. +slhc_uncompress() dereferences comp->rstate[x] when the VJ header +carries an explicit connection ID, and slhc_remember() later assigns +cs = &comp->rstate[...] after only comparing the packet's slot number +to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the +range check, and the code dereferences a NULL rstate. + +The configuration is reachable in-tree through PPP. PPPIOCSMAXCID +stores its argument in a signed int, and (val >> 16) uses arithmetic +shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 +is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because +/dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path +is reachable from an unprivileged user namespace. Once the malformed +VJ state is installed, any inbound VJ-compressed or VJ-uncompressed +frame that selects slot 0 crashes the kernel in softirq context: + + Oops: general protection fault, probably for non-canonical + address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519) + Call Trace: + + ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466) + ppp_input (drivers/net/ppp/ppp_generic.c:2359) + ppp_async_process (drivers/net/ppp/ppp_async.c:492) + tasklet_action_common (kernel/softirq.c:926) + handle_softirqs (kernel/softirq.c:623) + run_ksoftirqd (kernel/softirq.c:1055) + smpboot_thread_fn (kernel/smpboot.c:160) + kthread (kernel/kthread.c:436) + ret_from_fork (arch/x86/kernel/process.c:164) + + +Reject the receive side on such instances instead of touching rstate. +slhc_uncompress() falls through to its existing 'bad' label, which +bumps sls_i_error and enters the toss state. slhc_remember() mirrors +that with an explicit sls_i_error increment followed by slhc_toss(); +the sls_i_runt counter is not used here because a missing rstate is +an internal configuration state, not a runt packet. + +The transmit path is unaffected: the only in-tree caller that picks +rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and +slip.c always calls slhc_init(16, 16), so comp->tstate remains valid +and slhc_compress() continues to work. + +Fixes: 4ab42d78e37a ("ppp, slip: Validate VJ compression slot parameters completely") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415204130.258866-2-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index bf9e801cc61cc..3474792a37a67 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + comp->sls_i_error++; + return 0; + } ++ if (!comp->rstate) ++ goto bad; + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. +@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + unsigned int ihl; + ++ if (!comp->rstate) { ++ comp->sls_i_error++; ++ return slhc_toss(comp); ++ } + /* The packet is shorter than a legal IP header. + * Also make sure isize is positive. + */ +-- +2.53.0 + diff --git a/queue-5.15/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch b/queue-5.15/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch new file mode 100644 index 0000000000..320bc28af2 --- /dev/null +++ b/queue-5.15/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch @@ -0,0 +1,41 @@ +From 6f601c0be7cffea7c7bec70c61dc5d9a59be86e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 12:53:23 -0700 +Subject: soc: qcom: aoss: compare against normalized cooling state + +From: Alok Tiwari + +[ Upstream commit cd3c4670db3ffe997be9548c7a9db3952563cf14 ] + +qmp_cdev_set_cur_state() normalizes the requested state to a boolean +(cdev_state = !!state). The existing early-return check compares +qmp_cdev->state == state, which can be wrong if state is non-boolean +(any non-zero value). Compare qmp_cdev->state against cdev_state instead, +so the check matches the effective state and avoids redundant updates. + +Signed-off-by: Alok Tiwari +Fixes: 05589b30b21a ("soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260329195333.1478090-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/qcom_aoss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c +index 3973accdc9820..dbef3b27e594a 100644 +--- a/drivers/soc/qcom/qcom_aoss.c ++++ b/drivers/soc/qcom/qcom_aoss.c +@@ -436,7 +436,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, + /* Normalize state */ + cdev_state = !!state; + +- if (qmp_cdev->state == state) ++ if (qmp_cdev->state == cdev_state) + return 0; + + snprintf(buf, sizeof(buf), +-- +2.53.0 + diff --git a/queue-5.15/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch b/queue-5.15/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch new file mode 100644 index 0000000000..3f93989d84 --- /dev/null +++ b/queue-5.15/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch @@ -0,0 +1,46 @@ +From d5bcdb4986ee549438f506c6f81a58a59f403c31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:58 +0200 +Subject: soc: qcom: ocmem: register reasons for probe deferrals + +From: Dmitry Baryshkov + +[ Upstream commit 9dfd69cd89cd6afa4723be9098979abeef3bb8c6 ] + +Instead of printing messages to the dmesg, let the message be recorded +as a reason for the OCMEM client deferral. + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Brian Masney +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-2-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 0ac0a5426734b..35d96feb6b1e3 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -202,10 +202,10 @@ struct ocmem *of_get_ocmem(struct device *dev) + } + + pdev = of_find_device_by_node(devnode->parent); +- if (!pdev) { +- dev_err(dev, "Cannot find device node %s\n", devnode->name); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!pdev) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, ++ "Cannot find device node %s\n", ++ devnode->name); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-5.15/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch b/queue-5.15/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch new file mode 100644 index 0000000000..5bfd89a4f8 --- /dev/null +++ b/queue-5.15/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch @@ -0,0 +1,46 @@ +From 9ea75ee97dd63799c0d7bc537599fc790b9c8a98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:59 +0200 +Subject: soc: qcom: ocmem: return -EPROBE_DEFER is ocmem is not available + +From: Dmitry Baryshkov + +[ Upstream commit 91b59009c7d48b58dbc50fecb27f2ad20749a05a ] + +If OCMEM is declared in DT, it is expected that it is present and +handled by the driver. The GPU driver will ignore -ENODEV error, which +typically means that OCMEM isn't defined in DT. Let ocmem return +-EPROBE_DEFER if it supposed to be used, but it is not probed (yet). + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-3-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 35d96feb6b1e3..1ece9780e555e 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -209,10 +209,9 @@ struct ocmem *of_get_ocmem(struct device *dev) + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +- if (!ocmem) { +- dev_err(dev, "Cannot get ocmem\n"); +- return ERR_PTR(-ENODEV); +- } ++ if (!ocmem) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n"); ++ + return ocmem; + } + EXPORT_SYMBOL(of_get_ocmem); +-- +2.53.0 + diff --git a/queue-5.15/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch b/queue-5.15/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch new file mode 100644 index 0000000000..0e0bd6cebd --- /dev/null +++ b/queue-5.15/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch @@ -0,0 +1,55 @@ +From a9d34a74436fc06cb3102f034783c148145dd521 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Aug 2024 15:09:50 +0200 +Subject: soc: qcom: ocmem: use scoped device node handling to simplify error + paths + +From: Krzysztof Kozlowski + +[ Upstream commit f4c1c19f5c0e5cf2870df91dedc6b40400fd9c8a ] + +Obtain the device node reference with scoped/cleanup.h to reduce error +handling and make the code a bit simpler. + +Signed-off-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-4-cfb67323a95c@linaro.org +Signed-off-by: Bjorn Andersson +Stable-dep-of: 9dfd69cd89cd ("soc: qcom: ocmem: register reasons for probe deferrals") +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index bfebdcaf88146..0ac0a5426734b 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -192,23 +192,20 @@ static void update_range(struct ocmem *ocmem, struct ocmem_buf *buf, + struct ocmem *of_get_ocmem(struct device *dev) + { + struct platform_device *pdev; +- struct device_node *devnode; + struct ocmem *ocmem; + +- devnode = of_parse_phandle(dev->of_node, "sram", 0); ++ struct device_node *devnode __free(device_node) = of_parse_phandle(dev->of_node, ++ "sram", 0); + if (!devnode || !devnode->parent) { + dev_err(dev, "Cannot look up sram phandle\n"); +- of_node_put(devnode); + return ERR_PTR(-ENODEV); + } + + pdev = of_find_device_by_node(devnode->parent); + if (!pdev) { + dev_err(dev, "Cannot find device node %s\n", devnode->name); +- of_node_put(devnode); + return ERR_PTR(-EPROBE_DEFER); + } +- of_node_put(devnode); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-5.15/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch b/queue-5.15/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..62254e0b3b --- /dev/null +++ b/queue-5.15/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From ceb9db8a69d84b1b36391a977c90630bc68cc8dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:21 +0800 +Subject: spi: fsl-qspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 981b080a79724738882b0af1c5bb7ade30d94f24 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks could +get "lost" - use reinit_completion() in that case, but be aware of +other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: 84d043185dbe ("spi: Add a driver for the Freescale/NXP QuadSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-3-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-fsl-qspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c +index 46ae46a944c5c..2ff26027aafd2 100644 +--- a/drivers/spi/spi-fsl-qspi.c ++++ b/drivers/spi/spi-fsl-qspi.c +@@ -607,7 +607,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) + void __iomem *base = q->iobase; + int err = 0; + +- init_completion(&q->c); ++ reinit_completion(&q->c); + + /* + * Always start the sequence at the same index since we update +@@ -913,6 +913,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) + if (ret < 0) + goto err_disable_clk; + ++ init_completion(&q->c); + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { +-- +2.53.0 + diff --git a/queue-5.15/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch b/queue-5.15/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch new file mode 100644 index 0000000000..219235941b --- /dev/null +++ b/queue-5.15/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch @@ -0,0 +1,55 @@ +From 204b7cd659d13f2c018db038d0522b4369d9b1ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 11:06:41 +0800 +Subject: spi: hisi-kunpeng: prevent infinite while() loop in + hisi_spi_flush_fifo + +From: Pei Xiao + +[ Upstream commit 9f61daf2c2debe9f5cf4e1a4471e56a89a6fe45a ] + +The hisi_spi_flush_fifo()'s inner while loop that lacks any timeout +mechanism. Maybe the hardware never becomes empty, the loop will spin +forever, causing the CPU to hang. + +Fix this by adding a inner_limit based on loops_per_jiffy. The inner loop +now exits after approximately one jiffy if the FIFO remains non-empty, logs +a ratelimited warning, and breaks out of the outer loop. Additionally, add +a cpu_relax() inside the busy loop to improve power efficiency. + +Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/d834ce28172886bfaeb9c8ca00cfd9bf1c65d5a1.1773889292.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-hisi-kunpeng.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index 54730e93fba45..06c8893243b7d 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -198,8 +198,18 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs) + unsigned long limit = loops_per_jiffy << 1; + + do { +- while (hisi_spi_rx_not_empty(hs)) ++ unsigned long inner_limit = loops_per_jiffy; ++ ++ while (hisi_spi_rx_not_empty(hs) && --inner_limit) { + readl(hs->regs + HISI_SPI_DOUT); ++ cpu_relax(); ++ } ++ ++ if (!inner_limit) { ++ dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n"); ++ break; ++ } ++ + } while (hisi_spi_busy(hs) && limit--); + } + +-- +2.53.0 + diff --git a/queue-5.15/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch b/queue-5.15/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch new file mode 100644 index 0000000000..843d34e68f --- /dev/null +++ b/queue-5.15/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch @@ -0,0 +1,40 @@ +From 0d7139914a09e3415b49ef019846229327753ee2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:18 +0000 +Subject: tcp: annotate data-races around (tp->write_seq - tp->snd_nxt) + +From: Eric Dumazet + +[ Upstream commit 3a63b3d160560ef51e43fb4c880a5cde8078053c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() annotations to keep KCSAN happy. + +WRITE_ONCE() annotations are already present. + +Fixes: e08ab0b377a1 ("tcp: add bytes not sent to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-14-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 36981a3e9013f..dbb834d7eaee4 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3961,7 +3961,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +- max_t(int, 0, tp->write_seq - tp->snd_nxt)); ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt))); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, + TCP_NLA_PAD); + if (ack_skb) +-- +2.53.0 + diff --git a/queue-5.15/thermal-drivers-spear-fix-error-condition-for-readin.patch b/queue-5.15/thermal-drivers-spear-fix-error-condition-for-readin.patch new file mode 100644 index 0000000000..f17a6f6c63 --- /dev/null +++ b/queue-5.15/thermal-drivers-spear-fix-error-condition-for-readin.patch @@ -0,0 +1,42 @@ +From e8554378266370de55eaf2b484c0eed4c6d12736 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:35:24 +0530 +Subject: thermal/drivers/spear: Fix error condition for reading + st,thermal-flags + +From: Gopi Krishna Menon + +[ Upstream commit da2c4f332a0504d9c284e7626a561d343c8d6f57 ] + +of_property_read_u32 returns 0 on success. The current check returns +-EINVAL if the property is read successfully. + +Fix the check by removing ! from of_property_read_u32 + +Fixes: b9c7aff481f1 ("drivers/thermal/spear_thermal.c: add Device Tree probing capability") +Signed-off-by: Gopi Krishna Menon +Signed-off-by: Daniel Lezcano +Suggested-by: Daniel Baluta +Reviewed-by: Lukasz Luba +Link: https://patch.msgid.link/20260327090526.59330-1-krishnagopi487@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/thermal/spear_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c +index ee33ed692e4f7..42d8736d5ba49 100644 +--- a/drivers/thermal/spear_thermal.c ++++ b/drivers/thermal/spear_thermal.c +@@ -94,7 +94,7 @@ static int spear_thermal_probe(struct platform_device *pdev) + struct resource *res; + int ret = 0, val; + +- if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) { ++ if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) { + dev_err(&pdev->dev, "Failed: DT Pdata not passed\n"); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-5.15/tipc-fix-double-free-in-tipc_buf_append.patch b/queue-5.15/tipc-fix-double-free-in-tipc_buf_append.patch new file mode 100644 index 0000000000..476bc940db --- /dev/null +++ b/queue-5.15/tipc-fix-double-free-in-tipc_buf_append.patch @@ -0,0 +1,60 @@ +From dd535c03ba3c508250202356087c22a01e7403e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 13:45:26 +0100 +Subject: tipc: fix double-free in tipc_buf_append() + +From: Lee Jones + +[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ] + +tipc_msg_validate() can potentially reallocate the skb it is validating, +freeing the old one. In tipc_buf_append(), it was being called with a +pointer to a local variable which was a copy of the caller's skb +pointer. + +If the skb was reallocated and validation subsequently failed, the error +handling path would free the original skb pointer, which had already +been freed, leading to double-free. + +Fix this by checking if head now points to a newly allocated reassembled +skb. If it does, reassign *headbuf for later freeing operations. + +Fixes: d618d09a68e4 ("tipc: enforce valid ratio between skb truesize and contents") +Suggested-by: Tung Nguyen +Signed-off-by: Lee Jones +Reviewed-by: Tung Nguyen +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/msg.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/net/tipc/msg.c b/net/tipc/msg.c +index 76284fc538ebd..b0bba0feef564 100644 +--- a/net/tipc/msg.c ++++ b/net/tipc/msg.c +@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) + + if (fragid == LAST_FRAGMENT) { + TIPC_SKB_CB(head)->validated = 0; +- if (unlikely(!tipc_msg_validate(&head))) ++ ++ /* If the reassembled skb has been freed in ++ * tipc_msg_validate() because of an invalid truesize, ++ * then head will point to a newly allocated reassembled ++ * skb, while *headbuf points to freed reassembled skb. ++ * In such cases, correct *headbuf for freeing the newly ++ * allocated reassembled skb later. ++ */ ++ if (unlikely(!tipc_msg_validate(&head))) { ++ if (head != *headbuf) ++ *headbuf = head; + goto err; ++ } ++ + *buf = head; + TIPC_SKB_CB(head)->tail = NULL; + *headbuf = NULL; +-- +2.53.0 + diff --git a/queue-5.15/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch b/queue-5.15/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch new file mode 100644 index 0000000000..de6b5a571a --- /dev/null +++ b/queue-5.15/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch @@ -0,0 +1,69 @@ +From 3fc6d112f1178b6cb1d25bbe907a3956bd3bf7a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 06:25:09 -0700 +Subject: tracing: branch: Fix inverted check on stat tracer registration + +From: Breno Leitao + +[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ] + +init_annotated_branch_stats() and all_annotated_branch_stats() check the +return value of register_stat_tracer() with "if (!ret)", but +register_stat_tracer() returns 0 on success and a negative errno on +failure. The inverted check causes the warning to be printed on every +successful registration, e.g.: + + Warning: could not register annotated branches stats + +while leaving real failures silent. The initcall also returned a +hard-coded 1 instead of the actual error. + +Invert the check and propagate ret so that the warning fires on real +errors and the initcall reports the correct status. + +Cc: Mathieu Desnoyers +Cc: Ingo Molnar +Cc: Frederic Weisbecker +Link: https://patch.msgid.link/20260420-tracing-v1-1-d8f4cd0d6af1@debian.org +Fixes: 002bb86d8d42 ("tracing/ftrace: separate events tracing and stats tracing engine") +Signed-off-by: Breno Leitao +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_branch.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c +index e47fdb4c92fbc..30f72e0ecb5d4 100644 +--- a/kernel/trace/trace_branch.c ++++ b/kernel/trace/trace_branch.c +@@ -379,10 +379,10 @@ __init static int init_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&annotated_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "annotated branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +@@ -444,10 +444,10 @@ __init static int all_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&all_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "all branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +-- +2.53.0 + diff --git a/queue-5.15/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch b/queue-5.15/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch new file mode 100644 index 0000000000..fee96dac8a --- /dev/null +++ b/queue-5.15/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch @@ -0,0 +1,56 @@ +From b16179fa5a8ca2a85b3c9a7ce598d69a0b3cba05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 19:22:23 +0800 +Subject: tracing: Rebuild full_name on each hist_field_name() call + +From: Pengpeng Hou + +[ Upstream commit 5ec1d1e97de134beed3a5b08235a60fc1c51af96 ] + +hist_field_name() uses a static MAX_FILTER_STR_VAL buffer for fully +qualified variable-reference names, but it currently appends into that +buffer with strcat() without rebuilding it first. As a result, repeated +calls append a new "system.event.field" name onto the previous one, +which can eventually run past the end of full_name. + +Build the name with snprintf() on each call and return NULL if the fully +qualified name does not fit in MAX_FILTER_STR_VAL. + +Link: https://patch.msgid.link/20260401112224.85582-1-pengpeng@iscas.ac.cn +Fixes: 067fe038e70f ("tracing: Add variable reference handling to hist triggers") +Reviewed-by: Tom Zanussi +Tested-by: Tom Zanussi +Signed-off-by: Pengpeng Hou +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 8795913425416..03473d1e5f8bf 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -1141,12 +1141,14 @@ static const char *hist_field_name(struct hist_field *field, + field->flags & HIST_FIELD_FL_VAR_REF) { + if (field->system) { + static char full_name[MAX_FILTER_STR_VAL]; ++ int len; ++ ++ len = snprintf(full_name, sizeof(full_name), "%s.%s.%s", ++ field->system, field->event_name, ++ field->name); ++ if (len >= sizeof(full_name)) ++ return NULL; + +- strcat(full_name, field->system); +- strcat(full_name, "."); +- strcat(full_name, field->event_name); +- strcat(full_name, "."); +- strcat(full_name, field->name); + field_name = full_name; + } else + field_name = field->name; +-- +2.53.0 + diff --git a/queue-5.15/tty-hvc-remove-hvc_iucv_magic.patch b/queue-5.15/tty-hvc-remove-hvc_iucv_magic.patch new file mode 100644 index 0000000000..8a9cda7e4f --- /dev/null +++ b/queue-5.15/tty-hvc-remove-hvc_iucv_magic.patch @@ -0,0 +1,77 @@ +From d36580ecf61eacb4363ed5bca65ff88375c3d162 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Sep 2022 03:55:18 +0200 +Subject: tty: hvc: remove HVC_IUCV_MAGIC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: наб + +[ Upstream commit eef7381d8134f249dc17138bb1794c249aff7f5a ] + +According to Greg, in the context of magic numbers as defined in +magic-number.rst, "the tty layer should not need this and I'll gladly +take patches" + +This stretches that definition slightly, since it multiplexes it with +the terminal number as a constant offset, but is equivalent + +Acked-by: Jiri Slaby +Signed-off-by: Ahelenia Ziemiańska +Ref: https://lore.kernel.org/linux-doc/YyMlovoskUcHLEb7@kroah.com/ +Link: https://lore.kernel.org/r/8c8a2c9dfc1bfbe6ef3f3237368e483865fc1c29.1663288066.git.nabijaczleweli@nabijaczleweli.xyz +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: f2a880e802ad ("tty: hvc_iucv: fix off-by-one in number of supported devices") +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index 32366caca6623..7d49a872de48a 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -29,7 +29,6 @@ + + + /* General device driver settings */ +-#define HVC_IUCV_MAGIC 0xc9e4c3e5 + #define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS + #define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4) + +@@ -131,9 +130,9 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) ++ if (num > hvc_iucv_devices) + return NULL; +- return hvc_iucv_table[num - HVC_IUCV_MAGIC]; ++ return hvc_iucv_table[num]; + } + + /** +@@ -1072,8 +1071,8 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) + priv->is_console = is_console; + + /* allocate hvc device */ +- priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ +- HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); ++ priv->hvc = hvc_alloc(id, /* PAGE_SIZE */ ++ id, &hvc_iucv_ops, 256); + if (IS_ERR(priv->hvc)) { + rc = PTR_ERR(priv->hvc); + goto out_error_hvc; +@@ -1371,7 +1370,7 @@ static int __init hvc_iucv_init(void) + + /* register the first terminal device as console + * (must be done before allocating hvc terminal devices) */ +- rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops); ++ rc = hvc_instantiate(0, IUCV_HVC_CON_IDX, &hvc_iucv_ops); + if (rc) { + pr_err("Registering HVC terminal device as " + "Linux console failed\n"); +-- +2.53.0 + diff --git a/queue-5.15/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch b/queue-5.15/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch new file mode 100644 index 0000000000..1a9977eea0 --- /dev/null +++ b/queue-5.15/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch @@ -0,0 +1,50 @@ +From a0febc3161dd6331996c58187a22b511c9f5befc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 23:29:37 -0800 +Subject: tty: hvc_iucv: fix off-by-one in number of supported devices + +From: Randy Dunlap + +[ Upstream commit f2a880e802ad12d1e38039d1334fb1475d0f5241 ] + +MAX_HVC_IUCV_LINES == HVC_ALLOC_TTY_ADAPTERS == 8. +This is the number of entries in: + static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; + +Sometimes hvc_iucv_table[] is limited by: +(a) if (num > hvc_iucv_devices) // for error detection +or +(b) for (i = 0; i < hvc_iucv_devices; i++) // in 2 places +(so these 2 don't agree; second one appears to be correct to me.) + +hvc_iucv_devices can be 0..8. This is a counter. +(c) if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + +If hvc_iucv_devices == 8, (a) allows the code to access hvc_iucv_table[8]. +Oops. + +Fixes: 44a01d5ba8a4 ("[S390] s390/hvc_console: z/VM IUCV hypervisor console support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260130072939.1535869-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index 7d49a872de48a..9551269e106a4 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if (num > hvc_iucv_devices) ++ if (num >= hvc_iucv_devices) + return NULL; + return hvc_iucv_table[num]; + } +-- +2.53.0 + diff --git a/queue-5.15/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch b/queue-5.15/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch new file mode 100644 index 0000000000..6ece97f296 --- /dev/null +++ b/queue-5.15/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch @@ -0,0 +1,91 @@ +From 26d3e476f80e52bbc12c0316a375361fb1d1223b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 11:39:59 -0800 +Subject: unshare: fix nsproxy leak in ksys_unshare() on set_cred_ucounts() + failure + +From: Michal Grzedzicki + +[ Upstream commit a98621a0f187a934c115dcfe79a49520ae892111 ] + +When set_cred_ucounts() fails in ksys_unshare() new_nsproxy is leaked. + +Let's call put_nsproxy() if that happens. + +Link: https://lkml.kernel.org/r/20260213193959.2556730-1-mge@meta.com +Fixes: 905ae01c4ae2 ("Add a reference to ucounts for each cred") +Signed-off-by: Michal Grzedzicki +Reviewed-by: Andrew Morton +Cc: Alexey Gladkov (Intel) +Cc: Ben Segall +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: "Liam R. Howlett" +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index e1b291e5e1038..eb772b1e819f2 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -3176,11 +3176,10 @@ int ksys_unshare(unsigned long unshare_flags) + new_cred, new_fs); + if (err) + goto bad_unshare_cleanup_cred; +- + if (new_cred) { + err = set_cred_ucounts(new_cred); + if (err) +- goto bad_unshare_cleanup_cred; ++ goto bad_unshare_cleanup_nsproxy; + } + + if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { +@@ -3196,8 +3195,10 @@ int ksys_unshare(unsigned long unshare_flags) + shm_init_task(current); + } + +- if (new_nsproxy) ++ if (new_nsproxy) { + switch_task_namespaces(current, new_nsproxy); ++ new_nsproxy = NULL; ++ } + + task_lock(current); + +@@ -3229,13 +3230,15 @@ int ksys_unshare(unsigned long unshare_flags) + + perf_event_namespaces(current); + ++bad_unshare_cleanup_nsproxy: ++ if (new_nsproxy) ++ put_nsproxy(new_nsproxy); + bad_unshare_cleanup_cred: + if (new_cred) + put_cred(new_cred); + bad_unshare_cleanup_fd: + if (new_fd) + put_files_struct(new_fd); +- + bad_unshare_cleanup_fs: + if (new_fs) + free_fs_struct(new_fs); +-- +2.53.0 + diff --git a/queue-5.15/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch b/queue-5.15/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch new file mode 100644 index 0000000000..b82867966d --- /dev/null +++ b/queue-5.15/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch @@ -0,0 +1,64 @@ +From c0cbd38d9b31f9a61cfad832548ba55682bb4bab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 02:30:24 +0000 +Subject: vhost_net: fix sleeping with preempt-disabled in + vhost_net_busy_poll() + +From: Kohei Enju + +[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ] + +syzbot reported "sleeping function called from invalid context" in +vhost_net_busy_poll(). + +Commit 030881372460 ("vhost_net: basic polling support") introduced a +busy-poll loop and preempt_{disable,enable}() around it, where each +iteration calls a sleepable function inside the loop. + +The purpose of disabling preemption was to keep local_clock()-based +timeout accounting on a single CPU, rather than as a requirement of +busy-poll itself: + +https://lore.kernel.org/1448435489-5949-4-git-send-email-jasowang@redhat.com + +From this perspective, migrate_disable() is sufficient here, so replace +preempt_disable() with migrate_disable(), avoiding sleepable accesses +from a preempt-disabled context. + +Fixes: 030881372460 ("vhost_net: basic polling support") +Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/ +Signed-off-by: Kohei Enju +Acked-by: Michael S. Tsirkin +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/vhost/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index 7a6892cfa3c5e..9d454da419955 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -545,7 +545,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + busyloop_timeout = poll_rx ? rvq->busyloop_timeout: + tvq->busyloop_timeout; + +- preempt_disable(); ++ migrate_disable(); + endtime = busy_clock() + busyloop_timeout; + + while (vhost_can_busy_poll(endtime)) { +@@ -562,7 +562,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + cpu_relax(); + } + +- preempt_enable(); ++ migrate_enable(); + + if (poll_rx || sock_has_rx_data(sock)) + vhost_net_busy_poll_try_queue(net, vq); +-- +2.53.0 + diff --git a/queue-5.15/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch b/queue-5.15/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch new file mode 100644 index 0000000000..ffdb6515f6 --- /dev/null +++ b/queue-5.15/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch @@ -0,0 +1,115 @@ +From 130e4f01c17ea3c4ed51c58eda2f00af89f1c7b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 09:36:07 +0300 +Subject: vrf: Fix a potential NPD when removing a port from a VRF + +From: Ido Schimmel + +[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ] + +RCU readers that identified a net device as a VRF port using +netif_is_l3_slave() assume that a subsequent call to +netdev_master_upper_dev_get_rcu() will return a VRF device. They then +continue to dereference its l3mdev operations. + +This assumption is not always correct and can result in a NPD [1]. There +is no RCU synchronization when removing a port from a VRF, so it is +possible for an RCU reader to see a new master device (e.g., a bridge) +that does not have l3mdev operations. + +Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE +flag. Skip this synchronization when a net device is removed from a VRF +as part of its deletion and when the VRF device itself is deleted. In +the latter case an RCU grace period will pass by the time RTNL is +released. + +[1] +BUG: kernel NULL pointer dereference, address: 0000000000000000 +[...] +RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) +[...] +Call Trace: + +l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) +__inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) +inet_bind_sk (net/ipv4/af_inet.c:469) +__sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) +__x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Fixes: fdeea7be88b1 ("net: vrf: Set slave's private flag before linking") +Reported-by: Haoze Xie +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/netdev/20260419145332.3988923-1-n05ec@lzu.edu.cn/ +Signed-off-by: Ido Schimmel +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260423063607.1208202-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vrf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index 6c719d6da5b82..c0752e8748529 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -1135,6 +1135,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + + err: + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ synchronize_net(); + return ret; + } + +@@ -1154,10 +1155,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + } + + /* inverse of do_vrf_add_slave */ +-static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) ++static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, ++ bool needs_sync) + { + netdev_upper_dev_unlink(port_dev, dev); + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ /* Make sure that concurrent RCU readers that identified the device ++ * as a VRF port see a VRF master or no master at all. ++ */ ++ if (needs_sync) ++ synchronize_net(); + + cycle_netdev(port_dev, NULL); + +@@ -1166,7 +1173,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + + static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + { +- return do_vrf_del_slave(dev, port_dev); ++ return do_vrf_del_slave(dev, port_dev, true); + } + + static void vrf_dev_uninit(struct net_device *dev) +@@ -1731,7 +1738,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) + struct list_head *iter; + + netdev_for_each_lower_dev(dev, port_dev, iter) +- vrf_del_slave(dev, port_dev); ++ do_vrf_del_slave(dev, port_dev, false); + + vrf_map_unregister_dev(dev); + +@@ -1862,7 +1869,7 @@ static int vrf_device_event(struct notifier_block *unused, + goto out; + + vrf_dev = netdev_master_upper_dev_get(dev); +- vrf_del_slave(vrf_dev, dev); ++ do_vrf_del_slave(vrf_dev, dev, false); + } + out: + return NOTIFY_DONE; +-- +2.53.0 + diff --git a/queue-5.15/wifi-brcmfmac-fix-error-pointer-dereference.patch b/queue-5.15/wifi-brcmfmac-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..0c1936a0b9 --- /dev/null +++ b/queue-5.15/wifi-brcmfmac-fix-error-pointer-dereference.patch @@ -0,0 +1,80 @@ +From 13d5fa13994026268e742d3170662472f1599f1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 20:30:43 -0600 +Subject: wifi: brcmfmac: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit dd8592fc6007a451c3e4b9025de365e39de8178a ] + +The function brcmf_chip_add_core() can return an error pointer and is +not checked. Add checks for error pointer. + +Detected by Smatch: +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1010 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1013 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1016 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1019 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1022 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +Fixes: cb7cf7be9eba7 ("brcmfmac: make chip related functions host interface independent") +Signed-off-by: Ethan Tidmore +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260217023043.73631-1-ethantidmore06@gmail.com +[add missing wifi: prefix] +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 1ee49f9e325db..d4a3992323796 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -986,18 +986,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + + core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, + SI_ENUM_BASE_DEFAULT, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, + BCM4329_CORE_BUS_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, + BCM4329_CORE_SOCRAM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, + BCM4329_CORE_ARM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + + core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + } else if (socitype == SOCI_AI) { + ci->iscoreup = brcmf_chip_ai_iscoreup; +-- +2.53.0 + diff --git a/queue-5.15/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch b/queue-5.15/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch new file mode 100644 index 0000000000..193d10350b --- /dev/null +++ b/queue-5.15/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch @@ -0,0 +1,49 @@ +From b1cfe16cedbde29298a5cf6402ef49d1c6c531fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 09:26:25 +0000 +Subject: wifi: mwifiex: Fix memory leak in mwifiex_11n_aggregate_pkt() + +From: Zilin Guan + +[ Upstream commit 990a73dec3fdc145fef6c827c29205437d533ece ] + +In mwifiex_11n_aggregate_pkt(), skb_aggr is allocated via +mwifiex_alloc_dma_align_buf(). If mwifiex_is_ralist_valid() returns false, +the function currently returns -1 immediately without freeing the +previously allocated skb_aggr, causing a memory leak. + +Since skb_aggr has not yet been queued via skb_queue_tail(), no other +references to this memory exist. Therefore, it has to be freed locally +before returning the error. + +Fix this by calling mwifiex_write_data_complete() to free skb_aggr before +returning the error status. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") +Signed-off-by: Zilin Guan +Reviewed-by: Jeff Chen +Link: https://patch.msgid.link/20260119092625.1349934-1-zilin@seu.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +index 46f41dbcf30dd..54662bc5bc152 100644 +--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +@@ -215,6 +215,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); ++ mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); + return -1; + } + +-- +2.53.0 + diff --git a/queue-5.15/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch b/queue-5.15/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch new file mode 100644 index 0000000000..2230032680 --- /dev/null +++ b/queue-5.15/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch @@ -0,0 +1,49 @@ +From 4125bf8fd3f62a66e2dc277fa15d1ca396e37f37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:55:22 +0800 +Subject: wifi: rtlwifi: pci: fix possible use-after-free caused by unfinished + irq_prepare_bcn_tasklet + +From: Duoming Zhou + +[ Upstream commit 039cd522dc70151da13329a5e3ae19b1736f468a ] + +The irq_prepare_bcn_tasklet is initialized in rtl_pci_init() and +scheduled when RTL_IMR_BCNINT interrupt is triggered by hardware. +But it is never killed in rtl_pci_deinit(). When the rtlwifi card +probe fails or is being detached, the ieee80211_hw is deallocated. +However, irq_prepare_bcn_tasklet may still be running or pending, +leading to use-after-free when the freed ieee80211_hw is accessed +in _rtl_pci_prepare_bcn_tasklet(). + +Similar to irq_tasklet, add tasklet_kill() in rtl_pci_deinit() to +ensure that irq_prepare_bcn_tasklet is properly terminated before +the ieee80211_hw is released. + +The issue was identified through static analysis. + +Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") +Signed-off-by: Duoming Zhou +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260223045522.48377-1-duoming@zju.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtlwifi/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index 02821588673e5..3058c8356c292 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -1675,6 +1675,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); ++ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + } + +-- +2.53.0 + diff --git a/queue-6.1/6pack-propagage-new-tty-types.patch b/queue-6.1/6pack-propagage-new-tty-types.patch new file mode 100644 index 0000000000..37cfff628a --- /dev/null +++ b/queue-6.1/6pack-propagage-new-tty-types.patch @@ -0,0 +1,136 @@ +From 2a0da0204cbe0ef1f6cf0bbbc84319da97fd63ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 12:35:47 +0200 +Subject: 6pack: propagage new tty types + +From: Jiri Slaby (SUSE) + +[ Upstream commit 1241b384efa53f4b7a95fe2b34d69359bb3ae1b5 ] + +In tty, u8 is now used for data, ssize_t for sizes (with possible +negative error codes). Propagate these types to 6pack. + +Signed-off-by: Jiri Slaby (SUSE) +Cc: Greg Kroah-Hartman +Cc: Andreas Koensgen +Cc: David S. Miller +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: linux-hams@vger.kernel.org +Cc: netdev@vger.kernel.org +Reviewed-by: Jeremy Kerr +Link: https://lore.kernel.org/r/20240808103549.429349-12-jirislaby@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bf9a38803b26 ("net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf") +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 1b007dd174794..fe85cffa4f945 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -94,8 +94,8 @@ struct sixpack { + unsigned char *xhead; /* next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + +- unsigned char raw_buf[4]; +- unsigned char cooked_buf[400]; ++ u8 raw_buf[4]; ++ u8 cooked_buf[400]; + + unsigned int rx_count; + unsigned int rx_count_cooked; +@@ -113,8 +113,8 @@ struct sixpack { + unsigned char slottime; + unsigned char duplex; + unsigned char led_state; +- unsigned char status; +- unsigned char status1; ++ u8 status; ++ u8 status1; + unsigned char status2; + unsigned char tx_enable; + unsigned char tnc_state; +@@ -126,7 +126,7 @@ struct sixpack { + + #define AX25_6PACK_HEADER_LEN 0 + +-static void sixpack_decode(struct sixpack *, const unsigned char[], int); ++static void sixpack_decode(struct sixpack *, const u8 *, size_t); + static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); + + /* +@@ -331,7 +331,7 @@ static void sp_bump(struct sixpack *sp, char cmd) + { + struct sk_buff *skb; + int count; +- unsigned char *ptr; ++ u8 *ptr; + + count = sp->rcount + 1; + +@@ -397,7 +397,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, + const unsigned char *cp, const char *fp, int count) + { + struct sixpack *sp; +- int count1; ++ size_t count1; + + if (!count) + return; +@@ -773,9 +773,9 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, + + /* decode 4 sixpack-encoded bytes into 3 data bytes */ + +-static void decode_data(struct sixpack *sp, unsigned char inbyte) ++static void decode_data(struct sixpack *sp, u8 inbyte) + { +- unsigned char *buf; ++ u8 *buf; + + if (sp->rx_count != 3) { + sp->raw_buf[sp->rx_count++] = inbyte; +@@ -801,9 +801,9 @@ static void decode_data(struct sixpack *sp, unsigned char inbyte) + + /* identify and execute a 6pack priority command byte */ + +-static void decode_prio_command(struct sixpack *sp, unsigned char cmd) ++static void decode_prio_command(struct sixpack *sp, u8 cmd) + { +- int actual; ++ ssize_t actual; + + if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ + +@@ -851,9 +851,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd) + + /* identify and execute a standard 6pack command byte */ + +-static void decode_std_command(struct sixpack *sp, unsigned char cmd) ++static void decode_std_command(struct sixpack *sp, u8 cmd) + { +- unsigned char checksum = 0, rest = 0; ++ u8 checksum = 0, rest = 0; + short i; + + switch (cmd & SIXP_CMD_MASK) { /* normal command */ +@@ -901,10 +901,10 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd) + /* decode a 6pack packet */ + + static void +-sixpack_decode(struct sixpack *sp, const unsigned char *pre_rbuff, int count) ++sixpack_decode(struct sixpack *sp, const u8 *pre_rbuff, size_t count) + { +- unsigned char inbyte; +- int count1; ++ size_t count1; ++ u8 inbyte; + + for (count1 = 0; count1 < count; count1++) { + inbyte = pre_rbuff[count1]; +-- +2.53.0 + diff --git a/queue-6.1/acpi-agdi-fix-missing-newline-in-error-message.patch b/queue-6.1/acpi-agdi-fix-missing-newline-in-error-message.patch new file mode 100644 index 0000000000..dfc643cca8 --- /dev/null +++ b/queue-6.1/acpi-agdi-fix-missing-newline-in-error-message.patch @@ -0,0 +1,40 @@ +From 7bdb9aeb39488ce9cbf1395ee827e0aa9a400c3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:31:15 +0800 +Subject: ACPI: AGDI: fix missing newline in error message + +From: Haoyu Lu + +[ Upstream commit b178330b67abb7293b6de28b2a49d49c83962db5 ] + +Add the missing trailing newline to the dev_err() message +printed when SDEI event registration fails. + +This keeps the error output as a properly terminated log line. + +Fixes: a2a591fb76e6 ("ACPI: AGDI: Add driver for Arm Generic Diagnostic Dump and Reset device") +Reviewed-by: Ilkka Koskinen +Signed-off-by: Haoyu Lu +Reviewed-by: Hanjun Guo +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + drivers/acpi/arm64/agdi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c +index cf31abd0ed1bb..53a674c83f588 100644 +--- a/drivers/acpi/arm64/agdi.c ++++ b/drivers/acpi/arm64/agdi.c +@@ -32,7 +32,7 @@ static int agdi_sdei_probe(struct platform_device *pdev, + + err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev); + if (err) { +- dev_err(&pdev->dev, "Failed to register for SDEI event %d", ++ dev_err(&pdev->dev, "Failed to register for SDEI event %d\n", + adata->sdei_event); + return err; + } +-- +2.53.0 + diff --git a/queue-6.1/alsa-core-validate-compress-device-numbers-without-d.patch b/queue-6.1/alsa-core-validate-compress-device-numbers-without-d.patch new file mode 100644 index 0000000000..f715d7945b --- /dev/null +++ b/queue-6.1/alsa-core-validate-compress-device-numbers-without-d.patch @@ -0,0 +1,81 @@ +From b368cb05bf4c2deb42ba97d1254b9983475f66b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 02:24:04 -0300 +Subject: ALSA: core: Validate compress device numbers without dynamic minors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 796e119e9b14763be905ad0d023c71a14bc2e931 ] + +Without CONFIG_SND_DYNAMIC_MINORS, ALSA reserves only two fixed minors +for compress devices on each card: comprD0 and comprD1. + +snd_find_free_minor() currently computes the compress minor as +type + dev without validating dev first, so device numbers greater than +1 spill into the HWDEP minor range instead of failing registration. + +ASoC passes rtd->id to snd_compress_new(), so this can happen on real +non-dynamic-minor builds. + +Add a dedicated fixed-minor check for SNDRV_DEVICE_TYPE_COMPRESS in +snd_find_free_minor() and reject out-of-range device numbers with +-EINVAL before constructing the minor. + +Also remove the stale TODO in compress_offload.c that still claims +multiple compress nodes are missing. + +Fixes: 3eafc959b32f ("ALSA: core: add support for compressed devices") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-alsa-compress-static-minors-v1-1-0628573bee1c@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 7 ------- + sound/core/sound.c | 7 +++++++ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 243acad89fd3b..f1140a6bc996d 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -40,13 +40,6 @@ + #define COMPR_CODEC_CAPS_OVERFLOW + #endif + +-/* TODO: +- * - add substream support for multiple devices in case of +- * SND_DYNAMIC_MINORS is not used +- * - Multiple node representation +- * driver should be able to register multiple nodes +- */ +- + struct snd_compr_file { + unsigned long caps; + struct snd_compr_stream stream; +diff --git a/sound/core/sound.c b/sound/core/sound.c +index df5571d986295..f3bb0adf37cce 100644 +--- a/sound/core/sound.c ++++ b/sound/core/sound.c +@@ -219,9 +219,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev) + case SNDRV_DEVICE_TYPE_RAWMIDI: + case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: + case SNDRV_DEVICE_TYPE_PCM_CAPTURE: ++ if (snd_BUG_ON(!card)) ++ return -EINVAL; ++ minor = SNDRV_MINOR(card->number, type + dev); ++ break; + case SNDRV_DEVICE_TYPE_COMPRESS: + if (snd_BUG_ON(!card)) + return -EINVAL; ++ if (dev < 0 || ++ dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS) ++ return -EINVAL; + minor = SNDRV_MINOR(card->number, type + dev); + break; + default: +-- +2.53.0 + diff --git a/queue-6.1/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch b/queue-6.1/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch new file mode 100644 index 0000000000..94247ff7b7 --- /dev/null +++ b/queue-6.1/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch @@ -0,0 +1,60 @@ +From 6fdb757ae58859e57098da617255cc30e00f1fc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:04:50 +0800 +Subject: ALSA: hda/conexant: Fix missing error check for jack detection + +From: wangdicheng + +[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ] + +In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() +is ignored. This function returns a pointer, and if it fails (e.g., due +to memory allocation failure), it returns an error pointer which must +be checked using IS_ERR(). + +If the registration fails, the driver continues to probe, but the jack +detection callback will not be registered. This can lead to a kernel +crash later when the driver attempts to handle jack events or accesses +the uninitialized structure. + +Check the return value using IS_ERR() and propagate the error via +PTR_ERR() to the probe caller. + +Fixes: 7aeb25908648 ("ALSA: hda/conexant: Fix headset auto detect fail in cx8070 and SN6140") +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428080450.108801-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 7aeaccc9189c8..82186c4364c9b 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -1199,6 +1199,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) + static int patch_conexant_auto(struct hda_codec *codec) + { + struct conexant_spec *spec; ++ struct hda_jack_callback *callback; + int err; + + codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); +@@ -1215,7 +1216,12 @@ static int patch_conexant_auto(struct hda_codec *codec) + case 0x14f11f86: + case 0x14f11f87: + spec->is_cx11880_sn6140 = true; +- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); ++ callback = snd_hda_jack_detect_enable_callback(codec, 0x19, ++ cx_update_headset_mic_vref); ++ if (IS_ERR(callback)) { ++ err = PTR_ERR(callback); ++ goto error; ++ } + break; + } + +-- +2.53.0 + diff --git a/queue-6.1/alsa-hda-conexant-fix-some-typos.patch b/queue-6.1/alsa-hda-conexant-fix-some-typos.patch new file mode 100644 index 0000000000..1de030dca1 --- /dev/null +++ b/queue-6.1/alsa-hda-conexant-fix-some-typos.patch @@ -0,0 +1,64 @@ +From 696257e9e58abf0845946966d2579009be5d5a3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 16:41:32 +0800 +Subject: ALSA: hda/conexant: fix some typos + +From: Oldherl Oh + +[ Upstream commit 73253f2fd1d0a44708735c842e37163712e3f03b ] + +Fix some typos in patch_conexant.c + +Signed-off-by: Oldherl Oh +Link: https://patch.msgid.link/20240930084132.3373750-1-me@oldherl.one +Signed-off-by: Takashi Iwai +Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index e5837e47aa227..394932123b51d 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -166,18 +166,18 @@ static void cxt_init_gpio_led(struct hda_codec *codec) + + static void cx_fixup_headset_recog(struct hda_codec *codec) + { +- unsigned int mic_persent; ++ unsigned int mic_present; + + /* fix some headset type recognize fail issue, such as EDIFIER headset */ +- /* set micbiasd output current comparator threshold from 66% to 55%. */ ++ /* set micbias output current comparator threshold from 66% to 55%. */ + snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010); +- /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias registor ++ /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register + * value adjustment trim from 2.2K ohms to 2.0K ohms. + */ + snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10); + /* fix reboot headset type recognize fail issue */ +- mic_persent = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); +- if (mic_persent & AC_PINSENSE_PRESENCE) ++ mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); ++ if (mic_present & AC_PINSENSE_PRESENCE) + /* enable headset mic VREF */ + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); + else +@@ -247,9 +247,9 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ + { + unsigned int mic_present; + +- /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled, +- * the node 19 can only be config to microphone or disabled. +- * Check hp&mic tag to process headset pulgin&plugout. ++ /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, ++ * the node 19 can only be configured to microphone or disabled. ++ * Check hp&mic tag to process headset plugin & plugout. + */ + mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); + if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ +-- +2.53.0 + diff --git a/queue-6.1/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch b/queue-6.1/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch new file mode 100644 index 0000000000..362b31bb04 --- /dev/null +++ b/queue-6.1/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch @@ -0,0 +1,79 @@ +From 494ce1cb1b35a81655fa52f3f0c37e4c2c85c3ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Jun 2025 15:43:31 +0800 +Subject: ALSA: hda/conexant: Renaming the codec with device ID 0x1f86 and + 0x1f87 + +From: wangdicheng + +[ Upstream commit 7f4c540e0859e2025675d2c5c5c6ab88eaf817e2 ] + +Due to changes in the manufacturer's plan, all 0x14f11f86 will be +named CX11880, and 0x14f11f87 will be named SN6140 + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20250616074331.581309-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 394932123b51d..7aeaccc9189c8 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -42,7 +42,7 @@ struct conexant_spec { + unsigned int gpio_led; + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; +- bool is_cx8070_sn6140; ++ bool is_cx11880_sn6140; + }; + + +@@ -195,7 +195,7 @@ static int cx_auto_init(struct hda_codec *codec) + cxt_init_gpio_led(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + +- if (spec->is_cx8070_sn6140) ++ if (spec->is_cx11880_sn6140) + cx_fixup_headset_recog(codec); + + return 0; +@@ -247,7 +247,7 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ + { + unsigned int mic_present; + +- /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, ++ /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled, + * the node 19 can only be configured to microphone or disabled. + * Check hp&mic tag to process headset plugin & plugout. + */ +@@ -1210,11 +1210,11 @@ static int patch_conexant_auto(struct hda_codec *codec) + codec->spec = spec; + codec->patch_ops = cx_auto_patch_ops; + +- /* init cx8070/sn6140 flag and reset headset_present_flag */ ++ /* init cx11880/sn6140 flag and reset headset_present_flag */ + switch (codec->core.vendor_id) { + case 0x14f11f86: + case 0x14f11f87: +- spec->is_cx8070_sn6140 = true; ++ spec->is_cx11880_sn6140 = true; + snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); + break; + } +@@ -1302,7 +1302,7 @@ static int patch_conexant_auto(struct hda_codec *codec) + */ + + static const struct hda_device_id snd_hda_id_conexant[] = { +- HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), ++ HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), +-- +2.53.0 + diff --git a/queue-6.1/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch b/queue-6.1/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch new file mode 100644 index 0000000000..d6a7194589 --- /dev/null +++ b/queue-6.1/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch @@ -0,0 +1,45 @@ +From 718918bfa930f149bc0b6608ef94082aa48153fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 15:54:05 +0800 +Subject: ALSA: hda/realtek: fix code style (ERROR: else should follow close + brace '}') + +From: Lei Huang + +[ Upstream commit d1888bf848ade6a9e71c7ba516fd215aa1bd8d65 ] + +Fix checkpatch code style errors: + + ERROR: else should follow close brace '}' + #2300: FILE: sound/hda/codecs/realtek/alc269.c:2300: + + } + + else + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Lei Huang +Link: https://patch.msgid.link/20260331075405.78148-1-huanglei814@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 9bda2f43394cb..7b4fd95c66f9b 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -6040,9 +6040,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } +- else ++ } else { + alc_fixup_headset_mode(codec, fix, action); ++ } + } + + static void alc288_update_headset_jack_cb(struct hda_codec *codec, +-- +2.53.0 + diff --git a/queue-6.1/alsa-hda-realtek-whitespace-fix.patch b/queue-6.1/alsa-hda-realtek-whitespace-fix.patch new file mode 100644 index 0000000000..55633f729f --- /dev/null +++ b/queue-6.1/alsa-hda-realtek-whitespace-fix.patch @@ -0,0 +1,37 @@ +From 9cab83f7314840dd743f7bfd2eb3c9e577eb3906 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jul 2023 16:46:19 +1200 +Subject: ALSA: hda/realtek: Whitespace fix + +From: Luke D. Jones + +[ Upstream commit 72cea3a3175b50a4875b3c112fb13df20c6218a5 ] + +Remove an erroneous whitespace. + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Luke D. Jones +Link: https://lore.kernel.org/r/20230704044619.19343-6-luke@ljones.dev +Signed-off-by: Takashi Iwai +Stable-dep-of: d1888bf848ad ("ALSA: hda/realtek: fix code style (ERROR: else should follow close brace '}')") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 0889dfd80fa44..9bda2f43394cb 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -6040,7 +6040,7 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } ++ } + else + alc_fixup_headset_mode(codec, fix, action); + } +-- +2.53.0 + diff --git a/queue-6.1/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch b/queue-6.1/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch new file mode 100644 index 0000000000..897020c1b7 --- /dev/null +++ b/queue-6.1/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch @@ -0,0 +1,289 @@ +From 7087737a319085a611ff1b768fa42c2db0d9716f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:54:32 -0300 +Subject: ALSA: sc6000: Keep the programmed board state in card-private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit fb79bf127ac2577b4876132da6dba768018aad4c ] + +The driver may auto-select IRQ and DMA resources at probe time, but +sc6000_init_board() still derives the SC-6000 soft configuration from +the module parameter arrays. When irq=auto or dma=auto is used, the +codec is created with the selected resources while the board is +programmed with the unresolved values. + +Store the mapped ports and generated SC-6000 board configuration in +card-private data, build that configuration from the live probe +results instead of the raw module parameters, and keep the probe-time +board programming in a shared helper. + +This fixes the resource-programming mismatch and leaves the driver +with a stable board-state block that can be reused by suspend/resume. + +Fixes: c282866101bf ("ALSA: sc6000: add support for SC-6600 and SC-7000") +Signed-off-by: Cássio Gabriel +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260410-alsa-sc6000-pm-v1-1-4d9e95493d26@gmail.com +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 152 +++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 60 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 3115c32b4061b..4066b68a102e2 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -100,6 +100,15 @@ MODULE_PARM_DESC(joystick, "Enable gameport."); + #define PFX "sc6000: " + #define DRV_NAME "SC-6000" + ++struct snd_sc6000 { ++ char __iomem *vport; ++ char __iomem *vmss_port; ++ u8 mss_config; ++ u8 config; ++ u8 hw_cfg[2]; ++ bool old_dsp; ++}; ++ + /* hardware dependent functions */ + + /* +@@ -267,7 +276,7 @@ static int sc6000_dsp_reset(char __iomem *vport) + + /* detection and initialization */ + static int sc6000_hw_cfg_write(struct device *devptr, +- char __iomem *vport, const int *cfg) ++ char __iomem *vport, const u8 *cfg) + { + if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { + dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); +@@ -353,8 +362,7 @@ static int sc6000_init_mss(struct device *devptr, + return 0; + } + +-static void sc6000_hw_cfg_encode(struct device *devptr, +- char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, u8 *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -376,27 +384,83 @@ static void sc6000_hw_cfg_encode(struct device *devptr, + dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(struct device *devptr, +- char __iomem *vport, +- char __iomem *vmss_port, int dev) ++static void sc6000_prepare_board(struct device *devptr, ++ struct snd_sc6000 *sc6000, ++ unsigned int dev, int xirq, int xdma) ++{ ++ sc6000->mss_config = sc6000_irq_to_softcfg(xirq) | ++ sc6000_dma_to_softcfg(xdma); ++ sc6000->config = sc6000->mss_config | ++ sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); ++ sc6000_hw_cfg_encode(devptr, sc6000->hw_cfg, port[dev], mpu_port[dev], ++ mss_port[dev], joystick[dev]); ++} ++ ++static void sc6000_detect_old_dsp(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ sc6000_write(devptr, sc6000->vport, COMMAND_5C); ++ sc6000->old_dsp = sc6000_read(sc6000->vport) < 0; ++} ++ ++static int sc6000_program_board(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ int err; ++ ++ if (!sc6000->old_dsp) { ++ if (sc6000_hw_cfg_write(devptr, sc6000->vport, ++ sc6000->hw_cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); ++ return -EIO; ++ } ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ sc6000_dsp_reset(sc6000->vport); ++ ++ if (!sc6000->old_dsp) { ++ sc6000_write(devptr, sc6000->vport, COMMAND_60); ++ sc6000_write(devptr, sc6000->vport, 0x02); ++ sc6000_dsp_reset(sc6000->vport); ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ err = sc6000_init_mss(devptr, sc6000->vport, sc6000->config, ++ sc6000->vmss_port, sc6000->mss_config); ++ if (err < 0) { ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int sc6000_init_board(struct device *devptr, struct snd_sc6000 *sc6000) + { + char answer[15]; + char version[2]; +- int mss_config = sc6000_irq_to_softcfg(irq[dev]) | +- sc6000_dma_to_softcfg(dma[dev]); +- int config = mss_config | +- sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); + int err; +- int old = 0; + +- err = sc6000_dsp_reset(vport); ++ err = sc6000_dsp_reset(sc6000->vport); + if (err < 0) { + dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, sc6000->vport, GET_DSP_COPYRIGHT, ++ answer, 15); + if (err <= 0) { + dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; +@@ -408,54 +472,17 @@ static int sc6000_init_board(struct device *devptr, + if (strncmp("SC-6000", answer, 7)) + dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ if (sc6000_dsp_get_answer(devptr, sc6000->vport, ++ GET_DSP_VERSION, version, 2) < 2) { + dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } + dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + +- /* set configuration */ +- sc6000_write(devptr, vport, COMMAND_5C); +- if (sc6000_read(vport) < 0) +- old = 1; +- +- if (!old) { +- int cfg[2]; +- sc6000_hw_cfg_encode(devptr, +- vport, &cfg[0], port[dev], mpu_port[dev], +- mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { +- dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); +- return -EIO; +- } +- } +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- +- sc6000_dsp_reset(vport); +- +- if (!old) { +- sc6000_write(devptr, vport, COMMAND_60); +- sc6000_write(devptr, vport, 0x02); +- sc6000_dsp_reset(vport); +- } ++ sc6000_detect_old_dsp(devptr, sc6000); + +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); +- if (err < 0) { +- dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); +- return -ENODEV; +- } +- +- return 0; ++ return sc6000_program_board(devptr, sc6000); + } + + static int snd_sc6000_mixer(struct snd_wss *chip) +@@ -538,10 +565,10 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + + static void snd_sc6000_free(struct snd_card *card) + { +- char __iomem *vport = (char __force __iomem *)card->private_data; ++ struct snd_sc6000 *sc6000 = card->private_data; + +- if (vport) +- sc6000_setup_board(card->dev, vport, 0); ++ if (sc6000->vport) ++ sc6000_setup_board(card->dev, sc6000->vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -552,15 +579,17 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + int xirq = irq[dev]; + int xdma = dma[dev]; + struct snd_card *card; ++ struct snd_sc6000 *sc6000; + struct snd_wss *chip; + struct snd_opl3 *opl3; + char __iomem *vport; + char __iomem *vmss_port; + + err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE, +- 0, &card); ++ sizeof(*sc6000), &card); + if (err < 0) + return err; ++ sc6000 = card->private_data; + + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); +@@ -587,7 +616,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } +- card->private_data = (void __force *)vport; ++ sc6000->vport = vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +@@ -600,12 +629,15 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } ++ sc6000->vmss_port = vmss_port; + + dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(devptr, vport, vmss_port, dev); ++ sc6000_prepare_board(devptr, sc6000, dev, xirq, xdma); ++ ++ err = sc6000_init_board(devptr, sc6000); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +-- +2.53.0 + diff --git a/queue-6.1/alsa-sc6000-use-standard-print-api.patch b/queue-6.1/alsa-sc6000-use-standard-print-api.patch new file mode 100644 index 0000000000..280eae7ead --- /dev/null +++ b/queue-6.1/alsa-sc6000-use-standard-print-api.patch @@ -0,0 +1,453 @@ +From a0806e9fb0f4f6eaeb638eebba0f3fcd47178c73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Aug 2024 15:34:23 +0200 +Subject: ALSA: sc6000: Use standard print API + +From: Takashi Iwai + +[ Upstream commit e7c475b92043c02c3e6cd0c20e308fbb6f03ebde ] + +Use the standard print API with dev_*() instead of the old house-baked +one. It gives better information and allows dynamically control of +debug prints. + +Some functions are changed to receive a device pointer to be passed to +dev_*() calls. + +Reviewed-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20240807133452.9424-34-tiwai@suse.de +Stable-dep-of: fb79bf127ac2 ("ALSA: sc6000: Keep the programmed board state in card-private data") +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 177 +++++++++++++++++++++++---------------------- + 1 file changed, 90 insertions(+), 87 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 60398fced046b..3115c32b4061b 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -204,7 +204,7 @@ static int sc6000_read(char __iomem *vport) + + } + +-static int sc6000_write(char __iomem *vport, int cmd) ++static int sc6000_write(struct device *devptr, char __iomem *vport, int cmd) + { + unsigned char val; + int loop = 500000; +@@ -221,18 +221,19 @@ static int sc6000_write(char __iomem *vport, int cmd) + cpu_relax(); + } while (loop--); + +- snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd); ++ dev_err(devptr, "DSP Command (0x%x) timeout.\n", cmd); + + return -EIO; + } + +-static int sc6000_dsp_get_answer(char __iomem *vport, int command, ++static int sc6000_dsp_get_answer(struct device *devptr, ++ char __iomem *vport, int command, + char *data, int data_len) + { + int len = 0; + +- if (sc6000_write(vport, command)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command); ++ if (sc6000_write(devptr, vport, command)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", command); + return -EIO; + } + +@@ -265,82 +266,86 @@ static int sc6000_dsp_reset(char __iomem *vport) + } + + /* detection and initialization */ +-static int sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) ++static int sc6000_hw_cfg_write(struct device *devptr, ++ char __iomem *vport, const int *cfg) + { +- if (sc6000_write(vport, COMMAND_6C) < 0) { +- snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C); ++ if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { ++ dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); + return -EIO; + } +- if (sc6000_write(vport, COMMAND_5C) < 0) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C); ++ if (sc6000_write(devptr, vport, COMMAND_5C) < 0) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_5C); + return -EIO; + } +- if (sc6000_write(vport, cfg[0]) < 0) { +- snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]); ++ if (sc6000_write(devptr, vport, cfg[0]) < 0) { ++ dev_err(devptr, "DATA 0x%x: failed!\n", cfg[0]); + return -EIO; + } +- if (sc6000_write(vport, cfg[1]) < 0) { +- snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]); ++ if (sc6000_write(devptr, vport, cfg[1]) < 0) { ++ dev_err(devptr, "DATA 0x%x: failed!\n", cfg[1]); + return -EIO; + } +- if (sc6000_write(vport, COMMAND_C5) < 0) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5); ++ if (sc6000_write(devptr, vport, COMMAND_C5) < 0) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_C5); + return -EIO; + } + + return 0; + } + +-static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg) ++static int sc6000_cfg_write(struct device *devptr, ++ char __iomem *vport, unsigned char softcfg) + { + +- if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); ++ if (sc6000_write(devptr, vport, WRITE_MDIRQ_CFG)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); + return -EIO; + } +- if (sc6000_write(vport, softcfg)) { +- snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); ++ if (sc6000_write(devptr, vport, softcfg)) { ++ dev_err(devptr, "%s: failed!\n", __func__); + return -EIO; + } + return 0; + } + +-static int sc6000_setup_board(char __iomem *vport, int config) ++static int sc6000_setup_board(struct device *devptr, ++ char __iomem *vport, int config) + { + int loop = 10; + + do { +- if (sc6000_write(vport, COMMAND_88)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", +- COMMAND_88); ++ if (sc6000_write(devptr, vport, COMMAND_88)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", ++ COMMAND_88); + return -EIO; + } + } while ((sc6000_wait_data(vport) < 0) && loop--); + + if (sc6000_read(vport) < 0) { +- snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n", +- COMMAND_88); ++ dev_err(devptr, "sc6000_read after CMD 0x%x: failed\n", ++ COMMAND_88); + return -EIO; + } + +- if (sc6000_cfg_write(vport, config)) ++ if (sc6000_cfg_write(devptr, vport, config)) + return -ENODEV; + + return 0; + } + +-static int sc6000_init_mss(char __iomem *vport, int config, ++static int sc6000_init_mss(struct device *devptr, ++ char __iomem *vport, int config, + char __iomem *vmss_port, int mss_config) + { +- if (sc6000_write(vport, DSP_INIT_MSS)) { +- snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n", +- DSP_INIT_MSS); ++ if (sc6000_write(devptr, vport, DSP_INIT_MSS)) { ++ dev_err(devptr, "%s [0x%x]: failed!\n", __func__, ++ DSP_INIT_MSS); + return -EIO; + } + + msleep(10); + +- if (sc6000_cfg_write(vport, config)) ++ if (sc6000_cfg_write(devptr, vport, config)) + return -EIO; + + iowrite8(mss_config, vmss_port); +@@ -348,7 +353,8 @@ static int sc6000_init_mss(char __iomem *vport, int config, + return 0; + } + +-static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, ++ char __iomem *vport, int *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -367,10 +373,11 @@ static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, + cfg[0] |= 0x02; + cfg[1] |= 0x80; /* enable WSS system */ + cfg[1] &= ~0x40; /* disable IDE */ +- snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]); ++ dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(char __iomem *vport, ++static int sc6000_init_board(struct device *devptr, ++ char __iomem *vport, + char __iomem *vmss_port, int dev) + { + char answer[15]; +@@ -384,14 +391,14 @@ static int sc6000_init_board(char __iomem *vport, + + err = sc6000_dsp_reset(vport); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n"); ++ dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); + if (err <= 0) { +- snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n"); ++ dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; + } + /* +@@ -399,52 +406,52 @@ static int sc6000_init_board(char __iomem *vport, + * if we have something different, we have to be warned. + */ + if (strncmp("SC-6000", answer, 7)) +- snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); ++ dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) { +- snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n"); ++ if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } +- printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", ++ dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + + /* set configuration */ +- sc6000_write(vport, COMMAND_5C); ++ sc6000_write(devptr, vport, COMMAND_5C); + if (sc6000_read(vport) < 0) + old = 1; + + if (!old) { + int cfg[2]; +- sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev], ++ sc6000_hw_cfg_encode(devptr, ++ vport, &cfg[0], port[dev], mpu_port[dev], + mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(vport, cfg) < 0) { +- snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n"); ++ if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); + return -EIO; + } + } +- err = sc6000_setup_board(vport, config); ++ err = sc6000_setup_board(devptr, vport, config); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); + return -ENODEV; + } + + sc6000_dsp_reset(vport); + + if (!old) { +- sc6000_write(vport, COMMAND_60); +- sc6000_write(vport, 0x02); ++ sc6000_write(devptr, vport, COMMAND_60); ++ sc6000_write(devptr, vport, 0x02); + sc6000_dsp_reset(vport); + } + +- err = sc6000_setup_board(vport, config); ++ err = sc6000_setup_board(devptr, vport, config); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); + return -ENODEV; + } +- err = sc6000_init_mss(vport, config, vmss_port, mss_config); ++ err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); + if (err < 0) { +- snd_printk(KERN_ERR "Cannot initialize " +- "Microsoft Sound System mode.\n"); ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); + return -ENODEV; + } + +@@ -491,39 +498,39 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + if (!enable[dev]) + return 0; + if (port[dev] == SNDRV_AUTO_PORT) { +- printk(KERN_ERR PFX "specify IO port\n"); ++ dev_err(devptr, "specify IO port\n"); + return 0; + } + if (mss_port[dev] == SNDRV_AUTO_PORT) { +- printk(KERN_ERR PFX "specify MSS port\n"); ++ dev_err(devptr, "specify MSS port\n"); + return 0; + } + if (port[dev] != 0x220 && port[dev] != 0x240) { +- printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n"); ++ dev_err(devptr, "Port must be 0x220 or 0x240\n"); + return 0; + } + if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) { +- printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n"); ++ dev_err(devptr, "MSS port must be 0x530 or 0xe80\n"); + return 0; + } + if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) { +- printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]); ++ dev_err(devptr, "invalid IRQ %d\n", irq[dev]); + return 0; + } + if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) { +- printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]); ++ dev_err(devptr, "invalid DMA %d\n", dma[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + (mpu_port[dev] & ~0x30L) != 0x300) { +- printk(KERN_ERR PFX "invalid MPU-401 port %lx\n", ++ dev_err(devptr, "invalid MPU-401 port %lx\n", + mpu_port[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 && + !sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) { +- printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); ++ dev_err(devptr, "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); + return 0; + } + return 1; +@@ -534,7 +541,7 @@ static void snd_sc6000_free(struct snd_card *card) + char __iomem *vport = (char __force __iomem *)card->private_data; + + if (vport) +- sc6000_setup_board(vport, 0); ++ sc6000_setup_board(card->dev, vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -558,7 +565,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); + if (xirq < 0) { +- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); ++ dev_err(devptr, "unable to find a free IRQ\n"); + return -EBUSY; + } + } +@@ -566,42 +573,39 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + if (xdma == SNDRV_AUTO_DMA) { + xdma = snd_legacy_find_free_dma(possible_dmas); + if (xdma < 0) { +- snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); ++ dev_err(devptr, "unable to find a free DMA\n"); + return -EBUSY; + } + } + + if (!devm_request_region(devptr, port[dev], 0x10, DRV_NAME)) { +- snd_printk(KERN_ERR PFX +- "I/O port region is already in use.\n"); ++ dev_err(devptr, "I/O port region is already in use.\n"); + return -EBUSY; + } + vport = devm_ioport_map(devptr, port[dev], 0x10); + if (!vport) { +- snd_printk(KERN_ERR PFX +- "I/O port cannot be iomapped.\n"); ++ dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } + card->private_data = (void __force *)vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +- snd_printk(KERN_ERR PFX +- "SC-6000 port I/O port region is already in use.\n"); ++ dev_err(devptr, ++ "SC-6000 port I/O port region is already in use.\n"); + return -EBUSY; + } + vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); + if (!vmss_port) { +- snd_printk(KERN_ERR PFX +- "MSS port I/O cannot be iomapped.\n"); ++ dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } + +- snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", +- port[dev], xirq, xdma, +- mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); ++ dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", ++ port[dev], xirq, xdma, ++ mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(vport, vmss_port, dev); ++ err = sc6000_init_board(devptr, vport, vmss_port, dev); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +@@ -613,25 +617,24 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + + err = snd_wss_pcm(chip, 0); + if (err < 0) { +- snd_printk(KERN_ERR PFX +- "error creating new WSS PCM device\n"); ++ dev_err(devptr, "error creating new WSS PCM device\n"); + return err; + } + err = snd_wss_mixer(chip); + if (err < 0) { +- snd_printk(KERN_ERR PFX "error creating new WSS mixer\n"); ++ dev_err(devptr, "error creating new WSS mixer\n"); + return err; + } + err = snd_sc6000_mixer(chip); + if (err < 0) { +- snd_printk(KERN_ERR PFX "the mixer rewrite failed\n"); ++ dev_err(devptr, "the mixer rewrite failed\n"); + return err; + } + if (snd_opl3_create(card, + 0x388, 0x388 + 2, + OPL3_HW_AUTO, 0, &opl3) < 0) { +- snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n", +- 0x388, 0x388 + 2); ++ dev_err(devptr, "no OPL device at 0x%x-0x%x ?\n", ++ 0x388, 0x388 + 2); + } else { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) +@@ -645,8 +648,8 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + MPU401_HW_MPU401, + mpu_port[dev], 0, + mpu_irq[dev], NULL) < 0) +- snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", +- mpu_port[dev]); ++ dev_err(devptr, "no MPU-401 device at 0x%lx ?\n", ++ mpu_port[dev]); + } + + strcpy(card->driver, DRV_NAME); +-- +2.53.0 + diff --git a/queue-6.1/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch b/queue-6.1/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch new file mode 100644 index 0000000000..5dc15e434a --- /dev/null +++ b/queue-6.1/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch @@ -0,0 +1,39 @@ +From 5c1ab6d38d79c0901ce48cf616c53ef6daf2734b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 01:25:48 +0300 +Subject: ALSA: scarlett2: Add missing sentinel initializer field + +From: Panagiotis Petrakopoulos + +[ Upstream commit 2428cd6e8b6fa80c36db4652702ca0acd2ce3f08 ] + +A "-Wmissing-field-initializers" warning was emitted when compiling the +module using the W=2 option. There is a sentinel initializer field +missing in the end of scarlett2_devices[]. Tested using a +Scarlett Solo 4th gen. + +Fixes: d98cc489029d ("ALSA: scarlett2: Move USB IDs out from device_info struct") +Signed-off-by: Panagiotis Petrakopoulos +Link: https://patch.msgid.link/20260405222548.8903-1-npetrakopoulos2003@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_scarlett2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index 0366f4b386eb5..6c3a032d64adb 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -1011,7 +1011,7 @@ static const struct scarlett2_device_entry scarlett2_devices[] = { + { USB_ID(0x1235, 0x820c), &clarett_8pre_info, "Clarett+" }, + + /* End of list */ +- { 0, NULL }, ++ { 0, NULL, NULL }, + }; + + /* get the starting port index number for a given port type/direction */ +-- +2.53.0 + diff --git a/queue-6.1/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch b/queue-6.1/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch new file mode 100644 index 0000000000..c2519f5698 --- /dev/null +++ b/queue-6.1/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch @@ -0,0 +1,205 @@ +From 3da43f0fb79c7a51f89d64548f5580eed5108683 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 17:15:04 +0200 +Subject: ALSA: usb-audio: Fix potential leak of pd at parsing UAC3 streams + +From: Takashi Iwai + +[ Upstream commit c39f0bc03f84ba64c9144c95714df1dc36150f6d ] + +At parsing UAC3 streams, we allocate a PD object at each time, and +either assign or free it. But there is a case where the PD object may +be leaked; namely, in __snd_usb_parse_audio_interface() loop, when an +audioformat shares the same endpoint with others, it's put to a link +and returns from snd_usb_add_audio_stream(), but the PD is forgotten +afterwards. Overall, the treatment of PD object in the parser code is +a bit flaky, and we should be more careful about the object ownership. + +This patch tries to fix the above case and improve the code a bit. +The pd object is now managed with the auto-cleanup in the loop, and +the ownership is updated when the pd object gets assigned to the +stream, which guarantees the release of the leftover object. + +Fixes: 7edf3b5e6a45 ("ALSA: usb-audio: AudioStreaming Power Domain parsing") +Link: https://patch.msgid.link/20260427151508.12544-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 +- + sound/usb/stream.c | 58 ++++++++++++++++++---------------------------- + sound/usb/stream.h | 3 ++- + 3 files changed, 25 insertions(+), 38 deletions(-) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 23361e78189d0..8faf3731e3499 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -121,7 +121,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip, + + snd_usb_audioformat_set_sync_ep(chip, fp); + +- err = snd_usb_add_audio_stream(chip, stream, fp); ++ err = snd_usb_add_audio_stream(chip, stream, fp, NULL); + if (err < 0) + return err; + +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index 920a718f91e68..f964082da3a63 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) + static void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, + struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++ struct snd_usb_power_domain **pdptr) + { + struct snd_usb_substream *subs = &as->substream[stream]; + +@@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, + if (fp->channels > subs->channels_max) + subs->channels_max = fp->channels; + +- if (pd) { +- subs->str_pd = pd; ++ if (pdptr && *pdptr) { ++ subs->str_pd = *pdptr; ++ *pdptr = NULL; /* assigned */ + /* Initialize Power Domain to idle status D1 */ +- snd_usb_power_domain_set(subs->stream->chip, pd, ++ snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, + UAC3_PD_STATE_D1); + } + +@@ -486,11 +487,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor + * if not, create a new pcm stream. note, fp is added to the substream + * fmt_list and will be freed on the chip instance release. do not free + * fp or do remove it from the substream fmt_list to avoid double-free. ++ * ++ * pdptr is optional and can be NULL. When it's non-NULL and the PD gets ++ * assigned to the stream, *pdptr is cleared to NULL upon return. + */ +-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++int snd_usb_add_audio_stream(struct snd_usb_audio *chip, ++ int stream, ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr) + + { + struct snd_usb_stream *as; +@@ -523,7 +527,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + err = snd_pcm_new_stream(as->pcm, stream, 1); + if (err < 0) + return err; +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + return add_chmap(as->pcm, stream, subs); + } + +@@ -551,7 +555,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + else + strcpy(pcm->name, "USB Audio"); + +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + + /* + * Keep using head insertion for M-Audio Audiophile USB (tm) which has a +@@ -569,21 +573,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + return add_chmap(pcm, stream, &as->substream[stream]); + } + +-int snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, NULL); +-} +- +-static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, pd); +-} +- + static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, + struct usb_host_interface *alts, + int protocol, int iface_no) +@@ -1102,8 +1091,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + } + } + +- if (pd) +- *pd_out = pd; ++ *pd_out = pd; + + return fp; + } +@@ -1118,7 +1106,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + struct usb_interface_descriptor *altsd; + int i, altno, err, stream; + struct audioformat *fp = NULL; +- struct snd_usb_power_domain *pd = NULL; + bool set_iface_first; + int num, protocol; + +@@ -1160,6 +1147,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) + continue; + ++ /* pd may be allocated at snd_usb_get_audioformat_uac3() and ++ * assigned at snd_usb_add_audio_stream(); otherwise it'll be ++ * freed automatically by cleanup at each loop. ++ */ ++ struct snd_usb_power_domain *pd __free(kfree) = NULL; ++ + /* + * Roland audio streaming interfaces are marked with protocols + * 0/1/2, but are UAC 1 compatible. +@@ -1215,23 +1208,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + *has_non_pcm = true; + if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { + audioformat_free(fp); +- kfree(pd); + fp = NULL; +- pd = NULL; + continue; + } + + snd_usb_audioformat_set_sync_ep(chip, fp); + + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); +- if (protocol == UAC_VERSION_3) +- err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); +- else +- err = snd_usb_add_audio_stream(chip, stream, fp); +- ++ err = snd_usb_add_audio_stream(chip, stream, fp, &pd); + if (err < 0) { + audioformat_free(fp); +- kfree(pd); + return err; + } + +diff --git a/sound/usb/stream.h b/sound/usb/stream.h +index d92e18d5818fe..61b9a133da018 100644 +--- a/sound/usb/stream.h ++++ b/sound/usb/stream.h +@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + + int snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, +- struct audioformat *fp); ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr); + + #endif /* __USBAUDIO_STREAM_H */ + +-- +2.53.0 + diff --git a/queue-6.1/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch b/queue-6.1/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch new file mode 100644 index 0000000000..3297b6e76e --- /dev/null +++ b/queue-6.1/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch @@ -0,0 +1,46 @@ +From b5c47d1c57e01f7e7f1a8196756860463775cbf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 09:25:41 +0100 +Subject: ARM: dts: mediatek: mt7623: fix efuse fallback compatible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafał Miłecki + +[ Upstream commit 5978ff33cc6f0988388a2830dc5cd2ea4e81f36a ] + +Fix following validation error: +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: compatible: 'oneOf' conditional failed, one must be fixed: + ['mediatek,mt7623-efuse', 'mediatek,mt8173-efuse'] is too long + 'mediatek,mt8173-efuse' was expected + 'mediatek,efuse' was expected + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: Unevaluated properties are not allowed ('compatible' was unexpected) + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# + +Fixes: 43c7a91b4b3a ("arm: dts: mt7623: add efuse nodes to the mt7623.dtsi file") +Signed-off-by: Rafał Miłecki +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/mt7623.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 74767b6703720..e7b09d0c3030a 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -329,7 +329,7 @@ sysirq: interrupt-controller@10200100 { + + efuse: efuse@10206000 { + compatible = "mediatek,mt7623-efuse", +- "mediatek,mt8173-efuse"; ++ "mediatek,efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.1/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch b/queue-6.1/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch new file mode 100644 index 0000000000..cb9b36efbc --- /dev/null +++ b/queue-6.1/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch @@ -0,0 +1,40 @@ +From 0a7e6ea38831745693e568b8b5c6c41f421272bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 19:15:10 +0200 +Subject: ARM: OMAP1: Fix DEBUG_LL and earlyprintk on OMAP16XX + +From: Aaro Koskinen + +[ Upstream commit 7e74b606dd39c46d4378d6f6563f560a00ab8694 ] + +On OMAP16XX, the UART enable bit shifts are written instead of the actual +bits. This breaks the boot when DEBUG_LL and earlyprintk is enabled; +the UART gets disabled and some random bits get enabled. Fix that. + +Fixes: 34c86239b184 ("ARM: OMAP1: clock: Fix early UART rate issues") +Signed-off-by: Aaro Koskinen +Link: https://patch.msgid.link/aca7HnXZ-aCSJPW7@darkstar.musicnaut.iki.fi +Signed-off-by: Kevin Hilman +Signed-off-by: Sasha Levin +--- + arch/arm/mach-omap1/clock_data.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c +index 96d846c37c432..0b08aef5b3677 100644 +--- a/arch/arm/mach-omap1/clock_data.c ++++ b/arch/arm/mach-omap1/clock_data.c +@@ -700,8 +700,8 @@ int __init omap1_clk_init(void) + /* Make sure UART clocks are enabled early */ + if (cpu_is_omap16xx()) + omap_writel(omap_readl(MOD_CONF_CTRL_0) | +- CONF_MOD_UART1_CLK_MODE_R | +- CONF_MOD_UART3_CLK_MODE_R, MOD_CONF_CTRL_0); ++ (1 << CONF_MOD_UART1_CLK_MODE_R) | ++ (1 << CONF_MOD_UART3_CLK_MODE_R), MOD_CONF_CTRL_0); + #endif + + /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch b/queue-6.1/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..2a10228f7b --- /dev/null +++ b/queue-6.1/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From bea3f4bc950615b90529f02913f3ba7213be2f1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:13 +0800 +Subject: arm64: dts: imx8mm-tqma8mqml: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 42a9f5a16328ed78a88e0498556965b6c6ec515c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: dfcd1b6f7620e ("arm64: dts: freescale: add initial device tree for TQMa8MQML with i.MX8MM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +index f649dfacb4b69..4d79f388ebd26 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +@@ -280,7 +280,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch b/queue-6.1/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..af804de77d --- /dev/null +++ b/queue-6.1/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From b7ef8ecc9d3e0174986f278e09398e22dffacff7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:12 +0800 +Subject: arm64: dts: imx8mn-tqma8mqnl: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 0fb37990774113afd943eaa91323679388584b6d ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: 3e56e354db6d3 ("arm64: dts: freescale: add initial device tree for TQMa8MQNL with i.MX8MN") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +index 0ed3475feb164..6d43327927b9b 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +@@ -282,7 +282,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch b/queue-6.1/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..922441b330 --- /dev/null +++ b/queue-6.1/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From cd7afdafb02bf1a90761872e75d8600efa41177d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:15 +0800 +Subject: arm64: dts: imx8mp-dhcom-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit f9ed5afc988da3e22543725e35be6addbb0497bc ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 8d6712695bc8e ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +index 0b81b85887f40..9379a5b08e6dd 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +@@ -807,7 +807,7 @@ MX8MP_IOMUXC_HDMI_DDC_SDA__GPIO3_IO27 0x84 + pinctrl_pmic: dhcom-pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch b/queue-6.1/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch new file mode 100644 index 0000000000..9d00b96527 --- /dev/null +++ b/queue-6.1/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch @@ -0,0 +1,43 @@ +From 80cd7cdf5a8e149dac1f7cba1b24e98eae182132 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 15:34:53 +0800 +Subject: arm64: dts: imx8mp-evk: Enable pull select bit for PCIe regulator + GPIO (M.2 W_DISABLE1) + +From: Sherry Sun + +[ Upstream commit d1e7eab6033f9885a02c4b4e8f09e34d8e9d21ab ] + +The current pin configuration for MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 +sets the weak pull-up but does not enable the pull select field. +Bit 8 in the IOMUX register must be set in order for the weak pull-up +to actually take effect. + +Update the pinctrl setting from 0x40 to 0x140 to enable both the pull +select and the weak pull-up, ensuring the line behaves as expected. + +Fixes: d50650500064 ("arm64: dts: imx8mp-evk: Add PCIe support") +Signed-off-by: Sherry Sun +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +index 126c839b45f2d..703eec6b0107e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +@@ -551,7 +551,7 @@ MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07 0x40 + + pinctrl_pcie0_reg: pcie0reggrp { + fsl,pins = < +- MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x40 ++ MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x140 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch b/queue-6.1/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..8b3c3ef81e --- /dev/null +++ b/queue-6.1/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch @@ -0,0 +1,37 @@ +From 73ed272a73d9c2c07bf5ddeeaf71a7d36bc8b1e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:09 +0800 +Subject: arm64: dts: imx8mp-icore-mx8mp: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit ea8c90f5c7ceeb6657a8fe564aa7b190dce298a6 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: eefe06b295087 ("arm64: dts: imx8mp: Add Engicam i.Core MX8M Plus SoM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +index a6319824ea2eb..69558ffefa9a6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +@@ -132,7 +132,7 @@ MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x41 ++ MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch b/queue-6.1/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..2d7d86f4e8 --- /dev/null +++ b/queue-6.1/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From c5f1c30906a565f0a8aa77466e391563e40d4757 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:28 +0900 +Subject: arm64: dts: mediatek: mt6795: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit c4c4823c8a5baa10b8100b01f49d7c3f4a871689 ] + +The gpio-ranges in the MT6795 pinctrl node were incorrectly defined, +therefore, GPIO196 cannot be used. +Correct the range count to match the driver. + +Fixes: b888886a4536 ("arm64: dts: mediatek: mt6795: Add pinctrl controller node") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt6795.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +index 46f0e54be7664..8c715015284fb 100644 +--- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +@@ -200,7 +200,7 @@ pio: pinctrl@10005000 { + ; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 196>; ++ gpio-ranges = <&pio 0 0 197>; + interrupt-controller; + #interrupt-cells = <2>; + }; +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch b/queue-6.1/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..ba8ad70b49 --- /dev/null +++ b/queue-6.1/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From ebf6668eeb0e93836a8ac5a6e9f90bf26dbee4fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:30 +0900 +Subject: arm64: dts: mediatek: mt7986a: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit 820ed0c1a13c5fafb36232538d793f99a0986ef3 ] + +The gpio-ranges in the MT7986A pinctrl node were incorrectly defined, +therefore, pin 100 cannot be used. +Correct the range count to match the driver. + +Fixes: c3a064a32ed9 ("arm64: dts: mediatek: add pinctrl support for mt7986a") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 108931e796465..c647d99c9554a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -153,7 +153,7 @@ pio: pinctrl@1001f000 { + "iocfg_lb", "iocfg_tr", "iocfg_tl", "eint"; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 100>; ++ gpio-ranges = <&pio 0 0 101>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch b/queue-6.1/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch new file mode 100644 index 0000000000..94f81012c3 --- /dev/null +++ b/queue-6.1/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch @@ -0,0 +1,44 @@ +From 60f7c888e07895a86ecb16e8d45e9fe83a79fa38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:51:11 +0800 +Subject: arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number + +From: Jun Yan + +[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ] + +Correct the interrupt number assigned to the Realtek PHY in the p230 + +following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm: +fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY +interrupt improvements [1]. + +[1] https://lore.kernel.org/all/20171202214037.17017-1-martin.blumenstingl@googlemail.com/ + +Fixes: b94d22d94ad2 ("ARM64: dts: meson-gx: add external PHY interrupt on some platforms") +Signed-off-by: Jun Yan +Reviewed-by: Martin Blumenstingl +Link: https://patch.msgid.link/20260330145111.115318-1-jerrysteve1101@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +index c1470416faade..36e97ed585ae7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +@@ -84,7 +84,8 @@ external_phy: ethernet-phy@0 { + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; +- interrupts = <29 IRQ_TYPE_LEVEL_LOW>; ++ /* MAC_INTR on GPIOZ_15 */ ++ interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + eee-broken-1000t; + }; + }; +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch b/queue-6.1/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch new file mode 100644 index 0000000000..8b66a96d46 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch @@ -0,0 +1,38 @@ +From 4058bcf817a1685ea75dd7164ba493cd16533a96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 18:33:11 +0100 +Subject: arm64: dts: qcom: sdm845-xiaomi-beryllium: Mark l1a regulator as + powered during boot + +From: David Heidelberg + +[ Upstream commit 3b0dd81eea6b7a239fce456ce4545af76f1a9715 ] + +The regulator must be on, since it provides the display subsystem and +therefore the bootloader had turned it on before Linux booted. + +Fixes: 77809cf74a8c ("arm64: dts: qcom: Add support for Xiaomi Poco F1 (Beryllium)") +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260320-beryllium-booton-v2-1-931d1be21eae@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +index 6d6b3dd699475..9c0f7b410eee2 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium.dts +@@ -133,6 +133,7 @@ vreg_l1a_0p875: ldo1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l5a_0p8: ldo5 { +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch b/queue-6.1/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch new file mode 100644 index 0000000000..b794812927 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch @@ -0,0 +1,43 @@ +From 6baf4e4d190312d5d9ac208ad8b82622c0e004af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 04:26:37 +0000 +Subject: arm64: dts: qcom: sm8250: Add missing CPU7 3.09GHz OPP + +From: Alexander Koskovich + +[ Upstream commit b683730e27ba4f91986c4c92f5cb7297f1e01a6d ] + +This resolves the following error seen on the ASUS ROG Phone 3: + +cpu cpu7: Voltage update failed freq=3091200 +cpu cpu7: failed to update OPP for freq=3091200 + +Fixes: 8e0e8016cb79 ("arm64: dts: qcom: sm8250: Add CPU opp tables") +Signed-off-by: Alexander Koskovich +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260307-sm8250-cpu7-opp-v1-1-435f5f6628a1@pm.me +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8250.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi +index 72ab4ca129459..ba912e03441ef 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi +@@ -627,6 +627,11 @@ cpu7_opp20: opp-2841600000 { + opp-hz = /bits/ 64 <2841600000>; + opp-peak-kBps = <8368000 51609600>; + }; ++ ++ cpu7_opp21: opp-3091200000 { ++ opp-hz = /bits/ 64 <3091200000>; ++ opp-peak-kBps = <8368000 51609600>; ++ }; + }; + + firmware { +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.1/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..02be0926b9 --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,75 @@ +From cdfedfca573f762d8474f9414ab39d8effa513b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:13 +0200 +Subject: arm64: dts: qcom: sm8450: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit db0c5ef1abda6effdc5c85d6688fb6af2b351ae5 ] + +The reported problem of some non-working UHS-I speed modes on SM8450 +originates in commit 0a631a36f724 ("arm64: dts: qcom: Add device tree +for Sony Xperia 1 IV"), and then it was spread to all SM8450 powered +platforms by commit 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable +SDHCI SDR104/SDR50 on all boards"). + +The tests show that the rootcause of the problem was related to an +overclocking of SD cards, and it's fixed later on by commit a27ac3806b0a +("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs"). + +Since then both SDR50 and SDR104 speed modes are working fine on SM8450, +tested on SM8450-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 24.6254 s, 43.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 12.3266 s, 87.1 MB/s + +Remove the restrictions on SD card speed modes from the SM8450 platform +dtsi file and enable UHS-I speed modes. + +Fixes: 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable SDHCI SDR104/SDR50 on all boards") +Reviewed-by: Neil Armstrong +Reviewed-by: Konrad Dybcio +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-5-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 49502cdd1d4e0..c9ca7bd886397 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -3191,9 +3191,6 @@ sdhc_2: sdhci@8804000 { + bus-width = <4>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0x0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-6.1/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch b/queue-6.1/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..9a9d92f71d --- /dev/null +++ b/queue-6.1/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From f8afa3d4ac7793199b37194e1780753dd236fc62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:16 +0100 +Subject: arm64: dts: qcom: sm8450: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 14044fa192c50265bc1f636108371044bbdcf7b7 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: fc8b0b9b630d ("arm64: dts: qcom: sm8450 add ITS device tree node") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-3-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 9420857871b1e..49502cdd1d4e0 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -2915,7 +2915,7 @@ intc: interrupt-controller@17100000 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x17140000 0x0 0x20000>; ++ reg = <0x0 0x17140000 0x0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-6.1/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch b/queue-6.1/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch new file mode 100644 index 0000000000..ef9d352be4 --- /dev/null +++ b/queue-6.1/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch @@ -0,0 +1,38 @@ +From 722c0a79a4226d5012435fc1e129331435614a94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 19:42:31 +0800 +Subject: arm64: kexec: Remove duplicate allocation for trans_pgd + +From: Wang Wensheng + +[ Upstream commit ee020bf6f14094c9ae434bb37e6957a1fdad513c ] + +trans_pgd would be allocated in trans_pgd_create_copy(), so remove the +duplicate allocation before calling trans_pgd_create_copy(). + +Fixes: 3744b5280e67 ("arm64: kexec: install a copy of the linear-map") +Signed-off-by: Wang Wensheng +Reviewed-by: Pasha Tatashin +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/machine_kexec.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c +index ce3d40120f72f..f660648cbceee 100644 +--- a/arch/arm64/kernel/machine_kexec.c ++++ b/arch/arm64/kernel/machine_kexec.c +@@ -142,9 +142,6 @@ int machine_kexec_post_load(struct kimage *kimage) + } + + /* Create a copy of the linear map */ +- trans_pgd = kexec_page_alloc(kimage); +- if (!trans_pgd) +- return -ENOMEM; + rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END); + if (rc) + return rc; +-- +2.53.0 + diff --git a/queue-6.1/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch b/queue-6.1/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch new file mode 100644 index 0000000000..211574e4da --- /dev/null +++ b/queue-6.1/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch @@ -0,0 +1,79 @@ +From 0b2b0146c98ff064de1828d511d254fb9944ff79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 07:16:35 +0100 +Subject: arm64/xor: fix conflicting attributes for xor_block_template + +From: Christoph Hellwig + +[ Upstream commit 675a0dd596e712404557286d0a883b54ee28e4f4 ] + +Commit 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +changes the definition to __ro_after_init instead of const, but failed to +update the external declaration in xor.h. This was not found because +xor-neon.c doesn't include , and can't easily do that due to +current architecture of the XOR code. + +Link: https://lkml.kernel.org/r/20260327061704.3707577-4-hch@lst.de +Fixes: 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +Signed-off-by: Christoph Hellwig +Reviewed-by: Eric Biggers +Tested-by: Eric Biggers +Cc: Albert Ou +Cc: Alexander Gordeev +Cc: Alexandre Ghiti +Cc: Andreas Larsson +Cc: Anton Ivanov +Cc: Ard Biesheuvel +Cc: Arnd Bergmann +Cc: "Borislav Petkov (AMD)" +Cc: Catalin Marinas +Cc: Chris Mason +Cc: Christian Borntraeger +Cc: Dan Williams +Cc: David S. Miller +Cc: David Sterba +Cc: Heiko Carstens +Cc: Herbert Xu +Cc: "H. Peter Anvin" +Cc: Huacai Chen +Cc: Ingo Molnar +Cc: Jason A. Donenfeld +Cc: Johannes Berg +Cc: Li Nan +Cc: Madhavan Srinivasan +Cc: Magnus Lindholm +Cc: Matt Turner +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: Palmer Dabbelt +Cc: Richard Henderson +Cc: Richard Weinberger +Cc: Russell King +Cc: Song Liu +Cc: Sven Schnelle +Cc: Ted Ts'o +Cc: Vasily Gorbik +Cc: WANG Xuerui +Cc: Will Deacon +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/xor.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/xor.h b/arch/arm64/include/asm/xor.h +index befcd8a7abc98..7c03207157196 100644 +--- a/arch/arm64/include/asm/xor.h ++++ b/arch/arm64/include/asm/xor.h +@@ -13,7 +13,7 @@ + + #ifdef CONFIG_KERNEL_MODE_NEON + +-extern struct xor_block_template const xor_block_inner_neon; ++extern struct xor_block_template xor_block_inner_neon __ro_after_init; + + static void + xor_neon_2(unsigned long bytes, unsigned long * __restrict p1, +-- +2.53.0 + diff --git a/queue-6.1/asoc-codecs-ab8500-fix-casting-of-private-data.patch b/queue-6.1/asoc-codecs-ab8500-fix-casting-of-private-data.patch new file mode 100644 index 0000000000..11475d626f --- /dev/null +++ b/queue-6.1/asoc-codecs-ab8500-fix-casting-of-private-data.patch @@ -0,0 +1,56 @@ +From 27605f46160e408eb6f6d24acef458d9b6fd5a45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 21:22:49 +0200 +Subject: ASoC: codecs: ab8500: Fix casting of private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian A. Ehrhardt + +[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ] + +ab8500_filter_controls[i].private_value is initialized using + + .private_value = (unsigned long)&(struct filter_control) + {.count = xcount, .min = xmin, .max = xmax} + +thus it's a pointer to a struct filter_control casted to unsigned long. + +So to get back that pointer .private_data must be cast back, not its +address. + +Fixes: 679d7abdc754 ("ASoC: codecs: Add AB8500 codec-driver") +Signed-off-by: Christian A. Ehrhardt +Signed-off-by: Uwe Kleine-König (The Capable Hub) +Link: https://patch.msgid.link/20260428192255.2294705-2-u.kleine-koenig@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/ab8500-codec.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c +index 68342917419e4..42e448978c4a0 100644 +--- a/sound/soc/codecs/ab8500-codec.c ++++ b/sound/soc/codecs/ab8500-codec.c +@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) + return status; + } + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; + drvdata->anc_fir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; + drvdata->anc_iir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; + drvdata->sid_fir_values = (long *)fc->value; + + snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); +-- +2.53.0 + diff --git a/queue-6.1/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch b/queue-6.1/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch new file mode 100644 index 0000000000..49f1907b55 --- /dev/null +++ b/queue-6.1/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch @@ -0,0 +1,189 @@ +From 76202b8f08348e8d1175b382b3c8141eda37a35c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:26 +0800 +Subject: ASoC: fsl_easrc: Change the type for iec958 channel status controls + +From: Shengjiu Wang + +[ Upstream commit 47f28a5bd154a95d5aa563dde02a801bd32ddb81 ] + +Use the type SNDRV_CTL_ELEM_TYPE_IEC958 for iec958 channel status +controls, the original type will cause mixer-test to iterate all 32bit +values, which costs a lot of time. And using IEC958 type can reduce the +control numbers. + +Also enable pm runtime before updating registers to make the regmap cache +data align with the value in hardware. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-12-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 118 +++++++++++++++++++++++++++----------- + 1 file changed, 84 insertions(+), 34 deletions(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 05aacebee884f..4c3b462512461 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -78,17 +78,47 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + return 0; + } + ++static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ + static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; +- unsigned int regval; ++ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ int ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]); ++ if (ret) ++ return ret; + +- regval = snd_soc_component_read(component, mc->regbase); ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]); ++ if (ret) ++ return ret; + +- ucontrol->value.integer.value[0] = regval; ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]); ++ if (ret) ++ return ret; + + return 0; + } +@@ -100,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); +- unsigned int regval = ucontrol->value.integer.value[0]; +- bool changed; ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ bool changed, changed_all = false; + int ret; + +- ret = regmap_update_bits_check(easrc->regmap, mc->regbase, +- GENMASK(31, 0), regval, &changed); +- if (ret != 0) ++ ret = pm_runtime_resume_and_get(component->dev); ++ if (ret) + return ret; + +- return changed; ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase), ++ GENMASK(31, 0), regval[0], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase), ++ GENMASK(31, 0), regval[1], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase), ++ GENMASK(31, 0), regval[2], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase), ++ GENMASK(31, 0), regval[3], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase), ++ GENMASK(31, 0), regval[4], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase), ++ GENMASK(31, 0), regval[5], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++err: ++ pm_runtime_put_autosuspend(component->dev); ++ ++ if (ret != 0) ++ return ret; ++ else ++ return changed_all; + } + + #define SOC_SINGLE_REG_RW(xname, xreg) \ + { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ +- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ ++ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \ + .put = fsl_easrc_set_reg, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ +@@ -146,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { + SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), + SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), + +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), ++ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0), ++ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1), ++ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2), ++ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3), + }; + + /* +-- +2.53.0 + diff --git a/queue-6.1/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch b/queue-6.1/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch new file mode 100644 index 0000000000..6feff9a3de --- /dev/null +++ b/queue-6.1/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch @@ -0,0 +1,39 @@ +From e2004d8f06434f888e34d7ef1824c2880db7310d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:24 +0800 +Subject: ASoC: fsl_easrc: Check the variable range in + fsl_easrc_iec958_put_bits() + +From: Shengjiu Wang + +[ Upstream commit 00541b86fb578d4949cfdd6aff1f82d43fcf07af ] + +Add check of input value's range in fsl_easrc_iec958_put_bits(), +otherwise the wrong value may be written from user space. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-10-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index f04d183fe099f..bb8bad04fb47d 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, + unsigned int regval = ucontrol->value.integer.value[0]; + int ret; + ++ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT) ++ return -EINVAL; ++ + ret = (easrc_priv->bps_iec958[mc->regbase] != regval); + + easrc_priv->bps_iec958[mc->regbase] = regval; +-- +2.53.0 + diff --git a/queue-6.1/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch b/queue-6.1/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch new file mode 100644 index 0000000000..8c922ad1df --- /dev/null +++ b/queue-6.1/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch @@ -0,0 +1,37 @@ +From bd4d4dfb66d937c23a7e7eeb696855848b487622 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:25 +0800 +Subject: ASoC: fsl_easrc: Fix value type in fsl_easrc_iec958_get_bits() + +From: Shengjiu Wang + +[ Upstream commit aa21fe4a81458cf469c2615b08cbde5997dde25a ] + +The value type of controls "Context 0 IEC958 Bits Per Sample" should be +integer, not enumerated, the issue is found by the mixer-test. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-11-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index bb8bad04fb47d..05aacebee884f 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -73,7 +73,7 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + +- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; ++ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch b/queue-6.1/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch new file mode 100644 index 0000000000..31620ee5de --- /dev/null +++ b/queue-6.1/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch @@ -0,0 +1,71 @@ +From eda52c41e2b0a12a42e01a692f647d293842c5e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:21 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in micfil_quality_set() + +From: Shengjiu Wang + +[ Upstream commit e5785093b1b45af7ee57d18619b2854a8aed073a ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_quality_set() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the quality variable. + +Also enable pm runtime before calling the function micfil_set_quality() +to make the regmap cache data align with the value in hardware. + +Fixes: bea1d61d5892 ("ASoC: fsl_micfil: rework quality setting") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-7-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 1b6f5e33ff93a..953192f7b6433 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -148,10 +148,34 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol, + { + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); ++ int val = ucontrol->value.integer.value[0]; ++ bool change = false; ++ int old_val; ++ int ret; ++ ++ if (val < QUALITY_HIGH || val > QUALITY_VLOW2) ++ return -EINVAL; ++ ++ if (micfil->quality != val) { ++ ret = pm_runtime_resume_and_get(cmpnt->dev); ++ if (ret) ++ return ret; ++ ++ old_val = micfil->quality; ++ micfil->quality = val; ++ ret = micfil_set_quality(micfil); + +- micfil->quality = ucontrol->value.integer.value[0]; ++ pm_runtime_put_autosuspend(cmpnt->dev); ++ ++ if (ret) { ++ micfil->quality = old_val; ++ return ret; ++ } ++ ++ change = true; ++ } + +- return micfil_set_quality(micfil); ++ return change; + } + + static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { +-- +2.53.0 + diff --git a/queue-6.1/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch b/queue-6.1/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch new file mode 100644 index 0000000000..53af02cad7 --- /dev/null +++ b/queue-6.1/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch @@ -0,0 +1,52 @@ +From d5b9bfb1eba731b4aa3620b7c58a84e802b344d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:22 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_arc_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 1b61c8103c9317a9c37fe544c2d83cee1c281149 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_arc_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the arc_mode +variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-8-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index 5b61b93772d64..83b1d497fbf5f 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -97,10 +97,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); ++ int ret; + +- xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]); ++ if (val < 0 || val > 1) ++ return -EINVAL; + +- return 0; ++ ret = (xcvr->arc_mode != val); ++ ++ xcvr->arc_mode = val; ++ ++ return ret; + } + + static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.1/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch b/queue-6.1/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch new file mode 100644 index 0000000000..8f79fa39b5 --- /dev/null +++ b/queue-6.1/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch @@ -0,0 +1,59 @@ +From 4a54203ed96af10f0a4646aa6eae8c94b03d8d31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:23 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 64a496ba976324615b845d60739dfcdae3d57434 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the mode variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-9-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index 83b1d497fbf5f..513582d69bc15 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -205,10 +205,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); + struct snd_soc_card *card = dai->component->card; + struct snd_soc_pcm_runtime *rtd; ++ int ret; ++ ++ if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC) ++ return -EINVAL; + +- xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); ++ ret = (xcvr->mode != val); ++ ++ xcvr->mode = val; + + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_ARC)); +@@ -218,7 +225,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + rtd = snd_soc_get_pcm_runtime(card, card->dai_link); + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = + (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0); +- return 0; ++ return ret; + } + + static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.1/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch b/queue-6.1/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch new file mode 100644 index 0000000000..641716ac4e --- /dev/null +++ b/queue-6.1/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch @@ -0,0 +1,49 @@ +From f5dc116b2ed4d87721fc7a5f1d541e318f5ca904 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 08:11:08 +0000 +Subject: ASoC: qcom: qdsp6: topology: check widget type before accessing data + +From: Srinivas Kandagatla + +[ Upstream commit d5bfdd28e0cdd45043ae6e0ac168a451d59283dc ] + +Check widget type before accessing the private data, as this could a +virtual widget which is no associated with a dsp graph, container and +module. Accessing witout check could lead to incorrect memory access. + +Fixes: 36ad9bf1d93d ("ASoC: qdsp6: audioreach: add topology support") +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260402081118.348071-4-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/topology.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c +index 600e39e73b87a..fdb87e585e276 100644 +--- a/sound/soc/qcom/qdsp6/topology.c ++++ b/sound/soc/qcom/qdsp6/topology.c +@@ -814,14 +814,16 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + struct audioreach_container *cont; + struct audioreach_module *mod; + +- mod = dobj->private; +- cont = mod->container; +- + if (w->id == snd_soc_dapm_mixer) { + /* virtual widget */ + kfree(dobj->private); + return 0; + } ++ mod = dobj->private; ++ if (!mod) ++ return 0; ++ ++ cont = mod->container; + + mutex_lock(&apm->lock); + idr_remove(&apm->modules_idr, mod->instance_id); +-- +2.53.0 + diff --git a/queue-6.1/asoc-sof-add-support-for-compress-api-for-stream-dat.patch b/queue-6.1/asoc-sof-add-support-for-compress-api-for-stream-dat.patch new file mode 100644 index 0000000000..3a55e0da65 --- /dev/null +++ b/queue-6.1/asoc-sof-add-support-for-compress-api-for-stream-dat.patch @@ -0,0 +1,118 @@ +From a96db22442d3fe5456b21f6744e36b05a954cf98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Jan 2023 14:25:32 +0200 +Subject: ASoC: SOF: Add support for compress API for stream data/offset + +From: Daniel Baluta + +[ Upstream commit 090349a9feba3ceee3997d31d68ffe54e5b57acb ] + +snd_sof_pcm_stream keeps information about both PCM (snd_pcm_substream) +and Compress (snd_compr_stream) streams. + +When PCM substream pointer is NULL this means we are dealing with a +compress stream. + +Reviewed-by: Paul Olaru +Reviewed-by: Iuliana Prodan +Reviewed-by: Ranjani Sridharan +Reviewed-by: Peter Ujfalusi +Signed-off-by: Daniel Baluta +Link: https://lore.kernel.org/r/20230117122533.201708-4-daniel.baluta@oss.nxp.com +Signed-off-by: Mark Brown +Stable-dep-of: 2c4fdd055f92 ("ASoC: SOF: compress: return the configured codec from get_params") +Signed-off-by: Sasha Levin +--- + sound/soc/sof/sof-priv.h | 1 + + sound/soc/sof/stream-ipc.c | 48 ++++++++++++++++++++++++++++---------- + 2 files changed, 37 insertions(+), 12 deletions(-) + +diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h +index d7f4f828f38f9..6f5b06473011d 100644 +--- a/sound/soc/sof/sof-priv.h ++++ b/sound/soc/sof/sof-priv.h +@@ -112,6 +112,7 @@ struct sof_compr_stream { + u32 sampling_rate; + u16 channels; + u16 sample_container_bytes; ++ size_t posn_offset; + }; + + struct snd_sof_dev; +diff --git a/sound/soc/sof/stream-ipc.c b/sound/soc/sof/stream-ipc.c +index 872a49550672c..216b454f6b94e 100644 +--- a/sound/soc/sof/stream-ipc.c ++++ b/sound/soc/sof/stream-ipc.c +@@ -33,14 +33,27 @@ int sof_ipc_msg_data(struct snd_sof_dev *sdev, + if (!sps || !sdev->stream_box.size) { + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + } else { +- struct snd_pcm_substream *substream = sps->substream; +- struct sof_stream *stream = substream->runtime->private_data; ++ size_t posn_offset; + +- /* The stream might already be closed */ +- if (!stream) +- return -ESTRPIPE; ++ if (sps->substream) { ++ struct sof_stream *stream = sps->substream->runtime->private_data; + +- snd_sof_dsp_mailbox_read(sdev, stream->posn_offset, p, sz); ++ /* The stream might already be closed */ ++ if (!stream) ++ return -ESTRPIPE; ++ ++ posn_offset = stream->posn_offset; ++ } else { ++ ++ struct sof_compr_stream *sstream = sps->cstream->runtime->private_data; ++ ++ if (!sstream) ++ return -ESTRPIPE; ++ ++ posn_offset = sstream->posn_offset; ++ } ++ ++ snd_sof_dsp_mailbox_read(sdev, posn_offset, p, sz); + } + + return 0; +@@ -51,18 +64,29 @@ int sof_set_stream_data_offset(struct snd_sof_dev *sdev, + struct snd_sof_pcm_stream *sps, + size_t posn_offset) + { +- struct snd_pcm_substream *substream = sps->substream; +- struct sof_stream *stream = substream->runtime->private_data; +- + /* check if offset is overflow or it is not aligned */ + if (posn_offset > sdev->stream_box.size || + posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) + return -EINVAL; + +- stream->posn_offset = sdev->stream_box.offset + posn_offset; ++ posn_offset += sdev->stream_box.offset; ++ ++ if (sps->substream) { ++ struct sof_stream *stream = sps->substream->runtime->private_data; ++ ++ stream->posn_offset = posn_offset; ++ dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", ++ sps->substream->stream, posn_offset); ++ } else if (sps->cstream) { ++ struct sof_compr_stream *sstream = sps->cstream->runtime->private_data; + +- dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", +- substream->stream, stream->posn_offset); ++ sstream->posn_offset = posn_offset; ++ dev_dbg(sdev->dev, "compr: stream dir %d, posn mailbox offset is %zu", ++ sps->cstream->direction, posn_offset); ++ } else { ++ dev_err(sdev->dev, "No stream opened"); ++ return -EINVAL; ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/asoc-sof-amd-fix-for-reading-position-updates-from-s.patch b/queue-6.1/asoc-sof-amd-fix-for-reading-position-updates-from-s.patch new file mode 100644 index 0000000000..6298b6133c --- /dev/null +++ b/queue-6.1/asoc-sof-amd-fix-for-reading-position-updates-from-s.patch @@ -0,0 +1,108 @@ +From a4d109232da58aef95401153edad6ce3a3432854 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Nov 2022 17:49:08 +0530 +Subject: ASoC: SOF: amd: Fix for reading position updates from stream box. + +From: V sujith kumar Reddy + +[ Upstream commit aae7e412b0ec0378e392b18c50b612dae09cdb74 ] + +By default the position updates are read from dsp box when streambox +size is not defined.if the streambox size is defined to some value +then position updates can be read from the streambox. + +Signed-off-by: V sujith kumar Reddy +Link: https://lore.kernel.org/r/20221123121911.3446224-2-vsujithkumar.reddy@amd.corp-partner.google.com +Signed-off-by: Mark Brown +Stable-dep-of: 2c4fdd055f92 ("ASoC: SOF: compress: return the configured codec from get_params") +Signed-off-by: Sasha Levin +--- + sound/soc/sof/amd/acp-common.c | 1 + + sound/soc/sof/amd/acp-ipc.c | 30 +++++++++++++++++++++++++++++- + sound/soc/sof/amd/acp.h | 4 ++++ + 3 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c +index 27b95187356e5..150e042e40392 100644 +--- a/sound/soc/sof/amd/acp-common.c ++++ b/sound/soc/sof/amd/acp-common.c +@@ -76,6 +76,7 @@ struct snd_sof_dsp_ops sof_acp_common_ops = { + /*IPC */ + .send_msg = acp_sof_ipc_send_msg, + .ipc_msg_data = acp_sof_ipc_msg_data, ++ .set_stream_data_offset = acp_set_stream_data_offset, + .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, + .get_window_offset = acp_sof_ipc_get_window_offset, + .irq_thread = acp_sof_ipc_irq_thread, +diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c +index dd030566e3725..dd6e53c63407f 100644 +--- a/sound/soc/sof/amd/acp-ipc.c ++++ b/sound/soc/sof/amd/acp-ipc.c +@@ -192,13 +192,41 @@ int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *sub + { + unsigned int offset = sdev->dsp_box.offset; + +- if (!substream || !sdev->stream_box.size) ++ if (!substream || !sdev->stream_box.size) { + acp_mailbox_read(sdev, offset, p, sz); ++ } else { ++ struct acp_dsp_stream *stream = substream->runtime->private_data; ++ ++ if (!stream) ++ return -ESTRPIPE; ++ ++ acp_mailbox_read(sdev, stream->posn_offset, p, sz); ++ } + + return 0; + } + EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON); + ++int acp_set_stream_data_offset(struct snd_sof_dev *sdev, ++ struct snd_pcm_substream *substream, ++ size_t posn_offset) ++{ ++ struct acp_dsp_stream *stream = substream->runtime->private_data; ++ ++ /* check for unaligned offset or overflow */ ++ if (posn_offset > sdev->stream_box.size || ++ posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) ++ return -EINVAL; ++ ++ stream->posn_offset = sdev->stream_box.offset + posn_offset; ++ ++ dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", ++ substream->stream, stream->posn_offset); ++ ++ return 0; ++} ++EXPORT_SYMBOL_NS(acp_set_stream_data_offset, SND_SOC_SOF_AMD_COMMON); ++ + int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) + { + const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); +diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h +index b1414ac1ea985..b5bbdedb66697 100644 +--- a/sound/soc/sof/amd/acp.h ++++ b/sound/soc/sof/amd/acp.h +@@ -144,6 +144,7 @@ struct acp_dsp_stream { + int stream_tag; + int active; + unsigned int reg_offset; ++ size_t posn_offset; + }; + + struct sof_amd_acp_desc { +@@ -205,6 +206,9 @@ int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_ty + irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context); + int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, + void *p, size_t sz); ++int acp_set_stream_data_offset(struct snd_sof_dev *sdev, ++ struct snd_pcm_substream *substream, ++ size_t posn_offset); + int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg); + int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +-- +2.53.0 + diff --git a/queue-6.1/asoc-sof-compress-return-the-configured-codec-from-g.patch b/queue-6.1/asoc-sof-compress-return-the-configured-codec-from-g.patch new file mode 100644 index 0000000000..fb40cfe040 --- /dev/null +++ b/queue-6.1/asoc-sof-compress-return-the-configured-codec-from-g.patch @@ -0,0 +1,88 @@ +From a021c86d1707cac9b648a5b0d7bba1cf0ddb7a83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 17:05:11 -0300 +Subject: ASoC: SOF: compress: return the configured codec from get_params +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 2c4fdd055f92a2fc8602dcd88bcea08c374b7e8b ] + +The SOF compressed offload path accepts codec parameters in +sof_compr_set_params() and forwards them to firmware as +extended data in the SOF IPC stream params message. + +However, sof_compr_get_params() still returns success without +filling the snd_codec structure. Since the compress core allocates +that structure zeroed and copies it back to userspace on success, +SNDRV_COMPRESS_GET_PARAMS returns an all-zero codec description +even after the stream has been configured successfully. + +The stale TODO in this callback conflates get_params() with capability +discovery. Supported codec enumeration belongs in get_caps() and +get_codec_caps(). get_params() should report the current codec settings. + +Cache the codec accepted by sof_compr_set_params() in the per-stream SOF +compress state and return it from sof_compr_get_params(). + +Fixes: 6324cf901e14 ("ASoC: SOF: compr: Add compress ops implementation") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-sof-compr-get-params-v1-1-0758815f13c7@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/compress.c | 8 +++++--- + sound/soc/sof/sof-priv.h | 2 ++ + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c +index 71c66c1b518c6..5ce304f010cfd 100644 +--- a/sound/soc/sof/compress.c ++++ b/sound/soc/sof/compress.c +@@ -240,6 +240,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, + sstream->sampling_rate = params->codec.sample_rate; + sstream->channels = params->codec.ch_out; + sstream->sample_container_bytes = pcm->params.sample_container_bytes; ++ sstream->codec_params = params->codec; + + spcm->prepared[cstream->direction] = true; + +@@ -252,9 +253,10 @@ static int sof_compr_set_params(struct snd_soc_component *component, + static int sof_compr_get_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_codec *params) + { +- /* TODO: we don't query the supported codecs for now, if the +- * application asks for an unsupported codec the set_params() will fail. +- */ ++ struct sof_compr_stream *sstream = cstream->runtime->private_data; ++ ++ *params = sstream->codec_params; ++ + return 0; + } + +diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h +index 6f5b06473011d..77c9741fc1480 100644 +--- a/sound/soc/sof/sof-priv.h ++++ b/sound/soc/sof/sof-priv.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -112,6 +113,7 @@ struct sof_compr_stream { + u32 sampling_rate; + u16 channels; + u16 sample_container_bytes; ++ struct snd_codec codec_params; + size_t posn_offset; + }; + +-- +2.53.0 + diff --git a/queue-6.1/asoc-sof-prepare-ipc_msg_data-to-be-used-with-compre.patch b/queue-6.1/asoc-sof-prepare-ipc_msg_data-to-be-used-with-compre.patch new file mode 100644 index 0000000000..85bd445d4a --- /dev/null +++ b/queue-6.1/asoc-sof-prepare-ipc_msg_data-to-be-used-with-compre.patch @@ -0,0 +1,242 @@ +From eda524040d618c266fe1776d56585d76bd2d4909 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Jan 2023 14:25:30 +0200 +Subject: ASoC: SOF: Prepare ipc_msg_data to be used with compress API + +From: Daniel Baluta + +[ Upstream commit 1b905942d6cd182b7ef14e9f095178376d3847e6 ] + +Make second parameter of ipc_msg_data generic +in order to be able to support compressed streams. + +This patch doesn't hold any functional change. + +With this case we can use ipc_msg_data, to retrieve information from +DSP for both PCM/Compress API. + +Reviewed-by: Paul Olaru +Reviewed-by: Iuliana Prodan +Reviewed-by: Ranjani Sridharan +Reviewed-by: Peter Ujfalusi +Signed-off-by: Daniel Baluta +Link: https://lore.kernel.org/r/20230117122533.201708-2-daniel.baluta@oss.nxp.com +Signed-off-by: Mark Brown +Stable-dep-of: 2c4fdd055f92 ("ASoC: SOF: compress: return the configured codec from get_params") +Signed-off-by: Sasha Levin +--- + sound/soc/sof/amd/acp-ipc.c | 5 +++-- + sound/soc/sof/amd/acp.h | 3 ++- + sound/soc/sof/intel/hda-ipc.c | 5 +++-- + sound/soc/sof/intel/hda.h | 2 +- + sound/soc/sof/ipc3.c | 4 ++-- + sound/soc/sof/mediatek/mt8186/mt8186.c | 2 +- + sound/soc/sof/mediatek/mt8195/mt8195.c | 2 +- + sound/soc/sof/ops.h | 4 ++-- + sound/soc/sof/sof-priv.h | 6 ++++-- + sound/soc/sof/stream-ipc.c | 6 ++++-- + 10 files changed, 23 insertions(+), 16 deletions(-) + +diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c +index dd6e53c63407f..5d8a1b603c052 100644 +--- a/sound/soc/sof/amd/acp-ipc.c ++++ b/sound/soc/sof/amd/acp-ipc.c +@@ -187,14 +187,15 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) + } + EXPORT_SYMBOL_NS(acp_sof_ipc_irq_thread, SND_SOC_SOF_AMD_COMMON); + +-int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, ++int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, + void *p, size_t sz) + { + unsigned int offset = sdev->dsp_box.offset; + +- if (!substream || !sdev->stream_box.size) { ++ if (!sps || !sdev->stream_box.size) { + acp_mailbox_read(sdev, offset, p, sz); + } else { ++ struct snd_pcm_substream *substream = sps->substream; + struct acp_dsp_stream *stream = substream->runtime->private_data; + + if (!stream) +diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h +index b5bbdedb66697..ce5f32341ad2b 100644 +--- a/sound/soc/sof/amd/acp.h ++++ b/sound/soc/sof/amd/acp.h +@@ -12,6 +12,7 @@ + #define __SOF_AMD_ACP_H + + #include "../sof-priv.h" ++#include "../sof-audio.h" + + #define ACP_MAX_STREAM 8 + +@@ -204,7 +205,7 @@ int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_ty + + /* IPC callbacks */ + irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context); +-int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, ++int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, + void *p, size_t sz); + int acp_set_stream_data_offset(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, +diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c +index 9b3667c705e47..96f909441b44e 100644 +--- a/sound/soc/sof/intel/hda-ipc.c ++++ b/sound/soc/sof/intel/hda-ipc.c +@@ -342,12 +342,13 @@ int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) + } + + int hda_ipc_msg_data(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + void *p, size_t sz) + { +- if (!substream || !sdev->stream_box.size) { ++ if (!sps || !sdev->stream_box.size) { + sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + } else { ++ struct snd_pcm_substream *substream = sps->substream; + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_stream *hda_stream; + +diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h +index 9acd21901e68c..cea36d3bef81f 100644 +--- a/sound/soc/sof/intel/hda.h ++++ b/sound/soc/sof/intel/hda.h +@@ -645,7 +645,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, + int enable, u32 size); + + int hda_ipc_msg_data(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + void *p, size_t sz); + int hda_set_stream_data_offset(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, +diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c +index 60b96b0c2412f..1607e3602e22a 100644 +--- a/sound/soc/sof/ipc3.c ++++ b/sound/soc/sof/ipc3.c +@@ -847,7 +847,7 @@ static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) + } + + stream = &spcm->stream[direction]; +- ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); ++ ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); + return; +@@ -882,7 +882,7 @@ static void ipc3_xrun(struct snd_sof_dev *sdev, u32 msg_id) + } + + stream = &spcm->stream[direction]; +- ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); ++ ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read overrun position: %d\n", ret); + return; +diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c +index 181189e00e020..d727751e83ef6 100644 +--- a/sound/soc/sof/mediatek/mt8186/mt8186.c ++++ b/sound/soc/sof/mediatek/mt8186/mt8186.c +@@ -489,7 +489,7 @@ static snd_pcm_uframes_t mt8186_pcm_pointer(struct snd_sof_dev *sdev, + } + + stream = &spcm->stream[substream->stream]; +- ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); ++ ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); + return 0; +diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c +index ac96ea07e591b..040e9a003c060 100644 +--- a/sound/soc/sof/mediatek/mt8195/mt8195.c ++++ b/sound/soc/sof/mediatek/mt8195/mt8195.c +@@ -525,7 +525,7 @@ static snd_pcm_uframes_t mt8195_pcm_pointer(struct snd_sof_dev *sdev, + } + + stream = &spcm->stream[substream->stream]; +- ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); ++ ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); + return 0; +diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h +index 55d43adb6a295..3c86f2df2179a 100644 +--- a/sound/soc/sof/ops.h ++++ b/sound/soc/sof/ops.h +@@ -449,10 +449,10 @@ static inline int snd_sof_load_firmware(struct snd_sof_dev *sdev) + + /* host DSP message data */ + static inline int snd_sof_ipc_msg_data(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + void *p, size_t sz) + { +- return sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz); ++ return sof_ops(sdev)->ipc_msg_data(sdev, sps, p, sz); + } + /* host side configuration of the stream's data offset in stream mailbox area */ + static inline int +diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h +index 3d70b57e4864d..85b84e09e1e8a 100644 +--- a/sound/soc/sof/sof-priv.h ++++ b/sound/soc/sof/sof-priv.h +@@ -20,6 +20,8 @@ + #include + #include + ++struct snd_sof_pcm_stream; ++ + /* Flag definitions used in sof_core_debug (sof_debug module parameter) */ + #define SOF_DBG_ENABLE_TRACE BIT(0) + #define SOF_DBG_RETAIN_CTX BIT(1) /* prevent DSP D3 on FW exception */ +@@ -240,7 +242,7 @@ struct snd_sof_dsp_ops { + + /* host read DSP stream data */ + int (*ipc_msg_data)(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + void *p, size_t sz); /* mandatory */ + + /* host side configuration of the stream's data offset in stream mailbox area */ +@@ -743,7 +745,7 @@ int sof_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, + u32 offset, void *dest, size_t size); + + int sof_ipc_msg_data(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + void *p, size_t sz); + int sof_set_stream_data_offset(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, +diff --git a/sound/soc/sof/stream-ipc.c b/sound/soc/sof/stream-ipc.c +index 5f1ceeea893a5..13e44501d4420 100644 +--- a/sound/soc/sof/stream-ipc.c ++++ b/sound/soc/sof/stream-ipc.c +@@ -19,6 +19,7 @@ + + #include "ops.h" + #include "sof-priv.h" ++#include "sof-audio.h" + + struct sof_stream { + size_t posn_offset; +@@ -26,12 +27,13 @@ struct sof_stream { + + /* Mailbox-based Generic IPC implementation */ + int sof_ipc_msg_data(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + void *p, size_t sz) + { +- if (!substream || !sdev->stream_box.size) { ++ if (!sps || !sdev->stream_box.size) { + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + } else { ++ struct snd_pcm_substream *substream = sps->substream; + struct sof_stream *stream = substream->runtime->private_data; + + /* The stream might already be closed */ +-- +2.53.0 + diff --git a/queue-6.1/asoc-sof-prepare-set_stream_data_offset-for-compress.patch b/queue-6.1/asoc-sof-prepare-set_stream_data_offset-for-compress.patch new file mode 100644 index 0000000000..f43b688eff --- /dev/null +++ b/queue-6.1/asoc-sof-prepare-set_stream_data_offset-for-compress.patch @@ -0,0 +1,166 @@ +From 7132f20a7c71d04d9c16c57a44777493d821b062 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Jan 2023 14:25:31 +0200 +Subject: ASoC: SOF: Prepare set_stream_data_offset for compress API + +From: Daniel Baluta + +[ Upstream commit 249f186d6b0211fc59d83db128030f2b298063a1 ] + +Make second parameter of set_stream_data_offset generic +in order to be used for both PCM and compress streams. + +Current patch doesn't introduce any functional change, +just prepare the code for compress support. + +Reviewed-by: Paul Olaru +Reviewed-by: Iuliana Prodan +Reviewed-by: Ranjani Sridharan +Reviewed-by: Peter Ujfalusi +Signed-off-by: Daniel Baluta +Link: https://lore.kernel.org/r/20230117122533.201708-3-daniel.baluta@oss.nxp.com +Signed-off-by: Mark Brown +Stable-dep-of: 2c4fdd055f92 ("ASoC: SOF: compress: return the configured codec from get_params") +Signed-off-by: Sasha Levin +--- + sound/soc/sof/amd/acp-ipc.c | 3 ++- + sound/soc/sof/amd/acp.h | 2 +- + sound/soc/sof/intel/hda-ipc.c | 3 ++- + sound/soc/sof/intel/hda.h | 2 +- + sound/soc/sof/ipc3-pcm.c | 3 ++- + sound/soc/sof/ops.h | 4 ++-- + sound/soc/sof/sof-priv.h | 4 ++-- + sound/soc/sof/stream-ipc.c | 3 ++- + 8 files changed, 14 insertions(+), 10 deletions(-) + +diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c +index 5d8a1b603c052..4b8a6bac2b830 100644 +--- a/sound/soc/sof/amd/acp-ipc.c ++++ b/sound/soc/sof/amd/acp-ipc.c +@@ -209,9 +209,10 @@ int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sp + EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON); + + int acp_set_stream_data_offset(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + size_t posn_offset) + { ++ struct snd_pcm_substream *substream = sps->substream; + struct acp_dsp_stream *stream = substream->runtime->private_data; + + /* check for unaligned offset or overflow */ +diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h +index ce5f32341ad2b..37fe2a17396d7 100644 +--- a/sound/soc/sof/amd/acp.h ++++ b/sound/soc/sof/amd/acp.h +@@ -208,7 +208,7 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context); + int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, + void *p, size_t sz); + int acp_set_stream_data_offset(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + size_t posn_offset); + int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg); +diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c +index 96f909441b44e..ed87c00f345c9 100644 +--- a/sound/soc/sof/intel/hda-ipc.c ++++ b/sound/soc/sof/intel/hda-ipc.c +@@ -367,9 +367,10 @@ int hda_ipc_msg_data(struct snd_sof_dev *sdev, + } + + int hda_set_stream_data_offset(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + size_t posn_offset) + { ++ struct snd_pcm_substream *substream = sps->substream; + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_stream *hda_stream; + +diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h +index cea36d3bef81f..773df987d6473 100644 +--- a/sound/soc/sof/intel/hda.h ++++ b/sound/soc/sof/intel/hda.h +@@ -648,7 +648,7 @@ int hda_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_sof_pcm_stream *sps, + void *p, size_t sz); + int hda_set_stream_data_offset(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + size_t posn_offset); + + /* +diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c +index dad57bef38f6d..627edc7361844 100644 +--- a/sound/soc/sof/ipc3-pcm.c ++++ b/sound/soc/sof/ipc3-pcm.c +@@ -129,7 +129,8 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component, + return ret; + } + +- ret = snd_sof_set_stream_data_offset(sdev, substream, ipc_params_reply.posn_offset); ++ ret = snd_sof_set_stream_data_offset(sdev, &spcm->stream[substream->stream], ++ ipc_params_reply.posn_offset); + if (ret < 0) { + dev_err(component->dev, "%s: invalid stream data offset for PCM %d\n", + __func__, spcm->pcm.pcm_id); +diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h +index 3c86f2df2179a..2c56ad69ede1e 100644 +--- a/sound/soc/sof/ops.h ++++ b/sound/soc/sof/ops.h +@@ -457,11 +457,11 @@ static inline int snd_sof_ipc_msg_data(struct snd_sof_dev *sdev, + /* host side configuration of the stream's data offset in stream mailbox area */ + static inline int + snd_sof_set_stream_data_offset(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + size_t posn_offset) + { + if (sof_ops(sdev) && sof_ops(sdev)->set_stream_data_offset) +- return sof_ops(sdev)->set_stream_data_offset(sdev, substream, ++ return sof_ops(sdev)->set_stream_data_offset(sdev, sps, + posn_offset); + + return 0; +diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h +index 85b84e09e1e8a..d7f4f828f38f9 100644 +--- a/sound/soc/sof/sof-priv.h ++++ b/sound/soc/sof/sof-priv.h +@@ -247,7 +247,7 @@ struct snd_sof_dsp_ops { + + /* host side configuration of the stream's data offset in stream mailbox area */ + int (*set_stream_data_offset)(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + size_t posn_offset); /* optional */ + + /* pre/post firmware run */ +@@ -748,7 +748,7 @@ int sof_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_sof_pcm_stream *sps, + void *p, size_t sz); + int sof_set_stream_data_offset(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + size_t posn_offset); + + int sof_stream_pcm_open(struct snd_sof_dev *sdev, +diff --git a/sound/soc/sof/stream-ipc.c b/sound/soc/sof/stream-ipc.c +index 13e44501d4420..872a49550672c 100644 +--- a/sound/soc/sof/stream-ipc.c ++++ b/sound/soc/sof/stream-ipc.c +@@ -48,9 +48,10 @@ int sof_ipc_msg_data(struct snd_sof_dev *sdev, + EXPORT_SYMBOL(sof_ipc_msg_data); + + int sof_set_stream_data_offset(struct snd_sof_dev *sdev, +- struct snd_pcm_substream *substream, ++ struct snd_sof_pcm_stream *sps, + size_t posn_offset) + { ++ struct snd_pcm_substream *substream = sps->substream; + struct sof_stream *stream = substream->runtime->private_data; + + /* check if offset is overflow or it is not aligned */ +-- +2.53.0 + diff --git a/queue-6.1/asoc-sti-return-errors-from-regmap_field_alloc.patch b/queue-6.1/asoc-sti-return-errors-from-regmap_field_alloc.patch new file mode 100644 index 0000000000..2cdda79548 --- /dev/null +++ b/queue-6.1/asoc-sti-return-errors-from-regmap_field_alloc.patch @@ -0,0 +1,50 @@ +From 2b7b90bd25b0932ba621ec5dd21ab47e7aa1a3dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:33 +0100 +Subject: ASoC: sti: Return errors from regmap_field_alloc() + +From: Sander Vanheule + +[ Upstream commit 272aabef50bc3fe58edd26de000f4cdd41bdbe60 ] + +When regmap_field_alloc() fails, it can return an error. Specifically, +it will return PTR_ERR(-ENOMEM) when the allocation returns a NULL +pointer. The code then uses these allocations with a simple NULL check: + + if (player->clk_sel) { + // May dereference invalid pointer (-ENOMEM) + err = regmap_field_write(player->clk_sel, ...); + } + +Ensure initialization fails by forwarding the errors from +regmap_field_alloc(), thus avoiding the use of the invalid pointers. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-2-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index dd9013c476649..e5c4e5245b255 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1029,7 +1029,12 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + } + + player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ if (IS_ERR(player->clk_sel)) ++ return PTR_ERR(player->clk_sel); ++ + player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ if (IS_ERR(player->valid_sel)) ++ return PTR_ERR(player->valid_sel); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/asoc-sti-use-managed-regmap_field-allocations.patch b/queue-6.1/asoc-sti-use-managed-regmap_field-allocations.patch new file mode 100644 index 0000000000..fef11f7a74 --- /dev/null +++ b/queue-6.1/asoc-sti-use-managed-regmap_field-allocations.patch @@ -0,0 +1,45 @@ +From d6f8817a27fd23bd0069708f32a123efd6788062 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:34 +0100 +Subject: ASoC: sti: use managed regmap_field allocations + +From: Sander Vanheule + +[ Upstream commit 1696fad8b259a2d46e51cd6e17e4bcdbe02279fa ] + +The regmap_field objects allocated at player init are never freed and +may leak resources if the driver is removed. + +Switch to devm_regmap_field_alloc() to automatically limit the lifetime +of the allocations the lifetime of the device. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-3-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index e5c4e5245b255..da07f825f3c5f 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1028,11 +1028,11 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + return PTR_ERR(regmap); + } + +- player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]); + if (IS_ERR(player->clk_sel)) + return PTR_ERR(player->clk_sel); + +- player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]); + if (IS_ERR(player->valid_sel)) + return PTR_ERR(player->valid_sel); + +-- +2.53.0 + diff --git a/queue-6.1/backlight-sky81452-backlight-check-return-value-of-d.patch b/queue-6.1/backlight-sky81452-backlight-check-return-value-of-d.patch new file mode 100644 index 0000000000..5275c02036 --- /dev/null +++ b/queue-6.1/backlight-sky81452-backlight-check-return-value-of-d.patch @@ -0,0 +1,46 @@ +From 9d767627ba1cbf8efbe5d1ea36f3cd1ab4c6a997 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:16:25 +0800 +Subject: backlight: sky81452-backlight: Check return value of + devm_gpiod_get_optional() in sky81452_bl_parse_dt() + +From: Chen Ni + +[ Upstream commit 797cc011ae02bda26f93d25a4442d7a1a77d84df ] + +The devm_gpiod_get_optional() function may return an ERR_PTR in case of +genuine GPIO acquisition errors, not just NULL which indicates the +legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the call in sky81452_bl_parse_dt(). On +error, return the error code to ensure proper failure handling rather +than proceeding with invalid pointers. + +Fixes: e1915eec54a6 ("backlight: sky81452: Convert to GPIO descriptors") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260203021625.578678-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/sky81452-backlight.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c +index c95e0de7f4e70..0cf1f588a3873 100644 +--- a/drivers/video/backlight/sky81452-backlight.c ++++ b/drivers/video/backlight/sky81452-backlight.c +@@ -204,6 +204,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( + pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode"); + pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift"); + pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); ++ if (IS_ERR(pdata->gpiod_enable)) ++ return dev_err_cast_probe(dev, pdata->gpiod_enable, ++ "failed to get gpio\n"); + + ret = of_property_count_u32_elems(np, "led-sources"); + if (ret < 0) { +-- +2.53.0 + diff --git a/queue-6.1/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch b/queue-6.1/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch new file mode 100644 index 0000000000..4e4f9d71b8 --- /dev/null +++ b/queue-6.1/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch @@ -0,0 +1,60 @@ +From 1c6a0044d1cb72eb1aac1ba41784f86fbbd823a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 09:53:51 -0700 +Subject: bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst() + +From: Weiming Shi + +[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ] + +bareudp_fill_metadata_dst() passes bareudp->sock to +udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. +The socket is only created in bareudp_open() and NULLed in +bareudp_stop(), so calling this function while the device is down +triggers a NULL dereference via sock->sk. + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) + Call Trace: + + bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) + do_execute_actions (net/openvswitch/actions.c:901) + ovs_execute_actions (net/openvswitch/actions.c:1589) + ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) + genl_rcv_msg (net/netlink/genetlink.c:1209) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths +in the same driver. + +Fixes: 571912c69f0e ("net: UDP tunnel encapsulation module for tunnelling different protocols like MPLS, IP, NSH etc.") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426165350.1663137-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 150049d9a81a7..b181c03368153 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -520,6 +520,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + ++ if (!sock) ++ return -ESHUTDOWN; ++ + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, + &saddr, info, IPPROTO_UDP, + use_cache); +-- +2.53.0 + diff --git a/queue-6.1/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch b/queue-6.1/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch new file mode 100644 index 0000000000..ba36c81cfa --- /dev/null +++ b/queue-6.1/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch @@ -0,0 +1,75 @@ +From fecd015b67825e1290784cc8747f8fd724d827cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 11:28:37 +0800 +Subject: blk-cgroup: wait for blkcg cleanup before initializing new disk + +From: Ming Lei + +[ Upstream commit 3dbaacf6ab68f81e3375fe769a2ecdbd3ce386fd ] + +When a queue is shared across disk rebind (e.g., SCSI unbind/bind), the +previous disk's blkcg state is cleaned up asynchronously via +disk_release() -> blkcg_exit_disk(). If the new disk's blkcg_init_disk() +runs before that cleanup finishes, we may overwrite q->root_blkg while +the old one is still alive, and radix_tree_insert() in blkg_create() +fails with -EEXIST because the old blkg entries still occupy the same +queue id slot in blkcg->blkg_tree. This causes the sd probe to fail +with -ENOMEM. + +Fix it by waiting in blkcg_init_disk() for root_blkg to become NULL, +which indicates the previous disk's blkcg cleanup has completed. + +Fixes: 1059699f87eb ("block: move blkcg initialization/destroy into disk allocation/release handler") +Cc: Yi Zhang +Signed-off-by: Ming Lei +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260311032837.2368714-1-ming.lei@redhat.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index f314192b6de84..9b081dfba9007 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -509,6 +510,8 @@ static void blkg_destroy_all(struct gendisk *disk) + + q->root_blkg = NULL; + spin_unlock_irq(&q->queue_lock); ++ ++ wake_up_var(&q->root_blkg); + } + + static int blkcg_reset_stats(struct cgroup_subsys_state *css, +@@ -1259,6 +1262,18 @@ int blkcg_init_disk(struct gendisk *disk) + + INIT_LIST_HEAD(&q->blkg_list); + ++ /* ++ * If the queue is shared across disk rebind (e.g., SCSI), the ++ * previous disk's blkcg state is cleaned up asynchronously via ++ * disk_release() -> blkcg_exit_disk(). Wait for that cleanup to ++ * finish (indicated by root_blkg becoming NULL) before setting up ++ * new blkcg state. Otherwise, we may overwrite q->root_blkg while ++ * the old one is still alive, and radix_tree_insert() in ++ * blkg_create() will fail with -EEXIST because the old entries ++ * still occupy the same queue id slot in blkcg->blkg_tree. ++ */ ++ wait_var_event(&q->root_blkg, !READ_ONCE(q->root_blkg)); ++ + new_blkg = blkg_alloc(&blkcg_root, disk, GFP_KERNEL); + if (!new_blkg) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch b/queue-6.1/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch new file mode 100644 index 0000000000..f165834ef7 --- /dev/null +++ b/queue-6.1/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch @@ -0,0 +1,52 @@ +From ed7214b655789d3833e9bad6f7cccb59d67f5a58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:42:59 +0300 +Subject: Bluetooth: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER + +From: Pauli Virtanen + +[ Upstream commit 5c7209a341ff2ac338b2b0375c34a307b37c9ac2 ] + +When protocol sets HCI_PROTO_DEFER, hci_conn_request_evt() calls +hci_connect_cfm(conn) without hdev->lock. Generally hci_connect_cfm() +assumes it is held, and if conn is deleted concurrently -> UAF. + +Only SCO and ISO set HCI_PROTO_DEFER and only for defer setup listen, +and HCI_EV_CONN_REQUEST is not generated for ISO. In the non-deferred +listening socket code paths, hci_connect_cfm(conn) is called with +hdev->lock held. + +Fix by holding the lock. + +Fixes: 70c464256310 ("Bluetooth: Refactor connection request handling") +Signed-off-by: Pauli Virtanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 31606454c7c81..d572ce3061cf9 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -3365,8 +3365,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + + memcpy(conn->dev_class, ev->dev_class, 3); + +- hci_dev_unlock(hdev); +- + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; +@@ -3400,7 +3398,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + hci_connect_cfm(conn, 0); + } + +- return; + unlock: + hci_dev_unlock(hdev); + } +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch b/queue-6.1/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch new file mode 100644 index 0000000000..c25de00faf --- /dev/null +++ b/queue-6.1/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch @@ -0,0 +1,49 @@ +From 894f06b61c647fd25792d8bf44c36ffbd58398cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:20 +0100 +Subject: Bluetooth: hci_ldisc: Clear HCI_UART_PROTO_INIT on error + +From: Jonathan Rissanen + +[ Upstream commit 68d39ea5e0adc9ecaea1ce8abd842ec972eb8718 ] + +When hci_register_dev() fails in hci_uart_register_dev() +HCI_UART_PROTO_INIT is not cleared before calling hu->proto->close(hu) +and setting hu->hdev to NULL. This means incoming UART data will reach +the protocol-specific recv handler in hci_uart_tty_receive() after +resources are freed. + +Clear HCI_UART_PROTO_INIT with a write lock before calling +hu->proto->close() and setting hu->hdev to NULL. The write lock ensures +all active readers have completed and no new reader can enter the +protocol recv path before resources are freed. + +This allows the protocol-specific recv functions to remove the +"HCI_UART_REGISTERED" guard without risking a null pointer dereference +if hci_register_dev() fails. + +Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization") +Signed-off-by: Jonathan Rissanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ldisc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index 2752857dbccf3..f86ac94d53a4e 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -694,6 +694,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device"); ++ percpu_down_write(&hu->proto_lock); ++ clear_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ percpu_up_write(&hu->proto_lock); + hu->proto->close(hu); + hu->hdev = NULL; + hci_free_dev(hdev); +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch b/queue-6.1/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch new file mode 100644 index 0000000000..2c0019f452 --- /dev/null +++ b/queue-6.1/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch @@ -0,0 +1,48 @@ +From 09d4f79df0c0a33a17d085e404c69b40f4eae4a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 23:47:41 +0800 +Subject: Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp + +From: Dudu Lu + +[ Upstream commit 42776497cdbc9a665b384a6dcb85f0d4bd927eab ] + +l2cap_ecred_reconf_rsp() calls l2cap_chan_del() without holding +l2cap_chan_lock(). Every other l2cap_chan_del() caller in the file +acquires the lock first. A remote BLE device can send a crafted +L2CAP ECRED reconfiguration response to corrupt the channel list +while another thread is iterating it. + +Add l2cap_chan_hold() and l2cap_chan_lock() before l2cap_chan_del(), +and l2cap_chan_unlock() and l2cap_chan_put() after, matching the +pattern used in l2cap_ecred_conn_rsp() and l2cap_conn_del(). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 56fbf8d2769c6..21f63ca434e3f 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6461,7 +6461,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + if (chan->ident != cmd->ident) + continue; + ++ l2cap_chan_hold(chan); ++ l2cap_chan_lock(chan); ++ + l2cap_chan_del(chan, ECONNRESET); ++ ++ l2cap_chan_unlock(chan); ++ l2cap_chan_put(chan); + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch b/queue-6.1/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch new file mode 100644 index 0000000000..d442b61ded --- /dev/null +++ b/queue-6.1/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch @@ -0,0 +1,38 @@ +From 62c3d6d46ee195814c7e4326e5333f0d630d6f2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 14:34:13 -0400 +Subject: Bluetooth: L2CAP: Fix printing wrong information if SDU length + exceeds MTU + +From: Luiz Augusto von Dentz + +[ Upstream commit 15bf35a660eb82a49f8397fc3d3acada8dae13db ] + +The code was printing skb->len and sdu_len in the places where it should +be sdu_len and chan->imtu respectively to match the if conditions. + +Link: https://lore.kernel.org/linux-bluetooth/20260315132013.75ab40c5@kernel.org/T/#m1418f9c82eeff8510c1beaa21cf53af20db96c06 +Fixes: e1d9a6688986 ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU") +Signed-off-by: Luiz Augusto von Dentz +Reviewed-by: Paul Menzel +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 8a2d36f5cf33b..56fbf8d2769c6 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7730,7 +7730,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + + if (sdu_len > chan->imtu) { + BT_ERR("Too big LE L2CAP SDU length: len %u > %u", +- skb->len, sdu_len); ++ sdu_len, chan->imtu); + l2cap_send_disconn_req(chan, ECONNRESET); + err = -EMSGSIZE; + goto failed; +-- +2.53.0 + diff --git a/queue-6.1/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch b/queue-6.1/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch new file mode 100644 index 0000000000..0676d868d3 --- /dev/null +++ b/queue-6.1/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch @@ -0,0 +1,572 @@ +From e8fceea2afb6c14134da943243a36e9921dd7d78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:32:07 +0000 +Subject: bonding: 3ad: implement proper RCU rules for port->aggregator + +From: Eric Dumazet + +[ Upstream commit c4f050ce06c56cfb5993268af4a5cb66ed1cd04e ] + +syzbot found a data-race in bond_3ad_get_active_agg_info / +bond_3ad_state_machine_handler [1] which hints at lack of proper +RCU implementation. + +Add __rcu qualifier to port->aggregator, and add proper RCU API. + +[1] + +BUG: KCSAN: data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler + +write to 0xffff88813cf5c4b0 of 8 bytes by task 36 on cpu 0: + ad_port_selection_logic drivers/net/bonding/bond_3ad.c:1659 [inline] + bond_3ad_state_machine_handler+0x9d5/0x2d60 drivers/net/bonding/bond_3ad.c:2569 + process_one_work kernel/workqueue.c:3302 [inline] + process_scheduled_works+0x4f0/0x9c0 kernel/workqueue.c:3385 + worker_thread+0x58a/0x780 kernel/workqueue.c:3466 + kthread+0x22a/0x280 kernel/kthread.c:436 + ret_from_fork+0x146/0x330 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +read to 0xffff88813cf5c4b0 of 8 bytes by task 22063 on cpu 1: + __bond_3ad_get_active_agg_info drivers/net/bonding/bond_3ad.c:2858 [inline] + bond_3ad_get_active_agg_info+0x8c/0x230 drivers/net/bonding/bond_3ad.c:2881 + bond_fill_info+0xe0f/0x10f0 drivers/net/bonding/bond_netlink.c:853 + rtnl_link_info_fill net/core/rtnetlink.c:906 [inline] + rtnl_link_fill+0x1d7/0x4e0 net/core/rtnetlink.c:927 + rtnl_fill_ifinfo+0xf8e/0x1380 net/core/rtnetlink.c:2168 + rtmsg_ifinfo_build_skb+0x11c/0x1b0 net/core/rtnetlink.c:4453 + rtmsg_ifinfo_event net/core/rtnetlink.c:4486 [inline] + rtmsg_ifinfo+0x6d/0x110 net/core/rtnetlink.c:4495 + __dev_notify_flags+0x76/0x390 net/core/dev.c:9790 + netif_change_flags+0xac/0xd0 net/core/dev.c:9823 + do_setlink+0x905/0x2950 net/core/rtnetlink.c:3180 + rtnl_group_changelink net/core/rtnetlink.c:3813 [inline] + __rtnl_newlink net/core/rtnetlink.c:3981 [inline] + rtnl_newlink+0xf55/0x1400 net/core/rtnetlink.c:4109 + rtnetlink_rcv_msg+0x64b/0x720 net/core/rtnetlink.c:6995 + netlink_rcv_skb+0x123/0x220 net/netlink/af_netlink.c:2550 + rtnetlink_rcv+0x1c/0x30 net/core/rtnetlink.c:7022 + netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline] + netlink_unicast+0x5a8/0x680 net/netlink/af_netlink.c:1344 + netlink_sendmsg+0x5c8/0x6f0 net/netlink/af_netlink.c:1894 + sock_sendmsg_nosec net/socket.c:787 [inline] + __sock_sendmsg net/socket.c:802 [inline] + ____sys_sendmsg+0x563/0x5b0 net/socket.c:2698 + ___sys_sendmsg+0x195/0x1e0 net/socket.c:2752 + __sys_sendmsg net/socket.c:2784 [inline] + __do_sys_sendmsg net/socket.c:2789 [inline] + __se_sys_sendmsg net/socket.c:2787 [inline] + __x64_sys_sendmsg+0xd4/0x160 net/socket.c:2787 + x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x12c/0x3b0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +value changed: 0x0000000000000000 -> 0xffff88813cf5c400 + +Reported by Kernel Concurrency Sanitizer on: +CPU: 1 UID: 0 PID: 22063 Comm: syz.0.31122 Tainted: G W syzkaller #0 PREEMPT(full) +Tainted: [W]=WARN +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 + +Fixes: 47e91f56008b ("bonding: use RCU protection for 3ad xmit path") +Reported-by: syzbot+9bb2ff2a4ab9e17307e1@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/69f0a82f.050a0220.3aadc4.0000.GAE@google.com/ +Signed-off-by: Eric Dumazet +Cc: Jay Vosburgh +Cc: Andrew Lunn +Link: https://patch.msgid.link/20260428123207.3809211-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_3ad.c | 109 ++++++++++++++----------- + drivers/net/bonding/bond_main.c | 8 +- + drivers/net/bonding/bond_netlink.c | 16 ++-- + drivers/net/bonding/bond_procfs.c | 3 +- + drivers/net/bonding/bond_sysfs_slave.c | 17 ++-- + include/net/bond_3ad.h | 2 +- + 6 files changed, 89 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index cf611dce8fad1..2849c2e6a8951 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -982,6 +982,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) + static void ad_mux_machine(struct port *port, bool *update_slave_arr) + { + struct bonding *bond = __get_bond_by_port(port); ++ struct aggregator *aggregator; + mux_states_t last_state; + + /* keep current State Machine state to compare later if it was +@@ -989,6 +990,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + */ + last_state = port->sm_mux_state; + ++ aggregator = rcu_dereference(port->aggregator); + if (port->sm_vars & AD_PORT_BEGIN) { + port->sm_mux_state = AD_MUX_DETACHED; + } else { +@@ -1008,7 +1010,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * cycle to update ready variable, we check + * READY_N and update READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + port->sm_mux_state = AD_MUX_DETACHED; + break; + } +@@ -1023,7 +1025,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * update ready variable, we check READY_N and update + * READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + + /* if the wait_while_timer expired, and the port is + * in READY state, move to ATTACHED state +@@ -1039,7 +1041,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + if ((port->sm_vars & AD_PORT_SELECTED) && + (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && + !__check_agg_selection_timer(port)) { +- if (port->aggregator->is_active) { ++ if (aggregator->is_active) { + int state = AD_MUX_COLLECTING_DISTRIBUTING; + + if (!bond->params.coupled_control) +@@ -1055,9 +1057,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * cycle to update ready variable, we check + * READY_N and update READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + port->sm_mux_state = AD_MUX_DETACHED; +- } else if (port->aggregator->is_active) { ++ } else if (aggregator->is_active) { + port->actor_oper_port_state |= + LACP_STATE_SYNCHRONIZATION; + } +@@ -1068,7 +1070,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * sure that a collecting distributing + * port in an active aggregator is enabled + */ +- if (port->aggregator->is_active && ++ if (aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; +@@ -1087,7 +1089,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + */ + struct slave *slave = port->slave; + +- if (port->aggregator->is_active && ++ if (aggregator->is_active && + bond_is_slave_rx_disabled(slave)) { + ad_enable_collecting(port); + *update_slave_arr = true; +@@ -1107,8 +1109,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * sure that a collecting distributing + * port in an active aggregator is enabled + */ +- if (port->aggregator && +- port->aggregator->is_active && ++ if (aggregator && ++ aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; +@@ -1140,7 +1142,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); + break; + case AD_MUX_ATTACHED: +- if (port->aggregator->is_active) ++ if (aggregator->is_active) + port->actor_oper_port_state |= + LACP_STATE_SYNCHRONIZATION; + else +@@ -1513,9 +1515,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + bond = __get_bond_by_port(port); + + /* if the port is connected to other aggregator, detach it */ +- if (port->aggregator) { ++ temp_aggregator = rcu_dereference(port->aggregator); ++ if (temp_aggregator) { + /* detach the port from its former aggregator */ +- temp_aggregator = port->aggregator; + for (curr_port = temp_aggregator->lag_ports; curr_port; + last_port = curr_port, + curr_port = curr_port->next_port_in_aggregator) { +@@ -1538,7 +1540,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + /* clear the port's relations to this + * aggregator + */ +- port->aggregator = NULL; ++ RCU_INIT_POINTER(port->aggregator, NULL); + port->next_port_in_aggregator = NULL; + port->actor_port_aggregator_identifier = 0; + +@@ -1561,7 +1563,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + port->slave->bond->dev->name, + port->slave->dev->name, + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ temp_aggregator->aggregator_identifier); + } + } + /* search on all aggregators for a suitable aggregator for this port */ +@@ -1585,15 +1587,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + ) + ) { + /* attach to the founded aggregator */ +- port->aggregator = aggregator; ++ rcu_assign_pointer(port->aggregator, aggregator); + port->actor_port_aggregator_identifier = +- port->aggregator->aggregator_identifier; ++ aggregator->aggregator_identifier; + port->next_port_in_aggregator = aggregator->lag_ports; +- port->aggregator->num_of_ports++; ++ aggregator->num_of_ports++; + aggregator->lag_ports = port; + slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + + /* mark this port as selected */ + port->sm_vars |= AD_PORT_SELECTED; +@@ -1608,39 +1610,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + if (!found) { + if (free_aggregator) { + /* assign port a new aggregator */ +- port->aggregator = free_aggregator; + port->actor_port_aggregator_identifier = +- port->aggregator->aggregator_identifier; ++ free_aggregator->aggregator_identifier; + + /* update the new aggregator's parameters + * if port was responsed from the end-user + */ + if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) + /* if port is full duplex */ +- port->aggregator->is_individual = false; ++ free_aggregator->is_individual = false; + else +- port->aggregator->is_individual = true; ++ free_aggregator->is_individual = true; + +- port->aggregator->actor_admin_aggregator_key = ++ free_aggregator->actor_admin_aggregator_key = + port->actor_admin_port_key; +- port->aggregator->actor_oper_aggregator_key = ++ free_aggregator->actor_oper_aggregator_key = + port->actor_oper_port_key; +- port->aggregator->partner_system = ++ free_aggregator->partner_system = + port->partner_oper.system; +- port->aggregator->partner_system_priority = ++ free_aggregator->partner_system_priority = + port->partner_oper.system_priority; +- port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; +- port->aggregator->receive_state = 1; +- port->aggregator->transmit_state = 1; +- port->aggregator->lag_ports = port; +- port->aggregator->num_of_ports++; ++ free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; ++ free_aggregator->receive_state = 1; ++ free_aggregator->transmit_state = 1; ++ free_aggregator->lag_ports = port; ++ free_aggregator->num_of_ports++; ++ ++ rcu_assign_pointer(port->aggregator, free_aggregator); + + /* mark this port as selected */ + port->sm_vars |= AD_PORT_SELECTED; + + slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ free_aggregator->aggregator_identifier); + } else { + slave_err(bond->dev, port->slave->dev, + "Port %d did not find a suitable aggregator\n", +@@ -1652,13 +1655,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + * in all aggregator's ports, else set ready=FALSE in all + * aggregator's ports + */ +- __set_agg_ports_ready(port->aggregator, +- __agg_ports_are_ready(port->aggregator)); ++ aggregator = rcu_dereference(port->aggregator); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + +- aggregator = __get_first_agg(port); +- ad_agg_selection_logic(aggregator, update_slave_arr); ++ ad_agg_selection_logic(__get_first_agg(port), update_slave_arr); + +- if (!port->aggregator->is_active) ++ if (!aggregator->is_active) + port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION; + } + +@@ -2012,13 +2014,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond + */ + static void ad_enable_collecting(struct port *port) + { +- if (port->aggregator->is_active) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator->is_active) { + struct slave *slave = port->slave; + + slave_dbg(slave->bond->dev, slave->dev, + "Enabling collecting on port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __enable_collecting_port(port); + } + } +@@ -2030,11 +2034,13 @@ static void ad_enable_collecting(struct port *port) + */ + static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + { +- if (port->aggregator && __agg_has_partner(port->aggregator)) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator && __agg_has_partner(aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling distributing on port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __disable_distributing_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; +@@ -2051,11 +2057,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + static void ad_enable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator->is_active) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator->is_active) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Enabling port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __enable_port(port); + /* Slave array needs update */ + *update_slave_arr = true; +@@ -2070,11 +2078,13 @@ static void ad_enable_collecting_distributing(struct port *port, + static void ad_disable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator && __agg_has_partner(port->aggregator)) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator && __agg_has_partner(aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __disable_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; +@@ -2314,7 +2324,7 @@ void bond_3ad_unbind_slave(struct slave *slave) + */ + for (temp_port = aggregator->lag_ports; temp_port; + temp_port = temp_port->next_port_in_aggregator) { +- temp_port->aggregator = new_aggregator; ++ rcu_assign_pointer(temp_port->aggregator, new_aggregator); + temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; + } + +@@ -2783,15 +2793,16 @@ int bond_3ad_set_carrier(struct bonding *bond) + int __bond_3ad_get_active_agg_info(struct bonding *bond, + struct ad_info *ad_info) + { +- struct aggregator *aggregator = NULL; ++ struct aggregator *aggregator = NULL, *tmp; + struct list_head *iter; + struct slave *slave; + struct port *port; + + bond_for_each_slave_rcu(bond, slave, iter) { + port = &(SLAVE_AD_INFO(slave)->port); +- if (port->aggregator && port->aggregator->is_active) { +- aggregator = port->aggregator; ++ tmp = rcu_dereference(port->aggregator); ++ if (tmp && tmp->is_active) { ++ aggregator = tmp; + break; + } + } +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 97821c3c8b9a8..d3c41dc57e547 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1374,7 +1374,7 @@ static void bond_poll_controller(struct net_device *bond_dev) + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + struct aggregator *agg = +- SLAVE_AD_INFO(slave)->port.aggregator; ++ rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + + if (agg && + agg->aggregator_identifier != ad_info.aggregator_id) +@@ -5183,15 +5183,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) + spin_unlock_bh(&bond->mode_lock); + agg_id = ad_info.aggregator_id; + } ++ rcu_read_lock(); + bond_for_each_slave(bond, slave, iter) { + if (skipslave == slave) + continue; + + all_slaves->arr[all_slaves->count++] = slave; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { +- struct aggregator *agg; ++ const struct aggregator *agg; + +- agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (!agg || agg->aggregator_identifier != agg_id) + continue; + } +@@ -5203,6 +5204,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) + + usable_slaves->arr[usable_slaves->count++] = slave; + } ++ rcu_read_unlock(); + + bond_set_slave_arr(bond, usable_slaves, all_slaves); + return ret; +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index 086233dce9c8d..0eaf4b0e06ffb 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -65,27 +65,29 @@ static int bond_fill_slave_info(struct sk_buff *skb, + const struct port *ad_port; + + ad_port = &SLAVE_AD_INFO(slave)->port; +- agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ rcu_read_lock(); ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (agg) { + if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, + agg->aggregator_identifier)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u8(skb, + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, + ad_port->actor_oper_port_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u16(skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, + ad_port->sm_churn_actor_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + ad_port->sm_churn_partner_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + } ++ rcu_read_unlock(); + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + SLAVE_AD_INFO(slave)->port_priority)) +@@ -94,6 +96,8 @@ static int bond_fill_slave_info(struct sk_buff *skb, + + return 0; + ++nla_put_failure_rcu: ++ rcu_read_unlock(); + nla_put_failure: + return -EMSGSIZE; + } +diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c +index 43be458422b3f..bc919814eb504 100644 +--- a/drivers/net/bonding/bond_procfs.c ++++ b/drivers/net/bonding/bond_procfs.c +@@ -187,6 +187,7 @@ static void bond_info_show_master(struct seq_file *seq) + } + } + ++/* Note: runs under rcu_read_lock() */ + static void bond_info_show_slave(struct seq_file *seq, + const struct slave *slave) + { +@@ -213,7 +214,7 @@ static void bond_info_show_slave(struct seq_file *seq, + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + const struct port *port = &SLAVE_AD_INFO(slave)->port; +- const struct aggregator *agg = port->aggregator; ++ const struct aggregator *agg = rcu_dereference(port->aggregator); + + if (agg) { + seq_printf(seq, "Aggregator ID: %d\n", +diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c +index 313866f2c0e49..75df3e21b804d 100644 +--- a/drivers/net/bonding/bond_sysfs_slave.c ++++ b/drivers/net/bonding/bond_sysfs_slave.c +@@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf) + const struct aggregator *agg; + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { +- agg = SLAVE_AD_INFO(slave)->port.aggregator; +- if (agg) +- return sysfs_emit(buf, "%d\n", +- agg->aggregator_identifier); ++ rcu_read_lock(); ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); ++ if (agg) { ++ ssize_t res = sysfs_emit(buf, "%d\n", ++ agg->aggregator_identifier); ++ rcu_read_unlock(); ++ return res; ++ } ++ rcu_read_unlock(); + } + + return sysfs_emit(buf, "N/A\n"); +@@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf) + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; +- if (ad_port->aggregator) ++ if (rcu_access_pointer(ad_port->aggregator)) + return sysfs_emit(buf, "%u\n", + ad_port->actor_oper_port_state); + } +@@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf) + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; +- if (ad_port->aggregator) ++ if (rcu_access_pointer(ad_port->aggregator)) + return sysfs_emit(buf, "%u\n", + ad_port->partner_oper.port_state); + } +diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h +index 579f3000a855e..3f4496df50acd 100644 +--- a/include/net/bond_3ad.h ++++ b/include/net/bond_3ad.h +@@ -239,7 +239,7 @@ typedef struct port { + churn_state_t sm_churn_actor_state; + churn_state_t sm_churn_partner_state; + struct slave *slave; /* pointer to the bond slave that this port belongs to */ +- struct aggregator *aggregator; /* pointer to an aggregator that this port related to */ ++ struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */ + struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ + u32 transaction_id; /* continuous number for identification of Marker PDU's; */ + struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ +-- +2.53.0 + diff --git a/queue-6.1/bonding-802.3ad-replace-mac_address_equal-with-__agg.patch b/queue-6.1/bonding-802.3ad-replace-mac_address_equal-with-__agg.patch new file mode 100644 index 0000000000..af93446b8b --- /dev/null +++ b/queue-6.1/bonding-802.3ad-replace-mac_address_equal-with-__agg.patch @@ -0,0 +1,87 @@ +From e853ee90bcda5e2c5906298f1e792b620420a3c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Feb 2024 02:24:52 +0000 +Subject: bonding: 802.3ad replace MAC_ADDRESS_EQUAL with __agg_has_partner +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jones Syue 薛懷宗 + +[ Upstream commit 4440873f3655325f849366d75382aa05d09b5575 ] + +Replace macro MAC_ADDRESS_EQUAL() for null_mac_addr checking with inline +function__agg_has_partner(). When MAC_ADDRESS_EQUAL() is verifiying +aggregator's partner mac addr with null_mac_addr, means that seeing if +aggregator has a valid partner or not. Using __agg_has_partner() makes it +more clear to understand. + +In ad_port_selection_logic(), since aggregator->partner_system and +port->partner_oper.system has been compared first as a prerequisite, it is +safe to replace the upcoming MAC_ADDRESS_EQUAL() for null_mac_addr checking +with __agg_has_partner(). + +Delete null_mac_addr, which is not required anymore in bond_3ad.c, since +all references to it are gone. + +Signed-off-by: Jones Syue +Reviewed-by: Hangbin Liu +Reviewed-by: Jiri Pirko +Acked-by: Jay Vosburgh +Link: https://lore.kernel.org/r/SI2PR04MB5097BCA8FF2A2F03D9A5A3EEDC5A2@SI2PR04MB5097.apcprd04.prod.outlook.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_3ad.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index 37364bbfdbdc4..29e08415b16a6 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -81,10 +81,6 @@ enum ad_link_speed_type { + #define MAC_ADDRESS_EQUAL(A, B) \ + ether_addr_equal_64bits((const u8 *)A, (const u8 *)B) + +-static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = { +- 0, 0, 0, 0, 0, 0 +-}; +- + static const u16 ad_ticks_per_sec = 1000 / AD_TIMER_INTERVAL; + static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; + +@@ -1583,7 +1579,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + (aggregator->partner_system_priority == port->partner_oper.system_priority) && + (aggregator->partner_oper_aggregator_key == port->partner_oper.key) + ) && +- ((!MAC_ADDRESS_EQUAL(&(port->partner_oper.system), &(null_mac_addr)) && /* partner answers */ ++ ((__agg_has_partner(aggregator) && /* partner answers */ + !aggregator->is_individual) /* but is not individual OR */ + ) + ) { +@@ -2033,9 +2029,7 @@ static void ad_enable_collecting(struct port *port) + */ + static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + { +- if (port->aggregator && +- !MAC_ADDRESS_EQUAL(&port->aggregator->partner_system, +- &(null_mac_addr))) { ++ if (port->aggregator && __agg_has_partner(port->aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling distributing on port %d (LAG %d)\n", + port->actor_port_number, +@@ -2075,9 +2069,7 @@ static void ad_enable_collecting_distributing(struct port *port, + static void ad_disable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator && +- !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system), +- &(null_mac_addr))) { ++ if (port->aggregator && __agg_has_partner(port->aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling port %d (LAG %d)\n", + port->actor_port_number, +-- +2.53.0 + diff --git a/queue-6.1/bonding-add-support-for-per-port-lacp-actor-priority.patch b/queue-6.1/bonding-add-support-for-per-port-lacp-actor-priority.patch new file mode 100644 index 0000000000..68d1ef09fc --- /dev/null +++ b/queue-6.1/bonding-add-support-for-per-port-lacp-actor-priority.patch @@ -0,0 +1,229 @@ +From 3cf72a7bbe49c76f9eb504a5ce07b3fd4f8b9df6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Sep 2025 06:44:59 +0000 +Subject: bonding: add support for per-port LACP actor priority + +From: Hangbin Liu + +[ Upstream commit 6b6dc81ee7e8ca87c71a533e1d69cf96a4f1e986 ] + +Introduce a new netlink attribute 'actor_port_prio' to allow setting +the LACP actor port priority on a per-slave basis. This extends the +existing bonding infrastructure to support more granular control over +LACP negotiations. + +The priority value is embedded in LACPDU packets and will be used by +subsequent patches to influence aggregator selection policies. + +Signed-off-by: Hangbin Liu +Link: https://patch.msgid.link/20250902064501.360822-2-liuhangbin@gmail.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + Documentation/networking/bonding.rst | 9 +++++++ + drivers/net/bonding/bond_3ad.c | 4 ++++ + drivers/net/bonding/bond_netlink.c | 16 +++++++++++++ + drivers/net/bonding/bond_options.c | 36 ++++++++++++++++++++++++++++ + include/net/bond_3ad.h | 1 + + include/net/bond_options.h | 1 + + include/uapi/linux/if_link.h | 1 + + 7 files changed, 68 insertions(+) + +diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst +index d0e6a0fc6fd85..e90063cec821e 100644 +--- a/Documentation/networking/bonding.rst ++++ b/Documentation/networking/bonding.rst +@@ -193,6 +193,15 @@ ad_actor_sys_prio + This parameter has effect only in 802.3ad mode and is available through + SysFs interface. + ++actor_port_prio ++ ++ In an AD system, this specifies the port priority. The allowed range ++ is 1 - 65535. If the value is not specified, it takes 255 as the ++ default value. ++ ++ This parameter has effect only in 802.3ad mode and is available through ++ netlink interface. ++ + ad_actor_system + + In an AD system, this specifies the mac-address for the actor in +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index 29e08415b16a6..cf611dce8fad1 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -430,6 +430,7 @@ static void __ad_actor_update_port(struct port *port) + + port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr; + port->actor_system_priority = BOND_AD_INFO(bond).system.sys_priority; ++ port->actor_port_priority = SLAVE_AD_INFO(port->slave)->port_priority; + } + + /* Conversions */ +@@ -2186,6 +2187,9 @@ void bond_3ad_bind_slave(struct slave *slave) + + ad_initialize_port(port, &bond->params); + ++ /* Port priority is initialized. Update it to slave's ad info */ ++ SLAVE_AD_INFO(slave)->port_priority = port->actor_port_priority; ++ + port->slave = slave; + port->actor_port_number = SLAVE_AD_INFO(slave)->id; + /* key is determined according to the link speed, duplex and +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index aebc814ad495d..7e47d405d74aa 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -28,6 +28,7 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, + nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ + nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ ++ nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ + 0; + } + +@@ -76,6 +77,10 @@ static int bond_fill_slave_info(struct sk_buff *skb, + ad_port->partner_oper.port_state)) + goto nla_put_failure; + } ++ ++ if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, ++ SLAVE_AD_INFO(slave)->port_priority)) ++ goto nla_put_failure; + } + + return 0; +@@ -128,6 +133,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { + static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { + [IFLA_BOND_SLAVE_QUEUE_ID] = { .type = NLA_U16 }, + [IFLA_BOND_SLAVE_PRIO] = { .type = NLA_S32 }, ++ [IFLA_BOND_SLAVE_ACTOR_PORT_PRIO] = { .type = NLA_U16 }, + }; + + static int bond_validate(struct nlattr *tb[], struct nlattr *data[], +@@ -178,6 +184,16 @@ static int bond_slave_changelink(struct net_device *bond_dev, + return err; + } + ++ if (data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO]) { ++ u16 ad_prio = nla_get_u16(data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO]); ++ ++ bond_opt_slave_initval(&newval, &slave_dev, ad_prio); ++ err = __bond_opt_set(bond, BOND_OPT_ACTOR_PORT_PRIO, &newval, ++ data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO], extack); ++ if (err) ++ return err; ++ } ++ + return 0; + } + +diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c +index 1faf10667c03e..2991290f450ee 100644 +--- a/drivers/net/bonding/bond_options.c ++++ b/drivers/net/bonding/bond_options.c +@@ -79,6 +79,8 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, + const struct bond_opt_value *newval); + static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, + const struct bond_opt_value *newval); ++static int bond_option_actor_port_prio_set(struct bonding *bond, ++ const struct bond_opt_value *newval); + static int bond_option_ad_actor_system_set(struct bonding *bond, + const struct bond_opt_value *newval); + static int bond_option_ad_user_port_key_set(struct bonding *bond, +@@ -223,6 +225,13 @@ static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = { + { NULL, -1, 0}, + }; + ++static const struct bond_opt_value bond_actor_port_prio_tbl[] = { ++ { "minval", 0, BOND_VALFLAG_MIN}, ++ { "maxval", 65535, BOND_VALFLAG_MAX}, ++ { "default", 255, BOND_VALFLAG_DEFAULT}, ++ { NULL, -1, 0}, ++}; ++ + static const struct bond_opt_value bond_ad_user_port_key_tbl[] = { + { "minval", 0, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT}, + { "maxval", 1023, BOND_VALFLAG_MAX}, +@@ -484,6 +493,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { + .values = bond_ad_actor_sys_prio_tbl, + .set = bond_option_ad_actor_sys_prio_set, + }, ++ [BOND_OPT_ACTOR_PORT_PRIO] = { ++ .id = BOND_OPT_ACTOR_PORT_PRIO, ++ .name = "actor_port_prio", ++ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), ++ .values = bond_actor_port_prio_tbl, ++ .set = bond_option_actor_port_prio_set, ++ }, + [BOND_OPT_AD_ACTOR_SYSTEM] = { + .id = BOND_OPT_AD_ACTOR_SYSTEM, + .name = "ad_actor_system", +@@ -1833,6 +1849,26 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, + return 0; + } + ++static int bond_option_actor_port_prio_set(struct bonding *bond, ++ const struct bond_opt_value *newval) ++{ ++ struct slave *slave; ++ ++ slave = bond_slave_get_rtnl(newval->slave_dev); ++ if (!slave) { ++ netdev_dbg(bond->dev, "%s called on NULL slave\n", __func__); ++ return -ENODEV; ++ } ++ ++ netdev_dbg(newval->slave_dev, "Setting actor_port_prio to %llu\n", ++ newval->value); ++ ++ SLAVE_AD_INFO(slave)->port_priority = newval->value; ++ bond_3ad_update_ad_actor_settings(bond); ++ ++ return 0; ++} ++ + static int bond_option_ad_actor_system_set(struct bonding *bond, + const struct bond_opt_value *newval) + { +diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h +index 5047711944df9..579f3000a855e 100644 +--- a/include/net/bond_3ad.h ++++ b/include/net/bond_3ad.h +@@ -271,6 +271,7 @@ struct ad_slave_info { + struct port port; /* 802.3ad port structure */ + struct bond_3ad_stats stats; + u16 id; ++ u16 port_priority; + }; + + static inline const char *bond_3ad_churn_desc(churn_state_t state) +diff --git a/include/net/bond_options.h b/include/net/bond_options.h +index 022b122a9fb61..e6eedf23aea1a 100644 +--- a/include/net/bond_options.h ++++ b/include/net/bond_options.h +@@ -78,6 +78,7 @@ enum { + BOND_OPT_PRIO, + BOND_OPT_COUPLED_CONTROL, + BOND_OPT_BROADCAST_NEIGH, ++ BOND_OPT_ACTOR_PORT_PRIO, + BOND_OPT_LAST + }; + +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index feebb4509abd7..d255239285841 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -967,6 +967,7 @@ enum { + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + IFLA_BOND_SLAVE_PRIO, ++ IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + __IFLA_BOND_SLAVE_MAX, + }; + +-- +2.53.0 + diff --git a/queue-6.1/bonding-print-churn-state-via-netlink.patch b/queue-6.1/bonding-print-churn-state-via-netlink.patch new file mode 100644 index 0000000000..ae2523d604 --- /dev/null +++ b/queue-6.1/bonding-print-churn-state-via-netlink.patch @@ -0,0 +1,65 @@ +From cd276c1d1a482c33a3a5c4dab69d33ab476894ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 02:02:14 +0000 +Subject: bonding: print churn state via netlink + +From: Hangbin Liu + +[ Upstream commit 4916f2e2f3fc9aef289fcd07949301e5c29094c2 ] + +Currently, the churn state is printed only in sysfs. Add netlink support +so users could get the state via netlink. + +Signed-off-by: Hangbin Liu +Link: https://patch.msgid.link/20260224020215.6012-1-liuhangbin@gmail.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_netlink.c | 9 +++++++++ + include/uapi/linux/if_link.h | 2 ++ + 2 files changed, 11 insertions(+) + +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index 7e47d405d74aa..086233dce9c8d 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -29,6 +29,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ + nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ ++ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE */ ++ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE */ + 0; + } + +@@ -76,6 +78,13 @@ static int bond_fill_slave_info(struct sk_buff *skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) + goto nla_put_failure; ++ ++ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, ++ ad_port->sm_churn_actor_state)) ++ goto nla_put_failure; ++ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, ++ ad_port->sm_churn_partner_state)) ++ goto nla_put_failure; + } + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index d255239285841..d674eb4f1a90c 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -968,6 +968,8 @@ enum { + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + IFLA_BOND_SLAVE_PRIO, + IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, ++ IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, ++ IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + __IFLA_BOND_SLAVE_MAX, + }; + +-- +2.53.0 + diff --git a/queue-6.1/bpf-add-checksum_complete-to-bpf-test-progs.patch b/queue-6.1/bpf-add-checksum_complete-to-bpf-test-progs.patch new file mode 100644 index 0000000000..63aa74da9e --- /dev/null +++ b/queue-6.1/bpf-add-checksum_complete-to-bpf-test-progs.patch @@ -0,0 +1,117 @@ +From 8289c48fd0e86c552018332a45ad9b9ea718fae0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2024 07:58:50 -0700 +Subject: bpf: Add CHECKSUM_COMPLETE to bpf test progs + +From: Vadim Fedorenko + +[ Upstream commit a3cfe84cca28f205761a0450016593b0d728165e ] + +Add special flag to validate that TC BPF program properly updates +checksum information in skb. + +Signed-off-by: Vadim Fedorenko +Signed-off-by: Daniel Borkmann +Reviewed-by: Jakub Kicinski +Acked-by: Daniel Borkmann +Link: https://lore.kernel.org/bpf/20240606145851.229116-1-vadfed@meta.com +Stable-dep-of: 972787479ee7 ("bpf: test_run: Fix the null pointer dereference issue in bpf_lwt_xmit_push_encap") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/bpf.h | 2 ++ + net/bpf/test_run.c | 28 +++++++++++++++++++++++++++- + tools/include/uapi/linux/bpf.h | 2 ++ + 3 files changed, 31 insertions(+), 1 deletion(-) + +diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h +index 216d1f0009791..600b10c50fdd9 100644 +--- a/include/uapi/linux/bpf.h ++++ b/include/uapi/linux/bpf.h +@@ -1286,6 +1286,8 @@ enum { + #define BPF_F_TEST_RUN_ON_CPU (1U << 0) + /* If set, XDP frames will be transmitted after processing */ + #define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1) ++/* If set, apply CHECKSUM_COMPLETE to skb and validate the checksum */ ++#define BPF_F_TEST_SKB_CHECKSUM_COMPLETE (1U << 2) + + /* type for BPF_ENABLE_STATS */ + enum bpf_stats_type { +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 9cbdfb9fd6743..2b8daf1cb6885 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1099,7 +1099,8 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + void *data; + int ret; + +- if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size) ++ if ((kattr->test.flags & ~BPF_F_TEST_SKB_CHECKSUM_COMPLETE) || ++ kattr->test.cpu || kattr->test.batch_size) + return -EINVAL; + + if (size < ETH_HLEN) +@@ -1150,6 +1151,7 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + __skb_put(skb, size); ++ + if (ctx && ctx->ifindex > 1) { + dev = dev_get_by_index(net, ctx->ifindex); + if (!dev) { +@@ -1185,9 +1187,19 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + __skb_push(skb, hh_len); + if (is_direct_pkt_access) + bpf_compute_data_pointers(skb); ++ + ret = convert___skb_to_skb(skb, ctx); + if (ret) + goto out; ++ ++ if (kattr->test.flags & BPF_F_TEST_SKB_CHECKSUM_COMPLETE) { ++ const int off = skb_network_offset(skb); ++ int len = skb->len - off; ++ ++ skb->csum = skb_checksum(skb, off, len, 0); ++ skb->ip_summed = CHECKSUM_COMPLETE; ++ } ++ + ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false); + if (ret) + goto out; +@@ -1202,6 +1214,20 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + } + memset(__skb_push(skb, hh_len), 0, hh_len); + } ++ ++ if (kattr->test.flags & BPF_F_TEST_SKB_CHECKSUM_COMPLETE) { ++ const int off = skb_network_offset(skb); ++ int len = skb->len - off; ++ __wsum csum; ++ ++ csum = skb_checksum(skb, off, len, 0); ++ ++ if (csum_fold(skb->csum) != csum_fold(csum)) { ++ ret = -EBADMSG; ++ goto out; ++ } ++ } ++ + convert_skb_to___skb(skb, ctx); + + size = skb->len; +diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h +index 39818b6e0293c..cbdc5299f6bf7 100644 +--- a/tools/include/uapi/linux/bpf.h ++++ b/tools/include/uapi/linux/bpf.h +@@ -1286,6 +1286,8 @@ enum { + #define BPF_F_TEST_RUN_ON_CPU (1U << 0) + /* If set, XDP frames will be transmitted after processing */ + #define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1) ++/* If set, apply CHECKSUM_COMPLETE to skb and validate the checksum */ ++#define BPF_F_TEST_SKB_CHECKSUM_COMPLETE (1U << 2) + + /* type for BPF_ENABLE_STATS */ + enum bpf_stats_type { +-- +2.53.0 + diff --git a/queue-6.1/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch b/queue-6.1/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch new file mode 100644 index 0000000000..5156a782cb --- /dev/null +++ b/queue-6.1/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch @@ -0,0 +1,84 @@ +From 8b22c979ea4ea82d6dd4da37ffeec0f37501e704 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:01:41 +0800 +Subject: bpf: allow UTF-8 literals in bpf_bprintf_prepare() + +From: Yihan Ding + +[ Upstream commit b960430ea8862ef37ce53c8bf74a8dc79d3f2404 ] + +bpf_bprintf_prepare() only needs ASCII parsing for conversion +specifiers. Plain text can safely carry bytes >= 0x80, so allow +UTF-8 literals outside '%' sequences while keeping ASCII control +bytes rejected and format specifiers ASCII-only. + +This keeps existing parsing rules for format directives unchanged, +while allowing helpers such as bpf_trace_printk() to emit UTF-8 +literal text. + +Update test_snprintf_negative() in the same commit so selftests keep +matching the new plain-text vs format-specifier split during bisection. + +Fixes: 48cac3f4a96d ("bpf: Implement formatted output helpers with bstr_printf") +Signed-off-by: Yihan Ding +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416120142.1420646-2-dingyihan@uniontech.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/helpers.c | 17 ++++++++++++++++- + .../testing/selftests/bpf/prog_tests/snprintf.c | 3 ++- + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index be9dc396537f1..a19524c672012 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -840,7 +840,13 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, + data->buf = buffers->buf; + + for (i = 0; i < fmt_size; i++) { +- if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { ++ unsigned char c = fmt[i]; ++ ++ /* ++ * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass ++ * through unchanged, while still rejecting ASCII control bytes. ++ */ ++ if (isascii(c) && !isprint(c) && !isspace(c)) { + err = -EINVAL; + goto out; + } +@@ -862,6 +868,15 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, + * always access fmt[i + 1], in the worst case it will be a 0 + */ + i++; ++ c = fmt[i]; ++ /* ++ * The format parser below only understands ASCII conversion ++ * specifiers and modifiers, so reject non-ASCII after '%'. ++ */ ++ if (!isascii(c)) { ++ err = -EINVAL; ++ goto out; ++ } + + /* skip optional "[0 +-][num]" width formatting field */ + while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || +diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c +index 4be6fdb78c6a1..20a3c622bd28a 100644 +--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c ++++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c +@@ -114,7 +114,8 @@ static void test_snprintf_negative(void) + ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5"); + ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6"); + ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7"); +- ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character"); ++ ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text"); ++ ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier"); + ASSERT_ERR(load_single_snprintf("\x1"), "non printable character"); + } + +-- +2.53.0 + diff --git a/queue-6.1/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch b/queue-6.1/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch new file mode 100644 index 0000000000..937fbbe2a9 --- /dev/null +++ b/queue-6.1/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch @@ -0,0 +1,96 @@ +From 776d707de5b81552cae9bdf71dad85b5f0c1ce20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 07:33:52 -0700 +Subject: bpf, arm32: Reject BPF-to-BPF calls and callbacks in the JIT + +From: Puranjay Mohan + +[ Upstream commit e1d486445af3c392628532229f7ce5f5cf7891b6 ] + +The ARM32 BPF JIT does not support BPF-to-BPF function calls +(BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does +not reject them either. + +When a program with subprograms is loaded (e.g. libxdp's XDP +dispatcher uses __noinline__ subprograms, or any program using +callbacks like bpf_loop or bpf_for_each_map_elem), the verifier +invokes bpf_jit_subprogs() which calls bpf_int_jit_compile() +for each subprogram. + +For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT +silently emits code using the wrong address computation: + + func = __bpf_call_base + imm + +where imm is a pc-relative subprogram offset, producing a bogus +function pointer. + +For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and +loads the immediate as a normal 64-bit value without error. + +In both cases, build_body() reports success and a JIT image is +allocated. ARM32 lacks the jit_data/extra_pass mechanism needed +for the second JIT pass in bpf_jit_subprogs(). On the second +pass, bpf_int_jit_compile() performs a full fresh compilation, +allocating a new JIT binary and overwriting prog->bpf_func. The +first allocation is never freed. bpf_jit_subprogs() then detects +the function pointer changed and aborts with -ENOTSUPP, but the +original JIT binary has already been leaked. Each program +load/unload cycle leaks one JIT binary allocation, as reported +by kmemleak: + + unreferenced object 0xbf0a1000 (size 4096): + backtrace: + bpf_jit_binary_alloc+0x64/0xfc + bpf_int_jit_compile+0x14c/0x348 + bpf_jit_subprogs+0x4fc/0xa60 + +Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL +handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling +through to the existing 'notyet' path. This causes build_body() +to fail before any JIT binary is allocated, so +bpf_int_jit_compile() returns the original program unjitted. +bpf_jit_subprogs() then sees !prog->jited and cleanly falls +back to the interpreter with no leak. + +Acked-by: Daniel Borkmann +Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs") +Reported-by: Jonas Rebmann +Closes: https://lore.kernel.org/bpf/b63e9174-7a3d-4e22-8294-16df07a4af89@pengutronix.de +Tested-by: Jonas Rebmann +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417143353.838911-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm/net/bpf_jit_32.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c +index 6a1c9fca5260b..2292245cfe7a9 100644 +--- a/arch/arm/net/bpf_jit_32.c ++++ b/arch/arm/net/bpf_jit_32.c +@@ -1594,6 +1594,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + { + u64 val = (u32)imm | (u64)insn[1].imm << 32; + ++ if (insn->src_reg == BPF_PSEUDO_FUNC) ++ goto notyet; ++ + emit_a32_mov_i64(dst, val, ctx); + + return 1; +@@ -1785,6 +1788,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + const s8 *r5 = bpf2a32[BPF_REG_5]; + const u32 func = (u32)__bpf_call_base + (u32)imm; + ++ if (insn->src_reg == BPF_PSEUDO_CALL) ++ goto notyet; ++ + emit_a32_mov_r64(true, r0, r1, ctx); + emit_a32_mov_r64(true, r1, r2, ctx); + emit_push_r64(r5, ctx); +-- +2.53.0 + diff --git a/queue-6.1/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch b/queue-6.1/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch new file mode 100644 index 0000000000..4939344812 --- /dev/null +++ b/queue-6.1/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch @@ -0,0 +1,57 @@ +From 643355946fd4b1501636dbfbfb920d6c50dbeba9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:14:03 +0200 +Subject: bpf, arm64: Fix off-by-one in check_imm signed range check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Borkmann + +[ Upstream commit 1dd8be4ec722ce54e4cace59f3a4ba658111b3ec ] + +check_imm(bits, imm) is used in the arm64 BPF JIT to verify that +a branch displacement (in arm64 instruction units) fits into the +signed N-bit immediate field of a B, B.cond or CBZ/CBNZ encoding +before it is handed to the encoder. The macro currently tests for +(imm > 0 && imm >> bits) || (imm < 0 && ~imm >> bits) which admits +values in [-2^N, 2^N) — effectively a signed (N+1)-bit range. A +signed N-bit field only holds [-2^(N-1), 2^(N-1)), so the check +admits one extra bit of range on each side. + +In particular, for check_imm19(), values in [2^18, 2^19) slip past +the check but do not fit into the 19-bit signed imm19 field of +B.cond. aarch64_insn_encode_immediate() then masks the raw value +into the 19-bit field, setting bit 18 (the sign bit) and flipping +a forward branch into a backward one. Same class of issue exists +for check_imm26() and the B/BL encoding. Shift by (bits - 1) +instead of bits so the actual signed N-bit range is enforced. + +Fixes: e54bcde3d69d ("arm64: eBPF JIT compiler") +Signed-off-by: Daniel Borkmann +Reviewed-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260415121403.639619-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 783883721aaf5..e66218aed831d 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -33,8 +33,8 @@ + #define FP_BOTTOM (MAX_BPF_JIT_REG + 4) + + #define check_imm(bits, imm) do { \ +- if ((((imm) > 0) && ((imm) >> (bits))) || \ +- (((imm) < 0) && (~(imm) >> (bits)))) { \ ++ if ((((imm) > 0) && ((imm) >> ((bits) - 1))) || \ ++ (((imm) < 0) && (~(imm) >> ((bits) - 1)))) { \ + pr_info("[%2d] imm=%d(0x%x) out of range\n", \ + i, imm, imm); \ + return -EINVAL; \ +-- +2.53.0 + diff --git a/queue-6.1/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch b/queue-6.1/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch new file mode 100644 index 0000000000..cf020699b2 --- /dev/null +++ b/queue-6.1/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch @@ -0,0 +1,46 @@ +From e2da6946201c72dd0c71fe246e8a64aacf70a434 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 May 2024 12:19:01 +0200 +Subject: bpf, devmap: Remove unnecessary if check in for loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thorsten Blum + +[ Upstream commit 2317dc2c22cc353b699c7d1db47b2fe91f54055c ] + +The iterator variable dst cannot be NULL and the if check can be removed. +Remove it and fix the following Coccinelle/coccicheck warning reported +by itnull.cocci: + + ERROR: iterator variable bound on line 762 cannot be NULL + +Signed-off-by: Thorsten Blum +Signed-off-by: Daniel Borkmann +Reviewed-by: Toke Høiland-Jørgensen +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/bpf/20240529101900.103913-2-thorsten.blum@toblux.com +Stable-dep-of: 8ed82f807bb0 ("bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path") +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 5e05732db2368..71025d1311a57 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -759,9 +759,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_safe(dst, next, head, index_hlist) { +- if (!dst) +- continue; +- + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-6.1/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch b/queue-6.1/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch new file mode 100644 index 0000000000..20c800ced4 --- /dev/null +++ b/queue-6.1/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch @@ -0,0 +1,43 @@ +From bf0f1fa2866caf3e24ed3c81286ff6ae490209f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 20:23:33 +0800 +Subject: bpf: Drop task_to_inode and inet_conn_established from lsm sleepable + hooks + +From: Jiayuan Chen + +[ Upstream commit beaf0e96b1da74549a6cabd040f9667d83b2e97e ] + +bpf_lsm_task_to_inode() is called under rcu_read_lock() and +bpf_lsm_inet_conn_established() is called from softirq context, so +neither hook can be used by sleepable LSM programs. + +Fixes: 423f16108c9d8 ("bpf: Augment the set of sleepable LSM hooks") +Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/3ab69731-24d1-431a-a351-452aafaaf2a5@std.uestc.edu.cn/T/#u +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260407122334.344072-1-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_lsm.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c +index e6a76da4bca78..075c06aa9c951 100644 +--- a/kernel/bpf/bpf_lsm.c ++++ b/kernel/bpf/bpf_lsm.c +@@ -338,7 +338,6 @@ BTF_ID(func, bpf_lsm_current_getsecid_subj) + BTF_ID(func, bpf_lsm_task_getsecid_obj) + BTF_ID(func, bpf_lsm_task_prctl) + BTF_ID(func, bpf_lsm_task_setscheduler) +-BTF_ID(func, bpf_lsm_task_to_inode) + BTF_ID(func, bpf_lsm_userns_create) + BTF_SET_END(sleepable_lsm_hooks) + +-- +2.53.0 + diff --git a/queue-6.1/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch b/queue-6.1/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch new file mode 100644 index 0000000000..247909e31e --- /dev/null +++ b/queue-6.1/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch @@ -0,0 +1,47 @@ +From b403cc1521cdd997fb7bc5d4b695a093316be85c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 21:29:50 +0800 +Subject: bpf: fix end-of-list detection in cgroup_storage_get_next_key() + +From: Weiming Shi + +[ Upstream commit 5828b9e5b272ecff7cf5d345128d3de7324117f7 ] + +list_next_entry() never returns NULL -- when the current element is the +last entry it wraps to the list head via container_of(). The subsequent +NULL check is therefore dead code and get_next_key() never returns +-ENOENT for the last element, instead reading storage->key from a bogus +pointer that aliases internal map fields and copying the result to +userspace. + +Replace it with list_entry_is_head() so the function correctly returns +-ENOENT when there are no more entries. + +Fixes: de9cbbaadba5 ("bpf: introduce cgroup storage maps") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Sun Jian +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260403132951.43533-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/local_storage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c +index f01ca6f1ee031..acf4649f7e472 100644 +--- a/kernel/bpf/local_storage.c ++++ b/kernel/bpf/local_storage.c +@@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, + goto enoent; + + storage = list_next_entry(storage, list_map); +- if (!storage) ++ if (list_entry_is_head(storage, &map->list, list_map)) + goto enoent; + } else { + storage = list_first_entry(&map->list, +-- +2.53.0 + diff --git a/queue-6.1/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch b/queue-6.1/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch new file mode 100644 index 0000000000..460d4b5285 --- /dev/null +++ b/queue-6.1/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch @@ -0,0 +1,46 @@ +From fdef03f3ab53a69e8d373d059ff1221f6fdf7934 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:27:19 +0200 +Subject: bpf: Fix precedence bug in convert_bpf_ld_abs alignment check + +From: Daniel Borkmann + +[ Upstream commit e5f635edd393aeaa7cad9e42831d397e6e2e1eed ] + +Fix an operator precedence issue in convert_bpf_ld_abs() where the +expression offset + ip_align % size evaluates as offset + (ip_align % size) +due to % having higher precedence than +. That latter evaluation does +not make any sense. The intended check is (offset + ip_align) % size == 0 +to verify that the packet load offset is properly aligned for direct +access. + +With NET_IP_ALIGN == 2, the bug causes the inline fast-path for direct +packet loads to almost never be taken on !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +platforms. This forces nearly all cBPF BPF_LD_ABS packet loads through +the bpf_skb_load_helper slow path on the affected archs. + +Fixes: e0cea7ce988c ("bpf: implement ld_abs/ld_ind in native bpf") +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260416122719.661033-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index aee85a0062ce6..90e986228ab9a 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -493,7 +493,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp) + ((unaligned_ok && offset >= 0) || + (!unaligned_ok && offset >= 0 && + offset + ip_align >= 0 && +- offset + ip_align % size == 0))) { ++ (offset + ip_align) % size == 0))) { + bool ldx_off_ok = offset <= S16_MAX; + + *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H); +-- +2.53.0 + diff --git a/queue-6.1/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch b/queue-6.1/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch new file mode 100644 index 0000000000..c8cce41328 --- /dev/null +++ b/queue-6.1/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch @@ -0,0 +1,74 @@ +From 8ac5001c2a0eae5aeeeb5a161c9fd6091b9b0cf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 00:12:20 +0800 +Subject: bpf: reject negative CO-RE accessor indices in bpf_core_parse_spec() + +From: Weiming Shi + +[ Upstream commit 1c22483a2c4bbf747787f328392ca3e68619c4dc ] + +CO-RE accessor strings are colon-separated indices that describe a path +from a root BTF type to a target field, e.g. "0:1:2" walks through +nested struct members. bpf_core_parse_spec() parses each component with +sscanf("%d"), so negative values like -1 are silently accepted. The +subsequent bounds checks (access_idx >= btf_vlen(t)) only guard the +upper bound and always pass for negative values because C integer +promotion converts the __u16 btf_vlen result to int, making the +comparison (int)(-1) >= (int)(N) false for any positive N. + +When -1 reaches btf_member_bit_offset() it gets cast to u32 0xffffffff, +producing an out-of-bounds read far past the members array. A crafted +BPF program with a negative CO-RE accessor on any struct that exists in +vmlinux BTF (e.g. task_struct) crashes the kernel deterministically +during BPF_PROG_LOAD on any system with CONFIG_DEBUG_INFO_BTF=y +(default on major distributions). The bug is reachable with CAP_BPF: + + BUG: unable to handle page fault for address: ffffed11818b6626 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + Oops: Oops: 0000 [#1] SMP KASAN NOPTI + CPU: 0 UID: 0 PID: 85 Comm: poc Not tainted 7.0.0-rc6 #18 PREEMPT(full) + RIP: 0010:bpf_core_parse_spec (tools/lib/bpf/relo_core.c:354) + RAX: 00000000ffffffff + Call Trace: + + bpf_core_calc_relo_insn (tools/lib/bpf/relo_core.c:1321) + bpf_core_apply (kernel/bpf/btf.c:9507) + check_core_relo (kernel/bpf/verifier.c:19475) + bpf_check (kernel/bpf/verifier.c:26031) + bpf_prog_load (kernel/bpf/syscall.c:3089) + __sys_bpf (kernel/bpf/syscall.c:6228) + + +CO-RE accessor indices are inherently non-negative (struct member index, +array element index, or enumerator index), so reject them immediately +after parsing. + +Fixes: ddc7c3042614 ("libbpf: implement BPF CO-RE offset relocation algorithm") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Emil Tsalapatis +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260404161221.961828-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/relo_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c +index c4b0e81ae2931..701a4fc305b0a 100644 +--- a/tools/lib/bpf/relo_core.c ++++ b/tools/lib/bpf/relo_core.c +@@ -293,6 +293,8 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf, + ++spec_str; + if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1) + return -EINVAL; ++ if (access_idx < 0) ++ return -EINVAL; + if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) + return -E2BIG; + spec_str += parsed_len; +-- +2.53.0 + diff --git a/queue-6.1/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch b/queue-6.1/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch new file mode 100644 index 0000000000..5851ec4400 --- /dev/null +++ b/queue-6.1/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch @@ -0,0 +1,72 @@ +From 3d322b7d52d9136ae6b4634ecd3ba8678aa7777d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 11:46:22 +0800 +Subject: bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb + +From: Sun Jian + +[ Upstream commit 12bec2bd4b76d81c5d3996bd14ec1b7f4d983747 ] + +bpf_prog_test_run_skb() calls eth_type_trans() first and then uses +skb->protocol to initialize sk family and address fields for the test +run. + +For IPv4 and IPv6 packets, it may access ip_hdr(skb) or ipv6_hdr(skb) +even when the provided test input only contains an Ethernet header. + +Reject the input earlier if the Ethernet frame carries IPv4/IPv6 +EtherType but the L3 header is too short. + +Fold the IPv4/IPv6 header length checks into the existing protocol +switch and return -EINVAL before accessing the network headers. + +Fixes: fa5cb548ced6 ("bpf: Setup socket family and addresses in bpf_prog_test_run_skb") +Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc +Signed-off-by: Sun Jian +Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 51259647c65fb..84d7a4dd8f051 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1164,19 +1164,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + switch (skb->protocol) { + case htons(ETH_P_IP): +- sk->sk_family = AF_INET; +- if (sizeof(struct iphdr) <= skb_headlen(skb)) { +- sk->sk_rcv_saddr = ip_hdr(skb)->saddr; +- sk->sk_daddr = ip_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct iphdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET; ++ sk->sk_rcv_saddr = ip_hdr(skb)->saddr; ++ sk->sk_daddr = ip_hdr(skb)->daddr; + break; + #if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +- sk->sk_family = AF_INET6; +- if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { +- sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; +- sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET6; ++ sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; ++ sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + break; + #endif + default: +-- +2.53.0 + diff --git a/queue-6.1/bpf-sockmap-fix-af_unix-iter-deadlock.patch b/queue-6.1/bpf-sockmap-fix-af_unix-iter-deadlock.patch new file mode 100644 index 0000000000..6ae57372be --- /dev/null +++ b/queue-6.1/bpf-sockmap-fix-af_unix-iter-deadlock.patch @@ -0,0 +1,101 @@ +From 17c52f894469844e248039c93feaa3d7e16eb454 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:16 +0200 +Subject: bpf, sockmap: Fix af_unix iter deadlock + +From: Michal Luczaj + +[ Upstream commit 4d328dd695383224aa750ddee6b4ad40c0f8d205 ] + +bpf_iter_unix_seq_show() may deadlock when lock_sock_fast() takes the fast +path and the iter prog attempts to update a sockmap. Which ends up spinning +at sock_map_update_elem()'s bh_lock_sock(): + +WARNING: possible recursive locking detected +test_progs/1393 is trying to acquire lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: sock_map_update_elem+0xdb/0x1f0 + +but task is already holding lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + +other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(slock-AF_UNIX); + lock(slock-AF_UNIX); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + +4 locks held by test_progs/1393: + #0: ffff88814b59c790 (&p->lock){+.+.}-{4:4}, at: bpf_seq_read+0x59/0x10d0 + #1: ffff88811ec25fd8 (sk_lock-AF_UNIX){+.+.}-{0:0}, at: bpf_seq_read+0x42c/0x10d0 + #2: ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + #3: ffffffff85a6a7c0 (rcu_read_lock){....}-{1:3}, at: bpf_iter_run_prog+0x51d/0xb00 + +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_deadlock_bug.cold+0xc0/0xce + __lock_acquire+0x130f/0x2590 + lock_acquire+0x14e/0x2b0 + _raw_spin_lock+0x30/0x40 + sock_map_update_elem+0xdb/0x1f0 + bpf_prog_2d0075e5d9b721cd_dump_unix+0x55/0x4f4 + bpf_iter_run_prog+0x5b9/0xb00 + bpf_iter_unix_seq_show+0x1f7/0x2e0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-2-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 99d80687998bd..f810c2b90b8b1 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3601,15 +3601,14 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + struct bpf_prog *prog; + struct sock *sk = v; + uid_t uid; +- bool slow; + int ret; + + if (v == SEQ_START_TOKEN) + return 0; + +- slow = lock_sock_fast(sk); ++ lock_sock(sk); + +- if (unlikely(sk_unhashed(sk))) { ++ if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; + goto unlock; + } +@@ -3619,7 +3618,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: +- unlock_sock_fast(sk, slow); ++ release_sock(sk); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.1/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch b/queue-6.1/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch new file mode 100644 index 0000000000..8f253d4ae7 --- /dev/null +++ b/queue-6.1/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch @@ -0,0 +1,200 @@ +From 6952485c17e628eba74111c5386d4f5768fe3487 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:18 +0200 +Subject: bpf, sockmap: Fix af_unix null-ptr-deref in proto update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Luczaj + +[ Upstream commit dca38b7734d2ea00af4818ff3ae836fab33d5d5a ] + +unix_stream_connect() sets sk_state (`WRITE_ONCE(sk->sk_state, +TCP_ESTABLISHED)`) _before_ it assigns a peer (`unix_peer(sk) = newsk`). +sk_state == TCP_ESTABLISHED makes sock_map_sk_state_allowed() believe that +socket is properly set up, which would include having a defined peer. IOW, +there's a window when unix_stream_bpf_update_proto() can be called on +socket which still has unix_peer(sk) == NULL. + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) +sock_map_sk_state_allowed(sk) +... +sk_pair = unix_peer(sk) +sock_hold(sk_pair) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + +BUG: kernel NULL pointer dereference, address: 0000000000000080 +RIP: 0010:unix_stream_bpf_update_proto+0xa0/0x1b0 +Call Trace: + sock_map_link+0x564/0x8b0 + sock_map_update_common+0x6e/0x340 + sock_map_update_elem_sys+0x17d/0x240 + __sys_bpf+0x26db/0x3250 + __x64_sys_bpf+0x21/0x30 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Initial idea was to move peer assignment _before_ the sk_state update[1], +but that involved an additional memory barrier, and changing the hot path +was rejected. +Then a NULL check during proto update in unix_stream_bpf_update_proto() was +considered[2], but the follow-up discussion[3] focused on the root cause, +i.e. sockmap update taking a wrong lock. Or, more specifically, missing +unix_state_lock()[4]. +In the end it was concluded that teaching sockmap about the af_unix locking +would be unnecessarily complex[5]. +Complexity aside, since BPF_PROG_TYPE_SCHED_CLS and BPF_PROG_TYPE_SCHED_ACT +are allowed to update sockmaps, sock_map_update_elem() taking the unix +lock, as it is currently implemented in unix_state_lock(): +spin_lock(&unix_sk(s)->lock), would be problematic. unix_state_lock() taken +in a process context, followed by a softirq-context TC BPF program +attempting to take the same spinlock -- deadlock[6]. +This way we circled back to the peer check idea[2]. + +[1]: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +[2]: https://lore.kernel.org/netdev/20240610174906.32921-1-kuniyu@amazon.com/ +[3]: https://lore.kernel.org/netdev/7603c0e6-cd5b-452b-b710-73b64bd9de26@linux.dev/ +[4]: https://lore.kernel.org/netdev/CAAVpQUA+8GL_j63CaKb8hbxoL21izD58yr1NvhOhU=j+35+3og@mail.gmail.com/ +[5]: https://lore.kernel.org/bpf/CAAVpQUAHijOMext28Gi10dSLuMzGYh+jK61Ujn+fZ-wvcODR2A@mail.gmail.com/ +[6]: https://lore.kernel.org/bpf/dd043c69-4d03-46fe-8325-8f97101435cf@linux.dev/ + +Summary of scenarios where af_unix/stream connect() may race a sockmap +update: + +1. connect() vs. bpf(BPF_MAP_UPDATE_ELEM), i.e. sock_map_update_elem_sys() + + Implemented NULL check is sufficient. Once assigned, socket peer won't + be released until socket fd is released. And that's not an issue because + sock_map_update_elem_sys() bumps fd refcnf. + +2. connect() vs BPF program doing update + + Update restricted per verifier.c:may_update_sockmap() to + + BPF_PROG_TYPE_TRACING/BPF_TRACE_ITER + BPF_PROG_TYPE_SOCK_OPS (bpf_sock_map_update() only) + BPF_PROG_TYPE_SOCKET_FILTER + BPF_PROG_TYPE_SCHED_CLS + BPF_PROG_TYPE_SCHED_ACT + BPF_PROG_TYPE_XDP + BPF_PROG_TYPE_SK_REUSEPORT + BPF_PROG_TYPE_FLOW_DISSECTOR + BPF_PROG_TYPE_SK_LOOKUP + + Plus one more race to consider: + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) + sock_map_sk_state_allowed(sk) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + sk_pair = unix_peer(sk) + if (unlikely(!sk_pair)) + return -EINVAL; + + CPU1 close + ---------- + + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) + // use after free? + sock_hold(sk_pair) + + 2.1 BPF program invoking helper function bpf_sock_map_update() -> + BPF_CALL_4(bpf_sock_map_update(), ...) + + Helper limited to BPF_PROG_TYPE_SOCK_OPS. Nevertheless, a unix sock + might be accessible via bpf_map_lookup_elem(). Which implies sk + already having psock, which in turn implies sk already having + sk_pair. Since sk_psock_destroy() is queued as RCU work, sk_pair + won't go away while BPF executes the update. + + 2.2 BPF program invoking helper function bpf_map_update_elem() -> + sock_map_update_elem() + + 2.2.1 Unix sock accessible to BPF prog only via sockmap lookup in + BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_SK_REUSEPORT, BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_SK_LOOKUP. + + Pretty much the same as case 2.1. + + 2.2.2 Unix sock accessible to BPF program directly: + BPF_PROG_TYPE_TRACING, narrowed down to BPF_TRACE_ITER. + + Sockmap iterator (sock_map_seq_ops) is safe: unix sock + residing in a sockmap means that the sock already went through + the proto update step. + + Unix sock iterator (bpf_iter_unix_seq_ops), on the other hand, + gives access to socks that may still be unconnected. Which + means iterator prog can race sockmap/proto update against + connect(). + + BUG: KASAN: null-ptr-deref in unix_stream_bpf_update_proto+0x253/0x4d0 + Write of size 4 at addr 0000000000000080 by task test_progs/3140 + Call Trace: + dump_stack_lvl+0x5d/0x80 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x253/0x4d0 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + While the introduced NULL check prevents null-ptr-deref in the + BPF program path as well, it is insufficient to guard against + a poorly timed close() leading to a use-after-free. This will + be addressed in a subsequent patch. + +Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()") +Closes: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +Reported-by: Michal Luczaj +Reported-by: 钱一铭 +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-4-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/unix_bpf.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c +index bca2d86ba97d8..976e035053e5a 100644 +--- a/net/unix/unix_bpf.c ++++ b/net/unix/unix_bpf.c +@@ -184,6 +184,9 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r + */ + if (!psock->sk_pair) { + sk_pair = unix_peer(sk); ++ if (unlikely(!sk_pair)) ++ return -EINVAL; ++ + sock_hold(sk_pair); + psock->sk_pair = sk_pair; + } +-- +2.53.0 + diff --git a/queue-6.1/bpf-sockmap-take-state-lock-for-af_unix-iter.patch b/queue-6.1/bpf-sockmap-take-state-lock-for-af_unix-iter.patch new file mode 100644 index 0000000000..2e0134c9f7 --- /dev/null +++ b/queue-6.1/bpf-sockmap-take-state-lock-for-af_unix-iter.patch @@ -0,0 +1,115 @@ +From 08bdf92d68d1110308f6de42e153d4111861a534 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:19 +0200 +Subject: bpf, sockmap: Take state lock for af_unix iter + +From: Michal Luczaj + +[ Upstream commit 64c2f93fc3254d3bf5de4445fb732ee5c451edb6 ] + +When a BPF iterator program updates a sockmap, there is a race condition in +unix_stream_bpf_update_proto() where the `peer` pointer can become stale[1] +during a state transition TCP_ESTABLISHED -> TCP_CLOSE. + + CPU0 bpf CPU1 close + -------- ---------- +// unix_stream_bpf_update_proto() +sk_pair = unix_peer(sk) +if (unlikely(!sk_pair)) + return -EINVAL; + // unix_release_sock() + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) +sock_hold(sk_pair) // UaF + +More practically, this fix guarantees that the iterator program is +consistently provided with a unix socket that remains stable during +iterator execution. + +[1]: +BUG: KASAN: slab-use-after-free in unix_stream_bpf_update_proto+0x155/0x490 +Write of size 4 at addr ffff8881178c9a00 by task test_progs/2231 +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x170/0x4f3 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x155/0x490 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Allocated by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + __kasan_slab_alloc+0x63/0x80 + kmem_cache_alloc_noprof+0x1d5/0x680 + sk_prot_alloc+0x59/0x210 + sk_alloc+0x34/0x470 + unix_create1+0x86/0x8a0 + unix_stream_connect+0x318/0x15b0 + __sys_connect+0xfd/0x130 + __x64_sys_connect+0x72/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Freed by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + kasan_save_free_info+0x3b/0x70 + __kasan_slab_free+0x47/0x70 + kmem_cache_free+0x11c/0x590 + __sk_destruct+0x432/0x6e0 + unix_release_sock+0x9b3/0xf60 + unix_release+0x8a/0xf0 + __sock_release+0xb0/0x270 + sock_close+0x18/0x20 + __fput+0x36e/0xac0 + fput_close_sync+0xe5/0x1a0 + __x64_sys_close+0x7d/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-5-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index f810c2b90b8b1..8b0dc82fcdca3 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3607,6 +3607,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + return 0; + + lock_sock(sk); ++ unix_state_lock(sk); + + if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; +@@ -3618,6 +3619,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: ++ unix_state_unlock(sk); + release_sock(sk); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.1/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch b/queue-6.1/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch new file mode 100644 index 0000000000..c5a6f90a5a --- /dev/null +++ b/queue-6.1/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch @@ -0,0 +1,100 @@ +From e21b87f5073ba7c9348b66bbe047f24e7a6d270c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 17:44:28 +0800 +Subject: bpf: test_run: Fix the null pointer dereference issue in + bpf_lwt_xmit_push_encap + +From: Feng Yang + +[ Upstream commit 972787479ee73006fddb5e59ab5c8e733810ff42 ] + +The bpf_lwt_xmit_push_encap helper needs to access skb_dst(skb)->dev to +calculate the needed headroom: + + err = skb_cow_head(skb, + len + LL_RESERVED_SPACE(skb_dst(skb)->dev)); + +But skb->_skb_refdst may not be initialized when the skb is set up by +bpf_prog_test_run_skb function. Executing bpf_lwt_push_ip_encap function +in this scenario will trigger null pointer dereference, causing a kernel +crash as Yinhao reported: + +[ 105.186365] BUG: kernel NULL pointer dereference, address: 0000000000000000 +[ 105.186382] #PF: supervisor read access in kernel mode +[ 105.186388] #PF: error_code(0x0000) - not-present page +[ 105.186393] PGD 121d3d067 P4D 121d3d067 PUD 106c83067 PMD 0 +[ 105.186404] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 105.186412] CPU: 3 PID: 3250 Comm: poc Kdump: loaded Not tainted 6.19.0-rc5 #1 +[ 105.186423] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 105.186427] RIP: 0010:bpf_lwt_push_ip_encap+0x1eb/0x520 +[ 105.186443] Code: 0f 84 de 01 00 00 0f b7 4a 04 66 85 c9 0f 85 47 01 00 00 31 c0 5b 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8b 73 58 48 83 e6 fe <48> 8b 36 0f b7 be ec 00 00 00 0f b7 b6 e6 00 00 00 01 fe 83 e6 f0 +[ 105.186449] RSP: 0018:ffffbb0e0387bc50 EFLAGS: 00010246 +[ 105.186455] RAX: 000000000000004e RBX: ffff94c74e036500 RCX: ffff94c74874da00 +[ 105.186460] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff94c74e036500 +[ 105.186463] RBP: 0000000000000001 R08: 0000000000000002 R09: 0000000000000000 +[ 105.186467] R10: ffffbb0e0387bd50 R11: 0000000000000000 R12: ffffbb0e0387bc98 +[ 105.186471] R13: 0000000000000014 R14: 0000000000000000 R15: 0000000000000002 +[ 105.186484] FS: 00007f166aa4d680(0000) GS:ffff94c8b7780000(0000) knlGS:0000000000000000 +[ 105.186490] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 105.186494] CR2: 0000000000000000 CR3: 000000015eade001 CR4: 0000000000770ee0 +[ 105.186499] PKRU: 55555554 +[ 105.186502] Call Trace: +[ 105.186507] +[ 105.186513] bpf_lwt_xmit_push_encap+0x2b/0x40 +[ 105.186522] bpf_prog_a75eaad51e517912+0x41/0x49 +[ 105.186536] ? kvm_clock_get_cycles+0x18/0x30 +[ 105.186547] ? ktime_get+0x3c/0xa0 +[ 105.186554] bpf_test_run+0x195/0x320 +[ 105.186563] ? bpf_test_run+0x10f/0x320 +[ 105.186579] bpf_prog_test_run_skb+0x2f5/0x4f0 +[ 105.186590] __sys_bpf+0x69c/0xa40 +[ 105.186603] __x64_sys_bpf+0x1e/0x30 +[ 105.186611] do_syscall_64+0x59/0x110 +[ 105.186620] entry_SYSCALL_64_after_hwframe+0x76/0xe0 +[ 105.186649] RIP: 0033:0x7f166a97455d + +Temporarily add the setting of skb->_skb_refdst before bpf_test_run to resolve the issue. + +Fixes: 52f278774e79 ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap") +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Closes: https://groups.google.com/g/hust-os-kernel-patches/c/8-a0kPpBW2s +Signed-off-by: Yun Lu +Signed-off-by: Feng Yang +Signed-off-by: Martin KaFai Lau +Tested-by: syzbot@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260304094429.168521-2-yangfeng59949@163.com +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 2b8daf1cb6885..51259647c65fb 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1200,6 +1200,21 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + skb->ip_summed = CHECKSUM_COMPLETE; + } + ++ if (prog->type == BPF_PROG_TYPE_LWT_XMIT) { ++ if (!ipv6_bpf_stub) { ++ pr_warn_once("Please test this program with the IPv6 module loaded\n"); ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ /* For CONFIG_IPV6=n, ipv6_bpf_stub is NULL which is ++ * handled by the above if statement. ++ */ ++ dst_hold(&net->ipv6.ip6_null_entry->dst); ++ skb_dst_set(skb, &net->ipv6.ip6_null_entry->dst); ++#endif ++ } ++ + ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false); + if (ret) + goto out; +-- +2.53.0 + diff --git a/queue-6.1/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch b/queue-6.1/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch new file mode 100644 index 0000000000..1a36c8f4e4 --- /dev/null +++ b/queue-6.1/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch @@ -0,0 +1,71 @@ +From 0f5058997280bc83b6d2caf1259052b8c73702ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 07:26:45 +0000 +Subject: bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path + +From: David Carlier + +[ Upstream commit 8ed82f807bb09d2c8455aaa665f2c6cb17bc6a19 ] + +The DEVMAP_HASH branch in dev_map_redirect_multi() uses +hlist_for_each_entry_safe() to iterate hash buckets, but this function +runs under RCU protection (called from xdp_do_generic_redirect_map() +in softirq context). Concurrent writers (__dev_map_hash_update_elem, +dev_map_hash_delete_elem) modify the list using RCU primitives +(hlist_add_head_rcu, hlist_del_rcu). + +hlist_for_each_entry_safe() performs plain pointer dereferences without +rcu_dereference(), missing the acquire barrier needed to pair with +writers' rcu_assign_pointer(). On weakly-ordered architectures (ARM64, +POWER), a reader can observe a partially-constructed node. It also +defeats CONFIG_PROVE_RCU lockdep validation and KCSAN data-race +detection. + +Replace with hlist_for_each_entry_rcu() using rcu_read_lock_bh_held() +as the lockdep condition, consistent with the rcu_dereference_check() +used in the DEVMAP (non-hash) branch of the same functions. Also fix +the same incorrect lockdep_is_held(&dtab->index_lock) condition in +dev_map_enqueue_multi(), where the lock is not held either. + +Fixes: e624d4ed4aa8 ("xdp: Extend xdp_redirect_map with broadcast support") +Signed-off-by: David Carlier +Signed-off-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260320072645.16731-1-devnexen@gmail.com +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 71025d1311a57..c8d8977296bc1 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -636,7 +636,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_rcu(dst, head, index_hlist, +- lockdep_is_held(&dtab->index_lock)) { ++ rcu_read_lock_bh_held()) { + if (!is_valid_dst(dst, xdpf)) + continue; + +@@ -718,7 +718,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + struct bpf_dtab_netdev *dst, *last_dst = NULL; + int excluded_devices[1+MAX_NEST_DEV]; + struct hlist_head *head; +- struct hlist_node *next; + int num_excluded = 0; + unsigned int i; + int err; +@@ -758,7 +757,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + } else { /* BPF_MAP_TYPE_DEVMAP_HASH */ + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); +- hlist_for_each_entry_safe(dst, next, head, index_hlist) { ++ hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) { + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-6.1/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch b/queue-6.1/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch new file mode 100644 index 0000000000..27f381d53a --- /dev/null +++ b/queue-6.1/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch @@ -0,0 +1,48 @@ +From e454ff120c03187e280ccbe7d2189877b387de7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:15:23 +0100 +Subject: btrfs: fix double-decrement of bytes_may_use in + submit_one_async_extent() + +From: Mark Harmstone + +[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ] + +submit_one_async_extent() calls btrfs_reserve_extent(), which decrements +bytes_may_use. If the call btrfs_create_io_em() fails, we jump to +out_free_reserve, which calls extent_clear_unlock_delalloc(). + +Because we're specifying EXTENT_DO_ACCOUNTING, i.e. +EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases +bytes_may_use again. This can lead to problems later on, as an initial +write can fail only for the writeback to silently ENOSPC. + +Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. +This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved +extents in cow_one_range()"), which is the same fix in cow_one_range(). + +Fixes: 151a41bc46df ("Btrfs: fix what bits we clear when erroring out from delalloc") +Reviewed-by: Qu Wenruo +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 6a5364b466be1..3cdda1e4ad79e 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1069,7 +1069,7 @@ static int submit_one_async_extent(struct btrfs_inode *inode, + extent_clear_unlock_delalloc(inode, start, end, + NULL, EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | +- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, ++ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, + PAGE_UNLOCK | PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK | PAGE_SET_ERROR); + free_async_extent_pages(async_extent); +-- +2.53.0 + diff --git a/queue-6.1/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch b/queue-6.1/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch new file mode 100644 index 0000000000..3514739f5c --- /dev/null +++ b/queue-6.1/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch @@ -0,0 +1,237 @@ +From ec19b78d0355c754f0f9755ed6415d18320c624a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:01:39 +0100 +Subject: cdrom, scsi: sr: propagate read-only status to block layer via + set_disk_ro() + +From: Daan De Meyer + +[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ] + +The cdrom core never calls set_disk_ro() for a registered device, so +BLKROGET on a CD-ROM device always returns 0 (writable), even when the +drive has no write capabilities and writes will inevitably fail. This +causes problems for userspace that relies on BLKROGET to determine +whether a block device is read-only. For example, systemd's loop device +setup uses BLKROGET to decide whether to create a loop device with +LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the +loop device to the CD-ROM and fail with I/O errors. systemd-fsck +similarly checks BLKROGET to decide whether to run fsck in no-repair +mode (-n). + +The write-capability bits in cdi->mask come from two different sources: +CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE +SENSE capabilities page (page 0x2A) before register_cdrom() is called, +while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command +and were only probed by cdrom_open_write() at device open time. This +meant that any attempt to compute the writable state from the full +mask at probe time was incorrect, because the GET CONFIGURATION bits +were still unset (and cdi->mask is initialized such that capabilities +are assumed present). + +Fix this by factoring the GET CONFIGURATION probing out of +cdrom_open_write() into a new exported helper, +cdrom_probe_write_features(), and having sr call it from sr_probe() +right after get_capabilities() has populated the MODE SENSE bits. +register_cdrom() then calls set_disk_ro() based on the full +write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) +so the block layer reflects the drive's actual write support. The +feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with +RT=00) report drive-level capabilities that are persistent across +media, so a single probe before register_cdrom() is sufficient and the +redundant probe at open time is dropped. + +With set_disk_ro() now accurate, the long-vestigial cd->writeable flag +in sr can go: get_capabilities() used to set cd->writeable based on +the same four mask bits, but because CDC_MRW_W and CDC_RAM default to +"capability present" in cdi->mask and aren't touched by MODE SENSE, +the condition that gated cd->writeable was always true, making it +unconditionally 1. Replace the corresponding gate in sr_init_command() +with get_disk_ro(cd->disk), which turns a previously no-op check into +a real one and also catches kernel-internal bio writers that bypass +blkdev_write_iter()'s bdev_read_only() check. + +The sd driver (SCSI disks) does not have this problem because it +checks the MODE SENSE Write Protect bit and calls set_disk_ro() +accordingly. The sr driver cannot use the same approach because the +MMC specification does not define the WP bit in the MODE SENSE +device-specific parameter byte for CD-ROM devices. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Daan De Meyer +Reviewed-by: Phillip Potter +Reviewed-by: Martin K. Petersen +Signed-off-by: Phillip Potter +Link: https://patch.msgid.link/20260427210139.1400-2-phil@philpotter.co.uk +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- + drivers/scsi/sr.c | 11 ++----- + drivers/scsi/sr.h | 1 - + include/linux/cdrom.h | 1 + + 4 files changed, 51 insertions(+), 35 deletions(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index 8e3eeb96db63e..bba9eb8e2ca90 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -633,6 +633,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) + + WARN_ON(!cdo->generic_packet); + ++ /* ++ * Propagate the drive's write support to the block layer so BLKROGET ++ * reflects actual write capability. Drivers that use GET CONFIGURATION ++ * features (CDC_MRW_W, CDC_RAM) must have called ++ * cdrom_probe_write_features() before register_cdrom() so the mask is ++ * complete here. ++ */ ++ set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | ++ CDC_CD_RW)); ++ + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + mutex_lock(&cdrom_mutex); + list_add(&cdi->list, &cdrom_list); +@@ -747,6 +757,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) + return 0; + } + ++/* ++ * Probe write-related MMC features via GET CONFIGURATION and update ++ * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE ++ * capabilities page (e.g. sr) should call this after those MODE SENSE bits ++ * have been set but before register_cdrom(), so that the full set of ++ * write-capability bits is known by the time register_cdrom() decides on the ++ * initial read-only state of the disk. ++ */ ++void cdrom_probe_write_features(struct cdrom_device_info *cdi) ++{ ++ int mrw, mrw_write, ram_write; ++ ++ mrw = 0; ++ if (!cdrom_is_mrw(cdi, &mrw_write)) ++ mrw = 1; ++ ++ if (CDROM_CAN(CDC_MO_DRIVE)) ++ ram_write = 1; ++ else ++ (void) cdrom_is_random_writable(cdi, &ram_write); ++ ++ if (mrw) ++ cdi->mask &= ~CDC_MRW; ++ else ++ cdi->mask |= CDC_MRW; ++ ++ if (mrw_write) ++ cdi->mask &= ~CDC_MRW_W; ++ else ++ cdi->mask |= CDC_MRW_W; ++ ++ if (ram_write) ++ cdi->mask &= ~CDC_RAM; ++ else ++ cdi->mask |= CDC_RAM; ++} ++EXPORT_SYMBOL(cdrom_probe_write_features); ++ + static int cdrom_media_erasable(struct cdrom_device_info *cdi) + { + disc_information di; +@@ -899,33 +947,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) + */ + static int cdrom_open_write(struct cdrom_device_info *cdi) + { +- int mrw, mrw_write, ram_write; + int ret = 1; + +- mrw = 0; +- if (!cdrom_is_mrw(cdi, &mrw_write)) +- mrw = 1; +- +- if (CDROM_CAN(CDC_MO_DRIVE)) +- ram_write = 1; +- else +- (void) cdrom_is_random_writable(cdi, &ram_write); +- +- if (mrw) +- cdi->mask &= ~CDC_MRW; +- else +- cdi->mask |= CDC_MRW; +- +- if (mrw_write) +- cdi->mask &= ~CDC_MRW_W; +- else +- cdi->mask |= CDC_MRW_W; +- +- if (ram_write) +- cdi->mask &= ~CDC_RAM; +- else +- cdi->mask |= CDC_RAM; +- + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index a278b739d0c5f..dc9c49dd1d0fd 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -392,7 +392,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) + + switch (req_op(rq)) { + case REQ_OP_WRITE: +- if (!cd->writeable) ++ if (get_disk_ro(cd->disk)) + goto out; + SCpnt->cmnd[0] = WRITE_10; + cd->cdi.media_written = 1; +@@ -672,6 +672,7 @@ static int sr_probe(struct device *dev) + error = -ENOMEM; + if (get_capabilities(cd)) + goto fail_minor; ++ cdrom_probe_write_features(&cd->cdi); + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -890,14 +891,6 @@ static int get_capabilities(struct scsi_cd *cd) + /*else I don't think it can close its tray + cd->cdi.mask |= CDC_CLOSE_TRAY; */ + +- /* +- * if DVD-RAM, MRW-W or CD-RW, we are randomly writable +- */ +- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != +- (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { +- cd->writeable = 1; +- } +- + kfree(buffer); + return 0; + } +diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h +index 1175f2e213b56..9809dac8b57d5 100644 +--- a/drivers/scsi/sr.h ++++ b/drivers/scsi/sr.h +@@ -35,7 +35,6 @@ typedef struct scsi_cd { + struct scsi_device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ +- unsigned writeable : 1; + unsigned use:1; /* is this device still supportable */ + unsigned xa_flag:1; /* CD has XA sectors ? */ + unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ +diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h +index 67caa909e3e61..24a344b15bed1 100644 +--- a/include/linux/cdrom.h ++++ b/include/linux/cdrom.h +@@ -109,6 +109,7 @@ extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, + extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing); + ++extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); + extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); + extern void unregister_cdrom(struct cdrom_device_info *cdi); + +-- +2.53.0 + diff --git a/queue-6.1/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch b/queue-6.1/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch new file mode 100644 index 0000000000..95cceb7628 --- /dev/null +++ b/queue-6.1/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch @@ -0,0 +1,47 @@ +From 508e8b3fb1583e0aac30c8f4a783b4b6b6da50f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 09:53:27 +0800 +Subject: cgroup/rdma: fix integer overflow in rdmacg_try_charge() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: cuitao + +[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ] + +The expression `rpool->resources[index].usage + 1` is computed in int +arithmetic before being assigned to s64 variable `new`. When usage equals +INT_MAX (the default "max" value), the addition overflows to INT_MIN. +This negative value then passes the `new > max` check incorrectly, +allowing a charge that should be rejected and corrupting usage to +negative. + +Fix by casting usage to s64 before the addition so the arithmetic is +done in 64-bit. + +Fixes: 39d3e7584a68 ("rdmacg: Added rdma cgroup controller") +Signed-off-by: cuitao +Reviewed-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c +index 3135406608c75..3265fbbbe7e29 100644 +--- a/kernel/cgroup/rdma.c ++++ b/kernel/cgroup/rdma.c +@@ -281,7 +281,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, + ret = PTR_ERR(rpool); + goto err; + } else { +- new = rpool->resources[index].usage + 1; ++ new = (s64)rpool->resources[index].usage + 1; + if (new > rpool->resources[index].max) { + ret = -EAGAIN; + goto err; +-- +2.53.0 + diff --git a/queue-6.1/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch b/queue-6.1/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch new file mode 100644 index 0000000000..b166b0cce0 --- /dev/null +++ b/queue-6.1/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch @@ -0,0 +1,58 @@ +From 612fef5d6517b30e6cf769148e49c6d38d519e82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:58 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in + of_assigned_ldb_sels() + +From: Felix Gu + +[ Upstream commit 9faf207208951460f3f7eefbc112246c8d28ff1b ] + +The function of_assigned_ldb_sels() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing a memory +leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 5d283b083800 ("clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-2-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index b14c1606466d7..a95f07718b653 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -183,9 +183,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + } + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: parent clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + parent = clkspec.args[0]; ++ of_node_put(clkspec.np); + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); +@@ -193,9 +195,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + return; + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: child clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + child = clkspec.args[0]; ++ of_node_put(clkspec.np); + + if (child != IMX6QDL_CLK_LDB_DI0_SEL && + child != IMX6QDL_CLK_LDB_DI1_SEL) +-- +2.53.0 + diff --git a/queue-6.1/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch b/queue-6.1/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch new file mode 100644 index 0000000000..f9160ba34e --- /dev/null +++ b/queue-6.1/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch @@ -0,0 +1,56 @@ +From 2ca7eabfff8d6532eb48c574832e9cdc85cf3612 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:57 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in pll6_bypassed() + +From: Felix Gu + +[ Upstream commit 4b84d496c804b470124cd3a08e928df6801d8eae ] + +The function pll6_bypassed() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing +a memory leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 3cc48976e9763 ("clk: imx6q: handle ENET PLL bypass") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-1-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index de36f58d551c0..b14c1606466d7 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -233,8 +233,11 @@ static bool pll6_bypassed(struct device_node *node) + return false; + + if (clkspec.np == node && +- clkspec.args[0] == IMX6QDL_PLL6_BYPASS) ++ clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { ++ of_node_put(clkspec.np); + break; ++ } ++ of_node_put(clkspec.np); + } + + /* PLL6 bypass is not part of the assigned clock list */ +@@ -244,6 +247,9 @@ static bool pll6_bypassed(struct device_node *node) + ret = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + ++ if (!ret) ++ of_node_put(clkspec.np); ++ + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) + return true; + +-- +2.53.0 + diff --git a/queue-6.1/clk-imx8mq-correct-the-csi-phy-sels.patch b/queue-6.1/clk-imx8mq-correct-the-csi-phy-sels.patch new file mode 100644 index 0000000000..399a6c61cd --- /dev/null +++ b/queue-6.1/clk-imx8mq-correct-the-csi-phy-sels.patch @@ -0,0 +1,49 @@ +From 8e6537b7c045bf83d507fc53e533b589481d81df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 00:47:21 +0100 +Subject: clk: imx8mq: Correct the CSI PHY sels + +From: Sebastian Krzyszkowiak + +[ Upstream commit d16f57caa78776e6e8a88b96cb2597797b376138 ] + +According to i.MX 8M Quad Reference Manual (Section 5.1.2 Table 5-1) +MIPI_CSI1_PHY_REF_CLK_ROOT and MIPI_CSI2_PHY_REF_CLK_ROOT have +SYSTEM_PLL2_DIV3 available as their second source, which corresponds +to sys2_pll_333m rather than sys2_pll_125m. + +Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") +Signed-off-by: Sebastian Krzyszkowiak +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260128-imx8mq-csi-clk-v1-1-ac028ed26e8c@puri.sm +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index 0a75814b3bc77..db71b2aa8230a 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " + static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +@@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", + static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +-- +2.53.0 + diff --git a/queue-6.1/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch b/queue-6.1/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch new file mode 100644 index 0000000000..b0d0d2718f --- /dev/null +++ b/queue-6.1/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch @@ -0,0 +1,59 @@ +From 3fc27fafca465ca354a04957a4001392ff1527c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:26 +0100 +Subject: clk: qcom: dispcc-sc7180: Add missing MDSS resets + +From: Konrad Dybcio + +[ Upstream commit b0bc6011c5499bdfddd0390262bfa13dce1eff74 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: dd3d06622138 ("clk: qcom: Add display clock controller driver for SC7180") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Taniya Das +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-2-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc7180.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c +index 5d2ae297e7413..040149f24d798 100644 +--- a/drivers/clk/qcom/dispcc-sc7180.c ++++ b/drivers/clk/qcom/dispcc-sc7180.c +@@ -16,6 +16,7 @@ + #include "clk-regmap-divider.h" + #include "common.h" + #include "gdsc.h" ++#include "reset.h" + + enum { + P_BI_TCXO, +@@ -635,6 +636,11 @@ static struct gdsc mdss_gdsc = { + .flags = HW_CTRL, + }; + ++static const struct qcom_reset_map disp_cc_sc7180_resets[] = { ++ [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, ++ [DISP_CC_MDSS_RSCC_BCR] = { 0x4000 }, ++}; ++ + static struct gdsc *disp_cc_sc7180_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, + }; +@@ -686,6 +692,8 @@ static const struct qcom_cc_desc disp_cc_sc7180_desc = { + .config = &disp_cc_sc7180_regmap_config, + .clks = disp_cc_sc7180_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sc7180_clocks), ++ .resets = disp_cc_sc7180_resets, ++ .num_resets = ARRAY_SIZE(disp_cc_sc7180_resets), + .gdscs = disp_cc_sc7180_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sc7180_gdscs), + }; +-- +2.53.0 + diff --git a/queue-6.1/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch b/queue-6.1/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..34ebd28eec --- /dev/null +++ b/queue-6.1/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,48 @@ +From ffd00c529dca9d921937fecc78623857f72cc91f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:13 -0300 +Subject: clk: qcom: dispcc-sm8250: Enable parents for pixel clocks + +From: Val Packett + +[ Upstream commit acf7a91d0b0e9e3ef374944021de62062125b7e4 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-9-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index b7d3d3bd1f2af..eb46f1fb8a3a1 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -564,7 +564,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -578,7 +578,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.1/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch b/queue-6.1/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch new file mode 100644 index 0000000000..e9f6cd50b9 --- /dev/null +++ b/queue-6.1/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch @@ -0,0 +1,45 @@ +From 7bb06d0145c2d75da545cde6b54da61a253f8720 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:12 -0300 +Subject: clk: qcom: dispcc-sm8250: Use shared ops on the mdss vsync clk + +From: Val Packett + +[ Upstream commit 8c522da70f0c2e5148c4c13ccb1c64cca57a6fdb ] + +mdss_gdsc can get stuck on boot due to RCGs being left on from last boot. +As a fix, commit 01a0a6cc8cfd ("clk: qcom: Park shared RCGs upon +registration") introduced a callback to ensure the RCG is off upon init. +However, the fix depends on all shared RCGs being marked as such in code. + +For SM8150/SC8180X/SM8250 the MDSS vsync clock was using regular ops, +unlike the same clock in the SC7180 code. This was causing display to +frequently fail to initialize after rebooting on the Surface Pro X. +Fix by using shared ops for this clock. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-8-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index dcd76977a73b3..b7d3d3bd1f2af 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -618,7 +618,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.1/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch b/queue-6.1/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch new file mode 100644 index 0000000000..49d3fcf800 --- /dev/null +++ b/queue-6.1/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch @@ -0,0 +1,41 @@ +From 2458402ee5990dcb43b3962038d682e401091e83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 04:12:23 +0200 +Subject: clk: qcom: dispcc-sm8450: use RCG2 ops for DPTX1 AUX clock source + +From: Dmitry Baryshkov + +[ Upstream commit 141af1be817c42c7f1e1605348d4b1983d319bea ] + +The clk_dp_ops are supposed to be used for DP-related clocks with a +proper MND divier. Use standard RCG2 ops for dptx1_aux_clk_src, the same +as all other DPTX AUX clocks in this driver. + +Fixes: 16fb89f92ec4 ("clk: qcom: Add support for Display Clock Controller on SM8450") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260112-dp-aux-clks-v1-2-456b0c11b069@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8450.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c +index e7dd45a2058c1..e7fab9d38f85e 100644 +--- a/drivers/clk/qcom/dispcc-sm8450.c ++++ b/drivers/clk/qcom/dispcc-sm8450.c +@@ -364,7 +364,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_dp_ops, ++ .ops = &clk_rcg2_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.1/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-6.1/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..afa7e360c4 --- /dev/null +++ b/queue-6.1/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,94 @@ +From fa239244e7ed6add9dd2e4f277d3101e35275d90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:07 -0300 +Subject: clk: qcom: gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 3565741eb985a8a7cc6656eb33496195468cb99e ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-3-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 50 ++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index ba004281f2944..00e2e22a14175 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4200,6 +4200,51 @@ static struct gdsc usb30_mp_gdsc = { + .flags = POLL_CFG_GDSCR, + }; + ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { ++ .gdscr = 0x7d050, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { ++ .gdscr = 0x7d058, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { ++ .gdscr = 0x7d054, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { ++ .gdscr = 0x7d05c, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { ++ .gdscr = 0x7d060, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ + static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, +@@ -4500,6 +4545,11 @@ static struct gdsc *gcc_sc8180x_gdscs[] = { + [USB30_MP_GDSC] = &usb30_mp_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB30_SEC_GDSC] = &usb30_sec_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, + }; + + static const struct regmap_config gcc_sc8180x_regmap_config = { +-- +2.53.0 + diff --git a/queue-6.1/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch b/queue-6.1/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch new file mode 100644 index 0000000000..a5091f8d24 --- /dev/null +++ b/queue-6.1/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch @@ -0,0 +1,74 @@ +From 910ea04fb5f2914cafcd044c167c9ccc2b44fb1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:09 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for PCIe power domains + +From: Val Packett + +[ Upstream commit ccb92c78b42edd26225b4d5920847dfee3e1b093 ] + +As the PCIe host controller driver does not yet support dealing with the +loss of state during suspend, use retention for relevant GDSCs. + +This fixes the link not surviving upon resume: + + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS read failed (134) + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: Disabling device after reset failure: -19 + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260312112321.370983-5-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index e0992f280692b..94da183fad68d 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4133,7 +4133,7 @@ static struct gdsc pcie_0_gdsc = { + .pd = { + .name = "pcie_0_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4160,7 +4160,7 @@ static struct gdsc pcie_1_gdsc = { + .pd = { + .name = "pcie_1_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4169,7 +4169,7 @@ static struct gdsc pcie_2_gdsc = { + .pd = { + .name = "pcie_2_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4187,7 +4187,7 @@ static struct gdsc pcie_3_gdsc = { + .pd = { + .name = "pcie_3_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-6.1/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch b/queue-6.1/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch new file mode 100644 index 0000000000..a93b2bd8e2 --- /dev/null +++ b/queue-6.1/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch @@ -0,0 +1,65 @@ +From 8e706854c983786a356570489f2049f36745ca87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:08 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for USB power domains + +From: Val Packett + +[ Upstream commit 25bc96f26cd6c19dde13a0b9859183e531d6fbfc ] + +The USB subsystem does not expect to lose its state on suspend: + + xhci-hcd xhci-hcd.0.auto: xHC error in resume, USBSTS 0x401, Reinit + usb usb1: root hub lost power or was reset + +(The reinitialization usually succeeds, but it does slow down resume.) + +To maintain state during suspend, the relevant GDSCs need to stay in +retention mode, like they do on other similar SoCs. Change the mode to +PWRSTS_RET_ON to fix. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-4-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 00e2e22a14175..e0992f280692b 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4106,7 +4106,7 @@ static struct gdsc usb30_sec_gdsc = { + .pd = { + .name = "usb30_sec_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4124,7 +4124,7 @@ static struct gdsc usb30_prim_gdsc = { + .pd = { + .name = "usb30_prim_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4196,7 +4196,7 @@ static struct gdsc usb30_mp_gdsc = { + .pd = { + .name = "usb30_mp_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-6.1/clk-qoriq-avoid-format-string-warning.patch b/queue-6.1/clk-qoriq-avoid-format-string-warning.patch new file mode 100644 index 0000000000..e71e8bb2f4 --- /dev/null +++ b/queue-6.1/clk-qoriq-avoid-format-string-warning.patch @@ -0,0 +1,86 @@ +From 48fada94203e7002b13bf182ab38598b848847ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:18:49 +0100 +Subject: clk: qoriq: avoid format string warning + +From: Arnd Bergmann + +[ Upstream commit 096abbb6682ee031a0f5ce9f4c71ead9fa63d31e ] + +clang-22 warns about the use of non-variadic format arguments passed into +snprintf(): + +drivers/clk/clk-qoriq.c:925:39: error: diagnostic behavior may be improved by adding the + 'format(printf, 7, 8)' attribute to the declaration of 'create_mux_common' [-Werror,-Wmissing-format-attribute] + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + | __attribute__((format(printf, 7, 8))) + 911 | struct mux_hwclock *hwc, + 912 | const struct clk_ops *ops, + 913 | unsigned long min_rate, + 914 | unsigned long max_rate, + 915 | unsigned long pct80_rate, + 916 | const char *fmt, int idx) + 917 | { + 918 | struct clk_init_data init = {}; + 919 | struct clk *clk; + 920 | const struct clockgen_pll_div *div; + 921 | const char *parent_names[NUM_MUX_PARENTS]; + 922 | char name[32]; + 923 | int i, j; + 924 | + 925 | snprintf(name, sizeof(name), fmt, idx); + | ^ +drivers/clk/clk-qoriq.c:910:28: note: 'create_mux_common' declared here + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + +Rework this to pass the 'int idx' as a varargs argument, allowing the +format string to be verified at the caller location. + +Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") +Signed-off-by: Arnd Bergmann +Reviewed-by: Kees Cook +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-qoriq.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c +index 5eddb9f0d6bdb..4baec1bf3557f 100644 +--- a/drivers/clk/clk-qoriq.c ++++ b/drivers/clk/clk-qoriq.c +@@ -905,13 +905,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg, + return &cg->pll[pll].div[div]; + } + +-static struct clk * __init create_mux_common(struct clockgen *cg, +- struct mux_hwclock *hwc, +- const struct clk_ops *ops, +- unsigned long min_rate, +- unsigned long max_rate, +- unsigned long pct80_rate, +- const char *fmt, int idx) ++static struct clk * __init __printf(7, 8) ++create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, ++ const struct clk_ops *ops, unsigned long min_rate, ++ unsigned long max_rate, unsigned long pct80_rate, ++ const char *fmt, ...) + { + struct clk_init_data init = {}; + struct clk *clk; +@@ -919,8 +917,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg, + const char *parent_names[NUM_MUX_PARENTS]; + char name[32]; + int i, j; ++ va_list args; + +- snprintf(name, sizeof(name), fmt, idx); ++ va_start(args, fmt); ++ vsnprintf(name, sizeof(name), fmt, args); ++ va_end(args); + + for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) { + unsigned long rate; +-- +2.53.0 + diff --git a/queue-6.1/clk-visconti-pll-initialize-clk_init_data-to-zero.patch b/queue-6.1/clk-visconti-pll-initialize-clk_init_data-to-zero.patch new file mode 100644 index 0000000000..296944910b --- /dev/null +++ b/queue-6.1/clk-visconti-pll-initialize-clk_init_data-to-zero.patch @@ -0,0 +1,52 @@ +From 91d29b55eaa596434cc1cb3b14ec57e68bb3388e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 10:32:37 -0400 +Subject: clk: visconti: pll: initialize clk_init_data to zero +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 1603cbb64173a0e9fa7500f2a686f4aa011c58b9 ] + +Sashiko reported the following: + +> The struct clk_init_data init is declared on the stack without being +> fully zero-initialized. While fields like name, flags, parent_names, +> num_parents, and ops are explicitly assigned, the parent_data and +> parent_hws fields are left containing stack garbage. + +clk_core_populate_parent_map() currently prefers the parent names over +the parent data and hws, so this isn't a problem at the moment. If that +ordering ever changed in the future, then this could lead to some +unexpected crashes. Let's just go ahead and make sure that the struct +clk_init_data is initialized to zero as a good practice. + +Fixes: b4cbe606dc367 ("clk: visconti: Add support common clock driver and reset driver") +Link: https://sashiko.dev/#/patchset/20260326042317.122536-1-rosenp%40gmail.com +Signed-off-by: Brian Masney +Reviewed-by: Benoît Monin +Reviewed-by: Nobuhiro Iwamatsu +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/visconti/pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c +index e9cd80e085dc3..a540936196ca3 100644 +--- a/drivers/clk/visconti/pll.c ++++ b/drivers/clk/visconti/pll.c +@@ -244,7 +244,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, + const struct visconti_pll_rate_table *rate_table, + spinlock_t *lock) + { +- struct clk_init_data init; ++ struct clk_init_data init = {}; + struct visconti_pll *pll; + struct clk_hw *pll_hw_clk; + size_t len; +-- +2.53.0 + diff --git a/queue-6.1/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch b/queue-6.1/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch new file mode 100644 index 0000000000..5e58c67c37 --- /dev/null +++ b/queue-6.1/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch @@ -0,0 +1,37 @@ +From 89014835b0d748b047d7f703d7886795dcde6a1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:11:16 +0100 +Subject: clk: xgene: Fix mapping leak in xgene_pllclk_init() + +From: Geert Uytterhoeven + +[ Upstream commit f520a492e07bc6718e26cfb7543ab4cadd8bb0e2 ] + +If xgene_register_clk_pll() fails, the mapped register block is never +unmapped. + +Fixes: 308964caeebc45eb ("clk: Add APM X-Gene SoC clock driver") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-xgene.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c +index 0c3d0cee98c83..a542b78d9c731 100644 +--- a/drivers/clk/clk-xgene.c ++++ b/drivers/clk/clk-xgene.c +@@ -187,6 +187,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); ++ } else { ++ iounmap(reg); + } + } + +-- +2.53.0 + diff --git a/queue-6.1/container_of-add-container_of_const-that-preserves-c.patch b/queue-6.1/container_of-add-container_of_const-that-preserves-c.patch new file mode 100644 index 0000000000..fd0b291d77 --- /dev/null +++ b/queue-6.1/container_of-add-container_of_const-that-preserves-c.patch @@ -0,0 +1,57 @@ +From dee3269eb05c8f54a5f6d9b50c78e4fd624cc485 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Dec 2022 13:12:03 +0100 +Subject: container_of: add container_of_const() that preserves const-ness of + the pointer + +From: Greg Kroah-Hartman + +[ Upstream commit 64f6a5d1922bf6d2b2d845de20d4563a6f328e2d ] + +container_of does not preserve the const-ness of a pointer that is +passed into it, which can cause C code that passes in a const pointer to +get a pointer back that is not const and then scribble all over the data +in it. To prevent this, container_of_const() will preserve the const +status of the pointer passed into it using the newly available _Generic() +method. + +Suggested-by: Jason Gunthorpe +Suggested-by: Sakari Ailus +Reviewed-by: Matthew Wilcox (Oracle) +Reviewed-by: Jason Gunthorpe +Reviewed-by: Andy Shevchenko +Reviewed-by: Sakari Ailus +Acked-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/20221205121206.166576-1-gregkh@linuxfoundation.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 21e92a38cfd8 ("tcp: add data-race annotations around tp->data_segs_out and tp->total_retrans") +Signed-off-by: Sasha Levin +--- + include/linux/container_of.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/include/linux/container_of.h b/include/linux/container_of.h +index a6f242137b116..c8d7cf8b8522c 100644 +--- a/include/linux/container_of.h ++++ b/include/linux/container_of.h +@@ -21,4 +21,17 @@ + "pointer type mismatch in container_of()"); \ + ((type *)(__mptr - offsetof(type, member))); }) + ++/** ++ * container_of_const - cast a member of a structure out to the containing ++ * structure and preserve the const-ness of the pointer ++ * @ptr: the pointer to the member ++ * @type: the type of the container struct this is embedded in. ++ * @member: the name of the member within the struct. ++ */ ++#define container_of_const(ptr, type, member) \ ++ _Generic(ptr, \ ++ const typeof(*(ptr)) *: ((const type *)container_of(ptr, type, member)),\ ++ default: ((type *)container_of(ptr, type, member)) \ ++ ) ++ + #endif /* _LINUX_CONTAINER_OF_H */ +-- +2.53.0 + diff --git a/queue-6.1/container_of-remove-container_of_safe.patch b/queue-6.1/container_of-remove-container_of_safe.patch new file mode 100644 index 0000000000..3d1bef51a7 --- /dev/null +++ b/queue-6.1/container_of-remove-container_of_safe.patch @@ -0,0 +1,53 @@ +From c66210f75a643394b32b8300474d88b7d4bfaa08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Oct 2022 14:39:33 +0200 +Subject: container_of: remove container_of_safe() + +From: Greg Kroah-Hartman + +[ Upstream commit 848dba781f1951636c966c9f3a6a41a5b2f8b572 ] + +It came in from a staging driver that has been long removed from the +tree, and there are no in-kernel users of the macro, and it's very +dubious if anyone should ever use this thing, so just remove it +entirely. + +Reviewed-by: Sakari Ailus +Acked-by: Rafael J. Wysocki +Acked-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20221024123933.3331116-1-gregkh@linuxfoundation.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 21e92a38cfd8 ("tcp: add data-race annotations around tp->data_segs_out and tp->total_retrans") +Signed-off-by: Sasha Levin +--- + include/linux/container_of.h | 16 ---------------- + 1 file changed, 16 deletions(-) + +diff --git a/include/linux/container_of.h b/include/linux/container_of.h +index 2f4944b791b81..a6f242137b116 100644 +--- a/include/linux/container_of.h ++++ b/include/linux/container_of.h +@@ -21,20 +21,4 @@ + "pointer type mismatch in container_of()"); \ + ((type *)(__mptr - offsetof(type, member))); }) + +-/** +- * container_of_safe - cast a member of a structure out to the containing structure +- * @ptr: the pointer to the member. +- * @type: the type of the container struct this is embedded in. +- * @member: the name of the member within the struct. +- * +- * If IS_ERR_OR_NULL(ptr), ptr is returned unchanged. +- */ +-#define container_of_safe(ptr, type, member) ({ \ +- void *__mptr = (void *)(ptr); \ +- static_assert(__same_type(*(ptr), ((type *)0)->member) || \ +- __same_type(*(ptr), void), \ +- "pointer type mismatch in container_of_safe()"); \ +- IS_ERR_OR_NULL(__mptr) ? ERR_CAST(__mptr) : \ +- ((type *)(__mptr - offsetof(type, member))); }) +- + #endif /* _LINUX_CONTAINER_OF_H */ +-- +2.53.0 + diff --git a/queue-6.1/crypto-ccp-copy-iv-using-skcipher-ivsize.patch b/queue-6.1/crypto-ccp-copy-iv-using-skcipher-ivsize.patch new file mode 100644 index 0000000000..23d4e761c5 --- /dev/null +++ b/queue-6.1/crypto-ccp-copy-iv-using-skcipher-ivsize.patch @@ -0,0 +1,47 @@ +From 22a8f9e44e1affdd71c1fb7d61519953fb9ac903 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 03:07:49 -0500 +Subject: crypto: ccp - copy IV using skcipher ivsize + +From: Paul Moses + +[ Upstream commit a7a1f3cdd64d8a165d9b8c9e9ad7fb46ac19dfc4 ] + +AF_ALG rfc3686-ctr-aes-ccp requests pass an 8-byte IV to the driver. + +ccp_aes_complete() restores AES_BLOCK_SIZE bytes into the caller's IV +buffer while RFC3686 skciphers expose an 8-byte IV, so the restore +overruns the provided buffer. + +Use crypto_skcipher_ivsize() to copy only the algorithm's IV length. + +Fixes: 2b789435d7f3 ("crypto: ccp - CCP AES crypto API support") +Signed-off-by: Paul Moses +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-crypto-aes.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c +index bed331953ff94..87b628bebf96e 100644 +--- a/drivers/crypto/ccp/ccp-crypto-aes.c ++++ b/drivers/crypto/ccp/ccp-crypto-aes.c +@@ -28,8 +28,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) + if (ret) + return ret; + +- if (ctx->u.aes.mode != CCP_AES_MODE_ECB) +- memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE); ++ if (ctx->u.aes.mode != CCP_AES_MODE_ECB) { ++ size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); ++ ++ memcpy(req->iv, rctx->iv, ivsize); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch b/queue-6.1/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch new file mode 100644 index 0000000000..9c5cd2a110 --- /dev/null +++ b/queue-6.1/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch @@ -0,0 +1,47 @@ +From fb4396318a10448cbed2104867aa159d196f564d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 20:06:58 +0530 +Subject: crypto: sa2ul - Fix AEAD fallback algorithm names + +From: T Pratham + +[ Upstream commit 8451ab6ad686ffdcdf9ddadaa446a79ab48e5590 ] + +For authenc AEAD algorithms, sa2ul is trying to register very specific +-ce version as a fallback. This causes registration failure on SoCs +which do not have ARMv8-CE enabled/available. Change the fallback +algorithm from the specific driver name to generic algorithm name so +that the kernel can allocate any available fallback. + +Fixes: d2c8ac187fc92 ("crypto: sa2ul - Add AEAD algorithm support") +Signed-off-by: T Pratham +Reviewed-by: Manorit Chawdhry +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/sa2ul.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c +index e7efebf8127f0..2677062d33b8b 100644 +--- a/drivers/crypto/sa2ul.c ++++ b/drivers/crypto/sa2ul.c +@@ -1774,13 +1774,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, + static int sa_cra_init_aead_sha1(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha1", +- "authenc(hmac(sha1-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha1),cbc(aes))"); + } + + static int sa_cra_init_aead_sha256(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha256", +- "authenc(hmac(sha256-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha256),cbc(aes))"); + } + + static void sa_exit_tfm_aead(struct crypto_aead *tfm) +-- +2.53.0 + diff --git a/queue-6.1/debugfs-check-for-null-pointer-in-debugfs_create_str.patch b/queue-6.1/debugfs-check-for-null-pointer-in-debugfs_create_str.patch new file mode 100644 index 0000000000..a59c2b61b9 --- /dev/null +++ b/queue-6.1/debugfs-check-for-null-pointer-in-debugfs_create_str.patch @@ -0,0 +1,52 @@ +From fd5fc3f9f6342fddd128be3da500b8a059536975 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:44 +0800 +Subject: debugfs: check for NULL pointer in debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 31de83980d3764d784f79ff1bc93c42b324f4013 ] + +Passing a NULL pointer to debugfs_create_str() leads to a NULL pointer +dereference when the debugfs file is read. Following upstream +discussions, forbid the creation of debugfs string files with NULL +pointers. Add a WARN_ON() to expose offending callers and return early. + +Fixes: 9af0440ec86e ("debugfs: Implement debugfs_create_str()") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/2025122221-gag-malt-75ba@gregkh/ +Suggested-by: Greg Kroah-Hartman +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-2-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index b38304b444764..cda3ba59b10f6 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -942,7 +942,7 @@ static const struct file_operations fops_str_wo = { + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write +- * from. ++ * from. This pointer and the string it points to must not be %NULL. + * + * This function creates a file in debugfs with the given name that + * contains the value of the variable @value. If the @mode variable is so +@@ -960,6 +960,9 @@ static const struct file_operations fops_str_wo = { + void debugfs_create_str(const char *name, umode_t mode, + struct dentry *parent, char **value) + { ++ if (WARN_ON(!value || !*value)) ++ return; ++ + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } +-- +2.53.0 + diff --git a/queue-6.1/dev_printk-add-new-dev_err_probe-helpers.patch b/queue-6.1/dev_printk-add-new-dev_err_probe-helpers.patch new file mode 100644 index 0000000000..4b8b63346c --- /dev/null +++ b/queue-6.1/dev_printk-add-new-dev_err_probe-helpers.patch @@ -0,0 +1,47 @@ +From 65f0601633b03dd5b7860d1ced3a31b903ae034e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2024 09:22:37 +0200 +Subject: dev_printk: add new dev_err_probe() helpers + +From: Nuno Sa + +[ Upstream commit dbbe7eaf0e4795bf003ac06872aaf52b6b6b1310 ] + +This is similar to dev_err_probe() but for cases where an ERR_PTR() or +ERR_CAST() is to be returned simplifying patterns like: + + dev_err_probe(dev, ret, ...); + return ERR_PTR(ret) +or + dev_err_probe(dev, PTR_ERR(ptr), ...); + return ERR_CAST(ptr) + +Signed-off-by: Nuno Sa +Link: https://patch.msgid.link/20240606-dev-add_dev_errp_probe-v3-1-51bb229edd79@analog.com +Signed-off-by: Jonathan Cameron +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/dev_printk.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h +index ae80a303c216b..ca32b5bb28eb5 100644 +--- a/include/linux/dev_printk.h ++++ b/include/linux/dev_printk.h +@@ -277,4 +277,12 @@ do { \ + + __printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); + ++/* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */ ++#define dev_err_ptr_probe(dev, ___err, fmt, ...) \ ++ ERR_PTR(dev_err_probe(dev, ___err, fmt, ##__VA_ARGS__)) ++ ++/* Simple helper for dev_err_probe() when ERR_CAST() is to be returned. */ ++#define dev_err_cast_probe(dev, ___err_ptr, fmt, ...) \ ++ ERR_PTR(dev_err_probe(dev, PTR_ERR(___err_ptr), fmt, ##__VA_ARGS__)) ++ + #endif /* _DEVICE_PRINTK_H_ */ +-- +2.53.0 + diff --git a/queue-6.1/devres-fix-missing-node-debug-info-in-devm_krealloc.patch b/queue-6.1/devres-fix-missing-node-debug-info-in-devm_krealloc.patch new file mode 100644 index 0000000000..f75b3d6406 --- /dev/null +++ b/queue-6.1/devres-fix-missing-node-debug-info-in-devm_krealloc.patch @@ -0,0 +1,37 @@ +From 8123034825cc9223e58594ffd77aeaa502ad80f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 00:48:14 +0100 +Subject: devres: fix missing node debug info in devm_krealloc() + +From: Danilo Krummrich + +[ Upstream commit f813ec9e84b4d0ca81ec1da94ab07bfb4a29266c ] + +Fix missing call to set_node_dbginfo() for new devres nodes created by +devm_krealloc(). + +Fixes: f82485722e5d ("devres: provide devm_krealloc()") +Reviewed-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/20260202235210.55176-2-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/base/devres.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index 9d0ea5c14bc50..2b4f866a61db6 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -909,6 +909,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) + if (!new_dr) + return NULL; + ++ set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size); ++ + /* + * The spinlock protects the linked list against concurrent + * modifications but not the resource itself. +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-fix-concurrent-write-failure-in-passthrough.patch b/queue-6.1/dm-cache-fix-concurrent-write-failure-in-passthrough.patch new file mode 100644 index 0000000000..362a8fa073 --- /dev/null +++ b/queue-6.1/dm-cache-fix-concurrent-write-failure-in-passthrough.patch @@ -0,0 +1,84 @@ +From 9aca1411f61e713bb925bf38eebf4282c79fb2d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:09 +0800 +Subject: dm cache: fix concurrent write failure in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit e4f66341779d0cf4c83c74793753a84094286d9e ] + +When bio prison cell lock acquisition fails due to concurrent writes to +the same block in passthrough mode, dm-cache incorrectly returns an I/O +error instead of properly handling the concurrency. This can occur in +both process and workqueue contexts when invalidate_lock() is called for +exclusive access to a data block. Fix this by deferring the write bios +to ensure proper block device behavior. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently. Sometimes one of the + processes will receive I/O errors. + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + + + fio-3.41 + fio: io_u error on file /dev/mapper/cache: Input/output error: write offset=4096, buflen=4096 + fio: pid=106, err=5/file:io_u.c:2008, func=io_u error, error=Input/output error + test: (groupid=0, jobs=1): err= 0: pid=105 + test: (groupid=0, jobs=1): err= 5 (file:io_u.c:2008, func=io_u error, error=Input/output error): pid=106 + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index f7da6f853ec33..c57df4d91c9b2 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1536,6 +1536,15 @@ static int invalidate_lock(struct dm_cache_migration *mg) + READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell); + if (r < 0) { + free_prison_cell(cache, prealloc); ++ ++ /* Defer the bio for retrying the cell lock */ ++ if (mg->overwrite_bio) { ++ struct bio *bio = mg->overwrite_bio; ++ ++ mg->overwrite_bio = NULL; ++ defer_bio(cache, bio); ++ } ++ + invalidate_complete(mg, false); + return r; + } +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch b/queue-6.1/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch new file mode 100644 index 0000000000..724573e47a --- /dev/null +++ b/queue-6.1/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch @@ -0,0 +1,151 @@ +From 5fca8be792a34995553f89ff74cb8738407780f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:10 +0800 +Subject: dm cache: fix dirty mapping checking in passthrough mode switching + +From: Ming-Hung Tsai + +[ Upstream commit 322586745bd1a0e5f3559fd1635fdeb4dbd1d6b8 ] + +As mentioned in commit 9b1cc9f251af ("dm cache: share cache-metadata +object across inactive and active DM tables"), dm-cache assumed table +reload occurs after suspension, while LVM's table preload breaks this +assumption. The dirty mapping check for passthrough mode was designed +around this assumption and is performed during table creation, causing +the check to fail with preload while metadata updates are ongoing. This +risks loading dirty mappings into passthrough mode, resulting in data +loss. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty mappings + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Preload a table in passthrough mode + +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" + +3. Write to the first cache block to make it dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +4. Resume the inactive table. Now it's possible to load the dirty block + into passthrough mode. + +dmsetup resume cache + +Fix by moving the checks to the preresume phase to support table +preloading. Also remove the unused function dm_cache_metadata_all_clean. + +Fixes: 2ee57d587357 ("dm cache: add passthrough mode") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 11 ----------- + drivers/md/dm-cache-metadata.h | 5 ----- + drivers/md/dm-cache-target.c | 25 ++++++++----------------- + 3 files changed, 8 insertions(+), 33 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index f5b4c996dc05f..e921327caa369 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1748,17 +1748,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * + return r; + } + +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) +-{ +- int r; +- +- READ_LOCK(cmd); +- r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); +- READ_UNLOCK(cmd); +- +- return r; +-} +- + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) + { + WRITE_LOCK_VOID(cmd); +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index b40322bc44cf7..9c970fb8e5717 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -137,11 +137,6 @@ void dm_cache_dump(struct dm_cache_metadata *cmd); + */ + int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p); + +-/* +- * Query method. Are all the blocks in the cache clean? +- */ +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); +- + int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); + int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index cbc519f4895e1..cd48cefe0409a 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2482,23 +2482,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) + goto bad; + } + +- if (passthrough_mode(cache)) { +- bool all_clean; +- +- r = dm_cache_metadata_all_clean(cache->cmd, &all_clean); +- if (r) { +- *error = "dm_cache_metadata_all_clean() failed"; +- goto bad; +- } +- +- if (!all_clean) { +- *error = "Cannot enter passthrough mode unless all blocks are clean"; +- r = -EINVAL; +- goto bad; +- } +- ++ if (passthrough_mode(cache)) + policy_allow_migrations(cache->policy, false); +- } + + spin_lock_init(&cache->lock); + bio_list_init(&cache->deferred_bios); +@@ -2824,6 +2809,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + struct cache *cache = context; + + if (dirty) { ++ if (passthrough_mode(cache)) { ++ DMERR("%s: cannot enter passthrough mode unless all blocks are clean", ++ cache_device_name(cache)); ++ return -EBUSY; ++ } ++ + set_bit(from_cblock(cblock), cache->dirty_bitset); + atomic_inc(&cache->nr_dirty); + } else +@@ -3057,7 +3048,7 @@ static int cache_preresume(struct dm_target *ti) + load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- if (r != -EFBIG) ++ if (r != -EFBIG && r != -EBUSY) + metadata_operation_failed(cache, "dm_cache_load_mappings", r); + return r; + } +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-fix-missing-return-in-invalidate_committed-.patch b/queue-6.1/dm-cache-fix-missing-return-in-invalidate_committed-.patch new file mode 100644 index 0000000000..7d90b3d729 --- /dev/null +++ b/queue-6.1/dm-cache-fix-missing-return-in-invalidate_committed-.patch @@ -0,0 +1,51 @@ +From e8edb2c8820be93f4b01ea797e6d69d176d8b68c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 21:08:01 +0800 +Subject: dm cache: fix missing return in invalidate_committed's error path + +From: Ming-Hung Tsai + +[ Upstream commit 8c0ee19db81f0fa1ff25fd75b22b17c0cc2acde3 ] + +In passthrough mode, dm-cache defers write submission until after +metadata commit completes via the invalidate_committed() continuation. +On commit error, invalidate_committed() calls invalidate_complete() to +end the bio and free the migration struct, after which it should return +immediately. + +The patch 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +omitted this early return, causing execution to fall through into the +success path on error. This results in use-after-free on the migration +struct in the subsequent calls. + +Fix by adding the missing return after the invalidate_complete() call. + +Fixes: 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/dm-devel/adjMq6T5RRjv_uxM@stanley.mountain/ +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index cd48cefe0409a..e47033fc53106 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1502,8 +1502,10 @@ static void invalidate_committed(struct work_struct *ws) + struct bio *bio = mg->overwrite_bio; + struct per_bio_data *pb = get_per_bio_data(bio); + +- if (mg->k.input) ++ if (mg->k.input) { + invalidate_complete(mg, false); ++ return; ++ } + + init_continuation(&mg->k, invalidate_completed); + remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch b/queue-6.1/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch new file mode 100644 index 0000000000..644dd970e7 --- /dev/null +++ b/queue-6.1/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch @@ -0,0 +1,86 @@ +From e922d4f2b9e1b8acaea7d777c2509b72fc5ff812 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:05 +0800 +Subject: dm cache: fix null-deref with concurrent writes in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 7d1f98d668ee34c1d15bdc0420fdd062f24a27c0 ] + +In passthrough mode, when dm-cache starts to invalidate a cache +entry and bio prison cell lock fails due to concurrent write to +the same cached block, mg->cell remains NULL. The error path in +invalidate_complete() attempts to unlock and free the cell +unconditionally, causing a NULL pointer dereference: + +KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +CPU: 0 UID: 0 PID: 134 Comm: fio Not tainted 6.19.0-rc7 #3 PREEMPT +RIP: 0010:dm_cell_unlock_v2+0x3f/0x210 + +Call Trace: + invalidate_complete+0xef/0x430 + map_bio+0x130f/0x1a10 + cache_map+0x320/0x6b0 + __map_bio+0x458/0x510 + dm_submit_bio+0x40e/0x16d0 + __submit_bio+0x419/0x870 + + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + +Fix by checking if mg->cell is valid before attempting to unlock it. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 66608b42ee1ad..e0373522cb88c 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1440,8 +1440,10 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + struct cache *cache = mg->cache; + + bio_list_init(&bios); +- if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) +- free_prison_cell(cache, mg->cell); ++ if (mg->cell) { ++ if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) ++ free_prison_cell(cache, mg->cell); ++ } + + if (!success && mg->overwrite_bio) + bio_io_error(mg->overwrite_bio); +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-fix-write-hang-in-passthrough-mode.patch b/queue-6.1/dm-cache-fix-write-hang-in-passthrough-mode.patch new file mode 100644 index 0000000000..9d270a131b --- /dev/null +++ b/queue-6.1/dm-cache-fix-write-hang-in-passthrough-mode.patch @@ -0,0 +1,88 @@ +From 7622d6a9c8f43045c01e94c6fe848854c6611934 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:07 +0800 +Subject: dm cache: fix write hang in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 4ca8b8bd952df7c3ccdc68af9bd3419d0839a04b ] + +The invalidate_remove() function has incomplete logic for handling write +hit bios after cache invalidation. It sets up the remapping for the +overwrite_bio but then drops it immediately without submission, causing +write operations to hang. + +Fix by adding a new invalidate_committed() continuation that submits +the remapped writes to the cache origin after metadata commit completes, +while using the overwrite_endio hook to ensure proper completion +sequencing. This maintains existing coherency. Also improve error +handling in invalidate_complete() to preserve the original error status +instead of using bio_io_error() unconditionally. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index e2e234c3649a0..f7da6f853ec33 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1445,8 +1445,14 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + free_prison_cell(cache, mg->cell); + } + +- if (!success && mg->overwrite_bio) +- bio_io_error(mg->overwrite_bio); ++ if (mg->overwrite_bio) { ++ // Set generic error if the bio hasn't been issued yet, ++ // e.g., invalidation or metadata commit failed before bio ++ // submission. Otherwise preserve the bio's own error status. ++ if (!success && !mg->overwrite_bio->bi_status) ++ mg->overwrite_bio->bi_status = BLK_STS_IOERR; ++ bio_endio(mg->overwrite_bio); ++ } + + free_migration(mg); + defer_bios(cache, &bios); +@@ -1483,6 +1489,22 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock) + return r; + } + ++static void invalidate_committed(struct work_struct *ws) ++{ ++ struct dm_cache_migration *mg = ws_to_mg(ws); ++ struct cache *cache = mg->cache; ++ struct bio *bio = mg->overwrite_bio; ++ struct per_bio_data *pb = get_per_bio_data(bio); ++ ++ if (mg->k.input) ++ invalidate_complete(mg, false); ++ ++ init_continuation(&mg->k, invalidate_completed); ++ remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); ++ dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg); ++ dm_submit_bio_remap(bio, NULL); ++} ++ + static void invalidate_remove(struct work_struct *ws) + { + int r; +@@ -1495,10 +1517,8 @@ static void invalidate_remove(struct work_struct *ws) + return; + } + +- init_continuation(&mg->k, invalidate_completed); ++ init_continuation(&mg->k, invalidate_committed); + continue_after_commit(&cache->committer, &mg->k); +- remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock); +- mg->overwrite_bio = NULL; + schedule_commit(&cache->committer); + } + +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch b/queue-6.1/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch new file mode 100644 index 0000000000..ea5b1403e6 --- /dev/null +++ b/queue-6.1/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch @@ -0,0 +1,85 @@ +From 88764928ea38c0801a388f83f7a325ee9d84e847 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:06 +0800 +Subject: dm cache: fix write path cache coherency in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 0c5eef0aad508231d8e43ff8392692925e131b68 ] + +In passthrough mode, dm-cache defers write bio submission until cache +invalidation completes to maintain existing coherency, requiring the +target map function to return DM_MAPIO_SUBMITTED. The current map_bio() +returns DM_MAPIO_REMAPPED, violating the required ordering constraint. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into the cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first data block, and check io ordering using ftrace + +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_queue/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_complete/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_rq_complete/enable +fio --filename=/dev/mapper/cache --name=test --rw=write --bs=64k \ +--direct=1 --size 64k + +5. ftrace logs show that write operations to the cache origin (252:2) + and metadata operations (252:0) are unsynchronized: the origin write + occurs before metadata commit. + + + fio-146 [000] ..... 420.139562: block_bio_queue: 252,3 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149395: block_bio_queue: 252,2 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149763: block_bio_queue: 8,32 WS 262144 + 128 [fio] + fio-146 [000] dNh1. 420.151446: block_rq_complete: 8,32 WS () 262144 + 128 be,0,4 [0] + fio-146 [000] dNh1. 420.152731: block_bio_complete: 252,2 WS 0 + 128 [0] + fio-146 [000] dNh1. 420.154229: block_bio_complete: 252,3 WS 0 + 128 [0] + kworker/0:0-9 [000] ..... 420.160530: block_bio_queue: 252,0 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.161641: block_bio_queue: 8,32 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162533: block_bio_queue: 252,0 W 416 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162821: block_bio_queue: 8,32 W 416 + 8 [kworker/0:0] + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index e0373522cb88c..e2e234c3649a0 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1676,6 +1676,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, + bio_drop_shared_lock(cache, bio); + atomic_inc(&cache->stats.demotion); + invalidate_start(cache, cblock, block, bio); ++ return DM_MAPIO_SUBMITTED; + } else + remap_to_origin_clear_discard(cache, bio, block); + } else { +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch b/queue-6.1/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch new file mode 100644 index 0000000000..c8d6f050e2 --- /dev/null +++ b/queue-6.1/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch @@ -0,0 +1,121 @@ +From e414245eedbcb0136aa237b486da091cefc2e6ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:56:28 +0800 +Subject: dm cache metadata: fix memory leak on metadata abort retry + +From: Ming-Hung Tsai + +[ Upstream commit 044ca491d4086dc5bf233e9fcb71db52df32f633 ] + +When failing to acquire the root_lock in dm_cache_metadata_abort because +the block_manager is read-only, the temporary block_manager created +outside the root_lock is not properly released, causing a memory leak. + +Reproduce steps: + +This can be reproduced by reloading a new table while the metadata +is read-only. While the second call to dm_cache_metadata_abort is +caused by lack of support for table preload in dm-cache, mentioned +in commit 9b1cc9f251af ("dm cache: share cache-metadata object across +inactive and active DM tables"), it exposes the memory leak in +dm_cache_metadata_abort when the function is called multiple times. +Specifically, dm-cache fails to sync the new cache object's mode during +preresume, creating the reproducer condition. + +This issue could also occur through concurrent metadata_operation_failed +calls due to races in cache mode updates, but the table preload scenario +below provides a reliable reproducer. + +1. Create a cache device with some faulty trailing metadata blocks + +dmsetup create cmeta < +unreferenced object 0xffff8880080c2010 (size 16): + comm "dmsetup", pid 132, jiffies 4294982580 + hex dump (first 16 bytes): + 00 38 b9 07 80 88 ff ff 6a 6b 6b 6b 6b 6b 6b a5 ... + backtrace (crc 3118f31c): + kmemleak_alloc+0x28/0x40 + __kmalloc_cache_noprof+0x3d9/0x510 + dm_block_manager_create+0x51/0x140 + dm_cache_metadata_abort+0x85/0x320 + metadata_operation_failed+0x103/0x1e0 + cache_preresume+0xacd/0xe70 + dm_table_resume_targets+0xd3/0x320 + __dm_resume+0x1b/0xf0 + dm_resume+0x127/0x170 + + +Fixes: 352b837a5541 ("dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index e921327caa369..9c112ab72cbaa 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1017,6 +1017,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd) + return; \ + } while(0) + ++#define WRITE_LOCK_OR_GOTO(cmd, label) \ ++ do { \ ++ if (!cmd_write_lock((cmd))) \ ++ goto label; \ ++ } while (0) ++ + #define WRITE_UNLOCK(cmd) \ + up_write(&(cmd)->root_lock) + +@@ -1814,11 +1820,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, + CACHE_MAX_CONCURRENT_LOCKS); + +- WRITE_LOCK(cmd); +- if (cmd->fail_io) { +- WRITE_UNLOCK(cmd); +- goto out; +- } ++ /* cmd_write_lock() already checks fail_io with cmd->root_lock held */ ++ WRITE_LOCK_OR_GOTO(cmd, out); + + __destroy_persistent_data_objects(cmd, false); + old_bm = cmd->bm; +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch b/queue-6.1/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch new file mode 100644 index 0000000000..f98aa56cd1 --- /dev/null +++ b/queue-6.1/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch @@ -0,0 +1,91 @@ +From 1905d6a723a82291ee5a6d4fe05a50941c475c0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:08 +0800 +Subject: dm cache policy smq: fix missing locks in invalidating cache blocks + +From: Ming-Hung Tsai + +[ Upstream commit 2d1f7b65f5deedd2e6b09fdc6ea27f8375f24b45 ] + +In passthrough mode, the policy invalidate_mapping operation is called +simultaneously from multiple workers, thus it should be protected by a +lock. Otherwise, we might end up with data races on the allocated blocks +counter, or even use-after-free issues with internal data structures +when doing concurrent writes. + +Note that the existing FIXME in smq_invalidate_mapping() doesn't affect +passthrough mode since migration tasks don't exist there, but would need +attention if supporting fast device shrinking via suspend/resume without +target reloading. + +Reproduce steps: + +1. Create a cache device consisting of 1024 cache entries + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Populate the cache, and record the number of cached blocks + +fio --name=populate --filename=/dev/mapper/cache --rw=randwrite --bs=4k \ +--size=64m --direct=1 +nr_cached=$(dmsetup status cache | awk '{split($7, a, "/"); print a[1]}') + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the passthrough cache. By setting multiple jobs with I/O + size equal to the cache block size, cache blocks are invalidated + concurrently from different workers. + +fio --filename=/dev/mapper/cache --name=test --rw=randwrite --bs=64k \ +--direct=1 --numjobs=2 --randrepeat=0 --size=64m + +5. Check if demoted matches cached block count. These numbers should + match but may differ due to the data race. + +nr_demoted=$(dmsetup status cache | awk '{print $12}') +echo "$nr_cached, $nr_demoted" + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index c983cf240632e..d4c2bc5c0ef45 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1587,14 +1587,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + { + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); ++ unsigned long flags; + + if (!e->allocated) + return -ENODATA; + ++ spin_lock_irqsave(&mq->lock, flags); + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ spin_unlock_irqrestore(&mq->lock, flags); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.1/dm-cache-support-shrinking-the-origin-device.patch b/queue-6.1/dm-cache-support-shrinking-the-origin-device.patch new file mode 100644 index 0000000000..81cac61e12 --- /dev/null +++ b/queue-6.1/dm-cache-support-shrinking-the-origin-device.patch @@ -0,0 +1,197 @@ +From 48ca22faadee770584e80042f3f0f0c1e4d80096 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 16:41:51 +0800 +Subject: dm cache: support shrinking the origin device + +From: Ming-Hung Tsai + +[ Upstream commit c2662b1544cbd8ea3181381bb899b8e681dfedc7 ] + +This patch introduces formal support for shrinking the cache origin by +reducing the cache target length via table reloads. Cache blocks mapped +beyond the new target length must be clean and are invalidated during +preresume. If any dirty blocks exist in the area being removed, the +preresume operation fails without setting the NEEDS_CHECK flag in +superblock, and the resume ioctl returns EFBIG. The cache device remains +suspended until a table reload with target length that fits existing +mappings is performed. + +Without this patch, reducing the cache target length could result in +io errors (RHBZ: 2134334), out-of-bounds memory access to the discard +bitset, and security concerns regarding data leakage. + +Verification steps: + +1. create a cache metadata with some cached blocks mapped to the tail + of the origin device. Here we use cache_restore v1.0 to build a + metadata with one clean block mapped to the last origin block. + +cat <> cmeta.xml + + + + + +EOF +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +cache_restore -i cmeta.xml -o /dev/mapper/cmeta --metadata-version=2 +dmsetup remove cmeta + +2. bring up the cache whilst shrinking the cache origin by one block: + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" +dmsetup create corig --table "0 524160 linear /dev/sdc 262144" +dmsetup create cache --table "0 524160 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +3. check the number of cached data blocks via dmsetup status. It is + expected to be zero. + +dmsetup status cache | cut -d ' ' -f 7 + +In addition to the script above, this patch can be verified using the +"cache/resize" tests in dmtest-python: + +./dmtest run --rx cache/resize/shrink_origin --result-set default + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Stable-dep-of: 322586745bd1 ("dm cache: fix dirty mapping checking in passthrough mode switching") +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 72 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 69 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index c57df4d91c9b2..cbc519f4895e1 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -405,6 +405,12 @@ struct cache { + mempool_t migration_pool; + + struct bio_set bs; ++ ++ /* ++ * Cache_size entries. Set bits indicate blocks mapped beyond the ++ * target length, which are marked for invalidation. ++ */ ++ unsigned long *invalid_bitset; + }; + + struct per_bio_data { +@@ -1930,6 +1936,9 @@ static void __destroy(struct cache *cache) + if (cache->discard_bitset) + free_bitset(cache->discard_bitset); + ++ if (cache->invalid_bitset) ++ free_bitset(cache->invalid_bitset); ++ + if (cache->copier) + dm_kcopyd_client_destroy(cache->copier); + +@@ -2518,6 +2527,13 @@ static int cache_create(struct cache_args *ca, struct cache **result) + } + clear_bitset(cache->discard_bitset, from_dblock(cache->discard_nr_blocks)); + ++ cache->invalid_bitset = alloc_bitset(from_cblock(cache->cache_size)); ++ if (!cache->invalid_bitset) { ++ *error = "could not allocate bitset for invalid blocks"; ++ goto bad; ++ } ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + cache->copier = dm_kcopyd_client_create(&dm_kcopyd_throttle); + if (IS_ERR(cache->copier)) { + *error = "could not create kcopyd client"; +@@ -2816,6 +2832,24 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + return policy_load_mapping(cache->policy, oblock, cblock, dirty, hint, hint_valid); + } + ++static int load_filtered_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, ++ bool dirty, uint32_t hint, bool hint_valid) ++{ ++ struct cache *cache = context; ++ ++ if (from_oblock(oblock) >= from_oblock(cache->origin_blocks)) { ++ if (dirty) { ++ DMERR("%s: unable to shrink origin; cache block %u is dirty", ++ cache_device_name(cache), from_cblock(cblock)); ++ return -EFBIG; ++ } ++ set_bit(from_cblock(cblock), cache->invalid_bitset); ++ return 0; ++ } ++ ++ return load_mapping(context, oblock, cblock, dirty, hint, hint_valid); ++} ++ + /* + * The discard block size in the on disk metadata is not + * necessarily the same as we're currently using. So we have to +@@ -2970,6 +3004,24 @@ static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size) + return 0; + } + ++static int truncate_oblocks(struct cache *cache) ++{ ++ uint32_t nr_blocks = from_cblock(cache->cache_size); ++ uint32_t i; ++ int r; ++ ++ for_each_set_bit(i, cache->invalid_bitset, nr_blocks) { ++ r = dm_cache_remove_mapping(cache->cmd, to_cblock(i)); ++ if (r) { ++ DMERR_LIMIT("%s: invalidation failed; couldn't update on disk metadata", ++ cache_device_name(cache)); ++ return r; ++ } ++ } ++ ++ return 0; ++} ++ + static int cache_preresume(struct dm_target *ti) + { + int r = 0; +@@ -2994,11 +3046,25 @@ static int cache_preresume(struct dm_target *ti) + } + + if (!cache->loaded_mappings) { ++ /* ++ * The fast device could have been resized since the last ++ * failed preresume attempt. To be safe we start by a blank ++ * bitset for cache blocks. ++ */ ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + r = dm_cache_load_mappings(cache->cmd, cache->policy, +- load_mapping, cache); ++ load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ if (r != -EFBIG) ++ metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ return r; ++ } ++ ++ r = truncate_oblocks(cache); ++ if (r) { ++ metadata_operation_failed(cache, "dm_cache_remove_mapping", r); + return r; + } + +@@ -3464,7 +3530,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 2, 0}, ++ .version = {2, 3, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-6.1/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch b/queue-6.1/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch new file mode 100644 index 0000000000..eac945c913 --- /dev/null +++ b/queue-6.1/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch @@ -0,0 +1,58 @@ +From 5c80e5b339f2ae94a9c4cf0c7b156f20a04d3b6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 22:32:28 +0100 +Subject: dm init: ensure device probing has finished in dm-mod.waitfor= + +From: Guillaume Gonnet + +[ Upstream commit 99a2312f69805f4ba92d98a757625e0300a747ab ] + +The early_lookup_bdev() function returns successfully when the disk +device is present but not necessarily its partitions. In this situation, +dm_early_create() fails as the partition block device does not exist +yet. + +In my case, this phenomenon occurs quite often because the device is +an SD card with slow reading times, on which kernel takes time to +enumerate available partitions. + +Fortunately, the underlying device is back to "probing" state while +enumerating partitions. Waiting for all probing to end is enough to fix +this issue. + +That's also the reason why this problem never occurs with rootwait= +parameter: the while loop inside wait_for_root() explicitly waits for +probing to be done and then the function calls async_synchronize_full(). +These lines were omitted in 035641b, even though the commit says it's +based on the rootwait logic... + +Anyway, calling wait_for_device_probe() after our while loop does the +job (it both waits for probing and calls async_synchronize_full). + +Fixes: 035641b01e72 ("dm init: add dm-mod.waitfor to wait for asynchronously probed block devices") +Signed-off-by: Guillaume Gonnet +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-init.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c +index 6e9e73a558740..882dc385cf068 100644 +--- a/drivers/md/dm-init.c ++++ b/drivers/md/dm-init.c +@@ -302,8 +302,10 @@ static int __init dm_init_init(void) + } + } + +- if (waitfor[0]) ++ if (waitfor[0]) { ++ wait_for_device_probe(); + DMINFO("all devices available"); ++ } + + list_for_each_entry(dev, &devices, list) { + if (dm_early_create(&dev->dmi, dev->table, +-- +2.53.0 + diff --git a/queue-6.1/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch b/queue-6.1/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch new file mode 100644 index 0000000000..b822bfae9b --- /dev/null +++ b/queue-6.1/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch @@ -0,0 +1,81 @@ +From 697b9a43432e0dfd1fb6028dd08422ec2f9b152e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:05:48 +0800 +Subject: dm log: fix out-of-bounds write due to region_count overflow + +From: Junrui Luo + +[ Upstream commit c20e36b7631d83e7535877f08af8b0af72c44b1a ] + +The local variable region_count in create_log_context() is declared as +unsigned int (32-bit), but dm_sector_div_up() returns sector_t (64-bit). +When a device-mapper target has a sufficiently large ti->len with a small +region_size, the division result can exceed UINT_MAX. The truncated +value is then used to calculate bitset_size, causing clean_bits, +sync_bits, and recovering_bits to be allocated far smaller than needed +for the actual number of regions. + +Subsequent log operations (log_set_bit, log_clear_bit, log_test_bit) use +region indices derived from the full untruncated region space, causing +out-of-bounds writes to kernel heap memory allocated by vmalloc. + +This can be reproduced by creating a mirror target whose region_count +overflows 32 bits: + + dmsetup create bigzero --table '0 8589934594 zero' + dmsetup create mymirror --table '0 8589934594 mirror \ + core 2 2 nosync 2 /dev/mapper/bigzero 0 \ + /dev/mapper/bigzero 0' + +The status output confirms the truncation (sync_count=1 instead of +4294967297, because 0x100000001 was truncated to 1): + + $ dmsetup status mymirror + 0 8589934594 mirror 2 254:1 254:1 1/4294967297 ... + +This leads to a kernel crash in core_in_sync: + + BUG: scheduling while atomic: (udev-worker)/9150/0x00000000 + RIP: 0010:core_in_sync+0x14/0x30 [dm_log] + CR2: 0000000000000008 + Fixing recursive fault but reboot is needed! + +Fix by widening the local region_count to sector_t and adding an +explicit overflow check before the value is assigned to lc->region_count. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-log.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c +index da77878cb2c02..32a3cb131e578 100644 +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -366,7 +366,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + + struct log_c *lc; + uint32_t region_size; +- unsigned int region_count; ++ sector_t region_count; + size_t bitset_size, buf_size; + int r; + char dummy; +@@ -394,6 +394,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + } + + region_count = dm_sector_div_up(ti->len, region_size); ++ if (region_count > UINT_MAX) { ++ DMWARN("region count exceeds limit of %u", UINT_MAX); ++ return -EINVAL; ++ } + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) { +-- +2.53.0 + diff --git a/queue-6.1/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch b/queue-6.1/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch new file mode 100644 index 0000000000..efbc039ed2 --- /dev/null +++ b/queue-6.1/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch @@ -0,0 +1,50 @@ +From ef138614a5abc6f1d7c43fb1414857eb7971680d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 14:02:19 +0800 +Subject: dmaengine: dw-axi-dmac: Remove unnecessary return statement from void + function + +From: Khairul Anuar Romli + +[ Upstream commit 48278a72fce8a8d30efaedeb206c9c3f05c1eb3f ] + +checkpatch.pl --strict reports a WARNING in dw-axi-dmac-platform.c: + + WARNING: void function return statements are not generally useful + FILE: drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c + +According to Linux kernel coding style [Documentation/process/ +coding-style.rst], explicit "return;" statements at the end of void +functions are redundant and should be omitted. The function will +automatically return upon reaching the closing brace, so the extra +statement adds unnecessary clutter without functional benefit. + +This patch removes the superfluous "return;" statement in +dw_axi_dma_set_hw_channel() to comply with kernel coding standards and +eliminate the checkpatch warning. + +Fixes: 32286e279385 ("dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel") +Signed-off-by: Khairul Anuar Romli +Link: https://patch.msgid.link/20260202060224.12616-4-karom.9560@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index 7596864bf8bb2..46b080941b621 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -540,8 +540,6 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) + (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0); +- +- return; + } + + /* +-- +2.53.0 + diff --git a/queue-6.1/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch b/queue-6.1/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch new file mode 100644 index 0000000000..f4ecb89445 --- /dev/null +++ b/queue-6.1/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch @@ -0,0 +1,37 @@ +From 551a3d115073d31cc84caffdf0c9fe4e9a633126 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:41:38 -0500 +Subject: dmaengine: mxs-dma: Fix missing return value from + of_dma_controller_register() + +From: Frank Li + +[ Upstream commit ab2bf6d4c0a0152907b18d25c1b118ea5ea779df ] + +Propagate the return value of of_dma_controller_register() in probe() +instead of ignoring it. + +Fixes: a580b8c5429a6 ("dmaengine: mxs-dma: add dma support for i.MX23/28") +Signed-off-by: Frank Li +Link: https://patch.msgid.link/20260225-mxsdma-module-v3-2-8f798b13baa6@nxp.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mxs-dma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c +index dc147cc2436e9..5d34440b9e127 100644 +--- a/drivers/dma/mxs-dma.c ++++ b/drivers/dma/mxs-dma.c +@@ -827,6 +827,7 @@ static int mxs_dma_probe(struct platform_device *pdev) + if (ret) { + dev_err(mxs_dma->dma_device.dev, + "failed to register controller\n"); ++ return ret; + } + + dev_info(mxs_dma->dma_device.dev, "initialized\n"); +-- +2.53.0 + diff --git a/queue-6.1/documentation-fix-a-hugetlbfs-reservation-statement.patch b/queue-6.1/documentation-fix-a-hugetlbfs-reservation-statement.patch new file mode 100644 index 0000000000..50415ca678 --- /dev/null +++ b/queue-6.1/documentation-fix-a-hugetlbfs-reservation-statement.patch @@ -0,0 +1,63 @@ +From e7f6b8cbddd74f376ac42907995e9c789fedabe4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 13:10:15 -0700 +Subject: Documentation: fix a hugetlbfs reservation statement + +From: Jane Chu + +[ Upstream commit 7a197d346a44384a1a858a98ef03766840e561d4 ] + +Documentation/mm/hugetlbfs_reserv.rst has + if (resv_needed <= (resv_huge_pages - free_huge_pages)) + resv_huge_pages += resv_needed; +which describes this code in gather_surplus_pages() + needed = (h->resv_huge_pages + delta) - h->free_huge_pages; + if (needed <= 0) { + h->resv_huge_pages += delta; + return 0; + } +which means if there are enough free hugepages to account for the new +reservation, simply update the global reservation count without +further action. + +But the description is backwards, it should be + if (resv_needed <= (free_huge_pages - resv_huge_pages)) +instead. + +Link: https://lkml.kernel.org/r/20260302201015.1824798-1-jane.chu@oracle.com +Fixes: 70bc0dc578b3 ("Documentation: vm, add hugetlbfs reservation overview") +Signed-off-by: Jane Chu +Cc: David Hildenbrand +Cc: Hillf Danton +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Oscar Salvador +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/mm/hugetlbfs_reserv.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/mm/hugetlbfs_reserv.rst b/Documentation/mm/hugetlbfs_reserv.rst +index f143954e0d056..1c238b10e1772 100644 +--- a/Documentation/mm/hugetlbfs_reserv.rst ++++ b/Documentation/mm/hugetlbfs_reserv.rst +@@ -157,7 +157,7 @@ are enough free huge pages to accommodate the reservation. If there are, + the global reservation count resv_huge_pages is adjusted something like the + following:: + +- if (resv_needed <= (resv_huge_pages - free_huge_pages)) ++ if (resv_needed <= (free_huge_pages - resv_huge_pages) + resv_huge_pages += resv_needed; + + Note that the global lock hugetlb_lock is held when checking and adjusting +-- +2.53.0 + diff --git a/queue-6.1/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch b/queue-6.1/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch new file mode 100644 index 0000000000..23bcc4ceae --- /dev/null +++ b/queue-6.1/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch @@ -0,0 +1,54 @@ +From 53439ab27322e81730a8d81472dea8f25ef3ecb5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:06 +0000 +Subject: dpaa2: add independent dependencies for FSL_DPAA2_SWITCH + +From: Cai Xinchen + +[ Upstream commit 12589892f41c4c645c80ef9f036f7451a6045624 ] + +Since the commit 84cba72956fd ("dpaa2-switch: integrate +the MAC endpoint support") included dpaa2-mac.o in the driver, +but it didn't select PCS_LYNX, PHYLINK and FSL_XGMAC_MDIO. it +will lead to link error, such as +undefined reference to `phylink_ethtool_ksettings_set' +undefined reference to `lynx_pcs_create_fwnode' + +And the same reason as the commit d2624e70a2f53 ("dpaa2-eth: select +XGMAC_MDIO for MDIO bus support"), enable the FSL_XGMAC_MDIO Kconfig +option in order to have MDIO access to internal and external PHYs. + +Because dpaa2-switch uses fsl_mc_driver APIs, add depends on FSL_MC_BUS +&& FSL_MC_DPIO as FSL_DPAA2_SWITCH do. + +FSL_XGMAC_MDIO and FSL_MC_BUS depend on OF, thus the dependence of +FSL_MC_BUS can satisfy FSL_XGMAC_MDIO's OF requirement. + +Fixes: 84cba72956fd ("dpaa2-switch: integrate the MAC endpoint support") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-2-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/dpaa2/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig +index d029b69c3f183..36280e5d99e1f 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig ++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig +@@ -34,6 +34,10 @@ config FSL_DPAA2_SWITCH + tristate "Freescale DPAA2 Ethernet Switch" + depends on BRIDGE || BRIDGE=n + depends on NET_SWITCHDEV ++ depends on FSL_MC_BUS && FSL_MC_DPIO ++ select PHYLINK ++ select PCS_LYNX ++ select FSL_XGMAC_MDIO + help + Driver for Freescale DPAA2 Ethernet Switch. This driver manages + switch objects discovered on the Freeescale MC bus. +-- +2.53.0 + diff --git a/queue-6.1/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch b/queue-6.1/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch new file mode 100644 index 0000000000..1ae090805c --- /dev/null +++ b/queue-6.1/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch @@ -0,0 +1,42 @@ +From d9d33e36fb8941d59cc2c49cef4a2382f7990a4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:07 +0000 +Subject: dpaa2: compile dpaa2 even CONFIG_FSL_DPAA2_ETH=n + +From: Cai Xinchen + +[ Upstream commit 97daf00745f7f9f261b0e91418de6e79d7826c36 ] + +CONFIG_FSL_DPAA2_ETH and CONFIG_FSL_DPAA2_SWITCH are not +associated, but the compilation of FSL_DPAA2_SWITCH depends on +the compilation of the dpaa2 folder. The files controlled by +CONFIG_FSL_DPAA2_SWITCH in the dpaa2 folder are not controlled +by CONFIG_FSL_DPAA2_ETH, except for the files controlled by +CONFIG_FSL_DPAA2_SWITCH. Therefore, removing the restriction will +not affect the compilation of the files in the directory. + +Fixes: f48298d3fbfaa ("staging: dpaa2-switch: move the driver out of staging") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-3-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/Makefile | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile +index de7b318422330..d0a259e47960f 100644 +--- a/drivers/net/ethernet/freescale/Makefile ++++ b/drivers/net/ethernet/freescale/Makefile +@@ -22,6 +22,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o + obj-$(CONFIG_FSL_FMAN) += fman/ + obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/ + +-obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/ +- ++obj-y += dpaa2/ + obj-y += enetc/ +-- +2.53.0 + diff --git a/queue-6.1/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch b/queue-6.1/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch new file mode 100644 index 0000000000..12dac7fe84 --- /dev/null +++ b/queue-6.1/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch @@ -0,0 +1,59 @@ +From cf794682814ee65ccb252e382106cc138dc8fea7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:40:54 -0700 +Subject: drbd: Balance RCU calls in drbd_adm_dump_devices() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bart Van Assche + +[ Upstream commit 2b31e86387e60b3689339f0f0fbb4d3623d9d494 ] + +Make drbd_adm_dump_devices() call rcu_read_lock() before +rcu_read_unlock() is called. This has been detected by the Clang +thread-safety analyzer. + +Tested-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Cc: Andreas Gruenbacher +Fixes: a55bbd375d18 ("drbd: Backport the "status" command") +Signed-off-by: Bart Van Assche +Link: https://patch.msgid.link/20260326214054.284593-1-bvanassche@acm.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_nl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index 249eba7d21c28..5f6afcbb996c8 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -3345,8 +3345,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + cb->args[0] = (long)resource; + } + } +@@ -3595,8 +3597,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + } + cb->args[0] = (long)resource; + } +-- +2.53.0 + diff --git a/queue-6.1/driver-core-device.h-remove-extern-from-function-pro.patch b/queue-6.1/driver-core-device.h-remove-extern-from-function-pro.patch new file mode 100644 index 0000000000..d64ef34474 --- /dev/null +++ b/queue-6.1/driver-core-device.h-remove-extern-from-function-pro.patch @@ -0,0 +1,39 @@ +From 9255fc50498dc1d7dd95c17daf6d59ca71f1695a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Mar 2023 13:27:06 +0100 +Subject: driver core: device.h: remove extern from function prototypes + +From: Greg Kroah-Hartman + +[ Upstream commit f43243c66e5e9ad839d235f82a58e73a7e7612af ] + +The kernel coding style does not require 'extern' in function prototypes +in .h files, so remove them from include/linux/device.h as they are not +needed. + +Acked-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/20230324122711.2664537-1-gregkh@linuxfoundation.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/device.h | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/include/linux/device.h b/include/linux/device.h +index 98e4a0d01e5a4..428c96ce6b4c4 100644 +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -1149,8 +1149,7 @@ void device_links_supplier_sync_state_pause(void); + void device_links_supplier_sync_state_resume(void); + void device_link_wait_removal(void); + +-extern __printf(3, 4) +-int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); ++__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); + + /* Create alias, so I can be autoloaded. */ + #define MODULE_ALIAS_CHARDEV(major,minor) \ +-- +2.53.0 + diff --git a/queue-6.1/driver-core-move-dev_err_probe-to-where-it-belogs.patch b/queue-6.1/driver-core-move-dev_err_probe-to-where-it-belogs.patch new file mode 100644 index 0000000000..95883212e8 --- /dev/null +++ b/queue-6.1/driver-core-move-dev_err_probe-to-where-it-belogs.patch @@ -0,0 +1,54 @@ +From 835fc447c2a594af6d1b73186164d930a025415f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Jul 2023 16:13:09 +0300 +Subject: driver core: Move dev_err_probe() to where it belogs + +From: Andy Shevchenko + +[ Upstream commit 9e0cace7a6254070159ebd86497eadc29ea307ca ] + +dev_err_probe() belongs to the printing API, hence +move the definition from device.h to dev_printk.h. + +There is no change to the callers at all, since: +1) implementation is located in the same core.c; +2) dev_printk.h is guaranteed to be included by device.h. + +Signed-off-by: Andy Shevchenko +Reviewed-by: Andi Shyti +Link: https://lore.kernel.org/r/20230721131309.16821-1-andriy.shevchenko@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/dev_printk.h | 2 ++ + include/linux/device.h | 2 -- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h +index 65eec5be8ccb9..ae80a303c216b 100644 +--- a/include/linux/dev_printk.h ++++ b/include/linux/dev_printk.h +@@ -275,4 +275,6 @@ do { \ + WARN_ONCE(condition, "%s %s: " format, \ + dev_driver_string(dev), dev_name(dev), ## arg) + ++__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); ++ + #endif /* _DEVICE_PRINTK_H_ */ +diff --git a/include/linux/device.h b/include/linux/device.h +index 428c96ce6b4c4..e642b366aa380 100644 +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -1149,8 +1149,6 @@ void device_links_supplier_sync_state_pause(void); + void device_links_supplier_sync_state_resume(void); + void device_link_wait_removal(void); + +-__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); +- + /* Create alias, so I can be autoloaded. */ + #define MODULE_ALIAS_CHARDEV(major,minor) \ + MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) +-- +2.53.0 + diff --git a/queue-6.1/drivers-spi-rockchip.c-remove-redundant-variable-sla.patch b/queue-6.1/drivers-spi-rockchip.c-remove-redundant-variable-sla.patch new file mode 100644 index 0000000000..473df542e6 --- /dev/null +++ b/queue-6.1/drivers-spi-rockchip.c-remove-redundant-variable-sla.patch @@ -0,0 +1,36 @@ +From 0d00f31f84dcfd9fd9be6f636940a296ad367f3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Feb 2023 14:33:34 +0800 +Subject: drivers/spi-rockchip.c : Remove redundant variable slave + +From: Lizhe + +[ Upstream commit 8c220e6c6da9c2f70a78ba8b3121893b3634a54c ] + +variable slave in spi_alloc_master() or spi_alloc_slave() +has been assigned. it is not necessary to be assigned again + +Signed-off-by: Lizhe +Link: https://lore.kernel.org/r/20230226063334.7489-1-sensor1010@163.com +Signed-off-by: Mark Brown +Stable-dep-of: b4683a239a40 ("spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ") +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rockchip.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index b460a393a7fea..b3247fad5f7e2 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -772,7 +772,6 @@ static int rockchip_spi_probe(struct platform_device *pdev) + platform_set_drvdata(pdev, ctlr); + + rs = spi_controller_get_devdata(ctlr); +- ctlr->slave = slave_mode; + + /* Get basic io resource and map it */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch b/queue-6.1/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch new file mode 100644 index 0000000000..5218344730 --- /dev/null +++ b/queue-6.1/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch @@ -0,0 +1,45 @@ +From 14bd7c8f6644b0d02d9c6883c8b3070120cc9889 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:41 +0200 +Subject: drm/amd/display: Allow DCE link encoder without AUX registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ] + +Allow constructing the DCE link encoder without DDC, +which means the AUX registers array will be NULL. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 87f30b101af62590faf6020d106da07efdda199b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index 85926d2300444..e089407e24531 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -992,7 +992,9 @@ void dce110_link_encoder_hw_init( + ASSERT(result == BP_RESULT_OK); + + } +- aux_initialize(enc110); ++ ++ if (enc110->aux_regs) ++ aux_initialize(enc110); + + /* reinitialize HPD. + * hpd_initialize() will pass DIG_FE id to HW context. +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch b/queue-6.1/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch new file mode 100644 index 0000000000..e96cffdc0c --- /dev/null +++ b/queue-6.1/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch @@ -0,0 +1,137 @@ +From 9ccdc7d44fa977b8c69e3b243353acd7799e1180 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:44 +0200 +Subject: drm/amd/display: Read EDID from VBIOS embedded panel info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ] + +Some board manufacturers hardcode the EDID for the embedded +panel in the VBIOS. This EDID should be used when the panel +doesn't have a DDC. + +For reference, see the legacy non-DC display code: +amdgpu_atombios_encoder_get_lcd_info() + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364) +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ + .../display/include/grph_object_ctrl_defs.h | 4 ++ + 2 files changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index 0f686e363d308..d8982aca8ef68 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1215,6 +1215,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( + return BP_RESULT_FAILURE; + } + ++static enum bp_result get_embedded_panel_extra_info( ++ struct bios_parser *bp, ++ struct embedded_panel_info *info, ++ const uint32_t table_offset) ++{ ++ uint8_t *record = bios_get_image(&bp->base, table_offset, 1); ++ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; ++ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ++ ++ while (*record != ATOM_RECORD_END_TYPE) { ++ switch (*record) { ++ case LCD_MODE_PATCH_RECORD_MODE_TYPE: ++ record += sizeof(ATOM_PATCH_RECORD_MODE); ++ break; ++ case LCD_RTS_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_RTS_RECORD); ++ break; ++ case LCD_CAP_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); ++ break; ++ case LCD_FAKE_EDID_PATCH_RECORD_TYPE: ++ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; ++ if (fake_edid_record->ucFakeEDIDLength) { ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength; ++ else ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength * 128; ++ ++ info->fake_edid = fake_edid_record->ucFakeEDIDString; ++ ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ info->fake_edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; ++ } ++ break; ++ case LCD_PANEL_RESOLUTION_RECORD_TYPE: ++ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; ++ info->panel_width_mm = panel_res_record->usHSize; ++ info->panel_height_mm = panel_res_record->usVSize; ++ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); ++ break; ++ default: ++ return BP_RESULT_BADBIOSTABLE; ++ } ++ } ++ ++ return BP_RESULT_OK; ++} ++ + static enum bp_result get_embedded_panel_info_v1_2( + struct bios_parser *bp, + struct embedded_panel_info *info) +@@ -1331,6 +1385,10 @@ static enum bp_result get_embedded_panel_info_v1_2( + if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) + info->lcd_timing.misc_info.API_ENABLED = true; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +@@ -1456,6 +1514,10 @@ static enum bp_result get_embedded_panel_info_v1_3( + (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & + lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +index 813463ffe15c5..8e776c90d21bf 100644 +--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h ++++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +@@ -153,6 +153,10 @@ struct embedded_panel_info { + uint32_t drr_enabled; + uint32_t min_drr_refresh_rate; + bool realtek_eDPToLVDS; ++ uint16_t panel_width_mm; ++ uint16_t panel_height_mm; ++ uint16_t fake_edid_size; ++ const uint8_t *fake_edid; + }; + + struct dc_firmware_info { +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch b/queue-6.1/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch new file mode 100644 index 0000000000..6892960b3b --- /dev/null +++ b/queue-6.1/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch @@ -0,0 +1,38 @@ +From aa6cfaf961f0829886a9e51aa4bc6e3dd5351cd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:03 +0200 +Subject: drm/amd/pm/ci: Clear EnabledForActivity field for memory levels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 5facfd4c4c67e8500116ffec0d9da35d92b9c787 ] + +Follow what radeon did and what amdgpu does for other GPUs with SMU7. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index a43753f11ee96..0839be4dc38c7 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1218,7 +1218,7 @@ static int ci_populate_single_memory_level( + } + + memory_level->EnabledForThrottle = 1; +- memory_level->EnabledForActivity = 1; ++ memory_level->EnabledForActivity = 0; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; + memory_level->VoltageDownH = 0; +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch b/queue-6.1/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch new file mode 100644 index 0000000000..170ba0ad82 --- /dev/null +++ b/queue-6.1/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch @@ -0,0 +1,67 @@ +From b8d3c9d2b81a3a13e5c3131ca3e755575cccb07f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:59 +0200 +Subject: drm/amd/pm/ci: Disable MCLK DPM on problematic CI ASICs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9851f29cb06c09f7dad3867d8b0feec3fc71b6c8 ] + +There are two known cases where MCLK DPM can causes issues: + +Radeon R9 M380 found in iMac computers from 2015. +The SMU in this GPU just hangs as soon as we send it the +PPSMC_MSG_MCLKDPM_Enable command, even when MCLK switching is +disabled, and even when we only populate one MCLK DPM level. +Apply workaround to all devices with the same subsystem ID. + +Radeon R7 260X due to old memory controller microcode. +We only flash the MC ucode when it isn't set up by the VBIOS, +therefore there is no way to make sure that it has the correct +ucode version. + +I verified that this patch fixes the SMU hang on the R9 M380 +which would previously fail to boot. This also fixes the UVD +initialization error on that GPU which happened because the +SMU couldn't ungate the UVD after it hung. + +Fixes: 86457c3b21cb ("drm/amd/powerplay: Add support for CI asics to hwmgr") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +index f2cef0930aa96..997435a50f21e 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) + PP_GFXOFF_MASK); + hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; ++ switch (hwmgr->chip_id) { ++ case CHIP_BONAIRE: ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM ++ * R7 260X cards with old MC ucode: MCLK DPM is unstable ++ */ ++ if (adev->pdev->subsystem_vendor == 0x106B || ++ adev->pdev->device == 0x6658) { ++ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); ++ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; ++ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; ++ } ++ break; ++ default: ++ break; ++ } + smu7_init_function_pointers(hwmgr); + break; + case AMDGPU_FAMILY_CZ: +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch b/queue-6.1/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch new file mode 100644 index 0000000000..0da0fb8066 --- /dev/null +++ b/queue-6.1/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch @@ -0,0 +1,48 @@ +From c569866341246de00e389cb0f862129bc9dd1dff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:04 +0200 +Subject: drm/amd/pm/ci: Fill DW8 fields from SMC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit baf28ec5795c077406d6f52b8ad39e614153bce6 ] + +In ci_populate_dw8() we currently just read a value from the SMU +and then throw it away. Instead of throwing away the value, +we should use it to fill other fields in DW8 (like radeon). + +Otherwise the value of the other fiels is just cleared when +we copy this data to the SMU later. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 0839be4dc38c7..0b22563450a83 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -544,12 +544,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) + { + struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); + const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; +- uint32_t temp; + + if (ci_read_smc_sram_dword(hwmgr, + fuse_table_offset + + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), +- (uint32_t *)&temp, SMC_RAM_END)) ++ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) + PP_ASSERT_WITH_CODE(false, + "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", + return -EINVAL); +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch b/queue-6.1/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch new file mode 100644 index 0000000000..b04a92bacb --- /dev/null +++ b/queue-6.1/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch @@ -0,0 +1,41 @@ +From 6c270cafbf36522b856d3807b1ba0d7b532a4588 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:02 +0200 +Subject: drm/amd/pm/ci: Fix powertune defaults for Hawaii 0x67B0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit d784759c07924280f3c313f205fc48eb62d7cb71 ] + +There is no AMD GPU with the ID 0x66B0, this looks like a typo. +It should be 0x67B0 which is actually part of the PCI ID list, +and should use the Hawaii XT powertune defaults according to +the old radeon driver. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 20419da731993..a43753f11ee96 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -246,7 +246,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) + smu_data->power_tune_defaults = &defaults_hawaii_pro; + break; + case 0x67B8: +- case 0x66B0: ++ case 0x67B0: + smu_data->power_tune_defaults = &defaults_hawaii_xt; + break; + case 0x6640: +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch b/queue-6.1/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch new file mode 100644 index 0000000000..79ae53b1d5 --- /dev/null +++ b/queue-6.1/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch @@ -0,0 +1,47 @@ +From 7aba843a4d6d95f21a469530b6fe1d177ffeed15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:58 +0200 +Subject: drm/amd/pm/ci: Use highest MCLK on CI when MCLK DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 894f0d34d66cb47fe718fe2ae5c18729d22c5218 ] + +When MCLK DPM is disabled for any reason, populate the MCLK +table with the highest MCLK DPM level, so that the ASIC can +use the highest possible memory clock to get good performance +even when MCLK DPM is disabled. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 9b8974e89145d..20419da731993 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1323,6 +1323,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) + return result; + } + ++ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { ++ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ ++ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { ++ levels[i] = levels[dpm_table->mclk_table.count - 1]; ++ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; ++ } ++ } ++ + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; + + dev_id = adev->pdev->device; +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch b/queue-6.1/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch new file mode 100644 index 0000000000..0b731cb278 --- /dev/null +++ b/queue-6.1/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch @@ -0,0 +1,129 @@ +From b1d9e2f995ea231713a021cd23fe062ecc47d8d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:05 +0200 +Subject: drm/amd/pm/smu7: Add SCLK cap for quirky Hawaii board +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 4724bc5b8d78c34b993594f9406135408ccb312a ] + +On a specific Radeon R9 390X board, the GPU can "randomly" hang +while gaming. Initially I thought this was a RADV bug and tried +to work around this in Mesa: +commit 8ea08747b86b ("radv: Mitigate GPU hang on Hawaii in Dota 2 and RotTR") + +However, I got some feedback from other users who are reporting +that the above mitigation causes a significant performance +regression for them, and they didn't experience the hang on their +GPU in the first place. + +After some further investigation, it turns out that the problem +is that the highest SCLK DPM level on this board isn't stable. +Lowering SCLK to 1040 MHz (from 1070 MHz) works around the issue, +and has a negligible impact on performance compared to the Mesa +patch. (Note that increasing the voltage can also work around it, +but we felt that lowering the SCLK is the safer option.) + +To solve the above issue, add an "sclk_cap" field to smu7_hwmgr +and set this field for the affected board. The capped SCLK value +correctly appears on the sysfs interface and shows up in GUI +tools such as LACT. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 30 ++++++++++++++++--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h | 1 + + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index f9454e43e5c63..132669fb39860 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -788,7 +788,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.vddc_dependency_on_mclk; + struct phm_cac_leakage_table *std_voltage_table = + hwmgr->dyn_state.cac_leakage_table; +- uint32_t i; ++ uint32_t i, clk; + + PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, + "SCLK dependency table is missing. This table is mandatory", return -EINVAL); +@@ -805,10 +805,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + data->dpm_table.sclk_table.count = 0; + + for (i = 0; i < allowed_vdd_sclk_table->count; i++) { ++ clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); ++ + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != +- allowed_vdd_sclk_table->entries[i].clk) { ++ clk) { + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = +- allowed_vdd_sclk_table->entries[i].clk; ++ clk; + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; + data->dpm_table.sclk_table.count++; + } +@@ -3019,6 +3021,25 @@ static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr * + return 0; + } + ++static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) ++{ ++ struct amdgpu_device *adev = hwmgr->adev; ++ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); ++ ++ data->sclk_cap = 0xffffffff; ++ ++ if (hwmgr->od_enabled) ++ return; ++ ++ /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ ++ if (adev->pdev->device == 0x67B0 && ++ adev->pdev->subsystem_vendor == 0x1043) ++ data->sclk_cap = 104000; /* 1040 MHz */ ++ ++ if (data->sclk_cap != 0xffffffff) ++ dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -3030,6 +3051,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + return -ENOMEM; + + hwmgr->backend = data; ++ smu7_set_sclk_cap(hwmgr); + smu7_patch_voltage_workaround(hwmgr); + smu7_init_dpm_defaults(hwmgr); + +@@ -3916,7 +3938,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, + + /* Performance levels are arranged from low to high. */ + performance_level->memory_clock = memory_clock; +- performance_level->engine_clock = engine_clock; ++ performance_level->engine_clock = min(engine_clock, data->sclk_cap); + + pcie_gen_from_bios = visland_clk_info->ucPCIEGen; + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +index d9e8b386bd4d3..66adabeab6a3a 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +@@ -234,6 +234,7 @@ struct smu7_hwmgr { + uint32_t pcie_gen_cap; + uint32_t pcie_lane_cap; + uint32_t pcie_spc_cap; ++ uint32_t sclk_cap; + struct smu7_leakage_voltage vddc_leakage; + struct smu7_leakage_voltage vddci_leakage; + struct smu7_leakage_voltage vddcgfx_leakage; +-- +2.53.0 + diff --git a/queue-6.1/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch b/queue-6.1/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch new file mode 100644 index 0000000000..884149f20b --- /dev/null +++ b/queue-6.1/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch @@ -0,0 +1,192 @@ +From 745e2a30eba2f05f58c61f0526dc70f92d85d449 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:00 +0200 +Subject: drm/amd/pm/smu7: Fix SMU7 voltage dependency on display clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 0138610c14130425be53423b35336561829965e0 ] + +The DCE (display controller engine) requires a minimum voltage +in order to function correctly, depending on which clock level +it currently uses. + +Add a new table that contains display clock frequency levels +and the corresponding required voltages. The clock frequency +levels are taken from DC (and the old radeon driver's voltage +dependency table for CI in cases where its values were lower). +The voltage levels are taken from the following function: +phm_initializa_dynamic_state_adjustment_rule_settings(). +Furthermore, in case of CI, call smu7_patch_vddc() on the new +table to account for leakage voltage (like in radeon). + +Use the display clock value from amd_pp_display_configuration +to look up the voltage level needed by the DCE. Send the +voltage to the SMU via the PPSMC_MSG_VddC_Request command. + +The previous implementation of this feature was non-functional +because it relied on a "dal_power_level" field which was never +assigned; and it was not at all implemented for CI ASICs. + +I verified this on a Radeon R9 M380 which previously booted to +a black screen with DC enabled (default since Linux 6.19), but +now works correctly. + +Fixes: 599a7e9fe1b6 ("drm/amd/powerplay: implement smu7 hwmgr to manager asics with smu ip version 7.") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 88 ++++++++++++++++++- + drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h | 1 + + 2 files changed, 86 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index d13ab986a5c20..f9454e43e5c63 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -2815,6 +2815,10 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) + if (tmp) + return -EINVAL; + ++ tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ if (tmp) ++ return -EINVAL; ++ + tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); + if (tmp) + return -EINVAL; +@@ -2898,6 +2902,8 @@ static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) + { + kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); + hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; ++ kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; + kfree(hwmgr->backend); + hwmgr->backend = NULL; + +@@ -2968,6 +2974,51 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) + return ret; + } + ++static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) ++{ ++ struct phm_clock_voltage_dependency_table *table; ++ ++ if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) ++ return 0; ++ ++ table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); ++ if (!table) ++ return -ENOMEM; ++ ++ if (hwmgr->chip_id >= CHIP_POLARIS10) { ++ table->entries[0].clk = 38918; ++ table->entries[1].clk = 45900; ++ table->entries[2].clk = 66700; ++ table->entries[3].clk = 113200; ++ ++ table->entries[0].v = 700; ++ table->entries[1].v = 740; ++ table->entries[2].v = 800; ++ table->entries[3].v = 900; ++ } else { ++ if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { ++ table->entries[0].clk = 35200; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 46700; ++ table->entries[3].clk = 64300; ++ } else { ++ table->entries[0].clk = 0; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 54000; ++ table->entries[3].clk = 62500; ++ } ++ ++ table->entries[0].v = 0; ++ table->entries[1].v = 720; ++ table->entries[2].v = 810; ++ table->entries[3].v = 900; ++ } ++ ++ table->count = 4; ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = table; ++ return 0; ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -2996,6 +3047,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + smu7_get_elb_voltages(hwmgr); + } + ++ result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); ++ if (result) ++ goto fail; ++ + if (hwmgr->pp_table_version == PP_TABLE_V1) { + smu7_complete_dependency_tables(hwmgr); + smu7_set_private_data_based_on_pptable_v1(hwmgr); +@@ -3092,13 +3147,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) + return 0; + } + ++static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) ++{ ++ const struct amd_pp_display_configuration *cfg = hwmgr->display_config; ++ const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = ++ hwmgr->dyn_state.vddc_dependency_on_display_clock; ++ uint32_t i; ++ ++ if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || ++ !cfg || !cfg->num_display || !cfg->display_clk) ++ return 0; ++ ++ /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ ++ for (i = 1; i < vddc_dep_on_dispclk->count; ++i) ++ if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) ++ return vddc_dep_on_dispclk->entries[i].v; ++ ++ return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; ++} ++ ++static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) ++{ ++ uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_VddC_Request, ++ req_vddc * VOLTAGE_SCALE, ++ NULL); ++} ++ + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) + { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + +- if (hwmgr->pp_table_version == PP_TABLE_V1) +- phm_apply_dal_min_voltage_request(hwmgr); +-/* TO DO for v0 iceland and Ci*/ ++ smu7_apply_minimum_dce_voltage_request(hwmgr); + + if (!data->sclk_dpm_key_disabled) { + if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) +diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +index ec10643edea3e..dbd2ab50d150e 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +@@ -634,6 +634,7 @@ struct phm_dynamic_state_info { + struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; ++ struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; + struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; + struct phm_clock_array *valid_sclk_values; + struct phm_clock_array *valid_mclk_values; +-- +2.53.0 + diff --git a/queue-6.1/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch b/queue-6.1/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch new file mode 100644 index 0000000000..c4afed3e9a --- /dev/null +++ b/queue-6.1/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch @@ -0,0 +1,54 @@ +From 044f3a4ae2e041a393300ea5acbd2bb4c35d1162 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 19:29:54 +0530 +Subject: drm/amdgpu: Add default case in DVI mode validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit e6020a55b8e364d15eac27f9c788e13114eec6b7 ] + +amdgpu_connector_dvi_mode_valid() assigns max_digital_pixel_clock_khz +based on connector_object_id using a switch statement that lacks a +default case. + +In practice this code path should never be hit because the existing +cases already cover all digital connector types that this function is +used for. This is also legacy display code which is not used for new +hardware. + +Add a default case returning MODE_BAD to make the switch exhaustive and +silence the static analyzer smatch error. The new branch is effectively +defensive and should never be reached during normal operation. + +Fixes: 585b2f685c56 ("drm/amdgpu: Respect max pixel clock for HDMI and DVI-D (v2)") +Cc: Dan Carpenter +Cc: Timur Kristóf +Cc: Alex Deucher +Cc: Christian König +Signed-off-by: Srinivasan Shanmugam +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +index 02a731fdb2263..0661dcef14fb9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +@@ -1217,6 +1217,8 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector + case CONNECTOR_OBJECT_ID_HDMI_TYPE_B: + max_digital_pixel_clock_khz = max_dvi_single_link_pixel_clock * 2; + break; ++ default: ++ return MODE_BAD; + } + + /* When the display EDID claims that it's an HDMI display, +-- +2.53.0 + diff --git a/queue-6.1/drm-amdgpu-fix-spelling-typos.patch b/queue-6.1/drm-amdgpu-fix-spelling-typos.patch new file mode 100644 index 0000000000..5f9bef43de --- /dev/null +++ b/queue-6.1/drm-amdgpu-fix-spelling-typos.patch @@ -0,0 +1,103 @@ +From 6f9e9a88a5a293961cc1324b8a740154590cbf6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 00:05:04 -0500 +Subject: drm/amdgpu: fix spelling typos + +From: Alexandre Demers + +[ Upstream commit ce43abd7ec9464cf954f90e1c69e11768b02fa0a ] + +Found some typos while exploring amdgpu code. + +Signed-off-by: Alexandre Demers +Signed-off-by: Alex Deucher +Stable-dep-of: 13e4cf116dbf ("drm/amdgpu/uvd3.1: Don't validate the firmware when already validated") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 6 +++--- + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 3 ++- + drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | 2 +- + 4 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index 3a1576e2f8e3b..c76f1e1ee395c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -256,7 +256,7 @@ void amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc + * @adev: amdgpu device structure holding all necessary information + * @mc: memory controller structure holding memory information + * +- * Function will place try to place GART before or after VRAM. ++ * Function will try to place GART before or after VRAM. + * If GART size is bigger than space left then we ajust GART size. + * Thus function will never fails. + */ +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index e458e0d5801b0..fbfed90503868 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -98,7 +98,7 @@ static void uvd_v3_1_ring_emit_ib(struct amdgpu_ring *ring, + } + + /** +- * uvd_v3_1_ring_emit_fence - emit an fence & trap command ++ * uvd_v3_1_ring_emit_fence - emit a fence & trap command + * + * @ring: amdgpu_ring pointer + * @addr: address +@@ -242,7 +242,7 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + +- /* programm the VCPU memory controller bits 0-27 */ ++ /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; + WREG32(mmUVD_VCPU_CACHE_OFFSET0, addr); +@@ -416,7 +416,7 @@ static int uvd_v3_1_start(struct amdgpu_device *adev) + /* Set the write pointer delay */ + WREG32(mmUVD_RBC_RB_WPTR_CNTL, 0); + +- /* programm the 4GB memory segment for rptr and ring buffer */ ++ /* Program the 4GB memory segment for rptr and ring buffer */ + WREG32(mmUVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) | + (0x7 << 16) | (0x1 << 31)); + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +index c108b83817951..01d8e7d2caf97 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +@@ -298,7 +298,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) + /* enable VCPU clock */ + WREG32(mmUVD_VCPU_CNTL, 1 << 9); + +- /* disable interupt */ ++ /* disable interrupt */ + WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1)); + + #ifdef __BIG_ENDIAN +@@ -308,6 +308,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) + #endif + WREG32(mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl); + WREG32(mmUVD_MP_SWAP_CNTL, mp_swap_cntl); ++ + /* initialize UVD memory controller */ + WREG32(mmUVD_LMI_CTRL, 0x203108); + +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +index 67eb01fef789b..479eb9382c77e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +@@ -278,7 +278,7 @@ static int vce_v2_0_stop(struct amdgpu_device *adev) + int status; + + if (vce_v2_0_lmi_clean(adev)) { +- DRM_INFO("vce is not idle \n"); ++ DRM_INFO("VCE is not idle \n"); + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.1/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch b/queue-6.1/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch new file mode 100644 index 0000000000..d0909326de --- /dev/null +++ b/queue-6.1/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch @@ -0,0 +1,40 @@ +From d351e30261ba3bef4f7c0e24d294f453c479ed75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:18:28 -0500 +Subject: drm/amdgpu/gfx10: look at the right prop for gfx queue priority +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit 355d96cdec5c61fd83f7eb54f1a28e38809645d6 ] + +Look at hqd_queue_priority rather than hqd_pipe_priority. +In practice, it didn't matter as both were always set for +kernel queues, but that will change in the future. + +Fixes: b07d1d73b09e ("drm/amd/amdgpu: Enable high priority gfx queue") +Reviewed-by:Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 48462beddccf0..8953f093b9617 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -6411,7 +6411,7 @@ static void gfx_v10_0_gfx_mqd_set_priority(struct amdgpu_device *adev, + /* set up default queue priority level + * 0x0 = low priority, 0x1 = high priority + */ +- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) ++ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) + priority = 1; + + tmp = RREG32_SOC15(GC, 0, mmCP_GFX_HQD_QUEUE_PRIORITY); +-- +2.53.0 + diff --git a/queue-6.1/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch b/queue-6.1/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch new file mode 100644 index 0000000000..3c1c3a32e5 --- /dev/null +++ b/queue-6.1/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch @@ -0,0 +1,146 @@ +From 2a1fbf482294fd7e9a32048be834ae886290de18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:33 +0200 +Subject: drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ] + +This commit fixes amdgpu to work on the Radeon HD 7870 XT +which has never worked with the Linux open source drivers before. + +Some boards have "harvested" chips, meaning that some parts of +the chip are disabled and fused, and it's sold for cheaper and +under a different marketing name. +On a harvested chip, any of the following can be disabled: +- CUs (Compute Units) +- RBs (Render Backend, aka. ROP) +- Memory channels (ie. the chip has a lower bandwidth) +- TCCs (ie. less L2 cache) + +Handle chips with harvested TCCs by patching the registers +that configure how TCCs are mapped. + +If some TCCs are disabled, we need to make sure that +the disabled TCCs are not used, and the remaining TCCs +are used optimally. + +TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. + +Note that the TCC configuration is highly relevant to performance. +Suboptimal configuration (eg. CHAN_STEER=0) can significantly +reduce gaming performance. + +For optimal performance: +- Rely on the CHAN_STEER from the golden registers table, + only skip disabled TCCs but keep the mapping order. +- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, + which performs better than using the same TCC twice. + +v2: +- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs. + +Link: https://bugs.freedesktop.org/show_bug.cgi?id=60879 +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2664 +Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 00218d15528fab9f6b31241fe5904eea4fcaa30d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index 204b246f0e3f9..09cf6604e3d2c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -1568,6 +1568,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) + mutex_unlock(&adev->grbm_idx_mutex); + } + ++/** ++ * gfx_v6_0_setup_tcc() - setup which TCCs are used ++ * ++ * @adev: amdgpu_device pointer ++ * ++ * Verify whether the current GPU has any TCCs disabled, ++ * which can happen when the GPU is harvested and some ++ * memory channels are disabled, reducing the memory bus width. ++ * For example, on the Radeon HD 7870 XT (Tahiti LE). ++ * ++ * If some TCCs are disabled, we need to make sure that ++ * the disabled TCCs are not used, and the remaining TCCs ++ * are used optimally. ++ * ++ * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. ++ * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. ++ * ++ * For optimal performance: ++ * - Rely on the CHAN_STEER from the golden registers table, ++ * only skip disabled TCCs but keep the mapping order. ++ * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, ++ * which performs better than using the same TCC twice. ++ */ ++static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) ++{ ++ u32 i, tcc, tcp_addr_config, num_active_tcc = 0; ++ u64 chan_steer, patched_chan_steer = 0; ++ const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; ++ const u32 dis_tcc_mask = ++ amdgpu_gfx_create_bitmask(num_max_tcc) & ++ (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), ++ CGTS_TCC_DISABLE, TCC_DISABLE) | ++ REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), ++ CGTS_USER_TCC_DISABLE, TCC_DISABLE)); ++ ++ /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ ++ if (!dis_tcc_mask) ++ return; ++ ++ /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ ++ chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); ++ ++ /* Patch the TCP to TCC mapping to skip disabled TCCs */ ++ for (i = 0; i < num_max_tcc; ++i) { ++ tcc = (chan_steer >> (u64)(4 * i)) & 0xf; ++ ++ if (!((1 << tcc) & dis_tcc_mask)) { ++ /* Copy enabled TCC indices to the patched register value. */ ++ patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); ++ ++num_active_tcc; ++ } ++ } ++ ++ WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); ++ ++ /* Patch number of TCCs used by TCPs */ ++ tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), ++ TCP_ADDR_CONFIG, NUM_TCC_BANKS, ++ num_active_tcc - 1); ++ ++ WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); ++ WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); ++ WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); ++} ++ + static void gfx_v6_0_config_init(struct amdgpu_device *adev) + { + adev->gfx.config.double_offchip_lds_buf = 0; +@@ -1726,6 +1791,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) + gfx_v6_0_tiling_mode_table_init(adev); + + gfx_v6_0_setup_rb(adev); ++ gfx_v6_0_setup_tcc(adev); + + gfx_v6_0_setup_spi(adev); + +-- +2.53.0 + diff --git a/queue-6.1/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch b/queue-6.1/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch new file mode 100644 index 0000000000..edd97b8598 --- /dev/null +++ b/queue-6.1/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch @@ -0,0 +1,65 @@ +From 8563dfcbb93713e48746a9a11a6db663d438231f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:31 +0200 +Subject: drm/amdgpu/uvd3.1: Don't validate the firmware when already validated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ] + +UVD 3.1 firmware validation seems to always fail after +attempting it when it had already been validated. +(This works similarly with the VCE 1.0 as well.) + +Don't attempt repeating the validation when it's already done. + +This caused issues in situations when the system isn't able +to suspend the GPU properly and so the GPU isn't actually +powered down. Then amdgpu would fail when calling the IP +block resume function. + +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2887 +Fixes: bb7978111dd3 ("drm/amdgpu: fix SI UVD firmware validate resume fail") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 889a2cfd889c4a4dd9d0c89ce9a8e60b78be71dd) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index fbfed90503868..3a27bed57b4ff 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + ++ /* When the keyselect is already set, don't perturb it. */ ++ if (RREG32(mmUVD_FW_START)) ++ return; ++ + /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; +@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) + int i; + uint32_t keysel = adev->uvd.keyselect; + ++ if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { ++ dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", ++ RREG32(mmUVD_FW_START), adev->uvd.keyselect); ++ return 0; ++ } ++ + WREG32(mmUVD_FW_START, keysel); + + for (i = 0; i < 10; ++i) { +-- +2.53.0 + diff --git a/queue-6.1/drm-i915-constify-watermark-state-checker.patch b/queue-6.1/drm-i915-constify-watermark-state-checker.patch new file mode 100644 index 0000000000..f7f45bf5fe --- /dev/null +++ b/queue-6.1/drm-i915-constify-watermark-state-checker.patch @@ -0,0 +1,54 @@ +From 7e3f0ade06abe1af67f93662ae471eb1c7c52bfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Oct 2023 18:56:00 +0300 +Subject: drm/i915: Constify watermark state checker +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 487a2db8bc4eb79c53c9ff8fca65a7fc8350df6c ] + +The skl+ wm state checker has no reason to modify the crtc state, +so make it const. + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20231004155607.7719-6-ville.syrjala@linux.intel.com +Reviewed-by: Jani Nikula +Stable-dep-of: a97c88a176b6 ("drm/i915/wm: Verify the correct plane DDB entry") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 2 +- + drivers/gpu/drm/i915/display/skl_watermark.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index a7adf02476f6a..b6951881c0570 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3014,7 +3014,7 @@ void skl_wm_sanitize(struct drm_i915_private *i915) + } + + void intel_wm_state_verify(struct intel_crtc *crtc, +- struct intel_crtc_state *new_crtc_state) ++ const struct intel_crtc_state *new_crtc_state) + { + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct skl_hw_state { +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h +index 7a5a4e67cd738..d1a1fe322e869 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.h ++++ b/drivers/gpu/drm/i915/display/skl_watermark.h +@@ -42,7 +42,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *i915); + void skl_wm_sanitize(struct drm_i915_private *i915); + + void intel_wm_state_verify(struct intel_crtc *crtc, +- struct intel_crtc_state *new_crtc_state); ++ const struct intel_crtc_state *new_crtc_state); + + void skl_watermark_ipc_init(struct drm_i915_private *i915); + void skl_watermark_ipc_update(struct drm_i915_private *i915); +-- +2.53.0 + diff --git a/queue-6.1/drm-i915-extract-intel_dbuf_mdclk_cdclk_ratio_update.patch b/queue-6.1/drm-i915-extract-intel_dbuf_mdclk_cdclk_ratio_update.patch new file mode 100644 index 0000000000..179990010d --- /dev/null +++ b/queue-6.1/drm-i915-extract-intel_dbuf_mdclk_cdclk_ratio_update.patch @@ -0,0 +1,101 @@ +From b3badbf02af7e3862af06633c57877a9f31e8c9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Mar 2024 13:36:35 -0300 +Subject: drm/i915: Extract intel_dbuf_mdclk_cdclk_ratio_update() + +From: Gustavo Sousa + +[ Upstream commit 66a0e0681392420b326f00ba732e6bda099eda29 ] + +As of Xe2LPD, it is now possible to select the source of the MDCLK +as either the CD2XCLK or the CDCLK PLL. + +Previous display IPs were hardcoded to use the CD2XCLK. For those, the +ratio between MDCLK and CDCLK remained constant, namely 2. For Xe2LPD, +when we select the CDCLK PLL as the source, the ratio will vary +according to the squashing configuration (since the cd2x divisor is +fixed for all supported configurations). + +To help the transition to supporting changes in the ratio, extract the +function intel_dbuf_mdclk_cdclk_ratio_update() from the existing logic +and call it using 2 as hardcoded ratio. Upcoming changes will use that +function for updates in the ratio due to CDCLK changes. + +Bspec: 50057, 69445, 49213, 68868 +Reviewed-by: Matt Roper +Signed-off-by: Gustavo Sousa +Link: https://patchwork.freedesktop.org/patch/msgid/20240312163639.172321-5-gustavo.sousa@intel.com +Signed-off-by: Lucas De Marchi +Stable-dep-of: a97c88a176b6 ("drm/i915/wm: Verify the correct plane DDB entry") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 30 +++++++++++++------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index b6951881c0570..e553192e12b76 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3346,6 +3346,21 @@ int intel_dbuf_init(struct drm_i915_private *i915) + return 0; + } + ++static void intel_dbuf_mdclk_cdclk_ratio_update(struct drm_i915_private *i915, ++ u8 ratio, ++ bool joined_mbus) ++{ ++ enum dbuf_slice slice; ++ ++ if (joined_mbus) ++ ratio *= 2; ++ ++ for_each_dbuf_slice(i915, slice) ++ intel_de_rmw(i915, DBUF_CTL_S(slice), ++ DBUF_MIN_TRACKER_STATE_SERVICE_MASK, ++ DBUF_MIN_TRACKER_STATE_SERVICE(ratio - 1)); ++} ++ + /* + * Configure MBUS_CTL and all DBUF_CTL_S of each slice to join_mbus state before + * update the request state of all DBUS slices. +@@ -3353,8 +3368,7 @@ int intel_dbuf_init(struct drm_i915_private *i915) + static void update_mbus_pre_enable(struct intel_atomic_state *state) + { + struct drm_i915_private *i915 = to_i915(state->base.dev); +- u32 mbus_ctl, dbuf_min_tracker_val; +- enum dbuf_slice slice; ++ u32 mbus_ctl; + const struct intel_dbuf_state *dbuf_state = + intel_atomic_get_new_dbuf_state(state); + +@@ -3365,24 +3379,18 @@ static void update_mbus_pre_enable(struct intel_atomic_state *state) + * TODO: Implement vblank synchronized MBUS joining changes. + * Must be properly coordinated with dbuf reprogramming. + */ +- if (dbuf_state->joined_mbus) { ++ if (dbuf_state->joined_mbus) + mbus_ctl = MBUS_HASHING_MODE_1x4 | MBUS_JOIN | + MBUS_JOIN_PIPE_SELECT_NONE; +- dbuf_min_tracker_val = DBUF_MIN_TRACKER_STATE_SERVICE(3); +- } else { ++ else + mbus_ctl = MBUS_HASHING_MODE_2x2 | + MBUS_JOIN_PIPE_SELECT_NONE; +- dbuf_min_tracker_val = DBUF_MIN_TRACKER_STATE_SERVICE(1); +- } + + intel_de_rmw(i915, MBUS_CTL, + MBUS_HASHING_MODE_MASK | MBUS_JOIN | + MBUS_JOIN_PIPE_SELECT_MASK, mbus_ctl); + +- for_each_dbuf_slice(i915, slice) +- intel_de_rmw(i915, DBUF_CTL_S(slice), +- DBUF_MIN_TRACKER_STATE_SERVICE_MASK, +- dbuf_min_tracker_val); ++ intel_dbuf_mdclk_cdclk_ratio_update(i915, 2, dbuf_state->joined_mbus); + } + + void intel_dbuf_pre_plane_update(struct intel_atomic_state *state) +-- +2.53.0 + diff --git a/queue-6.1/drm-i915-loop-over-all-active-pipes-in-intel_mbus_db.patch b/queue-6.1/drm-i915-loop-over-all-active-pipes-in-intel_mbus_db.patch new file mode 100644 index 0000000000..0bfdd921f0 --- /dev/null +++ b/queue-6.1/drm-i915-loop-over-all-active-pipes-in-intel_mbus_db.patch @@ -0,0 +1,58 @@ +From 2b61f923e61e615c576107d97b6573ece300987d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Apr 2024 18:50:07 +0300 +Subject: drm/i915: Loop over all active pipes in intel_mbus_dbox_update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Stanislav Lisovskiy + +[ Upstream commit e8333ab22cd8c750b7c14d3da7c0eef3ba85527f ] + +We need to loop through all active pipes, not just the ones, that +are in current state, because disabling and enabling even a particular +pipe affects credits in another one. + +Reviewed-by: Uma Shankar +Signed-off-by: Stanislav Lisovskiy +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20240402155016.13733-6-ville.syrjala@linux.intel.com +Stable-dep-of: a97c88a176b6 ("drm/i915/wm: Verify the correct plane DDB entry") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index e553192e12b76..2a60aa3fedf82 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3456,10 +3456,8 @@ void intel_mbus_dbox_update(struct intel_atomic_state *state) + { + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state; +- const struct intel_crtc_state *new_crtc_state; + const struct intel_crtc *crtc; + u32 val = 0; +- int i; + + if (DISPLAY_VER(i915) < 11) + return; +@@ -3503,12 +3501,9 @@ void intel_mbus_dbox_update(struct intel_atomic_state *state) + val |= MBUS_DBOX_B_CREDIT(8); + } + +- for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { ++ for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, new_dbuf_state->active_pipes) { + u32 pipe_val = val; + +- if (!new_crtc_state->hw.active) +- continue; +- + if (DISPLAY_VER(i915) >= 14) { + if (xelpdp_is_only_pipe_per_dbuf_bank(crtc->pipe, + new_dbuf_state->active_pipes)) +-- +2.53.0 + diff --git a/queue-6.1/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch b/queue-6.1/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch new file mode 100644 index 0000000000..df70c421e5 --- /dev/null +++ b/queue-6.1/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch @@ -0,0 +1,44 @@ +From b47303bcb0f9f228234f0aa0a615a4e72f8fcad8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:48:38 +0200 +Subject: drm/i915/wm: Verify the correct plane DDB entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit a97c88a176b6b8d116f4d3f508f3bd02bc77b462 ] + +Actually verify the DDB entry for the plane we're looking +at instead of always verifying the cursor DDB. + +Fixes: 7d4561722c3b ("drm/i915: Tweak plane ddb allocation tracking") +Signed-off-by: Ville Syrjälä +Link: https://patch.msgid.link/20260324134843.2364-5-ville.syrjala@linux.intel.com +Reviewed-by: Vinod Govindapillai +(cherry picked from commit f002f7c7439de18117a31ca84dc87a59719c3dd6) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index 2a60aa3fedf82..965d8e762883f 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3118,8 +3118,8 @@ void intel_wm_state_verify(struct intel_crtc *crtc, + } + + /* DDB */ +- hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; +- sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; ++ hw_ddb_entry = &hw->ddb[plane->id]; ++ sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[plane->id]; + + if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { + drm_err(&i915->drm, +-- +2.53.0 + diff --git a/queue-6.1/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch b/queue-6.1/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch new file mode 100644 index 0000000000..c892bbeca3 --- /dev/null +++ b/queue-6.1/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch @@ -0,0 +1,60 @@ +From 749fcfcdc27477025f8c95401facda7c4197efc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:48:46 +0300 +Subject: drm/komeda: fix integer overflow in AFBC framebuffer size check + +From: Alexander Konyukhov + +[ Upstream commit 779ec12c85c9e4547519e3903a371a3b26a289de ] + +The AFBC framebuffer size validation calculates the minimum required +buffer size by adding the AFBC payload size to the framebuffer offset. +This addition is performed without checking for integer overflow. + +If the addition oveflows, the size check may incorrectly succed and +allow userspace to provide an undersized drm_gem_object, potentially +leading to out-of-bounds memory access. + +Add usage of check_add_overflow() to safely compute the minimum +required size and reject the framebuffer if an overflow is detected. +This makes the AFBC size validation more robust against malformed. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 65ad2392dd6d ("drm/komeda: Added AFBC support for komeda driver") +Signed-off-by: Alexander Konyukhov +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://lore.kernel.org/r/20260203134907.1587067-1-Alexander.Konyukhov@kaspersky.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +index df5da5a447555..b4f2b89651ff2 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +@@ -4,6 +4,8 @@ + * Author: James.Qian.Wang + * + */ ++#include ++ + #include + #include + #include +@@ -92,7 +94,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file, + kfb->afbc_size = kfb->offset_payload + n_blocks * + ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, + AFBC_SUPERBLK_ALIGNMENT); +- min_size = kfb->afbc_size + fb->offsets[0]; ++ if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) { ++ goto check_failed; ++ } + if (min_size > obj->size) { + DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n", + obj->size, min_size); +-- +2.53.0 + diff --git a/queue-6.1/drm-msm-a6xx-fix-hlsq-register-dumping.patch b/queue-6.1/drm-msm-a6xx-fix-hlsq-register-dumping.patch new file mode 100644 index 0000000000..2fba714e27 --- /dev/null +++ b/queue-6.1/drm-msm-a6xx-fix-hlsq-register-dumping.patch @@ -0,0 +1,39 @@ +From 0b0f7db3fa5fa0f568768588690f1e192a274b5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:40:42 -0700 +Subject: drm/msm/a6xx: Fix HLSQ register dumping + +From: Rob Clark + +[ Upstream commit c289a6db9ba6cb974f0317da142e4f665d589566 ] + +Fix the bitfield offset of HLSQ_READ_SEL state-type bitfield. Otherwise +we are always reading TP state when we wanted SP or HLSQ state. + +Reported-by: Connor Abbott +Suggested-by: Connor Abbott +Fixes: 1707add81551 ("drm/msm/a6xx: Add a6xx gpu state") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714236/ +Message-ID: <20260325184043.1259312-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 7a30249974cff..de84bd623f16a 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -649,7 +649,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, + u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; + int i, regcount = 0; + +- in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); ++ in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); + + for (i = 0; i < regs->count; i += 2) { + u32 count = RANGE(regs->registers, i); +-- +2.53.0 + diff --git a/queue-6.1/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch b/queue-6.1/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch new file mode 100644 index 0000000000..e11d5b7fff --- /dev/null +++ b/queue-6.1/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch @@ -0,0 +1,72 @@ +From 1e9e1a82d61ace8936e3bb4a5dfe269c919b8ff3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:50 +0530 +Subject: drm/msm/a6xx: Use barriers while updating HFI Q headers + +From: Akhil P Oommen + +[ Upstream commit dc78b35d5ec09d1b0b8a937e6e640d2c5a030915 ] + +To avoid harmful compiler optimizations and IO reordering in the HW, use +barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI +queue index variables. + +Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714653/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-1-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +index 2cc83e0496133..753a1bcc835cb 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +@@ -29,7 +29,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + struct a6xx_hfi_queue_header *header = queue->header; + u32 i, hdr, index = header->read_index; + +- if (header->read_index == header->write_index) { ++ if (header->read_index == READ_ONCE(header->write_index)) { + header->rx_request = 1; + return 0; + } +@@ -57,7 +57,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + if (!gmu->legacy) + index = ALIGN(index, 4) % header->size; + +- header->read_index = index; ++ /* Ensure all memory operations are complete before updating the read index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->read_index, index); + return HFI_HEADER_SIZE(hdr); + } + +@@ -69,7 +72,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + + spin_lock(&queue->lock); + +- space = CIRC_SPACE(header->write_index, header->read_index, ++ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), + header->size); + if (space < dwords) { + header->dropped++; +@@ -90,7 +93,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + queue->data[index] = 0xfafafafa; + } + +- header->write_index = index; ++ /* Ensure all memory operations are complete before updating the write index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->write_index, index); + spin_unlock(&queue->lock); + + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); +-- +2.53.0 + diff --git a/queue-6.1/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch b/queue-6.1/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch new file mode 100644 index 0000000000..5af174f696 --- /dev/null +++ b/queue-6.1/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch @@ -0,0 +1,58 @@ +From d48eabb20e77f8de8302117962abbeaf1d7463b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 14:37:20 +0800 +Subject: drm/msm/dpu: fix mismatch between power and frequency + +From: Yuanjie Yang + +[ Upstream commit bc1dccc518cc5ab5140fba06c27e7188e0ed342b ] + +During DPU runtime suspend, calling dev_pm_opp_set_rate(dev, 0) drops +the MMCX rail to MIN_SVS while the core clock frequency remains at its +original (highest) rate. When runtime resume re-enables the clock, this +may result in a mismatch between the rail voltage and the clock rate. + +For example, in the DPU bind path, the sequence could be: + cpu0: dev_sync_state -> rpmhpd_sync_state + cpu1: dpu_kms_hw_init +timeline 0 ------------------------------------------------> t + +After rpmhpd_sync_state, the voltage performance is no longer guaranteed +to stay at the highest level. During dpu_kms_hw_init, calling +dev_pm_opp_set_rate(dev, 0) drops the voltage, causing the MMCX rail to +fall to MIN_SVS while the core clock is still at its maximum frequency. +When the power is re-enabled, only the clock is enabled, leading to a +situation where the MMCX rail is at MIN_SVS but the core clock is at its +highest rate. In this state, the rail cannot sustain the clock rate, +which may cause instability or system crash. + +Remove the call to dev_pm_opp_set_rate(dev, 0) from dpu_runtime_suspend +to ensure the correct vote is restored when DPU resumes. + +Fixes: b0530eb11913 ("drm/msm/dpu: Use OPP API to set clk/perf state") +Signed-off-by: Yuanjie Yang +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/710077/ +Link: https://lore.kernel.org/r/20260309063720.13572-1-yuanjie.yang@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +index b7901b666612a..46fa3a703a1a5 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +@@ -1259,8 +1259,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); + +- /* Drop the performance state vote */ +- dev_pm_opp_set_rate(dev, 0); + clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks); + + for (i = 0; i < dpu_kms->num_paths; i++) +-- +2.53.0 + diff --git a/queue-6.1/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch b/queue-6.1/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch new file mode 100644 index 0000000000..4db21bcf0f --- /dev/null +++ b/queue-6.1/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch @@ -0,0 +1,62 @@ +From 126d5a98029368ede27fbf34f37cf004fbd341b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:48:27 +0000 +Subject: drm/msm/dsi: rename MSM8998 DSI version from V2_2_0 to V2_0_0 + +From: Alexander Koskovich + +[ Upstream commit 913a709dea0eff9c7b2e9470f8c8594b9a0114ab ] + +The MSM8998 DSI controller is v2.0.0 as stated in commit 7b8c9e203039 +("drm/msm/dsi: Add support for MSM8998 DSI controller"). The value was +always correct just the name was wrong. + +Rename and reorder to maintain version sorting. + +Fixes: 7b8c9e203039 ("drm/msm/dsi: Add support for MSM8998 DSI controller") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Alexander Koskovich +Patchwork: https://patchwork.freedesktop.org/patch/713717/ +Link: https://lore.kernel.org/r/20260324-dsi-rgb101010-support-v5-3-ff6afc904115@pm.me +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_cfg.c | 4 ++-- + drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +index e0bd452a9f1e6..4c1c2a77dec98 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +@@ -286,10 +286,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { + &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, + &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, ++ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, ++ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, + &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, +- {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, +- &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +index 8f04e685a74e9..7b56fc9297212 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +@@ -18,8 +18,8 @@ + #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 + #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 + #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 ++#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 +-#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 + #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 + #define MSM_DSI_6G_VER_MINOR_V2_4_0 0x20040000 +-- +2.53.0 + diff --git a/queue-6.1/drm-msm-shrinker-fix-can_block-logic.patch b/queue-6.1/drm-msm-shrinker-fix-can_block-logic.patch new file mode 100644 index 0000000000..8c138029a0 --- /dev/null +++ b/queue-6.1/drm-msm-shrinker-fix-can_block-logic.patch @@ -0,0 +1,44 @@ +From 500abbb2787839b11982a441f744c6508a7a8cb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:41:05 -0700 +Subject: drm/msm/shrinker: Fix can_block() logic + +From: Rob Clark + +[ Upstream commit df0f439e3926817cf577ca6272aad68468ff7624 ] + +The intention here was to allow blocking if DIRECT_RECLAIM or if called +from kswapd and KSWAPD_RECLAIM is set. + +Reported by Claude code review: https://lore.gitlab.freedesktop.org/drm-ai-reviews/review-patch9-20260309151119.290217-10-boris.brezillon@collabora.com/ on a panthor patch which had copied similar logic. + +Reported-by: Boris Brezillon +Fixes: 7860d720a84c ("drm/msm: Fix build break with recent mm tree") +Signed-off-by: Rob Clark +Reviewed-by: Boris Brezillon +Patchwork: https://patchwork.freedesktop.org/patch/714238/ +Message-ID: <20260325184106.1259528-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem_shrinker.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c +index a35c98306f1e5..f1b330c272fb7 100644 +--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c ++++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c +@@ -26,9 +26,8 @@ static bool can_swap(void) + + static bool can_block(struct shrink_control *sc) + { +- if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM)) +- return false; +- return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); ++ return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) || ++ (current_is_kswapd() && (sc->gfp_mask & __GFP_KSWAPD_RECLAIM)); + } + + static unsigned long +-- +2.53.0 + diff --git a/queue-6.1/drm-panel-simple-correct-g190ean01-prepare-timing.patch b/queue-6.1/drm-panel-simple-correct-g190ean01-prepare-timing.patch new file mode 100644 index 0000000000..6c8c90f813 --- /dev/null +++ b/queue-6.1/drm-panel-simple-correct-g190ean01-prepare-timing.patch @@ -0,0 +1,41 @@ +From 7c6e93551aab1eb14b11a8792f1881322f3c08a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 16:25:26 +0200 +Subject: drm/panel: simple: Correct G190EAN01 prepare timing + +From: Sebastian Reichel + +[ Upstream commit f1080f82570b797598c1ba7e9c800ae9e94aafc6 ] + +The prepare timing specified by the G190EAN01 datasheet should be +between 30 and 50 ms. Considering it might take some time for the +LVDS encoder to enable the signal, we should only wait the min. +required time in the panel driver and not the max. allowed time. + +Fixes: 2f7b832fc992 ("drm/panel: simple: Add support for AUO G190EAN01 panel") +Signed-off-by: Sebastian Reichel +Signed-off-by: Ian Ray +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260217142528.68613-1-ian.ray@gehealthcare.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-simple.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 3f41fd5edc333..316961a86b042 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1099,7 +1099,7 @@ static const struct panel_desc auo_g190ean01 = { + .height = 301, + }, + .delay = { +- .prepare = 50, ++ .prepare = 30, + .enable = 200, + .disable = 110, + .unprepare = 1000, +-- +2.53.0 + diff --git a/queue-6.1/drm-sun4i-backend-fix-error-pointer-dereference.patch b/queue-6.1/drm-sun4i-backend-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..7c7888c396 --- /dev/null +++ b/queue-6.1/drm-sun4i-backend-fix-error-pointer-dereference.patch @@ -0,0 +1,43 @@ +From 60bf246f2fad2d344c3d632a30de5a72f1d2ff2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 19:48:01 -0600 +Subject: drm/sun4i: backend: fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit 06277983eca4a31d3c2114fa33d99a6e82484b11 ] + +The function drm_atomic_get_plane_state() can return an error pointer +and is not checked for it. Add error pointer check. + +Detected by Smatch: +drivers/gpu/drm/sun4i/sun4i_backend.c:496 sun4i_backend_atomic_check() error: +'plane_state' dereferencing possible ERR_PTR() + +Fixes: 96180dde23b79 ("drm/sun4i: backend: Add a custom atomic_check for the frontend") +Signed-off-by: Ethan Tidmore +Reviewed-by: Chen-Yu Tsai +Link: https://patch.msgid.link/20260217014801.60760-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index 38070fc261f3a..d4fd621e33158 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -488,6 +488,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, + drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); ++ if (IS_ERR(plane_state)) ++ return PTR_ERR(plane_state); ++ + struct sun4i_layer_state *layer_state = + state_to_sun4i_layer_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; +-- +2.53.0 + diff --git a/queue-6.1/drm-sun4i-fix-resource-leaks.patch b/queue-6.1/drm-sun4i-fix-resource-leaks.patch new file mode 100644 index 0000000000..7125e05d01 --- /dev/null +++ b/queue-6.1/drm-sun4i-fix-resource-leaks.patch @@ -0,0 +1,41 @@ +From 4733ae21d3d02381f1ae5a88b1d1d0f0c82c2063 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:38:36 -0600 +Subject: drm/sun4i: Fix resource leaks + +From: Ethan Tidmore + +[ Upstream commit 127367ad2e0f4870de60c6d719ae82ecf68d674c ] + +Three clocks are not being released in devm_regmap_init_mmio() error +path. + +Add proper goto and set ret to the error code. + +Fixes: 8270249fbeaf0 ("drm/sun4i: backend: Create regmap after access is possible") +Signed-off-by: Ethan Tidmore +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260226163836.10335-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index d4fd621e33158..7cabf677ab1fc 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -878,7 +878,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, + &sun4i_backend_regmap_config); + if (IS_ERR(backend->engine.regs)) { + dev_err(dev, "Couldn't create the backend regmap\n"); +- return PTR_ERR(backend->engine.regs); ++ ret = PTR_ERR(backend->engine.regs); ++ goto err_disable_ram_clk; + } + + list_add_tail(&backend->engine.list, &drv->engine_list); +-- +2.53.0 + diff --git a/queue-6.1/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch b/queue-6.1/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch new file mode 100644 index 0000000000..7a963599e3 --- /dev/null +++ b/queue-6.1/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch @@ -0,0 +1,52 @@ +From 8de68a66c16940eccb9cf9bc5be251b7ef853d5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:25 +0100 +Subject: dt-bindings: clock: qcom,dispcc-sc7180: Define MDSS resets + +From: Konrad Dybcio + +[ Upstream commit fc6e29d42872680dca017f2e5169eefe971f8d89 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: 75616da71291 ("dt-bindings: clock: Introduce QCOM sc7180 display clock bindings") +Signed-off-by: Konrad Dybcio +Reviewed-by: Taniya Das +Acked-by: Krzysztof Kozlowski +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-1-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: b0bc6011c549 ("clk: qcom: dispcc-sc7180: Add missing MDSS resets") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,dispcc-sc7180.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/dt-bindings/clock/qcom,dispcc-sc7180.h b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +index b9b51617a335d..0705103060748 100644 +--- a/include/dt-bindings/clock/qcom,dispcc-sc7180.h ++++ b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +@@ -6,6 +6,7 @@ + #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + ++/* Clocks */ + #define DISP_CC_PLL0 0 + #define DISP_CC_PLL0_OUT_EVEN 1 + #define DISP_CC_MDSS_AHB_CLK 2 +@@ -40,7 +41,11 @@ + #define DISP_CC_MDSS_VSYNC_CLK_SRC 31 + #define DISP_CC_XO_CLK 32 + +-/* DISP_CC GDSCR */ ++/* Resets */ ++#define DISP_CC_MDSS_CORE_BCR 0 ++#define DISP_CC_MDSS_RSCC_BCR 1 ++ ++/* GDSCs */ + #define MDSS_GDSC 0 + + #endif +-- +2.53.0 + diff --git a/queue-6.1/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-6.1/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..99b8272845 --- /dev/null +++ b/queue-6.1/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,40 @@ +From 0c4bf9f67df2288a9ed1825491eb4000b9e3d9b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:06 -0300 +Subject: dt-bindings: clock: qcom,gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 76404ffbf07f28a5ec04748e18fce3dac2e78ef6 ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Signed-off-by: Val Packett +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20260312112321.370983-2-val@packett.cool +Signed-off-by: Bjorn Andersson +Stable-dep-of: 3565741eb985 ("clk: qcom: gcc-sc8180x: Add missing GDSCs") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,gcc-sc8180x.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/dt-bindings/clock/qcom,gcc-sc8180x.h b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +index 2569f874fe13c..be97a0ca2ade4 100644 +--- a/include/dt-bindings/clock/qcom,gcc-sc8180x.h ++++ b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +@@ -308,5 +308,10 @@ + #define USB30_MP_GDSC 8 + #define USB30_PRIM_GDSC 9 + #define USB30_SEC_GDSC 10 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 11 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 12 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 13 ++#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 14 ++#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 15 + + #endif +-- +2.53.0 + diff --git a/queue-6.1/e1000e-unroll-ptp-in-probe-error-handling.patch b/queue-6.1/e1000e-unroll-ptp-in-probe-error-handling.patch new file mode 100644 index 0000000000..e4a57fee23 --- /dev/null +++ b/queue-6.1/e1000e-unroll-ptp-in-probe-error-handling.patch @@ -0,0 +1,41 @@ +From b649f1181708bb88032f39e4807d499f53bae983 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:36 -0700 +Subject: e1000e: Unroll PTP in probe error handling + +From: Matt Vollrath + +[ Upstream commit aa3f7fe409350857c25d050482a2eef2cfd69b58 ] + +If probe fails after registering the PTP clock and its delayed work, +these resources must be released. + +This was not an issue until a 2016 fix moved the e1000e_ptp_init() call +before the jump to err_register. + +Fixes: aa524b66c5ef ("e1000e: don't modify SYSTIM registers during SIOCSHWTSTAMP ioctl") +Signed-off-by: Matt Vollrath +Tested-by: Avigail Dahan +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-12-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index fd056c17bd62e..f16668f47165b 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -7695,6 +7695,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + err_register: + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000e_release_hw_control(adapter); ++ e1000e_ptp_remove(adapter); + err_eeprom: + if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) + e1000_phy_hw_reset(&adapter->hw); +-- +2.53.0 + diff --git a/queue-6.1/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch b/queue-6.1/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch new file mode 100644 index 0000000000..b8cc7c7865 --- /dev/null +++ b/queue-6.1/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch @@ -0,0 +1,52 @@ +From 8da0b9324cbbd09bbd8dabefd5396b1774fee49a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:46:37 +0200 +Subject: efi/capsule-loader: fix incorrect sizeof in phys array reallocation + +From: Thomas Huth + +[ Upstream commit 48a428215782321b56956974f23593e40ce84b7a ] + +The krealloc() call for cap_info->phys in __efi_capsule_setup_info() uses +sizeof(phys_addr_t *) instead of sizeof(phys_addr_t), which might be +causing an undersized allocation. + +The allocation is also inconsistent with the initial array allocation in +efi_capsule_open() that allocates one entry with sizeof(phys_addr_t), +and the efi_capsule_write() function that stores phys_addr_t values (not +pointers) via page_to_phys(). + +On 64-bit systems where sizeof(phys_addr_t) == sizeof(phys_addr_t *), this +goes unnoticed. On 32-bit systems with PAE where phys_addr_t is 64-bit but +pointers are 32-bit, this allocates half the required space, which might +lead to a heap buffer overflow when storing physical addresses. + +This is similar to the bug fixed in commit fccfa646ef36 ("efi/capsule-loader: +fix incorrect allocation size") which fixed the same issue at the initial +allocation site. + +Fixes: f24c4d478013 ("efi/capsule-loader: Reinstate virtual capsule mapping") +Assisted-by: Claude:claude-sonnet-4-5 +Signed-off-by: Thomas Huth +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + drivers/firmware/efi/capsule-loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c +index 97bafb5f70389..c6a8bdbcae71b 100644 +--- a/drivers/firmware/efi/capsule-loader.c ++++ b/drivers/firmware/efi/capsule-loader.c +@@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) + cap_info->pages = temp_page; + + temp_page = krealloc(cap_info->phys, +- pages_needed * sizeof(phys_addr_t *), ++ pages_needed * sizeof(phys_addr_t), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.1/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch b/queue-6.1/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch new file mode 100644 index 0000000000..3e43b5cbe5 --- /dev/null +++ b/queue-6.1/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch @@ -0,0 +1,57 @@ +From 112f605a18cb3c3a6b823e8657c2a0e3023100e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:05:39 +0800 +Subject: f2fs: protect extension_list reading with sb_lock in f2fs_sbi_show() + +From: Yongpeng Yang + +[ Upstream commit 5909bedbed38c558bee7cb6758ceedf9bc3a9194 ] + +In f2fs_sbi_show(), the extension_list, extension_count and +hot_ext_count are read without holding sbi->sb_lock. If a concurrent +sysfs store modifies the extension list via f2fs_update_extension_list(), +the show path may read inconsistent count and array contents, potentially +leading to out-of-bounds access or displaying stale data. + +Fix this by holding sb_lock around the entire extension list read +and format operation. + +Fixes: b6a06cbbb5f7 ("f2fs: support hot file extension") +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/sysfs.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index aeb95c74710eb..503a50542ac53 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -306,10 +306,12 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + if (!strcmp(a->attr.name, "extension_list")) { + __u8 (*extlist)[F2FS_EXTENSION_LEN] = + sbi->raw_super->extension_list; +- int cold_count = le32_to_cpu(sbi->raw_super->extension_count); +- int hot_count = sbi->raw_super->hot_ext_count; ++ int cold_count, hot_count; + int len = 0, i; + ++ f2fs_down_read(&sbi->sb_lock); ++ cold_count = le32_to_cpu(sbi->raw_super->extension_count); ++ hot_count = sbi->raw_super->hot_ext_count; + len += sysfs_emit_at(buf, len, "cold file extension:\n"); + for (i = 0; i < cold_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); +@@ -317,6 +319,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + len += sysfs_emit_at(buf, len, "hot file extension:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); ++ f2fs_up_read(&sbi->sb_lock); + + return len; + } +-- +2.53.0 + diff --git a/queue-6.1/f2fs-use-sysfs_emit_at-to-simplify-code.patch b/queue-6.1/f2fs-use-sysfs_emit_at-to-simplify-code.patch new file mode 100644 index 0000000000..d942128192 --- /dev/null +++ b/queue-6.1/f2fs-use-sysfs_emit_at-to-simplify-code.patch @@ -0,0 +1,120 @@ +From 7615bc88a379b691596c9bb31baeb155af103636 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Aug 2024 08:47:28 +0800 +Subject: f2fs: Use sysfs_emit_at() to simplify code + +From: Christophe JAILLET + +[ Upstream commit f7a678bbe5a8f22cfcef5369757cc9b95f73e027 ] + +This file already uses sysfs_emit(). So be consistent and also use +sysfs_emit_at(). + +This slightly simplifies the code and makes it more readable. + +Reviewed-by: Chao Yu +Signed-off-by: Christophe JAILLET +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 5909bedbed38 ("f2fs: protect extension_list reading with sb_lock in f2fs_sbi_show()") +Signed-off-by: Sasha Levin +--- + fs/f2fs/sysfs.c | 45 +++++++++++++++++++++------------------------ + 1 file changed, 21 insertions(+), 24 deletions(-) + +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index 4e643abbd891a..aeb95c74710eb 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -150,50 +150,50 @@ static ssize_t features_show(struct f2fs_attr *a, + int len = 0; + + if (f2fs_sb_has_encrypt(sbi)) +- len += scnprintf(buf, PAGE_SIZE - len, "%s", ++ len += sysfs_emit_at(buf, len, "%s", + "encryption"); + if (f2fs_sb_has_blkzoned(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "blkzoned"); + if (f2fs_sb_has_extra_attr(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "extra_attr"); + if (f2fs_sb_has_project_quota(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "projquota"); + if (f2fs_sb_has_inode_chksum(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "inode_checksum"); + if (f2fs_sb_has_flexible_inline_xattr(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "flexible_inline_xattr"); + if (f2fs_sb_has_quota_ino(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "quota_ino"); + if (f2fs_sb_has_inode_crtime(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "inode_crtime"); + if (f2fs_sb_has_lost_found(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "lost_found"); + if (f2fs_sb_has_verity(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "verity"); + if (f2fs_sb_has_sb_chksum(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "sb_checksum"); + if (f2fs_sb_has_casefold(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "casefold"); + if (f2fs_sb_has_readonly(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "readonly"); + if (f2fs_sb_has_compression(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "compression"); +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "pin_file"); +- len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); ++ len += sysfs_emit_at(buf, len, "\n"); + return len; + } + +@@ -310,17 +310,14 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + int hot_count = sbi->raw_super->hot_ext_count; + int len = 0, i; + +- len += scnprintf(buf + len, PAGE_SIZE - len, +- "cold file extension:\n"); ++ len += sysfs_emit_at(buf, len, "cold file extension:\n"); + for (i = 0; i < cold_count; i++) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", +- extlist[i]); ++ len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); + +- len += scnprintf(buf + len, PAGE_SIZE - len, +- "hot file extension:\n"); ++ len += sysfs_emit_at(buf, len, "hot file extension:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", +- extlist[i]); ++ len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); ++ + return len; + } + +-- +2.53.0 + diff --git a/queue-6.1/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch b/queue-6.1/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch new file mode 100644 index 0000000000..29816df969 --- /dev/null +++ b/queue-6.1/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch @@ -0,0 +1,71 @@ +From 17d6522955703db4c074d8a4299c0f1ea11f0c7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 15:36:46 +0100 +Subject: fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build + break + +From: Andy Shevchenko + +[ Upstream commit caf6144053b4e1c815aa56afb54745a176f999df ] + +Clang is not happy about set but unused variable: + +drivers/video/fbdev/matrox/g450_pll.c:412:18: error: variable 'mnp' set but not used + 412 | unsigned int mnp; + | ^ +1 error generated. + +Since the commit 7b987887f97b ("video: fbdev: matroxfb: remove dead code +and set but not used variable") the 'mnp' became unused, but eliminating +that code might have side-effects. The question here is what should we do +with 'mnp'? The easiest way out is just mark it with __maybe_unused which +will shut the compiler up and won't change any possible IO flow. So does +this change. + +A dive into the history of the driver: + +The problem was revealed when the #if 0 guarded code along with unused +pixel_vco variable was removed. That code was introduced in the original +commit 213d22146d1f ("[PATCH] (1/3) matroxfb for 2.5.3"). And then guarded +in the commit 705e41f82988 ("matroxfb DVI updates: Handle DVI output on +G450/G550. Powerdown unused portions of G450/G550 DAC. Split G450/G550 DAC +from older DAC1064 handling. Modify PLL setting when both CRTCs use same +pixel clocks."). + +NOTE: The two commits mentioned above pre-date Git era and available in +history.git repository for archaeological purposes. + +Even without that guard the modern compilers may see that the pixel_vco +wasn't ever used and seems a leftover after some debug or review made +25 years ago. + +The g450_mnp2vco() doesn't have any IO and as Jason said doesn't seem +to have any side effects either than some unneeded CPU processing during +runtime. I agree that's unlikely that timeout (or heating up the CPU) has +any effect on the HW (GPU/display) functionality. + +Fixes: 7b987887f97b ("video: fbdev: matroxfb: remove dead code and set but not used variable") +Signed-off-by: Andy Shevchenko +Reviewed-by: Jason Yan +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/matrox/g450_pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c +index ff8e321a22cef..b2d3f7328ea83 100644 +--- a/drivers/video/fbdev/matrox/g450_pll.c ++++ b/drivers/video/fbdev/matrox/g450_pll.c +@@ -407,7 +407,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, + case M_VIDEO_PLL: + { + u_int8_t tmp; +- unsigned int mnp; ++ unsigned int mnp __maybe_unused; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); +-- +2.53.0 + diff --git a/queue-6.1/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch b/queue-6.1/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch new file mode 100644 index 0000000000..cd13c07b74 --- /dev/null +++ b/queue-6.1/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch @@ -0,0 +1,52 @@ +From efef17d2cc58e30d3359e451dc649703782dc5d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:01:18 -0400 +Subject: fbdev: offb: fix PCI device reference leak on probe failure + +From: Yuho Choi + +[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ] + +offb_init_nodriver() gets a referenced PCI device with pci_get_device(). +If pci_enable_device() fails, the function returns without dropping that +reference. + +Release the PCI device reference before returning from the +pci_enable_device() failure path. + +Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/offb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c +index ea232395e226f..e151b0d7b53c2 100644 +--- a/drivers/video/fbdev/offb.c ++++ b/drivers/video/fbdev/offb.c +@@ -646,8 +646,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod + vid = be32_to_cpup(vidp); + did = be32_to_cpup(didp); + pdev = pci_get_device(vid, did, NULL); +- if (!pdev || pci_enable_device(pdev)) ++ if (!pdev) + return; ++ ++ if (pci_enable_device(pdev)) { ++ pci_dev_put(pdev); ++ return; ++ } + } + #endif + /* kludge for valkyrie */ +-- +2.53.0 + diff --git a/queue-6.1/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch b/queue-6.1/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch new file mode 100644 index 0000000000..5bc589c1dd --- /dev/null +++ b/queue-6.1/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch @@ -0,0 +1,63 @@ +From 7e820a472fc47a357bef389f852589a3dc091356 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 08:10:20 -0600 +Subject: firmware: dmi: Correct an indexing error in dmi.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit c064abc68e009d2cc18416e7132d9c25e03125b6 ] + +The entries later in enum dmi_entry_type don't match the SMBIOS +specification¹. + +The entry for type 33: `64-Bit Memory Error Information` is not present and +thus the index for all later entries is incorrect. + +Add it. + +Also, add missing entry types 43-46, while at it. + + ¹ Search for "System Management BIOS (SMBIOS) Reference Specification" + + [ bp: Drop the flaky SMBIOS spec URL. ] + +Fixes: 93c890dbe5287 ("firmware: Add DMI entry types to the headers") +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Jean Delvare +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20260307141024.819807-2-superm1@kernel.org +Signed-off-by: Sasha Levin +--- + include/linux/dmi.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/dmi.h b/include/linux/dmi.h +index 927f8a8b7a1dd..2eedf44e68012 100644 +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -60,6 +60,7 @@ enum dmi_entry_type { + DMI_ENTRY_OOB_REMOTE_ACCESS, + DMI_ENTRY_BIS_ENTRY, + DMI_ENTRY_SYSTEM_BOOT, ++ DMI_ENTRY_64_MEM_ERROR, + DMI_ENTRY_MGMT_DEV, + DMI_ENTRY_MGMT_DEV_COMPONENT, + DMI_ENTRY_MGMT_DEV_THRES, +@@ -69,6 +70,10 @@ enum dmi_entry_type { + DMI_ENTRY_ADDITIONAL, + DMI_ENTRY_ONBOARD_DEV_EXT, + DMI_ENTRY_MGMT_CONTROLLER_HOST, ++ DMI_ENTRY_TPM_DEVICE, ++ DMI_ENTRY_PROCESSOR_ADDITIONAL, ++ DMI_ENTRY_FIRMWARE_INVENTORY, ++ DMI_ENTRY_STRING_PROPERTY, + DMI_ENTRY_INACTIVE = 126, + DMI_ENTRY_END_OF_TABLE = 127, + }; +-- +2.53.0 + diff --git a/queue-6.1/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch b/queue-6.1/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch new file mode 100644 index 0000000000..05b8d8615a --- /dev/null +++ b/queue-6.1/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch @@ -0,0 +1,48 @@ +From 3ecc6bdfd3fe6d467edc20887e17e6492dfa08f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 13:45:02 +0900 +Subject: fs/adfs: validate nzones in adfs_validate_bblk() + +From: Bae Yeonju + +[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ] + +Reject ADFS disc records with a zero zone count during boot block +validation, before the disc record is used. + +When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) +which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to +dm[-1], causing an out-of-bounds write before the allocated buffer. + +adfs_validate_dr0() already rejects nzones != 1 for old-format +images. Add the equivalent check to adfs_validate_bblk() for +new-format images so that a crafted image with nzones == 0 is +rejected at probe time. + +Found by syzkaller. + +Fixes: f6f14a0d71b0 ("fs/adfs: map: move map-specific sb initialisation to map.c") +Signed-off-by: Bae Yeonju +Signed-off-by: Russell King (Oracle) +Signed-off-by: Sasha Levin +--- + fs/adfs/super.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/adfs/super.c b/fs/adfs/super.c +index e8bfc38239cd5..76e37c6d4cad4 100644 +--- a/fs/adfs/super.c ++++ b/fs/adfs/super.c +@@ -343,6 +343,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, + if (adfs_checkdiscrecord(dr)) + return -EILSEQ; + ++ if ((dr->nzones | dr->nzones_high << 8) == 0) ++ return -EILSEQ; ++ + *drp = dr; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch b/queue-6.1/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch new file mode 100644 index 0000000000..16bba24386 --- /dev/null +++ b/queue-6.1/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch @@ -0,0 +1,51 @@ +From a36b2c90d24830cdfc0cc1c30d7aad0b16c134f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:19:55 +0800 +Subject: fs/ntfs3: terminate the cached volume label after UTF-8 conversion + +From: Pengpeng Hou + +[ Upstream commit a6cd43fe9b083fa23fe1595666d5738856cb261a ] + +ntfs_fill_super() loads the on-disk volume label with utf16s_to_utf8s() +and stores the result in sbi->volume.label. The converted label is later +exposed through ntfs3_label_show() using %s, but utf16s_to_utf8s() only +returns the number of bytes written and does not add a trailing NUL. + +If the converted label fills the entire fixed buffer, +ntfs3_label_show() can read past the end of sbi->volume.label while +looking for a terminator. + +Terminate the cached label explicitly after a successful conversion and +clamp the exact-full case to the last byte of the buffer. + +Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") +Signed-off-by: Pengpeng Hou +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 7cf52b70987b0..35dd0018e2bd4 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -992,8 +992,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + le32_to_cpu(attr->res.data_size) >> 1, + UTF16_LITTLE_ENDIAN, sbi->volume.label, + sizeof(sbi->volume.label)); +- if (err < 0) ++ if (err < 0) { + sbi->volume.label[0] = 0; ++ } else if (err >= sizeof(sbi->volume.label)) { ++ sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0; ++ } else { ++ sbi->volume.label[err] = 0; ++ } + } else { + /* Should we break mounting here? */ + //err = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.1/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch b/queue-6.1/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch new file mode 100644 index 0000000000..ef98e4e0ab --- /dev/null +++ b/queue-6.1/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch @@ -0,0 +1,55 @@ +From 3e126253bee8adffadfddc9d314d8bca32f37310 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:48:27 +0900 +Subject: fs/omfs: reject s_sys_blocksize smaller than OMFS_DIR_START + +From: HyungJung Joo + +[ Upstream commit 0621c385fda1376e967f37ccd534c26c3e511d14 ] + +omfs_fill_super() rejects oversized s_sys_blocksize values (> PAGE_SIZE), +but it does not reject values smaller than OMFS_DIR_START (0x1b8 = 440). + +Later, omfs_make_empty() uses + + sbi->s_sys_blocksize - OMFS_DIR_START + +as the length argument to memset(). Since s_sys_blocksize is u32, +a crafted filesystem image with s_sys_blocksize < OMFS_DIR_START causes +an unsigned underflow there, wrapping to a value near 2^32. That drives +a ~4 GiB memset() from bh->b_data + OMFS_DIR_START and overwrites kernel +memory far beyond the backing block buffer. + +Add the corresponding lower-bound check alongside the existing upper-bound +check in omfs_fill_super(), so that malformed images are rejected during +superblock validation before any filesystem data is processed. + +Fixes: a3ab7155ea21 ("omfs: add directory routines") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054827.1822061-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/omfs/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c +index 2a0e83236c011..9773846daa4bc 100644 +--- a/fs/omfs/inode.c ++++ b/fs/omfs/inode.c +@@ -515,6 +515,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) + goto out_brelse_bh; + } + ++ if (sbi->s_sys_blocksize < OMFS_DIR_START) { ++ printk(KERN_ERR "omfs: sysblock size (%d) is too small\n", ++ sbi->s_sys_blocksize); ++ goto out_brelse_bh; ++ } ++ + if (sbi->s_blocksize < sbi->s_sys_blocksize || + sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { + printk(KERN_ERR "omfs: block size (%d) is out of range\n", +-- +2.53.0 + diff --git a/queue-6.1/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch b/queue-6.1/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch new file mode 100644 index 0000000000..7efe4b2b01 --- /dev/null +++ b/queue-6.1/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch @@ -0,0 +1,100 @@ +From 19e8ab6e9bea47f10c074eea15571be7e7a53752 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:34:25 +0200 +Subject: futex: Prevent lockup in requeue-PI during signal/ timeout wakeup + +From: Sebastian Andrzej Siewior + +[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ] + +During wait-requeue-pi (task A) and requeue-PI (task B) the following +race can happen: + + Task A Task B + futex_wait_requeue_pi() + futex_setup_timer() + futex_do_wait() + futex_requeue() + CLASS(hb, hb1)(&key1); + CLASS(hb, hb2)(&key2); + *timeout* + futex_requeue_pi_wakeup_sync() + requeue_state = Q_REQUEUE_PI_IGNORE + + *blocks on hb->lock* + + futex_proxy_trylock_atomic() + futex_requeue_pi_prepare() + Q_REQUEUE_PI_IGNORE => -EAGAIN + double_unlock_hb(hb1, hb2) + *retry* + +Task B acquires both hb locks and attempts to acquire the PI-lock of the +top most waiter (task B). Task A is leaving early due to a signal/ +timeout and started removing itself from the queue. It updates its +requeue_state but can not remove it from the list because this requires +the hb lock which is owned by task B. + +Usually task A is able to swoop the lock after task B unlocked it. +However if task B is of higher priority then task A may not be able to +wake up in time and acquire the lock before task B gets it again. +Especially on a UP system where A is never scheduled. + +As a result task A blocks on the lock and task B busy loops, trying to +make progress but live locks the system instead. Tragic. + +This can be fixed by removing the top most waiter from the list in this +case. This allows task B to grab the next top waiter (if any) in the +next iteration and make progress. + +Remove the top most waiter if futex_requeue_pi_prepare() fails. +Let the waiter conditionally remove itself from the list in +handle_early_requeue_pi_wakeup(). + +Fixes: 07d91ef510fb1 ("futex: Prevent requeue_pi() lock nesting issue on RT") +Reported-by: Moritz Klammler +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260428103425.dywXyPd3@linutronix.de +Closes: https://lore.kernel.org/all/VE1PR06MB6894BE61C173D802365BE19DFF4CA@VE1PR06MB6894.eurprd06.prod.outlook.com +Signed-off-by: Sasha Levin +--- + kernel/futex/requeue.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c +index 7e43839ca7b05..60b08247b07dd 100644 +--- a/kernel/futex/requeue.c ++++ b/kernel/futex/requeue.c +@@ -307,8 +307,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, + return -EINVAL; + + /* Ensure that this does not race against an early wakeup */ +- if (!futex_requeue_pi_prepare(top_waiter, NULL)) ++ if (!futex_requeue_pi_prepare(top_waiter, NULL)) { ++ plist_del(&top_waiter->list, &hb1->chain); ++ futex_hb_waiters_dec(hb1); + return -EAGAIN; ++ } + + /* + * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit +@@ -707,10 +710,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, + + /* + * We were woken prior to requeue by a timeout or a signal. +- * Unqueue the futex_q and determine which it was. ++ * Conditionally unqueue the futex_q and determine which it was. + */ +- plist_del(&q->list, &hb->chain); +- futex_hb_waiters_dec(hb); ++ if (!plist_node_empty(&q->list)) { ++ plist_del(&q->list, &hb->chain); ++ futex_hb_waiters_dec(hb); ++ } + + /* Handle spurious wakeups gracefully */ + ret = -EWOULDBLOCK; +-- +2.53.0 + diff --git a/queue-6.1/gfs2-add-some-missing-log-locking.patch b/queue-6.1/gfs2-add-some-missing-log-locking.patch new file mode 100644 index 0000000000..81a8b5743a --- /dev/null +++ b/queue-6.1/gfs2-add-some-missing-log-locking.patch @@ -0,0 +1,109 @@ +From cfb4268bb3a0537d2f56429ca419bb45b586c04f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 06:13:42 +0200 +Subject: gfs2: add some missing log locking + +From: Andreas Gruenbacher + +[ Upstream commit fe2c8d051150b90b3ccb85f89e3b1d636cb88ec8 ] + +Function gfs2_logd() calls the log flushing functions gfs2_ail1_start(), +gfs2_ail1_wait(), and gfs2_ail1_empty() without holding sdp->sd_log_flush_lock, +but these functions require exclusion against concurrent transactions. + +To fix that, add a non-locking __gfs2_log_flush() function. Then, in +gfs2_logd(), take sdp->sd_log_flush_lock before calling the above mentioned log +flushing functions and __gfs2_log_flush(). + +Fixes: 5e4c7632aae1c ("gfs2: Issue revokes more intelligently") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 45f519ececd97..de6f38523db33 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -1025,14 +1025,15 @@ static void trans_drain(struct gfs2_trans *tr) + } + + /** +- * gfs2_log_flush - flush incore transaction(s) ++ * __gfs2_log_flush - flush incore transaction(s) + * @sdp: The filesystem + * @gl: The glock structure to flush. If NULL, flush the whole incore log + * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags + * + */ + +-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ++ u32 flags) + { + struct gfs2_trans *tr = NULL; + unsigned int reserved_blocks = 0, used_blocks = 0; +@@ -1040,7 +1041,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + unsigned int first_log_head; + unsigned int reserved_revokes = 0; + +- down_write(&sdp->sd_log_flush_lock); + trace_gfs2_log_flush(sdp, 1, flags); + + repeat: +@@ -1151,7 +1151,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + gfs2_assert_withdraw_delayed(sdp, used_blocks < reserved_blocks); + gfs2_log_release(sdp, reserved_blocks - used_blocks); + } +- up_write(&sdp->sd_log_flush_lock); + gfs2_trans_free(sdp, tr); + if (gfs2_withdrawing(sdp)) + gfs2_withdraw(sdp); +@@ -1174,6 +1173,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + goto out_end; + } + ++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++{ ++ down_write(&sdp->sd_log_flush_lock); ++ __gfs2_log_flush(sdp, gl, flags); ++ up_write(&sdp->sd_log_flush_lock); ++} ++ + /** + * gfs2_merge_trans - Merge a new transaction into a cached transaction + * @sdp: the filesystem +@@ -1319,19 +1325,25 @@ int gfs2_logd(void *data) + } + + if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_JFLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_JFLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) || + gfs2_ail_flush_reqd(sdp)) { + clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_start(sdp); + gfs2_ail1_wait(sdp); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; +-- +2.53.0 + diff --git a/queue-6.1/gfs2-call-unlock_new_inode-before-d_instantiate.patch b/queue-6.1/gfs2-call-unlock_new_inode-before-d_instantiate.patch new file mode 100644 index 0000000000..b6f43e09b6 --- /dev/null +++ b/queue-6.1/gfs2-call-unlock_new_inode-before-d_instantiate.patch @@ -0,0 +1,48 @@ +From 0b97d73bbec55ded9efebecfce1e310f413fd543 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:04:05 +0100 +Subject: gfs2: Call unlock_new_inode before d_instantiate + +From: Andreas Gruenbacher + +[ Upstream commit 2ff7cf7e0640ff071ebc5c7e3dc2df024a7c91e6 ] + +As Neil Brown describes in detail in the link referenced below, new +inodes must be unlocked before they can be instantiated. + +An even better fix is to use d_instantiate_new(), which combines +d_instantiate() and unlock_new_inode(). + +Fixes: 3d36e57ff768 ("gfs2: gfs2_create_inode rework") +Reported-by: syzbot+0ea5108a1f5fb4fcc2d8@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-fsdevel/177153754005.8396.8777398743501764194@noble.neil.brown.name/ +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/inode.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index 3048e3ca4b382..c291b9382e994 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -779,7 +779,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + goto fail_gunlock4; + + mark_inode_dirty(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + /* After instantiate, errors should result in evict which will destroy + * both inode and iopen glocks properly. */ + if (file) { +@@ -791,7 +791,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + gfs2_glock_dq_uninit(ghs + 1); + gfs2_glock_put(io_gl); + gfs2_qa_put(dip); +- unlock_new_inode(inode); + return error; + + fail_gunlock4: +-- +2.53.0 + diff --git a/queue-6.1/gfs2-prevent-null-pointer-dereference-during-unmount.patch b/queue-6.1/gfs2-prevent-null-pointer-dereference-during-unmount.patch new file mode 100644 index 0000000000..8d4f9ab059 --- /dev/null +++ b/queue-6.1/gfs2-prevent-null-pointer-dereference-during-unmount.patch @@ -0,0 +1,44 @@ +From 255268afac48c2be3410a57589f6987605ff86ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 12:14:30 +0200 +Subject: gfs2: prevent NULL pointer dereference during unmount + +From: Andreas Gruenbacher + +[ Upstream commit 74b4dbb946060a3233604d91859a9abd3708141d ] + +When flushing out outstanding glock work during an unmount, gfs2_log_flush() +can be called when sdp->sd_jdesc has already been deallocated and sdp->sd_jdesc +is NULL. Commit 35264909e9d1 ("gfs2: Fix NULL pointer dereference in +gfs2_log_flush") added a check for that to gfs2_log_flush() itself, but it +missed the sdp->sd_jdesc dereference in gfs2_log_release(). Fix that. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202604071139.HNJiCaAi-lkp@intel.com/ +Fixes: 35264909e9d1 ("gfs2: Fix NULL pointer dereference in gfs2_log_flush") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index de6f38523db33..229ceed689f69 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -478,8 +478,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) + { + atomic_add(blks, &sdp->sd_log_blks_free); + trace_gfs2_log_blocks(sdp, blks); +- gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= +- sdp->sd_jdesc->jd_blocks); ++ gfs2_assert_withdraw(sdp, !sdp->sd_jdesc || ++ atomic_read(&sdp->sd_log_blks_free) <= ++ sdp->sd_jdesc->jd_blocks); + if (atomic_read(&sdp->sd_log_blks_needed)) + wake_up(&sdp->sd_log_waitq); + } +-- +2.53.0 + diff --git a/queue-6.1/hid-asus-do-not-abort-probe-when-not-necessary.patch b/queue-6.1/hid-asus-do-not-abort-probe-when-not-necessary.patch new file mode 100644 index 0000000000..969b69743f --- /dev/null +++ b/queue-6.1/hid-asus-do-not-abort-probe-when-not-necessary.patch @@ -0,0 +1,65 @@ +From fb13dd7ebed6537d933fe88077d4206166d5086d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:09 +0100 +Subject: HID: asus: do not abort probe when not necessary + +From: Denis Benato + +[ Upstream commit 7253091766ded0fd81fe8d8be9b8b835495b06e8 ] + +In order to avoid dereferencing a NULL pointer asus_probe is aborted early +and control of some asus devices is transferred over hid-generic after +erroring out even when such NULL dereference cannot happen: only early +abort when the NULL dereference can happen. + +Also make the code shorter and more adherent to coding standards +removing square brackets enclosing single-line if-else statements. + +Fixes: d3af6ca9a8c3 ("HID: asus: fix UAF via HID_CLAIMED_INPUT validation") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index b51988e478e59..9193dfed68368 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1124,22 +1124,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + * were freed during registration due to no usages being mapped, + * leaving drvdata->input pointing to freed memory. + */ +- if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { +- hid_err(hdev, "Asus input not registered\n"); +- ret = -ENOMEM; +- goto err_stop_hw; +- } +- +- if (drvdata->tp) { +- drvdata->input->name = "Asus TouchPad"; +- } else { +- drvdata->input->name = "Asus Keyboard"; +- } ++ if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) { ++ if (drvdata->tp) ++ drvdata->input->name = "Asus TouchPad"; ++ else ++ drvdata->input->name = "Asus Keyboard"; + +- if (drvdata->tp) { +- ret = asus_start_multitouch(hdev); +- if (ret) +- goto err_stop_hw; ++ if (drvdata->tp) { ++ ret = asus_start_multitouch(hdev); ++ if (ret) ++ goto err_stop_hw; ++ } + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch b/queue-6.1/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch new file mode 100644 index 0000000000..8c078a73ed --- /dev/null +++ b/queue-6.1/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch @@ -0,0 +1,37 @@ +From 5d4724415abec18044340116d76cddf25b4c39f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:07 +0100 +Subject: HID: asus: make asus_resume adhere to linux kernel coding standards + +From: Denis Benato + +[ Upstream commit 51d33b42b8ae23da92819d28439fdd5636c45186 ] + +Linux kernel coding standars requires functions opening brackets to be in +a newline: move the opening bracket of asus_resume in its own line. + +Fixes: 546edbd26cff ("HID: hid-asus: reset the backlight brightness level on resume") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index a95e47ce6d1e5..b51988e478e59 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -996,7 +996,8 @@ static int asus_start_multitouch(struct hid_device *hdev) + return 0; + } + +-static int __maybe_unused asus_resume(struct hid_device *hdev) { ++static int __maybe_unused asus_resume(struct hid_device *hdev) ++{ + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + int ret = 0; + +-- +2.53.0 + diff --git a/queue-6.1/hid-usbhid-fix-deadlock-in-hid_post_reset.patch b/queue-6.1/hid-usbhid-fix-deadlock-in-hid_post_reset.patch new file mode 100644 index 0000000000..aeb05908e9 --- /dev/null +++ b/queue-6.1/hid-usbhid-fix-deadlock-in-hid_post_reset.patch @@ -0,0 +1,42 @@ +From 3b505ecae8fd08d5c877dc6964237835c122039e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:24:54 +0100 +Subject: HID: usbhid: fix deadlock in hid_post_reset() + +From: Oliver Neukum + +[ Upstream commit 8df2c1b47ee3cd50fd454f75c7a7e2ae8a6adf72 ] + +You can build a USB device that includes a HID component +and a storage or UAS component. The components can be reset +only together. That means that hid_pre_reset() and hid_post_reset() +are in the block IO error handling. Hence no memory allocation +used in them may do block IO because the IO can deadlock +on the mutex held while resetting a device and calling the +interface drivers. +Use GFP_NOIO for all allocations in them. + +Fixes: dc3c78e434690 ("HID: usbhid: Check HID report descriptor contents after device reset") +Signed-off-by: Oliver Neukum +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index 352c9327d08b2..ccf0aad99a4b9 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1544,7 +1544,7 @@ static int hid_post_reset(struct usb_interface *intf) + * configuration descriptors passed, we already know that + * the size of the HID report descriptor has not changed. + */ +- rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); ++ rdesc = kmalloc(hid->dev_rsize, GFP_NOIO); + if (!rdesc) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.1/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch b/queue-6.1/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch new file mode 100644 index 0000000000..845684245d --- /dev/null +++ b/queue-6.1/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch @@ -0,0 +1,46 @@ +From a7302bd252a8c0b84fcb03d4abb3366f85d08ebb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:35:37 +0100 +Subject: hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns() + +From: Peter Zijlstra + +[ Upstream commit d19ff16c11db38f3ee179d72751fb9b340174330 ] + +Much like hrtimer_reprogram(), skip programming if the cpu_base is running +the hrtimer interrupt. + +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Juri Lelli +Reviewed-by: Thomas Gleixner +Link: https://patch.msgid.link/20260224163429.069535561@kernel.org +Stable-dep-of: f2e388a019e4 ("hrtimer: Reduce trace noise in hrtimer_start()") +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 062dda96e2706..2d8c7b735baeb 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1284,6 +1284,14 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + } + + first = enqueue_hrtimer(timer, new_base, mode); ++ ++ /* ++ * If the hrtimer interrupt is running, then it will reevaluate the ++ * clock bases and reprogram the clock event device. ++ */ ++ if (new_base->cpu_base->in_hrtirq) ++ return false; ++ + if (!force_local) { + /* + * If the current CPU base is online, then the timer is +-- +2.53.0 + diff --git a/queue-6.1/hrtimer-reduce-trace-noise-in-hrtimer_start.patch b/queue-6.1/hrtimer-reduce-trace-noise-in-hrtimer_start.patch new file mode 100644 index 0000000000..7f9a67fb42 --- /dev/null +++ b/queue-6.1/hrtimer-reduce-trace-noise-in-hrtimer_start.patch @@ -0,0 +1,216 @@ +From dd786a9d5fe28e0b948cc87f9e7b76edd50b5e1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:36:59 +0100 +Subject: hrtimer: Reduce trace noise in hrtimer_start() + +From: Thomas Gleixner + +[ Upstream commit f2e388a019e4cf83a15883a3d1f1384298e9a6aa ] + +hrtimer_start() when invoked with an already armed timer traces like: + + -.. [032] d.h2. 5.002263: hrtimer_cancel: hrtimer= .... + -.. [032] d.h1. 5.002263: hrtimer_start: hrtimer= .... + +Which is incorrect as the timer doesn't get canceled. Just the expiry time +changes. The internal dequeue operation which is required for that is not +really interesting for trace analysis. But it makes it tedious to keep real +cancellations and the above case apart. + +Remove the cancel tracing in hrtimer_start() and add a 'was_armed' +indicator to the hrtimer start tracepoint, which clearly indicates what the +state of the hrtimer is when hrtimer_start() is invoked: + +-.. [032] d.h1. 6.200103: hrtimer_start: hrtimer= .... was_armed=0 + -.. [032] d.h1. 6.200558: hrtimer_start: hrtimer= .... was_armed=1 + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260224163430.208491877@kernel.org +Signed-off-by: Sasha Levin +--- + include/trace/events/timer.h | 11 +++++---- + kernel/time/hrtimer.c | 43 +++++++++++++++++------------------- + 2 files changed, 27 insertions(+), 27 deletions(-) + +diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h +index b4bc2828fa09f..ec8d0de1ad225 100644 +--- a/include/trace/events/timer.h ++++ b/include/trace/events/timer.h +@@ -198,12 +198,13 @@ TRACE_EVENT(hrtimer_init, + * hrtimer_start - called when the hrtimer is started + * @hrtimer: pointer to struct hrtimer + * @mode: the hrtimers mode ++ * @was_armed: Was armed when hrtimer_start*() was invoked + */ + TRACE_EVENT(hrtimer_start, + +- TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode), ++ TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode, bool was_armed), + +- TP_ARGS(hrtimer, mode), ++ TP_ARGS(hrtimer, mode, was_armed), + + TP_STRUCT__entry( + __field( void *, hrtimer ) +@@ -211,6 +212,7 @@ TRACE_EVENT(hrtimer_start, + __field( s64, expires ) + __field( s64, softexpires ) + __field( enum hrtimer_mode, mode ) ++ __field( bool, was_armed ) + ), + + TP_fast_assign( +@@ -219,13 +221,14 @@ TRACE_EVENT(hrtimer_start, + __entry->expires = hrtimer_get_expires(hrtimer); + __entry->softexpires = hrtimer_get_softexpires(hrtimer); + __entry->mode = mode; ++ __entry->was_armed = was_armed; + ), + + TP_printk("hrtimer=%p function=%ps expires=%llu softexpires=%llu " +- "mode=%s", __entry->hrtimer, __entry->function, ++ "mode=%s was_armed=%d", __entry->hrtimer, __entry->function, + (unsigned long long) __entry->expires, + (unsigned long long) __entry->softexpires, +- decode_hrtimer_mode(__entry->mode)) ++ decode_hrtimer_mode(__entry->mode), __entry->was_armed) + ); + + /** +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 2d8c7b735baeb..d56e18b133741 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -497,17 +497,10 @@ debug_init(struct hrtimer *timer, clockid_t clockid, + trace_hrtimer_init(timer, clockid, mode); + } + +-static inline void debug_activate(struct hrtimer *timer, +- enum hrtimer_mode mode) ++static inline void debug_activate(struct hrtimer *timer, enum hrtimer_mode mode, bool was_armed) + { + debug_hrtimer_activate(timer, mode); +- trace_hrtimer_start(timer, mode); +-} +- +-static inline void debug_deactivate(struct hrtimer *timer) +-{ +- debug_hrtimer_deactivate(timer); +- trace_hrtimer_cancel(timer); ++ trace_hrtimer_start(timer, mode, was_armed); + } + + static struct hrtimer_clock_base * +@@ -1099,9 +1092,9 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); + * Returns true when the new timer is the leftmost timer in the tree. + */ + static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, +- enum hrtimer_mode mode) ++ enum hrtimer_mode mode, bool was_armed) + { +- debug_activate(timer, mode); ++ debug_activate(timer, mode, was_armed); + WARN_ON_ONCE(!base->cpu_base->online); + + base->cpu_base->active_bases |= 1 << base->index; +@@ -1161,6 +1154,8 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + if (state & HRTIMER_STATE_ENQUEUED) { + bool reprogram; + ++ debug_hrtimer_deactivate(timer); ++ + /* + * Remove the timer and force reprogramming when high + * resolution mode is active and the timer is on the current +@@ -1169,7 +1164,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + * reprogramming happens in the interrupt handler. This is a + * rare case and less expensive than a smp call. + */ +- debug_deactivate(timer); + reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); + + /* +@@ -1236,15 +1230,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + { + struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); + struct hrtimer_clock_base *new_base; +- bool force_local, first; ++ bool force_local, first, was_armed; + + /* + * If the timer is on the local cpu base and is the first expiring + * timer then this might end up reprogramming the hardware twice +- * (on removal and on enqueue). To avoid that by prevent the +- * reprogram on removal, keep the timer local to the current CPU +- * and enforce reprogramming after it is queued no matter whether +- * it is the new first expiring timer again or not. ++ * (on removal and on enqueue). To avoid that prevent the reprogram ++ * on removal, keep the timer local to the current CPU and enforce ++ * reprogramming after it is queued no matter whether it is the new ++ * first expiring timer again or not. + */ + force_local = base->cpu_base == this_cpu_base; + force_local &= base->cpu_base->next_timer == timer; +@@ -1266,7 +1260,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + * avoids programming the underlying clock event twice (once at + * removal and once after enqueue). + */ +- remove_hrtimer(timer, base, true, force_local); ++ was_armed = remove_hrtimer(timer, base, true, force_local); + + if (mode & HRTIMER_MODE_REL) + tim = ktime_add_safe(tim, base->get_time()); +@@ -1283,7 +1277,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + new_base = base; + } + +- first = enqueue_hrtimer(timer, new_base, mode); ++ first = enqueue_hrtimer(timer, new_base, mode, was_armed); + + /* + * If the hrtimer interrupt is running, then it will reevaluate the +@@ -1387,8 +1381,11 @@ int hrtimer_try_to_cancel(struct hrtimer *timer) + + base = lock_hrtimer_base(timer, &flags); + +- if (!hrtimer_callback_running(timer)) ++ if (!hrtimer_callback_running(timer)) { + ret = remove_hrtimer(timer, base, false, false); ++ if (ret) ++ trace_hrtimer_cancel(timer); ++ } + + unlock_hrtimer_base(timer, &flags); + +@@ -1768,7 +1765,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + */ + if (restart != HRTIMER_NORESTART && + !(timer->state & HRTIMER_STATE_ENQUEUED)) +- enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, false); + + /* + * Separate the ->running assignment from the ->state assignment. +@@ -2250,7 +2247,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + while ((node = timerqueue_getnext(&old_base->active))) { + timer = container_of(node, struct hrtimer, node); + BUG_ON(hrtimer_callback_running(timer)); +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + + /* + * Mark it as ENQUEUED not INACTIVE otherwise the +@@ -2267,7 +2264,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + * sort out already expired timers and reprogram the + * event device. + */ +- enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, true); + } + } + +-- +2.53.0 + diff --git a/queue-6.1/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch b/queue-6.1/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch new file mode 100644 index 0000000000..05795f2dc4 --- /dev/null +++ b/queue-6.1/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch @@ -0,0 +1,49 @@ +From fcae2a75cb5338a16dccbc1ac5a85f2377505c71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Dec 2024 15:57:03 +0800 +Subject: hrtimers: Update the return type of enqueue_hrtimer() + +From: Richard Clark + +[ Upstream commit da7100d3bf7d6f5c49ef493ea963766898e9b069 ] + +The return type should be 'bool' instead of 'int' according to the calling +context in the kernel, and its internal implementation, i.e. : + + return timerqueue_add(); + +which is a bool-return function. + +[ tglx: Adjust function arguments ] + +Signed-off-by: Richard Clark +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/all/Z2ppT7me13dtxm1a@MBC02GN1V4Q05P +Stable-dep-of: f2e388a019e4 ("hrtimer: Reduce trace noise in hrtimer_start()") +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 002b29e566cb3..062dda96e2706 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1096,11 +1096,10 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); + * The timer is inserted in expiry order. Insertion into the + * red black tree is O(log(n)). Must hold the base lock. + * +- * Returns 1 when the new timer is the leftmost timer in the tree. ++ * Returns true when the new timer is the leftmost timer in the tree. + */ +-static int enqueue_hrtimer(struct hrtimer *timer, +- struct hrtimer_clock_base *base, +- enum hrtimer_mode mode) ++static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, ++ enum hrtimer_mode mode) + { + debug_activate(timer, mode); + WARN_ON_ONCE(!base->cpu_base->online); +-- +2.53.0 + diff --git a/queue-6.1/i3c-master-fix-error-codes-at-send_ccc_cmd.patch b/queue-6.1/i3c-master-fix-error-codes-at-send_ccc_cmd.patch new file mode 100644 index 0000000000..29d4d0696d --- /dev/null +++ b/queue-6.1/i3c-master-fix-error-codes-at-send_ccc_cmd.patch @@ -0,0 +1,126 @@ +From bb0fb099c8ba3c7c7f4edd03a0f72f7c75c92399 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:32 +0100 +Subject: i3c: master: Fix error codes at send_ccc_cmd + +From: Jorge Marques + +[ Upstream commit ef8b5229348f0719aca557c4ca5530630ae4d134 ] + +i3c_master_send_ccc_cmd_locked() would propagate cmd->err (positive, +Mx codes) to the ret variable, cascading down multiple methods until +reaching methods that explicitly stated they would return 0 on success +or negative error code. For example, the call chain: + + i3c_device_enable_ibi <- i3c_dev_enable_ibi_locked <- + master->ops.enable_ibi <- i3c_master_enec_locked <- + i3c_master_enec_disec_locked <- i3c_master_send_ccc_cmd_locked + +Fix this by returning the ret value, callers can still read the cmd->err +value if ret is negative. + +All corner cases where the Mx codes do need to be handled individually, +are resolved in previous commits. Those corner cases are all scenarios +when I3C_ERROR_M2 is expected and acceptable. +The prerequisite patches for the fix are: + + i3c: master: Move rstdaa error suppression + i3c: master: Move entdaa error suppression + i3c: master: Move bus_init error suppression + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-iio/aYXvT5FW0hXQwhm_@stanley.mountain/ +Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-4-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 32 +++++++++++++------------------- + 1 file changed, 13 insertions(+), 19 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 74138c499642e..74cadaf638936 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -792,11 +792,17 @@ static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id, + cmd->err = I3C_ERROR_UNKNOWN; + } + ++/** ++ * i3c_master_send_ccc_cmd_locked() - send a CCC (Common Command Codes) ++ * @master: master used to send frames on the bus ++ * @cmd: command to send ++ * ++ * Return: 0 in case of success, or a negative error code otherwise. ++ * I3C Mx error codes are stored in cmd->err. ++ */ + static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd) + { +- int ret; +- + if (!cmd || !master) + return -EINVAL; + +@@ -814,15 +820,7 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + !master->ops->supports_ccc_cmd(master, cmd)) + return -ENOTSUPP; + +- ret = master->ops->send_ccc_cmd(master, cmd); +- if (ret) { +- if (cmd->err != I3C_ERROR_UNKNOWN) +- return cmd->err; +- +- return ret; +- } +- +- return 0; ++ return master->ops->send_ccc_cmd(master, cmd); + } + + static struct i2c_dev_desc * +@@ -926,8 +924,7 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_entdaa_locked(struct i3c_master_controller *master) + { +@@ -979,8 +976,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1000,8 +996,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1026,8 +1021,7 @@ EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_defslvs_locked(struct i3c_master_controller *master) + { +-- +2.53.0 + diff --git a/queue-6.1/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch b/queue-6.1/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch new file mode 100644 index 0000000000..8b5085a198 --- /dev/null +++ b/queue-6.1/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch @@ -0,0 +1,56 @@ +From d431f4d01d2fda3b595e1958ddcc53fe5325c63b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:53:23 +0800 +Subject: i3c: mipi-i3c-hci: fix IBI payload length calculation for final + status + +From: Billy Tsai + +[ Upstream commit d35a6db887eeae7c57b719521e39d64f929c6dc3 ] + +In DMA mode, the IBI status descriptor encodes the payload using +CHUNKS (number of chunks) and DATA_LENGTH (valid bytes in the last +chunk). All preceding chunks are implicitly full-sized. + +The current code accumulates full chunk sizes for non-final status +descriptors, but for the final status descriptor it only adds +DATA_LENGTH. This ignores the contribution of the preceding full +chunks described by the same final status entry. + +As a result, the computed IBI payload length is truncated whenever +the final status spans multiple chunks. For example, with a chunk +size of 4 bytes, CHUNKS=2 and DATA_LENGTH=1 should result in a total +payload size of 5 bytes, but the current code reports only 1 byte. + +Fix the calculation by adding the size of (CHUNKS - 1) full chunks +plus DATA_LENGTH for the last chunk. + +Fixes: 9ad9a52cce28 ("i3c/master: introduce the mipi-i3c-hci driver") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260407-i3c-hci-dma-v2-1-a583187b9d22@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index e270fcd0f7c38..624d00b853a51 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -636,7 +636,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh) + if (!(ibi_status & IBI_LAST_STATUS)) { + ibi_size += chunks * rh->ibi_chunk_sz; + } else { +- ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ if (chunks) { ++ ibi_size += (chunks - 1) * rh->ibi_chunk_sz; ++ ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ } + last_ptr = ptr; + break; + } +-- +2.53.0 + diff --git a/queue-6.1/i40e-don-t-advertise-iff_supp_nofcs.patch b/queue-6.1/i40e-don-t-advertise-iff_supp_nofcs.patch new file mode 100644 index 0000000000..8a6e73f29d --- /dev/null +++ b/queue-6.1/i40e-don-t-advertise-iff_supp_nofcs.patch @@ -0,0 +1,53 @@ +From ada98aecb3973a921fb8852b66b2b29e7d12c6c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:33 -0700 +Subject: i40e: don't advertise IFF_SUPP_NOFCS + +From: Kohei Enju + +[ Upstream commit a24162f18825684ad04e3a5d0531f8a50d679347 ] + +i40e advertises IFF_SUPP_NOFCS, allowing users to use the SO_NOFCS +socket option. However, this option is silently ignored, as the driver +does not check skb->no_fcs, and always enables FCS insertion offload. + +Fix this by removing the advertisement of IFF_SUPP_NOFCS. + +This behavior can be reproduced with a simple AF_PACKET socket: + + import socket + s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) + s.setsockopt(socket.SOL_SOCKET, 43, 1) # SO_NOFCS + s.bind(("eth0", 0)) + s.send(b'\xff' * 64) + +Previously, send() succeeds but the driver ignores SO_NOFCS. +With this change, send() fails with -EPROTONOSUPPORT, as expected. + +Fixes: 41c445ff0f48 ("i40e: main driver core") +Signed-off-by: Kohei Enju +Reviewed-by: Aleksandr Loktionov +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-9-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index be4471072fe28..a1a0e7c9fb7f2 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -13864,7 +13864,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) + netdev->neigh_priv_len = sizeof(u32) * 4; + + netdev->priv_flags |= IFF_UNICAST_FLT; +- netdev->priv_flags |= IFF_SUPP_NOFCS; + /* Setup netdev TC information */ + i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); + +-- +2.53.0 + diff --git a/queue-6.1/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch b/queue-6.1/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch new file mode 100644 index 0000000000..a4cb28191d --- /dev/null +++ b/queue-6.1/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch @@ -0,0 +1,58 @@ +From 6cef936ea8f4350c1cddc5c2c644fe3787312b19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:16 -0700 +Subject: iavf: add VIRTCHNL_OP_ADD_VLAN to success completion handler + +From: Petr Oros + +[ Upstream commit 34d33313b52eeac3a97ad2e3176d523ec70d9283 ] + +The V1 ADD_VLAN opcode had no success handler; filters sent via V1 +stayed in ADDING state permanently. Add a fallthrough case so V1 +filters also transition ADDING -> ACTIVE on PF confirmation. + +Critically, add an `if (v_retval) break` guard: the error switch in +iavf_virtchnl_completion() does NOT return after handling errors, +it falls through to the success switch. Without this guard, a +PF-rejected ADD would incorrectly mark ADDING filters as ACTIVE, +creating a driver/HW mismatch where the driver believes the filter +is installed but the PF never accepted it. + +For V2, this is harmless: iavf_vlan_add_reject() in the error +block already kfree'd all ADDING filters, so the success handler +finds nothing to transition. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-4-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 6fb657ec654e8..9ae7c92ae1b1f 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -2501,9 +2501,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->adv_rss_lock); + } + break; ++ case VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN_V2: { + struct iavf_vlan_filter *f; + ++ if (v_retval) ++ break; ++ + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_ADDING) +-- +2.53.0 + diff --git a/queue-6.1/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch b/queue-6.1/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch new file mode 100644 index 0000000000..4de4a268b5 --- /dev/null +++ b/queue-6.1/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch @@ -0,0 +1,87 @@ +From a41b8a9b8e119835d248052783c0ca264298d2be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:13 -0700 +Subject: iavf: rename IAVF_VLAN_IS_NEW to IAVF_VLAN_ADDING + +From: Petr Oros + +[ Upstream commit 70d62b669f1f9080a25278fc90b64309f4ae8959 ] + +Rename the IAVF_VLAN_IS_NEW state to IAVF_VLAN_ADDING to better +describe what the state represents: an ADD request has been sent to +the PF and is waiting for a response. + +This is a pure rename with no behavioral change, preparing for a +cleanup of the VLAN filter state machine. + +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-1-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Stable-dep-of: f2ce65b9b917 ("iavf: stop removing VLAN filters from PF on interface down") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 2 +- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index ee0871d929302..64309bf18ef74 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -158,7 +158,7 @@ struct iavf_vlan { + enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ +- IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ ++ IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ + IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ + IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 951ef350323a2..de01edc5df79b 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -642,7 +642,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) { ++ if (f->state == IAVF_VLAN_ADDING) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +@@ -707,7 +707,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + if (f->state == IAVF_VLAN_ADD) { + vvfl->vlan_id[i] = f->vlan.vid; + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + if (i == count) + break; + } +@@ -771,7 +771,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + vlan->tpid = f->vlan.tpid; + + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + } + } + +@@ -2535,7 +2535,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) ++ if (f->state == IAVF_VLAN_ADDING) + f->state = IAVF_VLAN_ACTIVE; + } + spin_unlock_bh(&adapter->mac_vlan_list_lock); +-- +2.53.0 + diff --git a/queue-6.1/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch b/queue-6.1/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch new file mode 100644 index 0000000000..56f65f9d02 --- /dev/null +++ b/queue-6.1/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch @@ -0,0 +1,233 @@ +From e4092bf6502efb0968cbfa6f8df7cbe6c9858524 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:14 -0700 +Subject: iavf: stop removing VLAN filters from PF on interface down + +From: Petr Oros + +[ Upstream commit f2ce65b9b917474a1a6ce68d357e15fac2aca0f2 ] + +When a VF goes down, the driver currently sends DEL_VLAN to the PF for +every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then +re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING -> +ACTIVE). This round-trip is unnecessary because: + + 1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES, + which already prevents all RX/TX traffic regardless of VLAN filter + state. + + 2. The VLAN filters remaining in PF HW while the VF is down is + harmless - packets matching those filters have nowhere to go with + queues disabled. + + 3. The DEL+ADD cycle during down/up creates race windows where the + VLAN filter list is incomplete. With spoofcheck enabled, the PF + enables TX VLAN filtering on the first non-zero VLAN add, blocking + traffic for any VLANs not yet re-added. + +Remove the entire DISABLE/INACTIVE state machinery: + - Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values + - Remove iavf_restore_filters() and its call from iavf_open() + - Remove VLAN filter handling from iavf_clear_mac_vlan_filters(), + rename it to iavf_clear_mac_filters() + - Remove DEL_VLAN_FILTER scheduling from iavf_down() + - Remove all DISABLE/INACTIVE handling from iavf_del_vlans() + +VLAN filters now stay ACTIVE across down/up cycles. Only explicit +user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN +filter deletion/re-addition. + +Fixes: ed1f5b58ea01 ("i40evf: remove VLAN filters on close") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-2-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 6 +-- + drivers/net/ethernet/intel/iavf/iavf_main.c | 39 ++----------------- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 33 +++------------- + 3 files changed, 12 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 64309bf18ef74..dbbe622dec12f 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -159,10 +159,8 @@ enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ +- IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ +- IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ +- IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +- IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ ++ IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ ++ IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index 667949e8833bf..6346479366aa4 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -875,27 +875,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +-/** +- * iavf_restore_filters +- * @adapter: board private structure +- * +- * Restore existing non MAC filters when VF netdev comes back up +- **/ +-static void iavf_restore_filters(struct iavf_adapter *adapter) +-{ +- struct iavf_vlan_filter *f; +- +- /* re-add all VLAN filters */ +- spin_lock_bh(&adapter->mac_vlan_list_lock); +- +- list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_INACTIVE) +- f->state = IAVF_VLAN_ADD; +- } +- +- spin_unlock_bh(&adapter->mac_vlan_list_lock); +- adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; +-} + + /** + * iavf_get_num_vlans_added - get number of VLANs added +@@ -1322,13 +1301,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) + } + + /** +- * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF +- * yet and mark other to be removed. ++ * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark ++ * others to be removed. + * @adapter: board private structure + **/ +-static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) ++static void iavf_clear_mac_filters(struct iavf_adapter *adapter) + { +- struct iavf_vlan_filter *vlf, *vlftmp; + struct iavf_mac_filter *f, *ftmp; + + spin_lock_bh(&adapter->mac_vlan_list_lock); +@@ -1347,11 +1325,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) + } + } + +- /* disable all VLAN filters */ +- list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, +- list) +- vlf->state = IAVF_VLAN_DISABLE; +- + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +@@ -1447,7 +1420,7 @@ void iavf_down(struct iavf_adapter *adapter) + iavf_napi_disable_all(adapter); + iavf_irq_disable(adapter); + +- iavf_clear_mac_vlan_filters(adapter); ++ iavf_clear_mac_filters(adapter); + iavf_clear_cloud_filters(adapter); + iavf_clear_fdir_filters(adapter); + iavf_clear_adv_rss_conf(adapter); +@@ -1462,8 +1435,6 @@ void iavf_down(struct iavf_adapter *adapter) + */ + if (!list_empty(&adapter->mac_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; +- if (!list_empty(&adapter->vlan_filter_list)) +- adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; + if (!list_empty(&adapter->cloud_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; + if (!list_empty(&adapter->fdir_list_head)) +@@ -4352,8 +4323,6 @@ static int iavf_open(struct net_device *netdev) + + spin_unlock_bh(&adapter->mac_vlan_list_lock); + +- /* Restore filters that were removed with IFF_DOWN */ +- iavf_restore_filters(adapter); + iavf_restore_fdir_filters(adapter); + + iavf_configure(adapter); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index de01edc5df79b..ca7448e096a86 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -808,22 +808,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + spin_lock_bh(&adapter->mac_vlan_list_lock); + + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- /* since VLAN capabilities are not allowed, we dont want to send +- * a VLAN delete request because it will most likely fail and +- * create unnecessary errors/noise, so just free the VLAN +- * filters marked for removal to enable bailing out before +- * sending a virtchnl message +- */ + if (f->state == IAVF_VLAN_REMOVE && + !VLAN_FILTERING_ALLOWED(adapter)) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else if (f->state == IAVF_VLAN_DISABLE && +- !VLAN_FILTERING_ALLOWED(adapter)) { +- f->state = IAVF_VLAN_INACTIVE; +- } else if (f->state == IAVF_VLAN_REMOVE || +- f->state == IAVF_VLAN_DISABLE) { ++ } else if (f->state == IAVF_VLAN_REMOVE) { + count++; + } + } +@@ -855,13 +845,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE) { +- vvfl->vlan_id[i] = f->vlan.vid; +- f->state = IAVF_VLAN_INACTIVE; +- i++; +- if (i == count) +- break; +- } else if (f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; + list_del(&f->list); + kfree(f); +@@ -906,8 +890,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE || +- f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; + struct virtchnl_vlan *vlan; +@@ -921,13 +904,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- if (f->state == IAVF_VLAN_DISABLE) { +- f->state = IAVF_VLAN_INACTIVE; +- } else { +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; +- } ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; + i++; + if (i == count) + break; +-- +2.53.0 + diff --git a/queue-6.1/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch b/queue-6.1/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch new file mode 100644 index 0000000000..085de6f1bb --- /dev/null +++ b/queue-6.1/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch @@ -0,0 +1,189 @@ +From 37c98cca0bcfaf5e8c3e81ee3b2b68aecbb5473f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:15 -0700 +Subject: iavf: wait for PF confirmation before removing VLAN filters + +From: Petr Oros + +[ Upstream commit bbcbe4ed70dea948849549af7edf44bd42bbd695 ] + +The VLAN filter DELETE path was asymmetric with the ADD path: ADD +waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE +immediately frees the filter struct after sending the DEL message +without waiting for the PF response. + +This is problematic because: + - If the PF rejects the DEL, the filter remains in HW but the driver + has already freed the tracking structure, losing sync. + - Race conditions between DEL pending and other operations + (add, reset) cannot be properly resolved if the filter struct + is already gone. + +Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric: + + REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree + -> PF rejects -> ACTIVE + +In iavf_del_vlans(), transition filters from REMOVE to REMOVING +instead of immediately freeing them. The new DEL completion handler +in iavf_virtchnl_completion() frees filters on success or reverts +them to ACTIVE on error. + +Update iavf_add_vlan() to handle the REMOVING state: if a DEL is +pending and the user re-adds the same VLAN, queue it for ADD so +it gets re-programmed after the PF processes the DEL. + +The !VLAN_FILTERING_ALLOWED early-exit path still frees filters +directly since no PF message is sent in that case. + +Also update iavf_del_vlan() to skip filters already in REMOVING +state: DEL has been sent to PF and the completion handler will +free the filter when PF confirms. Without this guard, the sequence +DEL(pending) -> user-del -> second DEL could cause the PF to return +an error for the second DEL (filter already gone), causing the +completion handler to incorrectly revert a deleted filter back to +ACTIVE. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-3-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 1 + + drivers/net/ethernet/intel/iavf/iavf_main.c | 13 ++++--- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 37 +++++++++++++------ + 3 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index dbbe622dec12f..468449df9756e 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -161,6 +161,7 @@ enum iavf_vlan_state_t { + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ ++ IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index 6346479366aa4..0cf6260a83fb2 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -831,10 +831,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, + adapter->num_vlan_filters++; + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); + } else if (f->state == IAVF_VLAN_REMOVE) { +- /* Re-add the filter since we cannot tell whether the +- * pending delete has already been processed by the PF. +- * A duplicate add is harmless. +- */ ++ /* DEL not yet sent to PF, cancel it */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else if (f->state == IAVF_VLAN_REMOVING) { ++ /* DEL already sent to PF, re-add after completion */ + f->state = IAVF_VLAN_ADD; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_ADD_VLAN_FILTER); +@@ -865,11 +865,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else { ++ } else if (f->state != IAVF_VLAN_REMOVING) { + f->state = IAVF_VLAN_REMOVE; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_DEL_VLAN_FILTER); + } ++ /* If REMOVING, DEL is already sent to PF; completion ++ * handler will free the filter when PF confirms. ++ */ + } + + spin_unlock_bh(&adapter->mac_vlan_list_lock); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index ca7448e096a86..6fb657ec654e8 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -844,12 +844,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -889,7 +887,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; +@@ -904,9 +902,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -2033,10 +2029,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); + wake_up(&adapter->vc_waitqueue); + break; +- case VIRTCHNL_OP_DEL_VLAN: +- dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", +- iavf_stat_str(&adapter->hw, v_retval)); +- break; + case VIRTCHNL_OP_DEL_ETH_ADDR: + dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", + iavf_stat_str(&adapter->hw, v_retval)); +@@ -2520,6 +2512,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + break; ++ case VIRTCHNL_OP_DEL_VLAN: ++ case VIRTCHNL_OP_DEL_VLAN_V2: { ++ struct iavf_vlan_filter *f, *ftmp; ++ ++ spin_lock_bh(&adapter->mac_vlan_list_lock); ++ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, ++ list) { ++ if (f->state == IAVF_VLAN_REMOVING) { ++ if (v_retval) { ++ /* PF rejected DEL, keep filter */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else { ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; ++ } ++ } ++ } ++ spin_unlock_bh(&adapter->mac_vlan_list_lock); ++ } ++ break; + case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: + /* PF enabled vlan strip on this VF. + * Update netdev->features if needed to be in sync with ethtool. +-- +2.53.0 + diff --git a/queue-6.1/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch b/queue-6.1/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch new file mode 100644 index 0000000000..0bc4e7b459 --- /dev/null +++ b/queue-6.1/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch @@ -0,0 +1,130 @@ +From 3e713ff22205e42688356ef25b0a56d2d6b74f6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:17 -0700 +Subject: ice: fix NULL pointer dereference in ice_reset_all_vfs() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Petr Oros + +[ Upstream commit 54ef02487914c24170c7e1c061e45212dc55365e ] + +ice_reset_all_vfs() ignores the return value of ice_vf_rebuild_vsi(). +When the VSI rebuild fails (e.g. during NVM firmware update via +nvmupdate64e), ice_vsi_rebuild() tears down the VSI on its error path, +leaving txq_map and rxq_map as NULL. The subsequent unconditional call +to ice_vf_post_vsi_rebuild() leads to a NULL pointer dereference in +ice_ena_vf_q_mappings() when it accesses vsi->txq_map[0]. + +The single-VF reset path in ice_reset_vf() already handles this +correctly by checking the return value of ice_vf_reconfig_vsi() and +skipping ice_vf_post_vsi_rebuild() on failure. + +Apply the same pattern to ice_reset_all_vfs(): check the return value +of ice_vf_rebuild_vsi() and skip ice_vf_post_vsi_rebuild() and +ice_eswitch_attach_vf() on failure. The VF is left safely disabled +(ICE_VF_STATE_INIT not set, VFGEN_RSTAT not set to VFACTIVE) and can +be recovered via a VFLR triggered by a PCI reset of the VF +(sysfs reset or driver rebind). + +Note that this patch does not prevent the VF VSI rebuild from failing +during NVM update — the underlying cause is firmware being in a +transitional state while the EMP reset is processed, which can cause +Admin Queue commands (ice_add_vsi, ice_cfg_vsi_lan) to fail. This +patch only prevents the subsequent NULL pointer dereference that +crashes the kernel when the rebuild does fail. + + crash> bt + PID: 50795 TASK: ff34c9ee708dc680 CPU: 1 COMMAND: "kworker/u512:5" + #0 [ff72159bcfe5bb50] machine_kexec at ffffffffaa8850ee + #1 [ff72159bcfe5bba8] __crash_kexec at ffffffffaaa15fba + #2 [ff72159bcfe5bc68] crash_kexec at ffffffffaaa16540 + #3 [ff72159bcfe5bc70] oops_end at ffffffffaa837eda + #4 [ff72159bcfe5bc90] page_fault_oops at ffffffffaa893997 + #5 [ff72159bcfe5bce8] exc_page_fault at ffffffffab528595 + #6 [ff72159bcfe5bd10] asm_exc_page_fault at ffffffffab600bb2 + [exception RIP: ice_ena_vf_q_mappings+0x79] + RIP: ffffffffc0a85b29 RSP: ff72159bcfe5bdc8 RFLAGS: 00010206 + RAX: 00000000000f0000 RBX: ff34c9efc9c00000 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: 0000000000000010 RDI: ff34c9efc9c00000 + RBP: ff34c9efc27d4828 R8: 0000000000000093 R9: 0000000000000040 + R10: ff34c9efc27d4828 R11: 0000000000000040 R12: 0000000000100000 + R13: 0000000000000010 R14: R15: + ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 + #7 [ff72159bcfe5bdf8] ice_sriov_post_vsi_rebuild at ffffffffc0a85e2e [ice] + #8 [ff72159bcfe5be08] ice_reset_all_vfs at ffffffffc0a920b4 [ice] + #9 [ff72159bcfe5be48] ice_service_task at ffffffffc0a31519 [ice] + #10 [ff72159bcfe5be88] process_one_work at ffffffffaa93dca4 + #11 [ff72159bcfe5bec8] worker_thread at ffffffffaa93e9de + #12 [ff72159bcfe5bf18] kthread at ffffffffaa946663 + #13 [ff72159bcfe5bf50] ret_from_fork at ffffffffaa8086b9 + + The panic occurs attempting to dereference the NULL pointer in RDX at + ice_sriov.c:294, which loads vsi->txq_map (offset 0x4b8 in ice_vsi). + + The faulting VSI is an allocated slab object but not fully initialized + after a failed ice_vsi_rebuild(): + + crash> struct ice_vsi 0xff34c9efc27d4828 + netdev = 0x0, + rx_rings = 0x0, + tx_rings = 0x0, + q_vectors = 0x0, + txq_map = 0x0, + rxq_map = 0x0, + alloc_txq = 0x10, + num_txq = 0x10, + alloc_rxq = 0x10, + num_rxq = 0x10, + + The nvmupdate64e process was performing NVM firmware update: + + crash> bt 0xff34c9edd1a30000 + PID: 49858 TASK: ff34c9edd1a30000 CPU: 1 COMMAND: "nvmupdate64e" + #0 [ff72159bcd617618] __schedule at ffffffffab5333f8 + #4 [ff72159bcd617750] ice_sq_send_cmd at ffffffffc0a35347 [ice] + #5 [ff72159bcd6177a8] ice_sq_send_cmd_retry at ffffffffc0a35b47 [ice] + #6 [ff72159bcd617810] ice_aq_send_cmd at ffffffffc0a38018 [ice] + #7 [ff72159bcd617848] ice_aq_read_nvm at ffffffffc0a40254 [ice] + #8 [ff72159bcd6178b8] ice_read_flat_nvm at ffffffffc0a4034c [ice] + #9 [ff72159bcd617918] ice_devlink_nvm_snapshot at ffffffffc0a6ffa5 [ice] + + dmesg: + ice 0000:13:00.0: firmware recommends not updating fw.mgmt, as it + may result in a downgrade. continuing anyways + ice 0000:13:00.1: ice_init_nvm failed -5 + ice 0000:13:00.1: Rebuild failed, unload and reload driver + +Fixes: 12bb018c538c ("ice: Refactor VF reset") +Signed-off-by: Petr Oros +Tested-by: Rafal Romanowski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-5-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +index d146259c7b82f..7be59008ea1a5 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +@@ -509,7 +509,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) + ice_vf_ctrl_invalidate_vsi(vf); + + ice_vf_pre_vsi_rebuild(vf); +- ice_vf_rebuild_vsi(vf); ++ if (ice_vf_rebuild_vsi(vf)) { ++ dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", ++ vf->vf_id); ++ mutex_unlock(&vf->cfg_lock); ++ continue; ++ } + ice_vf_post_vsi_rebuild(vf); + + mutex_unlock(&vf->cfg_lock); +-- +2.53.0 + diff --git a/queue-6.1/ice-pull-common-tasks-into-ice_vf_post_vsi_rebuild.patch b/queue-6.1/ice-pull-common-tasks-into-ice_vf_post_vsi_rebuild.patch new file mode 100644 index 0000000000..01846f7dde --- /dev/null +++ b/queue-6.1/ice-pull-common-tasks-into-ice_vf_post_vsi_rebuild.patch @@ -0,0 +1,92 @@ +From 712cf6bb6097264f8c3c2410b2931e03a2a39e90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Jan 2023 17:16:47 -0800 +Subject: ice: Pull common tasks into ice_vf_post_vsi_rebuild + +From: Jacob Keller + +[ Upstream commit aeead3d04fa050a94ed314cc5de97125a957dc9f ] + +The Single Root IOV implementation of .post_vsi_rebuild performs some tasks +that will ultimately need to be shared with the Scalable IOV implementation +such as rebuilding the host configuration. + +Refactor by introducing a new wrapper function, ice_vf_post_vsi_rebuild +which performs the tasks that will be shared between SR-IOV and Scalable +IOV. Move the ice_vf_rebuild_host_cfg and ice_vf_set_initialized calls into +this wrapper. Then call the implementation specific post_vsi_rebuild +handler afterwards. + +This ensures that we will properly re-initialize filters and expected +settings for both SR-IOV and Scalable IOV. + +Signed-off-by: Jacob Keller +Tested-by: Marek Szlosek +Signed-off-by: Tony Nguyen +Stable-dep-of: 54ef02487914 ("ice: fix NULL pointer dereference in ice_reset_all_vfs()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_sriov.c | 2 -- + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 19 +++++++++++++++++-- + 2 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c +index b719e9a771e36..148712037bcbb 100644 +--- a/drivers/net/ethernet/intel/ice/ice_sriov.c ++++ b/drivers/net/ethernet/intel/ice/ice_sriov.c +@@ -841,8 +841,6 @@ static int ice_sriov_vsi_rebuild(struct ice_vf *vf) + */ + static void ice_sriov_post_vsi_rebuild(struct ice_vf *vf) + { +- ice_vf_rebuild_host_cfg(vf); +- ice_vf_set_initialized(vf); + ice_ena_vf_mappings(vf); + wr32(&vf->pf->hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE); + } +diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +index 9dbe6e9bb1f79..d146259c7b82f 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +@@ -270,6 +270,21 @@ static int ice_vf_rebuild_vsi(struct ice_vf *vf) + return 0; + } + ++/** ++ * ice_vf_post_vsi_rebuild - Reset tasks that occur after VSI rebuild ++ * @vf: the VF being reset ++ * ++ * Perform reset tasks which must occur after the VSI has been re-created or ++ * rebuilt during a VF reset. ++ */ ++static void ice_vf_post_vsi_rebuild(struct ice_vf *vf) ++{ ++ ice_vf_rebuild_host_cfg(vf); ++ ice_vf_set_initialized(vf); ++ ++ vf->vf_ops->post_vsi_rebuild(vf); ++} ++ + /** + * ice_is_any_vf_in_unicast_promisc - check if any VF(s) + * are in unicast promiscuous mode +@@ -495,7 +510,7 @@ void ice_reset_all_vfs(struct ice_pf *pf) + + ice_vf_pre_vsi_rebuild(vf); + ice_vf_rebuild_vsi(vf); +- vf->vf_ops->post_vsi_rebuild(vf); ++ ice_vf_post_vsi_rebuild(vf); + + mutex_unlock(&vf->cfg_lock); + } +@@ -647,7 +662,7 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags) + goto out_unlock; + } + +- vf->vf_ops->post_vsi_rebuild(vf); ++ ice_vf_post_vsi_rebuild(vf); + vsi = ice_get_vf_vsi(vf); + if (WARN_ON(!vsi)) { + err = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.1/ima-check-return-value-of-crypto_shash_final-in-boot.patch b/queue-6.1/ima-check-return-value-of-crypto_shash_final-in-boot.patch new file mode 100644 index 0000000000..79d0716b1e --- /dev/null +++ b/queue-6.1/ima-check-return-value-of-crypto_shash_final-in-boot.patch @@ -0,0 +1,41 @@ +From 50076e4cd68738129b4a61f13047fab5b16c5b00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 18:40:15 -0800 +Subject: ima: check return value of crypto_shash_final() in boot aggregate + +From: Daniel Hodges + +[ Upstream commit 870819434c8dfcc3158033b66e7851b81bb17e21 ] + +The return value of crypto_shash_final() is not checked in +ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the +function returns success and a corrupted boot aggregate digest could +be used for IMA measurements. + +Capture the return value and propagate any error to the caller. + +Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash") +Signed-off-by: Daniel Hodges +Reviewed-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 64499056648ad..c5153f0d7306d 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -837,7 +837,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, + } + } + if (!rc) +- crypto_shash_final(shash, digest); ++ rc = crypto_shash_final(shash, digest); + return rc; + } + +-- +2.53.0 + diff --git a/queue-6.1/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch b/queue-6.1/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch new file mode 100644 index 0000000000..2581409cd6 --- /dev/null +++ b/queue-6.1/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch @@ -0,0 +1,145 @@ +From f0031f1d72c29ddaa9239c95988f8df06cb37692 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:22 +0200 +Subject: ipv4: add new arguments to udp_tunnel_dst_lookup() + +From: Beniamino Galvani + +[ Upstream commit 72fc68c6356b663a8763f02d9b0ec773d59a4949 ] + +We want to make the function more generic so that it can be used by +other UDP tunnel implementations such as geneve and vxlan. To do that, +add the following arguments: + + - source and destination UDP port; + - ifindex of the output interface, needed by vxlan; + - the tos, because in some cases it is not taken from struct + ip_tunnel_info (for example, when it's inherited from the inner + packet); + - the dst cache, because not all tunnel types (e.g. vxlan) want to + use the one from struct ip_tunnel_info. + +With these parameters, the function no longer needs the full struct +ip_tunnel_info as argument and we can pass only the relevant part of +it (struct ip_tunnel_key). + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 11 +++++++---- + include/net/udp_tunnel.h | 8 +++++--- + net/ipv4/udp_tunnel_core.c | 26 +++++++++++++------------- + 3 files changed, 25 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 1a9a43ed462a8..385cc386ecaee 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -325,8 +325,10 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, +- use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, &info->key, ++ 0, 0, key->tos, ++ use_cache ? ++ (struct dst_cache *)&info->dst_cache : NULL); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -505,8 +507,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct rtable *rt; + __be32 saddr; + +- rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, +- info, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, ++ &info->key, 0, 0, info->key.tos, ++ use_cache ? &info->dst_cache : NULL); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index fe843d1b42efe..f757c061aaa88 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -163,9 +163,11 @@ void udp_tunnel_sock_release(struct socket *sock); + + struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- bool use_cache); ++ struct net *net, int oif, ++ __be32 *saddr, ++ const struct ip_tunnel_key *key, ++ __be16 sport, __be16 dport, u8 tos, ++ struct dst_cache *dst_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index c3e6a88487dbc..b04bea12c18f0 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -206,31 +206,31 @@ EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + + struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- bool use_cache) ++ struct net *net, int oif, ++ __be32 *saddr, ++ const struct ip_tunnel_key *key, ++ __be16 sport, __be16 dport, u8 tos, ++ struct dst_cache *dst_cache) + { +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif + struct rtable *rt = NULL; + struct flowi4 fl4; +- __u8 tos; + + #ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { ++ if (dst_cache) { + rt = dst_cache_get_ip4(dst_cache, saddr); + if (rt) + return rt; + } + #endif ++ + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; + fl4.flowi4_proto = IPPROTO_UDP; +- fl4.daddr = info->key.u.ipv4.dst; +- fl4.saddr = info->key.u.ipv4.src; +- tos = info->key.tos; ++ fl4.flowi4_oif = oif; ++ fl4.daddr = key->u.ipv4.dst; ++ fl4.saddr = key->u.ipv4.src; ++ fl4.fl4_dport = dport; ++ fl4.fl4_sport = sport; + fl4.flowi4_tos = RT_TOS(tos); + + rt = ip_route_output_key(net, &fl4); +@@ -244,7 +244,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + return ERR_PTR(-ELOOP); + } + #ifdef CONFIG_DST_CACHE +- if (use_cache) ++ if (dst_cache) + dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); + #endif + *saddr = fl4.saddr; +-- +2.53.0 + diff --git a/queue-6.1/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch b/queue-6.1/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch new file mode 100644 index 0000000000..64cdd467e1 --- /dev/null +++ b/queue-6.1/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch @@ -0,0 +1,83 @@ +From 219520f9ebfc33b489cc358e37dc325315ce8617 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:21 +0200 +Subject: ipv4: remove "proto" argument from udp_tunnel_dst_lookup() + +From: Beniamino Galvani + +[ Upstream commit 78f3655adcb52412275f282267ee771421731632 ] + +The function is now UDP-specific, the protocol is always IPPROTO_UDP. + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 4 ++-- + include/net/udp_tunnel.h | 2 +- + net/ipv4/udp_tunnel_core.c | 4 ++-- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index bbc246d27f88a..1a9a43ed462a8 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -326,7 +326,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + return -ESHUTDOWN; + + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, +- IPPROTO_UDP, use_cache); ++ use_cache); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -506,7 +506,7 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + __be32 saddr; + + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, +- info, IPPROTO_UDP, use_cache); ++ info, use_cache); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index f9a66a33e958b..fe843d1b42efe 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -165,7 +165,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, __be32 *saddr, + const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); ++ bool use_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 386e983560094..c3e6a88487dbc 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -208,7 +208,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, __be32 *saddr, + const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache) ++ bool use_cache) + { + #ifdef CONFIG_DST_CACHE + struct dst_cache *dst_cache; +@@ -227,7 +227,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + #endif + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; +- fl4.flowi4_proto = protocol; ++ fl4.flowi4_proto = IPPROTO_UDP; + fl4.daddr = info->key.u.ipv4.dst; + fl4.saddr = info->key.u.ipv4.src; + tos = info->key.tos; +-- +2.53.0 + diff --git a/queue-6.1/ipv4-rename-and-move-ip_route_output_tunnel.patch b/queue-6.1/ipv4-rename-and-move-ip_route_output_tunnel.patch new file mode 100644 index 0000000000..18eee5108c --- /dev/null +++ b/queue-6.1/ipv4-rename-and-move-ip_route_output_tunnel.patch @@ -0,0 +1,211 @@ +From 8ff32339adb2a56fddc6863b912fcfb7a2b76728 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:20 +0200 +Subject: ipv4: rename and move ip_route_output_tunnel() + +From: Beniamino Galvani + +[ Upstream commit bf3fcbf7e7a08015d3b169bad6281b29d45c272d ] + +At the moment ip_route_output_tunnel() is used only by bareudp. +Ideally, other UDP tunnel implementations should use it, but to do so +the function needs to accept new parameters that are specific for UDP +tunnels, such as the ports. + +Prepare for these changes by renaming the function to +udp_tunnel_dst_lookup() and move it to file +net/ipv4/udp_tunnel_core.c. + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 8 +++---- + include/net/route.h | 6 ----- + include/net/udp_tunnel.h | 6 +++++ + net/ipv4/route.c | 48 -------------------------------------- + net/ipv4/udp_tunnel_core.c | 48 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 58 insertions(+), 58 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index cfbc0240126ef..bbc246d27f88a 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -325,8 +325,8 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, info, +- IPPROTO_UDP, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, ++ IPPROTO_UDP, use_cache); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -505,8 +505,8 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct rtable *rt; + __be32 saddr; + +- rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, +- info, IPPROTO_UDP, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, ++ info, IPPROTO_UDP, use_cache); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/route.h b/include/net/route.h +index cdca622c5c6fe..568da3b95b06e 100644 +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -139,12 +139,6 @@ static inline struct rtable *__ip_route_output_key(struct net *net, + + struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp, + const struct sock *sk); +-struct rtable *ip_route_output_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); +- + struct dst_entry *ipv4_blackhole_route(struct net *net, + struct dst_entry *dst_orig); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index cd2bd3826d168..f9a66a33e958b 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -161,6 +161,12 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + + void udp_tunnel_sock_release(struct socket *sock); + ++struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, __be32 *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache); ++ + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, + int md_size); +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 86893963b930d..60516c6ae62e0 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -2922,54 +2922,6 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4, + } + EXPORT_SYMBOL_GPL(ip_route_output_flow); + +-struct rtable *ip_route_output_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache) +-{ +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif +- struct rtable *rt = NULL; +- struct flowi4 fl4; +- __u8 tos; +- +-#ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { +- rt = dst_cache_get_ip4(dst_cache, saddr); +- if (rt) +- return rt; +- } +-#endif +- memset(&fl4, 0, sizeof(fl4)); +- fl4.flowi4_mark = skb->mark; +- fl4.flowi4_proto = protocol; +- fl4.daddr = info->key.u.ipv4.dst; +- fl4.saddr = info->key.u.ipv4.src; +- tos = info->key.tos; +- fl4.flowi4_tos = RT_TOS(tos); +- +- rt = ip_route_output_key(net, &fl4); +- if (IS_ERR(rt)) { +- netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); +- return ERR_PTR(-ENETUNREACH); +- } +- if (rt->dst.dev == dev) { /* is this necessary? */ +- netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); +- ip_rt_put(rt); +- return ERR_PTR(-ELOOP); +- } +-#ifdef CONFIG_DST_CACHE +- if (use_cache) +- dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); +-#endif +- *saddr = fl4.saddr; +- return rt; +-} +-EXPORT_SYMBOL_GPL(ip_route_output_tunnel); +- + /* called with rcu_read_lock held */ + static int rt_fill_info(struct net *net, __be32 dst, __be32 src, + struct rtable *rt, u32 table_id, dscp_t dscp, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 732e21b75ba28..386e983560094 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -204,4 +204,52 @@ struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + } + EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + ++struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, __be32 *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache) ++{ ++#ifdef CONFIG_DST_CACHE ++ struct dst_cache *dst_cache; ++#endif ++ struct rtable *rt = NULL; ++ struct flowi4 fl4; ++ __u8 tos; ++ ++#ifdef CONFIG_DST_CACHE ++ dst_cache = (struct dst_cache *)&info->dst_cache; ++ if (use_cache) { ++ rt = dst_cache_get_ip4(dst_cache, saddr); ++ if (rt) ++ return rt; ++ } ++#endif ++ memset(&fl4, 0, sizeof(fl4)); ++ fl4.flowi4_mark = skb->mark; ++ fl4.flowi4_proto = protocol; ++ fl4.daddr = info->key.u.ipv4.dst; ++ fl4.saddr = info->key.u.ipv4.src; ++ tos = info->key.tos; ++ fl4.flowi4_tos = RT_TOS(tos); ++ ++ rt = ip_route_output_key(net, &fl4); ++ if (IS_ERR(rt)) { ++ netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); ++ return ERR_PTR(-ENETUNREACH); ++ } ++ if (rt->dst.dev == dev) { /* is this necessary? */ ++ netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); ++ ip_rt_put(rt); ++ return ERR_PTR(-ELOOP); ++ } ++#ifdef CONFIG_DST_CACHE ++ if (use_cache) ++ dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); ++#endif ++ *saddr = fl4.saddr; ++ return rt; ++} ++EXPORT_SYMBOL_GPL(udp_tunnel_dst_lookup); ++ + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.1/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch b/queue-6.1/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch new file mode 100644 index 0000000000..4500f3362f --- /dev/null +++ b/queue-6.1/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch @@ -0,0 +1,71 @@ +From 9b210cc23607431a51252fc22d220bb659ef3ff7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 10:35:05 +0000 +Subject: ipv6: fix possible UAF in icmpv6_rcv() + +From: Eric Dumazet + +[ Upstream commit f996edd7615e686ada141b7f3395025729ff8ccb ] + +Caching saddr and daddr before pskb_pull() is problematic +since skb->head can change. + +Remove these temporary variables: + +- We only access &ipv6_hdr(skb)->saddr and &ipv6_hdr(skb)->daddr + when net_dbg_ratelimited() is called in the slow path. + +- Avoid potential future misuse after pskb_pull() call. + +Fixes: 4b3418fba0fe ("ipv6: icmp: include addresses in debug messages") +Signed-off-by: Eric Dumazet +Reviewed-by: Fernando Fernandez Mancera +Reviewed-by: Joe Damato +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260416103505.2380753-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/icmp.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index 80eabb22d144f..877cb5e8ded7b 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -889,7 +889,6 @@ static int icmpv6_rcv(struct sk_buff *skb) + struct net *net = dev_net(skb->dev); + struct net_device *dev = icmp6_dev(skb); + struct inet6_dev *idev = __in6_dev_get(dev); +- const struct in6_addr *saddr, *daddr; + struct icmp6hdr *hdr; + u8 type; + +@@ -920,12 +919,10 @@ static int icmpv6_rcv(struct sk_buff *skb) + + __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS); + +- saddr = &ipv6_hdr(skb)->saddr; +- daddr = &ipv6_hdr(skb)->daddr; +- + if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { + net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + goto csum_error; + } + +@@ -1007,7 +1004,8 @@ static int icmpv6_rcv(struct sk_buff *skb) + break; + + net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + + /* + * error of unknown type. +-- +2.53.0 + diff --git a/queue-6.1/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch b/queue-6.1/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch new file mode 100644 index 0000000000..dab4f6eb70 --- /dev/null +++ b/queue-6.1/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch @@ -0,0 +1,262 @@ +From 686dd67831df2e5e0825c08b6613a3ffabe4da4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 13:55:25 +0200 +Subject: ipv6: rename and move ip6_dst_lookup_tunnel() + +From: Beniamino Galvani + +[ Upstream commit fc47e86dbfb75a864c0c9dd8e78affb6506296bb ] + +At the moment ip6_dst_lookup_tunnel() is used only by bareudp. +Ideally, other UDP tunnel implementations should use it, but to do so +the function needs to accept new parameters that are specific for UDP +tunnels, such as the ports. + +Prepare for these changes by renaming the function to +udp_tunnel6_dst_lookup() and move it to file +net/ipv6/ip6_udp_tunnel.c. + +This is similar to what already done for IPv4 in commit bf3fcbf7e7a0 +("ipv4: rename and move ip_route_output_tunnel()"). + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 10 +++--- + include/net/ipv6.h | 6 ---- + include/net/udp_tunnel.h | 7 ++++ + net/ipv6/ip6_output.c | 68 -------------------------------------- + net/ipv6/ip6_udp_tunnel.c | 69 +++++++++++++++++++++++++++++++++++++++ + 5 files changed, 81 insertions(+), 79 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 385cc386ecaee..150049d9a81a7 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -393,8 +393,8 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, &saddr, info, +- IPPROTO_UDP, use_cache); ++ dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, &saddr, info, ++ IPPROTO_UDP, use_cache); + if (IS_ERR(dst)) + return PTR_ERR(dst); + +@@ -520,9 +520,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + +- dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, +- &saddr, info, IPPROTO_UDP, +- use_cache); ++ dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, ++ &saddr, info, IPPROTO_UDP, ++ use_cache); + if (IS_ERR(dst)) + return PTR_ERR(dst); + +diff --git a/include/net/ipv6.h b/include/net/ipv6.h +index f4307b35294cf..e4715ac2ed672 100644 +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -1098,12 +1098,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, st + struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, + const struct in6_addr *final_dst, + bool connected); +-struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, struct socket *sock, +- struct in6_addr *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); + struct dst_entry *ip6_blackhole_route(struct net *net, + struct dst_entry *orig_dst); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index f757c061aaa88..7421fa1d5ec96 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -168,6 +168,13 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + const struct ip_tunnel_key *key, + __be16 sport, __be16 dport, u8 tos, + struct dst_cache *dst_cache); ++struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, ++ struct socket *sock, ++ struct in6_addr *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 4ea4da0e71c94..1e491fa7793ad 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1305,74 +1305,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, + } + EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); + +-/** +- * ip6_dst_lookup_tunnel - perform route lookup on tunnel +- * @skb: Packet for which lookup is done +- * @dev: Tunnel device +- * @net: Network namespace of tunnel device +- * @sock: Socket which provides route info +- * @saddr: Memory to store the src ip address +- * @info: Tunnel information +- * @protocol: IP protocol +- * @use_cache: Flag to enable cache usage +- * This function performs a route lookup on a tunnel +- * +- * It returns a valid dst pointer and stores src address to be used in +- * tunnel in param saddr on success, else a pointer encoded error code. +- */ +- +-struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, +- struct socket *sock, +- struct in6_addr *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, +- bool use_cache) +-{ +- struct dst_entry *dst = NULL; +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif +- struct flowi6 fl6; +- __u8 prio; +- +-#ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { +- dst = dst_cache_get_ip6(dst_cache, saddr); +- if (dst) +- return dst; +- } +-#endif +- memset(&fl6, 0, sizeof(fl6)); +- fl6.flowi6_mark = skb->mark; +- fl6.flowi6_proto = protocol; +- fl6.daddr = info->key.u.ipv6.dst; +- fl6.saddr = info->key.u.ipv6.src; +- prio = info->key.tos; +- fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); +- +- dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, +- NULL); +- if (IS_ERR(dst)) { +- netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); +- return ERR_PTR(-ENETUNREACH); +- } +- if (dst->dev == dev) { /* is this necessary? */ +- netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); +- dst_release(dst); +- return ERR_PTR(-ELOOP); +- } +-#ifdef CONFIG_DST_CACHE +- if (use_cache) +- dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); +-#endif +- *saddr = fl6.saddr; +- return dst; +-} +-EXPORT_SYMBOL_GPL(ip6_dst_lookup_tunnel); +- + static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, + gfp_t gfp) + { +diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c +index cdc4d4ee24206..7aef559e60ec5 100644 +--- a/net/ipv6/ip6_udp_tunnel.c ++++ b/net/ipv6/ip6_udp_tunnel.c +@@ -1,3 +1,4 @@ ++ + // SPDX-License-Identifier: GPL-2.0-only + #include + #include +@@ -111,4 +112,72 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + } + EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); + ++/** ++ * udp_tunnel6_dst_lookup - perform route lookup on UDP tunnel ++ * @skb: Packet for which lookup is done ++ * @dev: Tunnel device ++ * @net: Network namespace of tunnel device ++ * @sock: Socket which provides route info ++ * @saddr: Memory to store the src ip address ++ * @info: Tunnel information ++ * @protocol: IP protocol ++ * @use_cache: Flag to enable cache usage ++ * This function performs a route lookup on a UDP tunnel ++ * ++ * It returns a valid dst pointer and stores src address to be used in ++ * tunnel in param saddr on success, else a pointer encoded error code. ++ */ ++ ++struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, ++ struct socket *sock, ++ struct in6_addr *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, ++ bool use_cache) ++{ ++ struct dst_entry *dst = NULL; ++#ifdef CONFIG_DST_CACHE ++ struct dst_cache *dst_cache; ++#endif ++ struct flowi6 fl6; ++ __u8 prio; ++ ++#ifdef CONFIG_DST_CACHE ++ dst_cache = (struct dst_cache *)&info->dst_cache; ++ if (use_cache) { ++ dst = dst_cache_get_ip6(dst_cache, saddr); ++ if (dst) ++ return dst; ++ } ++#endif ++ memset(&fl6, 0, sizeof(fl6)); ++ fl6.flowi6_mark = skb->mark; ++ fl6.flowi6_proto = protocol; ++ fl6.daddr = info->key.u.ipv6.dst; ++ fl6.saddr = info->key.u.ipv6.src; ++ prio = info->key.tos; ++ fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); ++ ++ dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, ++ NULL); ++ if (IS_ERR(dst)) { ++ netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); ++ return ERR_PTR(-ENETUNREACH); ++ } ++ if (dst->dev == dev) { /* is this necessary? */ ++ netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); ++ dst_release(dst); ++ return ERR_PTR(-ELOOP); ++ } ++#ifdef CONFIG_DST_CACHE ++ if (use_cache) ++ dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); ++#endif ++ *saddr = fl6.saddr; ++ return dst; ++} ++EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup); ++ + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.1/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch b/queue-6.1/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch new file mode 100644 index 0000000000..b8e105b8d8 --- /dev/null +++ b/queue-6.1/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch @@ -0,0 +1,97 @@ +From 1c982f69261f916fe3c0ddf0ebf2b9abdce56841 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:40:29 +0800 +Subject: ipvs: fix MTU check for GSO packets in tunnel mode + +From: Yingnan Zhang <342144303@qq.com> + +[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ] + +Currently, IPVS skips MTU checks for GSO packets by excluding them with +the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel +mode encapsulates GSO packets with IPIP headers. + +The issue manifests in two ways: + +1. MTU violation after encapsulation: + When a GSO packet passes through IPVS tunnel mode, the original MTU + check is bypassed. After adding the IPIP tunnel header, the packet + size may exceed the outgoing interface MTU, leading to unexpected + fragmentation at the IP layer. + +2. Fragmentation with problematic IP IDs: + When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments + is fragmented after encapsulation, each segment gets a sequentially + incremented IP ID (0, 1, 2, ...). This happens because: + + a) The GSO packet bypasses MTU check and gets encapsulated + b) At __ip_finish_output, the oversized GSO packet is split into + separate SKBs (one per segment), with IP IDs incrementing + c) Each SKB is then fragmented again based on the actual MTU + + This sequential IP ID allocation differs from the expected behavior + and can cause issues with fragment reassembly and packet tracking. + +Fix this by properly validating GSO packets using +skb_gso_validate_network_len(). This function correctly validates +whether the GSO segments will fit within the MTU after segmentation. If +validation fails, send an ICMP Fragmentation Needed message to enable +proper PMTU discovery. + +Fixes: 4cdd34084d53 ("netfilter: nf_conntrack_ipv6: improve fragmentation handling") +Signed-off-by: Yingnan Zhang <342144303@qq.com> +Acked-by: Julian Anastasov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index 038f0bbbc9f6d..9793eb8884373 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -103,6 +103,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest) + return dest_dst; + } + ++/* Based on ip_exceeds_mtu(). */ ++static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) ++{ ++ if (skb->len <= mtu) ++ return false; ++ ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) ++ return false; ++ ++ return true; ++} ++ + static inline bool + __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + { +@@ -112,10 +124,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + */ + if (IP6CB(skb)->frag_max_size > mtu) + return true; /* largest fragment violate MTU */ +- } +- else if (skb->len > mtu && !skb_is_gso(skb)) { ++ } else if (ip_vs_exceeds_mtu(skb, mtu)) + return true; /* Packet size violate MTU size */ +- } ++ + return false; + } + +@@ -233,7 +244,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, + return true; + + if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && +- skb->len > mtu && !skb_is_gso(skb) && ++ ip_vs_exceeds_mtu(skb, mtu) && + !ip_vs_iph_icmp(ipvsh))) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); +-- +2.53.0 + diff --git a/queue-6.1/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch b/queue-6.1/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch new file mode 100644 index 0000000000..67fc2e5c9a --- /dev/null +++ b/queue-6.1/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch @@ -0,0 +1,48 @@ +From 4321345f0834811ec19232ceba2bd9e6e885c32c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Feb 2026 18:43:44 -0500 +Subject: irqchip/irq-pic32-evic: Address warning related to wrong printf() + formatter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 86be659415b0ddefebc3120e309091aa215a9064 ] + +This driver is currently only build on 32 bit MIPS systems. When building +it on x86_64, the following warning occurs: + + drivers/irqchip/irq-pic32-evic.c: In function ‘pic32_ext_irq_of_init’: + ./include/linux/kern_levels.h:5:25: error: format ‘%d’ expects argument of type + ‘int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] + +Update the printf() formatter in preparation for allowing this driver to +be compiled on all architectures. + +Fixes: aaa8666ada780 ("IRQCHIP: irq-pic32-evic: Add support for PIC32 interrupt controller") +Signed-off-by: Brian Masney +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260222-irqchip-pic32-v1-1-37f50d1f14af@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-pic32-evic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c +index 1d9bb28d13e5d..1a72047f3aa2e 100644 +--- a/drivers/irqchip/irq-pic32-evic.c ++++ b/drivers/irqchip/irq-pic32-evic.c +@@ -198,7 +198,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain) + + of_property_for_each_u32(node, pname, prop, p, hwirq) { + if (i >= ARRAY_SIZE(priv->ext_irqs)) { +- pr_warn("More than %d external irq, skip rest\n", ++ pr_warn("More than %zu external irq, skip rest\n", + ARRAY_SIZE(priv->ext_irqs)); + break; + } +-- +2.53.0 + diff --git a/queue-6.1/kernel-globalize-lookup_or_create_module_kobject.patch b/queue-6.1/kernel-globalize-lookup_or_create_module_kobject.patch new file mode 100644 index 0000000000..f84bdb4b7d --- /dev/null +++ b/queue-6.1/kernel-globalize-lookup_or_create_module_kobject.patch @@ -0,0 +1,55 @@ +From 47b8a9412cfb3921b32e43c4d2d79240b1fdadf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 10:49:29 -0800 +Subject: kernel: globalize lookup_or_create_module_kobject() + +From: Shyam Saini + +[ Upstream commit 7c76c813cfc42a7376378a0c4b7250db2eebab81 ] + +lookup_or_create_module_kobject() is marked as static and __init, +to make it global drop static keyword. +Since this function can be called from non-init code, use __modinit +instead of __init, __modinit marker will make it __init if +CONFIG_MODULES is not defined. + +Suggested-by: Rasmus Villemoes +Signed-off-by: Shyam Saini +Link: https://lore.kernel.org/r/20250227184930.34163-4-shyamsaini@linux.microsoft.com +Signed-off-by: Petr Pavlu +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 2 ++ + kernel/params.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index a119d2d6c0cba..92f6d8d6dcab0 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -161,6 +161,8 @@ extern void cleanup_module(void); + #define __INITRODATA_OR_MODULE __INITRODATA + #endif /*CONFIG_MODULES*/ + ++struct module_kobject *lookup_or_create_module_kobject(const char *name); ++ + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) + +diff --git a/kernel/params.c b/kernel/params.c +index 6e41ecc54b534..587d9cdafd118 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -758,7 +758,7 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-static struct module_kobject * __init lookup_or_create_module_kobject(const char *name) ++struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +-- +2.53.0 + diff --git a/queue-6.1/kernel-param-rename-locate_module_kobject.patch b/queue-6.1/kernel-param-rename-locate_module_kobject.patch new file mode 100644 index 0000000000..adb09c471d --- /dev/null +++ b/queue-6.1/kernel-param-rename-locate_module_kobject.patch @@ -0,0 +1,62 @@ +From 1915f8fada02be680900ebb6ea3ea515812494ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 10:49:27 -0800 +Subject: kernel: param: rename locate_module_kobject + +From: Shyam Saini + +[ Upstream commit bbc9462f0cb0c8917a4908e856731708f0cee910 ] + +The locate_module_kobject() function looks up an existing +module_kobject for a given module name. If it cannot find the +corresponding module_kobject, it creates one for the given name. + +This commit renames locate_module_kobject() to +lookup_or_create_module_kobject() to better describe its operations. + +This doesn't change anything functionality wise. + +Suggested-by: Rasmus Villemoes +Signed-off-by: Shyam Saini +Link: https://lore.kernel.org/r/20250227184930.34163-2-shyamsaini@linux.microsoft.com +Signed-off-by: Petr Pavlu +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + kernel/params.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/kernel/params.c b/kernel/params.c +index 27954dfe3d204..6e41ecc54b534 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -758,7 +758,7 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-static struct module_kobject * __init locate_module_kobject(const char *name) ++static struct module_kobject * __init lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +@@ -800,7 +800,7 @@ static void __init kernel_add_sysfs_param(const char *name, + struct module_kobject *mk; + int err; + +- mk = locate_module_kobject(name); ++ mk = lookup_or_create_module_kobject(name); + if (!mk) + return; + +@@ -871,7 +871,7 @@ static void __init version_sysfs_builtin(void) + int err; + + for (vattr = __start___modver; vattr < __stop___modver; vattr++) { +- mk = locate_module_kobject(vattr->module_name); ++ mk = lookup_or_create_module_kobject(vattr->module_name); + if (mk) { + err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); + WARN_ON_ONCE(err); +-- +2.53.0 + diff --git a/queue-6.1/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch b/queue-6.1/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch new file mode 100644 index 0000000000..6bf7fd9b0b --- /dev/null +++ b/queue-6.1/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch @@ -0,0 +1,71 @@ +From db3d4971fa34f5c080a50b853ed5168d423d8244 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:54 +0900 +Subject: ksmbd: destroy tree_conn_ida in ksmbd_session_destroy() + +From: DaeMyung Kang + +[ Upstream commit c049ee14eb4343b69b6f7755563f961f5e153423 ] + +When per-session tree_conn_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from ksmbd_session_destroy() but no matching ida_destroy() +was added. The session is therefore freed with the IDA's backing +xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +enclosing session is freed. + +Also move ida_init() to right after the session is allocated so that +it is always paired with the destroy call even on the early error +paths of __session_create() (ksmbd_init_file_table() or +__init_smb2_session() failures), both of which jump to the error +label and invoke ksmbd_session_destroy() on a partially initialised +session. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index 1b5ac28d7e66c..f7ba243c854e2 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -168,6 +168,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) + free_channel_list(sess); + kfree(sess->Preauth_HashValue); + ksmbd_release_id(&session_ida, sess->id); ++ ida_destroy(&sess->tree_conn_ida); + kfree(sess); + } + +@@ -404,6 +405,8 @@ static struct ksmbd_session *__session_create(int protocol) + if (!sess) + return NULL; + ++ ida_init(&sess->tree_conn_ida); ++ + if (ksmbd_init_file_table(&sess->file_table)) + goto error; + +@@ -422,8 +425,6 @@ static struct ksmbd_session *__session_create(int protocol) + if (ret) + goto error; + +- ida_init(&sess->tree_conn_ida); +- + down_write(&sessions_table_lock); + hash_add(sessions_table, &sess->hlist, sess->id); + up_write(&sessions_table_lock); +-- +2.53.0 + diff --git a/queue-6.1/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch b/queue-6.1/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch new file mode 100644 index 0000000000..6abd199c7f --- /dev/null +++ b/queue-6.1/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch @@ -0,0 +1,73 @@ +From 9c5c987dc5b505e85d0a59df2465e5d6be1d44d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 22:31:12 -0400 +Subject: ksmbd: fix use-after-free from async crypto on Qualcomm crypto engine + +From: Joshua Klinesmith + +[ Upstream commit 3e298897f41c61450c2e7a4f457e8b2485eb35b3 ] + +ksmbd_crypt_message() sets a NULL completion callback on AEAD requests +and does not handle the -EINPROGRESS return code from async hardware +crypto engines like the Qualcomm Crypto Engine (QCE). When QCE returns +-EINPROGRESS, ksmbd treats it as an error and immediately frees the +request while the hardware DMA operation is still in flight. The DMA +completion callback then dereferences freed memory, causing a NULL +pointer crash: + + pc : qce_skcipher_done+0x24/0x174 + lr : vchan_complete+0x230/0x27c + ... + el1h_64_irq+0x68/0x6c + ksmbd_free_work_struct+0x20/0x118 [ksmbd] + ksmbd_exit_file_cache+0x694/0xa4c [ksmbd] + +Use the standard crypto_wait_req() pattern with crypto_req_done() as +the completion callback, matching the approach used by the SMB client +in fs/smb/client/smb2ops.c. This properly handles both synchronous +engines (immediate return) and async engines (-EINPROGRESS followed +by callback notification). + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Link: https://github.com/openwrt/openwrt/issues/21822 +Signed-off-by: Joshua Klinesmith +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/auth.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index a9b73ea3a7427..38e0eb27bad53 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -1104,6 +1104,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int rc; ++ DECLARE_CRYPTO_WAIT(wait); + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; +@@ -1190,12 +1191,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); +- aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); ++ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | ++ CRYPTO_TFM_REQ_MAY_SLEEP, ++ crypto_req_done, &wait); + +- if (enc) +- rc = crypto_aead_encrypt(req); +- else +- rc = crypto_aead_decrypt(req); ++ rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : ++ crypto_aead_decrypt(req), &wait); + if (rc) + goto free_iv; + +-- +2.53.0 + diff --git a/queue-6.1/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch b/queue-6.1/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch new file mode 100644 index 0000000000..779431c8ae --- /dev/null +++ b/queue-6.1/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch @@ -0,0 +1,59 @@ +From bf352500fac18e8f280e060b585431e455fb64fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 00:31:47 +0900 +Subject: ksmbd: scope conn->binding slowpath to bound sessions only + +From: Hyunwoo Kim + +[ Upstream commit b0da97c034b6107d14e537e212d4ce8b22109a58 ] + +When the binding SESSION_SETUP sets conn->binding = true, the flag stays +set after the call so that the global session lookup in +ksmbd_session_lookup_all() can find the session, which was not added to +conn->sessions. Because the flag is connection-wide, the global lookup +path will also resolve any other session by id if asked. + +Tighten the global lookup so that the returned session must have this +connection registered in its channel xarray (sess->ksmbd_chann_list). +The channel entry is installed by the existing binding_session path in +ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes +successfully, so this condition is a strict equivalent of "this +connection has been accepted as a channel of this session". Connections +that have not bound to a given session cannot reach it via the global +table. + +The existing conn->binding gate for entering the slowpath is preserved +so that non-binding connections keep the fast-path-only behavior, and +the session->state check is unchanged. + +Fixes: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel") +Signed-off-by: Hyunwoo Kim +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index f7ba243c854e2..08eeca8ab0042 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -323,8 +323,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, + struct ksmbd_session *sess; + + sess = ksmbd_session_lookup(conn, id); +- if (!sess && conn->binding) ++ if (!sess && conn->binding) { + sess = ksmbd_session_lookup_slowpath(id); ++ if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) { ++ ksmbd_user_session_put(sess); ++ sess = NULL; ++ } ++ } + if (sess && sess->state != SMB2_SESSION_VALID) { + ksmbd_user_session_put(sess); + sess = NULL; +-- +2.53.0 + diff --git a/queue-6.1/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch b/queue-6.1/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch new file mode 100644 index 0000000000..3d58baeddd --- /dev/null +++ b/queue-6.1/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch @@ -0,0 +1,49 @@ +From cf5fc14eaac68b31d95204d0cc8ec0926fa869bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:56 -0300 +Subject: ktest: Avoid undef warning when WARNINGS_FILE is unset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit 057854f8a595160656fe77ed7bf0d2403724b915 ] + +check_buildlog() probes $warnings_file with -f even when WARNINGS_FILE is +not configured. Perl warns about the uninitialized value and adds noise to +the test log, which can hide the output we actually care about. + +Check that WARNINGS_FILE is defined before testing whether the file exists. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-1-565d412f4925@suse.com +Fixes: 4283b169abfb ("ktest: Add make_warnings_file and process full warnings") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index b1bd8be3cf666..d752c4bd0d8b3 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -2465,7 +2465,7 @@ sub check_buildlog { + my $save_no_reboot = $no_reboot; + $no_reboot = 1; + +- if (-f $warnings_file) { ++ if (defined($warnings_file) && -f $warnings_file) { + open(IN, $warnings_file) or + dodie "Error opening $warnings_file"; + +-- +2.53.0 + diff --git a/queue-6.1/ktest-honor-empty-per-test-option-overrides.patch b/queue-6.1/ktest-honor-empty-per-test-option-overrides.patch new file mode 100644 index 0000000000..4a0563706b --- /dev/null +++ b/queue-6.1/ktest-honor-empty-per-test-option-overrides.patch @@ -0,0 +1,79 @@ +From 1629a1db63ec51dfbcf3b46b228adf7da9f9a541 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:59 -0300 +Subject: ktest: Honor empty per-test option overrides +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit a2de57a3c8192dcd67cccaff6c341b93748d799b ] + +A per-test override can clear an inherited default option by assigning an +empty value, but __set_test_option() still used option_defined() to decide +whether a per-test key existed. That turned an empty per-test assignment +back into "fall back to the default", so tests still could not clear +inherited settings. + +For example: + + DEFAULTS + (...) + LOG_FILE = /tmp/ktest-empty-override.log + CLEAR_LOG = 1 + ADD_CONFIG = /tmp/.config + + TEST_START + TEST_TYPE = build + BUILD_TYPE = nobuild + ADD_CONFIG = + +This would run the test with ADD_CONFIG[1] = /tmp/.config + +Fix by checking whether the per-test key exists before falling back. If it +does exist but is empty, treat it as unset for that test and stop the +fallback chain there. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-4-565d412f4925@suse.com +Fixes: 22c37a9ac49d ("ktest: Allow tests to undefine default options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index d752c4bd0d8b3..28eebfa32621d 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -4106,7 +4106,8 @@ sub __set_test_option { + + my $option = "$name\[$i\]"; + +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + +@@ -4114,7 +4115,8 @@ sub __set_test_option { + if ($i >= $test && + $i < $test + $repeat_tests{$test}) { + $option = "$name\[$test\]"; +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + } +-- +2.53.0 + diff --git a/queue-6.1/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch b/queue-6.1/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch new file mode 100644 index 0000000000..d2c3394a47 --- /dev/null +++ b/queue-6.1/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch @@ -0,0 +1,105 @@ +From 23dcb76dceb4b7336da3d9c785b2eb1feceb5f0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:08:03 -0300 +Subject: ktest: Run POST_KTEST hooks on failure and cancellation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit bc6e165a452da909cef0efbc286e6695624db372 ] + +PRE_KTEST can be useful for setting up the environment and POST_KTEST to +tear it down, however POST_KTEST only runs on the normal end-of-run path. +It is skipped when ktest exits through dodie() or cancel_test(). Final +cleanup hooks are skipped. + +Factor the final hook execution into run_post_ktest(), call it from the +normal exit path and from the early exit paths, and guard it so the hook +runs at most once. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-8-565d412f4925@suse.com +Fixes: 921ed4c7208e ("ktest: Add PRE/POST_KTEST and TEST options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 28eebfa32621d..df8588dadc2ca 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -98,6 +98,7 @@ my $test_type; + my $build_type; + my $build_options; + my $final_post_ktest; ++my $post_ktest_done = 0; + my $pre_ktest; + my $post_ktest; + my $pre_test; +@@ -1530,6 +1531,24 @@ sub get_test_name() { + return $name; + } + ++sub run_post_ktest { ++ my $cmd; ++ ++ return if ($post_ktest_done); ++ ++ if (defined($final_post_ktest)) { ++ $cmd = $final_post_ktest; ++ } elsif (defined($post_ktest)) { ++ $cmd = $post_ktest; ++ } else { ++ return; ++ } ++ ++ my $cp_post_ktest = eval_kernel_version($cmd); ++ run_command $cp_post_ktest; ++ $post_ktest_done = 1; ++} ++ + sub dodie { + # avoid recursion + return if ($in_die); +@@ -1589,6 +1608,7 @@ sub dodie { + if (defined($post_test)) { + run_command $post_test; + } ++ run_post_ktest; + + die @_, "\n"; + } +@@ -4223,6 +4243,7 @@ sub cancel_test { + send_email("KTEST: Your [$name] test was cancelled", + "Your test started at $script_start_time was cancelled: sig int"); + } ++ run_post_ktest; + die "\nCaught Sig Int, test interrupted: $!\n" + } + +@@ -4533,11 +4554,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { + success $i; + } + +-if (defined($final_post_ktest)) { +- +- my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; +- run_command $cp_final_post_ktest; +-} ++run_post_ktest; + + if ($opt{"POWEROFF_ON_SUCCESS"}) { + halt; +-- +2.53.0 + diff --git a/queue-6.1/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch b/queue-6.1/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch new file mode 100644 index 0000000000..ec57d28d96 --- /dev/null +++ b/queue-6.1/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch @@ -0,0 +1,36 @@ +From 4d4f92aed5bdb76dafb92356f1bc13e0cd5d10ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:30:48 +0800 +Subject: leds: lgm-sso: Remove duplicate assignments for priv->mmap + +From: Chen Ni + +[ Upstream commit 7186d0330c3f3e86de577687a82f4ebd96dcb5ac ] + +Remove duplicate assignment of priv->mmap in intel_sso_led_probe(). + +Fixes: fba8a6f2263b ("leds: lgm-sso: Fix clock handling") +Signed-off-by: Chen Ni +Link: https://patch.msgid.link/20260226033048.3715915-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 6f270c0272fb1..a33a97c2abb65 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -807,8 +807,6 @@ static int intel_sso_led_probe(struct platform_device *pdev) + + priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk); + +- priv->mmap = syscon_node_to_regmap(dev->of_node); +- + priv->mmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(priv->mmap)) { + dev_err(dev, "Failed to map iomem!\n"); +-- +2.53.0 + diff --git a/queue-6.1/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch b/queue-6.1/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch new file mode 100644 index 0000000000..80a636a49f --- /dev/null +++ b/queue-6.1/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch @@ -0,0 +1,51 @@ +From 22a6ded332a200e9cef086ac212bf0612eecbfb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 17:21:43 +0200 +Subject: lib/hexdump: print_hex_dump_bytes() calls print_hex_dump_debug() + +From: Geert Uytterhoeven + +[ Upstream commit 36776b7f8a8955b4e75b5d490a75fee0c7a2a7ef ] + +print_hex_dump_bytes() claims to be a simple wrapper around +print_hex_dump(), but it actally calls print_hex_dump_debug(), which +means no output is printed if (dynamic) DEBUG is disabled. + +Update the documentation to match the implementation. + +Fixes: 091cb0994edd20d6 ("lib/hexdump: make print_hex_dump_bytes() a nop on !DEBUG builds") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Petr Mladek +Link: https://patch.msgid.link/3d5c3069fd9102ecaf81d044b750cd613eb72a08.1774970392.git.geert+renesas@glider.be +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + include/linux/printk.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index b1a12916f0361..90f991cb2a5c9 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -748,7 +748,8 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + #endif + + /** +- * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params ++ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default ++ * params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none +@@ -756,7 +757,7 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + * @buf: data blob to dump + * @len: number of bytes in the @buf + * +- * Calls print_hex_dump(), with log level of KERN_DEBUG, ++ * Calls print_hex_dump_debug(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ + #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ +-- +2.53.0 + diff --git a/queue-6.1/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch b/queue-6.1/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch new file mode 100644 index 0000000000..2c9ece27a3 --- /dev/null +++ b/queue-6.1/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch @@ -0,0 +1,75 @@ +From d59403718c094475be684652c8fddb81fa2dc32a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:15:07 -0700 +Subject: locking: Fix rwlock support in + +From: Bart Van Assche + +[ Upstream commit 756a0e011cfca0b45a48464aa25b05d9a9c2fb0b ] + +Architecture support for rwlocks must be available whether or not +CONFIG_DEBUG_SPINLOCK has been defined. Move the definitions of the +arch_{read,write}_{lock,trylock,unlock}() macros such that these become +visbile if CONFIG_DEBUG_SPINLOCK=n. + +This patch prepares for converting do_raw_{read,write}_trylock() into +inline functions. Without this patch that conversion triggers a build +failure for UP architectures, e.g. arm-ep93xx. I used the following +kernel configuration to build the kernel for that architecture: + + CONFIG_ARCH_MULTIPLATFORM=y + CONFIG_ARCH_MULTI_V7=n + CONFIG_ATAGS=y + CONFIG_MMU=y + CONFIG_ARCH_MULTI_V4T=y + CONFIG_CPU_LITTLE_ENDIAN=y + CONFIG_ARCH_EP93XX=y + +Fixes: fb1c8f93d869 ("[PATCH] spinlock consolidation") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260313171510.230998-2-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/spinlock_up.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h +index c87204247592f..a132fc562297a 100644 +--- a/include/linux/spinlock_up.h ++++ b/include/linux/spinlock_up.h +@@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + lock->slock = 1; + } + +-/* +- * Read-write spinlocks. No debug version. +- */ +-#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) +- + #else /* DEBUG_SPINLOCK */ + #define arch_spin_is_locked(lock) ((void)(lock), 0) + /* for sched/core.c and kernel_lock.c: */ +@@ -68,4 +58,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + + #define arch_spin_is_contended(lock) (((void)(lock), 0)) + ++/* ++ * Read-write spinlocks. No debug version. ++ */ ++#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) ++ + #endif /* __LINUX_SPINLOCK_UP_H */ +-- +2.53.0 + diff --git a/queue-6.1/macvlan-annotate-data-races-around-port-bc_queue_len.patch b/queue-6.1/macvlan-annotate-data-races-around-port-bc_queue_len.patch new file mode 100644 index 0000000000..f7ffd18a33 --- /dev/null +++ b/queue-6.1/macvlan-annotate-data-races-around-port-bc_queue_len.patch @@ -0,0 +1,67 @@ +From 01700b6639f88141e0a4a5f4d71264bf1944d197 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:38:08 +0000 +Subject: macvlan: annotate data-races around port->bc_queue_len_used + +From: Eric Dumazet + +[ Upstream commit 1ef5789d9906df3771c99b7f413caaf2bf473ca5 ] + +port->bc_queue_len_used is read and written locklessly, +add READ_ONCE()/WRITE_ONCE() annotations. + +While WRITE_ONCE() in macvlan_fill_info() is not yet needed, +it is a prereq for future RTNL avoidance. + +Fixes: d4bff72c8401 ("macvlan: Support for high multicast packet rate") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401103809.3038139-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index 24e36d78a23ae..14018be5e7e70 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -344,6 +344,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + const struct macvlan_dev *src, + struct sk_buff *skb) + { ++ u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used); + struct sk_buff *nskb; + int err = -ENOMEM; + +@@ -354,7 +355,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + MACVLAN_SKB_CB(nskb)->src = src; + + spin_lock(&port->bc_queue.lock); +- if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) { ++ if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) { + if (src) + dev_hold(src->dev); + __skb_queue_tail(&port->bc_queue, nskb); +@@ -1695,7 +1696,8 @@ static int macvlan_fill_info(struct sk_buff *skb, + } + if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) + goto nla_put_failure; +- if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) ++ if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, ++ READ_ONCE(port->bc_queue_len_used))) + goto nla_put_failure; + return 0; + +@@ -1751,7 +1753,7 @@ static void update_port_bc_queue_len(struct macvlan_port *port) + if (vlan->bc_queue_len_req > max_bc_queue_len_req) + max_bc_queue_len_req = vlan->bc_queue_len_req; + } +- port->bc_queue_len_used = max_bc_queue_len_req; ++ WRITE_ONCE(port->bc_queue_len_used, max_bc_queue_len_req); + } + + static int macvlan_device_event(struct notifier_block *unused, +-- +2.53.0 + diff --git a/queue-6.1/mailbox-add-sanity-check-for-channel-array.patch b/queue-6.1/mailbox-add-sanity-check-for-channel-array.patch new file mode 100644 index 0000000000..ac1ce07ebd --- /dev/null +++ b/queue-6.1/mailbox-add-sanity-check-for-channel-array.patch @@ -0,0 +1,40 @@ +From 7833a3c5b28c1a0fe5307f22ab022afcc897c1ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:42:38 +0200 +Subject: mailbox: add sanity check for channel array + +From: Wolfram Sang + +[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ] + +Fail gracefully if there is no channel array attached to the mailbox +controller. Otherwise the later dereference will cause an OOPS which +might not be seen because mailbox controllers might instantiate very +early. Remove the comment explaining the obvious while here. + +Fixes: 2b6d83e2b8b7 ("mailbox: Introduce framework for mailbox") +Signed-off-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index ac8c162b689b2..c5b9d24efb69c 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -524,8 +524,7 @@ int mbox_controller_register(struct mbox_controller *mbox) + { + int i, txdone; + +- /* Sanity check */ +- if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) ++ if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) + return -EINVAL; + + if (mbox->txdone_irq) +-- +2.53.0 + diff --git a/queue-6.1/mailbox-mailbox-test-don-t-free-the-reused-channel.patch b/queue-6.1/mailbox-mailbox-test-don-t-free-the-reused-channel.patch new file mode 100644 index 0000000000..aa3e411a95 --- /dev/null +++ b/queue-6.1/mailbox-mailbox-test-don-t-free-the-reused-channel.patch @@ -0,0 +1,46 @@ +From 75dd3c267ae238c4e4343d021e9eb1d2bf29640c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:34 +0200 +Subject: mailbox: mailbox-test: don't free the reused channel + +From: Wolfram Sang + +[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ] + +The RX channel can be aliased to the TX channel if it has a different +MMIO. This special case needs to be handled when freeing the channels +otherwise a double-free occurs. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 1d546cae922ce..247e83af060e3 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -423,7 +423,7 @@ static int mbox_test_probe(struct platform_device *pdev) + err_free_chans: + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + return ret; + } +@@ -436,7 +436,7 @@ static int mbox_test_remove(struct platform_device *pdev) + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/mailbox-mailbox-test-free-channels-on-probe-error.patch b/queue-6.1/mailbox-mailbox-test-free-channels-on-probe-error.patch new file mode 100644 index 0000000000..c6c6bddaf0 --- /dev/null +++ b/queue-6.1/mailbox-mailbox-test-free-channels-on-probe-error.patch @@ -0,0 +1,60 @@ +From ca07fddbab9969b3bfb88911a4644b490be50eda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 14:53:00 +0200 +Subject: mailbox: mailbox-test: free channels on probe error + +From: Wolfram Sang + +[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ] + +On probe error, free the previously obtained channels. This not only +prevents a leak, but also UAF scenarios because the client structure +will be removed nonetheless because it was allocated with devm. + +Link: https://sashiko.dev/#/patchset/20260327151217.5327-2-wsa%2Brenesas%40sang-engineering.com +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 29c04157b5e88..1d546cae922ce 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -405,18 +405,27 @@ static int mbox_test_probe(struct platform_device *pdev) + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +- if (!tdev->rx_buffer) +- return -ENOMEM; ++ if (!tdev->rx_buffer) { ++ ret = -ENOMEM; ++ goto err_free_chans; ++ } + } + + ret = mbox_test_add_debugfs(pdev, tdev); + if (ret) +- return ret; ++ goto err_free_chans; + + init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; ++ ++err_free_chans: ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ if (tdev->rx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ return ret; + } + + static int mbox_test_remove(struct platform_device *pdev) +-- +2.53.0 + diff --git a/queue-6.1/mailbox-mailbox-test-initialize-struct-earlier.patch b/queue-6.1/mailbox-mailbox-test-initialize-struct-earlier.patch new file mode 100644 index 0000000000..bc50901faf --- /dev/null +++ b/queue-6.1/mailbox-mailbox-test-initialize-struct-earlier.patch @@ -0,0 +1,64 @@ +From 2100c8bc5b45abd8a68ae3df758dac721a50a35a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:35 +0200 +Subject: mailbox: mailbox-test: initialize struct earlier + +From: Wolfram Sang + +[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ] + +The waitqueue must be initialized before the debugfs files are created +because from that time, requests from userspace can already be made. +Similarily, drvdata and spinlock needs to be initialized before we +request the channel, otherwise dangling irqs might run into problems +like a NULL pointer exception. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 247e83af060e3..41efe64976598 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -365,6 +365,12 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev) + return -ENOMEM; + ++ tdev->dev = &pdev->dev; ++ spin_lock_init(&tdev->lock); ++ mutex_init(&tdev->mutex); ++ init_waitqueue_head(&tdev->waitq); ++ platform_set_drvdata(pdev, tdev); ++ + /* It's okay for MMIO to be NULL */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); +@@ -396,12 +402,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) + tdev->rx_channel = tdev->tx_channel; + +- tdev->dev = &pdev->dev; +- platform_set_drvdata(pdev, tdev); +- +- spin_lock_init(&tdev->lock); +- mutex_init(&tdev->mutex); +- + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +@@ -415,7 +415,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (ret) + goto err_free_chans; + +- init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch b/queue-6.1/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch new file mode 100644 index 0000000000..f3463bf749 --- /dev/null +++ b/queue-6.1/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch @@ -0,0 +1,73 @@ +From f32d557b6590e6e8a56f611f1fd767ef0a876c7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:36 +0200 +Subject: mailbox: mailbox-test: make data_ready a per-instance variable + +From: Wolfram Sang + +[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ] + +While not the default case, multiple tests can be run simultaneously. +Then, data_ready being a global variable will be overwritten and the +per-instance lock will not help. Turn the global variable into a +per-instance one to avoid this problem. + +Fixes: e339c80af95e ("mailbox: mailbox-test: don't rely on rx_buffer content to signal data ready") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 41efe64976598..113858fe168c3 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -27,8 +27,6 @@ + #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ + (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) + +-static bool mbox_data_ready; +- + struct mbox_test_device { + struct device *dev; + void __iomem *tx_mmio; +@@ -41,6 +39,7 @@ struct mbox_test_device { + spinlock_t lock; + struct mutex mutex; + wait_queue_head_t waitq; ++ bool data_ready; + struct fasync_struct *async_queue; + struct dentry *root_debugfs_dir; + }; +@@ -161,7 +160,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); +- data_ready = mbox_data_ready; ++ data_ready = tdev->data_ready; + spin_unlock_irqrestore(&tdev->lock, flags); + + return data_ready; +@@ -226,7 +225,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, + *(touser + l) = '\0'; + + memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); +- mbox_data_ready = false; ++ tdev->data_ready = false; + + spin_unlock_irqrestore(&tdev->lock, flags); + +@@ -296,7 +295,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) + message, MBOX_MAX_MSG_LEN); + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); + } +- mbox_data_ready = true; ++ tdev->data_ready = true; + spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); +-- +2.53.0 + diff --git a/queue-6.1/memory-tegra124-emc-fix-dll_change-check.patch b/queue-6.1/memory-tegra124-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..a9ddfc4e76 --- /dev/null +++ b/queue-6.1/memory-tegra124-emc-fix-dll_change-check.patch @@ -0,0 +1,38 @@ +From e3970863d4a22a93ddd8162cc9a6fdaee6e0220c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:42 +0900 +Subject: memory: tegra124-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 9597ab9a8296ab337e6820f8a717ff621078b632 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: 73a7f0a90641 ("memory: tegra: Add EMC (external memory controller) driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-1-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra124-emc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c +index 00ed2b6a0d1b2..ca2714b0a521a 100644 +--- a/drivers/memory/tegra/tegra124-emc.c ++++ b/drivers/memory/tegra/tegra124-emc.c +@@ -608,7 +608,7 @@ static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, + + if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; +-- +2.53.0 + diff --git a/queue-6.1/memory-tegra30-emc-fix-dll_change-check.patch b/queue-6.1/memory-tegra30-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..ca75517a28 --- /dev/null +++ b/queue-6.1/memory-tegra30-emc-fix-dll_change-check.patch @@ -0,0 +1,47 @@ +From bc9061f6da1ada4cf56ee12182519239dda7a8e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:43 +0900 +Subject: memory: tegra30-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 0a93f2355cf4922ad2399dbef5ea1049fef116d4 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: e34212c75a68 ("memory: tegra: Introduce Tegra30 EMC driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-2-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra30-emc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c +index 1ea3792beb86d..fb09e8a463bd5 100644 +--- a/drivers/memory/tegra/tegra30-emc.c ++++ b/drivers/memory/tegra/tegra30-emc.c +@@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) + emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG); + emc_dbg = readl_relaxed(emc->regs + EMC_DBG); + +- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1)) ++ if (emc->dll_on == !(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; + +- emc->dll_on = !!(timing->emc_mode_1 & 0x1); ++ emc->dll_on = !(timing->emc_mode_1 & 0x1); + + if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL)) + emc->zcal_long = true; +-- +2.53.0 + diff --git a/queue-6.1/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch b/queue-6.1/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch new file mode 100644 index 0000000000..d0d2b439d8 --- /dev/null +++ b/queue-6.1/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch @@ -0,0 +1,37 @@ +From 0ad67fa20867f05f7a46c1998e0da16216b8147d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:56:20 +0530 +Subject: mfd: mc13xxx-core: Fix memory leak in mc13xxx_add_subdevice_pdata() + +From: Abdun Nihaal + +[ Upstream commit a5a65a7fb2f7796bbe492cd6be59c92cb64377d1 ] + +The memory allocated for cell.name using kmemdup() is not freed when +mfd_add_devices() fails. Fix that by using devm_kmemdup(). + +Fixes: 8e00593557c3 ("mfd: Add mc13892 support to mc13xxx") +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20260120102622.66921-1-nihaal@cse.iitm.ac.in +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mc13xxx-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c +index 1000572761a84..ddc90cbb7be52 100644 +--- a/drivers/mfd/mc13xxx-core.c ++++ b/drivers/mfd/mc13xxx-core.c +@@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return -E2BIG; + +- cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); ++ cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL); + if (!cell.name) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.1/module-fix-freeing-of-charp-module-parameters-when-c.patch b/queue-6.1/module-fix-freeing-of-charp-module-parameters-when-c.patch new file mode 100644 index 0000000000..1a86e545f6 --- /dev/null +++ b/queue-6.1/module-fix-freeing-of-charp-module-parameters-when-c.patch @@ -0,0 +1,122 @@ +From dbf6c795b9ba800e91652f6d582099022f11000e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:48:02 +0100 +Subject: module: Fix freeing of charp module parameters when CONFIG_SYSFS=n + +From: Petr Pavlu + +[ Upstream commit deffe1edba626d474fef38007c03646ca5876a0e ] + +When setting a charp module parameter, the param_set_charp() function +allocates memory to store a copy of the input value. Later, when the module +is potentially unloaded, the destroy_params() function is called to free +this allocated memory. + +However, destroy_params() is available only when CONFIG_SYSFS=y, otherwise +only a dummy variant is present. In the unlikely case that the kernel is +configured with CONFIG_MODULES=y and CONFIG_SYSFS=n, this results in +a memory leak of charp values when a module is unloaded. + +Fix this issue by making destroy_params() always available when +CONFIG_MODULES=y. Rename the function to module_destroy_params() to clarify +that it is intended for use by the module loader. + +Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs") +Signed-off-by: Petr Pavlu +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + include/linux/moduleparam.h | 11 +++-------- + kernel/module/main.c | 4 ++-- + kernel/params.c | 27 ++++++++++++++++++--------- + 3 files changed, 23 insertions(+), 19 deletions(-) + +diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h +index 061e19c94a6bc..f73ca4d62683b 100644 +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -392,14 +392,9 @@ extern char *parse_args(const char *name, + const char *doing, void *arg)); + + /* Called by module remove. */ +-#ifdef CONFIG_SYSFS +-extern void destroy_params(const struct kernel_param *params, unsigned num); +-#else +-static inline void destroy_params(const struct kernel_param *params, +- unsigned num) +-{ +-} +-#endif /* !CONFIG_SYSFS */ ++#ifdef CONFIG_MODULES ++void module_destroy_params(const struct kernel_param *params, unsigned int num); ++#endif + + /* All the helper functions */ + /* The macros to do compile-time type checking stolen from Jakub +diff --git a/kernel/module/main.c b/kernel/module/main.c +index 6b3cffd9f8a8a..e83e84f699ded 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -1172,7 +1172,7 @@ static void free_module(struct module *mod) + module_unload_free(mod); + + /* Free any allocated parameters. */ +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + + if (is_livepatch_module(mod)) + free_module_elf(mod); +@@ -2890,7 +2890,7 @@ static int load_module(struct load_info *info, const char __user *uargs, + mod_sysfs_teardown(mod); + coming_cleanup: + mod->state = MODULE_STATE_GOING; +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_GOING, mod); + klp_module_going(mod); +diff --git a/kernel/params.c b/kernel/params.c +index 5ae507cd19960..82109c0cf9918 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -743,15 +743,6 @@ void module_param_sysfs_remove(struct module *mod) + } + #endif + +-void destroy_params(const struct kernel_param *params, unsigned num) +-{ +- unsigned int i; +- +- for (i = 0; i < num; i++) +- if (params[i].ops->free) +- params[i].ops->free(params[i].arg); +-} +- + struct module_kobject * __init_or_module + lookup_or_create_module_kobject(const char *name) + { +@@ -971,3 +962,21 @@ static int __init param_sysfs_init(void) + subsys_initcall(param_sysfs_init); + + #endif /* CONFIG_SYSFS */ ++ ++#ifdef CONFIG_MODULES ++ ++/* ++ * module_destroy_params - free all parameters for one module ++ * @params: module parameters (array) ++ * @num: number of module parameters ++ */ ++void module_destroy_params(const struct kernel_param *params, unsigned int num) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < num; i++) ++ if (params[i].ops->free) ++ params[i].ops->free(params[i].arg); ++} ++ ++#endif /* CONFIG_MODULES */ +-- +2.53.0 + diff --git a/queue-6.1/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch b/queue-6.1/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch new file mode 100644 index 0000000000..ac2f28d8d5 --- /dev/null +++ b/queue-6.1/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch @@ -0,0 +1,59 @@ +From 92260ea91e26ce456a60b5f0e4a45d96f95dabf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:57 +0200 +Subject: mtd: parsers: ofpart: call of_node_get() for dedicated subpartitions + +From: Cosmin Tanislav + +[ Upstream commit e882626c1747653f1f01ea9d12e278e613b11d0f ] + +In order to parse sub-partitions, add_mtd_partitions() calls +parse_mtd_partitions() for all previously found partitions. + +Each partition will end up being passed to parse_fixed_partitions(), and +its of_node will be treated as the ofpart_node. + +Commit 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in +parse_fixed_partitions()") added of_node_put() calls for ofpart_node on +all exit paths. + +In the case where the partition passed to parse_fixed_partitions() has a +parent, it is treated as a dedicated partitions node, and of_node_put() +is wrongly called for it, even if of_node_get() was not called +explicitly. + +On repeated bind / unbinds of the MTD, the extra of_node_put() ends up +decrementing the refcount down to 0, which should never happen, +resulting in the following error: + +OF: ERROR: of_node_release() detected bad of_node_put() on +/soc/spi@80007000/flash@0/partitions/partition@0 + +Call of_node_get() to balance the call to of_node_put() done for +dedicated partitions nodes. + +Fixes: 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in parse_fixed_partitions()") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 110994b1e02f5..c18fa1b3e3276 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -71,7 +71,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + dedicated = false; + } + } else { /* Partition */ +- ofpart_node = mtd_node; ++ ofpart_node = of_node_get(mtd_node); + } + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); +-- +2.53.0 + diff --git a/queue-6.1/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch b/queue-6.1/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch new file mode 100644 index 0000000000..b148e7dbaf --- /dev/null +++ b/queue-6.1/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch @@ -0,0 +1,48 @@ +From 321051d6c14317ad07cf13d9715af02af1ad7318 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:56 +0200 +Subject: mtd: parsers: ofpart: call of_node_put() only in ofpart_fail path + +From: Cosmin Tanislav + +[ Upstream commit 0c87dea1aab86116211cb37387c404c9e9231c39 ] + +ofpart_none can only be reached after the for_each_child_of_node() loop +finishes. for_each_child_of_node() correctly calls of_node_put() for all +device nodes it iterates over as long as we don't break or jump out of +the loop. + +Calling of_node_put() inside the ofpart_none path will wrongly decrement +the ref count of the last node in the for_each_child_of_node() loop. + +Move the call to of_node_put() under the ofpart_fail label to fix this. + +Fixes: ebd5a74db74e ("mtd: ofpart: Check availability of reg property instead of name property") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 3cf75b56d5a2e..110994b1e02f5 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -191,11 +191,11 @@ static int parse_fixed_partitions(struct mtd_info *master, + ofpart_fail: + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", + master->name, pp, mtd_node); ++ of_node_put(pp); + ret = -EINVAL; + ofpart_none: + if (dedicated) + of_node_put(ofpart_node); +- of_node_put(pp); + kfree(parts); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.1/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch b/queue-6.1/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch new file mode 100644 index 0000000000..a1409bf602 --- /dev/null +++ b/queue-6.1/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch @@ -0,0 +1,41 @@ +From f7be3c8345069edc961a49ab0a210145a7274629 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:43:36 +0800 +Subject: mtd: physmap_of_gemini: Fix disabled pinctrl state check + +From: Chen Ni + +[ Upstream commit b7c0982184b0661f5b1b805f3a56f1bd3757b63e ] + +The condition for checking the disabled pinctrl state incorrectly checks +gf->enabled_state instead of gf->disabled_state. This causes misleading +error messages and could lead to incorrect behavior when only one of the +pinctrl states is defined. + +Fix the condition to properly check gf->disabled_state. + +Fixes: 9d3b5086f6d4 ("mtd: physmap_of_gemini: Handle pin control") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/maps/physmap-gemini.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c +index d4a46e159d38f..8d5b791dd08d4 100644 +--- a/drivers/mtd/maps/physmap-gemini.c ++++ b/drivers/mtd/maps/physmap-gemini.c +@@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev, + dev_err(dev, "no enabled pin control state\n"); + + gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled"); +- if (IS_ERR(gf->enabled_state)) { ++ if (IS_ERR(gf->disabled_state)) { + dev_err(dev, "no disabled pin control state\n"); + } else { + ret = pinctrl_select_state(gf->p, gf->disabled_state); +-- +2.53.0 + diff --git a/queue-6.1/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch b/queue-6.1/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch new file mode 100644 index 0000000000..3d8be135b3 --- /dev/null +++ b/queue-6.1/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch @@ -0,0 +1,66 @@ +From b6660a28db9afa842ea236c37303be1d9f848831 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:24:30 +0100 +Subject: mtd: rawnand: sunxi: fix sunxi_nfc_hw_ecc_read_extra_oob + +From: Richard Genoud + +[ Upstream commit 848c13996c55fe4ea6bf5acc3ce6c8c5c944b5f6 ] + +When dumping the OOB, the bytes at the end where actually copied from +the beginning of the OOB instead of current_offset. + +That leads to something like: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +instead of: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +(example with BCH16, user data [8,0], no scrambling) + +*cur_off (offset from the beginning of the page) was compared to offset +(offset from the beginning of the OOB), and then, the +nand_change_read_column_op() sets the current position to the beginning +of the OOB instead of OOB+offset + +Fixes: 15d6f118285f ("mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode") +Reviewed-by: Jernej Skrabec +Signed-off-by: Richard Genoud +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/sunxi_nand.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c +index a9daf195cba50..16231ca93b599 100644 +--- a/drivers/mtd/nand/raw/sunxi_nand.c ++++ b/drivers/mtd/nand/raw/sunxi_nand.c +@@ -898,9 +898,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, + if (len <= 0) + return; + +- if (!cur_off || *cur_off != offset) +- nand_change_read_column_op(nand, mtd->writesize, NULL, 0, +- false); ++ if (!cur_off || *cur_off != (offset + mtd->writesize)) ++ nand_change_read_column_op(nand, mtd->writesize + offset, ++ NULL, 0, false); + + if (!randomize) + sunxi_nfc_read_buf(nand, oob + offset, len); +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-allow-post_sfdp-hook-to-return-errors.patch b/queue-6.1/mtd-spi-nor-allow-post_sfdp-hook-to-return-errors.patch new file mode 100644 index 0000000000..e069c5c5ca --- /dev/null +++ b/queue-6.1/mtd-spi-nor-allow-post_sfdp-hook-to-return-errors.patch @@ -0,0 +1,162 @@ +From 3835ec6336c0ff1616f3929930ae397f352e4a27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Apr 2023 15:40:58 +0900 +Subject: mtd: spi-nor: Allow post_sfdp hook to return errors + +From: Tudor Ambarus + +[ Upstream commit e570f7872a34dc290014c80c7bad365d6577836b ] + +Multi die flashes like s25hl02gt need to determine the page_size at +run-time by querying a configuration register for each die. Since the +number of dice is determined in an optional SFDP table, SCCR MC, the +page size configuration must be done in the post_sfdp hook. Allow +post_sfdp to return errors, as reading the configuration register might +return errors. + +Link: https://lore.kernel.org/r/924ab710f128448ec62537cfbb377336e390043c.1680849425.git.Takahiro.Kuwano@infineon.com +Signed-off-by: Tudor Ambarus +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 2 +- + drivers/mtd/spi-nor/micron-st.c | 4 +++- + drivers/mtd/spi-nor/sfdp.c | 17 ++++++++++++----- + drivers/mtd/spi-nor/spansion.c | 12 +++++++++--- + 4 files changed, 25 insertions(+), 10 deletions(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 290613fd63ae7..cc70a2092494c 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -424,7 +424,7 @@ struct spi_nor_fixups { + int (*post_bfpt)(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); +- void (*post_sfdp)(struct spi_nor *nor); ++ int (*post_sfdp)(struct spi_nor *nor); + void (*late_init)(struct spi_nor *nor); + }; + +diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c +index 3c9681a3f7a33..f8f6e14452d58 100644 +--- a/drivers/mtd/spi-nor/micron-st.c ++++ b/drivers/mtd/spi-nor/micron-st.c +@@ -127,7 +127,7 @@ static void mt35xu512aba_default_init(struct spi_nor *nor) + nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable; + } + +-static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) ++static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) + { + /* Set the Fast Read settings. */ + nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; +@@ -145,6 +145,8 @@ static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) + * disable it. + */ + nor->params->quad_enable = NULL; ++ ++ return 0; + } + + static const struct spi_nor_fixups mt35xu512aba_fixups = { +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index 78110387be0b5..6f47982105bd9 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -1239,14 +1239,21 @@ static int spi_nor_parse_sccr(struct spi_nor *nor, + * Used to tweak various flash parameters when information provided by the SFDP + * tables are wrong. + */ +-static void spi_nor_post_sfdp_fixups(struct spi_nor *nor) ++static int spi_nor_post_sfdp_fixups(struct spi_nor *nor) + { ++ int ret; ++ + if (nor->manufacturer && nor->manufacturer->fixups && +- nor->manufacturer->fixups->post_sfdp) +- nor->manufacturer->fixups->post_sfdp(nor); ++ nor->manufacturer->fixups->post_sfdp) { ++ ret = nor->manufacturer->fixups->post_sfdp(nor); ++ if (ret) ++ return ret; ++ } + + if (nor->info->fixups && nor->info->fixups->post_sfdp) +- nor->info->fixups->post_sfdp(nor); ++ return nor->info->fixups->post_sfdp(nor); ++ ++ return 0; + } + + /** +@@ -1429,7 +1436,7 @@ int spi_nor_parse_sfdp(struct spi_nor *nor) + } + } + +- spi_nor_post_sfdp_fixups(nor); ++ err = spi_nor_post_sfdp_fixups(nor); + exit: + kfree(param_headers); + return err; +diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c +index 5914a6074a11e..af97e3741f987 100644 +--- a/drivers/mtd/spi-nor/spansion.c ++++ b/drivers/mtd/spi-nor/spansion.c +@@ -258,7 +258,7 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor, + return cypress_nor_set_page_size(nor); + } + +-static void s25fs256t_post_sfdp_fixup(struct spi_nor *nor) ++static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor) + { + struct spi_nor_flash_parameter *params = nor->params; + +@@ -267,6 +267,8 @@ static void s25fs256t_post_sfdp_fixup(struct spi_nor *nor) + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], + SPINOR_OP_PP_1_1_4_4B, + SNOR_PROTO_1_1_4); ++ ++ return 0; + } + + static void s25fs256t_late_init(struct spi_nor *nor) +@@ -297,7 +299,7 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor, + return cypress_nor_set_page_size(nor); + } + +-static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor) ++static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) + { + struct spi_nor_erase_type *erase_type = + nor->params->erase_map.erase_type; +@@ -319,6 +321,8 @@ static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor) + break; + } + } ++ ++ return 0; + } + + static void s25hx_t_late_init(struct spi_nor *nor) +@@ -351,7 +355,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) + cypress_nor_octal_dtr_dis(nor); + } + +-static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor) ++static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor) + { + /* + * On older versions of the flash the xSPI Profile 1.0 table has the +@@ -377,6 +381,8 @@ static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor) + * actual value for that is 4. + */ + nor->params->rdsr_addr_nbytes = 4; ++ ++ return 0; + } + + static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch b/queue-6.1/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch new file mode 100644 index 0000000000..d5f9b37106 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch @@ -0,0 +1,38 @@ +From d118e2b40d11e123d387344c77eeec5b624c21ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 17:14:14 +0800 +Subject: mtd: spi-nor: core: correct the op.dummy.nbytes when check read + operations + +From: Haibo Chen + +[ Upstream commit 756564a536ecd8c9d33edd89f0647a91a0b03587 ] + +When check read operation, need to setting the op.dummy.nbytes based +on current read operation rather than the nor->read_proto. + +Fixes: 0e30f47232ab ("mtd: spi-nor: add support for DTR protocol") +Signed-off-by: Haibo Chen +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 91622d9c9b032..3f38d67e1a336 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -2061,7 +2061,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; +- if (spi_nor_protocol_is_dtr(nor->read_proto)) ++ if (spi_nor_protocol_is_dtr(read->proto)) + op.dummy.nbytes *= 2; + + return spi_nor_spimem_check_op(nor, &op); +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch b/queue-6.1/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch new file mode 100644 index 0000000000..a69825916b --- /dev/null +++ b/queue-6.1/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch @@ -0,0 +1,88 @@ +From b8d41e294422ca24d8899000edde033d60223d3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 16:47:59 +0900 +Subject: mtd: spi-nor: sfdp: introduce smpt_map_id fixup hook + +From: Takahiro Kuwano + +[ Upstream commit f74de390557bf2bcc5dca4a357b41c0701d3f76e ] + +Certain chips have inconsistent Sector Map Parameter Table (SMPT) data, +which leads to the wrong map ID being identified, causing failures to +detect the correct sector map. + +To fix this, introduce smpt_map_id() into the struct spi_nor_fixups. +This function will be called after the initial SMPT-based detection, +allowing chip-specific logic to correct the map ID. + +Infineon S25FS512S needs this fixup as it has inconsistency between map +ID definition and configuration register value actually obtained. + +Co-developed-by: Marek Vasut +Signed-off-by: Marek Vasut +Reviewed-by: Tudor Ambarus +Tested-by: Marek Vasut # S25FS512S +Signed-off-by: Takahiro Kuwano +Reviewed-by: Tudor Ambarus > +Signed-off-by: Pratyush Yadav +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 3 +++ + drivers/mtd/spi-nor/sfdp.c | 12 ++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 4aac34f06c7bb..1bf6bad5942d6 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -409,6 +409,8 @@ struct spi_nor_flash_parameter { + * @post_bfpt: called after the BFPT table has been parsed + * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the + * number of dummy cycles in read register ops. ++ * @smpt_map_id: called after map ID in SMPT table has been determined for the ++ * case the map ID is wrong and needs to be fixed. + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. +@@ -427,6 +429,7 @@ struct spi_nor_fixups { + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); + void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); ++ void (*smpt_map_id)(const struct spi_nor *nor, u8 *map_id); + int (*post_sfdp)(struct spi_nor *nor); + void (*late_init)(struct spi_nor *nor); + }; +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index 66c233db20e8e..f738f6d5219a9 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -690,6 +690,16 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) + return read_dummy; + } + ++static void spi_nor_smpt_map_id_fixups(const struct spi_nor *nor, u8 *map_id) ++{ ++ if (nor->manufacturer && nor->manufacturer->fixups && ++ nor->manufacturer->fixups->smpt_map_id) ++ nor->manufacturer->fixups->smpt_map_id(nor, map_id); ++ ++ if (nor->info->fixups && nor->info->fixups->smpt_map_id) ++ nor->info->fixups->smpt_map_id(nor, map_id); ++} ++ + /** + * spi_nor_get_map_in_use() - get the configuration map in use + * @nor: pointer to a 'struct spi_nor' +@@ -743,6 +753,8 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt, + map_id = map_id << 1 | !!(*buf & read_data_mask); + } + ++ spi_nor_smpt_map_id_fixups(nor, &map_id); ++ + /* + * If command descriptors are provided, they always precede map + * descriptors in the table. There is no need to start the iteration +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch b/queue-6.1/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch new file mode 100644 index 0000000000..e85c1bbb45 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch @@ -0,0 +1,92 @@ +From 2d8e4fdafdd0c0774ef49739504a359d9a9a883e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 16:47:58 +0900 +Subject: mtd: spi-nor: sfdp: introduce smpt_read_dummy fixup hook + +From: Takahiro Kuwano + +[ Upstream commit 653f6def567c81f37302f9591ffd54df3e2a11eb ] + +SMPT contains config detection info that describes opcode, address, and +dummy cycles to read sector map config. The dummy cycles parameter can +be SMPT_CMD_READ_DUMMY_IS_VARIABLE and in that case nor->read_dummy +(initialized as 0) is used. In Infineon flash chips, Read Any Register +command with variable dummy cycle is defined in SMPT. S25Hx/S28Hx flash +has 0 dummy cycle by default to read volatile regiters and +nor->read_dummy can work. S25FS-S flash has 8 dummy cycles so we need a +hook that can fix dummy cycles with actually used value. + +Inroduce smpt_read_dummy() in struct spi_nor_fixups. It is called when +the dummy cycle field in SMPT config detection is 'varialble'. + +Reviewed-by: Tudor Ambarus +Tested-by: Marek Vasut # S25FS512S +Signed-off-by: Takahiro Kuwano +Signed-off-by: Pratyush Yadav +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 3 +++ + drivers/mtd/spi-nor/sfdp.c | 18 ++++++++++++++++-- + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index cc70a2092494c..4aac34f06c7bb 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -407,6 +407,8 @@ struct spi_nor_flash_parameter { + * flash parameters when information provided by the flash_info + * table is incomplete or wrong. + * @post_bfpt: called after the BFPT table has been parsed ++ * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the ++ * number of dummy cycles in read register ops. + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. +@@ -424,6 +426,7 @@ struct spi_nor_fixups { + int (*post_bfpt)(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); ++ void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); + int (*post_sfdp)(struct spi_nor *nor); + void (*late_init)(struct spi_nor *nor); + }; +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index 6f47982105bd9..66c233db20e8e 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -659,6 +659,17 @@ static u8 spi_nor_smpt_addr_nbytes(const struct spi_nor *nor, const u32 settings + } + } + ++static void spi_nor_smpt_read_dummy_fixups(const struct spi_nor *nor, ++ u8 *read_dummy) ++{ ++ if (nor->manufacturer && nor->manufacturer->fixups && ++ nor->manufacturer->fixups->smpt_read_dummy) ++ nor->manufacturer->fixups->smpt_read_dummy(nor, read_dummy); ++ ++ if (nor->info->fixups && nor->info->fixups->smpt_read_dummy) ++ nor->info->fixups->smpt_read_dummy(nor, read_dummy); ++} ++ + /** + * spi_nor_smpt_read_dummy() - return the configuration detection command read + * latency, in clock cycles. +@@ -671,8 +682,11 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) + { + u8 read_dummy = SMPT_CMD_READ_DUMMY(settings); + +- if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) +- return nor->read_dummy; ++ if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) { ++ read_dummy = nor->read_dummy; ++ spi_nor_smpt_read_dummy_fixups(nor, &read_dummy); ++ } ++ + return read_dummy; + } + +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-spansion-add-support-for-infineon-s25fs2.patch b/queue-6.1/mtd-spi-nor-spansion-add-support-for-infineon-s25fs2.patch new file mode 100644 index 0000000000..3cd27d1167 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-spansion-add-support-for-infineon-s25fs2.patch @@ -0,0 +1,118 @@ +From 7a08bcf99387bef79004cd13031f4dcd999812ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Mar 2023 16:35:07 +0900 +Subject: mtd: spi-nor: spansion: Add support for Infineon S25FS256T + +From: Takahiro Kuwano + +[ Upstream commit 6afcc84080c415df81765c6d773edcba8fc30f6c ] + +Infineon S25FS256T is 256Mbit Quad SPI NOR flash. The key features and +differences comparing to other Spansion/Cypress flash familes are: + - 4-byte address mode by factory default + - Quad mode is enabled by factory default + - OP_READ_FAST_4B(0Ch) is not supported + - Supports mixture of 128KB and 64KB sectors by OTP configuration + (this patch supports uniform 128KB only due to complexity of + non-uniform layout) + +Tested on Xilinx Zynq-7000 FPGA board. + +Link: https://www.infineon.com/dgdlac/Infineon-S25FS256T_256Mb_SEMPER_Nano_Flash_Quad_SPI_1.8V-DataSheet-v12_00-EN.pdf?fileId=8ac78c8c80027ecd0180740c5a46707a +Signed-off-by: Takahiro Kuwano +Link: https://lore.kernel.org/r/097ef04484966593ba1326d0a99462753d7d1073.1677557525.git.Takahiro.Kuwano@infineon.com +Signed-off-by: Tudor Ambarus +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/spansion.c | 60 ++++++++++++++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c +index 3ae59c7822039..5914a6074a11e 100644 +--- a/drivers/mtd/spi-nor/spansion.c ++++ b/drivers/mtd/spi-nor/spansion.c +@@ -29,6 +29,7 @@ + SPINOR_REG_CYPRESS_CFR5_OPI) + #define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS SPINOR_REG_CYPRESS_CFR5_BIT6 + #define SPINOR_OP_CYPRESS_RD_FAST 0xee ++#define SPINOR_REG_CYPRESS_ARCFN 0x00000006 + + /* Cypress SPI NOR flash operations. */ + #define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \ +@@ -229,6 +230,62 @@ static void cypress_nor_ecc_init(struct spi_nor *nor) + nor->flags |= SNOR_F_ECC; + } + ++static int ++s25fs256t_post_bfpt_fixup(struct spi_nor *nor, ++ const struct sfdp_parameter_header *bfpt_header, ++ const struct sfdp_bfpt *bfpt) ++{ ++ struct spi_mem_op op; ++ int ret; ++ ++ /* 4-byte address mode is enabled by default */ ++ nor->params->addr_nbytes = 4; ++ nor->params->addr_mode_nbytes = 4; ++ ++ /* Read Architecture Configuration Register (ARCFN) */ ++ op = (struct spi_mem_op) ++ CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, ++ SPINOR_REG_CYPRESS_ARCFN, 1, ++ nor->bouncebuf); ++ ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); ++ if (ret) ++ return ret; ++ ++ /* ARCFN value must be 0 if uniform sector is selected */ ++ if (nor->bouncebuf[0]) ++ return -ENODEV; ++ ++ return cypress_nor_set_page_size(nor); ++} ++ ++static void s25fs256t_post_sfdp_fixup(struct spi_nor *nor) ++{ ++ struct spi_nor_flash_parameter *params = nor->params; ++ ++ /* PP_1_1_4_4B is supported but missing in 4BAIT. */ ++ params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; ++ spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], ++ SPINOR_OP_PP_1_1_4_4B, ++ SNOR_PROTO_1_1_4); ++} ++ ++static void s25fs256t_late_init(struct spi_nor *nor) ++{ ++ /* ++ * Programming is supported only in 16-byte ECC data unit granularity. ++ * Byte-programming, bit-walking, or multiple program operations to the ++ * same ECC data unit without an erase are not allowed. See chapter ++ * 5.3.1 and 5.6 in the datasheet. ++ */ ++ nor->params->writesize = 16; ++} ++ ++static struct spi_nor_fixups s25fs256t_fixups = { ++ .post_bfpt = s25fs256t_post_bfpt_fixup, ++ .post_sfdp = s25fs256t_post_sfdp_fixup, ++ .late_init = s25fs256t_late_init, ++}; ++ + static int + s25hx_t_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, +@@ -454,6 +511,9 @@ static const struct flash_info spansion_nor_parts[] = { + { "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) + FIXUP_FLAGS(SPI_NOR_4B_OPCODES) }, ++ { "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0) ++ PARSE_SFDP ++ .fixups = &s25fs256t_fixups }, + { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256) + PARSE_SFDP + MFR_FLAGS(USE_CLSR) +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-spansion-make-rd_any_reg_op-macro-take-n.patch b/queue-6.1/mtd-spi-nor-spansion-make-rd_any_reg_op-macro-take-n.patch new file mode 100644 index 0000000000..7dac802782 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-spansion-make-rd_any_reg_op-macro-take-n.patch @@ -0,0 +1,72 @@ +From bdde21db748fc57cd8a50466029530b8f0f4093c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Mar 2023 16:35:06 +0900 +Subject: mtd: spi-nor: spansion: Make RD_ANY_REG_OP macro take number of dummy + bytes + +From: Takahiro Kuwano + +[ Upstream commit d628783c46d3c317deb0671ceb986be358fbaf69 ] + +Currently Read Any Register op is used to read volatile registers without +any dummy cycles, but the op requires dummy cycles depending on register +type (volatiler or non-volatile), device family, and device configuration. +Add 'ndummy' argument to RD_ANY_REG_OP macro to support other use cases. + +Suggested-by: Tudor Ambarus +Signed-off-by: Takahiro Kuwano +Link: https://lore.kernel.org/r/03756e9e3ac41d2016a71d2afb702398dd0b19ed.1677557525.git.Takahiro.Kuwano@infineon.com +Signed-off-by: Tudor Ambarus +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/spansion.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c +index faa8a49545be7..3ae59c7822039 100644 +--- a/drivers/mtd/spi-nor/spansion.c ++++ b/drivers/mtd/spi-nor/spansion.c +@@ -37,10 +37,10 @@ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) + +-#define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, buf) \ ++#define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, ndummy, buf) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), \ + SPI_MEM_OP_ADDR(naddr, addr, 0), \ +- SPI_MEM_OP_NO_DUMMY, \ ++ SPI_MEM_OP_DUMMY(ndummy, 0), \ + SPI_MEM_OP_DATA_IN(1, buf, 0)) + + #define SPANSION_CLSR_OP \ +@@ -148,7 +148,7 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) + + op = (struct spi_mem_op) + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, +- SPINOR_REG_CYPRESS_CFR1V, ++ SPINOR_REG_CYPRESS_CFR1V, 0, + nor->bouncebuf); + + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); +@@ -173,7 +173,7 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) + /* Read back and check it. */ + op = (struct spi_mem_op) + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, +- SPINOR_REG_CYPRESS_CFR1V, ++ SPINOR_REG_CYPRESS_CFR1V, 0, + nor->bouncebuf); + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (ret) +@@ -202,7 +202,7 @@ static int cypress_nor_set_page_size(struct spi_nor *nor) + { + struct spi_mem_op op = + CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, +- SPINOR_REG_CYPRESS_CFR3V, ++ SPINOR_REG_CYPRESS_CFR3V, 0, + nor->bouncebuf); + int ret; + +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-spansion-rename-s28hs512t-prefix.patch b/queue-6.1/mtd-spi-nor-spansion-rename-s28hs512t-prefix.patch new file mode 100644 index 0000000000..03aaa18335 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-spansion-rename-s28hs512t-prefix.patch @@ -0,0 +1,78 @@ +From cf7dcdb97d4fb05a73a672e299dda6cbaf6c4abb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Aug 2022 13:59:05 +0900 +Subject: mtd: spi-nor: spansion: Rename s28hs512t prefix + +From: Takahiro Kuwano + +[ Upstream commit 06051322704bf38cbd721e14bdbd6e43c8e6d7e1 ] + +Change prefix to support all other devices in SEMPER S28 family. + +Signed-off-by: Takahiro Kuwano +Signed-off-by: Tudor Ambarus +Reviewed-by: Michael Walle +Link: https://lore.kernel.org/r/8cf6bc9bffd50e486867c0817de1fa56c5d308ec.1661915569.git.Takahiro.Kuwano@infineon.com +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/spansion.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c +index 7e7c68fc7776d..0109fccca7ea2 100644 +--- a/drivers/mtd/spi-nor/spansion.c ++++ b/drivers/mtd/spi-nor/spansion.c +@@ -288,7 +288,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) + cypress_nor_octal_dtr_dis(nor); + } + +-static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor) ++static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor) + { + /* + * On older versions of the flash the xSPI Profile 1.0 table has the +@@ -316,23 +316,23 @@ static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor) + nor->params->rdsr_addr_nbytes = 4; + } + +-static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor, +- const struct sfdp_parameter_header *bfpt_header, +- const struct sfdp_bfpt *bfpt) ++static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, ++ const struct sfdp_parameter_header *bfpt_header, ++ const struct sfdp_bfpt *bfpt) + { + return cypress_nor_set_page_size(nor); + } + +-static void s28hs512t_late_init(struct spi_nor *nor) ++static void s28hx_t_late_init(struct spi_nor *nor) + { + nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; + cypress_nor_ecc_init(nor); + } + +-static const struct spi_nor_fixups s28hs512t_fixups = { +- .post_sfdp = s28hs512t_post_sfdp_fixup, +- .post_bfpt = s28hs512t_post_bfpt_fixup, +- .late_init = s28hs512t_late_init, ++static const struct spi_nor_fixups s28hx_t_fixups = { ++ .post_sfdp = s28hx_t_post_sfdp_fixup, ++ .post_bfpt = s28hx_t_post_bfpt_fixup, ++ .late_init = s28hx_t_late_init, + }; + + static int +@@ -468,7 +468,7 @@ static const struct flash_info spansion_nor_parts[] = { + FLAGS(SPI_NOR_NO_ERASE) }, + { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256) + PARSE_SFDP +- .fixups = &s28hs512t_fixups, ++ .fixups = &s28hx_t_fixups, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-spansion-replace-hardcoded-values-for-ad.patch b/queue-6.1/mtd-spi-nor-spansion-replace-hardcoded-values-for-ad.patch new file mode 100644 index 0000000000..860955ec86 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-spansion-replace-hardcoded-values-for-ad.patch @@ -0,0 +1,84 @@ +From 16d8fdb1f5d125a6ae87a752960d02de48642fa7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Jul 2022 07:14:50 +0300 +Subject: mtd: spi-nor: spansion: Replace hardcoded values for + addr_nbytes/addr_mode_nbytes + +From: Tudor Ambarus + +[ Upstream commit 05ebc1ccb8affcbaaa9f8b8fe56839cbfc9b9144 ] + +We track in the core the internal address mode of the flash. Stop using +hardcoded values for the number of bytes of address and use +nor->addr_nbytes and nor->params->addr_mode_nbytes instead. + +Signed-off-by: Tudor Ambarus +Tested-by: Takahiro Kuwano +Link: https://lore.kernel.org/r/20220728041451.85559-2-tudor.ambarus@microchip.com +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/spansion.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c +index 0109fccca7ea2..faa8a49545be7 100644 +--- a/drivers/mtd/spi-nor/spansion.c ++++ b/drivers/mtd/spi-nor/spansion.c +@@ -54,11 +54,13 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) + struct spi_mem_op op; + u8 *buf = nor->bouncebuf; + int ret; ++ u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; + + /* Use 24 dummy cycles for memory array reads. */ + *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24; + op = (struct spi_mem_op) +- CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR2V, 1, buf); ++ CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, ++ SPINOR_REG_CYPRESS_CFR2V, 1, buf); + + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + if (ret) +@@ -69,14 +71,16 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) + /* Set the octal and DTR enable bits. */ + buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN; + op = (struct spi_mem_op) +- CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR5V, 1, buf); ++ CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, ++ SPINOR_REG_CYPRESS_CFR5V, 1, buf); + + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + /* Read flash ID to make sure the switch was successful. */ +- ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR); ++ ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf, ++ SNOR_PROTO_8_8_8_DTR); + if (ret) { + dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); + return ret; +@@ -102,7 +106,8 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) + buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS; + buf[1] = 0; + op = (struct spi_mem_op) +- CYPRESS_NOR_WR_ANY_REG_OP(4, SPINOR_REG_CYPRESS_CFR5V, 2, buf); ++ CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, ++ SPINOR_REG_CYPRESS_CFR5V, 2, buf); + ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); + if (ret) + return ret; +@@ -196,7 +201,8 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) + static int cypress_nor_set_page_size(struct spi_nor *nor) + { + struct spi_mem_op op = +- CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR3V, ++ CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, ++ SPINOR_REG_CYPRESS_CFR3V, + nor->bouncebuf); + int ret; + +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch b/queue-6.1/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch new file mode 100644 index 0000000000..fe1f23f948 --- /dev/null +++ b/queue-6.1/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch @@ -0,0 +1,41 @@ +From 0060f65149a73471b20d408b689ae544f9410a5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 20:42:56 +0800 +Subject: mtd: spi-nor: swp: check SR_TB flag when getting tb_mask + +From: Shiji Yang + +[ Upstream commit 94645aa41bf9ecb87c2ce78b1c3405bfb6074a37 ] + +When the chip does not support top/bottom block protect, the tb_mask +must be set to 0, otherwise SR1 bit5 will be unexpectedly modified. + +Signed-off-by: Shiji Yang +Fixes: 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support") +Reviewed-by: Michael Walle +Reviewed-by: Miquel Raynal +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/swp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c +index e63cdae6dd745..a587561dd476e 100644 +--- a/drivers/mtd/spi-nor/swp.c ++++ b/drivers/mtd/spi-nor/swp.c +@@ -27,8 +27,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) + { + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + return SR_TB_BIT6; +- else ++ else if (nor->flags & SNOR_F_HAS_SR_TB) + return SR_TB_BIT5; ++ else ++ return 0; + } + + static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) +-- +2.53.0 + diff --git a/queue-6.1/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch b/queue-6.1/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch new file mode 100644 index 0000000000..9c70aeaeef --- /dev/null +++ b/queue-6.1/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch @@ -0,0 +1,40 @@ +From 8d500e08f212bb6c38df4bf86747724af383b859 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:54:30 +0100 +Subject: mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation + +From: Jonas Gorski + +[ Upstream commit 3620d67b48493c6252bbc873dc88dde81641d56b ] + +After commit 5273cc6df984 ("mtd: spi-nor: core: Call +spi_nor_post_sfdp_fixups() only when SFDP is defined") +spi_nor_post_sfdp_fixups() isn't called anymore if no SFDP is detected. + +Update the documentation accordingly. + +Fixes: 5273cc6df984 ("mtd: spi-nor: core: Call spi_nor_post_sfdp_fixups() only when SFDP is defined") +Signed-off-by: Jonas Gorski +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 1bf6bad5942d6..da451859c3910 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -411,7 +411,7 @@ struct spi_nor_flash_parameter { + * number of dummy cycles in read register ops. + * @smpt_map_id: called after map ID in SMPT table has been determined for the + * case the map ID is wrong and needs to be fixed. +- * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs ++ * @post_sfdp: called after SFDP has been parsed (is not called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. + * when information provided by the SFDP/flash_info tables are +-- +2.53.0 + diff --git a/queue-6.1/neigh-let-neigh_xmit-take-skb-ownership.patch b/queue-6.1/neigh-let-neigh_xmit-take-skb-ownership.patch new file mode 100644 index 0000000000..c32086dbd9 --- /dev/null +++ b/queue-6.1/neigh-let-neigh_xmit-take-skb-ownership.patch @@ -0,0 +1,74 @@ +From aaa17b254c67e844b2c4ece37aef40313c90fb13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 16:58:38 +0200 +Subject: neigh: let neigh_xmit take skb ownership + +From: Florian Westphal + +[ Upstream commit 4438113be604ee67a7bf4f81da6e1cca41332ce4 ] + +neigh_xmit always releases the skb, except when no neighbour table is +found. But even the first added user of neigh_xmit (mpls) relied on +neigh_xmit to release the skb (or queue it for tx). + +sashiko reported: + If neigh_xmit() is called with an uninitialized neighbor table (for + example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT + and bypasses its internal out_kfree_skb error path. Because the return + value of neigh_xmit() is ignored here, does this leak the SKB? + +Assume full ownership and remove the last code path that doesn't +xmit or free skb. + +Fixes: 4fd3d7d9e868 ("neigh: Add helper function neigh_xmit") +Signed-off-by: Florian Westphal +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260424145843.74055-1-fw@strlen.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index fe0e839972ba7..7bdb2b5a6e014 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -3154,8 +3154,10 @@ int neigh_xmit(int index, struct net_device *dev, + + rcu_read_lock(); + tbl = rcu_dereference(neigh_tables[index]); +- if (!tbl) +- goto out_unlock; ++ if (!tbl) { ++ rcu_read_unlock(); ++ goto out_kfree_skb; ++ } + if (index == NEIGH_ARP_TABLE) { + u32 key = *((u32 *)addr); + +@@ -3171,7 +3173,6 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + } + err = READ_ONCE(neigh->output)(neigh, skb); +-out_unlock: + rcu_read_unlock(); + } + else if (index == NEIGH_LINK_TABLE) { +@@ -3181,11 +3182,10 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + err = dev_queue_xmit(skb); + } +-out: + return err; + out_kfree_skb: + kfree_skb(skb); +- goto out; ++ return err; + } + EXPORT_SYMBOL(neigh_xmit); + +-- +2.53.0 + diff --git a/queue-6.1/neighbour-add-rcu-protection-to-neigh_tables.patch b/queue-6.1/neighbour-add-rcu-protection-to-neigh_tables.patch new file mode 100644 index 0000000000..25ece779cb --- /dev/null +++ b/queue-6.1/neighbour-add-rcu-protection-to-neigh_tables.patch @@ -0,0 +1,126 @@ +From 8e0951ce076a94e61e297f04a2b0645429c353e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Apr 2024 09:51:04 +0000 +Subject: neighbour: add RCU protection to neigh_tables[] + +From: Eric Dumazet + +[ Upstream commit f8f2eb9de69a1119117d198547c13d7a1123a5a9 ] + +In order to remove RTNL protection from neightbl_dump_info() +and neigh_dump_info() later, we need to add +RCU protection to neigh_tables[]. + +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +Stable-dep-of: 4438113be604 ("neigh: let neigh_xmit take skb ownership") +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 30 +++++++++++++++++++----------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index 92dc1f1788de7..fe0e839972ba7 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -1764,7 +1764,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms) + + static struct lock_class_key neigh_table_proxy_queue_class; + +-static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly; ++static struct neigh_table __rcu *neigh_tables[NEIGH_NR_TABLES] __read_mostly; + + void neigh_table_init(int index, struct neigh_table *tbl) + { +@@ -1821,13 +1821,19 @@ void neigh_table_init(int index, struct neigh_table *tbl) + tbl->last_flush = now; + tbl->last_rand = now + tbl->parms.reachable_time * 20; + +- neigh_tables[index] = tbl; ++ rcu_assign_pointer(neigh_tables[index], tbl); + } + EXPORT_SYMBOL(neigh_table_init); + ++/* ++ * Only called from ndisc_cleanup(), which means this is dead code ++ * because we no longer can unload IPv6 module. ++ */ + int neigh_table_clear(int index, struct neigh_table *tbl) + { +- neigh_tables[index] = NULL; ++ RCU_INIT_POINTER(neigh_tables[index], NULL); ++ synchronize_rcu(); ++ + /* It is not clean... Fix it to unload IPv6 module safely */ + cancel_delayed_work_sync(&tbl->managed_work); + cancel_delayed_work_sync(&tbl->gc_work); +@@ -1859,10 +1865,10 @@ static struct neigh_table *neigh_find_table(int family) + + switch (family) { + case AF_INET: +- tbl = neigh_tables[NEIGH_ARP_TABLE]; ++ tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ARP_TABLE]); + break; + case AF_INET6: +- tbl = neigh_tables[NEIGH_ND_TABLE]; ++ tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ND_TABLE]); + break; + } + +@@ -2328,7 +2334,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, + ndtmsg = nlmsg_data(nlh); + + for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { +- tbl = neigh_tables[tidx]; ++ tbl = rcu_dereference_rtnl(neigh_tables[tidx]); + if (!tbl) + continue; + if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) +@@ -2516,7 +2522,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) + for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { + struct neigh_parms *p; + +- tbl = neigh_tables[tidx]; ++ tbl = rcu_dereference_rtnl(neigh_tables[tidx]); + if (!tbl) + continue; + +@@ -2877,7 +2883,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) + s_t = cb->args[0]; + + for (t = 0; t < NEIGH_NR_TABLES; t++) { +- tbl = neigh_tables[t]; ++ tbl = rcu_dereference_rtnl(neigh_tables[t]); + + if (!tbl) + continue; +@@ -3141,14 +3147,15 @@ int neigh_xmit(int index, struct net_device *dev, + const void *addr, struct sk_buff *skb) + { + int err = -EAFNOSUPPORT; ++ + if (likely(index < NEIGH_NR_TABLES)) { + struct neigh_table *tbl; + struct neighbour *neigh; + +- tbl = neigh_tables[index]; +- if (!tbl) +- goto out; + rcu_read_lock(); ++ tbl = rcu_dereference(neigh_tables[index]); ++ if (!tbl) ++ goto out_unlock; + if (index == NEIGH_ARP_TABLE) { + u32 key = *((u32 *)addr); + +@@ -3164,6 +3171,7 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + } + err = READ_ONCE(neigh->output)(neigh, skb); ++out_unlock: + rcu_read_unlock(); + } + else if (index == NEIGH_LINK_TABLE) { +-- +2.53.0 + diff --git a/queue-6.1/net-bcmgenet-add-bcmgenet_has_-helpers.patch b/queue-6.1/net-bcmgenet-add-bcmgenet_has_-helpers.patch new file mode 100644 index 0000000000..11e458ac68 --- /dev/null +++ b/queue-6.1/net-bcmgenet-add-bcmgenet_has_-helpers.patch @@ -0,0 +1,192 @@ +From 6c2fa2ed2cc1ae8f9909321d0f6466cc4bfba066 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:30 -0800 +Subject: net: bcmgenet: add bcmgenet_has_* helpers + +From: Doug Berger + +[ Upstream commit 07c1a756a50b1180a085ab61819a388bbb906a95 ] + +Introduce helper functions to indicate whether the driver should +make use of a particular feature that it supports. These helpers +abstract the implementation of how the feature availability is +encoded. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-3-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 20 +++++++------- + .../net/ethernet/broadcom/genet/bcmgenet.h | 27 ++++++++++++++++++- + drivers/net/ethernet/broadcom/genet/bcmmii.c | 6 ++--- + 3 files changed, 39 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 4d76c9aebd439..88d2a8c3d3baf 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -104,7 +104,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, + * the platform is explicitly configured for 64-bits/LPAE. + */ + #ifdef CONFIG_PHYS_ADDR_T_64BIT +- if (priv->hw_params->flags & GENET_HAS_40BITS) ++ if (bcmgenet_has_40bits(priv)) + bcmgenet_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI); + #endif + } +@@ -1648,9 +1648,9 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv, + + case GENET_POWER_PASSIVE: + /* Power down LED */ +- if (priv->hw_params->flags & GENET_HAS_EXT) { ++ if (bcmgenet_has_ext(priv)) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); +- if (GENET_IS_V5(priv) && !priv->ephy_16nm) ++ if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) + reg |= EXT_PWR_DOWN_PHY_EN | + EXT_PWR_DOWN_PHY_RD | + EXT_PWR_DOWN_PHY_SD | +@@ -1678,7 +1678,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, + { + u32 reg; + +- if (!(priv->hw_params->flags & GENET_HAS_EXT)) ++ if (!bcmgenet_has_ext(priv)) + return; + + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); +@@ -1687,7 +1687,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, + case GENET_POWER_PASSIVE: + reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS | + EXT_ENERGY_DET_MASK); +- if (GENET_IS_V5(priv) && !priv->ephy_16nm) { ++ if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) { + reg &= ~(EXT_PWR_DOWN_PHY_EN | + EXT_PWR_DOWN_PHY_RD | + EXT_PWR_DOWN_PHY_SD | +@@ -2520,7 +2520,7 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv) + } else if (priv->ext_phy) { + int0_enable |= UMAC_IRQ_LINK_EVENT; + } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { +- if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) ++ if (bcmgenet_has_moca_link_det(priv)) + int0_enable |= UMAC_IRQ_LINK_EVENT; + } + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); +@@ -2585,7 +2585,7 @@ static void init_umac(struct bcmgenet_priv *priv) + } + + /* Enable MDIO interrupts on GENET v3+ */ +- if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) ++ if (bcmgenet_has_mdio_intr(priv)) + int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); + + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); +@@ -3225,7 +3225,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + } + } + +- if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && ++ if (bcmgenet_has_mdio_intr(priv) && + status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + wake_up(&priv->wq); + } +@@ -3895,7 +3895,7 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) + } + + #ifdef CONFIG_PHYS_ADDR_T_64BIT +- if (!(params->flags & GENET_HAS_40BITS)) ++ if (!bcmgenet_has_40bits(priv)) + pr_warn("GENET does not support 40-bits PA\n"); + #endif + +@@ -4074,7 +4074,7 @@ static int bcmgenet_probe(struct platform_device *pdev) + bcmgenet_set_hw_params(priv); + + err = -EIO; +- if (priv->hw_params->flags & GENET_HAS_40BITS) ++ if (bcmgenet_has_40bits(priv)) + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + if (err) + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index 28e2c94ef835c..ba83819210aa8 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0-only */ + /* +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #ifndef __BCMGENET_H__ +@@ -650,6 +650,31 @@ struct bcmgenet_priv { + struct ethtool_eee eee; + }; + ++static inline bool bcmgenet_has_40bits(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_40BITS); ++} ++ ++static inline bool bcmgenet_has_ext(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_EXT); ++} ++ ++static inline bool bcmgenet_has_mdio_intr(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_MDIO_INTR); ++} ++ ++static inline bool bcmgenet_has_moca_link_det(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET); ++} ++ ++static inline bool bcmgenet_has_ephy_16nm(struct bcmgenet_priv *priv) ++{ ++ return priv->ephy_16nm; ++} ++ + #define GENET_IO_MACRO(name, offset) \ + static inline u32 bcmgenet_##name##_readl(struct bcmgenet_priv *priv, \ + u32 off) \ +diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c +index f21f2aaa6fd91..3836ea92527f3 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c +@@ -2,7 +2,7 @@ + /* + * Broadcom GENET MDIO routines + * +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #include +@@ -153,7 +153,7 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable) + u32 reg = 0; + + /* EXT_GPHY_CTRL is only valid for GENETv4 and onward */ +- if (GENET_IS_V4(priv) || priv->ephy_16nm) { ++ if (GENET_IS_V4(priv) || bcmgenet_has_ephy_16nm(priv)) { + reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL); + if (enable) { + reg &= ~EXT_CK25_DIS; +@@ -183,7 +183,7 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable) + + static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) + { +- if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) ++ if (bcmgenet_has_moca_link_det(priv)) + fixed_phy_set_link_update(priv->dev->phydev, + bcmgenet_fixed_phy_link_update); + } +-- +2.53.0 + diff --git a/queue-6.1/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch b/queue-6.1/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch new file mode 100644 index 0000000000..2527639b1f --- /dev/null +++ b/queue-6.1/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch @@ -0,0 +1,50 @@ +From b18ddc8fcd601778a6a0761d0080b5f502ad72e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:54 -0700 +Subject: net: bcmgenet: fix off-by-one in bcmgenet_put_txcb + +From: Justin Chen + +[ Upstream commit 57f3f53d2c9c5a9e133596e2f7bc1c50688a6d38 ] + +The write_ptr points to the next open tx_cb. We want to return the +tx_cb that gets rewinded, so we must rewind the pointer first then +return the tx_cb that it points to. That way the txcb can be correctly +cleaned up. + +Fixes: 876dbadd53a7 ("net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()") +Signed-off-by: Justin Chen +Reviewed-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-2-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index f087a97164094..650f51471a0e1 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1744,15 +1744,15 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + { + struct enet_cb *tx_cb_ptr; + +- tx_cb_ptr = ring->cbs; +- tx_cb_ptr += ring->write_ptr - ring->cb_ptr; +- + /* Rewinding local write pointer */ + if (ring->write_ptr == ring->cb_ptr) + ring->write_ptr = ring->end_ptr; + else + ring->write_ptr--; + ++ tx_cb_ptr = ring->cbs; ++ tx_cb_ptr += ring->write_ptr - ring->cb_ptr; ++ + return tx_cb_ptr; + } + +-- +2.53.0 + diff --git a/queue-6.1/net-bcmgenet-fix-racing-timeout-handler.patch b/queue-6.1/net-bcmgenet-fix-racing-timeout-handler.patch new file mode 100644 index 0000000000..4ed80b56cc --- /dev/null +++ b/queue-6.1/net-bcmgenet-fix-racing-timeout-handler.patch @@ -0,0 +1,70 @@ +From c23dc533464d5938d1a0880357f1c0a71f3d1a29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:56 -0700 +Subject: net: bcmgenet: fix racing timeout handler + +From: Justin Chen + +[ Upstream commit 5393b2b5bee2ac51a0043dc7f4ac3475f053d08d ] + +The bcmgenet_timeout handler tries to take down all tx queues when +a single queue times out. This is over zealous and causes many race +conditions with queues that are still chugging along. Instead lets +only restart the timed out queue. + +Fixes: 13ea657806cf ("net: bcmgenet: improve TX timeout") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-4-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 22 ++++++++----------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 12aa07fb81db3..43fba7b47d1cd 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -3469,27 +3469,23 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 int1_enable = 0; +- unsigned int q; ++ struct bcmgenet_tx_ring *ring = &priv->tx_rings[txqueue]; ++ struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue); + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- bcmgenet_dump_tx_queue(&priv->tx_rings[q]); +- +- bcmgenet_tx_reclaim_all(dev); ++ bcmgenet_dump_tx_queue(ring); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- int1_enable |= (1 << q); ++ bcmgenet_tx_reclaim(dev, ring, true); + +- /* Re-enable TX interrupts if disabled */ +- bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); ++ /* Re-enable the TX interrupt for this ring */ ++ bcmgenet_intrl2_1_writel(priv, 1 << txqueue, INTRL2_CPU_MASK_CLEAR); + +- netif_trans_update(dev); ++ txq_trans_cond_update(txq); + +- BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors); ++ BCMGENET_STATS64_INC((&ring->stats64), errors); + +- netif_tx_wake_all_queues(dev); ++ netif_tx_wake_queue(txq); + } + + #define MAX_MDF_FILTER 17 +-- +2.53.0 + diff --git a/queue-6.1/net-bcmgenet-move-desc_index-flow-to-ring-0.patch b/queue-6.1/net-bcmgenet-move-desc_index-flow-to-ring-0.patch new file mode 100644 index 0000000000..b24a8b157c --- /dev/null +++ b/queue-6.1/net-bcmgenet-move-desc_index-flow-to-ring-0.patch @@ -0,0 +1,947 @@ +From e4745938ef36627ec6bac2c56983b0727ac2cec9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:34 -0800 +Subject: net: bcmgenet: move DESC_INDEX flow to ring 0 + +From: Doug Berger + +[ Upstream commit 3b5d4f5a820d362dd46472542b2e961fb1f93515 ] + +The default transmit and receive packet handling is moved from +the DESC_INDEX (i.e. 16) descriptor rings to the Ring 0 queues. +This saves a fair amount of special case code by unifying the +handling. + +A default dummy filter is enabled in the Hardware Filter Block +to route default receive packets to Ring 0. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-7-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 369 +++++------------- + .../net/ethernet/broadcom/genet/bcmgenet.h | 12 +- + .../ethernet/broadcom/genet/bcmgenet_wol.c | 4 +- + 3 files changed, 110 insertions(+), 275 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 88d2a8c3d3baf..9f670bbecc726 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -41,15 +41,13 @@ + + #include "bcmgenet.h" + +-/* Maximum number of hardware queues, downsized if needed */ +-#define GENET_MAX_MQ_CNT 4 +- + /* Default highest priority queue for multi queue support */ +-#define GENET_Q0_PRIORITY 0 ++#define GENET_Q1_PRIORITY 0 ++#define GENET_Q0_PRIORITY 1 + +-#define GENET_Q16_RX_BD_CNT \ ++#define GENET_Q0_RX_BD_CNT \ + (TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q) +-#define GENET_Q16_TX_BD_CNT \ ++#define GENET_Q0_TX_BD_CNT \ + (TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->tx_bds_per_q) + + #define RX_BUF_LENGTH 2048 +@@ -603,7 +601,7 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, + u16 mask_16; + size_t size; + +- f = fs->location; ++ f = fs->location + 1; + if (fs->flow_type & FLOW_MAC_EXT) { + bcmgenet_hfb_insert_data(priv, f, 0, + &fs->h_ext.h_dest, &fs->m_ext.h_dest, +@@ -685,19 +683,14 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, + } + + bcmgenet_hfb_set_filter_length(priv, f, 2 * f_length); +- if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) { +- /* Ring 0 flows can be handled by the default Descriptor Ring +- * We'll map them to ring 0, but don't enable the filter +- */ ++ if (fs->ring_cookie == RX_CLS_FLOW_WAKE) + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, 0); +- rule->state = BCMGENET_RXNFC_STATE_DISABLED; +- } else { ++ else + /* Other Rx rings are direct mapped here */ + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, + fs->ring_cookie); +- bcmgenet_hfb_enable_filter(priv, f); +- rule->state = BCMGENET_RXNFC_STATE_ENABLED; +- } ++ bcmgenet_hfb_enable_filter(priv, f); ++ rule->state = BCMGENET_RXNFC_STATE_ENABLED; + } + + /* bcmgenet_hfb_clear +@@ -733,6 +726,10 @@ static void bcmgenet_hfb_clear(struct bcmgenet_priv *priv) + + for (i = 0; i < priv->hw_params->hfb_filter_cnt; i++) + bcmgenet_hfb_clear_filter(priv, i); ++ ++ /* Enable filter 0 to send default flow to ring 0 */ ++ bcmgenet_hfb_set_filter_length(priv, 0, 4); ++ bcmgenet_hfb_enable_filter(priv, 0); + } + + static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) +@@ -837,20 +834,16 @@ static int bcmgenet_get_coalesce(struct net_device *dev, + unsigned int i; + + ec->tx_max_coalesced_frames = +- bcmgenet_tdma_ring_readl(priv, DESC_INDEX, +- DMA_MBUF_DONE_THRESH); ++ bcmgenet_tdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); + ec->rx_max_coalesced_frames = +- bcmgenet_rdma_ring_readl(priv, DESC_INDEX, +- DMA_MBUF_DONE_THRESH); ++ bcmgenet_rdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); + ec->rx_coalesce_usecs = +- bcmgenet_rdma_readl(priv, DMA_RING16_TIMEOUT) * 8192 / 1000; ++ bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT) * 8192 / 1000; + +- for (i = 0; i < priv->hw_params->rx_queues; i++) { ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) { + ring = &priv->rx_rings[i]; + ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; + } +- ring = &priv->rx_rings[DESC_INDEX]; +- ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; + + return 0; + } +@@ -920,17 +913,13 @@ static int bcmgenet_set_coalesce(struct net_device *dev, + /* Program all TX queues with the same values, as there is no + * ethtool knob to do coalescing on a per-queue basis + */ +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + bcmgenet_tdma_ring_writel(priv, i, + ec->tx_max_coalesced_frames, + DMA_MBUF_DONE_THRESH); +- bcmgenet_tdma_ring_writel(priv, DESC_INDEX, +- ec->tx_max_coalesced_frames, +- DMA_MBUF_DONE_THRESH); + +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[i], ec); +- bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[DESC_INDEX], ec); + + return 0; + } +@@ -1138,7 +1127,7 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + STAT_GENET_Q(1), + STAT_GENET_Q(2), + STAT_GENET_Q(3), +- STAT_GENET_Q(16), ++ STAT_GENET_Q(4), + }; + + #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) +@@ -1469,10 +1458,10 @@ static int bcmgenet_insert_flow(struct net_device *dev, + + loc_rule = &priv->rxnfc_rules[cmd->fs.location]; + if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) +- bcmgenet_hfb_disable_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); + if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { + list_del(&loc_rule->list); +- bcmgenet_hfb_clear_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); + } + loc_rule->state = BCMGENET_RXNFC_STATE_UNUSED; + memcpy(&loc_rule->fs, &cmd->fs, +@@ -1502,10 +1491,10 @@ static int bcmgenet_delete_flow(struct net_device *dev, + } + + if (rule->state == BCMGENET_RXNFC_STATE_ENABLED) +- bcmgenet_hfb_disable_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); + if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) { + list_del(&rule->list); +- bcmgenet_hfb_clear_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); + } + rule->state = BCMGENET_RXNFC_STATE_UNUSED; + memset(&rule->fs, 0, sizeof(struct ethtool_rx_flow_spec)); +@@ -1756,18 +1745,6 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + return tx_cb_ptr; + } + +-static inline void bcmgenet_rx_ring16_int_disable(struct bcmgenet_rx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_MASK_SET); +-} +- +-static inline void bcmgenet_rx_ring16_int_enable(struct bcmgenet_rx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_MASK_CLEAR); +-} +- + static inline void bcmgenet_rx_ring_int_disable(struct bcmgenet_rx_ring *ring) + { + bcmgenet_intrl2_1_writel(ring->priv, +@@ -1782,18 +1759,6 @@ static inline void bcmgenet_rx_ring_int_enable(struct bcmgenet_rx_ring *ring) + INTRL2_CPU_MASK_CLEAR); + } + +-static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_tx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_MASK_SET); +-} +- +-static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_tx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_MASK_CLEAR); +-} +- + static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_tx_ring *ring) + { + bcmgenet_intrl2_1_writel(ring->priv, 1 << ring->index, +@@ -1874,12 +1839,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + struct sk_buff *skb; + + /* Clear status before servicing to reduce spurious interrupts */ +- if (ring->index == DESC_INDEX) +- bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_CLEAR); +- else +- bcmgenet_intrl2_1_writel(priv, (1 << ring->index), +- INTRL2_CPU_CLEAR); ++ bcmgenet_intrl2_1_writel(priv, (1 << ring->index), INTRL2_CPU_CLEAR); + + /* Compute how many buffers are transmitted since last xmit call */ + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX) +@@ -1913,7 +1873,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + ring->packets += pkts_compl; + ring->bytes += bytes_compl; + +- netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->queue), ++ netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->index), + pkts_compl, bytes_compl); + + return txbds_processed; +@@ -1941,14 +1901,14 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) + spin_lock(&ring->lock); + work_done = __bcmgenet_tx_reclaim(ring->priv->dev, ring); + if (ring->free_bds > (MAX_SKB_FRAGS + 1)) { +- txq = netdev_get_tx_queue(ring->priv->dev, ring->queue); ++ txq = netdev_get_tx_queue(ring->priv->dev, ring->index); + netif_tx_wake_queue(txq); + } + spin_unlock(&ring->lock); + + if (work_done == 0) { + napi_complete(napi); +- ring->int_enable(ring); ++ bcmgenet_tx_ring_int_enable(ring); + + return 0; + } +@@ -1959,14 +1919,11 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) + static void bcmgenet_tx_reclaim_all(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- int i; +- +- if (netif_is_multiqueue(dev)) { +- for (i = 0; i < priv->hw_params->tx_queues; i++) +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[i]); +- } ++ int i = 0; + +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]); ++ do { ++ bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++]); ++ } while (i <= priv->hw_params->tx_queues && netif_is_multiqueue(dev)); + } + + /* Reallocate the SKB to put enough headroom in front of it and insert +@@ -2054,19 +2011,14 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) + + index = skb_get_queue_mapping(skb); + /* Mapping strategy: +- * queue_mapping = 0, unclassified, packet xmited through ring16 +- * queue_mapping = 1, goes to ring 0. (highest priority queue +- * queue_mapping = 2, goes to ring 1. +- * queue_mapping = 3, goes to ring 2. +- * queue_mapping = 4, goes to ring 3. ++ * queue_mapping = 0, unclassified, packet xmited through ring 0 ++ * queue_mapping = 1, goes to ring 1. (highest priority queue) ++ * queue_mapping = 2, goes to ring 2. ++ * queue_mapping = 3, goes to ring 3. ++ * queue_mapping = 4, goes to ring 4. + */ +- if (index == 0) +- index = DESC_INDEX; +- else +- index -= 1; +- + ring = &priv->tx_rings[index]; +- txq = netdev_get_tx_queue(dev, ring->queue); ++ txq = netdev_get_tx_queue(dev, index); + + nr_frags = skb_shinfo(skb)->nr_frags; + +@@ -2239,15 +2191,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + unsigned int discards; + + /* Clear status before servicing to reduce spurious interrupts */ +- if (ring->index == DESC_INDEX) { +- bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_CLEAR); +- } else { +- mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); +- bcmgenet_intrl2_1_writel(priv, +- mask, +- INTRL2_CPU_CLEAR); +- } ++ mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); ++ bcmgenet_intrl2_1_writel(priv, mask, INTRL2_CPU_CLEAR); + + p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX); + +@@ -2396,7 +2341,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) + + if (work_done < budget) { + napi_complete_done(napi, work_done); +- ring->int_enable(ring); ++ bcmgenet_rx_ring_int_enable(ring); + } + + if (ring->dim.use_dim) { +@@ -2636,15 +2581,6 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, + spin_lock_init(&ring->lock); + ring->priv = priv; + ring->index = index; +- if (index == DESC_INDEX) { +- ring->queue = 0; +- ring->int_enable = bcmgenet_tx_ring16_int_enable; +- ring->int_disable = bcmgenet_tx_ring16_int_disable; +- } else { +- ring->queue = index + 1; +- ring->int_enable = bcmgenet_tx_ring_int_enable; +- ring->int_disable = bcmgenet_tx_ring_int_disable; +- } + ring->cbs = priv->tx_cbs + start_ptr; + ring->size = size; + ring->clean_ptr = start_ptr; +@@ -2655,8 +2591,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, + ring->end_ptr = end_ptr - 1; + ring->prod_index = 0; + +- /* Set flow period for ring != 16 */ +- if (index != DESC_INDEX) ++ /* Set flow period for ring != 0 */ ++ if (index) + flow_period_val = ENET_MAX_MTU_SIZE << 16; + + bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); +@@ -2694,13 +2630,6 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, + + ring->priv = priv; + ring->index = index; +- if (index == DESC_INDEX) { +- ring->int_enable = bcmgenet_rx_ring16_int_enable; +- ring->int_disable = bcmgenet_rx_ring16_int_disable; +- } else { +- ring->int_enable = bcmgenet_rx_ring_int_enable; +- ring->int_disable = bcmgenet_rx_ring_int_disable; +- } + ring->cbs = priv->rx_cbs + start_ptr; + ring->size = size; + ring->c_index = 0; +@@ -2746,15 +2675,11 @@ static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + napi_enable(&ring->napi); +- ring->int_enable(ring); ++ bcmgenet_tx_ring_int_enable(ring); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- napi_enable(&ring->napi); +- ring->int_enable(ring); + } + + static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) +@@ -2762,13 +2687,10 @@ static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + napi_disable(&ring->napi); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- napi_disable(&ring->napi); + } + + static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) +@@ -2776,33 +2698,31 @@ static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + netif_napi_del(&ring->napi); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- netif_napi_del(&ring->napi); + } + + /* Initialize Tx queues + * +- * Queues 0-3 are priority-based, each one has 32 descriptors, +- * with queue 0 being the highest priority queue. ++ * Queues 1-4 are priority-based, each one has 32 descriptors, ++ * with queue 1 being the highest priority queue. + * +- * Queue 16 is the default Tx queue with +- * GENET_Q16_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. ++ * Queue 0 is the default Tx queue with ++ * GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. + * + * The transmit control block pool is then partitioned as follows: +- * - Tx queue 0 uses tx_cbs[0..31] +- * - Tx queue 1 uses tx_cbs[32..63] +- * - Tx queue 2 uses tx_cbs[64..95] +- * - Tx queue 3 uses tx_cbs[96..127] +- * - Tx queue 16 uses tx_cbs[128..255] ++ * - Tx queue 0 uses tx_cbs[0..127] ++ * - Tx queue 1 uses tx_cbs[128..159] ++ * - Tx queue 2 uses tx_cbs[160..191] ++ * - Tx queue 3 uses tx_cbs[192..223] ++ * - Tx queue 4 uses tx_cbs[224..255] + */ + static void bcmgenet_init_tx_queues(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); ++ unsigned int start = 0, end = GENET_Q0_TX_BD_CNT; + u32 i, dma_enable; + u32 dma_ctrl, ring_cfg; + u32 dma_priority[3] = {0, 0, 0}; +@@ -2819,27 +2739,17 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) + bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL); + + /* Initialize Tx priority queues */ +- for (i = 0; i < priv->hw_params->tx_queues; i++) { +- bcmgenet_init_tx_ring(priv, i, priv->hw_params->tx_bds_per_q, +- i * priv->hw_params->tx_bds_per_q, +- (i + 1) * priv->hw_params->tx_bds_per_q); ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) { ++ bcmgenet_init_tx_ring(priv, i, end - start, start, end); ++ start = end; ++ end += priv->hw_params->tx_bds_per_q; + ring_cfg |= (1 << i); + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + dma_priority[DMA_PRIO_REG_INDEX(i)] |= +- ((GENET_Q0_PRIORITY + i) << DMA_PRIO_REG_SHIFT(i)); ++ (i ? GENET_Q1_PRIORITY : GENET_Q0_PRIORITY) ++ << DMA_PRIO_REG_SHIFT(i); + } + +- /* Initialize Tx default queue 16 */ +- bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_Q16_TX_BD_CNT, +- priv->hw_params->tx_queues * +- priv->hw_params->tx_bds_per_q, +- TOTAL_DESC); +- ring_cfg |= (1 << DESC_INDEX); +- dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); +- dma_priority[DMA_PRIO_REG_INDEX(DESC_INDEX)] |= +- ((GENET_Q0_PRIORITY + priv->hw_params->tx_queues) << +- DMA_PRIO_REG_SHIFT(DESC_INDEX)); +- + /* Set Tx queue priorities */ + bcmgenet_tdma_writel(priv, dma_priority[0], DMA_PRIORITY_0); + bcmgenet_tdma_writel(priv, dma_priority[1], DMA_PRIORITY_1); +@@ -2859,15 +2769,11 @@ static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + napi_enable(&ring->napi); +- ring->int_enable(ring); ++ bcmgenet_rx_ring_int_enable(ring); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- napi_enable(&ring->napi); +- ring->int_enable(ring); + } + + static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) +@@ -2875,15 +2781,11 @@ static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + napi_disable(&ring->napi); + cancel_work_sync(&ring->dim.dim.work); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- napi_disable(&ring->napi); +- cancel_work_sync(&ring->dim.dim.work); + } + + static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) +@@ -2891,13 +2793,10 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + netif_napi_del(&ring->napi); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- netif_napi_del(&ring->napi); + } + + /* Initialize Rx queues +@@ -2905,15 +2804,13 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) + * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be + * used to direct traffic to these queues. + * +- * Queue 16 is the default Rx queue with GENET_Q16_RX_BD_CNT descriptors. ++ * Queue 0 is also the default Rx queue with GENET_Q0_RX_BD_CNT descriptors. + */ + static int bcmgenet_init_rx_queues(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 i; +- u32 dma_enable; +- u32 dma_ctrl; +- u32 ring_cfg; ++ unsigned int start = 0, end = GENET_Q0_RX_BD_CNT; ++ u32 i, dma_enable, dma_ctrl = 0, ring_cfg = 0; + int ret; + + dma_ctrl = bcmgenet_rdma_readl(priv, DMA_CTRL); +@@ -2925,34 +2822,21 @@ static int bcmgenet_init_rx_queues(struct net_device *dev) + ring_cfg = 0; + + /* Initialize Rx priority queues */ +- for (i = 0; i < priv->hw_params->rx_queues; i++) { +- ret = bcmgenet_init_rx_ring(priv, i, +- priv->hw_params->rx_bds_per_q, +- i * priv->hw_params->rx_bds_per_q, +- (i + 1) * +- priv->hw_params->rx_bds_per_q); ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) { ++ ret = bcmgenet_init_rx_ring(priv, i, end - start, start, end); + if (ret) + return ret; + ++ start = end; ++ end += priv->hw_params->rx_bds_per_q; + ring_cfg |= (1 << i); + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + } + +- /* Initialize Rx default queue 16 */ +- ret = bcmgenet_init_rx_ring(priv, DESC_INDEX, GENET_Q16_RX_BD_CNT, +- priv->hw_params->rx_queues * +- priv->hw_params->rx_bds_per_q, +- TOTAL_DESC); +- if (ret) +- return ret; +- +- ring_cfg |= (1 << DESC_INDEX); +- dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); +- +- /* Enable rings */ ++ /* Configure Rx queues as descriptor rings */ + bcmgenet_rdma_writel(priv, ring_cfg, DMA_RING_CFG); + +- /* Configure ring as descriptor ring and re-enable DMA if enabled */ ++ /* Enable Rx rings */ + if (dma_enable) + dma_ctrl |= DMA_EN; + bcmgenet_rdma_writel(priv, dma_ctrl, DMA_CTRL); +@@ -3011,14 +2895,14 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) + } + + dma_ctrl = 0; +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; + bcmgenet_rdma_writel(priv, reg, DMA_CTRL); + + dma_ctrl = 0; +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; +@@ -3039,14 +2923,11 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) + dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, + priv->tx_cbs + i)); + +- for (i = 0; i < priv->hw_params->tx_queues; i++) { +- txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[i].queue); ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) { ++ txq = netdev_get_tx_queue(priv->dev, i); + netdev_tx_reset_queue(txq); + } + +- txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[DESC_INDEX].queue); +- netdev_tx_reset_queue(txq); +- + bcmgenet_free_rx_buffers(priv); + kfree(priv->rx_cbs); + kfree(priv->tx_cbs); +@@ -3139,7 +3020,7 @@ static void bcmgenet_irq_task(struct work_struct *work) + + } + +-/* bcmgenet_isr1: handle Rx and Tx priority queues */ ++/* bcmgenet_isr1: handle Rx and Tx queues */ + static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + { + struct bcmgenet_priv *priv = dev_id; +@@ -3158,7 +3039,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + "%s: IRQ=0x%x\n", __func__, status); + + /* Check Rx priority queue interrupts */ +- for (index = 0; index < priv->hw_params->rx_queues; index++) { ++ for (index = 0; index <= priv->hw_params->rx_queues; index++) { + if (!(status & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index))) + continue; + +@@ -3166,20 +3047,20 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + rx_ring->dim.event_ctr++; + + if (likely(napi_schedule_prep(&rx_ring->napi))) { +- rx_ring->int_disable(rx_ring); ++ bcmgenet_rx_ring_int_disable(rx_ring); + __napi_schedule_irqoff(&rx_ring->napi); + } + } + + /* Check Tx priority queue interrupts */ +- for (index = 0; index < priv->hw_params->tx_queues; index++) { ++ for (index = 0; index <= priv->hw_params->tx_queues; index++) { + if (!(status & BIT(index))) + continue; + + tx_ring = &priv->tx_rings[index]; + + if (likely(napi_schedule_prep(&tx_ring->napi))) { +- tx_ring->int_disable(tx_ring); ++ bcmgenet_tx_ring_int_disable(tx_ring); + __napi_schedule_irqoff(&tx_ring->napi); + } + } +@@ -3187,12 +3068,10 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + return IRQ_HANDLED; + } + +-/* bcmgenet_isr0: handle Rx and Tx default queues + other stuff */ ++/* bcmgenet_isr0: handle other stuff */ + static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + { + struct bcmgenet_priv *priv = dev_id; +- struct bcmgenet_rx_ring *rx_ring; +- struct bcmgenet_tx_ring *tx_ring; + unsigned int status; + unsigned long flags; + +@@ -3206,25 +3085,6 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + netif_dbg(priv, intr, priv->dev, + "IRQ=0x%x\n", status); + +- if (status & UMAC_IRQ_RXDMA_DONE) { +- rx_ring = &priv->rx_rings[DESC_INDEX]; +- rx_ring->dim.event_ctr++; +- +- if (likely(napi_schedule_prep(&rx_ring->napi))) { +- rx_ring->int_disable(rx_ring); +- __napi_schedule_irqoff(&rx_ring->napi); +- } +- } +- +- if (status & UMAC_IRQ_TXDMA_DONE) { +- tx_ring = &priv->tx_rings[DESC_INDEX]; +- +- if (likely(napi_schedule_prep(&tx_ring->napi))) { +- tx_ring->int_disable(tx_ring); +- __napi_schedule_irqoff(&tx_ring->napi); +- } +- } +- + if (bcmgenet_has_mdio_intr(priv) && + status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + wake_up(&priv->wq); +@@ -3290,15 +3150,15 @@ static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv, bool flush_rx) + u32 dma_ctrl; + + /* disable DMA */ +- dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ dma_ctrl = DMA_EN; ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); + +- dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ dma_ctrl = DMA_EN; ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; +@@ -3381,6 +3241,9 @@ static int bcmgenet_open(struct net_device *dev) + + bcmgenet_set_hw_addr(priv, dev->dev_addr); + ++ /* HFB init */ ++ bcmgenet_hfb_init(priv); ++ + /* Disable RX/TX DMA and flush TX and RX queues */ + dma_ctrl = bcmgenet_dma_disable(priv, true); + +@@ -3391,12 +3254,8 @@ static int bcmgenet_open(struct net_device *dev) + goto err_clk_disable; + } + +- /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + +- /* HFB init */ +- bcmgenet_hfb_init(priv); +- + ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED, + dev->name, priv); + if (ret < 0) { +@@ -3503,16 +3362,11 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + if (!netif_msg_tx_err(priv)) + return; + +- txq = netdev_get_tx_queue(priv->dev, ring->queue); ++ txq = netdev_get_tx_queue(priv->dev, ring->index); + + spin_lock(&ring->lock); +- if (ring->index == DESC_INDEX) { +- intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); +- intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE; +- } else { +- intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); +- intmsk = 1 << ring->index; +- } ++ intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); ++ intmsk = 1 << ring->index; + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); + p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX); + txq_stopped = netif_tx_queue_stopped(txq); +@@ -3526,7 +3380,7 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + "(sw)c_index: %d (hw)c_index: %d\n" + "(sw)clean_p: %d (sw)write_p: %d\n" + "(sw)cb_ptr: %d (sw)end_ptr: %d\n", +- ring->index, ring->queue, ++ ring->index, ring->index, + txq_stopped ? "stopped" : "active", + intsts & intmsk ? "enabled" : "disabled", + free_bds, ring->size, +@@ -3539,25 +3393,20 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 int0_enable = 0; + u32 int1_enable = 0; + unsigned int q; + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + +- for (q = 0; q < priv->hw_params->tx_queues; q++) ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) + bcmgenet_dump_tx_queue(&priv->tx_rings[q]); +- bcmgenet_dump_tx_queue(&priv->tx_rings[DESC_INDEX]); + + bcmgenet_tx_reclaim_all(dev); + +- for (q = 0; q < priv->hw_params->tx_queues; q++) ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) + int1_enable |= (1 << q); + +- int0_enable = UMAC_IRQ_TXDMA_DONE; +- + /* Re-enable TX interrupts if disabled */ +- bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); + + netif_trans_update(dev); +@@ -3661,16 +3510,13 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) + struct bcmgenet_rx_ring *rx_ring; + unsigned int q; + +- for (q = 0; q < priv->hw_params->tx_queues; q++) { ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) { + tx_ring = &priv->tx_rings[q]; + tx_bytes += tx_ring->bytes; + tx_packets += tx_ring->packets; + } +- tx_ring = &priv->tx_rings[DESC_INDEX]; +- tx_bytes += tx_ring->bytes; +- tx_packets += tx_ring->packets; + +- for (q = 0; q < priv->hw_params->rx_queues; q++) { ++ for (q = 0; q <= priv->hw_params->rx_queues; q++) { + rx_ring = &priv->rx_rings[q]; + + rx_bytes += rx_ring->bytes; +@@ -3678,11 +3524,6 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) + rx_errors += rx_ring->errors; + rx_dropped += rx_ring->dropped; + } +- rx_ring = &priv->rx_rings[DESC_INDEX]; +- rx_bytes += rx_ring->bytes; +- rx_packets += rx_ring->packets; +- rx_errors += rx_ring->errors; +- rx_dropped += rx_ring->dropped; + + dev->stats.tx_bytes = tx_bytes; + dev->stats.tx_packets = tx_packets; +@@ -4129,16 +3970,13 @@ static int bcmgenet_probe(struct platform_device *pdev) + if (err) + goto err_clk_disable; + +- /* setup number of real queues + 1 (GENET_V1 has 0 hardware queues +- * just the ring 16 descriptor based TX +- */ ++ /* setup number of real queues + 1 */ + netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1); + netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); + + /* Set default coalescing parameters */ +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + priv->rx_rings[i].rx_max_coalesced_frames = 1; +- priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1; + + /* libphy will determine the link state */ + netif_carrier_off(dev); +@@ -4263,7 +4101,6 @@ static int bcmgenet_resume(struct device *d) + goto out_clk_disable; + } + +- /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + + if (!device_may_wakeup(d)) +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index ba83819210aa8..f3a1139cb7108 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -18,6 +18,9 @@ + + #include "../unimac.h" + ++/* Maximum number of hardware queues, downsized if needed */ ++#define GENET_MAX_MQ_CNT 4 ++ + /* total number of Buffer Descriptors, same for Rx/Tx */ + #define TOTAL_DESC 256 + +@@ -513,7 +516,6 @@ struct bcmgenet_tx_ring { + unsigned long packets; + unsigned long bytes; + unsigned int index; /* ring index */ +- unsigned int queue; /* queue index */ + struct enet_cb *cbs; /* tx ring buffer control block*/ + unsigned int size; /* size of each tx ring */ + unsigned int clean_ptr; /* Tx ring clean pointer */ +@@ -523,8 +525,6 @@ struct bcmgenet_tx_ring { + unsigned int prod_index; /* Tx ring producer index SW copy */ + unsigned int cb_ptr; /* Tx ring initial CB ptr */ + unsigned int end_ptr; /* Tx ring end CB ptr */ +- void (*int_enable)(struct bcmgenet_tx_ring *); +- void (*int_disable)(struct bcmgenet_tx_ring *); + struct bcmgenet_priv *priv; + }; + +@@ -553,8 +553,6 @@ struct bcmgenet_rx_ring { + struct bcmgenet_net_dim dim; + u32 rx_max_coalesced_frames; + u32 rx_coalesce_usecs; +- void (*int_enable)(struct bcmgenet_rx_ring *); +- void (*int_disable)(struct bcmgenet_rx_ring *); + struct bcmgenet_priv *priv; + }; + +@@ -583,7 +581,7 @@ struct bcmgenet_priv { + struct enet_cb *tx_cbs; + unsigned int num_tx_bds; + +- struct bcmgenet_tx_ring tx_rings[DESC_INDEX + 1]; ++ struct bcmgenet_tx_ring tx_rings[GENET_MAX_MQ_CNT + 1]; + + /* receive variables */ + void __iomem *rx_bds; +@@ -593,7 +591,7 @@ struct bcmgenet_priv { + struct bcmgenet_rxnfc_rule rxnfc_rules[MAX_NUM_OF_FS_RULES]; + struct list_head rxnfc_list; + +- struct bcmgenet_rx_ring rx_rings[DESC_INDEX + 1]; ++ struct bcmgenet_rx_ring rx_rings[GENET_MAX_MQ_CNT + 1]; + + /* other misc variables */ + struct bcmgenet_hw_params *hw_params; +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +index 3ab506ed94252..cd5a35309ca78 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +@@ -2,7 +2,7 @@ + /* + * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support + * +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #define pr_fmt(fmt) "bcmgenet_wol: " fmt +@@ -158,7 +158,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, + if (priv->wolopts & WAKE_FILTER) { + list_for_each_entry(rule, &priv->rxnfc_list, list) + if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE) +- hfb_enable |= (1 << rule->fs.location); ++ hfb_enable |= (1 << (rule->fs.location + 1)); + reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN; + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); + } +-- +2.53.0 + diff --git a/queue-6.1/net-bcmgenet-remove-custom-ndo_poll_controller.patch b/queue-6.1/net-bcmgenet-remove-custom-ndo_poll_controller.patch new file mode 100644 index 0000000000..30eb415ade --- /dev/null +++ b/queue-6.1/net-bcmgenet-remove-custom-ndo_poll_controller.patch @@ -0,0 +1,64 @@ +From 3470d8584ea2ecfc5093b0a5f3c25a19cd402ca1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Oct 2023 11:17:47 -0700 +Subject: net: bcmgenet: Remove custom ndo_poll_controller() + +From: Florian Fainelli + +[ Upstream commit 19537e125cc7cf2da43a606f5bcebbe0c9aea4cc ] + +The driver gained a .ndo_poll_controller() at a time where the TX +cleaning process was always done from NAPI which makes this unnecessary. +See commit ac3d9dd034e5 ("netpoll: make ndo_poll_controller() optional") +for more background. + +Signed-off-by: Florian Fainelli +Reviewed-by: Eric Dumazet +Signed-off-by: David S. Miller +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 20 ------------------- + 1 file changed, 20 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 1d679de9c3235..4d76c9aebd439 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -3250,23 +3250,6 @@ static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) + return IRQ_HANDLED; + } + +-#ifdef CONFIG_NET_POLL_CONTROLLER +-static void bcmgenet_poll_controller(struct net_device *dev) +-{ +- struct bcmgenet_priv *priv = netdev_priv(dev); +- +- /* Invoke the main RX/TX interrupt handler */ +- disable_irq(priv->irq0); +- bcmgenet_isr0(priv->irq0, priv); +- enable_irq(priv->irq0); +- +- /* And the interrupt handler for RX/TX priority queues */ +- disable_irq(priv->irq1); +- bcmgenet_isr1(priv->irq1, priv); +- enable_irq(priv->irq1); +-} +-#endif +- + static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) + { + u32 reg; +@@ -3736,9 +3719,6 @@ static const struct net_device_ops bcmgenet_netdev_ops = { + .ndo_set_mac_address = bcmgenet_set_mac_addr, + .ndo_eth_ioctl = phy_do_ioctl_running, + .ndo_set_features = bcmgenet_set_features, +-#ifdef CONFIG_NET_POLL_CONTROLLER +- .ndo_poll_controller = bcmgenet_poll_controller, +-#endif + .ndo_get_stats = bcmgenet_get_stats, + .ndo_change_carrier = bcmgenet_change_carrier, + }; +-- +2.53.0 + diff --git a/queue-6.1/net-bcmgenet-remove-tx-ring-full-logging.patch b/queue-6.1/net-bcmgenet-remove-tx-ring-full-logging.patch new file mode 100644 index 0000000000..d8d160935b --- /dev/null +++ b/queue-6.1/net-bcmgenet-remove-tx-ring-full-logging.patch @@ -0,0 +1,43 @@ +From 124a2c4fa573292386fd06a8ddb809cb0ea28794 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Jul 2023 11:39:45 -0700 +Subject: net: bcmgenet: Remove TX ring full logging + +From: Florian Fainelli + +[ Upstream commit df41fa677d9b4717c930afbe88b06f5cefdacb21 ] + +There is no need to spam the kernel log with such an indication, remove +this message. + +Signed-off-by: Florian Fainelli +Reviewed-by: Simon Horman +Link: https://lore.kernel.org/r/20230728183945.760531-1-florian.fainelli@broadcom.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 650f51471a0e1..1d679de9c3235 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -2072,12 +2072,8 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) + + spin_lock(&ring->lock); + if (ring->free_bds <= (nr_frags + 1)) { +- if (!netif_tx_queue_stopped(txq)) { ++ if (!netif_tx_queue_stopped(txq)) + netif_tx_stop_queue(txq); +- netdev_err(dev, +- "%s: tx ring %d full when queue %d awake\n", +- __func__, index, ring->queue); +- } + ret = NETDEV_TX_BUSY; + goto out; + } +-- +2.53.0 + diff --git a/queue-6.1/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch b/queue-6.1/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch new file mode 100644 index 0000000000..ae71e47825 --- /dev/null +++ b/queue-6.1/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch @@ -0,0 +1,92 @@ +From c82d7242ac28d9568ff2ad47998006607e534f49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:39 -0800 +Subject: net: bcmgenet: support reclaiming unsent Tx packets + +From: Doug Berger + +[ Upstream commit f1bacae8b655163dcbc3c54b9e714ef1a8986d7b ] + +When disabling the transmitter any outstanding packets can now +be reclaimed by bcmgenet_tx_reclaim_all() rather than by the +bcmgenet_fini_dma() function. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-12-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 37 +++++++++++++++---- + 1 file changed, 30 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 9f670bbecc726..032ba3a157e4b 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1880,12 +1880,39 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + } + + static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, +- struct bcmgenet_tx_ring *ring) ++ struct bcmgenet_tx_ring *ring, ++ bool all) + { +- unsigned int released; ++ struct bcmgenet_priv *priv = netdev_priv(dev); ++ struct device *kdev = &priv->pdev->dev; ++ unsigned int released, drop, wr_ptr; ++ struct enet_cb *cb_ptr; ++ struct sk_buff *skb; + + spin_lock_bh(&ring->lock); + released = __bcmgenet_tx_reclaim(dev, ring); ++ if (all) { ++ skb = NULL; ++ drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK; ++ released += drop; ++ ring->prod_index = ring->c_index & DMA_C_INDEX_MASK; ++ while (drop--) { ++ cb_ptr = bcmgenet_put_txcb(priv, ring); ++ skb = cb_ptr->skb; ++ bcmgenet_free_tx_cb(kdev, cb_ptr); ++ if (skb && cb_ptr == GENET_CB(skb)->first_cb) { ++ dev_consume_skb_any(skb); ++ skb = NULL; ++ } ++ } ++ if (skb) ++ dev_consume_skb_any(skb); ++ bcmgenet_tdma_ring_writel(priv, ring->index, ++ ring->prod_index, TDMA_PROD_INDEX); ++ wr_ptr = ring->write_ptr * WORDS_PER_BD(priv); ++ bcmgenet_tdma_ring_writel(priv, ring->index, wr_ptr, ++ TDMA_WRITE_PTR); ++ } + spin_unlock_bh(&ring->lock); + + return released; +@@ -1922,7 +1949,7 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev) + int i = 0; + + do { +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++]); ++ bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++], true); + } while (i <= priv->hw_params->tx_queues && netif_is_multiqueue(dev)); + } + +@@ -2919,10 +2946,6 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) + bcmgenet_fini_rx_napi(priv); + bcmgenet_fini_tx_napi(priv); + +- for (i = 0; i < priv->num_tx_bds; i++) +- dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, +- priv->tx_cbs + i)); +- + for (i = 0; i <= priv->hw_params->tx_queues; i++) { + txq = netdev_get_tx_queue(priv->dev, i); + netdev_tx_reset_queue(txq); +-- +2.53.0 + diff --git a/queue-6.1/net-bcmgenet-switch-to-use-64bit-statistics.patch b/queue-6.1/net-bcmgenet-switch-to-use-64bit-statistics.patch new file mode 100644 index 0000000000..77511c9ebf --- /dev/null +++ b/queue-6.1/net-bcmgenet-switch-to-use-64bit-statistics.patch @@ -0,0 +1,527 @@ +From 4d0412342232bfd6e8b03f88b027c4d3443b68d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 May 2025 12:32:55 +0100 +Subject: net: bcmgenet: switch to use 64bit statistics + +From: Zak Kemble + +[ Upstream commit 59aa6e3072aa7e51e9040e8c342d0c0825c5f48f ] + +Update the driver to use ndo_get_stats64, rtnl_link_stats64 and +u64_stats_t counters for statistics. + +Signed-off-by: Zak Kemble +Tested-by: Florian Fainelli +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250519113257.1031-2-zakkemble@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 246 ++++++++++++------ + .../net/ethernet/broadcom/genet/bcmgenet.h | 29 ++- + 2 files changed, 187 insertions(+), 88 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 032ba3a157e4b..12aa07fb81db3 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -968,12 +968,13 @@ static int bcmgenet_set_pauseparam(struct net_device *dev, + + /* standard ethtool support functions. */ + enum bcmgenet_stat_type { +- BCMGENET_STAT_NETDEV = -1, ++ BCMGENET_STAT_RTNL = -1, + BCMGENET_STAT_MIB_RX, + BCMGENET_STAT_MIB_TX, + BCMGENET_STAT_RUNT, + BCMGENET_STAT_MISC, + BCMGENET_STAT_SOFT, ++ BCMGENET_STAT_SOFT64, + }; + + struct bcmgenet_stats { +@@ -983,13 +984,15 @@ struct bcmgenet_stats { + enum bcmgenet_stat_type type; + /* reg offset from UMAC base for misc counters */ + u16 reg_offset; ++ /* sync for u64 stats counters */ ++ int syncp_offset; + }; + +-#define STAT_NETDEV(m) { \ ++#define STAT_RTNL(m) { \ + .stat_string = __stringify(m), \ +- .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \ +- .stat_offset = offsetof(struct net_device_stats, m), \ +- .type = BCMGENET_STAT_NETDEV, \ ++ .stat_sizeof = sizeof(((struct rtnl_link_stats64 *)0)->m), \ ++ .stat_offset = offsetof(struct rtnl_link_stats64, m), \ ++ .type = BCMGENET_STAT_RTNL, \ + } + + #define STAT_GENET_MIB(str, m, _type) { \ +@@ -999,6 +1002,14 @@ struct bcmgenet_stats { + .type = _type, \ + } + ++#define STAT_GENET_SOFT_MIB64(str, s, m) { \ ++ .stat_string = str, \ ++ .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->s.m), \ ++ .stat_offset = offsetof(struct bcmgenet_priv, s.m), \ ++ .type = BCMGENET_STAT_SOFT64, \ ++ .syncp_offset = offsetof(struct bcmgenet_priv, s.syncp), \ ++} ++ + #define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX) + #define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX) + #define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT) +@@ -1013,18 +1024,18 @@ struct bcmgenet_stats { + } + + #define STAT_GENET_Q(num) \ +- STAT_GENET_SOFT_MIB("txq" __stringify(num) "_packets", \ +- tx_rings[num].packets), \ +- STAT_GENET_SOFT_MIB("txq" __stringify(num) "_bytes", \ +- tx_rings[num].bytes), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_bytes", \ +- rx_rings[num].bytes), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_packets", \ +- rx_rings[num].packets), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_errors", \ +- rx_rings[num].errors), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_dropped", \ +- rx_rings[num].dropped) ++ STAT_GENET_SOFT_MIB64("txq" __stringify(num) "_packets", \ ++ tx_rings[num].stats64, packets), \ ++ STAT_GENET_SOFT_MIB64("txq" __stringify(num) "_bytes", \ ++ tx_rings[num].stats64, bytes), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_bytes", \ ++ rx_rings[num].stats64, bytes), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_packets", \ ++ rx_rings[num].stats64, packets), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_errors", \ ++ rx_rings[num].stats64, errors), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_dropped", \ ++ rx_rings[num].stats64, dropped) + + /* There is a 0xC gap between the end of RX and beginning of TX stats and then + * between the end of TX stats and the beginning of the RX RUNT +@@ -1036,15 +1047,15 @@ struct bcmgenet_stats { + */ + static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + /* general stats */ +- STAT_NETDEV(rx_packets), +- STAT_NETDEV(tx_packets), +- STAT_NETDEV(rx_bytes), +- STAT_NETDEV(tx_bytes), +- STAT_NETDEV(rx_errors), +- STAT_NETDEV(tx_errors), +- STAT_NETDEV(rx_dropped), +- STAT_NETDEV(tx_dropped), +- STAT_NETDEV(multicast), ++ STAT_RTNL(rx_packets), ++ STAT_RTNL(tx_packets), ++ STAT_RTNL(rx_bytes), ++ STAT_RTNL(tx_bytes), ++ STAT_RTNL(rx_errors), ++ STAT_RTNL(tx_errors), ++ STAT_RTNL(rx_dropped), ++ STAT_RTNL(tx_dropped), ++ STAT_RTNL(multicast), + /* UniMAC RSV counters */ + STAT_GENET_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64), + STAT_GENET_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127), +@@ -1132,6 +1143,20 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + + #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) + ++#define BCMGENET_STATS64_ADD(stats, m, v) \ ++ do { \ ++ u64_stats_update_begin(&stats->syncp); \ ++ u64_stats_add(&stats->m, v); \ ++ u64_stats_update_end(&stats->syncp); \ ++ } while (0) ++ ++#define BCMGENET_STATS64_INC(stats, m) \ ++ do { \ ++ u64_stats_update_begin(&stats->syncp); \ ++ u64_stats_inc(&stats->m); \ ++ u64_stats_update_end(&stats->syncp); \ ++ } while (0) ++ + static void bcmgenet_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) + { +@@ -1215,8 +1240,9 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) + + s = &bcmgenet_gstrings_stats[i]; + switch (s->type) { +- case BCMGENET_STAT_NETDEV: ++ case BCMGENET_STAT_RTNL: + case BCMGENET_STAT_SOFT: ++ case BCMGENET_STAT_SOFT64: + continue; + case BCMGENET_STAT_RUNT: + offset += BCMGENET_STAT_OFFSET; +@@ -1254,28 +1280,40 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev, + u64 *data) + { + struct bcmgenet_priv *priv = netdev_priv(dev); ++ struct rtnl_link_stats64 stats64; ++ struct u64_stats_sync *syncp; ++ unsigned int start; + int i; + + if (netif_running(dev)) + bcmgenet_update_mib_counters(priv); + +- dev->netdev_ops->ndo_get_stats(dev); ++ dev_get_stats(dev, &stats64); + + for (i = 0; i < BCMGENET_STATS_LEN; i++) { + const struct bcmgenet_stats *s; + char *p; + + s = &bcmgenet_gstrings_stats[i]; +- if (s->type == BCMGENET_STAT_NETDEV) +- p = (char *)&dev->stats; +- else +- p = (char *)priv; +- p += s->stat_offset; +- if (sizeof(unsigned long) != sizeof(u32) && +- s->stat_sizeof == sizeof(unsigned long)) +- data[i] = *(unsigned long *)p; +- else +- data[i] = *(u32 *)p; ++ p = (char *)priv; ++ ++ if (s->type == BCMGENET_STAT_SOFT64) { ++ syncp = (struct u64_stats_sync *)(p + s->syncp_offset); ++ do { ++ start = u64_stats_fetch_begin(syncp); ++ data[i] = u64_stats_read((u64_stats_t *)(p + s->stat_offset)); ++ } while (u64_stats_fetch_retry(syncp, start)); ++ } else { ++ if (s->type == BCMGENET_STAT_RTNL) ++ p = (char *)&stats64; ++ ++ p += s->stat_offset; ++ if (sizeof(unsigned long) != sizeof(u32) && ++ s->stat_sizeof == sizeof(unsigned long)) ++ data[i] = *(unsigned long *)p; ++ else ++ data[i] = *(u32 *)p; ++ } + } + } + +@@ -1830,6 +1868,7 @@ static struct sk_buff *bcmgenet_free_rx_cb(struct device *dev, + static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + struct bcmgenet_tx_ring *ring) + { ++ struct bcmgenet_tx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned int txbds_processed = 0; + unsigned int bytes_compl = 0; +@@ -1870,8 +1909,10 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + ring->free_bds += txbds_processed; + ring->c_index = c_index; + +- ring->packets += pkts_compl; +- ring->bytes += bytes_compl; ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_add(&stats->packets, pkts_compl); ++ u64_stats_add(&stats->bytes, bytes_compl); ++ u64_stats_update_end(&stats->syncp); + + netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->index), + pkts_compl, bytes_compl); +@@ -1957,8 +1998,10 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev) + * the transmit checksum offsets in the descriptors + */ + static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, +- struct sk_buff *skb) ++ struct sk_buff *skb, ++ struct bcmgenet_tx_ring *ring) + { ++ struct bcmgenet_tx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = netdev_priv(dev); + struct status_64 *status = NULL; + struct sk_buff *new_skb; +@@ -1975,7 +2018,7 @@ static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, + if (!new_skb) { + dev_kfree_skb_any(skb); + priv->mib.tx_realloc_tsb_failed++; +- dev->stats.tx_dropped++; ++ BCMGENET_STATS64_INC(stats, dropped); + return NULL; + } + dev_consume_skb_any(skb); +@@ -2063,7 +2106,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) + GENET_CB(skb)->bytes_sent = skb->len; + + /* add the Transmit Status Block */ +- skb = bcmgenet_add_tsb(dev, skb); ++ skb = bcmgenet_add_tsb(dev, skb, ring); + if (!skb) { + ret = NETDEV_TX_OK; + goto out; +@@ -2205,6 +2248,7 @@ static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv, + static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + unsigned int budget) + { ++ struct bcmgenet_rx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = ring->priv; + struct net_device *dev = priv->dev; + struct enet_cb *cb; +@@ -2227,7 +2271,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + DMA_P_INDEX_DISCARD_CNT_MASK; + if (discards > ring->old_discards) { + discards = discards - ring->old_discards; +- ring->errors += discards; ++ BCMGENET_STATS64_ADD(stats, errors, discards); + ring->old_discards += discards; + + /* Clear HW register when we reach 75% of maximum 0xFFFF */ +@@ -2253,7 +2297,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + skb = bcmgenet_rx_refill(priv, cb); + + if (unlikely(!skb)) { +- ring->dropped++; ++ BCMGENET_STATS64_INC(stats, dropped); + goto next; + } + +@@ -2280,8 +2324,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + + if (unlikely(len > RX_BUF_LENGTH)) { + netif_err(priv, rx_status, dev, "oversized packet\n"); +- dev->stats.rx_length_errors++; +- dev->stats.rx_errors++; ++ BCMGENET_STATS64_INC(stats, length_errors); + dev_kfree_skb_any(skb); + goto next; + } +@@ -2289,7 +2332,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { + netif_err(priv, rx_status, dev, + "dropping fragmented packet!\n"); +- ring->errors++; ++ BCMGENET_STATS64_INC(stats, errors); + dev_kfree_skb_any(skb); + goto next; + } +@@ -2302,15 +2345,22 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + DMA_RX_RXER))) { + netif_err(priv, rx_status, dev, "dma_flag=0x%x\n", + (unsigned int)dma_flag); ++ u64_stats_update_begin(&stats->syncp); + if (dma_flag & DMA_RX_CRC_ERROR) +- dev->stats.rx_crc_errors++; ++ u64_stats_inc(&stats->crc_errors); + if (dma_flag & DMA_RX_OV) +- dev->stats.rx_over_errors++; ++ u64_stats_inc(&stats->over_errors); + if (dma_flag & DMA_RX_NO) +- dev->stats.rx_frame_errors++; ++ u64_stats_inc(&stats->frame_errors); + if (dma_flag & DMA_RX_LG) +- dev->stats.rx_length_errors++; +- dev->stats.rx_errors++; ++ u64_stats_inc(&stats->length_errors); ++ if ((dma_flag & (DMA_RX_CRC_ERROR | ++ DMA_RX_OV | ++ DMA_RX_NO | ++ DMA_RX_LG | ++ DMA_RX_RXER)) == DMA_RX_RXER) ++ u64_stats_inc(&stats->errors); ++ u64_stats_update_end(&stats->syncp); + dev_kfree_skb_any(skb); + goto next; + } /* error packet */ +@@ -2330,10 +2380,13 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + + /*Finish setting up the received SKB and send it to the kernel*/ + skb->protocol = eth_type_trans(skb, priv->dev); +- ring->packets++; +- ring->bytes += len; ++ ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->packets); ++ u64_stats_add(&stats->bytes, len); + if (dma_flag & DMA_RX_MULT) +- dev->stats.multicast++; ++ u64_stats_inc(&stats->multicast); ++ u64_stats_update_end(&stats->syncp); + + /* Notify kernel */ + napi_gro_receive(&ring->napi, skb); +@@ -3434,7 +3487,7 @@ static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + + netif_trans_update(dev); + +- dev->stats.tx_errors++; ++ BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors); + + netif_tx_wake_all_queues(dev); + } +@@ -3523,39 +3576,68 @@ static int bcmgenet_set_mac_addr(struct net_device *dev, void *p) + return 0; + } + +-static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) ++static void bcmgenet_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- unsigned long tx_bytes = 0, tx_packets = 0; +- unsigned long rx_bytes = 0, rx_packets = 0; +- unsigned long rx_errors = 0, rx_dropped = 0; +- struct bcmgenet_tx_ring *tx_ring; +- struct bcmgenet_rx_ring *rx_ring; ++ struct bcmgenet_tx_stats64 *tx_stats; ++ struct bcmgenet_rx_stats64 *rx_stats; ++ u64 rx_length_errors, rx_over_errors; ++ u64 rx_crc_errors, rx_frame_errors; ++ u64 tx_errors, tx_dropped; ++ u64 rx_errors, rx_dropped; ++ u64 tx_bytes, tx_packets; ++ u64 rx_bytes, rx_packets; ++ unsigned int start; + unsigned int q; ++ u64 multicast; + + for (q = 0; q <= priv->hw_params->tx_queues; q++) { +- tx_ring = &priv->tx_rings[q]; +- tx_bytes += tx_ring->bytes; +- tx_packets += tx_ring->packets; ++ tx_stats = &priv->tx_rings[q].stats64; ++ do { ++ start = u64_stats_fetch_begin(&tx_stats->syncp); ++ tx_bytes = u64_stats_read(&tx_stats->bytes); ++ tx_packets = u64_stats_read(&tx_stats->packets); ++ tx_errors = u64_stats_read(&tx_stats->errors); ++ tx_dropped = u64_stats_read(&tx_stats->dropped); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); ++ ++ stats->tx_bytes += tx_bytes; ++ stats->tx_packets += tx_packets; ++ stats->tx_errors += tx_errors; ++ stats->tx_dropped += tx_dropped; + } + + for (q = 0; q <= priv->hw_params->rx_queues; q++) { +- rx_ring = &priv->rx_rings[q]; +- +- rx_bytes += rx_ring->bytes; +- rx_packets += rx_ring->packets; +- rx_errors += rx_ring->errors; +- rx_dropped += rx_ring->dropped; ++ rx_stats = &priv->rx_rings[q].stats64; ++ do { ++ start = u64_stats_fetch_begin(&rx_stats->syncp); ++ rx_bytes = u64_stats_read(&rx_stats->bytes); ++ rx_packets = u64_stats_read(&rx_stats->packets); ++ rx_errors = u64_stats_read(&rx_stats->errors); ++ rx_dropped = u64_stats_read(&rx_stats->dropped); ++ rx_length_errors = u64_stats_read(&rx_stats->length_errors); ++ rx_over_errors = u64_stats_read(&rx_stats->over_errors); ++ rx_crc_errors = u64_stats_read(&rx_stats->crc_errors); ++ rx_frame_errors = u64_stats_read(&rx_stats->frame_errors); ++ multicast = u64_stats_read(&rx_stats->multicast); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); ++ ++ rx_errors += rx_length_errors; ++ rx_errors += rx_crc_errors; ++ rx_errors += rx_frame_errors; ++ ++ stats->rx_bytes += rx_bytes; ++ stats->rx_packets += rx_packets; ++ stats->rx_errors += rx_errors; ++ stats->rx_dropped += rx_dropped; ++ stats->rx_missed_errors += rx_errors; ++ stats->rx_length_errors += rx_length_errors; ++ stats->rx_over_errors += rx_over_errors; ++ stats->rx_crc_errors += rx_crc_errors; ++ stats->rx_frame_errors += rx_frame_errors; ++ stats->multicast += multicast; + } +- +- dev->stats.tx_bytes = tx_bytes; +- dev->stats.tx_packets = tx_packets; +- dev->stats.rx_bytes = rx_bytes; +- dev->stats.rx_packets = rx_packets; +- dev->stats.rx_errors = rx_errors; +- dev->stats.rx_missed_errors = rx_errors; +- dev->stats.rx_dropped = rx_dropped; +- return &dev->stats; + } + + static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier) +@@ -3583,7 +3665,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = { + .ndo_set_mac_address = bcmgenet_set_mac_addr, + .ndo_eth_ioctl = phy_do_ioctl_running, + .ndo_set_features = bcmgenet_set_features, +- .ndo_get_stats = bcmgenet_get_stats, ++ .ndo_get_stats64 = bcmgenet_get_stats64, + .ndo_change_carrier = bcmgenet_change_carrier, + }; + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index f3a1139cb7108..94957dfa55b6f 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -155,6 +155,27 @@ struct bcmgenet_mib_counters { + u32 tx_realloc_tsb_failed; + }; + ++struct bcmgenet_tx_stats64 { ++ struct u64_stats_sync syncp; ++ u64_stats_t packets; ++ u64_stats_t bytes; ++ u64_stats_t errors; ++ u64_stats_t dropped; ++}; ++ ++struct bcmgenet_rx_stats64 { ++ struct u64_stats_sync syncp; ++ u64_stats_t bytes; ++ u64_stats_t packets; ++ u64_stats_t errors; ++ u64_stats_t dropped; ++ u64_stats_t multicast; ++ u64_stats_t length_errors; ++ u64_stats_t over_errors; ++ u64_stats_t crc_errors; ++ u64_stats_t frame_errors; ++}; ++ + #define UMAC_MIB_START 0x400 + + #define UMAC_MDIO_CMD 0x614 +@@ -513,8 +534,7 @@ struct bcmgenet_skb_cb { + struct bcmgenet_tx_ring { + spinlock_t lock; /* ring lock */ + struct napi_struct napi; /* NAPI per tx queue */ +- unsigned long packets; +- unsigned long bytes; ++ struct bcmgenet_tx_stats64 stats64; + unsigned int index; /* ring index */ + struct enet_cb *cbs; /* tx ring buffer control block*/ + unsigned int size; /* size of each tx ring */ +@@ -538,10 +558,7 @@ struct bcmgenet_net_dim { + + struct bcmgenet_rx_ring { + struct napi_struct napi; /* Rx NAPI struct */ +- unsigned long bytes; +- unsigned long packets; +- unsigned long errors; +- unsigned long dropped; ++ struct bcmgenet_rx_stats64 stats64; + unsigned int index; /* Rx ring index */ + struct enet_cb *cbs; /* Rx ring buffer control block */ + unsigned int size; /* Rx ring size */ +-- +2.53.0 + diff --git a/queue-6.1/net-bonding-add-broadcast_neighbor-option-for-802.3a.patch b/queue-6.1/net-bonding-add-broadcast_neighbor-option-for-802.3a.patch new file mode 100644 index 0000000000..5de1babcbe --- /dev/null +++ b/queue-6.1/net-bonding-add-broadcast_neighbor-option-for-802.3a.patch @@ -0,0 +1,342 @@ +From 59872585069dda37954a20985576fdc8bc7ae2dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Jun 2025 21:49:28 +0800 +Subject: net: bonding: add broadcast_neighbor option for 802.3ad + +From: Tonghao Zhang + +[ Upstream commit ce7a381697cb3958ffe0b45e5028ac69444e9288 ] + +Stacking technology is a type of technology used to expand ports on +Ethernet switches. It is widely used as a common access method in +large-scale Internet data center architectures. Years of practice +have proved that stacking technology has advantages and disadvantages +in high-reliability network architecture scenarios. For instance, +in stacking networking arch, conventional switch system upgrades +require multiple stacked devices to restart at the same time. +Therefore, it is inevitable that the business will be interrupted +for a while. It is for this reason that "no-stacking" in data centers +has become a trend. Additionally, when the stacking link connecting +the switches fails or is abnormal, the stack will split. Although it is +not common, it still happens in actual operation. The problem is that +after the split, it is equivalent to two switches with the same +configuration appearing in the network, causing network configuration +conflicts and ultimately interrupting the services carried by the +stacking system. + +To improve network stability, "non-stacking" solutions have been +increasingly adopted, particularly by public cloud providers and +tech companies like Alibaba, Tencent, and Didi. "non-stacking" is +a method of mimicing switch stacking that convinces a LACP peer, +bonding in this case, connected to a set of "non-stacked" switches +that all of its ports are connected to a single switch +(i.e., LACP aggregator), as if those switches were stacked. This +enables the LACP peer's ports to aggregate together, and requires +(a) special switch configuration, described in the linked article, +and (b) modifications to the bonding 802.3ad (LACP) mode to send +all ARP/ND packets across all ports of the active aggregator. + +Note that, with multiple aggregators, the current broadcast mode +logic will send only packets to the selected aggregator(s). + + +-----------+ +-----------+ + | switch1 | | switch2 | + +-----------+ +-----------+ + ^ ^ + | | + +-----------------+ + | bond4 lacp | + +-----------------+ + | | + | NIC1 | NIC2 + +-----------------+ + | server | + +-----------------+ + +- https://www.ruijie.com/fr-fr/support/tech-gallery/de-stack-data-center-network-architecture/ + +Cc: Jay Vosburgh +Cc: "David S. Miller" +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: Simon Horman +Cc: Jonathan Corbet +Cc: Andrew Lunn +Cc: Steven Rostedt +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Nikolay Aleksandrov +Signed-off-by: Tonghao Zhang +Signed-off-by: Zengbing Tu +Link: https://patch.msgid.link/84d0a044514157bb856a10b6d03a1028c4883561.1751031306.git.tonghao@bamaicloud.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + Documentation/networking/bonding.rst | 6 +++ + drivers/net/bonding/bond_main.c | 66 +++++++++++++++++++++++++--- + drivers/net/bonding/bond_options.c | 42 ++++++++++++++++++ + include/net/bond_options.h | 1 + + include/net/bonding.h | 3 ++ + 5 files changed, 112 insertions(+), 6 deletions(-) + +diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst +index 870b4e1343188..d0e6a0fc6fd85 100644 +--- a/Documentation/networking/bonding.rst ++++ b/Documentation/networking/bonding.rst +@@ -562,6 +562,12 @@ lacp_rate + + The default is slow. + ++broadcast_neighbor ++ ++ Option specifying whether to broadcast ARP/ND packets to all ++ active slaves. This option has no effect in modes other than ++ 802.3ad mode. The default is off (0). ++ + max_bonds + + Specifies the number of bonding devices to create for this +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 14e7439717a3d..97821c3c8b9a8 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -209,6 +209,8 @@ atomic_t netpoll_block_tx = ATOMIC_INIT(0); + + unsigned int bond_net_id __read_mostly; + ++DEFINE_STATIC_KEY_FALSE(bond_bcast_neigh_enabled); ++ + static const struct flow_dissector_key flow_keys_bonding_keys[] = { + { + .key_id = FLOW_DISSECTOR_KEY_CONTROL, +@@ -4334,6 +4336,9 @@ static int bond_open(struct net_device *bond_dev) + + bond_for_each_slave(bond, slave, iter) + dev_mc_add(slave->dev, lacpdu_mcast_addr); ++ ++ if (bond->params.broadcast_neighbor) ++ static_branch_inc(&bond_bcast_neigh_enabled); + } + + if (bond_mode_can_use_xmit_hash(bond)) +@@ -4357,6 +4362,10 @@ static int bond_close(struct net_device *bond_dev) + if (bond_is_lb(bond)) + bond_alb_deinitialize(bond); + ++ if (BOND_MODE(bond) == BOND_MODE_8023AD && ++ bond->params.broadcast_neighbor) ++ static_branch_dec(&bond_bcast_neigh_enabled); ++ + if (bond_uses_primary(bond)) { + rcu_read_lock(); + slave = rcu_dereference(bond->curr_active_slave); +@@ -5243,6 +5252,37 @@ static struct slave *bond_xdp_xmit_3ad_xor_slave_get(struct bonding *bond, + return slaves->arr[hash % count]; + } + ++static bool bond_should_broadcast_neighbor(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct bonding *bond = netdev_priv(dev); ++ struct { ++ struct ipv6hdr ip6; ++ struct icmp6hdr icmp6; ++ } *combined, _combined; ++ ++ if (!static_branch_unlikely(&bond_bcast_neigh_enabled)) ++ return false; ++ ++ if (!bond->params.broadcast_neighbor) ++ return false; ++ ++ if (skb->protocol == htons(ETH_P_ARP)) ++ return true; ++ ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ combined = skb_header_pointer(skb, skb_mac_header_len(skb), ++ sizeof(_combined), ++ &_combined); ++ if (combined && combined->ip6.nexthdr == NEXTHDR_ICMP && ++ (combined->icmp6.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION || ++ combined->icmp6.icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT)) ++ return true; ++ } ++ ++ return false; ++} ++ + /* Use this Xmit function for 3AD as well as XOR modes. The current + * usable slave array is formed in the control path. The xmit function + * just calculates hash and sends the packet out. +@@ -5262,17 +5302,27 @@ static netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb, + return bond_tx_drop(dev, skb); + } + +-/* in broadcast mode, we send everything to all usable interfaces. */ ++/* in broadcast mode, we send everything to all or usable slave interfaces. ++ * under rcu_read_lock when this function is called. ++ */ + static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, +- struct net_device *bond_dev) ++ struct net_device *bond_dev, ++ bool all_slaves) + { + struct bonding *bond = netdev_priv(bond_dev); +- struct slave *slave = NULL; +- struct list_head *iter; ++ struct bond_up_slave *slaves; + bool xmit_suc = false; + bool skb_used = false; ++ int slaves_count, i; + +- bond_for_each_slave_rcu(bond, slave, iter) { ++ if (all_slaves) ++ slaves = rcu_dereference(bond->all_slaves); ++ else ++ slaves = rcu_dereference(bond->usable_slaves); ++ ++ slaves_count = slaves ? READ_ONCE(slaves->count) : 0; ++ for (i = 0; i < slaves_count; i++) { ++ struct slave *slave = slaves->arr[i]; + struct sk_buff *skb2; + + if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)) +@@ -5510,10 +5560,13 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev + case BOND_MODE_ACTIVEBACKUP: + return bond_xmit_activebackup(skb, dev); + case BOND_MODE_8023AD: ++ if (bond_should_broadcast_neighbor(skb, dev)) ++ return bond_xmit_broadcast(skb, dev, false); ++ fallthrough; + case BOND_MODE_XOR: + return bond_3ad_xor_xmit(skb, dev); + case BOND_MODE_BROADCAST: +- return bond_xmit_broadcast(skb, dev); ++ return bond_xmit_broadcast(skb, dev, true); + case BOND_MODE_ALB: + return bond_alb_xmit(skb, dev); + case BOND_MODE_TLB: +@@ -6331,6 +6384,7 @@ static int bond_check_params(struct bond_params *params) + eth_zero_addr(params->ad_actor_system); + params->ad_user_port_key = ad_user_port_key; + params->coupled_control = 1; ++ params->broadcast_neighbor = 0; + if (packets_per_slave > 0) { + params->reciprocal_packets_per_slave = + reciprocal_value(packets_per_slave); +diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c +index 62b5d29e6db6c..1faf10667c03e 100644 +--- a/drivers/net/bonding/bond_options.c ++++ b/drivers/net/bonding/bond_options.c +@@ -87,6 +87,8 @@ static int bond_option_missed_max_set(struct bonding *bond, + const struct bond_opt_value *newval); + static int bond_option_coupled_control_set(struct bonding *bond, + const struct bond_opt_value *newval); ++static int bond_option_broadcast_neigh_set(struct bonding *bond, ++ const struct bond_opt_value *newval); + + static const struct bond_opt_value bond_mode_tbl[] = { + { "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT}, +@@ -240,6 +242,12 @@ static const struct bond_opt_value bond_coupled_control_tbl[] = { + { NULL, -1, 0}, + }; + ++static const struct bond_opt_value bond_broadcast_neigh_tbl[] = { ++ { "off", 0, BOND_VALFLAG_DEFAULT}, ++ { "on", 1, 0}, ++ { NULL, -1, 0} ++}; ++ + static const struct bond_option bond_opts[BOND_OPT_LAST] = { + [BOND_OPT_MODE] = { + .id = BOND_OPT_MODE, +@@ -513,6 +521,14 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { + .flags = BOND_OPTFLAG_IFDOWN, + .values = bond_coupled_control_tbl, + .set = bond_option_coupled_control_set, ++ }, ++ [BOND_OPT_BROADCAST_NEIGH] = { ++ .id = BOND_OPT_BROADCAST_NEIGH, ++ .name = "broadcast_neighbor", ++ .desc = "Broadcast neighbor packets to all active slaves", ++ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), ++ .values = bond_broadcast_neigh_tbl, ++ .set = bond_option_broadcast_neigh_set, + } + }; + +@@ -907,6 +923,13 @@ static int bond_option_mode_set(struct bonding *bond, + bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; + bond->params.mode = newval->value; + ++ /* When changing mode, the bond device is down, we may reduce ++ * the bond_bcast_neigh_enabled in bond_close() if broadcast_neighbor ++ * enabled in 8023ad mode. Therefore, only clear broadcast_neighbor ++ * to 0. ++ */ ++ bond->params.broadcast_neighbor = 0; ++ + if (bond->dev->reg_state == NETREG_REGISTERED) { + bool update = false; + +@@ -1857,3 +1880,22 @@ static int bond_option_coupled_control_set(struct bonding *bond, + bond->params.coupled_control = newval->value; + return 0; + } ++ ++static int bond_option_broadcast_neigh_set(struct bonding *bond, ++ const struct bond_opt_value *newval) ++{ ++ if (bond->params.broadcast_neighbor == newval->value) ++ return 0; ++ ++ bond->params.broadcast_neighbor = newval->value; ++ if (bond->dev->flags & IFF_UP) { ++ if (bond->params.broadcast_neighbor) ++ static_branch_inc(&bond_bcast_neigh_enabled); ++ else ++ static_branch_dec(&bond_bcast_neigh_enabled); ++ } ++ ++ netdev_dbg(bond->dev, "Setting broadcast_neighbor to %s (%llu)\n", ++ newval->string, newval->value); ++ return 0; ++} +diff --git a/include/net/bond_options.h b/include/net/bond_options.h +index 18687ccf06383..022b122a9fb61 100644 +--- a/include/net/bond_options.h ++++ b/include/net/bond_options.h +@@ -77,6 +77,7 @@ enum { + BOND_OPT_NS_TARGETS, + BOND_OPT_PRIO, + BOND_OPT_COUPLED_CONTROL, ++ BOND_OPT_BROADCAST_NEIGH, + BOND_OPT_LAST + }; + +diff --git a/include/net/bonding.h b/include/net/bonding.h +index 0a84a63d5e324..06a048d716b19 100644 +--- a/include/net/bonding.h ++++ b/include/net/bonding.h +@@ -119,6 +119,8 @@ static inline int is_netpoll_tx_blocked(struct net_device *dev) + #define is_netpoll_tx_blocked(dev) (0) + #endif + ++DECLARE_STATIC_KEY_FALSE(bond_bcast_neigh_enabled); ++ + struct bond_params { + int mode; + int xmit_policy; +@@ -153,6 +155,7 @@ struct bond_params { + struct in6_addr ns_targets[BOND_MAX_NS_TARGETS]; + #endif + int coupled_control; ++ int broadcast_neighbor; + + /* 2 bytes of padding : see ether_addr_equal_64bits() */ + u8 ad_actor_system[ETH_ALEN + 2]; +-- +2.53.0 + diff --git a/queue-6.1/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch b/queue-6.1/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch new file mode 100644 index 0000000000..4b70e1316f --- /dev/null +++ b/queue-6.1/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch @@ -0,0 +1,66 @@ +From 281fceef8d55aa0dac02a5a10c7bcc4bc85160aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 08:55:19 +0800 +Subject: net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master + +From: Jiayuan Chen + +[ Upstream commit 1921f91298d1388a0bb9db8f83800c998b649cb3 ] + +syzkaller reported a kernel panic in bond_rr_gen_slave_id() reached via +xdp_master_redirect(). Full decoded trace: + + https://syzkaller.appspot.com/bug?extid=80e046b8da2820b6ba73 + +bond_rr_gen_slave_id() dereferences bond->rr_tx_counter, a per-CPU +counter that bonding only allocates in bond_open() when the mode is +round-robin. If the bond device was never brought up, rr_tx_counter +stays NULL. + +The XDP redirect path can still reach that code on a bond that was +never opened: bpf_master_redirect_enabled_key is a global static key, +so as soon as any bond device has native XDP attached, the +XDP_TX -> xdp_master_redirect() interception is enabled for every +slave system-wide. The path xdp_master_redirect() -> +bond_xdp_get_xmit_slave() -> bond_xdp_xmit_roundrobin_slave_get() -> +bond_rr_gen_slave_id() then runs against a bond that has no +rr_tx_counter and crashes. + +Fix this in the generic xdp_master_redirect() by refusing to call into +the master's ->ndo_xdp_get_xmit_slave() when the master device is not +up. IFF_UP is only set after ->ndo_open() has successfully returned, +so this reliably excludes masters whose XDP state has not been fully +initialized. Drop the frame with XDP_ABORTED so the exception is +visible via trace_xdp_exception() rather than silently falling through. +This is not specific to bonding: any current or future master that +defers XDP state allocation to ->ndo_open() is protected. + +Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave device") +Reported-by: syzbot+80e046b8da2820b6ba73@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/698f84c6.a70a0220.2c38d7.00cc.GAE@google.com/T/ +Suggested-by: Daniel Borkmann +Acked-by: Daniel Borkmann +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260411005524.201200-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 271cb6881dbb1..aee85a0062ce6 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4268,6 +4268,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) + struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); + + master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); ++ if (unlikely(!(master->flags & IFF_UP))) ++ return XDP_ABORTED; + slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); + if (slave && slave != xdp->rxq->dev) { + /* The target device is different from the receiving device, so +-- +2.53.0 + diff --git a/queue-6.1/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch b/queue-6.1/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch new file mode 100644 index 0000000000..92712f0687 --- /dev/null +++ b/queue-6.1/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch @@ -0,0 +1,44 @@ +From 2b1fe974b8778566900a256c7ed16c5f3b9371ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:37:07 +0200 +Subject: net: dsa: realtek: rtl8365mb: fix mode mask calculation + +From: Mieczyslaw Nalewaj + +[ Upstream commit 0c078021d3861966614d5e594ee03587f0c9e74d ] + +The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting +the 4-bit mask (0xF) by only (_extint % 2) bits instead of +(_extint % 2) * 4. This caused the mask to overlap with the adjacent +nibble when configuring odd-numbered external interfaces, selecting +the wrong bits entirely. + +Align the shift calculation with the existing ...MODE_OFFSET macro. + +Fixes: 4af2950c50c8 ("net: dsa: realtek-smi: add rtl8365mb subdriver for RTL8365MB-VC") +Signed-off-by: Abdulkader Alrezej +Signed-off-by: Mieczyslaw Nalewaj +Reviewed-by: Luiz Angelo Daros de Luca +Link: https://patch.msgid.link/400a6387-a444-4576-af6d-26be5410bce3@yahoo.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/realtek/rtl8365mb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index c22e69ab0deb1..97673ccb7ac79 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -212,7 +212,7 @@ + (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ + 0x0) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \ +- (0xF << (((_extint) % 2))) ++ (0xF << (((_extint) % 2) * 4)) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \ + (((_extint) % 2) * 4) + +-- +2.53.0 + diff --git a/queue-6.1/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch b/queue-6.1/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch new file mode 100644 index 0000000000..1fc7aa98fb --- /dev/null +++ b/queue-6.1/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch @@ -0,0 +1,71 @@ +From b330a31d9f0e39c1886013282750a63c245d30df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:31:01 +0800 +Subject: net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf + +From: Mashiro Chen + +[ Upstream commit bf9a38803b2626b01cc769aaf13485d8650f576f ] + +sixpack_receive_buf() does not properly skip bytes with TTY error flags. +The while loop iterates through the flags buffer but never advances the +data pointer (cp), and passes the original count (including error bytes) +to sixpack_decode(). This causes sixpack_decode() to process bytes that +should have been skipped due to TTY errors. The TTY layer does not +guarantee that cp[i] holds a meaningful value when fp[i] is set, so +passing those positions to sixpack_decode() results in KMSAN reporting +an uninit-value read. + +Fix this by processing bytes one at a time, advancing cp on each +iteration, and only passing valid (non-error) bytes to sixpack_decode(). +This matches the pattern used by slip_receive_buf() and +mkiss_receive_buf() for the same purpose. + +Reported-by: syzbot+ecdb8c9878a81eb21e54@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ecdb8c9878a81eb21e54 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Mashiro Chen +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260407173101.107352-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index fe85cffa4f945..ac953fad5d8d9 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -397,7 +397,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, + const unsigned char *cp, const char *fp, int count) + { + struct sixpack *sp; +- size_t count1; + + if (!count) + return; +@@ -407,16 +406,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, + return; + + /* Read the characters out of the buffer */ +- count1 = count; +- while (count) { +- count--; ++ while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) + sp->dev->stats.rx_errors++; ++ cp++; + continue; + } ++ sixpack_decode(sp, cp, 1); ++ cp++; + } +- sixpack_decode(sp, cp, count1); + + tty_unthrottle(tty); + } +-- +2.53.0 + diff --git a/queue-6.1/net-mctp-i2c-check-length-before-marking-flow-active.patch b/queue-6.1/net-mctp-i2c-check-length-before-marking-flow-active.patch new file mode 100644 index 0000000000..34f4bf0bd7 --- /dev/null +++ b/queue-6.1/net-mctp-i2c-check-length-before-marking-flow-active.patch @@ -0,0 +1,90 @@ +From 80cc1609bc38e8bc728d47b2d395c05a3103eefb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:46:52 -0700 +Subject: net: mctp i2c: check length before marking flow active + +From: William A. Kennington III + +[ Upstream commit 4ca07b9239bd0478ae586632a2ed72be37ed8407 ] + +Currently, mctp_i2c_get_tx_flow_state() is called before the packet length +sanity check. This function marks a new flow as active in the MCTP core. + +If the sanity check fails, mctp_i2c_xmit() returns early without calling +mctp_i2c_lock_nest(). This results in a mismatched locking state: the +flow is active, but the I2C bus lock was never acquired for it. + +When the flow is later released, mctp_i2c_release_flow() will see the +active state and queue an unlock marker. The TX thread will then +decrement midev->i2c_lock_count from 0, causing it to underflow to -1. + +This underflow permanently breaks the driver's locking logic, allowing +future transmissions to occur without holding the I2C bus lock, leading +to bus collisions and potential hardware hangs. + +Move the mctp_i2c_get_tx_flow_state() call to after the length sanity +check to ensure we only transition the flow state if we are actually +going to proceed with the transmission and locking. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: William A. Kennington III +Acked-by: Jeremy Kerr +Link: https://patch.msgid.link/20260423074741.201460-1-william@wkennington.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 4 ++-- + net/sched/cls_flower.c | 4 +++- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index 2eeccc3b70eff..cf0947b64a123 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -461,8 +461,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + u8 *pecp; + int rc; + +- fs = mctp_i2c_get_tx_flow_state(midev, skb); +- + hdr = (void *)skb_mac_header(skb); + /* Sanity check that packet contents matches skb length, + * and can't exceed MCTP_I2C_BUFSZ +@@ -474,6 +472,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + return; + } + ++ fs = mctp_i2c_get_tx_flow_state(midev, skb); ++ + if (skb_tailroom(skb) >= 1) { + /* Linear case with space, we can just append the PEC */ + skb_put(skb, 1); +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index a40a9e84c75f4..fd8c2f0f3256e 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -537,6 +537,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); ++ struct fl_flow_mask *mask; + + *last = false; + +@@ -553,11 +554,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- *last = fl_mask_put(head, f->mask); ++ mask = f->mask; + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); ++ *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/net-netconsole-move-newline-trimming-to-function.patch b/queue-6.1/net-netconsole-move-newline-trimming-to-function.patch new file mode 100644 index 0000000000..60b36a0728 --- /dev/null +++ b/queue-6.1/net-netconsole-move-newline-trimming-to-function.patch @@ -0,0 +1,65 @@ +From 336fbb641da3bef6edc7857a1e45468d313a6800 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Feb 2024 15:27:34 -0800 +Subject: net: netconsole: move newline trimming to function + +From: Matthew Wood + +[ Upstream commit ae001dc67907618423fd15bbab2014308c00ad0b ] + +Move newline trimming logic from `dev_name_store()` to a new function +(trim_newline()) for shared use in netconsole.c + +Signed-off-by: Matthew Wood +Signed-off-by: David S. Miller +Stable-dep-of: 92ceb7bff62c ("netconsole: propagate device name truncation in dev_name_store()") +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 1e797f1ddc31c..f9bf2c9a3ae2a 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -240,6 +240,16 @@ static struct netconsole_target *to_target(struct config_item *item) + NULL; + } + ++/* Get rid of possible trailing newline, returning the new length */ ++static void trim_newline(char *s, size_t maxlen) ++{ ++ size_t len; ++ ++ len = strnlen(s, maxlen); ++ if (s[len - 1] == '\n') ++ s[len - 1] = '\0'; ++} ++ + /* + * Attribute operations for netconsole_target. + */ +@@ -404,7 +414,6 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + size_t count) + { + struct netconsole_target *nt = to_target(item); +- size_t len; + + mutex_lock(&dynamic_netconsole_mutex); + if (nt->enabled) { +@@ -415,11 +424,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + } + + strscpy(nt->np.dev_name, buf, IFNAMSIZ); +- +- /* Get rid of possible trailing newline from echo(1) */ +- len = strnlen(nt->np.dev_name, IFNAMSIZ); +- if (nt->np.dev_name[len - 1] == '\n') +- nt->np.dev_name[len - 1] = '\0'; ++ trim_newline(nt->np.dev_name, IFNAMSIZ); + + mutex_unlock(&dynamic_netconsole_mutex); + return strnlen(buf, count); +-- +2.53.0 + diff --git a/queue-6.1/net-phy-dp83869-fix-setting-clk_o_sel-field.patch b/queue-6.1/net-phy-dp83869-fix-setting-clk_o_sel-field.patch new file mode 100644 index 0000000000..f3c581f0c2 --- /dev/null +++ b/queue-6.1/net-phy-dp83869-fix-setting-clk_o_sel-field.patch @@ -0,0 +1,64 @@ +From 414b128992d56ad60f8217f84ef4d797bf2ad209 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 05:13:39 +0200 +Subject: net: phy: dp83869: fix setting CLK_O_SEL field. + +From: Heiko Schocher + +[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ] + +Table 7-121 in datasheet says we have to set register 0xc6 +to value 0x10 before CLK_O_SEL can be modified. No more infos +about this field found in datasheet. With this fix, setting +of CLK_O_SEL field in IO_MUX_CFG register worked through dts +property "ti,clk-output-sel" on a DP83869HMRGZR. + +Signed-off-by: Heiko Schocher +Reviewed-by: Simon Horman +Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") +Link: https://patch.msgid.link/20260425031339.3318-1-hs@nabladev.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83869.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c +index b924f98b23973..35202f2e1d3dc 100644 +--- a/drivers/net/phy/dp83869.c ++++ b/drivers/net/phy/dp83869.c +@@ -31,6 +31,7 @@ + #define DP83869_RGMIICTL 0x0032 + #define DP83869_STRAP_STS1 0x006e + #define DP83869_RGMIIDCTL 0x0086 ++#define DP83869_ANA_PLL_PROG_PI 0x00c6 + #define DP83869_RXFCFG 0x0134 + #define DP83869_RXFPMD1 0x0136 + #define DP83869_RXFPMD2 0x0137 +@@ -802,12 +803,22 @@ static int dp83869_config_init(struct phy_device *phydev) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ +- if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) ++ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { ++ /* ++ * Table 7-121 in datasheet says we have to set register 0xc6 ++ * to value 0x10 before CLK_O_SEL can be modified. ++ */ ++ ret = phy_write_mmd(phydev, DP83869_DEVADDR, ++ DP83869_ANA_PLL_PROG_PI, 0x10); ++ if (ret) ++ return ret; ++ + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); ++ } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, +-- +2.53.0 + diff --git a/queue-6.1/net-rds-optimize-rds_ib_laddr_check.patch b/queue-6.1/net-rds-optimize-rds_ib_laddr_check.patch new file mode 100644 index 0000000000..140b755265 --- /dev/null +++ b/queue-6.1/net-rds-optimize-rds_ib_laddr_check.patch @@ -0,0 +1,189 @@ +From d07b6686c8c8991f7689cef196d7c56433ba1c88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:19 -0700 +Subject: net/rds: Optimize rds_ib_laddr_check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 236f718ac885965fa886440b9898dfae185c9733 ] + +rds_ib_laddr_check() creates a CM_ID and attempts to bind the address +in question to it. This in order to qualify the allegedly local +address as a usable IB/RoCE address. + +In the field, ExaWatcher runs rds-ping to all ports in the fabric from +all local ports. This using all active ToS'es. In a full rack system, +we have 14 cell servers and eight db servers. Typically, 6 ToS'es are +used. This implies 528 rds-ping invocations per ExaWatcher's "RDSinfo" +interval. + +Adding to this, each rds-ping invocation creates eight sockets and +binds the local address to them: + +socket(AF_RDS, SOCK_SEQPACKET, 0) = 3 +bind(3, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 4 +bind(4, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 5 +bind(5, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 6 +bind(6, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 7 +bind(7, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 8 +bind(8, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 9 +bind(9, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 10 +bind(10, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 + +So, at every interval ExaWatcher executes rds-ping's, 4224 CM_IDs are +allocated, considering this full-rack system. After the a CM_ID has +been allocated, rdma_bind_addr() is called, with the port number being +zero. This implies that the CMA will attempt to search for an un-used +ephemeral port. Simplified, the algorithm is to start at a random +position in the available port space, and then if needed, iterate +until an un-used port is found. + +The book-keeping of used ports uses the idr system, which again uses +slab to allocate new struct idr_layer's. The size is 2092 bytes and +slab tries to reduce the wasted space. Hence, it chooses an order:3 +allocation, for which 15 idr_layer structs will fit and only 1388 +bytes are wasted per the 32KiB order:3 chunk. + +Although this order:3 allocation seems like a good space/speed +trade-off, it does not resonate well with how it used by the CMA. The +combination of the randomized starting point in the port space (which +has close to zero spatial locality) and the close proximity in time of +the 4224 invocations of the rds-ping's, creates a memory hog for +order:3 allocations. + +These costly allocations may need reclaims and/or compaction. At +worst, they may fail and produce a stack trace such as (from uek4): + +[] __inc_zone_page_state+0x35/0x40 +[] page_add_file_rmap+0x57/0x60 +[] remove_migration_pte+0x3f/0x3c0 [ksplice_6cn872bt_vmlinux_new] +[] rmap_walk+0xd8/0x340 +[] remove_migration_ptes+0x40/0x50 +[] migrate_pages+0x3ec/0x890 +[] compact_zone+0x32d/0x9a0 +[] compact_zone_order+0x6d/0x90 +[] try_to_compact_pages+0x102/0x270 +[] __alloc_pages_direct_compact+0x46/0x100 +[] __alloc_pages_nodemask+0x74b/0xaa0 +[] alloc_pages_current+0x91/0x110 +[] new_slab+0x38b/0x480 +[] __slab_alloc+0x3b7/0x4a0 [ksplice_s0dk66a8_vmlinux_new] +[] kmem_cache_alloc+0x1fb/0x250 +[] idr_layer_alloc+0x36/0x90 +[] idr_get_empty_slot+0x28c/0x3d0 +[] idr_alloc+0x4d/0xf0 +[] cma_alloc_port+0x4d/0xa0 [rdma_cm] +[] rdma_bind_addr+0x2ae/0x5b0 [rdma_cm] +[] rds_ib_laddr_check+0x83/0x2c0 [ksplice_6l2xst5i_rds_rdma_new] +[] rds_trans_get_preferred+0x5b/0xa0 [rds] +[] rds_bind+0x212/0x280 [rds] +[] SYSC_bind+0xe6/0x120 +[] SyS_bind+0xe/0x10 +[] system_call_fastpath+0x18/0xd4 + +To avoid these excessive calls to rdma_bind_addr(), we optimize +rds_ib_laddr_check() by simply checking if the address in question has +been used before. The rds_rdma module keeps track of addresses +associated with IB devices, and the function rds_ib_get_device() is +used to determine if the address already has been qualified as a valid +local address. If not found, we call the legacy rds_ib_laddr_check(), +now renamed to rds_ib_laddr_check_cm(). + +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Somasundaram Krishnasamy +Signed-off-by: Gerd Rausch +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-2-achender@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: ebf71dd4aff4 ("net/rds: Restrict use of RDS/IB to the initial network namespace") +Signed-off-by: Sasha Levin +--- + net/rds/ib.c | 20 ++++++++++++++++++-- + net/rds/ib.h | 1 + + net/rds/ib_rdma.c | 2 +- + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 9826fe7f9d008..996f007cd516b 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -403,8 +403,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len, + * allowed to influence which paths have priority. We could call userspace + * asserting this policy "routing". + */ +-static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, +- __u32 scope_id) ++static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) + { + int ret; + struct rdma_cm_id *cm_id; +@@ -489,6 +489,22 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + return ret; + } + ++static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) ++{ ++ struct rds_ib_device *rds_ibdev = NULL; ++ ++ if (ipv6_addr_v4mapped(addr)) { ++ rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); ++ if (rds_ibdev) { ++ rds_ib_dev_put(rds_ibdev); ++ return 0; ++ } ++ } ++ ++ return rds_ib_laddr_check_cm(net, addr, scope_id); ++} ++ + static void rds_ib_unregister_client(void) + { + ib_unregister_client(&rds_ib_client); +diff --git a/net/rds/ib.h b/net/rds/ib.h +index 2ba71102b1f1f..d6c1197731c1c 100644 +--- a/net/rds/ib.h ++++ b/net/rds/ib.h +@@ -384,6 +384,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, + __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) + + /* ib_rdma.c */ ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr); + int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, + struct in6_addr *ipaddr); + void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); +diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c +index 30fca2169aa7a..468fd60d818ff 100644 +--- a/net/rds/ib_rdma.c ++++ b/net/rds/ib_rdma.c +@@ -47,7 +47,7 @@ struct rds_ib_dereg_odp_mr { + + static void rds_ib_odp_mr_worker(struct work_struct *work); + +-static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) + { + struct rds_ib_device *rds_ibdev; + struct rds_ib_ipaddr *i_ipaddr; +-- +2.53.0 + diff --git a/queue-6.1/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch b/queue-6.1/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch new file mode 100644 index 0000000000..642dae39dd --- /dev/null +++ b/queue-6.1/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch @@ -0,0 +1,86 @@ +From b051e526ad069366684dbef789dd0635837020e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:20 -0700 +Subject: net/rds: Restrict use of RDS/IB to the initial network namespace + +From: Greg Jumper + +[ Upstream commit ebf71dd4aff46e8e421d455db3e231ba43d2fa8a ] + +Prevent using RDS/IB in network namespaces other than the initial one. +The existing RDS/IB code will not work properly in non-initial network +namespaces. + +Fixes: d5a8ac28a7ff ("RDS-TCP: Make RDS-TCP work correctly when it is set up in a netns other than init_net") +Reported-by: syzbot+da8e060735ae02c8f3d1@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=da8e060735ae02c8f3d1 +Signed-off-by: Greg Jumper +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-3-achender@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/af_rds.c | 10 ++++++++-- + net/rds/ib.c | 4 ++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c +index d107f7605db4f..752ae3fbc2e7a 100644 +--- a/net/rds/af_rds.c ++++ b/net/rds/af_rds.c +@@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen) + return ret; + } + +-static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) ++static int rds_set_transport(struct net *net, struct rds_sock *rs, ++ sockptr_t optval, int optlen) + { + int t_type; + +@@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) + if (t_type < 0 || t_type >= RDS_TRANS_COUNT) + return -EINVAL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + rs->rs_transport = rds_trans_get(t_type); + + return rs->rs_transport ? 0 : -ENOPROTOOPT; +@@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) + { + struct rds_sock *rs = rds_sk_to_rs(sock->sk); ++ struct net *net = sock_net(sock->sk); + int ret; + + if (level != SOL_RDS) { +@@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + break; + case SO_RDS_TRANSPORT: + lock_sock(sock->sk); +- ret = rds_set_transport(rs, optval, optlen); ++ ret = rds_set_transport(net, rs, optval, optlen); + release_sock(sock->sk); + break; + case SO_TIMESTAMP_OLD: +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 996f007cd516b..ce5be43c5fbac 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -494,6 +494,10 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + { + struct rds_ib_device *rds_ibdev = NULL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (!net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + if (ipv6_addr_v4mapped(addr)) { + rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); + if (rds_ibdev) { +-- +2.53.0 + diff --git a/queue-6.1/net-rds-zero-per-item-info-buffer-before-handing-it-.patch b/queue-6.1/net-rds-zero-per-item-info-buffer-before-handing-it-.patch new file mode 100644 index 0000000000..4bb26864e5 --- /dev/null +++ b/queue-6.1/net-rds-zero-per-item-info-buffer-before-handing-it-.patch @@ -0,0 +1,111 @@ +From 71828e14d13f16e6e70e0b74217463af8d96ebc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 10:10:47 -0400 +Subject: net/rds: zero per-item info buffer before handing it to visitors + +From: Michael Bommarito + +[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ] + +rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a +caller-allocated on-stack u64 buffer to a per-connection visitor and +then copy the full item_len bytes back to user space via +rds_info_copy() regardless of how much of the buffer the visitor +actually wrote. + +rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only +write a subset of their output struct when the underlying +rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl +and the two GIDs via explicit memsets). Several u32 fields +(max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, +cache_allocs) and the 2-byte alignment hole between sl and +cache_allocs remain as whatever stack contents preceded the visitor +call and are then memcpy_to_user()'d out to user space. + +struct rds_info_rdma_connection and struct rds6_info_rdma_connection +are the only rds_info_* structs in include/uapi/linux/rds.h that are +not marked __attribute__((packed)), so they have a real alignment +hole. The other info visitors (rds_conn_info_visitor, +rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of +their packed output struct today and are not known to be vulnerable, +but a future visitor that adds a conditional write-path would have +the same bug. + +Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y: +a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, +binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on +any netdev is sufficient), sendto()'s any peer on the same subnet +(fails cleanly but installs an rds_connection in the global hash in +RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, +RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 +bytes of stack garbage including kernel text/data pointers: + + 0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2 + 8..39 00 ... gids (memset-zeroed) + 40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr) + 48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max) + 56..59 01 00 08 00 rdma_mr_size (garbage) + 60..61 00 00 tos, sl + 62..63 00 00 alignment padding + 64..67 18 00 00 00 cache_allocs (garbage) + +Fix by zeroing the per-item buffer in both rds_for_each_conn_info() +and rds_walk_conn_path_info() before invoking the visitor. This +covers the IPv4/IPv6 IB visitors and hardens all current and future +visitors against the same class of bug. + +No functional change for visitors that fully populate their output. + +Changes in v2: +- retarget at the net tree (subject prefix "[PATCH net v2]", + net/rds: prefix in the title) +- pick up Reviewed-by tags from Sharath Srinivasan and + Allison Henderson + +Fixes: ec16227e1414 ("RDS/IB: Infiniband transport") +Signed-off-by: Michael Bommarito +Reviewed-by: Sharath Srinivasan +Reviewed-by: Allison Henderson +Assisted-by: Claude:claude-opus-4-7 +Link: https://patch.msgid.link/20260418141047.3398203-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/connection.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index 98c0d5ff9de9c..cd41f83863c89 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -673,6 +673,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, + i++, head++) { + hlist_for_each_entry_rcu(conn, head, c_hash_node) { + ++ /* Zero the per-item buffer before handing it to the ++ * visitor so any field the visitor does not write - ++ * including implicit alignment padding - cannot leak ++ * stack contents to user space via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no c_lock usage.. */ + if (!visitor(conn, buffer)) + continue; +@@ -722,6 +729,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, + */ + cp = conn->c_path; + ++ /* Zero the per-item buffer for the same reason as ++ * rds_for_each_conn_info(): any byte the visitor ++ * does not write (including alignment padding) must ++ * not leak stack contents via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no cp_lock usage.. */ + if (!visitor(cp, buffer)) + continue; +-- +2.53.0 + diff --git a/queue-6.1/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch b/queue-6.1/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch new file mode 100644 index 0000000000..a8687ead4b --- /dev/null +++ b/queue-6.1/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch @@ -0,0 +1,130 @@ +From 1c99b84e730d5d7850969a3bbef8cc540e32e38a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:16:27 -0400 +Subject: net/sched: act_ct: Only release RCU read lock after ct_ft + +From: Jamal Hadi Salim + +[ Upstream commit f462dca0c8415bf0058d0ffa476354c4476d0f09 ] + +When looking up a flow table in act_ct in tcf_ct_flow_table_get(), +rhashtable_lookup_fast() internally opens and closes an RCU read critical +section before returning ct_ft. +The tcf_ct_flow_table_cleanup_work() can complete before refcount_inc_not_zero() +is invoked on the returned ct_ft resulting in a UAF on the already freed ct_ft +object. This vulnerability can lead to privilege escalation. + +Analysis from zdi-disclosures@trendmicro.com: +When initializing act_ct, tcf_ct_init() is called, which internally triggers +tcf_ct_flow_table_get(). + +static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + +{ + struct zones_ht_key key = { .net = net, .zone = params->zone }; + struct tcf_ct_flow_table *ct_ft; + int err = -ENOMEM; + + mutex_lock(&zones_mutex); + ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); // [1] + if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) // [2] + goto out_unlock; + ... +} + +static __always_inline void *rhashtable_lookup_fast( + struct rhashtable *ht, const void *key, + const struct rhashtable_params params) +{ + void *obj; + + rcu_read_lock(); + obj = rhashtable_lookup(ht, key, params); + rcu_read_unlock(); + + return obj; +} + +At [1], rhashtable_lookup_fast() looks up and returns the corresponding ct_ft +from zones_ht . The lookup is performed within an RCU read critical section +through rcu_read_lock() / rcu_read_unlock(), which prevents the object from +being freed. However, at the point of function return, rcu_read_unlock() has +already been called, and there is nothing preventing ct_ft from being freed +before reaching refcount_inc_not_zero(&ct_ft->ref) at [2]. This interval becomes +the race window, during which ct_ft can be freed. + +Free Process: + +tcf_ct_flow_table_put() is executed through the path tcf_ct_cleanup() call_rcu() +tcf_ct_params_free_rcu() tcf_ct_params_free() tcf_ct_flow_table_put(). + +static void tcf_ct_flow_table_put(struct tcf_ct_flow_table *ct_ft) +{ + if (refcount_dec_and_test(&ct_ft->ref)) { + rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params); + INIT_RCU_WORK(&ct_ft->rwork, tcf_ct_flow_table_cleanup_work); // [3] + queue_rcu_work(act_ct_wq, &ct_ft->rwork); + } +} + +At [3], tcf_ct_flow_table_cleanup_work() is scheduled as RCU work + +static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) + +{ + struct tcf_ct_flow_table *ct_ft; + struct flow_block *block; + + ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, + rwork); + nf_flow_table_free(&ct_ft->nf_ft); + block = &ct_ft->nf_ft.flow_block; + down_write(&ct_ft->nf_ft.flow_block_lock); + WARN_ON(!list_empty(&block->cb_list)); + up_write(&ct_ft->nf_ft.flow_block_lock); + kfree(ct_ft); // [4] + + module_put(THIS_MODULE); +} + +tcf_ct_flow_table_cleanup_work() frees ct_ft at [4]. When this function executes +between [1] and [2], UAF occurs. + +This race condition has a very short race window, making it generally +difficult to trigger. Therefore, to trigger the vulnerability an msleep(100) was +inserted after[1] + +Fixes: 138470a9b2cc2 ("net/sched: act_ct: fix lockdep splat in tcf_ct_flow_table_get") +Reported-by: zdi-disclosures@trendmicro.com +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260410111627.46611-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/act_ct.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index 75a8fba9fa57a..651701a186fec 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -324,9 +324,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + int err = -ENOMEM; + + mutex_lock(&zones_mutex); +- ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); +- if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) ++ rcu_read_lock(); ++ ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params); ++ if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) { ++ rcu_read_unlock(); + goto out_unlock; ++ } ++ rcu_read_unlock(); + + ct_ft = kzalloc(sizeof(*ct_ft), GFP_KERNEL); + if (!ct_ft) +-- +2.53.0 + diff --git a/queue-6.1/net-sched-cls_flower-revert-unintended-changes.patch b/queue-6.1/net-sched-cls_flower-revert-unintended-changes.patch new file mode 100644 index 0000000000..533e7abaf1 --- /dev/null +++ b/queue-6.1/net-sched-cls_flower-revert-unintended-changes.patch @@ -0,0 +1,55 @@ +From e4eadff3e338e5317b44b247ac0a9542d622c2ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:39:11 +0200 +Subject: net/sched: cls_flower: revert unintended changes + +From: Paolo Abeni + +[ Upstream commit 1e01abec856593e02cd69fd95b784c10dd46880c ] + +While applying the blamed commit 4ca07b9239bd ("net: mctp i2c: check +length before marking flow active"), I unintentionally included +unrelated and unacceptable changes. + +Revert them. + +Fixes: 4ca07b9239bd ("net: mctp i2c: check length before marking flow active") +Reported-by: Jeremy Kerr +Closes: https://lore.kernel.org/netdev/bd8704fe0bd53e278add5cde4873256656623e2e.camel@codeconstruct.com.au/ +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/043026a53ff84da88b17648c4b0d17f0331749cb.1777447863.git.pabeni@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/cls_flower.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index fd8c2f0f3256e..a40a9e84c75f4 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -537,7 +537,6 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); +- struct fl_flow_mask *mask; + + *last = false; + +@@ -554,12 +553,11 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- mask = f->mask; ++ *last = fl_mask_put(head, f->mask); + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); +- *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch b/queue-6.1/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch new file mode 100644 index 0000000000..314097d1c8 --- /dev/null +++ b/queue-6.1/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch @@ -0,0 +1,67 @@ +From 0a6ad5e532b857908c73167d9f0743510ed018b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:39 -0700 +Subject: net/sched: netem: fix probability gaps in 4-state loss model + +From: Stephen Hemminger + +[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ] + +The 4-state Markov chain in loss_4state() has gaps at the boundaries +between transition probability ranges. The comparisons use: + + if (rnd < a4) + else if (a4 < rnd && rnd < a1 + a4) + +When rnd equals a boundary value exactly, neither branch matches and +no state transition occurs. The redundant lower-bound check (a4 < rnd) +is already implied by being in the else branch. + +Remove the unnecessary lower-bound comparisons so the ranges are +contiguous and every random value produces a transition, matching +the GI (General and Intuitive) loss model specification. + +This bug goes back to original implementation of this model. + +Fixes: 661b79725fea ("netem: revised correlated loss generator") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-2-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 2613353defde7..ab7074c357210 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -219,10 +219,10 @@ static bool loss_4state(struct netem_sched_data *q) + if (rnd < clg->a4) { + clg->state = LOST_IN_GAP_PERIOD; + return true; +- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { ++ } else if (rnd < clg->a1 + clg->a4) { + clg->state = LOST_IN_BURST_PERIOD; + return true; +- } else if (clg->a1 + clg->a4 < rnd) { ++ } else { + clg->state = TX_IN_GAP_PERIOD; + } + +@@ -239,9 +239,9 @@ static bool loss_4state(struct netem_sched_data *q) + case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; +- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { ++ else if (rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; +- } else if (clg->a2 + clg->a3 < rnd) { ++ } else { + clg->state = LOST_IN_BURST_PERIOD; + return true; + } +-- +2.53.0 + diff --git a/queue-6.1/net-sched-netem-fix-queue-limit-check-to-include-reo.patch b/queue-6.1/net-sched-netem-fix-queue-limit-check-to-include-reo.patch new file mode 100644 index 0000000000..a68aa8c582 --- /dev/null +++ b/queue-6.1/net-sched-netem-fix-queue-limit-check-to-include-reo.patch @@ -0,0 +1,42 @@ +From daa60c37f70ffdc8839ed12d2ad6acb6ec42577a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:40 -0700 +Subject: net/sched: netem: fix queue limit check to include reordered packets + +From: Stephen Hemminger + +[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ] + +The queue limit check in netem_enqueue() uses q->t_len which only +counts packets in the internal tfifo. Packets placed in sch->q by +the reorder path (__qdisc_enqueue_head) are not counted, allowing +the total queue occupancy to exceed sch->limit under reordering. + +Include sch->q.qlen in the limit check. + +Fixes: f8d4bc455047 ("net/sched: netem: account for backlog updates from child qdisc") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-3-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index ab7074c357210..288df378321d9 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -512,7 +512,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + 1<t_len >= sch->limit)) { ++ if (unlikely(sch->q.qlen >= sch->limit)) { + /* re-link segs, so that qdisc_drop_all() frees them all */ + skb->next = segs; + qdisc_drop_all(skb, sch, to_free); +-- +2.53.0 + diff --git a/queue-6.1/net-sched-netem-fix-slot-delay-calculation-overflow.patch b/queue-6.1/net-sched-netem-fix-slot-delay-calculation-overflow.patch new file mode 100644 index 0000000000..3516bdbf8d --- /dev/null +++ b/queue-6.1/net-sched-netem-fix-slot-delay-calculation-overflow.patch @@ -0,0 +1,51 @@ +From 4c0aba42b15f725161ff5433be4188b3daaf8e76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:43 -0700 +Subject: net/sched: netem: fix slot delay calculation overflow + +From: Stephen Hemminger + +[ Upstream commit 51e94e1e2fef351c74d69eb53666df808d26af95 ] + +get_slot_next() computes a random delay between min_delay and +max_delay using: + + get_random_u32() * (max_delay - min_delay) >> 32 + +This overflows signed 64-bit arithmetic when the delay range exceeds +approximately 2.1 seconds (2^31 nanoseconds), producing a negative +result that effectively disables slot-based pacing. This is a +realistic configuration for WAN emulation (e.g., slot 1s 5s). + +Use mul_u64_u32_shr() which handles the widening multiply without +overflow. + +Fixes: 0a9fe5c375b5 ("netem: slotting with non-uniform distribution") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-6-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index adb2bab79c87c..2c47bd8dba647 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -647,9 +647,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now) + + if (!q->slot_dist) + next_delay = q->slot_config.min_delay + +- (get_random_u32() * +- (q->slot_config.max_delay - +- q->slot_config.min_delay) >> 32); ++ mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay, ++ get_random_u32(), 32); + else + next_delay = tabledist(q->slot_config.dist_delay, + (s32)(q->slot_config.dist_jitter), +-- +2.53.0 + diff --git a/queue-6.1/net-sched-netem-validate-slot-configuration.patch b/queue-6.1/net-sched-netem-validate-slot-configuration.patch new file mode 100644 index 0000000000..3e364b377b --- /dev/null +++ b/queue-6.1/net-sched-netem-validate-slot-configuration.patch @@ -0,0 +1,86 @@ +From a825cb893629044d2c44523baf9e5ad2999c0f70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:42 -0700 +Subject: net/sched: netem: validate slot configuration + +From: Stephen Hemminger + +[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ] + +Reject slot configurations that have no defensible meaning: + + - negative min_delay or max_delay + - min_delay greater than max_delay + - negative dist_delay or dist_jitter + - negative max_packets or max_bytes + +Negative or out-of-order delays underflow in get_slot_next(), +producing garbage intervals. Negative limits trip the per-slot +accounting (packets_left/bytes_left <= 0) on the first packet of +every slot, defeating the rate-limiting half of the slot feature. + +Note that dist_jitter has been silently coerced to its absolute +value by get_slot() since the feature was introduced; rejecting +negatives here converts that silent coercion into -EINVAL. The +abs() can be removed in a follow-up. + +Fixes: 836af83b54e3 ("netem: support delivering packets in delayed time slots") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 288df378321d9..adb2bab79c87c 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -815,6 +815,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) ++{ ++ const struct tc_netem_slot *c = nla_data(attr); ++ ++ if (c->min_delay < 0 || c->max_delay < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); ++ return -EINVAL; ++ } ++ if (c->min_delay > c->max_delay) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); ++ return -EINVAL; ++ } ++ if (c->dist_delay < 0 || c->dist_jitter < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); ++ return -EINVAL; ++ } ++ if (c->max_packets < 0 || c->max_bytes < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1027,6 +1050,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_SLOT]) { ++ ret = validate_slot(tb[TCA_NETEM_SLOT], extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch b/queue-6.1/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch new file mode 100644 index 0000000000..3413635c3f --- /dev/null +++ b/queue-6.1/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch @@ -0,0 +1,62 @@ +From 2746acf6fff7fb5b52f416fbea4f373e0bbde6f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:06 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (V) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations +for cparams.target and cparams.interval. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 204cc04d4c6e8..c6c03f758d0d7 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -2313,10 +2313,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + + byte_target_ns = (byte_target * rate_ns) >> rate_shft; + +- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); +- b->cparams.interval = max(rtt_est_ns + +- b->cparams.target - target_ns, +- b->cparams.target * 2); ++ WRITE_ONCE(b->cparams.target, ++ max((byte_target_ns * 3) / 2, target_ns)); ++ WRITE_ONCE(b->cparams.interval, ++ max(rtt_est_ns + b->cparams.target - target_ns, ++ b->cparams.target * 2)); + b->cparams.mtu_time = byte_target_ns; + b->cparams.p_inc = 1 << 24; /* 1/256 */ + b->cparams.p_dec = 1 << 20; /* 1/4096 */ +@@ -2930,9 +2931,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); + + PUT_TSTAT_U32(TARGET_US, +- ktime_to_us(ns_to_ktime(b->cparams.target))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); + PUT_TSTAT_U32(INTERVAL_US, +- ktime_to_us(ns_to_ktime(b->cparams.interval))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); + + PUT_TSTAT_U32(SENT_PACKETS, b->packets); + PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch b/queue-6.1/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch new file mode 100644 index 0000000000..faf25dd01d --- /dev/null +++ b/queue-6.1/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch @@ -0,0 +1,64 @@ +From 098839ce1732473b3080a8e536282677bf1b4505 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:00:41 +0800 +Subject: net/sched: sch_cake: fix NAT destination port not being updated in + cake_update_flowkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit f9e40664706927d7ae22a448a3383e23c38a4c0b ] + +cake_update_flowkeys() is supposed to update the flow dissector keys +with the NAT-translated addresses and ports from conntrack, so that +CAKE's per-flow fairness correctly identifies post-NAT flows as +belonging to the same connection. + +For the source port, this works correctly: + keys->ports.src = port; + +But for the destination port, the assignment is reversed: + port = keys->ports.dst; + +This means the NAT destination port is never updated in the flow keys. +As a result, when multiple connections are NATed to the same destination, +CAKE treats them as separate flows because the original (pre-NAT) +destination ports differ. This breaks CAKE's NAT-aware flow isolation +when using the "nat" mode. + +The bug was introduced in commit b0c19ed6088a ("sch_cake: Take advantage +of skb->hash where appropriate") which refactored the original direct +assignment into a compare-and-conditionally-update pattern, but wrote +the destination port update backwards. + +Fix by reversing the assignment direction to match the source port +pattern. + +Fixes: b0c19ed6088a ("sch_cake: Take advantage of skb->hash where appropriate") +Signed-off-by: Dudu Lu +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260413110041.44704-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index e4fd66a1c5cd4..204cc04d4c6e8 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -619,7 +619,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys, + } + port = rev ? tuple.src.u.all : tuple.dst.u.all; + if (port != keys->ports.dst) { +- port = keys->ports.dst; ++ keys->ports.dst = port; + upd = true; + } + } +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch b/queue-6.1/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch new file mode 100644 index 0000000000..104837044b --- /dev/null +++ b/queue-6.1/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch @@ -0,0 +1,97 @@ +From 78e722fff09bb4878f0e9f69282688420d1cce93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:28:39 +0000 +Subject: net/sched: sch_choke: annotate data-races in choke_dump_stats() + +From: Eric Dumazet + +[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ] + +choke_dump_stats() only runs with RTNL held. +It reads fields that can be changed in qdisc fast path. +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423062839.2524324-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index e38cf34287018..7283f96dead62 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + /* Draw a packet at random from queue and compare flow */ + if (choke_match_random(q, skb, &idx)) { +- q->stats.matched++; ++ WRITE_ONCE(q->stats.matched, q->stats.matched + 1); + choke_drop_by_idx(sch, idx, to_free); + goto congestion_drop; + } +@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + qdisc_qstats_overlimit(sch); + if (use_harddrop(q) || !use_ecn(q) || + !INET_ECN_set_ce(skb)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + } else if (++q->vars.qcount) { + if (red_mark_probability(p, &q->vars, q->vars.qavg)) { + q->vars.qcount = 0; +@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + qdisc_qstats_overlimit(sch); + if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + } + } else + q->vars.qR = red_random(p); +@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + } + +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); + return qdisc_drop(skb, sch, to_free); + + congestion_drop: +@@ -460,10 +464,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct choke_sched_data *q = qdisc_priv(sch); + struct tc_choke_xstats st = { +- .early = q->stats.prob_drop + q->stats.forced_drop, +- .marked = q->stats.prob_mark + q->stats.forced_mark, +- .pdrop = q->stats.pdrop, +- .matched = q->stats.matched, ++ .early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop), ++ .marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark), ++ .pdrop = READ_ONCE(q->stats.pdrop), ++ .matched = READ_ONCE(q->stats.matched), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch b/queue-6.1/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch new file mode 100644 index 0000000000..c41330723c --- /dev/null +++ b/queue-6.1/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch @@ -0,0 +1,47 @@ +From b7fc8889349624f61b757ac7a85a56f44962b2b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:25:09 +0000 +Subject: net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats() + +From: Eric Dumazet + +[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill st.qdisc_stats with live data. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142509.3967231-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_codel.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 47b5a056165cb..056895df17854 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -568,6 +568,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + }; + struct list_head *pos; + ++ sch_tree_lock(sch); ++ + st.qdisc_stats.maxpacket = q->cstats.maxpacket; + st.qdisc_stats.drop_overlimit = q->drop_overlimit; + st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; +@@ -576,7 +578,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + st.qdisc_stats.memory_usage = q->memory_usage; + st.qdisc_stats.drop_overmemory = q->drop_overmemory; + +- sch_tree_lock(sch); + list_for_each(pos, &q->new_flows) + st.qdisc_stats.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch b/queue-6.1/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch new file mode 100644 index 0000000000..abe3420bad --- /dev/null +++ b/queue-6.1/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch @@ -0,0 +1,62 @@ +From a9812aca1373612097e44534c0d732334866ea11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:35:27 +0000 +Subject: net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill tc_fq_pie_xstats with live data. + +Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, +but the spinlock is needed anyway to scan q->new_flows and q->old_flows. + +Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423063527.2568262-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_pie.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index 607c580d75e4b..4bd5ca9acc53f 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -498,18 +498,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb) + static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct fq_pie_sched_data *q = qdisc_priv(sch); +- struct tc_fq_pie_xstats st = { +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .overmemory = q->overmemory, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, +- .new_flow_count = q->new_flow_count, +- .memory_usage = q->memory_usage, +- }; ++ struct tc_fq_pie_xstats st = { 0 }; + struct list_head *pos; + + sch_tree_lock(sch); ++ ++ st.packets_in = q->stats.packets_in; ++ st.overlimit = q->stats.overlimit; ++ st.overmemory = q->overmemory; ++ st.dropped = q->stats.dropped; ++ st.ecn_mark = q->stats.ecn_mark; ++ st.new_flow_count = q->new_flow_count; ++ st.memory_usage = q->memory_usage; ++ + list_for_each(pos, &q->new_flows) + st.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch b/queue-6.1/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch new file mode 100644 index 0000000000..bd831d7eb9 --- /dev/null +++ b/queue-6.1/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch @@ -0,0 +1,160 @@ +From 961323676e35a77d6a412d9900d35f8d09f458f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:29:44 +0000 +Subject: net/sched: sch_pie: annotate data-races in pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ] + +pie_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_pie_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142944.4009941-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/pie.h | 2 +- + net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/include/net/pie.h b/include/net/pie.h +index 3fe2361e03b46..f6fd51e2b7daa 100644 +--- a/include/net/pie.h ++++ b/include/net/pie.h +@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) + vars->dq_tstamp = DTIME_INVALID; + vars->accu_prob = 0; + vars->dq_count = DQCOUNT_INVALID; +- vars->avg_dq_rate = 0; ++ WRITE_ONCE(vars->avg_dq_rate, 0); + } + + static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb) +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index e1bb151a97195..afa94f058f5f5 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -89,7 +89,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + bool enqueue = false; + + if (unlikely(qdisc_qlen(sch) >= sch->limit)) { +- q->stats.overlimit++; ++ WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1); + goto out; + } + +@@ -101,7 +101,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + /* If packet is ecn capable, mark it if drop probability + * is lower than 10%, else drop it. + */ +- q->stats.ecn_mark++; ++ WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1); + enqueue = true; + } + +@@ -111,15 +111,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + if (!q->params.dq_rate_estimator) + pie_set_enqueue_time(skb); + +- q->stats.packets_in++; ++ WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1); + if (qdisc_qlen(sch) > q->stats.maxq) +- q->stats.maxq = qdisc_qlen(sch); ++ WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch)); + + return qdisc_enqueue_tail(skb, sch); + } + + out: +- q->stats.dropped++; ++ WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1); + q->vars.accu_prob = 0; + return qdisc_drop(skb, sch, to_free); + } +@@ -260,11 +260,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, + count = count / dtime; + + if (vars->avg_dq_rate == 0) +- vars->avg_dq_rate = count; ++ WRITE_ONCE(vars->avg_dq_rate, count); + else +- vars->avg_dq_rate = ++ WRITE_ONCE(vars->avg_dq_rate, + (vars->avg_dq_rate - +- (vars->avg_dq_rate >> 3)) + (count >> 3); ++ (vars->avg_dq_rate >> 3)) + (count >> 3)); + + /* If the queue has receded below the threshold, we hold + * on to the last drain rate calculated, else we reset +@@ -374,7 +374,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + if (delta > 0) { + /* prevent overflow */ + if (vars->prob < oldprob) { +- vars->prob = MAX_PROB; ++ WRITE_ONCE(vars->prob, MAX_PROB); + /* Prevent normalization error. If probability is at + * maximum value already, we normalize it here, and + * skip the check to do a non-linear drop in the next +@@ -385,7 +385,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + } else { + /* prevent underflow */ + if (vars->prob > oldprob) +- vars->prob = 0; ++ WRITE_ONCE(vars->prob, 0); + } + + /* Non-linear drop in probability: Reduce drop probability quickly if +@@ -396,7 +396,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + /* Reduce drop probability to 98.4% */ + vars->prob -= vars->prob / 64; + +- vars->qdelay = qdelay; ++ WRITE_ONCE(vars->qdelay, qdelay); + vars->backlog_old = backlog; + + /* We restart the measurement cycle if the following conditions are met +@@ -494,21 +494,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + struct pie_sched_data *q = qdisc_priv(sch); + struct tc_pie_xstats st = { + .prob = q->vars.prob << BITS_PER_BYTE, +- .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / ++ .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) / + NSEC_PER_USEC, +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .maxq = q->stats.maxq, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, ++ .packets_in = READ_ONCE(q->stats.packets_in), ++ .overlimit = READ_ONCE(q->stats.overlimit), ++ .maxq = READ_ONCE(q->stats.maxq), ++ .dropped = READ_ONCE(q->stats.dropped), ++ .ecn_mark = READ_ONCE(q->stats.ecn_mark), + }; + + /* avg_dq_rate is only valid if dq_rate_estimator is enabled */ + st.dq_rate_estimating = q->params.dq_rate_estimator; + + /* unscale and return dq_rate in bytes per sec */ +- if (q->params.dq_rate_estimator) +- st.avg_dq_rate = q->vars.avg_dq_rate * ++ if (st.dq_rate_estimating) ++ st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) * + (PSCHED_TICKS_PER_SEC) >> PIE_SCALE; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch b/queue-6.1/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch new file mode 100644 index 0000000000..9246823d76 --- /dev/null +++ b/queue-6.1/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch @@ -0,0 +1,112 @@ +From c1d713e70736f28180291c91e285c2e9375903d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:23:09 +0000 +Subject: net/sched: sch_red: annotate data-races in red_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ] + +red_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_red_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142309.3964322-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_red.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index ea3580d1d19e8..5348b61053068 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -89,17 +89,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_PROB_MARK: + qdisc_qstats_overlimit(sch); + if (!red_use_ecn(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +@@ -109,17 +112,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_HARD_MARK: + qdisc_qstats_overlimit(sch); + if (red_use_harddrop(q) || !red_use_ecn(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +@@ -133,7 +139,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->qstats.backlog += len; + sch->q.qlen++; + } else if (net_xmit_drop_count(ret)) { +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, ++ q->stats.pdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -461,9 +468,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, + &hw_stats_request); + } +- st.early = q->stats.prob_drop + q->stats.forced_drop; +- st.pdrop = q->stats.pdrop; +- st.marked = q->stats.prob_mark + q->stats.forced_mark; ++ st.early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop); ++ ++ st.pdrop = READ_ONCE(q->stats.pdrop); ++ ++ st.marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark); + + return gnet_stats_copy_app(d, &st, sizeof(st)); + } +-- +2.53.0 + diff --git a/queue-6.1/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch b/queue-6.1/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch new file mode 100644 index 0000000000..464c834204 --- /dev/null +++ b/queue-6.1/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch @@ -0,0 +1,169 @@ +From 00b0604464978caeef26b702e76054e7294e5044 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:16:55 +0000 +Subject: net/sched: sch_sfb: annotate data-races in sfb_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ] + +sfb_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_sfb_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260421141655.3953721-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 22 deletions(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index 1871a1c0224d4..ce67826fdf9b6 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen < 0xFFFF) +- b[hash].qlen++; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen > 0) +- b[hash].qlen--; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) + + static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_minus(b->p_mark, q->decrement); ++ WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement)); + } + + static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_plus(b->p_mark, q->increment); ++ WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment)); + } + + static void sfb_zero_all_buckets(struct sfb_sched_data *q) +@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da + const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0]; + + for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) { +- if (qlen < b->qlen) +- qlen = b->qlen; +- totalpm += b->p_mark; +- if (prob < b->p_mark) +- prob = b->p_mark; ++ u32 b_qlen = READ_ONCE(b->qlen); ++ u32 b_mark = READ_ONCE(b->p_mark); ++ ++ if (qlen < b_qlen) ++ qlen = b_qlen; ++ totalpm += b_mark; ++ if (prob < b_mark) ++ prob = b_mark; + b++; + } + *prob_r = prob; +@@ -294,7 +297,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(sch->q.qlen >= q->limit)) { + qdisc_qstats_overlimit(sch); +- q->stats.queuedrop++; ++ WRITE_ONCE(q->stats.queuedrop, ++ q->stats.queuedrop + 1); + goto drop; + } + +@@ -347,7 +351,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(minqlen >= q->max)) { + qdisc_qstats_overlimit(sch); +- q->stats.bucketdrop++; ++ WRITE_ONCE(q->stats.bucketdrop, ++ q->stats.bucketdrop + 1); + goto drop; + } + +@@ -373,7 +378,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + if (sfb_rate_limit(skb, q)) { + qdisc_qstats_overlimit(sch); +- q->stats.penaltydrop++; ++ WRITE_ONCE(q->stats.penaltydrop, ++ q->stats.penaltydrop + 1); + goto drop; + } + goto enqueue; +@@ -388,14 +394,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + * In either case, we want to start dropping packets. + */ + if (r < (p_min - SFB_MAX_PROB / 2) * 2) { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } + if (INET_ECN_set_ce(skb)) { +- q->stats.marked++; ++ WRITE_ONCE(q->stats.marked, ++ q->stats.marked + 1); + } else { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } +@@ -408,7 +417,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->q.qlen++; + increment_qlen(&cb, q); + } else if (net_xmit_drop_count(ret)) { +- q->stats.childdrop++; ++ WRITE_ONCE(q->stats.childdrop, ++ q->stats.childdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -597,12 +607,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct sfb_sched_data *q = qdisc_priv(sch); + struct tc_sfb_xstats st = { +- .earlydrop = q->stats.earlydrop, +- .penaltydrop = q->stats.penaltydrop, +- .bucketdrop = q->stats.bucketdrop, +- .queuedrop = q->stats.queuedrop, +- .childdrop = q->stats.childdrop, +- .marked = q->stats.marked, ++ .earlydrop = READ_ONCE(q->stats.earlydrop), ++ .penaltydrop = READ_ONCE(q->stats.penaltydrop), ++ .bucketdrop = READ_ONCE(q->stats.bucketdrop), ++ .queuedrop = READ_ONCE(q->stats.queuedrop), ++ .childdrop = READ_ONCE(q->stats.childdrop), ++ .marked = READ_ONCE(q->stats.marked), + }; + + st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q); +-- +2.53.0 + diff --git a/queue-6.1/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch b/queue-6.1/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch new file mode 100644 index 0000000000..62a590ebad --- /dev/null +++ b/queue-6.1/net-sched-taprio-continue-with-other-txqs-if-one-deq.patch @@ -0,0 +1,47 @@ +From 29d83c4942303ad56fc75b1ee696af15ed27bc09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:27 +0200 +Subject: net/sched: taprio: continue with other TXQs if one dequeue() failed + +From: Vladimir Oltean + +[ Upstream commit 1638bbbe4ececa615b273497d347d59ad71060a2 ] + +This changes the handling of an unlikely condition to not stop dequeuing +if taprio failed to dequeue the peeked skb in taprio_dequeue(). + +I've no idea when this can happen, but the only side effect seems to be +that the atomic_sub_return() call right above will have consumed some +budget. This isn't a big deal, since either that made us remain without +any budget (and therefore, we'd exit on the next peeked skb anyway), or +we could send some packets from other TXQs. + +I'm making this change because in a future patch I'll be refactoring the +dequeue procedure to simplify it, and this corner case will have to go +away. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 62219f23f76ab..aad95b084ae36 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -626,7 +626,7 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + + skb = child->ops->dequeue(child); + if (unlikely(!skb)) +- goto done; ++ continue; + + skb_found: + qdisc_bstats_update(sch, skb); +-- +2.53.0 + diff --git a/queue-6.1/net-sched-taprio-fix-use-after-free-in-advance_sched.patch b/queue-6.1/net-sched-taprio-fix-use-after-free-in-advance_sched.patch new file mode 100644 index 0000000000..35bb143c77 --- /dev/null +++ b/queue-6.1/net-sched-taprio-fix-use-after-free-in-advance_sched.patch @@ -0,0 +1,60 @@ +From 62f7193862c5438ef6a3fe342ab39541bfa91dd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 18:57:57 -0700 +Subject: net/sched: taprio: fix use-after-free in advance_sched() on schedule + switch + +From: Vinicius Costa Gomes + +[ Upstream commit 105425b1969c5affe532713cfac1c0b320d7ac2b ] + +In advance_sched(), when should_change_schedules() returns true, +switch_schedules() is called to promote the admin schedule to oper. +switch_schedules() queues the old oper schedule for RCU freeing via +call_rcu(), but 'next' still points into an entry of the old oper +schedule. The subsequent 'next->end_time = end_time' and +rcu_assign_pointer(q->current_entry, next) are use-after-free. + +Fix this by selecting 'next' from the new oper schedule immediately +after switch_schedules(), and using its pre-calculated end_time. +setup_first_end_time() sets the first entry's end_time to +base_time + interval when the schedule is installed, so the value +is already correct. + +The deleted 'end_time = sched_base_time(admin)' assignment was also +harmful independently: it would overwrite the new first entry's +pre-calculated end_time with just base_time. + +Fixes: a3d43c0d56f1 ("taprio: Add support adding an admin schedule") +Reported-by: Junxi Qian +Signed-off-by: Vinicius Costa Gomes +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index ce529b9448819..8da723f054f56 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -739,11 +739,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + end_time = min_t(ktime_t, end_time, oper->cycle_end_time); + + if (should_change_schedules(admin, oper, end_time)) { +- /* Set things so the next time this runs, the new +- * schedule runs. +- */ +- end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); ++ /* After changing schedules, the next entry is the first one ++ * in the new schedule, with a pre-calculated end_time. ++ */ ++ next = list_first_entry(&oper->entries, struct sched_entry, list); ++ end_time = next->end_time; + } + + next->end_time = end_time; +-- +2.53.0 + diff --git a/queue-6.1/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch b/queue-6.1/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch new file mode 100644 index 0000000000..19bb00705c --- /dev/null +++ b/queue-6.1/net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch @@ -0,0 +1,168 @@ +From c2e6b195cf14cb18733315305d021b8bc29ef9cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:28 +0200 +Subject: net/sched: taprio: refactor one skb dequeue from TXQ to separate + function + +From: Vladimir Oltean + +[ Upstream commit 92f966674f6a257eddfa60a85f9b6741d6087ccb ] + +Future changes will refactor the TXQ selection procedure, and a lot of +stuff will become messy, the indentation of the bulk of the dequeue +procedure would increase, etc. + +Break out the bulk of the function into a new one, which knows the TXQ +(child qdisc) we should perform a dequeue from. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 121 +++++++++++++++++++++-------------------- + 1 file changed, 63 insertions(+), 58 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index aad95b084ae36..10e1a420d4495 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -551,6 +551,66 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry) + atomic64_read(&q->picos_per_byte))); + } + ++static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, ++ struct sched_entry *entry, ++ u32 gate_mask) ++{ ++ struct taprio_sched *q = qdisc_priv(sch); ++ struct net_device *dev = qdisc_dev(sch); ++ struct Qdisc *child = q->qdiscs[txq]; ++ struct sk_buff *skb; ++ ktime_t guard; ++ int prio; ++ int len; ++ u8 tc; ++ ++ if (unlikely(!child)) ++ return NULL; ++ ++ if (TXTIME_ASSIST_IS_ENABLED(q->flags)) { ++ skb = child->ops->dequeue(child); ++ if (!skb) ++ return NULL; ++ goto skb_found; ++ } ++ ++ skb = child->ops->peek(child); ++ if (!skb) ++ return NULL; ++ ++ prio = skb->priority; ++ tc = netdev_get_prio_tc_map(dev, prio); ++ ++ if (!(gate_mask & BIT(tc))) ++ return NULL; ++ ++ len = qdisc_pkt_len(skb); ++ guard = ktime_add_ns(taprio_get_time(q), length_to_duration(q, len)); ++ ++ /* In the case that there's no gate entry, there's no ++ * guard band ... ++ */ ++ if (gate_mask != TAPRIO_ALL_GATES_OPEN && ++ ktime_after(guard, entry->close_time)) ++ return NULL; ++ ++ /* ... and no budget. */ ++ if (gate_mask != TAPRIO_ALL_GATES_OPEN && ++ atomic_sub_return(len, &entry->budget) < 0) ++ return NULL; ++ ++ skb = child->ops->dequeue(child); ++ if (unlikely(!skb)) ++ return NULL; ++ ++skb_found: ++ qdisc_bstats_update(sch, skb); ++ qdisc_qstats_backlog_dec(sch, skb); ++ sch->q.qlen--; ++ ++ return skb; ++} ++ + /* Will not be called in the full offload case, since the TX queues are + * attached to the Qdisc created using qdisc_create_dflt() + */ +@@ -576,64 +636,9 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) + goto done; + + for (i = 0; i < dev->num_tx_queues; i++) { +- struct Qdisc *child = q->qdiscs[i]; +- ktime_t guard; +- int prio; +- int len; +- u8 tc; +- +- if (unlikely(!child)) +- continue; +- +- if (TXTIME_ASSIST_IS_ENABLED(q->flags)) { +- skb = child->ops->dequeue(child); +- if (!skb) +- continue; +- goto skb_found; +- } +- +- skb = child->ops->peek(child); +- if (!skb) +- continue; +- +- prio = skb->priority; +- tc = netdev_get_prio_tc_map(dev, prio); +- +- if (!(gate_mask & BIT(tc))) { +- skb = NULL; +- continue; +- } +- +- len = qdisc_pkt_len(skb); +- guard = ktime_add_ns(taprio_get_time(q), +- length_to_duration(q, len)); +- +- /* In the case that there's no gate entry, there's no +- * guard band ... +- */ +- if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- ktime_after(guard, entry->close_time)) { +- skb = NULL; +- continue; +- } +- +- /* ... and no budget. */ +- if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- atomic_sub_return(len, &entry->budget) < 0) { +- skb = NULL; +- continue; +- } +- +- skb = child->ops->dequeue(child); +- if (unlikely(!skb)) +- continue; +- +-skb_found: +- qdisc_bstats_update(sch, skb); +- qdisc_qstats_backlog_dec(sch, skb); +- sch->q.qlen--; +- +- goto done; ++ skb = taprio_dequeue_from_txq(sch, i, entry, gate_mask); ++ if (skb) ++ goto done; + } + + done: +-- +2.53.0 + diff --git a/queue-6.1/net-sched-taprio-rename-close_time-to-end_time.patch b/queue-6.1/net-sched-taprio-rename-close_time-to-end_time.patch new file mode 100644 index 0000000000..23c8820a8f --- /dev/null +++ b/queue-6.1/net-sched-taprio-rename-close_time-to-end_time.patch @@ -0,0 +1,205 @@ +From 7891bc0eaa1b88d80f83477e430460f41c156d28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 15:54:32 +0200 +Subject: net/sched: taprio: rename close_time to end_time + +From: Vladimir Oltean + +[ Upstream commit e5517551112ff2395611e552443932152f83672d ] + +There is a confusion in terms in taprio which makes what is called +"close_time" to be actually used for 2 things: + +1. determining when an entry "closes" such that transmitted skbs are + never allowed to overrun that time (?!) +2. an aid for determining when to advance and/or restart the schedule + using the hrtimer + +It makes more sense to call this so-called "close_time" "end_time", +because it's not clear at all to me what "closes". Future patches will +hopefully make better use of the term "to close". + +This is an absolutely mechanical change. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Kurt Kanzenbach +Signed-off-by: David S. Miller +Stable-dep-of: 105425b1969c ("net/sched: taprio: fix use-after-free in advance_sched() on schedule switch") +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 52 +++++++++++++++++++++--------------------- + 1 file changed, 26 insertions(+), 26 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 10e1a420d4495..ce529b9448819 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -37,11 +37,11 @@ static LIST_HEAD(taprio_list); + struct sched_entry { + struct list_head list; + +- /* The instant that this entry "closes" and the next one ++ /* The instant that this entry ends and the next one + * should open, the qdisc will make some effort so that no + * packet leaves after this time. + */ +- ktime_t close_time; ++ ktime_t end_time; + ktime_t next_txtime; + atomic_t budget; + int index; +@@ -54,7 +54,7 @@ struct sched_gate_list { + struct rcu_head rcu; + struct list_head entries; + size_t num_entries; +- ktime_t cycle_close_time; ++ ktime_t cycle_end_time; + s64 cycle_time; + s64 cycle_time_extension; + s64 base_time; +@@ -591,7 +591,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, + * guard band ... + */ + if (gate_mask != TAPRIO_ALL_GATES_OPEN && +- ktime_after(guard, entry->close_time)) ++ ktime_after(guard, entry->end_time)) + return NULL; + + /* ... and no budget. */ +@@ -653,7 +653,7 @@ static bool should_restart_cycle(const struct sched_gate_list *oper, + if (list_is_last(&entry->list, &oper->entries)) + return true; + +- if (ktime_compare(entry->close_time, oper->cycle_close_time) == 0) ++ if (ktime_compare(entry->end_time, oper->cycle_end_time) == 0) + return true; + + return false; +@@ -661,7 +661,7 @@ static bool should_restart_cycle(const struct sched_gate_list *oper, + + static bool should_change_schedules(const struct sched_gate_list *admin, + const struct sched_gate_list *oper, +- ktime_t close_time) ++ ktime_t end_time) + { + ktime_t next_base_time, extension_time; + +@@ -670,18 +670,18 @@ static bool should_change_schedules(const struct sched_gate_list *admin, + + next_base_time = sched_base_time(admin); + +- /* This is the simple case, the close_time would fall after ++ /* This is the simple case, the end_time would fall after + * the next schedule base_time. + */ +- if (ktime_compare(next_base_time, close_time) <= 0) ++ if (ktime_compare(next_base_time, end_time) <= 0) + return true; + +- /* This is the cycle_time_extension case, if the close_time ++ /* This is the cycle_time_extension case, if the end_time + * plus the amount that can be extended would fall after the + * next schedule base_time, we can extend the current schedule + * for that amount. + */ +- extension_time = ktime_add_ns(close_time, oper->cycle_time_extension); ++ extension_time = ktime_add_ns(end_time, oper->cycle_time_extension); + + /* FIXME: the IEEE 802.1Q-2018 Specification isn't clear about + * how precisely the extension should be made. So after +@@ -700,7 +700,7 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + struct sched_gate_list *oper, *admin; + struct sched_entry *entry, *next; + struct Qdisc *sch = q->root; +- ktime_t close_time; ++ ktime_t end_time; + + spin_lock(&q->current_entry_lock); + entry = rcu_dereference_protected(q->current_entry, +@@ -719,41 +719,41 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + * entry of all schedules are pre-calculated during the + * schedule initialization. + */ +- if (unlikely(!entry || entry->close_time == oper->base_time)) { ++ if (unlikely(!entry || entry->end_time == oper->base_time)) { + next = list_first_entry(&oper->entries, struct sched_entry, + list); +- close_time = next->close_time; ++ end_time = next->end_time; + goto first_run; + } + + if (should_restart_cycle(oper, entry)) { + next = list_first_entry(&oper->entries, struct sched_entry, + list); +- oper->cycle_close_time = ktime_add_ns(oper->cycle_close_time, +- oper->cycle_time); ++ oper->cycle_end_time = ktime_add_ns(oper->cycle_end_time, ++ oper->cycle_time); + } else { + next = list_next_entry(entry, list); + } + +- close_time = ktime_add_ns(entry->close_time, next->interval); +- close_time = min_t(ktime_t, close_time, oper->cycle_close_time); ++ end_time = ktime_add_ns(entry->end_time, next->interval); ++ end_time = min_t(ktime_t, end_time, oper->cycle_end_time); + +- if (should_change_schedules(admin, oper, close_time)) { ++ if (should_change_schedules(admin, oper, end_time)) { + /* Set things so the next time this runs, the new + * schedule runs. + */ +- close_time = sched_base_time(admin); ++ end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); + } + +- next->close_time = close_time; ++ next->end_time = end_time; + taprio_set_budget(q, next); + + first_run: + rcu_assign_pointer(q->current_entry, next); + spin_unlock(&q->current_entry_lock); + +- hrtimer_set_expires(&q->advance_timer, close_time); ++ hrtimer_set_expires(&q->advance_timer, end_time); + + rcu_read_lock(); + __netif_schedule(sch); +@@ -1033,8 +1033,8 @@ static int taprio_get_start_time(struct Qdisc *sch, + return 0; + } + +-static void setup_first_close_time(struct taprio_sched *q, +- struct sched_gate_list *sched, ktime_t base) ++static void setup_first_end_time(struct taprio_sched *q, ++ struct sched_gate_list *sched, ktime_t base) + { + struct sched_entry *first; + ktime_t cycle; +@@ -1045,9 +1045,9 @@ static void setup_first_close_time(struct taprio_sched *q, + cycle = sched->cycle_time; + + /* FIXME: find a better place to do this */ +- sched->cycle_close_time = ktime_add_ns(base, cycle); ++ sched->cycle_end_time = ktime_add_ns(base, cycle); + +- first->close_time = ktime_add_ns(base, first->interval); ++ first->end_time = ktime_add_ns(base, first->interval); + taprio_set_budget(q, first); + rcu_assign_pointer(q->current_entry, NULL); + } +@@ -1679,7 +1679,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt, + if (admin) + call_rcu(&admin->rcu, taprio_free_sched_cb); + } else { +- setup_first_close_time(q, new_admin, start); ++ setup_first_end_time(q, new_admin, start); + + /* Protects against advance_sched() */ + spin_lock_irqsave(&q->current_entry_lock, flags); +-- +2.53.0 + diff --git a/queue-6.1/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch b/queue-6.1/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch new file mode 100644 index 0000000000..7dcd1261ca --- /dev/null +++ b/queue-6.1/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch @@ -0,0 +1,90 @@ +From d4fad73ec32330d11c828d36778be038fedad253 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:15:59 -0700 +Subject: net: tls: fix strparser anchor skb leak on offload RX setup failure + +From: Jakub Kicinski + +[ Upstream commit 58689498ca3384851145a754dbb1d8ed1cf9fb54 ] + +When tls_set_device_offload_rx() fails at tls_dev_add(), the error path +calls tls_sw_free_resources_rx() to clean up the SW context that was +initialized by tls_set_sw_offload(). This function calls +tls_sw_release_resources_rx() (which stops the strparser via +tls_strp_stop()) and tls_sw_free_ctx_rx() (which kfrees the context), +but never frees the anchor skb that was allocated by alloc_skb(0) in +tls_strp_init(). + +Note that tls_sw_free_resources_rx() is exclusively used for this +"failed to start offload" code path, there's no other caller. + +The leak did not exist before commit 84c61fe1a75b ("tls: rx: do not use +the standard strparser"), because the standard strparser doesn't try +to pre-allocate an skb. + +The normal close path in tls_sk_proto_close() handles cleanup by calling +tls_sw_strparser_done() (which calls tls_strp_done()) after dropping +the socket lock, because tls_strp_done() does cancel_work_sync() and +the strparser work handler takes the socket lock. + +Fixes: 84c61fe1a75b ("tls: rx: do not use the standard strparser") +Signed-off-by: Jakub Kicinski +Reviewed-by: Vadim Fedorenko +Link: https://patch.msgid.link/20260428231559.1358502-1-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls.h | 1 + + net/tls/tls_strp.c | 6 ++++++ + net/tls/tls_sw.c | 4 ++++ + 3 files changed, 11 insertions(+) + +diff --git a/net/tls/tls.h b/net/tls/tls.h +index f25699517bdf8..8304afbe09e96 100644 +--- a/net/tls/tls.h ++++ b/net/tls/tls.h +@@ -136,6 +136,7 @@ int tls_strp_dev_init(void); + void tls_strp_dev_exit(void); + + void tls_strp_done(struct tls_strparser *strp); ++void __tls_strp_done(struct tls_strparser *strp); + void tls_strp_stop(struct tls_strparser *strp); + int tls_strp_init(struct tls_strparser *strp, struct sock *sk); + void tls_strp_data_ready(struct tls_strparser *strp); +diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c +index 532230bed13b0..850146ed2d586 100644 +--- a/net/tls/tls_strp.c ++++ b/net/tls/tls_strp.c +@@ -619,6 +619,12 @@ void tls_strp_done(struct tls_strparser *strp) + WARN_ON(!strp->stopped); + + cancel_work_sync(&strp->work); ++ __tls_strp_done(strp); ++} ++ ++/* For setup error paths where the strparser was initialized but never armed. */ ++void __tls_strp_done(struct tls_strparser *strp) ++{ + tls_strp_anchor_free(strp); + } + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index a574d7ddd1499..ef7dda0915d33 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -2584,8 +2584,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx) + void tls_sw_free_resources_rx(struct sock *sk) + { + struct tls_context *tls_ctx = tls_get_ctx(sk); ++ struct tls_sw_context_rx *ctx; ++ ++ ctx = tls_sw_ctx_rx(tls_ctx); + + tls_sw_release_resources_rx(sk); ++ __tls_strp_done(&ctx->strp); + tls_sw_free_ctx_rx(tls_ctx); + } + +-- +2.53.0 + diff --git a/queue-6.1/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch b/queue-6.1/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch new file mode 100644 index 0000000000..43084dfed4 --- /dev/null +++ b/queue-6.1/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch @@ -0,0 +1,89 @@ +From 8ce16027a3eb09bf98da79e6d10e8c90378741b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 08:49:12 +0800 +Subject: net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit() + +From: Zhan Jun + +[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ] + +syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() +when accessing skb->len for tx statistics after usb_submit_urb() has +been called: + + BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760 + drivers/net/usb/rtl8150.c:712 + Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226 + +The URB completion handler write_bulk_callback() frees the skb via +dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU +in softirq context before usb_submit_urb() returns in the submitter, +so by the time the submitter reads skb->len the skb has already been +queued to the per-CPU completion_queue and freed by net_tx_action(): + + CPU A (xmit) CPU B (USB completion softirq) + ------------ ------------------------------ + dev->tx_skb = skb; + usb_submit_urb() --+ + |-------> write_bulk_callback() + | dev_kfree_skb_irq(dev->tx_skb) + | net_tx_action() + | napi_skb_cache_put() <-- free + netdev->stats.tx_bytes | + += skb->len; <-- UAF read + +Fix it by caching skb->len before submitting the URB and using the +cached value when updating the tx_bytes counter. + +The pre-existing tx_bytes semantics are preserved: the counter tracks +the original frame length (skb->len), not the ETH_ZLEN/USB-alignment +padded "count" value that is handed to the device. Changing that +would be a user-visible accounting change and is out of scope for +this UAF fix. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+3f46c095ac0ca048cb71@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e69ee7.050a0220.24bfd3.002b.GAE@google.com/ +Closes: https://syzkaller.appspot.com/bug?extid=3f46c095ac0ca048cb71 +Reviewed-by: Andrew Lunn +Signed-off-by: Zhan Jun +Link: https://patch.msgid.link/809895186B866C10+20260423004913.136655-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index e40b0669d9f4b..8700ae392b10a 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + rtl8150_t *dev = netdev_priv(netdev); ++ unsigned int skb_len; + int count, res; + + /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ +@@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + ++ skb_len = skb->len; ++ + netif_stop_queue(netdev); + dev->tx_skb = skb; + usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), +@@ -711,7 +714,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + } + } else { + netdev->stats.tx_packets++; +- netdev->stats.tx_bytes += skb->len; ++ netdev->stats.tx_bytes += skb_len; + netif_trans_update(netdev); + } + +-- +2.53.0 + diff --git a/queue-6.1/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch b/queue-6.1/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch new file mode 100644 index 0000000000..b946d2edb6 --- /dev/null +++ b/queue-6.1/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch @@ -0,0 +1,61 @@ +From 139ca45799fb3bba04240a93d32a9514f11e2a3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 09:55:17 +0800 +Subject: net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit + +From: Morduan Zang + +[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ] + +When rtl8150_start_xmit() fails to submit the tx URB, the URB is never +handed to the USB core and write_bulk_callback() will not run. The +driver returns NETDEV_TX_OK, which tells the networking stack that the +skb has been consumed, but nothing actually frees the skb on this +error path: + + dev->tx_skb = skb; + ... + if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { + ... + /* no kfree_skb here */ + } + return NETDEV_TX_OK; + +This leaks the skb on every submit failure and also leaves dev->tx_skb +pointing at memory that the driver itself may later free, which is +fragile. + +Free the skb with dev_kfree_skb_any() in the error path and clear +dev->tx_skb so no stale pointer is left behind. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reviewed-by: Andrew Lunn +Signed-off-by: Morduan Zang +Link: https://patch.msgid.link/E7D3E1C013C5A859+20260424015517.9574-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 8700ae392b10a..647f28b367b99 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -712,6 +712,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } ++ /* ++ * The URB was not submitted, so write_bulk_callback() will ++ * never run to free dev->tx_skb. Drop the skb here and ++ * clear tx_skb to avoid leaving a stale pointer. ++ */ ++ dev->tx_skb = NULL; ++ dev_kfree_skb_any(skb); + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb_len; +-- +2.53.0 + diff --git a/queue-6.1/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch b/queue-6.1/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch new file mode 100644 index 0000000000..814dd70e91 --- /dev/null +++ b/queue-6.1/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch @@ -0,0 +1,92 @@ +From b7751d964e8763b85e11eb6926726b467a7a248d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:33:49 +0000 +Subject: net_sched: sch_hhf: annotate data-races in hhf_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ] + +hhf_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421143349.4052215-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_hhf.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index 83fc44f20e31c..67b555c02f2c0 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash, + return NULL; + list_del(&flow->flowchain); + kfree(flow); +- q->hh_flows_current_cnt--; ++ WRITE_ONCE(q->hh_flows_current_cnt, ++ q->hh_flows_current_cnt - 1); + } else if (flow->hash_id == hash) { + return flow; + } +@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + } + + if (q->hh_flows_current_cnt >= q->hh_flows_limit) { +- q->hh_flows_overlimit++; ++ WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); + return NULL; + } + /* Create new entry. */ +@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + if (!flow) + return NULL; + +- q->hh_flows_current_cnt++; ++ WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); + INIT_LIST_HEAD(&flow->flowchain); + list_add_tail(&flow->flowchain, head); + +@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) + return WDRR_BUCKET_FOR_NON_HH; + flow->hash_id = hash; + flow->hit_timestamp = now; +- q->hh_flows_total_cnt++; ++ WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); + + /* By returning without updating counters in q->hhf_arrays, + * we implicitly implement "shielding" (see Optimization O1). +@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + + prev_backlog = sch->qstats.backlog; +- q->drop_overlimit++; ++ WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); + /* Return Congestion Notification only if we dropped a packet from this + * bucket. + */ +@@ -678,10 +679,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct hhf_sched_data *q = qdisc_priv(sch); + struct tc_hhf_xstats st = { +- .drop_overlimit = q->drop_overlimit, +- .hh_overlimit = q->hh_flows_overlimit, +- .hh_tot_count = q->hh_flows_total_cnt, +- .hh_cur_count = q->hh_flows_current_cnt, ++ .drop_overlimit = READ_ONCE(q->drop_overlimit), ++ .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), ++ .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), ++ .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.1/netconsole-propagate-device-name-truncation-in-dev_n.patch b/queue-6.1/netconsole-propagate-device-name-truncation-in-dev_n.patch new file mode 100644 index 0000000000..2a8987fc15 --- /dev/null +++ b/queue-6.1/netconsole-propagate-device-name-truncation-in-dev_n.patch @@ -0,0 +1,58 @@ +From be30fa6dc64f7f3f563a820dfd4e5425e1617ce0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 07:30:37 -0700 +Subject: netconsole: propagate device name truncation in dev_name_store() + +From: Breno Leitao + +[ Upstream commit 92ceb7bff62c2606f664c204750eca0b85d44112 ] + +dev_name_store() calls strscpy(nt->np.dev_name, buf, IFNAMSIZ) without +checking the return value. If userspace writes an interface name longer +than IFNAMSIZ - 1, strscpy() silently truncates and returns -E2BIG, but +the function ignores it and reports a fully successful write back to +userspace. + +If a real interface happens to match the truncated name, netconsole will +bind to the wrong device on the next enable, sending kernel logs and +panic output to an unintended network segment with no indication to +userspace that anything was rewritten. + +Reject writes whose length cannot fit in nt->np.dev_name up front: + + if (count >= IFNAMSIZ) + return -ENAMETOOLONG; + +This is not a big deal of a problem, but, it is still the correct +approach. + +Fixes: 0bcc1816188e57 ("[NET] netconsole: Support dynamic reconfiguration using configfs") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-3-59965f29d9cc@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index f9bf2c9a3ae2a..d150287c01a7d 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -414,6 +414,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + size_t count) + { + struct netconsole_target *nt = to_target(item); ++ size_t len = count; ++ ++ /* Account for a trailing newline appended by tools like echo */ ++ if (len && buf[len - 1] == '\n') ++ len--; ++ if (len >= IFNAMSIZ) ++ return -ENAMETOOLONG; + + mutex_lock(&dynamic_netconsole_mutex); + if (nt->enabled) { +-- +2.53.0 + diff --git a/queue-6.1/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch b/queue-6.1/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch new file mode 100644 index 0000000000..45eee7f58e --- /dev/null +++ b/queue-6.1/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch @@ -0,0 +1,43 @@ +From a7c1c78fa84db9e3aa2e38d89941e62c0c8e70da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 23:14:34 +0300 +Subject: netdevsim: zero initialize struct iphdr in dummy sk_buff + +From: Nikola Z. Ivanov + +[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ] + +Syzbot reports a KMSAN uninit-value originating from +nsim_dev_trap_skb_build, with the allocation also +being performed in the same function. + +Fix this by calling skb_put_zero instead of skb_put to +guarantee zero initialization of the whole IP header. + +Closes: https://syzkaller.appspot.com/bug?extid=23d7fcd204e3837866ff +Fixes: da58f90f11f5 ("netdevsim: Add devlink-trap support") +Signed-off-by: Nikola Z. Ivanov +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426201434.742030-1-zlatistiv@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netdevsim/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c +index 971796b30605a..97ace81b0b4dc 100644 +--- a/drivers/net/netdevsim/dev.c ++++ b/drivers/net/netdevsim/dev.c +@@ -758,7 +758,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) + skb->protocol = htons(ETH_P_IP); + + skb_set_network_header(skb, skb->len); +- iph = skb_put(skb, sizeof(struct iphdr)); ++ iph = skb_put_zero(skb, sizeof(struct iphdr)); + iph->protocol = IPPROTO_UDP; + iph->saddr = in_aton("192.0.2.1"); + iph->daddr = in_aton("198.51.100.1"); +-- +2.53.0 + diff --git a/queue-6.1/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch b/queue-6.1/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch new file mode 100644 index 0000000000..701dbd4b18 --- /dev/null +++ b/queue-6.1/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch @@ -0,0 +1,126 @@ +From bb2a1942dd4af5dad88df71e0911c98a2e855aaf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:15:32 +0200 +Subject: netfilter: arp_tables: fix IEEE1394 ARP payload parsing + +From: Pablo Neira Ayuso + +[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ] + +Weiming Shi says: + +"arp_packet_match() unconditionally parses the ARP payload assuming two +hardware addresses are present (source and target). However, +IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address +field, and arp_hdr_len() already accounts for this by returning a +shorter length for ARPHRD_IEEE1394 devices. + +As a result, on IEEE1394 interfaces arp_packet_match() advances past a +nonexistent target hardware address and reads the wrong bytes for both +the target device address comparison and the target IP address. This +causes arptables rules to match against garbage data, leading to +incorrect filtering decisions: packets that should be accepted may be +dropped and vice versa. + +The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already +handles this correctly by skipping the target hardware address for +ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()." + +Mangle the original patch to always return 0 (no match) in case user +matches on the target hardware address which is never present in +IEEE1394. + +Note that this returns 0 (no match) for either normal and inverse match +because matching in the target hardware address in ARPHRD_IEEE1394 has +never been supported by arptables. This is intentional, matching on the +target hardware address should never evaluate true for ARPHRD_IEEE1394. + +Moreover, adjust arpt_mangle to drop the packet too as AI suggests: + +In arpt_mangle, the logic assumes a standard ARP layout. Because +IEEE1394 (FireWire) omits the target hardware address, the linear +pointer arithmetic miscalculates the offset for the target IP address. +This causes mangling operations to write to the wrong location, leading +to packet corruption. To ensure safety, this patch drops packets +(NF_DROP) when mangling is requested for these fields on IEEE1394 +devices, as the current implementation cannot correctly map the FireWire +ARP payload. + +This omits both mangling target hardware and IP address. Even if IP +address mangling should be possible in IEEE1394, this would require +to adjust arpt_mangle offset calculation, which has never been +supported. + +Based on patch from Weiming Shi . + +Fixes: 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.") +Reported-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- + net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 14365b20f1c5c..564054123772a 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, + arpptr += dev->addr_len; + memcpy(&src_ipaddr, arpptr, sizeof(u32)); + arpptr += sizeof(u32); +- tgt_devaddr = arpptr; +- arpptr += dev->addr_len; ++ ++ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { ++ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, ++ sizeof(arpinfo->tgt_devaddr.mask)))) ++ return 0; ++ ++ tgt_devaddr = NULL; ++ } else { ++ tgt_devaddr = arpptr; ++ arpptr += dev->addr_len; ++ } + memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); + + if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, + arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, +- dev->addr_len)) || ++ dev->addr_len))) ++ return 0; ++ ++ if (tgt_devaddr && + NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, + arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, + dev->addr_len))) +diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c +index a4e07e5e9c118..f65dd339208e8 100644 +--- a/net/ipv4/netfilter/arpt_mangle.c ++++ b/net/ipv4/netfilter/arpt_mangle.c +@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += pln; + if (mangle->flags & ARPT_MANGLE_TDEV) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_DEV_ADDR_LEN_MAX < hln || + (arpptr + hln > skb_tail_pointer(skb))) + return NF_DROP; +@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += hln; + if (mangle->flags & ARPT_MANGLE_TIP) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_MANGLE_ADDR_LEN_MAX < pln || + (arpptr + pln > skb_tail_pointer(skb))) + return NF_DROP; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-conntrack-remove-sprintf-usage.patch b/queue-6.1/netfilter-conntrack-remove-sprintf-usage.patch new file mode 100644 index 0000000000..f4516ce357 --- /dev/null +++ b/queue-6.1/netfilter-conntrack-remove-sprintf-usage.patch @@ -0,0 +1,182 @@ +From ecbd11ceeae47216618172c4ac43eb6e25c0cac3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 19:13:46 +0200 +Subject: netfilter: conntrack: remove sprintf usage + +From: Florian Westphal + +[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ] + +Replace it with scnprintf, the buffer sizes are expected to be large enough +to hold the result, no need for snprintf+overflow check. + +Increase buffer size in mangle_content_len() while at it. + +BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 +Write of size 1 at addr [..] + vsnprintf+0xea5/0x1270 + sprintf+0xb1/0xe0 + mangle_content_len+0x1ac/0x280 + nf_nat_sdp_session+0x1cc/0x240 + process_sdp+0x8f8/0xb80 + process_invite_request+0x108/0x2b0 + process_sip_msg+0x5da/0xf50 + sip_help_tcp+0x45e/0x780 + nf_confirm+0x34d/0x990 + [..] + +Fixes: 9fafcd7b2032 ("[NETFILTER]: nf_conntrack/nf_nat: add SIP helper port") +Reported-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_nat_amanda.c | 2 +- + net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c +index 98deef6cde694..8f1054920a857 100644 +--- a/net/netfilter/nf_nat_amanda.c ++++ b/net/netfilter/nf_nat_amanda.c +@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb, + return NF_DROP; + } + +- sprintf(buffer, "%u", port); ++ snprintf(buffer, sizeof(buffer), "%u", port); + if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, + protoff, matchoff, matchlen, + buffer, strlen(buffer))) { +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index cf4aeb299bdef..c845b6d1a2bdf 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, + } + + static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, bool delim) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4", &addr->ip); ++ return scnprintf(buffer, size, "%pI4", &addr->ip); + else { + if (delim) +- return sprintf(buffer, "[%pI6c]", &addr->ip6); ++ return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); + else +- return sprintf(buffer, "%pI6c", &addr->ip6); ++ return scnprintf(buffer, size, "%pI6c", &addr->ip6); + } + } + + static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, u16 port) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4:%u", &addr->ip, port); ++ return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port); + else +- return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); ++ return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); + } + + static int map_addr(struct sk_buff *skb, unsigned int protoff, +@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, + if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) + return 1; + +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, true) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.dst.u3, + true); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, false) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.src.u3, + false); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +- buflen = sprintf(buffer, "%u", ntohs(p)); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle rport"); +@@ -418,7 +420,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, + + if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), ++ &newaddr, port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle packet"); +@@ -438,8 +441,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++ char buffer[sizeof("4294967295")]; + unsigned int matchoff, matchlen; +- char buffer[sizeof("65536")]; + int buflen, c_len; + + /* Get actual SDP length */ +@@ -454,7 +457,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + return 0; + +- buflen = sprintf(buffer, "%u", c_len); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -491,7 +494,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, + char buffer[INET6_ADDRSTRLEN]; + unsigned int buflen; + +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, + sdpoff, type, term, buffer, buflen)) + return 0; +@@ -509,7 +512,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + +- buflen = sprintf(buffer, "%u", port); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) + return 0; +@@ -529,7 +532,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, + SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) + return 0; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch b/queue-6.1/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch new file mode 100644 index 0000000000..3f96a43fe9 --- /dev/null +++ b/queue-6.1/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch @@ -0,0 +1,352 @@ +From 7c8396ed07314b1b8de5e5841ed9a7b7731a0edd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 02:19:11 +0200 +Subject: netfilter: nf_conntrack_sip: don't use simple_strtoul +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Florian Westphal + +[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ] + +Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), +and ct_sip_parse_request() with a new sip_parse_port() helper that +validates each digit against the buffer limit, eliminating the use of +simple_strtoul() which assumes NUL-terminated strings. + +The previous code dereferenced pointers without bounds checks after +sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated +skb data. A port that reaches the buffer limit without a trailing +character is also rejected as malformed. + +Also get rid of all simple_strtoul() usage in conntrack, prefer a +stricter version instead. There are intentional changes: + +- Bail out if number is > UINT_MAX and indicate a failure, same for + too long sequences. + While we do accept 05535 as port 5535, we will not accept e.g. + 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, + we should restrict this to not waste cycles when presented with + malformed packets with 64k '0' characters. + +- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch + 'expire=' and 'rports='; both are expected to use base-10. + +- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k + range. + +- epaddr_len now returns 0 if the port is invalid, as it already does + for invalid ip addresses. This is intentional. nf_conntrack_sip + performs lots of guesswork to find the right parts of the message + to parse. Being stricter could break existing setups. + Connection tracking helpers are designed to allow traffic to + pass, not to block it. + +Based on an earlier patch from Jenny Guanni Qu . + +Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper") +Reported-by: Klaudia Kloc +Reported-by: Dawid Moczadło +Reported-by: Jenny Guanni Qu . +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- + net/netfilter/nf_nat_sip.c | 1 + + 2 files changed, 119 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index fda6fc1fc4c58..4b32ee408ea15 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, + return 1; + } + ++/* Parse optional port number after IP address. ++ * Returns false on malformed input, true otherwise. ++ * If port is non-NULL, stores parsed port in network byte order. ++ * If no port is present, sets *port to default SIP port. ++ */ ++static bool sip_parse_port(const char *dptr, const char **endp, ++ const char *limit, __be16 *port) ++{ ++ unsigned int p = 0; ++ int len = 0; ++ ++ if (dptr >= limit) ++ return false; ++ ++ if (*dptr != ':') { ++ if (port) ++ *port = htons(SIP_PORT); ++ if (endp) ++ *endp = dptr; ++ return true; ++ } ++ ++ dptr++; /* skip ':' */ ++ ++ while (dptr < limit && isdigit(*dptr)) { ++ p = p * 10 + (*dptr - '0'); ++ dptr++; ++ len++; ++ if (len > 5) /* max "65535" */ ++ return false; ++ } ++ ++ if (len == 0) ++ return false; ++ ++ /* reached limit while parsing port */ ++ if (dptr >= limit) ++ return false; ++ ++ if (p < 1024 || p > 65535) ++ return false; ++ ++ if (port) ++ *port = htons(p); ++ ++ if (endp) ++ *endp = dptr; ++ ++ return true; ++} ++ + /* skip ip address. returns its length. */ + static int epaddr_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, + return 0; + } + +- /* Port number */ +- if (*dptr == ':') { +- dptr++; +- dptr += digits_len(ct, dptr, limit, shift); +- } ++ if (!sip_parse_port(dptr, &dptr, limit, NULL)) ++ return 0; + return dptr - aux; + } + +@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, + return epaddr_len(ct, dptr, limit, shift); + } + ++/* simple_strtoul stops after first non-number character. ++ * But as we're not dealing with c-strings, we can't rely on ++ * hitting \r,\n,\0 etc. before moving past end of buffer. ++ * ++ * This is a variant of simple_strtoul, but doesn't require ++ * a c-string. ++ * ++ * If value exceeds UINT_MAX, 0 is returned. ++ */ ++static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) ++{ ++ const unsigned int max = sizeof("4294967295"); ++ unsigned int olen = len; ++ const char *s = cp; ++ u64 result = 0; ++ ++ if (len > max) ++ len = max; ++ ++ while (olen > 0 && isdigit(*s)) { ++ unsigned int value; ++ ++ if (len == 0) ++ goto err; ++ ++ value = *s - '0'; ++ result = result * 10 + value; ++ ++ if (result > UINT_MAX) ++ goto err; ++ s++; ++ len--; ++ olen--; ++ } ++ ++ if (endp) ++ *endp = (char *)s; ++ ++ return result; ++err: ++ if (endp) ++ *endp = (char *)cp; ++ return 0; ++} ++ + /* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF +@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, + { + const char *start = dptr, *limit = dptr + datalen, *end; + unsigned int mlen; +- unsigned int p; + int shift = 0; + + /* Skip method and following whitespace */ +@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, + + if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) + return -1; +- if (end < limit && *end == ':') { +- end++; +- p = simple_strtoul(end, (char **)&end, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(end, &end, limit, port)) ++ return -1; + + if (end == dptr) + return 0; +@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + union nf_inet_addr *addr, __be16 *port) + { + const char *c, *limit = dptr + datalen; +- unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, +@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + + if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) + return -1; +- if (*c == ':') { +- c++; +- p = simple_strtoul(c, (char **)&c, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(c, &c, limit, port)) ++ return -1; + + if (dataoff) + *dataoff = c - dptr; +@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + return 0; + + start += strlen(name); +- *val = simple_strtoul(start, &end, 0); ++ *val = sip_strtouint(start, limit - start, (char **)&end); + if (start == end) + return -1; + if (matchoff && matchlen) { +@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { ++ char *end; ++ + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) +@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + mediaoff += t->len; + medialen -= t->len; + +- port = simple_strtoul(*dptr + mediaoff, NULL, 10); +- if (port == 0) ++ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); ++ if (port == 0 || *dptr + mediaoff == end) + continue; + if (port < 1024 || port > 65535) { + nf_ct_helper_log(skb, ct, "wrong port %u", port); +@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, +@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + while (1) { + unsigned int c_expires = expires; +@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen, matchend; + unsigned int code, cseq, i; ++ char *end; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; +- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); ++ code = sip_strtouint(*dptr + strlen("SIP/2.0 "), ++ *datalen - strlen("SIP/2.0 "), NULL); + if (!code) { + nf_ct_helper_log(skb, ct, "cannot get code"); + return NF_DROP; +@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; ++ char *end; + + handler = &sip_handlers[i]; + if (handler->request == NULL) +@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + break; + +- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); ++ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); + if (dptr + matchoff == end) + break; + +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index c845b6d1a2bdf..9fbfc6bff0c22 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, + "rport=", &poff, &plen, + &n) > 0 && ++ n >= 1024 && n <= 65535 && + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch b/queue-6.1/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch new file mode 100644 index 0000000000..3372c1b0a2 --- /dev/null +++ b/queue-6.1/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch @@ -0,0 +1,67 @@ +From 1de40786d0fac5284251f10548c1f18a0cbc90d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:14:01 -0700 +Subject: netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO + +From: Xiang Mei + +[ Upstream commit 2195574dc6d9017d32ac346987e12659f931d932 ] + +nf_osf_match_one() computes ctx->window % f->wss.val in the +OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A +CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a +subsequent matching TCP SYN divides by zero and panics the kernel. + +Reject the bogus fingerprint in nfnl_osf_add_callback() above the +per-option for-loop. f->wss is per-fingerprint, not per-option, so +the check must run regardless of f->opt_num (including 0). Also +reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that +as "should not happen". + +Crash: + Oops: divide error: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) + Call Trace: + + nf_osf_match (net/netfilter/nfnetlink_osf.c:220) + xt_osf_match_packet (net/netfilter/xt_osf.c:32) + ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) + nf_hook_slow (net/netfilter/core.c:622) + ip_local_deliver (net/ipv4/ip_input.c:265) + ip_rcv (include/linux/skbuff.h:1162) + __netif_receive_skb_one_core (net/core/dev.c:6181) + process_backlog (net/core/dev.c:6642) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7945) + handle_softirqs (kernel/softirq.c:622) + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Weiming Shi +Suggested-by: Florian Westphal +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Xiang Mei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index da9d5d6de98f4..000a5c280ef96 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, + if (f->opt_num > ARRAY_SIZE(f->opt)) + return -EINVAL; + ++ if (f->wss.wc >= OSF_WSS_MAX || ++ (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) ++ return -EINVAL; ++ + for (i = 0; i < f->opt_num; i++) { + if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch b/queue-6.1/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch new file mode 100644 index 0000000000..ec53960d38 --- /dev/null +++ b/queue-6.1/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch @@ -0,0 +1,100 @@ +From e377a4cc969ad6413226d3fb4326ea8eff7aac53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:56 +0200 +Subject: netfilter: nfnetlink_osf: fix out-of-bounds read on option matching + +From: Fernando Fernandez Mancera + +[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ] + +In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once +and passed by reference to nf_osf_match_one() for each fingerprint +checked. During TCP option parsing, nf_osf_match_one() advances the +shared ctx->optp pointer. + +If a fingerprint perfectly matches, the function returns early without +restoring ctx->optp to its initial state. If the user has configured +NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. +However, because ctx->optp was not restored, the next call to +nf_osf_match_one() starts parsing from the end of the options buffer. +This causes subsequent matches to read garbage data and fail +immediately, making it impossible to log more than one match or logging +incorrect matches. + +Instead of using a shared ctx->optp pointer, pass the context as a +constant pointer and use a local pointer (optp) for TCP option +traversal. This makes nf_osf_match_one() strictly stateless from the +caller's perspective, ensuring every fingerprint check starts at the +correct option offset. + +Fixes: 1a6a0951fc00 ("netfilter: nfnetlink_osf: add missing fmatch check") +Suggested-by: Florian Westphal +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 000a5c280ef96..2207bda442d54 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx { + static bool nf_osf_match_one(const struct sk_buff *skb, + const struct nf_osf_user_finger *f, + int ttl_check, +- struct nf_osf_hdr_ctx *ctx) ++ const struct nf_osf_hdr_ctx *ctx) + { +- const __u8 *optpinit = ctx->optp; ++ const __u8 *optp = ctx->optp; + unsigned int check_WSS = 0; + int fmatch = FMATCH_WRONG; + int foptsize, optnum; +@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { +- if (f->opt[optnum].kind == *ctx->optp) { ++ if (f->opt[optnum].kind == *optp) { + __u32 len = f->opt[optnum].length; +- const __u8 *optend = ctx->optp + len; ++ const __u8 *optend = optp + len; + + fmatch = FMATCH_OK; + +- switch (*ctx->optp) { ++ switch (*optp) { + case OSFOPT_MSS: +- mss = ctx->optp[3]; ++ mss = optp[3]; + mss <<= 8; +- mss |= ctx->optp[2]; ++ mss |= optp[2]; + + mss = ntohs((__force __be16)mss); + break; +@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + break; + } + +- ctx->optp = optend; ++ optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + +@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + } + } + +- if (fmatch != FMATCH_OK) +- ctx->optp = optpinit; +- + return fmatch == FMATCH_OK; + } + +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch b/queue-6.1/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch new file mode 100644 index 0000000000..d1860ecd13 --- /dev/null +++ b/queue-6.1/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch @@ -0,0 +1,74 @@ +From fcc5a9feea1635e4b618fe26db49e90f1c7b0461 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:57 +0200 +Subject: netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check + +From: Fernando Fernandez Mancera + +[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ] + +The nf_osf_ttl() function accessed skb->dev to perform a local interface +address lookup without verifying that the device pointer was valid. + +Additionally, the implementation utilized an in_dev_for_each_ifa_rcu +loop to match the packet source address against local interface +addresses. It assumed that packets from the same subnet should not see a +decrement on the initial TTL. A packet might appear it is from the same +subnet but it actually isn't especially in modern environments with +containers and virtual switching. + +Remove the device dereference and interface loop. Replace the logic with +a switch statement that evaluates the TTL according to the ttl_check. + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Kito Xu (veritas501) +Closes: https://lore.kernel.org/netfilter-devel/20260414074556.2512750-1-hxzene@gmail.com/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 2207bda442d54..6d3dfbeb398cb 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); + static inline int nf_osf_ttl(const struct sk_buff *skb, + int ttl_check, unsigned char f_ttl) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + const struct iphdr *ip = ip_hdr(skb); +- const struct in_ifaddr *ifa; +- int ret = 0; + +- if (ttl_check == NF_OSF_TTL_TRUE) ++ switch (ttl_check) { ++ case NF_OSF_TTL_TRUE: + return ip->ttl == f_ttl; +- if (ttl_check == NF_OSF_TTL_NOCHECK) +- return 1; +- else if (ip->ttl <= f_ttl) ++ break; ++ case NF_OSF_TTL_NOCHECK: + return 1; +- +- in_dev_for_each_ifa_rcu(ifa, in_dev) { +- if (inet_ifa_match(ip->saddr, ifa)) { +- ret = (ip->ttl == f_ttl); +- break; +- } ++ case NF_OSF_TTL_LESS: ++ default: ++ return ip->ttl <= f_ttl; + } +- +- return ret; + } + + struct nf_osf_hdr_ctx { +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch b/queue-6.1/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch new file mode 100644 index 0000000000..c4cd8e5c52 --- /dev/null +++ b/queue-6.1/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch @@ -0,0 +1,49 @@ +From caad1ddc41ea6ea227f710382c5056461845a6ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:30:41 +0200 +Subject: netfilter: nft_fwd_netdev: check ttl/hl before forwarding + +From: Florian Westphal + +[ Upstream commit 1dfd95bdf4d18d263aa8fad06bfb9f4d9c992b18 ] + +Drop packets if their ttl/hl is too small for forwarding. + +Fixes: d32de98ea70f ("netfilter: nft_fwd_netdev: allow to forward packets via neighbour layer") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_fwd_netdev.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c +index 7c5876dc9ff2b..6f6b355134625 100644 +--- a/net/netfilter/nft_fwd_netdev.c ++++ b/net/netfilter/nft_fwd_netdev.c +@@ -115,6 +115,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + iph = ip_hdr(skb); ++ if (iph->ttl <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip_decrease_ttl(iph); + neigh_table = NEIGH_ARP_TABLE; + break; +@@ -131,6 +136,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + ip6h = ipv6_hdr(skb); ++ if (ip6h->hop_limit <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip6h->hop_limit--; + neigh_table = NEIGH_ND_TABLE; + break; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-nft_osf-restrict-it-to-ipv4.patch b/queue-6.1/netfilter-nft_osf-restrict-it-to-ipv4.patch new file mode 100644 index 0000000000..2f2ac89a60 --- /dev/null +++ b/queue-6.1/netfilter-nft_osf-restrict-it-to-ipv4.patch @@ -0,0 +1,47 @@ +From 2de81e151bbd77b52423989cec1a5b8e314d989b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 13:06:38 +0200 +Subject: netfilter: nft_osf: restrict it to ipv4 + +From: Pablo Neira Ayuso + +[ Upstream commit b336fdbb7103fb1484e1dcb6741151d4b5a41e35 ] + +This expression only supports for ipv4, restrict it. + +Fixes: b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf") +Acked-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_osf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c +index adacf95b6e2bd..9bf2dfd351846 100644 +--- a/net/netfilter/nft_osf.c ++++ b/net/netfilter/nft_osf.c +@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, + struct nf_osf_data data; + struct tcphdr _tcph; + ++ if (nft_pf(pkt) != NFPROTO_IPV4) { ++ regs->verdict.code = NFT_BREAK; ++ return; ++ } ++ + if (pkt->tprot != IPPROTO_TCP) { + regs->verdict.code = NFT_BREAK; + return; +@@ -119,7 +124,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx, + + switch (ctx->family) { + case NFPROTO_IPV4: +- case NFPROTO_IPV6: + case NFPROTO_INET: + hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | +-- +2.53.0 + diff --git a/queue-6.1/netfilter-skip-recording-stale-or-retransmitted-init.patch b/queue-6.1/netfilter-skip-recording-stale-or-retransmitted-init.patch new file mode 100644 index 0000000000..8cc0b16299 --- /dev/null +++ b/queue-6.1/netfilter-skip-recording-stale-or-retransmitted-init.patch @@ -0,0 +1,63 @@ +From b511180469db6ac310a17be4227c6fb0ae0cbe47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:40 -0400 +Subject: netfilter: skip recording stale or retransmitted INIT + +From: Xin Long + +[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ] + +An INIT whose init_tag matches the peer's vtag does not provide new state +information. It indicates either: + +- a stale INIT (after INIT-ACK has already been seen on the same side), or +- a retransmitted INIT (after INIT has already been recorded on the same + side). + +In both cases, the INIT must not update ct->proto.sctp.init[] state, since +it does not advance the handshake tracking and may otherwise corrupt +INIT/INIT-ACK validation logic. + +Allow INIT processing only when the conntrack entry is newly created +(SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer +vtag. + +Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in +nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it +set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag. + +Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") +Signed-off-by: Xin Long +Reviewed-by: Marcelo Ricardo Leitner +Acked-by: Florian Westphal +Link: https://patch.msgid.link/ee56c3e416452b2a40589a2a85245ac2ad5e9f4b.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index 90458799324ec..ae89f3c590e8b 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -484,9 +484,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + if (!ih) + goto out_unlock; + +- if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) +- ct->proto.sctp.init[!dir] = 0; +- ct->proto.sctp.init[dir] = 1; ++ /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ ++ if (old_state == SCTP_CONNTRACK_NONE || ++ ct->proto.sctp.vtag[!dir] != ih->init_tag) { ++ if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) ++ ct->proto.sctp.init[!dir] = 0; ++ ct->proto.sctp.init[dir] = 1; ++ } + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); + ct->proto.sctp.vtag[!dir] = ih->init_tag; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch b/queue-6.1/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch new file mode 100644 index 0000000000..0a20ff6cae --- /dev/null +++ b/queue-6.1/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch @@ -0,0 +1,47 @@ +From 27ffe459053c7f2c0c7217093f964eb704b0e3d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:25:06 +0800 +Subject: netfilter: xt_policy: fix strict mode inbound policy matching + +From: Jiexun Wang + +[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ] + +match_policy_in() walks sec_path entries from the last transform to the +first one, but strict policy matching needs to consume info->pol[] in +the same forward order as the rule layout. + +Derive the strict-match policy position from the number of transforms +already consumed so that multi-element inbound rules are matched +consistently. + +Fixes: c4b885139203 ("[NETFILTER]: x_tables: replace IPv4/IPv6 policy match by address family independant version") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Acked-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c +index cb6e8279010a4..b5fa65558318f 100644 +--- a/net/netfilter/xt_policy.c ++++ b/net/netfilter/xt_policy.c +@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, + return 0; + + for (i = sp->len - 1; i >= 0; i--) { +- pos = strict ? i - sp->len + 1 : 0; ++ pos = strict ? sp->len - i - 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; +-- +2.53.0 + diff --git a/queue-6.1/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch b/queue-6.1/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch new file mode 100644 index 0000000000..00c39fc1fc --- /dev/null +++ b/queue-6.1/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch @@ -0,0 +1,86 @@ +From 20c201184e8137295646e4bdfe45ae4b4c2e8f32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 12:12:59 +0200 +Subject: netfilter: xt_socket: enable defrag after all other checks + +From: Florian Westphal + +[ Upstream commit 542be3fa5aff54210a02954c38f07e53ea9bdafd ] + +Originally this did not matter because defrag was enabled once per netns +and only disabled again on netns dismantle. When this got changed I should +have adjusted checkentry to not leave defrag enabled on error. + +Fixes: de8c12110a13 ("netfilter: disable defrag once its no longer needed") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_socket.c | 23 ++++++----------------- + 1 file changed, 6 insertions(+), 17 deletions(-) + +diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c +index 76e01f292aaff..811e53bee4085 100644 +--- a/net/netfilter/xt_socket.c ++++ b/net/netfilter/xt_socket.c +@@ -168,52 +168,41 @@ static int socket_mt_enable_defrag(struct net *net, int family) + static int socket_mt_v1_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V1) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V1); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v2_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V2) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V2); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v3_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo3 *info = + (struct xt_socket_mtinfo3 *)par->matchinfo; +- int err; + +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + if (info->flags & ~XT_SOCKET_FLAGS_V3) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V3); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static void socket_mt_destroy(const struct xt_mtdtor_param *par) +-- +2.53.0 + diff --git a/queue-6.1/netfilter-xtables-restrict-several-matches-to-inet-f.patch b/queue-6.1/netfilter-xtables-restrict-several-matches-to-inet-f.patch new file mode 100644 index 0000000000..1ab15a66f7 --- /dev/null +++ b/queue-6.1/netfilter-xtables-restrict-several-matches-to-inet-f.patch @@ -0,0 +1,208 @@ +From d3847e4a447ada9d8534cb31c0ce92c9335a7ac7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 12:21:00 +0200 +Subject: netfilter: xtables: restrict several matches to inet family + +From: Pablo Neira Ayuso + +[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ] + +This is a partial revert of: + + commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") + +to allow ipv4 and ipv6 only. + +- xt_mac +- xt_owner +- xt_physdev + +These extensions are not used by ebtables in userspace. + +Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 +specific. + +Fixes: ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") +Reported-by: "Kito Xu (veritas501)" +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- + net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ + net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- + net/netfilter/xt_realm.c | 2 +- + 4 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index 81649da57ba5d..bd2354760895d 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + return ret; + } + +-static struct xt_match mac_mt_reg __read_mostly = { +- .name = "mac", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .match = mac_mt, +- .matchsize = sizeof(struct xt_mac_info), +- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | +- (1 << NF_INET_FORWARD), +- .me = THIS_MODULE, ++static struct xt_match mac_mt_reg[] __read_mostly = { ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV4, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV6, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init mac_mt_init(void) + { +- return xt_register_match(&mac_mt_reg); ++ return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + static void __exit mac_mt_exit(void) + { +- xt_unregister_match(&mac_mt_reg); ++ xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + module_init(mac_mt_init); +diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c +index 50332888c8d23..7be2fe22b067e 100644 +--- a/net/netfilter/xt_owner.c ++++ b/net/netfilter/xt_owner.c +@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + +-static struct xt_match owner_mt_reg __read_mostly = { +- .name = "owner", +- .revision = 1, +- .family = NFPROTO_UNSPEC, +- .checkentry = owner_check, +- .match = owner_mt, +- .matchsize = sizeof(struct xt_owner_match_info), +- .hooks = (1 << NF_INET_LOCAL_OUT) | +- (1 << NF_INET_POST_ROUTING), +- .me = THIS_MODULE, ++static struct xt_match owner_mt_reg[] __read_mostly = { ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV4, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV6, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ } + }; + + static int __init owner_mt_init(void) + { +- return xt_register_match(&owner_mt_reg); ++ return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + static void __exit owner_mt_exit(void) + { +- xt_unregister_match(&owner_mt_reg); ++ xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + module_init(owner_mt_init); +diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c +index 343e65f377d44..130842c35c6fa 100644 +--- a/net/netfilter/xt_physdev.c ++++ b/net/netfilter/xt_physdev.c +@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) + return 0; + } + +-static struct xt_match physdev_mt_reg __read_mostly = { +- .name = "physdev", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .checkentry = physdev_mt_check, +- .match = physdev_mt, +- .matchsize = sizeof(struct xt_physdev_info), +- .me = THIS_MODULE, ++static struct xt_match physdev_mt_reg[] __read_mostly = { ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV4, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV6, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init physdev_mt_init(void) + { +- return xt_register_match(&physdev_mt_reg); ++ return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + static void __exit physdev_mt_exit(void) + { +- xt_unregister_match(&physdev_mt_reg); ++ xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + module_init(physdev_mt_init); +diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c +index 6df485f4403d0..61b2f1e58d150 100644 +--- a/net/netfilter/xt_realm.c ++++ b/net/netfilter/xt_realm.c +@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { + .matchsize = sizeof(struct xt_realm_info), + .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), +- .family = NFPROTO_UNSPEC, ++ .family = NFPROTO_IPV4, + .me = THIS_MODULE + }; + +-- +2.53.0 + diff --git a/queue-6.1/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch b/queue-6.1/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch new file mode 100644 index 0000000000..1513cbcb45 --- /dev/null +++ b/queue-6.1/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch @@ -0,0 +1,69 @@ +From c9d8f21758cdd4db65ba5d4987cbd0f8a86ad20f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:19 +0800 +Subject: nexthop: fix IPv6 route referencing IPv4 nexthop + +From: Jiayuan Chen + +[ Upstream commit 29c95185ba32b621fbc3800fb86e7dc3edf5c2be ] + +syzbot reported a panic [1] [2]. + +When an IPv6 nexthop is replaced with an IPv4 nexthop, the has_v4 flag +of all groups containing this nexthop is not updated. This is because +nh_group_v4_update is only called when replacing AF_INET to AF_INET6, +but the reverse direction (AF_INET6 to AF_INET) is missed. + +This allows a stale has_v4=false to bypass fib6_check_nexthop, causing +IPv6 routes to be attached to groups that effectively contain only AF_INET +members. Subsequent route lookups then call nexthop_fib6_nh() which +returns NULL for the AF_INET member, leading to a NULL pointer +dereference. + +Fix by calling nh_group_v4_update whenever the family changes, not just +AF_INET to AF_INET6. + +Reproducer: + # AF_INET6 blackhole + ip -6 nexthop add id 1 blackhole + # group with has_v4=false + ip nexthop add id 100 group 1 + # replace with AF_INET (no -6), has_v4 stays false + ip nexthop replace id 1 blackhole + # pass stale has_v4 check + ip -6 route add 2001:db8::/64 nhid 100 + # panic + ping -6 2001:db8::1 + +[1] https://syzkaller.appspot.com/bug?id=e17283eb2f8dcf3dd9b47fe6f67a95f71faadad0 +[2] https://syzkaller.appspot.com/bug?id=8699b6ae54c9f35837d925686208402949e12ef3 +Fixes: 7bf4796dd099 ("nexthops: add support for replace") +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/nexthop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c +index 10cb365639aaa..49871e5f46802 100644 +--- a/net/ipv4/nexthop.c ++++ b/net/ipv4/nexthop.c +@@ -2160,10 +2160,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + goto err_notify; + } + +- /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially ++ /* When replacing a nexthop with one of a different family, potentially + * update IPv4 indication in all the groups using the nexthop. + */ +- if (oldi->family == AF_INET && newi->family == AF_INET6) { ++ if (oldi->family != newi->family) { + list_for_each_entry(nhge, &old->grp_list, nh_list) { + struct nexthop *nhp = nhge->nh_parent; + struct nh_group *nhg; +-- +2.53.0 + diff --git a/queue-6.1/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch b/queue-6.1/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch new file mode 100644 index 0000000000..bb9fa9ce53 --- /dev/null +++ b/queue-6.1/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch @@ -0,0 +1,53 @@ +From 5b993628bc8b760da4f8dd21e90e7ca37dbb675d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 12:09:30 +0200 +Subject: NFC: trf7970a: Ignore antenna noise when checking for RF field + +From: Paul Geurts + +[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ] + +The main channel Received Signal Strength Indicator (RSSI) measurement +is used to determine whether an RF field is present or not. RSSI != 0 +is interpreted as an RF Field is present. This does not take RF noise +and measurement inaccuracy into account, and results in false positives +in the field. + +Define a noise level and make sure the RF field is only interpreted as +present when the RSSI is above the noise level. + +Fixes: 851ee3cbf850 ("NFC: trf7970a: Don't turn on RF if there is already an RF field") +Signed-off-by: Paul Geurts +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Mark Greer +Link: https://patch.msgid.link/20260422100930.581237-1-paul.geurts@prodrive-technologies.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/trf7970a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c +index 7968baa626d16..b7a8d525e3c29 100644 +--- a/drivers/nfc/trf7970a.c ++++ b/drivers/nfc/trf7970a.c +@@ -311,6 +311,7 @@ + #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) ++#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 + + #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) + #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +@@ -1253,7 +1254,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) + if (ret) + return ret; + +- if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) ++ if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) + *is_rf_field = true; + else + *is_rf_field = false; +-- +2.53.0 + diff --git a/queue-6.1/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch b/queue-6.1/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch new file mode 100644 index 0000000000..3014a13272 --- /dev/null +++ b/queue-6.1/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch @@ -0,0 +1,107 @@ +From fd1b17ea2cc17846f304fd4207066dda644061fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 16:05:36 +0000 +Subject: nfp: fix swapped arguments in nfp_encode_basic_qdr() calls + +From: Alexey Kodanev + +[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ] + +There is a mismatch between the passed arguments and the actual +nfp_encode_basic_qdr() function parameter names: + + static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + int mode, bool addr40, int isld1, + int isld0) + { + ... + +But "dest_island" and "cpp_tgt" are swapped at every call-site. +For example: + + return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + mode, addr40, isld1, isld0); + +As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target +type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" +as the destination island ID, which can accidentally match or be outside +the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination). + +Since code already worked for years, also add extra pr_warn() to error +paths in nfp_encode_basic_qdr() to help identify any potential address +verification failures. + +Detected using the static analysis tool - Svace. + +Fixes: 4cb584e0ee7d ("nfp: add CPP access core") +Signed-off-by: Alexey Kodanev +Link: https://patch.msgid.link/20260422160536.61855-1-aleksei.kodanev@bell-sw.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +index 79470f198a62a..9cf19446657c6 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + + /* Full Island ID and channel bits overlap? */ + ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0); +- if (ret) ++ if (ret) { ++ pr_warn("%s: decode dest_island failed: %d\n", __func__, ret); + return ret; ++ } + + /* The current address won't go where expected? */ +- if (dest_island != -1 && dest_island != v) ++ if (dest_island != -1 && dest_island != v) { ++ pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n", ++ __func__, dest_island, v); + return -EINVAL; ++ } + + /* If dest_island was -1, we don't care where it goes. */ + return 0; +@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * the address but we can verify if the existing + * contents will point to a valid island. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + iid_lsb = addr40 ? 34 : 26; +@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + return 0; + case 1: + if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40) +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + idx_lsb = addr40 ? 39 : 31; +@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * be set before hand and with them select an island. + * So we need to confirm that it's at least plausible. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + /* Make sure we compare against isldN values +@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * iid<1> = addr<30> = channel<0> + * channel<1> = addr<31> = Index + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + isld[0] &= ~3; +-- +2.53.0 + diff --git a/queue-6.1/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch b/queue-6.1/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch new file mode 100644 index 0000000000..5b05a162b5 --- /dev/null +++ b/queue-6.1/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch @@ -0,0 +1,58 @@ +From ca6a89f9b2aad16ddf1e87c165239460550a4d34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:49 +0100 +Subject: nfs/blocklayout: Fix compilation error (`make W=1`) in + bl_write_pagelist() + +From: Andy Shevchenko + +[ Upstream commit f83c8dda456ce4863f346aa26d88efa276eda35d ] + +Clang compiler is not happy about set but unused variable +(when dprintk() is no-op): + +.../blocklayout/blocklayout.c:384:9: error: variable 'count' set but not used [-Werror,-Wunused-but-set-variable] + +Remove a leftover from the previous cleanup. + +Fixes: 3a6fd1f004fc ("pnfs/blocklayout: remove read-modify-write handling in bl_write_pagelist") +Acked-by: Anna Schumaker +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/blocklayout/blocklayout.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c +index e498aade8c479..15f66d949adda 100644 +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -381,14 +381,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + sector_t isect, extent_length = 0; + struct parallel_io *par = NULL; + loff_t offset = header->args.offset; +- size_t count = header->args.count; + struct page **pages = header->args.pages; + int pg_index = header->args.pgbase >> PAGE_SHIFT; + unsigned int pg_len; + struct blk_plug plug; + int i; + +- dprintk("%s enter, %zu@%lld\n", __func__, count, offset); ++ dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); + + /* At this point, header->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error +@@ -429,7 +428,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + } + + offset += pg_len; +- count -= pg_len; + isect += (pg_len >> SECTOR_SHIFT); + extent_length -= (pg_len >> SECTOR_SHIFT); + } +-- +2.53.0 + diff --git a/queue-6.1/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch b/queue-6.1/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch new file mode 100644 index 0000000000..b5d734d012 --- /dev/null +++ b/queue-6.1/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch @@ -0,0 +1,61 @@ +From 3f857eb4849389a6089d731d1b37cce8e733b9bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:52:09 +0900 +Subject: nilfs2: reject zero bd_oblocknr in nilfs_ioctl_mark_blocks_dirty() + +From: Deepanshu Kartikey + +[ Upstream commit be3e5d10643d3be1cbac9d9939f220a99253f980 ] + +nilfs_ioctl_mark_blocks_dirty() uses bd_oblocknr to detect dead blocks +by comparing it with the current block number bd_blocknr. If they differ, +the block is considered dead and skipped. + +However, bd_oblocknr should never be 0 since block 0 typically stores the +primary superblock and is never a valid GC target block. A corrupted ioctl +request with bd_oblocknr set to 0 causes the comparison to incorrectly +match when the lookup returns -ENOENT and sets bd_blocknr to 0, bypassing +the dead block check and calling nilfs_bmap_mark() on a non-existent +block. This causes nilfs_btree_do_lookup() to return -ENOENT, triggering +the WARN_ON(ret == -ENOENT). + +Fix this by rejecting ioctl requests with bd_oblocknr set to 0 at the +beginning of each iteration. + +[ryusuke: slightly modified the commit message and comments for accuracy] + +Fixes: 7942b919f732 ("nilfs2: ioctl operations") +Reported-by: syzbot+98a040252119df0506f8@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=98a040252119df0506f8 +Suggested-by: Ryusuke Konishi +Signed-off-by: Deepanshu Kartikey +Reported-by: syzbot+466a45fcfb0562f5b9a0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=466a45fcfb0562f5b9a0 +Cc: Junjie Cao +Signed-off-by: Ryusuke Konishi +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/nilfs2/ioctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index 1d4d610bd82b5..7f972f0b1a885 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -751,6 +751,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, + int ret, i; + + for (i = 0; i < nmembs; i++) { ++ /* ++ * bd_oblocknr must never be 0 as block 0 ++ * is never a valid GC target block ++ */ ++ if (unlikely(!bdescs[i].bd_oblocknr)) ++ return -EINVAL; + /* XXX: use macro or inline func to check liveness */ + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, +-- +2.53.0 + diff --git a/queue-6.1/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch b/queue-6.1/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch new file mode 100644 index 0000000000..0c4d93d0f5 --- /dev/null +++ b/queue-6.1/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch @@ -0,0 +1,39 @@ +From 0fbf16178dde769d68a2201d9cc680319eb06de3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 09:14:02 -0700 +Subject: nvme-pci: fix missed admin queue sq doorbell write + +From: Keith Busch + +[ Upstream commit 1cc4cdae2a3b7730d462d69e30f213fd2efe7807 ] + +We can batch admin commands submitted through io_uring_cmd passthrough, +which means bd->last may be false and skips the doorbell write to +aggregate multiple commands per write. If a subsequent command can't be +dispatched for whatever reason, we have to provide the blk-mq ops' +commit_rqs callback in order to ensure we properly update the doorbell. + +Fixes: 58e5bdeb9c2b ("nvme: enable uring-passthrough for admin commands") +Reviewed-by: Christoph Hellwig +Reviewed-by: Kanchan Joshi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 394673a7f75cb..660e8fbb18136 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1756,6 +1756,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled) + static const struct blk_mq_ops nvme_mq_admin_ops = { + .queue_rq = nvme_queue_rq, + .complete = nvme_pci_complete_rq, ++ .commit_rqs = nvme_commit_rqs, + .init_hctx = nvme_admin_init_hctx, + .init_request = nvme_pci_init_request, + .timeout = nvme_timeout, +-- +2.53.0 + diff --git a/queue-6.1/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch b/queue-6.1/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch new file mode 100644 index 0000000000..291f6c13f4 --- /dev/null +++ b/queue-6.1/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch @@ -0,0 +1,162 @@ +From 52bdb713c3fa30a3b4bf907611d3780fa3e5e4f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 15:39:35 +0100 +Subject: nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its + callers + +From: Maurizio Lombardi + +[ Upstream commit ea8e356acb165cb1fd75537a52e1f66e5e76c538 ] + +Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds +PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) +and returns early. However, because the function returns void, the +callers are entirely unaware that a fatal error has occurred and +that the cmd->recv_msg.msg_iter was left uninitialized. + +Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly +overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA +Consequently, the socket receiving loop may attempt to read incoming +network data into the uninitialized iterator. + +Fix this by shifting the error handling responsibility to the callers. + +Fixes: 52a0a9854934 ("nvmet-tcp: add bounds checks in nvmet_tcp_build_pdu_iovec") +Reviewed-by: Hannes Reinecke +Reviewed-by: Yunje Shin +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Maurizio Lombardi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 51 ++++++++++++++++++++++----------------- + 1 file changed, 29 insertions(+), 22 deletions(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index a46c9f5110838..01d685499b97d 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -308,7 +308,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); + +-static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) ++static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + { + struct bio_vec *iov = cmd->iov; + struct scatterlist *sg; +@@ -321,22 +321,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + offset = cmd->rbytes_done; + cmd->sg_idx = offset / PAGE_SIZE; + sg_offset = offset % PAGE_SIZE; +- if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) ++ return -EPROTO; ++ + sg = &cmd->req.sg[cmd->sg_idx]; + sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; + + while (length) { +- if (!sg_remaining) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } +- if (!sg->length || sg->length <= sg_offset) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!sg_remaining) ++ return -EPROTO; ++ ++ if (!sg->length || sg->length <= sg_offset) ++ return -EPROTO; ++ + u32 iov_len = min_t(u32, length, sg->length - sg_offset); + + bvec_set_page(iov, sg_page(sg), iov_len, +@@ -351,6 +348,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + + iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, + nr_pages, cmd->pdu_len); ++ return 0; + } + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) +@@ -906,7 +904,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) + return 0; + } + +-static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, ++static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) + { + size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); +@@ -922,19 +920,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + if (!nvme_is_write(cmd->req.cmd) || !data_len || + data_len > cmd->req.port->inline_data_size) { + nvmet_prepare_receive_pdu(queue); +- return; ++ return 0; + } + + ret = nvmet_tcp_map_data(cmd); + if (unlikely(ret)) { + pr_err("queue %d: failed to map data\n", queue->idx); + nvmet_tcp_fatal_error(queue); +- return; ++ return -EPROTO; + } + + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(cmd); + cmd->flags |= NVMET_TCP_F_INIT_FAILED; ++ ret = nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ ++ return ret; + } + + static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) +@@ -986,7 +988,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) + goto err_proto; + } + cmd->pdu_recv = 0; +- nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) { ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ goto err_proto; ++ } + queue->cmd = cmd; + queue->rcv_state = NVMET_TCP_RECV_DATA; + +@@ -1049,8 +1054,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + req->cmd->common.opcode, + le32_to_cpu(req->cmd->common.dptr.sgl.length)); + +- nvmet_tcp_handle_req_failure(queue, queue->cmd, req); +- return 0; ++ return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); + } + + ret = nvmet_tcp_map_data(queue->cmd); +@@ -1067,8 +1071,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + if (nvmet_tcp_need_data_in(queue->cmd)) { + if (nvmet_tcp_has_inline_data(queue->cmd)) { + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(queue->cmd); +- return 0; ++ ret = nvmet_tcp_build_pdu_iovec(queue->cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", ++ queue->idx); ++ return ret; + } + /* send back R2T */ + nvmet_tcp_queue_response(&queue->cmd->req); +-- +2.53.0 + diff --git a/queue-6.1/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch b/queue-6.1/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch new file mode 100644 index 0000000000..856c6012fa --- /dev/null +++ b/queue-6.1/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch @@ -0,0 +1,48 @@ +From de6ef168975aaeae2f516f7a058ef378a3fd2686 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:09 +0800 +Subject: ocfs2/dlm: fix off-by-one in dlm_match_regions() region comparison + +From: Junrui Luo + +[ Upstream commit 01b61e8dda9b0fdb0d4cda43de25f4e390554d7b ] + +The local-vs-remote region comparison loop uses '<=' instead of '<', +causing it to read one entry past the valid range of qr_regions. The +other loops in the same function correctly use '<'. + +Fix the loop condition to use '<' for consistency and correctness. + +Link: https://lkml.kernel.org/r/SYBPR01MB78813DA26B50EC5E01F00566AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index dff3d2a48b608..3cd86b5de10f3 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1002,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + for (i = 0; i < localnr; ++i) { + foundit = 0; + r = remote; +- for (j = 0; j <= qr->qr_numregions; ++j) { ++ for (j = 0; j < qr->qr_numregions; ++j) { + if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { + foundit = 1; + break; +-- +2.53.0 + diff --git a/queue-6.1/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch b/queue-6.1/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch new file mode 100644 index 0000000000..f3c74284fc --- /dev/null +++ b/queue-6.1/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch @@ -0,0 +1,75 @@ +From 7edd9c6c93fb22e82ed16542f71f724e5e3902f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:08 +0800 +Subject: ocfs2/dlm: validate qr_numregions in dlm_match_regions() + +From: Junrui Luo + +[ Upstream commit 7ab3fbb01bc6d79091bc375e5235d360cd9b78be ] + +Patch series "ocfs2/dlm: fix two bugs in dlm_match_regions()". + +In dlm_match_regions(), the qr_numregions field from a DLM_QUERY_REGION +network message is used to drive loops over the qr_regions buffer without +sufficient validation. This series fixes two issues: + +- Patch 1 adds a bounds check to reject messages where qr_numregions + exceeds O2NM_MAX_REGIONS. The o2net layer only validates message + byte length; it does not constrain field values, so a crafted message + can set qr_numregions up to 255 and trigger out-of-bounds reads past + the 1024-byte qr_regions buffer. + +- Patch 2 fixes an off-by-one in the local-vs-remote comparison loop, + which uses '<=' instead of '<', reading one entry past the valid range + even when qr_numregions is within bounds. + +This patch (of 2): + +The qr_numregions field from a DLM_QUERY_REGION network message is used +directly as loop bounds in dlm_match_regions() without checking against +O2NM_MAX_REGIONS. Since qr_regions is sized for at most O2NM_MAX_REGIONS +(32) entries, a crafted message with qr_numregions > 32 causes +out-of-bounds reads past the qr_regions buffer. + +Add a bounds check for qr_numregions before entering the loops. + +Link: https://lkml.kernel.org/r/SYBPR01MB7881A334D02ACEE5E0645801AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Link: https://lkml.kernel.org/r/SYBPR01MB788166F524AD04E262E174BEAF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index c4eccd499db8a..dff3d2a48b608 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + goto bail; + } + ++ if (qr->qr_numregions > O2NM_MAX_REGIONS) { ++ mlog(ML_ERROR, "Domain %s: Joining node %d has invalid " ++ "number of heartbeat regions %u\n", ++ qr->qr_domain, qr->qr_node, qr->qr_numregions); ++ status = -EINVAL; ++ goto bail; ++ } ++ + r = remote; + for (i = 0; i < qr->qr_numregions; ++i) { + mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); +-- +2.53.0 + diff --git a/queue-6.1/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch b/queue-6.1/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch new file mode 100644 index 0000000000..da22e073fd --- /dev/null +++ b/queue-6.1/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch @@ -0,0 +1,89 @@ +From d17cb98cf0c90e82e522ab2b81f1eebd441213b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 12:03:39 +0800 +Subject: ocfs2: fix listxattr handling when the buffer is full + +From: ZhengYuan Huang + +[ Upstream commit d12f558e6200b3f47dbef9331ed6d115d2410e59 ] + +[BUG] +If an OCFS2 inode has both inline and block-based xattrs, listxattr() +can return a size larger than the caller's buffer when the inline names +consume that buffer exactly. + +kernel BUG at mm/usercopy.c:102! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:usercopy_abort+0xb7/0xd0 mm/usercopy.c:102 +Call Trace: + __check_heap_object+0xe3/0x120 mm/slub.c:8243 + check_heap_object mm/usercopy.c:196 [inline] + __check_object_size mm/usercopy.c:250 [inline] + __check_object_size+0x5c5/0x780 mm/usercopy.c:215 + check_object_size include/linux/ucopysize.h:22 [inline] + check_copy_size include/linux/ucopysize.h:59 [inline] + copy_to_user include/linux/uaccess.h:219 [inline] + listxattr+0xb0/0x170 fs/xattr.c:926 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x137/0x320 fs/xattr.c:988 + __do_sys_listxattr fs/xattr.c:1001 [inline] + __se_sys_listxattr fs/xattr.c:998 [inline] + __x64_sys_listxattr+0x7f/0xd0 fs/xattr.c:998 + ... + +[CAUSE] +Commit 936b8834366e ("ocfs2: Refactor xattr list and remove +ocfs2_xattr_handler().") replaced the old per-handler list accounting +with ocfs2_xattr_list_entry(), but it kept using size == 0 to detect +probe mode. + +That assumption stops being true once ocfs2_listxattr() finishes the +inline-xattr pass. If the inline names fill the caller buffer exactly, +the block-xattr pass runs with a non-NULL buffer and a remaining size of +zero. ocfs2_xattr_list_entry() then skips the bounds check, keeps +counting block names, and returns a positive size larger than the +supplied buffer. + +[FIX] +Detect probe mode by testing whether the destination buffer pointer is +NULL instead of whether the remaining size is zero. + +That restores the pre-refactor behavior and matches the OCFS2 getxattr +helpers. Once the remaining buffer reaches zero while more names are +left, the block-xattr pass now returns -ERANGE instead of reporting a +size larger than the allocated list buffer. + +Link: https://lkml.kernel.org/r/20260410040339.3837162-1-gality369@gmail.com +Fixes: 936b8834366e ("ocfs2: Refactor xattr list and remove ocfs2_xattr_handler().") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 7ac7cb6117d4f..1f22ad21ae608 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -911,8 +911,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb, + total_len = prefix_len + name_len + 1; + *result += total_len; + +- /* we are just looking for how big our buffer needs to be */ +- if (!size) ++ /* No buffer means we are only looking for the required size. */ ++ if (!buffer) + return 0; + + if (*result > size) +-- +2.53.0 + diff --git a/queue-6.1/ocfs2-validate-bg_bits-during-freefrag-scan.patch b/queue-6.1/ocfs2-validate-bg_bits-during-freefrag-scan.patch new file mode 100644 index 0000000000..404c105ab9 --- /dev/null +++ b/queue-6.1/ocfs2-validate-bg_bits-during-freefrag-scan.patch @@ -0,0 +1,121 @@ +From 8036fc99f3dcaa26fe2b0292528214820b6bd238 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:42:20 +0800 +Subject: ocfs2: validate bg_bits during freefrag scan + +From: ZhengYuan Huang + +[ Upstream commit 8f687eeed3da3012152b0f9473f578869de0cd7b ] + +[BUG] +A crafted filesystem can trigger an out-of-bounds bitmap walk when +OCFS2_IOC_INFO is issued with OCFS2_INFO_FL_NON_COHERENT. + +BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:68 [inline] +BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] +BUG: KASAN: use-after-free in test_bit_le include/asm-generic/bitops/le.h:21 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 +Read of size 8 at addr ffff888031bce000 by task syz.0.636/1435 +Call Trace: + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xd1/0x650 mm/kasan/report.c:482 + kasan_report+0xfb/0x140 mm/kasan/report.c:595 + check_region_inline mm/kasan/generic.c:186 [inline] + kasan_check_range+0x11c/0x200 mm/kasan/generic.c:200 + __kasan_check_read+0x11/0x20 mm/kasan/shadow.c:31 + instrument_atomic_read include/linux/instrumented.h:68 [inline] + _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] + test_bit_le include/asm-generic/bitops/le.h:21 [inline] + ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] + ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] + ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] + ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 + ocfs2_info_handle+0x18d/0x2a0 fs/ocfs2/ioctl.c:828 + ocfs2_ioctl+0x632/0x6e0 fs/ocfs2/ioctl.c:913 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + ... + +[CAUSE] +ocfs2_info_freefrag_scan_chain() uses on-disk bg_bits directly as the +bitmap scan limit. The coherent path reads group descriptors through +ocfs2_read_group_descriptor(), which validates the descriptor before +use. The non-coherent path uses ocfs2_read_blocks_sync() instead and +skips that validation, so an impossible bg_bits value can drive the +bitmap walk past the end of the block. + +[FIX] +Compute the bitmap capacity from the filesystem format with +ocfs2_group_bitmap_size(), report descriptors whose bg_bits exceeds +that limit, and clamp the scan to the computed capacity. This keeps the +freefrag report going while avoiding reads beyond the buffer. + +Link: https://lkml.kernel.org/r/20260410034220.3825769-1-gality369@gmail.com +Fixes: d24a10b9f8ed ("Ocfs2: Add a new code 'OCFS2_INFO_FREEFRAG' for o2info ioctl.") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Heming Zhao +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/ioctl.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c +index afd54ec661030..84fb4bc33db9e 100644 +--- a/fs/ocfs2/ioctl.c ++++ b/fs/ocfs2/ioctl.c +@@ -442,13 +442,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + struct buffer_head *bh = NULL; + struct ocfs2_group_desc *bg = NULL; + +- unsigned int max_bits, num_clusters; ++ unsigned int max_bits, max_bitmap_bits, num_clusters; + unsigned int offset = 0, cluster, chunk; + unsigned int chunk_free, last_chunksize = 0; + + if (!le32_to_cpu(rec->c_free)) + goto bail; + ++ max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0, ++ osb->s_feature_incompat); ++ + do { + if (!bg) + blkno = le64_to_cpu(rec->c_blkno); +@@ -480,6 +483,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + continue; + + max_bits = le16_to_cpu(bg->bg_bits); ++ ++ /* ++ * Non-coherent scans read raw blocks and do not get the ++ * bg_bits validation from ++ * ocfs2_read_group_descriptor(). ++ */ ++ if (max_bits > max_bitmap_bits) { ++ mlog(ML_ERROR, ++ "Group desc #%llu has %u bits, max bitmap bits %u\n", ++ (unsigned long long)blkno, max_bits, max_bitmap_bits); ++ max_bits = max_bitmap_bits; ++ } ++ + offset = 0; + + for (chunk = 0; chunk < chunks_in_group; chunk++) { +-- +2.53.0 + diff --git a/queue-6.1/ocfs2-validate-group-add-input-before-caching.patch b/queue-6.1/ocfs2-validate-group-add-input-before-caching.patch new file mode 100644 index 0000000000..f33eb024ea --- /dev/null +++ b/queue-6.1/ocfs2-validate-group-add-input-before-caching.patch @@ -0,0 +1,110 @@ +From 03fb12fbb0b7cb11e8ebc534a9c754e2f39d2060 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 10:02:08 +0800 +Subject: ocfs2: validate group add input before caching + +From: ZhengYuan Huang + +[ Upstream commit 70b672833f4025341c11b22c7f83778a5cd611bc ] + +[BUG] +OCFS2_IOC_GROUP_ADD can trigger a BUG_ON in +ocfs2_set_new_buffer_uptodate(): + +kernel BUG at fs/ocfs2/uptodate.c:509! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:ocfs2_set_new_buffer_uptodate+0x194/0x1e0 fs/ocfs2/uptodate.c:509 +Code: ffffe88f 42b9fe4c 89e64889 dfe8b4df +Call Trace: + ocfs2_group_add+0x3f1/0x1510 fs/ocfs2/resize.c:507 + ocfs2_ioctl+0x309/0x6e0 fs/ocfs2/ioctl.c:887 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + x64_sys_call+0x1144/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:17 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e +RIP: 0033:0x7bbfb55a966d + +[CAUSE] +ocfs2_group_add() calls ocfs2_set_new_buffer_uptodate() on a +user-controlled group block before ocfs2_verify_group_and_input() +validates that block number. That helper is only valid for newly +allocated metadata and asserts that the block is not already present in +the chosen metadata cache. The code also uses INODE_CACHE(inode) even +though the group descriptor belongs to main_bm_inode and later journal +accesses use that cache context instead. + +[FIX] +Validate the on-disk group descriptor before caching it, then add it to +the metadata cache tracked by INODE_CACHE(main_bm_inode). Keep the +validation failure path separate from the later cleanup path so we only +remove the buffer from that cache after it has actually been inserted. +This keeps the group buffer lifetime consistent across validation, +journaling, and cleanup. + +Link: https://lkml.kernel.org/r/20260410020209.3786348-1-gality369@gmail.com +Fixes: 7909f2bf8353 ("[PATCH 2/2] ocfs2: Implement group add for online resize") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/resize.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c +index 42c0d314f95e8..acf2769f4c8c7 100644 +--- a/fs/ocfs2/resize.c ++++ b/fs/ocfs2/resize.c +@@ -500,14 +500,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + goto out_unlock; + } + +- ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); +- + ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); + if (ret) { + mlog_errno(ret); + goto out_free_group_bh; + } + ++ ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh); ++ + trace_ocfs2_group_add((unsigned long long)input->group, + input->chain, input->clusters, input->frees); + +@@ -515,7 +515,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + if (IS_ERR(handle)) { + mlog_errno(PTR_ERR(handle)); + ret = -EINVAL; +- goto out_free_group_bh; ++ goto out_remove_cache; + } + + cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); +@@ -569,9 +569,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + out_commit: + ocfs2_commit_trans(osb, handle); + +-out_free_group_bh: ++out_remove_cache: + if (ret < 0) +- ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); ++ ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh); ++ ++out_free_group_bh: + brelse(group_bh); + + out_unlock: +-- +2.53.0 + diff --git a/queue-6.1/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch b/queue-6.1/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch new file mode 100644 index 0000000000..cebb3e4e33 --- /dev/null +++ b/queue-6.1/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch @@ -0,0 +1,132 @@ +From e0505a23a148414e14a569288f0b921b3adf1f68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 19:46:54 -0700 +Subject: openvswitch: cap upcall PID array size and pre-size vport replies + +From: Weiming Shi + +[ Upstream commit 2091c6aa0df6aba47deb5c8ab232b1cb60af3519 ] + +The vport netlink reply helpers allocate a fixed-size skb with +nlmsg_new(NLMSG_DEFAULT_SIZE, ...) but serialize the full upcall PID +array via ovs_vport_get_upcall_portids(). Since +ovs_vport_set_upcall_portids() accepts any non-zero multiple of +sizeof(u32) with no upper bound, a CAP_NET_ADMIN user can install a PID +array large enough to overflow the reply buffer, causing nla_put() to +fail with -EMSGSIZE and hitting BUG_ON(err < 0). On systems with +unprivileged user namespaces enabled (e.g., Ubuntu default), this is +reachable via unshare -Urn since OVS vport mutation operations use +GENL_UNS_ADMIN_PERM. + + kernel BUG at net/openvswitch/datapath.c:2414! + Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI + CPU: 1 UID: 0 PID: 65 Comm: poc Not tainted 7.0.0-rc7-00195-geb216e422044 #1 + RIP: 0010:ovs_vport_cmd_set+0x34c/0x400 + Call Trace: + + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1116) + genl_rcv_msg (net/netlink/genetlink.c:1194) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + genl_rcv (net/netlink/genetlink.c:1219) + netlink_unicast (net/netlink/af_netlink.c:1344) + netlink_sendmsg (net/netlink/af_netlink.c:1894) + __sys_sendto (net/socket.c:2206) + __x64_sys_sendto (net/socket.c:2209) + do_syscall_64 (arch/x86/entry/syscall_64.c:63) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + + Kernel panic - not syncing: Fatal exception + +Reject attempts to set more PIDs than nr_cpu_ids in +ovs_vport_set_upcall_portids(), and pre-compute the worst-case reply +size in ovs_vport_cmd_msg_size() based on that bound, similar to the +existing ovs_dp_cmd_msg_size(). nr_cpu_ids matches the cap already +used by the per-CPU dispatch configuration on the datapath side +(ovs_dp_cmd_fill_info() serialises at most nr_cpu_ids PIDs), so the +two sides stay consistent. + +Fixes: 5cd667b0a456 ("openvswitch: Allow each vport to have an array of 'port_id's.") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Weiming Shi +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260416024653.153456-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 35 +++++++++++++++++++++++++++++++++-- + net/openvswitch/vport.c | 3 +++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index a2d8b1b4c83e5..c751d6b36febd 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -2128,9 +2128,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + return err; + } + ++static size_t ovs_vport_cmd_msg_size(void) ++{ ++ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); ++ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */ ++ msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */ ++ msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */ ++ ++ /* OVS_VPORT_ATTR_STATS */ ++ msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats)); ++ ++ /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + ++ * OVS_VPORT_UPCALL_ATTR_FAIL) ++ */ ++ msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) + ++ nla_total_size_64bit(sizeof(u64))); ++ ++ /* OVS_VPORT_ATTR_UPCALL_PID */ ++ msgsize += nla_total_size(nr_cpu_ids * sizeof(u32)); ++ ++ /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + ++ * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) ++ */ ++ msgsize += nla_total_size(nla_total_size(sizeof(u16)) + ++ nla_total_size(nla_total_size(0))); ++ ++ return msgsize; ++} ++ + static struct sk_buff *ovs_vport_cmd_alloc_info(void) + { +- return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL); + } + + /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ +@@ -2140,7 +2171,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, + struct sk_buff *skb; + int retval; + +- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ skb = ovs_vport_cmd_alloc_info(); + if (!skb) + return ERR_PTR(-ENOMEM); + +diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c +index 82a74f9989667..5d7af559a20be 100644 +--- a/net/openvswitch/vport.c ++++ b/net/openvswitch/vport.c +@@ -342,6 +342,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids) + if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) + return -EINVAL; + ++ if (nla_len(ids) / sizeof(u32) > nr_cpu_ids) ++ return -EINVAL; ++ + old = ovsl_dereference(vport->upcall_portids); + + vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), +-- +2.53.0 + diff --git a/queue-6.1/padata-put-cpu-offline-callback-in-online-section-to.patch b/queue-6.1/padata-put-cpu-offline-callback-in-online-section-to.patch new file mode 100644 index 0000000000..23425ecdd5 --- /dev/null +++ b/queue-6.1/padata-put-cpu-offline-callback-in-online-section-to.patch @@ -0,0 +1,372 @@ +From e0143e8829a92d58bb950571d00b4c8a15ab09c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 11:24:33 -0400 +Subject: padata: Put CPU offline callback in ONLINE section to allow failure + +From: Daniel Jordan + +[ Upstream commit c8c4a2972f83c8b68ff03b43cecdb898939ff851 ] + +syzbot reported the following warning: + + DEAD callback error for CPU1 + WARNING: kernel/cpu.c:1463 at _cpu_down+0x759/0x1020 kernel/cpu.c:1463, CPU#0: syz.0.1960/14614 + +at commit 4ae12d8bd9a8 ("Merge tag 'kbuild-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux") +which tglx traced to padata_cpu_dead() given it's the only +sub-CPUHP_TEARDOWN_CPU callback that returns an error. + +Failure isn't allowed in hotplug states before CPUHP_TEARDOWN_CPU +so move the CPU offline callback to the ONLINE section where failure is +possible. + +Fixes: 894c9ef9780c ("padata: validate cpumask without removed CPU during offline") +Reported-by: syzbot+123e1b70473ce213f3af@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69af0a05.050a0220.310d8.002f.GAE@google.com/ +Debugged-by: Thomas Gleixner +Signed-off-by: Daniel Jordan +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + include/linux/cpuhotplug.h | 1 - + include/linux/padata.h | 8 +-- + kernel/padata.c | 120 +++++++++++++++++++------------------ + 3 files changed, 65 insertions(+), 64 deletions(-) + +diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h +index 67575bc8a7e29..762b88e1703c8 100644 +--- a/include/linux/cpuhotplug.h ++++ b/include/linux/cpuhotplug.h +@@ -98,7 +98,6 @@ enum cpuhp_state { + CPUHP_IOMMU_IOVA_DEAD, + CPUHP_LUSTRE_CFS_DEAD, + CPUHP_AP_ARM_CACHE_B15_RAC_DEAD, +- CPUHP_PADATA_DEAD, + CPUHP_AP_DTPM_CPU_DEAD, + CPUHP_RANDOM_PREPARE, + CPUHP_WORKQUEUE_PREP, +diff --git a/include/linux/padata.h b/include/linux/padata.h +index 6f07e12a43819..72f5899cc7a95 100644 +--- a/include/linux/padata.h ++++ b/include/linux/padata.h +@@ -147,23 +147,23 @@ struct padata_mt_job { + /** + * struct padata_instance - The overall control structure. + * +- * @cpu_online_node: Linkage for CPU online callback. +- * @cpu_dead_node: Linkage for CPU offline callback. ++ * @cpuhp_node: Linkage for CPU hotplug callbacks. + * @parallel_wq: The workqueue used for parallel work. + * @serial_wq: The workqueue used for serial work. + * @pslist: List of padata_shell objects attached to this instance. + * @cpumask: User supplied cpumasks for parallel and serial works. ++ * @validate_cpumask: Internal cpumask used to validate @cpumask during hotplug. + * @kobj: padata instance kernel object. + * @lock: padata instance lock. + * @flags: padata flags. + */ + struct padata_instance { +- struct hlist_node cpu_online_node; +- struct hlist_node cpu_dead_node; ++ struct hlist_node cpuhp_node; + struct workqueue_struct *parallel_wq; + struct workqueue_struct *serial_wq; + struct list_head pslist; + struct padata_cpumask cpumask; ++ cpumask_var_t validate_cpumask; + struct kobject kobj; + struct mutex lock; + u8 flags; +diff --git a/kernel/padata.c b/kernel/padata.c +index d4298c0c747ce..e62e10e9cfea5 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -540,7 +540,8 @@ static void padata_init_reorder_list(struct parallel_data *pd) + } + + /* Allocate and initialize the internal cpumask dependend resources. */ +-static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) ++static struct parallel_data *padata_alloc_pd(struct padata_shell *ps, ++ int offlining_cpu) + { + struct padata_instance *pinst = ps->pinst; + struct parallel_data *pd; +@@ -566,6 +567,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) + + cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask); + cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask); ++ if (offlining_cpu >= 0) { ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.pcpu); ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.cbcpu); ++ } + + padata_init_reorder_list(pd); + padata_init_squeues(pd); +@@ -612,11 +617,11 @@ static void __padata_stop(struct padata_instance *pinst) + } + + /* Replace the internal control structure with a new one. */ +-static int padata_replace_one(struct padata_shell *ps) ++static int padata_replace_one(struct padata_shell *ps, int offlining_cpu) + { + struct parallel_data *pd_new; + +- pd_new = padata_alloc_pd(ps); ++ pd_new = padata_alloc_pd(ps, offlining_cpu); + if (!pd_new) + return -ENOMEM; + +@@ -626,7 +631,7 @@ static int padata_replace_one(struct padata_shell *ps) + return 0; + } + +-static int padata_replace(struct padata_instance *pinst) ++static int padata_replace(struct padata_instance *pinst, int offlining_cpu) + { + struct padata_shell *ps; + int err = 0; +@@ -634,7 +639,7 @@ static int padata_replace(struct padata_instance *pinst) + pinst->flags |= PADATA_RESET; + + list_for_each_entry(ps, &pinst->pslist, list) { +- err = padata_replace_one(ps); ++ err = padata_replace_one(ps, offlining_cpu); + if (err) + break; + } +@@ -651,9 +656,21 @@ static int padata_replace(struct padata_instance *pinst) + + /* If cpumask contains no active cpu, we mark the instance as invalid. */ + static bool padata_validate_cpumask(struct padata_instance *pinst, +- const struct cpumask *cpumask) ++ const struct cpumask *cpumask, ++ int offlining_cpu) + { +- if (!cpumask_intersects(cpumask, cpu_online_mask)) { ++ cpumask_copy(pinst->validate_cpumask, cpu_online_mask); ++ ++ /* ++ * @offlining_cpu is still in cpu_online_mask, so remove it here for ++ * validation. Using a sub-CPUHP_TEARDOWN_CPU hotplug state where ++ * @offlining_cpu wouldn't be in the online mask doesn't work because ++ * padata_cpu_offline() can fail but such a state doesn't allow failure. ++ */ ++ if (offlining_cpu >= 0) ++ __cpumask_clear_cpu(offlining_cpu, pinst->validate_cpumask); ++ ++ if (!cpumask_intersects(cpumask, pinst->validate_cpumask)) { + pinst->flags |= PADATA_INVALID; + return false; + } +@@ -669,13 +686,13 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + int valid; + int err; + +- valid = padata_validate_cpumask(pinst, pcpumask); ++ valid = padata_validate_cpumask(pinst, pcpumask, -1); + if (!valid) { + __padata_stop(pinst); + goto out_replace; + } + +- valid = padata_validate_cpumask(pinst, cbcpumask); ++ valid = padata_validate_cpumask(pinst, cbcpumask, -1); + if (!valid) + __padata_stop(pinst); + +@@ -683,7 +700,7 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + cpumask_copy(pinst->cpumask.pcpu, pcpumask); + cpumask_copy(pinst->cpumask.cbcpu, cbcpumask); + +- err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst); ++ err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst, -1); + + if (valid) + __padata_start(pinst); +@@ -735,26 +752,6 @@ EXPORT_SYMBOL(padata_set_cpumask); + + #ifdef CONFIG_HOTPLUG_CPU + +-static int __padata_add_cpu(struct padata_instance *pinst, int cpu) +-{ +- int err = padata_replace(pinst); +- +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- +- return err; +-} +- +-static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) +-{ +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- return padata_replace(pinst); +-} +- + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) + { + return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) || +@@ -766,27 +763,39 @@ static int padata_cpu_online(unsigned int cpu, struct hlist_node *node) + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_add_cpu(pinst, cpu); ++ ++ ret = padata_replace(pinst, -1); ++ ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu, -1) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, -1)) ++ __padata_start(pinst); ++ + mutex_unlock(&pinst->lock); + return ret; + } + +-static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node) ++static int padata_cpu_offline(unsigned int cpu, struct hlist_node *node) + { + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_remove_cpu(pinst, cpu); ++ ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu, cpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, cpu)) ++ __padata_stop(pinst); ++ ++ ret = padata_replace(pinst, cpu); ++ + mutex_unlock(&pinst->lock); + return ret; + } +@@ -797,15 +806,14 @@ static enum cpuhp_state hp_online; + static void __padata_free(struct padata_instance *pinst) + { + #ifdef CONFIG_HOTPLUG_CPU +- cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); +- cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node); ++ cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpuhp_node); + #endif + + WARN_ON(!list_empty(&pinst->pslist)); + + free_cpumask_var(pinst->cpumask.pcpu); + free_cpumask_var(pinst->cpumask.cbcpu); ++ free_cpumask_var(pinst->validate_cpumask); + destroy_workqueue(pinst->serial_wq); + destroy_workqueue(pinst->parallel_wq); + kfree(pinst); +@@ -965,10 +973,10 @@ struct padata_instance *padata_alloc(const char *name) + + if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL)) + goto err_free_serial_wq; +- if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) { +- free_cpumask_var(pinst->cpumask.pcpu); +- goto err_free_serial_wq; +- } ++ if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) ++ goto err_free_p_mask; ++ if (!alloc_cpumask_var(&pinst->validate_cpumask, GFP_KERNEL)) ++ goto err_free_cb_mask; + + INIT_LIST_HEAD(&pinst->pslist); + +@@ -976,7 +984,7 @@ struct padata_instance *padata_alloc(const char *name) + cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask); + + if (padata_setup_cpumasks(pinst)) +- goto err_free_masks; ++ goto err_free_v_mask; + + __padata_start(pinst); + +@@ -985,18 +993,19 @@ struct padata_instance *padata_alloc(const char *name) + + #ifdef CONFIG_HOTPLUG_CPU + cpuhp_state_add_instance_nocalls_cpuslocked(hp_online, +- &pinst->cpu_online_node); +- cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); ++ &pinst->cpuhp_node); + #endif + + cpus_read_unlock(); + + return pinst; + +-err_free_masks: +- free_cpumask_var(pinst->cpumask.pcpu); ++err_free_v_mask: ++ free_cpumask_var(pinst->validate_cpumask); ++err_free_cb_mask: + free_cpumask_var(pinst->cpumask.cbcpu); ++err_free_p_mask: ++ free_cpumask_var(pinst->cpumask.pcpu); + err_free_serial_wq: + destroy_workqueue(pinst->serial_wq); + err_put_cpus: +@@ -1039,7 +1048,7 @@ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst) + ps->pinst = pinst; + + cpus_read_lock(); +- pd = padata_alloc_pd(ps); ++ pd = padata_alloc_pd(ps, -1); + cpus_read_unlock(); + + if (!pd) +@@ -1088,32 +1097,25 @@ void __init padata_init(void) + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online", +- padata_cpu_online, NULL); ++ padata_cpu_online, padata_cpu_offline); + if (ret < 0) + goto err; + hp_online = ret; +- +- ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead", +- NULL, padata_cpu_dead); +- if (ret < 0) +- goto remove_online_state; + #endif + + possible_cpus = num_possible_cpus(); + padata_works = kmalloc_array(possible_cpus, sizeof(struct padata_work), + GFP_KERNEL); + if (!padata_works) +- goto remove_dead_state; ++ goto remove_online_state; + + for (i = 0; i < possible_cpus; ++i) + list_add(&padata_works[i].pw_list, &padata_free_works); + + return; + +-remove_dead_state: +-#ifdef CONFIG_HOTPLUG_CPU +- cpuhp_remove_multi_state(CPUHP_PADATA_DEAD); + remove_online_state: ++#ifdef CONFIG_HOTPLUG_CPU + cpuhp_remove_multi_state(hp_online); + err: + #endif +-- +2.53.0 + diff --git a/queue-6.1/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch b/queue-6.1/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch new file mode 100644 index 0000000000..80a6b3e0f8 --- /dev/null +++ b/queue-6.1/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch @@ -0,0 +1,79 @@ +From 5a6ea4977ab42fd0890b1654d9ab7d7f49a1e9ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 16:07:03 +0800 +Subject: padata: Remove cpu online check from cpu add and removal + +From: Chuyi Zhou + +[ Upstream commit 73117ea6470dca787f70f33c001f9faf437a1c0b ] + +During the CPU offline process, the dying CPU is cleared from the +cpu_online_mask in takedown_cpu(). After this step, various CPUHP_*_DEAD +callbacks are executed to perform cleanup jobs for the dead CPU, so this +cpu online check in padata_cpu_dead() is unnecessary. + +Similarly, when executing padata_cpu_online() during the +CPUHP_AP_ONLINE_DYN phase, the CPU has already been set in the +cpu_online_mask, the action even occurs earlier than the +CPUHP_AP_ONLINE_IDLE stage. + +Remove this unnecessary cpu online check in __padata_add_cpu() and +__padata_remove_cpu(). + +Signed-off-by: Chuyi Zhou +Acked-by: Daniel Jordan +Signed-off-by: Herbert Xu +Stable-dep-of: c8c4a2972f83 ("padata: Put CPU offline callback in ONLINE section to allow failure") +Signed-off-by: Sasha Levin +--- + kernel/padata.c | 26 ++++++++------------------ + 1 file changed, 8 insertions(+), 18 deletions(-) + +diff --git a/kernel/padata.c b/kernel/padata.c +index 93e288dc373ee..d4298c0c747ce 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -737,32 +737,22 @@ EXPORT_SYMBOL(padata_set_cpumask); + + static int __padata_add_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (cpumask_test_cpu(cpu, cpu_online_mask)) { +- err = padata_replace(pinst); ++ int err = padata_replace(pinst); + +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- } ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_start(pinst); + + return err; + } + + static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (!cpumask_test_cpu(cpu, cpu_online_mask)) { +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- err = padata_replace(pinst); +- } ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_stop(pinst); + +- return err; ++ return padata_replace(pinst); + } + + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) +-- +2.53.0 + diff --git a/queue-6.1/params-replace-__modinit-with-__init_or_module.patch b/queue-6.1/params-replace-__modinit-with-__init_or_module.patch new file mode 100644 index 0000000000..9c52a841ec --- /dev/null +++ b/queue-6.1/params-replace-__modinit-with-__init_or_module.patch @@ -0,0 +1,67 @@ +From 0f2af910bf60a90d0fe42f7d2e2034dd34993d81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Aug 2025 14:12:09 +0200 +Subject: params: Replace __modinit with __init_or_module + +From: Petr Pavlu + +[ Upstream commit 3cb0c3bdea5388519bc1bf575dca6421b133302b ] + +Remove the custom __modinit macro from kernel/params.c and instead use the +common __init_or_module macro from include/linux/module.h. Both provide the +same functionality. + +Signed-off-by: Petr Pavlu +Reviewed-by: Aaron Tomlin +Reviewed-by: Daniel Gomez +Reviewed-by: Sami Tolvanen +Signed-off-by: Sami Tolvanen +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + kernel/params.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +diff --git a/kernel/params.c b/kernel/params.c +index 587d9cdafd118..5ae507cd19960 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -592,12 +592,6 @@ static ssize_t param_attr_store(struct module_attribute *mattr, + } + #endif + +-#ifdef CONFIG_MODULES +-#define __modinit +-#else +-#define __modinit __init +-#endif +- + #ifdef CONFIG_SYSFS + void kernel_param_lock(struct module *mod) + { +@@ -622,9 +616,9 @@ EXPORT_SYMBOL(kernel_param_unlock); + * create file in sysfs. Returns an error on out of memory. Always cleans up + * if there's an error. + */ +-static __modinit int add_sysfs_param(struct module_kobject *mk, +- const struct kernel_param *kp, +- const char *name) ++static __init_or_module int add_sysfs_param(struct module_kobject *mk, ++ const struct kernel_param *kp, ++ const char *name) + { + struct module_param_attrs *new_mp; + struct attribute **new_attrs; +@@ -758,7 +752,8 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) ++struct module_kobject * __init_or_module ++lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +-- +2.53.0 + diff --git a/queue-6.1/pci-add-pcie_pme_to_l2_timeout_us-l2-ready-timeout-v.patch b/queue-6.1/pci-add-pcie_pme_to_l2_timeout_us-l2-ready-timeout-v.patch new file mode 100644 index 0000000000..619c2de480 --- /dev/null +++ b/queue-6.1/pci-add-pcie_pme_to_l2_timeout_us-l2-ready-timeout-v.patch @@ -0,0 +1,42 @@ +From 78a53b6ff93afb12fa64198ec5a84160c31549d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Aug 2023 14:48:13 -0400 +Subject: PCI: Add PCIE_PME_TO_L2_TIMEOUT_US L2 ready timeout value + +From: Frank Li + +[ Upstream commit e78bd50b4078b3b2d9f85d97796b7c271e7860ca ] + +Add the PCIE_PME_TO_L2_TIMEOUT_US macro to define the L2 ready timeout +as described in the PCI specifications. + +Link: https://lore.kernel.org/r/20230821184815.2167131-2-Frank.Li@nxp.com +Signed-off-by: Frank Li +Signed-off-by: Lorenzo Pieralisi +Acked-by: Manivannan Sadhasivam +Stable-dep-of: adaffed907f1 ("PCI: tegra194: Fix polling delay for L2 state") +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index 85488bc8e7795..8b177931cf21e 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -14,6 +14,12 @@ + #define PCI_EXP_AER_FLAGS (PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_NFERE | \ + PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE) + ++/* ++ * PCIe r6.0, sec 5.3.3.2.1 ++ * Recommends 1ms to 10ms timeout to check L2 ready. ++ */ ++#define PCIE_PME_TO_L2_TIMEOUT_US 10000 ++ + extern const unsigned char pcie_link_speed[]; + extern bool pci_early_dump; + +-- +2.53.0 + diff --git a/queue-6.1/pci-enable-atomicops-only-if-root-port-supports-them.patch b/queue-6.1/pci-enable-atomicops-only-if-root-port-supports-them.patch new file mode 100644 index 0000000000..924f19208a --- /dev/null +++ b/queue-6.1/pci-enable-atomicops-only-if-root-port-supports-them.patch @@ -0,0 +1,110 @@ +From f6ce893325afcc0ee357d62f4d3190a9e163bf60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:09:45 +0200 +Subject: PCI: Enable AtomicOps only if Root Port supports them + +From: Gerd Bayer + +[ Upstream commit 1ae8c4ce157037e266184064a182af9ef9af278b ] + +When inspecting the config space of a Connect-X physical function in an +s390 system after it was initialized by the mlx5_core device driver, we +found the function to be enabled to request AtomicOps despite the Root Port +lacking support for completing them: + + 00:00.1 Ethernet controller: Mellanox Technologies MT2894 Family [ConnectX-6 Lx] + Subsystem: Mellanox Technologies Device 0002 + DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- + AtomicOpsCtl: ReqEn+ + +On s390 and many virtualized guests, the Endpoint is visible but the Root +Port is not. In this case, pci_enable_atomic_ops_to_root() previously +enabled AtomicOps in the Endpoint even though it can't tell whether the +Root Port supports them as a completer. + +Change pci_enable_atomic_ops_to_root() to fail if there's no Root Port or +the Root Port doesn't support AtomicOps. + +Fixes: 430a23689dea ("PCI: Add pci_enable_atomic_ops_to_root()") +Reported-by: Alexander Schmidt +Signed-off-by: Gerd Bayer +[bhelgaas: commit log, check RP first to simplify flow] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260330-fix_pciatops-v7-2-f601818417e8@linux.ibm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 41 ++++++++++++++++++++--------------------- + 1 file changed, 20 insertions(+), 21 deletions(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 2cb94c77df780..953646cd759b0 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -3910,8 +3910,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) + */ + int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + { +- struct pci_bus *bus = dev->bus; +- struct pci_dev *bridge; ++ struct pci_dev *root, *bridge; + u32 cap, ctl2; + + /* +@@ -3941,35 +3940,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + return -EINVAL; + } + +- while (bus->parent) { +- bridge = bus->self; ++ root = pcie_find_root_port(dev); ++ if (!root) ++ return -EINVAL; + +- pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap); ++ pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); ++ if ((cap & cap_mask) != cap_mask) ++ return -EINVAL; + ++ bridge = pci_upstream_bridge(dev); ++ while (bridge != root) { + switch (pci_pcie_type(bridge)) { +- /* Ensure switch ports support AtomicOp routing */ + case PCI_EXP_TYPE_UPSTREAM: +- case PCI_EXP_TYPE_DOWNSTREAM: +- if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) +- return -EINVAL; +- break; +- +- /* Ensure root port supports all the sizes we care about */ +- case PCI_EXP_TYPE_ROOT_PORT: +- if ((cap & cap_mask) != cap_mask) +- return -EINVAL; +- break; +- } +- +- /* Ensure upstream ports don't block AtomicOps on egress */ +- if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) { ++ /* Upstream ports must not block AtomicOps on egress */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, + &ctl2); + if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK) + return -EINVAL; ++ fallthrough; ++ ++ /* All switch ports need to route AtomicOps */ ++ case PCI_EXP_TYPE_DOWNSTREAM: ++ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, ++ &cap); ++ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) ++ return -EINVAL; ++ break; + } + +- bus = bus->parent; ++ bridge = pci_upstream_bridge(bridge); + } + + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, +-- +2.53.0 + diff --git a/queue-6.1/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch b/queue-6.1/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch new file mode 100644 index 0000000000..e44ec3c0fb --- /dev/null +++ b/queue-6.1/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch @@ -0,0 +1,55 @@ +From 69079c84260297d52d296d8bc726b9120c2ef0ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 17:35:41 +0800 +Subject: PCI: mediatek-gen3: Prevent leaking IRQ domains when IRQ not found + +From: Chen-Yu Tsai + +[ Upstream commit 5573c44cb3fd01a9f62d569ae9ac870ef5f0e0ba ] + +In mtk_pcie_setup_irq(), the IRQ domains are allocated before the +controller's IRQ is fetched. If the latter fails, the function +directly returns an error, without cleaning up the allocated domains. + +Hence, reverse the order so that the IRQ domains are allocated after the +controller's IRQ is found. + +This was flagged by Sashiko during a review of "[PATCH v6 0/7] PCI: +mediatek-gen3: add power control support". + +Fixes: 814cceebba9b ("PCI: mediatek-gen3: Add INTx support") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Manivannan Sadhasivam +Link: https://sashiko.dev/#/patchset/20260324052002.4072430-1-wenst%40chromium.org +Link: https://patch.msgid.link/20260324093542.18523-1-wenst@chromium.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek-gen3.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c +index 40c38ca5a42e2..b7d87827b5f23 100644 +--- a/drivers/pci/controller/pcie-mediatek-gen3.c ++++ b/drivers/pci/controller/pcie-mediatek-gen3.c +@@ -760,14 +760,14 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie) + struct platform_device *pdev = to_platform_device(dev); + int err; + +- err = mtk_pcie_init_irq_domains(pcie); +- if (err) +- return err; +- + pcie->irq = platform_get_irq(pdev, 0); + if (pcie->irq < 0) + return pcie->irq; + ++ err = mtk_pcie_init_irq_domains(pcie); ++ if (err) ++ return err; ++ + irq_set_chained_handler_and_data(pcie->irq, mtk_pcie_irq_handler, pcie); + + return 0; +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch b/queue-6.1/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch new file mode 100644 index 0000000000..764ff913a9 --- /dev/null +++ b/queue-6.1/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch @@ -0,0 +1,108 @@ +From 94a6e44aefb05901d1bbe3462559d9c6e8acb3bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:50 +0530 +Subject: PCI: tegra194: Allow system suspend when the Endpoint link is not up + +From: Vidya Sagar + +[ Upstream commit c76f8eae7d4695b1176c4ea5eb93c17e16a20272 ] + +Host software initiates the L2 sequence. PCIe link is kept in L2 state +during suspend. If Endpoint mode is enabled and the link is up, the +software cannot proceed with suspend. However, when the PCIe Endpoint +driver is probed, but the PCIe link is not up, Tegra can go into suspend +state. So, allow system to suspend in this case. + +Fixes: de2bbf2b71bb ("PCI: tegra194: Don't allow suspend when Tegra PCIe is in EP mode") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-10-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 31 +++++++++++++++++----- + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 431ae321ba055..076d44c7c46ba 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2287,16 +2287,28 @@ static int tegra_pcie_dw_remove(struct platform_device *pdev) + return 0; + } + +-static int tegra_pcie_dw_suspend_late(struct device *dev) ++static int tegra_pcie_dw_suspend(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); +- u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n"); +- return -EPERM; ++ if (pcie->ep_state == EP_STATE_ENABLED) { ++ dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n"); ++ return -EPERM; ++ } ++ ++ disable_irq(pcie->pex_rst_irq); ++ return 0; + } + ++ return 0; ++} ++ ++static int tegra_pcie_dw_suspend_late(struct device *dev) ++{ ++ struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); ++ u32 val; ++ + if (!pcie->link_state) + return 0; + +@@ -2316,6 +2328,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2330,6 +2345,9 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + int ret; + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2362,8 +2380,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev) + u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Suspend is not supported in EP mode"); +- return -ENOTSUPP; ++ enable_irq(pcie->pex_rst_irq); ++ return 0; + } + + if (!pcie->link_state) +@@ -2468,6 +2486,7 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = { + }; + + static const struct dev_pm_ops tegra_pcie_dw_pm_ops = { ++ .suspend = tegra_pcie_dw_suspend, + .suspend_late = tegra_pcie_dw_suspend_late, + .suspend_noirq = tegra_pcie_dw_suspend_noirq, + .resume_noirq = tegra_pcie_dw_resume_noirq, +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-disable-direct-speed-change-for-endpoin.patch b/queue-6.1/pci-tegra194-disable-direct-speed-change-for-endpoin.patch new file mode 100644 index 0000000000..92bd9b8a38 --- /dev/null +++ b/queue-6.1/pci-tegra194-disable-direct-speed-change-for-endpoin.patch @@ -0,0 +1,52 @@ +From 50ece3735c48d73607c2d742265c7b6f477f13e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:48 +0530 +Subject: PCI: tegra194: Disable direct speed change for Endpoint mode + +From: Vidya Sagar + +[ Upstream commit 976f6763f57970388bcd7118931f33f447916927 ] + +Pre-silicon simulation showed the controller operating in Endpoint mode +initiating link speed change after completing Secondary Bus Reset. Ideally, +the Root Port or the Switch Downstream Port should initiate the link speed +change post SBR, not the Endpoint. + +So, as per the hardware team recommendation, disable direct speed change +for the Endpoint mode to prevent it from initiating speed change after the +physical layer link is up at Gen1, leaving speed change ownership with the +host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-8-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 87851a56ebd2d..431ae321ba055 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1825,6 +1825,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); ++ val &= ~PORT_LOGIC_SPEED_CHANGE; ++ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); ++ + if (pcie->update_fc_fixup) { + val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); + val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-disable-ltssm-after-transition-to-detec.patch b/queue-6.1/pci-tegra194-disable-ltssm-after-transition-to-detec.patch new file mode 100644 index 0000000000..391c910795 --- /dev/null +++ b/queue-6.1/pci-tegra194-disable-ltssm-after-transition-to-detec.patch @@ -0,0 +1,92 @@ +From 04a09934b393542f8448c08efae16bf9d91a499f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:44 +0530 +Subject: PCI: tegra194: Disable LTSSM after transition to Detect on surprise + link down + +From: Manikanta Maddireddy + +[ Upstream commit 9fa0c242f8d7acf1b124d4462d18f4023573ac1c ] + +After the link reaches a Detect-related LTSSM state, disable LTSSM so it +does not keep toggling between Polling and Detect. Do this by polling for +the Detect state first, then clearing APPL_CTRL_LTSSM_EN in both +tegra_pcie_dw_pme_turnoff() and pex_ep_event_pex_rst_assert(). + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-4-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 29 ++++++++++++---------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index f502b925d486b..b6899d1f80fb5 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1610,14 +1610,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_PINMUX_PEX_RST; + appl_writel(pcie, data, APPL_PINMUX); + +- /* +- * Some cards do not go to detect state even after de-asserting +- * PERST#. So, de-assert LTSSM to bring link to detect state. +- */ +- data = readl(pcie->appl_base + APPL_CTRL); +- data &= ~APPL_CTRL_LTSSM_EN; +- writel(data, pcie->appl_base + APPL_CTRL); +- + err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1626,6 +1618,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); ++ ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ data = readl(pcie->appl_base + APPL_CTRL); ++ data &= ~APPL_CTRL_LTSSM_EN; ++ writel(data, pcie->appl_base + APPL_CTRL); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1707,11 +1707,6 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (pcie->ep_state == EP_STATE_DISABLED) + return; + +- /* Disable LTSSM */ +- val = appl_readl(pcie, APPL_CTRL); +- val &= ~APPL_CTRL_LTSSM_EN; +- appl_writel(pcie, val, APPL_CTRL); +- + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1722,6 +1717,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (ret) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ val = appl_readl(pcie, APPL_CTRL); ++ val &= ~APPL_CTRL_LTSSM_EN; ++ appl_writel(pcie, val, APPL_CTRL); ++ + reset_control_assert(pcie->core_rst); + + tegra_pcie_disable_phy(pcie); +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch b/queue-6.1/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch new file mode 100644 index 0000000000..389bcd63cd --- /dev/null +++ b/queue-6.1/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch @@ -0,0 +1,52 @@ +From 9525f64ea75a693ad84a3ed587fb47521706beb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:46 +0530 +Subject: PCI: tegra194: Disable PERST# IRQ only in Endpoint mode + +From: Manikanta Maddireddy + +[ Upstream commit 40658a31b6e134169c648041efc84944c4c71dcd ] + +The PERST# GPIO interrupt is only registered when the controller is +operating in Endpoint mode. In Root Port mode, the PERST# GPIO is +configured as an output to control downstream devices, and no interrupt is +registered for it. + +Currently, tegra_pcie_dw_stop_link() unconditionally calls disable_irq() +on pex_rst_irq, which causes issues in Root Port mode where this IRQ is +not registered. + +Fix this by only disabling the PERST# IRQ when operating in Endpoint mode, +where the interrupt is actually registered and used to detect PERST# +assertion/deassertion from the host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-6-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index c562a4b97da1c..5085bacd2f542 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1041,7 +1041,8 @@ static void tegra_pcie_dw_stop_link(struct dw_pcie *pci) + { + struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); + +- disable_irq(pcie->pex_rst_irq); ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ disable_irq(pcie->pex_rst_irq); + } + + static const struct dw_pcie_ops tegra_dw_pcie_ops = { +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch b/queue-6.1/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch new file mode 100644 index 0000000000..16a38dc6ea --- /dev/null +++ b/queue-6.1/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch @@ -0,0 +1,111 @@ +From 38e351482f2f16f0f82b122de467e3c4b79db07b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:45 +0530 +Subject: PCI: tegra194: Don't force the device into the D0 state before L2 + +From: Vidya Sagar + +[ Upstream commit 71d9f67701e1affc82d18ca88ae798c5361beddf ] + +As per PCIe CEM r6.0, sec 2.3, the PCIe Endpoint device should be in D3cold +to assert WAKE# pin. The previous workaround that forced downstream devices +to D0 before taking the link to L2 cited PCIe r4.0, sec 5.2, "Link State +Power Management"; however, that spec does not explicitly require putting +the device into D0 and only indicates that power removal may be initiated +without transitioning to D3hot. + +Remove the D0 workaround so that Endpoint devices can use wake +functionality (WAKE# from D3). With some Endpoints the link may not enter +L2 when they remain in D3, but the Root Port continues with the usual flow +after PME timeout, so there is no functional issue. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-5-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 41 ---------------------- + 1 file changed, 41 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 46fe5abfad8c1..c562a4b97da1c 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1274,44 +1274,6 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, + return 0; + } + +-static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) +-{ +- struct dw_pcie_rp *pp = &pcie->pci.pp; +- struct pci_bus *child, *root_port_bus = NULL; +- struct pci_dev *pdev; +- +- /* +- * link doesn't go into L2 state with some of the endpoints with Tegra +- * if they are not in D0 state. So, need to make sure that immediate +- * downstream devices are in D0 state before sending PME_TurnOff to put +- * link into L2 state. +- * This is as per PCI Express Base r4.0 v1.0 September 27-2017, +- * 5.2 Link State Power Management (Page #428). +- */ +- +- list_for_each_entry(child, &pp->bridge->bus->children, node) { +- if (child->parent == pp->bridge->bus) { +- root_port_bus = child; +- break; +- } +- } +- +- if (!root_port_bus) { +- dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); +- return; +- } +- +- /* Bring downstream devices to D0 if they are not already in */ +- list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { +- if (PCI_SLOT(pdev->devfn) == 0) { +- if (pci_set_power_state(pdev, PCI_D0)) +- dev_err(pcie->dev, +- "Failed to transition %s to D0 state\n", +- dev_name(&pdev->dev)); +- } +- } +-} +- + static int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie) + { + pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3"); +@@ -1641,7 +1603,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + + static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) + { +- tegra_pcie_downstream_dev_to_D0(pcie); + dw_pcie_host_deinit(&pcie->pci.pp); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); +@@ -2353,7 +2314,6 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + if (!pcie->link_state) + return 0; + +- tegra_pcie_downstream_dev_to_D0(pcie); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); + +@@ -2427,7 +2387,6 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev) + return; + + debugfs_remove_recursive(pcie->debugfs); +- tegra_pcie_downstream_dev_to_D0(pcie); + + disable_irq(pcie->pci.pp.irq); + if (IS_ENABLED(CONFIG_PCI_MSI)) +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-fix-polling-delay-for-l2-state.patch b/queue-6.1/pci-tegra194-fix-polling-delay-for-l2-state.patch new file mode 100644 index 0000000000..9c3ef3286c --- /dev/null +++ b/queue-6.1/pci-tegra194-fix-polling-delay-for-l2-state.patch @@ -0,0 +1,59 @@ +From 3844716e78fd1be6ddf21c0f0a1ada11164e02c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:42 +0530 +Subject: PCI: tegra194: Fix polling delay for L2 state + +From: Vidya Sagar + +[ Upstream commit adaffed907f14f954096555665ad6af2ae724d83 ] + +As per PCIe r7.0, sec 5.3.3.2.1, after sending PME_Turn_Off message, Root +Port should wait for 1-10 msec for PME_TO_Ack message. Currently, driver is +polling for 10 msec with 1 usec delay which is aggressive. Use existing +macro PCIE_PME_TO_L2_TIMEOUT_US to poll for 10 msec with 1 msec delay. +Since this function is used in non-atomic context only, use non-atomic poll +function. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 0dca4baad0dac..e6124eeb824d4 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -206,8 +206,6 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define PME_ACK_TIMEOUT 10000 +- + #define LTSSM_TIMEOUT 50000 /* 50ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 +@@ -1569,9 +1567,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) + val |= APPL_PM_XMT_TURNOFF_STATE; + appl_writel(pcie, val, APPL_RADM_STATUS); + +- return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val, +- val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, +- 1, PME_ACK_TIMEOUT); ++ return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, ++ val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, ++ PCIE_PME_TO_L2_TIMEOUT_US/10, ++ PCIE_PME_TO_L2_TIMEOUT_US); + } + + static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch b/queue-6.1/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch new file mode 100644 index 0000000000..7665ad3c63 --- /dev/null +++ b/queue-6.1/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch @@ -0,0 +1,106 @@ +From 2dbe0153bd2c4446a2f801ca2a5b9ba3c91f0ba6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:43 +0530 +Subject: PCI: tegra194: Increase LTSSM poll time on surprise link down + +From: Manikanta Maddireddy + +[ Upstream commit 74dd8efe4d6cead433162147333af989a568aac7 ] + +On surprise link down, LTSSM state transits from L0 -> Recovery.RcvrLock -> +Recovery.RcvrSpeed -> Gen1 Recovery.RcvrLock -> Detect. Recovery.RcvrLock +and Recovery.RcvrSpeed transit times are 24 ms and 48 ms respectively, so +the total time from L0 to Detect is ~96 ms. Increase the poll timeout to +120 ms to account for this. + +While at it, add LTSSM state defines for Detect-related states and use them +in the poll condition. Use readl_poll_timeout() instead of +readl_poll_timeout_atomic() in tegra_pcie_dw_pme_turnoff() since that path +runs in non-atomic context. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-3-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 36 +++++++++++++--------- + 1 file changed, 21 insertions(+), 15 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index e6124eeb824d4..f502b925d486b 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -140,7 +140,11 @@ + #define APPL_DEBUG_PM_LINKST_IN_L0 0x11 + #define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) + #define APPL_DEBUG_LTSSM_STATE_SHIFT 3 +-#define LTSSM_STATE_PRE_DETECT 5 ++#define LTSSM_STATE_DETECT_QUIET 0x00 ++#define LTSSM_STATE_DETECT_ACT 0x08 ++#define LTSSM_STATE_PRE_DETECT_QUIET 0x28 ++#define LTSSM_STATE_DETECT_WAIT 0x30 ++#define LTSSM_STATE_L2_IDLE 0xa8 + + #define APPL_RADM_STATUS 0xE4 + #define APPL_PM_XMT_TURNOFF_STATE BIT(0) +@@ -206,7 +210,8 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define LTSSM_TIMEOUT 50000 /* 50ms */ ++#define LTSSM_DELAY_US 10000 /* 10 ms */ ++#define LTSSM_TIMEOUT_US 120000 /* 120 ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 + +@@ -1613,15 +1618,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_CTRL_LTSSM_EN; + writel(data, pcie->appl_base + APPL_CTRL); + +- err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, +- data, +- ((data & +- APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) +- dev_info(pcie->dev, "Link didn't go to detect state\n"); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1709,12 +1713,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + appl_writel(pcie, val, APPL_CTRL); + + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, +- ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (ret) +- dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + + reset_control_assert(pcie->core_rst); + +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch b/queue-6.1/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch new file mode 100644 index 0000000000..d59bff0108 --- /dev/null +++ b/queue-6.1/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch @@ -0,0 +1,69 @@ +From e06ff29a0f9a48345439ac5b56ad5dd5eb972cdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Sep 2025 13:40:57 +0530 +Subject: PCI: tegra194: Rename 'root_bus' to 'root_port_bus' in + tegra_pcie_downstream_dev_to_D0() + +From: Manivannan Sadhasivam + +[ Upstream commit e1bd928479fb1fa60e9034b0fdb1ab9f3fa92f33 ] + +In tegra_pcie_downstream_dev_to_D0(), PCI devices are transitioned to D0 +state. For iterating over the devices, first the downstream bus of the Root +Port is searched from the root bus. But the name of the variable that holds +the Root Port downstream bus is named as 'root_bus', which is wrong. + +Rename the variable to 'root_port_bus'. Also, move the comment on 'bringing +the devices to D0' to where the state is set exactly. + +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20250922081057.15209-1-mani@kernel.org +Stable-dep-of: 71d9f67701e1 ("PCI: tegra194: Don't force the device into the D0 state before L2") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index b6899d1f80fb5..46fe5abfad8c1 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1277,7 +1277,7 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, + static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) + { + struct dw_pcie_rp *pp = &pcie->pci.pp; +- struct pci_bus *child, *root_bus = NULL; ++ struct pci_bus *child, *root_port_bus = NULL; + struct pci_dev *pdev; + + /* +@@ -1290,19 +1290,19 @@ static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) + */ + + list_for_each_entry(child, &pp->bridge->bus->children, node) { +- /* Bring downstream devices to D0 if they are not already in */ + if (child->parent == pp->bridge->bus) { +- root_bus = child; ++ root_port_bus = child; + break; + } + } + +- if (!root_bus) { +- dev_err(pcie->dev, "Failed to find downstream devices\n"); ++ if (!root_port_bus) { ++ dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); + return; + } + +- list_for_each_entry(pdev, &root_bus->devices, bus_list) { ++ /* Bring downstream devices to D0 if they are not already in */ ++ list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { + if (PCI_SLOT(pdev->devfn) == 0) { + if (pci_set_power_state(pdev, PCI_D0)) + dev_err(pcie->dev, +-- +2.53.0 + diff --git a/queue-6.1/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch b/queue-6.1/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch new file mode 100644 index 0000000000..b2419ae4b4 --- /dev/null +++ b/queue-6.1/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch @@ -0,0 +1,47 @@ +From ab73e7a5a3c2bac041c21354e14a0ff0237c8dd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:47 +0530 +Subject: PCI: tegra194: Use devm_gpiod_get_optional() to parse + "nvidia,refclk-select" + +From: Vidya Sagar + +[ Upstream commit f62bc7917de1374dce86a852ffba8baf9cb7a56a ] + +The GPIO DT property "nvidia,refclk-select", to select the PCIe reference +clock is optional. Use devm_gpiod_get_optional() to get it. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-7-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 5085bacd2f542..87851a56ebd2d 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1183,9 +1183,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) + return err; + } + +- pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, +- "nvidia,refclk-select", +- GPIOD_OUT_HIGH); ++ pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev, ++ "nvidia,refclk-select", ++ GPIOD_OUT_HIGH); + if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { + int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); + const char *level = KERN_ERR; +-- +2.53.0 + diff --git a/queue-6.1/pcmcia-fix-garbled-log-messages-for-kern_cont.patch b/queue-6.1/pcmcia-fix-garbled-log-messages-for-kern_cont.patch new file mode 100644 index 0000000000..9790e5c17b --- /dev/null +++ b/queue-6.1/pcmcia-fix-garbled-log-messages-for-kern_cont.patch @@ -0,0 +1,55 @@ +From 1f901347bfdf75a4ecd259e17963c0b4b50722a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 17:42:56 +0100 +Subject: PCMCIA: Fix garbled log messages for KERN_CONT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit bfeaa6814bd3f9a1f6d525b3b35a03b9a0368961 ] + +For years the PCMCIA info messages are messed up by superfluous +newlines. While f2e6cf76751d ("pcmcia: Convert dev_printk to +dev_") converted the code to pr_cont(), dev_info enforces a \n +via vprintk_store setting LOG_NEWLINE, breaking subsequent pr_cont. + +Fix by logging the device name manually to allow pr_cont to work for +more readable and not \n distorted logs. + +Fixes: f2e6cf76751d ("pcmcia: Convert dev_printk to dev_") +Signed-off-by: René Rebe +Signed-off-by: Dominik Brodowski +Signed-off-by: Sasha Levin +--- + drivers/pcmcia/rsrc_nonstatic.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c +index 0a4e439d46094..f9baf28bc32b8 100644 +--- a/drivers/pcmcia/rsrc_nonstatic.c ++++ b/drivers/pcmcia/rsrc_nonstatic.c +@@ -188,7 +188,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, + int any; + u_char *b, hole, most; + +- dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1); ++ pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1); + + /* First, what does a floating port look like? */ + b = kzalloc(256, GFP_KERNEL); +@@ -410,8 +410,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + struct socket_data *s_data = s->resource_data; + u_long i, j, bad, fail, step; + +- dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:", +- base, base+num-1); ++ pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:", ++ dev_name(&s->dev), base, base+num-1); + bad = fail = 0; + step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + /* don't allow too large steps */ +-- +2.53.0 + diff --git a/queue-6.1/perf-branch-avoid-incrementing-null.patch b/queue-6.1/perf-branch-avoid-incrementing-null.patch new file mode 100644 index 0000000000..564ebe7c85 --- /dev/null +++ b/queue-6.1/perf-branch-avoid-incrementing-null.patch @@ -0,0 +1,39 @@ +From ea903b1b46680257f3f4eda720f66ad2d0547603 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:31:31 -0700 +Subject: perf branch: Avoid incrementing NULL + +From: Ian Rogers + +[ Upstream commit c969a9d7bbf46f983c4a48566b3b2f7340b02296 ] + +If the entry is NULL the value is meaningless so early return NULL to +avoid an increment of NULL. This was happening in calls from +has_stitched_lbr when running the "perf record LBR tests". The return +value isn't used in that case, so returning NULL as no effect. + +Fixes: 42bbabed09ce ("perf tools: Add hw_idx in struct branch_stack") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/branch.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h +index dca75cad96f68..c99b389fac1e1 100644 +--- a/tools/perf/util/branch.h ++++ b/tools/perf/util/branch.h +@@ -66,6 +66,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl + { + u64 *entry = (u64 *)sample->branch_stack; + ++ if (entry == NULL) ++ return NULL; ++ + entry++; + if (sample->no_hw_idx) + return (struct branch_entry *)entry; +-- +2.53.0 + diff --git a/queue-6.1/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch b/queue-6.1/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch new file mode 100644 index 0000000000..a3efb4f1f7 --- /dev/null +++ b/queue-6.1/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch @@ -0,0 +1,57 @@ +From 5e91cde0ddec0c38af012c8f33acee9095de41ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:04:47 +0100 +Subject: perf expr: Return -EINVAL for syntax error in expr__find_ids() + +From: Leo Yan + +[ Upstream commit 3a61fd866ef9aaa1d3158b460f852b74a2df07f4 ] + +expr__find_ids() propagates the parser return value directly. For syntax +errors, the parser can return a positive value, but callers treat it as +success, e.g., for below case on Arm64 platform: + + metric expr 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) for backend_bound + parsing metric: 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) + Failure to read '#slots' literal: #slots = nan + syntax error + +Convert positive parser returns in expr__find_ids() to -EINVAL, as a +result, the error value will be respected by callers. + +Before: + + perf stat -C 5 + Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Segmentation fault + +After: + + perf stat -C 5 + Failure to read '#slots'Cannot find metric or group `Default' + +Fixes: ded80bda8bc9 ("perf expr: Migrate expr ids table to a hashmap") +Signed-off-by: Leo Yan +Reviewed-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/expr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index aaacf514dc09c..2afd561a7aab9 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -380,7 +380,8 @@ int expr__find_ids(const char *expr, const char *one, + if (one) + expr__del_id(ctx, one); + +- return ret; ++ /* A positive value means syntax error, convert to -EINVAL */ ++ return ret > 0 ? -EINVAL : ret; + } + + double expr_id_data__value(const struct expr_id_data *data) +-- +2.53.0 + diff --git a/queue-6.1/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch b/queue-6.1/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch new file mode 100644 index 0000000000..17d83388f5 --- /dev/null +++ b/queue-6.1/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch @@ -0,0 +1,115 @@ +From aae727806f141d92bf352a87cb29cfb42fcd641e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:36:39 +0000 +Subject: perf: tools: cs-etm: Fix print issue for Coresight debug in ETE/TRBE + trace + +From: Mike Leach + +[ Upstream commit 6c478e7b3eba3f387a2d6c749e3e3ee0f8ad1c53 ] + +Building perf with CORESIGHT=1 and the optional CSTRACE_RAW=1 enables +additional debug printing of raw trace data when using command:- +perf report --dump. + +This raw trace prints the CoreSight formatted trace frames, which may be +used to investigate suspected issues with trace quality / corruption / +decode. + +These frames are not present in ETE + TRBE trace. +This fix removes the unnecessary call to print these frames. + +This fix also rationalises implementation - original code had helper +function that unnecessarily repeated initialisation calls that had +already been made. + +Due to an addtional fault with the OpenCSD library, this call when ETE/TRBE +are being decoded will cause a segfault in perf. This fix also prevents +that problem for perf using older (<= 1.8.0 version) OpenCSD libraries. + +Fixes: 68ffe3902898 ("perf tools: Add decoder mechanic to support dumping trace data") +Reported-by: Leo Yan +Signed-off-by: Mike Leach +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 51 +++++-------------- + 1 file changed, 13 insertions(+), 38 deletions(-) + +diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +index 31fa3b45134a2..fc74a95a23faf 100644 +--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c ++++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +@@ -214,46 +214,24 @@ cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, + (void *)decoder, + cs_etm_decoder__print_str_cb); + if (ret != 0) +- ret = -1; +- +- return 0; +-} ++ return -1; + + #ifdef CS_LOG_RAW_FRAMES +-static void +-cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params, +- struct cs_etm_decoder *decoder) +-{ +- /* Only log these during a --dump operation */ +- if (d_params->operation == CS_ETM_OPERATION_PRINT) { +- /* set up a library default logger to process the +- * raw frame printer we add later +- */ +- ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); +- +- /* no stdout / err / file output */ +- ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); +- +- /* set the string CB for the default logger, +- * passes strings to perf print logger. +- */ +- ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, +- (void *)decoder, +- cs_etm_decoder__print_str_cb); +- ++ /* ++ * Only log raw frames if --dump operation and hardware is actually ++ * generating formatted CoreSight trace frames ++ */ ++ if ((d_params->operation == CS_ETM_OPERATION_PRINT) && ++ (d_params->formatted == true)) { + /* use the built in library printer for the raw frames */ +- ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, +- CS_RAW_DEBUG_FLAGS); ++ ret = ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, ++ CS_RAW_DEBUG_FLAGS); ++ if (ret != 0) ++ return -1; + } +-} +-#else +-static void +-cs_etm_decoder__init_raw_frame_logging( +- struct cs_etm_decoder_params *d_params __maybe_unused, +- struct cs_etm_decoder *decoder __maybe_unused) +-{ +-} + #endif ++ return 0; ++} + + static ocsd_datapath_resp_t + cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, +@@ -716,9 +694,6 @@ cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params, + if (ret != 0) + goto err_free_decoder; + +- /* init raw frame logging if required */ +- cs_etm_decoder__init_raw_frame_logging(d_params, decoder); +- + for (i = 0; i < decoders; i++) { + ret = cs_etm_decoder__create_etm_decoder(d_params, + &t_params[i], +-- +2.53.0 + diff --git a/queue-6.1/perf-tools-fix-module-symbol-resolution-for-non-zero.patch b/queue-6.1/perf-tools-fix-module-symbol-resolution-for-non-zero.patch new file mode 100644 index 0000000000..6627dd8467 --- /dev/null +++ b/queue-6.1/perf-tools-fix-module-symbol-resolution-for-non-zero.patch @@ -0,0 +1,77 @@ +From 12a816dcb4227e90b2bcff3f5b8e8734d95ebfe9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 11:58:04 -0400 +Subject: perf tools: Fix module symbol resolution for non-zero .text sh_addr + +From: Chuck Lever + +[ Upstream commit 9a82bfde4775b7a87cd1a7e791f46f83ae442848 ] + +When perf resolves symbols from kernel module ELF files (ET_REL), +it converts symbol addresses to file offsets so that sample IPs +can be matched to the correct symbol. The conversion adjusts each +symbol's st_value: + + sym->st_value -= shdr->sh_addr - shdr->sh_offset; + +For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr +is the section's virtual base, so subtracting sh_addr and adding +sh_offset correctly yields a file offset. + +For kernel modules (ET_REL), st_value is a section-relative +offset. The module loader ignores sh_addr entirely and places +symbols at module_base + st_value. Converting to file offset +requires only adding sh_offset; subtracting sh_addr introduces an +error equal to sh_addr bytes. + +When .text has sh_addr == 0 -- the historical norm for simple +modules -- both formulas produce the same result and the bug is +latent. As modules gain more metadata sections before .text (.note, +.static_call.text, etc.), the linker assigns .text a non-zero +sh_addr, exposing the defect. For example, nfsd.ko on this kernel +has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90. + +The effect is that all .text symbols in affected modules +shift by sh_addr bytes relative to sample IPs, causing perf +report to attribute samples to incorrect, nearby symbols. This +was observed as 13% of LLC-load-miss samples misattributed +to nfsd_file_get_dio_attrs when the actual hot function was +nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol +table. + +Use the existing dso__rel() flag (already set for ET_REL modules) +to select the correct adjustment: add sh_offset for ET_REL, +subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN. + +Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules") +Signed-off-by: Chuck Lever +Reviewed-by: Ian Rogers +Tested-by: Thomas Richter +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/symbol-elf.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c +index 29c9348c30f00..34bcce60e9ca3 100644 +--- a/tools/perf/util/symbol-elf.c ++++ b/tools/perf/util/symbol-elf.c +@@ -1006,8 +1006,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, + char dso_name[PATH_MAX]; + + /* Adjust symbol to map to file offset */ +- if (adjust_kernel_syms) +- sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ if (adjust_kernel_syms) { ++ if (dso__rel(dso)) ++ sym->st_value += shdr->sh_offset; ++ else ++ sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ } + + if (strcmp(section_name, (curr_dso->short_name + dso->short_name_len)) == 0) + return 0; +-- +2.53.0 + diff --git a/queue-6.1/perf-util-kill-die-prototype-dead-for-a-long-time.patch b/queue-6.1/perf-util-kill-die-prototype-dead-for-a-long-time.patch new file mode 100644 index 0000000000..41aab2ef4f --- /dev/null +++ b/queue-6.1/perf-util-kill-die-prototype-dead-for-a-long-time.patch @@ -0,0 +1,39 @@ +From 625a1cf2c1c2590e3a3b6e0038401e053932c3ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:31:57 -0300 +Subject: perf util: Kill die() prototype, dead for a long time + +From: Arnaldo Carvalho de Melo + +[ Upstream commit e5cce1b9c82fbd48e2f1f7a25a9fad8ee228176f ] + +In fef2a735167a827a ("perf tools: Kill die()") the die() function was +removed, but not the prototype in util.h, now when building with +LIBPERL=1, during a 'make -C tools/perf build-test' routine test, it is +failing as perl likes die() calls and then this clashes with this +remnant, remove it. + +Fixes: fef2a735167a827a ("perf tools: Kill die()") +Reviewed-by: Ian Rogers +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/util.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h +index c1f2d423a9ecb..bdb6d5e7102db 100644 +--- a/tools/perf/util/util.h ++++ b/tools/perf/util/util.h +@@ -17,7 +17,6 @@ + + /* General helper functions */ + void usage(const char *err) __noreturn; +-void die(const char *err, ...) __noreturn __printf(1, 2); + + struct dirent; + struct strlist; +-- +2.53.0 + diff --git a/queue-6.1/pinctrl-abx500-fix-type-of-argument-variable.patch b/queue-6.1/pinctrl-abx500-fix-type-of-argument-variable.patch new file mode 100644 index 0000000000..38c63b7563 --- /dev/null +++ b/queue-6.1/pinctrl-abx500-fix-type-of-argument-variable.patch @@ -0,0 +1,38 @@ +From 7dd02ab0dc72c5bae577b9e708ee38e37e31b3ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 23:15:06 +0800 +Subject: pinctrl: abx500: Fix type of 'argument' variable + +From: Yu-Chun Lin + +[ Upstream commit 34006f77890d050e6d80cbee365b5d703c1140b4 ] + +The argument variable is assigned the return value of +pinconf_to_config_argument(), which returns a u32. Change its type from +enum pin_config_param to unsigned int to correctly store the configuration +argument. + +Fixes: 03b054e9696c ("pinctrl: Pass all configs to driver on pin_config_set()") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/nomadik/pinctrl-abx500.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c +index 7aa534576a459..609313d93e31a 100644 +--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c ++++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c +@@ -850,7 +850,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, + int ret = -EINVAL; + int i; + enum pin_config_param param; +- enum pin_config_param argument; ++ unsigned int argument; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); +-- +2.53.0 + diff --git a/queue-6.1/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch b/queue-6.1/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch new file mode 100644 index 0000000000..9e2796c084 --- /dev/null +++ b/queue-6.1/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch @@ -0,0 +1,39 @@ +From bf3c57f6da9b0db0ea6e360bbbd10e1df1e32edb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 17:43:35 +0100 +Subject: pinctrl: cy8c95x0: Avoid returning positive values to user space + +From: Andy Shevchenko + +[ Upstream commit 5ad32c3607cf241a1a2680cabd64cbcd757227aa ] + +When probe fails due to unclear interrupt status register, it returns +a positive number instead of the proper error code. Fix this accordingly. + +Fixes: e6cbbe42944d ("pinctrl: Add Cypress cy8c95x0 support") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202602271847.vVWkqLBD-lkp@intel.com/ +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index 01f3c74f3dfa4..e4e8f744d27cb 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1216,7 +1216,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); + if (ret) +- return dev_err_probe(dev, ret, "failed to clear irq status register\n"); ++ return dev_err_probe(dev, -EBUSY, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-6.1/pinctrl-cy8c95x0-remove-duplicate-error-message.patch b/queue-6.1/pinctrl-cy8c95x0-remove-duplicate-error-message.patch new file mode 100644 index 0000000000..93ea5dce88 --- /dev/null +++ b/queue-6.1/pinctrl-cy8c95x0-remove-duplicate-error-message.patch @@ -0,0 +1,73 @@ +From 90d920af3c378f60492a3ab6c5020a5159032b18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:53 +0100 +Subject: pinctrl: cy8c95x0: remove duplicate error message + +From: Andy Shevchenko + +[ Upstream commit 970dacb3b9f0fedbbbcfd7dbf1f4f22340b3f359 ] + +The pin control core is covered to report any error via message. +The devm_request_threaded_irq() already prints an error message. +Remove the duplicates. + +While at it, drop the info message as the same information about +an IRQ in use can be retrieved differently. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 21 +++++---------------- + 1 file changed, 5 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index f7c8ae9808133..c60886d804ce0 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1206,6 +1206,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + { + struct gpio_irq_chip *girq = &chip->gpio_chip.irq; + DECLARE_BITMAP(pending_irqs, MAX_LINE); ++ struct device *dev = chip->dev; + int ret; + + mutex_init(&chip->irq_lock); +@@ -1232,17 +1233,9 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + girq->handler = handle_simple_irq; + girq->threaded = true; + +- ret = devm_request_threaded_irq(chip->dev, irq, +- NULL, cy8c95x0_irq_handler, +- IRQF_ONESHOT | IRQF_SHARED, +- dev_name(chip->dev), chip); +- if (ret) { +- dev_err(chip->dev, "failed to request irq %d\n", irq); +- return ret; +- } +- dev_info(chip->dev, "Registered threaded IRQ\n"); +- +- return 0; ++ return devm_request_threaded_irq(dev, irq, NULL, cy8c95x0_irq_handler, ++ IRQF_ONESHOT | IRQF_SHARED, ++ dev_name(chip->dev), chip); + } + + static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) +@@ -1258,11 +1251,7 @@ static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) + pd->owner = THIS_MODULE; + + chip->pctldev = devm_pinctrl_register(chip->dev, pd, chip); +- if (IS_ERR(chip->pctldev)) +- return dev_err_probe(chip->dev, PTR_ERR(chip->pctldev), +- "can't register controller\n"); +- +- return 0; ++ return PTR_ERR_OR_ZERO(chip->pctldev); + } + + static int cy8c95x0_detect(struct i2c_client *client, +-- +2.53.0 + diff --git a/queue-6.1/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch b/queue-6.1/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch new file mode 100644 index 0000000000..13aa8b6596 --- /dev/null +++ b/queue-6.1/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch @@ -0,0 +1,40 @@ +From 5e56539970a38441f909d118c182198bed601bf0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:54 +0100 +Subject: pinctrl: cy8c95x0: Unify messages with help of dev_err_probe() + +From: Andy Shevchenko + +[ Upstream commit 014884732095b982412d13d3220c3fe8483b9b3e ] + +Unify error messages that might appear during probe phase by +switching to use dev_err_probe(). + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index c60886d804ce0..01f3c74f3dfa4 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1215,10 +1215,8 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); +- if (ret) { +- dev_err(chip->dev, "failed to clear irq status register\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-6.1/pinctrl-pinctrl-pic32-fix-resource-leak.patch b/queue-6.1/pinctrl-pinctrl-pic32-fix-resource-leak.patch new file mode 100644 index 0000000000..377a145828 --- /dev/null +++ b/queue-6.1/pinctrl-pinctrl-pic32-fix-resource-leak.patch @@ -0,0 +1,72 @@ +From bc6bf8e8b80b7c2bb2011b7c2a32d98ce45a3e33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:56:23 -0600 +Subject: pinctrl: pinctrl-pic32: Fix resource leak + +From: Ethan Tidmore + +[ Upstream commit fe5560688f3ba98364c7de7b4f8dc240ffd1ff75 ] + +Fix three possible resource leaks by using the devres version of +clk_prepare_enable(). Also, update error message accordingly. + +Detected by Smatch: +drivers/pinctrl/pinctrl-pic32.c:2211 pic32_pinctrl_probe() warn: +'pctl->clk' from clk_prepare_enable() not released on lines: 2208. + +drivers/pinctrl/pinctrl-pic32.c:2274 pic32_gpio_probe() warn: +'bank->clk' from clk_prepare_enable() not released on lines: 2264,2272. + +Fixes: 2ba384e6c3810 ("pinctrl: pinctrl-pic32: Add PIC32 pin control driver") +Signed-off-by: Ethan Tidmore +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-pic32.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c +index 37acfdfc2cae0..ee9082a499c5f 100644 +--- a/drivers/pinctrl/pinctrl-pic32.c ++++ b/drivers/pinctrl/pinctrl-pic32.c +@@ -2162,16 +2162,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev) + if (IS_ERR(pctl->reg_base)) + return PTR_ERR(pctl->reg_base); + +- pctl->clk = devm_clk_get(&pdev->dev, NULL); ++ pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(pctl->clk)) { + ret = PTR_ERR(pctl->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(pctl->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +@@ -2227,16 +2221,10 @@ static int pic32_gpio_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- bank->clk = devm_clk_get(&pdev->dev, NULL); ++ bank->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bank->clk)) { + ret = PTR_ERR(bank->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(bank->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.1/platform-surface-surfacepro3_button-drop-wakeup-sour.patch b/queue-6.1/platform-surface-surfacepro3_button-drop-wakeup-sour.patch new file mode 100644 index 0000000000..0bf1fef6f5 --- /dev/null +++ b/queue-6.1/platform-surface-surfacepro3_button-drop-wakeup-sour.patch @@ -0,0 +1,41 @@ +From 24890b37951991d9f979cceb475f20e2e434bafd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:54:08 +0100 +Subject: platform/surface: surfacepro3_button: Drop wakeup source on remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 1410a228ab2d36fe2b383415a632ae12048d4f3a ] + +The wakeup source added by device_init_wakeup() in surface_button_add() +needs to be dropped during driver removal, so update the driver to do +that. + +Fixes: 19351f340765 ("platform/x86: surfacepro3: Support for wakeup from suspend-to-idle") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/4368848.1IzOArtZ34@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/surface/surfacepro3_button.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 242fb690dcaf7..892fb71d5916f 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -243,6 +243,7 @@ static int surface_button_remove(struct acpi_device *device) + { + struct surface_button *button = acpi_driver_data(device); + ++ device_init_wakeup(&device->dev, false); + input_unregister_device(button->input); + kfree(button); + return 0; +-- +2.53.0 + diff --git a/queue-6.1/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch b/queue-6.1/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch new file mode 100644 index 0000000000..4a23614883 --- /dev/null +++ b/queue-6.1/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch @@ -0,0 +1,99 @@ +From 2318d08b0cc0d08b0e438127d1b7a20fe07bd566 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:38:21 +0800 +Subject: platform/x86: dell-wmi-sysman: bound enumeration string aggregation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pengpeng Hou + +[ Upstream commit 3c34471c26abc52a37f5ad90949e2e4b8027eb14 ] + +populate_enum_data() aggregates firmware-provided value-modifier +and possible-value strings into fixed 512-byte struct members. +The current code bounds each individual source string but then +appends every string and separator with raw strcat() and no +remaining-space check. + +Switch the aggregation loops to a bounded append helper and +reject enumeration packages whose combined strings do not fit +in the destination buffers. + +Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems") +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260408084501.1-dell-wmi-sysman-v2-pengpeng@iscas.ac.cn +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + .../dell/dell-wmi-sysman/enum-attributes.c | 34 +++++++++++++++---- + 1 file changed, 28 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +index fc2f58b4cbc6e..7e44ba3015627 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +@@ -6,10 +6,32 @@ + * Copyright (c) 2020 Dell Inc. + */ + ++#include ++ + #include "dell-wmi-sysman.h" + + get_instance_id(enumeration); + ++static int append_enum_string(char *dest, const char *src) ++{ ++ size_t dest_len = strlen(dest); ++ ssize_t copied; ++ ++ if (WARN_ON_ONCE(dest_len >= MAX_BUFF)) ++ return -EINVAL; ++ ++ copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ dest_len += copied; ++ copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { + int instance_id = get_enumeration_instance_id(kobj); +@@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + if (next_obj >= enum_property_count) +@@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); +-- +2.53.0 + diff --git a/queue-6.1/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch b/queue-6.1/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch new file mode 100644 index 0000000000..693f5de316 --- /dev/null +++ b/queue-6.1/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch @@ -0,0 +1,60 @@ +From 536af61384debb3c6344076692e5f5209c5ea891 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:42:39 +0300 +Subject: platform/x86: dell_rbu: avoid uninit value usage in + packet_size_write() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fedor Pchelkin + +[ Upstream commit f8fd138c2363c0e2d3235c32bfb4fb5c6474e4ae ] + +Ensure the temp value has been properly parsed from the user-provided +buffer and initialized to be used in later operations. While at it, +prefer a convenient kstrtoul() helper. + +Found by Linux Verification Center (linuxtesting.org) with Svace static +analysis tool. + +Fixes: ad6ce87e5bd4 ("[PATCH] dell_rbu: changes in packet update mechanism") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260403134240.604837-1-pchelkin@ispras.ru +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/dell/dell_rbu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c +index fee20866b41e4..9039e494131fd 100644 +--- a/drivers/platform/x86/dell/dell_rbu.c ++++ b/drivers/platform/x86/dell/dell_rbu.c +@@ -30,6 +30,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -617,9 +618,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, + char *buffer, loff_t pos, size_t count) + { + unsigned long temp; ++ ++ if (kstrtoul(buffer, 10, &temp)) ++ return -EINVAL; ++ + spin_lock(&rbu_data.lock); + packet_empty_list(); +- sscanf(buffer, "%lu", &temp); + if (temp < 0xffffffff) + rbu_data.packetsize = temp; + +-- +2.53.0 + diff --git a/queue-6.1/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch b/queue-6.1/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch new file mode 100644 index 0000000000..0727c97fd6 --- /dev/null +++ b/queue-6.1/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch @@ -0,0 +1,67 @@ +From 09abca6e880f7eda36cc23c089e89a89dce2d977 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 11:31:54 +0100 +Subject: platform/x86: panasonic-laptop: Fix OPTD notifier registration and + cleanup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 8baeff2c1d33dad8572216c6ad3a7425852507d4 ] + +An ACPI notify handler is leaked if device_create_file() returns an +error in acpi_pcc_hotkey_add(). + +Also, it is pointless to call pcc_unregister_optd_notifier() in +acpi_pcc_hotkey_remove() if pcc->platform is NULL and it is better +to arrange the cleanup code in that function in the same order as +the rollback code in acpi_pcc_hotkey_add(). + +Address the above by placing the pcc_register_optd_notifier() call in +acpi_pcc_hotkey_add() after the device_create_file() return value +check and placing the pcc_unregister_optd_notifier() call in +acpi_pcc_hotkey_remove() right before the device_remove_file() call. + +Fixes: d5a81d8e864b ("platform/x86: panasonic-laptop: Add support for optical driver power in Y and W series") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2411055.ElGaqSPkdT@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/panasonic-laptop.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c +index 99cbacd0cbba4..0a7c4e83cdea9 100644 +--- a/drivers/platform/x86/panasonic-laptop.c ++++ b/drivers/platform/x86/panasonic-laptop.c +@@ -1081,9 +1081,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) + } + result = device_create_file(&pcc->platform->dev, + &dev_attr_cdpower); +- pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + if (result) + goto out_platform; ++ ++ pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + } else { + pcc->platform = NULL; + } +@@ -1117,10 +1118,10 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device) + i8042_remove_filter(panasonic_i8042_filter); + + if (pcc->platform) { ++ pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); + platform_device_unregister(pcc->platform); + } +- pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + + sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); + +-- +2.53.0 + diff --git a/queue-6.1/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch b/queue-6.1/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch new file mode 100644 index 0000000000..13c8b69bdd --- /dev/null +++ b/queue-6.1/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch @@ -0,0 +1,38 @@ +From f09fca3b1c55e40b25ecedbdcf4aedcbea7225f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 22:17:17 +0800 +Subject: pmdomain: imx: scu-pd: Fix device_node reference leak during + ->probe() + +From: Felix Gu + +[ Upstream commit c8e9b6a55702be6c6d034e973d519c52c3848415 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In imx_sc_pd_get_console_rsrc(), it does not release the reference. + +Fixes: 893cfb99734f ("firmware: imx: scu-pd: do not power off console domain") +Signed-off-by: Felix Gu +Reviewed-by: Peng Fan +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/firmware/imx/scu-pd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c +index af3d057e64217..f1977861cd429 100644 +--- a/drivers/firmware/imx/scu-pd.c ++++ b/drivers/firmware/imx/scu-pd.c +@@ -235,6 +235,7 @@ static void imx_sc_pd_get_console_rsrc(void) + return; + + imx_con_rsrc = specs.args[0]; ++ of_node_put(specs.np); + } + + static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on) +-- +2.53.0 + diff --git a/queue-6.1/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch b/queue-6.1/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch new file mode 100644 index 0000000000..36650e9d45 --- /dev/null +++ b/queue-6.1/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch @@ -0,0 +1,36 @@ +From 3f88921038b50c64b1442193da41ebce5fdeffe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 20:27:47 +0800 +Subject: pmdomain: ti: omap_prm: Fix a reference leak on device node + +From: Felix Gu + +[ Upstream commit 44c28e1c52764fef6dd1c1ada3a248728812e67f ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In omap_prm_domain_attach_dev, it does not release the reference. + +Fixes: 58cbff023bfa ("soc: ti: omap-prm: Add basic power domain support") +Signed-off-by: Felix Gu +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/soc/ti/omap_prm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c +index 33ef58195955d..1a85ae3507691 100644 +--- a/drivers/soc/ti/omap_prm.c ++++ b/drivers/soc/ti/omap_prm.c +@@ -652,6 +652,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, + if (pd_args.args_count != 0) + dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", + prmd->pd.name, pd_args.args_count); ++ of_node_put(pd_args.np); + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; +-- +2.53.0 + diff --git a/queue-6.1/powerpc-crash-fix-backup-region-offset-update-to-elf.patch b/queue-6.1/powerpc-crash-fix-backup-region-offset-update-to-elf.patch new file mode 100644 index 0000000000..323649ac1c --- /dev/null +++ b/queue-6.1/powerpc-crash-fix-backup-region-offset-update-to-elf.patch @@ -0,0 +1,63 @@ +From 0854b1af7d94eb1f9d534842a36fd7d9ef0904be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:49 +0530 +Subject: powerpc/crash: fix backup region offset update to elfcorehdr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sourabh Jain + +[ Upstream commit 789335cacdf37da93bb7c70322dff8c7e82881df ] + +update_backup_region_phdr() in file_load_64.c iterates over all the +program headers in the kdump kernel’s elfcorehdr and updates the +p_offset of the program header whose physical address starts at 0. + +However, the loop logic is incorrect because the program header pointer +is not updated during iteration. Since elfcorehdr typically contains +PT_NOTE entries first, the PT_LOAD program header with physical address +0 is never reached. As a result, its p_offset is not updated to point to +the backup region. + +Because of this behavior, the capture kernel exports the first 64 KB of +the crashed kernel’s memory at offset 0, even though that memory +actually lives in the backup region. When a crash happens, purgatory +copies the first 64 KB of the crashed kernel’s memory into the backup +region so the capture kernel can safely use it. + +This has not caused problems so far because the first 64 KB is usually +identical in both the crashed and capture kernels. However, this is +just an assumption and is not guaranteed to always hold true. + +Fix update_backup_region_phdr() to correctly update the p_offset of the +program header with a starting physical address of 0 by correcting the +logic used to iterate over the program headers. + +Fixes: cb350c1f1f86 ("powerpc/kexec_file: Prepare elfcore header for crashing kernel") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Reviewed-by: Hari Bathini +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-2-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kexec/file_load_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index 04d100ca18b86..9e3382e824311 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -768,7 +768,7 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) + unsigned int i; + + phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++) { ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + if (phdr->p_paddr == BACKUP_SRC_START) { + phdr->p_offset = image->arch.backup_start; + pr_debug("Backup region offset updated to 0x%lx\n", +-- +2.53.0 + diff --git a/queue-6.1/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch b/queue-6.1/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch new file mode 100644 index 0000000000..64b0514c43 --- /dev/null +++ b/queue-6.1/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch @@ -0,0 +1,50 @@ +From d114bec6caea438cd9422b910ca7e985045b31b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:11:15 +0900 +Subject: ppp: require CAP_NET_ADMIN in target netns for unattached ioctls + +From: Taegu Ha + +[ Upstream commit 2bb6379416fd19f44c3423a00bfd8626259f6067 ] + +/dev/ppp open is currently authorized against file->f_cred->user_ns, +while unattached administrative ioctls operate on current->nsproxy->net_ns. + +As a result, a local unprivileged user can create a new user namespace +with CLONE_NEWUSER, gain CAP_NET_ADMIN only in that new user namespace, +and still issue PPPIOCNEWUNIT, PPPIOCATTACH, or PPPIOCATTCHAN against +an inherited network namespace. + +Require CAP_NET_ADMIN in the user namespace that owns the target network +namespace before handling unattached PPP administrative ioctls. + +This preserves normal pppd operation in the network namespace it is +actually privileged in, while rejecting the userns-only inherited-netns +case. + +Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2") +Signed-off-by: Taegu Ha +Link: https://patch.msgid.link/20260409071117.4354-1-hataegu0826@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index f184368d5c5e7..89973d0959a68 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1062,6 +1062,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct ppp_net *pn; + int __user *p = (int __user *)arg; + ++ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ + switch (cmd) { + case PPPIOCNEWUNIT: + /* Create a new ppp unit */ +-- +2.53.0 + diff --git a/queue-6.1/pppoe-drop-pfc-frames.patch b/queue-6.1/pppoe-drop-pfc-frames.patch new file mode 100644 index 0000000000..f97c3adc0a --- /dev/null +++ b/queue-6.1/pppoe-drop-pfc-frames.patch @@ -0,0 +1,112 @@ +From bc34facba88e25640b4f8ae545c9c8a40d3d9650 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 10:24:51 +0800 +Subject: pppoe: drop PFC frames + +From: Qingfang Deng + +[ Upstream commit cc1ff87bce1ccd38410ab10960f576dcd17db679 ] + +RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT +RECOMMENDED for PPPoE. In practice, pppd does not support negotiating +PFC for PPPoE sessions, and the current PPPoE driver assumes an +uncompressed (2-byte) protocol field. However, the generic PPP layer +function ppp_input() is not aware of the negotiation result, and still +accepts PFC frames. + +If a peer with a broken implementation or an attacker sends a frame with +a compressed (1-byte) protocol field, the subsequent PPP payload is +shifted by one byte. This causes the network header to be 4-byte +misaligned, which may trigger unaligned access exceptions on some +architectures. + +To reduce the attack surface, drop PPPoE PFC frames. Introduce +ppp_skb_is_compressed_proto() helper function to be used in both +ppp_generic.c and pppoe.c to avoid open-coding. + +Fixes: 7fb1b8ca8fa1 ("ppp: Move PFC decompression to PPP generic layer") +Signed-off-by: Qingfang Deng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415022456.141758-2-qingfang.deng@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + drivers/net/ppp/pppoe.c | 8 +++++++- + include/linux/ppp_defs.h | 16 ++++++++++++++++ + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 89973d0959a68..df72070a3879d 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2245,7 +2245,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + */ + static void __ppp_decompress_proto(struct sk_buff *skb) + { +- if (skb->data[0] & 0x01) ++ if (ppp_skb_is_compressed_proto(skb)) + *(u8 *)skb_push(skb, 1) = 0x00; + } + +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index c6f44af35889d..1744a3e3ae2cf 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -425,7 +425,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb_mac_header_len(skb) < ETH_HLEN) + goto drop; + +- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) ++ if (!pskb_may_pull(skb, PPPOE_SES_HLEN)) + goto drop; + + ph = pppoe_hdr(skb); +@@ -435,6 +435,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb->len < len) + goto drop; + ++ /* skb->data points to the PPP protocol header after skb_pull_rcsum. ++ * Drop PFC frames. ++ */ ++ if (ppp_skb_is_compressed_proto(skb)) ++ goto drop; ++ + if (pskb_trim_rcsum(skb, len)) + goto drop; + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index b7e57fdbd4139..b1d1f46d7d3be 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -8,6 +8,7 @@ + #define _PPP_DEFS_H_ + + #include ++#include + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) +@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) + return !!((proto & 0x0101) == 0x0001); + } + ++/** ++ * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed ++ * @skb: skb to check ++ * ++ * Check if the PPP protocol field is compressed (the least significant ++ * bit of the most significant octet is 1). skb->data must point to the PPP ++ * protocol header. ++ * ++ * Return: Whether the PPP protocol field is compressed. ++ */ ++static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb) ++{ ++ return unlikely(skb->data[0] & 0x01); ++} ++ + #endif /* _PPP_DEFS_H_ */ +-- +2.53.0 + diff --git a/queue-6.1/pstore-ram-fix-resource-leak-when-ioremap-fails.patch b/queue-6.1/pstore-ram-fix-resource-leak-when-ioremap-fails.patch new file mode 100644 index 0000000000..7aaca00ddf --- /dev/null +++ b/queue-6.1/pstore-ram-fix-resource-leak-when-ioremap-fails.patch @@ -0,0 +1,52 @@ +From b2d3c8b8013adddb98a4cff400592bf6e0fe8c63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:54:06 -0700 +Subject: pstore/ram: fix resource leak when ioremap() fails + +From: Cole Leavitt + +[ Upstream commit 2ddb69f686ef7a621645e97fc7329c50edf5d0e5 ] + +In persistent_ram_iomap(), ioremap() or ioremap_wc() may return NULL on +failure. Currently, if this happens, the function returns NULL without +releasing the memory region acquired by request_mem_region(). + +This leads to a resource leak where the memory region remains reserved +but unusable. + +Additionally, the caller persistent_ram_buffer_map() handles NULL +correctly by returning -ENOMEM, but without this check, a NULL return +combined with request_mem_region() succeeding leaves resources in an +inconsistent state. + +This is the ioremap() counterpart to commit 05363abc7625 ("pstore: +ram_core: fix incorrect success return when vmap() fails") which fixed +a similar issue in the vmap() path. + +Fixes: 404a6043385d ("staging: android: persistent_ram: handle reserving and mapping memory") +Signed-off-by: Cole Leavitt +Link: https://patch.msgid.link/20260225235406.11790-1-cole@unwrap.rs +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index 0e58eb7ffac84..ed86e173f8cfc 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -489,6 +489,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, + else + va = ioremap_wc(start, size); + ++ /* We must release the mem region if ioremap fails. */ ++ if (!va) ++ release_mem_region(start, size); ++ + /* + * Since request_mem_region() and ioremap() are byte-granularity + * there is no need handle anything special like we do when the +-- +2.53.0 + diff --git a/queue-6.1/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch b/queue-6.1/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch new file mode 100644 index 0000000000..ca25864b3e --- /dev/null +++ b/queue-6.1/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch @@ -0,0 +1,148 @@ +From 9bdb6fe00aa0ae36529d2f38bb5bc1329f76d705 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 14:22:16 +0100 +Subject: quota: Fix race of dquot_scan_active() with quota deactivation + +From: Jan Kara + +[ Upstream commit e93ab401da4b2e2c1b8ef2424de2f238d51c8b2d ] + +dquot_scan_active() can race with quota deactivation in +quota_release_workfn() like: + + CPU0 (quota_release_workfn) CPU1 (dquot_scan_active) + ============================== ============================== + spin_lock(&dq_list_lock); + list_replace_init( + &releasing_dquots, &rls_head); + /* dquot X on rls_head, + dq_count == 0, + DQ_ACTIVE_B still set */ + spin_unlock(&dq_list_lock); + synchronize_srcu(&dquot_srcu); + spin_lock(&dq_list_lock); + list_for_each_entry(dquot, + &inuse_list, dq_inuse) { + /* finds dquot X */ + dquot_active(X) -> true + atomic_inc(&X->dq_count); + } + spin_unlock(&dq_list_lock); + spin_lock(&dq_list_lock); + dquot = list_first_entry(&rls_head); + WARN_ON_ONCE(atomic_read(&dquot->dq_count)); + +The problem is not only a cosmetic one as under memory pressure the +caller of dquot_scan_active() can end up working on freed dquot. + +Fix the problem by making sure the dquot is removed from releasing list +when we acquire a reference to it. + +Fixes: 869b6ea1609f ("quota: Fix slow quotaoff") +Reported-by: Sam Sun +Link: https://lore.kernel.org/all/CAEkJfYPTt3uP1vAYnQ5V2ZWn5O9PLhhGi5HbOcAzyP9vbXyjeg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/dquot.c | 38 ++++++++++++++++++++++++++++++-------- + include/linux/quotaops.h | 9 +-------- + 2 files changed, 31 insertions(+), 16 deletions(-) + +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 0f82db69d2d86..0aa0ed754f2e0 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -362,6 +362,31 @@ static inline int dquot_active(struct dquot *dquot) + return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); + } + ++static struct dquot *__dqgrab(struct dquot *dquot) ++{ ++ lockdep_assert_held(&dq_list_lock); ++ if (!atomic_read(&dquot->dq_count)) ++ remove_free_dquot(dquot); ++ atomic_inc(&dquot->dq_count); ++ return dquot; ++} ++ ++/* ++ * Get reference to dquot when we got pointer to it by some other means. The ++ * dquot has to be active and the caller has to make sure it cannot get ++ * deactivated under our hands. ++ */ ++struct dquot *dqgrab(struct dquot *dquot) ++{ ++ spin_lock(&dq_list_lock); ++ WARN_ON_ONCE(!dquot_active(dquot)); ++ dquot = __dqgrab(dquot); ++ spin_unlock(&dq_list_lock); ++ ++ return dquot; ++} ++EXPORT_SYMBOL_GPL(dqgrab); ++ + static inline int dquot_dirty(struct dquot *dquot) + { + return test_bit(DQ_MOD_B, &dquot->dq_flags); +@@ -640,15 +665,14 @@ int dquot_scan_active(struct super_block *sb, + continue; + if (dquot->dq_sb != sb) + continue; +- /* Now we have active dquot so we can just increase use count */ +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqput(old_dquot); + old_dquot = dquot; + /* + * ->release_dquot() can be racing with us. Our reference +- * protects us from new calls to it so just wait for any +- * outstanding call and recheck the DQ_ACTIVE_B after that. ++ * protects us from dquot_release() proceeding so just wait for ++ * any outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (dquot_active(dquot)) { +@@ -716,7 +740,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) + /* Now we have active dquot from which someone is + * holding reference so we can safely just increase + * use count */ +- dqgrab(dquot); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + err = dquot_write_dquot(dquot); + if (err && !ret) +@@ -971,9 +995,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_LOOKUPS); + } else { +- if (!atomic_read(&dquot->dq_count)) +- remove_free_dquot(dquot); +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_CACHE_HITS); + dqstats_inc(DQST_LOOKUPS); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 3abd249ec3373..7078e6f2429af 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -44,14 +44,7 @@ int dquot_initialize(struct inode *inode); + bool dquot_initialize_needed(struct inode *inode); + void dquot_drop(struct inode *inode); + struct dquot *dqget(struct super_block *sb, struct kqid qid); +-static inline struct dquot *dqgrab(struct dquot *dquot) +-{ +- /* Make sure someone else has active reference to dquot */ +- WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); +- WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); +- atomic_inc(&dquot->dq_count); +- return dquot; +-} ++struct dquot *dqgrab(struct dquot *dquot); + + static inline bool dquot_is_busy(struct dquot *dquot) + { +-- +2.53.0 + diff --git a/queue-6.1/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch b/queue-6.1/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch new file mode 100644 index 0000000000..6b625fa006 --- /dev/null +++ b/queue-6.1/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch @@ -0,0 +1,41 @@ +From 960314f3d0c8e6df3a4870505f849d040e979939 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:39:23 +0800 +Subject: r8152: fix incorrect register write to USB_UPHY_XTAL + +From: Chih Kai Hsu + +[ Upstream commit 48afd5124fd6129c46fd12cb06155384b1c4a0c4 ] + +The old code used ocp_write_byte() to clear the OOBS_POLLING bit +(BIT(8)) in the USB_UPHY_XTAL register, but this doesn't correctly +clear a bit in the upper byte of the 16-bit register. + +Fix this by using ocp_write_word() instead. + +Fixes: 195aae321c82 ("r8152: support new chips") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Link: https://patch.msgid.link/20260326073925.32976-454-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 15979cd7d15ae..98e30291b0500 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -3748,7 +3748,7 @@ static void r8156_ups_en(struct r8152 *tp, bool enable) + case RTL_VER_15: + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL); + ocp_data &= ~OOBS_POLLING; +- ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); ++ ocp_write_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); + break; + default: + break; +-- +2.53.0 + diff --git a/queue-6.1/rdma-core-prefer-nla_nul_string.patch b/queue-6.1/rdma-core-prefer-nla_nul_string.patch new file mode 100644 index 0000000000..ed56bb9d53 --- /dev/null +++ b/queue-6.1/rdma-core-prefer-nla_nul_string.patch @@ -0,0 +1,56 @@ +From 815b06d1327e61ba1dcdc80cf56c828156eb1a5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:27:39 +0200 +Subject: RDMA/core: Prefer NLA_NUL_STRING + +From: Florian Westphal + +[ Upstream commit 6ed3d14fc45d3da6025e7fe4a6a09066856698e2 ] + +These attributes are evaluated as c-string (passed to strcmp), but +NLA_STRING doesn't check for the presence of a \0 terminator. + +Either this needs to switch to nla_strcmp() and needs to adjust printf fmt +specifier to not use plain %s, or this needs to use NLA_NUL_STRING. + +As the code has been this way for long time, it seems to me that userspace +does include the terminating nul, even tough its not enforced so far, and +thus NLA_NUL_STRING use is the simpler solution. + +Fixes: 30dc5e63d6a5 ("RDMA/core: Add support for iWARP Port Mapper user space service") +Link: https://patch.msgid.link/r/20260330122742.13315-1-fw@strlen.de +Signed-off-by: Florian Westphal +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwpm_msg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c +index 3c9a9869212bb..feb09008eb9ca 100644 +--- a/drivers/infiniband/core/iwpm_msg.c ++++ b/drivers/infiniband/core/iwpm_msg.c +@@ -365,9 +365,9 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) + /* netlink attribute policy for the received response to register pid request */ + static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { + [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, +- [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_DEVNAME_SIZE - 1 }, +- [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, + [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } +@@ -677,7 +677,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) + + /* netlink attribute policy for the received request for mapping info */ + static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { +- [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } + }; +-- +2.53.0 + diff --git a/queue-6.1/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch b/queue-6.1/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch new file mode 100644 index 0000000000..d24b23818f --- /dev/null +++ b/queue-6.1/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch @@ -0,0 +1,51 @@ +From f71c386f2c248ec313676635f46b82dff0ff4af6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 18:00:10 +0000 +Subject: rtc: abx80x: Disable alarm feature if no interrupt attached + +From: Anthony Pighin (Nokia) + +[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ] + +Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting +alarm") exposed an issue where the rtc-abx80x driver does not clear the +alarm feature bit, but instead relies on the set_alarm operation to return +invalid. + +For example, when a RTC_UIE_ON ioctl is handled, it should abort at the +feature validation. Instead, it proceeds to the rtc_timer_enqueue(), +which used to return an error from the set_alarm call. However, +following the race condition handling, which likely should not be +discarding predecing errors, a success condition is returned to the +ioctl() caller. This results in (for example): + hwclock: select() to /dev/rtc0 to wait for clock tick timed out + +Notwithstanding the validity of the race condition handling, if an interrupt +wasn't specified, or could not be attached, the driver should clear the +alarm feature bit. + +Fixes: 718a820a303c ("rtc: abx80x: add alarm support") +Signed-off-by: Anthony Pighin +Link: https://patch.msgid.link/BN0PR08MB69510928028C933749F4139383D1A@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-abx80x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c +index 2ea6fdd2ae984..651270e5f1e66 100644 +--- a/drivers/rtc/rtc-abx80x.c ++++ b/drivers/rtc/rtc-abx80x.c +@@ -836,6 +836,8 @@ static int abx80x_probe(struct i2c_client *client, + client->irq = 0; + } + } ++ if (client->irq <= 0) ++ clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); + + err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); + if (err) { +-- +2.53.0 + diff --git a/queue-6.1/sched-psi-fix-race-between-file-release-and-pressure.patch b/queue-6.1/sched-psi-fix-race-between-file-release-and-pressure.patch new file mode 100644 index 0000000000..9efc19b89c --- /dev/null +++ b/queue-6.1/sched-psi-fix-race-between-file-release-and-pressure.patch @@ -0,0 +1,184 @@ +From 8a12efe5af86a1d188d64387576ccdcceef08b78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 14:15:43 +0800 +Subject: sched/psi: fix race between file release and pressure write + +From: Edward Adam Davis + +[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ] + +A potential race condition exists between pressure write and cgroup file +release regarding the priv member of struct kernfs_open_file, which +triggers the uaf reported in [1]. + +Consider the following scenario involving execution on two separate CPUs: + + CPU0 CPU1 + ==== ==== + vfs_rmdir() + kernfs_iop_rmdir() + cgroup_rmdir() + cgroup_kn_lock_live() + cgroup_destroy_locked() + cgroup_addrm_files() + cgroup_rm_file() + kernfs_remove_by_name() + kernfs_remove_by_name_ns() + vfs_write() __kernfs_remove() + new_sync_write() kernfs_drain() + kernfs_fop_write_iter() kernfs_drain_open_files() + cgroup_file_write() kernfs_release_file() + pressure_write() cgroup_file_release() + ctx = of->priv; + kfree(ctx); + of->priv = NULL; + cgroup_kn_unlock() + cgroup_kn_lock_live() + cgroup_get(cgrp) + cgroup_kn_unlock() + if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv + +The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards +the memory deallocation of of->priv performed within cgroup_file_release(). +However, the operations involving of->priv executed within pressure_write() +are not entirely covered by the protection of cgroup_mutex. Consequently, +if the code in pressure_write(), specifically the section handling the +ctx variable executes after cgroup_file_release() has completed, a uaf +vulnerability involving of->priv is triggered. + +Therefore, the issue can be resolved by extending the scope of the +cgroup_mutex lock within pressure_write() to encompass all code paths +involving of->priv, thereby properly synchronizing the race condition +occurring between cgroup_file_release() and pressure_write(). + +And, if an live kn lock can be successfully acquired while executing +the pressure write operation, it indicates that the cgroup deletion +process has not yet reached its final stage; consequently, the priv +pointer within open_file cannot be NULL. Therefore, the operation to +retrieve the ctx value must be moved to a point *after* the live kn +lock has been successfully acquired. + +In another situation, specifically after entering cgroup_kn_lock_live() +but before acquiring cgroup_mutex, there exists a different class of +race condition: + +CPU0: write memory.pressure CPU1: write cgroup.pressure=0 +=========================== ============================= + +kernfs_fop_write_iter() + kernfs_get_active_of(of) + pressure_write() + cgroup_kn_lock_live(memory.pressure) + cgroup_tryget(cgrp) + kernfs_break_active_protection(kn) + ... blocks on cgroup_mutex + + cgroup_pressure_write() + cgroup_kn_lock_live(cgroup.pressure) + cgroup_file_show(memory.pressure, false) + kernfs_show(false) + kernfs_drain_open_files() + cgroup_file_release(of) + kfree(ctx) + of->priv = NULL + cgroup_kn_unlock() + + ... acquires cgroup_mutex + ctx = of->priv; // may now be NULL + if (ctx->psi.trigger) // NULL dereference + +Consequently, there is a possibility that of->priv is NULL, the pressure +write needs to check for this. + +Now that the scope of the cgroup_mutex has been expanded, the original +explicit cgroup_get/put operations are no longer necessary, this is +because acquiring/releasing the live kn lock inherently executes a +cgroup get/put operation. + +[1] +BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 +Call Trace: + pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 + cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 + kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 + +Allocated by task 9352: + cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 + kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 + do_dentry_open+0x83d/0x13e0 fs/open.c:949 + +Freed by task 9353: + cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 + kernfs_release_file fs/kernfs/file.c:764 [inline] + kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 + kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525 + +Fixes: 0e94682b73bf ("psi: introduce psi monitor") +Reported-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=33e571025d88efd1312c +Tested-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Reviewed-by: Chen Ridong +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 5ff7619301458..606d17021e3e1 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -3786,33 +3786,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) + static ssize_t pressure_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, enum psi_res res) + { +- struct cgroup_file_ctx *ctx = of->priv; ++ struct cgroup_file_ctx *ctx; + struct psi_trigger *new; + struct cgroup *cgrp; + struct psi_group *psi; ++ ssize_t ret = 0; + + cgrp = cgroup_kn_lock_live(of->kn, false); + if (!cgrp) + return -ENODEV; + +- cgroup_get(cgrp); +- cgroup_kn_unlock(of->kn); ++ ctx = of->priv; ++ if (!ctx) { ++ ret = -ENODEV; ++ goto out_unlock; ++ } + + /* Allow only one trigger per file descriptor */ + if (ctx->psi.trigger) { +- cgroup_put(cgrp); +- return -EBUSY; ++ ret = -EBUSY; ++ goto out_unlock; + } + + psi = cgroup_psi(cgrp); + new = psi_trigger_create(psi, buf, res, of->file, of); + if (IS_ERR(new)) { +- cgroup_put(cgrp); +- return PTR_ERR(new); ++ ret = PTR_ERR(new); ++ goto out_unlock; + } + + smp_store_release(&ctx->psi.trigger, new); +- cgroup_put(cgrp); ++ ++out_unlock: ++ cgroup_kn_unlock(of->kn); ++ if (ret) ++ return ret; + + return nbytes; + } +-- +2.53.0 + diff --git a/queue-6.1/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch b/queue-6.1/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch new file mode 100644 index 0000000000..f5152955a0 --- /dev/null +++ b/queue-6.1/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch @@ -0,0 +1,100 @@ +From 912d49d792defa958f64db707f1c5ec860f69c1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:43 +0800 +Subject: scsi: sg: Resolve soft lockup issue when opening /dev/sgX + +From: Yang Erkun + +[ Upstream commit d06a310b45e153872033dd0cf19d5a2279121099 ] + +The parameter def_reserved_size defines the default buffer size reserved +for each Sg_fd and should be restricted to a range between 0 and 1,048,576 +(see https://tldp.org/HOWTO/SCSI-Generic-HOWTO/proc.html). Although the +function sg_proc_write_dressz enforces this limit, it is possible to bypass +it by directly modifying the module parameter as shown below, which then +causes a soft lockup: + +echo -1 > /sys/module/sg/parameters/def_reserved_size +exec 4<> /dev/sg0 + +watchdog: BUG: soft lockup - CPU#5 stuck for 26 seconds! [bash:537] +Modules loaded: +CPU: 5 UID: 0 PID: 537 Command: bash, kernel version 6.19.0-rc3+ #134, +PREEMPT disabled +Hardware: QEMU Standard PC (i440FX + PIIX, 1996), BIOS version +1.16.1-2.fc37 dated 04/01/2014 +... +Call Trace: + + sg_build_reserve+0x5c/0xa0 + sg_add_sfp+0x168/0x270 + sg_open+0x16e/0x340 + chrdev_open+0xbe/0x230 + do_dentry_open+0x175/0x480 + vfs_open+0x34/0xf0 + do_open+0x265/0x3d0 + path_openat+0x110/0x290 + do_filp_open+0xc3/0x170 + do_sys_openat2+0x71/0xe0 + __x64_sys_openat+0x6d/0xa0 + do_syscall_64+0x62/0x310 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The fix is to use module_param_cb to validate and reject invalid values +assigned to def_reserved_size. + +Fixes: 6460e75a104d ("[SCSI] sg: fixes for large page_size") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-3-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index b63f7c09c97a1..a7131500eafe7 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1614,10 +1614,35 @@ sg_remove_device(struct device *cl_dev, struct class_interface *cl_intf) + } + + module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +-module_param_named(def_reserved_size, def_reserved_size, int, +- S_IRUGO | S_IWUSR); + module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); + ++static int def_reserved_size_set(const char *val, const struct kernel_param *kp) ++{ ++ int size, ret; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtoint(val, 0, &size); ++ if (ret) ++ return ret; ++ ++ /* limit to 1 MB */ ++ if (size < 0 || size > 1048576) ++ return -ERANGE; ++ ++ def_reserved_size = size; ++ return 0; ++} ++ ++static const struct kernel_param_ops def_reserved_size_ops = { ++ .set = def_reserved_size_set, ++ .get = param_get_int, ++}; ++ ++module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, ++ S_IRUGO | S_IWUSR); ++ + MODULE_AUTHOR("Douglas Gilbert"); + MODULE_DESCRIPTION("SCSI generic (sg) driver"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.1/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch b/queue-6.1/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch new file mode 100644 index 0000000000..788e7d45c9 --- /dev/null +++ b/queue-6.1/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch @@ -0,0 +1,42 @@ +From 116e71be60a5460f7d511238ef92ce085157eea3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 23:42:58 +0800 +Subject: scsi: target: core: Fix integer overflow in UNMAP bounds check + +From: Junrui Luo + +[ Upstream commit 2bf2d65f76697820dbc4227d13866293576dd90a ] + +sbc_execute_unmap() checks LBA + range does not exceed the device capacity, +but does not guard against LBA + range wrapping around on 64-bit overflow. + +Add an overflow check matching the pattern already used for WRITE_SAME in +the same file. + +Fixes: 86d7182985d2 ("target: Add sbc_execute_unmap() helper") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881593C61AD52C69FBDB0BDAF7CA@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/target/target_core_sbc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c +index 1e3216de1e04d..7b08743c4f3ff 100644 +--- a/drivers/target/target_core_sbc.c ++++ b/drivers/target/target_core_sbc.c +@@ -1133,7 +1133,8 @@ sbc_execute_unmap(struct se_cmd *cmd) + goto err; + } + +- if (lba + range > dev->transport->get_blocks(dev) + 1) { ++ if (lba + range < lba || ++ lba + range > dev->transport->get_blocks(dev) + 1) { + ret = TCM_ADDRESS_OUT_OF_RANGE; + goto err; + } +-- +2.53.0 + diff --git a/queue-6.1/sctp-discard-stale-init-after-handshake-completion.patch b/queue-6.1/sctp-discard-stale-init-after-handshake-completion.patch new file mode 100644 index 0000000000..d334a3f9cb --- /dev/null +++ b/queue-6.1/sctp-discard-stale-init-after-handshake-completion.patch @@ -0,0 +1,49 @@ +From dbbd4f1ec6e0bfb56b3477696772a1f70666c0a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:41 -0400 +Subject: sctp: discard stale INIT after handshake completion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Xin Long + +[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ] + +After an association reaches ESTABLISHED, the peer’s init_tag is already +known from the handshake. Any subsequent INIT with the same init_tag is +not a valid restart, but a delayed or duplicate INIT. + +Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of +processing them as new association attempts. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/5788c76c1ee122a3ed00189e88dcf9df1fba226c.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 80a6b9fc964e5..1685f73602d5e 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( + /* Tag the variable length parameters. */ + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); + ++ if (asoc->state >= SCTP_STATE_ESTABLISHED) { ++ /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ ++ if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) ++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ } ++ + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, +-- +2.53.0 + diff --git a/queue-6.1/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch b/queue-6.1/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch new file mode 100644 index 0000000000..7d142342ec --- /dev/null +++ b/queue-6.1/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch @@ -0,0 +1,44 @@ +From 9cb90e1829ecc621aae630f4359173583b7e6157 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 14:13:51 -0400 +Subject: sctp: fix missing encap_port propagation for GSO fragments + +From: Xin Long + +[ Upstream commit bf6f95ae3b8b2638c0e1d6d802d50983ce5d0f45 ] + +encap_port in SCTP_INPUT_CB(skb) is used by sctp_vtag_verify() for +SCTP-over-UDP processing. In the GSO case, it is only set on the head +skb, while fragment skbs leave it 0. + +This results in fragment skbs seeing encap_port == 0, breaking +SCTP-over-UDP connections. + +Fix it by propagating encap_port from the head skb cb when initializing +fragment skbs in sctp_inq_pop(). + +Fixes: 046c052b475e ("sctp: enable udp tunneling socks") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/ea65ed61b3598d8b4940f0170b9aa1762307e6c3.1776017631.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/inqueue.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c +index f5a7d5a387555..a024c08432471 100644 +--- a/net/sctp/inqueue.c ++++ b/net/sctp/inqueue.c +@@ -201,6 +201,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + + cb->chunk = head_cb->chunk; + cb->af = head_cb->af; ++ cb->encap_port = head_cb->encap_port; + } + } + +-- +2.53.0 + diff --git a/queue-6.1/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch b/queue-6.1/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch new file mode 100644 index 0000000000..7c8e4bed7c --- /dev/null +++ b/queue-6.1/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch @@ -0,0 +1,68 @@ +From 3c87a61bc4bc0cd41733e190d4151158a8412a01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 23:19:03 -0400 +Subject: sctp: fix OOB write to userspace in sctp_getsockopt_peer_auth_chunks + +From: Michael Bommarito + +[ Upstream commit 0cf004ffb61cd32d140531c3a84afe975f9fc7ea ] + +sctp_getsockopt_peer_auth_chunks() checks that the caller's optval +buffer is large enough for the peer AUTH chunk list with + + if (len < num_chunks) + return -EINVAL; + +but then writes num_chunks bytes to p->gauth_chunks, which lives +at offset offsetof(struct sctp_authchunks, gauth_chunks) == 8 +inside optval. The check is missing the sizeof(struct +sctp_authchunks) = 8-byte header. When the caller supplies +len == num_chunks (for any num_chunks > 0) the test passes but +copy_to_user() writes sizeof(struct sctp_authchunks) = 8 bytes +past the declared buffer. + +The sibling function sctp_getsockopt_local_auth_chunks() at the +next line already has the correct check: + + if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + +Align the peer variant with its sibling. + +Reproducer confirms on v7.0-13-generic: an unprivileged userspace +caller that opens a loopback SCTP association with AUTH enabled, +queries num_chunks with a short optval, then issues the real +getsockopt with len == num_chunks and sentinel bytes painted past +the buffer observes those sentinel bytes overwritten with the +peer's AUTH chunk type. The bytes written are under the peer's +control but land in the caller's own userspace; this is not a +kernel memory corruption, but it is a kernel-side contract +violation that can silently corrupt adjacent userspace data. + +Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260416031903.1447072-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index dfc613859ff58..b544f403f7ca8 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -6995,7 +6995,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, + + /* See if the user provided enough room for all the data */ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); +- if (len < num_chunks) ++ if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + + if (copy_to_user(to, ch->chunks, num_chunks)) +-- +2.53.0 + diff --git a/queue-6.1/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch b/queue-6.1/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch new file mode 100644 index 0000000000..d1556f9872 --- /dev/null +++ b/queue-6.1/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch @@ -0,0 +1,75 @@ +From 24464b7b77efe9ab0e8e20947f1837d460563329 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 16:05:26 -0400 +Subject: selftest: memcg: skip memcg_sock test if address family not supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Waiman Long + +[ Upstream commit 2d028f3e4bbbfd448928a8d3d2814b0b04c214f4 ] + +The test_memcg_sock test in memcontrol.c sets up an IPv6 socket and send +data over it to consume memory and verify that memory.stat.sock and +memory.current values are close. + +On systems where IPv6 isn't enabled or not configured to support +SOCK_STREAM, the test_memcg_sock test always fails. When the socket() +call fails, there is no way we can test the memory consumption and verify +the above claim. I believe it is better to just skip the test in this +case instead of reporting a test failure hinting that there may be +something wrong with the memcg code. + +Link: https://lkml.kernel.org/r/20260311200526.885899-1-longman@redhat.com +Fixes: 5f8f019380b8 ("selftests: cgroup/memcontrol: add basic test for socket accounting") +Signed-off-by: Waiman Long +Acked-by: Michal Koutný +Acked-by: Shakeel Butt +Cc: Johannes Weiner +Cc: Michal Hocko +Cc: Michal Koutný +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Roman Gushchin +Cc: Shuah Khan +Cc: Tejun Heo +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/cgroup/test_memcontrol.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c +index 5a526a8e7d333..e75ff9289e419 100644 +--- a/tools/testing/selftests/cgroup/test_memcontrol.c ++++ b/tools/testing/selftests/cgroup/test_memcontrol.c +@@ -921,8 +921,11 @@ static int tcp_server(const char *cgroup, void *arg) + saddr.sin6_port = htons(srv_args->port); + + sk = socket(AF_INET6, SOCK_STREAM, 0); +- if (sk < 0) ++ if (sk < 0) { ++ /* Pass back errno to the ctl_fd */ ++ write(ctl_fd, &errno, sizeof(errno)); + return ret; ++ } + + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + goto cleanup; +@@ -1049,6 +1052,12 @@ static int test_memcg_sock(const char *root) + goto cleanup; + close(args.ctl[0]); + ++ /* Skip if address family not supported by protocol */ ++ if (err == EAFNOSUPPORT) { ++ ret = KSFT_SKIP; ++ goto cleanup; ++ } ++ + if (!err) + break; + if (err != EADDRINUSE) +-- +2.53.0 + diff --git a/queue-6.1/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch b/queue-6.1/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch new file mode 100644 index 0000000000..55e3953516 --- /dev/null +++ b/queue-6.1/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch @@ -0,0 +1,58 @@ +From d8ca2bc47f8772cfd70b9281592e2c639c59a59c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:39:41 -0500 +Subject: selftests/mm: skip migration tests if NUMA is unavailable + +From: AnishMulay + +[ Upstream commit 54218f10dfbe88c8e41c744fd45a756cde60b8c4 ] + +Currently, the migration test asserts that numa_available() returns 0. On +systems where NUMA is not available (returning -1), such as certain ARM64 +configurations or single-node systems, this assertion fails and crashes +the test. + +Update the test to check the return value of numa_available(). If it is +less than 0, skip the test gracefully instead of failing. + +This aligns the behavior with other MM selftests (like rmap) that skip +when NUMA support is missing. + +Link: https://lkml.kernel.org/r/20260218163941.13499-1-anishm7030@gmail.com +Fixes: 0c2d08728470 ("mm: add selftests for migration entries") +Signed-off-by: AnishMulay +Reviewed-by: SeongJae Park +Reviewed-by: Dev Jain +Reviewed-by: Anshuman Khandual +Tested-by: Sayali Patil +Acked-by: David Hildenbrand (Arm) +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/vm/migration.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/vm/migration.c b/tools/testing/selftests/vm/migration.c +index 1cec8425e3caa..6ea9826e6f979 100644 +--- a/tools/testing/selftests/vm/migration.c ++++ b/tools/testing/selftests/vm/migration.c +@@ -32,7 +32,8 @@ FIXTURE_SETUP(migration) + { + int n; + +- ASSERT_EQ(numa_available(), 0); ++ if (numa_available() < 0) ++ SKIP(return, "NUMA not available"); + self->nthreads = numa_num_task_cpus() - 1; + self->n1 = -1; + self->n2 = -1; +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index 757f8e66f6..c2b5851e8e 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -430,3 +430,365 @@ drm-amdgpu-vcn3-avoid-overflow-on-msg-bound-check.patch drm-amdgpu-vcn4-avoid-overflow-on-msg-bound-check.patch mtd-spi-nor-sst-fix-sst-write-failure.patch bcache-fix-uninitialized-closure-object.patch +blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch +fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch +drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch +nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch +pstore-ram-fix-resource-leak-when-ioremap-fails.patch +devres-fix-missing-node-debug-info-in-devm_krealloc.patch +thermal-drivers-spear-fix-error-condition-for-readin.patch +debugfs-check-for-null-pointer-in-debugfs_create_str.patch +irqchip-irq-pic32-evic-address-warning-related-to-wr.patch +hrtimers-update-the-return-type-of-enqueue_hrtimer.patch +hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch +hrtimer-reduce-trace-noise-in-hrtimer_start.patch +locking-fix-rwlock-support-in-linux-spinlock_up.h.patch +firmware-dmi-correct-an-indexing-error-in-dmi.h.patch +wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch +wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch +bpf-add-checksum_complete-to-bpf-test-progs.patch +bpf-test_run-fix-the-null-pointer-dereference-issue-.patch +dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch +dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch +kernel-param-rename-locate_module_kobject.patch +kernel-globalize-lookup_or_create_module_kobject.patch +params-replace-__modinit-with-__init_or_module.patch +module-fix-freeing-of-charp-module-parameters-when-c.patch +bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch +bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch +wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch +r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch +powerpc-crash-fix-backup-region-offset-update-to-elf.patch +macvlan-annotate-data-races-around-port-bc_queue_len.patch +bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch +wifi-brcmfmac-fix-error-pointer-dereference.patch +bpf-drop-task_to_inode-and-inet_conn_established-fro.patch +bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch +acpi-agdi-fix-missing-newline-in-error-message.patch +arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch +net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch +net-bcmgenet-remove-tx-ring-full-logging.patch +net-bcmgenet-remove-custom-ndo_poll_controller.patch +net-bcmgenet-add-bcmgenet_has_-helpers.patch +net-bcmgenet-move-desc_index-flow-to-ring-0.patch +net-bcmgenet-support-reclaiming-unsent-tx-packets.patch +net-bcmgenet-switch-to-use-64bit-statistics.patch +net-bcmgenet-fix-racing-timeout-handler.patch +netfilter-xt_socket-enable-defrag-after-all-other-ch.patch +netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch +6pack-propagage-new-tty-types.patch +net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch +net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch +net-rds-optimize-rds_ib_laddr_check.patch +net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch +ppp-require-cap_net_admin-in-target-netns-for-unatta.patch +bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch +bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch +bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch +bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch +bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch +sctp-fix-missing-encap_port-propagation-for-gso-frag.patch +net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch +drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch +drm-sun4i-backend-fix-error-pointer-dereference.patch +asoc-sti-return-errors-from-regmap_field_alloc.patch +asoc-sti-use-managed-regmap_field-allocations.patch +dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch +dm-cache-fix-write-path-cache-coherency-in-passthrou.patch +dm-cache-fix-write-hang-in-passthrough-mode.patch +dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch +dm-cache-fix-concurrent-write-failure-in-passthrough.patch +dm-cache-support-shrinking-the-origin-device.patch +dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch +dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch +dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch +spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch +drm-sun4i-fix-resource-leaks.patch +drm-amdgpu-add-default-case-in-dvi-mode-validation.patch +dm-init-ensure-device-probing-has-finished-in-dm-mod.patch +fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch +padata-remove-cpu-online-check-from-cpu-add-and-remo.patch +padata-put-cpu-offline-callback-in-online-section-to.patch +drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch +spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch +drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch +drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch +drm-panel-simple-correct-g190ean01-prepare-timing.patch +alsa-core-validate-compress-device-numbers-without-d.patch +drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch +drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch +drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch +drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch +drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch +drm-amd-pm-ci-fill-dw8-fields-from-smc.patch +drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch +alsa-hda-realtek-whitespace-fix.patch +alsa-hda-realtek-fix-code-style-error-else-should-fo.patch +drm-msm-a6xx-fix-hlsq-register-dumping.patch +drm-msm-shrinker-fix-can_block-logic.patch +drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch +pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch +pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch +asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch +asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch +asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch +asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch +pci-enable-atomicops-only-if-root-port-supports-them.patch +pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch +selftests-mm-skip-migration-tests-if-numa-is-unavail.patch +documentation-fix-a-hugetlbfs-reservation-statement.patch +selftest-memcg-skip-memcg_sock-test-if-address-famil.patch +alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch +asoc-sof-amd-fix-for-reading-position-updates-from-s.patch +asoc-sof-prepare-ipc_msg_data-to-be-used-with-compre.patch +asoc-sof-prepare-set_stream_data_offset-for-compress.patch +asoc-sof-add-support-for-compress-api-for-stream-dat.patch +asoc-sof-compress-return-the-configured-codec-from-g.patch +pci-add-pcie_pme_to_l2_timeout_us-l2-ready-timeout-v.patch +pci-tegra194-fix-polling-delay-for-l2-state.patch +pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch +pci-tegra194-disable-ltssm-after-transition-to-detec.patch +pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch +pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch +pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch +pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch +pci-tegra194-disable-direct-speed-change-for-endpoin.patch +pci-tegra194-allow-system-suspend-when-the-endpoint-.patch +spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch +alsa-sc6000-use-standard-print-api.patch +alsa-sc6000-keep-the-programmed-board-state-in-card-.patch +dm-cache-fix-missing-return-in-invalidate_committed-.patch +gfs2-call-unlock_new_inode-before-d_instantiate.patch +ktest-avoid-undef-warning-when-warnings_file-is-unse.patch +ktest-honor-empty-per-test-option-overrides.patch +ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch +quota-fix-race-of-dquot_scan_active-with-quota-deact.patch +gfs2-add-some-missing-log-locking.patch +gfs2-prevent-null-pointer-dereference-during-unmount.patch +efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch +ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch +arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch +memory-tegra124-emc-fix-dll_change-check.patch +memory-tegra30-emc-fix-dll_change-check.patch +arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch +arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch +arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch +soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch +soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch +soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch +arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch +soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch +unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch +ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch +ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch +soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch +soc-qcom-aoss-compare-against-normalized-cooling-sta.patch +arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch +arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch +arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch +ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch +ocfs2-validate-bg_bits-during-freefrag-scan.patch +ocfs2-validate-group-add-input-before-caching.patch +dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch +soundwire-bus-demote-unattached-state-warnings-to-de.patch +dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch +tracing-rebuild-full_name-on-each-hist_field_name-ca.patch +ima-check-return-value-of-crypto_shash_final-in-boot.patch +hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch +hid-asus-do-not-abort-probe-when-not-necessary.patch +mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch +mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch +mtd-spi-nor-spansion-rename-s28hs512t-prefix.patch +mtd-spi-nor-spansion-replace-hardcoded-values-for-ad.patch +mtd-spi-nor-spansion-make-rd_any_reg_op-macro-take-n.patch +mtd-spi-nor-spansion-add-support-for-infineon-s25fs2.patch +mtd-spi-nor-allow-post_sfdp-hook-to-return-errors.patch +mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch +mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch +mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch +mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch +mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch +mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch +mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch +hid-usbhid-fix-deadlock-in-hid_post_reset.patch +bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch +bpf-sockmap-fix-af_unix-iter-deadlock.patch +bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch +bpf-sockmap-take-state-lock-for-af_unix-iter.patch +bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch +bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch +bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch +pinctrl-pinctrl-pic32-fix-resource-leak.patch +pinctrl-cy8c95x0-remove-duplicate-error-message.patch +pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch +pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch +perf-branch-avoid-incrementing-null.patch +perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch +pinctrl-abx500-fix-type-of-argument-variable.patch +perf-tools-fix-module-symbol-resolution-for-non-zero.patch +perf-expr-return-einval-for-syntax-error-in-expr__fi.patch +perf-util-kill-die-prototype-dead-for-a-long-time.patch +i3c-master-fix-error-codes-at-send_ccc_cmd.patch +i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch +driver-core-device.h-remove-extern-from-function-pro.patch +driver-core-move-dev_err_probe-to-where-it-belogs.patch +dev_printk-add-new-dev_err_probe-helpers.patch +backlight-sky81452-backlight-check-return-value-of-d.patch +platform-surface-surfacepro3_button-drop-wakeup-sour.patch +leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch +tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch +platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch +mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch +nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch +fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch +platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch +platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch +rdma-core-prefer-nla_nul_string.patch +clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch +scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch +scsi-target-core-fix-integer-overflow-in-unmap-bound.patch +dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch +clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch +clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch +clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch +clk-imx8mq-correct-the-csi-phy-sels.patch +clk-qoriq-avoid-format-string-warning.patch +clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch +dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch +clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch +lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch +clk-visconti-pll-initialize-clk_init_data-to-zero.patch +f2fs-use-sysfs_emit_at-to-simplify-code.patch +f2fs-protect-extension_list-reading-with-sb_lock-in-.patch +drm-i915-constify-watermark-state-checker.patch +drm-i915-extract-intel_dbuf_mdclk_cdclk_ratio_update.patch +drm-i915-loop-over-all-active-pipes-in-intel_mbus_db.patch +drm-i915-wm-verify-the-correct-plane-ddb-entry.patch +crypto-sa2ul-fix-aead-fallback-algorithm-names.patch +crypto-ccp-copy-iv-using-skcipher-ivsize.patch +arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch +arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch +pcmcia-fix-garbled-log-messages-for-kern_cont.patch +arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch +arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch +net-sched-sch_cake-fix-nat-destination-port-not-bein.patch +nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch +net-sched-taprio-continue-with-other-txqs-if-one-deq.patch +net-sched-taprio-refactor-one-skb-dequeue-from-txq-t.patch +net-sched-taprio-rename-close_time-to-end_time.patch +net-sched-taprio-fix-use-after-free-in-advance_sched.patch +container_of-remove-container_of_safe.patch +container_of-add-container_of_const-that-preserves-c.patch +tcp-preserve-const-qualifier-in-tcp_sk.patch +tcp-add-data-race-annotations-around-tp-data_segs_ou.patch +tcp-annotate-data-races-around-tp-bytes_sent.patch +tcp-annotate-data-races-around-tp-bytes_retrans.patch +tcp-annotate-data-races-around-tp-dsack_dups.patch +tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch +i40e-don-t-advertise-iff_supp_nofcs.patch +e1000e-unroll-ptp-in-probe-error-handling.patch +ipv6-fix-possible-uaf-in-icmpv6_rcv.patch +sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch +pppoe-drop-pfc-frames.patch +openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch +netfilter-nft_osf-restrict-it-to-ipv4.patch +netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch +netfilter-conntrack-remove-sprintf-usage.patch +netfilter-xtables-restrict-several-matches-to-inet-f.patch +ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch +netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch +netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch +slip-reject-vj-receive-packets-on-instances-with-no-.patch +slip-bound-decode-reads-against-the-compressed-packe.patch +arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch +ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch +ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch +net-rds-zero-per-item-info-buffer-before-handing-it-.patch +net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch +net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch +net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch +net-sched-sch_red-annotate-data-races-in-red_dump_st.patch +net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch +net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch +nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch +tipc-fix-double-free-in-tipc_buf_append.patch +vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch +fs-adfs-validate-nzones-in-adfs_validate_bblk.patch +rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch +fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch +mailbox-mailbox-test-free-channels-on-probe-error.patch +sched-psi-fix-race-between-file-release-and-pressure.patch +cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch +mailbox-add-sanity-check-for-channel-array.patch +mailbox-mailbox-test-don-t-free-the-reused-channel.patch +mailbox-mailbox-test-initialize-struct-earlier.patch +mailbox-mailbox-test-make-data_ready-a-per-instance-.patch +btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch +tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch +nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch +netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch +nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch +drm-amdgpu-fix-spelling-typos.patch +drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch +drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch +netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch +netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch +drivers-spi-rockchip.c-remove-redundant-variable-sla.patch +spi-rockchip-switch-to-use-modern-name.patch +spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch +cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch +netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch +net-sched-netem-fix-probability-gaps-in-4-state-loss.patch +net-sched-netem-fix-queue-limit-check-to-include-reo.patch +net-sched-netem-validate-slot-configuration.patch +net-sched-netem-fix-slot-delay-calculation-overflow.patch +net-sched-sch_choke-annotate-data-races-in-choke_dum.patch +net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch +vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch +net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch +net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch +nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch +neighbour-add-rcu-protection-to-neigh_tables.patch +neigh-let-neigh_xmit-take-skb-ownership.patch +alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch +net-mctp-i2c-check-length-before-marking-flow-active.patch +net-phy-dp83869-fix-setting-clk_o_sel-field.patch +asoc-codecs-ab8500-fix-casting-of-private-data.patch +netfilter-skip-recording-stale-or-retransmitted-init.patch +sctp-discard-stale-init-after-handshake-completion.patch +ipv4-rename-and-move-ip_route_output_tunnel.patch +ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch +ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch +ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch +bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch +net-netconsole-move-newline-trimming-to-function.patch +netconsole-propagate-device-name-truncation-in-dev_n.patch +alsa-hda-conexant-fix-some-typos.patch +alsa-hda-conexant-renaming-the-codec-with-device-id-.patch +alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch +futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch +drm-amd-display-allow-dce-link-encoder-without-aux-r.patch +drm-amd-display-read-edid-from-vbios-embedded-panel-.patch +bonding-802.3ad-replace-mac_address_equal-with-__agg.patch +net-bonding-add-broadcast_neighbor-option-for-802.3a.patch +bonding-add-support-for-per-port-lacp-actor-priority.patch +bonding-print-churn-state-via-netlink.patch +bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch +iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch +iavf-stop-removing-vlan-filters-from-pf-on-interface.patch +iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch +iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch +ice-pull-common-tasks-into-ice_vf_post_vsi_rebuild.patch +ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch +net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch +net-sched-cls_flower-revert-unintended-changes.patch diff --git a/queue-6.1/slip-bound-decode-reads-against-the-compressed-packe.patch b/queue-6.1/slip-bound-decode-reads-against-the-compressed-packe.patch new file mode 100644 index 0000000000..6a2b8d69fe --- /dev/null +++ b/queue-6.1/slip-bound-decode-reads-against-the-compressed-packe.patch @@ -0,0 +1,158 @@ +From a8f6a31d0291fa3d944380ecffef3c977b6d0f87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:01:51 +0800 +Subject: slip: bound decode() reads against the compressed packet length + +From: Weiming Shi + +[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ] + +slhc_uncompress() parses a VJ-compressed TCP header by advancing a +pointer through the packet via decode() and pull16(). Neither helper +bounds-checks against isize, and decode() masks its return with +& 0xffff so it can never return the -1 that callers test for -- those +error paths are dead code. + +A short compressed frame whose change byte requests optional fields +lets decode() read past the end of the packet. The over-read bytes +are folded into the cached cstate and reflected into subsequent +reconstructed packets. + +Make decode() and pull16() take the packet end pointer and return -1 +when exhausted. Add a bounds check before the TCP-checksum read. +The existing == -1 tests now do what they were always meant to. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Simon Horman +Closes: https://lore.kernel.org/netdev/20260414134126.758795-2-horms@kernel.org/ +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416100147.531855-5-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index 3474792a37a67..ef586ab250747 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -80,9 +80,9 @@ + #include + + static unsigned char *encode(unsigned char *cp, unsigned short n); +-static long decode(unsigned char **cpp); ++static long decode(unsigned char **cpp, const unsigned char *end); + static unsigned char * put16(unsigned char *cp, unsigned short x); +-static unsigned short pull16(unsigned char **cpp); ++static long pull16(unsigned char **cpp, const unsigned char *end); + + /* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) +@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n) + return cp; + } + +-/* Pull a 16-bit integer in host order from buffer in network byte order */ +-static unsigned short +-pull16(unsigned char **cpp) ++/* Pull a 16-bit integer in host order from buffer in network byte order. ++ * Returns -1 if the buffer is exhausted, otherwise the 16-bit value. ++ */ ++static long ++pull16(unsigned char **cpp, const unsigned char *end) + { +- short rval; ++ long rval; + ++ if (*cpp + 2 > end) ++ return -1; + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; + } + +-/* Decode a number */ ++/* Decode a number. Returns -1 if the buffer is exhausted. */ + static long +-decode(unsigned char **cpp) ++decode(unsigned char **cpp, const unsigned char *end) + { + int x; + ++ if (*cpp >= end) ++ return -1; + x = *(*cpp)++; +- if(x == 0){ +- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ +- } else { +- return x & 0xff; /* -1 if PULLCHAR returned error */ +- } ++ if (x == 0) ++ return pull16(cpp, end); ++ return x & 0xff; + } + + /* +@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; ++ const unsigned char *end = icp + isize; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; +@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + ++ if (cp + 2 > end) ++ goto bad; + thp->check = *(__sum16 *)cp; + cp += 2; + +@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + default: + if(changes & NEW_U){ + thp->urg = 1; +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); +@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + break; + } + if(changes & NEW_I){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); +-- +2.53.0 + diff --git a/queue-6.1/slip-reject-vj-receive-packets-on-instances-with-no-.patch b/queue-6.1/slip-reject-vj-receive-packets-on-instances-with-no-.patch new file mode 100644 index 0000000000..3923ae9ee7 --- /dev/null +++ b/queue-6.1/slip-reject-vj-receive-packets-on-instances-with-no-.patch @@ -0,0 +1,98 @@ +From a86789d69734714340b0f9f89a6f8210b469c8a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 04:41:31 +0800 +Subject: slip: reject VJ receive packets on instances with no rstate array + +From: Weiming Shi + +[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ] + +slhc_init() accepts rslots == 0 as a valid configuration, with the +documented meaning of 'no receive compression'. In that case the +allocation loop in slhc_init() is skipped, so comp->rstate stays +NULL and comp->rslot_limit stays 0 (from the kzalloc of struct +slcompress). + +The receive helpers do not defend against that configuration. +slhc_uncompress() dereferences comp->rstate[x] when the VJ header +carries an explicit connection ID, and slhc_remember() later assigns +cs = &comp->rstate[...] after only comparing the packet's slot number +to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the +range check, and the code dereferences a NULL rstate. + +The configuration is reachable in-tree through PPP. PPPIOCSMAXCID +stores its argument in a signed int, and (val >> 16) uses arithmetic +shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 +is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because +/dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path +is reachable from an unprivileged user namespace. Once the malformed +VJ state is installed, any inbound VJ-compressed or VJ-uncompressed +frame that selects slot 0 crashes the kernel in softirq context: + + Oops: general protection fault, probably for non-canonical + address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519) + Call Trace: + + ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466) + ppp_input (drivers/net/ppp/ppp_generic.c:2359) + ppp_async_process (drivers/net/ppp/ppp_async.c:492) + tasklet_action_common (kernel/softirq.c:926) + handle_softirqs (kernel/softirq.c:623) + run_ksoftirqd (kernel/softirq.c:1055) + smpboot_thread_fn (kernel/smpboot.c:160) + kthread (kernel/kthread.c:436) + ret_from_fork (arch/x86/kernel/process.c:164) + + +Reject the receive side on such instances instead of touching rstate. +slhc_uncompress() falls through to its existing 'bad' label, which +bumps sls_i_error and enters the toss state. slhc_remember() mirrors +that with an explicit sls_i_error increment followed by slhc_toss(); +the sls_i_runt counter is not used here because a missing rstate is +an internal configuration state, not a runt packet. + +The transmit path is unaffected: the only in-tree caller that picks +rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and +slip.c always calls slhc_init(16, 16), so comp->tstate remains valid +and slhc_compress() continues to work. + +Fixes: 4ab42d78e37a ("ppp, slip: Validate VJ compression slot parameters completely") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415204130.258866-2-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index bf9e801cc61cc..3474792a37a67 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + comp->sls_i_error++; + return 0; + } ++ if (!comp->rstate) ++ goto bad; + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. +@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + unsigned int ihl; + ++ if (!comp->rstate) { ++ comp->sls_i_error++; ++ return slhc_toss(comp); ++ } + /* The packet is shorter than a legal IP header. + * Also make sure isize is positive. + */ +-- +2.53.0 + diff --git a/queue-6.1/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch b/queue-6.1/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch new file mode 100644 index 0000000000..074502247f --- /dev/null +++ b/queue-6.1/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch @@ -0,0 +1,41 @@ +From 73c4096fcd8c259703be90558113c4e6e8850696 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 12:53:23 -0700 +Subject: soc: qcom: aoss: compare against normalized cooling state + +From: Alok Tiwari + +[ Upstream commit cd3c4670db3ffe997be9548c7a9db3952563cf14 ] + +qmp_cdev_set_cur_state() normalizes the requested state to a boolean +(cdev_state = !!state). The existing early-return check compares +qmp_cdev->state == state, which can be wrong if state is non-boolean +(any non-zero value). Compare qmp_cdev->state against cdev_state instead, +so the check matches the effective state and avoids redundant updates. + +Signed-off-by: Alok Tiwari +Fixes: 05589b30b21a ("soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260329195333.1478090-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/qcom_aoss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c +index 18c856056475c..8b828d7a59060 100644 +--- a/drivers/soc/qcom/qcom_aoss.c ++++ b/drivers/soc/qcom/qcom_aoss.c +@@ -336,7 +336,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, + /* Normalize state */ + cdev_state = !!state; + +- if (qmp_cdev->state == state) ++ if (qmp_cdev->state == cdev_state) + return 0; + + snprintf(buf, sizeof(buf), +-- +2.53.0 + diff --git a/queue-6.1/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch b/queue-6.1/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch new file mode 100644 index 0000000000..82666dcc93 --- /dev/null +++ b/queue-6.1/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch @@ -0,0 +1,45 @@ +From 9354aef63f5f630fbcea24bf3f0f2bec220fdff7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 02:51:11 -0700 +Subject: soc: qcom: llcc: fix v1 SB syndrome register offset + +From: Alok Tiwari + +[ Upstream commit 24e7625df5ce065393249b78930781be593bc381 ] + +The llcc_v1_edac_reg_offset table uses 0x2304c for trp_ecc_sb_err_syn0, +which is inconsistent with the surrounding TRP ECC registers (0x2034x) +and with llcc_v2_1_edac_reg_offset, where trp_ecc_sb_err_syn0 is 0x2034c +adjacent to trp_ecc_error_status0/1 at 0x20344/0x20348. + +Use 0x2034c for llcc v1 so the SB syndrome register follows the expected ++0x4 progression from trp_ecc_error_status1. This fixes EDAC reading the +wrong register for SB syndrome reporting. + +Fixes: c13d7d261e36 ("soc: qcom: llcc: Pass LLCC version based register offsets to EDAC driver") +Signed-off-by: Alok Tiwari +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260330095118.2657362-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/llcc-qcom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c +index 16a05143d0d62..bf1e050002bf9 100644 +--- a/drivers/soc/qcom/llcc-qcom.c ++++ b/drivers/soc/qcom/llcc-qcom.c +@@ -299,7 +299,7 @@ static const struct llcc_slice_config sm8450_data[] = { + static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { + .trp_ecc_error_status0 = 0x20344, + .trp_ecc_error_status1 = 0x20348, +- .trp_ecc_sb_err_syn0 = 0x2304c, ++ .trp_ecc_sb_err_syn0 = 0x2034c, + .trp_ecc_db_err_syn0 = 0x20370, + .trp_ecc_error_cntr_clear = 0x20440, + .trp_interrupt_0_status = 0x20480, +-- +2.53.0 + diff --git a/queue-6.1/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch b/queue-6.1/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch new file mode 100644 index 0000000000..817962dd97 --- /dev/null +++ b/queue-6.1/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch @@ -0,0 +1,46 @@ +From 504775560222c038bfa71f06fddc4dceb111c68e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:58 +0200 +Subject: soc: qcom: ocmem: register reasons for probe deferrals + +From: Dmitry Baryshkov + +[ Upstream commit 9dfd69cd89cd6afa4723be9098979abeef3bb8c6 ] + +Instead of printing messages to the dmesg, let the message be recorded +as a reason for the OCMEM client deferral. + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Brian Masney +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-2-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index a8a0d89ab01b9..087271120ce3e 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -202,10 +202,10 @@ struct ocmem *of_get_ocmem(struct device *dev) + } + + pdev = of_find_device_by_node(devnode->parent); +- if (!pdev) { +- dev_err(dev, "Cannot find device node %s\n", devnode->name); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!pdev) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, ++ "Cannot find device node %s\n", ++ devnode->name); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-6.1/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch b/queue-6.1/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch new file mode 100644 index 0000000000..ac9b4e6e4c --- /dev/null +++ b/queue-6.1/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch @@ -0,0 +1,46 @@ +From 60327fdcd072c85f666572dd47e5880e8ae5c740 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:59 +0200 +Subject: soc: qcom: ocmem: return -EPROBE_DEFER is ocmem is not available + +From: Dmitry Baryshkov + +[ Upstream commit 91b59009c7d48b58dbc50fecb27f2ad20749a05a ] + +If OCMEM is declared in DT, it is expected that it is present and +handled by the driver. The GPU driver will ignore -ENODEV error, which +typically means that OCMEM isn't defined in DT. Let ocmem return +-EPROBE_DEFER if it supposed to be used, but it is not probed (yet). + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-3-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 087271120ce3e..2ecde3a275282 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -209,10 +209,9 @@ struct ocmem *of_get_ocmem(struct device *dev) + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +- if (!ocmem) { +- dev_err(dev, "Cannot get ocmem\n"); +- return ERR_PTR(-ENODEV); +- } ++ if (!ocmem) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n"); ++ + return ocmem; + } + EXPORT_SYMBOL(of_get_ocmem); +-- +2.53.0 + diff --git a/queue-6.1/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch b/queue-6.1/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch new file mode 100644 index 0000000000..ef9d6b1010 --- /dev/null +++ b/queue-6.1/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch @@ -0,0 +1,55 @@ +From 8623a05784b5dd25477e8494a3ef15bfb5fa0046 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Aug 2024 15:09:50 +0200 +Subject: soc: qcom: ocmem: use scoped device node handling to simplify error + paths + +From: Krzysztof Kozlowski + +[ Upstream commit f4c1c19f5c0e5cf2870df91dedc6b40400fd9c8a ] + +Obtain the device node reference with scoped/cleanup.h to reduce error +handling and make the code a bit simpler. + +Signed-off-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-4-cfb67323a95c@linaro.org +Signed-off-by: Bjorn Andersson +Stable-dep-of: 9dfd69cd89cd ("soc: qcom: ocmem: register reasons for probe deferrals") +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index a21a196fdcc24..a8a0d89ab01b9 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -192,23 +192,20 @@ static void update_range(struct ocmem *ocmem, struct ocmem_buf *buf, + struct ocmem *of_get_ocmem(struct device *dev) + { + struct platform_device *pdev; +- struct device_node *devnode; + struct ocmem *ocmem; + +- devnode = of_parse_phandle(dev->of_node, "sram", 0); ++ struct device_node *devnode __free(device_node) = of_parse_phandle(dev->of_node, ++ "sram", 0); + if (!devnode || !devnode->parent) { + dev_err(dev, "Cannot look up sram phandle\n"); +- of_node_put(devnode); + return ERR_PTR(-ENODEV); + } + + pdev = of_find_device_by_node(devnode->parent); + if (!pdev) { + dev_err(dev, "Cannot find device node %s\n", devnode->name); +- of_node_put(devnode); + return ERR_PTR(-EPROBE_DEFER); + } +- of_node_put(devnode); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-6.1/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch b/queue-6.1/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch new file mode 100644 index 0000000000..1b324d81fc --- /dev/null +++ b/queue-6.1/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch @@ -0,0 +1,43 @@ +From 05ce759cbb1928470fa741a77adad40efee64ce4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:03 +0530 +Subject: soc/tegra: cbb: Set ERD on resume for err interrupt + +From: Sumit Gupta + +[ Upstream commit b6ff71c5d1d4ad858ddf6f39394d169c96689596 ] + +Set the Error Response Disable (ERD) bit to mask SError responses +and use interrupt-based error reporting. When the ERD bit is set, +inband error responses to the initiator via SError are suppressed, +and fabric errors are reported via an interrupt instead. + +The register is set during boot but the info is lost during system +suspend and needs to be set again on resume. + +Fixes: fc2f151d2314 ("soc/tegra: cbb: Add driver for Tegra234 CBB 2.0") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index 5813c55222ca3..2cf0ceb60bd0f 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -1185,6 +1185,10 @@ static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) + { + struct tegra234_cbb *cbb = dev_get_drvdata(dev); + ++ /* set ERD bit to mask SError and generate interrupt to report error */ ++ if (cbb->fabric->off_mask_erd) ++ tegra234_cbb_mask_serror(cbb); ++ + tegra234_cbb_error_enable(&cbb->base); + + dev_dbg(dev, "%s resumed\n", cbb->fabric->name); +-- +2.53.0 + diff --git a/queue-6.1/soundwire-bus-demote-unattached-state-warnings-to-de.patch b/queue-6.1/soundwire-bus-demote-unattached-state-warnings-to-de.patch new file mode 100644 index 0000000000..902dd0c0c2 --- /dev/null +++ b/queue-6.1/soundwire-bus-demote-unattached-state-warnings-to-de.patch @@ -0,0 +1,62 @@ +From e6888f67eb85e7e50c1103e7c4de86849e4824de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:02:10 -0700 +Subject: soundwire: bus: demote UNATTACHED state warnings to dev_dbg() + +From: Cole Leavitt + +[ Upstream commit 2c96956fe764f8224f9ec93b2a9160a578949a7a ] + +The dev_warn() messages in sdw_handle_slave_status() for UNATTACHED +transitions were added in commit d1b328557058 ("soundwire: bus: add +dev_warn() messages to track UNATTACHED devices") to debug attachment +failures with dynamic debug enabled. + +These warnings fire during normal operation -- for example when a codec +driver triggers a hardware reset after firmware download, causing the +device to momentarily go UNATTACHED before re-attaching -- producing +misleading noise on every boot. + +Demote the messages to dev_dbg() so they remain available via dynamic +debug for diagnosing real attachment failures without alarming users +during expected initialization sequences. + +Fixes: d1b328557058 ("soundwire: bus: add dev_warn() messages to track UNATTACHED devices") +Signed-off-by: Cole Leavitt +Reviewed-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260218180210.9263-1-cole@unwrap.rs +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/bus.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c +index f7b3e6a6975b4..1b6ba23edf0fa 100644 +--- a/drivers/soundwire/bus.c ++++ b/drivers/soundwire/bus.c +@@ -1815,8 +1815,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + + if (status[i] == SDW_SLAVE_UNATTACHED && + slave->status != SDW_SLAVE_UNATTACHED) { +- dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", ++ i, slave->status); + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + + /* Ensure driver knows that peripheral unattached */ +@@ -1867,8 +1867,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + if (slave->status == SDW_SLAVE_UNATTACHED) + break; + +- dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", ++ i, slave->status); + + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + break; +-- +2.53.0 + diff --git a/queue-6.1/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch b/queue-6.1/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..3e0a3b1f05 --- /dev/null +++ b/queue-6.1/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 2579717c097696f3f8797c8dd39b1d013e561b64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:21 +0800 +Subject: spi: fsl-qspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 981b080a79724738882b0af1c5bb7ade30d94f24 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks could +get "lost" - use reinit_completion() in that case, but be aware of +other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: 84d043185dbe ("spi: Add a driver for the Freescale/NXP QuadSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-3-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-fsl-qspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c +index 85cc71ba624a9..aee9993fe09db 100644 +--- a/drivers/spi/spi-fsl-qspi.c ++++ b/drivers/spi/spi-fsl-qspi.c +@@ -607,7 +607,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) + void __iomem *base = q->iobase; + int err = 0; + +- init_completion(&q->c); ++ reinit_completion(&q->c); + + /* + * Always start the sequence at the same index since we update +@@ -912,6 +912,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) + if (ret < 0) + goto err_disable_clk; + ++ init_completion(&q->c); + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { +-- +2.53.0 + diff --git a/queue-6.1/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch b/queue-6.1/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch new file mode 100644 index 0000000000..0fba15f3d6 --- /dev/null +++ b/queue-6.1/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch @@ -0,0 +1,55 @@ +From 80330438e5ca651efd81b8fb924382576dfb5f71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 11:06:41 +0800 +Subject: spi: hisi-kunpeng: prevent infinite while() loop in + hisi_spi_flush_fifo + +From: Pei Xiao + +[ Upstream commit 9f61daf2c2debe9f5cf4e1a4471e56a89a6fe45a ] + +The hisi_spi_flush_fifo()'s inner while loop that lacks any timeout +mechanism. Maybe the hardware never becomes empty, the loop will spin +forever, causing the CPU to hang. + +Fix this by adding a inner_limit based on loops_per_jiffy. The inner loop +now exits after approximately one jiffy if the FIFO remains non-empty, logs +a ratelimited warning, and breaks out of the outer loop. Additionally, add +a cpu_relax() inside the busy loop to improve power efficiency. + +Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/d834ce28172886bfaeb9c8ca00cfd9bf1c65d5a1.1773889292.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-hisi-kunpeng.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index 54730e93fba45..06c8893243b7d 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -198,8 +198,18 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs) + unsigned long limit = loops_per_jiffy << 1; + + do { +- while (hisi_spi_rx_not_empty(hs)) ++ unsigned long inner_limit = loops_per_jiffy; ++ ++ while (hisi_spi_rx_not_empty(hs) && --inner_limit) { + readl(hs->regs + HISI_SPI_DOUT); ++ cpu_relax(); ++ } ++ ++ if (!inner_limit) { ++ dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n"); ++ break; ++ } ++ + } while (hisi_spi_busy(hs) && limit--); + } + +-- +2.53.0 + diff --git a/queue-6.1/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch b/queue-6.1/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch new file mode 100644 index 0000000000..cc138cba3f --- /dev/null +++ b/queue-6.1/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch @@ -0,0 +1,60 @@ +From 7ad92b4371d5a43c23423abad4dba60033570958 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 15:26:59 +0800 +Subject: spi: mtk-snfi: unregister ECC engine on probe failure and remove() + callback + +From: Pei Xiao + +[ Upstream commit ab00febad191d7a4400aa1c3468279fb508258d4 ] + +mtk_snand_probe() registers the on-host NAND ECC engine, but teardown was +missing from both probe unwind and remove-time cleanup. Add a devm cleanup +action after successful registration so +nand_ecc_unregister_on_host_hw_engine() runs automatically on probe +failures and during device removal. + +Fixes: 764f1b748164 ("spi: add driver for MTK SPI NAND Flash Interface") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/20263f885f1a9c9d559f95275298cd6de4b11ed5.1775546401.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-mtk-snfi.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c +index d66bf9762557c..7afb2202b2d95 100644 +--- a/drivers/spi/spi-mtk-snfi.c ++++ b/drivers/spi/spi-mtk-snfi.c +@@ -1276,6 +1276,13 @@ static const struct spi_controller_mem_caps mtk_snand_mem_caps = { + .ecc = true, + }; + ++static void mtk_unregister_ecc_engine(void *data) ++{ ++ struct nand_ecc_engine *eng = data; ++ ++ nand_ecc_unregister_on_host_hw_engine(eng); ++} ++ + static irqreturn_t mtk_snand_irq(int irq, void *id) + { + struct mtk_snand *snf = id; +@@ -1424,6 +1431,13 @@ static int mtk_snand_probe(struct platform_device *pdev) + goto disable_clk; + } + ++ ret = devm_add_action_or_reset(&pdev->dev, mtk_unregister_ecc_engine, ++ &ms->ecc_eng); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "failed to add ECC unregister action\n"); ++ goto release_ecc; ++ } ++ + ctlr->num_chipselect = 1; + ctlr->mem_ops = &mtk_snand_mem_ops; + ctlr->mem_caps = &mtk_snand_mem_caps; +-- +2.53.0 + diff --git a/queue-6.1/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch b/queue-6.1/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch new file mode 100644 index 0000000000..de0693cf08 --- /dev/null +++ b/queue-6.1/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch @@ -0,0 +1,61 @@ +From 2138afd3c5dfd5491706a3915ae834d830c7f430 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 09:29:34 +0000 +Subject: spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ + +From: John Madieu + +[ Upstream commit b4683a239a409d65f88052f5630c748a8ba070cd ] + +rockchip_spi_isr() decides whether the current interrupt was the +cs-inactive event by reading IMR: + + if (rs->cs_inactive && + readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) + ctlr->target_abort(ctlr); + +IMR is the interrupt mask register: it tells which sources are enabled, +not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables +both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true: + + if (rs->cs_inactive) + writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, + rs->regs + ROCKCHIP_SPI_IMR); + +so the IMR check is always true once cs_inactive is enabled, and every +PIO interrupt - including normal RF_FULL completions - is dispatched to +ctlr->target_abort(), aborting the transfer. The bug is reachable on +ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller +when the transfer is short enough to fall back to PIO +(rockchip_spi_can_dma() returns false below fifo_len). + +Read ISR (which is RISR masked by IMR) so the check actually reflects +which interrupt fired, and parenthesise the expression for clarity while +at it. + +Fixes: 869f2c94db92 ("spi: rockchip: Stop spi slave dma receiver when cs inactive") +Signed-off-by: John Madieu +Link: https://patch.msgid.link/20260425092936.2590132-2-john.madieu@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rockchip.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index 6383451b6612c..c38d515e4399e 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -350,7 +350,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + + /* When int_cs_inactive comes, spi target abort */ +- if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { ++ if (rs->cs_inactive && ++ (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) { + ctlr->target_abort(ctlr); + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); +-- +2.53.0 + diff --git a/queue-6.1/spi-rockchip-switch-to-use-modern-name.patch b/queue-6.1/spi-rockchip-switch-to-use-modern-name.patch new file mode 100644 index 0000000000..099eb19b8b --- /dev/null +++ b/queue-6.1/spi-rockchip-switch-to-use-modern-name.patch @@ -0,0 +1,213 @@ +From 120b017c17624b160e585eb771d4c060387a27ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Aug 2023 17:31:44 +0800 +Subject: spi: rockchip: switch to use modern name + +From: Yang Yingliang + +[ Upstream commit 1a3ccff3bc39acc04e69e3a65833d474471598ec ] + +Change legacy name master/slave to modern name host/target or controller. + +No functional changed. + +Signed-off-by: Yang Yingliang +Acked-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20230818093154.1183529-14-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Stable-dep-of: b4683a239a40 ("spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ") +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rockchip.c | 58 +++++++++++++++++++------------------- + 1 file changed, 29 insertions(+), 29 deletions(-) + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index b3247fad5f7e2..6383451b6612c 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -104,8 +104,8 @@ + #define CR0_XFM_RO 0x2 + + #define CR0_OPM_OFFSET 20 +-#define CR0_OPM_MASTER 0x0 +-#define CR0_OPM_SLAVE 0x1 ++#define CR0_OPM_HOST 0x0 ++#define CR0_OPM_TARGET 0x1 + + #define CR0_SOI_OFFSET 23 + +@@ -125,7 +125,7 @@ + #define SR_TF_EMPTY (1 << 2) + #define SR_RF_EMPTY (1 << 3) + #define SR_RF_FULL (1 << 4) +-#define SR_SLAVE_TX_BUSY (1 << 5) ++#define SR_TARGET_TX_BUSY (1 << 5) + + /* Bit fields in ISR, IMR, ISR, RISR, 5bit */ + #define INT_MASK 0x1f +@@ -151,7 +151,7 @@ + #define RXDMA (1 << 0) + #define TXDMA (1 << 1) + +-/* sclk_out: spi master internal logic in rk3x can support 50Mhz */ ++/* sclk_out: spi host internal logic in rk3x can support 50Mhz */ + #define MAX_SCLK_OUT 50000000U + + /* +@@ -194,8 +194,8 @@ struct rockchip_spi { + + bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; + +- bool slave_abort; +- bool cs_inactive; /* spi slave tansmition stop when cs inactive */ ++ bool target_abort; ++ bool cs_inactive; /* spi target tansmition stop when cs inactive */ + bool cs_high_supported; /* native CS supports active-high polarity */ + + struct spi_transfer *xfer; /* Store xfer temporarily */ +@@ -206,13 +206,13 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable) + writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR); + } + +-static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool slave_mode) ++static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool target_mode) + { + unsigned long timeout = jiffies + msecs_to_jiffies(5); + + do { +- if (slave_mode) { +- if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_SLAVE_TX_BUSY) && ++ if (target_mode) { ++ if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_TARGET_TX_BUSY) && + !((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))) + return; + } else { +@@ -349,9 +349,9 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) + struct spi_controller *ctlr = dev_id; + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + +- /* When int_cs_inactive comes, spi slave abort */ ++ /* When int_cs_inactive comes, spi target abort */ + if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { +- ctlr->slave_abort(ctlr); ++ ctlr->target_abort(ctlr); + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); + +@@ -403,7 +403,7 @@ static void rockchip_spi_dma_rxcb(void *data) + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + int state = atomic_fetch_andnot(RXDMA, &rs->state); + +- if (state & TXDMA && !rs->slave_abort) ++ if (state & TXDMA && !rs->target_abort) + return; + + if (rs->cs_inactive) +@@ -419,11 +419,11 @@ static void rockchip_spi_dma_txcb(void *data) + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + int state = atomic_fetch_andnot(TXDMA, &rs->state); + +- if (state & RXDMA && !rs->slave_abort) ++ if (state & RXDMA && !rs->target_abort) + return; + + /* Wait until the FIFO data completely. */ +- wait_for_tx_idle(rs, ctlr->slave); ++ wait_for_tx_idle(rs, ctlr->target); + + spi_enable_chip(rs, false); + spi_finalize_current_transfer(ctlr); +@@ -523,7 +523,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs, + + static int rockchip_spi_config(struct rockchip_spi *rs, + struct spi_device *spi, struct spi_transfer *xfer, +- bool use_dma, bool slave_mode) ++ bool use_dma, bool target_mode) + { + u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET + | CR0_BHT_8BIT << CR0_BHT_OFFSET +@@ -532,9 +532,9 @@ static int rockchip_spi_config(struct rockchip_spi *rs, + u32 cr1; + u32 dmacr = 0; + +- if (slave_mode) +- cr0 |= CR0_OPM_SLAVE << CR0_OPM_OFFSET; +- rs->slave_abort = false; ++ if (target_mode) ++ cr0 |= CR0_OPM_TARGET << CR0_OPM_OFFSET; ++ rs->target_abort = false; + + cr0 |= rs->rsd << CR0_RSD_OFFSET; + cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET; +@@ -612,7 +612,7 @@ static size_t rockchip_spi_max_transfer_size(struct spi_device *spi) + return ROCKCHIP_SPI_MAX_TRANLEN; + } + +-static int rockchip_spi_slave_abort(struct spi_controller *ctlr) ++static int rockchip_spi_target_abort(struct spi_controller *ctlr) + { + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + u32 rx_fifo_left; +@@ -657,7 +657,7 @@ static int rockchip_spi_slave_abort(struct spi_controller *ctlr) + dmaengine_terminate_sync(ctlr->dma_tx); + atomic_set(&rs->state, 0); + spi_enable_chip(rs, false); +- rs->slave_abort = true; ++ rs->target_abort = true; + spi_finalize_current_transfer(ctlr); + + return 0; +@@ -695,7 +695,7 @@ static int rockchip_spi_transfer_one( + rs->xfer = xfer; + use_dma = ctlr->can_dma ? ctlr->can_dma(ctlr, spi, xfer) : false; + +- ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave); ++ ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->target); + if (ret) + return ret; + +@@ -755,15 +755,15 @@ static int rockchip_spi_probe(struct platform_device *pdev) + struct resource *mem; + struct device_node *np = pdev->dev.of_node; + u32 rsd_nsecs, num_cs; +- bool slave_mode; ++ bool target_mode; + +- slave_mode = of_property_read_bool(np, "spi-slave"); ++ target_mode = of_property_read_bool(np, "spi-slave"); + +- if (slave_mode) +- ctlr = spi_alloc_slave(&pdev->dev, ++ if (target_mode) ++ ctlr = spi_alloc_target(&pdev->dev, + sizeof(struct rockchip_spi)); + else +- ctlr = spi_alloc_master(&pdev->dev, ++ ctlr = spi_alloc_host(&pdev->dev, + sizeof(struct rockchip_spi)); + + if (!ctlr) +@@ -853,9 +853,9 @@ static int rockchip_spi_probe(struct platform_device *pdev) + ctlr->auto_runtime_pm = true; + ctlr->bus_num = pdev->id; + ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST; +- if (slave_mode) { ++ if (target_mode) { + ctlr->mode_bits |= SPI_NO_CS; +- ctlr->slave_abort = rockchip_spi_slave_abort; ++ ctlr->target_abort = rockchip_spi_target_abort; + } else { + ctlr->flags = SPI_MASTER_GPIO_SS; + ctlr->max_native_cs = ROCKCHIP_SPI_MAX_CS_NUM; +@@ -910,7 +910,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) + case ROCKCHIP_SPI_VER2_TYPE2: + rs->cs_high_supported = true; + ctlr->mode_bits |= SPI_CS_HIGH; +- if (ctlr->can_dma && slave_mode) ++ if (ctlr->can_dma && target_mode) + rs->cs_inactive = true; + else + rs->cs_inactive = false; +-- +2.53.0 + diff --git a/queue-6.1/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch b/queue-6.1/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch new file mode 100644 index 0000000000..947e8afd63 --- /dev/null +++ b/queue-6.1/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch @@ -0,0 +1,75 @@ +From 1d3c7ff0bb0f10e6ab8b8a2d1162f6ceadfaa1a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:07 +0000 +Subject: tcp: add data-race annotations around tp->data_segs_out and + tp->total_retrans + +From: Eric Dumazet + +[ Upstream commit 21e92a38cfd891538598ba8f805e0165a820d532 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e98102f4897 ("tcp: record pkts sent and retransmistted") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 8 +++++--- + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 44ddb82621300..17e6f5e90b1af 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4084,9 +4084,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED, + info.tcpi_sndbuf_limited, TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT, +- tp->data_segs_out, TCP_NLA_PAD); ++ READ_ONCE(tp->data_segs_out), TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS, +- tp->total_retrans, TCP_NLA_PAD); ++ READ_ONCE(tp->total_retrans), TCP_NLA_PAD); + + rate = READ_ONCE(sk->sk_pacing_rate); + rate64 = (rate != ~0UL) ? rate : ~0ULL; +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 0a27d89dcc731..bff8b08a11ba5 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1380,7 +1380,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + + if (skb->len != tcp_header_size) { + tcp_event_data_sent(tp, sk); +- tp->data_segs_out += tcp_skb_pcount(skb); ++ WRITE_ONCE(tp->data_segs_out, ++ tp->data_segs_out + tcp_skb_pcount(skb)); + tp->bytes_sent += skb->len - tcp_header_size; + } + +@@ -3286,7 +3287,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); +- tp->total_retrans += segs; ++ WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); + tp->bytes_retrans += skb->len; + + /* make sure skb->data is aligned on arches that require it +@@ -4208,7 +4209,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) + * However in this case, we are dealing with a passive fastopen + * socket thus we can change total_retrans value. + */ +- tcp_sk_rw(sk)->total_retrans++; ++ WRITE_ONCE(tcp_sk_rw(sk)->total_retrans, ++ tcp_sk_rw(sk)->total_retrans + 1); + } + trace_tcp_retransmit_synack(sk, req); + } +-- +2.53.0 + diff --git a/queue-6.1/tcp-annotate-data-races-around-tp-bytes_retrans.patch b/queue-6.1/tcp-annotate-data-races-around-tp-bytes_retrans.patch new file mode 100644 index 0000000000..a16424f6d2 --- /dev/null +++ b/queue-6.1/tcp-annotate-data-races-around-tp-bytes_retrans.patch @@ -0,0 +1,53 @@ +From 9be019a0ff350e2af4c8af95b9c73fd55b3d6c23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:13 +0000 +Subject: tcp: annotate data-races around tp->bytes_retrans + +From: Eric Dumazet + +[ Upstream commit 5efc7b9f7cbd43401f1af81d3d7f2be00f93390d ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: fb31c9b9f6c8 ("tcp: add data bytes retransmitted stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-9-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index eb59c3d022bb7..c60f8c69c19f5 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4110,8 +4110,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, +- TCP_NLA_PAD); ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, ++ READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index bb023a07cb1fc..aa2832c90e272 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -3289,7 +3289,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); + WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); +- tp->bytes_retrans += skb->len; ++ WRITE_ONCE(tp->bytes_retrans, tp->bytes_retrans + skb->len); + + /* make sure skb->data is aligned on arches that require it + * and check if ack-trimming & collapsing extended the headroom +-- +2.53.0 + diff --git a/queue-6.1/tcp-annotate-data-races-around-tp-bytes_sent.patch b/queue-6.1/tcp-annotate-data-races-around-tp-bytes_sent.patch new file mode 100644 index 0000000000..f7a4e726ee --- /dev/null +++ b/queue-6.1/tcp-annotate-data-races-around-tp-bytes_sent.patch @@ -0,0 +1,52 @@ +From 6dabd600438bb33f0709082cea07a1727f39de85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:12 +0000 +Subject: tcp: annotate data-races around tp->bytes_sent + +From: Eric Dumazet + +[ Upstream commit ee43e957ce2ec77b2ec47fef28f3c0df6ab01a31 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: ba113c3aa79a ("tcp: add data bytes sent stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-8-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_output.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 17e6f5e90b1af..eb59c3d022bb7 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4108,7 +4108,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); + +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, + TCP_NLA_PAD); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index bff8b08a11ba5..bb023a07cb1fc 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1382,7 +1382,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + tcp_event_data_sent(tp, sk); + WRITE_ONCE(tp->data_segs_out, + tp->data_segs_out + tcp_skb_pcount(skb)); +- tp->bytes_sent += skb->len - tcp_header_size; ++ WRITE_ONCE(tp->bytes_sent, ++ tp->bytes_sent + skb->len - tcp_header_size); + } + + if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) +-- +2.53.0 + diff --git a/queue-6.1/tcp-annotate-data-races-around-tp-dsack_dups.patch b/queue-6.1/tcp-annotate-data-races-around-tp-dsack_dups.patch new file mode 100644 index 0000000000..bbd6b84efc --- /dev/null +++ b/queue-6.1/tcp-annotate-data-races-around-tp-dsack_dups.patch @@ -0,0 +1,51 @@ +From 30d416791eafe1d74f48bdefdd70d6fdbde00003 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:14 +0000 +Subject: tcp: annotate data-races around tp->dsack_dups + +From: Eric Dumazet + +[ Upstream commit a984705ca88b976bf1087978fd98b7f3993da88c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e10b6554ff2 ("tcp: add dsack blocks received stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-10-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_input.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index c60f8c69c19f5..518b439531b16 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4112,7 +4112,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); +- nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); ++ nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 9b40204248488..645ff379c4254 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1023,7 +1023,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq, + else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq) + state->flag |= FLAG_DSACK_TLP; + +- tp->dsack_dups += dup_segs; ++ WRITE_ONCE(tp->dsack_dups, tp->dsack_dups + dup_segs); + /* Skip the DSACK if dup segs weren't retransmitted by sender */ + if (tp->dsack_dups > tp->total_retrans) + return 0; +-- +2.53.0 + diff --git a/queue-6.1/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch b/queue-6.1/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch new file mode 100644 index 0000000000..bdcbc48af8 --- /dev/null +++ b/queue-6.1/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch @@ -0,0 +1,40 @@ +From 15b579b281654b08fdb26b165e344fbb32e732b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:18 +0000 +Subject: tcp: annotate data-races around (tp->write_seq - tp->snd_nxt) + +From: Eric Dumazet + +[ Upstream commit 3a63b3d160560ef51e43fb4c880a5cde8078053c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() annotations to keep KCSAN happy. + +WRITE_ONCE() annotations are already present. + +Fixes: e08ab0b377a1 ("tcp: add bytes not sent to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-14-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 518b439531b16..076aa73c99fa8 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4117,7 +4117,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +- max_t(int, 0, tp->write_seq - tp->snd_nxt)); ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt))); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, + TCP_NLA_PAD); + if (ack_skb) +-- +2.53.0 + diff --git a/queue-6.1/tcp-preserve-const-qualifier-in-tcp_sk.patch b/queue-6.1/tcp-preserve-const-qualifier-in-tcp_sk.patch new file mode 100644 index 0000000000..450293837a --- /dev/null +++ b/queue-6.1/tcp-preserve-const-qualifier-in-tcp_sk.patch @@ -0,0 +1,167 @@ +From 8ab1d7c33d985494a1bde28331054bf4aef20d91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Mar 2023 15:55:39 +0000 +Subject: tcp: preserve const qualifier in tcp_sk() + +From: Eric Dumazet + +[ Upstream commit e9d9da91548b21e189fcd0259a0f2d26d1afc509 ] + +We can change tcp_sk() to propagate its argument const qualifier, +thanks to container_of_const(). + +We have two places where a const sock pointer has to be upgraded +to a write one. We have been using const qualifier for lockless +listeners to clearly identify points where writes could happen. + +Add tcp_sk_rw() helper to better document these. + +tcp_inbound_md5_hash(), __tcp_grow_window(), tcp_reset_check() +and tcp_rack_reo_wnd() get an additional const qualififer +for their @tp local variables. + +smc_check_reset_syn_req() also needs a similar change. + +Signed-off-by: Eric Dumazet +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Stable-dep-of: 21e92a38cfd8 ("tcp: add data-race annotations around tp->data_segs_out and tp->total_retrans") +Signed-off-by: Sasha Levin +--- + include/linux/tcp.h | 10 ++++++---- + include/net/tcp.h | 2 +- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_input.c | 4 ++-- + net/ipv4/tcp_minisocks.c | 5 +++-- + net/ipv4/tcp_output.c | 9 +++++++-- + net/ipv4/tcp_recovery.c | 2 +- + 7 files changed, 21 insertions(+), 13 deletions(-) + +diff --git a/include/linux/tcp.h b/include/linux/tcp.h +index 9cd289ad3f5b5..3ac0b55a6bc7b 100644 +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -471,10 +471,12 @@ enum tsq_flags { + TCPF_MTU_REDUCED_DEFERRED = (1UL << TCP_MTU_REDUCED_DEFERRED), + }; + +-static inline struct tcp_sock *tcp_sk(const struct sock *sk) +-{ +- return (struct tcp_sock *)sk; +-} ++#define tcp_sk(ptr) container_of_const(ptr, struct tcp_sock, inet_conn.icsk_inet.sk) ++ ++/* Variant of tcp_sk() upgrading a const sock to a read/write tcp socket. ++ * Used in context of (lockless) tcp listeners. ++ */ ++#define tcp_sk_rw(ptr) container_of(ptr, struct tcp_sock, inet_conn.icsk_inet.sk) + + struct tcp_timewait_sock { + struct inet_timewait_sock tw_sk; +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 83e0362e3b721..9632ac801e016 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -535,7 +535,7 @@ static inline void tcp_synq_overflow(const struct sock *sk) + + last_overflow = READ_ONCE(tcp_sk(sk)->rx_opt.ts_recent_stamp); + if (!time_between32(now, last_overflow, last_overflow + HZ)) +- WRITE_ONCE(tcp_sk(sk)->rx_opt.ts_recent_stamp, now); ++ WRITE_ONCE(tcp_sk_rw(sk)->rx_opt.ts_recent_stamp, now); + } + + /* syncookies: no recent synqueue overflow on this listening socket? */ +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index fd81976d4beb7..44ddb82621300 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4642,7 +4642,7 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb, + const __u8 *hash_location = NULL; + struct tcp_md5sig_key *hash_expected; + const struct tcphdr *th = tcp_hdr(skb); +- struct tcp_sock *tp = tcp_sk(sk); ++ const struct tcp_sock *tp = tcp_sk(sk); + int genhash, l3index; + u8 newhash[16]; + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index e1334be1feba1..9b40204248488 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -484,7 +484,7 @@ static void tcp_sndbuf_expand(struct sock *sk) + static int __tcp_grow_window(const struct sock *sk, const struct sk_buff *skb, + unsigned int skbtruesize) + { +- struct tcp_sock *tp = tcp_sk(sk); ++ const struct tcp_sock *tp = tcp_sk(sk); + /* Optimize this! */ + int truesize = tcp_win_from_space(sk, skbtruesize) >> 1; + int window = tcp_win_from_space(sk, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2])) >> 1; +@@ -5783,7 +5783,7 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *t + */ + static bool tcp_reset_check(const struct sock *sk, const struct sk_buff *skb) + { +- struct tcp_sock *tp = tcp_sk(sk); ++ const struct tcp_sock *tp = tcp_sk(sk); + + return unlikely(TCP_SKB_CB(skb)->seq == (tp->rcv_nxt - 1) && + (1 << sk->sk_state) & (TCPF_CLOSE_WAIT | TCPF_LAST_ACK | +diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c +index bc94df0140bfd..0b934b6ebb55b 100644 +--- a/net/ipv4/tcp_minisocks.c ++++ b/net/ipv4/tcp_minisocks.c +@@ -441,7 +441,7 @@ void tcp_ca_openreq_child(struct sock *sk, const struct dst_entry *dst) + } + EXPORT_SYMBOL_GPL(tcp_ca_openreq_child); + +-static void smc_check_reset_syn_req(struct tcp_sock *oldtp, ++static void smc_check_reset_syn_req(const struct tcp_sock *oldtp, + struct request_sock *req, + struct tcp_sock *newtp) + { +@@ -470,7 +470,8 @@ struct sock *tcp_create_openreq_child(const struct sock *sk, + const struct inet_request_sock *ireq = inet_rsk(req); + struct tcp_request_sock *treq = tcp_rsk(req); + struct inet_connection_sock *newicsk; +- struct tcp_sock *oldtp, *newtp; ++ const struct tcp_sock *oldtp; ++ struct tcp_sock *newtp; + u32 seq; + + if (!newsk) +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index a8d8e2f294ff2..0a27d89dcc731 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -4203,8 +4203,13 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) + if (!res) { + TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); +- if (unlikely(tcp_passive_fastopen(sk))) +- tcp_sk(sk)->total_retrans++; ++ if (unlikely(tcp_passive_fastopen(sk))) { ++ /* sk has const attribute because listeners are lockless. ++ * However in this case, we are dealing with a passive fastopen ++ * socket thus we can change total_retrans value. ++ */ ++ tcp_sk_rw(sk)->total_retrans++; ++ } + trace_tcp_retransmit_synack(sk, req); + } + return res; +diff --git a/net/ipv4/tcp_recovery.c b/net/ipv4/tcp_recovery.c +index c085793691102..bba10110fbbc1 100644 +--- a/net/ipv4/tcp_recovery.c ++++ b/net/ipv4/tcp_recovery.c +@@ -4,7 +4,7 @@ + + static u32 tcp_rack_reo_wnd(const struct sock *sk) + { +- struct tcp_sock *tp = tcp_sk(sk); ++ const struct tcp_sock *tp = tcp_sk(sk); + + if (!tp->reord_seen) { + /* If reordering has not been observed, be aggressive during +-- +2.53.0 + diff --git a/queue-6.1/thermal-drivers-spear-fix-error-condition-for-readin.patch b/queue-6.1/thermal-drivers-spear-fix-error-condition-for-readin.patch new file mode 100644 index 0000000000..692e2b6f59 --- /dev/null +++ b/queue-6.1/thermal-drivers-spear-fix-error-condition-for-readin.patch @@ -0,0 +1,42 @@ +From fa6a0f4849ead070e64ecba6d69cc0448e0e4981 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:35:24 +0530 +Subject: thermal/drivers/spear: Fix error condition for reading + st,thermal-flags + +From: Gopi Krishna Menon + +[ Upstream commit da2c4f332a0504d9c284e7626a561d343c8d6f57 ] + +of_property_read_u32 returns 0 on success. The current check returns +-EINVAL if the property is read successfully. + +Fix the check by removing ! from of_property_read_u32 + +Fixes: b9c7aff481f1 ("drivers/thermal/spear_thermal.c: add Device Tree probing capability") +Signed-off-by: Gopi Krishna Menon +Signed-off-by: Daniel Lezcano +Suggested-by: Daniel Baluta +Reviewed-by: Lukasz Luba +Link: https://patch.msgid.link/20260327090526.59330-1-krishnagopi487@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/thermal/spear_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c +index ee33ed692e4f7..42d8736d5ba49 100644 +--- a/drivers/thermal/spear_thermal.c ++++ b/drivers/thermal/spear_thermal.c +@@ -94,7 +94,7 @@ static int spear_thermal_probe(struct platform_device *pdev) + struct resource *res; + int ret = 0, val; + +- if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) { ++ if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) { + dev_err(&pdev->dev, "Failed: DT Pdata not passed\n"); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.1/tipc-fix-double-free-in-tipc_buf_append.patch b/queue-6.1/tipc-fix-double-free-in-tipc_buf_append.patch new file mode 100644 index 0000000000..f791450ab3 --- /dev/null +++ b/queue-6.1/tipc-fix-double-free-in-tipc_buf_append.patch @@ -0,0 +1,60 @@ +From db37c73fa4294898da9ab672da6129cec05ff6c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 13:45:26 +0100 +Subject: tipc: fix double-free in tipc_buf_append() + +From: Lee Jones + +[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ] + +tipc_msg_validate() can potentially reallocate the skb it is validating, +freeing the old one. In tipc_buf_append(), it was being called with a +pointer to a local variable which was a copy of the caller's skb +pointer. + +If the skb was reallocated and validation subsequently failed, the error +handling path would free the original skb pointer, which had already +been freed, leading to double-free. + +Fix this by checking if head now points to a newly allocated reassembled +skb. If it does, reassign *headbuf for later freeing operations. + +Fixes: d618d09a68e4 ("tipc: enforce valid ratio between skb truesize and contents") +Suggested-by: Tung Nguyen +Signed-off-by: Lee Jones +Reviewed-by: Tung Nguyen +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/msg.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/net/tipc/msg.c b/net/tipc/msg.c +index 76284fc538ebd..b0bba0feef564 100644 +--- a/net/tipc/msg.c ++++ b/net/tipc/msg.c +@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) + + if (fragid == LAST_FRAGMENT) { + TIPC_SKB_CB(head)->validated = 0; +- if (unlikely(!tipc_msg_validate(&head))) ++ ++ /* If the reassembled skb has been freed in ++ * tipc_msg_validate() because of an invalid truesize, ++ * then head will point to a newly allocated reassembled ++ * skb, while *headbuf points to freed reassembled skb. ++ * In such cases, correct *headbuf for freeing the newly ++ * allocated reassembled skb later. ++ */ ++ if (unlikely(!tipc_msg_validate(&head))) { ++ if (head != *headbuf) ++ *headbuf = head; + goto err; ++ } ++ + *buf = head; + TIPC_SKB_CB(head)->tail = NULL; + *headbuf = NULL; +-- +2.53.0 + diff --git a/queue-6.1/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch b/queue-6.1/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch new file mode 100644 index 0000000000..fef5ac335c --- /dev/null +++ b/queue-6.1/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch @@ -0,0 +1,69 @@ +From b34c7b675864710831a644e475cb6ea91435c5b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 06:25:09 -0700 +Subject: tracing: branch: Fix inverted check on stat tracer registration + +From: Breno Leitao + +[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ] + +init_annotated_branch_stats() and all_annotated_branch_stats() check the +return value of register_stat_tracer() with "if (!ret)", but +register_stat_tracer() returns 0 on success and a negative errno on +failure. The inverted check causes the warning to be printed on every +successful registration, e.g.: + + Warning: could not register annotated branches stats + +while leaving real failures silent. The initcall also returned a +hard-coded 1 instead of the actual error. + +Invert the check and propagate ret so that the warning fires on real +errors and the initcall reports the correct status. + +Cc: Mathieu Desnoyers +Cc: Ingo Molnar +Cc: Frederic Weisbecker +Link: https://patch.msgid.link/20260420-tracing-v1-1-d8f4cd0d6af1@debian.org +Fixes: 002bb86d8d42 ("tracing/ftrace: separate events tracing and stats tracing engine") +Signed-off-by: Breno Leitao +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_branch.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c +index e47fdb4c92fbc..30f72e0ecb5d4 100644 +--- a/kernel/trace/trace_branch.c ++++ b/kernel/trace/trace_branch.c +@@ -379,10 +379,10 @@ __init static int init_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&annotated_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "annotated branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +@@ -444,10 +444,10 @@ __init static int all_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&all_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "all branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +-- +2.53.0 + diff --git a/queue-6.1/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch b/queue-6.1/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch new file mode 100644 index 0000000000..d46ef84f3c --- /dev/null +++ b/queue-6.1/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch @@ -0,0 +1,56 @@ +From ebfcf2bf6023035f52231dfd69bbec2e02763ed6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 19:22:23 +0800 +Subject: tracing: Rebuild full_name on each hist_field_name() call + +From: Pengpeng Hou + +[ Upstream commit 5ec1d1e97de134beed3a5b08235a60fc1c51af96 ] + +hist_field_name() uses a static MAX_FILTER_STR_VAL buffer for fully +qualified variable-reference names, but it currently appends into that +buffer with strcat() without rebuilding it first. As a result, repeated +calls append a new "system.event.field" name onto the previous one, +which can eventually run past the end of full_name. + +Build the name with snprintf() on each call and return NULL if the fully +qualified name does not fit in MAX_FILTER_STR_VAL. + +Link: https://patch.msgid.link/20260401112224.85582-1-pengpeng@iscas.ac.cn +Fixes: 067fe038e70f ("tracing: Add variable reference handling to hist triggers") +Reviewed-by: Tom Zanussi +Tested-by: Tom Zanussi +Signed-off-by: Pengpeng Hou +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 356360e75f9a7..b5276f2f2cf40 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -1346,12 +1346,14 @@ static const char *hist_field_name(struct hist_field *field, + field->flags & HIST_FIELD_FL_VAR_REF) { + if (field->system) { + static char full_name[MAX_FILTER_STR_VAL]; ++ int len; ++ ++ len = snprintf(full_name, sizeof(full_name), "%s.%s.%s", ++ field->system, field->event_name, ++ field->name); ++ if (len >= sizeof(full_name)) ++ return NULL; + +- strcat(full_name, field->system); +- strcat(full_name, "."); +- strcat(full_name, field->event_name); +- strcat(full_name, "."); +- strcat(full_name, field->name); + field_name = full_name; + } else + field_name = field->name; +-- +2.53.0 + diff --git a/queue-6.1/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch b/queue-6.1/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch new file mode 100644 index 0000000000..0c1209d6f7 --- /dev/null +++ b/queue-6.1/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch @@ -0,0 +1,50 @@ +From 071414fb5cee8b5b630f14e09565bb11e85f3232 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 23:29:37 -0800 +Subject: tty: hvc_iucv: fix off-by-one in number of supported devices + +From: Randy Dunlap + +[ Upstream commit f2a880e802ad12d1e38039d1334fb1475d0f5241 ] + +MAX_HVC_IUCV_LINES == HVC_ALLOC_TTY_ADAPTERS == 8. +This is the number of entries in: + static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; + +Sometimes hvc_iucv_table[] is limited by: +(a) if (num > hvc_iucv_devices) // for error detection +or +(b) for (i = 0; i < hvc_iucv_devices; i++) // in 2 places +(so these 2 don't agree; second one appears to be correct to me.) + +hvc_iucv_devices can be 0..8. This is a counter. +(c) if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + +If hvc_iucv_devices == 8, (a) allows the code to access hvc_iucv_table[8]. +Oops. + +Fixes: 44a01d5ba8a4 ("[S390] s390/hvc_console: z/VM IUCV hypervisor console support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260130072939.1535869-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index 7d49a872de48a..9551269e106a4 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if (num > hvc_iucv_devices) ++ if (num >= hvc_iucv_devices) + return NULL; + return hvc_iucv_table[num]; + } +-- +2.53.0 + diff --git a/queue-6.1/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch b/queue-6.1/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch new file mode 100644 index 0000000000..2a22e580dc --- /dev/null +++ b/queue-6.1/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch @@ -0,0 +1,91 @@ +From ed3427de9cbc42390e38565c622ad0d2b03e0003 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 11:39:59 -0800 +Subject: unshare: fix nsproxy leak in ksys_unshare() on set_cred_ucounts() + failure + +From: Michal Grzedzicki + +[ Upstream commit a98621a0f187a934c115dcfe79a49520ae892111 ] + +When set_cred_ucounts() fails in ksys_unshare() new_nsproxy is leaked. + +Let's call put_nsproxy() if that happens. + +Link: https://lkml.kernel.org/r/20260213193959.2556730-1-mge@meta.com +Fixes: 905ae01c4ae2 ("Add a reference to ucounts for each cred") +Signed-off-by: Michal Grzedzicki +Reviewed-by: Andrew Morton +Cc: Alexey Gladkov (Intel) +Cc: Ben Segall +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: "Liam R. Howlett" +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 96ecab82e38af..db2a9016f636f 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -3285,11 +3285,10 @@ int ksys_unshare(unsigned long unshare_flags) + new_cred, new_fs); + if (err) + goto bad_unshare_cleanup_cred; +- + if (new_cred) { + err = set_cred_ucounts(new_cred); + if (err) +- goto bad_unshare_cleanup_cred; ++ goto bad_unshare_cleanup_nsproxy; + } + + if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { +@@ -3305,8 +3304,10 @@ int ksys_unshare(unsigned long unshare_flags) + shm_init_task(current); + } + +- if (new_nsproxy) ++ if (new_nsproxy) { + switch_task_namespaces(current, new_nsproxy); ++ new_nsproxy = NULL; ++ } + + task_lock(current); + +@@ -3335,13 +3336,15 @@ int ksys_unshare(unsigned long unshare_flags) + + perf_event_namespaces(current); + ++bad_unshare_cleanup_nsproxy: ++ if (new_nsproxy) ++ put_nsproxy(new_nsproxy); + bad_unshare_cleanup_cred: + if (new_cred) + put_cred(new_cred); + bad_unshare_cleanup_fd: + if (new_fd) + put_files_struct(new_fd); +- + bad_unshare_cleanup_fs: + if (new_fs) + free_fs_struct(new_fs); +-- +2.53.0 + diff --git a/queue-6.1/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch b/queue-6.1/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch new file mode 100644 index 0000000000..a562c1c9a3 --- /dev/null +++ b/queue-6.1/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch @@ -0,0 +1,64 @@ +From 392a16a053ac545f8462953d6354c9a9eed24797 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 02:30:24 +0000 +Subject: vhost_net: fix sleeping with preempt-disabled in + vhost_net_busy_poll() + +From: Kohei Enju + +[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ] + +syzbot reported "sleeping function called from invalid context" in +vhost_net_busy_poll(). + +Commit 030881372460 ("vhost_net: basic polling support") introduced a +busy-poll loop and preempt_{disable,enable}() around it, where each +iteration calls a sleepable function inside the loop. + +The purpose of disabling preemption was to keep local_clock()-based +timeout accounting on a single CPU, rather than as a requirement of +busy-poll itself: + +https://lore.kernel.org/1448435489-5949-4-git-send-email-jasowang@redhat.com + +From this perspective, migrate_disable() is sufficient here, so replace +preempt_disable() with migrate_disable(), avoiding sleepable accesses +from a preempt-disabled context. + +Fixes: 030881372460 ("vhost_net: basic polling support") +Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/ +Signed-off-by: Kohei Enju +Acked-by: Michael S. Tsirkin +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/vhost/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index 2797cecc6c8be..3ae572df07960 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -546,7 +546,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + busyloop_timeout = poll_rx ? rvq->busyloop_timeout: + tvq->busyloop_timeout; + +- preempt_disable(); ++ migrate_disable(); + endtime = busy_clock() + busyloop_timeout; + + while (vhost_can_busy_poll(endtime)) { +@@ -563,7 +563,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + cpu_relax(); + } + +- preempt_enable(); ++ migrate_enable(); + + if (poll_rx || sock_has_rx_data(sock)) + vhost_net_busy_poll_try_queue(net, vq); +-- +2.53.0 + diff --git a/queue-6.1/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch b/queue-6.1/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch new file mode 100644 index 0000000000..1aa49db677 --- /dev/null +++ b/queue-6.1/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch @@ -0,0 +1,115 @@ +From 755aa334c224c13fd023bafb56b8a184e94c3808 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 09:36:07 +0300 +Subject: vrf: Fix a potential NPD when removing a port from a VRF + +From: Ido Schimmel + +[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ] + +RCU readers that identified a net device as a VRF port using +netif_is_l3_slave() assume that a subsequent call to +netdev_master_upper_dev_get_rcu() will return a VRF device. They then +continue to dereference its l3mdev operations. + +This assumption is not always correct and can result in a NPD [1]. There +is no RCU synchronization when removing a port from a VRF, so it is +possible for an RCU reader to see a new master device (e.g., a bridge) +that does not have l3mdev operations. + +Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE +flag. Skip this synchronization when a net device is removed from a VRF +as part of its deletion and when the VRF device itself is deleted. In +the latter case an RCU grace period will pass by the time RTNL is +released. + +[1] +BUG: kernel NULL pointer dereference, address: 0000000000000000 +[...] +RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) +[...] +Call Trace: + +l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) +__inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) +inet_bind_sk (net/ipv4/af_inet.c:469) +__sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) +__x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Fixes: fdeea7be88b1 ("net: vrf: Set slave's private flag before linking") +Reported-by: Haoze Xie +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/netdev/20260419145332.3988923-1-n05ec@lzu.edu.cn/ +Signed-off-by: Ido Schimmel +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260423063607.1208202-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vrf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index 75e95f6dd816c..51b34882827e9 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -1126,6 +1126,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + + err: + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ synchronize_net(); + return ret; + } + +@@ -1145,10 +1146,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + } + + /* inverse of do_vrf_add_slave */ +-static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) ++static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, ++ bool needs_sync) + { + netdev_upper_dev_unlink(port_dev, dev); + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ /* Make sure that concurrent RCU readers that identified the device ++ * as a VRF port see a VRF master or no master at all. ++ */ ++ if (needs_sync) ++ synchronize_net(); + + cycle_netdev(port_dev, NULL); + +@@ -1157,7 +1164,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + + static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + { +- return do_vrf_del_slave(dev, port_dev); ++ return do_vrf_del_slave(dev, port_dev, true); + } + + static void vrf_dev_uninit(struct net_device *dev) +@@ -1722,7 +1729,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) + struct list_head *iter; + + netdev_for_each_lower_dev(dev, port_dev, iter) +- vrf_del_slave(dev, port_dev); ++ do_vrf_del_slave(dev, port_dev, false); + + vrf_map_unregister_dev(dev); + +@@ -1853,7 +1860,7 @@ static int vrf_device_event(struct notifier_block *unused, + goto out; + + vrf_dev = netdev_master_upper_dev_get(dev); +- vrf_del_slave(vrf_dev, dev); ++ do_vrf_del_slave(vrf_dev, dev, false); + } + out: + return NOTIFY_DONE; +-- +2.53.0 + diff --git a/queue-6.1/wifi-brcmfmac-fix-error-pointer-dereference.patch b/queue-6.1/wifi-brcmfmac-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..4f2e0783d9 --- /dev/null +++ b/queue-6.1/wifi-brcmfmac-fix-error-pointer-dereference.patch @@ -0,0 +1,80 @@ +From 85613b7500ce07e50d8f062e3be3f794e3b9122a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 20:30:43 -0600 +Subject: wifi: brcmfmac: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit dd8592fc6007a451c3e4b9025de365e39de8178a ] + +The function brcmf_chip_add_core() can return an error pointer and is +not checked. Add checks for error pointer. + +Detected by Smatch: +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1010 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1013 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1016 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1019 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1022 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +Fixes: cb7cf7be9eba7 ("brcmfmac: make chip related functions host interface independent") +Signed-off-by: Ethan Tidmore +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260217023043.73631-1-ethantidmore06@gmail.com +[add missing wifi: prefix] +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 121893bbaa1d7..1fbe5c721adf8 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -992,18 +992,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + + core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, + SI_ENUM_BASE_DEFAULT, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, + BCM4329_CORE_BUS_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, + BCM4329_CORE_SOCRAM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, + BCM4329_CORE_ARM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + + core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + } else if (socitype == SOCI_AI) { + ci->iscoreup = brcmf_chip_ai_iscoreup; +-- +2.53.0 + diff --git a/queue-6.1/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch b/queue-6.1/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch new file mode 100644 index 0000000000..e25d28c9b7 --- /dev/null +++ b/queue-6.1/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch @@ -0,0 +1,49 @@ +From 9ee39b6441d3c92aa23e087cc63afd4cc6dec811 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 09:26:25 +0000 +Subject: wifi: mwifiex: Fix memory leak in mwifiex_11n_aggregate_pkt() + +From: Zilin Guan + +[ Upstream commit 990a73dec3fdc145fef6c827c29205437d533ece ] + +In mwifiex_11n_aggregate_pkt(), skb_aggr is allocated via +mwifiex_alloc_dma_align_buf(). If mwifiex_is_ralist_valid() returns false, +the function currently returns -1 immediately without freeing the +previously allocated skb_aggr, causing a memory leak. + +Since skb_aggr has not yet been queued via skb_queue_tail(), no other +references to this memory exist. Therefore, it has to be freed locally +before returning the error. + +Fix this by calling mwifiex_write_data_complete() to free skb_aggr before +returning the error status. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") +Signed-off-by: Zilin Guan +Reviewed-by: Jeff Chen +Link: https://patch.msgid.link/20260119092625.1349934-1-zilin@seu.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +index 34b4b34276d6d..042b1fe5f0d67 100644 +--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +@@ -203,6 +203,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); ++ mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); + return -1; + } + +-- +2.53.0 + diff --git a/queue-6.1/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch b/queue-6.1/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch new file mode 100644 index 0000000000..69c674328a --- /dev/null +++ b/queue-6.1/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch @@ -0,0 +1,49 @@ +From 5c084daea824d32bf6f023c99af7869ffb655a44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:55:22 +0800 +Subject: wifi: rtlwifi: pci: fix possible use-after-free caused by unfinished + irq_prepare_bcn_tasklet + +From: Duoming Zhou + +[ Upstream commit 039cd522dc70151da13329a5e3ae19b1736f468a ] + +The irq_prepare_bcn_tasklet is initialized in rtl_pci_init() and +scheduled when RTL_IMR_BCNINT interrupt is triggered by hardware. +But it is never killed in rtl_pci_deinit(). When the rtlwifi card +probe fails or is being detached, the ieee80211_hw is deallocated. +However, irq_prepare_bcn_tasklet may still be running or pending, +leading to use-after-free when the freed ieee80211_hw is accessed +in _rtl_pci_prepare_bcn_tasklet(). + +Similar to irq_tasklet, add tasklet_kill() in rtl_pci_deinit() to +ensure that irq_prepare_bcn_tasklet is properly terminated before +the ieee80211_hw is released. + +The issue was identified through static analysis. + +Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") +Signed-off-by: Duoming Zhou +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260223045522.48377-1-duoming@zju.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtlwifi/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index 4029e4e590fa6..ba2277cfbe3dc 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -1675,6 +1675,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); ++ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + } + +-- +2.53.0 + diff --git a/queue-6.1/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch b/queue-6.1/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch new file mode 100644 index 0000000000..5c6fa98ec6 --- /dev/null +++ b/queue-6.1/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch @@ -0,0 +1,48 @@ +From 2c03efc927fd4efb053e4308308394fcb8bfced1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:05:53 +0300 +Subject: wifi: rtw89: phy: fix uninitialized variable access in + rtw89_phy_cfo_set_crystal_cap() + +From: Alexey Velichayshiy + +[ Upstream commit 047cddf88c611e616d49a00311d4722e46286234 ] + +In the rtw89_phy_cfo_set_crystal_cap() function, for chips other than +RTL8852A/RTL8851B, the values read by rtw89_mac_read_xtal_si() are +stored into the local variables sc_xi_val and sc_xo_val. If either +read fails, these variables remain uninitialized, they are later +used to update cfo->crystal_cap and in debug print statements. This +can lead to undefined behavior. + +Fix the issue by initializing sc_xi_val and sc_xo_val to zero, +like is implemented in vendor driver. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 8379fa611536 ("rtw89: 8852c: add write/read crystal function in CFO tracking") +Signed-off-by: Alexey Velichayshiy +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260323140613.1615574-1-a.velichayshiy@ispras.ru +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/phy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c +index f6647f9d23939..980b8079bc707 100644 +--- a/drivers/net/wireless/realtek/rtw89/phy.c ++++ b/drivers/net/wireless/realtek/rtw89/phy.c +@@ -2148,7 +2148,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, + { + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + const struct rtw89_chip_info *chip = rtwdev->chip; +- u8 sc_xi_val, sc_xo_val; ++ u8 sc_xi_val = 0, sc_xo_val = 0; + + if (!force && cfo->crystal_cap == crystal_cap) + return; +-- +2.53.0 + diff --git a/queue-6.12/acpi-agdi-fix-missing-newline-in-error-message.patch b/queue-6.12/acpi-agdi-fix-missing-newline-in-error-message.patch new file mode 100644 index 0000000000..c6238ab225 --- /dev/null +++ b/queue-6.12/acpi-agdi-fix-missing-newline-in-error-message.patch @@ -0,0 +1,40 @@ +From ed37a4bc47a03a20348b24464abfe11e0eefa920 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:31:15 +0800 +Subject: ACPI: AGDI: fix missing newline in error message + +From: Haoyu Lu + +[ Upstream commit b178330b67abb7293b6de28b2a49d49c83962db5 ] + +Add the missing trailing newline to the dev_err() message +printed when SDEI event registration fails. + +This keeps the error output as a properly terminated log line. + +Fixes: a2a591fb76e6 ("ACPI: AGDI: Add driver for Arm Generic Diagnostic Dump and Reset device") +Reviewed-by: Ilkka Koskinen +Signed-off-by: Haoyu Lu +Reviewed-by: Hanjun Guo +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + drivers/acpi/arm64/agdi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c +index f5f21dd0d277e..dccbd1c4dafcf 100644 +--- a/drivers/acpi/arm64/agdi.c ++++ b/drivers/acpi/arm64/agdi.c +@@ -32,7 +32,7 @@ static int agdi_sdei_probe(struct platform_device *pdev, + + err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev); + if (err) { +- dev_err(&pdev->dev, "Failed to register for SDEI event %d", ++ dev_err(&pdev->dev, "Failed to register for SDEI event %d\n", + adata->sdei_event); + return err; + } +-- +2.53.0 + diff --git a/queue-6.12/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch b/queue-6.12/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch new file mode 100644 index 0000000000..2a07f64ba9 --- /dev/null +++ b/queue-6.12/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch @@ -0,0 +1,145 @@ +From 8c297f73ae26858f9246d08288647f1d1d761679 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:28:15 +0100 +Subject: ACPI: x86: cmos_rtc: Clean up address space handler driver + +From: Rafael J. Wysocki + +[ Upstream commit ba0b236736dde4059bdcb8e99beaa50d6e5b6e7e ] + +Make multiple changes that do not alter functionality to the CMOS RTC +ACPI address space handler driver, including the following: + + - Drop the unused .detach() callback from cmos_rtc_handler. + + - Rename acpi_cmos_rtc_attach_handler() to acpi_cmos_rtc_attach(). + + - Rearrange acpi_cmos_rtc_space_handler() to reduce the number of + redundant checks and make white space follow the coding style. + + - Adjust an error message in acpi_install_cmos_rtc_space_handler() + and make the white space follow the coding style. + + - Rearrange acpi_remove_cmos_rtc_space_handler() and adjust an error + message in it. + +No intentional functional impact. + +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/5094429.31r3eYUQgx@rafael.j.wysocki +Stable-dep-of: 6cee29ad9d7e ("ACPI: x86: cmos_rtc: Improve coordination with ACPI TAD driver") +Signed-off-by: Sasha Levin +--- + drivers/acpi/x86/cmos_rtc.c | 61 +++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 29 deletions(-) + +diff --git a/drivers/acpi/x86/cmos_rtc.c b/drivers/acpi/x86/cmos_rtc.c +index 51643ff6fe5fc..977234da9fc11 100644 +--- a/drivers/acpi/x86/cmos_rtc.c ++++ b/drivers/acpi/x86/cmos_rtc.c +@@ -24,31 +24,35 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + {} + }; + +-static acpi_status +-acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, +- u32 bits, u64 *value64, +- void *handler_context, void *region_context) ++static acpi_status acpi_cmos_rtc_space_handler(u32 function, ++ acpi_physical_address address, ++ u32 bits, u64 *value64, ++ void *handler_context, ++ void *region_context) + { +- int i; ++ unsigned int i, bytes = DIV_ROUND_UP(bits, 8); + u8 *value = (u8 *)value64; + + if (address > 0xff || !value64) + return AE_BAD_PARAMETER; + +- if (function != ACPI_WRITE && function != ACPI_READ) +- return AE_BAD_PARAMETER; ++ guard(spinlock_irq)(&rtc_lock); ++ ++ if (function == ACPI_WRITE) { ++ for (i = 0; i < bytes; i++, address++, value++) ++ CMOS_WRITE(*value, address); + +- spin_lock_irq(&rtc_lock); ++ return AE_OK; ++ } + +- for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) +- if (function == ACPI_READ) ++ if (function == ACPI_READ) { ++ for (i = 0; i < bytes; i++, address++, value++) + *value = CMOS_READ(address); +- else +- CMOS_WRITE(*value, address); + +- spin_unlock_irq(&rtc_lock); ++ return AE_OK; ++ } + +- return AE_OK; ++ return AE_BAD_PARAMETER; + } + + int acpi_install_cmos_rtc_space_handler(acpi_handle handle) +@@ -56,11 +60,11 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + acpi_status status; + + status = acpi_install_address_space_handler(handle, +- ACPI_ADR_SPACE_CMOS, +- &acpi_cmos_rtc_space_handler, +- NULL, NULL); ++ ACPI_ADR_SPACE_CMOS, ++ acpi_cmos_rtc_space_handler, ++ NULL, NULL); + if (ACPI_FAILURE(status)) { +- pr_err("Error installing CMOS-RTC region handler\n"); ++ pr_err("Failed to install CMOS-RTC address space handler\n"); + return -ENODEV; + } + +@@ -70,26 +74,25 @@ EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); + + void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) + { +- if (ACPI_FAILURE(acpi_remove_address_space_handler(handle, +- ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) +- pr_err("Error removing CMOS-RTC region handler\n"); ++ acpi_status status; ++ ++ status = acpi_remove_address_space_handler(handle, ++ ACPI_ADR_SPACE_CMOS, ++ acpi_cmos_rtc_space_handler); ++ if (ACPI_FAILURE(status)) ++ pr_err("Failed to remove CMOS-RTC address space handler\n"); + } + EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + +-static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id) ++static int acpi_cmos_rtc_attach(struct acpi_device *adev, ++ const struct acpi_device_id *id) + { + return acpi_install_cmos_rtc_space_handler(adev->handle); + } + +-static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev) +-{ +- acpi_remove_cmos_rtc_space_handler(adev->handle); +-} +- + static struct acpi_scan_handler cmos_rtc_handler = { + .ids = acpi_cmos_rtc_ids, +- .attach = acpi_cmos_rtc_attach_handler, +- .detach = acpi_cmos_rtc_detach_handler, ++ .attach = acpi_cmos_rtc_attach, + }; + + void __init acpi_cmos_rtc_init(void) +-- +2.53.0 + diff --git a/queue-6.12/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch b/queue-6.12/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch new file mode 100644 index 0000000000..3d00782add --- /dev/null +++ b/queue-6.12/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch @@ -0,0 +1,86 @@ +From 12c21c55b2aa10d64f88ff5919ba3bb672f4d78b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:28:57 +0100 +Subject: ACPI: x86: cmos_rtc: Improve coordination with ACPI TAD driver + +From: Rafael J. Wysocki + +[ Upstream commit 6cee29ad9d7e400d39ae0b1a54447fedcb62eecd ] + +If a CMOS RTC (PNP0B00/PNP0B01/PNP0B02) device coexists with an ACPI +TAD (timer and event alarm device, ACPI000E), the ACPI TAD driver will +attempt to install the CMOS RTC address space hanlder that has been +installed already and the TAD probing will fail. + +Avoid that by changing acpi_install_cmos_rtc_space_handler() to return +zero and acpi_remove_cmos_rtc_space_handler() to do nothing if the CMOS +RTC address space handler has been installed already. + +Fixes: 596ca52a56da ("ACPI: TAD: Install SystemCMOS address space handler for ACPI000E") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2415111.ElGaqSPkdT@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/x86/cmos_rtc.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/x86/cmos_rtc.c b/drivers/acpi/x86/cmos_rtc.c +index 977234da9fc11..45db7e51cbe60 100644 +--- a/drivers/acpi/x86/cmos_rtc.c ++++ b/drivers/acpi/x86/cmos_rtc.c +@@ -24,6 +24,8 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + {} + }; + ++static bool cmos_rtc_space_handler_present __read_mostly; ++ + static acpi_status acpi_cmos_rtc_space_handler(u32 function, + acpi_physical_address address, + u32 bits, u64 *value64, +@@ -59,6 +61,9 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + { + acpi_status status; + ++ if (cmos_rtc_space_handler_present) ++ return 0; ++ + status = acpi_install_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler, +@@ -68,6 +73,8 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + return -ENODEV; + } + ++ cmos_rtc_space_handler_present = true; ++ + return 1; + } + EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); +@@ -76,6 +83,9 @@ void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) + { + acpi_status status; + ++ if (cmos_rtc_space_handler_present) ++ return; ++ + status = acpi_remove_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler); +@@ -87,7 +97,13 @@ EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + static int acpi_cmos_rtc_attach(struct acpi_device *adev, + const struct acpi_device_id *id) + { +- return acpi_install_cmos_rtc_space_handler(adev->handle); ++ int ret; ++ ++ ret = acpi_install_cmos_rtc_space_handler(adev->handle); ++ if (ret < 0) ++ return ret; ++ ++ return 1; + } + + static struct acpi_scan_handler cmos_rtc_handler = { +-- +2.53.0 + diff --git a/queue-6.12/alsa-core-validate-compress-device-numbers-without-d.patch b/queue-6.12/alsa-core-validate-compress-device-numbers-without-d.patch new file mode 100644 index 0000000000..aa9e2f0f5f --- /dev/null +++ b/queue-6.12/alsa-core-validate-compress-device-numbers-without-d.patch @@ -0,0 +1,81 @@ +From aaf5f259d82144c48f4230dee25d467baba19c0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 02:24:04 -0300 +Subject: ALSA: core: Validate compress device numbers without dynamic minors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 796e119e9b14763be905ad0d023c71a14bc2e931 ] + +Without CONFIG_SND_DYNAMIC_MINORS, ALSA reserves only two fixed minors +for compress devices on each card: comprD0 and comprD1. + +snd_find_free_minor() currently computes the compress minor as +type + dev without validating dev first, so device numbers greater than +1 spill into the HWDEP minor range instead of failing registration. + +ASoC passes rtd->id to snd_compress_new(), so this can happen on real +non-dynamic-minor builds. + +Add a dedicated fixed-minor check for SNDRV_DEVICE_TYPE_COMPRESS in +snd_find_free_minor() and reject out-of-range device numbers with +-EINVAL before constructing the minor. + +Also remove the stale TODO in compress_offload.c that still claims +multiple compress nodes are missing. + +Fixes: 3eafc959b32f ("ALSA: core: add support for compressed devices") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-alsa-compress-static-minors-v1-1-0628573bee1c@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 7 ------- + sound/core/sound.c | 7 +++++++ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index bdf1d78de8338..d81a890b60c65 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -40,13 +40,6 @@ + #define COMPR_CODEC_CAPS_OVERFLOW + #endif + +-/* TODO: +- * - add substream support for multiple devices in case of +- * SND_DYNAMIC_MINORS is not used +- * - Multiple node representation +- * driver should be able to register multiple nodes +- */ +- + struct snd_compr_file { + unsigned long caps; + struct snd_compr_stream stream; +diff --git a/sound/core/sound.c b/sound/core/sound.c +index 6531a67f13b3e..7980b60f4ba0b 100644 +--- a/sound/core/sound.c ++++ b/sound/core/sound.c +@@ -216,9 +216,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev) + case SNDRV_DEVICE_TYPE_RAWMIDI: + case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: + case SNDRV_DEVICE_TYPE_PCM_CAPTURE: ++ if (snd_BUG_ON(!card)) ++ return -EINVAL; ++ minor = SNDRV_MINOR(card->number, type + dev); ++ break; + case SNDRV_DEVICE_TYPE_COMPRESS: + if (snd_BUG_ON(!card)) + return -EINVAL; ++ if (dev < 0 || ++ dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS) ++ return -EINVAL; + minor = SNDRV_MINOR(card->number, type + dev); + break; + default: +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch b/queue-6.12/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch new file mode 100644 index 0000000000..c7cd50941c --- /dev/null +++ b/queue-6.12/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch @@ -0,0 +1,60 @@ +From 28cf287593b02ea197fe34ed366995eb4629e0df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:04:50 +0800 +Subject: ALSA: hda/conexant: Fix missing error check for jack detection + +From: wangdicheng + +[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ] + +In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() +is ignored. This function returns a pointer, and if it fails (e.g., due +to memory allocation failure), it returns an error pointer which must +be checked using IS_ERR(). + +If the registration fails, the driver continues to probe, but the jack +detection callback will not be registered. This can lead to a kernel +crash later when the driver attempts to handle jack events or accesses +the uninitialized structure. + +Check the return value using IS_ERR() and propagate the error via +PTR_ERR() to the probe caller. + +Fixes: 7aeb25908648 ("ALSA: hda/conexant: Fix headset auto detect fail in cx8070 and SN6140") +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428080450.108801-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 00ac0e170619b..0296777bb380b 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -1182,6 +1182,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) + static int patch_conexant_auto(struct hda_codec *codec) + { + struct conexant_spec *spec; ++ struct hda_jack_callback *callback; + int err; + + codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); +@@ -1198,7 +1199,12 @@ static int patch_conexant_auto(struct hda_codec *codec) + case 0x14f11f86: + case 0x14f11f87: + spec->is_cx11880_sn6140 = true; +- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); ++ callback = snd_hda_jack_detect_enable_callback(codec, 0x19, ++ cx_update_headset_mic_vref); ++ if (IS_ERR(callback)) { ++ err = PTR_ERR(callback); ++ goto error; ++ } + break; + } + +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch b/queue-6.12/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch new file mode 100644 index 0000000000..0ede50ea21 --- /dev/null +++ b/queue-6.12/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch @@ -0,0 +1,79 @@ +From 3a8bb4f93e027a4441aa1c5f2e462019b5e6dea5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Jun 2025 15:43:31 +0800 +Subject: ALSA: hda/conexant: Renaming the codec with device ID 0x1f86 and + 0x1f87 + +From: wangdicheng + +[ Upstream commit 7f4c540e0859e2025675d2c5c5c6ab88eaf817e2 ] + +Due to changes in the manufacturer's plan, all 0x14f11f86 will be +named CX11880, and 0x14f11f87 will be named SN6140 + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20250616074331.581309-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index b7c9eba9236d8..00ac0e170619b 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -42,7 +42,7 @@ struct conexant_spec { + unsigned int gpio_led; + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; +- bool is_cx8070_sn6140; ++ bool is_cx11880_sn6140; + }; + + +@@ -195,7 +195,7 @@ static int cx_auto_init(struct hda_codec *codec) + cxt_init_gpio_led(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + +- if (spec->is_cx8070_sn6140) ++ if (spec->is_cx11880_sn6140) + cx_fixup_headset_recog(codec); + + return 0; +@@ -247,7 +247,7 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ + { + unsigned int mic_present; + +- /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, ++ /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled, + * the node 19 can only be configured to microphone or disabled. + * Check hp&mic tag to process headset plugin & plugout. + */ +@@ -1193,11 +1193,11 @@ static int patch_conexant_auto(struct hda_codec *codec) + codec->spec = spec; + codec->patch_ops = cx_auto_patch_ops; + +- /* init cx8070/sn6140 flag and reset headset_present_flag */ ++ /* init cx11880/sn6140 flag and reset headset_present_flag */ + switch (codec->core.vendor_id) { + case 0x14f11f86: + case 0x14f11f87: +- spec->is_cx8070_sn6140 = true; ++ spec->is_cx11880_sn6140 = true; + snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); + break; + } +@@ -1285,7 +1285,7 @@ static int patch_conexant_auto(struct hda_codec *codec) + */ + + static const struct hda_device_id snd_hda_id_conexant[] = { +- HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), ++ HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch b/queue-6.12/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch new file mode 100644 index 0000000000..4c6cb1a293 --- /dev/null +++ b/queue-6.12/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch @@ -0,0 +1,95 @@ +From 7657bebd3a629f4e8d6cdcfe8c4ec79661b03d31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 14:05:31 +0100 +Subject: ALSA: hda: cs35l56: Fix uninitialized value in + cs35l56_hda_read_acpi() + +From: Richard Fitzgerald + +[ Upstream commit 90df4957a3271adf391b3432cd76a40887cf3273 ] + +Eliminate the uninitialized 'nval' in cs35l56_hda_read_acpi() if a +system-specific quirk overrides processing of the dev-index property. +The value is now stored in a new 'num_amps' member of struct cs35l56_hda +so that the quirk handler can set the value. + +The quirk for the Lenovo Yoga Book 9i GenX replaces the values from the +dev-index property with hardcoded indexes. So cs35l56_hda_read_acpi() would +then skip reading the property. But this left the 'nval' local variable +uninitialized when it is later passed to cirrus_scodec_get_speaker_id(). + +Fixes: 40b1c2f9b299 ("ALSA: hda/cs35l56: Workaround bad dev-index on Lenovo Yoga Book 9i GenX") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-sound/aenFesLAStjrVNy8@stanley.mountain/T/#u +Signed-off-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260428130531.169600-1-rf@opensource.cirrus.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/cs35l56_hda.c | 12 +++++++----- + sound/pci/hda/cs35l56_hda.h | 1 + + 2 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c +index c868177712866..ee5387140ae48 100644 +--- a/sound/pci/hda/cs35l56_hda.c ++++ b/sound/pci/hda/cs35l56_hda.c +@@ -888,6 +888,7 @@ static int cs35l56_hda_system_resume(struct device *dev) + static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr) + { + /* The cirrus,dev-index property has the wrong values */ ++ cs35l56->num_amps = 2; + switch (*bus_addr) { + case 0x30: + cs35l56->index = 1; +@@ -937,7 +938,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + char hid_string[8]; + struct acpi_device *adev; + const char *property, *sub; +- size_t nval; + int i, ret; + + /* +@@ -973,13 +973,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + ret = -EINVAL; + goto err; + } +- nval = ret; ++ cs35l56->num_amps = ret; + +- ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval); ++ ret = device_property_read_u32_array(cs35l56->base.dev, property, values, ++ cs35l56->num_amps); + if (ret) + goto err; + +- for (i = 0; i < nval; i++) { ++ for (i = 0; i < cs35l56->num_amps; i++) { + if (values[i] == id) { + cs35l56->index = i; + break; +@@ -1002,7 +1003,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + "Read ACPI _SUB failed(%ld): fallback to generic firmware\n", + PTR_ERR(sub)); + } else { +- ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1); ++ ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, ++ cs35l56->num_amps, -1); + if (ret == -ENOENT) { + cs35l56->system_name = sub; + } else if (ret >= 0) { +diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h +index 38d94fb213a50..0074e8f5f18cb 100644 +--- a/sound/pci/hda/cs35l56_hda.h ++++ b/sound/pci/hda/cs35l56_hda.h +@@ -25,6 +25,7 @@ struct cs35l56_hda { + struct work_struct dsp_work; + + int index; ++ int num_amps; + const char *system_name; + const char *amp_name; + +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch b/queue-6.12/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch new file mode 100644 index 0000000000..d6204c724f --- /dev/null +++ b/queue-6.12/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch @@ -0,0 +1,45 @@ +From aacb4411989e1ca8d23ab1aeafb74f7a3563ba35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 15:54:05 +0800 +Subject: ALSA: hda/realtek: fix code style (ERROR: else should follow close + brace '}') + +From: Lei Huang + +[ Upstream commit d1888bf848ade6a9e71c7ba516fd215aa1bd8d65 ] + +Fix checkpatch code style errors: + + ERROR: else should follow close brace '}' + #2300: FILE: sound/hda/codecs/realtek/alc269.c:2300: + + } + + else + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Lei Huang +Link: https://patch.msgid.link/20260331075405.78148-1-huanglei814@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 4cab9696fdab0..c420cf5d87e99 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -6428,9 +6428,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } +- else ++ } else { + alc_fixup_headset_mode(codec, fix, action); ++ } + } + + static void alc288_update_headset_jack_cb(struct hda_codec *codec, +-- +2.53.0 + diff --git a/queue-6.12/alsa-hda-realtek-fixed-speaker-no-sound-update.patch b/queue-6.12/alsa-hda-realtek-fixed-speaker-no-sound-update.patch new file mode 100644 index 0000000000..8b909818fb --- /dev/null +++ b/queue-6.12/alsa-hda-realtek-fixed-speaker-no-sound-update.patch @@ -0,0 +1,67 @@ +From 5aef54fbc3adad51b3c962a2ff8adaf2e7cadf56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:44:04 +0800 +Subject: ALSA: hda/realtek - fixed speaker no sound update + +From: Kailang Yang + +[ Upstream commit 46c862f5419e0a86b60b9f9558d247f6084c99f9 ] + +Fixed speaker has pop noise on Lenovo Thinkpad X11 Carbon Gen 12. + +Fixes: 630fbc6e870e ("ALSA: hda/realtek - fixed speaker no sound") +Reported-and-tested-by: Jeremy Bethmont +Closes: https://lore.kernel.org/CAC88DfsHrhyhy0Pn1O-z9egBvMYu=6NYgcvcC6KCgwh_-Ldkxg@mail.gmail.com +Signed-off-by: Kailang Yang +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index c420cf5d87e99..b0ee9b58e0570 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -7881,22 +7881,11 @@ static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct snd_pcm_substream *substream, + int action) + { +- static const struct coef_fw dis_coefs[] = { +- WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), +- WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023), +- }; /* Disable AMP silence detection */ +- static const struct coef_fw en_coefs[] = { +- WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), +- WRITE_COEF(0x28, 0x0084), WRITE_COEF(0x29, 0xb023), +- }; /* Enable AMP silence detection */ +- + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: +- alc_process_coef_fw(codec, dis_coefs); + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */ + break; + case HDA_GEN_PCM_ACT_CLOSE: +- alc_process_coef_fw(codec, en_coefs); + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */ + break; + } +@@ -7919,10 +7908,15 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec, + WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301), + WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023), + }; ++ static const struct coef_fw dis_coefs[] = { ++ WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), ++ WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023), ++ }; /* Disable AMP silence detection */ + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11); ++ alc_process_coef_fw(codec, dis_coefs); + alc_process_coef_fw(codec, coefs); + spec->power_hook = alc287_s4_power_gpio3_default; + spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook; +-- +2.53.0 + diff --git a/queue-6.12/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch b/queue-6.12/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch new file mode 100644 index 0000000000..9aa8e98590 --- /dev/null +++ b/queue-6.12/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch @@ -0,0 +1,289 @@ +From cdb0938f9e29242fc37ee9c013ab6c5d05170ccf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:54:32 -0300 +Subject: ALSA: sc6000: Keep the programmed board state in card-private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit fb79bf127ac2577b4876132da6dba768018aad4c ] + +The driver may auto-select IRQ and DMA resources at probe time, but +sc6000_init_board() still derives the SC-6000 soft configuration from +the module parameter arrays. When irq=auto or dma=auto is used, the +codec is created with the selected resources while the board is +programmed with the unresolved values. + +Store the mapped ports and generated SC-6000 board configuration in +card-private data, build that configuration from the live probe +results instead of the raw module parameters, and keep the probe-time +board programming in a shared helper. + +This fixes the resource-programming mismatch and leaves the driver +with a stable board-state block that can be reused by suspend/resume. + +Fixes: c282866101bf ("ALSA: sc6000: add support for SC-6600 and SC-7000") +Signed-off-by: Cássio Gabriel +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260410-alsa-sc6000-pm-v1-1-4d9e95493d26@gmail.com +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 152 +++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 60 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 3115c32b4061b..4066b68a102e2 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -100,6 +100,15 @@ MODULE_PARM_DESC(joystick, "Enable gameport."); + #define PFX "sc6000: " + #define DRV_NAME "SC-6000" + ++struct snd_sc6000 { ++ char __iomem *vport; ++ char __iomem *vmss_port; ++ u8 mss_config; ++ u8 config; ++ u8 hw_cfg[2]; ++ bool old_dsp; ++}; ++ + /* hardware dependent functions */ + + /* +@@ -267,7 +276,7 @@ static int sc6000_dsp_reset(char __iomem *vport) + + /* detection and initialization */ + static int sc6000_hw_cfg_write(struct device *devptr, +- char __iomem *vport, const int *cfg) ++ char __iomem *vport, const u8 *cfg) + { + if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { + dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); +@@ -353,8 +362,7 @@ static int sc6000_init_mss(struct device *devptr, + return 0; + } + +-static void sc6000_hw_cfg_encode(struct device *devptr, +- char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, u8 *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -376,27 +384,83 @@ static void sc6000_hw_cfg_encode(struct device *devptr, + dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(struct device *devptr, +- char __iomem *vport, +- char __iomem *vmss_port, int dev) ++static void sc6000_prepare_board(struct device *devptr, ++ struct snd_sc6000 *sc6000, ++ unsigned int dev, int xirq, int xdma) ++{ ++ sc6000->mss_config = sc6000_irq_to_softcfg(xirq) | ++ sc6000_dma_to_softcfg(xdma); ++ sc6000->config = sc6000->mss_config | ++ sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); ++ sc6000_hw_cfg_encode(devptr, sc6000->hw_cfg, port[dev], mpu_port[dev], ++ mss_port[dev], joystick[dev]); ++} ++ ++static void sc6000_detect_old_dsp(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ sc6000_write(devptr, sc6000->vport, COMMAND_5C); ++ sc6000->old_dsp = sc6000_read(sc6000->vport) < 0; ++} ++ ++static int sc6000_program_board(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ int err; ++ ++ if (!sc6000->old_dsp) { ++ if (sc6000_hw_cfg_write(devptr, sc6000->vport, ++ sc6000->hw_cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); ++ return -EIO; ++ } ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ sc6000_dsp_reset(sc6000->vport); ++ ++ if (!sc6000->old_dsp) { ++ sc6000_write(devptr, sc6000->vport, COMMAND_60); ++ sc6000_write(devptr, sc6000->vport, 0x02); ++ sc6000_dsp_reset(sc6000->vport); ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ err = sc6000_init_mss(devptr, sc6000->vport, sc6000->config, ++ sc6000->vmss_port, sc6000->mss_config); ++ if (err < 0) { ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int sc6000_init_board(struct device *devptr, struct snd_sc6000 *sc6000) + { + char answer[15]; + char version[2]; +- int mss_config = sc6000_irq_to_softcfg(irq[dev]) | +- sc6000_dma_to_softcfg(dma[dev]); +- int config = mss_config | +- sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); + int err; +- int old = 0; + +- err = sc6000_dsp_reset(vport); ++ err = sc6000_dsp_reset(sc6000->vport); + if (err < 0) { + dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, sc6000->vport, GET_DSP_COPYRIGHT, ++ answer, 15); + if (err <= 0) { + dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; +@@ -408,54 +472,17 @@ static int sc6000_init_board(struct device *devptr, + if (strncmp("SC-6000", answer, 7)) + dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ if (sc6000_dsp_get_answer(devptr, sc6000->vport, ++ GET_DSP_VERSION, version, 2) < 2) { + dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } + dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + +- /* set configuration */ +- sc6000_write(devptr, vport, COMMAND_5C); +- if (sc6000_read(vport) < 0) +- old = 1; +- +- if (!old) { +- int cfg[2]; +- sc6000_hw_cfg_encode(devptr, +- vport, &cfg[0], port[dev], mpu_port[dev], +- mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { +- dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); +- return -EIO; +- } +- } +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- +- sc6000_dsp_reset(vport); +- +- if (!old) { +- sc6000_write(devptr, vport, COMMAND_60); +- sc6000_write(devptr, vport, 0x02); +- sc6000_dsp_reset(vport); +- } ++ sc6000_detect_old_dsp(devptr, sc6000); + +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); +- if (err < 0) { +- dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); +- return -ENODEV; +- } +- +- return 0; ++ return sc6000_program_board(devptr, sc6000); + } + + static int snd_sc6000_mixer(struct snd_wss *chip) +@@ -538,10 +565,10 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + + static void snd_sc6000_free(struct snd_card *card) + { +- char __iomem *vport = (char __force __iomem *)card->private_data; ++ struct snd_sc6000 *sc6000 = card->private_data; + +- if (vport) +- sc6000_setup_board(card->dev, vport, 0); ++ if (sc6000->vport) ++ sc6000_setup_board(card->dev, sc6000->vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -552,15 +579,17 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + int xirq = irq[dev]; + int xdma = dma[dev]; + struct snd_card *card; ++ struct snd_sc6000 *sc6000; + struct snd_wss *chip; + struct snd_opl3 *opl3; + char __iomem *vport; + char __iomem *vmss_port; + + err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE, +- 0, &card); ++ sizeof(*sc6000), &card); + if (err < 0) + return err; ++ sc6000 = card->private_data; + + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); +@@ -587,7 +616,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } +- card->private_data = (void __force *)vport; ++ sc6000->vport = vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +@@ -600,12 +629,15 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } ++ sc6000->vmss_port = vmss_port; + + dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(devptr, vport, vmss_port, dev); ++ sc6000_prepare_board(devptr, sc6000, dev, xirq, xdma); ++ ++ err = sc6000_init_board(devptr, sc6000); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +-- +2.53.0 + diff --git a/queue-6.12/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch b/queue-6.12/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch new file mode 100644 index 0000000000..980f508cf3 --- /dev/null +++ b/queue-6.12/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch @@ -0,0 +1,39 @@ +From 57a0bffc65a1985a2530c43fcb1925ded859fdad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 01:25:48 +0300 +Subject: ALSA: scarlett2: Add missing sentinel initializer field + +From: Panagiotis Petrakopoulos + +[ Upstream commit 2428cd6e8b6fa80c36db4652702ca0acd2ce3f08 ] + +A "-Wmissing-field-initializers" warning was emitted when compiling the +module using the W=2 option. There is a sentinel initializer field +missing in the end of scarlett2_devices[]. Tested using a +Scarlett Solo 4th gen. + +Fixes: d98cc489029d ("ALSA: scarlett2: Move USB IDs out from device_info struct") +Signed-off-by: Panagiotis Petrakopoulos +Link: https://patch.msgid.link/20260405222548.8903-1-npetrakopoulos2003@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_scarlett2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index fe1d6e512699c..ef5945aa40e4a 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -2221,7 +2221,7 @@ static const struct scarlett2_device_entry scarlett2_devices[] = { + { USB_ID(0x1235, 0x820c), &clarett_8pre_info, "Clarett+" }, + + /* End of list */ +- { 0, NULL }, ++ { 0, NULL, NULL }, + }; + + /* get the starting port index number for a given port type/direction */ +-- +2.53.0 + diff --git a/queue-6.12/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch b/queue-6.12/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch new file mode 100644 index 0000000000..6d0343ad76 --- /dev/null +++ b/queue-6.12/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch @@ -0,0 +1,205 @@ +From 5b27c3b59e20ffe003ea7719c07ab8fba20ffb1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 17:15:04 +0200 +Subject: ALSA: usb-audio: Fix potential leak of pd at parsing UAC3 streams + +From: Takashi Iwai + +[ Upstream commit c39f0bc03f84ba64c9144c95714df1dc36150f6d ] + +At parsing UAC3 streams, we allocate a PD object at each time, and +either assign or free it. But there is a case where the PD object may +be leaked; namely, in __snd_usb_parse_audio_interface() loop, when an +audioformat shares the same endpoint with others, it's put to a link +and returns from snd_usb_add_audio_stream(), but the PD is forgotten +afterwards. Overall, the treatment of PD object in the parser code is +a bit flaky, and we should be more careful about the object ownership. + +This patch tries to fix the above case and improve the code a bit. +The pd object is now managed with the auto-cleanup in the loop, and +the ownership is updated when the pd object gets assigned to the +stream, which guarantees the release of the leftover object. + +Fixes: 7edf3b5e6a45 ("ALSA: usb-audio: AudioStreaming Power Domain parsing") +Link: https://patch.msgid.link/20260427151508.12544-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 +- + sound/usb/stream.c | 58 ++++++++++++++++++---------------------------- + sound/usb/stream.h | 3 ++- + 3 files changed, 25 insertions(+), 38 deletions(-) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index fb81dcd6ca2ac..489dd84e20967 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip, + + snd_usb_audioformat_set_sync_ep(chip, fp); + +- err = snd_usb_add_audio_stream(chip, stream, fp); ++ err = snd_usb_add_audio_stream(chip, stream, fp, NULL); + if (err < 0) + return err; + +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index 8e8c99f21abf0..08e2ad14aa6da 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) + static void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, + struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++ struct snd_usb_power_domain **pdptr) + { + struct snd_usb_substream *subs = &as->substream[stream]; + +@@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, + if (fp->channels > subs->channels_max) + subs->channels_max = fp->channels; + +- if (pd) { +- subs->str_pd = pd; ++ if (pdptr && *pdptr) { ++ subs->str_pd = *pdptr; ++ *pdptr = NULL; /* assigned */ + /* Initialize Power Domain to idle status D1 */ +- snd_usb_power_domain_set(subs->stream->chip, pd, ++ snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, + UAC3_PD_STATE_D1); + } + +@@ -486,11 +487,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor + * if not, create a new pcm stream. note, fp is added to the substream + * fmt_list and will be freed on the chip instance release. do not free + * fp or do remove it from the substream fmt_list to avoid double-free. ++ * ++ * pdptr is optional and can be NULL. When it's non-NULL and the PD gets ++ * assigned to the stream, *pdptr is cleared to NULL upon return. + */ +-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++int snd_usb_add_audio_stream(struct snd_usb_audio *chip, ++ int stream, ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr) + + { + struct snd_usb_stream *as; +@@ -523,7 +527,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + err = snd_pcm_new_stream(as->pcm, stream, 1); + if (err < 0) + return err; +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + return add_chmap(as->pcm, stream, subs); + } + +@@ -551,7 +555,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + else + strcpy(pcm->name, "USB Audio"); + +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + + /* + * Keep using head insertion for M-Audio Audiophile USB (tm) which has a +@@ -569,21 +573,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + return add_chmap(pcm, stream, &as->substream[stream]); + } + +-int snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, NULL); +-} +- +-static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, pd); +-} +- + static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, + struct usb_host_interface *alts, + int protocol, int iface_no) +@@ -1108,8 +1097,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + } + } + +- if (pd) +- *pd_out = pd; ++ *pd_out = pd; + + return fp; + } +@@ -1124,7 +1112,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + struct usb_interface_descriptor *altsd; + int i, altno, err, stream; + struct audioformat *fp = NULL; +- struct snd_usb_power_domain *pd = NULL; + bool set_iface_first; + int num, protocol; + +@@ -1166,6 +1153,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) + continue; + ++ /* pd may be allocated at snd_usb_get_audioformat_uac3() and ++ * assigned at snd_usb_add_audio_stream(); otherwise it'll be ++ * freed automatically by cleanup at each loop. ++ */ ++ struct snd_usb_power_domain *pd __free(kfree) = NULL; ++ + /* + * Roland audio streaming interfaces are marked with protocols + * 0/1/2, but are UAC 1 compatible. +@@ -1221,23 +1214,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + *has_non_pcm = true; + if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { + audioformat_free(fp); +- kfree(pd); + fp = NULL; +- pd = NULL; + continue; + } + + snd_usb_audioformat_set_sync_ep(chip, fp); + + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); +- if (protocol == UAC_VERSION_3) +- err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); +- else +- err = snd_usb_add_audio_stream(chip, stream, fp); +- ++ err = snd_usb_add_audio_stream(chip, stream, fp, &pd); + if (err < 0) { + audioformat_free(fp); +- kfree(pd); + return err; + } + +diff --git a/sound/usb/stream.h b/sound/usb/stream.h +index d92e18d5818fe..61b9a133da018 100644 +--- a/sound/usb/stream.h ++++ b/sound/usb/stream.h +@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + + int snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, +- struct audioformat *fp); ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr); + + #endif /* __USBAUDIO_STREAM_H */ + +-- +2.53.0 + diff --git a/queue-6.12/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch b/queue-6.12/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch new file mode 100644 index 0000000000..0dd6188a3b --- /dev/null +++ b/queue-6.12/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch @@ -0,0 +1,76 @@ +From 87a92fe2b19231d19b5c3e963ed2526c55e845e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 18:12:55 -0500 +Subject: ARM: dts: imx27-eukrea: replace interrupts with interrupts-extended + +From: Frank Li + +[ Upstream commit 0477a6b31e2874e554e3bcfac9883684b8f8ca2d ] + +The property interrupts use default interrupt controllers. But pass down +gpio as phandle. Correct it by use interrupts-extended. + +Fixes: d8cae888aa2bc ("ARM: dts: Add support for the cpuimx27 board from Eukrea and its baseboard") +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi | 8 ++++---- + .../boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +index c7e9235848782..9f0e65526d5f9 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +@@ -106,7 +106,7 @@ uart8250@3,200000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x200000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -119,7 +119,7 @@ uart8250@3,400000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x400000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -132,7 +132,7 @@ uart8250@3,800000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x800000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -145,7 +145,7 @@ uart8250@3,1000000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x1000000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +index d78793601306c..c71f802983304 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +@@ -76,7 +76,7 @@ ads7846@0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_touch>; + reg = <0>; +- interrupts = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; + spi-cpol; + spi-max-frequency = <1500000>; + ti,keep-vref-on; +-- +2.53.0 + diff --git a/queue-6.12/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch b/queue-6.12/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch new file mode 100644 index 0000000000..26e09d4c9d --- /dev/null +++ b/queue-6.12/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch @@ -0,0 +1,46 @@ +From cd9037c2fb18e3bf0ba1f569c3663289744768a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 09:25:41 +0100 +Subject: ARM: dts: mediatek: mt7623: fix efuse fallback compatible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafał Miłecki + +[ Upstream commit 5978ff33cc6f0988388a2830dc5cd2ea4e81f36a ] + +Fix following validation error: +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: compatible: 'oneOf' conditional failed, one must be fixed: + ['mediatek,mt7623-efuse', 'mediatek,mt8173-efuse'] is too long + 'mediatek,mt8173-efuse' was expected + 'mediatek,efuse' was expected + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: Unevaluated properties are not allowed ('compatible' was unexpected) + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# + +Fixes: 43c7a91b4b3a ("arm: dts: mt7623: add efuse nodes to the mt7623.dtsi file") +Signed-off-by: Rafał Miłecki +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/mediatek/mt7623.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi +index fd7a89cc337d6..a60b1d6879ffe 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623.dtsi ++++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi +@@ -328,7 +328,7 @@ sysirq: interrupt-controller@10200100 { + + efuse: efuse@10206000 { + compatible = "mediatek,mt7623-efuse", +- "mediatek,mt8173-efuse"; ++ "mediatek,efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.12/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch b/queue-6.12/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch new file mode 100644 index 0000000000..503f238aa3 --- /dev/null +++ b/queue-6.12/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch @@ -0,0 +1,40 @@ +From 16c78eb6a12eb7e802aead645bf7703e5bd3a178 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 19:15:10 +0200 +Subject: ARM: OMAP1: Fix DEBUG_LL and earlyprintk on OMAP16XX + +From: Aaro Koskinen + +[ Upstream commit 7e74b606dd39c46d4378d6f6563f560a00ab8694 ] + +On OMAP16XX, the UART enable bit shifts are written instead of the actual +bits. This breaks the boot when DEBUG_LL and earlyprintk is enabled; +the UART gets disabled and some random bits get enabled. Fix that. + +Fixes: 34c86239b184 ("ARM: OMAP1: clock: Fix early UART rate issues") +Signed-off-by: Aaro Koskinen +Link: https://patch.msgid.link/aca7HnXZ-aCSJPW7@darkstar.musicnaut.iki.fi +Signed-off-by: Kevin Hilman +Signed-off-by: Sasha Levin +--- + arch/arm/mach-omap1/clock_data.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c +index c58d200e4816b..5203b047deac8 100644 +--- a/arch/arm/mach-omap1/clock_data.c ++++ b/arch/arm/mach-omap1/clock_data.c +@@ -700,8 +700,8 @@ int __init omap1_clk_init(void) + /* Make sure UART clocks are enabled early */ + if (cpu_is_omap16xx()) + omap_writel(omap_readl(MOD_CONF_CTRL_0) | +- CONF_MOD_UART1_CLK_MODE_R | +- CONF_MOD_UART3_CLK_MODE_R, MOD_CONF_CTRL_0); ++ (1 << CONF_MOD_UART1_CLK_MODE_R) | ++ (1 << CONF_MOD_UART3_CLK_MODE_R), MOD_CONF_CTRL_0); + #endif + + /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ +-- +2.53.0 + diff --git a/queue-6.12/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch b/queue-6.12/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch new file mode 100644 index 0000000000..cb10230151 --- /dev/null +++ b/queue-6.12/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch @@ -0,0 +1,56 @@ +From e300ec0b0b78855abb07f74548a06d4b8be24913 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:28:18 +0000 +Subject: arm64: cpufeature: Make PMUVer and PerfMon unsigned + +From: James Clark + +[ Upstream commit d1dcc20bcc40efe1f1c71639376c91dafa489222 ] + +On the host, this change doesn't make a difference because the fields +are defined as FTR_EXACT. However, KVM allows userspace to set these +fields for a guest and overrides the type to be FTR_LOWER_SAFE. And +while KVM used to do an unsigned comparison to validate that the new +value is lower than what the hardware provides, since the linked commit +it uses the generic sanitization framework which does a signed +comparison. + +Fix it by defining these fields as unsigned. In theory, without this +fix, userspace could set a higher PMU version than the hardware supports +by providing any value with the top bit set. + +Fixes: c118cead07a7 ("KVM: arm64: Use generic sanitisation for ID_(AA64)DFR0_EL1") +Signed-off-by: James Clark +Reviewed-by: Marc Zyngier +Reviewed-by: Colton Lewis +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/cpufeature.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c +index 5e68d65e675e5..8246015fd2d73 100644 +--- a/arch/arm64/kernel/cpufeature.c ++++ b/arch/arm64/kernel/cpufeature.c +@@ -533,7 +533,7 @@ static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = { + * We can instantiate multiple PMU instances with different levels + * of support. + */ +- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), ++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_EL1_DebugVer_SHIFT, 4, 0x6), + ARM64_FTR_END, + }; +@@ -677,7 +677,7 @@ static const struct arm64_ftr_bits ftr_id_pfr2[] = { + + static const struct arm64_ftr_bits ftr_id_dfr0[] = { + /* [31:28] TraceFilt */ +- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), ++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MProfDbg_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MMapTrc_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopTrc_SHIFT, 4, 0), +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch b/queue-6.12/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch new file mode 100644 index 0000000000..e57019a0e4 --- /dev/null +++ b/queue-6.12/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch @@ -0,0 +1,45 @@ +From 0014f91662ccbe334de108a847f7152366a8f65e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 09:45:48 +0100 +Subject: arm64: dts: freescale: imx8mp-tqma8mpql-mba8mp-ras314: fix UART1 + RTS/CTS muxing + +From: Nora Schiffer + +[ Upstream commit b8d785a9f360abcd6a6f8f10a2adf222f8494d66 ] + +UART1 operates in DCE mode, but the RTS/CTS pins were incorrectly +configured using the DTE pinmux setting. + +Correct the pinmux to match DCE mode. Switching the RTS and CTS signals +is fine for this board, as UART1 is routed to a pin header. Existing +functionality is unaffected, as RTS/CTS could never have worked with +the incorrect pinmux. + +Fixes: ddabb3ce3f90 ("arm64: dts: freescale: add TQMa8MPQL on MBa8MP-RAS314") +Signed-off-by: Nora Schiffer +Reviewed-by: Alexander Stein +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +index a122f2ed5f531..06c865c3a8cf8 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +@@ -833,8 +833,8 @@ pinctrl_tlv320aic3x04: tlv320aic3x04grp { + pinctrl_uart1: uart1grp { + fsl,pins = , + , +- , +- ; ++ , ++ ; + }; + + pinctrl_uart1_gpio: uart1gpiogrp { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8-apalis-fix-leds-name-collision.patch b/queue-6.12/arm64-dts-imx8-apalis-fix-leds-name-collision.patch new file mode 100644 index 0000000000..ba35af9363 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8-apalis-fix-leds-name-collision.patch @@ -0,0 +1,103 @@ +From a39b1c3ceb344075667e65d179f8a00726ca79b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:34:09 +0100 +Subject: arm64: dts: imx8-apalis: Fix LEDs name collision + +From: Francesco Dolcini + +[ Upstream commit 92ab53b9bb2a72581c32073755077af916eb9aee ] + +Ixora boards have multiple instances of status leds, to avoid a name +collision add the function-enumerator property. + +This fixes the following Linux kernel warnings: + + leds-gpio leds: Led green:status renamed to green:status_1 due to name collision + leds-gpio leds: Led red:status renamed to red:status_1 due to name collision + +Fixes: c083131c9021 ("arm64: dts: freescale: add apalis imx8 aka quadmax carrier board support") +Signed-off-by: Francesco Dolcini +Reviewed-by: Frank Li +Reviewed-by: Daniel Baluta +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi | 4 ++++ + arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +index 5438923a905ce..5dc12da72dd2e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +@@ -21,6 +21,7 @@ led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; + }; + +@@ -29,6 +30,7 @@ led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; + }; + +@@ -37,6 +39,7 @@ led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; + }; + +@@ -45,6 +48,7 @@ led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +index f6654fdcb1478..f3111bf03a4de 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +@@ -21,6 +21,7 @@ led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; + }; + +@@ -29,6 +30,7 @@ led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; + }; + +@@ -37,6 +39,7 @@ led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; + }; + +@@ -45,6 +48,7 @@ led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch b/queue-6.12/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..9316d2df9d --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch @@ -0,0 +1,48 @@ +From d490e95741286bd889928c68f9bd3a9b2b81fb2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:11 +0800 +Subject: arm64: dts: imx8mm-emtop-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 721dec3ee9ff5231d13a412ff87df63b966d137b ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +While at here, also correct interrupt type as IRQ_TYPE_LEVEL_LOW. + +Fixes: cbd3ef64eb9d1 ("arm64: dts: Add support for Emtop SoM & Baseboard") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +index 67d22d3768aa8..507d1824d99d9 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +@@ -60,7 +60,7 @@ pmic@25 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; +- interrupts = <3 IRQ_TYPE_EDGE_RISING>; ++ interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + regulators { + buck1: BUCK1 { +@@ -194,7 +194,7 @@ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 + + pinctrl_pmic: emtop-pmic-grp { + fsl,pins = < +- MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41 ++ MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x141 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch b/queue-6.12/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..69ab9cfa60 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 29d35cb34b733365e591a9d38e1305b67b96be1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:13 +0800 +Subject: arm64: dts: imx8mm-tqma8mqml: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 42a9f5a16328ed78a88e0498556965b6c6ec515c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: dfcd1b6f7620e ("arm64: dts: freescale: add initial device tree for TQMa8MQML with i.MX8MM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +index 8f58c84e14c8e..d94a59715ee0b 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +@@ -290,7 +290,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch b/queue-6.12/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..676d7541c8 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 2e511aa9e09ad135c9c8f486c00327ad58237513 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:12 +0800 +Subject: arm64: dts: imx8mn-tqma8mqnl: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 0fb37990774113afd943eaa91323679388584b6d ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: 3e56e354db6d3 ("arm64: dts: freescale: add initial device tree for TQMa8MQNL with i.MX8MN") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +index 2d64b2c0b181d..5cd81024269a9 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +@@ -293,7 +293,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch b/queue-6.12/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch new file mode 100644 index 0000000000..8112c2a8d7 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch @@ -0,0 +1,38 @@ +From 716dc4ead48f272fca42a7bfea0fccfdaf2f9c3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:16 +0800 +Subject: arm64: dts: imx8mp-data-modul-edm-sbc: Correct PAD settings for + PMIC_nINT + +From: Peng Fan + +[ Upstream commit 8ff145577e93f312ff398cb950ee3bd44835f5be ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 562d222f23f0f ("arm64: dts: imx8mp: Add support for Data Modul i.MX8M Plus eDM SBC") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +index 16078ff60ef08..fa13662ca3667 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +@@ -900,7 +900,7 @@ MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_PDM_BIT_STREAM00 0x0 + pinctrl_pmic: pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch b/queue-6.12/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch new file mode 100644 index 0000000000..fd18cbaa25 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch @@ -0,0 +1,42 @@ +From e7eb5a372963cba0aaad9da6a7c9afed1256935f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:05 +0800 +Subject: arm64: dts: imx8mp-debix-model-a: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 3b778178997aee24537b521a8cb60970bc1ce01c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there is interrupt storm for i.MX8MP DEBIX Model A. Per schematic, there +is no on board PULL-UP resistors for GPIO1_IO03, so need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: c86d350aae68e ("arm64: dts: Add device tree for the Debix Model A Board") +Reported-by: Laurent Pinchart +Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/ +Reviewed-by: Laurent Pinchart +Tested-by: Laurent Pinchart +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +index af02af9e5334d..740cac4cb31d9 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +@@ -440,7 +440,7 @@ MX8MP_IOMUXC_SAI5_RXC__I2C6_SDA 0x400001c3 + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch b/queue-6.12/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..f771271d91 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch @@ -0,0 +1,56 @@ +From c3441c1af6bdf71cd07648050114ae093fc54fdc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:06 +0800 +Subject: arm64: dts: imx8mp-debix-som-a: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 2ea7872048a179b0ea8dadc67771961df3f0fc4a ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there is interrupt storm for i.MX8MP DEBIX SOM A. Need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: 21baf0b47f81b ("arm64: dts: freescale: Add DEBIX SOM A and SOM A I/O Board support") +Reported-by: Laurent Pinchart +Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/ +Reported-by: Kieran Bingham +Closes: https://lore.kernel.org/imx/20260324194353.GB2352505@killaraus.ideasonboard.com/T/#m9a07fdc75496369a7d76d52c5e34ed140dcabfe3 +Signed-off-by: Peng Fan +Reviewed-by: Kieran Bingham +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts | 2 +- + arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +index d241db3743a9c..ed89d2ccb6ce2 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +@@ -452,7 +452,7 @@ MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x140 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +index 91094c2277443..b31e8fe95ca74 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +@@ -241,7 +241,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch b/queue-6.12/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..aa428b1f8c --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 618dfea520795c0cccc958d27ed52ccaa78e712e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:15 +0800 +Subject: arm64: dts: imx8mp-dhcom-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit f9ed5afc988da3e22543725e35be6addbb0497bc ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 8d6712695bc8e ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +index 1141b26d6b6f9..f2e6391ca3b17 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +@@ -989,7 +989,7 @@ MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20 0x22 + pinctrl_pmic: dhcom-pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch b/queue-6.12/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch new file mode 100644 index 0000000000..625a684399 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch @@ -0,0 +1,43 @@ +From ec87c1635a1d8c86e87bc00201a90104c56b8ab3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 15:34:53 +0800 +Subject: arm64: dts: imx8mp-evk: Enable pull select bit for PCIe regulator + GPIO (M.2 W_DISABLE1) + +From: Sherry Sun + +[ Upstream commit d1e7eab6033f9885a02c4b4e8f09e34d8e9d21ab ] + +The current pin configuration for MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 +sets the weak pull-up but does not enable the pull select field. +Bit 8 in the IOMUX register must be set in order for the weak pull-up +to actually take effect. + +Update the pinctrl setting from 0x40 to 0x140 to enable both the pull +select and the weak pull-up, ensuring the line behaves as expected. + +Fixes: d50650500064 ("arm64: dts: imx8mp-evk: Add PCIe support") +Signed-off-by: Sherry Sun +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +index d26930f1a9e9d..2f1ef1b188bed 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +@@ -947,7 +947,7 @@ MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07 0x40 + + pinctrl_pcie0_reg: pcie0reggrp { + fsl,pins = < +- MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x40 ++ MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x140 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch b/queue-6.12/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..bda196ef64 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch @@ -0,0 +1,37 @@ +From 05c511826912bbf251ed9d54dad89810b52b231f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:09 +0800 +Subject: arm64: dts: imx8mp-icore-mx8mp: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit ea8c90f5c7ceeb6657a8fe564aa7b190dce298a6 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: eefe06b295087 ("arm64: dts: imx8mp: Add Engicam i.Core MX8M Plus SoM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +index a6319824ea2eb..69558ffefa9a6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +@@ -132,7 +132,7 @@ MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x41 ++ MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch b/queue-6.12/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch new file mode 100644 index 0000000000..4159d29043 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch @@ -0,0 +1,38 @@ +From 6175dfc24487a5320ade6976477f8843883c4177 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:07 +0800 +Subject: arm64: dts: imx8mp-navqp: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 741d6ac1a2a2e0f3e2cae5eef3516cdd75119e83 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there will be interrupt storm for i.MX8MP NAVQP. Per schematic, there +is no on board PULL-UP resistors for GPIO1_IO03, so need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: 682729a9d506d ("arm64: dts: freescale: Add device tree for Emcraft Systems NavQ+ Kit") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-navqp.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts +index 5fd1614982cd5..128bc1e6dac54 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts +@@ -309,7 +309,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch b/queue-6.12/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch new file mode 100644 index 0000000000..bb1d4bb68f --- /dev/null +++ b/queue-6.12/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch @@ -0,0 +1,57 @@ +From 1b343337954646e31af9a5e699fd8f246c51563d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:04:58 +0800 +Subject: arm64: dts: imx8qm-mek: switch Type-C connector power-role to dual + +From: Xu Yang + +[ Upstream commit e3d3d19d1c0050789a4813ce836a641a3387d916 ] + +When attach to PC Type-A port, the USB device controller does not function +at all. Because it is configured as source-only and a Type-A port doesn't +support PD capability, a data role swap is impossible. + +Actually, PTN5110THQ is configured for Source role only at POR, but after +POR it can operate as a DRP (Dual-Role Power). By switching the power-role +to dual, the port can operate as a sink and enter device mode when attach +to Type-A port. + +Since the board design uses EN_SRC to control the 5V VBUS path and EN_SNK +to control the 12V VBUS output, to avoid outputting a higher VBUS when in +sink role, we set the operation current limit to 0mA so that SW will not +control EN_SNK at all. + +Fixes: b237975b2cd58 ("arm64: dts: imx8qm-mek: add usb 3.0 and related type C nodes") +Signed-off-by: Xu Yang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8qm-mek.dts | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +index 19c8d7ce1d409..32a37e0d0b425 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts ++++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +@@ -351,9 +351,17 @@ ptn5110: tcpc@51 { + usb_con1: connector { + compatible = "usb-c-connector"; + label = "USB-C"; +- power-role = "source"; ++ power-role = "dual"; + data-role = "dual"; ++ try-power-role = "sink"; + source-pdos = ; ++ /* ++ * Set operational current to 0mA as we don't want EN_SNK ++ * enable 12V VBUS switch when it work as a sink. ++ */ ++ sink-pdos = ; ++ op-sink-microwatt = <0>; ++ self-powered; + + ports { + #address-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch b/queue-6.12/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch new file mode 100644 index 0000000000..5cde6a0a87 --- /dev/null +++ b/queue-6.12/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch @@ -0,0 +1,57 @@ +From 501e8294938b0ea314adee624a36b2e0a854cbb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:04:59 +0800 +Subject: arm64: dts: imx8qxp-mek: switch Type-C connector power-role to dual + +From: Xu Yang + +[ Upstream commit 825b8c7e1d2918d89eb378b761530d1e51dba82e ] + +When attach to PC Type-A port, the USB device controller does not function +at all. Because it is configured as source-only and a Type-A port doesn't +support PD capability, a data role swap is impossible. + +Actually, PTN5110THQ is configured for Source role only at POR, but after +POR it can operate as a DRP (Dual-Role Power). By switching the power-role +to dual, the port can operate as a sink and enter device mode when attach +to Type-A port. + +Since the board design uses EN_SRC to control the 5V VBUS path and EN_SNK +to control the 12V VBUS output, to avoid outputting a higher VBUS when in +sink role, we set the operation current limit to 0mA so that SW will not +control EN_SNK at all. + +Fixes: 2faf4ebcee2e5 ("arm64: dts: freescale: imx8qxp-mek: enable cadence usb3") +Signed-off-by: Xu Yang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +index 936ba5ecdcac7..447a6a4c3c7ec 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts ++++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +@@ -176,9 +176,17 @@ ptn5110: tcpc@50 { + usb_con1: connector { + compatible = "usb-c-connector"; + label = "USB-C"; +- power-role = "source"; ++ power-role = "dual"; + data-role = "dual"; ++ try-power-role = "sink"; + source-pdos = ; ++ /* ++ * Set operational current to 0mA as we don't want EN_SNK ++ * enable 12V VBUS switch when it work as a sink. ++ */ ++ sink-pdos = ; ++ op-sink-microwatt = <0>; ++ self-powered; + + ports { + #address-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch b/queue-6.12/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch new file mode 100644 index 0000000000..9f2cffa6b0 --- /dev/null +++ b/queue-6.12/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch @@ -0,0 +1,99 @@ +From 437c95e5b70c2d0a2582628174abfdf5e428aa16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:59 +0100 +Subject: arm64: dts: lx2160a: add sda gpio references for i2c bus recovery + +From: Josua Mayer + +[ Upstream commit 89ea0dbd701f89805499d26bd90657468c789545 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +In particular i2c sda/scl pins are always configured together. Therefore +bus recovery may control both sda and scl. + +When pinmux nodes and bus recovery was enabled originally for LX2160, +only the scl-gpios were added to the i2c controller nodes. + +Add references to sda-gpios for each i2c controller. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 2b322cdab9479..83e618df6f4b9 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -753,6 +753,7 @@ i2c0: i2c@2000000 { + pinctrl-0 = <&i2c0_pins>; + pinctrl-1 = <&gpio0_3_2_pins>; + scl-gpios = <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -769,6 +770,7 @@ i2c1: i2c@2010000 { + pinctrl-0 = <&i2c1_pins>; + pinctrl-1 = <&gpio0_31_30_pins>; + scl-gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -785,6 +787,7 @@ i2c2: i2c@2020000 { + pinctrl-0 = <&i2c2_pins>; + pinctrl-1 = <&gpio0_29_28_pins>; + scl-gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -801,6 +804,7 @@ i2c3: i2c@2030000 { + pinctrl-0 = <&i2c3_pins>; + pinctrl-1 = <&gpio0_27_26_pins>; + scl-gpios = <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -817,6 +821,7 @@ i2c4: i2c@2040000 { + pinctrl-0 = <&i2c4_pins>; + pinctrl-1 = <&gpio0_25_24_pins>; + scl-gpios = <&gpio0 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -833,6 +838,7 @@ i2c5: i2c@2050000 { + pinctrl-0 = <&i2c5_pins>; + pinctrl-1 = <&gpio0_23_22_pins>; + scl-gpios = <&gpio0 23 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -849,6 +855,7 @@ i2c6: i2c@2060000 { + pinctrl-0 = <&i2c6_i2c7_pins>; + pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio1 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -865,6 +872,7 @@ i2c7: i2c@2070000 { + pinctrl-0 = <&i2c6_i2c7_pins>; + pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio1 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch b/queue-6.12/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch new file mode 100644 index 0000000000..2222f070ef --- /dev/null +++ b/queue-6.12/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch @@ -0,0 +1,55 @@ +From 908734bafb65fb443f5632c750c67b4f8687a305 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:56 +0100 +Subject: arm64: dts: lx2160a: change i2c0 (iic1) pinmux mask to one bit + +From: Josua Mayer + +[ Upstream commit 7a3cc49ad1fc8d063abb7f5de8f1b981b99d2978 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +The first i2c bus (called IIC1 in reference manual) is configured through +field IIC1_PMUX in register RCWSR14 bit 10 which is described in the +reference manual as a single bit, unlike the other i2c buses. + +Change the bitmask for the pinmux nodes from 0x7 to 0x1 to ensure only +single bit is modified. + +Further change the zero in the same line to hexadecimal format for +consistency. + +Align with documentation by avoiding writes to reserved bits. No functional +change, as writing the extra two reserved bits is not known to cause +issues. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 97f2ed267d698..e2c32f5b6a521 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1790,11 +1790,11 @@ i2c7_scl_gpio: i2c7-scl-gpio-pins { + }; + + i2c0_scl: i2c0-scl-pins { +- pinctrl-single,bits = <0x8 0 (0x7 << 10)>; ++ pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; + + i2c0_scl_gpio: i2c0-scl-gpio-pins { +- pinctrl-single,bits = <0x8 (0x1 << 10) (0x7 << 10)>; ++ pinctrl-single,bits = <0x8 (0x1 << 10) (0x1 << 10)>; + }; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch b/queue-6.12/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch new file mode 100644 index 0000000000..19dd428536 --- /dev/null +++ b/queue-6.12/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch @@ -0,0 +1,74 @@ +From 69aab7ccad4d8ea73c13d53bb66de032fee6e231 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:41:00 +0100 +Subject: arm64: dts: lx2160a: change zeros to hexadecimal in pinmux nodes + +From: Josua Mayer + +[ Upstream commit 03241620d2b9915c9e3463dbc56e9eb95ad43c08 ] + +Replace some stray zeros from decimal to hexadecimal format within +pinmux nodes. + +No functional change intended. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 83e618df6f4b9..15a5691c40060 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1718,7 +1718,7 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,function-mask = <0x7>; + + i2c1_pins: iic2-i2c-pins { +- pinctrl-single,bits = <0x0 0 0x7>; ++ pinctrl-single,bits = <0x0 0x0 0x7>; + }; + + gpio0_31_30_pins: iic2-gpio-pins { +@@ -1730,7 +1730,7 @@ esdhc0_cd_wp_pins: iic2-sdhc-pins { + }; + + i2c2_pins: iic3-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 3)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 3)>; + }; + + gpio0_29_28_pins: iic3-gpio-pins { +@@ -1738,7 +1738,7 @@ gpio0_29_28_pins: iic3-gpio-pins { + }; + + i2c3_pins: iic4-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 6)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 6)>; + }; + + gpio0_27_26_pins: iic4-gpio-pins { +@@ -1746,7 +1746,7 @@ gpio0_27_26_pins: iic4-gpio-pins { + }; + + i2c4_pins: iic5-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 9)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 9)>; + }; + + gpio0_25_24_pins: iic5-gpio-pins { +@@ -1754,7 +1754,7 @@ gpio0_25_24_pins: iic5-gpio-pins { + }; + + i2c5_pins: iic6-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 12)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 12)>; + }; + + gpio0_23_22_pins: iic6-gpio-pins { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch b/queue-6.12/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch new file mode 100644 index 0000000000..8cbec2d44b --- /dev/null +++ b/queue-6.12/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch @@ -0,0 +1,190 @@ +From 9954b27e468cc81b5daa14a73959216e77dbf8ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:41:01 +0100 +Subject: arm64: dts: lx2160a: complete pinmux for rcwsr12 configuration word + +From: Josua Mayer + +[ Upstream commit 284ad7064aaa1badde022785cd925af29c696b21 ] + +Commit 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to +support bus recovery") introduced pinmux nodes for lx2160 i2c +interfaces, allowing runtime change between i2c and gpio functions +implementing bus recovery. + +However, the dynamic configuration area (overwrite MUX) used by the +pinctrl-single driver initially reads as zero and does not reflect the +actual hardware state set by the Reset Configuration Word (RCW) at +power-on. + +Because multiple groups of pins are configured from a single 32-bit +register, the first write from the pinctrl driver unintentionally clears +all other bits to zero. + +Add description for all bits of RCWSR12 register, allowing boards to +explicitly define and restore their intended hardware state. + +This includes i2c, gpio, flextimer, spi, can and sdhc functions. + +Other configuration words, i.e. RCWSR13 & RCWSR14 may be added in the +future for boards setting non-zero values there. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 75 +++++++++++++++++++ + 1 file changed, 75 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 15a5691c40060..04c27ef91fb27 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1717,6 +1717,7 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x7>; + ++ /* RCWSR12 */ + i2c1_pins: iic2-i2c-pins { + pinctrl-single,bits = <0x0 0x0 0x7>; + }; +@@ -1725,6 +1726,10 @@ gpio0_31_30_pins: iic2-gpio-pins { + pinctrl-single,bits = <0x0 0x1 0x7>; + }; + ++ ftm0_ch10_pins: iic2-ftm-pins { ++ pinctrl-single,bits = <0x0 0x2 0x7>; ++ }; ++ + esdhc0_cd_wp_pins: iic2-sdhc-pins { + pinctrl-single,bits = <0x0 0x6 0x7>; + }; +@@ -1737,6 +1742,14 @@ gpio0_29_28_pins: iic3-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 3) (0x7 << 3)>; + }; + ++ can0_pins: iic3-can-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 3) (0x7 << 3)>; ++ }; ++ ++ event65_pins: iic3-event-pins { ++ pinctrl-single,bits = <0x0 (0x6 << 3) (0x7 << 3)>; ++ }; ++ + i2c3_pins: iic4-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 6)>; + }; +@@ -1745,6 +1758,14 @@ gpio0_27_26_pins: iic4-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 6) (0x7 << 6)>; + }; + ++ can1_pins: iic4-can-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 6) (0x7 << 6)>; ++ }; ++ ++ event87_pins: iic4-event-pins { ++ pinctrl-single,bits = <0x0 (0x6 << 6) (0x7 << 6)>; ++ }; ++ + i2c4_pins: iic5-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 9)>; + }; +@@ -1753,6 +1774,14 @@ gpio0_25_24_pins: iic5-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 9) (0x7 << 9)>; + }; + ++ esdhc0_clksync_pins: iic5-sdhc-clk-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 9) (0x7 << 9)>; ++ }; ++ ++ dspi2_miso_mosi_pins: iic5-spi3-pins { ++ pinctrl-single,bits = <0x3 (0x2 << 9) (0x7 << 9)>; ++ }; ++ + i2c5_pins: iic6-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 12)>; + }; +@@ -1761,26 +1790,71 @@ gpio0_23_22_pins: iic6-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 12) (0x7 << 12)>; + }; + ++ esdhc1_clksync_pins: iic6-sdhc-clk-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 12) (0x7 << 12)>; ++ }; ++ + fspi_data74_pins: xspi1-data74-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 15)>; + }; + ++ gpio1_31_28_pins: xspi1-data74-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 15)>; ++ }; ++ + fspi_data30_pins: xspi1-data30-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 18)>; + }; + ++ gpio1_27_24_pins: xspi1-data30-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 18)>; ++ }; ++ + fspi_dqs_sck_cs10_pins: xspi1-base-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 21)>; + }; + ++ gpio1_23_20_pins: xspi1-base-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 21)>; ++ }; ++ + esdhc0_cmd_data30_clk_vsel_pins: sdhc1-base-sdhc-vsel-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 24)>; + }; + ++ gpio0_21_15_pins: sdhc1-base-gpio-pins { ++ pinctrl-single,bits = <0x0 (0x1 << 24) (0x7 << 24)>; ++ }; ++ ++ dspi0_pins: sdhc1-base-spi1-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_cmd_data30_clk_dspi2_cs0_pins: sdhc1-base-sdhc-spi3-pins { ++ pinctrl-single,bits = <0x0 (0x3 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_cmd_data30_clk_data4_pins: sdhc1-base-sdhc-data4-pins { ++ pinctrl-single,bits = <0x0 (0x4 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_dir_pins: sdhc1-dir-pins { ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 27)>; ++ }; ++ + gpio0_14_12_pins: sdhc1-dir-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 27) (0x7 << 27)>; + }; + ++ dspi2_cs31_pins: sdhc1-dir-spi3-pins { ++ pinctrl-single,bits = <0x0 (0x3 << 27) (0x7 << 27)>; ++ }; ++ ++ esdhc0_data75_pins: sdhc1-dir-sdhc-pins { ++ pinctrl-single,bits = <0x0 (0x4 << 27) (0x7 << 27)>; ++ }; ++ ++ /* RCWSR13 */ + gpio1_18_15_pins: iic8-iic7-gpio-pins { + pinctrl-single,bits = <0x4 0x1 0x7>; + }; +@@ -1789,6 +1863,7 @@ i2c6_i2c7_pins: iic8-iic7-i2c-pins { + pinctrl-single,bits = <0x4 0x2 0x7>; + }; + ++ /* RCWSR14 */ + i2c0_pins: iic1-i2c-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch b/queue-6.12/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch new file mode 100644 index 0000000000..f8e9a49f7c --- /dev/null +++ b/queue-6.12/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch @@ -0,0 +1,62 @@ +From 0c34dde843812bd8dee73fb3d8beee998208cb53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:57 +0100 +Subject: arm64: dts: lx2160a: remove duplicate pinmux nodes + +From: Josua Mayer + +[ Upstream commit 325ca511ca3dda936207ce737e0afe837d45a674 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +The pinmux nodes i2c7-scl-pins and i2c7-scl-gpio-pins are duplicates of +i2c6-scl-gpio and i2c6-scl-gpio-pins, writing to the same register and +bits. + +These two i2c buses i2c6/i2c7 (IIC7/IIC8) are configured together in +register RCWSR13 bits 3-0. + +Drop the duplicate node name and change references to the i2c6 node. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index e2c32f5b6a521..599d7d4a4c573 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -862,8 +862,8 @@ i2c7: i2c@2070000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c7_scl>; +- pinctrl-1 = <&i2c7_scl_gpio>; ++ pinctrl-0 = <&i2c6_scl>; ++ pinctrl-1 = <&i2c6_scl_gpio>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -1781,14 +1781,6 @@ i2c6_scl_gpio: i2c6-scl-gpio-pins { + pinctrl-single,bits = <0x4 0x1 0x7>; + }; + +- i2c7_scl: i2c7-scl-pins { +- pinctrl-single,bits = <0x4 0x2 0x7>; +- }; +- +- i2c7_scl_gpio: i2c7-scl-gpio-pins { +- pinctrl-single,bits = <0x4 0x1 0x7>; +- }; +- + i2c0_scl: i2c0-scl-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch b/queue-6.12/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch new file mode 100644 index 0000000000..27775616c0 --- /dev/null +++ b/queue-6.12/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch @@ -0,0 +1,219 @@ +From 40dc961c81b966a34a25b1395f7fb7b6aaa54586 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:58 +0100 +Subject: arm64: dts: lx2160a: rename pinmux nodes for readability + +From: Josua Mayer + +[ Upstream commit 456eb494746afd56d3a9dc30271300136e55b96e ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +Each group of pins is named in the reference manual after a primary +function using soc-specific naming, e.g. IIC1 (for i2c0). + +Hardware block numbering starts from zero in device-tree but one in the +reference manual. + +Rename the already defined pinmux nodes originally added for changing +i2c pins between i2c and gpio functions reflecting the reference manual +name (IIC) in the node name, and the device-tree name (i2c, gpio) in the +label. + +Specifically, drop the "_scl" suffix from the I2C labels because the +nodes actually configure both SDA and SCL pins together. Instead add +"_pins" suffix to avoid conflicts with I2C controller labels. + +For GPIO functions, include the specific controller and pin numbers in +the label to clarify they are generic GPIOs and help spot mistakes. + +No functional change intended. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 64 +++++++++---------- + 1 file changed, 32 insertions(+), 32 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 599d7d4a4c573..2b322cdab9479 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -750,8 +750,8 @@ i2c0: i2c@2000000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c0_scl>; +- pinctrl-1 = <&i2c0_scl_gpio>; ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-1 = <&gpio0_3_2_pins>; + scl-gpios = <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -766,8 +766,8 @@ i2c1: i2c@2010000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c1_scl>; +- pinctrl-1 = <&i2c1_scl_gpio>; ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-1 = <&gpio0_31_30_pins>; + scl-gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -782,8 +782,8 @@ i2c2: i2c@2020000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c2_scl>; +- pinctrl-1 = <&i2c2_scl_gpio>; ++ pinctrl-0 = <&i2c2_pins>; ++ pinctrl-1 = <&gpio0_29_28_pins>; + scl-gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -798,8 +798,8 @@ i2c3: i2c@2030000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c3_scl>; +- pinctrl-1 = <&i2c3_scl_gpio>; ++ pinctrl-0 = <&i2c3_pins>; ++ pinctrl-1 = <&gpio0_27_26_pins>; + scl-gpios = <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -814,8 +814,8 @@ i2c4: i2c@2040000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c4_scl>; +- pinctrl-1 = <&i2c4_scl_gpio>; ++ pinctrl-0 = <&i2c4_pins>; ++ pinctrl-1 = <&gpio0_25_24_pins>; + scl-gpios = <&gpio0 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -830,8 +830,8 @@ i2c5: i2c@2050000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c5_scl>; +- pinctrl-1 = <&i2c5_scl_gpio>; ++ pinctrl-0 = <&i2c5_pins>; ++ pinctrl-1 = <&gpio0_23_22_pins>; + scl-gpios = <&gpio0 23 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -846,8 +846,8 @@ i2c6: i2c@2060000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c6_scl>; +- pinctrl-1 = <&i2c6_scl_gpio>; ++ pinctrl-0 = <&i2c6_i2c7_pins>; ++ pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -862,8 +862,8 @@ i2c7: i2c@2070000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c6_scl>; +- pinctrl-1 = <&i2c6_scl_gpio>; ++ pinctrl-0 = <&i2c6_i2c7_pins>; ++ pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -1709,11 +1709,11 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x7>; + +- i2c1_scl: i2c1-scl-pins { ++ i2c1_pins: iic2-i2c-pins { + pinctrl-single,bits = <0x0 0 0x7>; + }; + +- i2c1_scl_gpio: i2c1-scl-gpio-pins { ++ gpio0_31_30_pins: iic2-gpio-pins { + pinctrl-single,bits = <0x0 0x1 0x7>; + }; + +@@ -1721,35 +1721,35 @@ esdhc0_cd_wp_pins: iic2-sdhc-pins { + pinctrl-single,bits = <0x0 0x6 0x7>; + }; + +- i2c2_scl: i2c2-scl-pins { ++ i2c2_pins: iic3-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 3)>; + }; + +- i2c2_scl_gpio: i2c2-scl-gpio-pins { ++ gpio0_29_28_pins: iic3-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 3) (0x7 << 3)>; + }; + +- i2c3_scl: i2c3-scl-pins { ++ i2c3_pins: iic4-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 6)>; + }; + +- i2c3_scl_gpio: i2c3-scl-gpio-pins { ++ gpio0_27_26_pins: iic4-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 6) (0x7 << 6)>; + }; + +- i2c4_scl: i2c4-scl-pins { ++ i2c4_pins: iic5-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 9)>; + }; + +- i2c4_scl_gpio: i2c4-scl-gpio-pins { ++ gpio0_25_24_pins: iic5-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 9) (0x7 << 9)>; + }; + +- i2c5_scl: i2c5-scl-pins { ++ i2c5_pins: iic6-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 12)>; + }; + +- i2c5_scl_gpio: i2c5-scl-gpio-pins { ++ gpio0_23_22_pins: iic6-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 12) (0x7 << 12)>; + }; + +@@ -1773,19 +1773,19 @@ gpio0_14_12_pins: sdhc1-dir-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 27) (0x7 << 27)>; + }; + +- i2c6_scl: i2c6-scl-pins { +- pinctrl-single,bits = <0x4 0x2 0x7>; ++ gpio1_18_15_pins: iic8-iic7-gpio-pins { ++ pinctrl-single,bits = <0x4 0x1 0x7>; + }; + +- i2c6_scl_gpio: i2c6-scl-gpio-pins { +- pinctrl-single,bits = <0x4 0x1 0x7>; ++ i2c6_i2c7_pins: iic8-iic7-i2c-pins { ++ pinctrl-single,bits = <0x4 0x2 0x7>; + }; + +- i2c0_scl: i2c0-scl-pins { ++ i2c0_pins: iic1-i2c-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; + +- i2c0_scl_gpio: i2c0-scl-gpio-pins { ++ gpio0_3_2_pins: iic1-gpio-pins { + pinctrl-single,bits = <0x8 (0x1 << 10) (0x1 << 10)>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch b/queue-6.12/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch new file mode 100644 index 0000000000..9667a2db68 --- /dev/null +++ b/queue-6.12/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch @@ -0,0 +1,59 @@ +From c551f91fc6f0875a7a425598a244106a4432fe6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 17:25:16 +0200 +Subject: arm64: dts: marvell: armada-37xx: use 'usb2-phy' in USB3 controller's + phy-names + +From: Gabor Juhos + +[ Upstream commit 0fef19844624f8bc07651b4d26088d8940affba3 ] + +Instead of the generic 'usb2-phy' name, the Armada 37xx device trees +are using a custom 'usb2-utmi-otg-phy' name for the USB2 PHY in the USB3 +controller node. Since commit 53a2d95df836 ("usb: core: add phy notify +connect and disconnect"), this triggers a bug [1] in the USB core which +causes double use of the USB3 PHY. + +Change the PHY name to 'usb2-phy' in the SoC and in the uDPU specific +dtsi files in order to avoid triggering the bug and also to keep the +names in line with the ones used by other platforms. + +Link: https://lore.kernel.org/r/20260330-usb-avoid-usb3-phy-double-use-v1-1-d2113aecb535@gmail.com # [1] +Fixes: 53a2d95df836 ("usb: core: add phy notify connect and disconnect") +Signed-off-by: Gabor Juhos +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi | 2 +- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +index cd856c0aba71e..12deacb741ccb 100644 +--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +@@ -161,7 +161,7 @@ ð1 { + &usb3 { + status = "okay"; + phys = <&usb2_utmi_otg_phy>; +- phy-names = "usb2-utmi-otg-phy"; ++ phy-names = "usb2-phy"; + }; + + &uart0 { +diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +index 9603223dd761f..16b2b70529506 100644 +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -375,7 +375,7 @@ usb3: usb@58000 { + interrupts = ; + clocks = <&sb_periph_clk 12>; + phys = <&comphy0 0>, <&usb2_utmi_otg_phy>; +- phy-names = "usb3-phy", "usb2-utmi-otg-phy"; ++ phy-names = "usb3-phy", "usb2-phy"; + status = "disabled"; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch b/queue-6.12/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..7c6335f214 --- /dev/null +++ b/queue-6.12/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From 63cc78c5ae61aae79ad674a39e5be87e64934be7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:28 +0900 +Subject: arm64: dts: mediatek: mt6795: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit c4c4823c8a5baa10b8100b01f49d7c3f4a871689 ] + +The gpio-ranges in the MT6795 pinctrl node were incorrectly defined, +therefore, GPIO196 cannot be used. +Correct the range count to match the driver. + +Fixes: b888886a4536 ("arm64: dts: mediatek: mt6795: Add pinctrl controller node") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt6795.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +index e5e269a660b11..5dd822d470e89 100644 +--- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +@@ -372,7 +372,7 @@ pio: pinctrl@10005000 { + ; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 196>; ++ gpio-ranges = <&pio 0 0 197>; + interrupt-controller; + #interrupt-cells = <2>; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch b/queue-6.12/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..9802e1ce12 --- /dev/null +++ b/queue-6.12/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From 80e146a30ff785d1d9775338218599f6b43fb3b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:29 +0900 +Subject: arm64: dts: mediatek: mt7981b: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit b62a927f4a46a7f58d88ba3d5fb6e88e1a4b4603 ] + +The gpio-ranges in the MT7981B pinctrl node were incorrectly defined, +therefore, pin 56 cannot be used. +Correct the range count to match the driver. + +Fixes: 62b24c7fdf0a ("arm64: dts: mediatek: mt7981: add pinctrl") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 5cbea9cd411fb..63da296bebad6 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -200,7 +200,7 @@ pio: pinctrl@11d00000 { + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; +- gpio-ranges = <&pio 0 0 56>; ++ gpio-ranges = <&pio 0 0 57>; + gpio-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch b/queue-6.12/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..ab524d2f64 --- /dev/null +++ b/queue-6.12/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From f10001c14c6257a6d6e044e61a90dc6edfefa39e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:30 +0900 +Subject: arm64: dts: mediatek: mt7986a: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit 820ed0c1a13c5fafb36232538d793f99a0986ef3 ] + +The gpio-ranges in the MT7986A pinctrl node were incorrectly defined, +therefore, pin 100 cannot be used. +Correct the range count to match the driver. + +Fixes: c3a064a32ed9 ("arm64: dts: mediatek: add pinctrl support for mt7986a") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 559990dcd1d17..05bd2938242fc 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -187,7 +187,7 @@ pio: pinctrl@1001f000 { + "iocfg_lb", "iocfg_tr", "iocfg_tl", "eint"; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 100>; ++ gpio-ranges = <&pio 0 0 101>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch b/queue-6.12/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch new file mode 100644 index 0000000000..44dbd35d7e --- /dev/null +++ b/queue-6.12/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch @@ -0,0 +1,58 @@ +From 0472fbcaada7bbc0e8ac1a0db4edce08070e3424 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 May 2025 12:43:22 -0400 +Subject: arm64: dts: mediatek: mt8365: Describe infracfg-nao as a pure syscon +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit 0651c24658360706c30588cec0a12c05edb03e9a ] + +The infracfg-nao register space at 0x1020e000 has different registers +than the infracfg space at 0x10001000, and most importantly, doesn't +contain any clock controls. Therefore it shouldn't use the same +compatible used for the mt8365 infracfg clocks driver: +mediatek,mt8365-infracfg. Since it currently does, probe errors are +reported in the kernel logs: + + [ 0.245959] Failed to register clk ifr_pmic_tmr: -EEXIST + [ 0.245998] clk-mt8365 1020e000.infracfg: probe with driver clk-mt8365 failed with error -17 + +This register space is used only as a syscon for bus control by the +power domain controller, so in order to properly describe it and fix the +errors, set its compatible to a distinct compatible used exclusively as +a syscon, drop the clock-cells, and while at it rename the node to +'syscon' following the naming convention. + +Fixes: 6ff945376556 ("arm64: dts: mediatek: Initial mt8365-evk support") +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: David Lechner +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt8365.dtsi | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8365.dtsi b/arch/arm64/boot/dts/mediatek/mt8365.dtsi +index 2bf8c9d02b6ee..e9ec44ee72e23 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8365.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8365.dtsi +@@ -481,10 +481,9 @@ iommu: iommu@10205000 { + #iommu-cells = <1>; + }; + +- infracfg_nao: infracfg@1020e000 { +- compatible = "mediatek,mt8365-infracfg", "syscon"; ++ infracfg_nao: syscon@1020e000 { ++ compatible = "mediatek,mt8365-infracfg-nao", "syscon"; + reg = <0 0x1020e000 0 0x1000>; +- #clock-cells = <1>; + }; + + rng: rng@1020f000 { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch b/queue-6.12/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch new file mode 100644 index 0000000000..79e23e1449 --- /dev/null +++ b/queue-6.12/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch @@ -0,0 +1,44 @@ +From f8fabaa15c756a4a19d5665373f4548bca401af4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:51:11 +0800 +Subject: arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number + +From: Jun Yan + +[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ] + +Correct the interrupt number assigned to the Realtek PHY in the p230 + +following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm: +fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY +interrupt improvements [1]. + +[1] https://lore.kernel.org/all/20171202214037.17017-1-martin.blumenstingl@googlemail.com/ + +Fixes: b94d22d94ad2 ("ARM64: dts: meson-gx: add external PHY interrupt on some platforms") +Signed-off-by: Jun Yan +Reviewed-by: Martin Blumenstingl +Link: https://patch.msgid.link/20260330145111.115318-1-jerrysteve1101@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +index c1470416faade..36e97ed585ae7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +@@ -84,7 +84,8 @@ external_phy: ethernet-phy@0 { + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; +- interrupts = <29 IRQ_TYPE_LEVEL_LOW>; ++ /* MAC_INTR on GPIOZ_15 */ ++ interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + eee-broken-1000t; + }; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch b/queue-6.12/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch new file mode 100644 index 0000000000..b4f3ad78bb --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch @@ -0,0 +1,44 @@ +From bed371b94228e077dc88e850716aecfdcc624974 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:39 +0100 +Subject: arm64: dts: qcom: msm8953-xiaomi-daisy: fix backlight +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 7131f6d909a6546329b71f2bacfdc60cb3e6020e ] + +The backlight on this device is connected via 3 strings. Currently, +the DT claims only two are present, which results in visible stripes +on the display (since every third backlight string remains unconfigured). + +Fix the number of strings to avoid that. + +Fixes: 38d779c26395 ("arm64: dts: qcom: msm8953: Add device tree for Xiaomi Mi A2 Lite") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-7-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +index 336b916729e47..4e59d7de99766 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +@@ -157,7 +157,7 @@ &pm8953_resin { + + &pmi8950_wled { + qcom,current-limit-microamp = <20000>; +- qcom,num-strings = <2>; ++ qcom,num-strings = <3>; + + status = "okay"; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch b/queue-6.12/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch new file mode 100644 index 0000000000..bc9b0314a4 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch @@ -0,0 +1,41 @@ +From 6eb1e0789e7624824a3d9237163616c7398e6066 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:37 +0100 +Subject: arm64: dts: qcom: msm8953-xiaomi-vince: correct wled ovp value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 9e87f0eaadccc3fecdf3c3c0334e05694804b5f5 ] + +PMI8950 doesn't actually support setting an OVP threshold value of +29.6 V. The closest allowed value is 29.5 V. Set that instead. + +Fixes: aa17e707e04a ("arm64: dts: qcom: msm8953: Add device tree for Xiaomi Redmi 5 Plus") +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-5-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +index d46325e799176..c2a290bf493c1 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +@@ -169,7 +169,7 @@ &pm8953_resin { + + &pmi8950_wled { + qcom,current-limit-microamp = <20000>; +- qcom,ovp-millivolt = <29600>; ++ qcom,ovp-millivolt = <29500>; + qcom,num-strings = <2>; + qcom,external-pfet; + qcom,cabc; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch b/queue-6.12/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch new file mode 100644 index 0000000000..d49a3d7cf8 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch @@ -0,0 +1,38 @@ +From 9388bab6caaf8f5854aadc4f7e6667d3051df156 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 18:33:11 +0100 +Subject: arm64: dts: qcom: sdm845-xiaomi-beryllium: Mark l1a regulator as + powered during boot + +From: David Heidelberg + +[ Upstream commit 3b0dd81eea6b7a239fce456ce4545af76f1a9715 ] + +The regulator must be on, since it provides the display subsystem and +therefore the bootloader had turned it on before Linux booted. + +Fixes: 77809cf74a8c ("arm64: dts: qcom: Add support for Xiaomi Poco F1 (Beryllium)") +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260320-beryllium-booton-v2-1-931d1be21eae@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +index 617b17b2d7d9d..c872d6442018d 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +@@ -147,6 +147,7 @@ vreg_l1a_0p875: ldo1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l5a_0p8: ldo5 { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch b/queue-6.12/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch new file mode 100644 index 0000000000..b510259e36 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch @@ -0,0 +1,63 @@ +From a78a8c4d94ac4dd74fe80f10e3a8e4391891c983 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 09:55:00 +0100 +Subject: arm64: dts: qcom: sm7225-fairphone-fp4: Fix conflicting bias pinctrl + +From: Luca Weiss + +[ Upstream commit be7c1badb0b934cfe88427b1d4ec3eb9f52ba587 ] + +The pinctrl nodes from sm6350.dtsi already contain a bias-* property, so +that needs to be deleted, otherwise the dtb will contain two conflicting +bias-* properties. + +Reported-by: Conor Dooley +Closes: https://lore.kernel.org/r/20260310-maritime-silly-05e7b7e03aa6@spud/ +Fixes: c4ef464b24c5 ("arm64: dts: qcom: sm7225-fairphone-fp4: Add Bluetooth") +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Reviewed-by: Conor Dooley +Link: https://lore.kernel.org/r/20260319-fp4-uart1-fix-v1-1-f6b3fedef583@fairphone.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +index 52b16a4fdc432..83dac3ca53318 100644 +--- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts ++++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +@@ -946,12 +946,14 @@ &qup_uart1_cts { + * the Bluetooth module drives the pin in either + * direction or leaves the pin fully unpowered. + */ ++ /delete-property/ bias-disable; + bias-bus-hold; + }; + + &qup_uart1_rts { + /* We'll drive RTS, so no pull */ + drive-strength = <2>; ++ /delete-property/ bias-pull-down; + bias-disable; + }; + +@@ -962,12 +964,14 @@ &qup_uart1_rx { + * in tri-state (module powered off or not driving the + * signal yet). + */ ++ /delete-property/ bias-disable; + bias-pull-up; + }; + + &qup_uart1_tx { + /* We'll drive TX, so no pull */ + drive-strength = <2>; ++ /delete-property/ bias-pull-up; + bias-disable; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch b/queue-6.12/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch new file mode 100644 index 0000000000..cfba25cc97 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch @@ -0,0 +1,43 @@ +From 525ac798bb1b907cda84541f35d7f6c95ba79543 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 04:26:37 +0000 +Subject: arm64: dts: qcom: sm8250: Add missing CPU7 3.09GHz OPP + +From: Alexander Koskovich + +[ Upstream commit b683730e27ba4f91986c4c92f5cb7297f1e01a6d ] + +This resolves the following error seen on the ASUS ROG Phone 3: + +cpu cpu7: Voltage update failed freq=3091200 +cpu cpu7: failed to update OPP for freq=3091200 + +Fixes: 8e0e8016cb79 ("arm64: dts: qcom: sm8250: Add CPU opp tables") +Signed-off-by: Alexander Koskovich +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260307-sm8250-cpu7-opp-v1-1-435f5f6628a1@pm.me +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8250.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi +index e17937f76806c..9995fc515e113 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi +@@ -664,6 +664,11 @@ cpu7_opp20: opp-2841600000 { + opp-hz = /bits/ 64 <2841600000>; + opp-peak-kBps = <8368000 51609600>; + }; ++ ++ cpu7_opp21: opp-3091200000 { ++ opp-hz = /bits/ 64 <3091200000>; ++ opp-peak-kBps = <8368000 51609600>; ++ }; + }; + + firmware { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.12/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..e08607c900 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,75 @@ +From 873a1bff801720e1a7f6cf32e30760d7ec2d0ee0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:13 +0200 +Subject: arm64: dts: qcom: sm8450: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit db0c5ef1abda6effdc5c85d6688fb6af2b351ae5 ] + +The reported problem of some non-working UHS-I speed modes on SM8450 +originates in commit 0a631a36f724 ("arm64: dts: qcom: Add device tree +for Sony Xperia 1 IV"), and then it was spread to all SM8450 powered +platforms by commit 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable +SDHCI SDR104/SDR50 on all boards"). + +The tests show that the rootcause of the problem was related to an +overclocking of SD cards, and it's fixed later on by commit a27ac3806b0a +("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs"). + +Since then both SDR50 and SDR104 speed modes are working fine on SM8450, +tested on SM8450-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 24.6254 s, 43.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 12.3266 s, 87.1 MB/s + +Remove the restrictions on SD card speed modes from the SM8450 platform +dtsi file and enable UHS-I speed modes. + +Fixes: 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable SDHCI SDR104/SDR50 on all boards") +Reviewed-by: Neil Armstrong +Reviewed-by: Konrad Dybcio +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-5-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index cfa880c577a40..f5be69e3be997 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -4599,9 +4599,6 @@ sdhc_2: mmc@8804000 { + bus-width = <4>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0x0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch b/queue-6.12/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..7c6734f89a --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From 643d89aff7753c1a132ab5fa6f4c1a2407763fee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:16 +0100 +Subject: arm64: dts: qcom: sm8450: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 14044fa192c50265bc1f636108371044bbdcf7b7 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: fc8b0b9b630d ("arm64: dts: qcom: sm8450 add ITS device tree node") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-3-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 58ed68f534e50..cfa880c577a40 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -4274,7 +4274,7 @@ intc: interrupt-controller@17100000 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x17140000 0x0 0x20000>; ++ reg = <0x0 0x17140000 0x0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.12/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..93248eed6a --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,67 @@ +From 21a149f9299ef06e96c7dd19f6e21d5529098ca7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:14 +0200 +Subject: arm64: dts: qcom: sm8550: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit 66b0f024fba0728ddce6916dce173bb1bdd4eab0 ] + +The restriction on UHS-I speed modes was added to all SM8550 platforms +by copying it from SM8450 dtsi file, and due to the overclocking of SD +cards it was an actually reproducible problem. Since the latter issue +has been fixed, UHS-I speed modes are working fine on SM8550 boards, +below is the test performed on SM8550-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 23.5468 s, 45.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 11.9819 s, 89.6 MB/s + +Unset the UHS-I speed mode restrictions from the SM8550 platform dtsi +file, there is no indication that the SDHC controller is broken. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Reviewed-by: Neil Armstrong +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-6-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index efca98c7cc7a3..38b15db0676ce 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -2838,9 +2838,6 @@ sdhc_2: mmc@8804000 { + bus-width = <4>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch b/queue-6.12/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..72e3354bcc --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From fef862301aae0d66bda9622317cfdf3f42f13371 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:17 +0100 +Subject: arm64: dts: qcom: sm8550: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 357c559e386705609b6b9dc0544c420e3f91f3a0 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-4-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index cfdd30009015f..5044a754cf5b2 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -4418,7 +4418,7 @@ intc: interrupt-controller@17100000 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0 0x17140000 0 0x20000>; ++ reg = <0 0x17140000 0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch b/queue-6.12/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch new file mode 100644 index 0000000000..ae454f9784 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch @@ -0,0 +1,46 @@ +From f1a39ae73ab56032e7a55c69b6d61bc3d585f0f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:10 +0200 +Subject: arm64: dts: qcom: sm8550: Fix xo clock supply of platform SD host + controller + +From: Vladimir Zapolskiy + +[ Upstream commit 30ac651c69bddbc83cab6d52fc5d2e03bed83282 ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-2-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index 5044a754cf5b2..efca98c7cc7a3 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -2824,7 +2824,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", "core", "xo"; + iommus = <&apps_smmu 0x540 0>; + qcom,dll-config = <0x0007642c>; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.12/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..853623a82f --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,68 @@ +From 932a4c746c74a51d6d95ee8946205e0a8fcb2259 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:15 +0200 +Subject: arm64: dts: qcom: sm8650: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit 93f823e7d48232e62fb8fb74481696609c90244a ] + +The restriction on UHS-I speed modes was added to all SM8650 platforms +by copying it from SM8450 and SM8550 dtsi files, and it was an actually +reproducible problem due to the overclocking of SD cards. Since the latter +issue has been fixed in the SM8650 GCC driver, UHS-I speed modes are +working fine on SM8650 boards, below is the test performed on SM8650-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 24.8086 s, 43.3 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 12.9448 s, 82.9 MB/s + +Unset the UHS-I speed mode restrictions from the SM8550 platform dtsi +file, there is no indication that the SDHC controller is broken. + +Fixes: 10e024671295 ("arm64: dts: qcom: sm8650: add interconnect dependent device nodes") +Reviewed-by: Neil Armstrong +Reviewed-by: Konrad Dybcio +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-7-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 72a75dec13c73..6098206350f90 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -3442,9 +3442,6 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + + bus-width = <4>; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0>; +- + qcom,dll-config = <0x0007642c>; + qcom,ddr-config = <0x80040868>; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch b/queue-6.12/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..72a7fd71a9 --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From 2dbe55d2264de83266eac744419451fa25ca9bfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:18 +0100 +Subject: arm64: dts: qcom: sm8650: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 6c8e2ca1263d0da5976418ed285eaec430e8d87f ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: d2350377997f ("arm64: dts: qcom: add initial SM8650 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-5-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 6763c750f6801..d38d44438477f 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -5142,7 +5142,7 @@ intc: interrupt-controller@17100000 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0 0x17140000 0 0x20000>; ++ reg = <0 0x17140000 0 0x40000>; + + msi-controller; + #msi-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch b/queue-6.12/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch new file mode 100644 index 0000000000..a1cfe34acb --- /dev/null +++ b/queue-6.12/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch @@ -0,0 +1,45 @@ +From 064a6fb8a25973694ac60b4707204947cbb803bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:11 +0200 +Subject: arm64: dts: qcom: sm8650: Fix xo clock supply of SD host controller + +From: Vladimir Zapolskiy + +[ Upstream commit 390903efaa057c44fd80e7d9839419c50092018e ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: 10e024671295 ("arm64: dts: qcom: sm8650: add interconnect dependent device nodes") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-3-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index d38d44438477f..72a75dec13c73 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -3423,7 +3423,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", + "core", + "xo"; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch b/queue-6.12/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch new file mode 100644 index 0000000000..c3ad53ff11 --- /dev/null +++ b/queue-6.12/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch @@ -0,0 +1,39 @@ +From a6ad5a5d82f7e759e8bcf96106bb86bc3bd6e95b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 08:46:48 -0500 +Subject: arm64: dts: rockchip: Correct Fan Supply for Gameforce Ace + +From: Chris Morgan + +[ Upstream commit c7079215b7dbf88b84a95ff13982bf3dab3cfbe1 ] + +Correct the regulator providing power to the PWM controlled fan. +Without this fix the fan only runs when the audio path is playing +audio (because the speaker amplifier and PWM fan share the same +regulator). + +Fixes: 4e946c447a04 ("arm64: dts: rockchip: Add GameForce Ace") +Signed-off-by: Chris Morgan +Link: https://patch.msgid.link/20260310134648.550006-1-macroalpha82@gmail.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +index 467f69594089b..dc1639574f367 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +@@ -303,7 +303,7 @@ pwm_fan: pwm-fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + cooling-levels = <0 120 150 180 210 240 255>; +- fan-supply = <&vcc5v0_sys>; ++ fan-supply = <&vcc5v0_spk>; + interrupt-parent = <&gpio4>; + interrupts = ; + pulses-per-revolution = <4>; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch b/queue-6.12/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch new file mode 100644 index 0000000000..965470a27a --- /dev/null +++ b/queue-6.12/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch @@ -0,0 +1,70 @@ +From b46fe626e26ce48fdc39d4f6811ce3f0c772b4af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 08:49:19 -0500 +Subject: arm64: dts: rockchip: Correct Joystick Axes on Gameforce Ace + +From: Chris Morgan + +[ Upstream commit c337c1b561c1c3016d30776d7dc2032ea4979334 ] + +The Gameforce Ace's joystick axes were set incorrectly initially, +getting the X/Y and RX/RY axes backwards. Additionally, correct the +RY axis so that it is inverted. + +All axes tested with evtest and outputting correct values. + +Fixes: 4e946c447a04 ("arm64: dts: rockchip: Add GameForce Ace") +Reported-by: sydarn +Signed-off-by: Chris Morgan +Link: https://patch.msgid.link/20260310134919.550023-1-macroalpha82@gmail.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +index dc1639574f367..b9a17108e1acd 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +@@ -59,8 +59,8 @@ axis@0 { + reg = <0>; + abs-flat = <40>; + abs-fuzz = <30>; +- abs-range = <0 4095>; +- linux,code = ; ++ abs-range = <4095 0>; ++ linux,code = ; + }; + + axis@1 { +@@ -68,7 +68,7 @@ axis@1 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + + axis@2 { +@@ -76,7 +76,7 @@ axis@2 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + + axis@3 { +@@ -84,7 +84,7 @@ axis@3 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch b/queue-6.12/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch new file mode 100644 index 0000000000..e08332044c --- /dev/null +++ b/queue-6.12/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch @@ -0,0 +1,49 @@ +From 620e50fe5edffae210e7b555ad917154f2895c8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:04:53 +0800 +Subject: arm64: dts: rockchip: Fix Bluetooth stability on LCKFB TaiShan Pi + +From: Ming Wang + +[ Upstream commit 861a9593e10bb6ab2a492b315c8a2a3aad70ac00 ] + +The AP6212 WiFi/BT module on the LCKFB TaiShan Pi (RK3566) is prone to +communication timeouts and reset failures (error -110) when operating at +3 Mbps. + +This patch stabilizes the Bluetooth interface by: +1. Updating the compatible string to 'brcm,bcm43430a1-bt' to better reflect + the actual chip revision used in the AP6212 module. +2. Lowering the maximum UART baud rate from 3,000,000 to 1,500,000 bps. + Tests show that 1.5 Mbps is the reliable upper limit for this board's + UART configuration, eliminating the initialization timeouts. + +Fixes: 251e5ade9ba4 ("arm64: dts: rockchip: add dts for LCKFB Taishan Pi RK3566") +Signed-off-by: Ming Wang +Link: https://patch.msgid.link/20260206090453.1041919-1-wming126@126.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts +index 7cd91f8000cb0..419225a4806c1 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts +@@ -635,10 +635,10 @@ &uart1 { + status = "okay"; + + bluetooth: bluetooth { +- compatible = "brcm,bcm43438-bt"; ++ compatible = "brcm,bcm43430a1-bt"; + clocks = <&rk809 1>; + clock-names = "lpo"; +- max-speed = <3000000>; ++ max-speed = <1500000>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>; + shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch b/queue-6.12/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch new file mode 100644 index 0000000000..ff1c52da46 --- /dev/null +++ b/queue-6.12/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch @@ -0,0 +1,42 @@ +From f7c1e8c13c404bdf2a1a91da6b5c603252cb7871 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 09:03:02 +0100 +Subject: arm64: dts: rockchip: Make Jaguar PCIe-refclk pin use pull-up config + +From: Heiko Stuebner + +[ Upstream commit f45d4356feeba1c8dac3414b688f59292ddfc9f9 ] + +The hardware PU/PD config of the pin after reset is to pull-up and on +Jaguar this will also keep the device in reset until the driver actually +enables the pin. So restore this boot pull-up config of the pin on Jaguar +instead of setting it to pull-none. + +Suggested-by: Quentin Schulz +Fixes: 0ec7e1096332 ("arm64: dts: rockchip: add PCIe3 support on rk3588-jaguar") +Signed-off-by: Heiko Stuebner +Reviewed-by: Shawn Lin +Reviewed-by: Quentin Schulz +Link: https://patch.msgid.link/20260210080303.680403-5-heiko@sntech.de +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts +index e61c5731fb99f..46834d9ae565e 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts +@@ -424,7 +424,7 @@ led1_pin: led1-pin { + + pcie30x4 { + pcie30x4_clkreqn_m0: pcie30x4-clkreqn-m0 { +- rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; ++ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + pcie30x4_perstn_m0: pcie30x4-perstn-m0 { +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch b/queue-6.12/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch new file mode 100644 index 0000000000..1160cc58e2 --- /dev/null +++ b/queue-6.12/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch @@ -0,0 +1,58 @@ +From 6f8575d1a94c3c98ba7bc67b0e5d3c4b721d0bdc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 17:37:31 -0600 +Subject: arm64: dts: ti: k3-am62-lp-sk: Enable internal pulls for MMC0 data + pins + +From: Judith Mendez + +[ Upstream commit ee2a9d9c9e6c9643fb7e45febcaedfbc038e483a ] + +AM62 LP SK board does not have external pullups on MMC0 DAT1-DAT7 +pins [0]. Enable internal pullups on DAT1-DAT7 considering: +- without a host-side pullup, these lines rely solely on the eMMC + device's internal pullup (R_int, 10-150K per JEDEC), which may + exceed the recommended 50K max for 1.8V VCCQ +- JEDEC JESD84-B51 Table 200 requires host-side pullups (R_DAT, + 10K-100K) on all data lines to prevent bus floating + +[0] https://www.ti.com/lit/zip/SPRR471 + +Fixes: a0b8da04153e ("arm64: dts: ti: k3-am62*: Move eMMC pinmux to top level board file") +Signed-off-by: Judith Mendez +Reviewed-by: Moteen Shah +Link: https://patch.msgid.link/20260223233731.2690472-4-jm@ti.com +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts +index 4609f366006e4..f050886e67c6d 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts +@@ -80,13 +80,13 @@ main_mmc0_pins_default: main-mmc0-default-pins { + AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (V3) MMC0_CMD */ + AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (Y1) MMC0_CLK */ + AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (V2) MMC0_DAT0 */ +- AM62X_IOPAD(0x210, PIN_INPUT, 0) /* (V1) MMC0_DAT1 */ +- AM62X_IOPAD(0x20c, PIN_INPUT, 0) /* (W2) MMC0_DAT2 */ +- AM62X_IOPAD(0x208, PIN_INPUT, 0) /* (W1) MMC0_DAT3 */ +- AM62X_IOPAD(0x204, PIN_INPUT, 0) /* (Y2) MMC0_DAT4 */ +- AM62X_IOPAD(0x200, PIN_INPUT, 0) /* (W3) MMC0_DAT5 */ +- AM62X_IOPAD(0x1fc, PIN_INPUT, 0) /* (W4) MMC0_DAT6 */ +- AM62X_IOPAD(0x1f8, PIN_INPUT, 0) /* (V4) MMC0_DAT7 */ ++ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (V1) MMC0_DAT1 */ ++ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (W2) MMC0_DAT2 */ ++ AM62X_IOPAD(0x208, PIN_INPUT_PULLUP, 0) /* (W1) MMC0_DAT3 */ ++ AM62X_IOPAD(0x204, PIN_INPUT_PULLUP, 0) /* (Y2) MMC0_DAT4 */ ++ AM62X_IOPAD(0x200, PIN_INPUT_PULLUP, 0) /* (W3) MMC0_DAT5 */ ++ AM62X_IOPAD(0x1fc, PIN_INPUT_PULLUP, 0) /* (W4) MMC0_DAT6 */ ++ AM62X_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (V4) MMC0_DAT7 */ + >; + }; + +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch b/queue-6.12/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch new file mode 100644 index 0000000000..d156903dc8 --- /dev/null +++ b/queue-6.12/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch @@ -0,0 +1,39 @@ +From fbe9f59c4f5ffbf88d9aea58f9fb038097a7529a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:36:57 +0100 +Subject: arm64: dts: ti: k3-am62-verdin: Fix SPI_1 GPIO CS pinctrl label + +From: Francesco Dolcini + +[ Upstream commit 944dffaec1ef0f21c203728de77b5618ed70df6e ] + +Fix SPI_1_CS GPIO pinmux label, this is spi1_cs, not qspi1_io4. + +There are no user of this label yet, therefore this change does not +create any compatibility issue. + +Fixes: fcb335934c51 ("arm64: dts: ti: verdin-am62: Improve spi1 chip-select pinctrl") +Signed-off-by: Francesco Dolcini +Link: https://patch.msgid.link/20260324093705.26730-3-francesco@dolcini.it +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +index 7c90a4e488a4a..893834c8803bf 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +@@ -272,7 +272,7 @@ AM62X_IOPAD(0x0018, PIN_INPUT, 7) /* (F24) OSPI0_D3.GPIO0_6 */ /* SODIMM 62 */ + }; + + /* Verdin SPI_1 CS as GPIO */ +- pinctrl_qspi1_io4_gpio: main-gpio0-7-default-pins { ++ pinctrl_spi1_cs_gpio: main-gpio0-7-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 7) /* (J23) OSPI0_D4.GPIO0_7 */ /* SODIMM 202 */ + >; +-- +2.53.0 + diff --git a/queue-6.12/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch b/queue-6.12/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch new file mode 100644 index 0000000000..2bdb131d05 --- /dev/null +++ b/queue-6.12/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch @@ -0,0 +1,53 @@ +From 1b8a4079f69e2c29ca6fb0dfcc7e79a0a2ae14d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 17:37:29 -0600 +Subject: arm64: dts: ti: k3-am62p5-sk: Disable MMC1 internal pulls on data + pins + +From: Judith Mendez + +[ Upstream commit 6d4441be969bea89bb9702781f5dfb3a8f2a02a4 ] + +AM62P SK has external 10K pullups on MMC1 DAT1-DAT3 pins [0]. +Disable internal pullups on DAT1-DAT3 so that each line has a +single pullup source: +- with both pullups enabled, the effective parallel resistance on + DAT1-3 (~8.33K) drops below the 10K minimum pullup requirement + for data lines (per SD Physical Layer Specification) +- removing internal pullups makes DAT1-3 match DAT0 10K + external pullup so its consistent and within spec +- both internal and external pullups enabled equals unnecessary power + consumption + +[0] https://www.ti.com/lit/zip/SPRR487 + +Fixes: c00504ea42c0 ("arm64: dts: ti: k3-am62p5-sk: Updates for SK EVM") +Signed-off-by: Judith Mendez +Reviewed-by: Moteen Shah +Link: https://patch.msgid.link/20260223233731.2690472-2-jm@ti.com +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62p5-sk.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +index b94093a7a392a..de3a999aab139 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +@@ -224,9 +224,9 @@ main_mmc1_pins_default: main-mmc1-default-pins { + AM62PX_IOPAD(0x023c, PIN_INPUT, 0) /* (H20) MMC1_CMD */ + AM62PX_IOPAD(0x0234, PIN_OUTPUT, 0) /* (J24) MMC1_CLK */ + AM62PX_IOPAD(0x0230, PIN_INPUT, 0) /* (H21) MMC1_DAT0 */ +- AM62PX_IOPAD(0x022c, PIN_INPUT_PULLUP, 0) /* (H23) MMC1_DAT1 */ +- AM62PX_IOPAD(0x0228, PIN_INPUT_PULLUP, 0) /* (H22) MMC1_DAT2 */ +- AM62PX_IOPAD(0x0224, PIN_INPUT_PULLUP, 0) /* (H25) MMC1_DAT3 */ ++ AM62PX_IOPAD(0x022c, PIN_INPUT, 0) /* (H23) MMC1_DAT1 */ ++ AM62PX_IOPAD(0x0228, PIN_INPUT, 0) /* (H22) MMC1_DAT2 */ ++ AM62PX_IOPAD(0x0224, PIN_INPUT, 0) /* (H25) MMC1_DAT3 */ + AM62PX_IOPAD(0x0240, PIN_INPUT, 0) /* (D23) MMC1_SDCD */ + >; + bootph-all; +-- +2.53.0 + diff --git a/queue-6.12/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch b/queue-6.12/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch new file mode 100644 index 0000000000..7649e2b0d0 --- /dev/null +++ b/queue-6.12/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch @@ -0,0 +1,38 @@ +From eea67547dff4d44f53cf861d15a2de07ea8acad0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 19:42:31 +0800 +Subject: arm64: kexec: Remove duplicate allocation for trans_pgd + +From: Wang Wensheng + +[ Upstream commit ee020bf6f14094c9ae434bb37e6957a1fdad513c ] + +trans_pgd would be allocated in trans_pgd_create_copy(), so remove the +duplicate allocation before calling trans_pgd_create_copy(). + +Fixes: 3744b5280e67 ("arm64: kexec: install a copy of the linear-map") +Signed-off-by: Wang Wensheng +Reviewed-by: Pasha Tatashin +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/machine_kexec.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c +index 6f121a0164a48..28df62051cc97 100644 +--- a/arch/arm64/kernel/machine_kexec.c ++++ b/arch/arm64/kernel/machine_kexec.c +@@ -129,9 +129,6 @@ int machine_kexec_post_load(struct kimage *kimage) + } + + /* Create a copy of the linear map */ +- trans_pgd = kexec_page_alloc(kimage); +- if (!trans_pgd) +- return -ENOMEM; + rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END); + if (rc) + return rc; +-- +2.53.0 + diff --git a/queue-6.12/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch b/queue-6.12/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch new file mode 100644 index 0000000000..be32f32eca --- /dev/null +++ b/queue-6.12/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch @@ -0,0 +1,86 @@ +From 878d007f88321f8c1bd84f9916ac0e98d7399738 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 16:58:08 +0800 +Subject: arm64: Reserve an extra page for early kernel mapping + +From: Zhaoyang Huang + +[ Upstream commit 4d8e74ad4585672489da6145b3328d415f50db82 ] + +The final part of [data, end) segment may overflow into the next page of +init_pg_end[1] which is the gap page before early_init_stack[2]: + +[1] +crash_arm64_v9.0.1> vtop ffffffed00601000 +VIRTUAL PHYSICAL +ffffffed00601000 83401000 + +PAGE DIRECTORY: ffffffecffd62000 + PGD: ffffffecffd62da0 => 10000000833fb003 + PMD: ffffff80033fb018 => 10000000833fe003 + PTE: ffffff80033fe008 => 68000083401f03 + PAGE: 83401000 + + PTE PHYSICAL FLAGS +68000083401f03 83401000 (VALID|SHARED|AF|NG|PXN|UXN) + + PAGE PHYSICAL MAPPING INDEX CNT FLAGS +fffffffec00d0040 83401000 0 0 1 4000 reserved + +[2] +ffffffed002c8000 (r) __pi__data +ffffffed0054e000 (d) __pi___bss_start +ffffffed005f5000 (b) __pi_init_pg_dir +ffffffed005fe000 (b) __pi_init_pg_end +ffffffed005ff000 (B) early_init_stack +ffffffed00608000 (b) __pi__end + +For 4K pages, the early kernel mapping may use 2MB block entries but the +kernel segments are only 64KB aligned. Segment boundaries that fall +within a 2MB block therefore require a PTE table so that different +attributes can be applied on either side of the boundary. + +KERNEL_SEGMENT_COUNT still correctly counts the five permanent kernel +VMAs registered by declare_kernel_vmas(). However, since commit +5973a62efa34 ("arm64: map [_text, _stext) virtual address range +non-executable+read-only"), the early mapper also maps [_text, _stext) +separately from [_stext, _etext). This adds one more early-only split +and can require one more page-table page than the existing +EARLY_SEGMENT_EXTRA_PAGES allowance reserves. + +Increase the 4K-page early mapping allowance by one page to cover that +additional split. + +Fixes: 5973a62efa34 ("arm64: map [_text, _stext) virtual address range non-executable+read-only") +Assisted-by: TRAE:GLM-5.1 +Suggested-by: Ard Biesheuvel +Signed-off-by: Zhaoyang Huang +[catalin.marinas@arm.com: rewrote part of the commit log] +[catalin.marinas@arm.com: expanded the code comment] +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/kernel-pgtable.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h +index bf05a77873a49..56fe12a6f7b0a 100644 +--- a/arch/arm64/include/asm/kernel-pgtable.h ++++ b/arch/arm64/include/asm/kernel-pgtable.h +@@ -69,7 +69,12 @@ + #define KERNEL_SEGMENT_COUNT 5 + + #if SWAPPER_BLOCK_SIZE > SEGMENT_ALIGN +-#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1) ++/* ++ * KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping ++ * has one additional split, [_text, _stext). Reserve one more page for the ++ * SWAPPER_BLOCK_SIZE-unaligned boundaries. ++ */ ++#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2) + /* + * The initial ID map consists of the kernel image, mapped as two separate + * segments, and may appear misaligned wrt the swapper block size. This means +-- +2.53.0 + diff --git a/queue-6.12/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch b/queue-6.12/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch new file mode 100644 index 0000000000..6b40442ce3 --- /dev/null +++ b/queue-6.12/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch @@ -0,0 +1,47 @@ +From d6afceda92fe973e63262299ab3a1a40cec63919 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 17:54:59 +0800 +Subject: arm64/scs: Fix potential sign extension issue of advance_loc4 + +From: Wentao Guan + +[ Upstream commit 4023b7424ecd5d38cc75b650d6c1bf630ef8cb40 ] + +The expression (*opcode++ << 24) and exp * code_alignment_factor +may overflow signed int and becomes negative. + +Fix this by casting each byte to u64 before shifting. Also fix +the misaligned break statement while we are here. + +Example of the result can be seen here: +Link: https://godbolt.org/z/zhY8d3595 + +It maybe not a real problem, but could be a issue in future. + +Fixes: d499e9627d70 ("arm64/scs: Fix handling of advance_loc4") +Signed-off-by: Wentao Guan +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/pi/patch-scs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/pi/patch-scs.c b/arch/arm64/kernel/pi/patch-scs.c +index be7050fdfbba0..76e69df0085d1 100644 +--- a/arch/arm64/kernel/pi/patch-scs.c ++++ b/arch/arm64/kernel/pi/patch-scs.c +@@ -178,9 +178,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, + loc += *opcode++ * code_alignment_factor; + loc += (*opcode++ << 8) * code_alignment_factor; + loc += (*opcode++ << 16) * code_alignment_factor; +- loc += (*opcode++ << 24) * code_alignment_factor; ++ loc += ((u64)*opcode++ << 24) * code_alignment_factor; + size -= 4; +- break; ++ break; + + case DW_CFA_def_cfa: + case DW_CFA_offset_extended: +-- +2.53.0 + diff --git a/queue-6.12/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch b/queue-6.12/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch new file mode 100644 index 0000000000..f9471758ed --- /dev/null +++ b/queue-6.12/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch @@ -0,0 +1,79 @@ +From e053274146bf0999a04d0361baf77fa0d42fa6e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 07:16:35 +0100 +Subject: arm64/xor: fix conflicting attributes for xor_block_template + +From: Christoph Hellwig + +[ Upstream commit 675a0dd596e712404557286d0a883b54ee28e4f4 ] + +Commit 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +changes the definition to __ro_after_init instead of const, but failed to +update the external declaration in xor.h. This was not found because +xor-neon.c doesn't include , and can't easily do that due to +current architecture of the XOR code. + +Link: https://lkml.kernel.org/r/20260327061704.3707577-4-hch@lst.de +Fixes: 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +Signed-off-by: Christoph Hellwig +Reviewed-by: Eric Biggers +Tested-by: Eric Biggers +Cc: Albert Ou +Cc: Alexander Gordeev +Cc: Alexandre Ghiti +Cc: Andreas Larsson +Cc: Anton Ivanov +Cc: Ard Biesheuvel +Cc: Arnd Bergmann +Cc: "Borislav Petkov (AMD)" +Cc: Catalin Marinas +Cc: Chris Mason +Cc: Christian Borntraeger +Cc: Dan Williams +Cc: David S. Miller +Cc: David Sterba +Cc: Heiko Carstens +Cc: Herbert Xu +Cc: "H. Peter Anvin" +Cc: Huacai Chen +Cc: Ingo Molnar +Cc: Jason A. Donenfeld +Cc: Johannes Berg +Cc: Li Nan +Cc: Madhavan Srinivasan +Cc: Magnus Lindholm +Cc: Matt Turner +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: Palmer Dabbelt +Cc: Richard Henderson +Cc: Richard Weinberger +Cc: Russell King +Cc: Song Liu +Cc: Sven Schnelle +Cc: Ted Ts'o +Cc: Vasily Gorbik +Cc: WANG Xuerui +Cc: Will Deacon +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/xor.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/xor.h b/arch/arm64/include/asm/xor.h +index befcd8a7abc98..7c03207157196 100644 +--- a/arch/arm64/include/asm/xor.h ++++ b/arch/arm64/include/asm/xor.h +@@ -13,7 +13,7 @@ + + #ifdef CONFIG_KERNEL_MODE_NEON + +-extern struct xor_block_template const xor_block_inner_neon; ++extern struct xor_block_template xor_block_inner_neon __ro_after_init; + + static void + xor_neon_2(unsigned long bytes, unsigned long * __restrict p1, +-- +2.53.0 + diff --git a/queue-6.12/asoc-add-symmetric_-prefix-for-dai-rate-channels-sam.patch b/queue-6.12/asoc-add-symmetric_-prefix-for-dai-rate-channels-sam.patch new file mode 100644 index 0000000000..4ac6da5c6f --- /dev/null +++ b/queue-6.12/asoc-add-symmetric_-prefix-for-dai-rate-channels-sam.patch @@ -0,0 +1,194 @@ +From 0dd27f08ee8117ad6c535b79da52fa3cdd4606b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Nov 2024 00:10:44 +0000 +Subject: ASoC: add symmetric_ prefix for dai->rate/channels/sample_bits + +From: Kuninori Morimoto + +[ Upstream commit 1bd775da9ba919b87b2313a78d5957afc1a62dde ] + +snd_soc_dai has rate/channels/sample_bits parameter, but it is only valid +if symmetry is being enforced by symmetric_xxx flag on driver. + +It is very difficult to know about it from current naming, and easy to +misunderstand it. add symmetric_ prefix for it. + +Signed-off-by: Kuninori Morimoto +Link: https://patch.msgid.link/87zfmd8bnf.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +Stable-dep-of: 07c774dd64ba ("ASoC: soc-compress: use function to clear symmetric params") +Signed-off-by: Sasha Levin +--- + include/sound/soc-dai.h | 6 ++--- + sound/soc/mediatek/mt8188/mt8188-dai-pcm.c | 2 +- + sound/soc/mediatek/mt8195/mt8195-dai-pcm.c | 2 +- + sound/soc/mediatek/mt8365/mt8365-dai-dmic.c | 6 ++--- + sound/soc/mediatek/mt8365/mt8365-dai-pcm.c | 2 +- + sound/soc/soc-compress.c | 4 +-- + sound/soc/soc-pcm.c | 29 +++++++++++---------- + 7 files changed, 26 insertions(+), 25 deletions(-) + +diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h +index 0d1b215f24f4f..4a3505674f2f2 100644 +--- a/include/sound/soc-dai.h ++++ b/include/sound/soc-dai.h +@@ -450,9 +450,9 @@ struct snd_soc_dai { + struct snd_soc_dai_stream stream[SNDRV_PCM_STREAM_LAST + 1]; + + /* Symmetry data - only valid if symmetry is being enforced */ +- unsigned int rate; +- unsigned int channels; +- unsigned int sample_bits; ++ unsigned int symmetric_rate; ++ unsigned int symmetric_channels; ++ unsigned int symmetric_sample_bits; + + /* parent platform/codec */ + struct snd_soc_component *component; +diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c +index 5bc854a8f3df3..8ca7cc75e21dc 100644 +--- a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c ++++ b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c +@@ -128,7 +128,7 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, + unsigned int lrck_inv; + unsigned int bck_inv; + unsigned int fmt; +- unsigned int bit_width = dai->sample_bits; ++ unsigned int bit_width = dai->symmetric_sample_bits; + unsigned int val = 0; + unsigned int mask = 0; + int fs = 0; +diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c +index 6d6d79300d512..cdc16057d50e2 100644 +--- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c ++++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c +@@ -127,7 +127,7 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, + unsigned int lrck_inv; + unsigned int bck_inv; + unsigned int fmt; +- unsigned int bit_width = dai->sample_bits; ++ unsigned int bit_width = dai->symmetric_sample_bits; + unsigned int val = 0; + unsigned int mask = 0; + int fs = 0; +diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c +index f9945c2a2cd13..0bac143b48bfb 100644 +--- a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c ++++ b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c +@@ -118,13 +118,13 @@ static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe, + unsigned int clk_phase_sel_ch1 = dmic_data->clk_phase_sel_ch1; + unsigned int clk_phase_sel_ch2 = dmic_data->clk_phase_sel_ch2; + unsigned int val = 0; +- unsigned int rate = dai->rate; +- int reg = get_chan_reg(dai->channels); ++ unsigned int rate = dai->symmetric_rate; ++ int reg = get_chan_reg(dai->symmetric_channels); + + if (reg < 0) + return -EINVAL; + +- dmic_data->dmic_channel = dai->channels; ++ dmic_data->dmic_channel = dai->symmetric_channels; + + val |= DMIC_TOP_CON_SDM3_LEVEL_MODE; + +diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c +index f85ec07249c3b..3373b88da28ea 100644 +--- a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c ++++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c +@@ -44,7 +44,7 @@ static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream, + bool lrck_inv = pcm_priv->lrck_inv; + bool bck_inv = pcm_priv->bck_inv; + unsigned int fmt = pcm_priv->format; +- unsigned int bit_width = dai->sample_bits; ++ unsigned int bit_width = dai->symmetric_sample_bits; + unsigned int val = 0; + + if (!slave_mode) { +diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c +index e692aa3b8b22f..f787f60a16a11 100644 +--- a/sound/soc/soc-compress.c ++++ b/sound/soc/soc-compress.c +@@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) + snd_soc_dai_digital_mute(codec_dai, 1, stream); + + if (!snd_soc_dai_active(cpu_dai)) +- cpu_dai->rate = 0; ++ cpu_dai->symmetric_rate = 0; + + if (!snd_soc_dai_active(codec_dai)) +- codec_dai->rate = 0; ++ codec_dai->symmetric_rate = 0; + + snd_soc_link_compr_shutdown(cstream, rollback); + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 0e21ff9f7b74e..83e6a76da7e63 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -462,13 +462,13 @@ static void soc_pcm_set_dai_params(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params) + { + if (params) { +- dai->rate = params_rate(params); +- dai->channels = params_channels(params); +- dai->sample_bits = snd_pcm_format_physical_width(params_format(params)); ++ dai->symmetric_rate = params_rate(params); ++ dai->symmetric_channels = params_channels(params); ++ dai->symmetric_sample_bits = snd_pcm_format_physical_width(params_format(params)); + } else { +- dai->rate = 0; +- dai->channels = 0; +- dai->sample_bits = 0; ++ dai->symmetric_rate = 0; ++ dai->symmetric_channels = 0; ++ dai->symmetric_sample_bits = 0; + } + } + +@@ -482,14 +482,14 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, + return 0; + + #define __soc_pcm_apply_symmetry(name, NAME) \ +- if (soc_dai->name && (soc_dai->driver->symmetric_##name || \ +- rtd->dai_link->symmetric_##name)) { \ ++ if (soc_dai->symmetric_##name && \ ++ (soc_dai->driver->symmetric_##name || rtd->dai_link->symmetric_##name)) { \ + dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\ +- #name, soc_dai->name); \ ++ #name, soc_dai->symmetric_##name); \ + \ + ret = snd_pcm_hw_constraint_single(substream->runtime, \ + SNDRV_PCM_HW_PARAM_##NAME,\ +- soc_dai->name); \ ++ soc_dai->symmetric_##name); \ + if (ret < 0) { \ + dev_err(soc_dai->dev, \ + "ASoC: Unable to apply %s constraint: %d\n",\ +@@ -525,9 +525,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, + if (symmetry) \ + for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ + if (!snd_soc_dai_is_dummy(cpu_dai) && \ +- cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ ++ cpu_dai->symmetric_##xxx && \ ++ cpu_dai->symmetric_##xxx != d.symmetric_##xxx) { \ + dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \ +- #xxx, cpu_dai->name, cpu_dai->xxx, d.name, d.xxx); \ ++ #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \ ++ d.name, d.symmetric_##xxx); \ + return -EINVAL; \ + } + +@@ -798,8 +800,7 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd, + + /* Make sure DAI parameters cleared if the DAI becomes inactive */ + for_each_rtd_dais(rtd, i, dai) { +- if (snd_soc_dai_active(dai) == 0 && +- (dai->rate || dai->channels || dai->sample_bits)) ++ if (snd_soc_dai_active(dai) == 0) + soc_pcm_set_dai_params(dai, NULL); + } + } +-- +2.53.0 + diff --git a/queue-6.12/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch b/queue-6.12/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch new file mode 100644 index 0000000000..146630a53a --- /dev/null +++ b/queue-6.12/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch @@ -0,0 +1,177 @@ +From b6b6f396a332ea040c1c6897c5a03ec943339a30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 15:30:58 -0300 +Subject: ASoC: amd: acp: Add DMI quirk for Valve Steam Deck OLED + +From: Guilherme G. Piccoli + +[ Upstream commit b0f6f4ac7d5d04fe2adcdd63ed1cd1ad505b8958 ] + +Commit 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") +introduced a change that "broke" Steam Deck's audio probe, in the OLED +model, as observed in the following dmesg snippet: + +[...] +snd_sof_amd_vangogh 0000:04:00.5: Topology: ABI 3:26:0 Kernel ABI 3:23:1 +sof_mach nau8821-max: ASoC: physical link acp-bt-codec (id 2) not exist +sof_mach nau8821-max: ASoC: topology: could not load header: -22 +snd_sof_amd_vangogh 0000:04:00.5: tplg amd/sof-tplg/sof-vangogh-nau8821-max.tplg component load failed -22 +snd_sof_amd_vangogh 0000:04:00.5: error: failed to load DSP topology -22 +snd_sof_amd_vangogh 0000:04:00.5: ASoC error (-22): at snd_soc_component_probe() on 0000:04:00.5 +sof_mach nau8821-max: ASoC: failed to instantiate card -22 +sof_mach nau8821-max: error -EINVAL: Failed to register card(sof-nau8821-max) +sof_mach nau8821-max: probe with driver sof_mach failed with error -22 +[...] + +Notice the quotes in "broke": it's not really a bug in such commit, +but instead a problem with a topology file from Steam Deck OLED. This +was discussed to great extent in [1], and Cristian proposed a pretty +simple and functional change that resolved the issue for the Deck's +issue. That change, though, would break other devices, so it wasn't +accepted upstream. And the proper suggested solution (fix the topology) +was never implemented, so Valve's kernel (and anyone that wants to boot +the mainline on Steam Deck OLED) is carrying that fix downstream. + +So, we propose hereby a different approach: a DMI quirk, as many already +present in the sound drivers, to address this issue solely on Steam Deck +OLED, not breaking other devices and as a bonus, allowing simple patch +up in case eventually the topology file gets fixed (we'd just need to +check against any DMI info reflecting that or the topology/FW versions). + +The motivation of such upstream quirk is related to users that want +to test latest kernel trees on their devices and get no only non-working +sound device, but seems some games (like Ori and the Blind Forest) +can't properly work without a proper functional audio device. +Example of such report can be seen at [2]. + +Cc: Mark Brown +Cc: Robert Beckett +Cc: Umang Jain +Fixes: 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") +Link: https://lore.kernel.org/r/20231209205351.880797-11-cristian.ciocaltea@collabora.com/ [1] +Link: https://bugzilla.kernel.org/show_bug.cgi?id=218677 [2] +Reviewed-by: Cristian Ciocaltea +Reviewed-by: Mario Limonciello +Tested-by: Melissa Wen +Signed-off-by: Guilherme G. Piccoli +Link: https://patch.msgid.link/20260423183505.116445-1-gpiccoli@igalia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/acp/acp-legacy-mach.c | 2 +- + sound/soc/amd/acp/acp-mach-common.c | 22 +++++++++++++++++++--- + sound/soc/amd/acp/acp-mach.h | 4 ++++ + sound/soc/amd/acp/acp-sof-mach.c | 2 +- + 4 files changed, 25 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c +index d104f7e8fdcd8..4221fc0f081b8 100644 +--- a/sound/soc/amd/acp/acp-legacy-mach.c ++++ b/sound/soc/amd/acp/acp-legacy-mach.c +@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev) + acp_card_drvdata->platform = *((int *)dev->platform_data); + + dmi_id = dmi_first_match(acp_quirk_table); +- if (dmi_id && dmi_id->driver_data) ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE) + acp_card_drvdata->tdm_mode = dmi_id->driver_data; + + ret = acp_legacy_dai_links_create(card); +diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c +index e9ff4815c12c8..6c0a92d76b54d 100644 +--- a/sound/soc/amd/acp/acp-mach-common.c ++++ b/sound/soc/amd/acp/acp-mach-common.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "../../codecs/rt5682.h" + #include "../../codecs/rt1019.h" +@@ -37,15 +38,21 @@ + #define NAU8821_FREQ_OUT 12288000 + #define MAX98388_CODEC_DAI "max98388-aif1" + +-#define TDM_MODE_ENABLE 1 +- + const struct dmi_system_id acp_quirk_table[] = { + { + /* Google skyrim proto-0 */ + .matches = { + DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"), + }, +- .driver_data = (void *)TDM_MODE_ENABLE, ++ .driver_data = (void *)QUIRK_TDM_MODE_ENABLE, ++ }, ++ { ++ /* Valve Steam Deck OLED */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Valve"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), ++ }, ++ .driver_data = (void *)QUIRK_REMAP_DMIC_BT, + }, + {} + }; +@@ -1385,6 +1392,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + struct snd_soc_dai_link *links; + struct device *dev = card->dev; + struct acp_card_drvdata *drv_data = card->drvdata; ++ const struct dmi_system_id *dmi_id = dmi_first_match(acp_quirk_table); + int i = 0, num_links = 0; + + if (drv_data->hs_cpu_id) +@@ -1562,6 +1570,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + links[i].codecs = &snd_soc_dummy_dlc; + links[i].num_codecs = 1; + } ++ ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) ++ links[i].id = DMIC_BE_ID; + i++; + } + +@@ -1577,6 +1588,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + links[i].dpcm_capture = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; ++ ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) { ++ links[i].id = BT_BE_ID; ++ dev_dbg(dev, "quirk REMAP_DMIC_BT enabled\n"); ++ } + } + + card->dai_link = links; +diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h +index 93d9e3886b7ec..4b255cbde9ff4 100644 +--- a/sound/soc/amd/acp/acp-mach.h ++++ b/sound/soc/amd/acp/acp-mach.h +@@ -24,6 +24,10 @@ + + #define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata) + ++/* List of DMI quirks - check acp-mach-common.c for usage. */ ++#define QUIRK_TDM_MODE_ENABLE 1 ++#define QUIRK_REMAP_DMIC_BT 2 ++ + enum be_id { + HEADSET_BE_ID = 0, + AMP_BE_ID, +diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c +index f36750167fa29..4c069a34fbe17 100644 +--- a/sound/soc/amd/acp/acp-sof-mach.c ++++ b/sound/soc/amd/acp/acp-sof-mach.c +@@ -113,7 +113,7 @@ static int acp_sof_probe(struct platform_device *pdev) + + acp_card_drvdata = card->drvdata; + dmi_id = dmi_first_match(acp_quirk_table); +- if (dmi_id && dmi_id->driver_data) ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE) + acp_card_drvdata->tdm_mode = dmi_id->driver_data; + + ret = acp_sofdsp_dai_links_create(card); +-- +2.53.0 + diff --git a/queue-6.12/asoc-codecs-ab8500-fix-casting-of-private-data.patch b/queue-6.12/asoc-codecs-ab8500-fix-casting-of-private-data.patch new file mode 100644 index 0000000000..273d44cc2d --- /dev/null +++ b/queue-6.12/asoc-codecs-ab8500-fix-casting-of-private-data.patch @@ -0,0 +1,56 @@ +From 76a8c2c5883a497a188b70ec859dbb4c4930c099 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 21:22:49 +0200 +Subject: ASoC: codecs: ab8500: Fix casting of private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian A. Ehrhardt + +[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ] + +ab8500_filter_controls[i].private_value is initialized using + + .private_value = (unsigned long)&(struct filter_control) + {.count = xcount, .min = xmin, .max = xmax} + +thus it's a pointer to a struct filter_control casted to unsigned long. + +So to get back that pointer .private_data must be cast back, not its +address. + +Fixes: 679d7abdc754 ("ASoC: codecs: Add AB8500 codec-driver") +Signed-off-by: Christian A. Ehrhardt +Signed-off-by: Uwe Kleine-König (The Capable Hub) +Link: https://patch.msgid.link/20260428192255.2294705-2-u.kleine-koenig@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/ab8500-codec.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c +index 04b5e1d5a6530..32d9cdbc8c310 100644 +--- a/sound/soc/codecs/ab8500-codec.c ++++ b/sound/soc/codecs/ab8500-codec.c +@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) + return status; + } + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; + drvdata->anc_fir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; + drvdata->anc_iir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; + drvdata->sid_fir_values = (long *)fc->value; + + snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch b/queue-6.12/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch new file mode 100644 index 0000000000..7384907a0e --- /dev/null +++ b/queue-6.12/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch @@ -0,0 +1,189 @@ +From cfc14b92bd81da1aa3a7040255b2a4037a8dd9b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:26 +0800 +Subject: ASoC: fsl_easrc: Change the type for iec958 channel status controls + +From: Shengjiu Wang + +[ Upstream commit 47f28a5bd154a95d5aa563dde02a801bd32ddb81 ] + +Use the type SNDRV_CTL_ELEM_TYPE_IEC958 for iec958 channel status +controls, the original type will cause mixer-test to iterate all 32bit +values, which costs a lot of time. And using IEC958 type can reduce the +control numbers. + +Also enable pm runtime before updating registers to make the regmap cache +data align with the value in hardware. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-12-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 118 +++++++++++++++++++++++++++----------- + 1 file changed, 84 insertions(+), 34 deletions(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 1b47d2002fac6..e4079e154202c 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -78,17 +78,47 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + return 0; + } + ++static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ + static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; +- unsigned int regval; ++ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ int ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]); ++ if (ret) ++ return ret; + +- regval = snd_soc_component_read(component, mc->regbase); ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]); ++ if (ret) ++ return ret; + +- ucontrol->value.integer.value[0] = regval; ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]); ++ if (ret) ++ return ret; + + return 0; + } +@@ -100,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); +- unsigned int regval = ucontrol->value.integer.value[0]; +- bool changed; ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ bool changed, changed_all = false; + int ret; + +- ret = regmap_update_bits_check(easrc->regmap, mc->regbase, +- GENMASK(31, 0), regval, &changed); +- if (ret != 0) ++ ret = pm_runtime_resume_and_get(component->dev); ++ if (ret) + return ret; + +- return changed; ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase), ++ GENMASK(31, 0), regval[0], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase), ++ GENMASK(31, 0), regval[1], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase), ++ GENMASK(31, 0), regval[2], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase), ++ GENMASK(31, 0), regval[3], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase), ++ GENMASK(31, 0), regval[4], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase), ++ GENMASK(31, 0), regval[5], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++err: ++ pm_runtime_put_autosuspend(component->dev); ++ ++ if (ret != 0) ++ return ret; ++ else ++ return changed_all; + } + + #define SOC_SINGLE_REG_RW(xname, xreg) \ + { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ +- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ ++ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \ + .put = fsl_easrc_set_reg, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ +@@ -146,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { + SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), + SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), + +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), ++ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0), ++ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1), ++ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2), ++ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3), + }; + + /* +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch b/queue-6.12/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch new file mode 100644 index 0000000000..99ac7d4fb1 --- /dev/null +++ b/queue-6.12/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch @@ -0,0 +1,39 @@ +From 25224131cfccf24d46b16b8d2859ba70a0a578f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:24 +0800 +Subject: ASoC: fsl_easrc: Check the variable range in + fsl_easrc_iec958_put_bits() + +From: Shengjiu Wang + +[ Upstream commit 00541b86fb578d4949cfdd6aff1f82d43fcf07af ] + +Add check of input value's range in fsl_easrc_iec958_put_bits(), +otherwise the wrong value may be written from user space. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-10-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 5461a8b44a097..0f8c5210e358e 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, + unsigned int regval = ucontrol->value.integer.value[0]; + int ret; + ++ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT) ++ return -EINVAL; ++ + ret = (easrc_priv->bps_iec958[mc->regbase] != regval); + + easrc_priv->bps_iec958[mc->regbase] = regval; +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch b/queue-6.12/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch new file mode 100644 index 0000000000..35b0711799 --- /dev/null +++ b/queue-6.12/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch @@ -0,0 +1,37 @@ +From c91e4f7f4b98e42cbae44cd9e994376bc2ee86ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:25 +0800 +Subject: ASoC: fsl_easrc: Fix value type in fsl_easrc_iec958_get_bits() + +From: Shengjiu Wang + +[ Upstream commit aa21fe4a81458cf469c2615b08cbde5997dde25a ] + +The value type of controls "Context 0 IEC958 Bits Per Sample" should be +integer, not enumerated, the issue is found by the mixer-test. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-11-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 0f8c5210e358e..1b47d2002fac6 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -73,7 +73,7 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + +- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; ++ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_micfil-add-access-property-for-vad-detected.patch b/queue-6.12/asoc-fsl_micfil-add-access-property-for-vad-detected.patch new file mode 100644 index 0000000000..5c1172bb46 --- /dev/null +++ b/queue-6.12/asoc-fsl_micfil-add-access-property-for-vad-detected.patch @@ -0,0 +1,44 @@ +From cad56f54852b963004d1a9f6cc4d014ecc9491e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:16 +0800 +Subject: ASoC: fsl_micfil: Add access property for "VAD Detected" + +From: Shengjiu Wang + +[ Upstream commit c7661bfc7422443df394c01e069ae4e5c3a7f04c ] + +Add access property SNDRV_CTL_ELEM_ACCESS_READ for control "VAD +Detected", which doesn't support put operation, otherwise there will be +issue with mixer-test. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-2-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 7cfe77b57b3c2..a52e30aa6e086 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -395,7 +395,13 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { + SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0), + SOC_SINGLE("HWVAD ZCD And Behavior Switch", + REG_MICFIL_VAD0_ZCD, 4, 1, 0), +- SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .name = "VAD Detected", ++ .info = snd_soc_info_bool_ext, ++ .get = hwvad_detected, ++ }, + }; + + static int fsl_micfil_use_verid(struct device *dev) +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch b/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch new file mode 100644 index 0000000000..6568985e71 --- /dev/null +++ b/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch @@ -0,0 +1,49 @@ +From a4b3abfcdf5a798c6d64f1426052e8a9e1f5f610 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:17 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in hwvad_put_enable() + +From: Shengjiu Wang + +[ Upstream commit 59b9061824f2179fe133e2636203548eaba3e528 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation hwvad_put_enable() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the vad_enabled +variable. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-3-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index a52e30aa6e086..6fc94cafc9da8 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -277,10 +277,15 @@ static int hwvad_put_enable(struct snd_kcontrol *kcontrol, + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); ++ bool change = false; + ++ if (val < 0 || val > 1) ++ return -EINVAL; ++ ++ change = (micfil->vad_enabled != val); + micfil->vad_enabled = val; + +- return 0; ++ return change; + } + + static int hwvad_get_enable(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch b/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch new file mode 100644 index 0000000000..b19be6447b --- /dev/null +++ b/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch @@ -0,0 +1,52 @@ +From 8ff09cf5968716d759008232dad3210a3dc7e711 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:18 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in hwvad_put_init_mode() + +From: Shengjiu Wang + +[ Upstream commit 7e226209906906421f0d952d7304e48fdb0adabc ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation hwvad_put_init_mode() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the vad_init_mode +variable. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-4-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 6fc94cafc9da8..47b8688605fa6 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -307,13 +307,18 @@ static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol, + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); ++ bool change = false; ++ ++ if (val < MICFIL_HWVAD_ENVELOPE_MODE || val > MICFIL_HWVAD_ENERGY_MODE) ++ return -EINVAL; + + /* 0 - Envelope-based Mode + * 1 - Energy-based Mode + */ ++ change = (micfil->vad_init_mode != val); + micfil->vad_init_mode = val; + +- return 0; ++ return change; + } + + static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch b/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch new file mode 100644 index 0000000000..81f01d6d5f --- /dev/null +++ b/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch @@ -0,0 +1,62 @@ +From 828b40b8651bc26053577511a7005ce62f1a9fcb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:20 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in + micfil_put_dc_remover_state() + +From: Shengjiu Wang + +[ Upstream commit 7d2bd35100de370dc326b250e8f6b66bee06a2f3 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_put_dc_remover_state() only returns 0 or a +negative error code, causing ALSA to not generate any change events. + +return the value of snd_soc_component_update_bits() directly, as it has +the capability of return check status of changed or not. + +Also enable pm runtime before calling the function +snd_soc_component_update_bits() to make the regmap cache data align with +the value in hardware. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-6-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 47b8688605fa6..a04a17db80e43 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -243,6 +243,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + if (val < 0 || val > 3) + return -EINVAL; + ++ ret = pm_runtime_resume_and_get(comp->dev); ++ if (ret) ++ return ret; ++ + micfil->dc_remover = val; + + /* Calculate total value for all channels */ +@@ -252,10 +256,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + /* Update DC Remover mode for all channels */ + ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL, + MICFIL_DC_CTRL_CONFIG, reg_val); +- if (ret < 0) +- return ret; + +- return 0; ++ pm_runtime_put_autosuspend(comp->dev); ++ ++ return ret; + } + + static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch b/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch new file mode 100644 index 0000000000..e85819f7b2 --- /dev/null +++ b/queue-6.12/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch @@ -0,0 +1,71 @@ +From 4aef37b901ec331ceb9a7e23c8fc04afa7b8bdfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:21 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in micfil_quality_set() + +From: Shengjiu Wang + +[ Upstream commit e5785093b1b45af7ee57d18619b2854a8aed073a ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_quality_set() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the quality variable. + +Also enable pm runtime before calling the function micfil_set_quality() +to make the regmap cache data align with the value in hardware. + +Fixes: bea1d61d5892 ("ASoC: fsl_micfil: rework quality setting") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-7-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index a04a17db80e43..6998d30af4c42 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -181,10 +181,34 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol, + { + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); ++ int val = ucontrol->value.integer.value[0]; ++ bool change = false; ++ int old_val; ++ int ret; ++ ++ if (val < QUALITY_HIGH || val > QUALITY_VLOW2) ++ return -EINVAL; ++ ++ if (micfil->quality != val) { ++ ret = pm_runtime_resume_and_get(cmpnt->dev); ++ if (ret) ++ return ret; ++ ++ old_val = micfil->quality; ++ micfil->quality = val; ++ ret = micfil_set_quality(micfil); + +- micfil->quality = ucontrol->value.integer.value[0]; ++ pm_runtime_put_autosuspend(cmpnt->dev); + +- return micfil_set_quality(micfil); ++ if (ret) { ++ micfil->quality = old_val; ++ return ret; ++ } ++ ++ change = true; ++ } ++ ++ return change; + } + + static const char * const micfil_hwvad_enable[] = { +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch b/queue-6.12/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch new file mode 100644 index 0000000000..9274560cd2 --- /dev/null +++ b/queue-6.12/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch @@ -0,0 +1,52 @@ +From 23bb871cb459067391fa78adb6549490e4bb7bbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:22 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_arc_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 1b61c8103c9317a9c37fe544c2d83cee1c281149 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_arc_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the arc_mode +variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-8-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index 656a4d619cdf1..cae42d919f930 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -108,10 +108,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); ++ int ret; + +- xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]); ++ if (val < 0 || val > 1) ++ return -EINVAL; + +- return 0; ++ ret = (xcvr->arc_mode != val); ++ ++ xcvr->arc_mode = val; ++ ++ return ret; + } + + static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.12/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch b/queue-6.12/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch new file mode 100644 index 0000000000..f49983293f --- /dev/null +++ b/queue-6.12/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch @@ -0,0 +1,59 @@ +From e4a33fc240b2a42f892f93f1c935cf9ac09b3b4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:23 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 64a496ba976324615b845d60739dfcdae3d57434 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the mode variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-9-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index cae42d919f930..a042bae63ab34 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -218,10 +218,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); + struct snd_soc_card *card = dai->component->card; + struct snd_soc_pcm_runtime *rtd; ++ int ret; ++ ++ if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC) ++ return -EINVAL; + +- xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); ++ ret = (xcvr->mode != val); ++ ++ xcvr->mode = val; + + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_ARC)); +@@ -231,7 +238,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + rtd = snd_soc_get_pcm_runtime(card, card->dai_link); + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = + (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0); +- return 0; ++ return ret; + } + + static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.12/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch b/queue-6.12/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch new file mode 100644 index 0000000000..6cc7d573b1 --- /dev/null +++ b/queue-6.12/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch @@ -0,0 +1,51 @@ +From 956d1ce6d24e3e18b0197ec770fdd88fd49e8094 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 08:11:08 +0000 +Subject: ASoC: qcom: qdsp6: topology: check widget type before accessing data + +From: Srinivas Kandagatla + +[ Upstream commit d5bfdd28e0cdd45043ae6e0ac168a451d59283dc ] + +Check widget type before accessing the private data, as this could a +virtual widget which is no associated with a dsp graph, container and +module. Accessing witout check could lead to incorrect memory access. + +Fixes: 36ad9bf1d93d ("ASoC: qdsp6: audioreach: add topology support") +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260402081118.348071-4-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/topology.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c +index 01bb1bdee5cec..6f5534b8092b5 100644 +--- a/sound/soc/qcom/qdsp6/topology.c ++++ b/sound/soc/qcom/qdsp6/topology.c +@@ -930,9 +930,6 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + struct audioreach_container *cont; + struct audioreach_module *mod; + +- mod = dobj->private; +- cont = mod->container; +- + if (w->id == snd_soc_dapm_mixer) { + /* virtual widget */ + struct snd_ar_control *scontrol = dobj->private; +@@ -941,6 +938,11 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + kfree(scontrol); + return 0; + } ++ mod = dobj->private; ++ if (!mod) ++ return 0; ++ ++ cont = mod->container; + + mutex_lock(&apm->lock); + idr_remove(&apm->modules_idr, mod->instance_id); +-- +2.53.0 + diff --git a/queue-6.12/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch b/queue-6.12/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch new file mode 100644 index 0000000000..38f1c3d955 --- /dev/null +++ b/queue-6.12/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch @@ -0,0 +1,45 @@ +From fff34c0673caaed40c57f1d5a29f28d57062e3ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 13:33:11 +0300 +Subject: ASoC: rsnd: Fix potential out-of-bounds access of component_dais[] + +From: Denis Rastyogin + +[ Upstream commit f9e437cddf6cf9e603bdaefe148c1f4792aaf39c ] + +component_dais[RSND_MAX_COMPONENT] is initially zero-initialized +and later populated in rsnd_dai_of_node(). However, the existing boundary check: + if (i >= RSND_MAX_COMPONENT) + +does not guarantee that the last valid element remains zero. As a result, +the loop can rely on component_dais[RSND_MAX_COMPONENT] being zero, +which may lead to an out-of-bounds access. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 547b02f74e4a ("ASoC: rsnd: enable multi Component support for Audio Graph Card/Card2") +Signed-off-by: Denis Rastyogin +Acked-by: Kuninori Morimoto +Link: https://patch.msgid.link/20260327103311.459239-1-gerben@altlinux.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sh/rcar/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c +index e3ef9104b411c..c1d5f9b4d9342 100644 +--- a/sound/soc/sh/rcar/core.c ++++ b/sound/soc/sh/rcar/core.c +@@ -1978,7 +1978,7 @@ static int rsnd_probe(struct platform_device *pdev) + * asoc register + */ + ci = 0; +- for (i = 0; priv->component_dais[i] > 0; i++) { ++ for (i = 0; i < RSND_MAX_COMPONENT && priv->component_dais[i] > 0; i++) { + int nr = priv->component_dais[i]; + + ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, +-- +2.53.0 + diff --git a/queue-6.12/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch b/queue-6.12/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch new file mode 100644 index 0000000000..ea47710abb --- /dev/null +++ b/queue-6.12/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch @@ -0,0 +1,97 @@ +From 1809b91d3c4c1efa41a9f37c7dd2dc09da206775 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 04:53:52 +0000 +Subject: ASoC: soc-compress: use function to clear symmetric params + +From: Kuninori Morimoto + +[ Upstream commit 07c774dd64ba0c605dbf844132122e3edbdbea93 ] + +Current soc-compress.c clears symmetric_rate, but it clears rate only, +not clear other symmetric_channels/sample_bits. + + static int soc_compr_clean(...) + { + ... + if (!snd_soc_dai_active(cpu_dai)) +=> cpu_dai->symmetric_rate = 0; + + if (!snd_soc_dai_active(codec_dai)) +=> codec_dai->symmetric_rate = 0; + ... + }; + +This feature was added when v3.7 kernel [1], and there was only +symmetric_rate, no symmetric_channels/sample_bits in that timing. + +symmetric_channels/sample_bits were added in v3.14 [2], +but I guess it didn't notice that soc-compress.c is updating symmetric_xxx. + +We are clearing symmetry_xxx by soc_pcm_set_dai_params(), but is soc-pcm.c +local function. Makes it global function and clear symmetry_xxx by it. + +[1] commit 1245b7005de02 ("ASoC: add compress stream support") +[2] commit 3635bf09a89cf ("ASoC: soc-pcm: add symmetry for channels and + sample bits") + +Fixes: 3635bf09a89c ("ASoC: soc-pcm: add symmetry for channels and sample bits") +Cc: Nicolin Chen +Signed-off-by: Kuninori Morimoto +Link: https://patch.msgid.link/87ms15e3kv.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + include/sound/soc.h | 3 +++ + sound/soc/soc-compress.c | 4 ++-- + sound/soc/soc-pcm.c | 4 ++-- + 3 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/include/sound/soc.h b/include/sound/soc.h +index db3b464a91c7b..cd467f8babdb6 100644 +--- a/include/sound/soc.h ++++ b/include/sound/soc.h +@@ -1452,6 +1452,9 @@ struct snd_soc_dai *snd_soc_find_dai( + struct snd_soc_dai *snd_soc_find_dai_with_mutex( + const struct snd_soc_dai_link_component *dlc); + ++void soc_pcm_set_dai_params(struct snd_soc_dai *dai, ++ struct snd_pcm_hw_params *params); ++ + #include + + static inline +diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c +index f787f60a16a11..249cafe54f561 100644 +--- a/sound/soc/soc-compress.c ++++ b/sound/soc/soc-compress.c +@@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) + snd_soc_dai_digital_mute(codec_dai, 1, stream); + + if (!snd_soc_dai_active(cpu_dai)) +- cpu_dai->symmetric_rate = 0; ++ soc_pcm_set_dai_params(cpu_dai, NULL); + + if (!snd_soc_dai_active(codec_dai)) +- codec_dai->symmetric_rate = 0; ++ soc_pcm_set_dai_params(codec_dai, NULL); + + snd_soc_link_compr_shutdown(cstream, rollback); + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 83e6a76da7e63..628322790c878 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -458,8 +458,8 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, + return 0; + } + +-static void soc_pcm_set_dai_params(struct snd_soc_dai *dai, +- struct snd_pcm_hw_params *params) ++void soc_pcm_set_dai_params(struct snd_soc_dai *dai, ++ struct snd_pcm_hw_params *params) + { + if (params) { + dai->symmetric_rate = params_rate(params); +-- +2.53.0 + diff --git a/queue-6.12/asoc-sof-compress-return-the-configured-codec-from-g.patch b/queue-6.12/asoc-sof-compress-return-the-configured-codec-from-g.patch new file mode 100644 index 0000000000..aad6af51fa --- /dev/null +++ b/queue-6.12/asoc-sof-compress-return-the-configured-codec-from-g.patch @@ -0,0 +1,88 @@ +From 9fa8ff4469fdd0a1570f3d7aeb1ea82f0cb601fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 17:05:11 -0300 +Subject: ASoC: SOF: compress: return the configured codec from get_params +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 2c4fdd055f92a2fc8602dcd88bcea08c374b7e8b ] + +The SOF compressed offload path accepts codec parameters in +sof_compr_set_params() and forwards them to firmware as +extended data in the SOF IPC stream params message. + +However, sof_compr_get_params() still returns success without +filling the snd_codec structure. Since the compress core allocates +that structure zeroed and copies it back to userspace on success, +SNDRV_COMPRESS_GET_PARAMS returns an all-zero codec description +even after the stream has been configured successfully. + +The stale TODO in this callback conflates get_params() with capability +discovery. Supported codec enumeration belongs in get_caps() and +get_codec_caps(). get_params() should report the current codec settings. + +Cache the codec accepted by sof_compr_set_params() in the per-stream SOF +compress state and return it from sof_compr_get_params(). + +Fixes: 6324cf901e14 ("ASoC: SOF: compr: Add compress ops implementation") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-sof-compr-get-params-v1-1-0758815f13c7@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/compress.c | 8 +++++--- + sound/soc/sof/sof-priv.h | 2 ++ + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c +index c469bb706e4a4..b64a5d99fe608 100644 +--- a/sound/soc/sof/compress.c ++++ b/sound/soc/sof/compress.c +@@ -247,6 +247,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, + sstream->sampling_rate = params->codec.sample_rate; + sstream->channels = params->codec.ch_out; + sstream->sample_container_bytes = pcm->params.sample_container_bytes; ++ sstream->codec_params = params->codec; + + spcm->prepared[cstream->direction] = true; + +@@ -259,9 +260,10 @@ static int sof_compr_set_params(struct snd_soc_component *component, + static int sof_compr_get_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_codec *params) + { +- /* TODO: we don't query the supported codecs for now, if the +- * application asks for an unsupported codec the set_params() will fail. +- */ ++ struct sof_compr_stream *sstream = cstream->runtime->private_data; ++ ++ *params = sstream->codec_params; ++ + return 0; + } + +diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h +index 843be3b6415d9..53bcc627ae8b5 100644 +--- a/sound/soc/sof/sof-priv.h ++++ b/sound/soc/sof/sof-priv.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -119,6 +120,7 @@ struct sof_compr_stream { + u32 sampling_rate; + u16 channels; + u16 sample_container_bytes; ++ struct snd_codec codec_params; + size_t posn_offset; + }; + +-- +2.53.0 + diff --git a/queue-6.12/asoc-sof-intel-hda-place-check-before-dereference.patch b/queue-6.12/asoc-sof-intel-hda-place-check-before-dereference.patch new file mode 100644 index 0000000000..9467db6905 --- /dev/null +++ b/queue-6.12/asoc-sof-intel-hda-place-check-before-dereference.patch @@ -0,0 +1,60 @@ +From 291161f2ddd6e19568e892db4b6ba2880b5170fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 12:38:30 -0500 +Subject: ASoC: SOF: Intel: hda: Place check before dereference + +From: Ethan Tidmore + +[ Upstream commit 6cbc8360f51a3df2ea16a786b262b9fe44d4c68c ] + +The struct hext_stream is dereferenced before it is checked for NULL. +Although it can never be NULL due to a check prior to +hda_dsp_iccmax_stream_hw_params() being called, this change clears any +confusion regarding hext_stream possibly being NULL. + +Check hext_stream for NULL and then assign its members. + +Detected by Smatch: +sound/soc/sof/intel/hda-stream.c:488 hda_dsp_iccmax_stream_hw_params() warn: +variable dereferenced before check 'hext_stream' (see line 486) + +Fixes: aca961f196e5d ("ASoC: SOF: Intel: hda: Add helper function to program ICCMAX stream") +Signed-off-by: Ethan Tidmore +Link: https://patch.msgid.link/20260324173830.17563-1-ethantidmore06@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/intel/hda-stream.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c +index 2be0d02f9cf9b..d6a0e78b5ce73 100644 +--- a/sound/soc/sof/intel/hda-stream.c ++++ b/sound/soc/sof/intel/hda-stream.c +@@ -419,16 +419,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params) + { +- struct hdac_stream *hstream = &hext_stream->hstream; +- int sd_offset = SOF_STREAM_SD_OFFSET(hstream); ++ struct hdac_stream *hstream; ++ int sd_offset; + int ret; +- u32 mask = 0x1 << hstream->index; ++ u32 mask; + + if (!hext_stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + ++ hstream = &hext_stream->hstream; ++ sd_offset = SOF_STREAM_SD_OFFSET(hstream); ++ mask = 0x1 << hstream->index; ++ + if (!dmab) { + dev_err(sdev->dev, "error: no dma buffer allocated!\n"); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-6.12/asoc-sof-ipc3-use-standard-dev_dbg-api.patch b/queue-6.12/asoc-sof-ipc3-use-standard-dev_dbg-api.patch new file mode 100644 index 0000000000..40601de2d7 --- /dev/null +++ b/queue-6.12/asoc-sof-ipc3-use-standard-dev_dbg-api.patch @@ -0,0 +1,37 @@ +From a886628a86a778acfe401441522fd075231437e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Sep 2024 12:02:52 +0300 +Subject: ASoC: SOF: ipc3: Use standard dev_dbg API + +From: Daniel Baluta + +[ Upstream commit 55c39835ee0ef94593a78f6ea808138d476f3b81 ] + +Use standard dev_dbg API because it gives better debugging +information and allows dynamic control of prints. + +Signed-off-by: Daniel Baluta +Link: https://patch.msgid.link/20240926090252.106040-1-daniel.baluta@nxp.com +Signed-off-by: Mark Brown +Stable-dep-of: 07c774dd64ba ("ASoC: soc-compress: use function to clear symmetric params") +Signed-off-by: Sasha Levin +--- + sound/soc/sof/ipc3.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c +index 83c22d4a48304..7de5e3d285e73 100644 +--- a/sound/soc/sof/ipc3.c ++++ b/sound/soc/sof/ipc3.c +@@ -226,7 +226,7 @@ static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) + static void sof_ipc3_dump_payload(struct snd_sof_dev *sdev, + void *ipc_data, size_t size) + { +- printk(KERN_DEBUG "Size of payload following the header: %zu\n", size); ++ dev_dbg(sdev->dev, "Size of payload following the header: %zu\n", size); + print_hex_dump_debug("Message payload: ", DUMP_PREFIX_OFFSET, + 16, 4, ipc_data, size, false); + } +-- +2.53.0 + diff --git a/queue-6.12/asoc-sti-return-errors-from-regmap_field_alloc.patch b/queue-6.12/asoc-sti-return-errors-from-regmap_field_alloc.patch new file mode 100644 index 0000000000..88d2cdf3d5 --- /dev/null +++ b/queue-6.12/asoc-sti-return-errors-from-regmap_field_alloc.patch @@ -0,0 +1,50 @@ +From a927d77d8e5b87ee236fee64f2a977c363448886 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:33 +0100 +Subject: ASoC: sti: Return errors from regmap_field_alloc() + +From: Sander Vanheule + +[ Upstream commit 272aabef50bc3fe58edd26de000f4cdd41bdbe60 ] + +When regmap_field_alloc() fails, it can return an error. Specifically, +it will return PTR_ERR(-ENOMEM) when the allocation returns a NULL +pointer. The code then uses these allocations with a simple NULL check: + + if (player->clk_sel) { + // May dereference invalid pointer (-ENOMEM) + err = regmap_field_write(player->clk_sel, ...); + } + +Ensure initialization fails by forwarding the errors from +regmap_field_alloc(), thus avoiding the use of the invalid pointers. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-2-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index 6d1ce030963c6..f1b7e76f97b58 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1029,7 +1029,12 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + } + + player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ if (IS_ERR(player->clk_sel)) ++ return PTR_ERR(player->clk_sel); ++ + player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ if (IS_ERR(player->valid_sel)) ++ return PTR_ERR(player->valid_sel); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/asoc-sti-use-managed-regmap_field-allocations.patch b/queue-6.12/asoc-sti-use-managed-regmap_field-allocations.patch new file mode 100644 index 0000000000..c85da4d0df --- /dev/null +++ b/queue-6.12/asoc-sti-use-managed-regmap_field-allocations.patch @@ -0,0 +1,45 @@ +From e591f22452501c10801d40fa127a9d9fcb2fb0b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:34 +0100 +Subject: ASoC: sti: use managed regmap_field allocations + +From: Sander Vanheule + +[ Upstream commit 1696fad8b259a2d46e51cd6e17e4bcdbe02279fa ] + +The regmap_field objects allocated at player init are never freed and +may leak resources if the driver is removed. + +Switch to devm_regmap_field_alloc() to automatically limit the lifetime +of the allocations the lifetime of the device. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-3-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index f1b7e76f97b58..45d35b887e4eb 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1028,11 +1028,11 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + return PTR_ERR(regmap); + } + +- player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]); + if (IS_ERR(player->clk_sel)) + return PTR_ERR(player->clk_sel); + +- player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]); + if (IS_ERR(player->valid_sel)) + return PTR_ERR(player->valid_sel); + +-- +2.53.0 + diff --git a/queue-6.12/backlight-sky81452-backlight-check-return-value-of-d.patch b/queue-6.12/backlight-sky81452-backlight-check-return-value-of-d.patch new file mode 100644 index 0000000000..ea9df9c83d --- /dev/null +++ b/queue-6.12/backlight-sky81452-backlight-check-return-value-of-d.patch @@ -0,0 +1,46 @@ +From 43f14d5bc193392768feb860a5025e3ae3e4f943 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:16:25 +0800 +Subject: backlight: sky81452-backlight: Check return value of + devm_gpiod_get_optional() in sky81452_bl_parse_dt() + +From: Chen Ni + +[ Upstream commit 797cc011ae02bda26f93d25a4442d7a1a77d84df ] + +The devm_gpiod_get_optional() function may return an ERR_PTR in case of +genuine GPIO acquisition errors, not just NULL which indicates the +legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the call in sky81452_bl_parse_dt(). On +error, return the error code to ensure proper failure handling rather +than proceeding with invalid pointers. + +Fixes: e1915eec54a6 ("backlight: sky81452: Convert to GPIO descriptors") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260203021625.578678-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/sky81452-backlight.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c +index 935043b677869..3a5ff1b6f4327 100644 +--- a/drivers/video/backlight/sky81452-backlight.c ++++ b/drivers/video/backlight/sky81452-backlight.c +@@ -202,6 +202,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( + pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode"); + pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift"); + pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); ++ if (IS_ERR(pdata->gpiod_enable)) ++ return dev_err_cast_probe(dev, pdata->gpiod_enable, ++ "failed to get gpio\n"); + + ret = of_property_count_u32_elems(np, "led-sources"); + if (ret < 0) { +-- +2.53.0 + diff --git a/queue-6.12/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch b/queue-6.12/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch new file mode 100644 index 0000000000..1db21356c1 --- /dev/null +++ b/queue-6.12/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch @@ -0,0 +1,60 @@ +From c2dd6d308c0286e4140a7911d4d63cb58d77715f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 09:53:51 -0700 +Subject: bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst() + +From: Weiming Shi + +[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ] + +bareudp_fill_metadata_dst() passes bareudp->sock to +udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. +The socket is only created in bareudp_open() and NULLed in +bareudp_stop(), so calling this function while the device is down +triggers a NULL dereference via sock->sk. + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) + Call Trace: + + bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) + do_execute_actions (net/openvswitch/actions.c:901) + ovs_execute_actions (net/openvswitch/actions.c:1589) + ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) + genl_rcv_msg (net/netlink/genetlink.c:1209) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths +in the same driver. + +Fixes: 571912c69f0e ("net: UDP tunnel encapsulation module for tunnelling different protocols like MPLS, IP, NSH etc.") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426165350.1663137-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index fa2dd76ba3d9e..8d6b632371f89 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -528,6 +528,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + ++ if (!sock) ++ return -ESHUTDOWN; ++ + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, + 0, &saddr, &info->key, + sport, bareudp->port, info->key.tos, +-- +2.53.0 + diff --git a/queue-6.12/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch b/queue-6.12/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch new file mode 100644 index 0000000000..c0cdabbd6a --- /dev/null +++ b/queue-6.12/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch @@ -0,0 +1,47 @@ +From aa823201cf1d8368e85d6420d20cb09fb3b82011 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:50:54 +0800 +Subject: blk-cgroup: fix disk reference leak in blkcg_maybe_throttle_current() + +From: Jackie Liu + +[ Upstream commit 23308af722fefed00af5f238024c11710938fba3 ] + +Add the missing put_disk() on the error path in +blkcg_maybe_throttle_current(). When blkcg lookup, blkg lookup, or +blkg_tryget() fails, the function jumps to the out label which only +calls rcu_read_unlock() but does not release the disk reference acquired +by blkcg_schedule_throttle() via get_device(). Since current->throttle_disk +is already set to NULL before the lookup, blkcg_exit() cannot release +this reference either, causing the disk to never be freed. + +Restore the reference release that was present as blk_put_queue() in the +original code but was inadvertently dropped during the conversion from +request_queue to gendisk. + +Fixes: f05837ed73d0 ("blk-cgroup: store a gendisk to throttle in struct task_struct") +Signed-off-by: Jackie Liu +Acked-by: Tejun Heo +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260331085054.46857-1-liu.yun@linux.dev +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 9a198001cfa56..a0fbb427a7a62 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -1985,6 +1985,7 @@ void blkcg_maybe_throttle_current(void) + return; + out: + rcu_read_unlock(); ++ put_disk(disk); + } + + /** +-- +2.53.0 + diff --git a/queue-6.12/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch b/queue-6.12/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch new file mode 100644 index 0000000000..b798f8cca7 --- /dev/null +++ b/queue-6.12/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch @@ -0,0 +1,75 @@ +From 0ba737c0da48ee1d28a7dc282f2f2ebfc0a73abb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 11:28:37 +0800 +Subject: blk-cgroup: wait for blkcg cleanup before initializing new disk + +From: Ming Lei + +[ Upstream commit 3dbaacf6ab68f81e3375fe769a2ecdbd3ce386fd ] + +When a queue is shared across disk rebind (e.g., SCSI unbind/bind), the +previous disk's blkcg state is cleaned up asynchronously via +disk_release() -> blkcg_exit_disk(). If the new disk's blkcg_init_disk() +runs before that cleanup finishes, we may overwrite q->root_blkg while +the old one is still alive, and radix_tree_insert() in blkg_create() +fails with -EEXIST because the old blkg entries still occupy the same +queue id slot in blkcg->blkg_tree. This causes the sd probe to fail +with -ENOMEM. + +Fix it by waiting in blkcg_init_disk() for root_blkg to become NULL, +which indicates the previous disk's blkcg cleanup has completed. + +Fixes: 1059699f87eb ("block: move blkcg initialization/destroy into disk allocation/release handler") +Cc: Yi Zhang +Signed-off-by: Ming Lei +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260311032837.2368714-1-ming.lei@redhat.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 3f7cb9d891aa3..9a198001cfa56 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -611,6 +612,8 @@ static void blkg_destroy_all(struct gendisk *disk) + + q->root_blkg = NULL; + spin_unlock_irq(&q->queue_lock); ++ ++ wake_up_var(&q->root_blkg); + } + + static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) +@@ -1451,6 +1454,18 @@ int blkcg_init_disk(struct gendisk *disk) + struct blkcg_gq *new_blkg, *blkg; + bool preloaded; + ++ /* ++ * If the queue is shared across disk rebind (e.g., SCSI), the ++ * previous disk's blkcg state is cleaned up asynchronously via ++ * disk_release() -> blkcg_exit_disk(). Wait for that cleanup to ++ * finish (indicated by root_blkg becoming NULL) before setting up ++ * new blkcg state. Otherwise, we may overwrite q->root_blkg while ++ * the old one is still alive, and radix_tree_insert() in ++ * blkg_create() will fail with -EEXIST because the old entries ++ * still occupy the same queue id slot in blkcg->blkg_tree. ++ */ ++ wait_var_event(&q->root_blkg, !READ_ONCE(q->root_blkg)); ++ + new_blkg = blkg_alloc(&blkcg_root, disk, GFP_KERNEL); + if (!new_blkg) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch b/queue-6.12/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch new file mode 100644 index 0000000000..8c286639de --- /dev/null +++ b/queue-6.12/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch @@ -0,0 +1,52 @@ +From 08780df9da363c44fe938d0a699d5db10ab10b9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:42:59 +0300 +Subject: Bluetooth: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER + +From: Pauli Virtanen + +[ Upstream commit 5c7209a341ff2ac338b2b0375c34a307b37c9ac2 ] + +When protocol sets HCI_PROTO_DEFER, hci_conn_request_evt() calls +hci_connect_cfm(conn) without hdev->lock. Generally hci_connect_cfm() +assumes it is held, and if conn is deleted concurrently -> UAF. + +Only SCO and ISO set HCI_PROTO_DEFER and only for defer setup listen, +and HCI_EV_CONN_REQUEST is not generated for ISO. In the non-deferred +listening socket code paths, hci_connect_cfm(conn) is called with +hdev->lock held. + +Fix by holding the lock. + +Fixes: 70c464256310 ("Bluetooth: Refactor connection request handling") +Signed-off-by: Pauli Virtanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 8a14c00ad7278..92270b99ee0f2 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -3284,8 +3284,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + + memcpy(conn->dev_class, ev->dev_class, 3); + +- hci_dev_unlock(hdev); +- + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; +@@ -3319,7 +3317,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + hci_connect_cfm(conn, 0); + } + +- return; + unlock: + hci_dev_unlock(hdev); + } +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch b/queue-6.12/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch new file mode 100644 index 0000000000..079b7b87c3 --- /dev/null +++ b/queue-6.12/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch @@ -0,0 +1,49 @@ +From 27165722ef9d5361b4549df9f0a167ccdf688b2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:20 +0100 +Subject: Bluetooth: hci_ldisc: Clear HCI_UART_PROTO_INIT on error + +From: Jonathan Rissanen + +[ Upstream commit 68d39ea5e0adc9ecaea1ce8abd842ec972eb8718 ] + +When hci_register_dev() fails in hci_uart_register_dev() +HCI_UART_PROTO_INIT is not cleared before calling hu->proto->close(hu) +and setting hu->hdev to NULL. This means incoming UART data will reach +the protocol-specific recv handler in hci_uart_tty_receive() after +resources are freed. + +Clear HCI_UART_PROTO_INIT with a write lock before calling +hu->proto->close() and setting hu->hdev to NULL. The write lock ensures +all active readers have completed and no new reader can enter the +protocol recv path before resources are freed. + +This allows the protocol-specific recv functions to remove the +"HCI_UART_REGISTERED" guard without risking a null pointer dereference +if hci_register_dev() fails. + +Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization") +Signed-off-by: Jonathan Rissanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ldisc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index 436ee77d4bf2f..0d06b83816d1c 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -692,6 +692,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device"); ++ percpu_down_write(&hu->proto_lock); ++ clear_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ percpu_up_write(&hu->proto_lock); + hu->proto->close(hu); + hu->hdev = NULL; + hci_free_dev(hdev); +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch b/queue-6.12/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch new file mode 100644 index 0000000000..e1fa8aba17 --- /dev/null +++ b/queue-6.12/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch @@ -0,0 +1,48 @@ +From 44239765e07974a0dcf3586c34e99125e7054e43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 23:47:41 +0800 +Subject: Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp + +From: Dudu Lu + +[ Upstream commit 42776497cdbc9a665b384a6dcb85f0d4bd927eab ] + +l2cap_ecred_reconf_rsp() calls l2cap_chan_del() without holding +l2cap_chan_lock(). Every other l2cap_chan_del() caller in the file +acquires the lock first. A remote BLE device can send a crafted +L2CAP ECRED reconfiguration response to corrupt the channel list +while another thread is iterating it. + +Add l2cap_chan_hold() and l2cap_chan_lock() before l2cap_chan_del(), +and l2cap_chan_unlock() and l2cap_chan_put() after, matching the +pattern used in l2cap_ecred_conn_rsp() and l2cap_conn_del(). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index bb927603c2d15..b01107370cbcb 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5399,7 +5399,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + if (chan->ident != cmd->ident) + continue; + ++ l2cap_chan_hold(chan); ++ l2cap_chan_lock(chan); ++ + l2cap_chan_del(chan, ECONNRESET); ++ ++ l2cap_chan_unlock(chan); ++ l2cap_chan_put(chan); + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch b/queue-6.12/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch new file mode 100644 index 0000000000..61ea052cc9 --- /dev/null +++ b/queue-6.12/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch @@ -0,0 +1,38 @@ +From ddb534a29ebdca9427fa5c202324d7bf9e09ad25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 14:34:13 -0400 +Subject: Bluetooth: L2CAP: Fix printing wrong information if SDU length + exceeds MTU + +From: Luiz Augusto von Dentz + +[ Upstream commit 15bf35a660eb82a49f8397fc3d3acada8dae13db ] + +The code was printing skb->len and sdu_len in the places where it should +be sdu_len and chan->imtu respectively to match the if conditions. + +Link: https://lore.kernel.org/linux-bluetooth/20260315132013.75ab40c5@kernel.org/T/#m1418f9c82eeff8510c1beaa21cf53af20db96c06 +Fixes: e1d9a6688986 ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU") +Signed-off-by: Luiz Augusto von Dentz +Reviewed-by: Paul Menzel +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 307f7fe975b59..bb927603c2d15 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6657,7 +6657,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + + if (sdu_len > chan->imtu) { + BT_ERR("Too big LE L2CAP SDU length: len %u > %u", +- skb->len, sdu_len); ++ sdu_len, chan->imtu); + l2cap_send_disconn_req(chan, ECONNRESET); + err = -EMSGSIZE; + goto failed; +-- +2.53.0 + diff --git a/queue-6.12/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch b/queue-6.12/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch new file mode 100644 index 0000000000..f683b93573 --- /dev/null +++ b/queue-6.12/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch @@ -0,0 +1,70 @@ +From edf8ef0e86c58f48be329b75e3c995d18b70d87b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:13:45 +0200 +Subject: Bluetooth: SCO: check for codecs->num_codecs == 1 before assigning to + sco_pi(sk)->codec + +From: Stefan Metzmacher + +[ Upstream commit 4e10a9ebbf081c16517cdd9366ac618bf38d7d0c ] + +copy_struct_from_sockptr() fill 'buffer' in +sco_sock_setsockopt() with zeros, so there's no +real problem. + +But it actually looks strange to do this, +without checking all of codecs->codecs[0] +really comes from userspace: + + sco_pi(sk)->codec = codecs->codecs[0]; + +As only optlen < sizeof(struct bt_codecs) is checked +and codecs->num_codecs is not checked against != 1, +but only <= 1, and the space for the additional struct bt_codec +is not checked. + +Note I don't understand bluetooth and I didn't do any runtime +tests with this! I just found it when debugging a problem +in copy_struct_from_sockptr(). + +I just added this to check the size is as expected: + + BUILD_BUG_ON(struct_size(codecs, codecs, 0) != 1); + BUILD_BUG_ON(struct_size(codecs, codecs, 1) != 8); + +And made sure it still compiles using this: + + make CF=-D__CHECK_ENDIAN__ W=1ce C=1 net/bluetooth/sco.o + +Fixes: 3e643e4efa1e ("Bluetooth: Improve setsockopt() handling of malformed user input") +Cc: Michal Luczaj +Cc: Luiz Augusto von Dentz +Cc: Luiz Augusto von Dentz +Cc: Marcel Holtmann +Cc: David Wei +Cc: linux-bluetooth@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Stefan Metzmacher +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/sco.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index ded0c52ccf0b9..d915db52db221 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -978,7 +978,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, + + codecs = (void *)buffer; + +- if (codecs->num_codecs > 1) { ++ if (codecs->num_codecs != 1 || ++ optlen < struct_size(codecs, codecs, codecs->num_codecs)) { + hci_dev_put(hdev); + err = -EINVAL; + break; +-- +2.53.0 + diff --git a/queue-6.12/bpf-allow-instructions-with-arena-source-and-non-are.patch b/queue-6.12/bpf-allow-instructions-with-arena-source-and-non-are.patch new file mode 100644 index 0000000000..2bc76a4f8d --- /dev/null +++ b/queue-6.12/bpf-allow-instructions-with-arena-source-and-non-are.patch @@ -0,0 +1,64 @@ +From 0a08327717ce1b8c5fcc68a4ba865f221001bf13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 13:45:38 -0400 +Subject: bpf: Allow instructions with arena source and non-arena dest + registers + +From: Emil Tsalapatis + +[ Upstream commit ac61bffe91d4bda08806e12957c6d64756d042db ] + +The compiler sometimes stores the result of a PTR_TO_ARENA and SCALAR +operation into the scalar register rather than the pointer register. +Relax the verifier to allow operations between a source arena register +and a destination non-arena register, marking the destination's value +as a PTR_TO_ARENA. + +Signed-off-by: Emil Tsalapatis +Acked-by: Song Liu +Fixes: 6082b6c328b5 ("bpf: Recognize addr_space_cast instruction in the verifier.") +Link: https://lore.kernel.org/r/20260412174546.18684-2-emil@etsalapatis.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index f5e9ee63fff99..56a74ce4a29b9 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -14434,11 +14434,20 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + int err; + + dst_reg = ®s[insn->dst_reg]; +- src_reg = NULL; ++ if (BPF_SRC(insn->code) == BPF_X) ++ src_reg = ®s[insn->src_reg]; ++ else ++ src_reg = NULL; + +- if (dst_reg->type == PTR_TO_ARENA) { ++ /* Case where at least one operand is an arena. */ ++ if (dst_reg->type == PTR_TO_ARENA || (src_reg && src_reg->type == PTR_TO_ARENA)) { + struct bpf_insn_aux_data *aux = cur_aux(env); + ++ if (dst_reg->type != PTR_TO_ARENA) ++ *dst_reg = *src_reg; ++ ++ dst_reg->subreg_def = env->insn_idx + 1; ++ + if (BPF_CLASS(insn->code) == BPF_ALU64) + /* + * 32-bit operations zero upper bits automatically. +@@ -14454,7 +14463,6 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + ptr_reg = dst_reg; + + if (BPF_SRC(insn->code) == BPF_X) { +- src_reg = ®s[insn->src_reg]; + if (src_reg->type != SCALAR_VALUE) { + if (dst_reg->type != SCALAR_VALUE) { + /* Combining two pointers by any ALU op yields +-- +2.53.0 + diff --git a/queue-6.12/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch b/queue-6.12/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch new file mode 100644 index 0000000000..e701de9538 --- /dev/null +++ b/queue-6.12/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch @@ -0,0 +1,84 @@ +From 825542b7f0bfa7c7bef47d91a0dba18ef070980a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:01:41 +0800 +Subject: bpf: allow UTF-8 literals in bpf_bprintf_prepare() + +From: Yihan Ding + +[ Upstream commit b960430ea8862ef37ce53c8bf74a8dc79d3f2404 ] + +bpf_bprintf_prepare() only needs ASCII parsing for conversion +specifiers. Plain text can safely carry bytes >= 0x80, so allow +UTF-8 literals outside '%' sequences while keeping ASCII control +bytes rejected and format specifiers ASCII-only. + +This keeps existing parsing rules for format directives unchanged, +while allowing helpers such as bpf_trace_printk() to emit UTF-8 +literal text. + +Update test_snprintf_negative() in the same commit so selftests keep +matching the new plain-text vs format-specifier split during bisection. + +Fixes: 48cac3f4a96d ("bpf: Implement formatted output helpers with bstr_printf") +Signed-off-by: Yihan Ding +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416120142.1420646-2-dingyihan@uniontech.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/helpers.c | 17 ++++++++++++++++- + .../testing/selftests/bpf/prog_tests/snprintf.c | 3 ++- + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index db4739951702e..8aa7ca9c34c74 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -847,7 +847,13 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, + data->buf = buffers->buf; + + for (i = 0; i < fmt_size; i++) { +- if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { ++ unsigned char c = fmt[i]; ++ ++ /* ++ * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass ++ * through unchanged, while still rejecting ASCII control bytes. ++ */ ++ if (isascii(c) && !isprint(c) && !isspace(c)) { + err = -EINVAL; + goto out; + } +@@ -869,6 +875,15 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, + * always access fmt[i + 1], in the worst case it will be a 0 + */ + i++; ++ c = fmt[i]; ++ /* ++ * The format parser below only understands ASCII conversion ++ * specifiers and modifiers, so reject non-ASCII after '%'. ++ */ ++ if (!isascii(c)) { ++ err = -EINVAL; ++ goto out; ++ } + + /* skip optional "[0 +-][num]" width formatting field */ + while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || +diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c +index 4be6fdb78c6a1..20a3c622bd28a 100644 +--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c ++++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c +@@ -114,7 +114,8 @@ static void test_snprintf_negative(void) + ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5"); + ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6"); + ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7"); +- ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character"); ++ ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text"); ++ ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier"); + ASSERT_ERR(load_single_snprintf("\x1"), "non printable character"); + } + +-- +2.53.0 + diff --git a/queue-6.12/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch b/queue-6.12/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch new file mode 100644 index 0000000000..240ed2bece --- /dev/null +++ b/queue-6.12/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch @@ -0,0 +1,63 @@ +From e9dfddf422ac91eff049084a8380ac7ddb2f9393 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 20:27:02 +0800 +Subject: bpf,arc_jit: Fix missing newline in pr_err messages + +From: haoyu.lu + +[ Upstream commit b6b5e0ebd429d66ce37ae5af649a74ea1f041d92 ] + +Add missing newline to pr_err messages in ARC JIT. + +Fixes: f122668ddcce ("ARC: Add eBPF JIT support") +Signed-off-by: haoyu.lu +Link: https://lore.kernel.org/r/20260324122703.641-1-hechushiguitu666@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arc/net/bpf_jit_arcv2.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arc/net/bpf_jit_arcv2.c b/arch/arc/net/bpf_jit_arcv2.c +index 6d989b6d88c69..7ee50aeae5a45 100644 +--- a/arch/arc/net/bpf_jit_arcv2.c ++++ b/arch/arc/net/bpf_jit_arcv2.c +@@ -2427,7 +2427,7 @@ u8 arc_prologue(u8 *buf, u32 usage, u16 frame_size) + + #ifdef ARC_BPF_JIT_DEBUG + if ((usage & BIT(ARC_R_FP)) && frame_size == 0) { +- pr_err("FP is being saved while there is no frame."); ++ pr_err("FP is being saved while there is no frame.\n"); + BUG(); + } + #endif +@@ -2454,7 +2454,7 @@ u8 arc_epilogue(u8 *buf, u32 usage, u16 frame_size) + + #ifdef ARC_BPF_JIT_DEBUG + if ((usage & BIT(ARC_R_FP)) && frame_size == 0) { +- pr_err("FP is being saved while there is no frame."); ++ pr_err("FP is being saved while there is no frame.\n"); + BUG(); + } + #endif +@@ -2868,7 +2868,7 @@ u8 gen_jmp_64(u8 *buf, u8 rd, u8 rs, u8 cond, u32 curr_off, u32 targ_off) + break; + default: + #ifdef ARC_BPF_JIT_DEBUG +- pr_err("64-bit jump condition is not known."); ++ pr_err("64-bit jump condition is not known.\n"); + BUG(); + #endif + } +@@ -2948,7 +2948,7 @@ u8 gen_jmp_32(u8 *buf, u8 rd, u8 rs, u8 cond, u32 curr_off, u32 targ_off) + */ + if (cond >= ARC_CC_LAST) { + #ifdef ARC_BPF_JIT_DEBUG +- pr_err("32-bit jump condition is not known."); ++ pr_err("32-bit jump condition is not known.\n"); + BUG(); + #endif + return 0; +-- +2.53.0 + diff --git a/queue-6.12/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch b/queue-6.12/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch new file mode 100644 index 0000000000..09992eb2bb --- /dev/null +++ b/queue-6.12/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch @@ -0,0 +1,96 @@ +From eab71e3e657af362e2f67154030682b635fdd5bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 07:33:52 -0700 +Subject: bpf, arm32: Reject BPF-to-BPF calls and callbacks in the JIT + +From: Puranjay Mohan + +[ Upstream commit e1d486445af3c392628532229f7ce5f5cf7891b6 ] + +The ARM32 BPF JIT does not support BPF-to-BPF function calls +(BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does +not reject them either. + +When a program with subprograms is loaded (e.g. libxdp's XDP +dispatcher uses __noinline__ subprograms, or any program using +callbacks like bpf_loop or bpf_for_each_map_elem), the verifier +invokes bpf_jit_subprogs() which calls bpf_int_jit_compile() +for each subprogram. + +For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT +silently emits code using the wrong address computation: + + func = __bpf_call_base + imm + +where imm is a pc-relative subprogram offset, producing a bogus +function pointer. + +For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and +loads the immediate as a normal 64-bit value without error. + +In both cases, build_body() reports success and a JIT image is +allocated. ARM32 lacks the jit_data/extra_pass mechanism needed +for the second JIT pass in bpf_jit_subprogs(). On the second +pass, bpf_int_jit_compile() performs a full fresh compilation, +allocating a new JIT binary and overwriting prog->bpf_func. The +first allocation is never freed. bpf_jit_subprogs() then detects +the function pointer changed and aborts with -ENOTSUPP, but the +original JIT binary has already been leaked. Each program +load/unload cycle leaks one JIT binary allocation, as reported +by kmemleak: + + unreferenced object 0xbf0a1000 (size 4096): + backtrace: + bpf_jit_binary_alloc+0x64/0xfc + bpf_int_jit_compile+0x14c/0x348 + bpf_jit_subprogs+0x4fc/0xa60 + +Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL +handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling +through to the existing 'notyet' path. This causes build_body() +to fail before any JIT binary is allocated, so +bpf_int_jit_compile() returns the original program unjitted. +bpf_jit_subprogs() then sees !prog->jited and cleanly falls +back to the interpreter with no leak. + +Acked-by: Daniel Borkmann +Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs") +Reported-by: Jonas Rebmann +Closes: https://lore.kernel.org/bpf/b63e9174-7a3d-4e22-8294-16df07a4af89@pengutronix.de +Tested-by: Jonas Rebmann +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417143353.838911-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm/net/bpf_jit_32.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c +index deeb8f292454b..a900aa9738855 100644 +--- a/arch/arm/net/bpf_jit_32.c ++++ b/arch/arm/net/bpf_jit_32.c +@@ -1852,6 +1852,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + { + u64 val = (u32)imm | (u64)insn[1].imm << 32; + ++ if (insn->src_reg == BPF_PSEUDO_FUNC) ++ goto notyet; ++ + emit_a32_mov_i64(dst, val, ctx); + + return 1; +@@ -2055,6 +2058,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + const s8 *r5 = bpf2a32[BPF_REG_5]; + const u32 func = (u32)__bpf_call_base + (u32)imm; + ++ if (insn->src_reg == BPF_PSEUDO_CALL) ++ goto notyet; ++ + emit_a32_mov_r64(true, r0, r1, ctx); + emit_a32_mov_r64(true, r1, r2, ctx); + emit_push_r64(r5, ctx); +-- +2.53.0 + diff --git a/queue-6.12/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch b/queue-6.12/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch new file mode 100644 index 0000000000..2f89e445fe --- /dev/null +++ b/queue-6.12/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch @@ -0,0 +1,57 @@ +From f790a6224e365060e68dd0acb54f0ce1c6b04d51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:14:03 +0200 +Subject: bpf, arm64: Fix off-by-one in check_imm signed range check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Borkmann + +[ Upstream commit 1dd8be4ec722ce54e4cace59f3a4ba658111b3ec ] + +check_imm(bits, imm) is used in the arm64 BPF JIT to verify that +a branch displacement (in arm64 instruction units) fits into the +signed N-bit immediate field of a B, B.cond or CBZ/CBNZ encoding +before it is handed to the encoder. The macro currently tests for +(imm > 0 && imm >> bits) || (imm < 0 && ~imm >> bits) which admits +values in [-2^N, 2^N) — effectively a signed (N+1)-bit range. A +signed N-bit field only holds [-2^(N-1), 2^(N-1)), so the check +admits one extra bit of range on each side. + +In particular, for check_imm19(), values in [2^18, 2^19) slip past +the check but do not fit into the 19-bit signed imm19 field of +B.cond. aarch64_insn_encode_immediate() then masks the raw value +into the 19-bit field, setting bit 18 (the sign bit) and flipping +a forward branch into a backward one. Same class of issue exists +for check_imm26() and the B/BL encoding. Shift by (bits - 1) +instead of bits so the actual signed N-bit range is enforced. + +Fixes: e54bcde3d69d ("arm64: eBPF JIT compiler") +Signed-off-by: Daniel Borkmann +Reviewed-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260415121403.639619-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 9310196e0a09e..c852749405e0c 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -33,8 +33,8 @@ + #define ARENA_VM_START (MAX_BPF_JIT_REG + 5) + + #define check_imm(bits, imm) do { \ +- if ((((imm) > 0) && ((imm) >> (bits))) || \ +- (((imm) < 0) && (~(imm) >> (bits)))) { \ ++ if ((((imm) > 0) && ((imm) >> ((bits) - 1))) || \ ++ (((imm) < 0) && (~(imm) >> ((bits) - 1)))) { \ + pr_info("[%2d] imm=%d(0x%x) out of range\n", \ + i, imm, imm); \ + return -EINVAL; \ +-- +2.53.0 + diff --git a/queue-6.12/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch b/queue-6.12/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch new file mode 100644 index 0000000000..b9f0bdab50 --- /dev/null +++ b/queue-6.12/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch @@ -0,0 +1,52 @@ +From b5b847319e716563c9479a2c0f482af8b3909658 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 20:23:33 +0800 +Subject: bpf: Drop task_to_inode and inet_conn_established from lsm sleepable + hooks + +From: Jiayuan Chen + +[ Upstream commit beaf0e96b1da74549a6cabd040f9667d83b2e97e ] + +bpf_lsm_task_to_inode() is called under rcu_read_lock() and +bpf_lsm_inet_conn_established() is called from softirq context, so +neither hook can be used by sleepable LSM programs. + +Fixes: 423f16108c9d8 ("bpf: Augment the set of sleepable LSM hooks") +Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/3ab69731-24d1-431a-a351-452aafaaf2a5@std.uestc.edu.cn/T/#u +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260407122334.344072-1-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_lsm.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c +index 3bc61628ab251..0849453b36176 100644 +--- a/kernel/bpf/bpf_lsm.c ++++ b/kernel/bpf/bpf_lsm.c +@@ -355,8 +355,6 @@ BTF_ID(func, bpf_lsm_sb_umount) + BTF_ID(func, bpf_lsm_settime) + + #ifdef CONFIG_SECURITY_NETWORK +-BTF_ID(func, bpf_lsm_inet_conn_established) +- + BTF_ID(func, bpf_lsm_socket_accept) + BTF_ID(func, bpf_lsm_socket_bind) + BTF_ID(func, bpf_lsm_socket_connect) +@@ -379,7 +377,6 @@ BTF_ID(func, bpf_lsm_current_getsecid_subj) + BTF_ID(func, bpf_lsm_task_getsecid_obj) + BTF_ID(func, bpf_lsm_task_prctl) + BTF_ID(func, bpf_lsm_task_setscheduler) +-BTF_ID(func, bpf_lsm_task_to_inode) + BTF_ID(func, bpf_lsm_userns_create) + BTF_SET_END(sleepable_lsm_hooks) + +-- +2.53.0 + diff --git a/queue-6.12/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch b/queue-6.12/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch new file mode 100644 index 0000000000..4f84e21e83 --- /dev/null +++ b/queue-6.12/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch @@ -0,0 +1,77 @@ +From 3b1d677ddbb034a5b5f44c5e35a30d53bf9fe21b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 01:26:50 +0200 +Subject: bpf: Enforce regsafe base id consistency for BPF_ADD_CONST scalars + +From: Daniel Borkmann + +[ Upstream commit 2f2ec8e7730e21fc9bd49e0de9cdd58213ea24d0 ] + +When regsafe() compares two scalar registers that both carry +BPF_ADD_CONST, check_scalar_ids() maps their full compound id +(aka base | BPF_ADD_CONST flag) as one idmap entry. However, +it never verifies that the underlying base ids, that is, with +the flag stripped are consistent with existing idmap mappings. + +This allows construction of two verifier states where the old +state has R3 = R2 + 10 (both sharing base id A) while the current +state has R3 = R4 + 10 (base id C, unrelated to R2). The idmap +creates two independent entries: A->B (for R2) and A|flag->C|flag +(for R3), without catching that A->C conflicts with A->B. State +pruning then incorrectly succeeds. + +Fix this by additionally verifying base ID mapping consistency +whenever BPF_ADD_CONST is set: after mapping the compound ids, +also invoke check_ids() on the base IDs (flag bits stripped). +This ensures that if A was already mapped to B from comparing +the source register, any ADD_CONST derivative must also derive +from B, not an unrelated C. + +Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260410232651.559778-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 87d631917f4dd..f5e9ee63fff99 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -17442,6 +17442,13 @@ static bool check_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + * and r7.id=0 (both independent), without temp IDs both would map old_id=X + * to cur_id=0 and pass. With temp IDs: r6 maps X->temp1, r7 tries to map + * X->temp2, but X is already mapped to temp1, so the check fails correctly. ++ * ++ * When old_id has BPF_ADD_CONST set, the compound id (base | flag) and the ++ * base id (flag stripped) must both map consistently. Example: old has ++ * r2.id=A, r3.id=A|flag (r3 = r2 + delta), cur has r2.id=B, r3.id=C|flag ++ * (r3 derived from unrelated r4). Without the base check, idmap gets two ++ * independent entries A->B and A|flag->C|flag, missing that A->C conflicts ++ * with A->B. The base ID cross-check catches this. + */ + static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + { +@@ -17450,7 +17457,15 @@ static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + + cur_id = cur_id ? cur_id : ++idmap->tmp_id_gen; + +- return check_ids(old_id, cur_id, idmap); ++ if (!check_ids(old_id, cur_id, idmap)) ++ return false; ++ if (old_id & BPF_ADD_CONST) { ++ old_id &= ~BPF_ADD_CONST; ++ cur_id &= ~BPF_ADD_CONST; ++ if (!check_ids(old_id, cur_id, idmap)) ++ return false; ++ } ++ return true; + } + + static void clean_func_state(struct bpf_verifier_env *env, +-- +2.53.0 + diff --git a/queue-6.12/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch b/queue-6.12/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch new file mode 100644 index 0000000000..ac72c9aca8 --- /dev/null +++ b/queue-6.12/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch @@ -0,0 +1,47 @@ +From 91ba8c962856b559ceac60c95649a08d194a7b1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 21:29:50 +0800 +Subject: bpf: fix end-of-list detection in cgroup_storage_get_next_key() + +From: Weiming Shi + +[ Upstream commit 5828b9e5b272ecff7cf5d345128d3de7324117f7 ] + +list_next_entry() never returns NULL -- when the current element is the +last entry it wraps to the list head via container_of(). The subsequent +NULL check is therefore dead code and get_next_key() never returns +-ENOENT for the last element, instead reading storage->key from a bogus +pointer that aliases internal map fields and copying the result to +userspace. + +Replace it with list_entry_is_head() so the function correctly returns +-ENOENT when there are no more entries. + +Fixes: de9cbbaadba5 ("bpf: introduce cgroup storage maps") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Sun Jian +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260403132951.43533-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/local_storage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c +index 3969eb0382afb..cfb4ff2610518 100644 +--- a/kernel/bpf/local_storage.c ++++ b/kernel/bpf/local_storage.c +@@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, + goto enoent; + + storage = list_next_entry(storage, list_map); +- if (!storage) ++ if (list_entry_is_head(storage, &map->list, list_map)) + goto enoent; + } else { + storage = list_first_entry(&map->list, +-- +2.53.0 + diff --git a/queue-6.12/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch b/queue-6.12/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch new file mode 100644 index 0000000000..f486f0d318 --- /dev/null +++ b/queue-6.12/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch @@ -0,0 +1,148 @@ +From 79b0f992290826f3fd10845993f0db7dfe77b89b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:35 -0700 +Subject: bpf: fix mm lifecycle in open-coded task_vma iterator + +From: Puranjay Mohan + +[ Upstream commit d8e27d2d22b6e2df3a0125b8c08e9aace38c954c ] + +The open-coded task_vma iterator reads task->mm locklessly and acquires +mmap_read_trylock() but never calls mmget(). If the task exits +concurrently, the mm_struct can be freed as it is not +SLAB_TYPESAFE_BY_RCU, resulting in a use-after-free. + +Safely read task->mm with a trylock on alloc_lock and acquire an mm +reference. Drop the reference via bpf_iter_mmput_async() in _destroy() +and error paths. bpf_iter_mmput_async() is a local wrapper around +mmput_async() with a fallback to mmput() on !CONFIG_MMU. + +Reject irqs-disabled contexts (including NMI) up front. Operations used +by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) +take spinlocks with IRQs disabled (pool->lock, pi_lock). Running from +NMI or from a tracepoint that fires with those locks held could +deadlock. + +A trylock on alloc_lock is used instead of the blocking task_lock() +(get_task_mm) to avoid a deadlock when a softirq BPF program iterates +a task that already holds its alloc_lock on the same CPU. + +Fixes: 4ac454682158 ("bpf: Introduce task_vma open-coded iterator kfuncs") +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260408154539.3832150-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 54 +++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 51 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index 5af9e130e500f..c37ae44bd0a53 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include "mmap_unlock_work.h" + + static const char * const iter_task_type_names[] = { +@@ -798,6 +799,15 @@ const struct bpf_func_proto bpf_find_vma_proto = { + .arg5_type = ARG_ANYTHING, + }; + ++static inline void bpf_iter_mmput_async(struct mm_struct *mm) ++{ ++#ifdef CONFIG_MMU ++ mmput_async(mm); ++#else ++ mmput(mm); ++#endif ++} ++ + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +@@ -829,6 +839,24 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + BUILD_BUG_ON(sizeof(struct bpf_iter_task_vma_kern) != sizeof(struct bpf_iter_task_vma)); + BUILD_BUG_ON(__alignof__(struct bpf_iter_task_vma_kern) != __alignof__(struct bpf_iter_task_vma)); + ++ /* bpf_iter_mmput_async() needs mmput_async() which requires CONFIG_MMU */ ++ if (!IS_ENABLED(CONFIG_MMU)) { ++ kit->data = NULL; ++ return -EOPNOTSUPP; ++ } ++ ++ /* ++ * Reject irqs-disabled contexts including NMI. Operations used ++ * by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) ++ * can take spinlocks with IRQs disabled (pi_lock, pool->lock). ++ * Running from NMI or from a tracepoint that fires with those ++ * locks held could deadlock. ++ */ ++ if (irqs_disabled()) { ++ kit->data = NULL; ++ return -EBUSY; ++ } ++ + /* is_iter_reg_valid_uninit guarantees that kit hasn't been initialized + * before, so non-NULL kit->data doesn't point to previously + * bpf_mem_alloc'd bpf_iter_task_vma_kern_data +@@ -838,7 +866,25 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + return -ENOMEM; + + kit->data->task = get_task_struct(task); ++ /* ++ * Safely read task->mm and acquire an mm reference. ++ * ++ * Cannot use get_task_mm() because its task_lock() is a ++ * blocking spin_lock that would deadlock if the target task ++ * already holds alloc_lock on this CPU (e.g. a softirq BPF ++ * program iterating a task interrupted while holding its ++ * alloc_lock). ++ */ ++ if (!spin_trylock(&task->alloc_lock)) { ++ err = -EBUSY; ++ goto err_cleanup_iter; ++ } + kit->data->mm = task->mm; ++ if (kit->data->mm && !(task->flags & PF_KTHREAD)) ++ mmget(kit->data->mm); ++ else ++ kit->data->mm = NULL; ++ spin_unlock(&task->alloc_lock); + if (!kit->data->mm) { + err = -ENOENT; + goto err_cleanup_iter; +@@ -848,15 +894,16 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work); + if (irq_work_busy || !mmap_read_trylock(kit->data->mm)) { + err = -EBUSY; +- goto err_cleanup_iter; ++ goto err_cleanup_mmget; + } + + vma_iter_init(&kit->data->vmi, kit->data->mm, addr); + return 0; + ++err_cleanup_mmget: ++ bpf_iter_mmput_async(kit->data->mm); + err_cleanup_iter: +- if (kit->data->task) +- put_task_struct(kit->data->task); ++ put_task_struct(kit->data->task); + bpf_mem_free(&bpf_global_ma, kit->data); + /* NULL kit->data signals failed bpf_iter_task_vma initialization */ + kit->data = NULL; +@@ -879,6 +926,7 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + if (kit->data) { + bpf_mmap_unlock_mm(kit->data->work, kit->data->mm); + put_task_struct(kit->data->task); ++ bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); + } + } +-- +2.53.0 + diff --git a/queue-6.12/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch b/queue-6.12/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch new file mode 100644 index 0000000000..838c92873f --- /dev/null +++ b/queue-6.12/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch @@ -0,0 +1,56 @@ +From 2dc8c33199b2514abb52b284c5aada4620168b4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 11:08:07 -0700 +Subject: bpf: Fix NULL deref in map_kptr_match_type for scalar regs + +From: Mykyta Yatsenko + +[ Upstream commit 4d0a375887ab4d49e4da1ff10f9606cab8f7c3ad ] + +Commit ab6c637ad027 ("bpf: Fix a bpf_kptr_xchg() issue with local +kptr") refactored map_kptr_match_type() to branch on btf_is_kernel() +before checking base_type(). A scalar register stored into a kptr +slot has no btf, so the btf_is_kernel(reg->btf) call dereferences +NULL. + +Move the base_type() != PTR_TO_BTF_ID guard before any reg->btf +access. + +Fixes: ab6c637ad027 ("bpf: Fix a bpf_kptr_xchg() issue with local kptr") +Reported-by: Hiker Cl +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221372 +Signed-off-by: Mykyta Yatsenko +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416-kptr_crash-v1-1-5589356584b4@meta.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 56a74ce4a29b9..64a6ec8eb847b 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5473,6 +5473,9 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + int perm_flags; + const char *reg_name = ""; + ++ if (base_type(reg->type) != PTR_TO_BTF_ID) ++ goto bad_type; ++ + if (btf_is_kernel(reg->btf)) { + perm_flags = PTR_MAYBE_NULL | PTR_TRUSTED | MEM_RCU; + +@@ -5485,7 +5488,7 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + perm_flags |= MEM_PERCPU; + } + +- if (base_type(reg->type) != PTR_TO_BTF_ID || (type_flag(reg->type) & ~perm_flags)) ++ if (type_flag(reg->type) & ~perm_flags) + goto bad_type; + + /* We need to verify reg->type and reg->btf, before accessing reg->btf */ +-- +2.53.0 + diff --git a/queue-6.12/bpf-fix-oob-in-pcpu_init_value.patch b/queue-6.12/bpf-fix-oob-in-pcpu_init_value.patch new file mode 100644 index 0000000000..98fc0af031 --- /dev/null +++ b/queue-6.12/bpf-fix-oob-in-pcpu_init_value.patch @@ -0,0 +1,54 @@ +From 81e1543a90b472ff88457154713f4d0b70da0d09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 15:42:35 +0800 +Subject: bpf: Fix OOB in pcpu_init_value + +From: Lang Xu + +[ Upstream commit 576afddfee8d1108ee299bf10f581593540d1a36 ] + +An out-of-bounds read occurs when copying element from a +BPF_MAP_TYPE_CGROUP_STORAGE map to another pcpu map with the +same value_size that is not rounded up to 8 bytes. + +The issue happens when: +1. A CGROUP_STORAGE map is created with value_size not aligned to + 8 bytes (e.g., 4 bytes) +2. A pcpu map is created with the same value_size (e.g., 4 bytes) +3. Update element in 2 with data in 1 + +pcpu_init_value assumes that all sources are rounded up to 8 bytes, +and invokes copy_map_value_long to make a data copy, However, the +assumption doesn't stand since there are some cases where the source +may not be rounded up to 8 bytes, e.g., CGROUP_STORAGE, skb->data. +the verifier verifies exactly the size that the source claims, not +the size rounded up to 8 bytes by kernel, an OOB happens when the +source has only 4 bytes while the copy size(4) is rounded up to 8. + +Fixes: d3bec0138bfb ("bpf: Zero-fill re-used per-cpu map element") +Reported-by: Kaiyan Mei +Closes: https://lore.kernel.org/all/14e6c70c.6c121.19c0399d948.Coremail.kaiyanm@hust.edu.cn/ +Link: https://lore.kernel.org/r/420FEEDDC768A4BE+20260402074236.2187154-1-xulang@uniontech.com +Signed-off-by: Lang Xu +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/hashtab.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c +index 26883a997e717..9f9026a619d59 100644 +--- a/kernel/bpf/hashtab.c ++++ b/kernel/bpf/hashtab.c +@@ -995,7 +995,7 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr, + + for_each_possible_cpu(cpu) { + if (cpu == current_cpu) +- copy_map_value_long(&htab->map, per_cpu_ptr(pptr, cpu), value); ++ copy_map_value(&htab->map, per_cpu_ptr(pptr, cpu), value); + else /* Since elem is preallocated, we cannot touch special fields */ + zero_map_value(&htab->map, per_cpu_ptr(pptr, cpu)); + } +-- +2.53.0 + diff --git a/queue-6.12/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch b/queue-6.12/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch new file mode 100644 index 0000000000..5a027a99e7 --- /dev/null +++ b/queue-6.12/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch @@ -0,0 +1,46 @@ +From a462d11231b946d340936f66fbae0c15e903893f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:27:19 +0200 +Subject: bpf: Fix precedence bug in convert_bpf_ld_abs alignment check + +From: Daniel Borkmann + +[ Upstream commit e5f635edd393aeaa7cad9e42831d397e6e2e1eed ] + +Fix an operator precedence issue in convert_bpf_ld_abs() where the +expression offset + ip_align % size evaluates as offset + (ip_align % size) +due to % having higher precedence than +. That latter evaluation does +not make any sense. The intended check is (offset + ip_align) % size == 0 +to verify that the packet load offset is properly aligned for direct +access. + +With NET_IP_ALIGN == 2, the bug causes the inline fast-path for direct +packet loads to almost never be taken on !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +platforms. This forces nearly all cBPF BPF_LD_ABS packet loads through +the bpf_skb_load_helper slow path on the affected archs. + +Fixes: e0cea7ce988c ("bpf: implement ld_abs/ld_ind in native bpf") +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260416122719.661033-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 795e558155c6d..1d7467601a32c 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -499,7 +499,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp) + ((unaligned_ok && offset >= 0) || + (!unaligned_ok && offset >= 0 && + offset + ip_align >= 0 && +- offset + ip_align % size == 0))) { ++ (offset + ip_align) % size == 0))) { + bool ldx_off_ok = offset <= S16_MAX; + + *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H); +-- +2.53.0 + diff --git a/queue-6.12/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch b/queue-6.12/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch new file mode 100644 index 0000000000..3408235d9f --- /dev/null +++ b/queue-6.12/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch @@ -0,0 +1,62 @@ +From f5e39c4318bf5aee263a0730c09d41957e037b24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 10:38:23 +0000 +Subject: bpf: Fix RCU stall in bpf_fd_array_map_clear() + +From: Sechang Lim + +[ Upstream commit 4406942e65ca128c56c67443832988873c21d2e9 ] + +Add a missing cond_resched() in bpf_fd_array_map_clear() loop. + +For PROG_ARRAY maps with many entries this loop calls +prog_array_map_poke_run() per entry which can be expensive, and +without yielding this can cause RCU stalls under load: + + rcu: Stack dump where RCU GP kthread last ran: + CPU: 0 UID: 0 PID: 30932 Comm: kworker/0:2 Not tainted 6.14.0-13195-g967e8def1100 #2 PREEMPT(undef) + Workqueue: events prog_array_map_clear_deferred + RIP: 0010:write_comp_data+0x38/0x90 kernel/kcov.c:246 + Call Trace: + + prog_array_map_poke_run+0x77/0x380 kernel/bpf/arraymap.c:1096 + __fd_array_map_delete_elem+0x197/0x310 kernel/bpf/arraymap.c:925 + bpf_fd_array_map_clear kernel/bpf/arraymap.c:1000 [inline] + prog_array_map_clear_deferred+0x119/0x1b0 kernel/bpf/arraymap.c:1141 + process_one_work+0x898/0x19d0 kernel/workqueue.c:3238 + process_scheduled_works kernel/workqueue.c:3319 [inline] + worker_thread+0x770/0x10b0 kernel/workqueue.c:3400 + kthread+0x465/0x880 kernel/kthread.c:464 + ret_from_fork+0x4d/0x80 arch/x86/kernel/process.c:153 + ret_from_fork_asm+0x19/0x30 arch/x86/entry/entry_64.S:245 + + +Reviewed-by: Sun Jian +Fixes: da765a2f5993 ("bpf: Add poke dependency tracking for prog array maps") +Signed-off-by: Sechang Lim +Link: https://lore.kernel.org/r/20260407103823.3942156-1-rhkrqnwk98@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/arraymap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c +index 6cdbb4c33d31d..7ec69545fe056 100644 +--- a/kernel/bpf/arraymap.c ++++ b/kernel/bpf/arraymap.c +@@ -998,8 +998,10 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer) + struct bpf_array *array = container_of(map, struct bpf_array, map); + int i; + +- for (i = 0; i < array->map.max_entries; i++) ++ for (i = 0; i < array->map.max_entries; i++) { + __fd_array_map_delete_elem(map, &i, need_defer); ++ cond_resched(); ++ } + } + + static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key, +-- +2.53.0 + diff --git a/queue-6.12/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch b/queue-6.12/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch new file mode 100644 index 0000000000..986898ef05 --- /dev/null +++ b/queue-6.12/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch @@ -0,0 +1,72 @@ +From 58ce75a25eaf6c267579b2386ac763a595cad5f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:18:50 +0800 +Subject: bpf: Fix stale offload->prog pointer after constant blinding + +From: MingTao Huang + +[ Upstream commit a1aa9ef47c299c5bbc30594d3c2f0589edf908e6 ] + +When a dev-bound-only BPF program (BPF_F_XDP_DEV_BOUND_ONLY) undergoes +JIT compilation with constant blinding enabled (bpf_jit_harden >= 2), +bpf_jit_blind_constants() clones the program. The original prog is then +freed in bpf_jit_prog_release_other(), which updates aux->prog to point +to the surviving clone, but fails to update offload->prog. + +This leaves offload->prog pointing to the freed original program. When +the network namespace is subsequently destroyed, cleanup_net() triggers +bpf_dev_bound_netdev_unregister(), which iterates ondev->progs and calls +__bpf_prog_offload_destroy(offload->prog). Accessing the freed prog +causes a page fault: + +BUG: unable to handle page fault for address: ffffc900085f1038 +Workqueue: netns cleanup_net +RIP: 0010:__bpf_prog_offload_destroy+0xc/0x80 +Call Trace: +__bpf_offload_dev_netdev_unregister+0x257/0x350 +bpf_dev_bound_netdev_unregister+0x4a/0x90 +unregister_netdevice_many_notify+0x2a2/0x660 +... +cleanup_net+0x21a/0x320 + +The test sequence that triggers this reliably is: + +1. Set net.core.bpf_jit_harden=2 (echo 2 > /proc/sys/net/core/bpf_jit_harden) +2. Run xdp_metadata selftest, which creates a dev-bound-only XDP + program on a veth inside a netns (./test_progs -t xdp_metadata) +3. cleanup_net -> page fault in __bpf_prog_offload_destroy + +Dev-bound-only programs are unique in that they have an offload structure +but go through the normal JIT path instead of bpf_prog_offload_compile(). +This means they are subject to constant blinding's prog clone-and-replace, +while also having offload->prog that must stay in sync. + +Fix this by updating offload->prog in bpf_jit_prog_release_other(), +alongside the existing aux->prog update. Both are back-pointers to +the prog that must be kept in sync when the prog is replaced. + +Fixes: 2b3486bc2d23 ("bpf: Introduce device-bound XDP programs") +Signed-off-by: MingTao Huang +Link: https://lore.kernel.org/r/tencent_BCF692F45859CCE6C22B7B0B64827947D406@qq.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index b58833e99969a..517710c89fa50 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1489,6 +1489,8 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other) + * know whether fp here is the clone or the original. + */ + fp->aux->prog = fp; ++ if (fp->aux->offload) ++ fp->aux->offload->prog = fp; + bpf_prog_clone_free(fp_other); + } + +-- +2.53.0 + diff --git a/queue-6.12/bpf-fix-variable-length-stack-write-over-spilled-poi.patch b/queue-6.12/bpf-fix-variable-length-stack-write-over-spilled-poi.patch new file mode 100644 index 0000000000..f81f766bc7 --- /dev/null +++ b/queue-6.12/bpf-fix-variable-length-stack-write-over-spilled-poi.patch @@ -0,0 +1,80 @@ +From fb5f02b304eb930b3b4538a58af6d4a7b5db35db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:59:36 -0700 +Subject: bpf: Fix variable length stack write over spilled pointers + +From: Alexei Starovoitov + +[ Upstream commit 4639eb9e30ab10c7935c7c19e872facf9a94713f ] + +Scrub slots if variable-offset stack write goes over spilled pointers. +Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT +and valid program is rejected by check_stack_read_fixed_off() +with obscure "invalid size of register fill" message. + +Fixes: 01f810ace9ed ("bpf: Allow variable-offset stack access") +Acked-by: Eduard Zingerman +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260324215938.81733-1-alexei.starovoitov@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 96a04cd904a11..feb90c6e94620 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -4724,6 +4724,18 @@ static void check_fastcall_stack_contract(struct bpf_verifier_env *env, + } + } + ++static void scrub_special_slot(struct bpf_func_state *state, int spi) ++{ ++ int i; ++ ++ /* regular write of data into stack destroys any spilled ptr */ ++ state->stack[spi].spilled_ptr.type = NOT_INIT; ++ /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */ ++ if (is_stack_slot_special(&state->stack[spi])) ++ for (i = 0; i < BPF_REG_SIZE; i++) ++ scrub_spilled_slot(&state->stack[spi].slot_type[i]); ++} ++ + /* check_stack_{read,write}_fixed_off functions track spill/fill of registers, + * stack boundary and alignment are checked in check_mem_access() + */ +@@ -4809,12 +4821,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, + } else { + u8 type = STACK_MISC; + +- /* regular write of data into stack destroys any spilled ptr */ +- state->stack[spi].spilled_ptr.type = NOT_INIT; +- /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */ +- if (is_stack_slot_special(&state->stack[spi])) +- for (i = 0; i < BPF_REG_SIZE; i++) +- scrub_spilled_slot(&state->stack[spi].slot_type[i]); ++ scrub_special_slot(state, spi); + + /* only mark the slot as written if all 8 bytes were written + * otherwise read propagation may incorrectly stop too soon +@@ -4949,8 +4956,13 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env, + } + } + +- /* Erase all other spilled pointers. */ +- state->stack[spi].spilled_ptr.type = NOT_INIT; ++ /* ++ * Scrub slots if variable-offset stack write goes over spilled pointers. ++ * Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT ++ * and valid program is rejected by check_stack_read_fixed_off() ++ * with obscure "invalid size of register fill" message. ++ */ ++ scrub_special_slot(state, spi); + + /* Update the slot type. */ + new_type = STACK_MISC; +-- +2.53.0 + diff --git a/queue-6.12/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch b/queue-6.12/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch new file mode 100644 index 0000000000..ad5c656e23 --- /dev/null +++ b/queue-6.12/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch @@ -0,0 +1,74 @@ +From 23227b56b8bb0ff73a4443481ff1a0dbe43713d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 00:12:20 +0800 +Subject: bpf: reject negative CO-RE accessor indices in bpf_core_parse_spec() + +From: Weiming Shi + +[ Upstream commit 1c22483a2c4bbf747787f328392ca3e68619c4dc ] + +CO-RE accessor strings are colon-separated indices that describe a path +from a root BTF type to a target field, e.g. "0:1:2" walks through +nested struct members. bpf_core_parse_spec() parses each component with +sscanf("%d"), so negative values like -1 are silently accepted. The +subsequent bounds checks (access_idx >= btf_vlen(t)) only guard the +upper bound and always pass for negative values because C integer +promotion converts the __u16 btf_vlen result to int, making the +comparison (int)(-1) >= (int)(N) false for any positive N. + +When -1 reaches btf_member_bit_offset() it gets cast to u32 0xffffffff, +producing an out-of-bounds read far past the members array. A crafted +BPF program with a negative CO-RE accessor on any struct that exists in +vmlinux BTF (e.g. task_struct) crashes the kernel deterministically +during BPF_PROG_LOAD on any system with CONFIG_DEBUG_INFO_BTF=y +(default on major distributions). The bug is reachable with CAP_BPF: + + BUG: unable to handle page fault for address: ffffed11818b6626 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + Oops: Oops: 0000 [#1] SMP KASAN NOPTI + CPU: 0 UID: 0 PID: 85 Comm: poc Not tainted 7.0.0-rc6 #18 PREEMPT(full) + RIP: 0010:bpf_core_parse_spec (tools/lib/bpf/relo_core.c:354) + RAX: 00000000ffffffff + Call Trace: + + bpf_core_calc_relo_insn (tools/lib/bpf/relo_core.c:1321) + bpf_core_apply (kernel/bpf/btf.c:9507) + check_core_relo (kernel/bpf/verifier.c:19475) + bpf_check (kernel/bpf/verifier.c:26031) + bpf_prog_load (kernel/bpf/syscall.c:3089) + __sys_bpf (kernel/bpf/syscall.c:6228) + + +CO-RE accessor indices are inherently non-negative (struct member index, +array element index, or enumerator index), so reject them immediately +after parsing. + +Fixes: ddc7c3042614 ("libbpf: implement BPF CO-RE offset relocation algorithm") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Emil Tsalapatis +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260404161221.961828-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/relo_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c +index 63a4d5ad12d1a..04c8febfc0aa7 100644 +--- a/tools/lib/bpf/relo_core.c ++++ b/tools/lib/bpf/relo_core.c +@@ -293,6 +293,8 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf, + ++spec_str; + if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1) + return -EINVAL; ++ if (access_idx < 0) ++ return -EINVAL; + if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) + return -E2BIG; + spec_str += parsed_len; +-- +2.53.0 + diff --git a/queue-6.12/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch b/queue-6.12/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch new file mode 100644 index 0000000000..7334c55e85 --- /dev/null +++ b/queue-6.12/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch @@ -0,0 +1,72 @@ +From 0970810ae62b93ebec9e92db751fa34c44a3f94b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 11:46:22 +0800 +Subject: bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb + +From: Sun Jian + +[ Upstream commit 12bec2bd4b76d81c5d3996bd14ec1b7f4d983747 ] + +bpf_prog_test_run_skb() calls eth_type_trans() first and then uses +skb->protocol to initialize sk family and address fields for the test +run. + +For IPv4 and IPv6 packets, it may access ip_hdr(skb) or ipv6_hdr(skb) +even when the provided test input only contains an Ethernet header. + +Reject the input earlier if the Ethernet frame carries IPv4/IPv6 +EtherType but the L3 header is too short. + +Fold the IPv4/IPv6 header length checks into the existing protocol +switch and return -EINVAL before accessing the network headers. + +Fixes: fa5cb548ced6 ("bpf: Setup socket family and addresses in bpf_prog_test_run_skb") +Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc +Signed-off-by: Sun Jian +Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 18257cf6bb488..7f12abc8a80cb 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1061,19 +1061,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + switch (skb->protocol) { + case htons(ETH_P_IP): +- sk->sk_family = AF_INET; +- if (sizeof(struct iphdr) <= skb_headlen(skb)) { +- sk->sk_rcv_saddr = ip_hdr(skb)->saddr; +- sk->sk_daddr = ip_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct iphdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET; ++ sk->sk_rcv_saddr = ip_hdr(skb)->saddr; ++ sk->sk_daddr = ip_hdr(skb)->daddr; + break; + #if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +- sk->sk_family = AF_INET6; +- if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { +- sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; +- sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET6; ++ sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; ++ sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + break; + #endif + default: +-- +2.53.0 + diff --git a/queue-6.12/bpf-relax-scalar-id-equivalence-for-state-pruning.patch b/queue-6.12/bpf-relax-scalar-id-equivalence-for-state-pruning.patch new file mode 100644 index 0000000000..07c69742d7 --- /dev/null +++ b/queue-6.12/bpf-relax-scalar-id-equivalence-for-state-pruning.patch @@ -0,0 +1,172 @@ +From 84fcb61a47b89425eb27b5f81dcbb05b4a556a9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 08:51:00 -0800 +Subject: bpf: Relax scalar id equivalence for state pruning + +From: Puranjay Mohan + +[ Upstream commit b0388bafa4949bd30af7b3be5ee415f2a25ac014 ] + +Scalar register IDs are used by the verifier to track relationships +between registers and enable bounds propagation across those +relationships. Once an ID becomes singular (i.e. only a single +register/stack slot carries it), it can no longer contribute to bounds +propagation and effectively becomes stale. The previous commit makes the +verifier clear such ids before caching the state. + +When comparing the current and cached states for pruning, these stale +IDs can cause technically equivalent states to be considered different +and thus prevent pruning. + +For example, in the selftest added in the next commit, two registers - +r6 and r7 are not linked to any other registers and get cached with +id=0, in the current state, they are both linked to each other with +id=A. Before this commit, check_scalar_ids would give temporary ids to +r6 and r7 (say tid1 and tid2) and then check_ids() would map tid1->A, +and when it would see tid2->A, it would not consider these state +equivalent. + +Relax scalar ID equivalence by treating rold->id == 0 as "independent": +if the old state did not rely on any ID relationships for a register, +then any ID/linking present in the current state only adds constraints +and is always safe to accept for pruning. Implement this by returning +true immediately in check_scalar_ids() when old_id == 0. + +Maintain correctness for the opposite direction (old_id != 0 && cur_id +== 0) by still allocating a temporary ID for cur_id == 0. This avoids +incorrectly allowing multiple independent current registers (id==0) to +satisfy a single linked old ID during mapping. + +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260203165102.2302462-5-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Stable-dep-of: 2f2ec8e7730e ("bpf: Enforce regsafe base id consistency for BPF_ADD_CONST scalars") +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 63 +++++++++++++++---- + .../selftests/bpf/progs/verifier_scalar_ids.c | 8 ++- + 2 files changed, 56 insertions(+), 15 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index feb90c6e94620..87d631917f4dd 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -17425,13 +17425,29 @@ static bool check_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + return false; + } + +-/* Similar to check_ids(), but allocate a unique temporary ID +- * for 'old_id' or 'cur_id' of zero. +- * This makes pairs like '0 vs unique ID', 'unique ID vs 0' valid. ++/* ++ * Compare scalar register IDs for state equivalence. ++ * ++ * When old_id == 0, the old register is independent - not linked to any ++ * other register. Any linking in the current state only adds constraints, ++ * making it more restrictive. Since the old state didn't rely on any ID ++ * relationships for this register, it's always safe to accept cur regardless ++ * of its ID. Hence, return true immediately. ++ * ++ * When old_id != 0 but cur_id == 0, we need to ensure that different ++ * independent registers in cur don't incorrectly satisfy the ID matching ++ * requirements of linked registers in old. ++ * ++ * Example: if old has r6.id=X and r7.id=X (linked), but cur has r6.id=0 ++ * and r7.id=0 (both independent), without temp IDs both would map old_id=X ++ * to cur_id=0 and pass. With temp IDs: r6 maps X->temp1, r7 tries to map ++ * X->temp2, but X is already mapped to temp1, so the check fails correctly. + */ + static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + { +- old_id = old_id ? old_id : ++idmap->tmp_id_gen; ++ if (!old_id) ++ return true; ++ + cur_id = cur_id ? cur_id : ++idmap->tmp_id_gen; + + return check_ids(old_id, cur_id, idmap); +@@ -17600,11 +17616,21 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, + } + if (!rold->precise && exact == NOT_EXACT) + return true; +- if ((rold->id & BPF_ADD_CONST) != (rcur->id & BPF_ADD_CONST)) +- return false; +- if ((rold->id & BPF_ADD_CONST) && (rold->off != rcur->off)) +- return false; +- /* Why check_ids() for scalar registers? ++ /* ++ * Linked register tracking uses rold->id to detect relationships. ++ * When rold->id == 0, the register is independent and any linking ++ * in rcur only adds constraints. When rold->id != 0, we must verify ++ * id mapping and (for BPF_ADD_CONST) offset consistency. ++ * ++ * +------------------+-----------+------------------+---------------+ ++ * | | rold->id | rold + ADD_CONST | rold->id == 0 | ++ * |------------------+-----------+------------------+---------------| ++ * | rcur->id | range,ids | false | range | ++ * | rcur + ADD_CONST | false | range,ids,off | range | ++ * | rcur->id == 0 | range,ids | false | range | ++ * +------------------+-----------+------------------+---------------+ ++ * ++ * Why check_ids() for scalar registers? + * + * Consider the following BPF code: + * 1: r6 = ... unbound scalar, ID=a ... +@@ -17628,9 +17654,22 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, + * --- + * Also verify that new value satisfies old value range knowledge. + */ +- return range_within(rold, rcur) && +- tnum_in(rold->var_off, rcur->var_off) && +- check_scalar_ids(rold->id, rcur->id, idmap); ++ ++ /* ADD_CONST mismatch: different linking semantics */ ++ if ((rold->id & BPF_ADD_CONST) && !(rcur->id & BPF_ADD_CONST)) ++ return false; ++ ++ if (rold->id && !(rold->id & BPF_ADD_CONST) && (rcur->id & BPF_ADD_CONST)) ++ return false; ++ ++ /* Both have offset linkage: offsets must match */ ++ if ((rold->id & BPF_ADD_CONST) && rold->off != rcur->off) ++ return false; ++ ++ if (!check_scalar_ids(rold->id, rcur->id, idmap)) ++ return false; ++ ++ return range_within(rold, rcur) && tnum_in(rold->var_off, rcur->var_off); + case PTR_TO_MAP_KEY: + case PTR_TO_MAP_VALUE: + case PTR_TO_MEM: +diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +index 7c5e5e6d10ebc..dc65218e93c47 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c ++++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +@@ -723,9 +723,9 @@ __success __log_level(2) + /* The exit instruction should be reachable from two states, + * use two matches and "processed .. insns" to ensure this. + */ +-__msg("13: (95) exit") +-__msg("13: (95) exit") +-__msg("processed 18 insns") ++__msg("15: (95) exit") ++__msg("15: (95) exit") ++__msg("processed 20 insns") + __flag(BPF_F_TEST_STATE_FREQ) + __naked void two_old_ids_one_cur_id(void) + { +@@ -734,9 +734,11 @@ __naked void two_old_ids_one_cur_id(void) + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r6 = r0;" ++ "r8 = r0;" + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r7 = r0;" ++ "r9 = r0;" + "r0 = 0;" + /* Maybe make r{6,7} IDs identical */ + "if r6 > r7 goto l0_%=;" +-- +2.53.0 + diff --git a/queue-6.12/bpf-return-vma-snapshot-from-task_vma-iterator.patch b/queue-6.12/bpf-return-vma-snapshot-from-task_vma-iterator.patch new file mode 100644 index 0000000000..7c44bc2fb7 --- /dev/null +++ b/queue-6.12/bpf-return-vma-snapshot-from-task_vma-iterator.patch @@ -0,0 +1,133 @@ +From 7ad64c8489f89baea5df6d0f6c6959f6ef6228a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:37 -0700 +Subject: bpf: return VMA snapshot from task_vma iterator + +From: Puranjay Mohan + +[ Upstream commit 4cbee026db54cad39c39db4d356100cb133412b3 ] + +Holding the per-VMA lock across the BPF program body creates a lock +ordering problem when helpers acquire locks that depend on mmap_lock: + + vm_lock -> i_rwsem -> mmap_lock -> vm_lock + +Snapshot the VMA under the per-VMA lock in _next() via memcpy(), then +drop the lock before returning. The BPF program accesses only the +snapshot. + +The verifier only trusts vm_mm and vm_file pointers (see +BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). vm_file is reference- +counted with get_file() under the lock and released via fput() on the +next iteration or in _destroy(). vm_mm is already correct because +lock_vma_under_rcu() verifies vma->vm_mm == mm. All other pointers +are left as-is by memcpy() since the verifier treats them as untrusted. + +Fixes: 4ac454682158 ("bpf: Introduce task_vma open-coded iterator kfuncs") +Signed-off-by: Puranjay Mohan +Acked-by: Andrii Nakryiko +Acked-by: Mykyta Yatsenko +Link: https://lore.kernel.org/r/20260408154539.3832150-4-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 42 ++++++++++++++++++++++++++++++------------ + 1 file changed, 30 insertions(+), 12 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index aee03c55602a0..fc5f463ca529a 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -812,7 +812,7 @@ static inline void bpf_iter_mmput_async(struct mm_struct *mm) + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +- struct vm_area_struct *locked_vma; ++ struct vm_area_struct snapshot; + u64 next_addr; + }; + +@@ -846,7 +846,7 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + + /* + * Reject irqs-disabled contexts including NMI. Operations used +- * by _next() and _destroy() (vma_end_read, bpf_iter_mmput_async) ++ * by _next() and _destroy() (vma_end_read, fput, bpf_iter_mmput_async) + * can take spinlocks with IRQs disabled (pi_lock, pool->lock). + * Running from NMI or from a tracepoint that fires with those + * locks held could deadlock. +@@ -889,7 +889,7 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + goto err_cleanup_iter; + } + +- kit->data->locked_vma = NULL; ++ kit->data->snapshot.vm_file = NULL; + kit->data->next_addr = addr; + return 0; + +@@ -951,26 +951,45 @@ bpf_iter_task_vma_find_next(struct bpf_iter_task_vma_kern_data *data) + return vma; + } + ++static void bpf_iter_task_vma_snapshot_reset(struct vm_area_struct *snap) ++{ ++ if (snap->vm_file) { ++ fput(snap->vm_file); ++ snap->vm_file = NULL; ++ } ++} ++ + __bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; +- struct vm_area_struct *vma; ++ struct vm_area_struct *snap, *vma; + + if (!kit->data) /* bpf_iter_task_vma_new failed */ + return NULL; + +- if (kit->data->locked_vma) { +- vma_end_read(kit->data->locked_vma); +- kit->data->locked_vma = NULL; +- } ++ snap = &kit->data->snapshot; ++ ++ bpf_iter_task_vma_snapshot_reset(snap); + + vma = bpf_iter_task_vma_find_next(kit->data); + if (!vma) + return NULL; + +- kit->data->locked_vma = vma; ++ memcpy(snap, vma, sizeof(*snap)); ++ ++ /* ++ * The verifier only trusts vm_mm and vm_file (see ++ * BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). Take a reference ++ * on vm_file; vm_mm is already correct because lock_vma_under_rcu() ++ * verifies vma->vm_mm == mm. All other pointers are untrusted by ++ * the verifier and left as-is. ++ */ ++ if (snap->vm_file) ++ get_file(snap->vm_file); ++ + kit->data->next_addr = vma->vm_end; +- return vma; ++ vma_end_read(vma); ++ return snap; + } + + __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) +@@ -978,8 +997,7 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + struct bpf_iter_task_vma_kern *kit = (void *)it; + + if (kit->data) { +- if (kit->data->locked_vma) +- vma_end_read(kit->data->locked_vma); ++ bpf_iter_task_vma_snapshot_reset(&kit->data->snapshot); + put_task_struct(kit->data->task); + bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); +-- +2.53.0 + diff --git a/queue-6.12/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch b/queue-6.12/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch new file mode 100644 index 0000000000..58dad06c76 --- /dev/null +++ b/queue-6.12/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch @@ -0,0 +1,82 @@ +From 11489d03eafea7842ec22d6304b4824622ffa00c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:11:09 -0700 +Subject: bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator + finalize + +From: Puranjay Mohan + +[ Upstream commit 46ee1342b887c9387a933397d846ff6c9584322c ] + +bpf_flush_icache() calls flush_icache_range() to clean the data cache +and invalidate the instruction cache for the JITed code region. However, +since commit 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the +BPF JIT"), this flush is redundant. + +bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX +region via bpf_arch_text_copy() -> patch_text_nosync(), and +patch_text_nosync() already calls flush_icache_range() on the written +range. The subsequent bpf_flush_icache() repeats the same cache +maintenance on an overlapping range. + +Remove the redundant bpf_flush_icache() call and its now-unused +definition. + +Fixes: 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT") +Acked-by: Song Liu +Signed-off-by: Puranjay Mohan +Reviewed-by: Pu Lehui +Tested-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260413191111.3426023-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/riscv/net/bpf_jit.h | 6 ------ + arch/riscv/net/bpf_jit_core.c | 7 ------- + 2 files changed, 13 deletions(-) + +diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h +index 1d1c78d4cff1e..f87bad9a0578c 100644 +--- a/arch/riscv/net/bpf_jit.h ++++ b/arch/riscv/net/bpf_jit.h +@@ -11,7 +11,6 @@ + + #include + #include +-#include + + static inline bool rvc_enabled(void) + { +@@ -109,11 +108,6 @@ static inline void bpf_fill_ill_insns(void *area, unsigned int size) + memset(area, 0, size); + } + +-static inline void bpf_flush_icache(void *start, void *end) +-{ +- flush_icache_range((unsigned long)start, (unsigned long)end); +-} +- + /* Emit a 4-byte riscv instruction. */ + static inline void emit(const u32 insn, struct rv_jit_context *ctx) + { +diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c +index 6de753c667f42..fe362030ed2a9 100644 +--- a/arch/riscv/net/bpf_jit_core.c ++++ b/arch/riscv/net/bpf_jit_core.c +@@ -184,13 +184,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + prog = orig_prog; + goto out_offset; + } +- /* +- * The instructions have now been copied to the ROX region from +- * where they will execute. +- * Write any modified data cache blocks out to memory and +- * invalidate the corresponding blocks in the instruction cache. +- */ +- bpf_flush_icache(jit_data->ro_header, ctx->ro_insns + ctx->ninsns); + for (i = 0; i < prog->len; i++) + ctx->offset[i] = ninsns_rvoff(ctx->offset[i]); + bpf_prog_fill_jited_linfo(prog, ctx->offset); +-- +2.53.0 + diff --git a/queue-6.12/bpf-sockmap-fix-af_unix-iter-deadlock.patch b/queue-6.12/bpf-sockmap-fix-af_unix-iter-deadlock.patch new file mode 100644 index 0000000000..df4a8fae0b --- /dev/null +++ b/queue-6.12/bpf-sockmap-fix-af_unix-iter-deadlock.patch @@ -0,0 +1,101 @@ +From de13e6396a641dffd0bd48cb828f076abfe9201d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:16 +0200 +Subject: bpf, sockmap: Fix af_unix iter deadlock + +From: Michal Luczaj + +[ Upstream commit 4d328dd695383224aa750ddee6b4ad40c0f8d205 ] + +bpf_iter_unix_seq_show() may deadlock when lock_sock_fast() takes the fast +path and the iter prog attempts to update a sockmap. Which ends up spinning +at sock_map_update_elem()'s bh_lock_sock(): + +WARNING: possible recursive locking detected +test_progs/1393 is trying to acquire lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: sock_map_update_elem+0xdb/0x1f0 + +but task is already holding lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + +other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(slock-AF_UNIX); + lock(slock-AF_UNIX); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + +4 locks held by test_progs/1393: + #0: ffff88814b59c790 (&p->lock){+.+.}-{4:4}, at: bpf_seq_read+0x59/0x10d0 + #1: ffff88811ec25fd8 (sk_lock-AF_UNIX){+.+.}-{0:0}, at: bpf_seq_read+0x42c/0x10d0 + #2: ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + #3: ffffffff85a6a7c0 (rcu_read_lock){....}-{1:3}, at: bpf_iter_run_prog+0x51d/0xb00 + +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_deadlock_bug.cold+0xc0/0xce + __lock_acquire+0x130f/0x2590 + lock_acquire+0x14e/0x2b0 + _raw_spin_lock+0x30/0x40 + sock_map_update_elem+0xdb/0x1f0 + bpf_prog_2d0075e5d9b721cd_dump_unix+0x55/0x4f4 + bpf_iter_run_prog+0x5b9/0xb00 + bpf_iter_unix_seq_show+0x1f7/0x2e0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-2-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index fd7f161e6e396..a796cd648f446 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3621,15 +3621,14 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + struct bpf_prog *prog; + struct sock *sk = v; + uid_t uid; +- bool slow; + int ret; + + if (v == SEQ_START_TOKEN) + return 0; + +- slow = lock_sock_fast(sk); ++ lock_sock(sk); + +- if (unlikely(sk_unhashed(sk))) { ++ if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; + goto unlock; + } +@@ -3639,7 +3638,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: +- unlock_sock_fast(sk, slow); ++ release_sock(sk); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.12/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch b/queue-6.12/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch new file mode 100644 index 0000000000..a2c5d88fe3 --- /dev/null +++ b/queue-6.12/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch @@ -0,0 +1,200 @@ +From a9d3ab6615eab0862a1e2a8d41bd9f083d4841d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:18 +0200 +Subject: bpf, sockmap: Fix af_unix null-ptr-deref in proto update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Luczaj + +[ Upstream commit dca38b7734d2ea00af4818ff3ae836fab33d5d5a ] + +unix_stream_connect() sets sk_state (`WRITE_ONCE(sk->sk_state, +TCP_ESTABLISHED)`) _before_ it assigns a peer (`unix_peer(sk) = newsk`). +sk_state == TCP_ESTABLISHED makes sock_map_sk_state_allowed() believe that +socket is properly set up, which would include having a defined peer. IOW, +there's a window when unix_stream_bpf_update_proto() can be called on +socket which still has unix_peer(sk) == NULL. + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) +sock_map_sk_state_allowed(sk) +... +sk_pair = unix_peer(sk) +sock_hold(sk_pair) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + +BUG: kernel NULL pointer dereference, address: 0000000000000080 +RIP: 0010:unix_stream_bpf_update_proto+0xa0/0x1b0 +Call Trace: + sock_map_link+0x564/0x8b0 + sock_map_update_common+0x6e/0x340 + sock_map_update_elem_sys+0x17d/0x240 + __sys_bpf+0x26db/0x3250 + __x64_sys_bpf+0x21/0x30 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Initial idea was to move peer assignment _before_ the sk_state update[1], +but that involved an additional memory barrier, and changing the hot path +was rejected. +Then a NULL check during proto update in unix_stream_bpf_update_proto() was +considered[2], but the follow-up discussion[3] focused on the root cause, +i.e. sockmap update taking a wrong lock. Or, more specifically, missing +unix_state_lock()[4]. +In the end it was concluded that teaching sockmap about the af_unix locking +would be unnecessarily complex[5]. +Complexity aside, since BPF_PROG_TYPE_SCHED_CLS and BPF_PROG_TYPE_SCHED_ACT +are allowed to update sockmaps, sock_map_update_elem() taking the unix +lock, as it is currently implemented in unix_state_lock(): +spin_lock(&unix_sk(s)->lock), would be problematic. unix_state_lock() taken +in a process context, followed by a softirq-context TC BPF program +attempting to take the same spinlock -- deadlock[6]. +This way we circled back to the peer check idea[2]. + +[1]: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +[2]: https://lore.kernel.org/netdev/20240610174906.32921-1-kuniyu@amazon.com/ +[3]: https://lore.kernel.org/netdev/7603c0e6-cd5b-452b-b710-73b64bd9de26@linux.dev/ +[4]: https://lore.kernel.org/netdev/CAAVpQUA+8GL_j63CaKb8hbxoL21izD58yr1NvhOhU=j+35+3og@mail.gmail.com/ +[5]: https://lore.kernel.org/bpf/CAAVpQUAHijOMext28Gi10dSLuMzGYh+jK61Ujn+fZ-wvcODR2A@mail.gmail.com/ +[6]: https://lore.kernel.org/bpf/dd043c69-4d03-46fe-8325-8f97101435cf@linux.dev/ + +Summary of scenarios where af_unix/stream connect() may race a sockmap +update: + +1. connect() vs. bpf(BPF_MAP_UPDATE_ELEM), i.e. sock_map_update_elem_sys() + + Implemented NULL check is sufficient. Once assigned, socket peer won't + be released until socket fd is released. And that's not an issue because + sock_map_update_elem_sys() bumps fd refcnf. + +2. connect() vs BPF program doing update + + Update restricted per verifier.c:may_update_sockmap() to + + BPF_PROG_TYPE_TRACING/BPF_TRACE_ITER + BPF_PROG_TYPE_SOCK_OPS (bpf_sock_map_update() only) + BPF_PROG_TYPE_SOCKET_FILTER + BPF_PROG_TYPE_SCHED_CLS + BPF_PROG_TYPE_SCHED_ACT + BPF_PROG_TYPE_XDP + BPF_PROG_TYPE_SK_REUSEPORT + BPF_PROG_TYPE_FLOW_DISSECTOR + BPF_PROG_TYPE_SK_LOOKUP + + Plus one more race to consider: + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) + sock_map_sk_state_allowed(sk) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + sk_pair = unix_peer(sk) + if (unlikely(!sk_pair)) + return -EINVAL; + + CPU1 close + ---------- + + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) + // use after free? + sock_hold(sk_pair) + + 2.1 BPF program invoking helper function bpf_sock_map_update() -> + BPF_CALL_4(bpf_sock_map_update(), ...) + + Helper limited to BPF_PROG_TYPE_SOCK_OPS. Nevertheless, a unix sock + might be accessible via bpf_map_lookup_elem(). Which implies sk + already having psock, which in turn implies sk already having + sk_pair. Since sk_psock_destroy() is queued as RCU work, sk_pair + won't go away while BPF executes the update. + + 2.2 BPF program invoking helper function bpf_map_update_elem() -> + sock_map_update_elem() + + 2.2.1 Unix sock accessible to BPF prog only via sockmap lookup in + BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_SK_REUSEPORT, BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_SK_LOOKUP. + + Pretty much the same as case 2.1. + + 2.2.2 Unix sock accessible to BPF program directly: + BPF_PROG_TYPE_TRACING, narrowed down to BPF_TRACE_ITER. + + Sockmap iterator (sock_map_seq_ops) is safe: unix sock + residing in a sockmap means that the sock already went through + the proto update step. + + Unix sock iterator (bpf_iter_unix_seq_ops), on the other hand, + gives access to socks that may still be unconnected. Which + means iterator prog can race sockmap/proto update against + connect(). + + BUG: KASAN: null-ptr-deref in unix_stream_bpf_update_proto+0x253/0x4d0 + Write of size 4 at addr 0000000000000080 by task test_progs/3140 + Call Trace: + dump_stack_lvl+0x5d/0x80 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x253/0x4d0 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + While the introduced NULL check prevents null-ptr-deref in the + BPF program path as well, it is insufficient to guard against + a poorly timed close() leading to a use-after-free. This will + be addressed in a subsequent patch. + +Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()") +Closes: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +Reported-by: Michal Luczaj +Reported-by: 钱一铭 +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-4-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/unix_bpf.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c +index bca2d86ba97d8..976e035053e5a 100644 +--- a/net/unix/unix_bpf.c ++++ b/net/unix/unix_bpf.c +@@ -184,6 +184,9 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r + */ + if (!psock->sk_pair) { + sk_pair = unix_peer(sk); ++ if (unlikely(!sk_pair)) ++ return -EINVAL; ++ + sock_hold(sk_pair); + psock->sk_pair = sk_pair; + } +-- +2.53.0 + diff --git a/queue-6.12/bpf-sockmap-take-state-lock-for-af_unix-iter.patch b/queue-6.12/bpf-sockmap-take-state-lock-for-af_unix-iter.patch new file mode 100644 index 0000000000..f849002814 --- /dev/null +++ b/queue-6.12/bpf-sockmap-take-state-lock-for-af_unix-iter.patch @@ -0,0 +1,115 @@ +From 12ab3036d620eae477bb93ecbb538b889bf7fe71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:19 +0200 +Subject: bpf, sockmap: Take state lock for af_unix iter + +From: Michal Luczaj + +[ Upstream commit 64c2f93fc3254d3bf5de4445fb732ee5c451edb6 ] + +When a BPF iterator program updates a sockmap, there is a race condition in +unix_stream_bpf_update_proto() where the `peer` pointer can become stale[1] +during a state transition TCP_ESTABLISHED -> TCP_CLOSE. + + CPU0 bpf CPU1 close + -------- ---------- +// unix_stream_bpf_update_proto() +sk_pair = unix_peer(sk) +if (unlikely(!sk_pair)) + return -EINVAL; + // unix_release_sock() + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) +sock_hold(sk_pair) // UaF + +More practically, this fix guarantees that the iterator program is +consistently provided with a unix socket that remains stable during +iterator execution. + +[1]: +BUG: KASAN: slab-use-after-free in unix_stream_bpf_update_proto+0x155/0x490 +Write of size 4 at addr ffff8881178c9a00 by task test_progs/2231 +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x170/0x4f3 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x155/0x490 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Allocated by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + __kasan_slab_alloc+0x63/0x80 + kmem_cache_alloc_noprof+0x1d5/0x680 + sk_prot_alloc+0x59/0x210 + sk_alloc+0x34/0x470 + unix_create1+0x86/0x8a0 + unix_stream_connect+0x318/0x15b0 + __sys_connect+0xfd/0x130 + __x64_sys_connect+0x72/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Freed by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + kasan_save_free_info+0x3b/0x70 + __kasan_slab_free+0x47/0x70 + kmem_cache_free+0x11c/0x590 + __sk_destruct+0x432/0x6e0 + unix_release_sock+0x9b3/0xf60 + unix_release+0x8a/0xf0 + __sock_release+0xb0/0x270 + sock_close+0x18/0x20 + __fput+0x36e/0xac0 + fput_close_sync+0xe5/0x1a0 + __x64_sys_close+0x7d/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-5-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index a796cd648f446..77976f36c4aa4 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3627,6 +3627,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + return 0; + + lock_sock(sk); ++ unix_state_lock(sk); + + if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; +@@ -3638,6 +3639,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: ++ unix_state_unlock(sk); + release_sock(sk); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.12/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch b/queue-6.12/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch new file mode 100644 index 0000000000..35896cc9c6 --- /dev/null +++ b/queue-6.12/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch @@ -0,0 +1,199 @@ +From 8cf184736678f14eddee8482604b3486e50b8cdb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:36 -0700 +Subject: bpf: switch task_vma iterator from mmap_lock to per-VMA locks + +From: Puranjay Mohan + +[ Upstream commit bee9ef4a40a277bf401be43d39ba7f7f063cf39c ] + +The open-coded task_vma iterator holds mmap_lock for the entire duration +of iteration, increasing contention on this highly contended lock. + +Switch to per-VMA locking. Find the next VMA via an RCU-protected maple +tree walk and lock it with lock_vma_under_rcu(). lock_next_vma() is not +used because its fallback takes mmap_read_lock(), and the iterator must +work in non-sleepable contexts. + +lock_vma_under_rcu() is a point lookup (mas_walk) that finds the VMA +containing a given address but cannot iterate across gaps. An +RCU-protected vma_next() walk (mas_find) first locates the next VMA's +vm_start to pass to lock_vma_under_rcu(). + +Between the RCU walk and the lock, the VMA may be removed, shrunk, or +write-locked. On failure, advance past it using vm_end from the RCU +walk. Because the VMA slab is SLAB_TYPESAFE_BY_RCU, vm_end may be +stale; fall back to PAGE_SIZE advancement when it does not make forward +progress. Concurrent VMA insertions at addresses already passed by the +iterator are not detected. + +CONFIG_PER_VMA_LOCK is required; return -EOPNOTSUPP without it. + +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260408154539.3832150-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Stable-dep-of: 4cbee026db54 ("bpf: return VMA snapshot from task_vma iterator") +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 91 +++++++++++++++++++++++++++++++++--------- + 1 file changed, 73 insertions(+), 18 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index c37ae44bd0a53..aee03c55602a0 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include "mmap_unlock_work.h" + +@@ -811,8 +812,8 @@ static inline void bpf_iter_mmput_async(struct mm_struct *mm) + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +- struct mmap_unlock_irq_work *work; +- struct vma_iterator vmi; ++ struct vm_area_struct *locked_vma; ++ u64 next_addr; + }; + + struct bpf_iter_task_vma { +@@ -833,21 +834,19 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + struct task_struct *task, u64 addr) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; +- bool irq_work_busy = false; + int err; + + BUILD_BUG_ON(sizeof(struct bpf_iter_task_vma_kern) != sizeof(struct bpf_iter_task_vma)); + BUILD_BUG_ON(__alignof__(struct bpf_iter_task_vma_kern) != __alignof__(struct bpf_iter_task_vma)); + +- /* bpf_iter_mmput_async() needs mmput_async() which requires CONFIG_MMU */ +- if (!IS_ENABLED(CONFIG_MMU)) { ++ if (!IS_ENABLED(CONFIG_PER_VMA_LOCK)) { + kit->data = NULL; + return -EOPNOTSUPP; + } + + /* + * Reject irqs-disabled contexts including NMI. Operations used +- * by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) ++ * by _next() and _destroy() (vma_end_read, bpf_iter_mmput_async) + * can take spinlocks with IRQs disabled (pi_lock, pool->lock). + * Running from NMI or from a tracepoint that fires with those + * locks held could deadlock. +@@ -890,18 +889,10 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + goto err_cleanup_iter; + } + +- /* kit->data->work == NULL is valid after bpf_mmap_unlock_get_irq_work */ +- irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work); +- if (irq_work_busy || !mmap_read_trylock(kit->data->mm)) { +- err = -EBUSY; +- goto err_cleanup_mmget; +- } +- +- vma_iter_init(&kit->data->vmi, kit->data->mm, addr); ++ kit->data->locked_vma = NULL; ++ kit->data->next_addr = addr; + return 0; + +-err_cleanup_mmget: +- bpf_iter_mmput_async(kit->data->mm); + err_cleanup_iter: + put_task_struct(kit->data->task); + bpf_mem_free(&bpf_global_ma, kit->data); +@@ -910,13 +901,76 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + return err; + } + ++/* ++ * Find and lock the next VMA at or after data->next_addr. ++ * ++ * lock_vma_under_rcu() is a point lookup (mas_walk): it finds the VMA ++ * containing a given address but cannot iterate. An RCU-protected ++ * maple tree walk with vma_next() (mas_find) is needed first to locate ++ * the next VMA's vm_start across any gap. ++ * ++ * Between the RCU walk and the lock, the VMA may be removed, shrunk, ++ * or write-locked. On failure, advance past it using vm_end from the ++ * RCU walk. SLAB_TYPESAFE_BY_RCU can make vm_end stale, so fall back ++ * to PAGE_SIZE advancement to guarantee forward progress. ++ */ ++static struct vm_area_struct * ++bpf_iter_task_vma_find_next(struct bpf_iter_task_vma_kern_data *data) ++{ ++ struct vm_area_struct *vma; ++ struct vma_iterator vmi; ++ unsigned long start, end; ++ ++retry: ++ rcu_read_lock(); ++ vma_iter_init(&vmi, data->mm, data->next_addr); ++ vma = vma_next(&vmi); ++ if (!vma) { ++ rcu_read_unlock(); ++ return NULL; ++ } ++ start = vma->vm_start; ++ end = vma->vm_end; ++ rcu_read_unlock(); ++ ++ vma = lock_vma_under_rcu(data->mm, start); ++ if (!vma) { ++ if (end <= data->next_addr) ++ data->next_addr += PAGE_SIZE; ++ else ++ data->next_addr = end; ++ goto retry; ++ } ++ ++ if (unlikely(vma->vm_end <= data->next_addr)) { ++ data->next_addr += PAGE_SIZE; ++ vma_end_read(vma); ++ goto retry; ++ } ++ ++ return vma; ++} ++ + __bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; ++ struct vm_area_struct *vma; + + if (!kit->data) /* bpf_iter_task_vma_new failed */ + return NULL; +- return vma_next(&kit->data->vmi); ++ ++ if (kit->data->locked_vma) { ++ vma_end_read(kit->data->locked_vma); ++ kit->data->locked_vma = NULL; ++ } ++ ++ vma = bpf_iter_task_vma_find_next(kit->data); ++ if (!vma) ++ return NULL; ++ ++ kit->data->locked_vma = vma; ++ kit->data->next_addr = vma->vm_end; ++ return vma; + } + + __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) +@@ -924,7 +978,8 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + struct bpf_iter_task_vma_kern *kit = (void *)it; + + if (kit->data) { +- bpf_mmap_unlock_mm(kit->data->work, kit->data->mm); ++ if (kit->data->locked_vma) ++ vma_end_read(kit->data->locked_vma); + put_task_struct(kit->data->task); + bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); +-- +2.53.0 + diff --git a/queue-6.12/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch b/queue-6.12/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch new file mode 100644 index 0000000000..df5071a61b --- /dev/null +++ b/queue-6.12/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch @@ -0,0 +1,100 @@ +From c5ff8e9811a7cd21461bc4dba03ee0d899c6bcb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 17:44:28 +0800 +Subject: bpf: test_run: Fix the null pointer dereference issue in + bpf_lwt_xmit_push_encap + +From: Feng Yang + +[ Upstream commit 972787479ee73006fddb5e59ab5c8e733810ff42 ] + +The bpf_lwt_xmit_push_encap helper needs to access skb_dst(skb)->dev to +calculate the needed headroom: + + err = skb_cow_head(skb, + len + LL_RESERVED_SPACE(skb_dst(skb)->dev)); + +But skb->_skb_refdst may not be initialized when the skb is set up by +bpf_prog_test_run_skb function. Executing bpf_lwt_push_ip_encap function +in this scenario will trigger null pointer dereference, causing a kernel +crash as Yinhao reported: + +[ 105.186365] BUG: kernel NULL pointer dereference, address: 0000000000000000 +[ 105.186382] #PF: supervisor read access in kernel mode +[ 105.186388] #PF: error_code(0x0000) - not-present page +[ 105.186393] PGD 121d3d067 P4D 121d3d067 PUD 106c83067 PMD 0 +[ 105.186404] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 105.186412] CPU: 3 PID: 3250 Comm: poc Kdump: loaded Not tainted 6.19.0-rc5 #1 +[ 105.186423] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 105.186427] RIP: 0010:bpf_lwt_push_ip_encap+0x1eb/0x520 +[ 105.186443] Code: 0f 84 de 01 00 00 0f b7 4a 04 66 85 c9 0f 85 47 01 00 00 31 c0 5b 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8b 73 58 48 83 e6 fe <48> 8b 36 0f b7 be ec 00 00 00 0f b7 b6 e6 00 00 00 01 fe 83 e6 f0 +[ 105.186449] RSP: 0018:ffffbb0e0387bc50 EFLAGS: 00010246 +[ 105.186455] RAX: 000000000000004e RBX: ffff94c74e036500 RCX: ffff94c74874da00 +[ 105.186460] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff94c74e036500 +[ 105.186463] RBP: 0000000000000001 R08: 0000000000000002 R09: 0000000000000000 +[ 105.186467] R10: ffffbb0e0387bd50 R11: 0000000000000000 R12: ffffbb0e0387bc98 +[ 105.186471] R13: 0000000000000014 R14: 0000000000000000 R15: 0000000000000002 +[ 105.186484] FS: 00007f166aa4d680(0000) GS:ffff94c8b7780000(0000) knlGS:0000000000000000 +[ 105.186490] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 105.186494] CR2: 0000000000000000 CR3: 000000015eade001 CR4: 0000000000770ee0 +[ 105.186499] PKRU: 55555554 +[ 105.186502] Call Trace: +[ 105.186507] +[ 105.186513] bpf_lwt_xmit_push_encap+0x2b/0x40 +[ 105.186522] bpf_prog_a75eaad51e517912+0x41/0x49 +[ 105.186536] ? kvm_clock_get_cycles+0x18/0x30 +[ 105.186547] ? ktime_get+0x3c/0xa0 +[ 105.186554] bpf_test_run+0x195/0x320 +[ 105.186563] ? bpf_test_run+0x10f/0x320 +[ 105.186579] bpf_prog_test_run_skb+0x2f5/0x4f0 +[ 105.186590] __sys_bpf+0x69c/0xa40 +[ 105.186603] __x64_sys_bpf+0x1e/0x30 +[ 105.186611] do_syscall_64+0x59/0x110 +[ 105.186620] entry_SYSCALL_64_after_hwframe+0x76/0xe0 +[ 105.186649] RIP: 0033:0x7f166a97455d + +Temporarily add the setting of skb->_skb_refdst before bpf_test_run to resolve the issue. + +Fixes: 52f278774e79 ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap") +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Closes: https://groups.google.com/g/hust-os-kernel-patches/c/8-a0kPpBW2s +Signed-off-by: Yun Lu +Signed-off-by: Feng Yang +Signed-off-by: Martin KaFai Lau +Tested-by: syzbot@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260304094429.168521-2-yangfeng59949@163.com +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index c885a3942a161..18257cf6bb488 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1097,6 +1097,21 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + skb->ip_summed = CHECKSUM_COMPLETE; + } + ++ if (prog->type == BPF_PROG_TYPE_LWT_XMIT) { ++ if (!ipv6_bpf_stub) { ++ pr_warn_once("Please test this program with the IPv6 module loaded\n"); ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ /* For CONFIG_IPV6=n, ipv6_bpf_stub is NULL which is ++ * handled by the above if statement. ++ */ ++ dst_hold(&net->ipv6.ip6_null_entry->dst); ++ skb_dst_set(skb, &net->ipv6.ip6_null_entry->dst); ++#endif ++ } ++ + ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false); + if (ret) + goto out; +-- +2.53.0 + diff --git a/queue-6.12/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch b/queue-6.12/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch new file mode 100644 index 0000000000..997fbc2086 --- /dev/null +++ b/queue-6.12/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch @@ -0,0 +1,71 @@ +From b1f0d65c78602b145bb1fdf65486c64b922a074d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 07:26:45 +0000 +Subject: bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path + +From: David Carlier + +[ Upstream commit 8ed82f807bb09d2c8455aaa665f2c6cb17bc6a19 ] + +The DEVMAP_HASH branch in dev_map_redirect_multi() uses +hlist_for_each_entry_safe() to iterate hash buckets, but this function +runs under RCU protection (called from xdp_do_generic_redirect_map() +in softirq context). Concurrent writers (__dev_map_hash_update_elem, +dev_map_hash_delete_elem) modify the list using RCU primitives +(hlist_add_head_rcu, hlist_del_rcu). + +hlist_for_each_entry_safe() performs plain pointer dereferences without +rcu_dereference(), missing the acquire barrier needed to pair with +writers' rcu_assign_pointer(). On weakly-ordered architectures (ARM64, +POWER), a reader can observe a partially-constructed node. It also +defeats CONFIG_PROVE_RCU lockdep validation and KCSAN data-race +detection. + +Replace with hlist_for_each_entry_rcu() using rcu_read_lock_bh_held() +as the lockdep condition, consistent with the rcu_dereference_check() +used in the DEVMAP (non-hash) branch of the same functions. Also fix +the same incorrect lockdep_is_held(&dtab->index_lock) condition in +dev_map_enqueue_multi(), where the lock is not held either. + +Fixes: e624d4ed4aa8 ("xdp: Extend xdp_redirect_map with broadcast support") +Signed-off-by: David Carlier +Signed-off-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260320072645.16731-1-devnexen@gmail.com +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 39b7efa396b8e..17f8c9d6e95cc 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -653,7 +653,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_rcu(dst, head, index_hlist, +- lockdep_is_held(&dtab->index_lock)) { ++ rcu_read_lock_bh_held()) { + if (!is_valid_dst(dst, xdpf)) + continue; + +@@ -735,7 +735,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + struct bpf_dtab_netdev *dst, *last_dst = NULL; + int excluded_devices[1+MAX_NEST_DEV]; + struct hlist_head *head; +- struct hlist_node *next; + int num_excluded = 0; + unsigned int i; + int err; +@@ -775,7 +774,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + } else { /* BPF_MAP_TYPE_DEVMAP_HASH */ + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); +- hlist_for_each_entry_safe(dst, next, head, index_hlist) { ++ hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) { + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-6.12/bpf-validate-node_id-in-arena_alloc_pages.patch b/queue-6.12/bpf-validate-node_id-in-arena_alloc_pages.patch new file mode 100644 index 0000000000..d6dbdd4526 --- /dev/null +++ b/queue-6.12/bpf-validate-node_id-in-arena_alloc_pages.patch @@ -0,0 +1,43 @@ +From 2dd57489acdd54d6000ce904feaea2e1e550f5c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 08:21:33 -0700 +Subject: bpf: Validate node_id in arena_alloc_pages() + +From: Puranjay Mohan + +[ Upstream commit 2845989f2ebaf7848e4eccf9a779daf3156ea0a5 ] + +arena_alloc_pages() accepts a plain int node_id and forwards it through +the entire allocation chain without any bounds checking. + +Validate node_id before passing it down the allocation chain in +arena_alloc_pages(). + +Fixes: 317460317a02 ("bpf: Introduce bpf_arena.") +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417152135.1383754-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/arena.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c +index 4ce6786d39351..187e4871b74b3 100644 +--- a/kernel/bpf/arena.c ++++ b/kernel/bpf/arena.c +@@ -438,6 +438,10 @@ static long arena_alloc_pages(struct bpf_arena *arena, long uaddr, long page_cnt + u32 uaddr32; + int ret, i; + ++ if (node_id != NUMA_NO_NODE && ++ ((unsigned int)node_id >= nr_node_ids || !node_online(node_id))) ++ return 0; ++ + if (page_cnt > page_cnt_max) + return 0; + +-- +2.53.0 + diff --git a/queue-6.12/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch b/queue-6.12/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch new file mode 100644 index 0000000000..c4bb16e05f --- /dev/null +++ b/queue-6.12/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch @@ -0,0 +1,216 @@ +From e4cd5401815140a4df2729ceb7120234974b0957 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 15:50:13 +0000 +Subject: btrfs: fix deadlock between reflink and transaction commit when using + flushoncommit + +From: Filipe Manana + +[ Upstream commit b48c980b6a7e409050bb3067165db31cc6205e3e ] + +When using the flushoncommit mount option, we can have a deadlock between +a transaction commit and a reflink operation that copied an inline extent +to an offset beyond the current i_size of the destination node. + +The deadlock happens like this: + +1) Task A clones an inline extent from inode X to an offset of inode Y + that is beyond Y's current i_size. This means we copied the inline + extent's data to a folio of inode Y that is beyond its EOF, using a + call to copy_inline_to_page(); + +2) Task B starts a transaction commit and calls + btrfs_start_delalloc_flush() to flush delalloc; + +3) The delalloc flushing sees the new dirty folio of inode Y and when it + attempts to flush it, it ends up at extent_writepage() and sees that + the offset of the folio is beyond the i_size of inode Y, so it attempts + to invalidate the folio by calling folio_invalidate(), which ends up at + btrfs' folio invalidate callback - btrfs_invalidate_folio(). There it + tries to lock the folio's range in inode Y's extent io tree, but it + blocks since it's currently locked by task A - during a reflink we lock + the inodes and the source and destination ranges after flushing all + delalloc and waiting for ordered extent completion - after that we + don't expect to have dirty folios in the ranges, the exception is if + we have to copy an inline extent's data (because the destination offset + is not zero); + +4) Task A then attempts to start a transaction to update the inode item, + and then it's blocked since the current transaction is in the + TRANS_STATE_COMMIT_START state. Therefore task A has to wait for the + current transaction to become unblocked (its state >= + TRANS_STATE_UNBLOCKED). + + So task A is waiting for the transaction commit done by task B, and + the later waiting on the extent lock of inode Y that is currently + held by task A. + +Syzbot recently reported this with the following stack traces: + + INFO: task kworker/u8:7:1053 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:kworker/u8:7 state:D stack:23520 pid:1053 tgid:1053 ppid:2 task_flags:0x4208060 flags:0x00080000 + Workqueue: writeback wb_workfn (flush-btrfs-46) + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wait_extent_bit fs/btrfs/extent-io-tree.c:811 [inline] + btrfs_lock_extent_bits+0x59c/0x700 fs/btrfs/extent-io-tree.c:1914 + btrfs_lock_extent fs/btrfs/extent-io-tree.h:152 [inline] + btrfs_invalidate_folio+0x43d/0xc40 fs/btrfs/inode.c:7704 + extent_writepage fs/btrfs/extent_io.c:1852 [inline] + extent_write_cache_pages fs/btrfs/extent_io.c:2580 [inline] + btrfs_writepages+0x12ff/0x2440 fs/btrfs/extent_io.c:2713 + do_writepages+0x32e/0x550 mm/page-writeback.c:2554 + __writeback_single_inode+0x133/0x11a0 fs/fs-writeback.c:1750 + writeback_sb_inodes+0x995/0x19d0 fs/fs-writeback.c:2042 + wb_writeback+0x456/0xb70 fs/fs-writeback.c:2227 + wb_do_writeback fs/fs-writeback.c:2374 [inline] + wb_workfn+0x41a/0xf60 fs/fs-writeback.c:2414 + process_one_work kernel/workqueue.c:3276 [inline] + process_scheduled_works+0xb6e/0x18c0 kernel/workqueue.c:3359 + worker_thread+0xa53/0xfc0 kernel/workqueue.c:3440 + kthread+0x388/0x470 kernel/kthread.c:436 + ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + + INFO: task syz.4.64:6910 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:syz.4.64 state:D stack:22752 pid:6910 tgid:6905 ppid:5944 task_flags:0x400140 flags:0x00080002 + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wait_current_trans+0x39f/0x590 fs/btrfs/transaction.c:535 + start_transaction+0x6a7/0x1650 fs/btrfs/transaction.c:705 + clone_copy_inline_extent fs/btrfs/reflink.c:299 [inline] + btrfs_clone+0x128a/0x24d0 fs/btrfs/reflink.c:529 + btrfs_clone_files+0x271/0x3f0 fs/btrfs/reflink.c:750 + btrfs_remap_file_range+0x76b/0x1320 fs/btrfs/reflink.c:903 + vfs_copy_file_range+0xda7/0x1390 fs/read_write.c:1600 + __do_sys_copy_file_range fs/read_write.c:1683 [inline] + __se_sys_copy_file_range+0x2fb/0x480 fs/read_write.c:1650 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7f5f73afc799 + RSP: 002b:00007f5f7315e028 EFLAGS: 00000246 ORIG_RAX: 0000000000000146 + RAX: ffffffffffffffda RBX: 00007f5f73d75fa0 RCX: 00007f5f73afc799 + RDX: 0000000000000005 RSI: 0000000000000000 RDI: 0000000000000005 + RBP: 00007f5f73b92c99 R08: 0000000000000863 R09: 0000000000000000 + R10: 00002000000000c0 R11: 0000000000000246 R12: 0000000000000000 + R13: 00007f5f73d76038 R14: 00007f5f73d75fa0 R15: 00007fff138a5068 + + INFO: task syz.4.64:6975 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:syz.4.64 state:D stack:24736 pid:6975 tgid:6905 ppid:5944 task_flags:0x400040 flags:0x00080002 + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wb_wait_for_completion+0x3e8/0x790 fs/fs-writeback.c:227 + __writeback_inodes_sb_nr+0x24c/0x2d0 fs/fs-writeback.c:2838 + try_to_writeback_inodes_sb+0x9a/0xc0 fs/fs-writeback.c:2886 + btrfs_start_delalloc_flush fs/btrfs/transaction.c:2175 [inline] + btrfs_commit_transaction+0x82e/0x31a0 fs/btrfs/transaction.c:2364 + btrfs_ioctl+0xca7/0xd00 fs/btrfs/ioctl.c:5206 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7f5f73afc799 + RSP: 002b:00007f5f7313d028 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 + RAX: ffffffffffffffda RBX: 00007f5f73d76090 RCX: 00007f5f73afc799 + RDX: 0000000000000000 RSI: 0000000000009408 RDI: 0000000000000004 + RBP: 00007f5f73b92c99 R08: 0000000000000000 R09: 0000000000000000 + R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 + R13: 00007f5f73d76128 R14: 00007f5f73d76090 R15: 00007fff138a5068 + + +Fix this by updating the i_size of the destination inode of a reflink +operation after we copy an inline extent's data to an offset beyond the +i_size and before attempting to start a transaction to update the inode's +item. + +Reported-by: syzbot+63056bf627663701bbbf@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-btrfs/69bba3fe.050a0220.227207.002f.GAE@google.com/ +Fixes: 05a5a7621ce6 ("Btrfs: implement full reflink support for inline extents") +Reviewed-by: Boris Burkov +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/reflink.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c +index 8640dbf1aefa4..e86df9c83aba5 100644 +--- a/fs/btrfs/reflink.c ++++ b/fs/btrfs/reflink.c +@@ -320,6 +320,51 @@ static int clone_copy_inline_extent(struct btrfs_inode *inode, + + ret = copy_inline_to_page(inode, new_key->offset, + inline_data, size, datal, comp_type); ++ ++ /* ++ * If we copied the inline extent data to a page/folio beyond the i_size ++ * of the destination inode, then we need to increase the i_size before ++ * we start a transaction to update the inode item. This is to prevent a ++ * deadlock when the flushoncommit mount option is used, which happens ++ * like this: ++ * ++ * 1) Task A clones an inline extent from inode X to an offset of inode ++ * Y that is beyond Y's current i_size. This means we copied the ++ * inline extent's data to a folio of inode Y that is beyond its EOF, ++ * using the call above to copy_inline_to_page(); ++ * ++ * 2) Task B starts a transaction commit and calls ++ * btrfs_start_delalloc_flush() to flush delalloc; ++ * ++ * 3) The delalloc flushing sees the new dirty folio of inode Y and when ++ * it attempts to flush it, it ends up at extent_writepage() and sees ++ * that the offset of the folio is beyond the i_size of inode Y, so ++ * it attempts to invalidate the folio by calling folio_invalidate(), ++ * which ends up at btrfs' folio invalidate callback - ++ * btrfs_invalidate_folio(). There it tries to lock the folio's range ++ * in inode Y's extent io tree, but it blocks since it's currently ++ * locked by task A - during reflink we lock the inodes and the ++ * source and destination ranges after flushing all delalloc and ++ * waiting for ordered extent completion - after that we don't expect ++ * to have dirty folios in the ranges, the exception is if we have to ++ * copy an inline extent's data (because the destination offset is ++ * not zero); ++ * ++ * 4) Task A then does the 'goto out' below and attempts to start a ++ * transaction to update the inode item, and then it's blocked since ++ * the current transaction is in the TRANS_STATE_COMMIT_START state. ++ * Therefore task A has to wait for the current transaction to become ++ * unblocked (its state >= TRANS_STATE_UNBLOCKED). ++ * ++ * This leads to a deadlock - the task committing the transaction ++ * waiting for the delalloc flushing which is blocked during folio ++ * invalidation on the inode's extent lock and the reflink task waiting ++ * for the current transaction to be unblocked so that it can start a ++ * a new one to update the inode item (while holding the extent lock). ++ */ ++ if (ret == 0 && new_key->offset + datal > i_size_read(&inode->vfs_inode)) ++ i_size_write(&inode->vfs_inode, new_key->offset + datal); ++ + goto out; + } + +-- +2.53.0 + diff --git a/queue-6.12/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch b/queue-6.12/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch new file mode 100644 index 0000000000..ae523c0f5f --- /dev/null +++ b/queue-6.12/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch @@ -0,0 +1,48 @@ +From 37acaa7f3737724b4b87095a366179f70446c307 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:15:23 +0100 +Subject: btrfs: fix double-decrement of bytes_may_use in + submit_one_async_extent() + +From: Mark Harmstone + +[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ] + +submit_one_async_extent() calls btrfs_reserve_extent(), which decrements +bytes_may_use. If the call btrfs_create_io_em() fails, we jump to +out_free_reserve, which calls extent_clear_unlock_delalloc(). + +Because we're specifying EXTENT_DO_ACCOUNTING, i.e. +EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases +bytes_may_use again. This can lead to problems later on, as an initial +write can fail only for the writeback to silently ENOSPC. + +Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. +This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved +extents in cow_one_range()"), which is the same fix in cow_one_range(). + +Fixes: 151a41bc46df ("Btrfs: fix what bits we clear when erroring out from delalloc") +Reviewed-by: Qu Wenruo +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 28024c827b756..3e39692e36913 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1288,7 +1288,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk, + NULL, &cached, + EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | +- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, ++ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, + PAGE_UNLOCK | PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK); + free_async_extent_pages(async_extent); +-- +2.53.0 + diff --git a/queue-6.12/btrfs-pass-struct-btrfs_inode-to-clone_copy_inline_e.patch b/queue-6.12/btrfs-pass-struct-btrfs_inode-to-clone_copy_inline_e.patch new file mode 100644 index 0000000000..7803f026a5 --- /dev/null +++ b/queue-6.12/btrfs-pass-struct-btrfs_inode-to-clone_copy_inline_e.patch @@ -0,0 +1,129 @@ +From 4a323efa38f741f92898c97bcac759105940a768 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Feb 2025 01:31:38 +0100 +Subject: btrfs: pass struct btrfs_inode to clone_copy_inline_extent() + +From: David Sterba + +[ Upstream commit 65a66afd1ee5b2770fde296663baa0f79af56bc7 ] + +Pass a struct btrfs_inode to clone_copy_inline_extent() as it's an +internal interface, allowing to remove some use of BTRFS_I. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: David Sterba +Stable-dep-of: b48c980b6a7e ("btrfs: fix deadlock between reflink and transaction commit when using flushoncommit") +Signed-off-by: Sasha Levin +--- + fs/btrfs/reflink.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c +index f0824c948cb70..8640dbf1aefa4 100644 +--- a/fs/btrfs/reflink.c ++++ b/fs/btrfs/reflink.c +@@ -165,7 +165,7 @@ static int copy_inline_to_page(struct btrfs_inode *inode, + * the source inode to destination inode when possible. When not possible we + * copy the inline extent's data into the respective page of the inode. + */ +-static int clone_copy_inline_extent(struct inode *dst, ++static int clone_copy_inline_extent(struct btrfs_inode *inode, + struct btrfs_path *path, + struct btrfs_key *new_key, + const u64 drop_start, +@@ -175,8 +175,8 @@ static int clone_copy_inline_extent(struct inode *dst, + char *inline_data, + struct btrfs_trans_handle **trans_out) + { +- struct btrfs_fs_info *fs_info = inode_to_fs_info(dst); +- struct btrfs_root *root = BTRFS_I(dst)->root; ++ struct btrfs_root *root = inode->root; ++ struct btrfs_fs_info *fs_info = root->fs_info; + const u64 aligned_end = ALIGN(new_key->offset + datal, + fs_info->sectorsize); + struct btrfs_trans_handle *trans = NULL; +@@ -185,12 +185,12 @@ static int clone_copy_inline_extent(struct inode *dst, + struct btrfs_key key; + + if (new_key->offset > 0) { +- ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset, ++ ret = copy_inline_to_page(inode, new_key->offset, + inline_data, size, datal, comp_type); + goto out; + } + +- key.objectid = btrfs_ino(BTRFS_I(dst)); ++ key.objectid = btrfs_ino(inode); + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = 0; + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); +@@ -205,7 +205,7 @@ static int clone_copy_inline_extent(struct inode *dst, + goto copy_inline_extent; + } + btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); +- if (key.objectid == btrfs_ino(BTRFS_I(dst)) && ++ if (key.objectid == btrfs_ino(inode) && + key.type == BTRFS_EXTENT_DATA_KEY) { + /* + * There's an implicit hole at file offset 0, copy the +@@ -214,7 +214,7 @@ static int clone_copy_inline_extent(struct inode *dst, + ASSERT(key.offset > 0); + goto copy_to_page; + } +- } else if (i_size_read(dst) <= datal) { ++ } else if (i_size_read(&inode->vfs_inode) <= datal) { + struct btrfs_file_extent_item *ei; + + ei = btrfs_item_ptr(path->nodes[0], path->slots[0], +@@ -236,7 +236,7 @@ static int clone_copy_inline_extent(struct inode *dst, + * We have no extent items, or we have an extent at offset 0 which may + * or may not be inlined. All these cases are dealt the same way. + */ +- if (i_size_read(dst) > datal) { ++ if (i_size_read(&inode->vfs_inode) > datal) { + /* + * At the destination offset 0 we have either a hole, a regular + * extent or an inline extent larger then the one we want to +@@ -270,7 +270,7 @@ static int clone_copy_inline_extent(struct inode *dst, + drop_args.start = drop_start; + drop_args.end = aligned_end; + drop_args.drop_cache = true; +- ret = btrfs_drop_extents(trans, root, BTRFS_I(dst), &drop_args); ++ ret = btrfs_drop_extents(trans, root, inode, &drop_args); + if (ret) + goto out; + ret = btrfs_insert_empty_item(trans, root, path, new_key, size); +@@ -281,9 +281,9 @@ static int clone_copy_inline_extent(struct inode *dst, + btrfs_item_ptr_offset(path->nodes[0], + path->slots[0]), + size); +- btrfs_update_inode_bytes(BTRFS_I(dst), datal, drop_args.bytes_found); +- btrfs_set_inode_full_sync(BTRFS_I(dst)); +- ret = btrfs_inode_set_file_extent_range(BTRFS_I(dst), 0, aligned_end); ++ btrfs_update_inode_bytes(inode, datal, drop_args.bytes_found); ++ btrfs_set_inode_full_sync(inode); ++ ret = btrfs_inode_set_file_extent_range(inode, 0, aligned_end); + out: + if (!ret && !trans) { + /* +@@ -318,7 +318,7 @@ static int clone_copy_inline_extent(struct inode *dst, + */ + btrfs_release_path(path); + +- ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset, ++ ret = copy_inline_to_page(inode, new_key->offset, + inline_data, size, datal, comp_type); + goto out; + } +@@ -526,7 +526,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, + goto out; + } + +- ret = clone_copy_inline_extent(inode, path, &new_key, ++ ret = clone_copy_inline_extent(BTRFS_I(inode), path, &new_key, + drop_start, datal, size, + comp, buf, &trans); + if (ret) +-- +2.53.0 + diff --git a/queue-6.12/bus-fsl-mc-use-generic-driver_override-infrastructur.patch b/queue-6.12/bus-fsl-mc-use-generic-driver_override-infrastructur.patch new file mode 100644 index 0000000000..526604f428 --- /dev/null +++ b/queue-6.12/bus-fsl-mc-use-generic-driver_override-infrastructur.patch @@ -0,0 +1,156 @@ +From b0a4a3c29f8a9ae610fbb003425f695bcf9658bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:06 +0100 +Subject: bus: fsl-mc: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit 6c8dfb0362732bf1e4829867a2a5239fedc592d0 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Tested-by: Ioana Ciornei +Acked-by: Ioana Ciornei +Acked-by: Christophe Leroy (CS GROUP) +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 1f86a00c1159 ("bus/fsl-mc: add support for 'driver_override' in the mc-bus") +Link: https://patch.msgid.link/20260324005919.2408620-3-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/bus/fsl-mc/fsl-mc-bus.c | 43 +++++-------------------------- + drivers/vfio/fsl-mc/vfio_fsl_mc.c | 4 +-- + include/linux/fsl/mc.h | 4 --- + 3 files changed, 8 insertions(+), 43 deletions(-) + +diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c +index 5543ba93e5017..2810f3b6e2f6c 100644 +--- a/drivers/bus/fsl-mc/fsl-mc-bus.c ++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c +@@ -86,12 +86,16 @@ static int fsl_mc_bus_match(struct device *dev, const struct device_driver *drv) + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); + const struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); + bool found = false; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (mc_dev->driver_override) { +- found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); ++ ret = device_match_driver_override(dev, drv); ++ if (ret > 0) { ++ found = true; + goto out; + } ++ if (ret == 0) ++ goto out; + + if (!mc_drv->match_id_table) + goto out; +@@ -180,39 +184,8 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + } + static DEVICE_ATTR_RO(modalias); + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- int ret; +- +- if (WARN_ON(dev->bus != &fsl_mc_bus_type)) +- return -EINVAL; +- +- ret = driver_set_override(dev, &mc_dev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", mc_dev->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *fsl_mc_dev_attrs[] = { + &dev_attr_modalias.attr, +- &dev_attr_driver_override.attr, + NULL, + }; + +@@ -315,6 +288,7 @@ ATTRIBUTE_GROUPS(fsl_mc_bus); + + const struct bus_type fsl_mc_bus_type = { + .name = "fsl-mc", ++ .driver_override = true, + .match = fsl_mc_bus_match, + .uevent = fsl_mc_bus_uevent, + .dma_configure = fsl_mc_dma_configure, +@@ -924,9 +898,6 @@ static struct notifier_block fsl_mc_nb; + */ + void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) + { +- kfree(mc_dev->driver_override); +- mc_dev->driver_override = NULL; +- + /* + * The device-specific remove callback will get invoked by device_del() + */ +diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c +index f65d91c01f2ec..03600872c4809 100644 +--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c ++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c +@@ -430,9 +430,7 @@ static int vfio_fsl_mc_bus_notifier(struct notifier_block *nb, + + if (action == BUS_NOTIFY_ADD_DEVICE && + vdev->mc_dev == mc_cont) { +- mc_dev->driver_override = kasprintf(GFP_KERNEL, "%s", +- vfio_fsl_mc_ops.name); +- if (!mc_dev->driver_override) ++ if (device_set_driver_override(dev, vfio_fsl_mc_ops.name)) + dev_warn(dev, "VFIO_FSL_MC: Setting driver override for device in dprc %s failed\n", + dev_name(&mc_cont->dev)); + else +diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h +index c90ec889bfc26..b5f64a9046891 100644 +--- a/include/linux/fsl/mc.h ++++ b/include/linux/fsl/mc.h +@@ -178,9 +178,6 @@ struct fsl_mc_obj_desc { + * @regions: pointer to array of MMIO region entries + * @irqs: pointer to array of pointers to interrupts allocated to this device + * @resource: generic resource associated with this MC object device, if any. +- * @driver_override: driver name to force a match; do not set directly, +- * because core frees it; use driver_set_override() to +- * set or clear it. + * + * Generic device object for MC object devices that are "attached" to a + * MC bus. +@@ -214,7 +211,6 @@ struct fsl_mc_device { + struct fsl_mc_device_irq **irqs; + struct fsl_mc_resource *resource; + struct device_link *consumer_link; +- const char *driver_override; + }; + + #define to_fsl_mc_device(_dev) \ +-- +2.53.0 + diff --git a/queue-6.12/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch b/queue-6.12/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch new file mode 100644 index 0000000000..daab089582 --- /dev/null +++ b/queue-6.12/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch @@ -0,0 +1,102 @@ +From 0b7495f6c57529a548b3f20f743998298ab409e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 13:56:17 +0100 +Subject: bus: rifsc: fix RIF configuration check for peripherals + +From: Gatien Chevallier + +[ Upstream commit d5ce3b4e951bc41a6ce877c8500bb4fe42146669 ] + +Peripheral holding CID0 cannot be accessed, remove this completely +incorrect check. While there, fix and simplify the semaphore checking +that should be performed when the CID filtering is enabled. + +Fixes: a18208457253 ("bus: rifsc: introduce RIFSC firewall controller driver") +Signed-off-by: Gatien Chevallier +Link: https://lore.kernel.org/r/20260129-fix_cid_check_rifsc-v1-1-ef280ccf764d@foss.st.com +Signed-off-by: Alexandre Torgue +Signed-off-by: Sasha Levin +--- + drivers/bus/stm32_rifsc.c | 52 ++++++++++++++------------------------- + 1 file changed, 18 insertions(+), 34 deletions(-) + +diff --git a/drivers/bus/stm32_rifsc.c b/drivers/bus/stm32_rifsc.c +index 4cf1b60014b77..59872134c3224 100644 +--- a/drivers/bus/stm32_rifsc.c ++++ b/drivers/bus/stm32_rifsc.c +@@ -126,34 +126,6 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 + sec_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id); + cid_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * firewall_id); + +- /* First check conditions for semaphore mode, which doesn't take into account static CID. */ +- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) { +- if (cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT)) { +- /* Static CID is irrelevant if semaphore mode */ +- goto skip_cid_check; +- } else { +- dev_dbg(rifsc_controller->dev, +- "Invalid bus semaphore configuration: index %d\n", firewall_id); +- return -EACCES; +- } +- } +- +- /* +- * Skip CID check if CID filtering isn't enabled or filtering is enabled on CID0, which +- * corresponds to whatever CID. +- */ +- if (!(cid_reg_value & CIDCFGR_CFEN) || +- FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) == RIF_CID0) +- goto skip_cid_check; +- +- /* Coherency check with the CID configuration */ +- if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) { +- dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n", +- firewall_id); +- return -EACCES; +- } +- +-skip_cid_check: + /* Check security configuration */ + if (sec_reg_value & BIT(reg_offset)) { + dev_dbg(rifsc_controller->dev, +@@ -161,19 +133,31 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 + return -EACCES; + } + +- /* +- * If the peripheral is in semaphore mode, take the semaphore so that +- * the CID1 has the ownership. +- */ +- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) { ++ /* Skip CID check if CID filtering isn't enabled */ ++ if (!(cid_reg_value & CIDCFGR_CFEN)) ++ goto skip_cid_check; ++ ++ /* First check conditions for semaphore mode, which doesn't take into account static CID. */ ++ if (cid_reg_value & CIDCFGR_SEMEN) { ++ if (!(cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT))) { ++ dev_dbg(rifsc_controller->dev, ++ "Invalid bus semaphore configuration: index %d\n", firewall_id); ++ return -EACCES; ++ } ++ + rc = stm32_rif_acquire_semaphore(rifsc_controller, firewall_id); + if (rc) { +- dev_err(rifsc_controller->dev, ++ dev_dbg(rifsc_controller->dev, + "Couldn't acquire semaphore for peripheral: %d\n", firewall_id); + return rc; + } ++ } else if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) { ++ dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n", ++ firewall_id); ++ return -EACCES; + } + ++skip_cid_check: + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.12/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch b/queue-6.12/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch new file mode 100644 index 0000000000..4bb58b7847 --- /dev/null +++ b/queue-6.12/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch @@ -0,0 +1,237 @@ +From 7a883e7e2a56eb21f613d140c1c45aebb4607092 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:01:39 +0100 +Subject: cdrom, scsi: sr: propagate read-only status to block layer via + set_disk_ro() + +From: Daan De Meyer + +[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ] + +The cdrom core never calls set_disk_ro() for a registered device, so +BLKROGET on a CD-ROM device always returns 0 (writable), even when the +drive has no write capabilities and writes will inevitably fail. This +causes problems for userspace that relies on BLKROGET to determine +whether a block device is read-only. For example, systemd's loop device +setup uses BLKROGET to decide whether to create a loop device with +LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the +loop device to the CD-ROM and fail with I/O errors. systemd-fsck +similarly checks BLKROGET to decide whether to run fsck in no-repair +mode (-n). + +The write-capability bits in cdi->mask come from two different sources: +CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE +SENSE capabilities page (page 0x2A) before register_cdrom() is called, +while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command +and were only probed by cdrom_open_write() at device open time. This +meant that any attempt to compute the writable state from the full +mask at probe time was incorrect, because the GET CONFIGURATION bits +were still unset (and cdi->mask is initialized such that capabilities +are assumed present). + +Fix this by factoring the GET CONFIGURATION probing out of +cdrom_open_write() into a new exported helper, +cdrom_probe_write_features(), and having sr call it from sr_probe() +right after get_capabilities() has populated the MODE SENSE bits. +register_cdrom() then calls set_disk_ro() based on the full +write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) +so the block layer reflects the drive's actual write support. The +feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with +RT=00) report drive-level capabilities that are persistent across +media, so a single probe before register_cdrom() is sufficient and the +redundant probe at open time is dropped. + +With set_disk_ro() now accurate, the long-vestigial cd->writeable flag +in sr can go: get_capabilities() used to set cd->writeable based on +the same four mask bits, but because CDC_MRW_W and CDC_RAM default to +"capability present" in cdi->mask and aren't touched by MODE SENSE, +the condition that gated cd->writeable was always true, making it +unconditionally 1. Replace the corresponding gate in sr_init_command() +with get_disk_ro(cd->disk), which turns a previously no-op check into +a real one and also catches kernel-internal bio writers that bypass +blkdev_write_iter()'s bdev_read_only() check. + +The sd driver (SCSI disks) does not have this problem because it +checks the MODE SENSE Write Protect bit and calls set_disk_ro() +accordingly. The sr driver cannot use the same approach because the +MMC specification does not define the WP bit in the MODE SENSE +device-specific parameter byte for CD-ROM devices. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Daan De Meyer +Reviewed-by: Phillip Potter +Reviewed-by: Martin K. Petersen +Signed-off-by: Phillip Potter +Link: https://patch.msgid.link/20260427210139.1400-2-phil@philpotter.co.uk +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- + drivers/scsi/sr.c | 11 ++----- + drivers/scsi/sr.h | 1 - + include/linux/cdrom.h | 1 + + 4 files changed, 51 insertions(+), 35 deletions(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index 6a99a459b80b2..19d6f9a069bdf 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -634,6 +634,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) + + WARN_ON(!cdo->generic_packet); + ++ /* ++ * Propagate the drive's write support to the block layer so BLKROGET ++ * reflects actual write capability. Drivers that use GET CONFIGURATION ++ * features (CDC_MRW_W, CDC_RAM) must have called ++ * cdrom_probe_write_features() before register_cdrom() so the mask is ++ * complete here. ++ */ ++ set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | ++ CDC_CD_RW)); ++ + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + mutex_lock(&cdrom_mutex); + list_add(&cdi->list, &cdrom_list); +@@ -748,6 +758,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) + return 0; + } + ++/* ++ * Probe write-related MMC features via GET CONFIGURATION and update ++ * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE ++ * capabilities page (e.g. sr) should call this after those MODE SENSE bits ++ * have been set but before register_cdrom(), so that the full set of ++ * write-capability bits is known by the time register_cdrom() decides on the ++ * initial read-only state of the disk. ++ */ ++void cdrom_probe_write_features(struct cdrom_device_info *cdi) ++{ ++ int mrw, mrw_write, ram_write; ++ ++ mrw = 0; ++ if (!cdrom_is_mrw(cdi, &mrw_write)) ++ mrw = 1; ++ ++ if (CDROM_CAN(CDC_MO_DRIVE)) ++ ram_write = 1; ++ else ++ (void) cdrom_is_random_writable(cdi, &ram_write); ++ ++ if (mrw) ++ cdi->mask &= ~CDC_MRW; ++ else ++ cdi->mask |= CDC_MRW; ++ ++ if (mrw_write) ++ cdi->mask &= ~CDC_MRW_W; ++ else ++ cdi->mask |= CDC_MRW_W; ++ ++ if (ram_write) ++ cdi->mask &= ~CDC_RAM; ++ else ++ cdi->mask |= CDC_RAM; ++} ++EXPORT_SYMBOL(cdrom_probe_write_features); ++ + static int cdrom_media_erasable(struct cdrom_device_info *cdi) + { + disc_information di; +@@ -900,33 +948,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) + */ + static int cdrom_open_write(struct cdrom_device_info *cdi) + { +- int mrw, mrw_write, ram_write; + int ret = 1; + +- mrw = 0; +- if (!cdrom_is_mrw(cdi, &mrw_write)) +- mrw = 1; +- +- if (CDROM_CAN(CDC_MO_DRIVE)) +- ram_write = 1; +- else +- (void) cdrom_is_random_writable(cdi, &ram_write); +- +- if (mrw) +- cdi->mask &= ~CDC_MRW; +- else +- cdi->mask |= CDC_MRW; +- +- if (mrw_write) +- cdi->mask &= ~CDC_MRW_W; +- else +- cdi->mask |= CDC_MRW_W; +- +- if (ram_write) +- cdi->mask &= ~CDC_RAM; +- else +- cdi->mask |= CDC_RAM; +- + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index add13e3068983..803fc9c132298 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) + + switch (req_op(rq)) { + case REQ_OP_WRITE: +- if (!cd->writeable) ++ if (get_disk_ro(cd->disk)) + goto out; + SCpnt->cmnd[0] = WRITE_10; + cd->cdi.media_written = 1; +@@ -681,6 +681,7 @@ static int sr_probe(struct device *dev) + error = -ENOMEM; + if (get_capabilities(cd)) + goto fail_minor; ++ cdrom_probe_write_features(&cd->cdi); + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd) + /*else I don't think it can close its tray + cd->cdi.mask |= CDC_CLOSE_TRAY; */ + +- /* +- * if DVD-RAM, MRW-W or CD-RW, we are randomly writable +- */ +- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != +- (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { +- cd->writeable = 1; +- } +- + kfree(buffer); + return 0; + } +diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h +index dc899277b3a44..2d92f9cb6fec7 100644 +--- a/drivers/scsi/sr.h ++++ b/drivers/scsi/sr.h +@@ -35,7 +35,6 @@ typedef struct scsi_cd { + struct scsi_device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ +- unsigned writeable : 1; + unsigned use:1; /* is this device still supportable */ + unsigned xa_flag:1; /* CD has XA sectors ? */ + unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ +diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h +index fdfb61ccf55ae..b4f2b23744413 100644 +--- a/include/linux/cdrom.h ++++ b/include/linux/cdrom.h +@@ -109,6 +109,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, + extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing); + ++extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); + extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); + extern void unregister_cdrom(struct cdrom_device_info *cdi); + +-- +2.53.0 + diff --git a/queue-6.12/cgroup-increment-nr_dying_subsys_-from-rmdir-context.patch b/queue-6.12/cgroup-increment-nr_dying_subsys_-from-rmdir-context.patch new file mode 100644 index 0000000000..6ac956ebc5 --- /dev/null +++ b/queue-6.12/cgroup-increment-nr_dying_subsys_-from-rmdir-context.patch @@ -0,0 +1,76 @@ +From 20823c2caf74f1deaef2a5a8f05a7b7e01bab052 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 04:48:26 -0500 +Subject: cgroup: Increment nr_dying_subsys_* from rmdir context + +From: Petr Malat + +[ Upstream commit 13e786b64bd3fd81c7eb22aa32bf8305c32f2ccf ] + +Incrementing nr_dying_subsys_* in offline_css(), which is executed by +cgroup_offline_wq worker, leads to a race where user can see the value +to be 0 if he reads cgroup.stat after calling rmdir and before the worker +executes. This makes the user wrongly expect resources released by the +removed cgroup to be available for a new assignment. + +Increment nr_dying_subsys_* from kill_css(), which is called from the +cgroup_rmdir() context. + +Fixes: ab0312526867 ("cgroup: Show # of subsystem CSSes in cgroup.stat") +Signed-off-by: Petr Malat +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 0914a1a189ee1..dfb93a201fc32 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -5654,16 +5654,6 @@ static void offline_css(struct cgroup_subsys_state *css) + RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL); + + wake_up_all(&css->cgroup->offline_waitq); +- +- css->cgroup->nr_dying_subsys[ss->id]++; +- /* +- * Parent css and cgroup cannot be freed until after the freeing +- * of child css, see css_free_rwork_fn(). +- */ +- while ((css = css->parent)) { +- css->nr_descendants--; +- css->cgroup->nr_dying_subsys[ss->id]++; +- } + } + + /** +@@ -5965,6 +5955,8 @@ static void css_killed_ref_fn(struct percpu_ref *ref) + */ + static void kill_css(struct cgroup_subsys_state *css) + { ++ struct cgroup_subsys *ss = css->ss; ++ + lockdep_assert_held(&cgroup_mutex); + + if (css->flags & CSS_DYING) +@@ -6001,6 +5993,16 @@ static void kill_css(struct cgroup_subsys_state *css) + * css is confirmed to be seen as killed on all CPUs. + */ + percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn); ++ ++ css->cgroup->nr_dying_subsys[ss->id]++; ++ /* ++ * Parent css and cgroup cannot be freed until after the freeing ++ * of child css, see css_free_rwork_fn(). ++ */ ++ while ((css = css->parent)) { ++ css->nr_descendants--; ++ css->cgroup->nr_dying_subsys[ss->id]++; ++ } + } + + /** +-- +2.53.0 + diff --git a/queue-6.12/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch b/queue-6.12/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch new file mode 100644 index 0000000000..fbeb2215df --- /dev/null +++ b/queue-6.12/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch @@ -0,0 +1,47 @@ +From 03a1a4bb7729b6512a21d87606f0a38c83691594 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 09:53:27 +0800 +Subject: cgroup/rdma: fix integer overflow in rdmacg_try_charge() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: cuitao + +[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ] + +The expression `rpool->resources[index].usage + 1` is computed in int +arithmetic before being assigned to s64 variable `new`. When usage equals +INT_MAX (the default "max" value), the addition overflows to INT_MIN. +This negative value then passes the `new > max` check incorrectly, +allowing a charge that should be rejected and corrupting usage to +negative. + +Fix by casting usage to s64 before the addition so the arithmetic is +done in 64-bit. + +Fixes: 39d3e7584a68 ("rdmacg: Added rdma cgroup controller") +Signed-off-by: cuitao +Reviewed-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c +index ef5878fb20057..d544a747f3954 100644 +--- a/kernel/cgroup/rdma.c ++++ b/kernel/cgroup/rdma.c +@@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, + ret = PTR_ERR(rpool); + goto err; + } else { +- new = rpool->resources[index].usage + 1; ++ new = (s64)rpool->resources[index].usage + 1; + if (new > rpool->resources[index].max) { + ret = -EAGAIN; + goto err; +-- +2.53.0 + diff --git a/queue-6.12/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch b/queue-6.12/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch new file mode 100644 index 0000000000..9abebab43f --- /dev/null +++ b/queue-6.12/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch @@ -0,0 +1,58 @@ +From 7b2244146f937bbf07a272c966a5e3d2e65d3588 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:58 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in + of_assigned_ldb_sels() + +From: Felix Gu + +[ Upstream commit 9faf207208951460f3f7eefbc112246c8d28ff1b ] + +The function of_assigned_ldb_sels() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing a memory +leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 5d283b083800 ("clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-2-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index ba696cf34fe3b..048e2ddba490b 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -188,9 +188,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + } + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: parent clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + parent = clkspec.args[0]; ++ of_node_put(clkspec.np); + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); +@@ -198,9 +200,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + return; + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: child clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + child = clkspec.args[0]; ++ of_node_put(clkspec.np); + + if (child != IMX6QDL_CLK_LDB_DI0_SEL && + child != IMX6QDL_CLK_LDB_DI1_SEL) +-- +2.53.0 + diff --git a/queue-6.12/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch b/queue-6.12/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch new file mode 100644 index 0000000000..e581ac4f57 --- /dev/null +++ b/queue-6.12/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch @@ -0,0 +1,56 @@ +From 6737dda69fadc0df7d64e6f0099ff7797bad2870 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:57 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in pll6_bypassed() + +From: Felix Gu + +[ Upstream commit 4b84d496c804b470124cd3a08e928df6801d8eae ] + +The function pll6_bypassed() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing +a memory leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 3cc48976e9763 ("clk: imx6q: handle ENET PLL bypass") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-1-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index bf4c1d9c99287..ba696cf34fe3b 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -238,8 +238,11 @@ static bool pll6_bypassed(struct device_node *node) + return false; + + if (clkspec.np == node && +- clkspec.args[0] == IMX6QDL_PLL6_BYPASS) ++ clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { ++ of_node_put(clkspec.np); + break; ++ } ++ of_node_put(clkspec.np); + } + + /* PLL6 bypass is not part of the assigned clock list */ +@@ -249,6 +252,9 @@ static bool pll6_bypassed(struct device_node *node) + ret = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + ++ if (!ret) ++ of_node_put(clkspec.np); ++ + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) + return true; + +-- +2.53.0 + diff --git a/queue-6.12/clk-imx8mq-correct-the-csi-phy-sels.patch b/queue-6.12/clk-imx8mq-correct-the-csi-phy-sels.patch new file mode 100644 index 0000000000..56c16b3331 --- /dev/null +++ b/queue-6.12/clk-imx8mq-correct-the-csi-phy-sels.patch @@ -0,0 +1,49 @@ +From 9e3cdda8dd3a2d6011c8b6d0cc306a899d380f8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 00:47:21 +0100 +Subject: clk: imx8mq: Correct the CSI PHY sels + +From: Sebastian Krzyszkowiak + +[ Upstream commit d16f57caa78776e6e8a88b96cb2597797b376138 ] + +According to i.MX 8M Quad Reference Manual (Section 5.1.2 Table 5-1) +MIPI_CSI1_PHY_REF_CLK_ROOT and MIPI_CSI2_PHY_REF_CLK_ROOT have +SYSTEM_PLL2_DIV3 available as their second source, which corresponds +to sys2_pll_333m rather than sys2_pll_125m. + +Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") +Signed-off-by: Sebastian Krzyszkowiak +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260128-imx8mq-csi-clk-v1-1-ac028ed26e8c@puri.sm +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index f70ed231b92d6..cedc8a02aa1f0 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " + static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +@@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", + static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch b/queue-6.12/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch new file mode 100644 index 0000000000..b62632857b --- /dev/null +++ b/queue-6.12/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch @@ -0,0 +1,59 @@ +From 3d953de9bea27d28d2b9dea4d5df0909333d0c68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:26 +0100 +Subject: clk: qcom: dispcc-sc7180: Add missing MDSS resets + +From: Konrad Dybcio + +[ Upstream commit b0bc6011c5499bdfddd0390262bfa13dce1eff74 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: dd3d06622138 ("clk: qcom: Add display clock controller driver for SC7180") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Taniya Das +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-2-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc7180.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c +index 4710247be5306..ae98fe4dcfb2b 100644 +--- a/drivers/clk/qcom/dispcc-sc7180.c ++++ b/drivers/clk/qcom/dispcc-sc7180.c +@@ -16,6 +16,7 @@ + #include "clk-regmap-divider.h" + #include "common.h" + #include "gdsc.h" ++#include "reset.h" + + enum { + P_BI_TCXO, +@@ -635,6 +636,11 @@ static struct gdsc mdss_gdsc = { + .flags = HW_CTRL, + }; + ++static const struct qcom_reset_map disp_cc_sc7180_resets[] = { ++ [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, ++ [DISP_CC_MDSS_RSCC_BCR] = { 0x4000 }, ++}; ++ + static struct gdsc *disp_cc_sc7180_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, + }; +@@ -686,6 +692,8 @@ static const struct qcom_cc_desc disp_cc_sc7180_desc = { + .config = &disp_cc_sc7180_regmap_config, + .clks = disp_cc_sc7180_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sc7180_clocks), ++ .resets = disp_cc_sc7180_resets, ++ .num_resets = ARRAY_SIZE(disp_cc_sc7180_resets), + .gdscs = disp_cc_sc7180_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sc7180_gdscs), + }; +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch b/queue-6.12/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch new file mode 100644 index 0000000000..547ebf572b --- /dev/null +++ b/queue-6.12/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch @@ -0,0 +1,74 @@ +From 22d417e945ead69f9d6537afe4281b4345427d7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 19:55:50 +0800 +Subject: clk: qcom: dispcc-sc8280xp: remove CLK_SET_RATE_PARENT from + byte_div_clk_src dividers + +From: White Lewis + +[ Upstream commit 0b151a6307205eb867250985a910a88787cbf12e ] + +The four byte_div_clk_src dividers (disp{0,1}_cc_mdss_byte{0,1}_div_clk_src) +had CLK_SET_RATE_PARENT set. When the DSI driver calls clk_set_rate() on +byte_intf_clk, the rate-change propagates through the divider up to the +parent PLL (byte_clk_src), halving the byte clock rate. + +A simiar issue had been also encountered on SM8750. +b8501febdc51 ("clk: qcom: dispcc-sm8750: Drop incorrect CLK_SET_RATE_PARENT on byte intf parent"). + +Likewise, remove CLK_SET_RATE_PARENT from all four byte divider clocks +so that clk_set_rate() on the divider adjusts only the divider ratio, +leaving the parent PLL untouched. + +Fixes: 4a66e76fdb6d ("clk: qcom: Add SC8280XP display clock controller") +Signed-off-by: White Lewis +[pengyu: reword] +Signed-off-by: Pengyu Luo +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260303115550.9279-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc8280xp.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sc8280xp.c b/drivers/clk/qcom/dispcc-sc8280xp.c +index f1ca9ae0b33f4..c23cbb983d29e 100644 +--- a/drivers/clk/qcom/dispcc-sc8280xp.c ++++ b/drivers/clk/qcom/dispcc-sc8280xp.c +@@ -1161,7 +1161,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte0_div_clk_src = { + &disp0_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1176,7 +1175,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte0_div_clk_src = { + &disp1_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1191,7 +1189,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte1_div_clk_src = { + &disp0_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1206,7 +1203,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte1_div_clk_src = { + &disp1_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch b/queue-6.12/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch new file mode 100644 index 0000000000..784094a575 --- /dev/null +++ b/queue-6.12/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch @@ -0,0 +1,52 @@ +From 9f9af869756902123c152adafe928f160c41df5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:30 +0100 +Subject: clk: qcom: dispcc-sm4450: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit 7bc48fcdf9e77bf68ef04af015d50df2a9acac00 ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: 76f05f1ec766 ("clk: qcom: Add DISPCC driver support for SM4450") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-4-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm4450.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm4450.c b/drivers/clk/qcom/dispcc-sm4450.c +index 98ba016bc57f1..398910f09a725 100644 +--- a/drivers/clk/qcom/dispcc-sm4450.c ++++ b/drivers/clk/qcom/dispcc-sm4450.c +@@ -336,7 +336,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch b/queue-6.12/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..8a10bdfb5b --- /dev/null +++ b/queue-6.12/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,48 @@ +From 9f550dc6b41bdc00790e251694b11da865c49e67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:13 -0300 +Subject: clk: qcom: dispcc-sm8250: Enable parents for pixel clocks + +From: Val Packett + +[ Upstream commit acf7a91d0b0e9e3ef374944021de62062125b7e4 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-9-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index b21d16b094667..ea79d48b9a256 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -578,7 +578,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -592,7 +592,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch b/queue-6.12/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch new file mode 100644 index 0000000000..ece526fcb8 --- /dev/null +++ b/queue-6.12/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch @@ -0,0 +1,45 @@ +From 3f3827f7b436a0adbf250782ec4e3a929de5ef81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:12 -0300 +Subject: clk: qcom: dispcc-sm8250: Use shared ops on the mdss vsync clk + +From: Val Packett + +[ Upstream commit 8c522da70f0c2e5148c4c13ccb1c64cca57a6fdb ] + +mdss_gdsc can get stuck on boot due to RCGs being left on from last boot. +As a fix, commit 01a0a6cc8cfd ("clk: qcom: Park shared RCGs upon +registration") introduced a callback to ensure the RCG is off upon init. +However, the fix depends on all shared RCGs being marked as such in code. + +For SM8150/SC8180X/SM8250 the MDSS vsync clock was using regular ops, +unlike the same clock in the SC7180 code. This was causing display to +frequently fail to initialize after rebooting on the Surface Pro X. +Fix by using shared ops for this clock. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-8-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index 884bbd3fb3057..b21d16b094667 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -632,7 +632,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch b/queue-6.12/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch new file mode 100644 index 0000000000..cca192c23b --- /dev/null +++ b/queue-6.12/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch @@ -0,0 +1,41 @@ +From 37ec2ffdc2bc1b482277b1efceae7a5d71057592 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 04:12:23 +0200 +Subject: clk: qcom: dispcc-sm8450: use RCG2 ops for DPTX1 AUX clock source + +From: Dmitry Baryshkov + +[ Upstream commit 141af1be817c42c7f1e1605348d4b1983d319bea ] + +The clk_dp_ops are supposed to be used for DP-related clocks with a +proper MND divier. Use standard RCG2 ops for dptx1_aux_clk_src, the same +as all other DPTX AUX clocks in this driver. + +Fixes: 16fb89f92ec4 ("clk: qcom: Add support for Display Clock Controller on SM8450") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260112-dp-aux-clks-v1-2-456b0c11b069@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8450.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c +index d1d3f60789ee0..8baaf94a119e3 100644 +--- a/drivers/clk/qcom/dispcc-sm8450.c ++++ b/drivers/clk/qcom/dispcc-sm8450.c +@@ -364,7 +364,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_dp_ops, ++ .ops = &clk_rcg2_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-6.12/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..529579290d --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,94 @@ +From fb19ffef2997aa0e57a289188ee1bd28da4f2cf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:07 -0300 +Subject: clk: qcom: gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 3565741eb985a8a7cc6656eb33496195468cb99e ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-3-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 50 ++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 31e788e22ab4a..55dabf6259b29 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4266,6 +4266,51 @@ static struct gdsc usb30_mp_gdsc = { + .flags = POLL_CFG_GDSCR, + }; + ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { ++ .gdscr = 0x7d050, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { ++ .gdscr = 0x7d058, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { ++ .gdscr = 0x7d054, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { ++ .gdscr = 0x7d05c, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { ++ .gdscr = 0x7d060, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ + static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, +@@ -4595,6 +4640,11 @@ static struct gdsc *gcc_sc8180x_gdscs[] = { + [USB30_MP_GDSC] = &usb30_mp_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB30_SEC_GDSC] = &usb30_sec_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, + }; + + static const struct regmap_config gcc_sc8180x_regmap_config = { +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch b/queue-6.12/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch new file mode 100644 index 0000000000..88aa8242d1 --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch @@ -0,0 +1,74 @@ +From cc8556df9f446964ce730edf84a25770aecbdfc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:09 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for PCIe power domains + +From: Val Packett + +[ Upstream commit ccb92c78b42edd26225b4d5920847dfee3e1b093 ] + +As the PCIe host controller driver does not yet support dealing with the +loss of state during suspend, use retention for relevant GDSCs. + +This fixes the link not surviving upon resume: + + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS read failed (134) + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: Disabling device after reset failure: -19 + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260312112321.370983-5-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index b116a9c0b2d94..4095a1f54a099 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4199,7 +4199,7 @@ static struct gdsc pcie_0_gdsc = { + .pd = { + .name = "pcie_0_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4226,7 +4226,7 @@ static struct gdsc pcie_1_gdsc = { + .pd = { + .name = "pcie_1_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4235,7 +4235,7 @@ static struct gdsc pcie_2_gdsc = { + .pd = { + .name = "pcie_2_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4253,7 +4253,7 @@ static struct gdsc pcie_3_gdsc = { + .pd = { + .name = "pcie_3_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch b/queue-6.12/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch new file mode 100644 index 0000000000..810f5e7301 --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch @@ -0,0 +1,65 @@ +From 6d7d1de9918945e71a29ac18e74aa0a83455933f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:08 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for USB power domains + +From: Val Packett + +[ Upstream commit 25bc96f26cd6c19dde13a0b9859183e531d6fbfc ] + +The USB subsystem does not expect to lose its state on suspend: + + xhci-hcd xhci-hcd.0.auto: xHC error in resume, USBSTS 0x401, Reinit + usb usb1: root hub lost power or was reset + +(The reinitialization usually succeeds, but it does slow down resume.) + +To maintain state during suspend, the relevant GDSCs need to stay in +retention mode, like they do on other similar SoCs. Change the mode to +PWRSTS_RET_ON to fix. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-4-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 55dabf6259b29..b116a9c0b2d94 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4172,7 +4172,7 @@ static struct gdsc usb30_sec_gdsc = { + .pd = { + .name = "usb30_sec_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4190,7 +4190,7 @@ static struct gdsc usb30_prim_gdsc = { + .pd = { + .name = "usb30_prim_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4262,7 +4262,7 @@ static struct gdsc usb30_mp_gdsc = { + .pd = { + .name = "usb30_mp_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-6.12/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch b/queue-6.12/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch new file mode 100644 index 0000000000..1a650b5bbd --- /dev/null +++ b/queue-6.12/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch @@ -0,0 +1,44 @@ +From f1f15ff239afa1a4727f9984c98fd9ba68b3d6a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 20:36:46 +0530 +Subject: clk: qcom: gcc-x1e80100: Keep GCC USB QTB clock always ON + +From: Jagadeesh Kona + +[ Upstream commit 05566ebcc0cd170bd4f50c907ee3ed8e106251e3 ] + +In Hamoa, SMMU invalidation requires the GCC_AGGRE_USB_NOC_AXI_CLK +to be on for the USB QTB to be functional. This is currently +explicitly enabled by the DWC3 glue driver, so an invalidation +happening while the USB controller is suspended will fault. + +Solve this by voting for the GCC MMU USB QTB clock. + +Fixes: 161b7c401f4b ("clk: qcom: Add Global Clock controller (GCC) driver for X1E80100") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Jagadeesh Kona +Reviewed-by: Taniya Das +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260327-hamoa-usb-qtb-clk-always-on-v2-1-7d8a406e650f@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-x1e80100.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c +index 0c49f0461ae32..e96faa529d3c4 100644 +--- a/drivers/clk/qcom/gcc-x1e80100.c ++++ b/drivers/clk/qcom/gcc-x1e80100.c +@@ -7413,6 +7413,7 @@ static int gcc_x1e80100_probe(struct platform_device *pdev) + qcom_branch_set_clk_en(regmap, 0x32004); /* GCC_VIDEO_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x32030); /* GCC_VIDEO_XO_CLK */ + qcom_branch_set_clk_en(regmap, 0x71004); /* GCC_GPU_CFG_AHB_CLK */ ++ qcom_branch_set_clk_en(regmap, 0x7d01c); /* GCC_HLOS1_VOTE_AGGRE_NOC_MMU_USB_QTB_CLK */ + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52224, 0x0); +-- +2.53.0 + diff --git a/queue-6.12/clk-qoriq-avoid-format-string-warning.patch b/queue-6.12/clk-qoriq-avoid-format-string-warning.patch new file mode 100644 index 0000000000..ce6efd607e --- /dev/null +++ b/queue-6.12/clk-qoriq-avoid-format-string-warning.patch @@ -0,0 +1,86 @@ +From e96f2898659fb6f455aa199fa500051607b7c2a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:18:49 +0100 +Subject: clk: qoriq: avoid format string warning + +From: Arnd Bergmann + +[ Upstream commit 096abbb6682ee031a0f5ce9f4c71ead9fa63d31e ] + +clang-22 warns about the use of non-variadic format arguments passed into +snprintf(): + +drivers/clk/clk-qoriq.c:925:39: error: diagnostic behavior may be improved by adding the + 'format(printf, 7, 8)' attribute to the declaration of 'create_mux_common' [-Werror,-Wmissing-format-attribute] + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + | __attribute__((format(printf, 7, 8))) + 911 | struct mux_hwclock *hwc, + 912 | const struct clk_ops *ops, + 913 | unsigned long min_rate, + 914 | unsigned long max_rate, + 915 | unsigned long pct80_rate, + 916 | const char *fmt, int idx) + 917 | { + 918 | struct clk_init_data init = {}; + 919 | struct clk *clk; + 920 | const struct clockgen_pll_div *div; + 921 | const char *parent_names[NUM_MUX_PARENTS]; + 922 | char name[32]; + 923 | int i, j; + 924 | + 925 | snprintf(name, sizeof(name), fmt, idx); + | ^ +drivers/clk/clk-qoriq.c:910:28: note: 'create_mux_common' declared here + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + +Rework this to pass the 'int idx' as a varargs argument, allowing the +format string to be verified at the caller location. + +Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") +Signed-off-by: Arnd Bergmann +Reviewed-by: Kees Cook +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-qoriq.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c +index 4dcde305944c4..318acd176a2ef 100644 +--- a/drivers/clk/clk-qoriq.c ++++ b/drivers/clk/clk-qoriq.c +@@ -906,13 +906,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg, + return &cg->pll[pll].div[div]; + } + +-static struct clk * __init create_mux_common(struct clockgen *cg, +- struct mux_hwclock *hwc, +- const struct clk_ops *ops, +- unsigned long min_rate, +- unsigned long max_rate, +- unsigned long pct80_rate, +- const char *fmt, int idx) ++static struct clk * __init __printf(7, 8) ++create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, ++ const struct clk_ops *ops, unsigned long min_rate, ++ unsigned long max_rate, unsigned long pct80_rate, ++ const char *fmt, ...) + { + struct clk_init_data init = {}; + struct clk *clk; +@@ -920,8 +918,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg, + const char *parent_names[NUM_MUX_PARENTS]; + char name[32]; + int i, j; ++ va_list args; + +- snprintf(name, sizeof(name), fmt, idx); ++ va_start(args, fmt); ++ vsnprintf(name, sizeof(name), fmt, args); ++ va_end(args); + + for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) { + unsigned long rate; +-- +2.53.0 + diff --git a/queue-6.12/clk-visconti-pll-initialize-clk_init_data-to-zero.patch b/queue-6.12/clk-visconti-pll-initialize-clk_init_data-to-zero.patch new file mode 100644 index 0000000000..bfc8868c64 --- /dev/null +++ b/queue-6.12/clk-visconti-pll-initialize-clk_init_data-to-zero.patch @@ -0,0 +1,52 @@ +From 0439d84d9a373baaa12b1b20401a95e2e8737651 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 10:32:37 -0400 +Subject: clk: visconti: pll: initialize clk_init_data to zero +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 1603cbb64173a0e9fa7500f2a686f4aa011c58b9 ] + +Sashiko reported the following: + +> The struct clk_init_data init is declared on the stack without being +> fully zero-initialized. While fields like name, flags, parent_names, +> num_parents, and ops are explicitly assigned, the parent_data and +> parent_hws fields are left containing stack garbage. + +clk_core_populate_parent_map() currently prefers the parent names over +the parent data and hws, so this isn't a problem at the moment. If that +ordering ever changed in the future, then this could lead to some +unexpected crashes. Let's just go ahead and make sure that the struct +clk_init_data is initialized to zero as a good practice. + +Fixes: b4cbe606dc367 ("clk: visconti: Add support common clock driver and reset driver") +Link: https://sashiko.dev/#/patchset/20260326042317.122536-1-rosenp%40gmail.com +Signed-off-by: Brian Masney +Reviewed-by: Benoît Monin +Reviewed-by: Nobuhiro Iwamatsu +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/visconti/pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c +index 3f929cf8dd2f7..22930fd589b70 100644 +--- a/drivers/clk/visconti/pll.c ++++ b/drivers/clk/visconti/pll.c +@@ -244,7 +244,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, + const struct visconti_pll_rate_table *rate_table, + spinlock_t *lock) + { +- struct clk_init_data init; ++ struct clk_init_data init = {}; + struct visconti_pll *pll; + struct clk_hw *pll_hw_clk; + size_t len; +-- +2.53.0 + diff --git a/queue-6.12/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch b/queue-6.12/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch new file mode 100644 index 0000000000..64403b5097 --- /dev/null +++ b/queue-6.12/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch @@ -0,0 +1,37 @@ +From f4f6818d1b5b9373a9df8bd86e7da8e69cd8cad7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:11:16 +0100 +Subject: clk: xgene: Fix mapping leak in xgene_pllclk_init() + +From: Geert Uytterhoeven + +[ Upstream commit f520a492e07bc6718e26cfb7543ab4cadd8bb0e2 ] + +If xgene_register_clk_pll() fails, the mapped register block is never +unmapped. + +Fixes: 308964caeebc45eb ("clk: Add APM X-Gene SoC clock driver") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-xgene.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c +index 0c3d0cee98c83..a542b78d9c731 100644 +--- a/drivers/clk/clk-xgene.c ++++ b/drivers/clk/clk-xgene.c +@@ -187,6 +187,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); ++ } else { ++ iounmap(reg); + } + } + +-- +2.53.0 + diff --git a/queue-6.12/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch b/queue-6.12/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch new file mode 100644 index 0000000000..c59e5776f5 --- /dev/null +++ b/queue-6.12/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch @@ -0,0 +1,49 @@ +From 058a97fc0e854dcbac0c64ebde6e2373ac02ff4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 12:39:28 +0100 +Subject: crypto: atmel-aes - guard unregister on error in + atmel_aes_register_algs + +From: Thorsten Blum + +[ Upstream commit 57a13941c0bb06ae24e3b34672d7b6f2172b253f ] + +Ensure the device supports XTS and GCM with 'has_xts' and 'has_gcm' +before unregistering algorithms when XTS or authenc registration fails, +which would trigger a WARN in crypto_unregister_alg(). + +Currently, with the capabilities defined in atmel_aes_get_cap(), this +bug cannot happen because all devices that support XTS and authenc also +support GCM, but the error handling should still be correct regardless +of hardware capabilities. + +Fixes: d52db5188a87 ("crypto: atmel-aes - add support to the XTS mode") +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/atmel-aes.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c +index cf923be68a00f..5d35f6de452b7 100644 +--- a/drivers/crypto/atmel-aes.c ++++ b/drivers/crypto/atmel-aes.c +@@ -2269,10 +2269,12 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + /* i = ARRAY_SIZE(aes_authenc_algs); */ + err_aes_authenc_alg: + crypto_unregister_aeads(aes_authenc_algs, i); +- crypto_unregister_skcipher(&aes_xts_alg); ++ if (dd->caps.has_xts) ++ crypto_unregister_skcipher(&aes_xts_alg); + #endif + err_aes_xts_alg: +- crypto_unregister_aead(&aes_gcm_alg); ++ if (dd->caps.has_gcm) ++ crypto_unregister_aead(&aes_gcm_alg); + err_aes_gcm_alg: + i = ARRAY_SIZE(aes_algs); + err_aes_algs: +-- +2.53.0 + diff --git a/queue-6.12/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch b/queue-6.12/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch new file mode 100644 index 0000000000..f4d1b3daaa --- /dev/null +++ b/queue-6.12/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch @@ -0,0 +1,205 @@ +From 82919216d345d56a2db93b84efea3c1e60102501 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 18:47:03 +0100 +Subject: crypto: atmel - Use unregister_{aeads,ahashes,skciphers} + +From: Thorsten Blum + +[ Upstream commit 2ffc1ef4e826f0c3274f9ff5eb42bc70a5571afd ] + +Replace multiple for loops with calls to crypto_unregister_aeads(), +crypto_unregister_ahashes(), and crypto_unregister_skciphers(). + +Remove the definition of atmel_tdes_unregister_algs() because it is +equivalent to calling crypto_unregister_skciphers() directly, and the +function parameter 'struct atmel_tdes_dev *' is unused anyway. + +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Stable-dep-of: 57a13941c0bb ("crypto: atmel-aes - guard unregister on error in atmel_aes_register_algs") +Signed-off-by: Sasha Levin +--- + drivers/crypto/atmel-aes.c | 17 ++++++----------- + drivers/crypto/atmel-sha.c | 27 ++++++++++----------------- + drivers/crypto/atmel-tdes.c | 25 ++++++------------------- + 3 files changed, 22 insertions(+), 47 deletions(-) + +diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c +index 5f53936eb905d..cf923be68a00f 100644 +--- a/drivers/crypto/atmel-aes.c ++++ b/drivers/crypto/atmel-aes.c +@@ -2200,12 +2200,10 @@ static irqreturn_t atmel_aes_irq(int irq, void *dev_id) + + static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) + { +- int i; +- + #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) + if (dd->caps.has_authenc) +- for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++) +- crypto_unregister_aead(&aes_authenc_algs[i]); ++ crypto_unregister_aeads(aes_authenc_algs, ++ ARRAY_SIZE(aes_authenc_algs)); + #endif + + if (dd->caps.has_xts) +@@ -2214,8 +2212,7 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) + if (dd->caps.has_gcm) + crypto_unregister_aead(&aes_gcm_alg); + +- for (i = 0; i < ARRAY_SIZE(aes_algs); i++) +- crypto_unregister_skcipher(&aes_algs[i]); ++ crypto_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs)); + } + + static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) +@@ -2228,7 +2225,7 @@ static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) + + static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { + atmel_aes_crypto_alg_init(&aes_algs[i].base); +@@ -2271,8 +2268,7 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) + /* i = ARRAY_SIZE(aes_authenc_algs); */ + err_aes_authenc_alg: +- for (j = 0; j < i; j++) +- crypto_unregister_aead(&aes_authenc_algs[j]); ++ crypto_unregister_aeads(aes_authenc_algs, i); + crypto_unregister_skcipher(&aes_xts_alg); + #endif + err_aes_xts_alg: +@@ -2280,8 +2276,7 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + err_aes_gcm_alg: + i = ARRAY_SIZE(aes_algs); + err_aes_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_skcipher(&aes_algs[j]); ++ crypto_unregister_skciphers(aes_algs, i); + + return err; + } +diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c +index 8cc57df257784..4f2f57bc3bb67 100644 +--- a/drivers/crypto/atmel-sha.c ++++ b/drivers/crypto/atmel-sha.c +@@ -2416,27 +2416,23 @@ EXPORT_SYMBOL_GPL(atmel_sha_authenc_abort); + + static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) + { +- int i; +- + if (dd->caps.has_hmac) +- for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) +- crypto_unregister_ahash(&sha_hmac_algs[i]); ++ crypto_unregister_ahashes(sha_hmac_algs, ++ ARRAY_SIZE(sha_hmac_algs)); + +- for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) +- crypto_unregister_ahash(&sha_1_256_algs[i]); ++ crypto_unregister_ahashes(sha_1_256_algs, ARRAY_SIZE(sha_1_256_algs)); + + if (dd->caps.has_sha224) + crypto_unregister_ahash(&sha_224_alg); + +- if (dd->caps.has_sha_384_512) { +- for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) +- crypto_unregister_ahash(&sha_384_512_algs[i]); +- } ++ if (dd->caps.has_sha_384_512) ++ crypto_unregister_ahashes(sha_384_512_algs, ++ ARRAY_SIZE(sha_384_512_algs)); + } + + static int atmel_sha_register_algs(struct atmel_sha_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) { + atmel_sha_alg_init(&sha_1_256_algs[i]); +@@ -2478,18 +2474,15 @@ static int atmel_sha_register_algs(struct atmel_sha_dev *dd) + + /*i = ARRAY_SIZE(sha_hmac_algs);*/ + err_sha_hmac_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_hmac_algs[j]); ++ crypto_unregister_ahashes(sha_hmac_algs, i); + i = ARRAY_SIZE(sha_384_512_algs); + err_sha_384_512_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_384_512_algs[j]); ++ crypto_unregister_ahashes(sha_384_512_algs, i); + crypto_unregister_ahash(&sha_224_alg); + err_sha_224_algs: + i = ARRAY_SIZE(sha_1_256_algs); + err_sha_1_256_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_1_256_algs[j]); ++ crypto_unregister_ahashes(sha_1_256_algs, i); + + return err; + } +diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c +index 813ed47e60cce..f07109608a090 100644 +--- a/drivers/crypto/atmel-tdes.c ++++ b/drivers/crypto/atmel-tdes.c +@@ -897,38 +897,25 @@ static irqreturn_t atmel_tdes_irq(int irq, void *dev_id) + return IRQ_NONE; + } + +-static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) +- crypto_unregister_skcipher(&tdes_algs[i]); +-} +- + static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) { + atmel_tdes_skcipher_alg_init(&tdes_algs[i]); + + err = crypto_register_skcipher(&tdes_algs[i]); +- if (err) +- goto err_tdes_algs; ++ if (err) { ++ crypto_unregister_skciphers(tdes_algs, i); ++ return err; ++ } + } + + return 0; +- +-err_tdes_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_skcipher(&tdes_algs[j]); +- +- return err; + } + + static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd) + { +- + dd->caps.has_dma = 0; + + /* keep only major version number */ +@@ -1061,7 +1048,7 @@ static void atmel_tdes_remove(struct platform_device *pdev) + list_del(&tdes_dd->list); + spin_unlock(&atmel_tdes.lock); + +- atmel_tdes_unregister_algs(tdes_dd); ++ crypto_unregister_skciphers(tdes_algs, ARRAY_SIZE(tdes_algs)); + + tasklet_kill(&tdes_dd->done_task); + tasklet_kill(&tdes_dd->queue_task); +-- +2.53.0 + diff --git a/queue-6.12/crypto-ccp-copy-iv-using-skcipher-ivsize.patch b/queue-6.12/crypto-ccp-copy-iv-using-skcipher-ivsize.patch new file mode 100644 index 0000000000..0c3a33f9be --- /dev/null +++ b/queue-6.12/crypto-ccp-copy-iv-using-skcipher-ivsize.patch @@ -0,0 +1,47 @@ +From f624789f858320efdf666d559d70a2aae9cf39d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 03:07:49 -0500 +Subject: crypto: ccp - copy IV using skcipher ivsize + +From: Paul Moses + +[ Upstream commit a7a1f3cdd64d8a165d9b8c9e9ad7fb46ac19dfc4 ] + +AF_ALG rfc3686-ctr-aes-ccp requests pass an 8-byte IV to the driver. + +ccp_aes_complete() restores AES_BLOCK_SIZE bytes into the caller's IV +buffer while RFC3686 skciphers expose an 8-byte IV, so the restore +overruns the provided buffer. + +Use crypto_skcipher_ivsize() to copy only the algorithm's IV length. + +Fixes: 2b789435d7f3 ("crypto: ccp - CCP AES crypto API support") +Signed-off-by: Paul Moses +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-crypto-aes.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c +index d11daaf47f068..871886826cf00 100644 +--- a/drivers/crypto/ccp/ccp-crypto-aes.c ++++ b/drivers/crypto/ccp/ccp-crypto-aes.c +@@ -29,8 +29,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) + if (ret) + return ret; + +- if (ctx->u.aes.mode != CCP_AES_MODE_ECB) +- memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE); ++ if (ctx->u.aes.mode != CCP_AES_MODE_ECB) { ++ size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); ++ ++ memcpy(req->iv, rctx->iv, ivsize); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/crypto-jitterentropy-replace-long-held-spinlock-with.patch b/queue-6.12/crypto-jitterentropy-replace-long-held-spinlock-with.patch new file mode 100644 index 0000000000..7865e1fa6c --- /dev/null +++ b/queue-6.12/crypto-jitterentropy-replace-long-held-spinlock-with.patch @@ -0,0 +1,109 @@ +From 676117be10145d38234ebd49de2a7965dc9ee4b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:23:46 +0800 +Subject: crypto: jitterentropy - replace long-held spinlock with mutex + +From: Haixin Xu + +[ Upstream commit 01d798e9feb30212952d4e992801ba6bd6a82351 ] + +jent_kcapi_random() serializes the shared jitterentropy state, but it +currently holds a spinlock across the jent_read_entropy() call. That +path performs expensive jitter collection and SHA3 conditioning, so +parallel readers can trigger stalls as contending waiters spin for +the same lock. + +To prevent non-preemptible lock hold, replace rng->jent_lock with a +mutex so contended readers sleep instead of spinning on a shared lock +held across expensive entropy generation. + +Fixes: bb5530e40824 ("crypto: jitterentropy - add jitterentropy RNG") +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Haixin Xu +Reviewed-by: Stephan Mueller +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/jitterentropy-kcapi.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c +index 1266eb790708b..a9e9b8fe15985 100644 +--- a/crypto/jitterentropy-kcapi.c ++++ b/crypto/jitterentropy-kcapi.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -192,7 +193,7 @@ int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len) + ***************************************************************************/ + + struct jitterentropy { +- spinlock_t jent_lock; ++ struct mutex jent_lock; + struct rand_data *entropy_collector; + struct crypto_shash *tfm; + struct shash_desc *sdesc; +@@ -202,7 +203,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) + { + struct jitterentropy *rng = crypto_tfm_ctx(tfm); + +- spin_lock(&rng->jent_lock); ++ mutex_lock(&rng->jent_lock); + + if (rng->sdesc) { + shash_desc_zero(rng->sdesc); +@@ -217,7 +218,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) + if (rng->entropy_collector) + jent_entropy_collector_free(rng->entropy_collector); + rng->entropy_collector = NULL; +- spin_unlock(&rng->jent_lock); ++ mutex_unlock(&rng->jent_lock); + } + + static int jent_kcapi_init(struct crypto_tfm *tfm) +@@ -227,7 +228,7 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) + struct shash_desc *sdesc; + int size, ret = 0; + +- spin_lock_init(&rng->jent_lock); ++ mutex_init(&rng->jent_lock); + + /* + * Use SHA3-256 as conditioner. We allocate only the generic +@@ -264,7 +265,6 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) + goto err; + } + +- spin_lock_init(&rng->jent_lock); + return 0; + + err: +@@ -279,7 +279,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, + struct jitterentropy *rng = crypto_rng_ctx(tfm); + int ret = 0; + +- spin_lock(&rng->jent_lock); ++ mutex_lock(&rng->jent_lock); + + ret = jent_read_entropy(rng->entropy_collector, rdata, dlen); + +@@ -305,7 +305,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, + ret = -EINVAL; + } + +- spin_unlock(&rng->jent_lock); ++ mutex_unlock(&rng->jent_lock); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.12/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch b/queue-6.12/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch new file mode 100644 index 0000000000..8e0fe61f04 --- /dev/null +++ b/queue-6.12/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch @@ -0,0 +1,62 @@ +From f6199d8b24f261c5cff3a6ed7b970f3b98c896a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:12:34 +0000 +Subject: crypto: qat - disable 420xx AE cluster when lead engine is fused off + +From: Ahsan Atta + +[ Upstream commit f216e0f2d1787e662bb6662c9c522185aa3b855a ] + +The get_ae_mask() function only disables individual engines based on +the fuse register, but engines are organized in clusters of 4. If the +lead engine of a cluster is fused off, the entire cluster must be +disabled. + +Replace the single bitmask inversion with explicit test_bit() checks +on the lead engine of each group, disabling the full ADF_AE_GROUP +when the lead bit is set. + +Signed-off-by: Ahsan Atta +Reviewed-by: Giovanni Cabiddu +Fixes: fcf60f4bcf54 ("crypto: qat - add support for 420xx devices") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../intel/qat/qat_420xx/adf_420xx_hw_data.c | 20 +++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +index 0e7d0db475d5d..5d32f2958da87 100644 +--- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +@@ -98,9 +98,25 @@ static struct adf_hw_device_class adf_420xx_class = { + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 me_disable = self->fuses[ADF_FUSECTL4]; ++ unsigned long fuses = self->fuses[ADF_FUSECTL4]; ++ u32 mask = ADF_420XX_ACCELENGINES_MASK; + +- return ~me_disable & ADF_420XX_ACCELENGINES_MASK; ++ if (test_bit(0, &fuses)) ++ mask &= ~ADF_AE_GROUP_0; ++ ++ if (test_bit(4, &fuses)) ++ mask &= ~ADF_AE_GROUP_1; ++ ++ if (test_bit(8, &fuses)) ++ mask &= ~ADF_AE_GROUP_2; ++ ++ if (test_bit(12, &fuses)) ++ mask &= ~ADF_AE_GROUP_3; ++ ++ if (test_bit(16, &fuses)) ++ mask &= ~ADF_AE_GROUP_4; ++ ++ return mask; + } + + static u32 uof_get_num_objs(struct adf_accel_dev *accel_dev) +-- +2.53.0 + diff --git a/queue-6.12/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch b/queue-6.12/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch new file mode 100644 index 0000000000..463869a492 --- /dev/null +++ b/queue-6.12/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch @@ -0,0 +1,56 @@ +From 19bdc050344ee4142f57cd616bf4f5ba912dcda3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:11:12 +0000 +Subject: crypto: qat - disable 4xxx AE cluster when lead engine is fused off + +From: Ahsan Atta + +[ Upstream commit b260d53561dd69b29505222ec44cf386ac2c2ca6 ] + +The get_ae_mask() function only disables individual engines based on +the fuse register, but engines are organized in clusters of 4. If the +lead engine of a cluster is fused off, the entire cluster must be +disabled. + +Replace the single bitmask inversion with explicit test_bit() checks +on the lead engine of each group, disabling the full ADF_AE_GROUP +when the lead bit is set. + +Signed-off-by: Ahsan Atta +Reviewed-by: Giovanni Cabiddu +Fixes: 8c8268166e834 ("crypto: qat - add qat_4xxx driver") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +index a6d253ff20888..579f92e466f6d 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +@@ -101,9 +101,19 @@ static struct adf_hw_device_class adf_4xxx_class = { + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 me_disable = self->fuses[ADF_FUSECTL4]; ++ unsigned long fuses = self->fuses[ADF_FUSECTL4]; ++ u32 mask = ADF_4XXX_ACCELENGINES_MASK; + +- return ~me_disable & ADF_4XXX_ACCELENGINES_MASK; ++ if (test_bit(0, &fuses)) ++ mask &= ~ADF_AE_GROUP_0; ++ ++ if (test_bit(4, &fuses)) ++ mask &= ~ADF_AE_GROUP_1; ++ ++ if (test_bit(8, &fuses)) ++ mask &= ~ADF_AE_GROUP_2; ++ ++ return mask; + } + + static u32 get_accel_cap(struct adf_accel_dev *accel_dev) +-- +2.53.0 + diff --git a/queue-6.12/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch b/queue-6.12/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch new file mode 100644 index 0000000000..2613fd676b --- /dev/null +++ b/queue-6.12/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch @@ -0,0 +1,86 @@ +From 3968c7f2bfb59696230e05f6a9e5a1469bcff114 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 18:17:23 +0000 +Subject: crypto: qat - fix type mismatch in RAS sysfs show functions + +From: Giovanni Cabiddu + +[ Upstream commit ec23d75c4b77ae42af0777ea59599b1d4f611371 ] + +ADF_RAS_ERR_CTR_READ() expands to atomic_read(), which returns int. +The local variable 'counter' was declared as 'unsigned long', causing +a type mismatch on the assignment. The format specifier '%ld' was +consequently wrong in two ways: wrong length modifier and wrong +signedness. + +Use int to match the return type of atomic_read() and update the +format specifier to '%d' accordingly. + +Fixes: 532d7f6bc458 ("crypto: qat - add error counters") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Reviewed-by: Andy Shevchenko +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../intel/qat/qat_common/adf_sysfs_ras_counters.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c +index e97c67c87b3cf..6abb57bfd3285 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c +@@ -13,14 +13,14 @@ static ssize_t errors_correctable_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_CORR); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t errors_nonfatal_show(struct device *dev, +@@ -28,14 +28,14 @@ static ssize_t errors_nonfatal_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_UNCORR); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t errors_fatal_show(struct device *dev, +@@ -43,14 +43,14 @@ static ssize_t errors_fatal_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_FATAL); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t reset_error_counters_store(struct device *dev, +-- +2.53.0 + diff --git a/queue-6.12/crypto-qat-introduce-fuse-array.patch b/queue-6.12/crypto-qat-introduce-fuse-array.patch new file mode 100644 index 0000000000..b11939cdb8 --- /dev/null +++ b/queue-6.12/crypto-qat-introduce-fuse-array.patch @@ -0,0 +1,264 @@ +From bb706057ee833c2b306c4a584cddeb2c3797a90f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Mar 2025 11:39:38 +0000 +Subject: crypto: qat - introduce fuse array + +From: Suman Kumar Chakraborty + +[ Upstream commit f3bda3b9b69cb193968ba781446ff18c734f0276 ] + +Change the representation of fuses in the accelerator device +structure from a single value to an array. + +This allows the structure to accommodate additional fuses that +are required for future generations of QAT hardware. + +This does not introduce any functional changes. + +Signed-off-by: Suman Kumar Chakraborty +Reviewed-by: Giovanni Cabiddu +Reviewed-by: Andy Shevchenko +Signed-off-by: Herbert Xu +Stable-dep-of: b260d53561dd ("crypto: qat - disable 4xxx AE cluster when lead engine is fused off") +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c | 2 +- + drivers/crypto/intel/qat/qat_420xx/adf_drv.c | 2 +- + drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c | 2 +- + drivers/crypto/intel/qat/qat_4xxx/adf_drv.c | 2 +- + .../crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c | 4 ++-- + drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c | 2 +- + drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c | 4 ++-- + drivers/crypto/intel/qat/qat_c62x/adf_drv.c | 4 ++-- + .../crypto/intel/qat/qat_common/adf_accel_devices.h | 12 +++++++++++- + .../crypto/intel/qat/qat_common/adf_gen2_hw_data.c | 2 +- + .../intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 6 +++--- + drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c | 2 +- + 12 files changed, 27 insertions(+), 17 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +index ef5f03be41906..0e7d0db475d5d 100644 +--- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +@@ -98,7 +98,7 @@ static struct adf_hw_device_class adf_420xx_class = { + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 me_disable = self->fuses; ++ u32 me_disable = self->fuses[ADF_FUSECTL4]; + + return ~me_disable & ADF_420XX_ACCELENGINES_MASK; + } +diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c +index 41420e349572a..b24f0a55cf017 100644 +--- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c +@@ -79,7 +79,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + adf_init_hw_data_420xx(accel_dev->hw_device, ent->device); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid); +- pci_read_config_dword(pdev, ADF_GEN4_FUSECTL4_OFFSET, &hw_data->fuses); ++ pci_read_config_dword(pdev, ADF_GEN4_FUSECTL4_OFFSET, &hw_data->fuses[ADF_FUSECTL4]); + + /* Get Accelerators and Accelerators Engines masks */ + hw_data->accel_mask = hw_data->get_accel_mask(hw_data); +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +index bbd92c017c28e..a6d253ff20888 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +@@ -101,7 +101,7 @@ static struct adf_hw_device_class adf_4xxx_class = { + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 me_disable = self->fuses; ++ u32 me_disable = self->fuses[ADF_FUSECTL4]; + + return ~me_disable & ADF_4XXX_ACCELENGINES_MASK; + } +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +index 01b34eda83e91..6efbfed67c957 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +@@ -81,7 +81,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + adf_init_hw_data_4xxx(accel_dev->hw_device, ent->device); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid); +- pci_read_config_dword(pdev, ADF_GEN4_FUSECTL4_OFFSET, &hw_data->fuses); ++ pci_read_config_dword(pdev, ADF_GEN4_FUSECTL4_OFFSET, &hw_data->fuses[ADF_FUSECTL4]); + + /* Get Accelerators and Accelerators Engines masks */ + hw_data->accel_mask = hw_data->get_accel_mask(hw_data); +diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c +index 201f9412c5823..e78f7bfd30b85 100644 +--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_c3xxx_hw_data.c +@@ -27,8 +27,8 @@ static struct adf_hw_device_class c3xxx_class = { + + static u32 get_accel_mask(struct adf_hw_device_data *self) + { ++ u32 fuses = self->fuses[ADF_FUSECTL0]; + u32 straps = self->straps; +- u32 fuses = self->fuses; + u32 accel; + + accel = ~(fuses | straps) >> ADF_C3XXX_ACCELERATORS_REG_OFFSET; +@@ -39,8 +39,8 @@ static u32 get_accel_mask(struct adf_hw_device_data *self) + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { ++ u32 fuses = self->fuses[ADF_FUSECTL0]; + u32 straps = self->straps; +- u32 fuses = self->fuses; + unsigned long disabled; + u32 ae_disable; + int accel; +diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +index b776f7ea0dfb5..fdbfcb0c8214f 100644 +--- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +@@ -134,7 +134,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + adf_init_hw_data_c3xxx(accel_dev->hw_device); + pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid); + pci_read_config_dword(pdev, ADF_DEVICE_FUSECTL_OFFSET, +- &hw_data->fuses); ++ &hw_data->fuses[ADF_FUSECTL0]); + pci_read_config_dword(pdev, ADF_C3XXX_SOFTSTRAP_CSR_OFFSET, + &hw_data->straps); + +diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c +index 6b5b0cf9c7c74..32ebe09477a8d 100644 +--- a/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_c62x/adf_c62x_hw_data.c +@@ -27,8 +27,8 @@ static struct adf_hw_device_class c62x_class = { + + static u32 get_accel_mask(struct adf_hw_device_data *self) + { ++ u32 fuses = self->fuses[ADF_FUSECTL0]; + u32 straps = self->straps; +- u32 fuses = self->fuses; + u32 accel; + + accel = ~(fuses | straps) >> ADF_C62X_ACCELERATORS_REG_OFFSET; +@@ -39,8 +39,8 @@ static u32 get_accel_mask(struct adf_hw_device_data *self) + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { ++ u32 fuses = self->fuses[ADF_FUSECTL0]; + u32 straps = self->straps; +- u32 fuses = self->fuses; + unsigned long disabled; + u32 ae_disable; + int accel; +diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c +index 5310149c311e2..e8d8a057bbce5 100644 +--- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c +@@ -134,7 +134,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + adf_init_hw_data_c62x(accel_dev->hw_device); + pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid); + pci_read_config_dword(pdev, ADF_DEVICE_FUSECTL_OFFSET, +- &hw_data->fuses); ++ &hw_data->fuses[ADF_FUSECTL0]); + pci_read_config_dword(pdev, ADF_C62X_SOFTSTRAP_CSR_OFFSET, + &hw_data->straps); + +@@ -177,7 +177,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev); + + /* Find and map all the device's BARS */ +- i = (hw_data->fuses & ADF_DEVICE_FUSECTL_MASK) ? 1 : 0; ++ i = (hw_data->fuses[ADF_FUSECTL0] & ADF_DEVICE_FUSECTL_MASK) ? 1 : 0; + bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); + for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) { + struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; +diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +index 7830ecb1a1f15..cfe5bb9f5f7fe 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h ++++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +@@ -52,6 +52,16 @@ enum adf_accel_capabilities { + ADF_ACCEL_CAPABILITIES_RANDOM_NUMBER = 128 + }; + ++enum adf_fuses { ++ ADF_FUSECTL0, ++ ADF_FUSECTL1, ++ ADF_FUSECTL2, ++ ADF_FUSECTL3, ++ ADF_FUSECTL4, ++ ADF_FUSECTL5, ++ ADF_MAX_FUSES ++}; ++ + struct adf_bar { + resource_size_t base_addr; + void __iomem *virt_addr; +@@ -343,7 +353,7 @@ struct adf_hw_device_data { + struct qat_migdev_ops vfmig_ops; + const char *fw_name; + const char *fw_mmp_name; +- u32 fuses; ++ u32 fuses[ADF_MAX_FUSES]; + u32 straps; + u32 accel_capabilities_mask; + u32 extended_dc_capabilities; +diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.c b/drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.c +index 1f64bf49b221c..2b263442c8565 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_gen2_hw_data.c +@@ -115,8 +115,8 @@ u32 adf_gen2_get_accel_cap(struct adf_accel_dev *accel_dev) + { + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct pci_dev *pdev = accel_dev->accel_pci_dev.pci_dev; ++ u32 fuses = hw_data->fuses[ADF_FUSECTL0]; + u32 straps = hw_data->straps; +- u32 fuses = hw_data->fuses; + u32 legfuses; + u32 capabilities = ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC | + ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC | +diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +index c0661ff5e9292..e48bcf1818cd1 100644 +--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +@@ -29,7 +29,7 @@ static struct adf_hw_device_class dh895xcc_class = { + + static u32 get_accel_mask(struct adf_hw_device_data *self) + { +- u32 fuses = self->fuses; ++ u32 fuses = self->fuses[ADF_FUSECTL0]; + + return ~fuses >> ADF_DH895XCC_ACCELERATORS_REG_OFFSET & + ADF_DH895XCC_ACCELERATORS_MASK; +@@ -37,7 +37,7 @@ static u32 get_accel_mask(struct adf_hw_device_data *self) + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 fuses = self->fuses; ++ u32 fuses = self->fuses[ADF_FUSECTL0]; + + return ~fuses & ADF_DH895XCC_ACCELENGINES_MASK; + } +@@ -99,7 +99,7 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) + + static enum dev_sku_info get_sku(struct adf_hw_device_data *self) + { +- int sku = (self->fuses & ADF_DH895XCC_FUSECTL_SKU_MASK) ++ int sku = (self->fuses[ADF_FUSECTL0] & ADF_DH895XCC_FUSECTL_SKU_MASK) + >> ADF_DH895XCC_FUSECTL_SKU_SHIFT; + + switch (sku) { +diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +index 5ddf567ffcad6..9a29bb15ef153 100644 +--- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c ++++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +@@ -134,7 +134,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + adf_init_hw_data_dh895xcc(accel_dev->hw_device); + pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid); + pci_read_config_dword(pdev, ADF_DEVICE_FUSECTL_OFFSET, +- &hw_data->fuses); ++ &hw_data->fuses[ADF_FUSECTL0]); + + /* Get Accelerators and Accelerators Engines masks */ + hw_data->accel_mask = hw_data->get_accel_mask(hw_data); +-- +2.53.0 + diff --git a/queue-6.12/crypto-qat-use-swab32-macro.patch b/queue-6.12/crypto-qat-use-swab32-macro.patch new file mode 100644 index 0000000000..ce33ae5a2f --- /dev/null +++ b/queue-6.12/crypto-qat-use-swab32-macro.patch @@ -0,0 +1,82 @@ +From 0613e64cb77d31c07806e6eda5a8a620b17fe07c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 22:29:46 +0000 +Subject: crypto: qat - use swab32 macro + +From: Giovanni Cabiddu + +[ Upstream commit 35ecb77ae0749a2f1b04872c9978d9d7ddbbeb79 ] + +Replace __builtin_bswap32() with swab32 in icp_qat_hw_20_comp.h to fix +the following build errors on architectures without native byte-swap +support: + + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.o: in function `adf_gen4_build_decomp_block': + drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:141:(.text+0xeec): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:141:(.text+0xef8): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.o: in function `adf_gen4_build_comp_block': + drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:57:(.text+0xf64): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:57:(.text+0xf7c): undefined reference to `__bswapsi2' + +Fixes: 5b14b2b307e4 ("crypto: qat - enable deflate for QAT GEN4") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202603290259.Ig9kDOmI-lkp@intel.com/ +Signed-off-by: Giovanni Cabiddu +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +index 7ea8962272f2f..d28732225c9e0 100644 +--- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h ++++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +@@ -3,6 +3,8 @@ + #ifndef _ICP_QAT_HW_20_COMP_H_ + #define _ICP_QAT_HW_20_COMP_H_ + ++#include ++ + #include "icp_qat_hw_20_comp_defs.h" + #include "icp_qat_fw.h" + +@@ -54,7 +56,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_comp_20_config_csr_lower + QAT_FIELD_SET(val32, csr.abd, ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_comp_20_config_csr_upper { +@@ -106,7 +108,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_comp_20_config_csr_upper + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_decomp_20_config_csr_lower { +@@ -138,7 +140,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_decomp_20_config_csr_l + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_decomp_20_config_csr_upper { +@@ -158,7 +160,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_decomp_20_config_csr_u + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + #endif +-- +2.53.0 + diff --git a/queue-6.12/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch b/queue-6.12/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch new file mode 100644 index 0000000000..c8fdf5b08c --- /dev/null +++ b/queue-6.12/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch @@ -0,0 +1,47 @@ +From b898c6191baec1fc0abaf73adb8dda0e5cb063a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 20:06:58 +0530 +Subject: crypto: sa2ul - Fix AEAD fallback algorithm names + +From: T Pratham + +[ Upstream commit 8451ab6ad686ffdcdf9ddadaa446a79ab48e5590 ] + +For authenc AEAD algorithms, sa2ul is trying to register very specific +-ce version as a fallback. This causes registration failure on SoCs +which do not have ARMv8-CE enabled/available. Change the fallback +algorithm from the specific driver name to generic algorithm name so +that the kernel can allocate any available fallback. + +Fixes: d2c8ac187fc92 ("crypto: sa2ul - Add AEAD algorithm support") +Signed-off-by: T Pratham +Reviewed-by: Manorit Chawdhry +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/sa2ul.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c +index 461eca40e8789..d1c2d129ad418 100644 +--- a/drivers/crypto/sa2ul.c ++++ b/drivers/crypto/sa2ul.c +@@ -1775,13 +1775,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, + static int sa_cra_init_aead_sha1(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha1", +- "authenc(hmac(sha1-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha1),cbc(aes))"); + } + + static int sa_cra_init_aead_sha256(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha256", +- "authenc(hmac(sha256-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha256),cbc(aes))"); + } + + static void sa_exit_tfm_aead(struct crypto_aead *tfm) +-- +2.53.0 + diff --git a/queue-6.12/crypto-tegra-disable-softirqs-before-finalizing-requ.patch b/queue-6.12/crypto-tegra-disable-softirqs-before-finalizing-requ.patch new file mode 100644 index 0000000000..937f3c8e3d --- /dev/null +++ b/queue-6.12/crypto-tegra-disable-softirqs-before-finalizing-requ.patch @@ -0,0 +1,98 @@ +From 649ed185744dd44fd21e58feed7b430d74cb96ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 18:28:29 +0900 +Subject: crypto: tegra - Disable softirqs before finalizing request + +From: Herbert Xu + +[ Upstream commit 2aeec9af775fb53aa086419b953302c6f4ad4984 ] + +Softirqs must be disabled when calling the finalization fucntion on +a request. + +Reported-by: Guangwu Zhang +Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/tegra/tegra-se-aes.c | 9 +++++++++ + drivers/crypto/tegra/tegra-se-hash.c | 3 +++ + 2 files changed, 12 insertions(+) + +diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c +index 9210cceb4b7b2..30c78afe3dea6 100644 +--- a/drivers/crypto/tegra/tegra-se-aes.c ++++ b/drivers/crypto/tegra/tegra-se-aes.c +@@ -4,6 +4,7 @@ + * Crypto driver to handle block cipher algorithms using NVIDIA Security Engine. + */ + ++#include + #include + #include + #include +@@ -333,7 +334,9 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, key2_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_skcipher_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1262,7 +1265,9 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_aead_request(ctx->se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1348,7 +1353,9 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_aead_request(ctx->se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1746,7 +1753,9 @@ static int tegra_cmac_do_one_req(struct crypto_engine *engine, void *areq) + if (tegra_key_is_reserved(rctx->key_id)) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + ++ local_bh_disable(); + crypto_finalize_hash_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c +index 024f750bd7eea..327f9c802f6d4 100644 +--- a/drivers/crypto/tegra/tegra-se-hash.c ++++ b/drivers/crypto/tegra/tegra-se-hash.c +@@ -4,6 +4,7 @@ + * Crypto driver to handle HASH algorithms using NVIDIA Security Engine. + */ + ++#include + #include + #include + #include +@@ -498,7 +499,9 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq) + } + + out: ++ local_bh_disable(); + crypto_finalize_hash_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/crypto-tegra-finalize-crypto-req-on-error.patch b/queue-6.12/crypto-tegra-finalize-crypto-req-on-error.patch new file mode 100644 index 0000000000..49050e1af9 --- /dev/null +++ b/queue-6.12/crypto-tegra-finalize-crypto-req-on-error.patch @@ -0,0 +1,123 @@ +From 230ab684860bd1581dae0c6508306cddc9b2d501 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Feb 2025 14:46:03 +0530 +Subject: crypto: tegra - finalize crypto req on error + +From: Akhil R + +[ Upstream commit 1e245948ca0c252f561792fabb45de5518301d97 ] + +Call the crypto finalize function before exiting *do_one_req() functions. +This allows the driver to take up further requests even if the previous +one fails. + +Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver") +Signed-off-by: Akhil R +Signed-off-by: Herbert Xu +Stable-dep-of: 2aeec9af775f ("crypto: tegra - Disable softirqs before finalizing request") +Signed-off-by: Sasha Levin +--- + drivers/crypto/tegra/tegra-se-aes.c | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c +index 073431a110bdf..2af5d86856bb1 100644 +--- a/drivers/crypto/tegra/tegra-se-aes.c ++++ b/drivers/crypto/tegra/tegra-se-aes.c +@@ -275,8 +275,10 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) + rctx->datbuf.size = rctx->len; + rctx->datbuf.buf = dma_alloc_coherent(se->dev, rctx->datbuf.size, + &rctx->datbuf.addr, GFP_KERNEL); +- if (!rctx->datbuf.buf) +- return -ENOMEM; ++ if (!rctx->datbuf.buf) { ++ ret = -ENOMEM; ++ goto out_finalize; ++ } + + scatterwalk_map_and_copy(rctx->datbuf.buf, req->src, 0, req->cryptlen, 0); + +@@ -292,6 +294,7 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) + dma_free_coherent(ctx->se->dev, rctx->datbuf.size, + rctx->datbuf.buf, rctx->datbuf.addr); + ++out_finalize: + crypto_finalize_skcipher_request(se->engine, req, ret); + + return 0; +@@ -1153,21 +1156,21 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) + + ret = tegra_ccm_crypt_init(req, se, rctx); + if (ret) +- return ret; ++ goto out_finalize; + + /* Allocate buffers required */ + rctx->inbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen + 100; + rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->inbuf.size, + &rctx->inbuf.addr, GFP_KERNEL); + if (!rctx->inbuf.buf) +- return -ENOMEM; ++ goto out_finalize; + + rctx->outbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen + 100; + rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->outbuf.size, + &rctx->outbuf.addr, GFP_KERNEL); + if (!rctx->outbuf.buf) { + ret = -ENOMEM; +- goto outbuf_err; ++ goto out_free_inbuf; + } + + if (rctx->encrypt) { +@@ -1196,10 +1199,11 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) + dma_free_coherent(ctx->se->dev, rctx->inbuf.size, + rctx->outbuf.buf, rctx->outbuf.addr); + +-outbuf_err: ++out_free_inbuf: + dma_free_coherent(ctx->se->dev, rctx->outbuf.size, + rctx->inbuf.buf, rctx->inbuf.addr); + ++out_finalize: + crypto_finalize_aead_request(ctx->se->engine, req, ret); + + return 0; +@@ -1230,15 +1234,17 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) + rctx->inbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen; + rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->inbuf.size, + &rctx->inbuf.addr, GFP_KERNEL); +- if (!rctx->inbuf.buf) +- return -ENOMEM; ++ if (!rctx->inbuf.buf) { ++ ret = -ENOMEM; ++ goto out_finalize; ++ } + + rctx->outbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen; + rctx->outbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->outbuf.size, + &rctx->outbuf.addr, GFP_KERNEL); + if (!rctx->outbuf.buf) { + ret = -ENOMEM; +- goto outbuf_err; ++ goto out_free_inbuf; + } + + /* If there is associated data perform GMAC operation */ +@@ -1267,11 +1273,11 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) + dma_free_coherent(ctx->se->dev, rctx->outbuf.size, + rctx->outbuf.buf, rctx->outbuf.addr); + +-outbuf_err: ++out_free_inbuf: + dma_free_coherent(ctx->se->dev, rctx->inbuf.size, + rctx->inbuf.buf, rctx->inbuf.addr); + +- /* Finalize the request if there are no errors */ ++out_finalize: + crypto_finalize_aead_request(ctx->se->engine, req, ret); + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/crypto-tegra-reserve-keyslots-to-allocate-dynamicall.patch b/queue-6.12/crypto-tegra-reserve-keyslots-to-allocate-dynamicall.patch new file mode 100644 index 0000000000..376fd5a0fa --- /dev/null +++ b/queue-6.12/crypto-tegra-reserve-keyslots-to-allocate-dynamicall.patch @@ -0,0 +1,500 @@ +From 10941592160bde81ffa39bbcb8595421764ad808 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Feb 2025 14:46:09 +0530 +Subject: crypto: tegra - Reserve keyslots to allocate dynamically + +From: Akhil R + +[ Upstream commit b157e7a228aee9b48c2de05129476b822aa7956d ] + +The HW supports only storing 15 keys at a time. This limits the number +of tfms that can work without failutes. Reserve keyslots to solve this +and use the reserved ones during the encryption/decryption operation. +This allow users to have the capability of hardware protected keys +and faster operations if there are limited number of tfms while not +halting the operation if there are more tfms. + +Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver") +Signed-off-by: Akhil R +Signed-off-by: Herbert Xu +Stable-dep-of: 2aeec9af775f ("crypto: tegra - Disable softirqs before finalizing request") +Signed-off-by: Sasha Levin +--- + drivers/crypto/tegra/tegra-se-aes.c | 139 +++++++++++++++++++++++----- + drivers/crypto/tegra/tegra-se-key.c | 19 +++- + drivers/crypto/tegra/tegra-se.h | 28 ++++++ + 3 files changed, 164 insertions(+), 22 deletions(-) + +diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c +index fbb39436e6d54..9210cceb4b7b2 100644 +--- a/drivers/crypto/tegra/tegra-se-aes.c ++++ b/drivers/crypto/tegra/tegra-se-aes.c +@@ -28,6 +28,9 @@ struct tegra_aes_ctx { + u32 ivsize; + u32 key1_id; + u32 key2_id; ++ u32 keylen; ++ u8 key1[AES_MAX_KEY_SIZE]; ++ u8 key2[AES_MAX_KEY_SIZE]; + }; + + struct tegra_aes_reqctx { +@@ -43,8 +46,9 @@ struct tegra_aead_ctx { + struct tegra_se *se; + unsigned int authsize; + u32 alg; +- u32 keylen; + u32 key_id; ++ u32 keylen; ++ u8 key[AES_MAX_KEY_SIZE]; + }; + + struct tegra_aead_reqctx { +@@ -56,8 +60,8 @@ struct tegra_aead_reqctx { + unsigned int cryptlen; + unsigned int authsize; + bool encrypt; +- u32 config; + u32 crypto_config; ++ u32 config; + u32 key_id; + u32 iv[4]; + u8 authdata[16]; +@@ -67,6 +71,8 @@ struct tegra_cmac_ctx { + struct tegra_se *se; + unsigned int alg; + u32 key_id; ++ u32 keylen; ++ u8 key[AES_MAX_KEY_SIZE]; + struct crypto_shash *fallback_tfm; + }; + +@@ -260,11 +266,13 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) + struct tegra_aes_ctx *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); + struct tegra_aes_reqctx *rctx = skcipher_request_ctx(req); + struct tegra_se *se = ctx->se; +- unsigned int cmdlen; ++ unsigned int cmdlen, key1_id, key2_id; + int ret; + + rctx->iv = (ctx->alg == SE_ALG_ECB) ? NULL : (u32 *)req->iv; + rctx->len = req->cryptlen; ++ key1_id = ctx->key1_id; ++ key2_id = ctx->key2_id; + + /* Pad input to AES Block size */ + if (ctx->alg != SE_ALG_XTS) { +@@ -282,6 +290,29 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) + + scatterwalk_map_and_copy(rctx->datbuf.buf, req->src, 0, req->cryptlen, 0); + ++ rctx->config = tegra234_aes_cfg(ctx->alg, rctx->encrypt); ++ rctx->crypto_config = tegra234_aes_crypto_cfg(ctx->alg, rctx->encrypt); ++ ++ if (!key1_id) { ++ ret = tegra_key_submit_reserved_aes(ctx->se, ctx->key1, ++ ctx->keylen, ctx->alg, &key1_id); ++ if (ret) ++ goto out; ++ } ++ ++ rctx->crypto_config |= SE_AES_KEY_INDEX(key1_id); ++ ++ if (ctx->alg == SE_ALG_XTS) { ++ if (!key2_id) { ++ ret = tegra_key_submit_reserved_xts(ctx->se, ctx->key2, ++ ctx->keylen, ctx->alg, &key2_id); ++ if (ret) ++ goto out; ++ } ++ ++ rctx->crypto_config |= SE_AES_KEY2_INDEX(key2_id); ++ } ++ + /* Prepare the command and submit for execution */ + cmdlen = tegra_aes_prep_cmd(ctx, rctx); + ret = tegra_se_host1x_submit(se, se->cmdbuf, cmdlen); +@@ -290,10 +321,17 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) + tegra_aes_update_iv(req, ctx); + scatterwalk_map_and_copy(rctx->datbuf.buf, req->dst, 0, req->cryptlen, 1); + ++out: + /* Free the buffer */ + dma_free_coherent(ctx->se->dev, rctx->datbuf.size, + rctx->datbuf.buf, rctx->datbuf.addr); + ++ if (tegra_key_is_reserved(key1_id)) ++ tegra_key_invalidate_reserved(ctx->se, key1_id, ctx->alg); ++ ++ if (tegra_key_is_reserved(key2_id)) ++ tegra_key_invalidate_reserved(ctx->se, key2_id, ctx->alg); ++ + out_finalize: + crypto_finalize_skcipher_request(se->engine, req, ret); + +@@ -316,6 +354,7 @@ static int tegra_aes_cra_init(struct crypto_skcipher *tfm) + ctx->se = se_alg->se_dev; + ctx->key1_id = 0; + ctx->key2_id = 0; ++ ctx->keylen = 0; + + algname = crypto_tfm_alg_name(&tfm->base); + ret = se_algname_to_algid(algname); +@@ -344,13 +383,20 @@ static int tegra_aes_setkey(struct crypto_skcipher *tfm, + const u8 *key, u32 keylen) + { + struct tegra_aes_ctx *ctx = crypto_skcipher_ctx(tfm); ++ int ret; + + if (aes_check_keylen(keylen)) { + dev_dbg(ctx->se->dev, "invalid key length (%d)\n", keylen); + return -EINVAL; + } + +- return tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key1_id); ++ ret = tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key1_id); ++ if (ret) { ++ ctx->keylen = keylen; ++ memcpy(ctx->key1, key, keylen); ++ } ++ ++ return 0; + } + + static int tegra_xts_setkey(struct crypto_skcipher *tfm, +@@ -368,11 +414,17 @@ static int tegra_xts_setkey(struct crypto_skcipher *tfm, + + ret = tegra_key_submit(ctx->se, key, len, + ctx->alg, &ctx->key1_id); +- if (ret) +- return ret; ++ if (ret) { ++ ctx->keylen = len; ++ memcpy(ctx->key1, key, len); ++ } + +- return tegra_key_submit(ctx->se, key + len, len, ++ ret = tegra_key_submit(ctx->se, key + len, len, + ctx->alg, &ctx->key2_id); ++ if (ret) { ++ ctx->keylen = len; ++ memcpy(ctx->key2, key + len, len); ++ } + + return 0; + } +@@ -447,12 +499,6 @@ static int tegra_aes_crypt(struct skcipher_request *req, bool encrypt) + return 0; + + rctx->encrypt = encrypt; +- rctx->config = tegra234_aes_cfg(ctx->alg, encrypt); +- rctx->crypto_config = tegra234_aes_crypto_cfg(ctx->alg, encrypt); +- rctx->crypto_config |= SE_AES_KEY_INDEX(ctx->key1_id); +- +- if (ctx->key2_id) +- rctx->crypto_config |= SE_AES_KEY2_INDEX(ctx->key2_id); + + return crypto_transfer_skcipher_request_to_engine(ctx->se->engine, req); + } +@@ -719,7 +765,7 @@ static int tegra_gcm_do_gmac(struct tegra_aead_ctx *ctx, struct tegra_aead_reqct + + rctx->config = tegra234_aes_cfg(SE_ALG_GMAC, rctx->encrypt); + rctx->crypto_config = tegra234_aes_crypto_cfg(SE_ALG_GMAC, rctx->encrypt) | +- SE_AES_KEY_INDEX(ctx->key_id); ++ SE_AES_KEY_INDEX(rctx->key_id); + + cmdlen = tegra_gmac_prep_cmd(ctx, rctx); + +@@ -736,7 +782,7 @@ static int tegra_gcm_do_crypt(struct tegra_aead_ctx *ctx, struct tegra_aead_reqc + + rctx->config = tegra234_aes_cfg(SE_ALG_GCM, rctx->encrypt); + rctx->crypto_config = tegra234_aes_crypto_cfg(SE_ALG_GCM, rctx->encrypt) | +- SE_AES_KEY_INDEX(ctx->key_id); ++ SE_AES_KEY_INDEX(rctx->key_id); + + /* Prepare command and submit */ + cmdlen = tegra_gcm_crypt_prep_cmd(ctx, rctx); +@@ -759,7 +805,7 @@ static int tegra_gcm_do_final(struct tegra_aead_ctx *ctx, struct tegra_aead_reqc + + rctx->config = tegra234_aes_cfg(SE_ALG_GCM_FINAL, rctx->encrypt); + rctx->crypto_config = tegra234_aes_crypto_cfg(SE_ALG_GCM_FINAL, rctx->encrypt) | +- SE_AES_KEY_INDEX(ctx->key_id); ++ SE_AES_KEY_INDEX(rctx->key_id); + + /* Prepare command and submit */ + cmdlen = tegra_gcm_prep_final_cmd(se, cpuvaddr, rctx); +@@ -890,7 +936,7 @@ static int tegra_ccm_do_cbcmac(struct tegra_aead_ctx *ctx, struct tegra_aead_req + rctx->config = tegra234_aes_cfg(SE_ALG_CBC_MAC, rctx->encrypt); + rctx->crypto_config = tegra234_aes_crypto_cfg(SE_ALG_CBC_MAC, + rctx->encrypt) | +- SE_AES_KEY_INDEX(ctx->key_id); ++ SE_AES_KEY_INDEX(rctx->key_id); + + /* Prepare command and submit */ + cmdlen = tegra_cbcmac_prep_cmd(ctx, rctx); +@@ -1077,7 +1123,7 @@ static int tegra_ccm_do_ctr(struct tegra_aead_ctx *ctx, struct tegra_aead_reqctx + + rctx->config = tegra234_aes_cfg(SE_ALG_CTR, rctx->encrypt); + rctx->crypto_config = tegra234_aes_crypto_cfg(SE_ALG_CTR, rctx->encrypt) | +- SE_AES_KEY_INDEX(ctx->key_id); ++ SE_AES_KEY_INDEX(rctx->key_id); + + /* Copy authdata in the top of buffer for encryption/decryption */ + if (rctx->encrypt) +@@ -1158,6 +1204,8 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) + if (ret) + goto out_finalize; + ++ rctx->key_id = ctx->key_id; ++ + /* Allocate buffers required */ + rctx->inbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen + 100; + rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->inbuf.size, +@@ -1173,6 +1221,13 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) + goto out_free_inbuf; + } + ++ if (!ctx->key_id) { ++ ret = tegra_key_submit_reserved_aes(ctx->se, ctx->key, ++ ctx->keylen, ctx->alg, &rctx->key_id); ++ if (ret) ++ goto out; ++ } ++ + if (rctx->encrypt) { + /* CBC MAC Operation */ + ret = tegra_ccm_compute_auth(ctx, rctx); +@@ -1203,6 +1258,9 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) + dma_free_coherent(ctx->se->dev, rctx->outbuf.size, + rctx->inbuf.buf, rctx->inbuf.addr); + ++ if (tegra_key_is_reserved(rctx->key_id)) ++ tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); ++ + out_finalize: + crypto_finalize_aead_request(ctx->se->engine, req, ret); + +@@ -1230,6 +1288,8 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) + memcpy(rctx->iv, req->iv, GCM_AES_IV_SIZE); + rctx->iv[3] = (1 << 24); + ++ rctx->key_id = ctx->key_id; ++ + /* Allocate buffers required */ + rctx->inbuf.size = rctx->assoclen + rctx->authsize + rctx->cryptlen; + rctx->inbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->inbuf.size, +@@ -1247,6 +1307,13 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) + goto out_free_inbuf; + } + ++ if (!ctx->key_id) { ++ ret = tegra_key_submit_reserved_aes(ctx->se, ctx->key, ++ ctx->keylen, ctx->alg, &rctx->key_id); ++ if (ret) ++ goto out; ++ } ++ + /* If there is associated data perform GMAC operation */ + if (rctx->assoclen) { + ret = tegra_gcm_do_gmac(ctx, rctx); +@@ -1277,6 +1344,9 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) + dma_free_coherent(ctx->se->dev, rctx->inbuf.size, + rctx->inbuf.buf, rctx->inbuf.addr); + ++ if (tegra_key_is_reserved(rctx->key_id)) ++ tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); ++ + out_finalize: + crypto_finalize_aead_request(ctx->se->engine, req, ret); + +@@ -1299,6 +1369,7 @@ static int tegra_aead_cra_init(struct crypto_aead *tfm) + + ctx->se = se_alg->se_dev; + ctx->key_id = 0; ++ ctx->keylen = 0; + + ret = se_algname_to_algid(algname); + if (ret < 0) { +@@ -1380,13 +1451,20 @@ static int tegra_aead_setkey(struct crypto_aead *tfm, + const u8 *key, u32 keylen) + { + struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm); ++ int ret; + + if (aes_check_keylen(keylen)) { + dev_dbg(ctx->se->dev, "invalid key length (%d)\n", keylen); + return -EINVAL; + } + +- return tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id); ++ ret = tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id); ++ if (ret) { ++ ctx->keylen = keylen; ++ memcpy(ctx->key, key, keylen); ++ } ++ ++ return 0; + } + + static unsigned int tegra_cmac_prep_cmd(struct tegra_cmac_ctx *ctx, +@@ -1471,6 +1549,7 @@ static int tegra_cmac_do_init(struct ahash_request *req) + rctx->total_len = 0; + rctx->datbuf.size = 0; + rctx->residue.size = 0; ++ rctx->key_id = ctx->key_id; + rctx->task |= SHA_FIRST; + rctx->blk_size = crypto_ahash_blocksize(tfm); + +@@ -1515,7 +1594,7 @@ static int tegra_cmac_do_update(struct ahash_request *req) + rctx->datbuf.size = (req->nbytes + rctx->residue.size) - nresidue; + rctx->total_len += rctx->datbuf.size; + rctx->config = tegra234_aes_cfg(SE_ALG_CMAC, 0); +- rctx->crypto_config = SE_AES_KEY_INDEX(ctx->key_id); ++ rctx->crypto_config = SE_AES_KEY_INDEX(rctx->key_id); + + /* + * Keep one block and residue bytes in residue and +@@ -1641,6 +1720,13 @@ static int tegra_cmac_do_one_req(struct crypto_engine *engine, void *areq) + rctx->task &= ~SHA_INIT; + } + ++ if (!ctx->key_id) { ++ ret = tegra_key_submit_reserved_aes(ctx->se, ctx->key, ++ ctx->keylen, ctx->alg, &rctx->key_id); ++ if (ret) ++ goto out; ++ } ++ + if (rctx->task & SHA_UPDATE) { + ret = tegra_cmac_do_update(req); + if (ret) +@@ -1657,6 +1743,9 @@ static int tegra_cmac_do_one_req(struct crypto_engine *engine, void *areq) + rctx->task &= ~SHA_FINAL; + } + out: ++ if (tegra_key_is_reserved(rctx->key_id)) ++ tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); ++ + crypto_finalize_hash_request(se->engine, req, ret); + + return 0; +@@ -1697,6 +1786,7 @@ static int tegra_cmac_cra_init(struct crypto_tfm *tfm) + + ctx->se = se_alg->se_dev; + ctx->key_id = 0; ++ ctx->keylen = 0; + + ret = se_algname_to_algid(algname); + if (ret < 0) { +@@ -1725,6 +1815,7 @@ static int tegra_cmac_setkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen) + { + struct tegra_cmac_ctx *ctx = crypto_ahash_ctx(tfm); ++ int ret; + + if (aes_check_keylen(keylen)) { + dev_dbg(ctx->se->dev, "invalid key length (%d)\n", keylen); +@@ -1734,7 +1825,13 @@ static int tegra_cmac_setkey(struct crypto_ahash *tfm, const u8 *key, + if (ctx->fallback_tfm) + crypto_shash_setkey(ctx->fallback_tfm, key, keylen); + +- return tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id); ++ ret = tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id); ++ if (ret) { ++ ctx->keylen = keylen; ++ memcpy(ctx->key, key, keylen); ++ } ++ ++ return 0; + } + + static int tegra_cmac_init(struct ahash_request *req) +diff --git a/drivers/crypto/tegra/tegra-se-key.c b/drivers/crypto/tegra/tegra-se-key.c +index 276b261fb6df1..956fa9b4e9b1a 100644 +--- a/drivers/crypto/tegra/tegra-se-key.c ++++ b/drivers/crypto/tegra/tegra-se-key.c +@@ -141,6 +141,23 @@ void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg) + tegra_keyslot_free(keyid); + } + ++void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg) ++{ ++ u8 zkey[AES_MAX_KEY_SIZE] = {0}; ++ ++ if (!keyid) ++ return; ++ ++ /* Overwrite the key with 0s */ ++ tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg); ++} ++ ++inline int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key, ++ u32 keylen, u32 alg, u32 *keyid) ++{ ++ return tegra_key_insert(se, key, keylen, *keyid, alg); ++} ++ + int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u32 *keyid) + { + int ret; +@@ -149,7 +166,7 @@ int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u3 + if (!tegra_key_in_kslt(*keyid)) { + *keyid = tegra_keyslot_alloc(); + if (!(*keyid)) { +- dev_err(se->dev, "failed to allocate key slot\n"); ++ dev_dbg(se->dev, "failed to allocate key slot\n"); + return -ENOMEM; + } + } +diff --git a/drivers/crypto/tegra/tegra-se.h b/drivers/crypto/tegra/tegra-se.h +index e1ec37bfb80a8..85674703a9603 100644 +--- a/drivers/crypto/tegra/tegra-se.h ++++ b/drivers/crypto/tegra/tegra-se.h +@@ -341,6 +341,9 @@ + #define SE_MAX_KEYSLOT 15 + #define SE_MAX_MEM_ALLOC SZ_4M + ++#define TEGRA_AES_RESERVED_KSLT 14 ++#define TEGRA_XTS_RESERVED_KSLT 15 ++ + #define SHA_FIRST BIT(0) + #define SHA_INIT BIT(1) + #define SHA_UPDATE BIT(2) +@@ -501,9 +504,34 @@ void tegra_deinit_aes(struct tegra_se *se); + void tegra_deinit_hash(struct tegra_se *se); + int tegra_key_submit(struct tegra_se *se, const u8 *key, + u32 keylen, u32 alg, u32 *keyid); ++ ++int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key, ++ u32 keylen, u32 alg, u32 *keyid); ++ + void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg); ++void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg); + int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size); + ++static inline int tegra_key_submit_reserved_aes(struct tegra_se *se, const u8 *key, ++ u32 keylen, u32 alg, u32 *keyid) ++{ ++ *keyid = TEGRA_AES_RESERVED_KSLT; ++ return tegra_key_submit_reserved(se, key, keylen, alg, keyid); ++} ++ ++static inline int tegra_key_submit_reserved_xts(struct tegra_se *se, const u8 *key, ++ u32 keylen, u32 alg, u32 *keyid) ++{ ++ *keyid = TEGRA_XTS_RESERVED_KSLT; ++ return tegra_key_submit_reserved(se, key, keylen, alg, keyid); ++} ++ ++static inline bool tegra_key_is_reserved(u32 keyid) ++{ ++ return ((keyid == TEGRA_AES_RESERVED_KSLT) || ++ (keyid == TEGRA_XTS_RESERVED_KSLT)); ++} ++ + /* HOST1x OPCODES */ + static inline u32 host1x_opcode_setpayload(unsigned int payload) + { +-- +2.53.0 + diff --git a/queue-6.12/crypto-tegra-transfer-hash-init-function-to-crypto-e.patch b/queue-6.12/crypto-tegra-transfer-hash-init-function-to-crypto-e.patch new file mode 100644 index 0000000000..4c4e8f4fe7 --- /dev/null +++ b/queue-6.12/crypto-tegra-transfer-hash-init-function-to-crypto-e.patch @@ -0,0 +1,311 @@ +From c239378ed074ccb10398614808cdefbfd816b4f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Feb 2025 14:46:05 +0530 +Subject: crypto: tegra - Transfer HASH init function to crypto engine + +From: Akhil R + +[ Upstream commit 97ee15ea101629d2ffe21d3c5dc03b8d8be43603 ] + +Ahash init() function was called asynchronous to the crypto engine queue. +This could corrupt the request context if there is any ongoing operation +for the same request. Queue the init function as well to the crypto +engine queue so that this scenario can be avoided. + +Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver") +Signed-off-by: Akhil R +Signed-off-by: Herbert Xu +Stable-dep-of: 2aeec9af775f ("crypto: tegra - Disable softirqs before finalizing request") +Signed-off-by: Sasha Levin +--- + drivers/crypto/tegra/tegra-se-aes.c | 81 ++++++++++++--------- + drivers/crypto/tegra/tegra-se-hash.c | 101 +++++++++++++++------------ + drivers/crypto/tegra/tegra-se.h | 5 +- + 3 files changed, 109 insertions(+), 78 deletions(-) + +diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c +index 2af5d86856bb1..fbb39436e6d54 100644 +--- a/drivers/crypto/tegra/tegra-se-aes.c ++++ b/drivers/crypto/tegra/tegra-se-aes.c +@@ -1460,6 +1460,34 @@ static void tegra_cmac_paste_result(struct tegra_se *se, struct tegra_cmac_reqct + se->base + se->hw->regs->result + (i * 4)); + } + ++static int tegra_cmac_do_init(struct ahash_request *req) ++{ ++ struct tegra_cmac_reqctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct tegra_cmac_ctx *ctx = crypto_ahash_ctx(tfm); ++ struct tegra_se *se = ctx->se; ++ int i; ++ ++ rctx->total_len = 0; ++ rctx->datbuf.size = 0; ++ rctx->residue.size = 0; ++ rctx->task |= SHA_FIRST; ++ rctx->blk_size = crypto_ahash_blocksize(tfm); ++ ++ rctx->residue.buf = dma_alloc_coherent(se->dev, rctx->blk_size * 2, ++ &rctx->residue.addr, GFP_KERNEL); ++ if (!rctx->residue.buf) ++ return -ENOMEM; ++ ++ rctx->residue.size = 0; ++ ++ /* Clear any previous result */ ++ for (i = 0; i < CMAC_RESULT_REG_COUNT; i++) ++ writel(0, se->base + se->hw->regs->result + (i * 4)); ++ ++ return 0; ++} ++ + static int tegra_cmac_do_update(struct ahash_request *req) + { + struct tegra_cmac_reqctx *rctx = ahash_request_ctx(req); +@@ -1605,6 +1633,14 @@ static int tegra_cmac_do_one_req(struct crypto_engine *engine, void *areq) + struct tegra_se *se = ctx->se; + int ret = 0; + ++ if (rctx->task & SHA_INIT) { ++ ret = tegra_cmac_do_init(req); ++ if (ret) ++ goto out; ++ ++ rctx->task &= ~SHA_INIT; ++ } ++ + if (rctx->task & SHA_UPDATE) { + ret = tegra_cmac_do_update(req); + if (ret) +@@ -1685,34 +1721,6 @@ static void tegra_cmac_cra_exit(struct crypto_tfm *tfm) + tegra_key_invalidate(ctx->se, ctx->key_id, ctx->alg); + } + +-static int tegra_cmac_init(struct ahash_request *req) +-{ +- struct tegra_cmac_reqctx *rctx = ahash_request_ctx(req); +- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); +- struct tegra_cmac_ctx *ctx = crypto_ahash_ctx(tfm); +- struct tegra_se *se = ctx->se; +- int i; +- +- rctx->total_len = 0; +- rctx->datbuf.size = 0; +- rctx->residue.size = 0; +- rctx->task = SHA_FIRST; +- rctx->blk_size = crypto_ahash_blocksize(tfm); +- +- rctx->residue.buf = dma_alloc_coherent(se->dev, rctx->blk_size * 2, +- &rctx->residue.addr, GFP_KERNEL); +- if (!rctx->residue.buf) +- return -ENOMEM; +- +- rctx->residue.size = 0; +- +- /* Clear any previous result */ +- for (i = 0; i < CMAC_RESULT_REG_COUNT; i++) +- writel(0, se->base + se->hw->regs->result + (i * 4)); +- +- return 0; +-} +- + static int tegra_cmac_setkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen) + { +@@ -1729,6 +1737,17 @@ static int tegra_cmac_setkey(struct crypto_ahash *tfm, const u8 *key, + return tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id); + } + ++static int tegra_cmac_init(struct ahash_request *req) ++{ ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct tegra_cmac_ctx *ctx = crypto_ahash_ctx(tfm); ++ struct tegra_cmac_reqctx *rctx = ahash_request_ctx(req); ++ ++ rctx->task = SHA_INIT; ++ ++ return crypto_transfer_hash_request_to_engine(ctx->se->engine, req); ++} ++ + static int tegra_cmac_update(struct ahash_request *req) + { + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); +@@ -1767,13 +1786,9 @@ static int tegra_cmac_digest(struct ahash_request *req) + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct tegra_cmac_ctx *ctx = crypto_ahash_ctx(tfm); + struct tegra_cmac_reqctx *rctx = ahash_request_ctx(req); +- int ret; + +- ret = tegra_cmac_init(req); +- if (ret) +- return ret; ++ rctx->task |= SHA_INIT | SHA_UPDATE | SHA_FINAL; + +- rctx->task |= SHA_UPDATE | SHA_FINAL; + return crypto_transfer_hash_request_to_engine(ctx->se->engine, req); + } + +diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c +index fb28b7ef726ab..024f750bd7eea 100644 +--- a/drivers/crypto/tegra/tegra-se-hash.c ++++ b/drivers/crypto/tegra/tegra-se-hash.c +@@ -296,6 +296,44 @@ static void tegra_sha_paste_hash_result(struct tegra_se *se, struct tegra_sha_re + se->base + se->hw->regs->result + (i * 4)); + } + ++static int tegra_sha_do_init(struct ahash_request *req) ++{ ++ struct tegra_sha_reqctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm); ++ struct tegra_se *se = ctx->se; ++ ++ if (ctx->fallback) ++ return tegra_sha_fallback_init(req); ++ ++ rctx->total_len = 0; ++ rctx->datbuf.size = 0; ++ rctx->residue.size = 0; ++ rctx->key_id = ctx->key_id; ++ rctx->task |= SHA_FIRST; ++ rctx->alg = ctx->alg; ++ rctx->blk_size = crypto_ahash_blocksize(tfm); ++ rctx->digest.size = crypto_ahash_digestsize(tfm); ++ ++ rctx->digest.buf = dma_alloc_coherent(se->dev, rctx->digest.size, ++ &rctx->digest.addr, GFP_KERNEL); ++ if (!rctx->digest.buf) ++ goto digbuf_fail; ++ ++ rctx->residue.buf = dma_alloc_coherent(se->dev, rctx->blk_size, ++ &rctx->residue.addr, GFP_KERNEL); ++ if (!rctx->residue.buf) ++ goto resbuf_fail; ++ ++ return 0; ++ ++resbuf_fail: ++ dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf, ++ rctx->digest.addr); ++digbuf_fail: ++ return -ENOMEM; ++} ++ + static int tegra_sha_do_update(struct ahash_request *req) + { + struct tegra_sha_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +@@ -435,6 +473,14 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq) + struct tegra_se *se = ctx->se; + int ret = 0; + ++ if (rctx->task & SHA_INIT) { ++ ret = tegra_sha_do_init(req); ++ if (ret) ++ goto out; ++ ++ rctx->task &= ~SHA_INIT; ++ } ++ + if (rctx->task & SHA_UPDATE) { + ret = tegra_sha_do_update(req); + if (ret) +@@ -525,44 +571,6 @@ static void tegra_sha_cra_exit(struct crypto_tfm *tfm) + tegra_key_invalidate(ctx->se, ctx->key_id, ctx->alg); + } + +-static int tegra_sha_init(struct ahash_request *req) +-{ +- struct tegra_sha_reqctx *rctx = ahash_request_ctx(req); +- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); +- struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm); +- struct tegra_se *se = ctx->se; +- +- if (ctx->fallback) +- return tegra_sha_fallback_init(req); +- +- rctx->total_len = 0; +- rctx->datbuf.size = 0; +- rctx->residue.size = 0; +- rctx->key_id = ctx->key_id; +- rctx->task = SHA_FIRST; +- rctx->alg = ctx->alg; +- rctx->blk_size = crypto_ahash_blocksize(tfm); +- rctx->digest.size = crypto_ahash_digestsize(tfm); +- +- rctx->digest.buf = dma_alloc_coherent(se->dev, rctx->digest.size, +- &rctx->digest.addr, GFP_KERNEL); +- if (!rctx->digest.buf) +- goto digbuf_fail; +- +- rctx->residue.buf = dma_alloc_coherent(se->dev, rctx->blk_size, +- &rctx->residue.addr, GFP_KERNEL); +- if (!rctx->residue.buf) +- goto resbuf_fail; +- +- return 0; +- +-resbuf_fail: +- dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf, +- rctx->digest.addr); +-digbuf_fail: +- return -ENOMEM; +-} +- + static int tegra_hmac_fallback_setkey(struct tegra_sha_ctx *ctx, const u8 *key, + unsigned int keylen) + { +@@ -593,6 +601,17 @@ static int tegra_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, + return 0; + } + ++static int tegra_sha_init(struct ahash_request *req) ++{ ++ struct tegra_sha_reqctx *rctx = ahash_request_ctx(req); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm); ++ ++ rctx->task = SHA_INIT; ++ ++ return crypto_transfer_hash_request_to_engine(ctx->se->engine, req); ++} ++ + static int tegra_sha_update(struct ahash_request *req) + { + struct tegra_sha_reqctx *rctx = ahash_request_ctx(req); +@@ -640,16 +659,12 @@ static int tegra_sha_digest(struct ahash_request *req) + struct tegra_sha_reqctx *rctx = ahash_request_ctx(req); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm); +- int ret; + + if (ctx->fallback) + return tegra_sha_fallback_digest(req); + +- ret = tegra_sha_init(req); +- if (ret) +- return ret; ++ rctx->task |= SHA_INIT | SHA_UPDATE | SHA_FINAL; + +- rctx->task |= SHA_UPDATE | SHA_FINAL; + return crypto_transfer_hash_request_to_engine(ctx->se->engine, req); + } + +diff --git a/drivers/crypto/tegra/tegra-se.h b/drivers/crypto/tegra/tegra-se.h +index e196a90eedb92..e1ec37bfb80a8 100644 +--- a/drivers/crypto/tegra/tegra-se.h ++++ b/drivers/crypto/tegra/tegra-se.h +@@ -342,8 +342,9 @@ + #define SE_MAX_MEM_ALLOC SZ_4M + + #define SHA_FIRST BIT(0) +-#define SHA_UPDATE BIT(1) +-#define SHA_FINAL BIT(2) ++#define SHA_INIT BIT(1) ++#define SHA_UPDATE BIT(2) ++#define SHA_FINAL BIT(3) + + /* Security Engine operation modes */ + enum se_aes_alg { +-- +2.53.0 + diff --git a/queue-6.12/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch b/queue-6.12/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch new file mode 100644 index 0000000000..ff23457e81 --- /dev/null +++ b/queue-6.12/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch @@ -0,0 +1,47 @@ +From 6cfd000846f13b8f8ff69acdb9bf803a684a1066 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 15:06:33 +0800 +Subject: cxl/pci: Check memdev driver binding status in cxl_reset_done() + +From: Li Ming + +[ Upstream commit e8069c66d09309579e53567be8ddfa6ccb2f452a ] + +cxl_reset_done() accesses the endpoint of the corresponding CXL memdev +without endpoint validity checking. By default, cxlmd->endpoint is +initialized to -ENXIO, if cxl_reset_done() is triggered after the +corresponding CXL memdev probing failed, this results in access to an +invalid endpoint. + +CXL subsystem can always check CXL memdev driver binding status to +confirm its endpoint validity. So adding the CXL memdev driver checking +inside cxl_reset_done() to avoid accessing an invalid endpoint. + +Fixes: 934edcd436dc ("cxl: Add post-reset warning if reset results in loss of previously committed HDM decoders") +Reviewed-by: Dan Williams +Reviewed-by: Dave Jiang +Signed-off-by: Li Ming +Link: https://patch.msgid.link/20260314-fix_access_endpoint_without_drv_check-v2-4-4c09edf2e1db@zohomail.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c +index 6e553b5752b1d..09a2bc817d645 100644 +--- a/drivers/cxl/pci.c ++++ b/drivers/cxl/pci.c +@@ -994,6 +994,9 @@ static void cxl_reset_done(struct pci_dev *pdev) + * that no longer exists. + */ + guard(device)(&cxlmd->dev); ++ if (!cxlmd->dev.driver) ++ return; ++ + if (cxlmd->endpoint && + cxl_endpoint_decoder_reset_detected(cxlmd->endpoint)) { + dev_crit(dev, "SBR happened without memory regions removal.\n"); +-- +2.53.0 + diff --git a/queue-6.12/debugfs-check-for-null-pointer-in-debugfs_create_str.patch b/queue-6.12/debugfs-check-for-null-pointer-in-debugfs_create_str.patch new file mode 100644 index 0000000000..982741fcfc --- /dev/null +++ b/queue-6.12/debugfs-check-for-null-pointer-in-debugfs_create_str.patch @@ -0,0 +1,52 @@ +From 3eeec96724630b00269937f45443f76e8883eb19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:44 +0800 +Subject: debugfs: check for NULL pointer in debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 31de83980d3764d784f79ff1bc93c42b324f4013 ] + +Passing a NULL pointer to debugfs_create_str() leads to a NULL pointer +dereference when the debugfs file is read. Following upstream +discussions, forbid the creation of debugfs string files with NULL +pointers. Add a WARN_ON() to expose offending callers and return early. + +Fixes: 9af0440ec86e ("debugfs: Implement debugfs_create_str()") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/2025122221-gag-malt-75ba@gregkh/ +Suggested-by: Greg Kroah-Hartman +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-2-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index 67299e8b734ed..d3ffd954d6f94 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -1071,7 +1071,7 @@ static const struct file_operations fops_str_wo = { + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write +- * from. ++ * from. This pointer and the string it points to must not be %NULL. + * + * This function creates a file in debugfs with the given name that + * contains the value of the variable @value. If the @mode variable is so +@@ -1080,6 +1080,9 @@ static const struct file_operations fops_str_wo = { + void debugfs_create_str(const char *name, umode_t mode, + struct dentry *parent, char **value) + { ++ if (WARN_ON(!value || !*value)) ++ return; ++ + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } +-- +2.53.0 + diff --git a/queue-6.12/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch b/queue-6.12/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch new file mode 100644 index 0000000000..d90ebb22bb --- /dev/null +++ b/queue-6.12/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch @@ -0,0 +1,45 @@ +From c65181101492e8a41df9b0bcf378b0d4e24dc860 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:45 +0800 +Subject: debugfs: fix placement of EXPORT_SYMBOL_GPL for debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 4afc929c0f74c4f22b055a82b371d50586da58ca ] + +The EXPORT_SYMBOL_GPL() for debugfs_create_str was placed incorrectly +away from the function definition. Move it immediately below the +debugfs_create_str() function where it belongs. + +Fixes: d60b59b96795 ("debugfs: Export debugfs_create_str symbol") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-3-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index d3ffd954d6f94..cc9587a1c9a9f 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -991,7 +991,6 @@ ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf, + + return ret; + } +-EXPORT_SYMBOL_GPL(debugfs_create_str); + + static ssize_t debugfs_write_file_str(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +@@ -1086,6 +1085,7 @@ void debugfs_create_str(const char *name, umode_t mode, + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } ++EXPORT_SYMBOL_GPL(debugfs_create_str); + + static ssize_t read_file_blob(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +-- +2.53.0 + diff --git a/queue-6.12/devres-fix-missing-node-debug-info-in-devm_krealloc.patch b/queue-6.12/devres-fix-missing-node-debug-info-in-devm_krealloc.patch new file mode 100644 index 0000000000..d0d5f621b1 --- /dev/null +++ b/queue-6.12/devres-fix-missing-node-debug-info-in-devm_krealloc.patch @@ -0,0 +1,37 @@ +From 11b8a652d5bcf06abc648bb178405980be97e627 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 00:48:14 +0100 +Subject: devres: fix missing node debug info in devm_krealloc() + +From: Danilo Krummrich + +[ Upstream commit f813ec9e84b4d0ca81ec1da94ab07bfb4a29266c ] + +Fix missing call to set_node_dbginfo() for new devres nodes created by +devm_krealloc(). + +Fixes: f82485722e5d ("devres: provide devm_krealloc()") +Reviewed-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/20260202235210.55176-2-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/base/devres.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index 68224f2f83fff..f229c5b3e7850 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -913,6 +913,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) + if (!new_dr) + return NULL; + ++ set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size); ++ + /* + * The spinlock protects the linked list against concurrent + * modifications but not the resource itself. +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-fix-concurrent-write-failure-in-passthrough.patch b/queue-6.12/dm-cache-fix-concurrent-write-failure-in-passthrough.patch new file mode 100644 index 0000000000..55689a0d24 --- /dev/null +++ b/queue-6.12/dm-cache-fix-concurrent-write-failure-in-passthrough.patch @@ -0,0 +1,84 @@ +From ce4dc13450645f358fcb1b50db7e4c68fe7f739c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:09 +0800 +Subject: dm cache: fix concurrent write failure in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit e4f66341779d0cf4c83c74793753a84094286d9e ] + +When bio prison cell lock acquisition fails due to concurrent writes to +the same block in passthrough mode, dm-cache incorrectly returns an I/O +error instead of properly handling the concurrency. This can occur in +both process and workqueue contexts when invalidate_lock() is called for +exclusive access to a data block. Fix this by deferring the write bios +to ensure proper block device behavior. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently. Sometimes one of the + processes will receive I/O errors. + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + + + fio-3.41 + fio: io_u error on file /dev/mapper/cache: Input/output error: write offset=4096, buflen=4096 + fio: pid=106, err=5/file:io_u.c:2008, func=io_u error, error=Input/output error + test: (groupid=0, jobs=1): err= 0: pid=105 + test: (groupid=0, jobs=1): err= 5 (file:io_u.c:2008, func=io_u error, error=Input/output error): pid=106 + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 2f882eb77dacf..13543b5b3aa04 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1555,6 +1555,15 @@ static int invalidate_lock(struct dm_cache_migration *mg) + READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell); + if (r < 0) { + free_prison_cell(cache, prealloc); ++ ++ /* Defer the bio for retrying the cell lock */ ++ if (mg->overwrite_bio) { ++ struct bio *bio = mg->overwrite_bio; ++ ++ mg->overwrite_bio = NULL; ++ defer_bio(cache, bio); ++ } ++ + invalidate_complete(mg, false); + return r; + } +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch b/queue-6.12/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch new file mode 100644 index 0000000000..c180b09fd9 --- /dev/null +++ b/queue-6.12/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch @@ -0,0 +1,151 @@ +From ae013d91bf870ebdc53a70a1785dfce13c0e73c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:10 +0800 +Subject: dm cache: fix dirty mapping checking in passthrough mode switching + +From: Ming-Hung Tsai + +[ Upstream commit 322586745bd1a0e5f3559fd1635fdeb4dbd1d6b8 ] + +As mentioned in commit 9b1cc9f251af ("dm cache: share cache-metadata +object across inactive and active DM tables"), dm-cache assumed table +reload occurs after suspension, while LVM's table preload breaks this +assumption. The dirty mapping check for passthrough mode was designed +around this assumption and is performed during table creation, causing +the check to fail with preload while metadata updates are ongoing. This +risks loading dirty mappings into passthrough mode, resulting in data +loss. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty mappings + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Preload a table in passthrough mode + +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" + +3. Write to the first cache block to make it dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +4. Resume the inactive table. Now it's possible to load the dirty block + into passthrough mode. + +dmsetup resume cache + +Fix by moving the checks to the preresume phase to support table +preloading. Also remove the unused function dm_cache_metadata_all_clean. + +Fixes: 2ee57d587357 ("dm cache: add passthrough mode") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 11 ----------- + drivers/md/dm-cache-metadata.h | 5 ----- + drivers/md/dm-cache-target.c | 25 ++++++++----------------- + 3 files changed, 8 insertions(+), 33 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 24cd87fddf752..4447679cfc471 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1747,17 +1747,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * + return r; + } + +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) +-{ +- int r; +- +- READ_LOCK(cmd); +- r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); +- READ_UNLOCK(cmd); +- +- return r; +-} +- + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) + { + WRITE_LOCK_VOID(cmd); +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 57afc70479472..24e4af14fcca4 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -138,11 +138,6 @@ void dm_cache_dump(struct dm_cache_metadata *cmd); + */ + int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p); + +-/* +- * Query method. Are all the blocks in the cache clean? +- */ +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); +- + int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); + int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index c9a7fd97b7304..68751841e124f 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2506,23 +2506,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) + goto bad; + } + +- if (passthrough_mode(cache)) { +- bool all_clean; +- +- r = dm_cache_metadata_all_clean(cache->cmd, &all_clean); +- if (r) { +- *error = "dm_cache_metadata_all_clean() failed"; +- goto bad; +- } +- +- if (!all_clean) { +- *error = "Cannot enter passthrough mode unless all blocks are clean"; +- r = -EINVAL; +- goto bad; +- } +- ++ if (passthrough_mode(cache)) + policy_allow_migrations(cache->policy, false); +- } + + spin_lock_init(&cache->lock); + bio_list_init(&cache->deferred_bios); +@@ -2848,6 +2833,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + struct cache *cache = context; + + if (dirty) { ++ if (passthrough_mode(cache)) { ++ DMERR("%s: cannot enter passthrough mode unless all blocks are clean", ++ cache_device_name(cache)); ++ return -EBUSY; ++ } ++ + set_bit(from_cblock(cblock), cache->dirty_bitset); + atomic_inc(&cache->nr_dirty); + } else +@@ -3081,7 +3072,7 @@ static int cache_preresume(struct dm_target *ti) + load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- if (r != -EFBIG) ++ if (r != -EFBIG && r != -EBUSY) + metadata_operation_failed(cache, "dm_cache_load_mappings", r); + return r; + } +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-fix-missing-return-in-invalidate_committed-.patch b/queue-6.12/dm-cache-fix-missing-return-in-invalidate_committed-.patch new file mode 100644 index 0000000000..17389f41f7 --- /dev/null +++ b/queue-6.12/dm-cache-fix-missing-return-in-invalidate_committed-.patch @@ -0,0 +1,51 @@ +From 44565f1bbe5d02fd7e58844aff13692a1e145377 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 21:08:01 +0800 +Subject: dm cache: fix missing return in invalidate_committed's error path + +From: Ming-Hung Tsai + +[ Upstream commit 8c0ee19db81f0fa1ff25fd75b22b17c0cc2acde3 ] + +In passthrough mode, dm-cache defers write submission until after +metadata commit completes via the invalidate_committed() continuation. +On commit error, invalidate_committed() calls invalidate_complete() to +end the bio and free the migration struct, after which it should return +immediately. + +The patch 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +omitted this early return, causing execution to fall through into the +success path on error. This results in use-after-free on the migration +struct in the subsequent calls. + +Fix by adding the missing return after the invalidate_complete() call. + +Fixes: 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/dm-devel/adjMq6T5RRjv_uxM@stanley.mountain/ +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 68751841e124f..3a7881c0a5b13 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1521,8 +1521,10 @@ static void invalidate_committed(struct work_struct *ws) + struct bio *bio = mg->overwrite_bio; + struct per_bio_data *pb = get_per_bio_data(bio); + +- if (mg->k.input) ++ if (mg->k.input) { + invalidate_complete(mg, false); ++ return; ++ } + + init_continuation(&mg->k, invalidate_completed); + remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch b/queue-6.12/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch new file mode 100644 index 0000000000..a4f1bb6389 --- /dev/null +++ b/queue-6.12/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch @@ -0,0 +1,86 @@ +From ad8d1a0257d0f66e2a4f1a8ed434291f6c788aad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:05 +0800 +Subject: dm cache: fix null-deref with concurrent writes in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 7d1f98d668ee34c1d15bdc0420fdd062f24a27c0 ] + +In passthrough mode, when dm-cache starts to invalidate a cache +entry and bio prison cell lock fails due to concurrent write to +the same cached block, mg->cell remains NULL. The error path in +invalidate_complete() attempts to unlock and free the cell +unconditionally, causing a NULL pointer dereference: + +KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +CPU: 0 UID: 0 PID: 134 Comm: fio Not tainted 6.19.0-rc7 #3 PREEMPT +RIP: 0010:dm_cell_unlock_v2+0x3f/0x210 + +Call Trace: + invalidate_complete+0xef/0x430 + map_bio+0x130f/0x1a10 + cache_map+0x320/0x6b0 + __map_bio+0x458/0x510 + dm_submit_bio+0x40e/0x16d0 + __submit_bio+0x419/0x870 + + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + +Fix by checking if mg->cell is valid before attempting to unlock it. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 6aa4095dc5876..c1e94ffc9b3d6 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1456,8 +1456,10 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + struct cache *cache = mg->cache; + + bio_list_init(&bios); +- if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) +- free_prison_cell(cache, mg->cell); ++ if (mg->cell) { ++ if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) ++ free_prison_cell(cache, mg->cell); ++ } + + if (!success && mg->overwrite_bio) + bio_io_error(mg->overwrite_bio); +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-fix-write-hang-in-passthrough-mode.patch b/queue-6.12/dm-cache-fix-write-hang-in-passthrough-mode.patch new file mode 100644 index 0000000000..16ac113601 --- /dev/null +++ b/queue-6.12/dm-cache-fix-write-hang-in-passthrough-mode.patch @@ -0,0 +1,88 @@ +From 2601213d90f755e980066d5e4a185480609926ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:07 +0800 +Subject: dm cache: fix write hang in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 4ca8b8bd952df7c3ccdc68af9bd3419d0839a04b ] + +The invalidate_remove() function has incomplete logic for handling write +hit bios after cache invalidation. It sets up the remapping for the +overwrite_bio but then drops it immediately without submission, causing +write operations to hang. + +Fix by adding a new invalidate_committed() continuation that submits +the remapped writes to the cache origin after metadata commit completes, +while using the overwrite_endio hook to ensure proper completion +sequencing. This maintains existing coherency. Also improve error +handling in invalidate_complete() to preserve the original error status +instead of using bio_io_error() unconditionally. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 61f6050479d15..2f882eb77dacf 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1461,8 +1461,14 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + free_prison_cell(cache, mg->cell); + } + +- if (!success && mg->overwrite_bio) +- bio_io_error(mg->overwrite_bio); ++ if (mg->overwrite_bio) { ++ // Set generic error if the bio hasn't been issued yet, ++ // e.g., invalidation or metadata commit failed before bio ++ // submission. Otherwise preserve the bio's own error status. ++ if (!success && !mg->overwrite_bio->bi_status) ++ mg->overwrite_bio->bi_status = BLK_STS_IOERR; ++ bio_endio(mg->overwrite_bio); ++ } + + free_migration(mg); + defer_bios(cache, &bios); +@@ -1502,6 +1508,22 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock) + return r; + } + ++static void invalidate_committed(struct work_struct *ws) ++{ ++ struct dm_cache_migration *mg = ws_to_mg(ws); ++ struct cache *cache = mg->cache; ++ struct bio *bio = mg->overwrite_bio; ++ struct per_bio_data *pb = get_per_bio_data(bio); ++ ++ if (mg->k.input) ++ invalidate_complete(mg, false); ++ ++ init_continuation(&mg->k, invalidate_completed); ++ remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); ++ dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg); ++ dm_submit_bio_remap(bio, NULL); ++} ++ + static void invalidate_remove(struct work_struct *ws) + { + int r; +@@ -1514,10 +1536,8 @@ static void invalidate_remove(struct work_struct *ws) + return; + } + +- init_continuation(&mg->k, invalidate_completed); ++ init_continuation(&mg->k, invalidate_committed); + continue_after_commit(&cache->committer, &mg->k); +- remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock); +- mg->overwrite_bio = NULL; + schedule_commit(&cache->committer); + } + +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch b/queue-6.12/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch new file mode 100644 index 0000000000..8ac01566e3 --- /dev/null +++ b/queue-6.12/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch @@ -0,0 +1,85 @@ +From ed90d06da6ac314f86a6f648602b7d92b324fc2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:06 +0800 +Subject: dm cache: fix write path cache coherency in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 0c5eef0aad508231d8e43ff8392692925e131b68 ] + +In passthrough mode, dm-cache defers write bio submission until cache +invalidation completes to maintain existing coherency, requiring the +target map function to return DM_MAPIO_SUBMITTED. The current map_bio() +returns DM_MAPIO_REMAPPED, violating the required ordering constraint. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into the cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first data block, and check io ordering using ftrace + +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_queue/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_complete/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_rq_complete/enable +fio --filename=/dev/mapper/cache --name=test --rw=write --bs=64k \ +--direct=1 --size 64k + +5. ftrace logs show that write operations to the cache origin (252:2) + and metadata operations (252:0) are unsynchronized: the origin write + occurs before metadata commit. + + + fio-146 [000] ..... 420.139562: block_bio_queue: 252,3 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149395: block_bio_queue: 252,2 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149763: block_bio_queue: 8,32 WS 262144 + 128 [fio] + fio-146 [000] dNh1. 420.151446: block_rq_complete: 8,32 WS () 262144 + 128 be,0,4 [0] + fio-146 [000] dNh1. 420.152731: block_bio_complete: 252,2 WS 0 + 128 [0] + fio-146 [000] dNh1. 420.154229: block_bio_complete: 252,3 WS 0 + 128 [0] + kworker/0:0-9 [000] ..... 420.160530: block_bio_queue: 252,0 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.161641: block_bio_queue: 8,32 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162533: block_bio_queue: 252,0 W 416 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162821: block_bio_queue: 8,32 W 416 + 8 [kworker/0:0] + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index c1e94ffc9b3d6..61f6050479d15 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1697,6 +1697,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, + bio_drop_shared_lock(cache, bio); + atomic_inc(&cache->stats.demotion); + invalidate_start(cache, cblock, block, bio); ++ return DM_MAPIO_SUBMITTED; + } else + remap_to_origin_clear_discard(cache, bio, block); + } else { +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch b/queue-6.12/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch new file mode 100644 index 0000000000..7d5bf0e3e0 --- /dev/null +++ b/queue-6.12/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch @@ -0,0 +1,121 @@ +From 312a7857710610f91737a8a1b230b1910afcd72d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:56:28 +0800 +Subject: dm cache metadata: fix memory leak on metadata abort retry + +From: Ming-Hung Tsai + +[ Upstream commit 044ca491d4086dc5bf233e9fcb71db52df32f633 ] + +When failing to acquire the root_lock in dm_cache_metadata_abort because +the block_manager is read-only, the temporary block_manager created +outside the root_lock is not properly released, causing a memory leak. + +Reproduce steps: + +This can be reproduced by reloading a new table while the metadata +is read-only. While the second call to dm_cache_metadata_abort is +caused by lack of support for table preload in dm-cache, mentioned +in commit 9b1cc9f251af ("dm cache: share cache-metadata object across +inactive and active DM tables"), it exposes the memory leak in +dm_cache_metadata_abort when the function is called multiple times. +Specifically, dm-cache fails to sync the new cache object's mode during +preresume, creating the reproducer condition. + +This issue could also occur through concurrent metadata_operation_failed +calls due to races in cache mode updates, but the table preload scenario +below provides a reliable reproducer. + +1. Create a cache device with some faulty trailing metadata blocks + +dmsetup create cmeta < +unreferenced object 0xffff8880080c2010 (size 16): + comm "dmsetup", pid 132, jiffies 4294982580 + hex dump (first 16 bytes): + 00 38 b9 07 80 88 ff ff 6a 6b 6b 6b 6b 6b 6b a5 ... + backtrace (crc 3118f31c): + kmemleak_alloc+0x28/0x40 + __kmalloc_cache_noprof+0x3d9/0x510 + dm_block_manager_create+0x51/0x140 + dm_cache_metadata_abort+0x85/0x320 + metadata_operation_failed+0x103/0x1e0 + cache_preresume+0xacd/0xe70 + dm_table_resume_targets+0xd3/0x320 + __dm_resume+0x1b/0xf0 + dm_resume+0x127/0x170 + + +Fixes: 352b837a5541 ("dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 4447679cfc471..1328327d1d372 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1023,6 +1023,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd) + return; \ + } while (0) + ++#define WRITE_LOCK_OR_GOTO(cmd, label) \ ++ do { \ ++ if (!cmd_write_lock((cmd))) \ ++ goto label; \ ++ } while (0) ++ + #define WRITE_UNLOCK(cmd) \ + up_write(&(cmd)->root_lock) + +@@ -1813,11 +1819,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, + CACHE_MAX_CONCURRENT_LOCKS); + +- WRITE_LOCK(cmd); +- if (cmd->fail_io) { +- WRITE_UNLOCK(cmd); +- goto out; +- } ++ /* cmd_write_lock() already checks fail_io with cmd->root_lock held */ ++ WRITE_LOCK_OR_GOTO(cmd, out); + + __destroy_persistent_data_objects(cmd, false); + old_bm = cmd->bm; +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch b/queue-6.12/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch new file mode 100644 index 0000000000..34a31a8fa4 --- /dev/null +++ b/queue-6.12/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch @@ -0,0 +1,91 @@ +From c5cd272f71a0418e6e37d62ce601efc3c5ba835d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:08 +0800 +Subject: dm cache policy smq: fix missing locks in invalidating cache blocks + +From: Ming-Hung Tsai + +[ Upstream commit 2d1f7b65f5deedd2e6b09fdc6ea27f8375f24b45 ] + +In passthrough mode, the policy invalidate_mapping operation is called +simultaneously from multiple workers, thus it should be protected by a +lock. Otherwise, we might end up with data races on the allocated blocks +counter, or even use-after-free issues with internal data structures +when doing concurrent writes. + +Note that the existing FIXME in smq_invalidate_mapping() doesn't affect +passthrough mode since migration tasks don't exist there, but would need +attention if supporting fast device shrinking via suspend/resume without +target reloading. + +Reproduce steps: + +1. Create a cache device consisting of 1024 cache entries + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Populate the cache, and record the number of cached blocks + +fio --name=populate --filename=/dev/mapper/cache --rw=randwrite --bs=4k \ +--size=64m --direct=1 +nr_cached=$(dmsetup status cache | awk '{split($7, a, "/"); print a[1]}') + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the passthrough cache. By setting multiple jobs with I/O + size equal to the cache block size, cache blocks are invalidated + concurrently from different workers. + +fio --filename=/dev/mapper/cache --name=test --rw=randwrite --bs=64k \ +--direct=1 --numjobs=2 --randrepeat=0 --size=64m + +5. Check if demoted matches cached block count. These numbers should + match but may differ due to the data race. + +nr_demoted=$(dmsetup status cache | awk '{print $12}') +echo "$nr_cached, $nr_demoted" + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 2ed894155cabb..d81a87142cacf 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1589,14 +1589,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + { + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); ++ unsigned long flags; + + if (!e->allocated) + return -ENODATA; + ++ spin_lock_irqsave(&mq->lock, flags); + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ spin_unlock_irqrestore(&mq->lock, flags); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.12/dm-cache-support-shrinking-the-origin-device.patch b/queue-6.12/dm-cache-support-shrinking-the-origin-device.patch new file mode 100644 index 0000000000..3ad7bb4067 --- /dev/null +++ b/queue-6.12/dm-cache-support-shrinking-the-origin-device.patch @@ -0,0 +1,197 @@ +From 9c4c0f7eca1eaa57ab1b45ef8f982d7386ae3776 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 16:41:51 +0800 +Subject: dm cache: support shrinking the origin device + +From: Ming-Hung Tsai + +[ Upstream commit c2662b1544cbd8ea3181381bb899b8e681dfedc7 ] + +This patch introduces formal support for shrinking the cache origin by +reducing the cache target length via table reloads. Cache blocks mapped +beyond the new target length must be clean and are invalidated during +preresume. If any dirty blocks exist in the area being removed, the +preresume operation fails without setting the NEEDS_CHECK flag in +superblock, and the resume ioctl returns EFBIG. The cache device remains +suspended until a table reload with target length that fits existing +mappings is performed. + +Without this patch, reducing the cache target length could result in +io errors (RHBZ: 2134334), out-of-bounds memory access to the discard +bitset, and security concerns regarding data leakage. + +Verification steps: + +1. create a cache metadata with some cached blocks mapped to the tail + of the origin device. Here we use cache_restore v1.0 to build a + metadata with one clean block mapped to the last origin block. + +cat <> cmeta.xml + + + + + +EOF +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +cache_restore -i cmeta.xml -o /dev/mapper/cmeta --metadata-version=2 +dmsetup remove cmeta + +2. bring up the cache whilst shrinking the cache origin by one block: + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" +dmsetup create corig --table "0 524160 linear /dev/sdc 262144" +dmsetup create cache --table "0 524160 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +3. check the number of cached data blocks via dmsetup status. It is + expected to be zero. + +dmsetup status cache | cut -d ' ' -f 7 + +In addition to the script above, this patch can be verified using the +"cache/resize" tests in dmtest-python: + +./dmtest run --rx cache/resize/shrink_origin --result-set default + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Stable-dep-of: 322586745bd1 ("dm cache: fix dirty mapping checking in passthrough mode switching") +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 72 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 69 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 13543b5b3aa04..c9a7fd97b7304 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -406,6 +406,12 @@ struct cache { + mempool_t migration_pool; + + struct bio_set bs; ++ ++ /* ++ * Cache_size entries. Set bits indicate blocks mapped beyond the ++ * target length, which are marked for invalidation. ++ */ ++ unsigned long *invalid_bitset; + }; + + struct per_bio_data { +@@ -1954,6 +1960,9 @@ static void __destroy(struct cache *cache) + if (cache->discard_bitset) + free_bitset(cache->discard_bitset); + ++ if (cache->invalid_bitset) ++ free_bitset(cache->invalid_bitset); ++ + if (cache->copier) + dm_kcopyd_client_destroy(cache->copier); + +@@ -2542,6 +2551,13 @@ static int cache_create(struct cache_args *ca, struct cache **result) + } + clear_bitset(cache->discard_bitset, from_dblock(cache->discard_nr_blocks)); + ++ cache->invalid_bitset = alloc_bitset(from_cblock(cache->cache_size)); ++ if (!cache->invalid_bitset) { ++ *error = "could not allocate bitset for invalid blocks"; ++ goto bad; ++ } ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + cache->copier = dm_kcopyd_client_create(&dm_kcopyd_throttle); + if (IS_ERR(cache->copier)) { + *error = "could not create kcopyd client"; +@@ -2840,6 +2856,24 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + return policy_load_mapping(cache->policy, oblock, cblock, dirty, hint, hint_valid); + } + ++static int load_filtered_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, ++ bool dirty, uint32_t hint, bool hint_valid) ++{ ++ struct cache *cache = context; ++ ++ if (from_oblock(oblock) >= from_oblock(cache->origin_blocks)) { ++ if (dirty) { ++ DMERR("%s: unable to shrink origin; cache block %u is dirty", ++ cache_device_name(cache), from_cblock(cblock)); ++ return -EFBIG; ++ } ++ set_bit(from_cblock(cblock), cache->invalid_bitset); ++ return 0; ++ } ++ ++ return load_mapping(context, oblock, cblock, dirty, hint, hint_valid); ++} ++ + /* + * The discard block size in the on disk metadata is not + * necessarily the same as we're currently using. So we have to +@@ -2994,6 +3028,24 @@ static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size) + return 0; + } + ++static int truncate_oblocks(struct cache *cache) ++{ ++ uint32_t nr_blocks = from_cblock(cache->cache_size); ++ uint32_t i; ++ int r; ++ ++ for_each_set_bit(i, cache->invalid_bitset, nr_blocks) { ++ r = dm_cache_remove_mapping(cache->cmd, to_cblock(i)); ++ if (r) { ++ DMERR_LIMIT("%s: invalidation failed; couldn't update on disk metadata", ++ cache_device_name(cache)); ++ return r; ++ } ++ } ++ ++ return 0; ++} ++ + static int cache_preresume(struct dm_target *ti) + { + int r = 0; +@@ -3018,11 +3070,25 @@ static int cache_preresume(struct dm_target *ti) + } + + if (!cache->loaded_mappings) { ++ /* ++ * The fast device could have been resized since the last ++ * failed preresume attempt. To be safe we start by a blank ++ * bitset for cache blocks. ++ */ ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + r = dm_cache_load_mappings(cache->cmd, cache->policy, +- load_mapping, cache); ++ load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ if (r != -EFBIG) ++ metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ return r; ++ } ++ ++ r = truncate_oblocks(cache); ++ if (r) { ++ metadata_operation_failed(cache, "dm_cache_remove_mapping", r); + return r; + } + +@@ -3482,7 +3548,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 2, 0}, ++ .version = {2, 3, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-6.12/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch b/queue-6.12/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch new file mode 100644 index 0000000000..9e96d92f09 --- /dev/null +++ b/queue-6.12/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch @@ -0,0 +1,58 @@ +From dab1a858e74b8affe0147dbaabdc8a537dfdd06c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 22:32:28 +0100 +Subject: dm init: ensure device probing has finished in dm-mod.waitfor= + +From: Guillaume Gonnet + +[ Upstream commit 99a2312f69805f4ba92d98a757625e0300a747ab ] + +The early_lookup_bdev() function returns successfully when the disk +device is present but not necessarily its partitions. In this situation, +dm_early_create() fails as the partition block device does not exist +yet. + +In my case, this phenomenon occurs quite often because the device is +an SD card with slow reading times, on which kernel takes time to +enumerate available partitions. + +Fortunately, the underlying device is back to "probing" state while +enumerating partitions. Waiting for all probing to end is enough to fix +this issue. + +That's also the reason why this problem never occurs with rootwait= +parameter: the while loop inside wait_for_root() explicitly waits for +probing to be done and then the function calls async_synchronize_full(). +These lines were omitted in 035641b, even though the commit says it's +based on the rootwait logic... + +Anyway, calling wait_for_device_probe() after our while loop does the +job (it both waits for probing and calls async_synchronize_full). + +Fixes: 035641b01e72 ("dm init: add dm-mod.waitfor to wait for asynchronously probed block devices") +Signed-off-by: Guillaume Gonnet +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-init.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c +index b37bbe7625003..423269cbdd2bb 100644 +--- a/drivers/md/dm-init.c ++++ b/drivers/md/dm-init.c +@@ -303,8 +303,10 @@ static int __init dm_init_init(void) + } + } + +- if (waitfor[0]) ++ if (waitfor[0]) { ++ wait_for_device_probe(); + DMINFO("all devices available"); ++ } + + list_for_each_entry(dev, &devices, list) { + if (dm_early_create(&dev->dmi, dev->table, +-- +2.53.0 + diff --git a/queue-6.12/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch b/queue-6.12/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch new file mode 100644 index 0000000000..e125933f01 --- /dev/null +++ b/queue-6.12/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch @@ -0,0 +1,81 @@ +From 1095e01c659441ad981ee958a4dd84fd4993eaa2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:05:48 +0800 +Subject: dm log: fix out-of-bounds write due to region_count overflow + +From: Junrui Luo + +[ Upstream commit c20e36b7631d83e7535877f08af8b0af72c44b1a ] + +The local variable region_count in create_log_context() is declared as +unsigned int (32-bit), but dm_sector_div_up() returns sector_t (64-bit). +When a device-mapper target has a sufficiently large ti->len with a small +region_size, the division result can exceed UINT_MAX. The truncated +value is then used to calculate bitset_size, causing clean_bits, +sync_bits, and recovering_bits to be allocated far smaller than needed +for the actual number of regions. + +Subsequent log operations (log_set_bit, log_clear_bit, log_test_bit) use +region indices derived from the full untruncated region space, causing +out-of-bounds writes to kernel heap memory allocated by vmalloc. + +This can be reproduced by creating a mirror target whose region_count +overflows 32 bits: + + dmsetup create bigzero --table '0 8589934594 zero' + dmsetup create mymirror --table '0 8589934594 mirror \ + core 2 2 nosync 2 /dev/mapper/bigzero 0 \ + /dev/mapper/bigzero 0' + +The status output confirms the truncation (sync_count=1 instead of +4294967297, because 0x100000001 was truncated to 1): + + $ dmsetup status mymirror + 0 8589934594 mirror 2 254:1 254:1 1/4294967297 ... + +This leads to a kernel crash in core_in_sync: + + BUG: scheduling while atomic: (udev-worker)/9150/0x00000000 + RIP: 0010:core_in_sync+0x14/0x30 [dm_log] + CR2: 0000000000000008 + Fixing recursive fault but reboot is needed! + +Fix by widening the local region_count to sector_t and adding an +explicit overflow check before the value is assigned to lc->region_count. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-log.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c +index bced5a783ee33..4a1369b8f44a0 100644 +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -373,7 +373,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + + struct log_c *lc; + uint32_t region_size; +- unsigned int region_count; ++ sector_t region_count; + size_t bitset_size, buf_size; + int r; + char dummy; +@@ -401,6 +401,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + } + + region_count = dm_sector_div_up(ti->len, region_size); ++ if (region_count > UINT_MAX) { ++ DMWARN("region count exceeds limit of %u", UINT_MAX); ++ return -EINVAL; ++ } + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) { +-- +2.53.0 + diff --git a/queue-6.12/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch b/queue-6.12/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch new file mode 100644 index 0000000000..db7b1d4fc6 --- /dev/null +++ b/queue-6.12/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch @@ -0,0 +1,50 @@ +From 039fffbb590d1e8bf673b76ab2dbd5988a2d5aa1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 14:02:19 +0800 +Subject: dmaengine: dw-axi-dmac: Remove unnecessary return statement from void + function + +From: Khairul Anuar Romli + +[ Upstream commit 48278a72fce8a8d30efaedeb206c9c3f05c1eb3f ] + +checkpatch.pl --strict reports a WARNING in dw-axi-dmac-platform.c: + + WARNING: void function return statements are not generally useful + FILE: drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c + +According to Linux kernel coding style [Documentation/process/ +coding-style.rst], explicit "return;" statements at the end of void +functions are redundant and should be omitted. The function will +automatically return upon reaching the closing brace, so the extra +statement adds unnecessary clutter without functional benefit. + +This patch removes the superfluous "return;" statement in +dw_axi_dma_set_hw_channel() to comply with kernel coding standards and +eliminate the checkpatch warning. + +Fixes: 32286e279385 ("dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel") +Signed-off-by: Khairul Anuar Romli +Link: https://patch.msgid.link/20260202060224.12616-4-karom.9560@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index fffafa86d964e..adef111aca31e 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -592,8 +592,6 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) + (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0); +- +- return; + } + + /* +-- +2.53.0 + diff --git a/queue-6.12/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch b/queue-6.12/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch new file mode 100644 index 0000000000..5c2f80e98c --- /dev/null +++ b/queue-6.12/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch @@ -0,0 +1,37 @@ +From 10dffba000ddcd8ba19842116fbc39bf1fdd2f24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:41:38 -0500 +Subject: dmaengine: mxs-dma: Fix missing return value from + of_dma_controller_register() + +From: Frank Li + +[ Upstream commit ab2bf6d4c0a0152907b18d25c1b118ea5ea779df ] + +Propagate the return value of of_dma_controller_register() in probe() +instead of ignoring it. + +Fixes: a580b8c5429a6 ("dmaengine: mxs-dma: add dma support for i.MX23/28") +Signed-off-by: Frank Li +Link: https://patch.msgid.link/20260225-mxsdma-module-v3-2-8f798b13baa6@nxp.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mxs-dma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c +index cfb9962417ef6..53f572b6b6fc6 100644 +--- a/drivers/dma/mxs-dma.c ++++ b/drivers/dma/mxs-dma.c +@@ -824,6 +824,7 @@ static int mxs_dma_probe(struct platform_device *pdev) + if (ret) { + dev_err(mxs_dma->dma_device.dev, + "failed to register controller\n"); ++ return ret; + } + + dev_info(mxs_dma->dma_device.dev, "initialized\n"); +-- +2.53.0 + diff --git a/queue-6.12/documentation-fix-a-hugetlbfs-reservation-statement.patch b/queue-6.12/documentation-fix-a-hugetlbfs-reservation-statement.patch new file mode 100644 index 0000000000..7427fe470b --- /dev/null +++ b/queue-6.12/documentation-fix-a-hugetlbfs-reservation-statement.patch @@ -0,0 +1,63 @@ +From 2e6647f1eeb6bd765852ed2a76ca9abc1f48f40e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 13:10:15 -0700 +Subject: Documentation: fix a hugetlbfs reservation statement + +From: Jane Chu + +[ Upstream commit 7a197d346a44384a1a858a98ef03766840e561d4 ] + +Documentation/mm/hugetlbfs_reserv.rst has + if (resv_needed <= (resv_huge_pages - free_huge_pages)) + resv_huge_pages += resv_needed; +which describes this code in gather_surplus_pages() + needed = (h->resv_huge_pages + delta) - h->free_huge_pages; + if (needed <= 0) { + h->resv_huge_pages += delta; + return 0; + } +which means if there are enough free hugepages to account for the new +reservation, simply update the global reservation count without +further action. + +But the description is backwards, it should be + if (resv_needed <= (free_huge_pages - resv_huge_pages)) +instead. + +Link: https://lkml.kernel.org/r/20260302201015.1824798-1-jane.chu@oracle.com +Fixes: 70bc0dc578b3 ("Documentation: vm, add hugetlbfs reservation overview") +Signed-off-by: Jane Chu +Cc: David Hildenbrand +Cc: Hillf Danton +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Oscar Salvador +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/mm/hugetlbfs_reserv.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/mm/hugetlbfs_reserv.rst b/Documentation/mm/hugetlbfs_reserv.rst +index 4914fbf07966c..a49115db18c76 100644 +--- a/Documentation/mm/hugetlbfs_reserv.rst ++++ b/Documentation/mm/hugetlbfs_reserv.rst +@@ -155,7 +155,7 @@ are enough free huge pages to accommodate the reservation. If there are, + the global reservation count resv_huge_pages is adjusted something like the + following:: + +- if (resv_needed <= (resv_huge_pages - free_huge_pages)) ++ if (resv_needed <= (free_huge_pages - resv_huge_pages) + resv_huge_pages += resv_needed; + + Note that the global lock hugetlb_lock is held when checking and adjusting +-- +2.53.0 + diff --git a/queue-6.12/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch b/queue-6.12/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch new file mode 100644 index 0000000000..18a800812d --- /dev/null +++ b/queue-6.12/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch @@ -0,0 +1,54 @@ +From eafbff4da7297a0670f893e759567b9bbb003b0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:06 +0000 +Subject: dpaa2: add independent dependencies for FSL_DPAA2_SWITCH + +From: Cai Xinchen + +[ Upstream commit 12589892f41c4c645c80ef9f036f7451a6045624 ] + +Since the commit 84cba72956fd ("dpaa2-switch: integrate +the MAC endpoint support") included dpaa2-mac.o in the driver, +but it didn't select PCS_LYNX, PHYLINK and FSL_XGMAC_MDIO. it +will lead to link error, such as +undefined reference to `phylink_ethtool_ksettings_set' +undefined reference to `lynx_pcs_create_fwnode' + +And the same reason as the commit d2624e70a2f53 ("dpaa2-eth: select +XGMAC_MDIO for MDIO bus support"), enable the FSL_XGMAC_MDIO Kconfig +option in order to have MDIO access to internal and external PHYs. + +Because dpaa2-switch uses fsl_mc_driver APIs, add depends on FSL_MC_BUS +&& FSL_MC_DPIO as FSL_DPAA2_SWITCH do. + +FSL_XGMAC_MDIO and FSL_MC_BUS depend on OF, thus the dependence of +FSL_MC_BUS can satisfy FSL_XGMAC_MDIO's OF requirement. + +Fixes: 84cba72956fd ("dpaa2-switch: integrate the MAC endpoint support") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-2-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/dpaa2/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig +index d029b69c3f183..36280e5d99e1f 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig ++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig +@@ -34,6 +34,10 @@ config FSL_DPAA2_SWITCH + tristate "Freescale DPAA2 Ethernet Switch" + depends on BRIDGE || BRIDGE=n + depends on NET_SWITCHDEV ++ depends on FSL_MC_BUS && FSL_MC_DPIO ++ select PHYLINK ++ select PCS_LYNX ++ select FSL_XGMAC_MDIO + help + Driver for Freescale DPAA2 Ethernet Switch. This driver manages + switch objects discovered on the Freeescale MC bus. +-- +2.53.0 + diff --git a/queue-6.12/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch b/queue-6.12/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch new file mode 100644 index 0000000000..653ce7d716 --- /dev/null +++ b/queue-6.12/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch @@ -0,0 +1,42 @@ +From c85ec5e8d960231386f69399b377b050fceb1306 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:07 +0000 +Subject: dpaa2: compile dpaa2 even CONFIG_FSL_DPAA2_ETH=n + +From: Cai Xinchen + +[ Upstream commit 97daf00745f7f9f261b0e91418de6e79d7826c36 ] + +CONFIG_FSL_DPAA2_ETH and CONFIG_FSL_DPAA2_SWITCH are not +associated, but the compilation of FSL_DPAA2_SWITCH depends on +the compilation of the dpaa2 folder. The files controlled by +CONFIG_FSL_DPAA2_SWITCH in the dpaa2 folder are not controlled +by CONFIG_FSL_DPAA2_ETH, except for the files controlled by +CONFIG_FSL_DPAA2_SWITCH. Therefore, removing the restriction will +not affect the compilation of the files in the directory. + +Fixes: f48298d3fbfaa ("staging: dpaa2-switch: move the driver out of staging") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-3-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/Makefile | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile +index de7b318422330..d0a259e47960f 100644 +--- a/drivers/net/ethernet/freescale/Makefile ++++ b/drivers/net/ethernet/freescale/Makefile +@@ -22,6 +22,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o + obj-$(CONFIG_FSL_FMAN) += fman/ + obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/ + +-obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/ +- ++obj-y += dpaa2/ + obj-y += enetc/ +-- +2.53.0 + diff --git a/queue-6.12/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch b/queue-6.12/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch new file mode 100644 index 0000000000..cb4c93cbe3 --- /dev/null +++ b/queue-6.12/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch @@ -0,0 +1,59 @@ +From bfac60bb0ff4ff196fe092bc92d712f877e1fe50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:40:54 -0700 +Subject: drbd: Balance RCU calls in drbd_adm_dump_devices() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bart Van Assche + +[ Upstream commit 2b31e86387e60b3689339f0f0fbb4d3623d9d494 ] + +Make drbd_adm_dump_devices() call rcu_read_lock() before +rcu_read_unlock() is called. This has been detected by the Clang +thread-safety analyzer. + +Tested-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Cc: Andreas Gruenbacher +Fixes: a55bbd375d18 ("drbd: Backport the "status" command") +Signed-off-by: Bart Van Assche +Link: https://patch.msgid.link/20260326214054.284593-1-bvanassche@acm.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_nl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index 8c12bf1b2a0d2..2e985101963e6 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -3377,8 +3377,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + cb->args[0] = (long)resource; + } + } +@@ -3627,8 +3629,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + } + cb->args[0] = (long)resource; + } +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch b/queue-6.12/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch new file mode 100644 index 0000000000..869f2861c0 --- /dev/null +++ b/queue-6.12/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch @@ -0,0 +1,45 @@ +From e9dc451c1956a9249c298fe5495dbf30686cdf5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:41 +0200 +Subject: drm/amd/display: Allow DCE link encoder without AUX registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ] + +Allow constructing the DCE link encoder without DDC, +which means the AUX registers array will be NULL. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 87f30b101af62590faf6020d106da07efdda199b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index 0c50fe266c8a1..4103213a572ad 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -989,7 +989,9 @@ void dce110_link_encoder_hw_init( + ASSERT(result == BP_RESULT_OK); + + } +- aux_initialize(enc110); ++ ++ if (enc110->aux_regs) ++ aux_initialize(enc110); + + /* reinitialize HPD. + * hpd_initialize() will pass DIG_FE id to HW context. +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch b/queue-6.12/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch new file mode 100644 index 0000000000..f29a4b57f3 --- /dev/null +++ b/queue-6.12/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch @@ -0,0 +1,137 @@ +From db4e0d7c13e3d9f30aa736e5a730a2362bd8b82d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:44 +0200 +Subject: drm/amd/display: Read EDID from VBIOS embedded panel info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ] + +Some board manufacturers hardcode the EDID for the embedded +panel in the VBIOS. This EDID should be used when the panel +doesn't have a DDC. + +For reference, see the legacy non-DC display code: +amdgpu_atombios_encoder_get_lcd_info() + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364) +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ + .../display/include/grph_object_ctrl_defs.h | 4 ++ + 2 files changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index a523c5cfcd248..fad0129bf8b12 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1215,6 +1215,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( + return BP_RESULT_FAILURE; + } + ++static enum bp_result get_embedded_panel_extra_info( ++ struct bios_parser *bp, ++ struct embedded_panel_info *info, ++ const uint32_t table_offset) ++{ ++ uint8_t *record = bios_get_image(&bp->base, table_offset, 1); ++ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; ++ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ++ ++ while (*record != ATOM_RECORD_END_TYPE) { ++ switch (*record) { ++ case LCD_MODE_PATCH_RECORD_MODE_TYPE: ++ record += sizeof(ATOM_PATCH_RECORD_MODE); ++ break; ++ case LCD_RTS_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_RTS_RECORD); ++ break; ++ case LCD_CAP_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); ++ break; ++ case LCD_FAKE_EDID_PATCH_RECORD_TYPE: ++ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; ++ if (fake_edid_record->ucFakeEDIDLength) { ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength; ++ else ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength * 128; ++ ++ info->fake_edid = fake_edid_record->ucFakeEDIDString; ++ ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ info->fake_edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; ++ } ++ break; ++ case LCD_PANEL_RESOLUTION_RECORD_TYPE: ++ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; ++ info->panel_width_mm = panel_res_record->usHSize; ++ info->panel_height_mm = panel_res_record->usVSize; ++ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); ++ break; ++ default: ++ return BP_RESULT_BADBIOSTABLE; ++ } ++ } ++ ++ return BP_RESULT_OK; ++} ++ + static enum bp_result get_embedded_panel_info_v1_2( + struct bios_parser *bp, + struct embedded_panel_info *info) +@@ -1331,6 +1385,10 @@ static enum bp_result get_embedded_panel_info_v1_2( + if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) + info->lcd_timing.misc_info.API_ENABLED = true; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +@@ -1456,6 +1514,10 @@ static enum bp_result get_embedded_panel_info_v1_3( + (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & + lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +index 813463ffe15c5..8e776c90d21bf 100644 +--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h ++++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +@@ -153,6 +153,10 @@ struct embedded_panel_info { + uint32_t drr_enabled; + uint32_t min_drr_refresh_rate; + bool realtek_eDPToLVDS; ++ uint16_t panel_width_mm; ++ uint16_t panel_height_mm; ++ uint16_t fake_edid_size; ++ const uint8_t *fake_edid; + }; + + struct dc_firmware_info { +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch b/queue-6.12/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch new file mode 100644 index 0000000000..c2e37d0123 --- /dev/null +++ b/queue-6.12/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch @@ -0,0 +1,38 @@ +From a3b2c9e372932384ed75207623f4e240258e21ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:03 +0200 +Subject: drm/amd/pm/ci: Clear EnabledForActivity field for memory levels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 5facfd4c4c67e8500116ffec0d9da35d92b9c787 ] + +Follow what radeon did and what amdgpu does for other GPUs with SMU7. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 1d99b4f9bc03e..1494143132eb5 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1217,7 +1217,7 @@ static int ci_populate_single_memory_level( + } + + memory_level->EnabledForThrottle = 1; +- memory_level->EnabledForActivity = 1; ++ memory_level->EnabledForActivity = 0; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; + memory_level->VoltageDownH = 0; +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch b/queue-6.12/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch new file mode 100644 index 0000000000..79761bcb50 --- /dev/null +++ b/queue-6.12/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch @@ -0,0 +1,67 @@ +From fe3266814de3014de771d13b5f75e849924790e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:59 +0200 +Subject: drm/amd/pm/ci: Disable MCLK DPM on problematic CI ASICs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9851f29cb06c09f7dad3867d8b0feec3fc71b6c8 ] + +There are two known cases where MCLK DPM can causes issues: + +Radeon R9 M380 found in iMac computers from 2015. +The SMU in this GPU just hangs as soon as we send it the +PPSMC_MSG_MCLKDPM_Enable command, even when MCLK switching is +disabled, and even when we only populate one MCLK DPM level. +Apply workaround to all devices with the same subsystem ID. + +Radeon R7 260X due to old memory controller microcode. +We only flash the MC ucode when it isn't set up by the VBIOS, +therefore there is no way to make sure that it has the correct +ucode version. + +I verified that this patch fixes the SMU hang on the R9 M380 +which would previously fail to boot. This also fixes the UVD +initialization error on that GPU which happened because the +SMU couldn't ungate the UVD after it hung. + +Fixes: 86457c3b21cb ("drm/amd/powerplay: Add support for CI asics to hwmgr") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +index 2b5ac21fee399..1d6e30269d567 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) + PP_GFXOFF_MASK); + hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; ++ switch (hwmgr->chip_id) { ++ case CHIP_BONAIRE: ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM ++ * R7 260X cards with old MC ucode: MCLK DPM is unstable ++ */ ++ if (adev->pdev->subsystem_vendor == 0x106B || ++ adev->pdev->device == 0x6658) { ++ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); ++ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; ++ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; ++ } ++ break; ++ default: ++ break; ++ } + smu7_init_function_pointers(hwmgr); + break; + case AMDGPU_FAMILY_CZ: +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch b/queue-6.12/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch new file mode 100644 index 0000000000..8fcd09dde3 --- /dev/null +++ b/queue-6.12/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch @@ -0,0 +1,48 @@ +From 385bf2f4ad4f5d4d507531deedd8501f615698b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:04 +0200 +Subject: drm/amd/pm/ci: Fill DW8 fields from SMC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit baf28ec5795c077406d6f52b8ad39e614153bce6 ] + +In ci_populate_dw8() we currently just read a value from the SMU +and then throw it away. Instead of throwing away the value, +we should use it to fill other fields in DW8 (like radeon). + +Otherwise the value of the other fiels is just cleared when +we copy this data to the SMU later. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 1494143132eb5..aea3ad523cc03 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) + { + struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); + const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; +- uint32_t temp; + + if (ci_read_smc_sram_dword(hwmgr, + fuse_table_offset + + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), +- (uint32_t *)&temp, SMC_RAM_END)) ++ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) + PP_ASSERT_WITH_CODE(false, + "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", + return -EINVAL); +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch b/queue-6.12/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch new file mode 100644 index 0000000000..3546c71c27 --- /dev/null +++ b/queue-6.12/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch @@ -0,0 +1,41 @@ +From 35ced68603e959390a22f4ed27040eb9ce77ff2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:02 +0200 +Subject: drm/amd/pm/ci: Fix powertune defaults for Hawaii 0x67B0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit d784759c07924280f3c313f205fc48eb62d7cb71 ] + +There is no AMD GPU with the ID 0x66B0, this looks like a typo. +It should be 0x67B0 which is actually part of the PCI ID list, +and should use the Hawaii XT powertune defaults according to +the old radeon driver. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 71b1dad34926e..1d99b4f9bc03e 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) + smu_data->power_tune_defaults = &defaults_hawaii_pro; + break; + case 0x67B8: +- case 0x66B0: ++ case 0x67B0: + smu_data->power_tune_defaults = &defaults_hawaii_xt; + break; + case 0x6640: +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch b/queue-6.12/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch new file mode 100644 index 0000000000..7a24452058 --- /dev/null +++ b/queue-6.12/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch @@ -0,0 +1,47 @@ +From faa286bc1ba39b03bc6bb6907d6bd73eb81a63f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:58 +0200 +Subject: drm/amd/pm/ci: Use highest MCLK on CI when MCLK DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 894f0d34d66cb47fe718fe2ae5c18729d22c5218 ] + +When MCLK DPM is disabled for any reason, populate the MCLK +table with the highest MCLK DPM level, so that the ASIC can +use the highest possible memory clock to get good performance +even when MCLK DPM is disabled. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 0cb7eaaba3844..71b1dad34926e 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1322,6 +1322,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) + return result; + } + ++ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { ++ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ ++ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { ++ levels[i] = levels[dpm_table->mclk_table.count - 1]; ++ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; ++ } ++ } ++ + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; + + dev_id = adev->pdev->device; +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch b/queue-6.12/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch new file mode 100644 index 0000000000..f542c37686 --- /dev/null +++ b/queue-6.12/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch @@ -0,0 +1,129 @@ +From 8d1104335023a86e035b3e0d319ce0d22c923fd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:05 +0200 +Subject: drm/amd/pm/smu7: Add SCLK cap for quirky Hawaii board +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 4724bc5b8d78c34b993594f9406135408ccb312a ] + +On a specific Radeon R9 390X board, the GPU can "randomly" hang +while gaming. Initially I thought this was a RADV bug and tried +to work around this in Mesa: +commit 8ea08747b86b ("radv: Mitigate GPU hang on Hawaii in Dota 2 and RotTR") + +However, I got some feedback from other users who are reporting +that the above mitigation causes a significant performance +regression for them, and they didn't experience the hang on their +GPU in the first place. + +After some further investigation, it turns out that the problem +is that the highest SCLK DPM level on this board isn't stable. +Lowering SCLK to 1040 MHz (from 1070 MHz) works around the issue, +and has a negligible impact on performance compared to the Mesa +patch. (Note that increasing the voltage can also work around it, +but we felt that lowering the SCLK is the safer option.) + +To solve the above issue, add an "sclk_cap" field to smu7_hwmgr +and set this field for the affected board. The capped SCLK value +correctly appears on the sysfs interface and shows up in GUI +tools such as LACT. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 30 ++++++++++++++++--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h | 1 + + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index c8dc40197a730..80e34a7748d72 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.vddc_dependency_on_mclk; + struct phm_cac_leakage_table *std_voltage_table = + hwmgr->dyn_state.cac_leakage_table; +- uint32_t i; ++ uint32_t i, clk; + + PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, + "SCLK dependency table is missing. This table is mandatory", return -EINVAL); +@@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + data->dpm_table.sclk_table.count = 0; + + for (i = 0; i < allowed_vdd_sclk_table->count; i++) { ++ clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); ++ + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != +- allowed_vdd_sclk_table->entries[i].clk) { ++ clk) { + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = +- allowed_vdd_sclk_table->entries[i].clk; ++ clk; + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; + data->dpm_table.sclk_table.count++; + } +@@ -3006,6 +3008,25 @@ static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr * + return 0; + } + ++static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) ++{ ++ struct amdgpu_device *adev = hwmgr->adev; ++ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); ++ ++ data->sclk_cap = 0xffffffff; ++ ++ if (hwmgr->od_enabled) ++ return; ++ ++ /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ ++ if (adev->pdev->device == 0x67B0 && ++ adev->pdev->subsystem_vendor == 0x1043) ++ data->sclk_cap = 104000; /* 1040 MHz */ ++ ++ if (data->sclk_cap != 0xffffffff) ++ dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -3017,6 +3038,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + return -ENOMEM; + + hwmgr->backend = data; ++ smu7_set_sclk_cap(hwmgr); + smu7_patch_voltage_workaround(hwmgr); + smu7_init_dpm_defaults(hwmgr); + +@@ -3903,7 +3925,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, + + /* Performance levels are arranged from low to high. */ + performance_level->memory_clock = memory_clock; +- performance_level->engine_clock = engine_clock; ++ performance_level->engine_clock = min(engine_clock, data->sclk_cap); + + pcie_gen_from_bios = visland_clk_info->ucPCIEGen; + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +index d9e8b386bd4d3..66adabeab6a3a 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +@@ -234,6 +234,7 @@ struct smu7_hwmgr { + uint32_t pcie_gen_cap; + uint32_t pcie_lane_cap; + uint32_t pcie_spc_cap; ++ uint32_t sclk_cap; + struct smu7_leakage_voltage vddc_leakage; + struct smu7_leakage_voltage vddci_leakage; + struct smu7_leakage_voltage vddcgfx_leakage; +-- +2.53.0 + diff --git a/queue-6.12/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch b/queue-6.12/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch new file mode 100644 index 0000000000..8f71071f3b --- /dev/null +++ b/queue-6.12/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch @@ -0,0 +1,192 @@ +From 5338e2b726c8df3dc5d71fba8ca3c94119ebac63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:00 +0200 +Subject: drm/amd/pm/smu7: Fix SMU7 voltage dependency on display clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 0138610c14130425be53423b35336561829965e0 ] + +The DCE (display controller engine) requires a minimum voltage +in order to function correctly, depending on which clock level +it currently uses. + +Add a new table that contains display clock frequency levels +and the corresponding required voltages. The clock frequency +levels are taken from DC (and the old radeon driver's voltage +dependency table for CI in cases where its values were lower). +The voltage levels are taken from the following function: +phm_initializa_dynamic_state_adjustment_rule_settings(). +Furthermore, in case of CI, call smu7_patch_vddc() on the new +table to account for leakage voltage (like in radeon). + +Use the display clock value from amd_pp_display_configuration +to look up the voltage level needed by the DCE. Send the +voltage to the SMU via the PPSMC_MSG_VddC_Request command. + +The previous implementation of this feature was non-functional +because it relied on a "dal_power_level" field which was never +assigned; and it was not at all implemented for CI ASICs. + +I verified this on a Radeon R9 M380 which previously booted to +a black screen with DC enabled (default since Linux 6.19), but +now works correctly. + +Fixes: 599a7e9fe1b6 ("drm/amd/powerplay: implement smu7 hwmgr to manager asics with smu ip version 7.") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 88 ++++++++++++++++++- + drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h | 1 + + 2 files changed, 86 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index 3018e294673a5..c8dc40197a730 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -2802,6 +2802,10 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) + if (tmp) + return -EINVAL; + ++ tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ if (tmp) ++ return -EINVAL; ++ + tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); + if (tmp) + return -EINVAL; +@@ -2885,6 +2889,8 @@ static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) + { + kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); + hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; ++ kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; + kfree(hwmgr->backend); + hwmgr->backend = NULL; + +@@ -2955,6 +2961,51 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) + return ret; + } + ++static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) ++{ ++ struct phm_clock_voltage_dependency_table *table; ++ ++ if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) ++ return 0; ++ ++ table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); ++ if (!table) ++ return -ENOMEM; ++ ++ if (hwmgr->chip_id >= CHIP_POLARIS10) { ++ table->entries[0].clk = 38918; ++ table->entries[1].clk = 45900; ++ table->entries[2].clk = 66700; ++ table->entries[3].clk = 113200; ++ ++ table->entries[0].v = 700; ++ table->entries[1].v = 740; ++ table->entries[2].v = 800; ++ table->entries[3].v = 900; ++ } else { ++ if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { ++ table->entries[0].clk = 35200; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 46700; ++ table->entries[3].clk = 64300; ++ } else { ++ table->entries[0].clk = 0; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 54000; ++ table->entries[3].clk = 62500; ++ } ++ ++ table->entries[0].v = 0; ++ table->entries[1].v = 720; ++ table->entries[2].v = 810; ++ table->entries[3].v = 900; ++ } ++ ++ table->count = 4; ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = table; ++ return 0; ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -2983,6 +3034,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + smu7_get_elb_voltages(hwmgr); + } + ++ result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); ++ if (result) ++ goto fail; ++ + if (hwmgr->pp_table_version == PP_TABLE_V1) { + smu7_complete_dependency_tables(hwmgr); + smu7_set_private_data_based_on_pptable_v1(hwmgr); +@@ -3079,13 +3134,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) + return 0; + } + ++static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) ++{ ++ const struct amd_pp_display_configuration *cfg = hwmgr->display_config; ++ const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = ++ hwmgr->dyn_state.vddc_dependency_on_display_clock; ++ uint32_t i; ++ ++ if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || ++ !cfg || !cfg->num_display || !cfg->display_clk) ++ return 0; ++ ++ /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ ++ for (i = 1; i < vddc_dep_on_dispclk->count; ++i) ++ if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) ++ return vddc_dep_on_dispclk->entries[i].v; ++ ++ return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; ++} ++ ++static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) ++{ ++ uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_VddC_Request, ++ req_vddc * VOLTAGE_SCALE, ++ NULL); ++} ++ + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) + { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + +- if (hwmgr->pp_table_version == PP_TABLE_V1) +- phm_apply_dal_min_voltage_request(hwmgr); +-/* TO DO for v0 iceland and Ci*/ ++ smu7_apply_minimum_dce_voltage_request(hwmgr); + + if (!data->sclk_dpm_key_disabled) { + if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) +diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +index 227bf0e84a130..d829121d29fbc 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +@@ -632,6 +632,7 @@ struct phm_dynamic_state_info { + struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; ++ struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; + struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; + struct phm_clock_array *valid_sclk_values; + struct phm_clock_array *valid_mclk_values; +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-add-amdgpu_device-reference-in-ip-block.patch b/queue-6.12/drm-amdgpu-add-amdgpu_device-reference-in-ip-block.patch new file mode 100644 index 0000000000..e7dbe61dfd --- /dev/null +++ b/queue-6.12/drm-amdgpu-add-amdgpu_device-reference-in-ip-block.patch @@ -0,0 +1,55 @@ +From 3fb05e29aba2ac028f8c108d36963de516ca7232 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Sep 2024 18:16:29 +0530 +Subject: drm/amdgpu: add amdgpu_device reference in ip block +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit 37b993225d37744f2a62bf67074a76a6cb7b8b98 ] + +To handle amdgpu_device reference for different GPUs +we add it's reference in each ip block which can be +used to differentiate between difference gpu devices. + +Signed-off-by: Sunil Khatri +Suggested-by: Christian König +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Stable-dep-of: 8b3e8fa6d7bd ("drm/amdgpu/uvd4.2: Don't initialize UVD 4.2 when DPM is disabled") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +index 7edf8d67a0fa5..b667da0ec68a3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +@@ -388,6 +388,7 @@ struct amdgpu_ip_block_version { + struct amdgpu_ip_block { + struct amdgpu_ip_block_status status; + const struct amdgpu_ip_block_version *version; ++ struct amdgpu_device *adev; + }; + + int amdgpu_device_ip_block_version_cmp(struct amdgpu_device *adev, +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 12d7e45a42456..1183d671d0606 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -2336,6 +2336,8 @@ int amdgpu_device_ip_block_add(struct amdgpu_device *adev, + DRM_INFO("add ip block number %d <%s>\n", adev->num_ip_blocks, + ip_block_version->funcs->name); + ++ adev->ip_blocks[adev->num_ip_blocks].adev = adev; ++ + adev->ip_blocks[adev->num_ip_blocks++].version = ip_block_version; + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch b/queue-6.12/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch new file mode 100644 index 0000000000..6479ac4ab2 --- /dev/null +++ b/queue-6.12/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch @@ -0,0 +1,54 @@ +From cf77d4bb0a9e9acb224565d8d71e1a7f0e6c5aac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 19:29:54 +0530 +Subject: drm/amdgpu: Add default case in DVI mode validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit e6020a55b8e364d15eac27f9c788e13114eec6b7 ] + +amdgpu_connector_dvi_mode_valid() assigns max_digital_pixel_clock_khz +based on connector_object_id using a switch statement that lacks a +default case. + +In practice this code path should never be hit because the existing +cases already cover all digital connector types that this function is +used for. This is also legacy display code which is not used for new +hardware. + +Add a default case returning MODE_BAD to make the switch exhaustive and +silence the static analyzer smatch error. The new branch is effectively +defensive and should never be reached during normal operation. + +Fixes: 585b2f685c56 ("drm/amdgpu: Respect max pixel clock for HDMI and DVI-D (v2)") +Cc: Dan Carpenter +Cc: Timur Kristóf +Cc: Alex Deucher +Cc: Christian König +Signed-off-by: Srinivasan Shanmugam +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +index 54067edb7747b..47bef5e7747c4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +@@ -1247,6 +1247,8 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector + case CONNECTOR_OBJECT_ID_HDMI_TYPE_B: + max_digital_pixel_clock_khz = max_dvi_single_link_pixel_clock * 2; + break; ++ default: ++ return MODE_BAD; + } + + /* When the display EDID claims that it's an HDMI display, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch b/queue-6.12/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch new file mode 100644 index 0000000000..25e9fa64d8 --- /dev/null +++ b/queue-6.12/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch @@ -0,0 +1,133 @@ +From 6ad14d4f6fc970c444cff0eadde09c691dbe9ce9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 15:52:45 +0200 +Subject: drm/amdgpu: fix AMDGPU_INFO_READ_MMR_REG +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 0ef196a208385b7d7da79f411c161b04e97283e2 ] + +There were multiple issues in that code. + +First of all the order between the reset semaphore and the mm_lock was +wrong (e.g. copy_to_user) was called while holding the lock. + +Then we allocated memory while holding the reset semaphore which is also +a pretty big bug and can deadlock. + +Then we used down_read_trylock() instead of waiting for the reset to +finish. + +Signed-off-by: Christian König +Fixes: 9e823f307074 ("drm/amdgpu: Block MMR_READ IOCTL in reset") +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit 361b6e6b303d4b691f6c5974d3eaab67ca6dd90e) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 57 +++++++++++-------------- + 1 file changed, 24 insertions(+), 33 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +index c626f66ded189..6788265157dbf 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +@@ -786,68 +786,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + ? -EFAULT : 0; + } + case AMDGPU_INFO_READ_MMR_REG: { +- int ret = 0; +- unsigned int n, alloc_size; +- uint32_t *regs; + unsigned int se_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SE_INDEX_MASK; + unsigned int sh_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SH_INDEX_MASK; +- +- if (!down_read_trylock(&adev->reset_domain->sem)) +- return -ENOENT; ++ unsigned int alloc_size; ++ uint32_t *regs; ++ int ret; + + /* set full masks if the userspace set all bits + * in the bitfields + */ +- if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) { ++ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) + se_num = 0xffffffff; +- } else if (se_num >= AMDGPU_GFX_MAX_SE) { +- ret = -EINVAL; +- goto out; +- } ++ else if (se_num >= AMDGPU_GFX_MAX_SE) ++ return -EINVAL; + +- if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { ++ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) + sh_num = 0xffffffff; +- } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { +- ret = -EINVAL; +- goto out; +- } ++ else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) ++ return -EINVAL; + +- if (info->read_mmr_reg.count > 128) { +- ret = -EINVAL; +- goto out; +- } ++ if (info->read_mmr_reg.count > 128) ++ return -EINVAL; + +- regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); +- if (!regs) { +- ret = -ENOMEM; +- goto out; +- } ++ regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), ++ GFP_KERNEL); ++ if (!regs) ++ return -ENOMEM; + ++ down_read(&adev->reset_domain->sem); + alloc_size = info->read_mmr_reg.count * sizeof(*regs); +- + amdgpu_gfx_off_ctrl(adev, false); ++ ret = 0; + for (i = 0; i < info->read_mmr_reg.count; i++) { + if (amdgpu_asic_read_register(adev, se_num, sh_num, + info->read_mmr_reg.dword_offset + i, + ®s[i])) { + DRM_DEBUG_KMS("unallowed offset %#x\n", + info->read_mmr_reg.dword_offset + i); +- kfree(regs); +- amdgpu_gfx_off_ctrl(adev, true); + ret = -EFAULT; +- goto out; ++ break; + } + } + amdgpu_gfx_off_ctrl(adev, true); +- n = copy_to_user(out, regs, min(size, alloc_size)); +- kfree(regs); +- ret = (n ? -EFAULT : 0); +-out: + up_read(&adev->reset_domain->sem); ++ ++ if (!ret) { ++ ret = copy_to_user(out, regs, min(size, alloc_size)) ++ ? -EFAULT : 0; ++ } ++ kfree(regs); + return ret; + } + case AMDGPU_INFO_DEV_INFO: { +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-fix-spelling-typos.patch b/queue-6.12/drm-amdgpu-fix-spelling-typos.patch new file mode 100644 index 0000000000..9c236e975f --- /dev/null +++ b/queue-6.12/drm-amdgpu-fix-spelling-typos.patch @@ -0,0 +1,103 @@ +From 61b2bb233be0cf40dfe510bb3d1f701a12196ead Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 00:05:04 -0500 +Subject: drm/amdgpu: fix spelling typos + +From: Alexandre Demers + +[ Upstream commit ce43abd7ec9464cf954f90e1c69e11768b02fa0a ] + +Found some typos while exploring amdgpu code. + +Signed-off-by: Alexandre Demers +Signed-off-by: Alex Deucher +Stable-dep-of: 13e4cf116dbf ("drm/amdgpu/uvd3.1: Don't validate the firmware when already validated") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 6 +++--- + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 3 ++- + drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | 2 +- + 4 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index cf41ef9e3ad83..f63b5a429b107 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -269,7 +269,7 @@ void amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc + * @mc: memory controller structure holding memory information + * @gart_placement: GART placement policy with respect to VRAM + * +- * Function will place try to place GART before or after VRAM. ++ * Function will try to place GART before or after VRAM. + * If GART size is bigger than space left then we ajust GART size. + * Thus function will never fails. + */ +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index 2dd89f490dc37..4dd1595dc3d88 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -98,7 +98,7 @@ static void uvd_v3_1_ring_emit_ib(struct amdgpu_ring *ring, + } + + /** +- * uvd_v3_1_ring_emit_fence - emit an fence & trap command ++ * uvd_v3_1_ring_emit_fence - emit a fence & trap command + * + * @ring: amdgpu_ring pointer + * @addr: address +@@ -242,7 +242,7 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + +- /* programm the VCPU memory controller bits 0-27 */ ++ /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; + WREG32(mmUVD_VCPU_CACHE_OFFSET0, addr); +@@ -416,7 +416,7 @@ static int uvd_v3_1_start(struct amdgpu_device *adev) + /* Set the write pointer delay */ + WREG32(mmUVD_RBC_RB_WPTR_CNTL, 0); + +- /* programm the 4GB memory segment for rptr and ring buffer */ ++ /* Program the 4GB memory segment for rptr and ring buffer */ + WREG32(mmUVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) | + (0x7 << 16) | (0x1 << 31)); + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +index 0d291c497eed7..a1227867dc887 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +@@ -308,7 +308,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) + /* enable VCPU clock */ + WREG32(mmUVD_VCPU_CNTL, 1 << 9); + +- /* disable interupt */ ++ /* disable interrupt */ + WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1)); + + #ifdef __BIG_ENDIAN +@@ -318,6 +318,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) + #endif + WREG32(mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl); + WREG32(mmUVD_MP_SWAP_CNTL, mp_swap_cntl); ++ + /* initialize UVD memory controller */ + WREG32(mmUVD_LMI_CTRL, 0x203108); + +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +index 97ce06228a910..8a6c24b98f1fa 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +@@ -278,7 +278,7 @@ static int vce_v2_0_stop(struct amdgpu_device *adev) + int status; + + if (vce_v2_0_lmi_clean(adev)) { +- DRM_INFO("vce is not idle \n"); ++ DRM_INFO("VCE is not idle \n"); + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch b/queue-6.12/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch new file mode 100644 index 0000000000..461d2c33b5 --- /dev/null +++ b/queue-6.12/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch @@ -0,0 +1,40 @@ +From ceecc0d641feba06303de4d8b4e777fbaf907dff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:18:28 -0500 +Subject: drm/amdgpu/gfx10: look at the right prop for gfx queue priority +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit 355d96cdec5c61fd83f7eb54f1a28e38809645d6 ] + +Look at hqd_queue_priority rather than hqd_pipe_priority. +In practice, it didn't matter as both were always set for +kernel queues, but that will change in the future. + +Fixes: b07d1d73b09e ("drm/amd/amdgpu: Enable high priority gfx queue") +Reviewed-by:Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 7babb74caf6fc..7d5609e3dd412 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -6601,7 +6601,7 @@ static void gfx_v10_0_gfx_mqd_set_priority(struct amdgpu_device *adev, + /* set up default queue priority level + * 0x0 = low priority, 0x1 = high priority + */ +- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) ++ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) + priority = 1; + + tmp = RREG32_SOC15(GC, 0, mmCP_GFX_HQD_QUEUE_PRIORITY); +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch b/queue-6.12/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch new file mode 100644 index 0000000000..3e491e60a2 --- /dev/null +++ b/queue-6.12/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch @@ -0,0 +1,40 @@ +From ff894d9277a2d75118015bac71a5e6d40a4bda27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:20:27 -0500 +Subject: drm/amdgpu/gfx11: look at the right prop for gfx queue priority +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit f9a4e81bcbd04e6f967d851f9fe69d8bb3cc08b3 ] + +Look at hqd_queue_priority rather than hqd_pipe_priority. +In practice, it didn't matter as both were always set for +kernel queues, but that will change in the future. + +Fixes: 2e216b1e6ba2 ("drm/amdgpu/gfx11: handle priority setup for gfx pipe1") +Reviewed-by:Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index 3c91c30edf2be..7cb6b11257199 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -3919,7 +3919,7 @@ static void gfx_v11_0_gfx_mqd_set_priority(struct amdgpu_device *adev, + /* set up default queue priority level + * 0x0 = low priority, 0x1 = high priority + */ +- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) ++ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) + priority = 1; + + tmp = regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT; +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch b/queue-6.12/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch new file mode 100644 index 0000000000..c3b4eee3ee --- /dev/null +++ b/queue-6.12/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch @@ -0,0 +1,146 @@ +From 98131ca2bb5c8206ec7d4438aeb45cf04993bcdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:33 +0200 +Subject: drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ] + +This commit fixes amdgpu to work on the Radeon HD 7870 XT +which has never worked with the Linux open source drivers before. + +Some boards have "harvested" chips, meaning that some parts of +the chip are disabled and fused, and it's sold for cheaper and +under a different marketing name. +On a harvested chip, any of the following can be disabled: +- CUs (Compute Units) +- RBs (Render Backend, aka. ROP) +- Memory channels (ie. the chip has a lower bandwidth) +- TCCs (ie. less L2 cache) + +Handle chips with harvested TCCs by patching the registers +that configure how TCCs are mapped. + +If some TCCs are disabled, we need to make sure that +the disabled TCCs are not used, and the remaining TCCs +are used optimally. + +TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. + +Note that the TCC configuration is highly relevant to performance. +Suboptimal configuration (eg. CHAN_STEER=0) can significantly +reduce gaming performance. + +For optimal performance: +- Rely on the CHAN_STEER from the golden registers table, + only skip disabled TCCs but keep the mapping order. +- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, + which performs better than using the same TCC twice. + +v2: +- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs. + +Link: https://bugs.freedesktop.org/show_bug.cgi?id=60879 +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2664 +Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 00218d15528fab9f6b31241fe5904eea4fcaa30d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index cc9f9b10b435b..90c426ee877b6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -1553,6 +1553,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) + mutex_unlock(&adev->grbm_idx_mutex); + } + ++/** ++ * gfx_v6_0_setup_tcc() - setup which TCCs are used ++ * ++ * @adev: amdgpu_device pointer ++ * ++ * Verify whether the current GPU has any TCCs disabled, ++ * which can happen when the GPU is harvested and some ++ * memory channels are disabled, reducing the memory bus width. ++ * For example, on the Radeon HD 7870 XT (Tahiti LE). ++ * ++ * If some TCCs are disabled, we need to make sure that ++ * the disabled TCCs are not used, and the remaining TCCs ++ * are used optimally. ++ * ++ * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. ++ * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. ++ * ++ * For optimal performance: ++ * - Rely on the CHAN_STEER from the golden registers table, ++ * only skip disabled TCCs but keep the mapping order. ++ * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, ++ * which performs better than using the same TCC twice. ++ */ ++static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) ++{ ++ u32 i, tcc, tcp_addr_config, num_active_tcc = 0; ++ u64 chan_steer, patched_chan_steer = 0; ++ const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; ++ const u32 dis_tcc_mask = ++ amdgpu_gfx_create_bitmask(num_max_tcc) & ++ (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), ++ CGTS_TCC_DISABLE, TCC_DISABLE) | ++ REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), ++ CGTS_USER_TCC_DISABLE, TCC_DISABLE)); ++ ++ /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ ++ if (!dis_tcc_mask) ++ return; ++ ++ /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ ++ chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); ++ ++ /* Patch the TCP to TCC mapping to skip disabled TCCs */ ++ for (i = 0; i < num_max_tcc; ++i) { ++ tcc = (chan_steer >> (u64)(4 * i)) & 0xf; ++ ++ if (!((1 << tcc) & dis_tcc_mask)) { ++ /* Copy enabled TCC indices to the patched register value. */ ++ patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); ++ ++num_active_tcc; ++ } ++ } ++ ++ WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); ++ ++ /* Patch number of TCCs used by TCPs */ ++ tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), ++ TCP_ADDR_CONFIG, NUM_TCC_BANKS, ++ num_active_tcc - 1); ++ ++ WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); ++ WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); ++ WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); ++} ++ + static void gfx_v6_0_config_init(struct amdgpu_device *adev) + { + adev->gfx.config.double_offchip_lds_buf = 0; +@@ -1711,6 +1776,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) + gfx_v6_0_tiling_mode_table_init(adev); + + gfx_v6_0_setup_rb(adev); ++ gfx_v6_0_setup_tcc(adev); + + gfx_v6_0_setup_spi(adev); + +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch b/queue-6.12/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch new file mode 100644 index 0000000000..09c2825a9b --- /dev/null +++ b/queue-6.12/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch @@ -0,0 +1,54 @@ +From 709f9dcfb71cd4b6614c0b3d3e16fe6f5a7ec097 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:30 +0200 +Subject: drm/amdgpu/gmc: Fix AMDGPU_GART_PLACEMENT_LOW to not overlap with + VRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 36d65da7570bf72ce28504fa9a81abfc728e6d96 ] + +When the GART placement is set to AMDGPU_GART_PLACEMENT_LOW: +Make sure that GART does not overlap with VRAM when +VRAM is configured to be in the low address space. + +Solve this according to the following logic: +- When GART fits before VRAM, use zero address for GART +- Otherwise, put GART after the end of VRAM, aligned to 4 GiB + +Previously, I had assumed this was not possible +so it was OK to not handle it, but now we got a report +from a user who has a board that is configured this way. + +Fixes: 917f91d8d8e8 ("drm/amdgpu/gmc: add a way to force a particular placement for GART") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 3d9de5d86a1658cadb311461b001eb1df67263ad) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index 564c68c9277b3..cf41ef9e3ad83 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -297,7 +297,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, + mc->gart_start = max_mc_address - mc->gart_size + 1; + break; + case AMDGPU_GART_PLACEMENT_LOW: +- mc->gart_start = 0; ++ if (size_bf >= mc->gart_size) ++ mc->gart_start = 0; ++ else ++ mc->gart_start = ALIGN(mc->fb_end, four_gb); + break; + case AMDGPU_GART_PLACEMENT_BEST_FIT: + default: +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch new file mode 100644 index 0000000000..201ba8856b --- /dev/null +++ b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch @@ -0,0 +1,41 @@ +From 9f69bbcab5a0f785fae0841d845f0d1eb1bab072 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v2.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit e5f612dc91650561fe2b5b76dd6d2898ec9ad480 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 6ac27241106b ("drm/amdgpu: add JPEG v2.0 function supports") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 96179da0c6b059eb31706a0abe8dd6381c533143) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +index 341c551dad8b0..5c95cf6167d94 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +@@ -766,6 +766,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_0_dec_ring_get_rptr, + .get_wptr = jpeg_v2_0_dec_ring_get_wptr, + .set_wptr = jpeg_v2_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch new file mode 100644 index 0000000000..840041ae5e --- /dev/null +++ b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch @@ -0,0 +1,49 @@ +From 7b39913185c3ead95d5a18cb05be563a5eccb2a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v2.5 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 79405e774ede411c6b47ed41c651e40b92de64a2 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 14f43e8f88c5 ("drm/amdgpu: move JPEG2.5 out from VCN2.5") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 3216a7f4e2642bda5fd14f57586e835ae9202587) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +index ec0fa685e1275..e4cfa6b7141f6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +@@ -659,6 +659,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, +@@ -689,6 +690,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch new file mode 100644 index 0000000000..21d4d26d54 --- /dev/null +++ b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch @@ -0,0 +1,41 @@ +From 473efc03029d86b98d0c896ccb544fbcba9fdfb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v3.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit a2baf12eec41f246689e6a3f8619af1200031576 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: dfd57dbf44dd ("drm/amdgpu: add JPEG3.0 support for Sienna_Cichlid") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 4d7d774f100efb5089c86a1fb8c5bf47c63fc9ef) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +index dd00daa1d7eda..27a27de6c6c3d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +@@ -557,6 +557,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v3_0_dec_ring_get_rptr, + .get_wptr = jpeg_v3_0_dec_ring_get_wptr, + .set_wptr = jpeg_v3_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch new file mode 100644 index 0000000000..d7a0f1f2fa --- /dev/null +++ b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch @@ -0,0 +1,41 @@ +From 0873af2d96072f35bbee9fe9e703153322695d14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit e7e90b5839aeb8805ec83bb4da610b8dab8e184d ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: b13111de32a9 ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_0") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 8d0cac9478a3f046279c657d6a2545de49ae675a) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +index b147e0eba31da..90f64a46bff7c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +@@ -724,6 +724,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch new file mode 100644 index 0000000000..2f90e5b13d --- /dev/null +++ b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch @@ -0,0 +1,41 @@ +From affbcbfecc0b6588b30cfa8162652113c4265089 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.3 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 83e37c0987ca92f9e87789b46dd311dcf5a4a6c8 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: e684e654eba9 ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_3") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 2f6afc97d259d530f4f86c7743efbc573a8da927) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +index fd0ba04a66045..c4f812939a85f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +@@ -1122,6 +1122,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch new file mode 100644 index 0000000000..5d3015e8ee --- /dev/null +++ b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch @@ -0,0 +1,41 @@ +From cb531f829de75e7f6dbb31f9fae4db020719ad35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.5 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit b65b7f3f3c18f797f81a2af7c97e2079900ad6db ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 8f98a715da8e ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_5") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit f05d0a4f21fc720116d6e238f23308b199891058) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +index 48ab3e0a62d25..78a9fb26bce2e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +@@ -765,6 +765,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_5_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch new file mode 100644 index 0000000000..a600a4ccb5 --- /dev/null +++ b/queue-6.12/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch @@ -0,0 +1,41 @@ +From 653eadcb6f95b1f261a990e10ceb57d8eb0953be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit ea7c61c5f895e8f9ea0ffffa180498ef9c740152 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: dfad65c65728 ("drm/amdgpu: Add JPEG5 support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 0f43893d3cd478fa57836697525b338817c9c23d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +index 61288104060de..d0f800e7938dd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +@@ -644,6 +644,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, + .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, + .set_wptr = jpeg_v5_0_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-update-the-handle-ptr-in-dump_ip_state.patch b/queue-6.12/drm-amdgpu-update-the-handle-ptr-in-dump_ip_state.patch new file mode 100644 index 0000000000..023f98fc11 --- /dev/null +++ b/queue-6.12/drm-amdgpu-update-the-handle-ptr-in-dump_ip_state.patch @@ -0,0 +1,400 @@ +From 8cdebd4e7e939d2415ab074b59ea862554115b54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Sep 2024 21:30:17 +0530 +Subject: drm/amdgpu: update the handle ptr in dump_ip_state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit fa73462dc0482644416c2a2ee042c11d93a89663 ] + +Update the ptr handle to amdgpu_ip_block ptr in all +the functions. + +Signed-off-by: Sunil Khatri +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Stable-dep-of: 8b3e8fa6d7bd ("drm/amdgpu/uvd4.2: Don't initialize UVD 4.2 when DPM is disabled") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- + drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 2 +- + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 4 ++-- + drivers/gpu/drm/amd/include/amd_shared.h | 4 +++- + 22 files changed, 43 insertions(+), 41 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 1183d671d0606..778a0fcc34488 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -5466,7 +5466,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, + for (i = 0; i < tmp_adev->num_ip_blocks; i++) + if (tmp_adev->ip_blocks[i].version->funcs->dump_ip_state) + tmp_adev->ip_blocks[i].version->funcs +- ->dump_ip_state((void *)tmp_adev); ++ ->dump_ip_state((void *)&tmp_adev->ip_blocks[i]); + dev_info(tmp_adev->dev, "Dumping IP State Completed\n"); + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +index ba9a9adca0bff..70762c7fcfe46 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +@@ -42,7 +42,7 @@ static void amdgpu_job_do_core_dump(struct amdgpu_device *adev, + for (i = 0; i < adev->num_ip_blocks; i++) + if (adev->ip_blocks[i].version->funcs->dump_ip_state) + adev->ip_blocks[i].version->funcs +- ->dump_ip_state((void *)adev); ++ ->dump_ip_state((void *)&adev->ip_blocks[i]); + dev_info(adev->dev, "Dumping IP State Completed\n"); + + amdgpu_coredump(adev, true, false, job); +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 7d5609e3dd412..a715c7796f94b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -9630,9 +9630,9 @@ static void gfx_v10_ip_print(void *handle, struct drm_printer *p) + } + } + +-static void gfx_v10_ip_dump(void *handle) ++static void gfx_v10_ip_dump(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + uint32_t i, j, k, reg, index = 0; + uint32_t reg_count = ARRAY_SIZE(gc_reg_list_10_1); + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index 7cb6b11257199..0e99122ced4fb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -6746,9 +6746,9 @@ static void gfx_v11_ip_print(void *handle, struct drm_printer *p) + } + } + +-static void gfx_v11_ip_dump(void *handle) ++static void gfx_v11_ip_dump(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + uint32_t i, j, k, reg, index = 0; + uint32_t reg_count = ARRAY_SIZE(gc_reg_list_11_0); + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +index 0f4896a5f82c1..3f3f44b9fdaf9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +@@ -5096,9 +5096,9 @@ static void gfx_v12_ip_print(void *handle, struct drm_printer *p) + } + } + +-static void gfx_v12_ip_dump(void *handle) ++static void gfx_v12_ip_dump(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + uint32_t i, j, k, reg, index = 0; + uint32_t reg_count = ARRAY_SIZE(gc_reg_list_12_0); + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index a081fe118c26e..8c9d21854f820 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -7364,9 +7364,9 @@ static void gfx_v9_ip_print(void *handle, struct drm_printer *p) + + } + +-static void gfx_v9_ip_dump(void *handle) ++static void gfx_v9_ip_dump(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + uint32_t i, j, k, reg, index = 0; + uint32_t reg_count = ARRAY_SIZE(gc_reg_list_9); + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +index 26c2d8d9e2463..a6426dd37fbcc 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +@@ -4644,9 +4644,9 @@ static void gfx_v9_4_3_ip_print(void *handle, struct drm_printer *p) + } + } + +-static void gfx_v9_4_3_ip_dump(void *handle) ++static void gfx_v9_4_3_ip_dump(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + uint32_t i, j, k; + uint32_t num_xcc, reg, num_inst; + uint32_t xcc_id, xcc_offset, inst_offset; +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +index 37bb0857d8f88..4798c2681b606 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +@@ -2371,9 +2371,9 @@ static void sdma_v4_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void sdma_v4_0_dump_ip_state(void *handle) ++static void sdma_v4_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + uint32_t instance_offset; + uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_4_0); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +index 1e4ce06f5f2c3..c378668044c34 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +@@ -1884,9 +1884,9 @@ static void sdma_v4_4_2_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void sdma_v4_4_2_dump_ip_state(void *handle) ++static void sdma_v4_4_2_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + uint32_t instance_offset; + uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_4_4_2); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +index 3e48ea38385de..3ecf77ce2f1af 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +@@ -1799,9 +1799,9 @@ static void sdma_v5_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void sdma_v5_0_dump_ip_state(void *handle) ++static void sdma_v5_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + uint32_t instance_offset; + uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_5_0); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +index bc9b240a3488e..d19dde1d6fc5b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +@@ -1757,9 +1757,9 @@ static void sdma_v5_2_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void sdma_v5_2_dump_ip_state(void *handle) ++static void sdma_v5_2_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + uint32_t instance_offset; + uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_5_2); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +index 208a1fa9d4e7f..981b63a74cfc8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +@@ -1577,9 +1577,9 @@ static void sdma_v6_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void sdma_v6_0_dump_ip_state(void *handle) ++static void sdma_v6_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + uint32_t instance_offset; + uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_6_0); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +index 843e6b46deee8..b5897c98ebf05 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +@@ -1565,9 +1565,9 @@ static void sdma_v7_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void sdma_v7_0_dump_ip_state(void *handle) ++static void sdma_v7_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + uint32_t instance_offset; + uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_7_0); +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +index ecdfbfefd66ad..78dfcd02d8da4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +@@ -1957,9 +1957,9 @@ static void vcn_v1_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void vcn_v1_0_dump_ip_state(void *handle) ++static void vcn_v1_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + bool is_powered; + uint32_t inst_off; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index 9479bf9ea30fe..ca144ff63dc83 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -2074,9 +2074,9 @@ static void vcn_v2_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void vcn_v2_0_dump_ip_state(void *handle) ++static void vcn_v2_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + bool is_powered; + uint32_t inst_off; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +index 274d5063e9a26..90bebead51969 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +@@ -1965,9 +1965,9 @@ static void vcn_v2_5_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void vcn_v2_5_dump_ip_state(void *handle) ++static void vcn_v2_5_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + bool is_powered; + uint32_t inst_off; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +index f4ac8bcdb70a5..99e9679b4752a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +@@ -2312,9 +2312,9 @@ static void vcn_v3_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void vcn_v3_0_dump_ip_state(void *handle) ++static void vcn_v3_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + bool is_powered; + uint32_t inst_off; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +index 2f8d07a7b60ba..fd8774745e771 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +@@ -2210,9 +2210,9 @@ static void vcn_v4_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void vcn_v4_0_dump_ip_state(void *handle) ++static void vcn_v4_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + bool is_powered; + uint32_t inst_off; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +index 2094357a931c4..65a78a2e1b69f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +@@ -1787,9 +1787,9 @@ static void vcn_v4_0_3_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void vcn_v4_0_3_dump_ip_state(void *handle) ++static void vcn_v4_0_3_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + bool is_powered; + uint32_t inst_off, inst_id; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +index 48cb61a9c13fe..a739e667e6158 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +@@ -1663,9 +1663,9 @@ static void vcn_v4_0_5_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void vcn_v4_0_5_dump_ip_state(void *handle) ++static void vcn_v4_0_5_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + bool is_powered; + uint32_t inst_off; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +index 3aa715830fbe8..019bc6b1cd3b4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +@@ -1386,9 +1386,9 @@ static void vcn_v5_0_print_ip_state(void *handle, struct drm_printer *p) + } + } + +-static void vcn_v5_0_dump_ip_state(void *handle) ++static void vcn_v5_0_dump_ip_state(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i, j; + bool is_powered; + uint32_t inst_off; +diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h +index 3f91926a50e99..cbb19895ddaf5 100644 +--- a/drivers/gpu/drm/amd/include/amd_shared.h ++++ b/drivers/gpu/drm/amd/include/amd_shared.h +@@ -375,6 +375,8 @@ enum amd_dpm_forced_level; + * making calls to hooks from each IP block. This list is ordered to ensure + * that the driver initializes the IP blocks in a safe sequence. + */ ++struct amdgpu_ip_block; ++ + struct amd_ip_funcs { + char *name; + int (*early_init)(void *handle); +@@ -399,7 +401,7 @@ struct amd_ip_funcs { + int (*set_powergating_state)(void *handle, + enum amd_powergating_state state); + void (*get_clockgating_state)(void *handle, u64 *flags); +- void (*dump_ip_state)(void *handle); ++ void (*dump_ip_state)(struct amdgpu_ip_block *ip_block); + void (*print_ip_state)(void *handle, struct drm_printer *p); + }; + +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-update-the-handle-ptr-in-early_init.patch b/queue-6.12/drm-amdgpu-update-the-handle-ptr-in-early_init.patch new file mode 100644 index 0000000000..e6d5f10fa5 --- /dev/null +++ b/queue-6.12/drm-amdgpu-update-the-handle-ptr-in-early_init.patch @@ -0,0 +1,1527 @@ +From 2791d633953c360bfd50064c09bb9fb346e9a604 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Sep 2024 16:59:51 +0530 +Subject: drm/amdgpu: update the handle ptr in early_init +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sunil Khatri + +[ Upstream commit 146b085eadd2ce405e67492a80d6e767748d5642 ] + +update the handle ptr to amdgpu_ip_block ptr +for all functions pointers on early_init. + +Signed-off-by: Sunil Khatri +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Stable-dep-of: 8b3e8fa6d7bd ("drm/amdgpu/uvd4.2: Don't initialize UVD 4.2 when DPM is disabled") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 2 +- + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 24 +++++++++---------- + drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c | 5 ++-- + drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/cik.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/cik_ih.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/cz_ih.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/iceland_ih.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/ih_v6_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/ih_v6_1.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/ih_v7_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h | 2 +- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/mes_v12_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/navi10_ih.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/nv.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/si.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/si_dma.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/si_ih.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/soc15.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/soc21.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/soc24.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/tonga_ih.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vce_v4_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 6 ++--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vega10_ih.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vega20_ih.c | 4 ++-- + drivers/gpu/drm/amd/amdgpu/vi.c | 4 ++-- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++--- + drivers/gpu/drm/amd/include/amd_shared.h | 2 +- + drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c | 4 ++-- + drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c | 4 ++-- + .../gpu/drm/amd/pm/powerplay/amd_powerplay.c | 5 ++-- + drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 4 ++-- + 86 files changed, 182 insertions(+), 182 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +index bf6c4a0d05252..c4ca598756792 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +@@ -585,7 +585,7 @@ static int acp_resume(void *handle) + return 0; + } + +-static int acp_early_init(void *handle) ++static int acp_early_init(struct amdgpu_ip_block *ip_block) + { + return 0; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 778a0fcc34488..13e8bc2426f80 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -2639,25 +2639,25 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) + + total = true; + for (i = 0; i < adev->num_ip_blocks; i++) { ++ ip_block = &adev->ip_blocks[i]; ++ + if ((amdgpu_ip_block_mask & (1 << i)) == 0) { + DRM_WARN("disabled ip block: %d <%s>\n", + i, adev->ip_blocks[i].version->funcs->name); + adev->ip_blocks[i].status.valid = false; +- } else { +- if (adev->ip_blocks[i].version->funcs->early_init) { +- r = adev->ip_blocks[i].version->funcs->early_init((void *)adev); +- if (r == -ENOENT) { +- adev->ip_blocks[i].status.valid = false; +- } else if (r) { +- DRM_ERROR("early_init of IP block <%s> failed %d\n", +- adev->ip_blocks[i].version->funcs->name, r); +- total = false; +- } else { +- adev->ip_blocks[i].status.valid = true; +- } ++ } else if (ip_block->version->funcs->early_init) { ++ r = ip_block->version->funcs->early_init(ip_block); ++ if (r == -ENOENT) { ++ adev->ip_blocks[i].status.valid = false; ++ } else if (r) { ++ DRM_ERROR("early_init of IP block <%s> failed %d\n", ++ adev->ip_blocks[i].version->funcs->name, r); ++ total = false; + } else { + adev->ip_blocks[i].status.valid = true; + } ++ } else { ++ adev->ip_blocks[i].status.valid = true; + } + /* get the vbios after the asic_funcs are set up */ + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c +index 4766e99dd98fb..7c1f17dc6b4b6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c +@@ -122,9 +122,10 @@ static int isp_load_fw_by_psp(struct amdgpu_device *adev) + return r; + } + +-static int isp_early_init(void *handle) ++static int isp_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ ++ struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_isp *isp = &adev->isp; + + switch (amdgpu_ip_version(adev, ISP_HWIP, 0)) { +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +index 26260873f6a15..382125c64e4cd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +@@ -159,9 +159,9 @@ static int psp_init_sriov_microcode(struct psp_context *psp) + return ret; + } + +-static int psp_early_init(void *handle) ++static int psp_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + struct psp_context *psp = &adev->psp; + + psp->autoload_supported = true; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c +index d5125523bfa7b..2b9bf1c1951cb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c +@@ -765,9 +765,9 @@ static int umsch_mm_init(struct amdgpu_device *adev) + } + + +-static int umsch_mm_early_init(void *handle) ++static int umsch_mm_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + switch (amdgpu_ip_version(adev, VCN_HWIP, 0)) { + case IP_VERSION(4, 0, 5): +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c +index bf4d2e3f23956..9312b6a9e3be7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c +@@ -295,9 +295,9 @@ int amdgpu_vpe_ring_fini(struct amdgpu_vpe *vpe) + return 0; + } + +-static int vpe_early_init(void *handle) ++static int vpe_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_vpe *vpe = &adev->vpe; + + switch (amdgpu_ip_version(adev, VPE_HWIP, 0)) { +diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c +index cf1d5d462b676..0a0114de11b49 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cik.c ++++ b/drivers/gpu/drm/amd/amdgpu/cik.c +@@ -1985,9 +1985,9 @@ static const struct amdgpu_asic_funcs cik_asic_funcs = + .query_video_codecs = &cik_query_video_codecs, + }; + +-static int cik_common_early_init(void *handle) ++static int cik_common_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->smc_rreg = &cik_smc_rreg; + adev->smc_wreg = &cik_smc_wreg; +diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c +index 576baa9dbb0e1..5ccd7e2ebf675 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c +@@ -283,9 +283,9 @@ static void cik_ih_set_rptr(struct amdgpu_device *adev, + WREG32(mmIH_RB_RPTR, ih->rptr); + } + +-static int cik_ih_early_init(void *handle) ++static int cik_ih_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int ret; + + ret = amdgpu_irq_add_domain(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +index 952737de94111..3565dbcf7e38d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c ++++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +@@ -918,9 +918,9 @@ static void cik_enable_sdma_mgls(struct amdgpu_device *adev, + } + } + +-static int cik_sdma_early_init(void *handle) ++static int cik_sdma_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + adev->sdma.num_instances = SDMA_MAX_INSTANCE; +diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c +index 0726437873845..bbc50a8e3bc48 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c +@@ -274,9 +274,9 @@ static void cz_ih_set_rptr(struct amdgpu_device *adev, + WREG32(mmIH_RB_RPTR, ih->rptr); + } + +-static int cz_ih_early_init(void *handle) ++static int cz_ih_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int ret; + + ret = amdgpu_irq_add_domain(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +index baafbb5c032af..daed4a8439cc8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +@@ -2733,9 +2733,9 @@ static int dce_v10_0_crtc_init(struct amdgpu_device *adev, int index) + return 0; + } + +-static int dce_v10_0_early_init(void *handle) ++static int dce_v10_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->audio_endpt_rreg = &dce_v10_0_audio_endpt_rreg; + adev->audio_endpt_wreg = &dce_v10_0_audio_endpt_wreg; +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +index a67b6b20b677c..b00be90eb981a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +@@ -2846,9 +2846,9 @@ static int dce_v11_0_crtc_init(struct amdgpu_device *adev, int index) + return 0; + } + +-static int dce_v11_0_early_init(void *handle) ++static int dce_v11_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->audio_endpt_rreg = &dce_v11_0_audio_endpt_rreg; + adev->audio_endpt_wreg = &dce_v11_0_audio_endpt_wreg; +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +index 1036b7a373903..1e15348a5c7df 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +@@ -2628,9 +2628,9 @@ static int dce_v6_0_crtc_init(struct amdgpu_device *adev, int index) + return 0; + } + +-static int dce_v6_0_early_init(void *handle) ++static int dce_v6_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->audio_endpt_rreg = &dce_v6_0_audio_endpt_rreg; + adev->audio_endpt_wreg = &dce_v6_0_audio_endpt_wreg; +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +index 0b30b3ed9d4b9..7e92f322bc339 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +@@ -2639,9 +2639,9 @@ static int dce_v8_0_crtc_init(struct amdgpu_device *adev, int index) + return 0; + } + +-static int dce_v8_0_early_init(void *handle) ++static int dce_v8_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->audio_endpt_rreg = &dce_v8_0_audio_endpt_rreg; + adev->audio_endpt_wreg = &dce_v8_0_audio_endpt_wreg; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index a715c7796f94b..a6e22c897b9d3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -7678,9 +7678,9 @@ static void gfx_v10_0_ring_emit_gds_switch(struct amdgpu_ring *ring, + (1 << (oa_size + oa_base)) - (1 << oa_base)); + } + +-static int gfx_v10_0_early_init(void *handle) ++static int gfx_v10_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->gfx.funcs = &gfx_v10_0_gfx_funcs; + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index 0e99122ced4fb..6b5b5fcdb988c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -5037,9 +5037,9 @@ static void gfx_v11_0_ring_emit_gds_switch(struct amdgpu_ring *ring, + (1 << (oa_size + oa_base)) - (1 << oa_base)); + } + +-static int gfx_v11_0_early_init(void *handle) ++static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->gfx.funcs = &gfx_v11_0_gfx_funcs; + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +index 3f3f44b9fdaf9..97116a92cd8b3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +@@ -3712,9 +3712,9 @@ static uint64_t gfx_v12_0_get_gpu_clock_counter(struct amdgpu_device *adev) + return clock; + } + +-static int gfx_v12_0_early_init(void *handle) ++static int gfx_v12_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->gfx.funcs = &gfx_v12_0_gfx_funcs; + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index 564f0b9336b6a..cc9f9b10b435b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -3023,9 +3023,9 @@ static const struct amdgpu_rlc_funcs gfx_v6_0_rlc_funcs = { + .start = gfx_v6_0_rlc_start + }; + +-static int gfx_v6_0_early_init(void *handle) ++static int gfx_v6_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->gfx.xcc_mask = 1; + adev->gfx.num_gfx_rings = GFX6_NUM_GFX_RINGS; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +index f146806c4633b..3babf5b5a9dd2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +@@ -4134,9 +4134,9 @@ static const struct amdgpu_rlc_funcs gfx_v7_0_rlc_funcs = { + .update_spm_vmid = gfx_v7_0_update_spm_vmid + }; + +-static int gfx_v7_0_early_init(void *handle) ++static int gfx_v7_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->gfx.xcc_mask = 1; + adev->gfx.num_gfx_rings = GFX7_NUM_GFX_RINGS; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +index 1f675d67a1a78..2e54fb63dd5bc 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +@@ -5262,9 +5262,9 @@ static const struct amdgpu_gfx_funcs gfx_v8_0_gfx_funcs = { + .select_me_pipe_q = &gfx_v8_0_select_me_pipe_q + }; + +-static int gfx_v8_0_early_init(void *handle) ++static int gfx_v8_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->gfx.xcc_mask = 1; + adev->gfx.num_gfx_rings = GFX8_NUM_GFX_RINGS; +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index 8c9d21854f820..d16ac8669e07b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -4760,9 +4760,9 @@ static int gfx_v9_0_do_edc_gpr_workarounds(struct amdgpu_device *adev) + return r; + } + +-static int gfx_v9_0_early_init(void *handle) ++static int gfx_v9_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->gfx.funcs = &gfx_v9_0_gfx_funcs; + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +index a6426dd37fbcc..15d482990297c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +@@ -2517,9 +2517,9 @@ static void gfx_v9_4_3_ring_emit_gds_switch(struct amdgpu_ring *ring, + (1 << (oa_size + oa_base)) - (1 << oa_base)); + } + +-static int gfx_v9_4_3_early_init(void *handle) ++static int gfx_v9_4_3_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev), + AMDGPU_MAX_COMPUTE_RINGS); +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +index c6e7429212827..86a7261df8b7f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +@@ -630,9 +630,9 @@ static void gmc_v10_0_set_gfxhub_funcs(struct amdgpu_device *adev) + } + + +-static int gmc_v10_0_early_init(void *handle) ++static int gmc_v10_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + gmc_v10_0_set_mmhub_funcs(adev); + gmc_v10_0_set_gfxhub_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +index abbf49c90e57b..789b4f531f315 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +@@ -628,9 +628,9 @@ static void gmc_v11_0_set_gfxhub_funcs(struct amdgpu_device *adev) + } + } + +-static int gmc_v11_0_early_init(void *handle) ++static int gmc_v11_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + gmc_v11_0_set_gfxhub_funcs(adev); + gmc_v11_0_set_mmhub_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +index 729f343c17a75..aaa6307254ff1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +@@ -614,9 +614,9 @@ static void gmc_v12_0_set_gfxhub_funcs(struct amdgpu_device *adev) + } + } + +-static int gmc_v12_0_early_init(void *handle) ++static int gmc_v12_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + gmc_v12_0_set_gfxhub_funcs(adev); + gmc_v12_0_set_mmhub_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +index d36725666b54c..3a524319f31e1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +@@ -762,9 +762,9 @@ static int gmc_v6_0_convert_vram_type(int mc_seq_vram_type) + } + } + +-static int gmc_v6_0_early_init(void *handle) ++static int gmc_v6_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + gmc_v6_0_set_gmc_funcs(adev); + gmc_v6_0_set_irq_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +index 8e2f731256504..ece404a738e06 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +@@ -921,9 +921,9 @@ static int gmc_v7_0_convert_vram_type(int mc_seq_vram_type) + } + } + +-static int gmc_v7_0_early_init(void *handle) ++static int gmc_v7_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + gmc_v7_0_set_gmc_funcs(adev); + gmc_v7_0_set_irq_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +index 5248832c04adf..52f5843f8a37b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +@@ -1027,9 +1027,9 @@ static int gmc_v8_0_convert_vram_type(int mc_seq_vram_type) + } + } + +-static int gmc_v8_0_early_init(void *handle) ++static int gmc_v8_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + gmc_v8_0_set_gmc_funcs(adev); + gmc_v8_0_set_irq_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +index 91c6464efed2a..d82f90f480240 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +@@ -1554,9 +1554,9 @@ static void gmc_v9_0_set_xgmi_ras_funcs(struct amdgpu_device *adev) + adev->gmc.xgmi.ras = &xgmi_ras; + } + +-static int gmc_v9_0_early_init(void *handle) ++static int gmc_v9_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + /* + * 9.4.0, 9.4.1 and 9.4.3 don't have XGMI defined +diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +index 07984f7c3ae77..87b29600cf1fb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +@@ -273,9 +273,9 @@ static void iceland_ih_set_rptr(struct amdgpu_device *adev, + WREG32(mmIH_RB_RPTR, ih->rptr); + } + +-static int iceland_ih_early_init(void *handle) ++static int iceland_ih_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int ret; + + ret = amdgpu_irq_add_domain(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c +index 18a761d6ef330..fa6c7e5fbbe3b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c +@@ -559,9 +559,9 @@ static void ih_v6_0_set_self_irq_funcs(struct amdgpu_device *adev) + adev->irq.self_irq.funcs = &ih_v6_0_self_irq_funcs; + } + +-static int ih_v6_0_early_init(void *handle) ++static int ih_v6_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + ih_v6_0_set_interrupt_funcs(adev); + ih_v6_0_set_self_irq_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c +index 2e0469feca1e9..ebe23630e8f67 100644 +--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c +@@ -532,9 +532,9 @@ static void ih_v6_1_set_self_irq_funcs(struct amdgpu_device *adev) + adev->irq.self_irq.funcs = &ih_v6_1_self_irq_funcs; + } + +-static int ih_v6_1_early_init(void *handle) ++static int ih_v6_1_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int ret; + + ret = amdgpu_irq_add_domain(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c +index 6852081fcff21..1619f0ba4d1b9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c +@@ -528,9 +528,9 @@ static void ih_v7_0_set_self_irq_funcs(struct amdgpu_device *adev) + adev->irq.self_irq.funcs = &ih_v7_0_self_irq_funcs; + } + +-static int ih_v7_0_early_init(void *handle) ++static int ih_v7_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + ih_v7_0_set_interrupt_funcs(adev); + ih_v7_0_set_self_irq_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c +index 6e0e88076224b..8effd6dc65d41 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c +@@ -462,9 +462,9 @@ static int jpeg_v1_0_process_interrupt(struct amdgpu_device *adev, + * + * Set ring and irq function pointers + */ +-int jpeg_v1_0_early_init(void *handle) ++int jpeg_v1_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->jpeg.num_jpeg_inst = 1; + adev->jpeg.num_jpeg_rings = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h +index 9654d22e03763..791de235cd8bd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h +@@ -24,7 +24,7 @@ + #ifndef __JPEG_V1_0_H__ + #define __JPEG_V1_0_H__ + +-int jpeg_v1_0_early_init(void *handle); ++int jpeg_v1_0_early_init(struct amdgpu_ip_block *ip_block); + int jpeg_v1_0_sw_init(void *handle); + void jpeg_v1_0_sw_fini(void *handle); + void jpeg_v1_0_start(struct amdgpu_device *adev, int mode); +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +index 41c0f8750dc1d..341c551dad8b0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +@@ -45,9 +45,9 @@ static int jpeg_v2_0_set_powergating_state(void *handle, + * + * Set ring and irq function pointers + */ +-static int jpeg_v2_0_early_init(void *handle) ++static int jpeg_v2_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->jpeg.num_jpeg_inst = 1; + adev->jpeg.num_jpeg_rings = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +index eedb9a829d950..ec0fa685e1275 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +@@ -54,9 +54,9 @@ static int amdgpu_ih_clientid_jpeg[] = { + * + * Set ring and irq function pointers + */ +-static int jpeg_v2_5_early_init(void *handle) ++static int jpeg_v2_5_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + u32 harvest; + int i; + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +index b1e7fd25afbcb..dd00daa1d7eda 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +@@ -46,9 +46,9 @@ static int jpeg_v3_0_set_powergating_state(void *handle, + * + * Set ring and irq function pointers + */ +-static int jpeg_v3_0_early_init(void *handle) ++static int jpeg_v3_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + u32 harvest; + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +index 6c5c1a68a9b7b..b147e0eba31da 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +@@ -52,9 +52,9 @@ static void jpeg_v4_0_dec_ring_set_wptr(struct amdgpu_ring *ring); + * + * Set ring and irq function pointers + */ +-static int jpeg_v4_0_early_init(void *handle) ++static int jpeg_v4_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + + adev->jpeg.num_jpeg_inst = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +index ae9b95dd8602d..fd0ba04a66045 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +@@ -72,9 +72,9 @@ static inline bool jpeg_v4_0_3_normalizn_reqd(struct amdgpu_device *adev) + * + * Set ring and irq function pointers + */ +-static int jpeg_v4_0_3_early_init(void *handle) ++static int jpeg_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS; + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +index 44eeed445ea91..48ab3e0a62d25 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +@@ -65,9 +65,9 @@ static int amdgpu_ih_clientid_jpeg[] = { + * + * Set ring and irq function pointers + */ +-static int jpeg_v4_0_5_early_init(void *handle) ++static int jpeg_v4_0_5_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) { + case IP_VERSION(4, 0, 5): +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +index d662aa841f971..61288104060de 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +@@ -46,9 +46,9 @@ static int jpeg_v5_0_0_set_powergating_state(void *handle, + * + * Set ring and irq function pointers + */ +-static int jpeg_v5_0_0_early_init(void *handle) ++static int jpeg_v5_0_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->jpeg.num_jpeg_inst = 1; + adev->jpeg.num_jpeg_rings = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +index ccd9055360fcc..236fedc5b1838 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +@@ -1633,9 +1633,9 @@ static int mes_v11_0_resume(void *handle) + return amdgpu_mes_resume(adev); + } + +-static int mes_v11_0_early_init(void *handle) ++static int mes_v11_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int pipe, r; + + for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { +diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +index 945016712157d..c432a2a3405d6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +@@ -1628,9 +1628,9 @@ static int mes_v12_0_resume(void *handle) + return amdgpu_mes_resume(adev); + } + +-static int mes_v12_0_early_init(void *handle) ++static int mes_v12_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int pipe, r; + + for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { +diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +index b281462093f11..17aab897f86b9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +@@ -542,9 +542,9 @@ static void navi10_ih_set_self_irq_funcs(struct amdgpu_device *adev) + adev->irq.self_irq.funcs = &navi10_ih_self_irq_funcs; + } + +-static int navi10_ih_early_init(void *handle) ++static int navi10_ih_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + navi10_ih_set_interrupt_funcs(adev); + navi10_ih_set_self_irq_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c +index ab0eecbab4125..ba8341c62255f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/nv.c ++++ b/drivers/gpu/drm/amd/amdgpu/nv.c +@@ -634,9 +634,9 @@ static const struct amdgpu_asic_funcs nv_asic_funcs = { + .query_video_codecs = &nv_query_video_codecs, + }; + +-static int nv_common_early_init(void *handle) ++static int nv_common_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->nbio.funcs->set_reg_remap(adev); + adev->smc_rreg = NULL; +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +index 725392522267f..5b81985588690 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +@@ -807,9 +807,9 @@ static void sdma_v2_4_ring_emit_wreg(struct amdgpu_ring *ring, + amdgpu_ring_write(ring, val); + } + +-static int sdma_v2_4_early_init(void *handle) ++static int sdma_v2_4_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + adev->sdma.num_instances = SDMA_MAX_INSTANCE; +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +index e65194fe94af6..37275b38bca82 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +@@ -1080,9 +1080,9 @@ static void sdma_v3_0_ring_emit_wreg(struct amdgpu_ring *ring, + amdgpu_ring_write(ring, val); + } + +-static int sdma_v3_0_early_init(void *handle) ++static int sdma_v3_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + switch (adev->asic_type) { +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +index 4798c2681b606..dafd2ecac8e49 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +@@ -1751,9 +1751,9 @@ static bool sdma_v4_0_fw_support_paging_queue(struct amdgpu_device *adev) + } + } + +-static int sdma_v4_0_early_init(void *handle) ++static int sdma_v4_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + r = sdma_v4_0_init_microcode(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +index c378668044c34..8c97a67f4c9f0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +@@ -1296,9 +1296,9 @@ static bool sdma_v4_4_2_fw_support_paging_queue(struct amdgpu_device *adev) + } + } + +-static int sdma_v4_4_2_early_init(void *handle) ++static int sdma_v4_4_2_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + r = sdma_v4_4_2_init_microcode(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +index 3ecf77ce2f1af..34fcbcdd93b6c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +@@ -1366,9 +1366,9 @@ static void sdma_v5_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring, + amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); + } + +-static int sdma_v5_0_early_init(void *handle) ++static int sdma_v5_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + r = sdma_v5_0_init_microcode(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +index d19dde1d6fc5b..241995252ff0b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +@@ -1216,9 +1216,9 @@ static void sdma_v5_2_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring, + amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); + } + +-static int sdma_v5_2_early_init(void *handle) ++static int sdma_v5_2_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + r = amdgpu_sdma_init_microcode(adev, 0, true); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +index 981b63a74cfc8..74e79ddd714ac 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +@@ -1272,9 +1272,9 @@ static void sdma_v6_0_set_ras_funcs(struct amdgpu_device *adev) + } + } + +-static int sdma_v6_0_early_init(void *handle) ++static int sdma_v6_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + r = amdgpu_sdma_init_microcode(adev, 0, true); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +index b5897c98ebf05..1d0131c172d61 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +@@ -1259,9 +1259,9 @@ static void sdma_v7_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring, + amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); + } + +-static int sdma_v7_0_early_init(void *handle) ++static int sdma_v7_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int r; + + r = amdgpu_sdma_init_microcode(adev, 0, true); +diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c +index 85235470e872c..93c68abf447a6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si.c ++++ b/drivers/gpu/drm/amd/amdgpu/si.c +@@ -2022,9 +2022,9 @@ static uint32_t si_get_rev_id(struct amdgpu_device *adev) + >> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT; + } + +-static int si_common_early_init(void *handle) ++static int si_common_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->smc_rreg = &si_smc_rreg; + adev->smc_wreg = &si_smc_wreg; +diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c +index 11db5b7558321..791d492e991d4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si_dma.c ++++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c +@@ -457,9 +457,9 @@ static void si_dma_ring_emit_wreg(struct amdgpu_ring *ring, + amdgpu_ring_write(ring, val); + } + +-static int si_dma_early_init(void *handle) ++static int si_dma_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->sdma.num_instances = 2; + +diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c +index 5237395e4fab5..bd2ae82554982 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c +@@ -156,9 +156,9 @@ static void si_ih_set_rptr(struct amdgpu_device *adev, + WREG32(IH_RB_RPTR, ih->rptr); + } + +-static int si_ih_early_init(void *handle) ++static int si_ih_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + si_ih_set_interrupt_funcs(adev); + +diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c +index c162149b5494f..5b65b760cc914 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc15.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc15.c +@@ -928,9 +928,9 @@ static const struct amdgpu_asic_funcs aqua_vanjaram_asic_funcs = + .get_reg_state = &aqua_vanjaram_get_reg_state, + }; + +-static int soc15_common_early_init(void *handle) ++static int soc15_common_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->nbio.funcs->set_reg_remap(adev); + adev->smc_rreg = NULL; +diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c +index 7d570325167ec..1287dd875e3d2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc21.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc21.c +@@ -556,9 +556,9 @@ static const struct amdgpu_asic_funcs soc21_asic_funcs = { + .update_umd_stable_pstate = &soc21_update_umd_stable_pstate, + }; + +-static int soc21_common_early_init(void *handle) ++static int soc21_common_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->nbio.funcs->set_reg_remap(adev); + adev->smc_rreg = NULL; +diff --git a/drivers/gpu/drm/amd/amdgpu/soc24.c b/drivers/gpu/drm/amd/amdgpu/soc24.c +index 29a848f2466bb..53d96edc2877a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc24.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc24.c +@@ -363,9 +363,9 @@ static const struct amdgpu_asic_funcs soc24_asic_funcs = { + .update_umd_stable_pstate = &soc24_update_umd_stable_pstate, + }; + +-static int soc24_common_early_init(void *handle) ++static int soc24_common_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->nbio.funcs->set_reg_remap(adev); + adev->smc_rreg = NULL; +diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +index 24d49d813607f..ae27dac941177 100644 +--- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +@@ -283,9 +283,9 @@ static void tonga_ih_set_rptr(struct amdgpu_device *adev, + } + } + +-static int tonga_ih_early_init(void *handle) ++static int tonga_ih_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int ret; + + ret = amdgpu_irq_add_domain(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index 21376d98ee498..2dd89f490dc37 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -531,9 +531,9 @@ static void uvd_v3_1_set_irq_funcs(struct amdgpu_device *adev) + } + + +-static int uvd_v3_1_early_init(void *handle) ++static int uvd_v3_1_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + adev->uvd.num_uvd_inst = 1; + + uvd_v3_1_set_ring_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +index 3f19c606f4de5..5c46174dabbf3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +@@ -90,9 +90,9 @@ static void uvd_v4_2_ring_set_wptr(struct amdgpu_ring *ring) + WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr)); + } + +-static int uvd_v4_2_early_init(void *handle) ++static int uvd_v4_2_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + adev->uvd.num_uvd_inst = 1; + + uvd_v4_2_set_ring_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +index efd903c21d48e..fd4acb1300f93 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +@@ -88,9 +88,9 @@ static void uvd_v5_0_ring_set_wptr(struct amdgpu_ring *ring) + WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr)); + } + +-static int uvd_v5_0_early_init(void *handle) ++static int uvd_v5_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + adev->uvd.num_uvd_inst = 1; + + uvd_v5_0_set_ring_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +index 495de50684554..e05e81d6fbd49 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +@@ -354,9 +354,9 @@ static int uvd_v6_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) + return r; + } + +-static int uvd_v6_0_early_init(void *handle) ++static int uvd_v6_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + adev->uvd.num_uvd_inst = 1; + + if (!(adev->flags & AMD_IS_APU) && +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +index 9a30b8c10838c..e3c20cbc7a00e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +@@ -361,9 +361,9 @@ static int uvd_v7_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) + return r; + } + +-static int uvd_v7_0_early_init(void *handle) ++static int uvd_v7_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + if (adev->asic_type == CHIP_VEGA20) { + u32 harvest; +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +index 66fada199bda2..97ce06228a910 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +@@ -398,9 +398,9 @@ static void vce_v2_0_enable_mgcg(struct amdgpu_device *adev, bool enable, + } + } + +-static int vce_v2_0_early_init(void *handle) ++static int vce_v2_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->vce.num_rings = 2; + +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +index 4bfba2931b088..31ca855a950af 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +@@ -396,9 +396,9 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) + } + } + +-static int vce_v3_0_early_init(void *handle) ++static int vce_v3_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); + +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +index 0748bf44c8808..14ead62ec57db 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +@@ -407,9 +407,9 @@ static int vce_v4_0_stop(struct amdgpu_device *adev) + return 0; + } + +-static int vce_v4_0_early_init(void *handle) ++static int vce_v4_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + if (amdgpu_sriov_vf(adev)) /* currently only VCN0 support SRIOV */ + adev->vce.num_rings = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +index 78dfcd02d8da4..563721c551634 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +@@ -100,9 +100,9 @@ static void vcn_v1_0_ring_begin_use(struct amdgpu_ring *ring); + * Set ring and irq function pointers + * Load microcode from filesystem + */ +-static int vcn_v1_0_early_init(void *handle) ++static int vcn_v1_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->vcn.num_enc_rings = 2; + +@@ -110,7 +110,7 @@ static int vcn_v1_0_early_init(void *handle) + vcn_v1_0_set_enc_ring_funcs(adev); + vcn_v1_0_set_irq_funcs(adev); + +- jpeg_v1_0_early_init(handle); ++ jpeg_v1_0_early_init(ip_block); + + return amdgpu_vcn_early_init(adev); + } +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index ca144ff63dc83..5431b2589ed61 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -106,9 +106,9 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev); + * Set ring and irq function pointers + * Load microcode from filesystem + */ +-static int vcn_v2_0_early_init(void *handle) ++static int vcn_v2_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + if (amdgpu_sriov_vf(adev)) + adev->vcn.num_enc_rings = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +index 90bebead51969..9708b9a47b536 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +@@ -116,9 +116,9 @@ static int amdgpu_ih_clientid_vcns[] = { + * Set ring and irq function pointers + * Load microcode from filesystem + */ +-static int vcn_v2_5_early_init(void *handle) ++static int vcn_v2_5_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + if (amdgpu_sriov_vf(adev)) { + adev->vcn.num_vcn_inst = 2; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +index 99e9679b4752a..53428a364c1ae 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +@@ -122,9 +122,9 @@ static void vcn_v3_0_enc_ring_set_wptr(struct amdgpu_ring *ring); + * Set ring and irq function pointers + * Load microcode from filesystem + */ +-static int vcn_v3_0_early_init(void *handle) ++static int vcn_v3_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + if (amdgpu_sriov_vf(adev)) { + adev->vcn.num_vcn_inst = VCN_INSTANCES_SIENNA_CICHLID; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +index fd8774745e771..041531a799d46 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +@@ -112,9 +112,9 @@ static void vcn_v4_0_set_ras_funcs(struct amdgpu_device *adev); + * Set ring and irq function pointers + * Load microcode from filesystem + */ +-static int vcn_v4_0_early_init(void *handle) ++static int vcn_v4_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + int i; + + if (amdgpu_sriov_vf(adev)) { +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +index 65a78a2e1b69f..1cdf0a381f6b7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +@@ -103,9 +103,9 @@ static void vcn_v4_0_3_enable_ras(struct amdgpu_device *adev, + * + * Set ring and irq function pointers + */ +-static int vcn_v4_0_3_early_init(void *handle) ++static int vcn_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + /* re-use enc ring as unified ring */ + adev->vcn.num_enc_rings = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +index a739e667e6158..e2533776173ca 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +@@ -110,9 +110,9 @@ static void vcn_v4_0_5_unified_ring_set_wptr(struct amdgpu_ring *ring); + * Set ring and irq function pointers + * Load microcode from filesystem + */ +-static int vcn_v4_0_5_early_init(void *handle) ++static int vcn_v4_0_5_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + /* re-use enc ring as unified ring */ + adev->vcn.num_enc_rings = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +index 019bc6b1cd3b4..e21193111d4d4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +@@ -92,9 +92,9 @@ static void vcn_v5_0_0_unified_ring_set_wptr(struct amdgpu_ring *ring); + * Set ring and irq function pointers + * Load microcode from filesystem + */ +-static int vcn_v5_0_0_early_init(void *handle) ++static int vcn_v5_0_0_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + /* re-use enc ring as unified ring */ + adev->vcn.num_enc_rings = 1; +diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +index bf68e18e3824b..5b0c81d510e7b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +@@ -472,9 +472,9 @@ static void vega10_ih_set_self_irq_funcs(struct amdgpu_device *adev) + adev->irq.self_irq.funcs = &vega10_ih_self_irq_funcs; + } + +-static int vega10_ih_early_init(void *handle) ++static int vega10_ih_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + vega10_ih_set_interrupt_funcs(adev); + vega10_ih_set_self_irq_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +index 16f5561fb86ec..a96c7737d1b4f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c ++++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +@@ -553,9 +553,9 @@ static void vega20_ih_set_self_irq_funcs(struct amdgpu_device *adev) + adev->irq.self_irq.funcs = &vega20_ih_self_irq_funcs; + } + +-static int vega20_ih_early_init(void *handle) ++static int vega20_ih_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + vega20_ih_set_interrupt_funcs(adev); + vega20_ih_set_self_irq_funcs(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c +index 6e4f9c6108f60..80d06a7c1db7e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vi.c ++++ b/drivers/gpu/drm/amd/amdgpu/vi.c +@@ -1455,9 +1455,9 @@ static const struct amdgpu_asic_funcs vi_asic_funcs = + #define CZ_REV_BRISTOL(rev) \ + ((rev >= 0xC8 && rev <= 0xCE) || (rev >= 0xE1 && rev <= 0xE6)) + +-static int vi_common_early_init(void *handle) ++static int vi_common_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + if (adev->flags & AMD_IS_APU) { + adev->smc_rreg = &cz_smc_rreg; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 1ed631006e63f..ad9125f3655fa 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -975,7 +975,7 @@ static int dm_set_powergating_state(void *handle, + } + + /* Prototypes of private functions */ +-static int dm_early_init(void *handle); ++static int dm_early_init(struct amdgpu_ip_block *ip_block); + + /* Allocate memory for FBC compressed data */ + static void amdgpu_dm_fbc_init(struct drm_connector *connector) +@@ -5386,9 +5386,9 @@ static int dm_init_microcode(struct amdgpu_device *adev) + return r; + } + +-static int dm_early_init(void *handle) ++static int dm_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + struct amdgpu_mode_info *mode_info = &adev->mode_info; + struct atom_context *ctx = mode_info->atom_context; + int index = GetIndexIntoMasterTable(DATA, Object_Header); +diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h +index cbb19895ddaf5..847ca23a7c858 100644 +--- a/drivers/gpu/drm/amd/include/amd_shared.h ++++ b/drivers/gpu/drm/amd/include/amd_shared.h +@@ -379,7 +379,7 @@ struct amdgpu_ip_block; + + struct amd_ip_funcs { + char *name; +- int (*early_init)(void *handle); ++ int (*early_init)(struct amdgpu_ip_block *ip_block); + int (*late_init)(void *handle); + int (*sw_init)(void *handle); + int (*sw_fini)(void *handle); +diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +index 8cf7e517da842..e4820d8850ba2 100644 +--- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c ++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +@@ -2954,9 +2954,9 @@ static int kv_dpm_get_temp(void *handle) + return actual_temp; + } + +-static int kv_dpm_early_init(void *handle) ++static int kv_dpm_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->powerplay.pp_funcs = &kv_dpm_funcs; + adev->powerplay.pp_handle = adev; +diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +index 26defd72a36cf..b5ecef3f75bbe 100644 +--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c ++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +@@ -7972,10 +7972,10 @@ static void si_dpm_print_power_state(void *handle, + amdgpu_dpm_print_ps_status(adev, rps); + } + +-static int si_dpm_early_init(void *handle) ++static int si_dpm_early_init(struct amdgpu_ip_block *ip_block) + { + +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + + adev->powerplay.pp_funcs = &si_dpm_funcs; + adev->powerplay.pp_handle = adev; +diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +index 24b25cddf0c14..78721bce42fd5 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +@@ -80,11 +80,10 @@ static void amd_powerplay_destroy(struct amdgpu_device *adev) + hwmgr = NULL; + } + +-static int pp_early_init(void *handle) ++static int pp_early_init(struct amdgpu_ip_block *ip_block) + { + int ret; +- struct amdgpu_device *adev = handle; +- ++ struct amdgpu_device *adev = ip_block->adev; + ret = amd_powerplay_create(adev); + + if (ret != 0) +diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +index dff21c1f70152..a6683a8cebf2b 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +@@ -746,9 +746,9 @@ static int smu_set_funcs(struct amdgpu_device *adev) + return 0; + } + +-static int smu_early_init(void *handle) ++static int smu_early_init(struct amdgpu_ip_block *ip_block) + { +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct amdgpu_device *adev = ip_block->adev; + struct smu_context *smu; + int r; + +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch b/queue-6.12/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch new file mode 100644 index 0000000000..0a91bb0b14 --- /dev/null +++ b/queue-6.12/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch @@ -0,0 +1,65 @@ +From 8be30a4e5080cbd5e6dc33efe218e61eb20eaaa8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:31 +0200 +Subject: drm/amdgpu/uvd3.1: Don't validate the firmware when already validated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ] + +UVD 3.1 firmware validation seems to always fail after +attempting it when it had already been validated. +(This works similarly with the VCE 1.0 as well.) + +Don't attempt repeating the validation when it's already done. + +This caused issues in situations when the system isn't able +to suspend the GPU properly and so the GPU isn't actually +powered down. Then amdgpu would fail when calling the IP +block resume function. + +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2887 +Fixes: bb7978111dd3 ("drm/amdgpu: fix SI UVD firmware validate resume fail") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 889a2cfd889c4a4dd9d0c89ce9a8e60b78be71dd) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index 4dd1595dc3d88..0344f74cc4547 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + ++ /* When the keyselect is already set, don't perturb it. */ ++ if (RREG32(mmUVD_FW_START)) ++ return; ++ + /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; +@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) + int i; + uint32_t keysel = adev->uvd.keyselect; + ++ if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { ++ dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", ++ RREG32(mmUVD_FW_START), adev->uvd.keyselect); ++ return 0; ++ } ++ + WREG32(mmUVD_FW_START, keysel); + + for (i = 0; i < 10; ++i) { +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch b/queue-6.12/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch new file mode 100644 index 0000000000..f7d6e8b9ee --- /dev/null +++ b/queue-6.12/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch @@ -0,0 +1,49 @@ +From c936fb76e575f2823dc7019975d76d9e17b2c8ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:06 +0200 +Subject: drm/amdgpu/uvd4.2: Don't initialize UVD 4.2 when DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 8b3e8fa6d7bdab292447a43f70532db437d5d4f5 ] + +UVD 4.2 doesn't work at all when DPM is disabled because +the SMU is responsible for ungating it. So, Linux fails +to boot with CIK GPUs when using the amdgpu.dpm=0 parameter. + +Fix this by returning -ENOENT from uvd_v4_2_early_init() +when amdgpu_dpm isn't enabled. + +Note: amdgpu.dpm=0 is often suggested as a workaround +for issues and is useful for debugging. + +Fixes: a2e73f56fa62 ("drm/amdgpu: Add support for CIK parts") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +index 5c46174dabbf3..0d291c497eed7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +@@ -93,6 +93,11 @@ static void uvd_v4_2_ring_set_wptr(struct amdgpu_ring *ring) + static int uvd_v4_2_early_init(struct amdgpu_ip_block *ip_block) + { + struct amdgpu_device *adev = ip_block->adev; ++ ++ /* UVD doesn't work without DPM, it needs DPM to ungate it. */ ++ if (!amdgpu_dpm) ++ return -ENOENT; ++ + adev->uvd.num_uvd_inst = 1; + + uvd_v4_2_set_ring_funcs(adev); +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch new file mode 100644 index 0000000000..1168d7bbfd --- /dev/null +++ b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch @@ -0,0 +1,49 @@ +From 5f685fb21c79d4ac1cb8e821d146caa1c2bbd7b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v2.0 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8d80b293b41fcb5e9396db93e788b0f4ebcbafb7 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 1b61de45dfaf ("drm/amdgpu: add initial VCN2.0 support (v2)") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit e2b5499fca55f1a32960a311bbb62e35891eaf73) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index 5431b2589ed61..29f5f6b1eb0a4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -2127,6 +2127,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = { + static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v2_0_dec_ring_get_rptr, + .get_wptr = vcn_v2_0_dec_ring_get_wptr, +@@ -2158,6 +2159,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v2_0_enc_ring_get_rptr, + .get_wptr = vcn_v2_0_enc_ring_get_wptr, + .set_wptr = vcn_v2_0_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch new file mode 100644 index 0000000000..29f2481c7e --- /dev/null +++ b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch @@ -0,0 +1,49 @@ +From 83bb2b8be7fa91b4e3c6c37a1fe663cd34294b2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v2.5 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 4f317863a3ab212a027d8c8c3cc3af4e3fb95704 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 28c17d72072b ("drm/amdgpu: add VCN2.5 basic supports") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit efc9dd5590894109bce9a0bfe1fa5592dd6b20b1) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +index 9708b9a47b536..42edc91f4a78d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +@@ -1628,6 +1628,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring) + static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v2_5_dec_ring_get_rptr, + .get_wptr = vcn_v2_5_dec_ring_get_wptr, +@@ -1728,6 +1729,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v2_5_enc_ring_get_rptr, + .get_wptr = vcn_v2_5_enc_ring_get_wptr, + .set_wptr = vcn_v2_5_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch new file mode 100644 index 0000000000..988c90f71b --- /dev/null +++ b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch @@ -0,0 +1,57 @@ +From ad532b7b09dafe4a5eef4209e9f5fc4501c25aab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v3.0 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit f1e5a6660d7cbf006079126d9babbf0ccf538c6b ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: cf14826cdfb5 ("drm/amdgpu: add VCN3.0 support for Sienna_Cichlid") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 663bed3c7b8b9a7624b0d95d300ddae034ad0614) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +index 53428a364c1ae..09f8324fdb990 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +@@ -1791,6 +1791,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0x3f, + .nop = VCN_DEC_SW_CMD_NO_OP, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v3_0_dec_ring_get_rptr, + .get_wptr = vcn_v3_0_dec_ring_get_wptr, +@@ -1972,6 +1973,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v3_0_dec_ring_get_rptr, + .get_wptr = vcn_v3_0_dec_ring_get_wptr, +@@ -2073,6 +2075,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v3_0_enc_ring_get_rptr, + .get_wptr = vcn_v3_0_enc_ring_get_wptr, + .set_wptr = vcn_v3_0_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch new file mode 100644 index 0000000000..fcaabb3697 --- /dev/null +++ b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch @@ -0,0 +1,41 @@ +From 25bd51edb57afcc5ca58e35405097f0e027c8de1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0.3 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 4532b52b34e4e4310386e6fdf6a643368599f522 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: b889ef4ac988 ("drm/amdgpu/vcn: add vcn support for VCN4_0_3") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit ff1a5a125c5a70c328806b9bc01d7d942cf3f9aa) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +index 1cdf0a381f6b7..7edb6da93fd2e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +@@ -1520,6 +1520,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, + .set_wptr = vcn_v4_0_3_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch new file mode 100644 index 0000000000..2ad6c42931 --- /dev/null +++ b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch @@ -0,0 +1,41 @@ +From 3abd5c1501cbcf491f4dcd306d1a9aabe6a4e83a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0.5 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 589a254bf3e88204c8402b9cbccd5e23a0af990f ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 547aad32edac ("drm/amdgpu: add VCN4 ip block support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 084d94ac93707bdda07efb5cee786f632de4219b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +index e2533776173ca..f0354a7dfb461 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +@@ -1414,6 +1414,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, + .set_wptr = vcn_v4_0_5_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch new file mode 100644 index 0000000000..3813301046 --- /dev/null +++ b/queue-6.12/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch @@ -0,0 +1,41 @@ +From 9cdb88e1d50351a16b1d5d62bd5395bee833030b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v5.0.0 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8cae0ce77de492d7c31c1532a2e80c0c6e7e58cb ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: b6d1a0632051 ("drm/amdgpu: add VCN_5_0_0 IP block support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 49b1fbbb5a071197ee71e2d70959b1cb29bdc317) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +index e21193111d4d4..f8994e4bdf4b6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +@@ -1137,6 +1137,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, + .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, + .set_wptr = vcn_v5_0_0_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch b/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch new file mode 100644 index 0000000000..decb88bb7d --- /dev/null +++ b/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch @@ -0,0 +1,75 @@ +From bbcde14831d9cbf5b8e27d3379b3d13e759ec7f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:28 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Add mode_valid hook to + drm_bridge_funcs + +From: Jayesh Choudhary + +[ Upstream commit 6dbff34016052b099558b76632e4983e2df13fed ] + +Add cdns_mhdp_bridge_mode_valid() to check if specific mode is valid for +this bridge or not. In the legacy usecase with +!DRM_BRIDGE_ATTACH_NO_CONNECTOR we were using the hook from +drm_connector_helper_funcs but with DRM_BRIDGE_ATTACH_NO_CONNECTOR +we need to have mode_valid() in drm_bridge_funcs. + +Without this patch, when using DRM_BRIDGE_ATTACH_NO_CONNECTOR +flag, the cdns_mhdp_bandwidth_ok() function would not be called +during mode validation, potentially allowing modes that exceed +the bridge's bandwidth capabilities to be incorrectly marked as +valid. + +Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") +Reviewed-by: Tomi Valkeinen +Signed-off-by: Jayesh Choudhary +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Link: https://patch.msgid.link/20251209120332.3559893-3-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index d718a908208f5..d56466e9b155f 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2231,6 +2231,25 @@ static const struct drm_edid *cdns_mhdp_bridge_edid_read(struct drm_bridge *brid + return cdns_mhdp_edid_read(mhdp, connector); + } + ++static enum drm_mode_status ++cdns_mhdp_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); ++ ++ mutex_lock(&mhdp->link_mutex); ++ ++ if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes, ++ mhdp->link.rate)) { ++ mutex_unlock(&mhdp->link_mutex); ++ return MODE_CLOCK_HIGH; ++ } ++ ++ mutex_unlock(&mhdp->link_mutex); ++ return MODE_OK; ++} ++ + static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { + .atomic_enable = cdns_mhdp_atomic_enable, + .atomic_disable = cdns_mhdp_atomic_disable, +@@ -2245,6 +2264,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { + .edid_read = cdns_mhdp_bridge_edid_read, + .hpd_enable = cdns_mhdp_bridge_hpd_enable, + .hpd_disable = cdns_mhdp_bridge_hpd_disable, ++ .mode_valid = cdns_mhdp_bridge_mode_valid, + }; + + static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse) +-- +2.53.0 + diff --git a/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch b/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch new file mode 100644 index 0000000000..3d6bfc93b8 --- /dev/null +++ b/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch @@ -0,0 +1,75 @@ +From ce8a866fd337dd2bda90c841919c85cb016d9404 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:29 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Handle HDCP state in bridge + atomic check + +From: Harikrishna Shenoy + +[ Upstream commit 4a8edd658489ec2a3d7e20482fa9e8d366153d8d ] + +Now that we have DRM_BRIDGE_ATTACH_NO_CONNECTOR framework, handle the +HDCP state change in bridge atomic check as well to enable correct +functioning for HDCP in both DRM_BRIDGE_ATTACH_NO_CONNECTOR and +!DRM_BRIDGE_ATTACH_NO_CONNECTOR case. + +Without this patch, when using DRM_BRIDGE_ATTACH_NO_CONNECTOR flag, HDCP +state changes would not be properly handled during atomic commits, +potentially leading to HDCP authentication failures or incorrect +protection status for content requiring HDCP encryption. + +Fixes: 6a3608eae6d33 ("drm: bridge: cdns-mhdp8546: Enable HDCP") +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Reviewed-by: Tomi Valkeinen +Link: https://patch.msgid.link/20251209120332.3559893-4-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index d56466e9b155f..3c4ea9bdefbea 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2193,6 +2193,10 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, + { + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; ++ struct drm_connector_state *old_state, *new_state; ++ struct drm_atomic_state *state = crtc_state->state; ++ struct drm_connector *conn = mhdp->connector_ptr; ++ u64 old_cp, new_cp; + + mutex_lock(&mhdp->link_mutex); + +@@ -2212,6 +2216,25 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, + if (mhdp->info) + bridge_state->input_bus_cfg.flags = *mhdp->info->input_bus_flags; + ++ if (conn && mhdp->hdcp_supported) { ++ old_state = drm_atomic_get_old_connector_state(state, conn); ++ new_state = drm_atomic_get_new_connector_state(state, conn); ++ old_cp = old_state->content_protection; ++ new_cp = new_state->content_protection; ++ ++ if (old_state->hdcp_content_type != new_state->hdcp_content_type && ++ new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { ++ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; ++ crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); ++ crtc_state->mode_changed = true; ++ } ++ ++ if (!new_state->crtc) { ++ if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ++ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; ++ } ++ } ++ + mutex_unlock(&mhdp->link_mutex); + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch b/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch new file mode 100644 index 0000000000..81e1e40b3d --- /dev/null +++ b/queue-6.12/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch @@ -0,0 +1,196 @@ +From bb5a23ada166b544d33578ffb5f4b5f26d9e6252 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:27 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Set the mhdp connector + earlier in atomic_enable() + +From: Jayesh Choudhary + +[ Upstream commit 43d6508ddbf9fb974fbc359a033154f78c9d4c8b ] + +In case if we get errors in cdns_mhdp_link_up() or cdns_mhdp_reg_read() +in atomic_enable, we will go to cdns_mhdp_modeset_retry_fn() and will hit +NULL pointer while trying to access the mutex. We need the connector to +be set before that. Unlike in legacy cases with flag +!DRM_BRIDGE_ATTACH_NO_CONNECTOR, we do not have connector initialised +in bridge_attach(), so add the mhdp->connector_ptr in device structure +to handle both cases with DRM_BRIDGE_ATTACH_NO_CONNECTOR and +!DRM_BRIDGE_ATTACH_NO_CONNECTOR, set it in atomic_enable() earlier to +avoid possible NULL pointer dereference in recovery paths like +modeset_retry_fn() with the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag set. + +Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") +Signed-off-by: Jayesh Choudhary +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Reviewed-by: Tomi Valkeinen +Link: https://patch.msgid.link/20251209120332.3559893-2-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 29 ++++++++++--------- + .../drm/bridge/cadence/cdns-mhdp8546-core.h | 1 + + .../drm/bridge/cadence/cdns-mhdp8546-hdcp.c | 18 +++++++++--- + 3 files changed, 30 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index b18bdb2daddf8..d718a908208f5 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -810,7 +810,7 @@ static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context) + bridge_attached = mhdp->bridge_attached; + spin_unlock(&mhdp->start_lock); + if (bridge_attached) { +- if (mhdp->connector.dev) ++ if (mhdp->connector_ptr) + drm_kms_helper_hotplug_event(mhdp->bridge.dev); + else + drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); +@@ -1706,6 +1706,7 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp) + return ret; + } + ++ mhdp->connector_ptr = conn; + drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs); + + ret = drm_display_info_set_bus_formats(&conn->display_info, +@@ -1985,17 +1986,25 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state = bridge_state->base.state; + struct cdns_mhdp_bridge_state *mhdp_state; + struct drm_crtc_state *crtc_state; +- struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_bridge_state *new_state; + const struct drm_display_mode *mode; + u32 resp; +- int ret; ++ int ret = 0; + + dev_dbg(mhdp->dev, "bridge enable\n"); + + mutex_lock(&mhdp->link_mutex); + ++ mhdp->connector_ptr = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); ++ if (WARN_ON(!mhdp->connector_ptr)) ++ goto out; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, mhdp->connector_ptr); ++ if (WARN_ON(!conn_state)) ++ goto out; ++ + if (mhdp->plugged && !mhdp->link_up) { + ret = cdns_mhdp_link_up(mhdp); + if (ret < 0) +@@ -2015,15 +2024,6 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, + resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN); + +- connector = drm_atomic_get_new_connector_for_encoder(state, +- bridge->encoder); +- if (WARN_ON(!connector)) +- goto out; +- +- conn_state = drm_atomic_get_new_connector_state(state, connector); +- if (WARN_ON(!conn_state)) +- goto out; +- + if (mhdp->hdcp_supported && + mhdp->hw_state == MHDP_HW_READY && + conn_state->content_protection == +@@ -2100,6 +2100,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, + if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable) + mhdp->info->ops->disable(mhdp); + ++ mhdp->connector_ptr = NULL; + mutex_unlock(&mhdp->link_mutex); + } + +@@ -2365,7 +2366,7 @@ static void cdns_mhdp_modeset_retry_fn(struct work_struct *work) + + mhdp = container_of(work, typeof(*mhdp), modeset_retry_work); + +- conn = &mhdp->connector; ++ conn = mhdp->connector_ptr; + + /* Grab the locks before changing connector property */ + mutex_lock(&conn->dev->mode_config.mutex); +@@ -2442,7 +2443,7 @@ static void cdns_mhdp_hpd_work(struct work_struct *work) + int ret; + + ret = cdns_mhdp_update_link_status(mhdp); +- if (mhdp->connector.dev) { ++ if (mhdp->connector_ptr) { + if (ret < 0) + schedule_work(&mhdp->modeset_retry_work); + else +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +index bad2fc0c73066..a76775c768956 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +@@ -376,6 +376,7 @@ struct cdns_mhdp_device { + struct mutex link_mutex; + + struct drm_connector connector; ++ struct drm_connector *connector_ptr; + struct drm_bridge bridge; + + struct cdns_mhdp_link link; +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +index 31832ba4017f1..3c8532d7f7841 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +@@ -394,7 +394,7 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) + int ret; + + dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", +- mhdp->connector.name, mhdp->connector.base.id); ++ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); + + ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); + +@@ -436,6 +436,10 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) + int ret = 0; + + mutex_lock(&mhdp->hdcp.mutex); ++ ++ if (!mhdp->connector_ptr) ++ goto out; ++ + if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + goto out; + +@@ -445,7 +449,7 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) + + dev_err(mhdp->dev, + "[%s:%d] HDCP link failed, retrying authentication\n", +- mhdp->connector.name, mhdp->connector.base.id); ++ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); + + ret = _cdns_mhdp_hdcp_disable(mhdp); + if (ret) { +@@ -487,13 +491,19 @@ static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) + struct cdns_mhdp_device *mhdp = container_of(hdcp, + struct cdns_mhdp_device, + hdcp); +- struct drm_device *dev = mhdp->connector.dev; ++ struct drm_device *dev = NULL; + struct drm_connector_state *state; + ++ if (mhdp->connector_ptr) ++ dev = mhdp->connector_ptr->dev; ++ ++ if (!dev) ++ return; ++ + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { +- state = mhdp->connector.state; ++ state = mhdp->connector_ptr->state; + state->content_protection = mhdp->hdcp.value; + } + mutex_unlock(&mhdp->hdcp.mutex); +-- +2.53.0 + diff --git a/queue-6.12/drm-i915-relocate-the-skl-wm-sanitation-code.patch b/queue-6.12/drm-i915-relocate-the-skl-wm-sanitation-code.patch new file mode 100644 index 0000000000..0dce06deef --- /dev/null +++ b/queue-6.12/drm-i915-relocate-the-skl-wm-sanitation-code.patch @@ -0,0 +1,477 @@ +From a7f3fe8927782ddff964519db0febb8ab96df44d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 31 Oct 2024 17:56:41 +0200 +Subject: drm/i915: Relocate the SKL wm sanitation code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit e31e8681d29c5c35aa070ca6323c6b95ecf0db99 ] + +In order to add more MBUS sanitation into the code we'll want +to reuse a bunch of the code that performs the MBUS/related +hardware programming. Currently that code comes after the +main skl_wm_get_hw_state_and_sanitize() entrypoint. In order +to avoid annoying forward declarations relocate the +skl_wm_get_hw_state_and_sanitize() and related stuff nearer to +the end of the file. + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20241031155646.15165-2-ville.syrjala@linux.intel.com +Reviewed-by: Jani Nikula +Stable-dep-of: a97c88a176b6 ("drm/i915/wm: Verify the correct plane DDB entry") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 420 +++++++++---------- + 1 file changed, 210 insertions(+), 210 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index 045c7cac166bb..2b05db764a3a9 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3039,202 +3039,6 @@ static void skl_wm_get_hw_state(struct drm_i915_private *i915) + dbuf_state->enabled_slices = i915->display.dbuf.enabled_slices; + } + +-static bool skl_dbuf_is_misconfigured(struct drm_i915_private *i915) +-{ +- const struct intel_dbuf_state *dbuf_state = +- to_intel_dbuf_state(i915->display.dbuf.obj.state); +- struct skl_ddb_entry entries[I915_MAX_PIPES] = {}; +- struct intel_crtc *crtc; +- +- for_each_intel_crtc(&i915->drm, crtc) { +- const struct intel_crtc_state *crtc_state = +- to_intel_crtc_state(crtc->base.state); +- +- entries[crtc->pipe] = crtc_state->wm.skl.ddb; +- } +- +- for_each_intel_crtc(&i915->drm, crtc) { +- const struct intel_crtc_state *crtc_state = +- to_intel_crtc_state(crtc->base.state); +- u8 slices; +- +- slices = skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes, +- dbuf_state->joined_mbus); +- if (dbuf_state->slices[crtc->pipe] & ~slices) +- return true; +- +- if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.ddb, entries, +- I915_MAX_PIPES, crtc->pipe)) +- return true; +- } +- +- return false; +-} +- +-static void skl_wm_sanitize(struct drm_i915_private *i915) +-{ +- struct intel_crtc *crtc; +- +- /* +- * On TGL/RKL (at least) the BIOS likes to assign the planes +- * to the wrong DBUF slices. This will cause an infinite loop +- * in skl_commit_modeset_enables() as it can't find a way to +- * transition between the old bogus DBUF layout to the new +- * proper DBUF layout without DBUF allocation overlaps between +- * the planes (which cannot be allowed or else the hardware +- * may hang). If we detect a bogus DBUF layout just turn off +- * all the planes so that skl_commit_modeset_enables() can +- * simply ignore them. +- */ +- if (!skl_dbuf_is_misconfigured(i915)) +- return; +- +- drm_dbg_kms(&i915->drm, "BIOS has misprogrammed the DBUF, disabling all planes\n"); +- +- for_each_intel_crtc(&i915->drm, crtc) { +- struct intel_plane *plane = to_intel_plane(crtc->base.primary); +- const struct intel_plane_state *plane_state = +- to_intel_plane_state(plane->base.state); +- struct intel_crtc_state *crtc_state = +- to_intel_crtc_state(crtc->base.state); +- +- if (plane_state->uapi.visible) +- intel_plane_disable_noatomic(crtc, plane); +- +- drm_WARN_ON(&i915->drm, crtc_state->active_planes != 0); +- +- memset(&crtc_state->wm.skl.ddb, 0, sizeof(crtc_state->wm.skl.ddb)); +- } +-} +- +-static void skl_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915) +-{ +- skl_wm_get_hw_state(i915); +- skl_wm_sanitize(i915); +-} +- +-void intel_wm_state_verify(struct intel_atomic_state *state, +- struct intel_crtc *crtc) +-{ +- struct drm_i915_private *i915 = to_i915(state->base.dev); +- const struct intel_crtc_state *new_crtc_state = +- intel_atomic_get_new_crtc_state(state, crtc); +- struct skl_hw_state { +- struct skl_ddb_entry ddb[I915_MAX_PLANES]; +- struct skl_ddb_entry ddb_y[I915_MAX_PLANES]; +- struct skl_pipe_wm wm; +- } *hw; +- const struct skl_pipe_wm *sw_wm = &new_crtc_state->wm.skl.optimal; +- struct intel_plane *plane; +- u8 hw_enabled_slices; +- int level; +- +- if (DISPLAY_VER(i915) < 9 || !new_crtc_state->hw.active) +- return; +- +- hw = kzalloc(sizeof(*hw), GFP_KERNEL); +- if (!hw) +- return; +- +- skl_pipe_wm_get_hw_state(crtc, &hw->wm); +- +- skl_pipe_ddb_get_hw_state(crtc, hw->ddb, hw->ddb_y); +- +- hw_enabled_slices = intel_enabled_dbuf_slices_mask(i915); +- +- if (DISPLAY_VER(i915) >= 11 && +- hw_enabled_slices != i915->display.dbuf.enabled_slices) +- drm_err(&i915->drm, +- "mismatch in DBUF Slices (expected 0x%x, got 0x%x)\n", +- i915->display.dbuf.enabled_slices, +- hw_enabled_slices); +- +- for_each_intel_plane_on_crtc(&i915->drm, crtc, plane) { +- const struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry; +- const struct skl_wm_level *hw_wm_level, *sw_wm_level; +- +- /* Watermarks */ +- for (level = 0; level < i915->display.wm.num_levels; level++) { +- hw_wm_level = &hw->wm.planes[plane->id].wm[level]; +- sw_wm_level = skl_plane_wm_level(sw_wm, plane->id, level); +- +- if (skl_wm_level_equals(hw_wm_level, sw_wm_level)) +- continue; +- +- drm_err(&i915->drm, +- "[PLANE:%d:%s] mismatch in WM%d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", +- plane->base.base.id, plane->base.name, level, +- sw_wm_level->enable, +- sw_wm_level->blocks, +- sw_wm_level->lines, +- hw_wm_level->enable, +- hw_wm_level->blocks, +- hw_wm_level->lines); +- } +- +- hw_wm_level = &hw->wm.planes[plane->id].trans_wm; +- sw_wm_level = skl_plane_trans_wm(sw_wm, plane->id); +- +- if (!skl_wm_level_equals(hw_wm_level, sw_wm_level)) { +- drm_err(&i915->drm, +- "[PLANE:%d:%s] mismatch in trans WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", +- plane->base.base.id, plane->base.name, +- sw_wm_level->enable, +- sw_wm_level->blocks, +- sw_wm_level->lines, +- hw_wm_level->enable, +- hw_wm_level->blocks, +- hw_wm_level->lines); +- } +- +- hw_wm_level = &hw->wm.planes[plane->id].sagv.wm0; +- sw_wm_level = &sw_wm->planes[plane->id].sagv.wm0; +- +- if (HAS_HW_SAGV_WM(i915) && +- !skl_wm_level_equals(hw_wm_level, sw_wm_level)) { +- drm_err(&i915->drm, +- "[PLANE:%d:%s] mismatch in SAGV WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", +- plane->base.base.id, plane->base.name, +- sw_wm_level->enable, +- sw_wm_level->blocks, +- sw_wm_level->lines, +- hw_wm_level->enable, +- hw_wm_level->blocks, +- hw_wm_level->lines); +- } +- +- hw_wm_level = &hw->wm.planes[plane->id].sagv.trans_wm; +- sw_wm_level = &sw_wm->planes[plane->id].sagv.trans_wm; +- +- if (HAS_HW_SAGV_WM(i915) && +- !skl_wm_level_equals(hw_wm_level, sw_wm_level)) { +- drm_err(&i915->drm, +- "[PLANE:%d:%s] mismatch in SAGV trans WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", +- plane->base.base.id, plane->base.name, +- sw_wm_level->enable, +- sw_wm_level->blocks, +- sw_wm_level->lines, +- hw_wm_level->enable, +- hw_wm_level->blocks, +- hw_wm_level->lines); +- } +- +- /* DDB */ +- hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; +- sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; +- +- if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { +- drm_err(&i915->drm, +- "[PLANE:%d:%s] mismatch in DDB (expected (%u,%u), found (%u,%u))\n", +- plane->base.base.id, plane->base.name, +- sw_ddb_entry->start, sw_ddb_entry->end, +- hw_ddb_entry->start, hw_ddb_entry->end); +- } +- } +- +- kfree(hw); +-} +- + bool skl_watermark_ipc_enabled(struct drm_i915_private *i915) + { + return i915->display.wm.ipc_enabled; +@@ -3390,20 +3194,6 @@ static void skl_setup_wm_latency(struct drm_i915_private *i915) + intel_print_wm_latency(i915, "Gen9 Plane", i915->display.wm.skl_latency); + } + +-static const struct intel_wm_funcs skl_wm_funcs = { +- .compute_global_watermarks = skl_compute_wm, +- .get_hw_state = skl_wm_get_hw_state_and_sanitize, +-}; +- +-void skl_wm_init(struct drm_i915_private *i915) +-{ +- intel_sagv_init(i915); +- +- skl_setup_wm_latency(i915); +- +- i915->display.funcs.wm = &skl_wm_funcs; +-} +- + static struct intel_global_state *intel_dbuf_duplicate_state(struct intel_global_obj *obj) + { + struct intel_dbuf_state *dbuf_state; +@@ -3747,6 +3537,216 @@ void intel_dbuf_post_plane_update(struct intel_atomic_state *state) + gen9_dbuf_slices_update(i915, new_slices); + } + ++static bool skl_dbuf_is_misconfigured(struct drm_i915_private *i915) ++{ ++ const struct intel_dbuf_state *dbuf_state = ++ to_intel_dbuf_state(i915->display.dbuf.obj.state); ++ struct skl_ddb_entry entries[I915_MAX_PIPES] = {}; ++ struct intel_crtc *crtc; ++ ++ for_each_intel_crtc(&i915->drm, crtc) { ++ const struct intel_crtc_state *crtc_state = ++ to_intel_crtc_state(crtc->base.state); ++ ++ entries[crtc->pipe] = crtc_state->wm.skl.ddb; ++ } ++ ++ for_each_intel_crtc(&i915->drm, crtc) { ++ const struct intel_crtc_state *crtc_state = ++ to_intel_crtc_state(crtc->base.state); ++ u8 slices; ++ ++ slices = skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes, ++ dbuf_state->joined_mbus); ++ if (dbuf_state->slices[crtc->pipe] & ~slices) ++ return true; ++ ++ if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.ddb, entries, ++ I915_MAX_PIPES, crtc->pipe)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void skl_wm_sanitize(struct drm_i915_private *i915) ++{ ++ struct intel_crtc *crtc; ++ ++ /* ++ * On TGL/RKL (at least) the BIOS likes to assign the planes ++ * to the wrong DBUF slices. This will cause an infinite loop ++ * in skl_commit_modeset_enables() as it can't find a way to ++ * transition between the old bogus DBUF layout to the new ++ * proper DBUF layout without DBUF allocation overlaps between ++ * the planes (which cannot be allowed or else the hardware ++ * may hang). If we detect a bogus DBUF layout just turn off ++ * all the planes so that skl_commit_modeset_enables() can ++ * simply ignore them. ++ */ ++ if (!skl_dbuf_is_misconfigured(i915)) ++ return; ++ ++ drm_dbg_kms(&i915->drm, "BIOS has misprogrammed the DBUF, disabling all planes\n"); ++ ++ for_each_intel_crtc(&i915->drm, crtc) { ++ struct intel_plane *plane = to_intel_plane(crtc->base.primary); ++ const struct intel_plane_state *plane_state = ++ to_intel_plane_state(plane->base.state); ++ struct intel_crtc_state *crtc_state = ++ to_intel_crtc_state(crtc->base.state); ++ ++ if (plane_state->uapi.visible) ++ intel_plane_disable_noatomic(crtc, plane); ++ ++ drm_WARN_ON(&i915->drm, crtc_state->active_planes != 0); ++ ++ memset(&crtc_state->wm.skl.ddb, 0, sizeof(crtc_state->wm.skl.ddb)); ++ } ++} ++ ++static void skl_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915) ++{ ++ skl_wm_get_hw_state(i915); ++ skl_wm_sanitize(i915); ++} ++ ++void intel_wm_state_verify(struct intel_atomic_state *state, ++ struct intel_crtc *crtc) ++{ ++ struct drm_i915_private *i915 = to_i915(state->base.dev); ++ const struct intel_crtc_state *new_crtc_state = ++ intel_atomic_get_new_crtc_state(state, crtc); ++ struct skl_hw_state { ++ struct skl_ddb_entry ddb[I915_MAX_PLANES]; ++ struct skl_ddb_entry ddb_y[I915_MAX_PLANES]; ++ struct skl_pipe_wm wm; ++ } *hw; ++ const struct skl_pipe_wm *sw_wm = &new_crtc_state->wm.skl.optimal; ++ struct intel_plane *plane; ++ u8 hw_enabled_slices; ++ int level; ++ ++ if (DISPLAY_VER(i915) < 9 || !new_crtc_state->hw.active) ++ return; ++ ++ hw = kzalloc(sizeof(*hw), GFP_KERNEL); ++ if (!hw) ++ return; ++ ++ skl_pipe_wm_get_hw_state(crtc, &hw->wm); ++ ++ skl_pipe_ddb_get_hw_state(crtc, hw->ddb, hw->ddb_y); ++ ++ hw_enabled_slices = intel_enabled_dbuf_slices_mask(i915); ++ ++ if (DISPLAY_VER(i915) >= 11 && ++ hw_enabled_slices != i915->display.dbuf.enabled_slices) ++ drm_err(&i915->drm, ++ "mismatch in DBUF Slices (expected 0x%x, got 0x%x)\n", ++ i915->display.dbuf.enabled_slices, ++ hw_enabled_slices); ++ ++ for_each_intel_plane_on_crtc(&i915->drm, crtc, plane) { ++ const struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry; ++ const struct skl_wm_level *hw_wm_level, *sw_wm_level; ++ ++ /* Watermarks */ ++ for (level = 0; level < i915->display.wm.num_levels; level++) { ++ hw_wm_level = &hw->wm.planes[plane->id].wm[level]; ++ sw_wm_level = skl_plane_wm_level(sw_wm, plane->id, level); ++ ++ if (skl_wm_level_equals(hw_wm_level, sw_wm_level)) ++ continue; ++ ++ drm_err(&i915->drm, ++ "[PLANE:%d:%s] mismatch in WM%d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", ++ plane->base.base.id, plane->base.name, level, ++ sw_wm_level->enable, ++ sw_wm_level->blocks, ++ sw_wm_level->lines, ++ hw_wm_level->enable, ++ hw_wm_level->blocks, ++ hw_wm_level->lines); ++ } ++ ++ hw_wm_level = &hw->wm.planes[plane->id].trans_wm; ++ sw_wm_level = skl_plane_trans_wm(sw_wm, plane->id); ++ ++ if (!skl_wm_level_equals(hw_wm_level, sw_wm_level)) { ++ drm_err(&i915->drm, ++ "[PLANE:%d:%s] mismatch in trans WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", ++ plane->base.base.id, plane->base.name, ++ sw_wm_level->enable, ++ sw_wm_level->blocks, ++ sw_wm_level->lines, ++ hw_wm_level->enable, ++ hw_wm_level->blocks, ++ hw_wm_level->lines); ++ } ++ ++ hw_wm_level = &hw->wm.planes[plane->id].sagv.wm0; ++ sw_wm_level = &sw_wm->planes[plane->id].sagv.wm0; ++ ++ if (HAS_HW_SAGV_WM(i915) && ++ !skl_wm_level_equals(hw_wm_level, sw_wm_level)) { ++ drm_err(&i915->drm, ++ "[PLANE:%d:%s] mismatch in SAGV WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", ++ plane->base.base.id, plane->base.name, ++ sw_wm_level->enable, ++ sw_wm_level->blocks, ++ sw_wm_level->lines, ++ hw_wm_level->enable, ++ hw_wm_level->blocks, ++ hw_wm_level->lines); ++ } ++ ++ hw_wm_level = &hw->wm.planes[plane->id].sagv.trans_wm; ++ sw_wm_level = &sw_wm->planes[plane->id].sagv.trans_wm; ++ ++ if (HAS_HW_SAGV_WM(i915) && ++ !skl_wm_level_equals(hw_wm_level, sw_wm_level)) { ++ drm_err(&i915->drm, ++ "[PLANE:%d:%s] mismatch in SAGV trans WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", ++ plane->base.base.id, plane->base.name, ++ sw_wm_level->enable, ++ sw_wm_level->blocks, ++ sw_wm_level->lines, ++ hw_wm_level->enable, ++ hw_wm_level->blocks, ++ hw_wm_level->lines); ++ } ++ ++ /* DDB */ ++ hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; ++ sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; ++ ++ if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { ++ drm_err(&i915->drm, ++ "[PLANE:%d:%s] mismatch in DDB (expected (%u,%u), found (%u,%u))\n", ++ plane->base.base.id, plane->base.name, ++ sw_ddb_entry->start, sw_ddb_entry->end, ++ hw_ddb_entry->start, hw_ddb_entry->end); ++ } ++ } ++ ++ kfree(hw); ++} ++ ++static const struct intel_wm_funcs skl_wm_funcs = { ++ .compute_global_watermarks = skl_compute_wm, ++ .get_hw_state = skl_wm_get_hw_state_and_sanitize, ++}; ++ ++void skl_wm_init(struct drm_i915_private *i915) ++{ ++ intel_sagv_init(i915); ++ ++ skl_setup_wm_latency(i915); ++ ++ i915->display.funcs.wm = &skl_wm_funcs; ++} ++ + static int skl_watermark_ipc_status_show(struct seq_file *m, void *data) + { + struct drm_i915_private *i915 = m->private; +-- +2.53.0 + diff --git a/queue-6.12/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch b/queue-6.12/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch new file mode 100644 index 0000000000..3f906602f8 --- /dev/null +++ b/queue-6.12/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch @@ -0,0 +1,44 @@ +From 52749beabad73da3788ad5d6154c44bc07e7778c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:48:38 +0200 +Subject: drm/i915/wm: Verify the correct plane DDB entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit a97c88a176b6b8d116f4d3f508f3bd02bc77b462 ] + +Actually verify the DDB entry for the plane we're looking +at instead of always verifying the cursor DDB. + +Fixes: 7d4561722c3b ("drm/i915: Tweak plane ddb allocation tracking") +Signed-off-by: Ville Syrjälä +Link: https://patch.msgid.link/20260324134843.2364-5-ville.syrjala@linux.intel.com +Reviewed-by: Vinod Govindapillai +(cherry picked from commit f002f7c7439de18117a31ca84dc87a59719c3dd6) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index 2b05db764a3a9..0c868be53f2f9 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3718,8 +3718,8 @@ void intel_wm_state_verify(struct intel_atomic_state *state, + } + + /* DDB */ +- hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; +- sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; ++ hw_ddb_entry = &hw->ddb[plane->id]; ++ sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[plane->id]; + + if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { + drm_err(&i915->drm, +-- +2.53.0 + diff --git a/queue-6.12/drm-imagination-switch-reset_reason-fields-from-enum.patch b/queue-6.12/drm-imagination-switch-reset_reason-fields-from-enum.patch new file mode 100644 index 0000000000..44cfbd6374 --- /dev/null +++ b/queue-6.12/drm-imagination-switch-reset_reason-fields-from-enum.patch @@ -0,0 +1,63 @@ +From 9e2561c4569749be56e2666381fd9fb2291862ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:31:29 +0200 +Subject: drm/imagination: Switch reset_reason fields from enum to u32 + +From: Alexandru Dadu + +[ Upstream commit d2f83a6cd598bf413f1acf34153bd1d71023fbab ] + +Update the reset_reason fwif structure fields from enum to u32 to remove +any ambiguity from the interface (enum is not a fixed size thus is unfit +for the purpose of the data type). + +Fixes: a26f067feac1f ("drm/imagination: Add FWIF headers") +Signed-off-by: Alexandru Dadu +Reviewed-by: Matt Coster +Link: https://patch.msgid.link/20260323-b4-firmware-context-reset-notification-handling-v3-2-1a66049a9a65@imgtec.com +Signed-off-by: Matt Coster +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imagination/pvr_rogue_fwif.h | 8 ++++++-- + drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h | 6 +++++- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h +index 172886be4c820..5d590c4c25663 100644 +--- a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h ++++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h +@@ -1347,8 +1347,12 @@ struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data { + struct rogue_fwif_fwccb_cmd_context_reset_data { + /* Context affected by the reset */ + u32 server_common_context_id; +- /* Reason for reset */ +- enum rogue_context_reset_reason reset_reason; ++ /* ++ * Reason for reset ++ * The valid values for reset_reason are the ones from ++ * enum rogue_context_reset_reason ++ */ ++ u32 reset_reason; + /* Data Master affected by the reset */ + u32 dm; + /* Job ref running at the time of reset */ +diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h +index 6c09c15bf9bd8..f95acd5a1f8e8 100644 +--- a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h ++++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h +@@ -249,7 +249,11 @@ enum rogue_context_reset_reason { + }; + + struct rogue_context_reset_reason_data { +- enum rogue_context_reset_reason reset_reason; ++ /* ++ * The valid values for reset_reason are the ones from ++ * enum rogue_context_reset_reason ++ */ ++ u32 reset_reason; + u32 reset_ext_job_ref; + }; + +-- +2.53.0 + diff --git a/queue-6.12/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch b/queue-6.12/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch new file mode 100644 index 0000000000..b674aa2d4b --- /dev/null +++ b/queue-6.12/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch @@ -0,0 +1,60 @@ +From 70d3a6eddfddf092119b0666c5d157fe46c3d688 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:48:46 +0300 +Subject: drm/komeda: fix integer overflow in AFBC framebuffer size check + +From: Alexander Konyukhov + +[ Upstream commit 779ec12c85c9e4547519e3903a371a3b26a289de ] + +The AFBC framebuffer size validation calculates the minimum required +buffer size by adding the AFBC payload size to the framebuffer offset. +This addition is performed without checking for integer overflow. + +If the addition oveflows, the size check may incorrectly succed and +allow userspace to provide an undersized drm_gem_object, potentially +leading to out-of-bounds memory access. + +Add usage of check_add_overflow() to safely compute the minimum +required size and reject the framebuffer if an overflow is detected. +This makes the AFBC size validation more robust against malformed. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 65ad2392dd6d ("drm/komeda: Added AFBC support for komeda driver") +Signed-off-by: Alexander Konyukhov +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://lore.kernel.org/r/20260203134907.1587067-1-Alexander.Konyukhov@kaspersky.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +index df5da5a447555..b4f2b89651ff2 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +@@ -4,6 +4,8 @@ + * Author: James.Qian.Wang + * + */ ++#include ++ + #include + #include + #include +@@ -92,7 +94,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file, + kfb->afbc_size = kfb->offset_payload + n_blocks * + ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, + AFBC_SUPERBLK_ALIGNMENT); +- min_size = kfb->afbc_size + fb->offsets[0]; ++ if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) { ++ goto check_failed; ++ } + if (min_size > obj->size) { + DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n", + obj->size, min_size); +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch b/queue-6.12/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch new file mode 100644 index 0000000000..5c5ffdf00e --- /dev/null +++ b/queue-6.12/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch @@ -0,0 +1,70 @@ +From c3fbed922098c6f8b6d283a99cc68ef0abc9e557 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 16:58:37 -0400 +Subject: drm/msm/a6xx: Fix dumping A650+ debugbus blocks + +From: Connor Abbott + +[ Upstream commit cc83f71c9be0715fe93b963ffa9767d5d84354ed ] + +These should be appended after the existing debugbus blocks, instead of +replacing them. + +Fixes: 1e05bba5e2b8 ("drm/msm/a6xx: Update a6xx gpu coredump") +Signed-off-by: Connor Abbott +Patchwork: https://patchwork.freedesktop.org/patch/714270/ +Message-ID: <20260325-drm-msm-a650-debugbus-v1-1-dfbf358890a7@gmail.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 8f104f7fcaa29..dac88af9b3d09 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -346,7 +346,7 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + sizeof(*a6xx_state->debugbus)); + + if (a6xx_state->debugbus) { +- int i; ++ int i, j; + + for (i = 0; i < ARRAY_SIZE(a6xx_debugbus_blocks); i++) + a6xx_get_debugbus_block(gpu, +@@ -354,8 +354,6 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + &a6xx_debugbus_blocks[i], + &a6xx_state->debugbus[i]); + +- a6xx_state->nr_debugbus = ARRAY_SIZE(a6xx_debugbus_blocks); +- + /* + * GBIF has same debugbus as of other GPU blocks, fall back to + * default path if GPU uses GBIF, also GBIF uses exactly same +@@ -366,17 +364,19 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + &a6xx_gbif_debugbus_block, + &a6xx_state->debugbus[i]); + +- a6xx_state->nr_debugbus += 1; ++ i++; + } + + + if (adreno_is_a650_family(to_adreno_gpu(gpu))) { +- for (i = 0; i < ARRAY_SIZE(a650_debugbus_blocks); i++) ++ for (j = 0; j < ARRAY_SIZE(a650_debugbus_blocks); i++, j++) + a6xx_get_debugbus_block(gpu, + a6xx_state, +- &a650_debugbus_blocks[i], ++ &a650_debugbus_blocks[j], + &a6xx_state->debugbus[i]); + } ++ ++ a6xx_state->nr_debugbus = i; + } + } + +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-a6xx-fix-hlsq-register-dumping.patch b/queue-6.12/drm-msm-a6xx-fix-hlsq-register-dumping.patch new file mode 100644 index 0000000000..44442f38e5 --- /dev/null +++ b/queue-6.12/drm-msm-a6xx-fix-hlsq-register-dumping.patch @@ -0,0 +1,39 @@ +From e22479470f2085d83cf98403f8b5256d66997108 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:40:42 -0700 +Subject: drm/msm/a6xx: Fix HLSQ register dumping + +From: Rob Clark + +[ Upstream commit c289a6db9ba6cb974f0317da142e4f665d589566 ] + +Fix the bitfield offset of HLSQ_READ_SEL state-type bitfield. Otherwise +we are always reading TP state when we wanted SP or HLSQ state. + +Reported-by: Connor Abbott +Suggested-by: Connor Abbott +Fixes: 1707add81551 ("drm/msm/a6xx: Add a6xx gpu state") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714236/ +Message-ID: <20260325184043.1259312-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 5d7d2f5a2a1f8..8f104f7fcaa29 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -996,7 +996,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, + u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; + int i, regcount = 0; + +- in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); ++ in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); + + for (i = 0; i < regs->count; i += 2) { + u32 count = RANGE(regs->registers, i); +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch b/queue-6.12/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch new file mode 100644 index 0000000000..010c0f83e8 --- /dev/null +++ b/queue-6.12/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch @@ -0,0 +1,72 @@ +From 5a94a07273e16108becbae58c09df6eb0c09f702 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:50 +0530 +Subject: drm/msm/a6xx: Use barriers while updating HFI Q headers + +From: Akhil P Oommen + +[ Upstream commit dc78b35d5ec09d1b0b8a937e6e640d2c5a030915 ] + +To avoid harmful compiler optimizations and IO reordering in the HW, use +barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI +queue index variables. + +Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714653/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-1-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +index cdb3f6e74d3e6..b858e740ac7e5 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +@@ -31,7 +31,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + struct a6xx_hfi_queue_header *header = queue->header; + u32 i, hdr, index = header->read_index; + +- if (header->read_index == header->write_index) { ++ if (header->read_index == READ_ONCE(header->write_index)) { + header->rx_request = 1; + return 0; + } +@@ -59,7 +59,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + if (!gmu->legacy) + index = ALIGN(index, 4) % header->size; + +- header->read_index = index; ++ /* Ensure all memory operations are complete before updating the read index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->read_index, index); + return HFI_HEADER_SIZE(hdr); + } + +@@ -71,7 +74,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + + spin_lock(&queue->lock); + +- space = CIRC_SPACE(header->write_index, header->read_index, ++ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), + header->size); + if (space < dwords) { + header->dropped++; +@@ -92,7 +95,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + queue->data[index] = 0xfafafafa; + } + +- header->write_index = index; ++ /* Ensure all memory operations are complete before updating the write index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->write_index, index); + spin_unlock(&queue->lock); + + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch b/queue-6.12/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch new file mode 100644 index 0000000000..8c6fe2305d --- /dev/null +++ b/queue-6.12/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch @@ -0,0 +1,58 @@ +From a6c30d2d66154c9941252cbffae098f3cfac68cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 14:37:20 +0800 +Subject: drm/msm/dpu: fix mismatch between power and frequency + +From: Yuanjie Yang + +[ Upstream commit bc1dccc518cc5ab5140fba06c27e7188e0ed342b ] + +During DPU runtime suspend, calling dev_pm_opp_set_rate(dev, 0) drops +the MMCX rail to MIN_SVS while the core clock frequency remains at its +original (highest) rate. When runtime resume re-enables the clock, this +may result in a mismatch between the rail voltage and the clock rate. + +For example, in the DPU bind path, the sequence could be: + cpu0: dev_sync_state -> rpmhpd_sync_state + cpu1: dpu_kms_hw_init +timeline 0 ------------------------------------------------> t + +After rpmhpd_sync_state, the voltage performance is no longer guaranteed +to stay at the highest level. During dpu_kms_hw_init, calling +dev_pm_opp_set_rate(dev, 0) drops the voltage, causing the MMCX rail to +fall to MIN_SVS while the core clock is still at its maximum frequency. +When the power is re-enabled, only the clock is enabled, leading to a +situation where the MMCX rail is at MIN_SVS but the core clock is at its +highest rate. In this state, the rail cannot sustain the clock rate, +which may cause instability or system crash. + +Remove the call to dev_pm_opp_set_rate(dev, 0) from dpu_runtime_suspend +to ensure the correct vote is restored when DPU resumes. + +Fixes: b0530eb11913 ("drm/msm/dpu: Use OPP API to set clk/perf state") +Signed-off-by: Yuanjie Yang +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/710077/ +Link: https://lore.kernel.org/r/20260309063720.13572-1-yuanjie.yang@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +index 9bcae53c4f458..edc35638ce763 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +@@ -1401,8 +1401,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); + +- /* Drop the performance state vote */ +- dev_pm_opp_set_rate(dev, 0); + clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks); + + for (i = 0; i < dpu_kms->num_paths; i++) +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-dsi-add-the-missing-parameter-description.patch b/queue-6.12/drm-msm-dsi-add-the-missing-parameter-description.patch new file mode 100644 index 0000000000..684cf54eea --- /dev/null +++ b/queue-6.12/drm-msm-dsi-add-the-missing-parameter-description.patch @@ -0,0 +1,40 @@ +From ba7fdc27903a49445f8ab64a1b1be90985e474b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 18:02:53 +0800 +Subject: drm/msm/dsi: add the missing parameter description + +From: Pengyu Luo + +[ Upstream commit 958adefc4c0fddee3b12269da5dd7cb49bac953f ] + +Add a description for is_bonded_dsi in dsi_adjust_pclk_for_compression +to match the existing kernel-doc comment. + +Fixes: e4eb11b34d6c ("drm/msm/dsi: fix pclk rate calculation for bonded dsi") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202603080314.XeqyRZ7A-lkp@intel.com/ +Signed-off-by: Pengyu Luo +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/710112/ +Link: https://lore.kernel.org/r/20260309100254.877801-1-mitltlatltl@gmail.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 0c360e7903295..1027434b72620 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -519,6 +519,7 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) + * dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case + * @mode: The selected mode for the DSI output + * @dsc: DRM DSC configuration for this DSI output ++ * @is_bonded_dsi: True if two DSI controllers are bonded + * + * Adjust the pclk rate by calculating a new hdisplay proportional to + * the compression ratio such that: +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-dsi-fix-bits_per_pclk.patch b/queue-6.12/drm-msm-dsi-fix-bits_per_pclk.patch new file mode 100644 index 0000000000..a0aa797abd --- /dev/null +++ b/queue-6.12/drm-msm-dsi-fix-bits_per_pclk.patch @@ -0,0 +1,39 @@ +From 920602b6b4785112a038bc49c5b69aac8c0fd8d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:12:48 +0800 +Subject: drm/msm/dsi: fix bits_per_pclk + +From: Pengyu Luo + +[ Upstream commit 2d51cfb77daa30b10bc68c403f8ace35783d2922 ] + +mipi_dsi_pixel_format_to_bpp return dst bpp not src bpp, dst bpp may +not be the uncompressed data size. use src bpc * 3 to get src bpp, +this aligns with pclk rate calculation. + +Fixes: ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when programming dsi registers") +Signed-off-by: Pengyu Luo +Patchwork: https://patchwork.freedesktop.org/patch/709916/ +Link: https://lore.kernel.org/r/20260307111250.105772-1-mitltlatltl@gmail.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 1027434b72620..d0cc9ad58c140 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -999,7 +999,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + */ + h_total -= hdisplay; + if (wide_bus_enabled) +- bits_per_pclk = mipi_dsi_pixel_format_to_bpp(msm_host->format); ++ bits_per_pclk = dsc->bits_per_component * 3; + else + bits_per_pclk = 24; + +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch b/queue-6.12/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch new file mode 100644 index 0000000000..716cbe4e11 --- /dev/null +++ b/queue-6.12/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch @@ -0,0 +1,61 @@ +From ddc32bd757b11ba278db167c9c0a77a329c78880 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:12:49 +0800 +Subject: drm/msm/dsi: fix hdisplay calculation for CMD mode panel + +From: Pengyu Luo + +[ Upstream commit 82159db4371f5cef56444ebd0b8f96e2a6d709ff ] + +Commit ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when +programming dsi registers") incorrecly broke hdisplay calculation for +CMD mode by specifying incorrect number of bytes per transfer, fix it. + +Fixes: ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when programming dsi registers") +Signed-off-by: Pengyu Luo +Patchwork: https://patchwork.freedesktop.org/patch/709917/ +Link: https://lore.kernel.org/r/20260307111250.105772-2-mitltlatltl@gmail.com +[DB: fixed commit message] +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index d0cc9ad58c140..6f538c578f740 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -985,8 +985,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + /* + * DPU sends 3 bytes per pclk cycle to DSI. If widebus is + * enabled, MDP always sends out 48-bit compressed data per +- * pclk and on average, DSI consumes an amount of compressed +- * data equivalent to the uncompressed pixel depth per pclk. ++ * pclk and on average, for video mode, DSI consumes only an ++ * amount of compressed data equivalent to the uncompressed ++ * pixel depth per pclk. + * + * Calculate the number of pclks needed to transmit one line of + * the compressed data. +@@ -998,10 +999,14 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + * unused anyway. + */ + h_total -= hdisplay; +- if (wide_bus_enabled) +- bits_per_pclk = dsc->bits_per_component * 3; +- else ++ if (wide_bus_enabled) { ++ if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) ++ bits_per_pclk = dsc->bits_per_component * 3; ++ else ++ bits_per_pclk = 48; ++ } else { + bits_per_pclk = 24; ++ } + + hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc) * 8, bits_per_pclk); + +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch b/queue-6.12/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch new file mode 100644 index 0000000000..79cc3a022b --- /dev/null +++ b/queue-6.12/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch @@ -0,0 +1,62 @@ +From 1fecbf17f4614b55264806cb66f3efd648c71b48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:48:27 +0000 +Subject: drm/msm/dsi: rename MSM8998 DSI version from V2_2_0 to V2_0_0 + +From: Alexander Koskovich + +[ Upstream commit 913a709dea0eff9c7b2e9470f8c8594b9a0114ab ] + +The MSM8998 DSI controller is v2.0.0 as stated in commit 7b8c9e203039 +("drm/msm/dsi: Add support for MSM8998 DSI controller"). The value was +always correct just the name was wrong. + +Rename and reorder to maintain version sorting. + +Fixes: 7b8c9e203039 ("drm/msm/dsi: Add support for MSM8998 DSI controller") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Alexander Koskovich +Patchwork: https://patchwork.freedesktop.org/patch/713717/ +Link: https://lore.kernel.org/r/20260324-dsi-rgb101010-support-v5-3-ff6afc904115@pm.me +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_cfg.c | 4 ++-- + drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +index 10ba7d153d1cf..8bf3266d13831 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +@@ -278,10 +278,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { + &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, + &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, ++ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, ++ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, + &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, +- {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, +- &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +index 4c9b4b37681b0..2c9ed626f7909 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +@@ -19,8 +19,8 @@ + #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 + #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 + #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 ++#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 +-#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 + #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 + #define MSM_DSI_6G_VER_MINOR_V2_4_0 0x20040000 +-- +2.53.0 + diff --git a/queue-6.12/drm-msm-shrinker-fix-can_block-logic.patch b/queue-6.12/drm-msm-shrinker-fix-can_block-logic.patch new file mode 100644 index 0000000000..ce26fe81b8 --- /dev/null +++ b/queue-6.12/drm-msm-shrinker-fix-can_block-logic.patch @@ -0,0 +1,44 @@ +From c241493821957144ebeabb1aedfc4c17ddaf7d8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:41:05 -0700 +Subject: drm/msm/shrinker: Fix can_block() logic + +From: Rob Clark + +[ Upstream commit df0f439e3926817cf577ca6272aad68468ff7624 ] + +The intention here was to allow blocking if DIRECT_RECLAIM or if called +from kswapd and KSWAPD_RECLAIM is set. + +Reported by Claude code review: https://lore.gitlab.freedesktop.org/drm-ai-reviews/review-patch9-20260309151119.290217-10-boris.brezillon@collabora.com/ on a panthor patch which had copied similar logic. + +Reported-by: Boris Brezillon +Fixes: 7860d720a84c ("drm/msm: Fix build break with recent mm tree") +Signed-off-by: Rob Clark +Reviewed-by: Boris Brezillon +Patchwork: https://patchwork.freedesktop.org/patch/714238/ +Message-ID: <20260325184106.1259528-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem_shrinker.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c +index 07ca4ddfe4e37..89c0ea8ddeaac 100644 +--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c ++++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c +@@ -26,9 +26,8 @@ static bool can_swap(void) + + static bool can_block(struct shrink_control *sc) + { +- if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM)) +- return false; +- return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); ++ return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) || ++ (current_is_kswapd() && (sc->gfp_mask & __GFP_KSWAPD_RECLAIM)); + } + + static unsigned long +-- +2.53.0 + diff --git a/queue-6.12/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch b/queue-6.12/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch new file mode 100644 index 0000000000..4445683e4c --- /dev/null +++ b/queue-6.12/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch @@ -0,0 +1,38 @@ +From e8925456002e0a464338c9c3a79f03900dc0435b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:21:49 +0200 +Subject: drm/panel: sharp-ls043t1le01: make use of prepare_prev_first + +From: Dmitry Baryshkov + +[ Upstream commit c222177d7c7e1b2e0433d9e47ec2da7015345d50 ] + +The DSI link must be powered up to let panel driver to talk to the panel +during prepare() callback execution. Set the prepare_prev_first flag to +guarantee this. + +Fixes: 9e15123eca79 ("drm/msm/dsi: Stop unconditionally powering up DSI hosts at modeset") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Douglas Anderson +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260323-panel-fix-v1-1-9f12b09161e8@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +index 729cbb0d8403f..bc3e13b5a1f76 100644 +--- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c ++++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +@@ -212,6 +212,7 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) + + drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev, + &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); ++ sharp_nt->base.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&sharp_nt->base); + if (ret) +-- +2.53.0 + diff --git a/queue-6.12/drm-panel-simple-correct-g190ean01-prepare-timing.patch b/queue-6.12/drm-panel-simple-correct-g190ean01-prepare-timing.patch new file mode 100644 index 0000000000..83a9ae352a --- /dev/null +++ b/queue-6.12/drm-panel-simple-correct-g190ean01-prepare-timing.patch @@ -0,0 +1,41 @@ +From d7d52a04f4a473d5d2d0d2182cb684c22b947cc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 16:25:26 +0200 +Subject: drm/panel: simple: Correct G190EAN01 prepare timing + +From: Sebastian Reichel + +[ Upstream commit f1080f82570b797598c1ba7e9c800ae9e94aafc6 ] + +The prepare timing specified by the G190EAN01 datasheet should be +between 30 and 50 ms. Considering it might take some time for the +LVDS encoder to enable the signal, we should only wait the min. +required time in the panel driver and not the max. allowed time. + +Fixes: 2f7b832fc992 ("drm/panel: simple: Add support for AUO G190EAN01 panel") +Signed-off-by: Sebastian Reichel +Signed-off-by: Ian Ray +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260217142528.68613-1-ian.ray@gehealthcare.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-simple.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 32d876f6684e2..a0e2da2953768 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1260,7 +1260,7 @@ static const struct panel_desc auo_g190ean01 = { + .height = 301, + }, + .delay = { +- .prepare = 50, ++ .prepare = 30, + .enable = 200, + .disable = 110, + .unprepare = 1000, +-- +2.53.0 + diff --git a/queue-6.12/drm-sun4i-backend-fix-error-pointer-dereference.patch b/queue-6.12/drm-sun4i-backend-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..6215d4b677 --- /dev/null +++ b/queue-6.12/drm-sun4i-backend-fix-error-pointer-dereference.patch @@ -0,0 +1,43 @@ +From abfd20ebfde9373a315b613628644106b04e445f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 19:48:01 -0600 +Subject: drm/sun4i: backend: fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit 06277983eca4a31d3c2114fa33d99a6e82484b11 ] + +The function drm_atomic_get_plane_state() can return an error pointer +and is not checked for it. Add error pointer check. + +Detected by Smatch: +drivers/gpu/drm/sun4i/sun4i_backend.c:496 sun4i_backend_atomic_check() error: +'plane_state' dereferencing possible ERR_PTR() + +Fixes: 96180dde23b79 ("drm/sun4i: backend: Add a custom atomic_check for the frontend") +Signed-off-by: Ethan Tidmore +Reviewed-by: Chen-Yu Tsai +Link: https://patch.msgid.link/20260217014801.60760-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index e89eb96d31317..a7c256e2c632b 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -490,6 +490,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, + drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); ++ if (IS_ERR(plane_state)) ++ return PTR_ERR(plane_state); ++ + struct sun4i_layer_state *layer_state = + state_to_sun4i_layer_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; +-- +2.53.0 + diff --git a/queue-6.12/drm-sun4i-fix-resource-leaks.patch b/queue-6.12/drm-sun4i-fix-resource-leaks.patch new file mode 100644 index 0000000000..55f16e5a1c --- /dev/null +++ b/queue-6.12/drm-sun4i-fix-resource-leaks.patch @@ -0,0 +1,41 @@ +From f23eb915277380beaf573733a6288225e2e8f23f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:38:36 -0600 +Subject: drm/sun4i: Fix resource leaks + +From: Ethan Tidmore + +[ Upstream commit 127367ad2e0f4870de60c6d719ae82ecf68d674c ] + +Three clocks are not being released in devm_regmap_init_mmio() error +path. + +Add proper goto and set ret to the error code. + +Fixes: 8270249fbeaf0 ("drm/sun4i: backend: Create regmap after access is possible") +Signed-off-by: Ethan Tidmore +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260226163836.10335-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index a7c256e2c632b..329e2a2384e89 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -880,7 +880,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, + &sun4i_backend_regmap_config); + if (IS_ERR(backend->engine.regs)) { + dev_err(dev, "Couldn't create the backend regmap\n"); +- return PTR_ERR(backend->engine.regs); ++ ret = PTR_ERR(backend->engine.regs); ++ goto err_disable_ram_clk; + } + + list_add_tail(&backend->engine.list, &drv->engine_list); +-- +2.53.0 + diff --git a/queue-6.12/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch b/queue-6.12/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch new file mode 100644 index 0000000000..349ec8a9a0 --- /dev/null +++ b/queue-6.12/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch @@ -0,0 +1,55 @@ +From 1a22c0b6f354f4410e3241984356e5f90876b81a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:25:13 -0400 +Subject: drm/sysfb: ofdrm: fix PCI device reference leaks + +From: Yuho Choi + +[ Upstream commit 4aa8110000b0d215deef8eed283565dd0c1def88 ] + +display_get_pci_dev_of() gets a referenced PCI device via +pci_get_device(). Drop that reference when pci_enable_device() fails and +release it during the managed teardown path after pci_disable_device(). + +Without that, ofdrm leaks the pci_dev reference on both the error path +and the normal cleanup path. + +Fixes: c8a17756c425 ("drm/ofdrm: Add ofdrm for Open Firmware framebuffers") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Reviewed-by: Thomas Zimmermann +Signed-off-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260420002513.216-1-dbgh9129@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/tiny/ofdrm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c +index 35996f7eedac0..cc90e0035d034 100644 +--- a/drivers/gpu/drm/tiny/ofdrm.c ++++ b/drivers/gpu/drm/tiny/ofdrm.c +@@ -350,6 +350,7 @@ static void ofdrm_pci_release(void *data) + struct pci_dev *pcidev = data; + + pci_disable_device(pcidev); ++ pci_dev_put(pcidev); + } + + static int ofdrm_device_init_pci(struct ofdrm_device *odev) +@@ -375,6 +376,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev) + if (ret) { + drm_err(dev, "pci_enable_device(%s) failed: %d\n", + dev_name(&pcidev->dev), ret); ++ pci_dev_put(pcidev); + return ret; + } + ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); +-- +2.53.0 + diff --git a/queue-6.12/drm-v3d-handle-error-from-drm_sched_entity_init.patch b/queue-6.12/drm-v3d-handle-error-from-drm_sched_entity_init.patch new file mode 100644 index 0000000000..7094818400 --- /dev/null +++ b/queue-6.12/drm-v3d-handle-error-from-drm_sched_entity_init.patch @@ -0,0 +1,69 @@ +From dad7a28052b2cf74ac6028aca6cf8bd95752526f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 08:30:33 -0300 +Subject: drm/v3d: Handle error from drm_sched_entity_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maíra Canal + +[ Upstream commit 8cf1bec37b27846ad3169744c9f1a89a06dcb3fa ] + +drm_sched_entity_init() can fail but its return value is currently being +ignored in v3d_open(). Check the return value and properly unwind +on failure by destroying any already-initialized scheduler entities. + +Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+") +Reviewed-by: Iago Toral Quiroga +Link: https://patch.msgid.link/20260306-v3d-reset-locking-improv-v3-1-49864fe00692@igalia.com +Signed-off-by: Maíra Canal +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/v3d/v3d_drv.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c +index f45fdd7d542f6..e0272acad2a89 100644 +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -109,7 +109,7 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + struct v3d_dev *v3d = to_v3d_dev(dev); + struct v3d_file_priv *v3d_priv; + struct drm_gpu_scheduler *sched; +- int i; ++ int i, ret; + + v3d_priv = kzalloc(sizeof(*v3d_priv), GFP_KERNEL); + if (!v3d_priv) +@@ -119,9 +119,11 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + + for (i = 0; i < V3D_MAX_QUEUES; i++) { + sched = &v3d->queue[i].sched; +- drm_sched_entity_init(&v3d_priv->sched_entity[i], +- DRM_SCHED_PRIORITY_NORMAL, &sched, +- 1, NULL); ++ ret = drm_sched_entity_init(&v3d_priv->sched_entity[i], ++ DRM_SCHED_PRIORITY_NORMAL, &sched, ++ 1, NULL); ++ if (ret) ++ goto err_sched; + + memset(&v3d_priv->stats[i], 0, sizeof(v3d_priv->stats[i])); + seqcount_init(&v3d_priv->stats[i].lock); +@@ -131,6 +133,12 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + file->driver_priv = v3d_priv; + + return 0; ++ ++err_sched: ++ for (i--; i >= 0; i--) ++ drm_sched_entity_destroy(&v3d_priv->sched_entity[i]); ++ kfree(v3d_priv); ++ return ret; + } + + static void +-- +2.53.0 + diff --git a/queue-6.12/drm-xe-debugfs-correct-printing-of-register-whitelis.patch b/queue-6.12/drm-xe-debugfs-correct-printing-of-register-whitelis.patch new file mode 100644 index 0000000000..a0e849116c --- /dev/null +++ b/queue-6.12/drm-xe-debugfs-correct-printing-of-register-whitelis.patch @@ -0,0 +1,58 @@ +From 887cce2c9252e44672158c4c73a2ff89eee128a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 15:27:44 -0700 +Subject: drm/xe/debugfs: Correct printing of register whitelist ranges + +From: Matt Roper + +[ Upstream commit 03f2499c51dffce611b065b2894406beb9f2ebe0 ] + +The register-save-restore debugfs prints whitelist entries as offset +ranges. E.g., + + REG[0x39319c-0x39319f]: allow read access + +for a single dword-sized register. However the GENMASK value used to +set the lower bits to '1' for the upper bound of the whitelist range +incorrectly included one more bit than it should have, causing the +whitelist ranges to sometimes appear twice as large as they really were. +For example, + + REG[0x6210-0x6217]: allow rw access + +was also intended to be a single dword-sized register whitelist (with a +range 0x6210-0x6213) but was printed incorrectly as a qword-sized range +because one too many bits was flipped on. Similar 'off by one' logic +was applied when printing 4-dword register ranges and 64-dword register +ranges as well. + +Correct the GENMASK logic to print these ranges in debugfs correctly. +No impact outside of correcting the misleading debugfs output. + +Fixes: d855d2246ea6 ("drm/xe: Print whitelist while applying") +Reviewed-by: Stuart Summers +Link: https://patch.msgid.link/20260408-regsr_wl_range-v1-1-e9a28c8b4264@intel.com +Signed-off-by: Matt Roper +(cherry picked from commit 1a2a722ff96749734a5585dfe7f0bea7719caa8b) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c +index 3996934974fa0..3de0a867149da 100644 +--- a/drivers/gpu/drm/xe/xe_reg_whitelist.c ++++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c +@@ -137,7 +137,7 @@ void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, + } + + range_start = reg & REG_GENMASK(25, range_bit); +- range_end = range_start | REG_GENMASK(range_bit, 0); ++ range_end = range_start | REG_GENMASK(range_bit - 1, 0); + + switch (val & RING_FORCE_TO_NONPRIV_ACCESS_MASK) { + case RING_FORCE_TO_NONPRIV_ACCESS_RW: +-- +2.53.0 + diff --git a/queue-6.12/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch b/queue-6.12/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch new file mode 100644 index 0000000000..2e66c51f6b --- /dev/null +++ b/queue-6.12/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch @@ -0,0 +1,80 @@ +From 166e682e465b968a86d3d5cdd1437e0f118fdb07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 02:06:47 +0000 +Subject: drm/xe: Fix error cleanup in xe_exec_queue_create_ioctl() + +From: Shuicheng Lin + +[ Upstream commit f3cc22d4df3ed58439ea7e21daa54c3608e03b78 ] + +Two error handling issues exist in xe_exec_queue_create_ioctl(): + +1. When xe_hw_engine_group_add_exec_queue() fails, the error path jumps + to put_exec_queue which skips xe_exec_queue_kill(). If the VM is in + preempt fence mode, xe_vm_add_compute_exec_queue() has already added + the queue to the VM's compute exec queue list. Skipping the kill + leaves the queue on that list, leading to a dangling pointer after + the queue is freed. + +2. When xa_alloc() fails after xe_hw_engine_group_add_exec_queue() has + succeeded, the error path does not call + xe_hw_engine_group_del_exec_queue() to remove the queue from the hw + engine group list. The queue is then freed while still linked into + the hw engine group, causing a use-after-free. + +Fix both by: +- Changing the xe_hw_engine_group_add_exec_queue() failure path to jump + to kill_exec_queue so that xe_exec_queue_kill() properly removes the + queue from the VM's compute list. +- Adding a del_hw_engine_group label before kill_exec_queue for the + xa_alloc() failure path, which removes the queue from the hw engine + group before proceeding with the rest of the cleanup. + +Fixes: 7970cb36966c ("'drm/xe/hw_engine_group: Register hw engine group's exec queues") +Cc: Francois Dugast +Cc: Matthew Brost +Cc: Niranjana Vishwanathapura +Assisted-by: Claude:claude-opus-4.6 +Reviewed-by: Matthew Brost +Link: https://patch.msgid.link/20260408020647.3397933-1-shuicheng.lin@intel.com +Signed-off-by: Shuicheng Lin +(cherry picked from commit 37c831f401746a45d510b312b0ed7a77b1e06ec8) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_exec_queue.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c +index 268cd3123be9d..e6c3074d0a785 100644 +--- a/drivers/gpu/drm/xe/xe_exec_queue.c ++++ b/drivers/gpu/drm/xe/xe_exec_queue.c +@@ -638,7 +638,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, + if (q->vm && q->hwe->hw_engine_group) { + err = xe_hw_engine_group_add_exec_queue(q->hwe->hw_engine_group, q); + if (err) +- goto put_exec_queue; ++ goto kill_exec_queue; + } + } + +@@ -647,12 +647,15 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, + /* user id alloc must always be last in ioctl to prevent UAF */ + err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL); + if (err) +- goto kill_exec_queue; ++ goto del_hw_engine_group; + + args->exec_queue_id = id; + + return 0; + ++del_hw_engine_group: ++ if (q->vm && q->hwe && q->hwe->hw_engine_group) ++ xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); + kill_exec_queue: + xe_exec_queue_kill(q); + put_exec_queue: +-- +2.53.0 + diff --git a/queue-6.12/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch b/queue-6.12/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch new file mode 100644 index 0000000000..38a5ea8745 --- /dev/null +++ b/queue-6.12/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch @@ -0,0 +1,45 @@ +From 4acfa9a22766558b2a36e65a42a3248996d49347 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 16:33:08 +0000 +Subject: drm/xe/gsc: Fix BO leak on error in query_compatibility_version() + +From: Shuicheng Lin + +[ Upstream commit 3762d6c36549accea7068c4a175483fafdd03657 ] + +When xe_gsc_read_out_header() fails, query_compatibility_version() +returns directly instead of jumping to the out_bo label. This skips +the xe_bo_unpin_map_no_vm() call, leaving the BO pinned and mapped +with no remaining reference to free it. + +Fix by using goto out_bo so the error path properly cleans up the BO, +consistent with the other error handling in the same function. + +Fixes: 0881cbe04077 ("drm/xe/gsc: Query GSC compatibility version") +Cc: Daniele Ceraolo Spurio +Reviewed-by: Daniele Ceraolo Spurio +Link: https://patch.msgid.link/20260417163308.3416147-1-shuicheng.lin@intel.com +Signed-off-by: Shuicheng Lin +(cherry picked from commit 8de86d0a843c32ca9d36864bdb92f0376a830bce) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_gsc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c +index feb680d127e60..efc480d34c9dd 100644 +--- a/drivers/gpu/drm/xe/xe_gsc.c ++++ b/drivers/gpu/drm/xe/xe_gsc.c +@@ -163,7 +163,7 @@ static int query_compatibility_version(struct xe_gsc *gsc) + &rd_offset); + if (err) { + xe_gt_err(gt, "HuC: invalid GSC reply for version query (err=%d)\n", err); +- return err; ++ goto out_bo; + } + + compat->major = version_query_rd(xe, &bo->vmap, rd_offset, proj_major); +-- +2.53.0 + diff --git a/queue-6.12/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch b/queue-6.12/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch new file mode 100644 index 0000000000..bdcd507712 --- /dev/null +++ b/queue-6.12/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch @@ -0,0 +1,52 @@ +From cdf4ceea1cf080b6b8c214478ccd72154ed50434 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:25 +0100 +Subject: dt-bindings: clock: qcom,dispcc-sc7180: Define MDSS resets + +From: Konrad Dybcio + +[ Upstream commit fc6e29d42872680dca017f2e5169eefe971f8d89 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: 75616da71291 ("dt-bindings: clock: Introduce QCOM sc7180 display clock bindings") +Signed-off-by: Konrad Dybcio +Reviewed-by: Taniya Das +Acked-by: Krzysztof Kozlowski +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-1-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: b0bc6011c549 ("clk: qcom: dispcc-sc7180: Add missing MDSS resets") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,dispcc-sc7180.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/dt-bindings/clock/qcom,dispcc-sc7180.h b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +index b9b51617a335d..0705103060748 100644 +--- a/include/dt-bindings/clock/qcom,dispcc-sc7180.h ++++ b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +@@ -6,6 +6,7 @@ + #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + ++/* Clocks */ + #define DISP_CC_PLL0 0 + #define DISP_CC_PLL0_OUT_EVEN 1 + #define DISP_CC_MDSS_AHB_CLK 2 +@@ -40,7 +41,11 @@ + #define DISP_CC_MDSS_VSYNC_CLK_SRC 31 + #define DISP_CC_XO_CLK 32 + +-/* DISP_CC GDSCR */ ++/* Resets */ ++#define DISP_CC_MDSS_CORE_BCR 0 ++#define DISP_CC_MDSS_RSCC_BCR 1 ++ ++/* GDSCs */ + #define MDSS_GDSC 0 + + #endif +-- +2.53.0 + diff --git a/queue-6.12/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-6.12/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..628b9e6176 --- /dev/null +++ b/queue-6.12/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,40 @@ +From c37f309dda28d155b8904457a04b5b8cc9a3d7c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:06 -0300 +Subject: dt-bindings: clock: qcom,gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 76404ffbf07f28a5ec04748e18fce3dac2e78ef6 ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Signed-off-by: Val Packett +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20260312112321.370983-2-val@packett.cool +Signed-off-by: Bjorn Andersson +Stable-dep-of: 3565741eb985 ("clk: qcom: gcc-sc8180x: Add missing GDSCs") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,gcc-sc8180x.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/dt-bindings/clock/qcom,gcc-sc8180x.h b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +index e364006aa6eab..99c97b2033fc5 100644 +--- a/include/dt-bindings/clock/qcom,gcc-sc8180x.h ++++ b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +@@ -312,5 +312,10 @@ + #define USB30_MP_GDSC 8 + #define USB30_PRIM_GDSC 9 + #define USB30_SEC_GDSC 10 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 11 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 12 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 13 ++#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 14 ++#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 15 + + #endif +-- +2.53.0 + diff --git a/queue-6.12/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch b/queue-6.12/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch new file mode 100644 index 0000000000..a749e5a2f8 --- /dev/null +++ b/queue-6.12/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch @@ -0,0 +1,42 @@ +From ea804cb5afaaac31ac07a2e94a20727735248266 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 11:26:20 +0100 +Subject: dt-bindings: interrupt-controller: arm,gic-v3: Fix EPPI range + +From: Geert Uytterhoeven + +[ Upstream commit 15cfc8984defc17e5e4de1f58db7b993240fcbda ] + +According to the "Arm Generic Interrupt Controller (GIC) Architecture +Specification, v3 and v4", revision H.b[1], there can be only 64 +Extended PPI interrupts. + +[1] https://developer.arm.com/documentation/ihi0069/hb/ + +Fixes: 4b049063e0bcbfd3 ("dt-bindings: interrupt-controller: arm,gic-v3: Describe EPPI range support") +Signed-off-by: Geert Uytterhoeven +Brain-farted-by: Marc Zyngier +Acked-by: Marc Zyngier +Link: https://patch.msgid.link/3e49a63c6b2b6ee48e3737adee87781f9c136c5f.1772792753.git.geert+renesas@glider.be +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/interrupt-controller/arm,gic-v3.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +index 5f051c666cbe5..9deaf132d0e9b 100644 +--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml ++++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +@@ -50,7 +50,7 @@ properties: + The 2nd cell contains the interrupt number for the interrupt type. + SPI interrupts are in the range [0-987]. PPI interrupts are in the + range [0-15]. Extended SPI interrupts are in the range [0-1023]. +- Extended PPI interrupts are in the range [0-127]. ++ Extended PPI interrupts are in the range [0-63]. + + The 3rd cell is the flags, encoded as follows: + bits[3:0] trigger type and level flags. +-- +2.53.0 + diff --git a/queue-6.12/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch b/queue-6.12/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch new file mode 100644 index 0000000000..629b7eca4f --- /dev/null +++ b/queue-6.12/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch @@ -0,0 +1,47 @@ +From ba3d949a2900b73898e629dec913a8b6305df143 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 14:34:33 +0200 +Subject: dt-bindings: net: dsa: nxp,sja1105: make spi-cpol optional for + sja1110 + +From: Josua Mayer + +[ Upstream commit 600f01dc4bd0c736b3ffea9f7976136d8bf1b136 ] + +Currently, the binding requires 'spi-cpha' for SJA1105 and 'spi-cpol' +for SJA1110. + +However, the SJA1110 supports both SPI modes 0 and 2. Mode 2 +(cpha=0, cpol=1) is used by the NXP LX2160 Bluebox 3. + +On the SolidRun i.MX8DXL HummingBoard Telematics, mode 0 is stable, +while forcing mode 2 introduces CRC errors especially during bursts. + +Drop the requirement on spi-cpol for SJA1110. + +Fixes: af2eab1a8243 ("dt-bindings: net: nxp,sja1105: document spi-cpol/cpha") +Signed-off-by: Josua Mayer +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260409-imx8dxl-sr-som-v2-1-83ff20629ba0@solid-run.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +index 9432565f4f5d3..8bfa2ea579f0c 100644 +--- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml ++++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +@@ -131,8 +131,6 @@ allOf: + else: + properties: + spi-cpha: false +- required: +- - spi-cpol + + unevaluatedProperties: false + +-- +2.53.0 + diff --git a/queue-6.12/e1000e-unroll-ptp-in-probe-error-handling.patch b/queue-6.12/e1000e-unroll-ptp-in-probe-error-handling.patch new file mode 100644 index 0000000000..e8c45af583 --- /dev/null +++ b/queue-6.12/e1000e-unroll-ptp-in-probe-error-handling.patch @@ -0,0 +1,41 @@ +From 04f47aadfd01894e5261899b1311b01179f0ce28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:36 -0700 +Subject: e1000e: Unroll PTP in probe error handling + +From: Matt Vollrath + +[ Upstream commit aa3f7fe409350857c25d050482a2eef2cfd69b58 ] + +If probe fails after registering the PTP clock and its delayed work, +these resources must be released. + +This was not an issue until a 2016 fix moved the e1000e_ptp_init() call +before the jump to err_register. + +Fixes: aa524b66c5ef ("e1000e: don't modify SYSTIM registers during SIOCSHWTSTAMP ioctl") +Signed-off-by: Matt Vollrath +Tested-by: Avigail Dahan +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-12-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 4d9dcb0001d21..3f0dd19ba399c 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -7700,6 +7700,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + err_register: + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000e_release_hw_control(adapter); ++ e1000e_ptp_remove(adapter); + err_eeprom: + if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) + e1000_phy_hw_reset(&adapter->hw); +-- +2.53.0 + diff --git a/queue-6.12/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch b/queue-6.12/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch new file mode 100644 index 0000000000..2388dbfca4 --- /dev/null +++ b/queue-6.12/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch @@ -0,0 +1,52 @@ +From cc87dce92105cf56560c04d49c88849b1155415c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:46:37 +0200 +Subject: efi/capsule-loader: fix incorrect sizeof in phys array reallocation + +From: Thomas Huth + +[ Upstream commit 48a428215782321b56956974f23593e40ce84b7a ] + +The krealloc() call for cap_info->phys in __efi_capsule_setup_info() uses +sizeof(phys_addr_t *) instead of sizeof(phys_addr_t), which might be +causing an undersized allocation. + +The allocation is also inconsistent with the initial array allocation in +efi_capsule_open() that allocates one entry with sizeof(phys_addr_t), +and the efi_capsule_write() function that stores phys_addr_t values (not +pointers) via page_to_phys(). + +On 64-bit systems where sizeof(phys_addr_t) == sizeof(phys_addr_t *), this +goes unnoticed. On 32-bit systems with PAE where phys_addr_t is 64-bit but +pointers are 32-bit, this allocates half the required space, which might +lead to a heap buffer overflow when storing physical addresses. + +This is similar to the bug fixed in commit fccfa646ef36 ("efi/capsule-loader: +fix incorrect allocation size") which fixed the same issue at the initial +allocation site. + +Fixes: f24c4d478013 ("efi/capsule-loader: Reinstate virtual capsule mapping") +Assisted-by: Claude:claude-sonnet-4-5 +Signed-off-by: Thomas Huth +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + drivers/firmware/efi/capsule-loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c +index 0c17bdd388e12..bbddeb6a09552 100644 +--- a/drivers/firmware/efi/capsule-loader.c ++++ b/drivers/firmware/efi/capsule-loader.c +@@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) + cap_info->pages = temp_page; + + temp_page = krealloc(cap_info->phys, +- pages_needed * sizeof(phys_addr_t *), ++ pages_needed * sizeof(phys_addr_t), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.12/erofs-add-encoded-extent-on-disk-definition.patch b/queue-6.12/erofs-add-encoded-extent-on-disk-definition.patch new file mode 100644 index 0000000000..be0ff90626 --- /dev/null +++ b/queue-6.12/erofs-add-encoded-extent-on-disk-definition.patch @@ -0,0 +1,349 @@ +From 420409bdad034297a13de862cc54039c21d8b512 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Mar 2025 17:54:57 +0800 +Subject: erofs: add encoded extent on-disk definition + +From: Gao Xiang + +[ Upstream commit efb2aef569b35b415c232c4e9fdecd0e540e1f60 ] + +Previously, EROFS provided both (non-)compact compressed indexes to +keep necessary hints for each logical block, enabling O(1) random +indexing. This approach was originally designed for small compression +units (e.g., 4KiB), where compressed data is strictly block-aligned via +fixed-sized output compression. + +However, EROFS now supports big pclusters up to 1MiB and many users use +large configurations to minimize image sizes. For such configurations, +the total number of extents decreases significantly (e.g., only 1,024 +extents for a 1GiB file using 1MiB pclusters), then runtime metadata +overhead becomes negligible compared to data I/O and decoding costs. + +Additionally, some popular compression algorithm (mainly Zstd) still +lacks native fixed-sized output compression support (although it's +planned by their authors). Instead of just waiting for compressor +improvements, let's adopt byte-oriented extents, allowing these +compressors to retain their current methods. + +For example, it speeds up Zstd compression a lot: +Processor: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz * 96 +Dataset: enwik9 +Build time Size Type Command Line +3m52.339s 266653696 FO -C524288 -zzstd,22 +3m48.549s 266174464 FO -E48bit -C524288 -zzstd,22 +0m12.821s 272134144 FI -E48bit -C1048576 --max-extent-bytes=1048576 -zzstd,22 + +0m14.528s 248987648 FO -C1048576 -zlzma,9 +0m14.605s 248504320 FO -E48bit -C1048576 -zlzma,9 + +Encoded extents are structured as an array of `struct z_erofs_extent`, +sorted by logical address in ascending order: + __le32 plen // encoded length, algorithm id and flags + __le32 pstart_lo // physical offset LSB + __le32 pstart_hi // physical offset MSB + __le32 lstart_lo // logical offset + __le32 lstart_hi // logical offset MSB + .. + +Note that prefixed reduced records can be used to minimize metadata for +specific cases (e.g. lstart less than 32 bits, then 32 to 16 bytes). + +If the logical lengths of all encoded extents are the same, 4-byte +(plen) and 8-byte (plen, pstart_lo) records can be used. Or, 16-byte +(plen .. lstart_lo) and 32-byte full records have to be used instead. + +If 16-byte and 32-byte records are used, the total number of extents +is kept in `struct z_erofs_map_header`, and binary search can be +applied on them. Note that `eytzinger order` is not considerd because +data sequential access is important. + +If 4-byte records are used, 8-byte start physical offset is between +`struct z_erofs_map_header` and the `plen` array. + +In addition, 64-bit physical offsets can be applied with new encoded +extent format to match full 48-bit block addressing. + +Remove redundant comments around `struct z_erofs_lcluster_index` too. + +Signed-off-by: Gao Xiang +Acked-by: Chao Yu +Link: https://lore.kernel.org/r/20250310095459.2620647-8-hsiangkao@linux.alibaba.com +Stable-dep-of: 2d8c7edcb661 ("erofs: unify lcn as u64 for 32-bit platforms") +Signed-off-by: Sasha Levin +--- + fs/erofs/erofs_fs.h | 99 +++++++++++++++++++++------------------------ + fs/erofs/internal.h | 2 +- + fs/erofs/zmap.c | 24 +++++------ + 3 files changed, 58 insertions(+), 67 deletions(-) + +diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h +index c8f2ae845bd29..5b237148cb644 100644 +--- a/fs/erofs/erofs_fs.h ++++ b/fs/erofs/erofs_fs.h +@@ -336,21 +336,20 @@ struct z_erofs_zstd_cfgs { + #define Z_EROFS_ZSTD_MAX_DICT_SIZE Z_EROFS_PCLUSTER_MAX_SIZE + + /* +- * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on) +- * e.g. for 4k logical cluster size, 4B if compacted 2B is off; +- * (4B) + 2B + (4B) if compacted 2B is on. +- * bit 1 : HEAD1 big pcluster (0 - off; 1 - on) +- * bit 2 : HEAD2 big pcluster (0 - off; 1 - on) +- * bit 3 : tailpacking inline pcluster (0 - off; 1 - on) +- * bit 4 : interlaced plain pcluster (0 - off; 1 - on) +- * bit 5 : fragment pcluster (0 - off; 1 - on) ++ * Enable COMPACTED_2B for EROFS_INODE_COMPRESSED_COMPACT inodes: ++ * 4B (disabled) vs 4B+2B+4B (enabled) + */ + #define Z_EROFS_ADVISE_COMPACTED_2B 0x0001 ++/* Enable extent metadata for EROFS_INODE_COMPRESSED_FULL inodes */ ++#define Z_EROFS_ADVISE_EXTENTS 0x0001 + #define Z_EROFS_ADVISE_BIG_PCLUSTER_1 0x0002 + #define Z_EROFS_ADVISE_BIG_PCLUSTER_2 0x0004 + #define Z_EROFS_ADVISE_INLINE_PCLUSTER 0x0008 + #define Z_EROFS_ADVISE_INTERLACED_PCLUSTER 0x0010 + #define Z_EROFS_ADVISE_FRAGMENT_PCLUSTER 0x0020 ++/* Indicate the record size for each extent if extent metadata is used */ ++#define Z_EROFS_ADVISE_EXTRECSZ_BIT 1 ++#define Z_EROFS_ADVISE_EXTRECSZ_MASK 0x3 + + #define Z_EROFS_FRAGMENT_INODE_BIT 7 + struct z_erofs_map_header { +@@ -362,45 +361,24 @@ struct z_erofs_map_header { + /* indicates the encoded size of tailpacking data */ + __le16 h_idata_size; + }; ++ __le32 h_extents_lo; /* extent count LSB */ + }; + __le16 h_advise; +- /* +- * bit 0-3 : algorithm type of head 1 (logical cluster type 01); +- * bit 4-7 : algorithm type of head 2 (logical cluster type 11). +- */ +- __u8 h_algorithmtype; +- /* +- * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096; +- * bit 3-6 : reserved; +- * bit 7 : move the whole file into packed inode or not. +- */ +- __u8 h_clusterbits; ++ union { ++ struct { ++ /* algorithm type (bit 0-3: HEAD1; bit 4-7: HEAD2) */ ++ __u8 h_algorithmtype; ++ /* ++ * bit 0-3 : logical cluster bits - blkszbits ++ * bit 4-6 : reserved ++ * bit 7 : pack the whole file into packed inode ++ */ ++ __u8 h_clusterbits; ++ }; ++ __le16 h_extents_hi; /* extent count MSB */ ++ }; + }; + +-/* +- * On-disk logical cluster type: +- * 0 - literal (uncompressed) lcluster +- * 1,3 - compressed lcluster (for HEAD lclusters) +- * 2 - compressed lcluster (for NONHEAD lclusters) +- * +- * In detail, +- * 0 - literal (uncompressed) lcluster, +- * di_advise = 0 +- * di_clusterofs = the literal data offset of the lcluster +- * di_blkaddr = the blkaddr of the literal pcluster +- * +- * 1,3 - compressed lcluster (for HEAD lclusters) +- * di_advise = 1 or 3 +- * di_clusterofs = the decompressed data offset of the lcluster +- * di_blkaddr = the blkaddr of the compressed pcluster +- * +- * 2 - compressed lcluster (for NONHEAD lclusters) +- * di_advise = 2 +- * di_clusterofs = +- * the decompressed data offset in its own HEAD lcluster +- * di_u.delta[0] = distance to this HEAD lcluster +- * di_u.delta[1] = distance to the next HEAD lcluster +- */ + enum { + Z_EROFS_LCLUSTER_TYPE_PLAIN = 0, + Z_EROFS_LCLUSTER_TYPE_HEAD1 = 1, +@@ -414,11 +392,7 @@ enum { + /* (noncompact only, HEAD) This pcluster refers to partial decompressed data */ + #define Z_EROFS_LI_PARTIAL_REF (1 << 15) + +-/* +- * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the +- * compressed block count of a compressed extent (in logical clusters, aka. +- * block count of a pcluster). +- */ ++/* Set on 1st non-head lcluster to store compressed block counti (in blocks) */ + #define Z_EROFS_LI_D0_CBLKCNT (1 << 11) + + struct z_erofs_lcluster_index { +@@ -427,19 +401,36 @@ struct z_erofs_lcluster_index { + __le16 di_clusterofs; + + union { +- /* for the HEAD lclusters */ +- __le32 blkaddr; ++ __le32 blkaddr; /* for the HEAD lclusters */ + /* +- * for the NONHEAD lclusters + * [0] - distance to its HEAD lcluster + * [1] - distance to the next HEAD lcluster + */ +- __le16 delta[2]; ++ __le16 delta[2]; /* for the NONHEAD lclusters */ + } di_u; + }; + +-#define Z_EROFS_FULL_INDEX_ALIGN(end) \ +- (ALIGN(end, 8) + sizeof(struct z_erofs_map_header) + 8) ++#define Z_EROFS_MAP_HEADER_END(end) \ ++ (ALIGN(end, 8) + sizeof(struct z_erofs_map_header)) ++#define Z_EROFS_FULL_INDEX_START(end) (Z_EROFS_MAP_HEADER_END(end) + 8) ++ ++#define Z_EROFS_EXTENT_PLEN_PARTIAL BIT(27) ++#define Z_EROFS_EXTENT_PLEN_FMT_BIT 28 ++#define Z_EROFS_EXTENT_PLEN_MASK ((Z_EROFS_PCLUSTER_MAX_SIZE << 1) - 1) ++struct z_erofs_extent { ++ __le32 plen; /* encoded length */ ++ __le32 pstart_lo; /* physical offset */ ++ __le32 pstart_hi; /* physical offset MSB */ ++ __le32 lstart_lo; /* logical offset */ ++ __le32 lstart_hi; /* logical offset MSB (>= 4GiB inodes) */ ++ __u8 reserved[12]; /* for future use */ ++}; ++ ++static inline int z_erofs_extent_recsize(unsigned int advise) ++{ ++ return 4 << ((advise >> Z_EROFS_ADVISE_EXTRECSZ_BIT) & ++ Z_EROFS_ADVISE_EXTRECSZ_MASK); ++} + + /* check the EROFS on-disk layout strictly at compile time */ + static inline void erofs_check_ondisk_layout_definitions(void) +diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h +index 856463a702b2c..1c003412677ef 100644 +--- a/fs/erofs/internal.h ++++ b/fs/erofs/internal.h +@@ -275,7 +275,7 @@ struct erofs_inode { + struct { + unsigned short z_advise; + unsigned char z_algorithmtype[2]; +- unsigned char z_logical_clusterbits; ++ unsigned char z_lclusterbits; + unsigned long z_tailextent_headlcn; + erofs_off_t z_fragmentoff; + unsigned short z_idata_size; +diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c +index 25a4b82c183c0..a03700cbd2c1c 100644 +--- a/fs/erofs/zmap.c ++++ b/fs/erofs/zmap.c +@@ -25,7 +25,7 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, + { + struct inode *const inode = m->inode; + struct erofs_inode *const vi = EROFS_I(inode); +- const erofs_off_t pos = Z_EROFS_FULL_INDEX_ALIGN(erofs_iloc(inode) + ++ const erofs_off_t pos = Z_EROFS_FULL_INDEX_START(erofs_iloc(inode) + + vi->inode_isize + vi->xattr_isize) + + lcn * sizeof(struct z_erofs_lcluster_index); + struct z_erofs_lcluster_index *di; +@@ -40,7 +40,7 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, + advise = le16_to_cpu(di->di_advise); + m->type = advise & Z_EROFS_LI_LCLUSTER_TYPE_MASK; + if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) { +- m->clusterofs = 1 << vi->z_logical_clusterbits; ++ m->clusterofs = 1 << vi->z_lclusterbits; + m->delta[0] = le16_to_cpu(di->di_u.delta[0]); + if (m->delta[0] & Z_EROFS_LI_D0_CBLKCNT) { + if (!(vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 | +@@ -55,7 +55,7 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, + } else { + m->partialref = !!(advise & Z_EROFS_LI_PARTIAL_REF); + m->clusterofs = le16_to_cpu(di->di_clusterofs); +- if (m->clusterofs >= 1 << vi->z_logical_clusterbits) { ++ if (m->clusterofs >= 1 << vi->z_lclusterbits) { + DBG_BUGON(1); + return -EFSCORRUPTED; + } +@@ -102,9 +102,9 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, + { + struct inode *const inode = m->inode; + struct erofs_inode *const vi = EROFS_I(inode); +- const erofs_off_t ebase = sizeof(struct z_erofs_map_header) + +- ALIGN(erofs_iloc(inode) + vi->inode_isize + vi->xattr_isize, 8); +- const unsigned int lclusterbits = vi->z_logical_clusterbits; ++ const erofs_off_t ebase = Z_EROFS_MAP_HEADER_END(erofs_iloc(inode) + ++ vi->inode_isize + vi->xattr_isize); ++ const unsigned int lclusterbits = vi->z_lclusterbits; + const unsigned int totalidx = erofs_iblks(inode); + unsigned int compacted_4b_initial, compacted_2b, amortizedshift; + unsigned int vcnt, lo, lobits, encodebits, nblk, bytes; +@@ -255,7 +255,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, + { + struct super_block *sb = m->inode->i_sb; + struct erofs_inode *const vi = EROFS_I(m->inode); +- const unsigned int lclusterbits = vi->z_logical_clusterbits; ++ const unsigned int lclusterbits = vi->z_lclusterbits; + + while (m->lcn >= lookback_distance) { + unsigned long lcn = m->lcn - lookback_distance; +@@ -304,7 +304,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + if ((m->headtype == Z_EROFS_LCLUSTER_TYPE_HEAD1 && !bigpcl1) || + ((m->headtype == Z_EROFS_LCLUSTER_TYPE_PLAIN || + m->headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2) && !bigpcl2) || +- (lcn << vi->z_logical_clusterbits) >= inode->i_size) ++ (lcn << vi->z_lclusterbits) >= inode->i_size) + m->compressedblks = 1; + + if (m->compressedblks) +@@ -354,7 +354,7 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m) + struct inode *inode = m->inode; + struct erofs_inode *vi = EROFS_I(inode); + struct erofs_map_blocks *map = m->map; +- unsigned int lclusterbits = vi->z_logical_clusterbits; ++ unsigned int lclusterbits = vi->z_lclusterbits; + u64 lcn = m->lcn, headlcn = map->m_la >> lclusterbits; + int err; + +@@ -398,16 +398,16 @@ static int z_erofs_do_map_blocks(struct inode *inode, + struct super_block *sb = inode->i_sb; + bool fragment = vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER; + bool ztailpacking = vi->z_idata_size; ++ unsigned int lclusterbits = vi->z_lclusterbits; + struct z_erofs_maprecorder m = { + .inode = inode, + .map = map, + }; + int err = 0; +- unsigned int lclusterbits, endoff, afmt; ++ unsigned int endoff, afmt; + unsigned long initial_lcn; + unsigned long long ofs, end; + +- lclusterbits = vi->z_logical_clusterbits; + ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? inode->i_size - 1 : map->m_la; + initial_lcn = ofs >> lclusterbits; + endoff = ofs & ((1 << lclusterbits) - 1); +@@ -569,6 +569,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) + goto done; + } + vi->z_advise = le16_to_cpu(h->h_advise); ++ vi->z_lclusterbits = sb->s_blocksize_bits + (h->h_clusterbits & 15); + vi->z_algorithmtype[0] = h->h_algorithmtype & 15; + vi->z_algorithmtype[1] = h->h_algorithmtype >> 4; + if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) +@@ -585,7 +586,6 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) + goto out_put_metabuf; + } + +- vi->z_logical_clusterbits = sb->s_blocksize_bits + (h->h_clusterbits & 7); + if (!erofs_sb_has_big_pcluster(EROFS_SB(sb)) && + vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 | + Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { +-- +2.53.0 + diff --git a/queue-6.12/erofs-avoid-infinite-loops-due-to-corrupted-subpage-.patch b/queue-6.12/erofs-avoid-infinite-loops-due-to-corrupted-subpage-.patch new file mode 100644 index 0000000000..0bcda937f1 --- /dev/null +++ b/queue-6.12/erofs-avoid-infinite-loops-due-to-corrupted-subpage-.patch @@ -0,0 +1,94 @@ +From 307f271ed489ed2b7bcd804090bf5eba2a9b3e55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Oct 2025 15:05:38 +0800 +Subject: erofs: avoid infinite loops due to corrupted subpage compact indexes + +From: Gao Xiang + +[ Upstream commit e13d315ae077bb7c3c6027cc292401bc0f4ec683 ] + +Robert reported an infinite loop observed by two crafted images. + +The root cause is that `clusterofs` can be larger than `lclustersize` +for !NONHEAD `lclusters` in corrupted subpage compact indexes, e.g.: + + blocksize = lclustersize = 512 lcn = 6 clusterofs = 515 + +Move the corresponding check for full compress indexes to +`z_erofs_load_lcluster_from_disk()` to also cover subpage compact +compress indexes. + +It also fixes the position of `m->type >= Z_EROFS_LCLUSTER_TYPE_MAX` +check, since it should be placed right after +`z_erofs_load_{compact,full}_lcluster()`. + +Fixes: 8d2517aaeea3 ("erofs: fix up compacted indexes for block size < 4096") +Fixes: 1a5223c182fd ("erofs: do sanity check on m->type in z_erofs_load_compact_lcluster()") +Reported-by: Robert Morris +Closes: https://lore.kernel.org/r/35167.1760645886@localhost +Reviewed-by: Hongbo Li +Signed-off-by: Gao Xiang +Stable-dep-of: 2d8c7edcb661 ("erofs: unify lcn as u64 for 32-bit platforms") +Signed-off-by: Sasha Levin +--- + fs/erofs/zmap.c | 32 ++++++++++++++++++-------------- + 1 file changed, 18 insertions(+), 14 deletions(-) + +diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c +index fe193a7e83a85..d0371ca374ce2 100644 +--- a/fs/erofs/zmap.c ++++ b/fs/erofs/zmap.c +@@ -55,10 +55,6 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, + } else { + m->partialref = !!(advise & Z_EROFS_LI_PARTIAL_REF); + m->clusterofs = le16_to_cpu(di->di_clusterofs); +- if (m->clusterofs >= 1 << vi->z_lclusterbits) { +- DBG_BUGON(1); +- return -EFSCORRUPTED; +- } + m->pblk = le32_to_cpu(di->di_u.blkaddr); + } + return 0; +@@ -240,21 +236,29 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, + static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m, + unsigned int lcn, bool lookahead) + { ++ struct erofs_inode *vi = EROFS_I(m->inode); ++ int err; ++ ++ if (vi->datalayout == EROFS_INODE_COMPRESSED_COMPACT) { ++ err = z_erofs_load_compact_lcluster(m, lcn, lookahead); ++ } else { ++ DBG_BUGON(vi->datalayout != EROFS_INODE_COMPRESSED_FULL); ++ err = z_erofs_load_full_lcluster(m, lcn); ++ } ++ if (err) ++ return err; ++ + if (m->type >= Z_EROFS_LCLUSTER_TYPE_MAX) { + erofs_err(m->inode->i_sb, "unknown type %u @ lcn %u of nid %llu", +- m->type, lcn, EROFS_I(m->inode)->nid); ++ m->type, lcn, EROFS_I(m->inode)->nid); + DBG_BUGON(1); + return -EOPNOTSUPP; ++ } else if (m->type != Z_EROFS_LCLUSTER_TYPE_NONHEAD && ++ m->clusterofs >= (1 << vi->z_lclusterbits)) { ++ DBG_BUGON(1); ++ return -EFSCORRUPTED; + } +- +- switch (EROFS_I(m->inode)->datalayout) { +- case EROFS_INODE_COMPRESSED_FULL: +- return z_erofs_load_full_lcluster(m, lcn); +- case EROFS_INODE_COMPRESSED_COMPACT: +- return z_erofs_load_compact_lcluster(m, lcn, lookahead); +- default: +- return -EINVAL; +- } ++ return 0; + } + + static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, +-- +2.53.0 + diff --git a/queue-6.12/erofs-do-sanity-check-on-m-type-in-z_erofs_load_comp.patch b/queue-6.12/erofs-do-sanity-check-on-m-type-in-z_erofs_load_comp.patch new file mode 100644 index 0000000000..163acc9532 --- /dev/null +++ b/queue-6.12/erofs-do-sanity-check-on-m-type-in-z_erofs_load_comp.patch @@ -0,0 +1,178 @@ +From 4594aeeb80ab4a91613632e0abaa2cd8b0913163 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Jul 2025 19:09:28 +0800 +Subject: erofs: do sanity check on m->type in z_erofs_load_compact_lcluster() + +From: Chao Yu + +[ Upstream commit 1a5223c182fdb3bb3c0ca85cec101c740f685ab6 ] + +All below functions will do sanity check on m->type, let's move sanity +check to z_erofs_load_compact_lcluster() for cleanup. +- z_erofs_map_blocks_fo +- z_erofs_get_extent_compressedlen +- z_erofs_get_extent_decompressedlen +- z_erofs_extent_lookback + +Reviewed-by: Hongbo Li +Signed-off-by: Chao Yu +Reviewed-by: Gao Xiang +Link: https://lore.kernel.org/r/20250708110928.3110375-1-chao@kernel.org +Signed-off-by: Gao Xiang +Stable-dep-of: 2d8c7edcb661 ("erofs: unify lcn as u64 for 32-bit platforms") +Signed-off-by: Sasha Levin +--- + fs/erofs/zmap.c | 103 +++++++++++++++++++----------------------------- + 1 file changed, 41 insertions(+), 62 deletions(-) + +diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c +index a03700cbd2c1c..fe193a7e83a85 100644 +--- a/fs/erofs/zmap.c ++++ b/fs/erofs/zmap.c +@@ -240,6 +240,13 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, + static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m, + unsigned int lcn, bool lookahead) + { ++ if (m->type >= Z_EROFS_LCLUSTER_TYPE_MAX) { ++ erofs_err(m->inode->i_sb, "unknown type %u @ lcn %u of nid %llu", ++ m->type, lcn, EROFS_I(m->inode)->nid); ++ DBG_BUGON(1); ++ return -EOPNOTSUPP; ++ } ++ + switch (EROFS_I(m->inode)->datalayout) { + case EROFS_INODE_COMPRESSED_FULL: + return z_erofs_load_full_lcluster(m, lcn); +@@ -265,12 +272,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, + if (err) + return err; + +- if (m->type >= Z_EROFS_LCLUSTER_TYPE_MAX) { +- erofs_err(sb, "unknown type %u @ lcn %lu of nid %llu", +- m->type, lcn, vi->nid); +- DBG_BUGON(1); +- return -EOPNOTSUPP; +- } else if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) { ++ if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) { + lookback_distance = m->delta[0]; + if (!lookback_distance) + break; +@@ -325,25 +327,18 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + DBG_BUGON(lcn == initial_lcn && + m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD); + +- if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) { +- if (m->delta[0] != 1) { +- erofs_err(sb, "bogus CBLKCNT @ lcn %lu of nid %llu", lcn, vi->nid); +- DBG_BUGON(1); +- return -EFSCORRUPTED; +- } +- if (m->compressedblks) +- goto out; +- } else if (m->type < Z_EROFS_LCLUSTER_TYPE_MAX) { +- /* +- * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type +- * rather than CBLKCNT, it's a 1 block-sized pcluster. +- */ +- m->compressedblks = 1; +- goto out; ++ if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD && m->delta[0] != 1) { ++ erofs_err(sb, "bogus CBLKCNT @ lcn %lu of nid %llu", lcn, vi->nid); ++ DBG_BUGON(1); ++ return -EFSCORRUPTED; + } +- erofs_err(sb, "cannot found CBLKCNT @ lcn %lu of nid %llu", lcn, vi->nid); +- DBG_BUGON(1); +- return -EFSCORRUPTED; ++ ++ /* ++ * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type rather ++ * than CBLKCNT, it's a 1 block-sized pcluster. ++ */ ++ if (m->type != Z_EROFS_LCLUSTER_TYPE_NONHEAD || !m->compressedblks) ++ m->compressedblks = 1; + out: + m->map->m_plen = erofs_pos(sb, m->compressedblks); + return 0; +@@ -379,11 +374,6 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m) + if (lcn != headlcn) + break; /* ends at the next HEAD lcluster */ + m->delta[1] = 1; +- } else { +- erofs_err(inode->i_sb, "unknown type %u @ lcn %llu of nid %llu", +- m->type, lcn, vi->nid); +- DBG_BUGON(1); +- return -EOPNOTSUPP; + } + lcn += m->delta[1]; + } +@@ -421,44 +411,33 @@ static int z_erofs_do_map_blocks(struct inode *inode, + map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_ENCODED; + end = (m.lcn + 1ULL) << lclusterbits; + +- switch (m.type) { +- case Z_EROFS_LCLUSTER_TYPE_PLAIN: +- case Z_EROFS_LCLUSTER_TYPE_HEAD1: +- case Z_EROFS_LCLUSTER_TYPE_HEAD2: +- if (endoff >= m.clusterofs) { +- m.headtype = m.type; +- map->m_la = (m.lcn << lclusterbits) | m.clusterofs; +- /* +- * For ztailpacking files, in order to inline data more +- * effectively, special EOF lclusters are now supported +- * which can have three parts at most. +- */ +- if (ztailpacking && end > inode->i_size) +- end = inode->i_size; +- break; +- } +- /* m.lcn should be >= 1 if endoff < m.clusterofs */ +- if (!m.lcn) { +- erofs_err(sb, "invalid logical cluster 0 at nid %llu", +- vi->nid); +- err = -EFSCORRUPTED; +- goto unmap_out; ++ if (m.type != Z_EROFS_LCLUSTER_TYPE_NONHEAD && endoff >= m.clusterofs) { ++ m.headtype = m.type; ++ map->m_la = (m.lcn << lclusterbits) | m.clusterofs; ++ /* ++ * For ztailpacking files, in order to inline data more ++ * effectively, special EOF lclusters are now supported ++ * which can have three parts at most. ++ */ ++ if (ztailpacking && end > inode->i_size) ++ end = inode->i_size; ++ } else { ++ if (m.type != Z_EROFS_LCLUSTER_TYPE_NONHEAD) { ++ /* m.lcn should be >= 1 if endoff < m.clusterofs */ ++ if (!m.lcn) { ++ erofs_err(sb, "invalid logical cluster 0 at nid %llu", ++ vi->nid); ++ err = -EFSCORRUPTED; ++ goto unmap_out; ++ } ++ end = (m.lcn << lclusterbits) | m.clusterofs; ++ map->m_flags |= EROFS_MAP_FULL_MAPPED; ++ m.delta[0] = 1; + } +- end = (m.lcn << lclusterbits) | m.clusterofs; +- map->m_flags |= EROFS_MAP_FULL_MAPPED; +- m.delta[0] = 1; +- fallthrough; +- case Z_EROFS_LCLUSTER_TYPE_NONHEAD: + /* get the corresponding first chunk */ + err = z_erofs_extent_lookback(&m, m.delta[0]); + if (err) + goto unmap_out; +- break; +- default: +- erofs_err(sb, "unknown type %u @ offset %llu of nid %llu", +- m.type, ofs, vi->nid); +- err = -EOPNOTSUPP; +- goto unmap_out; + } + if (m.partialref) + map->m_flags |= EROFS_MAP_PARTIAL_REF; +-- +2.53.0 + diff --git a/queue-6.12/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch b/queue-6.12/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch new file mode 100644 index 0000000000..783c67564f --- /dev/null +++ b/queue-6.12/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch @@ -0,0 +1,115 @@ +From b5c35366f4f15ea1c2221a58545fb129f797f2f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 18:11:42 +0800 +Subject: erofs: unify lcn as u64 for 32-bit platforms + +From: Gao Xiang + +[ Upstream commit 2d8c7edcb661812249469f4a5b62e9339118846f ] + +As sashiko reported [1], `lcn` was typed as `unsigned long` (or +`unsigned int` sometimes), which is only 32 bits wide on 32-bit +platforms, which causes `(lcn << lclusterbits)` to be truncated +at 4 GiB. + +In order to consolidate the logic, just use `u64` consistently +around the codebase. + +[1] https://sashiko.dev/r/20260420034612.1899973-1-hsiangkao%40linux.alibaba.com + +Fixes: 152a333a5895 ("staging: erofs: add compacted compression indexes support") +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zmap.c | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c +index d0371ca374ce2..af1046908c626 100644 +--- a/fs/erofs/zmap.c ++++ b/fs/erofs/zmap.c +@@ -10,7 +10,7 @@ + struct z_erofs_maprecorder { + struct inode *inode; + struct erofs_map_blocks *map; +- unsigned long lcn; ++ u64 lcn; + /* compression extent information gathered */ + u8 type, headtype; + u16 clusterofs; +@@ -20,8 +20,7 @@ struct z_erofs_maprecorder { + bool partialref; + }; + +-static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, +- unsigned long lcn) ++static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, u64 lcn) + { + struct inode *const inode = m->inode; + struct erofs_inode *const vi = EROFS_I(inode); +@@ -94,7 +93,7 @@ static int get_compacted_la_distance(unsigned int lobits, + } + + static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, +- unsigned long lcn, bool lookahead) ++ u64 lcn, bool lookahead) + { + struct inode *const inode = m->inode; + struct erofs_inode *const vi = EROFS_I(inode); +@@ -234,7 +233,7 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, + } + + static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m, +- unsigned int lcn, bool lookahead) ++ u64 lcn, bool lookahead) + { + struct erofs_inode *vi = EROFS_I(m->inode); + int err; +@@ -249,7 +248,7 @@ static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m, + return err; + + if (m->type >= Z_EROFS_LCLUSTER_TYPE_MAX) { +- erofs_err(m->inode->i_sb, "unknown type %u @ lcn %u of nid %llu", ++ erofs_err(m->inode->i_sb, "unknown type %u @ lcn %llu of nid %llu", + m->type, lcn, EROFS_I(m->inode)->nid); + DBG_BUGON(1); + return -EOPNOTSUPP; +@@ -269,7 +268,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, + const unsigned int lclusterbits = vi->z_lclusterbits; + + while (m->lcn >= lookback_distance) { +- unsigned long lcn = m->lcn - lookback_distance; ++ u64 lcn = m->lcn - lookback_distance; + int err; + + err = z_erofs_load_lcluster_from_disk(m, lcn, false); +@@ -287,7 +286,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, + return 0; + } + } +- erofs_err(sb, "bogus lookback distance %u @ lcn %lu of nid %llu", ++ erofs_err(sb, "bogus lookback distance %u @ lcn %llu of nid %llu", + lookback_distance, m->lcn, vi->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; +@@ -301,7 +300,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + struct erofs_inode *vi = EROFS_I(inode); + bool bigpcl1 = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1; + bool bigpcl2 = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2; +- unsigned long lcn = m->lcn + 1; ++ u64 lcn = m->lcn + 1; + int err; + + DBG_BUGON(m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD); +@@ -332,7 +331,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD); + + if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD && m->delta[0] != 1) { +- erofs_err(sb, "bogus CBLKCNT @ lcn %lu of nid %llu", lcn, vi->nid); ++ erofs_err(sb, "bogus CBLKCNT @ lcn %llu of nid %llu", lcn, vi->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; + } +-- +2.53.0 + diff --git a/queue-6.12/erofs-verify-metadata-accesses-for-file-backed-mount.patch b/queue-6.12/erofs-verify-metadata-accesses-for-file-backed-mount.patch new file mode 100644 index 0000000000..42dc10628c --- /dev/null +++ b/queue-6.12/erofs-verify-metadata-accesses-for-file-backed-mount.patch @@ -0,0 +1,58 @@ +From b0430f341b4a894a824898564365a845eda46c75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 10:29:29 +0800 +Subject: erofs: verify metadata accesses for file-backed mounts + +From: Gao Xiang + +[ Upstream commit 307210c262a29f41d7177851295ea1703bd04175 ] + +For file-backed mounts, metadata is fetched via the page cache of +backing inodes to avoid double caching and redundant copy ops out +of RO uptodate folios, which is used by Android APEXes, ComposeFS, +containerd. However, rw_verify_area() was missing prior to +metadata accesses. + +Similar to vfs_iocb_iter_read(), fix this by: + - Enabling fanotify pre-content hooks on metadata accesses; + - security_file_permission() for security modules. + +Verified that fanotify pre-content hooks now works correctly. + +Fixes: fb176750266a ("erofs: add file-backed mount support") +Acked-by: Amir Goldstein +Reviewed-by: Chunhai Guo +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/data.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/fs/erofs/data.c b/fs/erofs/data.c +index 91182d5e3a66c..192c7ed885acd 100644 +--- a/fs/erofs/data.c ++++ b/fs/erofs/data.c +@@ -30,6 +30,20 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, + { + pgoff_t index = offset >> PAGE_SHIFT; + struct folio *folio = NULL; ++ loff_t fpos; ++ int err; ++ ++ /* ++ * Metadata access for file-backed mounts reuses page cache of backing ++ * fs inodes (only folio data will be needed) to prevent double caching. ++ * However, the data access range must be verified here in advance. ++ */ ++ if (buf->file) { ++ fpos = index << PAGE_SHIFT; ++ err = rw_verify_area(READ, buf->file, &fpos, PAGE_SIZE); ++ if (err < 0) ++ return ERR_PTR(err); ++ } + + if (buf->page) { + folio = page_folio(buf->page); +-- +2.53.0 + diff --git a/queue-6.12/eth-fbnic-use-wake-instead-of-start.patch b/queue-6.12/eth-fbnic-use-wake-instead-of-start.patch new file mode 100644 index 0000000000..dc03d3bba7 --- /dev/null +++ b/queue-6.12/eth-fbnic-use-wake-instead-of-start.patch @@ -0,0 +1,44 @@ +From f7cba30be463b5052ffc8a22bf3a907b2eb4f490 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:24:15 -0700 +Subject: eth: fbnic: Use wake instead of start + +From: Mohsin Bashir + +[ Upstream commit 12ff2a4aee6c86746623d5aed24389dbf6dffded ] + +fbnic_up() calls netif_tx_start_all_queues(), which only clears +__QUEUE_STATE_DRV_XOFF. If qdisc backlog has accumulated on any TX +queue before the reconfiguration (e.g. ring resize via ethtool -G), +start does not call __netif_schedule() to kick the qdisc, so the +pending backlog is never drained and the queue stalls. + +Switch to netif_tx_wake_all_queues(), which clears DRV_XOFF and also +calls __netif_schedule() on every queue, ensuring any backlog that +built up before the down/up cycle is promptly dequeued. + +Fixes: bc6107771bb4 ("eth: fbnic: Allocate a netdevice and napi vectors with queues") +Signed-off-by: Mohsin Bashir +Link: https://patch.msgid.link/20260408002415.2963915-1-mohsin.bashr@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +index 72bdc6c76c0c5..53bb1d691cc0c 100644 +--- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c ++++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +@@ -137,7 +137,7 @@ void fbnic_up(struct fbnic_net *fbn) + + /* Enable Tx/Rx processing */ + fbnic_napi_enable(fbn); +- netif_tx_start_all_queues(fbn->netdev); ++ netif_tx_wake_all_queues(fbn->netdev); + + fbnic_service_task_start(fbn); + } +-- +2.53.0 + diff --git a/queue-6.12/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch b/queue-6.12/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch new file mode 100644 index 0000000000..b09c580f8e --- /dev/null +++ b/queue-6.12/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch @@ -0,0 +1,70 @@ +From 14c910e478b9495c67171505783ad502463bf24c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:30:35 +0800 +Subject: ext4: fix possible null-ptr-deref in mbt_kunit_exit() + +From: Ye Bin + +[ Upstream commit 22f53f08d9eb837ce69b1a07641d414aac8d045f ] + +There's issue as follows: + # test_new_blocks_simple: failed to initialize: -12 +KASAN: null-ptr-deref in range [0x0000000000000638-0x000000000000063f] +Tainted: [E]=UNSIGNED_MODULE, [N]=TEST +RIP: 0010:mbt_kunit_exit+0x5e/0x3e0 [ext4_test] +Call Trace: + + kunit_try_run_case_cleanup+0xbc/0x100 [kunit] + kunit_generic_run_threadfn_adapter+0x89/0x100 [kunit] + kthread+0x408/0x540 + ret_from_fork+0xa76/0xdf0 + ret_from_fork_asm+0x1a/0x30 + +If mbt_kunit_init() init testcase failed will lead to null-ptr-deref. +So add test if 'sb' is inited success in mbt_kunit_exit(). + +Fixes: 7c9fa399a369 ("ext4: add first unit test for ext4_mb_new_blocks_simple in mballoc") +Signed-off-by: Ye Bin +Reviewed-by: Ritesh Harjani (IBM) +Reviewed-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20260330133035.287842-6-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc-test.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/ext4/mballoc-test.c b/fs/ext4/mballoc-test.c +index 0f81094fc0db1..6f506118d18ee 100644 +--- a/fs/ext4/mballoc-test.c ++++ b/fs/ext4/mballoc-test.c +@@ -362,7 +362,6 @@ static int mbt_kunit_init(struct kunit *test) + return ret; + } + +- test->priv = sb; + kunit_activate_static_stub(test, + ext4_read_block_bitmap_nowait, + ext4_read_block_bitmap_nowait_stub); +@@ -383,6 +382,8 @@ static int mbt_kunit_init(struct kunit *test) + return -ENOMEM; + } + ++ test->priv = sb; ++ + return 0; + } + +@@ -390,6 +391,9 @@ static void mbt_kunit_exit(struct kunit *test) + { + struct super_block *sb = (struct super_block *)test->priv; + ++ if (!sb) ++ return; ++ + mbt_mb_release(sb); + mbt_ctx_release(sb); + mbt_ext4_free_super_block(sb); +-- +2.53.0 + diff --git a/queue-6.12/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch b/queue-6.12/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch new file mode 100644 index 0000000000..5e8f284a42 --- /dev/null +++ b/queue-6.12/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch @@ -0,0 +1,57 @@ +From 77f8597f1dcc923f5deb7ce5654efbd0f604b6c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:05:39 +0800 +Subject: f2fs: protect extension_list reading with sb_lock in f2fs_sbi_show() + +From: Yongpeng Yang + +[ Upstream commit 5909bedbed38c558bee7cb6758ceedf9bc3a9194 ] + +In f2fs_sbi_show(), the extension_list, extension_count and +hot_ext_count are read without holding sbi->sb_lock. If a concurrent +sysfs store modifies the extension list via f2fs_update_extension_list(), +the show path may read inconsistent count and array contents, potentially +leading to out-of-bounds access or displaying stale data. + +Fix this by holding sb_lock around the entire extension list read +and format operation. + +Fixes: b6a06cbbb5f7 ("f2fs: support hot file extension") +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/sysfs.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index 7b490242bd054..4e1021eb372ee 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -358,10 +358,12 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + if (!strcmp(a->attr.name, "extension_list")) { + __u8 (*extlist)[F2FS_EXTENSION_LEN] = + sbi->raw_super->extension_list; +- int cold_count = le32_to_cpu(sbi->raw_super->extension_count); +- int hot_count = sbi->raw_super->hot_ext_count; ++ int cold_count, hot_count; + int len = 0, i; + ++ f2fs_down_read(&sbi->sb_lock); ++ cold_count = le32_to_cpu(sbi->raw_super->extension_count); ++ hot_count = sbi->raw_super->hot_ext_count; + len += sysfs_emit_at(buf, len, "cold file extension:\n"); + for (i = 0; i < cold_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); +@@ -369,6 +371,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + len += sysfs_emit_at(buf, len, "hot file extension:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); ++ f2fs_up_read(&sbi->sb_lock); + + return len; + } +-- +2.53.0 + diff --git a/queue-6.12/fanotify-call-fanotify_events_supported-before-path_.patch b/queue-6.12/fanotify-call-fanotify_events_supported-before-path_.patch new file mode 100644 index 0000000000..853886a5ad --- /dev/null +++ b/queue-6.12/fanotify-call-fanotify_events_supported-before-path_.patch @@ -0,0 +1,79 @@ +From 59e80857c788891b367953338d9a9b7e07bacd75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 16:06:25 +0100 +Subject: fanotify: call fanotify_events_supported() before path_permission() + and security_path_notify() + +From: Ondrej Mosnacek + +[ Upstream commit 66052a768d4726a31e939b5ac902f2b0b452c8d5 ] + +The latter trigger LSM (e.g. SELinux) checks, which will log a denial +when permission is denied, so it's better to do them after validity +checks to avoid logging a denial when the operation would fail anyway. + +Fixes: 0b3b094ac9a7 ("fanotify: Disallow permission events for proc filesystem") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Amir Goldstein +Reviewed-by: Paul Moore +Link: https://patch.msgid.link/20260216150625.793013-3-omosnace@redhat.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index f3f957bac71b0..93c1619cdad65 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1025,6 +1025,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, + + *path = fd_file(f)->f_path; + path_get(path); ++ ret = 0; + } else { + unsigned int lookup_flags = 0; + +@@ -1034,22 +1035,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, + lookup_flags |= LOOKUP_DIRECTORY; + + ret = user_path_at(dfd, filename, lookup_flags, path); +- if (ret) +- goto out; +- } +- +- /* you can only watch an inode if you have read permissions on it */ +- ret = path_permission(path, MAY_READ); +- if (ret) { +- path_put(path); +- goto out; + } +- +- ret = security_path_notify(path, mask, obj_type); +- if (ret) +- path_put(path); +- +-out: + return ret; + } + +@@ -1841,6 +1827,15 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + goto path_put_and_out; + } + ++ /* you can only watch an inode if you have read permissions on it */ ++ ret = path_permission(&path, MAY_READ); ++ if (ret) ++ goto path_put_and_out; ++ ++ ret = security_path_notify(&path, mask, obj_type); ++ if (ret) ++ goto path_put_and_out; ++ + if (fid_mode) { + ret = fanotify_test_fsid(path.dentry, flags, &__fsid); + if (ret) +-- +2.53.0 + diff --git a/queue-6.12/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch b/queue-6.12/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch new file mode 100644 index 0000000000..d43f0fbf38 --- /dev/null +++ b/queue-6.12/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch @@ -0,0 +1,71 @@ +From 99ec3cdb4496561867c5b332ed71e68ac901bb73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 15:36:46 +0100 +Subject: fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build + break + +From: Andy Shevchenko + +[ Upstream commit caf6144053b4e1c815aa56afb54745a176f999df ] + +Clang is not happy about set but unused variable: + +drivers/video/fbdev/matrox/g450_pll.c:412:18: error: variable 'mnp' set but not used + 412 | unsigned int mnp; + | ^ +1 error generated. + +Since the commit 7b987887f97b ("video: fbdev: matroxfb: remove dead code +and set but not used variable") the 'mnp' became unused, but eliminating +that code might have side-effects. The question here is what should we do +with 'mnp'? The easiest way out is just mark it with __maybe_unused which +will shut the compiler up and won't change any possible IO flow. So does +this change. + +A dive into the history of the driver: + +The problem was revealed when the #if 0 guarded code along with unused +pixel_vco variable was removed. That code was introduced in the original +commit 213d22146d1f ("[PATCH] (1/3) matroxfb for 2.5.3"). And then guarded +in the commit 705e41f82988 ("matroxfb DVI updates: Handle DVI output on +G450/G550. Powerdown unused portions of G450/G550 DAC. Split G450/G550 DAC +from older DAC1064 handling. Modify PLL setting when both CRTCs use same +pixel clocks."). + +NOTE: The two commits mentioned above pre-date Git era and available in +history.git repository for archaeological purposes. + +Even without that guard the modern compilers may see that the pixel_vco +wasn't ever used and seems a leftover after some debug or review made +25 years ago. + +The g450_mnp2vco() doesn't have any IO and as Jason said doesn't seem +to have any side effects either than some unneeded CPU processing during +runtime. I agree that's unlikely that timeout (or heating up the CPU) has +any effect on the HW (GPU/display) functionality. + +Fixes: 7b987887f97b ("video: fbdev: matroxfb: remove dead code and set but not used variable") +Signed-off-by: Andy Shevchenko +Reviewed-by: Jason Yan +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/matrox/g450_pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c +index ff8e321a22cef..b2d3f7328ea83 100644 +--- a/drivers/video/fbdev/matrox/g450_pll.c ++++ b/drivers/video/fbdev/matrox/g450_pll.c +@@ -407,7 +407,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, + case M_VIDEO_PLL: + { + u_int8_t tmp; +- unsigned int mnp; ++ unsigned int mnp __maybe_unused; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); +-- +2.53.0 + diff --git a/queue-6.12/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch b/queue-6.12/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch new file mode 100644 index 0000000000..ee23421e67 --- /dev/null +++ b/queue-6.12/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch @@ -0,0 +1,52 @@ +From 93325473afb69d952bfd27c5adbcd054b587e3ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:01:18 -0400 +Subject: fbdev: offb: fix PCI device reference leak on probe failure + +From: Yuho Choi + +[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ] + +offb_init_nodriver() gets a referenced PCI device with pci_get_device(). +If pci_enable_device() fails, the function returns without dropping that +reference. + +Release the PCI device reference before returning from the +pci_enable_device() failure path. + +Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/offb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c +index f85428e13996b..166b2dff36f59 100644 +--- a/drivers/video/fbdev/offb.c ++++ b/drivers/video/fbdev/offb.c +@@ -640,8 +640,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod + vid = be32_to_cpup(vidp); + did = be32_to_cpup(didp); + pdev = pci_get_device(vid, did, NULL); +- if (!pdev || pci_enable_device(pdev)) ++ if (!pdev) + return; ++ ++ if (pci_enable_device(pdev)) { ++ pci_dev_put(pdev); ++ return; ++ } + } + #endif + /* kludge for valkyrie */ +-- +2.53.0 + diff --git a/queue-6.12/fdget-trivial-conversions.patch b/queue-6.12/fdget-trivial-conversions.patch new file mode 100644 index 0000000000..1b04390f4b --- /dev/null +++ b/queue-6.12/fdget-trivial-conversions.patch @@ -0,0 +1,1399 @@ +From 92465129f4a4c1097d0aa26179529917fd287c9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Jul 2024 20:17:58 -0400 +Subject: fdget(), trivial conversions + +From: Al Viro + +[ Upstream commit 6348be02eead77bdd1562154ed6b3296ad3b3750 ] + +fdget() is the first thing done in scope, all matching fdput() are +immediately followed by leaving the scope. + +Reviewed-by: Christian Brauner +Signed-off-by: Al Viro +Stable-dep-of: 66052a768d47 ("fanotify: call fanotify_events_supported() before path_permission() and security_path_notify()") +Signed-off-by: Sasha Levin +--- + arch/powerpc/kvm/book3s_64_vio.c | 21 +++--------- + arch/powerpc/kvm/powerpc.c | 24 ++++--------- + arch/powerpc/platforms/cell/spu_syscalls.c | 6 ++-- + arch/x86/kernel/cpu/sgx/main.c | 10 ++---- + arch/x86/kvm/svm/sev.c | 39 ++++++++-------------- + drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 23 ++++--------- + drivers/gpu/drm/drm_syncobj.c | 9 ++--- + drivers/media/rc/lirc_dev.c | 13 +++----- + fs/btrfs/ioctl.c | 5 ++- + fs/eventfd.c | 9 ++--- + fs/eventpoll.c | 23 ++++--------- + fs/fhandle.c | 5 ++- + fs/ioctl.c | 23 +++++-------- + fs/kernel_read_file.c | 12 +++---- + fs/notify/fanotify/fanotify_user.c | 15 +++------ + fs/notify/inotify/inotify_user.c | 17 +++------- + fs/open.c | 36 +++++++++----------- + fs/read_write.c | 28 +++++----------- + fs/signalfd.c | 9 ++--- + fs/sync.c | 29 ++++++---------- + io_uring/sqpoll.c | 29 +++++----------- + kernel/events/core.c | 14 +++----- + kernel/nsproxy.c | 5 ++- + kernel/pid.c | 7 ++-- + kernel/sys.c | 15 +++------ + kernel/watch_queue.c | 6 ++-- + mm/fadvise.c | 10 ++---- + mm/readahead.c | 17 +++------- + net/core/net_namespace.c | 10 +++--- + security/landlock/syscalls.c | 26 +++++---------- + virt/kvm/vfio.c | 8 ++--- + 31 files changed, 164 insertions(+), 339 deletions(-) + +diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c +index 34c0adb9fdbf2..742aa58a7c7e3 100644 +--- a/arch/powerpc/kvm/book3s_64_vio.c ++++ b/arch/powerpc/kvm/book3s_64_vio.c +@@ -115,10 +115,9 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + struct iommu_table_group *table_group; + long i; + struct kvmppc_spapr_tce_iommu_table *stit; +- struct fd f; ++ CLASS(fd, f)(tablefd); + +- f = fdget(tablefd); +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + + rcu_read_lock(); +@@ -130,16 +129,12 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + } + rcu_read_unlock(); + +- if (!found) { +- fdput(f); ++ if (!found) + return -EINVAL; +- } + + table_group = iommu_group_get_iommudata(grp); +- if (WARN_ON(!table_group)) { +- fdput(f); ++ if (WARN_ON(!table_group)) + return -EFAULT; +- } + + for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { + struct iommu_table *tbltmp = table_group->tables[i]; +@@ -160,10 +155,8 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + break; + } + } +- if (!tbl) { +- fdput(f); ++ if (!tbl) + return -EINVAL; +- } + + rcu_read_lock(); + list_for_each_entry_rcu(stit, &stt->iommu_tables, next) { +@@ -174,7 +167,6 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + /* stit is being destroyed */ + iommu_tce_table_put(tbl); + rcu_read_unlock(); +- fdput(f); + return -ENOTTY; + } + /* +@@ -182,7 +174,6 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + * its KVM reference counter and can return. + */ + rcu_read_unlock(); +- fdput(f); + return 0; + } + rcu_read_unlock(); +@@ -190,7 +181,6 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + stit = kzalloc(sizeof(*stit), GFP_KERNEL); + if (!stit) { + iommu_tce_table_put(tbl); +- fdput(f); + return -ENOMEM; + } + +@@ -199,7 +189,6 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + + list_add_rcu(&stit->next, &stt->iommu_tables); + +- fdput(f); + return 0; + } + +diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c +index 4b6ce4f07bc2c..5a95c3d473b0d 100644 +--- a/arch/powerpc/kvm/powerpc.c ++++ b/arch/powerpc/kvm/powerpc.c +@@ -1930,12 +1930,11 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, + #endif + #ifdef CONFIG_KVM_MPIC + case KVM_CAP_IRQ_MPIC: { +- struct fd f; ++ CLASS(fd, f)(cap->args[0]); + struct kvm_device *dev; + + r = -EBADF; +- f = fdget(cap->args[0]); +- if (!fd_file(f)) ++ if (fd_empty(f)) + break; + + r = -EPERM; +@@ -1943,18 +1942,16 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, + if (dev) + r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); + +- fdput(f); + break; + } + #endif + #ifdef CONFIG_KVM_XICS + case KVM_CAP_IRQ_XICS: { +- struct fd f; ++ CLASS(fd, f)(cap->args[0]); + struct kvm_device *dev; + + r = -EBADF; +- f = fdget(cap->args[0]); +- if (!fd_file(f)) ++ if (fd_empty(f)) + break; + + r = -EPERM; +@@ -1965,34 +1962,27 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, + else + r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]); + } +- +- fdput(f); + break; + } + #endif /* CONFIG_KVM_XICS */ + #ifdef CONFIG_KVM_XIVE + case KVM_CAP_PPC_IRQ_XIVE: { +- struct fd f; ++ CLASS(fd, f)(cap->args[0]); + struct kvm_device *dev; + + r = -EBADF; +- f = fdget(cap->args[0]); +- if (!fd_file(f)) ++ if (fd_empty(f)) + break; + + r = -ENXIO; +- if (!xive_enabled()) { +- fdput(f); ++ if (!xive_enabled()) + break; +- } + + r = -EPERM; + dev = kvm_device_from_filp(fd_file(f)); + if (dev) + r = kvmppc_xive_native_connect_vcpu(dev, vcpu, + cap->args[1]); +- +- fdput(f); + break; + } + #endif /* CONFIG_KVM_XIVE */ +diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c +index cd7d42fc12a67..da4fad7fc8bf6 100644 +--- a/arch/powerpc/platforms/cell/spu_syscalls.c ++++ b/arch/powerpc/platforms/cell/spu_syscalls.c +@@ -64,12 +64,10 @@ SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, + return -ENOSYS; + + if (flags & SPU_CREATE_AFFINITY_SPU) { +- struct fd neighbor = fdget(neighbor_fd); ++ CLASS(fd, neighbor)(neighbor_fd); + ret = -EBADF; +- if (fd_file(neighbor)) { ++ if (!fd_empty(neighbor)) + ret = calls->create_thread(name, flags, mode, fd_file(neighbor)); +- fdput(neighbor); +- } + } else + ret = calls->create_thread(name, flags, mode, NULL); + +diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c +index 147ea26dfdad6..6fb1e7dd4595b 100644 +--- a/arch/x86/kernel/cpu/sgx/main.c ++++ b/arch/x86/kernel/cpu/sgx/main.c +@@ -903,19 +903,15 @@ static struct miscdevice sgx_dev_provision = { + int sgx_set_attribute(unsigned long *allowed_attributes, + unsigned int attribute_fd) + { +- struct fd f = fdget(attribute_fd); ++ CLASS(fd, f)(attribute_fd); + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EINVAL; + +- if (fd_file(f)->f_op != &sgx_provision_fops) { +- fdput(f); ++ if (fd_file(f)->f_op != &sgx_provision_fops) + return -EINVAL; +- } + + *allowed_attributes |= SGX_ATTR_PROVISIONKEY; +- +- fdput(f); + return 0; + } + EXPORT_SYMBOL_GPL(sgx_set_attribute); +diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c +index 7aedb0a063549..ad7590ec40659 100644 +--- a/arch/x86/kvm/svm/sev.c ++++ b/arch/x86/kvm/svm/sev.c +@@ -533,17 +533,12 @@ static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error) + + static int __sev_issue_cmd(int fd, int id, void *data, int *error) + { +- struct fd f; +- int ret; ++ CLASS(fd, f)(fd); + +- f = fdget(fd); +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + +- ret = sev_issue_cmd_external_user(fd_file(f), id, data, error); +- +- fdput(f); +- return ret; ++ return sev_issue_cmd_external_user(fd_file(f), id, data, error); + } + + static int sev_issue_cmd(struct kvm *kvm, int id, void *data, int *error) +@@ -2089,23 +2084,21 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd) + { + struct kvm_sev_info *dst_sev = &to_kvm_svm(kvm)->sev_info; + struct kvm_sev_info *src_sev, *cg_cleanup_sev; +- struct fd f = fdget(source_fd); ++ CLASS(fd, f)(source_fd); + struct kvm *source_kvm; + bool charged = false; + int ret; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + +- if (!file_is_kvm(fd_file(f))) { +- ret = -EBADF; +- goto out_fput; +- } ++ if (!file_is_kvm(fd_file(f))) ++ return -EBADF; + + source_kvm = fd_file(f)->private_data; + ret = sev_lock_two_vms(kvm, source_kvm); + if (ret) +- goto out_fput; ++ return ret; + + if (kvm->arch.vm_type != source_kvm->arch.vm_type || + sev_guest(kvm) || !sev_guest(source_kvm)) { +@@ -2152,8 +2145,6 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd) + cg_cleanup_sev->misc_cg = NULL; + out_unlock: + sev_unlock_two_vms(kvm, source_kvm); +-out_fput: +- fdput(f); + return ret; + } + +@@ -2817,23 +2808,21 @@ int sev_mem_enc_unregister_region(struct kvm *kvm, + + int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd) + { +- struct fd f = fdget(source_fd); ++ CLASS(fd, f)(source_fd); + struct kvm *source_kvm; + struct kvm_sev_info *source_sev, *mirror_sev; + int ret; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + +- if (!file_is_kvm(fd_file(f))) { +- ret = -EBADF; +- goto e_source_fput; +- } ++ if (!file_is_kvm(fd_file(f))) ++ return -EBADF; + + source_kvm = fd_file(f)->private_data; + ret = sev_lock_two_vms(kvm, source_kvm); + if (ret) +- goto e_source_fput; ++ return ret; + + /* + * Mirrors of mirrors should work, but let's not get silly. Also +@@ -2876,8 +2865,6 @@ int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd) + + e_unlock: + sev_unlock_two_vms(kvm, source_kvm); +-e_source_fput: +- fdput(f); + return ret; + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +index b0a8abc7a8ecf..341beec595375 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +@@ -35,21 +35,19 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, + int fd, + int32_t priority) + { +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + struct amdgpu_fpriv *fpriv; + struct amdgpu_ctx_mgr *mgr; + struct amdgpu_ctx *ctx; + uint32_t id; + int r; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EINVAL; + + r = amdgpu_file_to_fpriv(fd_file(f), &fpriv); +- if (r) { +- fdput(f); ++ if (r) + return r; +- } + + mgr = &fpriv->ctx_mgr; + mutex_lock(&mgr->lock); +@@ -57,7 +55,6 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, + amdgpu_ctx_priority_override(ctx, priority); + mutex_unlock(&mgr->lock); + +- fdput(f); + return 0; + } + +@@ -66,31 +63,25 @@ static int amdgpu_sched_context_priority_override(struct amdgpu_device *adev, + unsigned ctx_id, + int32_t priority) + { +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + struct amdgpu_fpriv *fpriv; + struct amdgpu_ctx *ctx; + int r; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EINVAL; + + r = amdgpu_file_to_fpriv(fd_file(f), &fpriv); +- if (r) { +- fdput(f); ++ if (r) + return r; +- } + + ctx = amdgpu_ctx_get(fpriv, ctx_id); + +- if (!ctx) { +- fdput(f); ++ if (!ctx) + return -EINVAL; +- } + + amdgpu_ctx_priority_override(ctx, priority); + amdgpu_ctx_put(ctx); +- fdput(f); +- + return 0; + } + +diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c +index 8e3d2d7060f80..4f2ab8a7b50fd 100644 +--- a/drivers/gpu/drm/drm_syncobj.c ++++ b/drivers/gpu/drm/drm_syncobj.c +@@ -712,16 +712,14 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private, + int fd, u32 *handle) + { + struct drm_syncobj *syncobj; +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + int ret; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EINVAL; + +- if (fd_file(f)->f_op != &drm_syncobj_file_fops) { +- fdput(f); ++ if (fd_file(f)->f_op != &drm_syncobj_file_fops) + return -EINVAL; +- } + + /* take a reference to put in the idr */ + syncobj = fd_file(f)->private_data; +@@ -739,7 +737,6 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private, + } else + drm_syncobj_put(syncobj); + +- fdput(f); + return ret; + } + +diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c +index 314f64420f629..7d4942925993a 100644 +--- a/drivers/media/rc/lirc_dev.c ++++ b/drivers/media/rc/lirc_dev.c +@@ -816,28 +816,23 @@ void __exit lirc_dev_exit(void) + + struct rc_dev *rc_dev_get_from_fd(int fd, bool write) + { +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + struct lirc_fh *fh; + struct rc_dev *dev; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return ERR_PTR(-EBADF); + +- if (fd_file(f)->f_op != &lirc_fops) { +- fdput(f); ++ if (fd_file(f)->f_op != &lirc_fops) + return ERR_PTR(-EINVAL); +- } + +- if (write && !(fd_file(f)->f_mode & FMODE_WRITE)) { +- fdput(f); ++ if (write && !(fd_file(f)->f_mode & FMODE_WRITE)) + return ERR_PTR(-EPERM); +- } + + fh = fd_file(f)->private_data; + dev = fh->rc; + + get_device(&dev->dev); +- fdput(f); + + return dev; + } +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index a61022182f45d..b6152b36f81ec 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -1315,9 +1315,9 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file, + ret = btrfs_mksubvol(&file->f_path, idmap, name, + namelen, NULL, readonly, inherit); + } else { +- struct fd src = fdget(fd); ++ CLASS(fd, src)(fd); + struct inode *src_inode; +- if (!fd_file(src)) { ++ if (fd_empty(src)) { + ret = -EINVAL; + goto out_drop_write; + } +@@ -1348,7 +1348,6 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file, + BTRFS_I(src_inode)->root, + readonly, inherit); + } +- fdput(src); + } + out_drop_write: + mnt_drop_write_file(file); +diff --git a/fs/eventfd.c b/fs/eventfd.c +index 22c934f3a080e..76129bfcd663a 100644 +--- a/fs/eventfd.c ++++ b/fs/eventfd.c +@@ -347,13 +347,10 @@ EXPORT_SYMBOL_GPL(eventfd_fget); + */ + struct eventfd_ctx *eventfd_ctx_fdget(int fd) + { +- struct eventfd_ctx *ctx; +- struct fd f = fdget(fd); +- if (!fd_file(f)) ++ CLASS(fd, f)(fd); ++ if (fd_empty(f)) + return ERR_PTR(-EBADF); +- ctx = eventfd_ctx_fileget(fd_file(f)); +- fdput(f); +- return ctx; ++ return eventfd_ctx_fileget(fd_file(f)); + } + EXPORT_SYMBOL_GPL(eventfd_ctx_fdget); + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 075aa8793aaa9..a860cb54658a3 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -2207,25 +2207,22 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, + { + int error; + int full_check = 0; +- struct fd f, tf; + struct eventpoll *ep; + struct epitem *epi; + struct eventpoll *tep = NULL; + +- error = -EBADF; +- f = fdget(epfd); +- if (!fd_file(f)) +- goto error_return; ++ CLASS(fd, f)(epfd); ++ if (fd_empty(f)) ++ return -EBADF; + + /* Get the "struct file *" for the target file */ +- tf = fdget(fd); +- if (!fd_file(tf)) +- goto error_fput; ++ CLASS(fd, tf)(fd); ++ if (fd_empty(tf)) ++ return -EBADF; + + /* The target file descriptor must support poll */ +- error = -EPERM; + if (!file_can_poll(fd_file(tf))) +- goto error_tgt_fput; ++ return -EPERM; + + /* Check if EPOLLWAKEUP is allowed */ + if (ep_op_has_event(op)) +@@ -2344,12 +2341,6 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, + loop_check_gen++; + mutex_unlock(&epnested_mutex); + } +- +- fdput(tf); +-error_fput: +- fdput(f); +-error_return: +- + return error; + } + +diff --git a/fs/fhandle.c b/fs/fhandle.c +index ff90f8203015e..38d803a28ab91 100644 +--- a/fs/fhandle.c ++++ b/fs/fhandle.c +@@ -139,12 +139,11 @@ static int get_path_from_fd(int fd, struct path *root) + path_get(root); + spin_unlock(&fs->lock); + } else { +- struct fd f = fdget(fd); +- if (!fd_file(f)) ++ CLASS(fd, f)(fd); ++ if (fd_empty(f)) + return -EBADF; + *root = fd_file(f)->f_path; + path_get(root); +- fdput(f); + } + + return 0; +diff --git a/fs/ioctl.c b/fs/ioctl.c +index 6e0c954388d47..638a36be31c14 100644 +--- a/fs/ioctl.c ++++ b/fs/ioctl.c +@@ -231,11 +231,11 @@ static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap) + static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, + u64 off, u64 olen, u64 destoff) + { +- struct fd src_file = fdget(srcfd); ++ CLASS(fd, src_file)(srcfd); + loff_t cloned; + int ret; + +- if (!fd_file(src_file)) ++ if (fd_empty(src_file)) + return -EBADF; + cloned = vfs_clone_file_range(fd_file(src_file), off, dst_file, destoff, + olen, 0); +@@ -245,7 +245,6 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, + ret = -EINVAL; + else + ret = 0; +- fdput(src_file); + return ret; + } + +@@ -892,22 +891,20 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd, + + SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) + { +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + int error; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + + error = security_file_ioctl(fd_file(f), cmd, arg); + if (error) +- goto out; ++ return error; + + error = do_vfs_ioctl(fd_file(f), fd, cmd, arg); + if (error == -ENOIOCTLCMD) + error = vfs_ioctl(fd_file(f), cmd, arg); + +-out: +- fdput(f); + return error; + } + +@@ -950,15 +947,15 @@ EXPORT_SYMBOL(compat_ptr_ioctl); + COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, + compat_ulong_t, arg) + { +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + int error; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + + error = security_file_ioctl_compat(fd_file(f), cmd, arg); + if (error) +- goto out; ++ return error; + + switch (cmd) { + /* FICLONE takes an int argument, so don't use compat_ptr() */ +@@ -1009,10 +1006,6 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, + error = -ENOTTY; + break; + } +- +- out: +- fdput(f); +- + return error; + } + #endif +diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c +index 9ff37ae650ea4..de32c95d823db 100644 +--- a/fs/kernel_read_file.c ++++ b/fs/kernel_read_file.c +@@ -175,15 +175,11 @@ ssize_t kernel_read_file_from_fd(int fd, loff_t offset, void **buf, + size_t buf_size, size_t *file_size, + enum kernel_read_file_id id) + { +- struct fd f = fdget(fd); +- ssize_t ret = -EBADF; ++ CLASS(fd, f)(fd); + +- if (!fd_file(f) || !(fd_file(f)->f_mode & FMODE_READ)) +- goto out; ++ if (fd_empty(f) || !(fd_file(f)->f_mode & FMODE_READ)) ++ return -EBADF; + +- ret = kernel_read_file(fd_file(f), offset, buf, buf_size, file_size, id); +-out: +- fdput(f); +- return ret; ++ return kernel_read_file(fd_file(f), offset, buf, buf_size, file_size, id); + } + EXPORT_SYMBOL_GPL(kernel_read_file_from_fd); +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 8e2d43fc6f7c1..f3f957bac71b0 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1014,22 +1014,17 @@ static int fanotify_find_path(int dfd, const char __user *filename, + dfd, filename, flags); + + if (filename == NULL) { +- struct fd f = fdget(dfd); ++ CLASS(fd, f)(dfd); + +- ret = -EBADF; +- if (!fd_file(f)) +- goto out; ++ if (fd_empty(f)) ++ return -EBADF; + +- ret = -ENOTDIR; + if ((flags & FAN_MARK_ONLYDIR) && +- !(S_ISDIR(file_inode(fd_file(f))->i_mode))) { +- fdput(f); +- goto out; +- } ++ !(S_ISDIR(file_inode(fd_file(f))->i_mode))) ++ return -ENOTDIR; + + *path = fd_file(f)->f_path; + path_get(path); +- fdput(f); + } else { + unsigned int lookup_flags = 0; + +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 26839972f609b..0ea4e99dc449c 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -795,33 +795,26 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) + { + struct fsnotify_group *group; + struct inotify_inode_mark *i_mark; +- struct fd f; +- int ret = -EINVAL; ++ CLASS(fd, f)(fd); + +- f = fdget(fd); +- if (unlikely(!fd_file(f))) ++ if (fd_empty(f)) + return -EBADF; + + /* verify that this is indeed an inotify instance */ + if (unlikely(fd_file(f)->f_op != &inotify_fops)) +- goto out; ++ return -EINVAL; + + group = fd_file(f)->private_data; + + i_mark = inotify_idr_find(group, wd); + if (unlikely(!i_mark)) +- goto out; +- +- ret = 0; ++ return -EINVAL; + + fsnotify_destroy_mark(&i_mark->fsn_mark, group); + + /* match ref taken by inotify_idr_find */ + fsnotify_put_mark(&i_mark->fsn_mark); +- +-out: +- fdput(f); +- return ret; ++ return 0; + } + + /* +diff --git a/fs/open.c b/fs/open.c +index de1ea1b2f6ef5..be7b55260a755 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -349,14 +349,12 @@ EXPORT_SYMBOL_GPL(vfs_fallocate); + + int ksys_fallocate(int fd, int mode, loff_t offset, loff_t len) + { +- struct fd f = fdget(fd); +- int error = -EBADF; ++ CLASS(fd, f)(fd); + +- if (fd_file(f)) { +- error = vfs_fallocate(fd_file(f), mode, offset, len); +- fdput(f); +- } +- return error; ++ if (fd_empty(f)) ++ return -EBADF; ++ ++ return vfs_fallocate(fd_file(f), mode, offset, len); + } + + SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) +@@ -671,14 +669,12 @@ int vfs_fchmod(struct file *file, umode_t mode) + + SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode) + { +- struct fd f = fdget(fd); +- int err = -EBADF; ++ CLASS(fd, f)(fd); + +- if (fd_file(f)) { +- err = vfs_fchmod(fd_file(f), mode); +- fdput(f); +- } +- return err; ++ if (fd_empty(f)) ++ return -EBADF; ++ ++ return vfs_fchmod(fd_file(f), mode); + } + + static int do_fchmodat(int dfd, const char __user *filename, umode_t mode, +@@ -865,14 +861,12 @@ int vfs_fchown(struct file *file, uid_t user, gid_t group) + + int ksys_fchown(unsigned int fd, uid_t user, gid_t group) + { +- struct fd f = fdget(fd); +- int error = -EBADF; ++ CLASS(fd, f)(fd); + +- if (fd_file(f)) { +- error = vfs_fchown(fd_file(f), user, group); +- fdput(f); +- } +- return error; ++ if (fd_empty(f)) ++ return -EBADF; ++ ++ return vfs_fchown(fd_file(f), user, group); + } + + SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) +diff --git a/fs/read_write.c b/fs/read_write.c +index 46408bab92385..430c06993b758 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -1675,36 +1675,32 @@ SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in, + { + loff_t pos_in; + loff_t pos_out; +- struct fd f_in; +- struct fd f_out; + ssize_t ret = -EBADF; + +- f_in = fdget(fd_in); +- if (!fd_file(f_in)) +- goto out2; ++ CLASS(fd, f_in)(fd_in); ++ if (fd_empty(f_in)) ++ return -EBADF; + +- f_out = fdget(fd_out); +- if (!fd_file(f_out)) +- goto out1; ++ CLASS(fd, f_out)(fd_out); ++ if (fd_empty(f_out)) ++ return -EBADF; + +- ret = -EFAULT; + if (off_in) { + if (copy_from_user(&pos_in, off_in, sizeof(loff_t))) +- goto out; ++ return -EFAULT; + } else { + pos_in = fd_file(f_in)->f_pos; + } + + if (off_out) { + if (copy_from_user(&pos_out, off_out, sizeof(loff_t))) +- goto out; ++ return -EFAULT; + } else { + pos_out = fd_file(f_out)->f_pos; + } + +- ret = -EINVAL; + if (flags != 0) +- goto out; ++ return -EINVAL; + + ret = vfs_copy_file_range(fd_file(f_in), pos_in, fd_file(f_out), pos_out, len, + flags); +@@ -1726,12 +1722,6 @@ SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in, + fd_file(f_out)->f_pos = pos_out; + } + } +- +-out: +- fdput(f_out); +-out1: +- fdput(f_in); +-out2: + return ret; + } + +diff --git a/fs/signalfd.c b/fs/signalfd.c +index 736bebf935918..d1a5f43ce4669 100644 +--- a/fs/signalfd.c ++++ b/fs/signalfd.c +@@ -288,20 +288,17 @@ static int do_signalfd4(int ufd, sigset_t *mask, int flags) + + fd_install(ufd, file); + } else { +- struct fd f = fdget(ufd); +- if (!fd_file(f)) ++ CLASS(fd, f)(ufd); ++ if (fd_empty(f)) + return -EBADF; + ctx = fd_file(f)->private_data; +- if (fd_file(f)->f_op != &signalfd_fops) { +- fdput(f); ++ if (fd_file(f)->f_op != &signalfd_fops) + return -EINVAL; +- } + spin_lock_irq(¤t->sighand->siglock); + ctx->sigmask = *mask; + spin_unlock_irq(¤t->sighand->siglock); + + wake_up(¤t->sighand->signalfd_wqh); +- fdput(f); + } + + return ufd; +diff --git a/fs/sync.c b/fs/sync.c +index 67df255eb189d..2955cd4c77a3e 100644 +--- a/fs/sync.c ++++ b/fs/sync.c +@@ -148,11 +148,11 @@ void emergency_sync(void) + */ + SYSCALL_DEFINE1(syncfs, int, fd) + { +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + struct super_block *sb; + int ret, ret2; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + sb = fd_file(f)->f_path.dentry->d_sb; + +@@ -162,7 +162,6 @@ SYSCALL_DEFINE1(syncfs, int, fd) + + ret2 = errseq_check_and_advance(&sb->s_wb_err, &fd_file(f)->f_sb_err); + +- fdput(f); + return ret ? ret : ret2; + } + +@@ -205,14 +204,12 @@ EXPORT_SYMBOL(vfs_fsync); + + static int do_fsync(unsigned int fd, int datasync) + { +- struct fd f = fdget(fd); +- int ret = -EBADF; ++ CLASS(fd, f)(fd); + +- if (fd_file(f)) { +- ret = vfs_fsync(fd_file(f), datasync); +- fdput(f); +- } +- return ret; ++ if (fd_empty(f)) ++ return -EBADF; ++ ++ return vfs_fsync(fd_file(f), datasync); + } + + SYSCALL_DEFINE1(fsync, unsigned int, fd) +@@ -355,16 +352,12 @@ int sync_file_range(struct file *file, loff_t offset, loff_t nbytes, + int ksys_sync_file_range(int fd, loff_t offset, loff_t nbytes, + unsigned int flags) + { +- int ret; +- struct fd f; ++ CLASS(fd, f)(fd); + +- ret = -EBADF; +- f = fdget(fd); +- if (fd_file(f)) +- ret = sync_file_range(fd_file(f), offset, nbytes, flags); ++ if (fd_empty(f)) ++ return -EBADF; + +- fdput(f); +- return ret; ++ return sync_file_range(fd_file(f), offset, nbytes, flags); + } + + SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes, +diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c +index 44e7959b52d94..b39067a049fd9 100644 +--- a/io_uring/sqpoll.c ++++ b/io_uring/sqpoll.c +@@ -115,29 +115,21 @@ static struct io_sq_data *io_attach_sq_data(struct io_uring_params *p) + { + struct io_ring_ctx *ctx_attach; + struct io_sq_data *sqd; +- struct fd f; ++ CLASS(fd, f)(p->wq_fd); + +- f = fdget(p->wq_fd); +- if (!fd_file(f)) ++ if (fd_empty(f)) + return ERR_PTR(-ENXIO); +- if (!io_is_uring_fops(fd_file(f))) { +- fdput(f); ++ if (!io_is_uring_fops(fd_file(f))) + return ERR_PTR(-EINVAL); +- } + + ctx_attach = fd_file(f)->private_data; + sqd = ctx_attach->sq_data; +- if (!sqd) { +- fdput(f); ++ if (!sqd) + return ERR_PTR(-EINVAL); +- } +- if (sqd->task_tgid != current->tgid) { +- fdput(f); ++ if (sqd->task_tgid != current->tgid) + return ERR_PTR(-EPERM); +- } + + refcount_inc(&sqd->refs); +- fdput(f); + return sqd; + } + +@@ -456,16 +448,11 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx, + /* Retain compatibility with failing for an invalid attach attempt */ + if ((ctx->flags & (IORING_SETUP_ATTACH_WQ | IORING_SETUP_SQPOLL)) == + IORING_SETUP_ATTACH_WQ) { +- struct fd f; +- +- f = fdget(p->wq_fd); +- if (!fd_file(f)) ++ CLASS(fd, f)(p->wq_fd); ++ if (fd_empty(f)) + return -ENXIO; +- if (!io_is_uring_fops(fd_file(f))) { +- fdput(f); ++ if (!io_is_uring_fops(fd_file(f))) + return -EINVAL; +- } +- fdput(f); + } + if (ctx->flags & IORING_SETUP_SQPOLL) { + struct task_struct *tsk; +diff --git a/kernel/events/core.c b/kernel/events/core.c +index bcedf9611cf4f..6fce2bac6dae5 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -984,22 +984,20 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event, + { + struct perf_cgroup *cgrp; + struct cgroup_subsys_state *css; +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + int ret = 0; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + + css = css_tryget_online_from_dir(fd_file(f)->f_path.dentry, + &perf_event_cgrp_subsys); +- if (IS_ERR(css)) { +- ret = PTR_ERR(css); +- goto out; +- } ++ if (IS_ERR(css)) ++ return PTR_ERR(css); + + ret = perf_cgroup_ensure_storage(event, css); + if (ret) +- goto out; ++ return ret; + + cgrp = container_of(css, struct perf_cgroup, css); + event->cgrp = cgrp; +@@ -1013,8 +1011,6 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event, + perf_detach_cgroup(event); + ret = -EINVAL; + } +-out: +- fdput(f); + return ret; + } + +diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c +index dc952c3b05afd..c9d97ed201227 100644 +--- a/kernel/nsproxy.c ++++ b/kernel/nsproxy.c +@@ -545,12 +545,12 @@ static void commit_nsset(struct nsset *nsset) + + SYSCALL_DEFINE2(setns, int, fd, int, flags) + { +- struct fd f = fdget(fd); ++ CLASS(fd, f)(fd); + struct ns_common *ns = NULL; + struct nsset nsset = {}; + int err = 0; + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + + if (proc_ns_file(fd_file(f))) { +@@ -580,7 +580,6 @@ SYSCALL_DEFINE2(setns, int, fd, int, flags) + } + put_nsset(&nsset); + out: +- fdput(f); + return err; + } + +diff --git a/kernel/pid.c b/kernel/pid.c +index b80c3bfb58d07..c5650ea80a2b7 100644 +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -536,11 +536,10 @@ EXPORT_SYMBOL_GPL(find_ge_pid); + + struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags) + { +- struct fd f; ++ CLASS(fd, f)(fd); + struct pid *pid; + +- f = fdget(fd); +- if (!fd_file(f)) ++ if (fd_empty(f)) + return ERR_PTR(-EBADF); + + pid = pidfd_pid(fd_file(f)); +@@ -548,8 +547,6 @@ struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags) + get_pid(pid); + *flags = fd_file(f)->f_flags; + } +- +- fdput(f); + return pid; + } + +diff --git a/kernel/sys.c b/kernel/sys.c +index 35990f0796bca..8283e35c9eeb5 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -1929,12 +1929,11 @@ SYSCALL_DEFINE1(umask, int, mask) + + static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) + { +- struct fd exe; ++ CLASS(fd, exe)(fd); + struct inode *inode; + int err; + +- exe = fdget(fd); +- if (!fd_file(exe)) ++ if (fd_empty(exe)) + return -EBADF; + + inode = file_inode(fd_file(exe)); +@@ -1944,18 +1943,14 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) + * sure that this one is executable as well, to avoid breaking an + * overall picture. + */ +- err = -EACCES; + if (!S_ISREG(inode->i_mode) || path_noexec(&fd_file(exe)->f_path)) +- goto exit; ++ return -EACCES; + + err = file_permission(fd_file(exe), MAY_EXEC); + if (err) +- goto exit; ++ return err; + +- err = replace_mm_exe_file(mm, fd_file(exe)); +-exit: +- fdput(exe); +- return err; ++ return replace_mm_exe_file(mm, fd_file(exe)); + } + + /* +diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c +index e55f9810b91ad..6d1936fb8ff02 100644 +--- a/kernel/watch_queue.c ++++ b/kernel/watch_queue.c +@@ -672,16 +672,14 @@ struct watch_queue *get_watch_queue(int fd) + { + struct pipe_inode_info *pipe; + struct watch_queue *wqueue = ERR_PTR(-EINVAL); +- struct fd f; ++ CLASS(fd, f)(fd); + +- f = fdget(fd); +- if (fd_file(f)) { ++ if (!fd_empty(f)) { + pipe = get_pipe_info(fd_file(f), false); + if (pipe && pipe->watch_queue) { + wqueue = pipe->watch_queue; + kref_get(&wqueue->usage); + } +- fdput(f); + } + + return wqueue; +diff --git a/mm/fadvise.c b/mm/fadvise.c +index 532dee205c6e7..588fe76c5a142 100644 +--- a/mm/fadvise.c ++++ b/mm/fadvise.c +@@ -190,16 +190,12 @@ EXPORT_SYMBOL(vfs_fadvise); + + int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) + { +- struct fd f = fdget(fd); +- int ret; ++ CLASS(fd, f)(fd); + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + +- ret = vfs_fadvise(fd_file(f), offset, len, advice); +- +- fdput(f); +- return ret; ++ return vfs_fadvise(fd_file(f), offset, len, advice); + } + + SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice) +diff --git a/mm/readahead.c b/mm/readahead.c +index bf79275060f3b..32f57d0db9ac3 100644 +--- a/mm/readahead.c ++++ b/mm/readahead.c +@@ -676,29 +676,22 @@ EXPORT_SYMBOL_GPL(page_cache_async_ra); + + ssize_t ksys_readahead(int fd, loff_t offset, size_t count) + { +- ssize_t ret; +- struct fd f; ++ CLASS(fd, f)(fd); + +- ret = -EBADF; +- f = fdget(fd); +- if (!fd_file(f) || !(fd_file(f)->f_mode & FMODE_READ)) +- goto out; ++ if (fd_empty(f) || !(fd_file(f)->f_mode & FMODE_READ)) ++ return -EBADF; + + /* + * The readahead() syscall is intended to run only on files + * that can execute readahead. If readahead is not possible + * on this file, then we must return -EINVAL. + */ +- ret = -EINVAL; + if (!fd_file(f)->f_mapping || !fd_file(f)->f_mapping->a_ops || + (!S_ISREG(file_inode(fd_file(f))->i_mode) && + !S_ISBLK(file_inode(fd_file(f))->i_mode))) +- goto out; ++ return -EINVAL; + +- ret = vfs_fadvise(fd_file(f), offset, count, POSIX_FADV_WILLNEED); +-out: +- fdput(f); +- return ret; ++ return vfs_fadvise(fd_file(f), offset, count, POSIX_FADV_WILLNEED); + } + + SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count) +diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c +index ee3c1b37d06c1..bb4ae3864ad25 100644 +--- a/net/core/net_namespace.c ++++ b/net/core/net_namespace.c +@@ -712,20 +712,18 @@ EXPORT_SYMBOL_GPL(get_net_ns); + + struct net *get_net_ns_by_fd(int fd) + { +- struct fd f = fdget(fd); +- struct net *net = ERR_PTR(-EINVAL); ++ CLASS(fd, f)(fd); + +- if (!fd_file(f)) ++ if (fd_empty(f)) + return ERR_PTR(-EBADF); + + if (proc_ns_file(fd_file(f))) { + struct ns_common *ns = get_proc_ns(file_inode(fd_file(f))); + if (ns->ops == &netns_operations) +- net = get_net(container_of(ns, struct net, ns)); ++ return get_net(container_of(ns, struct net, ns)); + } +- fdput(f); + +- return net; ++ return ERR_PTR(-EINVAL); + } + EXPORT_SYMBOL_GPL(get_net_ns_by_fd); + #endif +diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c +index 4fa2d09f657ae..25f9f3e0d3971 100644 +--- a/security/landlock/syscalls.c ++++ b/security/landlock/syscalls.c +@@ -255,31 +255,21 @@ const int landlock_abi_version = LANDLOCK_ABI_VERSION; + static struct landlock_ruleset *get_ruleset_from_fd(const int fd, + const fmode_t mode) + { +- struct fd ruleset_f; ++ CLASS(fd, ruleset_f)(fd); + struct landlock_ruleset *ruleset; + +- ruleset_f = fdget(fd); +- if (!fd_file(ruleset_f)) ++ if (fd_empty(ruleset_f)) + return ERR_PTR(-EBADF); + + /* Checks FD type and access right. */ +- if (fd_file(ruleset_f)->f_op != &ruleset_fops) { +- ruleset = ERR_PTR(-EBADFD); +- goto out_fdput; +- } +- if (!(fd_file(ruleset_f)->f_mode & mode)) { +- ruleset = ERR_PTR(-EPERM); +- goto out_fdput; +- } ++ if (fd_file(ruleset_f)->f_op != &ruleset_fops) ++ return ERR_PTR(-EBADFD); ++ if (!(fd_file(ruleset_f)->f_mode & mode)) ++ return ERR_PTR(-EPERM); + ruleset = fd_file(ruleset_f)->private_data; +- if (WARN_ON_ONCE(ruleset->num_layers != 1)) { +- ruleset = ERR_PTR(-EINVAL); +- goto out_fdput; +- } ++ if (WARN_ON_ONCE(ruleset->num_layers != 1)) ++ return ERR_PTR(-EINVAL); + landlock_get_ruleset(ruleset); +- +-out_fdput: +- fdput(ruleset_f); + return ruleset; + } + +diff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c +index 388ae471d2584..53262b8a76564 100644 +--- a/virt/kvm/vfio.c ++++ b/virt/kvm/vfio.c +@@ -190,11 +190,10 @@ static int kvm_vfio_file_del(struct kvm_device *dev, unsigned int fd) + { + struct kvm_vfio *kv = dev->private; + struct kvm_vfio_file *kvf; +- struct fd f; ++ CLASS(fd, f)(fd); + int ret; + +- f = fdget(fd); +- if (!fd_file(f)) ++ if (fd_empty(f)) + return -EBADF; + + ret = -ENOENT; +@@ -220,9 +219,6 @@ static int kvm_vfio_file_del(struct kvm_device *dev, unsigned int fd) + kvm_vfio_update_coherency(dev); + + mutex_unlock(&kv->lock); +- +- fdput(f); +- + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.12/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch b/queue-6.12/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch new file mode 100644 index 0000000000..1524027729 --- /dev/null +++ b/queue-6.12/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch @@ -0,0 +1,39 @@ +From 1c2bdf1d43a353ddb05989849dcb726f81cd6214 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 11:39:39 +0000 +Subject: firmware: arm_ffa: Use the correct buffer size during RXTX_MAP + +From: Sebastian Ene + +[ Upstream commit 83210251fd70d5f96bcdc8911e15f7411a6b2463 ] + +Don't use the discovered buffer size from an FFA_FEATURES call directly +since we can run on a system that has the PAGE_SIZE larger than the +returned size which makes the alloc_pages_exact for the buffer to be +rounded up. + +Fixes: 61824feae5c0 ("firmware: arm_ffa: Fetch the Rx/Tx buffer size using ffa_features()") +Signed-off-by: Sebastian Ene +Link: https://patch.msgid.link/20260402113939.930221-1-sebastianene@google.com +Signed-off-by: Sudeep Holla +Signed-off-by: Sasha Levin +--- + drivers/firmware/arm_ffa/driver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index bec1fbaff7f34..15e71a53956e2 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -1804,7 +1804,7 @@ static int __init ffa_init(void) + + ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), + virt_to_phys(drv_info->rx_buffer), +- rxtx_bufsz / FFA_PAGE_SIZE); ++ PAGE_ALIGN(rxtx_bufsz) / FFA_PAGE_SIZE); + if (ret) { + pr_err("failed to register FFA RxTx buffers\n"); + goto free_pages; +-- +2.53.0 + diff --git a/queue-6.12/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch b/queue-6.12/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch new file mode 100644 index 0000000000..afef61d283 --- /dev/null +++ b/queue-6.12/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch @@ -0,0 +1,63 @@ +From ffdabe0aa2d97dd911b9fac6b683c3290dd90d1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 08:10:20 -0600 +Subject: firmware: dmi: Correct an indexing error in dmi.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit c064abc68e009d2cc18416e7132d9c25e03125b6 ] + +The entries later in enum dmi_entry_type don't match the SMBIOS +specification¹. + +The entry for type 33: `64-Bit Memory Error Information` is not present and +thus the index for all later entries is incorrect. + +Add it. + +Also, add missing entry types 43-46, while at it. + + ¹ Search for "System Management BIOS (SMBIOS) Reference Specification" + + [ bp: Drop the flaky SMBIOS spec URL. ] + +Fixes: 93c890dbe5287 ("firmware: Add DMI entry types to the headers") +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Jean Delvare +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20260307141024.819807-2-superm1@kernel.org +Signed-off-by: Sasha Levin +--- + include/linux/dmi.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/dmi.h b/include/linux/dmi.h +index 927f8a8b7a1dd..2eedf44e68012 100644 +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -60,6 +60,7 @@ enum dmi_entry_type { + DMI_ENTRY_OOB_REMOTE_ACCESS, + DMI_ENTRY_BIS_ENTRY, + DMI_ENTRY_SYSTEM_BOOT, ++ DMI_ENTRY_64_MEM_ERROR, + DMI_ENTRY_MGMT_DEV, + DMI_ENTRY_MGMT_DEV_COMPONENT, + DMI_ENTRY_MGMT_DEV_THRES, +@@ -69,6 +70,10 @@ enum dmi_entry_type { + DMI_ENTRY_ADDITIONAL, + DMI_ENTRY_ONBOARD_DEV_EXT, + DMI_ENTRY_MGMT_CONTROLLER_HOST, ++ DMI_ENTRY_TPM_DEVICE, ++ DMI_ENTRY_PROCESSOR_ADDITIONAL, ++ DMI_ENTRY_FIRMWARE_INVENTORY, ++ DMI_ENTRY_STRING_PROPERTY, + DMI_ENTRY_INACTIVE = 126, + DMI_ENTRY_END_OF_TABLE = 127, + }; +-- +2.53.0 + diff --git a/queue-6.12/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch b/queue-6.12/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch new file mode 100644 index 0000000000..7f8b60723c --- /dev/null +++ b/queue-6.12/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch @@ -0,0 +1,48 @@ +From 509bfc4c39f5e5b1cd6c87ae77639fc7b4fa2657 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 13:45:02 +0900 +Subject: fs/adfs: validate nzones in adfs_validate_bblk() + +From: Bae Yeonju + +[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ] + +Reject ADFS disc records with a zero zone count during boot block +validation, before the disc record is used. + +When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) +which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to +dm[-1], causing an out-of-bounds write before the allocated buffer. + +adfs_validate_dr0() already rejects nzones != 1 for old-format +images. Add the equivalent check to adfs_validate_bblk() for +new-format images so that a crafted image with nzones == 0 is +rejected at probe time. + +Found by syzkaller. + +Fixes: f6f14a0d71b0 ("fs/adfs: map: move map-specific sb initialisation to map.c") +Signed-off-by: Bae Yeonju +Signed-off-by: Russell King (Oracle) +Signed-off-by: Sasha Levin +--- + fs/adfs/super.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/adfs/super.c b/fs/adfs/super.c +index f0b999a4961b2..998ea8a2f8337 100644 +--- a/fs/adfs/super.c ++++ b/fs/adfs/super.c +@@ -343,6 +343,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, + if (adfs_checkdiscrecord(dr)) + return -EILSEQ; + ++ if ((dr->nzones | dr->nzones_high << 8) == 0) ++ return -EILSEQ; ++ + *drp = dr; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch b/queue-6.12/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch new file mode 100644 index 0000000000..a6e0c6754e --- /dev/null +++ b/queue-6.12/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch @@ -0,0 +1,49 @@ +From 2c63106a91cbe7a6ec3210603c02beb4713e5780 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:45:56 +0900 +Subject: fs/mbcache: cancel shrink work before destroying the cache + +From: HyungJung Joo + +[ Upstream commit d227786ab1119669df4dc333a61510c52047cce4 ] + +mb_cache_destroy() calls shrinker_free() and then frees all cache +entries and the cache itself, but it does not cancel the pending +c_shrink_work work item first. + +If mb_cache_entry_create() schedules c_shrink_work via schedule_work() +and the work item is still pending or running when mb_cache_destroy() +runs, mb_cache_shrink_worker() will access the cache after its memory +has been freed, causing a use-after-free. + +This is only reachable by a privileged user (root or CAP_SYS_ADMIN) +who can trigger the last put of a mounted ext2/ext4/ocfs2 filesystem. + +Cancel the work item with cancel_work_sync() before calling +shrinker_free(), ensuring the worker has finished and will not be +rescheduled before the cache is torn down. + +Fixes: c2f3140fe2ec ("mbcache2: limit cache size") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054556.1821600-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/mbcache.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/mbcache.c b/fs/mbcache.c +index e60a840999aa9..90b0564c62d0b 100644 +--- a/fs/mbcache.c ++++ b/fs/mbcache.c +@@ -408,6 +408,7 @@ void mb_cache_destroy(struct mb_cache *cache) + { + struct mb_cache_entry *entry, *next; + ++ cancel_work_sync(&cache->c_shrink_work); + shrinker_free(cache->c_shrink); + + /* +-- +2.53.0 + diff --git a/queue-6.12/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch b/queue-6.12/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch new file mode 100644 index 0000000000..6ebac136b6 --- /dev/null +++ b/queue-6.12/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch @@ -0,0 +1,51 @@ +From 5bb6920ab08d2328293102e0d2e51c213d078519 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:19:55 +0800 +Subject: fs/ntfs3: terminate the cached volume label after UTF-8 conversion + +From: Pengpeng Hou + +[ Upstream commit a6cd43fe9b083fa23fe1595666d5738856cb261a ] + +ntfs_fill_super() loads the on-disk volume label with utf16s_to_utf8s() +and stores the result in sbi->volume.label. The converted label is later +exposed through ntfs3_label_show() using %s, but utf16s_to_utf8s() only +returns the number of bytes written and does not add a trailing NUL. + +If the converted label fills the entire fixed buffer, +ntfs3_label_show() can read past the end of sbi->volume.label while +looking for a terminator. + +Terminate the cached label explicitly after a successful conversion and +clamp the exact-full case to the last byte of the buffer. + +Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") +Signed-off-by: Pengpeng Hou +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 89d126c155c7d..1af1500ec24b6 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1235,8 +1235,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + le32_to_cpu(attr->res.data_size) >> 1, + UTF16_LITTLE_ENDIAN, sbi->volume.label, + sizeof(sbi->volume.label)); +- if (err < 0) ++ if (err < 0) { + sbi->volume.label[0] = 0; ++ } else if (err >= sizeof(sbi->volume.label)) { ++ sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0; ++ } else { ++ sbi->volume.label[err] = 0; ++ } + } else { + /* Should we break mounting here? */ + //err = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.12/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch b/queue-6.12/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch new file mode 100644 index 0000000000..24e7e60fac --- /dev/null +++ b/queue-6.12/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch @@ -0,0 +1,55 @@ +From a62577ba1b544aafd44fd7755d1db6c7290ff042 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:48:27 +0900 +Subject: fs/omfs: reject s_sys_blocksize smaller than OMFS_DIR_START + +From: HyungJung Joo + +[ Upstream commit 0621c385fda1376e967f37ccd534c26c3e511d14 ] + +omfs_fill_super() rejects oversized s_sys_blocksize values (> PAGE_SIZE), +but it does not reject values smaller than OMFS_DIR_START (0x1b8 = 440). + +Later, omfs_make_empty() uses + + sbi->s_sys_blocksize - OMFS_DIR_START + +as the length argument to memset(). Since s_sys_blocksize is u32, +a crafted filesystem image with s_sys_blocksize < OMFS_DIR_START causes +an unsigned underflow there, wrapping to a value near 2^32. That drives +a ~4 GiB memset() from bh->b_data + OMFS_DIR_START and overwrites kernel +memory far beyond the backing block buffer. + +Add the corresponding lower-bound check alongside the existing upper-bound +check in omfs_fill_super(), so that malformed images are rejected during +superblock validation before any filesystem data is processed. + +Fixes: a3ab7155ea21 ("omfs: add directory routines") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054827.1822061-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/omfs/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c +index d6cd811630309..eb5a5fb26a791 100644 +--- a/fs/omfs/inode.c ++++ b/fs/omfs/inode.c +@@ -512,6 +512,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) + goto out_brelse_bh; + } + ++ if (sbi->s_sys_blocksize < OMFS_DIR_START) { ++ printk(KERN_ERR "omfs: sysblock size (%d) is too small\n", ++ sbi->s_sys_blocksize); ++ goto out_brelse_bh; ++ } ++ + if (sbi->s_blocksize < sbi->s_sys_blocksize || + sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { + printk(KERN_ERR "omfs: block size (%d) is out of range\n", +-- +2.53.0 + diff --git a/queue-6.12/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch b/queue-6.12/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch new file mode 100644 index 0000000000..7be194e000 --- /dev/null +++ b/queue-6.12/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch @@ -0,0 +1,151 @@ +From 9b1c29504696e2d1401a6760a56a28e440b3646f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 14:58:00 +0200 +Subject: fsnotify: fix inode reference leak in fsnotify_recalc_mask() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Amir Goldstein + +[ Upstream commit 4aca914ac152f5d055ddcb36704d1e539ac08977 ] + +fsnotify_recalc_mask() fails to handle the return value of +__fsnotify_recalc_mask(), which may return an inode pointer that needs +to be released via fsnotify_drop_object() when the connector's HAS_IREF +flag transitions from set to cleared. + +This manifests as a hung task with the following call trace: + + INFO: task umount:1234 blocked for more than 120 seconds. + Call Trace: + __schedule + schedule + fsnotify_sb_delete + generic_shutdown_super + kill_anon_super + cleanup_mnt + task_work_run + do_exit + do_group_exit + +The race window that triggers the iref leak: + + Thread A (adding mark) Thread B (removing mark) + ────────────────────── ──────────────────────── + fsnotify_add_mark_locked(): + fsnotify_add_mark_list(): + spin_lock(conn->lock) + add mark_B(evictable) to list + spin_unlock(conn->lock) + return + + /* ---- gap: no lock held ---- */ + + fsnotify_detach_mark(mark_A): + spin_lock(mark_A->lock) + clear ATTACHED flag on mark_A + spin_unlock(mark_A->lock) + fsnotify_put_mark(mark_A) + + fsnotify_recalc_mask(): + spin_lock(conn->lock) + __fsnotify_recalc_mask(): + /* mark_A skipped: ATTACHED cleared */ + /* only mark_B(evictable) remains */ + want_iref = false + has_iref = true /* not yet cleared */ + -> HAS_IREF transitions true -> false + -> returns inode pointer + spin_unlock(conn->lock) + /* BUG: return value discarded! + * iput() and fsnotify_put_sb_watched_objects() + * are never called */ + +Fix this by deferring the transition true -> false of HAS_IREF flag from +fsnotify_recalc_mask() (Thread A) to fsnotify_put_mark() (thread B). + +Fixes: c3638b5b1374 ("fsnotify: allow adding an inode mark without pinning inode") +Signed-off-by: Xin Yin +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/CAOQ4uxiPsbHb0o5voUKyPFMvBsDkG914FYDcs4C5UpBMNm0Vcg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/notify/mark.c | 39 ++++++++++++++++++++++++++++++++++++--- + 1 file changed, 36 insertions(+), 3 deletions(-) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 09e50fe5757c4..a263305ed7c85 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -233,7 +233,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn, + return inode; + } + +-static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) ++/* ++ * Calculate mask of events for a list of marks. ++ * ++ * Return true if any of the attached marks want to hold an inode reference. ++ */ ++static bool __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + { + u32 new_mask = 0; + bool want_iref = false; +@@ -257,6 +262,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + */ + WRITE_ONCE(*fsnotify_conn_mask_p(conn), new_mask); + ++ return want_iref; ++} ++ ++/* ++ * Calculate mask of events for a list of marks after attach/modify mark ++ * and get an inode reference for the connector if needed. ++ * ++ * A concurrent add of evictable mark and detach of non-evictable mark can ++ * lead to __fsnotify_recalc_mask() returning false want_iref, but in this ++ * case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called ++ * from fsnotify_put_mark(). ++ */ ++static void fsnotify_recalc_mask_set_iref(struct fsnotify_mark_connector *conn) ++{ ++ bool has_iref = conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF; ++ bool want_iref = __fsnotify_recalc_mask(conn) || has_iref; ++ ++ (void) fsnotify_update_iref(conn, want_iref); ++} ++ ++/* ++ * Calculate mask of events for a list of marks after detach mark ++ * and return the inode object if its reference is no longer needed. ++ */ ++static void *fsnotify_recalc_mask_clear_iref(struct fsnotify_mark_connector *conn) ++{ ++ bool want_iref = __fsnotify_recalc_mask(conn); ++ + return fsnotify_update_iref(conn, want_iref); + } + +@@ -293,7 +326,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + + spin_lock(&conn->lock); + update_children = !fsnotify_conn_watches_children(conn); +- __fsnotify_recalc_mask(conn); ++ fsnotify_recalc_mask_set_iref(conn); + update_children &= fsnotify_conn_watches_children(conn); + spin_unlock(&conn->lock); + /* +@@ -408,7 +441,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) + /* Update watched objects after detaching mark */ + if (sb) + fsnotify_update_sb_watchers(sb, conn); +- objp = __fsnotify_recalc_mask(conn); ++ objp = fsnotify_recalc_mask_clear_iref(conn); + type = conn->type; + } + WRITE_ONCE(mark->connector, NULL); +-- +2.53.0 + diff --git a/queue-6.12/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch b/queue-6.12/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch new file mode 100644 index 0000000000..c891a169a4 --- /dev/null +++ b/queue-6.12/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch @@ -0,0 +1,100 @@ +From 1d5c7bc3f383b2d3fe792d8d3f98752dcc86e38c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:34:25 +0200 +Subject: futex: Prevent lockup in requeue-PI during signal/ timeout wakeup + +From: Sebastian Andrzej Siewior + +[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ] + +During wait-requeue-pi (task A) and requeue-PI (task B) the following +race can happen: + + Task A Task B + futex_wait_requeue_pi() + futex_setup_timer() + futex_do_wait() + futex_requeue() + CLASS(hb, hb1)(&key1); + CLASS(hb, hb2)(&key2); + *timeout* + futex_requeue_pi_wakeup_sync() + requeue_state = Q_REQUEUE_PI_IGNORE + + *blocks on hb->lock* + + futex_proxy_trylock_atomic() + futex_requeue_pi_prepare() + Q_REQUEUE_PI_IGNORE => -EAGAIN + double_unlock_hb(hb1, hb2) + *retry* + +Task B acquires both hb locks and attempts to acquire the PI-lock of the +top most waiter (task B). Task A is leaving early due to a signal/ +timeout and started removing itself from the queue. It updates its +requeue_state but can not remove it from the list because this requires +the hb lock which is owned by task B. + +Usually task A is able to swoop the lock after task B unlocked it. +However if task B is of higher priority then task A may not be able to +wake up in time and acquire the lock before task B gets it again. +Especially on a UP system where A is never scheduled. + +As a result task A blocks on the lock and task B busy loops, trying to +make progress but live locks the system instead. Tragic. + +This can be fixed by removing the top most waiter from the list in this +case. This allows task B to grab the next top waiter (if any) in the +next iteration and make progress. + +Remove the top most waiter if futex_requeue_pi_prepare() fails. +Let the waiter conditionally remove itself from the list in +handle_early_requeue_pi_wakeup(). + +Fixes: 07d91ef510fb1 ("futex: Prevent requeue_pi() lock nesting issue on RT") +Reported-by: Moritz Klammler +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260428103425.dywXyPd3@linutronix.de +Closes: https://lore.kernel.org/all/VE1PR06MB6894BE61C173D802365BE19DFF4CA@VE1PR06MB6894.eurprd06.prod.outlook.com +Signed-off-by: Sasha Levin +--- + kernel/futex/requeue.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c +index 559aae55792c6..f4a69942780f6 100644 +--- a/kernel/futex/requeue.c ++++ b/kernel/futex/requeue.c +@@ -309,8 +309,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, + return -EINVAL; + + /* Ensure that this does not race against an early wakeup */ +- if (!futex_requeue_pi_prepare(top_waiter, NULL)) ++ if (!futex_requeue_pi_prepare(top_waiter, NULL)) { ++ plist_del(&top_waiter->list, &hb1->chain); ++ futex_hb_waiters_dec(hb1); + return -EAGAIN; ++ } + + /* + * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit +@@ -711,10 +714,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, + + /* + * We were woken prior to requeue by a timeout or a signal. +- * Unqueue the futex_q and determine which it was. ++ * Conditionally unqueue the futex_q and determine which it was. + */ +- plist_del(&q->list, &hb->chain); +- futex_hb_waiters_dec(hb); ++ if (!plist_node_empty(&q->list)) { ++ plist_del(&q->list, &hb->chain); ++ futex_hb_waiters_dec(hb); ++ } + + /* Handle spurious wakeups gracefully */ + ret = -EWOULDBLOCK; +-- +2.53.0 + diff --git a/queue-6.12/gfs2-add-some-missing-log-locking.patch b/queue-6.12/gfs2-add-some-missing-log-locking.patch new file mode 100644 index 0000000000..96e3bdf2ab --- /dev/null +++ b/queue-6.12/gfs2-add-some-missing-log-locking.patch @@ -0,0 +1,109 @@ +From 30b51e69d1388ceb6162ba1b4d9c11467c942dc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 06:13:42 +0200 +Subject: gfs2: add some missing log locking + +From: Andreas Gruenbacher + +[ Upstream commit fe2c8d051150b90b3ccb85f89e3b1d636cb88ec8 ] + +Function gfs2_logd() calls the log flushing functions gfs2_ail1_start(), +gfs2_ail1_wait(), and gfs2_ail1_empty() without holding sdp->sd_log_flush_lock, +but these functions require exclusion against concurrent transactions. + +To fix that, add a non-locking __gfs2_log_flush() function. Then, in +gfs2_logd(), take sdp->sd_log_flush_lock before calling the above mentioned log +flushing functions and __gfs2_log_flush(). + +Fixes: 5e4c7632aae1c ("gfs2: Issue revokes more intelligently") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 115c4ac457e90..592f69602e5aa 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -1027,14 +1027,15 @@ static void trans_drain(struct gfs2_trans *tr) + } + + /** +- * gfs2_log_flush - flush incore transaction(s) ++ * __gfs2_log_flush - flush incore transaction(s) + * @sdp: The filesystem + * @gl: The glock structure to flush. If NULL, flush the whole incore log + * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags + * + */ + +-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ++ u32 flags) + { + struct gfs2_trans *tr = NULL; + unsigned int reserved_blocks = 0, used_blocks = 0; +@@ -1042,7 +1043,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + unsigned int first_log_head; + unsigned int reserved_revokes = 0; + +- down_write(&sdp->sd_log_flush_lock); + trace_gfs2_log_flush(sdp, 1, flags); + + repeat: +@@ -1154,7 +1154,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + gfs2_assert_withdraw_delayed(sdp, used_blocks < reserved_blocks); + gfs2_log_release(sdp, reserved_blocks - used_blocks); + } +- up_write(&sdp->sd_log_flush_lock); + gfs2_trans_free(sdp, tr); + if (gfs2_withdrawing(sdp)) + gfs2_withdraw(sdp); +@@ -1177,6 +1176,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + goto out_end; + } + ++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++{ ++ down_write(&sdp->sd_log_flush_lock); ++ __gfs2_log_flush(sdp, gl, flags); ++ up_write(&sdp->sd_log_flush_lock); ++} ++ + /** + * gfs2_merge_trans - Merge a new transaction into a cached transaction + * @sdp: the filesystem +@@ -1319,19 +1325,25 @@ int gfs2_logd(void *data) + } + + if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_JFLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_JFLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) || + gfs2_ail_flush_reqd(sdp)) { + clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_start(sdp); + gfs2_ail1_wait(sdp); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; +-- +2.53.0 + diff --git a/queue-6.12/gfs2-call-unlock_new_inode-before-d_instantiate.patch b/queue-6.12/gfs2-call-unlock_new_inode-before-d_instantiate.patch new file mode 100644 index 0000000000..a8d49edfb7 --- /dev/null +++ b/queue-6.12/gfs2-call-unlock_new_inode-before-d_instantiate.patch @@ -0,0 +1,48 @@ +From 021fb48e5ff53106eba2cf30c9284afbc7fbad8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:04:05 +0100 +Subject: gfs2: Call unlock_new_inode before d_instantiate + +From: Andreas Gruenbacher + +[ Upstream commit 2ff7cf7e0640ff071ebc5c7e3dc2df024a7c91e6 ] + +As Neil Brown describes in detail in the link referenced below, new +inodes must be unlocked before they can be instantiated. + +An even better fix is to use d_instantiate_new(), which combines +d_instantiate() and unlock_new_inode(). + +Fixes: 3d36e57ff768 ("gfs2: gfs2_create_inode rework") +Reported-by: syzbot+0ea5108a1f5fb4fcc2d8@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-fsdevel/177153754005.8396.8777398743501764194@noble.neil.brown.name/ +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/inode.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index c37079718fdd5..e6fe1a95d9304 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -893,7 +893,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + goto fail_gunlock4; + + mark_inode_dirty(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + /* After instantiate, errors should result in evict which will destroy + * both inode and iopen glocks properly. */ + if (file) { +@@ -905,7 +905,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + gfs2_glock_dq_uninit(&gh); + gfs2_glock_put(io_gl); + gfs2_qa_put(dip); +- unlock_new_inode(inode); + return error; + + fail_gunlock4: +-- +2.53.0 + diff --git a/queue-6.12/gfs2-prevent-null-pointer-dereference-during-unmount.patch b/queue-6.12/gfs2-prevent-null-pointer-dereference-during-unmount.patch new file mode 100644 index 0000000000..e8f136d85d --- /dev/null +++ b/queue-6.12/gfs2-prevent-null-pointer-dereference-during-unmount.patch @@ -0,0 +1,44 @@ +From eee6a3b6328123d573caaa7ab3bbf81c8cfc8dee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 12:14:30 +0200 +Subject: gfs2: prevent NULL pointer dereference during unmount + +From: Andreas Gruenbacher + +[ Upstream commit 74b4dbb946060a3233604d91859a9abd3708141d ] + +When flushing out outstanding glock work during an unmount, gfs2_log_flush() +can be called when sdp->sd_jdesc has already been deallocated and sdp->sd_jdesc +is NULL. Commit 35264909e9d1 ("gfs2: Fix NULL pointer dereference in +gfs2_log_flush") added a check for that to gfs2_log_flush() itself, but it +missed the sdp->sd_jdesc dereference in gfs2_log_release(). Fix that. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202604071139.HNJiCaAi-lkp@intel.com/ +Fixes: 35264909e9d1 ("gfs2: Fix NULL pointer dereference in gfs2_log_flush") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 592f69602e5aa..ecc5c59b87008 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -471,8 +471,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) + { + atomic_add(blks, &sdp->sd_log_blks_free); + trace_gfs2_log_blocks(sdp, blks); +- gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= +- sdp->sd_jdesc->jd_blocks); ++ gfs2_assert_withdraw(sdp, !sdp->sd_jdesc || ++ atomic_read(&sdp->sd_log_blks_free) <= ++ sdp->sd_jdesc->jd_blocks); + if (atomic_read(&sdp->sd_log_blks_needed)) + wake_up(&sdp->sd_log_waitq); + } +-- +2.53.0 + diff --git a/queue-6.12/hid-asus-do-not-abort-probe-when-not-necessary.patch b/queue-6.12/hid-asus-do-not-abort-probe-when-not-necessary.patch new file mode 100644 index 0000000000..1523bb9810 --- /dev/null +++ b/queue-6.12/hid-asus-do-not-abort-probe-when-not-necessary.patch @@ -0,0 +1,65 @@ +From 5d07fa95f61475c36a64314b9fdb791d4401da67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:09 +0100 +Subject: HID: asus: do not abort probe when not necessary + +From: Denis Benato + +[ Upstream commit 7253091766ded0fd81fe8d8be9b8b835495b06e8 ] + +In order to avoid dereferencing a NULL pointer asus_probe is aborted early +and control of some asus devices is transferred over hid-generic after +erroring out even when such NULL dereference cannot happen: only early +abort when the NULL dereference can happen. + +Also make the code shorter and more adherent to coding standards +removing square brackets enclosing single-line if-else statements. + +Fixes: d3af6ca9a8c3 ("HID: asus: fix UAF via HID_CLAIMED_INPUT validation") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index cba383ccfc74c..552a049c7d148 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1220,22 +1220,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + * were freed during registration due to no usages being mapped, + * leaving drvdata->input pointing to freed memory. + */ +- if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { +- hid_err(hdev, "Asus input not registered\n"); +- ret = -ENOMEM; +- goto err_stop_hw; +- } +- +- if (drvdata->tp) { +- drvdata->input->name = "Asus TouchPad"; +- } else { +- drvdata->input->name = "Asus Keyboard"; +- } ++ if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) { ++ if (drvdata->tp) ++ drvdata->input->name = "Asus TouchPad"; ++ else ++ drvdata->input->name = "Asus Keyboard"; + +- if (drvdata->tp) { +- ret = asus_start_multitouch(hdev); +- if (ret) +- goto err_stop_hw; ++ if (drvdata->tp) { ++ ret = asus_start_multitouch(hdev); ++ if (ret) ++ goto err_stop_hw; ++ } + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch b/queue-6.12/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch new file mode 100644 index 0000000000..68c87df485 --- /dev/null +++ b/queue-6.12/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch @@ -0,0 +1,37 @@ +From db3c0a95b9019822164f20c0ddec372703cc7446 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:07 +0100 +Subject: HID: asus: make asus_resume adhere to linux kernel coding standards + +From: Denis Benato + +[ Upstream commit 51d33b42b8ae23da92819d28439fdd5636c45186 ] + +Linux kernel coding standars requires functions opening brackets to be in +a newline: move the opening bracket of asus_resume in its own line. + +Fixes: 546edbd26cff ("HID: hid-asus: reset the backlight brightness level on resume") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index b2788bb0477f0..cba383ccfc74c 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1092,7 +1092,8 @@ static int asus_start_multitouch(struct hid_device *hdev) + return 0; + } + +-static int __maybe_unused asus_resume(struct hid_device *hdev) { ++static int __maybe_unused asus_resume(struct hid_device *hdev) ++{ + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + int ret = 0; + +-- +2.53.0 + diff --git a/queue-6.12/hid-usbhid-fix-deadlock-in-hid_post_reset.patch b/queue-6.12/hid-usbhid-fix-deadlock-in-hid_post_reset.patch new file mode 100644 index 0000000000..a18b269e5b --- /dev/null +++ b/queue-6.12/hid-usbhid-fix-deadlock-in-hid_post_reset.patch @@ -0,0 +1,42 @@ +From 579adff58b613dd88d9a76d158d23efff43ad1a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:24:54 +0100 +Subject: HID: usbhid: fix deadlock in hid_post_reset() + +From: Oliver Neukum + +[ Upstream commit 8df2c1b47ee3cd50fd454f75c7a7e2ae8a6adf72 ] + +You can build a USB device that includes a HID component +and a storage or UAS component. The components can be reset +only together. That means that hid_pre_reset() and hid_post_reset() +are in the block IO error handling. Hence no memory allocation +used in them may do block IO because the IO can deadlock +on the mutex held while resetting a device and calling the +interface drivers. +Use GFP_NOIO for all allocations in them. + +Fixes: dc3c78e434690 ("HID: usbhid: Check HID report descriptor contents after device reset") +Signed-off-by: Oliver Neukum +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index a2c5a31931f69..f14b46ce00cb6 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1552,7 +1552,7 @@ static int hid_post_reset(struct usb_interface *intf) + * configuration descriptors passed, we already know that + * the size of the HID report descriptor has not changed. + */ +- rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); ++ rdesc = kmalloc(hid->dev_rsize, GFP_NOIO); + if (!rdesc) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.12/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch b/queue-6.12/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch new file mode 100644 index 0000000000..b4329e8624 --- /dev/null +++ b/queue-6.12/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch @@ -0,0 +1,46 @@ +From 3e35ad2b3aac543e496ebec32851e96e1737a395 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:35:37 +0100 +Subject: hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns() + +From: Peter Zijlstra + +[ Upstream commit d19ff16c11db38f3ee179d72751fb9b340174330 ] + +Much like hrtimer_reprogram(), skip programming if the cpu_base is running +the hrtimer interrupt. + +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Juri Lelli +Reviewed-by: Thomas Gleixner +Link: https://patch.msgid.link/20260224163429.069535561@kernel.org +Stable-dep-of: f2e388a019e4 ("hrtimer: Reduce trace noise in hrtimer_start()") +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 6abd0d2807f5d..343c7e4008aba 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1279,6 +1279,14 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + } + + first = enqueue_hrtimer(timer, new_base, mode); ++ ++ /* ++ * If the hrtimer interrupt is running, then it will reevaluate the ++ * clock bases and reprogram the clock event device. ++ */ ++ if (new_base->cpu_base->in_hrtirq) ++ return false; ++ + if (!force_local) { + /* + * If the current CPU base is online, then the timer is +-- +2.53.0 + diff --git a/queue-6.12/hrtimer-reduce-trace-noise-in-hrtimer_start.patch b/queue-6.12/hrtimer-reduce-trace-noise-in-hrtimer_start.patch new file mode 100644 index 0000000000..bd0e9a32ae --- /dev/null +++ b/queue-6.12/hrtimer-reduce-trace-noise-in-hrtimer_start.patch @@ -0,0 +1,216 @@ +From 80bdb40ebf660f916f2578ace97ad770831e2539 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:36:59 +0100 +Subject: hrtimer: Reduce trace noise in hrtimer_start() + +From: Thomas Gleixner + +[ Upstream commit f2e388a019e4cf83a15883a3d1f1384298e9a6aa ] + +hrtimer_start() when invoked with an already armed timer traces like: + + -.. [032] d.h2. 5.002263: hrtimer_cancel: hrtimer= .... + -.. [032] d.h1. 5.002263: hrtimer_start: hrtimer= .... + +Which is incorrect as the timer doesn't get canceled. Just the expiry time +changes. The internal dequeue operation which is required for that is not +really interesting for trace analysis. But it makes it tedious to keep real +cancellations and the above case apart. + +Remove the cancel tracing in hrtimer_start() and add a 'was_armed' +indicator to the hrtimer start tracepoint, which clearly indicates what the +state of the hrtimer is when hrtimer_start() is invoked: + +-.. [032] d.h1. 6.200103: hrtimer_start: hrtimer= .... was_armed=0 + -.. [032] d.h1. 6.200558: hrtimer_start: hrtimer= .... was_armed=1 + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260224163430.208491877@kernel.org +Signed-off-by: Sasha Levin +--- + include/trace/events/timer.h | 11 +++++---- + kernel/time/hrtimer.c | 43 +++++++++++++++++------------------- + 2 files changed, 27 insertions(+), 27 deletions(-) + +diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h +index 1ef58a04fc579..19c975ffea176 100644 +--- a/include/trace/events/timer.h ++++ b/include/trace/events/timer.h +@@ -218,12 +218,13 @@ TRACE_EVENT(hrtimer_init, + * hrtimer_start - called when the hrtimer is started + * @hrtimer: pointer to struct hrtimer + * @mode: the hrtimers mode ++ * @was_armed: Was armed when hrtimer_start*() was invoked + */ + TRACE_EVENT(hrtimer_start, + +- TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode), ++ TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode, bool was_armed), + +- TP_ARGS(hrtimer, mode), ++ TP_ARGS(hrtimer, mode, was_armed), + + TP_STRUCT__entry( + __field( void *, hrtimer ) +@@ -231,6 +232,7 @@ TRACE_EVENT(hrtimer_start, + __field( s64, expires ) + __field( s64, softexpires ) + __field( enum hrtimer_mode, mode ) ++ __field( bool, was_armed ) + ), + + TP_fast_assign( +@@ -239,13 +241,14 @@ TRACE_EVENT(hrtimer_start, + __entry->expires = hrtimer_get_expires(hrtimer); + __entry->softexpires = hrtimer_get_softexpires(hrtimer); + __entry->mode = mode; ++ __entry->was_armed = was_armed; + ), + + TP_printk("hrtimer=%p function=%ps expires=%llu softexpires=%llu " +- "mode=%s", __entry->hrtimer, __entry->function, ++ "mode=%s was_armed=%d", __entry->hrtimer, __entry->function, + (unsigned long long) __entry->expires, + (unsigned long long) __entry->softexpires, +- decode_hrtimer_mode(__entry->mode)) ++ decode_hrtimer_mode(__entry->mode), __entry->was_armed) + ); + + /** +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 343c7e4008aba..5d1b880de171d 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -489,17 +489,10 @@ debug_init(struct hrtimer *timer, clockid_t clockid, + trace_hrtimer_init(timer, clockid, mode); + } + +-static inline void debug_activate(struct hrtimer *timer, +- enum hrtimer_mode mode) ++static inline void debug_activate(struct hrtimer *timer, enum hrtimer_mode mode, bool was_armed) + { + debug_hrtimer_activate(timer, mode); +- trace_hrtimer_start(timer, mode); +-} +- +-static inline void debug_deactivate(struct hrtimer *timer) +-{ +- debug_hrtimer_deactivate(timer); +- trace_hrtimer_cancel(timer); ++ trace_hrtimer_start(timer, mode, was_armed); + } + + static struct hrtimer_clock_base * +@@ -1094,9 +1087,9 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); + * Returns true when the new timer is the leftmost timer in the tree. + */ + static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, +- enum hrtimer_mode mode) ++ enum hrtimer_mode mode, bool was_armed) + { +- debug_activate(timer, mode); ++ debug_activate(timer, mode, was_armed); + WARN_ON_ONCE(!base->cpu_base->online); + + base->cpu_base->active_bases |= 1 << base->index; +@@ -1156,6 +1149,8 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + if (state & HRTIMER_STATE_ENQUEUED) { + bool reprogram; + ++ debug_hrtimer_deactivate(timer); ++ + /* + * Remove the timer and force reprogramming when high + * resolution mode is active and the timer is on the current +@@ -1164,7 +1159,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + * reprogramming happens in the interrupt handler. This is a + * rare case and less expensive than a smp call. + */ +- debug_deactivate(timer); + reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); + + /* +@@ -1231,15 +1225,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + { + struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); + struct hrtimer_clock_base *new_base; +- bool force_local, first; ++ bool force_local, first, was_armed; + + /* + * If the timer is on the local cpu base and is the first expiring + * timer then this might end up reprogramming the hardware twice +- * (on removal and on enqueue). To avoid that by prevent the +- * reprogram on removal, keep the timer local to the current CPU +- * and enforce reprogramming after it is queued no matter whether +- * it is the new first expiring timer again or not. ++ * (on removal and on enqueue). To avoid that prevent the reprogram ++ * on removal, keep the timer local to the current CPU and enforce ++ * reprogramming after it is queued no matter whether it is the new ++ * first expiring timer again or not. + */ + force_local = base->cpu_base == this_cpu_base; + force_local &= base->cpu_base->next_timer == timer; +@@ -1261,7 +1255,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + * avoids programming the underlying clock event twice (once at + * removal and once after enqueue). + */ +- remove_hrtimer(timer, base, true, force_local); ++ was_armed = remove_hrtimer(timer, base, true, force_local); + + if (mode & HRTIMER_MODE_REL) + tim = ktime_add_safe(tim, base->get_time()); +@@ -1278,7 +1272,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + new_base = base; + } + +- first = enqueue_hrtimer(timer, new_base, mode); ++ first = enqueue_hrtimer(timer, new_base, mode, was_armed); + + /* + * If the hrtimer interrupt is running, then it will reevaluate the +@@ -1382,8 +1376,11 @@ int hrtimer_try_to_cancel(struct hrtimer *timer) + + base = lock_hrtimer_base(timer, &flags); + +- if (!hrtimer_callback_running(timer)) ++ if (!hrtimer_callback_running(timer)) { + ret = remove_hrtimer(timer, base, false, false); ++ if (ret) ++ trace_hrtimer_cancel(timer); ++ } + + unlock_hrtimer_base(timer, &flags); + +@@ -1770,7 +1767,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + */ + if (restart != HRTIMER_NORESTART && + !(timer->state & HRTIMER_STATE_ENQUEUED)) +- enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, false); + + /* + * Separate the ->running assignment from the ->state assignment. +@@ -2252,7 +2249,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + while ((node = timerqueue_getnext(&old_base->active))) { + timer = container_of(node, struct hrtimer, node); + BUG_ON(hrtimer_callback_running(timer)); +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + + /* + * Mark it as ENQUEUED not INACTIVE otherwise the +@@ -2269,7 +2266,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + * sort out already expired timers and reprogram the + * event device. + */ +- enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, true); + } + } + +-- +2.53.0 + diff --git a/queue-6.12/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch b/queue-6.12/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch new file mode 100644 index 0000000000..d0a4d3547f --- /dev/null +++ b/queue-6.12/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch @@ -0,0 +1,49 @@ +From 162e9fc1fd5d113981c01138f5717163c1646313 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Dec 2024 15:57:03 +0800 +Subject: hrtimers: Update the return type of enqueue_hrtimer() + +From: Richard Clark + +[ Upstream commit da7100d3bf7d6f5c49ef493ea963766898e9b069 ] + +The return type should be 'bool' instead of 'int' according to the calling +context in the kernel, and its internal implementation, i.e. : + + return timerqueue_add(); + +which is a bool-return function. + +[ tglx: Adjust function arguments ] + +Signed-off-by: Richard Clark +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/all/Z2ppT7me13dtxm1a@MBC02GN1V4Q05P +Stable-dep-of: f2e388a019e4 ("hrtimer: Reduce trace noise in hrtimer_start()") +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 640d2ea4bd1fa..6abd0d2807f5d 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1091,11 +1091,10 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); + * The timer is inserted in expiry order. Insertion into the + * red black tree is O(log(n)). Must hold the base lock. + * +- * Returns 1 when the new timer is the leftmost timer in the tree. ++ * Returns true when the new timer is the leftmost timer in the tree. + */ +-static int enqueue_hrtimer(struct hrtimer *timer, +- struct hrtimer_clock_base *base, +- enum hrtimer_mode mode) ++static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, ++ enum hrtimer_mode mode) + { + debug_activate(timer, mode); + WARN_ON_ONCE(!base->cpu_base->online); +-- +2.53.0 + diff --git a/queue-6.12/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch b/queue-6.12/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch new file mode 100644 index 0000000000..1e06a1d9c0 --- /dev/null +++ b/queue-6.12/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch @@ -0,0 +1,47 @@ +From c4449757109f29ef7d9b089d4bc5bcdb4ca6dd1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 11:46:18 +0100 +Subject: hte: tegra194: remove Kconfig dependency on Tegra194 SoC + +From: Francesco Lavra + +[ Upstream commit 92dfd92f747698352b256cd9ddd7497bb7ebe9c8 ] + +This driver runs also on other Tegra SoCs (e.g. Tegra234). +Replace Kconfig dependency on Tegra194 with more generic dependency on +Tegra, and amend the Kconfig help text to reflect the fact that this +driver works on SoCs other than Tegra194. + +Fixes: b003fb5c9df8 ("hte: Add Tegra234 provider") +Signed-off-by: Francesco Lavra +Acked-by: Dipen Patel +Signed-off-by: Dipen Patel +Signed-off-by: Sasha Levin +--- + drivers/hte/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/hte/Kconfig b/drivers/hte/Kconfig +index 641af722b555d..f57bad67deef0 100644 +--- a/drivers/hte/Kconfig ++++ b/drivers/hte/Kconfig +@@ -16,13 +16,13 @@ if HTE + + config HTE_TEGRA194 + tristate "NVIDIA Tegra194 HTE Support" +- depends on (ARCH_TEGRA_194_SOC || COMPILE_TEST) ++ depends on (ARCH_TEGRA || COMPILE_TEST) + depends on GPIOLIB + help + Enable this option for integrated hardware timestamping engine also + known as generic timestamping engine (GTE) support on NVIDIA Tegra194 +- systems-on-chip. The driver supports 352 LIC IRQs and 39 AON GPIOs +- lines for timestamping in realtime. ++ and later systems-on-chip. The driver supports 352 LIC IRQs and 39 ++ AON GPIOs lines for timestamping in realtime. + + config HTE_TEGRA194_TEST + tristate "NVIDIA Tegra194 HTE Test" +-- +2.53.0 + diff --git a/queue-6.12/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch b/queue-6.12/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch new file mode 100644 index 0000000000..96b826e346 --- /dev/null +++ b/queue-6.12/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch @@ -0,0 +1,51 @@ +From b632de59f05cfa1915ad72ef639247d511ca793d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 10:33:24 +0800 +Subject: hwmon: (aspeed-g6-pwm-tach): remove redundant driver remove callback + +From: Billy Tsai + +[ Upstream commit 46fef8583daa1bf78fda7eaa523c64d4440322ac ] + +Drops the remove callback as it only asserts reset and the probe already +registers a devres action (devm_add_action_or_reset()) to call +aspeed_pwm_tach_reset_assert(). + +Fixes: 7e1449cd15d1 ("hwmon: (aspeed-g6-pwm-tacho): Support for ASPEED g6 PWM/Fan tach") +Signed-off-by: Billy Tsai +Link: https://lore.kernel.org/r/20260309-pwm_fixes-v2-1-ca9768e70470@aspeedtech.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/aspeed-g6-pwm-tach.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c +index 4174b129d1fce..d1f7f43974824 100644 +--- a/drivers/hwmon/aspeed-g6-pwm-tach.c ++++ b/drivers/hwmon/aspeed-g6-pwm-tach.c +@@ -517,13 +517,6 @@ static int aspeed_pwm_tach_probe(struct platform_device *pdev) + return 0; + } + +-static void aspeed_pwm_tach_remove(struct platform_device *pdev) +-{ +- struct aspeed_pwm_tach_data *priv = platform_get_drvdata(pdev); +- +- reset_control_assert(priv->reset); +-} +- + static const struct of_device_id aspeed_pwm_tach_match[] = { + { + .compatible = "aspeed,ast2600-pwm-tach", +@@ -534,7 +527,6 @@ MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); + + static struct platform_driver aspeed_pwm_tach_driver = { + .probe = aspeed_pwm_tach_probe, +- .remove = aspeed_pwm_tach_remove, + .driver = { + .name = "aspeed-g6-pwm-tach", + .of_match_table = aspeed_pwm_tach_match, +-- +2.53.0 + diff --git a/queue-6.12/hwmon-switch-back-to-struct-platform_driver-remove.patch b/queue-6.12/hwmon-switch-back-to-struct-platform_driver-remove.patch new file mode 100644 index 0000000000..92cdd0e67c --- /dev/null +++ b/queue-6.12/hwmon-switch-back-to-struct-platform_driver-remove.patch @@ -0,0 +1,398 @@ +From 61ced47e0c73bc2928f85377f1f23a539cbc18a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Oct 2024 17:59:01 +0200 +Subject: hwmon: Switch back to struct platform_driver::remove() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 6126f7bb6075d0af577e55bf7e2cbbcc272f520b ] + +After commit 0edb555a65d1 ("platform: Make platform_driver::remove() +return void") .remove() is (again) the right callback to implement for +platform drivers. + +Convert all platform drivers below drivers/hwmonto use .remove(), with +the eventual goal to drop struct platform_driver::remove_new(). As +.remove() and .remove_new() have the same prototypes, conversion is done +by just changing the structure member name in the driver initializer. + +While touching these files, make indention of the struct initializer +consistent in several files. + +Signed-off-by: Uwe Kleine-König +Message-ID: <20241017155900.137357-2-u.kleine-koenig@baylibre.com> +Signed-off-by: Guenter Roeck +Stable-dep-of: 46fef8583daa ("hwmon: (aspeed-g6-pwm-tach): remove redundant driver remove callback") +Signed-off-by: Sasha Levin +--- + drivers/hwmon/abituguru.c | 2 +- + drivers/hwmon/abituguru3.c | 4 ++-- + drivers/hwmon/aspeed-g6-pwm-tach.c | 2 +- + drivers/hwmon/da9052-hwmon.c | 2 +- + drivers/hwmon/dme1737.c | 2 +- + drivers/hwmon/f71805f.c | 2 +- + drivers/hwmon/f71882fg.c | 2 +- + drivers/hwmon/i5k_amb.c | 2 +- + drivers/hwmon/max197.c | 2 +- + drivers/hwmon/mc13783-adc.c | 2 +- + drivers/hwmon/occ/p9_sbe.c | 4 ++-- + drivers/hwmon/pc87360.c | 2 +- + drivers/hwmon/pc87427.c | 2 +- + drivers/hwmon/sch5636.c | 2 +- + drivers/hwmon/sht15.c | 2 +- + drivers/hwmon/sis5595.c | 2 +- + drivers/hwmon/smsc47m1.c | 2 +- + drivers/hwmon/ultra45_env.c | 2 +- + drivers/hwmon/via-cputemp.c | 2 +- + drivers/hwmon/via686a.c | 2 +- + drivers/hwmon/vt1211.c | 2 +- + drivers/hwmon/vt8231.c | 4 ++-- + drivers/hwmon/w83627hf.c | 2 +- + drivers/hwmon/w83781d.c | 2 +- + drivers/hwmon/xgene-hwmon.c | 2 +- + 25 files changed, 28 insertions(+), 28 deletions(-) + +diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c +index 93653ea054308..ba8c68ae45953 100644 +--- a/drivers/hwmon/abituguru.c ++++ b/drivers/hwmon/abituguru.c +@@ -1531,7 +1531,7 @@ static struct platform_driver abituguru_driver = { + .pm = pm_sleep_ptr(&abituguru_pm), + }, + .probe = abituguru_probe, +- .remove_new = abituguru_remove, ++ .remove = abituguru_remove, + }; + + static int __init abituguru_detect(void) +diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c +index 4501f0e49efb1..b70330dc21984 100644 +--- a/drivers/hwmon/abituguru3.c ++++ b/drivers/hwmon/abituguru3.c +@@ -1147,12 +1147,12 @@ static int abituguru3_resume(struct device *dev) + static DEFINE_SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume); + + static struct platform_driver abituguru3_driver = { +- .driver = { ++ .driver = { + .name = ABIT_UGURU3_NAME, + .pm = pm_sleep_ptr(&abituguru3_pm), + }, + .probe = abituguru3_probe, +- .remove_new = abituguru3_remove, ++ .remove = abituguru3_remove, + }; + + static int __init abituguru3_dmi_detect(void) +diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c +index 75eadda738ab6..4174b129d1fce 100644 +--- a/drivers/hwmon/aspeed-g6-pwm-tach.c ++++ b/drivers/hwmon/aspeed-g6-pwm-tach.c +@@ -534,7 +534,7 @@ MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); + + static struct platform_driver aspeed_pwm_tach_driver = { + .probe = aspeed_pwm_tach_probe, +- .remove_new = aspeed_pwm_tach_remove, ++ .remove = aspeed_pwm_tach_remove, + .driver = { + .name = "aspeed-g6-pwm-tach", + .of_match_table = aspeed_pwm_tach_match, +diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c +index 7fb0c57dfef50..588e96790850a 100644 +--- a/drivers/hwmon/da9052-hwmon.c ++++ b/drivers/hwmon/da9052-hwmon.c +@@ -473,7 +473,7 @@ static void da9052_hwmon_remove(struct platform_device *pdev) + + static struct platform_driver da9052_hwmon_driver = { + .probe = da9052_hwmon_probe, +- .remove_new = da9052_hwmon_remove, ++ .remove = da9052_hwmon_remove, + .driver = { + .name = "da9052-hwmon", + }, +diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c +index 1a9b28dc91e64..3d4057309950d 100644 +--- a/drivers/hwmon/dme1737.c ++++ b/drivers/hwmon/dme1737.c +@@ -2721,7 +2721,7 @@ static struct platform_driver dme1737_isa_driver = { + .name = "dme1737", + }, + .probe = dme1737_isa_probe, +- .remove_new = dme1737_isa_remove, ++ .remove = dme1737_isa_remove, + }; + + /* --------------------------------------------------------------------- +diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c +index 243c570dee4c1..820f894d9ffda 100644 +--- a/drivers/hwmon/f71805f.c ++++ b/drivers/hwmon/f71805f.c +@@ -1497,7 +1497,7 @@ static struct platform_driver f71805f_driver = { + .name = DRVNAME, + }, + .probe = f71805f_probe, +- .remove_new = f71805f_remove, ++ .remove = f71805f_remove, + }; + + static int __init f71805f_device_add(unsigned short address, +diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c +index 734df959276af..204059d2de6cd 100644 +--- a/drivers/hwmon/f71882fg.c ++++ b/drivers/hwmon/f71882fg.c +@@ -2660,7 +2660,7 @@ static struct platform_driver f71882fg_driver = { + .name = DRVNAME, + }, + .probe = f71882fg_probe, +- .remove_new = f71882fg_remove, ++ .remove = f71882fg_remove, + }; + + static int __init f71882fg_init(void) +diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c +index 02f5d35dd3199..b22e0423e3249 100644 +--- a/drivers/hwmon/i5k_amb.c ++++ b/drivers/hwmon/i5k_amb.c +@@ -568,7 +568,7 @@ static struct platform_driver i5k_amb_driver = { + .name = DRVNAME, + }, + .probe = i5k_amb_probe, +- .remove_new = i5k_amb_remove, ++ .remove = i5k_amb_remove, + }; + + static int __init i5k_amb_init(void) +diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c +index bb30403f81caa..f0048ff376072 100644 +--- a/drivers/hwmon/max197.c ++++ b/drivers/hwmon/max197.c +@@ -332,7 +332,7 @@ static struct platform_driver max197_driver = { + .name = "max197", + }, + .probe = max197_probe, +- .remove_new = max197_remove, ++ .remove = max197_remove, + .id_table = max197_device_ids, + }; + module_platform_driver(max197_driver); +diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c +index 67471c9cd4d47..66304d48d33a4 100644 +--- a/drivers/hwmon/mc13783-adc.c ++++ b/drivers/hwmon/mc13783-adc.c +@@ -315,7 +315,7 @@ static const struct platform_device_id mc13783_adc_idtable[] = { + MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); + + static struct platform_driver mc13783_adc_driver = { +- .remove_new = mc13783_adc_remove, ++ .remove = mc13783_adc_remove, + .driver = { + .name = DRIVER_NAME, + }, +diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c +index b5993c79c09ea..89761a9c8892f 100644 +--- a/drivers/hwmon/occ/p9_sbe.c ++++ b/drivers/hwmon/occ/p9_sbe.c +@@ -192,8 +192,8 @@ static struct platform_driver p9_sbe_occ_driver = { + .name = "occ-hwmon", + .of_match_table = p9_sbe_occ_of_match, + }, +- .probe = p9_sbe_occ_probe, +- .remove_new = p9_sbe_occ_remove, ++ .probe = p9_sbe_occ_probe, ++ .remove = p9_sbe_occ_remove, + }; + + module_platform_driver(p9_sbe_occ_driver); +diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c +index 788b5d58f77ea..0f8aa6b42164f 100644 +--- a/drivers/hwmon/pc87360.c ++++ b/drivers/hwmon/pc87360.c +@@ -1606,7 +1606,7 @@ static struct platform_driver pc87360_driver = { + .name = DRIVER_NAME, + }, + .probe = pc87360_probe, +- .remove_new = pc87360_remove, ++ .remove = pc87360_remove, + }; + + /* +diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c +index 7bca04eb4ee4f..571402a89368a 100644 +--- a/drivers/hwmon/pc87427.c ++++ b/drivers/hwmon/pc87427.c +@@ -1129,7 +1129,7 @@ static struct platform_driver pc87427_driver = { + .name = DRVNAME, + }, + .probe = pc87427_probe, +- .remove_new = pc87427_remove, ++ .remove = pc87427_remove, + }; + + static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) +diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c +index a4b05ebb05460..d00bd5cc6b154 100644 +--- a/drivers/hwmon/sch5636.c ++++ b/drivers/hwmon/sch5636.c +@@ -512,7 +512,7 @@ static struct platform_driver sch5636_driver = { + .name = DRVNAME, + }, + .probe = sch5636_probe, +- .remove_new = sch5636_remove, ++ .remove = sch5636_remove, + .id_table = sch5636_device_id, + }; + +diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c +index 494f9655f44f4..3d55047e9baf9 100644 +--- a/drivers/hwmon/sht15.c ++++ b/drivers/hwmon/sht15.c +@@ -1051,7 +1051,7 @@ static struct platform_driver sht15_driver = { + .of_match_table = of_match_ptr(sht15_dt_match), + }, + .probe = sht15_probe, +- .remove_new = sht15_remove, ++ .remove = sht15_remove, + .id_table = sht15_device_ids, + }; + module_platform_driver(sht15_driver); +diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c +index e73b1522f3cef..b7a7bcd6d3af0 100644 +--- a/drivers/hwmon/sis5595.c ++++ b/drivers/hwmon/sis5595.c +@@ -784,7 +784,7 @@ static struct platform_driver sis5595_driver = { + .name = DRIVER_NAME, + }, + .probe = sis5595_probe, +- .remove_new = sis5595_remove, ++ .remove = sis5595_remove, + }; + + static int sis5595_pci_probe(struct pci_dev *dev, +diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c +index 0d46edbcb144b..595bceb78d760 100644 +--- a/drivers/hwmon/smsc47m1.c ++++ b/drivers/hwmon/smsc47m1.c +@@ -858,7 +858,7 @@ static struct platform_driver smsc47m1_driver __refdata = { + .driver = { + .name = DRVNAME, + }, +- .remove_new = __exit_p(smsc47m1_remove), ++ .remove = __exit_p(smsc47m1_remove), + }; + + static int __init smsc47m1_device_add(unsigned short address, +diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c +index 2765d5f1b7f05..e4f1bb538628c 100644 +--- a/drivers/hwmon/ultra45_env.c ++++ b/drivers/hwmon/ultra45_env.c +@@ -317,7 +317,7 @@ static struct platform_driver env_driver = { + .of_match_table = env_match, + }, + .probe = env_probe, +- .remove_new = env_remove, ++ .remove = env_remove, + }; + + module_platform_driver(env_driver); +diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c +index 5abe95b683c02..823bff2871e1e 100644 +--- a/drivers/hwmon/via-cputemp.c ++++ b/drivers/hwmon/via-cputemp.c +@@ -197,7 +197,7 @@ static struct platform_driver via_cputemp_driver = { + .name = DRVNAME, + }, + .probe = via_cputemp_probe, +- .remove_new = via_cputemp_remove, ++ .remove = via_cputemp_remove, + }; + + struct pdev_entry { +diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c +index 3a002ad3c005b..bbaeb808cc15e 100644 +--- a/drivers/hwmon/via686a.c ++++ b/drivers/hwmon/via686a.c +@@ -799,7 +799,7 @@ static struct platform_driver via686a_driver = { + .name = DRIVER_NAME, + }, + .probe = via686a_probe, +- .remove_new = via686a_remove, ++ .remove = via686a_remove, + }; + + static const struct pci_device_id via686a_pci_ids[] = { +diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c +index 2f3890463e18d..386edea6b69e5 100644 +--- a/drivers/hwmon/vt1211.c ++++ b/drivers/hwmon/vt1211.c +@@ -1221,7 +1221,7 @@ static struct platform_driver vt1211_driver = { + .name = DRVNAME, + }, + .probe = vt1211_probe, +- .remove_new = vt1211_remove, ++ .remove = vt1211_remove, + }; + + static int __init vt1211_device_add(unsigned short address) +diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c +index dcdd14ccd115c..3bf27c21845ba 100644 +--- a/drivers/hwmon/vt8231.c ++++ b/drivers/hwmon/vt8231.c +@@ -910,11 +910,11 @@ static void vt8231_remove(struct platform_device *pdev) + + + static struct platform_driver vt8231_driver = { +- .driver = { ++ .driver = { + .name = DRIVER_NAME, + }, + .probe = vt8231_probe, +- .remove_new = vt8231_remove, ++ .remove = vt8231_remove, + }; + + static const struct pci_device_id vt8231_pci_ids[] = { +diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c +index 2fc9b718e2aba..95115d7b863e3 100644 +--- a/drivers/hwmon/w83627hf.c ++++ b/drivers/hwmon/w83627hf.c +@@ -1844,7 +1844,7 @@ static struct platform_driver w83627hf_driver = { + .pm = W83627HF_DEV_PM_OPS, + }, + .probe = w83627hf_probe, +- .remove_new = w83627hf_remove, ++ .remove = w83627hf_remove, + }; + + static int __init w83627hf_find(int sioaddr, unsigned short *addr, +diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c +index b7957c84d2352..076200ed2ec91 100644 +--- a/drivers/hwmon/w83781d.c ++++ b/drivers/hwmon/w83781d.c +@@ -1828,7 +1828,7 @@ static struct platform_driver w83781d_isa_driver = { + .name = "w83781d", + }, + .probe = w83781d_isa_probe, +- .remove_new = w83781d_isa_remove, ++ .remove = w83781d_isa_remove, + }; + + /* return 1 if a supported chip is found, 0 otherwise */ +diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c +index 4e05077e4256d..2cdbd5f107a2c 100644 +--- a/drivers/hwmon/xgene-hwmon.c ++++ b/drivers/hwmon/xgene-hwmon.c +@@ -772,7 +772,7 @@ MODULE_DEVICE_TABLE(of, xgene_hwmon_of_match); + + static struct platform_driver xgene_hwmon_driver = { + .probe = xgene_hwmon_probe, +- .remove_new = xgene_hwmon_remove, ++ .remove = xgene_hwmon_remove, + .driver = { + .name = "xgene-slimpro-hwmon", + .of_match_table = xgene_hwmon_of_match, +-- +2.53.0 + diff --git a/queue-6.12/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch b/queue-6.12/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch new file mode 100644 index 0000000000..f83288d043 --- /dev/null +++ b/queue-6.12/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch @@ -0,0 +1,68 @@ +From 12405369cc52038f2ea74bf45d349b4222528b1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 18:32:30 +0800 +Subject: i3c: dw: Fix memory leak in dw_i3c_master_i3c_xfers() + +From: Felix Gu + +[ Upstream commit 256cc1f1305a8e5dcadf8ca208d04a3acadd26f1 ] + +The dw_i3c_master_i3c_xfers() function allocates memory for the xfer +structure using dw_i3c_master_alloc_xfer(). If pm_runtime_resume_and_get() +fails, the function returns without freeing the allocated xfer, resulting +in a memory leak. + +Since dw_i3c_master_free_xfer() is a thin wrapper around kfree(), use +the __free(kfree) cleanup attribute to handle the free automatically on +all exit paths. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260404-dw-i3c-2-v3-1-8f7d146549c1@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index 6c56e0b89b02d..a60eb86bddba8 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -6,6 +6,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -912,7 +913,6 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct dw_i3c_master *master = to_dw_i3c_master(m); + unsigned int nrxwords = 0, ntxwords = 0; +- struct dw_i3c_xfer *xfer; + int i, ret = 0; + + if (!i3c_nxfers) +@@ -932,7 +932,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, + nrxwords > master->caps.datafifodepth) + return -ENOTSUPP; + +- xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers); ++ struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, i3c_nxfers); + if (!xfer) + return -ENOMEM; + +@@ -983,7 +983,6 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, + } + + ret = xfer->ret; +- dw_i3c_master_free_xfer(xfer); + + pm_runtime_mark_last_busy(master->dev); + pm_runtime_put_autosuspend(master->dev); +-- +2.53.0 + diff --git a/queue-6.12/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch b/queue-6.12/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch new file mode 100644 index 0000000000..6c3ecdd3f2 --- /dev/null +++ b/queue-6.12/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch @@ -0,0 +1,69 @@ +From c0cf18991afaa7431cff3b8ce8735639e215a706 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 22:18:02 +0800 +Subject: i3c: master: dw-i3c: Fix missing reset assertion in remove() callback + +From: Felix Gu + +[ Upstream commit bef1eef667186cedb0bc6d152464acb3c97d5f72 ] + +The reset line acquired during probe is currently left deasserted when +the driver is unbound. + +Switch to devm_reset_control_get_optional_exclusive_deasserted() to +ensure the reset is automatically re-asserted by the devres core when +the driver is removed. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Reviewed-by: Philipp Zabel +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260320-dw-i3c-v3-1-477040c2e3f5@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index 3453431e49a24..6c56e0b89b02d 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1566,13 +1566,11 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + if (IS_ERR(master->pclk)) + return PTR_ERR(master->pclk); + +- master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, +- "core_rst"); ++ master->core_rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, ++ "core_rst"); + if (IS_ERR(master->core_rst)) + return PTR_ERR(master->core_rst); + +- reset_control_deassert(master->core_rst); +- + spin_lock_init(&master->xferqueue.lock); + INIT_LIST_HEAD(&master->xferqueue.list); + +@@ -1584,7 +1582,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + dw_i3c_master_irq_handler, 0, + dev_name(&pdev->dev), master); + if (ret) +- goto err_assert_rst; ++ return ret; + + platform_set_drvdata(pdev, master); + +@@ -1620,9 +1618,6 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + +-err_assert_rst: +- reset_control_assert(master->core_rst); +- + return ret; + } + EXPORT_SYMBOL_GPL(dw_i3c_common_probe); +-- +2.53.0 + diff --git a/queue-6.12/i3c-master-fix-error-codes-at-send_ccc_cmd.patch b/queue-6.12/i3c-master-fix-error-codes-at-send_ccc_cmd.patch new file mode 100644 index 0000000000..b7fc34c66b --- /dev/null +++ b/queue-6.12/i3c-master-fix-error-codes-at-send_ccc_cmd.patch @@ -0,0 +1,126 @@ +From 325b4891ff551740fe01af306ac31287e85f7de0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:32 +0100 +Subject: i3c: master: Fix error codes at send_ccc_cmd + +From: Jorge Marques + +[ Upstream commit ef8b5229348f0719aca557c4ca5530630ae4d134 ] + +i3c_master_send_ccc_cmd_locked() would propagate cmd->err (positive, +Mx codes) to the ret variable, cascading down multiple methods until +reaching methods that explicitly stated they would return 0 on success +or negative error code. For example, the call chain: + + i3c_device_enable_ibi <- i3c_dev_enable_ibi_locked <- + master->ops.enable_ibi <- i3c_master_enec_locked <- + i3c_master_enec_disec_locked <- i3c_master_send_ccc_cmd_locked + +Fix this by returning the ret value, callers can still read the cmd->err +value if ret is negative. + +All corner cases where the Mx codes do need to be handled individually, +are resolved in previous commits. Those corner cases are all scenarios +when I3C_ERROR_M2 is expected and acceptable. +The prerequisite patches for the fix are: + + i3c: master: Move rstdaa error suppression + i3c: master: Move entdaa error suppression + i3c: master: Move bus_init error suppression + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-iio/aYXvT5FW0hXQwhm_@stanley.mountain/ +Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-4-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 32 +++++++++++++------------------- + 1 file changed, 13 insertions(+), 19 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index fe6f956cc3111..8e2bff031aac9 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -825,11 +825,17 @@ static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id, + cmd->err = I3C_ERROR_UNKNOWN; + } + ++/** ++ * i3c_master_send_ccc_cmd_locked() - send a CCC (Common Command Codes) ++ * @master: master used to send frames on the bus ++ * @cmd: command to send ++ * ++ * Return: 0 in case of success, or a negative error code otherwise. ++ * I3C Mx error codes are stored in cmd->err. ++ */ + static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd) + { +- int ret; +- + if (!cmd || !master) + return -EINVAL; + +@@ -847,15 +853,7 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + !master->ops->supports_ccc_cmd(master, cmd)) + return -ENOTSUPP; + +- ret = master->ops->send_ccc_cmd(master, cmd); +- if (ret) { +- if (cmd->err != I3C_ERROR_UNKNOWN) +- return cmd->err; +- +- return ret; +- } +- +- return 0; ++ return master->ops->send_ccc_cmd(master, cmd); + } + + static struct i2c_dev_desc * +@@ -959,8 +957,7 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_entdaa_locked(struct i3c_master_controller *master) + { +@@ -1012,8 +1009,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1033,8 +1029,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1059,8 +1054,7 @@ EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_defslvs_locked(struct i3c_master_controller *master) + { +-- +2.53.0 + diff --git a/queue-6.12/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch b/queue-6.12/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch new file mode 100644 index 0000000000..bc66a25e0f --- /dev/null +++ b/queue-6.12/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch @@ -0,0 +1,56 @@ +From 5e799b2a80033e60f7e33fc7c5f04aa12323ec55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:53:23 +0800 +Subject: i3c: mipi-i3c-hci: fix IBI payload length calculation for final + status + +From: Billy Tsai + +[ Upstream commit d35a6db887eeae7c57b719521e39d64f929c6dc3 ] + +In DMA mode, the IBI status descriptor encodes the payload using +CHUNKS (number of chunks) and DATA_LENGTH (valid bytes in the last +chunk). All preceding chunks are implicitly full-sized. + +The current code accumulates full chunk sizes for non-final status +descriptors, but for the final status descriptor it only adds +DATA_LENGTH. This ignores the contribution of the preceding full +chunks described by the same final status entry. + +As a result, the computed IBI payload length is truncated whenever +the final status spans multiple chunks. For example, with a chunk +size of 4 bytes, CHUNKS=2 and DATA_LENGTH=1 should result in a total +payload size of 5 bytes, but the current code reports only 1 byte. + +Fix the calculation by adding the size of (CHUNKS - 1) full chunks +plus DATA_LENGTH for the last chunk. + +Fixes: 9ad9a52cce28 ("i3c/master: introduce the mipi-i3c-hci driver") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260407-i3c-hci-dma-v2-1-a583187b9d22@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index 36a4c13ab7578..b9496e8c4784d 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -645,7 +645,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh) + if (!(ibi_status & IBI_LAST_STATUS)) { + ibi_size += chunks * rh->ibi_chunk_sz; + } else { +- ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ if (chunks) { ++ ibi_size += (chunks - 1) * rh->ibi_chunk_sz; ++ ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ } + last_ptr = ptr; + break; + } +-- +2.53.0 + diff --git a/queue-6.12/i40e-don-t-advertise-iff_supp_nofcs.patch b/queue-6.12/i40e-don-t-advertise-iff_supp_nofcs.patch new file mode 100644 index 0000000000..4cf790cf99 --- /dev/null +++ b/queue-6.12/i40e-don-t-advertise-iff_supp_nofcs.patch @@ -0,0 +1,53 @@ +From 160f5ae2f4ec171e1a6934146d7e49f9fd4d9338 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:33 -0700 +Subject: i40e: don't advertise IFF_SUPP_NOFCS + +From: Kohei Enju + +[ Upstream commit a24162f18825684ad04e3a5d0531f8a50d679347 ] + +i40e advertises IFF_SUPP_NOFCS, allowing users to use the SO_NOFCS +socket option. However, this option is silently ignored, as the driver +does not check skb->no_fcs, and always enables FCS insertion offload. + +Fix this by removing the advertisement of IFF_SUPP_NOFCS. + +This behavior can be reproduced with a simple AF_PACKET socket: + + import socket + s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) + s.setsockopt(socket.SOL_SOCKET, 43, 1) # SO_NOFCS + s.bind(("eth0", 0)) + s.send(b'\xff' * 64) + +Previously, send() succeeds but the driver ignores SO_NOFCS. +With this change, send() fails with -EPROTONOSUPPORT, as expected. + +Fixes: 41c445ff0f48 ("i40e: main driver core") +Signed-off-by: Kohei Enju +Reviewed-by: Aleksandr Loktionov +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-9-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index e7a06db26c915..6f25445751795 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -13883,7 +13883,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) + netdev->neigh_priv_len = sizeof(u32) * 4; + + netdev->priv_flags |= IFF_UNICAST_FLT; +- netdev->priv_flags |= IFF_SUPP_NOFCS; + /* Setup netdev TC information */ + i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); + +-- +2.53.0 + diff --git a/queue-6.12/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch b/queue-6.12/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch new file mode 100644 index 0000000000..e09f0b9777 --- /dev/null +++ b/queue-6.12/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch @@ -0,0 +1,58 @@ +From edc47e3a6412b3e7ff77feb6ebfb3a824aa7c452 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:16 -0700 +Subject: iavf: add VIRTCHNL_OP_ADD_VLAN to success completion handler + +From: Petr Oros + +[ Upstream commit 34d33313b52eeac3a97ad2e3176d523ec70d9283 ] + +The V1 ADD_VLAN opcode had no success handler; filters sent via V1 +stayed in ADDING state permanently. Add a fallthrough case so V1 +filters also transition ADDING -> ACTIVE on PF confirmation. + +Critically, add an `if (v_retval) break` guard: the error switch in +iavf_virtchnl_completion() does NOT return after handling errors, +it falls through to the success switch. Without this guard, a +PF-rejected ADD would incorrectly mark ADDING filters as ACTIVE, +creating a driver/HW mismatch where the driver believes the filter +is installed but the PF never accepted it. + +For V2, this is harmless: iavf_vlan_add_reject() in the error +block already kfree'd all ADDING filters, so the success handler +finds nothing to transition. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-4-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 9ba36e12dabf0..3e6bdd6ba5372 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -2515,9 +2515,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->adv_rss_lock); + } + break; ++ case VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN_V2: { + struct iavf_vlan_filter *f; + ++ if (v_retval) ++ break; ++ + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_ADDING) +-- +2.53.0 + diff --git a/queue-6.12/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch b/queue-6.12/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch new file mode 100644 index 0000000000..cd82ee8d67 --- /dev/null +++ b/queue-6.12/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch @@ -0,0 +1,87 @@ +From 2c62f69e7619bc39820b85df8de138fb909f6dca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:13 -0700 +Subject: iavf: rename IAVF_VLAN_IS_NEW to IAVF_VLAN_ADDING + +From: Petr Oros + +[ Upstream commit 70d62b669f1f9080a25278fc90b64309f4ae8959 ] + +Rename the IAVF_VLAN_IS_NEW state to IAVF_VLAN_ADDING to better +describe what the state represents: an ADD request has been sent to +the PF and is waiting for a response. + +This is a pure rename with no behavioral change, preparing for a +cleanup of the VLAN filter state machine. + +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-1-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Stable-dep-of: f2ce65b9b917 ("iavf: stop removing VLAN filters from PF on interface down") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 2 +- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 48cd1d06761c8..3ed541529e4fe 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -158,7 +158,7 @@ struct iavf_vlan { + enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ +- IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ ++ IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ + IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ + IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 7e810b65380ca..84eea8f8c62ff 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -636,7 +636,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) { ++ if (f->state == IAVF_VLAN_ADDING) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +@@ -701,7 +701,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + if (f->state == IAVF_VLAN_ADD) { + vvfl->vlan_id[i] = f->vlan.vid; + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + if (i == count) + break; + } +@@ -762,7 +762,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + vlan->tpid = f->vlan.tpid; + + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + } + } + +@@ -2549,7 +2549,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) ++ if (f->state == IAVF_VLAN_ADDING) + f->state = IAVF_VLAN_ACTIVE; + } + spin_unlock_bh(&adapter->mac_vlan_list_lock); +-- +2.53.0 + diff --git a/queue-6.12/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch b/queue-6.12/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch new file mode 100644 index 0000000000..6b4b445f2b --- /dev/null +++ b/queue-6.12/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch @@ -0,0 +1,233 @@ +From 8a9a05b9abe5efeaddecd319ff5e8d9ab399401a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:14 -0700 +Subject: iavf: stop removing VLAN filters from PF on interface down + +From: Petr Oros + +[ Upstream commit f2ce65b9b917474a1a6ce68d357e15fac2aca0f2 ] + +When a VF goes down, the driver currently sends DEL_VLAN to the PF for +every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then +re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING -> +ACTIVE). This round-trip is unnecessary because: + + 1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES, + which already prevents all RX/TX traffic regardless of VLAN filter + state. + + 2. The VLAN filters remaining in PF HW while the VF is down is + harmless - packets matching those filters have nowhere to go with + queues disabled. + + 3. The DEL+ADD cycle during down/up creates race windows where the + VLAN filter list is incomplete. With spoofcheck enabled, the PF + enables TX VLAN filtering on the first non-zero VLAN add, blocking + traffic for any VLANs not yet re-added. + +Remove the entire DISABLE/INACTIVE state machinery: + - Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values + - Remove iavf_restore_filters() and its call from iavf_open() + - Remove VLAN filter handling from iavf_clear_mac_vlan_filters(), + rename it to iavf_clear_mac_filters() + - Remove DEL_VLAN_FILTER scheduling from iavf_down() + - Remove all DISABLE/INACTIVE handling from iavf_del_vlans() + +VLAN filters now stay ACTIVE across down/up cycles. Only explicit +user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN +filter deletion/re-addition. + +Fixes: ed1f5b58ea01 ("i40evf: remove VLAN filters on close") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-2-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 6 +-- + drivers/net/ethernet/intel/iavf/iavf_main.c | 39 ++----------------- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 33 +++------------- + 3 files changed, 12 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 3ed541529e4fe..41596b9889540 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -159,10 +159,8 @@ enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ +- IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ +- IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ +- IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +- IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ ++ IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ ++ IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index 5f07f37933a04..cc1430b2ec593 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -818,27 +818,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +-/** +- * iavf_restore_filters +- * @adapter: board private structure +- * +- * Restore existing non MAC filters when VF netdev comes back up +- **/ +-static void iavf_restore_filters(struct iavf_adapter *adapter) +-{ +- struct iavf_vlan_filter *f; +- +- /* re-add all VLAN filters */ +- spin_lock_bh(&adapter->mac_vlan_list_lock); +- +- list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_INACTIVE) +- f->state = IAVF_VLAN_ADD; +- } +- +- spin_unlock_bh(&adapter->mac_vlan_list_lock); +- adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; +-} + + /** + * iavf_get_num_vlans_added - get number of VLANs added +@@ -1257,13 +1236,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) + } + + /** +- * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF +- * yet and mark other to be removed. ++ * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark ++ * others to be removed. + * @adapter: board private structure + **/ +-static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) ++static void iavf_clear_mac_filters(struct iavf_adapter *adapter) + { +- struct iavf_vlan_filter *vlf, *vlftmp; + struct iavf_mac_filter *f, *ftmp; + + spin_lock_bh(&adapter->mac_vlan_list_lock); +@@ -1282,11 +1260,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) + } + } + +- /* disable all VLAN filters */ +- list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, +- list) +- vlf->state = IAVF_VLAN_DISABLE; +- + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +@@ -1382,7 +1355,7 @@ void iavf_down(struct iavf_adapter *adapter) + iavf_napi_disable_all(adapter); + iavf_irq_disable(adapter); + +- iavf_clear_mac_vlan_filters(adapter); ++ iavf_clear_mac_filters(adapter); + iavf_clear_cloud_filters(adapter); + iavf_clear_fdir_filters(adapter); + iavf_clear_adv_rss_conf(adapter); +@@ -1399,8 +1372,6 @@ void iavf_down(struct iavf_adapter *adapter) + */ + if (!list_empty(&adapter->mac_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; +- if (!list_empty(&adapter->vlan_filter_list)) +- adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; + if (!list_empty(&adapter->cloud_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; + if (!list_empty(&adapter->fdir_list_head)) +@@ -4363,8 +4334,6 @@ static int iavf_open(struct net_device *netdev) + + spin_unlock_bh(&adapter->mac_vlan_list_lock); + +- /* Restore filters that were removed with IFF_DOWN */ +- iavf_restore_filters(adapter); + iavf_restore_fdir_filters(adapter); + + iavf_configure(adapter); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 84eea8f8c62ff..316ce79f14c36 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -799,22 +799,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + spin_lock_bh(&adapter->mac_vlan_list_lock); + + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- /* since VLAN capabilities are not allowed, we dont want to send +- * a VLAN delete request because it will most likely fail and +- * create unnecessary errors/noise, so just free the VLAN +- * filters marked for removal to enable bailing out before +- * sending a virtchnl message +- */ + if (f->state == IAVF_VLAN_REMOVE && + !VLAN_FILTERING_ALLOWED(adapter)) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else if (f->state == IAVF_VLAN_DISABLE && +- !VLAN_FILTERING_ALLOWED(adapter)) { +- f->state = IAVF_VLAN_INACTIVE; +- } else if (f->state == IAVF_VLAN_REMOVE || +- f->state == IAVF_VLAN_DISABLE) { ++ } else if (f->state == IAVF_VLAN_REMOVE) { + count++; + } + } +@@ -846,13 +836,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE) { +- vvfl->vlan_id[i] = f->vlan.vid; +- f->state = IAVF_VLAN_INACTIVE; +- i++; +- if (i == count) +- break; +- } else if (f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; + list_del(&f->list); + kfree(f); +@@ -893,8 +877,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE || +- f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; + struct virtchnl_vlan *vlan; +@@ -908,13 +891,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- if (f->state == IAVF_VLAN_DISABLE) { +- f->state = IAVF_VLAN_INACTIVE; +- } else { +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; +- } ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; + i++; + if (i == count) + break; +-- +2.53.0 + diff --git a/queue-6.12/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch b/queue-6.12/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch new file mode 100644 index 0000000000..2fd67de3a2 --- /dev/null +++ b/queue-6.12/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch @@ -0,0 +1,189 @@ +From 5548ebc5d90299822bcfe574b6592c335ad50966 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:15 -0700 +Subject: iavf: wait for PF confirmation before removing VLAN filters + +From: Petr Oros + +[ Upstream commit bbcbe4ed70dea948849549af7edf44bd42bbd695 ] + +The VLAN filter DELETE path was asymmetric with the ADD path: ADD +waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE +immediately frees the filter struct after sending the DEL message +without waiting for the PF response. + +This is problematic because: + - If the PF rejects the DEL, the filter remains in HW but the driver + has already freed the tracking structure, losing sync. + - Race conditions between DEL pending and other operations + (add, reset) cannot be properly resolved if the filter struct + is already gone. + +Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric: + + REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree + -> PF rejects -> ACTIVE + +In iavf_del_vlans(), transition filters from REMOVE to REMOVING +instead of immediately freeing them. The new DEL completion handler +in iavf_virtchnl_completion() frees filters on success or reverts +them to ACTIVE on error. + +Update iavf_add_vlan() to handle the REMOVING state: if a DEL is +pending and the user re-adds the same VLAN, queue it for ADD so +it gets re-programmed after the PF processes the DEL. + +The !VLAN_FILTERING_ALLOWED early-exit path still frees filters +directly since no PF message is sent in that case. + +Also update iavf_del_vlan() to skip filters already in REMOVING +state: DEL has been sent to PF and the completion handler will +free the filter when PF confirms. Without this guard, the sequence +DEL(pending) -> user-del -> second DEL could cause the PF to return +an error for the second DEL (filter already gone), causing the +completion handler to incorrectly revert a deleted filter back to +ACTIVE. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-3-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 1 + + drivers/net/ethernet/intel/iavf/iavf_main.c | 13 ++++--- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 37 +++++++++++++------ + 3 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 41596b9889540..8cd742c4da913 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -161,6 +161,7 @@ enum iavf_vlan_state_t { + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ ++ IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index cc1430b2ec593..383e015a6f4eb 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -774,10 +774,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, + adapter->num_vlan_filters++; + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); + } else if (f->state == IAVF_VLAN_REMOVE) { +- /* Re-add the filter since we cannot tell whether the +- * pending delete has already been processed by the PF. +- * A duplicate add is harmless. +- */ ++ /* DEL not yet sent to PF, cancel it */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else if (f->state == IAVF_VLAN_REMOVING) { ++ /* DEL already sent to PF, re-add after completion */ + f->state = IAVF_VLAN_ADD; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_ADD_VLAN_FILTER); +@@ -808,11 +808,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else { ++ } else if (f->state != IAVF_VLAN_REMOVING) { + f->state = IAVF_VLAN_REMOVE; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_DEL_VLAN_FILTER); + } ++ /* If REMOVING, DEL is already sent to PF; completion ++ * handler will free the filter when PF confirms. ++ */ + } + + spin_unlock_bh(&adapter->mac_vlan_list_lock); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 316ce79f14c36..9ba36e12dabf0 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -835,12 +835,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -876,7 +874,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; +@@ -891,9 +889,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -2040,10 +2036,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); + wake_up(&adapter->vc_waitqueue); + break; +- case VIRTCHNL_OP_DEL_VLAN: +- dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", +- iavf_stat_str(&adapter->hw, v_retval)); +- break; + case VIRTCHNL_OP_DEL_ETH_ADDR: + dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", + iavf_stat_str(&adapter->hw, v_retval)); +@@ -2534,6 +2526,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + break; ++ case VIRTCHNL_OP_DEL_VLAN: ++ case VIRTCHNL_OP_DEL_VLAN_V2: { ++ struct iavf_vlan_filter *f, *ftmp; ++ ++ spin_lock_bh(&adapter->mac_vlan_list_lock); ++ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, ++ list) { ++ if (f->state == IAVF_VLAN_REMOVING) { ++ if (v_retval) { ++ /* PF rejected DEL, keep filter */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else { ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; ++ } ++ } ++ } ++ spin_unlock_bh(&adapter->mac_vlan_list_lock); ++ } ++ break; + case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: + /* PF enabled vlan strip on this VF. + * Update netdev->features if needed to be in sync with ethtool. +-- +2.53.0 + diff --git a/queue-6.12/ice-fix-double-free-of-tx_buf-skb.patch b/queue-6.12/ice-fix-double-free-of-tx_buf-skb.patch new file mode 100644 index 0000000000..9066f5f816 --- /dev/null +++ b/queue-6.12/ice-fix-double-free-of-tx_buf-skb.patch @@ -0,0 +1,76 @@ +From 0c6da6609943be82134e780fad41c9461911b9bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:28 -0700 +Subject: ice: fix double-free of tx_buf skb + +From: Michal Schmidt + +[ Upstream commit 1a303baa715e6b78d6a406aaf335f87ff35acfcd ] + +If ice_tso() or ice_tx_csum() fail, the error path in +ice_xmit_frame_ring() frees the skb, but the 'first' tx_buf still points +to it and is marked as valid (ICE_TX_BUF_SKB). +'next_to_use' remains unchanged, so the potential problem will +likely fix itself when the next packet is transmitted and the tx_buf +gets overwritten. But if there is no next packet and the interface is +brought down instead, ice_clean_tx_ring() -> ice_unmap_and_free_tx_buf() +will find the tx_buf and free the skb for the second time. + +The fix is to reset the tx_buf type to ICE_TX_BUF_EMPTY in the error +path, so that ice_unmap_and_free_tx_buf(). +Move the initialization of 'first' up, to ensure it's already valid in +case we hit the linearization error path. + +The bug was spotted by AI while I had it looking for something else. +It also proposed an initial version of the patch. + +I reproduced the bug and tested the fix by adding code to inject +failures, on a build with KASAN. + +I looked for similar bugs in related Intel drivers and did not find any. + +Fixes: d76a60ba7afb ("ice: Add support for VLANs and offloads") +Assisted-by: Claude:claude-4.6-opus-high Cursor +Signed-off-by: Michal Schmidt +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-4-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 08d1757f40888..48434a79869cb 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2346,6 +2346,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + ++ /* record the location of the first descriptor for this packet */ ++ first = &tx_ring->tx_buf[tx_ring->next_to_use]; ++ + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +@@ -2371,8 +2374,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + offload.tx_ring = tx_ring; + +- /* record the location of the first descriptor for this packet */ +- first = &tx_ring->tx_buf[tx_ring->next_to_use]; + first->skb = skb; + first->type = ICE_TX_BUF_SKB; + first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); +@@ -2436,6 +2437,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + out_drop: + ice_trace(xmit_frame_ring_drop, tx_ring, skb); + dev_kfree_skb_any(skb); ++ first->type = ICE_TX_BUF_EMPTY; + return NETDEV_TX_OK; + } + +-- +2.53.0 + diff --git a/queue-6.12/ice-fix-ice_aq_link_speed_m-for-200g.patch b/queue-6.12/ice-fix-ice_aq_link_speed_m-for-200g.patch new file mode 100644 index 0000000000..34ceb14c4d --- /dev/null +++ b/queue-6.12/ice-fix-ice_aq_link_speed_m-for-200g.patch @@ -0,0 +1,47 @@ +From 6e79e5d4b0de4e8b5bff49c97381fa718d5f640a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:30 -0700 +Subject: ice: fix ICE_AQ_LINK_SPEED_M for 200G + +From: Paul Greenwalt + +[ Upstream commit 4a3a940059e98539de293a6e36e464094c2e875b ] + +When setting PHY configuration during driver initialization, 200G link +speed is not being advertised even when the PHY is capable. This is +because the get PHY capabilities link speed response is being masked by +ICE_AQ_LINK_SPEED_M, which does not include the 200G link speed bit. + +ICE_AQ_LINK_SPEED_200GB is defined as BIT(11), but the mask 0x7FF only +covers bits 0-10. Fix ICE_AQ_LINK_SPEED_M to use GENMASK(11, 0) so +that it covers all defined link speed bits including 200G. + +Fixes: 24407a01e57c ("ice: Add 200G speed/phy type use") +Signed-off-by: Paul Greenwalt +Signed-off-by: Aleksandr Loktionov +Reviewed-by: Simon Horman +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-6-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +index 66ae0352c6bca..d8013818da960 100644 +--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h ++++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +@@ -1347,7 +1347,7 @@ struct ice_aqc_get_link_status_data { + #define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2 + #define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3 + __le16 link_speed; +-#define ICE_AQ_LINK_SPEED_M 0x7FF ++#define ICE_AQ_LINK_SPEED_M GENMASK(11, 0) + #define ICE_AQ_LINK_SPEED_10MB BIT(0) + #define ICE_AQ_LINK_SPEED_100MB BIT(1) + #define ICE_AQ_LINK_SPEED_1000MB BIT(2) +-- +2.53.0 + diff --git a/queue-6.12/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch b/queue-6.12/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch new file mode 100644 index 0000000000..fb09267b3c --- /dev/null +++ b/queue-6.12/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch @@ -0,0 +1,63 @@ +From 72bfcf8f56a5044a88fcbeedc86c731ab9675d82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:28 -0700 +Subject: ice: fix ice_ptp_read_tx_hwtstamp_status_eth56g + +From: Jacob Keller + +[ Upstream commit 1f75dbc53f68f0fb2acd99f92315e426a3d0b446 ] + +The ice_ptp_read_tx_hwtstamp_status_eth56g function calls +ice_read_phy_eth56g with a PHY index. However the function actually expects +a port index. This causes the function to read the wrong PHY_PTP_INT_STATUS +registers, and effectively makes the status wrong for the second set of +ports from 4 to 7. + +The ice_read_phy_eth56g function uses the provided port index to determine +which PHY device to read. We could refactor the entire chain to take a PHY +index, but this would impact many code sites. Instead, multiply the PHY +index by the number of ports, so that we read from the first port of each +PHY. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-4-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index dc97bee4fd2ea..478ee1c540142 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -2682,13 +2682,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) + *ts_status = 0; + + for (phy = 0; phy < params->num_phys; phy++) { ++ u8 port; + int err; + +- err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status); ++ /* ice_read_phy_eth56g expects a port index, so use the first ++ * port of the PHY ++ */ ++ port = phy * hw->ptp.ports_per_phy; ++ ++ err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status); + if (err) + return err; + +- *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy); ++ *ts_status |= (status & mask) << port; + } + + ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status); +-- +2.53.0 + diff --git a/queue-6.12/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch b/queue-6.12/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch new file mode 100644 index 0000000000..9a3de3281a --- /dev/null +++ b/queue-6.12/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch @@ -0,0 +1,130 @@ +From 3693f7a1e1cffce591c486bc310f7cda8abdd174 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:17 -0700 +Subject: ice: fix NULL pointer dereference in ice_reset_all_vfs() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Petr Oros + +[ Upstream commit 54ef02487914c24170c7e1c061e45212dc55365e ] + +ice_reset_all_vfs() ignores the return value of ice_vf_rebuild_vsi(). +When the VSI rebuild fails (e.g. during NVM firmware update via +nvmupdate64e), ice_vsi_rebuild() tears down the VSI on its error path, +leaving txq_map and rxq_map as NULL. The subsequent unconditional call +to ice_vf_post_vsi_rebuild() leads to a NULL pointer dereference in +ice_ena_vf_q_mappings() when it accesses vsi->txq_map[0]. + +The single-VF reset path in ice_reset_vf() already handles this +correctly by checking the return value of ice_vf_reconfig_vsi() and +skipping ice_vf_post_vsi_rebuild() on failure. + +Apply the same pattern to ice_reset_all_vfs(): check the return value +of ice_vf_rebuild_vsi() and skip ice_vf_post_vsi_rebuild() and +ice_eswitch_attach_vf() on failure. The VF is left safely disabled +(ICE_VF_STATE_INIT not set, VFGEN_RSTAT not set to VFACTIVE) and can +be recovered via a VFLR triggered by a PCI reset of the VF +(sysfs reset or driver rebind). + +Note that this patch does not prevent the VF VSI rebuild from failing +during NVM update — the underlying cause is firmware being in a +transitional state while the EMP reset is processed, which can cause +Admin Queue commands (ice_add_vsi, ice_cfg_vsi_lan) to fail. This +patch only prevents the subsequent NULL pointer dereference that +crashes the kernel when the rebuild does fail. + + crash> bt + PID: 50795 TASK: ff34c9ee708dc680 CPU: 1 COMMAND: "kworker/u512:5" + #0 [ff72159bcfe5bb50] machine_kexec at ffffffffaa8850ee + #1 [ff72159bcfe5bba8] __crash_kexec at ffffffffaaa15fba + #2 [ff72159bcfe5bc68] crash_kexec at ffffffffaaa16540 + #3 [ff72159bcfe5bc70] oops_end at ffffffffaa837eda + #4 [ff72159bcfe5bc90] page_fault_oops at ffffffffaa893997 + #5 [ff72159bcfe5bce8] exc_page_fault at ffffffffab528595 + #6 [ff72159bcfe5bd10] asm_exc_page_fault at ffffffffab600bb2 + [exception RIP: ice_ena_vf_q_mappings+0x79] + RIP: ffffffffc0a85b29 RSP: ff72159bcfe5bdc8 RFLAGS: 00010206 + RAX: 00000000000f0000 RBX: ff34c9efc9c00000 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: 0000000000000010 RDI: ff34c9efc9c00000 + RBP: ff34c9efc27d4828 R8: 0000000000000093 R9: 0000000000000040 + R10: ff34c9efc27d4828 R11: 0000000000000040 R12: 0000000000100000 + R13: 0000000000000010 R14: R15: + ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 + #7 [ff72159bcfe5bdf8] ice_sriov_post_vsi_rebuild at ffffffffc0a85e2e [ice] + #8 [ff72159bcfe5be08] ice_reset_all_vfs at ffffffffc0a920b4 [ice] + #9 [ff72159bcfe5be48] ice_service_task at ffffffffc0a31519 [ice] + #10 [ff72159bcfe5be88] process_one_work at ffffffffaa93dca4 + #11 [ff72159bcfe5bec8] worker_thread at ffffffffaa93e9de + #12 [ff72159bcfe5bf18] kthread at ffffffffaa946663 + #13 [ff72159bcfe5bf50] ret_from_fork at ffffffffaa8086b9 + + The panic occurs attempting to dereference the NULL pointer in RDX at + ice_sriov.c:294, which loads vsi->txq_map (offset 0x4b8 in ice_vsi). + + The faulting VSI is an allocated slab object but not fully initialized + after a failed ice_vsi_rebuild(): + + crash> struct ice_vsi 0xff34c9efc27d4828 + netdev = 0x0, + rx_rings = 0x0, + tx_rings = 0x0, + q_vectors = 0x0, + txq_map = 0x0, + rxq_map = 0x0, + alloc_txq = 0x10, + num_txq = 0x10, + alloc_rxq = 0x10, + num_rxq = 0x10, + + The nvmupdate64e process was performing NVM firmware update: + + crash> bt 0xff34c9edd1a30000 + PID: 49858 TASK: ff34c9edd1a30000 CPU: 1 COMMAND: "nvmupdate64e" + #0 [ff72159bcd617618] __schedule at ffffffffab5333f8 + #4 [ff72159bcd617750] ice_sq_send_cmd at ffffffffc0a35347 [ice] + #5 [ff72159bcd6177a8] ice_sq_send_cmd_retry at ffffffffc0a35b47 [ice] + #6 [ff72159bcd617810] ice_aq_send_cmd at ffffffffc0a38018 [ice] + #7 [ff72159bcd617848] ice_aq_read_nvm at ffffffffc0a40254 [ice] + #8 [ff72159bcd6178b8] ice_read_flat_nvm at ffffffffc0a4034c [ice] + #9 [ff72159bcd617918] ice_devlink_nvm_snapshot at ffffffffc0a6ffa5 [ice] + + dmesg: + ice 0000:13:00.0: firmware recommends not updating fw.mgmt, as it + may result in a downgrade. continuing anyways + ice 0000:13:00.1: ice_init_nvm failed -5 + ice 0000:13:00.1: Rebuild failed, unload and reload driver + +Fixes: 12bb018c538c ("ice: Refactor VF reset") +Signed-off-by: Petr Oros +Tested-by: Rafal Romanowski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-5-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +index 815ad0bfe8326..5267b08011fcf 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +@@ -803,7 +803,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) + ice_vf_ctrl_invalidate_vsi(vf); + + ice_vf_pre_vsi_rebuild(vf); +- ice_vf_rebuild_vsi(vf); ++ if (ice_vf_rebuild_vsi(vf)) { ++ dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", ++ vf->vf_id); ++ mutex_unlock(&vf->cfg_lock); ++ continue; ++ } + ice_vf_post_vsi_rebuild(vf); + + ice_eswitch_attach_vf(pf, vf); +-- +2.53.0 + diff --git a/queue-6.12/ice-fix-timestamp-interrupt-configuration-for-e825c.patch b/queue-6.12/ice-fix-timestamp-interrupt-configuration-for-e825c.patch new file mode 100644 index 0000000000..f8439c5b0a --- /dev/null +++ b/queue-6.12/ice-fix-timestamp-interrupt-configuration-for-e825c.patch @@ -0,0 +1,144 @@ +From f4ff1df194ba394ee9ceda62209c7bad4f7f9ff9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:25 -0700 +Subject: ice: fix timestamp interrupt configuration for E825C + +From: Grzegorz Nitka + +[ Upstream commit c0a575a801a2040eb1e0db54b488f8c548c8458a ] + +The E825C ice_phy_cfg_intr_eth56g() function is responsible for programming +the PHY interrupt for a given port. This function writes to the +PHY_REG_TS_INT_CONFIG register of the port. The register is responsible for +configuring whether the port interrupt logic is enabled, as well as +programming the threshold of waiting timestamps that will trigger an +interrupt from this port. + +This threshold value must not be programmed to zero while the interrupt is +enabled. Doing so puts the port in a misconfigured state where the PHY +timestamp interrupt for the quad of connected ports will become stuck. + +This occurs, because a threshold of zero results in the timestamp interrupt +status for the port becoming stuck high. The four ports in the connected +quad have their timestamp status indicators muxed together. A new interrupt +cannot be generated until the timestamp status indicators return low for +all four ports. + +Normally, the timestamp status for a port will clear once there are fewer +timestamps in that ports timestamp memory bank than the threshold. A +threshold of zero makes this impossible, so the timestamp status for the +port does not clear. + +The ice driver never intentionally programs the threshold to zero, indeed +the driver always programs it to a value of 1, intending to get an +interrupt immediately as soon as even a single packet is waiting for a +timestamp. + +However, there is a subtle flaw in the programming logic in the +ice_phy_cfg_intr_eth56g() function. Due to the way that the hardware +handles enabling the PHY interrupt. If the threshold value is modified at +the same time as the interrupt is enabled, the HW PHY state machine might +enable the interrupt before the new threshold value is actually updated. +This leaves a potential race condition caused by the hardware logic where +a PHY timestamp interrupt might be triggered before the non-zero threshold +is written, resulting in the PHY timestamp logic becoming stuck. + +Once the PHY timestamp status is stuck high, it will remain stuck even +after attempting to reprogram the PHY block by changing its threshold or +disabling the interrupt. Even a typical PF or CORE reset will not reset the +particular block of the PHY that becomes stuck. Even a warm power cycle is +not guaranteed to cause the PHY block to reset, and a cold power cycle is +required. + +Prevent this by always writing the PHY_REG_TS_INT_CONFIG in two stages. +First write the threshold value with the interrupt disabled, and only write +the enable bit after the threshold has been programmed. When disabling the +interrupt, leave the threshold unchanged. Additionally, re-read the +register after writing it to guarantee that the write to the PHY has been +flushed upon exit of the function. + +While we're modifying this function implementation, explicitly reject +programming a threshold of 0 when enabling the interrupt. No caller does +this today, but the consequences of doing so are significant. An explicit +rejection in the code makes this clear. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Signed-off-by: Grzegorz Nitka +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-1-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 36 ++++++++++++++++++--- + 1 file changed, 32 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 7190fde16c868..dc97bee4fd2ea 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -2340,6 +2340,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port) + * @ena: enable or disable interrupt + * @threshold: interrupt threshold + * ++ * The threshold cannot be 0 while the interrupt is enabled. ++ * + * Configure TX timestamp interrupt for the specified port + * + * Return: +@@ -2351,19 +2353,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold) + int err; + u32 val; + ++ if (ena && !threshold) ++ return -EINVAL; ++ + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); + if (err) + return err; + ++ val &= ~PHY_TS_INT_CONFIG_ENA_M; + if (ena) { +- val |= PHY_TS_INT_CONFIG_ENA_M; + val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M; + val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold); +- } else { +- val &= ~PHY_TS_INT_CONFIG_ENA_M; ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, ++ val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ val |= PHY_TS_INT_CONFIG_ENA_M; + } + +- return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ ++ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ ++ return 0; + } + + /** +-- +2.53.0 + diff --git a/queue-6.12/ice-remove-jumbo_remove-step-from-tx-path.patch b/queue-6.12/ice-remove-jumbo_remove-step-from-tx-path.patch new file mode 100644 index 0000000000..a0fee288b2 --- /dev/null +++ b/queue-6.12/ice-remove-jumbo_remove-step-from-tx-path.patch @@ -0,0 +1,41 @@ +From c36fd165f5662987658e3bb6fb8df8059508d506 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 15:39:20 +0200 +Subject: ice: Remove jumbo_remove step from TX path + +From: Alice Mikityanska + +[ Upstream commit 8b76102c5e00d1f090e0c31d17b060c76d8fa859 ] + +Now that the kernel doesn't insert HBH for BIG TCP IPv6 packets, remove +unnecessary steps from the ice TX path, that used to check and remove +HBH. + +Signed-off-by: Alice Mikityanska +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260205133925.526371-8-alice.kernel@fastmail.im +Signed-off-by: Jakub Kicinski +Stable-dep-of: 1a303baa715e ("ice: fix double-free of tx_buf skb") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 431a6ed498a4e..08d1757f40888 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2346,9 +2346,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + +- if (unlikely(ipv6_hopopt_jumbo_remove(skb))) +- goto out_drop; +- + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +-- +2.53.0 + diff --git a/queue-6.12/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch b/queue-6.12/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch new file mode 100644 index 0000000000..4d1fd02024 --- /dev/null +++ b/queue-6.12/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch @@ -0,0 +1,86 @@ +From 2c39d8d7f76468253e84026ab9caa3e0e217fb5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:26 -0700 +Subject: ice: update PCS latency settings for E825 10G/25Gb modes + +From: Grzegorz Nitka + +[ Upstream commit 05567e4052732d70c7ff9655217b3d14d25f639a ] + +Update MAC Rx/Tx offset registers settings (PHY_MAC_[RX|TX]_OFFSET +registers) with the data obtained with the latest research. It applies +to PCS latency settings for the following speeds/modes: +* 10Gb NO-FEC + - TX latency changed from 71.25 ns to 73 ns + - RX latency changed from -25.6 ns to -28 ns +* 25Gb NO-FEC + - TX latency changed from 28.17 ns to 33 ns + - RX latency changed from -12.45 ns to -12 ns +* 25Gb RS-FEC + - TX latency changed from 64.5 ns to 69 ns + - RX latency changed from -3.6 ns to -3 ns + +The original data came from simulation and pre-production hardware. +The new data measures the actual delays and as such is more accurate. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Co-developed-by: Zoltan Fodor +Signed-off-by: Zoltan Fodor +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Jacob Keller +Signed-off-by: Grzegorz Nitka +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-2-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_consts.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +index bdb1020147d1c..91cc7df5cab5b 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +@@ -123,14 +123,14 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { + .blktime = 0x666, /* 3.2 */ + .tx_offset = { + .serdes = 0x234c, /* 17.6484848 */ +- .no_fec = 0x8e80, /* 71.25 */ ++ .no_fec = 0x93d9, /* 73 */ + .fc = 0xb4a4, /* 90.32 */ + .sfd = 0x4a4, /* 2.32 */ + .onestep = 0x4ccd /* 38.4 */ + }, + .rx_offset = { + .serdes = 0xffffeb27, /* -10.42424 */ +- .no_fec = 0xffffcccd, /* -25.6 */ ++ .no_fec = 0xffffc7b6, /* -28 */ + .fc = 0xfffc557b, /* -469.26 */ + .sfd = 0x4a4, /* 2.32 */ + .bs_ds = 0x32 /* 0.0969697 */ +@@ -163,17 +163,17 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { + .mktime = 0x147b, /* 10.24, only if RS-FEC enabled */ + .tx_offset = { + .serdes = 0xe1e, /* 7.0593939 */ +- .no_fec = 0x3857, /* 28.17 */ ++ .no_fec = 0x4266, /* 33 */ + .fc = 0x48c3, /* 36.38 */ +- .rs = 0x8100, /* 64.5 */ ++ .rs = 0x8a00, /* 69 */ + .sfd = 0x1dc, /* 0.93 */ + .onestep = 0x1eb8 /* 15.36 */ + }, + .rx_offset = { + .serdes = 0xfffff7a9, /* -4.1697 */ +- .no_fec = 0xffffe71a, /* -12.45 */ ++ .no_fec = 0xffffe700, /* -12 */ + .fc = 0xfffe894d, /* -187.35 */ +- .rs = 0xfffff8cd, /* -3.6 */ ++ .rs = 0xfffff8cc, /* -3 */ + .sfd = 0x1dc, /* 0.93 */ + .bs_ds = 0x14 /* 0.0387879, RS-FEC 0 */ + } +-- +2.53.0 + diff --git a/queue-6.12/ima-check-return-value-of-crypto_shash_final-in-boot.patch b/queue-6.12/ima-check-return-value-of-crypto_shash_final-in-boot.patch new file mode 100644 index 0000000000..7668309a6f --- /dev/null +++ b/queue-6.12/ima-check-return-value-of-crypto_shash_final-in-boot.patch @@ -0,0 +1,41 @@ +From 64b28be2333b06fdee9eeeef91a389a330f99483 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 18:40:15 -0800 +Subject: ima: check return value of crypto_shash_final() in boot aggregate + +From: Daniel Hodges + +[ Upstream commit 870819434c8dfcc3158033b66e7851b81bb17e21 ] + +The return value of crypto_shash_final() is not checked in +ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the +function returns success and a corrupted boot aggregate digest could +be used for IMA measurements. + +Capture the return value and propagate any error to the caller. + +Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash") +Signed-off-by: Daniel Hodges +Reviewed-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 6f5696d999d0d..8ae7821a65c26 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -832,7 +832,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, + } + } + if (!rc) +- crypto_shash_final(shash, digest); ++ rc = crypto_shash_final(shash, digest); + return rc; + } + +-- +2.53.0 + diff --git a/queue-6.12/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch b/queue-6.12/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch new file mode 100644 index 0000000000..31b79329bd --- /dev/null +++ b/queue-6.12/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch @@ -0,0 +1,130 @@ +From be0e629179ed38219f8cc6a16f11a8a41357b091 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 17:40:39 +0000 +Subject: ima_fs: Correctly create securityfs files for unsupported hash algos + +From: Dmitry Safonov + +[ Upstream commit d7bd8cf0b348d3edae7bee33e74a32b21668b181 ] + +ima_tpm_chip->allocated_banks[i].crypto_id is initialized to +HASH_ALGO__LAST if the TPM algorithm is not supported. However there +are places relying on the algorithm to be valid because it is accessed +by hash_algo_name[]. + +On 6.12.40 I observe the following read out-of-bounds in hash_algo_name: + ================================================================== + BUG: KASAN: global-out-of-bounds in create_securityfs_measurement_lists+0x396/0x440 + Read of size 8 at addr ffffffff83e18138 by task swapper/0/1 + + CPU: 4 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.40 #3 + Call Trace: + + dump_stack_lvl+0x61/0x90 + print_report+0xc4/0x580 + ? kasan_addr_to_slab+0x26/0x80 + ? create_securityfs_measurement_lists+0x396/0x440 + kasan_report+0xc2/0x100 + ? create_securityfs_measurement_lists+0x396/0x440 + create_securityfs_measurement_lists+0x396/0x440 + ima_fs_init+0xa3/0x300 + ima_init+0x7d/0xd0 + init_ima+0x28/0x100 + do_one_initcall+0xa6/0x3e0 + kernel_init_freeable+0x455/0x740 + kernel_init+0x24/0x1d0 + ret_from_fork+0x38/0x80 + ret_from_fork_asm+0x11/0x20 + + + The buggy address belongs to the variable: + hash_algo_name+0xb8/0x420 + + Memory state around the buggy address: + ffffffff83e18000: 00 01 f9 f9 f9 f9 f9 f9 00 01 f9 f9 f9 f9 f9 f9 + ffffffff83e18080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + >ffffffff83e18100: 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 00 05 f9 f9 + ^ + ffffffff83e18180: f9 f9 f9 f9 00 00 00 00 00 00 00 04 f9 f9 f9 f9 + ffffffff83e18200: 00 00 00 00 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9 + ================================================================== + +Seems like the TPM chip supports sha3_256, which isn't yet in +tpm_algorithms: + tpm tpm0: TPM with unsupported bank algorithm 0x0027 + +That's TPM_ALG_SHA3_256 == 0x0027 from "Trusted Platform Module 2.0 +Library Part 2: Structures", page 51 [1]. +See also the related U-Boot algorithms update [2]. + +Thus solve the problem by creating a file name with "_tpm_alg_" +postfix if the crypto algorithm isn't initialized. + +This is how it looks on the test machine (patch ported to v6.12 release): + # ls -1 /sys/kernel/security/ima/ + ascii_runtime_measurements + ascii_runtime_measurements_tpm_alg_27 + ascii_runtime_measurements_sha1 + ascii_runtime_measurements_sha256 + binary_runtime_measurements + binary_runtime_measurements_tpm_alg_27 + binary_runtime_measurements_sha1 + binary_runtime_measurements_sha256 + policy + runtime_measurements_count + violations + +[1]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-2-Version-184_pub.pdf +[2]: https://lists.denx.de/pipermail/u-boot/2024-July/558835.html + +Fixes: 9fa8e7625008 ("ima: add crypto agility support for template-hash algorithm") +Signed-off-by: Dmitry Safonov +Cc: Enrico Bravi +Cc: Silvia Sisinni +Cc: Roberto Sassu +Cc: Mimi Zohar +Reviewed-by: Roberto Sassu +Tested-by: Roberto Sassu +Link: https://github.com/linux-integrity/linux/issues/14 +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_fs.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index 87045b09f1206..25970867f594e 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -404,16 +404,24 @@ static int __init create_securityfs_measurement_lists(void) + char file_name[NAME_MAX + 1]; + struct dentry *dentry; + +- sprintf(file_name, "ascii_runtime_measurements_%s", +- hash_algo_name[algo]); ++ if (algo == HASH_ALGO__LAST) ++ sprintf(file_name, "ascii_runtime_measurements_tpm_alg_%x", ++ ima_tpm_chip->allocated_banks[i].alg_id); ++ else ++ sprintf(file_name, "ascii_runtime_measurements_%s", ++ hash_algo_name[algo]); + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP, + ima_dir, (void *)(uintptr_t)i, + &ima_ascii_measurements_ops); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + +- sprintf(file_name, "binary_runtime_measurements_%s", +- hash_algo_name[algo]); ++ if (algo == HASH_ALGO__LAST) ++ sprintf(file_name, "binary_runtime_measurements_tpm_alg_%x", ++ ima_tpm_chip->allocated_banks[i].alg_id); ++ else ++ sprintf(file_name, "binary_runtime_measurements_%s", ++ hash_algo_name[algo]); + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP, + ima_dir, (void *)(uintptr_t)i, + &ima_measurements_ops); +-- +2.53.0 + diff --git a/queue-6.12/ima_fs-don-t-bother-with-removal-of-files-in-directo.patch b/queue-6.12/ima_fs-don-t-bother-with-removal-of-files-in-directo.patch new file mode 100644 index 0000000000..fed2ae9673 --- /dev/null +++ b/queue-6.12/ima_fs-don-t-bother-with-removal-of-files-in-directo.patch @@ -0,0 +1,143 @@ +From 01f7f08966ee9e33504d7341aeed0cc50b740fb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 May 2024 23:41:51 -0600 +Subject: ima_fs: don't bother with removal of files in directory we'll be + removing + +From: Al Viro + +[ Upstream commit 22260a99d791163f7697a240dfc48e4e5a91ecfe ] + +removal of parent takes all children out + +Acked-by: Mimi Zohar +Signed-off-by: Al Viro +Stable-dep-of: d7bd8cf0b348 ("ima_fs: Correctly create securityfs files for unsupported hash algos") +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_fs.c | 57 +++++++++++---------------------- + 1 file changed, 18 insertions(+), 39 deletions(-) + +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index e4a79a9b2d588..88421e8895c44 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -396,11 +396,6 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf, + + static struct dentry *ima_dir; + static struct dentry *ima_symlink; +-static struct dentry *binary_runtime_measurements; +-static struct dentry *ascii_runtime_measurements; +-static struct dentry *runtime_measurements_count; +-static struct dentry *violations; +-static struct dentry *ima_policy; + + enum ima_fs_flags { + IMA_FS_BUSY, +@@ -419,14 +414,7 @@ static const struct seq_operations ima_policy_seqops = { + + static void __init remove_securityfs_measurement_lists(struct dentry **lists) + { +- int i; +- +- if (lists) { +- for (i = 0; i < securityfs_measurement_list_count; i++) +- securityfs_remove(lists[i]); +- +- kfree(lists); +- } ++ kfree(lists); + } + + static int __init create_securityfs_measurement_lists(void) +@@ -533,8 +521,7 @@ static int ima_release_policy(struct inode *inode, struct file *file) + + ima_update_policy(); + #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY) +- securityfs_remove(ima_policy); +- ima_policy = NULL; ++ securityfs_remove(file->f_path.dentry); + #elif defined(CONFIG_IMA_WRITE_POLICY) + clear_bit(IMA_FS_BUSY, &ima_fs_flags); + #elif defined(CONFIG_IMA_READ_POLICY) +@@ -553,6 +540,7 @@ static const struct file_operations ima_measure_policy_ops = { + + int __init ima_fs_init(void) + { ++ struct dentry *dentry; + int ret; + + ascii_securityfs_measurement_lists = NULL; +@@ -573,54 +561,45 @@ int __init ima_fs_init(void) + if (ret != 0) + goto out; + +- binary_runtime_measurements = +- securityfs_create_symlink("binary_runtime_measurements", ima_dir, ++ dentry = securityfs_create_symlink("binary_runtime_measurements", ima_dir, + "binary_runtime_measurements_sha1", NULL); +- if (IS_ERR(binary_runtime_measurements)) { +- ret = PTR_ERR(binary_runtime_measurements); ++ if (IS_ERR(dentry)) { ++ ret = PTR_ERR(dentry); + goto out; + } + +- ascii_runtime_measurements = +- securityfs_create_symlink("ascii_runtime_measurements", ima_dir, ++ dentry = securityfs_create_symlink("ascii_runtime_measurements", ima_dir, + "ascii_runtime_measurements_sha1", NULL); +- if (IS_ERR(ascii_runtime_measurements)) { +- ret = PTR_ERR(ascii_runtime_measurements); ++ if (IS_ERR(dentry)) { ++ ret = PTR_ERR(dentry); + goto out; + } + +- runtime_measurements_count = +- securityfs_create_file("runtime_measurements_count", ++ dentry = securityfs_create_file("runtime_measurements_count", + S_IRUSR | S_IRGRP, ima_dir, NULL, + &ima_measurements_count_ops); +- if (IS_ERR(runtime_measurements_count)) { +- ret = PTR_ERR(runtime_measurements_count); ++ if (IS_ERR(dentry)) { ++ ret = PTR_ERR(dentry); + goto out; + } + +- violations = +- securityfs_create_file("violations", S_IRUSR | S_IRGRP, ++ dentry = securityfs_create_file("violations", S_IRUSR | S_IRGRP, + ima_dir, NULL, &ima_htable_violations_ops); +- if (IS_ERR(violations)) { +- ret = PTR_ERR(violations); ++ if (IS_ERR(dentry)) { ++ ret = PTR_ERR(dentry); + goto out; + } + +- ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS, ++ dentry = securityfs_create_file("policy", POLICY_FILE_FLAGS, + ima_dir, NULL, + &ima_measure_policy_ops); +- if (IS_ERR(ima_policy)) { +- ret = PTR_ERR(ima_policy); ++ if (IS_ERR(dentry)) { ++ ret = PTR_ERR(dentry); + goto out; + } + + return 0; + out: +- securityfs_remove(ima_policy); +- securityfs_remove(violations); +- securityfs_remove(runtime_measurements_count); +- securityfs_remove(ascii_runtime_measurements); +- securityfs_remove(binary_runtime_measurements); + remove_securityfs_measurement_lists(ascii_securityfs_measurement_lists); + remove_securityfs_measurement_lists(binary_securityfs_measurement_lists); + securityfs_measurement_list_count = 0; +-- +2.53.0 + diff --git a/queue-6.12/ima_fs-get-rid-of-lookup-by-dentry-stuff.patch b/queue-6.12/ima_fs-get-rid-of-lookup-by-dentry-stuff.patch new file mode 100644 index 0000000000..be46d4c8f9 --- /dev/null +++ b/queue-6.12/ima_fs-get-rid-of-lookup-by-dentry-stuff.patch @@ -0,0 +1,172 @@ +From af95df130146cab3af1349fa833f0c098d4e4bc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Mar 2025 12:30:20 -0400 +Subject: ima_fs: get rid of lookup-by-dentry stuff + +From: Al Viro + +[ Upstream commit d15ffbbf4d32a9007c4a339a9fecac90ce30432a ] + +lookup_template_data_hash_algo() machinery is used to locate the +matching ima_algo_array[] element at read time; securityfs +allows to stash that into inode->i_private at object creation +time, so there's no need to bother + +Acked-by: Mimi Zohar +Signed-off-by: Al Viro +Stable-dep-of: d7bd8cf0b348 ("ima_fs: Correctly create securityfs files for unsupported hash algos") +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_fs.c | 82 +++++++-------------------------- + 1 file changed, 16 insertions(+), 66 deletions(-) + +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index 88421e8895c44..87045b09f1206 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -116,28 +116,6 @@ void ima_putc(struct seq_file *m, void *data, int datalen) + seq_putc(m, *(char *)data++); + } + +-static struct dentry **ascii_securityfs_measurement_lists __ro_after_init; +-static struct dentry **binary_securityfs_measurement_lists __ro_after_init; +-static int securityfs_measurement_list_count __ro_after_init; +- +-static void lookup_template_data_hash_algo(int *algo_idx, enum hash_algo *algo, +- struct seq_file *m, +- struct dentry **lists) +-{ +- struct dentry *dentry; +- int i; +- +- dentry = file_dentry(m->file); +- +- for (i = 0; i < securityfs_measurement_list_count; i++) { +- if (dentry == lists[i]) { +- *algo_idx = i; +- *algo = ima_algo_array[i].algo; +- break; +- } +- } +-} +- + /* print format: + * 32bit-le=pcr# + * char[n]=template digest +@@ -160,9 +138,10 @@ int ima_measurements_show(struct seq_file *m, void *v) + algo_idx = ima_sha1_idx; + algo = HASH_ALGO_SHA1; + +- if (m->file != NULL) +- lookup_template_data_hash_algo(&algo_idx, &algo, m, +- binary_securityfs_measurement_lists); ++ if (m->file != NULL) { ++ algo_idx = (unsigned long)file_inode(m->file)->i_private; ++ algo = ima_algo_array[algo_idx].algo; ++ } + + /* get entry */ + e = qe->entry; +@@ -256,9 +235,10 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v) + algo_idx = ima_sha1_idx; + algo = HASH_ALGO_SHA1; + +- if (m->file != NULL) +- lookup_template_data_hash_algo(&algo_idx, &algo, m, +- ascii_securityfs_measurement_lists); ++ if (m->file != NULL) { ++ algo_idx = (unsigned long)file_inode(m->file)->i_private; ++ algo = ima_algo_array[algo_idx].algo; ++ } + + /* get entry */ + e = qe->entry; +@@ -412,57 +392,33 @@ static const struct seq_operations ima_policy_seqops = { + }; + #endif + +-static void __init remove_securityfs_measurement_lists(struct dentry **lists) +-{ +- kfree(lists); +-} +- + static int __init create_securityfs_measurement_lists(void) + { +- char file_name[NAME_MAX + 1]; +- struct dentry *dentry; +- u16 algo; +- int i; +- +- securityfs_measurement_list_count = NR_BANKS(ima_tpm_chip); ++ int count = NR_BANKS(ima_tpm_chip); + + if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip)) +- securityfs_measurement_list_count++; ++ count++; + +- ascii_securityfs_measurement_lists = +- kcalloc(securityfs_measurement_list_count, sizeof(struct dentry *), +- GFP_KERNEL); +- if (!ascii_securityfs_measurement_lists) +- return -ENOMEM; +- +- binary_securityfs_measurement_lists = +- kcalloc(securityfs_measurement_list_count, sizeof(struct dentry *), +- GFP_KERNEL); +- if (!binary_securityfs_measurement_lists) +- return -ENOMEM; +- +- for (i = 0; i < securityfs_measurement_list_count; i++) { +- algo = ima_algo_array[i].algo; ++ for (int i = 0; i < count; i++) { ++ u16 algo = ima_algo_array[i].algo; ++ char file_name[NAME_MAX + 1]; ++ struct dentry *dentry; + + sprintf(file_name, "ascii_runtime_measurements_%s", + hash_algo_name[algo]); + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP, +- ima_dir, NULL, ++ ima_dir, (void *)(uintptr_t)i, + &ima_ascii_measurements_ops); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + +- ascii_securityfs_measurement_lists[i] = dentry; +- + sprintf(file_name, "binary_runtime_measurements_%s", + hash_algo_name[algo]); + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP, +- ima_dir, NULL, ++ ima_dir, (void *)(uintptr_t)i, + &ima_measurements_ops); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); +- +- binary_securityfs_measurement_lists[i] = dentry; + } + + return 0; +@@ -543,9 +499,6 @@ int __init ima_fs_init(void) + struct dentry *dentry; + int ret; + +- ascii_securityfs_measurement_lists = NULL; +- binary_securityfs_measurement_lists = NULL; +- + ima_dir = securityfs_create_dir("ima", integrity_dir); + if (IS_ERR(ima_dir)) + return PTR_ERR(ima_dir); +@@ -600,9 +553,6 @@ int __init ima_fs_init(void) + + return 0; + out: +- remove_securityfs_measurement_lists(ascii_securityfs_measurement_lists); +- remove_securityfs_measurement_lists(binary_securityfs_measurement_lists); +- securityfs_measurement_list_count = 0; + securityfs_remove(ima_symlink); + securityfs_remove(ima_dir); + +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-convert-dev_data-lock-from-spinlock-to-mut.patch b/queue-6.12/iommu-amd-convert-dev_data-lock-from-spinlock-to-mut.patch new file mode 100644 index 0000000000..b1923c0265 --- /dev/null +++ b/queue-6.12/iommu-amd-convert-dev_data-lock-from-spinlock-to-mut.patch @@ -0,0 +1,106 @@ +From c95f16f7b78ee8e318429aef000674174139bb69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2024 06:35:53 +0000 +Subject: iommu/amd: Convert dev_data lock from spinlock to mutex + +From: Vasant Hegde + +[ Upstream commit e843aedbeb82b17a5fe6172449bff133fc8b68a1 ] + +Currently in attach device path it takes dev_data->spinlock. But as per +design attach device path can sleep. Also if device is PRI capable then +it adds device to IOMMU fault handler queue which takes mutex. Hence +currently PRI enablement is done outside dev_data lock. + +Covert dev_data lock from spinlock to mutex so that it follows the +design and also PRI enablement can be done properly. + +Signed-off-by: Vasant Hegde +Reviewed-by: Joerg Roedel +Reviewed-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/20241030063556.6104-10-vasant.hegde@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: faad224fe0f0 ("iommu/amd: Fix clone_alias() to use the original device's devid") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/amd_iommu_types.h | 2 +- + drivers/iommu/amd/iommu.c | 14 +++++++------- + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h +index f99a4b1349287..eadb4379cb4a1 100644 +--- a/drivers/iommu/amd/amd_iommu_types.h ++++ b/drivers/iommu/amd/amd_iommu_types.h +@@ -838,7 +838,7 @@ struct devid_map { + */ + struct iommu_dev_data { + /*Protect against attach/detach races */ +- spinlock_t lock; ++ struct mutex mutex; + + struct list_head list; /* For domain->dev_list */ + struct llist_node dev_data_list; /* For global dev_data_list */ +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 4d59832ed6f81..2a2b9e3e3be7e 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -225,7 +225,7 @@ static struct iommu_dev_data *alloc_dev_data(struct amd_iommu *iommu, u16 devid) + if (!dev_data) + return NULL; + +- spin_lock_init(&dev_data->lock); ++ mutex_init(&dev_data->mutex); + dev_data->devid = devid; + ratelimit_default_init(&dev_data->rs); + +@@ -2129,7 +2129,7 @@ static int attach_device(struct device *dev, + struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); + int ret = 0; + +- spin_lock(&dev_data->lock); ++ mutex_lock(&dev_data->mutex); + + if (dev_data->domain != NULL) { + ret = -EBUSY; +@@ -2155,7 +2155,7 @@ static int attach_device(struct device *dev, + } + + out: +- spin_unlock(&dev_data->lock); ++ mutex_unlock(&dev_data->mutex); + + return ret; + } +@@ -2171,7 +2171,7 @@ static void detach_device(struct device *dev) + bool ppr = dev_data->ppr; + unsigned long flags; + +- spin_lock(&dev_data->lock); ++ mutex_lock(&dev_data->mutex); + + /* + * First check if the device is still attached. It might already +@@ -2209,7 +2209,7 @@ static void detach_device(struct device *dev) + pdom_detach_iommu(iommu, domain); + + out: +- spin_unlock(&dev_data->lock); ++ mutex_unlock(&dev_data->mutex); + + /* Remove IOPF handler */ + if (ppr) +@@ -2486,9 +2486,9 @@ static int blocked_domain_attach_device(struct iommu_domain *domain, + detach_device(dev); + + /* Clear DTE and flush the entry */ +- spin_lock(&dev_data->lock); ++ mutex_lock(&dev_data->mutex); + dev_update_dte(dev_data, false); +- spin_unlock(&dev_data->lock); ++ mutex_unlock(&dev_data->mutex); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-do-not-detach-devices-in-domain-free-path.patch b/queue-6.12/iommu-amd-do-not-detach-devices-in-domain-free-path.patch new file mode 100644 index 0000000000..4e45f890ad --- /dev/null +++ b/queue-6.12/iommu-amd-do-not-detach-devices-in-domain-free-path.patch @@ -0,0 +1,72 @@ +From e88f699abc115836805146d3a04879f6b88c4699 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2024 06:35:50 +0000 +Subject: iommu/amd: Do not detach devices in domain free path + +From: Vasant Hegde + +[ Upstream commit 07bbd660dbd6ff03907d9ddbdfe9deabbd18ac4d ] + +All devices attached to a protection domain must be freed before +calling domain free. Hence do not try to free devices in domain +free path. Continue to throw warning if pdom->dev_list is not empty +so that any potential issues can be fixed. + +Signed-off-by: Vasant Hegde +Reviewed-by: Joerg Roedel +Reviewed-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/20241030063556.6104-7-vasant.hegde@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: faad224fe0f0 ("iommu/amd: Fix clone_alias() to use the original device's devid") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 26 +------------------------- + 1 file changed, 1 insertion(+), 25 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index d9b296e007cc7..799e1a1adfc32 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -2316,21 +2316,6 @@ static struct iommu_group *amd_iommu_device_group(struct device *dev) + * + *****************************************************************************/ + +-static void cleanup_domain(struct protection_domain *domain) +-{ +- struct iommu_dev_data *entry; +- +- lockdep_assert_held(&domain->lock); +- +- while (!list_empty(&domain->dev_list)) { +- entry = list_first_entry(&domain->dev_list, +- struct iommu_dev_data, list); +- BUG_ON(!entry->domain); +- do_detach(entry); +- } +- WARN_ON(!list_empty(&domain->dev_list)); +-} +- + void protection_domain_free(struct protection_domain *domain) + { + WARN_ON(!list_empty(&domain->dev_list)); +@@ -2498,16 +2483,7 @@ amd_iommu_domain_alloc_user(struct device *dev, u32 flags, + + void amd_iommu_domain_free(struct iommu_domain *dom) + { +- struct protection_domain *domain; +- unsigned long flags; +- +- domain = to_pdomain(dom); +- +- spin_lock_irqsave(&domain->lock, flags); +- +- cleanup_domain(domain); +- +- spin_unlock_irqrestore(&domain->lock, flags); ++ struct protection_domain *domain = to_pdomain(dom); + + protection_domain_free(domain); + } +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-fix-clone_alias-to-use-the-original-device.patch b/queue-6.12/iommu-amd-fix-clone_alias-to-use-the-original-device.patch new file mode 100644 index 0000000000..1218f6bcc6 --- /dev/null +++ b/queue-6.12/iommu-amd-fix-clone_alias-to-use-the-original-device.patch @@ -0,0 +1,64 @@ +From 1f37e86a3edee1cc008559b9cd805d707c4d952a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:00:17 +0000 +Subject: iommu/amd: Fix clone_alias() to use the original device's devid + +From: Vasant Hegde + +[ Upstream commit faad224fe0f0857a04ff2eb3c90f0de57f47d0f3 ] + +Currently clone_alias() assumes first argument (pdev) is always the +original device pointer. This function is called by +pci_for_each_dma_alias() which based on topology decides to send +original or alias device details in first argument. + +This meant that the source devid used to look up and copy the DTE +may be incorrect, leading to wrong or stale DTE entries being +propagated to alias device. + +Fix this by passing the original pdev as the opaque data argument to +both the direct clone_alias() call and pci_for_each_dma_alias(). Inside +clone_alias(), retrieve the original device from data and compute devid +from it. + +Fixes: 3332364e4ebc ("iommu/amd: Support multiple PCI DMA aliases in device table") +Signed-off-by: Vasant Hegde +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 3e28aefdc6a02..a5adc4714f5c9 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -382,11 +382,12 @@ static struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devid + return NULL; + } + +-static int clone_alias(struct pci_dev *pdev, u16 alias, void *data) ++static int clone_alias(struct pci_dev *pdev_origin, u16 alias, void *data) + { + struct dev_table_entry new; + struct amd_iommu *iommu; + struct iommu_dev_data *dev_data, *alias_data; ++ struct pci_dev *pdev = data; + u16 devid = pci_dev_id(pdev); + int ret = 0; + +@@ -433,9 +434,9 @@ static void clone_aliases(struct amd_iommu *iommu, struct device *dev) + * part of the PCI DMA aliases if it's bus differs + * from the original device. + */ +- clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], NULL); ++ clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], pdev); + +- pci_for_each_dma_alias(pdev, clone_alias, NULL); ++ pci_for_each_dma_alias(pdev, clone_alias, pdev); + } + + static void setup_aliases(struct amd_iommu *iommu, struct device *dev) +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-introduce-helper-function-get_dte256.patch b/queue-6.12/iommu-amd-introduce-helper-function-get_dte256.patch new file mode 100644 index 0000000000..61d793305f --- /dev/null +++ b/queue-6.12/iommu-amd-introduce-helper-function-get_dte256.patch @@ -0,0 +1,145 @@ +From da9a877a6783539dce86413b3e42959b05af5d06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Nov 2024 05:49:34 +0000 +Subject: iommu/amd: Introduce helper function get_dte256() + +From: Suravee Suthikulpanit + +[ Upstream commit a2ce608a1eb65c2af99c58b63eae557165a0da87 ] + +And use it in clone_alias() along with update_dte256(). +Also use get_dte256() in dump_dte_entry(). + +Reviewed-by: Jason Gunthorpe +Signed-off-by: Suravee Suthikulpanit +Link: https://lore.kernel.org/r/20241118054937.5203-7-suravee.suthikulpanit@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: faad224fe0f0 ("iommu/amd: Fix clone_alias() to use the original device's devid") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 62 ++++++++++++++++++++++++++++++++------- + 1 file changed, 51 insertions(+), 11 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index e5c6cf57439c9..3e28aefdc6a02 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -79,6 +79,8 @@ static void set_dte_entry(struct amd_iommu *iommu, + + static void iommu_flush_dte_sync(struct amd_iommu *iommu, u16 devid); + ++static struct iommu_dev_data *find_dev_data(struct amd_iommu *iommu, u16 devid); ++ + /**************************************************************************** + * + * Helper functions +@@ -196,6 +198,21 @@ static void update_dte256(struct amd_iommu *iommu, struct iommu_dev_data *dev_da + spin_unlock_irqrestore(&dev_data->dte_lock, flags); + } + ++static void get_dte256(struct amd_iommu *iommu, struct iommu_dev_data *dev_data, ++ struct dev_table_entry *dte) ++{ ++ unsigned long flags; ++ struct dev_table_entry *ptr; ++ struct dev_table_entry *dev_table = get_dev_table(iommu); ++ ++ ptr = &dev_table[dev_data->devid]; ++ ++ spin_lock_irqsave(&dev_data->dte_lock, flags); ++ dte->data128[0] = ptr->data128[0]; ++ dte->data128[1] = ptr->data128[1]; ++ spin_unlock_irqrestore(&dev_data->dte_lock, flags); ++} ++ + static inline bool pdom_is_v2_pgtbl_mode(struct protection_domain *pdom) + { + return (pdom && (pdom->pd_mode == PD_MODE_V2)); +@@ -367,9 +384,11 @@ static struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devid + + static int clone_alias(struct pci_dev *pdev, u16 alias, void *data) + { ++ struct dev_table_entry new; + struct amd_iommu *iommu; +- struct dev_table_entry *dev_table; ++ struct iommu_dev_data *dev_data, *alias_data; + u16 devid = pci_dev_id(pdev); ++ int ret = 0; + + if (devid == alias) + return 0; +@@ -378,13 +397,27 @@ static int clone_alias(struct pci_dev *pdev, u16 alias, void *data) + if (!iommu) + return 0; + +- amd_iommu_set_rlookup_table(iommu, alias); +- dev_table = get_dev_table(iommu); +- memcpy(dev_table[alias].data, +- dev_table[devid].data, +- sizeof(dev_table[alias].data)); ++ /* Copy the data from pdev */ ++ dev_data = dev_iommu_priv_get(&pdev->dev); ++ if (!dev_data) { ++ pr_err("%s : Failed to get dev_data for 0x%x\n", __func__, devid); ++ ret = -EINVAL; ++ goto out; ++ } ++ get_dte256(iommu, dev_data, &new); + +- return 0; ++ /* Setup alias */ ++ alias_data = find_dev_data(iommu, alias); ++ if (!alias_data) { ++ pr_err("%s : Failed to get alias dev_data for 0x%x\n", __func__, alias); ++ ret = -EINVAL; ++ goto out; ++ } ++ update_dte256(iommu, alias_data, &new); ++ ++ amd_iommu_set_rlookup_table(iommu, alias); ++out: ++ return ret; + } + + static void clone_aliases(struct amd_iommu *iommu, struct device *dev) +@@ -657,6 +690,12 @@ static int iommu_init_device(struct amd_iommu *iommu, struct device *dev) + return -ENOMEM; + + dev_data->dev = dev; ++ ++ /* ++ * The dev_iommu_priv_set() needes to be called before setup_aliases. ++ * Otherwise, subsequent call to dev_iommu_priv_get() will fail. ++ */ ++ dev_iommu_priv_set(dev, dev_data); + setup_aliases(iommu, dev); + + /* +@@ -670,8 +709,6 @@ static int iommu_init_device(struct amd_iommu *iommu, struct device *dev) + dev_data->flags = pdev_get_caps(to_pci_dev(dev)); + } + +- dev_iommu_priv_set(dev, dev_data); +- + return 0; + } + +@@ -718,10 +755,13 @@ static void amd_iommu_uninit_device(struct device *dev) + static void dump_dte_entry(struct amd_iommu *iommu, u16 devid) + { + int i; +- struct dev_table_entry *dev_table = get_dev_table(iommu); ++ struct dev_table_entry dte; ++ struct iommu_dev_data *dev_data = find_dev_data(iommu, devid); ++ ++ get_dte256(iommu, dev_data, &dte); + + for (i = 0; i < 4; ++i) +- pr_err("DTE[%d]: %016llx\n", i, dev_table[devid].data[i]); ++ pr_err("DTE[%d]: %016llx\n", i, dte.data[i]); + } + + static void dump_command(unsigned long phys_addr) +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-introduce-helper-function-to-update-256-bi.patch b/queue-6.12/iommu-amd-introduce-helper-function-to-update-256-bi.patch new file mode 100644 index 0000000000..0b7914b12a --- /dev/null +++ b/queue-6.12/iommu-amd-introduce-helper-function-to-update-256-bi.patch @@ -0,0 +1,232 @@ +From a70ea844be8e0f0472f636953e62e01e705c94cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Nov 2024 05:49:32 +0000 +Subject: iommu/amd: Introduce helper function to update 256-bit DTE + +From: Suravee Suthikulpanit + +[ Upstream commit 8b3f78733814b180089a400743b6f19d118aec62 ] + +The current implementation does not follow 128-bit write requirement +to update DTE as specified in the AMD I/O Virtualization Techonology +(IOMMU) Specification. + +Therefore, modify the struct dev_table_entry to contain union of u128 data +array, and introduce a helper functions update_dte256() to update DTE using +two 128-bit cmpxchg operations to update 256-bit DTE with the modified +structure, and take into account the DTE[V, GV] bits when programming +the DTE to ensure proper order of DTE programming and flushing. + +In addition, introduce a per-DTE spin_lock struct dev_data.dte_lock to +provide synchronization when updating the DTE to prevent cmpxchg128 +failure. + +Suggested-by: Jason Gunthorpe +Suggested-by: Uros Bizjak +Reviewed-by: Jason Gunthorpe +Reviewed-by: Uros Bizjak +Signed-off-by: Suravee Suthikulpanit +Link: https://lore.kernel.org/r/20241118054937.5203-5-suravee.suthikulpanit@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: faad224fe0f0 ("iommu/amd: Fix clone_alias() to use the original device's devid") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/amd_iommu_types.h | 10 ++- + drivers/iommu/amd/iommu.c | 123 ++++++++++++++++++++++++++++ + 2 files changed, 132 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h +index eadb4379cb4a1..7f13b314abbce 100644 +--- a/drivers/iommu/amd/amd_iommu_types.h ++++ b/drivers/iommu/amd/amd_iommu_types.h +@@ -426,9 +426,13 @@ + #define DTE_GCR3_SHIFT_C 43 + + #define DTE_GPT_LEVEL_SHIFT 54 ++#define DTE_GPT_LEVEL_MASK GENMASK_ULL(55, 54) + + #define GCR3_VALID 0x01ULL + ++/* DTE[128:179] | DTE[184:191] */ ++#define DTE_DATA2_INTR_MASK ~GENMASK_ULL(55, 52) ++ + #define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL) + #define IOMMU_PTE_PRESENT(pte) ((pte) & IOMMU_PTE_PR) + #define IOMMU_PTE_DIRTY(pte) ((pte) & IOMMU_PTE_HD) +@@ -839,6 +843,7 @@ struct devid_map { + struct iommu_dev_data { + /*Protect against attach/detach races */ + struct mutex mutex; ++ spinlock_t dte_lock; /* DTE lock for 256-bit access */ + + struct list_head list; /* For domain->dev_list */ + struct llist_node dev_data_list; /* For global dev_data_list */ +@@ -889,7 +894,10 @@ extern struct amd_iommu *amd_iommus[MAX_IOMMUS]; + * Structure defining one entry in the device table + */ + struct dev_table_entry { +- u64 data[4]; ++ union { ++ u64 data[4]; ++ u128 data128[2]; ++ }; + }; + + /* +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 2a2b9e3e3be7e..e5c6cf57439c9 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -77,12 +77,125 @@ static void detach_device(struct device *dev); + static void set_dte_entry(struct amd_iommu *iommu, + struct iommu_dev_data *dev_data); + ++static void iommu_flush_dte_sync(struct amd_iommu *iommu, u16 devid); ++ + /**************************************************************************** + * + * Helper functions + * + ****************************************************************************/ + ++static __always_inline void amd_iommu_atomic128_set(__int128 *ptr, __int128 val) ++{ ++ /* ++ * Note: ++ * We use arch_cmpxchg128_local() because: ++ * - Need cmpxchg16b instruction mainly for 128-bit store to DTE ++ * (not necessary for cmpxchg since this function is already ++ * protected by a spin_lock for this DTE). ++ * - Neither need LOCK_PREFIX nor try loop because of the spin_lock. ++ */ ++ arch_cmpxchg128_local(ptr, *ptr, val); ++} ++ ++static void write_dte_upper128(struct dev_table_entry *ptr, struct dev_table_entry *new) ++{ ++ struct dev_table_entry old; ++ ++ old.data128[1] = ptr->data128[1]; ++ /* ++ * Preserve DTE_DATA2_INTR_MASK. This needs to be ++ * done here since it requires to be inside ++ * spin_lock(&dev_data->dte_lock) context. ++ */ ++ new->data[2] &= ~DTE_DATA2_INTR_MASK; ++ new->data[2] |= old.data[2] & DTE_DATA2_INTR_MASK; ++ ++ amd_iommu_atomic128_set(&ptr->data128[1], new->data128[1]); ++} ++ ++static void write_dte_lower128(struct dev_table_entry *ptr, struct dev_table_entry *new) ++{ ++ amd_iommu_atomic128_set(&ptr->data128[0], new->data128[0]); ++} ++ ++/* ++ * Note: ++ * IOMMU reads the entire Device Table entry in a single 256-bit transaction ++ * but the driver is programming DTE using 2 128-bit cmpxchg. So, the driver ++ * need to ensure the following: ++ * - DTE[V|GV] bit is being written last when setting. ++ * - DTE[V|GV] bit is being written first when clearing. ++ * ++ * This function is used only by code, which updates DMA translation part of the DTE. ++ * So, only consider control bits related to DMA when updating the entry. ++ */ ++static void update_dte256(struct amd_iommu *iommu, struct iommu_dev_data *dev_data, ++ struct dev_table_entry *new) ++{ ++ unsigned long flags; ++ struct dev_table_entry *dev_table = get_dev_table(iommu); ++ struct dev_table_entry *ptr = &dev_table[dev_data->devid]; ++ ++ spin_lock_irqsave(&dev_data->dte_lock, flags); ++ ++ if (!(ptr->data[0] & DTE_FLAG_V)) { ++ /* Existing DTE is not valid. */ ++ write_dte_upper128(ptr, new); ++ write_dte_lower128(ptr, new); ++ iommu_flush_dte_sync(iommu, dev_data->devid); ++ } else if (!(new->data[0] & DTE_FLAG_V)) { ++ /* Existing DTE is valid. New DTE is not valid. */ ++ write_dte_lower128(ptr, new); ++ write_dte_upper128(ptr, new); ++ iommu_flush_dte_sync(iommu, dev_data->devid); ++ } else if (!FIELD_GET(DTE_FLAG_GV, ptr->data[0])) { ++ /* ++ * Both DTEs are valid. ++ * Existing DTE has no guest page table. ++ */ ++ write_dte_upper128(ptr, new); ++ write_dte_lower128(ptr, new); ++ iommu_flush_dte_sync(iommu, dev_data->devid); ++ } else if (!FIELD_GET(DTE_FLAG_GV, new->data[0])) { ++ /* ++ * Both DTEs are valid. ++ * Existing DTE has guest page table, ++ * new DTE has no guest page table, ++ */ ++ write_dte_lower128(ptr, new); ++ write_dte_upper128(ptr, new); ++ iommu_flush_dte_sync(iommu, dev_data->devid); ++ } else if (FIELD_GET(DTE_GPT_LEVEL_MASK, ptr->data[2]) != ++ FIELD_GET(DTE_GPT_LEVEL_MASK, new->data[2])) { ++ /* ++ * Both DTEs are valid and have guest page table, ++ * but have different number of levels. So, we need ++ * to upadte both upper and lower 128-bit value, which ++ * require disabling and flushing. ++ */ ++ struct dev_table_entry clear = {}; ++ ++ /* First disable DTE */ ++ write_dte_lower128(ptr, &clear); ++ iommu_flush_dte_sync(iommu, dev_data->devid); ++ ++ /* Then update DTE */ ++ write_dte_upper128(ptr, new); ++ write_dte_lower128(ptr, new); ++ iommu_flush_dte_sync(iommu, dev_data->devid); ++ } else { ++ /* ++ * Both DTEs are valid and have guest page table, ++ * and same number of levels. We just need to only ++ * update the lower 128-bit. So no need to disable DTE. ++ */ ++ write_dte_lower128(ptr, new); ++ } ++ ++ spin_unlock_irqrestore(&dev_data->dte_lock, flags); ++} ++ + static inline bool pdom_is_v2_pgtbl_mode(struct protection_domain *pdom) + { + return (pdom && (pdom->pd_mode == PD_MODE_V2)); +@@ -226,6 +339,7 @@ static struct iommu_dev_data *alloc_dev_data(struct amd_iommu *iommu, u16 devid) + return NULL; + + mutex_init(&dev_data->mutex); ++ spin_lock_init(&dev_data->dte_lock); + dev_data->devid = devid; + ratelimit_default_init(&dev_data->rs); + +@@ -1312,6 +1426,15 @@ static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid) + return iommu_queue_command(iommu, &cmd); + } + ++static void iommu_flush_dte_sync(struct amd_iommu *iommu, u16 devid) ++{ ++ int ret; ++ ++ ret = iommu_flush_dte(iommu, devid); ++ if (!ret) ++ iommu_completion_wait(iommu); ++} ++ + static void amd_iommu_flush_dte_all(struct amd_iommu *iommu) + { + u32 devid; +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-rearrange-attach-device-code.patch b/queue-6.12/iommu-amd-rearrange-attach-device-code.patch new file mode 100644 index 0000000000..ac7ce64100 --- /dev/null +++ b/queue-6.12/iommu-amd-rearrange-attach-device-code.patch @@ -0,0 +1,164 @@ +From ec8003395b447ef643a55650cdd7bddc8fbb8987 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2024 06:35:52 +0000 +Subject: iommu/amd: Rearrange attach device code + +From: Vasant Hegde + +[ Upstream commit 4b18ef8491b06e353e8801705092cc292582cb7a ] + +attach_device() is just holding lock and calling do_attach(). There is +not need to have another function. Just move do_attach() code to +attach_device(). Similarly move do_detach() code to detach_device(). + +Signed-off-by: Vasant Hegde +Reviewed-by: Joerg Roedel +Reviewed-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/20241030063556.6104-9-vasant.hegde@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: faad224fe0f0 ("iommu/amd: Fix clone_alias() to use the original device's devid") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 91 ++++++++++++++++----------------------- + 1 file changed, 36 insertions(+), 55 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 3ac8f64a21475..4d59832ed6f81 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -2118,12 +2118,24 @@ static void pdom_detach_iommu(struct amd_iommu *iommu, + spin_unlock_irqrestore(&pdom->lock, flags); + } + +-static int do_attach(struct iommu_dev_data *dev_data, +- struct protection_domain *domain) ++/* ++ * If a device is not yet associated with a domain, this function makes the ++ * device visible in the domain ++ */ ++static int attach_device(struct device *dev, ++ struct protection_domain *domain) + { ++ struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); + struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); + int ret = 0; + ++ spin_lock(&dev_data->lock); ++ ++ if (dev_data->domain != NULL) { ++ ret = -EBUSY; ++ goto out; ++ } ++ + /* Update data structures */ + dev_data->domain = domain; + list_add(&dev_data->list, &domain->dev_list); +@@ -2131,67 +2143,17 @@ static int do_attach(struct iommu_dev_data *dev_data, + /* Do reference counting */ + ret = pdom_attach_iommu(iommu, domain); + if (ret) +- return ret; ++ goto out; + + /* Setup GCR3 table */ + if (pdom_is_sva_capable(domain)) { + ret = init_gcr3_table(dev_data, domain); + if (ret) { + pdom_detach_iommu(iommu, domain); +- return ret; ++ goto out; + } + } + +- return ret; +-} +- +-static void do_detach(struct iommu_dev_data *dev_data) +-{ +- struct protection_domain *domain = dev_data->domain; +- struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); +- unsigned long flags; +- +- /* Clear DTE and flush the entry */ +- dev_update_dte(dev_data, false); +- +- /* Flush IOTLB and wait for the flushes to finish */ +- spin_lock_irqsave(&domain->lock, flags); +- amd_iommu_domain_flush_all(domain); +- spin_unlock_irqrestore(&domain->lock, flags); +- +- /* Clear GCR3 table */ +- if (pdom_is_sva_capable(domain)) +- destroy_gcr3_table(dev_data, domain); +- +- /* Update data structures */ +- dev_data->domain = NULL; +- list_del(&dev_data->list); +- +- /* decrease reference counters - needs to happen after the flushes */ +- pdom_detach_iommu(iommu, domain); +-} +- +-/* +- * If a device is not yet associated with a domain, this function makes the +- * device visible in the domain +- */ +-static int attach_device(struct device *dev, +- struct protection_domain *domain) +-{ +- struct iommu_dev_data *dev_data; +- int ret = 0; +- +- dev_data = dev_iommu_priv_get(dev); +- +- spin_lock(&dev_data->lock); +- +- if (dev_data->domain != NULL) { +- ret = -EBUSY; +- goto out; +- } +- +- ret = do_attach(dev_data, domain); +- + out: + spin_unlock(&dev_data->lock); + +@@ -2205,7 +2167,9 @@ static void detach_device(struct device *dev) + { + struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); + struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); ++ struct protection_domain *domain = dev_data->domain; + bool ppr = dev_data->ppr; ++ unsigned long flags; + + spin_lock(&dev_data->lock); + +@@ -2225,7 +2189,24 @@ static void detach_device(struct device *dev) + dev_data->ppr = false; + } + +- do_detach(dev_data); ++ /* Clear DTE and flush the entry */ ++ dev_update_dte(dev_data, false); ++ ++ /* Flush IOTLB and wait for the flushes to finish */ ++ spin_lock_irqsave(&domain->lock, flags); ++ amd_iommu_domain_flush_all(domain); ++ spin_unlock_irqrestore(&domain->lock, flags); ++ ++ /* Clear GCR3 table */ ++ if (pdom_is_sva_capable(domain)) ++ destroy_gcr3_table(dev_data, domain); ++ ++ /* Update data structures */ ++ dev_data->domain = NULL; ++ list_del(&dev_data->list); ++ ++ /* decrease reference counters - needs to happen after the flushes */ ++ pdom_detach_iommu(iommu, domain); + + out: + spin_unlock(&dev_data->lock); +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-reduce-domain-lock-scope-in-attach-device-.patch b/queue-6.12/iommu-amd-reduce-domain-lock-scope-in-attach-device-.patch new file mode 100644 index 0000000000..8fb7b19c83 --- /dev/null +++ b/queue-6.12/iommu-amd-reduce-domain-lock-scope-in-attach-device-.patch @@ -0,0 +1,186 @@ +From 635b6821a52997590c77a73c55aa373c8cffe7f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2024 06:35:51 +0000 +Subject: iommu/amd: Reduce domain lock scope in attach device path + +From: Vasant Hegde + +[ Upstream commit d6b47dec368400a62d2b9d44c8e136fc15eac72c ] + +Currently attach device path takes protection domain lock followed by +dev_data lock. Most of the operations in this function is specific to +device data except pdom_attach_iommu() where it updates protection +domain structure. Hence reduce the scope of protection domain lock. + +Note that this changes the locking order. Now it takes device lock +before taking doamin lock (group->mutex -> dev_data->lock -> +pdom->lock). dev_data->lock is used only in device attachment path. +So changing order is fine. It will not create any issue. + +Finally move numa node assignment to pdom_attach_iommu(). + +Signed-off-by: Vasant Hegde +Reviewed-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/20241030063556.6104-8-vasant.hegde@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: faad224fe0f0 ("iommu/amd: Fix clone_alias() to use the original device's devid") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 52 ++++++++++++++++++++++----------------- + 1 file changed, 30 insertions(+), 22 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 799e1a1adfc32..3ac8f64a21475 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -2057,16 +2057,23 @@ static int pdom_attach_iommu(struct amd_iommu *iommu, + struct protection_domain *pdom) + { + struct pdom_iommu_info *pdom_iommu_info, *curr; ++ struct io_pgtable_cfg *cfg = &pdom->iop.pgtbl.cfg; ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&pdom->lock, flags); + + pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index); + if (pdom_iommu_info) { + pdom_iommu_info->refcnt++; +- return 0; ++ goto out_unlock; + } + + pdom_iommu_info = kzalloc(sizeof(*pdom_iommu_info), GFP_ATOMIC); +- if (!pdom_iommu_info) +- return -ENOMEM; ++ if (!pdom_iommu_info) { ++ ret = -ENOMEM; ++ goto out_unlock; ++ } + + pdom_iommu_info->iommu = iommu; + pdom_iommu_info->refcnt = 1; +@@ -2075,43 +2082,52 @@ static int pdom_attach_iommu(struct amd_iommu *iommu, + NULL, pdom_iommu_info, GFP_ATOMIC); + if (curr) { + kfree(pdom_iommu_info); +- return -ENOSPC; ++ ret = -ENOSPC; ++ goto out_unlock; + } + +- return 0; ++ /* Update NUMA Node ID */ ++ if (cfg->amd.nid == NUMA_NO_NODE) ++ cfg->amd.nid = dev_to_node(&iommu->dev->dev); ++ ++out_unlock: ++ spin_unlock_irqrestore(&pdom->lock, flags); ++ return ret; + } + + static void pdom_detach_iommu(struct amd_iommu *iommu, + struct protection_domain *pdom) + { + struct pdom_iommu_info *pdom_iommu_info; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pdom->lock, flags); + + pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index); +- if (!pdom_iommu_info) ++ if (!pdom_iommu_info) { ++ spin_unlock_irqrestore(&pdom->lock, flags); + return; ++ } + + pdom_iommu_info->refcnt--; + if (pdom_iommu_info->refcnt == 0) { + xa_erase(&pdom->iommu_array, iommu->index); + kfree(pdom_iommu_info); + } ++ ++ spin_unlock_irqrestore(&pdom->lock, flags); + } + + static int do_attach(struct iommu_dev_data *dev_data, + struct protection_domain *domain) + { + struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); +- struct io_pgtable_cfg *cfg = &domain->iop.pgtbl.cfg; + int ret = 0; + + /* Update data structures */ + dev_data->domain = domain; + list_add(&dev_data->list, &domain->dev_list); + +- /* Update NUMA Node ID */ +- if (cfg->amd.nid == NUMA_NO_NODE) +- cfg->amd.nid = dev_to_node(dev_data->dev); +- + /* Do reference counting */ + ret = pdom_attach_iommu(iommu, domain); + if (ret) +@@ -2133,12 +2149,15 @@ static void do_detach(struct iommu_dev_data *dev_data) + { + struct protection_domain *domain = dev_data->domain; + struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); ++ unsigned long flags; + + /* Clear DTE and flush the entry */ + dev_update_dte(dev_data, false); + + /* Flush IOTLB and wait for the flushes to finish */ ++ spin_lock_irqsave(&domain->lock, flags); + amd_iommu_domain_flush_all(domain); ++ spin_unlock_irqrestore(&domain->lock, flags); + + /* Clear GCR3 table */ + if (pdom_is_sva_capable(domain)) +@@ -2160,11 +2179,8 @@ static int attach_device(struct device *dev, + struct protection_domain *domain) + { + struct iommu_dev_data *dev_data; +- unsigned long flags; + int ret = 0; + +- spin_lock_irqsave(&domain->lock, flags); +- + dev_data = dev_iommu_priv_get(dev); + + spin_lock(&dev_data->lock); +@@ -2179,8 +2195,6 @@ static int attach_device(struct device *dev, + out: + spin_unlock(&dev_data->lock); + +- spin_unlock_irqrestore(&domain->lock, flags); +- + return ret; + } + +@@ -2190,13 +2204,9 @@ static int attach_device(struct device *dev, + static void detach_device(struct device *dev) + { + struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); +- struct protection_domain *domain = dev_data->domain; + struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); +- unsigned long flags; + bool ppr = dev_data->ppr; + +- spin_lock_irqsave(&domain->lock, flags); +- + spin_lock(&dev_data->lock); + + /* +@@ -2220,8 +2230,6 @@ static void detach_device(struct device *dev) + out: + spin_unlock(&dev_data->lock); + +- spin_unlock_irqrestore(&domain->lock, flags); +- + /* Remove IOPF handler */ + if (ppr) + amd_iommu_iopf_remove_device(iommu, dev_data); +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-remove-protection_domain.dev_cnt-variable.patch b/queue-6.12/iommu-amd-remove-protection_domain.dev_cnt-variable.patch new file mode 100644 index 0000000000..4a622a3151 --- /dev/null +++ b/queue-6.12/iommu-amd-remove-protection_domain.dev_cnt-variable.patch @@ -0,0 +1,81 @@ +From 5fd05643b625896e03cc0fcac7f3663c18b464a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2024 06:35:47 +0000 +Subject: iommu/amd: Remove protection_domain.dev_cnt variable + +From: Vasant Hegde + +[ Upstream commit 743a4bae9fa1480e5f6837f6a55be918d6cd0e16 ] + +protection_domain->dev_list tracks list of attached devices to +domain. We can use list_* functions on dev_list to get device count. +Hence remove 'dev_cnt' variable. + +No functional change intended. + +Signed-off-by: Vasant Hegde +Reviewed-by: Suravee Suthikulpanit +Reviewed-by: Joerg Roedel +Reviewed-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/20241030063556.6104-4-vasant.hegde@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: faad224fe0f0 ("iommu/amd: Fix clone_alias() to use the original device's devid") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/amd_iommu_types.h | 1 - + drivers/iommu/amd/iommu.c | 7 +------ + 2 files changed, 1 insertion(+), 7 deletions(-) + +diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h +index df2aa1c4fafcf..d5a689a4f4397 100644 +--- a/drivers/iommu/amd/amd_iommu_types.h ++++ b/drivers/iommu/amd/amd_iommu_types.h +@@ -580,7 +580,6 @@ struct protection_domain { + u16 id; /* the domain id written to the device table */ + enum protection_domain_mode pd_mode; /* Track page table type */ + bool dirty_tracking; /* dirty tracking is enabled in the domain */ +- unsigned dev_cnt; /* devices assigned to this domain */ + unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */ + + struct mmu_notifier mn; /* mmu notifier for the SVA domain */ +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index d0e53a03eff02..cf03fe0e8b083 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -2068,7 +2068,6 @@ static int do_attach(struct iommu_dev_data *dev_data, + + /* Do reference counting */ + domain->dev_iommu[iommu->index] += 1; +- domain->dev_cnt += 1; + + /* Setup GCR3 table */ + if (pdom_is_sva_capable(domain)) { +@@ -2101,7 +2100,6 @@ static void do_detach(struct iommu_dev_data *dev_data) + + /* decrease reference counters - needs to happen after the flushes */ + domain->dev_iommu[iommu->index] -= 1; +- domain->dev_cnt -= 1; + } + + /* +@@ -2274,16 +2272,13 @@ static void cleanup_domain(struct protection_domain *domain) + + lockdep_assert_held(&domain->lock); + +- if (!domain->dev_cnt) +- return; +- + while (!list_empty(&domain->dev_list)) { + entry = list_first_entry(&domain->dev_list, + struct iommu_dev_data, list); + BUG_ON(!entry->domain); + do_detach(entry); + } +- WARN_ON(domain->dev_cnt != 0); ++ WARN_ON(!list_empty(&domain->dev_list)); + } + + void protection_domain_free(struct protection_domain *domain) +-- +2.53.0 + diff --git a/queue-6.12/iommu-amd-xarray-to-track-protection_domain-iommu-li.patch b/queue-6.12/iommu-amd-xarray-to-track-protection_domain-iommu-li.patch new file mode 100644 index 0000000000..8fc7c145ac --- /dev/null +++ b/queue-6.12/iommu-amd-xarray-to-track-protection_domain-iommu-li.patch @@ -0,0 +1,211 @@ +From de7bd3b986cfef2ef04c0f7bdafedc17c095de3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2024 06:35:48 +0000 +Subject: iommu/amd: xarray to track protection_domain->iommu list + +From: Vasant Hegde + +[ Upstream commit d16041124de1dea4389b5e6b330657f34f8c0492 ] + +Use xarray to track IOMMU attached to protection domain instead of +static array of MAX_IOMMUS. Also add lockdep assertion. + +Signed-off-by: Vasant Hegde +Reviewed-by: Joerg Roedel +Reviewed-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/20241030063556.6104-5-vasant.hegde@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: faad224fe0f0 ("iommu/amd: Fix clone_alias() to use the original device's devid") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/amd_iommu_types.h | 8 ++- + drivers/iommu/amd/iommu.c | 89 +++++++++++++++++++++++------ + 2 files changed, 77 insertions(+), 20 deletions(-) + +diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h +index d5a689a4f4397..f99a4b1349287 100644 +--- a/drivers/iommu/amd/amd_iommu_types.h ++++ b/drivers/iommu/amd/amd_iommu_types.h +@@ -567,6 +567,12 @@ struct pdom_dev_data { + struct list_head list; + }; + ++/* Keeps track of the IOMMUs attached to protection domain */ ++struct pdom_iommu_info { ++ struct amd_iommu *iommu; /* IOMMUs attach to protection domain */ ++ u32 refcnt; /* Count of attached dev/pasid per domain/IOMMU */ ++}; ++ + /* + * This structure contains generic data for IOMMU protection domains + * independent of their use. +@@ -580,7 +586,7 @@ struct protection_domain { + u16 id; /* the domain id written to the device table */ + enum protection_domain_mode pd_mode; /* Track page table type */ + bool dirty_tracking; /* dirty tracking is enabled in the domain */ +- unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */ ++ struct xarray iommu_array; /* per-IOMMU reference count */ + + struct mmu_notifier mn; /* mmu notifier for the SVA domain */ + struct list_head dev_data_list; /* List of pdom_dev_data */ +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index cf03fe0e8b083..d9b296e007cc7 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -1290,18 +1290,17 @@ static int iommu_completion_wait(struct amd_iommu *iommu) + + static void domain_flush_complete(struct protection_domain *domain) + { +- int i; ++ struct pdom_iommu_info *pdom_iommu_info; ++ unsigned long i; + +- for (i = 0; i < amd_iommu_get_num_iommus(); ++i) { +- if (domain && !domain->dev_iommu[i]) +- continue; ++ lockdep_assert_held(&domain->lock); + +- /* +- * Devices of this domain are behind this IOMMU +- * We need to wait for completion of all commands. +- */ +- iommu_completion_wait(amd_iommus[i]); +- } ++ /* ++ * Devices of this domain are behind this IOMMU ++ * We need to wait for completion of all commands. ++ */ ++ xa_for_each(&domain->iommu_array, i, pdom_iommu_info) ++ iommu_completion_wait(pdom_iommu_info->iommu); + } + + static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid) +@@ -1483,21 +1482,22 @@ static int domain_flush_pages_v2(struct protection_domain *pdom, + static int domain_flush_pages_v1(struct protection_domain *pdom, + u64 address, size_t size) + { ++ struct pdom_iommu_info *pdom_iommu_info; + struct iommu_cmd cmd; +- int ret = 0, i; ++ int ret = 0; ++ unsigned long i; ++ ++ lockdep_assert_held(&pdom->lock); + + build_inv_iommu_pages(&cmd, address, size, + pdom->id, IOMMU_NO_PASID, false); + +- for (i = 0; i < amd_iommu_get_num_iommus(); ++i) { +- if (!pdom->dev_iommu[i]) +- continue; +- ++ xa_for_each(&pdom->iommu_array, i, pdom_iommu_info) { + /* + * Devices of this domain are behind this IOMMU + * We need a TLB flush + */ +- ret |= iommu_queue_command(amd_iommus[i], &cmd); ++ ret |= iommu_queue_command(pdom_iommu_info->iommu, &cmd); + } + + return ret; +@@ -1536,6 +1536,8 @@ static void __domain_flush_pages(struct protection_domain *domain, + void amd_iommu_domain_flush_pages(struct protection_domain *domain, + u64 address, size_t size) + { ++ lockdep_assert_held(&domain->lock); ++ + if (likely(!amd_iommu_np_cache)) { + __domain_flush_pages(domain, address, size); + +@@ -2051,6 +2053,50 @@ static void destroy_gcr3_table(struct iommu_dev_data *dev_data, + free_gcr3_table(gcr3_info); + } + ++static int pdom_attach_iommu(struct amd_iommu *iommu, ++ struct protection_domain *pdom) ++{ ++ struct pdom_iommu_info *pdom_iommu_info, *curr; ++ ++ pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index); ++ if (pdom_iommu_info) { ++ pdom_iommu_info->refcnt++; ++ return 0; ++ } ++ ++ pdom_iommu_info = kzalloc(sizeof(*pdom_iommu_info), GFP_ATOMIC); ++ if (!pdom_iommu_info) ++ return -ENOMEM; ++ ++ pdom_iommu_info->iommu = iommu; ++ pdom_iommu_info->refcnt = 1; ++ ++ curr = xa_cmpxchg(&pdom->iommu_array, iommu->index, ++ NULL, pdom_iommu_info, GFP_ATOMIC); ++ if (curr) { ++ kfree(pdom_iommu_info); ++ return -ENOSPC; ++ } ++ ++ return 0; ++} ++ ++static void pdom_detach_iommu(struct amd_iommu *iommu, ++ struct protection_domain *pdom) ++{ ++ struct pdom_iommu_info *pdom_iommu_info; ++ ++ pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index); ++ if (!pdom_iommu_info) ++ return; ++ ++ pdom_iommu_info->refcnt--; ++ if (pdom_iommu_info->refcnt == 0) { ++ xa_erase(&pdom->iommu_array, iommu->index); ++ kfree(pdom_iommu_info); ++ } ++} ++ + static int do_attach(struct iommu_dev_data *dev_data, + struct protection_domain *domain) + { +@@ -2067,13 +2113,17 @@ static int do_attach(struct iommu_dev_data *dev_data, + cfg->amd.nid = dev_to_node(dev_data->dev); + + /* Do reference counting */ +- domain->dev_iommu[iommu->index] += 1; ++ ret = pdom_attach_iommu(iommu, domain); ++ if (ret) ++ return ret; + + /* Setup GCR3 table */ + if (pdom_is_sva_capable(domain)) { + ret = init_gcr3_table(dev_data, domain); +- if (ret) ++ if (ret) { ++ pdom_detach_iommu(iommu, domain); + return ret; ++ } + } + + return ret; +@@ -2099,7 +2149,7 @@ static void do_detach(struct iommu_dev_data *dev_data) + list_del(&dev_data->list); + + /* decrease reference counters - needs to happen after the flushes */ +- domain->dev_iommu[iommu->index] -= 1; ++ pdom_detach_iommu(iommu, domain); + } + + /* +@@ -2307,6 +2357,7 @@ struct protection_domain *protection_domain_alloc(unsigned int type, int nid) + spin_lock_init(&domain->lock); + INIT_LIST_HEAD(&domain->dev_list); + INIT_LIST_HEAD(&domain->dev_data_list); ++ xa_init(&domain->iommu_array); + domain->iop.pgtbl.cfg.amd.nid = nid; + + switch (type) { +-- +2.53.0 + diff --git a/queue-6.12/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch b/queue-6.12/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch new file mode 100644 index 0000000000..f3ac6111dd --- /dev/null +++ b/queue-6.12/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch @@ -0,0 +1,65 @@ +From 8a044fa00affd1f97c725ab44ad9b418ddd02403 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:36:34 -0700 +Subject: iommu/tegra241-cmdqv: Set supports_cmd op in tegra241_vcmdq_hw_init() + +From: Nicolin Chen + +[ Upstream commit 803e41f36d227022ab9bbe780c82283fd4713b2e ] + +vintf->hyp_own is finalized in tegra241_vintf_hw_init(). On the other hand, +tegra241_vcmdq_alloc_smmu_cmdq() is called via an init_structures callback, +which is earlier than tegra241_vintf_hw_init(). + +This results in the supports_cmd op always being set to the guest function, +although this doesn't break any functionality nor have some noticeable perf +impact since non-invalidation commands are not issued in the perf sensitive +context. + +Fix this by moving supports_cmd to tegra241_vcmdq_hw_init(). + +After this change, + - For a guest kernel, this will be a status quo + - For a host kernel, non-invalidation commands will be issued to VCMDQ(s) + +Fixes: a9d40285bdef ("iommu/tegra241-cmdqv: Limit CMDs for VCMDQs of a guest owned VINTF") +Reported-by: Eric Auger +Reported-by: Shameer Kolothum +Closes: https://lore.kernel.org/qemu-devel/CH3PR12MB754836BEE54E39B30C7210C0AB44A@CH3PR12MB7548.namprd12.prod.outlook.com/ +Signed-off-by: Nicolin Chen +Reviewed-by: Eric Auger +Tested-by: Shameer Kolothum +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +index dd7d030d2e890..a76839cf571d2 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c ++++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +@@ -387,6 +387,10 @@ static int tegra241_vcmdq_hw_init(struct tegra241_vcmdq *vcmdq) + /* Reset VCMDQ */ + tegra241_vcmdq_hw_deinit(vcmdq); + ++ /* vintf->hyp_own is a HW state finalized in tegra241_vintf_hw_init() */ ++ if (!vcmdq->vintf->hyp_own) ++ vcmdq->cmdq.supports_cmd = tegra241_guest_vcmdq_supports_cmd; ++ + /* Configure and enable VCMDQ */ + writeq_relaxed(vcmdq->cmdq.q.q_base, REG_VCMDQ_PAGE1(vcmdq, BASE)); + +@@ -514,9 +518,6 @@ static int tegra241_vcmdq_alloc_smmu_cmdq(struct tegra241_vcmdq *vcmdq) + q->q_base = q->base_dma & VCMDQ_ADDR; + q->q_base |= FIELD_PREP(VCMDQ_LOG2SIZE, q->llq.max_n_shift); + +- if (!vcmdq->vintf->hyp_own) +- cmdq->supports_cmd = tegra241_guest_vcmdq_supports_cmd; +- + return arm_smmu_cmdq_init(smmu, cmdq); + } + +-- +2.53.0 + diff --git a/queue-6.12/iommufd-vfio-compatibility-extension-check-for-noiom.patch b/queue-6.12/iommufd-vfio-compatibility-extension-check-for-noiom.patch new file mode 100644 index 0000000000..5c9aa3737f --- /dev/null +++ b/queue-6.12/iommufd-vfio-compatibility-extension-check-for-noiom.patch @@ -0,0 +1,40 @@ +From 18f6cb15f16c6ab90f418e84bab4e1f3584340f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 10:36:36 -0800 +Subject: iommufd: vfio compatibility extension check for noiommu mode + +From: Jacob Pan + +[ Upstream commit 7147ec874ea08c322d779d8eba28946e294ed1f3 ] + +VFIO_CHECK_EXTENSION should return false for TYPE1_IOMMU variants when +in NO-IOMMU mode and IOMMUFD compat container is set. This change makes +the behavior match VFIO_CONTAINER in noiommu mode. It also prevents +userspace from incorrectly attempting to use TYPE1 IOMMU operations +in a no-iommu context. + +Fixes: d624d6652a65 ("iommufd: vfio container FD ioctl compatibility") +Link: https://patch.msgid.link/r/20260213183636.3340-1-jacob.pan@linux.microsoft.com +Signed-off-by: Jacob Pan +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommufd/vfio_compat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c +index a3ad5f0b6c59d..80a2f7faee9bb 100644 +--- a/drivers/iommu/iommufd/vfio_compat.c ++++ b/drivers/iommu/iommufd/vfio_compat.c +@@ -283,7 +283,7 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx, + case VFIO_TYPE1_IOMMU: + case VFIO_TYPE1v2_IOMMU: + case VFIO_UNMAP_ALL: +- return 1; ++ return !ictx->no_iommu_mode; + + case VFIO_NOIOMMU_IOMMU: + return IS_ENABLED(CONFIG_VFIO_NOIOMMU); +-- +2.53.0 + diff --git a/queue-6.12/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch b/queue-6.12/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch new file mode 100644 index 0000000000..7d2741f994 --- /dev/null +++ b/queue-6.12/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch @@ -0,0 +1,114 @@ +From d47a1008216623d61fabc9b283f3a776029facd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:06:01 +0800 +Subject: ipmi: ssif_bmc: change log level to dbg in irq callback + +From: Jian Zhang + +[ Upstream commit c9c99b7b7051eb7121b3224bfce181fb023b0269 ] + +Long-running tests indicate that this logging can occasionally disrupt +timing and lead to request/response corruption. + +Irq handler need to be executed as fast as possible, +most I2C slave IRQ implementations are byte-level, logging here +can significantly affect transfer behavior and timing. It is recommended +to use dev_dbg() for these messages. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-4-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index d3a088d758fce..c5492e17ae573 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -568,7 +568,7 @@ static void process_request_part(struct ssif_bmc_ctx *ssif_bmc) + len = ssif_bmc->request.len + part->length; + /* Do the bound check here, not allow the request len exceed 254 bytes */ + if (len > IPMI_SSIF_PAYLOAD_MAX) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: Request exceeded 254 bytes, aborting"); + /* Request too long, aborting */ + ssif_bmc->aborting = true; +@@ -614,7 +614,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected READ REQUESTED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -623,7 +623,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + if (!supported_read_cmd(ssif_bmc->part_buf.smbus_cmd)) { +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", + ssif_bmc->part_buf.smbus_cmd); + ssif_bmc->aborting = true; + } +@@ -658,7 +658,7 @@ static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_SMBUS_CMD) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected READ PROCESSED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -683,7 +683,7 @@ static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + } else if (ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE REQUEST in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -698,7 +698,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + { + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -708,7 +708,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + if (!supported_write_cmd(ssif_bmc->part_buf.smbus_cmd)) { +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", + ssif_bmc->part_buf.smbus_cmd); + ssif_bmc->aborting = true; + } +@@ -737,7 +737,7 @@ static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_SMBUS_CMD || + ssif_bmc->state == SSIF_ABORTING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected SLAVE STOP in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_READY; +@@ -804,7 +804,7 @@ static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 + break; + + default: +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); + break; + } + +-- +2.53.0 + diff --git a/queue-6.12/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch b/queue-6.12/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch new file mode 100644 index 0000000000..2463c19569 --- /dev/null +++ b/queue-6.12/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch @@ -0,0 +1,88 @@ +From ac05fc675a8bda8810e86c7e749eeab517932fa0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:06:00 +0800 +Subject: ipmi: ssif_bmc: fix message desynchronization after truncated + response + +From: Jian Zhang + +[ Upstream commit 1d38e849adb6851ee280aa1a1d687b2181549a66 ] + +A truncated response, caused by host power-off, or other conditions, +can lead to message desynchronization. + +Raw trace data (STOP loss scenario, add state transition comment): + +1. T-1: Read response phase (SSIF_RES_SENDING) +8271.955342 WR_RCV [03] <- Read polling cmd +8271.955348 RD_REQ [04] <== SSIF_RES_SENDING <- start sending response +8271.955436 RD_PRO [b4] +8271.955527 RD_PRO [00] +8271.955618 RD_PRO [c1] +8271.955707 RD_PRO [00] +8271.955814 RD_PRO [ad] <== SSIF_RES_SENDING <- last byte + <- !! STOP lost (truncated response) + +2. T: New Write request arrives, BMC still in SSIF_RES_SENDING +8271.967973 WR_REQ [] <== SSIF_RES_SENDING >> SSIF_ABORTING <- log: unexpected WR_REQ in RES_SENDING +8271.968447 WR_RCV [02] <== SSIF_ABORTING <- do nothing +8271.968452 WR_RCV [02] <== SSIF_ABORTING <- do nothing +8271.968454 WR_RCV [18] <== SSIF_ABORTING <- do nothing +8271.968456 WR_RCV [01] <== SSIF_ABORTING <- do nothing +8271.968458 WR_RCV [66] <== SSIF_ABORTING <- do nothing +8271.978714 STOP [] <== SSIF_ABORTING >> SSIF_READY <- log: unexpected SLAVE STOP in state=SSIF_ABORTING + +3. T+1: Next Read polling, treated as a fresh transaction +8271.979125 WR_REQ [] <== SSIF_READY >> SSIF_START +8271.979326 WR_RCV [03] <== SSIF_START >> SSIF_SMBUS_CMD <- smbus_cmd=0x03 +8271.979331 RD_REQ [04] <== SSIF_RES_SENDING <- sending response +8271.979427 RD_PRO [b4] <- !! this is T's stale response -> desynchronization + +When in SSIF_ABORTING state, a newly arrived command should still be +handled to avoid dropping the request or causing message +desynchronization. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-3-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index c2e59899f1c4c..d3a088d758fce 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -457,6 +457,15 @@ static bool supported_write_cmd(u8 cmd) + return false; + } + ++static bool supported_write_start_cmd(u8 cmd) ++{ ++ if (cmd == SSIF_IPMI_SINGLEPART_WRITE || ++ cmd == SSIF_IPMI_MULTIPART_WRITE_START) ++ return true; ++ ++ return false; ++} ++ + /* Process the IPMI response that will be read by master */ + static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + { +@@ -708,6 +717,11 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state = SSIF_ABORTING; + else + ssif_bmc->state = SSIF_REQ_RECVING; ++ } else if (ssif_bmc->state == SSIF_ABORTING) { ++ if (supported_write_start_cmd(*val)) { ++ ssif_bmc->state = SSIF_SMBUS_CMD; ++ ssif_bmc->aborting = false; ++ } + } + + /* This is response sending state */ +-- +2.53.0 + diff --git a/queue-6.12/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch b/queue-6.12/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch new file mode 100644 index 0000000000..4e2469dfcc --- /dev/null +++ b/queue-6.12/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch @@ -0,0 +1,42 @@ +From e762771297c02c8cd74ad0b8931352c45caf4bce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:05:59 +0800 +Subject: ipmi: ssif_bmc: fix missing check for copy_to_user() partial failure + +From: Jian Zhang + +[ Upstream commit ea641be7a4faee4351f9c5ed6b188e1bbf5586a6 ] + +copy_to_user() returns the number of bytes that could not be copied, +with a non-zero value indicating a partial or complete failure. The +current code only checks for negative return values and treats all +non-negative results as success. + +Treating any positive return value from copy_to_user() as +an error and returning -EFAULT. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-2-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index 310f17dd9511a..c2e59899f1c4c 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -163,6 +163,8 @@ static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + ret = copy_to_user(buf, &msg, count); ++ if (ret > 0) ++ ret = -EFAULT; + } + + return (ret < 0) ? ret : count; +-- +2.53.0 + diff --git a/queue-6.12/ipv4-udp-fix-typos-in-comments.patch b/queue-6.12/ipv4-udp-fix-typos-in-comments.patch new file mode 100644 index 0000000000..efe46a3bf1 --- /dev/null +++ b/queue-6.12/ipv4-udp-fix-typos-in-comments.patch @@ -0,0 +1,60 @@ +From 980cb829755a4267b4c8bfd57d5b50136eedcb54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 7 Sep 2025 12:25:32 -0700 +Subject: ipv4: udp: fix typos in comments + +From: Alok Tiwari + +[ Upstream commit d436b5abba4f80e968b3ff83be4363c7aedcc799 ] + +Correct typos in ipv4/udp.c comments for clarity: +"Encapulation" -> "Encapsulation" +"measureable" -> "measurable" +"tacking care" -> "taking care" + +No functional changes. + +Signed-off-by: Alok Tiwari +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20250907192535.3610686-1-alok.a.tiwari@oracle.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: b80a95ccf160 ("udp: Force compute_score to always inline") +Signed-off-by: Sasha Levin +--- + net/ipv4/udp.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index 27694334e410e..0d4a6abdfb963 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -68,7 +68,7 @@ + * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which + * Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind + * a single port at the same time. +- * Derek Atkins : Add Encapulation Support ++ * Derek Atkins : Add Encapsulation Support + * James Chapman : Add L2TP encapsulation type. + */ + +@@ -510,7 +510,7 @@ static struct sock *udp4_lib_lookup2(const struct net *net, + + /* compute_score is too long of a function to be + * inlined, and calling it again here yields +- * measureable overhead for some ++ * measurable overhead for some + * workloads. Work around it by jumping + * backwards to rescore 'result'. + */ +@@ -2414,7 +2414,7 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, + return 0; + } + +-/* wrapper for udp_queue_rcv_skb tacking care of csum conversion and ++/* wrapper for udp_queue_rcv_skb taking care of csum conversion and + * return code conversion for ip layer consumption + */ + static int udp_unicast_rcv_skb(struct sock *sk, struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-6.12/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch b/queue-6.12/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch new file mode 100644 index 0000000000..d794f6225a --- /dev/null +++ b/queue-6.12/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch @@ -0,0 +1,71 @@ +From c4a9ad8a111bd2004ff5accad74c9b77a43e8d22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 10:35:05 +0000 +Subject: ipv6: fix possible UAF in icmpv6_rcv() + +From: Eric Dumazet + +[ Upstream commit f996edd7615e686ada141b7f3395025729ff8ccb ] + +Caching saddr and daddr before pskb_pull() is problematic +since skb->head can change. + +Remove these temporary variables: + +- We only access &ipv6_hdr(skb)->saddr and &ipv6_hdr(skb)->daddr + when net_dbg_ratelimited() is called in the slow path. + +- Avoid potential future misuse after pskb_pull() call. + +Fixes: 4b3418fba0fe ("ipv6: icmp: include addresses in debug messages") +Signed-off-by: Eric Dumazet +Reviewed-by: Fernando Fernandez Mancera +Reviewed-by: Joe Damato +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260416103505.2380753-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/icmp.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index 387400829b207..229ae205450d3 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -910,7 +910,6 @@ static int icmpv6_rcv(struct sk_buff *skb) + struct net *net = dev_net_rcu(skb->dev); + struct net_device *dev = icmp6_dev(skb); + struct inet6_dev *idev = __in6_dev_get(dev); +- const struct in6_addr *saddr, *daddr; + struct icmp6hdr *hdr; + u8 type; + +@@ -941,12 +940,10 @@ static int icmpv6_rcv(struct sk_buff *skb) + + __ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS); + +- saddr = &ipv6_hdr(skb)->saddr; +- daddr = &ipv6_hdr(skb)->daddr; +- + if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { + net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + goto csum_error; + } + +@@ -1029,7 +1026,8 @@ static int icmpv6_rcv(struct sk_buff *skb) + break; + + net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + + /* + * error of unknown type. +-- +2.53.0 + diff --git a/queue-6.12/ipv6-udp-fix-typos-in-comments.patch b/queue-6.12/ipv6-udp-fix-typos-in-comments.patch new file mode 100644 index 0000000000..b5e2666400 --- /dev/null +++ b/queue-6.12/ipv6-udp-fix-typos-in-comments.patch @@ -0,0 +1,60 @@ +From b70a15fb00857e8f3b4bf428360a35951916f4ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Sep 2025 05:26:07 -0700 +Subject: ipv6: udp: fix typos in comments + +From: Alok Tiwari + +[ Upstream commit ac36dea3bc85c2cde87e490736708032328dfbdc ] + +Correct typos in ipv6/udp.c comments: +"execeeds" -> "exceeds" +"tacking care" -> "taking care" +"measureable" -> "measurable" + +No functional changes. + +Signed-off-by: Alok Tiwari +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20250909122611.3711859-1-alok.a.tiwari@oracle.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: b80a95ccf160 ("udp: Force compute_score to always inline") +Signed-off-by: Sasha Levin +--- + net/ipv6/udp.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index 9b93df668025d..bfda1f318b779 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -248,7 +248,7 @@ static struct sock *udp6_lib_lookup2(const struct net *net, + + /* compute_score is too long of a function to be + * inlined, and calling it again here yields +- * measureable overhead for some ++ * measurable overhead for some + * workloads. Work around it by jumping + * backwards to rescore 'result'. + */ +@@ -364,7 +364,7 @@ struct sock *udp6_lib_lookup(const struct net *net, const struct in6_addr *saddr + EXPORT_SYMBOL_GPL(udp6_lib_lookup); + #endif + +-/* do not use the scratch area len for jumbogram: their length execeeds the ++/* do not use the scratch area len for jumbogram: their length exceeds the + * scratch area space; note that the IP6CB flags is still in the first + * cacheline, so checking for jumbograms is cheap + */ +@@ -964,7 +964,7 @@ static void udp6_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) + sk->sk_rx_dst_cookie = rt6_get_cookie(dst_rt6_info(dst)); + } + +-/* wrapper for udp_queue_rcv_skb tacking care of csum conversion and ++/* wrapper for udp_queue_rcv_skb taking care of csum conversion and + * return code conversion for ip layer consumption + */ + static int udp6_unicast_rcv_skb(struct sock *sk, struct sk_buff *skb, +-- +2.53.0 + diff --git a/queue-6.12/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch b/queue-6.12/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch new file mode 100644 index 0000000000..8465864e5d --- /dev/null +++ b/queue-6.12/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch @@ -0,0 +1,97 @@ +From 7065e28ed80d71935b94769c075b2cd5c048b4a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:40:29 +0800 +Subject: ipvs: fix MTU check for GSO packets in tunnel mode + +From: Yingnan Zhang <342144303@qq.com> + +[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ] + +Currently, IPVS skips MTU checks for GSO packets by excluding them with +the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel +mode encapsulates GSO packets with IPIP headers. + +The issue manifests in two ways: + +1. MTU violation after encapsulation: + When a GSO packet passes through IPVS tunnel mode, the original MTU + check is bypassed. After adding the IPIP tunnel header, the packet + size may exceed the outgoing interface MTU, leading to unexpected + fragmentation at the IP layer. + +2. Fragmentation with problematic IP IDs: + When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments + is fragmented after encapsulation, each segment gets a sequentially + incremented IP ID (0, 1, 2, ...). This happens because: + + a) The GSO packet bypasses MTU check and gets encapsulated + b) At __ip_finish_output, the oversized GSO packet is split into + separate SKBs (one per segment), with IP IDs incrementing + c) Each SKB is then fragmented again based on the actual MTU + + This sequential IP ID allocation differs from the expected behavior + and can cause issues with fragment reassembly and packet tracking. + +Fix this by properly validating GSO packets using +skb_gso_validate_network_len(). This function correctly validates +whether the GSO segments will fit within the MTU after segmentation. If +validation fails, send an ICMP Fragmentation Needed message to enable +proper PMTU discovery. + +Fixes: 4cdd34084d53 ("netfilter: nf_conntrack_ipv6: improve fragmentation handling") +Signed-off-by: Yingnan Zhang <342144303@qq.com> +Acked-by: Julian Anastasov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index 8892f261451e9..ed8b2616cf178 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -103,6 +103,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest) + return dest_dst; + } + ++/* Based on ip_exceeds_mtu(). */ ++static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) ++{ ++ if (skb->len <= mtu) ++ return false; ++ ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) ++ return false; ++ ++ return true; ++} ++ + static inline bool + __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + { +@@ -112,10 +124,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + */ + if (IP6CB(skb)->frag_max_size > mtu) + return true; /* largest fragment violate MTU */ +- } +- else if (skb->len > mtu && !skb_is_gso(skb)) { ++ } else if (ip_vs_exceeds_mtu(skb, mtu)) + return true; /* Packet size violate MTU size */ +- } ++ + return false; + } + +@@ -233,7 +244,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, + return true; + + if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && +- skb->len > mtu && !skb_is_gso(skb) && ++ ip_vs_exceeds_mtu(skb, mtu) && + !ip_vs_iph_icmp(ipvsh))) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); +-- +2.53.0 + diff --git a/queue-6.12/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch b/queue-6.12/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch new file mode 100644 index 0000000000..335b84af20 --- /dev/null +++ b/queue-6.12/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch @@ -0,0 +1,48 @@ +From bf33c80e12247086ccd3e5c3360c3950edbfb39a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Feb 2026 18:43:44 -0500 +Subject: irqchip/irq-pic32-evic: Address warning related to wrong printf() + formatter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 86be659415b0ddefebc3120e309091aa215a9064 ] + +This driver is currently only build on 32 bit MIPS systems. When building +it on x86_64, the following warning occurs: + + drivers/irqchip/irq-pic32-evic.c: In function ‘pic32_ext_irq_of_init’: + ./include/linux/kern_levels.h:5:25: error: format ‘%d’ expects argument of type + ‘int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] + +Update the printf() formatter in preparation for allowing this driver to +be compiled on all architectures. + +Fixes: aaa8666ada780 ("IRQCHIP: irq-pic32-evic: Add support for PIC32 interrupt controller") +Signed-off-by: Brian Masney +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260222-irqchip-pic32-v1-1-37f50d1f14af@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-pic32-evic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c +index eb6ca516a1664..9b309d8ec20c3 100644 +--- a/drivers/irqchip/irq-pic32-evic.c ++++ b/drivers/irqchip/irq-pic32-evic.c +@@ -196,7 +196,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain) + + of_property_for_each_u32(node, pname, hwirq) { + if (i >= ARRAY_SIZE(priv->ext_irqs)) { +- pr_warn("More than %d external irq, skip rest\n", ++ pr_warn("More than %zu external irq, skip rest\n", + ARRAY_SIZE(priv->ext_irqs)); + break; + } +-- +2.53.0 + diff --git a/queue-6.12/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch b/queue-6.12/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch new file mode 100644 index 0000000000..45e9dd0c34 --- /dev/null +++ b/queue-6.12/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch @@ -0,0 +1,57 @@ +From 8cd7093b70820cf267cd49443d5269f09481c0a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 16:51:16 +0200 +Subject: kbuild: builddeb - avoid recompiles for non-cross-compiles + +From: Mathias Krause + +[ Upstream commit 2452dcf4d740effff5aa71b7f6529ee8c04fd8f6 ] + +Commit e2c318225ac1 ("kbuild: deb-pkg: add +pkg.linux-upstream.nokernelheaders build profile") changed how +install-extmod-build gets called, making it always rebuild the host +programs below scripts/ if HOSTCC wasn't specified with its full triplet +on the make command line. That is, apparently, needed to fix up commit +f1d87664b82a ("kbuild: cross-compile linux-headers package when +possible") for cross-compiles. However, in the much more common case of +non-cross-compile builds this will lead to unnecessary rebuilding of +host tools including gcc plugins. This, in turn, will lead to a full +kernel rebuild on the next 'make bindeb-pkg' which is unfortunate. + +Avoid that by only triggering the rebuild of host tools for actual +cross-compile builds. + +Signed-off-by: Mathias Krause +Fixes: e2c318225ac1 ("kbuild: deb-pkg: add pkg.linux-upstream.nokernelheaders build profile") +Cc: Masahiro Yamada +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Link: https://patch.msgid.link/20260402145116.1010901-1-minipli@grsecurity.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + scripts/package/builddeb | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/scripts/package/builddeb b/scripts/package/builddeb +index fb686fd3266f0..1d7d4838eebd4 100755 +--- a/scripts/package/builddeb ++++ b/scripts/package/builddeb +@@ -125,7 +125,13 @@ install_kernel_headers () { + pdir=debian/$1 + version=${1#linux-headers-} + +- CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ # Override $CC only for cross-compiles, to not unnecessarily rebuild ++ # scripts/ including plugins, which may lead to a full kernel rebuild. ++ if [ -n "${CROSS_COMPILE}" ]; then ++ CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ else ++ "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ fi + + mkdir -p $pdir/lib/modules/$version/ + ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build +-- +2.53.0 + diff --git a/queue-6.12/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch b/queue-6.12/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch new file mode 100644 index 0000000000..faaf47ed1b --- /dev/null +++ b/queue-6.12/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch @@ -0,0 +1,54 @@ +From 5c7e54c8e7968657243ee1939296d551a408603c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:55 +0900 +Subject: ksmbd: destroy async_ida in ksmbd_conn_free() + +From: DaeMyung Kang + +[ Upstream commit b32c8db48212a34998c36d0bbc05b29d5c407ef5 ] + +When per-connection async_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from the connection teardown path but no matching +ida_destroy() was added. The connection is therefore freed with the +IDA's backing xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +connection is freed. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/connection.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c +index 8470aba1233a9..1610b4d2fd414 100644 +--- a/fs/smb/server/connection.c ++++ b/fs/smb/server/connection.c +@@ -41,6 +41,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn) + kfree(conn->preauth_info); + kfree(conn->mechToken); + if (atomic_dec_and_test(&conn->refcnt)) { ++ /* ++ * async_ida is embedded in struct ksmbd_conn, so pair ++ * ida_destroy() with the final kfree() rather than with ++ * the unconditional field teardown above. This keeps ++ * the IDA valid for the entire lifetime of the struct, ++ * even while other refcount holders (oplock / vfs ++ * durable handles) still reference the connection. ++ */ ++ ida_destroy(&conn->async_ida); + conn->transport->ops->free_transport(conn->transport); + kfree(conn); + } +-- +2.53.0 + diff --git a/queue-6.12/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch b/queue-6.12/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch new file mode 100644 index 0000000000..b61fa195c2 --- /dev/null +++ b/queue-6.12/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch @@ -0,0 +1,71 @@ +From d370591ad5cd23c18b30dc354a045f1b024291fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:54 +0900 +Subject: ksmbd: destroy tree_conn_ida in ksmbd_session_destroy() + +From: DaeMyung Kang + +[ Upstream commit c049ee14eb4343b69b6f7755563f961f5e153423 ] + +When per-session tree_conn_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from ksmbd_session_destroy() but no matching ida_destroy() +was added. The session is therefore freed with the IDA's backing +xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +enclosing session is freed. + +Also move ida_init() to right after the session is allocated so that +it is always paired with the destroy call even on the early error +paths of __session_create() (ksmbd_init_file_table() or +__init_smb2_session() failures), both of which jump to the error +label and invoke ksmbd_session_destroy() on a partially initialised +session. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index 352cf9e47ebeb..faba7a502c0b7 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -171,6 +171,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) + free_channel_list(sess); + kfree(sess->Preauth_HashValue); + ksmbd_release_id(&session_ida, sess->id); ++ ida_destroy(&sess->tree_conn_ida); + kfree(sess); + } + +@@ -445,6 +446,8 @@ static struct ksmbd_session *__session_create(int protocol) + if (!sess) + return NULL; + ++ ida_init(&sess->tree_conn_ida); ++ + if (ksmbd_init_file_table(&sess->file_table)) + goto error; + +@@ -464,8 +467,6 @@ static struct ksmbd_session *__session_create(int protocol) + if (ret) + goto error; + +- ida_init(&sess->tree_conn_ida); +- + down_write(&sessions_table_lock); + hash_add(sessions_table, &sess->hlist, sess->id); + up_write(&sessions_table_lock); +-- +2.53.0 + diff --git a/queue-6.12/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch b/queue-6.12/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch new file mode 100644 index 0000000000..941d42cb01 --- /dev/null +++ b/queue-6.12/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch @@ -0,0 +1,64 @@ +From 64df97d541fa58152d03a9f4dccc9fed54118c64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 03:45:11 +0900 +Subject: ksmbd: fix durable fd leak on ClientGUID mismatch in durable v2 open + +From: DaeMyung Kang + +[ Upstream commit 804054d19886ac6628883d82410f6ee42a818664 ] + +ksmbd_lookup_fd_cguid() returns a ksmbd_file with its refcount +incremented via ksmbd_fp_get(). parse_durable_handle_context() in +the DURABLE_REQ_V2 case properly releases this reference on every +path inside the ClientGUID-match branch, either by calling +ksmbd_put_durable_fd() or by transferring ownership to dh_info->fp +for a successful reconnect. However, when an entry exists in the +global file table with the same CreateGuid but a different +ClientGUID, the code simply falls through to the new-open path +without dropping the reference obtained from ksmbd_lookup_fd_cguid(). + +Per MS-SMB2 section 3.3.5.9.10 ("Handling the +SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context"), the server +MUST locate an Open whose Open.CreateGuid matches the request's +CreateGuid AND whose Open.ClientGuid matches the ClientGuid of the +connection that received the request. If no such Open is found, the +server MUST continue with the normal open execution phase. A +CreateGuid hit with a ClientGUID mismatch is therefore the +"Open not found" case: proceeding with a new open is correct, but +the reference obtained purely as a side effect of the lookup must +not be leaked. + +Repeated requests that hit this mismatch pin global_ft entries, +prevent __ksmbd_close_fd() from ever running for the corresponding +files, and defeat the durable scavenger, leading to long-lived +resource leaks. + +Release the reference in the mismatch path and clear dh_info->fp so +subsequent logic does not mistake a non-matching lookup result for +a reconnect target. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 29fbdada7259a..700d9da3c65a9 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -2849,6 +2849,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work, + dh_info->reconnected = true; + goto out; + } ++ ksmbd_put_durable_fd(dh_info->fp); ++ dh_info->fp = NULL; + } + + if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || +-- +2.53.0 + diff --git a/queue-6.12/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch b/queue-6.12/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch new file mode 100644 index 0000000000..42d8ffb25d --- /dev/null +++ b/queue-6.12/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch @@ -0,0 +1,73 @@ +From ab7619a1a2021c8edfce33e2a246f052d9d3c84a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 22:31:12 -0400 +Subject: ksmbd: fix use-after-free from async crypto on Qualcomm crypto engine + +From: Joshua Klinesmith + +[ Upstream commit 3e298897f41c61450c2e7a4f457e8b2485eb35b3 ] + +ksmbd_crypt_message() sets a NULL completion callback on AEAD requests +and does not handle the -EINPROGRESS return code from async hardware +crypto engines like the Qualcomm Crypto Engine (QCE). When QCE returns +-EINPROGRESS, ksmbd treats it as an error and immediately frees the +request while the hardware DMA operation is still in flight. The DMA +completion callback then dereferences freed memory, causing a NULL +pointer crash: + + pc : qce_skcipher_done+0x24/0x174 + lr : vchan_complete+0x230/0x27c + ... + el1h_64_irq+0x68/0x6c + ksmbd_free_work_struct+0x20/0x118 [ksmbd] + ksmbd_exit_file_cache+0x694/0xa4c [ksmbd] + +Use the standard crypto_wait_req() pattern with crypto_req_done() as +the completion callback, matching the approach used by the SMB client +in fs/smb/client/smb2ops.c. This properly handles both synchronous +engines (immediate return) and async engines (-EINPROGRESS followed +by callback notification). + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Link: https://github.com/openwrt/openwrt/issues/21822 +Signed-off-by: Joshua Klinesmith +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/auth.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index c12dcb0a47dd5..fea62d1cc4732 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -1111,6 +1111,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int rc; ++ DECLARE_CRYPTO_WAIT(wait); + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; +@@ -1197,12 +1198,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); +- aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); ++ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | ++ CRYPTO_TFM_REQ_MAY_SLEEP, ++ crypto_req_done, &wait); + +- if (enc) +- rc = crypto_aead_encrypt(req); +- else +- rc = crypto_aead_decrypt(req); ++ rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : ++ crypto_aead_decrypt(req), &wait); + if (rc) + goto free_iv; + +-- +2.53.0 + diff --git a/queue-6.12/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch b/queue-6.12/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch new file mode 100644 index 0000000000..9830ee70eb --- /dev/null +++ b/queue-6.12/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch @@ -0,0 +1,59 @@ +From 0b8071cbfabace9572fca517efcef1eeffcbb7db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 00:31:47 +0900 +Subject: ksmbd: scope conn->binding slowpath to bound sessions only + +From: Hyunwoo Kim + +[ Upstream commit b0da97c034b6107d14e537e212d4ce8b22109a58 ] + +When the binding SESSION_SETUP sets conn->binding = true, the flag stays +set after the call so that the global session lookup in +ksmbd_session_lookup_all() can find the session, which was not added to +conn->sessions. Because the flag is connection-wide, the global lookup +path will also resolve any other session by id if asked. + +Tighten the global lookup so that the returned session must have this +connection registered in its channel xarray (sess->ksmbd_chann_list). +The channel entry is installed by the existing binding_session path in +ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes +successfully, so this condition is a strict equivalent of "this +connection has been accepted as a channel of this session". Connections +that have not bound to a given session cannot reach it via the global +table. + +The existing conn->binding gate for entering the slowpath is preserved +so that non-binding connections keep the fast-path-only behavior, and +the session->state check is unchanged. + +Fixes: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel") +Signed-off-by: Hyunwoo Kim +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index faba7a502c0b7..151248e02e9eb 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -328,8 +328,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, + struct ksmbd_session *sess; + + sess = ksmbd_session_lookup(conn, id); +- if (!sess && conn->binding) ++ if (!sess && conn->binding) { + sess = ksmbd_session_lookup_slowpath(id); ++ if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) { ++ ksmbd_user_session_put(sess); ++ sess = NULL; ++ } ++ } + if (sess && sess->state != SMB2_SESSION_VALID) { + ksmbd_user_session_put(sess); + sess = NULL; +-- +2.53.0 + diff --git a/queue-6.12/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch b/queue-6.12/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch new file mode 100644 index 0000000000..bf6a9c8c68 --- /dev/null +++ b/queue-6.12/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch @@ -0,0 +1,49 @@ +From 741e3e4d9a7b7b649f640068c4d8f0a4d3026f55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:56 -0300 +Subject: ktest: Avoid undef warning when WARNINGS_FILE is unset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit 057854f8a595160656fe77ed7bf0d2403724b915 ] + +check_buildlog() probes $warnings_file with -f even when WARNINGS_FILE is +not configured. Perl warns about the uninitialized value and adds noise to +the test log, which can hide the output we actually care about. + +Check that WARNINGS_FILE is defined before testing whether the file exists. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-1-565d412f4925@suse.com +Fixes: 4283b169abfb ("ktest: Add make_warnings_file and process full warnings") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 3242a216af9e7..b18ea351c8b16 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -2483,7 +2483,7 @@ sub check_buildlog { + my $save_no_reboot = $no_reboot; + $no_reboot = 1; + +- if (-f $warnings_file) { ++ if (defined($warnings_file) && -f $warnings_file) { + open(IN, $warnings_file) or + dodie "Error opening $warnings_file"; + +-- +2.53.0 + diff --git a/queue-6.12/ktest-honor-empty-per-test-option-overrides.patch b/queue-6.12/ktest-honor-empty-per-test-option-overrides.patch new file mode 100644 index 0000000000..8b0588bef2 --- /dev/null +++ b/queue-6.12/ktest-honor-empty-per-test-option-overrides.patch @@ -0,0 +1,79 @@ +From a9043245865266741ff2ca94549eaaee653c6994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:59 -0300 +Subject: ktest: Honor empty per-test option overrides +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit a2de57a3c8192dcd67cccaff6c341b93748d799b ] + +A per-test override can clear an inherited default option by assigning an +empty value, but __set_test_option() still used option_defined() to decide +whether a per-test key existed. That turned an empty per-test assignment +back into "fall back to the default", so tests still could not clear +inherited settings. + +For example: + + DEFAULTS + (...) + LOG_FILE = /tmp/ktest-empty-override.log + CLEAR_LOG = 1 + ADD_CONFIG = /tmp/.config + + TEST_START + TEST_TYPE = build + BUILD_TYPE = nobuild + ADD_CONFIG = + +This would run the test with ADD_CONFIG[1] = /tmp/.config + +Fix by checking whether the per-test key exists before falling back. If it +does exist but is empty, treat it as unset for that test and stop the +fallback chain there. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-4-565d412f4925@suse.com +Fixes: 22c37a9ac49d ("ktest: Allow tests to undefine default options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index b18ea351c8b16..777ab6790d5db 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -4127,7 +4127,8 @@ sub __set_test_option { + + my $option = "$name\[$i\]"; + +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + +@@ -4135,7 +4136,8 @@ sub __set_test_option { + if ($i >= $test && + $i < $test + $repeat_tests{$test}) { + $option = "$name\[$test\]"; +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + } +-- +2.53.0 + diff --git a/queue-6.12/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch b/queue-6.12/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch new file mode 100644 index 0000000000..669baf3ef9 --- /dev/null +++ b/queue-6.12/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch @@ -0,0 +1,105 @@ +From ba7d10103ab807ff30508f7499c483ac8df54fab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:08:03 -0300 +Subject: ktest: Run POST_KTEST hooks on failure and cancellation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit bc6e165a452da909cef0efbc286e6695624db372 ] + +PRE_KTEST can be useful for setting up the environment and POST_KTEST to +tear it down, however POST_KTEST only runs on the normal end-of-run path. +It is skipped when ktest exits through dodie() or cancel_test(). Final +cleanup hooks are skipped. + +Factor the final hook execution into run_post_ktest(), call it from the +normal exit path and from the early exit paths, and guard it so the hook +runs at most once. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-8-565d412f4925@suse.com +Fixes: 921ed4c7208e ("ktest: Add PRE/POST_KTEST and TEST options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 777ab6790d5db..c61adcfa837af 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -98,6 +98,7 @@ my $test_type; + my $build_type; + my $build_options; + my $final_post_ktest; ++my $post_ktest_done = 0; + my $pre_ktest; + my $post_ktest; + my $pre_test; +@@ -1550,6 +1551,24 @@ sub get_test_name() { + return $name; + } + ++sub run_post_ktest { ++ my $cmd; ++ ++ return if ($post_ktest_done); ++ ++ if (defined($final_post_ktest)) { ++ $cmd = $final_post_ktest; ++ } elsif (defined($post_ktest)) { ++ $cmd = $post_ktest; ++ } else { ++ return; ++ } ++ ++ my $cp_post_ktest = eval_kernel_version($cmd); ++ run_command $cp_post_ktest; ++ $post_ktest_done = 1; ++} ++ + sub dodie { + # avoid recursion + return if ($in_die); +@@ -1609,6 +1628,7 @@ sub dodie { + if (defined($post_test)) { + run_command $post_test; + } ++ run_post_ktest; + + die @_, "\n"; + } +@@ -4244,6 +4264,7 @@ sub cancel_test { + send_email("KTEST: Your [$name] test was cancelled", + "Your test started at $script_start_time was cancelled: sig int"); + } ++ run_post_ktest; + die "\nCaught Sig Int, test interrupted: $!\n" + } + +@@ -4554,11 +4575,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { + success $i; + } + +-if (defined($final_post_ktest)) { +- +- my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; +- run_command $cp_final_post_ktest; +-} ++run_post_ktest; + + if ($opt{"POWEROFF_ON_SUCCESS"}) { + halt; +-- +2.53.0 + diff --git a/queue-6.12/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch b/queue-6.12/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch new file mode 100644 index 0000000000..65cf2370ca --- /dev/null +++ b/queue-6.12/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch @@ -0,0 +1,36 @@ +From 030455d28fc62972e2985c0a277eaef51b0210b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:30:48 +0800 +Subject: leds: lgm-sso: Remove duplicate assignments for priv->mmap + +From: Chen Ni + +[ Upstream commit 7186d0330c3f3e86de577687a82f4ebd96dcb5ac ] + +Remove duplicate assignment of priv->mmap in intel_sso_led_probe(). + +Fixes: fba8a6f2263b ("leds: lgm-sso: Fix clock handling") +Signed-off-by: Chen Ni +Link: https://patch.msgid.link/20260226033048.3715915-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 7b04ea1462605..330cd46194659 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -806,8 +806,6 @@ static int intel_sso_led_probe(struct platform_device *pdev) + + priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk); + +- priv->mmap = syscon_node_to_regmap(dev->of_node); +- + priv->mmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(priv->mmap)) { + dev_err(dev, "Failed to map iomem!\n"); +-- +2.53.0 + diff --git a/queue-6.12/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch b/queue-6.12/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch new file mode 100644 index 0000000000..6ec92b2b7f --- /dev/null +++ b/queue-6.12/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch @@ -0,0 +1,51 @@ +From c0fd020a8ccea7b0e82682c30e185dc6371832ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 17:21:43 +0200 +Subject: lib/hexdump: print_hex_dump_bytes() calls print_hex_dump_debug() + +From: Geert Uytterhoeven + +[ Upstream commit 36776b7f8a8955b4e75b5d490a75fee0c7a2a7ef ] + +print_hex_dump_bytes() claims to be a simple wrapper around +print_hex_dump(), but it actally calls print_hex_dump_debug(), which +means no output is printed if (dynamic) DEBUG is disabled. + +Update the documentation to match the implementation. + +Fixes: 091cb0994edd20d6 ("lib/hexdump: make print_hex_dump_bytes() a nop on !DEBUG builds") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Petr Mladek +Link: https://patch.msgid.link/3d5c3069fd9102ecaf81d044b750cd613eb72a08.1774970392.git.geert+renesas@glider.be +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + include/linux/printk.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index f9498e9cb8ba4..a6c6fd107805b 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -800,7 +800,8 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, + #endif + + /** +- * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params ++ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default ++ * params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none +@@ -808,7 +809,7 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, + * @buf: data blob to dump + * @len: number of bytes in the @buf + * +- * Calls print_hex_dump(), with log level of KERN_DEBUG, ++ * Calls print_hex_dump_debug(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ + #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ +-- +2.53.0 + diff --git a/queue-6.12/libbpf-change-log-level-of-btf-loading-error-message.patch b/queue-6.12/libbpf-change-log-level-of-btf-loading-error-message.patch new file mode 100644 index 0000000000..4918fab485 --- /dev/null +++ b/queue-6.12/libbpf-change-log-level-of-btf-loading-error-message.patch @@ -0,0 +1,59 @@ +From 067b3e73c87f4506af9aa650bf21b701deb5f2cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Sep 2024 19:33:22 +0000 +Subject: libbpf: Change log level of BTF loading error message + +From: Ihor Solodrai + +[ Upstream commit 8b334d91834666dbc4c1c0b0abed3f855ed16cf3 ] + +Reduce log level of BTF loading error to INFO if BTF is not required. + +Andrii says: + + Nowadays the expectation is that the BPF program will have a valid + .BTF section, so even though .BTF is "optional", I think it's fine + to emit a warning for that case (any reasonably recent Clang will + produce valid BTF). + + Ihor's patch is fixing the situation with an outdated host kernel + that doesn't understand BTF. libbpf will try to "upload" the + program's BTF, but if that fails and the BPF object doesn't use + any features that require having BTF uploaded, then it's just an + information message to the user, but otherwise can be ignored. + +Suggested-by: Andrii Nakryiko +Signed-off-by: Ihor Solodrai +Acked-by: Andrii Nakryiko +Signed-off-by: Daniel Borkmann +Signed-off-by: Alexei Starovoitov +Stable-dep-of: 380044c40b16 ("libbpf: Prevent double close and leak of btf objects") +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/libbpf.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 7d496f0a9a30d..791488efec27d 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -3582,11 +3582,12 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj) + report: + if (err) { + btf_mandatory = kernel_needs_btf(obj); +- pr_warn("Error loading .BTF into kernel: %d. %s\n", err, +- btf_mandatory ? "BTF is mandatory, can't proceed." +- : "BTF is optional, ignoring."); +- if (!btf_mandatory) ++ if (btf_mandatory) { ++ pr_warn("Error loading .BTF into kernel: %d. BTF is mandatory, can't proceed.\n", err); ++ } else { ++ pr_info("Error loading .BTF into kernel: %d. BTF is optional, ignoring.\n", err); + err = 0; ++ } + } + return err; + } +-- +2.53.0 + diff --git a/queue-6.12/libbpf-prevent-double-close-and-leak-of-btf-objects.patch b/queue-6.12/libbpf-prevent-double-close-and-leak-of-btf-objects.patch new file mode 100644 index 0000000000..2851a8b541 --- /dev/null +++ b/queue-6.12/libbpf-prevent-double-close-and-leak-of-btf-objects.patch @@ -0,0 +1,98 @@ +From 1894fb9133efe593ce53b7b3e176b5b9509d2c28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 12:00:34 +0200 +Subject: libbpf: Prevent double close and leak of btf objects + +From: Jiri Olsa + +[ Upstream commit 380044c40b1636a72fd8f188b5806be6ae564279 ] + +Sashiko found possible double close of btf object fd [1], +which happens when strdup in load_module_btfs fails at which +point the obj->btf_module_cnt is already incremented. + +The error path close btf fd and so does later cleanup code in +bpf_object_post_load_cleanup function. + +Also libbpf_ensure_mem failure leaves btf object not assigned +and it's leaked. + +Replacing the err_out label with break to make the error path +less confusing as suggested by Alan. + +Incrementing obj->btf_module_cnt only if there's no failure +and releasing btf object in error path. + +Fixes: 91abb4a6d79d ("libbpf: Support attachment of BPF tracing programs to kernel modules") +[1] https://sashiko.dev/#/patchset/20260324081846.2334094-1-jolsa%40kernel.org +Signed-off-by: Jiri Olsa +Link: https://lore.kernel.org/r/20260416100034.1610852-1-jolsa@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/libbpf.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 9c94d56e79764..c7b7a15b9901c 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -5664,11 +5664,12 @@ static int load_module_btfs(struct bpf_object *obj) + info.name = ptr_to_u64(name); + info.name_len = sizeof(name); + ++ btf = NULL; + err = bpf_btf_get_info_by_fd(fd, &info, &len); + if (err) { + err = -errno; + pr_warn("failed to get BTF object #%d info: %s\n", id, errstr(err)); +- goto err_out; ++ break; + } + + /* ignore non-module BTFs */ +@@ -5682,15 +5683,15 @@ static int load_module_btfs(struct bpf_object *obj) + if (err) { + pr_warn("failed to load module [%s]'s BTF object #%d: %s\n", + name, id, errstr(err)); +- goto err_out; ++ break; + } + + err = libbpf_ensure_mem((void **)&obj->btf_modules, &obj->btf_module_cap, + sizeof(*obj->btf_modules), obj->btf_module_cnt + 1); + if (err) +- goto err_out; ++ break; + +- mod_btf = &obj->btf_modules[obj->btf_module_cnt++]; ++ mod_btf = &obj->btf_modules[obj->btf_module_cnt]; + + mod_btf->btf = btf; + mod_btf->id = id; +@@ -5698,16 +5699,16 @@ static int load_module_btfs(struct bpf_object *obj) + mod_btf->name = strdup(name); + if (!mod_btf->name) { + err = -ENOMEM; +- goto err_out; ++ break; + } +- continue; ++ obj->btf_module_cnt++; ++ } + +-err_out: ++ if (err) { ++ btf__free(btf); + close(fd); +- return err; + } +- +- return 0; ++ return err; + } + + static struct bpf_core_cand_list * +-- +2.53.0 + diff --git a/queue-6.12/libbpf-stringify-errno-in-log-messages-in-libbpf.c.patch b/queue-6.12/libbpf-stringify-errno-in-log-messages-in-libbpf.c.patch new file mode 100644 index 0000000000..25e14bd84a --- /dev/null +++ b/queue-6.12/libbpf-stringify-errno-in-log-messages-in-libbpf.c.patch @@ -0,0 +1,1324 @@ +From e4b99fff67305994d092cf6fbaa5bd78c7486a43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Nov 2024 21:29:17 +0000 +Subject: libbpf: Stringify errno in log messages in libbpf.c + +From: Mykyta Yatsenko + +[ Upstream commit 271abf041cb354ce99df33ce1f99db79faf90477 ] + +Convert numeric error codes into the string representations in log +messages in libbpf.c. + +Signed-off-by: Mykyta Yatsenko +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20241111212919.368971-3-mykyta.yatsenko5@gmail.com +Stable-dep-of: 380044c40b16 ("libbpf: Prevent double close and leak of btf objects") +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/libbpf.c | 356 ++++++++++++++++++----------------------- + 1 file changed, 156 insertions(+), 200 deletions(-) + +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 791488efec27d..9c94d56e79764 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -1534,11 +1534,8 @@ static int bpf_object__elf_init(struct bpf_object *obj) + } else { + obj->efile.fd = open(obj->path, O_RDONLY | O_CLOEXEC); + if (obj->efile.fd < 0) { +- char errmsg[STRERR_BUFSIZE], *cp; +- + err = -errno; +- cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); +- pr_warn("elf: failed to open %s: %s\n", obj->path, cp); ++ pr_warn("elf: failed to open %s: %s\n", obj->path, errstr(err)); + return err; + } + +@@ -1938,8 +1935,7 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, + if (map->mmaped == MAP_FAILED) { + err = -errno; + map->mmaped = NULL; +- pr_warn("failed to alloc map '%s' content buffer: %d\n", +- map->name, err); ++ pr_warn("failed to alloc map '%s' content buffer: %s\n", map->name, errstr(err)); + zfree(&map->real_name); + zfree(&map->name); + return err; +@@ -2103,7 +2099,7 @@ static int parse_u64(const char *value, __u64 *res) + *res = strtoull(value, &value_end, 0); + if (errno) { + err = -errno; +- pr_warn("failed to parse '%s' as integer: %d\n", value, err); ++ pr_warn("failed to parse '%s': %s\n", value, errstr(err)); + return err; + } + if (*value_end) { +@@ -2269,8 +2265,8 @@ static int bpf_object__read_kconfig_file(struct bpf_object *obj, void *data) + while (gzgets(file, buf, sizeof(buf))) { + err = bpf_object__process_kconfig_line(obj, buf, data); + if (err) { +- pr_warn("error parsing system Kconfig line '%s': %d\n", +- buf, err); ++ pr_warn("error parsing system Kconfig line '%s': %s\n", ++ buf, errstr(err)); + goto out; + } + } +@@ -2290,15 +2286,15 @@ static int bpf_object__read_kconfig_mem(struct bpf_object *obj, + file = fmemopen((void *)config, strlen(config), "r"); + if (!file) { + err = -errno; +- pr_warn("failed to open in-memory Kconfig: %d\n", err); ++ pr_warn("failed to open in-memory Kconfig: %s\n", errstr(err)); + return err; + } + + while (fgets(buf, sizeof(buf), file)) { + err = bpf_object__process_kconfig_line(obj, buf, data); + if (err) { +- pr_warn("error parsing in-memory Kconfig line '%s': %d\n", +- buf, err); ++ pr_warn("error parsing in-memory Kconfig line '%s': %s\n", ++ buf, errstr(err)); + break; + } + } +@@ -3213,7 +3209,7 @@ static int bpf_object__init_btf(struct bpf_object *obj, + err = libbpf_get_error(obj->btf); + if (err) { + obj->btf = NULL; +- pr_warn("Error loading ELF section %s: %d.\n", BTF_ELF_SEC, err); ++ pr_warn("Error loading ELF section %s: %s.\n", BTF_ELF_SEC, errstr(err)); + goto out; + } + /* enforce 8-byte pointers for BPF-targeted BTFs */ +@@ -3231,8 +3227,8 @@ static int bpf_object__init_btf(struct bpf_object *obj, + obj->btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size); + err = libbpf_get_error(obj->btf_ext); + if (err) { +- pr_warn("Error loading ELF section %s: %d. Ignored and continue.\n", +- BTF_EXT_ELF_SEC, err); ++ pr_warn("Error loading ELF section %s: %s. Ignored and continue.\n", ++ BTF_EXT_ELF_SEC, errstr(err)); + obj->btf_ext = NULL; + goto out; + } +@@ -3324,8 +3320,8 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf, + if (t->size == 0) { + err = find_elf_sec_sz(obj, sec_name, &size); + if (err || !size) { +- pr_debug("sec '%s': failed to determine size from ELF: size %u, err %d\n", +- sec_name, size, err); ++ pr_debug("sec '%s': failed to determine size from ELF: size %u, err %s\n", ++ sec_name, size, errstr(err)); + return -ENOENT; + } + +@@ -3479,7 +3475,7 @@ static int bpf_object__load_vmlinux_btf(struct bpf_object *obj, bool force) + obj->btf_vmlinux = btf__load_vmlinux_btf(); + err = libbpf_get_error(obj->btf_vmlinux); + if (err) { +- pr_warn("Error loading vmlinux BTF: %d\n", err); ++ pr_warn("Error loading vmlinux BTF: %s\n", errstr(err)); + obj->btf_vmlinux = NULL; + return err; + } +@@ -3583,9 +3579,11 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj) + if (err) { + btf_mandatory = kernel_needs_btf(obj); + if (btf_mandatory) { +- pr_warn("Error loading .BTF into kernel: %d. BTF is mandatory, can't proceed.\n", err); ++ pr_warn("Error loading .BTF into kernel: %s. BTF is mandatory, can't proceed.\n", ++ errstr(err)); + } else { +- pr_info("Error loading .BTF into kernel: %d. BTF is optional, ignoring.\n", err); ++ pr_info("Error loading .BTF into kernel: %s. BTF is optional, ignoring.\n", ++ errstr(err)); + err = 0; + } + } +@@ -4797,8 +4795,8 @@ static int bpf_get_map_info_from_fdinfo(int fd, struct bpf_map_info *info) + fp = fopen(file, "re"); + if (!fp) { + err = -errno; +- pr_warn("failed to open %s: %d. No procfs support?\n", file, +- err); ++ pr_warn("failed to open %s: %s. No procfs support?\n", file, ++ errstr(err)); + return err; + } + +@@ -4953,8 +4951,8 @@ static int bpf_object_prepare_token(struct bpf_object *obj) + bpffs_fd = open(bpffs_path, O_DIRECTORY, O_RDWR); + if (bpffs_fd < 0) { + err = -errno; +- __pr(level, "object '%s': failed (%d) to open BPF FS mount at '%s'%s\n", +- obj->name, err, bpffs_path, ++ __pr(level, "object '%s': failed (%s) to open BPF FS mount at '%s'%s\n", ++ obj->name, errstr(err), bpffs_path, + mandatory ? "" : ", skipping optional step..."); + return mandatory ? err : 0; + } +@@ -4988,7 +4986,6 @@ static int bpf_object_prepare_token(struct bpf_object *obj) + static int + bpf_object__probe_loading(struct bpf_object *obj) + { +- char *cp, errmsg[STRERR_BUFSIZE]; + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), +@@ -5004,7 +5001,8 @@ bpf_object__probe_loading(struct bpf_object *obj) + + ret = bump_rlimit_memlock(); + if (ret) +- pr_warn("Failed to bump RLIMIT_MEMLOCK (err = %d), you might need to do it explicitly!\n", ret); ++ pr_warn("Failed to bump RLIMIT_MEMLOCK (err = %s), you might need to do it explicitly!\n", ++ errstr(ret)); + + /* make sure basic loading works */ + ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &opts); +@@ -5012,11 +5010,8 @@ bpf_object__probe_loading(struct bpf_object *obj) + ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); + if (ret < 0) { + ret = errno; +- cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); +- pr_warn("Error in %s():%s(%d). Couldn't load trivial BPF " +- "program. Make sure your kernel supports BPF " +- "(CONFIG_BPF_SYSCALL=y) and/or that RLIMIT_MEMLOCK is " +- "set to big enough value.\n", __func__, cp, ret); ++ pr_warn("Error in %s(): %s. Couldn't load trivial BPF program. Make sure your kernel supports BPF (CONFIG_BPF_SYSCALL=y) and/or that RLIMIT_MEMLOCK is set to big enough value.\n", ++ __func__, errstr(ret)); + return -ret; + } + close(ret); +@@ -5041,7 +5036,6 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) + static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) + { + struct bpf_map_info map_info; +- char msg[STRERR_BUFSIZE]; + __u32 map_info_len = sizeof(map_info); + int err; + +@@ -5051,7 +5045,7 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) + err = bpf_get_map_info_from_fdinfo(map_fd, &map_info); + if (err) { + pr_warn("failed to get map info for map FD %d: %s\n", map_fd, +- libbpf_strerror_r(errno, msg, sizeof(msg))); ++ errstr(err)); + return false; + } + +@@ -5076,7 +5070,6 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) + static int + bpf_object__reuse_map(struct bpf_map *map) + { +- char *cp, errmsg[STRERR_BUFSIZE]; + int err, pin_fd; + + pin_fd = bpf_obj_get(map->pin_path); +@@ -5088,9 +5081,8 @@ bpf_object__reuse_map(struct bpf_map *map) + return 0; + } + +- cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg)); + pr_warn("couldn't retrieve pinned map '%s': %s\n", +- map->pin_path, cp); ++ map->pin_path, errstr(err)); + return err; + } + +@@ -5116,7 +5108,6 @@ static int + bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) + { + enum libbpf_map_type map_type = map->libbpf_type; +- char *cp, errmsg[STRERR_BUFSIZE]; + int err, zero = 0; + size_t mmap_sz; + +@@ -5131,9 +5122,8 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) + err = bpf_map_update_elem(map->fd, &zero, map->mmaped, 0); + if (err) { + err = -errno; +- cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); + pr_warn("map '%s': failed to set initial contents: %s\n", +- bpf_map__name(map), cp); ++ bpf_map__name(map), errstr(err)); + return err; + } + +@@ -5142,9 +5132,8 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) + err = bpf_map_freeze(map->fd); + if (err) { + err = -errno; +- cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); + pr_warn("map '%s': failed to freeze as read-only: %s\n", +- bpf_map__name(map), cp); ++ bpf_map__name(map), errstr(err)); + return err; + } + } +@@ -5170,8 +5159,8 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) + mmaped = mmap(map->mmaped, mmap_sz, prot, MAP_SHARED | MAP_FIXED, map->fd, 0); + if (mmaped == MAP_FAILED) { + err = -errno; +- pr_warn("map '%s': failed to re-mmap() contents: %d\n", +- bpf_map__name(map), err); ++ pr_warn("map '%s': failed to re-mmap() contents: %s\n", ++ bpf_map__name(map), errstr(err)); + return err; + } + map->mmaped = mmaped; +@@ -5228,8 +5217,8 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b + return err; + err = bpf_object__create_map(obj, map->inner_map, true); + if (err) { +- pr_warn("map '%s': failed to create inner map: %d\n", +- map->name, err); ++ pr_warn("map '%s': failed to create inner map: %s\n", ++ map->name, errstr(err)); + return err; + } + map->inner_map_fd = map->inner_map->fd; +@@ -5283,12 +5272,9 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b + def->max_entries, &create_attr); + } + if (map_fd < 0 && (create_attr.btf_key_type_id || create_attr.btf_value_type_id)) { +- char *cp, errmsg[STRERR_BUFSIZE]; +- + err = -errno; +- cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); +- pr_warn("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", +- map->name, cp, err); ++ pr_warn("Error in bpf_create_map_xattr(%s): %s. Retrying without BTF.\n", ++ map->name, errstr(err)); + create_attr.btf_fd = 0; + create_attr.btf_key_type_id = 0; + create_attr.btf_value_type_id = 0; +@@ -5343,8 +5329,8 @@ static int init_map_in_map_slots(struct bpf_object *obj, struct bpf_map *map) + } + if (err) { + err = -errno; +- pr_warn("map '%s': failed to initialize slot [%d] to map '%s' fd=%d: %d\n", +- map->name, i, targ_map->name, fd, err); ++ pr_warn("map '%s': failed to initialize slot [%d] to map '%s' fd=%d: %s\n", ++ map->name, i, targ_map->name, fd, errstr(err)); + return err; + } + pr_debug("map '%s': slot [%d] set to map '%s' fd=%d\n", +@@ -5376,8 +5362,8 @@ static int init_prog_array_slots(struct bpf_object *obj, struct bpf_map *map) + err = bpf_map_update_elem(map->fd, &i, &fd, 0); + if (err) { + err = -errno; +- pr_warn("map '%s': failed to initialize slot [%d] to prog '%s' fd=%d: %d\n", +- map->name, i, targ_prog->name, fd, err); ++ pr_warn("map '%s': failed to initialize slot [%d] to prog '%s' fd=%d: %s\n", ++ map->name, i, targ_prog->name, fd, errstr(err)); + return err; + } + pr_debug("map '%s': slot [%d] set to prog '%s' fd=%d\n", +@@ -5430,7 +5416,6 @@ static int + bpf_object__create_maps(struct bpf_object *obj) + { + struct bpf_map *map; +- char *cp, errmsg[STRERR_BUFSIZE]; + unsigned int i, j; + int err; + bool retried; +@@ -5504,8 +5489,8 @@ bpf_object__create_maps(struct bpf_object *obj) + if (map->mmaped == MAP_FAILED) { + err = -errno; + map->mmaped = NULL; +- pr_warn("map '%s': failed to mmap arena: %d\n", +- map->name, err); ++ pr_warn("map '%s': failed to mmap arena: %s\n", ++ map->name, errstr(err)); + return err; + } + if (obj->arena_data) { +@@ -5527,8 +5512,8 @@ bpf_object__create_maps(struct bpf_object *obj) + retried = true; + goto retry; + } +- pr_warn("map '%s': failed to auto-pin at '%s': %d\n", +- map->name, map->pin_path, err); ++ pr_warn("map '%s': failed to auto-pin at '%s': %s\n", ++ map->name, map->pin_path, errstr(err)); + goto err_out; + } + } +@@ -5537,8 +5522,7 @@ bpf_object__create_maps(struct bpf_object *obj) + return 0; + + err_out: +- cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); +- pr_warn("map '%s': failed to create: %s(%d)\n", map->name, cp, err); ++ pr_warn("map '%s': failed to create: %s\n", map->name, errstr(err)); + pr_perm_msg(err); + for (j = 0; j < i; j++) + zclose(obj->maps[j].fd); +@@ -5662,7 +5646,7 @@ static int load_module_btfs(struct bpf_object *obj) + } + if (err) { + err = -errno; +- pr_warn("failed to iterate BTF objects: %d\n", err); ++ pr_warn("failed to iterate BTF objects: %s\n", errstr(err)); + return err; + } + +@@ -5671,7 +5655,7 @@ static int load_module_btfs(struct bpf_object *obj) + if (errno == ENOENT) + continue; /* expected race: BTF was unloaded */ + err = -errno; +- pr_warn("failed to get BTF object #%d FD: %d\n", id, err); ++ pr_warn("failed to get BTF object #%d FD: %s\n", id, errstr(err)); + return err; + } + +@@ -5683,7 +5667,7 @@ static int load_module_btfs(struct bpf_object *obj) + err = bpf_btf_get_info_by_fd(fd, &info, &len); + if (err) { + err = -errno; +- pr_warn("failed to get BTF object #%d info: %d\n", id, err); ++ pr_warn("failed to get BTF object #%d info: %s\n", id, errstr(err)); + goto err_out; + } + +@@ -5696,8 +5680,8 @@ static int load_module_btfs(struct bpf_object *obj) + btf = btf_get_from_fd(fd, obj->btf_vmlinux); + err = libbpf_get_error(btf); + if (err) { +- pr_warn("failed to load module [%s]'s BTF object #%d: %d\n", +- name, id, err); ++ pr_warn("failed to load module [%s]'s BTF object #%d: %s\n", ++ name, id, errstr(err)); + goto err_out; + } + +@@ -5926,7 +5910,7 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path) + obj->btf_vmlinux_override = btf__parse(targ_btf_path, NULL); + err = libbpf_get_error(obj->btf_vmlinux_override); + if (err) { +- pr_warn("failed to parse target BTF: %d\n", err); ++ pr_warn("failed to parse target BTF: %s\n", errstr(err)); + return err; + } + } +@@ -5986,8 +5970,8 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path) + + err = record_relo_core(prog, rec, insn_idx); + if (err) { +- pr_warn("prog '%s': relo #%d: failed to record relocation: %d\n", +- prog->name, i, err); ++ pr_warn("prog '%s': relo #%d: failed to record relocation: %s\n", ++ prog->name, i, errstr(err)); + goto out; + } + +@@ -5996,15 +5980,15 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path) + + err = bpf_core_resolve_relo(prog, rec, i, obj->btf, cand_cache, &targ_res); + if (err) { +- pr_warn("prog '%s': relo #%d: failed to relocate: %d\n", +- prog->name, i, err); ++ pr_warn("prog '%s': relo #%d: failed to relocate: %s\n", ++ prog->name, i, errstr(err)); + goto out; + } + + err = bpf_core_patch_insn(prog->name, insn, insn_idx, rec, i, &targ_res); + if (err) { +- pr_warn("prog '%s': relo #%d: failed to patch insn #%u: %d\n", +- prog->name, i, insn_idx, err); ++ pr_warn("prog '%s': relo #%d: failed to patch insn #%u: %s\n", ++ prog->name, i, insn_idx, errstr(err)); + goto out; + } + } +@@ -6272,8 +6256,8 @@ reloc_prog_func_and_line_info(const struct bpf_object *obj, + &main_prog->func_info_rec_size); + if (err) { + if (err != -ENOENT) { +- pr_warn("prog '%s': error relocating .BTF.ext function info: %d\n", +- prog->name, err); ++ pr_warn("prog '%s': error relocating .BTF.ext function info: %s\n", ++ prog->name, errstr(err)); + return err; + } + if (main_prog->func_info) { +@@ -6300,8 +6284,8 @@ reloc_prog_func_and_line_info(const struct bpf_object *obj, + &main_prog->line_info_rec_size); + if (err) { + if (err != -ENOENT) { +- pr_warn("prog '%s': error relocating .BTF.ext line info: %d\n", +- prog->name, err); ++ pr_warn("prog '%s': error relocating .BTF.ext line info: %s\n", ++ prog->name, errstr(err)); + return err; + } + if (main_prog->line_info) { +@@ -7065,8 +7049,8 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat + if (obj->btf_ext) { + err = bpf_object__relocate_core(obj, targ_btf_path); + if (err) { +- pr_warn("failed to perform CO-RE relocations: %d\n", +- err); ++ pr_warn("failed to perform CO-RE relocations: %s\n", ++ errstr(err)); + return err; + } + bpf_object__sort_relos(obj); +@@ -7110,8 +7094,8 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat + + err = bpf_object__relocate_calls(obj, prog); + if (err) { +- pr_warn("prog '%s': failed to relocate calls: %d\n", +- prog->name, err); ++ pr_warn("prog '%s': failed to relocate calls: %s\n", ++ prog->name, errstr(err)); + return err; + } + +@@ -7147,16 +7131,16 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat + /* Process data relos for main programs */ + err = bpf_object__relocate_data(obj, prog); + if (err) { +- pr_warn("prog '%s': failed to relocate data references: %d\n", +- prog->name, err); ++ pr_warn("prog '%s': failed to relocate data references: %s\n", ++ prog->name, errstr(err)); + return err; + } + + /* Fix up .BTF.ext information, if necessary */ + err = bpf_program_fixup_func_info(obj, prog); + if (err) { +- pr_warn("prog '%s': failed to perform .BTF.ext fix ups: %d\n", +- prog->name, err); ++ pr_warn("prog '%s': failed to perform .BTF.ext fix ups: %s\n", ++ prog->name, errstr(err)); + return err; + } + } +@@ -7465,7 +7449,6 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog + { + LIBBPF_OPTS(bpf_prog_load_opts, load_attr); + const char *prog_name = NULL; +- char *cp, errmsg[STRERR_BUFSIZE]; + size_t log_buf_size = 0; + char *log_buf = NULL, *tmp; + bool own_log_buf = true; +@@ -7529,8 +7512,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog + if (prog->sec_def && prog->sec_def->prog_prepare_load_fn) { + err = prog->sec_def->prog_prepare_load_fn(prog, &load_attr, prog->sec_def->cookie); + if (err < 0) { +- pr_warn("prog '%s': failed to prepare load attributes: %d\n", +- prog->name, err); ++ pr_warn("prog '%s': failed to prepare load attributes: %s\n", ++ prog->name, errstr(err)); + return err; + } + insns = prog->insns; +@@ -7594,9 +7577,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog + continue; + + if (bpf_prog_bind_map(ret, map->fd, NULL)) { +- cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warn("prog '%s': failed to bind map '%s': %s\n", +- prog->name, map->real_name, cp); ++ prog->name, map->real_name, errstr(errno)); + /* Don't fail hard if can't bind rodata. */ + } + } +@@ -7626,8 +7608,7 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog + /* post-process verifier log to improve error descriptions */ + fixup_verifier_log(prog, log_buf, log_buf_size); + +- cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); +- pr_warn("prog '%s': BPF program load failed: %s\n", prog->name, cp); ++ pr_warn("prog '%s': BPF program load failed: %s\n", prog->name, errstr(errno)); + pr_perm_msg(ret); + + if (own_log_buf && log_buf && log_buf[0] != '\0') { +@@ -7920,7 +7901,7 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level) + err = bpf_object_load_prog(obj, prog, prog->insns, prog->insns_cnt, + obj->license, obj->kern_version, &prog->fd); + if (err) { +- pr_warn("prog '%s': failed to load: %d\n", prog->name, err); ++ pr_warn("prog '%s': failed to load: %s\n", prog->name, errstr(err)); + return err; + } + } +@@ -7954,8 +7935,8 @@ static int bpf_object_init_progs(struct bpf_object *obj, const struct bpf_object + if (prog->sec_def->prog_setup_fn) { + err = prog->sec_def->prog_setup_fn(prog, prog->sec_def->cookie); + if (err < 0) { +- pr_warn("prog '%s': failed to initialize: %d\n", +- prog->name, err); ++ pr_warn("prog '%s': failed to initialize: %s\n", ++ prog->name, errstr(err)); + return err; + } + } +@@ -8145,7 +8126,7 @@ static int libbpf_kallsyms_parse(kallsyms_cb_t cb, void *ctx) + f = fopen("/proc/kallsyms", "re"); + if (!f) { + err = -errno; +- pr_warn("failed to open /proc/kallsyms: %d\n", err); ++ pr_warn("failed to open /proc/kallsyms: %s\n", errstr(err)); + return err; + } + +@@ -8622,7 +8603,6 @@ int bpf_object__load(struct bpf_object *obj) + + static int make_parent_dir(const char *path) + { +- char *cp, errmsg[STRERR_BUFSIZE]; + char *dname, *dir; + int err = 0; + +@@ -8636,15 +8616,13 @@ static int make_parent_dir(const char *path) + + free(dname); + if (err) { +- cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg)); +- pr_warn("failed to mkdir %s: %s\n", path, cp); ++ pr_warn("failed to mkdir %s: %s\n", path, errstr(err)); + } + return err; + } + + static int check_path(const char *path) + { +- char *cp, errmsg[STRERR_BUFSIZE]; + struct statfs st_fs; + char *dname, *dir; + int err = 0; +@@ -8658,8 +8636,7 @@ static int check_path(const char *path) + + dir = dirname(dname); + if (statfs(dir, &st_fs)) { +- cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); +- pr_warn("failed to statfs %s: %s\n", dir, cp); ++ pr_warn("failed to statfs %s: %s\n", dir, errstr(errno)); + err = -errno; + } + free(dname); +@@ -8674,7 +8651,6 @@ static int check_path(const char *path) + + int bpf_program__pin(struct bpf_program *prog, const char *path) + { +- char *cp, errmsg[STRERR_BUFSIZE]; + int err; + + if (prog->fd < 0) { +@@ -8692,8 +8668,7 @@ int bpf_program__pin(struct bpf_program *prog, const char *path) + + if (bpf_obj_pin(prog->fd, path)) { + err = -errno; +- cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); +- pr_warn("prog '%s': failed to pin at '%s': %s\n", prog->name, path, cp); ++ pr_warn("prog '%s': failed to pin at '%s': %s\n", prog->name, path, errstr(err)); + return libbpf_err(err); + } + +@@ -8724,7 +8699,6 @@ int bpf_program__unpin(struct bpf_program *prog, const char *path) + + int bpf_map__pin(struct bpf_map *map, const char *path) + { +- char *cp, errmsg[STRERR_BUFSIZE]; + int err; + + if (map == NULL) { +@@ -8783,8 +8757,7 @@ int bpf_map__pin(struct bpf_map *map, const char *path) + return 0; + + out_err: +- cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg)); +- pr_warn("failed to pin map: %s\n", cp); ++ pr_warn("failed to pin map: %s\n", errstr(err)); + return libbpf_err(err); + } + +@@ -9972,8 +9945,8 @@ static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd) + memset(&info, 0, info_len); + err = bpf_prog_get_info_by_fd(attach_prog_fd, &info, &info_len); + if (err) { +- pr_warn("failed bpf_prog_get_info_by_fd for FD %d: %d\n", +- attach_prog_fd, err); ++ pr_warn("failed bpf_prog_get_info_by_fd for FD %d: %s\n", ++ attach_prog_fd, errstr(err)); + return err; + } + +@@ -9985,7 +9958,7 @@ static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd) + btf = btf__load_from_kernel_by_id(info.btf_id); + err = libbpf_get_error(btf); + if (err) { +- pr_warn("Failed to get BTF %d of the program: %d\n", info.btf_id, err); ++ pr_warn("Failed to get BTF %d of the program: %s\n", info.btf_id, errstr(err)); + goto out; + } + err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC); +@@ -10067,8 +10040,8 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attac + } + err = libbpf_find_prog_btf_id(attach_name, attach_prog_fd); + if (err < 0) { +- pr_warn("prog '%s': failed to find BPF program (FD %d) BTF ID for '%s': %d\n", +- prog->name, attach_prog_fd, attach_name, err); ++ pr_warn("prog '%s': failed to find BPF program (FD %d) BTF ID for '%s': %s\n", ++ prog->name, attach_prog_fd, attach_name, errstr(err)); + return err; + } + *btf_obj_fd = 0; +@@ -10087,8 +10060,8 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attac + btf_type_id); + } + if (err) { +- pr_warn("prog '%s': failed to find kernel BTF type ID of '%s': %d\n", +- prog->name, attach_name, err); ++ pr_warn("prog '%s': failed to find kernel BTF type ID of '%s': %s\n", ++ prog->name, attach_name, errstr(err)); + return err; + } + return 0; +@@ -10316,14 +10289,14 @@ int bpf_map__set_value_size(struct bpf_map *map, __u32 size) + mmap_new_sz = array_map_mmap_sz(size, map->def.max_entries); + err = bpf_map_mmap_resize(map, mmap_old_sz, mmap_new_sz); + if (err) { +- pr_warn("map '%s': failed to resize memory-mapped region: %d\n", +- bpf_map__name(map), err); ++ pr_warn("map '%s': failed to resize memory-mapped region: %s\n", ++ bpf_map__name(map), errstr(err)); + return err; + } + err = map_btf_datasec_resize(map, size); + if (err && err != -ENOENT) { +- pr_warn("map '%s': failed to adjust resized BTF, clearing BTF key/value info: %d\n", +- bpf_map__name(map), err); ++ pr_warn("map '%s': failed to adjust resized BTF, clearing BTF key/value info: %s\n", ++ bpf_map__name(map), errstr(err)); + map->btf_value_type_id = 0; + map->btf_key_type_id = 0; + } +@@ -10814,7 +10787,6 @@ static void bpf_link_perf_dealloc(struct bpf_link *link) + struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *prog, int pfd, + const struct bpf_perf_event_opts *opts) + { +- char errmsg[STRERR_BUFSIZE]; + struct bpf_link_perf *link; + int prog_fd, link_fd = -1, err; + bool force_ioctl_attach; +@@ -10849,9 +10821,8 @@ struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *p + link_fd = bpf_link_create(prog_fd, pfd, BPF_PERF_EVENT, &link_opts); + if (link_fd < 0) { + err = -errno; +- pr_warn("prog '%s': failed to create BPF link for perf_event FD %d: %d (%s)\n", +- prog->name, pfd, +- err, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ pr_warn("prog '%s': failed to create BPF link for perf_event FD %d: %s\n", ++ prog->name, pfd, errstr(err)); + goto err_out; + } + link->link.fd = link_fd; +@@ -10865,7 +10836,7 @@ struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *p + if (ioctl(pfd, PERF_EVENT_IOC_SET_BPF, prog_fd) < 0) { + err = -errno; + pr_warn("prog '%s': failed to attach to perf_event FD %d: %s\n", +- prog->name, pfd, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ prog->name, pfd, errstr(err)); + if (err == -EPROTO) + pr_warn("prog '%s': try add PERF_SAMPLE_CALLCHAIN to or remove exclude_callchain_[kernel|user] from pfd %d\n", + prog->name, pfd); +@@ -10876,7 +10847,7 @@ struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *p + if (ioctl(pfd, PERF_EVENT_IOC_ENABLE, 0) < 0) { + err = -errno; + pr_warn("prog '%s': failed to enable perf_event FD %d: %s\n", +- prog->name, pfd, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ prog->name, pfd, errstr(err)); + goto err_out; + } + +@@ -10900,22 +10871,19 @@ struct bpf_link *bpf_program__attach_perf_event(const struct bpf_program *prog, + */ + static int parse_uint_from_file(const char *file, const char *fmt) + { +- char buf[STRERR_BUFSIZE]; + int err, ret; + FILE *f; + + f = fopen(file, "re"); + if (!f) { + err = -errno; +- pr_debug("failed to open '%s': %s\n", file, +- libbpf_strerror_r(err, buf, sizeof(buf))); ++ pr_debug("failed to open '%s': %s\n", file, errstr(err)); + return err; + } + err = fscanf(f, fmt, &ret); + if (err != 1) { + err = err == EOF ? -EIO : -errno; +- pr_debug("failed to parse '%s': %s\n", file, +- libbpf_strerror_r(err, buf, sizeof(buf))); ++ pr_debug("failed to parse '%s': %s\n", file, errstr(err)); + fclose(f); + return err; + } +@@ -10959,7 +10927,6 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, + { + const size_t attr_sz = sizeof(struct perf_event_attr); + struct perf_event_attr attr; +- char errmsg[STRERR_BUFSIZE]; + int type, pfd; + + if ((__u64)ref_ctr_off >= (1ULL << PERF_UPROBE_REF_CTR_OFFSET_BITS)) +@@ -10972,7 +10939,7 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, + if (type < 0) { + pr_warn("failed to determine %s perf type: %s\n", + uprobe ? "uprobe" : "kprobe", +- libbpf_strerror_r(type, errmsg, sizeof(errmsg))); ++ errstr(type)); + return type; + } + if (retprobe) { +@@ -10982,7 +10949,7 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, + if (bit < 0) { + pr_warn("failed to determine %s retprobe bit: %s\n", + uprobe ? "uprobe" : "kprobe", +- libbpf_strerror_r(bit, errmsg, sizeof(errmsg))); ++ errstr(bit)); + return bit; + } + attr.config |= 1 << bit; +@@ -11111,14 +11078,13 @@ static int perf_event_kprobe_open_legacy(const char *probe_name, bool retprobe, + { + const size_t attr_sz = sizeof(struct perf_event_attr); + struct perf_event_attr attr; +- char errmsg[STRERR_BUFSIZE]; + int type, pfd, err; + + err = add_kprobe_event_legacy(probe_name, retprobe, kfunc_name, offset); + if (err < 0) { + pr_warn("failed to add legacy kprobe event for '%s+0x%zx': %s\n", + kfunc_name, offset, +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + return err; + } + type = determine_kprobe_perf_type_legacy(probe_name, retprobe); +@@ -11126,7 +11092,7 @@ static int perf_event_kprobe_open_legacy(const char *probe_name, bool retprobe, + err = type; + pr_warn("failed to determine legacy kprobe event id for '%s+0x%zx': %s\n", + kfunc_name, offset, +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + goto err_clean_legacy; + } + +@@ -11142,7 +11108,7 @@ static int perf_event_kprobe_open_legacy(const char *probe_name, bool retprobe, + if (pfd < 0) { + err = -errno; + pr_warn("legacy kprobe perf_event_open() failed: %s\n", +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + goto err_clean_legacy; + } + return pfd; +@@ -11218,7 +11184,6 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog, + { + DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts); + enum probe_attach_mode attach_mode; +- char errmsg[STRERR_BUFSIZE]; + char *legacy_probe = NULL; + struct bpf_link *link; + size_t offset; +@@ -11276,7 +11241,7 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog, + pr_warn("prog '%s': failed to create %s '%s+0x%zx' perf event: %s\n", + prog->name, retprobe ? "kretprobe" : "kprobe", + func_name, offset, +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + goto err_out; + } + link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts); +@@ -11286,7 +11251,7 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog, + pr_warn("prog '%s': failed to attach to %s '%s+0x%zx': %s\n", + prog->name, retprobe ? "kretprobe" : "kprobe", + func_name, offset, +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + goto err_clean_legacy; + } + if (legacy) { +@@ -11422,7 +11387,7 @@ static int libbpf_available_kallsyms_parse(struct kprobe_multi_resolve *res) + f = fopen(available_functions_file, "re"); + if (!f) { + err = -errno; +- pr_warn("failed to open %s: %d\n", available_functions_file, err); ++ pr_warn("failed to open %s: %s\n", available_functions_file, errstr(err)); + return err; + } + +@@ -11497,7 +11462,7 @@ static int libbpf_available_kprobes_parse(struct kprobe_multi_resolve *res) + f = fopen(available_path, "re"); + if (!f) { + err = -errno; +- pr_warn("failed to open %s: %d\n", available_path, err); ++ pr_warn("failed to open %s: %s\n", available_path, errstr(err)); + return err; + } + +@@ -11543,7 +11508,6 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog, + }; + enum bpf_attach_type attach_type; + struct bpf_link *link = NULL; +- char errmsg[STRERR_BUFSIZE]; + const unsigned long *addrs; + int err, link_fd, prog_fd; + bool retprobe, session; +@@ -11611,7 +11575,7 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog, + if (link_fd < 0) { + err = -errno; + pr_warn("prog '%s': failed to attach: %s\n", +- prog->name, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ prog->name, errstr(err)); + goto error; + } + link->fd = link_fd; +@@ -11804,15 +11768,15 @@ static int perf_event_uprobe_open_legacy(const char *probe_name, bool retprobe, + + err = add_uprobe_event_legacy(probe_name, retprobe, binary_path, offset); + if (err < 0) { +- pr_warn("failed to add legacy uprobe event for %s:0x%zx: %d\n", +- binary_path, (size_t)offset, err); ++ pr_warn("failed to add legacy uprobe event for %s:0x%zx: %s\n", ++ binary_path, (size_t)offset, errstr(err)); + return err; + } + type = determine_uprobe_perf_type_legacy(probe_name, retprobe); + if (type < 0) { + err = type; +- pr_warn("failed to determine legacy uprobe event id for %s:0x%zx: %d\n", +- binary_path, offset, err); ++ pr_warn("failed to determine legacy uprobe event id for %s:0x%zx: %s\n", ++ binary_path, offset, errstr(err)); + goto err_clean_legacy; + } + +@@ -11827,7 +11791,7 @@ static int perf_event_uprobe_open_legacy(const char *probe_name, bool retprobe, + -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC); + if (pfd < 0) { + err = -errno; +- pr_warn("legacy uprobe perf_event_open() failed: %d\n", err); ++ pr_warn("legacy uprobe perf_event_open() failed: %s\n", errstr(err)); + goto err_clean_legacy; + } + return pfd; +@@ -11992,7 +11956,6 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, + unsigned long *resolved_offsets = NULL; + int err = 0, link_fd, prog_fd; + struct bpf_link *link = NULL; +- char errmsg[STRERR_BUFSIZE]; + char full_path[PATH_MAX]; + const __u64 *cookies; + const char **syms; +@@ -12045,8 +12008,8 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, + if (!strchr(path, '/')) { + err = resolve_full_path(path, full_path, sizeof(full_path)); + if (err) { +- pr_warn("prog '%s': failed to resolve full path for '%s': %d\n", +- prog->name, path, err); ++ pr_warn("prog '%s': failed to resolve full path for '%s': %s\n", ++ prog->name, path, errstr(err)); + return libbpf_err_ptr(err); + } + path = full_path; +@@ -12087,7 +12050,7 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, + if (link_fd < 0) { + err = -errno; + pr_warn("prog '%s': failed to attach multi-uprobe: %s\n", +- prog->name, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ prog->name, errstr(err)); + goto error; + } + link->fd = link_fd; +@@ -12106,7 +12069,7 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid, + const struct bpf_uprobe_opts *opts) + { + const char *archive_path = NULL, *archive_sep = NULL; +- char errmsg[STRERR_BUFSIZE], *legacy_probe = NULL; ++ char *legacy_probe = NULL; + DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts); + enum probe_attach_mode attach_mode; + char full_path[PATH_MAX]; +@@ -12138,8 +12101,8 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid, + } else if (!strchr(binary_path, '/')) { + err = resolve_full_path(binary_path, full_path, sizeof(full_path)); + if (err) { +- pr_warn("prog '%s': failed to resolve full path for '%s': %d\n", +- prog->name, binary_path, err); ++ pr_warn("prog '%s': failed to resolve full path for '%s': %s\n", ++ prog->name, binary_path, errstr(err)); + return libbpf_err_ptr(err); + } + binary_path = full_path; +@@ -12206,7 +12169,7 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid, + pr_warn("prog '%s': failed to create %s '%s:0x%zx' perf event: %s\n", + prog->name, retprobe ? "uretprobe" : "uprobe", + binary_path, func_offset, +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + goto err_out; + } + +@@ -12217,7 +12180,7 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid, + pr_warn("prog '%s': failed to attach to %s '%s:0x%zx': %s\n", + prog->name, retprobe ? "uretprobe" : "uprobe", + binary_path, func_offset, +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + goto err_clean_legacy; + } + if (legacy) { +@@ -12338,8 +12301,8 @@ struct bpf_link *bpf_program__attach_usdt(const struct bpf_program *prog, + if (!strchr(binary_path, '/')) { + err = resolve_full_path(binary_path, resolved_path, sizeof(resolved_path)); + if (err) { +- pr_warn("prog '%s': failed to resolve full path for '%s': %d\n", +- prog->name, binary_path, err); ++ pr_warn("prog '%s': failed to resolve full path for '%s': %s\n", ++ prog->name, binary_path, errstr(err)); + return libbpf_err_ptr(err); + } + binary_path = resolved_path; +@@ -12417,14 +12380,13 @@ static int perf_event_open_tracepoint(const char *tp_category, + { + const size_t attr_sz = sizeof(struct perf_event_attr); + struct perf_event_attr attr; +- char errmsg[STRERR_BUFSIZE]; + int tp_id, pfd, err; + + tp_id = determine_tracepoint_id(tp_category, tp_name); + if (tp_id < 0) { + pr_warn("failed to determine tracepoint '%s/%s' perf event ID: %s\n", + tp_category, tp_name, +- libbpf_strerror_r(tp_id, errmsg, sizeof(errmsg))); ++ errstr(tp_id)); + return tp_id; + } + +@@ -12439,7 +12401,7 @@ static int perf_event_open_tracepoint(const char *tp_category, + err = -errno; + pr_warn("tracepoint '%s/%s' perf_event_open() failed: %s\n", + tp_category, tp_name, +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + return err; + } + return pfd; +@@ -12451,7 +12413,6 @@ struct bpf_link *bpf_program__attach_tracepoint_opts(const struct bpf_program *p + const struct bpf_tracepoint_opts *opts) + { + DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts); +- char errmsg[STRERR_BUFSIZE]; + struct bpf_link *link; + int pfd, err; + +@@ -12464,7 +12425,7 @@ struct bpf_link *bpf_program__attach_tracepoint_opts(const struct bpf_program *p + if (pfd < 0) { + pr_warn("prog '%s': failed to create tracepoint '%s/%s' perf event: %s\n", + prog->name, tp_category, tp_name, +- libbpf_strerror_r(pfd, errmsg, sizeof(errmsg))); ++ errstr(pfd)); + return libbpf_err_ptr(pfd); + } + link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts); +@@ -12473,7 +12434,7 @@ struct bpf_link *bpf_program__attach_tracepoint_opts(const struct bpf_program *p + close(pfd); + pr_warn("prog '%s': failed to attach to tracepoint '%s/%s': %s\n", + prog->name, tp_category, tp_name, +- libbpf_strerror_r(err, errmsg, sizeof(errmsg))); ++ errstr(err)); + return libbpf_err_ptr(err); + } + return link; +@@ -12524,7 +12485,6 @@ bpf_program__attach_raw_tracepoint_opts(const struct bpf_program *prog, + struct bpf_raw_tracepoint_opts *opts) + { + LIBBPF_OPTS(bpf_raw_tp_opts, raw_opts); +- char errmsg[STRERR_BUFSIZE]; + struct bpf_link *link; + int prog_fd, pfd; + +@@ -12549,7 +12509,7 @@ bpf_program__attach_raw_tracepoint_opts(const struct bpf_program *prog, + pfd = -errno; + free(link); + pr_warn("prog '%s': failed to attach to raw tracepoint '%s': %s\n", +- prog->name, tp_name, libbpf_strerror_r(pfd, errmsg, sizeof(errmsg))); ++ prog->name, tp_name, errstr(pfd)); + return libbpf_err_ptr(pfd); + } + link->fd = pfd; +@@ -12608,7 +12568,6 @@ static struct bpf_link *bpf_program__attach_btf_id(const struct bpf_program *pro + const struct bpf_trace_opts *opts) + { + LIBBPF_OPTS(bpf_link_create_opts, link_opts); +- char errmsg[STRERR_BUFSIZE]; + struct bpf_link *link; + int prog_fd, pfd; + +@@ -12633,7 +12592,7 @@ static struct bpf_link *bpf_program__attach_btf_id(const struct bpf_program *pro + pfd = -errno; + free(link); + pr_warn("prog '%s': failed to attach: %s\n", +- prog->name, libbpf_strerror_r(pfd, errmsg, sizeof(errmsg))); ++ prog->name, errstr(pfd)); + return libbpf_err_ptr(pfd); + } + link->fd = pfd; +@@ -12674,7 +12633,6 @@ bpf_program_attach_fd(const struct bpf_program *prog, + const struct bpf_link_create_opts *opts) + { + enum bpf_attach_type attach_type; +- char errmsg[STRERR_BUFSIZE]; + struct bpf_link *link; + int prog_fd, link_fd; + +@@ -12696,7 +12654,7 @@ bpf_program_attach_fd(const struct bpf_program *prog, + free(link); + pr_warn("prog '%s': failed to attach to %s: %s\n", + prog->name, target_name, +- libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg))); ++ errstr(link_fd)); + return libbpf_err_ptr(link_fd); + } + link->fd = link_fd; +@@ -12838,7 +12796,6 @@ bpf_program__attach_iter(const struct bpf_program *prog, + const struct bpf_iter_attach_opts *opts) + { + DECLARE_LIBBPF_OPTS(bpf_link_create_opts, link_create_opts); +- char errmsg[STRERR_BUFSIZE]; + struct bpf_link *link; + int prog_fd, link_fd; + __u32 target_fd = 0; +@@ -12866,7 +12823,7 @@ bpf_program__attach_iter(const struct bpf_program *prog, + link_fd = -errno; + free(link); + pr_warn("prog '%s': failed to attach to iterator: %s\n", +- prog->name, libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg))); ++ prog->name, errstr(link_fd)); + return libbpf_err_ptr(link_fd); + } + link->fd = link_fd; +@@ -12908,12 +12865,10 @@ struct bpf_link *bpf_program__attach_netfilter(const struct bpf_program *prog, + + link_fd = bpf_link_create(prog_fd, 0, BPF_NETFILTER, &lopts); + if (link_fd < 0) { +- char errmsg[STRERR_BUFSIZE]; +- + link_fd = -errno; + free(link); + pr_warn("prog '%s': failed to attach to netfilter: %s\n", +- prog->name, libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg))); ++ prog->name, errstr(link_fd)); + return libbpf_err_ptr(link_fd); + } + link->fd = link_fd; +@@ -13198,7 +13153,6 @@ perf_buffer__open_cpu_buf(struct perf_buffer *pb, struct perf_event_attr *attr, + int cpu, int map_key) + { + struct perf_cpu_buf *cpu_buf; +- char msg[STRERR_BUFSIZE]; + int err; + + cpu_buf = calloc(1, sizeof(*cpu_buf)); +@@ -13214,7 +13168,7 @@ perf_buffer__open_cpu_buf(struct perf_buffer *pb, struct perf_event_attr *attr, + if (cpu_buf->fd < 0) { + err = -errno; + pr_warn("failed to open perf buffer event on cpu #%d: %s\n", +- cpu, libbpf_strerror_r(err, msg, sizeof(msg))); ++ cpu, errstr(err)); + goto error; + } + +@@ -13225,14 +13179,14 @@ perf_buffer__open_cpu_buf(struct perf_buffer *pb, struct perf_event_attr *attr, + cpu_buf->base = NULL; + err = -errno; + pr_warn("failed to mmap perf buffer on cpu #%d: %s\n", +- cpu, libbpf_strerror_r(err, msg, sizeof(msg))); ++ cpu, errstr(err)); + goto error; + } + + if (ioctl(cpu_buf->fd, PERF_EVENT_IOC_ENABLE, 0) < 0) { + err = -errno; + pr_warn("failed to enable perf buffer event on cpu #%d: %s\n", +- cpu, libbpf_strerror_r(err, msg, sizeof(msg))); ++ cpu, errstr(err)); + goto error; + } + +@@ -13307,7 +13261,6 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, + { + const char *online_cpus_file = "/sys/devices/system/cpu/online"; + struct bpf_map_info map; +- char msg[STRERR_BUFSIZE]; + struct perf_buffer *pb; + bool *online = NULL; + __u32 map_info_len; +@@ -13330,7 +13283,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, + */ + if (err != -EINVAL) { + pr_warn("failed to get map info for map FD %d: %s\n", +- map_fd, libbpf_strerror_r(err, msg, sizeof(msg))); ++ map_fd, errstr(err)); + return ERR_PTR(err); + } + pr_debug("failed to get map info for FD %d; API not supported? Ignoring...\n", +@@ -13360,7 +13313,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, + if (pb->epoll_fd < 0) { + err = -errno; + pr_warn("failed to create epoll instance: %s\n", +- libbpf_strerror_r(err, msg, sizeof(msg))); ++ errstr(err)); + goto error; + } + +@@ -13391,7 +13344,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, + + err = parse_cpu_mask_file(online_cpus_file, &online, &n); + if (err) { +- pr_warn("failed to get online CPU mask: %d\n", err); ++ pr_warn("failed to get online CPU mask: %s\n", errstr(err)); + goto error; + } + +@@ -13422,7 +13375,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, + err = -errno; + pr_warn("failed to set cpu #%d, key %d -> perf FD %d: %s\n", + cpu, map_key, cpu_buf->fd, +- libbpf_strerror_r(err, msg, sizeof(msg))); ++ errstr(err)); + goto error; + } + +@@ -13433,7 +13386,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, + err = -errno; + pr_warn("failed to epoll_ctl cpu #%d perf FD %d: %s\n", + cpu, cpu_buf->fd, +- libbpf_strerror_r(err, msg, sizeof(msg))); ++ errstr(err)); + goto error; + } + j++; +@@ -13528,7 +13481,7 @@ int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms) + + err = perf_buffer__process_records(pb, cpu_buf); + if (err) { +- pr_warn("error while processing records: %d\n", err); ++ pr_warn("error while processing records: %s\n", errstr(err)); + return libbpf_err(err); + } + } +@@ -13612,7 +13565,8 @@ int perf_buffer__consume(struct perf_buffer *pb) + + err = perf_buffer__process_records(pb, cpu_buf); + if (err) { +- pr_warn("perf_buffer: failed to process records in buffer #%d: %d\n", i, err); ++ pr_warn("perf_buffer: failed to process records in buffer #%d: %s\n", ++ i, errstr(err)); + return libbpf_err(err); + } + } +@@ -13723,14 +13677,14 @@ int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz) + fd = open(fcpu, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + err = -errno; +- pr_warn("Failed to open cpu mask file %s: %d\n", fcpu, err); ++ pr_warn("Failed to open cpu mask file %s: %s\n", fcpu, errstr(err)); + return err; + } + len = read(fd, buf, sizeof(buf)); + close(fd); + if (len <= 0) { + err = len ? -errno : -EINVAL; +- pr_warn("Failed to read cpu mask from %s: %d\n", fcpu, err); ++ pr_warn("Failed to read cpu mask from %s: %s\n", fcpu, errstr(err)); + return err; + } + if (len >= sizeof(buf)) { +@@ -13822,20 +13776,21 @@ int bpf_object__open_skeleton(struct bpf_object_skeleton *s, + obj = bpf_object_open(NULL, s->data, s->data_sz, s->name, opts); + if (IS_ERR(obj)) { + err = PTR_ERR(obj); +- pr_warn("failed to initialize skeleton BPF object '%s': %d\n", s->name, err); ++ pr_warn("failed to initialize skeleton BPF object '%s': %s\n", ++ s->name, errstr(err)); + return libbpf_err(err); + } + + *s->obj = obj; + err = populate_skeleton_maps(obj, s->maps, s->map_cnt, s->map_skel_sz); + if (err) { +- pr_warn("failed to populate skeleton maps for '%s': %d\n", s->name, err); ++ pr_warn("failed to populate skeleton maps for '%s': %s\n", s->name, errstr(err)); + return libbpf_err(err); + } + + err = populate_skeleton_progs(obj, s->progs, s->prog_cnt, s->prog_skel_sz); + if (err) { +- pr_warn("failed to populate skeleton progs for '%s': %d\n", s->name, err); ++ pr_warn("failed to populate skeleton progs for '%s': %s\n", s->name, errstr(err)); + return libbpf_err(err); + } + +@@ -13865,13 +13820,13 @@ int bpf_object__open_subskeleton(struct bpf_object_subskeleton *s) + + err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt, s->map_skel_sz); + if (err) { +- pr_warn("failed to populate subskeleton maps: %d\n", err); ++ pr_warn("failed to populate subskeleton maps: %s\n", errstr(err)); + return libbpf_err(err); + } + + err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt, s->prog_skel_sz); + if (err) { +- pr_warn("failed to populate subskeleton maps: %d\n", err); ++ pr_warn("failed to populate subskeleton maps: %s\n", errstr(err)); + return libbpf_err(err); + } + +@@ -13918,7 +13873,7 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s) + + err = bpf_object__load(*s->obj); + if (err) { +- pr_warn("failed to load BPF skeleton '%s': %d\n", s->name, err); ++ pr_warn("failed to load BPF skeleton '%s': %s\n", s->name, errstr(err)); + return libbpf_err(err); + } + +@@ -13957,8 +13912,8 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s) + + err = prog->sec_def->prog_attach_fn(prog, prog->sec_def->cookie, link); + if (err) { +- pr_warn("prog '%s': failed to auto-attach: %d\n", +- bpf_program__name(prog), err); ++ pr_warn("prog '%s': failed to auto-attach: %s\n", ++ bpf_program__name(prog), errstr(err)); + return libbpf_err(err); + } + +@@ -14007,7 +13962,8 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s) + *link = bpf_map__attach_struct_ops(map); + if (!*link) { + err = -errno; +- pr_warn("map '%s': failed to auto-attach: %d\n", bpf_map__name(map), err); ++ pr_warn("map '%s': failed to auto-attach: %s\n", ++ bpf_map__name(map), errstr(err)); + return libbpf_err(err); + } + } +-- +2.53.0 + diff --git a/queue-6.12/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch b/queue-6.12/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch new file mode 100644 index 0000000000..bb65a89ca8 --- /dev/null +++ b/queue-6.12/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch @@ -0,0 +1,75 @@ +From 8dcaa75c83c22ab5eecb66d5eb47d264df684c00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:15:07 -0700 +Subject: locking: Fix rwlock support in + +From: Bart Van Assche + +[ Upstream commit 756a0e011cfca0b45a48464aa25b05d9a9c2fb0b ] + +Architecture support for rwlocks must be available whether or not +CONFIG_DEBUG_SPINLOCK has been defined. Move the definitions of the +arch_{read,write}_{lock,trylock,unlock}() macros such that these become +visbile if CONFIG_DEBUG_SPINLOCK=n. + +This patch prepares for converting do_raw_{read,write}_trylock() into +inline functions. Without this patch that conversion triggers a build +failure for UP architectures, e.g. arm-ep93xx. I used the following +kernel configuration to build the kernel for that architecture: + + CONFIG_ARCH_MULTIPLATFORM=y + CONFIG_ARCH_MULTI_V7=n + CONFIG_ATAGS=y + CONFIG_MMU=y + CONFIG_ARCH_MULTI_V4T=y + CONFIG_CPU_LITTLE_ENDIAN=y + CONFIG_ARCH_EP93XX=y + +Fixes: fb1c8f93d869 ("[PATCH] spinlock consolidation") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260313171510.230998-2-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/spinlock_up.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h +index c87204247592f..a132fc562297a 100644 +--- a/include/linux/spinlock_up.h ++++ b/include/linux/spinlock_up.h +@@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + lock->slock = 1; + } + +-/* +- * Read-write spinlocks. No debug version. +- */ +-#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) +- + #else /* DEBUG_SPINLOCK */ + #define arch_spin_is_locked(lock) ((void)(lock), 0) + /* for sched/core.c and kernel_lock.c: */ +@@ -68,4 +58,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + + #define arch_spin_is_contended(lock) (((void)(lock), 0)) + ++/* ++ * Read-write spinlocks. No debug version. ++ */ ++#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) ++ + #endif /* __LINUX_SPINLOCK_UP_H */ +-- +2.53.0 + diff --git a/queue-6.12/loop-fix-partition-scan-race-between-udev-and-loop_r.patch b/queue-6.12/loop-fix-partition-scan-race-between-udev-and-loop_r.patch new file mode 100644 index 0000000000..29d3a597e0 --- /dev/null +++ b/queue-6.12/loop-fix-partition-scan-race-between-udev-and-loop_r.patch @@ -0,0 +1,87 @@ +From 746153d2c4edc38a4dc6f9ce9d3ed85804bb8588 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:51:28 +0000 +Subject: loop: fix partition scan race between udev and + loop_reread_partitions() + +From: Daan De Meyer + +[ Upstream commit 267ec4d7223a783f029a980f41b93c39b17996da ] + +When LOOP_CONFIGURE is called with LO_FLAGS_PARTSCAN, the following +sequence occurs: + + 1. disk_force_media_change() sets GD_NEED_PART_SCAN + 2. Uevent suppression is lifted and a KOBJ_CHANGE uevent is sent + 3. loop_global_unlock() releases the lock + 4. loop_reread_partitions() calls bdev_disk_changed() to scan + +There is a race between steps 2 and 4: when udev receives the uevent +and opens the device before loop_reread_partitions() runs, +blkdev_get_whole() in bdev.c sees GD_NEED_PART_SCAN set and calls +bdev_disk_changed() for a first scan. Then loop_reread_partitions() +does a second scan. The open_mutex serializes these two scans, but +does not prevent both from running. + +The second scan in bdev_disk_changed() drops all partition devices +from the first scan (via blk_drop_partitions()) before re-adding +them, causing partition block devices to briefly disappear. This +breaks any systemd unit with BindsTo= on the partition device: systemd +observes the device going dead, fails the dependent units, and does +not retry them when the device reappears. + +Fix this by removing the GD_NEED_PART_SCAN set from +disk_force_media_change() entirely. None of the current callers need +the lazy on-open partition scan triggered by this flag: + + - floppy: sets GENHD_FL_NO_PART, so disk_has_partscan() is always + false and GD_NEED_PART_SCAN has no effect. + - loop (loop_configure, loop_change_fd): when LO_FLAGS_PARTSCAN is + set, loop_reread_partitions() performs an explicit scan. When not + set, GD_SUPPRESS_PART_SCAN prevents the lazy scan path. + - loop (__loop_clr_fd): calls bdev_disk_changed() explicitly if + LO_FLAGS_PARTSCAN is set. + - nbd (nbd_clear_sock_ioctl): capacity is set to zero immediately + after; nbd manages GD_NEED_PART_SCAN explicitly elsewhere. + +With GD_NEED_PART_SCAN no longer set by disk_force_media_change(), +udev opening the loop device after the uevent no longer triggers a +redundant scan in blkdev_get_whole(), and only the single explicit +scan from loop_reread_partitions() runs. + +A regression test for this bug has been submitted to blktests: +https://github.com/linux-blktests/blktests/pull/240. + +Fixes: 9f65c489b68d ("loop: raise media_change event") +Signed-off-by: Daan De Meyer +Acked-by: Christian Brauner +Link: https://patch.msgid.link/20260331105130.1077599-1-daan@amutable.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/disk-events.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/block/disk-events.c b/block/disk-events.c +index 2f697224386aa..868823915bdc6 100644 +--- a/block/disk-events.c ++++ b/block/disk-events.c +@@ -290,13 +290,14 @@ EXPORT_SYMBOL(disk_check_media_change); + * Should be called when the media changes for @disk. Generates a uevent + * and attempts to free all dentries and inodes and invalidates all block + * device page cache entries in that case. ++ * ++ * Callers that need a partition re-scan should arrange for one explicitly. + */ + void disk_force_media_change(struct gendisk *disk) + { + disk_event_uevent(disk, DISK_EVENT_MEDIA_CHANGE); + inc_diskseq(disk); + bdev_mark_dead(disk->part0, true); +- set_bit(GD_NEED_PART_SCAN, &disk->state); + } + EXPORT_SYMBOL_GPL(disk_force_media_change); + +-- +2.53.0 + diff --git a/queue-6.12/macvlan-annotate-data-races-around-port-bc_queue_len.patch b/queue-6.12/macvlan-annotate-data-races-around-port-bc_queue_len.patch new file mode 100644 index 0000000000..547906d335 --- /dev/null +++ b/queue-6.12/macvlan-annotate-data-races-around-port-bc_queue_len.patch @@ -0,0 +1,67 @@ +From 3802893e1023b345a7b4f7de4125abf4a4cd312a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:38:08 +0000 +Subject: macvlan: annotate data-races around port->bc_queue_len_used + +From: Eric Dumazet + +[ Upstream commit 1ef5789d9906df3771c99b7f413caaf2bf473ca5 ] + +port->bc_queue_len_used is read and written locklessly, +add READ_ONCE()/WRITE_ONCE() annotations. + +While WRITE_ONCE() in macvlan_fill_info() is not yet needed, +it is a prereq for future RTNL avoidance. + +Fixes: d4bff72c8401 ("macvlan: Support for high multicast packet rate") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401103809.3038139-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index 3770bc84a9445..b43a1221a5908 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -351,6 +351,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + const struct macvlan_dev *src, + struct sk_buff *skb) + { ++ u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used); + struct sk_buff *nskb; + int err = -ENOMEM; + +@@ -361,7 +362,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + MACVLAN_SKB_CB(nskb)->src = src; + + spin_lock(&port->bc_queue.lock); +- if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) { ++ if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) { + if (src) + dev_hold(src->dev); + __skb_queue_tail(&port->bc_queue, nskb); +@@ -1723,7 +1724,8 @@ static int macvlan_fill_info(struct sk_buff *skb, + } + if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) + goto nla_put_failure; +- if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) ++ if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, ++ READ_ONCE(port->bc_queue_len_used))) + goto nla_put_failure; + if (port->bc_cutoff != 1 && + nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff)) +@@ -1783,7 +1785,7 @@ static void update_port_bc_queue_len(struct macvlan_port *port) + if (vlan->bc_queue_len_req > max_bc_queue_len_req) + max_bc_queue_len_req = vlan->bc_queue_len_req; + } +- port->bc_queue_len_used = max_bc_queue_len_req; ++ WRITE_ONCE(port->bc_queue_len_used, max_bc_queue_len_req); + } + + static int macvlan_device_event(struct notifier_block *unused, +-- +2.53.0 + diff --git a/queue-6.12/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch b/queue-6.12/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch new file mode 100644 index 0000000000..cb8a73c866 --- /dev/null +++ b/queue-6.12/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch @@ -0,0 +1,56 @@ +From f07c3efb4c564b091d4b1bf2a5b9a13dd2be7074 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:53:49 +0800 +Subject: macvlan: fix macvlan_get_size() not reserving space for + IFLA_MACVLAN_BC_CUTOFF + +From: Dudu Lu + +[ Upstream commit fa92a77b0ed4d5f11a71665a232ac5a54a4b055d ] + +macvlan_get_size() does not account for IFLA_MACVLAN_BC_CUTOFF, but +macvlan_fill_info() conditionally includes it when port->bc_cutoff != 1. +This causes nla_put_s32() to fail with -EMSGSIZE when the netlink skb +runs out of space, triggering a WARN_ON in rtnetlink and preventing the +interface from being dumped. + +The bug can be reproduced with: + + ip link add macvlan0 link eth0 type macvlan mode bridge + ip link set macvlan0 type macvlan bc_cutoff 0 + ip -d link show macvlan0 # fails with -EMSGSIZE + +The bc_cutoff feature was added in commit 954d1fa1ac93 ("macvlan: Add +netlink attribute for broadcast cutoff"), which added the nla_put_s32() +call in macvlan_fill_info() but missed adding the corresponding +nla_total_size(4) in macvlan_get_size(). A follow-up commit +55cef78c244d ("macvlan: add forgotten nla_policy for +IFLA_MACVLAN_BC_CUTOFF") fixed the missing nla_policy entry but still +did not fix the size calculation. + +Fixes: 954d1fa1ac93 ("macvlan: Add netlink attribute for broadcast cutoff") +Signed-off-by: Dudu Lu +Reviewed-by: Vadim Fedorenko +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260413085349.73977-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index b43a1221a5908..e778367c1d296 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -1678,6 +1678,7 @@ static size_t macvlan_get_size(const struct net_device *dev) + + macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN_USED */ ++ + nla_total_size(4) /* IFLA_MACVLAN_BC_CUTOFF */ + ); + } + +-- +2.53.0 + diff --git a/queue-6.12/mailbox-add-sanity-check-for-channel-array.patch b/queue-6.12/mailbox-add-sanity-check-for-channel-array.patch new file mode 100644 index 0000000000..6733153df7 --- /dev/null +++ b/queue-6.12/mailbox-add-sanity-check-for-channel-array.patch @@ -0,0 +1,40 @@ +From 9d2bc04dcc0e5339ac9507bcb362efaf8f15fa7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:42:38 +0200 +Subject: mailbox: add sanity check for channel array + +From: Wolfram Sang + +[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ] + +Fail gracefully if there is no channel array attached to the mailbox +controller. Otherwise the later dereference will cause an OOPS which +might not be seen because mailbox controllers might instantiate very +early. Remove the comment explaining the obvious while here. + +Fixes: 2b6d83e2b8b7 ("mailbox: Introduce framework for mailbox") +Signed-off-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index b4d52b814055b..39269359e3a64 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -520,8 +520,7 @@ int mbox_controller_register(struct mbox_controller *mbox) + { + int i, txdone; + +- /* Sanity check */ +- if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) ++ if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) + return -EINVAL; + + if (mbox->txdone_irq) +-- +2.53.0 + diff --git a/queue-6.12/mailbox-mailbox-test-don-t-free-the-reused-channel.patch b/queue-6.12/mailbox-mailbox-test-don-t-free-the-reused-channel.patch new file mode 100644 index 0000000000..902442adb5 --- /dev/null +++ b/queue-6.12/mailbox-mailbox-test-don-t-free-the-reused-channel.patch @@ -0,0 +1,46 @@ +From cc11caa3dae0a4ba9c4cf137cd7e078ee1433a16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:34 +0200 +Subject: mailbox: mailbox-test: don't free the reused channel + +From: Wolfram Sang + +[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ] + +The RX channel can be aliased to the TX channel if it has a different +MMIO. This special case needs to be handled when freeing the channels +otherwise a double-free occurs. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 2e0ce6c590485..30b0a230a3e28 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -422,7 +422,7 @@ static int mbox_test_probe(struct platform_device *pdev) + err_free_chans: + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + return ret; + } +@@ -435,7 +435,7 @@ static void mbox_test_remove(struct platform_device *pdev) + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + } + +-- +2.53.0 + diff --git a/queue-6.12/mailbox-mailbox-test-free-channels-on-probe-error.patch b/queue-6.12/mailbox-mailbox-test-free-channels-on-probe-error.patch new file mode 100644 index 0000000000..d11d207a8b --- /dev/null +++ b/queue-6.12/mailbox-mailbox-test-free-channels-on-probe-error.patch @@ -0,0 +1,60 @@ +From c1afec1fedd776ce6ad250be77f8299cf58d6fc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 14:53:00 +0200 +Subject: mailbox: mailbox-test: free channels on probe error + +From: Wolfram Sang + +[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ] + +On probe error, free the previously obtained channels. This not only +prevents a leak, but also UAF scenarios because the client structure +will be removed nonetheless because it was allocated with devm. + +Link: https://sashiko.dev/#/patchset/20260327151217.5327-2-wsa%2Brenesas%40sang-engineering.com +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index e416ce9e2d674..2e0ce6c590485 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -404,18 +404,27 @@ static int mbox_test_probe(struct platform_device *pdev) + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +- if (!tdev->rx_buffer) +- return -ENOMEM; ++ if (!tdev->rx_buffer) { ++ ret = -ENOMEM; ++ goto err_free_chans; ++ } + } + + ret = mbox_test_add_debugfs(pdev, tdev); + if (ret) +- return ret; ++ goto err_free_chans; + + init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; ++ ++err_free_chans: ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ if (tdev->rx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ return ret; + } + + static void mbox_test_remove(struct platform_device *pdev) +-- +2.53.0 + diff --git a/queue-6.12/mailbox-mailbox-test-initialize-struct-earlier.patch b/queue-6.12/mailbox-mailbox-test-initialize-struct-earlier.patch new file mode 100644 index 0000000000..74bdac300b --- /dev/null +++ b/queue-6.12/mailbox-mailbox-test-initialize-struct-earlier.patch @@ -0,0 +1,64 @@ +From 71e7e1a563c25a87095636bc41aa38b67789c841 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:35 +0200 +Subject: mailbox: mailbox-test: initialize struct earlier + +From: Wolfram Sang + +[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ] + +The waitqueue must be initialized before the debugfs files are created +because from that time, requests from userspace can already be made. +Similarily, drvdata and spinlock needs to be initialized before we +request the channel, otherwise dangling irqs might run into problems +like a NULL pointer exception. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 30b0a230a3e28..9eeb0b61b887c 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -366,6 +366,12 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev) + return -ENOMEM; + ++ tdev->dev = &pdev->dev; ++ spin_lock_init(&tdev->lock); ++ mutex_init(&tdev->mutex); ++ init_waitqueue_head(&tdev->waitq); ++ platform_set_drvdata(pdev, tdev); ++ + /* It's okay for MMIO to be NULL */ + tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { +@@ -395,12 +401,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) + tdev->rx_channel = tdev->tx_channel; + +- tdev->dev = &pdev->dev; +- platform_set_drvdata(pdev, tdev); +- +- spin_lock_init(&tdev->lock); +- mutex_init(&tdev->mutex); +- + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +@@ -414,7 +414,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (ret) + goto err_free_chans; + +- init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch b/queue-6.12/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch new file mode 100644 index 0000000000..8826fce8ae --- /dev/null +++ b/queue-6.12/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch @@ -0,0 +1,73 @@ +From 399ca53abde044691e4f2b25141efe33614ac020 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:36 +0200 +Subject: mailbox: mailbox-test: make data_ready a per-instance variable + +From: Wolfram Sang + +[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ] + +While not the default case, multiple tests can be run simultaneously. +Then, data_ready being a global variable will be overwritten and the +per-instance lock will not help. Turn the global variable into a +per-instance one to avoid this problem. + +Fixes: e339c80af95e ("mailbox: mailbox-test: don't rely on rx_buffer content to signal data ready") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 9eeb0b61b887c..b4ed96be815db 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -28,8 +28,6 @@ + #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ + (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) + +-static bool mbox_data_ready; +- + struct mbox_test_device { + struct device *dev; + void __iomem *tx_mmio; +@@ -42,6 +40,7 @@ struct mbox_test_device { + spinlock_t lock; + struct mutex mutex; + wait_queue_head_t waitq; ++ bool data_ready; + struct fasync_struct *async_queue; + struct dentry *root_debugfs_dir; + }; +@@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); +- data_ready = mbox_data_ready; ++ data_ready = tdev->data_ready; + spin_unlock_irqrestore(&tdev->lock, flags); + + return data_ready; +@@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, + *(touser + l) = '\0'; + + memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); +- mbox_data_ready = false; ++ tdev->data_ready = false; + + spin_unlock_irqrestore(&tdev->lock, flags); + +@@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) + message, MBOX_MAX_MSG_LEN); + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); + } +- mbox_data_ready = true; ++ tdev->data_ready = true; + spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); +-- +2.53.0 + diff --git a/queue-6.12/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch b/queue-6.12/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch new file mode 100644 index 0000000000..b60c4aed83 --- /dev/null +++ b/queue-6.12/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch @@ -0,0 +1,48 @@ +From b59ed09675bc81b4b0bcb94c96b753baa6b755eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:07:11 +0800 +Subject: mailbox: mtk-cmdq: Fix CURR and END addr for task insert case + +From: Jason-JH Lin + +[ Upstream commit d2591db9c8ef19fbb4d24ed15e0c6edfa6bc7917 ] + +Fix CURR and END address calculation for inserting a cmdq task into the +task list by using cmdq_reg_shift_addr() for proper address converting. +This ensures both CURR and END addresses are set correctly when +enabling the thread. + +Fixes: a195c7ccfb7a ("mailbox: mtk-cmdq: Refine DMA address handling for the command buffer") +Signed-off-by: Jason-JH Lin +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mtk-cmdq-mailbox.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c +index 80a10361492b0..f1159dabcd4e9 100644 +--- a/drivers/mailbox/mtk-cmdq-mailbox.c ++++ b/drivers/mailbox/mtk-cmdq-mailbox.c +@@ -434,14 +434,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data) + if (curr_pa == end_pa - CMDQ_INST_SIZE || + curr_pa == end_pa) { + /* set to this task directly */ +- writel(task->pa_base >> cmdq->pdata->shift, +- thread->base + CMDQ_THR_CURR_ADDR); ++ gce_addr = cmdq_convert_gce_addr(task->pa_base, cmdq->pdata); ++ writel(gce_addr, thread->base + CMDQ_THR_CURR_ADDR); + } else { + cmdq_task_insert_into_thread(task); + smp_mb(); /* modify jump before enable thread */ + } +- writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift, +- thread->base + CMDQ_THR_END_ADDR); ++ gce_addr = cmdq_convert_gce_addr(task->pa_base + pkt->cmd_buf_size, cmdq->pdata); ++ writel(gce_addr, thread->base + CMDQ_THR_END_ADDR); + cmdq_thread_resume(thread); + } + list_move_tail(&task->list_entry, &thread->task_busy_list); +-- +2.53.0 + diff --git a/queue-6.12/md-raid1-fix-the-comparing-region-of-interval-tree.patch b/queue-6.12/md-raid1-fix-the-comparing-region-of-interval-tree.patch new file mode 100644 index 0000000000..13fcc030b7 --- /dev/null +++ b/queue-6.12/md-raid1-fix-the-comparing-region-of-interval-tree.patch @@ -0,0 +1,51 @@ +From 498ba8bafa4bc353544683ba04ca7ea4df8cd647 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 09:18:33 +0800 +Subject: md/raid1: fix the comparing region of interval tree + +From: Xiao Ni + +[ Upstream commit de3544d2e5ea99064498de3c21ba490155864657 ] + +Interval tree uses [start, end] as a region which stores in the tree. +In raid1, it uses the wrong end value. For example: +bio(A,B) is too big and needs to be split to bio1(A,C-1), bio2(C,B). +The region of bio1 is [A,C] and the region of bio2 is [C,B]. So bio1 and +bio2 overlap which is not right. + +Fix this problem by using right end value of the region. + +Fixes: d0d2d8ba0494 ("md/raid1: introduce wait_for_serialization") +Signed-off-by: Xiao Ni +Link: https://lore.kernel.org/linux-raid/20260305011839.5118-2-xni@redhat.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid1.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 093b04e6be675..eb583df45ecbc 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -61,7 +61,7 @@ static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio, + unsigned long flags; + int ret = 0; + sector_t lo = r1_bio->sector; +- sector_t hi = lo + r1_bio->sectors; ++ sector_t hi = lo + r1_bio->sectors - 1; + struct serial_in_rdev *serial = &rdev->serial[idx]; + + spin_lock_irqsave(&serial->serial_lock, flags); +@@ -453,7 +453,7 @@ static void raid1_end_write_request(struct bio *bio) + int mirror = find_bio_disk(r1_bio, bio); + struct md_rdev *rdev = conf->mirrors[mirror].rdev; + sector_t lo = r1_bio->sector; +- sector_t hi = r1_bio->sector + r1_bio->sectors; ++ sector_t hi = r1_bio->sector + r1_bio->sectors - 1; + bool ignore_error = !raid1_should_handle_error(bio) || + (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD); + +-- +2.53.0 + diff --git a/queue-6.12/md-wake-raid456-reshape-waiters-before-suspend.patch b/queue-6.12/md-wake-raid456-reshape-waiters-before-suspend.patch new file mode 100644 index 0000000000..456b65a68a --- /dev/null +++ b/queue-6.12/md-wake-raid456-reshape-waiters-before-suspend.patch @@ -0,0 +1,59 @@ +From 1b77b49cde82a396bcbd97cd02cb65630d60c498 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 22:07:29 +0800 +Subject: md: wake raid456 reshape waiters before suspend + +From: Yu Kuai + +[ Upstream commit cf86bb53b9c92354904a328e947a05ffbfdd1840 ] + +During raid456 reshape, direct IO across the reshape position can sleep +in raid5_make_request() waiting for reshape progress while still +holding an active_io reference. If userspace then freezes reshape and +writes md/suspend_lo or md/suspend_hi, mddev_suspend() kills active_io +and waits for all in-flight IO to drain. + +This can deadlock: the IO needs reshape progress to continue, but the +reshape thread is already frozen, so the active_io reference is never +dropped and suspend never completes. + +raid5_prepare_suspend() already wakes wait_for_reshape for dm-raid. Do +the same for normal md suspend when reshape is already interrupted, so +waiting raid456 IO can abort, drop its reference, and let suspend +finish. + +The mdadm test tests/25raid456-reshape-deadlock reproduces the hang. + +Fixes: 714d20150ed8 ("md: add new helpers to suspend/resume array") +Link: https://lore.kernel.org/linux-raid/20260327140729.2030564-1-yukuai@fnnas.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 526390acd39e0..1aff3e541ceb5 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -470,6 +470,17 @@ int mddev_suspend(struct mddev *mddev, bool interruptible) + } + + percpu_ref_kill(&mddev->active_io); ++ ++ /* ++ * RAID456 IO can sleep in wait_for_reshape while still holding an ++ * active_io reference. If reshape is already interrupted or frozen, ++ * wake those waiters so they can abort and drop the reference instead ++ * of deadlocking suspend. ++ */ ++ if (mddev->pers && mddev->pers->prepare_suspend && ++ reshape_interrupted(mddev)) ++ mddev->pers->prepare_suspend(mddev); ++ + if (interruptible) + err = wait_event_interruptible(mddev->sb_wait, + percpu_ref_is_zero(&mddev->active_io)); +-- +2.53.0 + diff --git a/queue-6.12/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch b/queue-6.12/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch new file mode 100644 index 0000000000..8f63175e3d --- /dev/null +++ b/queue-6.12/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch @@ -0,0 +1,72 @@ +From 1fd37d8b384dd197c9d1a3b619649ab15fd2166c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 15:37:34 +0200 +Subject: media: i2c: og01a1b: Fix V4L2 subdevice data initialization on probe + +From: Vladimir Zapolskiy + +[ Upstream commit 535b7f106991c7d8f0e5b8e1769bfb8b1ce9d3d6 ] + +It's necessary to finalize the camera sensor subdevice initialization on +driver probe and clean V4L2 subdevice data up on error paths and driver +removal. + +The change fixes a previously reported by v4l2-compliance issue of +the failed VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT test: + + fail: v4l2-test-controls.cpp(1104): subscribe event for control 'User Controls' failed + +Fixes: 472377febf84 ("media: Add a driver for the og01a1b camera sensor") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/og01a1b.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c +index a9baf8095d4f3..68573122cd6ee 100644 +--- a/drivers/media/i2c/og01a1b.c ++++ b/drivers/media/i2c/og01a1b.c +@@ -1058,6 +1058,7 @@ static void og01a1b_remove(struct i2c_client *client) + struct og01a1b *og01a1b = to_og01a1b(sd); + + v4l2_async_unregister_subdev(sd); ++ v4l2_subdev_cleanup(&og01a1b->sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(og01a1b->dev); +@@ -1164,11 +1165,18 @@ static int og01a1b_probe(struct i2c_client *client) + goto probe_error_v4l2_ctrl_handler_free; + } + ++ ret = v4l2_subdev_init_finalize(&og01a1b->sd); ++ if (ret < 0) { ++ dev_err_probe(og01a1b->dev, ret, ++ "failed to finalize subdevice init\n"); ++ goto probe_error_media_entity_cleanup; ++ } ++ + ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); + if (ret < 0) { + dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d", + ret); +- goto probe_error_media_entity_cleanup; ++ goto probe_error_v4l2_subdev_cleanup; + } + + /* Enable runtime PM and turn off the device */ +@@ -1178,6 +1186,9 @@ static int og01a1b_probe(struct i2c_client *client) + + return 0; + ++probe_error_v4l2_subdev_cleanup: ++ v4l2_subdev_cleanup(&og01a1b->sd); ++ + probe_error_media_entity_cleanup: + media_entity_cleanup(&og01a1b->sd.entity); + +-- +2.53.0 + diff --git a/queue-6.12/media-i2c-og01a1b-replace-client-dev-usage.patch b/queue-6.12/media-i2c-og01a1b-replace-client-dev-usage.patch new file mode 100644 index 0000000000..bdade041ca --- /dev/null +++ b/queue-6.12/media-i2c-og01a1b-replace-client-dev-usage.patch @@ -0,0 +1,343 @@ +From 1673fc8c7e524754339e85228a72ab026c921da5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Aug 2025 00:45:28 +0300 +Subject: media: i2c: og01a1b: Replace client->dev usage + +From: Laurent Pinchart + +[ Upstream commit 4d58f671944a16314f03d3c0c40ee69058ca02c9 ] + +The driver needs to access the struct device in many places, and +retrieves it from the i2c_client itself retrieved with +v4l2_get_subdevdata(). Store it as a pointer in struct og01a1b and +access it from there instead, to simplify the driver. + +While at it, fix a mistake in the sort order of include statements. + +Signed-off-by: Laurent Pinchart +Signed-off-by: Sakari Ailus +Reviewed-by: Mehdi Djait +Signed-off-by: Hans Verkuil +Stable-dep-of: 535b7f106991 ("media: i2c: og01a1b: Fix V4L2 subdevice data initialization on probe") +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/og01a1b.c | 80 ++++++++++++++++++------------------- + 1 file changed, 38 insertions(+), 42 deletions(-) + +diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c +index b7d0b677975d5..a9baf8095d4f3 100644 +--- a/drivers/media/i2c/og01a1b.c ++++ b/drivers/media/i2c/og01a1b.c +@@ -1,7 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 + // Copyright (c) 2022 Intel Corporation. + +-#include + #include + #include + #include +@@ -10,6 +9,8 @@ + #include + #include + #include ++#include ++ + #include + #include + #include +@@ -421,6 +422,7 @@ static const struct og01a1b_mode supported_modes[] = { + }; + + struct og01a1b { ++ struct device *dev; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator *avdd; +@@ -512,7 +514,6 @@ static int og01a1b_write_reg(struct og01a1b *og01a1b, u16 reg, u16 len, u32 val) + static int og01a1b_write_reg_list(struct og01a1b *og01a1b, + const struct og01a1b_reg_list *r_list) + { +- struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); + unsigned int i; + int ret; + +@@ -520,7 +521,7 @@ static int og01a1b_write_reg_list(struct og01a1b *og01a1b, + ret = og01a1b_write_reg(og01a1b, r_list->regs[i].address, 1, + r_list->regs[i].val); + if (ret) { +- dev_err_ratelimited(&client->dev, ++ dev_err_ratelimited(og01a1b->dev, + "failed to write reg 0x%4.4x. error = %d", + r_list->regs[i].address, ret); + return ret; +@@ -544,7 +545,6 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) + { + struct og01a1b *og01a1b = container_of(ctrl->handler, + struct og01a1b, ctrl_handler); +- struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); + s64 exposure_max; + int ret = 0; + +@@ -560,7 +560,7 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) + } + + /* V4L2 controls values will be applied only when power is already up */ +- if (!pm_runtime_get_if_in_use(&client->dev)) ++ if (!pm_runtime_get_if_in_use(og01a1b->dev)) + return 0; + + switch (ctrl->id) { +@@ -596,7 +596,7 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) + break; + } + +- pm_runtime_put(&client->dev); ++ pm_runtime_put(og01a1b->dev); + + return ret; + } +@@ -688,7 +688,6 @@ static void og01a1b_update_pad_format(const struct og01a1b_mode *mode, + + static int og01a1b_start_streaming(struct og01a1b *og01a1b) + { +- struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); + const struct og01a1b_reg_list *reg_list; + int link_freq_index, ret; + +@@ -697,14 +696,14 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) + + ret = og01a1b_write_reg_list(og01a1b, reg_list); + if (ret) { +- dev_err(&client->dev, "failed to set plls"); ++ dev_err(og01a1b->dev, "failed to set plls"); + return ret; + } + + reg_list = &og01a1b->cur_mode->reg_list; + ret = og01a1b_write_reg_list(og01a1b, reg_list); + if (ret) { +- dev_err(&client->dev, "failed to set mode"); ++ dev_err(og01a1b->dev, "failed to set mode"); + return ret; + } + +@@ -716,7 +715,7 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) + OG01A1B_REG_VALUE_08BIT, + OG01A1B_MODE_STREAMING); + if (ret) { +- dev_err(&client->dev, "failed to set stream"); ++ dev_err(og01a1b->dev, "failed to set stream"); + return ret; + } + +@@ -725,22 +724,19 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) + + static void og01a1b_stop_streaming(struct og01a1b *og01a1b) + { +- struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); +- + if (og01a1b_write_reg(og01a1b, OG01A1B_REG_MODE_SELECT, + OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STANDBY)) +- dev_err(&client->dev, "failed to set stream"); ++ dev_err(og01a1b->dev, "failed to set stream"); + } + + static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) + { + struct og01a1b *og01a1b = to_og01a1b(sd); +- struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + mutex_lock(&og01a1b->mutex); + if (enable) { +- ret = pm_runtime_resume_and_get(&client->dev); ++ ret = pm_runtime_resume_and_get(og01a1b->dev); + if (ret) { + mutex_unlock(&og01a1b->mutex); + return ret; +@@ -750,11 +746,11 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) + if (ret) { + enable = 0; + og01a1b_stop_streaming(og01a1b); +- pm_runtime_put(&client->dev); ++ pm_runtime_put(og01a1b->dev); + } + } else { + og01a1b_stop_streaming(og01a1b); +- pm_runtime_put(&client->dev); ++ pm_runtime_put(og01a1b->dev); + } + + mutex_unlock(&og01a1b->mutex); +@@ -889,7 +885,6 @@ static const struct v4l2_subdev_internal_ops og01a1b_internal_ops = { + + static int og01a1b_identify_module(struct og01a1b *og01a1b) + { +- struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); + int ret; + u32 val; + +@@ -899,7 +894,7 @@ static int og01a1b_identify_module(struct og01a1b *og01a1b) + return ret; + + if (val != OG01A1B_CHIP_ID) { +- dev_err(&client->dev, "chip id mismatch: %x!=%x", ++ dev_err(og01a1b->dev, "chip id mismatch: %x!=%x", + OG01A1B_CHIP_ID, val); + return -ENXIO; + } +@@ -909,8 +904,7 @@ static int og01a1b_identify_module(struct og01a1b *og01a1b) + + static int og01a1b_check_hwcfg(struct og01a1b *og01a1b) + { +- struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); +- struct device *dev = &client->dev; ++ struct device *dev = og01a1b->dev; + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg = { +@@ -1066,7 +1060,7 @@ static void og01a1b_remove(struct i2c_client *client) + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); +- pm_runtime_disable(&client->dev); ++ pm_runtime_disable(og01a1b->dev); + mutex_destroy(&og01a1b->mutex); + } + +@@ -1079,34 +1073,36 @@ static int og01a1b_probe(struct i2c_client *client) + if (!og01a1b) + return -ENOMEM; + ++ og01a1b->dev = &client->dev; ++ + v4l2_i2c_subdev_init(&og01a1b->sd, client, &og01a1b_subdev_ops); + +- og01a1b->xvclk = devm_clk_get_optional(&client->dev, NULL); ++ og01a1b->xvclk = devm_clk_get_optional(og01a1b->dev, NULL); + if (IS_ERR(og01a1b->xvclk)) { + ret = PTR_ERR(og01a1b->xvclk); +- dev_err(&client->dev, "failed to get xvclk clock: %d\n", ret); ++ dev_err(og01a1b->dev, "failed to get xvclk clock: %d\n", ret); + return ret; + } + + ret = og01a1b_check_hwcfg(og01a1b); + if (ret) { +- dev_err(&client->dev, "failed to check HW configuration: %d", ++ dev_err(og01a1b->dev, "failed to check HW configuration: %d", + ret); + return ret; + } + +- og01a1b->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", ++ og01a1b->reset_gpio = devm_gpiod_get_optional(og01a1b->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(og01a1b->reset_gpio)) { +- dev_err(&client->dev, "cannot get reset GPIO\n"); ++ dev_err(og01a1b->dev, "cannot get reset GPIO\n"); + return PTR_ERR(og01a1b->reset_gpio); + } + +- og01a1b->avdd = devm_regulator_get_optional(&client->dev, "avdd"); ++ og01a1b->avdd = devm_regulator_get_optional(og01a1b->dev, "avdd"); + if (IS_ERR(og01a1b->avdd)) { + ret = PTR_ERR(og01a1b->avdd); + if (ret != -ENODEV) { +- dev_err_probe(&client->dev, ret, ++ dev_err_probe(og01a1b->dev, ret, + "Failed to get 'avdd' regulator\n"); + return ret; + } +@@ -1114,11 +1110,11 @@ static int og01a1b_probe(struct i2c_client *client) + og01a1b->avdd = NULL; + } + +- og01a1b->dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); ++ og01a1b->dovdd = devm_regulator_get_optional(og01a1b->dev, "dovdd"); + if (IS_ERR(og01a1b->dovdd)) { + ret = PTR_ERR(og01a1b->dovdd); + if (ret != -ENODEV) { +- dev_err_probe(&client->dev, ret, ++ dev_err_probe(og01a1b->dev, ret, + "Failed to get 'dovdd' regulator\n"); + return ret; + } +@@ -1126,11 +1122,11 @@ static int og01a1b_probe(struct i2c_client *client) + og01a1b->dovdd = NULL; + } + +- og01a1b->dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); ++ og01a1b->dvdd = devm_regulator_get_optional(og01a1b->dev, "dvdd"); + if (IS_ERR(og01a1b->dvdd)) { + ret = PTR_ERR(og01a1b->dvdd); + if (ret != -ENODEV) { +- dev_err_probe(&client->dev, ret, ++ dev_err_probe(og01a1b->dev, ret, + "Failed to get 'dvdd' regulator\n"); + return ret; + } +@@ -1139,13 +1135,13 @@ static int og01a1b_probe(struct i2c_client *client) + } + + /* The sensor must be powered on to read the CHIP_ID register */ +- ret = og01a1b_power_on(&client->dev); ++ ret = og01a1b_power_on(og01a1b->dev); + if (ret) + return ret; + + ret = og01a1b_identify_module(og01a1b); + if (ret) { +- dev_err(&client->dev, "failed to find sensor: %d", ret); ++ dev_err(og01a1b->dev, "failed to find sensor: %d", ret); + goto power_off; + } + +@@ -1153,7 +1149,7 @@ static int og01a1b_probe(struct i2c_client *client) + og01a1b->cur_mode = &supported_modes[0]; + ret = og01a1b_init_controls(og01a1b); + if (ret) { +- dev_err(&client->dev, "failed to init controls: %d", ret); ++ dev_err(og01a1b->dev, "failed to init controls: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + +@@ -1164,21 +1160,21 @@ static int og01a1b_probe(struct i2c_client *client) + og01a1b->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&og01a1b->sd.entity, 1, &og01a1b->pad); + if (ret) { +- dev_err(&client->dev, "failed to init entity pads: %d", ret); ++ dev_err(og01a1b->dev, "failed to init entity pads: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); + if (ret < 0) { +- dev_err(&client->dev, "failed to register V4L2 subdev: %d", ++ dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d", + ret); + goto probe_error_media_entity_cleanup; + } + + /* Enable runtime PM and turn off the device */ +- pm_runtime_set_active(&client->dev); +- pm_runtime_enable(&client->dev); +- pm_runtime_idle(&client->dev); ++ pm_runtime_set_active(og01a1b->dev); ++ pm_runtime_enable(og01a1b->dev); ++ pm_runtime_idle(og01a1b->dev); + + return 0; + +@@ -1190,7 +1186,7 @@ static int og01a1b_probe(struct i2c_client *client) + mutex_destroy(&og01a1b->mutex); + + power_off: +- og01a1b_power_off(&client->dev); ++ og01a1b_power_off(og01a1b->dev); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.12/memory-tegra124-emc-fix-dll_change-check.patch b/queue-6.12/memory-tegra124-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..cb31a29c69 --- /dev/null +++ b/queue-6.12/memory-tegra124-emc-fix-dll_change-check.patch @@ -0,0 +1,38 @@ +From 80ecb8f5c11346df727282d702cf7e4f406f8176 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:42 +0900 +Subject: memory: tegra124-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 9597ab9a8296ab337e6820f8a717ff621078b632 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: 73a7f0a90641 ("memory: tegra: Add EMC (external memory controller) driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-1-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra124-emc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c +index 03f1daa2d132a..71d20b5916d89 100644 +--- a/drivers/memory/tegra/tegra124-emc.c ++++ b/drivers/memory/tegra/tegra124-emc.c +@@ -608,7 +608,7 @@ static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, + + if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; +-- +2.53.0 + diff --git a/queue-6.12/memory-tegra30-emc-fix-dll_change-check.patch b/queue-6.12/memory-tegra30-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..071f39cc7e --- /dev/null +++ b/queue-6.12/memory-tegra30-emc-fix-dll_change-check.patch @@ -0,0 +1,47 @@ +From a8e571914b3ede3488b61530f0eaf6df73a2a2ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:43 +0900 +Subject: memory: tegra30-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 0a93f2355cf4922ad2399dbef5ea1049fef116d4 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: e34212c75a68 ("memory: tegra: Introduce Tegra30 EMC driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-2-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra30-emc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c +index 921dce1b8bc63..4981b7fa0f780 100644 +--- a/drivers/memory/tegra/tegra30-emc.c ++++ b/drivers/memory/tegra/tegra30-emc.c +@@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) + emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG); + emc_dbg = readl_relaxed(emc->regs + EMC_DBG); + +- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1)) ++ if (emc->dll_on == !(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; + +- emc->dll_on = !!(timing->emc_mode_1 & 0x1); ++ emc->dll_on = !(timing->emc_mode_1 & 0x1); + + if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL)) + emc->zcal_long = true; +-- +2.53.0 + diff --git a/queue-6.12/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch b/queue-6.12/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch new file mode 100644 index 0000000000..cc6e3c8bb3 --- /dev/null +++ b/queue-6.12/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch @@ -0,0 +1,37 @@ +From f1456fed792dd4190146e140f750db2a1b3c154c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:56:20 +0530 +Subject: mfd: mc13xxx-core: Fix memory leak in mc13xxx_add_subdevice_pdata() + +From: Abdun Nihaal + +[ Upstream commit a5a65a7fb2f7796bbe492cd6be59c92cb64377d1 ] + +The memory allocated for cell.name using kmemdup() is not freed when +mfd_add_devices() fails. Fix that by using devm_kmemdup(). + +Fixes: 8e00593557c3 ("mfd: Add mc13892 support to mc13xxx") +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20260120102622.66921-1-nihaal@cse.iitm.ac.in +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mc13xxx-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c +index 920797b806ced..786eab3b2d03c 100644 +--- a/drivers/mfd/mc13xxx-core.c ++++ b/drivers/mfd/mc13xxx-core.c +@@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return -E2BIG; + +- cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); ++ cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL); + if (!cell.name) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.12/module-fix-freeing-of-charp-module-parameters-when-c.patch b/queue-6.12/module-fix-freeing-of-charp-module-parameters-when-c.patch new file mode 100644 index 0000000000..3f7cfd973e --- /dev/null +++ b/queue-6.12/module-fix-freeing-of-charp-module-parameters-when-c.patch @@ -0,0 +1,122 @@ +From 22eb605e28b0490bd03067c52c51561e2d28a007 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:48:02 +0100 +Subject: module: Fix freeing of charp module parameters when CONFIG_SYSFS=n + +From: Petr Pavlu + +[ Upstream commit deffe1edba626d474fef38007c03646ca5876a0e ] + +When setting a charp module parameter, the param_set_charp() function +allocates memory to store a copy of the input value. Later, when the module +is potentially unloaded, the destroy_params() function is called to free +this allocated memory. + +However, destroy_params() is available only when CONFIG_SYSFS=y, otherwise +only a dummy variant is present. In the unlikely case that the kernel is +configured with CONFIG_MODULES=y and CONFIG_SYSFS=n, this results in +a memory leak of charp values when a module is unloaded. + +Fix this issue by making destroy_params() always available when +CONFIG_MODULES=y. Rename the function to module_destroy_params() to clarify +that it is intended for use by the module loader. + +Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs") +Signed-off-by: Petr Pavlu +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + include/linux/moduleparam.h | 11 +++-------- + kernel/module/main.c | 4 ++-- + kernel/params.c | 27 ++++++++++++++++++--------- + 3 files changed, 23 insertions(+), 19 deletions(-) + +diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h +index 110e9d09de243..4c0b436f2092a 100644 +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -396,14 +396,9 @@ extern char *parse_args(const char *name, + void *arg, parse_unknown_fn unknown); + + /* Called by module remove. */ +-#ifdef CONFIG_SYSFS +-extern void destroy_params(const struct kernel_param *params, unsigned num); +-#else +-static inline void destroy_params(const struct kernel_param *params, +- unsigned num) +-{ +-} +-#endif /* !CONFIG_SYSFS */ ++#ifdef CONFIG_MODULES ++void module_destroy_params(const struct kernel_param *params, unsigned int num); ++#endif + + /* All the helper functions */ + /* The macros to do compile-time type checking stolen from Jakub +diff --git a/kernel/module/main.c b/kernel/module/main.c +index 915a9cf33dd0d..ad58c44fb74fd 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -1286,7 +1286,7 @@ static void free_module(struct module *mod) + module_unload_free(mod); + + /* Free any allocated parameters. */ +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + + if (is_livepatch_module(mod)) + free_module_elf(mod); +@@ -3022,7 +3022,7 @@ static int load_module(struct load_info *info, const char __user *uargs, + mod_sysfs_teardown(mod); + coming_cleanup: + mod->state = MODULE_STATE_GOING; +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_GOING, mod); + klp_module_going(mod); +diff --git a/kernel/params.c b/kernel/params.c +index 2be5a083f9399..4495038fc2e7e 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -748,15 +748,6 @@ void module_param_sysfs_remove(struct module *mod) + } + #endif + +-void destroy_params(const struct kernel_param *params, unsigned num) +-{ +- unsigned int i; +- +- for (i = 0; i < num; i++) +- if (params[i].ops->free) +- params[i].ops->free(params[i].arg); +-} +- + struct module_kobject * __init_or_module + lookup_or_create_module_kobject(const char *name) + { +@@ -991,3 +982,21 @@ static int __init param_sysfs_builtin_init(void) + late_initcall(param_sysfs_builtin_init); + + #endif /* CONFIG_SYSFS */ ++ ++#ifdef CONFIG_MODULES ++ ++/* ++ * module_destroy_params - free all parameters for one module ++ * @params: module parameters (array) ++ * @num: number of module parameters ++ */ ++void module_destroy_params(const struct kernel_param *params, unsigned int num) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < num; i++) ++ if (params[i].ops->free) ++ params[i].ops->free(params[i].arg); ++} ++ ++#endif /* CONFIG_MODULES */ +-- +2.53.0 + diff --git a/queue-6.12/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch b/queue-6.12/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch new file mode 100644 index 0000000000..b91019b1a5 --- /dev/null +++ b/queue-6.12/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch @@ -0,0 +1,59 @@ +From d8a722e5d04437bfe9d8ddc8766867be99699ca3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:57 +0200 +Subject: mtd: parsers: ofpart: call of_node_get() for dedicated subpartitions + +From: Cosmin Tanislav + +[ Upstream commit e882626c1747653f1f01ea9d12e278e613b11d0f ] + +In order to parse sub-partitions, add_mtd_partitions() calls +parse_mtd_partitions() for all previously found partitions. + +Each partition will end up being passed to parse_fixed_partitions(), and +its of_node will be treated as the ofpart_node. + +Commit 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in +parse_fixed_partitions()") added of_node_put() calls for ofpart_node on +all exit paths. + +In the case where the partition passed to parse_fixed_partitions() has a +parent, it is treated as a dedicated partitions node, and of_node_put() +is wrongly called for it, even if of_node_get() was not called +explicitly. + +On repeated bind / unbinds of the MTD, the extra of_node_put() ends up +decrementing the refcount down to 0, which should never happen, +resulting in the following error: + +OF: ERROR: of_node_release() detected bad of_node_put() on +/soc/spi@80007000/flash@0/partitions/partition@0 + +Call of_node_get() to balance the call to of_node_put() done for +dedicated partitions nodes. + +Fixes: 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in parse_fixed_partitions()") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index a5ba78c6723ee..321002a1d0cae 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -71,7 +71,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + dedicated = false; + } + } else { /* Partition */ +- ofpart_node = mtd_node; ++ ofpart_node = of_node_get(mtd_node); + } + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); +-- +2.53.0 + diff --git a/queue-6.12/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch b/queue-6.12/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch new file mode 100644 index 0000000000..4747923e02 --- /dev/null +++ b/queue-6.12/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch @@ -0,0 +1,48 @@ +From cc84c2a414529872e0c233d95d3ec0cdb76a8b05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:56 +0200 +Subject: mtd: parsers: ofpart: call of_node_put() only in ofpart_fail path + +From: Cosmin Tanislav + +[ Upstream commit 0c87dea1aab86116211cb37387c404c9e9231c39 ] + +ofpart_none can only be reached after the for_each_child_of_node() loop +finishes. for_each_child_of_node() correctly calls of_node_put() for all +device nodes it iterates over as long as we don't break or jump out of +the loop. + +Calling of_node_put() inside the ofpart_none path will wrongly decrement +the ref count of the last node in the for_each_child_of_node() loop. + +Move the call to of_node_put() under the ofpart_fail label to fix this. + +Fixes: ebd5a74db74e ("mtd: ofpart: Check availability of reg property instead of name property") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 09961c6f39496..a5ba78c6723ee 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -191,11 +191,11 @@ static int parse_fixed_partitions(struct mtd_info *master, + ofpart_fail: + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", + master->name, pp, mtd_node); ++ of_node_put(pp); + ret = -EINVAL; + ofpart_none: + if (dedicated) + of_node_put(ofpart_node); +- of_node_put(pp); + kfree(parts); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.12/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch b/queue-6.12/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch new file mode 100644 index 0000000000..842607170a --- /dev/null +++ b/queue-6.12/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch @@ -0,0 +1,41 @@ +From 72bfdf6233ac9718e54efb4d324980fae0d0b608 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:43:36 +0800 +Subject: mtd: physmap_of_gemini: Fix disabled pinctrl state check + +From: Chen Ni + +[ Upstream commit b7c0982184b0661f5b1b805f3a56f1bd3757b63e ] + +The condition for checking the disabled pinctrl state incorrectly checks +gf->enabled_state instead of gf->disabled_state. This causes misleading +error messages and could lead to incorrect behavior when only one of the +pinctrl states is defined. + +Fix the condition to properly check gf->disabled_state. + +Fixes: 9d3b5086f6d4 ("mtd: physmap_of_gemini: Handle pin control") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/maps/physmap-gemini.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c +index 9d3b4bf84a1ad..1c34b4ef77ea3 100644 +--- a/drivers/mtd/maps/physmap-gemini.c ++++ b/drivers/mtd/maps/physmap-gemini.c +@@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev, + dev_err(dev, "no enabled pin control state\n"); + + gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled"); +- if (IS_ERR(gf->enabled_state)) { ++ if (IS_ERR(gf->disabled_state)) { + dev_err(dev, "no disabled pin control state\n"); + } else { + ret = pinctrl_select_state(gf->p, gf->disabled_state); +-- +2.53.0 + diff --git a/queue-6.12/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch b/queue-6.12/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch new file mode 100644 index 0000000000..4d32b1f13d --- /dev/null +++ b/queue-6.12/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch @@ -0,0 +1,66 @@ +From 6ebc33af53a9d3969e9fdb5e3b1daf85a4998f69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:24:30 +0100 +Subject: mtd: rawnand: sunxi: fix sunxi_nfc_hw_ecc_read_extra_oob + +From: Richard Genoud + +[ Upstream commit 848c13996c55fe4ea6bf5acc3ce6c8c5c944b5f6 ] + +When dumping the OOB, the bytes at the end where actually copied from +the beginning of the OOB instead of current_offset. + +That leads to something like: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +instead of: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +(example with BCH16, user data [8,0], no scrambling) + +*cur_off (offset from the beginning of the page) was compared to offset +(offset from the beginning of the OOB), and then, the +nand_change_read_column_op() sets the current position to the beginning +of the OOB instead of OOB+offset + +Fixes: 15d6f118285f ("mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode") +Reviewed-by: Jernej Skrabec +Signed-off-by: Richard Genoud +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/sunxi_nand.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c +index ac887754b98e2..136d67af97178 100644 +--- a/drivers/mtd/nand/raw/sunxi_nand.c ++++ b/drivers/mtd/nand/raw/sunxi_nand.c +@@ -886,9 +886,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, + if (len <= 0) + return; + +- if (!cur_off || *cur_off != offset) +- nand_change_read_column_op(nand, mtd->writesize, NULL, 0, +- false); ++ if (!cur_off || *cur_off != (offset + mtd->writesize)) ++ nand_change_read_column_op(nand, mtd->writesize + offset, ++ NULL, 0, false); + + if (!randomize) + sunxi_nfc_read_buf(nand, oob + offset, len); +-- +2.53.0 + diff --git a/queue-6.12/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch b/queue-6.12/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch new file mode 100644 index 0000000000..8163c4337a --- /dev/null +++ b/queue-6.12/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch @@ -0,0 +1,38 @@ +From ca99d666cf02a6b7cabc11161d540092cd6cc642 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 17:14:14 +0800 +Subject: mtd: spi-nor: core: correct the op.dummy.nbytes when check read + operations + +From: Haibo Chen + +[ Upstream commit 756564a536ecd8c9d33edd89f0647a91a0b03587 ] + +When check read operation, need to setting the op.dummy.nbytes based +on current read operation rather than the nor->read_proto. + +Fixes: 0e30f47232ab ("mtd: spi-nor: add support for DTR protocol") +Signed-off-by: Haibo Chen +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index a3e6a8c28dfbe..d666e044b0c4d 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -2416,7 +2416,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; +- if (spi_nor_protocol_is_dtr(nor->read_proto)) ++ if (spi_nor_protocol_is_dtr(read->proto)) + op.dummy.nbytes *= 2; + + return spi_nor_spimem_check_op(nor, &op); +-- +2.53.0 + diff --git a/queue-6.12/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch b/queue-6.12/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch new file mode 100644 index 0000000000..51b014cb37 --- /dev/null +++ b/queue-6.12/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch @@ -0,0 +1,88 @@ +From 3bb8120d32bd0e0deb06c0ac270546049c007541 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 16:47:59 +0900 +Subject: mtd: spi-nor: sfdp: introduce smpt_map_id fixup hook + +From: Takahiro Kuwano + +[ Upstream commit f74de390557bf2bcc5dca4a357b41c0701d3f76e ] + +Certain chips have inconsistent Sector Map Parameter Table (SMPT) data, +which leads to the wrong map ID being identified, causing failures to +detect the correct sector map. + +To fix this, introduce smpt_map_id() into the struct spi_nor_fixups. +This function will be called after the initial SMPT-based detection, +allowing chip-specific logic to correct the map ID. + +Infineon S25FS512S needs this fixup as it has inconsistency between map +ID definition and configuration register value actually obtained. + +Co-developed-by: Marek Vasut +Signed-off-by: Marek Vasut +Reviewed-by: Tudor Ambarus +Tested-by: Marek Vasut # S25FS512S +Signed-off-by: Takahiro Kuwano +Reviewed-by: Tudor Ambarus > +Signed-off-by: Pratyush Yadav +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 3 +++ + drivers/mtd/spi-nor/sfdp.c | 12 ++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 56718f954a859..3aeca2299ddb1 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -410,6 +410,8 @@ struct spi_nor_flash_parameter { + * @post_bfpt: called after the BFPT table has been parsed + * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the + * number of dummy cycles in read register ops. ++ * @smpt_map_id: called after map ID in SMPT table has been determined for the ++ * case the map ID is wrong and needs to be fixed. + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. +@@ -428,6 +430,7 @@ struct spi_nor_fixups { + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); + void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); ++ void (*smpt_map_id)(const struct spi_nor *nor, u8 *map_id); + int (*post_sfdp)(struct spi_nor *nor); + int (*late_init)(struct spi_nor *nor); + }; +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index 86d869810d07a..20b791568d5f0 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -726,6 +726,16 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) + return read_dummy; + } + ++static void spi_nor_smpt_map_id_fixups(const struct spi_nor *nor, u8 *map_id) ++{ ++ if (nor->manufacturer && nor->manufacturer->fixups && ++ nor->manufacturer->fixups->smpt_map_id) ++ nor->manufacturer->fixups->smpt_map_id(nor, map_id); ++ ++ if (nor->info->fixups && nor->info->fixups->smpt_map_id) ++ nor->info->fixups->smpt_map_id(nor, map_id); ++} ++ + /** + * spi_nor_get_map_in_use() - get the configuration map in use + * @nor: pointer to a 'struct spi_nor' +@@ -779,6 +789,8 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt, + map_id = map_id << 1 | !!(*buf & read_data_mask); + } + ++ spi_nor_smpt_map_id_fixups(nor, &map_id); ++ + /* + * If command descriptors are provided, they always precede map + * descriptors in the table. There is no need to start the iteration +-- +2.53.0 + diff --git a/queue-6.12/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch b/queue-6.12/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch new file mode 100644 index 0000000000..b3889de2ec --- /dev/null +++ b/queue-6.12/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch @@ -0,0 +1,92 @@ +From 9ce87237943d513b8bd96268fe8b3a27e60867ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 16:47:58 +0900 +Subject: mtd: spi-nor: sfdp: introduce smpt_read_dummy fixup hook + +From: Takahiro Kuwano + +[ Upstream commit 653f6def567c81f37302f9591ffd54df3e2a11eb ] + +SMPT contains config detection info that describes opcode, address, and +dummy cycles to read sector map config. The dummy cycles parameter can +be SMPT_CMD_READ_DUMMY_IS_VARIABLE and in that case nor->read_dummy +(initialized as 0) is used. In Infineon flash chips, Read Any Register +command with variable dummy cycle is defined in SMPT. S25Hx/S28Hx flash +has 0 dummy cycle by default to read volatile regiters and +nor->read_dummy can work. S25FS-S flash has 8 dummy cycles so we need a +hook that can fix dummy cycles with actually used value. + +Inroduce smpt_read_dummy() in struct spi_nor_fixups. It is called when +the dummy cycle field in SMPT config detection is 'varialble'. + +Reviewed-by: Tudor Ambarus +Tested-by: Marek Vasut # S25FS512S +Signed-off-by: Takahiro Kuwano +Signed-off-by: Pratyush Yadav +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 3 +++ + drivers/mtd/spi-nor/sfdp.c | 18 ++++++++++++++++-- + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 1516b6d0dc37a..56718f954a859 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -408,6 +408,8 @@ struct spi_nor_flash_parameter { + * flash parameters when information provided by the flash_info + * table is incomplete or wrong. + * @post_bfpt: called after the BFPT table has been parsed ++ * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the ++ * number of dummy cycles in read register ops. + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. +@@ -425,6 +427,7 @@ struct spi_nor_fixups { + int (*post_bfpt)(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); ++ void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); + int (*post_sfdp)(struct spi_nor *nor); + int (*late_init)(struct spi_nor *nor); + }; +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index 5b1117265bd28..86d869810d07a 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -695,6 +695,17 @@ static u8 spi_nor_smpt_addr_nbytes(const struct spi_nor *nor, const u32 settings + } + } + ++static void spi_nor_smpt_read_dummy_fixups(const struct spi_nor *nor, ++ u8 *read_dummy) ++{ ++ if (nor->manufacturer && nor->manufacturer->fixups && ++ nor->manufacturer->fixups->smpt_read_dummy) ++ nor->manufacturer->fixups->smpt_read_dummy(nor, read_dummy); ++ ++ if (nor->info->fixups && nor->info->fixups->smpt_read_dummy) ++ nor->info->fixups->smpt_read_dummy(nor, read_dummy); ++} ++ + /** + * spi_nor_smpt_read_dummy() - return the configuration detection command read + * latency, in clock cycles. +@@ -707,8 +718,11 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) + { + u8 read_dummy = SMPT_CMD_READ_DUMMY(settings); + +- if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) +- return nor->read_dummy; ++ if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) { ++ read_dummy = nor->read_dummy; ++ spi_nor_smpt_read_dummy_fixups(nor, &read_dummy); ++ } ++ + return read_dummy; + } + +-- +2.53.0 + diff --git a/queue-6.12/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch b/queue-6.12/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch new file mode 100644 index 0000000000..d5ea7f9ed9 --- /dev/null +++ b/queue-6.12/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch @@ -0,0 +1,41 @@ +From c9d3ddd1a6d7a8aac290b774edaec87d0f477b06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 20:42:56 +0800 +Subject: mtd: spi-nor: swp: check SR_TB flag when getting tb_mask + +From: Shiji Yang + +[ Upstream commit 94645aa41bf9ecb87c2ce78b1c3405bfb6074a37 ] + +When the chip does not support top/bottom block protect, the tb_mask +must be set to 0, otherwise SR1 bit5 will be unexpectedly modified. + +Signed-off-by: Shiji Yang +Fixes: 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support") +Reviewed-by: Michael Walle +Reviewed-by: Miquel Raynal +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/swp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c +index fdc411f2a23c5..7208be75d850f 100644 +--- a/drivers/mtd/spi-nor/swp.c ++++ b/drivers/mtd/spi-nor/swp.c +@@ -27,8 +27,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) + { + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + return SR_TB_BIT6; +- else ++ else if (nor->flags & SNOR_F_HAS_SR_TB) + return SR_TB_BIT5; ++ else ++ return 0; + } + + static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) +-- +2.53.0 + diff --git a/queue-6.12/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch b/queue-6.12/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch new file mode 100644 index 0000000000..e0f97db5e5 --- /dev/null +++ b/queue-6.12/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch @@ -0,0 +1,40 @@ +From 3bdfa32bf5efb037b42dfda8f4998bd97104443e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:54:30 +0100 +Subject: mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation + +From: Jonas Gorski + +[ Upstream commit 3620d67b48493c6252bbc873dc88dde81641d56b ] + +After commit 5273cc6df984 ("mtd: spi-nor: core: Call +spi_nor_post_sfdp_fixups() only when SFDP is defined") +spi_nor_post_sfdp_fixups() isn't called anymore if no SFDP is detected. + +Update the documentation accordingly. + +Fixes: 5273cc6df984 ("mtd: spi-nor: core: Call spi_nor_post_sfdp_fixups() only when SFDP is defined") +Signed-off-by: Jonas Gorski +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 3aeca2299ddb1..df07ded382605 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -412,7 +412,7 @@ struct spi_nor_flash_parameter { + * number of dummy cycles in read register ops. + * @smpt_map_id: called after map ID in SMPT table has been determined for the + * case the map ID is wrong and needs to be fixed. +- * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs ++ * @post_sfdp: called after SFDP has been parsed (is not called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. + * when information provided by the SFDP/flash_info tables are +-- +2.53.0 + diff --git a/queue-6.12/neigh-let-neigh_xmit-take-skb-ownership.patch b/queue-6.12/neigh-let-neigh_xmit-take-skb-ownership.patch new file mode 100644 index 0000000000..58d25e0fd6 --- /dev/null +++ b/queue-6.12/neigh-let-neigh_xmit-take-skb-ownership.patch @@ -0,0 +1,74 @@ +From 15a1f705be146e2f6f4becadcafa2e218811a70f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 16:58:38 +0200 +Subject: neigh: let neigh_xmit take skb ownership + +From: Florian Westphal + +[ Upstream commit 4438113be604ee67a7bf4f81da6e1cca41332ce4 ] + +neigh_xmit always releases the skb, except when no neighbour table is +found. But even the first added user of neigh_xmit (mpls) relied on +neigh_xmit to release the skb (or queue it for tx). + +sashiko reported: + If neigh_xmit() is called with an uninitialized neighbor table (for + example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT + and bypasses its internal out_kfree_skb error path. Because the return + value of neigh_xmit() is ignored here, does this leak the SKB? + +Assume full ownership and remove the last code path that doesn't +xmit or free skb. + +Fixes: 4fd3d7d9e868 ("neigh: Add helper function neigh_xmit") +Signed-off-by: Florian Westphal +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260424145843.74055-1-fw@strlen.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index 96786016dbb4e..bf07438d6dfa5 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -3161,8 +3161,10 @@ int neigh_xmit(int index, struct net_device *dev, + + rcu_read_lock(); + tbl = rcu_dereference(neigh_tables[index]); +- if (!tbl) +- goto out_unlock; ++ if (!tbl) { ++ rcu_read_unlock(); ++ goto out_kfree_skb; ++ } + if (index == NEIGH_ARP_TABLE) { + u32 key = *((u32 *)addr); + +@@ -3178,7 +3180,6 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + } + err = READ_ONCE(neigh->output)(neigh, skb); +-out_unlock: + rcu_read_unlock(); + } + else if (index == NEIGH_LINK_TABLE) { +@@ -3188,11 +3189,10 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + err = dev_queue_xmit(skb); + } +-out: + return err; + out_kfree_skb: + kfree_skb(skb); +- goto out; ++ return err; + } + EXPORT_SYMBOL(neigh_xmit); + +-- +2.53.0 + diff --git a/queue-6.12/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch b/queue-6.12/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch new file mode 100644 index 0000000000..0fdf6ab1f8 --- /dev/null +++ b/queue-6.12/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch @@ -0,0 +1,44 @@ +From f09ada83e8f5b8434c7888d22cbc11c0d0bd85a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 20:26:56 +0200 +Subject: net: airoha: Add missing RX_CPU_IDX() configuration in + airoha_qdma_cleanup_rx_queue() + +From: Lorenzo Bianconi + +[ Upstream commit 656121b155030086b01cfce9bd31b0c925ee6860 ] + +When the descriptor index written in REG_RX_CPU_IDX() is equal to the one +stored in REG_RX_DMA_IDX(), the hw will stop since the QDMA RX ring is +empty. +Add missing REG_RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue +routine during QDMA RX ring cleanup. + +Fixes: 514aac359987 ("net: airoha: Add missing cleanup bits in airoha_qdma_cleanup_rx_queue()") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260408-airoha-cpu-idx-airoha_qdma_cleanup_rx_queue-v1-1-8efa64844308@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/airoha_eth.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c +index 268d3050c0178..d8af267f64f71 100644 +--- a/drivers/net/ethernet/mediatek/airoha_eth.c ++++ b/drivers/net/ethernet/mediatek/airoha_eth.c +@@ -1641,6 +1641,11 @@ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q) + } + + q->head = q->tail; ++ /* Set RX_DMA_IDX to RX_CPU_IDX to notify the hw the QDMA RX ring is ++ * empty. ++ */ ++ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, ++ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head)); + airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, + FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail)); + } +-- +2.53.0 + diff --git a/queue-6.12/net-airoha-implement-bql-support.patch b/queue-6.12/net-airoha-implement-bql-support.patch new file mode 100644 index 0000000000..b92817ea31 --- /dev/null +++ b/queue-6.12/net-airoha-implement-bql-support.patch @@ -0,0 +1,53 @@ +From 6fda610779636b8c53f2342cb0f45f10f118a4cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 12 Oct 2024 11:01:11 +0200 +Subject: net: airoha: Implement BQL support + +From: Lorenzo Bianconi + +[ Upstream commit 1d304174106c93ce05f6088813ad7203b3eb381a ] + +Introduce BQL support in the airoha_eth driver reporting to the kernel +info about tx hw DMA queues in order to avoid bufferbloat and keep the +latency small. + +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20241012-en7581-bql-v2-1-4deb4efdb60b@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 656121b15503 ("net: airoha: Add missing RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/airoha_eth.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c +index 7a85550e5ecb3..268d3050c0178 100644 +--- a/drivers/net/ethernet/mediatek/airoha_eth.c ++++ b/drivers/net/ethernet/mediatek/airoha_eth.c +@@ -1729,9 +1729,11 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) + WRITE_ONCE(desc->msg1, 0); + + if (skb) { ++ u16 queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq; + +- txq = netdev_get_tx_queue(skb->dev, qid); ++ txq = netdev_get_tx_queue(skb->dev, queue); ++ netdev_tx_completed_queue(txq, 1, skb->len); + if (netif_tx_queue_stopped(txq) && + q->ndesc - q->queued >= q->free_thr) + netif_tx_wake_queue(txq); +@@ -2510,7 +2512,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + q->queued += i; + + skb_tx_timestamp(skb); +- if (!netdev_xmit_more()) ++ netdev_tx_sent_queue(txq, skb->len); ++ ++ if (netif_xmit_stopped(txq) || !netdev_xmit_more()) + airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), + TX_RING_CPU_IDX_MASK, + FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head)); +-- +2.53.0 + diff --git a/queue-6.12/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch b/queue-6.12/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch new file mode 100644 index 0000000000..a47f45d5de --- /dev/null +++ b/queue-6.12/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch @@ -0,0 +1,71 @@ +From e07df434ed8d9031e9adad22c360d8b303e8f12c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:07:47 +0200 +Subject: net: airoha: Move ndesc initialization at end of + airoha_qdma_init_rx_queue() + +From: Lorenzo Bianconi + +[ Upstream commit 379050947a1828826ad7ea50c95245a56929b35a ] + +If queue entry or DMA descriptor list allocation fails in +airoha_qdma_init_rx_queue routine, airoha_qdma_cleanup() will trigger a +NULL pointer dereference running netif_napi_del() for RX queue NAPIs +since netif_napi_add() has never been executed to this particular RX NAPI. +The issue is due to the early ndesc initialization in +airoha_qdma_init_rx_queue() since airoha_qdma_cleanup() relies on ndesc +value to check if the queue is properly initialized. Fix the issue moving +ndesc initialization at end of airoha_qdma_init_tx routine. +Move page_pool allocation after descriptor list allocation in order to +avoid memory leaks if desc allocation fails. + +Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260420-airoha_qdma_init_rx_queue-fix-v2-1-d99347e5c18d@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/airoha_eth.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c +index d8af267f64f71..7b929b20fe64b 100644 +--- a/drivers/net/ethernet/mediatek/airoha_eth.c ++++ b/drivers/net/ethernet/mediatek/airoha_eth.c +@@ -1574,14 +1574,18 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, + dma_addr_t dma_addr; + + q->buf_size = PAGE_SIZE / 2; +- q->ndesc = ndesc; + q->qdma = qdma; + +- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry), ++ q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry), + GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + ++ q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc), ++ &dma_addr, GFP_KERNEL); ++ if (!q->desc) ++ return -ENOMEM; ++ + q->page_pool = page_pool_create(&pp_params); + if (IS_ERR(q->page_pool)) { + int err = PTR_ERR(q->page_pool); +@@ -1590,11 +1594,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, + return err; + } + +- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc), +- &dma_addr, GFP_KERNEL); +- if (!q->desc) +- return -ENOMEM; +- ++ q->ndesc = ndesc; + netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll); + + airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr); +-- +2.53.0 + diff --git a/queue-6.12/net-bcmgenet-add-bcmgenet_has_-helpers.patch b/queue-6.12/net-bcmgenet-add-bcmgenet_has_-helpers.patch new file mode 100644 index 0000000000..0fe03a47e6 --- /dev/null +++ b/queue-6.12/net-bcmgenet-add-bcmgenet_has_-helpers.patch @@ -0,0 +1,192 @@ +From 33ccc933f3a61aa1802b9229746e8ed19a65665a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:30 -0800 +Subject: net: bcmgenet: add bcmgenet_has_* helpers + +From: Doug Berger + +[ Upstream commit 07c1a756a50b1180a085ab61819a388bbb906a95 ] + +Introduce helper functions to indicate whether the driver should +make use of a particular feature that it supports. These helpers +abstract the implementation of how the feature availability is +encoded. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-3-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 20 +++++++------- + .../net/ethernet/broadcom/genet/bcmgenet.h | 27 ++++++++++++++++++- + drivers/net/ethernet/broadcom/genet/bcmmii.c | 6 ++--- + 3 files changed, 39 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index ac9bd34f3b3ce..1767d96dd6546 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -104,7 +104,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, + * the platform is explicitly configured for 64-bits/LPAE. + */ + #ifdef CONFIG_PHYS_ADDR_T_64BIT +- if (priv->hw_params->flags & GENET_HAS_40BITS) ++ if (bcmgenet_has_40bits(priv)) + bcmgenet_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI); + #endif + } +@@ -1644,9 +1644,9 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv, + + case GENET_POWER_PASSIVE: + /* Power down LED */ +- if (priv->hw_params->flags & GENET_HAS_EXT) { ++ if (bcmgenet_has_ext(priv)) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); +- if (GENET_IS_V5(priv) && !priv->ephy_16nm) ++ if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) + reg |= EXT_PWR_DOWN_PHY_EN | + EXT_PWR_DOWN_PHY_RD | + EXT_PWR_DOWN_PHY_SD | +@@ -1674,7 +1674,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, + { + u32 reg; + +- if (!(priv->hw_params->flags & GENET_HAS_EXT)) ++ if (!bcmgenet_has_ext(priv)) + return; + + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); +@@ -1683,7 +1683,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, + case GENET_POWER_PASSIVE: + reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS | + EXT_ENERGY_DET_MASK); +- if (GENET_IS_V5(priv) && !priv->ephy_16nm) { ++ if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) { + reg &= ~(EXT_PWR_DOWN_PHY_EN | + EXT_PWR_DOWN_PHY_RD | + EXT_PWR_DOWN_PHY_SD | +@@ -2516,7 +2516,7 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv) + } else if (priv->ext_phy) { + int0_enable |= UMAC_IRQ_LINK_EVENT; + } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { +- if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) ++ if (bcmgenet_has_moca_link_det(priv)) + int0_enable |= UMAC_IRQ_LINK_EVENT; + } + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); +@@ -2581,7 +2581,7 @@ static void init_umac(struct bcmgenet_priv *priv) + } + + /* Enable MDIO interrupts on GENET v3+ */ +- if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) ++ if (bcmgenet_has_mdio_intr(priv)) + int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); + + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); +@@ -3221,7 +3221,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + } + } + +- if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && ++ if (bcmgenet_has_mdio_intr(priv) && + status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + wake_up(&priv->wq); + } +@@ -3891,7 +3891,7 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) + } + + #ifdef CONFIG_PHYS_ADDR_T_64BIT +- if (!(params->flags & GENET_HAS_40BITS)) ++ if (!bcmgenet_has_40bits(priv)) + pr_warn("GENET does not support 40-bits PA\n"); + #endif + +@@ -4070,7 +4070,7 @@ static int bcmgenet_probe(struct platform_device *pdev) + bcmgenet_set_hw_params(priv); + + err = -EIO; +- if (priv->hw_params->flags & GENET_HAS_40BITS) ++ if (bcmgenet_has_40bits(priv)) + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + if (err) + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index c0005a0fff567..ed7402fb7fdaa 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0-only */ + /* +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #ifndef __BCMGENET_H__ +@@ -648,6 +648,31 @@ struct bcmgenet_priv { + struct bcmgenet_mib_counters mib; + }; + ++static inline bool bcmgenet_has_40bits(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_40BITS); ++} ++ ++static inline bool bcmgenet_has_ext(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_EXT); ++} ++ ++static inline bool bcmgenet_has_mdio_intr(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_MDIO_INTR); ++} ++ ++static inline bool bcmgenet_has_moca_link_det(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET); ++} ++ ++static inline bool bcmgenet_has_ephy_16nm(struct bcmgenet_priv *priv) ++{ ++ return priv->ephy_16nm; ++} ++ + #define GENET_IO_MACRO(name, offset) \ + static inline u32 bcmgenet_##name##_readl(struct bcmgenet_priv *priv, \ + u32 off) \ +diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c +index 9beb65e6d0a96..eeb2aa75efdae 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c +@@ -2,7 +2,7 @@ + /* + * Broadcom GENET MDIO routines + * +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #include +@@ -151,7 +151,7 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable) + u32 reg = 0; + + /* EXT_GPHY_CTRL is only valid for GENETv4 and onward */ +- if (GENET_IS_V4(priv) || priv->ephy_16nm) { ++ if (GENET_IS_V4(priv) || bcmgenet_has_ephy_16nm(priv)) { + reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL); + if (enable) { + reg &= ~EXT_CK25_DIS; +@@ -181,7 +181,7 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable) + + static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) + { +- if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) ++ if (bcmgenet_has_moca_link_det(priv)) + fixed_phy_set_link_update(priv->dev->phydev, + bcmgenet_fixed_phy_link_update); + } +-- +2.53.0 + diff --git a/queue-6.12/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch b/queue-6.12/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch new file mode 100644 index 0000000000..30fae2497e --- /dev/null +++ b/queue-6.12/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch @@ -0,0 +1,50 @@ +From f2da5be34df85811a59df929afdfef1d0fc68b49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:54 -0700 +Subject: net: bcmgenet: fix off-by-one in bcmgenet_put_txcb + +From: Justin Chen + +[ Upstream commit 57f3f53d2c9c5a9e133596e2f7bc1c50688a6d38 ] + +The write_ptr points to the next open tx_cb. We want to return the +tx_cb that gets rewinded, so we must rewind the pointer first then +return the tx_cb that it points to. That way the txcb can be correctly +cleaned up. + +Fixes: 876dbadd53a7 ("net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()") +Signed-off-by: Justin Chen +Reviewed-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-2-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 49f6e83d60139..ac9bd34f3b3ce 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1740,15 +1740,15 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + { + struct enet_cb *tx_cb_ptr; + +- tx_cb_ptr = ring->cbs; +- tx_cb_ptr += ring->write_ptr - ring->cb_ptr; +- + /* Rewinding local write pointer */ + if (ring->write_ptr == ring->cb_ptr) + ring->write_ptr = ring->end_ptr; + else + ring->write_ptr--; + ++ tx_cb_ptr = ring->cbs; ++ tx_cb_ptr += ring->write_ptr - ring->cb_ptr; ++ + return tx_cb_ptr; + } + +-- +2.53.0 + diff --git a/queue-6.12/net-bcmgenet-fix-racing-timeout-handler.patch b/queue-6.12/net-bcmgenet-fix-racing-timeout-handler.patch new file mode 100644 index 0000000000..7f3119ab3d --- /dev/null +++ b/queue-6.12/net-bcmgenet-fix-racing-timeout-handler.patch @@ -0,0 +1,70 @@ +From 8f55b908f6332bf36b97328f9bd48135d628772d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:56 -0700 +Subject: net: bcmgenet: fix racing timeout handler + +From: Justin Chen + +[ Upstream commit 5393b2b5bee2ac51a0043dc7f4ac3475f053d08d ] + +The bcmgenet_timeout handler tries to take down all tx queues when +a single queue times out. This is over zealous and causes many race +conditions with queues that are still chugging along. Instead lets +only restart the timed out queue. + +Fixes: 13ea657806cf ("net: bcmgenet: improve TX timeout") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-4-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 22 ++++++++----------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 0fe11e98f738d..f012025a517dd 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -3465,27 +3465,23 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 int1_enable = 0; +- unsigned int q; ++ struct bcmgenet_tx_ring *ring = &priv->tx_rings[txqueue]; ++ struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue); + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- bcmgenet_dump_tx_queue(&priv->tx_rings[q]); +- +- bcmgenet_tx_reclaim_all(dev); ++ bcmgenet_dump_tx_queue(ring); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- int1_enable |= (1 << q); ++ bcmgenet_tx_reclaim(dev, ring, true); + +- /* Re-enable TX interrupts if disabled */ +- bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); ++ /* Re-enable the TX interrupt for this ring */ ++ bcmgenet_intrl2_1_writel(priv, 1 << txqueue, INTRL2_CPU_MASK_CLEAR); + +- netif_trans_update(dev); ++ txq_trans_cond_update(txq); + +- BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors); ++ BCMGENET_STATS64_INC((&ring->stats64), errors); + +- netif_tx_wake_all_queues(dev); ++ netif_tx_wake_queue(txq); + } + + #define MAX_MDF_FILTER 17 +-- +2.53.0 + diff --git a/queue-6.12/net-bcmgenet-move-desc_index-flow-to-ring-0.patch b/queue-6.12/net-bcmgenet-move-desc_index-flow-to-ring-0.patch new file mode 100644 index 0000000000..455bd7f91c --- /dev/null +++ b/queue-6.12/net-bcmgenet-move-desc_index-flow-to-ring-0.patch @@ -0,0 +1,947 @@ +From c2a886a80ff0d712c2727481ea7e86b50747cdd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:34 -0800 +Subject: net: bcmgenet: move DESC_INDEX flow to ring 0 + +From: Doug Berger + +[ Upstream commit 3b5d4f5a820d362dd46472542b2e961fb1f93515 ] + +The default transmit and receive packet handling is moved from +the DESC_INDEX (i.e. 16) descriptor rings to the Ring 0 queues. +This saves a fair amount of special case code by unifying the +handling. + +A default dummy filter is enabled in the Hardware Filter Block +to route default receive packets to Ring 0. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-7-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 369 +++++------------- + .../net/ethernet/broadcom/genet/bcmgenet.h | 12 +- + .../ethernet/broadcom/genet/bcmgenet_wol.c | 4 +- + 3 files changed, 110 insertions(+), 275 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 1767d96dd6546..8b73f1ed97a4c 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -41,15 +41,13 @@ + + #include "bcmgenet.h" + +-/* Maximum number of hardware queues, downsized if needed */ +-#define GENET_MAX_MQ_CNT 4 +- + /* Default highest priority queue for multi queue support */ +-#define GENET_Q0_PRIORITY 0 ++#define GENET_Q1_PRIORITY 0 ++#define GENET_Q0_PRIORITY 1 + +-#define GENET_Q16_RX_BD_CNT \ ++#define GENET_Q0_RX_BD_CNT \ + (TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q) +-#define GENET_Q16_TX_BD_CNT \ ++#define GENET_Q0_TX_BD_CNT \ + (TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->tx_bds_per_q) + + #define RX_BUF_LENGTH 2048 +@@ -585,7 +583,7 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, + u16 mask_16; + size_t size; + +- f = fs->location; ++ f = fs->location + 1; + if (fs->flow_type & FLOW_MAC_EXT) { + bcmgenet_hfb_insert_data(priv, f, 0, + &fs->h_ext.h_dest, &fs->m_ext.h_dest, +@@ -667,19 +665,14 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, + } + + bcmgenet_hfb_set_filter_length(priv, f, 2 * f_length); +- if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) { +- /* Ring 0 flows can be handled by the default Descriptor Ring +- * We'll map them to ring 0, but don't enable the filter +- */ ++ if (fs->ring_cookie == RX_CLS_FLOW_WAKE) + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, 0); +- rule->state = BCMGENET_RXNFC_STATE_DISABLED; +- } else { ++ else + /* Other Rx rings are direct mapped here */ + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, + fs->ring_cookie); +- bcmgenet_hfb_enable_filter(priv, f); +- rule->state = BCMGENET_RXNFC_STATE_ENABLED; +- } ++ bcmgenet_hfb_enable_filter(priv, f); ++ rule->state = BCMGENET_RXNFC_STATE_ENABLED; + } + + /* bcmgenet_hfb_clear +@@ -715,6 +708,10 @@ static void bcmgenet_hfb_clear(struct bcmgenet_priv *priv) + + for (i = 0; i < priv->hw_params->hfb_filter_cnt; i++) + bcmgenet_hfb_clear_filter(priv, i); ++ ++ /* Enable filter 0 to send default flow to ring 0 */ ++ bcmgenet_hfb_set_filter_length(priv, 0, 4); ++ bcmgenet_hfb_enable_filter(priv, 0); + } + + static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) +@@ -819,20 +816,16 @@ static int bcmgenet_get_coalesce(struct net_device *dev, + unsigned int i; + + ec->tx_max_coalesced_frames = +- bcmgenet_tdma_ring_readl(priv, DESC_INDEX, +- DMA_MBUF_DONE_THRESH); ++ bcmgenet_tdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); + ec->rx_max_coalesced_frames = +- bcmgenet_rdma_ring_readl(priv, DESC_INDEX, +- DMA_MBUF_DONE_THRESH); ++ bcmgenet_rdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); + ec->rx_coalesce_usecs = +- bcmgenet_rdma_readl(priv, DMA_RING16_TIMEOUT) * 8192 / 1000; ++ bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT) * 8192 / 1000; + +- for (i = 0; i < priv->hw_params->rx_queues; i++) { ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) { + ring = &priv->rx_rings[i]; + ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; + } +- ring = &priv->rx_rings[DESC_INDEX]; +- ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; + + return 0; + } +@@ -902,17 +895,13 @@ static int bcmgenet_set_coalesce(struct net_device *dev, + /* Program all TX queues with the same values, as there is no + * ethtool knob to do coalescing on a per-queue basis + */ +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + bcmgenet_tdma_ring_writel(priv, i, + ec->tx_max_coalesced_frames, + DMA_MBUF_DONE_THRESH); +- bcmgenet_tdma_ring_writel(priv, DESC_INDEX, +- ec->tx_max_coalesced_frames, +- DMA_MBUF_DONE_THRESH); + +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[i], ec); +- bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[DESC_INDEX], ec); + + return 0; + } +@@ -1120,7 +1109,7 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + STAT_GENET_Q(1), + STAT_GENET_Q(2), + STAT_GENET_Q(3), +- STAT_GENET_Q(16), ++ STAT_GENET_Q(4), + }; + + #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) +@@ -1465,10 +1454,10 @@ static int bcmgenet_insert_flow(struct net_device *dev, + loc_rule = &priv->rxnfc_rules[cmd->fs.location]; + } + if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) +- bcmgenet_hfb_disable_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); + if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { + list_del(&loc_rule->list); +- bcmgenet_hfb_clear_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); + } + loc_rule->state = BCMGENET_RXNFC_STATE_UNUSED; + memcpy(&loc_rule->fs, &cmd->fs, +@@ -1498,10 +1487,10 @@ static int bcmgenet_delete_flow(struct net_device *dev, + } + + if (rule->state == BCMGENET_RXNFC_STATE_ENABLED) +- bcmgenet_hfb_disable_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); + if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) { + list_del(&rule->list); +- bcmgenet_hfb_clear_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); + } + rule->state = BCMGENET_RXNFC_STATE_UNUSED; + memset(&rule->fs, 0, sizeof(struct ethtool_rx_flow_spec)); +@@ -1752,18 +1741,6 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + return tx_cb_ptr; + } + +-static inline void bcmgenet_rx_ring16_int_disable(struct bcmgenet_rx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_MASK_SET); +-} +- +-static inline void bcmgenet_rx_ring16_int_enable(struct bcmgenet_rx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_MASK_CLEAR); +-} +- + static inline void bcmgenet_rx_ring_int_disable(struct bcmgenet_rx_ring *ring) + { + bcmgenet_intrl2_1_writel(ring->priv, +@@ -1778,18 +1755,6 @@ static inline void bcmgenet_rx_ring_int_enable(struct bcmgenet_rx_ring *ring) + INTRL2_CPU_MASK_CLEAR); + } + +-static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_tx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_MASK_SET); +-} +- +-static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_tx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_MASK_CLEAR); +-} +- + static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_tx_ring *ring) + { + bcmgenet_intrl2_1_writel(ring->priv, 1 << ring->index, +@@ -1870,12 +1835,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + struct sk_buff *skb; + + /* Clear status before servicing to reduce spurious interrupts */ +- if (ring->index == DESC_INDEX) +- bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_CLEAR); +- else +- bcmgenet_intrl2_1_writel(priv, (1 << ring->index), +- INTRL2_CPU_CLEAR); ++ bcmgenet_intrl2_1_writel(priv, (1 << ring->index), INTRL2_CPU_CLEAR); + + /* Compute how many buffers are transmitted since last xmit call */ + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX) +@@ -1909,7 +1869,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + ring->packets += pkts_compl; + ring->bytes += bytes_compl; + +- netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->queue), ++ netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->index), + pkts_compl, bytes_compl); + + return txbds_processed; +@@ -1937,14 +1897,14 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) + spin_lock(&ring->lock); + work_done = __bcmgenet_tx_reclaim(ring->priv->dev, ring); + if (ring->free_bds > (MAX_SKB_FRAGS + 1)) { +- txq = netdev_get_tx_queue(ring->priv->dev, ring->queue); ++ txq = netdev_get_tx_queue(ring->priv->dev, ring->index); + netif_tx_wake_queue(txq); + } + spin_unlock(&ring->lock); + + if (work_done == 0) { + napi_complete(napi); +- ring->int_enable(ring); ++ bcmgenet_tx_ring_int_enable(ring); + + return 0; + } +@@ -1955,14 +1915,11 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) + static void bcmgenet_tx_reclaim_all(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- int i; +- +- if (netif_is_multiqueue(dev)) { +- for (i = 0; i < priv->hw_params->tx_queues; i++) +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[i]); +- } ++ int i = 0; + +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]); ++ do { ++ bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++]); ++ } while (i <= priv->hw_params->tx_queues && netif_is_multiqueue(dev)); + } + + /* Reallocate the SKB to put enough headroom in front of it and insert +@@ -2050,19 +2007,14 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) + + index = skb_get_queue_mapping(skb); + /* Mapping strategy: +- * queue_mapping = 0, unclassified, packet xmited through ring16 +- * queue_mapping = 1, goes to ring 0. (highest priority queue +- * queue_mapping = 2, goes to ring 1. +- * queue_mapping = 3, goes to ring 2. +- * queue_mapping = 4, goes to ring 3. ++ * queue_mapping = 0, unclassified, packet xmited through ring 0 ++ * queue_mapping = 1, goes to ring 1. (highest priority queue) ++ * queue_mapping = 2, goes to ring 2. ++ * queue_mapping = 3, goes to ring 3. ++ * queue_mapping = 4, goes to ring 4. + */ +- if (index == 0) +- index = DESC_INDEX; +- else +- index -= 1; +- + ring = &priv->tx_rings[index]; +- txq = netdev_get_tx_queue(dev, ring->queue); ++ txq = netdev_get_tx_queue(dev, index); + + nr_frags = skb_shinfo(skb)->nr_frags; + +@@ -2235,15 +2187,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + unsigned int discards; + + /* Clear status before servicing to reduce spurious interrupts */ +- if (ring->index == DESC_INDEX) { +- bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_CLEAR); +- } else { +- mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); +- bcmgenet_intrl2_1_writel(priv, +- mask, +- INTRL2_CPU_CLEAR); +- } ++ mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); ++ bcmgenet_intrl2_1_writel(priv, mask, INTRL2_CPU_CLEAR); + + p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX); + +@@ -2392,7 +2337,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) + + if (work_done < budget) { + napi_complete_done(napi, work_done); +- ring->int_enable(ring); ++ bcmgenet_rx_ring_int_enable(ring); + } + + if (ring->dim.use_dim) { +@@ -2632,15 +2577,6 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, + spin_lock_init(&ring->lock); + ring->priv = priv; + ring->index = index; +- if (index == DESC_INDEX) { +- ring->queue = 0; +- ring->int_enable = bcmgenet_tx_ring16_int_enable; +- ring->int_disable = bcmgenet_tx_ring16_int_disable; +- } else { +- ring->queue = index + 1; +- ring->int_enable = bcmgenet_tx_ring_int_enable; +- ring->int_disable = bcmgenet_tx_ring_int_disable; +- } + ring->cbs = priv->tx_cbs + start_ptr; + ring->size = size; + ring->clean_ptr = start_ptr; +@@ -2651,8 +2587,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, + ring->end_ptr = end_ptr - 1; + ring->prod_index = 0; + +- /* Set flow period for ring != 16 */ +- if (index != DESC_INDEX) ++ /* Set flow period for ring != 0 */ ++ if (index) + flow_period_val = ENET_MAX_MTU_SIZE << 16; + + bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); +@@ -2690,13 +2626,6 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, + + ring->priv = priv; + ring->index = index; +- if (index == DESC_INDEX) { +- ring->int_enable = bcmgenet_rx_ring16_int_enable; +- ring->int_disable = bcmgenet_rx_ring16_int_disable; +- } else { +- ring->int_enable = bcmgenet_rx_ring_int_enable; +- ring->int_disable = bcmgenet_rx_ring_int_disable; +- } + ring->cbs = priv->rx_cbs + start_ptr; + ring->size = size; + ring->c_index = 0; +@@ -2742,15 +2671,11 @@ static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + napi_enable(&ring->napi); +- ring->int_enable(ring); ++ bcmgenet_tx_ring_int_enable(ring); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- napi_enable(&ring->napi); +- ring->int_enable(ring); + } + + static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) +@@ -2758,13 +2683,10 @@ static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + napi_disable(&ring->napi); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- napi_disable(&ring->napi); + } + + static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) +@@ -2772,33 +2694,31 @@ static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + netif_napi_del(&ring->napi); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- netif_napi_del(&ring->napi); + } + + /* Initialize Tx queues + * +- * Queues 0-3 are priority-based, each one has 32 descriptors, +- * with queue 0 being the highest priority queue. ++ * Queues 1-4 are priority-based, each one has 32 descriptors, ++ * with queue 1 being the highest priority queue. + * +- * Queue 16 is the default Tx queue with +- * GENET_Q16_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. ++ * Queue 0 is the default Tx queue with ++ * GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. + * + * The transmit control block pool is then partitioned as follows: +- * - Tx queue 0 uses tx_cbs[0..31] +- * - Tx queue 1 uses tx_cbs[32..63] +- * - Tx queue 2 uses tx_cbs[64..95] +- * - Tx queue 3 uses tx_cbs[96..127] +- * - Tx queue 16 uses tx_cbs[128..255] ++ * - Tx queue 0 uses tx_cbs[0..127] ++ * - Tx queue 1 uses tx_cbs[128..159] ++ * - Tx queue 2 uses tx_cbs[160..191] ++ * - Tx queue 3 uses tx_cbs[192..223] ++ * - Tx queue 4 uses tx_cbs[224..255] + */ + static void bcmgenet_init_tx_queues(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); ++ unsigned int start = 0, end = GENET_Q0_TX_BD_CNT; + u32 i, dma_enable; + u32 dma_ctrl, ring_cfg; + u32 dma_priority[3] = {0, 0, 0}; +@@ -2815,27 +2735,17 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) + bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL); + + /* Initialize Tx priority queues */ +- for (i = 0; i < priv->hw_params->tx_queues; i++) { +- bcmgenet_init_tx_ring(priv, i, priv->hw_params->tx_bds_per_q, +- i * priv->hw_params->tx_bds_per_q, +- (i + 1) * priv->hw_params->tx_bds_per_q); ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) { ++ bcmgenet_init_tx_ring(priv, i, end - start, start, end); ++ start = end; ++ end += priv->hw_params->tx_bds_per_q; + ring_cfg |= (1 << i); + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + dma_priority[DMA_PRIO_REG_INDEX(i)] |= +- ((GENET_Q0_PRIORITY + i) << DMA_PRIO_REG_SHIFT(i)); ++ (i ? GENET_Q1_PRIORITY : GENET_Q0_PRIORITY) ++ << DMA_PRIO_REG_SHIFT(i); + } + +- /* Initialize Tx default queue 16 */ +- bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_Q16_TX_BD_CNT, +- priv->hw_params->tx_queues * +- priv->hw_params->tx_bds_per_q, +- TOTAL_DESC); +- ring_cfg |= (1 << DESC_INDEX); +- dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); +- dma_priority[DMA_PRIO_REG_INDEX(DESC_INDEX)] |= +- ((GENET_Q0_PRIORITY + priv->hw_params->tx_queues) << +- DMA_PRIO_REG_SHIFT(DESC_INDEX)); +- + /* Set Tx queue priorities */ + bcmgenet_tdma_writel(priv, dma_priority[0], DMA_PRIORITY_0); + bcmgenet_tdma_writel(priv, dma_priority[1], DMA_PRIORITY_1); +@@ -2855,15 +2765,11 @@ static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + napi_enable(&ring->napi); +- ring->int_enable(ring); ++ bcmgenet_rx_ring_int_enable(ring); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- napi_enable(&ring->napi); +- ring->int_enable(ring); + } + + static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) +@@ -2871,15 +2777,11 @@ static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + napi_disable(&ring->napi); + cancel_work_sync(&ring->dim.dim.work); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- napi_disable(&ring->napi); +- cancel_work_sync(&ring->dim.dim.work); + } + + static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) +@@ -2887,13 +2789,10 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + netif_napi_del(&ring->napi); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- netif_napi_del(&ring->napi); + } + + /* Initialize Rx queues +@@ -2901,15 +2800,13 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) + * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be + * used to direct traffic to these queues. + * +- * Queue 16 is the default Rx queue with GENET_Q16_RX_BD_CNT descriptors. ++ * Queue 0 is also the default Rx queue with GENET_Q0_RX_BD_CNT descriptors. + */ + static int bcmgenet_init_rx_queues(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 i; +- u32 dma_enable; +- u32 dma_ctrl; +- u32 ring_cfg; ++ unsigned int start = 0, end = GENET_Q0_RX_BD_CNT; ++ u32 i, dma_enable, dma_ctrl = 0, ring_cfg = 0; + int ret; + + dma_ctrl = bcmgenet_rdma_readl(priv, DMA_CTRL); +@@ -2921,34 +2818,21 @@ static int bcmgenet_init_rx_queues(struct net_device *dev) + ring_cfg = 0; + + /* Initialize Rx priority queues */ +- for (i = 0; i < priv->hw_params->rx_queues; i++) { +- ret = bcmgenet_init_rx_ring(priv, i, +- priv->hw_params->rx_bds_per_q, +- i * priv->hw_params->rx_bds_per_q, +- (i + 1) * +- priv->hw_params->rx_bds_per_q); ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) { ++ ret = bcmgenet_init_rx_ring(priv, i, end - start, start, end); + if (ret) + return ret; + ++ start = end; ++ end += priv->hw_params->rx_bds_per_q; + ring_cfg |= (1 << i); + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + } + +- /* Initialize Rx default queue 16 */ +- ret = bcmgenet_init_rx_ring(priv, DESC_INDEX, GENET_Q16_RX_BD_CNT, +- priv->hw_params->rx_queues * +- priv->hw_params->rx_bds_per_q, +- TOTAL_DESC); +- if (ret) +- return ret; +- +- ring_cfg |= (1 << DESC_INDEX); +- dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); +- +- /* Enable rings */ ++ /* Configure Rx queues as descriptor rings */ + bcmgenet_rdma_writel(priv, ring_cfg, DMA_RING_CFG); + +- /* Configure ring as descriptor ring and re-enable DMA if enabled */ ++ /* Enable Rx rings */ + if (dma_enable) + dma_ctrl |= DMA_EN; + bcmgenet_rdma_writel(priv, dma_ctrl, DMA_CTRL); +@@ -3007,14 +2891,14 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) + } + + dma_ctrl = 0; +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; + bcmgenet_rdma_writel(priv, reg, DMA_CTRL); + + dma_ctrl = 0; +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; +@@ -3035,14 +2919,11 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) + dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, + priv->tx_cbs + i)); + +- for (i = 0; i < priv->hw_params->tx_queues; i++) { +- txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[i].queue); ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) { ++ txq = netdev_get_tx_queue(priv->dev, i); + netdev_tx_reset_queue(txq); + } + +- txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[DESC_INDEX].queue); +- netdev_tx_reset_queue(txq); +- + bcmgenet_free_rx_buffers(priv); + kfree(priv->rx_cbs); + kfree(priv->tx_cbs); +@@ -3135,7 +3016,7 @@ static void bcmgenet_irq_task(struct work_struct *work) + + } + +-/* bcmgenet_isr1: handle Rx and Tx priority queues */ ++/* bcmgenet_isr1: handle Rx and Tx queues */ + static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + { + struct bcmgenet_priv *priv = dev_id; +@@ -3154,7 +3035,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + "%s: IRQ=0x%x\n", __func__, status); + + /* Check Rx priority queue interrupts */ +- for (index = 0; index < priv->hw_params->rx_queues; index++) { ++ for (index = 0; index <= priv->hw_params->rx_queues; index++) { + if (!(status & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index))) + continue; + +@@ -3162,20 +3043,20 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + rx_ring->dim.event_ctr++; + + if (likely(napi_schedule_prep(&rx_ring->napi))) { +- rx_ring->int_disable(rx_ring); ++ bcmgenet_rx_ring_int_disable(rx_ring); + __napi_schedule_irqoff(&rx_ring->napi); + } + } + + /* Check Tx priority queue interrupts */ +- for (index = 0; index < priv->hw_params->tx_queues; index++) { ++ for (index = 0; index <= priv->hw_params->tx_queues; index++) { + if (!(status & BIT(index))) + continue; + + tx_ring = &priv->tx_rings[index]; + + if (likely(napi_schedule_prep(&tx_ring->napi))) { +- tx_ring->int_disable(tx_ring); ++ bcmgenet_tx_ring_int_disable(tx_ring); + __napi_schedule_irqoff(&tx_ring->napi); + } + } +@@ -3183,12 +3064,10 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + return IRQ_HANDLED; + } + +-/* bcmgenet_isr0: handle Rx and Tx default queues + other stuff */ ++/* bcmgenet_isr0: handle other stuff */ + static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + { + struct bcmgenet_priv *priv = dev_id; +- struct bcmgenet_rx_ring *rx_ring; +- struct bcmgenet_tx_ring *tx_ring; + unsigned int status; + unsigned long flags; + +@@ -3202,25 +3081,6 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + netif_dbg(priv, intr, priv->dev, + "IRQ=0x%x\n", status); + +- if (status & UMAC_IRQ_RXDMA_DONE) { +- rx_ring = &priv->rx_rings[DESC_INDEX]; +- rx_ring->dim.event_ctr++; +- +- if (likely(napi_schedule_prep(&rx_ring->napi))) { +- rx_ring->int_disable(rx_ring); +- __napi_schedule_irqoff(&rx_ring->napi); +- } +- } +- +- if (status & UMAC_IRQ_TXDMA_DONE) { +- tx_ring = &priv->tx_rings[DESC_INDEX]; +- +- if (likely(napi_schedule_prep(&tx_ring->napi))) { +- tx_ring->int_disable(tx_ring); +- __napi_schedule_irqoff(&tx_ring->napi); +- } +- } +- + if (bcmgenet_has_mdio_intr(priv) && + status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + wake_up(&priv->wq); +@@ -3286,15 +3146,15 @@ static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv, bool flush_rx) + u32 dma_ctrl; + + /* disable DMA */ +- dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ dma_ctrl = DMA_EN; ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); + +- dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ dma_ctrl = DMA_EN; ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; +@@ -3377,6 +3237,9 @@ static int bcmgenet_open(struct net_device *dev) + + bcmgenet_set_hw_addr(priv, dev->dev_addr); + ++ /* HFB init */ ++ bcmgenet_hfb_init(priv); ++ + /* Disable RX/TX DMA and flush TX and RX queues */ + dma_ctrl = bcmgenet_dma_disable(priv, true); + +@@ -3387,12 +3250,8 @@ static int bcmgenet_open(struct net_device *dev) + goto err_clk_disable; + } + +- /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + +- /* HFB init */ +- bcmgenet_hfb_init(priv); +- + ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED, + dev->name, priv); + if (ret < 0) { +@@ -3499,16 +3358,11 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + if (!netif_msg_tx_err(priv)) + return; + +- txq = netdev_get_tx_queue(priv->dev, ring->queue); ++ txq = netdev_get_tx_queue(priv->dev, ring->index); + + spin_lock(&ring->lock); +- if (ring->index == DESC_INDEX) { +- intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); +- intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE; +- } else { +- intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); +- intmsk = 1 << ring->index; +- } ++ intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); ++ intmsk = 1 << ring->index; + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); + p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX); + txq_stopped = netif_tx_queue_stopped(txq); +@@ -3522,7 +3376,7 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + "(sw)c_index: %d (hw)c_index: %d\n" + "(sw)clean_p: %d (sw)write_p: %d\n" + "(sw)cb_ptr: %d (sw)end_ptr: %d\n", +- ring->index, ring->queue, ++ ring->index, ring->index, + txq_stopped ? "stopped" : "active", + intsts & intmsk ? "enabled" : "disabled", + free_bds, ring->size, +@@ -3535,25 +3389,20 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 int0_enable = 0; + u32 int1_enable = 0; + unsigned int q; + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + +- for (q = 0; q < priv->hw_params->tx_queues; q++) ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) + bcmgenet_dump_tx_queue(&priv->tx_rings[q]); +- bcmgenet_dump_tx_queue(&priv->tx_rings[DESC_INDEX]); + + bcmgenet_tx_reclaim_all(dev); + +- for (q = 0; q < priv->hw_params->tx_queues; q++) ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) + int1_enable |= (1 << q); + +- int0_enable = UMAC_IRQ_TXDMA_DONE; +- + /* Re-enable TX interrupts if disabled */ +- bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); + + netif_trans_update(dev); +@@ -3657,16 +3506,13 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) + struct bcmgenet_rx_ring *rx_ring; + unsigned int q; + +- for (q = 0; q < priv->hw_params->tx_queues; q++) { ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) { + tx_ring = &priv->tx_rings[q]; + tx_bytes += tx_ring->bytes; + tx_packets += tx_ring->packets; + } +- tx_ring = &priv->tx_rings[DESC_INDEX]; +- tx_bytes += tx_ring->bytes; +- tx_packets += tx_ring->packets; + +- for (q = 0; q < priv->hw_params->rx_queues; q++) { ++ for (q = 0; q <= priv->hw_params->rx_queues; q++) { + rx_ring = &priv->rx_rings[q]; + + rx_bytes += rx_ring->bytes; +@@ -3674,11 +3520,6 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) + rx_errors += rx_ring->errors; + rx_dropped += rx_ring->dropped; + } +- rx_ring = &priv->rx_rings[DESC_INDEX]; +- rx_bytes += rx_ring->bytes; +- rx_packets += rx_ring->packets; +- rx_errors += rx_ring->errors; +- rx_dropped += rx_ring->dropped; + + dev->stats.tx_bytes = tx_bytes; + dev->stats.tx_packets = tx_packets; +@@ -4125,16 +3966,13 @@ static int bcmgenet_probe(struct platform_device *pdev) + if (err) + goto err_clk_disable; + +- /* setup number of real queues + 1 (GENET_V1 has 0 hardware queues +- * just the ring 16 descriptor based TX +- */ ++ /* setup number of real queues + 1 */ + netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1); + netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); + + /* Set default coalescing parameters */ +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + priv->rx_rings[i].rx_max_coalesced_frames = 1; +- priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1; + + /* libphy will determine the link state */ + netif_carrier_off(dev); +@@ -4257,7 +4095,6 @@ static int bcmgenet_resume(struct device *d) + goto out_clk_disable; + } + +- /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + + if (!device_may_wakeup(d)) +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index ed7402fb7fdaa..371e01e2c1895 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -18,6 +18,9 @@ + + #include "../unimac.h" + ++/* Maximum number of hardware queues, downsized if needed */ ++#define GENET_MAX_MQ_CNT 4 ++ + /* total number of Buffer Descriptors, same for Rx/Tx */ + #define TOTAL_DESC 256 + +@@ -513,7 +516,6 @@ struct bcmgenet_tx_ring { + unsigned long packets; + unsigned long bytes; + unsigned int index; /* ring index */ +- unsigned int queue; /* queue index */ + struct enet_cb *cbs; /* tx ring buffer control block*/ + unsigned int size; /* size of each tx ring */ + unsigned int clean_ptr; /* Tx ring clean pointer */ +@@ -523,8 +525,6 @@ struct bcmgenet_tx_ring { + unsigned int prod_index; /* Tx ring producer index SW copy */ + unsigned int cb_ptr; /* Tx ring initial CB ptr */ + unsigned int end_ptr; /* Tx ring end CB ptr */ +- void (*int_enable)(struct bcmgenet_tx_ring *); +- void (*int_disable)(struct bcmgenet_tx_ring *); + struct bcmgenet_priv *priv; + }; + +@@ -553,8 +553,6 @@ struct bcmgenet_rx_ring { + struct bcmgenet_net_dim dim; + u32 rx_max_coalesced_frames; + u32 rx_coalesce_usecs; +- void (*int_enable)(struct bcmgenet_rx_ring *); +- void (*int_disable)(struct bcmgenet_rx_ring *); + struct bcmgenet_priv *priv; + }; + +@@ -583,7 +581,7 @@ struct bcmgenet_priv { + struct enet_cb *tx_cbs; + unsigned int num_tx_bds; + +- struct bcmgenet_tx_ring tx_rings[DESC_INDEX + 1]; ++ struct bcmgenet_tx_ring tx_rings[GENET_MAX_MQ_CNT + 1]; + + /* receive variables */ + void __iomem *rx_bds; +@@ -593,7 +591,7 @@ struct bcmgenet_priv { + struct bcmgenet_rxnfc_rule rxnfc_rules[MAX_NUM_OF_FS_RULES]; + struct list_head rxnfc_list; + +- struct bcmgenet_rx_ring rx_rings[DESC_INDEX + 1]; ++ struct bcmgenet_rx_ring rx_rings[GENET_MAX_MQ_CNT + 1]; + + /* other misc variables */ + struct bcmgenet_hw_params *hw_params; +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +index 2033fb9d893e0..98358b71cef5c 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +@@ -2,7 +2,7 @@ + /* + * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support + * +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #define pr_fmt(fmt) "bcmgenet_wol: " fmt +@@ -180,7 +180,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, + if (priv->wolopts & WAKE_FILTER) { + list_for_each_entry(rule, &priv->rxnfc_list, list) + if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE) +- hfb_enable |= (1 << rule->fs.location); ++ hfb_enable |= (1 << (rule->fs.location + 1)); + reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN; + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); + } +-- +2.53.0 + diff --git a/queue-6.12/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch b/queue-6.12/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch new file mode 100644 index 0000000000..44cd41dae7 --- /dev/null +++ b/queue-6.12/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch @@ -0,0 +1,92 @@ +From 42d0e9f2642c8d63f0d6519b3e72bc0bec87a287 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:39 -0800 +Subject: net: bcmgenet: support reclaiming unsent Tx packets + +From: Doug Berger + +[ Upstream commit f1bacae8b655163dcbc3c54b9e714ef1a8986d7b ] + +When disabling the transmitter any outstanding packets can now +be reclaimed by bcmgenet_tx_reclaim_all() rather than by the +bcmgenet_fini_dma() function. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-12-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 37 +++++++++++++++---- + 1 file changed, 30 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 8b73f1ed97a4c..35b613930238c 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1876,12 +1876,39 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + } + + static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, +- struct bcmgenet_tx_ring *ring) ++ struct bcmgenet_tx_ring *ring, ++ bool all) + { +- unsigned int released; ++ struct bcmgenet_priv *priv = netdev_priv(dev); ++ struct device *kdev = &priv->pdev->dev; ++ unsigned int released, drop, wr_ptr; ++ struct enet_cb *cb_ptr; ++ struct sk_buff *skb; + + spin_lock_bh(&ring->lock); + released = __bcmgenet_tx_reclaim(dev, ring); ++ if (all) { ++ skb = NULL; ++ drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK; ++ released += drop; ++ ring->prod_index = ring->c_index & DMA_C_INDEX_MASK; ++ while (drop--) { ++ cb_ptr = bcmgenet_put_txcb(priv, ring); ++ skb = cb_ptr->skb; ++ bcmgenet_free_tx_cb(kdev, cb_ptr); ++ if (skb && cb_ptr == GENET_CB(skb)->first_cb) { ++ dev_consume_skb_any(skb); ++ skb = NULL; ++ } ++ } ++ if (skb) ++ dev_consume_skb_any(skb); ++ bcmgenet_tdma_ring_writel(priv, ring->index, ++ ring->prod_index, TDMA_PROD_INDEX); ++ wr_ptr = ring->write_ptr * WORDS_PER_BD(priv); ++ bcmgenet_tdma_ring_writel(priv, ring->index, wr_ptr, ++ TDMA_WRITE_PTR); ++ } + spin_unlock_bh(&ring->lock); + + return released; +@@ -1918,7 +1945,7 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev) + int i = 0; + + do { +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++]); ++ bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++], true); + } while (i <= priv->hw_params->tx_queues && netif_is_multiqueue(dev)); + } + +@@ -2915,10 +2942,6 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) + bcmgenet_fini_rx_napi(priv); + bcmgenet_fini_tx_napi(priv); + +- for (i = 0; i < priv->num_tx_bds; i++) +- dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, +- priv->tx_cbs + i)); +- + for (i = 0; i <= priv->hw_params->tx_queues; i++) { + txq = netdev_get_tx_queue(priv->dev, i); + netdev_tx_reset_queue(txq); +-- +2.53.0 + diff --git a/queue-6.12/net-bcmgenet-switch-to-use-64bit-statistics.patch b/queue-6.12/net-bcmgenet-switch-to-use-64bit-statistics.patch new file mode 100644 index 0000000000..030515753f --- /dev/null +++ b/queue-6.12/net-bcmgenet-switch-to-use-64bit-statistics.patch @@ -0,0 +1,527 @@ +From c091c6934734f950cd6274dfaef9b4b0507ac24e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 May 2025 12:32:55 +0100 +Subject: net: bcmgenet: switch to use 64bit statistics + +From: Zak Kemble + +[ Upstream commit 59aa6e3072aa7e51e9040e8c342d0c0825c5f48f ] + +Update the driver to use ndo_get_stats64, rtnl_link_stats64 and +u64_stats_t counters for statistics. + +Signed-off-by: Zak Kemble +Tested-by: Florian Fainelli +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250519113257.1031-2-zakkemble@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 246 ++++++++++++------ + .../net/ethernet/broadcom/genet/bcmgenet.h | 29 ++- + 2 files changed, 187 insertions(+), 88 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 35b613930238c..0fe11e98f738d 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -950,12 +950,13 @@ static int bcmgenet_set_pauseparam(struct net_device *dev, + + /* standard ethtool support functions. */ + enum bcmgenet_stat_type { +- BCMGENET_STAT_NETDEV = -1, ++ BCMGENET_STAT_RTNL = -1, + BCMGENET_STAT_MIB_RX, + BCMGENET_STAT_MIB_TX, + BCMGENET_STAT_RUNT, + BCMGENET_STAT_MISC, + BCMGENET_STAT_SOFT, ++ BCMGENET_STAT_SOFT64, + }; + + struct bcmgenet_stats { +@@ -965,13 +966,15 @@ struct bcmgenet_stats { + enum bcmgenet_stat_type type; + /* reg offset from UMAC base for misc counters */ + u16 reg_offset; ++ /* sync for u64 stats counters */ ++ int syncp_offset; + }; + +-#define STAT_NETDEV(m) { \ ++#define STAT_RTNL(m) { \ + .stat_string = __stringify(m), \ +- .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \ +- .stat_offset = offsetof(struct net_device_stats, m), \ +- .type = BCMGENET_STAT_NETDEV, \ ++ .stat_sizeof = sizeof(((struct rtnl_link_stats64 *)0)->m), \ ++ .stat_offset = offsetof(struct rtnl_link_stats64, m), \ ++ .type = BCMGENET_STAT_RTNL, \ + } + + #define STAT_GENET_MIB(str, m, _type) { \ +@@ -981,6 +984,14 @@ struct bcmgenet_stats { + .type = _type, \ + } + ++#define STAT_GENET_SOFT_MIB64(str, s, m) { \ ++ .stat_string = str, \ ++ .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->s.m), \ ++ .stat_offset = offsetof(struct bcmgenet_priv, s.m), \ ++ .type = BCMGENET_STAT_SOFT64, \ ++ .syncp_offset = offsetof(struct bcmgenet_priv, s.syncp), \ ++} ++ + #define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX) + #define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX) + #define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT) +@@ -995,18 +1006,18 @@ struct bcmgenet_stats { + } + + #define STAT_GENET_Q(num) \ +- STAT_GENET_SOFT_MIB("txq" __stringify(num) "_packets", \ +- tx_rings[num].packets), \ +- STAT_GENET_SOFT_MIB("txq" __stringify(num) "_bytes", \ +- tx_rings[num].bytes), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_bytes", \ +- rx_rings[num].bytes), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_packets", \ +- rx_rings[num].packets), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_errors", \ +- rx_rings[num].errors), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_dropped", \ +- rx_rings[num].dropped) ++ STAT_GENET_SOFT_MIB64("txq" __stringify(num) "_packets", \ ++ tx_rings[num].stats64, packets), \ ++ STAT_GENET_SOFT_MIB64("txq" __stringify(num) "_bytes", \ ++ tx_rings[num].stats64, bytes), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_bytes", \ ++ rx_rings[num].stats64, bytes), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_packets", \ ++ rx_rings[num].stats64, packets), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_errors", \ ++ rx_rings[num].stats64, errors), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_dropped", \ ++ rx_rings[num].stats64, dropped) + + /* There is a 0xC gap between the end of RX and beginning of TX stats and then + * between the end of TX stats and the beginning of the RX RUNT +@@ -1018,15 +1029,15 @@ struct bcmgenet_stats { + */ + static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + /* general stats */ +- STAT_NETDEV(rx_packets), +- STAT_NETDEV(tx_packets), +- STAT_NETDEV(rx_bytes), +- STAT_NETDEV(tx_bytes), +- STAT_NETDEV(rx_errors), +- STAT_NETDEV(tx_errors), +- STAT_NETDEV(rx_dropped), +- STAT_NETDEV(tx_dropped), +- STAT_NETDEV(multicast), ++ STAT_RTNL(rx_packets), ++ STAT_RTNL(tx_packets), ++ STAT_RTNL(rx_bytes), ++ STAT_RTNL(tx_bytes), ++ STAT_RTNL(rx_errors), ++ STAT_RTNL(tx_errors), ++ STAT_RTNL(rx_dropped), ++ STAT_RTNL(tx_dropped), ++ STAT_RTNL(multicast), + /* UniMAC RSV counters */ + STAT_GENET_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64), + STAT_GENET_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127), +@@ -1114,6 +1125,20 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + + #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) + ++#define BCMGENET_STATS64_ADD(stats, m, v) \ ++ do { \ ++ u64_stats_update_begin(&stats->syncp); \ ++ u64_stats_add(&stats->m, v); \ ++ u64_stats_update_end(&stats->syncp); \ ++ } while (0) ++ ++#define BCMGENET_STATS64_INC(stats, m) \ ++ do { \ ++ u64_stats_update_begin(&stats->syncp); \ ++ u64_stats_inc(&stats->m); \ ++ u64_stats_update_end(&stats->syncp); \ ++ } while (0) ++ + static void bcmgenet_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) + { +@@ -1197,8 +1222,9 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) + + s = &bcmgenet_gstrings_stats[i]; + switch (s->type) { +- case BCMGENET_STAT_NETDEV: ++ case BCMGENET_STAT_RTNL: + case BCMGENET_STAT_SOFT: ++ case BCMGENET_STAT_SOFT64: + continue; + case BCMGENET_STAT_RUNT: + offset += BCMGENET_STAT_OFFSET; +@@ -1236,28 +1262,40 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev, + u64 *data) + { + struct bcmgenet_priv *priv = netdev_priv(dev); ++ struct rtnl_link_stats64 stats64; ++ struct u64_stats_sync *syncp; ++ unsigned int start; + int i; + + if (netif_running(dev)) + bcmgenet_update_mib_counters(priv); + +- dev->netdev_ops->ndo_get_stats(dev); ++ dev_get_stats(dev, &stats64); + + for (i = 0; i < BCMGENET_STATS_LEN; i++) { + const struct bcmgenet_stats *s; + char *p; + + s = &bcmgenet_gstrings_stats[i]; +- if (s->type == BCMGENET_STAT_NETDEV) +- p = (char *)&dev->stats; +- else +- p = (char *)priv; +- p += s->stat_offset; +- if (sizeof(unsigned long) != sizeof(u32) && +- s->stat_sizeof == sizeof(unsigned long)) +- data[i] = *(unsigned long *)p; +- else +- data[i] = *(u32 *)p; ++ p = (char *)priv; ++ ++ if (s->type == BCMGENET_STAT_SOFT64) { ++ syncp = (struct u64_stats_sync *)(p + s->syncp_offset); ++ do { ++ start = u64_stats_fetch_begin(syncp); ++ data[i] = u64_stats_read((u64_stats_t *)(p + s->stat_offset)); ++ } while (u64_stats_fetch_retry(syncp, start)); ++ } else { ++ if (s->type == BCMGENET_STAT_RTNL) ++ p = (char *)&stats64; ++ ++ p += s->stat_offset; ++ if (sizeof(unsigned long) != sizeof(u32) && ++ s->stat_sizeof == sizeof(unsigned long)) ++ data[i] = *(unsigned long *)p; ++ else ++ data[i] = *(u32 *)p; ++ } + } + } + +@@ -1826,6 +1864,7 @@ static struct sk_buff *bcmgenet_free_rx_cb(struct device *dev, + static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + struct bcmgenet_tx_ring *ring) + { ++ struct bcmgenet_tx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned int txbds_processed = 0; + unsigned int bytes_compl = 0; +@@ -1866,8 +1905,10 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + ring->free_bds += txbds_processed; + ring->c_index = c_index; + +- ring->packets += pkts_compl; +- ring->bytes += bytes_compl; ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_add(&stats->packets, pkts_compl); ++ u64_stats_add(&stats->bytes, bytes_compl); ++ u64_stats_update_end(&stats->syncp); + + netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->index), + pkts_compl, bytes_compl); +@@ -1953,8 +1994,10 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev) + * the transmit checksum offsets in the descriptors + */ + static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, +- struct sk_buff *skb) ++ struct sk_buff *skb, ++ struct bcmgenet_tx_ring *ring) + { ++ struct bcmgenet_tx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = netdev_priv(dev); + struct status_64 *status = NULL; + struct sk_buff *new_skb; +@@ -1971,7 +2014,7 @@ static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, + if (!new_skb) { + dev_kfree_skb_any(skb); + priv->mib.tx_realloc_tsb_failed++; +- dev->stats.tx_dropped++; ++ BCMGENET_STATS64_INC(stats, dropped); + return NULL; + } + dev_consume_skb_any(skb); +@@ -2059,7 +2102,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) + GENET_CB(skb)->bytes_sent = skb->len; + + /* add the Transmit Status Block */ +- skb = bcmgenet_add_tsb(dev, skb); ++ skb = bcmgenet_add_tsb(dev, skb, ring); + if (!skb) { + ret = NETDEV_TX_OK; + goto out; +@@ -2201,6 +2244,7 @@ static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv, + static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + unsigned int budget) + { ++ struct bcmgenet_rx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = ring->priv; + struct net_device *dev = priv->dev; + struct enet_cb *cb; +@@ -2223,7 +2267,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + DMA_P_INDEX_DISCARD_CNT_MASK; + if (discards > ring->old_discards) { + discards = discards - ring->old_discards; +- ring->errors += discards; ++ BCMGENET_STATS64_ADD(stats, errors, discards); + ring->old_discards += discards; + + /* Clear HW register when we reach 75% of maximum 0xFFFF */ +@@ -2249,7 +2293,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + skb = bcmgenet_rx_refill(priv, cb); + + if (unlikely(!skb)) { +- ring->dropped++; ++ BCMGENET_STATS64_INC(stats, dropped); + goto next; + } + +@@ -2276,8 +2320,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + + if (unlikely(len > RX_BUF_LENGTH)) { + netif_err(priv, rx_status, dev, "oversized packet\n"); +- dev->stats.rx_length_errors++; +- dev->stats.rx_errors++; ++ BCMGENET_STATS64_INC(stats, length_errors); + dev_kfree_skb_any(skb); + goto next; + } +@@ -2285,7 +2328,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { + netif_err(priv, rx_status, dev, + "dropping fragmented packet!\n"); +- ring->errors++; ++ BCMGENET_STATS64_INC(stats, errors); + dev_kfree_skb_any(skb); + goto next; + } +@@ -2298,15 +2341,22 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + DMA_RX_RXER))) { + netif_err(priv, rx_status, dev, "dma_flag=0x%x\n", + (unsigned int)dma_flag); ++ u64_stats_update_begin(&stats->syncp); + if (dma_flag & DMA_RX_CRC_ERROR) +- dev->stats.rx_crc_errors++; ++ u64_stats_inc(&stats->crc_errors); + if (dma_flag & DMA_RX_OV) +- dev->stats.rx_over_errors++; ++ u64_stats_inc(&stats->over_errors); + if (dma_flag & DMA_RX_NO) +- dev->stats.rx_frame_errors++; ++ u64_stats_inc(&stats->frame_errors); + if (dma_flag & DMA_RX_LG) +- dev->stats.rx_length_errors++; +- dev->stats.rx_errors++; ++ u64_stats_inc(&stats->length_errors); ++ if ((dma_flag & (DMA_RX_CRC_ERROR | ++ DMA_RX_OV | ++ DMA_RX_NO | ++ DMA_RX_LG | ++ DMA_RX_RXER)) == DMA_RX_RXER) ++ u64_stats_inc(&stats->errors); ++ u64_stats_update_end(&stats->syncp); + dev_kfree_skb_any(skb); + goto next; + } /* error packet */ +@@ -2326,10 +2376,13 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + + /*Finish setting up the received SKB and send it to the kernel*/ + skb->protocol = eth_type_trans(skb, priv->dev); +- ring->packets++; +- ring->bytes += len; ++ ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->packets); ++ u64_stats_add(&stats->bytes, len); + if (dma_flag & DMA_RX_MULT) +- dev->stats.multicast++; ++ u64_stats_inc(&stats->multicast); ++ u64_stats_update_end(&stats->syncp); + + /* Notify kernel */ + napi_gro_receive(&ring->napi, skb); +@@ -3430,7 +3483,7 @@ static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + + netif_trans_update(dev); + +- dev->stats.tx_errors++; ++ BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors); + + netif_tx_wake_all_queues(dev); + } +@@ -3519,39 +3572,68 @@ static int bcmgenet_set_mac_addr(struct net_device *dev, void *p) + return 0; + } + +-static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) ++static void bcmgenet_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- unsigned long tx_bytes = 0, tx_packets = 0; +- unsigned long rx_bytes = 0, rx_packets = 0; +- unsigned long rx_errors = 0, rx_dropped = 0; +- struct bcmgenet_tx_ring *tx_ring; +- struct bcmgenet_rx_ring *rx_ring; ++ struct bcmgenet_tx_stats64 *tx_stats; ++ struct bcmgenet_rx_stats64 *rx_stats; ++ u64 rx_length_errors, rx_over_errors; ++ u64 rx_crc_errors, rx_frame_errors; ++ u64 tx_errors, tx_dropped; ++ u64 rx_errors, rx_dropped; ++ u64 tx_bytes, tx_packets; ++ u64 rx_bytes, rx_packets; ++ unsigned int start; + unsigned int q; ++ u64 multicast; + + for (q = 0; q <= priv->hw_params->tx_queues; q++) { +- tx_ring = &priv->tx_rings[q]; +- tx_bytes += tx_ring->bytes; +- tx_packets += tx_ring->packets; ++ tx_stats = &priv->tx_rings[q].stats64; ++ do { ++ start = u64_stats_fetch_begin(&tx_stats->syncp); ++ tx_bytes = u64_stats_read(&tx_stats->bytes); ++ tx_packets = u64_stats_read(&tx_stats->packets); ++ tx_errors = u64_stats_read(&tx_stats->errors); ++ tx_dropped = u64_stats_read(&tx_stats->dropped); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); ++ ++ stats->tx_bytes += tx_bytes; ++ stats->tx_packets += tx_packets; ++ stats->tx_errors += tx_errors; ++ stats->tx_dropped += tx_dropped; + } + + for (q = 0; q <= priv->hw_params->rx_queues; q++) { +- rx_ring = &priv->rx_rings[q]; +- +- rx_bytes += rx_ring->bytes; +- rx_packets += rx_ring->packets; +- rx_errors += rx_ring->errors; +- rx_dropped += rx_ring->dropped; ++ rx_stats = &priv->rx_rings[q].stats64; ++ do { ++ start = u64_stats_fetch_begin(&rx_stats->syncp); ++ rx_bytes = u64_stats_read(&rx_stats->bytes); ++ rx_packets = u64_stats_read(&rx_stats->packets); ++ rx_errors = u64_stats_read(&rx_stats->errors); ++ rx_dropped = u64_stats_read(&rx_stats->dropped); ++ rx_length_errors = u64_stats_read(&rx_stats->length_errors); ++ rx_over_errors = u64_stats_read(&rx_stats->over_errors); ++ rx_crc_errors = u64_stats_read(&rx_stats->crc_errors); ++ rx_frame_errors = u64_stats_read(&rx_stats->frame_errors); ++ multicast = u64_stats_read(&rx_stats->multicast); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); ++ ++ rx_errors += rx_length_errors; ++ rx_errors += rx_crc_errors; ++ rx_errors += rx_frame_errors; ++ ++ stats->rx_bytes += rx_bytes; ++ stats->rx_packets += rx_packets; ++ stats->rx_errors += rx_errors; ++ stats->rx_dropped += rx_dropped; ++ stats->rx_missed_errors += rx_errors; ++ stats->rx_length_errors += rx_length_errors; ++ stats->rx_over_errors += rx_over_errors; ++ stats->rx_crc_errors += rx_crc_errors; ++ stats->rx_frame_errors += rx_frame_errors; ++ stats->multicast += multicast; + } +- +- dev->stats.tx_bytes = tx_bytes; +- dev->stats.tx_packets = tx_packets; +- dev->stats.rx_bytes = rx_bytes; +- dev->stats.rx_packets = rx_packets; +- dev->stats.rx_errors = rx_errors; +- dev->stats.rx_missed_errors = rx_errors; +- dev->stats.rx_dropped = rx_dropped; +- return &dev->stats; + } + + static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier) +@@ -3579,7 +3661,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = { + .ndo_set_mac_address = bcmgenet_set_mac_addr, + .ndo_eth_ioctl = phy_do_ioctl_running, + .ndo_set_features = bcmgenet_set_features, +- .ndo_get_stats = bcmgenet_get_stats, ++ .ndo_get_stats64 = bcmgenet_get_stats64, + .ndo_change_carrier = bcmgenet_change_carrier, + }; + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index 371e01e2c1895..89b071da31142 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -155,6 +155,27 @@ struct bcmgenet_mib_counters { + u32 tx_realloc_tsb_failed; + }; + ++struct bcmgenet_tx_stats64 { ++ struct u64_stats_sync syncp; ++ u64_stats_t packets; ++ u64_stats_t bytes; ++ u64_stats_t errors; ++ u64_stats_t dropped; ++}; ++ ++struct bcmgenet_rx_stats64 { ++ struct u64_stats_sync syncp; ++ u64_stats_t bytes; ++ u64_stats_t packets; ++ u64_stats_t errors; ++ u64_stats_t dropped; ++ u64_stats_t multicast; ++ u64_stats_t length_errors; ++ u64_stats_t over_errors; ++ u64_stats_t crc_errors; ++ u64_stats_t frame_errors; ++}; ++ + #define UMAC_MIB_START 0x400 + + #define UMAC_MDIO_CMD 0x614 +@@ -513,8 +534,7 @@ struct bcmgenet_skb_cb { + struct bcmgenet_tx_ring { + spinlock_t lock; /* ring lock */ + struct napi_struct napi; /* NAPI per tx queue */ +- unsigned long packets; +- unsigned long bytes; ++ struct bcmgenet_tx_stats64 stats64; + unsigned int index; /* ring index */ + struct enet_cb *cbs; /* tx ring buffer control block*/ + unsigned int size; /* size of each tx ring */ +@@ -538,10 +558,7 @@ struct bcmgenet_net_dim { + + struct bcmgenet_rx_ring { + struct napi_struct napi; /* Rx NAPI struct */ +- unsigned long bytes; +- unsigned long packets; +- unsigned long errors; +- unsigned long dropped; ++ struct bcmgenet_rx_stats64 stats64; + unsigned int index; /* Rx ring index */ + struct enet_cb *cbs; /* Rx ring buffer control block */ + unsigned int size; /* Rx ring size */ +-- +2.53.0 + diff --git a/queue-6.12/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch b/queue-6.12/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch new file mode 100644 index 0000000000..fb622e2cb4 --- /dev/null +++ b/queue-6.12/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch @@ -0,0 +1,66 @@ +From 93f7e372d0181d02718a80cb3307015e9b78cf3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 08:55:19 +0800 +Subject: net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master + +From: Jiayuan Chen + +[ Upstream commit 1921f91298d1388a0bb9db8f83800c998b649cb3 ] + +syzkaller reported a kernel panic in bond_rr_gen_slave_id() reached via +xdp_master_redirect(). Full decoded trace: + + https://syzkaller.appspot.com/bug?extid=80e046b8da2820b6ba73 + +bond_rr_gen_slave_id() dereferences bond->rr_tx_counter, a per-CPU +counter that bonding only allocates in bond_open() when the mode is +round-robin. If the bond device was never brought up, rr_tx_counter +stays NULL. + +The XDP redirect path can still reach that code on a bond that was +never opened: bpf_master_redirect_enabled_key is a global static key, +so as soon as any bond device has native XDP attached, the +XDP_TX -> xdp_master_redirect() interception is enabled for every +slave system-wide. The path xdp_master_redirect() -> +bond_xdp_get_xmit_slave() -> bond_xdp_xmit_roundrobin_slave_get() -> +bond_rr_gen_slave_id() then runs against a bond that has no +rr_tx_counter and crashes. + +Fix this in the generic xdp_master_redirect() by refusing to call into +the master's ->ndo_xdp_get_xmit_slave() when the master device is not +up. IFF_UP is only set after ->ndo_open() has successfully returned, +so this reliably excludes masters whose XDP state has not been fully +initialized. Drop the frame with XDP_ABORTED so the exception is +visible via trace_xdp_exception() rather than silently falling through. +This is not specific to bonding: any current or future master that +defers XDP state allocation to ->ndo_open() is protected. + +Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave device") +Reported-by: syzbot+80e046b8da2820b6ba73@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/698f84c6.a70a0220.2c38d7.00cc.GAE@google.com/T/ +Suggested-by: Daniel Borkmann +Acked-by: Daniel Borkmann +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260411005524.201200-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 1f96c3aa01cad..795e558155c6d 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4388,6 +4388,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) + struct net_device *master, *slave; + + master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); ++ if (unlikely(!(master->flags & IFF_UP))) ++ return XDP_ABORTED; + slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); + if (slave && slave != xdp->rxq->dev) { + /* The target device is different from the receiving device, so +-- +2.53.0 + diff --git a/queue-6.12/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch b/queue-6.12/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch new file mode 100644 index 0000000000..e4ade1551a --- /dev/null +++ b/queue-6.12/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch @@ -0,0 +1,44 @@ +From 63e2141200b5e7cae159414c0bc189e19cb4cf88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:37:07 +0200 +Subject: net: dsa: realtek: rtl8365mb: fix mode mask calculation + +From: Mieczyslaw Nalewaj + +[ Upstream commit 0c078021d3861966614d5e594ee03587f0c9e74d ] + +The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting +the 4-bit mask (0xF) by only (_extint % 2) bits instead of +(_extint % 2) * 4. This caused the mask to overlap with the adjacent +nibble when configuring odd-numbered external interfaces, selecting +the wrong bits entirely. + +Align the shift calculation with the existing ...MODE_OFFSET macro. + +Fixes: 4af2950c50c8 ("net: dsa: realtek-smi: add rtl8365mb subdriver for RTL8365MB-VC") +Signed-off-by: Abdulkader Alrezej +Signed-off-by: Mieczyslaw Nalewaj +Reviewed-by: Luiz Angelo Daros de Luca +Link: https://patch.msgid.link/400a6387-a444-4576-af6d-26be5410bce3@yahoo.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/realtek/rtl8365mb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index 4cb986988f1ad..9621fa4052f84 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -216,7 +216,7 @@ + (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ + 0x0) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \ +- (0xF << (((_extint) % 2))) ++ (0xF << (((_extint) % 2) * 4)) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \ + (((_extint) % 2) * 4) + +-- +2.53.0 + diff --git a/queue-6.12/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch b/queue-6.12/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch new file mode 100644 index 0000000000..0ff046c551 --- /dev/null +++ b/queue-6.12/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch @@ -0,0 +1,71 @@ +From af14dd83e571bd27ee5c1122fdb10b52c901b394 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:31:01 +0800 +Subject: net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf + +From: Mashiro Chen + +[ Upstream commit bf9a38803b2626b01cc769aaf13485d8650f576f ] + +sixpack_receive_buf() does not properly skip bytes with TTY error flags. +The while loop iterates through the flags buffer but never advances the +data pointer (cp), and passes the original count (including error bytes) +to sixpack_decode(). This causes sixpack_decode() to process bytes that +should have been skipped due to TTY errors. The TTY layer does not +guarantee that cp[i] holds a meaningful value when fp[i] is set, so +passing those positions to sixpack_decode() results in KMSAN reporting +an uninit-value read. + +Fix this by processing bytes one at a time, advancing cp on each +iteration, and only passing valid (non-error) bytes to sixpack_decode(). +This matches the pattern used by slip_receive_buf() and +mkiss_receive_buf() for the same purpose. + +Reported-by: syzbot+ecdb8c9878a81eb21e54@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ecdb8c9878a81eb21e54 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Mashiro Chen +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260407173101.107352-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 0c766c9c31955..437e5e391a770 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -391,7 +391,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + const u8 *fp, size_t count) + { + struct sixpack *sp; +- size_t count1; + + if (!count) + return; +@@ -401,16 +400,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + return; + + /* Read the characters out of the buffer */ +- count1 = count; +- while (count) { +- count--; ++ while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) + sp->dev->stats.rx_errors++; ++ cp++; + continue; + } ++ sixpack_decode(sp, cp, 1); ++ cp++; + } +- sixpack_decode(sp, cp, count1); + + tty_unthrottle(tty); + } +-- +2.53.0 + diff --git a/queue-6.12/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch b/queue-6.12/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch new file mode 100644 index 0000000000..9a9a77b384 --- /dev/null +++ b/queue-6.12/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch @@ -0,0 +1,42 @@ +From 2dcebccfb945f328df6949ce54c8d21b609f5d0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:13:32 +0200 +Subject: net: ipa: Fix decoding EV_PER_EE for IPA v5.0+ + +From: Luca Weiss + +[ Upstream commit 1335b903cf2e8aeaca87fd665683384c731ec941 ] + +Initially 'reg' and 'val' are assigned from HW_PARAM_2. + +But since IPA v5.0+ takes EV_PER_EE from HW_PARAM_4 (instead of +NUM_EV_PER_EE from HW_PARAM_2), we not only need to re-assign 'reg' but +also read the register value of that register into 'val' so that +reg_decode() works on the correct value. + +Fixes: f651334e1ef5 ("net: ipa: add HW_PARAM_4 GSI register") +Link: https://sashiko.dev/#/patchset/20260403-milos-ipa-v1-0-01e9e4e03d3e%40fairphone.com?part=2 +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260409-ipa-fixes-v1-2-a817c30678ac@fairphone.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ipa/gsi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c +index 4c3227e77898c..624649484d627 100644 +--- a/drivers/net/ipa/gsi.c ++++ b/drivers/net/ipa/gsi.c +@@ -2044,6 +2044,7 @@ static int gsi_ring_setup(struct gsi *gsi) + count = reg_decode(reg, NUM_EV_PER_EE, val); + } else { + reg = gsi_reg(gsi, HW_PARAM_4); ++ val = ioread32(gsi->virt + reg_offset(reg)); + count = reg_decode(reg, EV_PER_EE, val); + } + if (!count) { +-- +2.53.0 + diff --git a/queue-6.12/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch b/queue-6.12/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch new file mode 100644 index 0000000000..51bfe4f37d --- /dev/null +++ b/queue-6.12/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch @@ -0,0 +1,51 @@ +From 5a65fd15cd2640e7e8641e9fe718febb95387df1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:13:31 +0200 +Subject: net: ipa: Fix programming of QTIME_TIMESTAMP_CFG + +From: Luca Weiss + +[ Upstream commit de08f9585692813bd41ee654fca0487664c4de30 ] + +The 'val' variable gets overwritten multiple times, discarding previous +values. Looking at the git log shows these should be combined with |= +instead. + +Fixes: 9265a4f0f0b4 ("net: ipa: define even more IPA register fields") +Link: https://sashiko.dev/#/patchset/20260403-milos-ipa-v1-0-01e9e4e03d3e%40fairphone.com?part=4 +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260409-ipa-fixes-v1-1-a817c30678ac@fairphone.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ipa/ipa_main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c +index 5f3dd5a2dcf46..f374a590d1c5e 100644 +--- a/drivers/net/ipa/ipa_main.c ++++ b/drivers/net/ipa/ipa_main.c +@@ -361,7 +361,7 @@ static void ipa_qtime_config(struct ipa *ipa) + { + const struct reg *reg; + u32 offset; +- u32 val; ++ u32 val = 0; + + /* Timer clock divider must be disabled when we change the rate */ + reg = ipa_reg(ipa, TIMERS_XO_CLK_DIV_CFG); +@@ -374,8 +374,8 @@ static void ipa_qtime_config(struct ipa *ipa) + val |= reg_bit(reg, DPL_TIMESTAMP_SEL); + } + /* Configure tag and NAT Qtime timestamp resolution as well */ +- val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); +- val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); ++ val |= reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); ++ val |= reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); + + iowrite32(val, ipa->reg_virt + reg_offset(reg)); + +-- +2.53.0 + diff --git a/queue-6.12/net-mctp-i2c-check-length-before-marking-flow-active.patch b/queue-6.12/net-mctp-i2c-check-length-before-marking-flow-active.patch new file mode 100644 index 0000000000..bfdc3ade6b --- /dev/null +++ b/queue-6.12/net-mctp-i2c-check-length-before-marking-flow-active.patch @@ -0,0 +1,90 @@ +From ff15a89b97cafc9eae62d06d604b59f4d59038ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:46:52 -0700 +Subject: net: mctp i2c: check length before marking flow active + +From: William A. Kennington III + +[ Upstream commit 4ca07b9239bd0478ae586632a2ed72be37ed8407 ] + +Currently, mctp_i2c_get_tx_flow_state() is called before the packet length +sanity check. This function marks a new flow as active in the MCTP core. + +If the sanity check fails, mctp_i2c_xmit() returns early without calling +mctp_i2c_lock_nest(). This results in a mismatched locking state: the +flow is active, but the I2C bus lock was never acquired for it. + +When the flow is later released, mctp_i2c_release_flow() will see the +active state and queue an unlock marker. The TX thread will then +decrement midev->i2c_lock_count from 0, causing it to underflow to -1. + +This underflow permanently breaks the driver's locking logic, allowing +future transmissions to occur without holding the I2C bus lock, leading +to bus collisions and potential hardware hangs. + +Move the mctp_i2c_get_tx_flow_state() call to after the length sanity +check to ensure we only transition the flow state if we are actually +going to proceed with the transmission and locking. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: William A. Kennington III +Acked-by: Jeremy Kerr +Link: https://patch.msgid.link/20260423074741.201460-1-william@wkennington.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 4 ++-- + net/sched/cls_flower.c | 4 +++- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index f8f83fe424e51..a939bc084fe8d 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -497,8 +497,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + u8 *pecp; + int rc; + +- fs = mctp_i2c_get_tx_flow_state(midev, skb); +- + hdr = (void *)skb_mac_header(skb); + /* Sanity check that packet contents matches skb length, + * and can't exceed MCTP_I2C_BUFSZ +@@ -510,6 +508,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + return; + } + ++ fs = mctp_i2c_get_tx_flow_state(midev, skb); ++ + if (skb_tailroom(skb) >= 1) { + /* Linear case with space, we can just append the PEC */ + skb_put(skb, 1); +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index 099ff6a3e1f51..f3af0ac892a86 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -560,6 +560,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); ++ struct fl_flow_mask *mask; + + *last = false; + +@@ -576,11 +577,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- *last = fl_mask_put(head, f->mask); ++ mask = f->mask; + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); ++ *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch b/queue-6.12/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch new file mode 100644 index 0000000000..e8e1cf6c5d --- /dev/null +++ b/queue-6.12/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch @@ -0,0 +1,53 @@ +From b18244563cd8e0877f67b428d1b076ec0b07be3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 01:49:37 +0100 +Subject: net/mlx5: Fix HCA caps leak on notifier init failure + +From: Prathamesh Deshpande + +[ Upstream commit d03fc81a57956248383efec99967d0ae627390a8 ] + +mlx5_mdev_init() allocates HCA caps via mlx5_hca_caps_alloc() before +calling mlx5_notifiers_init(). If notifier initialization fails, the +error path jumps to err_hca_caps and skips mlx5_hca_caps_free(), leaking +allocated caps. + +Add a dedicated unwind label for notifier-init failure that frees HCA +caps before continuing the existing cleanup sequence. + +Fixes: b6b03097f982 ("net/mlx5: Initialize events outside devlink lock") +Signed-off-by: Prathamesh Deshpande +Reviewed-by: Cosmin Ratiu +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260415005022.34764-1-prathameshdeshpande7@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c +index 8856949fbe6a4..4d8295249c427 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c +@@ -1885,7 +1885,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) + + err = mlx5_notifiers_init(dev); + if (err) +- goto err_hca_caps; ++ goto err_notifiers_init; + + /* The conjunction of sw_vhca_id with sw_owner_id will be a global + * unique id per function which uses mlx5_core. +@@ -1901,6 +1901,8 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) + + return 0; + ++err_notifiers_init: ++ mlx5_hca_caps_free(dev); + err_hca_caps: + mlx5_adev_cleanup(dev); + err_adev_init: +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch b/queue-6.12/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch new file mode 100644 index 0000000000..f27b3d16fa --- /dev/null +++ b/queue-6.12/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch @@ -0,0 +1,63 @@ +From eed3fe3826d4ac763de9e00bcf7a7c92dad55461 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 23:28:51 +0300 +Subject: net/mlx5e: Fix features not applied during netdev registration + +From: Gal Pressman + +[ Upstream commit 9994ad4df82d64e57135c0f0906897685f5a9e87 ] + +mlx5e_fix_features() returns early when the netdevice is not present. +This is correct during profile transitions where priv is cleared, but it +also incorrectly blocks feature fixups during register_netdev(), when +the device is also not yet present. + +It is not trivial to distinguish between both cases as we cannot use +priv to carry state, and in both cases reg_state == NETREG_REGISTERED. + +Force a netdev features update after register_netdev() completes, where +the device is present and fix_features() can actually work. + +This is not a pretty solution, as it results in an additional features +update call (register_netdevice() already calls +__netdev_update_features() internally), but it is the simplest, +cleanest, and most robust way I found to fix this issue after multiple +attempts. + +This fixes an issue on systems where CQE compression is enabled by +default, RXHASH remains enabled after registration despite the two +features being mutually exclusive. + +Fixes: ab4b01bfdaa6 ("net/mlx5e: Verify dev is present for fix features ndo") +Signed-off-by: Gal Pressman +Reviewed-by: Dragos Tatulea +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260409202852.158059-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index 5736ed61e6eba..dbfb900980de7 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -6466,6 +6466,14 @@ static int _mlx5e_probe(struct auxiliary_device *adev) + goto err_resume; + } + ++ /* mlx5e_fix_features() returns early when the device is not present ++ * to avoid dereferencing cleared priv during profile changes. ++ * This also causes it to be a no-op during register_netdev(), where ++ * the device is not yet present. ++ * Trigger an additional features update that will actually work. ++ */ ++ mlx5e_update_features(netdev); ++ + mlx5e_dcbnl_init_app(priv); + mlx5_core_uplink_netdev_set(mdev, netdev); + mlx5e_params_print_info(mdev, &priv->channels.params); +-- +2.53.0 + diff --git a/queue-6.12/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch b/queue-6.12/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch new file mode 100644 index 0000000000..d5a61fe50d --- /dev/null +++ b/queue-6.12/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch @@ -0,0 +1,81 @@ +From b27a8bd7ab7820facf04ecd8b729e8f09dad9636 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 23:28:52 +0300 +Subject: net/mlx5e: IPsec, fix ASO poll timeout with + read_poll_timeout_atomic() + +From: Gal Pressman + +[ Upstream commit edccdd1eb94712da97a6ce71123ec27890add754 ] + +The do-while poll loop uses jiffies for its timeout: + expires = jiffies + msecs_to_jiffies(10); + +jiffies is sampled at an arbitrary point within the current tick, so the +first partial tick contributes anywhere from a full tick down to nearly +zero real time. For small msecs_to_jiffies() results this is +significant, the effective poll window can be much shorter than the +requested 10ms, and in the worst case the loop exits after a single +iteration (e.g., when HZ=100), well before the device has delivered the +CQE. + +Replace the loop with read_poll_timeout_atomic(), which counts elapsed +time via udelay() accounting rather than jiffies, guaranteeing the full +poll window regardless of HZ. + +Additionally, read_poll_timeout_atomic() executes the poll operation one +more time after the timeout has expired, giving the CQE a final chance +to be detected. The old do-while loop could exit without a final poll if +the timeout expired during the udelay() between iterations. + +Fixes: 76e463f6508b ("net/mlx5e: Overcome slow response for first IPsec ASO WQE") +Signed-off-by: Gal Pressman +Reviewed-by: Jianbo Liu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260409202852.158059-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../mellanox/mlx5/core/en_accel/ipsec_offload.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +index 40fe3d1e2342c..8f22559e373cd 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +@@ -1,6 +1,8 @@ + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB + /* Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. */ + ++#include ++ + #include "mlx5_core.h" + #include "en.h" + #include "ipsec.h" +@@ -593,7 +595,6 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, + struct mlx5_wqe_aso_ctrl_seg *ctrl; + struct mlx5e_hw_objs *res; + struct mlx5_aso_wqe *wqe; +- unsigned long expires; + u8 ds_cnt; + int ret; + +@@ -615,13 +616,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, + mlx5e_ipsec_aso_copy(ctrl, data); + + mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl); +- expires = jiffies + msecs_to_jiffies(10); +- do { +- ret = mlx5_aso_poll_cq(aso->aso, false); +- if (ret) +- /* We are in atomic context */ +- udelay(10); +- } while (ret && time_is_after_jiffies(expires)); ++ read_poll_timeout_atomic(mlx5_aso_poll_cq, ret, !ret, 10, ++ 10 * USEC_PER_MSEC, false, aso->aso, false); + if (!ret) + memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso)); + spin_unlock_bh(&aso->lock); +-- +2.53.0 + diff --git a/queue-6.12/net-page_pool-create-hooks-for-custom-memory-provide.patch b/queue-6.12/net-page_pool-create-hooks-for-custom-memory-provide.patch new file mode 100644 index 0000000000..723681f0a4 --- /dev/null +++ b/queue-6.12/net-page_pool-create-hooks-for-custom-memory-provide.patch @@ -0,0 +1,210 @@ +From 907f691e44408bd66ed8bd24b3d629a87b79fc8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Feb 2025 13:56:15 -0800 +Subject: net: page_pool: create hooks for custom memory providers + +From: Pavel Begunkov + +[ Upstream commit 57afb483015768903029c8336ee287f4b03c1235 ] + +A spin off from the original page pool memory providers patch by Jakub, +which allows extending page pools with custom allocators. One of such +providers is devmem TCP, and the other is io_uring zerocopy added in +following patches. + +Link: https://lore.kernel.org/netdev/20230707183935.997267-7-kuba@kernel.org/ +Co-developed-by: Jakub Kicinski # initial mp proposal +Signed-off-by: Pavel Begunkov +Signed-off-by: David Wei +Link: https://patch.msgid.link/20250204215622.695511-5-dw@davidwei.uk +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5ef343614db7 ("page_pool: fix memory-provider leak in page_pool_create_percpu() error path") +Signed-off-by: Sasha Levin +--- + include/net/page_pool/memory_provider.h | 15 +++++++++++++++ + include/net/page_pool/types.h | 4 ++++ + net/core/devmem.c | 15 ++++++++++++++- + net/core/page_pool.c | 23 +++++++++++++++-------- + 4 files changed, 48 insertions(+), 9 deletions(-) + create mode 100644 include/net/page_pool/memory_provider.h + +diff --git a/include/net/page_pool/memory_provider.h b/include/net/page_pool/memory_provider.h +new file mode 100644 +index 0000000000000..e49d0a52629d7 +--- /dev/null ++++ b/include/net/page_pool/memory_provider.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _NET_PAGE_POOL_MEMORY_PROVIDER_H ++#define _NET_PAGE_POOL_MEMORY_PROVIDER_H ++ ++#include ++#include ++ ++struct memory_provider_ops { ++ netmem_ref (*alloc_netmems)(struct page_pool *pool, gfp_t gfp); ++ bool (*release_netmem)(struct page_pool *pool, netmem_ref netmem); ++ int (*init)(struct page_pool *pool); ++ void (*destroy)(struct page_pool *pool); ++}; ++ ++#endif +diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h +index f53e2c90b6866..7fae0d4eef5eb 100644 +--- a/include/net/page_pool/types.h ++++ b/include/net/page_pool/types.h +@@ -156,8 +156,11 @@ struct page_pool_stats { + */ + #define PAGE_POOL_FRAG_GROUP_ALIGN (4 * sizeof(long)) + ++struct memory_provider_ops; ++ + struct pp_memory_provider_params { + void *mp_priv; ++ const struct memory_provider_ops *mp_ops; + }; + + struct page_pool { +@@ -219,6 +222,7 @@ struct page_pool { + struct ptr_ring ring; + + void *mp_priv; ++ const struct memory_provider_ops *mp_ops; + + struct xarray dma_mapped; + +diff --git a/net/core/devmem.c b/net/core/devmem.c +index f04a89b0a41fe..55f27a9ed1214 100644 +--- a/net/core/devmem.c ++++ b/net/core/devmem.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + + #include "devmem.h" +@@ -26,6 +27,8 @@ + /* Protected by rtnl_lock() */ + static DEFINE_XARRAY_FLAGS(net_devmem_dmabuf_bindings, XA_FLAGS_ALLOC1); + ++static const struct memory_provider_ops dmabuf_devmem_ops; ++ + static void net_devmem_dmabuf_free_chunk_owner(struct gen_pool *genpool, + struct gen_pool_chunk *chunk, + void *not_used) +@@ -117,6 +120,7 @@ void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding) + WARN_ON(rxq->mp_params.mp_priv != binding); + + rxq->mp_params.mp_priv = NULL; ++ rxq->mp_params.mp_ops = NULL; + + rxq_idx = get_netdev_rx_queue_index(rxq); + +@@ -143,7 +147,7 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx, + } + + rxq = __netif_get_rx_queue(dev, rxq_idx); +- if (rxq->mp_params.mp_priv) { ++ if (rxq->mp_params.mp_ops) { + NL_SET_ERR_MSG(extack, "designated queue already memory provider bound"); + return -EEXIST; + } +@@ -161,6 +165,7 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx, + return err; + + rxq->mp_params.mp_priv = binding; ++ rxq->mp_params.mp_ops = &dmabuf_devmem_ops; + + err = netdev_rx_queue_restart(dev, rxq_idx); + if (err) +@@ -170,6 +175,7 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx, + + err_xa_erase: + rxq->mp_params.mp_priv = NULL; ++ rxq->mp_params.mp_ops = NULL; + xa_erase(&binding->bound_rxqs, xa_idx); + + return err; +@@ -388,3 +394,10 @@ bool mp_dmabuf_devmem_release_page(struct page_pool *pool, netmem_ref netmem) + /* We don't want the page pool put_page()ing our net_iovs. */ + return false; + } ++ ++static const struct memory_provider_ops dmabuf_devmem_ops = { ++ .init = mp_dmabuf_devmem_init, ++ .destroy = mp_dmabuf_devmem_destroy, ++ .alloc_netmems = mp_dmabuf_devmem_alloc_netmems, ++ .release_netmem = mp_dmabuf_devmem_release_page, ++}; +diff --git a/net/core/page_pool.c b/net/core/page_pool.c +index 2ad52612d8ae8..5c089469541c4 100644 +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -13,6 +13,7 @@ + + #include + #include ++#include + #include + + #include +@@ -280,13 +281,19 @@ static int page_pool_init(struct page_pool *pool, + rxq = __netif_get_rx_queue(pool->slow.netdev, + pool->slow.queue_idx); + pool->mp_priv = rxq->mp_params.mp_priv; ++ pool->mp_ops = rxq->mp_params.mp_ops; + } + +- if (pool->mp_priv) { ++ if (pool->mp_ops) { + if (!pool->dma_map || !pool->dma_sync) + return -EOPNOTSUPP; + +- err = mp_dmabuf_devmem_init(pool); ++ if (WARN_ON(!is_kernel_rodata((unsigned long)pool->mp_ops))) { ++ err = -EFAULT; ++ goto free_ptr_ring; ++ } ++ ++ err = pool->mp_ops->init(pool); + if (err) { + pr_warn("%s() mem-provider init failed %d\n", __func__, + err); +@@ -651,8 +658,8 @@ netmem_ref page_pool_alloc_netmem(struct page_pool *pool, gfp_t gfp) + return netmem; + + /* Slow-path: cache empty, do real allocation */ +- if (static_branch_unlikely(&page_pool_mem_providers) && pool->mp_priv) +- netmem = mp_dmabuf_devmem_alloc_netmems(pool, gfp); ++ if (static_branch_unlikely(&page_pool_mem_providers) && pool->mp_ops) ++ netmem = pool->mp_ops->alloc_netmems(pool, gfp); + else + netmem = __page_pool_alloc_pages_slow(pool, gfp); + return netmem; +@@ -746,8 +753,8 @@ void page_pool_return_page(struct page_pool *pool, netmem_ref netmem) + bool put; + + put = true; +- if (static_branch_unlikely(&page_pool_mem_providers) && pool->mp_priv) +- put = mp_dmabuf_devmem_release_page(pool, netmem); ++ if (static_branch_unlikely(&page_pool_mem_providers) && pool->mp_ops) ++ put = pool->mp_ops->release_netmem(pool, netmem); + else + __page_pool_release_page_dma(pool, netmem); + +@@ -1081,8 +1088,8 @@ static void __page_pool_destroy(struct page_pool *pool) + page_pool_unlist(pool); + page_pool_uninit(pool); + +- if (pool->mp_priv) { +- mp_dmabuf_devmem_destroy(pool); ++ if (pool->mp_ops) { ++ pool->mp_ops->destroy(pool); + static_branch_dec(&page_pool_mem_providers); + } + +-- +2.53.0 + diff --git a/queue-6.12/net-phy-dp83869-fix-setting-clk_o_sel-field.patch b/queue-6.12/net-phy-dp83869-fix-setting-clk_o_sel-field.patch new file mode 100644 index 0000000000..3e33a8ba37 --- /dev/null +++ b/queue-6.12/net-phy-dp83869-fix-setting-clk_o_sel-field.patch @@ -0,0 +1,64 @@ +From 6f0ea97ba030c51802aa3e4fbb8fab15f4b225a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 05:13:39 +0200 +Subject: net: phy: dp83869: fix setting CLK_O_SEL field. + +From: Heiko Schocher + +[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ] + +Table 7-121 in datasheet says we have to set register 0xc6 +to value 0x10 before CLK_O_SEL can be modified. No more infos +about this field found in datasheet. With this fix, setting +of CLK_O_SEL field in IO_MUX_CFG register worked through dts +property "ti,clk-output-sel" on a DP83869HMRGZR. + +Signed-off-by: Heiko Schocher +Reviewed-by: Simon Horman +Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") +Link: https://patch.msgid.link/20260425031339.3318-1-hs@nabladev.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83869.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c +index b6b38caf9c0ed..96e5b8b03083a 100644 +--- a/drivers/net/phy/dp83869.c ++++ b/drivers/net/phy/dp83869.c +@@ -31,6 +31,7 @@ + #define DP83869_RGMIICTL 0x0032 + #define DP83869_STRAP_STS1 0x006e + #define DP83869_RGMIIDCTL 0x0086 ++#define DP83869_ANA_PLL_PROG_PI 0x00c6 + #define DP83869_RXFCFG 0x0134 + #define DP83869_RXFPMD1 0x0136 + #define DP83869_RXFPMD2 0x0137 +@@ -827,12 +828,22 @@ static int dp83869_config_init(struct phy_device *phydev) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ +- if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) ++ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { ++ /* ++ * Table 7-121 in datasheet says we have to set register 0xc6 ++ * to value 0x10 before CLK_O_SEL can be modified. ++ */ ++ ret = phy_write_mmd(phydev, DP83869_DEVADDR, ++ DP83869_ANA_PLL_PROG_PI, 0x10); ++ if (ret) ++ return ret; ++ + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); ++ } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, +-- +2.53.0 + diff --git a/queue-6.12/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch b/queue-6.12/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch new file mode 100644 index 0000000000..1c7cbab3a2 --- /dev/null +++ b/queue-6.12/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch @@ -0,0 +1,44 @@ +From bb6e944c84d6268d68975537f15aa1ed7b295165 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 06:36:54 -0700 +Subject: net: phy: fix a return path in get_phy_c45_ids() + +From: Charles Perry + +[ Upstream commit 6f533abe7bbad2eef1e42c639b6bb9dad2b02362 ] + +The return value of phy_c45_probe_present() is stored in "ret", not +"phy_reg", fix this. "phy_reg" always has a positive value if we reach +this return path (since it would have returned earlier otherwise), which +means that the original goal of the patch of not considering -ENODEV +fatal wasn't achieved. + +Fixes: 17b447539408 ("net: phy: c45 scanning: Don't consider -ENODEV fatal") +Signed-off-by: Charles Perry +Reviewed-by: Andrew Lunn +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260409133654.3203336-1-charles.perry@microchip.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 7f995d0e51f7b..eb478e4961cb9 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -873,8 +873,8 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr, + /* returning -ENODEV doesn't stop bus + * scanning + */ +- return (phy_reg == -EIO || +- phy_reg == -ENODEV) ? -ENODEV : -EIO; ++ return (ret == -EIO || ++ ret == -ENODEV) ? -ENODEV : -EIO; + + if (!ret) + continue; +-- +2.53.0 + diff --git a/queue-6.12/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch b/queue-6.12/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch new file mode 100644 index 0000000000..ec7c00fdc3 --- /dev/null +++ b/queue-6.12/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch @@ -0,0 +1,67 @@ +From 3847ad2c5294289969c858371ff93780ebc8f034 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:10:20 +0200 +Subject: net: phy: qcom: at803x: Use the correct bit to disable extended next + page + +From: Maxime Chevallier + +[ Upstream commit e7a62edd34b1b4bc5f979988efc2f81c075733fd ] + +As noted in the blamed commit, the AR8035 and other PHYs from this +family advertise the Extended Next Page support by default, which may be +understood by some partners as this PHY being multi-gig capable. + +The fix is to disable XNP advertising, which is done by setting bit 12 +of the Auto-Negotiation Advertisement Register (MII_ADVERTISE). + +The blamed commit incorrectly uses MDIO_AN_CTRL1_XNP, which is bit 13 as per +802.3 : 45.2.7.1 AN control register (Register 7.0) + +BIT 12 in MII_ADVERTISE is wrapped by ADVERTISE_RESV, used by some +drivers such as the aquantia one. 802.3 Clause 28 defines bit 12 as +Extended Next Page ability, at least in recent versions of the standard. + +Let's add a define for it and use it in the at803x driver. + +Fixes: 3c51fa5d2afe ("net: phy: ar803x: disable extended next page bit") +Signed-off-by: Maxime Chevallier +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260410171021.1277138-1-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/qcom/at803x.c | 2 +- + include/uapi/linux/mii.h | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c +index ac909ad8a87b4..11b7540b69582 100644 +--- a/drivers/net/phy/qcom/at803x.c ++++ b/drivers/net/phy/qcom/at803x.c +@@ -474,7 +474,7 @@ static int at803x_config_init(struct phy_device *phydev) + * behaviour but we still need to accommodate it. XNP is only needed + * for 10Gbps support, so disable XNP. + */ +- return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); ++ return phy_modify(phydev, MII_ADVERTISE, ADVERTISE_XNP, 0); + } + + static void at803x_link_change_notify(struct phy_device *phydev) +diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h +index 39f7c44baf535..61d6edad4b94a 100644 +--- a/include/uapi/linux/mii.h ++++ b/include/uapi/linux/mii.h +@@ -82,7 +82,8 @@ + #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ + #define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ + #define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +-#define ADVERTISE_RESV 0x1000 /* Unused... */ ++#define ADVERTISE_XNP 0x1000 /* Extended Next Page */ ++#define ADVERTISE_RESV ADVERTISE_XNP /* Used to be reserved */ + #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ + #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ + #define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +-- +2.53.0 + diff --git a/queue-6.12/net-rds-optimize-rds_ib_laddr_check.patch b/queue-6.12/net-rds-optimize-rds_ib_laddr_check.patch new file mode 100644 index 0000000000..4df941c352 --- /dev/null +++ b/queue-6.12/net-rds-optimize-rds_ib_laddr_check.patch @@ -0,0 +1,189 @@ +From 3d42406dc8cedd17efc41413ebba1e2df99ca2ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:19 -0700 +Subject: net/rds: Optimize rds_ib_laddr_check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 236f718ac885965fa886440b9898dfae185c9733 ] + +rds_ib_laddr_check() creates a CM_ID and attempts to bind the address +in question to it. This in order to qualify the allegedly local +address as a usable IB/RoCE address. + +In the field, ExaWatcher runs rds-ping to all ports in the fabric from +all local ports. This using all active ToS'es. In a full rack system, +we have 14 cell servers and eight db servers. Typically, 6 ToS'es are +used. This implies 528 rds-ping invocations per ExaWatcher's "RDSinfo" +interval. + +Adding to this, each rds-ping invocation creates eight sockets and +binds the local address to them: + +socket(AF_RDS, SOCK_SEQPACKET, 0) = 3 +bind(3, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 4 +bind(4, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 5 +bind(5, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 6 +bind(6, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 7 +bind(7, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 8 +bind(8, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 9 +bind(9, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 10 +bind(10, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 + +So, at every interval ExaWatcher executes rds-ping's, 4224 CM_IDs are +allocated, considering this full-rack system. After the a CM_ID has +been allocated, rdma_bind_addr() is called, with the port number being +zero. This implies that the CMA will attempt to search for an un-used +ephemeral port. Simplified, the algorithm is to start at a random +position in the available port space, and then if needed, iterate +until an un-used port is found. + +The book-keeping of used ports uses the idr system, which again uses +slab to allocate new struct idr_layer's. The size is 2092 bytes and +slab tries to reduce the wasted space. Hence, it chooses an order:3 +allocation, for which 15 idr_layer structs will fit and only 1388 +bytes are wasted per the 32KiB order:3 chunk. + +Although this order:3 allocation seems like a good space/speed +trade-off, it does not resonate well with how it used by the CMA. The +combination of the randomized starting point in the port space (which +has close to zero spatial locality) and the close proximity in time of +the 4224 invocations of the rds-ping's, creates a memory hog for +order:3 allocations. + +These costly allocations may need reclaims and/or compaction. At +worst, they may fail and produce a stack trace such as (from uek4): + +[] __inc_zone_page_state+0x35/0x40 +[] page_add_file_rmap+0x57/0x60 +[] remove_migration_pte+0x3f/0x3c0 [ksplice_6cn872bt_vmlinux_new] +[] rmap_walk+0xd8/0x340 +[] remove_migration_ptes+0x40/0x50 +[] migrate_pages+0x3ec/0x890 +[] compact_zone+0x32d/0x9a0 +[] compact_zone_order+0x6d/0x90 +[] try_to_compact_pages+0x102/0x270 +[] __alloc_pages_direct_compact+0x46/0x100 +[] __alloc_pages_nodemask+0x74b/0xaa0 +[] alloc_pages_current+0x91/0x110 +[] new_slab+0x38b/0x480 +[] __slab_alloc+0x3b7/0x4a0 [ksplice_s0dk66a8_vmlinux_new] +[] kmem_cache_alloc+0x1fb/0x250 +[] idr_layer_alloc+0x36/0x90 +[] idr_get_empty_slot+0x28c/0x3d0 +[] idr_alloc+0x4d/0xf0 +[] cma_alloc_port+0x4d/0xa0 [rdma_cm] +[] rdma_bind_addr+0x2ae/0x5b0 [rdma_cm] +[] rds_ib_laddr_check+0x83/0x2c0 [ksplice_6l2xst5i_rds_rdma_new] +[] rds_trans_get_preferred+0x5b/0xa0 [rds] +[] rds_bind+0x212/0x280 [rds] +[] SYSC_bind+0xe6/0x120 +[] SyS_bind+0xe/0x10 +[] system_call_fastpath+0x18/0xd4 + +To avoid these excessive calls to rdma_bind_addr(), we optimize +rds_ib_laddr_check() by simply checking if the address in question has +been used before. The rds_rdma module keeps track of addresses +associated with IB devices, and the function rds_ib_get_device() is +used to determine if the address already has been qualified as a valid +local address. If not found, we call the legacy rds_ib_laddr_check(), +now renamed to rds_ib_laddr_check_cm(). + +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Somasundaram Krishnasamy +Signed-off-by: Gerd Rausch +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-2-achender@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: ebf71dd4aff4 ("net/rds: Restrict use of RDS/IB to the initial network namespace") +Signed-off-by: Sasha Levin +--- + net/rds/ib.c | 20 ++++++++++++++++++-- + net/rds/ib.h | 1 + + net/rds/ib_rdma.c | 2 +- + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 9826fe7f9d008..996f007cd516b 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -403,8 +403,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len, + * allowed to influence which paths have priority. We could call userspace + * asserting this policy "routing". + */ +-static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, +- __u32 scope_id) ++static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) + { + int ret; + struct rdma_cm_id *cm_id; +@@ -489,6 +489,22 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + return ret; + } + ++static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) ++{ ++ struct rds_ib_device *rds_ibdev = NULL; ++ ++ if (ipv6_addr_v4mapped(addr)) { ++ rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); ++ if (rds_ibdev) { ++ rds_ib_dev_put(rds_ibdev); ++ return 0; ++ } ++ } ++ ++ return rds_ib_laddr_check_cm(net, addr, scope_id); ++} ++ + static void rds_ib_unregister_client(void) + { + ib_unregister_client(&rds_ib_client); +diff --git a/net/rds/ib.h b/net/rds/ib.h +index 8ef3178ed4d61..5ff346a1e8baa 100644 +--- a/net/rds/ib.h ++++ b/net/rds/ib.h +@@ -381,6 +381,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, + __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) + + /* ib_rdma.c */ ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr); + int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, + struct in6_addr *ipaddr); + void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); +diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c +index 30fca2169aa7a..468fd60d818ff 100644 +--- a/net/rds/ib_rdma.c ++++ b/net/rds/ib_rdma.c +@@ -47,7 +47,7 @@ struct rds_ib_dereg_odp_mr { + + static void rds_ib_odp_mr_worker(struct work_struct *work); + +-static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) + { + struct rds_ib_device *rds_ibdev; + struct rds_ib_ipaddr *i_ipaddr; +-- +2.53.0 + diff --git a/queue-6.12/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch b/queue-6.12/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch new file mode 100644 index 0000000000..01a6e569a7 --- /dev/null +++ b/queue-6.12/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch @@ -0,0 +1,86 @@ +From 448fe1cd5bd13d2678af734c4242e96a3f12b96d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:20 -0700 +Subject: net/rds: Restrict use of RDS/IB to the initial network namespace + +From: Greg Jumper + +[ Upstream commit ebf71dd4aff46e8e421d455db3e231ba43d2fa8a ] + +Prevent using RDS/IB in network namespaces other than the initial one. +The existing RDS/IB code will not work properly in non-initial network +namespaces. + +Fixes: d5a8ac28a7ff ("RDS-TCP: Make RDS-TCP work correctly when it is set up in a netns other than init_net") +Reported-by: syzbot+da8e060735ae02c8f3d1@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=da8e060735ae02c8f3d1 +Signed-off-by: Greg Jumper +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-3-achender@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/af_rds.c | 10 ++++++++-- + net/rds/ib.c | 4 ++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c +index 8435a20968ef5..f0840169d5e31 100644 +--- a/net/rds/af_rds.c ++++ b/net/rds/af_rds.c +@@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen) + return ret; + } + +-static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) ++static int rds_set_transport(struct net *net, struct rds_sock *rs, ++ sockptr_t optval, int optlen) + { + int t_type; + +@@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) + if (t_type < 0 || t_type >= RDS_TRANS_COUNT) + return -EINVAL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + rs->rs_transport = rds_trans_get(t_type); + + return rs->rs_transport ? 0 : -ENOPROTOOPT; +@@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) + { + struct rds_sock *rs = rds_sk_to_rs(sock->sk); ++ struct net *net = sock_net(sock->sk); + int ret; + + if (level != SOL_RDS) { +@@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + break; + case SO_RDS_TRANSPORT: + lock_sock(sock->sk); +- ret = rds_set_transport(rs, optval, optlen); ++ ret = rds_set_transport(net, rs, optval, optlen); + release_sock(sock->sk); + break; + case SO_TIMESTAMP_OLD: +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 996f007cd516b..ce5be43c5fbac 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -494,6 +494,10 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + { + struct rds_ib_device *rds_ibdev = NULL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (!net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + if (ipv6_addr_v4mapped(addr)) { + rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); + if (rds_ibdev) { +-- +2.53.0 + diff --git a/queue-6.12/net-rds-zero-per-item-info-buffer-before-handing-it-.patch b/queue-6.12/net-rds-zero-per-item-info-buffer-before-handing-it-.patch new file mode 100644 index 0000000000..e1a421d550 --- /dev/null +++ b/queue-6.12/net-rds-zero-per-item-info-buffer-before-handing-it-.patch @@ -0,0 +1,111 @@ +From 17a4d22e9df39278e85b9d35e181b78b082e4db2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 10:10:47 -0400 +Subject: net/rds: zero per-item info buffer before handing it to visitors + +From: Michael Bommarito + +[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ] + +rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a +caller-allocated on-stack u64 buffer to a per-connection visitor and +then copy the full item_len bytes back to user space via +rds_info_copy() regardless of how much of the buffer the visitor +actually wrote. + +rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only +write a subset of their output struct when the underlying +rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl +and the two GIDs via explicit memsets). Several u32 fields +(max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, +cache_allocs) and the 2-byte alignment hole between sl and +cache_allocs remain as whatever stack contents preceded the visitor +call and are then memcpy_to_user()'d out to user space. + +struct rds_info_rdma_connection and struct rds6_info_rdma_connection +are the only rds_info_* structs in include/uapi/linux/rds.h that are +not marked __attribute__((packed)), so they have a real alignment +hole. The other info visitors (rds_conn_info_visitor, +rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of +their packed output struct today and are not known to be vulnerable, +but a future visitor that adds a conditional write-path would have +the same bug. + +Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y: +a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, +binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on +any netdev is sufficient), sendto()'s any peer on the same subnet +(fails cleanly but installs an rds_connection in the global hash in +RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, +RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 +bytes of stack garbage including kernel text/data pointers: + + 0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2 + 8..39 00 ... gids (memset-zeroed) + 40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr) + 48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max) + 56..59 01 00 08 00 rdma_mr_size (garbage) + 60..61 00 00 tos, sl + 62..63 00 00 alignment padding + 64..67 18 00 00 00 cache_allocs (garbage) + +Fix by zeroing the per-item buffer in both rds_for_each_conn_info() +and rds_walk_conn_path_info() before invoking the visitor. This +covers the IPv4/IPv6 IB visitors and hardens all current and future +visitors against the same class of bug. + +No functional change for visitors that fully populate their output. + +Changes in v2: +- retarget at the net tree (subject prefix "[PATCH net v2]", + net/rds: prefix in the title) +- pick up Reviewed-by tags from Sharath Srinivasan and + Allison Henderson + +Fixes: ec16227e1414 ("RDS/IB: Infiniband transport") +Signed-off-by: Michael Bommarito +Reviewed-by: Sharath Srinivasan +Reviewed-by: Allison Henderson +Assisted-by: Claude:claude-opus-4-7 +Link: https://patch.msgid.link/20260418141047.3398203-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/connection.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index 3a1b548dcdcb2..d6ee386fd820e 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -673,6 +673,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, + i++, head++) { + hlist_for_each_entry_rcu(conn, head, c_hash_node) { + ++ /* Zero the per-item buffer before handing it to the ++ * visitor so any field the visitor does not write - ++ * including implicit alignment padding - cannot leak ++ * stack contents to user space via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no c_lock usage.. */ + if (!visitor(conn, buffer)) + continue; +@@ -722,6 +729,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, + */ + cp = conn->c_path; + ++ /* Zero the per-item buffer for the same reason as ++ * rds_for_each_conn_info(): any byte the visitor ++ * does not write (including alignment padding) must ++ * not leak stack contents via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no cp_lock usage.. */ + if (!visitor(cp, buffer)) + continue; +-- +2.53.0 + diff --git a/queue-6.12/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch b/queue-6.12/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch new file mode 100644 index 0000000000..ba4b0124fb --- /dev/null +++ b/queue-6.12/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch @@ -0,0 +1,130 @@ +From c72c8d77b4e38a3b64c4ed479122fddc8bb9f351 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:16:27 -0400 +Subject: net/sched: act_ct: Only release RCU read lock after ct_ft + +From: Jamal Hadi Salim + +[ Upstream commit f462dca0c8415bf0058d0ffa476354c4476d0f09 ] + +When looking up a flow table in act_ct in tcf_ct_flow_table_get(), +rhashtable_lookup_fast() internally opens and closes an RCU read critical +section before returning ct_ft. +The tcf_ct_flow_table_cleanup_work() can complete before refcount_inc_not_zero() +is invoked on the returned ct_ft resulting in a UAF on the already freed ct_ft +object. This vulnerability can lead to privilege escalation. + +Analysis from zdi-disclosures@trendmicro.com: +When initializing act_ct, tcf_ct_init() is called, which internally triggers +tcf_ct_flow_table_get(). + +static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + +{ + struct zones_ht_key key = { .net = net, .zone = params->zone }; + struct tcf_ct_flow_table *ct_ft; + int err = -ENOMEM; + + mutex_lock(&zones_mutex); + ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); // [1] + if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) // [2] + goto out_unlock; + ... +} + +static __always_inline void *rhashtable_lookup_fast( + struct rhashtable *ht, const void *key, + const struct rhashtable_params params) +{ + void *obj; + + rcu_read_lock(); + obj = rhashtable_lookup(ht, key, params); + rcu_read_unlock(); + + return obj; +} + +At [1], rhashtable_lookup_fast() looks up and returns the corresponding ct_ft +from zones_ht . The lookup is performed within an RCU read critical section +through rcu_read_lock() / rcu_read_unlock(), which prevents the object from +being freed. However, at the point of function return, rcu_read_unlock() has +already been called, and there is nothing preventing ct_ft from being freed +before reaching refcount_inc_not_zero(&ct_ft->ref) at [2]. This interval becomes +the race window, during which ct_ft can be freed. + +Free Process: + +tcf_ct_flow_table_put() is executed through the path tcf_ct_cleanup() call_rcu() +tcf_ct_params_free_rcu() tcf_ct_params_free() tcf_ct_flow_table_put(). + +static void tcf_ct_flow_table_put(struct tcf_ct_flow_table *ct_ft) +{ + if (refcount_dec_and_test(&ct_ft->ref)) { + rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params); + INIT_RCU_WORK(&ct_ft->rwork, tcf_ct_flow_table_cleanup_work); // [3] + queue_rcu_work(act_ct_wq, &ct_ft->rwork); + } +} + +At [3], tcf_ct_flow_table_cleanup_work() is scheduled as RCU work + +static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) + +{ + struct tcf_ct_flow_table *ct_ft; + struct flow_block *block; + + ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, + rwork); + nf_flow_table_free(&ct_ft->nf_ft); + block = &ct_ft->nf_ft.flow_block; + down_write(&ct_ft->nf_ft.flow_block_lock); + WARN_ON(!list_empty(&block->cb_list)); + up_write(&ct_ft->nf_ft.flow_block_lock); + kfree(ct_ft); // [4] + + module_put(THIS_MODULE); +} + +tcf_ct_flow_table_cleanup_work() frees ct_ft at [4]. When this function executes +between [1] and [2], UAF occurs. + +This race condition has a very short race window, making it generally +difficult to trigger. Therefore, to trigger the vulnerability an msleep(100) was +inserted after[1] + +Fixes: 138470a9b2cc2 ("net/sched: act_ct: fix lockdep splat in tcf_ct_flow_table_get") +Reported-by: zdi-disclosures@trendmicro.com +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260410111627.46611-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/act_ct.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index 945b64be4c1f1..c82755749211c 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -326,9 +326,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + int err = -ENOMEM; + + mutex_lock(&zones_mutex); +- ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); +- if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) ++ rcu_read_lock(); ++ ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params); ++ if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) { ++ rcu_read_unlock(); + goto out_unlock; ++ } ++ rcu_read_unlock(); + + ct_ft = kzalloc(sizeof(*ct_ft), GFP_KERNEL); + if (!ct_ft) +-- +2.53.0 + diff --git a/queue-6.12/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch b/queue-6.12/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch new file mode 100644 index 0000000000..078ab8eecf --- /dev/null +++ b/queue-6.12/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch @@ -0,0 +1,59 @@ +From 358390c0b9599396ce76cb9bbc2916b5053e29ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:49:27 +0800 +Subject: net/sched: act_mirred: fix wrong device for mac_header_xmit check in + tcf_blockcast_redir +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit 4510d140524ca7d6e772db962e013f26f09a63b1 ] + +In tcf_blockcast_redir(), when iterating block ports to redirect +packets to multiple devices, the mac_header_xmit flag is queried +from the wrong device. The loop sends to dev_prev but queries +dev_is_mac_header_xmit(dev) — which is the NEXT device in the +iteration, not the one being sent to. + +This causes tcf_mirred_to_dev() to make incorrect decisions about +whether to push or pull the MAC header. When the block contains +mixed device types (e.g., an ethernet veth and a tunnel device), +intermediate devices get the wrong mac_header_xmit flag, leading to +skb header corruption. In the worst case, skb_push_rcsum with an +incorrect mac_len can exhaust headroom and panic. + +The last device in the loop is handled correctly (line 365-366 uses +dev_is_mac_header_xmit(dev_prev)), confirming this is a copy-paste +oversight for the intermediate devices. + +Fix by using dev_prev instead of dev for the mac_header_xmit query, +consistent with the device actually being sent to. + +Fixes: 42f39036cda8 ("net/sched: act_mirred: Allow mirred to block") +Signed-off-by: Dudu Lu +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260413084927.71353-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/act_mirred.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index 5b38143659249..b1b0049d7a0e9 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -348,7 +348,7 @@ static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m, + goto assign_prev; + + tcf_mirred_to_dev(skb, m, dev_prev, +- dev_is_mac_header_xmit(dev), ++ dev_is_mac_header_xmit(dev_prev), + mirred_eaction, retval); + assign_prev: + dev_prev = dev; +-- +2.53.0 + diff --git a/queue-6.12/net-sched-cls_flower-revert-unintended-changes.patch b/queue-6.12/net-sched-cls_flower-revert-unintended-changes.patch new file mode 100644 index 0000000000..3195bf0be6 --- /dev/null +++ b/queue-6.12/net-sched-cls_flower-revert-unintended-changes.patch @@ -0,0 +1,55 @@ +From 992d3c87ac3ab12dd728209152bce1cbfb9434e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:39:11 +0200 +Subject: net/sched: cls_flower: revert unintended changes + +From: Paolo Abeni + +[ Upstream commit 1e01abec856593e02cd69fd95b784c10dd46880c ] + +While applying the blamed commit 4ca07b9239bd ("net: mctp i2c: check +length before marking flow active"), I unintentionally included +unrelated and unacceptable changes. + +Revert them. + +Fixes: 4ca07b9239bd ("net: mctp i2c: check length before marking flow active") +Reported-by: Jeremy Kerr +Closes: https://lore.kernel.org/netdev/bd8704fe0bd53e278add5cde4873256656623e2e.camel@codeconstruct.com.au/ +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/043026a53ff84da88b17648c4b0d17f0331749cb.1777447863.git.pabeni@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/cls_flower.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index f3af0ac892a86..099ff6a3e1f51 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -560,7 +560,6 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); +- struct fl_flow_mask *mask; + + *last = false; + +@@ -577,12 +576,11 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- mask = f->mask; ++ *last = fl_mask_put(head, f->mask); + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); +- *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/net-sched-netem-check-for-negative-latency-and-jitte.patch b/queue-6.12/net-sched-netem-check-for-negative-latency-and-jitte.patch new file mode 100644 index 0000000000..0e9c41ca6a --- /dev/null +++ b/queue-6.12/net-sched-netem-check-for-negative-latency-and-jitte.patch @@ -0,0 +1,73 @@ +From 787300fef1c725a19ddb268216a75510b6c25f93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:44 -0700 +Subject: net/sched: netem: check for negative latency and jitter + +From: Stephen Hemminger + +[ Upstream commit 90be9fedb218ee95a1cf59050d1306fbfb0e8b87 ] + +Reject requests with negative latency or jitter. +A negative value added to current timestamp (u64) wraps +to an enormous time_to_send, disabling dequeue. +The original UAPI used u32 for these values; the conversion to 64-bit +time values via TCA_NETEM_LATENCY64 and TCA_NETEM_JITTER64 +allowed signed values to reach the kernel without validation. + +Jitter is already silently clamped by an abs() in netem_change(); +that abs() can be removed in a follow-up once this rejection is in +place. + +Fixes: 99803171ef04 ("netem: add uapi to express delay and jitter in nanoseconds") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-7-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 543a043f84f41..498c18d7d9c39 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -824,6 +824,16 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_time(const struct nlattr *attr, const char *name, ++ struct netlink_ext_ack *extack) ++{ ++ if (nla_get_s64(attr) < 0) { ++ NL_SET_ERR_MSG_ATTR_FMT(extack, attr, "negative %s", name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1066,6 +1076,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_LATENCY64]) { ++ ret = validate_time(tb[TCA_NETEM_LATENCY64], "latency", extack); ++ if (ret) ++ goto table_free; ++ } ++ ++ if (tb[TCA_NETEM_JITTER64]) { ++ ret = validate_time(tb[TCA_NETEM_JITTER64], "jitter", extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-6.12/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch b/queue-6.12/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch new file mode 100644 index 0000000000..d5ff5ae390 --- /dev/null +++ b/queue-6.12/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch @@ -0,0 +1,67 @@ +From 00fc63fccced373ab3e5c2631d531aded0040ce5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:39 -0700 +Subject: net/sched: netem: fix probability gaps in 4-state loss model + +From: Stephen Hemminger + +[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ] + +The 4-state Markov chain in loss_4state() has gaps at the boundaries +between transition probability ranges. The comparisons use: + + if (rnd < a4) + else if (a4 < rnd && rnd < a1 + a4) + +When rnd equals a boundary value exactly, neither branch matches and +no state transition occurs. The redundant lower-bound check (a4 < rnd) +is already implied by being in the else branch. + +Remove the unnecessary lower-bound comparisons so the ranges are +contiguous and every random value produces a transition, matching +the GI (General and Intuitive) loss model specification. + +This bug goes back to original implementation of this model. + +Fixes: 661b79725fea ("netem: revised correlated loss generator") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-2-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 825c398aa1232..add20b1ab79b2 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -226,10 +226,10 @@ static bool loss_4state(struct netem_sched_data *q) + if (rnd < clg->a4) { + clg->state = LOST_IN_GAP_PERIOD; + return true; +- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { ++ } else if (rnd < clg->a1 + clg->a4) { + clg->state = LOST_IN_BURST_PERIOD; + return true; +- } else if (clg->a1 + clg->a4 < rnd) { ++ } else { + clg->state = TX_IN_GAP_PERIOD; + } + +@@ -246,9 +246,9 @@ static bool loss_4state(struct netem_sched_data *q) + case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; +- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { ++ else if (rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; +- } else if (clg->a2 + clg->a3 < rnd) { ++ } else { + clg->state = LOST_IN_BURST_PERIOD; + return true; + } +-- +2.53.0 + diff --git a/queue-6.12/net-sched-netem-fix-queue-limit-check-to-include-reo.patch b/queue-6.12/net-sched-netem-fix-queue-limit-check-to-include-reo.patch new file mode 100644 index 0000000000..020e8f8085 --- /dev/null +++ b/queue-6.12/net-sched-netem-fix-queue-limit-check-to-include-reo.patch @@ -0,0 +1,42 @@ +From 1a2260e8c1e8999f8e031165c8d9b4b50b4566b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:40 -0700 +Subject: net/sched: netem: fix queue limit check to include reordered packets + +From: Stephen Hemminger + +[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ] + +The queue limit check in netem_enqueue() uses q->t_len which only +counts packets in the internal tfifo. Packets placed in sch->q by +the reorder path (__qdisc_enqueue_head) are not counted, allowing +the total queue occupancy to exceed sch->limit under reordering. + +Include sch->q.qlen in the limit check. + +Fixes: f8d4bc455047 ("net/sched: netem: account for backlog updates from child qdisc") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-3-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index add20b1ab79b2..542ab3f7e3d07 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -522,7 +522,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + 1 << get_random_u32_below(8); + } + +- if (unlikely(q->t_len >= sch->limit)) { ++ if (unlikely(sch->q.qlen >= sch->limit)) { + /* re-link segs, so that qdisc_drop_all() frees them all */ + skb->next = segs; + qdisc_drop_all(skb, sch, to_free); +-- +2.53.0 + diff --git a/queue-6.12/net-sched-netem-fix-slot-delay-calculation-overflow.patch b/queue-6.12/net-sched-netem-fix-slot-delay-calculation-overflow.patch new file mode 100644 index 0000000000..b65ceba72e --- /dev/null +++ b/queue-6.12/net-sched-netem-fix-slot-delay-calculation-overflow.patch @@ -0,0 +1,51 @@ +From e1b355341faf1718c2dde788233bca3e11a5ada8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:43 -0700 +Subject: net/sched: netem: fix slot delay calculation overflow + +From: Stephen Hemminger + +[ Upstream commit 51e94e1e2fef351c74d69eb53666df808d26af95 ] + +get_slot_next() computes a random delay between min_delay and +max_delay using: + + get_random_u32() * (max_delay - min_delay) >> 32 + +This overflows signed 64-bit arithmetic when the delay range exceeds +approximately 2.1 seconds (2^31 nanoseconds), producing a negative +result that effectively disables slot-based pacing. This is a +realistic configuration for WAN emulation (e.g., slot 1s 5s). + +Use mul_u64_u32_shr() which handles the widening multiply without +overflow. + +Fixes: 0a9fe5c375b5 ("netem: slotting with non-uniform distribution") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-6-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 330d4ff7324d1..543a043f84f41 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -657,9 +657,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now) + + if (!q->slot_dist) + next_delay = q->slot_config.min_delay + +- (get_random_u32() * +- (q->slot_config.max_delay - +- q->slot_config.min_delay) >> 32); ++ mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay, ++ get_random_u32(), 32); + else + next_delay = tabledist(q->slot_config.dist_delay, + (s32)(q->slot_config.dist_jitter), +-- +2.53.0 + diff --git a/queue-6.12/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch b/queue-6.12/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch new file mode 100644 index 0000000000..4dec40cbf6 --- /dev/null +++ b/queue-6.12/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch @@ -0,0 +1,60 @@ +From abcab1215021a2c717ab5dd0e406aae14fea0bc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:41 -0700 +Subject: net/sched: netem: only reseed PRNG when seed is explicitly provided + +From: Stephen Hemminger + +[ Upstream commit 986afaf809940577224a99c3a08d97a15eb37e93 ] + +netem_change() unconditionally reseeds the PRNG on every tc change +command. If TCA_NETEM_PRNG_SEED is not specified, a new random seed +is generated, destroying reproducibility for users who set a +deterministic seed on a previous change. + +Move the initial random seed generation to netem_init() and only +reseed in netem_change() when TCA_NETEM_PRNG_SEED is explicitly +provided by the user. + +Fixes: 4072d97ddc44 ("netem: add prng attribute to netem_sched_data") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-4-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 542ab3f7e3d07..67f3b06373dcf 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1110,11 +1110,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + /* capping jitter to the range acceptable by tabledist() */ + q->jitter = min_t(s64, abs(q->jitter), INT_MAX); + +- if (tb[TCA_NETEM_PRNG_SEED]) ++ if (tb[TCA_NETEM_PRNG_SEED]) { + q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]); +- else +- q->prng.seed = get_random_u64(); +- prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ } + + unlock: + sch_tree_unlock(sch); +@@ -1137,6 +1136,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt, + return -EINVAL; + + q->loss_model = CLG_RANDOM; ++ q->prng.seed = get_random_u64(); ++ prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ + ret = netem_change(sch, opt, extack); + if (ret) + pr_info("netem: change failed\n"); +-- +2.53.0 + diff --git a/queue-6.12/net-sched-netem-validate-slot-configuration.patch b/queue-6.12/net-sched-netem-validate-slot-configuration.patch new file mode 100644 index 0000000000..badb63e18a --- /dev/null +++ b/queue-6.12/net-sched-netem-validate-slot-configuration.patch @@ -0,0 +1,86 @@ +From 304861b0936600e98fa7a64e1dd040979ea84429 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:42 -0700 +Subject: net/sched: netem: validate slot configuration + +From: Stephen Hemminger + +[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ] + +Reject slot configurations that have no defensible meaning: + + - negative min_delay or max_delay + - min_delay greater than max_delay + - negative dist_delay or dist_jitter + - negative max_packets or max_bytes + +Negative or out-of-order delays underflow in get_slot_next(), +producing garbage intervals. Negative limits trip the per-slot +accounting (packets_left/bytes_left <= 0) on the first packet of +every slot, defeating the rate-limiting half of the slot feature. + +Note that dist_jitter has been silently coerced to its absolute +value by get_slot() since the feature was introduced; rejecting +negatives here converts that silent coercion into -EINVAL. The +abs() can be removed in a follow-up. + +Fixes: 836af83b54e3 ("netem: support delivering packets in delayed time slots") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 67f3b06373dcf..330d4ff7324d1 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -825,6 +825,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) ++{ ++ const struct tc_netem_slot *c = nla_data(attr); ++ ++ if (c->min_delay < 0 || c->max_delay < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); ++ return -EINVAL; ++ } ++ if (c->min_delay > c->max_delay) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); ++ return -EINVAL; ++ } ++ if (c->dist_delay < 0 || c->dist_jitter < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); ++ return -EINVAL; ++ } ++ if (c->max_packets < 0 || c->max_bytes < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1038,6 +1061,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_SLOT]) { ++ ret = validate_slot(tb[TCA_NETEM_SLOT], extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch b/queue-6.12/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch new file mode 100644 index 0000000000..f72c52afe4 --- /dev/null +++ b/queue-6.12/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch @@ -0,0 +1,62 @@ +From 64ee6683f4beb3b29ba04420d72a507e7b59f294 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:06 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (V) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations +for cparams.target and cparams.interval. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index ee8d662db747c..ba1a5c15e6cab 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -2297,10 +2297,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + + byte_target_ns = (byte_target * rate_ns) >> rate_shft; + +- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); +- b->cparams.interval = max(rtt_est_ns + +- b->cparams.target - target_ns, +- b->cparams.target * 2); ++ WRITE_ONCE(b->cparams.target, ++ max((byte_target_ns * 3) / 2, target_ns)); ++ WRITE_ONCE(b->cparams.interval, ++ max(rtt_est_ns + b->cparams.target - target_ns, ++ b->cparams.target * 2)); + b->cparams.mtu_time = byte_target_ns; + b->cparams.p_inc = 1 << 24; /* 1/256 */ + b->cparams.p_dec = 1 << 20; /* 1/4096 */ +@@ -2930,9 +2931,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); + + PUT_TSTAT_U32(TARGET_US, +- ktime_to_us(ns_to_ktime(b->cparams.target))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); + PUT_TSTAT_U32(INTERVAL_US, +- ktime_to_us(ns_to_ktime(b->cparams.interval))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); + + PUT_TSTAT_U32(SENT_PACKETS, b->packets); + PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch b/queue-6.12/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch new file mode 100644 index 0000000000..1f32e0e3fd --- /dev/null +++ b/queue-6.12/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch @@ -0,0 +1,64 @@ +From 9cfe4fe838903a2329eb35d0d748680bde8631f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:00:41 +0800 +Subject: net/sched: sch_cake: fix NAT destination port not being updated in + cake_update_flowkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit f9e40664706927d7ae22a448a3383e23c38a4c0b ] + +cake_update_flowkeys() is supposed to update the flow dissector keys +with the NAT-translated addresses and ports from conntrack, so that +CAKE's per-flow fairness correctly identifies post-NAT flows as +belonging to the same connection. + +For the source port, this works correctly: + keys->ports.src = port; + +But for the destination port, the assignment is reversed: + port = keys->ports.dst; + +This means the NAT destination port is never updated in the flow keys. +As a result, when multiple connections are NATed to the same destination, +CAKE treats them as separate flows because the original (pre-NAT) +destination ports differ. This breaks CAKE's NAT-aware flow isolation +when using the "nat" mode. + +The bug was introduced in commit b0c19ed6088a ("sch_cake: Take advantage +of skb->hash where appropriate") which refactored the original direct +assignment into a compare-and-conditionally-update pattern, but wrote +the destination port update backwards. + +Fix by reversing the assignment direction to match the source port +pattern. + +Fixes: b0c19ed6088a ("sch_cake: Take advantage of skb->hash where appropriate") +Signed-off-by: Dudu Lu +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260413110041.44704-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 8024b6503cd9a..ee8d662db747c 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -603,7 +603,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys, + } + port = rev ? tuple.src.u.all : tuple.dst.u.all; + if (port != keys->ports.dst) { +- port = keys->ports.dst; ++ keys->ports.dst = port; + upd = true; + } + } +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch b/queue-6.12/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch new file mode 100644 index 0000000000..58d9973ff7 --- /dev/null +++ b/queue-6.12/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch @@ -0,0 +1,97 @@ +From 674201b07cf1987bd1c1caed6e930f0d393f8338 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:28:39 +0000 +Subject: net/sched: sch_choke: annotate data-races in choke_dump_stats() + +From: Eric Dumazet + +[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ] + +choke_dump_stats() only runs with RTNL held. +It reads fields that can be changed in qdisc fast path. +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423062839.2524324-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index 757b89292e7e6..87d92b2a74441 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + /* Draw a packet at random from queue and compare flow */ + if (choke_match_random(q, skb, &idx)) { +- q->stats.matched++; ++ WRITE_ONCE(q->stats.matched, q->stats.matched + 1); + choke_drop_by_idx(sch, idx, to_free); + goto congestion_drop; + } +@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + qdisc_qstats_overlimit(sch); + if (use_harddrop(q) || !use_ecn(q) || + !INET_ECN_set_ce(skb)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + } else if (++q->vars.qcount) { + if (red_mark_probability(p, &q->vars, q->vars.qavg)) { + q->vars.qcount = 0; +@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + qdisc_qstats_overlimit(sch); + if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + } + } else + q->vars.qR = red_random(p); +@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + } + +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); + return qdisc_drop(skb, sch, to_free); + + congestion_drop: +@@ -461,10 +465,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct choke_sched_data *q = qdisc_priv(sch); + struct tc_choke_xstats st = { +- .early = q->stats.prob_drop + q->stats.forced_drop, +- .marked = q->stats.prob_mark + q->stats.forced_mark, +- .pdrop = q->stats.pdrop, +- .matched = q->stats.matched, ++ .early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop), ++ .marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark), ++ .pdrop = READ_ONCE(q->stats.pdrop), ++ .matched = READ_ONCE(q->stats.matched), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch b/queue-6.12/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch new file mode 100644 index 0000000000..88e1e6aa92 --- /dev/null +++ b/queue-6.12/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch @@ -0,0 +1,47 @@ +From aa005da482d27b8bd1fc92953a02af050f2d05b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:25:09 +0000 +Subject: net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats() + +From: Eric Dumazet + +[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill st.qdisc_stats with live data. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142509.3967231-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_codel.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 551b7cbdae90c..3f797ec4b0c2f 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -581,6 +581,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + }; + struct list_head *pos; + ++ sch_tree_lock(sch); ++ + st.qdisc_stats.maxpacket = q->cstats.maxpacket; + st.qdisc_stats.drop_overlimit = q->drop_overlimit; + st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; +@@ -589,7 +591,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + st.qdisc_stats.memory_usage = q->memory_usage; + st.qdisc_stats.drop_overmemory = q->drop_overmemory; + +- sch_tree_lock(sch); + list_for_each(pos, &q->new_flows) + st.qdisc_stats.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch b/queue-6.12/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch new file mode 100644 index 0000000000..c94f4f65eb --- /dev/null +++ b/queue-6.12/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch @@ -0,0 +1,62 @@ +From 18866340aa471286e9c4966c374dd20143ae85c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:35:27 +0000 +Subject: net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill tc_fq_pie_xstats with live data. + +Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, +but the spinlock is needed anyway to scan q->new_flows and q->old_flows. + +Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423063527.2568262-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_pie.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index 6ed08b705f8a5..ceba154656624 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -506,18 +506,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb) + static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct fq_pie_sched_data *q = qdisc_priv(sch); +- struct tc_fq_pie_xstats st = { +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .overmemory = q->overmemory, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, +- .new_flow_count = q->new_flow_count, +- .memory_usage = q->memory_usage, +- }; ++ struct tc_fq_pie_xstats st = { 0 }; + struct list_head *pos; + + sch_tree_lock(sch); ++ ++ st.packets_in = q->stats.packets_in; ++ st.overlimit = q->stats.overlimit; ++ st.overmemory = q->overmemory; ++ st.dropped = q->stats.dropped; ++ st.ecn_mark = q->stats.ecn_mark; ++ st.new_flow_count = q->new_flow_count; ++ st.memory_usage = q->memory_usage; ++ + list_for_each(pos, &q->new_flows) + st.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch b/queue-6.12/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch new file mode 100644 index 0000000000..a35bd98627 --- /dev/null +++ b/queue-6.12/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch @@ -0,0 +1,160 @@ +From c3d451deb1c1849f07277619641e1777afc3682f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:29:44 +0000 +Subject: net/sched: sch_pie: annotate data-races in pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ] + +pie_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_pie_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142944.4009941-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/pie.h | 2 +- + net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/include/net/pie.h b/include/net/pie.h +index 01cbc66825a40..1f3db0c355149 100644 +--- a/include/net/pie.h ++++ b/include/net/pie.h +@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) + vars->dq_tstamp = DTIME_INVALID; + vars->accu_prob = 0; + vars->dq_count = DQCOUNT_INVALID; +- vars->avg_dq_rate = 0; ++ WRITE_ONCE(vars->avg_dq_rate, 0); + } + + static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb) +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index db61cbc21b138..abb8cdb409c48 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -89,7 +89,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + bool enqueue = false; + + if (unlikely(qdisc_qlen(sch) >= sch->limit)) { +- q->stats.overlimit++; ++ WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1); + goto out; + } + +@@ -101,7 +101,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + /* If packet is ecn capable, mark it if drop probability + * is lower than 10%, else drop it. + */ +- q->stats.ecn_mark++; ++ WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1); + enqueue = true; + } + +@@ -111,15 +111,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + if (!q->params.dq_rate_estimator) + pie_set_enqueue_time(skb); + +- q->stats.packets_in++; ++ WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1); + if (qdisc_qlen(sch) > q->stats.maxq) +- q->stats.maxq = qdisc_qlen(sch); ++ WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch)); + + return qdisc_enqueue_tail(skb, sch); + } + + out: +- q->stats.dropped++; ++ WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1); + q->vars.accu_prob = 0; + return qdisc_drop(skb, sch, to_free); + } +@@ -262,11 +262,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, + count = count / dtime; + + if (vars->avg_dq_rate == 0) +- vars->avg_dq_rate = count; ++ WRITE_ONCE(vars->avg_dq_rate, count); + else +- vars->avg_dq_rate = ++ WRITE_ONCE(vars->avg_dq_rate, + (vars->avg_dq_rate - +- (vars->avg_dq_rate >> 3)) + (count >> 3); ++ (vars->avg_dq_rate >> 3)) + (count >> 3)); + + /* If the queue has receded below the threshold, we hold + * on to the last drain rate calculated, else we reset +@@ -376,7 +376,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + if (delta > 0) { + /* prevent overflow */ + if (vars->prob < oldprob) { +- vars->prob = MAX_PROB; ++ WRITE_ONCE(vars->prob, MAX_PROB); + /* Prevent normalization error. If probability is at + * maximum value already, we normalize it here, and + * skip the check to do a non-linear drop in the next +@@ -387,7 +387,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + } else { + /* prevent underflow */ + if (vars->prob > oldprob) +- vars->prob = 0; ++ WRITE_ONCE(vars->prob, 0); + } + + /* Non-linear drop in probability: Reduce drop probability quickly if +@@ -398,7 +398,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + /* Reduce drop probability to 98.4% */ + vars->prob -= vars->prob / 64; + +- vars->qdelay = qdelay; ++ WRITE_ONCE(vars->qdelay, qdelay); + vars->backlog_old = backlog; + + /* We restart the measurement cycle if the following conditions are met +@@ -497,21 +497,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + struct pie_sched_data *q = qdisc_priv(sch); + struct tc_pie_xstats st = { + .prob = q->vars.prob << BITS_PER_BYTE, +- .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / ++ .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) / + NSEC_PER_USEC, +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .maxq = q->stats.maxq, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, ++ .packets_in = READ_ONCE(q->stats.packets_in), ++ .overlimit = READ_ONCE(q->stats.overlimit), ++ .maxq = READ_ONCE(q->stats.maxq), ++ .dropped = READ_ONCE(q->stats.dropped), ++ .ecn_mark = READ_ONCE(q->stats.ecn_mark), + }; + + /* avg_dq_rate is only valid if dq_rate_estimator is enabled */ + st.dq_rate_estimating = q->params.dq_rate_estimator; + + /* unscale and return dq_rate in bytes per sec */ +- if (q->params.dq_rate_estimator) +- st.avg_dq_rate = q->vars.avg_dq_rate * ++ if (st.dq_rate_estimating) ++ st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) * + (PSCHED_TICKS_PER_SEC) >> PIE_SCALE; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch b/queue-6.12/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch new file mode 100644 index 0000000000..6c7e0fc4a5 --- /dev/null +++ b/queue-6.12/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch @@ -0,0 +1,112 @@ +From 06d60506898ebcb4ddfd506f7bec69525b2c8d85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:23:09 +0000 +Subject: net/sched: sch_red: annotate data-races in red_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ] + +red_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_red_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142309.3964322-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_red.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index a745d429a8141..6f53a0dbd0572 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -89,17 +89,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_PROB_MARK: + qdisc_qstats_overlimit(sch); + if (!red_use_ecn(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +@@ -109,17 +112,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_HARD_MARK: + qdisc_qstats_overlimit(sch); + if (red_use_harddrop(q) || !red_use_ecn(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +@@ -133,7 +139,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->qstats.backlog += len; + sch->q.qlen++; + } else if (net_xmit_drop_count(ret)) { +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, ++ q->stats.pdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -461,9 +468,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, + &hw_stats_request); + } +- st.early = q->stats.prob_drop + q->stats.forced_drop; +- st.pdrop = q->stats.pdrop; +- st.marked = q->stats.prob_mark + q->stats.forced_mark; ++ st.early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop); ++ ++ st.pdrop = READ_ONCE(q->stats.pdrop); ++ ++ st.marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark); + + return gnet_stats_copy_app(d, &st, sizeof(st)); + } +-- +2.53.0 + diff --git a/queue-6.12/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch b/queue-6.12/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch new file mode 100644 index 0000000000..03a867b3cc --- /dev/null +++ b/queue-6.12/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch @@ -0,0 +1,169 @@ +From ada1e56c649406071113fb06535980b6e91b83a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:16:55 +0000 +Subject: net/sched: sch_sfb: annotate data-races in sfb_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ] + +sfb_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_sfb_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260421141655.3953721-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 22 deletions(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index b717e15a3a17b..c36725f0870d4 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen < 0xFFFF) +- b[hash].qlen++; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen > 0) +- b[hash].qlen--; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) + + static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_minus(b->p_mark, q->decrement); ++ WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement)); + } + + static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_plus(b->p_mark, q->increment); ++ WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment)); + } + + static void sfb_zero_all_buckets(struct sfb_sched_data *q) +@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da + const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0]; + + for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) { +- if (qlen < b->qlen) +- qlen = b->qlen; +- totalpm += b->p_mark; +- if (prob < b->p_mark) +- prob = b->p_mark; ++ u32 b_qlen = READ_ONCE(b->qlen); ++ u32 b_mark = READ_ONCE(b->p_mark); ++ ++ if (qlen < b_qlen) ++ qlen = b_qlen; ++ totalpm += b_mark; ++ if (prob < b_mark) ++ prob = b_mark; + b++; + } + *prob_r = prob; +@@ -294,7 +297,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(sch->q.qlen >= q->limit)) { + qdisc_qstats_overlimit(sch); +- q->stats.queuedrop++; ++ WRITE_ONCE(q->stats.queuedrop, ++ q->stats.queuedrop + 1); + goto drop; + } + +@@ -347,7 +351,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(minqlen >= q->max)) { + qdisc_qstats_overlimit(sch); +- q->stats.bucketdrop++; ++ WRITE_ONCE(q->stats.bucketdrop, ++ q->stats.bucketdrop + 1); + goto drop; + } + +@@ -373,7 +378,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + if (sfb_rate_limit(skb, q)) { + qdisc_qstats_overlimit(sch); +- q->stats.penaltydrop++; ++ WRITE_ONCE(q->stats.penaltydrop, ++ q->stats.penaltydrop + 1); + goto drop; + } + goto enqueue; +@@ -388,14 +394,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + * In either case, we want to start dropping packets. + */ + if (r < (p_min - SFB_MAX_PROB / 2) * 2) { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } + if (INET_ECN_set_ce(skb)) { +- q->stats.marked++; ++ WRITE_ONCE(q->stats.marked, ++ q->stats.marked + 1); + } else { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } +@@ -408,7 +417,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->q.qlen++; + increment_qlen(&cb, q); + } else if (net_xmit_drop_count(ret)) { +- q->stats.childdrop++; ++ WRITE_ONCE(q->stats.childdrop, ++ q->stats.childdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -597,12 +607,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct sfb_sched_data *q = qdisc_priv(sch); + struct tc_sfb_xstats st = { +- .earlydrop = q->stats.earlydrop, +- .penaltydrop = q->stats.penaltydrop, +- .bucketdrop = q->stats.bucketdrop, +- .queuedrop = q->stats.queuedrop, +- .childdrop = q->stats.childdrop, +- .marked = q->stats.marked, ++ .earlydrop = READ_ONCE(q->stats.earlydrop), ++ .penaltydrop = READ_ONCE(q->stats.penaltydrop), ++ .bucketdrop = READ_ONCE(q->stats.bucketdrop), ++ .queuedrop = READ_ONCE(q->stats.queuedrop), ++ .childdrop = READ_ONCE(q->stats.childdrop), ++ .marked = READ_ONCE(q->stats.marked), + }; + + st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q); +-- +2.53.0 + diff --git a/queue-6.12/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch b/queue-6.12/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch new file mode 100644 index 0000000000..1fdef2bc93 --- /dev/null +++ b/queue-6.12/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch @@ -0,0 +1,123 @@ +From 55a2b9b8850f9db5ca029b797544a3b9fba48c61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:19:58 +0800 +Subject: net/sched: taprio: fix NULL pointer dereference in class dump + +From: Weiming Shi + +[ Upstream commit 3d07ca5c0fae311226f737963984bd94bb159a87 ] + +When a TAPRIO child qdisc is deleted via RTM_DELQDISC, taprio_graft() +is called with new == NULL and stores NULL into q->qdiscs[cl - 1]. +Subsequent RTM_GETTCLASS dump operations walk all classes via +taprio_walk() and call taprio_dump_class(), which calls taprio_leaf() +returning the NULL pointer, then dereferences it to read child->handle, +causing a kernel NULL pointer dereference. + +The bug is reachable with namespace-scoped CAP_NET_ADMIN on any kernel +with CONFIG_NET_SCH_TAPRIO enabled. On systems with unprivileged user +namespaces enabled, an unprivileged local user can trigger a kernel +panic by creating a taprio qdisc inside a new network namespace, +grafting an explicit child qdisc, deleting it, and requesting a class +dump. The RTM_GETTCLASS dump itself requires no capability. + + Oops: general protection fault, probably for non-canonical address 0xdffffc0000000007: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f] + RIP: 0010:taprio_dump_class (net/sched/sch_taprio.c:2478) + Call Trace: + + tc_fill_tclass (net/sched/sch_api.c:1966) + qdisc_class_dump (net/sched/sch_api.c:2326) + taprio_walk (net/sched/sch_taprio.c:2514) + tc_dump_tclass_qdisc (net/sched/sch_api.c:2352) + tc_dump_tclass_root (net/sched/sch_api.c:2370) + tc_dump_tclass (net/sched/sch_api.c:2431) + rtnl_dumpit (net/core/rtnetlink.c:6864) + netlink_dump (net/netlink/af_netlink.c:2325) + rtnetlink_rcv_msg (net/core/rtnetlink.c:6959) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Fix this by substituting &noop_qdisc when new is NULL in +taprio_graft(), a common pattern used by other qdiscs (e.g., +multiq_graft()) to ensure the q->qdiscs[] slots are never NULL. +This makes control-plane dump paths safe without requiring individual +NULL checks. + +Since the data-plane paths (taprio_enqueue and taprio_dequeue_from_txq) +previously had explicit NULL guards that would drop/skip the packet +cleanly, update those checks to test for &noop_qdisc instead. Without +this, packets would reach taprio_enqueue_one() which increments the root +qdisc's qlen and backlog before calling the child's enqueue; noop_qdisc +drops the packet but those counters are never rolled back, permanently +inflating the root qdisc's statistics. + +After this change *old can be a valid qdisc, NULL, or &noop_qdisc. +Only call qdisc_put(*old) in the first case to avoid decreasing +noop_qdisc's refcount, which was never increased. + +Fixes: 665338b2a7a0 ("net/sched: taprio: dump class stats for the actual q->qdiscs[]") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Acked-by: Jamal Hadi Salim +Tested-by: Weiming Shi +Link: https://patch.msgid.link/20260422161958.2517539-3-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 366eb7627b30d..f1709efb5f04e 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -633,7 +633,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + queue = skb_get_queue_mapping(skb); + + child = q->qdiscs[queue]; +- if (unlikely(!child)) ++ if (unlikely(child == &noop_qdisc)) + return qdisc_drop(skb, sch, to_free); + + if (taprio_skb_exceeds_queue_max_sdu(sch, skb)) { +@@ -716,7 +716,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, + int len; + u8 tc; + +- if (unlikely(!child)) ++ if (unlikely(child == &noop_qdisc)) + return NULL; + + if (TXTIME_ASSIST_IS_ENABLED(q->flags)) +@@ -2191,6 +2191,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + if (!dev_queue) + return -EINVAL; + ++ if (!new) ++ new = &noop_qdisc; ++ + if (dev->flags & IFF_UP) + dev_deactivate(dev); + +@@ -2204,14 +2207,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + *old = q->qdiscs[cl - 1]; + if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { + WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old); +- if (new) ++ if (new != &noop_qdisc) + qdisc_refcount_inc(new); +- if (*old) ++ if (*old && *old != &noop_qdisc) + qdisc_put(*old); + } + + q->qdiscs[cl - 1] = new; +- if (new) ++ if (new != &noop_qdisc) + new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; + + if (dev->flags & IFF_UP) +-- +2.53.0 + diff --git a/queue-6.12/net-sched-taprio-fix-use-after-free-in-advance_sched.patch b/queue-6.12/net-sched-taprio-fix-use-after-free-in-advance_sched.patch new file mode 100644 index 0000000000..e301a3b9a3 --- /dev/null +++ b/queue-6.12/net-sched-taprio-fix-use-after-free-in-advance_sched.patch @@ -0,0 +1,60 @@ +From 2a1845cf0e3be2069979ba28c57b6a3c0b0d3dc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 18:57:57 -0700 +Subject: net/sched: taprio: fix use-after-free in advance_sched() on schedule + switch + +From: Vinicius Costa Gomes + +[ Upstream commit 105425b1969c5affe532713cfac1c0b320d7ac2b ] + +In advance_sched(), when should_change_schedules() returns true, +switch_schedules() is called to promote the admin schedule to oper. +switch_schedules() queues the old oper schedule for RCU freeing via +call_rcu(), but 'next' still points into an entry of the old oper +schedule. The subsequent 'next->end_time = end_time' and +rcu_assign_pointer(q->current_entry, next) are use-after-free. + +Fix this by selecting 'next' from the new oper schedule immediately +after switch_schedules(), and using its pre-calculated end_time. +setup_first_end_time() sets the first entry's end_time to +base_time + interval when the schedule is installed, so the value +is already correct. + +The deleted 'end_time = sched_base_time(admin)' assignment was also +harmful independently: it would overwrite the new first entry's +pre-calculated end_time with just base_time. + +Fixes: a3d43c0d56f1 ("taprio: Add support adding an admin schedule") +Reported-by: Junxi Qian +Signed-off-by: Vinicius Costa Gomes +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 1620f0fd78ce7..366eb7627b30d 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -971,11 +971,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + } + + if (should_change_schedules(admin, oper, end_time)) { +- /* Set things so the next time this runs, the new +- * schedule runs. +- */ +- end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); ++ /* After changing schedules, the next entry is the first one ++ * in the new schedule, with a pre-calculated end_time. ++ */ ++ next = list_first_entry(&oper->entries, struct sched_entry, list); ++ end_time = next->end_time; + } + + next->end_time = end_time; +-- +2.53.0 + diff --git a/queue-6.12/net-socket.c-switch-to-class-fd.patch b/queue-6.12/net-socket.c-switch-to-class-fd.patch new file mode 100644 index 0000000000..c9e6addbe3 --- /dev/null +++ b/queue-6.12/net-socket.c-switch-to-class-fd.patch @@ -0,0 +1,602 @@ +From 6f5e6c7f226dd50a70855b5840df5bed45610341 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 May 2024 23:32:20 -0400 +Subject: net/socket.c: switch to CLASS(fd) + +From: Al Viro + +[ Upstream commit 53c0a58beb60b76e105a61aae518fd780eec03d9 ] + + The important part in sockfd_lookup_light() is avoiding needless +file refcount operations, not the marginal reduction of the register +pressure from not keeping a struct file pointer in the caller. + + Switch to use fdget()/fdpu(); with sane use of CLASS(fd) we can +get a better code generation... + + Would be nice if somebody tested it on networking test suites +(including benchmarks)... + + sockfd_lookup_light() does fdget(), uses sock_from_file() to +get the associated socket and returns the struct socket reference to +the caller, along with "do we need to fput()" flag. No matching fdput(), +the caller does its equivalent manually, using the fact that sock->file +points to the struct file the socket has come from. + + Get rid of that - have the callers do fdget()/fdput() and +use sock_from_file() directly. That kills sockfd_lookup_light() +and fput_light() (no users left). + + What's more, we can get rid of explicit fdget()/fdput() by +switching to CLASS(fd, ...) - code generation does not suffer, since +now fdput() inserted on "descriptor is not opened" failure exit +is recognized to be a no-op by compiler. + +[folded a fix for braino in do_recvmmsg() caught by Simon Horman] + +Reviewed-by: Christian Brauner +Signed-off-by: Al Viro +Stable-dep-of: 66052a768d47 ("fanotify: call fanotify_events_supported() before path_permission() and security_path_notify()") +Signed-off-by: Sasha Levin +--- + include/linux/file.h | 6 - + net/socket.c | 303 +++++++++++++++++++------------------------ + 2 files changed, 137 insertions(+), 172 deletions(-) + +diff --git a/include/linux/file.h b/include/linux/file.h +index f98de143245ab..b49a92295b3ff 100644 +--- a/include/linux/file.h ++++ b/include/linux/file.h +@@ -30,12 +30,6 @@ extern struct file *alloc_file_pseudo_noaccount(struct inode *, struct vfsmount + extern struct file *alloc_file_clone(struct file *, int flags, + const struct file_operations *); + +-static inline void fput_light(struct file *file, int fput_needed) +-{ +- if (fput_needed) +- fput(file); +-} +- + /* either a reference to struct file + flags + * (cloned vs. borrowed, pos locked), with + * flags stored in lower bits of value, +diff --git a/net/socket.c b/net/socket.c +index a0f6f8b3376d5..878155076bc0f 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -509,7 +509,7 @@ static int sock_map_fd(struct socket *sock, int flags) + + struct socket *sock_from_file(struct file *file) + { +- if (file->f_op == &socket_file_ops) ++ if (likely(file->f_op == &socket_file_ops)) + return file->private_data; /* set in sock_alloc_file */ + + return NULL; +@@ -549,24 +549,6 @@ struct socket *sockfd_lookup(int fd, int *err) + } + EXPORT_SYMBOL(sockfd_lookup); + +-static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) +-{ +- struct fd f = fdget(fd); +- struct socket *sock; +- +- *err = -EBADF; +- if (fd_file(f)) { +- sock = sock_from_file(fd_file(f)); +- if (likely(sock)) { +- *fput_needed = f.word & FDPUT_FPUT; +- return sock; +- } +- *err = -ENOTSOCK; +- fdput(f); +- } +- return NULL; +-} +- + static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, + size_t size) + { +@@ -1857,16 +1839,20 @@ int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) + { + struct socket *sock; + struct sockaddr_storage address; +- int err, fput_needed; +- +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (sock) { +- err = move_addr_to_kernel(umyaddr, addrlen, &address); +- if (!err) +- err = __sys_bind_socket(sock, &address, addrlen); +- fput_light(sock->file, fput_needed); +- } +- return err; ++ CLASS(fd, f)(fd); ++ int err; ++ ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; ++ ++ err = move_addr_to_kernel(umyaddr, addrlen, &address); ++ if (unlikely(err)) ++ return err; ++ ++ return __sys_bind_socket(sock, &address, addrlen); + } + + SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) +@@ -1895,15 +1881,16 @@ int __sys_listen_socket(struct socket *sock, int backlog) + + int __sys_listen(int fd, int backlog) + { ++ CLASS(fd, f)(fd); + struct socket *sock; +- int err, fput_needed; + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (sock) { +- err = __sys_listen_socket(sock, backlog); +- fput_light(sock->file, fput_needed); +- } +- return err; ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; ++ ++ return __sys_listen_socket(sock, backlog); + } + + SYSCALL_DEFINE2(listen, int, fd, int, backlog) +@@ -2013,17 +2000,12 @@ static int __sys_accept4_file(struct file *file, struct sockaddr __user *upeer_s + int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, + int __user *upeer_addrlen, int flags) + { +- int ret = -EBADF; +- struct fd f; ++ CLASS(fd, f)(fd); + +- f = fdget(fd); +- if (fd_file(f)) { +- ret = __sys_accept4_file(fd_file(f), upeer_sockaddr, ++ if (fd_empty(f)) ++ return -EBADF; ++ return __sys_accept4_file(fd_file(f), upeer_sockaddr, + upeer_addrlen, flags); +- fdput(f); +- } +- +- return ret; + } + + SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, +@@ -2075,20 +2057,18 @@ int __sys_connect_file(struct file *file, struct sockaddr_storage *address, + + int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) + { +- int ret = -EBADF; +- struct fd f; ++ struct sockaddr_storage address; ++ CLASS(fd, f)(fd); ++ int ret; + +- f = fdget(fd); +- if (fd_file(f)) { +- struct sockaddr_storage address; ++ if (fd_empty(f)) ++ return -EBADF; + +- ret = move_addr_to_kernel(uservaddr, addrlen, &address); +- if (!ret) +- ret = __sys_connect_file(fd_file(f), &address, addrlen, 0); +- fdput(f); +- } ++ ret = move_addr_to_kernel(uservaddr, addrlen, &address); ++ if (ret) ++ return ret; + +- return ret; ++ return __sys_connect_file(fd_file(f), &address, addrlen, 0); + } + + SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, +@@ -2107,26 +2087,25 @@ int __sys_getsockname(int fd, struct sockaddr __user *usockaddr, + { + struct socket *sock; + struct sockaddr_storage address; +- int err, fput_needed; ++ CLASS(fd, f)(fd); ++ int err; + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- goto out; ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + + err = security_socket_getsockname(sock); + if (err) +- goto out_put; ++ return err; + + err = READ_ONCE(sock->ops)->getname(sock, (struct sockaddr *)&address, 0); + if (err < 0) +- goto out_put; +- /* "err" is actually length in this case */ +- err = move_addr_to_user(&address, err, usockaddr, usockaddr_len); ++ return err; + +-out_put: +- fput_light(sock->file, fput_needed); +-out: +- return err; ++ /* "err" is actually length in this case */ ++ return move_addr_to_user(&address, err, usockaddr, usockaddr_len); + } + + SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, +@@ -2145,26 +2124,25 @@ int __sys_getpeername(int fd, struct sockaddr __user *usockaddr, + { + struct socket *sock; + struct sockaddr_storage address; +- int err, fput_needed; ++ CLASS(fd, f)(fd); ++ int err; + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (sock != NULL) { +- const struct proto_ops *ops = READ_ONCE(sock->ops); ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + +- err = security_socket_getpeername(sock); +- if (err) { +- fput_light(sock->file, fput_needed); +- return err; +- } ++ err = security_socket_getpeername(sock); ++ if (err) ++ return err; + +- err = ops->getname(sock, (struct sockaddr *)&address, 1); +- if (err >= 0) +- /* "err" is actually length in this case */ +- err = move_addr_to_user(&address, err, usockaddr, +- usockaddr_len); +- fput_light(sock->file, fput_needed); +- } +- return err; ++ err = READ_ONCE(sock->ops)->getname(sock, (struct sockaddr *)&address, 1); ++ if (err < 0) ++ return err; ++ ++ /* "err" is actually length in this case */ ++ return move_addr_to_user(&address, err, usockaddr, usockaddr_len); + } + + SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, +@@ -2185,14 +2163,17 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, + struct sockaddr_storage address; + int err; + struct msghdr msg; +- int fput_needed; + + err = import_ubuf(ITER_SOURCE, buff, len, &msg.msg_iter); + if (unlikely(err)) + return err; +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- goto out; ++ ++ CLASS(fd, f)(fd); ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + + msg.msg_name = NULL; + msg.msg_control = NULL; +@@ -2202,7 +2183,7 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, + if (addr) { + err = move_addr_to_kernel(addr, addr_len, &address); + if (err < 0) +- goto out_put; ++ return err; + msg.msg_name = (struct sockaddr *)&address; + msg.msg_namelen = addr_len; + } +@@ -2210,12 +2191,7 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + msg.msg_flags = flags; +- err = __sock_sendmsg(sock, &msg); +- +-out_put: +- fput_light(sock->file, fput_needed); +-out: +- return err; ++ return __sock_sendmsg(sock, &msg); + } + + SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, +@@ -2250,14 +2226,18 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags, + }; + struct socket *sock; + int err, err2; +- int fput_needed; + + err = import_ubuf(ITER_DEST, ubuf, size, &msg.msg_iter); + if (unlikely(err)) + return err; +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- goto out; ++ ++ CLASS(fd, f)(fd); ++ ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; +@@ -2269,9 +2249,6 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags, + if (err2 < 0) + err = err2; + } +- +- fput_light(sock->file, fput_needed); +-out: + return err; + } + +@@ -2346,17 +2323,16 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval, + { + sockptr_t optval = USER_SOCKPTR(user_optval); + bool compat = in_compat_syscall(); +- int err, fput_needed; + struct socket *sock; ++ CLASS(fd, f)(fd); + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- return err; +- +- err = do_sock_setsockopt(sock, compat, level, optname, optval, optlen); ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + +- fput_light(sock->file, fput_needed); +- return err; ++ return do_sock_setsockopt(sock, compat, level, optname, optval, optlen); + } + + SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, +@@ -2412,20 +2388,17 @@ EXPORT_SYMBOL(do_sock_getsockopt); + int __sys_getsockopt(int fd, int level, int optname, char __user *optval, + int __user *optlen) + { +- int err, fput_needed; + struct socket *sock; +- bool compat; ++ CLASS(fd, f)(fd); + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- return err; ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + +- compat = in_compat_syscall(); +- err = do_sock_getsockopt(sock, compat, level, optname, ++ return do_sock_getsockopt(sock, in_compat_syscall(), level, optname, + USER_SOCKPTR(optval), USER_SOCKPTR(optlen)); +- +- fput_light(sock->file, fput_needed); +- return err; + } + + SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, +@@ -2451,15 +2424,16 @@ int __sys_shutdown_sock(struct socket *sock, int how) + + int __sys_shutdown(int fd, int how) + { +- int err, fput_needed; + struct socket *sock; ++ CLASS(fd, f)(fd); + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (sock != NULL) { +- err = __sys_shutdown_sock(sock, how); +- fput_light(sock->file, fput_needed); +- } +- return err; ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; ++ ++ return __sys_shutdown_sock(sock, how); + } + + SYSCALL_DEFINE2(shutdown, int, fd, int, how) +@@ -2675,22 +2649,21 @@ long __sys_sendmsg_sock(struct socket *sock, struct msghdr *msg, + long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, + bool forbid_cmsg_compat) + { +- int fput_needed, err; + struct msghdr msg_sys; + struct socket *sock; + + if (forbid_cmsg_compat && (flags & MSG_CMSG_COMPAT)) + return -EINVAL; + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- goto out; ++ CLASS(fd, f)(fd); + +- err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, 0); ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + +- fput_light(sock->file, fput_needed); +-out: +- return err; ++ return ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, 0); + } + + SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags) +@@ -2705,7 +2678,7 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int + int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, + unsigned int flags, bool forbid_cmsg_compat) + { +- int fput_needed, err, datagrams; ++ int err, datagrams; + struct socket *sock; + struct mmsghdr __user *entry; + struct compat_mmsghdr __user *compat_entry; +@@ -2721,9 +2694,13 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, + + datagrams = 0; + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- return err; ++ CLASS(fd, f)(fd); ++ ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + + used_address.name_len = UINT_MAX; + entry = mmsg; +@@ -2760,8 +2737,6 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, + cond_resched(); + } + +- fput_light(sock->file, fput_needed); +- + /* We only return an error if no datagrams were able to be sent */ + if (datagrams != 0) + return datagrams; +@@ -2883,22 +2858,21 @@ long __sys_recvmsg_sock(struct socket *sock, struct msghdr *msg, + long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, + bool forbid_cmsg_compat) + { +- int fput_needed, err; + struct msghdr msg_sys; + struct socket *sock; + + if (forbid_cmsg_compat && (flags & MSG_CMSG_COMPAT)) + return -EINVAL; + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- goto out; ++ CLASS(fd, f)(fd); + +- err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0); ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + +- fput_light(sock->file, fput_needed); +-out: +- return err; ++ return ___sys_recvmsg(sock, msg, &msg_sys, flags, 0); + } + + SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg, +@@ -2915,7 +2889,7 @@ static int do_recvmmsg(int fd, struct mmsghdr __user *mmsg, + unsigned int vlen, unsigned int flags, + struct timespec64 *timeout) + { +- int fput_needed, err, datagrams; ++ int err = 0, datagrams; + struct socket *sock; + struct mmsghdr __user *entry; + struct compat_mmsghdr __user *compat_entry; +@@ -2930,16 +2904,18 @@ static int do_recvmmsg(int fd, struct mmsghdr __user *mmsg, + + datagrams = 0; + +- sock = sockfd_lookup_light(fd, &err, &fput_needed); +- if (!sock) +- return err; ++ CLASS(fd, f)(fd); ++ ++ if (fd_empty(f)) ++ return -EBADF; ++ sock = sock_from_file(fd_file(f)); ++ if (unlikely(!sock)) ++ return -ENOTSOCK; + + if (likely(!(flags & MSG_ERRQUEUE))) { + err = sock_error(sock->sk); +- if (err) { +- datagrams = err; +- goto out_put; +- } ++ if (err) ++ return err; + } + + entry = mmsg; +@@ -2996,12 +2972,10 @@ static int do_recvmmsg(int fd, struct mmsghdr __user *mmsg, + } + + if (err == 0) +- goto out_put; ++ return datagrams; + +- if (datagrams == 0) { +- datagrams = err; +- goto out_put; +- } ++ if (datagrams == 0) ++ return err; + + /* + * We may return less entries than requested (vlen) if the +@@ -3016,9 +2990,6 @@ static int do_recvmmsg(int fd, struct mmsghdr __user *mmsg, + */ + WRITE_ONCE(sock->sk->sk_err, -err); + } +-out_put: +- fput_light(sock->file, fput_needed); +- + return datagrams; + } + +-- +2.53.0 + diff --git a/queue-6.12/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch b/queue-6.12/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch new file mode 100644 index 0000000000..1656658ad7 --- /dev/null +++ b/queue-6.12/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch @@ -0,0 +1,90 @@ +From 4016b53562df21689a9cef3b7c43261b8e3bed08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:15:59 -0700 +Subject: net: tls: fix strparser anchor skb leak on offload RX setup failure + +From: Jakub Kicinski + +[ Upstream commit 58689498ca3384851145a754dbb1d8ed1cf9fb54 ] + +When tls_set_device_offload_rx() fails at tls_dev_add(), the error path +calls tls_sw_free_resources_rx() to clean up the SW context that was +initialized by tls_set_sw_offload(). This function calls +tls_sw_release_resources_rx() (which stops the strparser via +tls_strp_stop()) and tls_sw_free_ctx_rx() (which kfrees the context), +but never frees the anchor skb that was allocated by alloc_skb(0) in +tls_strp_init(). + +Note that tls_sw_free_resources_rx() is exclusively used for this +"failed to start offload" code path, there's no other caller. + +The leak did not exist before commit 84c61fe1a75b ("tls: rx: do not use +the standard strparser"), because the standard strparser doesn't try +to pre-allocate an skb. + +The normal close path in tls_sk_proto_close() handles cleanup by calling +tls_sw_strparser_done() (which calls tls_strp_done()) after dropping +the socket lock, because tls_strp_done() does cancel_work_sync() and +the strparser work handler takes the socket lock. + +Fixes: 84c61fe1a75b ("tls: rx: do not use the standard strparser") +Signed-off-by: Jakub Kicinski +Reviewed-by: Vadim Fedorenko +Link: https://patch.msgid.link/20260428231559.1358502-1-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls.h | 1 + + net/tls/tls_strp.c | 6 ++++++ + net/tls/tls_sw.c | 4 ++++ + 3 files changed, 11 insertions(+) + +diff --git a/net/tls/tls.h b/net/tls/tls.h +index fca0c0e170047..97eba6f6ab653 100644 +--- a/net/tls/tls.h ++++ b/net/tls/tls.h +@@ -186,6 +186,7 @@ int tls_strp_dev_init(void); + void tls_strp_dev_exit(void); + + void tls_strp_done(struct tls_strparser *strp); ++void __tls_strp_done(struct tls_strparser *strp); + void tls_strp_stop(struct tls_strparser *strp); + int tls_strp_init(struct tls_strparser *strp, struct sock *sk); + void tls_strp_data_ready(struct tls_strparser *strp); +diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c +index 98e12f0ff57e5..c72e883176273 100644 +--- a/net/tls/tls_strp.c ++++ b/net/tls/tls_strp.c +@@ -624,6 +624,12 @@ void tls_strp_done(struct tls_strparser *strp) + WARN_ON(!strp->stopped); + + cancel_work_sync(&strp->work); ++ __tls_strp_done(strp); ++} ++ ++/* For setup error paths where the strparser was initialized but never armed. */ ++void __tls_strp_done(struct tls_strparser *strp) ++{ + tls_strp_anchor_free(strp); + } + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 36351942903b9..4550f15d052dc 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -2591,8 +2591,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx) + void tls_sw_free_resources_rx(struct sock *sk) + { + struct tls_context *tls_ctx = tls_get_ctx(sk); ++ struct tls_sw_context_rx *ctx; ++ ++ ctx = tls_sw_ctx_rx(tls_ctx); + + tls_sw_release_resources_rx(sk); ++ __tls_strp_done(&ctx->strp); + tls_sw_free_ctx_rx(tls_ctx); + } + +-- +2.53.0 + diff --git a/queue-6.12/net-treewide-define-and-use-mac_addr_str_len.patch b/queue-6.12/net-treewide-define-and-use-mac_addr_str_len.patch new file mode 100644 index 0000000000..f6142c9c97 --- /dev/null +++ b/queue-6.12/net-treewide-define-and-use-mac_addr_str_len.patch @@ -0,0 +1,133 @@ +From 41a5b5574b82ffc03bb60c5eb46ec4d15f01b854 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Mar 2025 13:51:46 -0600 +Subject: net, treewide: define and use MAC_ADDR_STR_LEN + +From: Uday Shankar + +[ Upstream commit 6d6c1ba7824022528dbe3e283fafbd0775424128 ] + +There are a few places in the tree which compute the length of the +string representation of a MAC address as 3 * ETH_ALEN - 1. Define a +constant for this and use it where relevant. No functionality changes +are expected. + +Signed-off-by: Uday Shankar +Reviewed-by: Michal Swiatkowski +Acked-by: Johannes Berg +Reviewed-by: Breno Leitao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20250312-netconsole-v6-1-3437933e79b8@purestorage.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 3bc179bc7146 ("netpoll: fix IPv6 local-address corruption") +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 2 +- + drivers/nvmem/brcm_nvram.c | 2 +- + drivers/nvmem/layouts/u-boot-env.c | 2 +- + include/linux/if_ether.h | 3 +++ + lib/net_utils.c | 4 +--- + net/mac80211/debugfs_sta.c | 7 ++++--- + 6 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 2f20f9ed3a0d8..4048d99b7c57d 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -652,7 +652,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf, + + if (!mac_pton(buf, remote_mac)) + goto out_unlock; +- if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') ++ if (buf[MAC_ADDR_STR_LEN] && buf[MAC_ADDR_STR_LEN] != '\n') + goto out_unlock; + memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); + +diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c +index 3d8c87835f4d6..65f458af3a195 100644 +--- a/drivers/nvmem/brcm_nvram.c ++++ b/drivers/nvmem/brcm_nvram.c +@@ -100,7 +100,7 @@ static int brcm_nvram_read_post_process_macaddr(void *context, const char *id, i + { + u8 mac[ETH_ALEN]; + +- if (bytes != 3 * ETH_ALEN - 1) ++ if (bytes != MAC_ADDR_STR_LEN) + return -EINVAL; + + if (!mac_pton(buf, mac)) +diff --git a/drivers/nvmem/layouts/u-boot-env.c b/drivers/nvmem/layouts/u-boot-env.c +index 21f6dcf905dd9..8571aac56295a 100644 +--- a/drivers/nvmem/layouts/u-boot-env.c ++++ b/drivers/nvmem/layouts/u-boot-env.c +@@ -37,7 +37,7 @@ static int u_boot_env_read_post_process_ethaddr(void *context, const char *id, i + { + u8 mac[ETH_ALEN]; + +- if (bytes != 3 * ETH_ALEN - 1) ++ if (bytes != MAC_ADDR_STR_LEN) + return -EINVAL; + + if (!mac_pton(buf, mac)) +diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h +index 47a0feffc1215..ca9afa824aa4f 100644 +--- a/include/linux/if_ether.h ++++ b/include/linux/if_ether.h +@@ -19,6 +19,9 @@ + #include + #include + ++/* XX:XX:XX:XX:XX:XX */ ++#define MAC_ADDR_STR_LEN (3 * ETH_ALEN - 1) ++ + static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) + { + return (struct ethhdr *)skb_mac_header(skb); +diff --git a/lib/net_utils.c b/lib/net_utils.c +index 42bb0473fb22f..215cda672fee1 100644 +--- a/lib/net_utils.c ++++ b/lib/net_utils.c +@@ -7,11 +7,9 @@ + + bool mac_pton(const char *s, u8 *mac) + { +- size_t maxlen = 3 * ETH_ALEN - 1; + int i; + +- /* XX:XX:XX:XX:XX:XX */ +- if (strnlen(s, maxlen) < maxlen) ++ if (strnlen(s, MAC_ADDR_STR_LEN) < MAC_ADDR_STR_LEN) + return false; + + /* Don't dirty result unless string is valid MAC. */ +diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c +index e6f937cfedcf6..3df6725ab00e7 100644 +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -454,11 +454,12 @@ static ssize_t link_sta_addr_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) + { + struct link_sta_info *link_sta = file->private_data; +- u8 mac[3 * ETH_ALEN + 1]; ++ u8 mac[MAC_ADDR_STR_LEN + 2]; + + snprintf(mac, sizeof(mac), "%pM\n", link_sta->pub->addr); + +- return simple_read_from_buffer(userbuf, count, ppos, mac, 3 * ETH_ALEN); ++ return simple_read_from_buffer(userbuf, count, ppos, mac, ++ MAC_ADDR_STR_LEN + 1); + } + + LINK_STA_OPS(addr); +@@ -1237,7 +1238,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; +- u8 mac[3*ETH_ALEN]; ++ u8 mac[MAC_ADDR_STR_LEN + 1]; + + if (!stations_dir) + return; +-- +2.53.0 + diff --git a/queue-6.12/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch b/queue-6.12/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch new file mode 100644 index 0000000000..50bd66fb34 --- /dev/null +++ b/queue-6.12/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch @@ -0,0 +1,89 @@ +From b69e21caef1af6b5c3daddec85bd1f26f35493a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 08:49:12 +0800 +Subject: net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit() + +From: Zhan Jun + +[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ] + +syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() +when accessing skb->len for tx statistics after usb_submit_urb() has +been called: + + BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760 + drivers/net/usb/rtl8150.c:712 + Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226 + +The URB completion handler write_bulk_callback() frees the skb via +dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU +in softirq context before usb_submit_urb() returns in the submitter, +so by the time the submitter reads skb->len the skb has already been +queued to the per-CPU completion_queue and freed by net_tx_action(): + + CPU A (xmit) CPU B (USB completion softirq) + ------------ ------------------------------ + dev->tx_skb = skb; + usb_submit_urb() --+ + |-------> write_bulk_callback() + | dev_kfree_skb_irq(dev->tx_skb) + | net_tx_action() + | napi_skb_cache_put() <-- free + netdev->stats.tx_bytes | + += skb->len; <-- UAF read + +Fix it by caching skb->len before submitting the URB and using the +cached value when updating the tx_bytes counter. + +The pre-existing tx_bytes semantics are preserved: the counter tracks +the original frame length (skb->len), not the ETH_ZLEN/USB-alignment +padded "count" value that is handed to the device. Changing that +would be a user-visible accounting change and is out of scope for +this UAF fix. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+3f46c095ac0ca048cb71@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e69ee7.050a0220.24bfd3.002b.GAE@google.com/ +Closes: https://syzkaller.appspot.com/bug?extid=3f46c095ac0ca048cb71 +Reviewed-by: Andrew Lunn +Signed-off-by: Zhan Jun +Link: https://patch.msgid.link/809895186B866C10+20260423004913.136655-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index e40b0669d9f4b..8700ae392b10a 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + rtl8150_t *dev = netdev_priv(netdev); ++ unsigned int skb_len; + int count, res; + + /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ +@@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + ++ skb_len = skb->len; ++ + netif_stop_queue(netdev); + dev->tx_skb = skb; + usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), +@@ -711,7 +714,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + } + } else { + netdev->stats.tx_packets++; +- netdev->stats.tx_bytes += skb->len; ++ netdev->stats.tx_bytes += skb_len; + netif_trans_update(netdev); + } + +-- +2.53.0 + diff --git a/queue-6.12/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch b/queue-6.12/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch new file mode 100644 index 0000000000..8a4ca56c6d --- /dev/null +++ b/queue-6.12/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch @@ -0,0 +1,61 @@ +From 41b5fc833fb7d784642026bc3ba9307ce5319608 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 09:55:17 +0800 +Subject: net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit + +From: Morduan Zang + +[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ] + +When rtl8150_start_xmit() fails to submit the tx URB, the URB is never +handed to the USB core and write_bulk_callback() will not run. The +driver returns NETDEV_TX_OK, which tells the networking stack that the +skb has been consumed, but nothing actually frees the skb on this +error path: + + dev->tx_skb = skb; + ... + if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { + ... + /* no kfree_skb here */ + } + return NETDEV_TX_OK; + +This leaks the skb on every submit failure and also leaves dev->tx_skb +pointing at memory that the driver itself may later free, which is +fragile. + +Free the skb with dev_kfree_skb_any() in the error path and clear +dev->tx_skb so no stale pointer is left behind. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reviewed-by: Andrew Lunn +Signed-off-by: Morduan Zang +Link: https://patch.msgid.link/E7D3E1C013C5A859+20260424015517.9574-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 8700ae392b10a..647f28b367b99 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -712,6 +712,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } ++ /* ++ * The URB was not submitted, so write_bulk_callback() will ++ * never run to free dev->tx_skb. Drop the skb here and ++ * clear tx_skb to avoid leaving a stale pointer. ++ */ ++ dev->tx_skb = NULL; ++ dev_kfree_skb_any(skb); + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb_len; +-- +2.53.0 + diff --git a/queue-6.12/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch b/queue-6.12/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch new file mode 100644 index 0000000000..afa921e05d --- /dev/null +++ b/queue-6.12/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch @@ -0,0 +1,92 @@ +From 910771bd5f3b492647d2de9614994c98eb992997 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:33:49 +0000 +Subject: net_sched: sch_hhf: annotate data-races in hhf_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ] + +hhf_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421143349.4052215-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_hhf.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index 5aa434b467073..914e985427744 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash, + return NULL; + list_del(&flow->flowchain); + kfree(flow); +- q->hh_flows_current_cnt--; ++ WRITE_ONCE(q->hh_flows_current_cnt, ++ q->hh_flows_current_cnt - 1); + } else if (flow->hash_id == hash) { + return flow; + } +@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + } + + if (q->hh_flows_current_cnt >= q->hh_flows_limit) { +- q->hh_flows_overlimit++; ++ WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); + return NULL; + } + /* Create new entry. */ +@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + if (!flow) + return NULL; + +- q->hh_flows_current_cnt++; ++ WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); + INIT_LIST_HEAD(&flow->flowchain); + list_add_tail(&flow->flowchain, head); + +@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) + return WDRR_BUCKET_FOR_NON_HH; + flow->hash_id = hash; + flow->hit_timestamp = now; +- q->hh_flows_total_cnt++; ++ WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); + + /* By returning without updating counters in q->hhf_arrays, + * we implicitly implement "shielding" (see Optimization O1). +@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + + prev_backlog = sch->qstats.backlog; +- q->drop_overlimit++; ++ WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); + /* Return Congestion Notification only if we dropped a packet from this + * bucket. + */ +@@ -685,10 +686,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct hhf_sched_data *q = qdisc_priv(sch); + struct tc_hhf_xstats st = { +- .drop_overlimit = q->drop_overlimit, +- .hh_overlimit = q->hh_flows_overlimit, +- .hh_tot_count = q->hh_flows_total_cnt, +- .hh_cur_count = q->hh_flows_current_cnt, ++ .drop_overlimit = READ_ONCE(q->drop_overlimit), ++ .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), ++ .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), ++ .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.12/netconsole-allow-selection-of-egress-interface-via-m.patch b/queue-6.12/netconsole-allow-selection-of-egress-interface-via-m.patch new file mode 100644 index 0000000000..f722cc8ce1 --- /dev/null +++ b/queue-6.12/netconsole-allow-selection-of-egress-interface-via-m.patch @@ -0,0 +1,214 @@ +From fcd83f02a510d1534a661f541f85758497ae7c33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Mar 2025 13:51:47 -0600 +Subject: netconsole: allow selection of egress interface via MAC address + +From: Uday Shankar + +[ Upstream commit f8a10bed32f5fbede13a5f22fdc4ab8740ea213a ] + +Currently, netconsole has two methods of configuration - module +parameter and configfs. The former interface allows for netconsole +activation earlier during boot (by specifying the module parameter on +the kernel command line), so it is preferred for debugging issues which +arise before userspace is up/the configfs interface can be used. The +module parameter syntax requires specifying the egress interface name. +This requirement makes it hard to use for a couple reasons: +- The egress interface name can be hard or impossible to predict. For + example, installing a new network card in a system can change the + interface names assigned by the kernel. +- When constructing the module parameter, one may have trouble + determining the original (kernel-assigned) name of the interface + (which is the name that should be given to netconsole) if some stable + interface naming scheme is in effect. A human can usually look at + kernel logs to determine the original name, but this is very painful + if automation is constructing the parameter. + +For these reasons, allow selection of the egress interface via MAC +address when configuring netconsole using the module parameter. Update +the netconsole documentation with an example of the new syntax. +Selection of egress interface by MAC address via configfs is far less +interesting (since when this interface can be used, one should be able +to easily convert between MAC address and interface name), so it is left +unimplemented. + +Signed-off-by: Uday Shankar +Reviewed-by: Breno Leitao +Tested-by: Breno Leitao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20250312-netconsole-v6-2-3437933e79b8@purestorage.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 3bc179bc7146 ("netpoll: fix IPv6 local-address corruption") +Signed-off-by: Sasha Levin +--- + Documentation/networking/netconsole.rst | 6 ++- + include/linux/netpoll.h | 6 +++ + net/core/netpoll.c | 51 +++++++++++++++++++------ + 3 files changed, 50 insertions(+), 13 deletions(-) + +diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst +index d55c2a22ec7af..56578486ff7e8 100644 +--- a/Documentation/networking/netconsole.rst ++++ b/Documentation/networking/netconsole.rst +@@ -45,7 +45,7 @@ following format:: + r if present, prepend kernel version (release) to the message + src-port source for UDP packets (defaults to 6665) + src-ip source IP to use (interface address) +- dev network interface (eth0) ++ dev network interface name (eth0) or MAC address + tgt-port port for logging agent (6666) + tgt-ip IP address for logging agent + tgt-macaddr ethernet MAC address for logging agent (broadcast) +@@ -62,6 +62,10 @@ or using IPv6:: + + insmod netconsole netconsole=@/,@fd00:1:2:3::1/ + ++or using a MAC address to select the egress interface:: ++ ++ linux netconsole=4444@10.0.0.1/22:33:44:55:66:77,9353@10.0.0.2/12:34:56:78:9a:bc ++ + It also supports logging to multiple remote agents by specifying + parameters for the multiple agents separated by semicolons and the + complete string enclosed in "quotes", thusly:: +diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h +index b34301650c479..ca88b1b87059f 100644 +--- a/include/linux/netpoll.h ++++ b/include/linux/netpoll.h +@@ -25,7 +25,13 @@ union inet_addr { + struct netpoll { + struct net_device *dev; + netdevice_tracker dev_tracker; ++ /* ++ * Either dev_name or dev_mac can be used to specify the local ++ * interface - dev_name is used if it is a nonempty string, else ++ * dev_mac is used. ++ */ + char dev_name[IFNAMSIZ]; ++ u8 dev_mac[ETH_ALEN]; + const char *name; + + union inet_addr local_ip, remote_ip; +diff --git a/net/core/netpoll.c b/net/core/netpoll.c +index 11b2a841b7488..a38b239cd7db6 100644 +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -506,7 +506,8 @@ void netpoll_print_options(struct netpoll *np) + np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6); + else + np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip); +- np_info(np, "interface '%s'\n", np->dev_name); ++ np_info(np, "interface name '%s'\n", np->dev_name); ++ np_info(np, "local ethernet address '%pM'\n", np->dev_mac); + np_info(np, "remote port %d\n", np->remote_port); + if (np->ipv6) + np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6); +@@ -575,11 +576,18 @@ int netpoll_parse_options(struct netpoll *np, char *opt) + cur++; + + if (*cur != ',') { +- /* parse out dev name */ ++ /* parse out dev_name or dev_mac */ + if ((delim = strchr(cur, ',')) == NULL) + goto parse_failed; + *delim = 0; +- strscpy(np->dev_name, cur, sizeof(np->dev_name)); ++ ++ np->dev_name[0] = '\0'; ++ eth_broadcast_addr(np->dev_mac); ++ if (!strchr(cur, ':')) ++ strscpy(np->dev_name, cur, sizeof(np->dev_name)); ++ else if (!mac_pton(cur, np->dev_mac)) ++ goto parse_failed; ++ + cur = delim; + } + cur++; +@@ -684,27 +692,45 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev) + } + EXPORT_SYMBOL_GPL(__netpoll_setup); + ++/* ++ * Returns a pointer to a string representation of the identifier used ++ * to select the egress interface for the given netpoll instance. buf ++ * must be a buffer of length at least MAC_ADDR_STR_LEN + 1. ++ */ ++static char *egress_dev(struct netpoll *np, char *buf) ++{ ++ if (np->dev_name[0]) ++ return np->dev_name; ++ ++ snprintf(buf, MAC_ADDR_STR_LEN, "%pM", np->dev_mac); ++ return buf; ++} ++ + int netpoll_setup(struct netpoll *np) + { ++ struct net *net = current->nsproxy->net_ns; ++ char buf[MAC_ADDR_STR_LEN + 1]; + struct net_device *ndev = NULL; + bool ip_overwritten = false; + struct in_device *in_dev; + int err; + + rtnl_lock(); +- if (np->dev_name[0]) { +- struct net *net = current->nsproxy->net_ns; ++ if (np->dev_name[0]) + ndev = __dev_get_by_name(net, np->dev_name); +- } ++ else if (is_valid_ether_addr(np->dev_mac)) ++ ndev = dev_getbyhwaddr(net, ARPHRD_ETHER, np->dev_mac); ++ + if (!ndev) { +- np_err(np, "%s doesn't exist, aborting\n", np->dev_name); ++ np_err(np, "%s doesn't exist, aborting\n", egress_dev(np, buf)); + err = -ENODEV; + goto unlock; + } + netdev_hold(ndev, &np->dev_tracker, GFP_KERNEL); + + if (netdev_master_upper_dev_get(ndev)) { +- np_err(np, "%s is a slave device, aborting\n", np->dev_name); ++ np_err(np, "%s is a slave device, aborting\n", ++ egress_dev(np, buf)); + err = -EBUSY; + goto put; + } +@@ -712,7 +738,8 @@ int netpoll_setup(struct netpoll *np) + if (!netif_running(ndev)) { + unsigned long atmost; + +- np_info(np, "device %s not up yet, forcing it\n", np->dev_name); ++ np_info(np, "device %s not up yet, forcing it\n", ++ egress_dev(np, buf)); + + err = dev_open(ndev, NULL); + +@@ -746,7 +773,7 @@ int netpoll_setup(struct netpoll *np) + if (!ifa) { + put_noaddr: + np_err(np, "no IP address for %s, aborting\n", +- np->dev_name); ++ egress_dev(np, buf)); + err = -EDESTADDRREQ; + goto put; + } +@@ -777,13 +804,13 @@ int netpoll_setup(struct netpoll *np) + } + if (err) { + np_err(np, "no IPv6 address for %s, aborting\n", +- np->dev_name); ++ egress_dev(np, buf)); + goto put; + } else + np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6); + #else + np_err(np, "IPv6 is not supported %s, aborting\n", +- np->dev_name); ++ egress_dev(np, buf)); + err = -EINVAL; + goto put; + #endif +-- +2.53.0 + diff --git a/queue-6.12/netconsole-propagate-device-name-truncation-in-dev_n.patch b/queue-6.12/netconsole-propagate-device-name-truncation-in-dev_n.patch new file mode 100644 index 0000000000..c2e6c55c29 --- /dev/null +++ b/queue-6.12/netconsole-propagate-device-name-truncation-in-dev_n.patch @@ -0,0 +1,58 @@ +From 2ef39f3a03a9a38666e5270efc43523eb7edc8d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 07:30:37 -0700 +Subject: netconsole: propagate device name truncation in dev_name_store() + +From: Breno Leitao + +[ Upstream commit 92ceb7bff62c2606f664c204750eca0b85d44112 ] + +dev_name_store() calls strscpy(nt->np.dev_name, buf, IFNAMSIZ) without +checking the return value. If userspace writes an interface name longer +than IFNAMSIZ - 1, strscpy() silently truncates and returns -E2BIG, but +the function ignores it and reports a fully successful write back to +userspace. + +If a real interface happens to match the truncated name, netconsole will +bind to the wrong device on the next enable, sending kernel logs and +panic output to an unintended network segment with no indication to +userspace that anything was rewritten. + +Reject writes whose length cannot fit in nt->np.dev_name up front: + + if (count >= IFNAMSIZ) + return -ENAMETOOLONG; + +This is not a big deal of a problem, but, it is still the correct +approach. + +Fixes: 0bcc1816188e57 ("[NET] netconsole: Support dynamic reconfiguration using configfs") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-3-59965f29d9cc@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 4048d99b7c57d..60375bb814a1e 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -502,6 +502,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + size_t count) + { + struct netconsole_target *nt = to_target(item); ++ size_t len = count; ++ ++ /* Account for a trailing newline appended by tools like echo */ ++ if (len && buf[len - 1] == '\n') ++ len--; ++ if (len >= IFNAMSIZ) ++ return -ENAMETOOLONG; + + mutex_lock(&dynamic_netconsole_mutex); + if (nt->enabled) { +-- +2.53.0 + diff --git a/queue-6.12/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch b/queue-6.12/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch new file mode 100644 index 0000000000..a9da872f12 --- /dev/null +++ b/queue-6.12/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch @@ -0,0 +1,43 @@ +From 3b0d7cb4756e5475e4690bc541011da50bb297fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 23:14:34 +0300 +Subject: netdevsim: zero initialize struct iphdr in dummy sk_buff + +From: Nikola Z. Ivanov + +[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ] + +Syzbot reports a KMSAN uninit-value originating from +nsim_dev_trap_skb_build, with the allocation also +being performed in the same function. + +Fix this by calling skb_put_zero instead of skb_put to +guarantee zero initialization of the whole IP header. + +Closes: https://syzkaller.appspot.com/bug?extid=23d7fcd204e3837866ff +Fixes: da58f90f11f5 ("netdevsim: Add devlink-trap support") +Signed-off-by: Nikola Z. Ivanov +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426201434.742030-1-zlatistiv@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netdevsim/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c +index 2614d6509954c..daec92570c2e3 100644 +--- a/drivers/net/netdevsim/dev.c ++++ b/drivers/net/netdevsim/dev.c +@@ -758,7 +758,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) + skb->protocol = htons(ETH_P_IP); + + skb_set_network_header(skb, skb->len); +- iph = skb_put(skb, sizeof(struct iphdr)); ++ iph = skb_put_zero(skb, sizeof(struct iphdr)); + iph->protocol = IPPROTO_UDP; + iph->saddr = in_aton("192.0.2.1"); + iph->daddr = in_aton("198.51.100.1"); +-- +2.53.0 + diff --git a/queue-6.12/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch b/queue-6.12/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch new file mode 100644 index 0000000000..876eee14e4 --- /dev/null +++ b/queue-6.12/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch @@ -0,0 +1,126 @@ +From 9689affb96d35c3994234cedcf2f233a400f8bd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:15:32 +0200 +Subject: netfilter: arp_tables: fix IEEE1394 ARP payload parsing + +From: Pablo Neira Ayuso + +[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ] + +Weiming Shi says: + +"arp_packet_match() unconditionally parses the ARP payload assuming two +hardware addresses are present (source and target). However, +IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address +field, and arp_hdr_len() already accounts for this by returning a +shorter length for ARPHRD_IEEE1394 devices. + +As a result, on IEEE1394 interfaces arp_packet_match() advances past a +nonexistent target hardware address and reads the wrong bytes for both +the target device address comparison and the target IP address. This +causes arptables rules to match against garbage data, leading to +incorrect filtering decisions: packets that should be accepted may be +dropped and vice versa. + +The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already +handles this correctly by skipping the target hardware address for +ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()." + +Mangle the original patch to always return 0 (no match) in case user +matches on the target hardware address which is never present in +IEEE1394. + +Note that this returns 0 (no match) for either normal and inverse match +because matching in the target hardware address in ARPHRD_IEEE1394 has +never been supported by arptables. This is intentional, matching on the +target hardware address should never evaluate true for ARPHRD_IEEE1394. + +Moreover, adjust arpt_mangle to drop the packet too as AI suggests: + +In arpt_mangle, the logic assumes a standard ARP layout. Because +IEEE1394 (FireWire) omits the target hardware address, the linear +pointer arithmetic miscalculates the offset for the target IP address. +This causes mangling operations to write to the wrong location, leading +to packet corruption. To ensure safety, this patch drops packets +(NF_DROP) when mangling is requested for these fields on IEEE1394 +devices, as the current implementation cannot correctly map the FireWire +ARP payload. + +This omits both mangling target hardware and IP address. Even if IP +address mangling should be possible in IEEE1394, this would require +to adjust arpt_mangle offset calculation, which has never been +supported. + +Based on patch from Weiming Shi . + +Fixes: 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.") +Reported-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- + net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 1cdd9c28ab2da..97ead883e4a13 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, + arpptr += dev->addr_len; + memcpy(&src_ipaddr, arpptr, sizeof(u32)); + arpptr += sizeof(u32); +- tgt_devaddr = arpptr; +- arpptr += dev->addr_len; ++ ++ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { ++ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, ++ sizeof(arpinfo->tgt_devaddr.mask)))) ++ return 0; ++ ++ tgt_devaddr = NULL; ++ } else { ++ tgt_devaddr = arpptr; ++ arpptr += dev->addr_len; ++ } + memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); + + if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, + arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, +- dev->addr_len)) || ++ dev->addr_len))) ++ return 0; ++ ++ if (tgt_devaddr && + NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, + arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, + dev->addr_len))) +diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c +index a4e07e5e9c118..f65dd339208e8 100644 +--- a/net/ipv4/netfilter/arpt_mangle.c ++++ b/net/ipv4/netfilter/arpt_mangle.c +@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += pln; + if (mangle->flags & ARPT_MANGLE_TDEV) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_DEV_ADDR_LEN_MAX < hln || + (arpptr + hln > skb_tail_pointer(skb))) + return NF_DROP; +@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += hln; + if (mangle->flags & ARPT_MANGLE_TIP) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_MANGLE_ADDR_LEN_MAX < pln || + (arpptr + pln > skb_tail_pointer(skb))) + return NF_DROP; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-conntrack-remove-sprintf-usage.patch b/queue-6.12/netfilter-conntrack-remove-sprintf-usage.patch new file mode 100644 index 0000000000..48996af849 --- /dev/null +++ b/queue-6.12/netfilter-conntrack-remove-sprintf-usage.patch @@ -0,0 +1,182 @@ +From 7997267e04ff7e27ca3be4eb879cd27df53604cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 19:13:46 +0200 +Subject: netfilter: conntrack: remove sprintf usage + +From: Florian Westphal + +[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ] + +Replace it with scnprintf, the buffer sizes are expected to be large enough +to hold the result, no need for snprintf+overflow check. + +Increase buffer size in mangle_content_len() while at it. + +BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 +Write of size 1 at addr [..] + vsnprintf+0xea5/0x1270 + sprintf+0xb1/0xe0 + mangle_content_len+0x1ac/0x280 + nf_nat_sdp_session+0x1cc/0x240 + process_sdp+0x8f8/0xb80 + process_invite_request+0x108/0x2b0 + process_sip_msg+0x5da/0xf50 + sip_help_tcp+0x45e/0x780 + nf_confirm+0x34d/0x990 + [..] + +Fixes: 9fafcd7b2032 ("[NETFILTER]: nf_conntrack/nf_nat: add SIP helper port") +Reported-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_nat_amanda.c | 2 +- + net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c +index 98deef6cde694..8f1054920a857 100644 +--- a/net/netfilter/nf_nat_amanda.c ++++ b/net/netfilter/nf_nat_amanda.c +@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb, + return NF_DROP; + } + +- sprintf(buffer, "%u", port); ++ snprintf(buffer, sizeof(buffer), "%u", port); + if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, + protoff, matchoff, matchlen, + buffer, strlen(buffer))) { +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index cf4aeb299bdef..c845b6d1a2bdf 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, + } + + static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, bool delim) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4", &addr->ip); ++ return scnprintf(buffer, size, "%pI4", &addr->ip); + else { + if (delim) +- return sprintf(buffer, "[%pI6c]", &addr->ip6); ++ return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); + else +- return sprintf(buffer, "%pI6c", &addr->ip6); ++ return scnprintf(buffer, size, "%pI6c", &addr->ip6); + } + } + + static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, u16 port) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4:%u", &addr->ip, port); ++ return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port); + else +- return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); ++ return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); + } + + static int map_addr(struct sk_buff *skb, unsigned int protoff, +@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, + if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) + return 1; + +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, true) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.dst.u3, + true); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, false) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.src.u3, + false); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +- buflen = sprintf(buffer, "%u", ntohs(p)); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle rport"); +@@ -418,7 +420,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, + + if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), ++ &newaddr, port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle packet"); +@@ -438,8 +441,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++ char buffer[sizeof("4294967295")]; + unsigned int matchoff, matchlen; +- char buffer[sizeof("65536")]; + int buflen, c_len; + + /* Get actual SDP length */ +@@ -454,7 +457,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + return 0; + +- buflen = sprintf(buffer, "%u", c_len); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -491,7 +494,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, + char buffer[INET6_ADDRSTRLEN]; + unsigned int buflen; + +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, + sdpoff, type, term, buffer, buflen)) + return 0; +@@ -509,7 +512,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + +- buflen = sprintf(buffer, "%u", port); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) + return 0; +@@ -529,7 +532,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, + SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) + return 0; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch b/queue-6.12/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch new file mode 100644 index 0000000000..38b9e992c1 --- /dev/null +++ b/queue-6.12/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch @@ -0,0 +1,352 @@ +From 1e246f6a85ca976a3d2bca146809eb482b715041 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 02:19:11 +0200 +Subject: netfilter: nf_conntrack_sip: don't use simple_strtoul +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Florian Westphal + +[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ] + +Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), +and ct_sip_parse_request() with a new sip_parse_port() helper that +validates each digit against the buffer limit, eliminating the use of +simple_strtoul() which assumes NUL-terminated strings. + +The previous code dereferenced pointers without bounds checks after +sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated +skb data. A port that reaches the buffer limit without a trailing +character is also rejected as malformed. + +Also get rid of all simple_strtoul() usage in conntrack, prefer a +stricter version instead. There are intentional changes: + +- Bail out if number is > UINT_MAX and indicate a failure, same for + too long sequences. + While we do accept 05535 as port 5535, we will not accept e.g. + 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, + we should restrict this to not waste cycles when presented with + malformed packets with 64k '0' characters. + +- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch + 'expire=' and 'rports='; both are expected to use base-10. + +- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k + range. + +- epaddr_len now returns 0 if the port is invalid, as it already does + for invalid ip addresses. This is intentional. nf_conntrack_sip + performs lots of guesswork to find the right parts of the message + to parse. Being stricter could break existing setups. + Connection tracking helpers are designed to allow traffic to + pass, not to block it. + +Based on an earlier patch from Jenny Guanni Qu . + +Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper") +Reported-by: Klaudia Kloc +Reported-by: Dawid Moczadło +Reported-by: Jenny Guanni Qu . +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- + net/netfilter/nf_nat_sip.c | 1 + + 2 files changed, 119 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index fda6fc1fc4c58..4b32ee408ea15 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, + return 1; + } + ++/* Parse optional port number after IP address. ++ * Returns false on malformed input, true otherwise. ++ * If port is non-NULL, stores parsed port in network byte order. ++ * If no port is present, sets *port to default SIP port. ++ */ ++static bool sip_parse_port(const char *dptr, const char **endp, ++ const char *limit, __be16 *port) ++{ ++ unsigned int p = 0; ++ int len = 0; ++ ++ if (dptr >= limit) ++ return false; ++ ++ if (*dptr != ':') { ++ if (port) ++ *port = htons(SIP_PORT); ++ if (endp) ++ *endp = dptr; ++ return true; ++ } ++ ++ dptr++; /* skip ':' */ ++ ++ while (dptr < limit && isdigit(*dptr)) { ++ p = p * 10 + (*dptr - '0'); ++ dptr++; ++ len++; ++ if (len > 5) /* max "65535" */ ++ return false; ++ } ++ ++ if (len == 0) ++ return false; ++ ++ /* reached limit while parsing port */ ++ if (dptr >= limit) ++ return false; ++ ++ if (p < 1024 || p > 65535) ++ return false; ++ ++ if (port) ++ *port = htons(p); ++ ++ if (endp) ++ *endp = dptr; ++ ++ return true; ++} ++ + /* skip ip address. returns its length. */ + static int epaddr_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, + return 0; + } + +- /* Port number */ +- if (*dptr == ':') { +- dptr++; +- dptr += digits_len(ct, dptr, limit, shift); +- } ++ if (!sip_parse_port(dptr, &dptr, limit, NULL)) ++ return 0; + return dptr - aux; + } + +@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, + return epaddr_len(ct, dptr, limit, shift); + } + ++/* simple_strtoul stops after first non-number character. ++ * But as we're not dealing with c-strings, we can't rely on ++ * hitting \r,\n,\0 etc. before moving past end of buffer. ++ * ++ * This is a variant of simple_strtoul, but doesn't require ++ * a c-string. ++ * ++ * If value exceeds UINT_MAX, 0 is returned. ++ */ ++static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) ++{ ++ const unsigned int max = sizeof("4294967295"); ++ unsigned int olen = len; ++ const char *s = cp; ++ u64 result = 0; ++ ++ if (len > max) ++ len = max; ++ ++ while (olen > 0 && isdigit(*s)) { ++ unsigned int value; ++ ++ if (len == 0) ++ goto err; ++ ++ value = *s - '0'; ++ result = result * 10 + value; ++ ++ if (result > UINT_MAX) ++ goto err; ++ s++; ++ len--; ++ olen--; ++ } ++ ++ if (endp) ++ *endp = (char *)s; ++ ++ return result; ++err: ++ if (endp) ++ *endp = (char *)cp; ++ return 0; ++} ++ + /* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF +@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, + { + const char *start = dptr, *limit = dptr + datalen, *end; + unsigned int mlen; +- unsigned int p; + int shift = 0; + + /* Skip method and following whitespace */ +@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, + + if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) + return -1; +- if (end < limit && *end == ':') { +- end++; +- p = simple_strtoul(end, (char **)&end, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(end, &end, limit, port)) ++ return -1; + + if (end == dptr) + return 0; +@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + union nf_inet_addr *addr, __be16 *port) + { + const char *c, *limit = dptr + datalen; +- unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, +@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + + if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) + return -1; +- if (*c == ':') { +- c++; +- p = simple_strtoul(c, (char **)&c, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(c, &c, limit, port)) ++ return -1; + + if (dataoff) + *dataoff = c - dptr; +@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + return 0; + + start += strlen(name); +- *val = simple_strtoul(start, &end, 0); ++ *val = sip_strtouint(start, limit - start, (char **)&end); + if (start == end) + return -1; + if (matchoff && matchlen) { +@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { ++ char *end; ++ + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) +@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + mediaoff += t->len; + medialen -= t->len; + +- port = simple_strtoul(*dptr + mediaoff, NULL, 10); +- if (port == 0) ++ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); ++ if (port == 0 || *dptr + mediaoff == end) + continue; + if (port < 1024 || port > 65535) { + nf_ct_helper_log(skb, ct, "wrong port %u", port); +@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, +@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + while (1) { + unsigned int c_expires = expires; +@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen, matchend; + unsigned int code, cseq, i; ++ char *end; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; +- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); ++ code = sip_strtouint(*dptr + strlen("SIP/2.0 "), ++ *datalen - strlen("SIP/2.0 "), NULL); + if (!code) { + nf_ct_helper_log(skb, ct, "cannot get code"); + return NF_DROP; +@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; ++ char *end; + + handler = &sip_handlers[i]; + if (handler->request == NULL) +@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + break; + +- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); ++ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); + if (dptr + matchoff == end) + break; + +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index c845b6d1a2bdf..9fbfc6bff0c22 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, + "rport=", &poff, &plen, + &n) > 0 && ++ n >= 1024 && n <= 65535 && + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch b/queue-6.12/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch new file mode 100644 index 0000000000..346b480400 --- /dev/null +++ b/queue-6.12/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch @@ -0,0 +1,67 @@ +From 7749661486e61f0bf894a42f7f437db6bc1d1fa0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:14:01 -0700 +Subject: netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO + +From: Xiang Mei + +[ Upstream commit 2195574dc6d9017d32ac346987e12659f931d932 ] + +nf_osf_match_one() computes ctx->window % f->wss.val in the +OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A +CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a +subsequent matching TCP SYN divides by zero and panics the kernel. + +Reject the bogus fingerprint in nfnl_osf_add_callback() above the +per-option for-loop. f->wss is per-fingerprint, not per-option, so +the check must run regardless of f->opt_num (including 0). Also +reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that +as "should not happen". + +Crash: + Oops: divide error: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) + Call Trace: + + nf_osf_match (net/netfilter/nfnetlink_osf.c:220) + xt_osf_match_packet (net/netfilter/xt_osf.c:32) + ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) + nf_hook_slow (net/netfilter/core.c:622) + ip_local_deliver (net/ipv4/ip_input.c:265) + ip_rcv (include/linux/skbuff.h:1162) + __netif_receive_skb_one_core (net/core/dev.c:6181) + process_backlog (net/core/dev.c:6642) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7945) + handle_softirqs (kernel/softirq.c:622) + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Weiming Shi +Suggested-by: Florian Westphal +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Xiang Mei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 9fc9544d4bc53..2305c7d9761eb 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, + if (f->opt_num > ARRAY_SIZE(f->opt)) + return -EINVAL; + ++ if (f->wss.wc >= OSF_WSS_MAX || ++ (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) ++ return -EINVAL; ++ + for (i = 0; i < f->opt_num; i++) { + if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch b/queue-6.12/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch new file mode 100644 index 0000000000..bfde1700dd --- /dev/null +++ b/queue-6.12/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch @@ -0,0 +1,100 @@ +From b5b5e80352b5243a8c22e0c1d28bf94228feecdb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:56 +0200 +Subject: netfilter: nfnetlink_osf: fix out-of-bounds read on option matching + +From: Fernando Fernandez Mancera + +[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ] + +In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once +and passed by reference to nf_osf_match_one() for each fingerprint +checked. During TCP option parsing, nf_osf_match_one() advances the +shared ctx->optp pointer. + +If a fingerprint perfectly matches, the function returns early without +restoring ctx->optp to its initial state. If the user has configured +NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. +However, because ctx->optp was not restored, the next call to +nf_osf_match_one() starts parsing from the end of the options buffer. +This causes subsequent matches to read garbage data and fail +immediately, making it impossible to log more than one match or logging +incorrect matches. + +Instead of using a shared ctx->optp pointer, pass the context as a +constant pointer and use a local pointer (optp) for TCP option +traversal. This makes nf_osf_match_one() strictly stateless from the +caller's perspective, ensuring every fingerprint check starts at the +correct option offset. + +Fixes: 1a6a0951fc00 ("netfilter: nfnetlink_osf: add missing fmatch check") +Suggested-by: Florian Westphal +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 2305c7d9761eb..832a973c41777 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx { + static bool nf_osf_match_one(const struct sk_buff *skb, + const struct nf_osf_user_finger *f, + int ttl_check, +- struct nf_osf_hdr_ctx *ctx) ++ const struct nf_osf_hdr_ctx *ctx) + { +- const __u8 *optpinit = ctx->optp; ++ const __u8 *optp = ctx->optp; + unsigned int check_WSS = 0; + int fmatch = FMATCH_WRONG; + int foptsize, optnum; +@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { +- if (f->opt[optnum].kind == *ctx->optp) { ++ if (f->opt[optnum].kind == *optp) { + __u32 len = f->opt[optnum].length; +- const __u8 *optend = ctx->optp + len; ++ const __u8 *optend = optp + len; + + fmatch = FMATCH_OK; + +- switch (*ctx->optp) { ++ switch (*optp) { + case OSFOPT_MSS: +- mss = ctx->optp[3]; ++ mss = optp[3]; + mss <<= 8; +- mss |= ctx->optp[2]; ++ mss |= optp[2]; + + mss = ntohs((__force __be16)mss); + break; +@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + break; + } + +- ctx->optp = optend; ++ optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + +@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + } + } + +- if (fmatch != FMATCH_OK) +- ctx->optp = optpinit; +- + return fmatch == FMATCH_OK; + } + +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch b/queue-6.12/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch new file mode 100644 index 0000000000..90b6301397 --- /dev/null +++ b/queue-6.12/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch @@ -0,0 +1,74 @@ +From 39abbf2ceffe48ab63a6fe3187c01baacd964e2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:57 +0200 +Subject: netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check + +From: Fernando Fernandez Mancera + +[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ] + +The nf_osf_ttl() function accessed skb->dev to perform a local interface +address lookup without verifying that the device pointer was valid. + +Additionally, the implementation utilized an in_dev_for_each_ifa_rcu +loop to match the packet source address against local interface +addresses. It assumed that packets from the same subnet should not see a +decrement on the initial TTL. A packet might appear it is from the same +subnet but it actually isn't especially in modern environments with +containers and virtual switching. + +Remove the device dereference and interface loop. Replace the logic with +a switch statement that evaluates the TTL according to the ttl_check. + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Kito Xu (veritas501) +Closes: https://lore.kernel.org/netfilter-devel/20260414074556.2512750-1-hxzene@gmail.com/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 832a973c41777..c89efb951994a 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); + static inline int nf_osf_ttl(const struct sk_buff *skb, + int ttl_check, unsigned char f_ttl) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + const struct iphdr *ip = ip_hdr(skb); +- const struct in_ifaddr *ifa; +- int ret = 0; + +- if (ttl_check == NF_OSF_TTL_TRUE) ++ switch (ttl_check) { ++ case NF_OSF_TTL_TRUE: + return ip->ttl == f_ttl; +- if (ttl_check == NF_OSF_TTL_NOCHECK) +- return 1; +- else if (ip->ttl <= f_ttl) ++ break; ++ case NF_OSF_TTL_NOCHECK: + return 1; +- +- in_dev_for_each_ifa_rcu(ifa, in_dev) { +- if (inet_ifa_match(ip->saddr, ifa)) { +- ret = (ip->ttl == f_ttl); +- break; +- } ++ case NF_OSF_TTL_LESS: ++ default: ++ return ip->ttl <= f_ttl; + } +- +- return ret; + } + + struct nf_osf_hdr_ctx { +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch b/queue-6.12/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch new file mode 100644 index 0000000000..f3afabe044 --- /dev/null +++ b/queue-6.12/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch @@ -0,0 +1,49 @@ +From 2aa1b5a0be43a5a4c48c6fbaf8a66cc8adbadbd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:30:41 +0200 +Subject: netfilter: nft_fwd_netdev: check ttl/hl before forwarding + +From: Florian Westphal + +[ Upstream commit 1dfd95bdf4d18d263aa8fad06bfb9f4d9c992b18 ] + +Drop packets if their ttl/hl is too small for forwarding. + +Fixes: d32de98ea70f ("netfilter: nft_fwd_netdev: allow to forward packets via neighbour layer") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_fwd_netdev.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c +index 152a9fb4d23af..256e832f1bb99 100644 +--- a/net/netfilter/nft_fwd_netdev.c ++++ b/net/netfilter/nft_fwd_netdev.c +@@ -116,6 +116,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + iph = ip_hdr(skb); ++ if (iph->ttl <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip_decrease_ttl(iph); + neigh_table = NEIGH_ARP_TABLE; + break; +@@ -132,6 +137,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + ip6h = ipv6_hdr(skb); ++ if (ip6h->hop_limit <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip6h->hop_limit--; + neigh_table = NEIGH_ND_TABLE; + break; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-nft_osf-restrict-it-to-ipv4.patch b/queue-6.12/netfilter-nft_osf-restrict-it-to-ipv4.patch new file mode 100644 index 0000000000..1b8c6279f5 --- /dev/null +++ b/queue-6.12/netfilter-nft_osf-restrict-it-to-ipv4.patch @@ -0,0 +1,47 @@ +From 3d71211d4d8f3b21a424061bfdfd52c61ed85d82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 13:06:38 +0200 +Subject: netfilter: nft_osf: restrict it to ipv4 + +From: Pablo Neira Ayuso + +[ Upstream commit b336fdbb7103fb1484e1dcb6741151d4b5a41e35 ] + +This expression only supports for ipv4, restrict it. + +Fixes: b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf") +Acked-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_osf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c +index 1c0b493ef0a99..bdc2f6c90e2f7 100644 +--- a/net/netfilter/nft_osf.c ++++ b/net/netfilter/nft_osf.c +@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, + struct nf_osf_data data; + struct tcphdr _tcph; + ++ if (nft_pf(pkt) != NFPROTO_IPV4) { ++ regs->verdict.code = NFT_BREAK; ++ return; ++ } ++ + if (pkt->tprot != IPPROTO_TCP) { + regs->verdict.code = NFT_BREAK; + return; +@@ -114,7 +119,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx, + + switch (ctx->family) { + case NFPROTO_IPV4: +- case NFPROTO_IPV6: + case NFPROTO_INET: + hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | +-- +2.53.0 + diff --git a/queue-6.12/netfilter-skip-recording-stale-or-retransmitted-init.patch b/queue-6.12/netfilter-skip-recording-stale-or-retransmitted-init.patch new file mode 100644 index 0000000000..b4292c6073 --- /dev/null +++ b/queue-6.12/netfilter-skip-recording-stale-or-retransmitted-init.patch @@ -0,0 +1,63 @@ +From 1271cb4f39955c80e14b1b7a5f6393100a938ea6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:40 -0400 +Subject: netfilter: skip recording stale or retransmitted INIT + +From: Xin Long + +[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ] + +An INIT whose init_tag matches the peer's vtag does not provide new state +information. It indicates either: + +- a stale INIT (after INIT-ACK has already been seen on the same side), or +- a retransmitted INIT (after INIT has already been recorded on the same + side). + +In both cases, the INIT must not update ct->proto.sctp.init[] state, since +it does not advance the handshake tracking and may otherwise corrupt +INIT/INIT-ACK validation logic. + +Allow INIT processing only when the conntrack entry is newly created +(SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer +vtag. + +Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in +nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it +set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag. + +Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") +Signed-off-by: Xin Long +Reviewed-by: Marcelo Ricardo Leitner +Acked-by: Florian Westphal +Link: https://patch.msgid.link/ee56c3e416452b2a40589a2a85245ac2ad5e9f4b.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index fabb2c1ca00ab..0dd55d3fba38d 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -471,9 +471,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + if (!ih) + goto out_unlock; + +- if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) +- ct->proto.sctp.init[!dir] = 0; +- ct->proto.sctp.init[dir] = 1; ++ /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ ++ if (old_state == SCTP_CONNTRACK_NONE || ++ ct->proto.sctp.vtag[!dir] != ih->init_tag) { ++ if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) ++ ct->proto.sctp.init[!dir] = 0; ++ ct->proto.sctp.init[dir] = 1; ++ } + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); + ct->proto.sctp.vtag[!dir] = ih->init_tag; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch b/queue-6.12/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch new file mode 100644 index 0000000000..3896c96be1 --- /dev/null +++ b/queue-6.12/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch @@ -0,0 +1,47 @@ +From 83f8d34233ee35402746c68d641a48bbb8e17d6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:25:06 +0800 +Subject: netfilter: xt_policy: fix strict mode inbound policy matching + +From: Jiexun Wang + +[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ] + +match_policy_in() walks sec_path entries from the last transform to the +first one, but strict policy matching needs to consume info->pol[] in +the same forward order as the rule layout. + +Derive the strict-match policy position from the number of transforms +already consumed so that multi-element inbound rules are matched +consistently. + +Fixes: c4b885139203 ("[NETFILTER]: x_tables: replace IPv4/IPv6 policy match by address family independant version") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Acked-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c +index cb6e8279010a4..b5fa65558318f 100644 +--- a/net/netfilter/xt_policy.c ++++ b/net/netfilter/xt_policy.c +@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, + return 0; + + for (i = sp->len - 1; i >= 0; i--) { +- pos = strict ? i - sp->len + 1 : 0; ++ pos = strict ? sp->len - i - 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; +-- +2.53.0 + diff --git a/queue-6.12/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch b/queue-6.12/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch new file mode 100644 index 0000000000..5822c99bd4 --- /dev/null +++ b/queue-6.12/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch @@ -0,0 +1,86 @@ +From 7bcde2977958b4d1f3df5dbefe139348a57276c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 12:12:59 +0200 +Subject: netfilter: xt_socket: enable defrag after all other checks + +From: Florian Westphal + +[ Upstream commit 542be3fa5aff54210a02954c38f07e53ea9bdafd ] + +Originally this did not matter because defrag was enabled once per netns +and only disabled again on netns dismantle. When this got changed I should +have adjusted checkentry to not leave defrag enabled on error. + +Fixes: de8c12110a13 ("netfilter: disable defrag once its no longer needed") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_socket.c | 23 ++++++----------------- + 1 file changed, 6 insertions(+), 17 deletions(-) + +diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c +index 76e01f292aaff..811e53bee4085 100644 +--- a/net/netfilter/xt_socket.c ++++ b/net/netfilter/xt_socket.c +@@ -168,52 +168,41 @@ static int socket_mt_enable_defrag(struct net *net, int family) + static int socket_mt_v1_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V1) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V1); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v2_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V2) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V2); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v3_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo3 *info = + (struct xt_socket_mtinfo3 *)par->matchinfo; +- int err; + +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + if (info->flags & ~XT_SOCKET_FLAGS_V3) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V3); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static void socket_mt_destroy(const struct xt_mtdtor_param *par) +-- +2.53.0 + diff --git a/queue-6.12/netfilter-xtables-restrict-several-matches-to-inet-f.patch b/queue-6.12/netfilter-xtables-restrict-several-matches-to-inet-f.patch new file mode 100644 index 0000000000..90e6d0565c --- /dev/null +++ b/queue-6.12/netfilter-xtables-restrict-several-matches-to-inet-f.patch @@ -0,0 +1,208 @@ +From 094a8b0a169ccfbb35c416137be8745f4ca5877c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 12:21:00 +0200 +Subject: netfilter: xtables: restrict several matches to inet family + +From: Pablo Neira Ayuso + +[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ] + +This is a partial revert of: + + commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") + +to allow ipv4 and ipv6 only. + +- xt_mac +- xt_owner +- xt_physdev + +These extensions are not used by ebtables in userspace. + +Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 +specific. + +Fixes: ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") +Reported-by: "Kito Xu (veritas501)" +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- + net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ + net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- + net/netfilter/xt_realm.c | 2 +- + 4 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index 81649da57ba5d..bd2354760895d 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + return ret; + } + +-static struct xt_match mac_mt_reg __read_mostly = { +- .name = "mac", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .match = mac_mt, +- .matchsize = sizeof(struct xt_mac_info), +- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | +- (1 << NF_INET_FORWARD), +- .me = THIS_MODULE, ++static struct xt_match mac_mt_reg[] __read_mostly = { ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV4, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV6, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init mac_mt_init(void) + { +- return xt_register_match(&mac_mt_reg); ++ return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + static void __exit mac_mt_exit(void) + { +- xt_unregister_match(&mac_mt_reg); ++ xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + module_init(mac_mt_init); +diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c +index 50332888c8d23..7be2fe22b067e 100644 +--- a/net/netfilter/xt_owner.c ++++ b/net/netfilter/xt_owner.c +@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + +-static struct xt_match owner_mt_reg __read_mostly = { +- .name = "owner", +- .revision = 1, +- .family = NFPROTO_UNSPEC, +- .checkentry = owner_check, +- .match = owner_mt, +- .matchsize = sizeof(struct xt_owner_match_info), +- .hooks = (1 << NF_INET_LOCAL_OUT) | +- (1 << NF_INET_POST_ROUTING), +- .me = THIS_MODULE, ++static struct xt_match owner_mt_reg[] __read_mostly = { ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV4, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV6, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ } + }; + + static int __init owner_mt_init(void) + { +- return xt_register_match(&owner_mt_reg); ++ return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + static void __exit owner_mt_exit(void) + { +- xt_unregister_match(&owner_mt_reg); ++ xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + module_init(owner_mt_init); +diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c +index 343e65f377d44..130842c35c6fa 100644 +--- a/net/netfilter/xt_physdev.c ++++ b/net/netfilter/xt_physdev.c +@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) + return 0; + } + +-static struct xt_match physdev_mt_reg __read_mostly = { +- .name = "physdev", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .checkentry = physdev_mt_check, +- .match = physdev_mt, +- .matchsize = sizeof(struct xt_physdev_info), +- .me = THIS_MODULE, ++static struct xt_match physdev_mt_reg[] __read_mostly = { ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV4, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV6, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init physdev_mt_init(void) + { +- return xt_register_match(&physdev_mt_reg); ++ return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + static void __exit physdev_mt_exit(void) + { +- xt_unregister_match(&physdev_mt_reg); ++ xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + module_init(physdev_mt_init); +diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c +index 6df485f4403d0..61b2f1e58d150 100644 +--- a/net/netfilter/xt_realm.c ++++ b/net/netfilter/xt_realm.c +@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { + .matchsize = sizeof(struct xt_realm_info), + .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), +- .family = NFPROTO_UNSPEC, ++ .family = NFPROTO_IPV4, + .me = THIS_MODULE + }; + +-- +2.53.0 + diff --git a/queue-6.12/netpoll-extract-carrier-wait-function.patch b/queue-6.12/netpoll-extract-carrier-wait-function.patch new file mode 100644 index 0000000000..8eb69173c3 --- /dev/null +++ b/queue-6.12/netpoll-extract-carrier-wait-function.patch @@ -0,0 +1,82 @@ +From 5298f70380daf258021e8f5c30b281f43931f9ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Jun 2025 02:32:45 -0700 +Subject: netpoll: Extract carrier wait function + +From: Breno Leitao + +[ Upstream commit 76d30b51e818064e02917ce6328fb2c8adce5c87 ] + +Extract the carrier waiting logic into a dedicated helper function +netpoll_wait_carrier() to improve code readability and reduce +duplication in netpoll_setup(). + +Signed-off-by: Breno Leitao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20250618-netpoll_ip_ref-v1-1-c2ac00fe558f@debian.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 3bc179bc7146 ("netpoll: fix IPv6 local-address corruption") +Signed-off-by: Sasha Levin +--- + net/core/netpoll.c | 28 ++++++++++++++++------------ + 1 file changed, 16 insertions(+), 12 deletions(-) + +diff --git a/net/core/netpoll.c b/net/core/netpoll.c +index a38b239cd7db6..a9c38f75b00ec 100644 +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -706,6 +706,21 @@ static char *egress_dev(struct netpoll *np, char *buf) + return buf; + } + ++static void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev, ++ unsigned int timeout) ++{ ++ unsigned long atmost; ++ ++ atmost = jiffies + timeout * HZ; ++ while (!netif_carrier_ok(ndev)) { ++ if (time_after(jiffies, atmost)) { ++ np_notice(np, "timeout waiting for carrier\n"); ++ break; ++ } ++ msleep(1); ++ } ++} ++ + int netpoll_setup(struct netpoll *np) + { + struct net *net = current->nsproxy->net_ns; +@@ -736,28 +751,17 @@ int netpoll_setup(struct netpoll *np) + } + + if (!netif_running(ndev)) { +- unsigned long atmost; +- + np_info(np, "device %s not up yet, forcing it\n", + egress_dev(np, buf)); + + err = dev_open(ndev, NULL); +- + if (err) { + np_err(np, "failed to open %s\n", ndev->name); + goto put; + } + + rtnl_unlock(); +- atmost = jiffies + carrier_timeout * HZ; +- while (!netif_carrier_ok(ndev)) { +- if (time_after(jiffies, atmost)) { +- np_notice(np, "timeout waiting for carrier\n"); +- break; +- } +- msleep(1); +- } +- ++ netpoll_wait_carrier(np, ndev, carrier_timeout); + rtnl_lock(); + } + +-- +2.53.0 + diff --git a/queue-6.12/netpoll-extract-ipv4-address-retrieval-into-helper-f.patch b/queue-6.12/netpoll-extract-ipv4-address-retrieval-into-helper-f.patch new file mode 100644 index 0000000000..9436f1a987 --- /dev/null +++ b/queue-6.12/netpoll-extract-ipv4-address-retrieval-into-helper-f.patch @@ -0,0 +1,104 @@ +From b50588de36342bea4b8ea5919a49ba4ed484225e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Jun 2025 02:32:46 -0700 +Subject: netpoll: extract IPv4 address retrieval into helper function + +From: Breno Leitao + +[ Upstream commit 3699f992e8c22d3ce54d2c1a5774e2c49028f99c ] + +Move the IPv4 address retrieval logic from netpoll_setup() into a +separate netpoll_take_ipv4() function to improve code organization +and readability. This change consolidates the IPv4-specific logic +and error handling into a dedicated function while maintaining +the same functionality. + +No functional changes. + +Signed-off-by: Breno Leitao +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20250618-netpoll_ip_ref-v1-2-c2ac00fe558f@debian.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 3bc179bc7146 ("netpoll: fix IPv6 local-address corruption") +Signed-off-by: Sasha Levin +--- + net/core/netpoll.c | 48 ++++++++++++++++++++++++++++++---------------- + 1 file changed, 31 insertions(+), 17 deletions(-) + +diff --git a/net/core/netpoll.c b/net/core/netpoll.c +index a9c38f75b00ec..b5305ff217a8b 100644 +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -721,13 +721,41 @@ static void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev, + } + } + ++/* ++ * Take the IPv4 from ndev and populate local_ip structure in netpoll ++ */ ++static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev) ++{ ++ char buf[MAC_ADDR_STR_LEN + 1]; ++ const struct in_ifaddr *ifa; ++ struct in_device *in_dev; ++ ++ in_dev = __in_dev_get_rtnl(ndev); ++ if (!in_dev) { ++ np_err(np, "no IP address for %s, aborting\n", ++ egress_dev(np, buf)); ++ return -EDESTADDRREQ; ++ } ++ ++ ifa = rtnl_dereference(in_dev->ifa_list); ++ if (!ifa) { ++ np_err(np, "no IP address for %s, aborting\n", ++ egress_dev(np, buf)); ++ return -EDESTADDRREQ; ++ } ++ ++ np->local_ip.ip = ifa->ifa_local; ++ np_info(np, "local IP %pI4\n", &np->local_ip.ip); ++ ++ return 0; ++} ++ + int netpoll_setup(struct netpoll *np) + { + struct net *net = current->nsproxy->net_ns; + char buf[MAC_ADDR_STR_LEN + 1]; + struct net_device *ndev = NULL; + bool ip_overwritten = false; +- struct in_device *in_dev; + int err; + + rtnl_lock(); +@@ -767,24 +795,10 @@ int netpoll_setup(struct netpoll *np) + + if (!np->local_ip.ip) { + if (!np->ipv6) { +- const struct in_ifaddr *ifa; +- +- in_dev = __in_dev_get_rtnl(ndev); +- if (!in_dev) +- goto put_noaddr; +- +- ifa = rtnl_dereference(in_dev->ifa_list); +- if (!ifa) { +-put_noaddr: +- np_err(np, "no IP address for %s, aborting\n", +- egress_dev(np, buf)); +- err = -EDESTADDRREQ; ++ err = netpoll_take_ipv4(np, ndev); ++ if (err) + goto put; +- } +- +- np->local_ip.ip = ifa->ifa_local; + ip_overwritten = true; +- np_info(np, "local IP %pI4\n", &np->local_ip.ip); + } else { + #if IS_ENABLED(CONFIG_IPV6) + struct inet6_dev *idev; +-- +2.53.0 + diff --git a/queue-6.12/netpoll-fix-ipv6-local-address-corruption.patch b/queue-6.12/netpoll-fix-ipv6-local-address-corruption.patch new file mode 100644 index 0000000000..5c82bec8e6 --- /dev/null +++ b/queue-6.12/netpoll-fix-ipv6-local-address-corruption.patch @@ -0,0 +1,81 @@ +From b46edbcf08cf83ca59e182662ebbf9f07e4d5b67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 08:31:16 -0700 +Subject: netpoll: fix IPv6 local-address corruption + +From: Breno Leitao + +[ Upstream commit 3bc179bc7146c26c9dff75d2943d10528274e301 ] + +netpoll_setup() decides whether to auto-populate the local source +address by testing np->local_ip.ip, which only inspects the first 4 +bytes of the union inet_addr storage. + +For an IPv6 netpoll whose caller-supplied local address has a zero +high-32 bits (::1, ::, IPv4-mapped ::ffff:a.b.c.d, etc.), this +misdetects the address as unset (which they are not, but the first +4 bytes are empty), calls netpoll_take_ipv6() and overwrites it with +whatever matching link-local/global address the device happens to expose +first. + +Introduce a helper netpoll_local_ip_unset() that picks the correct +family-aware test (ipv6_addr_any() for IPv6, !.ip for IPv4) and use it +from netpoll_setup(). + +Reproducer is something like: + + echo "::2" > local_ip + echo 1 > enabled + cat local_ip + # before this fix: 2001:db8::1 (caller-supplied ::2 was clobbered) + # after this fix: ::2 + +Fixes: b7394d2429c1 ("netpoll: prepare for ipv6") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260424-netpoll_fix-v1-1-3a55348c625f@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/netpoll.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/net/core/netpoll.c b/net/core/netpoll.c +index b5305ff217a8b..b754341db50fe 100644 +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -750,6 +750,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev) + return 0; + } + ++/* ++ * Test whether the caller left np->local_ip unset, so that ++ * netpoll_setup() should auto-populate it from the egress device. ++ * ++ * np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6), ++ * so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2, ++ * IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm — ++ * doing so would misclassify a caller-supplied address as unset and ++ * silently overwrite it with whatever address the device exposes. ++ */ ++static bool netpoll_local_ip_unset(const struct netpoll *np) ++{ ++ if (np->ipv6) ++ return ipv6_addr_any(&np->local_ip.in6); ++ return !np->local_ip.ip; ++} ++ + int netpoll_setup(struct netpoll *np) + { + struct net *net = current->nsproxy->net_ns; +@@ -793,7 +810,7 @@ int netpoll_setup(struct netpoll *np) + rtnl_lock(); + } + +- if (!np->local_ip.ip) { ++ if (netpoll_local_ip_unset(np)) { + if (!np->ipv6) { + err = netpoll_take_ipv4(np, ndev); + if (err) +-- +2.53.0 + diff --git a/queue-6.12/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch b/queue-6.12/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch new file mode 100644 index 0000000000..ea0dfd904e --- /dev/null +++ b/queue-6.12/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch @@ -0,0 +1,69 @@ +From 33d184073d8f7851ecd7841cd28b2391a0653456 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:19 +0800 +Subject: nexthop: fix IPv6 route referencing IPv4 nexthop + +From: Jiayuan Chen + +[ Upstream commit 29c95185ba32b621fbc3800fb86e7dc3edf5c2be ] + +syzbot reported a panic [1] [2]. + +When an IPv6 nexthop is replaced with an IPv4 nexthop, the has_v4 flag +of all groups containing this nexthop is not updated. This is because +nh_group_v4_update is only called when replacing AF_INET to AF_INET6, +but the reverse direction (AF_INET6 to AF_INET) is missed. + +This allows a stale has_v4=false to bypass fib6_check_nexthop, causing +IPv6 routes to be attached to groups that effectively contain only AF_INET +members. Subsequent route lookups then call nexthop_fib6_nh() which +returns NULL for the AF_INET member, leading to a NULL pointer +dereference. + +Fix by calling nh_group_v4_update whenever the family changes, not just +AF_INET to AF_INET6. + +Reproducer: + # AF_INET6 blackhole + ip -6 nexthop add id 1 blackhole + # group with has_v4=false + ip nexthop add id 100 group 1 + # replace with AF_INET (no -6), has_v4 stays false + ip nexthop replace id 1 blackhole + # pass stale has_v4 check + ip -6 route add 2001:db8::/64 nhid 100 + # panic + ping -6 2001:db8::1 + +[1] https://syzkaller.appspot.com/bug?id=e17283eb2f8dcf3dd9b47fe6f67a95f71faadad0 +[2] https://syzkaller.appspot.com/bug?id=8699b6ae54c9f35837d925686208402949e12ef3 +Fixes: 7bf4796dd099 ("nexthops: add support for replace") +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/nexthop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c +index f1d499a3e2748..52d4890be83e8 100644 +--- a/net/ipv4/nexthop.c ++++ b/net/ipv4/nexthop.c +@@ -2445,10 +2445,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + goto err_notify; + } + +- /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially ++ /* When replacing a nexthop with one of a different family, potentially + * update IPv4 indication in all the groups using the nexthop. + */ +- if (oldi->family == AF_INET && newi->family == AF_INET6) { ++ if (oldi->family != newi->family) { + list_for_each_entry(nhge, &old->grp_list, nh_list) { + struct nexthop *nhp = nhge->nh_parent; + struct nh_group *nhg; +-- +2.53.0 + diff --git a/queue-6.12/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch b/queue-6.12/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch new file mode 100644 index 0000000000..e5fd2345ae --- /dev/null +++ b/queue-6.12/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch @@ -0,0 +1,53 @@ +From f79bd50c841cc2f88af76b9064d076cea8ae5c74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 12:09:30 +0200 +Subject: NFC: trf7970a: Ignore antenna noise when checking for RF field + +From: Paul Geurts + +[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ] + +The main channel Received Signal Strength Indicator (RSSI) measurement +is used to determine whether an RF field is present or not. RSSI != 0 +is interpreted as an RF Field is present. This does not take RF noise +and measurement inaccuracy into account, and results in false positives +in the field. + +Define a noise level and make sure the RF field is only interpreted as +present when the RSSI is above the noise level. + +Fixes: 851ee3cbf850 ("NFC: trf7970a: Don't turn on RF if there is already an RF field") +Signed-off-by: Paul Geurts +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Mark Greer +Link: https://patch.msgid.link/20260422100930.581237-1-paul.geurts@prodrive-technologies.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/trf7970a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c +index 9e1a34e23af26..6b8311f526a5e 100644 +--- a/drivers/nfc/trf7970a.c ++++ b/drivers/nfc/trf7970a.c +@@ -311,6 +311,7 @@ + #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) ++#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 + + #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) + #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +@@ -1253,7 +1254,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) + if (ret) + return ret; + +- if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) ++ if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) + *is_rf_field = true; + else + *is_rf_field = false; +-- +2.53.0 + diff --git a/queue-6.12/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch b/queue-6.12/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch new file mode 100644 index 0000000000..1f9fd80b3d --- /dev/null +++ b/queue-6.12/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch @@ -0,0 +1,107 @@ +From 4ff8d1681b3b7c165bddc7fcf54c7b09b57b6284 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 16:05:36 +0000 +Subject: nfp: fix swapped arguments in nfp_encode_basic_qdr() calls + +From: Alexey Kodanev + +[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ] + +There is a mismatch between the passed arguments and the actual +nfp_encode_basic_qdr() function parameter names: + + static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + int mode, bool addr40, int isld1, + int isld0) + { + ... + +But "dest_island" and "cpp_tgt" are swapped at every call-site. +For example: + + return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + mode, addr40, isld1, isld0); + +As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target +type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" +as the destination island ID, which can accidentally match or be outside +the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination). + +Since code already worked for years, also add extra pr_warn() to error +paths in nfp_encode_basic_qdr() to help identify any potential address +verification failures. + +Detected using the static analysis tool - Svace. + +Fixes: 4cb584e0ee7d ("nfp: add CPP access core") +Signed-off-by: Alexey Kodanev +Link: https://patch.msgid.link/20260422160536.61855-1-aleksei.kodanev@bell-sw.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +index 79470f198a62a..9cf19446657c6 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + + /* Full Island ID and channel bits overlap? */ + ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0); +- if (ret) ++ if (ret) { ++ pr_warn("%s: decode dest_island failed: %d\n", __func__, ret); + return ret; ++ } + + /* The current address won't go where expected? */ +- if (dest_island != -1 && dest_island != v) ++ if (dest_island != -1 && dest_island != v) { ++ pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n", ++ __func__, dest_island, v); + return -EINVAL; ++ } + + /* If dest_island was -1, we don't care where it goes. */ + return 0; +@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * the address but we can verify if the existing + * contents will point to a valid island. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + iid_lsb = addr40 ? 34 : 26; +@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + return 0; + case 1: + if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40) +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + idx_lsb = addr40 ? 39 : 31; +@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * be set before hand and with them select an island. + * So we need to confirm that it's at least plausible. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + /* Make sure we compare against isldN values +@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * iid<1> = addr<30> = channel<0> + * channel<1> = addr<31> = Index + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + isld[0] &= ~3; +-- +2.53.0 + diff --git a/queue-6.12/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch b/queue-6.12/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch new file mode 100644 index 0000000000..9695e41e15 --- /dev/null +++ b/queue-6.12/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch @@ -0,0 +1,58 @@ +From 988324459ae2ce0c747923b1fa6efb17e5133238 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:49 +0100 +Subject: nfs/blocklayout: Fix compilation error (`make W=1`) in + bl_write_pagelist() + +From: Andy Shevchenko + +[ Upstream commit f83c8dda456ce4863f346aa26d88efa276eda35d ] + +Clang compiler is not happy about set but unused variable +(when dprintk() is no-op): + +.../blocklayout/blocklayout.c:384:9: error: variable 'count' set but not used [-Werror,-Wunused-but-set-variable] + +Remove a leftover from the previous cleanup. + +Fixes: 3a6fd1f004fc ("pnfs/blocklayout: remove read-modify-write handling in bl_write_pagelist") +Acked-by: Anna Schumaker +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/blocklayout/blocklayout.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c +index 5d6edafbed202..d1889f608b5d8 100644 +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -381,14 +381,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + sector_t isect, extent_length = 0; + struct parallel_io *par = NULL; + loff_t offset = header->args.offset; +- size_t count = header->args.count; + struct page **pages = header->args.pages; + int pg_index = header->args.pgbase >> PAGE_SHIFT; + unsigned int pg_len; + struct blk_plug plug; + int i; + +- dprintk("%s enter, %zu@%lld\n", __func__, count, offset); ++ dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); + + /* At this point, header->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error +@@ -429,7 +428,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + } + + offset += pg_len; +- count -= pg_len; + isect += (pg_len >> SECTOR_SHIFT); + extent_length -= (pg_len >> SECTOR_SHIFT); + } +-- +2.53.0 + diff --git a/queue-6.12/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch b/queue-6.12/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch new file mode 100644 index 0000000000..fe9a446587 --- /dev/null +++ b/queue-6.12/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch @@ -0,0 +1,61 @@ +From e17b4ab3e53a3d7b1d7bb932818be3244795c42f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:52:09 +0900 +Subject: nilfs2: reject zero bd_oblocknr in nilfs_ioctl_mark_blocks_dirty() + +From: Deepanshu Kartikey + +[ Upstream commit be3e5d10643d3be1cbac9d9939f220a99253f980 ] + +nilfs_ioctl_mark_blocks_dirty() uses bd_oblocknr to detect dead blocks +by comparing it with the current block number bd_blocknr. If they differ, +the block is considered dead and skipped. + +However, bd_oblocknr should never be 0 since block 0 typically stores the +primary superblock and is never a valid GC target block. A corrupted ioctl +request with bd_oblocknr set to 0 causes the comparison to incorrectly +match when the lookup returns -ENOENT and sets bd_blocknr to 0, bypassing +the dead block check and calling nilfs_bmap_mark() on a non-existent +block. This causes nilfs_btree_do_lookup() to return -ENOENT, triggering +the WARN_ON(ret == -ENOENT). + +Fix this by rejecting ioctl requests with bd_oblocknr set to 0 at the +beginning of each iteration. + +[ryusuke: slightly modified the commit message and comments for accuracy] + +Fixes: 7942b919f732 ("nilfs2: ioctl operations") +Reported-by: syzbot+98a040252119df0506f8@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=98a040252119df0506f8 +Suggested-by: Ryusuke Konishi +Signed-off-by: Deepanshu Kartikey +Reported-by: syzbot+466a45fcfb0562f5b9a0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=466a45fcfb0562f5b9a0 +Cc: Junjie Cao +Signed-off-by: Ryusuke Konishi +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/nilfs2/ioctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index fa77f78df6817..4c66f6f99b2b2 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -765,6 +765,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, + int ret, i; + + for (i = 0; i < nmembs; i++) { ++ /* ++ * bd_oblocknr must never be 0 as block 0 ++ * is never a valid GC target block ++ */ ++ if (unlikely(!bdescs[i].bd_oblocknr)) ++ return -EINVAL; + /* XXX: use macro or inline func to check liveness */ + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, +-- +2.53.0 + diff --git a/queue-6.12/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch b/queue-6.12/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch new file mode 100644 index 0000000000..183f587759 --- /dev/null +++ b/queue-6.12/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch @@ -0,0 +1,39 @@ +From 425110b0e5e7fa1b041e9edb56c57475fee28f40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 09:14:02 -0700 +Subject: nvme-pci: fix missed admin queue sq doorbell write + +From: Keith Busch + +[ Upstream commit 1cc4cdae2a3b7730d462d69e30f213fd2efe7807 ] + +We can batch admin commands submitted through io_uring_cmd passthrough, +which means bd->last may be false and skips the doorbell write to +aggregate multiple commands per write. If a subsequent command can't be +dispatched for whatever reason, we have to provide the blk-mq ops' +commit_rqs callback in order to ensure we properly update the doorbell. + +Fixes: 58e5bdeb9c2b ("nvme: enable uring-passthrough for admin commands") +Reviewed-by: Christoph Hellwig +Reviewed-by: Kanchan Joshi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 8eb1e4d48c432..758a187a8ab33 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1816,6 +1816,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled) + static const struct blk_mq_ops nvme_mq_admin_ops = { + .queue_rq = nvme_queue_rq, + .complete = nvme_pci_complete_rq, ++ .commit_rqs = nvme_commit_rqs, + .init_hctx = nvme_admin_init_hctx, + .init_request = nvme_pci_init_request, + .timeout = nvme_timeout, +-- +2.53.0 + diff --git a/queue-6.12/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch b/queue-6.12/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch new file mode 100644 index 0000000000..c459b88579 --- /dev/null +++ b/queue-6.12/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch @@ -0,0 +1,162 @@ +From 211da48a7765403fad4e147f763973691971ae12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 15:39:35 +0100 +Subject: nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its + callers + +From: Maurizio Lombardi + +[ Upstream commit ea8e356acb165cb1fd75537a52e1f66e5e76c538 ] + +Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds +PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) +and returns early. However, because the function returns void, the +callers are entirely unaware that a fatal error has occurred and +that the cmd->recv_msg.msg_iter was left uninitialized. + +Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly +overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA +Consequently, the socket receiving loop may attempt to read incoming +network data into the uninitialized iterator. + +Fix this by shifting the error handling responsibility to the callers. + +Fixes: 52a0a9854934 ("nvmet-tcp: add bounds checks in nvmet_tcp_build_pdu_iovec") +Reviewed-by: Hannes Reinecke +Reviewed-by: Yunje Shin +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Maurizio Lombardi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 51 ++++++++++++++++++++++----------------- + 1 file changed, 29 insertions(+), 22 deletions(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 0e92198813057..6c64af6a7c07a 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -359,7 +359,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); + +-static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) ++static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + { + struct bio_vec *iov = cmd->iov; + struct scatterlist *sg; +@@ -372,22 +372,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + offset = cmd->rbytes_done; + cmd->sg_idx = offset / PAGE_SIZE; + sg_offset = offset % PAGE_SIZE; +- if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) ++ return -EPROTO; ++ + sg = &cmd->req.sg[cmd->sg_idx]; + sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; + + while (length) { +- if (!sg_remaining) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } +- if (!sg->length || sg->length <= sg_offset) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!sg_remaining) ++ return -EPROTO; ++ ++ if (!sg->length || sg->length <= sg_offset) ++ return -EPROTO; ++ + u32 iov_len = min_t(u32, length, sg->length - sg_offset); + + bvec_set_page(iov, sg_page(sg), iov_len, +@@ -402,6 +399,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + + iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, + nr_pages, cmd->pdu_len); ++ return 0; + } + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) +@@ -997,7 +995,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) + return 0; + } + +-static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, ++static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) + { + size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); +@@ -1013,19 +1011,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + if (!nvme_is_write(cmd->req.cmd) || !data_len || + data_len > cmd->req.port->inline_data_size) { + nvmet_prepare_receive_pdu(queue); +- return; ++ return 0; + } + + ret = nvmet_tcp_map_data(cmd); + if (unlikely(ret)) { + pr_err("queue %d: failed to map data\n", queue->idx); + nvmet_tcp_fatal_error(queue); +- return; ++ return -EPROTO; + } + + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(cmd); + cmd->flags |= NVMET_TCP_F_INIT_FAILED; ++ ret = nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ ++ return ret; + } + + static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) +@@ -1077,7 +1079,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) + goto err_proto; + } + cmd->pdu_recv = 0; +- nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) { ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ goto err_proto; ++ } + queue->cmd = cmd; + queue->rcv_state = NVMET_TCP_RECV_DATA; + +@@ -1140,8 +1145,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + req->cmd->common.opcode, + le32_to_cpu(req->cmd->common.dptr.sgl.length)); + +- nvmet_tcp_handle_req_failure(queue, queue->cmd, req); +- return 0; ++ return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); + } + + ret = nvmet_tcp_map_data(queue->cmd); +@@ -1158,8 +1162,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + if (nvmet_tcp_need_data_in(queue->cmd)) { + if (nvmet_tcp_has_inline_data(queue->cmd)) { + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(queue->cmd); +- return 0; ++ ret = nvmet_tcp_build_pdu_iovec(queue->cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", ++ queue->idx); ++ return ret; + } + /* send back R2T */ + nvmet_tcp_queue_response(&queue->cmd->req); +-- +2.53.0 + diff --git a/queue-6.12/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch b/queue-6.12/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch new file mode 100644 index 0000000000..f105b2a3d9 --- /dev/null +++ b/queue-6.12/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch @@ -0,0 +1,48 @@ +From 47d8a4129d5deabe60bac3e9269b47235e1715a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:09 +0800 +Subject: ocfs2/dlm: fix off-by-one in dlm_match_regions() region comparison + +From: Junrui Luo + +[ Upstream commit 01b61e8dda9b0fdb0d4cda43de25f4e390554d7b ] + +The local-vs-remote region comparison loop uses '<=' instead of '<', +causing it to read one entry past the valid range of qr_regions. The +other loops in the same function correctly use '<'. + +Fix the loop condition to use '<' for consistency and correctness. + +Link: https://lkml.kernel.org/r/SYBPR01MB78813DA26B50EC5E01F00566AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index ad335fa6c188d..fe17f1e548c1c 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1002,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + for (i = 0; i < localnr; ++i) { + foundit = 0; + r = remote; +- for (j = 0; j <= qr->qr_numregions; ++j) { ++ for (j = 0; j < qr->qr_numregions; ++j) { + if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { + foundit = 1; + break; +-- +2.53.0 + diff --git a/queue-6.12/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch b/queue-6.12/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch new file mode 100644 index 0000000000..288015d5aa --- /dev/null +++ b/queue-6.12/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch @@ -0,0 +1,75 @@ +From 6ad9da0963ca3e17dc6edee402460bd5469418f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:08 +0800 +Subject: ocfs2/dlm: validate qr_numregions in dlm_match_regions() + +From: Junrui Luo + +[ Upstream commit 7ab3fbb01bc6d79091bc375e5235d360cd9b78be ] + +Patch series "ocfs2/dlm: fix two bugs in dlm_match_regions()". + +In dlm_match_regions(), the qr_numregions field from a DLM_QUERY_REGION +network message is used to drive loops over the qr_regions buffer without +sufficient validation. This series fixes two issues: + +- Patch 1 adds a bounds check to reject messages where qr_numregions + exceeds O2NM_MAX_REGIONS. The o2net layer only validates message + byte length; it does not constrain field values, so a crafted message + can set qr_numregions up to 255 and trigger out-of-bounds reads past + the 1024-byte qr_regions buffer. + +- Patch 2 fixes an off-by-one in the local-vs-remote comparison loop, + which uses '<=' instead of '<', reading one entry past the valid range + even when qr_numregions is within bounds. + +This patch (of 2): + +The qr_numregions field from a DLM_QUERY_REGION network message is used +directly as loop bounds in dlm_match_regions() without checking against +O2NM_MAX_REGIONS. Since qr_regions is sized for at most O2NM_MAX_REGIONS +(32) entries, a crafted message with qr_numregions > 32 causes +out-of-bounds reads past the qr_regions buffer. + +Add a bounds check for qr_numregions before entering the loops. + +Link: https://lkml.kernel.org/r/SYBPR01MB7881A334D02ACEE5E0645801AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Link: https://lkml.kernel.org/r/SYBPR01MB788166F524AD04E262E174BEAF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 2018501b22493..ad335fa6c188d 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + goto bail; + } + ++ if (qr->qr_numregions > O2NM_MAX_REGIONS) { ++ mlog(ML_ERROR, "Domain %s: Joining node %d has invalid " ++ "number of heartbeat regions %u\n", ++ qr->qr_domain, qr->qr_node, qr->qr_numregions); ++ status = -EINVAL; ++ goto bail; ++ } ++ + r = remote; + for (i = 0; i < qr->qr_numregions; ++i) { + mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); +-- +2.53.0 + diff --git a/queue-6.12/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch b/queue-6.12/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch new file mode 100644 index 0000000000..d3dd2e866b --- /dev/null +++ b/queue-6.12/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch @@ -0,0 +1,89 @@ +From 146d4584ea15739374c5897f59c79b2e6e03a0fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 12:03:39 +0800 +Subject: ocfs2: fix listxattr handling when the buffer is full + +From: ZhengYuan Huang + +[ Upstream commit d12f558e6200b3f47dbef9331ed6d115d2410e59 ] + +[BUG] +If an OCFS2 inode has both inline and block-based xattrs, listxattr() +can return a size larger than the caller's buffer when the inline names +consume that buffer exactly. + +kernel BUG at mm/usercopy.c:102! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:usercopy_abort+0xb7/0xd0 mm/usercopy.c:102 +Call Trace: + __check_heap_object+0xe3/0x120 mm/slub.c:8243 + check_heap_object mm/usercopy.c:196 [inline] + __check_object_size mm/usercopy.c:250 [inline] + __check_object_size+0x5c5/0x780 mm/usercopy.c:215 + check_object_size include/linux/ucopysize.h:22 [inline] + check_copy_size include/linux/ucopysize.h:59 [inline] + copy_to_user include/linux/uaccess.h:219 [inline] + listxattr+0xb0/0x170 fs/xattr.c:926 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x137/0x320 fs/xattr.c:988 + __do_sys_listxattr fs/xattr.c:1001 [inline] + __se_sys_listxattr fs/xattr.c:998 [inline] + __x64_sys_listxattr+0x7f/0xd0 fs/xattr.c:998 + ... + +[CAUSE] +Commit 936b8834366e ("ocfs2: Refactor xattr list and remove +ocfs2_xattr_handler().") replaced the old per-handler list accounting +with ocfs2_xattr_list_entry(), but it kept using size == 0 to detect +probe mode. + +That assumption stops being true once ocfs2_listxattr() finishes the +inline-xattr pass. If the inline names fill the caller buffer exactly, +the block-xattr pass runs with a non-NULL buffer and a remaining size of +zero. ocfs2_xattr_list_entry() then skips the bounds check, keeps +counting block names, and returns a positive size larger than the +supplied buffer. + +[FIX] +Detect probe mode by testing whether the destination buffer pointer is +NULL instead of whether the remaining size is zero. + +That restores the pre-refactor behavior and matches the OCFS2 getxattr +helpers. Once the remaining buffer reaches zero while more names are +left, the block-xattr pass now returns -ERANGE instead of reporting a +size larger than the allocated list buffer. + +Link: https://lkml.kernel.org/r/20260410040339.3837162-1-gality369@gmail.com +Fixes: 936b8834366e ("ocfs2: Refactor xattr list and remove ocfs2_xattr_handler().") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index b1a18a944c850..069732e657d78 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -907,8 +907,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb, + total_len = prefix_len + name_len + 1; + *result += total_len; + +- /* we are just looking for how big our buffer needs to be */ +- if (!size) ++ /* No buffer means we are only looking for the required size. */ ++ if (!buffer) + return 0; + + if (*result > size) +-- +2.53.0 + diff --git a/queue-6.12/ocfs2-validate-bg_bits-during-freefrag-scan.patch b/queue-6.12/ocfs2-validate-bg_bits-during-freefrag-scan.patch new file mode 100644 index 0000000000..d933fbdaa5 --- /dev/null +++ b/queue-6.12/ocfs2-validate-bg_bits-during-freefrag-scan.patch @@ -0,0 +1,121 @@ +From e1e47c1e5a8c63d73c085bfccb8837c011bf6a8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:42:20 +0800 +Subject: ocfs2: validate bg_bits during freefrag scan + +From: ZhengYuan Huang + +[ Upstream commit 8f687eeed3da3012152b0f9473f578869de0cd7b ] + +[BUG] +A crafted filesystem can trigger an out-of-bounds bitmap walk when +OCFS2_IOC_INFO is issued with OCFS2_INFO_FL_NON_COHERENT. + +BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:68 [inline] +BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] +BUG: KASAN: use-after-free in test_bit_le include/asm-generic/bitops/le.h:21 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 +Read of size 8 at addr ffff888031bce000 by task syz.0.636/1435 +Call Trace: + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xd1/0x650 mm/kasan/report.c:482 + kasan_report+0xfb/0x140 mm/kasan/report.c:595 + check_region_inline mm/kasan/generic.c:186 [inline] + kasan_check_range+0x11c/0x200 mm/kasan/generic.c:200 + __kasan_check_read+0x11/0x20 mm/kasan/shadow.c:31 + instrument_atomic_read include/linux/instrumented.h:68 [inline] + _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] + test_bit_le include/asm-generic/bitops/le.h:21 [inline] + ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] + ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] + ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] + ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 + ocfs2_info_handle+0x18d/0x2a0 fs/ocfs2/ioctl.c:828 + ocfs2_ioctl+0x632/0x6e0 fs/ocfs2/ioctl.c:913 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + ... + +[CAUSE] +ocfs2_info_freefrag_scan_chain() uses on-disk bg_bits directly as the +bitmap scan limit. The coherent path reads group descriptors through +ocfs2_read_group_descriptor(), which validates the descriptor before +use. The non-coherent path uses ocfs2_read_blocks_sync() instead and +skips that validation, so an impossible bg_bits value can drive the +bitmap walk past the end of the block. + +[FIX] +Compute the bitmap capacity from the filesystem format with +ocfs2_group_bitmap_size(), report descriptors whose bg_bits exceeds +that limit, and clamp the scan to the computed capacity. This keeps the +freefrag report going while avoiding reads beyond the buffer. + +Link: https://lkml.kernel.org/r/20260410034220.3825769-1-gality369@gmail.com +Fixes: d24a10b9f8ed ("Ocfs2: Add a new code 'OCFS2_INFO_FREEFRAG' for o2info ioctl.") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Heming Zhao +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/ioctl.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c +index 71beef7f8a60b..6bafb17aa9fbc 100644 +--- a/fs/ocfs2/ioctl.c ++++ b/fs/ocfs2/ioctl.c +@@ -443,13 +443,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + struct buffer_head *bh = NULL; + struct ocfs2_group_desc *bg = NULL; + +- unsigned int max_bits, num_clusters; ++ unsigned int max_bits, max_bitmap_bits, num_clusters; + unsigned int offset = 0, cluster, chunk; + unsigned int chunk_free, last_chunksize = 0; + + if (!le32_to_cpu(rec->c_free)) + goto bail; + ++ max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0, ++ osb->s_feature_incompat); ++ + do { + if (!bg) + blkno = le64_to_cpu(rec->c_blkno); +@@ -481,6 +484,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + continue; + + max_bits = le16_to_cpu(bg->bg_bits); ++ ++ /* ++ * Non-coherent scans read raw blocks and do not get the ++ * bg_bits validation from ++ * ocfs2_read_group_descriptor(). ++ */ ++ if (max_bits > max_bitmap_bits) { ++ mlog(ML_ERROR, ++ "Group desc #%llu has %u bits, max bitmap bits %u\n", ++ (unsigned long long)blkno, max_bits, max_bitmap_bits); ++ max_bits = max_bitmap_bits; ++ } ++ + offset = 0; + + for (chunk = 0; chunk < chunks_in_group; chunk++) { +-- +2.53.0 + diff --git a/queue-6.12/ocfs2-validate-group-add-input-before-caching.patch b/queue-6.12/ocfs2-validate-group-add-input-before-caching.patch new file mode 100644 index 0000000000..3a7f52e5b5 --- /dev/null +++ b/queue-6.12/ocfs2-validate-group-add-input-before-caching.patch @@ -0,0 +1,110 @@ +From 670cb8f9eec4df3c9aded5cc74ee6f5e69129fe3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 10:02:08 +0800 +Subject: ocfs2: validate group add input before caching + +From: ZhengYuan Huang + +[ Upstream commit 70b672833f4025341c11b22c7f83778a5cd611bc ] + +[BUG] +OCFS2_IOC_GROUP_ADD can trigger a BUG_ON in +ocfs2_set_new_buffer_uptodate(): + +kernel BUG at fs/ocfs2/uptodate.c:509! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:ocfs2_set_new_buffer_uptodate+0x194/0x1e0 fs/ocfs2/uptodate.c:509 +Code: ffffe88f 42b9fe4c 89e64889 dfe8b4df +Call Trace: + ocfs2_group_add+0x3f1/0x1510 fs/ocfs2/resize.c:507 + ocfs2_ioctl+0x309/0x6e0 fs/ocfs2/ioctl.c:887 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + x64_sys_call+0x1144/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:17 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e +RIP: 0033:0x7bbfb55a966d + +[CAUSE] +ocfs2_group_add() calls ocfs2_set_new_buffer_uptodate() on a +user-controlled group block before ocfs2_verify_group_and_input() +validates that block number. That helper is only valid for newly +allocated metadata and asserts that the block is not already present in +the chosen metadata cache. The code also uses INODE_CACHE(inode) even +though the group descriptor belongs to main_bm_inode and later journal +accesses use that cache context instead. + +[FIX] +Validate the on-disk group descriptor before caching it, then add it to +the metadata cache tracked by INODE_CACHE(main_bm_inode). Keep the +validation failure path separate from the later cleanup path so we only +remove the buffer from that cache after it has actually been inserted. +This keeps the group buffer lifetime consistent across validation, +journaling, and cleanup. + +Link: https://lkml.kernel.org/r/20260410020209.3786348-1-gality369@gmail.com +Fixes: 7909f2bf8353 ("[PATCH 2/2] ocfs2: Implement group add for online resize") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/resize.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c +index ed7ed15ad9a73..583a411557ab9 100644 +--- a/fs/ocfs2/resize.c ++++ b/fs/ocfs2/resize.c +@@ -508,14 +508,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + goto out_unlock; + } + +- ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); +- + ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); + if (ret) { + mlog_errno(ret); + goto out_free_group_bh; + } + ++ ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh); ++ + trace_ocfs2_group_add((unsigned long long)input->group, + input->chain, input->clusters, input->frees); + +@@ -523,7 +523,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + if (IS_ERR(handle)) { + mlog_errno(PTR_ERR(handle)); + ret = -EINVAL; +- goto out_free_group_bh; ++ goto out_remove_cache; + } + + cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); +@@ -577,9 +577,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + out_commit: + ocfs2_commit_trans(osb, handle); + +-out_free_group_bh: ++out_remove_cache: + if (ret < 0) +- ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); ++ ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh); ++ ++out_free_group_bh: + brelse(group_bh); + + out_unlock: +-- +2.53.0 + diff --git a/queue-6.12/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch b/queue-6.12/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch new file mode 100644 index 0000000000..df12f268dc --- /dev/null +++ b/queue-6.12/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch @@ -0,0 +1,132 @@ +From e41b7f5880a4a48c730abd107b21c370d54873a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 19:46:54 -0700 +Subject: openvswitch: cap upcall PID array size and pre-size vport replies + +From: Weiming Shi + +[ Upstream commit 2091c6aa0df6aba47deb5c8ab232b1cb60af3519 ] + +The vport netlink reply helpers allocate a fixed-size skb with +nlmsg_new(NLMSG_DEFAULT_SIZE, ...) but serialize the full upcall PID +array via ovs_vport_get_upcall_portids(). Since +ovs_vport_set_upcall_portids() accepts any non-zero multiple of +sizeof(u32) with no upper bound, a CAP_NET_ADMIN user can install a PID +array large enough to overflow the reply buffer, causing nla_put() to +fail with -EMSGSIZE and hitting BUG_ON(err < 0). On systems with +unprivileged user namespaces enabled (e.g., Ubuntu default), this is +reachable via unshare -Urn since OVS vport mutation operations use +GENL_UNS_ADMIN_PERM. + + kernel BUG at net/openvswitch/datapath.c:2414! + Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI + CPU: 1 UID: 0 PID: 65 Comm: poc Not tainted 7.0.0-rc7-00195-geb216e422044 #1 + RIP: 0010:ovs_vport_cmd_set+0x34c/0x400 + Call Trace: + + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1116) + genl_rcv_msg (net/netlink/genetlink.c:1194) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + genl_rcv (net/netlink/genetlink.c:1219) + netlink_unicast (net/netlink/af_netlink.c:1344) + netlink_sendmsg (net/netlink/af_netlink.c:1894) + __sys_sendto (net/socket.c:2206) + __x64_sys_sendto (net/socket.c:2209) + do_syscall_64 (arch/x86/entry/syscall_64.c:63) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + + Kernel panic - not syncing: Fatal exception + +Reject attempts to set more PIDs than nr_cpu_ids in +ovs_vport_set_upcall_portids(), and pre-compute the worst-case reply +size in ovs_vport_cmd_msg_size() based on that bound, similar to the +existing ovs_dp_cmd_msg_size(). nr_cpu_ids matches the cap already +used by the per-CPU dispatch configuration on the datapath side +(ovs_dp_cmd_fill_info() serialises at most nr_cpu_ids PIDs), so the +two sides stay consistent. + +Fixes: 5cd667b0a456 ("openvswitch: Allow each vport to have an array of 'port_id's.") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Weiming Shi +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260416024653.153456-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 35 +++++++++++++++++++++++++++++++++-- + net/openvswitch/vport.c | 3 +++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index 8d3c01f0e2aa1..607b5ca70ea54 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -2157,9 +2157,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + return err; + } + ++static size_t ovs_vport_cmd_msg_size(void) ++{ ++ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); ++ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */ ++ msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */ ++ msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */ ++ ++ /* OVS_VPORT_ATTR_STATS */ ++ msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats)); ++ ++ /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + ++ * OVS_VPORT_UPCALL_ATTR_FAIL) ++ */ ++ msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) + ++ nla_total_size_64bit(sizeof(u64))); ++ ++ /* OVS_VPORT_ATTR_UPCALL_PID */ ++ msgsize += nla_total_size(nr_cpu_ids * sizeof(u32)); ++ ++ /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + ++ * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) ++ */ ++ msgsize += nla_total_size(nla_total_size(sizeof(u16)) + ++ nla_total_size(nla_total_size(0))); ++ ++ return msgsize; ++} ++ + static struct sk_buff *ovs_vport_cmd_alloc_info(void) + { +- return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL); + } + + /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ +@@ -2169,7 +2200,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, + struct sk_buff *skb; + int retval; + +- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ skb = ovs_vport_cmd_alloc_info(); + if (!skb) + return ERR_PTR(-ENOMEM); + +diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c +index 2a996858a9145..469bc1fda726e 100644 +--- a/net/openvswitch/vport.c ++++ b/net/openvswitch/vport.c +@@ -407,6 +407,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids) + if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) + return -EINVAL; + ++ if (nla_len(ids) / sizeof(u32) > nr_cpu_ids) ++ return -EINVAL; ++ + old = ovsl_dereference(vport->upcall_portids); + + vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), +-- +2.53.0 + diff --git a/queue-6.12/padata-put-cpu-offline-callback-in-online-section-to.patch b/queue-6.12/padata-put-cpu-offline-callback-in-online-section-to.patch new file mode 100644 index 0000000000..4fef2597e0 --- /dev/null +++ b/queue-6.12/padata-put-cpu-offline-callback-in-online-section-to.patch @@ -0,0 +1,372 @@ +From 1ac6261929675736bd7513440c55ccb1e40e4011 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 11:24:33 -0400 +Subject: padata: Put CPU offline callback in ONLINE section to allow failure + +From: Daniel Jordan + +[ Upstream commit c8c4a2972f83c8b68ff03b43cecdb898939ff851 ] + +syzbot reported the following warning: + + DEAD callback error for CPU1 + WARNING: kernel/cpu.c:1463 at _cpu_down+0x759/0x1020 kernel/cpu.c:1463, CPU#0: syz.0.1960/14614 + +at commit 4ae12d8bd9a8 ("Merge tag 'kbuild-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux") +which tglx traced to padata_cpu_dead() given it's the only +sub-CPUHP_TEARDOWN_CPU callback that returns an error. + +Failure isn't allowed in hotplug states before CPUHP_TEARDOWN_CPU +so move the CPU offline callback to the ONLINE section where failure is +possible. + +Fixes: 894c9ef9780c ("padata: validate cpumask without removed CPU during offline") +Reported-by: syzbot+123e1b70473ce213f3af@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69af0a05.050a0220.310d8.002f.GAE@google.com/ +Debugged-by: Thomas Gleixner +Signed-off-by: Daniel Jordan +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + include/linux/cpuhotplug.h | 1 - + include/linux/padata.h | 8 +-- + kernel/padata.c | 120 +++++++++++++++++++------------------ + 3 files changed, 65 insertions(+), 64 deletions(-) + +diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h +index 2361ed4d2b152..6645faf1cc1d5 100644 +--- a/include/linux/cpuhotplug.h ++++ b/include/linux/cpuhotplug.h +@@ -94,7 +94,6 @@ enum cpuhp_state { + CPUHP_PCI_XGENE_DEAD, + CPUHP_IOMMU_IOVA_DEAD, + CPUHP_AP_ARM_CACHE_B15_RAC_DEAD, +- CPUHP_PADATA_DEAD, + CPUHP_AP_DTPM_CPU_DEAD, + CPUHP_RANDOM_PREPARE, + CPUHP_WORKQUEUE_PREP, +diff --git a/include/linux/padata.h b/include/linux/padata.h +index 765f2778e264a..b6232bea6edf5 100644 +--- a/include/linux/padata.h ++++ b/include/linux/padata.h +@@ -149,23 +149,23 @@ struct padata_mt_job { + /** + * struct padata_instance - The overall control structure. + * +- * @cpu_online_node: Linkage for CPU online callback. +- * @cpu_dead_node: Linkage for CPU offline callback. ++ * @cpuhp_node: Linkage for CPU hotplug callbacks. + * @parallel_wq: The workqueue used for parallel work. + * @serial_wq: The workqueue used for serial work. + * @pslist: List of padata_shell objects attached to this instance. + * @cpumask: User supplied cpumasks for parallel and serial works. ++ * @validate_cpumask: Internal cpumask used to validate @cpumask during hotplug. + * @kobj: padata instance kernel object. + * @lock: padata instance lock. + * @flags: padata flags. + */ + struct padata_instance { +- struct hlist_node cpu_online_node; +- struct hlist_node cpu_dead_node; ++ struct hlist_node cpuhp_node; + struct workqueue_struct *parallel_wq; + struct workqueue_struct *serial_wq; + struct list_head pslist; + struct padata_cpumask cpumask; ++ cpumask_var_t validate_cpumask; + struct kobject kobj; + struct mutex lock; + u8 flags; +diff --git a/kernel/padata.c b/kernel/padata.c +index af10aff28ff68..483239c7fe826 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -558,7 +558,8 @@ static void padata_init_reorder_list(struct parallel_data *pd) + } + + /* Allocate and initialize the internal cpumask dependend resources. */ +-static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) ++static struct parallel_data *padata_alloc_pd(struct padata_shell *ps, ++ int offlining_cpu) + { + struct padata_instance *pinst = ps->pinst; + struct parallel_data *pd; +@@ -584,6 +585,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) + + cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask); + cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask); ++ if (offlining_cpu >= 0) { ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.pcpu); ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.cbcpu); ++ } + + padata_init_reorder_list(pd); + padata_init_squeues(pd); +@@ -630,11 +635,11 @@ static void __padata_stop(struct padata_instance *pinst) + } + + /* Replace the internal control structure with a new one. */ +-static int padata_replace_one(struct padata_shell *ps) ++static int padata_replace_one(struct padata_shell *ps, int offlining_cpu) + { + struct parallel_data *pd_new; + +- pd_new = padata_alloc_pd(ps); ++ pd_new = padata_alloc_pd(ps, offlining_cpu); + if (!pd_new) + return -ENOMEM; + +@@ -644,7 +649,7 @@ static int padata_replace_one(struct padata_shell *ps) + return 0; + } + +-static int padata_replace(struct padata_instance *pinst) ++static int padata_replace(struct padata_instance *pinst, int offlining_cpu) + { + struct padata_shell *ps; + int err = 0; +@@ -652,7 +657,7 @@ static int padata_replace(struct padata_instance *pinst) + pinst->flags |= PADATA_RESET; + + list_for_each_entry(ps, &pinst->pslist, list) { +- err = padata_replace_one(ps); ++ err = padata_replace_one(ps, offlining_cpu); + if (err) + break; + } +@@ -669,9 +674,21 @@ static int padata_replace(struct padata_instance *pinst) + + /* If cpumask contains no active cpu, we mark the instance as invalid. */ + static bool padata_validate_cpumask(struct padata_instance *pinst, +- const struct cpumask *cpumask) ++ const struct cpumask *cpumask, ++ int offlining_cpu) + { +- if (!cpumask_intersects(cpumask, cpu_online_mask)) { ++ cpumask_copy(pinst->validate_cpumask, cpu_online_mask); ++ ++ /* ++ * @offlining_cpu is still in cpu_online_mask, so remove it here for ++ * validation. Using a sub-CPUHP_TEARDOWN_CPU hotplug state where ++ * @offlining_cpu wouldn't be in the online mask doesn't work because ++ * padata_cpu_offline() can fail but such a state doesn't allow failure. ++ */ ++ if (offlining_cpu >= 0) ++ __cpumask_clear_cpu(offlining_cpu, pinst->validate_cpumask); ++ ++ if (!cpumask_intersects(cpumask, pinst->validate_cpumask)) { + pinst->flags |= PADATA_INVALID; + return false; + } +@@ -687,13 +704,13 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + int valid; + int err; + +- valid = padata_validate_cpumask(pinst, pcpumask); ++ valid = padata_validate_cpumask(pinst, pcpumask, -1); + if (!valid) { + __padata_stop(pinst); + goto out_replace; + } + +- valid = padata_validate_cpumask(pinst, cbcpumask); ++ valid = padata_validate_cpumask(pinst, cbcpumask, -1); + if (!valid) + __padata_stop(pinst); + +@@ -701,7 +718,7 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + cpumask_copy(pinst->cpumask.pcpu, pcpumask); + cpumask_copy(pinst->cpumask.cbcpu, cbcpumask); + +- err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst); ++ err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst, -1); + + if (valid) + __padata_start(pinst); +@@ -753,26 +770,6 @@ EXPORT_SYMBOL(padata_set_cpumask); + + #ifdef CONFIG_HOTPLUG_CPU + +-static int __padata_add_cpu(struct padata_instance *pinst, int cpu) +-{ +- int err = padata_replace(pinst); +- +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- +- return err; +-} +- +-static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) +-{ +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- return padata_replace(pinst); +-} +- + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) + { + return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) || +@@ -784,27 +781,39 @@ static int padata_cpu_online(unsigned int cpu, struct hlist_node *node) + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_add_cpu(pinst, cpu); ++ ++ ret = padata_replace(pinst, -1); ++ ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu, -1) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, -1)) ++ __padata_start(pinst); ++ + mutex_unlock(&pinst->lock); + return ret; + } + +-static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node) ++static int padata_cpu_offline(unsigned int cpu, struct hlist_node *node) + { + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_remove_cpu(pinst, cpu); ++ ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu, cpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, cpu)) ++ __padata_stop(pinst); ++ ++ ret = padata_replace(pinst, cpu); ++ + mutex_unlock(&pinst->lock); + return ret; + } +@@ -815,15 +824,14 @@ static enum cpuhp_state hp_online; + static void __padata_free(struct padata_instance *pinst) + { + #ifdef CONFIG_HOTPLUG_CPU +- cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); +- cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node); ++ cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpuhp_node); + #endif + + WARN_ON(!list_empty(&pinst->pslist)); + + free_cpumask_var(pinst->cpumask.pcpu); + free_cpumask_var(pinst->cpumask.cbcpu); ++ free_cpumask_var(pinst->validate_cpumask); + destroy_workqueue(pinst->serial_wq); + destroy_workqueue(pinst->parallel_wq); + kfree(pinst); +@@ -983,10 +991,10 @@ struct padata_instance *padata_alloc(const char *name) + + if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL)) + goto err_free_serial_wq; +- if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) { +- free_cpumask_var(pinst->cpumask.pcpu); +- goto err_free_serial_wq; +- } ++ if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) ++ goto err_free_p_mask; ++ if (!alloc_cpumask_var(&pinst->validate_cpumask, GFP_KERNEL)) ++ goto err_free_cb_mask; + + INIT_LIST_HEAD(&pinst->pslist); + +@@ -994,7 +1002,7 @@ struct padata_instance *padata_alloc(const char *name) + cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask); + + if (padata_setup_cpumasks(pinst)) +- goto err_free_masks; ++ goto err_free_v_mask; + + __padata_start(pinst); + +@@ -1003,18 +1011,19 @@ struct padata_instance *padata_alloc(const char *name) + + #ifdef CONFIG_HOTPLUG_CPU + cpuhp_state_add_instance_nocalls_cpuslocked(hp_online, +- &pinst->cpu_online_node); +- cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); ++ &pinst->cpuhp_node); + #endif + + cpus_read_unlock(); + + return pinst; + +-err_free_masks: +- free_cpumask_var(pinst->cpumask.pcpu); ++err_free_v_mask: ++ free_cpumask_var(pinst->validate_cpumask); ++err_free_cb_mask: + free_cpumask_var(pinst->cpumask.cbcpu); ++err_free_p_mask: ++ free_cpumask_var(pinst->cpumask.pcpu); + err_free_serial_wq: + destroy_workqueue(pinst->serial_wq); + err_put_cpus: +@@ -1057,7 +1066,7 @@ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst) + ps->pinst = pinst; + + cpus_read_lock(); +- pd = padata_alloc_pd(ps); ++ pd = padata_alloc_pd(ps, -1); + cpus_read_unlock(); + + if (!pd) +@@ -1106,32 +1115,25 @@ void __init padata_init(void) + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online", +- padata_cpu_online, NULL); ++ padata_cpu_online, padata_cpu_offline); + if (ret < 0) + goto err; + hp_online = ret; +- +- ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead", +- NULL, padata_cpu_dead); +- if (ret < 0) +- goto remove_online_state; + #endif + + possible_cpus = num_possible_cpus(); + padata_works = kmalloc_array(possible_cpus, sizeof(struct padata_work), + GFP_KERNEL); + if (!padata_works) +- goto remove_dead_state; ++ goto remove_online_state; + + for (i = 0; i < possible_cpus; ++i) + list_add(&padata_works[i].pw_list, &padata_free_works); + + return; + +-remove_dead_state: +-#ifdef CONFIG_HOTPLUG_CPU +- cpuhp_remove_multi_state(CPUHP_PADATA_DEAD); + remove_online_state: ++#ifdef CONFIG_HOTPLUG_CPU + cpuhp_remove_multi_state(hp_online); + err: + #endif +-- +2.53.0 + diff --git a/queue-6.12/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch b/queue-6.12/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch new file mode 100644 index 0000000000..4af1197d0b --- /dev/null +++ b/queue-6.12/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch @@ -0,0 +1,79 @@ +From 4626209fdbbac726f8b19eaf25d9e8fc83302c2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 16:07:03 +0800 +Subject: padata: Remove cpu online check from cpu add and removal + +From: Chuyi Zhou + +[ Upstream commit 73117ea6470dca787f70f33c001f9faf437a1c0b ] + +During the CPU offline process, the dying CPU is cleared from the +cpu_online_mask in takedown_cpu(). After this step, various CPUHP_*_DEAD +callbacks are executed to perform cleanup jobs for the dead CPU, so this +cpu online check in padata_cpu_dead() is unnecessary. + +Similarly, when executing padata_cpu_online() during the +CPUHP_AP_ONLINE_DYN phase, the CPU has already been set in the +cpu_online_mask, the action even occurs earlier than the +CPUHP_AP_ONLINE_IDLE stage. + +Remove this unnecessary cpu online check in __padata_add_cpu() and +__padata_remove_cpu(). + +Signed-off-by: Chuyi Zhou +Acked-by: Daniel Jordan +Signed-off-by: Herbert Xu +Stable-dep-of: c8c4a2972f83 ("padata: Put CPU offline callback in ONLINE section to allow failure") +Signed-off-by: Sasha Levin +--- + kernel/padata.c | 26 ++++++++------------------ + 1 file changed, 8 insertions(+), 18 deletions(-) + +diff --git a/kernel/padata.c b/kernel/padata.c +index e61bdc248551f..af10aff28ff68 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -755,32 +755,22 @@ EXPORT_SYMBOL(padata_set_cpumask); + + static int __padata_add_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (cpumask_test_cpu(cpu, cpu_online_mask)) { +- err = padata_replace(pinst); ++ int err = padata_replace(pinst); + +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- } ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_start(pinst); + + return err; + } + + static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (!cpumask_test_cpu(cpu, cpu_online_mask)) { +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- err = padata_replace(pinst); +- } ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_stop(pinst); + +- return err; ++ return padata_replace(pinst); + } + + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) +-- +2.53.0 + diff --git a/queue-6.12/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch b/queue-6.12/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch new file mode 100644 index 0000000000..42fa29dcab --- /dev/null +++ b/queue-6.12/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch @@ -0,0 +1,109 @@ +From 27587eda16dfefd84dea718fea24a7a4cfa27c8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 19:07:39 +0200 +Subject: page_pool: fix memory-provider leak in page_pool_create_percpu() + error path + +From: Hasan Basbunar + +[ Upstream commit 5ef343614db766acdc01c56d66e780a1b43c6ac6 ] + +When page_pool_create_percpu() fails on page_pool_list(), it falls +through to its err_uninit: label, which calls page_pool_uninit(). +At that point page_pool_init() has already taken two references +when the user requested PP_FLAG_ALLOW_UNREADABLE_NETMEM: + + pool->mp_ops->init(pool) + static_branch_inc(&page_pool_mem_providers); + +Neither is undone by page_pool_uninit(); both are only undone by +__page_pool_destroy() (success-side teardown). The error path +therefore leaks the per-provider reference taken by mp_ops->init +(io_zcrx_ifq->refs in the io_uring zcrx provider, the dmabuf +binding refcount in the devmem provider) plus one increment of +the page_pool_mem_providers static branch on every failure of +xa_alloc_cyclic() inside page_pool_list(). + +The leaked io_zcrx_ifq->refs in turn pins everything +io_zcrx_ifq_free() would release on cleanup: ifq->user (uid), +ifq->mm_account (mmdrop), ifq->dev (device refcount), +ifq->netdev_tracker (netdev refcount), and the rbuf region. +The leaked static branch increment forces all subsequent +page_pool_alloc_netmems() and page_pool_return_page() callers to +take the slow mp_ops branch for the lifetime of the kernel. + +Reachable via the io_uring zcrx path: + + io_uring_register(IORING_REGISTER_ZCRX_IFQ) /* CAP_NET_ADMIN */ + -> __io_uring_register + -> io_register_zcrx + -> zcrx_register_netdev + -> netif_mp_open_rxq + -> driver ndo_queue_mem_alloc + -> page_pool_create_percpu + -> page_pool_init succeeds (mp_ops->init runs, branch++) + -> page_pool_list fails (xa_alloc_cyclic -ENOMEM) + -> goto err_uninit <-- leak + +The same shape applies to the devmem dmabuf provider via +mp_dmabuf_devmem_init()/mp_dmabuf_devmem_destroy(). + +Restore the cleanup symmetry by moving the mp_ops->destroy() and +static_branch_dec() calls out of __page_pool_destroy() and into +page_pool_uninit(), so page_pool_uninit() is again the strict +inverse of page_pool_init(). page_pool_uninit() has only two +callers (the err_uninit: path and __page_pool_destroy()), so this +preserves the single-call invariant on the success path while +fixing the err path. The error path of page_pool_init() itself +still skips the mp_ops cleanup correctly: mp_ops->init is the +last action that takes a reference before page_pool_init() returns +0, so when it returns an error neither the refcount nor the static +branch has been touched. + +Triggering the bug requires xa_alloc_cyclic() to fail with -ENOMEM, +which under normal GFP_KERNEL retry behaviour is rare. It is +deterministic under CONFIG_FAULT_INJECTION with fail_page_alloc / +xa fault injection, or under sustained memory pressure. The leak +is silent: there is no warning, and the released kernel build +continues running with a permanently-incremented static branch. + +Fixes: 0f9214046893 ("memory-provider: dmabuf devmem memory provider") +Signed-off-by: Hasan Basbunar +Link: https://patch.msgid.link/20260428170739.34881-1-basbunarhasan@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/page_pool.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/core/page_pool.c b/net/core/page_pool.c +index 5c089469541c4..9c569a0371656 100644 +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -323,6 +323,11 @@ static void page_pool_uninit(struct page_pool *pool) + if (!pool->system) + free_percpu(pool->recycle_stats); + #endif ++ ++ if (pool->mp_ops) { ++ pool->mp_ops->destroy(pool); ++ static_branch_dec(&page_pool_mem_providers); ++ } + } + + /** +@@ -1088,11 +1093,6 @@ static void __page_pool_destroy(struct page_pool *pool) + page_pool_unlist(pool); + page_pool_uninit(pool); + +- if (pool->mp_ops) { +- pool->mp_ops->destroy(pool); +- static_branch_dec(&page_pool_mem_providers); +- } +- + kfree(pool); + } + +-- +2.53.0 + diff --git a/queue-6.12/page_pool-set-dma_sync-to-false-for-devmem-memory-pr.patch b/queue-6.12/page_pool-set-dma_sync-to-false-for-devmem-memory-pr.patch new file mode 100644 index 0000000000..f80408af8f --- /dev/null +++ b/queue-6.12/page_pool-set-dma_sync-to-false-for-devmem-memory-pr.patch @@ -0,0 +1,63 @@ +From f46b4f1d34d30b4716e09ed96bf1861f4b5373ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Dec 2024 21:20:30 +0000 +Subject: page_pool: Set `dma_sync` to false for devmem memory provider + +From: Samiullah Khawaja + +[ Upstream commit b400f4b87430c105d92550cee5a72aea01fdf3d6 ] + +Move the `dma_map` and `dma_sync` checks to `page_pool_init` to make +them generic. Set dma_sync to false for devmem memory provider because +the dma_sync APIs should not be used for dma_buf backed devmem memory +provider. + +Cc: Jason Gunthorpe +Signed-off-by: Samiullah Khawaja +Signed-off-by: Mina Almasry +Link: https://patch.msgid.link/20241211212033.1684197-4-almasrymina@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5ef343614db7 ("page_pool: fix memory-provider leak in page_pool_create_percpu() error path") +Signed-off-by: Sasha Levin +--- + net/core/devmem.c | 9 ++++----- + net/core/page_pool.c | 3 +++ + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/net/core/devmem.c b/net/core/devmem.c +index 17f8a83a5ee74..f04a89b0a41fe 100644 +--- a/net/core/devmem.c ++++ b/net/core/devmem.c +@@ -333,11 +333,10 @@ int mp_dmabuf_devmem_init(struct page_pool *pool) + if (!binding) + return -EINVAL; + +- if (!pool->dma_map) +- return -EOPNOTSUPP; +- +- if (pool->dma_sync) +- return -EOPNOTSUPP; ++ /* dma-buf dma addresses do not need and should not be used with ++ * dma_sync_for_cpu/device. Force disable dma_sync. ++ */ ++ pool->dma_sync = false; + + if (pool->p.order != 0) + return -E2BIG; +diff --git a/net/core/page_pool.c b/net/core/page_pool.c +index 458b040a8655d..2ad52612d8ae8 100644 +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -283,6 +283,9 @@ static int page_pool_init(struct page_pool *pool, + } + + if (pool->mp_priv) { ++ if (!pool->dma_map || !pool->dma_sync) ++ return -EOPNOTSUPP; ++ + err = mp_dmabuf_devmem_init(pool); + if (err) { + pr_warn("%s() mem-provider init failed %d\n", __func__, +-- +2.53.0 + diff --git a/queue-6.12/params-replace-__modinit-with-__init_or_module.patch b/queue-6.12/params-replace-__modinit-with-__init_or_module.patch new file mode 100644 index 0000000000..a5aece54e8 --- /dev/null +++ b/queue-6.12/params-replace-__modinit-with-__init_or_module.patch @@ -0,0 +1,67 @@ +From b158361fd3f5a6705a12dc075f6bab024d450d9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Aug 2025 14:12:09 +0200 +Subject: params: Replace __modinit with __init_or_module + +From: Petr Pavlu + +[ Upstream commit 3cb0c3bdea5388519bc1bf575dca6421b133302b ] + +Remove the custom __modinit macro from kernel/params.c and instead use the +common __init_or_module macro from include/linux/module.h. Both provide the +same functionality. + +Signed-off-by: Petr Pavlu +Reviewed-by: Aaron Tomlin +Reviewed-by: Daniel Gomez +Reviewed-by: Sami Tolvanen +Signed-off-by: Sami Tolvanen +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + kernel/params.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +diff --git a/kernel/params.c b/kernel/params.c +index 9935ff599356b..2be5a083f9399 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -595,12 +595,6 @@ static ssize_t param_attr_store(struct module_attribute *mattr, + } + #endif + +-#ifdef CONFIG_MODULES +-#define __modinit +-#else +-#define __modinit __init +-#endif +- + #ifdef CONFIG_SYSFS + void kernel_param_lock(struct module *mod) + { +@@ -625,9 +619,9 @@ EXPORT_SYMBOL(kernel_param_unlock); + * create file in sysfs. Returns an error on out of memory. Always cleans up + * if there's an error. + */ +-static __modinit int add_sysfs_param(struct module_kobject *mk, +- const struct kernel_param *kp, +- const char *name) ++static __init_or_module int add_sysfs_param(struct module_kobject *mk, ++ const struct kernel_param *kp, ++ const char *name) + { + struct module_param_attrs *new_mp; + struct attribute **new_attrs; +@@ -763,7 +757,8 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) ++struct module_kobject * __init_or_module ++lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +-- +2.53.0 + diff --git a/queue-6.12/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch b/queue-6.12/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch new file mode 100644 index 0000000000..94b5cc3039 --- /dev/null +++ b/queue-6.12/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch @@ -0,0 +1,63 @@ +From a9c2fdaacbf4105c23a7b2082a850fbc6fcd9d71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:53 +0530 +Subject: PCI: dwc: Apply ECRC workaround to DesignWare 5.00a as well + +From: Manikanta Maddireddy + +[ Upstream commit 40805f32dceadebb7381d911003100bec7b8cd51 ] + +The ECRC (TLP digest) workaround was originally added for DesignWare +version 4.90a. Tegra234 SoC has 5.00a DWC HW version, which has the same +ATU TD override behaviour, so apply the workaround for 5.00a too. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-13-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c +index f7d10cb788e0e..bc3d6269f33bc 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.c ++++ b/drivers/pci/controller/dwc/pcie-designware.c +@@ -429,13 +429,13 @@ static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg + static inline u32 dw_pcie_enable_ecrc(u32 val) + { + /* +- * DesignWare core version 4.90A has a design issue where the 'TD' +- * bit in the Control register-1 of the ATU outbound region acts +- * like an override for the ECRC setting, i.e., the presence of TLP +- * Digest (ECRC) in the outgoing TLPs is solely determined by this +- * bit. This is contrary to the PCIe spec which says that the +- * enablement of the ECRC is solely determined by the AER +- * registers. ++ * DWC versions 0x3530302a and 0x3536322a have a design issue where ++ * the 'TD' bit in the Control register-1 of the ATU outbound ++ * region acts like an override for the ECRC setting, i.e., the ++ * presence of TLP Digest (ECRC) in the outgoing TLPs is solely ++ * determined by this bit. This is contrary to the PCIe spec which ++ * says that the enablement of the ECRC is solely determined by the ++ * AER registers. + * + * Because of this, even when the ECRC is enabled through AER + * registers, the transactions going through ATU won't have TLP +@@ -505,7 +505,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, + if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) && + dw_pcie_ver_is_ge(pci, 460A)) + val |= PCIE_ATU_INCREASE_REGION_SIZE; +- if (dw_pcie_ver_is(pci, 490A)) ++ if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A)) + val = dw_pcie_enable_ecrc(val); + dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val); + +-- +2.53.0 + diff --git a/queue-6.12/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch b/queue-6.12/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch new file mode 100644 index 0000000000..3b5265968d --- /dev/null +++ b/queue-6.12/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch @@ -0,0 +1,47 @@ +From 5ca9ea8e0a9bebb1d2e29481ecdc6c25035f2aab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 14:08:16 +0530 +Subject: PCI: dwc: ep: Fix MSI-X Table Size configuration in + dw_pcie_ep_set_msix() + +From: Aksh Garg + +[ Upstream commit 271d0b1f058ae9815e75233d04b23e3558c3e4f4 ] + +In dw_pcie_ep_set_msix(), while updating the MSI-X Table Size value for +individual functions, Message Control register is read from the passed +function number register space using dw_pcie_ep_readw_dbi(), but always +written back to the Function 0's register space using dw_pcie_writew_dbi(). +This causes incorrect MSI-X configuration for the rest of the functions, +other than Function 0. + +Fix this by using dw_pcie_ep_writew_dbi() to write to the correct +function's register space, matching the read operation. + +Fixes: 70fa02ca1446 ("PCI: dwc: Add dw_pcie_ep_{read,write}_dbi[2] helpers") +Signed-off-by: Aksh Garg +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260224083817.916782-2-a-garg7@ti.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index a23af31d1e2c3..ec306406959af 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -423,7 +423,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + val = dw_pcie_ep_readw_dbi(ep, func_no, reg); + val &= ~PCI_MSIX_FLAGS_QSIZE; + val |= nr_irqs - 1; /* encoded as N-1 */ +- dw_pcie_writew_dbi(pci, reg, val); ++ dw_pcie_ep_writew_dbi(ep, func_no, reg, val); + + reg = ep_func->msix_cap + PCI_MSIX_TABLE; + val = offset | bir; +-- +2.53.0 + diff --git a/queue-6.12/pci-dwc-invoke-post_init-in-dw_pcie_resume_noirq.patch b/queue-6.12/pci-dwc-invoke-post_init-in-dw_pcie_resume_noirq.patch new file mode 100644 index 0000000000..0b9c4bc404 --- /dev/null +++ b/queue-6.12/pci-dwc-invoke-post_init-in-dw_pcie_resume_noirq.patch @@ -0,0 +1,46 @@ +From b95d3b307d77cd171596b2883f764727a7ea69c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Oct 2025 11:04:25 +0800 +Subject: PCI: dwc: Invoke post_init in dw_pcie_resume_noirq() + +From: Richard Zhu + +[ Upstream commit c577ce2881f9c76892de5ffc1a122e3ef427ecee ] + +In some SoCs like i.MX95, CLKREQ# is pulled low by the controller driver +before link up. After link up, if the 'supports-clkreq' property is +specified in DT, the driver will release CLKREQ# so that it can go high and +the endpoint can pull it low whenever required i.e., during exit from L1 +Substates. + +Hence, at the end of dw_pcie_resume_noirq(), invoke the '.post_init()' +callback if exists to perform the above mentioned action. + +Signed-off-by: Richard Zhu +[mani: reworded description] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20251015030428.2980427-9-hongxing.zhu@nxp.com +Stable-dep-of: edb5ca3262e2 ("PCI: dwc: Perform cleanup in the error path of dw_pcie_resume_noirq()") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-host.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c +index 3e3168204e303..92fd4810f2e21 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -990,6 +990,9 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci) + if (ret) + return ret; + ++ if (pci->pp.ops->post_init) ++ pci->pp.ops->post_init(&pci->pp); ++ + return ret; + } + EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); +-- +2.53.0 + diff --git a/queue-6.12/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch b/queue-6.12/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch new file mode 100644 index 0000000000..bd0d49f693 --- /dev/null +++ b/queue-6.12/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch @@ -0,0 +1,60 @@ +From e90e22c95f7433fd649e1020c28c1180d881cdd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 19:09:51 +0530 +Subject: PCI: dwc: Perform cleanup in the error path of dw_pcie_resume_noirq() + +From: Manivannan Sadhasivam + +[ Upstream commit edb5ca3262e2255cf938a5948709d3472d4871ad ] + +If the dw_pcie_resume_noirq() API fails, it just returns the errno without +doing cleanup in the error path, leading to resource leak. + +So perform cleanup in the error path. + +Fixes: 4774faf854f5 ("PCI: dwc: Implement generic suspend/resume functionality") +Reported-by: Senchuan Zhang +Closes: https://lore.kernel.org/linux-pci/78296255.3869.19c8eb694d6.Coremail.zhangsenchuan@eswincomputing.com +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260226133951.296743-1-mani@kernel.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-host.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c +index 92fd4810f2e21..deda5b040d7a0 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -984,15 +984,24 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci) + + ret = dw_pcie_start_link(pci); + if (ret) +- return ret; ++ goto err_deinit; + + ret = dw_pcie_wait_for_link(pci); +- if (ret) +- return ret; ++ if (ret == -ETIMEDOUT) ++ goto err_stop_link; + + if (pci->pp.ops->post_init) + pci->pp.ops->post_init(&pci->pp); + ++ return 0; ++ ++err_stop_link: ++ dw_pcie_stop_link(pci); ++ ++err_deinit: ++ if (pci->pp.ops->deinit) ++ pci->pp.ops->deinit(&pci->pp); ++ + return ret; + } + EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); +-- +2.53.0 + diff --git a/queue-6.12/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch b/queue-6.12/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch new file mode 100644 index 0000000000..d0a4814e22 --- /dev/null +++ b/queue-6.12/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch @@ -0,0 +1,48 @@ +From 8438f368d09d1d6f5ce4ef6182719d85a67519c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 00:10:50 +0900 +Subject: PCI: dwc: rcar-gen4: Change EPC BAR alignment to 4K as per the + documentation + +From: Koichiro Den + +[ Upstream commit 13f55a7ca773c731a1e645934c1ae48577f48785 ] + +R-Car S4 Series (R8A779F[4-7]*) EP controller uses a 4K minimum iATU region +size (CX_ATU_MIN_REGION_SIZE = 4K) as per R19UH0161EJ0130 Rev.1.30. Also, +the controller itself can only be configured in the range 4 KB to 64 KB, so +the current 1 MB alignment requirement is incorrect. + +Hence, change the alignment to the min size 4K as per the documentation. + +This also fixes needless unusability of BAR4 on this platform when the +target address is fixed, such as for doorbell targets. + +Fixes: e311b3834dfa ("PCI: rcar-gen4: Add endpoint mode support") +Signed-off-by: Koichiro Den +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260305151050.1834007-1-den@valinux.co.jp +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c +index 397c2f9477a15..8dcb63f813beb 100644 +--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c ++++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c +@@ -427,7 +427,7 @@ static const struct pci_epc_features rcar_gen4_pcie_epc_features = { + .bar[BAR_3] = { .type = BAR_RESERVED, }, + .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256 }, + .bar[BAR_5] = { .type = BAR_RESERVED, }, +- .align = SZ_1M, ++ .align = SZ_4K, + }; + + static const struct pci_epc_features* +-- +2.53.0 + diff --git a/queue-6.12/pci-enable-atomicops-only-if-root-port-supports-them.patch b/queue-6.12/pci-enable-atomicops-only-if-root-port-supports-them.patch new file mode 100644 index 0000000000..83de6e2301 --- /dev/null +++ b/queue-6.12/pci-enable-atomicops-only-if-root-port-supports-them.patch @@ -0,0 +1,110 @@ +From 264460a6f20f369efe3f5b9c2aeefa88d2f022fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:09:45 +0200 +Subject: PCI: Enable AtomicOps only if Root Port supports them + +From: Gerd Bayer + +[ Upstream commit 1ae8c4ce157037e266184064a182af9ef9af278b ] + +When inspecting the config space of a Connect-X physical function in an +s390 system after it was initialized by the mlx5_core device driver, we +found the function to be enabled to request AtomicOps despite the Root Port +lacking support for completing them: + + 00:00.1 Ethernet controller: Mellanox Technologies MT2894 Family [ConnectX-6 Lx] + Subsystem: Mellanox Technologies Device 0002 + DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- + AtomicOpsCtl: ReqEn+ + +On s390 and many virtualized guests, the Endpoint is visible but the Root +Port is not. In this case, pci_enable_atomic_ops_to_root() previously +enabled AtomicOps in the Endpoint even though it can't tell whether the +Root Port supports them as a completer. + +Change pci_enable_atomic_ops_to_root() to fail if there's no Root Port or +the Root Port doesn't support AtomicOps. + +Fixes: 430a23689dea ("PCI: Add pci_enable_atomic_ops_to_root()") +Reported-by: Alexander Schmidt +Signed-off-by: Gerd Bayer +[bhelgaas: commit log, check RP first to simplify flow] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260330-fix_pciatops-v7-2-f601818417e8@linux.ibm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 41 ++++++++++++++++++++--------------------- + 1 file changed, 20 insertions(+), 21 deletions(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 2c8d0c1c317e4..d44c07bb0a229 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -3850,8 +3850,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) + */ + int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + { +- struct pci_bus *bus = dev->bus; +- struct pci_dev *bridge; ++ struct pci_dev *root, *bridge; + u32 cap, ctl2; + + /* +@@ -3881,35 +3880,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + return -EINVAL; + } + +- while (bus->parent) { +- bridge = bus->self; ++ root = pcie_find_root_port(dev); ++ if (!root) ++ return -EINVAL; + +- pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap); ++ pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); ++ if ((cap & cap_mask) != cap_mask) ++ return -EINVAL; + ++ bridge = pci_upstream_bridge(dev); ++ while (bridge != root) { + switch (pci_pcie_type(bridge)) { +- /* Ensure switch ports support AtomicOp routing */ + case PCI_EXP_TYPE_UPSTREAM: +- case PCI_EXP_TYPE_DOWNSTREAM: +- if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) +- return -EINVAL; +- break; +- +- /* Ensure root port supports all the sizes we care about */ +- case PCI_EXP_TYPE_ROOT_PORT: +- if ((cap & cap_mask) != cap_mask) +- return -EINVAL; +- break; +- } +- +- /* Ensure upstream ports don't block AtomicOps on egress */ +- if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) { ++ /* Upstream ports must not block AtomicOps on egress */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, + &ctl2); + if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK) + return -EINVAL; ++ fallthrough; ++ ++ /* All switch ports need to route AtomicOps */ ++ case PCI_EXP_TYPE_DOWNSTREAM: ++ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, ++ &cap); ++ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) ++ return -EINVAL; ++ break; + } + +- bus = bus->parent; ++ bridge = pci_upstream_bridge(bridge); + } + + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, +-- +2.53.0 + diff --git a/queue-6.12/pci-endpoint-align-pci_epc_set_msix-pci_epc_ops-set_.patch b/queue-6.12/pci-endpoint-align-pci_epc_set_msix-pci_epc_ops-set_.patch new file mode 100644 index 0000000000..540a7855ec --- /dev/null +++ b/queue-6.12/pci-endpoint-align-pci_epc_set_msix-pci_epc_ops-set_.patch @@ -0,0 +1,189 @@ +From fff6721dc982a2c7afea2b503aefae6f1b4d050d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 May 2025 09:43:19 +0200 +Subject: PCI: endpoint: Align pci_epc_set_msix(), pci_epc_ops::set_msix() + nr_irqs encoding + +From: Niklas Cassel + +[ Upstream commit de0321bcc5fdd83631f0c2a6fdebfe0ad4e23449 ] + +The kdoc for pci_epc_set_msix() says: +"Invoke to set the required number of MSI-X interrupts." + +The kdoc for the callback pci_epc_ops->set_msix() says: +"ops to set the requested number of MSI-X interrupts in the MSI-X +capability register" + +pci_epc_ops::set_msix() does however expect the parameter 'interrupts' to +be in the encoding as defined by the Table Size field. Nowhere in the +kdoc does it say that the number of interrupts should be in Table Size +encoding. + +It is very confusing that the API pci_epc_set_msix() and the callback +function pci_epc_ops::set_msix() both take a parameter named 'interrupts', +but they expect completely different encodings. + +Clean up the API and the callback function to have the same semantics, +i.e. the parameter represents the number of interrupts, regardless of the +internal encoding of that value. + +Also rename the parameter 'interrupts' to 'nr_irqs', in both the wrapper +function and the callback function, such that the name is unambiguous. + +[bhelgaas: more specific subject] + +Signed-off-by: Niklas Cassel +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Cc: stable+noautosel@kernel.org # this is simply a cleanup +Link: https://patch.msgid.link/20250514074313.283156-14-cassel@kernel.org +Stable-dep-of: 271d0b1f058a ("PCI: dwc: ep: Fix MSI-X Table Size configuration in dw_pcie_ep_set_msix()") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/cadence/pcie-cadence-ep.c | 8 +++----- + drivers/pci/controller/dwc/pcie-designware-ep.c | 7 +++---- + drivers/pci/endpoint/pci-epc-core.c | 11 +++++------ + include/linux/pci-epc.h | 6 +++--- + 4 files changed, 14 insertions(+), 18 deletions(-) + +diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c +index f700e8c490822..55bd13a2496e5 100644 +--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c ++++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c +@@ -285,21 +285,19 @@ static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) + } + + static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, +- u16 interrupts, enum pci_barno bir, +- u32 offset) ++ u16 nr_irqs, enum pci_barno bir, u32 offset) + { + struct cdns_pcie_ep *ep = epc_get_drvdata(epc); + struct cdns_pcie *pcie = &ep->pcie; + u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; + u32 val, reg; +- u16 actual_interrupts = interrupts + 1; + + fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); + + reg = cap + PCI_MSIX_FLAGS; + val = cdns_pcie_ep_fn_readw(pcie, fn, reg); + val &= ~PCI_MSIX_FLAGS_QSIZE; +- val |= interrupts; /* 0's based value */ ++ val |= nr_irqs - 1; /* encoded as N-1 */ + cdns_pcie_ep_fn_writew(pcie, fn, reg, val); + + /* Set MSIX BAR and offset */ +@@ -309,7 +307,7 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, + + /* Set PBA BAR and offset. BAR must match MSIX BAR */ + reg = cap + PCI_MSIX_PBA; +- val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; ++ val = (offset + (nr_irqs * PCI_MSIX_ENTRY_SIZE)) | bir; + cdns_pcie_ep_fn_writel(pcie, fn, reg, val); + + return 0; +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index 189675747b2bc..a23af31d1e2c3 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -406,13 +406,12 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) + } + + static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, +- u16 interrupts, enum pci_barno bir, u32 offset) ++ u16 nr_irqs, enum pci_barno bir, u32 offset) + { + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct dw_pcie_ep_func *ep_func; + u32 val, reg; +- u16 actual_interrupts = interrupts + 1; + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) +@@ -423,7 +422,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + reg = ep_func->msix_cap + PCI_MSIX_FLAGS; + val = dw_pcie_ep_readw_dbi(ep, func_no, reg); + val &= ~PCI_MSIX_FLAGS_QSIZE; +- val |= interrupts; /* 0's based value */ ++ val |= nr_irqs - 1; /* encoded as N-1 */ + dw_pcie_writew_dbi(pci, reg, val); + + reg = ep_func->msix_cap + PCI_MSIX_TABLE; +@@ -431,7 +430,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + dw_pcie_ep_writel_dbi(ep, func_no, reg, val); + + reg = ep_func->msix_cap + PCI_MSIX_PBA; +- val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; ++ val = (offset + (nr_irqs * PCI_MSIX_ENTRY_SIZE)) | bir; + dw_pcie_ep_writel_dbi(ep, func_no, reg, val); + + dw_pcie_dbi_ro_wr_dis(pci); +diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c +index 75c6688290034..03d6949447141 100644 +--- a/drivers/pci/endpoint/pci-epc-core.c ++++ b/drivers/pci/endpoint/pci-epc-core.c +@@ -382,29 +382,28 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msix); + * @epc: the EPC device on which MSI-X has to be configured + * @func_no: the physical endpoint function number in the EPC device + * @vfunc_no: the virtual endpoint function number in the physical function +- * @interrupts: number of MSI-X interrupts required by the EPF ++ * @nr_irqs: number of MSI-X interrupts required by the EPF + * @bir: BAR where the MSI-X table resides + * @offset: Offset pointing to the start of MSI-X table + * + * Invoke to set the required number of MSI-X interrupts. + */ +-int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, +- u16 interrupts, enum pci_barno bir, u32 offset) ++int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 nr_irqs, ++ enum pci_barno bir, u32 offset) + { + int ret; + + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) + return -EINVAL; + +- if (interrupts < 1 || interrupts > 2048) ++ if (nr_irqs < 1 || nr_irqs > 2048) + return -EINVAL; + + if (!epc->ops->set_msix) + return 0; + + mutex_lock(&epc->lock); +- ret = epc->ops->set_msix(epc, func_no, vfunc_no, interrupts - 1, bir, +- offset); ++ ret = epc->ops->set_msix(epc, func_no, vfunc_no, nr_irqs, bir, offset); + mutex_unlock(&epc->lock); + + return ret; +diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h +index de8cc3658220b..8a275df496fb3 100644 +--- a/include/linux/pci-epc.h ++++ b/include/linux/pci-epc.h +@@ -103,7 +103,7 @@ struct pci_epc_ops { + u8 interrupts); + int (*get_msi)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); + int (*set_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, +- u16 interrupts, enum pci_barno, u32 offset); ++ u16 nr_irqs, enum pci_barno, u32 offset); + int (*get_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); + int (*raise_irq)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + unsigned int type, u16 interrupt_num); +@@ -283,8 +283,8 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + u8 interrupts); + int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no); +-int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, +- u16 interrupts, enum pci_barno, u32 offset); ++int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 nr_irqs, ++ enum pci_barno, u32 offset); + int pci_epc_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no); + int pci_epc_map_msi_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + phys_addr_t phys_addr, u8 interrupt_num, +-- +2.53.0 + diff --git a/queue-6.12/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch b/queue-6.12/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch new file mode 100644 index 0000000000..c017ab86ef --- /dev/null +++ b/queue-6.12/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch @@ -0,0 +1,55 @@ +From 76fb6a81b6e1a14f709173ea3c88732fbb43b094 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 17:35:41 +0800 +Subject: PCI: mediatek-gen3: Prevent leaking IRQ domains when IRQ not found + +From: Chen-Yu Tsai + +[ Upstream commit 5573c44cb3fd01a9f62d569ae9ac870ef5f0e0ba ] + +In mtk_pcie_setup_irq(), the IRQ domains are allocated before the +controller's IRQ is fetched. If the latter fails, the function +directly returns an error, without cleaning up the allocated domains. + +Hence, reverse the order so that the IRQ domains are allocated after the +controller's IRQ is found. + +This was flagged by Sashiko during a review of "[PATCH v6 0/7] PCI: +mediatek-gen3: add power control support". + +Fixes: 814cceebba9b ("PCI: mediatek-gen3: Add INTx support") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Manivannan Sadhasivam +Link: https://sashiko.dev/#/patchset/20260324052002.4072430-1-wenst%40chromium.org +Link: https://patch.msgid.link/20260324093542.18523-1-wenst@chromium.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek-gen3.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c +index 66ce4b5d309bb..b373ece9542c4 100644 +--- a/drivers/pci/controller/pcie-mediatek-gen3.c ++++ b/drivers/pci/controller/pcie-mediatek-gen3.c +@@ -794,14 +794,14 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie) + struct platform_device *pdev = to_platform_device(dev); + int err; + +- err = mtk_pcie_init_irq_domains(pcie); +- if (err) +- return err; +- + pcie->irq = platform_get_irq(pdev, 0); + if (pcie->irq < 0) + return pcie->irq; + ++ err = mtk_pcie_init_irq_domains(pcie); ++ if (err) ++ return err; ++ + irq_set_chained_handler_and_data(pcie->irq, mtk_pcie_irq_handler, pcie); + + return 0; +-- +2.53.0 + diff --git a/queue-6.12/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch b/queue-6.12/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch new file mode 100644 index 0000000000..de421469ef --- /dev/null +++ b/queue-6.12/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch @@ -0,0 +1,48 @@ +From c12de18811bbad40e3ffce3c17fee931057ff81d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:38:50 +0800 +Subject: PCI/NPEM: Set LED_HW_PLUGGABLE for hotplug-capable ports + +From: Richard Cheng + +[ Upstream commit 16d021c878dca22532c984668c9e8cf4722d6a49 ] + +NPEM registers LED classdevs on PCI endpoint that may be behind +hotplug-capable ports. During hot-removal, led_classdev_unregister() calls +led_set_brightness(LED_OFF) which leads to a PCI config read to a +disconnected device, which fails and returns -ENODEV (topology details in +msgid.link below): + + leds 0003:01:00.0:enclosure:ok: Setting an LED's brightness failed (-19) + +The LED core already suppresses this for devices with LED_HW_PLUGGABLE set, +but NPEM never sets it. Add the flag since NPEM LEDs are on hot-pluggable +hardware by nature. + +Fixes: 4e893545ef87 ("PCI/NPEM: Add Native PCIe Enclosure Management support") +Signed-off-by: Richard Cheng +Signed-off-by: Bjorn Helgaas +Reviewed-by: Lukas Wunner +Acked-by: Kai-Heng Feng +Link: https://patch.msgid.link/20260402093850.23075-1-icheng@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/npem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/npem.c b/drivers/pci/npem.c +index 97507e0df769b..b5d012edebf35 100644 +--- a/drivers/pci/npem.c ++++ b/drivers/pci/npem.c +@@ -504,7 +504,7 @@ static int pci_npem_set_led_classdev(struct npem *npem, struct npem_led *nled) + led->brightness_get = brightness_get; + led->max_brightness = 1; + led->default_trigger = "none"; +- led->flags = 0; ++ led->flags = LED_HW_PLUGGABLE; + + ret = led_classdev_register(&npem->dev->dev, led); + if (ret) +-- +2.53.0 + diff --git a/queue-6.12/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch b/queue-6.12/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch new file mode 100644 index 0000000000..9b724ddc45 --- /dev/null +++ b/queue-6.12/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch @@ -0,0 +1,104 @@ +From cd7da04737b5890718e3637269caeae22453ba86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 07:26:34 +0530 +Subject: PCI: qcom: Advertise Hotplug Slot Capability with no Command + Completion support + +From: Krishna Chaitanya Chundru + +[ Upstream commit 33a76fc3c3e61386524479b99f35423bd3d9a895 ] + +Qcom PCIe Root Ports advertise hotplug capability in hardware, but do not +support hotplug command completion. As a result, the hotplug commands +issued by the pciehp driver never gets completion notification, leading to +repeated timeout warnings and multi-second delays during boot and +suspend/resume. + +Commit a54db86ddc153 ("PCI: qcom: Do not advertise hotplug capability for +IPs v2.7.0 and v1.9.0") mistakenly assumed that the Root Ports doesn't +support Hotplug due to timeouts and disabled the Hotplug functionality +altogether. But the Root Ports does support reporting Hotplug events like +DL_Up/Down events. + +So to fix the command completion timeout issues, just set the No Command +Completed Support (NCCS) bit and enable Hotplug in Slot Capability field +back. + +Fixes: a54db86ddc153 ("PCI: qcom: Do not advertise hotplug capability for IPs v2.7.0 and v1.9.0") +Signed-off-by: Krishna Chaitanya Chundru +[mani: renamed function, commit log and added comment] +Signed-off-by: Manivannan Sadhasivam +Tested-by: Konrad Dybcio # Hamoa CRD, tunneled link +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260314-hotplug-v1-1-96ac87d93867@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-qcom.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c +index 5d27cd149f512..ae0f36e270baa 100644 +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -329,15 +329,20 @@ static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci) + dw_pcie_dbi_ro_wr_dis(pci); + } + +-static void qcom_pcie_clear_hpc(struct dw_pcie *pci) ++static void qcom_pcie_set_slot_nccs(struct dw_pcie *pci) + { + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 val; + + dw_pcie_dbi_ro_wr_en(pci); + ++ /* ++ * Qcom PCIe Root Ports do not support generating command completion ++ * notifications for the Hot-Plug commands. So set the NCCS field to ++ * avoid waiting for the completions. ++ */ + val = readl(pci->dbi_base + offset + PCI_EXP_SLTCAP); +- val &= ~PCI_EXP_SLTCAP_HPC; ++ val |= PCI_EXP_SLTCAP_NCCS; + writel(val, pci->dbi_base + offset + PCI_EXP_SLTCAP); + + dw_pcie_dbi_ro_wr_dis(pci); +@@ -532,7 +537,7 @@ static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie) + writel(CFG_BRIDGE_SB_INIT, + pci->dbi_base + AXI_MSTR_RESP_COMP_CTRL1); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -612,7 +617,7 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT); + } + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -705,7 +710,7 @@ static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie) + val |= EN; + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -1009,7 +1014,7 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) + writel(WR_NO_SNOOP_OVERIDE_EN | RD_NO_SNOOP_OVERIDE_EN, + pcie->parf + PARF_NO_SNOOP_OVERIDE); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch b/queue-6.12/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch new file mode 100644 index 0000000000..ceb3039dfe --- /dev/null +++ b/queue-6.12/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch @@ -0,0 +1,108 @@ +From b0b142e2bdc2b9f24dd410bfff6813d16e99d19c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:50 +0530 +Subject: PCI: tegra194: Allow system suspend when the Endpoint link is not up + +From: Vidya Sagar + +[ Upstream commit c76f8eae7d4695b1176c4ea5eb93c17e16a20272 ] + +Host software initiates the L2 sequence. PCIe link is kept in L2 state +during suspend. If Endpoint mode is enabled and the link is up, the +software cannot proceed with suspend. However, when the PCIe Endpoint +driver is probed, but the PCIe link is not up, Tegra can go into suspend +state. So, allow system to suspend in this case. + +Fixes: de2bbf2b71bb ("PCI: tegra194: Don't allow suspend when Tegra PCIe is in EP mode") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-10-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 31 +++++++++++++++++----- + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 625660d4f747c..bf7acdb725a33 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2301,16 +2301,28 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev) + gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0); + } + +-static int tegra_pcie_dw_suspend_late(struct device *dev) ++static int tegra_pcie_dw_suspend(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); +- u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n"); +- return -EPERM; ++ if (pcie->ep_state == EP_STATE_ENABLED) { ++ dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n"); ++ return -EPERM; ++ } ++ ++ disable_irq(pcie->pex_rst_irq); ++ return 0; + } + ++ return 0; ++} ++ ++static int tegra_pcie_dw_suspend_late(struct device *dev) ++{ ++ struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); ++ u32 val; ++ + if (!pcie->link_state) + return 0; + +@@ -2330,6 +2342,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2344,6 +2359,9 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + int ret; + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2376,8 +2394,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev) + u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Suspend is not supported in EP mode"); +- return -ENOTSUPP; ++ enable_irq(pcie->pex_rst_irq); ++ return 0; + } + + if (!pcie->link_state) +@@ -2482,6 +2500,7 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = { + }; + + static const struct dev_pm_ops tegra_pcie_dw_pm_ops = { ++ .suspend = tegra_pcie_dw_suspend, + .suspend_late = tegra_pcie_dw_suspend_late, + .suspend_noirq = tegra_pcie_dw_suspend_noirq, + .resume_noirq = tegra_pcie_dw_resume_noirq, +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-disable-direct-speed-change-for-endpoin.patch b/queue-6.12/pci-tegra194-disable-direct-speed-change-for-endpoin.patch new file mode 100644 index 0000000000..363a1870cc --- /dev/null +++ b/queue-6.12/pci-tegra194-disable-direct-speed-change-for-endpoin.patch @@ -0,0 +1,52 @@ +From e14f6fd2c1a15e9c7511857426c21a156eed7c9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:48 +0530 +Subject: PCI: tegra194: Disable direct speed change for Endpoint mode + +From: Vidya Sagar + +[ Upstream commit 976f6763f57970388bcd7118931f33f447916927 ] + +Pre-silicon simulation showed the controller operating in Endpoint mode +initiating link speed change after completing Secondary Bus Reset. Ideally, +the Root Port or the Switch Downstream Port should initiate the link speed +change post SBR, not the Endpoint. + +So, as per the hardware team recommendation, disable direct speed change +for the Endpoint mode to prevent it from initiating speed change after the +physical layer link is up at Gen1, leaving speed change ownership with the +host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-8-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index fcc9f724147c4..42a8bbfee3f9a 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1830,6 +1830,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); ++ val &= ~PORT_LOGIC_SPEED_CHANGE; ++ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); ++ + if (pcie->update_fc_fixup) { + val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); + val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-disable-ltssm-after-transition-to-detec.patch b/queue-6.12/pci-tegra194-disable-ltssm-after-transition-to-detec.patch new file mode 100644 index 0000000000..f971d4ee88 --- /dev/null +++ b/queue-6.12/pci-tegra194-disable-ltssm-after-transition-to-detec.patch @@ -0,0 +1,92 @@ +From e5ddcacef318fa3435c44f80e4532b5b0c2b3f31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:44 +0530 +Subject: PCI: tegra194: Disable LTSSM after transition to Detect on surprise + link down + +From: Manikanta Maddireddy + +[ Upstream commit 9fa0c242f8d7acf1b124d4462d18f4023573ac1c ] + +After the link reaches a Detect-related LTSSM state, disable LTSSM so it +does not keep toggling between Polling and Detect. Do this by polling for +the Detect state first, then clearing APPL_CTRL_LTSSM_EN in both +tegra_pcie_dw_pme_turnoff() and pex_ep_event_pex_rst_assert(). + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-4-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 29 ++++++++++++---------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index e64a0360c7ce7..c83457adf5782 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1611,14 +1611,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_PINMUX_PEX_RST; + appl_writel(pcie, data, APPL_PINMUX); + +- /* +- * Some cards do not go to detect state even after de-asserting +- * PERST#. So, de-assert LTSSM to bring link to detect state. +- */ +- data = readl(pcie->appl_base + APPL_CTRL); +- data &= ~APPL_CTRL_LTSSM_EN; +- writel(data, pcie->appl_base + APPL_CTRL); +- + err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1627,6 +1619,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); ++ ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ data = readl(pcie->appl_base + APPL_CTRL); ++ data &= ~APPL_CTRL_LTSSM_EN; ++ writel(data, pcie->appl_base + APPL_CTRL); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1708,11 +1708,6 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (pcie->ep_state == EP_STATE_DISABLED) + return; + +- /* Disable LTSSM */ +- val = appl_readl(pcie, APPL_CTRL); +- val &= ~APPL_CTRL_LTSSM_EN; +- appl_writel(pcie, val, APPL_CTRL); +- + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1723,6 +1718,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (ret) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ val = appl_readl(pcie, APPL_CTRL); ++ val &= ~APPL_CTRL_LTSSM_EN; ++ appl_writel(pcie, val, APPL_CTRL); ++ + reset_control_assert(pcie->core_rst); + + tegra_pcie_disable_phy(pcie); +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch b/queue-6.12/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch new file mode 100644 index 0000000000..54d33f3926 --- /dev/null +++ b/queue-6.12/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch @@ -0,0 +1,52 @@ +From da28d7cbd1ed60d473e82c32e6b9719d682d8a3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:46 +0530 +Subject: PCI: tegra194: Disable PERST# IRQ only in Endpoint mode + +From: Manikanta Maddireddy + +[ Upstream commit 40658a31b6e134169c648041efc84944c4c71dcd ] + +The PERST# GPIO interrupt is only registered when the controller is +operating in Endpoint mode. In Root Port mode, the PERST# GPIO is +configured as an output to control downstream devices, and no interrupt is +registered for it. + +Currently, tegra_pcie_dw_stop_link() unconditionally calls disable_irq() +on pex_rst_irq, which causes issues in Root Port mode where this IRQ is +not registered. + +Fix this by only disabling the PERST# IRQ when operating in Endpoint mode, +where the interrupt is actually registered and used to detect PERST# +assertion/deassertion from the host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-6-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index d2a06a34137d7..4b88cfd1fa64e 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1042,7 +1042,8 @@ static void tegra_pcie_dw_stop_link(struct dw_pcie *pci) + { + struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); + +- disable_irq(pcie->pex_rst_irq); ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ disable_irq(pcie->pex_rst_irq); + } + + static const struct dw_pcie_ops tegra_dw_pcie_ops = { +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch b/queue-6.12/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch new file mode 100644 index 0000000000..c92860b34e --- /dev/null +++ b/queue-6.12/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch @@ -0,0 +1,111 @@ +From 1af2699d84a5bfd1ebea131aa7ab3313d3055c86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:45 +0530 +Subject: PCI: tegra194: Don't force the device into the D0 state before L2 + +From: Vidya Sagar + +[ Upstream commit 71d9f67701e1affc82d18ca88ae798c5361beddf ] + +As per PCIe CEM r6.0, sec 2.3, the PCIe Endpoint device should be in D3cold +to assert WAKE# pin. The previous workaround that forced downstream devices +to D0 before taking the link to L2 cited PCIe r4.0, sec 5.2, "Link State +Power Management"; however, that spec does not explicitly require putting +the device into D0 and only indicates that power removal may be initiated +without transitioning to D3hot. + +Remove the D0 workaround so that Endpoint devices can use wake +functionality (WAKE# from D3). With some Endpoints the link may not enter +L2 when they remain in D3, but the Root Port continues with the usual flow +after PME timeout, so there is no functional issue. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-5-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 41 ---------------------- + 1 file changed, 41 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index f35a5e107f3fd..d2a06a34137d7 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1275,44 +1275,6 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, + return 0; + } + +-static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) +-{ +- struct dw_pcie_rp *pp = &pcie->pci.pp; +- struct pci_bus *child, *root_port_bus = NULL; +- struct pci_dev *pdev; +- +- /* +- * link doesn't go into L2 state with some of the endpoints with Tegra +- * if they are not in D0 state. So, need to make sure that immediate +- * downstream devices are in D0 state before sending PME_TurnOff to put +- * link into L2 state. +- * This is as per PCI Express Base r4.0 v1.0 September 27-2017, +- * 5.2 Link State Power Management (Page #428). +- */ +- +- list_for_each_entry(child, &pp->bridge->bus->children, node) { +- if (child->parent == pp->bridge->bus) { +- root_port_bus = child; +- break; +- } +- } +- +- if (!root_port_bus) { +- dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); +- return; +- } +- +- /* Bring downstream devices to D0 if they are not already in */ +- list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { +- if (PCI_SLOT(pdev->devfn) == 0) { +- if (pci_set_power_state(pdev, PCI_D0)) +- dev_err(pcie->dev, +- "Failed to transition %s to D0 state\n", +- dev_name(&pdev->dev)); +- } +- } +-} +- + static int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie) + { + pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3"); +@@ -1642,7 +1604,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + + static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) + { +- tegra_pcie_downstream_dev_to_D0(pcie); + dw_pcie_host_deinit(&pcie->pci.pp); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); +@@ -2367,7 +2328,6 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + if (!pcie->link_state) + return 0; + +- tegra_pcie_downstream_dev_to_D0(pcie); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); + +@@ -2441,7 +2401,6 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev) + return; + + debugfs_remove_recursive(pcie->debugfs); +- tegra_pcie_downstream_dev_to_D0(pcie); + + disable_irq(pcie->pci.pp.irq); + if (IS_ENABLED(CONFIG_PCI_MSI)) +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch b/queue-6.12/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch new file mode 100644 index 0000000000..1920857f95 --- /dev/null +++ b/queue-6.12/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch @@ -0,0 +1,79 @@ +From 8556c0c4135fae0c67b3dcf5f80fc3631b46b363 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:55 +0530 +Subject: PCI: tegra194: Fix CBB timeout caused by DBI access before core + power-on + +From: Manikanta Maddireddy + +[ Upstream commit 34b3eef48d980cd37b876e128bbf314f69fb5d70 ] + +When PERST# is deasserted twice (assert -> deassert -> assert -> deassert), +a CBB (Control Backbone) timeout occurs at DBI register offset 0x8bc +(PCIE_MISC_CONTROL_1_OFF). This happens because pci_epc_deinit_notify() +and dw_pcie_ep_cleanup() are called before reset_control_deassert() powers +on the controller core. + +The call chain that causes the timeout: + + pex_ep_event_pex_rst_deassert() + pci_epc_deinit_notify() + pci_epf_test_epc_deinit() + pci_epf_test_clear_bar() + pci_epc_clear_bar() + dw_pcie_ep_clear_bar() + __dw_pcie_ep_reset_bar() + dw_pcie_dbi_ro_wr_en() <- Accesses 0x8bc DBI register + reset_control_deassert(pcie->core_rst) <- Core powered on HERE + +The DBI registers, including PCIE_MISC_CONTROL_1_OFF (0x8bc), are only +accessible after the controller core is powered on via +reset_control_deassert(pcie->core_rst). Accessing them before this point +results in a CBB timeout because the hardware is not yet operational. + +Fix this by moving pci_epc_deinit_notify() and dw_pcie_ep_cleanup() to +after reset_control_deassert(pcie->core_rst), ensuring the controller is +fully powered on before any DBI register accesses occur. + +Fixes: 40e2125381dc ("PCI: tegra194: Move controller cleanups to pex_ep_event_pex_rst_deassert()") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-15-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 5faac8b7190ca..368c50abd4fc4 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1757,10 +1757,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + goto fail_phy; + } + +- /* Perform cleanup that requires refclk */ +- pci_epc_deinit_notify(pcie->pci.ep.epc); +- dw_pcie_ep_cleanup(&pcie->pci.ep); +- + /* Clear any stale interrupt statuses */ + appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0); + appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0); +@@ -1830,6 +1826,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ /* Perform cleanup that requires refclk and core reset deasserted */ ++ pci_epc_deinit_notify(pcie->pci.ep.epc); ++ dw_pcie_ep_cleanup(&pcie->pci.ep); ++ + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-fix-polling-delay-for-l2-state.patch b/queue-6.12/pci-tegra194-fix-polling-delay-for-l2-state.patch new file mode 100644 index 0000000000..0c755ffdd8 --- /dev/null +++ b/queue-6.12/pci-tegra194-fix-polling-delay-for-l2-state.patch @@ -0,0 +1,59 @@ +From 357feb799e393cf6f7ff82dc343750efa5daf91c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:42 +0530 +Subject: PCI: tegra194: Fix polling delay for L2 state + +From: Vidya Sagar + +[ Upstream commit adaffed907f14f954096555665ad6af2ae724d83 ] + +As per PCIe r7.0, sec 5.3.3.2.1, after sending PME_Turn_Off message, Root +Port should wait for 1-10 msec for PME_TO_Ack message. Currently, driver is +polling for 10 msec with 1 usec delay which is aggressive. Use existing +macro PCIE_PME_TO_L2_TIMEOUT_US to poll for 10 msec with 1 msec delay. +Since this function is used in non-atomic context only, use non-atomic poll +function. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index c2d626b090e3c..8f2f60fc032eb 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -198,8 +198,6 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define PME_ACK_TIMEOUT 10000 +- + #define LTSSM_TIMEOUT 50000 /* 50ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 +@@ -1570,9 +1568,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) + val |= APPL_PM_XMT_TURNOFF_STATE; + appl_writel(pcie, val, APPL_RADM_STATUS); + +- return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val, +- val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, +- 1, PME_ACK_TIMEOUT); ++ return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, ++ val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, ++ PCIE_PME_TO_L2_TIMEOUT_US/10, ++ PCIE_PME_TO_L2_TIMEOUT_US); + } + + static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-free-up-endpoint-resources-during-remov.patch b/queue-6.12/pci-tegra194-free-up-endpoint-resources-during-remov.patch new file mode 100644 index 0000000000..32a33b3334 --- /dev/null +++ b/queue-6.12/pci-tegra194-free-up-endpoint-resources-during-remov.patch @@ -0,0 +1,49 @@ +From c2a5ed266a8ef0e4126ccdd51e69d86ea070cdc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:51 +0530 +Subject: PCI: tegra194: Free up Endpoint resources during remove() + +From: Vidya Sagar + +[ Upstream commit 8870f02f7868209eb9bdc5dc53540a6262cf9227 ] + +Free up the resources during remove() that were acquired by the DesignWare +driver for the Endpoint mode during probe(). + +Fixes: bb617cbd8151 ("PCI: tegra194: Clean up the exit path for Endpoint mode") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-11-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index bf7acdb725a33..dd08ad8d08cbd 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2282,6 +2282,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) + static void tegra_pcie_dw_remove(struct platform_device *pdev) + { + struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev); ++ struct dw_pcie_ep *ep = &pcie->pci.ep; + + if (pcie->of_data->mode == DW_PCIE_RC_TYPE) { + if (!pcie->link_state) +@@ -2293,6 +2294,7 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev) + } else { + disable_irq(pcie->pex_rst_irq); + pex_ep_event_pex_rst_assert(pcie); ++ dw_pcie_ep_deinit(ep); + } + + pm_runtime_disable(pcie->dev); +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch b/queue-6.12/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch new file mode 100644 index 0000000000..0899e8af9c --- /dev/null +++ b/queue-6.12/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch @@ -0,0 +1,106 @@ +From ae204a14616cce0136a4b91f106ed470af92f5d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:43 +0530 +Subject: PCI: tegra194: Increase LTSSM poll time on surprise link down + +From: Manikanta Maddireddy + +[ Upstream commit 74dd8efe4d6cead433162147333af989a568aac7 ] + +On surprise link down, LTSSM state transits from L0 -> Recovery.RcvrLock -> +Recovery.RcvrSpeed -> Gen1 Recovery.RcvrLock -> Detect. Recovery.RcvrLock +and Recovery.RcvrSpeed transit times are 24 ms and 48 ms respectively, so +the total time from L0 to Detect is ~96 ms. Increase the poll timeout to +120 ms to account for this. + +While at it, add LTSSM state defines for Detect-related states and use them +in the poll condition. Use readl_poll_timeout() instead of +readl_poll_timeout_atomic() in tegra_pcie_dw_pme_turnoff() since that path +runs in non-atomic context. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-3-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 36 +++++++++++++--------- + 1 file changed, 21 insertions(+), 15 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 8f2f60fc032eb..e64a0360c7ce7 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -137,7 +137,11 @@ + #define APPL_DEBUG_PM_LINKST_IN_L0 0x11 + #define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) + #define APPL_DEBUG_LTSSM_STATE_SHIFT 3 +-#define LTSSM_STATE_PRE_DETECT 5 ++#define LTSSM_STATE_DETECT_QUIET 0x00 ++#define LTSSM_STATE_DETECT_ACT 0x08 ++#define LTSSM_STATE_PRE_DETECT_QUIET 0x28 ++#define LTSSM_STATE_DETECT_WAIT 0x30 ++#define LTSSM_STATE_L2_IDLE 0xa8 + + #define APPL_RADM_STATUS 0xE4 + #define APPL_PM_XMT_TURNOFF_STATE BIT(0) +@@ -198,7 +202,8 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define LTSSM_TIMEOUT 50000 /* 50ms */ ++#define LTSSM_DELAY_US 10000 /* 10 ms */ ++#define LTSSM_TIMEOUT_US 120000 /* 120 ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 + +@@ -1614,15 +1619,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_CTRL_LTSSM_EN; + writel(data, pcie->appl_base + APPL_CTRL); + +- err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, +- data, +- ((data & +- APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) +- dev_info(pcie->dev, "Link didn't go to detect state\n"); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1710,12 +1714,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + appl_writel(pcie, val, APPL_CTRL); + + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, +- ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (ret) +- dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + + reset_control_assert(pcie->core_rst); + +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch b/queue-6.12/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch new file mode 100644 index 0000000000..070e9252df --- /dev/null +++ b/queue-6.12/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch @@ -0,0 +1,69 @@ +From 690d04aa8119813ad0dc2125ec9f50eb25ff3a62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Sep 2025 13:40:57 +0530 +Subject: PCI: tegra194: Rename 'root_bus' to 'root_port_bus' in + tegra_pcie_downstream_dev_to_D0() + +From: Manivannan Sadhasivam + +[ Upstream commit e1bd928479fb1fa60e9034b0fdb1ab9f3fa92f33 ] + +In tegra_pcie_downstream_dev_to_D0(), PCI devices are transitioned to D0 +state. For iterating over the devices, first the downstream bus of the Root +Port is searched from the root bus. But the name of the variable that holds +the Root Port downstream bus is named as 'root_bus', which is wrong. + +Rename the variable to 'root_port_bus'. Also, move the comment on 'bringing +the devices to D0' to where the state is set exactly. + +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20250922081057.15209-1-mani@kernel.org +Stable-dep-of: 71d9f67701e1 ("PCI: tegra194: Don't force the device into the D0 state before L2") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index c83457adf5782..f35a5e107f3fd 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1278,7 +1278,7 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, + static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) + { + struct dw_pcie_rp *pp = &pcie->pci.pp; +- struct pci_bus *child, *root_bus = NULL; ++ struct pci_bus *child, *root_port_bus = NULL; + struct pci_dev *pdev; + + /* +@@ -1291,19 +1291,19 @@ static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) + */ + + list_for_each_entry(child, &pp->bridge->bus->children, node) { +- /* Bring downstream devices to D0 if they are not already in */ + if (child->parent == pp->bridge->bus) { +- root_bus = child; ++ root_port_bus = child; + break; + } + } + +- if (!root_bus) { +- dev_err(pcie->dev, "Failed to find downstream devices\n"); ++ if (!root_port_bus) { ++ dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); + return; + } + +- list_for_each_entry(pdev, &root_bus->devices, bus_list) { ++ /* Bring downstream devices to D0 if they are not already in */ ++ list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { + if (PCI_SLOT(pdev->devfn) == 0) { + if (pci_set_power_state(pdev, PCI_D0)) + dev_err(pcie->dev, +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch b/queue-6.12/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch new file mode 100644 index 0000000000..d14caf3f33 --- /dev/null +++ b/queue-6.12/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch @@ -0,0 +1,71 @@ +From 1c9964d3aee3092ba34e9a1c68fa7b97f37c9d72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:49 +0530 +Subject: PCI: tegra194: Set LTR message request before PCIe link up in + Endpoint mode + +From: Vidya Sagar + +[ Upstream commit b256493bf8cacf0e524bf4c10b5c4901d0c6cefe ] + +LTR message should be sent as soon as the Root Port enables LTR in the +Endpoint mode. So set snoop and no-snoop LTR timing and LTR message request +before the PCIe link comes up, so that the LTR message is sent upstream as +soon as LTR is enabled. + +Without programming these values, the Endpoint would send latencies of 0 to +the host, which will be inaccurate. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Jon Hunter +Tested-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-9-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 42a8bbfee3f9a..625660d4f747c 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -487,15 +487,6 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg) + if (val & PCI_COMMAND_MASTER) { + ktime_t timeout; + +- /* 110us for both snoop and no-snoop */ +- val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) | +- FIELD_PREP(PCI_LTR_SCALE_MASK, 2) | +- LTR_MSG_REQ | +- FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) | +- FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) | +- LTR_NOSNOOP_MSG_REQ; +- appl_writel(pcie, val, APPL_LTR_MSG_1); +- + /* Send LTR upstream */ + val = appl_readl(pcie, APPL_LTR_MSG_2); + val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE; +@@ -1828,6 +1819,15 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + val |= APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN; + appl_writel(pcie, val, APPL_INTR_EN_L1_0_0); + ++ /* 110us for both snoop and no-snoop */ ++ val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) | ++ FIELD_PREP(PCI_LTR_SCALE_MASK, 2) | ++ LTR_MSG_REQ | ++ FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) | ++ FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) | ++ LTR_NOSNOOP_MSG_REQ; ++ appl_writel(pcie, val, APPL_LTR_MSG_1); ++ + reset_control_deassert(pcie->core_rst); + + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch b/queue-6.12/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch new file mode 100644 index 0000000000..6ddb0df5ea --- /dev/null +++ b/queue-6.12/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch @@ -0,0 +1,47 @@ +From aab95a4fe1c0216cd9e4e3826aafc7c9f42d0ece Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:47 +0530 +Subject: PCI: tegra194: Use devm_gpiod_get_optional() to parse + "nvidia,refclk-select" + +From: Vidya Sagar + +[ Upstream commit f62bc7917de1374dce86a852ffba8baf9cb7a56a ] + +The GPIO DT property "nvidia,refclk-select", to select the PCIe reference +clock is optional. Use devm_gpiod_get_optional() to get it. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-7-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 4b88cfd1fa64e..fcc9f724147c4 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1184,9 +1184,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) + return err; + } + +- pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, +- "nvidia,refclk-select", +- GPIOD_OUT_HIGH); ++ pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev, ++ "nvidia,refclk-select", ++ GPIOD_OUT_HIGH); + if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { + int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); + const char *level = KERN_ERR; +-- +2.53.0 + diff --git a/queue-6.12/pci-tegra194-use-dwc-ip-core-version.patch b/queue-6.12/pci-tegra194-use-dwc-ip-core-version.patch new file mode 100644 index 0000000000..15b7e59306 --- /dev/null +++ b/queue-6.12/pci-tegra194-use-dwc-ip-core-version.patch @@ -0,0 +1,65 @@ +From 06f0e1533ccab932fb9647868a69c72ffd2385d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:52 +0530 +Subject: PCI: tegra194: Use DWC IP core version + +From: Manikanta Maddireddy + +[ Upstream commit ea60ca067f0f098043610c96a915d162113c1aac ] + +Tegra194 PCIe driver used custom version numbers to detect Tegra194 and +Tegra234 IPs. With version detect logic added, version check results in +mismatch warnings: + + tegra194-pcie 14100000.pcie: Versions don't match (0000562a != 3536322a) + +Use HW version numbers which match to PORT_LOGIC.PCIE_VERSION_OFF in +Tegra194 driver to avoid these kernel warnings. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-12-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.h | 2 ++ + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index 0fad7751490f5..a5f58ac8ea941 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -31,8 +31,10 @@ + #define DW_PCIE_VER_470A 0x3437302a + #define DW_PCIE_VER_480A 0x3438302a + #define DW_PCIE_VER_490A 0x3439302a ++#define DW_PCIE_VER_500A 0x3530302a + #define DW_PCIE_VER_520A 0x3532302a + #define DW_PCIE_VER_540A 0x3534302a ++#define DW_PCIE_VER_562A 0x3536322a + + #define __dw_pcie_ver_cmp(_pci, _ver, _op) \ + ((_pci)->version _op DW_PCIE_VER_ ## _ver) +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index dd08ad8d08cbd..5faac8b7190ca 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -35,8 +35,8 @@ + #include + #include "../../pci.h" + +-#define TEGRA194_DWC_IP_VER 0x490A +-#define TEGRA234_DWC_IP_VER 0x562A ++#define TEGRA194_DWC_IP_VER DW_PCIE_VER_500A ++#define TEGRA234_DWC_IP_VER DW_PCIE_VER_562A + + #define APPL_PINMUX 0x0 + #define APPL_PINMUX_PEX_RST BIT(0) +-- +2.53.0 + diff --git a/queue-6.12/pci-use-generic-driver_override-infrastructure.patch b/queue-6.12/pci-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..22c6b12a68 --- /dev/null +++ b/queue-6.12/pci-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,209 @@ +From 60d17a90b8602ef6b86e6933b42a2c7e0cd44123 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:09 +0100 +Subject: PCI: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit 10a4206a24013be4d558d476010cbf2eb4c9fa64 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 782a985d7af2 ("PCI: Introduce new device binding path using pci_dev.driver_override") +Acked-by: Bjorn Helgaas +Acked-by: Alex Williamson +Tested-by: Gui-Dong Han +Reviewed-by: Gui-Dong Han +Link: https://patch.msgid.link/20260324005919.2408620-6-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/pci/pci-driver.c | 11 +++++++---- + drivers/pci/pci-sysfs.c | 28 ---------------------------- + drivers/pci/probe.c | 1 - + drivers/vfio/pci/vfio_pci_core.c | 5 ++--- + drivers/xen/xen-pciback/pci_stub.c | 6 ++++-- + include/linux/pci.h | 6 ------ + 6 files changed, 13 insertions(+), 44 deletions(-) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index a00a2ce01045f..860d80787d9b1 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -138,9 +138,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + { + struct pci_dynid *dynid; + const struct pci_device_id *found_id = NULL, *ids; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (dev->driver_override && strcmp(dev->driver_override, drv->name)) ++ ret = device_match_driver_override(&dev->dev, &drv->driver); ++ if (ret == 0) + return NULL; + + /* Look at the dynamic ids first, before the static ones */ +@@ -164,7 +166,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + * matching. + */ + if (found_id->override_only) { +- if (dev->driver_override) ++ if (ret > 0) + return found_id; + } else { + return found_id; +@@ -172,7 +174,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + } + + /* driver_override will always match, send a dummy id */ +- if (dev->driver_override) ++ if (ret > 0) + return &pci_device_id_any; + return NULL; + } +@@ -423,7 +425,7 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) + static inline bool pci_device_can_probe(struct pci_dev *pdev) + { + return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe || +- pdev->driver_override); ++ device_has_driver_override(&pdev->dev)); + } + #else + static inline bool pci_device_can_probe(struct pci_dev *pdev) +@@ -1677,6 +1679,7 @@ static void pci_dma_cleanup(struct device *dev) + + const struct bus_type pci_bus_type = { + .name = "pci", ++ .driver_override = true, + .match = pci_bus_match, + .uevent = pci_uevent, + .probe = pci_device_probe, +diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c +index 96f9cf9f8d643..122c182229b33 100644 +--- a/drivers/pci/pci-sysfs.c ++++ b/drivers/pci/pci-sysfs.c +@@ -606,33 +606,6 @@ static ssize_t devspec_show(struct device *dev, + static DEVICE_ATTR_RO(devspec); + #endif + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct pci_dev *pdev = to_pci_dev(dev); +- int ret; +- +- ret = driver_set_override(dev, &pdev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct pci_dev *pdev = to_pci_dev(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", pdev->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *pci_dev_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_resource.attr, +@@ -660,7 +633,6 @@ static struct attribute *pci_dev_attrs[] = { + #ifdef CONFIG_OF + &dev_attr_devspec.attr, + #endif +- &dev_attr_driver_override.attr, + &dev_attr_ari_enabled.attr, + NULL, + }; +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 9e71eb4d1010e..d8c5a957b70e5 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2373,7 +2373,6 @@ static void pci_release_dev(struct device *dev) + pci_release_of_node(pci_dev); + pcibios_release_device(pci_dev); + pci_bus_put(pci_dev->bus); +- kfree(pci_dev->driver_override); + bitmap_free(pci_dev->dma_alias_mask); + dev_dbg(dev, "device released\n"); + kfree(pci_dev); +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index 5f545b45078f8..dd6e73de2e2a0 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -2014,9 +2014,8 @@ static int vfio_pci_bus_notifier(struct notifier_block *nb, + pdev->is_virtfn && physfn == vdev->pdev) { + pci_info(vdev->pdev, "Captured SR-IOV VF %s driver_override\n", + pci_name(pdev)); +- pdev->driver_override = kasprintf(GFP_KERNEL, "%s", +- vdev->vdev.ops->name); +- WARN_ON(!pdev->driver_override); ++ WARN_ON(device_set_driver_override(&pdev->dev, ++ vdev->vdev.ops->name)); + } else if (action == BUS_NOTIFY_BOUND_DRIVER && + pdev->is_virtfn && physfn == vdev->pdev) { + struct pci_driver *drv = pci_dev_driver(pdev); +diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c +index b616b7768c3b9..8b3006078d003 100644 +--- a/drivers/xen/xen-pciback/pci_stub.c ++++ b/drivers/xen/xen-pciback/pci_stub.c +@@ -618,6 +618,8 @@ static int pcistub_seize(struct pci_dev *dev, + return err; + } + ++static struct pci_driver xen_pcibk_pci_driver; ++ + /* Called when 'bind'. This means we must _NOT_ call pci_reset_function or + * other functions that take the sysfs lock. */ + static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) +@@ -629,8 +631,8 @@ static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) + + match = pcistub_match(dev); + +- if ((dev->driver_override && +- !strcmp(dev->driver_override, PCISTUB_DRIVER_NAME)) || ++ if (device_match_driver_override(&dev->dev, ++ &xen_pcibk_pci_driver.driver) > 0 || + match) { + + if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 242ee3843e10e..825e6b3056f15 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -540,12 +540,6 @@ struct pci_dev { + u8 supported_speeds; /* Supported Link Speeds Vector */ + phys_addr_t rom; /* Physical address if not from BAR */ + size_t romlen; /* Length if not from BAR */ +- /* +- * Driver name to force a match. Do not set directly, because core +- * frees it. Use driver_set_override() to set or clear it. +- */ +- const char *driver_override; +- + unsigned long priv_flags; /* Private flags for the PCI driver */ + + /* These methods index pci_reset_fn_methods[] */ +-- +2.53.0 + diff --git a/queue-6.12/pcmcia-fix-garbled-log-messages-for-kern_cont.patch b/queue-6.12/pcmcia-fix-garbled-log-messages-for-kern_cont.patch new file mode 100644 index 0000000000..9270f91794 --- /dev/null +++ b/queue-6.12/pcmcia-fix-garbled-log-messages-for-kern_cont.patch @@ -0,0 +1,55 @@ +From cb0182572e32ab38b7d136817a50f76fb6b07c56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 17:42:56 +0100 +Subject: PCMCIA: Fix garbled log messages for KERN_CONT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit bfeaa6814bd3f9a1f6d525b3b35a03b9a0368961 ] + +For years the PCMCIA info messages are messed up by superfluous +newlines. While f2e6cf76751d ("pcmcia: Convert dev_printk to +dev_") converted the code to pr_cont(), dev_info enforces a \n +via vprintk_store setting LOG_NEWLINE, breaking subsequent pr_cont. + +Fix by logging the device name manually to allow pr_cont to work for +more readable and not \n distorted logs. + +Fixes: f2e6cf76751d ("pcmcia: Convert dev_printk to dev_") +Signed-off-by: René Rebe +Signed-off-by: Dominik Brodowski +Signed-off-by: Sasha Levin +--- + drivers/pcmcia/rsrc_nonstatic.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c +index da494fe451baf..efc439c748862 100644 +--- a/drivers/pcmcia/rsrc_nonstatic.c ++++ b/drivers/pcmcia/rsrc_nonstatic.c +@@ -188,7 +188,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, + int any; + u_char *b, hole, most; + +- dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1); ++ pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1); + + /* First, what does a floating port look like? */ + b = kzalloc(256, GFP_KERNEL); +@@ -410,8 +410,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + struct socket_data *s_data = s->resource_data; + u_long i, j, bad, fail, step; + +- dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:", +- base, base+num-1); ++ pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:", ++ dev_name(&s->dev), base, base+num-1); + bad = fail = 0; + step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + /* don't allow too large steps */ +-- +2.53.0 + diff --git a/queue-6.12/perf-branch-avoid-incrementing-null.patch b/queue-6.12/perf-branch-avoid-incrementing-null.patch new file mode 100644 index 0000000000..719c707b3d --- /dev/null +++ b/queue-6.12/perf-branch-avoid-incrementing-null.patch @@ -0,0 +1,39 @@ +From 3f96d56ff3eab2ebc3ddaee0690b4cef3466ddda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:31:31 -0700 +Subject: perf branch: Avoid incrementing NULL + +From: Ian Rogers + +[ Upstream commit c969a9d7bbf46f983c4a48566b3b2f7340b02296 ] + +If the entry is NULL the value is meaningless so early return NULL to +avoid an increment of NULL. This was happening in calls from +has_stitched_lbr when running the "perf record LBR tests". The return +value isn't used in that case, so returning NULL as no effect. + +Fixes: 42bbabed09ce ("perf tools: Add hw_idx in struct branch_stack") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/branch.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h +index b80c12c74bbbe..90f76910b23fb 100644 +--- a/tools/perf/util/branch.h ++++ b/tools/perf/util/branch.h +@@ -65,6 +65,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl + { + u64 *entry = (u64 *)sample->branch_stack; + ++ if (entry == NULL) ++ return NULL; ++ + entry++; + if (sample->no_hw_idx) + return (struct branch_entry *)entry; +-- +2.53.0 + diff --git a/queue-6.12/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch b/queue-6.12/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch new file mode 100644 index 0000000000..4381d57c3e --- /dev/null +++ b/queue-6.12/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch @@ -0,0 +1,94 @@ +From 397e6d1cebc2281712555a89fe883e7256af8120 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 23:05:52 -0700 +Subject: perf cgroup: Update metric leader in evlist__expand_cgroup + +From: Ian Rogers + +[ Upstream commit c9ef786c0970991578397043f1c819229e2b7197 ] + +When the evlist is expanded the metric leader wasn't being updated. As +the original evsel is deleted this creates a use-after-free in +stat-shadow's prepare_metric. This was detected running the "perf stat +--bpf-counters --for-each-cgroup test" with sanitizers. + +The change itself puts the copied evsel into the priv field (known +unused because of evsel__clone use) and then in a second pass over the +list updates the copied values using the priv pointer. + +Fixes: d1c5a0e86a4e ("perf stat: Add --for-each-cgroup option") +Signed-off-by: Ian Rogers +Acked-by: Sun Jian +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/cgroup.c | 30 +++++++++++++++++++++++------- + 1 file changed, 23 insertions(+), 7 deletions(-) + +diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c +index fbcc0626f9ce2..e172bcdf7fcb1 100644 +--- a/tools/perf/util/cgroup.c ++++ b/tools/perf/util/cgroup.c +@@ -417,7 +417,6 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, + struct rblist *metric_events, bool open_cgroup) + { + struct evlist *orig_list, *tmp_list; +- struct evsel *pos, *evsel, *leader; + struct rblist orig_metric_events; + struct cgroup *cgrp = NULL; + struct cgroup_name *cn; +@@ -456,6 +455,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, + goto out_err; + + list_for_each_entry(cn, &cgroup_list, list) { ++ struct evsel *pos; + char *name; + + if (!cn->used) +@@ -471,21 +471,37 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, + if (cgrp == NULL) + continue; + +- leader = NULL; ++ /* copy the list and set to the new cgroup. */ + evlist__for_each_entry(orig_list, pos) { +- evsel = evsel__clone(/*dest=*/NULL, pos); ++ struct evsel *evsel = evsel__clone(/*dest=*/NULL, pos); ++ + if (evsel == NULL) + goto out_err; + ++ /* stash the copy during the copying. */ ++ pos->priv = evsel; + cgroup__put(evsel->cgrp); + evsel->cgrp = cgroup__get(cgrp); + +- if (evsel__is_group_leader(pos)) +- leader = evsel; +- evsel__set_leader(evsel, leader); +- + evlist__add(tmp_list, evsel); + } ++ /* update leader information using stashed pointer to copy. */ ++ evlist__for_each_entry(orig_list, pos) { ++ struct evsel *evsel = pos->priv; ++ ++ if (evsel__leader(pos)) ++ evsel__set_leader(evsel, evsel__leader(pos)->priv); ++ ++ if (pos->metric_leader) ++ evsel->metric_leader = pos->metric_leader->priv; ++ ++ if (pos->first_wildcard_match) ++ evsel->first_wildcard_match = pos->first_wildcard_match->priv; ++ } ++ /* the stashed copy is no longer used. */ ++ evlist__for_each_entry(orig_list, pos) ++ pos->priv = NULL; ++ + /* cgroup__new() has a refcount, release it here */ + cgroup__put(cgrp); + nr_cgroups++; +-- +2.53.0 + diff --git a/queue-6.12/perf-evsel-add-alternate_hw_config-and-use-in-evsel_.patch b/queue-6.12/perf-evsel-add-alternate_hw_config-and-use-in-evsel_.patch new file mode 100644 index 0000000000..d3ab902319 --- /dev/null +++ b/queue-6.12/perf-evsel-add-alternate_hw_config-and-use-in-evsel_.patch @@ -0,0 +1,463 @@ +From 91fbcef6d82fe0abc66ac18ae58cfbde9db6f527 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Sep 2024 15:48:32 +0100 +Subject: perf evsel: Add alternate_hw_config and use in evsel__match + +From: Ian Rogers + +[ Upstream commit 22a4db3c36034e2b034c5b88414680857fc59cf4 ] + +There are cases where we want to match events like instructions and +cycles with legacy hardware values, in particular in stat-shadow's +hard coded metrics. An evsel's name isn't a good point of reference as +it gets altered, strstr would be too imprecise and re-parsing the +event from its name is silly. Instead, hold the legacy hardware event +name, determined during parsing, in the evsel for this matching case. + +Inline evsel__match2 that is only used in builtin-diff. + +Acked-by: Namhyung Kim +Signed-off-by: Ian Rogers +Acked-by: Kan Liang +Signed-off-by: James Clark +Cc: Yang Jihong +Cc: Dominique Martinet +Cc: Colin Ian King +Cc: Howard Chu +Cc: Yunseong Kim +Cc: Ze Gao +Cc: Yicong Yang +Cc: Weilin Wang +Cc: Will Deacon +Cc: Mike Leach +Cc: Jing Zhang +Cc: Yang Li +Cc: Leo Yan +Cc: ak@linux.intel.com +Cc: Athira Rajeev +Cc: linux-arm-kernel@lists.infradead.org +Cc: Sun Haiyong +Cc: John Garry +Link: https://lore.kernel.org/r/20240926144851.245903-2-james.clark@linaro.org +Signed-off-by: Namhyung Kim +Stable-dep-of: c9ef786c0970 ("perf cgroup: Update metric leader in evlist__expand_cgroup") +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-diff.c | 6 ++-- + tools/perf/util/evsel.c | 21 ++++++++++++ + tools/perf/util/evsel.h | 19 ++--------- + tools/perf/util/parse-events.c | 59 +++++++++++++++++++++------------- + tools/perf/util/parse-events.h | 8 ++++- + tools/perf/util/parse-events.y | 2 +- + tools/perf/util/pmu.c | 6 +++- + tools/perf/util/pmu.h | 2 +- + 8 files changed, 77 insertions(+), 46 deletions(-) + +diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c +index 23326dd203339..82fb7773e03e6 100644 +--- a/tools/perf/builtin-diff.c ++++ b/tools/perf/builtin-diff.c +@@ -469,13 +469,13 @@ static int diff__process_sample_event(const struct perf_tool *tool, + + static struct perf_diff pdiff; + +-static struct evsel *evsel_match(struct evsel *evsel, +- struct evlist *evlist) ++static struct evsel *evsel_match(struct evsel *evsel, struct evlist *evlist) + { + struct evsel *e; + + evlist__for_each_entry(evlist, e) { +- if (evsel__match2(evsel, e)) ++ if ((evsel->core.attr.type == e->core.attr.type) && ++ (evsel->core.attr.config == e->core.attr.config)) + return e; + } + +diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c +index dda107b12b8c6..6e8d70ec05bad 100644 +--- a/tools/perf/util/evsel.c ++++ b/tools/perf/util/evsel.c +@@ -299,6 +299,7 @@ void evsel__init(struct evsel *evsel, + evsel->pmu_name = NULL; + evsel->group_pmu_name = NULL; + evsel->skippable = false; ++ evsel->alternate_hw_config = PERF_COUNT_HW_MAX; + } + + struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx) +@@ -445,6 +446,8 @@ struct evsel *evsel__clone(struct evsel *orig) + if (evsel__copy_config_terms(evsel, orig) < 0) + goto out_err; + ++ evsel->alternate_hw_config = orig->alternate_hw_config; ++ + return evsel; + + out_err: +@@ -1856,6 +1859,24 @@ static int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread) + return 0; + } + ++bool __evsel__match(const struct evsel *evsel, u32 type, u64 config) ++{ ++ ++ u32 e_type = evsel->core.attr.type; ++ u64 e_config = evsel->core.attr.config; ++ ++ if (e_type != type) { ++ return type == PERF_TYPE_HARDWARE && evsel->pmu && evsel->pmu->is_core && ++ evsel->alternate_hw_config == config; ++ } ++ ++ if ((type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) && ++ perf_pmus__supports_extended_type()) ++ e_config &= PERF_HW_EVENT_MASK; ++ ++ return e_config == config; ++} ++ + int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread) + { + if (evsel__is_tool(evsel)) +diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h +index 26574a33a7250..dc0d300776f16 100644 +--- a/tools/perf/util/evsel.h ++++ b/tools/perf/util/evsel.h +@@ -102,6 +102,7 @@ struct evsel { + int bpf_fd; + struct bpf_object *bpf_obj; + struct list_head config_terms; ++ u64 alternate_hw_config; + }; + + /* +@@ -395,26 +396,10 @@ u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sam + struct tep_format_field *evsel__field(struct evsel *evsel, const char *name); + struct tep_format_field *evsel__common_field(struct evsel *evsel, const char *name); + +-static inline bool __evsel__match(const struct evsel *evsel, u32 type, u64 config) +-{ +- if (evsel->core.attr.type != type) +- return false; +- +- if ((type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) && +- perf_pmus__supports_extended_type()) +- return (evsel->core.attr.config & PERF_HW_EVENT_MASK) == config; +- +- return evsel->core.attr.config == config; +-} ++bool __evsel__match(const struct evsel *evsel, u32 type, u64 config); + + #define evsel__match(evsel, t, c) __evsel__match(evsel, PERF_TYPE_##t, PERF_COUNT_##c) + +-static inline bool evsel__match2(struct evsel *e1, struct evsel *e2) +-{ +- return (e1->core.attr.type == e2->core.attr.type) && +- (e1->core.attr.config == e2->core.attr.config); +-} +- + int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread); + + int __evsel__read_on_cpu(struct evsel *evsel, int cpu_map_idx, int thread, bool scale); +diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c +index 9a8be1e46d674..fcc4dab618bee 100644 +--- a/tools/perf/util/parse-events.c ++++ b/tools/perf/util/parse-events.c +@@ -228,7 +228,7 @@ __add_event(struct list_head *list, int *idx, + bool init_attr, + const char *name, const char *metric_id, struct perf_pmu *pmu, + struct list_head *config_terms, bool auto_merge_stats, +- struct perf_cpu_map *cpu_list) ++ struct perf_cpu_map *cpu_list, u64 alternate_hw_config) + { + struct evsel *evsel; + struct perf_cpu_map *cpus = perf_cpu_map__is_empty(cpu_list) && pmu ? pmu->cpus : cpu_list; +@@ -264,6 +264,7 @@ __add_event(struct list_head *list, int *idx, + evsel->auto_merge_stats = auto_merge_stats; + evsel->pmu = pmu; + evsel->pmu_name = pmu ? strdup(pmu->name) : NULL; ++ evsel->alternate_hw_config = alternate_hw_config; + + if (name) + evsel->name = strdup(name); +@@ -286,16 +287,19 @@ struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, + { + return __add_event(/*list=*/NULL, &idx, attr, /*init_attr=*/false, name, + metric_id, pmu, /*config_terms=*/NULL, +- /*auto_merge_stats=*/false, /*cpu_list=*/NULL); ++ /*auto_merge_stats=*/false, /*cpu_list=*/NULL, ++ /*alternate_hw_config=*/PERF_COUNT_HW_MAX); + } + + static int add_event(struct list_head *list, int *idx, + struct perf_event_attr *attr, const char *name, +- const char *metric_id, struct list_head *config_terms) ++ const char *metric_id, struct list_head *config_terms, ++ u64 alternate_hw_config) + { + return __add_event(list, idx, attr, /*init_attr*/true, name, metric_id, + /*pmu=*/NULL, config_terms, +- /*auto_merge_stats=*/false, /*cpu_list=*/NULL) ? 0 : -ENOMEM; ++ /*auto_merge_stats=*/false, /*cpu_list=*/NULL, ++ alternate_hw_config) ? 0 : -ENOMEM; + } + + static int add_event_tool(struct list_head *list, int *idx, +@@ -315,7 +319,8 @@ static int add_event_tool(struct list_head *list, int *idx, + evsel = __add_event(list, idx, &attr, /*init_attr=*/true, /*name=*/NULL, + /*metric_id=*/NULL, /*pmu=*/NULL, + /*config_terms=*/NULL, /*auto_merge_stats=*/false, +- cpu_list); ++ cpu_list, ++ /*alternate_hw_config=*/PERF_COUNT_HW_MAX); + perf_cpu_map__put(cpu_list); + if (!evsel) + return -ENOMEM; +@@ -450,7 +455,7 @@ bool parse_events__filter_pmu(const struct parse_events_state *parse_state, + static int parse_events_add_pmu(struct parse_events_state *parse_state, + struct list_head *list, struct perf_pmu *pmu, + const struct parse_events_terms *const_parsed_terms, +- bool auto_merge_stats); ++ bool auto_merge_stats, u64 alternate_hw_config); + + int parse_events_add_cache(struct list_head *list, int *idx, const char *name, + struct parse_events_state *parse_state, +@@ -476,7 +481,8 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name, + */ + ret = parse_events_add_pmu(parse_state, list, pmu, + parsed_terms, +- perf_pmu__auto_merge_stats(pmu)); ++ perf_pmu__auto_merge_stats(pmu), ++ /*alternate_hw_config=*/PERF_COUNT_HW_MAX); + if (ret) + return ret; + continue; +@@ -507,7 +513,8 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name, + + if (__add_event(list, idx, &attr, /*init_attr*/true, config_name ?: name, + metric_id, pmu, &config_terms, /*auto_merge_stats=*/false, +- /*cpu_list=*/NULL) == NULL) ++ /*cpu_list=*/NULL, ++ /*alternate_hw_config=*/PERF_COUNT_HW_MAX) == NULL) + return -ENOMEM; + + free_config_terms(&config_terms); +@@ -772,7 +779,7 @@ int parse_events_add_breakpoint(struct parse_events_state *parse_state, + name = get_config_name(head_config); + + return add_event(list, &parse_state->idx, &attr, name, /*mertic_id=*/NULL, +- &config_terms); ++ &config_terms, /*alternate_hw_config=*/PERF_COUNT_HW_MAX); + } + + static int check_type_val(struct parse_events_term *term, +@@ -1072,6 +1079,7 @@ static int config_term_pmu(struct perf_event_attr *attr, + if (perf_pmu__have_event(pmu, term->config)) { + term->type_term = PARSE_EVENTS__TERM_TYPE_USER; + term->no_value = true; ++ term->alternate_hw_config = true; + } else { + attr->type = PERF_TYPE_HARDWARE; + attr->config = term->val.num; +@@ -1384,8 +1392,9 @@ static int __parse_events_add_numeric(struct parse_events_state *parse_state, + name = get_config_name(head_config); + metric_id = get_config_metric_id(head_config); + ret = __add_event(list, &parse_state->idx, &attr, /*init_attr*/true, name, +- metric_id, pmu, &config_terms, /*auto_merge_stats=*/false, +- /*cpu_list=*/NULL) ? 0 : -ENOMEM; ++ metric_id, pmu, &config_terms, /*auto_merge_stats=*/false, ++ /*cpu_list=*/NULL, /*alternate_hw_config=*/PERF_COUNT_HW_MAX ++ ) == NULL ? -ENOMEM : 0; + free_config_terms(&config_terms); + return ret; + } +@@ -1443,7 +1452,7 @@ static bool config_term_percore(struct list_head *config_terms) + static int parse_events_add_pmu(struct parse_events_state *parse_state, + struct list_head *list, struct perf_pmu *pmu, + const struct parse_events_terms *const_parsed_terms, +- bool auto_merge_stats) ++ bool auto_merge_stats, u64 alternate_hw_config) + { + struct perf_event_attr attr; + struct perf_pmu_info info; +@@ -1480,7 +1489,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, + /*init_attr=*/true, /*name=*/NULL, + /*metric_id=*/NULL, pmu, + /*config_terms=*/NULL, auto_merge_stats, +- /*cpu_list=*/NULL); ++ /*cpu_list=*/NULL, alternate_hw_config); + return evsel ? 0 : -ENOMEM; + } + +@@ -1501,7 +1510,8 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, + + /* Look for event names in the terms and rewrite into format based terms. */ + if (perf_pmu__check_alias(pmu, &parsed_terms, +- &info, &alias_rewrote_terms, err)) { ++ &info, &alias_rewrote_terms, ++ &alternate_hw_config, err)) { + parse_events_terms__exit(&parsed_terms); + return -EINVAL; + } +@@ -1546,7 +1556,8 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, + evsel = __add_event(list, &parse_state->idx, &attr, /*init_attr=*/true, + get_config_name(&parsed_terms), + get_config_metric_id(&parsed_terms), pmu, +- &config_terms, auto_merge_stats, /*cpu_list=*/NULL); ++ &config_terms, auto_merge_stats, /*cpu_list=*/NULL, ++ alternate_hw_config); + if (!evsel) { + parse_events_terms__exit(&parsed_terms); + return -ENOMEM; +@@ -1567,7 +1578,7 @@ static int parse_events_add_pmu(struct parse_events_state *parse_state, + } + + int parse_events_multi_pmu_add(struct parse_events_state *parse_state, +- const char *event_name, ++ const char *event_name, u64 hw_config, + const struct parse_events_terms *const_parsed_terms, + struct list_head **listp, void *loc_) + { +@@ -1620,7 +1631,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, + + auto_merge_stats = perf_pmu__auto_merge_stats(pmu); + if (!parse_events_add_pmu(parse_state, list, pmu, +- &parsed_terms, auto_merge_stats)) { ++ &parsed_terms, auto_merge_stats, hw_config)) { + struct strbuf sb; + + strbuf_init(&sb, /*hint=*/ 0); +@@ -1633,7 +1644,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, + + if (parse_state->fake_pmu) { + if (!parse_events_add_pmu(parse_state, list, perf_pmus__fake_pmu(), &parsed_terms, +- /*auto_merge_stats=*/true)) { ++ /*auto_merge_stats=*/true, hw_config)) { + struct strbuf sb; + + strbuf_init(&sb, /*hint=*/ 0); +@@ -1674,13 +1685,15 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state + /* Attempt to add to list assuming event_or_pmu is a PMU name. */ + pmu = perf_pmus__find(event_or_pmu); + if (pmu && !parse_events_add_pmu(parse_state, *listp, pmu, const_parsed_terms, +- /*auto_merge_stats=*/false)) ++ /*auto_merge_stats=*/false, ++ /*alternate_hw_config=*/PERF_COUNT_HW_MAX)) + return 0; + + if (parse_state->fake_pmu) { + if (!parse_events_add_pmu(parse_state, *listp, perf_pmus__fake_pmu(), + const_parsed_terms, +- /*auto_merge_stats=*/false)) ++ /*auto_merge_stats=*/false, ++ /*alternate_hw_config=*/PERF_COUNT_HW_MAX)) + return 0; + } + +@@ -1693,7 +1706,8 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state + + if (!parse_events_add_pmu(parse_state, *listp, pmu, + const_parsed_terms, +- auto_merge_stats)) { ++ auto_merge_stats, ++ /*alternate_hw_config=*/PERF_COUNT_HW_MAX)) { + ok++; + parse_state->wild_card_pmus = true; + } +@@ -1704,7 +1718,8 @@ int parse_events_multi_pmu_add_or_add_pmu(struct parse_events_state *parse_state + + /* Failure to add, assume event_or_pmu is an event name. */ + zfree(listp); +- if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, const_parsed_terms, listp, loc)) ++ if (!parse_events_multi_pmu_add(parse_state, event_or_pmu, PERF_COUNT_HW_MAX, ++ const_parsed_terms, listp, loc)) + return 0; + + if (asprintf(&help, "Unable to find PMU or event on a PMU of '%s'", event_or_pmu) < 0) +diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h +index 10cc9c433116d..2b52f8d6aa29a 100644 +--- a/tools/perf/util/parse-events.h ++++ b/tools/perf/util/parse-events.h +@@ -127,6 +127,12 @@ struct parse_events_term { + * value is assumed to be 1. An event name also has no value. + */ + bool no_value; ++ /** ++ * @alternate_hw_config: config is the event name but num is an ++ * alternate PERF_TYPE_HARDWARE config value which is often nice for the ++ * sake of quick matching. ++ */ ++ bool alternate_hw_config; + }; + + struct parse_events_error { +@@ -238,7 +244,7 @@ struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, + struct perf_pmu *pmu); + + int parse_events_multi_pmu_add(struct parse_events_state *parse_state, +- const char *event_name, ++ const char *event_name, u64 hw_config, + const struct parse_events_terms *const_parsed_terms, + struct list_head **listp, void *loc); + +diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y +index b3c51f06cbdc4..dcf47fabdfdd7 100644 +--- a/tools/perf/util/parse-events.y ++++ b/tools/perf/util/parse-events.y +@@ -292,7 +292,7 @@ PE_NAME sep_dc + struct list_head *list; + int err; + +- err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list, &@1); ++ err = parse_events_multi_pmu_add(_parse_state, $1, PERF_COUNT_HW_MAX, NULL, &list, &@1); + if (err < 0) { + struct parse_events_state *parse_state = _parse_state; + struct parse_events_error *error = parse_state->error; +diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c +index 8b4e346808b4c..8885998c19530 100644 +--- a/tools/perf/util/pmu.c ++++ b/tools/perf/util/pmu.c +@@ -1606,7 +1606,7 @@ static int check_info_data(struct perf_pmu *pmu, + */ + int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms, + struct perf_pmu_info *info, bool *rewrote_terms, +- struct parse_events_error *err) ++ u64 *alternate_hw_config, struct parse_events_error *err) + { + struct parse_events_term *term, *h; + struct perf_pmu_alias *alias; +@@ -1638,6 +1638,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_ + NULL); + return ret; + } ++ + *rewrote_terms = true; + ret = check_info_data(pmu, alias, info, err, term->err_term); + if (ret) +@@ -1646,6 +1647,9 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_ + if (alias->per_pkg) + info->per_pkg = true; + ++ if (term->alternate_hw_config) ++ *alternate_hw_config = term->val.num; ++ + list_del_init(&term->list); + parse_events_term__delete(term); + } +diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h +index bcd278b9b546f..0222124b86b92 100644 +--- a/tools/perf/util/pmu.h ++++ b/tools/perf/util/pmu.h +@@ -220,7 +220,7 @@ __u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name); + int perf_pmu__format_type(struct perf_pmu *pmu, const char *name); + int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms, + struct perf_pmu_info *info, bool *rewrote_terms, +- struct parse_events_error *err); ++ u64 *alternate_hw_config, struct parse_events_error *err); + int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb); + + void perf_pmu_format__set_value(void *format, int config, unsigned long *bits); +-- +2.53.0 + diff --git a/queue-6.12/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch b/queue-6.12/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch new file mode 100644 index 0000000000..bf36bca146 --- /dev/null +++ b/queue-6.12/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch @@ -0,0 +1,57 @@ +From 69c58cc374a85e052c14d3dc000d6e4ac2e94c07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:04:47 +0100 +Subject: perf expr: Return -EINVAL for syntax error in expr__find_ids() + +From: Leo Yan + +[ Upstream commit 3a61fd866ef9aaa1d3158b460f852b74a2df07f4 ] + +expr__find_ids() propagates the parser return value directly. For syntax +errors, the parser can return a positive value, but callers treat it as +success, e.g., for below case on Arm64 platform: + + metric expr 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) for backend_bound + parsing metric: 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) + Failure to read '#slots' literal: #slots = nan + syntax error + +Convert positive parser returns in expr__find_ids() to -EINVAL, as a +result, the error value will be respected by callers. + +Before: + + perf stat -C 5 + Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Segmentation fault + +After: + + perf stat -C 5 + Failure to read '#slots'Cannot find metric or group `Default' + +Fixes: ded80bda8bc9 ("perf expr: Migrate expr ids table to a hashmap") +Signed-off-by: Leo Yan +Reviewed-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/expr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index 90c6ce2212e4f..7ceefed276b73 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -373,7 +373,8 @@ int expr__find_ids(const char *expr, const char *one, + if (one) + expr__del_id(ctx, one); + +- return ret; ++ /* A positive value means syntax error, convert to -EINVAL */ ++ return ret > 0 ? -EINVAL : ret; + } + + double expr_id_data__value(const struct expr_id_data *data) +-- +2.53.0 + diff --git a/queue-6.12/perf-lock-fix-option-value-type-in-parse_max_stack.patch b/queue-6.12/perf-lock-fix-option-value-type-in-parse_max_stack.patch new file mode 100644 index 0000000000..2306d089cd --- /dev/null +++ b/queue-6.12/perf-lock-fix-option-value-type-in-parse_max_stack.patch @@ -0,0 +1,38 @@ +From b5c1e55994988ac6faed66dfb7cfba50498f9d3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 16:33:48 -0700 +Subject: perf lock: Fix option value type in parse_max_stack + +From: Ian Rogers + +[ Upstream commit cfaade34b52aa1ec553044255702c4b31b57c005 ] + +The value is a void* and the address of an int, max_stack_depth, is +set up in the perf lock options. The parse_max_stack function treats +the int* as a long*, make this more correct by declaring the value to +be an int*. + +Fixes: 0a277b622670 ("perf lock contention: Check --max-stack option") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-lock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c +index 33a456980664a..3d490ea46551b 100644 +--- a/tools/perf/builtin-lock.c ++++ b/tools/perf/builtin-lock.c +@@ -2300,7 +2300,7 @@ static int parse_map_entry(const struct option *opt, const char *str, + static int parse_max_stack(const struct option *opt, const char *str, + int unset __maybe_unused) + { +- unsigned long *len = (unsigned long *)opt->value; ++ int *len = opt->value; + long val; + char *endptr; + +-- +2.53.0 + diff --git a/queue-6.12/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch b/queue-6.12/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch new file mode 100644 index 0000000000..b7e4e64379 --- /dev/null +++ b/queue-6.12/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch @@ -0,0 +1,47 @@ +From b08541362a0d612c8205adaa6529a7848afd2f18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 19:08:38 -0700 +Subject: perf maps: Fix copy_from that can break sorted by name order + +From: Ian Rogers + +[ Upstream commit f552b132e4d5248715828e7e5c2bf7889bf05b2e ] + +When an parent is copied into a child the name array is populated in +address not name order. Make sure the name array isn't flagged as sorted. + +Fixes: 659ad3492b91 ("perf maps: Switch from rbtree to lazily sorted array for addresses") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/maps.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c +index 67133b60b03cd..7b8f48677c318 100644 +--- a/tools/perf/util/maps.c ++++ b/tools/perf/util/maps.c +@@ -989,16 +989,9 @@ int maps__copy_from(struct maps *dest, struct maps *parent) + map__put(new); + } + maps__set_maps_by_address_sorted(dest, maps__maps_by_address_sorted(parent)); +- if (!err) { +- RC_CHK_ACCESS(dest)->last_search_by_name_idx = +- RC_CHK_ACCESS(parent)->last_search_by_name_idx; +- maps__set_maps_by_name_sorted(dest, +- dest_maps_by_name && +- maps__maps_by_name_sorted(parent)); +- } else { +- RC_CHK_ACCESS(dest)->last_search_by_name_idx = 0; +- maps__set_maps_by_name_sorted(dest, false); +- } ++ RC_CHK_ACCESS(dest)->last_search_by_name_idx = 0; ++ /* Values were copied into the name array in address order. */ ++ maps__set_maps_by_name_sorted(dest, false); + } else { + /* Unexpected copying to a maps containing entries. */ + for (unsigned int i = 0; !err && i < n; i++) { +-- +2.53.0 + diff --git a/queue-6.12/perf-python-add-parse_events-function.patch b/queue-6.12/perf-python-add-parse_events-function.patch new file mode 100644 index 0000000000..951cdd36af --- /dev/null +++ b/queue-6.12/perf-python-add-parse_events-function.patch @@ -0,0 +1,205 @@ +From 6e89efb2d8d82f32833cb385a1175626a5ca6f3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Nov 2024 17:16:41 -0800 +Subject: perf python: Add parse_events function + +From: Ian Rogers + +[ Upstream commit f081defccd934a8db309c90a61178e4f2eef386c ] + +Add basic parse_events function that takes a string and returns an +evlist. As the python evlist is embedded in a pyrf_evlist, and the +evsels are embedded in pyrf_evsels, copy the parsed data into those +structs and update evsel__clone to enable this. + +Signed-off-by: Ian Rogers +Cc: Adrian Hunter +Cc: Alexander Shishkin +Cc: Andi Kleen +Cc: Athira Rajeev +Cc: Colin Ian King +Cc: Dapeng Mi +Cc: Howard Chu +Cc: Ilya Leoshkevich +Cc: Ingo Molnar +Cc: James Clark +Cc: Jiri Olsa +Cc: Josh Poimboeuf +Cc: Kan Liang +Cc: Mark Rutland +Cc: Michael Petlan +Cc: Namhyung Kim +Cc: Peter Zijlstra +Cc: Thomas Richter +Cc: Veronika Molnarova +Cc: Weilin Wang +Link: https://lore.kernel.org/r/20241119011644.971342-20-irogers@google.com +Signed-off-by: Arnaldo Carvalho de Melo +Stable-dep-of: c9ef786c0970 ("perf cgroup: Update metric leader in evlist__expand_cgroup") +Signed-off-by: Sasha Levin +--- + tools/perf/util/cgroup.c | 2 +- + tools/perf/util/evsel.c | 19 ++++++++----- + tools/perf/util/evsel.h | 2 +- + tools/perf/util/python.c | 61 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 75 insertions(+), 9 deletions(-) + +diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c +index 0f759dd96db71..fbcc0626f9ce2 100644 +--- a/tools/perf/util/cgroup.c ++++ b/tools/perf/util/cgroup.c +@@ -473,7 +473,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, + + leader = NULL; + evlist__for_each_entry(orig_list, pos) { +- evsel = evsel__clone(pos); ++ evsel = evsel__clone(/*dest=*/NULL, pos); + if (evsel == NULL) + goto out_err; + +diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c +index d2965dc49bac2..45a7ed5c7a473 100644 +--- a/tools/perf/util/evsel.c ++++ b/tools/perf/util/evsel.c +@@ -332,7 +332,7 @@ static int evsel__copy_config_terms(struct evsel *dst, struct evsel *src) + * The assumption is that @orig is not configured nor opened yet. + * So we only care about the attributes that can be set while it's parsed. + */ +-struct evsel *evsel__clone(struct evsel *orig) ++struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig) + { + struct evsel *evsel; + +@@ -345,7 +345,11 @@ struct evsel *evsel__clone(struct evsel *orig) + if (orig->bpf_obj) + return NULL; + +- evsel = evsel__new(&orig->core.attr); ++ if (dest) ++ evsel = dest; ++ else ++ evsel = evsel__new(&orig->core.attr); ++ + if (evsel == NULL) + return NULL; + +@@ -395,11 +399,12 @@ struct evsel *evsel__clone(struct evsel *orig) + evsel->core.leader = orig->core.leader; + + evsel->max_events = orig->max_events; +- free((char *)evsel->unit); +- evsel->unit = strdup(orig->unit); +- if (evsel->unit == NULL) +- goto out_err; +- ++ zfree(&evsel->unit); ++ if (orig->unit) { ++ evsel->unit = strdup(orig->unit); ++ if (evsel->unit == NULL) ++ goto out_err; ++ } + evsel->scale = orig->scale; + evsel->snapshot = orig->snapshot; + evsel->per_pkg = orig->per_pkg; +diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h +index b23fa3ca88883..0e64b9f17f0a6 100644 +--- a/tools/perf/util/evsel.h ++++ b/tools/perf/util/evsel.h +@@ -241,7 +241,7 @@ static inline struct evsel *evsel__new(struct perf_event_attr *attr) + return evsel__new_idx(attr, 0); + } + +-struct evsel *evsel__clone(struct evsel *orig); ++struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig); + + int copy_config_terms(struct list_head *dst, struct list_head *src); + void free_config_terms(struct list_head *config_terms); +diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c +index e7f36ea9e2fa1..5060dc801dede 100644 +--- a/tools/perf/util/python.c ++++ b/tools/perf/util/python.c +@@ -13,6 +13,7 @@ + #include "evsel.h" + #include "event.h" + #include "print_binary.h" ++#include "strbuf.h" + #include "thread_map.h" + #include "trace-event.h" + #include "mmap.h" +@@ -1247,6 +1248,60 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel, + #endif // HAVE_LIBTRACEEVENT + } + ++static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel) ++{ ++ struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type); ++ ++ if (!pevsel) ++ return NULL; ++ ++ memset(&pevsel->evsel, 0, sizeof(pevsel->evsel)); ++ evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx); ++ ++ evsel__clone(&pevsel->evsel, evsel); ++ return (PyObject *)pevsel; ++} ++ ++static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist) ++{ ++ struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type); ++ struct evsel *pos; ++ ++ if (!pevlist) ++ return NULL; ++ ++ memset(&pevlist->evlist, 0, sizeof(pevlist->evlist)); ++ evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads); ++ evlist__for_each_entry(evlist, pos) { ++ struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos); ++ ++ evlist__add(&pevlist->evlist, &pevsel->evsel); ++ } ++ return (PyObject *)pevlist; ++} ++ ++static PyObject *pyrf__parse_events(PyObject *self, PyObject *args) ++{ ++ const char *input; ++ struct evlist evlist = {}; ++ struct parse_events_error err; ++ PyObject *result; ++ ++ if (!PyArg_ParseTuple(args, "s", &input)) ++ return NULL; ++ ++ parse_events_error__init(&err); ++ evlist__init(&evlist, NULL, NULL); ++ if (parse_events(&evlist, input, &err)) { ++ parse_events_error__print(&err, input); ++ PyErr_SetFromErrno(PyExc_OSError); ++ return NULL; ++ } ++ result = pyrf_evlist__from_evlist(&evlist); ++ evlist__exit(&evlist); ++ return result; ++} ++ + static PyMethodDef perf__methods[] = { + { + .ml_name = "tracepoint", +@@ -1254,6 +1309,12 @@ static PyMethodDef perf__methods[] = { + .ml_flags = METH_VARARGS | METH_KEYWORDS, + .ml_doc = PyDoc_STR("Get tracepoint config.") + }, ++ { ++ .ml_name = "parse_events", ++ .ml_meth = (PyCFunction) pyrf__parse_events, ++ .ml_flags = METH_VARARGS, ++ .ml_doc = PyDoc_STR("Parse a string of events and return an evlist.") ++ }, + { .ml_name = NULL, } + }; + +-- +2.53.0 + diff --git a/queue-6.12/perf-stat-fix-opt-value-type-for-parse_cache_level.patch b/queue-6.12/perf-stat-fix-opt-value-type-for-parse_cache_level.patch new file mode 100644 index 0000000000..65e9c2d821 --- /dev/null +++ b/queue-6.12/perf-stat-fix-opt-value-type-for-parse_cache_level.patch @@ -0,0 +1,120 @@ +From 21eb518defe6bc4801c6d66c771042370d584f76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 16:33:49 -0700 +Subject: perf stat: Fix opt->value type for parse_cache_level + +From: Ian Rogers + +[ Upstream commit 44311ae84ad9177fb311aee856027861c22f17b2 ] + +Commit f5803651b4a4 ("perf stat: Choose the most disaggregate command +line option") changed aggregation option handling for `perf stat` but +not `perf stat report` leading to parse_cache_level being passed a +struct in the `perf stat` case but erroneously an aggr_mode enum value +for `perf stat report`. Change the `perf stat report` aggregation +handling to use the same opt_aggr_mode as `perf stat`. Also, just pass +the boolean for consistency with other boolean argument handling. + +Fixes: f5803651b4a4 ("perf stat: Choose the most disaggregate command line option") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-stat.c | 43 +++++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 20 deletions(-) + +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index b578930ed76a4..e476598de8083 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -171,7 +171,7 @@ struct opt_aggr_mode { + }; + + /* Turn command line option into most generic aggregation mode setting. */ +-static enum aggr_mode opt_aggr_mode_to_aggr_mode(struct opt_aggr_mode *opt_mode) ++static enum aggr_mode opt_aggr_mode_to_aggr_mode(const struct opt_aggr_mode *opt_mode) + { + enum aggr_mode mode = AGGR_GLOBAL; + +@@ -1154,8 +1154,8 @@ static int parse_cache_level(const struct option *opt, + int unset __maybe_unused) + { + int level; +- struct opt_aggr_mode *opt_aggr_mode = (struct opt_aggr_mode *)opt->value; +- u32 *aggr_level = (u32 *)opt->data; ++ bool *per_cache = opt->value; ++ u32 *aggr_level = opt->data; + + /* + * If no string is specified, aggregate based on the topology of +@@ -1193,7 +1193,7 @@ static int parse_cache_level(const struct option *opt, + return -EINVAL; + } + out: +- opt_aggr_mode->cache = true; ++ *per_cache = true; + *aggr_level = level; + return 0; + } +@@ -2316,24 +2316,23 @@ static struct perf_stat perf_stat = { + static int __cmd_report(int argc, const char **argv) + { + struct perf_session *session; ++ struct opt_aggr_mode opt_mode = {}; + const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", "input file name"), +- OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode, +- "aggregate counts per processor socket", AGGR_SOCKET), +- OPT_SET_UINT(0, "per-die", &perf_stat.aggr_mode, +- "aggregate counts per processor die", AGGR_DIE), +- OPT_SET_UINT(0, "per-cluster", &perf_stat.aggr_mode, +- "aggregate counts perf processor cluster", AGGR_CLUSTER), +- OPT_CALLBACK_OPTARG(0, "per-cache", &perf_stat.aggr_mode, &perf_stat.aggr_level, +- "cache level", +- "aggregate count at this cache level (Default: LLC)", ++ OPT_BOOLEAN(0, "per-thread", &opt_mode.thread, "aggregate counts per thread"), ++ OPT_BOOLEAN(0, "per-socket", &opt_mode.socket, ++ "aggregate counts per processor socket"), ++ OPT_BOOLEAN(0, "per-die", &opt_mode.die, "aggregate counts per processor die"), ++ OPT_BOOLEAN(0, "per-cluster", &opt_mode.cluster, ++ "aggregate counts per processor cluster"), ++ OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode.cache, &perf_stat.aggr_level, ++ "cache level", "aggregate count at this cache level (Default: LLC)", + parse_cache_level), +- OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode, +- "aggregate counts per physical processor core", AGGR_CORE), +- OPT_SET_UINT(0, "per-node", &perf_stat.aggr_mode, +- "aggregate counts per numa node", AGGR_NODE), +- OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode, +- "disable CPU count aggregation", AGGR_NONE), ++ OPT_BOOLEAN(0, "per-core", &opt_mode.core, ++ "aggregate counts per physical processor core"), ++ OPT_BOOLEAN(0, "per-node", &opt_mode.node, "aggregate counts per numa node"), ++ OPT_BOOLEAN('A', "no-aggr", &opt_mode.no_aggr, ++ "disable aggregation across CPUs or PMUs"), + OPT_END() + }; + struct stat st; +@@ -2341,6 +2340,10 @@ static int __cmd_report(int argc, const char **argv) + + argc = parse_options(argc, argv, options, stat_report_usage, 0); + ++ perf_stat.aggr_mode = opt_aggr_mode_to_aggr_mode(&opt_mode); ++ if (perf_stat.aggr_mode == AGGR_GLOBAL) ++ perf_stat.aggr_mode = AGGR_UNSET; /* No option found so leave unset. */ ++ + if (!input_name || !strlen(input_name)) { + if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) + input_name = "-"; +@@ -2490,7 +2493,7 @@ int cmd_stat(int argc, const char **argv) + OPT_BOOLEAN(0, "per-die", &opt_mode.die, "aggregate counts per processor die"), + OPT_BOOLEAN(0, "per-cluster", &opt_mode.cluster, + "aggregate counts per processor cluster"), +- OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode, &stat_config.aggr_level, ++ OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode.cache, &stat_config.aggr_level, + "cache level", "aggregate count at this cache level (Default: LLC)", + parse_cache_level), + OPT_BOOLEAN(0, "per-core", &opt_mode.core, +-- +2.53.0 + diff --git a/queue-6.12/perf-tool_pmu-factor-tool-events-into-their-own-pmu.patch b/queue-6.12/perf-tool_pmu-factor-tool-events-into-their-own-pmu.patch new file mode 100644 index 0000000000..f156877936 --- /dev/null +++ b/queue-6.12/perf-tool_pmu-factor-tool-events-into-their-own-pmu.patch @@ -0,0 +1,1446 @@ +From a5f9887b11f913c701a38c9817506681f8b63549 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Oct 2024 20:20:07 -0700 +Subject: perf tool_pmu: Factor tool events into their own PMU + +From: Ian Rogers + +[ Upstream commit 240505b2d0adcdc8fd018117e88dc27b09734735 ] + +Rather than treat tool events as a special kind of event, create a +tool only PMU where the events/aliases match the existing +duration_time, user_time and system_time events. Remove special +parsing and printing support for the tool events, but add function +calls for when PMU functions are called on a tool_pmu. + +Move the tool PMU code in evsel into tool_pmu.c to better encapsulate +the tool event behavior in that file. + +Signed-off-by: Ian Rogers +Acked-by: Namhyung Kim +Link: https://lore.kernel.org/r/20241002032016.333748-5-irogers@google.com +Signed-off-by: Namhyung Kim +Stable-dep-of: c9ef786c0970 ("perf cgroup: Update metric leader in evlist__expand_cgroup") +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-list.c | 13 +- + tools/perf/builtin-stat.c | 1 + + tools/perf/util/Build | 1 + + tools/perf/util/evsel.c | 272 ++-------------------- + tools/perf/util/evsel.h | 28 +-- + tools/perf/util/metricgroup.c | 1 + + tools/perf/util/parse-events.c | 39 ---- + tools/perf/util/parse-events.h | 3 - + tools/perf/util/parse-events.l | 11 - + tools/perf/util/parse-events.y | 16 -- + tools/perf/util/pmu.c | 20 +- + tools/perf/util/pmu.h | 2 + + tools/perf/util/pmus.c | 9 + + tools/perf/util/print-events.c | 36 +-- + tools/perf/util/print-events.h | 1 - + tools/perf/util/stat-display.c | 6 +- + tools/perf/util/stat-shadow.c | 1 + + tools/perf/util/tool_pmu.c | 411 +++++++++++++++++++++++++++++++++ + tools/perf/util/tool_pmu.h | 51 ++++ + 19 files changed, 530 insertions(+), 392 deletions(-) + create mode 100644 tools/perf/util/tool_pmu.c + create mode 100644 tools/perf/util/tool_pmu.h + +diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c +index c5331721dfee9..9e7fdfcdd7ffb 100644 +--- a/tools/perf/builtin-list.c ++++ b/tools/perf/builtin-list.c +@@ -19,6 +19,7 @@ + #include "util/string2.h" + #include "util/strlist.h" + #include "util/strbuf.h" ++#include "util/tool_pmu.h" + #include + #include + #include +@@ -614,9 +615,18 @@ int cmd_list(int argc, const char **argv) + event_symbols_hw, PERF_COUNT_HW_MAX); + else if (strcmp(argv[i], "sw") == 0 || + strcmp(argv[i], "software") == 0) { ++ char *old_pmu_glob = default_ps.pmu_glob; ++ + print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, + event_symbols_sw, PERF_COUNT_SW_MAX); +- print_tool_events(&print_cb, ps); ++ default_ps.pmu_glob = strdup("tool"); ++ if (!default_ps.pmu_glob) { ++ ret = -1; ++ goto out; ++ } ++ perf_pmus__print_pmu_events(&print_cb, ps); ++ zfree(&default_ps.pmu_glob); ++ default_ps.pmu_glob = old_pmu_glob; + } else if (strcmp(argv[i], "cache") == 0 || + strcmp(argv[i], "hwcache") == 0) + print_hwcache_events(&print_cb, ps); +@@ -664,7 +674,6 @@ int cmd_list(int argc, const char **argv) + event_symbols_hw, PERF_COUNT_HW_MAX); + print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, + event_symbols_sw, PERF_COUNT_SW_MAX); +- print_tool_events(&print_cb, ps); + print_hwcache_events(&print_cb, ps); + perf_pmus__print_pmu_events(&print_cb, ps); + print_tracepoint_events(&print_cb, ps); +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index e476598de8083..e8708f785e7f2 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -46,6 +46,7 @@ + #include "util/parse-events.h" + #include "util/pmus.h" + #include "util/pmu.h" ++#include "util/tool_pmu.h" + #include "util/event.h" + #include "util/evlist.h" + #include "util/evsel.h" +diff --git a/tools/perf/util/Build b/tools/perf/util/Build +index dc616292b2ddf..fa508e113dd0c 100644 +--- a/tools/perf/util/Build ++++ b/tools/perf/util/Build +@@ -83,6 +83,7 @@ perf-util-y += pmu.o + perf-util-y += pmus.o + perf-util-y += pmu-flex.o + perf-util-y += pmu-bison.o ++perf-util-y += tool_pmu.o + perf-util-y += svghelper.o + perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-info.o + perf-util-y += trace-event-scripting.o +diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c +index 6e8d70ec05bad..d2965dc49bac2 100644 +--- a/tools/perf/util/evsel.c ++++ b/tools/perf/util/evsel.c +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -51,6 +50,7 @@ + #include "off_cpu.h" + #include "pmu.h" + #include "pmus.h" ++#include "tool_pmu.h" + #include "rlimit.h" + #include "../perf-sys.h" + #include "util/parse-branch-options.h" +@@ -71,33 +71,6 @@ struct perf_missing_features perf_missing_features; + + static clockid_t clockid; + +-static const char *const perf_tool_event__tool_names[PERF_TOOL_MAX] = { +- NULL, +- "duration_time", +- "user_time", +- "system_time", +-}; +- +-const char *perf_tool_event__to_str(enum perf_tool_event ev) +-{ +- if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX) +- return perf_tool_event__tool_names[ev]; +- +- return NULL; +-} +- +-enum perf_tool_event perf_tool_event__from_str(const char *str) +-{ +- int i; +- +- perf_tool_event__for_each_event(i) { +- if (!strcmp(str, perf_tool_event__tool_names[i])) +- return i; +- } +- return PERF_TOOL_NONE; +-} +- +- + static int evsel__no_extra_init(struct evsel *evsel __maybe_unused) + { + return 0; +@@ -422,7 +395,6 @@ struct evsel *evsel__clone(struct evsel *orig) + evsel->core.leader = orig->core.leader; + + evsel->max_events = orig->max_events; +- evsel->tool_event = orig->tool_event; + free((char *)evsel->unit); + evsel->unit = strdup(orig->unit); + if (evsel->unit == NULL) +@@ -620,11 +592,6 @@ static int evsel__sw_name(struct evsel *evsel, char *bf, size_t size) + return r + evsel__add_modifiers(evsel, bf + r, size - r); + } + +-static int evsel__tool_name(enum perf_tool_event ev, char *bf, size_t size) +-{ +- return scnprintf(bf, size, "%s", perf_tool_event__to_str(ev)); +-} +- + static int __evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) + { + int r; +@@ -775,10 +742,7 @@ const char *evsel__name(struct evsel *evsel) + break; + + case PERF_TYPE_SOFTWARE: +- if (evsel__is_tool(evsel)) +- evsel__tool_name(evsel__tool_event(evsel), bf, sizeof(bf)); +- else +- evsel__sw_name(evsel, bf, sizeof(bf)); ++ evsel__sw_name(evsel, bf, sizeof(bf)); + break; + + case PERF_TYPE_TRACEPOINT: +@@ -789,6 +753,10 @@ const char *evsel__name(struct evsel *evsel) + evsel__bp_name(evsel, bf, sizeof(bf)); + break; + ++ case PERF_PMU_TYPE_TOOL: ++ scnprintf(bf, sizeof(bf), "%s", evsel__tool_pmu_event_name(evsel)); ++ break; ++ + default: + scnprintf(bf, sizeof(bf), "unknown attr type: %d", + evsel->core.attr.type); +@@ -814,7 +782,7 @@ const char *evsel__metric_id(const struct evsel *evsel) + return evsel->metric_id; + + if (evsel__is_tool(evsel)) +- return perf_tool_event__to_str(evsel__tool_event(evsel)); ++ return evsel__tool_pmu_event_name(evsel); + + return "unknown"; + } +@@ -1698,167 +1666,6 @@ static int evsel__read_group(struct evsel *leader, int cpu_map_idx, int thread) + return evsel__process_group_data(leader, cpu_map_idx, thread, data); + } + +-static bool read_until_char(struct io *io, char e) +-{ +- int c; +- +- do { +- c = io__get_char(io); +- if (c == -1) +- return false; +- } while (c != e); +- return true; +-} +- +-static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val) +-{ +- char buf[256]; +- struct io io; +- int i; +- +- io__init(&io, fd, buf, sizeof(buf)); +- +- /* Skip lines to relevant CPU. */ +- for (i = -1; i < cpu.cpu; i++) { +- if (!read_until_char(&io, '\n')) +- return -EINVAL; +- } +- /* Skip to "cpu". */ +- if (io__get_char(&io) != 'c') return -EINVAL; +- if (io__get_char(&io) != 'p') return -EINVAL; +- if (io__get_char(&io) != 'u') return -EINVAL; +- +- /* Skip N of cpuN. */ +- if (!read_until_char(&io, ' ')) +- return -EINVAL; +- +- i = 1; +- while (true) { +- if (io__get_dec(&io, val) != ' ') +- break; +- if (field == i) +- return 0; +- i++; +- } +- return -EINVAL; +-} +- +-static int read_pid_stat_field(int fd, int field, __u64 *val) +-{ +- char buf[256]; +- struct io io; +- int c, i; +- +- io__init(&io, fd, buf, sizeof(buf)); +- if (io__get_dec(&io, val) != ' ') +- return -EINVAL; +- if (field == 1) +- return 0; +- +- /* Skip comm. */ +- if (io__get_char(&io) != '(' || !read_until_char(&io, ')')) +- return -EINVAL; +- if (field == 2) +- return -EINVAL; /* String can't be returned. */ +- +- /* Skip state */ +- if (io__get_char(&io) != ' ' || io__get_char(&io) == -1) +- return -EINVAL; +- if (field == 3) +- return -EINVAL; /* String can't be returned. */ +- +- /* Loop over numeric fields*/ +- if (io__get_char(&io) != ' ') +- return -EINVAL; +- +- i = 4; +- while (true) { +- c = io__get_dec(&io, val); +- if (c == -1) +- return -EINVAL; +- if (c == -2) { +- /* Assume a -ve was read */ +- c = io__get_dec(&io, val); +- *val *= -1; +- } +- if (c != ' ') +- return -EINVAL; +- if (field == i) +- return 0; +- i++; +- } +- return -EINVAL; +-} +- +-static int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread) +-{ +- __u64 *start_time, cur_time, delta_start; +- int fd, err = 0; +- struct perf_counts_values *count; +- bool adjust = false; +- +- count = perf_counts(evsel->counts, cpu_map_idx, thread); +- +- switch (evsel__tool_event(evsel)) { +- case PERF_TOOL_DURATION_TIME: +- /* +- * Pretend duration_time is only on the first CPU and thread, or +- * else aggregation will scale duration_time by the number of +- * CPUs/threads. +- */ +- start_time = &evsel->start_time; +- if (cpu_map_idx == 0 && thread == 0) +- cur_time = rdclock(); +- else +- cur_time = *start_time; +- break; +- case PERF_TOOL_USER_TIME: +- case PERF_TOOL_SYSTEM_TIME: { +- bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME; +- +- start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread); +- fd = FD(evsel, cpu_map_idx, thread); +- lseek(fd, SEEK_SET, 0); +- if (evsel->pid_stat) { +- /* The event exists solely on 1 CPU. */ +- if (cpu_map_idx == 0) +- err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time); +- else +- cur_time = 0; +- } else { +- /* The event is for all threads. */ +- if (thread == 0) { +- struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus, +- cpu_map_idx); +- +- err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time); +- } else { +- cur_time = 0; +- } +- } +- adjust = true; +- break; +- } +- case PERF_TOOL_NONE: +- case PERF_TOOL_MAX: +- default: +- err = -EINVAL; +- } +- if (err) +- return err; +- +- delta_start = cur_time - *start_time; +- if (adjust) { +- __u64 ticks_per_sec = sysconf(_SC_CLK_TCK); +- +- delta_start *= 1000000000 / ticks_per_sec; +- } +- count->val = delta_start; +- count->ena = count->run = delta_start; +- count->lost = 0; +- return 0; +-} +- + bool __evsel__match(const struct evsel *evsel, u32 type, u64 config) + { + +@@ -2074,6 +1881,7 @@ static struct perf_thread_map *empty_thread_map; + static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, + struct perf_thread_map *threads) + { ++ int ret = 0; + int nthreads = perf_thread_map__nr(threads); + + if ((perf_missing_features.write_backward && evsel->core.attr.write_backward) || +@@ -2104,19 +1912,14 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, + perf_evsel__alloc_fd(&evsel->core, perf_cpu_map__nr(cpus), nthreads) < 0) + return -ENOMEM; + +- if ((evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME || +- evsel__tool_event(evsel) == PERF_TOOL_USER_TIME) && +- !evsel->start_times) { +- evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus), nthreads, sizeof(__u64)); +- if (!evsel->start_times) +- return -ENOMEM; +- } ++ if (evsel__is_tool(evsel)) ++ ret = evsel__tool_pmu_prepare_open(evsel, cpus, nthreads); + + evsel->open_flags = PERF_FLAG_FD_CLOEXEC; + if (evsel->cgrp) + evsel->open_flags |= PERF_FLAG_PID_CGROUP; + +- return 0; ++ return ret; + } + + static void evsel__disable_missing_features(struct evsel *evsel) +@@ -2294,13 +2097,6 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, + int pid = -1, err, old_errno; + enum rlimit_action set_rlimit = NO_CHANGE; + +- if (evsel__tool_event(evsel) == PERF_TOOL_DURATION_TIME) { +- if (evsel->core.attr.sample_period) /* no sampling */ +- return -EINVAL; +- evsel->start_time = rdclock(); +- return 0; +- } +- + if (evsel__is_retire_lat(evsel)) + return tpebs_start(evsel->evlist); + +@@ -2325,6 +2121,12 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, + pr_debug3("Opening: %s\n", evsel__name(evsel)); + display_attr(&evsel->core.attr); + ++ if (evsel__is_tool(evsel)) { ++ return evsel__tool_pmu_open(evsel, threads, ++ start_cpu_map_idx, ++ end_cpu_map_idx); ++ } ++ + for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) { + + for (thread = 0; thread < nthreads; thread++) { +@@ -2336,46 +2138,6 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, + if (!evsel->cgrp && !evsel->core.system_wide) + pid = perf_thread_map__pid(threads, thread); + +- if (evsel__tool_event(evsel) == PERF_TOOL_USER_TIME || +- evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME) { +- bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME; +- __u64 *start_time = NULL; +- +- if (evsel->core.attr.sample_period) { +- /* no sampling */ +- err = -EINVAL; +- goto out_close; +- } +- if (pid > -1) { +- char buf[64]; +- +- snprintf(buf, sizeof(buf), "/proc/%d/stat", pid); +- fd = open(buf, O_RDONLY); +- evsel->pid_stat = true; +- } else { +- fd = open("/proc/stat", O_RDONLY); +- } +- FD(evsel, idx, thread) = fd; +- if (fd < 0) { +- err = -errno; +- goto out_close; +- } +- start_time = xyarray__entry(evsel->start_times, idx, thread); +- if (pid > -1) { +- err = read_pid_stat_field(fd, system ? 15 : 14, +- start_time); +- } else { +- struct perf_cpu cpu; +- +- cpu = perf_cpu_map__cpu(evsel->core.cpus, idx); +- err = read_stat_field(fd, cpu, system ? 3 : 1, +- start_time); +- } +- if (err) +- goto out_close; +- continue; +- } +- + group_fd = get_group_fd(evsel, idx, thread); + + if (group_fd == -2) { +diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h +index dc0d300776f16..b23fa3ca88883 100644 +--- a/tools/perf/util/evsel.h ++++ b/tools/perf/util/evsel.h +@@ -11,6 +11,7 @@ + #include + #include "symbol_conf.h" + #include "pmus.h" ++#include "pmu.h" + + struct bpf_object; + struct cgroup; +@@ -22,25 +23,9 @@ struct target; + struct hashmap; + struct bperf_leader_bpf; + struct bperf_follower_bpf; +-struct perf_pmu; + + typedef int (evsel__sb_cb_t)(union perf_event *event, void *data); + +-enum perf_tool_event { +- PERF_TOOL_NONE = 0, +- PERF_TOOL_DURATION_TIME = 1, +- PERF_TOOL_USER_TIME = 2, +- PERF_TOOL_SYSTEM_TIME = 3, +- +- PERF_TOOL_MAX, +-}; +- +-const char *perf_tool_event__to_str(enum perf_tool_event ev); +-enum perf_tool_event perf_tool_event__from_str(const char *str); +- +-#define perf_tool_event__for_each_event(ev) \ +- for ((ev) = PERF_TOOL_DURATION_TIME; (ev) < PERF_TOOL_MAX; ev++) +- + /** struct evsel - event selector + * + * @evlist - evlist this evsel is in, if it is in one. +@@ -83,7 +68,6 @@ struct evsel { + const char *unit; + struct cgroup *cgrp; + const char *metric_id; +- enum perf_tool_event tool_event; + /* parse modifier helper */ + int exclude_GH; + int sample_read; +@@ -323,21 +307,11 @@ const char *evsel__name(struct evsel *evsel); + bool evsel__name_is(struct evsel *evsel, const char *name); + const char *evsel__metric_id(const struct evsel *evsel); + +-static inline bool evsel__is_tool(const struct evsel *evsel) +-{ +- return evsel->tool_event != PERF_TOOL_NONE; +-} +- + static inline bool evsel__is_retire_lat(const struct evsel *evsel) + { + return evsel->retire_lat; + } + +-static inline enum perf_tool_event evsel__tool_event(const struct evsel *evsel) +-{ +- return evsel->tool_event; +-} +- + const char *evsel__group_name(struct evsel *evsel); + int evsel__group_desc(struct evsel *evsel, char *buf, size_t size); + +diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c +index 4dff3e925a47b..9181548e88810 100644 +--- a/tools/perf/util/metricgroup.c ++++ b/tools/perf/util/metricgroup.c +@@ -14,6 +14,7 @@ + #include "pmus.h" + #include "print-events.h" + #include "smt.h" ++#include "tool_pmu.h" + #include "expr.h" + #include "rblist.h" + #include +diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c +index fcc4dab618bee..ba84a451c70a3 100644 +--- a/tools/perf/util/parse-events.c ++++ b/tools/perf/util/parse-events.c +@@ -302,38 +302,6 @@ static int add_event(struct list_head *list, int *idx, + alternate_hw_config) ? 0 : -ENOMEM; + } + +-static int add_event_tool(struct list_head *list, int *idx, +- enum perf_tool_event tool_event) +-{ +- struct evsel *evsel; +- struct perf_event_attr attr = { +- .type = PERF_TYPE_SOFTWARE, +- .config = PERF_COUNT_SW_DUMMY, +- }; +- struct perf_cpu_map *cpu_list = NULL; +- +- if (tool_event == PERF_TOOL_DURATION_TIME) { +- /* Duration time is gathered globally, pretend it is only on CPU0. */ +- cpu_list = perf_cpu_map__new("0"); +- } +- evsel = __add_event(list, idx, &attr, /*init_attr=*/true, /*name=*/NULL, +- /*metric_id=*/NULL, /*pmu=*/NULL, +- /*config_terms=*/NULL, /*auto_merge_stats=*/false, +- cpu_list, +- /*alternate_hw_config=*/PERF_COUNT_HW_MAX); +- perf_cpu_map__put(cpu_list); +- if (!evsel) +- return -ENOMEM; +- evsel->tool_event = tool_event; +- if (tool_event == PERF_TOOL_DURATION_TIME +- || tool_event == PERF_TOOL_USER_TIME +- || tool_event == PERF_TOOL_SYSTEM_TIME) { +- free((char *)evsel->unit); +- evsel->unit = strdup("ns"); +- } +- return 0; +-} +- + /** + * parse_aliases - search names for entries beginning or equalling str ignoring + * case. If mutliple entries in names match str then the longest +@@ -1430,13 +1398,6 @@ int parse_events_add_numeric(struct parse_events_state *parse_state, + type, /*extended_type=*/0, config, head_config); + } + +-int parse_events_add_tool(struct parse_events_state *parse_state, +- struct list_head *list, +- int tool_event) +-{ +- return add_event_tool(list, &parse_state->idx, tool_event); +-} +- + static bool config_term_percore(struct list_head *config_terms) + { + struct evsel_config_term *term; +diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h +index 2b52f8d6aa29a..e9f59de2304be 100644 +--- a/tools/perf/util/parse-events.h ++++ b/tools/perf/util/parse-events.h +@@ -227,9 +227,6 @@ int parse_events_add_numeric(struct parse_events_state *parse_state, + u32 type, u64 config, + const struct parse_events_terms *head_config, + bool wildcard); +-int parse_events_add_tool(struct parse_events_state *parse_state, +- struct list_head *list, +- int tool_event); + int parse_events_add_cache(struct list_head *list, int *idx, const char *name, + struct parse_events_state *parse_state, + struct parse_events_terms *parsed_terms); +diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l +index 5a0bcd7f166ae..14e5bd856a187 100644 +--- a/tools/perf/util/parse-events.l ++++ b/tools/perf/util/parse-events.l +@@ -121,14 +121,6 @@ static int sym(yyscan_t scanner, int type, int config) + return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW; + } + +-static int tool(yyscan_t scanner, enum perf_tool_event event) +-{ +- YYSTYPE *yylval = parse_events_get_lval(scanner); +- +- yylval->num = event; +- return PE_VALUE_SYM_TOOL; +-} +- + static int term(yyscan_t scanner, enum parse_events__term_type type) + { + YYSTYPE *yylval = parse_events_get_lval(scanner); +@@ -404,9 +396,6 @@ cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COU + alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } + emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } + dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); } +-duration_time { return tool(yyscanner, PERF_TOOL_DURATION_TIME); } +-user_time { return tool(yyscanner, PERF_TOOL_USER_TIME); } +-system_time { return tool(yyscanner, PERF_TOOL_SYSTEM_TIME); } + bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); } + cgroup-switches { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CGROUP_SWITCHES); } + +diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y +index dcf47fabdfdd7..f888cbb076d67 100644 +--- a/tools/perf/util/parse-events.y ++++ b/tools/perf/util/parse-events.y +@@ -56,7 +56,6 @@ static void free_list_evsel(struct list_head* list_evsel) + + %token PE_START_EVENTS PE_START_TERMS + %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM +-%token PE_VALUE_SYM_TOOL + %token PE_EVENT_NAME + %token PE_RAW PE_NAME + %token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH +@@ -68,7 +67,6 @@ static void free_list_evsel(struct list_head* list_evsel) + %type PE_VALUE + %type PE_VALUE_SYM_HW + %type PE_VALUE_SYM_SW +-%type PE_VALUE_SYM_TOOL + %type PE_MODIFIER_EVENT + %type PE_TERM + %type value_sym +@@ -350,20 +348,6 @@ value_sym sep_slash_slash_dc + PE_ABORT(err); + $$ = list; + } +-| +-PE_VALUE_SYM_TOOL sep_slash_slash_dc +-{ +- struct list_head *list; +- int err; +- +- list = alloc_list(); +- if (!list) +- YYNOMEM; +- err = parse_events_add_tool(_parse_state, list, $1); +- if (err) +- YYNOMEM; +- $$ = list; +-} + + event_legacy_cache: + PE_LEGACY_CACHE opt_event_config +diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c +index 8885998c19530..15fb144e890f0 100644 +--- a/tools/perf/util/pmu.c ++++ b/tools/perf/util/pmu.c +@@ -19,6 +19,7 @@ + #include "evsel.h" + #include "pmu.h" + #include "pmus.h" ++#include "tool_pmu.h" + #include + #include + #include "parse-events.h" +@@ -1511,6 +1512,9 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, + { + bool zero = !!pmu->perf_event_attr_init_default; + ++ if (perf_pmu__is_tool(pmu)) ++ return tool_pmu__config_terms(attr, head_terms, err); ++ + /* Fake PMU doesn't have proper terms so nothing to configure in attr. */ + if (perf_pmu__is_fake(pmu)) + return 0; +@@ -1623,8 +1627,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_ + info->scale = 0.0; + info->snapshot = false; + +- /* Fake PMU doesn't rewrite terms. */ +- if (perf_pmu__is_fake(pmu)) ++ /* Tool/fake PMU doesn't rewrite terms. */ ++ if (perf_pmu__is_tool(pmu) || perf_pmu__is_fake(pmu)) + goto out; + + list_for_each_entry_safe(term, h, &head_terms->terms, list) { +@@ -1794,6 +1798,8 @@ bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name) + { + if (!name) + return false; ++ if (perf_pmu__is_tool(pmu)) ++ return perf_tool_event__from_str(name) != PERF_TOOL_NONE; + if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL) + return true; + if (pmu->cpu_aliases_added || !pmu->events_table) +@@ -1805,6 +1811,9 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu) + { + size_t nr; + ++ if (perf_pmu__is_tool(pmu)) ++ return tool_pmu__num_events(); ++ + pmu_aliases_parse(pmu); + nr = pmu->sysfs_aliases + pmu->sys_json_aliases; + +@@ -1866,6 +1875,9 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus, + int ret = 0; + struct strbuf sb; + ++ if (perf_pmu__is_tool(pmu)) ++ return tool_pmu__for_each_event_cb(pmu, state, cb); ++ + strbuf_init(&sb, /*hint=*/ 0); + pmu_aliases_parse(pmu); + pmu_add_cpu_aliases(pmu); +@@ -1954,6 +1966,7 @@ bool perf_pmu__is_software(const struct perf_pmu *pmu) + case PERF_TYPE_HW_CACHE: return false; + case PERF_TYPE_RAW: return false; + case PERF_TYPE_BREAKPOINT: return true; ++ case PERF_PMU_TYPE_TOOL: return true; + default: break; + } + for (size_t i = 0; i < ARRAY_SIZE(known_sw_pmus); i++) { +@@ -2281,6 +2294,9 @@ const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config) + if (!pmu) + return NULL; + ++ if (perf_pmu__is_tool(pmu)) ++ return perf_tool_event__to_str(config); ++ + pmu_aliases_parse(pmu); + pmu_add_cpu_aliases(pmu); + list_for_each_entry(event, &pmu->aliases, list) { +diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h +index 0222124b86b92..2dba1cfa20ddd 100644 +--- a/tools/perf/util/pmu.h ++++ b/tools/perf/util/pmu.h +@@ -37,6 +37,7 @@ struct perf_pmu_caps { + }; + + enum { ++ PERF_PMU_TYPE_TOOL = 0xFFFFFFFE, + PERF_PMU_TYPE_FAKE = 0xFFFFFFFF, + }; + +@@ -285,6 +286,7 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char + struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus); + void perf_pmu__delete(struct perf_pmu *pmu); + struct perf_pmu *perf_pmus__find_core_pmu(void); ++ + const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config); + + #endif /* __PMU_H */ +diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c +index 362596ed27294..5af26a08fb915 100644 +--- a/tools/perf/util/pmus.c ++++ b/tools/perf/util/pmus.c +@@ -15,6 +15,7 @@ + #include "evsel.h" + #include "pmus.h" + #include "pmu.h" ++#include "tool_pmu.h" + #include "print-events.h" + #include "strbuf.h" + +@@ -200,6 +201,7 @@ static void pmu_read_sysfs(bool core_only) + int fd; + DIR *dir; + struct dirent *dent; ++ struct perf_pmu *tool_pmu; + + if (read_sysfs_all_pmus || (core_only && read_sysfs_core_pmus)) + return; +@@ -229,6 +231,10 @@ static void pmu_read_sysfs(bool core_only) + pr_err("Failure to set up any core PMUs\n"); + } + list_sort(NULL, &core_pmus, pmus_cmp); ++ if (!core_only) { ++ tool_pmu = perf_pmus__tool_pmu(); ++ list_add_tail(&tool_pmu->list, &other_pmus); ++ } + list_sort(NULL, &other_pmus, pmus_cmp); + if (!list_empty(&core_pmus)) { + read_sysfs_core_pmus = true; +@@ -584,6 +590,9 @@ void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, voi + int len = pmu_name_len_no_suffix(pmu->name); + const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)"; + ++ if (perf_pmu__is_tool(pmu)) ++ continue; ++ + if (!pmu->is_core) + desc = NULL; + +diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c +index a1c71d9793bd8..83aaf7cda6359 100644 +--- a/tools/perf/util/print-events.c ++++ b/tools/perf/util/print-events.c +@@ -29,6 +29,7 @@ + #include "tracepoint.h" + #include "pfm.h" + #include "thread_map.h" ++#include "tool_pmu.h" + #include "util.h" + + #define MAX_NAME_LEN 100 +@@ -43,21 +44,6 @@ static const char * const event_type_descriptors[] = { + "Hardware breakpoint", + }; + +-static const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = { +- [PERF_TOOL_DURATION_TIME] = { +- .symbol = "duration_time", +- .alias = "", +- }, +- [PERF_TOOL_USER_TIME] = { +- .symbol = "user_time", +- .alias = "", +- }, +- [PERF_TOOL_SYSTEM_TIME] = { +- .symbol = "system_time", +- .alias = "", +- }, +-}; +- + /* + * Print the events from /tracing/events + */ +@@ -342,24 +328,6 @@ int print_hwcache_events(const struct print_callbacks *print_cb, void *print_sta + return 0; + } + +-void print_tool_events(const struct print_callbacks *print_cb, void *print_state) +-{ +- // Start at 1 because the first enum entry means no tool event. +- for (int i = 1; i < PERF_TOOL_MAX; ++i) { +- print_cb->print_event(print_state, +- "tool", +- /*pmu_name=*/NULL, +- event_symbols_tool[i].symbol, +- event_symbols_tool[i].alias, +- /*scale_unit=*/NULL, +- /*deprecated=*/false, +- "Tool event", +- /*desc=*/NULL, +- /*long_desc=*/NULL, +- /*encoding_desc=*/NULL); +- } +-} +- + void print_symbol_events(const struct print_callbacks *print_cb, void *print_state, + unsigned int type, const struct event_symbol *syms, + unsigned int max) +@@ -423,8 +391,6 @@ void print_events(const struct print_callbacks *print_cb, void *print_state) + print_symbol_events(print_cb, print_state, PERF_TYPE_SOFTWARE, + event_symbols_sw, PERF_COUNT_SW_MAX); + +- print_tool_events(print_cb, print_state); +- + print_hwcache_events(print_cb, print_state); + + perf_pmus__print_pmu_events(print_cb, print_state); +diff --git a/tools/perf/util/print-events.h b/tools/perf/util/print-events.h +index bf4290bef0cd6..445efa1636c1b 100644 +--- a/tools/perf/util/print-events.h ++++ b/tools/perf/util/print-events.h +@@ -36,7 +36,6 @@ void print_sdt_events(const struct print_callbacks *print_cb, void *print_state) + void print_symbol_events(const struct print_callbacks *print_cb, void *print_state, + unsigned int type, const struct event_symbol *syms, + unsigned int max); +-void print_tool_events(const struct print_callbacks *print_cb, void *print_state); + void print_tracepoint_events(const struct print_callbacks *print_cb, void *print_state); + bool is_event_supported(u8 type, u64 config); + +diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c +index ea96e4ebad8c8..a82a8ec79b399 100644 +--- a/tools/perf/util/stat-display.c ++++ b/tools/perf/util/stat-display.c +@@ -21,6 +21,7 @@ + #include "iostat.h" + #include "pmu.h" + #include "pmus.h" ++#include "tool_pmu.h" + + #define CNTR_NOT_SUPPORTED "" + #define CNTR_NOT_COUNTED "" +@@ -946,7 +947,10 @@ static bool should_skip_zero_counter(struct perf_stat_config *config, + if (config->aggr_mode == AGGR_THREAD && config->system_wide) + return true; + +- /* Tool events have the software PMU but are only gathered on 1. */ ++ /* ++ * Many tool events are only gathered on the first index, skip other ++ * zero values. ++ */ + if (evsel__is_tool(counter)) + return true; + +diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c +index 7c49997fab3a3..caffdaa8be9a1 100644 +--- a/tools/perf/util/stat-shadow.c ++++ b/tools/perf/util/stat-shadow.c +@@ -15,6 +15,7 @@ + #include + #include "iostat.h" + #include "util/hashmap.h" ++#include "tool_pmu.h" + + struct stats walltime_nsecs_stats; + struct rusage_stats ru_stats; +diff --git a/tools/perf/util/tool_pmu.c b/tools/perf/util/tool_pmu.c +new file mode 100644 +index 0000000000000..f41fed39d70d8 +--- /dev/null ++++ b/tools/perf/util/tool_pmu.c +@@ -0,0 +1,411 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++#include "cgroup.h" ++#include "counts.h" ++#include "evsel.h" ++#include "pmu.h" ++#include "print-events.h" ++#include "time-utils.h" ++#include "tool_pmu.h" ++#include ++#include ++#include ++#include ++#include ++ ++static const char *const tool_pmu__event_names[PERF_TOOL_MAX] = { ++ NULL, ++ "duration_time", ++ "user_time", ++ "system_time", ++}; ++ ++ ++const char *perf_tool_event__to_str(enum perf_tool_event ev) ++{ ++ if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX) ++ return tool_pmu__event_names[ev]; ++ ++ return NULL; ++} ++ ++enum perf_tool_event perf_tool_event__from_str(const char *str) ++{ ++ int i; ++ ++ perf_tool_event__for_each_event(i) { ++ if (!strcasecmp(str, tool_pmu__event_names[i])) ++ return i; ++ } ++ return PERF_TOOL_NONE; ++} ++ ++static int tool_pmu__config_term(struct perf_event_attr *attr, ++ struct parse_events_term *term, ++ struct parse_events_error *err) ++{ ++ if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) { ++ enum perf_tool_event ev = perf_tool_event__from_str(term->config); ++ ++ if (ev == PERF_TOOL_NONE) ++ goto err_out; ++ ++ attr->config = ev; ++ return 0; ++ } ++err_out: ++ if (err) { ++ char *err_str; ++ ++ parse_events_error__handle(err, term->err_val, ++ asprintf(&err_str, ++ "unexpected tool event term (%s) %s", ++ parse_events__term_type_str(term->type_term), ++ term->config) < 0 ++ ? strdup("unexpected tool event term") ++ : err_str, ++ NULL); ++ } ++ return -EINVAL; ++} ++ ++int tool_pmu__config_terms(struct perf_event_attr *attr, ++ struct parse_events_terms *terms, ++ struct parse_events_error *err) ++{ ++ struct parse_events_term *term; ++ ++ list_for_each_entry(term, &terms->terms, list) { ++ if (tool_pmu__config_term(attr, term, err)) ++ return -EINVAL; ++ } ++ ++ return 0; ++ ++} ++ ++int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb) ++{ ++ struct pmu_event_info info = { ++ .pmu = pmu, ++ .event_type_desc = "Tool event", ++ }; ++ int i; ++ ++ perf_tool_event__for_each_event(i) { ++ int ret; ++ ++ info.name = perf_tool_event__to_str(i); ++ info.alias = NULL; ++ info.scale_unit = NULL; ++ info.desc = NULL; ++ info.long_desc = NULL; ++ info.encoding_desc = NULL; ++ info.topic = NULL; ++ info.pmu_name = pmu->name; ++ info.deprecated = false; ++ ret = cb(state, &info); ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++bool perf_pmu__is_tool(const struct perf_pmu *pmu) ++{ ++ return pmu && pmu->type == PERF_PMU_TYPE_TOOL; ++} ++ ++bool evsel__is_tool(const struct evsel *evsel) ++{ ++ return perf_pmu__is_tool(evsel->pmu); ++} ++ ++enum perf_tool_event evsel__tool_event(const struct evsel *evsel) ++{ ++ if (!evsel__is_tool(evsel)) ++ return PERF_TOOL_NONE; ++ ++ return (enum perf_tool_event)evsel->core.attr.config; ++} ++ ++const char *evsel__tool_pmu_event_name(const struct evsel *evsel) ++{ ++ return perf_tool_event__to_str(evsel->core.attr.config); ++} ++ ++static bool read_until_char(struct io *io, char e) ++{ ++ int c; ++ ++ do { ++ c = io__get_char(io); ++ if (c == -1) ++ return false; ++ } while (c != e); ++ return true; ++} ++ ++static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val) ++{ ++ char buf[256]; ++ struct io io; ++ int i; ++ ++ io__init(&io, fd, buf, sizeof(buf)); ++ ++ /* Skip lines to relevant CPU. */ ++ for (i = -1; i < cpu.cpu; i++) { ++ if (!read_until_char(&io, '\n')) ++ return -EINVAL; ++ } ++ /* Skip to "cpu". */ ++ if (io__get_char(&io) != 'c') return -EINVAL; ++ if (io__get_char(&io) != 'p') return -EINVAL; ++ if (io__get_char(&io) != 'u') return -EINVAL; ++ ++ /* Skip N of cpuN. */ ++ if (!read_until_char(&io, ' ')) ++ return -EINVAL; ++ ++ i = 1; ++ while (true) { ++ if (io__get_dec(&io, val) != ' ') ++ break; ++ if (field == i) ++ return 0; ++ i++; ++ } ++ return -EINVAL; ++} ++ ++static int read_pid_stat_field(int fd, int field, __u64 *val) ++{ ++ char buf[256]; ++ struct io io; ++ int c, i; ++ ++ io__init(&io, fd, buf, sizeof(buf)); ++ if (io__get_dec(&io, val) != ' ') ++ return -EINVAL; ++ if (field == 1) ++ return 0; ++ ++ /* Skip comm. */ ++ if (io__get_char(&io) != '(' || !read_until_char(&io, ')')) ++ return -EINVAL; ++ if (field == 2) ++ return -EINVAL; /* String can't be returned. */ ++ ++ /* Skip state */ ++ if (io__get_char(&io) != ' ' || io__get_char(&io) == -1) ++ return -EINVAL; ++ if (field == 3) ++ return -EINVAL; /* String can't be returned. */ ++ ++ /* Loop over numeric fields*/ ++ if (io__get_char(&io) != ' ') ++ return -EINVAL; ++ ++ i = 4; ++ while (true) { ++ c = io__get_dec(&io, val); ++ if (c == -1) ++ return -EINVAL; ++ if (c == -2) { ++ /* Assume a -ve was read */ ++ c = io__get_dec(&io, val); ++ *val *= -1; ++ } ++ if (c != ' ') ++ return -EINVAL; ++ if (field == i) ++ return 0; ++ i++; ++ } ++ return -EINVAL; ++} ++ ++int evsel__tool_pmu_prepare_open(struct evsel *evsel, ++ struct perf_cpu_map *cpus, ++ int nthreads) ++{ ++ if ((evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME || ++ evsel__tool_event(evsel) == PERF_TOOL_USER_TIME) && ++ !evsel->start_times) { ++ evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus), ++ nthreads, ++ sizeof(__u64)); ++ if (!evsel->start_times) ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) ++ ++int evsel__tool_pmu_open(struct evsel *evsel, ++ struct perf_thread_map *threads, ++ int start_cpu_map_idx, int end_cpu_map_idx) ++{ ++ enum perf_tool_event ev = evsel__tool_event(evsel); ++ int pid = -1, idx = 0, thread = 0, nthreads, err = 0, old_errno; ++ ++ if (ev == PERF_TOOL_DURATION_TIME) { ++ if (evsel->core.attr.sample_period) /* no sampling */ ++ return -EINVAL; ++ evsel->start_time = rdclock(); ++ return 0; ++ } ++ ++ if (evsel->cgrp) ++ pid = evsel->cgrp->fd; ++ ++ nthreads = perf_thread_map__nr(threads); ++ for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) { ++ for (thread = 0; thread < nthreads; thread++) { ++ if (thread >= nthreads) ++ break; ++ ++ if (!evsel->cgrp && !evsel->core.system_wide) ++ pid = perf_thread_map__pid(threads, thread); ++ ++ if (ev == PERF_TOOL_USER_TIME || ev == PERF_TOOL_SYSTEM_TIME) { ++ bool system = ev == PERF_TOOL_SYSTEM_TIME; ++ __u64 *start_time = NULL; ++ int fd; ++ ++ if (evsel->core.attr.sample_period) { ++ /* no sampling */ ++ err = -EINVAL; ++ goto out_close; ++ } ++ if (pid > -1) { ++ char buf[64]; ++ ++ snprintf(buf, sizeof(buf), "/proc/%d/stat", pid); ++ fd = open(buf, O_RDONLY); ++ evsel->pid_stat = true; ++ } else { ++ fd = open("/proc/stat", O_RDONLY); ++ } ++ FD(evsel, idx, thread) = fd; ++ if (fd < 0) { ++ err = -errno; ++ goto out_close; ++ } ++ start_time = xyarray__entry(evsel->start_times, idx, thread); ++ if (pid > -1) { ++ err = read_pid_stat_field(fd, system ? 15 : 14, ++ start_time); ++ } else { ++ struct perf_cpu cpu; ++ ++ cpu = perf_cpu_map__cpu(evsel->core.cpus, idx); ++ err = read_stat_field(fd, cpu, system ? 3 : 1, ++ start_time); ++ } ++ if (err) ++ goto out_close; ++ } ++ ++ } ++ } ++ return 0; ++out_close: ++ if (err) ++ threads->err_thread = thread; ++ ++ old_errno = errno; ++ do { ++ while (--thread >= 0) { ++ if (FD(evsel, idx, thread) >= 0) ++ close(FD(evsel, idx, thread)); ++ FD(evsel, idx, thread) = -1; ++ } ++ thread = nthreads; ++ } while (--idx >= 0); ++ errno = old_errno; ++ return err; ++} ++ ++int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread) ++{ ++ __u64 *start_time, cur_time, delta_start; ++ int fd, err = 0; ++ struct perf_counts_values *count; ++ bool adjust = false; ++ ++ count = perf_counts(evsel->counts, cpu_map_idx, thread); ++ ++ switch (evsel__tool_event(evsel)) { ++ case PERF_TOOL_DURATION_TIME: ++ /* ++ * Pretend duration_time is only on the first CPU and thread, or ++ * else aggregation will scale duration_time by the number of ++ * CPUs/threads. ++ */ ++ start_time = &evsel->start_time; ++ if (cpu_map_idx == 0 && thread == 0) ++ cur_time = rdclock(); ++ else ++ cur_time = *start_time; ++ break; ++ case PERF_TOOL_USER_TIME: ++ case PERF_TOOL_SYSTEM_TIME: { ++ bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME; ++ ++ start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread); ++ fd = FD(evsel, cpu_map_idx, thread); ++ lseek(fd, SEEK_SET, 0); ++ if (evsel->pid_stat) { ++ /* The event exists solely on 1 CPU. */ ++ if (cpu_map_idx == 0) ++ err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time); ++ else ++ cur_time = 0; ++ } else { ++ /* The event is for all threads. */ ++ if (thread == 0) { ++ struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus, ++ cpu_map_idx); ++ ++ err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time); ++ } else { ++ cur_time = 0; ++ } ++ } ++ adjust = true; ++ break; ++ } ++ case PERF_TOOL_NONE: ++ case PERF_TOOL_MAX: ++ default: ++ err = -EINVAL; ++ } ++ if (err) ++ return err; ++ ++ delta_start = cur_time - *start_time; ++ if (adjust) { ++ __u64 ticks_per_sec = sysconf(_SC_CLK_TCK); ++ ++ delta_start *= 1000000000 / ticks_per_sec; ++ } ++ count->val = delta_start; ++ count->ena = count->run = delta_start; ++ count->lost = 0; ++ return 0; ++} ++ ++struct perf_pmu *perf_pmus__tool_pmu(void) ++{ ++ static struct perf_pmu tool = { ++ .name = "tool", ++ .type = PERF_PMU_TYPE_TOOL, ++ .aliases = LIST_HEAD_INIT(tool.aliases), ++ .caps = LIST_HEAD_INIT(tool.caps), ++ .format = LIST_HEAD_INIT(tool.format), ++ }; ++ ++ return &tool; ++} +diff --git a/tools/perf/util/tool_pmu.h b/tools/perf/util/tool_pmu.h +new file mode 100644 +index 0000000000000..05a4052c8b9d8 +--- /dev/null ++++ b/tools/perf/util/tool_pmu.h +@@ -0,0 +1,51 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __TOOL_PMU_H ++#define __TOOL_PMU_H ++ ++#include "pmu.h" ++ ++struct evsel; ++struct perf_thread_map; ++struct print_callbacks; ++ ++enum perf_tool_event { ++ PERF_TOOL_NONE = 0, ++ PERF_TOOL_DURATION_TIME = 1, ++ PERF_TOOL_USER_TIME = 2, ++ PERF_TOOL_SYSTEM_TIME = 3, ++ ++ PERF_TOOL_MAX, ++}; ++ ++#define perf_tool_event__for_each_event(ev) \ ++ for ((ev) = PERF_TOOL_DURATION_TIME; (ev) < PERF_TOOL_MAX; ev++) ++ ++static inline size_t tool_pmu__num_events(void) ++{ ++ return PERF_TOOL_MAX - 1; ++} ++ ++const char *perf_tool_event__to_str(enum perf_tool_event ev); ++enum perf_tool_event perf_tool_event__from_str(const char *str); ++int tool_pmu__config_terms(struct perf_event_attr *attr, ++ struct parse_events_terms *terms, ++ struct parse_events_error *err); ++int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb); ++ ++bool perf_pmu__is_tool(const struct perf_pmu *pmu); ++ ++ ++bool evsel__is_tool(const struct evsel *evsel); ++enum perf_tool_event evsel__tool_event(const struct evsel *evsel); ++const char *evsel__tool_pmu_event_name(const struct evsel *evsel); ++int evsel__tool_pmu_prepare_open(struct evsel *evsel, ++ struct perf_cpu_map *cpus, ++ int nthreads); ++int evsel__tool_pmu_open(struct evsel *evsel, ++ struct perf_thread_map *threads, ++ int start_cpu_map_idx, int end_cpu_map_idx); ++int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread); ++ ++struct perf_pmu *perf_pmus__tool_pmu(void); ++ ++#endif /* __TOOL_PMU_H */ +-- +2.53.0 + diff --git a/queue-6.12/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch b/queue-6.12/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch new file mode 100644 index 0000000000..b385517f9c --- /dev/null +++ b/queue-6.12/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch @@ -0,0 +1,115 @@ +From f2c3ce9236a2493f526e0c74401ee63f11da5ed2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:36:39 +0000 +Subject: perf: tools: cs-etm: Fix print issue for Coresight debug in ETE/TRBE + trace + +From: Mike Leach + +[ Upstream commit 6c478e7b3eba3f387a2d6c749e3e3ee0f8ad1c53 ] + +Building perf with CORESIGHT=1 and the optional CSTRACE_RAW=1 enables +additional debug printing of raw trace data when using command:- +perf report --dump. + +This raw trace prints the CoreSight formatted trace frames, which may be +used to investigate suspected issues with trace quality / corruption / +decode. + +These frames are not present in ETE + TRBE trace. +This fix removes the unnecessary call to print these frames. + +This fix also rationalises implementation - original code had helper +function that unnecessarily repeated initialisation calls that had +already been made. + +Due to an addtional fault with the OpenCSD library, this call when ETE/TRBE +are being decoded will cause a segfault in perf. This fix also prevents +that problem for perf using older (<= 1.8.0 version) OpenCSD libraries. + +Fixes: 68ffe3902898 ("perf tools: Add decoder mechanic to support dumping trace data") +Reported-by: Leo Yan +Signed-off-by: Mike Leach +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 51 +++++-------------- + 1 file changed, 13 insertions(+), 38 deletions(-) + +diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +index b78ef0262135c..9bf09a856b44a 100644 +--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c ++++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +@@ -237,46 +237,24 @@ cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, + (void *)decoder, + cs_etm_decoder__print_str_cb); + if (ret != 0) +- ret = -1; +- +- return 0; +-} ++ return -1; + + #ifdef CS_LOG_RAW_FRAMES +-static void +-cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params, +- struct cs_etm_decoder *decoder) +-{ +- /* Only log these during a --dump operation */ +- if (d_params->operation == CS_ETM_OPERATION_PRINT) { +- /* set up a library default logger to process the +- * raw frame printer we add later +- */ +- ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); +- +- /* no stdout / err / file output */ +- ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); +- +- /* set the string CB for the default logger, +- * passes strings to perf print logger. +- */ +- ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, +- (void *)decoder, +- cs_etm_decoder__print_str_cb); +- ++ /* ++ * Only log raw frames if --dump operation and hardware is actually ++ * generating formatted CoreSight trace frames ++ */ ++ if ((d_params->operation == CS_ETM_OPERATION_PRINT) && ++ (d_params->formatted == true)) { + /* use the built in library printer for the raw frames */ +- ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, +- CS_RAW_DEBUG_FLAGS); ++ ret = ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, ++ CS_RAW_DEBUG_FLAGS); ++ if (ret != 0) ++ return -1; + } +-} +-#else +-static void +-cs_etm_decoder__init_raw_frame_logging( +- struct cs_etm_decoder_params *d_params __maybe_unused, +- struct cs_etm_decoder *decoder __maybe_unused) +-{ +-} + #endif ++ return 0; ++} + + static ocsd_datapath_resp_t + cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, +@@ -755,9 +733,6 @@ cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params, + if (ret != 0) + goto err_free_decoder; + +- /* init raw frame logging if required */ +- cs_etm_decoder__init_raw_frame_logging(d_params, decoder); +- + for (i = 0; i < decoders; i++) { + ret = cs_etm_decoder__create_etm_decoder(d_params, + &t_params[i], +-- +2.53.0 + diff --git a/queue-6.12/perf-tools-fix-module-symbol-resolution-for-non-zero.patch b/queue-6.12/perf-tools-fix-module-symbol-resolution-for-non-zero.patch new file mode 100644 index 0000000000..0c70b3818a --- /dev/null +++ b/queue-6.12/perf-tools-fix-module-symbol-resolution-for-non-zero.patch @@ -0,0 +1,77 @@ +From 286c115679c9bfe4a6c47c7a9f4f1732a5879785 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 11:58:04 -0400 +Subject: perf tools: Fix module symbol resolution for non-zero .text sh_addr + +From: Chuck Lever + +[ Upstream commit 9a82bfde4775b7a87cd1a7e791f46f83ae442848 ] + +When perf resolves symbols from kernel module ELF files (ET_REL), +it converts symbol addresses to file offsets so that sample IPs +can be matched to the correct symbol. The conversion adjusts each +symbol's st_value: + + sym->st_value -= shdr->sh_addr - shdr->sh_offset; + +For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr +is the section's virtual base, so subtracting sh_addr and adding +sh_offset correctly yields a file offset. + +For kernel modules (ET_REL), st_value is a section-relative +offset. The module loader ignores sh_addr entirely and places +symbols at module_base + st_value. Converting to file offset +requires only adding sh_offset; subtracting sh_addr introduces an +error equal to sh_addr bytes. + +When .text has sh_addr == 0 -- the historical norm for simple +modules -- both formulas produce the same result and the bug is +latent. As modules gain more metadata sections before .text (.note, +.static_call.text, etc.), the linker assigns .text a non-zero +sh_addr, exposing the defect. For example, nfsd.ko on this kernel +has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90. + +The effect is that all .text symbols in affected modules +shift by sh_addr bytes relative to sample IPs, causing perf +report to attribute samples to incorrect, nearby symbols. This +was observed as 13% of LLC-load-miss samples misattributed +to nfsd_file_get_dio_attrs when the actual hot function was +nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol +table. + +Use the existing dso__rel() flag (already set for ET_REL modules) +to select the correct adjustment: add sh_offset for ET_REL, +subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN. + +Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules") +Signed-off-by: Chuck Lever +Reviewed-by: Ian Rogers +Tested-by: Thomas Richter +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/symbol-elf.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c +index e398abfd13a09..61f931997f2ec 100644 +--- a/tools/perf/util/symbol-elf.c ++++ b/tools/perf/util/symbol-elf.c +@@ -1429,8 +1429,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, + char dso_name[PATH_MAX]; + + /* Adjust symbol to map to file offset */ +- if (adjust_kernel_syms) +- sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ if (adjust_kernel_syms) { ++ if (dso__rel(dso)) ++ sym->st_value += shdr->sh_offset; ++ else ++ sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ } + + if (strcmp(section_name, (dso__short_name(curr_dso) + dso__short_name_len(dso))) == 0) + return 0; +-- +2.53.0 + diff --git a/queue-6.12/perf-util-kill-die-prototype-dead-for-a-long-time.patch b/queue-6.12/perf-util-kill-die-prototype-dead-for-a-long-time.patch new file mode 100644 index 0000000000..809f2e1335 --- /dev/null +++ b/queue-6.12/perf-util-kill-die-prototype-dead-for-a-long-time.patch @@ -0,0 +1,39 @@ +From 06e45935dd90ddc7aac0c07a2983bd014531f841 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:31:57 -0300 +Subject: perf util: Kill die() prototype, dead for a long time + +From: Arnaldo Carvalho de Melo + +[ Upstream commit e5cce1b9c82fbd48e2f1f7a25a9fad8ee228176f ] + +In fef2a735167a827a ("perf tools: Kill die()") the die() function was +removed, but not the prototype in util.h, now when building with +LIBPERL=1, during a 'make -C tools/perf build-test' routine test, it is +failing as perl likes die() calls and then this clashes with this +remnant, remove it. + +Fixes: fef2a735167a827a ("perf tools: Kill die()") +Reviewed-by: Ian Rogers +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/util.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h +index 9966c21aaf048..bc30d038817db 100644 +--- a/tools/perf/util/util.h ++++ b/tools/perf/util/util.h +@@ -26,7 +26,6 @@ extern bool perf_guest; + + /* General helper functions */ + void usage(const char *err) __noreturn; +-void die(const char *err, ...) __noreturn __printf(1, 2); + + struct dirent; + struct strlist; +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-abx500-fix-type-of-argument-variable.patch b/queue-6.12/pinctrl-abx500-fix-type-of-argument-variable.patch new file mode 100644 index 0000000000..5f3b9722f1 --- /dev/null +++ b/queue-6.12/pinctrl-abx500-fix-type-of-argument-variable.patch @@ -0,0 +1,38 @@ +From eb85432a7add7ca5f2684c15a7d359f7fb014a21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 23:15:06 +0800 +Subject: pinctrl: abx500: Fix type of 'argument' variable + +From: Yu-Chun Lin + +[ Upstream commit 34006f77890d050e6d80cbee365b5d703c1140b4 ] + +The argument variable is assigned the return value of +pinconf_to_config_argument(), which returns a u32. Change its type from +enum pin_config_param to unsigned int to correctly store the configuration +argument. + +Fixes: 03b054e9696c ("pinctrl: Pass all configs to driver on pin_config_set()") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/nomadik/pinctrl-abx500.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c +index 68750b6f8e57a..22ef6c2d16a61 100644 +--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c ++++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c +@@ -855,7 +855,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, + int ret = -EINVAL; + int i; + enum pin_config_param param; +- enum pin_config_param argument; ++ unsigned int argument; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch b/queue-6.12/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch new file mode 100644 index 0000000000..269f226e51 --- /dev/null +++ b/queue-6.12/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch @@ -0,0 +1,39 @@ +From 7c7aba83b30b60b5d70ab63bb722f94735e70a08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 17:43:35 +0100 +Subject: pinctrl: cy8c95x0: Avoid returning positive values to user space + +From: Andy Shevchenko + +[ Upstream commit 5ad32c3607cf241a1a2680cabd64cbcd757227aa ] + +When probe fails due to unclear interrupt status register, it returns +a positive number instead of the proper error code. Fix this accordingly. + +Fixes: e6cbbe42944d ("pinctrl: Add Cypress cy8c95x0 support") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202602271847.vVWkqLBD-lkp@intel.com/ +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index baf32847cea5a..c7948e2a08028 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1355,7 +1355,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); + if (ret) +- return dev_err_probe(dev, ret, "failed to clear irq status register\n"); ++ return dev_err_probe(dev, -EBUSY, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-cy8c95x0-remove-duplicate-error-message.patch b/queue-6.12/pinctrl-cy8c95x0-remove-duplicate-error-message.patch new file mode 100644 index 0000000000..7e8c7b1182 --- /dev/null +++ b/queue-6.12/pinctrl-cy8c95x0-remove-duplicate-error-message.patch @@ -0,0 +1,73 @@ +From 3aadb121b6ba566c871b42d33ef2222b3e498f05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:53 +0100 +Subject: pinctrl: cy8c95x0: remove duplicate error message + +From: Andy Shevchenko + +[ Upstream commit 970dacb3b9f0fedbbbcfd7dbf1f4f22340b3f359 ] + +The pin control core is covered to report any error via message. +The devm_request_threaded_irq() already prints an error message. +Remove the duplicates. + +While at it, drop the info message as the same information about +an IRQ in use can be retrieved differently. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 21 +++++---------------- + 1 file changed, 5 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index 7a6a1434ae7f4..adbfea8ca5fd6 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1345,6 +1345,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + { + struct gpio_irq_chip *girq = &chip->gpio_chip.irq; + DECLARE_BITMAP(pending_irqs, MAX_LINE); ++ struct device *dev = chip->dev; + int ret; + + mutex_init(&chip->irq_lock); +@@ -1371,17 +1372,9 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + girq->handler = handle_simple_irq; + girq->threaded = true; + +- ret = devm_request_threaded_irq(chip->dev, irq, +- NULL, cy8c95x0_irq_handler, +- IRQF_ONESHOT | IRQF_SHARED, +- dev_name(chip->dev), chip); +- if (ret) { +- dev_err(chip->dev, "failed to request irq %d\n", irq); +- return ret; +- } +- dev_info(chip->dev, "Registered threaded IRQ\n"); +- +- return 0; ++ return devm_request_threaded_irq(dev, irq, NULL, cy8c95x0_irq_handler, ++ IRQF_ONESHOT | IRQF_SHARED, ++ dev_name(chip->dev), chip); + } + + static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) +@@ -1397,11 +1390,7 @@ static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) + pd->owner = THIS_MODULE; + + chip->pctldev = devm_pinctrl_register(chip->dev, pd, chip); +- if (IS_ERR(chip->pctldev)) +- return dev_err_probe(chip->dev, PTR_ERR(chip->pctldev), +- "can't register controller\n"); +- +- return 0; ++ return PTR_ERR_OR_ZERO(chip->pctldev); + } + + static int cy8c95x0_detect(struct i2c_client *client, +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch b/queue-6.12/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch new file mode 100644 index 0000000000..e2cb7e3bca --- /dev/null +++ b/queue-6.12/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch @@ -0,0 +1,40 @@ +From d9ee97fcc70f6e70165d8d820130d178f96c0491 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:54 +0100 +Subject: pinctrl: cy8c95x0: Unify messages with help of dev_err_probe() + +From: Andy Shevchenko + +[ Upstream commit 014884732095b982412d13d3220c3fe8483b9b3e ] + +Unify error messages that might appear during probe phase by +switching to use dev_err_probe(). + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index adbfea8ca5fd6..baf32847cea5a 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1354,10 +1354,8 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); +- if (ret) { +- dev_err(chip->dev, "failed to clear irq status register\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-pinctrl-pic32-fix-resource-leak.patch b/queue-6.12/pinctrl-pinctrl-pic32-fix-resource-leak.patch new file mode 100644 index 0000000000..9c2c8f9245 --- /dev/null +++ b/queue-6.12/pinctrl-pinctrl-pic32-fix-resource-leak.patch @@ -0,0 +1,72 @@ +From 14940226330c9408151c185eff021eaac1de8a80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:56:23 -0600 +Subject: pinctrl: pinctrl-pic32: Fix resource leak + +From: Ethan Tidmore + +[ Upstream commit fe5560688f3ba98364c7de7b4f8dc240ffd1ff75 ] + +Fix three possible resource leaks by using the devres version of +clk_prepare_enable(). Also, update error message accordingly. + +Detected by Smatch: +drivers/pinctrl/pinctrl-pic32.c:2211 pic32_pinctrl_probe() warn: +'pctl->clk' from clk_prepare_enable() not released on lines: 2208. + +drivers/pinctrl/pinctrl-pic32.c:2274 pic32_gpio_probe() warn: +'bank->clk' from clk_prepare_enable() not released on lines: 2264,2272. + +Fixes: 2ba384e6c3810 ("pinctrl: pinctrl-pic32: Add PIC32 pin control driver") +Signed-off-by: Ethan Tidmore +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-pic32.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c +index bf827ab081a1d..f87b5964e8b31 100644 +--- a/drivers/pinctrl/pinctrl-pic32.c ++++ b/drivers/pinctrl/pinctrl-pic32.c +@@ -2173,16 +2173,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev) + if (IS_ERR(pctl->reg_base)) + return PTR_ERR(pctl->reg_base); + +- pctl->clk = devm_clk_get(&pdev->dev, NULL); ++ pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(pctl->clk)) { + ret = PTR_ERR(pctl->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(pctl->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +@@ -2238,16 +2232,10 @@ static int pic32_gpio_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- bank->clk = devm_clk_get(&pdev->dev, NULL); ++ bank->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bank->clk)) { + ret = PTR_ERR(bank->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(bank->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-realtek-fix-function-signature-for-config-ar.patch b/queue-6.12/pinctrl-realtek-fix-function-signature-for-config-ar.patch new file mode 100644 index 0000000000..6ce4cdb3ff --- /dev/null +++ b/queue-6.12/pinctrl-realtek-fix-function-signature-for-config-ar.patch @@ -0,0 +1,37 @@ +From fef0962c0ae332c86517ce4e8d4e266571488f11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 19:54:03 +0800 +Subject: pinctrl: realtek: Fix function signature for config argument + +From: Yu-Chun Lin + +[ Upstream commit 1f5451844786ed203605528dca9e5d84ed378160 ] + +The argument originates from pinconf_to_config_argument(), which returns a +u32. Therefore, the arg parameter should be an unsigned int instead of enum +pin_config_param. + +Fixes: e99ce78030db ("pinctrl: realtek: Add common pinctrl driver for Realtek DHC RTD SoCs") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/realtek/pinctrl-rtd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c +index 2440604863327..4c876d1f6ad59 100644 +--- a/drivers/pinctrl/realtek/pinctrl-rtd.c ++++ b/drivers/pinctrl/realtek/pinctrl-rtd.c +@@ -279,7 +279,7 @@ static const struct rtd_pin_sconfig_desc *rtd_pinctrl_find_sconfig(struct rtd_pi + static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, + unsigned int pinnr, + enum pin_config_param param, +- enum pin_config_param arg) ++ unsigned int arg) + { + const struct rtd_pin_config_desc *config_desc; + const struct rtd_pin_sconfig_desc *sconfig_desc; +-- +2.53.0 + diff --git a/queue-6.12/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch b/queue-6.12/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch new file mode 100644 index 0000000000..1132b8197f --- /dev/null +++ b/queue-6.12/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch @@ -0,0 +1,47 @@ +From 1f08fc828df52bca250fb3d91573ce8160ac45d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:24:51 +0000 +Subject: pinctrl: renesas: rzg2l: Fix save/restore of {IOLH,IEN,PUPD,SMT} + registers + +From: Biju Das + +[ Upstream commit d9a60e367919752a1d398ebeba667f1e200fae1e ] + +The rzg2l_pinctrl_pm_setup_regs() handles save/restore of +{IOLH,IEN,PUPD,SMT} registers during s2ram, but only for ports where all +pins share the same pincfg. Extend the code to also support ports with +variable pincfg per pin, so that {IOLH,IEN,PUPD,SMT} registers are +correctly saved and restored for all pins. + +Fixes: 254203f9a94c ("pinctrl: renesas: rzg2l: Add suspend/resume support") +Signed-off-by: Biju Das +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260326162459.101414-1-biju.das.jz@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/renesas/pinctrl-rzg2l.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +index 8a7eb11df9029..bcb0c39369e05 100644 +--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c ++++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +@@ -2812,6 +2812,13 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen + off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg); + pincnt = hweight8(FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg)); + ++ if (cfg & RZG2L_VARIABLE_CFG) { ++ unsigned int pin = port * RZG2L_PINS_PER_PORT; ++ ++ for (unsigned int i = 0; i < RZG2L_PINS_PER_PORT; i++) ++ cfg |= *(u64 *)pctrl->desc.pins[pin + i].drv_data; ++ } ++ + caps = FIELD_GET(PIN_CFG_MASK, cfg); + has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)); + has_ien = !!(caps & PIN_CFG_IEN); +-- +2.53.0 + diff --git a/queue-6.12/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch b/queue-6.12/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch new file mode 100644 index 0000000000..09da6ce9e4 --- /dev/null +++ b/queue-6.12/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch @@ -0,0 +1,49 @@ +From 41db2ab5c6f760b31a0c6221b7a82d2fee02af0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:47:03 +0100 +Subject: platform/chrome: chromeos_tbmc: Drop wakeup source on remove + +From: Rafael J. Wysocki + +[ Upstream commit 5d441a4bc93642ed6f41da87327a39946b4e1455 ] + +The wakeup source added by device_init_wakeup() in chromeos_tbmc_add() +needs to be dropped during driver removal, so add a .remove() callback +to the driver for this purpose. + +Fixes: 0144c00ed86b ("platform/chrome: chromeos_tbmc: Report wake events") +Signed-off-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/6151957.MhkbZ0Pkbq@rafael.j.wysocki +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/chromeos_tbmc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c +index d1cf8f3463ce3..e248567c0a182 100644 +--- a/drivers/platform/chrome/chromeos_tbmc.c ++++ b/drivers/platform/chrome/chromeos_tbmc.c +@@ -95,6 +95,11 @@ static int chromeos_tbmc_add(struct acpi_device *adev) + return 0; + } + ++static void chromeos_tbmc_remove(struct acpi_device *adev) ++{ ++ device_init_wakeup(&adev->dev, false); ++} ++ + static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = { + { ACPI_DRV_NAME, 0 }, + { } +@@ -110,6 +115,7 @@ static struct acpi_driver chromeos_tbmc_driver = { + .ids = chromeos_tbmc_acpi_device_ids, + .ops = { + .add = chromeos_tbmc_add, ++ .remove = chromeos_tbmc_remove, + .notify = chromeos_tbmc_notify, + }, + .drv.pm = &chromeos_tbmc_pm_ops, +-- +2.53.0 + diff --git a/queue-6.12/platform-surface-surfacepro3_button-drop-wakeup-sour.patch b/queue-6.12/platform-surface-surfacepro3_button-drop-wakeup-sour.patch new file mode 100644 index 0000000000..43a6730e01 --- /dev/null +++ b/queue-6.12/platform-surface-surfacepro3_button-drop-wakeup-sour.patch @@ -0,0 +1,41 @@ +From 1dd56a00c94c07d4181d60f235b657971f75dbab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:54:08 +0100 +Subject: platform/surface: surfacepro3_button: Drop wakeup source on remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 1410a228ab2d36fe2b383415a632ae12048d4f3a ] + +The wakeup source added by device_init_wakeup() in surface_button_add() +needs to be dropped during driver removal, so update the driver to do +that. + +Fixes: 19351f340765 ("platform/x86: surfacepro3: Support for wakeup from suspend-to-idle") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/4368848.1IzOArtZ34@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/surface/surfacepro3_button.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979cd..7c7622f8f8716 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -243,6 +243,7 @@ static void surface_button_remove(struct acpi_device *device) + { + struct surface_button *button = acpi_driver_data(device); + ++ device_init_wakeup(&device->dev, false); + input_unregister_device(button->input); + kfree(button); + } +-- +2.53.0 + diff --git a/queue-6.12/platform-wmi-use-generic-driver_override-infrastruct.patch b/queue-6.12/platform-wmi-use-generic-driver_override-infrastruct.patch new file mode 100644 index 0000000000..d3037a87bc --- /dev/null +++ b/queue-6.12/platform-wmi-use-generic-driver_override-infrastruct.patch @@ -0,0 +1,135 @@ +From d0c09658a052cba64127d12fc5db2810fad27fb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:10 +0100 +Subject: platform/wmi: use generic driver_override infrastructure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Danilo Krummrich + +[ Upstream commit 8a700b1fc94df4d847a04f14ebc7f8532592b367 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 12046f8c77e0 ("platform/x86: wmi: Add driver_override support") +Reviewed-by: Armin Wolf +Acked-by: Ilpo Järvinen +Link: https://patch.msgid.link/20260324005919.2408620-7-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/wmi.c | 36 +++++------------------------------- + include/linux/wmi.h | 4 ---- + 2 files changed, 5 insertions(+), 35 deletions(-) + +diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c +index 3cbe180c3fc0a..f13173eb070e6 100644 +--- a/drivers/platform/x86/wmi.c ++++ b/drivers/platform/x86/wmi.c +@@ -696,39 +696,11 @@ static ssize_t expensive_show(struct device *dev, + } + static DEVICE_ATTR_RO(expensive); + +-static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr, +- char *buf) +-{ +- struct wmi_device *wdev = to_wmi_device(dev); +- ssize_t ret; +- +- device_lock(dev); +- ret = sysfs_emit(buf, "%s\n", wdev->driver_override); +- device_unlock(dev); +- +- return ret; +-} +- +-static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct wmi_device *wdev = to_wmi_device(dev); +- int ret; +- +- ret = driver_set_override(dev, &wdev->driver_override, buf, count); +- if (ret < 0) +- return ret; +- +- return count; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *wmi_attrs[] = { + &dev_attr_modalias.attr, + &dev_attr_guid.attr, + &dev_attr_instance_count.attr, + &dev_attr_expensive.attr, +- &dev_attr_driver_override.attr, + NULL + }; + ATTRIBUTE_GROUPS(wmi); +@@ -797,7 +769,6 @@ static void wmi_dev_release(struct device *dev) + { + struct wmi_block *wblock = dev_to_wblock(dev); + +- kfree(wblock->dev.driver_override); + kfree(wblock); + } + +@@ -806,10 +777,12 @@ static int wmi_dev_match(struct device *dev, const struct device_driver *driver) + const struct wmi_driver *wmi_driver = drv_to_wdrv(driver); + struct wmi_block *wblock = dev_to_wblock(dev); + const struct wmi_device_id *id = wmi_driver->id_table; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (wblock->dev.driver_override) +- return !strcmp(wblock->dev.driver_override, driver->name); ++ ret = device_match_driver_override(dev, driver); ++ if (ret >= 0) ++ return ret; + + if (id == NULL) + return 0; +@@ -891,6 +864,7 @@ static struct class wmi_bus_class = { + static const struct bus_type wmi_bus_type = { + .name = "wmi", + .dev_groups = wmi_groups, ++ .driver_override = true, + .match = wmi_dev_match, + .uevent = wmi_dev_uevent, + .probe = wmi_dev_probe, +diff --git a/include/linux/wmi.h b/include/linux/wmi.h +index 3275470b5531e..63cca3b58d6df 100644 +--- a/include/linux/wmi.h ++++ b/include/linux/wmi.h +@@ -16,16 +16,12 @@ + * struct wmi_device - WMI device structure + * @dev: Device associated with this WMI device + * @setable: True for devices implementing the Set Control Method +- * @driver_override: Driver name to force a match; do not set directly, +- * because core frees it; use driver_set_override() to +- * set or clear it. + * + * This represents WMI devices discovered by the WMI driver core. + */ + struct wmi_device { + struct device dev; + bool setable; +- const char *driver_override; + }; + + /** +-- +2.53.0 + diff --git a/queue-6.12/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch b/queue-6.12/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch new file mode 100644 index 0000000000..dded5cb106 --- /dev/null +++ b/queue-6.12/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch @@ -0,0 +1,81 @@ +From 1a332d6e33ab85c40e5f0138d6b540530bac9eee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 18:44:30 +0100 +Subject: platform/x86: asus-wmi: adjust screenpad power/brightness handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Denis Benato + +[ Upstream commit 130d29c5627cd50e786e926ad7ef66322c5a0c09 ] + +Fix illogical screen off control by hardcoding 0 and 1 depending on the +requested brightness and also do not rely on the last screenpad power +state to issue screen brightness commands. + +Fixes: 2c97d3e55b70 ("platform/x86: asus-wmi: add support for ASUS screenpad") +Signed-off-by: Denis Benato +Signed-off-by: Luke Jones +Link: https://patch.msgid.link/20260302174431.349816-2-denis.benato@linux.dev +Link: https://patch.msgid.link/20260326231154.856729-2-ethantidmore06@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 34 +++++++++++++-------------------- + 1 file changed, 13 insertions(+), 21 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 92ce975d900d0..2e03d63708a7c 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -4130,32 +4130,24 @@ static int read_screenpad_brightness(struct backlight_device *bd) + + static int update_screenpad_bl_status(struct backlight_device *bd) + { +- struct asus_wmi *asus = bl_get_data(bd); +- int power, err = 0; +- u32 ctrl_param; ++ u32 ctrl_param = bd->props.brightness; ++ int err = 0; + +- power = read_screenpad_backlight_power(asus); +- if (power < 0) +- return power; ++ if (bd->props.power) { ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL); ++ if (err < 0) ++ return err; + +- if (bd->props.power != power) { +- if (power != BACKLIGHT_POWER_ON) { +- /* Only brightness > 0 can power it back on */ +- ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; +- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, +- ctrl_param, NULL); +- } else { +- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); +- } +- } else if (power == BACKLIGHT_POWER_ON) { +- /* Only set brightness if powered on or we get invalid/unsync state */ +- ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); ++ if (err < 0) ++ return err; + } + +- /* Ensure brightness is stored to turn back on with */ +- if (err == 0) +- asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; ++ if (!bd->props.power) { ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); ++ if (err < 0) ++ return err; ++ } + + return err; + } +-- +2.53.0 + diff --git a/queue-6.12/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch b/queue-6.12/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch new file mode 100644 index 0000000000..494096c76d --- /dev/null +++ b/queue-6.12/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch @@ -0,0 +1,94 @@ +From bd0f1c419b7460af904bd72550a359c473c52c79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 18:44:31 +0100 +Subject: platform/x86: asus-wmi: fix screenpad brightness range +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Denis Benato + +[ Upstream commit 8d95d1f4aa5c76202b0833a70998769384612488 ] + +Fix screenpad brightness range being too limited without reason: +testing this patch on a Zenbook Duo showed the hardware minimum not being +too low, therefore allow the user to configure the entire range, and +expose to userspace the hardware brightness range and value. + +Fixes: 2c97d3e55b70 ("platform/x86: asus-wmi: add support for ASUS screenpad") +Signed-off-by: Denis Benato +Signed-off-by: Luke Jones +Link: https://patch.msgid.link/20260302174431.349816-3-denis.benato@linux.dev +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 2e03d63708a7c..5d701fde07df4 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -127,7 +127,6 @@ module_param(fnlock_default, bool, 0444); + #define NVIDIA_TEMP_MIN 75 + #define NVIDIA_TEMP_MAX 87 + +-#define ASUS_SCREENPAD_BRIGHT_MIN 20 + #define ASUS_SCREENPAD_BRIGHT_MAX 255 + #define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 + +@@ -4119,13 +4118,13 @@ static int read_screenpad_brightness(struct backlight_device *bd) + return err; + /* The device brightness can only be read if powered, so return stored */ + if (err == BACKLIGHT_POWER_OFF) +- return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; ++ return bd->props.brightness; + + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); + if (err < 0) + return err; + +- return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN; ++ return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; + } + + static int update_screenpad_bl_status(struct backlight_device *bd) +@@ -4165,22 +4164,19 @@ static int asus_screenpad_init(struct asus_wmi *asus) + int err, power; + int brightness = 0; + +- power = read_screenpad_backlight_power(asus); ++ power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); + if (power < 0) + return power; + +- if (power != BACKLIGHT_POWER_OFF) { ++ if (power) { + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); + if (err < 0) + return err; + } +- /* default to an acceptable min brightness on boot if too low */ +- if (brightness < ASUS_SCREENPAD_BRIGHT_MIN) +- brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ +- props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN; ++ props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX; + bd = backlight_device_register("asus_screenpad", + &asus->platform_device->dev, asus, + &asus_screenpad_bl_ops, &props); +@@ -4191,7 +4187,7 @@ static int asus_screenpad_init(struct asus_wmi *asus) + + asus->screenpad_backlight_device = bd; + asus->driver->screenpad_brightness = brightness; +- bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN; ++ bd->props.brightness = brightness; + bd->props.power = power; + backlight_update_status(bd); + +-- +2.53.0 + diff --git a/queue-6.12/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch b/queue-6.12/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch new file mode 100644 index 0000000000..c2b5efc000 --- /dev/null +++ b/queue-6.12/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch @@ -0,0 +1,99 @@ +From e1c43b627c2a6262bc6438eb1c1f54fa432c5e6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:38:21 +0800 +Subject: platform/x86: dell-wmi-sysman: bound enumeration string aggregation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pengpeng Hou + +[ Upstream commit 3c34471c26abc52a37f5ad90949e2e4b8027eb14 ] + +populate_enum_data() aggregates firmware-provided value-modifier +and possible-value strings into fixed 512-byte struct members. +The current code bounds each individual source string but then +appends every string and separator with raw strcat() and no +remaining-space check. + +Switch the aggregation loops to a bounded append helper and +reject enumeration packages whose combined strings do not fit +in the destination buffers. + +Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems") +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260408084501.1-dell-wmi-sysman-v2-pengpeng@iscas.ac.cn +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + .../dell/dell-wmi-sysman/enum-attributes.c | 34 +++++++++++++++---- + 1 file changed, 28 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +index fc2f58b4cbc6e..7e44ba3015627 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +@@ -6,10 +6,32 @@ + * Copyright (c) 2020 Dell Inc. + */ + ++#include ++ + #include "dell-wmi-sysman.h" + + get_instance_id(enumeration); + ++static int append_enum_string(char *dest, const char *src) ++{ ++ size_t dest_len = strlen(dest); ++ ssize_t copied; ++ ++ if (WARN_ON_ONCE(dest_len >= MAX_BUFF)) ++ return -EINVAL; ++ ++ copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ dest_len += copied; ++ copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { + int instance_id = get_enumeration_instance_id(kobj); +@@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + if (next_obj >= enum_property_count) +@@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); +-- +2.53.0 + diff --git a/queue-6.12/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch b/queue-6.12/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch new file mode 100644 index 0000000000..95b1d8700e --- /dev/null +++ b/queue-6.12/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch @@ -0,0 +1,60 @@ +From 17baa26f3162b015e407d897ec3e32480e8ac03c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:42:39 +0300 +Subject: platform/x86: dell_rbu: avoid uninit value usage in + packet_size_write() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fedor Pchelkin + +[ Upstream commit f8fd138c2363c0e2d3235c32bfb4fb5c6474e4ae ] + +Ensure the temp value has been properly parsed from the user-provided +buffer and initialized to be used in later operations. While at it, +prefer a convenient kstrtoul() helper. + +Found by Linux Verification Center (linuxtesting.org) with Svace static +analysis tool. + +Fixes: ad6ce87e5bd4 ("[PATCH] dell_rbu: changes in packet update mechanism") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260403134240.604837-1-pchelkin@ispras.ru +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/dell/dell_rbu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c +index fee20866b41e4..9039e494131fd 100644 +--- a/drivers/platform/x86/dell/dell_rbu.c ++++ b/drivers/platform/x86/dell/dell_rbu.c +@@ -30,6 +30,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -617,9 +618,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, + char *buffer, loff_t pos, size_t count) + { + unsigned long temp; ++ ++ if (kstrtoul(buffer, 10, &temp)) ++ return -EINVAL; ++ + spin_lock(&rbu_data.lock); + packet_empty_list(); +- sscanf(buffer, "%lu", &temp); + if (temp < 0xffffffff) + rbu_data.packetsize = temp; + +-- +2.53.0 + diff --git a/queue-6.12/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch b/queue-6.12/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch new file mode 100644 index 0000000000..f0d03ad4f7 --- /dev/null +++ b/queue-6.12/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch @@ -0,0 +1,67 @@ +From e8c4c9c7d0679149fe63252229f075f621ba79a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 11:31:54 +0100 +Subject: platform/x86: panasonic-laptop: Fix OPTD notifier registration and + cleanup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 8baeff2c1d33dad8572216c6ad3a7425852507d4 ] + +An ACPI notify handler is leaked if device_create_file() returns an +error in acpi_pcc_hotkey_add(). + +Also, it is pointless to call pcc_unregister_optd_notifier() in +acpi_pcc_hotkey_remove() if pcc->platform is NULL and it is better +to arrange the cleanup code in that function in the same order as +the rollback code in acpi_pcc_hotkey_add(). + +Address the above by placing the pcc_register_optd_notifier() call in +acpi_pcc_hotkey_add() after the device_create_file() return value +check and placing the pcc_unregister_optd_notifier() call in +acpi_pcc_hotkey_remove() right before the device_remove_file() call. + +Fixes: d5a81d8e864b ("platform/x86: panasonic-laptop: Add support for optical driver power in Y and W series") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2411055.ElGaqSPkdT@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/panasonic-laptop.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c +index 851f0f92219dd..1b544953858c9 100644 +--- a/drivers/platform/x86/panasonic-laptop.c ++++ b/drivers/platform/x86/panasonic-laptop.c +@@ -1093,9 +1093,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) + } + result = device_create_file(&pcc->platform->dev, + &dev_attr_cdpower); +- pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + if (result) + goto out_platform; ++ ++ pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + } else { + pcc->platform = NULL; + } +@@ -1129,10 +1130,10 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device) + i8042_remove_filter(panasonic_i8042_filter); + + if (pcc->platform) { ++ pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); + platform_device_unregister(pcc->platform); + } +- pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + + sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); + +-- +2.53.0 + diff --git a/queue-6.12/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch b/queue-6.12/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch new file mode 100644 index 0000000000..590dcf1ba6 --- /dev/null +++ b/queue-6.12/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch @@ -0,0 +1,39 @@ +From 93627630d3925de9b47ff435438a08b8c492cfc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 12:48:59 +0200 +Subject: PM: domains: De-constify fields in struct dev_pm_domain_attach_data + +From: Dmitry Baryshkov + +[ Upstream commit 1877d3f258cbb57d64e275754fb9b18b089ce72d ] + +It doesn't really make sense to keep u32 fields to be marked as const. +Having the const fields prevents their modification in the driver. Instead +the whole struct can be defined as const, if it is constant. + +Fixes: 161e16a5e50a ("PM: domains: Add helper functions to attach/detach multiple PM domains") +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + include/linux/pm_domain.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h +index c6716f474ba45..908e20bbfcaef 100644 +--- a/include/linux/pm_domain.h ++++ b/include/linux/pm_domain.h +@@ -36,8 +36,8 @@ + + struct dev_pm_domain_attach_data { + const char * const *pd_names; +- const u32 num_pd_names; +- const u32 pd_flags; ++ u32 num_pd_names; ++ u32 pd_flags; + }; + + struct dev_pm_domain_list { +-- +2.53.0 + diff --git a/queue-6.12/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch b/queue-6.12/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch new file mode 100644 index 0000000000..0bb66c1a46 --- /dev/null +++ b/queue-6.12/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch @@ -0,0 +1,38 @@ +From 04c87c3b8eab366a6332d951d1d7e93335e557d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 22:17:17 +0800 +Subject: pmdomain: imx: scu-pd: Fix device_node reference leak during + ->probe() + +From: Felix Gu + +[ Upstream commit c8e9b6a55702be6c6d034e973d519c52c3848415 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In imx_sc_pd_get_console_rsrc(), it does not release the reference. + +Fixes: 893cfb99734f ("firmware: imx: scu-pd: do not power off console domain") +Signed-off-by: Felix Gu +Reviewed-by: Peng Fan +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/pmdomain/imx/scu-pd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pmdomain/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c +index 01d465d88f60d..3ec33667a308c 100644 +--- a/drivers/pmdomain/imx/scu-pd.c ++++ b/drivers/pmdomain/imx/scu-pd.c +@@ -326,6 +326,7 @@ static void imx_sc_pd_get_console_rsrc(void) + return; + + imx_con_rsrc = specs.args[0]; ++ of_node_put(specs.np); + } + + static int imx_sc_get_pd_power(struct device *dev, u32 rsrc) +-- +2.53.0 + diff --git a/queue-6.12/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch b/queue-6.12/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch new file mode 100644 index 0000000000..034627670c --- /dev/null +++ b/queue-6.12/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch @@ -0,0 +1,36 @@ +From 99fcbda0d2bec53d5dbcc16dbb9db63987435ce7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 20:27:47 +0800 +Subject: pmdomain: ti: omap_prm: Fix a reference leak on device node + +From: Felix Gu + +[ Upstream commit 44c28e1c52764fef6dd1c1ada3a248728812e67f ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In omap_prm_domain_attach_dev, it does not release the reference. + +Fixes: 58cbff023bfa ("soc: ti: omap-prm: Add basic power domain support") +Signed-off-by: Felix Gu +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/pmdomain/ti/omap_prm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pmdomain/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c +index b8ceb3c2b81c2..f4e52e92dcbf6 100644 +--- a/drivers/pmdomain/ti/omap_prm.c ++++ b/drivers/pmdomain/ti/omap_prm.c +@@ -651,6 +651,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, + if (pd_args.args_count != 0) + dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", + prmd->pd.name, pd_args.args_count); ++ of_node_put(pd_args.np); + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; +-- +2.53.0 + diff --git a/queue-6.12/powerpc-crash-fix-backup-region-offset-update-to-elf.patch b/queue-6.12/powerpc-crash-fix-backup-region-offset-update-to-elf.patch new file mode 100644 index 0000000000..60ca2205d0 --- /dev/null +++ b/queue-6.12/powerpc-crash-fix-backup-region-offset-update-to-elf.patch @@ -0,0 +1,63 @@ +From ab0df1f7ffe73dd9883ce37d783e32b8056a9555 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:49 +0530 +Subject: powerpc/crash: fix backup region offset update to elfcorehdr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sourabh Jain + +[ Upstream commit 789335cacdf37da93bb7c70322dff8c7e82881df ] + +update_backup_region_phdr() in file_load_64.c iterates over all the +program headers in the kdump kernel’s elfcorehdr and updates the +p_offset of the program header whose physical address starts at 0. + +However, the loop logic is incorrect because the program header pointer +is not updated during iteration. Since elfcorehdr typically contains +PT_NOTE entries first, the PT_LOAD program header with physical address +0 is never reached. As a result, its p_offset is not updated to point to +the backup region. + +Because of this behavior, the capture kernel exports the first 64 KB of +the crashed kernel’s memory at offset 0, even though that memory +actually lives in the backup region. When a crash happens, purgatory +copies the first 64 KB of the crashed kernel’s memory into the backup +region so the capture kernel can safely use it. + +This has not caused problems so far because the first 64 KB is usually +identical in both the crashed and capture kernels. However, this is +just an assumption and is not guaranteed to always hold true. + +Fix update_backup_region_phdr() to correctly update the p_offset of the +program header with a starting physical address of 0 by correcting the +logic used to iterate over the program headers. + +Fixes: cb350c1f1f86 ("powerpc/kexec_file: Prepare elfcore header for crashing kernel") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Reviewed-by: Hari Bathini +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-2-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kexec/file_load_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index 248a0f00a291f..cb09916b4056b 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -574,7 +574,7 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) + unsigned int i; + + phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++) { ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + if (phdr->p_paddr == BACKUP_SRC_START) { + phdr->p_offset = image->arch.backup_start; + kexec_dprintk("Backup region offset updated to 0x%lx\n", +-- +2.53.0 + diff --git a/queue-6.12/powerpc-crash-update-backup-region-offset-in-elfcore.patch b/queue-6.12/powerpc-crash-update-backup-region-offset-in-elfcore.patch new file mode 100644 index 0000000000..d087776fdc --- /dev/null +++ b/queue-6.12/powerpc-crash-update-backup-region-offset-in-elfcore.patch @@ -0,0 +1,245 @@ +From 039495233f6ecf6d402fbab4b83faeb6bd9e07f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:50 +0530 +Subject: powerpc/crash: Update backup region offset in elfcorehdr on memory + hotplug + +From: Sourabh Jain + +[ Upstream commit f53b24d1fa263f56155213eabab734c18d884aff ] + +When elfcorehdr is prepared for kdump, the program header representing +the first 64 KB of memory is expected to have its offset point to the +backup region. This is required because purgatory copies the first 64 KB +of the crashed kernel memory to this backup region following a kernel +crash. This allows the capture kernel to use the first 64 KB of memory +to place the exception vectors and other required data. + +When elfcorehdr is recreated due to memory hotplug, the offset of +the program header representing the first 64 KB is not updated. +As a result, the capture kernel exports the first 64 KB at offset +0, even though the data actually resides in the backup region. + +Fix this by calling sync_backup_region_phdr() to update the program +header offset in the elfcorehdr created during memory hotplug. + +sync_backup_region_phdr() works for images loaded via the +kexec_file_load syscall. However, it does not work for kexec_load, +because image->arch.backup_start is not initialized in that case. +So introduce machine_kexec_post_load() to process the elfcorehdr +prepared by kexec-tools and initialize image->arch.backup_start for +kdump images loaded via kexec_load syscall. + +Rename update_backup_region_phdr() to sync_backup_region_phdr() and +extend it to synchronize the backup region offset between the kdump +image and the ELF core header. The helper now supports updating either +the kdump image from the ELF program header or updating the ELF program +header from the kdump image, avoiding code duplication. + +Define ARCH_HAS_KIMAGE_ARCH and struct kimage_arch when +CONFIG_KEXEC_FILE or CONFIG_CRASH_DUMP is enabled so that +kimage->arch.backup_start is available with the kexec_load system call. + +This patch depends on the patch titled +"powerpc/crash: fix backup region offset update to elfcorehdr". + +Fixes: 849599b702ef ("powerpc/crash: add crash memory hotplug support") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-3-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kexec.h | 14 +++++-- + arch/powerpc/kexec/crash.c | 64 +++++++++++++++++++++++++++++++ + arch/powerpc/kexec/file_load_64.c | 29 +------------- + 3 files changed, 76 insertions(+), 31 deletions(-) + +diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h +index 601e569303e1b..e6c0724109e39 100644 +--- a/arch/powerpc/include/asm/kexec.h ++++ b/arch/powerpc/include/asm/kexec.h +@@ -66,11 +66,9 @@ void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_co + unsigned long start_address) __noreturn; + void kexec_copy_flush(struct kimage *image); + +-#ifdef CONFIG_KEXEC_FILE +-extern const struct kexec_file_ops kexec_elf64_ops; + ++#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP) + #define ARCH_HAS_KIMAGE_ARCH +- + struct kimage_arch { + struct crash_mem *exclude_ranges; + +@@ -78,6 +76,10 @@ struct kimage_arch { + void *backup_buf; + void *fdt; + }; ++#endif ++ ++#ifdef CONFIG_KEXEC_FILE ++extern const struct kexec_file_ops kexec_elf64_ops; + + char *setup_kdump_cmdline(struct kimage *image, char *cmdline, + unsigned long cmdline_len); +@@ -141,6 +143,10 @@ int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags); + + unsigned int arch_crash_get_elfcorehdr_size(void); + #define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size ++ ++int machine_kexec_post_load(struct kimage *image); ++#define machine_kexec_post_load machine_kexec_post_load ++ + #endif /* CONFIG_CRASH_HOTPLUG */ + + extern int crashing_cpu; +@@ -155,6 +161,8 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs); + extern void crash_kexec_prepare(void); + extern void crash_kexec_secondary(struct pt_regs *regs); + ++extern void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, ++ bool phdr_to_kimage); + static inline bool kdump_in_progress(void) + { + return crashing_cpu >= 0; +diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c +index a325c1c02f96d..e6539f213b3d1 100644 +--- a/arch/powerpc/kexec/crash.c ++++ b/arch/powerpc/kexec/crash.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + /* + * The primary CPU waits a while for all secondary CPUs to enter. This is to +@@ -399,7 +400,68 @@ void default_machine_crash_shutdown(struct pt_regs *regs) + ppc_md.kexec_cpu_down(1, 0); + } + ++#ifdef CONFIG_CRASH_DUMP ++/** ++ * sync_backup_region_phdr - synchronize backup region offset between ++ * kexec image and ELF core header. ++ * @image: Kexec image. ++ * @ehdr: ELF core header. ++ * @phdr_to_kimage: If true, read the offset from the ELF program header ++ * and update the kimage backup region. If false, update ++ * the ELF program header offset from the kimage backup ++ * region. ++ * ++ * Note: During kexec_load, this is called with phdr_to_kimage = true. For ++ * kexec_file_load and ELF core header recreation during memory hotplug ++ * events, it is called with phdr_to_kimage = false. ++ * ++ * Returns nothing. ++ */ ++void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, bool phdr_to_kimage) ++{ ++ Elf64_Phdr *phdr; ++ unsigned int i; ++ ++ phdr = (Elf64_Phdr *)(ehdr + 1); ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { ++ if (phdr->p_paddr == BACKUP_SRC_START) { ++ if (phdr_to_kimage) ++ image->arch.backup_start = phdr->p_offset; ++ else ++ phdr->p_offset = image->arch.backup_start; ++ ++ kexec_dprintk("Backup region offset updated to 0x%lx\n", ++ image->arch.backup_start); ++ return; ++ } ++ } ++} ++#endif /* CONFIG_CRASH_DUMP */ ++ + #ifdef CONFIG_CRASH_HOTPLUG ++ ++int machine_kexec_post_load(struct kimage *image) ++{ ++ int i; ++ unsigned long mem; ++ unsigned char *ptr; ++ ++ if (image->type != KEXEC_TYPE_CRASH) ++ return 0; ++ ++ if (image->file_mode) ++ return 0; ++ ++ for (i = 0; i < image->nr_segments; i++) { ++ mem = image->segment[i].mem; ++ ptr = (char *)__va(mem); ++ ++ if (ptr && memcmp(ptr, ELFMAG, SELFMAG) == 0) ++ sync_backup_region_phdr(image, (Elf64_Ehdr *) ptr, true); ++ } ++ return 0; ++} ++ + #undef pr_fmt + #define pr_fmt(fmt) "crash hp: " fmt + +@@ -474,6 +536,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify * + goto out; + } + ++ sync_backup_region_phdr(image, (Elf64_Ehdr *) elfbuf, false); ++ + ptr = __va(mem); + if (ptr) { + /* Temporarily invalidate the crash image while it is replaced */ +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index cb09916b4056b..276233f73a533 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -557,33 +557,6 @@ static int load_backup_segment(struct kimage *image, struct kexec_buf *kbuf) + return 0; + } + +-/** +- * update_backup_region_phdr - Update backup region's offset for the core to +- * export the region appropriately. +- * @image: Kexec image. +- * @ehdr: ELF core header. +- * +- * Assumes an exclusive program header is setup for the backup region +- * in the ELF headers +- * +- * Returns nothing. +- */ +-static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) +-{ +- Elf64_Phdr *phdr; +- unsigned int i; +- +- phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++, phdr++) { +- if (phdr->p_paddr == BACKUP_SRC_START) { +- phdr->p_offset = image->arch.backup_start; +- kexec_dprintk("Backup region offset updated to 0x%lx\n", +- image->arch.backup_start); +- return; +- } +- } +-} +- + static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem) + { + #if defined(CONFIG_CRASH_HOTPLUG) && defined(CONFIG_MEMORY_HOTPLUG) +@@ -628,7 +601,7 @@ static int load_elfcorehdr_segment(struct kimage *image, struct kexec_buf *kbuf) + } + + /* Fix the offset for backup region in the ELF header */ +- update_backup_region_phdr(image, headers); ++ sync_backup_region_phdr(image, headers, false); + + kbuf->buffer = headers; + kbuf->mem = KEXEC_BUF_MEM_UNKNOWN; +-- +2.53.0 + diff --git a/queue-6.12/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch b/queue-6.12/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch new file mode 100644 index 0000000000..71bc991da0 --- /dev/null +++ b/queue-6.12/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch @@ -0,0 +1,50 @@ +From 975fe0021d7706779c38f0d678d1237960c10d4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:11:15 +0900 +Subject: ppp: require CAP_NET_ADMIN in target netns for unattached ioctls + +From: Taegu Ha + +[ Upstream commit 2bb6379416fd19f44c3423a00bfd8626259f6067 ] + +/dev/ppp open is currently authorized against file->f_cred->user_ns, +while unattached administrative ioctls operate on current->nsproxy->net_ns. + +As a result, a local unprivileged user can create a new user namespace +with CLONE_NEWUSER, gain CAP_NET_ADMIN only in that new user namespace, +and still issue PPPIOCNEWUNIT, PPPIOCATTACH, or PPPIOCATTCHAN against +an inherited network namespace. + +Require CAP_NET_ADMIN in the user namespace that owns the target network +namespace before handling unattached PPP administrative ioctls. + +This preserves normal pppd operation in the network namespace it is +actually privileged in, while rejecting the userns-only inherited-netns +case. + +Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2") +Signed-off-by: Taegu Ha +Link: https://patch.msgid.link/20260409071117.4354-1-hataegu0826@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index afc1566488b32..e08ce91bc19a9 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1064,6 +1064,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct ppp_net *pn; + int __user *p = (int __user *)arg; + ++ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ + switch (cmd) { + case PPPIOCNEWUNIT: + /* Create a new ppp unit */ +-- +2.53.0 + diff --git a/queue-6.12/pppoe-drop-pfc-frames.patch b/queue-6.12/pppoe-drop-pfc-frames.patch new file mode 100644 index 0000000000..5060203cc1 --- /dev/null +++ b/queue-6.12/pppoe-drop-pfc-frames.patch @@ -0,0 +1,112 @@ +From b9e3c826031950084522ce5b60d22adb0d200932 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 10:24:51 +0800 +Subject: pppoe: drop PFC frames + +From: Qingfang Deng + +[ Upstream commit cc1ff87bce1ccd38410ab10960f576dcd17db679 ] + +RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT +RECOMMENDED for PPPoE. In practice, pppd does not support negotiating +PFC for PPPoE sessions, and the current PPPoE driver assumes an +uncompressed (2-byte) protocol field. However, the generic PPP layer +function ppp_input() is not aware of the negotiation result, and still +accepts PFC frames. + +If a peer with a broken implementation or an attacker sends a frame with +a compressed (1-byte) protocol field, the subsequent PPP payload is +shifted by one byte. This causes the network header to be 4-byte +misaligned, which may trigger unaligned access exceptions on some +architectures. + +To reduce the attack surface, drop PPPoE PFC frames. Introduce +ppp_skb_is_compressed_proto() helper function to be used in both +ppp_generic.c and pppoe.c to avoid open-coding. + +Fixes: 7fb1b8ca8fa1 ("ppp: Move PFC decompression to PPP generic layer") +Signed-off-by: Qingfang Deng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415022456.141758-2-qingfang.deng@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + drivers/net/ppp/pppoe.c | 8 +++++++- + include/linux/ppp_defs.h | 16 ++++++++++++++++ + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index e08ce91bc19a9..c70994c6a265e 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2245,7 +2245,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + */ + static void __ppp_decompress_proto(struct sk_buff *skb) + { +- if (skb->data[0] & 0x01) ++ if (ppp_skb_is_compressed_proto(skb)) + *(u8 *)skb_push(skb, 1) = 0x00; + } + +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index 2ea4f4890d23b..937cf9b17f9ae 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -425,7 +425,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb_mac_header_len(skb) < ETH_HLEN) + goto drop; + +- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) ++ if (!pskb_may_pull(skb, PPPOE_SES_HLEN)) + goto drop; + + ph = pppoe_hdr(skb); +@@ -435,6 +435,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb->len < len) + goto drop; + ++ /* skb->data points to the PPP protocol header after skb_pull_rcsum. ++ * Drop PFC frames. ++ */ ++ if (ppp_skb_is_compressed_proto(skb)) ++ goto drop; ++ + if (pskb_trim_rcsum(skb, len)) + goto drop; + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index b7e57fdbd4139..b1d1f46d7d3be 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -8,6 +8,7 @@ + #define _PPP_DEFS_H_ + + #include ++#include + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) +@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) + return !!((proto & 0x0101) == 0x0001); + } + ++/** ++ * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed ++ * @skb: skb to check ++ * ++ * Check if the PPP protocol field is compressed (the least significant ++ * bit of the most significant octet is 1). skb->data must point to the PPP ++ * protocol header. ++ * ++ * Return: Whether the PPP protocol field is compressed. ++ */ ++static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb) ++{ ++ return unlikely(skb->data[0] & 0x01); ++} ++ + #endif /* _PPP_DEFS_H_ */ +-- +2.53.0 + diff --git a/queue-6.12/pstore-ram-fix-resource-leak-when-ioremap-fails.patch b/queue-6.12/pstore-ram-fix-resource-leak-when-ioremap-fails.patch new file mode 100644 index 0000000000..b0e98f588d --- /dev/null +++ b/queue-6.12/pstore-ram-fix-resource-leak-when-ioremap-fails.patch @@ -0,0 +1,52 @@ +From b992ea8cd9389a894346bf177a03e695c0ae3389 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:54:06 -0700 +Subject: pstore/ram: fix resource leak when ioremap() fails + +From: Cole Leavitt + +[ Upstream commit 2ddb69f686ef7a621645e97fc7329c50edf5d0e5 ] + +In persistent_ram_iomap(), ioremap() or ioremap_wc() may return NULL on +failure. Currently, if this happens, the function returns NULL without +releasing the memory region acquired by request_mem_region(). + +This leads to a resource leak where the memory region remains reserved +but unusable. + +Additionally, the caller persistent_ram_buffer_map() handles NULL +correctly by returning -ENOMEM, but without this check, a NULL return +combined with request_mem_region() succeeding leaves resources in an +inconsistent state. + +This is the ioremap() counterpart to commit 05363abc7625 ("pstore: +ram_core: fix incorrect success return when vmap() fails") which fixed +a similar issue in the vmap() path. + +Fixes: 404a6043385d ("staging: android: persistent_ram: handle reserving and mapping memory") +Signed-off-by: Cole Leavitt +Link: https://patch.msgid.link/20260225235406.11790-1-cole@unwrap.rs +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index 7b6d6378a3b87..95675d4bab141 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -489,6 +489,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, + else + va = ioremap_wc(start, size); + ++ /* We must release the mem region if ioremap fails. */ ++ if (!va) ++ release_mem_region(start, size); ++ + /* + * Since request_mem_region() and ioremap() are byte-granularity + * there is no need handle anything special like we do when the +-- +2.53.0 + diff --git a/queue-6.12/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch b/queue-6.12/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch new file mode 100644 index 0000000000..114778c029 --- /dev/null +++ b/queue-6.12/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch @@ -0,0 +1,139 @@ +From c3bc4b5d191f077d5bc878a24cacb754c41a7a89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 17:08:38 +0900 +Subject: pwm: atmel-tcb: Cache clock rates and mark chip as atomic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sangyun Kim + +[ Upstream commit 68637b68afcc3cb4d56aca14a3a1d1b47b879369 ] + +atmel_tcb_pwm_apply() holds tcbpwmc->lock as a spinlock via +guard(spinlock)() and then calls atmel_tcb_pwm_config(), which calls +clk_get_rate() twice. clk_get_rate() acquires clk_prepare_lock (a +mutex), so this is a sleep-in-atomic-context violation. + +On CONFIG_DEBUG_ATOMIC_SLEEP kernels every pwm_apply_state() that +enables or reconfigures the PWM triggers a "BUG: sleeping function +called from invalid context" warning. + +Acquire exclusive control over the clock rates with +clk_rate_exclusive_get() at probe time and cache the rates in struct +atmel_tcb_pwm_chip, then read the cached rates from +atmel_tcb_pwm_config(). This keeps the spinlock-based mutual exclusion +introduced in commit 37f7707077f5 ("pwm: atmel-tcb: Fix race condition +and convert to guards") and removes the sleeping calls from the atomic +section. + +With no sleeping calls left in .apply() and the regmap-mmio bus already +running with fast_io=true, also mark the chip as atomic so consumers +can use pwm_apply_atomic() from atomic context. + +Fixes: 37f7707077f5 ("pwm: atmel-tcb: Fix race condition and convert to guards") +Signed-off-by: Sangyun Kim +Link: https://patch.msgid.link/20260419080838.3192357-1-sangyun.kim@snu.ac.kr +[ukleinek: Ensure .clk is enabled before calling clk_get_rate on it.] +Signed-off-by: Uwe Kleine-König +Signed-off-by: Sasha Levin +--- + drivers/pwm/pwm-atmel-tcb.c | 38 +++++++++++++++++++++++++++++++++---- + 1 file changed, 34 insertions(+), 4 deletions(-) + +diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c +index 5ee4254d1e487..9554deb413ab3 100644 +--- a/drivers/pwm/pwm-atmel-tcb.c ++++ b/drivers/pwm/pwm-atmel-tcb.c +@@ -50,6 +50,8 @@ struct atmel_tcb_pwm_chip { + spinlock_t lock; + u8 channel; + u8 width; ++ unsigned long rate; ++ unsigned long slow_rate; + struct regmap *regmap; + struct clk *clk; + struct clk *gclk; +@@ -266,7 +268,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int slowclk = 0; + unsigned period; + unsigned duty; +- unsigned rate = clk_get_rate(tcbpwmc->clk); ++ unsigned long rate = tcbpwmc->rate; + unsigned long long min; + unsigned long long max; + +@@ -294,7 +296,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + */ + if (i == ARRAY_SIZE(atmel_tcb_divisors)) { + i = slowclk; +- rate = clk_get_rate(tcbpwmc->slow_clk); ++ rate = tcbpwmc->slow_rate; + min = div_u64(NSEC_PER_SEC, rate); + max = min << tcbpwmc->width; + +@@ -431,24 +433,49 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) + } + + chip->ops = &atmel_tcb_pwm_ops; ++ chip->atomic = true; + tcbpwmc->channel = channel; + tcbpwmc->width = config->counter_width; + +- err = clk_prepare_enable(tcbpwmc->slow_clk); ++ err = clk_prepare_enable(tcbpwmc->clk); + if (err) + goto err_gclk; + ++ err = clk_prepare_enable(tcbpwmc->slow_clk); ++ if (err) ++ goto err_disable_clk;; ++ ++ err = clk_rate_exclusive_get(tcbpwmc->clk); ++ if (err) ++ goto err_disable_slow_clk; ++ ++ err = clk_rate_exclusive_get(tcbpwmc->slow_clk); ++ if (err) ++ goto err_clk_unlock; ++ ++ tcbpwmc->rate = clk_get_rate(tcbpwmc->clk); ++ tcbpwmc->slow_rate = clk_get_rate(tcbpwmc->slow_clk); ++ + spin_lock_init(&tcbpwmc->lock); + + err = pwmchip_add(chip); + if (err < 0) +- goto err_disable_clk; ++ goto err_slow_clk_unlock; + + platform_set_drvdata(pdev, chip); + + return 0; + ++err_slow_clk_unlock: ++ clk_rate_exclusive_put(tcbpwmc->slow_clk); ++ ++err_clk_unlock: ++ clk_rate_exclusive_put(tcbpwmc->clk); ++ + err_disable_clk: ++ clk_disable_unprepare(tcbpwmc->clk); ++ ++err_disable_slow_clk: + clk_disable_unprepare(tcbpwmc->slow_clk); + + err_gclk: +@@ -470,6 +497,9 @@ static void atmel_tcb_pwm_remove(struct platform_device *pdev) + + pwmchip_remove(chip); + ++ clk_rate_exclusive_put(tcbpwmc->slow_clk); ++ clk_rate_exclusive_put(tcbpwmc->clk); ++ clk_disable_unprepare(tcbpwmc->clk); + clk_disable_unprepare(tcbpwmc->slow_clk); + clk_put(tcbpwmc->gclk); + clk_put(tcbpwmc->clk); +-- +2.53.0 + diff --git a/queue-6.12/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch b/queue-6.12/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch new file mode 100644 index 0000000000..0a7e45975b --- /dev/null +++ b/queue-6.12/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch @@ -0,0 +1,148 @@ +From 3d003ad3aa131ec371c1012b961dc86256733e9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 14:22:16 +0100 +Subject: quota: Fix race of dquot_scan_active() with quota deactivation + +From: Jan Kara + +[ Upstream commit e93ab401da4b2e2c1b8ef2424de2f238d51c8b2d ] + +dquot_scan_active() can race with quota deactivation in +quota_release_workfn() like: + + CPU0 (quota_release_workfn) CPU1 (dquot_scan_active) + ============================== ============================== + spin_lock(&dq_list_lock); + list_replace_init( + &releasing_dquots, &rls_head); + /* dquot X on rls_head, + dq_count == 0, + DQ_ACTIVE_B still set */ + spin_unlock(&dq_list_lock); + synchronize_srcu(&dquot_srcu); + spin_lock(&dq_list_lock); + list_for_each_entry(dquot, + &inuse_list, dq_inuse) { + /* finds dquot X */ + dquot_active(X) -> true + atomic_inc(&X->dq_count); + } + spin_unlock(&dq_list_lock); + spin_lock(&dq_list_lock); + dquot = list_first_entry(&rls_head); + WARN_ON_ONCE(atomic_read(&dquot->dq_count)); + +The problem is not only a cosmetic one as under memory pressure the +caller of dquot_scan_active() can end up working on freed dquot. + +Fix the problem by making sure the dquot is removed from releasing list +when we acquire a reference to it. + +Fixes: 869b6ea1609f ("quota: Fix slow quotaoff") +Reported-by: Sam Sun +Link: https://lore.kernel.org/all/CAEkJfYPTt3uP1vAYnQ5V2ZWn5O9PLhhGi5HbOcAzyP9vbXyjeg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/dquot.c | 38 ++++++++++++++++++++++++++++++-------- + include/linux/quotaops.h | 9 +-------- + 2 files changed, 31 insertions(+), 16 deletions(-) + +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 94825180385ab..7c3095622872f 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -364,6 +364,31 @@ static inline int dquot_active(struct dquot *dquot) + return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); + } + ++static struct dquot *__dqgrab(struct dquot *dquot) ++{ ++ lockdep_assert_held(&dq_list_lock); ++ if (!atomic_read(&dquot->dq_count)) ++ remove_free_dquot(dquot); ++ atomic_inc(&dquot->dq_count); ++ return dquot; ++} ++ ++/* ++ * Get reference to dquot when we got pointer to it by some other means. The ++ * dquot has to be active and the caller has to make sure it cannot get ++ * deactivated under our hands. ++ */ ++struct dquot *dqgrab(struct dquot *dquot) ++{ ++ spin_lock(&dq_list_lock); ++ WARN_ON_ONCE(!dquot_active(dquot)); ++ dquot = __dqgrab(dquot); ++ spin_unlock(&dq_list_lock); ++ ++ return dquot; ++} ++EXPORT_SYMBOL_GPL(dqgrab); ++ + static inline int dquot_dirty(struct dquot *dquot) + { + return test_bit(DQ_MOD_B, &dquot->dq_flags); +@@ -642,15 +667,14 @@ int dquot_scan_active(struct super_block *sb, + continue; + if (dquot->dq_sb != sb) + continue; +- /* Now we have active dquot so we can just increase use count */ +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqput(old_dquot); + old_dquot = dquot; + /* + * ->release_dquot() can be racing with us. Our reference +- * protects us from new calls to it so just wait for any +- * outstanding call and recheck the DQ_ACTIVE_B after that. ++ * protects us from dquot_release() proceeding so just wait for ++ * any outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (dquot_active(dquot)) { +@@ -718,7 +742,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) + /* Now we have active dquot from which someone is + * holding reference so we can safely just increase + * use count */ +- dqgrab(dquot); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + err = dquot_write_dquot(dquot); + if (err && !ret) +@@ -964,9 +988,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_LOOKUPS); + } else { +- if (!atomic_read(&dquot->dq_count)) +- remove_free_dquot(dquot); +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_CACHE_HITS); + dqstats_inc(DQST_LOOKUPS); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 06cc8888199e8..2334a02c30149 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -44,14 +44,7 @@ int dquot_initialize(struct inode *inode); + bool dquot_initialize_needed(struct inode *inode); + void dquot_drop(struct inode *inode); + struct dquot *dqget(struct super_block *sb, struct kqid qid); +-static inline struct dquot *dqgrab(struct dquot *dquot) +-{ +- /* Make sure someone else has active reference to dquot */ +- WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); +- WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); +- atomic_inc(&dquot->dq_count); +- return dquot; +-} ++struct dquot *dqgrab(struct dquot *dquot); + + static inline bool dquot_is_busy(struct dquot *dquot) + { +-- +2.53.0 + diff --git a/queue-6.12/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch b/queue-6.12/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch new file mode 100644 index 0000000000..df1febf1e1 --- /dev/null +++ b/queue-6.12/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch @@ -0,0 +1,41 @@ +From bb0eafcb81f5cdcd5133dcf18c5f47e8af602915 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:39:23 +0800 +Subject: r8152: fix incorrect register write to USB_UPHY_XTAL + +From: Chih Kai Hsu + +[ Upstream commit 48afd5124fd6129c46fd12cb06155384b1c4a0c4 ] + +The old code used ocp_write_byte() to clear the OOBS_POLLING bit +(BIT(8)) in the USB_UPHY_XTAL register, but this doesn't correctly +clear a bit in the upper byte of the 16-bit register. + +Fix this by using ocp_write_word() instead. + +Fixes: 195aae321c82 ("r8152: support new chips") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Link: https://patch.msgid.link/20260326073925.32976-454-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 6ce25673e4cc8..1c36816405f13 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -3894,7 +3894,7 @@ static void r8156_ups_en(struct r8152 *tp, bool enable) + case RTL_VER_15: + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL); + ocp_data &= ~OOBS_POLLING; +- ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); ++ ocp_write_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); + break; + default: + break; +-- +2.53.0 + diff --git a/queue-6.12/rdma-core-prefer-nla_nul_string.patch b/queue-6.12/rdma-core-prefer-nla_nul_string.patch new file mode 100644 index 0000000000..140d8b657b --- /dev/null +++ b/queue-6.12/rdma-core-prefer-nla_nul_string.patch @@ -0,0 +1,56 @@ +From 991ec0d0f9fee145028fe87f98371a6aef64faea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:27:39 +0200 +Subject: RDMA/core: Prefer NLA_NUL_STRING + +From: Florian Westphal + +[ Upstream commit 6ed3d14fc45d3da6025e7fe4a6a09066856698e2 ] + +These attributes are evaluated as c-string (passed to strcmp), but +NLA_STRING doesn't check for the presence of a \0 terminator. + +Either this needs to switch to nla_strcmp() and needs to adjust printf fmt +specifier to not use plain %s, or this needs to use NLA_NUL_STRING. + +As the code has been this way for long time, it seems to me that userspace +does include the terminating nul, even tough its not enforced so far, and +thus NLA_NUL_STRING use is the simpler solution. + +Fixes: 30dc5e63d6a5 ("RDMA/core: Add support for iWARP Port Mapper user space service") +Link: https://patch.msgid.link/r/20260330122742.13315-1-fw@strlen.de +Signed-off-by: Florian Westphal +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwpm_msg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c +index 3c9a9869212bb..feb09008eb9ca 100644 +--- a/drivers/infiniband/core/iwpm_msg.c ++++ b/drivers/infiniband/core/iwpm_msg.c +@@ -365,9 +365,9 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) + /* netlink attribute policy for the received response to register pid request */ + static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { + [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, +- [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_DEVNAME_SIZE - 1 }, +- [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, + [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } +@@ -677,7 +677,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) + + /* netlink attribute policy for the received request for mapping info */ + static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { +- [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } + }; +-- +2.53.0 + diff --git a/queue-6.12/remoteproc-xlnx-fix-sram-property-parsing.patch b/queue-6.12/remoteproc-xlnx-fix-sram-property-parsing.patch new file mode 100644 index 0000000000..807cbe1790 --- /dev/null +++ b/queue-6.12/remoteproc-xlnx-fix-sram-property-parsing.patch @@ -0,0 +1,42 @@ +From 8ce58f8d69aec876ecdc5158a31426337ddc05d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 12:27:30 -0800 +Subject: remoteproc: xlnx: Fix sram property parsing + +From: Tim Michals + +[ Upstream commit d116bccf6f1c199b27c9ebdf07cc3cfe868f919c ] + +As per sram bindings, "sram" property can be list of phandles. +When more than one sram phandles are listed, driver can't parse second +phandle's address correctly. Because, phandle index is passed to the API +instead of offset of address from reg property which is always 0 as per +sram.yaml bindings. Fix it by passing 0 to the API instead of sram +phandle index. + +Fixes: 77fcdf51b8ca ("remoteproc: xlnx: Add sram support") +Signed-off-by: Tim Michals +Signed-off-by: Tanmay Shah +Link: https://lore.kernel.org/r/20260204202730.3729984-1-tanmay.shah@amd.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/xlnx_r5_remoteproc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c +index 6a64e5909f6ae..d1c069704da8d 100644 +--- a/drivers/remoteproc/xlnx_r5_remoteproc.c ++++ b/drivers/remoteproc/xlnx_r5_remoteproc.c +@@ -990,7 +990,7 @@ static int zynqmp_r5_get_sram_banks(struct zynqmp_r5_core *r5_core) + } + + /* Get SRAM device address */ +- ret = of_property_read_reg(sram_np, i, &abs_addr, &size); ++ ret = of_property_read_reg(sram_np, 0, &abs_addr, &size); + if (ret) { + dev_err(dev, "failed to get reg property\n"); + goto fail_sram_get; +-- +2.53.0 + diff --git a/queue-6.12/reset-add-devres-helpers-to-request-pre-deasserted-r.patch b/queue-6.12/reset-add-devres-helpers-to-request-pre-deasserted-r.patch new file mode 100644 index 0000000000..041bda31dc --- /dev/null +++ b/queue-6.12/reset-add-devres-helpers-to-request-pre-deasserted-r.patch @@ -0,0 +1,320 @@ +From 176339a6923682eed8a088c5cf114d0c772af7c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Sep 2024 18:40:10 +0200 +Subject: reset: Add devres helpers to request pre-deasserted reset controls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Philipp Zabel + +[ Upstream commit d872bed85036f5e60c66b0dd0994346b4ea6470c ] + +Add devres helpers + + - devm_reset_control_bulk_get_exclusive_deasserted + - devm_reset_control_bulk_get_optional_exclusive_deasserted + - devm_reset_control_bulk_get_optional_shared_deasserted + - devm_reset_control_bulk_get_shared_deasserted + - devm_reset_control_get_exclusive_deasserted + - devm_reset_control_get_optional_exclusive_deasserted + - devm_reset_control_get_optional_shared_deasserted + - devm_reset_control_get_shared_deasserted + +to request and immediately deassert reset controls. During cleanup, +reset_control_assert() will be called automatically on the returned +reset controls. + +Acked-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20240925-reset-get-deasserted-v2-2-b3601bbd0458@pengutronix.de +Signed-off-by: Philipp Zabel +Stable-dep-of: bef1eef66718 ("i3c: master: dw-i3c: Fix missing reset assertion in remove() callback") +Signed-off-by: Sasha Levin +--- + drivers/reset/core.c | 48 +++++++++++++++++- + include/linux/reset.h | 113 ++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 159 insertions(+), 2 deletions(-) + +diff --git a/drivers/reset/core.c b/drivers/reset/core.c +index 682d61812852b..22f67fc77ae53 100644 +--- a/drivers/reset/core.c ++++ b/drivers/reset/core.c +@@ -1236,23 +1236,46 @@ static void devm_reset_control_release(struct device *dev, void *res) + reset_control_put(*(struct reset_control **)res); + } + ++static void devm_reset_control_release_deasserted(struct device *dev, void *res) ++{ ++ struct reset_control *rstc = *(struct reset_control **)res; ++ ++ reset_control_assert(rstc); ++ reset_control_put(rstc); ++} ++ + struct reset_control * + __devm_reset_control_get(struct device *dev, const char *id, int index, + enum reset_control_flags flags) + { + struct reset_control **ptr, *rstc; ++ bool deasserted = flags & RESET_CONTROL_FLAGS_BIT_DEASSERTED; + +- ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr), ++ ptr = devres_alloc(deasserted ? devm_reset_control_release_deasserted : ++ devm_reset_control_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + ++ flags &= ~RESET_CONTROL_FLAGS_BIT_DEASSERTED; ++ + rstc = __reset_control_get(dev, id, index, flags); + if (IS_ERR_OR_NULL(rstc)) { + devres_free(ptr); + return rstc; + } + ++ if (deasserted) { ++ int ret; ++ ++ ret = reset_control_deassert(rstc); ++ if (ret) { ++ reset_control_put(rstc); ++ devres_free(ptr); ++ return ERR_PTR(ret); ++ } ++ } ++ + *ptr = rstc; + devres_add(dev, ptr); + +@@ -1272,24 +1295,45 @@ static void devm_reset_control_bulk_release(struct device *dev, void *res) + reset_control_bulk_put(devres->num_rstcs, devres->rstcs); + } + ++static void devm_reset_control_bulk_release_deasserted(struct device *dev, void *res) ++{ ++ struct reset_control_bulk_devres *devres = res; ++ ++ reset_control_bulk_assert(devres->num_rstcs, devres->rstcs); ++ reset_control_bulk_put(devres->num_rstcs, devres->rstcs); ++} ++ + int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + enum reset_control_flags flags) + { + struct reset_control_bulk_devres *ptr; ++ bool deasserted = flags & RESET_CONTROL_FLAGS_BIT_DEASSERTED; + int ret; + +- ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr), ++ ptr = devres_alloc(deasserted ? devm_reset_control_bulk_release_deasserted : ++ devm_reset_control_bulk_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + ++ flags &= ~RESET_CONTROL_FLAGS_BIT_DEASSERTED; ++ + ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, flags); + if (ret < 0) { + devres_free(ptr); + return ret; + } + ++ if (deasserted) { ++ ret = reset_control_bulk_deassert(num_rstcs, rstcs); ++ if (ret) { ++ reset_control_bulk_put(num_rstcs, rstcs); ++ devres_free(ptr); ++ return ret; ++ } ++ } ++ + ptr->num_rstcs = num_rstcs; + ptr->rstcs = rstcs; + devres_add(dev, ptr); +diff --git a/include/linux/reset.h b/include/linux/reset.h +index 30edaea2c8fb8..0ae6e9030d346 100644 +--- a/include/linux/reset.h ++++ b/include/linux/reset.h +@@ -29,6 +29,7 @@ struct reset_control_bulk_data { + #define RESET_CONTROL_FLAGS_BIT_SHARED BIT(0) /* not exclusive */ + #define RESET_CONTROL_FLAGS_BIT_OPTIONAL BIT(1) + #define RESET_CONTROL_FLAGS_BIT_ACQUIRED BIT(2) /* iff exclusive, not released */ ++#define RESET_CONTROL_FLAGS_BIT_DEASSERTED BIT(3) + + /** + * enum reset_control_flags - Flags that can be passed to the reset_control_get functions +@@ -36,21 +37,35 @@ struct reset_control_bulk_data { + * These values cannot be OR'd. + * + * @RESET_CONTROL_EXCLUSIVE: exclusive, acquired, ++ * @RESET_CONTROL_EXCLUSIVE_DEASSERTED: exclusive, acquired, deasserted + * @RESET_CONTROL_EXCLUSIVE_RELEASED: exclusive, released, + * @RESET_CONTROL_SHARED: shared ++ * @RESET_CONTROL_SHARED_DEASSERTED: shared, deasserted + * @RESET_CONTROL_OPTIONAL_EXCLUSIVE: optional, exclusive, acquired ++ * @RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED: optional, exclusive, acquired, deasserted + * @RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED: optional, exclusive, released + * @RESET_CONTROL_OPTIONAL_SHARED: optional, shared ++ * @RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED: optional, shared, deasserted + */ + enum reset_control_flags { + RESET_CONTROL_EXCLUSIVE = RESET_CONTROL_FLAGS_BIT_ACQUIRED, ++ RESET_CONTROL_EXCLUSIVE_DEASSERTED = RESET_CONTROL_FLAGS_BIT_ACQUIRED | ++ RESET_CONTROL_FLAGS_BIT_DEASSERTED, + RESET_CONTROL_EXCLUSIVE_RELEASED = 0, + RESET_CONTROL_SHARED = RESET_CONTROL_FLAGS_BIT_SHARED, ++ RESET_CONTROL_SHARED_DEASSERTED = RESET_CONTROL_FLAGS_BIT_SHARED | ++ RESET_CONTROL_FLAGS_BIT_DEASSERTED, + RESET_CONTROL_OPTIONAL_EXCLUSIVE = RESET_CONTROL_FLAGS_BIT_OPTIONAL | + RESET_CONTROL_FLAGS_BIT_ACQUIRED, ++ RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED = RESET_CONTROL_FLAGS_BIT_OPTIONAL | ++ RESET_CONTROL_FLAGS_BIT_ACQUIRED | ++ RESET_CONTROL_FLAGS_BIT_DEASSERTED, + RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED = RESET_CONTROL_FLAGS_BIT_OPTIONAL, + RESET_CONTROL_OPTIONAL_SHARED = RESET_CONTROL_FLAGS_BIT_OPTIONAL | + RESET_CONTROL_FLAGS_BIT_SHARED, ++ RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED = RESET_CONTROL_FLAGS_BIT_OPTIONAL | ++ RESET_CONTROL_FLAGS_BIT_SHARED | ++ RESET_CONTROL_FLAGS_BIT_DEASSERTED, + }; + + #ifdef CONFIG_RESET_CONTROLLER +@@ -597,6 +612,25 @@ __must_check devm_reset_control_get_exclusive(struct device *dev, + return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE); + } + ++/** ++ * devm_reset_control_get_exclusive_deasserted - resource managed ++ * reset_control_get_exclusive() + ++ * reset_control_deassert() ++ * @dev: device to be reset by the controller ++ * @id: reset line name ++ * ++ * Managed reset_control_get_exclusive() + reset_control_deassert(). For reset ++ * controllers returned from this function, reset_control_assert() + ++ * reset_control_put() is called automatically on driver detach. ++ * ++ * See reset_control_get_exclusive() for more information. ++ */ ++static inline struct reset_control * __must_check ++devm_reset_control_get_exclusive_deasserted(struct device *dev, const char *id) ++{ ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE_DEASSERTED); ++} ++ + /** + * devm_reset_control_bulk_get_exclusive - resource managed + * reset_control_bulk_get_exclusive() +@@ -713,6 +747,25 @@ static inline struct reset_control *devm_reset_control_get_shared( + return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_SHARED); + } + ++/** ++ * devm_reset_control_get_shared_deasserted - resource managed ++ * reset_control_get_shared() + ++ * reset_control_deassert() ++ * @dev: device to be reset by the controller ++ * @id: reset line name ++ * ++ * Managed reset_control_get_shared() + reset_control_deassert(). For reset ++ * controllers returned from this function, reset_control_assert() + ++ * reset_control_put() is called automatically on driver detach. ++ * ++ * See devm_reset_control_get_shared() for more information. ++ */ ++static inline struct reset_control * __must_check ++devm_reset_control_get_shared_deasserted(struct device *dev, const char *id) ++{ ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_SHARED_DEASSERTED); ++} ++ + /** + * devm_reset_control_bulk_get_shared - resource managed + * reset_control_bulk_get_shared() +@@ -733,6 +786,28 @@ devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs, + return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_SHARED); + } + ++/** ++ * devm_reset_control_bulk_get_shared_deasserted - resource managed ++ * reset_control_bulk_get_shared() + ++ * reset_control_bulk_deassert() ++ * @dev: device to be reset by the controller ++ * @num_rstcs: number of entries in rstcs array ++ * @rstcs: array of struct reset_control_bulk_data with reset line names set ++ * ++ * Managed reset_control_bulk_get_shared() + reset_control_bulk_deassert(). For ++ * reset controllers returned from this function, reset_control_bulk_assert() + ++ * reset_control_bulk_put() are called automatically on driver detach. ++ * ++ * See devm_reset_control_bulk_get_shared() for more information. ++ */ ++static inline int __must_check ++devm_reset_control_bulk_get_shared_deasserted(struct device *dev, int num_rstcs, ++ struct reset_control_bulk_data *rstcs) ++{ ++ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, ++ RESET_CONTROL_SHARED_DEASSERTED); ++} ++ + /** + * devm_reset_control_get_optional_exclusive - resource managed + * reset_control_get_optional_exclusive() +@@ -751,6 +826,25 @@ static inline struct reset_control *devm_reset_control_get_optional_exclusive( + return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE); + } + ++/** ++ * devm_reset_control_get_optional_exclusive_deasserted - resource managed ++ * reset_control_get_optional_exclusive() + ++ * reset_control_deassert() ++ * @dev: device to be reset by the controller ++ * @id: reset line name ++ * ++ * Managed reset_control_get_optional_exclusive() + reset_control_deassert(). ++ * For reset controllers returned from this function, reset_control_assert() + ++ * reset_control_put() is called automatically on driver detach. ++ * ++ * See devm_reset_control_get_optional_exclusive() for more information. ++ */ ++static inline struct reset_control * ++devm_reset_control_get_optional_exclusive_deasserted(struct device *dev, const char *id) ++{ ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE_DEASSERTED); ++} ++ + /** + * devm_reset_control_bulk_get_optional_exclusive - resource managed + * reset_control_bulk_get_optional_exclusive() +@@ -790,6 +884,25 @@ static inline struct reset_control *devm_reset_control_get_optional_shared( + return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED); + } + ++/** ++ * devm_reset_control_get_optional_shared_deasserted - resource managed ++ * reset_control_get_optional_shared() + ++ * reset_control_deassert() ++ * @dev: device to be reset by the controller ++ * @id: reset line name ++ * ++ * Managed reset_control_get_optional_shared() + reset_control_deassert(). For ++ * reset controllers returned from this function, reset_control_assert() + ++ * reset_control_put() is called automatically on driver detach. ++ * ++ * See devm_reset_control_get_optional_shared() for more information. ++ */ ++static inline struct reset_control * ++devm_reset_control_get_optional_shared_deasserted(struct device *dev, const char *id) ++{ ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED_DEASSERTED); ++} ++ + /** + * devm_reset_control_bulk_get_optional_shared - resource managed + * reset_control_bulk_get_optional_shared() +-- +2.53.0 + diff --git a/queue-6.12/reset-replace-boolean-parameters-with-flags-paramete.patch b/queue-6.12/reset-replace-boolean-parameters-with-flags-paramete.patch new file mode 100644 index 0000000000..3e95b198fe --- /dev/null +++ b/queue-6.12/reset-replace-boolean-parameters-with-flags-paramete.patch @@ -0,0 +1,751 @@ +From a435ca923238eaa02cb1648477e724c1144547e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Sep 2024 18:40:09 +0200 +Subject: reset: replace boolean parameters with flags parameter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Philipp Zabel + +[ Upstream commit dad35f7d2fc14e446669d4cab100597a6798eae5 ] + +Introduce enum reset_control_flags and replace the list of boolean +parameters to the internal reset_control_get functions with a single +flags parameter, before adding more boolean options. + +The separate boolean parameters have been shown to be error prone in +the past. See for example commit a57f68ddc886 ("reset: Fix devm bulk +optional exclusive control getter"). + +Acked-by: Uwe Kleine-König +Link: https://lore.kernel.org/r/20240925-reset-get-deasserted-v2-1-b3601bbd0458@pengutronix.de +Signed-off-by: Philipp Zabel +Stable-dep-of: bef1eef66718 ("i3c: master: dw-i3c: Fix missing reset assertion in remove() callback") +Signed-off-by: Sasha Levin +--- + drivers/reset/core.c | 71 +++++++++++-------- + include/linux/reset.h | 161 ++++++++++++++++++++++++++---------------- + 2 files changed, 139 insertions(+), 93 deletions(-) + +diff --git a/drivers/reset/core.c b/drivers/reset/core.c +index 4d509d41456ad..682d61812852b 100644 +--- a/drivers/reset/core.c ++++ b/drivers/reset/core.c +@@ -773,12 +773,19 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_release); + + static struct reset_control * + __reset_control_get_internal(struct reset_controller_dev *rcdev, +- unsigned int index, bool shared, bool acquired) ++ unsigned int index, enum reset_control_flags flags) + { ++ bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED; ++ bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED; + struct reset_control *rstc; + + lockdep_assert_held(&reset_list_mutex); + ++ /* Expect callers to filter out OPTIONAL and DEASSERTED bits */ ++ if (WARN_ON(flags & ~(RESET_CONTROL_FLAGS_BIT_SHARED | ++ RESET_CONTROL_FLAGS_BIT_ACQUIRED))) ++ return ERR_PTR(-EINVAL); ++ + list_for_each_entry(rstc, &rcdev->reset_control_head, list) { + if (rstc->id == index) { + /* +@@ -994,8 +1001,9 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a + + struct reset_control * + __of_reset_control_get(struct device_node *node, const char *id, int index, +- bool shared, bool optional, bool acquired) ++ enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; + bool gpio_fallback = false; + struct reset_control *rstc; + struct reset_controller_dev *rcdev; +@@ -1059,8 +1067,10 @@ __of_reset_control_get(struct device_node *node, const char *id, int index, + goto out_unlock; + } + ++ flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + /* reset_list_mutex also protects the rcdev's reset_control list */ +- rstc = __reset_control_get_internal(rcdev, rstc_id, shared, acquired); ++ rstc = __reset_control_get_internal(rcdev, rstc_id, flags); + + out_unlock: + mutex_unlock(&reset_list_mutex); +@@ -1091,8 +1101,9 @@ __reset_controller_by_name(const char *name) + + static struct reset_control * + __reset_control_get_from_lookup(struct device *dev, const char *con_id, +- bool shared, bool optional, bool acquired) ++ enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; + const struct reset_control_lookup *lookup; + struct reset_controller_dev *rcdev; + const char *dev_id = dev_name(dev); +@@ -1116,9 +1127,11 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id, + return ERR_PTR(-EPROBE_DEFER); + } + ++ flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + rstc = __reset_control_get_internal(rcdev, + lookup->index, +- shared, acquired); ++ flags); + mutex_unlock(&reset_list_mutex); + break; + } +@@ -1133,30 +1146,29 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id, + } + + struct reset_control *__reset_control_get(struct device *dev, const char *id, +- int index, bool shared, bool optional, +- bool acquired) ++ int index, enum reset_control_flags flags) + { ++ bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED; ++ bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED; ++ + if (WARN_ON(shared && acquired)) + return ERR_PTR(-EINVAL); + + if (dev->of_node) +- return __of_reset_control_get(dev->of_node, id, index, shared, +- optional, acquired); ++ return __of_reset_control_get(dev->of_node, id, index, flags); + +- return __reset_control_get_from_lookup(dev, id, shared, optional, +- acquired); ++ return __reset_control_get_from_lookup(dev, id, flags); + } + EXPORT_SYMBOL_GPL(__reset_control_get); + + int __reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, +- bool shared, bool optional, bool acquired) ++ enum reset_control_flags flags) + { + int ret, i; + + for (i = 0; i < num_rstcs; i++) { +- rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0, +- shared, optional, acquired); ++ rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0, flags); + if (IS_ERR(rstcs[i].rstc)) { + ret = PTR_ERR(rstcs[i].rstc); + goto err; +@@ -1226,7 +1238,7 @@ static void devm_reset_control_release(struct device *dev, void *res) + + struct reset_control * + __devm_reset_control_get(struct device *dev, const char *id, int index, +- bool shared, bool optional, bool acquired) ++ enum reset_control_flags flags) + { + struct reset_control **ptr, *rstc; + +@@ -1235,7 +1247,7 @@ __devm_reset_control_get(struct device *dev, const char *id, int index, + if (!ptr) + return ERR_PTR(-ENOMEM); + +- rstc = __reset_control_get(dev, id, index, shared, optional, acquired); ++ rstc = __reset_control_get(dev, id, index, flags); + if (IS_ERR_OR_NULL(rstc)) { + devres_free(ptr); + return rstc; +@@ -1262,7 +1274,7 @@ static void devm_reset_control_bulk_release(struct device *dev, void *res) + + int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, +- bool shared, bool optional, bool acquired) ++ enum reset_control_flags flags) + { + struct reset_control_bulk_devres *ptr; + int ret; +@@ -1272,7 +1284,7 @@ int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, + if (!ptr) + return -ENOMEM; + +- ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired); ++ ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, flags); + if (ret < 0) { + devres_free(ptr); + return ret; +@@ -1298,6 +1310,7 @@ EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get); + */ + int __device_reset(struct device *dev, bool optional) + { ++ enum reset_control_flags flags; + struct reset_control *rstc; + int ret; + +@@ -1313,7 +1326,8 @@ int __device_reset(struct device *dev, bool optional) + } + #endif + +- rstc = __reset_control_get(dev, NULL, 0, 0, optional, true); ++ flags = optional ? RESET_CONTROL_OPTIONAL_EXCLUSIVE : RESET_CONTROL_EXCLUSIVE; ++ rstc = __reset_control_get(dev, NULL, 0, flags); + if (IS_ERR(rstc)) + return PTR_ERR(rstc); + +@@ -1356,17 +1370,14 @@ static int of_reset_control_get_count(struct device_node *node) + * device node. + * + * @np: device node for the device that requests the reset controls array +- * @shared: whether reset controls are shared or not +- * @optional: whether it is optional to get the reset controls +- * @acquired: only one reset control may be acquired for a given controller +- * and ID ++ * @flags: whether reset controls are shared, optional, acquired + * + * Returns pointer to allocated reset_control on success or error on failure + */ + struct reset_control * +-of_reset_control_array_get(struct device_node *np, bool shared, bool optional, +- bool acquired) ++of_reset_control_array_get(struct device_node *np, enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; + struct reset_control_array *resets; + struct reset_control *rstc; + int num, i; +@@ -1381,8 +1392,7 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional, + resets->num_rstcs = num; + + for (i = 0; i < num; i++) { +- rstc = __of_reset_control_get(np, NULL, i, shared, optional, +- acquired); ++ rstc = __of_reset_control_get(np, NULL, i, flags); + if (IS_ERR(rstc)) + goto err_rst; + resets->rstc[i] = rstc; +@@ -1407,8 +1417,7 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get); + * devm_reset_control_array_get - Resource managed reset control array get + * + * @dev: device that requests the list of reset controls +- * @shared: whether reset controls are shared or not +- * @optional: whether it is optional to get the reset controls ++ * @flags: whether reset controls are shared, optional, acquired + * + * The reset control array APIs are intended for a list of resets + * that just have to be asserted or deasserted, without any +@@ -1417,7 +1426,7 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get); + * Returns pointer to allocated reset_control on success or error on failure + */ + struct reset_control * +-devm_reset_control_array_get(struct device *dev, bool shared, bool optional) ++devm_reset_control_array_get(struct device *dev, enum reset_control_flags flags) + { + struct reset_control **ptr, *rstc; + +@@ -1426,7 +1435,7 @@ devm_reset_control_array_get(struct device *dev, bool shared, bool optional) + if (!ptr) + return ERR_PTR(-ENOMEM); + +- rstc = of_reset_control_array_get(dev->of_node, shared, optional, true); ++ rstc = of_reset_control_array_get(dev->of_node, flags); + if (IS_ERR_OR_NULL(rstc)) { + devres_free(ptr); + return rstc; +diff --git a/include/linux/reset.h b/include/linux/reset.h +index 4b31d683776eb..30edaea2c8fb8 100644 +--- a/include/linux/reset.h ++++ b/include/linux/reset.h +@@ -26,6 +26,33 @@ struct reset_control_bulk_data { + struct reset_control *rstc; + }; + ++#define RESET_CONTROL_FLAGS_BIT_SHARED BIT(0) /* not exclusive */ ++#define RESET_CONTROL_FLAGS_BIT_OPTIONAL BIT(1) ++#define RESET_CONTROL_FLAGS_BIT_ACQUIRED BIT(2) /* iff exclusive, not released */ ++ ++/** ++ * enum reset_control_flags - Flags that can be passed to the reset_control_get functions ++ * to determine the type of reset control. ++ * These values cannot be OR'd. ++ * ++ * @RESET_CONTROL_EXCLUSIVE: exclusive, acquired, ++ * @RESET_CONTROL_EXCLUSIVE_RELEASED: exclusive, released, ++ * @RESET_CONTROL_SHARED: shared ++ * @RESET_CONTROL_OPTIONAL_EXCLUSIVE: optional, exclusive, acquired ++ * @RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED: optional, exclusive, released ++ * @RESET_CONTROL_OPTIONAL_SHARED: optional, shared ++ */ ++enum reset_control_flags { ++ RESET_CONTROL_EXCLUSIVE = RESET_CONTROL_FLAGS_BIT_ACQUIRED, ++ RESET_CONTROL_EXCLUSIVE_RELEASED = 0, ++ RESET_CONTROL_SHARED = RESET_CONTROL_FLAGS_BIT_SHARED, ++ RESET_CONTROL_OPTIONAL_EXCLUSIVE = RESET_CONTROL_FLAGS_BIT_OPTIONAL | ++ RESET_CONTROL_FLAGS_BIT_ACQUIRED, ++ RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED = RESET_CONTROL_FLAGS_BIT_OPTIONAL, ++ RESET_CONTROL_OPTIONAL_SHARED = RESET_CONTROL_FLAGS_BIT_OPTIONAL | ++ RESET_CONTROL_FLAGS_BIT_SHARED, ++}; ++ + #ifdef CONFIG_RESET_CONTROLLER + + int reset_control_reset(struct reset_control *rstc); +@@ -43,30 +70,25 @@ int reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rs + void reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs); + + struct reset_control *__of_reset_control_get(struct device_node *node, +- const char *id, int index, bool shared, +- bool optional, bool acquired); ++ const char *id, int index, enum reset_control_flags flags); + struct reset_control *__reset_control_get(struct device *dev, const char *id, +- int index, bool shared, +- bool optional, bool acquired); ++ int index, enum reset_control_flags flags); + void reset_control_put(struct reset_control *rstc); + int __reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, +- bool shared, bool optional, bool acquired); ++ enum reset_control_flags flags); + void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs); + + int __device_reset(struct device *dev, bool optional); + struct reset_control *__devm_reset_control_get(struct device *dev, +- const char *id, int index, bool shared, +- bool optional, bool acquired); ++ const char *id, int index, enum reset_control_flags flags); + int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, +- bool shared, bool optional, bool acquired); ++ enum reset_control_flags flags); + + struct reset_control *devm_reset_control_array_get(struct device *dev, +- bool shared, bool optional); +-struct reset_control *of_reset_control_array_get(struct device_node *np, +- bool shared, bool optional, +- bool acquired); ++ enum reset_control_flags flags); ++struct reset_control *of_reset_control_array_get(struct device_node *np, enum reset_control_flags); + + int reset_control_get_count(struct device *dev); + +@@ -117,17 +139,19 @@ static inline int __device_reset(struct device *dev, bool optional) + + static inline struct reset_control *__of_reset_control_get( + struct device_node *node, +- const char *id, int index, bool shared, +- bool optional, bool acquired) ++ const char *id, int index, enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + return optional ? NULL : ERR_PTR(-ENOTSUPP); + } + + static inline struct reset_control *__reset_control_get( + struct device *dev, const char *id, +- int index, bool shared, bool optional, +- bool acquired) ++ int index, enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + return optional ? NULL : ERR_PTR(-ENOTSUPP); + } + +@@ -163,8 +187,10 @@ reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs) + static inline int + __reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, +- bool shared, bool optional, bool acquired) ++ enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + return optional ? 0 : -EOPNOTSUPP; + } + +@@ -175,30 +201,36 @@ reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs) + + static inline struct reset_control *__devm_reset_control_get( + struct device *dev, const char *id, +- int index, bool shared, bool optional, +- bool acquired) ++ int index, enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + return optional ? NULL : ERR_PTR(-ENOTSUPP); + } + + static inline int + __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, +- bool shared, bool optional, bool acquired) ++ enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + return optional ? 0 : -EOPNOTSUPP; + } + + static inline struct reset_control * +-devm_reset_control_array_get(struct device *dev, bool shared, bool optional) ++devm_reset_control_array_get(struct device *dev, enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + return optional ? NULL : ERR_PTR(-ENOTSUPP); + } + + static inline struct reset_control * +-of_reset_control_array_get(struct device_node *np, bool shared, bool optional, +- bool acquired) ++of_reset_control_array_get(struct device_node *np, enum reset_control_flags flags) + { ++ bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; ++ + return optional ? NULL : ERR_PTR(-ENOTSUPP); + } + +@@ -237,7 +269,7 @@ static inline int device_reset_optional(struct device *dev) + static inline struct reset_control * + __must_check reset_control_get_exclusive(struct device *dev, const char *id) + { +- return __reset_control_get(dev, id, 0, false, false, true); ++ return __reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE); + } + + /** +@@ -254,7 +286,7 @@ static inline int __must_check + reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true); ++ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_EXCLUSIVE); + } + + /** +@@ -275,7 +307,7 @@ static inline struct reset_control * + __must_check reset_control_get_exclusive_released(struct device *dev, + const char *id) + { +- return __reset_control_get(dev, id, 0, false, false, false); ++ return __reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE_RELEASED); + } + + /** +@@ -296,7 +328,7 @@ static inline int __must_check + reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false); ++ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_EXCLUSIVE_RELEASED); + } + + /** +@@ -317,7 +349,8 @@ static inline int __must_check + reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false); ++ return __reset_control_bulk_get(dev, num_rstcs, rstcs, ++ RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED); + } + + /** +@@ -345,7 +378,7 @@ reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_r + static inline struct reset_control *reset_control_get_shared( + struct device *dev, const char *id) + { +- return __reset_control_get(dev, id, 0, true, false, false); ++ return __reset_control_get(dev, id, 0, RESET_CONTROL_SHARED); + } + + /** +@@ -362,7 +395,7 @@ static inline int __must_check + reset_control_bulk_get_shared(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false); ++ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_SHARED); + } + + /** +@@ -379,7 +412,7 @@ reset_control_bulk_get_shared(struct device *dev, int num_rstcs, + static inline struct reset_control *reset_control_get_optional_exclusive( + struct device *dev, const char *id) + { +- return __reset_control_get(dev, id, 0, false, true, true); ++ return __reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE); + } + + /** +@@ -399,7 +432,7 @@ static inline int __must_check + reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true); ++ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_OPTIONAL_EXCLUSIVE); + } + + /** +@@ -416,7 +449,7 @@ reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs, + static inline struct reset_control *reset_control_get_optional_shared( + struct device *dev, const char *id) + { +- return __reset_control_get(dev, id, 0, true, true, false); ++ return __reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED); + } + + /** +@@ -436,7 +469,7 @@ static inline int __must_check + reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false); ++ return __reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_OPTIONAL_SHARED); + } + + /** +@@ -452,7 +485,7 @@ reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs, + static inline struct reset_control *of_reset_control_get_exclusive( + struct device_node *node, const char *id) + { +- return __of_reset_control_get(node, id, 0, false, false, true); ++ return __of_reset_control_get(node, id, 0, RESET_CONTROL_EXCLUSIVE); + } + + /** +@@ -472,7 +505,7 @@ static inline struct reset_control *of_reset_control_get_exclusive( + static inline struct reset_control *of_reset_control_get_optional_exclusive( + struct device_node *node, const char *id) + { +- return __of_reset_control_get(node, id, 0, false, true, true); ++ return __of_reset_control_get(node, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE); + } + + /** +@@ -497,7 +530,7 @@ static inline struct reset_control *of_reset_control_get_optional_exclusive( + static inline struct reset_control *of_reset_control_get_shared( + struct device_node *node, const char *id) + { +- return __of_reset_control_get(node, id, 0, true, false, false); ++ return __of_reset_control_get(node, id, 0, RESET_CONTROL_SHARED); + } + + /** +@@ -514,7 +547,7 @@ static inline struct reset_control *of_reset_control_get_shared( + static inline struct reset_control *of_reset_control_get_exclusive_by_index( + struct device_node *node, int index) + { +- return __of_reset_control_get(node, NULL, index, false, false, true); ++ return __of_reset_control_get(node, NULL, index, RESET_CONTROL_EXCLUSIVE); + } + + /** +@@ -542,7 +575,7 @@ static inline struct reset_control *of_reset_control_get_exclusive_by_index( + static inline struct reset_control *of_reset_control_get_shared_by_index( + struct device_node *node, int index) + { +- return __of_reset_control_get(node, NULL, index, true, false, false); ++ return __of_reset_control_get(node, NULL, index, RESET_CONTROL_SHARED); + } + + /** +@@ -561,7 +594,7 @@ static inline struct reset_control * + __must_check devm_reset_control_get_exclusive(struct device *dev, + const char *id) + { +- return __devm_reset_control_get(dev, id, 0, false, false, true); ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE); + } + + /** +@@ -581,7 +614,8 @@ static inline int __must_check + devm_reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true); ++ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, ++ RESET_CONTROL_EXCLUSIVE); + } + + /** +@@ -600,7 +634,7 @@ static inline struct reset_control * + __must_check devm_reset_control_get_exclusive_released(struct device *dev, + const char *id) + { +- return __devm_reset_control_get(dev, id, 0, false, false, false); ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_EXCLUSIVE_RELEASED); + } + + /** +@@ -620,7 +654,8 @@ static inline int __must_check + devm_reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false); ++ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, ++ RESET_CONTROL_EXCLUSIVE_RELEASED); + } + + /** +@@ -639,7 +674,7 @@ static inline struct reset_control * + __must_check devm_reset_control_get_optional_exclusive_released(struct device *dev, + const char *id) + { +- return __devm_reset_control_get(dev, id, 0, false, true, false); ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED); + } + + /** +@@ -659,7 +694,8 @@ static inline int __must_check + devm_reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false); ++ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, ++ RESET_CONTROL_OPTIONAL_EXCLUSIVE_RELEASED); + } + + /** +@@ -674,7 +710,7 @@ devm_reset_control_bulk_get_optional_exclusive_released(struct device *dev, int + static inline struct reset_control *devm_reset_control_get_shared( + struct device *dev, const char *id) + { +- return __devm_reset_control_get(dev, id, 0, true, false, false); ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_SHARED); + } + + /** +@@ -694,7 +730,7 @@ static inline int __must_check + devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false); ++ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_SHARED); + } + + /** +@@ -712,7 +748,7 @@ devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs, + static inline struct reset_control *devm_reset_control_get_optional_exclusive( + struct device *dev, const char *id) + { +- return __devm_reset_control_get(dev, id, 0, false, true, true); ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_EXCLUSIVE); + } + + /** +@@ -732,7 +768,8 @@ static inline int __must_check + devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true); ++ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, ++ RESET_CONTROL_OPTIONAL_EXCLUSIVE); + } + + /** +@@ -750,7 +787,7 @@ devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs + static inline struct reset_control *devm_reset_control_get_optional_shared( + struct device *dev, const char *id) + { +- return __devm_reset_control_get(dev, id, 0, true, true, false); ++ return __devm_reset_control_get(dev, id, 0, RESET_CONTROL_OPTIONAL_SHARED); + } + + /** +@@ -770,7 +807,7 @@ static inline int __must_check + devm_reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) + { +- return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false); ++ return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, RESET_CONTROL_OPTIONAL_SHARED); + } + + /** +@@ -788,7 +825,7 @@ devm_reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs, + static inline struct reset_control * + devm_reset_control_get_exclusive_by_index(struct device *dev, int index) + { +- return __devm_reset_control_get(dev, NULL, index, false, false, true); ++ return __devm_reset_control_get(dev, NULL, index, RESET_CONTROL_EXCLUSIVE); + } + + /** +@@ -804,7 +841,7 @@ devm_reset_control_get_exclusive_by_index(struct device *dev, int index) + static inline struct reset_control * + devm_reset_control_get_shared_by_index(struct device *dev, int index) + { +- return __devm_reset_control_get(dev, NULL, index, true, false, false); ++ return __devm_reset_control_get(dev, NULL, index, RESET_CONTROL_SHARED); + } + + /* +@@ -852,54 +889,54 @@ static inline struct reset_control *devm_reset_control_get_by_index( + static inline struct reset_control * + devm_reset_control_array_get_exclusive(struct device *dev) + { +- return devm_reset_control_array_get(dev, false, false); ++ return devm_reset_control_array_get(dev, RESET_CONTROL_EXCLUSIVE); + } + + static inline struct reset_control * + devm_reset_control_array_get_shared(struct device *dev) + { +- return devm_reset_control_array_get(dev, true, false); ++ return devm_reset_control_array_get(dev, RESET_CONTROL_SHARED); + } + + static inline struct reset_control * + devm_reset_control_array_get_optional_exclusive(struct device *dev) + { +- return devm_reset_control_array_get(dev, false, true); ++ return devm_reset_control_array_get(dev, RESET_CONTROL_OPTIONAL_EXCLUSIVE); + } + + static inline struct reset_control * + devm_reset_control_array_get_optional_shared(struct device *dev) + { +- return devm_reset_control_array_get(dev, true, true); ++ return devm_reset_control_array_get(dev, RESET_CONTROL_OPTIONAL_SHARED); + } + + static inline struct reset_control * + of_reset_control_array_get_exclusive(struct device_node *node) + { +- return of_reset_control_array_get(node, false, false, true); ++ return of_reset_control_array_get(node, RESET_CONTROL_EXCLUSIVE); + } + + static inline struct reset_control * + of_reset_control_array_get_exclusive_released(struct device_node *node) + { +- return of_reset_control_array_get(node, false, false, false); ++ return of_reset_control_array_get(node, RESET_CONTROL_EXCLUSIVE_RELEASED); + } + + static inline struct reset_control * + of_reset_control_array_get_shared(struct device_node *node) + { +- return of_reset_control_array_get(node, true, false, true); ++ return of_reset_control_array_get(node, RESET_CONTROL_SHARED); + } + + static inline struct reset_control * + of_reset_control_array_get_optional_exclusive(struct device_node *node) + { +- return of_reset_control_array_get(node, false, true, true); ++ return of_reset_control_array_get(node, RESET_CONTROL_OPTIONAL_EXCLUSIVE); + } + + static inline struct reset_control * + of_reset_control_array_get_optional_shared(struct device_node *node) + { +- return of_reset_control_array_get(node, true, true, true); ++ return of_reset_control_array_get(node, RESET_CONTROL_OPTIONAL_SHARED); + } + #endif +-- +2.53.0 + diff --git a/queue-6.12/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch b/queue-6.12/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch new file mode 100644 index 0000000000..d03006d727 --- /dev/null +++ b/queue-6.12/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch @@ -0,0 +1,51 @@ +From 9a73a79bedf220a71ef2e825ebae555cf75c3d0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 18:00:10 +0000 +Subject: rtc: abx80x: Disable alarm feature if no interrupt attached + +From: Anthony Pighin (Nokia) + +[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ] + +Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting +alarm") exposed an issue where the rtc-abx80x driver does not clear the +alarm feature bit, but instead relies on the set_alarm operation to return +invalid. + +For example, when a RTC_UIE_ON ioctl is handled, it should abort at the +feature validation. Instead, it proceeds to the rtc_timer_enqueue(), +which used to return an error from the set_alarm call. However, +following the race condition handling, which likely should not be +discarding predecing errors, a success condition is returned to the +ioctl() caller. This results in (for example): + hwclock: select() to /dev/rtc0 to wait for clock tick timed out + +Notwithstanding the validity of the race condition handling, if an interrupt +wasn't specified, or could not be attached, the driver should clear the +alarm feature bit. + +Fixes: 718a820a303c ("rtc: abx80x: add alarm support") +Signed-off-by: Anthony Pighin +Link: https://patch.msgid.link/BN0PR08MB69510928028C933749F4139383D1A@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-abx80x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c +index 3fee27914ba80..5f3a3e60a19d0 100644 +--- a/drivers/rtc/rtc-abx80x.c ++++ b/drivers/rtc/rtc-abx80x.c +@@ -933,6 +933,8 @@ static int abx80x_probe(struct i2c_client *client) + client->irq = 0; + } + } ++ if (client->irq <= 0) ++ clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); + + err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); + if (err) { +-- +2.53.0 + diff --git a/queue-6.12/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch b/queue-6.12/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch new file mode 100644 index 0000000000..a3342c89a2 --- /dev/null +++ b/queue-6.12/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch @@ -0,0 +1,103 @@ +From 7329b8f36e5d77477980a67adbbbab5e8d9040e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 18:46:25 +0100 +Subject: s390/bpf: Zero-extend bpf prog return values and kfunc arguments + +From: Ilya Leoshkevich + +[ Upstream commit 202e42e4aa890172366354b233c42c73107a3f59 ] + +s390x ABI requires callers to zero-extend unsigned arguments and +sign-extend signed arguments, and callees to zero-extend unsigned +return values and sign-extend signed return values. + +s390 BPF JIT currently implements only sign extension. Fix this +omission and implement zero extension too. + +Fixes: 528eb2cb87bc ("s390/bpf: Implement arch_prepare_bpf_trampoline()") +Reported-by: Hari Bathini +Closes: https://lore.kernel.org/bpf/20260312080113.843408-1-hbathini@linux.ibm.com/ +Signed-off-by: Ilya Leoshkevich +Tested-by: Ihor Solodrai +Link: https://lore.kernel.org/r/20260313174807.581826-1-iii@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/s390/net/bpf_jit_comp.c | 39 ++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 15 deletions(-) + +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index f305cb42070df..c3ad3cf86ca64 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -842,25 +842,34 @@ static int bpf_jit_probe_post(struct bpf_jit *jit, struct bpf_prog *fp, + } + + /* +- * Sign-extend the register if necessary ++ * Sign- or zero-extend the register if necessary + */ +-static int sign_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) ++static int sign_zero_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) + { +- if (!(flags & BTF_FMODEL_SIGNED_ARG)) +- return 0; +- + switch (size) { + case 1: +- /* lgbr %r,%r */ +- EMIT4(0xb9060000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lgbr %r,%r */ ++ EMIT4(0xb9060000, r, r); ++ else ++ /* llgcr %r,%r */ ++ EMIT4(0xb9840000, r, r); + return 0; + case 2: +- /* lghr %r,%r */ +- EMIT4(0xb9070000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lghr %r,%r */ ++ EMIT4(0xb9070000, r, r); ++ else ++ /* llghr %r,%r */ ++ EMIT4(0xb9850000, r, r); + return 0; + case 4: +- /* lgfr %r,%r */ +- EMIT4(0xb9140000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lgfr %r,%r */ ++ EMIT4(0xb9140000, r, r); ++ else ++ /* llgfr %r,%r */ ++ EMIT4(0xb9160000, r, r); + return 0; + case 8: + return 0; +@@ -1802,9 +1811,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + return -1; + + for (j = 0; j < m->nr_args; j++) { +- if (sign_extend(jit, BPF_REG_1 + j, +- m->arg_size[j], +- m->arg_flags[j])) ++ if (sign_zero_extend(jit, BPF_REG_1 + j, ++ m->arg_size[j], ++ m->arg_flags[j])) + return -1; + } + } +@@ -2551,7 +2560,7 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit, + call_r1(jit); + /* stg %r2,retval_off(%r15) */ + if (save_ret) { +- if (sign_extend(jit, REG_2, m->ret_size, m->ret_flags)) ++ if (sign_zero_extend(jit, REG_2, m->ret_size, m->ret_flags)) + return -1; + EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15, + tjit->retval_off); +-- +2.53.0 + diff --git a/queue-6.12/s390-cio-use-generic-driver_override-infrastructure.patch b/queue-6.12/s390-cio-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..54509e293b --- /dev/null +++ b/queue-6.12/s390-cio-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,122 @@ +From 5324ef0df0465bb406a1cb5c99c2216eff8305e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:13 +0100 +Subject: s390/cio: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit ac4d8bb6e2e13e8684a76ea48d13ebaaaf5c24c4 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: ebc3d1791503 ("s390/cio: introduce driver_override on the css bus") +Reviewed-by: Vineeth Vijayan +Link: https://patch.msgid.link/20260324005919.2408620-10-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/cio.h | 5 ----- + drivers/s390/cio/css.c | 34 ++++------------------------------ + 2 files changed, 4 insertions(+), 35 deletions(-) + +diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h +index a9057a5b670a6..23374604c6b01 100644 +--- a/drivers/s390/cio/cio.h ++++ b/drivers/s390/cio/cio.h +@@ -103,11 +103,6 @@ struct subchannel { + struct work_struct todo_work; + struct schib_config config; + u64 dma_mask; +- /* +- * Driver name to force a match. Do not set directly, because core +- * frees it. Use driver_set_override() to set or clear it. +- */ +- const char *driver_override; + } __attribute__ ((aligned(8))); + + DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb); +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 61be7c0550bc4..b0ddbad1ebf37 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -160,7 +160,6 @@ static void css_subchannel_release(struct device *dev) + + sch->config.intparm = 0; + cio_commit_config(sch); +- kfree(sch->driver_override); + kfree(sch); + } + +@@ -324,37 +323,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(modalias); + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct subchannel *sch = to_subchannel(dev); +- int ret; +- +- ret = driver_set_override(dev, &sch->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct subchannel *sch = to_subchannel(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", sch->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *subch_attrs[] = { + &dev_attr_type.attr, + &dev_attr_modalias.attr, +- &dev_attr_driver_override.attr, + NULL, + }; + +@@ -1358,9 +1329,11 @@ static int css_bus_match(struct device *dev, const struct device_driver *drv) + struct subchannel *sch = to_subchannel(dev); + const struct css_driver *driver = to_cssdriver(drv); + struct css_device_id *id; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (sch->driver_override && strcmp(sch->driver_override, drv->name)) ++ ret = device_match_driver_override(dev, drv); ++ if (ret == 0) + return 0; + + for (id = driver->subchannel_type; id->match_flags; id++) { +@@ -1417,6 +1390,7 @@ static int css_uevent(const struct device *dev, struct kobj_uevent_env *env) + + static const struct bus_type css_bus_type = { + .name = "css", ++ .driver_override = true, + .match = css_bus_match, + .probe = css_probe, + .remove = css_remove, +-- +2.53.0 + diff --git a/queue-6.12/sched-fair-clear-rel_deadline-when-initializing-fork.patch b/queue-6.12/sched-fair-clear-rel_deadline-when-initializing-fork.patch new file mode 100644 index 0000000000..30d584c172 --- /dev/null +++ b/queue-6.12/sched-fair-clear-rel_deadline-when-initializing-fork.patch @@ -0,0 +1,87 @@ +From 71b7505106a7e726cd5631960d7cc8107088d374 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 07:11:13 +0000 +Subject: sched/fair: Clear rel_deadline when initializing forked entities + +From: Zicheng Qu + +[ Upstream commit 3da56dc063cd77b9c0b40add930767fab4e389f3 ] + +A yield-triggered crash can happen when a newly forked sched_entity +enters the fair class with se->rel_deadline unexpectedly set. + +The failing sequence is: + + 1. A task is forked while se->rel_deadline is still set. + 2. __sched_fork() initializes vruntime, vlag and other sched_entity + state, but does not clear rel_deadline. + 3. On the first enqueue, enqueue_entity() calls place_entity(). + 4. Because se->rel_deadline is set, place_entity() treats se->deadline + as a relative deadline and converts it to an absolute deadline by + adding the current vruntime. + 5. However, the forked entity's deadline is not a valid inherited + relative deadline for this new scheduling instance, so the conversion + produces an abnormally large deadline. + 6. If the task later calls sched_yield(), yield_task_fair() advances + se->vruntime to se->deadline. + 7. The inflated vruntime is then used by the following enqueue path, + where the vruntime-derived key can overflow when multiplied by the + entity weight. + 8. This corrupts cfs_rq->sum_w_vruntime, breaks EEVDF eligibility + calculation, and can eventually make all entities appear ineligible. + pick_next_entity() may then return NULL unexpectedly, leading to a + later NULL dereference. + +A captured trace shows the effect clearly. Before yield, the entity's +vruntime was around: + + 9834017729983308 + +After yield_task_fair() executed: + + se->vruntime = se->deadline + +the vruntime jumped to: + + 19668035460670230 + +and the deadline was later advanced further to: + + 19668035463470230 + +This shows that the deadline had already become abnormally large before +yield_task_fair() copied it into vruntime. + +rel_deadline is only meaningful when se->deadline really carries a +relative deadline that still needs to be placed against vruntime. A +freshly forked sched_entity should not inherit or retain this state. +Clear se->rel_deadline in __sched_fork(), together with the other +sched_entity runtime state, so that the first enqueue does not interpret +the new entity's deadline as a stale relative deadline. + +Fixes: 82e9d0456e06 ("sched/fair: Avoid re-setting virtual deadline on 'migrations'") +Analyzed-by: Hui Tang +Analyzed-by: Zhang Qiao +Signed-off-by: Zicheng Qu +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260424071113.1199600-1-quzicheng@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index df76b32a013fb..9b238c9c71c67 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -4453,6 +4453,7 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p) + p->se.nr_migrations = 0; + p->se.vruntime = 0; + p->se.vlag = 0; ++ p->se.rel_deadline = 0; + INIT_LIST_HEAD(&p->se.group_node); + + /* A delayed task cannot be in clone(). */ +-- +2.53.0 + diff --git a/queue-6.12/sched-psi-fix-race-between-file-release-and-pressure.patch b/queue-6.12/sched-psi-fix-race-between-file-release-and-pressure.patch new file mode 100644 index 0000000000..2e9c96be2b --- /dev/null +++ b/queue-6.12/sched-psi-fix-race-between-file-release-and-pressure.patch @@ -0,0 +1,184 @@ +From 381e2082e9eae7ccc71e3bfad2022de432ae07ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 14:15:43 +0800 +Subject: sched/psi: fix race between file release and pressure write + +From: Edward Adam Davis + +[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ] + +A potential race condition exists between pressure write and cgroup file +release regarding the priv member of struct kernfs_open_file, which +triggers the uaf reported in [1]. + +Consider the following scenario involving execution on two separate CPUs: + + CPU0 CPU1 + ==== ==== + vfs_rmdir() + kernfs_iop_rmdir() + cgroup_rmdir() + cgroup_kn_lock_live() + cgroup_destroy_locked() + cgroup_addrm_files() + cgroup_rm_file() + kernfs_remove_by_name() + kernfs_remove_by_name_ns() + vfs_write() __kernfs_remove() + new_sync_write() kernfs_drain() + kernfs_fop_write_iter() kernfs_drain_open_files() + cgroup_file_write() kernfs_release_file() + pressure_write() cgroup_file_release() + ctx = of->priv; + kfree(ctx); + of->priv = NULL; + cgroup_kn_unlock() + cgroup_kn_lock_live() + cgroup_get(cgrp) + cgroup_kn_unlock() + if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv + +The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards +the memory deallocation of of->priv performed within cgroup_file_release(). +However, the operations involving of->priv executed within pressure_write() +are not entirely covered by the protection of cgroup_mutex. Consequently, +if the code in pressure_write(), specifically the section handling the +ctx variable executes after cgroup_file_release() has completed, a uaf +vulnerability involving of->priv is triggered. + +Therefore, the issue can be resolved by extending the scope of the +cgroup_mutex lock within pressure_write() to encompass all code paths +involving of->priv, thereby properly synchronizing the race condition +occurring between cgroup_file_release() and pressure_write(). + +And, if an live kn lock can be successfully acquired while executing +the pressure write operation, it indicates that the cgroup deletion +process has not yet reached its final stage; consequently, the priv +pointer within open_file cannot be NULL. Therefore, the operation to +retrieve the ctx value must be moved to a point *after* the live kn +lock has been successfully acquired. + +In another situation, specifically after entering cgroup_kn_lock_live() +but before acquiring cgroup_mutex, there exists a different class of +race condition: + +CPU0: write memory.pressure CPU1: write cgroup.pressure=0 +=========================== ============================= + +kernfs_fop_write_iter() + kernfs_get_active_of(of) + pressure_write() + cgroup_kn_lock_live(memory.pressure) + cgroup_tryget(cgrp) + kernfs_break_active_protection(kn) + ... blocks on cgroup_mutex + + cgroup_pressure_write() + cgroup_kn_lock_live(cgroup.pressure) + cgroup_file_show(memory.pressure, false) + kernfs_show(false) + kernfs_drain_open_files() + cgroup_file_release(of) + kfree(ctx) + of->priv = NULL + cgroup_kn_unlock() + + ... acquires cgroup_mutex + ctx = of->priv; // may now be NULL + if (ctx->psi.trigger) // NULL dereference + +Consequently, there is a possibility that of->priv is NULL, the pressure +write needs to check for this. + +Now that the scope of the cgroup_mutex has been expanded, the original +explicit cgroup_get/put operations are no longer necessary, this is +because acquiring/releasing the live kn lock inherently executes a +cgroup get/put operation. + +[1] +BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 +Call Trace: + pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 + cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 + kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 + +Allocated by task 9352: + cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 + kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 + do_dentry_open+0x83d/0x13e0 fs/open.c:949 + +Freed by task 9353: + cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 + kernfs_release_file fs/kernfs/file.c:764 [inline] + kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 + kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525 + +Fixes: 0e94682b73bf ("psi: introduce psi monitor") +Reported-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=33e571025d88efd1312c +Tested-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Reviewed-by: Chen Ridong +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 046f671532b04..0914a1a189ee1 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -3876,33 +3876,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) + static ssize_t pressure_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, enum psi_res res) + { +- struct cgroup_file_ctx *ctx = of->priv; ++ struct cgroup_file_ctx *ctx; + struct psi_trigger *new; + struct cgroup *cgrp; + struct psi_group *psi; ++ ssize_t ret = 0; + + cgrp = cgroup_kn_lock_live(of->kn, false); + if (!cgrp) + return -ENODEV; + +- cgroup_get(cgrp); +- cgroup_kn_unlock(of->kn); ++ ctx = of->priv; ++ if (!ctx) { ++ ret = -ENODEV; ++ goto out_unlock; ++ } + + /* Allow only one trigger per file descriptor */ + if (ctx->psi.trigger) { +- cgroup_put(cgrp); +- return -EBUSY; ++ ret = -EBUSY; ++ goto out_unlock; + } + + psi = cgroup_psi(cgrp); + new = psi_trigger_create(psi, buf, res, of->file, of); + if (IS_ERR(new)) { +- cgroup_put(cgrp); +- return PTR_ERR(new); ++ ret = PTR_ERR(new); ++ goto out_unlock; + } + + smp_store_release(&ctx->psi.trigger, new); +- cgroup_put(cgrp); ++ ++out_unlock: ++ cgroup_kn_unlock(of->kn); ++ if (ret) ++ return ret; + + return nbytes; + } +-- +2.53.0 + diff --git a/queue-6.12/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch b/queue-6.12/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch new file mode 100644 index 0000000000..95ecfd6a59 --- /dev/null +++ b/queue-6.12/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch @@ -0,0 +1,45 @@ +From 97248b007b9926f70add512f429ad045b7e281f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:42 +0800 +Subject: scsi: sg: Fix sysctl sg-big-buff register during sg_init() + +From: Yang Erkun + +[ Upstream commit 3033c471aaf675254efaa0da431e95d91a104b41 ] + +Commit 26d1c80fd61e ("scsi/sg: move sg-big-buff sysctl to scsi/sg.c") made +a mistake. sysctl sg-big-buff was not created because the call to +register_sg_sysctls() was placed on the wrong code path. + +Fixes: 26d1c80fd61e ("scsi/sg: move sg-big-buff sysctl to scsi/sg.c") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-2-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 53dd461508494..0100a2828f803 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1691,13 +1691,13 @@ init_sg(void) + sg_sysfs_valid = 1; + rc = scsi_register_interface(&sg_interface); + if (0 == rc) { ++ register_sg_sysctls(); + #ifdef CONFIG_SCSI_PROC_FS + sg_proc_init(); + #endif /* CONFIG_SCSI_PROC_FS */ + return 0; + } + class_unregister(&sg_sysfs_class); +- register_sg_sysctls(); + err_out: + unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); + return rc; +-- +2.53.0 + diff --git a/queue-6.12/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch b/queue-6.12/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch new file mode 100644 index 0000000000..ed2583e2c8 --- /dev/null +++ b/queue-6.12/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch @@ -0,0 +1,100 @@ +From 985c89e4044d13d758b5cd380bb6ef870ed7c7e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:43 +0800 +Subject: scsi: sg: Resolve soft lockup issue when opening /dev/sgX + +From: Yang Erkun + +[ Upstream commit d06a310b45e153872033dd0cf19d5a2279121099 ] + +The parameter def_reserved_size defines the default buffer size reserved +for each Sg_fd and should be restricted to a range between 0 and 1,048,576 +(see https://tldp.org/HOWTO/SCSI-Generic-HOWTO/proc.html). Although the +function sg_proc_write_dressz enforces this limit, it is possible to bypass +it by directly modifying the module parameter as shown below, which then +causes a soft lockup: + +echo -1 > /sys/module/sg/parameters/def_reserved_size +exec 4<> /dev/sg0 + +watchdog: BUG: soft lockup - CPU#5 stuck for 26 seconds! [bash:537] +Modules loaded: +CPU: 5 UID: 0 PID: 537 Command: bash, kernel version 6.19.0-rc3+ #134, +PREEMPT disabled +Hardware: QEMU Standard PC (i440FX + PIIX, 1996), BIOS version +1.16.1-2.fc37 dated 04/01/2014 +... +Call Trace: + + sg_build_reserve+0x5c/0xa0 + sg_add_sfp+0x168/0x270 + sg_open+0x16e/0x340 + chrdev_open+0xbe/0x230 + do_dentry_open+0x175/0x480 + vfs_open+0x34/0xf0 + do_open+0x265/0x3d0 + path_openat+0x110/0x290 + do_filp_open+0xc3/0x170 + do_sys_openat2+0x71/0xe0 + __x64_sys_openat+0x6d/0xa0 + do_syscall_64+0x62/0x310 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The fix is to use module_param_cb to validate and reject invalid values +assigned to def_reserved_size. + +Fixes: 6460e75a104d ("[SCSI] sg: fixes for large page_size") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-3-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 0100a2828f803..f85a52e9a7a7f 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1622,10 +1622,35 @@ sg_remove_device(struct device *cl_dev) + } + + module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +-module_param_named(def_reserved_size, def_reserved_size, int, +- S_IRUGO | S_IWUSR); + module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); + ++static int def_reserved_size_set(const char *val, const struct kernel_param *kp) ++{ ++ int size, ret; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtoint(val, 0, &size); ++ if (ret) ++ return ret; ++ ++ /* limit to 1 MB */ ++ if (size < 0 || size > 1048576) ++ return -ERANGE; ++ ++ def_reserved_size = size; ++ return 0; ++} ++ ++static const struct kernel_param_ops def_reserved_size_ops = { ++ .set = def_reserved_size_set, ++ .get = param_get_int, ++}; ++ ++module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, ++ S_IRUGO | S_IWUSR); ++ + MODULE_AUTHOR("Douglas Gilbert"); + MODULE_DESCRIPTION("SCSI generic (sg) driver"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.12/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch b/queue-6.12/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch new file mode 100644 index 0000000000..c9edde6911 --- /dev/null +++ b/queue-6.12/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch @@ -0,0 +1,42 @@ +From 1158d2783ad9bbd028eea47ef3f36052b8022e25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 23:42:58 +0800 +Subject: scsi: target: core: Fix integer overflow in UNMAP bounds check + +From: Junrui Luo + +[ Upstream commit 2bf2d65f76697820dbc4227d13866293576dd90a ] + +sbc_execute_unmap() checks LBA + range does not exceed the device capacity, +but does not guard against LBA + range wrapping around on 64-bit overflow. + +Add an overflow check matching the pattern already used for WRITE_SAME in +the same file. + +Fixes: 86d7182985d2 ("target: Add sbc_execute_unmap() helper") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881593C61AD52C69FBDB0BDAF7CA@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/target/target_core_sbc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c +index fe8beb7dbab12..4c828a3ac18c7 100644 +--- a/drivers/target/target_core_sbc.c ++++ b/drivers/target/target_core_sbc.c +@@ -1136,7 +1136,8 @@ sbc_execute_unmap(struct se_cmd *cmd) + goto err; + } + +- if (lba + range > dev->transport->get_blocks(dev) + 1) { ++ if (lba + range < lba || ++ lba + range > dev->transport->get_blocks(dev) + 1) { + ret = TCM_ADDRESS_OUT_OF_RANGE; + goto err; + } +-- +2.53.0 + diff --git a/queue-6.12/sctp-discard-stale-init-after-handshake-completion.patch b/queue-6.12/sctp-discard-stale-init-after-handshake-completion.patch new file mode 100644 index 0000000000..90a7789253 --- /dev/null +++ b/queue-6.12/sctp-discard-stale-init-after-handshake-completion.patch @@ -0,0 +1,49 @@ +From ce3d06514ba92453a6947f5a09d4eb65a3ef153c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:41 -0400 +Subject: sctp: discard stale INIT after handshake completion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Xin Long + +[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ] + +After an association reaches ESTABLISHED, the peer’s init_tag is already +known from the handshake. Any subsequent INIT with the same init_tag is +not a valid restart, but a delayed or duplicate INIT. + +Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of +processing them as new association attempts. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/5788c76c1ee122a3ed00189e88dcf9df1fba226c.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 966bd6a44594a..376d4ce5ebb3c 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( + /* Tag the variable length parameters. */ + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); + ++ if (asoc->state >= SCTP_STATE_ESTABLISHED) { ++ /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ ++ if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) ++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ } ++ + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, +-- +2.53.0 + diff --git a/queue-6.12/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch b/queue-6.12/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch new file mode 100644 index 0000000000..70684e40a4 --- /dev/null +++ b/queue-6.12/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch @@ -0,0 +1,44 @@ +From 575bfc390265c08f356df303e8088bb5956e6e8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 14:13:51 -0400 +Subject: sctp: fix missing encap_port propagation for GSO fragments + +From: Xin Long + +[ Upstream commit bf6f95ae3b8b2638c0e1d6d802d50983ce5d0f45 ] + +encap_port in SCTP_INPUT_CB(skb) is used by sctp_vtag_verify() for +SCTP-over-UDP processing. In the GSO case, it is only set on the head +skb, while fragment skbs leave it 0. + +This results in fragment skbs seeing encap_port == 0, breaking +SCTP-over-UDP connections. + +Fix it by propagating encap_port from the head skb cb when initializing +fragment skbs in sctp_inq_pop(). + +Fixes: 046c052b475e ("sctp: enable udp tunneling socks") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/ea65ed61b3598d8b4940f0170b9aa1762307e6c3.1776017631.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/inqueue.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c +index f5a7d5a387555..a024c08432471 100644 +--- a/net/sctp/inqueue.c ++++ b/net/sctp/inqueue.c +@@ -201,6 +201,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + + cb->chunk = head_cb->chunk; + cb->af = head_cb->af; ++ cb->encap_port = head_cb->encap_port; + } + } + +-- +2.53.0 + diff --git a/queue-6.12/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch b/queue-6.12/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch new file mode 100644 index 0000000000..0f1b30a6de --- /dev/null +++ b/queue-6.12/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch @@ -0,0 +1,68 @@ +From 7ac1a8805159c463671bbd52d13bb42de9eaf47e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 23:19:03 -0400 +Subject: sctp: fix OOB write to userspace in sctp_getsockopt_peer_auth_chunks + +From: Michael Bommarito + +[ Upstream commit 0cf004ffb61cd32d140531c3a84afe975f9fc7ea ] + +sctp_getsockopt_peer_auth_chunks() checks that the caller's optval +buffer is large enough for the peer AUTH chunk list with + + if (len < num_chunks) + return -EINVAL; + +but then writes num_chunks bytes to p->gauth_chunks, which lives +at offset offsetof(struct sctp_authchunks, gauth_chunks) == 8 +inside optval. The check is missing the sizeof(struct +sctp_authchunks) = 8-byte header. When the caller supplies +len == num_chunks (for any num_chunks > 0) the test passes but +copy_to_user() writes sizeof(struct sctp_authchunks) = 8 bytes +past the declared buffer. + +The sibling function sctp_getsockopt_local_auth_chunks() at the +next line already has the correct check: + + if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + +Align the peer variant with its sibling. + +Reproducer confirms on v7.0-13-generic: an unprivileged userspace +caller that opens a loopback SCTP association with AUTH enabled, +queries num_chunks with a short optval, then issues the real +getsockopt with len == num_chunks and sentinel bytes painted past +the buffer observes those sentinel bytes overwritten with the +peer's AUTH chunk type. The bytes written are under the peer's +control but land in the caller's own userspace; this is not a +kernel memory corruption, but it is a kernel-side contract +violation that can silently corrupt adjacent userspace data. + +Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260416031903.1447072-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index c8038b4b67c71..6b562dd1aae11 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -7003,7 +7003,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, + + /* See if the user provided enough room for all the data */ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); +- if (len < num_chunks) ++ if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + + if (copy_to_user(to, ch->chunks, num_chunks)) +-- +2.53.0 + diff --git a/queue-6.12/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch b/queue-6.12/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch new file mode 100644 index 0000000000..3c0b724789 --- /dev/null +++ b/queue-6.12/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch @@ -0,0 +1,75 @@ +From 0341bcf562fd162bc4322bddd5dd64d4349eb735 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 16:05:26 -0400 +Subject: selftest: memcg: skip memcg_sock test if address family not supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Waiman Long + +[ Upstream commit 2d028f3e4bbbfd448928a8d3d2814b0b04c214f4 ] + +The test_memcg_sock test in memcontrol.c sets up an IPv6 socket and send +data over it to consume memory and verify that memory.stat.sock and +memory.current values are close. + +On systems where IPv6 isn't enabled or not configured to support +SOCK_STREAM, the test_memcg_sock test always fails. When the socket() +call fails, there is no way we can test the memory consumption and verify +the above claim. I believe it is better to just skip the test in this +case instead of reporting a test failure hinting that there may be +something wrong with the memcg code. + +Link: https://lkml.kernel.org/r/20260311200526.885899-1-longman@redhat.com +Fixes: 5f8f019380b8 ("selftests: cgroup/memcontrol: add basic test for socket accounting") +Signed-off-by: Waiman Long +Acked-by: Michal Koutný +Acked-by: Shakeel Butt +Cc: Johannes Weiner +Cc: Michal Hocko +Cc: Michal Koutný +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Roman Gushchin +Cc: Shuah Khan +Cc: Tejun Heo +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/cgroup/test_memcontrol.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c +index 16f5d74ae762e..7a44d221b8c4b 100644 +--- a/tools/testing/selftests/cgroup/test_memcontrol.c ++++ b/tools/testing/selftests/cgroup/test_memcontrol.c +@@ -1190,8 +1190,11 @@ static int tcp_server(const char *cgroup, void *arg) + saddr.sin6_port = htons(srv_args->port); + + sk = socket(AF_INET6, SOCK_STREAM, 0); +- if (sk < 0) ++ if (sk < 0) { ++ /* Pass back errno to the ctl_fd */ ++ write(ctl_fd, &errno, sizeof(errno)); + return ret; ++ } + + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + goto cleanup; +@@ -1321,6 +1324,12 @@ static int test_memcg_sock(const char *root) + goto cleanup; + close(args.ctl[0]); + ++ /* Skip if address family not supported by protocol */ ++ if (err == EAFNOSUPPORT) { ++ ret = KSFT_SKIP; ++ goto cleanup; ++ } ++ + if (!err) + break; + if (err != EADDRINUSE) +-- +2.53.0 + diff --git a/queue-6.12/selftests-bpf-fix-__jited_unpriv-tag-name.patch b/queue-6.12/selftests-bpf-fix-__jited_unpriv-tag-name.patch new file mode 100644 index 0000000000..50e30c431c --- /dev/null +++ b/queue-6.12/selftests-bpf-fix-__jited_unpriv-tag-name.patch @@ -0,0 +1,39 @@ +From 51d1720477dd0328dd91196227eb9b58c2f41692 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 00:33:44 -0700 +Subject: selftests/bpf: fix __jited_unpriv tag name + +From: Eduard Zingerman + +[ Upstream commit cdd54fe98c00549264a92613af6bb0e9a5fd0d1c ] + +__jited_unpriv was using "test_jited=" as its tag name, same as the +priv variant __jited. Fix by using "test_jited_unpriv=". + +Fixes: 7d743e4c759c ("selftests/bpf: __jited test tag to check disassembly after jit") +Acked-by: Ihor Solodrai +Reviewed-by: Puranjay Mohan +Signed-off-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260410-selftests-global-tags-ordering-v2-1-c566ec9781bf@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/progs/bpf_misc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h +index eccaf955e3947..9c0d71f0b3cc3 100644 +--- a/tools/testing/selftests/bpf/progs/bpf_misc.h ++++ b/tools/testing/selftests/bpf/progs/bpf_misc.h +@@ -115,7 +115,7 @@ + #define __description(desc) __attribute__((btf_decl_tag("comment:test_description=" desc))) + #define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" XSTR(__COUNTER__) "=" msg))) + #define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" XSTR(__COUNTER__) "=" msg))) +-#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited=" XSTR(__COUNTER__) "=" msg))) ++#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited_unpriv=" XSTR(__COUNTER__) "=" msg))) + #define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv"))) + #define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv"))) + #define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl))) +-- +2.53.0 + diff --git a/queue-6.12/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch b/queue-6.12/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch new file mode 100644 index 0000000000..6516b6f1e7 --- /dev/null +++ b/queue-6.12/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch @@ -0,0 +1,58 @@ +From 49848298ac8276630429dfa576452dd4a8f1a94e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:39:41 -0500 +Subject: selftests/mm: skip migration tests if NUMA is unavailable + +From: AnishMulay + +[ Upstream commit 54218f10dfbe88c8e41c744fd45a756cde60b8c4 ] + +Currently, the migration test asserts that numa_available() returns 0. On +systems where NUMA is not available (returning -1), such as certain ARM64 +configurations or single-node systems, this assertion fails and crashes +the test. + +Update the test to check the return value of numa_available(). If it is +less than 0, skip the test gracefully instead of failing. + +This aligns the behavior with other MM selftests (like rmap) that skip +when NUMA support is missing. + +Link: https://lkml.kernel.org/r/20260218163941.13499-1-anishm7030@gmail.com +Fixes: 0c2d08728470 ("mm: add selftests for migration entries") +Signed-off-by: AnishMulay +Reviewed-by: SeongJae Park +Reviewed-by: Dev Jain +Reviewed-by: Anshuman Khandual +Tested-by: Sayali Patil +Acked-by: David Hildenbrand (Arm) +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/migration.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c +index 64bcbb7151cff..c883ef420d3ba 100644 +--- a/tools/testing/selftests/mm/migration.c ++++ b/tools/testing/selftests/mm/migration.c +@@ -33,7 +33,8 @@ FIXTURE_SETUP(migration) + { + int n; + +- ASSERT_EQ(numa_available(), 0); ++ if (numa_available() < 0) ++ SKIP(return, "NUMA not available"); + self->nthreads = numa_num_task_cpus() - 1; + self->n1 = -1; + self->n2 = -1; +-- +2.53.0 + diff --git a/queue-6.12/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch b/queue-6.12/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch new file mode 100644 index 0000000000..289c8a64ca --- /dev/null +++ b/queue-6.12/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch @@ -0,0 +1,86 @@ +From 7f40c523e95e8b80970b5860f37c4dea920fe83c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:45:02 +0200 +Subject: selftests: netfilter: nft_tproxy.sh: adjust to socat changes + +From: Florian Westphal + +[ Upstream commit 61119542663cac70898aef532eb57ee41ea9b477 ] + +Like e65d8b6f3092 ("selftests: drv-net: adjust to socat changes") we +need to add shut-none for this test too. + +The extra 0-packet can trigger a second (unexpected) reply from the server. + +Fixes: 7e37e0eacd22 ("selftests: netfilter: nft_tproxy.sh: add tcp tests") +Reported-by: Jakub Kicinski +Closes: https://lore.kernel.org/netdev/20260408152432.24b8ad0d@kernel.org/ +Suggested-by: Jakub Kicinski +Signed-off-by: Florian Westphal +Link: https://patch.msgid.link/20260409224506.27072-1-fw@strlen.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../selftests/net/netfilter/nft_tproxy_udp.sh | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh b/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh +index d16de13fe5a75..1dc7b04501459 100755 +--- a/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh ++++ b/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh +@@ -190,13 +190,13 @@ table inet filter { + } + EOF + +- timeout "$timeout" ip netns exec "$nsrouter" socat -u "$socat_ipproto" udp-listen:12345,fork,ip-transparent,reuseport udp:"$ns1_ip_port",ip-transparent,reuseport,bind="$ns2_ip_port" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$nsrouter" socat -u "$socat_ipproto" udp-listen:12345,fork,ip-transparent,reuseport,shut-none udp:"$ns1_ip_port",ip-transparent,reuseport,bind="$ns2_ip_port",shut-none 2>/dev/null & + local tproxy_pid=$! + +- timeout "$timeout" ip netns exec "$ns2" socat "$socat_ipproto" udp-listen:8080,fork SYSTEM:"echo PONG_NS2" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$ns2" socat "$socat_ipproto" udp-listen:8080,fork,shut-none SYSTEM:"echo PONG_NS2" 2>/dev/null & + local server2_pid=$! + +- timeout "$timeout" ip netns exec "$ns3" socat "$socat_ipproto" udp-listen:8080,fork SYSTEM:"echo PONG_NS3" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$ns3" socat "$socat_ipproto" udp-listen:8080,fork,shut-none SYSTEM:"echo PONG_NS3" 2>/dev/null & + local server3_pid=$! + + busywait "$BUSYWAIT_TIMEOUT" listener_ready "$nsrouter" 12345 "-u" +@@ -205,7 +205,7 @@ EOF + + local result + # request from ns1 to ns2 (forwarded traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",sourceport=18888) ++ result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",sourceport=18888,shut-none) + if [ "$result" == "$expect_ns1_ns2" ] ;then + echo "PASS: tproxy test $testname: ns1 got reply \"$result\" connecting to ns2" + else +@@ -214,7 +214,7 @@ EOF + fi + + # request from ns1 to ns3 (forwarded traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port",shut-none) + if [ "$result" = "$expect_ns1_ns3" ] ;then + echo "PASS: tproxy test $testname: ns1 got reply \"$result\" connecting to ns3" + else +@@ -223,7 +223,7 @@ EOF + fi + + # request from nsrouter to ns2 (localy originated traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",shut-none) + if [ "$result" == "$expect_nsrouter_ns2" ] ;then + echo "PASS: tproxy test $testname: nsrouter got reply \"$result\" connecting to ns2" + else +@@ -232,7 +232,7 @@ EOF + fi + + # request from nsrouter to ns3 (localy originated traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port",shut-none) + if [ "$result" = "$expect_nsrouter_ns3" ] ;then + echo "PASS: tproxy test $testname: nsrouter got reply \"$result\" connecting to ns3" + else +-- +2.53.0 + diff --git a/queue-6.12/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch b/queue-6.12/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch new file mode 100644 index 0000000000..b214d79a36 --- /dev/null +++ b/queue-6.12/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch @@ -0,0 +1,87 @@ +From c5f4597fd37cc609c6a024a650402eaf6da3251c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:24:26 +0530 +Subject: selftests/powerpc: Suppress -Wmaybe-uninitialized with GCC 15 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Amit Machhiwal + +[ Upstream commit 6e65886fceb23605eff952d6b1975737b4c4b154 ] + +GCC 15 reports the below false positive '-Wmaybe-uninitialized' warning +in vphn_unpack_associativity() when building the powerpc selftests. + + # make -C tools/testing/selftests TARGETS="powerpc" + [...] + CC test-vphn + In file included from test-vphn.c:3: + In function ‘vphn_unpack_associativity’, + inlined from ‘test_one’ at test-vphn.c:371:2, + inlined from ‘test_vphn’ at test-vphn.c:399:9: + test-vphn.c:10:33: error: ‘be_packed’ may be used uninitialized [-Werror=maybe-uninitialized] + 10 | #define be16_to_cpup(x) bswap_16(*x) + | ^~~~~~~~ + vphn.c:42:27: note: in expansion of macro ‘be16_to_cpup’ + 42 | u16 new = be16_to_cpup(field++); + | ^~~~~~~~~~~~ + In file included from test-vphn.c:19: + vphn.c: In function ‘test_vphn’: + vphn.c:27:16: note: ‘be_packed’ declared here + 27 | __be64 be_packed[VPHN_REGISTER_COUNT]; + | ^~~~~~~~~ + cc1: all warnings being treated as errors + +When vphn_unpack_associativity() is called from hcall_vphn() in kernel +the error is not seen while building vphn.c during kernel compilation. +This is because the top level Makefile includes '-fno-strict-aliasing' +flag always. + +The issue here is that GCC 15 emits '-Wmaybe-uninitialized' due to type +punning between __be64[] and __b16* when accessing the buffer via +be16_to_cpup(). The underlying object is fully initialized but GCC 15 +fails to track the aliasing due to the strict aliasing violation here. +Please refer [1] and [2]. This results in a false positive warning which +is promoted to an error under '-Werror'. This problem is not seen when +the compilation is performed with GCC 13 and 14. An issue [1] has also +been created on GCC bugzilla. + +The selftest compiles fine with '-fno-strict-aliasing'. Since this GCC +flag is used to compile vphn.c in kernel too, the same flag should be +used to build vphn tests when compiling vphn.c in the selftest as well. + +Fix this by including '-fno-strict-aliasing' during vphn.c compilation +in the selftest. This keeps the build working while limiting the scope +of the suppression to building vphn tests. + +[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124427 +[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99768 + +Fixes: 58dae82843f5 ("selftests/powerpc: Add test for VPHN") +Reviewed-by: Vaibhav Jain +Signed-off-by: Amit Machhiwal +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260313165426.43259-1-amachhiw@linux.ibm.com +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/powerpc/vphn/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/powerpc/vphn/Makefile b/tools/testing/selftests/powerpc/vphn/Makefile +index 61d519a076c6f..778fc396340db 100644 +--- a/tools/testing/selftests/powerpc/vphn/Makefile ++++ b/tools/testing/selftests/powerpc/vphn/Makefile +@@ -5,7 +5,7 @@ top_srcdir = ../../../../.. + include ../../lib.mk + include ../flags.mk + +-CFLAGS += -m64 -I$(CURDIR) ++CFLAGS += -m64 -I$(CURDIR) -fno-strict-aliasing + + $(TEST_GEN_PROGS): ../harness.c + +-- +2.53.0 + diff --git a/queue-6.12/selftests-sched_ext-add-missing-error-check-for-exit.patch b/queue-6.12/selftests-sched_ext-add-missing-error-check-for-exit.patch new file mode 100644 index 0000000000..927d8af5d1 --- /dev/null +++ b/queue-6.12/selftests-sched_ext-add-missing-error-check-for-exit.patch @@ -0,0 +1,38 @@ +From 3d11c5722b11f19daf5c01ff5f1617297c248303 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 05:17:55 +0000 +Subject: selftests/sched_ext: Add missing error check for exit__load() + +From: David Carlier + +[ Upstream commit 1d02346fec8d13b05e54296ddc6ae29b7e1067df ] + +exit__load(skel) was called without checking its return value. +Every other test in the suite wraps the load call with +SCX_FAIL_IF(). Add the missing check to be consistent with the +rest of the test suite. + +Fixes: a5db7817af78 ("sched_ext: Add selftests") +Signed-off-by: David Carlier +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/sched_ext/exit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/sched_ext/exit.c b/tools/testing/selftests/sched_ext/exit.c +index 2c084ded29680..b4a8dd630b550 100644 +--- a/tools/testing/selftests/sched_ext/exit.c ++++ b/tools/testing/selftests/sched_ext/exit.c +@@ -32,7 +32,7 @@ static enum scx_test_status run(void *ctx) + + skel = exit__open(); + skel->rodata->exit_point = tc; +- exit__load(skel); ++ SCX_FAIL_IF(exit__load(skel), "Failed to load skel"); + link = bpf_map__attach_struct_ops(skel->maps.exit_ops); + if (!link) { + SCX_ERR("Failed to attach scheduler"); +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series new file mode 100644 index 0000000000..afdc7ec0a1 --- /dev/null +++ b/queue-6.12/series @@ -0,0 +1,593 @@ +blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch +fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch +fs-mbcache-cancel-shrink-work-before-destroying-the-.patch +md-raid1-fix-the-comparing-region-of-interval-tree.patch +drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch +loop-fix-partition-scan-race-between-udev-and-loop_r.patch +nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch +blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch +pstore-ram-fix-resource-leak-when-ioremap-fails.patch +erofs-verify-metadata-accesses-for-file-backed-mount.patch +md-wake-raid456-reshape-waiters-before-suspend.patch +btrfs-pass-struct-btrfs_inode-to-clone_copy_inline_e.patch +btrfs-fix-deadlock-between-reflink-and-transaction-c.patch +acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch +acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch +devres-fix-missing-node-debug-info-in-devm_krealloc.patch +thermal-drivers-spear-fix-error-condition-for-readin.patch +debugfs-check-for-null-pointer-in-debugfs_create_str.patch +debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch +soundwire-debugfs-initialize-firmware_file-to-empty-.patch +pci-use-generic-driver_override-infrastructure.patch +platform-wmi-use-generic-driver_override-infrastruct.patch +s390-cio-use-generic-driver_override-infrastructure.patch +bus-fsl-mc-use-generic-driver_override-infrastructur.patch +irqchip-irq-pic32-evic-address-warning-related-to-wr.patch +hrtimers-update-the-return-type-of-enqueue_hrtimer.patch +hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch +hrtimer-reduce-trace-noise-in-hrtimer_start.patch +sparc-vdso-always-reject-undefined-references-during.patch +sparc64-vdso-link-with-z-noexecstack.patch +locking-fix-rwlock-support-in-linux-spinlock_up.h.patch +firmware-dmi-correct-an-indexing-error-in-dmi.h.patch +wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch +wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch +bpf-test_run-fix-the-null-pointer-dereference-issue-.patch +dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch +dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch +s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch +params-replace-__modinit-with-__init_or_module.patch +module-fix-freeing-of-charp-module-parameters-when-c.patch +wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch +wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch +wifi-mt76-mt7615-fix-use_cts_prot-support.patch +wifi-mt76-mt7915-fix-use_cts_prot-support.patch +wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch +wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch +wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch +wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch +arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch +wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch +wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch +wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch +wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch +bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch +bpf-fix-variable-length-stack-write-over-spilled-poi.patch +bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch +wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch +r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch +powerpc-crash-fix-backup-region-offset-update-to-elf.patch +powerpc-crash-update-backup-region-offset-in-elfcore.patch +selftests-powerpc-suppress-wmaybe-uninitialized-with.patch +macvlan-annotate-data-races-around-port-bc_queue_len.patch +bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch +bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch +wifi-brcmfmac-fix-error-pointer-dereference.patch +wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch +bpf-drop-task_to_inode-and-inet_conn_established-fro.patch +bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch +wifi-ath10k-fix-station-lookup-failure-during-discon.patch +acpi-agdi-fix-missing-newline-in-error-message.patch +arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch +net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch +net-bcmgenet-add-bcmgenet_has_-helpers.patch +net-bcmgenet-move-desc_index-flow-to-ring-0.patch +net-bcmgenet-support-reclaiming-unsent-tx-packets.patch +net-bcmgenet-switch-to-use-64bit-statistics.patch +net-bcmgenet-fix-racing-timeout-handler.patch +eth-fbnic-use-wake-instead-of-start.patch +netfilter-xt_socket-enable-defrag-after-all-other-ch.patch +netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch +bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch +bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch +bpf-return-vma-snapshot-from-task_vma-iterator.patch +bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch +net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch +bpf-relax-scalar-id-equivalence-for-state-pruning.patch +bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch +selftests-bpf-fix-__jited_unpriv-tag-name.patch +net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch +selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch +net-airoha-implement-bql-support.patch +net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch +bpf-allow-instructions-with-arena-source-and-non-are.patch +net-rds-optimize-rds_ib_laddr_check.patch +net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch +bpf-fix-oob-in-pcpu_init_value.patch +ppp-require-cap_net_admin-in-target-netns-for-unatta.patch +net-ipa-fix-programming-of-qtime_timestamp_cfg.patch +net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch +dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch +net-phy-fix-a-return-path-in-get_phy_c45_ids.patch +net-mlx5e-fix-features-not-applied-during-netdev-reg.patch +net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch +bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch +bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch +bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch +bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch +bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch +bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch +net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch +ipv4-udp-fix-typos-in-comments.patch +ipv6-udp-fix-typos-in-comments.patch +udp-force-compute_score-to-always-inline.patch +tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch +sctp-fix-missing-encap_port-propagation-for-gso-frag.patch +net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch +drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch +asoc-sof-ipc3-use-standard-dev_dbg-api.patch +asoc-add-symmetric_-prefix-for-dai-rate-channels-sam.patch +asoc-soc-compress-use-function-to-clear-symmetric-pa.patch +drm-sun4i-backend-fix-error-pointer-dereference.patch +asoc-sti-return-errors-from-regmap_field_alloc.patch +asoc-sti-use-managed-regmap_field-allocations.patch +dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch +dm-cache-fix-write-path-cache-coherency-in-passthrou.patch +dm-cache-fix-write-hang-in-passthrough-mode.patch +dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch +dm-cache-fix-concurrent-write-failure-in-passthrough.patch +dm-cache-support-shrinking-the-origin-device.patch +dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch +platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch +pci-endpoint-align-pci_epc_set_msix-pci_epc_ops-set_.patch +pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch +pci-dwc-invoke-post_init-in-dw_pcie_resume_noirq.patch +pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch +dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch +dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch +drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch +drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch +drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch +spi-spi-nxp-fspi-enable-runtime-pm-for-fspi.patch +spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch +spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch +media-i2c-og01a1b-replace-client-dev-usage.patch +media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch +selftests-sched_ext-add-missing-error-check-for-exit.patch +drm-v3d-handle-error-from-drm_sched_entity_init.patch +drm-sun4i-fix-resource-leaks.patch +drm-amdgpu-add-default-case-in-dvi-mode-validation.patch +dm-init-ensure-device-probing-has-finished-in-dm-mod.patch +fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch +crypto-tegra-finalize-crypto-req-on-error.patch +crypto-tegra-transfer-hash-init-function-to-crypto-e.patch +crypto-tegra-reserve-keyslots-to-allocate-dynamicall.patch +crypto-tegra-disable-softirqs-before-finalizing-requ.patch +crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch +crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch +padata-remove-cpu-online-check-from-cpu-add-and-remo.patch +padata-put-cpu-offline-callback-in-online-section-to.patch +pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch +drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch +drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch +spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch +drm-imagination-switch-reset_reason-fields-from-enum.patch +iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch +drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch +drm-msm-dsi-add-the-missing-parameter-description.patch +drm-msm-dsi-fix-bits_per_pclk.patch +drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch +drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch +drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch +drm-panel-simple-correct-g190ean01-prepare-timing.patch +pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch +alsa-core-validate-compress-device-numbers-without-d.patch +drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch +drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch +drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch +drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch +drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch +drm-amd-pm-ci-fill-dw8-fields-from-smc.patch +drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch +drm-amdgpu-add-amdgpu_device-reference-in-ip-block.patch +drm-amdgpu-update-the-handle-ptr-in-dump_ip_state.patch +drm-amdgpu-update-the-handle-ptr-in-early_init.patch +drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch +hwmon-switch-back-to-struct-platform_driver-remove.patch +hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch +alsa-hda-realtek-fix-code-style-error-else-should-fo.patch +asoc-sof-intel-hda-place-check-before-dereference.patch +drm-msm-a6xx-fix-hlsq-register-dumping.patch +drm-msm-shrinker-fix-can_block-logic.patch +drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch +drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch +pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch +pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch +pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch +asoc-fsl_micfil-add-access-property-for-vad-detected.patch +asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch +asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch +asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch +asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch +asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch +iommu-amd-remove-protection_domain.dev_cnt-variable.patch +iommu-amd-xarray-to-track-protection_domain-iommu-li.patch +iommu-amd-do-not-detach-devices-in-domain-free-path.patch +iommu-amd-reduce-domain-lock-scope-in-attach-device-.patch +iommu-amd-rearrange-attach-device-code.patch +iommu-amd-convert-dev_data-lock-from-spinlock-to-mut.patch +iommu-amd-introduce-helper-function-to-update-256-bi.patch +iommu-amd-introduce-helper-function-get_dte256.patch +iommu-amd-fix-clone_alias-to-use-the-original-device.patch +asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch +crypto-qat-introduce-fuse-array.patch +crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch +crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch +crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch +crypto-qat-use-swab32-macro.patch +asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch +pci-enable-atomicops-only-if-root-port-supports-them.patch +pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch +selftests-mm-skip-migration-tests-if-numa-is-unavail.patch +documentation-fix-a-hugetlbfs-reservation-statement.patch +selftest-memcg-skip-memcg_sock-test-if-address-famil.patch +alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch +asoc-sof-compress-return-the-configured-codec-from-g.patch +pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch +pci-tegra194-fix-polling-delay-for-l2-state.patch +pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch +pci-tegra194-disable-ltssm-after-transition-to-detec.patch +pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch +pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch +pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch +pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch +pci-tegra194-disable-direct-speed-change-for-endpoin.patch +pci-tegra194-set-ltr-message-request-before-pcie-lin.patch +pci-tegra194-allow-system-suspend-when-the-endpoint-.patch +pci-tegra194-free-up-endpoint-resources-during-remov.patch +pci-tegra194-use-dwc-ip-core-version.patch +pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch +pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch +spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch +alsa-sc6000-keep-the-programmed-board-state-in-card-.patch +dm-cache-fix-missing-return-in-invalidate_committed-.patch +crypto-jitterentropy-replace-long-held-spinlock-with.patch +alsa-hda-realtek-fixed-speaker-no-sound-update.patch +gfs2-call-unlock_new_inode-before-d_instantiate.patch +net-socket.c-switch-to-class-fd.patch +fdget-trivial-conversions.patch +fanotify-call-fanotify_events_supported-before-path_.patch +ktest-avoid-undef-warning-when-warnings_file-is-unse.patch +ktest-honor-empty-per-test-option-overrides.patch +ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch +quota-fix-race-of-dquot_scan_active-with-quota-deact.patch +gfs2-add-some-missing-log-locking.patch +gfs2-prevent-null-pointer-dereference-during-unmount.patch +efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch +ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch +arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch +arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch +memory-tegra124-emc-fix-dll_change-check.patch +memory-tegra30-emc-fix-dll_change-check.patch +arm64-dts-imx8-apalis-fix-leds-name-collision.patch +arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch +arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch +iommufd-vfio-compatibility-extension-check-for-noiom.patch +arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch +arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch +arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch +arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch +arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch +arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch +arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch +arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch +soc-qcom-ocmem-make-the-core-clock-optional.patch +soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch +soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch +bus-rifsc-fix-rif-configuration-check-for-peripheral.patch +arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch +arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch +arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch +arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch +arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch +arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch +arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch +arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch +arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch +arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch +arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch +arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch +arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch +arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch +arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch +arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch +soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch +unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch +ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch +ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch +soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch +soc-qcom-aoss-compare-against-normalized-cooling-sta.patch +arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch +arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch +arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch +arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch +firmware-arm_ffa-use-the-correct-buffer-size-during-.patch +ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch +ocfs2-validate-bg_bits-during-freefrag-scan.patch +ocfs2-validate-group-add-input-before-caching.patch +dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch +soundwire-bus-demote-unattached-state-warnings-to-de.patch +dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch +soundwire-cadence-clear-message-complete-before-sign.patch +tracing-rebuild-full_name-on-each-hist_field_name-ca.patch +hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch +remoteproc-xlnx-fix-sram-property-parsing.patch +ima-check-return-value-of-crypto_shash_final-in-boot.patch +hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch +hid-asus-do-not-abort-probe-when-not-necessary.patch +mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch +ima_fs-don-t-bother-with-removal-of-files-in-directo.patch +ima_fs-get-rid-of-lookup-by-dentry-stuff.patch +ima_fs-correctly-create-securityfs-files-for-unsuppo.patch +dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch +mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch +mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch +mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch +mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch +mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch +mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch +mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch +cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch +mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch +hid-usbhid-fix-deadlock-in-hid_post_reset.patch +ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch +bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch +bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch +bpf-sockmap-fix-af_unix-iter-deadlock.patch +bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch +bpf-sockmap-take-state-lock-for-af_unix-iter.patch +bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch +bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch +bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch +libbpf-change-log-level-of-btf-loading-error-message.patch +libbpf-stringify-errno-in-log-messages-in-libbpf.c.patch +libbpf-prevent-double-close-and-leak-of-btf-objects.patch +bpf-validate-node_id-in-arena_alloc_pages.patch +bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch +pinctrl-pinctrl-pic32-fix-resource-leak.patch +pinctrl-cy8c95x0-remove-duplicate-error-message.patch +pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch +pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch +perf-branch-avoid-incrementing-null.patch +perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch +pinctrl-realtek-fix-function-signature-for-config-ar.patch +pinctrl-abx500-fix-type-of-argument-variable.patch +pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch +perf-lock-fix-option-value-type-in-parse_max_stack.patch +perf-stat-fix-opt-value-type-for-parse_cache_level.patch +perf-tools-fix-module-symbol-resolution-for-non-zero.patch +perf-expr-return-einval-for-syntax-error-in-expr__fi.patch +ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch +ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch +ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch +perf-evsel-add-alternate_hw_config-and-use-in-evsel_.patch +perf-tool_pmu-factor-tool-events-into-their-own-pmu.patch +perf-python-add-parse_events-function.patch +perf-cgroup-update-metric-leader-in-evlist__expand_c.patch +perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch +perf-util-kill-die-prototype-dead-for-a-long-time.patch +reset-replace-boolean-parameters-with-flags-paramete.patch +reset-add-devres-helpers-to-request-pre-deasserted-r.patch +i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch +i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch +i3c-master-fix-error-codes-at-send_ccc_cmd.patch +i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch +backlight-sky81452-backlight-check-return-value-of-d.patch +platform-surface-surfacepro3_button-drop-wakeup-sour.patch +leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch +tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch +platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch +mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch +nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch +platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch +platform-x86-asus-wmi-fix-screenpad-brightness-range.patch +tty-serial-ip22zilog-fix-section-mispatch-warning.patch +fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch +platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch +platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch +rdma-core-prefer-nla_nul_string.patch +clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch +scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch +scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch +clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch +clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch +scsi-target-core-fix-integer-overflow-in-unmap-bound.patch +dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch +clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch +clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch +clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch +clk-imx8mq-correct-the-csi-phy-sels.patch +x86-um-vdso-drop-vdso64-y-from-makefile.patch +x86-um-fix-vdso-installation.patch +clk-qoriq-avoid-format-string-warning.patch +clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch +dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch +clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch +lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch +clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch +clk-visconti-pll-initialize-clk_init_data-to-zero.patch +f2fs-protect-extension_list-reading-with-sb_lock-in-.patch +drm-i915-relocate-the-skl-wm-sanitation-code.patch +drm-i915-wm-verify-the-correct-plane-ddb-entry.patch +crypto-sa2ul-fix-aead-fallback-algorithm-names.patch +crypto-ccp-copy-iv-using-skcipher-ivsize.patch +erofs-add-encoded-extent-on-disk-definition.patch +erofs-do-sanity-check-on-m-type-in-z_erofs_load_comp.patch +erofs-avoid-infinite-loops-due-to-corrupted-subpage-.patch +erofs-unify-lcn-as-u64-for-32-bit-platforms.patch +arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch +arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch +arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch +arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch +arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch +arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch +pcmcia-fix-garbled-log-messages-for-kern_cont.patch +arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch +arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch +arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch +arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch +net-sched-act_mirred-fix-wrong-device-for-mac_header.patch +macvlan-fix-macvlan_get_size-not-reserving-space-for.patch +net-sched-sch_cake-fix-nat-destination-port-not-bein.patch +nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch +net-sched-taprio-fix-use-after-free-in-advance_sched.patch +tcp-add-data-race-annotations-around-tp-data_segs_ou.patch +tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch +tcp-annotate-data-races-around-tp-bytes_sent.patch +tcp-annotate-data-races-around-tp-bytes_retrans.patch +tcp-annotate-data-races-around-tp-dsack_dups.patch +tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch +tcp-annotate-data-races-around-tp-plb_rehash.patch +ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch +ice-remove-jumbo_remove-step-from-tx-path.patch +ice-fix-double-free-of-tx_buf-skb.patch +ice-fix-ice_aq_link_speed_m-for-200g.patch +i40e-don-t-advertise-iff_supp_nofcs.patch +e1000e-unroll-ptp-in-probe-error-handling.patch +ipv6-fix-possible-uaf-in-icmpv6_rcv.patch +sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch +pppoe-drop-pfc-frames.patch +net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch +openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch +netfilter-nft_osf-restrict-it-to-ipv4.patch +netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch +netfilter-conntrack-remove-sprintf-usage.patch +netfilter-xtables-restrict-several-matches-to-inet-f.patch +ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch +netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch +netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch +slip-reject-vj-receive-packets-on-instances-with-no-.patch +slip-bound-decode-reads-against-the-compressed-packe.patch +arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch +pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch +ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch +ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch +ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch +ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch +net-rds-zero-per-item-info-buffer-before-handing-it-.patch +ice-fix-timestamp-interrupt-configuration-for-e825c.patch +ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch +net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch +net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch +net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch +net-sched-sch_red-annotate-data-races-in-red_dump_st.patch +net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch +net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch +net-airoha-move-ndesc-initialization-at-end-of-airoh.patch +virtio_net-split-struct-virtio_net_rss_config.patch +virtio_net-fix-endian-with-virtio_net_ctrl_rss.patch +virtio_net-use-new-rss-config-structs.patch +virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch +nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch +tipc-fix-double-free-in-tipc_buf_append.patch +vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch +fs-adfs-validate-nzones-in-adfs_validate_bblk.patch +rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch +kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch +fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch +mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch +mailbox-mailbox-test-free-channels-on-probe-error.patch +sched-psi-fix-race-between-file-release-and-pressure.patch +cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch +mailbox-add-sanity-check-for-channel-array.patch +mailbox-mailbox-test-don-t-free-the-reused-channel.patch +mailbox-mailbox-test-initialize-struct-earlier.patch +mailbox-mailbox-test-make-data_ready-a-per-instance-.patch +fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch +btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch +cgroup-increment-nr_dying_subsys_-from-rmdir-context.patch +tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch +nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch +netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch +nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch +drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch +drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch +drm-amdgpu-fix-spelling-typos.patch +drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch +drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch +netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch +netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch +asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch +spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch +drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch +arm64-scs-fix-potential-sign-extension-issue-of-adva.patch +cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch +netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch +net-sched-netem-fix-probability-gaps-in-4-state-loss.patch +net-sched-netem-fix-queue-limit-check-to-include-reo.patch +net-sched-netem-only-reseed-prng-when-seed-is-explic.patch +net-sched-netem-validate-slot-configuration.patch +net-sched-netem-fix-slot-delay-calculation-overflow.patch +net-sched-netem-check-for-negative-latency-and-jitte.patch +net-sched-sch_choke-annotate-data-races-in-choke_dum.patch +net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch +vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch +net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch +net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch +nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch +net-sched-taprio-fix-null-pointer-dereference-in-cla.patch +neigh-let-neigh_xmit-take-skb-ownership.patch +tcp-make-probe0-timer-handle-expired-user-timeout.patch +net-treewide-define-and-use-mac_addr_str_len.patch +netconsole-allow-selection-of-egress-interface-via-m.patch +netpoll-extract-carrier-wait-function.patch +netpoll-extract-ipv4-address-retrieval-into-helper-f.patch +netpoll-fix-ipv6-local-address-corruption.patch +alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch +sched-fair-clear-rel_deadline-when-initializing-fork.patch +net-mctp-i2c-check-length-before-marking-flow-active.patch +net-phy-dp83869-fix-setting-clk_o_sel-field.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch +asoc-codecs-ab8500-fix-casting-of-private-data.patch +netfilter-skip-recording-stale-or-retransmitted-init.patch +sctp-discard-stale-init-after-handshake-completion.patch +bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch +netconsole-propagate-device-name-truncation-in-dev_n.patch +alsa-hda-conexant-renaming-the-codec-with-device-id-.patch +alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch +alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch +futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch +drm-amd-display-allow-dce-link-encoder-without-aux-r.patch +drm-amd-display-read-edid-from-vbios-embedded-panel-.patch +drm-xe-debugfs-correct-printing-of-register-whitelis.patch +drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch +drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch +page_pool-set-dma_sync-to-false-for-devmem-memory-pr.patch +net-page_pool-create-hooks-for-custom-memory-provide.patch +page_pool-fix-memory-provider-leak-in-page_pool_crea.patch +iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch +iavf-stop-removing-vlan-filters-from-pf-on-interface.patch +iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch +iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch +ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch +net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch +sfc-fix-error-code-in-efx_devlink_info_running_versi.patch +net-sched-cls_flower-revert-unintended-changes.patch +arm64-reserve-an-extra-page-for-early-kernel-mapping.patch diff --git a/queue-6.12/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch b/queue-6.12/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch new file mode 100644 index 0000000000..e04fe6daf4 --- /dev/null +++ b/queue-6.12/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch @@ -0,0 +1,37 @@ +From d9a3e0aae286a8d451b6aeb1dedf07b69a08abbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:48:17 +0300 +Subject: sfc: fix error code in efx_devlink_info_running_versions() + +From: Dan Carpenter + +[ Upstream commit 051ffb001b8a232cfa6e72f38bb5f51c4270a60b ] + +Return -EIO if efx_mcdi_rpc() doesn't return enough space. + +Fixes: 14743ddd2495 ("sfc: add devlink info support for ef100") +Signed-off-by: Dan Carpenter +Reviewed-by: Edward Cree +Link: https://patch.msgid.link/afGpsbLRHL4_H0KS@stanley.mountain +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sfc/efx_devlink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c +index 3cd750820fdde..d5a4b3cf94544 100644 +--- a/drivers/net/ethernet/sfc/efx_devlink.c ++++ b/drivers/net/ethernet/sfc/efx_devlink.c +@@ -530,7 +530,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx, + if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) { + netif_err(efx, drv, efx->net_dev, + "mcdi MC_CMD_GET_VERSION failed\n"); +- return rc; ++ return rc ?: -EIO; + } + + /* Handle previous output */ +-- +2.53.0 + diff --git a/queue-6.12/slip-bound-decode-reads-against-the-compressed-packe.patch b/queue-6.12/slip-bound-decode-reads-against-the-compressed-packe.patch new file mode 100644 index 0000000000..56e4b9640f --- /dev/null +++ b/queue-6.12/slip-bound-decode-reads-against-the-compressed-packe.patch @@ -0,0 +1,158 @@ +From a822da679727221108a1648114aabcba27d3ea88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:01:51 +0800 +Subject: slip: bound decode() reads against the compressed packet length + +From: Weiming Shi + +[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ] + +slhc_uncompress() parses a VJ-compressed TCP header by advancing a +pointer through the packet via decode() and pull16(). Neither helper +bounds-checks against isize, and decode() masks its return with +& 0xffff so it can never return the -1 that callers test for -- those +error paths are dead code. + +A short compressed frame whose change byte requests optional fields +lets decode() read past the end of the packet. The over-read bytes +are folded into the cached cstate and reflected into subsequent +reconstructed packets. + +Make decode() and pull16() take the packet end pointer and return -1 +when exhausted. Add a bounds check before the TCP-checksum read. +The existing == -1 tests now do what they were always meant to. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Simon Horman +Closes: https://lore.kernel.org/netdev/20260414134126.758795-2-horms@kernel.org/ +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416100147.531855-5-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index fcb3eebe7311c..daf086c283423 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -80,9 +80,9 @@ + #include + + static unsigned char *encode(unsigned char *cp, unsigned short n); +-static long decode(unsigned char **cpp); ++static long decode(unsigned char **cpp, const unsigned char *end); + static unsigned char * put16(unsigned char *cp, unsigned short x); +-static unsigned short pull16(unsigned char **cpp); ++static long pull16(unsigned char **cpp, const unsigned char *end); + + /* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) +@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n) + return cp; + } + +-/* Pull a 16-bit integer in host order from buffer in network byte order */ +-static unsigned short +-pull16(unsigned char **cpp) ++/* Pull a 16-bit integer in host order from buffer in network byte order. ++ * Returns -1 if the buffer is exhausted, otherwise the 16-bit value. ++ */ ++static long ++pull16(unsigned char **cpp, const unsigned char *end) + { +- short rval; ++ long rval; + ++ if (*cpp + 2 > end) ++ return -1; + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; + } + +-/* Decode a number */ ++/* Decode a number. Returns -1 if the buffer is exhausted. */ + static long +-decode(unsigned char **cpp) ++decode(unsigned char **cpp, const unsigned char *end) + { + int x; + ++ if (*cpp >= end) ++ return -1; + x = *(*cpp)++; +- if(x == 0){ +- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ +- } else { +- return x & 0xff; /* -1 if PULLCHAR returned error */ +- } ++ if (x == 0) ++ return pull16(cpp, end); ++ return x & 0xff; + } + + /* +@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; ++ const unsigned char *end = icp + isize; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; +@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + ++ if (cp + 2 > end) ++ goto bad; + thp->check = *(__sum16 *)cp; + cp += 2; + +@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + default: + if(changes & NEW_U){ + thp->urg = 1; +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); +@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + break; + } + if(changes & NEW_I){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); +-- +2.53.0 + diff --git a/queue-6.12/slip-reject-vj-receive-packets-on-instances-with-no-.patch b/queue-6.12/slip-reject-vj-receive-packets-on-instances-with-no-.patch new file mode 100644 index 0000000000..a324446903 --- /dev/null +++ b/queue-6.12/slip-reject-vj-receive-packets-on-instances-with-no-.patch @@ -0,0 +1,98 @@ +From b16e11700dbefb896b152dd8afe5300770dd1b11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 04:41:31 +0800 +Subject: slip: reject VJ receive packets on instances with no rstate array + +From: Weiming Shi + +[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ] + +slhc_init() accepts rslots == 0 as a valid configuration, with the +documented meaning of 'no receive compression'. In that case the +allocation loop in slhc_init() is skipped, so comp->rstate stays +NULL and comp->rslot_limit stays 0 (from the kzalloc of struct +slcompress). + +The receive helpers do not defend against that configuration. +slhc_uncompress() dereferences comp->rstate[x] when the VJ header +carries an explicit connection ID, and slhc_remember() later assigns +cs = &comp->rstate[...] after only comparing the packet's slot number +to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the +range check, and the code dereferences a NULL rstate. + +The configuration is reachable in-tree through PPP. PPPIOCSMAXCID +stores its argument in a signed int, and (val >> 16) uses arithmetic +shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 +is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because +/dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path +is reachable from an unprivileged user namespace. Once the malformed +VJ state is installed, any inbound VJ-compressed or VJ-uncompressed +frame that selects slot 0 crashes the kernel in softirq context: + + Oops: general protection fault, probably for non-canonical + address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519) + Call Trace: + + ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466) + ppp_input (drivers/net/ppp/ppp_generic.c:2359) + ppp_async_process (drivers/net/ppp/ppp_async.c:492) + tasklet_action_common (kernel/softirq.c:926) + handle_softirqs (kernel/softirq.c:623) + run_ksoftirqd (kernel/softirq.c:1055) + smpboot_thread_fn (kernel/smpboot.c:160) + kthread (kernel/kthread.c:436) + ret_from_fork (arch/x86/kernel/process.c:164) + + +Reject the receive side on such instances instead of touching rstate. +slhc_uncompress() falls through to its existing 'bad' label, which +bumps sls_i_error and enters the toss state. slhc_remember() mirrors +that with an explicit sls_i_error increment followed by slhc_toss(); +the sls_i_runt counter is not used here because a missing rstate is +an internal configuration state, not a runt packet. + +The transmit path is unaffected: the only in-tree caller that picks +rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and +slip.c always calls slhc_init(16, 16), so comp->tstate remains valid +and slhc_compress() continues to work. + +Fixes: 4ab42d78e37a ("ppp, slip: Validate VJ compression slot parameters completely") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415204130.258866-2-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index ee9fd3a94b96f..fcb3eebe7311c 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + comp->sls_i_error++; + return 0; + } ++ if (!comp->rstate) ++ goto bad; + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. +@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + unsigned int ihl; + ++ if (!comp->rstate) { ++ comp->sls_i_error++; ++ return slhc_toss(comp); ++ } + /* The packet is shorter than a legal IP header. + * Also make sure isize is positive. + */ +-- +2.53.0 + diff --git a/queue-6.12/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch b/queue-6.12/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch new file mode 100644 index 0000000000..d616a6ab3f --- /dev/null +++ b/queue-6.12/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch @@ -0,0 +1,41 @@ +From bbdc02f57664b1fdc0d7ceb93189201995514209 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 12:53:23 -0700 +Subject: soc: qcom: aoss: compare against normalized cooling state + +From: Alok Tiwari + +[ Upstream commit cd3c4670db3ffe997be9548c7a9db3952563cf14 ] + +qmp_cdev_set_cur_state() normalizes the requested state to a boolean +(cdev_state = !!state). The existing early-return check compares +qmp_cdev->state == state, which can be wrong if state is non-boolean +(any non-zero value). Compare qmp_cdev->state against cdev_state instead, +so the check matches the effective state and avoids redundant updates. + +Signed-off-by: Alok Tiwari +Fixes: 05589b30b21a ("soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260329195333.1478090-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/qcom_aoss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c +index 0320ad3b91483..d7cd449c57b69 100644 +--- a/drivers/soc/qcom/qcom_aoss.c ++++ b/drivers/soc/qcom/qcom_aoss.c +@@ -354,7 +354,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, + /* Normalize state */ + cdev_state = !!state; + +- if (qmp_cdev->state == state) ++ if (qmp_cdev->state == cdev_state) + return 0; + + ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}", +-- +2.53.0 + diff --git a/queue-6.12/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch b/queue-6.12/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch new file mode 100644 index 0000000000..217d9d161a --- /dev/null +++ b/queue-6.12/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch @@ -0,0 +1,45 @@ +From 2045cd880a8c61f0ecdd47fffbdf809d26930059 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 02:51:11 -0700 +Subject: soc: qcom: llcc: fix v1 SB syndrome register offset + +From: Alok Tiwari + +[ Upstream commit 24e7625df5ce065393249b78930781be593bc381 ] + +The llcc_v1_edac_reg_offset table uses 0x2304c for trp_ecc_sb_err_syn0, +which is inconsistent with the surrounding TRP ECC registers (0x2034x) +and with llcc_v2_1_edac_reg_offset, where trp_ecc_sb_err_syn0 is 0x2034c +adjacent to trp_ecc_error_status0/1 at 0x20344/0x20348. + +Use 0x2034c for llcc v1 so the SB syndrome register follows the expected ++0x4 progression from trp_ecc_error_status1. This fixes EDAC reading the +wrong register for SB syndrome reporting. + +Fixes: c13d7d261e36 ("soc: qcom: llcc: Pass LLCC version based register offsets to EDAC driver") +Signed-off-by: Alok Tiwari +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260330095118.2657362-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/llcc-qcom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c +index 0278e1854af06..5de1a72c077c3 100644 +--- a/drivers/soc/qcom/llcc-qcom.c ++++ b/drivers/soc/qcom/llcc-qcom.c +@@ -2584,7 +2584,7 @@ static const struct llcc_slice_config x1e80100_data[] = { + static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { + .trp_ecc_error_status0 = 0x20344, + .trp_ecc_error_status1 = 0x20348, +- .trp_ecc_sb_err_syn0 = 0x2304c, ++ .trp_ecc_sb_err_syn0 = 0x2034c, + .trp_ecc_db_err_syn0 = 0x20370, + .trp_ecc_error_cntr_clear = 0x20440, + .trp_interrupt_0_status = 0x20480, +-- +2.53.0 + diff --git a/queue-6.12/soc-qcom-ocmem-make-the-core-clock-optional.patch b/queue-6.12/soc-qcom-ocmem-make-the-core-clock-optional.patch new file mode 100644 index 0000000000..bb34910925 --- /dev/null +++ b/queue-6.12/soc-qcom-ocmem-make-the-core-clock-optional.patch @@ -0,0 +1,41 @@ +From 58ddab953987696813da3030e82f174d02c76ac5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:57 +0200 +Subject: soc: qcom: ocmem: make the core clock optional + +From: Dmitry Baryshkov + +[ Upstream commit e8a61c51417c679d1a599fb36695e9d3b8d95514 ] + +OCMEM's core clock (aka RPM bus 2 clock) is being handled internally by +the interconnect driver. Corresponding clock has been dropped from the +SMD RPM clock driver. The users of the ocmem will vote on the ocmemnoc +interconnect paths, making sure that ocmem is on. Make the clock +optional, keeping it for compatibility with older DT. + +Fixes: d6edc31f3a68 ("clk: qcom: smd-rpm: Separate out interconnect bus clocks") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-1-ad9bcae44763@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 71130a2f62e9e..7bcd0c71d7f64 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -308,7 +308,7 @@ static int ocmem_dev_probe(struct platform_device *pdev) + ocmem->dev = dev; + ocmem->config = device_get_match_data(dev); + +- ocmem->core_clk = devm_clk_get(dev, "core"); ++ ocmem->core_clk = devm_clk_get_optional(dev, "core"); + if (IS_ERR(ocmem->core_clk)) + return dev_err_probe(dev, PTR_ERR(ocmem->core_clk), + "Unable to get core clock\n"); +-- +2.53.0 + diff --git a/queue-6.12/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch b/queue-6.12/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch new file mode 100644 index 0000000000..870d8ff553 --- /dev/null +++ b/queue-6.12/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch @@ -0,0 +1,46 @@ +From 24e2be0f4394806bb9c97529fb68eff2f2c8c9ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:58 +0200 +Subject: soc: qcom: ocmem: register reasons for probe deferrals + +From: Dmitry Baryshkov + +[ Upstream commit 9dfd69cd89cd6afa4723be9098979abeef3bb8c6 ] + +Instead of printing messages to the dmesg, let the message be recorded +as a reason for the OCMEM client deferral. + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Brian Masney +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-2-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 7bcd0c71d7f64..ed77fdc76c9b2 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -196,10 +196,10 @@ struct ocmem *of_get_ocmem(struct device *dev) + } + + pdev = of_find_device_by_node(devnode->parent); +- if (!pdev) { +- dev_err(dev, "Cannot find device node %s\n", devnode->name); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!pdev) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, ++ "Cannot find device node %s\n", ++ devnode->name); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-6.12/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch b/queue-6.12/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch new file mode 100644 index 0000000000..7c96af78d0 --- /dev/null +++ b/queue-6.12/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch @@ -0,0 +1,46 @@ +From c34ff05accfe4e5d67f07bf55c00f8bf959ffb65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:59 +0200 +Subject: soc: qcom: ocmem: return -EPROBE_DEFER is ocmem is not available + +From: Dmitry Baryshkov + +[ Upstream commit 91b59009c7d48b58dbc50fecb27f2ad20749a05a ] + +If OCMEM is declared in DT, it is expected that it is present and +handled by the driver. The GPU driver will ignore -ENODEV error, which +typically means that OCMEM isn't defined in DT. Let ocmem return +-EPROBE_DEFER if it supposed to be used, but it is not probed (yet). + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-3-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index ed77fdc76c9b2..37ea6b86aebcb 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -203,10 +203,9 @@ struct ocmem *of_get_ocmem(struct device *dev) + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +- if (!ocmem) { +- dev_err(dev, "Cannot get ocmem\n"); +- return ERR_PTR(-ENODEV); +- } ++ if (!ocmem) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n"); ++ + return ocmem; + } + EXPORT_SYMBOL_GPL(of_get_ocmem); +-- +2.53.0 + diff --git a/queue-6.12/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch b/queue-6.12/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch new file mode 100644 index 0000000000..80b9708648 --- /dev/null +++ b/queue-6.12/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch @@ -0,0 +1,43 @@ +From f9b2d2b7b69f05cccb47945e5701a0af8b28ec33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:03 +0530 +Subject: soc/tegra: cbb: Set ERD on resume for err interrupt + +From: Sumit Gupta + +[ Upstream commit b6ff71c5d1d4ad858ddf6f39394d169c96689596 ] + +Set the Error Response Disable (ERD) bit to mask SError responses +and use interrupt-based error reporting. When the ERD bit is set, +inband error responses to the initiator via SError are suppressed, +and fabric errors are reported via an interrupt instead. + +The register is set during boot but the info is lost during system +suspend and needs to be set again on resume. + +Fixes: fc2f151d2314 ("soc/tegra: cbb: Add driver for Tegra234 CBB 2.0") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index e8cc46874c729..eace89ed16176 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -1176,6 +1176,10 @@ static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) + { + struct tegra234_cbb *cbb = dev_get_drvdata(dev); + ++ /* set ERD bit to mask SError and generate interrupt to report error */ ++ if (cbb->fabric->off_mask_erd) ++ tegra234_cbb_mask_serror(cbb); ++ + tegra234_cbb_error_enable(&cbb->base); + + dev_dbg(dev, "%s resumed\n", cbb->fabric->name); +-- +2.53.0 + diff --git a/queue-6.12/soundwire-bus-demote-unattached-state-warnings-to-de.patch b/queue-6.12/soundwire-bus-demote-unattached-state-warnings-to-de.patch new file mode 100644 index 0000000000..341797aaf7 --- /dev/null +++ b/queue-6.12/soundwire-bus-demote-unattached-state-warnings-to-de.patch @@ -0,0 +1,62 @@ +From 449c7ca5d8f281949f877e69f20cfcd06cc51b0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:02:10 -0700 +Subject: soundwire: bus: demote UNATTACHED state warnings to dev_dbg() + +From: Cole Leavitt + +[ Upstream commit 2c96956fe764f8224f9ec93b2a9160a578949a7a ] + +The dev_warn() messages in sdw_handle_slave_status() for UNATTACHED +transitions were added in commit d1b328557058 ("soundwire: bus: add +dev_warn() messages to track UNATTACHED devices") to debug attachment +failures with dynamic debug enabled. + +These warnings fire during normal operation -- for example when a codec +driver triggers a hardware reset after firmware download, causing the +device to momentarily go UNATTACHED before re-attaching -- producing +misleading noise on every boot. + +Demote the messages to dev_dbg() so they remain available via dynamic +debug for diagnosing real attachment failures without alarming users +during expected initialization sequences. + +Fixes: d1b328557058 ("soundwire: bus: add dev_warn() messages to track UNATTACHED devices") +Signed-off-by: Cole Leavitt +Reviewed-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260218180210.9263-1-cole@unwrap.rs +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/bus.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c +index 6c7989e2079e0..25efafd89c036 100644 +--- a/drivers/soundwire/bus.c ++++ b/drivers/soundwire/bus.c +@@ -1866,8 +1866,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + + if (status[i] == SDW_SLAVE_UNATTACHED && + slave->status != SDW_SLAVE_UNATTACHED) { +- dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", ++ i, slave->status); + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + + /* Ensure driver knows that peripheral unattached */ +@@ -1918,8 +1918,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + if (slave->status == SDW_SLAVE_UNATTACHED) + break; + +- dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", ++ i, slave->status); + + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + break; +-- +2.53.0 + diff --git a/queue-6.12/soundwire-cadence-clear-message-complete-before-sign.patch b/queue-6.12/soundwire-cadence-clear-message-complete-before-sign.patch new file mode 100644 index 0000000000..c26b0d45db --- /dev/null +++ b/queue-6.12/soundwire-cadence-clear-message-complete-before-sign.patch @@ -0,0 +1,89 @@ +From 41ce0d50983562ee6538eb75ef3ee3a65ea75f31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 11:31:33 +0000 +Subject: soundwire: cadence: Clear message complete before signaling waiting + thread + +From: Richard Fitzgerald + +[ Upstream commit cbfea84f820962c3c5394ff06e7e9344c96bf761 ] + +Clear the CDNS_MCP_INT_RX_WL interrupt before signaling completion. + +This is to prevent the potential race where: +- The main thread is scheduled immediately the completion is signaled, + and starts a new message +- The RX_WL IRQ for this new message happens before sdw_cdns_irq() has + been re-scheduled. +- When sdw_cdns_irq() is re-scheduled it clears the new RX_WL interrupt. + +MAIN THREAD | IRQ THREAD + | + _cdns_xfer_msg() | + { | + write data to FIFO | + wait_for_completion_timeout() | + | <---- RX_WL IRQ + | sdw_cdns_irq() + | { + | signal completion + <== RESCHEDULE <== + Handle message completion | + } | + | +Start new message | + _cdns_xfer_msg() | + { | + write data to FIFO | + wait_for_completion_timeout() | + | <---- RX_WL IRQ + ==> RESCHEDULE ==> + | // New RX_WL IRQ is cleared before + | // it has been handled. + | clear CDNS_MCP_INTSTAT + + | return IRQ_HANDLED; + | } + +Before this change, this error message was sometimes seen on kernels +that have large amounts of debugging enabled: + + SCP Msg trf timed out + +This error indicates that the completion has not been signalled after +500ms. + +Signed-off-by: Richard Fitzgerald +Fixes: 956baa1992f9 ("soundwire: cdns: Add sdw_master_ops and IO transfer support") +Reported-by: Norman Bintang +Closes: https://issuetracker.google.com/issues/477099834 +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20260310113133.1707288-1-rf@opensource.cirrus.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/cadence_master.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c +index 6f2b5ec5c87c6..a503ef606a62c 100644 +--- a/drivers/soundwire/cadence_master.c ++++ b/drivers/soundwire/cadence_master.c +@@ -931,6 +931,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) + + cdns_read_response(cdns); + ++ /* ++ * Clear interrupt before signalling the completion to avoid ++ * a race between this thread and the main thread starting ++ * another TX. ++ */ ++ cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_RX_WL); ++ int_status &= ~CDNS_MCP_INT_RX_WL; ++ + if (defer && defer->msg) { + cdns_fill_msg_resp(cdns, defer->msg, + defer->length, 0); +-- +2.53.0 + diff --git a/queue-6.12/soundwire-debugfs-initialize-firmware_file-to-empty-.patch b/queue-6.12/soundwire-debugfs-initialize-firmware_file-to-empty-.patch new file mode 100644 index 0000000000..31add07e7a --- /dev/null +++ b/queue-6.12/soundwire-debugfs-initialize-firmware_file-to-empty-.patch @@ -0,0 +1,66 @@ +From b5211dbd6e080255aedcd82471203f4e379ee609 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:46 +0800 +Subject: soundwire: debugfs: initialize firmware_file to empty string + +From: Gui-Dong Han + +[ Upstream commit 7215e4552f31e53595eae56a834f7e286beecccc ] + +Passing NULL to debugfs_create_str() causes a NULL pointer dereference, +and creating debugfs nodes with NULL string pointers is no longer +permitted. + +Additionally, firmware_file is a global pointer. Previously, adding every +new slave blindly overwrote it with NULL. + +Fix these issues by initializing firmware_file to an allocated empty +string once in the subsystem init path (sdw_debugfs_init), and freeing +it in the exit path. Existing driver code handles empty strings +correctly. + +Fixes: fe46d2a4301d ("soundwire: debugfs: add interface to read/write commands") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/17647e4c.d461.19b46144a4e.Coremail.yangshiguang1011@163.com/ +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-4-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/soundwire/debugfs.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c +index c30f571934ee2..93c93a128fb23 100644 +--- a/drivers/soundwire/debugfs.c ++++ b/drivers/soundwire/debugfs.c +@@ -295,8 +295,8 @@ void sdw_slave_debugfs_init(struct sdw_slave *slave) + debugfs_create_file("go", 0200, d, slave, &cmd_go_fops); + + debugfs_create_file("read_buffer", 0400, d, slave, &read_buffer_fops); +- firmware_file = NULL; +- debugfs_create_str("firmware_file", 0200, d, &firmware_file); ++ if (firmware_file) ++ debugfs_create_str("firmware_file", 0200, d, &firmware_file); + + slave->debugfs = d; + } +@@ -308,10 +308,15 @@ void sdw_slave_debugfs_exit(struct sdw_slave *slave) + + void sdw_debugfs_init(void) + { ++ if (!firmware_file) ++ firmware_file = kstrdup("", GFP_KERNEL); ++ + sdw_debugfs_root = debugfs_create_dir("soundwire", NULL); + } + + void sdw_debugfs_exit(void) + { + debugfs_remove_recursive(sdw_debugfs_root); ++ kfree(firmware_file); ++ firmware_file = NULL; + } +-- +2.53.0 + diff --git a/queue-6.12/sparc-vdso-always-reject-undefined-references-during.patch b/queue-6.12/sparc-vdso-always-reject-undefined-references-during.patch new file mode 100644 index 0000000000..710a05fe71 --- /dev/null +++ b/queue-6.12/sparc-vdso-always-reject-undefined-references-during.patch @@ -0,0 +1,72 @@ +From 2325df7e87707909efd7b7f1524266f3f25e719e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 15:07:21 +0100 +Subject: sparc/vdso: Always reject undefined references during linking +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 652262975db421767ada3f05b926854bbb357759 ] + +Instead of using a custom script to detect and fail on undefined +references, use --no-undefined for all VDSO linker invocations. + +Drop the now unused checkundef.sh script. + +Signed-off-by: Thomas Weißschuh +Signed-off-by: Ingo Molnar +Cc: David S. Miller +Cc: Andreas Larsson +Link: https://lore.kernel.org/r/20250306-vdso-checkundef-v2-2-a26cc315fd73@linutronix.de +Stable-dep-of: acc4f131d5d5 ("sparc64: vdso: Link with -z noexecstack") +Signed-off-by: Sasha Levin +--- + arch/sparc/vdso/Makefile | 7 +++---- + arch/sparc/vdso/checkundef.sh | 10 ---------- + 2 files changed, 3 insertions(+), 14 deletions(-) + delete mode 100644 arch/sparc/vdso/checkundef.sh + +diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile +index 243dbfc4609d8..c7697884975ea 100644 +--- a/arch/sparc/vdso/Makefile ++++ b/arch/sparc/vdso/Makefile +@@ -22,7 +22,7 @@ targets += $(foreach x, 32 64, vdso-image-$(x).c vdso$(x).so vdso$(x).so.dbg) + + CPPFLAGS_vdso.lds += -P -C + +-VDSO_LDFLAGS_vdso.lds = -m elf64_sparc -soname linux-vdso.so.1 --no-undefined \ ++VDSO_LDFLAGS_vdso.lds = -m elf64_sparc -soname linux-vdso.so.1 \ + -z max-page-size=8192 + + $(obj)/vdso64.so.dbg: $(obj)/vdso.lds $(vobjs) FORCE +@@ -101,7 +101,6 @@ $(obj)/vdso32.so.dbg: FORCE \ + quiet_cmd_vdso = VDSO $@ + cmd_vdso = $(LD) -nostdlib -o $@ \ + $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ +- -T $(filter %.lds,$^) $(filter %.o,$^) && \ +- sh $(src)/checkundef.sh '$(OBJDUMP)' '$@' ++ -T $(filter %.lds,$^) $(filter %.o,$^) + +-VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic ++VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined +diff --git a/arch/sparc/vdso/checkundef.sh b/arch/sparc/vdso/checkundef.sh +deleted file mode 100644 +index 2d85876ffc325..0000000000000 +--- a/arch/sparc/vdso/checkundef.sh ++++ /dev/null +@@ -1,10 +0,0 @@ +-#!/bin/sh +-objdump="$1" +-file="$2" +-$objdump -t "$file" | grep '*UUND*' | grep -v '#scratch' > /dev/null 2>&1 +-if [ $? -eq 1 ]; then +- exit 0 +-else +- echo "$file: undefined symbols found" >&2 +- exit 1 +-fi +-- +2.53.0 + diff --git a/queue-6.12/sparc64-vdso-link-with-z-noexecstack.patch b/queue-6.12/sparc64-vdso-link-with-z-noexecstack.patch new file mode 100644 index 0000000000..25f7338698 --- /dev/null +++ b/queue-6.12/sparc64-vdso-link-with-z-noexecstack.patch @@ -0,0 +1,47 @@ +From 4264c80bd69fdef0ad3ddde48b0adf185eb4d275 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 08:49:01 +0100 +Subject: sparc64: vdso: Link with -z noexecstack +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit acc4f131d5d57c2aa89db914aeb6f7bb0ab4eb4a ] + +The vDSO stack does not need to be executable. Prevent the linker from +creating executable. For more background see commit ffcf9c5700e4 ("x86: +link vdso and boot with -z noexecstack --no-warn-rwx-segments"). + +Also prevent the following warning from the linker: +sparc64-linux-ld: warning: arch/sparc/vdso/vdso-note.o: missing .note.GNU-stack section implies executable stack +sparc64-linux-ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker + +Fixes: 9a08862a5d2e ("vDSO for sparc") +Suggested-by: Arnd Bergmann +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Tested-by: Andreas Larsson +Reviewed-by: Andreas Larsson +Acked-by: Andreas Larsson +Link: https://lore.kernel.org/lkml/20250707144726.4008707-1-arnd@kernel.org/ +Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-4-d8eb3b0e1410@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/sparc/vdso/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile +index c7697884975ea..fc3ada4269f1a 100644 +--- a/arch/sparc/vdso/Makefile ++++ b/arch/sparc/vdso/Makefile +@@ -103,4 +103,4 @@ quiet_cmd_vdso = VDSO $@ + $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ + -T $(filter %.lds,$^) $(filter %.o,$^) + +-VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined ++VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined -z noexecstack +-- +2.53.0 + diff --git a/queue-6.12/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch b/queue-6.12/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..e0065db631 --- /dev/null +++ b/queue-6.12/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 696f571429c9df85650d81f70bb44fe9aa5138f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:21 +0800 +Subject: spi: fsl-qspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 981b080a79724738882b0af1c5bb7ade30d94f24 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks could +get "lost" - use reinit_completion() in that case, but be aware of +other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: 84d043185dbe ("spi: Add a driver for the Freescale/NXP QuadSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-3-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-fsl-qspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c +index 21e357966d2a2..cb2e5413dd32b 100644 +--- a/drivers/spi/spi-fsl-qspi.c ++++ b/drivers/spi/spi-fsl-qspi.c +@@ -606,7 +606,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) + void __iomem *base = q->iobase; + int err = 0; + +- init_completion(&q->c); ++ reinit_completion(&q->c); + + /* + * Always start the sequence at the same index since we update +@@ -924,6 +924,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) + if (ret < 0) + goto err_disable_clk; + ++ init_completion(&q->c); + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { +-- +2.53.0 + diff --git a/queue-6.12/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch b/queue-6.12/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch new file mode 100644 index 0000000000..df0df3d771 --- /dev/null +++ b/queue-6.12/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch @@ -0,0 +1,55 @@ +From fba54de4b233ecbf4d8c6d97f8bd687c03c85484 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 11:06:41 +0800 +Subject: spi: hisi-kunpeng: prevent infinite while() loop in + hisi_spi_flush_fifo + +From: Pei Xiao + +[ Upstream commit 9f61daf2c2debe9f5cf4e1a4471e56a89a6fe45a ] + +The hisi_spi_flush_fifo()'s inner while loop that lacks any timeout +mechanism. Maybe the hardware never becomes empty, the loop will spin +forever, causing the CPU to hang. + +Fix this by adding a inner_limit based on loops_per_jiffy. The inner loop +now exits after approximately one jiffy if the FIFO remains non-empty, logs +a ratelimited warning, and breaks out of the outer loop. Additionally, add +a cpu_relax() inside the busy loop to improve power efficiency. + +Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/d834ce28172886bfaeb9c8ca00cfd9bf1c65d5a1.1773889292.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-hisi-kunpeng.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index f0a50f40a3ba1..77526f7940688 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -196,8 +196,18 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs) + unsigned long limit = loops_per_jiffy << 1; + + do { +- while (hisi_spi_rx_not_empty(hs)) ++ unsigned long inner_limit = loops_per_jiffy; ++ ++ while (hisi_spi_rx_not_empty(hs) && --inner_limit) { + readl(hs->regs + HISI_SPI_DOUT); ++ cpu_relax(); ++ } ++ ++ if (!inner_limit) { ++ dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n"); ++ break; ++ } ++ + } while (hisi_spi_busy(hs) && limit--); + } + +-- +2.53.0 + diff --git a/queue-6.12/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch b/queue-6.12/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch new file mode 100644 index 0000000000..f8105a63c3 --- /dev/null +++ b/queue-6.12/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch @@ -0,0 +1,60 @@ +From 4c3bba5c2cfc08a72f9b375386d0ffd9320c9529 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 15:26:59 +0800 +Subject: spi: mtk-snfi: unregister ECC engine on probe failure and remove() + callback + +From: Pei Xiao + +[ Upstream commit ab00febad191d7a4400aa1c3468279fb508258d4 ] + +mtk_snand_probe() registers the on-host NAND ECC engine, but teardown was +missing from both probe unwind and remove-time cleanup. Add a devm cleanup +action after successful registration so +nand_ecc_unregister_on_host_hw_engine() runs automatically on probe +failures and during device removal. + +Fixes: 764f1b748164 ("spi: add driver for MTK SPI NAND Flash Interface") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/20263f885f1a9c9d559f95275298cd6de4b11ed5.1775546401.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-mtk-snfi.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c +index c5677fd94e5e1..8234064921f36 100644 +--- a/drivers/spi/spi-mtk-snfi.c ++++ b/drivers/spi/spi-mtk-snfi.c +@@ -1307,6 +1307,13 @@ static const struct spi_controller_mem_caps mtk_snand_mem_caps = { + .ecc = true, + }; + ++static void mtk_unregister_ecc_engine(void *data) ++{ ++ struct nand_ecc_engine *eng = data; ++ ++ nand_ecc_unregister_on_host_hw_engine(eng); ++} ++ + static irqreturn_t mtk_snand_irq(int irq, void *id) + { + struct mtk_snand *snf = id; +@@ -1447,6 +1454,13 @@ static int mtk_snand_probe(struct platform_device *pdev) + goto release_ecc; + } + ++ ret = devm_add_action_or_reset(&pdev->dev, mtk_unregister_ecc_engine, ++ &ms->ecc_eng); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "failed to add ECC unregister action\n"); ++ goto release_ecc; ++ } ++ + ctlr->num_chipselect = 1; + ctlr->mem_ops = &mtk_snand_mem_ops; + ctlr->mem_caps = &mtk_snand_mem_caps; +-- +2.53.0 + diff --git a/queue-6.12/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch b/queue-6.12/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..5c5b658971 --- /dev/null +++ b/queue-6.12/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 879eb7991eba3c1b6b57a419b73ad88a92b949df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:20 +0800 +Subject: spi: nxp-fspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 68c8c93fdb0de7e528dc3dfb1d17eb0f652259b8 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks +could get "lost" - use reinit_completion() in that case, but be +aware of other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: a5356aef6a90 ("spi: spi-mem: Add driver for NXP FlexSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-2-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-nxp-fspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c +index 67bcc6d351326..b7dbc015d88fa 100644 +--- a/drivers/spi/spi-nxp-fspi.c ++++ b/drivers/spi/spi-nxp-fspi.c +@@ -907,7 +907,7 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op) + reg = reg | FSPI_IPRXFCR_CLR; + fspi_writel(f, reg, base + FSPI_IPRXFCR); + +- init_completion(&f->c); ++ reinit_completion(&f->c); + + fspi_writel(f, op->addr.val, base + FSPI_IPCR0); + /* +@@ -1267,6 +1267,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to disable clock"); + ++ init_completion(&f->c); + ret = devm_request_irq(dev, irq, + nxp_fspi_irq_handler, 0, pdev->name, f); + if (ret) +-- +2.53.0 + diff --git a/queue-6.12/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch b/queue-6.12/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch new file mode 100644 index 0000000000..857b65479b --- /dev/null +++ b/queue-6.12/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch @@ -0,0 +1,61 @@ +From 089f7965e62eedc337e484a3e6d402fd160c85db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 09:29:34 +0000 +Subject: spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ + +From: John Madieu + +[ Upstream commit b4683a239a409d65f88052f5630c748a8ba070cd ] + +rockchip_spi_isr() decides whether the current interrupt was the +cs-inactive event by reading IMR: + + if (rs->cs_inactive && + readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) + ctlr->target_abort(ctlr); + +IMR is the interrupt mask register: it tells which sources are enabled, +not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables +both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true: + + if (rs->cs_inactive) + writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, + rs->regs + ROCKCHIP_SPI_IMR); + +so the IMR check is always true once cs_inactive is enabled, and every +PIO interrupt - including normal RF_FULL completions - is dispatched to +ctlr->target_abort(), aborting the transfer. The bug is reachable on +ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller +when the transfer is short enough to fall back to PIO +(rockchip_spi_can_dma() returns false below fifo_len). + +Read ISR (which is RISR masked by IMR) so the check actually reflects +which interrupt fired, and parenthesise the expression for clarity while +at it. + +Fixes: 869f2c94db92 ("spi: rockchip: Stop spi slave dma receiver when cs inactive") +Signed-off-by: John Madieu +Link: https://patch.msgid.link/20260425092936.2590132-2-john.madieu@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rockchip.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index b480408c812f8..ccb35a2e39fbd 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -357,7 +357,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + + /* When int_cs_inactive comes, spi target abort */ +- if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { ++ if (rs->cs_inactive && ++ (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) { + ctlr->target_abort(ctlr); + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); +-- +2.53.0 + diff --git a/queue-6.12/spi-spi-nxp-fspi-enable-runtime-pm-for-fspi.patch b/queue-6.12/spi-spi-nxp-fspi-enable-runtime-pm-for-fspi.patch new file mode 100644 index 0000000000..93214049ef --- /dev/null +++ b/queue-6.12/spi-spi-nxp-fspi-enable-runtime-pm-for-fspi.patch @@ -0,0 +1,216 @@ +From 10a79fd56ab5e340409b51200638900e8610875e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Apr 2025 18:06:44 +0800 +Subject: spi: spi-nxp-fspi: enable runtime pm for fspi + +From: Haibo Chen + +[ Upstream commit 97be4b919a609fc8c4bd1118502b5d26cc2f77c4 ] + +Enable the runtime PM in fspi driver. +Also for system PM, On some board like i.MX8ULP-EVK board, +after system suspend, IOMUX module will lost power, so all +the pinctrl setting will lost when system resume back, need +driver to save/restore the pinctrl setting. + +Signed-off-by: Han Xu +Signed-off-by: Haibo Chen +Link: https://patch.msgid.link/20250428-flexspipatch-v3-2-61d5e8f591bc@nxp.com +Signed-off-by: Mark Brown +Stable-dep-of: 68c8c93fdb0d ("spi: nxp-fspi: Use reinit_completion() for repeated operations") +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-nxp-fspi.c | 93 +++++++++++++++++++++++++++++++------- + 1 file changed, 76 insertions(+), 17 deletions(-) + +diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c +index a43540d7995ef..67bcc6d351326 100644 +--- a/drivers/spi/spi-nxp-fspi.c ++++ b/drivers/spi/spi-nxp-fspi.c +@@ -48,6 +48,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -57,6 +59,9 @@ + #include + #include + ++/* runtime pm timeout */ ++#define FSPI_RPM_TIMEOUT 50 /* 50ms */ ++ + /* Registers used by the driver */ + #define FSPI_MCR0 0x00 + #define FSPI_MCR0_AHB_TIMEOUT(x) ((x) << 24) +@@ -396,6 +401,8 @@ struct nxp_fspi { + struct mutex lock; + struct pm_qos_request pm_qos_req; + int selected; ++#define FSPI_NEED_INIT (1 << 0) ++ int flags; + }; + + static inline int needs_ip_only(struct nxp_fspi *f) +@@ -935,6 +942,13 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) + + mutex_lock(&f->lock); + ++ err = pm_runtime_get_sync(f->dev); ++ if (err < 0) { ++ mutex_unlock(&f->lock); ++ dev_err(f->dev, "Failed to enable clock %d\n", __LINE__); ++ return err; ++ } ++ + /* Wait for controller being ready. */ + err = fspi_readl_poll_tout(f, f->iobase + FSPI_STS0, + FSPI_STS0_ARB_IDLE, 1, POLL_TOUT, true); +@@ -963,8 +977,10 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) + /* Invalidate the data in the AHB buffer. */ + nxp_fspi_invalid(f); + +- mutex_unlock(&f->lock); ++ pm_runtime_mark_last_busy(f->dev); ++ pm_runtime_put_autosuspend(f->dev); + ++ mutex_unlock(&f->lock); + return err; + } + +@@ -1231,9 +1247,14 @@ static int nxp_fspi_probe(struct platform_device *pdev) + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get irq source"); + +- ret = nxp_fspi_clk_prep_enable(f); +- if (ret) +- return dev_err_probe(dev, ret, "Can't enable the clock\n"); ++ pm_runtime_enable(dev); ++ pm_runtime_set_autosuspend_delay(dev, FSPI_RPM_TIMEOUT); ++ pm_runtime_use_autosuspend(dev); ++ ++ /* enable clock */ ++ ret = pm_runtime_get_sync(f->dev); ++ if (ret < 0) ++ return dev_err_probe(dev, ret, "Failed to enable clock"); + + /* Clear potential interrupts */ + reg = fspi_readl(f, f->iobase + FSPI_INTR); +@@ -1242,12 +1263,14 @@ static int nxp_fspi_probe(struct platform_device *pdev) + + nxp_fspi_default_setup(f); + ++ ret = pm_runtime_put_sync(dev); ++ if (ret < 0) ++ return dev_err_probe(dev, ret, "Failed to disable clock"); ++ + ret = devm_request_irq(dev, irq, + nxp_fspi_irq_handler, 0, pdev->name, f); +- if (ret) { +- nxp_fspi_clk_disable_unprep(f); ++ if (ret) + return dev_err_probe(dev, ret, "Failed to request irq\n"); +- } + + ret = devm_mutex_init(dev, &f->lock); + if (ret) +@@ -1271,29 +1294,70 @@ static void nxp_fspi_remove(struct platform_device *pdev) + { + struct nxp_fspi *f = platform_get_drvdata(pdev); + ++ /* enable clock first since there is reigster access */ ++ pm_runtime_get_sync(f->dev); ++ + /* disable the hardware */ + fspi_writel(f, FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0); + ++ pm_runtime_disable(f->dev); ++ pm_runtime_put_noidle(f->dev); + nxp_fspi_clk_disable_unprep(f); + + if (f->ahb_addr) + iounmap(f->ahb_addr); + } + +-static int nxp_fspi_suspend(struct device *dev) ++static int nxp_fspi_runtime_suspend(struct device *dev) + { ++ struct nxp_fspi *f = dev_get_drvdata(dev); ++ ++ nxp_fspi_clk_disable_unprep(f); ++ + return 0; + } + +-static int nxp_fspi_resume(struct device *dev) ++static int nxp_fspi_runtime_resume(struct device *dev) + { + struct nxp_fspi *f = dev_get_drvdata(dev); ++ int ret; + +- nxp_fspi_default_setup(f); ++ ret = nxp_fspi_clk_prep_enable(f); ++ if (ret) ++ return ret; + +- return 0; ++ if (f->flags & FSPI_NEED_INIT) { ++ nxp_fspi_default_setup(f); ++ ret = pinctrl_pm_select_default_state(dev); ++ if (ret) ++ dev_err(dev, "select flexspi default pinctrl failed!\n"); ++ f->flags &= ~FSPI_NEED_INIT; ++ } ++ ++ return ret; + } + ++static int nxp_fspi_suspend(struct device *dev) ++{ ++ struct nxp_fspi *f = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = pinctrl_pm_select_sleep_state(dev); ++ if (ret) { ++ dev_err(dev, "select flexspi sleep pinctrl failed!\n"); ++ return ret; ++ } ++ ++ f->flags |= FSPI_NEED_INIT; ++ ++ return pm_runtime_force_suspend(dev); ++} ++ ++static const struct dev_pm_ops nxp_fspi_pm_ops = { ++ RUNTIME_PM_OPS(nxp_fspi_runtime_suspend, nxp_fspi_runtime_resume, NULL) ++ SYSTEM_SLEEP_PM_OPS(nxp_fspi_suspend, pm_runtime_force_resume) ++}; ++ + static const struct of_device_id nxp_fspi_dt_ids[] = { + { .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, }, + { .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, }, +@@ -1313,17 +1377,12 @@ static const struct acpi_device_id nxp_fspi_acpi_ids[] = { + MODULE_DEVICE_TABLE(acpi, nxp_fspi_acpi_ids); + #endif + +-static const struct dev_pm_ops nxp_fspi_pm_ops = { +- .suspend = nxp_fspi_suspend, +- .resume = nxp_fspi_resume, +-}; +- + static struct platform_driver nxp_fspi_driver = { + .driver = { + .name = "nxp-fspi", + .of_match_table = nxp_fspi_dt_ids, + .acpi_match_table = ACPI_PTR(nxp_fspi_acpi_ids), +- .pm = &nxp_fspi_pm_ops, ++ .pm = pm_ptr(&nxp_fspi_pm_ops), + }, + .probe = nxp_fspi_probe, + .remove_new = nxp_fspi_remove, +-- +2.53.0 + diff --git a/queue-6.12/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch b/queue-6.12/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch new file mode 100644 index 0000000000..da2d00670a --- /dev/null +++ b/queue-6.12/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch @@ -0,0 +1,75 @@ +From a5a28fef2a2955e61fac7ae05eaa8de1e59bef0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:07 +0000 +Subject: tcp: add data-race annotations around tp->data_segs_out and + tp->total_retrans + +From: Eric Dumazet + +[ Upstream commit 21e92a38cfd891538598ba8f805e0165a820d532 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e98102f4897 ("tcp: record pkts sent and retransmistted") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 8 +++++--- + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 9c5fc44647831..382c2895ec311 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4276,9 +4276,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED, + info.tcpi_sndbuf_limited, TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT, +- tp->data_segs_out, TCP_NLA_PAD); ++ READ_ONCE(tp->data_segs_out), TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS, +- tp->total_retrans, TCP_NLA_PAD); ++ READ_ONCE(tp->total_retrans), TCP_NLA_PAD); + + rate = READ_ONCE(sk->sk_pacing_rate); + rate64 = (rate != ~0UL) ? rate : ~0ULL; +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 5e37dc45639db..dbe39ad886821 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1446,7 +1446,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + + if (skb->len != tcp_header_size) { + tcp_event_data_sent(tp, sk); +- tp->data_segs_out += tcp_skb_pcount(skb); ++ WRITE_ONCE(tp->data_segs_out, ++ tp->data_segs_out + tcp_skb_pcount(skb)); + tp->bytes_sent += skb->len - tcp_header_size; + } + +@@ -3411,7 +3412,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); +- tp->total_retrans += segs; ++ WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); + tp->bytes_retrans += skb->len; + + /* make sure skb->data is aligned on arches that require it +@@ -4433,7 +4434,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) + * However in this case, we are dealing with a passive fastopen + * socket thus we can change total_retrans value. + */ +- tcp_sk_rw(sk)->total_retrans++; ++ WRITE_ONCE(tcp_sk_rw(sk)->total_retrans, ++ tcp_sk_rw(sk)->total_retrans + 1); + } + trace_tcp_retransmit_synack(sk, req); + } +-- +2.53.0 + diff --git a/queue-6.12/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch b/queue-6.12/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch new file mode 100644 index 0000000000..b0af987ef2 --- /dev/null +++ b/queue-6.12/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch @@ -0,0 +1,76 @@ +From 21623ca78912da91b596c05177423a8ff71bf99a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:11 +0000 +Subject: tcp: add data-race annotations for TCP_NLA_SNDQ_SIZE + +From: Eric Dumazet + +[ Upstream commit 124199444de467767175a9004e1574dc42523e62 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 87ecc95d81d9 ("tcp: add send queue size stat in SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-7-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 +++- + net/ipv4/tcp_input.c | 4 ++-- + net/ipv4/tcp_output.c | 2 +- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 382c2895ec311..16ee72717e039 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4297,7 +4297,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered); + nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce); + +- nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); ++ nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una))); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); + + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index c498588c021d7..39463842231c0 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3670,7 +3670,7 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) + sock_owned_by_me((struct sock *)tp); + tp->bytes_acked += delta; + tcp_snd_sne_update(tp, ack); +- tp->snd_una = ack; ++ WRITE_ONCE(tp->snd_una, ack); + } + + static void tcp_rcv_sne_update(struct tcp_sock *tp, u32 seq) +@@ -6877,7 +6877,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) + if (sk->sk_socket) + sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); + +- tp->snd_una = TCP_SKB_CB(skb)->ack_seq; ++ WRITE_ONCE(tp->snd_una, TCP_SKB_CB(skb)->ack_seq); + tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale; + tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); + +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index dbe39ad886821..59a0ef96b4d85 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -3945,7 +3945,7 @@ static void tcp_connect_init(struct sock *sk) + tp->snd_wnd = 0; + tcp_init_wl(tp, 0); + tcp_write_queue_purge(sk); +- tp->snd_una = tp->write_seq; ++ WRITE_ONCE(tp->snd_una, tp->write_seq); + tp->snd_sml = tp->write_seq; + tp->snd_up = tp->write_seq; + WRITE_ONCE(tp->snd_nxt, tp->write_seq); +-- +2.53.0 + diff --git a/queue-6.12/tcp-annotate-data-races-around-tp-bytes_retrans.patch b/queue-6.12/tcp-annotate-data-races-around-tp-bytes_retrans.patch new file mode 100644 index 0000000000..a86cb615d3 --- /dev/null +++ b/queue-6.12/tcp-annotate-data-races-around-tp-bytes_retrans.patch @@ -0,0 +1,53 @@ +From 959f41e456dcaa006f7acee576519255e63b579c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:13 +0000 +Subject: tcp: annotate data-races around tp->bytes_retrans + +From: Eric Dumazet + +[ Upstream commit 5efc7b9f7cbd43401f1af81d3d7f2be00f93390d ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: fb31c9b9f6c8 ("tcp: add data bytes retransmitted stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-9-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 08678dd21950e..291db82518b03 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4304,8 +4304,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, +- TCP_NLA_PAD); ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, ++ READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 5d1aa41592720..33c2fb60d0562 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -3414,7 +3414,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); + WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); +- tp->bytes_retrans += skb->len; ++ WRITE_ONCE(tp->bytes_retrans, tp->bytes_retrans + skb->len); + + /* make sure skb->data is aligned on arches that require it + * and check if ack-trimming & collapsing extended the headroom +-- +2.53.0 + diff --git a/queue-6.12/tcp-annotate-data-races-around-tp-bytes_sent.patch b/queue-6.12/tcp-annotate-data-races-around-tp-bytes_sent.patch new file mode 100644 index 0000000000..3ed4f631c8 --- /dev/null +++ b/queue-6.12/tcp-annotate-data-races-around-tp-bytes_sent.patch @@ -0,0 +1,52 @@ +From e59f5210f584e2d963aacc626258ccd47867b6fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:12 +0000 +Subject: tcp: annotate data-races around tp->bytes_sent + +From: Eric Dumazet + +[ Upstream commit ee43e957ce2ec77b2ec47fef28f3c0df6ab01a31 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: ba113c3aa79a ("tcp: add data bytes sent stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-8-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_output.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 16ee72717e039..08678dd21950e 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4302,7 +4302,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una))); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); + +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, + TCP_NLA_PAD); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 59a0ef96b4d85..5d1aa41592720 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1448,7 +1448,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + tcp_event_data_sent(tp, sk); + WRITE_ONCE(tp->data_segs_out, + tp->data_segs_out + tcp_skb_pcount(skb)); +- tp->bytes_sent += skb->len - tcp_header_size; ++ WRITE_ONCE(tp->bytes_sent, ++ tp->bytes_sent + skb->len - tcp_header_size); + } + + if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) +-- +2.53.0 + diff --git a/queue-6.12/tcp-annotate-data-races-around-tp-dsack_dups.patch b/queue-6.12/tcp-annotate-data-races-around-tp-dsack_dups.patch new file mode 100644 index 0000000000..88b437467b --- /dev/null +++ b/queue-6.12/tcp-annotate-data-races-around-tp-dsack_dups.patch @@ -0,0 +1,51 @@ +From 8d4f2c34c291730d8f2f470384d56e0991a8a135 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:14 +0000 +Subject: tcp: annotate data-races around tp->dsack_dups + +From: Eric Dumazet + +[ Upstream commit a984705ca88b976bf1087978fd98b7f3993da88c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e10b6554ff2 ("tcp: add dsack blocks received stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-10-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_input.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 291db82518b03..cacb298147d4b 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4306,7 +4306,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); +- nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); ++ nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 39463842231c0..60c42d612d186 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1059,7 +1059,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq, + else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq) + state->flag |= FLAG_DSACK_TLP; + +- tp->dsack_dups += dup_segs; ++ WRITE_ONCE(tp->dsack_dups, tp->dsack_dups + dup_segs); + /* Skip the DSACK if dup segs weren't retransmitted by sender */ + if (tp->dsack_dups > tp->total_retrans) + return 0; +-- +2.53.0 + diff --git a/queue-6.12/tcp-annotate-data-races-around-tp-plb_rehash.patch b/queue-6.12/tcp-annotate-data-races-around-tp-plb_rehash.patch new file mode 100644 index 0000000000..67b7e6911c --- /dev/null +++ b/queue-6.12/tcp-annotate-data-races-around-tp-plb_rehash.patch @@ -0,0 +1,52 @@ +From 3587f63b5f75f763b41672dc39f22e119d1df1d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:19 +0000 +Subject: tcp: annotate data-races around tp->plb_rehash + +From: Eric Dumazet + +[ Upstream commit 9e89b9d03a2d2e30dcca166d5af52f9a8eceab25 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 29c1c44646ae ("tcp: add u32 counter in tcp_sock and an SNMP counter for PLB") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-15-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + net/ipv4/tcp_plb.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 45e093ca22533..8b90665245b2d 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4319,7 +4319,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u8(stats, TCP_NLA_TTL, + tcp_skb_ttl_or_hop_limit(ack_skb)); + +- nla_put_u32(stats, TCP_NLA_REHASH, tp->plb_rehash + tp->timeout_rehash); ++ nla_put_u32(stats, TCP_NLA_REHASH, ++ READ_ONCE(tp->plb_rehash) + READ_ONCE(tp->timeout_rehash)); + return stats; + } + +diff --git a/net/ipv4/tcp_plb.c b/net/ipv4/tcp_plb.c +index 4bcf7eff95e39..b7f9b60d8991f 100644 +--- a/net/ipv4/tcp_plb.c ++++ b/net/ipv4/tcp_plb.c +@@ -79,7 +79,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb) + + sk_rethink_txhash(sk); + plb->consec_cong_rounds = 0; +- tcp_sk(sk)->plb_rehash++; ++ WRITE_ONCE(tcp_sk(sk)->plb_rehash, tcp_sk(sk)->plb_rehash + 1); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPLBREHASH); + } + EXPORT_SYMBOL_GPL(tcp_plb_check_rehash); +-- +2.53.0 + diff --git a/queue-6.12/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch b/queue-6.12/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch new file mode 100644 index 0000000000..3a57a0e536 --- /dev/null +++ b/queue-6.12/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch @@ -0,0 +1,40 @@ +From 00f36a1174c197705f46aaaf3bccd4aa823feafa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:18 +0000 +Subject: tcp: annotate data-races around (tp->write_seq - tp->snd_nxt) + +From: Eric Dumazet + +[ Upstream commit 3a63b3d160560ef51e43fb4c880a5cde8078053c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() annotations to keep KCSAN happy. + +WRITE_ONCE() annotations are already present. + +Fixes: e08ab0b377a1 ("tcp: add bytes not sent to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-14-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index cacb298147d4b..45e093ca22533 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4311,7 +4311,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +- max_t(int, 0, tp->write_seq - tp->snd_nxt)); ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt))); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, + TCP_NLA_PAD); + if (ack_skb) +-- +2.53.0 + diff --git a/queue-6.12/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch b/queue-6.12/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch new file mode 100644 index 0000000000..7bb07e6d63 --- /dev/null +++ b/queue-6.12/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch @@ -0,0 +1,54 @@ +From e575fdf16061f149edd69fa184d42ff10552f26d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:53:27 +0000 +Subject: tcp: Don't set treq->req_usec_ts in cookie_tcp_reqsk_init(). + +From: Kuniyuki Iwashima + +[ Upstream commit c058bbf05b1197c33df7204842665bd8bc70b3a8 ] + +Commit de5626b95e13 ("tcp: Factorise cookie-independent fields +initialisation in cookie_v[46]_check().") miscategorised +tcp_rsk(req)->req_usec_ts init to cookie_tcp_reqsk_init(), +which is used by both BPF/non-BPF SYN cookie reqsk. + +Rather, it should have been moved to cookie_tcp_reqsk_alloc() by +commit 8e7bab6b9652 ("tcp: Factorise cookie-dependent fields +initialisation in cookie_v[46]_check()") so that only non-BPF SYN +cookie sets tcp_rsk(req)->req_usec_ts to false. + +Let's move the initialisation to cookie_tcp_reqsk_alloc() to +respect bpf_tcp_req_attrs.usec_ts_ok. + +Fixes: e472f88891ab ("bpf: tcp: Support arbitrary SYN Cookie.") +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260410235328.1773449-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/syncookies.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c +index 1948d15f1f281..640fc3b54277d 100644 +--- a/net/ipv4/syncookies.c ++++ b/net/ipv4/syncookies.c +@@ -284,7 +284,6 @@ static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb, + treq->rcv_isn = ntohl(th->seq) - 1; + treq->snt_isn = ntohl(th->ack_seq) - 1; + treq->syn_tos = TCP_SKB_CB(skb)->ip_dsfield; +- treq->req_usec_ts = false; + + #if IS_ENABLED(CONFIG_MPTCP) + treq->is_mptcp = sk_is_mptcp(sk); +@@ -347,6 +346,7 @@ struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, + ireq->wscale_ok = tcp_opt->wscale_ok; + ireq->ecn_ok = !!(tcp_opt->rcv_tsecr & TS_OPT_ECN); + ++ treq->req_usec_ts = false; + treq->ts_off = tsoff; + + return req; +-- +2.53.0 + diff --git a/queue-6.12/tcp-make-probe0-timer-handle-expired-user-timeout.patch b/queue-6.12/tcp-make-probe0-timer-handle-expired-user-timeout.patch new file mode 100644 index 0000000000..0ad6e0c41e --- /dev/null +++ b/queue-6.12/tcp-make-probe0-timer-handle-expired-user-timeout.patch @@ -0,0 +1,58 @@ +From c16718cd15242bf253930d8e18919ff0d64f08bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 18:46:38 -0700 +Subject: tcp: make probe0 timer handle expired user timeout + +From: Altan Hacigumus + +[ Upstream commit 2b9f6f7065d4cfb65ba19126e0b35ac4544c3f3a ] + +tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies +using subtraction with an unsigned lvalue. If elapsed probing time +exceeds the configured TCP_USER_TIMEOUT, the underflow yields a large +value. + +This ends up re-arming the probe timer for a full backoff interval +instead of expiring immediately, delaying connection teardown beyond +the configured timeout. + +Fix this by preventing underflow so user-set timeout expiration is +handled correctly without extending the probe timer. + +Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes") +Link: https://lore.kernel.org/r/20260414013634.43997-1-ahacigu.linux@gmail.com +Signed-off-by: Altan Hacigumus +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260424014639.54110-1-ahacigu.linux@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp_timer.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c +index 79064580c8c0d..0cc8f19bc1024 100644 +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -49,7 +49,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) + u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) + { + const struct inet_connection_sock *icsk = inet_csk(sk); +- u32 remaining, user_timeout; ++ u32 user_timeout; ++ s32 remaining; + s32 elapsed; + + user_timeout = READ_ONCE(icsk->icsk_user_timeout); +@@ -60,7 +61,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) + if (unlikely(elapsed < 0)) + elapsed = 0; + remaining = msecs_to_jiffies(user_timeout) - elapsed; +- remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN); ++ remaining = max_t(int, remaining, TCP_TIMEOUT_MIN); + + return min_t(u32, remaining, when); + } +-- +2.53.0 + diff --git a/queue-6.12/thermal-drivers-spear-fix-error-condition-for-readin.patch b/queue-6.12/thermal-drivers-spear-fix-error-condition-for-readin.patch new file mode 100644 index 0000000000..c4817fc31f --- /dev/null +++ b/queue-6.12/thermal-drivers-spear-fix-error-condition-for-readin.patch @@ -0,0 +1,42 @@ +From c89dedde478c75941770d32d939c3bb93e78484e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:35:24 +0530 +Subject: thermal/drivers/spear: Fix error condition for reading + st,thermal-flags + +From: Gopi Krishna Menon + +[ Upstream commit da2c4f332a0504d9c284e7626a561d343c8d6f57 ] + +of_property_read_u32 returns 0 on success. The current check returns +-EINVAL if the property is read successfully. + +Fix the check by removing ! from of_property_read_u32 + +Fixes: b9c7aff481f1 ("drivers/thermal/spear_thermal.c: add Device Tree probing capability") +Signed-off-by: Gopi Krishna Menon +Signed-off-by: Daniel Lezcano +Suggested-by: Daniel Baluta +Reviewed-by: Lukasz Luba +Link: https://patch.msgid.link/20260327090526.59330-1-krishnagopi487@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/thermal/spear_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c +index 60a871998b07e..19b37f9b093f9 100644 +--- a/drivers/thermal/spear_thermal.c ++++ b/drivers/thermal/spear_thermal.c +@@ -93,7 +93,7 @@ static int spear_thermal_probe(struct platform_device *pdev) + struct device_node *np = pdev->dev.of_node; + int ret = 0, val; + +- if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) { ++ if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) { + dev_err(&pdev->dev, "Failed: DT Pdata not passed\n"); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.12/tipc-fix-double-free-in-tipc_buf_append.patch b/queue-6.12/tipc-fix-double-free-in-tipc_buf_append.patch new file mode 100644 index 0000000000..4be771082c --- /dev/null +++ b/queue-6.12/tipc-fix-double-free-in-tipc_buf_append.patch @@ -0,0 +1,60 @@ +From 513aeeb2f11ba7d899251b22d4ec7c23f3b42205 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 13:45:26 +0100 +Subject: tipc: fix double-free in tipc_buf_append() + +From: Lee Jones + +[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ] + +tipc_msg_validate() can potentially reallocate the skb it is validating, +freeing the old one. In tipc_buf_append(), it was being called with a +pointer to a local variable which was a copy of the caller's skb +pointer. + +If the skb was reallocated and validation subsequently failed, the error +handling path would free the original skb pointer, which had already +been freed, leading to double-free. + +Fix this by checking if head now points to a newly allocated reassembled +skb. If it does, reassign *headbuf for later freeing operations. + +Fixes: d618d09a68e4 ("tipc: enforce valid ratio between skb truesize and contents") +Suggested-by: Tung Nguyen +Signed-off-by: Lee Jones +Reviewed-by: Tung Nguyen +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/msg.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/net/tipc/msg.c b/net/tipc/msg.c +index 76284fc538ebd..b0bba0feef564 100644 +--- a/net/tipc/msg.c ++++ b/net/tipc/msg.c +@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) + + if (fragid == LAST_FRAGMENT) { + TIPC_SKB_CB(head)->validated = 0; +- if (unlikely(!tipc_msg_validate(&head))) ++ ++ /* If the reassembled skb has been freed in ++ * tipc_msg_validate() because of an invalid truesize, ++ * then head will point to a newly allocated reassembled ++ * skb, while *headbuf points to freed reassembled skb. ++ * In such cases, correct *headbuf for freeing the newly ++ * allocated reassembled skb later. ++ */ ++ if (unlikely(!tipc_msg_validate(&head))) { ++ if (head != *headbuf) ++ *headbuf = head; + goto err; ++ } ++ + *buf = head; + TIPC_SKB_CB(head)->tail = NULL; + *headbuf = NULL; +-- +2.53.0 + diff --git a/queue-6.12/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch b/queue-6.12/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch new file mode 100644 index 0000000000..afbb181493 --- /dev/null +++ b/queue-6.12/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch @@ -0,0 +1,69 @@ +From a04f9c900d9e4fd74acdb5d59f6fcc4e1eddd713 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 06:25:09 -0700 +Subject: tracing: branch: Fix inverted check on stat tracer registration + +From: Breno Leitao + +[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ] + +init_annotated_branch_stats() and all_annotated_branch_stats() check the +return value of register_stat_tracer() with "if (!ret)", but +register_stat_tracer() returns 0 on success and a negative errno on +failure. The inverted check causes the warning to be printed on every +successful registration, e.g.: + + Warning: could not register annotated branches stats + +while leaving real failures silent. The initcall also returned a +hard-coded 1 instead of the actual error. + +Invert the check and propagate ret so that the warning fires on real +errors and the initcall reports the correct status. + +Cc: Mathieu Desnoyers +Cc: Ingo Molnar +Cc: Frederic Weisbecker +Link: https://patch.msgid.link/20260420-tracing-v1-1-d8f4cd0d6af1@debian.org +Fixes: 002bb86d8d42 ("tracing/ftrace: separate events tracing and stats tracing engine") +Signed-off-by: Breno Leitao +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_branch.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c +index e47fdb4c92fbc..30f72e0ecb5d4 100644 +--- a/kernel/trace/trace_branch.c ++++ b/kernel/trace/trace_branch.c +@@ -379,10 +379,10 @@ __init static int init_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&annotated_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "annotated branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +@@ -444,10 +444,10 @@ __init static int all_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&all_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "all branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch b/queue-6.12/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch new file mode 100644 index 0000000000..6a7cef38f3 --- /dev/null +++ b/queue-6.12/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch @@ -0,0 +1,56 @@ +From 47c78fd0d057481e9a0b03666833f222fc4dc5a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 19:22:23 +0800 +Subject: tracing: Rebuild full_name on each hist_field_name() call + +From: Pengpeng Hou + +[ Upstream commit 5ec1d1e97de134beed3a5b08235a60fc1c51af96 ] + +hist_field_name() uses a static MAX_FILTER_STR_VAL buffer for fully +qualified variable-reference names, but it currently appends into that +buffer with strcat() without rebuilding it first. As a result, repeated +calls append a new "system.event.field" name onto the previous one, +which can eventually run past the end of full_name. + +Build the name with snprintf() on each call and return NULL if the fully +qualified name does not fit in MAX_FILTER_STR_VAL. + +Link: https://patch.msgid.link/20260401112224.85582-1-pengpeng@iscas.ac.cn +Fixes: 067fe038e70f ("tracing: Add variable reference handling to hist triggers") +Reviewed-by: Tom Zanussi +Tested-by: Tom Zanussi +Signed-off-by: Pengpeng Hou +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 83de1a196a4af..2d085115afde3 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -1342,12 +1342,14 @@ static const char *hist_field_name(struct hist_field *field, + field->flags & HIST_FIELD_FL_VAR_REF) { + if (field->system) { + static char full_name[MAX_FILTER_STR_VAL]; ++ int len; ++ ++ len = snprintf(full_name, sizeof(full_name), "%s.%s.%s", ++ field->system, field->event_name, ++ field->name); ++ if (len >= sizeof(full_name)) ++ return NULL; + +- strcat(full_name, field->system); +- strcat(full_name, "."); +- strcat(full_name, field->event_name); +- strcat(full_name, "."); +- strcat(full_name, field->name); + field_name = full_name; + } else + field_name = field->name; +-- +2.53.0 + diff --git a/queue-6.12/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch b/queue-6.12/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch new file mode 100644 index 0000000000..a8124cd5ad --- /dev/null +++ b/queue-6.12/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch @@ -0,0 +1,50 @@ +From fee1a85d8eaeff81e2940a68fc460527110a3c88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 23:29:37 -0800 +Subject: tty: hvc_iucv: fix off-by-one in number of supported devices + +From: Randy Dunlap + +[ Upstream commit f2a880e802ad12d1e38039d1334fb1475d0f5241 ] + +MAX_HVC_IUCV_LINES == HVC_ALLOC_TTY_ADAPTERS == 8. +This is the number of entries in: + static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; + +Sometimes hvc_iucv_table[] is limited by: +(a) if (num > hvc_iucv_devices) // for error detection +or +(b) for (i = 0; i < hvc_iucv_devices; i++) // in 2 places +(so these 2 don't agree; second one appears to be correct to me.) + +hvc_iucv_devices can be 0..8. This is a counter. +(c) if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + +If hvc_iucv_devices == 8, (a) allows the code to access hvc_iucv_table[8]. +Oops. + +Fixes: 44a01d5ba8a4 ("[S390] s390/hvc_console: z/VM IUCV hypervisor console support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260130072939.1535869-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index ed4bf40278a7e..a88722afa3731 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if (num > hvc_iucv_devices) ++ if (num >= hvc_iucv_devices) + return NULL; + return hvc_iucv_table[num]; + } +-- +2.53.0 + diff --git a/queue-6.12/tty-serial-ip22zilog-fix-section-mispatch-warning.patch b/queue-6.12/tty-serial-ip22zilog-fix-section-mispatch-warning.patch new file mode 100644 index 0000000000..f45472107d --- /dev/null +++ b/queue-6.12/tty-serial-ip22zilog-fix-section-mispatch-warning.patch @@ -0,0 +1,39 @@ +From 1bae4a48c0d9b7b838ac84839722f9a27690304f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 12:21:53 +0200 +Subject: tty: serial: ip22zilog: Fix section mispatch warning + +From: Thomas Bogendoerfer + +[ Upstream commit a1a81aef99e853dec84241d701fbf587d713eb5b ] + +ip22zilog_prepare() is now called by driver probe routine, so it +shouldn't be in the __init section any longer. + +Fixes: 3fc36ae6abd2 ("tty: serial: ip22zilog: Use platform device for probing") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604020945.c9jAvCPs-lkp@intel.com/ +Signed-off-by: Thomas Bogendoerfer +Link: https://patch.msgid.link/20260402102154.136620-1-tbogendoerfer@suse.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/ip22zilog.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c +index 6e19c6713849a..a12101dc05546 100644 +--- a/drivers/tty/serial/ip22zilog.c ++++ b/drivers/tty/serial/ip22zilog.c +@@ -1025,7 +1025,7 @@ static struct uart_driver ip22zilog_reg = { + #endif + }; + +-static void __init ip22zilog_prepare(struct uart_ip22zilog_port *up) ++static void ip22zilog_prepare(struct uart_ip22zilog_port *up) + { + unsigned char sysrq_on = IS_ENABLED(CONFIG_SERIAL_IP22_ZILOG_CONSOLE); + int brg; +-- +2.53.0 + diff --git a/queue-6.12/udp-force-compute_score-to-always-inline.patch b/queue-6.12/udp-force-compute_score-to-always-inline.patch new file mode 100644 index 0000000000..0743c14ed8 --- /dev/null +++ b/queue-6.12/udp-force-compute_score-to-always-inline.patch @@ -0,0 +1,125 @@ +From e945821b0073d86dbdb198438eb4d4790b6a9500 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:59:36 -0400 +Subject: udp: Force compute_score to always inline + +From: Gabriel Krisman Bertazi + +[ Upstream commit b80a95ccf1604a882bb153c45ccb4056e44c8edb ] + +Back in 2024 I reported a 7-12% regression on an iperf3 UDP loopback +thoughput test that we traced to the extra overhead of calling +compute_score on two places, introduced by commit f0ea27e7bfe1 ("udp: +re-score reuseport groups when connected sockets are present"). At the +time, I pointed out the overhead was caused by the multiple calls, +associated with cpu-specific mitigations, and merged commit +50aee97d1511 ("udp: Avoid call to compute_score on multiple sites") to +jump back explicitly, to force the rescore call in a single place. + +Recently though, we got another regression report against a newer distro +version, which a team colleague traced back to the same root-cause. +Turns out that once we updated to gcc-13, the compiler got smart enough +to unroll the loop, undoing my previous mitigation. Let's bite the +bullet and __always_inline compute_score on both ipv4 and ipv6 to +prevent gcc from de-optimizing it again in the future. These functions +are only called in two places each, udpX_lib_lookup1 and +udpX_lib_lookup2, so the extra size shouldn't be a problem and it is hot +enough to be very visible in profilings. In fact, with gcc13, forcing +the inline will prevent gcc from unrolling the fix from commit +50aee97d1511, so we don't end up increasing udpX_lib_lookup2 at all. + +I haven't recollected the results myself, as I don't have access to the +machine at the moment. But the same colleague reported 4.67% +inprovement with this patch in the loopback benchmark, solving the +regression report within noise margins. + +Eric Dumazet reported no size change to vmlinux when built with clang. +I report the same also with gcc-13: + +scripts/bloat-o-meter vmlinux vmlinux-inline +add/remove: 0/2 grow/shrink: 4/0 up/down: 616/-416 (200) +Function old new delta +udp6_lib_lookup2 762 949 +187 +__udp6_lib_lookup 810 975 +165 +udp4_lib_lookup2 757 906 +149 +__udp4_lib_lookup 871 986 +115 +__pfx_compute_score 32 - -32 +compute_score 384 - -384 +Total: Before=35011784, After=35011984, chg +0.00% + +Fixes: 50aee97d1511 ("udp: Avoid call to compute_score on multiple sites") +Reviewed-by: Eric Dumazet +Acked-by: Willem de Bruijn +Signed-off-by: Gabriel Krisman Bertazi +Link: https://patch.msgid.link/20260410155936.654915-1-krisman@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/udp.c | 12 ++++++------ + net/ipv6/udp.c | 13 +++++++------ + 2 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index 0d4a6abdfb963..865803caed742 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -366,10 +366,10 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum) + return udp_lib_get_port(sk, snum, hash2_nulladdr); + } + +-static int compute_score(struct sock *sk, const struct net *net, +- __be32 saddr, __be16 sport, +- __be32 daddr, unsigned short hnum, +- int dif, int sdif) ++static __always_inline int ++compute_score(struct sock *sk, const struct net *net, ++ __be32 saddr, __be16 sport, __be32 daddr, ++ unsigned short hnum, int dif, int sdif) + { + int score; + struct inet_sock *inet; +@@ -509,8 +509,8 @@ static struct sock *udp4_lib_lookup2(const struct net *net, + continue; + + /* compute_score is too long of a function to be +- * inlined, and calling it again here yields +- * measurable overhead for some ++ * inlined twice here, and calling it uninlined ++ * here yields measurable overhead for some + * workloads. Work around it by jumping + * backwards to rescore 'result'. + */ +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index bfda1f318b779..f6717b0d037d0 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -114,10 +114,11 @@ void udp_v6_rehash(struct sock *sk) + udp_lib_rehash(sk, new_hash); + } + +-static int compute_score(struct sock *sk, const struct net *net, +- const struct in6_addr *saddr, __be16 sport, +- const struct in6_addr *daddr, unsigned short hnum, +- int dif, int sdif) ++static __always_inline int ++compute_score(struct sock *sk, const struct net *net, ++ const struct in6_addr *saddr, __be16 sport, ++ const struct in6_addr *daddr, unsigned short hnum, ++ int dif, int sdif) + { + int bound_dev_if, score; + struct inet_sock *inet; +@@ -247,8 +248,8 @@ static struct sock *udp6_lib_lookup2(const struct net *net, + continue; + + /* compute_score is too long of a function to be +- * inlined, and calling it again here yields +- * measurable overhead for some ++ * inlined twice here, and calling it uninlined ++ * here yields measurable overhead for some + * workloads. Work around it by jumping + * backwards to rescore 'result'. + */ +-- +2.53.0 + diff --git a/queue-6.12/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch b/queue-6.12/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch new file mode 100644 index 0000000000..8251753619 --- /dev/null +++ b/queue-6.12/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch @@ -0,0 +1,91 @@ +From 506bb979fcac82411fcd71a235a0bc4ed19c116e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 11:39:59 -0800 +Subject: unshare: fix nsproxy leak in ksys_unshare() on set_cred_ucounts() + failure + +From: Michal Grzedzicki + +[ Upstream commit a98621a0f187a934c115dcfe79a49520ae892111 ] + +When set_cred_ucounts() fails in ksys_unshare() new_nsproxy is leaked. + +Let's call put_nsproxy() if that happens. + +Link: https://lkml.kernel.org/r/20260213193959.2556730-1-mge@meta.com +Fixes: 905ae01c4ae2 ("Add a reference to ucounts for each cred") +Signed-off-by: Michal Grzedzicki +Reviewed-by: Andrew Morton +Cc: Alexey Gladkov (Intel) +Cc: Ben Segall +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: "Liam R. Howlett" +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index c6415bb0abf59..c4955cffcb6f4 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -3348,11 +3348,10 @@ int ksys_unshare(unsigned long unshare_flags) + new_cred, new_fs); + if (err) + goto bad_unshare_cleanup_cred; +- + if (new_cred) { + err = set_cred_ucounts(new_cred); + if (err) +- goto bad_unshare_cleanup_cred; ++ goto bad_unshare_cleanup_nsproxy; + } + + if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { +@@ -3368,8 +3367,10 @@ int ksys_unshare(unsigned long unshare_flags) + shm_init_task(current); + } + +- if (new_nsproxy) ++ if (new_nsproxy) { + switch_task_namespaces(current, new_nsproxy); ++ new_nsproxy = NULL; ++ } + + task_lock(current); + +@@ -3398,13 +3399,15 @@ int ksys_unshare(unsigned long unshare_flags) + + perf_event_namespaces(current); + ++bad_unshare_cleanup_nsproxy: ++ if (new_nsproxy) ++ put_nsproxy(new_nsproxy); + bad_unshare_cleanup_cred: + if (new_cred) + put_cred(new_cred); + bad_unshare_cleanup_fd: + if (new_fd) + put_files_struct(new_fd); +- + bad_unshare_cleanup_fs: + if (new_fs) + free_fs_struct(new_fs); +-- +2.53.0 + diff --git a/queue-6.12/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch b/queue-6.12/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch new file mode 100644 index 0000000000..133c26e841 --- /dev/null +++ b/queue-6.12/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch @@ -0,0 +1,64 @@ +From 1bf85b9bd1652eb1d4ff661ff8802793cb5f3656 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 02:30:24 +0000 +Subject: vhost_net: fix sleeping with preempt-disabled in + vhost_net_busy_poll() + +From: Kohei Enju + +[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ] + +syzbot reported "sleeping function called from invalid context" in +vhost_net_busy_poll(). + +Commit 030881372460 ("vhost_net: basic polling support") introduced a +busy-poll loop and preempt_{disable,enable}() around it, where each +iteration calls a sleepable function inside the loop. + +The purpose of disabling preemption was to keep local_clock()-based +timeout accounting on a single CPU, rather than as a requirement of +busy-poll itself: + +https://lore.kernel.org/1448435489-5949-4-git-send-email-jasowang@redhat.com + +From this perspective, migrate_disable() is sufficient here, so replace +preempt_disable() with migrate_disable(), avoiding sleepable accesses +from a preempt-disabled context. + +Fixes: 030881372460 ("vhost_net: basic polling support") +Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/ +Signed-off-by: Kohei Enju +Acked-by: Michael S. Tsirkin +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/vhost/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index aff4ec7835628..3ad1a6f4ef965 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -549,7 +549,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + busyloop_timeout = poll_rx ? rvq->busyloop_timeout: + tvq->busyloop_timeout; + +- preempt_disable(); ++ migrate_disable(); + endtime = busy_clock() + busyloop_timeout; + + while (vhost_can_busy_poll(endtime)) { +@@ -566,7 +566,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + cpu_relax(); + } + +- preempt_enable(); ++ migrate_enable(); + + if (poll_rx || sock_has_rx_data(sock)) + vhost_net_busy_poll_try_queue(net, vq); +-- +2.53.0 + diff --git a/queue-6.12/virtio_net-fix-endian-with-virtio_net_ctrl_rss.patch b/queue-6.12/virtio_net-fix-endian-with-virtio_net_ctrl_rss.patch new file mode 100644 index 0000000000..adf90475d5 --- /dev/null +++ b/queue-6.12/virtio_net-fix-endian-with-virtio_net_ctrl_rss.patch @@ -0,0 +1,119 @@ +From 60d685b6b4e4db33a672d39b27ad2fec2f231e6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Mar 2025 15:48:33 +0900 +Subject: virtio_net: Fix endian with virtio_net_ctrl_rss + +From: Akihiko Odaki + +[ Upstream commit 97841341e302eac13d54eb5e968570b5626196a7 ] + +Mark the fields of struct virtio_net_ctrl_rss as little endian as +they are in struct virtio_net_rss_config, which it follows. + +Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.") +Signed-off-by: Akihiko Odaki +Acked-by: Jason Wang +Reviewed-by: Xuan Zhuo +Acked-by: Michael S. Tsirkin +Tested-by: Lei Yang +Link: https://patch.msgid.link/20250321-virtio-v2-2-33afb8f4640b@daynix.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 3bc06da858ef ("virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET") +Signed-off-by: Sasha Levin +--- + drivers/net/virtio_net.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 5c83983f0eb3f..05b50a4626b85 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -373,15 +373,15 @@ struct receive_queue { + */ + #define VIRTIO_NET_RSS_MAX_KEY_SIZE 40 + struct virtio_net_ctrl_rss { +- u32 hash_types; +- u16 indirection_table_mask; +- u16 unclassified_queue; +- u16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */ +- u16 max_tx_vq; ++ __le32 hash_types; ++ __le16 indirection_table_mask; ++ __le16 unclassified_queue; ++ __le16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */ ++ __le16 max_tx_vq; + u8 hash_key_length; + u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE]; + +- u16 *indirection_table; ++ __le16 *indirection_table; + }; + + /* Control VQ buffers: protected by the rtnl lock */ +@@ -3477,9 +3477,9 @@ static void virtnet_rss_update_by_qpairs(struct virtnet_info *vi, u16 queue_pair + + for (; i < vi->rss_indir_table_size; ++i) { + indir_val = ethtool_rxfh_indir_default(i, queue_pairs); +- vi->rss.indirection_table[i] = indir_val; ++ vi->rss.indirection_table[i] = cpu_to_le16(indir_val); + } +- vi->rss.max_tx_vq = queue_pairs; ++ vi->rss.max_tx_vq = cpu_to_le16(queue_pairs); + } + + static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) +@@ -3998,10 +3998,10 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi) + + static void virtnet_init_default_rss(struct virtnet_info *vi) + { +- vi->rss.hash_types = vi->rss_hash_types_supported; ++ vi->rss.hash_types = cpu_to_le32(vi->rss_hash_types_supported); + vi->rss_hash_types_saved = vi->rss_hash_types_supported; + vi->rss.indirection_table_mask = vi->rss_indir_table_size +- ? vi->rss_indir_table_size - 1 : 0; ++ ? cpu_to_le16(vi->rss_indir_table_size - 1) : 0; + vi->rss.unclassified_queue = 0; + + virtnet_rss_update_by_qpairs(vi, vi->curr_queue_pairs); +@@ -4119,7 +4119,7 @@ static bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc * + + if (new_hashtypes != vi->rss_hash_types_saved) { + vi->rss_hash_types_saved = new_hashtypes; +- vi->rss.hash_types = vi->rss_hash_types_saved; ++ vi->rss.hash_types = cpu_to_le32(vi->rss_hash_types_saved); + if (vi->dev->features & NETIF_F_RXHASH) + return virtnet_commit_rss_command(vi); + } +@@ -5291,7 +5291,7 @@ static int virtnet_get_rxfh(struct net_device *dev, + + if (rxfh->indir) { + for (i = 0; i < vi->rss_indir_table_size; ++i) +- rxfh->indir[i] = vi->rss.indirection_table[i]; ++ rxfh->indir[i] = le16_to_cpu(vi->rss.indirection_table[i]); + } + + if (rxfh->key) +@@ -5319,7 +5319,7 @@ static int virtnet_set_rxfh(struct net_device *dev, + return -EOPNOTSUPP; + + for (i = 0; i < vi->rss_indir_table_size; ++i) +- vi->rss.indirection_table[i] = rxfh->indir[i]; ++ vi->rss.indirection_table[i] = cpu_to_le16(rxfh->indir[i]); + update = true; + } + +@@ -5945,9 +5945,9 @@ static int virtnet_set_features(struct net_device *dev, + + if ((dev->features ^ features) & NETIF_F_RXHASH) { + if (features & NETIF_F_RXHASH) +- vi->rss.hash_types = vi->rss_hash_types_saved; ++ vi->rss.hash_types = cpu_to_le32(vi->rss_hash_types_saved); + else +- vi->rss.hash_types = VIRTIO_NET_HASH_REPORT_NONE; ++ vi->rss.hash_types = cpu_to_le32(VIRTIO_NET_HASH_REPORT_NONE); + + if (!virtnet_commit_rss_command(vi)) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.12/virtio_net-split-struct-virtio_net_rss_config.patch b/queue-6.12/virtio_net-split-struct-virtio_net_rss_config.patch new file mode 100644 index 0000000000..2e2aa381c2 --- /dev/null +++ b/queue-6.12/virtio_net-split-struct-virtio_net_rss_config.patch @@ -0,0 +1,54 @@ +From 19ce123f291696a147fd8c3c584c53ff93707ad9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Mar 2025 15:48:32 +0900 +Subject: virtio_net: Split struct virtio_net_rss_config + +From: Akihiko Odaki + +[ Upstream commit 976c2696b71da376d42e63ca3802eb2aafc164eb ] + +struct virtio_net_rss_config was less useful in actual code because of a +flexible array placed in the middle. Add new structures that split it +into two to avoid having a flexible array in the middle. + +Suggested-by: Jason Wang +Signed-off-by: Akihiko Odaki +Acked-by: Jason Wang +Reviewed-by: Xuan Zhuo +Acked-by: Michael S. Tsirkin +Tested-by: Lei Yang +Link: https://patch.msgid.link/20250321-virtio-v2-1-33afb8f4640b@daynix.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 3bc06da858ef ("virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/virtio_net.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h +index ac9174717ef13..963540deae66a 100644 +--- a/include/uapi/linux/virtio_net.h ++++ b/include/uapi/linux/virtio_net.h +@@ -327,6 +327,19 @@ struct virtio_net_rss_config { + __u8 hash_key_data[/* hash_key_length */]; + }; + ++struct virtio_net_rss_config_hdr { ++ __le32 hash_types; ++ __le16 indirection_table_mask; ++ __le16 unclassified_queue; ++ __le16 indirection_table[/* 1 + indirection_table_mask */]; ++}; ++ ++struct virtio_net_rss_config_trailer { ++ __le16 max_tx_vq; ++ __u8 hash_key_length; ++ __u8 hash_key_data[/* hash_key_length */]; ++}; ++ + #define VIRTIO_NET_CTRL_MQ_RSS_CONFIG 1 + + /* +-- +2.53.0 + diff --git a/queue-6.12/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch b/queue-6.12/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch new file mode 100644 index 0000000000..6a5a1fd76e --- /dev/null +++ b/queue-6.12/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch @@ -0,0 +1,63 @@ +From 73fb56d959685386b5516f0b80a316204a5569fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:21:21 -0700 +Subject: virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via + VQ_PAIRS_SET + +From: Brett Creeley + +[ Upstream commit 3bc06da858ef17cfe94b49efc0d9713727012835 ] + +When netif_is_rxfh_configured() is true (i.e., the user has explicitly +configured the RSS indirection table), virtnet_set_queues() skips the +RSS update path and falls through to the VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET +command to change the number of queue pairs. However, it does not update +vi->rss_trailer.max_tx_vq to reflect the new queue_pairs value. + +This causes a mismatch between vi->curr_queue_pairs and +vi->rss_trailer.max_tx_vq. Any subsequent RSS reconfiguration (e.g., +via ethtool -X) calls virtnet_commit_rss_command(), which sends the +stale max_tx_vq to the device, silently reverting the queue count. + +Reproduction: +1. User configured RSS + ethtool -X eth0 equal 8 +2. VQ_PAIRS_SET path; max_tx_vq stays 16 + ethtool -L eth0 combined 12 +3. RSS commit uses max_tx_vq=16 instead of 12 + ethtool -X eth0 equal 4 + +Fix this by updating vi->rss_trailer.max_tx_vq after a successful +VQ_PAIRS_SET command when RSS is enabled, keeping it in sync with +curr_queue_pairs. + +Fixes: 50bfcaedd78e ("virtio_net: Update rss when set queue") +Signed-off-by: Brett Creeley +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260416212121.29073-1-brett.creeley@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/virtio_net.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 7aa1832672942..324802cef40b4 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -3517,6 +3517,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) + queue_pairs); + return -EINVAL; + } ++ ++ /* Keep max_tx_vq in sync so that a later RSS command does not ++ * revert queue_pairs to a stale value. ++ */ ++ if (vi->has_rss) ++ vi->rss_trailer.max_tx_vq = cpu_to_le16(queue_pairs); + succ: + vi->curr_queue_pairs = queue_pairs; + /* virtnet_open() will refill when device is going to up. */ +-- +2.53.0 + diff --git a/queue-6.12/virtio_net-use-new-rss-config-structs.patch b/queue-6.12/virtio_net-use-new-rss-config-structs.patch new file mode 100644 index 0000000000..7496812072 --- /dev/null +++ b/queue-6.12/virtio_net-use-new-rss-config-structs.patch @@ -0,0 +1,285 @@ +From b8c353bb9af7e07099cbbd2c58415313a41b06c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Mar 2025 15:48:34 +0900 +Subject: virtio_net: Use new RSS config structs + +From: Akihiko Odaki + +[ Upstream commit ed3100e90d0d120a045a551b85eb43cf2527e885 ] + +The new RSS configuration structures allow easily constructing data for +VIRTIO_NET_CTRL_MQ_RSS_CONFIG as they strictly follow the order of data +for the command. + +Signed-off-by: Akihiko Odaki +Acked-by: Jason Wang +Reviewed-by: Xuan Zhuo +Acked-by: Michael S. Tsirkin +Tested-by: Lei Yang +Link: https://patch.msgid.link/20250321-virtio-v2-3-33afb8f4640b@daynix.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 3bc06da858ef ("virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET") +Signed-off-by: Sasha Levin +--- + drivers/net/virtio_net.c | 117 ++++++++++++++------------------------- + 1 file changed, 43 insertions(+), 74 deletions(-) + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 05b50a4626b85..7aa1832672942 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -365,24 +365,7 @@ struct receive_queue { + bool do_dma; + }; + +-/* This structure can contain rss message with maximum settings for indirection table and keysize +- * Note, that default structure that describes RSS configuration virtio_net_rss_config +- * contains same info but can't handle table values. +- * In any case, structure would be passed to virtio hw through sg_buf split by parts +- * because table sizes may be differ according to the device configuration. +- */ + #define VIRTIO_NET_RSS_MAX_KEY_SIZE 40 +-struct virtio_net_ctrl_rss { +- __le32 hash_types; +- __le16 indirection_table_mask; +- __le16 unclassified_queue; +- __le16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */ +- __le16 max_tx_vq; +- u8 hash_key_length; +- u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE]; +- +- __le16 *indirection_table; +-}; + + /* Control VQ buffers: protected by the rtnl lock */ + struct control_buf { +@@ -426,7 +409,9 @@ struct virtnet_info { + u16 rss_indir_table_size; + u32 rss_hash_types_supported; + u32 rss_hash_types_saved; +- struct virtio_net_ctrl_rss rss; ++ struct virtio_net_rss_config_hdr *rss_hdr; ++ struct virtio_net_rss_config_trailer rss_trailer; ++ u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE]; + + /* Has control virtqueue */ + bool has_cvq; +@@ -520,23 +505,16 @@ static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb, + struct page *page, void *buf, + int len, int truesize); + +-static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size) ++static size_t virtnet_rss_hdr_size(const struct virtnet_info *vi) + { +- if (!indir_table_size) { +- rss->indirection_table = NULL; +- return 0; +- } ++ u16 indir_table_size = vi->has_rss ? vi->rss_indir_table_size : 1; + +- rss->indirection_table = kmalloc_array(indir_table_size, sizeof(u16), GFP_KERNEL); +- if (!rss->indirection_table) +- return -ENOMEM; +- +- return 0; ++ return struct_size(vi->rss_hdr, indirection_table, indir_table_size); + } + +-static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss) ++static size_t virtnet_rss_trailer_size(const struct virtnet_info *vi) + { +- kfree(rss->indirection_table); ++ return struct_size(&vi->rss_trailer, hash_key_data, vi->rss_key_size); + } + + static bool is_xdp_frame(void *ptr) +@@ -3477,15 +3455,16 @@ static void virtnet_rss_update_by_qpairs(struct virtnet_info *vi, u16 queue_pair + + for (; i < vi->rss_indir_table_size; ++i) { + indir_val = ethtool_rxfh_indir_default(i, queue_pairs); +- vi->rss.indirection_table[i] = cpu_to_le16(indir_val); ++ vi->rss_hdr->indirection_table[i] = cpu_to_le16(indir_val); + } +- vi->rss.max_tx_vq = cpu_to_le16(queue_pairs); ++ vi->rss_trailer.max_tx_vq = cpu_to_le16(queue_pairs); + } + + static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) + { + struct virtio_net_ctrl_mq *mq __free(kfree) = NULL; +- struct virtio_net_ctrl_rss old_rss; ++ struct virtio_net_rss_config_hdr *old_rss_hdr; ++ struct virtio_net_rss_config_trailer old_rss_trailer; + struct net_device *dev = vi->dev; + struct scatterlist sg; + +@@ -3500,24 +3479,28 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) + * update (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET below) and return directly. + */ + if (vi->has_rss && !netif_is_rxfh_configured(dev)) { +- memcpy(&old_rss, &vi->rss, sizeof(old_rss)); +- if (rss_indirection_table_alloc(&vi->rss, vi->rss_indir_table_size)) { +- vi->rss.indirection_table = old_rss.indirection_table; ++ old_rss_hdr = vi->rss_hdr; ++ old_rss_trailer = vi->rss_trailer; ++ vi->rss_hdr = kzalloc(virtnet_rss_hdr_size(vi), GFP_KERNEL); ++ if (!vi->rss_hdr) { ++ vi->rss_hdr = old_rss_hdr; + return -ENOMEM; + } + ++ *vi->rss_hdr = *old_rss_hdr; + virtnet_rss_update_by_qpairs(vi, queue_pairs); + + if (!virtnet_commit_rss_command(vi)) { + /* restore ctrl_rss if commit_rss_command failed */ +- rss_indirection_table_free(&vi->rss); +- memcpy(&vi->rss, &old_rss, sizeof(old_rss)); ++ kfree(vi->rss_hdr); ++ vi->rss_hdr = old_rss_hdr; ++ vi->rss_trailer = old_rss_trailer; + + dev_warn(&dev->dev, "Fail to set num of queue pairs to %d, because committing RSS failed\n", + queue_pairs); + return -EINVAL; + } +- rss_indirection_table_free(&old_rss); ++ kfree(old_rss_hdr); + goto succ; + } + +@@ -3960,28 +3943,12 @@ static int virtnet_set_ringparam(struct net_device *dev, + static bool virtnet_commit_rss_command(struct virtnet_info *vi) + { + struct net_device *dev = vi->dev; +- struct scatterlist sgs[4]; +- unsigned int sg_buf_size; ++ struct scatterlist sgs[2]; + + /* prepare sgs */ +- sg_init_table(sgs, 4); +- +- sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved); +- sg_set_buf(&sgs[0], &vi->rss, sg_buf_size); +- +- if (vi->has_rss) { +- sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size; +- sg_set_buf(&sgs[1], vi->rss.indirection_table, sg_buf_size); +- } else { +- sg_set_buf(&sgs[1], &vi->rss.hash_cfg_reserved, sizeof(uint16_t)); +- } +- +- sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key) +- - offsetof(struct virtio_net_ctrl_rss, max_tx_vq); +- sg_set_buf(&sgs[2], &vi->rss.max_tx_vq, sg_buf_size); +- +- sg_buf_size = vi->rss_key_size; +- sg_set_buf(&sgs[3], vi->rss.key, sg_buf_size); ++ sg_init_table(sgs, 2); ++ sg_set_buf(&sgs[0], vi->rss_hdr, virtnet_rss_hdr_size(vi)); ++ sg_set_buf(&sgs[1], &vi->rss_trailer, virtnet_rss_trailer_size(vi)); + + if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ, + vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG +@@ -3998,17 +3965,17 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi) + + static void virtnet_init_default_rss(struct virtnet_info *vi) + { +- vi->rss.hash_types = cpu_to_le32(vi->rss_hash_types_supported); ++ vi->rss_hdr->hash_types = cpu_to_le32(vi->rss_hash_types_supported); + vi->rss_hash_types_saved = vi->rss_hash_types_supported; +- vi->rss.indirection_table_mask = vi->rss_indir_table_size ++ vi->rss_hdr->indirection_table_mask = vi->rss_indir_table_size + ? cpu_to_le16(vi->rss_indir_table_size - 1) : 0; +- vi->rss.unclassified_queue = 0; ++ vi->rss_hdr->unclassified_queue = 0; + + virtnet_rss_update_by_qpairs(vi, vi->curr_queue_pairs); + +- vi->rss.hash_key_length = vi->rss_key_size; ++ vi->rss_trailer.hash_key_length = vi->rss_key_size; + +- netdev_rss_key_fill(vi->rss.key, vi->rss_key_size); ++ netdev_rss_key_fill(vi->rss_hash_key_data, vi->rss_key_size); + } + + static void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info) +@@ -4119,7 +4086,7 @@ static bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc * + + if (new_hashtypes != vi->rss_hash_types_saved) { + vi->rss_hash_types_saved = new_hashtypes; +- vi->rss.hash_types = cpu_to_le32(vi->rss_hash_types_saved); ++ vi->rss_hdr->hash_types = cpu_to_le32(vi->rss_hash_types_saved); + if (vi->dev->features & NETIF_F_RXHASH) + return virtnet_commit_rss_command(vi); + } +@@ -5291,11 +5258,11 @@ static int virtnet_get_rxfh(struct net_device *dev, + + if (rxfh->indir) { + for (i = 0; i < vi->rss_indir_table_size; ++i) +- rxfh->indir[i] = le16_to_cpu(vi->rss.indirection_table[i]); ++ rxfh->indir[i] = le16_to_cpu(vi->rss_hdr->indirection_table[i]); + } + + if (rxfh->key) +- memcpy(rxfh->key, vi->rss.key, vi->rss_key_size); ++ memcpy(rxfh->key, vi->rss_hash_key_data, vi->rss_key_size); + + rxfh->hfunc = ETH_RSS_HASH_TOP; + +@@ -5319,7 +5286,7 @@ static int virtnet_set_rxfh(struct net_device *dev, + return -EOPNOTSUPP; + + for (i = 0; i < vi->rss_indir_table_size; ++i) +- vi->rss.indirection_table[i] = cpu_to_le16(rxfh->indir[i]); ++ vi->rss_hdr->indirection_table[i] = cpu_to_le16(rxfh->indir[i]); + update = true; + } + +@@ -5331,7 +5298,7 @@ static int virtnet_set_rxfh(struct net_device *dev, + if (!vi->has_rss && !vi->has_rss_hash_report) + return -EOPNOTSUPP; + +- memcpy(vi->rss.key, rxfh->key, vi->rss_key_size); ++ memcpy(vi->rss_hash_key_data, rxfh->key, vi->rss_key_size); + update = true; + } + +@@ -5945,9 +5912,9 @@ static int virtnet_set_features(struct net_device *dev, + + if ((dev->features ^ features) & NETIF_F_RXHASH) { + if (features & NETIF_F_RXHASH) +- vi->rss.hash_types = cpu_to_le32(vi->rss_hash_types_saved); ++ vi->rss_hdr->hash_types = cpu_to_le32(vi->rss_hash_types_saved); + else +- vi->rss.hash_types = cpu_to_le32(VIRTIO_NET_HASH_REPORT_NONE); ++ vi->rss_hdr->hash_types = cpu_to_le32(VIRTIO_NET_HASH_REPORT_NONE); + + if (!virtnet_commit_rss_command(vi)) + return -EINVAL; +@@ -6619,9 +6586,11 @@ static int virtnet_probe(struct virtio_device *vdev) + virtio_cread16(vdev, offsetof(struct virtio_net_config, + rss_max_indirection_table_length)); + } +- err = rss_indirection_table_alloc(&vi->rss, vi->rss_indir_table_size); +- if (err) ++ vi->rss_hdr = kzalloc(virtnet_rss_hdr_size(vi), GFP_KERNEL); ++ if (!vi->rss_hdr) { ++ err = -ENOMEM; + goto free; ++ } + + if (vi->has_rss || vi->has_rss_hash_report) { + vi->rss_key_size = +@@ -6900,7 +6869,7 @@ static void virtnet_remove(struct virtio_device *vdev) + + remove_vq_common(vi); + +- rss_indirection_table_free(&vi->rss); ++ kfree(vi->rss_hdr); + + free_netdev(vi->dev); + } +-- +2.53.0 + diff --git a/queue-6.12/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch b/queue-6.12/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch new file mode 100644 index 0000000000..8b01a070f4 --- /dev/null +++ b/queue-6.12/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch @@ -0,0 +1,115 @@ +From 5d8df2e4bd712477ac1900286cfb45a55354e4ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 09:36:07 +0300 +Subject: vrf: Fix a potential NPD when removing a port from a VRF + +From: Ido Schimmel + +[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ] + +RCU readers that identified a net device as a VRF port using +netif_is_l3_slave() assume that a subsequent call to +netdev_master_upper_dev_get_rcu() will return a VRF device. They then +continue to dereference its l3mdev operations. + +This assumption is not always correct and can result in a NPD [1]. There +is no RCU synchronization when removing a port from a VRF, so it is +possible for an RCU reader to see a new master device (e.g., a bridge) +that does not have l3mdev operations. + +Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE +flag. Skip this synchronization when a net device is removed from a VRF +as part of its deletion and when the VRF device itself is deleted. In +the latter case an RCU grace period will pass by the time RTNL is +released. + +[1] +BUG: kernel NULL pointer dereference, address: 0000000000000000 +[...] +RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) +[...] +Call Trace: + +l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) +__inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) +inet_bind_sk (net/ipv4/af_inet.c:469) +__sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) +__x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Fixes: fdeea7be88b1 ("net: vrf: Set slave's private flag before linking") +Reported-by: Haoze Xie +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/netdev/20260419145332.3988923-1-n05ec@lzu.edu.cn/ +Signed-off-by: Ido Schimmel +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260423063607.1208202-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vrf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index b62462d8eff26..93ecd9577f4d3 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -1104,6 +1104,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + + err: + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ synchronize_net(); + return ret; + } + +@@ -1123,10 +1124,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + } + + /* inverse of do_vrf_add_slave */ +-static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) ++static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, ++ bool needs_sync) + { + netdev_upper_dev_unlink(port_dev, dev); + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ /* Make sure that concurrent RCU readers that identified the device ++ * as a VRF port see a VRF master or no master at all. ++ */ ++ if (needs_sync) ++ synchronize_net(); + + cycle_netdev(port_dev, NULL); + +@@ -1135,7 +1142,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + + static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + { +- return do_vrf_del_slave(dev, port_dev); ++ return do_vrf_del_slave(dev, port_dev, true); + } + + static void vrf_dev_uninit(struct net_device *dev) +@@ -1691,7 +1698,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) + struct list_head *iter; + + netdev_for_each_lower_dev(dev, port_dev, iter) +- vrf_del_slave(dev, port_dev); ++ do_vrf_del_slave(dev, port_dev, false); + + vrf_map_unregister_dev(dev); + +@@ -1822,7 +1829,7 @@ static int vrf_device_event(struct notifier_block *unused, + goto out; + + vrf_dev = netdev_master_upper_dev_get(dev); +- vrf_del_slave(vrf_dev, dev); ++ do_vrf_del_slave(vrf_dev, dev, false); + } + out: + return NOTIFY_DONE; +-- +2.53.0 + diff --git a/queue-6.12/wifi-ath10k-fix-station-lookup-failure-during-discon.patch b/queue-6.12/wifi-ath10k-fix-station-lookup-failure-during-discon.patch new file mode 100644 index 0000000000..0d1fd883fe --- /dev/null +++ b/queue-6.12/wifi-ath10k-fix-station-lookup-failure-during-discon.patch @@ -0,0 +1,140 @@ +From 0734e9a1a326197d5827801c5e06c5c0cafe2e4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:05:01 +0800 +Subject: wifi: ath10k: fix station lookup failure during disconnect + +From: Baochen Qiang + +[ Upstream commit 9a34a59c6086ae731a06b3e61b0951feef758648 ] + +Recent commit [1] moved station statistics collection to an earlier stage +of the disconnect flow. With this change in place, ath10k fails to resolve +the station entry when handling a peer stats event triggered during +disconnect, resulting in log messages such as: + +wlp58s0: deauthenticating from 74:1a:e0:e7:b4:c8 by local choice (Reason: 3=DEAUTH_LEAVING) +ath10k_pci 0000:3a:00.0: not found station for peer stats +ath10k_pci 0000:3a:00.0: failed to parse stats info tlv: -22 + +The failure occurs because ath10k relies on ieee80211_find_sta_by_ifaddr() +for station lookup. That function uses local->sta_hash, but by the time +the peer stats request is triggered during disconnect, mac80211 has +already removed the station from that hash table, leading to lookup +failure. + +Before commit [1], this issue was not visible because the transition from +IEEE80211_STA_NONE to IEEE80211_STA_NOTEXIST prevented ath10k from sending +a peer stats request at all: ath10k_mac_sta_get_peer_stats_info() would +fail early to find the peer and skip requesting statistics. + +Fix this by switching the lookup path to ath10k_peer_find(), which queries +ath10k's internal peer table. At the point where the firmware emits the +peer stats event, the peer entry is still present in the driver's list, +ensuring lookup succeeds. + +Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00309-QCARMSWPZ-1 + +Fixes: a203dbeeca15 ("wifi: mac80211: collect station statistics earlier when disconnect") # [1] +Reported-by: Paul Menzel +Closes: https://lore.kernel.org/ath10k/57671b89-ec9f-4e6c-992c-45eb8e75929c@molgen.mpg.de +Signed-off-by: Baochen Qiang +Reviewed-by: Rameshkumar Sundaram +Reviewed-by: Paul Menzel +Tested-by: Paul Menzel +Link: https://patch.msgid.link/20260325-ath10k-station-lookup-failure-v1-1-2e0c970f25d5@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/wmi-tlv.c | 26 +++++++++++++---------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +index 16d07d619b4df..ba1294c8ee39f 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +@@ -3,7 +3,7 @@ + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +- * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + #include "core.h" + #include "debug.h" +@@ -14,6 +14,7 @@ + #include "wmi-tlv.h" + #include "p2p.h" + #include "testmode.h" ++#include "txrx.h" + #include + + /***************/ +@@ -224,8 +225,9 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 + const void *ptr, void *data) + { + const struct wmi_tlv_peer_stats_info *stat = ptr; +- struct ieee80211_sta *sta; ++ u32 vdev_id = *(u32 *)data; + struct ath10k_sta *arsta; ++ struct ath10k_peer *peer; + + if (tag != WMI_TLV_TAG_STRUCT_PEER_STATS_INFO) + return -EPROTO; +@@ -241,20 +243,20 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 + __le32_to_cpu(stat->last_tx_rate_code), + __le32_to_cpu(stat->last_tx_bitrate_kbps)); + +- rcu_read_lock(); +- sta = ieee80211_find_sta_by_ifaddr(ar->hw, stat->peer_macaddr.addr, NULL); +- if (!sta) { +- rcu_read_unlock(); +- ath10k_warn(ar, "not found station for peer stats\n"); ++ guard(spinlock_bh)(&ar->data_lock); ++ ++ peer = ath10k_peer_find(ar, vdev_id, stat->peer_macaddr.addr); ++ if (!peer || !peer->sta) { ++ ath10k_warn(ar, "not found %s with vdev id %u mac addr %pM for peer stats\n", ++ peer ? "sta" : "peer", vdev_id, stat->peer_macaddr.addr); + return -EINVAL; + } + +- arsta = (struct ath10k_sta *)sta->drv_priv; ++ arsta = (struct ath10k_sta *)peer->sta->drv_priv; + arsta->rx_rate_code = __le32_to_cpu(stat->last_rx_rate_code); + arsta->rx_bitrate_kbps = __le32_to_cpu(stat->last_rx_bitrate_kbps); + arsta->tx_rate_code = __le32_to_cpu(stat->last_tx_rate_code); + arsta->tx_bitrate_kbps = __le32_to_cpu(stat->last_tx_bitrate_kbps); +- rcu_read_unlock(); + + return 0; + } +@@ -266,6 +268,7 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar, + const struct wmi_tlv_peer_stats_info_ev *ev; + const void *data; + u32 num_peer_stats; ++ u32 vdev_id; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +@@ -284,15 +287,16 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar, + } + + num_peer_stats = __le32_to_cpu(ev->num_peers); ++ vdev_id = __le32_to_cpu(ev->vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv peer stats info update peer vdev id %d peers %i more data %d\n", +- __le32_to_cpu(ev->vdev_id), ++ vdev_id, + num_peer_stats, + __le32_to_cpu(ev->more_data)); + + ret = ath10k_wmi_tlv_iter(ar, data, ath10k_wmi_tlv_len(data), +- ath10k_wmi_tlv_parse_peer_stats_info, NULL); ++ ath10k_wmi_tlv_parse_peer_stats_info, &vdev_id); + if (ret) + ath10k_warn(ar, "failed to parse stats info tlv: %d\n", ret); + +-- +2.53.0 + diff --git a/queue-6.12/wifi-brcmfmac-fix-error-pointer-dereference.patch b/queue-6.12/wifi-brcmfmac-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..6a1ebc7323 --- /dev/null +++ b/queue-6.12/wifi-brcmfmac-fix-error-pointer-dereference.patch @@ -0,0 +1,80 @@ +From 19c2ff3bc097c2611372f7984c1d5c2cc9aa4c08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 20:30:43 -0600 +Subject: wifi: brcmfmac: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit dd8592fc6007a451c3e4b9025de365e39de8178a ] + +The function brcmf_chip_add_core() can return an error pointer and is +not checked. Add checks for error pointer. + +Detected by Smatch: +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1010 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1013 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1016 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1019 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1022 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +Fixes: cb7cf7be9eba7 ("brcmfmac: make chip related functions host interface independent") +Signed-off-by: Ethan Tidmore +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260217023043.73631-1-ethantidmore06@gmail.com +[add missing wifi: prefix] +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 2ef92ef25517e..4dbb1898f3065 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -1006,18 +1006,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + + core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, + SI_ENUM_BASE_DEFAULT, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, + BCM4329_CORE_BUS_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, + BCM4329_CORE_SOCRAM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, + BCM4329_CORE_ARM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + + core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + } else if (socitype == SOCI_AI) { + ci->iscoreup = brcmf_chip_ai_iscoreup; +-- +2.53.0 + diff --git a/queue-6.12/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch b/queue-6.12/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch new file mode 100644 index 0000000000..14d0a326c9 --- /dev/null +++ b/queue-6.12/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch @@ -0,0 +1,46 @@ +From 0e2279a66ec6a42b7e9f5b14791c2d47ec975908 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:02:56 +0100 +Subject: wifi: mac80211: handle VHT EXT NSS in + ieee80211_determine_our_sta_mode() + +From: Nicolas Escande + +[ Upstream commit b5b8e295973083abf823fb66647a7c702a8db8a7 ] + +A station which has a NSS ratio on the number of streams it is capable of +in 160MHz VHT operation is supposed to use the 'Extended NSS BW Support' +as defined by section '9.4.2.156.2 VHT Capabilities Information field'. + +This was missing in ieee80211_determine_our_sta_mode() and so we would +wrongfully downgrade our bandwidth when connecting to an AP that supported +160MHz with messages such as: + + [ 37.638346] wlan1: AP XX:XX:XX:XX:XX:XX changed bandwidth in assoc response, new used config is 5280.000 MHz, width 3 (5290.000/0 MHz) + +Fixes: 310c8387c638 ("wifi: mac80211: clean up connection process") +Signed-off-by: Nicolas Escande +Link: https://patch.msgid.link/20260327100256.3101348-1-nico.escande@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 835316fd3cd76..20e5f513a27a3 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -5304,7 +5304,8 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata, + + if (is_5ghz && + !(vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | +- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { ++ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | ++ IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))) { + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80; + mlme_link_id_dbg(sdata, link_id, + "no VHT 160 MHz capability on 5 GHz, limiting to 80 MHz"); +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7615-fix-use_cts_prot-support.patch b/queue-6.12/wifi-mt76-mt7615-fix-use_cts_prot-support.patch new file mode 100644 index 0000000000..bc9458e6a3 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7615-fix-use_cts_prot-support.patch @@ -0,0 +1,173 @@ +From 507558c677180fe8874c5b89ffc8facde5242f51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 09:41:56 -0800 +Subject: wifi: mt76: mt7615: fix use_cts_prot support + +From: Ryder Lee + +[ Upstream commit 1974a67d9b65c29a0a9426e32e8cd8c056de48b7 ] + +Driver should not directly write WTBL to prevent overwritten issues. + +With this fix, when driver needs to adjust its behavior for compatibility, +especially concerning older 11g/n devices, by enabling or disabling CTS +protection frames, often for hidden SSIDs or to manage legacy clients. + +Fixes: e34235ccc5e3 ("wifi: mt76: mt7615: enable use_cts_prot support") +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/edb87088b0111b32fafc6c4179f54a5286dd37d8.1768879119.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7615/mac.c | 15 ------ + .../net/wireless/mediatek/mt76/mt7615/main.c | 7 +-- + .../net/wireless/mediatek/mt76/mt7615/mcu.c | 47 +++++++++++++++++++ + .../wireless/mediatek/mt76/mt7615/mt7615.h | 5 +- + .../net/wireless/mediatek/mt76/mt7615/regs.h | 2 - + 5 files changed, 53 insertions(+), 23 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +index 7ba789834e8df..1e473f490b4bd 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +@@ -1174,21 +1174,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, + } + EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); + +-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, +- struct ieee80211_vif *vif, bool enable) +-{ +- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; +- u32 addr; +- +- addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4; +- +- if (enable) +- mt76_set(dev, addr, MT_WTBL_W3_RTS); +- else +- mt76_clear(dev, addr, MT_WTBL_W3_RTS); +-} +-EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); +- + static int + mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c +index 4f0c840ef93de..f747285a1a5dd 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c +@@ -584,9 +584,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, + } + } + +- if (changed & BSS_CHANGED_ERP_CTS_PROT) +- mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot); +- + if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { + mt7615_mcu_add_bss_info(phy, vif, NULL, true); + mt7615_mcu_sta_add(phy, vif, NULL, true); +@@ -599,6 +596,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, + BSS_CHANGED_BEACON_ENABLED)) + mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); + ++ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) ++ mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode, ++ info->use_cts_prot); ++ + if (changed & BSS_CHANGED_PS) + mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +index 40e15a0ba95a9..ac831422d4c77 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +@@ -2564,3 +2564,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, + return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), + &req, sizeof(req), false); + } ++ ++int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot) ++{ ++ struct mt7615_dev *dev = phy->dev; ++ struct { ++ u8 prot_idx; ++ u8 band; ++ u8 rsv[2]; ++ ++ bool long_nav; ++ bool prot_mm; ++ bool prot_gf; ++ bool prot_bw40; ++ bool prot_rifs; ++ bool prot_bw80; ++ bool prot_bw160; ++ u8 prot_erp_mask; ++ } __packed req = { ++ .prot_idx = 0x2, ++ .band = phy != &dev->phy, ++ }; ++ ++ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: ++ req.prot_mm = true; ++ req.prot_gf = true; ++ fallthrough; ++ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: ++ req.prot_bw40 = true; ++ break; ++ } ++ ++ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) ++ req.prot_gf = true; ++ ++ if (use_cts_prot) { ++ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; ++ u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; ++ ++ req.prot_erp_mask = BIT(i); ++ } ++ ++ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req, ++ sizeof(req), true); ++} +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +index 530da48ce3ea9..aac748fee257f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +@@ -466,8 +466,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy); + void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); + void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); + void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); +-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, +- struct ieee80211_vif *vif, bool enable); + void mt7615_mac_sta_poll(struct mt7615_dev *dev); + int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, +@@ -522,7 +520,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); + int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); + int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); + int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); +- ++int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot); + int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +index 806b3887c541c..9e6d55c91b269 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +@@ -455,8 +455,6 @@ enum mt7615_reg_base { + #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) + #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) + +-#define MT_WTBL_W3_RTS BIT(22) +- + #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) + #define MT_WTBL_W5_SHORT_GI_20 BIT(8) + #define MT_WTBL_W5_SHORT_GI_40 BIT(9) +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch b/queue-6.12/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch new file mode 100644 index 0000000000..3c60313521 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch @@ -0,0 +1,53 @@ +From e6d47503845da29647e276b4d26cb782aa232809 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 22:57:59 +0800 +Subject: wifi: mt76: mt7915: fix use-after-free bugs in mt7915_mac_dump_work() + +From: Duoming Zhou + +[ Upstream commit 1146d0946b5358fad24812bd39d68f31cd40cc34 ] + +When the mt7915 pci chip is detaching, the mt7915_crash_data is +released in mt7915_coredump_unregister(). However, the work item +dump_work may still be running or pending, leading to UAF bugs +when the already freed crash_data is dereferenced again in +mt7915_mac_dump_work(). + +The race condition can occur as follows: + +CPU 0 (removal path) | CPU 1 (workqueue) +mt7915_pci_remove() | mt7915_sys_recovery_set() + mt7915_unregister_device() | mt7915_reset() + mt7915_coredump_unregister() | queue_work() + vfree(dev->coredump.crash_data) | mt7915_mac_dump_work() + | crash_data-> // UAF + +Fix this by ensuring dump_work is properly canceled before +the crash_data is deallocated. Add cancel_work_sync() in +mt7915_unregister_device() to synchronize with any pending +or executing dump work. + +Fixes: 4dbcb9125cc3 ("wifi: mt76: mt7915: enable coredump support") +Signed-off-by: Duoming Zhou +Link: https://patch.msgid.link/20260130145759.84272-1-duoming@zju.edu.cn +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +index 83f062fb95d5a..b2220ff7d6758 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -1275,6 +1275,7 @@ int mt7915_register_device(struct mt7915_dev *dev) + + void mt7915_unregister_device(struct mt7915_dev *dev) + { ++ cancel_work_sync(&dev->dump_work); + mt7915_unregister_ext_phy(dev); + mt7915_coredump_unregister(dev); + mt7915_unregister_thermal(&dev->phy); +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7915-fix-use_cts_prot-support.patch b/queue-6.12/wifi-mt76-mt7915-fix-use_cts_prot-support.patch new file mode 100644 index 0000000000..163291ae70 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7915-fix-use_cts_prot-support.patch @@ -0,0 +1,195 @@ +From 74e73f5737b5f2bb0b3ff1f19410fe09ea333774 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 09:41:57 -0800 +Subject: wifi: mt76: mt7915: fix use_cts_prot support + +From: Ryder Lee + +[ Upstream commit 8b2c26562b95c6397e132d21f2bd3d73aaee0c0a ] + +With this fix, when driver needs to adjust its behavior for compatibility, +especially concerning older 11g/n devices, by enabling or disabling CTS +protection frames, often for hidden SSIDs or to manage legacy clients. + +Fixes: 150b91419d3d ("wifi: mt76: mt7915: enable use_cts_prot support") +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/eb8db4d0bf1c89b7486e89facb788ae3e510dd8b.1768879119.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7915/mac.c | 13 ---- + .../net/wireless/mediatek/mt76/mt7915/main.c | 7 ++- + .../net/wireless/mediatek/mt76/mt7915/mcu.c | 62 +++++++++++++++++++ + .../net/wireless/mediatek/mt76/mt7915/mcu.h | 11 ++++ + .../wireless/mediatek/mt76/mt7915/mt7915.h | 4 ++ + 5 files changed, 81 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +index 799e8d2cc7e6e..ab31a350ca735 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +@@ -235,19 +235,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) + rcu_read_unlock(); + } + +-void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, +- struct ieee80211_vif *vif, bool enable) +-{ +- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; +- u32 addr; +- +- addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); +- if (enable) +- mt76_set(dev, addr, BIT(5)); +- else +- mt76_clear(dev, addr, BIT(5)); +-} +- + static void + mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, + struct mt7915_sta *msta, struct sk_buff *skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +index 8c0d63cebf3e1..f49dcdde3f2c6 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +@@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw) + if (ret) + goto out; + +- ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, ++ ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES, + phy->mt76->band_idx); + if (ret) + goto out; +@@ -630,8 +630,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + if (set_sta == 1) + mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); + +- if (changed & BSS_CHANGED_ERP_CTS_PROT) +- mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); ++ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) ++ mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode, ++ info->use_cts_prot); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +index 7b481aea76b6c..2489364110d6e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -3799,6 +3799,68 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, + return ret; + } + ++int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot) ++{ ++ struct mt7915_dev *dev = phy->dev; ++ int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot); ++ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; ++ struct bss_info_prot *prot; ++ struct sk_buff *skb; ++ struct tlv *tlv; ++ enum { ++ PROT_NONMEMBER = BIT(1), ++ PROT_20MHZ = BIT(2), ++ PROT_NONHT_MIXED = BIT(3), ++ PROT_LEGACY_ERP = BIT(5), ++ PROT_NONGF_STA = BIT(7), ++ }; ++ u32 rts_threshold; ++ ++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, ++ NULL, len); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO, ++ sizeof(*prot)); ++ prot = (struct bss_info_prot *)tlv; ++ ++ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: ++ prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); ++ break; ++ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: ++ prot->prot_mode = cpu_to_le32(PROT_20MHZ); ++ break; ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: ++ prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); ++ break; ++ } ++ ++ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) ++ prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); ++ ++ if (use_cts_prot) ++ prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); ++ ++ /* reuse current RTS setting */ ++ rts_threshold = phy->mt76->hw->wiphy->rts_threshold; ++ if (rts_threshold == (u32)-1) ++ prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES); ++ else ++ prot->rts_len_thres = cpu_to_le32(rts_threshold); ++ ++ prot->rts_pkt_thres = 0x2; ++ ++ prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); ++ if (!prot->he_rts_thres) ++ prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); ++ ++ return mt76_mcu_skb_send_msg(&dev->mt76, skb, ++ MCU_EXT_CMD(BSS_INFO_UPDATE), true); ++} ++ + int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct cfg80211_he_bss_color *he_bss_color) + { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +index 49476a4182fd1..b7e26c2409444 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +@@ -399,6 +399,17 @@ struct bss_info_inband_discovery { + __le16 prob_rsp_len; + } __packed __aligned(4); + ++struct bss_info_prot { ++ __le16 tag; ++ __le16 len; ++ __le32 prot_type; ++ __le32 prot_mode; ++ __le32 rts_len_thres; ++ __le16 he_rts_thres; ++ u8 rts_pkt_thres; ++ u8 rsv[5]; ++} __packed; ++ + enum { + BSS_INFO_BCN_CSA, + BSS_INFO_BCN_BCC, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +index 5fe872ef2e939..f49d6b2f81e42 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +@@ -83,6 +83,8 @@ + #define MT7915_CRIT_TEMP 110 + #define MT7915_MAX_TEMP 120 + ++#define MT7915_RTS_LEN_THRES 0x92b ++ + struct mt7915_vif; + struct mt7915_sta; + struct mt7915_dfs_pulse; +@@ -458,6 +460,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v + u32 changed); + int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int enable, u32 changed); ++int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot); + int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd); + int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch b/queue-6.12/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch new file mode 100644 index 0000000000..cbdf9ff8a0 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch @@ -0,0 +1,39 @@ +From 7b1a63a4aa0968dc3362437f375c609e7fe7194a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 17:50:25 +0800 +Subject: wifi: mt76: mt7921: fix 6GHz regulatory update on connection + +From: Michael Lo + +[ Upstream commit 3dc0c40d7806c72cfe88cf4e1e2650c1673f9db4 ] + +Call mt7921_regd_update() instead of mt7921_mcu_set_clc() when setting +the 6GHz power type after connection, so that regulatory limits and SAR +power are also applied. + +Fixes: 51ba0e3a15eb ("wifi: mt76: mt7921: add 6GHz power type support for clc") +Signed-off-by: Michael Lo +Link: https://patch.msgid.link/20260211095025.2415624-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index 6ed2edd054b55..a93ae4e44f16a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -791,7 +791,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) + } + + out: +- mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env); ++ if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ) ++ mt7921_regd_update(dev); + } + + int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch b/queue-6.12/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch new file mode 100644 index 0000000000..a627b6b217 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch @@ -0,0 +1,73 @@ +From b81585e29777b06dd266b09fde625c0dfc412736 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Sep 2025 17:07:11 -0700 +Subject: wifi: mt76: mt7921: Place upper limit on station AID + +From: Rory Little + +[ Upstream commit 4d0bf21e3e20619d51d06c0c36207aabab8b712c ] + +Any station configured with an AID over 20 causes a firmware crash. +This situation occurred in our testing using an AP interface on 7922 +hardware, with a modified hostapd, sourced from Mediatek's OpenWRT +feeds. + +In stock hostapd, station AIDs begin counting at 1, and this +configuration is prevented with an upper limit on associated stations. +However, the modified hostapd began allocation at 65, which caused the +firmware to crash. This fix does not allow these AIDs to work, but will +prevent the firmware crash. + +This crash was only seen on IFTYPE_AP interfaces, and the fix does not +appear to have an effect on IFTYPE_STATION behavior. + +Fixes: 5c14a5f944b9 ("mt76: mt7921: introduce mt7921e support") +Signed-off-by: Rory Little +Link: https://patch.msgid.link/20250904000711.3033860-1-rory@candelatech.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 6 ++++++ + drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++ + 2 files changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index bc823a7c09bba..6ed2edd054b55 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -802,6 +802,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + int ret, idx; + ++ if (sta->aid > MT7921_MAX_AID) ++ return -ENOENT; ++ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); + if (idx < 0) + return -ENOSPC; +@@ -845,6 +848,9 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + ++ if (sta->aid > MT7921_MAX_AID) ++ return -ENOENT; ++ + if (ev != MT76_STA_EVENT_ASSOC) + return 0; + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +index 16c89815c0b8a..7a7e09fcf4b5e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +@@ -7,6 +7,8 @@ + #include "../mt792x.h" + #include "regs.h" + ++#define MT7921_MAX_AID 20 ++ + #define MT7921_TX_RING_SIZE 2048 + #define MT7921_TX_MCU_RING_SIZE 256 + #define MT7921_TX_FWDL_RING_SIZE 128 +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch b/queue-6.12/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch new file mode 100644 index 0000000000..2b37fe29ea --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch @@ -0,0 +1,43 @@ +From 8d721f1e0c93526f60698cb5a4d04e2960920133 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 18:59:30 -0600 +Subject: wifi: mt76: mt7921: Reset ampdu_state state in case of failure in + mt76_connac2_tx_check_aggr() + +From: Sean Wang + +[ Upstream commit 53ffffeb9624ffab6d9a3b1da8635a23f1172b5e ] + +Reset ampdu_state if ieee80211_start_tx_ba_session() fails in +mt76_connac2_tx_check_aggr(), otherwise the driver may incorrectly +assume aggregation is active and skip future BA setup attempts. + +Fixes: 163f4d22c118 ("mt76: mt7921: add MAC support") +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20251216005930.9412-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +index 268f414f0a023..05f2ff8e012b5 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +@@ -1135,8 +1135,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) + return; + + wcid = (struct mt76_wcid *)sta->drv_priv; +- if (!test_and_set_bit(tid, &wcid->ampdu_state)) +- ieee80211_start_tx_ba_session(sta, tid, 0); ++ if (!test_and_set_bit(tid, &wcid->ampdu_state)) { ++ if (ieee80211_start_tx_ba_session(sta, tid, 0)) ++ clear_bit(tid, &wcid->ampdu_state); ++ } + } + EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); + +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch b/queue-6.12/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch new file mode 100644 index 0000000000..c4b7b38ca0 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch @@ -0,0 +1,89 @@ +From fbfb2fd5d02d1421d6ccd52cf50b06c4afbf0306 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 20:38:36 +0800 +Subject: wifi: mt76: mt7925: Fix incorrect MLO mode in firmware control + +From: Leon Yen + +[ Upstream commit 1695f662329faa07c860c73453c097823852df28 ] + +The selection of MLO mode should depend on the capabilities of the STA +rather than those of the peer AP to avoid compatibility issues with +certain APs, such as Xiaomi BE5000 WiFi7 router. + +Fixes: 69acd6d910b0c ("wifi: mt76: mt7925: add mt7925_change_vif_links") +Signed-off-by: Leon Yen +Link: https://patch.msgid.link/20251211123836.4169436-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 +- + drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 9 ++++++--- + drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 4 ++-- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 59d4357819eda..5fc95c8623647 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -535,7 +535,7 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy, + + phy->roc_grant = false; + +- err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id); ++ err = mt7925_mcu_set_mlo_roc(phy, mconf, sel_links, 5, ++phy->roc_token_id); + if (err < 0) { + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + goto out; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +index 0e7ea02574de0..1f113a618515e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +@@ -1245,8 +1245,8 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, + return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); + } + +-int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, +- int duration, u8 token_id) ++int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, ++ u16 sel_links, int duration, u8 token_id) + { + struct mt792x_vif *mvif = mconf->vif; + struct ieee80211_vif *vif = container_of((void *)mvif, +@@ -1281,6 +1281,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + .roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)) + }; + ++ struct wiphy *wiphy = phy->mt76->hw->wiphy; ++ + if (!mconf || hweight16(vif->valid_links) < 2 || + hweight16(sel_links) != 2) + return -EPERM; +@@ -1303,7 +1305,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ; + } + +- if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) ++ if (!(wiphy->iftype_ext_capab[0].mld_capa_and_ops & ++ IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS)) + type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : + MT7925_ROC_REQ_MLSR_AA; + else +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +index 27680ad28b600..bc8d38782a81a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +@@ -324,8 +324,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, + int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); + int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap env_cap); +-int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, +- int duration, u8 token_id); ++int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, ++ u16 sel_links, int duration, u8 token_id); + int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + struct ieee80211_channel *chan, int duration, + enum mt7925_roc_req type, u8 token_id); +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch b/queue-6.12/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch new file mode 100644 index 0000000000..145350b357 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch @@ -0,0 +1,45 @@ +From 7f27bf644773e8ecdf4909f524b16a499aa08f2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 11:06:48 +0800 +Subject: wifi: mt76: mt7925: prevent NULL pointer dereference in + mt7925_tx_check_aggr() + +From: Ming Yen Hsieh + +[ Upstream commit 83ae3a18ba957257b4c406273d2da2caeea2b439 ] + +Move the NULL check for 'sta' before dereferencing it to prevent a +possible crash. + +Fixes: 44eb173bdd4f ("wifi: mt76: mt7925: add link handling in mt7925_txwi_free") +Signed-off-by: Ming Yen Hsieh +Link: https://patch.msgid.link/20250904030649.655436-4-mingyen.hsieh@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +index 18b7479cee799..e308c97b574b8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +@@ -849,11 +849,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, + bool is_8023; + u16 fc, tid; + ++ if (!sta) ++ return; ++ + link_sta = rcu_dereference(sta->link[wcid->link_id]); + if (!link_sta) + return; + +- if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) ++ if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) + return; + + tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch b/queue-6.12/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch new file mode 100644 index 0000000000..5109ff5462 --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch @@ -0,0 +1,41 @@ +From b643f2c06ac74fe7a2b5e199ee05d272ca7b43a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 11:06:47 +0800 +Subject: wifi: mt76: mt7925: prevent NULL vif dereference in + mt7925_mac_write_txwi + +From: Ming Yen Hsieh + +[ Upstream commit 962eb04e67552be406c906c83099c1d736aae3b6 ] + +Check for a NULL `vif` before accessing `ieee80211_vif_is_mld(vif)` to +avoid a potential kernel panic in scenarios where `vif` might not be +initialized. + +Fixes: ebb1406813c6 ("wifi: mt76: mt7925: add link handling to txwi") +Signed-off-by: Ming Yen Hsieh +Link: https://patch.msgid.link/20250904030649.655436-3-mingyen.hsieh@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +index e308c97b574b8..e5de05a91aee7 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +@@ -807,8 +807,8 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, + txwi[5] = cpu_to_le32(val); + + val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); +- if (!ieee80211_vif_is_mld(vif) || +- (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)) ++ if (vif && (!ieee80211_vif_is_mld(vif) || ++ (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))) + val |= MT_TXD6_DIS_MAT; + txwi[6] = cpu_to_le32(val); + txwi[7] = 0; +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch b/queue-6.12/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch new file mode 100644 index 0000000000..630312bd7c --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch @@ -0,0 +1,44 @@ +From a314d56f4e92bcbd53c219065ab4cb3295624376 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Oct 2025 02:08:24 -0700 +Subject: wifi: mt76: mt7996: fix FCS error flag check in RX descriptor + +From: Alok Tiwari + +[ Upstream commit d8db56142e531f060c938fa0b5175ed6c8cabb11 ] + +The mt7996 driver currently checks the MT_RXD3_NORMAL_FCS_ERR bit in +rxd1 whereas other Connac3-based drivers(mt7925) correctly check this +bit in rxd3. + +Since the MT_RXD3_NORMAL_FCS_ERR bit is defined in the fourth RX +descriptor word (rxd3), update mt7996 to use the proper descriptor +field. This change aligns mt7996 with mt7925 and the rest of the +Connac3 family. + +Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: Alok Tiwari +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251013090826.753992-1-alok.a.tiwari@oracle.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index b7a5426c933d0..6f8167bb86136 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -501,7 +501,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + +- if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) ++ if (rxd3 & MT_RXD3_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch b/queue-6.12/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch new file mode 100644 index 0000000000..d52832db6e --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch @@ -0,0 +1,53 @@ +From 432f30a76efb1a4aefb4eada51886e3c519c1c6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:30 +0800 +Subject: wifi: mt76: mt7996: fix struct mt7996_mcu_uni_event + +From: StanleyYP Wang + +[ Upstream commit efbd5bf395f4e6b45a87f3835d4c2e28170c77c5 ] + +The cid field is defined as a two-byte value in the firmware. + +Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: StanleyYP Wang +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-2-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 8738e4b645420..54567a5893449 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -218,7 +218,7 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + event = (struct mt7996_mcu_uni_event *)skb->data; + ret = le32_to_cpu(event->status); + /* skip invalid event */ +- if (mcu_cmd != event->cid) ++ if (mcu_cmd != le16_to_cpu(event->cid)) + ret = -EAGAIN; + } else { + skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +index a75e1c9435bb0..ded2fe7210680 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +@@ -25,8 +25,8 @@ struct mt7996_mcu_rxd { + }; + + struct mt7996_mcu_uni_event { +- u8 cid; +- u8 __rsv[3]; ++ __le16 cid; ++ u8 __rsv[2]; + __le32 status; /* 0: success, others: fail */ + } __packed; + +-- +2.53.0 + diff --git a/queue-6.12/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch b/queue-6.12/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch new file mode 100644 index 0000000000..8128a5615c --- /dev/null +++ b/queue-6.12/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch @@ -0,0 +1,53 @@ +From b06727f3cde28231d0fd33f214da6c84ff456555 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 10:47:31 +0800 +Subject: wifi: mt76: mt7996: fix use-after-free bugs in mt7996_mac_dump_work() + +From: Duoming Zhou + +[ Upstream commit c8f62f73bbced3a79894655bdb0b625462d956fc ] + +When the mt7996 pci chip is detaching, the mt7996_crash_data is +released in mt7996_coredump_unregister(). However, the work item +dump_work may still be running or pending, leading to UAF bugs +when the already freed crash_data is dereferenced again in +mt7996_mac_dump_work(). + +The race condition can occur as follows: + +CPU 0 (removal path) | CPU 1 (workqueue) +mt7996_pci_remove() | mt7996_sys_recovery_set() + mt7996_unregister_device() | mt7996_reset() + mt7996_coredump_unregister() | queue_work() + vfree(dev->coredump.crash_data) | mt7996_mac_dump_work() + | crash_data-> // UAF + +Fix this by ensuring dump_work is properly canceled before +the crash_data is deallocated. Add cancel_work_sync() in +mt7996_unregister_device() to synchronize with any pending +or executing dump work. + +Fixes: 878161d5d4a4 ("wifi: mt76: mt7996: enable coredump support") +Signed-off-by: Duoming Zhou +Link: https://patch.msgid.link/20260131024731.18741-1-duoming@zju.edu.cn +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index 5cd2fb7d9835c..fc2d46b10b720 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -1399,6 +1399,7 @@ int mt7996_register_device(struct mt7996_dev *dev) + + void mt7996_unregister_device(struct mt7996_dev *dev) + { ++ cancel_work_sync(&dev->dump_work); + cancel_work_sync(&dev->wed_rro.work); + mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2); + mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); +-- +2.53.0 + diff --git a/queue-6.12/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch b/queue-6.12/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch new file mode 100644 index 0000000000..62b2795c0d --- /dev/null +++ b/queue-6.12/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch @@ -0,0 +1,49 @@ +From a002c0a4d4fa5bae6e4922e3fd5417ab428901ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 09:26:25 +0000 +Subject: wifi: mwifiex: Fix memory leak in mwifiex_11n_aggregate_pkt() + +From: Zilin Guan + +[ Upstream commit 990a73dec3fdc145fef6c827c29205437d533ece ] + +In mwifiex_11n_aggregate_pkt(), skb_aggr is allocated via +mwifiex_alloc_dma_align_buf(). If mwifiex_is_ralist_valid() returns false, +the function currently returns -1 immediately without freeing the +previously allocated skb_aggr, causing a memory leak. + +Since skb_aggr has not yet been queued via skb_queue_tail(), no other +references to this memory exist. Therefore, it has to be freed locally +before returning the error. + +Fix this by calling mwifiex_write_data_complete() to free skb_aggr before +returning the error status. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") +Signed-off-by: Zilin Guan +Reviewed-by: Jeff Chen +Link: https://patch.msgid.link/20260119092625.1349934-1-zilin@seu.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +index 34b4b34276d6d..042b1fe5f0d67 100644 +--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +@@ -203,6 +203,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); ++ mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); + return -1; + } + +-- +2.53.0 + diff --git a/queue-6.12/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch b/queue-6.12/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch new file mode 100644 index 0000000000..f2060aff7b --- /dev/null +++ b/queue-6.12/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch @@ -0,0 +1,49 @@ +From 9c64e0a51f245c392a526470356b87dc309bbc45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:55:22 +0800 +Subject: wifi: rtlwifi: pci: fix possible use-after-free caused by unfinished + irq_prepare_bcn_tasklet + +From: Duoming Zhou + +[ Upstream commit 039cd522dc70151da13329a5e3ae19b1736f468a ] + +The irq_prepare_bcn_tasklet is initialized in rtl_pci_init() and +scheduled when RTL_IMR_BCNINT interrupt is triggered by hardware. +But it is never killed in rtl_pci_deinit(). When the rtlwifi card +probe fails or is being detached, the ieee80211_hw is deallocated. +However, irq_prepare_bcn_tasklet may still be running or pending, +leading to use-after-free when the freed ieee80211_hw is accessed +in _rtl_pci_prepare_bcn_tasklet(). + +Similar to irq_tasklet, add tasklet_kill() in rtl_pci_deinit() to +ensure that irq_prepare_bcn_tasklet is properly terminated before +the ieee80211_hw is released. + +The issue was identified through static analysis. + +Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") +Signed-off-by: Duoming Zhou +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260223045522.48377-1-duoming@zju.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtlwifi/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index d080469264cf8..f0010336e78c1 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -1674,6 +1674,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); ++ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + } + +-- +2.53.0 + diff --git a/queue-6.12/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch b/queue-6.12/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch new file mode 100644 index 0000000000..9f18b12c67 --- /dev/null +++ b/queue-6.12/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch @@ -0,0 +1,48 @@ +From 60d85edab8051632664e54a4d1865d9ff7ac0bb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:05:53 +0300 +Subject: wifi: rtw89: phy: fix uninitialized variable access in + rtw89_phy_cfo_set_crystal_cap() + +From: Alexey Velichayshiy + +[ Upstream commit 047cddf88c611e616d49a00311d4722e46286234 ] + +In the rtw89_phy_cfo_set_crystal_cap() function, for chips other than +RTL8852A/RTL8851B, the values read by rtw89_mac_read_xtal_si() are +stored into the local variables sc_xi_val and sc_xo_val. If either +read fails, these variables remain uninitialized, they are later +used to update cfo->crystal_cap and in debug print statements. This +can lead to undefined behavior. + +Fix the issue by initializing sc_xi_val and sc_xo_val to zero, +like is implemented in vendor driver. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 8379fa611536 ("rtw89: 8852c: add write/read crystal function in CFO tracking") +Signed-off-by: Alexey Velichayshiy +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260323140613.1615574-1-a.velichayshiy@ispras.ru +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/phy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c +index b473e02ecd9e7..d544077ec2989 100644 +--- a/drivers/net/wireless/realtek/rtw89/phy.c ++++ b/drivers/net/wireless/realtek/rtw89/phy.c +@@ -3893,7 +3893,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, + { + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + const struct rtw89_chip_info *chip = rtwdev->chip; +- u8 sc_xi_val, sc_xo_val; ++ u8 sc_xi_val = 0, sc_xo_val = 0; + + if (!force && cfo->crystal_cap == crystal_cap) + return; +-- +2.53.0 + diff --git a/queue-6.12/x86-um-fix-vdso-installation.patch b/queue-6.12/x86-um-fix-vdso-installation.patch new file mode 100644 index 0000000000..64ab5e5399 --- /dev/null +++ b/queue-6.12/x86-um-fix-vdso-installation.patch @@ -0,0 +1,57 @@ +From 4c1a09caf4082f204d0f8328ba71a2a929becc3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 22:03:26 +0100 +Subject: x86/um: fix vDSO installation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit d1895c15fc7d90a615bc8c455feb02acaf08ef1e ] + +The generic vDSO installation logic used by 'make vdso_install' requires +that $(vdso-install-y) is defined by the top-level architecture Makefile +and that it contains a path relative to the root of the tree. +For UML neither of these is satisfied. + +Move the definition of $(vdso-install-y) to a place which is included by +the arch/um/Makefile and use the full relative path. + +Fixes: f1c2bb8b9964 ("um: implement a x86_64 vDSO") +Signed-off-by: Thomas Weißschuh +Link: https://patch.msgid.link/20260318-um-vdso-install-v1-1-26a4ca5c4210@weissschuh.net +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/x86/Makefile.um | 2 ++ + arch/x86/um/vdso/Makefile | 2 -- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/Makefile.um b/arch/x86/Makefile.um +index c86cbd9cbba38..19c13afa474e9 100644 +--- a/arch/x86/Makefile.um ++++ b/arch/x86/Makefile.um +@@ -60,4 +60,6 @@ ELF_FORMAT := elf64-x86-64 + LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib64 + LINK-y += -m64 + ++vdso-install-y += arch/x86/um/vdso/vdso.so.dbg ++ + endif +diff --git a/arch/x86/um/vdso/Makefile b/arch/x86/um/vdso/Makefile +index b3dfd60619e8a..bde42fac402ca 100644 +--- a/arch/x86/um/vdso/Makefile ++++ b/arch/x86/um/vdso/Makefile +@@ -3,8 +3,6 @@ + # Building vDSO images for x86. + # + +-vdso-install-y += vdso.so +- + # files to link into the vdso + vobjs-y := vdso-note.o um_vdso.o + +-- +2.53.0 + diff --git a/queue-6.12/x86-um-vdso-drop-vdso64-y-from-makefile.patch b/queue-6.12/x86-um-vdso-drop-vdso64-y-from-makefile.patch new file mode 100644 index 0000000000..a95a7b304f --- /dev/null +++ b/queue-6.12/x86-um-vdso-drop-vdso64-y-from-makefile.patch @@ -0,0 +1,49 @@ +From ef83bdf5b69efe99747694f875a1522b45b6f971 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Oct 2025 12:40:21 +0200 +Subject: x86/um/vdso: Drop VDSO64-y from Makefile +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 3c9b904f9033fb250db72d258bbdec791dc89405 ] + +This symbol is unnecessary, remove it. + +Signed-off-by: Thomas Weißschuh +Link: https://patch.msgid.link/20251013-uml-vdso-cleanup-v1-4-a079c7adcc69@weissschuh.net +Signed-off-by: Johannes Berg +Stable-dep-of: d1895c15fc7d ("x86/um: fix vDSO installation") +Signed-off-by: Sasha Levin +--- + arch/x86/um/vdso/Makefile | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/um/vdso/Makefile b/arch/x86/um/vdso/Makefile +index 6a77ea6434ffd..b3dfd60619e8a 100644 +--- a/arch/x86/um/vdso/Makefile ++++ b/arch/x86/um/vdso/Makefile +@@ -3,16 +3,13 @@ + # Building vDSO images for x86. + # + +-VDSO64-y := y +- +-vdso-install-$(VDSO64-y) += vdso.so +- ++vdso-install-y += vdso.so + + # files to link into the vdso + vobjs-y := vdso-note.o um_vdso.o + + # files to link into kernel +-obj-$(VDSO64-y) += vdso.o vma.o ++obj-y += vdso.o vma.o + + vobjs := $(foreach F,$(vobjs-y),$(obj)/$F) + +-- +2.53.0 + diff --git a/queue-6.18/acpi-agdi-fix-missing-newline-in-error-message.patch b/queue-6.18/acpi-agdi-fix-missing-newline-in-error-message.patch new file mode 100644 index 0000000000..38c6a2c724 --- /dev/null +++ b/queue-6.18/acpi-agdi-fix-missing-newline-in-error-message.patch @@ -0,0 +1,40 @@ +From a5744863815f370fe5fbf2650457bd77414cc740 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:31:15 +0800 +Subject: ACPI: AGDI: fix missing newline in error message + +From: Haoyu Lu + +[ Upstream commit b178330b67abb7293b6de28b2a49d49c83962db5 ] + +Add the missing trailing newline to the dev_err() message +printed when SDEI event registration fails. + +This keeps the error output as a properly terminated log line. + +Fixes: a2a591fb76e6 ("ACPI: AGDI: Add driver for Arm Generic Diagnostic Dump and Reset device") +Reviewed-by: Ilkka Koskinen +Signed-off-by: Haoyu Lu +Reviewed-by: Hanjun Guo +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + drivers/acpi/arm64/agdi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c +index e0df3daa4abf0..abe29705744e5 100644 +--- a/drivers/acpi/arm64/agdi.c ++++ b/drivers/acpi/arm64/agdi.c +@@ -32,7 +32,7 @@ static int agdi_sdei_probe(struct platform_device *pdev, + + err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev); + if (err) { +- dev_err(&pdev->dev, "Failed to register for SDEI event %d", ++ dev_err(&pdev->dev, "Failed to register for SDEI event %d\n", + adata->sdei_event); + return err; + } +-- +2.53.0 + diff --git a/queue-6.18/acpi-apei-einj-fix-einjv2-memory-error-injection.patch b/queue-6.18/acpi-apei-einj-fix-einjv2-memory-error-injection.patch new file mode 100644 index 0000000000..ceba78485b --- /dev/null +++ b/queue-6.18/acpi-apei-einj-fix-einjv2-memory-error-injection.patch @@ -0,0 +1,135 @@ +From 8bfcebab5c546ace95a6b27b7e62c3d926652114 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 08:02:16 -0700 +Subject: ACPI: APEI: EINJ: Fix EINJV2 memory error injection + +From: Tony Luck + +[ Upstream commit 0c00cfbcfcffa7085e4f0c7fd7a4caada4e7a90f ] + +Error types in EINJV2 use different bit positions for each flavor of +injection from legacy EINJ. + +Two issues: + + 1) The address sanity checks in einj_error_inject() were skipped for + EINJV2 injections. Noted by sashiko[1] + 2) __einj_error_trigger() failed to drop the entry of the target + physical address from the list of resources that need to be + requested. + +Add a helper function that checks if an injection is to memory and use it +to solve each of these issues. + +Note that the old test in __einj_error_trigger() checked that param2 was +not zero. This isn't needed because the sanity checks in einj_error_inject() +reject memory injections with param2 == 0. + +Fixes: b47610296d17 ("ACPI: APEI: EINJ: Enable EINJv2 error injections") +Reported-by: sashiko +Reported-by: Herman Li +Signed-off-by: Tony Luck +Tested-by: "Lai, Yi1" +Link: https://sashiko.dev/#/patchset/20260415163620.12957-1-tony.luck%40intel.com # [1] +Reviewed-by: Jiaqi Yan +Reviewed-by: Zaid Alali +Link: https://patch.msgid.link/20260421150216.11666-3-tony.luck@intel.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/apei/einj-core.c | 45 +++++++++++++++++++---------------- + 1 file changed, 25 insertions(+), 20 deletions(-) + +diff --git a/drivers/acpi/apei/einj-core.c b/drivers/acpi/apei/einj-core.c +index 305c240a303f6..02b81b7b5a2e2 100644 +--- a/drivers/acpi/apei/einj-core.c ++++ b/drivers/acpi/apei/einj-core.c +@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region( + + return NULL; + } ++ ++static bool is_memory_injection(u32 type, u32 flags) ++{ ++ if (flags & SETWA_FLAGS_EINJV2) ++ return !!(type & ACPI_EINJV2_MEMORY); ++ if (type & ACPI5_VENDOR_BIT) ++ return !!(vendor_flags & SETWA_FLAGS_MEM); ++ return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM); ++} ++ + /* Execute instructions in trigger error action table */ +-static int __einj_error_trigger(u64 trigger_paddr, u32 type, ++static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags, + u64 param1, u64 param2) + { + struct acpi_einj_trigger trigger_tab; +@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, + * This will cause resource conflict with regular memory. So + * remove it from trigger table resources. + */ +- if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) { ++ if ((param_extension || acpi5) && is_memory_injection(type, flags)) { + struct apei_resources addr_resources; + + apei_resources_init(&addr_resources); +@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, + return rc; + trigger_paddr = apei_exec_ctx_get_output(&ctx); + if (notrigger == 0) { +- rc = __einj_error_trigger(trigger_paddr, type, param1, param2); ++ rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2); + if (rc) + return rc; + } +@@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, + SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2))) + return -EINVAL; + ++ /* ++ * Injections targeting a CXL 1.0/1.1 port have to be injected ++ * via the einj_cxl_rch_error_inject() path as that does the proper ++ * validation of the given RCRB base (MMIO) address. ++ */ ++ if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)) ++ return -EINVAL; ++ + /* check if type is a valid EINJv2 error type */ + if (is_v2) { + if (!(type & available_error_type_v2)) + return -EINVAL; + } +- /* +- * We need extra sanity checks for memory errors. +- * Other types leap directly to injection. +- */ + + /* ensure param1/param2 existed */ + if (!(param_extension || acpi5)) + goto inject; + +- /* ensure injection is memory related */ +- if (type & ACPI5_VENDOR_BIT) { +- if (vendor_flags != SETWA_FLAGS_MEM) +- goto inject; +- } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) { +- goto inject; +- } +- + /* +- * Injections targeting a CXL 1.0/1.1 port have to be injected +- * via the einj_cxl_rch_error_inject() path as that does the proper +- * validation of the given RCRB base (MMIO) address. ++ * We need extra sanity checks for memory errors. ++ * Other types leap directly to injection. + */ +- if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)) +- return -EINVAL; ++ if (!is_memory_injection(type, flags)) ++ goto inject; + + /* + * Disallow crazy address masks that give BIOS leeway to pick +-- +2.53.0 + diff --git a/queue-6.18/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch b/queue-6.18/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch new file mode 100644 index 0000000000..c8e466ce4b --- /dev/null +++ b/queue-6.18/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch @@ -0,0 +1,145 @@ +From d0938152e6127cf55401bffde98cf2e217726be3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:28:15 +0100 +Subject: ACPI: x86: cmos_rtc: Clean up address space handler driver + +From: Rafael J. Wysocki + +[ Upstream commit ba0b236736dde4059bdcb8e99beaa50d6e5b6e7e ] + +Make multiple changes that do not alter functionality to the CMOS RTC +ACPI address space handler driver, including the following: + + - Drop the unused .detach() callback from cmos_rtc_handler. + + - Rename acpi_cmos_rtc_attach_handler() to acpi_cmos_rtc_attach(). + + - Rearrange acpi_cmos_rtc_space_handler() to reduce the number of + redundant checks and make white space follow the coding style. + + - Adjust an error message in acpi_install_cmos_rtc_space_handler() + and make the white space follow the coding style. + + - Rearrange acpi_remove_cmos_rtc_space_handler() and adjust an error + message in it. + +No intentional functional impact. + +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/5094429.31r3eYUQgx@rafael.j.wysocki +Stable-dep-of: 6cee29ad9d7e ("ACPI: x86: cmos_rtc: Improve coordination with ACPI TAD driver") +Signed-off-by: Sasha Levin +--- + drivers/acpi/x86/cmos_rtc.c | 61 +++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 29 deletions(-) + +diff --git a/drivers/acpi/x86/cmos_rtc.c b/drivers/acpi/x86/cmos_rtc.c +index 51643ff6fe5fc..977234da9fc11 100644 +--- a/drivers/acpi/x86/cmos_rtc.c ++++ b/drivers/acpi/x86/cmos_rtc.c +@@ -24,31 +24,35 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + {} + }; + +-static acpi_status +-acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, +- u32 bits, u64 *value64, +- void *handler_context, void *region_context) ++static acpi_status acpi_cmos_rtc_space_handler(u32 function, ++ acpi_physical_address address, ++ u32 bits, u64 *value64, ++ void *handler_context, ++ void *region_context) + { +- int i; ++ unsigned int i, bytes = DIV_ROUND_UP(bits, 8); + u8 *value = (u8 *)value64; + + if (address > 0xff || !value64) + return AE_BAD_PARAMETER; + +- if (function != ACPI_WRITE && function != ACPI_READ) +- return AE_BAD_PARAMETER; ++ guard(spinlock_irq)(&rtc_lock); ++ ++ if (function == ACPI_WRITE) { ++ for (i = 0; i < bytes; i++, address++, value++) ++ CMOS_WRITE(*value, address); + +- spin_lock_irq(&rtc_lock); ++ return AE_OK; ++ } + +- for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) +- if (function == ACPI_READ) ++ if (function == ACPI_READ) { ++ for (i = 0; i < bytes; i++, address++, value++) + *value = CMOS_READ(address); +- else +- CMOS_WRITE(*value, address); + +- spin_unlock_irq(&rtc_lock); ++ return AE_OK; ++ } + +- return AE_OK; ++ return AE_BAD_PARAMETER; + } + + int acpi_install_cmos_rtc_space_handler(acpi_handle handle) +@@ -56,11 +60,11 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + acpi_status status; + + status = acpi_install_address_space_handler(handle, +- ACPI_ADR_SPACE_CMOS, +- &acpi_cmos_rtc_space_handler, +- NULL, NULL); ++ ACPI_ADR_SPACE_CMOS, ++ acpi_cmos_rtc_space_handler, ++ NULL, NULL); + if (ACPI_FAILURE(status)) { +- pr_err("Error installing CMOS-RTC region handler\n"); ++ pr_err("Failed to install CMOS-RTC address space handler\n"); + return -ENODEV; + } + +@@ -70,26 +74,25 @@ EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); + + void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) + { +- if (ACPI_FAILURE(acpi_remove_address_space_handler(handle, +- ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) +- pr_err("Error removing CMOS-RTC region handler\n"); ++ acpi_status status; ++ ++ status = acpi_remove_address_space_handler(handle, ++ ACPI_ADR_SPACE_CMOS, ++ acpi_cmos_rtc_space_handler); ++ if (ACPI_FAILURE(status)) ++ pr_err("Failed to remove CMOS-RTC address space handler\n"); + } + EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + +-static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id) ++static int acpi_cmos_rtc_attach(struct acpi_device *adev, ++ const struct acpi_device_id *id) + { + return acpi_install_cmos_rtc_space_handler(adev->handle); + } + +-static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev) +-{ +- acpi_remove_cmos_rtc_space_handler(adev->handle); +-} +- + static struct acpi_scan_handler cmos_rtc_handler = { + .ids = acpi_cmos_rtc_ids, +- .attach = acpi_cmos_rtc_attach_handler, +- .detach = acpi_cmos_rtc_detach_handler, ++ .attach = acpi_cmos_rtc_attach, + }; + + void __init acpi_cmos_rtc_init(void) +-- +2.53.0 + diff --git a/queue-6.18/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch b/queue-6.18/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch new file mode 100644 index 0000000000..5d5943297a --- /dev/null +++ b/queue-6.18/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch @@ -0,0 +1,86 @@ +From be2f6eab28ea5a835ff5315d10f0496e7250cc69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:28:57 +0100 +Subject: ACPI: x86: cmos_rtc: Improve coordination with ACPI TAD driver + +From: Rafael J. Wysocki + +[ Upstream commit 6cee29ad9d7e400d39ae0b1a54447fedcb62eecd ] + +If a CMOS RTC (PNP0B00/PNP0B01/PNP0B02) device coexists with an ACPI +TAD (timer and event alarm device, ACPI000E), the ACPI TAD driver will +attempt to install the CMOS RTC address space hanlder that has been +installed already and the TAD probing will fail. + +Avoid that by changing acpi_install_cmos_rtc_space_handler() to return +zero and acpi_remove_cmos_rtc_space_handler() to do nothing if the CMOS +RTC address space handler has been installed already. + +Fixes: 596ca52a56da ("ACPI: TAD: Install SystemCMOS address space handler for ACPI000E") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2415111.ElGaqSPkdT@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/x86/cmos_rtc.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/x86/cmos_rtc.c b/drivers/acpi/x86/cmos_rtc.c +index 977234da9fc11..45db7e51cbe60 100644 +--- a/drivers/acpi/x86/cmos_rtc.c ++++ b/drivers/acpi/x86/cmos_rtc.c +@@ -24,6 +24,8 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + {} + }; + ++static bool cmos_rtc_space_handler_present __read_mostly; ++ + static acpi_status acpi_cmos_rtc_space_handler(u32 function, + acpi_physical_address address, + u32 bits, u64 *value64, +@@ -59,6 +61,9 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + { + acpi_status status; + ++ if (cmos_rtc_space_handler_present) ++ return 0; ++ + status = acpi_install_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler, +@@ -68,6 +73,8 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + return -ENODEV; + } + ++ cmos_rtc_space_handler_present = true; ++ + return 1; + } + EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); +@@ -76,6 +83,9 @@ void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) + { + acpi_status status; + ++ if (cmos_rtc_space_handler_present) ++ return; ++ + status = acpi_remove_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler); +@@ -87,7 +97,13 @@ EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + static int acpi_cmos_rtc_attach(struct acpi_device *adev, + const struct acpi_device_id *id) + { +- return acpi_install_cmos_rtc_space_handler(adev->handle); ++ int ret; ++ ++ ret = acpi_install_cmos_rtc_space_handler(adev->handle); ++ if (ret < 0) ++ return ret; ++ ++ return 1; + } + + static struct acpi_scan_handler cmos_rtc_handler = { +-- +2.53.0 + diff --git a/queue-6.18/acpica-provide-defines-for-einjv2-error-types.patch b/queue-6.18/acpica-provide-defines-for-einjv2-error-types.patch new file mode 100644 index 0000000000..316859a341 --- /dev/null +++ b/queue-6.18/acpica-provide-defines-for-einjv2-error-types.patch @@ -0,0 +1,45 @@ +From fde35da49053cc9507dc9f1230dd5cf425a4188d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 08:02:15 -0700 +Subject: ACPICA: Provide #defines for EINJV2 error types + +From: Tony Luck + +[ Upstream commit 1f6008538384453eb4c13a3d7ff9e37ee8aee6b9 ] + +EINJV2 defined new error types by moving the severity (correctable, +uncorrectable non-fatal, uncorrectable fatal) out of the "type". + +ACPI 6.5 introduced EINJV2 and defined a vendor defined error type +using bit 31. This was dropped in ACPI 6.6. + +Link: https://github.com/acpica/acpica/commit/e82d2d2fd145 +Signed-off-by: Tony Luck +Link: https://patch.msgid.link/20260421150216.11666-2-tony.luck@intel.com +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 0c00cfbcfcff ("ACPI: APEI: EINJ: Fix EINJV2 memory error injection") +Signed-off-by: Sasha Levin +--- + include/acpi/actbl1.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h +index 7f35eb0e84586..b074244cbdcbf 100644 +--- a/include/acpi/actbl1.h ++++ b/include/acpi/actbl1.h +@@ -1129,6 +1129,12 @@ enum acpi_einj_command_status { + #define ACPI_EINJ_CXL_MEM_FATAL (1<<17) + #define ACPI_EINJ_VENDOR_DEFINED (1<<31) + ++/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */ ++ ++#define ACPI_EINJV2_PROCESSOR (1) ++#define ACPI_EINJV2_MEMORY (1<<1) ++#define ACPI_EINJV2_PCIE (1<<2) ++ + /******************************************************************************* + * + * ERST - Error Record Serialization Table (ACPI 4.0) +-- +2.53.0 + diff --git a/queue-6.18/alsa-core-validate-compress-device-numbers-without-d.patch b/queue-6.18/alsa-core-validate-compress-device-numbers-without-d.patch new file mode 100644 index 0000000000..a7668dd9f0 --- /dev/null +++ b/queue-6.18/alsa-core-validate-compress-device-numbers-without-d.patch @@ -0,0 +1,81 @@ +From 46ea88009babcb8b06ea0cac3b0d784f90795077 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 02:24:04 -0300 +Subject: ALSA: core: Validate compress device numbers without dynamic minors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 796e119e9b14763be905ad0d023c71a14bc2e931 ] + +Without CONFIG_SND_DYNAMIC_MINORS, ALSA reserves only two fixed minors +for compress devices on each card: comprD0 and comprD1. + +snd_find_free_minor() currently computes the compress minor as +type + dev without validating dev first, so device numbers greater than +1 spill into the HWDEP minor range instead of failing registration. + +ASoC passes rtd->id to snd_compress_new(), so this can happen on real +non-dynamic-minor builds. + +Add a dedicated fixed-minor check for SNDRV_DEVICE_TYPE_COMPRESS in +snd_find_free_minor() and reject out-of-range device numbers with +-EINVAL before constructing the minor. + +Also remove the stale TODO in compress_offload.c that still claims +multiple compress nodes are missing. + +Fixes: 3eafc959b32f ("ALSA: core: add support for compressed devices") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-alsa-compress-static-minors-v1-1-0628573bee1c@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 7 ------- + sound/core/sound.c | 7 +++++++ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index da514fef45bca..2181442e3a1da 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -41,13 +41,6 @@ + #define COMPR_CODEC_CAPS_OVERFLOW + #endif + +-/* TODO: +- * - add substream support for multiple devices in case of +- * SND_DYNAMIC_MINORS is not used +- * - Multiple node representation +- * driver should be able to register multiple nodes +- */ +- + struct snd_compr_file { + unsigned long caps; + struct snd_compr_stream stream; +diff --git a/sound/core/sound.c b/sound/core/sound.c +index 6531a67f13b3e..7980b60f4ba0b 100644 +--- a/sound/core/sound.c ++++ b/sound/core/sound.c +@@ -216,9 +216,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev) + case SNDRV_DEVICE_TYPE_RAWMIDI: + case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: + case SNDRV_DEVICE_TYPE_PCM_CAPTURE: ++ if (snd_BUG_ON(!card)) ++ return -EINVAL; ++ minor = SNDRV_MINOR(card->number, type + dev); ++ break; + case SNDRV_DEVICE_TYPE_COMPRESS: + if (snd_BUG_ON(!card)) + return -EINVAL; ++ if (dev < 0 || ++ dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS) ++ return -EINVAL; + minor = SNDRV_MINOR(card->number, type + dev); + break; + default: +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-cmedia-remove-duplicate-pin-configuration-p.patch b/queue-6.18/alsa-hda-cmedia-remove-duplicate-pin-configuration-p.patch new file mode 100644 index 0000000000..5809fee950 --- /dev/null +++ b/queue-6.18/alsa-hda-cmedia-remove-duplicate-pin-configuration-p.patch @@ -0,0 +1,43 @@ +From f561e4215444daf81a516f492093d3add2183c29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 16:26:25 +0800 +Subject: ALSA: hda/cmedia: Remove duplicate pin configuration parsing + +From: wangdicheng + +[ Upstream commit 579e7b820de5dd5124585413bb5e9c278d255436 ] + +The cmedia_probe() function calls snd_hda_parse_pin_defcfg() and +snd_hda_gen_parse_auto_config() twice unnecessarily. Remove The +duplicate code. + +Fixes: 0f1e8306dcbe ("ALSA: hda/cmedia: Rewrite to new probe method") +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260401082625.157868-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/cmedia.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/sound/hda/codecs/cmedia.c b/sound/hda/codecs/cmedia.c +index 15e5a1118a6e8..a156bea7ca446 100644 +--- a/sound/hda/codecs/cmedia.c ++++ b/sound/hda/codecs/cmedia.c +@@ -39,13 +39,6 @@ static int cmedia_probe(struct hda_codec *codec, const struct hda_device_id *id) + spec->out_vol_mask = (1ULL << 0x10); + } + +- err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); +- if (err < 0) +- goto error; +- err = snd_hda_gen_parse_auto_config(codec, cfg); +- if (err < 0) +- goto error; +- + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + goto error; +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch b/queue-6.18/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch new file mode 100644 index 0000000000..93890eb5b8 --- /dev/null +++ b/queue-6.18/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch @@ -0,0 +1,60 @@ +From 178296bf91bb5226e09d9aa96c9053cf1b3e9ccd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:04:50 +0800 +Subject: ALSA: hda/conexant: Fix missing error check for jack detection + +From: wangdicheng + +[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ] + +In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() +is ignored. This function returns a pointer, and if it fails (e.g., due +to memory allocation failure), it returns an error pointer which must +be checked using IS_ERR(). + +If the registration fails, the driver continues to probe, but the jack +detection callback will not be registered. This can lead to a kernel +crash later when the driver attempts to handle jack events or accesses +the uninitialized structure. + +Check the return value using IS_ERR() and propagate the error via +PTR_ERR() to the probe caller. + +Fixes: 7aeb25908648 ("ALSA: hda/conexant: Fix headset auto detect fail in cx8070 and SN6140") +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428080450.108801-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/conexant.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c +index f71123a475464..263773f8bd6ae 100644 +--- a/sound/hda/codecs/conexant.c ++++ b/sound/hda/codecs/conexant.c +@@ -1183,6 +1183,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) + static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) + { + struct conexant_spec *spec; ++ struct hda_jack_callback *callback; + int err; + + codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); +@@ -1198,7 +1199,12 @@ static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) + case 0x14f11f86: + case 0x14f11f87: + spec->is_cx11880_sn6140 = true; +- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); ++ callback = snd_hda_jack_detect_enable_callback(codec, 0x19, ++ cx_update_headset_mic_vref); ++ if (IS_ERR(callback)) { ++ err = PTR_ERR(callback); ++ goto error; ++ } + break; + } + +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch b/queue-6.18/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch new file mode 100644 index 0000000000..a88704e742 --- /dev/null +++ b/queue-6.18/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch @@ -0,0 +1,95 @@ +From 0d4055c3fe4b84d85ab11d57b7f6364c5d81b512 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 14:05:31 +0100 +Subject: ALSA: hda: cs35l56: Fix uninitialized value in + cs35l56_hda_read_acpi() + +From: Richard Fitzgerald + +[ Upstream commit 90df4957a3271adf391b3432cd76a40887cf3273 ] + +Eliminate the uninitialized 'nval' in cs35l56_hda_read_acpi() if a +system-specific quirk overrides processing of the dev-index property. +The value is now stored in a new 'num_amps' member of struct cs35l56_hda +so that the quirk handler can set the value. + +The quirk for the Lenovo Yoga Book 9i GenX replaces the values from the +dev-index property with hardcoded indexes. So cs35l56_hda_read_acpi() would +then skip reading the property. But this left the 'nval' local variable +uninitialized when it is later passed to cirrus_scodec_get_speaker_id(). + +Fixes: 40b1c2f9b299 ("ALSA: hda/cs35l56: Workaround bad dev-index on Lenovo Yoga Book 9i GenX") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-sound/aenFesLAStjrVNy8@stanley.mountain/T/#u +Signed-off-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260428130531.169600-1-rf@opensource.cirrus.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l56_hda.c | 12 +++++++----- + sound/hda/codecs/side-codecs/cs35l56_hda.h | 1 + + 2 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c +index 82b7352e7ea97..79c15e21d4bcb 100644 +--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c ++++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c +@@ -884,6 +884,7 @@ static int cs35l56_hda_system_resume(struct device *dev) + static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr) + { + /* The cirrus,dev-index property has the wrong values */ ++ cs35l56->num_amps = 2; + switch (*bus_addr) { + case 0x30: + cs35l56->index = 1; +@@ -933,7 +934,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + char hid_string[8]; + struct acpi_device *adev; + const char *property, *sub; +- size_t nval; + int i, ret; + + /* +@@ -969,13 +969,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + ret = -EINVAL; + goto err; + } +- nval = ret; ++ cs35l56->num_amps = ret; + +- ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval); ++ ret = device_property_read_u32_array(cs35l56->base.dev, property, values, ++ cs35l56->num_amps); + if (ret) + goto err; + +- for (i = 0; i < nval; i++) { ++ for (i = 0; i < cs35l56->num_amps; i++) { + if (values[i] == id) { + cs35l56->index = i; + break; +@@ -998,7 +999,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + "Read ACPI _SUB failed(%ld): fallback to generic firmware\n", + PTR_ERR(sub)); + } else { +- ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1); ++ ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, ++ cs35l56->num_amps, -1); + if (ret == -ENOENT) { + cs35l56->system_name = sub; + } else if (ret >= 0) { +diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h +index 38d94fb213a50..0074e8f5f18cb 100644 +--- a/sound/hda/codecs/side-codecs/cs35l56_hda.h ++++ b/sound/hda/codecs/side-codecs/cs35l56_hda.h +@@ -25,6 +25,7 @@ struct cs35l56_hda { + struct work_struct dsp_work; + + int index; ++ int num_amps; + const char *system_name; + const char *amp_name; + +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch b/queue-6.18/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch new file mode 100644 index 0000000000..77f6f3ef44 --- /dev/null +++ b/queue-6.18/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch @@ -0,0 +1,45 @@ +From 8c488998472ee5fdb95de7c7577114806f3b4122 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 15:54:05 +0800 +Subject: ALSA: hda/realtek: fix code style (ERROR: else should follow close + brace '}') + +From: Lei Huang + +[ Upstream commit d1888bf848ade6a9e71c7ba516fd215aa1bd8d65 ] + +Fix checkpatch code style errors: + + ERROR: else should follow close brace '}' + #2300: FILE: sound/hda/codecs/realtek/alc269.c:2300: + + } + + else + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Lei Huang +Link: https://patch.msgid.link/20260331075405.78148-1-huanglei814@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index 844c4650230cd..a2ecbe1412632 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -2237,9 +2237,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } +- else ++ } else { + alc_fixup_headset_mode(codec, fix, action); ++ } + } + + static void alc288_update_headset_jack_cb(struct hda_codec *codec, +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-realtek-fixed-speaker-no-sound-update.patch b/queue-6.18/alsa-hda-realtek-fixed-speaker-no-sound-update.patch new file mode 100644 index 0000000000..8cf752c9e4 --- /dev/null +++ b/queue-6.18/alsa-hda-realtek-fixed-speaker-no-sound-update.patch @@ -0,0 +1,67 @@ +From 3071042ad007b4be31401e7f7d382af144a1127a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:44:04 +0800 +Subject: ALSA: hda/realtek - fixed speaker no sound update + +From: Kailang Yang + +[ Upstream commit 46c862f5419e0a86b60b9f9558d247f6084c99f9 ] + +Fixed speaker has pop noise on Lenovo Thinkpad X11 Carbon Gen 12. + +Fixes: 630fbc6e870e ("ALSA: hda/realtek - fixed speaker no sound") +Reported-and-tested-by: Jeremy Bethmont +Closes: https://lore.kernel.org/CAC88DfsHrhyhy0Pn1O-z9egBvMYu=6NYgcvcC6KCgwh_-Ldkxg@mail.gmail.com +Signed-off-by: Kailang Yang +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index a2ecbe1412632..e14caa040fc92 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -3615,22 +3615,11 @@ static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct snd_pcm_substream *substream, + int action) + { +- static const struct coef_fw dis_coefs[] = { +- WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), +- WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023), +- }; /* Disable AMP silence detection */ +- static const struct coef_fw en_coefs[] = { +- WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), +- WRITE_COEF(0x28, 0x0084), WRITE_COEF(0x29, 0xb023), +- }; /* Enable AMP silence detection */ +- + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: +- alc_process_coef_fw(codec, dis_coefs); + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */ + break; + case HDA_GEN_PCM_ACT_CLOSE: +- alc_process_coef_fw(codec, en_coefs); + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */ + break; + } +@@ -3653,10 +3642,15 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec, + WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301), + WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023), + }; ++ static const struct coef_fw dis_coefs[] = { ++ WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), ++ WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023), ++ }; /* Disable AMP silence detection */ + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11); ++ alc_process_coef_fw(codec, dis_coefs); + alc_process_coef_fw(codec, coefs); + spec->power_hook = alc287_s4_power_gpio3_default; + spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook; +-- +2.53.0 + diff --git a/queue-6.18/alsa-hda-tas2781-fix-incorrect-bit-update-for-non-bo.patch b/queue-6.18/alsa-hda-tas2781-fix-incorrect-bit-update-for-non-bo.patch new file mode 100644 index 0000000000..bbbea4b26f --- /dev/null +++ b/queue-6.18/alsa-hda-tas2781-fix-incorrect-bit-update-for-non-bo.patch @@ -0,0 +1,52 @@ +From da49751b3f0f1dbcbd9e7b5e89a2c2ce80bcd41a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:42:06 +0800 +Subject: ALSA: hda/tas2781: Fix incorrect bit update for non-book-zero or book + 0 pages >1 + +From: Shenghao Ding + +[ Upstream commit e052a1f7199260eda4d6ca08a59c3b98738f8491 ] + +In TAS2781 SPI mode, when accessing non-book-zero or page numbers greater +than 1 in book 0, an additional byte must be read. The first byte in such +cases is a dummy byte and should be ignored. + +Fixes: 9fa6a693ad8d ("ALSA: hda/tas2781: Remove tas2781_spi_fwlib.c and leverage SND_SOC_TAS2781_FMWLIB") +Signed-off-by: Shenghao Ding +Link: https://patch.msgid.link/20260429054206.429-1-shenghao-ding@ti.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/tas2781_hda_spi.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c +index 488e35dac9524..a64f2c899d50c 100644 +--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c ++++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c +@@ -135,10 +135,18 @@ static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv, + int ret, val; + + /* +- * In our TAS2781 SPI mode, read/write was masked in last bit of +- * address, it cause regmap_update_bits() not work as expected. ++ * In TAS2781 SPI mode, when accessing non-book-zero or page numbers ++ * greater than 1 in book 0, an additional byte must be read. The ++ * first byte in such cases is a dummy byte and should be ignored. + */ +- ret = tasdevice_dev_read(tas_priv, chn, reg, &val); ++ if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) { ++ unsigned char buf[2]; ++ ++ ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, buf, 2); ++ val = buf[1]; ++ } else { ++ ret = tasdevice_dev_read(tas_priv, chn, reg, &val); ++ } + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + return ret; +-- +2.53.0 + diff --git a/queue-6.18/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch b/queue-6.18/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch new file mode 100644 index 0000000000..5df73e66be --- /dev/null +++ b/queue-6.18/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch @@ -0,0 +1,289 @@ +From fdc390416be4effa024b7f5c8170379ea74ccd13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:54:32 -0300 +Subject: ALSA: sc6000: Keep the programmed board state in card-private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit fb79bf127ac2577b4876132da6dba768018aad4c ] + +The driver may auto-select IRQ and DMA resources at probe time, but +sc6000_init_board() still derives the SC-6000 soft configuration from +the module parameter arrays. When irq=auto or dma=auto is used, the +codec is created with the selected resources while the board is +programmed with the unresolved values. + +Store the mapped ports and generated SC-6000 board configuration in +card-private data, build that configuration from the live probe +results instead of the raw module parameters, and keep the probe-time +board programming in a shared helper. + +This fixes the resource-programming mismatch and leaves the driver +with a stable board-state block that can be reused by suspend/resume. + +Fixes: c282866101bf ("ALSA: sc6000: add support for SC-6600 and SC-7000") +Signed-off-by: Cássio Gabriel +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260410-alsa-sc6000-pm-v1-1-4d9e95493d26@gmail.com +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 152 +++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 60 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 6d618cc2ba457..9949e06403f61 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -100,6 +100,15 @@ MODULE_PARM_DESC(joystick, "Enable gameport."); + #define PFX "sc6000: " + #define DRV_NAME "SC-6000" + ++struct snd_sc6000 { ++ char __iomem *vport; ++ char __iomem *vmss_port; ++ u8 mss_config; ++ u8 config; ++ u8 hw_cfg[2]; ++ bool old_dsp; ++}; ++ + /* hardware dependent functions */ + + /* +@@ -267,7 +276,7 @@ static int sc6000_dsp_reset(char __iomem *vport) + + /* detection and initialization */ + static int sc6000_hw_cfg_write(struct device *devptr, +- char __iomem *vport, const int *cfg) ++ char __iomem *vport, const u8 *cfg) + { + if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { + dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); +@@ -353,8 +362,7 @@ static int sc6000_init_mss(struct device *devptr, + return 0; + } + +-static void sc6000_hw_cfg_encode(struct device *devptr, +- char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, u8 *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -376,27 +384,83 @@ static void sc6000_hw_cfg_encode(struct device *devptr, + dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(struct device *devptr, +- char __iomem *vport, +- char __iomem *vmss_port, int dev) ++static void sc6000_prepare_board(struct device *devptr, ++ struct snd_sc6000 *sc6000, ++ unsigned int dev, int xirq, int xdma) ++{ ++ sc6000->mss_config = sc6000_irq_to_softcfg(xirq) | ++ sc6000_dma_to_softcfg(xdma); ++ sc6000->config = sc6000->mss_config | ++ sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); ++ sc6000_hw_cfg_encode(devptr, sc6000->hw_cfg, port[dev], mpu_port[dev], ++ mss_port[dev], joystick[dev]); ++} ++ ++static void sc6000_detect_old_dsp(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ sc6000_write(devptr, sc6000->vport, COMMAND_5C); ++ sc6000->old_dsp = sc6000_read(sc6000->vport) < 0; ++} ++ ++static int sc6000_program_board(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ int err; ++ ++ if (!sc6000->old_dsp) { ++ if (sc6000_hw_cfg_write(devptr, sc6000->vport, ++ sc6000->hw_cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); ++ return -EIO; ++ } ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ sc6000_dsp_reset(sc6000->vport); ++ ++ if (!sc6000->old_dsp) { ++ sc6000_write(devptr, sc6000->vport, COMMAND_60); ++ sc6000_write(devptr, sc6000->vport, 0x02); ++ sc6000_dsp_reset(sc6000->vport); ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ err = sc6000_init_mss(devptr, sc6000->vport, sc6000->config, ++ sc6000->vmss_port, sc6000->mss_config); ++ if (err < 0) { ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int sc6000_init_board(struct device *devptr, struct snd_sc6000 *sc6000) + { + char answer[15]; + char version[2]; +- int mss_config = sc6000_irq_to_softcfg(irq[dev]) | +- sc6000_dma_to_softcfg(dma[dev]); +- int config = mss_config | +- sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); + int err; +- int old = 0; + +- err = sc6000_dsp_reset(vport); ++ err = sc6000_dsp_reset(sc6000->vport); + if (err < 0) { + dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, sc6000->vport, GET_DSP_COPYRIGHT, ++ answer, 15); + if (err <= 0) { + dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; +@@ -408,54 +472,17 @@ static int sc6000_init_board(struct device *devptr, + if (strncmp("SC-6000", answer, 7)) + dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ if (sc6000_dsp_get_answer(devptr, sc6000->vport, ++ GET_DSP_VERSION, version, 2) < 2) { + dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } + dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + +- /* set configuration */ +- sc6000_write(devptr, vport, COMMAND_5C); +- if (sc6000_read(vport) < 0) +- old = 1; +- +- if (!old) { +- int cfg[2]; +- sc6000_hw_cfg_encode(devptr, +- vport, &cfg[0], port[dev], mpu_port[dev], +- mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { +- dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); +- return -EIO; +- } +- } +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- +- sc6000_dsp_reset(vport); +- +- if (!old) { +- sc6000_write(devptr, vport, COMMAND_60); +- sc6000_write(devptr, vport, 0x02); +- sc6000_dsp_reset(vport); +- } ++ sc6000_detect_old_dsp(devptr, sc6000); + +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); +- if (err < 0) { +- dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); +- return -ENODEV; +- } +- +- return 0; ++ return sc6000_program_board(devptr, sc6000); + } + + static int snd_sc6000_mixer(struct snd_wss *chip) +@@ -538,10 +565,10 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + + static void snd_sc6000_free(struct snd_card *card) + { +- char __iomem *vport = (char __force __iomem *)card->private_data; ++ struct snd_sc6000 *sc6000 = card->private_data; + +- if (vport) +- sc6000_setup_board(card->dev, vport, 0); ++ if (sc6000->vport) ++ sc6000_setup_board(card->dev, sc6000->vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -552,15 +579,17 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + int xirq = irq[dev]; + int xdma = dma[dev]; + struct snd_card *card; ++ struct snd_sc6000 *sc6000; + struct snd_wss *chip; + struct snd_opl3 *opl3; + char __iomem *vport; + char __iomem *vmss_port; + + err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE, +- 0, &card); ++ sizeof(*sc6000), &card); + if (err < 0) + return err; ++ sc6000 = card->private_data; + + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); +@@ -587,7 +616,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } +- card->private_data = (void __force *)vport; ++ sc6000->vport = vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +@@ -600,12 +629,15 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } ++ sc6000->vmss_port = vmss_port; + + dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(devptr, vport, vmss_port, dev); ++ sc6000_prepare_board(devptr, sc6000, dev, xirq, xdma); ++ ++ err = sc6000_init_board(devptr, sc6000); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +-- +2.53.0 + diff --git a/queue-6.18/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch b/queue-6.18/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch new file mode 100644 index 0000000000..4fe56c17f3 --- /dev/null +++ b/queue-6.18/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch @@ -0,0 +1,39 @@ +From b5d7a01e6d77182ee39c39780c5c8c0019765677 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 01:25:48 +0300 +Subject: ALSA: scarlett2: Add missing sentinel initializer field + +From: Panagiotis Petrakopoulos + +[ Upstream commit 2428cd6e8b6fa80c36db4652702ca0acd2ce3f08 ] + +A "-Wmissing-field-initializers" warning was emitted when compiling the +module using the W=2 option. There is a sentinel initializer field +missing in the end of scarlett2_devices[]. Tested using a +Scarlett Solo 4th gen. + +Fixes: d98cc489029d ("ALSA: scarlett2: Move USB IDs out from device_info struct") +Signed-off-by: Panagiotis Petrakopoulos +Link: https://patch.msgid.link/20260405222548.8903-1-npetrakopoulos2003@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_scarlett2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index 48d77030a63d8..a75a4610663e9 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -2262,7 +2262,7 @@ static const struct scarlett2_device_entry scarlett2_devices[] = { + { USB_ID(0x1235, 0x820c), &clarett_8pre_info, "Clarett+" }, + + /* End of list */ +- { 0, NULL }, ++ { 0, NULL, NULL }, + }; + + /* get the starting port index number for a given port type/direction */ +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-exclude-scarlett-18i20-1st-gen-from-s.patch b/queue-6.18/alsa-usb-audio-exclude-scarlett-18i20-1st-gen-from-s.patch new file mode 100644 index 0000000000..c68b54ca22 --- /dev/null +++ b/queue-6.18/alsa-usb-audio-exclude-scarlett-18i20-1st-gen-from-s.patch @@ -0,0 +1,37 @@ +From 122636d7b5401c41a49fc33b17c4b6527c3f1711 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 03:03:00 +0930 +Subject: ALSA: usb-audio: Exclude Scarlett 18i20 1st Gen from SKIP_IFACE_SETUP + +From: Geoffrey D. Bennett + +[ Upstream commit a47306a74c31557b1e5cab54642950bbb20294cb ] + +Same issue as the other 1st Gen Scarletts: QUIRK_FLAG_SKIP_IFACE_SETUP +causes distorted audio on the Scarlett 18i20 1st Gen (1235:800c). + +Fixes: 38c322068a26 ("ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP") +Reported-by: tucktuckg00se [https://github.com/geoffreybennett/linux-fcp/issues/54] +Signed-off-by: Geoffrey D. Bennett +Link: https://patch.msgid.link/ad0ozNnkcFrcjVQz@m.b4.vu +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index a2c039a1b3cd6..f21e708675422 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2426,6 +2426,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_VALIDATE_RATES), + DEVICE_FLG(0x1235, 0x8006, 0), /* Focusrite Scarlett 2i2 1st Gen */ + DEVICE_FLG(0x1235, 0x800a, 0), /* Focusrite Scarlett 2i4 1st Gen */ ++ DEVICE_FLG(0x1235, 0x800c, 0), /* Focusrite Scarlett 18i20 1st Gen */ + DEVICE_FLG(0x1235, 0x8016, 0), /* Focusrite Scarlett 2i2 1st Gen */ + DEVICE_FLG(0x1235, 0x801c, 0), /* Focusrite Scarlett Solo 1st Gen */ + VENDOR_FLG(0x1235, /* Focusrite Novation */ +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch b/queue-6.18/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch new file mode 100644 index 0000000000..3fe839f0ea --- /dev/null +++ b/queue-6.18/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch @@ -0,0 +1,205 @@ +From c3d85785c3fc7c1eb2df638457304210f2ef8483 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 17:15:04 +0200 +Subject: ALSA: usb-audio: Fix potential leak of pd at parsing UAC3 streams + +From: Takashi Iwai + +[ Upstream commit c39f0bc03f84ba64c9144c95714df1dc36150f6d ] + +At parsing UAC3 streams, we allocate a PD object at each time, and +either assign or free it. But there is a case where the PD object may +be leaked; namely, in __snd_usb_parse_audio_interface() loop, when an +audioformat shares the same endpoint with others, it's put to a link +and returns from snd_usb_add_audio_stream(), but the PD is forgotten +afterwards. Overall, the treatment of PD object in the parser code is +a bit flaky, and we should be more careful about the object ownership. + +This patch tries to fix the above case and improve the code a bit. +The pd object is now managed with the auto-cleanup in the loop, and +the ownership is updated when the pd object gets assigned to the +stream, which guarantees the release of the leftover object. + +Fixes: 7edf3b5e6a45 ("ALSA: usb-audio: AudioStreaming Power Domain parsing") +Link: https://patch.msgid.link/20260427151508.12544-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 +- + sound/usb/stream.c | 58 ++++++++++++++++++---------------------------- + sound/usb/stream.h | 3 ++- + 3 files changed, 25 insertions(+), 38 deletions(-) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index f21e708675422..1b4cfc2b68f9d 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip, + + snd_usb_audioformat_set_sync_ep(chip, fp); + +- err = snd_usb_add_audio_stream(chip, stream, fp); ++ err = snd_usb_add_audio_stream(chip, stream, fp, NULL); + if (err < 0) + return err; + +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index 8b83092a1999e..34a50fb4e50b9 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) + static void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, + struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++ struct snd_usb_power_domain **pdptr) + { + struct snd_usb_substream *subs = &as->substream[stream]; + +@@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, + if (fp->channels > subs->channels_max) + subs->channels_max = fp->channels; + +- if (pd) { +- subs->str_pd = pd; ++ if (pdptr && *pdptr) { ++ subs->str_pd = *pdptr; ++ *pdptr = NULL; /* assigned */ + /* Initialize Power Domain to idle status D1 */ +- snd_usb_power_domain_set(subs->stream->chip, pd, ++ snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, + UAC3_PD_STATE_D1); + } + +@@ -486,11 +487,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor + * if not, create a new pcm stream. note, fp is added to the substream + * fmt_list and will be freed on the chip instance release. do not free + * fp or do remove it from the substream fmt_list to avoid double-free. ++ * ++ * pdptr is optional and can be NULL. When it's non-NULL and the PD gets ++ * assigned to the stream, *pdptr is cleared to NULL upon return. + */ +-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++int snd_usb_add_audio_stream(struct snd_usb_audio *chip, ++ int stream, ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr) + + { + struct snd_usb_stream *as; +@@ -523,7 +527,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + err = snd_pcm_new_stream(as->pcm, stream, 1); + if (err < 0) + return err; +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + return add_chmap(as->pcm, stream, subs); + } + +@@ -552,7 +556,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + else + strscpy(pcm->name, "USB Audio"); + +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + + /* + * Keep using head insertion for M-Audio Audiophile USB (tm) which has a +@@ -570,21 +574,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + return add_chmap(pcm, stream, &as->substream[stream]); + } + +-int snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, NULL); +-} +- +-static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, pd); +-} +- + static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, + struct usb_host_interface *alts, + int protocol, int iface_no) +@@ -1109,8 +1098,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + } + } + +- if (pd) +- *pd_out = pd; ++ *pd_out = pd; + + return fp; + } +@@ -1125,7 +1113,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + struct usb_interface_descriptor *altsd; + int i, altno, err, stream; + struct audioformat *fp = NULL; +- struct snd_usb_power_domain *pd = NULL; + bool set_iface_first; + int num, protocol; + +@@ -1167,6 +1154,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) + continue; + ++ /* pd may be allocated at snd_usb_get_audioformat_uac3() and ++ * assigned at snd_usb_add_audio_stream(); otherwise it'll be ++ * freed automatically by cleanup at each loop. ++ */ ++ struct snd_usb_power_domain *pd __free(kfree) = NULL; ++ + /* + * Roland audio streaming interfaces are marked with protocols + * 0/1/2, but are UAC 1 compatible. +@@ -1222,23 +1215,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + *has_non_pcm = true; + if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { + audioformat_free(fp); +- kfree(pd); + fp = NULL; +- pd = NULL; + continue; + } + + snd_usb_audioformat_set_sync_ep(chip, fp); + + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); +- if (protocol == UAC_VERSION_3) +- err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); +- else +- err = snd_usb_add_audio_stream(chip, stream, fp); +- ++ err = snd_usb_add_audio_stream(chip, stream, fp, &pd); + if (err < 0) { + audioformat_free(fp); +- kfree(pd); + return err; + } + +diff --git a/sound/usb/stream.h b/sound/usb/stream.h +index d92e18d5818fe..61b9a133da018 100644 +--- a/sound/usb/stream.h ++++ b/sound/usb/stream.h +@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + + int snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, +- struct audioformat *fp); ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr); + + #endif /* __USBAUDIO_STREAM_H */ + +-- +2.53.0 + diff --git a/queue-6.18/alsa-usb-audio-qcom-fix-incorrect-type-in-enable_aud.patch b/queue-6.18/alsa-usb-audio-qcom-fix-incorrect-type-in-enable_aud.patch new file mode 100644 index 0000000000..b5232652af --- /dev/null +++ b/queue-6.18/alsa-usb-audio-qcom-fix-incorrect-type-in-enable_aud.patch @@ -0,0 +1,42 @@ +From 00053da625b08d7d2fa06c0240960ba286489dc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 16:33:11 +0800 +Subject: ALSA: usb-audio: qcom: Fix incorrect type in enable_audio_stream + +From: songxiebing + +[ Upstream commit 292286b2d229fb732421429b027d38ac3f969383 ] + +Fix sparse warning: +sound/usb/qcom/qc_audio_offload.c:943:27: sparse: incorrect type in argument 2 +expected unsigned int val but got snd_pcm_format_t. + +Explicitly cast pcm_format to unsigned int for snd_mask_leave(). + +Fixes: 326bbc348298 ("ALSA: usb-audio: qcom: Introduce QC USB SND offloading support") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604062109.Oxi8JjWW-lkp@intel.com/ +Signed-off-by: songxiebing +Link: https://patch.msgid.link/20260408083311.774173-1-songxiebing@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/qcom/qc_audio_offload.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c +index 542eae3a57d9d..fc25e709ed4b2 100644 +--- a/sound/usb/qcom/qc_audio_offload.c ++++ b/sound/usb/qcom/qc_audio_offload.c +@@ -948,7 +948,7 @@ static int enable_audio_stream(struct snd_usb_substream *subs, + _snd_pcm_hw_params_any(¶ms); + + m = hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT); +- snd_mask_leave(m, pcm_format); ++ snd_mask_leave(m, (__force unsigned int)pcm_format); + + i = hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_setinteger(i); +-- +2.53.0 + diff --git a/queue-6.18/amd-pstate-fix-memory-leak-in-amd_pstate_epp_cpu_ini.patch b/queue-6.18/amd-pstate-fix-memory-leak-in-amd_pstate_epp_cpu_ini.patch new file mode 100644 index 0000000000..82ade6f0e4 --- /dev/null +++ b/queue-6.18/amd-pstate-fix-memory-leak-in-amd_pstate_epp_cpu_ini.patch @@ -0,0 +1,46 @@ +From e9451260dd334606ced720af870607457309dd85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:17:45 +0530 +Subject: amd-pstate: Fix memory leak in amd_pstate_epp_cpu_init() + +From: Gautham R. Shenoy + +[ Upstream commit beda3b363546a423e4e29a7395e04c0ac4ff677e ] + +On failure to set the epp, the function amd_pstate_epp_cpu_init() +returns with an error code without freeing the cpudata object that was +allocated at the beginning of the function. + +Ensure that the cpudata object is freed before returning from the +function. + +This memory leak was discovered by Claude Opus 4.6 with the aid of +Chris Mason's AI review-prompts +(https://github.com/masoncl/review-prompts/tree/main/kernel). + +Assisted-by: Claude:claude-opus-4.6 review-prompts/linux +Fixes: f9a378ff6443 ("cpufreq/amd-pstate: Set different default EPP policy for Epyc and Ryzen") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Gautham R. Shenoy +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/amd-pstate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c +index 602e4fa81d6c5..86d8762ac82c5 100644 +--- a/drivers/cpufreq/amd-pstate.c ++++ b/drivers/cpufreq/amd-pstate.c +@@ -1525,7 +1525,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) + + ret = amd_pstate_set_epp(policy, cpudata->epp_default); + if (ret) +- return ret; ++ goto free_cpudata1; + + current_pstate_driver->adjust_perf = NULL; + +-- +2.53.0 + diff --git a/queue-6.18/amd-pstate-update-cppc_req_cached-in-fast_switch-cas.patch b/queue-6.18/amd-pstate-update-cppc_req_cached-in-fast_switch-cas.patch new file mode 100644 index 0000000000..eccea43e58 --- /dev/null +++ b/queue-6.18/amd-pstate-update-cppc_req_cached-in-fast_switch-cas.patch @@ -0,0 +1,45 @@ +From eec68e0fbd9f0dcf530d4b2822708c1d35655c7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:17:46 +0530 +Subject: amd-pstate: Update cppc_req_cached in fast_switch case + +From: Gautham R. Shenoy + +[ Upstream commit fcc25a291fbdca2c06c2c6602532050873f0c9de ] + +The function msr_update_perf() does not cache the new value that is +written to MSR_AMD_CPPC_REQ into the variable cpudata->cppc_req_cached +when the update is happening from the fast path. + +Fix that by caching the value everytime the MSR_AMD_CPPC_REQ gets +updated. + +This issue was discovered by Claude Opus 4.6 with the aid of Chris +Mason's AI review-prompts +(https://github.com/masoncl/review-prompts/tree/main/kernel). + +Assisted-by: Claude:claude-opus-4.6 review-prompts/linux +Reviewed-by: Mario Limonciello (AMD) +Fixes: fff395796917 ("cpufreq/amd-pstate: Always write EPP value when updating perf") +Signed-off-by: Gautham R. Shenoy +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/amd-pstate.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c +index 86d8762ac82c5..39681ad1606f6 100644 +--- a/drivers/cpufreq/amd-pstate.c ++++ b/drivers/cpufreq/amd-pstate.c +@@ -259,7 +259,6 @@ static int msr_update_perf(struct cpufreq_policy *policy, u8 min_perf, + + if (fast_switch) { + wrmsrq(MSR_AMD_CPPC_REQ, value); +- return 0; + } else { + int ret = wrmsrq_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value); + +-- +2.53.0 + diff --git a/queue-6.18/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch b/queue-6.18/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch new file mode 100644 index 0000000000..245ae9d9b6 --- /dev/null +++ b/queue-6.18/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch @@ -0,0 +1,76 @@ +From 8b17e1a62d7dd7bbe52af3a0767c52c342419843 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 18:12:55 -0500 +Subject: ARM: dts: imx27-eukrea: replace interrupts with interrupts-extended + +From: Frank Li + +[ Upstream commit 0477a6b31e2874e554e3bcfac9883684b8f8ca2d ] + +The property interrupts use default interrupt controllers. But pass down +gpio as phandle. Correct it by use interrupts-extended. + +Fixes: d8cae888aa2bc ("ARM: dts: Add support for the cpuimx27 board from Eukrea and its baseboard") +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi | 8 ++++---- + .../boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +index c7e9235848782..9f0e65526d5f9 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +@@ -106,7 +106,7 @@ uart8250@3,200000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x200000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -119,7 +119,7 @@ uart8250@3,400000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x400000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -132,7 +132,7 @@ uart8250@3,800000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x800000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -145,7 +145,7 @@ uart8250@3,1000000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x1000000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +index d78793601306c..c71f802983304 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +@@ -76,7 +76,7 @@ ads7846@0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_touch>; + reg = <0>; +- interrupts = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; + spi-cpol; + spi-max-frequency = <1500000>; + ti,keep-vref-on; +-- +2.53.0 + diff --git a/queue-6.18/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch b/queue-6.18/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch new file mode 100644 index 0000000000..42cc50d1bf --- /dev/null +++ b/queue-6.18/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch @@ -0,0 +1,46 @@ +From 47175cae54a8e25ac1e4d0b8a0c2be45f470248c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 09:25:41 +0100 +Subject: ARM: dts: mediatek: mt7623: fix efuse fallback compatible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafał Miłecki + +[ Upstream commit 5978ff33cc6f0988388a2830dc5cd2ea4e81f36a ] + +Fix following validation error: +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: compatible: 'oneOf' conditional failed, one must be fixed: + ['mediatek,mt7623-efuse', 'mediatek,mt8173-efuse'] is too long + 'mediatek,mt8173-efuse' was expected + 'mediatek,efuse' was expected + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: Unevaluated properties are not allowed ('compatible' was unexpected) + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# + +Fixes: 43c7a91b4b3a ("arm: dts: mt7623: add efuse nodes to the mt7623.dtsi file") +Signed-off-by: Rafał Miłecki +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/mediatek/mt7623.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi +index fd7a89cc337d6..a60b1d6879ffe 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623.dtsi ++++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi +@@ -328,7 +328,7 @@ sysirq: interrupt-controller@10200100 { + + efuse: efuse@10206000 { + compatible = "mediatek,mt7623-efuse", +- "mediatek,mt8173-efuse"; ++ "mediatek,efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.18/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch b/queue-6.18/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch new file mode 100644 index 0000000000..900399881b --- /dev/null +++ b/queue-6.18/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch @@ -0,0 +1,40 @@ +From 849533200eccdad70cdfefdfc6b713f38ec0d62b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 19:15:10 +0200 +Subject: ARM: OMAP1: Fix DEBUG_LL and earlyprintk on OMAP16XX + +From: Aaro Koskinen + +[ Upstream commit 7e74b606dd39c46d4378d6f6563f560a00ab8694 ] + +On OMAP16XX, the UART enable bit shifts are written instead of the actual +bits. This breaks the boot when DEBUG_LL and earlyprintk is enabled; +the UART gets disabled and some random bits get enabled. Fix that. + +Fixes: 34c86239b184 ("ARM: OMAP1: clock: Fix early UART rate issues") +Signed-off-by: Aaro Koskinen +Link: https://patch.msgid.link/aca7HnXZ-aCSJPW7@darkstar.musicnaut.iki.fi +Signed-off-by: Kevin Hilman +Signed-off-by: Sasha Levin +--- + arch/arm/mach-omap1/clock_data.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c +index c58d200e4816b..5203b047deac8 100644 +--- a/arch/arm/mach-omap1/clock_data.c ++++ b/arch/arm/mach-omap1/clock_data.c +@@ -700,8 +700,8 @@ int __init omap1_clk_init(void) + /* Make sure UART clocks are enabled early */ + if (cpu_is_omap16xx()) + omap_writel(omap_readl(MOD_CONF_CTRL_0) | +- CONF_MOD_UART1_CLK_MODE_R | +- CONF_MOD_UART3_CLK_MODE_R, MOD_CONF_CTRL_0); ++ (1 << CONF_MOD_UART1_CLK_MODE_R) | ++ (1 << CONF_MOD_UART3_CLK_MODE_R), MOD_CONF_CTRL_0); + #endif + + /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ +-- +2.53.0 + diff --git a/queue-6.18/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch b/queue-6.18/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch new file mode 100644 index 0000000000..e0d00892b3 --- /dev/null +++ b/queue-6.18/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch @@ -0,0 +1,56 @@ +From a710cf386a4708aae7a3dffb44f437492e33e891 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:28:18 +0000 +Subject: arm64: cpufeature: Make PMUVer and PerfMon unsigned + +From: James Clark + +[ Upstream commit d1dcc20bcc40efe1f1c71639376c91dafa489222 ] + +On the host, this change doesn't make a difference because the fields +are defined as FTR_EXACT. However, KVM allows userspace to set these +fields for a guest and overrides the type to be FTR_LOWER_SAFE. And +while KVM used to do an unsigned comparison to validate that the new +value is lower than what the hardware provides, since the linked commit +it uses the generic sanitization framework which does a signed +comparison. + +Fix it by defining these fields as unsigned. In theory, without this +fix, userspace could set a higher PMU version than the hardware supports +by providing any value with the top bit set. + +Fixes: c118cead07a7 ("KVM: arm64: Use generic sanitisation for ID_(AA64)DFR0_EL1") +Signed-off-by: James Clark +Reviewed-by: Marc Zyngier +Reviewed-by: Colton Lewis +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/cpufeature.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c +index e25b0f84a22da..39a798f74778e 100644 +--- a/arch/arm64/kernel/cpufeature.c ++++ b/arch/arm64/kernel/cpufeature.c +@@ -564,7 +564,7 @@ static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = { + * We can instantiate multiple PMU instances with different levels + * of support. + */ +- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), ++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_EL1_DebugVer_SHIFT, 4, 0x6), + ARM64_FTR_END, + }; +@@ -708,7 +708,7 @@ static const struct arm64_ftr_bits ftr_id_pfr2[] = { + + static const struct arm64_ftr_bits ftr_id_dfr0[] = { + /* [31:28] TraceFilt */ +- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), ++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MProfDbg_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MMapTrc_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopTrc_SHIFT, 4, 0), +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-amlogic-meson-axg-add-missing-cache-inform.patch b/queue-6.18/arm64-dts-amlogic-meson-axg-add-missing-cache-inform.patch new file mode 100644 index 0000000000..c80e81b050 --- /dev/null +++ b/queue-6.18/arm64-dts-amlogic-meson-axg-add-missing-cache-inform.patch @@ -0,0 +1,41 @@ +From 95ca047ec6a7f15364697708300eb73c7aa41df4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 16:05:46 +0530 +Subject: arm64: dts: amlogic: meson-axg: Add missing cache information to cpu0 + +From: Anand Moon + +[ Upstream commit 918273be0885362a9a00615b46e03f15f8b55667 ] + +Add missing L1 data and instruction cache parameters to the CPU node 0 +for the Cortex-A53 caches on the Meson AXG SoC. + +Fixes: 3b6ad2a43367 ("arm64: dts: amlogic: Add cache information to the Amlogic AXG SoCS") +Signed-off-by: Anand Moon +Link: https://patch.msgid.link/20260219103548.18392-1-linux.amoon@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index bbf94a1f92a10..3058b60338dbf 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -72,6 +72,12 @@ cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + reg = <0x0 0x0>; + enable-method = "psci"; ++ d-cache-line-size = <32>; ++ d-cache-size = <0x8000>; ++ d-cache-sets = <32>; ++ i-cache-line-size = <32>; ++ i-cache-size = <0x8000>; ++ i-cache-sets = <32>; + next-level-cache = <&l2>; + clocks = <&scpi_dvfs 0>; + dynamic-power-coefficient = <140>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch b/queue-6.18/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch new file mode 100644 index 0000000000..7a4792cc55 --- /dev/null +++ b/queue-6.18/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch @@ -0,0 +1,45 @@ +From 9d88ba16cbfd93b53d247f638dfeae7664de4825 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 09:45:48 +0100 +Subject: arm64: dts: freescale: imx8mp-tqma8mpql-mba8mp-ras314: fix UART1 + RTS/CTS muxing + +From: Nora Schiffer + +[ Upstream commit b8d785a9f360abcd6a6f8f10a2adf222f8494d66 ] + +UART1 operates in DCE mode, but the RTS/CTS pins were incorrectly +configured using the DTE pinmux setting. + +Correct the pinmux to match DCE mode. Switching the RTS and CTS signals +is fine for this board, as UART1 is routed to a pin header. Existing +functionality is unaffected, as RTS/CTS could never have worked with +the incorrect pinmux. + +Fixes: ddabb3ce3f90 ("arm64: dts: freescale: add TQMa8MPQL on MBa8MP-RAS314") +Signed-off-by: Nora Schiffer +Reviewed-by: Alexander Stein +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +index a122f2ed5f531..06c865c3a8cf8 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +@@ -833,8 +833,8 @@ pinctrl_tlv320aic3x04: tlv320aic3x04grp { + pinctrl_uart1: uart1grp { + fsl,pins = , + , +- , +- ; ++ , ++ ; + }; + + pinctrl_uart1_gpio: uart1gpiogrp { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8-apalis-fix-leds-name-collision.patch b/queue-6.18/arm64-dts-imx8-apalis-fix-leds-name-collision.patch new file mode 100644 index 0000000000..49a76dffab --- /dev/null +++ b/queue-6.18/arm64-dts-imx8-apalis-fix-leds-name-collision.patch @@ -0,0 +1,103 @@ +From 1f8697b763a9910e632bf7604de0e900f9f7b418 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:34:09 +0100 +Subject: arm64: dts: imx8-apalis: Fix LEDs name collision + +From: Francesco Dolcini + +[ Upstream commit 92ab53b9bb2a72581c32073755077af916eb9aee ] + +Ixora boards have multiple instances of status leds, to avoid a name +collision add the function-enumerator property. + +This fixes the following Linux kernel warnings: + + leds-gpio leds: Led green:status renamed to green:status_1 due to name collision + leds-gpio leds: Led red:status renamed to red:status_1 due to name collision + +Fixes: c083131c9021 ("arm64: dts: freescale: add apalis imx8 aka quadmax carrier board support") +Signed-off-by: Francesco Dolcini +Reviewed-by: Frank Li +Reviewed-by: Daniel Baluta +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi | 4 ++++ + arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +index 3d8731504ce15..1e8b6e61e33d4 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +@@ -21,6 +21,7 @@ led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; + }; + +@@ -29,6 +30,7 @@ led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; + }; + +@@ -37,6 +39,7 @@ led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; + }; + +@@ -45,6 +48,7 @@ led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +index 106e802a68ba5..70dcb66f8fda4 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +@@ -21,6 +21,7 @@ led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; + }; + +@@ -29,6 +30,7 @@ led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; + }; + +@@ -37,6 +39,7 @@ led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; + }; + +@@ -45,6 +48,7 @@ led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8dxl-evk-use-audio-graph-card2-for-wm89.patch b/queue-6.18/arm64-dts-imx8dxl-evk-use-audio-graph-card2-for-wm89.patch new file mode 100644 index 0000000000..2d165e1a73 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8dxl-evk-use-audio-graph-card2-for-wm89.patch @@ -0,0 +1,189 @@ +From 7718134fe88fdb7e32739ecbdc8f5ddc15362b59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:37:38 +0800 +Subject: arm64: dts: imx8dxl-evk: Use audio-graph-card2 for wm8960-2 and + wm8960-3 + +From: Shengjiu Wang + +[ Upstream commit e8341b0245736619f8d6a2cc311c9e8ad8e82390 ] + +The sound card wm8960-2 and wm8960-3 only support capture mode for the +reason of connection on the EVK board. But fsl-asoc-card don't support +capture_only setting, the sound card creation will fail. + +fsl-sai 59060000.sai: Missing dma channel for stream: 0 +fsl-sai 59060000.sai: ASoC error (-22): at snd_soc_pcm_component_new() on 59060000.sai +fsl-sai 59070000.sai: Missing dma channel for stream: 0 +fsl-sai 59070000.sai: ASoC error (-22): at snd_soc_pcm_component_new() on 59070000.sai + +so switch to use audio-graph-card2 which supports 'capture_only' +property for wm8960-2 and wm8960-3 cards. + +Fixes: b41c45eb990a ("arm64: dts: imx8dxl-evk: add audio nodes") +Signed-off-by: Shengjiu Wang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8dxl-evk.dts | 114 ++++++++++++++---- + 1 file changed, 90 insertions(+), 24 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts +index 25a77cac6f0b5..b75ab1e010f0c 100644 +--- a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts +@@ -259,33 +259,37 @@ sound-wm8960-1 { + }; + + sound-wm8960-2 { +- compatible = "fsl,imx-audio-wm8960"; +- model = "wm8960-audio-2"; +- audio-cpu = <&sai2>; +- audio-codec = <&wm8960_2>; +- audio-routing = "Headphone Jack", "HP_L", +- "Headphone Jack", "HP_R", +- "Ext Spk", "SPK_LP", +- "Ext Spk", "SPK_LN", +- "Ext Spk", "SPK_RP", +- "Ext Spk", "SPK_RN", +- "LINPUT1", "Mic Jack", +- "Mic Jack", "MICB"; ++ compatible = "audio-graph-card2"; ++ label = "wm8960-audio-2"; ++ links = <&sai2_port2>; ++ routing = "Headphones", "HP_L", ++ "Headphones", "HP_R", ++ "Ext Spk", "SPK_LP", ++ "Ext Spk", "SPK_LN", ++ "Ext Spk", "SPK_RP", ++ "Ext Spk", "SPK_RN", ++ "LINPUT1", "Mic Jack", ++ "Mic Jack", "MICB"; ++ widgets = "Headphone", "Headphones", ++ "Speaker", "Ext Spk", ++ "Microphone", "Mic Jack"; + }; + + sound-wm8960-3 { +- compatible = "fsl,imx-audio-wm8960"; +- model = "wm8960-audio-3"; +- audio-cpu = <&sai3>; +- audio-codec = <&wm8960_3>; +- audio-routing = "Headphone Jack", "HP_L", +- "Headphone Jack", "HP_R", +- "Ext Spk", "SPK_LP", +- "Ext Spk", "SPK_LN", +- "Ext Spk", "SPK_RP", +- "Ext Spk", "SPK_RN", +- "LINPUT1", "Mic Jack", +- "Mic Jack", "MICB"; ++ compatible = "audio-graph-card2"; ++ label = "wm8960-audio-3"; ++ links = <&sai3_port2>; ++ routing = "Headphones", "HP_L", ++ "Headphones", "HP_R", ++ "Ext Spk", "SPK_LP", ++ "Ext Spk", "SPK_LN", ++ "Ext Spk", "SPK_RP", ++ "Ext Spk", "SPK_RN", ++ "LINPUT1", "Mic Jack", ++ "Mic Jack", "MICB"; ++ widgets = "Headphone", "Headphones", ++ "Speaker", "Ext Spk", ++ "Microphone", "Mic Jack"; + }; + }; + +@@ -481,6 +485,16 @@ wm8960_2: audio-codec@1a { + DCVDD-supply = <®_audio_1v8>; + SPKVDD1-supply = <®_audio_5v>; + SPKVDD2-supply = <®_audio_5v>; ++ ++ port { ++ capture-only; ++ ++ wm8960_2_ep: endpoint { ++ bitclock-master; ++ frame-master; ++ remote-endpoint = <&sai2_endpoint2>; ++ }; ++ }; + }; + }; + +@@ -510,6 +524,16 @@ wm8960_3: audio-codec@1a { + DCVDD-supply = <®_audio_1v8>; + SPKVDD1-supply = <®_audio_5v>; + SPKVDD2-supply = <®_audio_5v>; ++ ++ port { ++ capture-only; ++ ++ wm8960_3_ep: endpoint { ++ bitclock-master; ++ frame-master; ++ remote-endpoint = <&sai3_endpoint2>; ++ }; ++ }; + }; + }; + +@@ -695,6 +719,27 @@ &sai2 { + pinctrl-0 = <&pinctrl_sai2>; + fsl,sai-asynchronous; + status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sai2_port1: port@1 { ++ reg = <1>; ++ endpoint { /* not used */ }; ++ }; ++ ++ sai2_port2: port@2 { ++ reg = <2>; ++ capture-only; ++ ++ sai2_endpoint2: endpoint { ++ dai-format = "i2s"; ++ remote-endpoint = <&wm8960_2_ep>; ++ system-clock-direction-out; ++ }; ++ }; ++ }; + }; + + &sai3 { +@@ -707,6 +752,27 @@ &sai3 { + pinctrl-0 = <&pinctrl_sai3>; + fsl,sai-asynchronous; + status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sai3_port1: port@1 { ++ reg = <1>; ++ endpoint { /* not used */ }; ++ }; ++ ++ sai3_port2: port@2 { ++ reg = <2>; ++ capture-only; ++ ++ sai3_endpoint2: endpoint { ++ dai-format = "i2s"; ++ remote-endpoint = <&wm8960_3_ep>; ++ system-clock-direction-out; ++ }; ++ }; ++ }; + }; + + &thermal_zones { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch b/queue-6.18/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..5b3c4ac1ce --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch @@ -0,0 +1,48 @@ +From 7315bb59cc221cd286a9c1698d700c6efe4bd3bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:11 +0800 +Subject: arm64: dts: imx8mm-emtop-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 721dec3ee9ff5231d13a412ff87df63b966d137b ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +While at here, also correct interrupt type as IRQ_TYPE_LEVEL_LOW. + +Fixes: cbd3ef64eb9d1 ("arm64: dts: Add support for Emtop SoM & Baseboard") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +index 67d22d3768aa8..507d1824d99d9 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +@@ -60,7 +60,7 @@ pmic@25 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; +- interrupts = <3 IRQ_TYPE_EDGE_RISING>; ++ interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + regulators { + buck1: BUCK1 { +@@ -194,7 +194,7 @@ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 + + pinctrl_pmic: emtop-pmic-grp { + fsl,pins = < +- MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41 ++ MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x141 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch b/queue-6.18/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..c94e5da101 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 5fbf0503fce37e1c7a577a88bd84747376d2fddb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:13 +0800 +Subject: arm64: dts: imx8mm-tqma8mqml: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 42a9f5a16328ed78a88e0498556965b6c6ec515c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: dfcd1b6f7620e ("arm64: dts: freescale: add initial device tree for TQMa8MQML with i.MX8MM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +index b82e9790ea205..a0e8b158c4edf 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +@@ -291,7 +291,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch b/queue-6.18/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..a16ad6cfa3 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 49a5471c5a496bf8754391d66dac862b01a52ecb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:12 +0800 +Subject: arm64: dts: imx8mn-tqma8mqnl: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 0fb37990774113afd943eaa91323679388584b6d ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: 3e56e354db6d3 ("arm64: dts: freescale: add initial device tree for TQMa8MQNL with i.MX8MN") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +index e2ccebf6ee13f..5e2c6d6e94550 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +@@ -298,7 +298,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-aristainetos3a-som-v1-correct-pad-s.patch b/queue-6.18/arm64-dts-imx8mp-aristainetos3a-som-v1-correct-pad-s.patch new file mode 100644 index 0000000000..4ec5c756f7 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-aristainetos3a-som-v1-correct-pad-s.patch @@ -0,0 +1,38 @@ +From 51e1d2fe8efcba75edb926d93b9c10f2d778c660 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:11 +0800 +Subject: arm64: dts: imx8mp-aristainetos3a-som-v1: Correct PAD settings for + PMIC_nINT + +From: Peng Fan + +[ Upstream commit e6d2d8e49ca34bb39126a69128794d08ffd7c83e ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: eead8f3536d5c ("arm64: dts: imx8mp: add aristainetos3 board support") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi +index f654d866e58c0..e7666e54310be 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi +@@ -903,7 +903,7 @@ MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20 0x41 + + pinctrl_pmic: aristainetos3-pmic-grp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch b/queue-6.18/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch new file mode 100644 index 0000000000..348495881c --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch @@ -0,0 +1,38 @@ +From 71205214ebbc8641573e8f02539ba05947a5791f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:16 +0800 +Subject: arm64: dts: imx8mp-data-modul-edm-sbc: Correct PAD settings for + PMIC_nINT + +From: Peng Fan + +[ Upstream commit 8ff145577e93f312ff398cb950ee3bd44835f5be ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 562d222f23f0f ("arm64: dts: imx8mp: Add support for Data Modul i.MX8M Plus eDM SBC") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +index 16078ff60ef08..fa13662ca3667 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +@@ -900,7 +900,7 @@ MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_PDM_BIT_STREAM00 0x0 + pinctrl_pmic: pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch b/queue-6.18/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch new file mode 100644 index 0000000000..0f8e29972d --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch @@ -0,0 +1,42 @@ +From 352e4d595ca51a07a9d0a16341c21e7bf294df42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:05 +0800 +Subject: arm64: dts: imx8mp-debix-model-a: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 3b778178997aee24537b521a8cb60970bc1ce01c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there is interrupt storm for i.MX8MP DEBIX Model A. Per schematic, there +is no on board PULL-UP resistors for GPIO1_IO03, so need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: c86d350aae68e ("arm64: dts: Add device tree for the Debix Model A Board") +Reported-by: Laurent Pinchart +Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/ +Reviewed-by: Laurent Pinchart +Tested-by: Laurent Pinchart +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +index af02af9e5334d..740cac4cb31d9 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +@@ -440,7 +440,7 @@ MX8MP_IOMUXC_SAI5_RXC__I2C6_SDA 0x400001c3 + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch b/queue-6.18/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..8710e7e402 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch @@ -0,0 +1,56 @@ +From a7b71c68bc3485c927bdcbb9999a05925d547b66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:06 +0800 +Subject: arm64: dts: imx8mp-debix-som-a: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 2ea7872048a179b0ea8dadc67771961df3f0fc4a ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there is interrupt storm for i.MX8MP DEBIX SOM A. Need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: 21baf0b47f81b ("arm64: dts: freescale: Add DEBIX SOM A and SOM A I/O Board support") +Reported-by: Laurent Pinchart +Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/ +Reported-by: Kieran Bingham +Closes: https://lore.kernel.org/imx/20260324194353.GB2352505@killaraus.ideasonboard.com/T/#m9a07fdc75496369a7d76d52c5e34ed140dcabfe3 +Signed-off-by: Peng Fan +Reviewed-by: Kieran Bingham +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts | 2 +- + arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +index d241db3743a9c..ed89d2ccb6ce2 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +@@ -452,7 +452,7 @@ MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x140 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +index 91094c2277443..b31e8fe95ca74 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +@@ -241,7 +241,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch b/queue-6.18/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..c86c771ee9 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 50af4406194579aa6d94c72df9b94ff491b03e55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:15 +0800 +Subject: arm64: dts: imx8mp-dhcom-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit f9ed5afc988da3e22543725e35be6addbb0497bc ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 8d6712695bc8e ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +index f8303b7e2bd22..0a6a60670f762 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +@@ -989,7 +989,7 @@ MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20 0x22 + pinctrl_pmic: dhcom-pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-edm-g-correct-pad-settings-for-pmic.patch b/queue-6.18/arm64-dts-imx8mp-edm-g-correct-pad-settings-for-pmic.patch new file mode 100644 index 0000000000..3577a9f7f3 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-edm-g-correct-pad-settings-for-pmic.patch @@ -0,0 +1,37 @@ +From 53c8b0b2a79e8b3aac7730f5846fe306206b116c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:10 +0800 +Subject: arm64: dts: imx8mp-edm-g: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit c46c5a54443440ce0f71de9f4df9dd860f5c2afd ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: 95e882c021c8b ("arm64: dts: imx8mp: Add TechNexion EDM-G-IMX8M-PLUS SOM on WB-EDM-G carrier board") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi +index 3f1e0837f349f..91b87a7248dd1 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi +@@ -563,7 +563,7 @@ MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x41 /* PCIE RST */ + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch b/queue-6.18/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch new file mode 100644 index 0000000000..fb559a9027 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch @@ -0,0 +1,43 @@ +From 12b3d298fee618acbc3c60093b88bed4948fe242 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 15:34:53 +0800 +Subject: arm64: dts: imx8mp-evk: Enable pull select bit for PCIe regulator + GPIO (M.2 W_DISABLE1) + +From: Sherry Sun + +[ Upstream commit d1e7eab6033f9885a02c4b4e8f09e34d8e9d21ab ] + +The current pin configuration for MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 +sets the weak pull-up but does not enable the pull select field. +Bit 8 in the IOMUX register must be set in order for the weak pull-up +to actually take effect. + +Update the pinctrl setting from 0x40 to 0x140 to enable both the pull +select and the weak pull-up, ensuring the line behaves as expected. + +Fixes: d50650500064 ("arm64: dts: imx8mp-evk: Add PCIe support") +Signed-off-by: Sherry Sun +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +index 3730792daf501..d957d6cc20f7f 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +@@ -995,7 +995,7 @@ MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07 0x40 + + pinctrl_pcie0_reg: pcie0reggrp { + fsl,pins = < +- MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x40 ++ MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x140 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-hummingboard-pulse-fix-mini-hdmi-ds.patch b/queue-6.18/arm64-dts-imx8mp-hummingboard-pulse-fix-mini-hdmi-ds.patch new file mode 100644 index 0000000000..d54eaec0af --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-hummingboard-pulse-fix-mini-hdmi-ds.patch @@ -0,0 +1,61 @@ +From 55b0a2784e1ca32510df898d36a7acd8b21ba2c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 18:36:32 +0200 +Subject: arm64: dts: imx8mp-hummingboard-pulse: fix mini-hdmi dsi port + reference + +From: Josua Mayer + +[ Upstream commit 1d1d14d4253e6f373c247e67f3716768910be81e ] + +imx8mp.dtsi includes a default port@1 node with an empty placeholder +endpoint intended for linking to a dsi bridge or panel. + +HummingBoard Pulse mini-hdmi dtsi described a new endpoint node with a +different label attached. + +This duplicate label causes confusion and is suspected to also cause +errors during dsi_attach. + +Remove the duplicate node and link to the one defined in soc dtsi. +Further remove the unnecessary attach-bridge property. + +Fixes: 2a222aa2bee9 ("arm64: dts: add description for solidrun imx8mp hummingboard variants") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../imx8mp-hummingboard-pulse-mini-hdmi.dtsi | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi +index 46916ddc05335..0e5f4607c7c1b 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi +@@ -41,7 +41,7 @@ port@0 { + reg = <0>; + + adv7535_from_dsim: endpoint { +- remote-endpoint = <&dsim_to_adv7535>; ++ remote-endpoint = <&mipi_dsi_out>; + }; + }; + +@@ -71,11 +71,8 @@ &lcdif1 { + &mipi_dsi { + samsung,esc-clock-frequency = <10000000>; + status = "okay"; ++}; + +- port@1 { +- dsim_to_adv7535: endpoint { +- remote-endpoint = <&adv7535_from_dsim>; +- attach-bridge; +- }; +- }; ++&mipi_dsi_out { ++ remote-endpoint = <&adv7535_from_dsim>; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch b/queue-6.18/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..d181a3ecc7 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch @@ -0,0 +1,37 @@ +From 38882bb701c1a0034f7fc6fbddb390a0339da1cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:09 +0800 +Subject: arm64: dts: imx8mp-icore-mx8mp: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit ea8c90f5c7ceeb6657a8fe564aa7b190dce298a6 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: eefe06b295087 ("arm64: dts: imx8mp: Add Engicam i.Core MX8M Plus SoM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +index a6319824ea2eb..69558ffefa9a6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +@@ -132,7 +132,7 @@ MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x41 ++ MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-kontron-drop-vmmc-supply-to-fix-sd-.patch b/queue-6.18/arm64-dts-imx8mp-kontron-drop-vmmc-supply-to-fix-sd-.patch new file mode 100644 index 0000000000..765c82f077 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-kontron-drop-vmmc-supply-to-fix-sd-.patch @@ -0,0 +1,40 @@ +From b32a1222f24998f2bf9cfef2c950e2ac5c3dbb74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:36:17 +0100 +Subject: arm64: dts: imx8mp-kontron: Drop vmmc-supply to fix SD card on SMARC + eval carrier + +From: Frieder Schrempf + +[ Upstream commit d2ce84eecf081056b1d18d7524de52f849281ba7 ] + +The SMARC evaluation carrier provides an SD card power switch that +complies with the OSM standard definition. The OSM base devicetree +already describes this correctly. + +Stop overriding the vmmc-supply in the board devicetree and rely on +the definition from the OSM base DTS instead to fix the power supply +configuration for the SD card. + +Fixes: 6fe1ced5ccab7 ("arm64: dts: Add support for Kontron i.MX8MP SMARC module and eval carrier") +Signed-off-by: Frieder Schrempf +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts +index 2173a36ff6917..74d620dd06b7b 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts +@@ -249,6 +249,5 @@ &usb3_phy1 { + }; + + &usdhc2 { +- vmmc-supply = <®_vdd_3v3>; + status = "okay"; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-kontron-fix-boot-order-for-pmic-and.patch b/queue-6.18/arm64-dts-imx8mp-kontron-fix-boot-order-for-pmic-and.patch new file mode 100644 index 0000000000..785019a4ed --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-kontron-fix-boot-order-for-pmic-and.patch @@ -0,0 +1,48 @@ +From ae32738327f97827a961a68514a66d3dd4560603 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:57:43 +0100 +Subject: arm64: dts: imx8mp-kontron: Fix boot order for PMIC and RTC + +From: Annette Kobou + +[ Upstream commit 130d90114c5255a7a729158da8fd8298a02017f1 ] + +The PMIC provides a level-shifter for the I2C lines to the RTC. As the +level shifter needs to be enabled before the RTC can be accessed, make sure +that the PMIC driver is probed first. + +As the PMIC also provides the supply voltage for the RTC through the 3.3V +regulator, simply express this in the DT to create the required dependency. + +Avoid sporadic boot hangs that occurred when the RTC was accessed before +the level-shifter was enabled. + +Fixes: 946ab10e3f40f ("arm64: dts: Add support for Kontron OSM-S i.MX8MP SoM and BL carrier board") +Signed-off-by: Annette Kobou +Signed-off-by: Frieder Schrempf +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi +index b97bfeb1c30f8..bc1a261bb000e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi +@@ -330,6 +330,12 @@ rv3028: rtc@52 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rtc>; + interrupts-extended = <&gpio3 24 IRQ_TYPE_LEVEL_LOW>; ++ /* ++ * While specifying the vdd-supply is normally not strictly necessary, ++ * here it also makes sure that the PMIC driver enables the level- ++ * shifter for the RTC before the RTC is probed. ++ */ ++ vdd-supply = <®_vdd_3v3>; + }; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-kontron-fix-touch-reset-configurati.patch b/queue-6.18/arm64-dts-imx8mp-kontron-fix-touch-reset-configurati.patch new file mode 100644 index 0000000000..297d39952d --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-kontron-fix-touch-reset-configurati.patch @@ -0,0 +1,71 @@ +From 04d87871c8ca34155b37de04d8cb053ae93bc44e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:36:16 +0100 +Subject: arm64: dts: imx8mp-kontron: Fix touch reset configuration on DL + devices + +From: Frieder Schrempf + +[ Upstream commit 058c53476dde9937877e93d964a283bbb5e1e4c7 ] + +The reset signal needs a pullup, but there is no hardware pullup. +As a workaround, enable the internal pullup to fix the touchscreen. + +As this deviates from the default generic GPIO settings in the OSM +devicetree, add a new node for the touch pinctrl and redefine the +generic gpio1 pinctrl. + +Fixes: 946ab10e3f40f ("arm64: dts: Add support for Kontron OSM-S i.MX8MP SoM and BL carrier board") +Signed-off-by: Frieder Schrempf +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../boot/dts/freescale/imx8mp-kontron-dl.dtso | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso b/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso +index a3cba41d2b531..7131e9a499ae1 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso ++++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso +@@ -77,6 +77,8 @@ &i2c1 { + touchscreen@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_touch>; + interrupt-parent = <&gpio1>; + interrupts = <6 8>; + irq-gpios = <&gpio1 6 0>; +@@ -98,6 +100,16 @@ &lvds_bridge { + status = "okay"; + }; + ++/* redefine to remove touch controller GPIOs */ ++&pinctrl_gpio1 { ++ fsl,pins = < ++ MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00 0x19 /* GPIO_A_0 */ ++ MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x19 /* GPIO_A_1 */ ++ MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05 0x19 /* GPIO_A_2 */ ++ MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08 0x19 /* GPIO_A_5 */ ++ >; ++}; ++ + &pwm1 { + status = "okay"; + }; +@@ -108,4 +120,11 @@ pinctrl_panel_stby: panelstbygrp { + MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28 0x19 + >; + }; ++ ++ pinctrl_touch: touchgrp { ++ fsl,pins = < ++ MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06 0x19 ++ MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x150 ++ >; ++ }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch b/queue-6.18/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch new file mode 100644 index 0000000000..8973ecd67b --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch @@ -0,0 +1,38 @@ +From d084e1564ff0981a898e584e0e5212e2aa0203d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:07 +0800 +Subject: arm64: dts: imx8mp-navqp: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 741d6ac1a2a2e0f3e2cae5eef3516cdd75119e83 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there will be interrupt storm for i.MX8MP NAVQP. Per schematic, there +is no on board PULL-UP resistors for GPIO1_IO03, so need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: 682729a9d506d ("arm64: dts: freescale: Add device tree for Emcraft Systems NavQ+ Kit") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-navqp.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts +index 4a4f7c1adc23f..9dedb9f11145e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts +@@ -356,7 +356,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-nitrogen-som-correct-pad-settings-f.patch b/queue-6.18/arm64-dts-imx8mp-nitrogen-som-correct-pad-settings-f.patch new file mode 100644 index 0000000000..70a9702005 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-nitrogen-som-correct-pad-settings-f.patch @@ -0,0 +1,37 @@ +From 86b3564b4ddb900c3a8f34933f75a83452d73fd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:12 +0800 +Subject: arm64: dts: imx8mp-nitrogen-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 16611eda2c7584a1a7d6f80511d825e5108f026c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: ab4d874c9f44e ("arm64: dts: imx8mp: Add device tree for Nitrogen8M Plus ENC Carrier Board") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi +index f658309612eff..8465b36d440ae 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi +@@ -296,7 +296,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < +- MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00 0x41 ++ MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-sr-som-correct-pad-settings-for-pmi.patch b/queue-6.18/arm64-dts-imx8mp-sr-som-correct-pad-settings-for-pmi.patch new file mode 100644 index 0000000000..023877d4d0 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-sr-som-correct-pad-settings-for-pmi.patch @@ -0,0 +1,47 @@ +From 9db018c7d269d0ff878b7bdef7f64431185b1317 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:13 +0800 +Subject: arm64: dts: imx8mp-sr-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 695a476275cfb9c798a696aeaa43967701d5c78a ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: a009c0c66ecb4 ("arm64: dts: add description for solidrun imx8mp som and cubox-m") +Signed-off-by: Peng Fan +Reviewed-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi +index 4e6629f940bfa..82a3ed80235a8 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi +@@ -174,7 +174,7 @@ pmic: pmic@25 { + pinctrl-0 = <&pmic_pins>; + pinctrl-names = "default"; + interrupt-parent = <&gpio1>; +- interrupts = <3 GPIO_ACTIVE_LOW>; ++ interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + nxp,i2c-lt-enable; + + regulators { +@@ -417,7 +417,7 @@ MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x160 + + pmic_pins: pinctrl-pmic-grp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8mp-ultra-mach-sbc-correct-pad-settings.patch b/queue-6.18/arm64-dts-imx8mp-ultra-mach-sbc-correct-pad-settings.patch new file mode 100644 index 0000000000..d800ac4c6f --- /dev/null +++ b/queue-6.18/arm64-dts-imx8mp-ultra-mach-sbc-correct-pad-settings.patch @@ -0,0 +1,46 @@ +From 7b2676f50e3996bc7b7626907f69ff1d8e063ebd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:14 +0800 +Subject: arm64: dts: imx8mp-ultra-mach-sbc: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit daaf41ee72fb5fad936e7051a015cccae9b33937 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: d1c1400bd3b8b ("arm64: dts: imx8mp: Add initial support for Ultratronik imx8mp-ultra-mach-sbc board") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts +index 9ecec1a418781..3e6f9c88cc200 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts +@@ -275,7 +275,7 @@ pmic@25 { + reg = <0x25>; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; +- interrupts = <3 GPIO_ACTIVE_LOW>; ++ interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + /* + * i.MX 8M Plus Data Sheet for Consumer Products +@@ -739,7 +739,7 @@ MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x40 /* NFC_INT */ + + pinctrl_pmic: pmic-grp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40 /* #PMIC_INT */ ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 /* #PMIC_INT */ + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch b/queue-6.18/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch new file mode 100644 index 0000000000..8195ebfbc7 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch @@ -0,0 +1,57 @@ +From 178f0aee80f63a0bc8ccb191d5aee82c4f3d394c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:04:58 +0800 +Subject: arm64: dts: imx8qm-mek: switch Type-C connector power-role to dual + +From: Xu Yang + +[ Upstream commit e3d3d19d1c0050789a4813ce836a641a3387d916 ] + +When attach to PC Type-A port, the USB device controller does not function +at all. Because it is configured as source-only and a Type-A port doesn't +support PD capability, a data role swap is impossible. + +Actually, PTN5110THQ is configured for Source role only at POR, but after +POR it can operate as a DRP (Dual-Role Power). By switching the power-role +to dual, the port can operate as a sink and enter device mode when attach +to Type-A port. + +Since the board design uses EN_SRC to control the 5V VBUS path and EN_SNK +to control the 12V VBUS output, to avoid outputting a higher VBUS when in +sink role, we set the operation current limit to 0mA so that SW will not +control EN_SNK at all. + +Fixes: b237975b2cd58 ("arm64: dts: imx8qm-mek: add usb 3.0 and related type C nodes") +Signed-off-by: Xu Yang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8qm-mek.dts | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +index df99fe88cf4ac..a97883873b564 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts ++++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +@@ -593,9 +593,17 @@ ptn5110: tcpc@51 { + usb_con1: connector { + compatible = "usb-c-connector"; + label = "USB-C"; +- power-role = "source"; ++ power-role = "dual"; + data-role = "dual"; ++ try-power-role = "sink"; + source-pdos = ; ++ /* ++ * Set operational current to 0mA as we don't want EN_SNK ++ * enable 12V VBUS switch when it work as a sink. ++ */ ++ sink-pdos = ; ++ op-sink-microwatt = <0>; ++ self-powered; + + ports { + #address-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch b/queue-6.18/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch new file mode 100644 index 0000000000..09ad996d26 --- /dev/null +++ b/queue-6.18/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch @@ -0,0 +1,57 @@ +From d148a9a3dab9f65a33912404e69c8583a304b341 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:04:59 +0800 +Subject: arm64: dts: imx8qxp-mek: switch Type-C connector power-role to dual + +From: Xu Yang + +[ Upstream commit 825b8c7e1d2918d89eb378b761530d1e51dba82e ] + +When attach to PC Type-A port, the USB device controller does not function +at all. Because it is configured as source-only and a Type-A port doesn't +support PD capability, a data role swap is impossible. + +Actually, PTN5110THQ is configured for Source role only at POR, but after +POR it can operate as a DRP (Dual-Role Power). By switching the power-role +to dual, the port can operate as a sink and enter device mode when attach +to Type-A port. + +Since the board design uses EN_SRC to control the 5V VBUS path and EN_SNK +to control the 12V VBUS output, to avoid outputting a higher VBUS when in +sink role, we set the operation current limit to 0mA so that SW will not +control EN_SNK at all. + +Fixes: 2faf4ebcee2e5 ("arm64: dts: freescale: imx8qxp-mek: enable cadence usb3") +Signed-off-by: Xu Yang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +index 7b03374455410..ea78e84341523 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts ++++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +@@ -497,9 +497,17 @@ ptn5110: tcpc@50 { + usb_con1: connector { + compatible = "usb-c-connector"; + label = "USB-C"; +- power-role = "source"; ++ power-role = "dual"; + data-role = "dual"; ++ try-power-role = "sink"; + source-pdos = ; ++ /* ++ * Set operational current to 0mA as we don't want EN_SNK ++ * enable 12V VBUS switch when it work as a sink. ++ */ ++ sink-pdos = ; ++ op-sink-microwatt = <0>; ++ self-powered; + + ports { + #address-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-imx91-11x11-evk-change-usdhc-tuning-step-f.patch b/queue-6.18/arm64-dts-imx91-11x11-evk-change-usdhc-tuning-step-f.patch new file mode 100644 index 0000000000..982519b070 --- /dev/null +++ b/queue-6.18/arm64-dts-imx91-11x11-evk-change-usdhc-tuning-step-f.patch @@ -0,0 +1,56 @@ +From 114d3a71da69da562a3d7d7bb33fe4bbf2ae7df1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:23:10 +0800 +Subject: arm64: dts: imx91-11x11-evk: change usdhc tuning step for eMMC and SD + +From: Luke Wang + +[ Upstream commit 5ab0c76df2403137a6d0fb27a55e03cedf47f44c ] + +During system resume, the following errors occurred: + + [ 430.638625] mmc1: error -84 writing Cache Enable bit + [ 430.643618] mmc1: error -84 doing runtime resume + +For eMMC and SD, there are two tuning pass windows and the gap between +those two windows may only have one cell. If tuning step > 1, the gap may +just be skipped and host assumes those two windows as a continuous +windows. This will cause a wrong delay cell near the gap to be selected. + +Set the tuning step to 1 to avoid selecting the wrong delay cell. + +For SDIO, the gap is sufficiently large, so the default tuning step does +not cause this issue. + +Fixes: 6772c4cffd87 ("arm64: dts: freescale: add i.MX91 11x11 EVK basic support") +Signed-off-by: Luke Wang +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts +index aca78768dbd4b..4164d9e4e0fd2 100644 +--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts +@@ -415,6 +415,7 @@ &usdhc1 { + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ fsl,tuning-step = <1>; + status = "okay"; + }; + +@@ -429,6 +430,7 @@ &usdhc2 { + pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>; + pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; + vmmc-supply = <®_usdhc2_vmmc>; ++ fsl,tuning-step = <1>; + status = "okay"; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch b/queue-6.18/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch new file mode 100644 index 0000000000..81bcb1b35a --- /dev/null +++ b/queue-6.18/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch @@ -0,0 +1,99 @@ +From 7da12383d02dedb9feee47a62b27a774d1b6a961 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:59 +0100 +Subject: arm64: dts: lx2160a: add sda gpio references for i2c bus recovery + +From: Josua Mayer + +[ Upstream commit 89ea0dbd701f89805499d26bd90657468c789545 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +In particular i2c sda/scl pins are always configured together. Therefore +bus recovery may control both sda and scl. + +When pinmux nodes and bus recovery was enabled originally for LX2160, +only the scl-gpios were added to the i2c controller nodes. + +Add references to sda-gpios for each i2c controller. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 59417e00ac93d..e7790a94e888f 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -753,6 +753,7 @@ i2c0: i2c@2000000 { + pinctrl-0 = <&i2c0_pins>; + pinctrl-1 = <&gpio0_3_2_pins>; + scl-gpios = <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -769,6 +770,7 @@ i2c1: i2c@2010000 { + pinctrl-0 = <&i2c1_pins>; + pinctrl-1 = <&gpio0_31_30_pins>; + scl-gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -785,6 +787,7 @@ i2c2: i2c@2020000 { + pinctrl-0 = <&i2c2_pins>; + pinctrl-1 = <&gpio0_29_28_pins>; + scl-gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -801,6 +804,7 @@ i2c3: i2c@2030000 { + pinctrl-0 = <&i2c3_pins>; + pinctrl-1 = <&gpio0_27_26_pins>; + scl-gpios = <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -817,6 +821,7 @@ i2c4: i2c@2040000 { + pinctrl-0 = <&i2c4_pins>; + pinctrl-1 = <&gpio0_25_24_pins>; + scl-gpios = <&gpio0 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -833,6 +838,7 @@ i2c5: i2c@2050000 { + pinctrl-0 = <&i2c5_pins>; + pinctrl-1 = <&gpio0_23_22_pins>; + scl-gpios = <&gpio0 23 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -849,6 +855,7 @@ i2c6: i2c@2060000 { + pinctrl-0 = <&i2c6_i2c7_pins>; + pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio1 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -865,6 +872,7 @@ i2c7: i2c@2070000 { + pinctrl-0 = <&i2c6_i2c7_pins>; + pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio1 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch b/queue-6.18/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch new file mode 100644 index 0000000000..ad8ae9ed30 --- /dev/null +++ b/queue-6.18/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch @@ -0,0 +1,55 @@ +From e96125974a5cd13c1b481988c2c366e274904872 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:56 +0100 +Subject: arm64: dts: lx2160a: change i2c0 (iic1) pinmux mask to one bit + +From: Josua Mayer + +[ Upstream commit 7a3cc49ad1fc8d063abb7f5de8f1b981b99d2978 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +The first i2c bus (called IIC1 in reference manual) is configured through +field IIC1_PMUX in register RCWSR14 bit 10 which is described in the +reference manual as a single bit, unlike the other i2c buses. + +Change the bitmask for the pinmux nodes from 0x7 to 0x1 to ensure only +single bit is modified. + +Further change the zero in the same line to hexadecimal format for +consistency. + +Align with documentation by avoiding writes to reserved bits. No functional +change, as writing the extra two reserved bits is not known to cause +issues. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index bc1d34f1cd545..79a22f53afc50 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1790,11 +1790,11 @@ i2c7_scl_gpio: i2c7-scl-gpio-pins { + }; + + i2c0_scl: i2c0-scl-pins { +- pinctrl-single,bits = <0x8 0 (0x7 << 10)>; ++ pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; + + i2c0_scl_gpio: i2c0-scl-gpio-pins { +- pinctrl-single,bits = <0x8 (0x1 << 10) (0x7 << 10)>; ++ pinctrl-single,bits = <0x8 (0x1 << 10) (0x1 << 10)>; + }; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch b/queue-6.18/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch new file mode 100644 index 0000000000..1e4a0f910a --- /dev/null +++ b/queue-6.18/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch @@ -0,0 +1,74 @@ +From 062710bdd9f70cef2799be3ba154634b0a18cbd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:41:00 +0100 +Subject: arm64: dts: lx2160a: change zeros to hexadecimal in pinmux nodes + +From: Josua Mayer + +[ Upstream commit 03241620d2b9915c9e3463dbc56e9eb95ad43c08 ] + +Replace some stray zeros from decimal to hexadecimal format within +pinmux nodes. + +No functional change intended. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index e7790a94e888f..536f4bfad9a67 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1718,7 +1718,7 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,function-mask = <0x7>; + + i2c1_pins: iic2-i2c-pins { +- pinctrl-single,bits = <0x0 0 0x7>; ++ pinctrl-single,bits = <0x0 0x0 0x7>; + }; + + gpio0_31_30_pins: iic2-gpio-pins { +@@ -1730,7 +1730,7 @@ esdhc0_cd_wp_pins: iic2-sdhc-pins { + }; + + i2c2_pins: iic3-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 3)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 3)>; + }; + + gpio0_29_28_pins: iic3-gpio-pins { +@@ -1738,7 +1738,7 @@ gpio0_29_28_pins: iic3-gpio-pins { + }; + + i2c3_pins: iic4-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 6)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 6)>; + }; + + gpio0_27_26_pins: iic4-gpio-pins { +@@ -1746,7 +1746,7 @@ gpio0_27_26_pins: iic4-gpio-pins { + }; + + i2c4_pins: iic5-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 9)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 9)>; + }; + + gpio0_25_24_pins: iic5-gpio-pins { +@@ -1754,7 +1754,7 @@ gpio0_25_24_pins: iic5-gpio-pins { + }; + + i2c5_pins: iic6-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 12)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 12)>; + }; + + gpio0_23_22_pins: iic6-gpio-pins { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch b/queue-6.18/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch new file mode 100644 index 0000000000..52c065bd0b --- /dev/null +++ b/queue-6.18/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch @@ -0,0 +1,190 @@ +From ff68e74c04037b0db0af48c5084112a168671022 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:41:01 +0100 +Subject: arm64: dts: lx2160a: complete pinmux for rcwsr12 configuration word + +From: Josua Mayer + +[ Upstream commit 284ad7064aaa1badde022785cd925af29c696b21 ] + +Commit 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to +support bus recovery") introduced pinmux nodes for lx2160 i2c +interfaces, allowing runtime change between i2c and gpio functions +implementing bus recovery. + +However, the dynamic configuration area (overwrite MUX) used by the +pinctrl-single driver initially reads as zero and does not reflect the +actual hardware state set by the Reset Configuration Word (RCW) at +power-on. + +Because multiple groups of pins are configured from a single 32-bit +register, the first write from the pinctrl driver unintentionally clears +all other bits to zero. + +Add description for all bits of RCWSR12 register, allowing boards to +explicitly define and restore their intended hardware state. + +This includes i2c, gpio, flextimer, spi, can and sdhc functions. + +Other configuration words, i.e. RCWSR13 & RCWSR14 may be added in the +future for boards setting non-zero values there. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 75 +++++++++++++++++++ + 1 file changed, 75 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 536f4bfad9a67..f7fb0a0562ec7 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1717,6 +1717,7 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x7>; + ++ /* RCWSR12 */ + i2c1_pins: iic2-i2c-pins { + pinctrl-single,bits = <0x0 0x0 0x7>; + }; +@@ -1725,6 +1726,10 @@ gpio0_31_30_pins: iic2-gpio-pins { + pinctrl-single,bits = <0x0 0x1 0x7>; + }; + ++ ftm0_ch10_pins: iic2-ftm-pins { ++ pinctrl-single,bits = <0x0 0x2 0x7>; ++ }; ++ + esdhc0_cd_wp_pins: iic2-sdhc-pins { + pinctrl-single,bits = <0x0 0x6 0x7>; + }; +@@ -1737,6 +1742,14 @@ gpio0_29_28_pins: iic3-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 3) (0x7 << 3)>; + }; + ++ can0_pins: iic3-can-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 3) (0x7 << 3)>; ++ }; ++ ++ event65_pins: iic3-event-pins { ++ pinctrl-single,bits = <0x0 (0x6 << 3) (0x7 << 3)>; ++ }; ++ + i2c3_pins: iic4-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 6)>; + }; +@@ -1745,6 +1758,14 @@ gpio0_27_26_pins: iic4-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 6) (0x7 << 6)>; + }; + ++ can1_pins: iic4-can-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 6) (0x7 << 6)>; ++ }; ++ ++ event87_pins: iic4-event-pins { ++ pinctrl-single,bits = <0x0 (0x6 << 6) (0x7 << 6)>; ++ }; ++ + i2c4_pins: iic5-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 9)>; + }; +@@ -1753,6 +1774,14 @@ gpio0_25_24_pins: iic5-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 9) (0x7 << 9)>; + }; + ++ esdhc0_clksync_pins: iic5-sdhc-clk-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 9) (0x7 << 9)>; ++ }; ++ ++ dspi2_miso_mosi_pins: iic5-spi3-pins { ++ pinctrl-single,bits = <0x3 (0x2 << 9) (0x7 << 9)>; ++ }; ++ + i2c5_pins: iic6-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 12)>; + }; +@@ -1761,26 +1790,71 @@ gpio0_23_22_pins: iic6-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 12) (0x7 << 12)>; + }; + ++ esdhc1_clksync_pins: iic6-sdhc-clk-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 12) (0x7 << 12)>; ++ }; ++ + fspi_data74_pins: xspi1-data74-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 15)>; + }; + ++ gpio1_31_28_pins: xspi1-data74-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 15)>; ++ }; ++ + fspi_data30_pins: xspi1-data30-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 18)>; + }; + ++ gpio1_27_24_pins: xspi1-data30-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 18)>; ++ }; ++ + fspi_dqs_sck_cs10_pins: xspi1-base-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 21)>; + }; + ++ gpio1_23_20_pins: xspi1-base-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 21)>; ++ }; ++ + esdhc0_cmd_data30_clk_vsel_pins: sdhc1-base-sdhc-vsel-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 24)>; + }; + ++ gpio0_21_15_pins: sdhc1-base-gpio-pins { ++ pinctrl-single,bits = <0x0 (0x1 << 24) (0x7 << 24)>; ++ }; ++ ++ dspi0_pins: sdhc1-base-spi1-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_cmd_data30_clk_dspi2_cs0_pins: sdhc1-base-sdhc-spi3-pins { ++ pinctrl-single,bits = <0x0 (0x3 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_cmd_data30_clk_data4_pins: sdhc1-base-sdhc-data4-pins { ++ pinctrl-single,bits = <0x0 (0x4 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_dir_pins: sdhc1-dir-pins { ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 27)>; ++ }; ++ + gpio0_14_12_pins: sdhc1-dir-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 27) (0x7 << 27)>; + }; + ++ dspi2_cs31_pins: sdhc1-dir-spi3-pins { ++ pinctrl-single,bits = <0x0 (0x3 << 27) (0x7 << 27)>; ++ }; ++ ++ esdhc0_data75_pins: sdhc1-dir-sdhc-pins { ++ pinctrl-single,bits = <0x0 (0x4 << 27) (0x7 << 27)>; ++ }; ++ ++ /* RCWSR13 */ + gpio1_18_15_pins: iic8-iic7-gpio-pins { + pinctrl-single,bits = <0x4 0x1 0x7>; + }; +@@ -1789,6 +1863,7 @@ i2c6_i2c7_pins: iic8-iic7-i2c-pins { + pinctrl-single,bits = <0x4 0x2 0x7>; + }; + ++ /* RCWSR14 */ + i2c0_pins: iic1-i2c-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch b/queue-6.18/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch new file mode 100644 index 0000000000..7a636284e0 --- /dev/null +++ b/queue-6.18/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch @@ -0,0 +1,62 @@ +From 18247111ed44d4ebb461f15482f23e0042963aed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:57 +0100 +Subject: arm64: dts: lx2160a: remove duplicate pinmux nodes + +From: Josua Mayer + +[ Upstream commit 325ca511ca3dda936207ce737e0afe837d45a674 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +The pinmux nodes i2c7-scl-pins and i2c7-scl-gpio-pins are duplicates of +i2c6-scl-gpio and i2c6-scl-gpio-pins, writing to the same register and +bits. + +These two i2c buses i2c6/i2c7 (IIC7/IIC8) are configured together in +register RCWSR13 bits 3-0. + +Drop the duplicate node name and change references to the i2c6 node. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 79a22f53afc50..6d21982e057b3 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -862,8 +862,8 @@ i2c7: i2c@2070000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c7_scl>; +- pinctrl-1 = <&i2c7_scl_gpio>; ++ pinctrl-0 = <&i2c6_scl>; ++ pinctrl-1 = <&i2c6_scl_gpio>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -1781,14 +1781,6 @@ i2c6_scl_gpio: i2c6-scl-gpio-pins { + pinctrl-single,bits = <0x4 0x1 0x7>; + }; + +- i2c7_scl: i2c7-scl-pins { +- pinctrl-single,bits = <0x4 0x2 0x7>; +- }; +- +- i2c7_scl_gpio: i2c7-scl-gpio-pins { +- pinctrl-single,bits = <0x4 0x1 0x7>; +- }; +- + i2c0_scl: i2c0-scl-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch b/queue-6.18/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch new file mode 100644 index 0000000000..db85e69a29 --- /dev/null +++ b/queue-6.18/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch @@ -0,0 +1,219 @@ +From 3966adb45548ab00c2e4046942c334cf8b3c9f4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:58 +0100 +Subject: arm64: dts: lx2160a: rename pinmux nodes for readability + +From: Josua Mayer + +[ Upstream commit 456eb494746afd56d3a9dc30271300136e55b96e ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +Each group of pins is named in the reference manual after a primary +function using soc-specific naming, e.g. IIC1 (for i2c0). + +Hardware block numbering starts from zero in device-tree but one in the +reference manual. + +Rename the already defined pinmux nodes originally added for changing +i2c pins between i2c and gpio functions reflecting the reference manual +name (IIC) in the node name, and the device-tree name (i2c, gpio) in the +label. + +Specifically, drop the "_scl" suffix from the I2C labels because the +nodes actually configure both SDA and SCL pins together. Instead add +"_pins" suffix to avoid conflicts with I2C controller labels. + +For GPIO functions, include the specific controller and pin numbers in +the label to clarify they are generic GPIOs and help spot mistakes. + +No functional change intended. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 64 +++++++++---------- + 1 file changed, 32 insertions(+), 32 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 6d21982e057b3..59417e00ac93d 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -750,8 +750,8 @@ i2c0: i2c@2000000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c0_scl>; +- pinctrl-1 = <&i2c0_scl_gpio>; ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-1 = <&gpio0_3_2_pins>; + scl-gpios = <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -766,8 +766,8 @@ i2c1: i2c@2010000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c1_scl>; +- pinctrl-1 = <&i2c1_scl_gpio>; ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-1 = <&gpio0_31_30_pins>; + scl-gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -782,8 +782,8 @@ i2c2: i2c@2020000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c2_scl>; +- pinctrl-1 = <&i2c2_scl_gpio>; ++ pinctrl-0 = <&i2c2_pins>; ++ pinctrl-1 = <&gpio0_29_28_pins>; + scl-gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -798,8 +798,8 @@ i2c3: i2c@2030000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c3_scl>; +- pinctrl-1 = <&i2c3_scl_gpio>; ++ pinctrl-0 = <&i2c3_pins>; ++ pinctrl-1 = <&gpio0_27_26_pins>; + scl-gpios = <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -814,8 +814,8 @@ i2c4: i2c@2040000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c4_scl>; +- pinctrl-1 = <&i2c4_scl_gpio>; ++ pinctrl-0 = <&i2c4_pins>; ++ pinctrl-1 = <&gpio0_25_24_pins>; + scl-gpios = <&gpio0 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -830,8 +830,8 @@ i2c5: i2c@2050000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c5_scl>; +- pinctrl-1 = <&i2c5_scl_gpio>; ++ pinctrl-0 = <&i2c5_pins>; ++ pinctrl-1 = <&gpio0_23_22_pins>; + scl-gpios = <&gpio0 23 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -846,8 +846,8 @@ i2c6: i2c@2060000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c6_scl>; +- pinctrl-1 = <&i2c6_scl_gpio>; ++ pinctrl-0 = <&i2c6_i2c7_pins>; ++ pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -862,8 +862,8 @@ i2c7: i2c@2070000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c6_scl>; +- pinctrl-1 = <&i2c6_scl_gpio>; ++ pinctrl-0 = <&i2c6_i2c7_pins>; ++ pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -1709,11 +1709,11 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x7>; + +- i2c1_scl: i2c1-scl-pins { ++ i2c1_pins: iic2-i2c-pins { + pinctrl-single,bits = <0x0 0 0x7>; + }; + +- i2c1_scl_gpio: i2c1-scl-gpio-pins { ++ gpio0_31_30_pins: iic2-gpio-pins { + pinctrl-single,bits = <0x0 0x1 0x7>; + }; + +@@ -1721,35 +1721,35 @@ esdhc0_cd_wp_pins: iic2-sdhc-pins { + pinctrl-single,bits = <0x0 0x6 0x7>; + }; + +- i2c2_scl: i2c2-scl-pins { ++ i2c2_pins: iic3-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 3)>; + }; + +- i2c2_scl_gpio: i2c2-scl-gpio-pins { ++ gpio0_29_28_pins: iic3-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 3) (0x7 << 3)>; + }; + +- i2c3_scl: i2c3-scl-pins { ++ i2c3_pins: iic4-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 6)>; + }; + +- i2c3_scl_gpio: i2c3-scl-gpio-pins { ++ gpio0_27_26_pins: iic4-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 6) (0x7 << 6)>; + }; + +- i2c4_scl: i2c4-scl-pins { ++ i2c4_pins: iic5-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 9)>; + }; + +- i2c4_scl_gpio: i2c4-scl-gpio-pins { ++ gpio0_25_24_pins: iic5-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 9) (0x7 << 9)>; + }; + +- i2c5_scl: i2c5-scl-pins { ++ i2c5_pins: iic6-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 12)>; + }; + +- i2c5_scl_gpio: i2c5-scl-gpio-pins { ++ gpio0_23_22_pins: iic6-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 12) (0x7 << 12)>; + }; + +@@ -1773,19 +1773,19 @@ gpio0_14_12_pins: sdhc1-dir-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 27) (0x7 << 27)>; + }; + +- i2c6_scl: i2c6-scl-pins { +- pinctrl-single,bits = <0x4 0x2 0x7>; ++ gpio1_18_15_pins: iic8-iic7-gpio-pins { ++ pinctrl-single,bits = <0x4 0x1 0x7>; + }; + +- i2c6_scl_gpio: i2c6-scl-gpio-pins { +- pinctrl-single,bits = <0x4 0x1 0x7>; ++ i2c6_i2c7_pins: iic8-iic7-i2c-pins { ++ pinctrl-single,bits = <0x4 0x2 0x7>; + }; + +- i2c0_scl: i2c0-scl-pins { ++ i2c0_pins: iic1-i2c-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; + +- i2c0_scl_gpio: i2c0-scl-gpio-pins { ++ gpio0_3_2_pins: iic1-gpio-pins { + pinctrl-single,bits = <0x8 (0x1 << 10) (0x1 << 10)>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch b/queue-6.18/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch new file mode 100644 index 0000000000..88f161ec2f --- /dev/null +++ b/queue-6.18/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch @@ -0,0 +1,59 @@ +From 50110bfcb43f2ae2a46ae85f2bcb321caf98f339 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 17:25:16 +0200 +Subject: arm64: dts: marvell: armada-37xx: use 'usb2-phy' in USB3 controller's + phy-names + +From: Gabor Juhos + +[ Upstream commit 0fef19844624f8bc07651b4d26088d8940affba3 ] + +Instead of the generic 'usb2-phy' name, the Armada 37xx device trees +are using a custom 'usb2-utmi-otg-phy' name for the USB2 PHY in the USB3 +controller node. Since commit 53a2d95df836 ("usb: core: add phy notify +connect and disconnect"), this triggers a bug [1] in the USB core which +causes double use of the USB3 PHY. + +Change the PHY name to 'usb2-phy' in the SoC and in the uDPU specific +dtsi files in order to avoid triggering the bug and also to keep the +names in line with the ones used by other platforms. + +Link: https://lore.kernel.org/r/20260330-usb-avoid-usb3-phy-double-use-v1-1-d2113aecb535@gmail.com # [1] +Fixes: 53a2d95df836 ("usb: core: add phy notify connect and disconnect") +Signed-off-by: Gabor Juhos +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi | 2 +- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +index cd856c0aba71e..12deacb741ccb 100644 +--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +@@ -161,7 +161,7 @@ ð1 { + &usb3 { + status = "okay"; + phys = <&usb2_utmi_otg_phy>; +- phy-names = "usb2-utmi-otg-phy"; ++ phy-names = "usb2-phy"; + }; + + &uart0 { +diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +index c612317043ea7..a66157cb439b4 100644 +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -373,7 +373,7 @@ usb3: usb@58000 { + interrupts = ; + clocks = <&sb_periph_clk 12>; + phys = <&comphy0 0>, <&usb2_utmi_otg_phy>; +- phy-names = "usb3-phy", "usb2-utmi-otg-phy"; ++ phy-names = "usb3-phy", "usb2-phy"; + status = "disabled"; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch b/queue-6.18/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..221394b7eb --- /dev/null +++ b/queue-6.18/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From a433362c26015a98634386f65d4b53e96660dcfb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:28 +0900 +Subject: arm64: dts: mediatek: mt6795: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit c4c4823c8a5baa10b8100b01f49d7c3f4a871689 ] + +The gpio-ranges in the MT6795 pinctrl node were incorrectly defined, +therefore, GPIO196 cannot be used. +Correct the range count to match the driver. + +Fixes: b888886a4536 ("arm64: dts: mediatek: mt6795: Add pinctrl controller node") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt6795.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +index 58833e5135c8e..9757e37a65d4e 100644 +--- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +@@ -372,7 +372,7 @@ pio: pinctrl@10005000 { + ; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 196>; ++ gpio-ranges = <&pio 0 0 197>; + interrupt-controller; + #interrupt-cells = <2>; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch b/queue-6.18/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..d436504001 --- /dev/null +++ b/queue-6.18/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From 0da88c894381e410de37eba3b78c2330876cd1a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:29 +0900 +Subject: arm64: dts: mediatek: mt7981b: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit b62a927f4a46a7f58d88ba3d5fb6e88e1a4b4603 ] + +The gpio-ranges in the MT7981B pinctrl node were incorrectly defined, +therefore, pin 56 cannot be used. +Correct the range count to match the driver. + +Fixes: 62b24c7fdf0a ("arm64: dts: mediatek: mt7981: add pinctrl") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 277c11247c132..88d7c3da3e49b 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -225,7 +225,7 @@ pio: pinctrl@11d00000 { + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; +- gpio-ranges = <&pio 0 0 56>; ++ gpio-ranges = <&pio 0 0 57>; + gpio-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch b/queue-6.18/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..844e408be3 --- /dev/null +++ b/queue-6.18/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From e47887fd612980d0741746d067519ccb2cd7bf1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:30 +0900 +Subject: arm64: dts: mediatek: mt7986a: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit 820ed0c1a13c5fafb36232538d793f99a0986ef3 ] + +The gpio-ranges in the MT7986A pinctrl node were incorrectly defined, +therefore, pin 100 cannot be used. +Correct the range count to match the driver. + +Fixes: c3a064a32ed9 ("arm64: dts: mediatek: add pinctrl support for mt7986a") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index a8972330a7b89..6786e5b590e85 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -187,7 +187,7 @@ pio: pinctrl@1001f000 { + "iocfg_lb", "iocfg_tr", "iocfg_tl", "eint"; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 100>; ++ gpio-ranges = <&pio 0 0 101>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch b/queue-6.18/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch new file mode 100644 index 0000000000..fce7ee7889 --- /dev/null +++ b/queue-6.18/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch @@ -0,0 +1,58 @@ +From 49cde678f2d916c618422773dc60f8e2a616d40e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 May 2025 12:43:22 -0400 +Subject: arm64: dts: mediatek: mt8365: Describe infracfg-nao as a pure syscon +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit 0651c24658360706c30588cec0a12c05edb03e9a ] + +The infracfg-nao register space at 0x1020e000 has different registers +than the infracfg space at 0x10001000, and most importantly, doesn't +contain any clock controls. Therefore it shouldn't use the same +compatible used for the mt8365 infracfg clocks driver: +mediatek,mt8365-infracfg. Since it currently does, probe errors are +reported in the kernel logs: + + [ 0.245959] Failed to register clk ifr_pmic_tmr: -EEXIST + [ 0.245998] clk-mt8365 1020e000.infracfg: probe with driver clk-mt8365 failed with error -17 + +This register space is used only as a syscon for bus control by the +power domain controller, so in order to properly describe it and fix the +errors, set its compatible to a distinct compatible used exclusively as +a syscon, drop the clock-cells, and while at it rename the node to +'syscon' following the naming convention. + +Fixes: 6ff945376556 ("arm64: dts: mediatek: Initial mt8365-evk support") +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: David Lechner +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt8365.dtsi | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8365.dtsi b/arch/arm64/boot/dts/mediatek/mt8365.dtsi +index e6d2b3221a3b7..49ad4dee9c4cf 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8365.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8365.dtsi +@@ -495,10 +495,9 @@ iommu: iommu@10205000 { + #iommu-cells = <1>; + }; + +- infracfg_nao: infracfg@1020e000 { +- compatible = "mediatek,mt8365-infracfg", "syscon"; ++ infracfg_nao: syscon@1020e000 { ++ compatible = "mediatek,mt8365-infracfg-nao", "syscon"; + reg = <0 0x1020e000 0 0x1000>; +- #clock-cells = <1>; + }; + + rng: rng@1020f000 { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch b/queue-6.18/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch new file mode 100644 index 0000000000..dea377b12f --- /dev/null +++ b/queue-6.18/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch @@ -0,0 +1,44 @@ +From 7f19bf9d068cc3e9317b3324a3dbfb454cc092a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:51:11 +0800 +Subject: arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number + +From: Jun Yan + +[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ] + +Correct the interrupt number assigned to the Realtek PHY in the p230 + +following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm: +fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY +interrupt improvements [1]. + +[1] https://lore.kernel.org/all/20171202214037.17017-1-martin.blumenstingl@googlemail.com/ + +Fixes: b94d22d94ad2 ("ARM64: dts: meson-gx: add external PHY interrupt on some platforms") +Signed-off-by: Jun Yan +Reviewed-by: Martin Blumenstingl +Link: https://patch.msgid.link/20260330145111.115318-1-jerrysteve1101@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +index 7dffeb5931c9b..701de57ff0f37 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +@@ -84,7 +84,8 @@ external_phy: ethernet-phy@0 { + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; +- interrupts = <29 IRQ_TYPE_LEVEL_LOW>; ++ /* MAC_INTR on GPIOZ_15 */ ++ interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + eee-broken-1000t; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-hamoa-correct-iris-corners-for-the-mx.patch b/queue-6.18/arm64-dts-qcom-hamoa-correct-iris-corners-for-the-mx.patch new file mode 100644 index 0000000000..a9b103a604 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-hamoa-correct-iris-corners-for-the-mx.patch @@ -0,0 +1,53 @@ +From 2226ef6398a0fd14d6ce0127df05d6df77ac105b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:08 +0200 +Subject: arm64: dts: qcom: hamoa: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit baac8b5e43f42b632b912a6a837d94fd5bca48f2 ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: 9065340ac04d ("arm64: dts: qcom: x1e80100: Add IRIS video codec") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-1-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/x1e80100.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +index efe8d5e7079fe..66c31c1799421 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +@@ -5297,19 +5297,19 @@ opp-338000000 { + + opp-366000000 { + opp-hz = /bits/ 64 <366000000>; +- required-opps = <&rpmhpd_opp_svs_l1>, ++ required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_svs_l1>; + }; + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-481000000 { + opp-hz = /bits/ 64 <481000000>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_turbo>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-hamoa-fix-xo-clock-supply-of-platform.patch b/queue-6.18/arm64-dts-qcom-hamoa-fix-xo-clock-supply-of-platform.patch new file mode 100644 index 0000000000..ec6cc6363f --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-hamoa-fix-xo-clock-supply-of-platform.patch @@ -0,0 +1,56 @@ +From 9edec03efd4e388050d9c0c31657db2d8011df5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:12 +0200 +Subject: arm64: dts: qcom: hamoa: Fix xo clock supply of platform SD host + controller + +From: Vladimir Zapolskiy + +[ Upstream commit d094f79960e1da20c1380083c95945371baa3668 ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: ffb21c1e19b1 ("arm64: dts: qcom: x1e80100: Describe the SDHC controllers") +Reported-by: Neil Armstrong +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-4-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/x1e80100.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +index 66c31c1799421..ee9c12600f95a 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +@@ -4579,7 +4579,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", "core", "xo"; + iommus = <&apps_smmu 0x520 0>; + qcom,dll-config = <0x0007642c>; +@@ -4632,7 +4632,7 @@ sdhc_4: mmc@8844000 { + + clocks = <&gcc GCC_SDCC4_AHB_CLK>, + <&gcc GCC_SDCC4_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", "core", "xo"; + iommus = <&apps_smmu 0x160 0>; + qcom,dll-config = <0x0007642c>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-lemans-correct-iris-corners-for-the-m.patch b/queue-6.18/arm64-dts-qcom-lemans-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..86b95b8538 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-lemans-correct-iris-corners-for-the-m.patch @@ -0,0 +1,53 @@ +From 239dc3983e55727d20848b2d0b5276783b2c4fe5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:09 +0200 +Subject: arm64: dts: qcom: lemans: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit 85a6cf5ef8cf6e6de948fbba56101fa05049417f ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: 7bc95052c64f ("arm64: dts: qcom: sa8775p: add support for video node") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-2-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/lemans.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi +index 530dc1e832b70..ef20ea941aa91 100644 +--- a/arch/arm64/boot/dts/qcom/lemans.dtsi ++++ b/arch/arm64/boot/dts/qcom/lemans.dtsi +@@ -4363,19 +4363,19 @@ opp-366000000 { + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-533000000 { + opp-hz = /bits/ 64 <533000000>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo>; + }; + + opp-560000000 { + opp-hz = /bits/ 64 <560000000>; +- required-opps = <&rpmhpd_opp_turbo_l1>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo_l1>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-monaco-correct-iris-corners-for-the-m.patch b/queue-6.18/arm64-dts-qcom-monaco-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..6876b3cf2c --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-monaco-correct-iris-corners-for-the-m.patch @@ -0,0 +1,52 @@ +From 68d2de71fe068da58dc759d2d7f062fc8844817f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:10 +0200 +Subject: arm64: dts: qcom: monaco: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit bba8d9ba7df8f6592552377049fc84958fd0575a ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: bf6ec39c3f36 ("arm64: dts: qcom: qcs8300: add video node") +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-3-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/qcs8300.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/qcs8300.dtsi b/arch/arm64/boot/dts/qcom/qcs8300.dtsi +index 7a4c3e872d8ee..8580884a16e98 100644 +--- a/arch/arm64/boot/dts/qcom/qcs8300.dtsi ++++ b/arch/arm64/boot/dts/qcom/qcs8300.dtsi +@@ -4743,19 +4743,19 @@ opp-366000000 { + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-533000000 { + opp-hz = /bits/ 64 <533000000>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo>; + }; + + opp-560000000 { + opp-hz = /bits/ 64 <560000000>; +- required-opps = <&rpmhpd_opp_turbo_l1>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo_l1>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-msm8917-xiaomi-riva-fix-board-id-for-.patch b/queue-6.18/arm64-dts-qcom-msm8917-xiaomi-riva-fix-board-id-for-.patch new file mode 100644 index 0000000000..771fa47694 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-msm8917-xiaomi-riva-fix-board-id-for-.patch @@ -0,0 +1,45 @@ +From efc9e7437abea694cac03771e8380a5d201cf87d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 17:26:19 +0100 +Subject: arm64: dts: qcom: msm8917-xiaomi-riva: Fix board-id for all + bootloader +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit a49cd243503c528ea99e31a7853cf438ccc9032d ] + +Redmi 5A comes with multiple bootloader versions where the expected +board-id is different. +Change the board-id to unified form what works on both bootloader +version. + +Fixes: 26633b582056 ("arm64: dts: qcom: Add Xiaomi Redmi 5A") +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260315-riva-common-v3-1-897f130786ed@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts b/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts +index 9db503e218886..1bfb16f90ddd5 100644 +--- a/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts ++++ b/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts +@@ -18,7 +18,7 @@ / { + chassis-type = "handset"; + + qcom,msm-id = ; +- qcom,board-id = <0x1000b 2>, <0x2000b 2>; ++ qcom,board-id = <0x1000b 1>, <0x1000b 2>; + + pwm_backlight: backlight { + compatible = "pwm-backlight"; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch b/queue-6.18/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch new file mode 100644 index 0000000000..fbdad24419 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch @@ -0,0 +1,44 @@ +From 11f2a824b3a7202e0c71781321fa6beeefe1ae66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:39 +0100 +Subject: arm64: dts: qcom: msm8953-xiaomi-daisy: fix backlight +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 7131f6d909a6546329b71f2bacfdc60cb3e6020e ] + +The backlight on this device is connected via 3 strings. Currently, +the DT claims only two are present, which results in visible stripes +on the display (since every third backlight string remains unconfigured). + +Fix the number of strings to avoid that. + +Fixes: 38d779c26395 ("arm64: dts: qcom: msm8953: Add device tree for Xiaomi Mi A2 Lite") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-7-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +index ddd7af6167942..59f873a06e4dd 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +@@ -157,7 +157,7 @@ &pm8953_resin { + + &pmi8950_wled { + qcom,current-limit-microamp = <20000>; +- qcom,num-strings = <2>; ++ qcom,num-strings = <3>; + + status = "okay"; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch b/queue-6.18/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch new file mode 100644 index 0000000000..b79b2f0939 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch @@ -0,0 +1,41 @@ +From 225169a695198ca2c1ecc4e0ba5ee3c1c84ab47a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:37 +0100 +Subject: arm64: dts: qcom: msm8953-xiaomi-vince: correct wled ovp value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 9e87f0eaadccc3fecdf3c3c0334e05694804b5f5 ] + +PMI8950 doesn't actually support setting an OVP threshold value of +29.6 V. The closest allowed value is 29.5 V. Set that instead. + +Fixes: aa17e707e04a ("arm64: dts: qcom: msm8953: Add device tree for Xiaomi Redmi 5 Plus") +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-5-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +index d46325e799176..c2a290bf493c1 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +@@ -169,7 +169,7 @@ &pm8953_resin { + + &pmi8950_wled { + qcom,current-limit-microamp = <20000>; +- qcom,ovp-millivolt = <29600>; ++ qcom,ovp-millivolt = <29500>; + qcom,num-strings = <2>; + qcom,external-pfet; + qcom,cabc; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch b/queue-6.18/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch new file mode 100644 index 0000000000..81a5c42147 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch @@ -0,0 +1,38 @@ +From ee06d956592f711743a5a383f3c03d8e9dbe8813 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 18:33:11 +0100 +Subject: arm64: dts: qcom: sdm845-xiaomi-beryllium: Mark l1a regulator as + powered during boot + +From: David Heidelberg + +[ Upstream commit 3b0dd81eea6b7a239fce456ce4545af76f1a9715 ] + +The regulator must be on, since it provides the display subsystem and +therefore the bootloader had turned it on before Linux booted. + +Fixes: 77809cf74a8c ("arm64: dts: qcom: Add support for Xiaomi Poco F1 (Beryllium)") +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260320-beryllium-booton-v2-1-931d1be21eae@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +index 7480c8d7ac5b7..dbd5f08b5cdd3 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +@@ -148,6 +148,7 @@ vreg_l1a_0p875: ldo1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l5a_0p8: ldo5 { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm6125-ginkgo-fix-missing-msm-id-subt.patch b/queue-6.18/arm64-dts-qcom-sm6125-ginkgo-fix-missing-msm-id-subt.patch new file mode 100644 index 0000000000..e462552f3b --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm6125-ginkgo-fix-missing-msm-id-subt.patch @@ -0,0 +1,42 @@ +From 79f95915aa2a5a5015e4cc441a9e27fe342507b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Dec 2025 15:28:07 +0100 +Subject: arm64: dts: qcom: sm6125-ginkgo: Fix missing msm-id subtype + +From: Krzysztof Kozlowski + +[ Upstream commit 2c3b8260d1a0d9a388f2d30e3bbe50d93edfa2aa ] + +qcom,msm-id property must consist of two numbers, where the second +number is the subtype, as reported by dtbs_check: + + sm6125-xiaomi-ginkgo.dtb: / (xiaomi,ginkgo): qcom,msm-id:0: [394] is too short + +Xiaomi vendor DTS for Trinket IDP and QRD boards uses value of 0x10000, +so put it here as well. + +Signed-off-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20251229142806.241088-2-krzysztof.kozlowski@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: 535e5741bc9a ("arm64: dts: qcom: sm6125-xiaomi-ginkgo: Remove board-id") +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index 68a237215bd1f..6b68e391cf3ea 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -19,7 +19,7 @@ / { + chassis-type = "handset"; + + /* required for bootloader to select correct board */ +- qcom,msm-id = ; ++ qcom,msm-id = ; + qcom,board-id = <22 0>; + + chosen { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-correct-reserved.patch b/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-correct-reserved.patch new file mode 100644 index 0000000000..22327f8ed8 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-correct-reserved.patch @@ -0,0 +1,100 @@ +From c7d3378e1f051416caff976401e2c242ba342252 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 17:34:52 +0100 +Subject: arm64: dts: qcom: sm6125-xiaomi-ginkgo: Correct reserved memory + ranges +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 242801cc24e865cb525ef7d826ce6ebeffcad606 ] + +The device was crashing on high memory load because the reserved memory +ranges was wrongly defined. Correct the ranges for avoid the crashes. +Change the ramoops memory range to match with the values from the recovery +to be able to get the results from the device. + +Fixes: 9b1a6c925c88 ("arm64: dts: qcom: sm6125: Initial support for xiaomi-ginkgo") +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260126-xiaomi-willow-v3-2-aad7b106c311@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + .../boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 41 +++++++++++++------ + 1 file changed, 29 insertions(+), 12 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index bf03226a6f854..d5e5abdb3b2ff 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -13,6 +13,12 @@ + #include "sm6125.dtsi" + #include "pm6125.dtsi" + ++/delete-node/ &adsp_pil_mem; ++/delete-node/ &cont_splash_mem; ++/delete-node/ &gpu_mem; ++/delete-node/ &ipa_fw_mem; ++/delete-node/ &ipa_gsi_mem; ++ + / { + model = "Xiaomi Redmi Note 8"; + compatible = "xiaomi,ginkgo", "qcom,sm6125"; +@@ -36,28 +42,39 @@ framebuffer0: framebuffer@5c000000 { + }; + + reserved-memory { +- debug_mem: debug@ffb00000 { +- reg = <0x0 0xffb00000 0x0 0xc0000>; ++ adsp_pil_mem: adsp_pil_mem@55300000 { ++ reg = <0x0 0x55300000 0x0 0x2200000>; + no-map; + }; + +- last_log_mem: lastlog@ffbc0000 { +- reg = <0x0 0xffbc0000 0x0 0x80000>; ++ ipa_fw_mem: ipa_fw_mem@57500000 { ++ reg = <0x0 0x57500000 0x0 0x10000>; + no-map; + }; + +- pstore_mem: ramoops@ffc00000 { +- compatible = "ramoops"; +- reg = <0x0 0xffc40000 0x0 0xc0000>; +- record-size = <0x1000>; +- console-size = <0x40000>; +- pmsg-size = <0x20000>; ++ ipa_gsi_mem: ipa_gsi_mem@57510000 { ++ reg = <0x0 0x57510000 0x0 0x5000>; ++ no-map; + }; + +- cmdline_mem: memory@ffd00000 { +- reg = <0x0 0xffd40000 0x0 0x1000>; ++ gpu_mem: gpu_mem@57515000 { ++ reg = <0x0 0x57515000 0x0 0x2000>; + no-map; + }; ++ ++ framebuffer@5c000000 { ++ reg = <0x0 0x5c000000 0x0 (2340 * 1080 * 4)>; ++ no-map; ++ }; ++ ++ /* Matching with recovery values to be able to get the results. */ ++ ramoops@61600000 { ++ compatible = "ramoops"; ++ reg = <0x0 0x61600000 0x0 0x400000>; ++ record-size = <0x80000>; ++ pmsg-size = <0x200000>; ++ console-size = <0x100000>; ++ }; + }; + + extcon_usb: extcon-usb { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-fix-reserved-gpi.patch b/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-fix-reserved-gpi.patch new file mode 100644 index 0000000000..f8b12191f4 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-fix-reserved-gpi.patch @@ -0,0 +1,42 @@ +From 5219b5ec2617cef5ec47cfd098b3a88f7c8d4351 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 17:34:55 +0100 +Subject: arm64: dts: qcom: sm6125-xiaomi-ginkgo: Fix reserved gpio ranges +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit e8669e010991154bedadd1cd67700544e0362e99 ] + +The device was crashing on boot because the reserved gpio ranges +was wrongly defined. Correct the ranges for avoid pinctrl crashing. + +Fixes: 9b1a6c925c88 ("arm64: dts: qcom: sm6125: Initial support for xiaomi-ginkgo") +Tested-by: Biswapriyo Nath +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260126-xiaomi-willow-v3-5-aad7b106c311@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index 418cfe67a2da8..c3edeee3af3ef 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -293,7 +293,7 @@ &sdhc_2 { + }; + + &tlmm { +- gpio-reserved-ranges = <22 2>, <28 6>; ++ gpio-reserved-ranges = <0 4>, <30 4>; + }; + + &usb3 { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-board-id.patch b/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-board-id.patch new file mode 100644 index 0000000000..ebfa608fa6 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-board-id.patch @@ -0,0 +1,42 @@ +From e5dd4f5a39bd9f52714a5cb5f6888574761e7562 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 17:34:51 +0100 +Subject: arm64: dts: qcom: sm6125-xiaomi-ginkgo: Remove board-id +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 535e5741bc9acef5ea2561aa300f28370599e7e2 ] + +Remove board-id it is not necessary for the bootloader. + +Fixes: 9b1a6c925c88 ("arm64: dts: qcom: sm6125: Initial support for xiaomi-ginkgo") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260126-xiaomi-willow-v3-1-aad7b106c311@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index 6b68e391cf3ea..bf03226a6f854 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -18,9 +18,7 @@ / { + compatible = "xiaomi,ginkgo", "qcom,sm6125"; + chassis-type = "handset"; + +- /* required for bootloader to select correct board */ + qcom,msm-id = ; +- qcom,board-id = <22 0>; + + chosen { + #address-cells = <2>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-extcon.patch b/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-extcon.patch new file mode 100644 index 0000000000..a882b4683f --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-extcon.patch @@ -0,0 +1,54 @@ +From 6aa492c4198bc556fa60013d9591abef042f2390 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 17:34:54 +0100 +Subject: arm64: dts: qcom: sm6125-xiaomi-ginkgo: Remove extcon +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 79664600fd3ed3972ad9321e13d1f80267730447 ] + +GPIO pin 102 is related to DisplayPort what is not supported +by this device and it is also disabled at downstream, +remove the unnecessary extcon-usb node. + +Fixes: 9b1a6c925c88 ("arm64: dts: qcom: sm6125: Initial support for xiaomi-ginkgo") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260126-xiaomi-willow-v3-4-aad7b106c311@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index d5e5abdb3b2ff..418cfe67a2da8 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -77,11 +77,6 @@ ramoops@61600000 { + }; + }; + +- extcon_usb: extcon-usb { +- compatible = "linux,extcon-usb-gpio"; +- id-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>; +- }; +- + gpio-keys { + compatible = "gpio-keys"; + +@@ -304,7 +299,3 @@ &tlmm { + &usb3 { + status = "okay"; + }; +- +-&usb3_dwc3 { +- extcon = <&extcon_usb>; +-}; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch b/queue-6.18/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch new file mode 100644 index 0000000000..9e92d4ddb7 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch @@ -0,0 +1,63 @@ +From 14579794295f90ee5a48e5b13b54df8dc9ab4948 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 09:55:00 +0100 +Subject: arm64: dts: qcom: sm7225-fairphone-fp4: Fix conflicting bias pinctrl + +From: Luca Weiss + +[ Upstream commit be7c1badb0b934cfe88427b1d4ec3eb9f52ba587 ] + +The pinctrl nodes from sm6350.dtsi already contain a bias-* property, so +that needs to be deleted, otherwise the dtb will contain two conflicting +bias-* properties. + +Reported-by: Conor Dooley +Closes: https://lore.kernel.org/r/20260310-maritime-silly-05e7b7e03aa6@spud/ +Fixes: c4ef464b24c5 ("arm64: dts: qcom: sm7225-fairphone-fp4: Add Bluetooth") +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Reviewed-by: Conor Dooley +Link: https://lore.kernel.org/r/20260319-fp4-uart1-fix-v1-1-f6b3fedef583@fairphone.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +index 4afbab570ca15..8cbe068645ea9 100644 +--- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts ++++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +@@ -953,12 +953,14 @@ &qup_uart1_cts { + * the Bluetooth module drives the pin in either + * direction or leaves the pin fully unpowered. + */ ++ /delete-property/ bias-disable; + bias-bus-hold; + }; + + &qup_uart1_rts { + /* We'll drive RTS, so no pull */ + drive-strength = <2>; ++ /delete-property/ bias-pull-down; + bias-disable; + }; + +@@ -969,12 +971,14 @@ &qup_uart1_rx { + * in tri-state (module powered off or not driving the + * signal yet). + */ ++ /delete-property/ bias-disable; + bias-pull-up; + }; + + &qup_uart1_tx { + /* We'll drive TX, so no pull */ + drive-strength = <2>; ++ /delete-property/ bias-pull-up; + bias-disable; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch b/queue-6.18/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch new file mode 100644 index 0000000000..b8dc0b117b --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch @@ -0,0 +1,43 @@ +From 4d398e3e6641a6b3ee4ba4552c2a3da66cf39f4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 04:26:37 +0000 +Subject: arm64: dts: qcom: sm8250: Add missing CPU7 3.09GHz OPP + +From: Alexander Koskovich + +[ Upstream commit b683730e27ba4f91986c4c92f5cb7297f1e01a6d ] + +This resolves the following error seen on the ASUS ROG Phone 3: + +cpu cpu7: Voltage update failed freq=3091200 +cpu cpu7: failed to update OPP for freq=3091200 + +Fixes: 8e0e8016cb79 ("arm64: dts: qcom: sm8250: Add CPU opp tables") +Signed-off-by: Alexander Koskovich +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260307-sm8250-cpu7-opp-v1-1-435f5f6628a1@pm.me +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8250.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi +index 50dd11432bb2e..adf6b49b52c48 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi +@@ -665,6 +665,11 @@ cpu7_opp20: opp-2841600000 { + opp-hz = /bits/ 64 <2841600000>; + opp-peak-kBps = <8368000 51609600>; + }; ++ ++ cpu7_opp21: opp-3091200000 { ++ opp-hz = /bits/ 64 <3091200000>; ++ opp-peak-kBps = <8368000 51609600>; ++ }; + }; + + firmware { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.18/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..62afd30820 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,75 @@ +From e367bb8471139049c7bed4264f6ea8b3c937b8c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:13 +0200 +Subject: arm64: dts: qcom: sm8450: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit db0c5ef1abda6effdc5c85d6688fb6af2b351ae5 ] + +The reported problem of some non-working UHS-I speed modes on SM8450 +originates in commit 0a631a36f724 ("arm64: dts: qcom: Add device tree +for Sony Xperia 1 IV"), and then it was spread to all SM8450 powered +platforms by commit 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable +SDHCI SDR104/SDR50 on all boards"). + +The tests show that the rootcause of the problem was related to an +overclocking of SD cards, and it's fixed later on by commit a27ac3806b0a +("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs"). + +Since then both SDR50 and SDR104 speed modes are working fine on SM8450, +tested on SM8450-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 24.6254 s, 43.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 12.3266 s, 87.1 MB/s + +Remove the restrictions on SD card speed modes from the SM8450 platform +dtsi file and enable UHS-I speed modes. + +Fixes: 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable SDHCI SDR104/SDR50 on all boards") +Reviewed-by: Neil Armstrong +Reviewed-by: Konrad Dybcio +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-5-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 68f5e7bca7cde..6c00390010f1f 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -5404,9 +5404,6 @@ sdhc_2: mmc@8804000 { + bus-width = <4>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0x0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch b/queue-6.18/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..dfafc158a9 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From 04f0f98743d7dfd8e94d69118f8ff717924c99be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:16 +0100 +Subject: arm64: dts: qcom: sm8450: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 14044fa192c50265bc1f636108371044bbdcf7b7 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: fc8b0b9b630d ("arm64: dts: qcom: sm8450 add ITS device tree node") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-3-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 23420e6924728..68f5e7bca7cde 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -5079,7 +5079,7 @@ intc: interrupt-controller@17100000 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x17140000 0x0 0x20000>; ++ reg = <0x0 0x17140000 0x0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8550-correct-iris-corners-for-the-m.patch b/queue-6.18/arm64-dts-qcom-sm8550-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..18f462bdeb --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8550-correct-iris-corners-for-the-m.patch @@ -0,0 +1,53 @@ +From 4771fa3381aab437304fcfe5c4a7153286f5fce2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:11 +0200 +Subject: arm64: dts: qcom: sm8550: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit ff8edb5bc8bdf8bdf4573d8dc062b09cc1e6bc76 ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: 41661853ae8e ("arm64: dts: qcom: sm8550: add iris DT node") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-4-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index e294dc9c68c9a..63e17c3014061 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -3284,19 +3284,19 @@ opp-338000000 { + + opp-366000000 { + opp-hz = /bits/ 64 <366000000>; +- required-opps = <&rpmhpd_opp_svs_l1>, ++ required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_svs_l1>; + }; + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-533333334 { + opp-hz = /bits/ 64 <533333334>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.18/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..5d2e7386f0 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,67 @@ +From 8097ef3b2eeea0d2ab22181ed455d6f2dc8f954c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:14 +0200 +Subject: arm64: dts: qcom: sm8550: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit 66b0f024fba0728ddce6916dce173bb1bdd4eab0 ] + +The restriction on UHS-I speed modes was added to all SM8550 platforms +by copying it from SM8450 dtsi file, and due to the overclocking of SD +cards it was an actually reproducible problem. Since the latter issue +has been fixed, UHS-I speed modes are working fine on SM8550 boards, +below is the test performed on SM8550-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 23.5468 s, 45.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 11.9819 s, 89.6 MB/s + +Unset the UHS-I speed mode restrictions from the SM8550 platform dtsi +file, there is no indication that the SDHC controller is broken. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Reviewed-by: Neil Armstrong +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-6-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index 002ed12f942c0..118a626dfcff5 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -3191,9 +3191,6 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + bus-width = <4>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch b/queue-6.18/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..e916c83485 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From 99904faf4526def6a9505b8507abe68d520eafb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:17 +0100 +Subject: arm64: dts: qcom: sm8550: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 357c559e386705609b6b9dc0544c420e3f91f3a0 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-4-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index 63e17c3014061..c9a781273e842 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -5094,7 +5094,7 @@ ppi_cluster3: interrupt-partition-3 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0 0x17140000 0 0x20000>; ++ reg = <0 0x17140000 0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch b/queue-6.18/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch new file mode 100644 index 0000000000..cb5ac51e77 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch @@ -0,0 +1,46 @@ +From 56c38fc5796a53d0fe60c8d7b3d23c6705e54ec8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:10 +0200 +Subject: arm64: dts: qcom: sm8550: Fix xo clock supply of platform SD host + controller + +From: Vladimir Zapolskiy + +[ Upstream commit 30ac651c69bddbc83cab6d52fc5d2e03bed83282 ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-2-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index c9a781273e842..002ed12f942c0 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -3175,7 +3175,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", "core", "xo"; + iommus = <&apps_smmu 0x540 0>; + qcom,dll-config = <0x0007642c>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8650-correct-iris-corners-for-the-m.patch b/queue-6.18/arm64-dts-qcom-sm8650-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..036a00a986 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8650-correct-iris-corners-for-the-m.patch @@ -0,0 +1,62 @@ +From 40abc7b5111529a9d1de3abb0f556c02838467bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:12 +0200 +Subject: arm64: dts: qcom: sm8650: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit 7c302a2a6c1a4644e798ecfc4e72ddc4acec653f ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: 56cf5ad39a55 ("arm64: dts: qcom: sm8650: add iris DT node") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-5-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index d22a26a416ccc..4e34c686265d6 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -5201,13 +5201,13 @@ opp-196000000 { + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; +- required-opps = <&rpmhpd_opp_low_svs>, ++ required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_low_svs>; + }; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; +- required-opps = <&rpmhpd_opp_svs>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs>; + }; + +@@ -5219,13 +5219,13 @@ opp-435000000 { + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-533333334 { + opp-hz = /bits/ 64 <533333334>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_turbo>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.18/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..d568fdd60e --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,68 @@ +From 91d7b1e44c97a502686f44f90ae7f717df19516d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:15 +0200 +Subject: arm64: dts: qcom: sm8650: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit 93f823e7d48232e62fb8fb74481696609c90244a ] + +The restriction on UHS-I speed modes was added to all SM8650 platforms +by copying it from SM8450 and SM8550 dtsi files, and it was an actually +reproducible problem due to the overclocking of SD cards. Since the latter +issue has been fixed in the SM8650 GCC driver, UHS-I speed modes are +working fine on SM8650 boards, below is the test performed on SM8650-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 24.8086 s, 43.3 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 12.9448 s, 82.9 MB/s + +Unset the UHS-I speed mode restrictions from the SM8550 platform dtsi +file, there is no indication that the SDHC controller is broken. + +Fixes: 10e024671295 ("arm64: dts: qcom: sm8650: add interconnect dependent device nodes") +Reviewed-by: Neil Armstrong +Reviewed-by: Konrad Dybcio +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-7-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index d157cbc493d92..069b7f1267a0e 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -4941,9 +4941,6 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + + bus-width = <4>; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0>; +- + qcom,dll-config = <0x0007642c>; + qcom,ddr-config = <0x80040868>; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch b/queue-6.18/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..5b581a2d5c --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From d61c561e3a3e1307b8d5a274f735326abe42ff3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:18 +0100 +Subject: arm64: dts: qcom: sm8650: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 6c8e2ca1263d0da5976418ed285eaec430e8d87f ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: d2350377997f ("arm64: dts: qcom: add initial SM8650 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-5-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 4e34c686265d6..0faaf54e597ea 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -6885,7 +6885,7 @@ ppi_cluster2: interrupt-partition-2 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0 0x17140000 0 0x20000>; ++ reg = <0 0x17140000 0 0x40000>; + + msi-controller; + #msi-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch b/queue-6.18/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch new file mode 100644 index 0000000000..828d14119f --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch @@ -0,0 +1,45 @@ +From 9f7b4f4edb41f9924908810389c3585b7eb2d14d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:11 +0200 +Subject: arm64: dts: qcom: sm8650: Fix xo clock supply of SD host controller + +From: Vladimir Zapolskiy + +[ Upstream commit 390903efaa057c44fd80e7d9839419c50092018e ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: 10e024671295 ("arm64: dts: qcom: sm8650: add interconnect dependent device nodes") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-3-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 0faaf54e597ea..d157cbc493d92 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -4922,7 +4922,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", + "core", + "xo"; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-sm8750-fix-gic_its-range-length.patch b/queue-6.18/arm64-dts-qcom-sm8750-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..369ff010f3 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-sm8750-fix-gic_its-range-length.patch @@ -0,0 +1,37 @@ +From 12d67f6b79ebccd16dcb68fcb733eaddaae6e589 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:19 +0100 +Subject: arm64: dts: qcom: sm8750: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit c2f1f8874fda674af1efaa9a90efbdea8b6834ff ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: 068c3d3c83be ("arm64: dts: qcom: Add base SM8750 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-6-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8750.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi +index 33963fee1f699..3e1d1133792bb 100644 +--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi +@@ -3299,7 +3299,7 @@ intc: interrupt-controller@16000000 { + + gic_its: msi-controller@16040000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x16040000 0x0 0x20000>; ++ reg = <0x0 0x16040000 0x0 0x40000>; + + msi-controller; + #msi-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-qcom-talos-add-missing-clock-names-to-gcc.patch b/queue-6.18/arm64-dts-qcom-talos-add-missing-clock-names-to-gcc.patch new file mode 100644 index 0000000000..b838cee719 --- /dev/null +++ b/queue-6.18/arm64-dts-qcom-talos-add-missing-clock-names-to-gcc.patch @@ -0,0 +1,46 @@ +From e44dd9c435cfe67154b5630c8ba22515226a8f6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 10:45:03 +0100 +Subject: arm64: dts: qcom: talos: Add missing clock-names to GCC + +From: Konrad Dybcio + +[ Upstream commit c653607929bb4e0d8b80573bdb523adab5b975c2 ] + +The binding for this clock controller requires that clock-names are +present. They're not really used by the kernel driver, but they're +marked as required, so someone might have assumed it's done on purpose +(where in reality we try to stay away from that since index-based +references are faster, take up less space and are already widely used) +and referenced it in drivers for another OS. + +Hence, do the least painful thing and add the missing entries. + +Fixes: 8e266654a2fe ("arm64: dts: qcom: add QCS615 platform") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260126-topic-talos_dt_warn-v1-1-c452afc647ad@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6150.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi +index 363b9f436cd0a..a066ad5ffde57 100644 +--- a/arch/arm64/boot/dts/qcom/sm6150.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi +@@ -522,6 +522,9 @@ gcc: clock-controller@100000 { + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>; ++ clock-names = "bi_tcxo", ++ "bi_tcxo_ao", ++ "sleep_clk"; + + #clock-cells = <1>; + #reset-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-rockchip-add-mphy-reset-to-ufshc-node.patch b/queue-6.18/arm64-dts-rockchip-add-mphy-reset-to-ufshc-node.patch new file mode 100644 index 0000000000..da57c8e78d --- /dev/null +++ b/queue-6.18/arm64-dts-rockchip-add-mphy-reset-to-ufshc-node.patch @@ -0,0 +1,47 @@ +From 82333754a5a439c63a32c0142248e68505385cf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 09:11:53 +0800 +Subject: arm64: dts: rockchip: Add mphy reset to ufshc node + +From: Shawn Lin + +[ Upstream commit 792c42da47fa199f90492784e3c57280acd57f22 ] + +The mphy reset signal is used to reset the physical adapter. Resetting +other components while leaving the mphy unreset may occasionally prevent +the UFS controller from successfully linking up with the device. + +This addresses an intermittent hardware bug where the UFS link fails to +establish under specific timing conditions with certain chips. While +difficult to reproduce initially, this issue was consistently observed in +downstream testing and requires explicit mphy reset control for full +stability. + +Fixes: c75e5e010fef ("scsi: arm64: dts: rockchip: Add UFS support for RK3576 SoC") +Signed-off-by: Shawn Lin +Link: https://patch.msgid.link/1773277913-29580-1-git-send-email-shawn.lin@rock-chips.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3576.dtsi | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi +index 70e67d4dccb8a..5d69a81aecc64 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi +@@ -1829,8 +1829,9 @@ ufshc: ufshc@2a2d0000 { + pinctrl-0 = <&ufs_refclk &ufs_rstgpio>; + pinctrl-names = "default"; + resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>, +- <&cru SRST_A_UFS>, <&cru SRST_P_UFS_GRF>; +- reset-names = "biu", "sys", "ufs", "grf"; ++ <&cru SRST_A_UFS>, <&cru SRST_P_UFS_GRF>, ++ <&cru SRST_MPHY_INIT>; ++ reset-names = "biu", "sys", "ufs", "grf", "mphy"; + reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>; + status = "disabled"; + }; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch b/queue-6.18/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch new file mode 100644 index 0000000000..4a8f855a13 --- /dev/null +++ b/queue-6.18/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch @@ -0,0 +1,39 @@ +From a5099b6d84c0390d4b4f2f5fa961b85153274268 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 08:46:48 -0500 +Subject: arm64: dts: rockchip: Correct Fan Supply for Gameforce Ace + +From: Chris Morgan + +[ Upstream commit c7079215b7dbf88b84a95ff13982bf3dab3cfbe1 ] + +Correct the regulator providing power to the PWM controlled fan. +Without this fix the fan only runs when the audio path is playing +audio (because the speaker amplifier and PWM fan share the same +regulator). + +Fixes: 4e946c447a04 ("arm64: dts: rockchip: Add GameForce Ace") +Signed-off-by: Chris Morgan +Link: https://patch.msgid.link/20260310134648.550006-1-macroalpha82@gmail.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +index f5894672fcbd3..ef8805219ea16 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +@@ -304,7 +304,7 @@ pwm_fan: pwm-fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + cooling-levels = <0 120 150 180 210 240 255>; +- fan-supply = <&vcc5v0_sys>; ++ fan-supply = <&vcc5v0_spk>; + interrupt-parent = <&gpio4>; + interrupts = ; + pulses-per-revolution = <4>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch b/queue-6.18/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch new file mode 100644 index 0000000000..81e28ff6ac --- /dev/null +++ b/queue-6.18/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch @@ -0,0 +1,70 @@ +From af997e72879e2d8e3a17ef2d67d84fae5726ec00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 08:49:19 -0500 +Subject: arm64: dts: rockchip: Correct Joystick Axes on Gameforce Ace + +From: Chris Morgan + +[ Upstream commit c337c1b561c1c3016d30776d7dc2032ea4979334 ] + +The Gameforce Ace's joystick axes were set incorrectly initially, +getting the X/Y and RX/RY axes backwards. Additionally, correct the +RY axis so that it is inverted. + +All axes tested with evtest and outputting correct values. + +Fixes: 4e946c447a04 ("arm64: dts: rockchip: Add GameForce Ace") +Reported-by: sydarn +Signed-off-by: Chris Morgan +Link: https://patch.msgid.link/20260310134919.550023-1-macroalpha82@gmail.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +index ef8805219ea16..afac54ba58318 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +@@ -60,8 +60,8 @@ axis@0 { + reg = <0>; + abs-flat = <40>; + abs-fuzz = <30>; +- abs-range = <0 4095>; +- linux,code = ; ++ abs-range = <4095 0>; ++ linux,code = ; + }; + + axis@1 { +@@ -69,7 +69,7 @@ axis@1 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + + axis@2 { +@@ -77,7 +77,7 @@ axis@2 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + + axis@3 { +@@ -85,7 +85,7 @@ axis@3 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch b/queue-6.18/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch new file mode 100644 index 0000000000..8eb5fd7937 --- /dev/null +++ b/queue-6.18/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch @@ -0,0 +1,49 @@ +From c94257ae815adbd289346643683088add2aa2098 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:04:53 +0800 +Subject: arm64: dts: rockchip: Fix Bluetooth stability on LCKFB TaiShan Pi + +From: Ming Wang + +[ Upstream commit 861a9593e10bb6ab2a492b315c8a2a3aad70ac00 ] + +The AP6212 WiFi/BT module on the LCKFB TaiShan Pi (RK3566) is prone to +communication timeouts and reset failures (error -110) when operating at +3 Mbps. + +This patch stabilizes the Bluetooth interface by: +1. Updating the compatible string to 'brcm,bcm43430a1-bt' to better reflect + the actual chip revision used in the AP6212 module. +2. Lowering the maximum UART baud rate from 3,000,000 to 1,500,000 bps. + Tests show that 1.5 Mbps is the reliable upper limit for this board's + UART configuration, eliminating the initialization timeouts. + +Fixes: 251e5ade9ba4 ("arm64: dts: rockchip: add dts for LCKFB Taishan Pi RK3566") +Signed-off-by: Ming Wang +Link: https://patch.msgid.link/20260206090453.1041919-1-wming126@126.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts +index ed65d31204446..18a560a6e2a4a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts +@@ -635,10 +635,10 @@ &uart1 { + status = "okay"; + + bluetooth: bluetooth { +- compatible = "brcm,bcm43438-bt"; ++ compatible = "brcm,bcm43430a1-bt"; + clocks = <&rk809 1>; + clock-names = "lpo"; +- max-speed = <3000000>; ++ max-speed = <1500000>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>; + shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-rockchip-fix-rk3562-evb2-model-name.patch b/queue-6.18/arm64-dts-rockchip-fix-rk3562-evb2-model-name.patch new file mode 100644 index 0000000000..a46b34aa8e --- /dev/null +++ b/queue-6.18/arm64-dts-rockchip-fix-rk3562-evb2-model-name.patch @@ -0,0 +1,39 @@ +From 24f740a5efdc78b6c3a6b231de2671e5372a1327 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:55:00 +0000 +Subject: arm64: dts: rockchip: Fix RK3562 EVB2 model name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: 谢致邦 (XIE Zhibang) + +[ Upstream commit ede6a05606892bab4f6d785ffcfc124150c2eb32 ] + +The model name should be "Rockchip RK3562 EVB2 V10 Board". + +Fixes: ceb6ef1ea900 ("arm64: dts: rockchip: Add RK3562 evb2 devicetree") +Signed-off-by: 谢致邦 (XIE Zhibang) +Link: https://patch.msgid.link/tencent_78E7E3F6991FB4403D5ADC9E6A6BC3BF8307@qq.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts b/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts +index 6a84db154a7d5..387062eea5208 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts +@@ -13,7 +13,7 @@ + #include "rk3562.dtsi" + + / { +- model = "Rockchip RK3562 EVB V20 Board"; ++ model = "Rockchip RK3562 EVB2 V10 Board"; + compatible = "rockchip,rk3562-evb2-v10", "rockchip,rk3562"; + + chosen: chosen { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch b/queue-6.18/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch new file mode 100644 index 0000000000..226e8553c6 --- /dev/null +++ b/queue-6.18/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch @@ -0,0 +1,42 @@ +From 7a6751b9900e63003ef915e75e5372c6f0c02a8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 09:03:02 +0100 +Subject: arm64: dts: rockchip: Make Jaguar PCIe-refclk pin use pull-up config + +From: Heiko Stuebner + +[ Upstream commit f45d4356feeba1c8dac3414b688f59292ddfc9f9 ] + +The hardware PU/PD config of the pin after reset is to pull-up and on +Jaguar this will also keep the device in reset until the driver actually +enables the pin. So restore this boot pull-up config of the pin on Jaguar +instead of setting it to pull-none. + +Suggested-by: Quentin Schulz +Fixes: 0ec7e1096332 ("arm64: dts: rockchip: add PCIe3 support on rk3588-jaguar") +Signed-off-by: Heiko Stuebner +Reviewed-by: Shawn Lin +Reviewed-by: Quentin Schulz +Link: https://patch.msgid.link/20260210080303.680403-5-heiko@sntech.de +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts +index 176925d0a1a80..557158093b586 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts +@@ -585,7 +585,7 @@ led1_pin: led1-pin { + + pcie30x4 { + pcie30x4_clkreqn_m0: pcie30x4-clkreqn-m0 { +- rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; ++ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + pcie30x4_perstn_m0: pcie30x4-perstn-m0 { +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch b/queue-6.18/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch new file mode 100644 index 0000000000..6fa598ff1c --- /dev/null +++ b/queue-6.18/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch @@ -0,0 +1,58 @@ +From 4cbda64792462d1ee536ee2d1177137101ae5d4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 17:37:31 -0600 +Subject: arm64: dts: ti: k3-am62-lp-sk: Enable internal pulls for MMC0 data + pins + +From: Judith Mendez + +[ Upstream commit ee2a9d9c9e6c9643fb7e45febcaedfbc038e483a ] + +AM62 LP SK board does not have external pullups on MMC0 DAT1-DAT7 +pins [0]. Enable internal pullups on DAT1-DAT7 considering: +- without a host-side pullup, these lines rely solely on the eMMC + device's internal pullup (R_int, 10-150K per JEDEC), which may + exceed the recommended 50K max for 1.8V VCCQ +- JEDEC JESD84-B51 Table 200 requires host-side pullups (R_DAT, + 10K-100K) on all data lines to prevent bus floating + +[0] https://www.ti.com/lit/zip/SPRR471 + +Fixes: a0b8da04153e ("arm64: dts: ti: k3-am62*: Move eMMC pinmux to top level board file") +Signed-off-by: Judith Mendez +Reviewed-by: Moteen Shah +Link: https://patch.msgid.link/20260223233731.2690472-4-jm@ti.com +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts +index ecfba05fe5c27..5ed757c19db60 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts +@@ -88,13 +88,13 @@ main_mmc0_pins_default: main-mmc0-default-pins { + AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (V3) MMC0_CMD */ + AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (Y1) MMC0_CLK */ + AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (V2) MMC0_DAT0 */ +- AM62X_IOPAD(0x210, PIN_INPUT, 0) /* (V1) MMC0_DAT1 */ +- AM62X_IOPAD(0x20c, PIN_INPUT, 0) /* (W2) MMC0_DAT2 */ +- AM62X_IOPAD(0x208, PIN_INPUT, 0) /* (W1) MMC0_DAT3 */ +- AM62X_IOPAD(0x204, PIN_INPUT, 0) /* (Y2) MMC0_DAT4 */ +- AM62X_IOPAD(0x200, PIN_INPUT, 0) /* (W3) MMC0_DAT5 */ +- AM62X_IOPAD(0x1fc, PIN_INPUT, 0) /* (W4) MMC0_DAT6 */ +- AM62X_IOPAD(0x1f8, PIN_INPUT, 0) /* (V4) MMC0_DAT7 */ ++ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (V1) MMC0_DAT1 */ ++ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (W2) MMC0_DAT2 */ ++ AM62X_IOPAD(0x208, PIN_INPUT_PULLUP, 0) /* (W1) MMC0_DAT3 */ ++ AM62X_IOPAD(0x204, PIN_INPUT_PULLUP, 0) /* (Y2) MMC0_DAT4 */ ++ AM62X_IOPAD(0x200, PIN_INPUT_PULLUP, 0) /* (W3) MMC0_DAT5 */ ++ AM62X_IOPAD(0x1fc, PIN_INPUT_PULLUP, 0) /* (W4) MMC0_DAT6 */ ++ AM62X_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (V4) MMC0_DAT7 */ + >; + }; + +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch b/queue-6.18/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch new file mode 100644 index 0000000000..5bc80821d0 --- /dev/null +++ b/queue-6.18/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch @@ -0,0 +1,39 @@ +From f5b1358a07924e20e8627b647feb5bf7e589522e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:36:57 +0100 +Subject: arm64: dts: ti: k3-am62-verdin: Fix SPI_1 GPIO CS pinctrl label + +From: Francesco Dolcini + +[ Upstream commit 944dffaec1ef0f21c203728de77b5618ed70df6e ] + +Fix SPI_1_CS GPIO pinmux label, this is spi1_cs, not qspi1_io4. + +There are no user of this label yet, therefore this change does not +create any compatibility issue. + +Fixes: fcb335934c51 ("arm64: dts: ti: verdin-am62: Improve spi1 chip-select pinctrl") +Signed-off-by: Francesco Dolcini +Link: https://patch.msgid.link/20260324093705.26730-3-francesco@dolcini.it +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +index 796f2cedf5d62..059ec492a973e 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +@@ -278,7 +278,7 @@ AM62X_IOPAD(0x0018, PIN_INPUT, 7) /* (F24) OSPI0_D3.GPIO0_6 */ /* SODIMM 62 */ + }; + + /* Verdin SPI_1 CS as GPIO */ +- pinctrl_qspi1_io4_gpio: main-gpio0-7-default-pins { ++ pinctrl_spi1_cs_gpio: main-gpio0-7-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 7) /* (J23) OSPI0_D4.GPIO0_7 */ /* SODIMM 202 */ + >; +-- +2.53.0 + diff --git a/queue-6.18/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch b/queue-6.18/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch new file mode 100644 index 0000000000..1621125d84 --- /dev/null +++ b/queue-6.18/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch @@ -0,0 +1,53 @@ +From 5220f4c93b90afd78e45901b88601d3fd4370752 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 17:37:29 -0600 +Subject: arm64: dts: ti: k3-am62p5-sk: Disable MMC1 internal pulls on data + pins + +From: Judith Mendez + +[ Upstream commit 6d4441be969bea89bb9702781f5dfb3a8f2a02a4 ] + +AM62P SK has external 10K pullups on MMC1 DAT1-DAT3 pins [0]. +Disable internal pullups on DAT1-DAT3 so that each line has a +single pullup source: +- with both pullups enabled, the effective parallel resistance on + DAT1-3 (~8.33K) drops below the 10K minimum pullup requirement + for data lines (per SD Physical Layer Specification) +- removing internal pullups makes DAT1-3 match DAT0 10K + external pullup so its consistent and within spec +- both internal and external pullups enabled equals unnecessary power + consumption + +[0] https://www.ti.com/lit/zip/SPRR487 + +Fixes: c00504ea42c0 ("arm64: dts: ti: k3-am62p5-sk: Updates for SK EVM") +Signed-off-by: Judith Mendez +Reviewed-by: Moteen Shah +Link: https://patch.msgid.link/20260223233731.2690472-2-jm@ti.com +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62p5-sk.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +index a064a632680ec..f5054912ad910 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +@@ -271,9 +271,9 @@ main_mmc1_pins_default: main-mmc1-default-pins { + AM62PX_IOPAD(0x023c, PIN_INPUT, 0) /* (H20) MMC1_CMD */ + AM62PX_IOPAD(0x0234, PIN_OUTPUT, 0) /* (J24) MMC1_CLK */ + AM62PX_IOPAD(0x0230, PIN_INPUT, 0) /* (H21) MMC1_DAT0 */ +- AM62PX_IOPAD(0x022c, PIN_INPUT_PULLUP, 0) /* (H23) MMC1_DAT1 */ +- AM62PX_IOPAD(0x0228, PIN_INPUT_PULLUP, 0) /* (H22) MMC1_DAT2 */ +- AM62PX_IOPAD(0x0224, PIN_INPUT_PULLUP, 0) /* (H25) MMC1_DAT3 */ ++ AM62PX_IOPAD(0x022c, PIN_INPUT, 0) /* (H23) MMC1_DAT1 */ ++ AM62PX_IOPAD(0x0228, PIN_INPUT, 0) /* (H22) MMC1_DAT2 */ ++ AM62PX_IOPAD(0x0224, PIN_INPUT, 0) /* (H25) MMC1_DAT3 */ + AM62PX_IOPAD(0x0240, PIN_INPUT, 0) /* (D23) MMC1_SDCD */ + >; + bootph-all; +-- +2.53.0 + diff --git a/queue-6.18/arm64-entry-don-t-preempt-with-serror-or-debug-maske.patch b/queue-6.18/arm64-entry-don-t-preempt-with-serror-or-debug-maske.patch new file mode 100644 index 0000000000..455af5787f --- /dev/null +++ b/queue-6.18/arm64-entry-don-t-preempt-with-serror-or-debug-maske.patch @@ -0,0 +1,87 @@ +From 8e87d86f2dfbec52ba2f971fb4dcb056c96d0620 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 14:16:46 +0100 +Subject: arm64: entry: Don't preempt with SError or Debug masked + +From: Mark Rutland + +[ Upstream commit 2371bd83b3df9d833191fe58dadb0e69a794a1cd ] + +On arm64, involuntary kernel preemption has been subtly broken since the +move to the generic irqentry code. When preemption occurs, the new task +may run with SError and Debug exceptions masked unexpectedly, leading to +a loss of RAS events, breakpoints, watchpoints, and single-step +exceptions. + +Prior to moving to the generic irqentry code, involuntary preemption of +kernel mode would only occur when returning from regular interrupts, in +a state where interrupts were masked and all other arm64-specific +exceptions (SError, Debug, and pseudo-NMI) were unmasked. This is the +only state in which it is valid to switch tasks. + +As part of moving to the generic irqentry code, the involuntary +preemption logic was moved such that involuntary preemption could occur +when returning from any (non-NMI) exception. As most exception handlers +mask all arm64-specific exceptions before this point, preemption could +occur in a state where arm64-specific exceptions were masked. This is +not a valid state to switch tasks, and resulted in the loss of +exceptions described above. + +As a temporary bodge, avoid the loss of exceptions by avoiding +involuntary preemption when SError and/or Debug exceptions are masked. +Practically speaking this means that involuntary preemption will only +occur when returning from regular interrupts, as was the case before +moving to the generic irqentry code. + +Fixes: 99eb057ccd67 ("arm64: entry: Move arm64_preempt_schedule_irq() into __exit_to_kernel_mode()") +Reported-by: Ada Couprie Diaz +Reported-by: Vladimir Murzin +Signed-off-by: Mark Rutland +Cc: Andy Lutomirski +Cc: Jinjie Ruan +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Cc: Will Deacon +Reviewed-by: Jinjie Ruan +Acked-by: Peter Zijlstra (Intel) +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/entry-common.h | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/arm64/include/asm/entry-common.h b/arch/arm64/include/asm/entry-common.h +index cab8cd78f6938..20f0a7c7bde15 100644 +--- a/arch/arm64/include/asm/entry-common.h ++++ b/arch/arm64/include/asm/entry-common.h +@@ -29,14 +29,19 @@ static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs, + + static inline bool arch_irqentry_exit_need_resched(void) + { +- /* +- * DAIF.DA are cleared at the start of IRQ/FIQ handling, and when GIC +- * priority masking is used the GIC irqchip driver will clear DAIF.IF +- * using gic_arch_enable_irqs() for normal IRQs. If anything is set in +- * DAIF we must have handled an NMI, so skip preemption. +- */ +- if (system_uses_irq_prio_masking() && read_sysreg(daif)) +- return false; ++ if (system_uses_irq_prio_masking()) { ++ /* ++ * DAIF.DA are cleared at the start of IRQ/FIQ handling, and when GIC ++ * priority masking is used the GIC irqchip driver will clear DAIF.IF ++ * using gic_arch_enable_irqs() for normal IRQs. If anything is set in ++ * DAIF we must have handled an NMI, so skip preemption. ++ */ ++ if (read_sysreg(daif)) ++ return false; ++ } else { ++ if (read_sysreg(daif) & (PSR_D_BIT | PSR_A_BIT)) ++ return false; ++ } + + /* + * Preempting a task from an IRQ means we leave copies of PSTATE +-- +2.53.0 + diff --git a/queue-6.18/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch b/queue-6.18/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch new file mode 100644 index 0000000000..54c7610528 --- /dev/null +++ b/queue-6.18/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch @@ -0,0 +1,38 @@ +From c9db306291c4c75aac496c3cb03962ea87a71327 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 19:42:31 +0800 +Subject: arm64: kexec: Remove duplicate allocation for trans_pgd + +From: Wang Wensheng + +[ Upstream commit ee020bf6f14094c9ae434bb37e6957a1fdad513c ] + +trans_pgd would be allocated in trans_pgd_create_copy(), so remove the +duplicate allocation before calling trans_pgd_create_copy(). + +Fixes: 3744b5280e67 ("arm64: kexec: install a copy of the linear-map") +Signed-off-by: Wang Wensheng +Reviewed-by: Pasha Tatashin +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/machine_kexec.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c +index 6f121a0164a48..28df62051cc97 100644 +--- a/arch/arm64/kernel/machine_kexec.c ++++ b/arch/arm64/kernel/machine_kexec.c +@@ -129,9 +129,6 @@ int machine_kexec_post_load(struct kimage *kimage) + } + + /* Create a copy of the linear map */ +- trans_pgd = kexec_page_alloc(kimage); +- if (!trans_pgd) +- return -ENOMEM; + rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END); + if (rc) + return rc; +-- +2.53.0 + diff --git a/queue-6.18/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch b/queue-6.18/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch new file mode 100644 index 0000000000..86ee52c722 --- /dev/null +++ b/queue-6.18/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch @@ -0,0 +1,86 @@ +From 0e3893ad6ab7e73b030bb2c2bc25ed4d6f4c2532 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 16:58:08 +0800 +Subject: arm64: Reserve an extra page for early kernel mapping + +From: Zhaoyang Huang + +[ Upstream commit 4d8e74ad4585672489da6145b3328d415f50db82 ] + +The final part of [data, end) segment may overflow into the next page of +init_pg_end[1] which is the gap page before early_init_stack[2]: + +[1] +crash_arm64_v9.0.1> vtop ffffffed00601000 +VIRTUAL PHYSICAL +ffffffed00601000 83401000 + +PAGE DIRECTORY: ffffffecffd62000 + PGD: ffffffecffd62da0 => 10000000833fb003 + PMD: ffffff80033fb018 => 10000000833fe003 + PTE: ffffff80033fe008 => 68000083401f03 + PAGE: 83401000 + + PTE PHYSICAL FLAGS +68000083401f03 83401000 (VALID|SHARED|AF|NG|PXN|UXN) + + PAGE PHYSICAL MAPPING INDEX CNT FLAGS +fffffffec00d0040 83401000 0 0 1 4000 reserved + +[2] +ffffffed002c8000 (r) __pi__data +ffffffed0054e000 (d) __pi___bss_start +ffffffed005f5000 (b) __pi_init_pg_dir +ffffffed005fe000 (b) __pi_init_pg_end +ffffffed005ff000 (B) early_init_stack +ffffffed00608000 (b) __pi__end + +For 4K pages, the early kernel mapping may use 2MB block entries but the +kernel segments are only 64KB aligned. Segment boundaries that fall +within a 2MB block therefore require a PTE table so that different +attributes can be applied on either side of the boundary. + +KERNEL_SEGMENT_COUNT still correctly counts the five permanent kernel +VMAs registered by declare_kernel_vmas(). However, since commit +5973a62efa34 ("arm64: map [_text, _stext) virtual address range +non-executable+read-only"), the early mapper also maps [_text, _stext) +separately from [_stext, _etext). This adds one more early-only split +and can require one more page-table page than the existing +EARLY_SEGMENT_EXTRA_PAGES allowance reserves. + +Increase the 4K-page early mapping allowance by one page to cover that +additional split. + +Fixes: 5973a62efa34 ("arm64: map [_text, _stext) virtual address range non-executable+read-only") +Assisted-by: TRAE:GLM-5.1 +Suggested-by: Ard Biesheuvel +Signed-off-by: Zhaoyang Huang +[catalin.marinas@arm.com: rewrote part of the commit log] +[catalin.marinas@arm.com: expanded the code comment] +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/kernel-pgtable.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h +index 74a4f738c5f52..229ee7976f693 100644 +--- a/arch/arm64/include/asm/kernel-pgtable.h ++++ b/arch/arm64/include/asm/kernel-pgtable.h +@@ -68,7 +68,12 @@ + #define KERNEL_SEGMENT_COUNT 5 + + #if SWAPPER_BLOCK_SIZE > SEGMENT_ALIGN +-#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1) ++/* ++ * KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping ++ * has one additional split, [_text, _stext). Reserve one more page for the ++ * SWAPPER_BLOCK_SIZE-unaligned boundaries. ++ */ ++#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2) + /* + * The initial ID map consists of the kernel image, mapped as two separate + * segments, and may appear misaligned wrt the swapper block size. This means +-- +2.53.0 + diff --git a/queue-6.18/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch b/queue-6.18/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch new file mode 100644 index 0000000000..a9b8230970 --- /dev/null +++ b/queue-6.18/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch @@ -0,0 +1,47 @@ +From 2ea81b3067fd6bcce531b9471e2f2954dccf1113 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 17:54:59 +0800 +Subject: arm64/scs: Fix potential sign extension issue of advance_loc4 + +From: Wentao Guan + +[ Upstream commit 4023b7424ecd5d38cc75b650d6c1bf630ef8cb40 ] + +The expression (*opcode++ << 24) and exp * code_alignment_factor +may overflow signed int and becomes negative. + +Fix this by casting each byte to u64 before shifting. Also fix +the misaligned break statement while we are here. + +Example of the result can be seen here: +Link: https://godbolt.org/z/zhY8d3595 + +It maybe not a real problem, but could be a issue in future. + +Fixes: d499e9627d70 ("arm64/scs: Fix handling of advance_loc4") +Signed-off-by: Wentao Guan +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/pi/patch-scs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/pi/patch-scs.c b/arch/arm64/kernel/pi/patch-scs.c +index dac568e4a54f2..3944ad899021c 100644 +--- a/arch/arm64/kernel/pi/patch-scs.c ++++ b/arch/arm64/kernel/pi/patch-scs.c +@@ -196,9 +196,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, + loc += *opcode++ * code_alignment_factor; + loc += (*opcode++ << 8) * code_alignment_factor; + loc += (*opcode++ << 16) * code_alignment_factor; +- loc += (*opcode++ << 24) * code_alignment_factor; ++ loc += ((u64)*opcode++ << 24) * code_alignment_factor; + size -= 4; +- break; ++ break; + + case DW_CFA_def_cfa: + case DW_CFA_offset_extended: +-- +2.53.0 + diff --git a/queue-6.18/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch b/queue-6.18/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch new file mode 100644 index 0000000000..9360817d16 --- /dev/null +++ b/queue-6.18/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch @@ -0,0 +1,79 @@ +From 12ffaf719962f4a3bf0e4406ff1b3c9417fe2486 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 07:16:35 +0100 +Subject: arm64/xor: fix conflicting attributes for xor_block_template + +From: Christoph Hellwig + +[ Upstream commit 675a0dd596e712404557286d0a883b54ee28e4f4 ] + +Commit 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +changes the definition to __ro_after_init instead of const, but failed to +update the external declaration in xor.h. This was not found because +xor-neon.c doesn't include , and can't easily do that due to +current architecture of the XOR code. + +Link: https://lkml.kernel.org/r/20260327061704.3707577-4-hch@lst.de +Fixes: 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +Signed-off-by: Christoph Hellwig +Reviewed-by: Eric Biggers +Tested-by: Eric Biggers +Cc: Albert Ou +Cc: Alexander Gordeev +Cc: Alexandre Ghiti +Cc: Andreas Larsson +Cc: Anton Ivanov +Cc: Ard Biesheuvel +Cc: Arnd Bergmann +Cc: "Borislav Petkov (AMD)" +Cc: Catalin Marinas +Cc: Chris Mason +Cc: Christian Borntraeger +Cc: Dan Williams +Cc: David S. Miller +Cc: David Sterba +Cc: Heiko Carstens +Cc: Herbert Xu +Cc: "H. Peter Anvin" +Cc: Huacai Chen +Cc: Ingo Molnar +Cc: Jason A. Donenfeld +Cc: Johannes Berg +Cc: Li Nan +Cc: Madhavan Srinivasan +Cc: Magnus Lindholm +Cc: Matt Turner +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: Palmer Dabbelt +Cc: Richard Henderson +Cc: Richard Weinberger +Cc: Russell King +Cc: Song Liu +Cc: Sven Schnelle +Cc: Ted Ts'o +Cc: Vasily Gorbik +Cc: WANG Xuerui +Cc: Will Deacon +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/xor.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/xor.h b/arch/arm64/include/asm/xor.h +index befcd8a7abc98..7c03207157196 100644 +--- a/arch/arm64/include/asm/xor.h ++++ b/arch/arm64/include/asm/xor.h +@@ -13,7 +13,7 @@ + + #ifdef CONFIG_KERNEL_MODE_NEON + +-extern struct xor_block_template const xor_block_inner_neon; ++extern struct xor_block_template xor_block_inner_neon __ro_after_init; + + static void + xor_neon_2(unsigned long bytes, unsigned long * __restrict p1, +-- +2.53.0 + diff --git a/queue-6.18/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch b/queue-6.18/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch new file mode 100644 index 0000000000..404303414e --- /dev/null +++ b/queue-6.18/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch @@ -0,0 +1,177 @@ +From 2be79b72f1f54a2405857b8d7a43c9ce903c6579 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 15:30:58 -0300 +Subject: ASoC: amd: acp: Add DMI quirk for Valve Steam Deck OLED + +From: Guilherme G. Piccoli + +[ Upstream commit b0f6f4ac7d5d04fe2adcdd63ed1cd1ad505b8958 ] + +Commit 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") +introduced a change that "broke" Steam Deck's audio probe, in the OLED +model, as observed in the following dmesg snippet: + +[...] +snd_sof_amd_vangogh 0000:04:00.5: Topology: ABI 3:26:0 Kernel ABI 3:23:1 +sof_mach nau8821-max: ASoC: physical link acp-bt-codec (id 2) not exist +sof_mach nau8821-max: ASoC: topology: could not load header: -22 +snd_sof_amd_vangogh 0000:04:00.5: tplg amd/sof-tplg/sof-vangogh-nau8821-max.tplg component load failed -22 +snd_sof_amd_vangogh 0000:04:00.5: error: failed to load DSP topology -22 +snd_sof_amd_vangogh 0000:04:00.5: ASoC error (-22): at snd_soc_component_probe() on 0000:04:00.5 +sof_mach nau8821-max: ASoC: failed to instantiate card -22 +sof_mach nau8821-max: error -EINVAL: Failed to register card(sof-nau8821-max) +sof_mach nau8821-max: probe with driver sof_mach failed with error -22 +[...] + +Notice the quotes in "broke": it's not really a bug in such commit, +but instead a problem with a topology file from Steam Deck OLED. This +was discussed to great extent in [1], and Cristian proposed a pretty +simple and functional change that resolved the issue for the Deck's +issue. That change, though, would break other devices, so it wasn't +accepted upstream. And the proper suggested solution (fix the topology) +was never implemented, so Valve's kernel (and anyone that wants to boot +the mainline on Steam Deck OLED) is carrying that fix downstream. + +So, we propose hereby a different approach: a DMI quirk, as many already +present in the sound drivers, to address this issue solely on Steam Deck +OLED, not breaking other devices and as a bonus, allowing simple patch +up in case eventually the topology file gets fixed (we'd just need to +check against any DMI info reflecting that or the topology/FW versions). + +The motivation of such upstream quirk is related to users that want +to test latest kernel trees on their devices and get no only non-working +sound device, but seems some games (like Ori and the Blind Forest) +can't properly work without a proper functional audio device. +Example of such report can be seen at [2]. + +Cc: Mark Brown +Cc: Robert Beckett +Cc: Umang Jain +Fixes: 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") +Link: https://lore.kernel.org/r/20231209205351.880797-11-cristian.ciocaltea@collabora.com/ [1] +Link: https://bugzilla.kernel.org/show_bug.cgi?id=218677 [2] +Reviewed-by: Cristian Ciocaltea +Reviewed-by: Mario Limonciello +Tested-by: Melissa Wen +Signed-off-by: Guilherme G. Piccoli +Link: https://patch.msgid.link/20260423183505.116445-1-gpiccoli@igalia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/acp/acp-legacy-mach.c | 2 +- + sound/soc/amd/acp/acp-mach-common.c | 22 +++++++++++++++++++--- + sound/soc/amd/acp/acp-mach.h | 4 ++++ + sound/soc/amd/acp/acp-sof-mach.c | 2 +- + 4 files changed, 25 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c +index a7a551366a409..235d6cc83fa98 100644 +--- a/sound/soc/amd/acp/acp-legacy-mach.c ++++ b/sound/soc/amd/acp/acp-legacy-mach.c +@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev) + acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; + + dmi_id = dmi_first_match(acp_quirk_table); +- if (dmi_id && dmi_id->driver_data) ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE) + acp_card_drvdata->tdm_mode = dmi_id->driver_data; + + ret = acp_legacy_dai_links_create(card); +diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c +index c4bc8e849284c..a2031e7f61424 100644 +--- a/sound/soc/amd/acp/acp-mach-common.c ++++ b/sound/soc/amd/acp/acp-mach-common.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "../../codecs/rt5682.h" + #include "../../codecs/rt1019.h" +@@ -37,15 +38,21 @@ + #define NAU8821_FREQ_OUT 12288000 + #define MAX98388_CODEC_DAI "max98388-aif1" + +-#define TDM_MODE_ENABLE 1 +- + const struct dmi_system_id acp_quirk_table[] = { + { + /* Google skyrim proto-0 */ + .matches = { + DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"), + }, +- .driver_data = (void *)TDM_MODE_ENABLE, ++ .driver_data = (void *)QUIRK_TDM_MODE_ENABLE, ++ }, ++ { ++ /* Valve Steam Deck OLED */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Valve"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), ++ }, ++ .driver_data = (void *)QUIRK_REMAP_DMIC_BT, + }, + {} + }; +@@ -1385,6 +1392,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + struct snd_soc_dai_link *links; + struct device *dev = card->dev; + struct acp_card_drvdata *drv_data = card->drvdata; ++ const struct dmi_system_id *dmi_id = dmi_first_match(acp_quirk_table); + int i = 0, num_links = 0; + + if (drv_data->hs_cpu_id) +@@ -1556,6 +1564,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + links[i].codecs = &snd_soc_dummy_dlc; + links[i].num_codecs = 1; + } ++ ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) ++ links[i].id = DMIC_BE_ID; + i++; + } + +@@ -1571,6 +1582,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + links[i].capture_only = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; ++ ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) { ++ links[i].id = BT_BE_ID; ++ dev_dbg(dev, "quirk REMAP_DMIC_BT enabled\n"); ++ } + } + + card->dai_link = links; +diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h +index f94c30c20f20b..7177d3fd96192 100644 +--- a/sound/soc/amd/acp/acp-mach.h ++++ b/sound/soc/amd/acp/acp-mach.h +@@ -26,6 +26,10 @@ + + #define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata) + ++/* List of DMI quirks - check acp-mach-common.c for usage. */ ++#define QUIRK_TDM_MODE_ENABLE 1 ++#define QUIRK_REMAP_DMIC_BT 2 ++ + enum be_id { + HEADSET_BE_ID = 0, + AMP_BE_ID, +diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c +index 6215e31eceddf..36ecef7013b9c 100644 +--- a/sound/soc/amd/acp/acp-sof-mach.c ++++ b/sound/soc/amd/acp/acp-sof-mach.c +@@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev) + + acp_card_drvdata = card->drvdata; + dmi_id = dmi_first_match(acp_quirk_table); +- if (dmi_id && dmi_id->driver_data) ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE) + acp_card_drvdata->tdm_mode = dmi_id->driver_data; + + acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; +-- +2.53.0 + diff --git a/queue-6.18/asoc-amd-acp-update-dmic_num-logic-for-acp-pdm-dmic.patch b/queue-6.18/asoc-amd-acp-update-dmic_num-logic-for-acp-pdm-dmic.patch new file mode 100644 index 0000000000..5f38a636fa --- /dev/null +++ b/queue-6.18/asoc-amd-acp-update-dmic_num-logic-for-acp-pdm-dmic.patch @@ -0,0 +1,46 @@ +From ce165603810520722b79582a1f3f65d6597a6b66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 12:50:27 +0530 +Subject: ASoC: amd: acp: update dmic_num logic for acp pdm dmic + +From: Vijendar Mukunda + +[ Upstream commit 5902e1f3c501375797dcd7ca21b58e2c9abbe317 ] + +Currently there is no mechanism to read dmic_num in mach_params +structure. In this scenario mach_params->dmic_num check always +returns 0 which fails to add component string for dmic. +Update the condition check with acp pdm dmic quirk check and +pass the dmic_num as 1. + +Fixes: 2981d9b0789c ("ASoC: amd: acp: add soundwire machine driver for legacy stack") + +Signed-off-by: Vijendar Mukunda +Link: https://patch.msgid.link/20260330072431.3512358-2-Vijendar.Mukunda@amd.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/acp/acp-sdw-legacy-mach.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c +index 2b2910b1856d5..798c73d7e26de 100644 +--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c ++++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c +@@ -520,11 +520,11 @@ static int mc_probe(struct platform_device *pdev) + " cfg-amp:%d", amp_num); + if (!card->components) + return -ENOMEM; +- if (mach->mach_params.dmic_num) { ++ if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) { + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:dmic cfg-mics:%d", + card->components, +- mach->mach_params.dmic_num); ++ 1); + if (!card->components) + return -ENOMEM; + } +-- +2.53.0 + diff --git a/queue-6.18/asoc-codecs-ab8500-fix-casting-of-private-data.patch b/queue-6.18/asoc-codecs-ab8500-fix-casting-of-private-data.patch new file mode 100644 index 0000000000..50977e4404 --- /dev/null +++ b/queue-6.18/asoc-codecs-ab8500-fix-casting-of-private-data.patch @@ -0,0 +1,56 @@ +From 7b220bc1254979c7bf14f3078d045092c4fc3ff0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 21:22:49 +0200 +Subject: ASoC: codecs: ab8500: Fix casting of private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian A. Ehrhardt + +[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ] + +ab8500_filter_controls[i].private_value is initialized using + + .private_value = (unsigned long)&(struct filter_control) + {.count = xcount, .min = xmin, .max = xmax} + +thus it's a pointer to a struct filter_control casted to unsigned long. + +So to get back that pointer .private_data must be cast back, not its +address. + +Fixes: 679d7abdc754 ("ASoC: codecs: Add AB8500 codec-driver") +Signed-off-by: Christian A. Ehrhardt +Signed-off-by: Uwe Kleine-König (The Capable Hub) +Link: https://patch.msgid.link/20260428192255.2294705-2-u.kleine-koenig@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/ab8500-codec.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c +index 04b5e1d5a6530..32d9cdbc8c310 100644 +--- a/sound/soc/codecs/ab8500-codec.c ++++ b/sound/soc/codecs/ab8500-codec.c +@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) + return status; + } + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; + drvdata->anc_fir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; + drvdata->anc_iir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; + drvdata->sid_fir_values = (long *)fc->value; + + snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch b/queue-6.18/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch new file mode 100644 index 0000000000..b246112eba --- /dev/null +++ b/queue-6.18/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch @@ -0,0 +1,189 @@ +From 15b8ed86a83d15a410248733038a41ae9cc1e9da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:26 +0800 +Subject: ASoC: fsl_easrc: Change the type for iec958 channel status controls + +From: Shengjiu Wang + +[ Upstream commit 47f28a5bd154a95d5aa563dde02a801bd32ddb81 ] + +Use the type SNDRV_CTL_ELEM_TYPE_IEC958 for iec958 channel status +controls, the original type will cause mixer-test to iterate all 32bit +values, which costs a lot of time. And using IEC958 type can reduce the +control numbers. + +Also enable pm runtime before updating registers to make the regmap cache +data align with the value in hardware. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-12-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 118 +++++++++++++++++++++++++++----------- + 1 file changed, 84 insertions(+), 34 deletions(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 725c7b65fe6b8..59cdf18731a0a 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -78,17 +78,47 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + return 0; + } + ++static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ + static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; +- unsigned int regval; ++ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ int ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]); ++ if (ret) ++ return ret; + +- regval = snd_soc_component_read(component, mc->regbase); ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]); ++ if (ret) ++ return ret; + +- ucontrol->value.integer.value[0] = regval; ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]); ++ if (ret) ++ return ret; + + return 0; + } +@@ -100,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); +- unsigned int regval = ucontrol->value.integer.value[0]; +- bool changed; ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ bool changed, changed_all = false; + int ret; + +- ret = regmap_update_bits_check(easrc->regmap, mc->regbase, +- GENMASK(31, 0), regval, &changed); +- if (ret != 0) ++ ret = pm_runtime_resume_and_get(component->dev); ++ if (ret) + return ret; + +- return changed; ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase), ++ GENMASK(31, 0), regval[0], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase), ++ GENMASK(31, 0), regval[1], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase), ++ GENMASK(31, 0), regval[2], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase), ++ GENMASK(31, 0), regval[3], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase), ++ GENMASK(31, 0), regval[4], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase), ++ GENMASK(31, 0), regval[5], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++err: ++ pm_runtime_put_autosuspend(component->dev); ++ ++ if (ret != 0) ++ return ret; ++ else ++ return changed_all; + } + + #define SOC_SINGLE_REG_RW(xname, xreg) \ + { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ +- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ ++ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \ + .put = fsl_easrc_set_reg, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ +@@ -146,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { + SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), + SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), + +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), ++ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0), ++ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1), ++ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2), ++ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3), + }; + + /* +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch b/queue-6.18/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch new file mode 100644 index 0000000000..90d33a13a0 --- /dev/null +++ b/queue-6.18/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch @@ -0,0 +1,39 @@ +From ab20265199e19596a86485e914ac7d79881bfe3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:24 +0800 +Subject: ASoC: fsl_easrc: Check the variable range in + fsl_easrc_iec958_put_bits() + +From: Shengjiu Wang + +[ Upstream commit 00541b86fb578d4949cfdd6aff1f82d43fcf07af ] + +Add check of input value's range in fsl_easrc_iec958_put_bits(), +otherwise the wrong value may be written from user space. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-10-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 8e52e43a8ba85..8647df027c3fd 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, + unsigned int regval = ucontrol->value.integer.value[0]; + int ret; + ++ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT) ++ return -EINVAL; ++ + ret = (easrc_priv->bps_iec958[mc->regbase] != regval); + + easrc_priv->bps_iec958[mc->regbase] = regval; +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch b/queue-6.18/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch new file mode 100644 index 0000000000..f8a649ce37 --- /dev/null +++ b/queue-6.18/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch @@ -0,0 +1,37 @@ +From 568d713934801554b9e23d2dad115edebe3a0125 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:25 +0800 +Subject: ASoC: fsl_easrc: Fix value type in fsl_easrc_iec958_get_bits() + +From: Shengjiu Wang + +[ Upstream commit aa21fe4a81458cf469c2615b08cbde5997dde25a ] + +The value type of controls "Context 0 IEC958 Bits Per Sample" should be +integer, not enumerated, the issue is found by the mixer-test. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-11-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 8647df027c3fd..725c7b65fe6b8 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -73,7 +73,7 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + +- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; ++ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_micfil-add-access-property-for-vad-detected.patch b/queue-6.18/asoc-fsl_micfil-add-access-property-for-vad-detected.patch new file mode 100644 index 0000000000..21e7ef683e --- /dev/null +++ b/queue-6.18/asoc-fsl_micfil-add-access-property-for-vad-detected.patch @@ -0,0 +1,44 @@ +From 5cf67780f32372d68ceddf697d70f7bf89244229 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:16 +0800 +Subject: ASoC: fsl_micfil: Add access property for "VAD Detected" + +From: Shengjiu Wang + +[ Upstream commit c7661bfc7422443df394c01e069ae4e5c3a7f04c ] + +Add access property SNDRV_CTL_ELEM_ACCESS_READ for control "VAD +Detected", which doesn't support put operation, otherwise there will be +issue with mixer-test. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-2-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index cac26ba0aa4b0..ddc56f77f1455 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -424,7 +424,13 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { + SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0), + SOC_SINGLE("HWVAD ZCD And Behavior Switch", + REG_MICFIL_VAD0_ZCD, 4, 1, 0), +- SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .name = "VAD Detected", ++ .info = snd_soc_info_bool_ext, ++ .get = hwvad_detected, ++ }, + }; + + static int fsl_micfil_use_verid(struct device *dev) +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch b/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch new file mode 100644 index 0000000000..17cc44c84f --- /dev/null +++ b/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch @@ -0,0 +1,49 @@ +From a81ebbc8895a32ca3b416f69f94e69c5c77df133 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:17 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in hwvad_put_enable() + +From: Shengjiu Wang + +[ Upstream commit 59b9061824f2179fe133e2636203548eaba3e528 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation hwvad_put_enable() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the vad_enabled +variable. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-3-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index ddc56f77f1455..668e6dbe5a712 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -306,10 +306,15 @@ static int hwvad_put_enable(struct snd_kcontrol *kcontrol, + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); ++ bool change = false; + ++ if (val < 0 || val > 1) ++ return -EINVAL; ++ ++ change = (micfil->vad_enabled != val); + micfil->vad_enabled = val; + +- return 0; ++ return change; + } + + static int hwvad_get_enable(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch b/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch new file mode 100644 index 0000000000..60a5cabe1e --- /dev/null +++ b/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch @@ -0,0 +1,52 @@ +From 74f8054dc85ae2a57adb5726fad99d14fccc0b72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:18 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in hwvad_put_init_mode() + +From: Shengjiu Wang + +[ Upstream commit 7e226209906906421f0d952d7304e48fdb0adabc ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation hwvad_put_init_mode() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the vad_init_mode +variable. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-4-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 668e6dbe5a712..36eefb7f0eb2f 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -336,13 +336,18 @@ static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol, + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); ++ bool change = false; ++ ++ if (val < MICFIL_HWVAD_ENVELOPE_MODE || val > MICFIL_HWVAD_ENERGY_MODE) ++ return -EINVAL; + + /* 0 - Envelope-based Mode + * 1 - Energy-based Mode + */ ++ change = (micfil->vad_init_mode != val); + micfil->vad_init_mode = val; + +- return 0; ++ return change; + } + + static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch b/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch new file mode 100644 index 0000000000..a456b52db2 --- /dev/null +++ b/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch @@ -0,0 +1,62 @@ +From 96d2471f4bdb53d4ecdbe26d61e4705de7ec0bdc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:20 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in + micfil_put_dc_remover_state() + +From: Shengjiu Wang + +[ Upstream commit 7d2bd35100de370dc326b250e8f6b66bee06a2f3 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_put_dc_remover_state() only returns 0 or a +negative error code, causing ALSA to not generate any change events. + +return the value of snd_soc_component_update_bits() directly, as it has +the capability of return check status of changed or not. + +Also enable pm runtime before calling the function +snd_soc_component_update_bits() to make the regmap cache data align with +the value in hardware. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-6-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 36eefb7f0eb2f..980c6e1d9b1ce 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -272,6 +272,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + if (val < 0 || val > 3) + return -EINVAL; + ++ ret = pm_runtime_resume_and_get(comp->dev); ++ if (ret) ++ return ret; ++ + micfil->dc_remover = val; + + /* Calculate total value for all channels */ +@@ -281,10 +285,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + /* Update DC Remover mode for all channels */ + ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL, + MICFIL_DC_CTRL_CONFIG, reg_val); +- if (ret < 0) +- return ret; + +- return 0; ++ pm_runtime_put_autosuspend(comp->dev); ++ ++ return ret; + } + + static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch b/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch new file mode 100644 index 0000000000..c0541cbf2a --- /dev/null +++ b/queue-6.18/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch @@ -0,0 +1,71 @@ +From 2f7d454de0fb20c58d5c0198d73b9d56c590c605 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:21 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in micfil_quality_set() + +From: Shengjiu Wang + +[ Upstream commit e5785093b1b45af7ee57d18619b2854a8aed073a ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_quality_set() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the quality variable. + +Also enable pm runtime before calling the function micfil_set_quality() +to make the regmap cache data align with the value in hardware. + +Fixes: bea1d61d5892 ("ASoC: fsl_micfil: rework quality setting") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-7-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 980c6e1d9b1ce..09deb880bd37d 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -210,10 +210,34 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol, + { + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); ++ int val = ucontrol->value.integer.value[0]; ++ bool change = false; ++ int old_val; ++ int ret; ++ ++ if (val < QUALITY_HIGH || val > QUALITY_VLOW2) ++ return -EINVAL; ++ ++ if (micfil->quality != val) { ++ ret = pm_runtime_resume_and_get(cmpnt->dev); ++ if (ret) ++ return ret; ++ ++ old_val = micfil->quality; ++ micfil->quality = val; ++ ret = micfil_set_quality(micfil); + +- micfil->quality = ucontrol->value.integer.value[0]; ++ pm_runtime_put_autosuspend(cmpnt->dev); + +- return micfil_set_quality(micfil); ++ if (ret) { ++ micfil->quality = old_val; ++ return ret; ++ } ++ ++ change = true; ++ } ++ ++ return change; + } + + static const char * const micfil_hwvad_enable[] = { +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch b/queue-6.18/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch new file mode 100644 index 0000000000..7e1b8fd9b5 --- /dev/null +++ b/queue-6.18/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch @@ -0,0 +1,52 @@ +From 75034022c7452cae755622d0d796dd5421dc5ee8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:22 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_arc_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 1b61c8103c9317a9c37fe544c2d83cee1c281149 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_arc_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the arc_mode +variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-8-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index a268fb81a2f86..008e45009c83f 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -115,10 +115,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); ++ int ret; + +- xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]); ++ if (val < 0 || val > 1) ++ return -EINVAL; + +- return 0; ++ ret = (xcvr->arc_mode != val); ++ ++ xcvr->arc_mode = val; ++ ++ return ret; + } + + static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.18/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch b/queue-6.18/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch new file mode 100644 index 0000000000..abe1578063 --- /dev/null +++ b/queue-6.18/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch @@ -0,0 +1,59 @@ +From 37bf9aee713070b126b0759194612cbafbe520af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:23 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 64a496ba976324615b845d60739dfcdae3d57434 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the mode variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-9-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index 008e45009c83f..d7a823384c08a 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -225,10 +225,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); + struct snd_soc_card *card = dai->component->card; + struct snd_soc_pcm_runtime *rtd; ++ int ret; ++ ++ if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC) ++ return -EINVAL; + +- xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); ++ ret = (xcvr->mode != val); ++ ++ xcvr->mode = val; + + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_ARC)); +@@ -238,7 +245,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + rtd = snd_soc_get_pcm_runtime(card, card->dai_link); + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = + (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0); +- return 0; ++ return ret; + } + + static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.18/asoc-intel-avs-check-maximum-valid-cpuid-leaf.patch b/queue-6.18/asoc-intel-avs-check-maximum-valid-cpuid-leaf.patch new file mode 100644 index 0000000000..7202df6658 --- /dev/null +++ b/queue-6.18/asoc-intel-avs-check-maximum-valid-cpuid-leaf.patch @@ -0,0 +1,62 @@ +From ba875c1076bcf6492b5e72f36a09914ee1fe7c2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 03:15:15 +0100 +Subject: ASoC: Intel: avs: Check maximum valid CPUID leaf + +From: Ahmed S. Darwish + +[ Upstream commit 93a1f0e61329f538cfc7122d7fa0e7a1803e326d ] + +The Intel AVS driver queries CPUID(0x15) before checking if the CPUID leaf +is available. Check the maximum-valid CPU standard leaf beforehand. + +Use the CPUID_LEAF_TSC macro instead of the custom local one for the +CPUID(0x15) leaf number. + +Fixes: cbe37a4d2b3c ("ASoC: Intel: avs: Configure basefw on TGL-based platforms") +Signed-off-by: Ahmed S. Darwish +Signed-off-by: Borislav Petkov (AMD) +Acked-by: Cezary Rojewski +Link: https://patch.msgid.link/20260327021645.555257-2-darwi@linutronix.de +Signed-off-by: Sasha Levin +--- + sound/soc/intel/avs/tgl.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c +index afb0665161010..4649d749b41e0 100644 +--- a/sound/soc/intel/avs/tgl.c ++++ b/sound/soc/intel/avs/tgl.c +@@ -11,8 +11,6 @@ + #include "debug.h" + #include "messages.h" + +-#define CPUID_TSC_LEAF 0x15 +- + static int avs_tgl_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) + { + core_mask &= AVS_MAIN_CORE_MASK; +@@ -49,7 +47,11 @@ static int avs_tgl_config_basefw(struct avs_dev *adev) + unsigned int ecx; + + #include +- ecx = cpuid_ecx(CPUID_TSC_LEAF); ++ ++ if (boot_cpu_data.cpuid_level < CPUID_LEAF_TSC) ++ goto no_cpuid; ++ ++ ecx = cpuid_ecx(CPUID_LEAF_TSC); + if (ecx) { + ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx); + if (ret) +@@ -57,6 +59,7 @@ static int avs_tgl_config_basefw(struct avs_dev *adev) + } + #endif + ++no_cpuid: + hwid.device = pci->device; + hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16); + hwid.revision = pci->revision; +-- +2.53.0 + diff --git a/queue-6.18/asoc-intel-avs-include-cpuid-header-at-file-scope.patch b/queue-6.18/asoc-intel-avs-include-cpuid-header-at-file-scope.patch new file mode 100644 index 0000000000..4d39a7d42d --- /dev/null +++ b/queue-6.18/asoc-intel-avs-include-cpuid-header-at-file-scope.patch @@ -0,0 +1,116 @@ +From 4508b33ff800877b7eaa39184fd7ea551a56e33e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 03:15:16 +0100 +Subject: ASoC: Intel: avs: Include CPUID header at file scope + +From: Ahmed S. Darwish + +[ Upstream commit 7f78e0b46e9984e955cb73ffada8dace8b4dd059 ] + +Commit + + cbe37a4d2b3c ("ASoC: Intel: avs: Configure basefw on TGL-based platforms") + +includes the main CPUID header from within a C function. This works by +luck and forbids valid refactoring inside that header. + +Include the CPUID header at file scope instead. + +Remove the COMPILE_TEST build flag so that the CONFIG_X86 conditionals can +be removed. The driver gets enough compilation testing already on x86. + +For clarity, refactor the CPUID(0x15) code into its own function without +changing any of the driver's logic. + +Fixes: cbe37a4d2b3c ("ASoC: Intel: avs: Configure basefw on TGL-based platforms") +Suggested-by: Borislav Petkov # CONFIG_X86 removal +Signed-off-by: Ahmed S. Darwish +Signed-off-by: Borislav Petkov (AMD) +Acked-by: Cezary Rojewski +Link: https://lore.kernel.org/all/20250612234010.572636-3-darwi@linutronix.de +Signed-off-by: Sasha Levin +--- + sound/soc/intel/Kconfig | 2 +- + sound/soc/intel/avs/tgl.c | 37 ++++++++++++++++++++++++------------- + 2 files changed, 25 insertions(+), 14 deletions(-) + +diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig +index 412555e626b81..63367364916ae 100644 +--- a/sound/soc/intel/Kconfig ++++ b/sound/soc/intel/Kconfig +@@ -95,7 +95,7 @@ config SND_SOC_INTEL_KEEMBAY + + config SND_SOC_INTEL_AVS + tristate "Intel AVS driver" +- depends on X86 || COMPILE_TEST ++ depends on X86 + depends on PCI + depends on COMMON_CLK + select ACPI_NHLT if ACPI +diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c +index 4649d749b41e0..a7123639de431 100644 +--- a/sound/soc/intel/avs/tgl.c ++++ b/sound/soc/intel/avs/tgl.c +@@ -7,6 +7,7 @@ + // + + #include ++#include + #include "avs.h" + #include "debug.h" + #include "messages.h" +@@ -38,28 +39,38 @@ static int avs_tgl_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stal + return avs_dsp_core_stall(adev, core_mask, stall); + } + +-static int avs_tgl_config_basefw(struct avs_dev *adev) ++/* ++ * Succeed if CPUID(0x15) is not available, or if the nominal core crystal clock ++ * frequency cannot be enumerated from it. There is nothing to do in both cases. ++ */ ++static int avs_tgl_set_xtal_freq(struct avs_dev *adev) + { +- struct pci_dev *pci = adev->base.pci; +- struct avs_bus_hwid hwid; ++ unsigned int freq; + int ret; +-#ifdef CONFIG_X86 +- unsigned int ecx; +- +-#include + + if (boot_cpu_data.cpuid_level < CPUID_LEAF_TSC) +- goto no_cpuid; ++ return 0; + +- ecx = cpuid_ecx(CPUID_LEAF_TSC); +- if (ecx) { +- ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx); ++ freq = cpuid_ecx(CPUID_LEAF_TSC); ++ if (freq) { ++ ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(freq), &freq); + if (ret) + return AVS_IPC_RET(ret); + } +-#endif + +-no_cpuid: ++ return 0; ++} ++ ++static int avs_tgl_config_basefw(struct avs_dev *adev) ++{ ++ struct pci_dev *pci = adev->base.pci; ++ struct avs_bus_hwid hwid; ++ int ret; ++ ++ ret = avs_tgl_set_xtal_freq(adev); ++ if (ret) ++ return ret; ++ + hwid.device = pci->device; + hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16); + hwid.revision = pci->revision; +-- +2.53.0 + diff --git a/queue-6.18/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch b/queue-6.18/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch new file mode 100644 index 0000000000..0d25d5a9b4 --- /dev/null +++ b/queue-6.18/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch @@ -0,0 +1,51 @@ +From a9765cdfce6a3eb9229f40534ea661cf9248ea5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 08:11:08 +0000 +Subject: ASoC: qcom: qdsp6: topology: check widget type before accessing data + +From: Srinivas Kandagatla + +[ Upstream commit d5bfdd28e0cdd45043ae6e0ac168a451d59283dc ] + +Check widget type before accessing the private data, as this could a +virtual widget which is no associated with a dsp graph, container and +module. Accessing witout check could lead to incorrect memory access. + +Fixes: 36ad9bf1d93d ("ASoC: qdsp6: audioreach: add topology support") +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260402081118.348071-4-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/topology.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c +index f61285e7dcf20..f8d3bb83e3b0d 100644 +--- a/sound/soc/qcom/qdsp6/topology.c ++++ b/sound/soc/qcom/qdsp6/topology.c +@@ -952,9 +952,6 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + struct audioreach_container *cont; + struct audioreach_module *mod; + +- mod = dobj->private; +- cont = mod->container; +- + if (w->id == snd_soc_dapm_mixer) { + /* virtual widget */ + struct snd_ar_control *scontrol = dobj->private; +@@ -963,6 +960,11 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + kfree(scontrol); + return 0; + } ++ mod = dobj->private; ++ if (!mod) ++ return 0; ++ ++ cont = mod->container; + + mutex_lock(&apm->lock); + idr_remove(&apm->modules_idr, mod->instance_id); +-- +2.53.0 + diff --git a/queue-6.18/asoc-rockchip-rockchip_sai-set-slot-width-for-non-td.patch b/queue-6.18/asoc-rockchip-rockchip_sai-set-slot-width-for-non-td.patch new file mode 100644 index 0000000000..75675dcf29 --- /dev/null +++ b/queue-6.18/asoc-rockchip-rockchip_sai-set-slot-width-for-non-td.patch @@ -0,0 +1,52 @@ +From e5dcc6b591b71ba56210d199a240f18194db8813 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:50:25 +0400 +Subject: ASoC: rockchip: rockchip_sai: Set slot width for non-TDM mode + +From: Alexey Charkov + +[ Upstream commit 8a6391ec669366cbe7bde92b468c561e8b309fd6 ] + +Currently the slot width in non-TDM mode is always kept at the POR value +of 32 bits, regardless of the sample width, which doesn't work well for +some codecs such as NAU8822. + +Set the slot width according to the sample width in non-TDM mode, which +is what other CPU DAI drivers do. + +Tested on the following RK3576 configurations: +- SAI2 + NAU8822 (codec as the clock master), custom board +- SAI1 + ES8388 (codec as the clock master), RK3576 EVB1 +- SAI2 + RT5616 (SAI as the clock master), FriendlyElec NanoPi M5 + +NAU8822 didn't work prior to this patch but works after the patch. Other +two configurations work both before and after the patch. + +Fixes: cc78d1eaabad ("ASoC: rockchip: add Serial Audio Interface (SAI) driver") +Signed-off-by: Alexey Charkov +Tested-by: Nicolas Frattaroli +Link: https://patch.msgid.link/20260318-sai-slot-width-v1-1-1f68186f71e3@flipper.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/rockchip/rockchip_sai.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c +index 6695349ee561e..b38c2cb81f807 100644 +--- a/sound/soc/rockchip/rockchip_sai.c ++++ b/sound/soc/rockchip/rockchip_sai.c +@@ -628,6 +628,10 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, + + regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val); + ++ if (!sai->is_tdm) ++ regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK, ++ SAI_XCR_SBW(params_physical_width(params))); ++ + regmap_read(sai->regmap, reg, &val); + + slot_width = SAI_XCR_SBW_V(val); +-- +2.53.0 + diff --git a/queue-6.18/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch b/queue-6.18/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch new file mode 100644 index 0000000000..71a398628e --- /dev/null +++ b/queue-6.18/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch @@ -0,0 +1,45 @@ +From 066b50b0cae33a69db300873cb69c0bef5fbd9e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 13:33:11 +0300 +Subject: ASoC: rsnd: Fix potential out-of-bounds access of component_dais[] + +From: Denis Rastyogin + +[ Upstream commit f9e437cddf6cf9e603bdaefe148c1f4792aaf39c ] + +component_dais[RSND_MAX_COMPONENT] is initially zero-initialized +and later populated in rsnd_dai_of_node(). However, the existing boundary check: + if (i >= RSND_MAX_COMPONENT) + +does not guarantee that the last valid element remains zero. As a result, +the loop can rely on component_dais[RSND_MAX_COMPONENT] being zero, +which may lead to an out-of-bounds access. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 547b02f74e4a ("ASoC: rsnd: enable multi Component support for Audio Graph Card/Card2") +Signed-off-by: Denis Rastyogin +Acked-by: Kuninori Morimoto +Link: https://patch.msgid.link/20260327103311.459239-1-gerben@altlinux.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/renesas/rcar/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c +index 69fb19964a71d..2dc078358612d 100644 +--- a/sound/soc/renesas/rcar/core.c ++++ b/sound/soc/renesas/rcar/core.c +@@ -1974,7 +1974,7 @@ static int rsnd_probe(struct platform_device *pdev) + * asoc register + */ + ci = 0; +- for (i = 0; priv->component_dais[i] > 0; i++) { ++ for (i = 0; i < RSND_MAX_COMPONENT && priv->component_dais[i] > 0; i++) { + int nr = priv->component_dais[i]; + + ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, +-- +2.53.0 + diff --git a/queue-6.18/asoc-sdca-update-counting-of-su-ge-dapm-routes.patch b/queue-6.18/asoc-sdca-update-counting-of-su-ge-dapm-routes.patch new file mode 100644 index 0000000000..3b9f6be92e --- /dev/null +++ b/queue-6.18/asoc-sdca-update-counting-of-su-ge-dapm-routes.patch @@ -0,0 +1,137 @@ +From f2045fe1a8e75a9b26ce3fb7e0ead2fdb85e2a90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 14:01:16 +0000 +Subject: ASoC: SDCA: Update counting of SU/GE DAPM routes + +From: Charles Keepax + +[ Upstream commit 1fb720d33eecdb9a90ee340b3000ba378d49f5ca ] + +Device Layer Selector Unit's are controlled by a Group Entity control +rather than by the host directly. For the purposes of the ASoC class +driver the number of input routes to the SU is controlled by the number +of options within the Group Entity Selected Mode Control. ie. One valid +DAPM route for each valid route defined in the Group Entity. + +Currently the code assumes that a Device Layer SU will have a number of +routes equal to the number of potential sources for the SU. ie. it +counts the routes using the SU, but then creates the routes using the +GE. However, this isn't actually true, it is perfectly allowed for the +GE to only define options for some of the potential sources of the SU.o +In such a case the number of routes return will not match those created, +leading to either an overflow of the routes array or undefined routes to +be past to the ASoC core, both of which generally lead to the sound card +failing to probe. + +Update the handling for the counting of routes to count the connected +routes on the GE itself and then ignore the source routes on the SU. +This makes it match the logic generating the routes and ensuring that +both remain in sync. + +Fixes: 2c8b3a8e6aa8 ("ASoC: SDCA: Create DAPM widgets and routes from DisCo") +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260225140118.402695-3-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_asoc.c | 41 +++++++++++++++++++++++++++++++------- + 1 file changed, 34 insertions(+), 7 deletions(-) + +diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c +index 197a592ec2f16..523ea9a2c5f42 100644 +--- a/sound/soc/sdca/sdca_asoc.c ++++ b/sound/soc/sdca/sdca_asoc.c +@@ -51,6 +51,25 @@ static bool readonly_control(struct sdca_control *control) + return control->has_fixed || control->mode == SDCA_ACCESS_MODE_RO; + } + ++static int ge_count_routes(struct sdca_entity *entity) ++{ ++ int count = 0; ++ int i, j; ++ ++ for (i = 0; i < entity->ge.num_modes; i++) { ++ struct sdca_ge_mode *mode = &entity->ge.modes[i]; ++ ++ for (j = 0; j < mode->num_controls; j++) { ++ struct sdca_ge_control *affected = &mode->controls[j]; ++ ++ if (affected->sel != SDCA_CTL_SU_SELECTOR || affected->val) ++ count++; ++ } ++ } ++ ++ return count; ++} ++ + /** + * sdca_asoc_count_component - count the various component parts + * @dev: Pointer to the device against which allocations will be done. +@@ -74,6 +93,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + int *num_widgets, int *num_routes, int *num_controls, + int *num_dais) + { ++ struct sdca_control *control; + int i, j; + + *num_widgets = function->num_entities - 1; +@@ -83,6 +103,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + + for (i = 0; i < function->num_entities - 1; i++) { + struct sdca_entity *entity = &function->entities[i]; ++ bool skip_primary_routes = false; + + /* Add supply/DAI widget connections */ + switch (entity->type) { +@@ -96,6 +117,17 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + case SDCA_ENTITY_TYPE_PDE: + *num_routes += entity->pde.num_managed; + break; ++ case SDCA_ENTITY_TYPE_GE: ++ *num_routes += ge_count_routes(entity); ++ skip_primary_routes = true; ++ break; ++ case SDCA_ENTITY_TYPE_SU: ++ control = sdca_selector_find_control(dev, entity, SDCA_CTL_SU_SELECTOR); ++ if (!control) ++ return -EINVAL; ++ ++ skip_primary_routes = (control->layers == SDCA_ACCESS_LAYER_DEVICE); ++ break; + default: + break; + } +@@ -104,7 +136,8 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + (*num_routes)++; + + /* Add primary entity connections from DisCo */ +- *num_routes += entity->num_sources; ++ if (!skip_primary_routes) ++ *num_routes += entity->num_sources; + + for (j = 0; j < entity->num_controls; j++) { + if (exported_control(entity, &entity->controls[j])) +@@ -451,7 +484,6 @@ static int entity_parse_su_device(struct device *dev, + struct snd_soc_dapm_route **route) + { + struct sdca_control_range *range; +- int num_routes = 0; + int i, j; + + if (!entity->group) { +@@ -487,11 +519,6 @@ static int entity_parse_su_device(struct device *dev, + return -EINVAL; + } + +- if (++num_routes > entity->num_sources) { +- dev_err(dev, "%s: too many input routes\n", entity->label); +- return -EINVAL; +- } +- + term = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX, + mode->val, SDCA_SELECTED_MODE_TERM_TYPE); + if (!term) { +-- +2.53.0 + diff --git a/queue-6.18/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch b/queue-6.18/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch new file mode 100644 index 0000000000..555f06c3aa --- /dev/null +++ b/queue-6.18/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch @@ -0,0 +1,97 @@ +From 7a8e7112ee9addb54db5aab5ba602dc5c4605f6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 04:53:52 +0000 +Subject: ASoC: soc-compress: use function to clear symmetric params + +From: Kuninori Morimoto + +[ Upstream commit 07c774dd64ba0c605dbf844132122e3edbdbea93 ] + +Current soc-compress.c clears symmetric_rate, but it clears rate only, +not clear other symmetric_channels/sample_bits. + + static int soc_compr_clean(...) + { + ... + if (!snd_soc_dai_active(cpu_dai)) +=> cpu_dai->symmetric_rate = 0; + + if (!snd_soc_dai_active(codec_dai)) +=> codec_dai->symmetric_rate = 0; + ... + }; + +This feature was added when v3.7 kernel [1], and there was only +symmetric_rate, no symmetric_channels/sample_bits in that timing. + +symmetric_channels/sample_bits were added in v3.14 [2], +but I guess it didn't notice that soc-compress.c is updating symmetric_xxx. + +We are clearing symmetry_xxx by soc_pcm_set_dai_params(), but is soc-pcm.c +local function. Makes it global function and clear symmetry_xxx by it. + +[1] commit 1245b7005de02 ("ASoC: add compress stream support") +[2] commit 3635bf09a89cf ("ASoC: soc-pcm: add symmetry for channels and + sample bits") + +Fixes: 3635bf09a89c ("ASoC: soc-pcm: add symmetry for channels and sample bits") +Cc: Nicolin Chen +Signed-off-by: Kuninori Morimoto +Link: https://patch.msgid.link/87ms15e3kv.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + include/sound/soc.h | 3 +++ + sound/soc/soc-compress.c | 4 ++-- + sound/soc/soc-pcm.c | 4 ++-- + 3 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/include/sound/soc.h b/include/sound/soc.h +index a9c058b06ab42..33968935d00a9 100644 +--- a/include/sound/soc.h ++++ b/include/sound/soc.h +@@ -1414,6 +1414,9 @@ struct snd_soc_dai *snd_soc_find_dai( + struct snd_soc_dai *snd_soc_find_dai_with_mutex( + const struct snd_soc_dai_link_component *dlc); + ++void soc_pcm_set_dai_params(struct snd_soc_dai *dai, ++ struct snd_pcm_hw_params *params); ++ + #include + + static inline +diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c +index 7b81dffc6a935..b8402802ae784 100644 +--- a/sound/soc/soc-compress.c ++++ b/sound/soc/soc-compress.c +@@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) + snd_soc_dai_digital_mute(codec_dai, 1, stream); + + if (!snd_soc_dai_active(cpu_dai)) +- cpu_dai->symmetric_rate = 0; ++ soc_pcm_set_dai_params(cpu_dai, NULL); + + if (!snd_soc_dai_active(codec_dai)) +- codec_dai->symmetric_rate = 0; ++ soc_pcm_set_dai_params(codec_dai, NULL); + + snd_soc_link_compr_shutdown(cstream, rollback); + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 2c21fd528afd0..99299364c9ba3 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -423,8 +423,8 @@ void dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event) + snd_soc_dapm_stream_event(fe, dir, event); + } + +-static void soc_pcm_set_dai_params(struct snd_soc_dai *dai, +- struct snd_pcm_hw_params *params) ++void soc_pcm_set_dai_params(struct snd_soc_dai *dai, ++ struct snd_pcm_hw_params *params) + { + if (params) { + dai->symmetric_rate = params_rate(params); +-- +2.53.0 + diff --git a/queue-6.18/asoc-sof-compress-return-the-configured-codec-from-g.patch b/queue-6.18/asoc-sof-compress-return-the-configured-codec-from-g.patch new file mode 100644 index 0000000000..c92eb9a854 --- /dev/null +++ b/queue-6.18/asoc-sof-compress-return-the-configured-codec-from-g.patch @@ -0,0 +1,88 @@ +From 7963a665093413cfe301407b5dc0384b9658cb0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 17:05:11 -0300 +Subject: ASoC: SOF: compress: return the configured codec from get_params +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 2c4fdd055f92a2fc8602dcd88bcea08c374b7e8b ] + +The SOF compressed offload path accepts codec parameters in +sof_compr_set_params() and forwards them to firmware as +extended data in the SOF IPC stream params message. + +However, sof_compr_get_params() still returns success without +filling the snd_codec structure. Since the compress core allocates +that structure zeroed and copies it back to userspace on success, +SNDRV_COMPRESS_GET_PARAMS returns an all-zero codec description +even after the stream has been configured successfully. + +The stale TODO in this callback conflates get_params() with capability +discovery. Supported codec enumeration belongs in get_caps() and +get_codec_caps(). get_params() should report the current codec settings. + +Cache the codec accepted by sof_compr_set_params() in the per-stream SOF +compress state and return it from sof_compr_get_params(). + +Fixes: 6324cf901e14 ("ASoC: SOF: compr: Add compress ops implementation") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-sof-compr-get-params-v1-1-0758815f13c7@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/compress.c | 8 +++++--- + sound/soc/sof/sof-priv.h | 2 ++ + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c +index 593b8c7474846..31455ebb0f5bb 100644 +--- a/sound/soc/sof/compress.c ++++ b/sound/soc/sof/compress.c +@@ -247,6 +247,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, + sstream->sampling_rate = params->codec.sample_rate; + sstream->channels = params->codec.ch_out; + sstream->sample_container_bytes = pcm->params.sample_container_bytes; ++ sstream->codec_params = params->codec; + + spcm->prepared[cstream->direction] = true; + +@@ -259,9 +260,10 @@ static int sof_compr_set_params(struct snd_soc_component *component, + static int sof_compr_get_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_codec *params) + { +- /* TODO: we don't query the supported codecs for now, if the +- * application asks for an unsupported codec the set_params() will fail. +- */ ++ struct sof_compr_stream *sstream = cstream->runtime->private_data; ++ ++ *params = sstream->codec_params; ++ + return 0; + } + +diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h +index 0f624d8cde201..985284a7b4ec9 100644 +--- a/sound/soc/sof/sof-priv.h ++++ b/sound/soc/sof/sof-priv.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -111,6 +112,7 @@ struct sof_compr_stream { + u32 sampling_rate; + u16 channels; + u16 sample_container_bytes; ++ struct snd_codec codec_params; + size_t posn_offset; + }; + +-- +2.53.0 + diff --git a/queue-6.18/asoc-sof-intel-hda-place-check-before-dereference.patch b/queue-6.18/asoc-sof-intel-hda-place-check-before-dereference.patch new file mode 100644 index 0000000000..81a308e8b0 --- /dev/null +++ b/queue-6.18/asoc-sof-intel-hda-place-check-before-dereference.patch @@ -0,0 +1,60 @@ +From de90b7cddca4389aa7438d4e0ffa9da0e5bb3f65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 12:38:30 -0500 +Subject: ASoC: SOF: Intel: hda: Place check before dereference + +From: Ethan Tidmore + +[ Upstream commit 6cbc8360f51a3df2ea16a786b262b9fe44d4c68c ] + +The struct hext_stream is dereferenced before it is checked for NULL. +Although it can never be NULL due to a check prior to +hda_dsp_iccmax_stream_hw_params() being called, this change clears any +confusion regarding hext_stream possibly being NULL. + +Check hext_stream for NULL and then assign its members. + +Detected by Smatch: +sound/soc/sof/intel/hda-stream.c:488 hda_dsp_iccmax_stream_hw_params() warn: +variable dereferenced before check 'hext_stream' (see line 486) + +Fixes: aca961f196e5d ("ASoC: SOF: Intel: hda: Add helper function to program ICCMAX stream") +Signed-off-by: Ethan Tidmore +Link: https://patch.msgid.link/20260324173830.17563-1-ethantidmore06@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/intel/hda-stream.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c +index 9c3b3a9aaf83c..56faafb3dd0e5 100644 +--- a/sound/soc/sof/intel/hda-stream.c ++++ b/sound/soc/sof/intel/hda-stream.c +@@ -445,16 +445,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params) + { +- struct hdac_stream *hstream = &hext_stream->hstream; +- int sd_offset = SOF_STREAM_SD_OFFSET(hstream); ++ struct hdac_stream *hstream; ++ int sd_offset; + int ret; +- u32 mask = 0x1 << hstream->index; ++ u32 mask; + + if (!hext_stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + ++ hstream = &hext_stream->hstream; ++ sd_offset = SOF_STREAM_SD_OFFSET(hstream); ++ mask = 0x1 << hstream->index; ++ + if (!dmab) { + dev_err(sdev->dev, "error: no dma buffer allocated!\n"); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-6.18/asoc-sti-return-errors-from-regmap_field_alloc.patch b/queue-6.18/asoc-sti-return-errors-from-regmap_field_alloc.patch new file mode 100644 index 0000000000..1fb717b975 --- /dev/null +++ b/queue-6.18/asoc-sti-return-errors-from-regmap_field_alloc.patch @@ -0,0 +1,50 @@ +From c040a0fa3f46ff0c5b6f27e872aff9121f02fd03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:33 +0100 +Subject: ASoC: sti: Return errors from regmap_field_alloc() + +From: Sander Vanheule + +[ Upstream commit 272aabef50bc3fe58edd26de000f4cdd41bdbe60 ] + +When regmap_field_alloc() fails, it can return an error. Specifically, +it will return PTR_ERR(-ENOMEM) when the allocation returns a NULL +pointer. The code then uses these allocations with a simple NULL check: + + if (player->clk_sel) { + // May dereference invalid pointer (-ENOMEM) + err = regmap_field_write(player->clk_sel, ...); + } + +Ensure initialization fails by forwarding the errors from +regmap_field_alloc(), thus avoiding the use of the invalid pointers. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-2-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index 6d1ce030963c6..f1b7e76f97b58 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1029,7 +1029,12 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + } + + player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ if (IS_ERR(player->clk_sel)) ++ return PTR_ERR(player->clk_sel); ++ + player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ if (IS_ERR(player->valid_sel)) ++ return PTR_ERR(player->valid_sel); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/asoc-sti-use-managed-regmap_field-allocations.patch b/queue-6.18/asoc-sti-use-managed-regmap_field-allocations.patch new file mode 100644 index 0000000000..923486a4fb --- /dev/null +++ b/queue-6.18/asoc-sti-use-managed-regmap_field-allocations.patch @@ -0,0 +1,45 @@ +From 493399eb3ac90761b0575dbce3883cb4144a1866 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:34 +0100 +Subject: ASoC: sti: use managed regmap_field allocations + +From: Sander Vanheule + +[ Upstream commit 1696fad8b259a2d46e51cd6e17e4bcdbe02279fa ] + +The regmap_field objects allocated at player init are never freed and +may leak resources if the driver is removed. + +Switch to devm_regmap_field_alloc() to automatically limit the lifetime +of the allocations the lifetime of the device. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-3-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index f1b7e76f97b58..45d35b887e4eb 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1028,11 +1028,11 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + return PTR_ERR(regmap); + } + +- player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]); + if (IS_ERR(player->clk_sel)) + return PTR_ERR(player->clk_sel); + +- player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]); + if (IS_ERR(player->valid_sel)) + return PTR_ERR(player->valid_sel); + +-- +2.53.0 + diff --git a/queue-6.18/asoc-tas2764-mark-die-temp-register-as-volatile.patch b/queue-6.18/asoc-tas2764-mark-die-temp-register-as-volatile.patch new file mode 100644 index 0000000000..0c483dce46 --- /dev/null +++ b/queue-6.18/asoc-tas2764-mark-die-temp-register-as-volatile.patch @@ -0,0 +1,39 @@ +From 67c6a824f168ad677bdf50edf8f874cb139291f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:44:03 +1000 +Subject: ASoC: tas2764: Mark die temp register as volatile + +From: James Calligeros + +[ Upstream commit 4cfb5971c2fbfac061c23fb4224a3a008199de81 ] + +Reading the temperature register always returns the first value +read from the chip due to regcache. + +Mark TAS2764_TEMP as volatile to prevent returning stale, cached +values when reading the die temp. + +Fixes: 186dfc85f9a8 ("ASoC: tas2764: expose die temp to hwmon") +Signed-off-by: James Calligeros +Link: https://patch.msgid.link/20260425-tas27xx-hwmon-fixes-v1-1-83c13b8e8f54@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2764.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c +index 36e25e48b3546..9f351565dc82d 100644 +--- a/sound/soc/codecs/tas2764.c ++++ b/sound/soc/codecs/tas2764.c +@@ -809,6 +809,7 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg) + { + switch (reg) { + case TAS2764_SW_RST: ++ case TAS2764_TEMP: + case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: + case TAS2764_INT_CLK_CFG: + return true; +-- +2.53.0 + diff --git a/queue-6.18/asoc-tas2770-fix-order-of-operations-for-temperature.patch b/queue-6.18/asoc-tas2770-fix-order-of-operations-for-temperature.patch new file mode 100644 index 0000000000..c5ae5b69c6 --- /dev/null +++ b/queue-6.18/asoc-tas2770-fix-order-of-operations-for-temperature.patch @@ -0,0 +1,52 @@ +From a1d3972eac07f01c99daddcd50a07deb0aab2d21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:44:05 +1000 +Subject: ASoC: tas2770: Fix order of operations for temperature calculation + +From: James Calligeros + +[ Upstream commit c7ecb6a61908c2604dda6e42da66724d256de7b9 ] + +The order of operations to derive the temperature from the temp +register values was wrong, since 1000 / 16 is not an integer. This +resulted in the calculated temperature value deviating from the +value represented by the registers slightly, which was most obvious +when the registers were zeroed (-92.265 *C vs the expected -93.000 *C). + +Scale the reading before dividing the whole thing by 16 to correct +this. + +Fixes: ff73e2780169 ("ASoC: tas2770: expose die temp to hwmon") +Signed-off-by: James Calligeros +Link: https://patch.msgid.link/20260425-tas27xx-hwmon-fixes-v1-3-83c13b8e8f54@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2770.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c +index 6f878b01716f7..2ce3011119bdb 100644 +--- a/sound/soc/codecs/tas2770.c ++++ b/sound/soc/codecs/tas2770.c +@@ -549,7 +549,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result) + /* + * As per datasheet: divide register by 16 and subtract 93 to get + * degrees Celsius. hwmon requires millidegrees. Let's avoid rounding +- * errors by subtracting 93 * 16 then multiplying by 1000 / 16. ++ * errors by subtracting 93 * 16 and scaling before dividing. + * + * NOTE: The ADC registers are initialised to 0 on reset. This means + * that the temperature will read -93 *C until the chip is brought out +@@ -558,7 +558,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result) + * value read back from its registers will be the last value sampled + * before entering software shutdown. + */ +- *result = (reading - (93 * 16)) * (1000 / 16); ++ *result = (reading - (93 * 16)) * 1000 / 16; + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/backlight-sky81452-backlight-check-return-value-of-d.patch b/queue-6.18/backlight-sky81452-backlight-check-return-value-of-d.patch new file mode 100644 index 0000000000..7610b1c717 --- /dev/null +++ b/queue-6.18/backlight-sky81452-backlight-check-return-value-of-d.patch @@ -0,0 +1,46 @@ +From a892b5f53b4e128c1e05d8ba10ee8116d98b4e49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:16:25 +0800 +Subject: backlight: sky81452-backlight: Check return value of + devm_gpiod_get_optional() in sky81452_bl_parse_dt() + +From: Chen Ni + +[ Upstream commit 797cc011ae02bda26f93d25a4442d7a1a77d84df ] + +The devm_gpiod_get_optional() function may return an ERR_PTR in case of +genuine GPIO acquisition errors, not just NULL which indicates the +legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the call in sky81452_bl_parse_dt(). On +error, return the error code to ensure proper failure handling rather +than proceeding with invalid pointers. + +Fixes: e1915eec54a6 ("backlight: sky81452: Convert to GPIO descriptors") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260203021625.578678-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/sky81452-backlight.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c +index 2749231f03854..b2679b24de14b 100644 +--- a/drivers/video/backlight/sky81452-backlight.c ++++ b/drivers/video/backlight/sky81452-backlight.c +@@ -202,6 +202,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( + pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode"); + pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift"); + pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); ++ if (IS_ERR(pdata->gpiod_enable)) ++ return dev_err_cast_probe(dev, pdata->gpiod_enable, ++ "failed to get gpio\n"); + + ret = of_property_count_u32_elems(np, "led-sources"); + if (ret < 0) { +-- +2.53.0 + diff --git a/queue-6.18/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch b/queue-6.18/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch new file mode 100644 index 0000000000..a1c3ba7881 --- /dev/null +++ b/queue-6.18/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch @@ -0,0 +1,60 @@ +From 9a0e69074388382b6e831efab2032233800905fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 09:53:51 -0700 +Subject: bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst() + +From: Weiming Shi + +[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ] + +bareudp_fill_metadata_dst() passes bareudp->sock to +udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. +The socket is only created in bareudp_open() and NULLed in +bareudp_stop(), so calling this function while the device is down +triggers a NULL dereference via sock->sk. + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) + Call Trace: + + bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) + do_execute_actions (net/openvswitch/actions.c:901) + ovs_execute_actions (net/openvswitch/actions.c:1589) + ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) + genl_rcv_msg (net/netlink/genetlink.c:1209) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths +in the same driver. + +Fixes: 571912c69f0e ("net: UDP tunnel encapsulation module for tunnelling different protocols like MPLS, IP, NSH etc.") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426165350.1663137-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 0df3208783ad9..da5866ba06999 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + ++ if (!sock) ++ return -ESHUTDOWN; ++ + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, + 0, &saddr, &info->key, + sport, bareudp->port, info->key.tos, +-- +2.53.0 + diff --git a/queue-6.18/batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failu.patch b/queue-6.18/batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failu.patch new file mode 100644 index 0000000000..d071707f2b --- /dev/null +++ b/queue-6.18/batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failu.patch @@ -0,0 +1,56 @@ +From 12fa00f7a53a1f70649dd4f43e351636c30017ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 13:44:28 +0200 +Subject: batman-adv: tp_meter: fix tp_num leak on kmalloc failure + +From: Sven Eckelmann + +commit ce425dd05d0fe7594930a0fb103634f35ac47bb6 upstream. + +When batadv_tp_start() or batadv_tp_init_recv() fail to allocate a new +tp_vars object, the previously incremented bat_priv->tp_num counter is +never decremented. This causes tp_num to drift upward on each allocation +failure. Since only BATADV_TP_MAX_NUM sessions can be started and the count +is never reduced for these failed allocations, it causes to an exhaustion +of throughput meter sessions. In worst case, no new throughput meter +session can be started until the mesh interface is removed. + +The error handling must decrement tp_num releasing the lock and aborting +the creation of an throughput meter session + +Cc: stable@kernel.org +Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") +[ Context ] +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/tp_meter.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c +index 190affbad3c94..76ece40143840 100644 +--- a/net/batman-adv/tp_meter.c ++++ b/net/batman-adv/tp_meter.c +@@ -994,6 +994,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, + + tp_vars = kmalloc(sizeof(*tp_vars), GFP_ATOMIC); + if (!tp_vars) { ++ atomic_dec(&bat_priv->tp_num); + spin_unlock_bh(&bat_priv->tp_list_lock); + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Meter: %s cannot allocate list elements\n", +@@ -1366,8 +1367,10 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv, + } + + tp_vars = kmalloc(sizeof(*tp_vars), GFP_ATOMIC); +- if (!tp_vars) ++ if (!tp_vars) { ++ atomic_dec(&bat_priv->tp_num); + goto out_unlock; ++ } + + ether_addr_copy(tp_vars->other_end, icmp->orig); + tp_vars->role = BATADV_TP_RECEIVER; +-- +2.53.0 + diff --git a/queue-6.18/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch b/queue-6.18/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch new file mode 100644 index 0000000000..1e4fa41c6b --- /dev/null +++ b/queue-6.18/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch @@ -0,0 +1,47 @@ +From f26f89c954a01dcbdb08b6deed31fc5a5d09a996 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:50:54 +0800 +Subject: blk-cgroup: fix disk reference leak in blkcg_maybe_throttle_current() + +From: Jackie Liu + +[ Upstream commit 23308af722fefed00af5f238024c11710938fba3 ] + +Add the missing put_disk() on the error path in +blkcg_maybe_throttle_current(). When blkcg lookup, blkg lookup, or +blkg_tryget() fails, the function jumps to the out label which only +calls rcu_read_unlock() but does not release the disk reference acquired +by blkcg_schedule_throttle() via get_device(). Since current->throttle_disk +is already set to NULL before the lookup, blkcg_exit() cannot release +this reference either, causing the disk to never be freed. + +Restore the reference release that was present as blk_put_queue() in the +original code but was inadvertently dropped during the conversion from +request_queue to gendisk. + +Fixes: f05837ed73d0 ("blk-cgroup: store a gendisk to throttle in struct task_struct") +Signed-off-by: Jackie Liu +Acked-by: Tejun Heo +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260331085054.46857-1-liu.yun@linux.dev +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 890c161bee25e..9a8d047be580b 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -2037,6 +2037,7 @@ void blkcg_maybe_throttle_current(void) + return; + out: + rcu_read_unlock(); ++ put_disk(disk); + } + + /** +-- +2.53.0 + diff --git a/queue-6.18/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch b/queue-6.18/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch new file mode 100644 index 0000000000..0d8ffffd2d --- /dev/null +++ b/queue-6.18/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch @@ -0,0 +1,75 @@ +From fddee28d099a2caf0aba14baf44ca64d8cf4534d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 11:28:37 +0800 +Subject: blk-cgroup: wait for blkcg cleanup before initializing new disk + +From: Ming Lei + +[ Upstream commit 3dbaacf6ab68f81e3375fe769a2ecdbd3ce386fd ] + +When a queue is shared across disk rebind (e.g., SCSI unbind/bind), the +previous disk's blkcg state is cleaned up asynchronously via +disk_release() -> blkcg_exit_disk(). If the new disk's blkcg_init_disk() +runs before that cleanup finishes, we may overwrite q->root_blkg while +the old one is still alive, and radix_tree_insert() in blkg_create() +fails with -EEXIST because the old blkg entries still occupy the same +queue id slot in blkcg->blkg_tree. This causes the sd probe to fail +with -ENOMEM. + +Fix it by waiting in blkcg_init_disk() for root_blkg to become NULL, +which indicates the previous disk's blkcg cleanup has completed. + +Fixes: 1059699f87eb ("block: move blkcg initialization/destroy into disk allocation/release handler") +Cc: Yi Zhang +Signed-off-by: Ming Lei +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260311032837.2368714-1-ming.lei@redhat.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 3cffb68ba5d87..890c161bee25e 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -611,6 +612,8 @@ static void blkg_destroy_all(struct gendisk *disk) + + q->root_blkg = NULL; + spin_unlock_irq(&q->queue_lock); ++ ++ wake_up_var(&q->root_blkg); + } + + static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) +@@ -1498,6 +1501,18 @@ int blkcg_init_disk(struct gendisk *disk) + struct blkcg_gq *new_blkg, *blkg; + bool preloaded; + ++ /* ++ * If the queue is shared across disk rebind (e.g., SCSI), the ++ * previous disk's blkcg state is cleaned up asynchronously via ++ * disk_release() -> blkcg_exit_disk(). Wait for that cleanup to ++ * finish (indicated by root_blkg becoming NULL) before setting up ++ * new blkcg state. Otherwise, we may overwrite q->root_blkg while ++ * the old one is still alive, and radix_tree_insert() in ++ * blkg_create() will fail with -EEXIST because the old entries ++ * still occupy the same queue id slot in blkcg->blkg_tree. ++ */ ++ wait_var_event(&q->root_blkg, !READ_ONCE(q->root_blkg)); ++ + new_blkg = blkg_alloc(&blkcg_root, disk, GFP_KERNEL); + if (!new_blkg) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch b/queue-6.18/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch new file mode 100644 index 0000000000..a42bf6d3d0 --- /dev/null +++ b/queue-6.18/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch @@ -0,0 +1,52 @@ +From 54dad5de57b1d9671e3a131c7fc338aa8a79dc7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:42:59 +0300 +Subject: Bluetooth: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER + +From: Pauli Virtanen + +[ Upstream commit 5c7209a341ff2ac338b2b0375c34a307b37c9ac2 ] + +When protocol sets HCI_PROTO_DEFER, hci_conn_request_evt() calls +hci_connect_cfm(conn) without hdev->lock. Generally hci_connect_cfm() +assumes it is held, and if conn is deleted concurrently -> UAF. + +Only SCO and ISO set HCI_PROTO_DEFER and only for defer setup listen, +and HCI_EV_CONN_REQUEST is not generated for ISO. In the non-deferred +listening socket code paths, hci_connect_cfm(conn) is called with +hdev->lock held. + +Fix by holding the lock. + +Fixes: 70c464256310 ("Bluetooth: Refactor connection request handling") +Signed-off-by: Pauli Virtanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 6f77ab2629d65..b6b52b81b7b9c 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -3309,8 +3309,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + + memcpy(conn->dev_class, ev->dev_class, 3); + +- hci_dev_unlock(hdev); +- + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; +@@ -3344,7 +3342,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + hci_connect_cfm(conn, 0); + } + +- return; + unlock: + hci_dev_unlock(hdev); + } +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-hci_conn-fix-potential-uaf-in-create_big_s.patch b/queue-6.18/bluetooth-hci_conn-fix-potential-uaf-in-create_big_s.patch new file mode 100644 index 0000000000..083b440686 --- /dev/null +++ b/queue-6.18/bluetooth-hci_conn-fix-potential-uaf-in-create_big_s.patch @@ -0,0 +1,98 @@ +From d4e7257682ad88e3a0f766af63cdeec70617d4e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 13:10:03 -0400 +Subject: Bluetooth: hci_conn: fix potential UAF in create_big_sync + +From: David Carlier + +[ Upstream commit 0beddb0c380bed5f5b8e61ddbe14635bb73d0b41 ] + +Add hci_conn_valid() check in create_big_sync() to detect stale +connections before proceeding with BIG creation. Handle the +resulting -ECANCELED in create_big_complete() and re-validate the +connection under hci_dev_lock() before dereferencing, matching the +pattern used by create_le_conn_complete() and create_pa_complete(). + +Keep the hci_conn object alive across the async boundary by taking +a reference via hci_conn_get() when queueing create_big_sync(), and +dropping it in the completion callback. The refcount and the lock +are complementary: the refcount keeps the object allocated, while +hci_dev_lock() serializes hci_conn_hash_del()'s list_del_rcu() on +hdev->conn_hash, as required by hci_conn_del(). + +hci_conn_put() is called outside hci_dev_unlock() so the final put +(which resolves to kfree() via bt_link_release) does not run under +hdev->lock, though the release path would be safe either way. + +Without this, create_big_complete() would unconditionally +dereference the conn pointer on error, causing a use-after-free +via hci_connect_cfm() and hci_conn_del(). + +Fixes: eca0ae4aea66 ("Bluetooth: Add initial implementation of BIS connections") +Cc: stable@vger.kernel.org +Co-developed-by: Luiz Augusto von Dentz +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: David Carlier +Signed-off-by: Luiz Augusto von Dentz +[ kept stable's `qos->bcast.out.phy == 0x02` context line instead of upstream's renamed `qos->bcast.out.phys == BIT(1)` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/hci_conn.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index 71a24be2a6d67..1b63bc2753a24 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -2113,6 +2113,9 @@ static int create_big_sync(struct hci_dev *hdev, void *data) + u32 flags = 0; + int err; + ++ if (!hci_conn_valid(hdev, conn)) ++ return -ECANCELED; ++ + if (qos->bcast.out.phy == 0x02) + flags |= MGMT_ADV_FLAG_SEC_2M; + +@@ -2188,11 +2191,24 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) + + bt_dev_dbg(hdev, "conn %p", conn); + ++ if (err == -ECANCELED) ++ goto done; ++ ++ hci_dev_lock(hdev); ++ ++ if (!hci_conn_valid(hdev, conn)) ++ goto unlock; ++ + if (err) { + bt_dev_err(hdev, "Unable to create BIG: %d", err); + hci_connect_cfm(conn, err); + hci_conn_del(conn); + } ++ ++unlock: ++ hci_dev_unlock(hdev); ++done: ++ hci_conn_put(conn); + } + + struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, +@@ -2309,10 +2325,11 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, + BT_BOUND, &data); + + /* Queue start periodic advertising and create BIG */ +- err = hci_cmd_sync_queue(hdev, create_big_sync, conn, ++ err = hci_cmd_sync_queue(hdev, create_big_sync, hci_conn_get(conn), + create_big_complete); + if (err < 0) { + hci_conn_drop(conn); ++ hci_conn_put(conn); + return ERR_PTR(err); + } + +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch b/queue-6.18/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch new file mode 100644 index 0000000000..39158bfe65 --- /dev/null +++ b/queue-6.18/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch @@ -0,0 +1,49 @@ +From 4dca1208cfc5ecca906a81a86a4db75455a4ed38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:20 +0100 +Subject: Bluetooth: hci_ldisc: Clear HCI_UART_PROTO_INIT on error + +From: Jonathan Rissanen + +[ Upstream commit 68d39ea5e0adc9ecaea1ce8abd842ec972eb8718 ] + +When hci_register_dev() fails in hci_uart_register_dev() +HCI_UART_PROTO_INIT is not cleared before calling hu->proto->close(hu) +and setting hu->hdev to NULL. This means incoming UART data will reach +the protocol-specific recv handler in hci_uart_tty_receive() after +resources are freed. + +Clear HCI_UART_PROTO_INIT with a write lock before calling +hu->proto->close() and setting hu->hdev to NULL. The write lock ensures +all active readers have completed and no new reader can enter the +protocol recv path before resources are freed. + +This allows the protocol-specific recv functions to remove the +"HCI_UART_REGISTERED" guard without risking a null pointer dereference +if hci_register_dev() fails. + +Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization") +Signed-off-by: Jonathan Rissanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ldisc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index 2b28515de92c4..5455990ab211e 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -692,6 +692,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device"); ++ percpu_down_write(&hu->proto_lock); ++ clear_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ percpu_up_write(&hu->proto_lock); + hu->proto->close(hu); + hu->hdev = NULL; + hci_free_dev(hdev); +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch b/queue-6.18/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch new file mode 100644 index 0000000000..923afb36c9 --- /dev/null +++ b/queue-6.18/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch @@ -0,0 +1,48 @@ +From fd823f41e974a2f3bf3680faa0db679672f7b7e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 23:47:41 +0800 +Subject: Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp + +From: Dudu Lu + +[ Upstream commit 42776497cdbc9a665b384a6dcb85f0d4bd927eab ] + +l2cap_ecred_reconf_rsp() calls l2cap_chan_del() without holding +l2cap_chan_lock(). Every other l2cap_chan_del() caller in the file +acquires the lock first. A remote BLE device can send a crafted +L2CAP ECRED reconfiguration response to corrupt the channel list +while another thread is iterating it. + +Add l2cap_chan_hold() and l2cap_chan_lock() before l2cap_chan_del(), +and l2cap_chan_unlock() and l2cap_chan_put() after, matching the +pattern used in l2cap_ecred_conn_rsp() and l2cap_conn_del(). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 7664723a34d0a..bcb13ce531099 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5473,7 +5473,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + if (chan->ident != cmd->ident) + continue; + ++ l2cap_chan_hold(chan); ++ l2cap_chan_lock(chan); ++ + l2cap_chan_del(chan, ECONNRESET); ++ ++ l2cap_chan_unlock(chan); ++ l2cap_chan_put(chan); + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch b/queue-6.18/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch new file mode 100644 index 0000000000..835d2eec3c --- /dev/null +++ b/queue-6.18/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch @@ -0,0 +1,38 @@ +From 847c422ca053f64b24bf81f7d03609351ff5c6aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 14:34:13 -0400 +Subject: Bluetooth: L2CAP: Fix printing wrong information if SDU length + exceeds MTU + +From: Luiz Augusto von Dentz + +[ Upstream commit 15bf35a660eb82a49f8397fc3d3acada8dae13db ] + +The code was printing skb->len and sdu_len in the places where it should +be sdu_len and chan->imtu respectively to match the if conditions. + +Link: https://lore.kernel.org/linux-bluetooth/20260315132013.75ab40c5@kernel.org/T/#m1418f9c82eeff8510c1beaa21cf53af20db96c06 +Fixes: e1d9a6688986 ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU") +Signed-off-by: Luiz Augusto von Dentz +Reviewed-by: Paul Menzel +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 29e23f20dc438..7664723a34d0a 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6733,7 +6733,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + + if (sdu_len > chan->imtu) { + BT_ERR("Too big LE L2CAP SDU length: len %u > %u", +- skb->len, sdu_len); ++ sdu_len, chan->imtu); + l2cap_send_disconn_req(chan, ECONNRESET); + err = -EMSGSIZE; + goto failed; +-- +2.53.0 + diff --git a/queue-6.18/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch b/queue-6.18/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch new file mode 100644 index 0000000000..76ed70110d --- /dev/null +++ b/queue-6.18/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch @@ -0,0 +1,70 @@ +From 92a87953527da70e8ff54fa9d33f21e1923bddd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:13:45 +0200 +Subject: Bluetooth: SCO: check for codecs->num_codecs == 1 before assigning to + sco_pi(sk)->codec + +From: Stefan Metzmacher + +[ Upstream commit 4e10a9ebbf081c16517cdd9366ac618bf38d7d0c ] + +copy_struct_from_sockptr() fill 'buffer' in +sco_sock_setsockopt() with zeros, so there's no +real problem. + +But it actually looks strange to do this, +without checking all of codecs->codecs[0] +really comes from userspace: + + sco_pi(sk)->codec = codecs->codecs[0]; + +As only optlen < sizeof(struct bt_codecs) is checked +and codecs->num_codecs is not checked against != 1, +but only <= 1, and the space for the additional struct bt_codec +is not checked. + +Note I don't understand bluetooth and I didn't do any runtime +tests with this! I just found it when debugging a problem +in copy_struct_from_sockptr(). + +I just added this to check the size is as expected: + + BUILD_BUG_ON(struct_size(codecs, codecs, 0) != 1); + BUILD_BUG_ON(struct_size(codecs, codecs, 1) != 8); + +And made sure it still compiles using this: + + make CF=-D__CHECK_ENDIAN__ W=1ce C=1 net/bluetooth/sco.o + +Fixes: 3e643e4efa1e ("Bluetooth: Improve setsockopt() handling of malformed user input") +Cc: Michal Luczaj +Cc: Luiz Augusto von Dentz +Cc: Luiz Augusto von Dentz +Cc: Marcel Holtmann +Cc: David Wei +Cc: linux-bluetooth@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Stefan Metzmacher +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/sco.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index 1a38577135d44..9404fdb10ea63 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -1045,7 +1045,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, + + codecs = (void *)buffer; + +- if (codecs->num_codecs > 1) { ++ if (codecs->num_codecs != 1 || ++ optlen < struct_size(codecs, codecs, codecs->num_codecs)) { + hci_dev_put(hdev); + err = -EINVAL; + break; +-- +2.53.0 + diff --git a/queue-6.18/bnge-fix-initial-hwrm-sequence.patch b/queue-6.18/bnge-fix-initial-hwrm-sequence.patch new file mode 100644 index 0000000000..14c8d042c0 --- /dev/null +++ b/queue-6.18/bnge-fix-initial-hwrm-sequence.patch @@ -0,0 +1,92 @@ +From 4b6caef2f778be11bbaadd24f93ae073606afb99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 08:04:37 +0530 +Subject: bnge: fix initial HWRM sequence + +From: Vikas Gupta + +[ Upstream commit 70d7c905a07ae8415b955569620bf2bf77423553 ] + +Firmware may not advertize correct resources if backing store is not +enabled before resource information is queried. +Fix the initial sequence of HWRMs so that driver gets capabilities +and resource information correctly. + +Fixes: 3fa9e977a0cd ("bng_en: Initialize default configuration") +Signed-off-by: Vikas Gupta +Reviewed-by: Rahul Gupta +Link: https://patch.msgid.link/20260418023438.1597876-2-vikas.gupta@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/bnge/bnge_core.c | 30 ++++++++++++++----- + 1 file changed, 22 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_core.c b/drivers/net/ethernet/broadcom/bnge/bnge_core.c +index 312a9db4d75d1..657cd7a880d29 100644 +--- a/drivers/net/ethernet/broadcom/bnge/bnge_core.c ++++ b/drivers/net/ethernet/broadcom/bnge/bnge_core.c +@@ -68,6 +68,13 @@ static int bnge_func_qcaps(struct bnge_dev *bd) + return rc; + } + ++ return 0; ++} ++ ++static int bnge_func_qrcaps_qcfg(struct bnge_dev *bd) ++{ ++ int rc; ++ + rc = bnge_hwrm_func_resc_qcaps(bd); + if (rc) { + dev_err(bd->dev, "query resc caps failure rc: %d\n", rc); +@@ -127,23 +134,28 @@ static int bnge_fw_register_dev(struct bnge_dev *bd) + + bnge_hwrm_fw_set_time(bd); + +- rc = bnge_hwrm_func_drv_rgtr(bd); ++ /* Get the resources and configuration from firmware */ ++ rc = bnge_func_qcaps(bd); + if (rc) { +- dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc); ++ dev_err(bd->dev, "Failed querying caps rc: %d\n", rc); + return rc; + } + + rc = bnge_alloc_ctx_mem(bd); + if (rc) { + dev_err(bd->dev, "Failed to allocate ctx mem rc: %d\n", rc); +- goto err_func_unrgtr; ++ goto err_free_ctx_mem; + } + +- /* Get the resources and configuration from firmware */ +- rc = bnge_func_qcaps(bd); ++ rc = bnge_hwrm_func_drv_rgtr(bd); + if (rc) { +- dev_err(bd->dev, "Failed initial configuration rc: %d\n", rc); +- rc = -ENODEV; ++ dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc); ++ goto err_free_ctx_mem; ++ } ++ ++ rc = bnge_func_qrcaps_qcfg(bd); ++ if (rc) { ++ dev_err(bd->dev, "Failed querying resources rc: %d\n", rc); + goto err_func_unrgtr; + } + +@@ -152,7 +164,9 @@ static int bnge_fw_register_dev(struct bnge_dev *bd) + return 0; + + err_func_unrgtr: +- bnge_fw_unregister_dev(bd); ++ bnge_hwrm_func_drv_unrgtr(bd); ++err_free_ctx_mem: ++ bnge_free_ctx_mem(bd); + return rc; + } + +-- +2.53.0 + diff --git a/queue-6.18/bnge-remove-unsupported-backing-store-type.patch b/queue-6.18/bnge-remove-unsupported-backing-store-type.patch new file mode 100644 index 0000000000..af63d319ab --- /dev/null +++ b/queue-6.18/bnge-remove-unsupported-backing-store-type.patch @@ -0,0 +1,61 @@ +From 8f69422072a2284e9d7bde46c67539655d8df4a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 08:04:38 +0530 +Subject: bnge: remove unsupported backing store type + +From: Vikas Gupta + +[ Upstream commit c6b34add67a5402f53359580956b5c318965a893 ] + +The backing store type, BNGE_CTX_MRAV, is not applicable in Thor Ultra +devices. Remove it from the backing store configuration, as the firmware +will not populate entities in this backing store type, due to which the +driver load fails. + +Fixes: 29c5b358f385 ("bng_en: Add backing store support") +Signed-off-by: Vikas Gupta +Reviewed-by: Dharmender Garg +Link: https://patch.msgid.link/20260418023438.1597876-3-vikas.gupta@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnge/bnge_rmem.c | 16 ---------------- + 1 file changed, 16 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c b/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c +index 79f5ce2e5d083..75d14e52a5bb2 100644 +--- a/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c ++++ b/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c +@@ -325,7 +325,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd) + u32 l2_qps, qp1_qps, max_qps; + u32 ena, entries_sp, entries; + u32 srqs, max_srqs, min; +- u32 num_mr, num_ah; + u32 extra_srqs = 0; + u32 extra_qps = 0; + u32 fast_qpmd_qps; +@@ -391,21 +390,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd) + if (!bnge_is_roce_en(bd)) + goto skip_rdma; + +- ctxm = &ctx->ctx_arr[BNGE_CTX_MRAV]; +- /* 128K extra is needed to accommodate static AH context +- * allocation by f/w. +- */ +- num_mr = min_t(u32, ctxm->max_entries / 2, 1024 * 256); +- num_ah = min_t(u32, num_mr, 1024 * 128); +- ctxm->split_entry_cnt = BNGE_CTX_MRAV_AV_SPLIT_ENTRY + 1; +- if (!ctxm->mrav_av_entries || ctxm->mrav_av_entries > num_ah) +- ctxm->mrav_av_entries = num_ah; +- +- rc = bnge_setup_ctxm_pg_tbls(bd, ctxm, num_mr + num_ah, 2); +- if (rc) +- return rc; +- ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV; +- + ctxm = &ctx->ctx_arr[BNGE_CTX_TIM]; + rc = bnge_setup_ctxm_pg_tbls(bd, ctxm, l2_qps + qp1_qps + extra_qps, 1); + if (rc) +-- +2.53.0 + diff --git a/queue-6.18/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch b/queue-6.18/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch new file mode 100644 index 0000000000..6c3172866b --- /dev/null +++ b/queue-6.18/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch @@ -0,0 +1,572 @@ +From 25f933bf1cbf08a4290f70552d7777e7b0e9a2a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:32:07 +0000 +Subject: bonding: 3ad: implement proper RCU rules for port->aggregator + +From: Eric Dumazet + +[ Upstream commit c4f050ce06c56cfb5993268af4a5cb66ed1cd04e ] + +syzbot found a data-race in bond_3ad_get_active_agg_info / +bond_3ad_state_machine_handler [1] which hints at lack of proper +RCU implementation. + +Add __rcu qualifier to port->aggregator, and add proper RCU API. + +[1] + +BUG: KCSAN: data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler + +write to 0xffff88813cf5c4b0 of 8 bytes by task 36 on cpu 0: + ad_port_selection_logic drivers/net/bonding/bond_3ad.c:1659 [inline] + bond_3ad_state_machine_handler+0x9d5/0x2d60 drivers/net/bonding/bond_3ad.c:2569 + process_one_work kernel/workqueue.c:3302 [inline] + process_scheduled_works+0x4f0/0x9c0 kernel/workqueue.c:3385 + worker_thread+0x58a/0x780 kernel/workqueue.c:3466 + kthread+0x22a/0x280 kernel/kthread.c:436 + ret_from_fork+0x146/0x330 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +read to 0xffff88813cf5c4b0 of 8 bytes by task 22063 on cpu 1: + __bond_3ad_get_active_agg_info drivers/net/bonding/bond_3ad.c:2858 [inline] + bond_3ad_get_active_agg_info+0x8c/0x230 drivers/net/bonding/bond_3ad.c:2881 + bond_fill_info+0xe0f/0x10f0 drivers/net/bonding/bond_netlink.c:853 + rtnl_link_info_fill net/core/rtnetlink.c:906 [inline] + rtnl_link_fill+0x1d7/0x4e0 net/core/rtnetlink.c:927 + rtnl_fill_ifinfo+0xf8e/0x1380 net/core/rtnetlink.c:2168 + rtmsg_ifinfo_build_skb+0x11c/0x1b0 net/core/rtnetlink.c:4453 + rtmsg_ifinfo_event net/core/rtnetlink.c:4486 [inline] + rtmsg_ifinfo+0x6d/0x110 net/core/rtnetlink.c:4495 + __dev_notify_flags+0x76/0x390 net/core/dev.c:9790 + netif_change_flags+0xac/0xd0 net/core/dev.c:9823 + do_setlink+0x905/0x2950 net/core/rtnetlink.c:3180 + rtnl_group_changelink net/core/rtnetlink.c:3813 [inline] + __rtnl_newlink net/core/rtnetlink.c:3981 [inline] + rtnl_newlink+0xf55/0x1400 net/core/rtnetlink.c:4109 + rtnetlink_rcv_msg+0x64b/0x720 net/core/rtnetlink.c:6995 + netlink_rcv_skb+0x123/0x220 net/netlink/af_netlink.c:2550 + rtnetlink_rcv+0x1c/0x30 net/core/rtnetlink.c:7022 + netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline] + netlink_unicast+0x5a8/0x680 net/netlink/af_netlink.c:1344 + netlink_sendmsg+0x5c8/0x6f0 net/netlink/af_netlink.c:1894 + sock_sendmsg_nosec net/socket.c:787 [inline] + __sock_sendmsg net/socket.c:802 [inline] + ____sys_sendmsg+0x563/0x5b0 net/socket.c:2698 + ___sys_sendmsg+0x195/0x1e0 net/socket.c:2752 + __sys_sendmsg net/socket.c:2784 [inline] + __do_sys_sendmsg net/socket.c:2789 [inline] + __se_sys_sendmsg net/socket.c:2787 [inline] + __x64_sys_sendmsg+0xd4/0x160 net/socket.c:2787 + x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x12c/0x3b0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +value changed: 0x0000000000000000 -> 0xffff88813cf5c400 + +Reported by Kernel Concurrency Sanitizer on: +CPU: 1 UID: 0 PID: 22063 Comm: syz.0.31122 Tainted: G W syzkaller #0 PREEMPT(full) +Tainted: [W]=WARN +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 + +Fixes: 47e91f56008b ("bonding: use RCU protection for 3ad xmit path") +Reported-by: syzbot+9bb2ff2a4ab9e17307e1@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/69f0a82f.050a0220.3aadc4.0000.GAE@google.com/ +Signed-off-by: Eric Dumazet +Cc: Jay Vosburgh +Cc: Andrew Lunn +Link: https://patch.msgid.link/20260428123207.3809211-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_3ad.c | 109 ++++++++++++++----------- + drivers/net/bonding/bond_main.c | 8 +- + drivers/net/bonding/bond_netlink.c | 16 ++-- + drivers/net/bonding/bond_procfs.c | 3 +- + drivers/net/bonding/bond_sysfs_slave.c | 17 ++-- + include/net/bond_3ad.h | 2 +- + 6 files changed, 89 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index 49717b7b82a2c..f1ef99f7515b0 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -1014,6 +1014,7 @@ static void ad_cond_set_peer_notif(struct port *port) + static void ad_mux_machine(struct port *port, bool *update_slave_arr) + { + struct bonding *bond = __get_bond_by_port(port); ++ struct aggregator *aggregator; + mux_states_t last_state; + + /* keep current State Machine state to compare later if it was +@@ -1021,6 +1022,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + */ + last_state = port->sm_mux_state; + ++ aggregator = rcu_dereference(port->aggregator); + if (port->sm_vars & AD_PORT_BEGIN) { + port->sm_mux_state = AD_MUX_DETACHED; + } else { +@@ -1040,7 +1042,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * cycle to update ready variable, we check + * READY_N and update READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + port->sm_mux_state = AD_MUX_DETACHED; + break; + } +@@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * update ready variable, we check READY_N and update + * READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + + /* if the wait_while_timer expired, and the port is + * in READY state, move to ATTACHED state +@@ -1071,7 +1073,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + if ((port->sm_vars & AD_PORT_SELECTED) && + (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && + !__check_agg_selection_timer(port)) { +- if (port->aggregator->is_active) { ++ if (aggregator->is_active) { + int state = AD_MUX_COLLECTING_DISTRIBUTING; + + if (!bond->params.coupled_control) +@@ -1087,9 +1089,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * cycle to update ready variable, we check + * READY_N and update READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + port->sm_mux_state = AD_MUX_DETACHED; +- } else if (port->aggregator->is_active) { ++ } else if (aggregator->is_active) { + port->actor_oper_port_state |= + LACP_STATE_SYNCHRONIZATION; + } +@@ -1100,7 +1102,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * sure that a collecting distributing + * port in an active aggregator is enabled + */ +- if (port->aggregator->is_active && ++ if (aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; +@@ -1119,7 +1121,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + */ + struct slave *slave = port->slave; + +- if (port->aggregator->is_active && ++ if (aggregator->is_active && + bond_is_slave_rx_disabled(slave)) { + ad_enable_collecting(port); + *update_slave_arr = true; +@@ -1139,8 +1141,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * sure that a collecting distributing + * port in an active aggregator is enabled + */ +- if (port->aggregator && +- port->aggregator->is_active && ++ if (aggregator && ++ aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; +@@ -1172,7 +1174,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); + break; + case AD_MUX_ATTACHED: +- if (port->aggregator->is_active) ++ if (aggregator->is_active) + port->actor_oper_port_state |= + LACP_STATE_SYNCHRONIZATION; + else +@@ -1546,9 +1548,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + bond = __get_bond_by_port(port); + + /* if the port is connected to other aggregator, detach it */ +- if (port->aggregator) { ++ temp_aggregator = rcu_dereference(port->aggregator); ++ if (temp_aggregator) { + /* detach the port from its former aggregator */ +- temp_aggregator = port->aggregator; + for (curr_port = temp_aggregator->lag_ports; curr_port; + last_port = curr_port, + curr_port = curr_port->next_port_in_aggregator) { +@@ -1571,7 +1573,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + /* clear the port's relations to this + * aggregator + */ +- port->aggregator = NULL; ++ RCU_INIT_POINTER(port->aggregator, NULL); + port->next_port_in_aggregator = NULL; + port->actor_port_aggregator_identifier = 0; + +@@ -1594,7 +1596,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + port->slave->bond->dev->name, + port->slave->dev->name, + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ temp_aggregator->aggregator_identifier); + } + } + /* search on all aggregators for a suitable aggregator for this port */ +@@ -1618,15 +1620,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + ) + ) { + /* attach to the founded aggregator */ +- port->aggregator = aggregator; ++ rcu_assign_pointer(port->aggregator, aggregator); + port->actor_port_aggregator_identifier = +- port->aggregator->aggregator_identifier; ++ aggregator->aggregator_identifier; + port->next_port_in_aggregator = aggregator->lag_ports; +- port->aggregator->num_of_ports++; ++ aggregator->num_of_ports++; + aggregator->lag_ports = port; + slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + + /* mark this port as selected */ + port->sm_vars |= AD_PORT_SELECTED; +@@ -1641,39 +1643,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + if (!found) { + if (free_aggregator) { + /* assign port a new aggregator */ +- port->aggregator = free_aggregator; + port->actor_port_aggregator_identifier = +- port->aggregator->aggregator_identifier; ++ free_aggregator->aggregator_identifier; + + /* update the new aggregator's parameters + * if port was responsed from the end-user + */ + if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) + /* if port is full duplex */ +- port->aggregator->is_individual = false; ++ free_aggregator->is_individual = false; + else +- port->aggregator->is_individual = true; ++ free_aggregator->is_individual = true; + +- port->aggregator->actor_admin_aggregator_key = ++ free_aggregator->actor_admin_aggregator_key = + port->actor_admin_port_key; +- port->aggregator->actor_oper_aggregator_key = ++ free_aggregator->actor_oper_aggregator_key = + port->actor_oper_port_key; +- port->aggregator->partner_system = ++ free_aggregator->partner_system = + port->partner_oper.system; +- port->aggregator->partner_system_priority = ++ free_aggregator->partner_system_priority = + port->partner_oper.system_priority; +- port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; +- port->aggregator->receive_state = 1; +- port->aggregator->transmit_state = 1; +- port->aggregator->lag_ports = port; +- port->aggregator->num_of_ports++; ++ free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; ++ free_aggregator->receive_state = 1; ++ free_aggregator->transmit_state = 1; ++ free_aggregator->lag_ports = port; ++ free_aggregator->num_of_ports++; ++ ++ rcu_assign_pointer(port->aggregator, free_aggregator); + + /* mark this port as selected */ + port->sm_vars |= AD_PORT_SELECTED; + + slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ free_aggregator->aggregator_identifier); + } else { + slave_err(bond->dev, port->slave->dev, + "Port %d did not find a suitable aggregator\n", +@@ -1685,13 +1688,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + * in all aggregator's ports, else set ready=FALSE in all + * aggregator's ports + */ +- __set_agg_ports_ready(port->aggregator, +- __agg_ports_are_ready(port->aggregator)); ++ aggregator = rcu_dereference(port->aggregator); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + +- aggregator = __get_first_agg(port); +- ad_agg_selection_logic(aggregator, update_slave_arr); ++ ad_agg_selection_logic(__get_first_agg(port), update_slave_arr); + +- if (!port->aggregator->is_active) ++ if (!aggregator->is_active) + port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION; + } + +@@ -2060,13 +2062,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond + */ + static void ad_enable_collecting(struct port *port) + { +- if (port->aggregator->is_active) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator->is_active) { + struct slave *slave = port->slave; + + slave_dbg(slave->bond->dev, slave->dev, + "Enabling collecting on port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __enable_collecting_port(port); + } + } +@@ -2078,11 +2082,13 @@ static void ad_enable_collecting(struct port *port) + */ + static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + { +- if (port->aggregator && __agg_has_partner(port->aggregator)) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator && __agg_has_partner(aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling distributing on port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __disable_distributing_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; +@@ -2099,11 +2105,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + static void ad_enable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator->is_active) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator->is_active) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Enabling port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __enable_port(port); + /* Slave array needs update */ + *update_slave_arr = true; +@@ -2120,11 +2128,13 @@ static void ad_enable_collecting_distributing(struct port *port, + static void ad_disable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator && __agg_has_partner(port->aggregator)) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator && __agg_has_partner(aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __disable_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; +@@ -2364,7 +2374,7 @@ void bond_3ad_unbind_slave(struct slave *slave) + */ + for (temp_port = aggregator->lag_ports; temp_port; + temp_port = temp_port->next_port_in_aggregator) { +- temp_port->aggregator = new_aggregator; ++ rcu_assign_pointer(temp_port->aggregator, new_aggregator); + temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; + } + +@@ -2833,15 +2843,16 @@ int bond_3ad_set_carrier(struct bonding *bond) + int __bond_3ad_get_active_agg_info(struct bonding *bond, + struct ad_info *ad_info) + { +- struct aggregator *aggregator = NULL; ++ struct aggregator *aggregator = NULL, *tmp; + struct list_head *iter; + struct slave *slave; + struct port *port; + + bond_for_each_slave_rcu(bond, slave, iter) { + port = &(SLAVE_AD_INFO(slave)->port); +- if (port->aggregator && port->aggregator->is_active) { +- aggregator = port->aggregator; ++ tmp = rcu_dereference(port->aggregator); ++ if (tmp && tmp->is_active) { ++ aggregator = tmp; + break; + } + } +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 1d84e348f2cc7..8b1422dda4c08 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1402,7 +1402,7 @@ static void bond_poll_controller(struct net_device *bond_dev) + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + struct aggregator *agg = +- SLAVE_AD_INFO(slave)->port.aggregator; ++ rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + + if (agg && + agg->aggregator_identifier != ad_info.aggregator_id) +@@ -5155,15 +5155,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) + spin_unlock_bh(&bond->mode_lock); + agg_id = ad_info.aggregator_id; + } ++ rcu_read_lock(); + bond_for_each_slave(bond, slave, iter) { + if (skipslave == slave) + continue; + + all_slaves->arr[all_slaves->count++] = slave; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { +- struct aggregator *agg; ++ const struct aggregator *agg; + +- agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (!agg || agg->aggregator_identifier != agg_id) + continue; + } +@@ -5175,6 +5176,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) + + usable_slaves->arr[usable_slaves->count++] = slave; + } ++ rcu_read_unlock(); + + bond_set_slave_arr(bond, usable_slaves, all_slaves); + return ret; +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index ea1a80e658aeb..c7d3e0602c831 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -66,27 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb, + const struct port *ad_port; + + ad_port = &SLAVE_AD_INFO(slave)->port; +- agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ rcu_read_lock(); ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (agg) { + if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, + agg->aggregator_identifier)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u8(skb, + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, + ad_port->actor_oper_port_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u16(skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, + ad_port->sm_churn_actor_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + ad_port->sm_churn_partner_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + } ++ rcu_read_unlock(); + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + SLAVE_AD_INFO(slave)->port_priority)) +@@ -95,6 +97,8 @@ static int bond_fill_slave_info(struct sk_buff *skb, + + return 0; + ++nla_put_failure_rcu: ++ rcu_read_unlock(); + nla_put_failure: + return -EMSGSIZE; + } +diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c +index 7edf72ec816ab..0c0146b761772 100644 +--- a/drivers/net/bonding/bond_procfs.c ++++ b/drivers/net/bonding/bond_procfs.c +@@ -187,6 +187,7 @@ static void bond_info_show_master(struct seq_file *seq) + } + } + ++/* Note: runs under rcu_read_lock() */ + static void bond_info_show_slave(struct seq_file *seq, + const struct slave *slave) + { +@@ -213,7 +214,7 @@ static void bond_info_show_slave(struct seq_file *seq, + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + const struct port *port = &SLAVE_AD_INFO(slave)->port; +- const struct aggregator *agg = port->aggregator; ++ const struct aggregator *agg = rcu_dereference(port->aggregator); + + if (agg) { + seq_printf(seq, "Aggregator ID: %d\n", +diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c +index 36d0e8440b5b9..fc6fe7181789d 100644 +--- a/drivers/net/bonding/bond_sysfs_slave.c ++++ b/drivers/net/bonding/bond_sysfs_slave.c +@@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf) + const struct aggregator *agg; + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { +- agg = SLAVE_AD_INFO(slave)->port.aggregator; +- if (agg) +- return sysfs_emit(buf, "%d\n", +- agg->aggregator_identifier); ++ rcu_read_lock(); ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); ++ if (agg) { ++ ssize_t res = sysfs_emit(buf, "%d\n", ++ agg->aggregator_identifier); ++ rcu_read_unlock(); ++ return res; ++ } ++ rcu_read_unlock(); + } + + return sysfs_emit(buf, "N/A\n"); +@@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf) + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; +- if (ad_port->aggregator) ++ if (rcu_access_pointer(ad_port->aggregator)) + return sysfs_emit(buf, "%u\n", + ad_port->actor_oper_port_state); + } +@@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf) + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; +- if (ad_port->aggregator) ++ if (rcu_access_pointer(ad_port->aggregator)) + return sysfs_emit(buf, "%u\n", + ad_port->partner_oper.port_state); + } +diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h +index c92d4a976246d..05572c19e14b7 100644 +--- a/include/net/bond_3ad.h ++++ b/include/net/bond_3ad.h +@@ -243,7 +243,7 @@ typedef struct port { + churn_state_t sm_churn_actor_state; + churn_state_t sm_churn_partner_state; + struct slave *slave; /* pointer to the bond slave that this port belongs to */ +- struct aggregator *aggregator; /* pointer to an aggregator that this port related to */ ++ struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */ + struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ + u32 transaction_id; /* continuous number for identification of Marker PDU's; */ + struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ +-- +2.53.0 + diff --git a/queue-6.18/bonding-print-churn-state-via-netlink.patch b/queue-6.18/bonding-print-churn-state-via-netlink.patch new file mode 100644 index 0000000000..6fff7b4e96 --- /dev/null +++ b/queue-6.18/bonding-print-churn-state-via-netlink.patch @@ -0,0 +1,65 @@ +From ce31c223f05a90fbe967e5e7ecbcdcdfed73ae8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 02:02:14 +0000 +Subject: bonding: print churn state via netlink + +From: Hangbin Liu + +[ Upstream commit 4916f2e2f3fc9aef289fcd07949301e5c29094c2 ] + +Currently, the churn state is printed only in sysfs. Add netlink support +so users could get the state via netlink. + +Signed-off-by: Hangbin Liu +Link: https://patch.msgid.link/20260224020215.6012-1-liuhangbin@gmail.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_netlink.c | 9 +++++++++ + include/uapi/linux/if_link.h | 2 ++ + 2 files changed, 11 insertions(+) + +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index 286f11c517f76..ea1a80e658aeb 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -29,6 +29,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ + nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ ++ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE */ ++ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE */ + 0; + } + +@@ -77,6 +79,13 @@ static int bond_fill_slave_info(struct sk_buff *skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) + goto nla_put_failure; ++ ++ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, ++ ad_port->sm_churn_actor_state)) ++ goto nla_put_failure; ++ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, ++ ad_port->sm_churn_partner_state)) ++ goto nla_put_failure; + } + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index 3b491d96e52eb..69f19759b79d5 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -1567,6 +1567,8 @@ enum { + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + IFLA_BOND_SLAVE_PRIO, + IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, ++ IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, ++ IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + __IFLA_BOND_SLAVE_MAX, + }; + +-- +2.53.0 + diff --git a/queue-6.18/bpf-allow-instructions-with-arena-source-and-non-are.patch b/queue-6.18/bpf-allow-instructions-with-arena-source-and-non-are.patch new file mode 100644 index 0000000000..b560419fb6 --- /dev/null +++ b/queue-6.18/bpf-allow-instructions-with-arena-source-and-non-are.patch @@ -0,0 +1,64 @@ +From 921169e54e533295299e958653c39f3d467c1154 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 13:45:38 -0400 +Subject: bpf: Allow instructions with arena source and non-arena dest + registers + +From: Emil Tsalapatis + +[ Upstream commit ac61bffe91d4bda08806e12957c6d64756d042db ] + +The compiler sometimes stores the result of a PTR_TO_ARENA and SCALAR +operation into the scalar register rather than the pointer register. +Relax the verifier to allow operations between a source arena register +and a destination non-arena register, marking the destination's value +as a PTR_TO_ARENA. + +Signed-off-by: Emil Tsalapatis +Acked-by: Song Liu +Fixes: 6082b6c328b5 ("bpf: Recognize addr_space_cast instruction in the verifier.") +Link: https://lore.kernel.org/r/20260412174546.18684-2-emil@etsalapatis.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index e8975e9761e26..153a7c1d32069 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -15705,11 +15705,20 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + int err; + + dst_reg = ®s[insn->dst_reg]; +- src_reg = NULL; ++ if (BPF_SRC(insn->code) == BPF_X) ++ src_reg = ®s[insn->src_reg]; ++ else ++ src_reg = NULL; + +- if (dst_reg->type == PTR_TO_ARENA) { ++ /* Case where at least one operand is an arena. */ ++ if (dst_reg->type == PTR_TO_ARENA || (src_reg && src_reg->type == PTR_TO_ARENA)) { + struct bpf_insn_aux_data *aux = cur_aux(env); + ++ if (dst_reg->type != PTR_TO_ARENA) ++ *dst_reg = *src_reg; ++ ++ dst_reg->subreg_def = env->insn_idx + 1; ++ + if (BPF_CLASS(insn->code) == BPF_ALU64) + /* + * 32-bit operations zero upper bits automatically. +@@ -15725,7 +15734,6 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + ptr_reg = dst_reg; + + if (BPF_SRC(insn->code) == BPF_X) { +- src_reg = ®s[insn->src_reg]; + if (src_reg->type != SCALAR_VALUE) { + if (dst_reg->type != SCALAR_VALUE) { + /* Combining two pointers by any ALU op yields +-- +2.53.0 + diff --git a/queue-6.18/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch b/queue-6.18/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch new file mode 100644 index 0000000000..b9af840280 --- /dev/null +++ b/queue-6.18/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch @@ -0,0 +1,84 @@ +From 13cacfcd9e62355ec25c8d390b29033c1b376fcb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:01:41 +0800 +Subject: bpf: allow UTF-8 literals in bpf_bprintf_prepare() + +From: Yihan Ding + +[ Upstream commit b960430ea8862ef37ce53c8bf74a8dc79d3f2404 ] + +bpf_bprintf_prepare() only needs ASCII parsing for conversion +specifiers. Plain text can safely carry bytes >= 0x80, so allow +UTF-8 literals outside '%' sequences while keeping ASCII control +bytes rejected and format specifiers ASCII-only. + +This keeps existing parsing rules for format directives unchanged, +while allowing helpers such as bpf_trace_printk() to emit UTF-8 +literal text. + +Update test_snprintf_negative() in the same commit so selftests keep +matching the new plain-text vs format-specifier split during bisection. + +Fixes: 48cac3f4a96d ("bpf: Implement formatted output helpers with bstr_printf") +Signed-off-by: Yihan Ding +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416120142.1420646-2-dingyihan@uniontech.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/helpers.c | 17 ++++++++++++++++- + .../testing/selftests/bpf/prog_tests/snprintf.c | 3 ++- + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index 68da6dcfb4bb7..b596452424481 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -848,7 +848,13 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args, + data->buf = buffers->buf; + + for (i = 0; i < fmt_size; i++) { +- if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { ++ unsigned char c = fmt[i]; ++ ++ /* ++ * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass ++ * through unchanged, while still rejecting ASCII control bytes. ++ */ ++ if (isascii(c) && !isprint(c) && !isspace(c)) { + err = -EINVAL; + goto out; + } +@@ -870,6 +876,15 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args, + * always access fmt[i + 1], in the worst case it will be a 0 + */ + i++; ++ c = fmt[i]; ++ /* ++ * The format parser below only understands ASCII conversion ++ * specifiers and modifiers, so reject non-ASCII after '%'. ++ */ ++ if (!isascii(c)) { ++ err = -EINVAL; ++ goto out; ++ } + + /* skip optional "[0 +-][num]" width formatting field */ + while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || +diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c +index 594441acb7071..4e4a82d54f799 100644 +--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c ++++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c +@@ -114,7 +114,8 @@ static void test_snprintf_negative(void) + ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5"); + ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6"); + ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7"); +- ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character"); ++ ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text"); ++ ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier"); + ASSERT_ERR(load_single_snprintf("\x1"), "non printable character"); + ASSERT_ERR(load_single_snprintf("%p%"), "invalid specifier 8"); + ASSERT_ERR(load_single_snprintf("%s%"), "invalid specifier 9"); +-- +2.53.0 + diff --git a/queue-6.18/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch b/queue-6.18/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch new file mode 100644 index 0000000000..c2ef4f5822 --- /dev/null +++ b/queue-6.18/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch @@ -0,0 +1,63 @@ +From 8f828c6a779ddcc22d267eff76a0a2481221955b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 20:27:02 +0800 +Subject: bpf,arc_jit: Fix missing newline in pr_err messages + +From: haoyu.lu + +[ Upstream commit b6b5e0ebd429d66ce37ae5af649a74ea1f041d92 ] + +Add missing newline to pr_err messages in ARC JIT. + +Fixes: f122668ddcce ("ARC: Add eBPF JIT support") +Signed-off-by: haoyu.lu +Link: https://lore.kernel.org/r/20260324122703.641-1-hechushiguitu666@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arc/net/bpf_jit_arcv2.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arc/net/bpf_jit_arcv2.c b/arch/arc/net/bpf_jit_arcv2.c +index 6d989b6d88c69..7ee50aeae5a45 100644 +--- a/arch/arc/net/bpf_jit_arcv2.c ++++ b/arch/arc/net/bpf_jit_arcv2.c +@@ -2427,7 +2427,7 @@ u8 arc_prologue(u8 *buf, u32 usage, u16 frame_size) + + #ifdef ARC_BPF_JIT_DEBUG + if ((usage & BIT(ARC_R_FP)) && frame_size == 0) { +- pr_err("FP is being saved while there is no frame."); ++ pr_err("FP is being saved while there is no frame.\n"); + BUG(); + } + #endif +@@ -2454,7 +2454,7 @@ u8 arc_epilogue(u8 *buf, u32 usage, u16 frame_size) + + #ifdef ARC_BPF_JIT_DEBUG + if ((usage & BIT(ARC_R_FP)) && frame_size == 0) { +- pr_err("FP is being saved while there is no frame."); ++ pr_err("FP is being saved while there is no frame.\n"); + BUG(); + } + #endif +@@ -2868,7 +2868,7 @@ u8 gen_jmp_64(u8 *buf, u8 rd, u8 rs, u8 cond, u32 curr_off, u32 targ_off) + break; + default: + #ifdef ARC_BPF_JIT_DEBUG +- pr_err("64-bit jump condition is not known."); ++ pr_err("64-bit jump condition is not known.\n"); + BUG(); + #endif + } +@@ -2948,7 +2948,7 @@ u8 gen_jmp_32(u8 *buf, u8 rd, u8 rs, u8 cond, u32 curr_off, u32 targ_off) + */ + if (cond >= ARC_CC_LAST) { + #ifdef ARC_BPF_JIT_DEBUG +- pr_err("32-bit jump condition is not known."); ++ pr_err("32-bit jump condition is not known.\n"); + BUG(); + #endif + return 0; +-- +2.53.0 + diff --git a/queue-6.18/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch b/queue-6.18/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch new file mode 100644 index 0000000000..6408544b07 --- /dev/null +++ b/queue-6.18/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch @@ -0,0 +1,96 @@ +From cd9ce049d775d552373c1fdde8b3b56908d10526 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 07:33:52 -0700 +Subject: bpf, arm32: Reject BPF-to-BPF calls and callbacks in the JIT + +From: Puranjay Mohan + +[ Upstream commit e1d486445af3c392628532229f7ce5f5cf7891b6 ] + +The ARM32 BPF JIT does not support BPF-to-BPF function calls +(BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does +not reject them either. + +When a program with subprograms is loaded (e.g. libxdp's XDP +dispatcher uses __noinline__ subprograms, or any program using +callbacks like bpf_loop or bpf_for_each_map_elem), the verifier +invokes bpf_jit_subprogs() which calls bpf_int_jit_compile() +for each subprogram. + +For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT +silently emits code using the wrong address computation: + + func = __bpf_call_base + imm + +where imm is a pc-relative subprogram offset, producing a bogus +function pointer. + +For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and +loads the immediate as a normal 64-bit value without error. + +In both cases, build_body() reports success and a JIT image is +allocated. ARM32 lacks the jit_data/extra_pass mechanism needed +for the second JIT pass in bpf_jit_subprogs(). On the second +pass, bpf_int_jit_compile() performs a full fresh compilation, +allocating a new JIT binary and overwriting prog->bpf_func. The +first allocation is never freed. bpf_jit_subprogs() then detects +the function pointer changed and aborts with -ENOTSUPP, but the +original JIT binary has already been leaked. Each program +load/unload cycle leaks one JIT binary allocation, as reported +by kmemleak: + + unreferenced object 0xbf0a1000 (size 4096): + backtrace: + bpf_jit_binary_alloc+0x64/0xfc + bpf_int_jit_compile+0x14c/0x348 + bpf_jit_subprogs+0x4fc/0xa60 + +Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL +handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling +through to the existing 'notyet' path. This causes build_body() +to fail before any JIT binary is allocated, so +bpf_int_jit_compile() returns the original program unjitted. +bpf_jit_subprogs() then sees !prog->jited and cleanly falls +back to the interpreter with no leak. + +Acked-by: Daniel Borkmann +Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs") +Reported-by: Jonas Rebmann +Closes: https://lore.kernel.org/bpf/b63e9174-7a3d-4e22-8294-16df07a4af89@pengutronix.de +Tested-by: Jonas Rebmann +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417143353.838911-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm/net/bpf_jit_32.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c +index deeb8f292454b..a900aa9738855 100644 +--- a/arch/arm/net/bpf_jit_32.c ++++ b/arch/arm/net/bpf_jit_32.c +@@ -1852,6 +1852,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + { + u64 val = (u32)imm | (u64)insn[1].imm << 32; + ++ if (insn->src_reg == BPF_PSEUDO_FUNC) ++ goto notyet; ++ + emit_a32_mov_i64(dst, val, ctx); + + return 1; +@@ -2055,6 +2058,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + const s8 *r5 = bpf2a32[BPF_REG_5]; + const u32 func = (u32)__bpf_call_base + (u32)imm; + ++ if (insn->src_reg == BPF_PSEUDO_CALL) ++ goto notyet; ++ + emit_a32_mov_r64(true, r0, r1, ctx); + emit_a32_mov_r64(true, r1, r2, ctx); + emit_push_r64(r5, ctx); +-- +2.53.0 + diff --git a/queue-6.18/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch b/queue-6.18/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch new file mode 100644 index 0000000000..05ec38e6da --- /dev/null +++ b/queue-6.18/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch @@ -0,0 +1,57 @@ +From 5245afd9e68e8b02771ced8436c607dc7468d306 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:14:03 +0200 +Subject: bpf, arm64: Fix off-by-one in check_imm signed range check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Borkmann + +[ Upstream commit 1dd8be4ec722ce54e4cace59f3a4ba658111b3ec ] + +check_imm(bits, imm) is used in the arm64 BPF JIT to verify that +a branch displacement (in arm64 instruction units) fits into the +signed N-bit immediate field of a B, B.cond or CBZ/CBNZ encoding +before it is handed to the encoder. The macro currently tests for +(imm > 0 && imm >> bits) || (imm < 0 && ~imm >> bits) which admits +values in [-2^N, 2^N) — effectively a signed (N+1)-bit range. A +signed N-bit field only holds [-2^(N-1), 2^(N-1)), so the check +admits one extra bit of range on each side. + +In particular, for check_imm19(), values in [2^18, 2^19) slip past +the check but do not fit into the 19-bit signed imm19 field of +B.cond. aarch64_insn_encode_immediate() then masks the raw value +into the 19-bit field, setting bit 18 (the sign bit) and flipping +a forward branch into a backward one. Same class of issue exists +for check_imm26() and the B/BL encoding. Shift by (bits - 1) +instead of bits so the actual signed N-bit range is enforced. + +Fixes: e54bcde3d69d ("arm64: eBPF JIT compiler") +Signed-off-by: Daniel Borkmann +Reviewed-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260415121403.639619-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 107eb71b533a0..4b2aacdd43221 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -35,8 +35,8 @@ + #define ARENA_VM_START (MAX_BPF_JIT_REG + 5) + + #define check_imm(bits, imm) do { \ +- if ((((imm) > 0) && ((imm) >> (bits))) || \ +- (((imm) < 0) && (~(imm) >> (bits)))) { \ ++ if ((((imm) > 0) && ((imm) >> ((bits) - 1))) || \ ++ (((imm) < 0) && (~(imm) >> ((bits) - 1)))) { \ + pr_info("[%2d] imm=%d(0x%x) out of range\n", \ + i, imm, imm); \ + return -EINVAL; \ +-- +2.53.0 + diff --git a/queue-6.18/bpf-arm64-remove-redundant-bpf_flush_icache-after-pa.patch b/queue-6.18/bpf-arm64-remove-redundant-bpf_flush_icache-after-pa.patch new file mode 100644 index 0000000000..9fbc05a90e --- /dev/null +++ b/queue-6.18/bpf-arm64-remove-redundant-bpf_flush_icache-after-pa.patch @@ -0,0 +1,76 @@ +From 554ada92dea40c105075bc35bdf6c6cf2f1d1d52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:11:08 -0700 +Subject: bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator + finalize + +From: Puranjay Mohan + +[ Upstream commit 42f18ae53011826cfd3c84d041817e7f07bc645b ] + +bpf_flush_icache() calls flush_icache_range() to clean the data cache +and invalidate the instruction cache for the JITed code region. However, +since commit 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory +management"), this flush is redundant. + +bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX +region via bpf_arch_text_copy() -> aarch64_insn_copy() -> __text_poke(), +and __text_poke() already calls flush_icache_range() on the written +range. The subsequent bpf_flush_icache() repeats the same cache +maintenance on an overlapping range, including an unnecessary second +synchronous IPI to all CPUs via kick_all_cpus_sync(). + +Remove the redundant bpf_flush_icache() call and its now-unused +definition. + +Fixes: 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management") +Acked-by: Song Liu +Signed-off-by: Puranjay Mohan +Acked-by: Breno Leitao +Link: https://lore.kernel.org/r/20260413191111.3426023-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 4b2aacdd43221..873c1b784a872 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -18,7 +18,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -1964,11 +1963,6 @@ static int validate_ctx(struct jit_ctx *ctx) + return 0; + } + +-static inline void bpf_flush_icache(void *start, void *end) +-{ +- flush_icache_range((unsigned long)start, (unsigned long)end); +-} +- + static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size) + { + int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3; +@@ -2207,12 +2201,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + prog = orig_prog; + goto out_off; + } +- /* +- * The instructions have now been copied to the ROX region from +- * where they will execute. Now the data cache has to be cleaned to +- * the PoU and the I-cache has to be invalidated for the VAs. +- */ +- bpf_flush_icache(ro_header, ctx.ro_image + ctx.idx); + } else { + jit_data->ctx = ctx; + jit_data->ro_image = ro_image_ptr; +-- +2.53.0 + diff --git a/queue-6.18/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch b/queue-6.18/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch new file mode 100644 index 0000000000..91ee9fd716 --- /dev/null +++ b/queue-6.18/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch @@ -0,0 +1,52 @@ +From 17a16aac9e8b47192d42439862afc0c83723bcea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 20:23:33 +0800 +Subject: bpf: Drop task_to_inode and inet_conn_established from lsm sleepable + hooks + +From: Jiayuan Chen + +[ Upstream commit beaf0e96b1da74549a6cabd040f9667d83b2e97e ] + +bpf_lsm_task_to_inode() is called under rcu_read_lock() and +bpf_lsm_inet_conn_established() is called from softirq context, so +neither hook can be used by sleepable LSM programs. + +Fixes: 423f16108c9d8 ("bpf: Augment the set of sleepable LSM hooks") +Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/3ab69731-24d1-431a-a351-452aafaaf2a5@std.uestc.edu.cn/T/#u +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260407122334.344072-1-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_lsm.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c +index 0a59df1c550a0..2eead789b898b 100644 +--- a/kernel/bpf/bpf_lsm.c ++++ b/kernel/bpf/bpf_lsm.c +@@ -357,8 +357,6 @@ BTF_ID(func, bpf_lsm_sb_umount) + BTF_ID(func, bpf_lsm_settime) + + #ifdef CONFIG_SECURITY_NETWORK +-BTF_ID(func, bpf_lsm_inet_conn_established) +- + BTF_ID(func, bpf_lsm_socket_accept) + BTF_ID(func, bpf_lsm_socket_bind) + BTF_ID(func, bpf_lsm_socket_connect) +@@ -379,7 +377,6 @@ BTF_ID(func, bpf_lsm_syslog) + BTF_ID(func, bpf_lsm_task_alloc) + BTF_ID(func, bpf_lsm_task_prctl) + BTF_ID(func, bpf_lsm_task_setscheduler) +-BTF_ID(func, bpf_lsm_task_to_inode) + BTF_ID(func, bpf_lsm_userns_create) + BTF_SET_END(sleepable_lsm_hooks) + +-- +2.53.0 + diff --git a/queue-6.18/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch b/queue-6.18/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch new file mode 100644 index 0000000000..3a7880551a --- /dev/null +++ b/queue-6.18/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch @@ -0,0 +1,77 @@ +From 39341580296efc3dec6d04de1dac5c5b7bd8f7ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 01:26:50 +0200 +Subject: bpf: Enforce regsafe base id consistency for BPF_ADD_CONST scalars + +From: Daniel Borkmann + +[ Upstream commit 2f2ec8e7730e21fc9bd49e0de9cdd58213ea24d0 ] + +When regsafe() compares two scalar registers that both carry +BPF_ADD_CONST, check_scalar_ids() maps their full compound id +(aka base | BPF_ADD_CONST flag) as one idmap entry. However, +it never verifies that the underlying base ids, that is, with +the flag stripped are consistent with existing idmap mappings. + +This allows construction of two verifier states where the old +state has R3 = R2 + 10 (both sharing base id A) while the current +state has R3 = R4 + 10 (base id C, unrelated to R2). The idmap +creates two independent entries: A->B (for R2) and A|flag->C|flag +(for R3), without catching that A->C conflicts with A->B. State +pruning then incorrectly succeeds. + +Fix this by additionally verifying base ID mapping consistency +whenever BPF_ADD_CONST is set: after mapping the compound ids, +also invoke check_ids() on the base IDs (flag bits stripped). +This ensures that if A was already mapped to B from comparing +the source register, any ADD_CONST derivative must also derive +from B, not an unrelated C. + +Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260410232651.559778-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 0cf6ca1f870f7..e8975e9761e26 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -18825,6 +18825,13 @@ static bool check_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + * and r7.id=0 (both independent), without temp IDs both would map old_id=X + * to cur_id=0 and pass. With temp IDs: r6 maps X->temp1, r7 tries to map + * X->temp2, but X is already mapped to temp1, so the check fails correctly. ++ * ++ * When old_id has BPF_ADD_CONST set, the compound id (base | flag) and the ++ * base id (flag stripped) must both map consistently. Example: old has ++ * r2.id=A, r3.id=A|flag (r3 = r2 + delta), cur has r2.id=B, r3.id=C|flag ++ * (r3 derived from unrelated r4). Without the base check, idmap gets two ++ * independent entries A->B and A|flag->C|flag, missing that A->C conflicts ++ * with A->B. The base ID cross-check catches this. + */ + static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + { +@@ -18833,7 +18840,15 @@ static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + + cur_id = cur_id ? cur_id : ++idmap->tmp_id_gen; + +- return check_ids(old_id, cur_id, idmap); ++ if (!check_ids(old_id, cur_id, idmap)) ++ return false; ++ if (old_id & BPF_ADD_CONST) { ++ old_id &= ~BPF_ADD_CONST; ++ cur_id &= ~BPF_ADD_CONST; ++ if (!check_ids(old_id, cur_id, idmap)) ++ return false; ++ } ++ return true; + } + + static void clean_func_state(struct bpf_verifier_env *env, +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-abuse-of-kprobe_write_ctx-via-freplace.patch b/queue-6.18/bpf-fix-abuse-of-kprobe_write_ctx-via-freplace.patch new file mode 100644 index 0000000000..bc226c7e32 --- /dev/null +++ b/queue-6.18/bpf-fix-abuse-of-kprobe_write_ctx-via-freplace.patch @@ -0,0 +1,82 @@ +From 6641bce4ca0e59f2b523109ecf525e083daeaebf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 22:53:52 +0800 +Subject: bpf: Fix abuse of kprobe_write_ctx via freplace + +From: Leon Hwang + +[ Upstream commit 611fe4b79af72d00d80f2223354284447daafae9 ] + +uprobe programs are allowed to modify struct pt_regs. + +Since the actual program type of uprobe is KPROBE, it can be abused to +modify struct pt_regs via kprobe+freplace when the kprobe attaches to +kernel functions. + +For example, + +SEC("?kprobe") +int kprobe(struct pt_regs *regs) +{ + return 0; +} + +SEC("?freplace") +int freplace_kprobe(struct pt_regs *regs) +{ + regs->di = 0; + return 0; +} + +freplace_kprobe prog will attach to kprobe prog. +kprobe prog will attach to a kernel function. + +Without this patch, when the kernel function runs, its first arg will +always be set as 0 via the freplace_kprobe prog. + +To fix the abuse of kprobe_write_ctx=true via kprobe+freplace, disallow +attaching freplace programs on kprobe programs with different +kprobe_write_ctx values. + +Fixes: 7384893d970e ("bpf: Allow uprobe program to change context registers") +Acked-by: Jiri Olsa +Acked-by: Song Liu +Signed-off-by: Leon Hwang +Link: https://lore.kernel.org/r/20260331145353.87606-2-leon.hwang@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 586ece78f783a..ff268fd2ff8b5 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -3708,6 +3708,23 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog, + tr = prog->aux->dst_trampoline; + tgt_prog = prog->aux->dst_prog; + } ++ /* ++ * It is to prevent modifying struct pt_regs via kprobe_write_ctx=true ++ * freplace prog. Without this check, kprobe_write_ctx=true freplace ++ * prog is allowed to attach to kprobe_write_ctx=false kprobe prog, and ++ * then modify the registers of the kprobe prog's target kernel ++ * function. ++ * ++ * This also blocks the combination of uprobe+freplace, because it is ++ * unable to recognize the use of the tgt_prog as an uprobe or a kprobe ++ * by tgt_prog itself. At attach time, uprobe/kprobe is recognized by ++ * the target perf event flags in __perf_event_set_bpf_prog(). ++ */ ++ if (prog->type == BPF_PROG_TYPE_EXT && ++ prog->aux->kprobe_write_ctx != tgt_prog->aux->kprobe_write_ctx) { ++ err = -EINVAL; ++ goto out_unlock; ++ } + + err = bpf_link_prime(&link->link.link, &link_primer); + if (err) +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch b/queue-6.18/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch new file mode 100644 index 0000000000..e991f6cebf --- /dev/null +++ b/queue-6.18/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch @@ -0,0 +1,47 @@ +From 564b5bf16c7e0a34dd5489602cad4c48ca3e8608 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 21:29:50 +0800 +Subject: bpf: fix end-of-list detection in cgroup_storage_get_next_key() + +From: Weiming Shi + +[ Upstream commit 5828b9e5b272ecff7cf5d345128d3de7324117f7 ] + +list_next_entry() never returns NULL -- when the current element is the +last entry it wraps to the list head via container_of(). The subsequent +NULL check is therefore dead code and get_next_key() never returns +-ENOENT for the last element, instead reading storage->key from a bogus +pointer that aliases internal map fields and copying the result to +userspace. + +Replace it with list_entry_is_head() so the function correctly returns +-ENOENT when there are no more entries. + +Fixes: de9cbbaadba5 ("bpf: introduce cgroup storage maps") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Sun Jian +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260403132951.43533-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/local_storage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c +index c93a756e035c0..b8db4fbd3bd2a 100644 +--- a/kernel/bpf/local_storage.c ++++ b/kernel/bpf/local_storage.c +@@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, + goto enoent; + + storage = list_next_entry(storage, list_map); +- if (!storage) ++ if (list_entry_is_head(storage, &map->list, list_map)) + goto enoent; + } else { + storage = list_first_entry(&map->list, +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-linked-reg-delta-tracking-when-src_reg-dst_r.patch b/queue-6.18/bpf-fix-linked-reg-delta-tracking-when-src_reg-dst_r.patch new file mode 100644 index 0000000000..ad864ff53f --- /dev/null +++ b/queue-6.18/bpf-fix-linked-reg-delta-tracking-when-src_reg-dst_r.patch @@ -0,0 +1,46 @@ +From 993a3d0387429ba92caac0f5688cf1b4322771a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 21:24:18 +0200 +Subject: bpf: Fix linked reg delta tracking when src_reg == dst_reg + +From: Daniel Borkmann + +[ Upstream commit d7f14173c0d5866c3cae759dee560ad1bed10d2e ] + +Consider the case of rX += rX where src_reg and dst_reg are pointers to +the same bpf_reg_state in adjust_reg_min_max_vals(). The latter first +modifies the dst_reg in-place, and later in the delta tracking, the +subsequent is_reg_const(src_reg)/reg_const_value(src_reg) reads the +post-{add,sub} value instead of the original source. + +This is problematic since it sets an incorrect delta, which sync_linked_regs() +then propagates to linked registers, thus creating a verifier-vs-runtime +mismatch. Fix it by just skipping this corner case. + +Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260407192421.508817-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 6cf8b13db301b..6d5fc1af7a1f6 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -15808,7 +15808,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + */ + if (env->bpf_capable && + (BPF_OP(insn->code) == BPF_ADD || BPF_OP(insn->code) == BPF_SUB) && +- dst_reg->id && is_reg_const(src_reg, alu32)) { ++ dst_reg->id && is_reg_const(src_reg, alu32) && ++ !(BPF_SRC(insn->code) == BPF_X && insn->src_reg == insn->dst_reg)) { + u64 val = reg_const_value(src_reg, alu32); + s32 off; + +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch b/queue-6.18/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch new file mode 100644 index 0000000000..a99fbe3121 --- /dev/null +++ b/queue-6.18/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch @@ -0,0 +1,148 @@ +From c24282f624297580cef538a59ea48c6e11d14e7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:35 -0700 +Subject: bpf: fix mm lifecycle in open-coded task_vma iterator + +From: Puranjay Mohan + +[ Upstream commit d8e27d2d22b6e2df3a0125b8c08e9aace38c954c ] + +The open-coded task_vma iterator reads task->mm locklessly and acquires +mmap_read_trylock() but never calls mmget(). If the task exits +concurrently, the mm_struct can be freed as it is not +SLAB_TYPESAFE_BY_RCU, resulting in a use-after-free. + +Safely read task->mm with a trylock on alloc_lock and acquire an mm +reference. Drop the reference via bpf_iter_mmput_async() in _destroy() +and error paths. bpf_iter_mmput_async() is a local wrapper around +mmput_async() with a fallback to mmput() on !CONFIG_MMU. + +Reject irqs-disabled contexts (including NMI) up front. Operations used +by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) +take spinlocks with IRQs disabled (pool->lock, pi_lock). Running from +NMI or from a tracepoint that fires with those locks held could +deadlock. + +A trylock on alloc_lock is used instead of the blocking task_lock() +(get_task_mm) to avoid a deadlock when a softirq BPF program iterates +a task that already holds its alloc_lock on the same CPU. + +Fixes: 4ac454682158 ("bpf: Introduce task_vma open-coded iterator kfuncs") +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260408154539.3832150-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 54 +++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 51 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index 98d9b4c0daff3..c1f5fbe9dc2f3 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include "mmap_unlock_work.h" + + static const char * const iter_task_type_names[] = { +@@ -794,6 +795,15 @@ const struct bpf_func_proto bpf_find_vma_proto = { + .arg5_type = ARG_ANYTHING, + }; + ++static inline void bpf_iter_mmput_async(struct mm_struct *mm) ++{ ++#ifdef CONFIG_MMU ++ mmput_async(mm); ++#else ++ mmput(mm); ++#endif ++} ++ + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +@@ -825,6 +835,24 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + BUILD_BUG_ON(sizeof(struct bpf_iter_task_vma_kern) != sizeof(struct bpf_iter_task_vma)); + BUILD_BUG_ON(__alignof__(struct bpf_iter_task_vma_kern) != __alignof__(struct bpf_iter_task_vma)); + ++ /* bpf_iter_mmput_async() needs mmput_async() which requires CONFIG_MMU */ ++ if (!IS_ENABLED(CONFIG_MMU)) { ++ kit->data = NULL; ++ return -EOPNOTSUPP; ++ } ++ ++ /* ++ * Reject irqs-disabled contexts including NMI. Operations used ++ * by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) ++ * can take spinlocks with IRQs disabled (pi_lock, pool->lock). ++ * Running from NMI or from a tracepoint that fires with those ++ * locks held could deadlock. ++ */ ++ if (irqs_disabled()) { ++ kit->data = NULL; ++ return -EBUSY; ++ } ++ + /* is_iter_reg_valid_uninit guarantees that kit hasn't been initialized + * before, so non-NULL kit->data doesn't point to previously + * bpf_mem_alloc'd bpf_iter_task_vma_kern_data +@@ -834,7 +862,25 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + return -ENOMEM; + + kit->data->task = get_task_struct(task); ++ /* ++ * Safely read task->mm and acquire an mm reference. ++ * ++ * Cannot use get_task_mm() because its task_lock() is a ++ * blocking spin_lock that would deadlock if the target task ++ * already holds alloc_lock on this CPU (e.g. a softirq BPF ++ * program iterating a task interrupted while holding its ++ * alloc_lock). ++ */ ++ if (!spin_trylock(&task->alloc_lock)) { ++ err = -EBUSY; ++ goto err_cleanup_iter; ++ } + kit->data->mm = task->mm; ++ if (kit->data->mm && !(task->flags & PF_KTHREAD)) ++ mmget(kit->data->mm); ++ else ++ kit->data->mm = NULL; ++ spin_unlock(&task->alloc_lock); + if (!kit->data->mm) { + err = -ENOENT; + goto err_cleanup_iter; +@@ -844,15 +890,16 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work); + if (irq_work_busy || !mmap_read_trylock(kit->data->mm)) { + err = -EBUSY; +- goto err_cleanup_iter; ++ goto err_cleanup_mmget; + } + + vma_iter_init(&kit->data->vmi, kit->data->mm, addr); + return 0; + ++err_cleanup_mmget: ++ bpf_iter_mmput_async(kit->data->mm); + err_cleanup_iter: +- if (kit->data->task) +- put_task_struct(kit->data->task); ++ put_task_struct(kit->data->task); + bpf_mem_free(&bpf_global_ma, kit->data); + /* NULL kit->data signals failed bpf_iter_task_vma initialization */ + kit->data = NULL; +@@ -875,6 +922,7 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + if (kit->data) { + bpf_mmap_unlock_mm(kit->data->work, kit->data->mm); + put_task_struct(kit->data->task); ++ bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); + } + } +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch b/queue-6.18/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch new file mode 100644 index 0000000000..824d278f74 --- /dev/null +++ b/queue-6.18/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch @@ -0,0 +1,56 @@ +From 30c9a4175e47e8bcd71c1475be624ec4dcc88a65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 11:08:07 -0700 +Subject: bpf: Fix NULL deref in map_kptr_match_type for scalar regs + +From: Mykyta Yatsenko + +[ Upstream commit 4d0a375887ab4d49e4da1ff10f9606cab8f7c3ad ] + +Commit ab6c637ad027 ("bpf: Fix a bpf_kptr_xchg() issue with local +kptr") refactored map_kptr_match_type() to branch on btf_is_kernel() +before checking base_type(). A scalar register stored into a kptr +slot has no btf, so the btf_is_kernel(reg->btf) call dereferences +NULL. + +Move the base_type() != PTR_TO_BTF_ID guard before any reg->btf +access. + +Fixes: ab6c637ad027 ("bpf: Fix a bpf_kptr_xchg() issue with local kptr") +Reported-by: Hiker Cl +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221372 +Signed-off-by: Mykyta Yatsenko +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416-kptr_crash-v1-1-5589356584b4@meta.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 153a7c1d32069..ebfa27d4002c5 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5843,6 +5843,9 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + int perm_flags; + const char *reg_name = ""; + ++ if (base_type(reg->type) != PTR_TO_BTF_ID) ++ goto bad_type; ++ + if (btf_is_kernel(reg->btf)) { + perm_flags = PTR_MAYBE_NULL | PTR_TRUSTED | MEM_RCU; + +@@ -5855,7 +5858,7 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + perm_flags |= MEM_PERCPU; + } + +- if (base_type(reg->type) != PTR_TO_BTF_ID || (type_flag(reg->type) & ~perm_flags)) ++ if (type_flag(reg->type) & ~perm_flags) + goto bad_type; + + /* We need to verify reg->type and reg->btf, before accessing reg->btf */ +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-oob-in-pcpu_init_value.patch b/queue-6.18/bpf-fix-oob-in-pcpu_init_value.patch new file mode 100644 index 0000000000..df35e192e4 --- /dev/null +++ b/queue-6.18/bpf-fix-oob-in-pcpu_init_value.patch @@ -0,0 +1,54 @@ +From 8c01904e8f2d47d018fe9befc4fb270d263851eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 15:42:35 +0800 +Subject: bpf: Fix OOB in pcpu_init_value + +From: Lang Xu + +[ Upstream commit 576afddfee8d1108ee299bf10f581593540d1a36 ] + +An out-of-bounds read occurs when copying element from a +BPF_MAP_TYPE_CGROUP_STORAGE map to another pcpu map with the +same value_size that is not rounded up to 8 bytes. + +The issue happens when: +1. A CGROUP_STORAGE map is created with value_size not aligned to + 8 bytes (e.g., 4 bytes) +2. A pcpu map is created with the same value_size (e.g., 4 bytes) +3. Update element in 2 with data in 1 + +pcpu_init_value assumes that all sources are rounded up to 8 bytes, +and invokes copy_map_value_long to make a data copy, However, the +assumption doesn't stand since there are some cases where the source +may not be rounded up to 8 bytes, e.g., CGROUP_STORAGE, skb->data. +the verifier verifies exactly the size that the source claims, not +the size rounded up to 8 bytes by kernel, an OOB happens when the +source has only 4 bytes while the copy size(4) is rounded up to 8. + +Fixes: d3bec0138bfb ("bpf: Zero-fill re-used per-cpu map element") +Reported-by: Kaiyan Mei +Closes: https://lore.kernel.org/all/14e6c70c.6c121.19c0399d948.Coremail.kaiyanm@hust.edu.cn/ +Link: https://lore.kernel.org/r/420FEEDDC768A4BE+20260402074236.2187154-1-xulang@uniontech.com +Signed-off-by: Lang Xu +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/hashtab.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c +index e7721f0776c72..469bc48b25127 100644 +--- a/kernel/bpf/hashtab.c ++++ b/kernel/bpf/hashtab.c +@@ -981,7 +981,7 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr, + + for_each_possible_cpu(cpu) { + if (cpu == current_cpu) +- copy_map_value_long(&htab->map, per_cpu_ptr(pptr, cpu), value); ++ copy_map_value(&htab->map, per_cpu_ptr(pptr, cpu), value); + else /* Since elem is preallocated, we cannot touch special fields */ + zero_map_value(&htab->map, per_cpu_ptr(pptr, cpu)); + } +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch b/queue-6.18/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch new file mode 100644 index 0000000000..2b2f1e677b --- /dev/null +++ b/queue-6.18/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch @@ -0,0 +1,46 @@ +From 3f09deb3be4a62b248a1a485255a4927d971ebcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:27:19 +0200 +Subject: bpf: Fix precedence bug in convert_bpf_ld_abs alignment check + +From: Daniel Borkmann + +[ Upstream commit e5f635edd393aeaa7cad9e42831d397e6e2e1eed ] + +Fix an operator precedence issue in convert_bpf_ld_abs() where the +expression offset + ip_align % size evaluates as offset + (ip_align % size) +due to % having higher precedence than +. That latter evaluation does +not make any sense. The intended check is (offset + ip_align) % size == 0 +to verify that the packet load offset is properly aligned for direct +access. + +With NET_IP_ALIGN == 2, the bug causes the inline fast-path for direct +packet loads to almost never be taken on !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +platforms. This forces nearly all cBPF BPF_LD_ABS packet loads through +the bpf_skb_load_helper slow path on the affected archs. + +Fixes: e0cea7ce988c ("bpf: implement ld_abs/ld_ind in native bpf") +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260416122719.661033-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 7fc01474c3781..ae6d0453cf123 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -508,7 +508,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp) + ((unaligned_ok && offset >= 0) || + (!unaligned_ok && offset >= 0 && + offset + ip_align >= 0 && +- offset + ip_align % size == 0))) { ++ (offset + ip_align) % size == 0))) { + bool ldx_off_ok = offset <= S16_MAX; + + *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H); +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch b/queue-6.18/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch new file mode 100644 index 0000000000..1cb10d304e --- /dev/null +++ b/queue-6.18/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch @@ -0,0 +1,62 @@ +From 66b6b70e79bb43c3628df8a947027aad82ee9f8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 10:38:23 +0000 +Subject: bpf: Fix RCU stall in bpf_fd_array_map_clear() + +From: Sechang Lim + +[ Upstream commit 4406942e65ca128c56c67443832988873c21d2e9 ] + +Add a missing cond_resched() in bpf_fd_array_map_clear() loop. + +For PROG_ARRAY maps with many entries this loop calls +prog_array_map_poke_run() per entry which can be expensive, and +without yielding this can cause RCU stalls under load: + + rcu: Stack dump where RCU GP kthread last ran: + CPU: 0 UID: 0 PID: 30932 Comm: kworker/0:2 Not tainted 6.14.0-13195-g967e8def1100 #2 PREEMPT(undef) + Workqueue: events prog_array_map_clear_deferred + RIP: 0010:write_comp_data+0x38/0x90 kernel/kcov.c:246 + Call Trace: + + prog_array_map_poke_run+0x77/0x380 kernel/bpf/arraymap.c:1096 + __fd_array_map_delete_elem+0x197/0x310 kernel/bpf/arraymap.c:925 + bpf_fd_array_map_clear kernel/bpf/arraymap.c:1000 [inline] + prog_array_map_clear_deferred+0x119/0x1b0 kernel/bpf/arraymap.c:1141 + process_one_work+0x898/0x19d0 kernel/workqueue.c:3238 + process_scheduled_works kernel/workqueue.c:3319 [inline] + worker_thread+0x770/0x10b0 kernel/workqueue.c:3400 + kthread+0x465/0x880 kernel/kthread.c:464 + ret_from_fork+0x4d/0x80 arch/x86/kernel/process.c:153 + ret_from_fork_asm+0x19/0x30 arch/x86/entry/entry_64.S:245 + + +Reviewed-by: Sun Jian +Fixes: da765a2f5993 ("bpf: Add poke dependency tracking for prog array maps") +Signed-off-by: Sechang Lim +Link: https://lore.kernel.org/r/20260407103823.3942156-1-rhkrqnwk98@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/arraymap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c +index 80b1765a31596..248ab6854cf24 100644 +--- a/kernel/bpf/arraymap.c ++++ b/kernel/bpf/arraymap.c +@@ -1006,8 +1006,10 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer) + struct bpf_array *array = container_of(map, struct bpf_array, map); + int i; + +- for (i = 0; i < array->map.max_entries; i++) ++ for (i = 0; i < array->map.max_entries; i++) { + __fd_array_map_delete_elem(map, &i, need_defer); ++ cond_resched(); ++ } + } + + static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key, +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-refcount-check-in-check_struct_ops_btf_id.patch b/queue-6.18/bpf-fix-refcount-check-in-check_struct_ops_btf_id.patch new file mode 100644 index 0000000000..3cdeee1fd6 --- /dev/null +++ b/queue-6.18/bpf-fix-refcount-check-in-check_struct_ops_btf_id.patch @@ -0,0 +1,39 @@ +From 2aee692087e2bc5a43012ffb9a5b74784d2aaec1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 14:02:20 +0100 +Subject: bpf: Fix refcount check in check_struct_ops_btf_id() + +From: Keisuke Nishimura + +[ Upstream commit 25e3e1f1096089a64901ae1faa7b7b13446653db ] + +The current implementation only checks whether the first argument is +refcounted. Fix this by iterating over all arguments. + +Signed-off-by: Keisuke Nishimura +Fixes: 38f1e66abd184 ("bpf: Do not allow tail call in strcut_ops program with __ref argument") +Reviewed-by: Emil Tsalapatis +Acked-by: Amery Hung +Link: https://lore.kernel.org/r/20260320130219.63711-1-keisuke.nishimura@inria.fr +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index db1c591a1da3b..76503ed088b5d 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -23687,7 +23687,7 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) + } + + for (i = 0; i < st_ops_desc->arg_info[member_idx].cnt; i++) { +- if (st_ops_desc->arg_info[member_idx].info->refcounted) { ++ if (st_ops_desc->arg_info[member_idx].info[i].refcounted) { + has_refcounted_arg = true; + break; + } +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch b/queue-6.18/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch new file mode 100644 index 0000000000..3a3e4c5b9e --- /dev/null +++ b/queue-6.18/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch @@ -0,0 +1,72 @@ +From ca3662df21078addf858d8ba0a8a40d3811f8f05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:18:50 +0800 +Subject: bpf: Fix stale offload->prog pointer after constant blinding + +From: MingTao Huang + +[ Upstream commit a1aa9ef47c299c5bbc30594d3c2f0589edf908e6 ] + +When a dev-bound-only BPF program (BPF_F_XDP_DEV_BOUND_ONLY) undergoes +JIT compilation with constant blinding enabled (bpf_jit_harden >= 2), +bpf_jit_blind_constants() clones the program. The original prog is then +freed in bpf_jit_prog_release_other(), which updates aux->prog to point +to the surviving clone, but fails to update offload->prog. + +This leaves offload->prog pointing to the freed original program. When +the network namespace is subsequently destroyed, cleanup_net() triggers +bpf_dev_bound_netdev_unregister(), which iterates ondev->progs and calls +__bpf_prog_offload_destroy(offload->prog). Accessing the freed prog +causes a page fault: + +BUG: unable to handle page fault for address: ffffc900085f1038 +Workqueue: netns cleanup_net +RIP: 0010:__bpf_prog_offload_destroy+0xc/0x80 +Call Trace: +__bpf_offload_dev_netdev_unregister+0x257/0x350 +bpf_dev_bound_netdev_unregister+0x4a/0x90 +unregister_netdevice_many_notify+0x2a2/0x660 +... +cleanup_net+0x21a/0x320 + +The test sequence that triggers this reliably is: + +1. Set net.core.bpf_jit_harden=2 (echo 2 > /proc/sys/net/core/bpf_jit_harden) +2. Run xdp_metadata selftest, which creates a dev-bound-only XDP + program on a veth inside a netns (./test_progs -t xdp_metadata) +3. cleanup_net -> page fault in __bpf_prog_offload_destroy + +Dev-bound-only programs are unique in that they have an offload structure +but go through the normal JIT path instead of bpf_prog_offload_compile(). +This means they are subject to constant blinding's prog clone-and-replace, +while also having offload->prog that must stay in sync. + +Fix this by updating offload->prog in bpf_jit_prog_release_other(), +alongside the existing aux->prog update. Both are back-pointers to +the prog that must be kept in sync when the prog is replaced. + +Fixes: 2b3486bc2d23 ("bpf: Introduce device-bound XDP programs") +Signed-off-by: MingTao Huang +Link: https://lore.kernel.org/r/tencent_BCF692F45859CCE6C22B7B0B64827947D406@qq.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 8de006d388f67..931a4ddd8530c 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1468,6 +1468,8 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other) + * know whether fp here is the clone or the original. + */ + fp->aux->prog = fp; ++ if (fp->aux->offload) ++ fp->aux->offload->prog = fp; + bpf_prog_clone_free(fp_other); + } + +-- +2.53.0 + diff --git a/queue-6.18/bpf-fix-variable-length-stack-write-over-spilled-poi.patch b/queue-6.18/bpf-fix-variable-length-stack-write-over-spilled-poi.patch new file mode 100644 index 0000000000..da9a6b6a5d --- /dev/null +++ b/queue-6.18/bpf-fix-variable-length-stack-write-over-spilled-poi.patch @@ -0,0 +1,80 @@ +From 3c1665acb0c28e29e620787fab63997171d6eda6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:59:36 -0700 +Subject: bpf: Fix variable length stack write over spilled pointers + +From: Alexei Starovoitov + +[ Upstream commit 4639eb9e30ab10c7935c7c19e872facf9a94713f ] + +Scrub slots if variable-offset stack write goes over spilled pointers. +Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT +and valid program is rejected by check_stack_read_fixed_off() +with obscure "invalid size of register fill" message. + +Fixes: 01f810ace9ed ("bpf: Allow variable-offset stack access") +Acked-by: Eduard Zingerman +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260324215938.81733-1-alexei.starovoitov@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 76503ed088b5d..0d1ec2b5d469a 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5095,6 +5095,18 @@ static void check_fastcall_stack_contract(struct bpf_verifier_env *env, + } + } + ++static void scrub_special_slot(struct bpf_func_state *state, int spi) ++{ ++ int i; ++ ++ /* regular write of data into stack destroys any spilled ptr */ ++ state->stack[spi].spilled_ptr.type = NOT_INIT; ++ /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */ ++ if (is_stack_slot_special(&state->stack[spi])) ++ for (i = 0; i < BPF_REG_SIZE; i++) ++ scrub_spilled_slot(&state->stack[spi].slot_type[i]); ++} ++ + /* check_stack_{read,write}_fixed_off functions track spill/fill of registers, + * stack boundary and alignment are checked in check_mem_access() + */ +@@ -5192,12 +5204,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, + } else { + u8 type = STACK_MISC; + +- /* regular write of data into stack destroys any spilled ptr */ +- state->stack[spi].spilled_ptr.type = NOT_INIT; +- /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */ +- if (is_stack_slot_special(&state->stack[spi])) +- for (i = 0; i < BPF_REG_SIZE; i++) +- scrub_spilled_slot(&state->stack[spi].slot_type[i]); ++ scrub_special_slot(state, spi); + + /* when we zero initialize stack slots mark them as such */ + if ((reg && register_is_null(reg)) || +@@ -5321,8 +5328,13 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env, + } + } + +- /* Erase all other spilled pointers. */ +- state->stack[spi].spilled_ptr.type = NOT_INIT; ++ /* ++ * Scrub slots if variable-offset stack write goes over spilled pointers. ++ * Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT ++ * and valid program is rejected by check_stack_read_fixed_off() ++ * with obscure "invalid size of register fill" message. ++ */ ++ scrub_special_slot(state, spi); + + /* Update the slot type. */ + new_type = STACK_MISC; +-- +2.53.0 + diff --git a/queue-6.18/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch b/queue-6.18/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch new file mode 100644 index 0000000000..fb4f50ef59 --- /dev/null +++ b/queue-6.18/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch @@ -0,0 +1,74 @@ +From 4193e237c773ff71b326f250efee2d9133eb7a79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 00:12:20 +0800 +Subject: bpf: reject negative CO-RE accessor indices in bpf_core_parse_spec() + +From: Weiming Shi + +[ Upstream commit 1c22483a2c4bbf747787f328392ca3e68619c4dc ] + +CO-RE accessor strings are colon-separated indices that describe a path +from a root BTF type to a target field, e.g. "0:1:2" walks through +nested struct members. bpf_core_parse_spec() parses each component with +sscanf("%d"), so negative values like -1 are silently accepted. The +subsequent bounds checks (access_idx >= btf_vlen(t)) only guard the +upper bound and always pass for negative values because C integer +promotion converts the __u16 btf_vlen result to int, making the +comparison (int)(-1) >= (int)(N) false for any positive N. + +When -1 reaches btf_member_bit_offset() it gets cast to u32 0xffffffff, +producing an out-of-bounds read far past the members array. A crafted +BPF program with a negative CO-RE accessor on any struct that exists in +vmlinux BTF (e.g. task_struct) crashes the kernel deterministically +during BPF_PROG_LOAD on any system with CONFIG_DEBUG_INFO_BTF=y +(default on major distributions). The bug is reachable with CAP_BPF: + + BUG: unable to handle page fault for address: ffffed11818b6626 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + Oops: Oops: 0000 [#1] SMP KASAN NOPTI + CPU: 0 UID: 0 PID: 85 Comm: poc Not tainted 7.0.0-rc6 #18 PREEMPT(full) + RIP: 0010:bpf_core_parse_spec (tools/lib/bpf/relo_core.c:354) + RAX: 00000000ffffffff + Call Trace: + + bpf_core_calc_relo_insn (tools/lib/bpf/relo_core.c:1321) + bpf_core_apply (kernel/bpf/btf.c:9507) + check_core_relo (kernel/bpf/verifier.c:19475) + bpf_check (kernel/bpf/verifier.c:26031) + bpf_prog_load (kernel/bpf/syscall.c:3089) + __sys_bpf (kernel/bpf/syscall.c:6228) + + +CO-RE accessor indices are inherently non-negative (struct member index, +array element index, or enumerator index), so reject them immediately +after parsing. + +Fixes: ddc7c3042614 ("libbpf: implement BPF CO-RE offset relocation algorithm") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Emil Tsalapatis +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260404161221.961828-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/relo_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c +index 6eea5edba58a5..0ccc8f548cbaa 100644 +--- a/tools/lib/bpf/relo_core.c ++++ b/tools/lib/bpf/relo_core.c +@@ -292,6 +292,8 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf, + ++spec_str; + if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1) + return -EINVAL; ++ if (access_idx < 0) ++ return -EINVAL; + if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) + return -E2BIG; + spec_str += parsed_len; +-- +2.53.0 + diff --git a/queue-6.18/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch b/queue-6.18/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch new file mode 100644 index 0000000000..5d961bc060 --- /dev/null +++ b/queue-6.18/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch @@ -0,0 +1,72 @@ +From 27bbbdfcfb94f42fca616a1ff2e9144a5cce4cc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 11:46:22 +0800 +Subject: bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb + +From: Sun Jian + +[ Upstream commit 12bec2bd4b76d81c5d3996bd14ec1b7f4d983747 ] + +bpf_prog_test_run_skb() calls eth_type_trans() first and then uses +skb->protocol to initialize sk family and address fields for the test +run. + +For IPv4 and IPv6 packets, it may access ip_hdr(skb) or ipv6_hdr(skb) +even when the provided test input only contains an Ethernet header. + +Reject the input earlier if the Ethernet frame carries IPv4/IPv6 +EtherType but the L3 header is too short. + +Fold the IPv4/IPv6 header length checks into the existing protocol +switch and return -EINVAL before accessing the network headers. + +Fixes: fa5cb548ced6 ("bpf: Setup socket family and addresses in bpf_prog_test_run_skb") +Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc +Signed-off-by: Sun Jian +Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 65d7f8d51823e..963fee5d01e24 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1057,19 +1057,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + switch (skb->protocol) { + case htons(ETH_P_IP): +- sk->sk_family = AF_INET; +- if (sizeof(struct iphdr) <= skb_headlen(skb)) { +- sk->sk_rcv_saddr = ip_hdr(skb)->saddr; +- sk->sk_daddr = ip_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct iphdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET; ++ sk->sk_rcv_saddr = ip_hdr(skb)->saddr; ++ sk->sk_daddr = ip_hdr(skb)->daddr; + break; + #if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +- sk->sk_family = AF_INET6; +- if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { +- sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; +- sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET6; ++ sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; ++ sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + break; + #endif + default: +-- +2.53.0 + diff --git a/queue-6.18/bpf-relax-scalar-id-equivalence-for-state-pruning.patch b/queue-6.18/bpf-relax-scalar-id-equivalence-for-state-pruning.patch new file mode 100644 index 0000000000..b24e7388b7 --- /dev/null +++ b/queue-6.18/bpf-relax-scalar-id-equivalence-for-state-pruning.patch @@ -0,0 +1,172 @@ +From a596b0d8c219ab7e50c4b3385cd612bc74abaa27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 08:51:00 -0800 +Subject: bpf: Relax scalar id equivalence for state pruning + +From: Puranjay Mohan + +[ Upstream commit b0388bafa4949bd30af7b3be5ee415f2a25ac014 ] + +Scalar register IDs are used by the verifier to track relationships +between registers and enable bounds propagation across those +relationships. Once an ID becomes singular (i.e. only a single +register/stack slot carries it), it can no longer contribute to bounds +propagation and effectively becomes stale. The previous commit makes the +verifier clear such ids before caching the state. + +When comparing the current and cached states for pruning, these stale +IDs can cause technically equivalent states to be considered different +and thus prevent pruning. + +For example, in the selftest added in the next commit, two registers - +r6 and r7 are not linked to any other registers and get cached with +id=0, in the current state, they are both linked to each other with +id=A. Before this commit, check_scalar_ids would give temporary ids to +r6 and r7 (say tid1 and tid2) and then check_ids() would map tid1->A, +and when it would see tid2->A, it would not consider these state +equivalent. + +Relax scalar ID equivalence by treating rold->id == 0 as "independent": +if the old state did not rely on any ID relationships for a register, +then any ID/linking present in the current state only adds constraints +and is always safe to accept for pruning. Implement this by returning +true immediately in check_scalar_ids() when old_id == 0. + +Maintain correctness for the opposite direction (old_id != 0 && cur_id +== 0) by still allocating a temporary ID for cur_id == 0. This avoids +incorrectly allowing multiple independent current registers (id==0) to +satisfy a single linked old ID during mapping. + +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260203165102.2302462-5-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Stable-dep-of: 2f2ec8e7730e ("bpf: Enforce regsafe base id consistency for BPF_ADD_CONST scalars") +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 63 +++++++++++++++---- + .../selftests/bpf/progs/verifier_scalar_ids.c | 8 ++- + 2 files changed, 56 insertions(+), 15 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 6d5fc1af7a1f6..0cf6ca1f870f7 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -18808,13 +18808,29 @@ static bool check_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + return false; + } + +-/* Similar to check_ids(), but allocate a unique temporary ID +- * for 'old_id' or 'cur_id' of zero. +- * This makes pairs like '0 vs unique ID', 'unique ID vs 0' valid. ++/* ++ * Compare scalar register IDs for state equivalence. ++ * ++ * When old_id == 0, the old register is independent - not linked to any ++ * other register. Any linking in the current state only adds constraints, ++ * making it more restrictive. Since the old state didn't rely on any ID ++ * relationships for this register, it's always safe to accept cur regardless ++ * of its ID. Hence, return true immediately. ++ * ++ * When old_id != 0 but cur_id == 0, we need to ensure that different ++ * independent registers in cur don't incorrectly satisfy the ID matching ++ * requirements of linked registers in old. ++ * ++ * Example: if old has r6.id=X and r7.id=X (linked), but cur has r6.id=0 ++ * and r7.id=0 (both independent), without temp IDs both would map old_id=X ++ * to cur_id=0 and pass. With temp IDs: r6 maps X->temp1, r7 tries to map ++ * X->temp2, but X is already mapped to temp1, so the check fails correctly. + */ + static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + { +- old_id = old_id ? old_id : ++idmap->tmp_id_gen; ++ if (!old_id) ++ return true; ++ + cur_id = cur_id ? cur_id : ++idmap->tmp_id_gen; + + return check_ids(old_id, cur_id, idmap); +@@ -18975,11 +18991,21 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, + } + if (!rold->precise && exact == NOT_EXACT) + return true; +- if ((rold->id & BPF_ADD_CONST) != (rcur->id & BPF_ADD_CONST)) +- return false; +- if ((rold->id & BPF_ADD_CONST) && (rold->off != rcur->off)) +- return false; +- /* Why check_ids() for scalar registers? ++ /* ++ * Linked register tracking uses rold->id to detect relationships. ++ * When rold->id == 0, the register is independent and any linking ++ * in rcur only adds constraints. When rold->id != 0, we must verify ++ * id mapping and (for BPF_ADD_CONST) offset consistency. ++ * ++ * +------------------+-----------+------------------+---------------+ ++ * | | rold->id | rold + ADD_CONST | rold->id == 0 | ++ * |------------------+-----------+------------------+---------------| ++ * | rcur->id | range,ids | false | range | ++ * | rcur + ADD_CONST | false | range,ids,off | range | ++ * | rcur->id == 0 | range,ids | false | range | ++ * +------------------+-----------+------------------+---------------+ ++ * ++ * Why check_ids() for scalar registers? + * + * Consider the following BPF code: + * 1: r6 = ... unbound scalar, ID=a ... +@@ -19003,9 +19029,22 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, + * --- + * Also verify that new value satisfies old value range knowledge. + */ +- return range_within(rold, rcur) && +- tnum_in(rold->var_off, rcur->var_off) && +- check_scalar_ids(rold->id, rcur->id, idmap); ++ ++ /* ADD_CONST mismatch: different linking semantics */ ++ if ((rold->id & BPF_ADD_CONST) && !(rcur->id & BPF_ADD_CONST)) ++ return false; ++ ++ if (rold->id && !(rold->id & BPF_ADD_CONST) && (rcur->id & BPF_ADD_CONST)) ++ return false; ++ ++ /* Both have offset linkage: offsets must match */ ++ if ((rold->id & BPF_ADD_CONST) && rold->off != rcur->off) ++ return false; ++ ++ if (!check_scalar_ids(rold->id, rcur->id, idmap)) ++ return false; ++ ++ return range_within(rold, rcur) && tnum_in(rold->var_off, rcur->var_off); + case PTR_TO_MAP_KEY: + case PTR_TO_MAP_VALUE: + case PTR_TO_MEM: +diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +index 1fdd85b4b8443..f1c17df9c4f99 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c ++++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +@@ -751,9 +751,9 @@ __success __log_level(2) + /* The exit instruction should be reachable from two states, + * use two matches and "processed .. insns" to ensure this. + */ +-__msg("13: (95) exit") +-__msg("13: (95) exit") +-__msg("processed 18 insns") ++__msg("15: (95) exit") ++__msg("15: (95) exit") ++__msg("processed 20 insns") + __flag(BPF_F_TEST_STATE_FREQ) + __naked void two_old_ids_one_cur_id(void) + { +@@ -762,9 +762,11 @@ __naked void two_old_ids_one_cur_id(void) + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r6 = r0;" ++ "r8 = r0;" + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r7 = r0;" ++ "r9 = r0;" + "r0 = 0;" + /* Maybe make r{6,7} IDs identical */ + "if r6 > r7 goto l0_%=;" +-- +2.53.0 + diff --git a/queue-6.18/bpf-return-vma-snapshot-from-task_vma-iterator.patch b/queue-6.18/bpf-return-vma-snapshot-from-task_vma-iterator.patch new file mode 100644 index 0000000000..d58782a579 --- /dev/null +++ b/queue-6.18/bpf-return-vma-snapshot-from-task_vma-iterator.patch @@ -0,0 +1,133 @@ +From 57dbddd7d4349d28968eb73218a564b882c42d17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:37 -0700 +Subject: bpf: return VMA snapshot from task_vma iterator + +From: Puranjay Mohan + +[ Upstream commit 4cbee026db54cad39c39db4d356100cb133412b3 ] + +Holding the per-VMA lock across the BPF program body creates a lock +ordering problem when helpers acquire locks that depend on mmap_lock: + + vm_lock -> i_rwsem -> mmap_lock -> vm_lock + +Snapshot the VMA under the per-VMA lock in _next() via memcpy(), then +drop the lock before returning. The BPF program accesses only the +snapshot. + +The verifier only trusts vm_mm and vm_file pointers (see +BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). vm_file is reference- +counted with get_file() under the lock and released via fput() on the +next iteration or in _destroy(). vm_mm is already correct because +lock_vma_under_rcu() verifies vma->vm_mm == mm. All other pointers +are left as-is by memcpy() since the verifier treats them as untrusted. + +Fixes: 4ac454682158 ("bpf: Introduce task_vma open-coded iterator kfuncs") +Signed-off-by: Puranjay Mohan +Acked-by: Andrii Nakryiko +Acked-by: Mykyta Yatsenko +Link: https://lore.kernel.org/r/20260408154539.3832150-4-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 42 ++++++++++++++++++++++++++++++------------ + 1 file changed, 30 insertions(+), 12 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index 87e87f18913d9..e791ae065c39b 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -808,7 +808,7 @@ static inline void bpf_iter_mmput_async(struct mm_struct *mm) + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +- struct vm_area_struct *locked_vma; ++ struct vm_area_struct snapshot; + u64 next_addr; + }; + +@@ -842,7 +842,7 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + + /* + * Reject irqs-disabled contexts including NMI. Operations used +- * by _next() and _destroy() (vma_end_read, bpf_iter_mmput_async) ++ * by _next() and _destroy() (vma_end_read, fput, bpf_iter_mmput_async) + * can take spinlocks with IRQs disabled (pi_lock, pool->lock). + * Running from NMI or from a tracepoint that fires with those + * locks held could deadlock. +@@ -885,7 +885,7 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + goto err_cleanup_iter; + } + +- kit->data->locked_vma = NULL; ++ kit->data->snapshot.vm_file = NULL; + kit->data->next_addr = addr; + return 0; + +@@ -947,26 +947,45 @@ bpf_iter_task_vma_find_next(struct bpf_iter_task_vma_kern_data *data) + return vma; + } + ++static void bpf_iter_task_vma_snapshot_reset(struct vm_area_struct *snap) ++{ ++ if (snap->vm_file) { ++ fput(snap->vm_file); ++ snap->vm_file = NULL; ++ } ++} ++ + __bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; +- struct vm_area_struct *vma; ++ struct vm_area_struct *snap, *vma; + + if (!kit->data) /* bpf_iter_task_vma_new failed */ + return NULL; + +- if (kit->data->locked_vma) { +- vma_end_read(kit->data->locked_vma); +- kit->data->locked_vma = NULL; +- } ++ snap = &kit->data->snapshot; ++ ++ bpf_iter_task_vma_snapshot_reset(snap); + + vma = bpf_iter_task_vma_find_next(kit->data); + if (!vma) + return NULL; + +- kit->data->locked_vma = vma; ++ memcpy(snap, vma, sizeof(*snap)); ++ ++ /* ++ * The verifier only trusts vm_mm and vm_file (see ++ * BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). Take a reference ++ * on vm_file; vm_mm is already correct because lock_vma_under_rcu() ++ * verifies vma->vm_mm == mm. All other pointers are untrusted by ++ * the verifier and left as-is. ++ */ ++ if (snap->vm_file) ++ get_file(snap->vm_file); ++ + kit->data->next_addr = vma->vm_end; +- return vma; ++ vma_end_read(vma); ++ return snap; + } + + __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) +@@ -974,8 +993,7 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + struct bpf_iter_task_vma_kern *kit = (void *)it; + + if (kit->data) { +- if (kit->data->locked_vma) +- vma_end_read(kit->data->locked_vma); ++ bpf_iter_task_vma_snapshot_reset(&kit->data->snapshot); + put_task_struct(kit->data->task); + bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); +-- +2.53.0 + diff --git a/queue-6.18/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch b/queue-6.18/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch new file mode 100644 index 0000000000..ab7a7be94b --- /dev/null +++ b/queue-6.18/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch @@ -0,0 +1,82 @@ +From 103258828c5d98b01da44955445561d03795c2b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:11:09 -0700 +Subject: bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator + finalize + +From: Puranjay Mohan + +[ Upstream commit 46ee1342b887c9387a933397d846ff6c9584322c ] + +bpf_flush_icache() calls flush_icache_range() to clean the data cache +and invalidate the instruction cache for the JITed code region. However, +since commit 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the +BPF JIT"), this flush is redundant. + +bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX +region via bpf_arch_text_copy() -> patch_text_nosync(), and +patch_text_nosync() already calls flush_icache_range() on the written +range. The subsequent bpf_flush_icache() repeats the same cache +maintenance on an overlapping range. + +Remove the redundant bpf_flush_icache() call and its now-unused +definition. + +Fixes: 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT") +Acked-by: Song Liu +Signed-off-by: Puranjay Mohan +Reviewed-by: Pu Lehui +Tested-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260413191111.3426023-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/riscv/net/bpf_jit.h | 6 ------ + arch/riscv/net/bpf_jit_core.c | 7 ------- + 2 files changed, 13 deletions(-) + +diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h +index 632ced07bca44..da02717902442 100644 +--- a/arch/riscv/net/bpf_jit.h ++++ b/arch/riscv/net/bpf_jit.h +@@ -11,7 +11,6 @@ + + #include + #include +-#include + + /* verify runtime detection extension status */ + #define rv_ext_enabled(ext) \ +@@ -105,11 +104,6 @@ static inline void bpf_fill_ill_insns(void *area, unsigned int size) + memset(area, 0, size); + } + +-static inline void bpf_flush_icache(void *start, void *end) +-{ +- flush_icache_range((unsigned long)start, (unsigned long)end); +-} +- + /* Emit a 4-byte riscv instruction. */ + static inline void emit(const u32 insn, struct rv_jit_context *ctx) + { +diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c +index f6ca5cfa6b2fd..191bf0e66c824 100644 +--- a/arch/riscv/net/bpf_jit_core.c ++++ b/arch/riscv/net/bpf_jit_core.c +@@ -183,13 +183,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + prog = orig_prog; + goto out_offset; + } +- /* +- * The instructions have now been copied to the ROX region from +- * where they will execute. +- * Write any modified data cache blocks out to memory and +- * invalidate the corresponding blocks in the instruction cache. +- */ +- bpf_flush_icache(jit_data->ro_header, ctx->ro_insns + ctx->ninsns); + for (i = 0; i < prog->len; i++) + ctx->offset[i] = ninsns_rvoff(ctx->offset[i]); + bpf_prog_fill_jited_linfo(prog, ctx->offset); +-- +2.53.0 + diff --git a/queue-6.18/bpf-sockmap-fix-af_unix-iter-deadlock.patch b/queue-6.18/bpf-sockmap-fix-af_unix-iter-deadlock.patch new file mode 100644 index 0000000000..147c72360c --- /dev/null +++ b/queue-6.18/bpf-sockmap-fix-af_unix-iter-deadlock.patch @@ -0,0 +1,101 @@ +From eb3bee5887af0efb431ed2f5c4caf660d6af4146 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:16 +0200 +Subject: bpf, sockmap: Fix af_unix iter deadlock + +From: Michal Luczaj + +[ Upstream commit 4d328dd695383224aa750ddee6b4ad40c0f8d205 ] + +bpf_iter_unix_seq_show() may deadlock when lock_sock_fast() takes the fast +path and the iter prog attempts to update a sockmap. Which ends up spinning +at sock_map_update_elem()'s bh_lock_sock(): + +WARNING: possible recursive locking detected +test_progs/1393 is trying to acquire lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: sock_map_update_elem+0xdb/0x1f0 + +but task is already holding lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + +other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(slock-AF_UNIX); + lock(slock-AF_UNIX); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + +4 locks held by test_progs/1393: + #0: ffff88814b59c790 (&p->lock){+.+.}-{4:4}, at: bpf_seq_read+0x59/0x10d0 + #1: ffff88811ec25fd8 (sk_lock-AF_UNIX){+.+.}-{0:0}, at: bpf_seq_read+0x42c/0x10d0 + #2: ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + #3: ffffffff85a6a7c0 (rcu_read_lock){....}-{1:3}, at: bpf_iter_run_prog+0x51d/0xb00 + +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_deadlock_bug.cold+0xc0/0xce + __lock_acquire+0x130f/0x2590 + lock_acquire+0x14e/0x2b0 + _raw_spin_lock+0x30/0x40 + sock_map_update_elem+0xdb/0x1f0 + bpf_prog_2d0075e5d9b721cd_dump_unix+0x55/0x4f4 + bpf_iter_run_prog+0x5b9/0xb00 + bpf_iter_unix_seq_show+0x1f7/0x2e0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-2-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index a09c732748945..cf022252d521c 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3773,15 +3773,14 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + struct bpf_prog *prog; + struct sock *sk = v; + uid_t uid; +- bool slow; + int ret; + + if (v == SEQ_START_TOKEN) + return 0; + +- slow = lock_sock_fast(sk); ++ lock_sock(sk); + +- if (unlikely(sk_unhashed(sk))) { ++ if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; + goto unlock; + } +@@ -3791,7 +3790,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: +- unlock_sock_fast(sk, slow); ++ release_sock(sk); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch b/queue-6.18/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch new file mode 100644 index 0000000000..ec4955c991 --- /dev/null +++ b/queue-6.18/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch @@ -0,0 +1,200 @@ +From 38560c5df3a40caee941a5c94565554c0a55a049 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:18 +0200 +Subject: bpf, sockmap: Fix af_unix null-ptr-deref in proto update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Luczaj + +[ Upstream commit dca38b7734d2ea00af4818ff3ae836fab33d5d5a ] + +unix_stream_connect() sets sk_state (`WRITE_ONCE(sk->sk_state, +TCP_ESTABLISHED)`) _before_ it assigns a peer (`unix_peer(sk) = newsk`). +sk_state == TCP_ESTABLISHED makes sock_map_sk_state_allowed() believe that +socket is properly set up, which would include having a defined peer. IOW, +there's a window when unix_stream_bpf_update_proto() can be called on +socket which still has unix_peer(sk) == NULL. + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) +sock_map_sk_state_allowed(sk) +... +sk_pair = unix_peer(sk) +sock_hold(sk_pair) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + +BUG: kernel NULL pointer dereference, address: 0000000000000080 +RIP: 0010:unix_stream_bpf_update_proto+0xa0/0x1b0 +Call Trace: + sock_map_link+0x564/0x8b0 + sock_map_update_common+0x6e/0x340 + sock_map_update_elem_sys+0x17d/0x240 + __sys_bpf+0x26db/0x3250 + __x64_sys_bpf+0x21/0x30 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Initial idea was to move peer assignment _before_ the sk_state update[1], +but that involved an additional memory barrier, and changing the hot path +was rejected. +Then a NULL check during proto update in unix_stream_bpf_update_proto() was +considered[2], but the follow-up discussion[3] focused on the root cause, +i.e. sockmap update taking a wrong lock. Or, more specifically, missing +unix_state_lock()[4]. +In the end it was concluded that teaching sockmap about the af_unix locking +would be unnecessarily complex[5]. +Complexity aside, since BPF_PROG_TYPE_SCHED_CLS and BPF_PROG_TYPE_SCHED_ACT +are allowed to update sockmaps, sock_map_update_elem() taking the unix +lock, as it is currently implemented in unix_state_lock(): +spin_lock(&unix_sk(s)->lock), would be problematic. unix_state_lock() taken +in a process context, followed by a softirq-context TC BPF program +attempting to take the same spinlock -- deadlock[6]. +This way we circled back to the peer check idea[2]. + +[1]: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +[2]: https://lore.kernel.org/netdev/20240610174906.32921-1-kuniyu@amazon.com/ +[3]: https://lore.kernel.org/netdev/7603c0e6-cd5b-452b-b710-73b64bd9de26@linux.dev/ +[4]: https://lore.kernel.org/netdev/CAAVpQUA+8GL_j63CaKb8hbxoL21izD58yr1NvhOhU=j+35+3og@mail.gmail.com/ +[5]: https://lore.kernel.org/bpf/CAAVpQUAHijOMext28Gi10dSLuMzGYh+jK61Ujn+fZ-wvcODR2A@mail.gmail.com/ +[6]: https://lore.kernel.org/bpf/dd043c69-4d03-46fe-8325-8f97101435cf@linux.dev/ + +Summary of scenarios where af_unix/stream connect() may race a sockmap +update: + +1. connect() vs. bpf(BPF_MAP_UPDATE_ELEM), i.e. sock_map_update_elem_sys() + + Implemented NULL check is sufficient. Once assigned, socket peer won't + be released until socket fd is released. And that's not an issue because + sock_map_update_elem_sys() bumps fd refcnf. + +2. connect() vs BPF program doing update + + Update restricted per verifier.c:may_update_sockmap() to + + BPF_PROG_TYPE_TRACING/BPF_TRACE_ITER + BPF_PROG_TYPE_SOCK_OPS (bpf_sock_map_update() only) + BPF_PROG_TYPE_SOCKET_FILTER + BPF_PROG_TYPE_SCHED_CLS + BPF_PROG_TYPE_SCHED_ACT + BPF_PROG_TYPE_XDP + BPF_PROG_TYPE_SK_REUSEPORT + BPF_PROG_TYPE_FLOW_DISSECTOR + BPF_PROG_TYPE_SK_LOOKUP + + Plus one more race to consider: + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) + sock_map_sk_state_allowed(sk) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + sk_pair = unix_peer(sk) + if (unlikely(!sk_pair)) + return -EINVAL; + + CPU1 close + ---------- + + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) + // use after free? + sock_hold(sk_pair) + + 2.1 BPF program invoking helper function bpf_sock_map_update() -> + BPF_CALL_4(bpf_sock_map_update(), ...) + + Helper limited to BPF_PROG_TYPE_SOCK_OPS. Nevertheless, a unix sock + might be accessible via bpf_map_lookup_elem(). Which implies sk + already having psock, which in turn implies sk already having + sk_pair. Since sk_psock_destroy() is queued as RCU work, sk_pair + won't go away while BPF executes the update. + + 2.2 BPF program invoking helper function bpf_map_update_elem() -> + sock_map_update_elem() + + 2.2.1 Unix sock accessible to BPF prog only via sockmap lookup in + BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_SK_REUSEPORT, BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_SK_LOOKUP. + + Pretty much the same as case 2.1. + + 2.2.2 Unix sock accessible to BPF program directly: + BPF_PROG_TYPE_TRACING, narrowed down to BPF_TRACE_ITER. + + Sockmap iterator (sock_map_seq_ops) is safe: unix sock + residing in a sockmap means that the sock already went through + the proto update step. + + Unix sock iterator (bpf_iter_unix_seq_ops), on the other hand, + gives access to socks that may still be unconnected. Which + means iterator prog can race sockmap/proto update against + connect(). + + BUG: KASAN: null-ptr-deref in unix_stream_bpf_update_proto+0x253/0x4d0 + Write of size 4 at addr 0000000000000080 by task test_progs/3140 + Call Trace: + dump_stack_lvl+0x5d/0x80 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x253/0x4d0 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + While the introduced NULL check prevents null-ptr-deref in the + BPF program path as well, it is insufficient to guard against + a poorly timed close() leading to a use-after-free. This will + be addressed in a subsequent patch. + +Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()") +Closes: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +Reported-by: Michal Luczaj +Reported-by: 钱一铭 +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-4-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/unix_bpf.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c +index e0d30d6d22acb..57f3124c9d8db 100644 +--- a/net/unix/unix_bpf.c ++++ b/net/unix/unix_bpf.c +@@ -185,6 +185,9 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r + */ + if (!psock->sk_pair) { + sk_pair = unix_peer(sk); ++ if (unlikely(!sk_pair)) ++ return -EINVAL; ++ + sock_hold(sk_pair); + psock->sk_pair = sk_pair; + } +-- +2.53.0 + diff --git a/queue-6.18/bpf-sockmap-take-state-lock-for-af_unix-iter.patch b/queue-6.18/bpf-sockmap-take-state-lock-for-af_unix-iter.patch new file mode 100644 index 0000000000..aa42d38451 --- /dev/null +++ b/queue-6.18/bpf-sockmap-take-state-lock-for-af_unix-iter.patch @@ -0,0 +1,115 @@ +From ec9c4c95572ea32bbacd296115a827b19a43172a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:19 +0200 +Subject: bpf, sockmap: Take state lock for af_unix iter + +From: Michal Luczaj + +[ Upstream commit 64c2f93fc3254d3bf5de4445fb732ee5c451edb6 ] + +When a BPF iterator program updates a sockmap, there is a race condition in +unix_stream_bpf_update_proto() where the `peer` pointer can become stale[1] +during a state transition TCP_ESTABLISHED -> TCP_CLOSE. + + CPU0 bpf CPU1 close + -------- ---------- +// unix_stream_bpf_update_proto() +sk_pair = unix_peer(sk) +if (unlikely(!sk_pair)) + return -EINVAL; + // unix_release_sock() + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) +sock_hold(sk_pair) // UaF + +More practically, this fix guarantees that the iterator program is +consistently provided with a unix socket that remains stable during +iterator execution. + +[1]: +BUG: KASAN: slab-use-after-free in unix_stream_bpf_update_proto+0x155/0x490 +Write of size 4 at addr ffff8881178c9a00 by task test_progs/2231 +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x170/0x4f3 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x155/0x490 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Allocated by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + __kasan_slab_alloc+0x63/0x80 + kmem_cache_alloc_noprof+0x1d5/0x680 + sk_prot_alloc+0x59/0x210 + sk_alloc+0x34/0x470 + unix_create1+0x86/0x8a0 + unix_stream_connect+0x318/0x15b0 + __sys_connect+0xfd/0x130 + __x64_sys_connect+0x72/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Freed by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + kasan_save_free_info+0x3b/0x70 + __kasan_slab_free+0x47/0x70 + kmem_cache_free+0x11c/0x590 + __sk_destruct+0x432/0x6e0 + unix_release_sock+0x9b3/0xf60 + unix_release+0x8a/0xf0 + __sock_release+0xb0/0x270 + sock_close+0x18/0x20 + __fput+0x36e/0xac0 + fput_close_sync+0xe5/0x1a0 + __x64_sys_close+0x7d/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-5-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index cf022252d521c..33ed8ecb556dd 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3779,6 +3779,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + return 0; + + lock_sock(sk); ++ unix_state_lock(sk); + + if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; +@@ -3790,6 +3791,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: ++ unix_state_unlock(sk); + release_sock(sk); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.18/bpf-support-negative-offsets-bpf_sub-and-alu32-for-l.patch b/queue-6.18/bpf-support-negative-offsets-bpf_sub-and-alu32-for-l.patch new file mode 100644 index 0000000000..108b02c436 --- /dev/null +++ b/queue-6.18/bpf-support-negative-offsets-bpf_sub-and-alu32-for-l.patch @@ -0,0 +1,170 @@ +From 193b76cdac20816f3a14bd0d3b60ced5429d5d6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 07:17:37 -0800 +Subject: bpf: Support negative offsets, BPF_SUB, and alu32 for linked register + tracking + +From: Puranjay Mohan + +[ Upstream commit 7a433e519364c3c19643e5c857f4fbfaebec441c ] + +Previously, the verifier only tracked positive constant deltas between +linked registers using BPF_ADD. This limitation meant patterns like: + + r1 = r0; + r1 += -4; + if r1 s>= 0 goto l0_%=; // r1 >= 0 implies r0 >= 4 + // verifier couldn't propagate bounds back to r0 + if r0 != 0 goto l0_%=; + r0 /= 0; // Verifier thinks this is reachable + l0_%=: + +Similar limitation exists for 32-bit registers. + +With this change, the verifier can now track negative deltas in reg->off +enabling bound propagation for the above pattern. + +For alu32, we make sure the destination register has the upper 32 bits +as 0s before creating the link. BPF_ADD_CONST is split into +BPF_ADD_CONST64 and BPF_ADD_CONST32, the latter is used in case of alu32 +and sync_linked_regs uses this to zext the result if known_reg has this +flag. + +Signed-off-by: Puranjay Mohan +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260204151741.2678118-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Stable-dep-of: d7f14173c0d5 ("bpf: Fix linked reg delta tracking when src_reg == dst_reg") +Signed-off-by: Sasha Levin +--- + include/linux/bpf_verifier.h | 6 ++- + kernel/bpf/verifier.c | 50 +++++++++++++++---- + .../selftests/bpf/progs/verifier_bounds.c | 2 +- + 3 files changed, 45 insertions(+), 13 deletions(-) + +diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h +index 4c497e839526a..4867b0e8b5d9d 100644 +--- a/include/linux/bpf_verifier.h ++++ b/include/linux/bpf_verifier.h +@@ -147,8 +147,12 @@ struct bpf_reg_state { + * registers. Example: + * r1 = r2; both will have r1->id == r2->id == N + * r1 += 10; r1->id == N | BPF_ADD_CONST and r1->off == 10 ++ * r3 = r2; both will have r3->id == r2->id == N ++ * w3 += 10; r3->id == N | BPF_ADD_CONST32 and r3->off == 10 + */ +-#define BPF_ADD_CONST (1U << 31) ++#define BPF_ADD_CONST64 (1U << 31) ++#define BPF_ADD_CONST32 (1U << 30) ++#define BPF_ADD_CONST (BPF_ADD_CONST64 | BPF_ADD_CONST32) + u32 id; + /* PTR_TO_SOCKET and PTR_TO_TCP_SOCK could be a ptr returned + * from a pointer-cast helper, bpf_sk_fullsock() and +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 0d1ec2b5d469a..6cf8b13db301b 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -15787,6 +15787,13 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + verbose(env, "verifier internal error: no src_reg\n"); + return -EFAULT; + } ++ /* ++ * For alu32 linked register tracking, we need to check dst_reg's ++ * umax_value before the ALU operation. After adjust_scalar_min_max_vals(), ++ * alu32 ops will have zero-extended the result, making umax_value <= U32_MAX. ++ */ ++ u64 dst_umax = dst_reg->umax_value; ++ + err = adjust_scalar_min_max_vals(env, insn, dst_reg, *src_reg); + if (err) + return err; +@@ -15796,26 +15803,44 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + * r1 += 0x1 + * if r2 < 1000 goto ... + * use r1 in memory access +- * So for 64-bit alu remember constant delta between r2 and r1 and +- * update r1 after 'if' condition. ++ * So remember constant delta between r2 and r1 and update r1 after ++ * 'if' condition. + */ + if (env->bpf_capable && +- BPF_OP(insn->code) == BPF_ADD && !alu32 && +- dst_reg->id && is_reg_const(src_reg, false)) { +- u64 val = reg_const_value(src_reg, false); ++ (BPF_OP(insn->code) == BPF_ADD || BPF_OP(insn->code) == BPF_SUB) && ++ dst_reg->id && is_reg_const(src_reg, alu32)) { ++ u64 val = reg_const_value(src_reg, alu32); ++ s32 off; ++ ++ if (!alu32 && ((s64)val < S32_MIN || (s64)val > S32_MAX)) ++ goto clear_id; ++ ++ if (alu32 && (dst_umax > U32_MAX)) ++ goto clear_id; + +- if ((dst_reg->id & BPF_ADD_CONST) || +- /* prevent overflow in sync_linked_regs() later */ +- val > (u32)S32_MAX) { ++ off = (s32)val; ++ ++ if (BPF_OP(insn->code) == BPF_SUB) { ++ /* Negating S32_MIN would overflow */ ++ if (off == S32_MIN) ++ goto clear_id; ++ off = -off; ++ } ++ ++ if (dst_reg->id & BPF_ADD_CONST) { + /* + * If the register already went through rX += val + * we cannot accumulate another val into rx->off. + */ ++clear_id: + dst_reg->off = 0; + dst_reg->id = 0; + } else { +- dst_reg->id |= BPF_ADD_CONST; +- dst_reg->off = val; ++ if (alu32) ++ dst_reg->id |= BPF_ADD_CONST32; ++ else ++ dst_reg->id |= BPF_ADD_CONST64; ++ dst_reg->off = off; + } + } else { + /* +@@ -16888,7 +16913,7 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s + u32 saved_id = reg->id; + + fake_reg.type = SCALAR_VALUE; +- __mark_reg_known(&fake_reg, (s32)reg->off - (s32)known_reg->off); ++ __mark_reg_known(&fake_reg, (s64)reg->off - (s64)known_reg->off); + + /* reg = known_reg; reg += delta */ + copy_register_state(reg, known_reg); +@@ -16903,6 +16928,9 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s + scalar32_min_max_add(reg, &fake_reg); + scalar_min_max_add(reg, &fake_reg); + reg->var_off = tnum_add(reg->var_off, fake_reg.var_off); ++ if (known_reg->id & BPF_ADD_CONST32) ++ zext_32_to_64(reg); ++ reg_bounds_sync(reg); + } + } + } +diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c +index e772ae430915f..ea5db79da40ef 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_bounds.c ++++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c +@@ -1477,7 +1477,7 @@ __naked void sub64_full_overflow(void) + SEC("socket") + __description("64-bit subtraction, partial overflow, result in unbounded reg") + __success __log_level(2) +-__msg("3: (1f) r3 -= r2 {{.*}} R3=scalar()") ++__msg("3: (1f) r3 -= r2 {{.*}} R3=scalar(id=1-1)") + __retval(0) + __naked void sub64_partial_overflow(void) + { +-- +2.53.0 + diff --git a/queue-6.18/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch b/queue-6.18/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch new file mode 100644 index 0000000000..9cc8269089 --- /dev/null +++ b/queue-6.18/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch @@ -0,0 +1,199 @@ +From cce970dec7f5baa08532338bc34ee87f1773220c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:36 -0700 +Subject: bpf: switch task_vma iterator from mmap_lock to per-VMA locks + +From: Puranjay Mohan + +[ Upstream commit bee9ef4a40a277bf401be43d39ba7f7f063cf39c ] + +The open-coded task_vma iterator holds mmap_lock for the entire duration +of iteration, increasing contention on this highly contended lock. + +Switch to per-VMA locking. Find the next VMA via an RCU-protected maple +tree walk and lock it with lock_vma_under_rcu(). lock_next_vma() is not +used because its fallback takes mmap_read_lock(), and the iterator must +work in non-sleepable contexts. + +lock_vma_under_rcu() is a point lookup (mas_walk) that finds the VMA +containing a given address but cannot iterate across gaps. An +RCU-protected vma_next() walk (mas_find) first locates the next VMA's +vm_start to pass to lock_vma_under_rcu(). + +Between the RCU walk and the lock, the VMA may be removed, shrunk, or +write-locked. On failure, advance past it using vm_end from the RCU +walk. Because the VMA slab is SLAB_TYPESAFE_BY_RCU, vm_end may be +stale; fall back to PAGE_SIZE advancement when it does not make forward +progress. Concurrent VMA insertions at addresses already passed by the +iterator are not detected. + +CONFIG_PER_VMA_LOCK is required; return -EOPNOTSUPP without it. + +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260408154539.3832150-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Stable-dep-of: 4cbee026db54 ("bpf: return VMA snapshot from task_vma iterator") +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 91 +++++++++++++++++++++++++++++++++--------- + 1 file changed, 73 insertions(+), 18 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index c1f5fbe9dc2f3..87e87f18913d9 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include "mmap_unlock_work.h" + +@@ -807,8 +808,8 @@ static inline void bpf_iter_mmput_async(struct mm_struct *mm) + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +- struct mmap_unlock_irq_work *work; +- struct vma_iterator vmi; ++ struct vm_area_struct *locked_vma; ++ u64 next_addr; + }; + + struct bpf_iter_task_vma { +@@ -829,21 +830,19 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + struct task_struct *task, u64 addr) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; +- bool irq_work_busy = false; + int err; + + BUILD_BUG_ON(sizeof(struct bpf_iter_task_vma_kern) != sizeof(struct bpf_iter_task_vma)); + BUILD_BUG_ON(__alignof__(struct bpf_iter_task_vma_kern) != __alignof__(struct bpf_iter_task_vma)); + +- /* bpf_iter_mmput_async() needs mmput_async() which requires CONFIG_MMU */ +- if (!IS_ENABLED(CONFIG_MMU)) { ++ if (!IS_ENABLED(CONFIG_PER_VMA_LOCK)) { + kit->data = NULL; + return -EOPNOTSUPP; + } + + /* + * Reject irqs-disabled contexts including NMI. Operations used +- * by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) ++ * by _next() and _destroy() (vma_end_read, bpf_iter_mmput_async) + * can take spinlocks with IRQs disabled (pi_lock, pool->lock). + * Running from NMI or from a tracepoint that fires with those + * locks held could deadlock. +@@ -886,18 +885,10 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + goto err_cleanup_iter; + } + +- /* kit->data->work == NULL is valid after bpf_mmap_unlock_get_irq_work */ +- irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work); +- if (irq_work_busy || !mmap_read_trylock(kit->data->mm)) { +- err = -EBUSY; +- goto err_cleanup_mmget; +- } +- +- vma_iter_init(&kit->data->vmi, kit->data->mm, addr); ++ kit->data->locked_vma = NULL; ++ kit->data->next_addr = addr; + return 0; + +-err_cleanup_mmget: +- bpf_iter_mmput_async(kit->data->mm); + err_cleanup_iter: + put_task_struct(kit->data->task); + bpf_mem_free(&bpf_global_ma, kit->data); +@@ -906,13 +897,76 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + return err; + } + ++/* ++ * Find and lock the next VMA at or after data->next_addr. ++ * ++ * lock_vma_under_rcu() is a point lookup (mas_walk): it finds the VMA ++ * containing a given address but cannot iterate. An RCU-protected ++ * maple tree walk with vma_next() (mas_find) is needed first to locate ++ * the next VMA's vm_start across any gap. ++ * ++ * Between the RCU walk and the lock, the VMA may be removed, shrunk, ++ * or write-locked. On failure, advance past it using vm_end from the ++ * RCU walk. SLAB_TYPESAFE_BY_RCU can make vm_end stale, so fall back ++ * to PAGE_SIZE advancement to guarantee forward progress. ++ */ ++static struct vm_area_struct * ++bpf_iter_task_vma_find_next(struct bpf_iter_task_vma_kern_data *data) ++{ ++ struct vm_area_struct *vma; ++ struct vma_iterator vmi; ++ unsigned long start, end; ++ ++retry: ++ rcu_read_lock(); ++ vma_iter_init(&vmi, data->mm, data->next_addr); ++ vma = vma_next(&vmi); ++ if (!vma) { ++ rcu_read_unlock(); ++ return NULL; ++ } ++ start = vma->vm_start; ++ end = vma->vm_end; ++ rcu_read_unlock(); ++ ++ vma = lock_vma_under_rcu(data->mm, start); ++ if (!vma) { ++ if (end <= data->next_addr) ++ data->next_addr += PAGE_SIZE; ++ else ++ data->next_addr = end; ++ goto retry; ++ } ++ ++ if (unlikely(vma->vm_end <= data->next_addr)) { ++ data->next_addr += PAGE_SIZE; ++ vma_end_read(vma); ++ goto retry; ++ } ++ ++ return vma; ++} ++ + __bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; ++ struct vm_area_struct *vma; + + if (!kit->data) /* bpf_iter_task_vma_new failed */ + return NULL; +- return vma_next(&kit->data->vmi); ++ ++ if (kit->data->locked_vma) { ++ vma_end_read(kit->data->locked_vma); ++ kit->data->locked_vma = NULL; ++ } ++ ++ vma = bpf_iter_task_vma_find_next(kit->data); ++ if (!vma) ++ return NULL; ++ ++ kit->data->locked_vma = vma; ++ kit->data->next_addr = vma->vm_end; ++ return vma; + } + + __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) +@@ -920,7 +974,8 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + struct bpf_iter_task_vma_kern *kit = (void *)it; + + if (kit->data) { +- bpf_mmap_unlock_mm(kit->data->work, kit->data->mm); ++ if (kit->data->locked_vma) ++ vma_end_read(kit->data->locked_vma); + put_task_struct(kit->data->task); + bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); +-- +2.53.0 + diff --git a/queue-6.18/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch b/queue-6.18/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch new file mode 100644 index 0000000000..55e28b39a4 --- /dev/null +++ b/queue-6.18/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch @@ -0,0 +1,100 @@ +From 0709337a7350ac4b21b5450520ab7e8cffc209d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 17:44:28 +0800 +Subject: bpf: test_run: Fix the null pointer dereference issue in + bpf_lwt_xmit_push_encap + +From: Feng Yang + +[ Upstream commit 972787479ee73006fddb5e59ab5c8e733810ff42 ] + +The bpf_lwt_xmit_push_encap helper needs to access skb_dst(skb)->dev to +calculate the needed headroom: + + err = skb_cow_head(skb, + len + LL_RESERVED_SPACE(skb_dst(skb)->dev)); + +But skb->_skb_refdst may not be initialized when the skb is set up by +bpf_prog_test_run_skb function. Executing bpf_lwt_push_ip_encap function +in this scenario will trigger null pointer dereference, causing a kernel +crash as Yinhao reported: + +[ 105.186365] BUG: kernel NULL pointer dereference, address: 0000000000000000 +[ 105.186382] #PF: supervisor read access in kernel mode +[ 105.186388] #PF: error_code(0x0000) - not-present page +[ 105.186393] PGD 121d3d067 P4D 121d3d067 PUD 106c83067 PMD 0 +[ 105.186404] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 105.186412] CPU: 3 PID: 3250 Comm: poc Kdump: loaded Not tainted 6.19.0-rc5 #1 +[ 105.186423] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 105.186427] RIP: 0010:bpf_lwt_push_ip_encap+0x1eb/0x520 +[ 105.186443] Code: 0f 84 de 01 00 00 0f b7 4a 04 66 85 c9 0f 85 47 01 00 00 31 c0 5b 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8b 73 58 48 83 e6 fe <48> 8b 36 0f b7 be ec 00 00 00 0f b7 b6 e6 00 00 00 01 fe 83 e6 f0 +[ 105.186449] RSP: 0018:ffffbb0e0387bc50 EFLAGS: 00010246 +[ 105.186455] RAX: 000000000000004e RBX: ffff94c74e036500 RCX: ffff94c74874da00 +[ 105.186460] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff94c74e036500 +[ 105.186463] RBP: 0000000000000001 R08: 0000000000000002 R09: 0000000000000000 +[ 105.186467] R10: ffffbb0e0387bd50 R11: 0000000000000000 R12: ffffbb0e0387bc98 +[ 105.186471] R13: 0000000000000014 R14: 0000000000000000 R15: 0000000000000002 +[ 105.186484] FS: 00007f166aa4d680(0000) GS:ffff94c8b7780000(0000) knlGS:0000000000000000 +[ 105.186490] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 105.186494] CR2: 0000000000000000 CR3: 000000015eade001 CR4: 0000000000770ee0 +[ 105.186499] PKRU: 55555554 +[ 105.186502] Call Trace: +[ 105.186507] +[ 105.186513] bpf_lwt_xmit_push_encap+0x2b/0x40 +[ 105.186522] bpf_prog_a75eaad51e517912+0x41/0x49 +[ 105.186536] ? kvm_clock_get_cycles+0x18/0x30 +[ 105.186547] ? ktime_get+0x3c/0xa0 +[ 105.186554] bpf_test_run+0x195/0x320 +[ 105.186563] ? bpf_test_run+0x10f/0x320 +[ 105.186579] bpf_prog_test_run_skb+0x2f5/0x4f0 +[ 105.186590] __sys_bpf+0x69c/0xa40 +[ 105.186603] __x64_sys_bpf+0x1e/0x30 +[ 105.186611] do_syscall_64+0x59/0x110 +[ 105.186620] entry_SYSCALL_64_after_hwframe+0x76/0xe0 +[ 105.186649] RIP: 0033:0x7f166a97455d + +Temporarily add the setting of skb->_skb_refdst before bpf_test_run to resolve the issue. + +Fixes: 52f278774e79 ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap") +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Closes: https://groups.google.com/g/hust-os-kernel-patches/c/8-a0kPpBW2s +Signed-off-by: Yun Lu +Signed-off-by: Feng Yang +Signed-off-by: Martin KaFai Lau +Tested-by: syzbot@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260304094429.168521-2-yangfeng59949@163.com +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 6b04f47301c1e..65d7f8d51823e 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1093,6 +1093,21 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + skb->ip_summed = CHECKSUM_COMPLETE; + } + ++ if (prog->type == BPF_PROG_TYPE_LWT_XMIT) { ++ if (!ipv6_bpf_stub) { ++ pr_warn_once("Please test this program with the IPv6 module loaded\n"); ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ /* For CONFIG_IPV6=n, ipv6_bpf_stub is NULL which is ++ * handled by the above if statement. ++ */ ++ dst_hold(&net->ipv6.ip6_null_entry->dst); ++ skb_dst_set(skb, &net->ipv6.ip6_null_entry->dst); ++#endif ++ } ++ + ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false); + if (ret) + goto out; +-- +2.53.0 + diff --git a/queue-6.18/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch b/queue-6.18/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch new file mode 100644 index 0000000000..1f915b31ed --- /dev/null +++ b/queue-6.18/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch @@ -0,0 +1,71 @@ +From 2779f62d9f2ce5a61eef8756b812a981c89d371e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 07:26:45 +0000 +Subject: bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path + +From: David Carlier + +[ Upstream commit 8ed82f807bb09d2c8455aaa665f2c6cb17bc6a19 ] + +The DEVMAP_HASH branch in dev_map_redirect_multi() uses +hlist_for_each_entry_safe() to iterate hash buckets, but this function +runs under RCU protection (called from xdp_do_generic_redirect_map() +in softirq context). Concurrent writers (__dev_map_hash_update_elem, +dev_map_hash_delete_elem) modify the list using RCU primitives +(hlist_add_head_rcu, hlist_del_rcu). + +hlist_for_each_entry_safe() performs plain pointer dereferences without +rcu_dereference(), missing the acquire barrier needed to pair with +writers' rcu_assign_pointer(). On weakly-ordered architectures (ARM64, +POWER), a reader can observe a partially-constructed node. It also +defeats CONFIG_PROVE_RCU lockdep validation and KCSAN data-race +detection. + +Replace with hlist_for_each_entry_rcu() using rcu_read_lock_bh_held() +as the lockdep condition, consistent with the rcu_dereference_check() +used in the DEVMAP (non-hash) branch of the same functions. Also fix +the same incorrect lockdep_is_held(&dtab->index_lock) condition in +dev_map_enqueue_multi(), where the lock is not held either. + +Fixes: e624d4ed4aa8 ("xdp: Extend xdp_redirect_map with broadcast support") +Signed-off-by: David Carlier +Signed-off-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260320072645.16731-1-devnexen@gmail.com +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 3d619d01088e3..cc0a43ebab6b9 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -665,7 +665,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_rcu(dst, head, index_hlist, +- lockdep_is_held(&dtab->index_lock)) { ++ rcu_read_lock_bh_held()) { + if (!is_valid_dst(dst, xdpf)) + continue; + +@@ -747,7 +747,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + struct bpf_dtab_netdev *dst, *last_dst = NULL; + int excluded_devices[1+MAX_NEST_DEV]; + struct hlist_head *head; +- struct hlist_node *next; + int num_excluded = 0; + unsigned int i; + int err; +@@ -787,7 +786,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + } else { /* BPF_MAP_TYPE_DEVMAP_HASH */ + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); +- hlist_for_each_entry_safe(dst, next, head, index_hlist) { ++ hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) { + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-6.18/bpf-validate-node_id-in-arena_alloc_pages.patch b/queue-6.18/bpf-validate-node_id-in-arena_alloc_pages.patch new file mode 100644 index 0000000000..26776c581c --- /dev/null +++ b/queue-6.18/bpf-validate-node_id-in-arena_alloc_pages.patch @@ -0,0 +1,43 @@ +From f3cc44daf5ddf2e3f5c1ac9be85cc08d14612016 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 08:21:33 -0700 +Subject: bpf: Validate node_id in arena_alloc_pages() + +From: Puranjay Mohan + +[ Upstream commit 2845989f2ebaf7848e4eccf9a779daf3156ea0a5 ] + +arena_alloc_pages() accepts a plain int node_id and forwards it through +the entire allocation chain without any bounds checking. + +Validate node_id before passing it down the allocation chain in +arena_alloc_pages(). + +Fixes: 317460317a02 ("bpf: Introduce bpf_arena.") +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417152135.1383754-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/arena.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c +index c67525847687f..dafa179da0c9c 100644 +--- a/kernel/bpf/arena.c ++++ b/kernel/bpf/arena.c +@@ -446,6 +446,10 @@ static long arena_alloc_pages(struct bpf_arena *arena, long uaddr, long page_cnt + u32 uaddr32; + int ret, i; + ++ if (node_id != NUMA_NO_NODE && ++ ((unsigned int)node_id >= nr_node_ids || !node_online(node_id))) ++ return 0; ++ + if (page_cnt > page_cnt_max) + return 0; + +-- +2.53.0 + diff --git a/queue-6.18/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-w.patch b/queue-6.18/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-w.patch new file mode 100644 index 0000000000..7a745de06a --- /dev/null +++ b/queue-6.18/btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-w.patch @@ -0,0 +1,62 @@ +From 7a7424b1ed77d7f059e2e7143d6cd918e690ce25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 07:45:37 -0400 +Subject: btrfs: fix btrfs_ioctl_space_info() slot_count TOCTOU which can lead + to info-leak + +From: Yochai Eisenrich + +[ Upstream commit 973e57c726c1f8e77259d1c8e519519f1e9aea77 ] + +btrfs_ioctl_space_info() has a TOCTOU race between two passes over the +block group RAID type lists. The first pass counts entries to determine +the allocation size, then the second pass fills the buffer. The +groups_sem rwlock is released between passes, allowing concurrent block +group removal to reduce the entry count. + +When the second pass fills fewer entries than the first pass counted, +copy_to_user() copies the full alloc_size bytes including trailing +uninitialized kmalloc bytes to userspace. + +Fix by copying only total_spaces entries (the actually-filled count from +the second pass) instead of alloc_size bytes, and switch to kzalloc so +any future copy size mismatch cannot leak heap data. + +Fixes: 7fde62bffb57 ("Btrfs: buffer results in the space_info ioctl") +CC: stable@vger.kernel.org # 3.0 +Signed-off-by: Yochai Eisenrich +Reviewed-by: David Sterba +Signed-off-by: David Sterba +[ adapted upstream's `return -EFAULT;` to stable's `ret = -EFAULT;` fall-through to existing `out:` cleanup label ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/ioctl.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index bfe253c2849a5..c0691e93e0a58 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -3025,7 +3025,7 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info, + return -ENOMEM; + + space_args.total_spaces = 0; +- dest = kmalloc(alloc_size, GFP_KERNEL); ++ dest = kzalloc(alloc_size, GFP_KERNEL); + if (!dest) + return -ENOMEM; + dest_orig = dest; +@@ -3081,7 +3081,8 @@ static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info, + user_dest = (struct btrfs_ioctl_space_info __user *) + (arg + sizeof(struct btrfs_ioctl_space_args)); + +- if (copy_to_user(user_dest, dest_orig, alloc_size)) ++ if (copy_to_user(user_dest, dest_orig, ++ space_args.total_spaces * sizeof(*dest_orig))) + ret = -EFAULT; + + kfree(dest_orig); +-- +2.53.0 + diff --git a/queue-6.18/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch b/queue-6.18/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch new file mode 100644 index 0000000000..b737861cca --- /dev/null +++ b/queue-6.18/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch @@ -0,0 +1,216 @@ +From fac5d594b1f007dcbf895a91c2fe206a8483f3be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 15:50:13 +0000 +Subject: btrfs: fix deadlock between reflink and transaction commit when using + flushoncommit + +From: Filipe Manana + +[ Upstream commit b48c980b6a7e409050bb3067165db31cc6205e3e ] + +When using the flushoncommit mount option, we can have a deadlock between +a transaction commit and a reflink operation that copied an inline extent +to an offset beyond the current i_size of the destination node. + +The deadlock happens like this: + +1) Task A clones an inline extent from inode X to an offset of inode Y + that is beyond Y's current i_size. This means we copied the inline + extent's data to a folio of inode Y that is beyond its EOF, using a + call to copy_inline_to_page(); + +2) Task B starts a transaction commit and calls + btrfs_start_delalloc_flush() to flush delalloc; + +3) The delalloc flushing sees the new dirty folio of inode Y and when it + attempts to flush it, it ends up at extent_writepage() and sees that + the offset of the folio is beyond the i_size of inode Y, so it attempts + to invalidate the folio by calling folio_invalidate(), which ends up at + btrfs' folio invalidate callback - btrfs_invalidate_folio(). There it + tries to lock the folio's range in inode Y's extent io tree, but it + blocks since it's currently locked by task A - during a reflink we lock + the inodes and the source and destination ranges after flushing all + delalloc and waiting for ordered extent completion - after that we + don't expect to have dirty folios in the ranges, the exception is if + we have to copy an inline extent's data (because the destination offset + is not zero); + +4) Task A then attempts to start a transaction to update the inode item, + and then it's blocked since the current transaction is in the + TRANS_STATE_COMMIT_START state. Therefore task A has to wait for the + current transaction to become unblocked (its state >= + TRANS_STATE_UNBLOCKED). + + So task A is waiting for the transaction commit done by task B, and + the later waiting on the extent lock of inode Y that is currently + held by task A. + +Syzbot recently reported this with the following stack traces: + + INFO: task kworker/u8:7:1053 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:kworker/u8:7 state:D stack:23520 pid:1053 tgid:1053 ppid:2 task_flags:0x4208060 flags:0x00080000 + Workqueue: writeback wb_workfn (flush-btrfs-46) + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wait_extent_bit fs/btrfs/extent-io-tree.c:811 [inline] + btrfs_lock_extent_bits+0x59c/0x700 fs/btrfs/extent-io-tree.c:1914 + btrfs_lock_extent fs/btrfs/extent-io-tree.h:152 [inline] + btrfs_invalidate_folio+0x43d/0xc40 fs/btrfs/inode.c:7704 + extent_writepage fs/btrfs/extent_io.c:1852 [inline] + extent_write_cache_pages fs/btrfs/extent_io.c:2580 [inline] + btrfs_writepages+0x12ff/0x2440 fs/btrfs/extent_io.c:2713 + do_writepages+0x32e/0x550 mm/page-writeback.c:2554 + __writeback_single_inode+0x133/0x11a0 fs/fs-writeback.c:1750 + writeback_sb_inodes+0x995/0x19d0 fs/fs-writeback.c:2042 + wb_writeback+0x456/0xb70 fs/fs-writeback.c:2227 + wb_do_writeback fs/fs-writeback.c:2374 [inline] + wb_workfn+0x41a/0xf60 fs/fs-writeback.c:2414 + process_one_work kernel/workqueue.c:3276 [inline] + process_scheduled_works+0xb6e/0x18c0 kernel/workqueue.c:3359 + worker_thread+0xa53/0xfc0 kernel/workqueue.c:3440 + kthread+0x388/0x470 kernel/kthread.c:436 + ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + + INFO: task syz.4.64:6910 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:syz.4.64 state:D stack:22752 pid:6910 tgid:6905 ppid:5944 task_flags:0x400140 flags:0x00080002 + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wait_current_trans+0x39f/0x590 fs/btrfs/transaction.c:535 + start_transaction+0x6a7/0x1650 fs/btrfs/transaction.c:705 + clone_copy_inline_extent fs/btrfs/reflink.c:299 [inline] + btrfs_clone+0x128a/0x24d0 fs/btrfs/reflink.c:529 + btrfs_clone_files+0x271/0x3f0 fs/btrfs/reflink.c:750 + btrfs_remap_file_range+0x76b/0x1320 fs/btrfs/reflink.c:903 + vfs_copy_file_range+0xda7/0x1390 fs/read_write.c:1600 + __do_sys_copy_file_range fs/read_write.c:1683 [inline] + __se_sys_copy_file_range+0x2fb/0x480 fs/read_write.c:1650 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7f5f73afc799 + RSP: 002b:00007f5f7315e028 EFLAGS: 00000246 ORIG_RAX: 0000000000000146 + RAX: ffffffffffffffda RBX: 00007f5f73d75fa0 RCX: 00007f5f73afc799 + RDX: 0000000000000005 RSI: 0000000000000000 RDI: 0000000000000005 + RBP: 00007f5f73b92c99 R08: 0000000000000863 R09: 0000000000000000 + R10: 00002000000000c0 R11: 0000000000000246 R12: 0000000000000000 + R13: 00007f5f73d76038 R14: 00007f5f73d75fa0 R15: 00007fff138a5068 + + INFO: task syz.4.64:6975 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:syz.4.64 state:D stack:24736 pid:6975 tgid:6905 ppid:5944 task_flags:0x400040 flags:0x00080002 + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wb_wait_for_completion+0x3e8/0x790 fs/fs-writeback.c:227 + __writeback_inodes_sb_nr+0x24c/0x2d0 fs/fs-writeback.c:2838 + try_to_writeback_inodes_sb+0x9a/0xc0 fs/fs-writeback.c:2886 + btrfs_start_delalloc_flush fs/btrfs/transaction.c:2175 [inline] + btrfs_commit_transaction+0x82e/0x31a0 fs/btrfs/transaction.c:2364 + btrfs_ioctl+0xca7/0xd00 fs/btrfs/ioctl.c:5206 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7f5f73afc799 + RSP: 002b:00007f5f7313d028 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 + RAX: ffffffffffffffda RBX: 00007f5f73d76090 RCX: 00007f5f73afc799 + RDX: 0000000000000000 RSI: 0000000000009408 RDI: 0000000000000004 + RBP: 00007f5f73b92c99 R08: 0000000000000000 R09: 0000000000000000 + R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 + R13: 00007f5f73d76128 R14: 00007f5f73d76090 R15: 00007fff138a5068 + + +Fix this by updating the i_size of the destination inode of a reflink +operation after we copy an inline extent's data to an offset beyond the +i_size and before attempting to start a transaction to update the inode's +item. + +Reported-by: syzbot+63056bf627663701bbbf@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-btrfs/69bba3fe.050a0220.227207.002f.GAE@google.com/ +Fixes: 05a5a7621ce6 ("Btrfs: implement full reflink support for inline extents") +Reviewed-by: Boris Burkov +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/reflink.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c +index 5465a5eae9b2d..614e884c2a9bc 100644 +--- a/fs/btrfs/reflink.c ++++ b/fs/btrfs/reflink.c +@@ -321,6 +321,51 @@ static int clone_copy_inline_extent(struct btrfs_inode *inode, + + ret = copy_inline_to_page(inode, new_key->offset, + inline_data, size, datal, comp_type); ++ ++ /* ++ * If we copied the inline extent data to a page/folio beyond the i_size ++ * of the destination inode, then we need to increase the i_size before ++ * we start a transaction to update the inode item. This is to prevent a ++ * deadlock when the flushoncommit mount option is used, which happens ++ * like this: ++ * ++ * 1) Task A clones an inline extent from inode X to an offset of inode ++ * Y that is beyond Y's current i_size. This means we copied the ++ * inline extent's data to a folio of inode Y that is beyond its EOF, ++ * using the call above to copy_inline_to_page(); ++ * ++ * 2) Task B starts a transaction commit and calls ++ * btrfs_start_delalloc_flush() to flush delalloc; ++ * ++ * 3) The delalloc flushing sees the new dirty folio of inode Y and when ++ * it attempts to flush it, it ends up at extent_writepage() and sees ++ * that the offset of the folio is beyond the i_size of inode Y, so ++ * it attempts to invalidate the folio by calling folio_invalidate(), ++ * which ends up at btrfs' folio invalidate callback - ++ * btrfs_invalidate_folio(). There it tries to lock the folio's range ++ * in inode Y's extent io tree, but it blocks since it's currently ++ * locked by task A - during reflink we lock the inodes and the ++ * source and destination ranges after flushing all delalloc and ++ * waiting for ordered extent completion - after that we don't expect ++ * to have dirty folios in the ranges, the exception is if we have to ++ * copy an inline extent's data (because the destination offset is ++ * not zero); ++ * ++ * 4) Task A then does the 'goto out' below and attempts to start a ++ * transaction to update the inode item, and then it's blocked since ++ * the current transaction is in the TRANS_STATE_COMMIT_START state. ++ * Therefore task A has to wait for the current transaction to become ++ * unblocked (its state >= TRANS_STATE_UNBLOCKED). ++ * ++ * This leads to a deadlock - the task committing the transaction ++ * waiting for the delalloc flushing which is blocked during folio ++ * invalidation on the inode's extent lock and the reflink task waiting ++ * for the current transaction to be unblocked so that it can start a ++ * a new one to update the inode item (while holding the extent lock). ++ */ ++ if (ret == 0 && new_key->offset + datal > i_size_read(&inode->vfs_inode)) ++ i_size_write(&inode->vfs_inode, new_key->offset + datal); ++ + goto out; + } + +-- +2.53.0 + diff --git a/queue-6.18/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch b/queue-6.18/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch new file mode 100644 index 0000000000..0c793d166a --- /dev/null +++ b/queue-6.18/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch @@ -0,0 +1,48 @@ +From 904dee89872be4290f15ca8adc3f2f21d3837fee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:15:23 +0100 +Subject: btrfs: fix double-decrement of bytes_may_use in + submit_one_async_extent() + +From: Mark Harmstone + +[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ] + +submit_one_async_extent() calls btrfs_reserve_extent(), which decrements +bytes_may_use. If the call btrfs_create_io_em() fails, we jump to +out_free_reserve, which calls extent_clear_unlock_delalloc(). + +Because we're specifying EXTENT_DO_ACCOUNTING, i.e. +EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases +bytes_may_use again. This can lead to problems later on, as an initial +write can fail only for the writeback to silently ENOSPC. + +Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. +This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved +extents in cow_one_range()"), which is the same fix in cow_one_range(). + +Fixes: 151a41bc46df ("Btrfs: fix what bits we clear when erroring out from delalloc") +Reviewed-by: Qu Wenruo +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index feaa6de8a90f2..5b99f2941f577 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1208,7 +1208,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk, + NULL, &cached, + EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | +- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, ++ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, + PAGE_UNLOCK | PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK); + free_async_extent_pages(async_extent); +-- +2.53.0 + diff --git a/queue-6.18/btrfs-fix-double-free-in-create_space_info_sub_group.patch b/queue-6.18/btrfs-fix-double-free-in-create_space_info_sub_group.patch new file mode 100644 index 0000000000..5bbf66f486 --- /dev/null +++ b/queue-6.18/btrfs-fix-double-free-in-create_space_info_sub_group.patch @@ -0,0 +1,60 @@ +From 8a2c3a8be3ca070ce716e65422441c6b33f39af2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 08:06:15 -0400 +Subject: btrfs: fix double free in create_space_info_sub_group() error path + +From: Guangshuo Li + +[ Upstream commit a7449edf96143f192606ec8647e3167e1ecbd728 ] + +When kobject_init_and_add() fails, the call chain is: + +create_space_info_sub_group() +-> btrfs_sysfs_add_space_info_type() +-> kobject_init_and_add() +-> failure +-> kobject_put(&sub_group->kobj) +-> space_info_release() +-> kfree(sub_group) + +Then control returns to create_space_info_sub_group(), where: + +btrfs_sysfs_add_space_info_type() returns error +-> kfree(sub_group) + +Thus, sub_group is freed twice. + +Keep parent->sub_group[index] = NULL for the failure path, but after +btrfs_sysfs_add_space_info_type() has called kobject_put(), let the +kobject release callback handle the cleanup. + +Fixes: f92ee31e031c ("btrfs: introduce btrfs_space_info sub-group") +CC: stable@vger.kernel.org # 6.18+ +Reviewed-by: Qu Wenruo +Signed-off-by: Guangshuo Li +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/space-info.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index c4a50550672da..b3ff2e1da89ba 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -276,10 +276,8 @@ static int create_space_info_sub_group(struct btrfs_space_info *parent, u64 flag + sub_group->subgroup_id = id; + + ret = btrfs_sysfs_add_space_info_type(sub_group); +- if (ret) { +- kfree(sub_group); ++ if (ret) + parent->sub_group[index] = NULL; +- } + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_s.patch b/queue-6.18/btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_s.patch new file mode 100644 index 0000000000..c82a8ada64 --- /dev/null +++ b/queue-6.18/btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_s.patch @@ -0,0 +1,84 @@ +From 88c59e30f1f6e1dad7d804f603e3dabe039dc63b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 08:06:14 -0400 +Subject: btrfs: remove fs_info argument from btrfs_sysfs_add_space_info_type() + +From: Filipe Manana + +[ Upstream commit 771af6ff72e0ed0eb8bf97e5ae4fa5094e0c5d1d ] + +We don't need it since we can grab fs_info from the given space_info. +So remove the fs_info argument. + +Reviewed-by: Johannes Thumshirn +Signed-off-by: Filipe Manana +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Stable-dep-of: a7449edf9614 ("btrfs: fix double free in create_space_info_sub_group() error path") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/space-info.c | 4 ++-- + fs/btrfs/sysfs.c | 5 ++--- + fs/btrfs/sysfs.h | 3 +-- + 3 files changed, 5 insertions(+), 7 deletions(-) + +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index a815308e2db91..c4a50550672da 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -275,7 +275,7 @@ static int create_space_info_sub_group(struct btrfs_space_info *parent, u64 flag + sub_group->parent = parent; + sub_group->subgroup_id = id; + +- ret = btrfs_sysfs_add_space_info_type(fs_info, sub_group); ++ ret = btrfs_sysfs_add_space_info_type(sub_group); + if (ret) { + kfree(sub_group); + parent->sub_group[index] = NULL; +@@ -309,7 +309,7 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags) + goto out_free; + } + +- ret = btrfs_sysfs_add_space_info_type(info, space_info); ++ ret = btrfs_sysfs_add_space_info_type(space_info); + if (ret) + return ret; + +diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c +index 81f52c1f55ce5..d66681ce2b3da 100644 +--- a/fs/btrfs/sysfs.c ++++ b/fs/btrfs/sysfs.c +@@ -1981,13 +1981,12 @@ static const char *alloc_name(struct btrfs_space_info *space_info) + * Create a sysfs entry for a space info type at path + * /sys/fs/btrfs/UUID/allocation/TYPE + */ +-int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, +- struct btrfs_space_info *space_info) ++int btrfs_sysfs_add_space_info_type(struct btrfs_space_info *space_info) + { + int ret; + + ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype, +- fs_info->space_info_kobj, "%s", ++ space_info->fs_info->space_info_kobj, "%s", + alloc_name(space_info)); + if (ret) { + kobject_put(&space_info->kobj); +diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h +index 0f94ae9232101..05498e5346c39 100644 +--- a/fs/btrfs/sysfs.h ++++ b/fs/btrfs/sysfs.h +@@ -37,8 +37,7 @@ void __cold btrfs_exit_sysfs(void); + int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info); + void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info); + void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache); +-int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, +- struct btrfs_space_info *space_info); ++int btrfs_sysfs_add_space_info_type(struct btrfs_space_info *space_info); + void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info); + void btrfs_sysfs_update_devid(struct btrfs_device *device); + +-- +2.53.0 + diff --git a/queue-6.18/bus-fsl-mc-use-generic-driver_override-infrastructur.patch b/queue-6.18/bus-fsl-mc-use-generic-driver_override-infrastructur.patch new file mode 100644 index 0000000000..0fa7572310 --- /dev/null +++ b/queue-6.18/bus-fsl-mc-use-generic-driver_override-infrastructur.patch @@ -0,0 +1,156 @@ +From 36c95f073354a82a8e5c0044142bc348f7c16280 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:06 +0100 +Subject: bus: fsl-mc: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit 6c8dfb0362732bf1e4829867a2a5239fedc592d0 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Tested-by: Ioana Ciornei +Acked-by: Ioana Ciornei +Acked-by: Christophe Leroy (CS GROUP) +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 1f86a00c1159 ("bus/fsl-mc: add support for 'driver_override' in the mc-bus") +Link: https://patch.msgid.link/20260324005919.2408620-3-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/bus/fsl-mc/fsl-mc-bus.c | 43 +++++-------------------------- + drivers/vfio/fsl-mc/vfio_fsl_mc.c | 4 +-- + include/linux/fsl/mc.h | 4 --- + 3 files changed, 8 insertions(+), 43 deletions(-) + +diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c +index eb7b6c0ba9e7c..996379ace3764 100644 +--- a/drivers/bus/fsl-mc/fsl-mc-bus.c ++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c +@@ -86,12 +86,16 @@ static int fsl_mc_bus_match(struct device *dev, const struct device_driver *drv) + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); + const struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); + bool found = false; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (mc_dev->driver_override) { +- found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); ++ ret = device_match_driver_override(dev, drv); ++ if (ret > 0) { ++ found = true; + goto out; + } ++ if (ret == 0) ++ goto out; + + if (!mc_drv->match_id_table) + goto out; +@@ -181,39 +185,8 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + } + static DEVICE_ATTR_RO(modalias); + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- int ret; +- +- if (WARN_ON(dev->bus != &fsl_mc_bus_type)) +- return -EINVAL; +- +- ret = driver_set_override(dev, &mc_dev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", mc_dev->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *fsl_mc_dev_attrs[] = { + &dev_attr_modalias.attr, +- &dev_attr_driver_override.attr, + NULL, + }; + +@@ -316,6 +289,7 @@ ATTRIBUTE_GROUPS(fsl_mc_bus); + + const struct bus_type fsl_mc_bus_type = { + .name = "fsl-mc", ++ .driver_override = true, + .match = fsl_mc_bus_match, + .uevent = fsl_mc_bus_uevent, + .dma_configure = fsl_mc_dma_configure, +@@ -925,9 +899,6 @@ static struct notifier_block fsl_mc_nb; + */ + void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) + { +- kfree(mc_dev->driver_override); +- mc_dev->driver_override = NULL; +- + /* + * The device-specific remove callback will get invoked by device_del() + */ +diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c +index 76ccbab0e3d64..84cd0eb65c471 100644 +--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c ++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c +@@ -430,9 +430,7 @@ static int vfio_fsl_mc_bus_notifier(struct notifier_block *nb, + + if (action == BUS_NOTIFY_ADD_DEVICE && + vdev->mc_dev == mc_cont) { +- mc_dev->driver_override = kasprintf(GFP_KERNEL, "%s", +- vfio_fsl_mc_ops.name); +- if (!mc_dev->driver_override) ++ if (device_set_driver_override(dev, vfio_fsl_mc_ops.name)) + dev_warn(dev, "VFIO_FSL_MC: Setting driver override for device in dprc %s failed\n", + dev_name(&mc_cont->dev)); + else +diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h +index 897d6211c1635..1da63f2d70401 100644 +--- a/include/linux/fsl/mc.h ++++ b/include/linux/fsl/mc.h +@@ -178,9 +178,6 @@ struct fsl_mc_obj_desc { + * @regions: pointer to array of MMIO region entries + * @irqs: pointer to array of pointers to interrupts allocated to this device + * @resource: generic resource associated with this MC object device, if any. +- * @driver_override: driver name to force a match; do not set directly, +- * because core frees it; use driver_set_override() to +- * set or clear it. + * + * Generic device object for MC object devices that are "attached" to a + * MC bus. +@@ -214,7 +211,6 @@ struct fsl_mc_device { + struct fsl_mc_device_irq **irqs; + struct fsl_mc_resource *resource; + struct device_link *consumer_link; +- const char *driver_override; + }; + + #define to_fsl_mc_device(_dev) \ +-- +2.53.0 + diff --git a/queue-6.18/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch b/queue-6.18/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch new file mode 100644 index 0000000000..c0060f8e27 --- /dev/null +++ b/queue-6.18/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch @@ -0,0 +1,102 @@ +From 9711aa083ebd751e781541cda1ee0a812f6ea9eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 13:56:17 +0100 +Subject: bus: rifsc: fix RIF configuration check for peripherals + +From: Gatien Chevallier + +[ Upstream commit d5ce3b4e951bc41a6ce877c8500bb4fe42146669 ] + +Peripheral holding CID0 cannot be accessed, remove this completely +incorrect check. While there, fix and simplify the semaphore checking +that should be performed when the CID filtering is enabled. + +Fixes: a18208457253 ("bus: rifsc: introduce RIFSC firewall controller driver") +Signed-off-by: Gatien Chevallier +Link: https://lore.kernel.org/r/20260129-fix_cid_check_rifsc-v1-1-ef280ccf764d@foss.st.com +Signed-off-by: Alexandre Torgue +Signed-off-by: Sasha Levin +--- + drivers/bus/stm32_rifsc.c | 52 ++++++++++++++------------------------- + 1 file changed, 18 insertions(+), 34 deletions(-) + +diff --git a/drivers/bus/stm32_rifsc.c b/drivers/bus/stm32_rifsc.c +index 4cf1b60014b77..59872134c3224 100644 +--- a/drivers/bus/stm32_rifsc.c ++++ b/drivers/bus/stm32_rifsc.c +@@ -126,34 +126,6 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 + sec_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id); + cid_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * firewall_id); + +- /* First check conditions for semaphore mode, which doesn't take into account static CID. */ +- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) { +- if (cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT)) { +- /* Static CID is irrelevant if semaphore mode */ +- goto skip_cid_check; +- } else { +- dev_dbg(rifsc_controller->dev, +- "Invalid bus semaphore configuration: index %d\n", firewall_id); +- return -EACCES; +- } +- } +- +- /* +- * Skip CID check if CID filtering isn't enabled or filtering is enabled on CID0, which +- * corresponds to whatever CID. +- */ +- if (!(cid_reg_value & CIDCFGR_CFEN) || +- FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) == RIF_CID0) +- goto skip_cid_check; +- +- /* Coherency check with the CID configuration */ +- if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) { +- dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n", +- firewall_id); +- return -EACCES; +- } +- +-skip_cid_check: + /* Check security configuration */ + if (sec_reg_value & BIT(reg_offset)) { + dev_dbg(rifsc_controller->dev, +@@ -161,19 +133,31 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 + return -EACCES; + } + +- /* +- * If the peripheral is in semaphore mode, take the semaphore so that +- * the CID1 has the ownership. +- */ +- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) { ++ /* Skip CID check if CID filtering isn't enabled */ ++ if (!(cid_reg_value & CIDCFGR_CFEN)) ++ goto skip_cid_check; ++ ++ /* First check conditions for semaphore mode, which doesn't take into account static CID. */ ++ if (cid_reg_value & CIDCFGR_SEMEN) { ++ if (!(cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT))) { ++ dev_dbg(rifsc_controller->dev, ++ "Invalid bus semaphore configuration: index %d\n", firewall_id); ++ return -EACCES; ++ } ++ + rc = stm32_rif_acquire_semaphore(rifsc_controller, firewall_id); + if (rc) { +- dev_err(rifsc_controller->dev, ++ dev_dbg(rifsc_controller->dev, + "Couldn't acquire semaphore for peripheral: %d\n", firewall_id); + return rc; + } ++ } else if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) { ++ dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n", ++ firewall_id); ++ return -EACCES; + } + ++skip_cid_check: + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch b/queue-6.18/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch new file mode 100644 index 0000000000..ec452ff6d6 --- /dev/null +++ b/queue-6.18/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch @@ -0,0 +1,237 @@ +From 93c2cb24fa678fc42bdee578094003ba3f6769cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:01:39 +0100 +Subject: cdrom, scsi: sr: propagate read-only status to block layer via + set_disk_ro() + +From: Daan De Meyer + +[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ] + +The cdrom core never calls set_disk_ro() for a registered device, so +BLKROGET on a CD-ROM device always returns 0 (writable), even when the +drive has no write capabilities and writes will inevitably fail. This +causes problems for userspace that relies on BLKROGET to determine +whether a block device is read-only. For example, systemd's loop device +setup uses BLKROGET to decide whether to create a loop device with +LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the +loop device to the CD-ROM and fail with I/O errors. systemd-fsck +similarly checks BLKROGET to decide whether to run fsck in no-repair +mode (-n). + +The write-capability bits in cdi->mask come from two different sources: +CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE +SENSE capabilities page (page 0x2A) before register_cdrom() is called, +while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command +and were only probed by cdrom_open_write() at device open time. This +meant that any attempt to compute the writable state from the full +mask at probe time was incorrect, because the GET CONFIGURATION bits +were still unset (and cdi->mask is initialized such that capabilities +are assumed present). + +Fix this by factoring the GET CONFIGURATION probing out of +cdrom_open_write() into a new exported helper, +cdrom_probe_write_features(), and having sr call it from sr_probe() +right after get_capabilities() has populated the MODE SENSE bits. +register_cdrom() then calls set_disk_ro() based on the full +write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) +so the block layer reflects the drive's actual write support. The +feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with +RT=00) report drive-level capabilities that are persistent across +media, so a single probe before register_cdrom() is sufficient and the +redundant probe at open time is dropped. + +With set_disk_ro() now accurate, the long-vestigial cd->writeable flag +in sr can go: get_capabilities() used to set cd->writeable based on +the same four mask bits, but because CDC_MRW_W and CDC_RAM default to +"capability present" in cdi->mask and aren't touched by MODE SENSE, +the condition that gated cd->writeable was always true, making it +unconditionally 1. Replace the corresponding gate in sr_init_command() +with get_disk_ro(cd->disk), which turns a previously no-op check into +a real one and also catches kernel-internal bio writers that bypass +blkdev_write_iter()'s bdev_read_only() check. + +The sd driver (SCSI disks) does not have this problem because it +checks the MODE SENSE Write Protect bit and calls set_disk_ro() +accordingly. The sr driver cannot use the same approach because the +MMC specification does not define the WP bit in the MODE SENSE +device-specific parameter byte for CD-ROM devices. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Daan De Meyer +Reviewed-by: Phillip Potter +Reviewed-by: Martin K. Petersen +Signed-off-by: Phillip Potter +Link: https://patch.msgid.link/20260427210139.1400-2-phil@philpotter.co.uk +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- + drivers/scsi/sr.c | 11 ++----- + drivers/scsi/sr.h | 1 - + include/linux/cdrom.h | 1 + + 4 files changed, 51 insertions(+), 35 deletions(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index 31ba1f8c1f786..e30414f0d4560 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) + + WARN_ON(!cdo->generic_packet); + ++ /* ++ * Propagate the drive's write support to the block layer so BLKROGET ++ * reflects actual write capability. Drivers that use GET CONFIGURATION ++ * features (CDC_MRW_W, CDC_RAM) must have called ++ * cdrom_probe_write_features() before register_cdrom() so the mask is ++ * complete here. ++ */ ++ set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | ++ CDC_CD_RW)); ++ + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + mutex_lock(&cdrom_mutex); + list_add(&cdi->list, &cdrom_list); +@@ -742,6 +752,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) + return 0; + } + ++/* ++ * Probe write-related MMC features via GET CONFIGURATION and update ++ * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE ++ * capabilities page (e.g. sr) should call this after those MODE SENSE bits ++ * have been set but before register_cdrom(), so that the full set of ++ * write-capability bits is known by the time register_cdrom() decides on the ++ * initial read-only state of the disk. ++ */ ++void cdrom_probe_write_features(struct cdrom_device_info *cdi) ++{ ++ int mrw, mrw_write, ram_write; ++ ++ mrw = 0; ++ if (!cdrom_is_mrw(cdi, &mrw_write)) ++ mrw = 1; ++ ++ if (CDROM_CAN(CDC_MO_DRIVE)) ++ ram_write = 1; ++ else ++ (void) cdrom_is_random_writable(cdi, &ram_write); ++ ++ if (mrw) ++ cdi->mask &= ~CDC_MRW; ++ else ++ cdi->mask |= CDC_MRW; ++ ++ if (mrw_write) ++ cdi->mask &= ~CDC_MRW_W; ++ else ++ cdi->mask |= CDC_MRW_W; ++ ++ if (ram_write) ++ cdi->mask &= ~CDC_RAM; ++ else ++ cdi->mask |= CDC_RAM; ++} ++EXPORT_SYMBOL(cdrom_probe_write_features); ++ + static int cdrom_media_erasable(struct cdrom_device_info *cdi) + { + disc_information di; +@@ -894,33 +942,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) + */ + static int cdrom_open_write(struct cdrom_device_info *cdi) + { +- int mrw, mrw_write, ram_write; + int ret = 1; + +- mrw = 0; +- if (!cdrom_is_mrw(cdi, &mrw_write)) +- mrw = 1; +- +- if (CDROM_CAN(CDC_MO_DRIVE)) +- ram_write = 1; +- else +- (void) cdrom_is_random_writable(cdi, &ram_write); +- +- if (mrw) +- cdi->mask &= ~CDC_MRW; +- else +- cdi->mask |= CDC_MRW; +- +- if (mrw_write) +- cdi->mask &= ~CDC_MRW_W; +- else +- cdi->mask |= CDC_MRW_W; +- +- if (ram_write) +- cdi->mask &= ~CDC_RAM; +- else +- cdi->mask |= CDC_RAM; +- + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index add13e3068983..803fc9c132298 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) + + switch (req_op(rq)) { + case REQ_OP_WRITE: +- if (!cd->writeable) ++ if (get_disk_ro(cd->disk)) + goto out; + SCpnt->cmnd[0] = WRITE_10; + cd->cdi.media_written = 1; +@@ -681,6 +681,7 @@ static int sr_probe(struct device *dev) + error = -ENOMEM; + if (get_capabilities(cd)) + goto fail_minor; ++ cdrom_probe_write_features(&cd->cdi); + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd) + /*else I don't think it can close its tray + cd->cdi.mask |= CDC_CLOSE_TRAY; */ + +- /* +- * if DVD-RAM, MRW-W or CD-RW, we are randomly writable +- */ +- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != +- (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { +- cd->writeable = 1; +- } +- + kfree(buffer); + return 0; + } +diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h +index dc899277b3a44..2d92f9cb6fec7 100644 +--- a/drivers/scsi/sr.h ++++ b/drivers/scsi/sr.h +@@ -35,7 +35,6 @@ typedef struct scsi_cd { + struct scsi_device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ +- unsigned writeable : 1; + unsigned use:1; /* is this device still supportable */ + unsigned xa_flag:1; /* CD has XA sectors ? */ + unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ +diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h +index b907e6c2307d8..260d7968cf720 100644 +--- a/include/linux/cdrom.h ++++ b/include/linux/cdrom.h +@@ -108,6 +108,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, + extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing); + ++extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); + extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); + extern void unregister_cdrom(struct cdrom_device_info *cdi); + +-- +2.53.0 + diff --git a/queue-6.18/cgroup-increment-nr_dying_subsys_-from-rmdir-context.patch b/queue-6.18/cgroup-increment-nr_dying_subsys_-from-rmdir-context.patch new file mode 100644 index 0000000000..d46b8fdf17 --- /dev/null +++ b/queue-6.18/cgroup-increment-nr_dying_subsys_-from-rmdir-context.patch @@ -0,0 +1,76 @@ +From 0a2e89575c22404c5ca877f1c7deb378135e2cf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 04:48:26 -0500 +Subject: cgroup: Increment nr_dying_subsys_* from rmdir context + +From: Petr Malat + +[ Upstream commit 13e786b64bd3fd81c7eb22aa32bf8305c32f2ccf ] + +Incrementing nr_dying_subsys_* in offline_css(), which is executed by +cgroup_offline_wq worker, leads to a race where user can see the value +to be 0 if he reads cgroup.stat after calling rmdir and before the worker +executes. This makes the user wrongly expect resources released by the +removed cgroup to be available for a new assignment. + +Increment nr_dying_subsys_* from kill_css(), which is called from the +cgroup_rmdir() context. + +Fixes: ab0312526867 ("cgroup: Show # of subsystem CSSes in cgroup.stat") +Signed-off-by: Petr Malat +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index b60fc0b2c6036..1239bff9a994c 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -5773,16 +5773,6 @@ static void offline_css(struct cgroup_subsys_state *css) + RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL); + + wake_up_all(&css->cgroup->offline_waitq); +- +- css->cgroup->nr_dying_subsys[ss->id]++; +- /* +- * Parent css and cgroup cannot be freed until after the freeing +- * of child css, see css_free_rwork_fn(). +- */ +- while ((css = css->parent)) { +- css->nr_descendants--; +- css->cgroup->nr_dying_subsys[ss->id]++; +- } + } + + /** +@@ -6094,6 +6084,8 @@ static void css_killed_ref_fn(struct percpu_ref *ref) + */ + static void kill_css(struct cgroup_subsys_state *css) + { ++ struct cgroup_subsys *ss = css->ss; ++ + lockdep_assert_held(&cgroup_mutex); + + if (css->flags & CSS_DYING) +@@ -6130,6 +6122,16 @@ static void kill_css(struct cgroup_subsys_state *css) + * css is confirmed to be seen as killed on all CPUs. + */ + percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn); ++ ++ css->cgroup->nr_dying_subsys[ss->id]++; ++ /* ++ * Parent css and cgroup cannot be freed until after the freeing ++ * of child css, see css_free_rwork_fn(). ++ */ ++ while ((css = css->parent)) { ++ css->nr_descendants--; ++ css->cgroup->nr_dying_subsys[ss->id]++; ++ } + } + + /** +-- +2.53.0 + diff --git a/queue-6.18/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch b/queue-6.18/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch new file mode 100644 index 0000000000..5de5cf1f5d --- /dev/null +++ b/queue-6.18/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch @@ -0,0 +1,47 @@ +From 7e2e15dd076c5339ef98e8b247abbe7ea636ca0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 09:53:27 +0800 +Subject: cgroup/rdma: fix integer overflow in rdmacg_try_charge() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: cuitao + +[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ] + +The expression `rpool->resources[index].usage + 1` is computed in int +arithmetic before being assigned to s64 variable `new`. When usage equals +INT_MAX (the default "max" value), the addition overflows to INT_MIN. +This negative value then passes the `new > max` check incorrectly, +allowing a charge that should be rejected and corrupting usage to +negative. + +Fix by casting usage to s64 before the addition so the arithmetic is +done in 64-bit. + +Fixes: 39d3e7584a68 ("rdmacg: Added rdma cgroup controller") +Signed-off-by: cuitao +Reviewed-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c +index ef5878fb20057..d544a747f3954 100644 +--- a/kernel/cgroup/rdma.c ++++ b/kernel/cgroup/rdma.c +@@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, + ret = PTR_ERR(rpool); + goto err; + } else { +- new = rpool->resources[index].usage + 1; ++ new = (s64)rpool->resources[index].usage + 1; + if (new > rpool->resources[index].max) { + ret = -EAGAIN; + goto err; +-- +2.53.0 + diff --git a/queue-6.18/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch b/queue-6.18/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch new file mode 100644 index 0000000000..5e383da84c --- /dev/null +++ b/queue-6.18/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch @@ -0,0 +1,58 @@ +From c36d565460f5faf491e87e28dd5b4898da7f3c39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:58 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in + of_assigned_ldb_sels() + +From: Felix Gu + +[ Upstream commit 9faf207208951460f3f7eefbc112246c8d28ff1b ] + +The function of_assigned_ldb_sels() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing a memory +leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 5d283b083800 ("clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-2-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index ba696cf34fe3b..048e2ddba490b 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -188,9 +188,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + } + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: parent clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + parent = clkspec.args[0]; ++ of_node_put(clkspec.np); + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); +@@ -198,9 +200,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + return; + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: child clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + child = clkspec.args[0]; ++ of_node_put(clkspec.np); + + if (child != IMX6QDL_CLK_LDB_DI0_SEL && + child != IMX6QDL_CLK_LDB_DI1_SEL) +-- +2.53.0 + diff --git a/queue-6.18/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch b/queue-6.18/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch new file mode 100644 index 0000000000..6c7b975581 --- /dev/null +++ b/queue-6.18/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch @@ -0,0 +1,56 @@ +From 1aa2b08183d38f7df08a1c3948ba4e4ff1ca2113 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:57 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in pll6_bypassed() + +From: Felix Gu + +[ Upstream commit 4b84d496c804b470124cd3a08e928df6801d8eae ] + +The function pll6_bypassed() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing +a memory leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 3cc48976e9763 ("clk: imx6q: handle ENET PLL bypass") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-1-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index bf4c1d9c99287..ba696cf34fe3b 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -238,8 +238,11 @@ static bool pll6_bypassed(struct device_node *node) + return false; + + if (clkspec.np == node && +- clkspec.args[0] == IMX6QDL_PLL6_BYPASS) ++ clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { ++ of_node_put(clkspec.np); + break; ++ } ++ of_node_put(clkspec.np); + } + + /* PLL6 bypass is not part of the assigned clock list */ +@@ -249,6 +252,9 @@ static bool pll6_bypassed(struct device_node *node) + ret = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + ++ if (!ret) ++ of_node_put(clkspec.np); ++ + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) + return true; + +-- +2.53.0 + diff --git a/queue-6.18/clk-imx8mq-correct-the-csi-phy-sels.patch b/queue-6.18/clk-imx8mq-correct-the-csi-phy-sels.patch new file mode 100644 index 0000000000..11f9012472 --- /dev/null +++ b/queue-6.18/clk-imx8mq-correct-the-csi-phy-sels.patch @@ -0,0 +1,49 @@ +From 66a8f8633982019016fd0af4b1419bdad5f8590e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 00:47:21 +0100 +Subject: clk: imx8mq: Correct the CSI PHY sels + +From: Sebastian Krzyszkowiak + +[ Upstream commit d16f57caa78776e6e8a88b96cb2597797b376138 ] + +According to i.MX 8M Quad Reference Manual (Section 5.1.2 Table 5-1) +MIPI_CSI1_PHY_REF_CLK_ROOT and MIPI_CSI2_PHY_REF_CLK_ROOT have +SYSTEM_PLL2_DIV3 available as their second source, which corresponds +to sys2_pll_333m rather than sys2_pll_125m. + +Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") +Signed-off-by: Sebastian Krzyszkowiak +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260128-imx8mq-csi-clk-v1-1-ac028ed26e8c@puri.sm +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index f70ed231b92d6..cedc8a02aa1f0 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " + static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +@@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", + static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-01-sa8775p-fix-dsi-byte-clock-rate-s.patch b/queue-6.18/clk-qcom-dispcc-01-sa8775p-fix-dsi-byte-clock-rate-s.patch new file mode 100644 index 0000000000..6632e6ed8f --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-01-sa8775p-fix-dsi-byte-clock-rate-s.patch @@ -0,0 +1,81 @@ +From d3237dab12e4e087c5ca75af8771396f4a21d4f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:31 +0100 +Subject: clk: qcom: dispcc[01]-sa8775p: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit 2851b6c6a42e22c243aa4cd606a49e2b9acfb6d6 ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: e700bfd2f976 ("clk: qcom: Add support for Display clock Controllers on SA8775P") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-5-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc0-sa8775p.c | 2 -- + drivers/clk/qcom/dispcc1-sa8775p.c | 2 -- + 2 files changed, 4 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc0-sa8775p.c b/drivers/clk/qcom/dispcc0-sa8775p.c +index aeda9cf4bfee8..b248fa9705873 100644 +--- a/drivers/clk/qcom/dispcc0-sa8775p.c ++++ b/drivers/clk/qcom/dispcc0-sa8775p.c +@@ -591,7 +591,6 @@ static struct clk_regmap_div mdss_0_disp_cc_mdss_byte0_div_clk_src = { + &mdss_0_disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -606,7 +605,6 @@ static struct clk_regmap_div mdss_0_disp_cc_mdss_byte1_div_clk_src = { + &mdss_0_disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +diff --git a/drivers/clk/qcom/dispcc1-sa8775p.c b/drivers/clk/qcom/dispcc1-sa8775p.c +index cd55d1c119024..9882edbb79f9e 100644 +--- a/drivers/clk/qcom/dispcc1-sa8775p.c ++++ b/drivers/clk/qcom/dispcc1-sa8775p.c +@@ -591,7 +591,6 @@ static struct clk_regmap_div mdss_1_disp_cc_mdss_byte0_div_clk_src = { + &mdss_1_disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -606,7 +605,6 @@ static struct clk_regmap_div mdss_1_disp_cc_mdss_byte1_div_clk_src = { + &mdss_1_disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-glymur-fix-dsi-byte-clock-rate-setti.patch b/queue-6.18/clk-qcom-dispcc-glymur-fix-dsi-byte-clock-rate-setti.patch new file mode 100644 index 0000000000..c42f358756 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-glymur-fix-dsi-byte-clock-rate-setti.patch @@ -0,0 +1,60 @@ +From e82050ea2ae0c85fac1f770095daf89940709a2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:27 +0100 +Subject: clk: qcom: dispcc-glymur: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit 98ea9eda030587601db56425efcd32263d853591 ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: b4d15211c408 ("clk: qcom: dispcc-glymur: Add support for Display Clock Controller") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-1-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-glymur.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-glymur.c b/drivers/clk/qcom/dispcc-glymur.c +index f352165bf56fc..bef74f58405ba 100644 +--- a/drivers/clk/qcom/dispcc-glymur.c ++++ b/drivers/clk/qcom/dispcc-glymur.c +@@ -747,7 +747,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -762,7 +761,6 @@ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-glymur-use-rcg2-ops-for-dptx1-aux-cl.patch b/queue-6.18/clk-qcom-dispcc-glymur-use-rcg2-ops-for-dptx1-aux-cl.patch new file mode 100644 index 0000000000..69103db81f --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-glymur-use-rcg2-ops-for-dptx1-aux-cl.patch @@ -0,0 +1,41 @@ +From 609aa7db2c8f7ad4968172843e81d07e2d258970 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 04:12:22 +0200 +Subject: clk: qcom: dispcc-glymur: use RCG2 ops for DPTX1 AUX clock source + +From: Dmitry Baryshkov + +[ Upstream commit e7c8eb1646db5d967d77ee67793dd95a2c5ff451 ] + +The clk_dp_ops are supposed to be used for DP-related clocks with a +proper MND divier. Use shared RCG2 ops for dptx1_aux_clk_src, the same +as all other DPTX AUX clocks in this driver. + +Fixes: b4d15211c408 ("clk: qcom: dispcc-glymur: Add support for Display Clock Controller") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260112-dp-aux-clks-v1-1-456b0c11b069@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-glymur.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-glymur.c b/drivers/clk/qcom/dispcc-glymur.c +index 5203fa6383f6a..f352165bf56fc 100644 +--- a/drivers/clk/qcom/dispcc-glymur.c ++++ b/drivers/clk/qcom/dispcc-glymur.c +@@ -417,7 +417,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_dp_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-milos-fix-dsi-byte-clock-rate-settin.patch b/queue-6.18/clk-qcom-dispcc-milos-fix-dsi-byte-clock-rate-settin.patch new file mode 100644 index 0000000000..78a64444b7 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-milos-fix-dsi-byte-clock-rate-settin.patch @@ -0,0 +1,52 @@ +From 645d3e1fbd26d8b8e3464ef794fabd82d039edea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:29 +0100 +Subject: clk: qcom: dispcc-milos: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit dd5b76257b4048151006620c9895e2f5f0d997eb ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: f40b5217dce1 ("clk: qcom: Add Display Clock controller (DISPCC) driver for Milos") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-3-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-milos.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-milos.c b/drivers/clk/qcom/dispcc-milos.c +index 95b6dd89d9ae3..339cb1c63ba77 100644 +--- a/drivers/clk/qcom/dispcc-milos.c ++++ b/drivers/clk/qcom/dispcc-milos.c +@@ -394,7 +394,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch b/queue-6.18/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch new file mode 100644 index 0000000000..06c914c7b8 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch @@ -0,0 +1,59 @@ +From dc71cd8c186da55a7116fe5ad355c269de90bb5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:26 +0100 +Subject: clk: qcom: dispcc-sc7180: Add missing MDSS resets + +From: Konrad Dybcio + +[ Upstream commit b0bc6011c5499bdfddd0390262bfa13dce1eff74 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: dd3d06622138 ("clk: qcom: Add display clock controller driver for SC7180") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Taniya Das +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-2-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc7180.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c +index ab1a8d419863d..d7e37fbbe87ed 100644 +--- a/drivers/clk/qcom/dispcc-sc7180.c ++++ b/drivers/clk/qcom/dispcc-sc7180.c +@@ -17,6 +17,7 @@ + #include "clk-regmap-divider.h" + #include "common.h" + #include "gdsc.h" ++#include "reset.h" + + enum { + P_BI_TCXO, +@@ -636,6 +637,11 @@ static struct gdsc mdss_gdsc = { + .flags = HW_CTRL, + }; + ++static const struct qcom_reset_map disp_cc_sc7180_resets[] = { ++ [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, ++ [DISP_CC_MDSS_RSCC_BCR] = { 0x4000 }, ++}; ++ + static struct gdsc *disp_cc_sc7180_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, + }; +@@ -687,6 +693,8 @@ static const struct qcom_cc_desc disp_cc_sc7180_desc = { + .config = &disp_cc_sc7180_regmap_config, + .clks = disp_cc_sc7180_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sc7180_clocks), ++ .resets = disp_cc_sc7180_resets, ++ .num_resets = ARRAY_SIZE(disp_cc_sc7180_resets), + .gdscs = disp_cc_sc7180_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sc7180_gdscs), + }; +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch b/queue-6.18/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch new file mode 100644 index 0000000000..51c9ea5b07 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch @@ -0,0 +1,74 @@ +From 8dfa65d358504f7f0f69a37d731649629665cd48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 19:55:50 +0800 +Subject: clk: qcom: dispcc-sc8280xp: remove CLK_SET_RATE_PARENT from + byte_div_clk_src dividers + +From: White Lewis + +[ Upstream commit 0b151a6307205eb867250985a910a88787cbf12e ] + +The four byte_div_clk_src dividers (disp{0,1}_cc_mdss_byte{0,1}_div_clk_src) +had CLK_SET_RATE_PARENT set. When the DSI driver calls clk_set_rate() on +byte_intf_clk, the rate-change propagates through the divider up to the +parent PLL (byte_clk_src), halving the byte clock rate. + +A simiar issue had been also encountered on SM8750. +b8501febdc51 ("clk: qcom: dispcc-sm8750: Drop incorrect CLK_SET_RATE_PARENT on byte intf parent"). + +Likewise, remove CLK_SET_RATE_PARENT from all four byte divider clocks +so that clk_set_rate() on the divider adjusts only the divider ratio, +leaving the parent PLL untouched. + +Fixes: 4a66e76fdb6d ("clk: qcom: Add SC8280XP display clock controller") +Signed-off-by: White Lewis +[pengyu: reword] +Signed-off-by: Pengyu Luo +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260303115550.9279-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc8280xp.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sc8280xp.c b/drivers/clk/qcom/dispcc-sc8280xp.c +index 5903a759d4af4..e91dfed0f37e9 100644 +--- a/drivers/clk/qcom/dispcc-sc8280xp.c ++++ b/drivers/clk/qcom/dispcc-sc8280xp.c +@@ -1160,7 +1160,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte0_div_clk_src = { + &disp0_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1175,7 +1174,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte0_div_clk_src = { + &disp1_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1190,7 +1188,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte1_div_clk_src = { + &disp0_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1205,7 +1202,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte1_div_clk_src = { + &disp1_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch b/queue-6.18/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch new file mode 100644 index 0000000000..843be33b27 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch @@ -0,0 +1,52 @@ +From 937beaefc3bd84902370cee30a57678034b9583a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:30 +0100 +Subject: clk: qcom: dispcc-sm4450: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit 7bc48fcdf9e77bf68ef04af015d50df2a9acac00 ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: 76f05f1ec766 ("clk: qcom: Add DISPCC driver support for SM4450") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-4-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm4450.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm4450.c b/drivers/clk/qcom/dispcc-sm4450.c +index e8752d01c8e62..2fdacc26df698 100644 +--- a/drivers/clk/qcom/dispcc-sm4450.c ++++ b/drivers/clk/qcom/dispcc-sm4450.c +@@ -335,7 +335,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch b/queue-6.18/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..5a5ea29849 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,48 @@ +From a6958c0fe1d630bad568f8b89592cbb62248a519 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:13 -0300 +Subject: clk: qcom: dispcc-sm8250: Enable parents for pixel clocks + +From: Val Packett + +[ Upstream commit acf7a91d0b0e9e3ef374944021de62062125b7e4 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-9-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index cdfdb2cfb02b2..e59cdadd56479 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -578,7 +578,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -592,7 +592,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch b/queue-6.18/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch new file mode 100644 index 0000000000..bcdb15a6b1 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch @@ -0,0 +1,45 @@ +From 2fcc66ba3415f4c97f059ce6112c201ad764fc65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:12 -0300 +Subject: clk: qcom: dispcc-sm8250: Use shared ops on the mdss vsync clk + +From: Val Packett + +[ Upstream commit 8c522da70f0c2e5148c4c13ccb1c64cca57a6fdb ] + +mdss_gdsc can get stuck on boot due to RCGs being left on from last boot. +As a fix, commit 01a0a6cc8cfd ("clk: qcom: Park shared RCGs upon +registration") introduced a callback to ensure the RCG is off upon init. +However, the fix depends on all shared RCGs being marked as such in code. + +For SM8150/SC8180X/SM8250 the MDSS vsync clock was using regular ops, +unlike the same clock in the SC7180 code. This was causing display to +frequently fail to initialize after rebooting on the Surface Pro X. +Fix by using shared ops for this clock. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-8-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index 8f433e1e70283..cdfdb2cfb02b2 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -632,7 +632,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch b/queue-6.18/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch new file mode 100644 index 0000000000..b37007d5e1 --- /dev/null +++ b/queue-6.18/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch @@ -0,0 +1,41 @@ +From 3fdc5edeecfadaca3c552f6e33fb31f9f7442a4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 04:12:23 +0200 +Subject: clk: qcom: dispcc-sm8450: use RCG2 ops for DPTX1 AUX clock source + +From: Dmitry Baryshkov + +[ Upstream commit 141af1be817c42c7f1e1605348d4b1983d319bea ] + +The clk_dp_ops are supposed to be used for DP-related clocks with a +proper MND divier. Use standard RCG2 ops for dptx1_aux_clk_src, the same +as all other DPTX AUX clocks in this driver. + +Fixes: 16fb89f92ec4 ("clk: qcom: Add support for Display Clock Controller on SM8450") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260112-dp-aux-clks-v1-2-456b0c11b069@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8450.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c +index 9ce9fd28e55b2..2e91332dd92ab 100644 +--- a/drivers/clk/qcom/dispcc-sm8450.c ++++ b/drivers/clk/qcom/dispcc-sm8450.c +@@ -409,7 +409,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_dp_ops, ++ .ops = &clk_rcg2_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-gcc-glymur-add-video-axi-clock-resets-for-g.patch b/queue-6.18/clk-qcom-gcc-glymur-add-video-axi-clock-resets-for-g.patch new file mode 100644 index 0000000000..9268c69163 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-glymur-add-video-axi-clock-resets-for-g.patch @@ -0,0 +1,39 @@ +From 2bb8ec7c1ee5b9c75cb2832f79c20cdd02f59ae1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:26:52 +0530 +Subject: clk: qcom: gcc-glymur: Add video axi clock resets for glymur + +From: Taniya Das + +[ Upstream commit 1c8ce43e1e07ecc531fb517f95620ed85e998608 ] + +The global clock controller video axi reset clocks are required by +the video SW driver to assert and deassert the clock resets during +their power down sequence. Hence add these clock resets. + +Fixes: efe504300a17 ("clk: qcom: gcc: Add support for Global Clock Controller") +Signed-off-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260202-glymur_videocc-v2-3-8f7d8b4d8edd@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-glymur.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c +index 17e860307fa10..eff3248d483ad 100644 +--- a/drivers/clk/qcom/gcc-glymur.c ++++ b/drivers/clk/qcom/gcc-glymur.c +@@ -8508,6 +8508,7 @@ static const struct qcom_reset_map gcc_glymur_resets[] = { + [GCC_VIDEO_AXI0_CLK_ARES] = { 0x3201c, 2 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { 0x32044, 2 }, + [GCC_VIDEO_BCR] = { 0x32000 }, ++ [GCC_VIDEO_AXI0C_CLK_ARES] = { 0x32030, 2 }, + }; + + static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-6.18/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..10fe3699b0 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,94 @@ +From 4696c0fb2ed9f9022a60eb4e95564e28652aae85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:07 -0300 +Subject: clk: qcom: gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 3565741eb985a8a7cc6656eb33496195468cb99e ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-3-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 50 ++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 31e788e22ab4a..55dabf6259b29 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4266,6 +4266,51 @@ static struct gdsc usb30_mp_gdsc = { + .flags = POLL_CFG_GDSCR, + }; + ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { ++ .gdscr = 0x7d050, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { ++ .gdscr = 0x7d058, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { ++ .gdscr = 0x7d054, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { ++ .gdscr = 0x7d05c, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { ++ .gdscr = 0x7d060, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ + static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, +@@ -4595,6 +4640,11 @@ static struct gdsc *gcc_sc8180x_gdscs[] = { + [USB30_MP_GDSC] = &usb30_mp_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB30_SEC_GDSC] = &usb30_sec_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, + }; + + static const struct regmap_config gcc_sc8180x_regmap_config = { +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch b/queue-6.18/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch new file mode 100644 index 0000000000..c985adbc87 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch @@ -0,0 +1,74 @@ +From f86efcdb6c4e472c4982ded9bf61f86762bdb3ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:09 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for PCIe power domains + +From: Val Packett + +[ Upstream commit ccb92c78b42edd26225b4d5920847dfee3e1b093 ] + +As the PCIe host controller driver does not yet support dealing with the +loss of state during suspend, use retention for relevant GDSCs. + +This fixes the link not surviving upon resume: + + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS read failed (134) + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: Disabling device after reset failure: -19 + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260312112321.370983-5-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index b116a9c0b2d94..4095a1f54a099 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4199,7 +4199,7 @@ static struct gdsc pcie_0_gdsc = { + .pd = { + .name = "pcie_0_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4226,7 +4226,7 @@ static struct gdsc pcie_1_gdsc = { + .pd = { + .name = "pcie_1_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4235,7 +4235,7 @@ static struct gdsc pcie_2_gdsc = { + .pd = { + .name = "pcie_2_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4253,7 +4253,7 @@ static struct gdsc pcie_3_gdsc = { + .pd = { + .name = "pcie_3_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch b/queue-6.18/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch new file mode 100644 index 0000000000..e9db43ee34 --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch @@ -0,0 +1,65 @@ +From f56b2562cd312c2ca645debc67661d10bdbb31b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:08 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for USB power domains + +From: Val Packett + +[ Upstream commit 25bc96f26cd6c19dde13a0b9859183e531d6fbfc ] + +The USB subsystem does not expect to lose its state on suspend: + + xhci-hcd xhci-hcd.0.auto: xHC error in resume, USBSTS 0x401, Reinit + usb usb1: root hub lost power or was reset + +(The reinitialization usually succeeds, but it does slow down resume.) + +To maintain state during suspend, the relevant GDSCs need to stay in +retention mode, like they do on other similar SoCs. Change the mode to +PWRSTS_RET_ON to fix. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-4-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 55dabf6259b29..b116a9c0b2d94 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4172,7 +4172,7 @@ static struct gdsc usb30_sec_gdsc = { + .pd = { + .name = "usb30_sec_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4190,7 +4190,7 @@ static struct gdsc usb30_prim_gdsc = { + .pd = { + .name = "usb30_prim_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4262,7 +4262,7 @@ static struct gdsc usb30_mp_gdsc = { + .pd = { + .name = "usb30_mp_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch b/queue-6.18/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch new file mode 100644 index 0000000000..26bf40a51d --- /dev/null +++ b/queue-6.18/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch @@ -0,0 +1,44 @@ +From 02188b16e8ac6dbcd2c520de82dcae978c92860a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 20:36:46 +0530 +Subject: clk: qcom: gcc-x1e80100: Keep GCC USB QTB clock always ON + +From: Jagadeesh Kona + +[ Upstream commit 05566ebcc0cd170bd4f50c907ee3ed8e106251e3 ] + +In Hamoa, SMMU invalidation requires the GCC_AGGRE_USB_NOC_AXI_CLK +to be on for the USB QTB to be functional. This is currently +explicitly enabled by the DWC3 glue driver, so an invalidation +happening while the USB controller is suspended will fault. + +Solve this by voting for the GCC MMU USB QTB clock. + +Fixes: 161b7c401f4b ("clk: qcom: Add Global Clock controller (GCC) driver for X1E80100") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Jagadeesh Kona +Reviewed-by: Taniya Das +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260327-hamoa-usb-qtb-clk-always-on-v2-1-7d8a406e650f@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-x1e80100.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c +index ef8d2df188d3b..104b1bf6a5010 100644 +--- a/drivers/clk/qcom/gcc-x1e80100.c ++++ b/drivers/clk/qcom/gcc-x1e80100.c +@@ -6751,6 +6751,7 @@ static int gcc_x1e80100_probe(struct platform_device *pdev) + qcom_branch_set_clk_en(regmap, 0x32004); /* GCC_VIDEO_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x32030); /* GCC_VIDEO_XO_CLK */ + qcom_branch_set_clk_en(regmap, 0x71004); /* GCC_GPU_CFG_AHB_CLK */ ++ qcom_branch_set_clk_en(regmap, 0x7d01c); /* GCC_HLOS1_VOTE_AGGRE_NOC_MMU_USB_QTB_CLK */ + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52224, 0x0); +-- +2.53.0 + diff --git a/queue-6.18/clk-qcom-gdsc-fix-error-path-on-registration-of-mult.patch b/queue-6.18/clk-qcom-gdsc-fix-error-path-on-registration-of-mult.patch new file mode 100644 index 0000000000..f0cd95f066 --- /dev/null +++ b/queue-6.18/clk-qcom-gdsc-fix-error-path-on-registration-of-mult.patch @@ -0,0 +1,54 @@ +From 7a6aef8d7a04e8965fc2c50981404c12dd865f34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 03:26:19 +0200 +Subject: clk: qcom: gdsc: Fix error path on registration of multiple pm + subdomains + +From: Vladimir Zapolskiy + +[ Upstream commit 16ba98dace9e7cfe25ad8a314e34befacd91f86f ] + +Some pm subdomains may be left in added to a parent domain state, if +gdsc_add_subdomain_list() function fails in the middle and bails from +a GDSC power domain controller registration out. + +Fixes: b489235b4dc0 ("clk: qcom: Support attaching GDSCs to multiple parents") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Bryan O'Donoghue +Link: https://lore.kernel.org/r/20260328012619.832770-1-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gdsc.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c +index 7deabf8400cf6..95aa071202455 100644 +--- a/drivers/clk/qcom/gdsc.c ++++ b/drivers/clk/qcom/gdsc.c +@@ -518,10 +518,20 @@ static int gdsc_add_subdomain_list(struct dev_pm_domain_list *pd_list, + + ret = pm_genpd_add_subdomain(genpd, subdomain); + if (ret) +- return ret; ++ goto remove_added_subdomains; + } + + return 0; ++ ++remove_added_subdomains: ++ for (i--; i >= 0; i--) { ++ struct device *dev = pd_list->pd_devs[i]; ++ struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain); ++ ++ pm_genpd_remove_subdomain(genpd, subdomain); ++ } ++ ++ return ret; + } + + static void gdsc_remove_subdomain_list(struct dev_pm_domain_list *pd_list, +-- +2.53.0 + diff --git a/queue-6.18/clk-qoriq-avoid-format-string-warning.patch b/queue-6.18/clk-qoriq-avoid-format-string-warning.patch new file mode 100644 index 0000000000..e6ad4b4fe0 --- /dev/null +++ b/queue-6.18/clk-qoriq-avoid-format-string-warning.patch @@ -0,0 +1,86 @@ +From 533982a2734daa8759c31bb8b1e4554d868ca37b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:18:49 +0100 +Subject: clk: qoriq: avoid format string warning + +From: Arnd Bergmann + +[ Upstream commit 096abbb6682ee031a0f5ce9f4c71ead9fa63d31e ] + +clang-22 warns about the use of non-variadic format arguments passed into +snprintf(): + +drivers/clk/clk-qoriq.c:925:39: error: diagnostic behavior may be improved by adding the + 'format(printf, 7, 8)' attribute to the declaration of 'create_mux_common' [-Werror,-Wmissing-format-attribute] + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + | __attribute__((format(printf, 7, 8))) + 911 | struct mux_hwclock *hwc, + 912 | const struct clk_ops *ops, + 913 | unsigned long min_rate, + 914 | unsigned long max_rate, + 915 | unsigned long pct80_rate, + 916 | const char *fmt, int idx) + 917 | { + 918 | struct clk_init_data init = {}; + 919 | struct clk *clk; + 920 | const struct clockgen_pll_div *div; + 921 | const char *parent_names[NUM_MUX_PARENTS]; + 922 | char name[32]; + 923 | int i, j; + 924 | + 925 | snprintf(name, sizeof(name), fmt, idx); + | ^ +drivers/clk/clk-qoriq.c:910:28: note: 'create_mux_common' declared here + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + +Rework this to pass the 'int idx' as a varargs argument, allowing the +format string to be verified at the caller location. + +Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") +Signed-off-by: Arnd Bergmann +Reviewed-by: Kees Cook +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-qoriq.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c +index a560edeb4b55a..03f9381e26fb7 100644 +--- a/drivers/clk/clk-qoriq.c ++++ b/drivers/clk/clk-qoriq.c +@@ -907,13 +907,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg, + return &cg->pll[pll].div[div]; + } + +-static struct clk * __init create_mux_common(struct clockgen *cg, +- struct mux_hwclock *hwc, +- const struct clk_ops *ops, +- unsigned long min_rate, +- unsigned long max_rate, +- unsigned long pct80_rate, +- const char *fmt, int idx) ++static struct clk * __init __printf(7, 8) ++create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, ++ const struct clk_ops *ops, unsigned long min_rate, ++ unsigned long max_rate, unsigned long pct80_rate, ++ const char *fmt, ...) + { + struct clk_init_data init = {}; + struct clk *clk; +@@ -921,8 +919,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg, + const char *parent_names[NUM_MUX_PARENTS]; + char name[32]; + int i, j; ++ va_list args; + +- snprintf(name, sizeof(name), fmt, idx); ++ va_start(args, fmt); ++ vsnprintf(name, sizeof(name), fmt, args); ++ va_end(args); + + for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) { + unsigned long rate; +-- +2.53.0 + diff --git a/queue-6.18/clk-renesas-r9a09g057-add-clock-and-reset-entries-fo.patch b/queue-6.18/clk-renesas-r9a09g057-add-clock-and-reset-entries-fo.patch new file mode 100644 index 0000000000..528f0f46af --- /dev/null +++ b/queue-6.18/clk-renesas-r9a09g057-add-clock-and-reset-entries-fo.patch @@ -0,0 +1,47 @@ +From b92b9cc3f5633f403333f7c96389f15718e7880d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Oct 2025 08:07:00 +0000 +Subject: clk: renesas: r9a09g057: Add clock and reset entries for RTC + +From: Ovidiu Panait + +[ Upstream commit 7a03ef9f8223434f19e19a37acc32dcb581ab475 ] + +Add module clock and reset entries for the RTC module on the Renesas RZ/V2H +(R9A09G057) SoC. + +Signed-off-by: Ovidiu Panait +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20251021080705.18116-2-ovidiu.panait.rb@renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 1b4f047dc401 ("clk: renesas: r9a09g057: Remove entries for WDT{0,2,3}") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a09g057-cpg.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c +index 6389c4b6a5231..4e47fea3f8946 100644 +--- a/drivers/clk/renesas/r9a09g057-cpg.c ++++ b/drivers/clk/renesas/r9a09g057-cpg.c +@@ -239,6 +239,8 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + BUS_MSTOP(5, BIT(13))), + DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18, + BUS_MSTOP(5, BIT(13))), ++ DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19, ++ BUS_MSTOP(3, BIT(11) | BIT(12))), + DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, + BUS_MSTOP(11, BIT(0))), + DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21, +@@ -401,6 +403,8 @@ static const struct rzv2h_reset r9a09g057_resets[] __initconst = { + DEF_RST(7, 6, 3, 7), /* WDT_1_RESET */ + DEF_RST(7, 7, 3, 8), /* WDT_2_RESET */ + DEF_RST(7, 8, 3, 9), /* WDT_3_RESET */ ++ DEF_RST(7, 9, 3, 10), /* RTC_0_RST_RTC */ ++ DEF_RST(7, 10, 3, 11), /* RTC_0_RST_RTC_V */ + DEF_RST(7, 11, 3, 12), /* RSPI_0_PRESETN */ + DEF_RST(7, 12, 3, 13), /* RSPI_0_TRESETN */ + DEF_RST(7, 13, 3, 14), /* RSPI_1_PRESETN */ +-- +2.53.0 + diff --git a/queue-6.18/clk-renesas-r9a09g057-add-entries-for-rscis.patch b/queue-6.18/clk-renesas-r9a09g057-add-entries-for-rscis.patch new file mode 100644 index 0000000000..3e28e32083 --- /dev/null +++ b/queue-6.18/clk-renesas-r9a09g057-add-entries-for-rscis.patch @@ -0,0 +1,182 @@ +From ba6e2197048351ae0faebb04fe8a76341e4675e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Dec 2025 09:41:47 +0000 +Subject: clk: renesas: r9a09g057: Add entries for RSCIs + +From: Lad Prabhakar + +[ Upstream commit 2efea3b35cc916f04f06b89f2e2557dbd9c48109 ] + +Add clock and reset entries for the RSCI IPs. + +Signed-off-by: Lad Prabhakar +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20251203094147.6429-3-prabhakar.mahadev-lad.rj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 1b4f047dc401 ("clk: renesas: r9a09g057: Remove entries for WDT{0,2,3}") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a09g057-cpg.c | 126 ++++++++++++++++++++++++++++ + 1 file changed, 126 insertions(+) + +diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c +index 4e47fea3f8946..ac3d309365b45 100644 +--- a/drivers/clk/renesas/r9a09g057-cpg.c ++++ b/drivers/clk/renesas/r9a09g057-cpg.c +@@ -44,6 +44,9 @@ enum clk_ids { + CLK_PLLCLN_DIV2, + CLK_PLLCLN_DIV8, + CLK_PLLCLN_DIV16, ++ CLK_PLLCLN_DIV64, ++ CLK_PLLCLN_DIV256, ++ CLK_PLLCLN_DIV1024, + CLK_PLLDTY_ACPU, + CLK_PLLDTY_ACPU_DIV2, + CLK_PLLDTY_ACPU_DIV4, +@@ -144,6 +147,9 @@ static const struct cpg_core_clk r9a09g057_core_clks[] __initconst = { + DEF_FIXED(".pllcln_div2", CLK_PLLCLN_DIV2, CLK_PLLCLN, 1, 2), + DEF_FIXED(".pllcln_div8", CLK_PLLCLN_DIV8, CLK_PLLCLN, 1, 8), + DEF_FIXED(".pllcln_div16", CLK_PLLCLN_DIV16, CLK_PLLCLN, 1, 16), ++ DEF_FIXED(".pllcln_div64", CLK_PLLCLN_DIV64, CLK_PLLCLN, 1, 64), ++ DEF_FIXED(".pllcln_div256", CLK_PLLCLN_DIV256, CLK_PLLCLN, 1, 256), ++ DEF_FIXED(".pllcln_div1024", CLK_PLLCLN_DIV1024, CLK_PLLCLN, 1, 1024), + + DEF_DDIV(".plldty_acpu", CLK_PLLDTY_ACPU, CLK_PLLDTY, CDDIV0_DIVCTL2, dtable_2_64), + DEF_FIXED(".plldty_acpu_div2", CLK_PLLDTY_ACPU_DIV2, CLK_PLLDTY_ACPU, 1, 2), +@@ -239,6 +245,106 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + BUS_MSTOP(5, BIT(13))), + DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18, + BUS_MSTOP(5, BIT(13))), ++ DEF_MOD("rsci0_pclk", CLK_PLLCLN_DIV16, 5, 13, 2, 29, ++ BUS_MSTOP(11, BIT(3))), ++ DEF_MOD("rsci0_tclk", CLK_PLLCLN_DIV16, 5, 14, 2, 30, ++ BUS_MSTOP(11, BIT(3))), ++ DEF_MOD("rsci0_ps_ps3_n", CLK_PLLCLN_DIV1024, 5, 15, 2, 31, ++ BUS_MSTOP(11, BIT(3))), ++ DEF_MOD("rsci0_ps_ps2_n", CLK_PLLCLN_DIV256, 6, 0, 3, 0, ++ BUS_MSTOP(11, BIT(3))), ++ DEF_MOD("rsci0_ps_ps1_n", CLK_PLLCLN_DIV64, 6, 1, 3, 1, ++ BUS_MSTOP(11, BIT(3))), ++ DEF_MOD("rsci1_pclk", CLK_PLLCLN_DIV16, 6, 2, 3, 2, ++ BUS_MSTOP(11, BIT(4))), ++ DEF_MOD("rsci1_tclk", CLK_PLLCLN_DIV16, 6, 3, 3, 3, ++ BUS_MSTOP(11, BIT(4))), ++ DEF_MOD("rsci1_ps_ps3_n", CLK_PLLCLN_DIV1024, 6, 4, 3, 4, ++ BUS_MSTOP(11, BIT(4))), ++ DEF_MOD("rsci1_ps_ps2_n", CLK_PLLCLN_DIV256, 6, 5, 3, 5, ++ BUS_MSTOP(11, BIT(4))), ++ DEF_MOD("rsci1_ps_ps1_n", CLK_PLLCLN_DIV64, 6, 6, 3, 6, ++ BUS_MSTOP(11, BIT(4))), ++ DEF_MOD("rsci2_pclk", CLK_PLLCLN_DIV16, 6, 7, 3, 7, ++ BUS_MSTOP(11, BIT(5))), ++ DEF_MOD("rsci2_tclk", CLK_PLLCLN_DIV16, 6, 8, 3, 8, ++ BUS_MSTOP(11, BIT(5))), ++ DEF_MOD("rsci2_ps_ps3_n", CLK_PLLCLN_DIV1024, 6, 9, 3, 9, ++ BUS_MSTOP(11, BIT(5))), ++ DEF_MOD("rsci2_ps_ps2_n", CLK_PLLCLN_DIV256, 6, 10, 3, 10, ++ BUS_MSTOP(11, BIT(5))), ++ DEF_MOD("rsci2_ps_ps1_n", CLK_PLLCLN_DIV64, 6, 11, 3, 11, ++ BUS_MSTOP(11, BIT(5))), ++ DEF_MOD("rsci3_pclk", CLK_PLLCLN_DIV16, 6, 12, 3, 12, ++ BUS_MSTOP(11, BIT(6))), ++ DEF_MOD("rsci3_tclk", CLK_PLLCLN_DIV16, 6, 13, 3, 13, ++ BUS_MSTOP(11, BIT(6))), ++ DEF_MOD("rsci3_ps_ps3_n", CLK_PLLCLN_DIV1024, 6, 14, 3, 14, ++ BUS_MSTOP(11, BIT(6))), ++ DEF_MOD("rsci3_ps_ps2_n", CLK_PLLCLN_DIV256, 6, 15, 3, 15, ++ BUS_MSTOP(11, BIT(6))), ++ DEF_MOD("rsci3_ps_ps1_n", CLK_PLLCLN_DIV64, 7, 0, 3, 16, ++ BUS_MSTOP(11, BIT(6))), ++ DEF_MOD("rsci4_pclk", CLK_PLLCLN_DIV16, 7, 1, 3, 17, ++ BUS_MSTOP(11, BIT(7))), ++ DEF_MOD("rsci4_tclk", CLK_PLLCLN_DIV16, 7, 2, 3, 18, ++ BUS_MSTOP(11, BIT(7))), ++ DEF_MOD("rsci4_ps_ps3_n", CLK_PLLCLN_DIV1024, 7, 3, 3, 19, ++ BUS_MSTOP(11, BIT(7))), ++ DEF_MOD("rsci4_ps_ps2_n", CLK_PLLCLN_DIV256, 7, 4, 3, 20, ++ BUS_MSTOP(11, BIT(7))), ++ DEF_MOD("rsci4_ps_ps1_n", CLK_PLLCLN_DIV64, 7, 5, 3, 21, ++ BUS_MSTOP(11, BIT(7))), ++ DEF_MOD("rsci5_pclk", CLK_PLLCLN_DIV16, 7, 6, 3, 22, ++ BUS_MSTOP(11, BIT(8))), ++ DEF_MOD("rsci5_tclk", CLK_PLLCLN_DIV16, 7, 7, 3, 23, ++ BUS_MSTOP(11, BIT(8))), ++ DEF_MOD("rsci5_ps_ps3_n", CLK_PLLCLN_DIV1024, 7, 8, 3, 24, ++ BUS_MSTOP(11, BIT(8))), ++ DEF_MOD("rsci5_ps_ps2_n", CLK_PLLCLN_DIV256, 7, 9, 3, 25, ++ BUS_MSTOP(11, BIT(8))), ++ DEF_MOD("rsci5_ps_ps1_n", CLK_PLLCLN_DIV64, 7, 10, 3, 26, ++ BUS_MSTOP(11, BIT(8))), ++ DEF_MOD("rsci6_pclk", CLK_PLLCLN_DIV16, 7, 11, 3, 27, ++ BUS_MSTOP(11, BIT(9))), ++ DEF_MOD("rsci6_tclk", CLK_PLLCLN_DIV16, 7, 12, 3, 28, ++ BUS_MSTOP(11, BIT(9))), ++ DEF_MOD("rsci6_ps_ps3_n", CLK_PLLCLN_DIV1024, 7, 13, 3, 29, ++ BUS_MSTOP(11, BIT(9))), ++ DEF_MOD("rsci6_ps_ps2_n", CLK_PLLCLN_DIV256, 7, 14, 3, 30, ++ BUS_MSTOP(11, BIT(9))), ++ DEF_MOD("rsci6_ps_ps1_n", CLK_PLLCLN_DIV64, 7, 15, 3, 31, ++ BUS_MSTOP(11, BIT(9))), ++ DEF_MOD("rsci7_pclk", CLK_PLLCLN_DIV16, 8, 0, 4, 0, ++ BUS_MSTOP(11, BIT(10))), ++ DEF_MOD("rsci7_tclk", CLK_PLLCLN_DIV16, 8, 1, 4, 1, ++ BUS_MSTOP(11, BIT(10))), ++ DEF_MOD("rsci7_ps_ps3_n", CLK_PLLCLN_DIV1024, 8, 2, 4, 2, ++ BUS_MSTOP(11, BIT(10))), ++ DEF_MOD("rsci7_ps_ps2_n", CLK_PLLCLN_DIV256, 8, 3, 4, 3, ++ BUS_MSTOP(11, BIT(10))), ++ DEF_MOD("rsci7_ps_ps1_n", CLK_PLLCLN_DIV64, 8, 4, 4, 4, ++ BUS_MSTOP(11, BIT(10))), ++ DEF_MOD("rsci8_pclk", CLK_PLLCLN_DIV16, 8, 5, 4, 5, ++ BUS_MSTOP(11, BIT(11))), ++ DEF_MOD("rsci8_tclk", CLK_PLLCLN_DIV16, 8, 6, 4, 6, ++ BUS_MSTOP(11, BIT(11))), ++ DEF_MOD("rsci8_ps_ps3_n", CLK_PLLCLN_DIV1024, 8, 7, 4, 7, ++ BUS_MSTOP(11, BIT(11))), ++ DEF_MOD("rsci8_ps_ps2_n", CLK_PLLCLN_DIV256, 8, 8, 4, 8, ++ BUS_MSTOP(11, BIT(11))), ++ DEF_MOD("rsci8_ps_ps1_n", CLK_PLLCLN_DIV64, 8, 9, 4, 9, ++ BUS_MSTOP(11, BIT(11))), ++ DEF_MOD("rsci9_pclk", CLK_PLLCLN_DIV16, 8, 10, 4, 10, ++ BUS_MSTOP(11, BIT(12))), ++ DEF_MOD("rsci9_tclk", CLK_PLLCLN_DIV16, 8, 11, 4, 11, ++ BUS_MSTOP(11, BIT(12))), ++ DEF_MOD("rsci9_ps_ps3_n", CLK_PLLCLN_DIV1024, 8, 12, 4, 12, ++ BUS_MSTOP(11, BIT(12))), ++ DEF_MOD("rsci9_ps_ps2_n", CLK_PLLCLN_DIV256, 8, 13, 4, 13, ++ BUS_MSTOP(11, BIT(12))), ++ DEF_MOD("rsci9_ps_ps1_n", CLK_PLLCLN_DIV64, 8, 14, 4, 14, ++ BUS_MSTOP(11, BIT(12))), + DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19, + BUS_MSTOP(3, BIT(11) | BIT(12))), + DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, +@@ -403,6 +509,26 @@ static const struct rzv2h_reset r9a09g057_resets[] __initconst = { + DEF_RST(7, 6, 3, 7), /* WDT_1_RESET */ + DEF_RST(7, 7, 3, 8), /* WDT_2_RESET */ + DEF_RST(7, 8, 3, 9), /* WDT_3_RESET */ ++ DEF_RST(8, 1, 3, 18), /* RSCI0_PRESETN */ ++ DEF_RST(8, 2, 3, 19), /* RSCI0_TRESETN */ ++ DEF_RST(8, 3, 3, 20), /* RSCI1_PRESETN */ ++ DEF_RST(8, 4, 3, 21), /* RSCI1_TRESETN */ ++ DEF_RST(8, 5, 3, 22), /* RSCI2_PRESETN */ ++ DEF_RST(8, 6, 3, 23), /* RSCI2_TRESETN */ ++ DEF_RST(8, 7, 3, 24), /* RSCI3_PRESETN */ ++ DEF_RST(8, 8, 3, 25), /* RSCI3_TRESETN */ ++ DEF_RST(8, 9, 3, 26), /* RSCI4_PRESETN */ ++ DEF_RST(8, 10, 3, 27), /* RSCI4_TRESETN */ ++ DEF_RST(8, 11, 3, 28), /* RSCI5_PRESETN */ ++ DEF_RST(8, 12, 3, 29), /* RSCI5_TRESETN */ ++ DEF_RST(8, 13, 3, 30), /* RSCI6_PRESETN */ ++ DEF_RST(8, 14, 3, 31), /* RSCI6_TRESETN */ ++ DEF_RST(8, 15, 4, 0), /* RSCI7_PRESETN */ ++ DEF_RST(9, 0, 4, 1), /* RSCI7_TRESETN */ ++ DEF_RST(9, 1, 4, 2), /* RSCI8_PRESETN */ ++ DEF_RST(9, 2, 4, 3), /* RSCI8_TRESETN */ ++ DEF_RST(9, 3, 4, 4), /* RSCI9_PRESETN */ ++ DEF_RST(9, 4, 4, 5), /* RSCI9_TRESETN */ + DEF_RST(7, 9, 3, 10), /* RTC_0_RST_RTC */ + DEF_RST(7, 10, 3, 11), /* RTC_0_RST_RTC_V */ + DEF_RST(7, 11, 3, 12), /* RSPI_0_PRESETN */ +-- +2.53.0 + diff --git a/queue-6.18/clk-renesas-r9a09g057-fix-ordering-of-module-clocks-.patch b/queue-6.18/clk-renesas-r9a09g057-fix-ordering-of-module-clocks-.patch new file mode 100644 index 0000000000..68e0608714 --- /dev/null +++ b/queue-6.18/clk-renesas-r9a09g057-fix-ordering-of-module-clocks-.patch @@ -0,0 +1,85 @@ +From 8004dff723f8d57cb74d09335e59a5acf3b66d40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Jan 2026 19:03:14 +0000 +Subject: clk: renesas: r9a09g057: Fix ordering of module clocks array + +From: Ovidiu Panait + +[ Upstream commit 79cac2b8dc1d9f63fbf6c6793e423052118cc51a ] + +The r9a09g057_mod_clks array is sorted by CPG_CLKON register number and +bit position. Move the RTC and RSPI module clock entries to their +correct position to restore the array sort order. + +Fixes: 2efea3b35cc9 ("clk: renesas: r9a09g057: Add entries for RSCIs") +Signed-off-by: Ovidiu Panait +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260125190314.26729-1-ovidiu.panait.rb@renesas.com +Signed-off-by: Geert Uytterhoeven +Stable-dep-of: 1b4f047dc401 ("clk: renesas: r9a09g057: Remove entries for WDT{0,2,3}") +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a09g057-cpg.c | 40 ++++++++++++++--------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c +index ac3d309365b45..647e394727f6b 100644 +--- a/drivers/clk/renesas/r9a09g057-cpg.c ++++ b/drivers/clk/renesas/r9a09g057-cpg.c +@@ -245,6 +245,26 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + BUS_MSTOP(5, BIT(13))), + DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18, + BUS_MSTOP(5, BIT(13))), ++ DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19, ++ BUS_MSTOP(3, BIT(11) | BIT(12))), ++ DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26, ++ BUS_MSTOP(11, BIT(2))), ++ DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27, ++ BUS_MSTOP(11, BIT(2))), ++ DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28, ++ BUS_MSTOP(11, BIT(2))), + DEF_MOD("rsci0_pclk", CLK_PLLCLN_DIV16, 5, 13, 2, 29, + BUS_MSTOP(11, BIT(3))), + DEF_MOD("rsci0_tclk", CLK_PLLCLN_DIV16, 5, 14, 2, 30, +@@ -345,26 +365,6 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + BUS_MSTOP(11, BIT(12))), + DEF_MOD("rsci9_ps_ps1_n", CLK_PLLCLN_DIV64, 8, 14, 4, 14, + BUS_MSTOP(11, BIT(12))), +- DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19, +- BUS_MSTOP(3, BIT(11) | BIT(12))), +- DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26, +- BUS_MSTOP(11, BIT(2))), +- DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27, +- BUS_MSTOP(11, BIT(2))), +- DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28, +- BUS_MSTOP(11, BIT(2))), + DEF_MOD("scif_0_clk_pck", CLK_PLLCM33_DIV16, 8, 15, 4, 15, + BUS_MSTOP(3, BIT(14))), + DEF_MOD("i3c_0_pclkrw", CLK_PLLCLN_DIV16, 9, 0, 4, 16, +-- +2.53.0 + diff --git a/queue-6.18/clk-renesas-r9a09g057-remove-entries-for-wdt-0-2-3.patch b/queue-6.18/clk-renesas-r9a09g057-remove-entries-for-wdt-0-2-3.patch new file mode 100644 index 0000000000..6fbdea78ae --- /dev/null +++ b/queue-6.18/clk-renesas-r9a09g057-remove-entries-for-wdt-0-2-3.patch @@ -0,0 +1,71 @@ +From 774c5ff9e2319213a5a3b6e78938314856138374 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 12:42:47 +0000 +Subject: clk: renesas: r9a09g057: Remove entries for WDT{0,2,3} + +From: Fabrizio Castro + +[ Upstream commit 1b4f047dc4010d51821694cc4ed73b52b3040a5c ] + +The HW user manual for the Renesas RZ/V2H(P) SoC specifies +that only the WDT1 IP is supposed to be used by Linux, +while the WDT{0,2,3} IPs are supposed to be used by the CM33 +and CR8 cores. + +Remove the clock and reset entries for WDT{0,2,3} to prevent +interfering with the CM33 and CR8 cores. + +This change is harmless as only WDT1 is used by Linux, there +are no users for the WDT{0,2,3} cores. + +Fixes: 3aeccbe08171 ("clk: renesas: r9a09g057: Add clock and reset entries for GTM/RIIC/SDHI/WDT") +Signed-off-by: Fabrizio Castro +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260203124247.7320-4-fabrizio.castro.jz@renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a09g057-cpg.c | 15 --------------- + 1 file changed, 15 deletions(-) + +diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c +index 647e394727f6b..5d799dd9fbfc1 100644 +--- a/drivers/clk/renesas/r9a09g057-cpg.c ++++ b/drivers/clk/renesas/r9a09g057-cpg.c +@@ -229,22 +229,10 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + BUS_MSTOP(11, BIT(15))), + DEF_MOD("gtm_7_pclk", CLK_PLLCLN_DIV16, 4, 10, 2, 10, + BUS_MSTOP(12, BIT(0))), +- DEF_MOD("wdt_0_clkp", CLK_PLLCM33_DIV16, 4, 11, 2, 11, +- BUS_MSTOP(3, BIT(10))), +- DEF_MOD("wdt_0_clk_loco", CLK_QEXTAL, 4, 12, 2, 12, +- BUS_MSTOP(3, BIT(10))), + DEF_MOD("wdt_1_clkp", CLK_PLLCLN_DIV16, 4, 13, 2, 13, + BUS_MSTOP(1, BIT(0))), + DEF_MOD("wdt_1_clk_loco", CLK_QEXTAL, 4, 14, 2, 14, + BUS_MSTOP(1, BIT(0))), +- DEF_MOD("wdt_2_clkp", CLK_PLLCLN_DIV16, 4, 15, 2, 15, +- BUS_MSTOP(5, BIT(12))), +- DEF_MOD("wdt_2_clk_loco", CLK_QEXTAL, 5, 0, 2, 16, +- BUS_MSTOP(5, BIT(12))), +- DEF_MOD("wdt_3_clkp", CLK_PLLCLN_DIV16, 5, 1, 2, 17, +- BUS_MSTOP(5, BIT(13))), +- DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18, +- BUS_MSTOP(5, BIT(13))), + DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19, + BUS_MSTOP(3, BIT(11) | BIT(12))), + DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, +@@ -505,10 +493,7 @@ static const struct rzv2h_reset r9a09g057_resets[] __initconst = { + DEF_RST(7, 2, 3, 3), /* GTM_5_PRESETZ */ + DEF_RST(7, 3, 3, 4), /* GTM_6_PRESETZ */ + DEF_RST(7, 4, 3, 5), /* GTM_7_PRESETZ */ +- DEF_RST(7, 5, 3, 6), /* WDT_0_RESET */ + DEF_RST(7, 6, 3, 7), /* WDT_1_RESET */ +- DEF_RST(7, 7, 3, 8), /* WDT_2_RESET */ +- DEF_RST(7, 8, 3, 9), /* WDT_3_RESET */ + DEF_RST(8, 1, 3, 18), /* RSCI0_PRESETN */ + DEF_RST(8, 2, 3, 19), /* RSCI0_TRESETN */ + DEF_RST(8, 3, 3, 20), /* RSCI1_PRESETN */ +-- +2.53.0 + diff --git a/queue-6.18/clk-spacemit-ccu_mix-fix-inverted-condition-in-ccu_m.patch b/queue-6.18/clk-spacemit-ccu_mix-fix-inverted-condition-in-ccu_m.patch new file mode 100644 index 0000000000..15b2207e49 --- /dev/null +++ b/queue-6.18/clk-spacemit-ccu_mix-fix-inverted-condition-in-ccu_m.patch @@ -0,0 +1,39 @@ +From 40a10113be45dedaed66ebf4153f7e602e5ca4b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:46:08 +0800 +Subject: clk: spacemit: ccu_mix: fix inverted condition in + ccu_mix_trigger_fc() + +From: Shuwei Wu + +[ Upstream commit 54e97360b44bed6b4399dd3be3d65f392df940fa ] + +Fix inverted condition that skips frequency change trigger, +causing kernel panics during cpufreq scaling. + +Fixes: 1b72c59db0ad ("clk: spacemit: Add clock support for SpacemiT K1 SoC") +Signed-off-by: Shuwei Wu +Reviewed-by: Yixun Lan +Link: https://lore.kernel.org/r/20260305-k1-clk-fix-v1-1-abca85d6e266@mailbox.org +Signed-off-by: Yixun Lan +Signed-off-by: Sasha Levin +--- + drivers/clk/spacemit/ccu_mix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/spacemit/ccu_mix.c b/drivers/clk/spacemit/ccu_mix.c +index 67f8b12b4f5b7..9a3fc9ea1ce56 100644 +--- a/drivers/clk/spacemit/ccu_mix.c ++++ b/drivers/clk/spacemit/ccu_mix.c +@@ -69,7 +69,7 @@ static int ccu_mix_trigger_fc(struct clk_hw *hw) + struct ccu_common *common = hw_to_ccu_common(hw); + unsigned int val; + +- if (common->reg_fc) ++ if (!common->reg_fc) + return 0; + + ccu_update(common, fc, common->mask_fc, common->mask_fc); +-- +2.53.0 + diff --git a/queue-6.18/clk-sunxi-ng-sun55i-a523-r-add-missing-r-spi-module-.patch b/queue-6.18/clk-sunxi-ng-sun55i-a523-r-add-missing-r-spi-module-.patch new file mode 100644 index 0000000000..939e550e89 --- /dev/null +++ b/queue-6.18/clk-sunxi-ng-sun55i-a523-r-add-missing-r-spi-module-.patch @@ -0,0 +1,71 @@ +From 0aa59a4980cfa4ae75cfd16a55a42f9f0dcff782 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 17:30:03 +0800 +Subject: clk: sunxi-ng: sun55i-a523-r: Add missing r-spi module clock + +From: Chen-Yu Tsai + +[ Upstream commit fb20ccf70cf695f178d7c32e2d33b376560df0ff ] + +When the PRCM clk driver was added, somehow the r-spi module clock +was skipped over. + +Add it so that r-spi can actually work. + +Fixes: 8cea339cfb81 ("clk: sunxi-ng: add support for the A523/T527 PRCM CCU") +Reviewed-by: Andre Przywara +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260217093004.3239051-1-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c +index 0339c4af0fe5b..db0e36d8838e7 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c ++++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c +@@ -83,9 +83,22 @@ static SUNXI_CCU_MUX_DATA_WITH_GATE(r_pwmctrl_clk, "r-pwmctrl", + static SUNXI_CCU_GATE_HW(bus_r_pwmctrl_clk, "bus-r-pwmctrl", + &r_apb0_clk.common.hw, 0x13c, BIT(0), 0); + +-/* SPI clock is /M/N (same as new MMC?) */ ++static const struct clk_parent_data r_spi_parents[] = { ++ { .fw_name = "hosc" }, ++ { .fw_name = "pll-periph" }, ++ { .name = "pll-periph0-300M" }, ++ { .name = "pll-periph1-300M" }, ++ { .name = "pll-audio" }, ++}; ++static SUNXI_CCU_DUALDIV_MUX_GATE(r_spi_clk, "r-spi", r_spi_parents, 0x150, ++ 0, 5, /* M */ ++ 8, 5, /* P */ ++ 24, 3, /* mux */ ++ BIT(31), /* gate */ ++ 0); + static SUNXI_CCU_GATE_HW(bus_r_spi_clk, "bus-r-spi", + &r_ahb_clk.common.hw, 0x15c, BIT(0), 0); ++ + static SUNXI_CCU_GATE_HW(bus_r_spinlock_clk, "bus-r-spinlock", + &r_ahb_clk.common.hw, 0x16c, BIT(0), 0); + static SUNXI_CCU_GATE_HW(bus_r_msgbox_clk, "bus-r-msgbox", +@@ -138,6 +151,7 @@ static struct ccu_common *sun55i_a523_r_ccu_clks[] = { + &bus_r_twd_clk.common, + &r_pwmctrl_clk.common, + &bus_r_pwmctrl_clk.common, ++ &r_spi_clk.common, + &bus_r_spi_clk.common, + &bus_r_spinlock_clk.common, + &bus_r_msgbox_clk.common, +@@ -169,6 +183,7 @@ static struct clk_hw_onecell_data sun55i_a523_r_hw_clks = { + [CLK_BUS_R_TWD] = &bus_r_twd_clk.common.hw, + [CLK_R_PWMCTRL] = &r_pwmctrl_clk.common.hw, + [CLK_BUS_R_PWMCTRL] = &bus_r_pwmctrl_clk.common.hw, ++ [CLK_R_SPI] = &r_spi_clk.common.hw, + [CLK_BUS_R_SPI] = &bus_r_spi_clk.common.hw, + [CLK_BUS_R_SPINLOCK] = &bus_r_spinlock_clk.common.hw, + [CLK_BUS_R_MSGBOX] = &bus_r_msgbox_clk.common.hw, +-- +2.53.0 + diff --git a/queue-6.18/clk-visconti-pll-initialize-clk_init_data-to-zero.patch b/queue-6.18/clk-visconti-pll-initialize-clk_init_data-to-zero.patch new file mode 100644 index 0000000000..8dd0711581 --- /dev/null +++ b/queue-6.18/clk-visconti-pll-initialize-clk_init_data-to-zero.patch @@ -0,0 +1,52 @@ +From 1fdfb3041b33d66fa552b9f045377807946588e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 10:32:37 -0400 +Subject: clk: visconti: pll: initialize clk_init_data to zero +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 1603cbb64173a0e9fa7500f2a686f4aa011c58b9 ] + +Sashiko reported the following: + +> The struct clk_init_data init is declared on the stack without being +> fully zero-initialized. While fields like name, flags, parent_names, +> num_parents, and ops are explicitly assigned, the parent_data and +> parent_hws fields are left containing stack garbage. + +clk_core_populate_parent_map() currently prefers the parent names over +the parent data and hws, so this isn't a problem at the moment. If that +ordering ever changed in the future, then this could lead to some +unexpected crashes. Let's just go ahead and make sure that the struct +clk_init_data is initialized to zero as a good practice. + +Fixes: b4cbe606dc367 ("clk: visconti: Add support common clock driver and reset driver") +Link: https://sashiko.dev/#/patchset/20260326042317.122536-1-rosenp%40gmail.com +Signed-off-by: Brian Masney +Reviewed-by: Benoît Monin +Reviewed-by: Nobuhiro Iwamatsu +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/visconti/pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c +index 681721d850320..9d088239a1b2c 100644 +--- a/drivers/clk/visconti/pll.c ++++ b/drivers/clk/visconti/pll.c +@@ -249,7 +249,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, + const struct visconti_pll_rate_table *rate_table, + spinlock_t *lock) + { +- struct clk_init_data init; ++ struct clk_init_data init = {}; + struct visconti_pll *pll; + struct clk_hw *pll_hw_clk; + size_t len; +-- +2.53.0 + diff --git a/queue-6.18/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch b/queue-6.18/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch new file mode 100644 index 0000000000..7845c626f9 --- /dev/null +++ b/queue-6.18/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch @@ -0,0 +1,37 @@ +From 843aa83a516c14a50a8ae4b93a0ba64d344bfc16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:11:16 +0100 +Subject: clk: xgene: Fix mapping leak in xgene_pllclk_init() + +From: Geert Uytterhoeven + +[ Upstream commit f520a492e07bc6718e26cfb7543ab4cadd8bb0e2 ] + +If xgene_register_clk_pll() fails, the mapped register block is never +unmapped. + +Fixes: 308964caeebc45eb ("clk: Add APM X-Gene SoC clock driver") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-xgene.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c +index 92e39f3237c2f..7dc247eb880fb 100644 +--- a/drivers/clk/clk-xgene.c ++++ b/drivers/clk/clk-xgene.c +@@ -188,6 +188,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); ++ } else { ++ iounmap(reg); + } + } + +-- +2.53.0 + diff --git a/queue-6.18/cpufreq-pass-the-policy-to-cpufreq_driver-adjust_per.patch b/queue-6.18/cpufreq-pass-the-policy-to-cpufreq_driver-adjust_per.patch new file mode 100644 index 0000000000..c4d5624b1c --- /dev/null +++ b/queue-6.18/cpufreq-pass-the-policy-to-cpufreq_driver-adjust_per.patch @@ -0,0 +1,193 @@ +From 813a9a3a5a6d13086a81adebb70e05c1aa8d066f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 08:18:49 +0000 +Subject: cpufreq: Pass the policy to cpufreq_driver->adjust_perf() + +From: K Prateek Nayak + +[ Upstream commit c03791085adcd61fa9b766ab303c7d0941d7378d ] + +cpufreq_cpu_get() can sleep on PREEMPT_RT in presence of concurrent +writer(s), however amd-pstate depends on fetching the cpudata via the +policy's driver data which necessitates grabbing the reference. + +Since schedutil governor can call "cpufreq_driver->update_perf()" +during sched_tick/enqueue/dequeue with rq_lock held and IRQs disabled, +fetching the policy object using the cpufreq_cpu_get() helper in the +scheduler fast-path leads to "BUG: scheduling while atomic" on +PREEMPT_RT [1]. + +Pass the cached cpufreq policy object in sg_policy to the update_perf() +instead of just the CPU. The CPU can be inferred using "policy->cpu". + +The lifetime of cpufreq_policy object outlasts that of the governor and +the cpufreq driver (allocated when the CPU is onlined and only reclaimed +when the CPU is offlined / the CPU device is removed) which makes it +safe to be referenced throughout the governor's lifetime. + +Closes:https://lore.kernel.org/all/20250731092316.3191-1-spasswolf@web.de/ [1] + +Fixes: 1d215f0319c2 ("cpufreq: amd-pstate: Add fast switch function for AMD P-State") +Reported-by: Bert Karwatzki +Acked-by: Viresh Kumar +Signed-off-by: K Prateek Nayak +Acked-by: Gary Guo # Rust +Reviewed-by: Gautham R. Shenoy +Reviewed-by: Zhongqiu Han +Link: https://lore.kernel.org/r/20260316081849.19368-3-kprateek.nayak@amd.com +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/amd-pstate.c | 3 +-- + drivers/cpufreq/cpufreq.c | 6 +++--- + drivers/cpufreq/intel_pstate.c | 4 ++-- + include/linux/cpufreq.h | 4 ++-- + kernel/sched/cpufreq_schedutil.c | 5 +++-- + rust/kernel/cpufreq.rs | 13 ++++++------- + 6 files changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c +index 39681ad1606f6..ce6d6b3ff58a3 100644 +--- a/drivers/cpufreq/amd-pstate.c ++++ b/drivers/cpufreq/amd-pstate.c +@@ -697,13 +697,12 @@ static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy, + return policy->cur; + } + +-static void amd_pstate_adjust_perf(unsigned int cpu, ++static void amd_pstate_adjust_perf(struct cpufreq_policy *policy, + unsigned long _min_perf, + unsigned long target_perf, + unsigned long capacity) + { + u8 max_perf, min_perf, des_perf, cap_perf; +- struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); + struct amd_cpudata *cpudata; + union perf_cached perf; + +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 852e024facc3c..1ed528e34bab4 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -2222,7 +2222,7 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch); + + /** + * cpufreq_driver_adjust_perf - Adjust CPU performance level in one go. +- * @cpu: Target CPU. ++ * @policy: cpufreq policy object of the target CPU. + * @min_perf: Minimum (required) performance level (units of @capacity). + * @target_perf: Target (desired) performance level (units of @capacity). + * @capacity: Capacity of the target CPU. +@@ -2241,12 +2241,12 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch); + * parallel with either ->target() or ->target_index() or ->fast_switch() for + * the same CPU. + */ +-void cpufreq_driver_adjust_perf(unsigned int cpu, ++void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy, + unsigned long min_perf, + unsigned long target_perf, + unsigned long capacity) + { +- cpufreq_driver->adjust_perf(cpu, min_perf, target_perf, capacity); ++ cpufreq_driver->adjust_perf(policy, min_perf, target_perf, capacity); + } + + /** +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index 5efda8af4b708..eb7fb25dfbefc 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -3270,12 +3270,12 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, + return target_pstate * cpu->pstate.scaling; + } + +-static void intel_cpufreq_adjust_perf(unsigned int cpunum, ++static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy, + unsigned long min_perf, + unsigned long target_perf, + unsigned long capacity) + { +- struct cpudata *cpu = all_cpu_data[cpunum]; ++ struct cpudata *cpu = all_cpu_data[policy->cpu]; + u64 hwp_cap = READ_ONCE(cpu->hwp_cap_cached); + int old_pstate = cpu->pstate.current_pstate; + int cap_pstate, min_pstate, max_pstate, target_pstate; +diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h +index 0465d1e6f72ac..fd26b3a4aa286 100644 +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -367,7 +367,7 @@ struct cpufreq_driver { + * conditions) scale invariance can be disabled, which causes the + * schedutil governor to fall back to the latter. + */ +- void (*adjust_perf)(unsigned int cpu, ++ void (*adjust_perf)(struct cpufreq_policy *policy, + unsigned long min_perf, + unsigned long target_perf, + unsigned long capacity); +@@ -612,7 +612,7 @@ struct cpufreq_governor { + /* Pass a target to the cpufreq driver */ + unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq); +-void cpufreq_driver_adjust_perf(unsigned int cpu, ++void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy, + unsigned long min_perf, + unsigned long target_perf, + unsigned long capacity); +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index 0ab5f9d4bc59a..307f3076635eb 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -461,6 +461,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time, + unsigned int flags) + { + struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util); ++ struct sugov_policy *sg_policy = sg_cpu->sg_policy; + unsigned long prev_util = sg_cpu->util; + unsigned long max_cap; + +@@ -482,10 +483,10 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time, + if (sugov_hold_freq(sg_cpu) && sg_cpu->util < prev_util) + sg_cpu->util = prev_util; + +- cpufreq_driver_adjust_perf(sg_cpu->cpu, sg_cpu->bw_min, ++ cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min, + sg_cpu->util, max_cap); + +- sg_cpu->sg_policy->last_freq_update_time = time; ++ sg_policy->last_freq_update_time = time; + } + + static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time) +diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs +index df5d9f6f43f3b..19729ccb3f6d2 100644 +--- a/rust/kernel/cpufreq.rs ++++ b/rust/kernel/cpufreq.rs +@@ -1257,18 +1257,17 @@ impl Registration { + /// # Safety + /// + /// - This function may only be called from the cpufreq C infrastructure. ++ /// - The pointer arguments must be valid pointers. + unsafe extern "C" fn adjust_perf_callback( +- cpu: c_uint, ++ ptr: *mut bindings::cpufreq_policy, + min_perf: c_ulong, + target_perf: c_ulong, + capacity: c_ulong, + ) { +- // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. +- let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) }; +- +- if let Ok(mut policy) = PolicyCpu::from_cpu(cpu_id) { +- T::adjust_perf(&mut policy, min_perf, target_perf, capacity); +- } ++ // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the ++ // lifetime of `policy`. ++ let policy = unsafe { Policy::from_raw_mut(ptr) }; ++ T::adjust_perf(policy, min_perf, target_perf, capacity); + } + + /// Driver's `get_intermediate` callback. +-- +2.53.0 + diff --git a/queue-6.18/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch b/queue-6.18/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch new file mode 100644 index 0000000000..599d9eeeda --- /dev/null +++ b/queue-6.18/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch @@ -0,0 +1,49 @@ +From 65fd31bb6fc01b28161d0dff20f3eea21a71f035 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 12:39:28 +0100 +Subject: crypto: atmel-aes - guard unregister on error in + atmel_aes_register_algs + +From: Thorsten Blum + +[ Upstream commit 57a13941c0bb06ae24e3b34672d7b6f2172b253f ] + +Ensure the device supports XTS and GCM with 'has_xts' and 'has_gcm' +before unregistering algorithms when XTS or authenc registration fails, +which would trigger a WARN in crypto_unregister_alg(). + +Currently, with the capabilities defined in atmel_aes_get_cap(), this +bug cannot happen because all devices that support XTS and authenc also +support GCM, but the error handling should still be correct regardless +of hardware capabilities. + +Fixes: d52db5188a87 ("crypto: atmel-aes - add support to the XTS mode") +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/atmel-aes.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c +index 9b0cb97055dc5..b393689400b4c 100644 +--- a/drivers/crypto/atmel-aes.c ++++ b/drivers/crypto/atmel-aes.c +@@ -2270,10 +2270,12 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + /* i = ARRAY_SIZE(aes_authenc_algs); */ + err_aes_authenc_alg: + crypto_unregister_aeads(aes_authenc_algs, i); +- crypto_unregister_skcipher(&aes_xts_alg); ++ if (dd->caps.has_xts) ++ crypto_unregister_skcipher(&aes_xts_alg); + #endif + err_aes_xts_alg: +- crypto_unregister_aead(&aes_gcm_alg); ++ if (dd->caps.has_gcm) ++ crypto_unregister_aead(&aes_gcm_alg); + err_aes_gcm_alg: + i = ARRAY_SIZE(aes_algs); + err_aes_algs: +-- +2.53.0 + diff --git a/queue-6.18/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch b/queue-6.18/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch new file mode 100644 index 0000000000..78e1457ef8 --- /dev/null +++ b/queue-6.18/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch @@ -0,0 +1,205 @@ +From 81190bab5d84e45ed874c3d8550525052cb158f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 18:47:03 +0100 +Subject: crypto: atmel - Use unregister_{aeads,ahashes,skciphers} + +From: Thorsten Blum + +[ Upstream commit 2ffc1ef4e826f0c3274f9ff5eb42bc70a5571afd ] + +Replace multiple for loops with calls to crypto_unregister_aeads(), +crypto_unregister_ahashes(), and crypto_unregister_skciphers(). + +Remove the definition of atmel_tdes_unregister_algs() because it is +equivalent to calling crypto_unregister_skciphers() directly, and the +function parameter 'struct atmel_tdes_dev *' is unused anyway. + +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Stable-dep-of: 57a13941c0bb ("crypto: atmel-aes - guard unregister on error in atmel_aes_register_algs") +Signed-off-by: Sasha Levin +--- + drivers/crypto/atmel-aes.c | 17 ++++++----------- + drivers/crypto/atmel-sha.c | 27 ++++++++++----------------- + drivers/crypto/atmel-tdes.c | 25 ++++++------------------- + 3 files changed, 22 insertions(+), 47 deletions(-) + +diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c +index 5a6d64be81858..9b0cb97055dc5 100644 +--- a/drivers/crypto/atmel-aes.c ++++ b/drivers/crypto/atmel-aes.c +@@ -2201,12 +2201,10 @@ static irqreturn_t atmel_aes_irq(int irq, void *dev_id) + + static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) + { +- int i; +- + #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) + if (dd->caps.has_authenc) +- for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++) +- crypto_unregister_aead(&aes_authenc_algs[i]); ++ crypto_unregister_aeads(aes_authenc_algs, ++ ARRAY_SIZE(aes_authenc_algs)); + #endif + + if (dd->caps.has_xts) +@@ -2215,8 +2213,7 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) + if (dd->caps.has_gcm) + crypto_unregister_aead(&aes_gcm_alg); + +- for (i = 0; i < ARRAY_SIZE(aes_algs); i++) +- crypto_unregister_skcipher(&aes_algs[i]); ++ crypto_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs)); + } + + static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) +@@ -2229,7 +2226,7 @@ static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) + + static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { + atmel_aes_crypto_alg_init(&aes_algs[i].base); +@@ -2272,8 +2269,7 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) + /* i = ARRAY_SIZE(aes_authenc_algs); */ + err_aes_authenc_alg: +- for (j = 0; j < i; j++) +- crypto_unregister_aead(&aes_authenc_algs[j]); ++ crypto_unregister_aeads(aes_authenc_algs, i); + crypto_unregister_skcipher(&aes_xts_alg); + #endif + err_aes_xts_alg: +@@ -2281,8 +2277,7 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + err_aes_gcm_alg: + i = ARRAY_SIZE(aes_algs); + err_aes_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_skcipher(&aes_algs[j]); ++ crypto_unregister_skciphers(aes_algs, i); + + return err; + } +diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c +index 3d7573c7bd1ca..b02a71061708c 100644 +--- a/drivers/crypto/atmel-sha.c ++++ b/drivers/crypto/atmel-sha.c +@@ -2418,27 +2418,23 @@ EXPORT_SYMBOL_GPL(atmel_sha_authenc_abort); + + static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) + { +- int i; +- + if (dd->caps.has_hmac) +- for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) +- crypto_unregister_ahash(&sha_hmac_algs[i]); ++ crypto_unregister_ahashes(sha_hmac_algs, ++ ARRAY_SIZE(sha_hmac_algs)); + +- for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) +- crypto_unregister_ahash(&sha_1_256_algs[i]); ++ crypto_unregister_ahashes(sha_1_256_algs, ARRAY_SIZE(sha_1_256_algs)); + + if (dd->caps.has_sha224) + crypto_unregister_ahash(&sha_224_alg); + +- if (dd->caps.has_sha_384_512) { +- for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) +- crypto_unregister_ahash(&sha_384_512_algs[i]); +- } ++ if (dd->caps.has_sha_384_512) ++ crypto_unregister_ahashes(sha_384_512_algs, ++ ARRAY_SIZE(sha_384_512_algs)); + } + + static int atmel_sha_register_algs(struct atmel_sha_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) { + atmel_sha_alg_init(&sha_1_256_algs[i]); +@@ -2480,18 +2476,15 @@ static int atmel_sha_register_algs(struct atmel_sha_dev *dd) + + /*i = ARRAY_SIZE(sha_hmac_algs);*/ + err_sha_hmac_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_hmac_algs[j]); ++ crypto_unregister_ahashes(sha_hmac_algs, i); + i = ARRAY_SIZE(sha_384_512_algs); + err_sha_384_512_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_384_512_algs[j]); ++ crypto_unregister_ahashes(sha_384_512_algs, i); + crypto_unregister_ahash(&sha_224_alg); + err_sha_224_algs: + i = ARRAY_SIZE(sha_1_256_algs); + err_sha_1_256_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_1_256_algs[j]); ++ crypto_unregister_ahashes(sha_1_256_algs, i); + + return err; + } +diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c +index d3bd8b72c2c95..643e507f9c020 100644 +--- a/drivers/crypto/atmel-tdes.c ++++ b/drivers/crypto/atmel-tdes.c +@@ -897,38 +897,25 @@ static irqreturn_t atmel_tdes_irq(int irq, void *dev_id) + return IRQ_NONE; + } + +-static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) +- crypto_unregister_skcipher(&tdes_algs[i]); +-} +- + static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) { + atmel_tdes_skcipher_alg_init(&tdes_algs[i]); + + err = crypto_register_skcipher(&tdes_algs[i]); +- if (err) +- goto err_tdes_algs; ++ if (err) { ++ crypto_unregister_skciphers(tdes_algs, i); ++ return err; ++ } + } + + return 0; +- +-err_tdes_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_skcipher(&tdes_algs[j]); +- +- return err; + } + + static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd) + { +- + dd->caps.has_dma = 0; + + /* keep only major version number */ +@@ -1061,7 +1048,7 @@ static void atmel_tdes_remove(struct platform_device *pdev) + list_del(&tdes_dd->list); + spin_unlock(&atmel_tdes.lock); + +- atmel_tdes_unregister_algs(tdes_dd); ++ crypto_unregister_skciphers(tdes_algs, ARRAY_SIZE(tdes_algs)); + + tasklet_kill(&tdes_dd->done_task); + tasklet_kill(&tdes_dd->queue_task); +-- +2.53.0 + diff --git a/queue-6.18/crypto-ccp-copy-iv-using-skcipher-ivsize.patch b/queue-6.18/crypto-ccp-copy-iv-using-skcipher-ivsize.patch new file mode 100644 index 0000000000..338b58a664 --- /dev/null +++ b/queue-6.18/crypto-ccp-copy-iv-using-skcipher-ivsize.patch @@ -0,0 +1,47 @@ +From 5dabd5124298364ef79f4fb8cc11da83acc9efe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 03:07:49 -0500 +Subject: crypto: ccp - copy IV using skcipher ivsize + +From: Paul Moses + +[ Upstream commit a7a1f3cdd64d8a165d9b8c9e9ad7fb46ac19dfc4 ] + +AF_ALG rfc3686-ctr-aes-ccp requests pass an 8-byte IV to the driver. + +ccp_aes_complete() restores AES_BLOCK_SIZE bytes into the caller's IV +buffer while RFC3686 skciphers expose an 8-byte IV, so the restore +overruns the provided buffer. + +Use crypto_skcipher_ivsize() to copy only the algorithm's IV length. + +Fixes: 2b789435d7f3 ("crypto: ccp - CCP AES crypto API support") +Signed-off-by: Paul Moses +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-crypto-aes.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c +index 685d42ec7adea..b5be3af8b2fe5 100644 +--- a/drivers/crypto/ccp/ccp-crypto-aes.c ++++ b/drivers/crypto/ccp/ccp-crypto-aes.c +@@ -30,8 +30,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) + if (ret) + return ret; + +- if (ctx->u.aes.mode != CCP_AES_MODE_ECB) +- memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE); ++ if (ctx->u.aes.mode != CCP_AES_MODE_ECB) { ++ size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); ++ ++ memcpy(req->iv, rctx->iv, ivsize); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/crypto-eip93-fix-hmac-setkey-algo-selection.patch b/queue-6.18/crypto-eip93-fix-hmac-setkey-algo-selection.patch new file mode 100644 index 0000000000..2c3c4b74c4 --- /dev/null +++ b/queue-6.18/crypto-eip93-fix-hmac-setkey-algo-selection.patch @@ -0,0 +1,93 @@ +From ac5a3e8bf14c0cf8050f4d3e6d3945cab88522a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 23:08:17 +0200 +Subject: crypto: eip93 - fix hmac setkey algo selection + +From: Aleksander Jan Bajkowski + +[ Upstream commit 3ba3b02f897b14e34977e1886d95ffe64d907204 ] + +eip93_hmac_setkey() allocates a temporary ahash transform for +computing HMAC ipad/opad key material. The allocation uses the +driver-specific cra_driver_name (e.g. "sha256-eip93") but passes +CRYPTO_ALG_ASYNC as the mask, which excludes async algorithms. + +Since the EIP93 hash algorithms are the only ones registered +under those driver names and they are inherently async, the +lookup is self-contradictory and always fails with -ENOENT. + +When called from the AEAD setkey path, this failure leaves the +SA record partially initialized with zeroed digest fields. A +subsequent crypto operation then dereferences a NULL pointer in +the request context, resulting in a kernel panic: + +``` + pc : eip93_aead_handle_result+0xc8c/0x1240 [crypto_hw_eip93] + lr : eip93_aead_handle_result+0xbec/0x1240 [crypto_hw_eip93] + sp : ffffffc082feb820 + x29: ffffffc082feb820 x28: ffffff8011043980 x27: 0000000000000000 + x26: 0000000000000000 x25: ffffffc078da0bc8 x24: 0000000091043980 + x23: ffffff8004d59e50 x22: ffffff8004d59410 x21: ffffff8004d593c0 + x20: ffffff8004d593c0 x19: ffffff8004d4f300 x18: 0000000000000000 + x17: 0000000000000000 x16: 0000000000000000 x15: 0000007fda7aa498 + x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 + x11: 0000000000000000 x10: fffffffff8127a80 x9 : 0000000000000000 + x8 : ffffff8004d4f380 x7 : 0000000000000000 x6 : 000000000000003f + x5 : 0000000000000040 x4 : 0000000000000008 x3 : 0000000000000009 + x2 : 0000000000000008 x1 : 0000000028000003 x0 : ffffff8004d388c0 + Code: 910142b6 f94012e0 f9002aa0 f90006d3 (f9400740) +``` + +The reported symbol eip93_aead_handle_result+0xc8c is a +resolution artifact from static functions being merged under +the nearest exported symbol. Decoding the faulting sequence: + +``` + 910142b6 ADD X22, X21, #0x50 + f94012e0 LDR X0, [X23, #0x20] + f9002aa0 STR X0, [X21, #0x50] + f90006d3 STR X19, [X22, #0x8] + f9400740 LDR X0, [X26, #0x8] +``` + +The faulting LDR at [X26, #0x8] is loading ctx->flags +(offset 8 in eip93_hash_ctx), where ctx has been resolved +to NULL from a partially initialized or unreachable +transform context following the failed setkey. + +Fix this by dropping the CRYPTO_ALG_ASYNC mask from the +crypto_alloc_ahash() call. The code already handles async +completion correctly via crypto_wait_req(), so there is no +requirement to restrict the lookup to synchronous algorithms. + +Note that hashing a single 64-byte block through the hardware +is likely slower than doing it in software due to the DMA +round-trip overhead, but offloading it may still spare CPU +cycles on the slower embedded cores where this IP is found. + +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +[Detailed investigation report of this bug] +Signed-off-by: Kenneth Kasilag +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/inside-secure/eip93/eip93-common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-common.c b/drivers/crypto/inside-secure/eip93/eip93-common.c +index 66153aa2493f2..43a2df542583b 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-common.c ++++ b/drivers/crypto/inside-secure/eip93/eip93-common.c +@@ -731,7 +731,7 @@ int eip93_hmac_setkey(u32 ctx_flags, const u8 *key, unsigned int keylen, + return -EINVAL; + } + +- ahash_tfm = crypto_alloc_ahash(alg_name, 0, CRYPTO_ALG_ASYNC); ++ ahash_tfm = crypto_alloc_ahash(alg_name, 0, 0); + if (IS_ERR(ahash_tfm)) + return PTR_ERR(ahash_tfm); + +-- +2.53.0 + diff --git a/queue-6.18/crypto-hisilicon-sec2-prevent-req-used-after-free-fo.patch b/queue-6.18/crypto-hisilicon-sec2-prevent-req-used-after-free-fo.patch new file mode 100644 index 0000000000..9bf61ac167 --- /dev/null +++ b/queue-6.18/crypto-hisilicon-sec2-prevent-req-used-after-free-fo.patch @@ -0,0 +1,41 @@ +From 8960b6ab777d6acb07be40dd56790cfbea24efef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 15:00:38 +0800 +Subject: crypto: hisilicon/sec2 - prevent req used-after-free for sec + +From: Wenkai Lin + +[ Upstream commit 67b53a660e6bf0da2fa8d8872e897a14d8059eaf ] + +During packet transmission, if the system is under heavy load, +the hardware might complete processing the packet and free the +request memory (req) before the transmission function finishes. +If the software subsequently accesses this req, a use-after-free +error will occur. The qp_ctx memory exists throughout the packet +sending process, so replace the req with the qp_ctx. + +Fixes: f0ae287c5045 ("crypto: hisilicon/sec2 - implement full backlog mode for sec") +Signed-off-by: Wenkai Lin +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index c462b58d30343..2d0b248c59ebd 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -230,7 +230,7 @@ static int qp_send_message(struct sec_req *req) + + spin_unlock_bh(&qp_ctx->req_lock); + +- atomic64_inc(&req->ctx->sec->debug.dfx.send_cnt); ++ atomic64_inc(&qp_ctx->ctx->sec->debug.dfx.send_cnt); + return -EINPROGRESS; + } + +-- +2.53.0 + diff --git a/queue-6.18/crypto-iaa-fix-per-node-cpu-counter-reset-in-rebalan.patch b/queue-6.18/crypto-iaa-fix-per-node-cpu-counter-reset-in-rebalan.patch new file mode 100644 index 0000000000..d4e8e9bd5a --- /dev/null +++ b/queue-6.18/crypto-iaa-fix-per-node-cpu-counter-reset-in-rebalan.patch @@ -0,0 +1,46 @@ +From 041714122f85bc6df20200d91609d107f99d7281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 18:29:05 +0000 +Subject: crypto: iaa - fix per-node CPU counter reset in rebalance_wq_table() + +From: Giovanni Cabiddu + +[ Upstream commit 590fa5d69c27cfaecd2e8287aec78f902417c877 ] + +The cpu counter used to compute the IAA device index is reset to zero +at the start of each NUMA node iteration. This causes CPUs on every +node to map starting from IAA index 0 instead of continuing from the +previous node's last index. On multi-node systems, this results in all +nodes mapping their CPUs to the same initial set of IAA devices, +leaving higher-indexed devices unused. + +Move the cpu counter initialization before the for_each_node_with_cpus() +loop so that the IAA index computation accumulates correctly across all +nodes. + +Fixes: 714ca27e9bf4 ("crypto: iaa - Optimize rebalance_wq_table()") +Signed-off-by: Giovanni Cabiddu +Acked-by: Vinicius Costa Gomes +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/intel/iaa/iaa_crypto_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c +index da9b2bc515194..78218f3a3cd06 100644 +--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c ++++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c +@@ -911,8 +911,8 @@ static void rebalance_wq_table(void) + return; + } + ++ cpu = 0; + for_each_node_with_cpus(node) { +- cpu = 0; + node_cpus = cpumask_of_node(node); + + for_each_cpu(node_cpu, node_cpus) { +-- +2.53.0 + diff --git a/queue-6.18/crypto-inside-secure-eip93-fix-register-definition.patch b/queue-6.18/crypto-inside-secure-eip93-fix-register-definition.patch new file mode 100644 index 0000000000..ec935cf0f9 --- /dev/null +++ b/queue-6.18/crypto-inside-secure-eip93-fix-register-definition.patch @@ -0,0 +1,39 @@ +From 2842c112d7320ea1f68fdf97ace639293f5a9703 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Feb 2026 11:35:53 +0100 +Subject: crypto: inside-secure/eip93 - fix register definition + +From: Aleksander Jan Bajkowski + +[ Upstream commit b7abbc8c7acaeb60c114b038f1fa91bbedb3d16a ] + +Checked the register definitions with the documentation[1]. Turns out +that the PKTE_INBUF_CNT register has a bad offset. It's used in Direct +Host Mode (DHM). The driver uses Autonomous Ring Mode (ARM), so it +causes no harm. + +1. ADSP-SC58x/ADSP-2158x SHARC+ Processor Hardware Reference +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/inside-secure/eip93/eip93-regs.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-regs.h b/drivers/crypto/inside-secure/eip93/eip93-regs.h +index 0490b8d151311..116b3fbb6ad79 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-regs.h ++++ b/drivers/crypto/inside-secure/eip93/eip93-regs.h +@@ -109,7 +109,7 @@ + #define EIP93_REG_PE_BUF_THRESH 0x10c + #define EIP93_PE_OUTBUF_THRESH GENMASK(23, 16) + #define EIP93_PE_INBUF_THRESH GENMASK(7, 0) +-#define EIP93_REG_PE_INBUF_COUNT 0x100 ++#define EIP93_REG_PE_INBUF_COUNT 0x110 + #define EIP93_REG_PE_OUTBUF_COUNT 0x114 + #define EIP93_REG_PE_BUF_RW_PNTR 0x118 /* BUF_PNTR */ + +-- +2.53.0 + diff --git a/queue-6.18/crypto-inside-secure-eip93-register-hash-before-auth.patch b/queue-6.18/crypto-inside-secure-eip93-register-hash-before-auth.patch new file mode 100644 index 0000000000..7fe5f538c6 --- /dev/null +++ b/queue-6.18/crypto-inside-secure-eip93-register-hash-before-auth.patch @@ -0,0 +1,67 @@ +From 6d92cba1378483a505d7e5f8593a9aaca64085fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 23:17:40 +0100 +Subject: crypto: inside-secure/eip93 - register hash before authenc algorithms + +From: Aleksander Jan Bajkowski + +[ Upstream commit 5377032914b29b4643adece0ff1dfc67e36700f4 ] + +Register hash before hmac and authenc algorithms. This will ensure +selftests pass at startup. Previously, selftests failed on the +crypto_alloc_ahash() function since the associated algorithm was +not yet registered. + +Fixes following error: +... +[ 18.375811] alg: self-tests for authenc(hmac(sha1),cbc(aes)) using authenc(hmac(sha1-eip93),cbc(aes-eip93)) failed (rc=-2) +[ 18.382140] alg: self-tests for authenc(hmac(sha224),rfc3686(ctr(aes))) using authenc(hmac(sha224-eip93),rfc3686(ctr(aes-eip93))) failed (rc=-2) +[ 18.395029] alg: aead: authenc(hmac(sha256-eip93),cbc(des-eip93)) setkey failed on test vector 0; expected_error=0, actual_error=-2, flags=0x1 +[ 18.409734] alg: aead: authenc(hmac(md5-eip93),cbc(des3_ede-eip93)) setkey failed on test vector 0; expected_error=0, actual_error=-2, flags=0x1 +... + +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/inside-secure/eip93/eip93-main.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c +index b7fd9795062d4..76858bb4fcc22 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-main.c ++++ b/drivers/crypto/inside-secure/eip93/eip93-main.c +@@ -36,6 +36,14 @@ static struct eip93_alg_template *eip93_algs[] = { + &eip93_alg_cbc_aes, + &eip93_alg_ctr_aes, + &eip93_alg_rfc3686_aes, ++ &eip93_alg_md5, ++ &eip93_alg_sha1, ++ &eip93_alg_sha224, ++ &eip93_alg_sha256, ++ &eip93_alg_hmac_md5, ++ &eip93_alg_hmac_sha1, ++ &eip93_alg_hmac_sha224, ++ &eip93_alg_hmac_sha256, + &eip93_alg_authenc_hmac_md5_cbc_des, + &eip93_alg_authenc_hmac_sha1_cbc_des, + &eip93_alg_authenc_hmac_sha224_cbc_des, +@@ -52,14 +60,6 @@ static struct eip93_alg_template *eip93_algs[] = { + &eip93_alg_authenc_hmac_sha1_rfc3686_aes, + &eip93_alg_authenc_hmac_sha224_rfc3686_aes, + &eip93_alg_authenc_hmac_sha256_rfc3686_aes, +- &eip93_alg_md5, +- &eip93_alg_sha1, +- &eip93_alg_sha224, +- &eip93_alg_sha256, +- &eip93_alg_hmac_md5, +- &eip93_alg_hmac_sha1, +- &eip93_alg_hmac_sha224, +- &eip93_alg_hmac_sha256, + }; + + inline void eip93_irq_disable(struct eip93_device *eip93, u32 mask) +-- +2.53.0 + diff --git a/queue-6.18/crypto-jitterentropy-replace-long-held-spinlock-with.patch b/queue-6.18/crypto-jitterentropy-replace-long-held-spinlock-with.patch new file mode 100644 index 0000000000..719b4c15af --- /dev/null +++ b/queue-6.18/crypto-jitterentropy-replace-long-held-spinlock-with.patch @@ -0,0 +1,109 @@ +From dfbe240c1df3fea609246d50de1fafbae2228046 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:23:46 +0800 +Subject: crypto: jitterentropy - replace long-held spinlock with mutex + +From: Haixin Xu + +[ Upstream commit 01d798e9feb30212952d4e992801ba6bd6a82351 ] + +jent_kcapi_random() serializes the shared jitterentropy state, but it +currently holds a spinlock across the jent_read_entropy() call. That +path performs expensive jitter collection and SHA3 conditioning, so +parallel readers can trigger stalls as contending waiters spin for +the same lock. + +To prevent non-preemptible lock hold, replace rng->jent_lock with a +mutex so contended readers sleep instead of spinning on a shared lock +held across expensive entropy generation. + +Fixes: bb5530e40824 ("crypto: jitterentropy - add jitterentropy RNG") +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Haixin Xu +Reviewed-by: Stephan Mueller +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/jitterentropy-kcapi.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c +index a53de7affe8d1..e9cd2b27d1e3c 100644 +--- a/crypto/jitterentropy-kcapi.c ++++ b/crypto/jitterentropy-kcapi.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -193,7 +194,7 @@ int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len) + ***************************************************************************/ + + struct jitterentropy { +- spinlock_t jent_lock; ++ struct mutex jent_lock; + struct rand_data *entropy_collector; + struct crypto_shash *tfm; + struct shash_desc *sdesc; +@@ -203,7 +204,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) + { + struct jitterentropy *rng = crypto_tfm_ctx(tfm); + +- spin_lock(&rng->jent_lock); ++ mutex_lock(&rng->jent_lock); + + if (rng->sdesc) { + shash_desc_zero(rng->sdesc); +@@ -218,7 +219,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) + if (rng->entropy_collector) + jent_entropy_collector_free(rng->entropy_collector); + rng->entropy_collector = NULL; +- spin_unlock(&rng->jent_lock); ++ mutex_unlock(&rng->jent_lock); + } + + static int jent_kcapi_init(struct crypto_tfm *tfm) +@@ -228,7 +229,7 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) + struct shash_desc *sdesc; + int size, ret = 0; + +- spin_lock_init(&rng->jent_lock); ++ mutex_init(&rng->jent_lock); + + /* + * Use SHA3-256 as conditioner. We allocate only the generic +@@ -265,7 +266,6 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) + goto err; + } + +- spin_lock_init(&rng->jent_lock); + return 0; + + err: +@@ -280,7 +280,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, + struct jitterentropy *rng = crypto_rng_ctx(tfm); + int ret = 0; + +- spin_lock(&rng->jent_lock); ++ mutex_lock(&rng->jent_lock); + + ret = jent_read_entropy(rng->entropy_collector, rdata, dlen); + +@@ -306,7 +306,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, + ret = -EINVAL; + } + +- spin_unlock(&rng->jent_lock); ++ mutex_unlock(&rng->jent_lock); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.18/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch b/queue-6.18/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch new file mode 100644 index 0000000000..776e219fc4 --- /dev/null +++ b/queue-6.18/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch @@ -0,0 +1,62 @@ +From 40a52699cb97cd2fc00b6340bff09d46be36936b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:12:34 +0000 +Subject: crypto: qat - disable 420xx AE cluster when lead engine is fused off + +From: Ahsan Atta + +[ Upstream commit f216e0f2d1787e662bb6662c9c522185aa3b855a ] + +The get_ae_mask() function only disables individual engines based on +the fuse register, but engines are organized in clusters of 4. If the +lead engine of a cluster is fused off, the entire cluster must be +disabled. + +Replace the single bitmask inversion with explicit test_bit() checks +on the lead engine of each group, disabling the full ADF_AE_GROUP +when the lead bit is set. + +Signed-off-by: Ahsan Atta +Reviewed-by: Giovanni Cabiddu +Fixes: fcf60f4bcf54 ("crypto: qat - add support for 420xx devices") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../intel/qat/qat_420xx/adf_420xx_hw_data.c | 20 +++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +index 53fa91d577ed0..cb52aaa323a7e 100644 +--- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +@@ -96,9 +96,25 @@ static struct adf_hw_device_class adf_420xx_class = { + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 me_disable = self->fuses[ADF_FUSECTL4]; ++ unsigned long fuses = self->fuses[ADF_FUSECTL4]; ++ u32 mask = ADF_420XX_ACCELENGINES_MASK; + +- return ~me_disable & ADF_420XX_ACCELENGINES_MASK; ++ if (test_bit(0, &fuses)) ++ mask &= ~ADF_AE_GROUP_0; ++ ++ if (test_bit(4, &fuses)) ++ mask &= ~ADF_AE_GROUP_1; ++ ++ if (test_bit(8, &fuses)) ++ mask &= ~ADF_AE_GROUP_2; ++ ++ if (test_bit(12, &fuses)) ++ mask &= ~ADF_AE_GROUP_3; ++ ++ if (test_bit(16, &fuses)) ++ mask &= ~ADF_AE_GROUP_4; ++ ++ return mask; + } + + static u32 uof_get_num_objs(struct adf_accel_dev *accel_dev) +-- +2.53.0 + diff --git a/queue-6.18/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch b/queue-6.18/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch new file mode 100644 index 0000000000..95b034c1b7 --- /dev/null +++ b/queue-6.18/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch @@ -0,0 +1,56 @@ +From fbc450f8c5d0ec171738143954e97798a7991211 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:11:12 +0000 +Subject: crypto: qat - disable 4xxx AE cluster when lead engine is fused off + +From: Ahsan Atta + +[ Upstream commit b260d53561dd69b29505222ec44cf386ac2c2ca6 ] + +The get_ae_mask() function only disables individual engines based on +the fuse register, but engines are organized in clusters of 4. If the +lead engine of a cluster is fused off, the entire cluster must be +disabled. + +Replace the single bitmask inversion with explicit test_bit() checks +on the lead engine of each group, disabling the full ADF_AE_GROUP +when the lead bit is set. + +Signed-off-by: Ahsan Atta +Reviewed-by: Giovanni Cabiddu +Fixes: 8c8268166e834 ("crypto: qat - add qat_4xxx driver") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +index 740f68a36ac51..900f19b90b2dc 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +@@ -100,9 +100,19 @@ static struct adf_hw_device_class adf_4xxx_class = { + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 me_disable = self->fuses[ADF_FUSECTL4]; ++ unsigned long fuses = self->fuses[ADF_FUSECTL4]; ++ u32 mask = ADF_4XXX_ACCELENGINES_MASK; + +- return ~me_disable & ADF_4XXX_ACCELENGINES_MASK; ++ if (test_bit(0, &fuses)) ++ mask &= ~ADF_AE_GROUP_0; ++ ++ if (test_bit(4, &fuses)) ++ mask &= ~ADF_AE_GROUP_1; ++ ++ if (test_bit(8, &fuses)) ++ mask &= ~ADF_AE_GROUP_2; ++ ++ return mask; + } + + static u32 get_accel_cap(struct adf_accel_dev *accel_dev) +-- +2.53.0 + diff --git a/queue-6.18/crypto-qat-fix-compression-instance-leak.patch b/queue-6.18/crypto-qat-fix-compression-instance-leak.patch new file mode 100644 index 0000000000..a5c9ad05e2 --- /dev/null +++ b/queue-6.18/crypto-qat-fix-compression-instance-leak.patch @@ -0,0 +1,65 @@ +From eb91a8422f08fb63508a45c0d5d07280073c264b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 17:59:40 +0000 +Subject: crypto: qat - fix compression instance leak + +From: Giovanni Cabiddu + +[ Upstream commit 795c24c677c7a1c12f5768daf22a874a2890662f ] + +qat_comp_alg_init_tfm() acquires a compression instance via +qat_compression_get_instance_node() before calling qat_comp_build_ctx() +to initialize the compression context. If qat_comp_build_ctx() fails, the +function returns an error without releasing the compression instance, +causing a resource leak. + +When qat_comp_build_ctx() fails, release the compression instance with +qat_compression_put_instance() and clear the context to avoid leaving a +stale reference to the released instance. + +The issue was introduced when build_deflate_ctx() (which always returned +void) was replaced by qat_comp_build_ctx() (which can return an error) +without adding error handling for the failure path. + +Fixes: cd0e7160f80f ("crypto: qat - refactor compression template logic") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Laurent M Coquerel +Reviewed-by: Ahsan Atta +Reviewed-by: Wojciech Drewek +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/intel/qat/qat_common/qat_comp_algs.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c +index 8b123472b71cc..4273a0ecb6c80 100644 +--- a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c ++++ b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c +@@ -133,7 +133,7 @@ static int qat_comp_alg_init_tfm(struct crypto_acomp *acomp_tfm) + struct crypto_tfm *tfm = crypto_acomp_tfm(acomp_tfm); + struct qat_compression_ctx *ctx = crypto_tfm_ctx(tfm); + struct qat_compression_instance *inst; +- int node; ++ int node, ret; + + if (tfm->node == NUMA_NO_NODE) + node = numa_node_id(); +@@ -146,7 +146,13 @@ static int qat_comp_alg_init_tfm(struct crypto_acomp *acomp_tfm) + return -EINVAL; + ctx->inst = inst; + +- return qat_comp_build_ctx(inst->accel_dev, ctx->comp_ctx, QAT_DEFLATE); ++ ret = qat_comp_build_ctx(inst->accel_dev, ctx->comp_ctx, QAT_DEFLATE); ++ if (ret) { ++ qat_compression_put_instance(inst); ++ memset(ctx, 0, sizeof(*ctx)); ++ } ++ ++ return ret; + } + + static void qat_comp_alg_exit_tfm(struct crypto_acomp *acomp_tfm) +-- +2.53.0 + diff --git a/queue-6.18/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch b/queue-6.18/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch new file mode 100644 index 0000000000..3b5f08fd83 --- /dev/null +++ b/queue-6.18/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch @@ -0,0 +1,86 @@ +From ffc2829a609300c48eb329db38ebb71c1596f044 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 18:17:23 +0000 +Subject: crypto: qat - fix type mismatch in RAS sysfs show functions + +From: Giovanni Cabiddu + +[ Upstream commit ec23d75c4b77ae42af0777ea59599b1d4f611371 ] + +ADF_RAS_ERR_CTR_READ() expands to atomic_read(), which returns int. +The local variable 'counter' was declared as 'unsigned long', causing +a type mismatch on the assignment. The format specifier '%ld' was +consequently wrong in two ways: wrong length modifier and wrong +signedness. + +Use int to match the return type of atomic_read() and update the +format specifier to '%d' accordingly. + +Fixes: 532d7f6bc458 ("crypto: qat - add error counters") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Reviewed-by: Andy Shevchenko +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../intel/qat/qat_common/adf_sysfs_ras_counters.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c +index e97c67c87b3cf..6abb57bfd3285 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c +@@ -13,14 +13,14 @@ static ssize_t errors_correctable_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_CORR); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t errors_nonfatal_show(struct device *dev, +@@ -28,14 +28,14 @@ static ssize_t errors_nonfatal_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_UNCORR); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t errors_fatal_show(struct device *dev, +@@ -43,14 +43,14 @@ static ssize_t errors_fatal_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_FATAL); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t reset_error_counters_store(struct device *dev, +-- +2.53.0 + diff --git a/queue-6.18/crypto-qat-use-swab32-macro.patch b/queue-6.18/crypto-qat-use-swab32-macro.patch new file mode 100644 index 0000000000..08980a6bf9 --- /dev/null +++ b/queue-6.18/crypto-qat-use-swab32-macro.patch @@ -0,0 +1,82 @@ +From 80fc9ad8341b044ef26b5464c50b72a531fafedb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 22:29:46 +0000 +Subject: crypto: qat - use swab32 macro + +From: Giovanni Cabiddu + +[ Upstream commit 35ecb77ae0749a2f1b04872c9978d9d7ddbbeb79 ] + +Replace __builtin_bswap32() with swab32 in icp_qat_hw_20_comp.h to fix +the following build errors on architectures without native byte-swap +support: + + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.o: in function `adf_gen4_build_decomp_block': + drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:141:(.text+0xeec): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:141:(.text+0xef8): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.o: in function `adf_gen4_build_comp_block': + drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:57:(.text+0xf64): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:57:(.text+0xf7c): undefined reference to `__bswapsi2' + +Fixes: 5b14b2b307e4 ("crypto: qat - enable deflate for QAT GEN4") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202603290259.Ig9kDOmI-lkp@intel.com/ +Signed-off-by: Giovanni Cabiddu +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +index 7ea8962272f2f..d28732225c9e0 100644 +--- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h ++++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +@@ -3,6 +3,8 @@ + #ifndef _ICP_QAT_HW_20_COMP_H_ + #define _ICP_QAT_HW_20_COMP_H_ + ++#include ++ + #include "icp_qat_hw_20_comp_defs.h" + #include "icp_qat_fw.h" + +@@ -54,7 +56,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_comp_20_config_csr_lower + QAT_FIELD_SET(val32, csr.abd, ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_comp_20_config_csr_upper { +@@ -106,7 +108,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_comp_20_config_csr_upper + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_decomp_20_config_csr_lower { +@@ -138,7 +140,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_decomp_20_config_csr_l + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_decomp_20_config_csr_upper { +@@ -158,7 +160,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_decomp_20_config_csr_u + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + #endif +-- +2.53.0 + diff --git a/queue-6.18/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch b/queue-6.18/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch new file mode 100644 index 0000000000..1f3638058e --- /dev/null +++ b/queue-6.18/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch @@ -0,0 +1,47 @@ +From 98403c3d0506aeb57f6f864fbb458bbf43528b02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 20:06:58 +0530 +Subject: crypto: sa2ul - Fix AEAD fallback algorithm names + +From: T Pratham + +[ Upstream commit 8451ab6ad686ffdcdf9ddadaa446a79ab48e5590 ] + +For authenc AEAD algorithms, sa2ul is trying to register very specific +-ce version as a fallback. This causes registration failure on SoCs +which do not have ARMv8-CE enabled/available. Change the fallback +algorithm from the specific driver name to generic algorithm name so +that the kernel can allocate any available fallback. + +Fixes: d2c8ac187fc92 ("crypto: sa2ul - Add AEAD algorithm support") +Signed-off-by: T Pratham +Reviewed-by: Manorit Chawdhry +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/sa2ul.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c +index fdc0b24860691..52fe4baeff934 100644 +--- a/drivers/crypto/sa2ul.c ++++ b/drivers/crypto/sa2ul.c +@@ -1744,13 +1744,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, + static int sa_cra_init_aead_sha1(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha1", +- "authenc(hmac(sha1-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha1),cbc(aes))"); + } + + static int sa_cra_init_aead_sha256(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha256", +- "authenc(hmac(sha256-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha256),cbc(aes))"); + } + + static void sa_exit_tfm_aead(struct crypto_aead *tfm) +-- +2.53.0 + diff --git a/queue-6.18/crypto-tegra-disable-softirqs-before-finalizing-requ.patch b/queue-6.18/crypto-tegra-disable-softirqs-before-finalizing-requ.patch new file mode 100644 index 0000000000..7df1c8f6cc --- /dev/null +++ b/queue-6.18/crypto-tegra-disable-softirqs-before-finalizing-requ.patch @@ -0,0 +1,98 @@ +From 0203504d3c8acdd1027fe8140c3095584f07890d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 18:28:29 +0900 +Subject: crypto: tegra - Disable softirqs before finalizing request + +From: Herbert Xu + +[ Upstream commit 2aeec9af775fb53aa086419b953302c6f4ad4984 ] + +Softirqs must be disabled when calling the finalization fucntion on +a request. + +Reported-by: Guangwu Zhang +Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/tegra/tegra-se-aes.c | 9 +++++++++ + drivers/crypto/tegra/tegra-se-hash.c | 3 +++ + 2 files changed, 12 insertions(+) + +diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c +index 9210cceb4b7b2..30c78afe3dea6 100644 +--- a/drivers/crypto/tegra/tegra-se-aes.c ++++ b/drivers/crypto/tegra/tegra-se-aes.c +@@ -4,6 +4,7 @@ + * Crypto driver to handle block cipher algorithms using NVIDIA Security Engine. + */ + ++#include + #include + #include + #include +@@ -333,7 +334,9 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, key2_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_skcipher_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1262,7 +1265,9 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_aead_request(ctx->se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1348,7 +1353,9 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_aead_request(ctx->se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1746,7 +1753,9 @@ static int tegra_cmac_do_one_req(struct crypto_engine *engine, void *areq) + if (tegra_key_is_reserved(rctx->key_id)) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + ++ local_bh_disable(); + crypto_finalize_hash_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c +index 06bb5bf0fa335..23d549801612e 100644 +--- a/drivers/crypto/tegra/tegra-se-hash.c ++++ b/drivers/crypto/tegra/tegra-se-hash.c +@@ -4,6 +4,7 @@ + * Crypto driver to handle HASH algorithms using NVIDIA Security Engine. + */ + ++#include + #include + #include + #include +@@ -546,7 +547,9 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq) + } + + out: ++ local_bh_disable(); + crypto_finalize_hash_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch b/queue-6.18/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch new file mode 100644 index 0000000000..6b1de4e6f1 --- /dev/null +++ b/queue-6.18/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch @@ -0,0 +1,47 @@ +From fcb2e9efe41ac4b534b20083bf7224407b82270b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 15:06:33 +0800 +Subject: cxl/pci: Check memdev driver binding status in cxl_reset_done() + +From: Li Ming + +[ Upstream commit e8069c66d09309579e53567be8ddfa6ccb2f452a ] + +cxl_reset_done() accesses the endpoint of the corresponding CXL memdev +without endpoint validity checking. By default, cxlmd->endpoint is +initialized to -ENXIO, if cxl_reset_done() is triggered after the +corresponding CXL memdev probing failed, this results in access to an +invalid endpoint. + +CXL subsystem can always check CXL memdev driver binding status to +confirm its endpoint validity. So adding the CXL memdev driver checking +inside cxl_reset_done() to avoid accessing an invalid endpoint. + +Fixes: 934edcd436dc ("cxl: Add post-reset warning if reset results in loss of previously committed HDM decoders") +Reviewed-by: Dan Williams +Reviewed-by: Dave Jiang +Signed-off-by: Li Ming +Link: https://patch.msgid.link/20260314-fix_access_endpoint_without_drv_check-v2-4-4c09edf2e1db@zohomail.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c +index bd100ac31672d..c78d7d88744bf 100644 +--- a/drivers/cxl/pci.c ++++ b/drivers/cxl/pci.c +@@ -1104,6 +1104,9 @@ static void cxl_reset_done(struct pci_dev *pdev) + * that no longer exists. + */ + guard(device)(&cxlmd->dev); ++ if (!cxlmd->dev.driver) ++ return; ++ + if (cxlmd->endpoint && + cxl_endpoint_decoder_reset_detected(cxlmd->endpoint)) { + dev_crit(dev, "SBR happened without memory regions removal.\n"); +-- +2.53.0 + diff --git a/queue-6.18/dcache-export-shrink_dentry_list-and-add-new-helper-.patch b/queue-6.18/dcache-export-shrink_dentry_list-and-add-new-helper-.patch new file mode 100644 index 0000000000..345419e5f6 --- /dev/null +++ b/queue-6.18/dcache-export-shrink_dentry_list-and-add-new-helper-.patch @@ -0,0 +1,85 @@ +From a5113431dede0e7d5faebab923616d1b0718d1bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Sep 2025 14:53:07 +0100 +Subject: dcache: export shrink_dentry_list() and add new helper + d_dispose_if_unused() + +From: Luis Henriques + +[ Upstream commit 395b95530343e7f4bdd2870190d985a222997fb6 ] + +Add and export a new helper d_dispose_if_unused() which is simply a wrapper +around to_shrink_list(), to add an entry to a dispose list if it's not used +anymore. + +Also export shrink_dentry_list() to kill all dentries in a dispose list. + +Suggested-by: Miklos Szeredi +Signed-off-by: Luis Henriques +Signed-off-by: Miklos Szeredi +Stable-dep-of: 5a6baf204610 ("fuse: fix uninit-value in fuse_dentry_revalidate()") +Signed-off-by: Sasha Levin +--- + fs/dcache.c | 18 ++++++++++++------ + include/linux/dcache.h | 2 ++ + 2 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/fs/dcache.c b/fs/dcache.c +index 8bf82b002b4d4..fcc8ddf7d3fa4 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1086,6 +1086,15 @@ struct dentry *d_find_alias_rcu(struct inode *inode) + return de; + } + ++void d_dispose_if_unused(struct dentry *dentry, struct list_head *dispose) ++{ ++ spin_lock(&dentry->d_lock); ++ if (!dentry->d_lockref.count) ++ to_shrink_list(dentry, dispose); ++ spin_unlock(&dentry->d_lock); ++} ++EXPORT_SYMBOL(d_dispose_if_unused); ++ + /* + * Try to kill dentries associated with this inode. + * WARNING: you must own a reference to inode. +@@ -1096,12 +1105,8 @@ void d_prune_aliases(struct inode *inode) + struct dentry *dentry; + + spin_lock(&inode->i_lock); +- hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { +- spin_lock(&dentry->d_lock); +- if (!dentry->d_lockref.count) +- to_shrink_list(dentry, &dispose); +- spin_unlock(&dentry->d_lock); +- } ++ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) ++ d_dispose_if_unused(dentry, &dispose); + spin_unlock(&inode->i_lock); + shrink_dentry_list(&dispose); + } +@@ -1141,6 +1146,7 @@ void shrink_dentry_list(struct list_head *list) + shrink_kill(dentry); + } + } ++EXPORT_SYMBOL(shrink_dentry_list); + + static enum lru_status dentry_lru_isolate(struct list_head *item, + struct list_lru_one *lru, void *arg) +diff --git a/include/linux/dcache.h b/include/linux/dcache.h +index c83e02b943894..2bc1339bf6d03 100644 +--- a/include/linux/dcache.h ++++ b/include/linux/dcache.h +@@ -268,6 +268,8 @@ extern void d_tmpfile(struct file *, struct inode *); + + extern struct dentry *d_find_alias(struct inode *); + extern void d_prune_aliases(struct inode *); ++extern void d_dispose_if_unused(struct dentry *, struct list_head *); ++extern void shrink_dentry_list(struct list_head *); + + extern struct dentry *d_find_alias_rcu(struct inode *); + +-- +2.53.0 + diff --git a/queue-6.18/debugfs-check-for-null-pointer-in-debugfs_create_str.patch b/queue-6.18/debugfs-check-for-null-pointer-in-debugfs_create_str.patch new file mode 100644 index 0000000000..83c490033f --- /dev/null +++ b/queue-6.18/debugfs-check-for-null-pointer-in-debugfs_create_str.patch @@ -0,0 +1,52 @@ +From 9031e659aa7f43937d93be8f8c7cd0e81f7ac0e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:44 +0800 +Subject: debugfs: check for NULL pointer in debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 31de83980d3764d784f79ff1bc93c42b324f4013 ] + +Passing a NULL pointer to debugfs_create_str() leads to a NULL pointer +dereference when the debugfs file is read. Following upstream +discussions, forbid the creation of debugfs string files with NULL +pointers. Add a WARN_ON() to expose offending callers and return early. + +Fixes: 9af0440ec86e ("debugfs: Implement debugfs_create_str()") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/2025122221-gag-malt-75ba@gregkh/ +Suggested-by: Greg Kroah-Hartman +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-2-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index 3ec3324c20603..252fca572eb76 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -1127,7 +1127,7 @@ static const struct file_operations fops_str_wo = { + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write +- * from. ++ * from. This pointer and the string it points to must not be %NULL. + * + * This function creates a file in debugfs with the given name that + * contains the value of the variable @value. If the @mode variable is so +@@ -1136,6 +1136,9 @@ static const struct file_operations fops_str_wo = { + void debugfs_create_str(const char *name, umode_t mode, + struct dentry *parent, char **value) + { ++ if (WARN_ON(!value || !*value)) ++ return; ++ + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } +-- +2.53.0 + diff --git a/queue-6.18/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch b/queue-6.18/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch new file mode 100644 index 0000000000..55a0cfc999 --- /dev/null +++ b/queue-6.18/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch @@ -0,0 +1,45 @@ +From 88dbc81860fa9dfbd60bad5230f06dd27107c66b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:45 +0800 +Subject: debugfs: fix placement of EXPORT_SYMBOL_GPL for debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 4afc929c0f74c4f22b055a82b371d50586da58ca ] + +The EXPORT_SYMBOL_GPL() for debugfs_create_str was placed incorrectly +away from the function definition. Move it immediately below the +debugfs_create_str() function where it belongs. + +Fixes: d60b59b96795 ("debugfs: Export debugfs_create_str symbol") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-3-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index 252fca572eb76..880a8a9deacfe 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -1047,7 +1047,6 @@ ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf, + + return ret; + } +-EXPORT_SYMBOL_GPL(debugfs_create_str); + + static ssize_t debugfs_write_file_str(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +@@ -1142,6 +1141,7 @@ void debugfs_create_str(const char *name, umode_t mode, + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } ++EXPORT_SYMBOL_GPL(debugfs_create_str); + + static ssize_t read_file_blob(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +-- +2.53.0 + diff --git a/queue-6.18/devres-fix-missing-node-debug-info-in-devm_krealloc.patch b/queue-6.18/devres-fix-missing-node-debug-info-in-devm_krealloc.patch new file mode 100644 index 0000000000..6edb7653f5 --- /dev/null +++ b/queue-6.18/devres-fix-missing-node-debug-info-in-devm_krealloc.patch @@ -0,0 +1,37 @@ +From b8f3c867d18ef4c9603a77e69bd2e05131eaad8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 00:48:14 +0100 +Subject: devres: fix missing node debug info in devm_krealloc() + +From: Danilo Krummrich + +[ Upstream commit f813ec9e84b4d0ca81ec1da94ab07bfb4a29266c ] + +Fix missing call to set_node_dbginfo() for new devres nodes created by +devm_krealloc(). + +Fixes: f82485722e5d ("devres: provide devm_krealloc()") +Reviewed-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/20260202235210.55176-2-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/base/devres.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index c948c88d39560..9893d656302d9 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -940,6 +940,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) + if (!new_dr) + return NULL; + ++ set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size); ++ + /* + * The spinlock protects the linked list against concurrent + * modifications but not the resource itself. +-- +2.53.0 + diff --git a/queue-6.18/dm-add-wq_percpu-to-alloc_workqueue-users.patch b/queue-6.18/dm-add-wq_percpu-to-alloc_workqueue-users.patch new file mode 100644 index 0000000000..da73b99934 --- /dev/null +++ b/queue-6.18/dm-add-wq_percpu-to-alloc_workqueue-users.patch @@ -0,0 +1,353 @@ +From 18179bf303d50ac7d2401b379fa296552a900cba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Jan 2026 12:03:02 +0100 +Subject: dm: add WQ_PERCPU to alloc_workqueue users +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Marco Crivellari + +[ Upstream commit d4880868670198df321627a949e7b7f2d76cf54e ] + +This continues the effort to refactor workqueue APIs, which began with +the introduction of new workqueues and a new alloc_workqueue flag in: + + commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") + commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") + +The refactoring is going to alter the default behavior of +alloc_workqueue() to be unbound by default. + +With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), +any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND +must now use WQ_PERCPU. For more details see the Link tag below. + +In order to keep alloc_workqueue() behavior identical, explicitly request +WQ_PERCPU. + +Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/ +Suggested-by: Tejun Heo +Signed-off-by: Marco Crivellari +Signed-off-by: Mikulas Patocka +Stable-dep-of: e4979f4fac4d ("md: remove unused static md_wq workqueue") +Signed-off-by: Sasha Levin +--- + drivers/md/dm-bufio.c | 3 ++- + drivers/md/dm-cache-target.c | 3 ++- + drivers/md/dm-clone-target.c | 3 ++- + drivers/md/dm-crypt.c | 6 ++++-- + drivers/md/dm-delay.c | 4 +++- + drivers/md/dm-integrity.c | 15 ++++++++++----- + drivers/md/dm-kcopyd.c | 3 ++- + drivers/md/dm-log-userspace-base.c | 3 ++- + drivers/md/dm-mpath.c | 5 +++-- + drivers/md/dm-raid1.c | 5 +++-- + drivers/md/dm-snap-persistent.c | 3 ++- + drivers/md/dm-stripe.c | 2 +- + drivers/md/dm-verity-target.c | 4 +++- + drivers/md/dm-writecache.c | 3 ++- + drivers/md/dm.c | 3 ++- + drivers/md/md.c | 4 ++-- + 16 files changed, 45 insertions(+), 24 deletions(-) + +diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c +index 5235f3e4924b7..f41f649c01d4e 100644 +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -2833,7 +2833,8 @@ static int __init dm_bufio_init(void) + __cache_size_refresh(); + mutex_unlock(&dm_bufio_clients_lock); + +- dm_bufio_wq = alloc_workqueue("dm_bufio_cache", WQ_MEM_RECLAIM, 0); ++ dm_bufio_wq = alloc_workqueue("dm_bufio_cache", ++ WQ_MEM_RECLAIM | WQ_PERCPU, 0); + if (!dm_bufio_wq) + return -ENOMEM; + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index a10d75a562db0..7bad7cc87d370 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2533,7 +2533,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) + goto bad; + } + +- cache->wq = alloc_workqueue("dm-" DM_MSG_PREFIX, WQ_MEM_RECLAIM, 0); ++ cache->wq = alloc_workqueue("dm-" DM_MSG_PREFIX, ++ WQ_MEM_RECLAIM | WQ_PERCPU, 0); + if (!cache->wq) { + *error = "could not create workqueue for metadata object"; + goto bad; +diff --git a/drivers/md/dm-clone-target.c b/drivers/md/dm-clone-target.c +index e956d980672c8..b25845e362744 100644 +--- a/drivers/md/dm-clone-target.c ++++ b/drivers/md/dm-clone-target.c +@@ -1877,7 +1877,8 @@ static int clone_ctr(struct dm_target *ti, unsigned int argc, char **argv) + clone->hydration_offset = 0; + atomic_set(&clone->hydrations_in_flight, 0); + +- clone->wq = alloc_workqueue("dm-" DM_MSG_PREFIX, WQ_MEM_RECLAIM, 0); ++ clone->wq = alloc_workqueue("dm-" DM_MSG_PREFIX, ++ WQ_MEM_RECLAIM | WQ_PERCPU, 0); + if (!clone->wq) { + ti->error = "Failed to allocate workqueue"; + r = -ENOMEM; +diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c +index 5ef43231fe77f..fd735155336bc 100644 +--- a/drivers/md/dm-crypt.c ++++ b/drivers/md/dm-crypt.c +@@ -3441,7 +3441,9 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) + if (test_bit(DM_CRYPT_HIGH_PRIORITY, &cc->flags)) + common_wq_flags |= WQ_HIGHPRI; + +- cc->io_queue = alloc_workqueue("kcryptd_io-%s-%d", common_wq_flags, 1, devname, wq_id); ++ cc->io_queue = alloc_workqueue("kcryptd_io-%s-%d", ++ common_wq_flags | WQ_PERCPU, 1, ++ devname, wq_id); + if (!cc->io_queue) { + ti->error = "Couldn't create kcryptd io queue"; + goto bad; +@@ -3449,7 +3451,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) + + if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags)) { + cc->crypt_queue = alloc_workqueue("kcryptd-%s-%d", +- common_wq_flags | WQ_CPU_INTENSIVE, ++ common_wq_flags | WQ_CPU_INTENSIVE | WQ_PERCPU, + 1, devname, wq_id); + } else { + /* +diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c +index 4bb6553278c74..029f04776490a 100644 +--- a/drivers/md/dm-delay.c ++++ b/drivers/md/dm-delay.c +@@ -290,7 +290,9 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv) + } else { + timer_setup(&dc->delay_timer, handle_delayed_timer, 0); + INIT_WORK(&dc->flush_expired_bios, flush_expired_bios); +- dc->kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0); ++ dc->kdelayd_wq = alloc_workqueue("kdelayd", ++ WQ_MEM_RECLAIM | WQ_PERCPU, ++ 0); + if (!dc->kdelayd_wq) { + ret = -EINVAL; + DMERR("Couldn't start kdelayd"); +diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c +index ba52631052503..a9c0157bf42fe 100644 +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -5003,7 +5003,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv + } + + ic->metadata_wq = alloc_workqueue("dm-integrity-metadata", +- WQ_MEM_RECLAIM, METADATA_WORKQUEUE_MAX_ACTIVE); ++ WQ_MEM_RECLAIM | WQ_PERCPU, ++ METADATA_WORKQUEUE_MAX_ACTIVE); + if (!ic->metadata_wq) { + ti->error = "Cannot allocate workqueue"; + r = -ENOMEM; +@@ -5021,7 +5022,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv + goto bad; + } + +- ic->offload_wq = alloc_workqueue("dm-integrity-offload", WQ_MEM_RECLAIM, ++ ic->offload_wq = alloc_workqueue("dm-integrity-offload", ++ WQ_MEM_RECLAIM | WQ_PERCPU, + METADATA_WORKQUEUE_MAX_ACTIVE); + if (!ic->offload_wq) { + ti->error = "Cannot allocate workqueue"; +@@ -5029,7 +5031,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv + goto bad; + } + +- ic->commit_wq = alloc_workqueue("dm-integrity-commit", WQ_MEM_RECLAIM, 1); ++ ic->commit_wq = alloc_workqueue("dm-integrity-commit", ++ WQ_MEM_RECLAIM | WQ_PERCPU, 1); + if (!ic->commit_wq) { + ti->error = "Cannot allocate workqueue"; + r = -ENOMEM; +@@ -5038,7 +5041,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv + INIT_WORK(&ic->commit_work, integrity_commit); + + if (ic->mode == 'J' || ic->mode == 'B') { +- ic->writer_wq = alloc_workqueue("dm-integrity-writer", WQ_MEM_RECLAIM, 1); ++ ic->writer_wq = alloc_workqueue("dm-integrity-writer", ++ WQ_MEM_RECLAIM | WQ_PERCPU, 1); + if (!ic->writer_wq) { + ti->error = "Cannot allocate workqueue"; + r = -ENOMEM; +@@ -5210,7 +5214,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv + } + + if (ic->internal_hash) { +- ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", WQ_MEM_RECLAIM, 1); ++ ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", ++ WQ_MEM_RECLAIM | WQ_PERCPU, 1); + if (!ic->recalc_wq) { + ti->error = "Cannot allocate workqueue"; + r = -ENOMEM; +diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c +index 6ea75436a433a..cec9a60227b6f 100644 +--- a/drivers/md/dm-kcopyd.c ++++ b/drivers/md/dm-kcopyd.c +@@ -934,7 +934,8 @@ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *thro + goto bad_slab; + + INIT_WORK(&kc->kcopyd_work, do_work); +- kc->kcopyd_wq = alloc_workqueue("kcopyd", WQ_MEM_RECLAIM, 0); ++ kc->kcopyd_wq = alloc_workqueue("kcopyd", WQ_MEM_RECLAIM | WQ_PERCPU, ++ 0); + if (!kc->kcopyd_wq) { + r = -ENOMEM; + goto bad_workqueue; +diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c +index 9fbb4b48fb2bb..607436804a8b2 100644 +--- a/drivers/md/dm-log-userspace-base.c ++++ b/drivers/md/dm-log-userspace-base.c +@@ -299,7 +299,8 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti, + } + + if (lc->integrated_flush) { +- lc->dmlog_wq = alloc_workqueue("dmlogd", WQ_MEM_RECLAIM, 0); ++ lc->dmlog_wq = alloc_workqueue("dmlogd", ++ WQ_MEM_RECLAIM | WQ_PERCPU, 0); + if (!lc->dmlog_wq) { + DMERR("couldn't start dmlogd"); + r = -ENOMEM; +diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c +index 7d3fdd96f4edf..00df5be165759 100644 +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -2330,7 +2330,8 @@ static int __init dm_multipath_init(void) + { + int r = -ENOMEM; + +- kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); ++ kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM | WQ_PERCPU, ++ 0); + if (!kmultipathd) { + DMERR("failed to create workqueue kmpathd"); + goto bad_alloc_kmultipathd; +@@ -2349,7 +2350,7 @@ static int __init dm_multipath_init(void) + goto bad_alloc_kmpath_handlerd; + } + +- dm_mpath_wq = alloc_workqueue("dm_mpath_wq", 0, 0); ++ dm_mpath_wq = alloc_workqueue("dm_mpath_wq", WQ_PERCPU, 0); + if (!dm_mpath_wq) { + DMERR("failed to create workqueue dm_mpath_wq"); + goto bad_alloc_dm_mpath_wq; +diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c +index bc8e04f6832a6..d9ec783a37ddc 100644 +--- a/drivers/md/dm-raid1.c ++++ b/drivers/md/dm-raid1.c +@@ -1128,7 +1128,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) + ti->num_discard_bios = 1; + ti->per_io_data_size = sizeof(struct dm_raid1_bio_record); + +- ms->kmirrord_wq = alloc_workqueue("kmirrord", WQ_MEM_RECLAIM, 0); ++ ms->kmirrord_wq = alloc_workqueue("kmirrord", ++ WQ_MEM_RECLAIM | WQ_PERCPU, 0); + if (!ms->kmirrord_wq) { + DMERR("couldn't start kmirrord"); + r = -ENOMEM; +@@ -1500,7 +1501,7 @@ static int __init dm_mirror_init(void) + { + int r; + +- dm_raid1_wq = alloc_workqueue("dm_raid1_wq", 0, 0); ++ dm_raid1_wq = alloc_workqueue("dm_raid1_wq", WQ_PERCPU, 0); + if (!dm_raid1_wq) { + DMERR("Failed to alloc workqueue"); + return -ENOMEM; +diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c +index 568d10842b1f4..0e13d60bfdd12 100644 +--- a/drivers/md/dm-snap-persistent.c ++++ b/drivers/md/dm-snap-persistent.c +@@ -871,7 +871,8 @@ static int persistent_ctr(struct dm_exception_store *store, char *options) + atomic_set(&ps->pending_count, 0); + ps->callbacks = NULL; + +- ps->metadata_wq = alloc_workqueue("ksnaphd", WQ_MEM_RECLAIM, 0); ++ ps->metadata_wq = alloc_workqueue("ksnaphd", ++ WQ_MEM_RECLAIM | WQ_PERCPU, 0); + if (!ps->metadata_wq) { + DMERR("couldn't start header metadata update thread"); + r = -ENOMEM; +diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c +index 1461dc740dae6..1cff9df5b8b47 100644 +--- a/drivers/md/dm-stripe.c ++++ b/drivers/md/dm-stripe.c +@@ -489,7 +489,7 @@ int __init dm_stripe_init(void) + { + int r; + +- dm_stripe_wq = alloc_workqueue("dm_stripe_wq", 0, 0); ++ dm_stripe_wq = alloc_workqueue("dm_stripe_wq", WQ_PERCPU, 0); + if (!dm_stripe_wq) + return -ENOMEM; + r = dm_register_target(&stripe_target); +diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c +index c8695c079cfe0..a5cd55b2ba02f 100644 +--- a/drivers/md/dm-verity-target.c ++++ b/drivers/md/dm-verity-target.c +@@ -1549,7 +1549,9 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv) + * will fall-back to using it for error handling (or if the bufio cache + * doesn't have required hashes). + */ +- v->verify_wq = alloc_workqueue("kverityd", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); ++ v->verify_wq = alloc_workqueue("kverityd", ++ WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, ++ 0); + if (!v->verify_wq) { + ti->error = "Cannot allocate workqueue"; + r = -ENOMEM; +diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c +index d8de4a3076a17..af54e289bcebe 100644 +--- a/drivers/md/dm-writecache.c ++++ b/drivers/md/dm-writecache.c +@@ -2275,7 +2275,8 @@ static int writecache_ctr(struct dm_target *ti, unsigned int argc, char **argv) + goto bad; + } + +- wc->writeback_wq = alloc_workqueue("writecache-writeback", WQ_MEM_RECLAIM, 1); ++ wc->writeback_wq = alloc_workqueue("writecache-writeback", ++ WQ_MEM_RECLAIM | WQ_PERCPU, 1); + if (!wc->writeback_wq) { + r = -ENOMEM; + ti->error = "Could not allocate writeback workqueue"; +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index 52f01c44e73a6..fb6bcd598c5b8 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -2363,7 +2363,8 @@ static struct mapped_device *alloc_dev(int minor) + + format_dev_t(md->name, MKDEV(_major, minor)); + +- md->wq = alloc_workqueue("kdmflush/%s", WQ_MEM_RECLAIM, 0, md->name); ++ md->wq = alloc_workqueue("kdmflush/%s", WQ_MEM_RECLAIM | WQ_PERCPU, 0, ++ md->name); + if (!md->wq) + goto bad; + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 7560e98dc35b3..0fc779493fa78 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -10345,11 +10345,11 @@ static int __init md_init(void) + goto err_bitmap; + + ret = -ENOMEM; +- md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM, 0); ++ md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM | WQ_PERCPU, 0); + if (!md_wq) + goto err_wq; + +- md_misc_wq = alloc_workqueue("md_misc", 0, 0); ++ md_misc_wq = alloc_workqueue("md_misc", WQ_PERCPU, 0); + if (!md_misc_wq) + goto err_misc_wq; + +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-fix-concurrent-write-failure-in-passthrough.patch b/queue-6.18/dm-cache-fix-concurrent-write-failure-in-passthrough.patch new file mode 100644 index 0000000000..69371362b0 --- /dev/null +++ b/queue-6.18/dm-cache-fix-concurrent-write-failure-in-passthrough.patch @@ -0,0 +1,84 @@ +From 28d3181e60c6da911efc9b09e988ea0302e896b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:09 +0800 +Subject: dm cache: fix concurrent write failure in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit e4f66341779d0cf4c83c74793753a84094286d9e ] + +When bio prison cell lock acquisition fails due to concurrent writes to +the same block in passthrough mode, dm-cache incorrectly returns an I/O +error instead of properly handling the concurrency. This can occur in +both process and workqueue contexts when invalidate_lock() is called for +exclusive access to a data block. Fix this by deferring the write bios +to ensure proper block device behavior. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently. Sometimes one of the + processes will receive I/O errors. + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + + + fio-3.41 + fio: io_u error on file /dev/mapper/cache: Input/output error: write offset=4096, buflen=4096 + fio: pid=106, err=5/file:io_u.c:2008, func=io_u error, error=Input/output error + test: (groupid=0, jobs=1): err= 0: pid=105 + test: (groupid=0, jobs=1): err= 5 (file:io_u.c:2008, func=io_u error, error=Input/output error): pid=106 + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index b191ea1361b40..e8709950dc49d 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1561,6 +1561,15 @@ static int invalidate_lock(struct dm_cache_migration *mg) + READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell); + if (r < 0) { + free_prison_cell(cache, prealloc); ++ ++ /* Defer the bio for retrying the cell lock */ ++ if (mg->overwrite_bio) { ++ struct bio *bio = mg->overwrite_bio; ++ ++ mg->overwrite_bio = NULL; ++ defer_bio(cache, bio); ++ } ++ + invalidate_complete(mg, false); + return r; + } +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch b/queue-6.18/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch new file mode 100644 index 0000000000..6738bc7d22 --- /dev/null +++ b/queue-6.18/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch @@ -0,0 +1,151 @@ +From 29d91a5ad82eeeb6e33407b630c79e54139e29b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:10 +0800 +Subject: dm cache: fix dirty mapping checking in passthrough mode switching + +From: Ming-Hung Tsai + +[ Upstream commit 322586745bd1a0e5f3559fd1635fdeb4dbd1d6b8 ] + +As mentioned in commit 9b1cc9f251af ("dm cache: share cache-metadata +object across inactive and active DM tables"), dm-cache assumed table +reload occurs after suspension, while LVM's table preload breaks this +assumption. The dirty mapping check for passthrough mode was designed +around this assumption and is performed during table creation, causing +the check to fail with preload while metadata updates are ongoing. This +risks loading dirty mappings into passthrough mode, resulting in data +loss. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty mappings + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Preload a table in passthrough mode + +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" + +3. Write to the first cache block to make it dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +4. Resume the inactive table. Now it's possible to load the dirty block + into passthrough mode. + +dmsetup resume cache + +Fix by moving the checks to the preresume phase to support table +preloading. Also remove the unused function dm_cache_metadata_all_clean. + +Fixes: 2ee57d587357 ("dm cache: add passthrough mode") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 11 ----------- + drivers/md/dm-cache-metadata.h | 5 ----- + drivers/md/dm-cache-target.c | 25 ++++++++----------------- + 3 files changed, 8 insertions(+), 33 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index a9a1ab284076a..cf491c8508a42 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1714,17 +1714,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * + return r; + } + +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) +-{ +- int r; +- +- READ_LOCK(cmd); +- r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); +- READ_UNLOCK(cmd); +- +- return r; +-} +- + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) + { + WRITE_LOCK_VOID(cmd); +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 5f77890207fed..2f107e7c67d0a 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -135,11 +135,6 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd, + */ + int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p); + +-/* +- * Query method. Are all the blocks in the cache clean? +- */ +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); +- + int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); + int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index e8709950dc49d..9c64fe56ecb6c 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2506,23 +2506,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) + goto bad; + } + +- if (passthrough_mode(cache)) { +- bool all_clean; +- +- r = dm_cache_metadata_all_clean(cache->cmd, &all_clean); +- if (r) { +- *error = "dm_cache_metadata_all_clean() failed"; +- goto bad; +- } +- +- if (!all_clean) { +- *error = "Cannot enter passthrough mode unless all blocks are clean"; +- r = -EINVAL; +- goto bad; +- } +- ++ if (passthrough_mode(cache)) + policy_allow_migrations(cache->policy, false); +- } + + spin_lock_init(&cache->lock); + bio_list_init(&cache->deferred_bios); +@@ -2849,6 +2834,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + struct cache *cache = context; + + if (dirty) { ++ if (passthrough_mode(cache)) { ++ DMERR("%s: cannot enter passthrough mode unless all blocks are clean", ++ cache_device_name(cache)); ++ return -EBUSY; ++ } ++ + set_bit(from_cblock(cblock), cache->dirty_bitset); + atomic_inc(&cache->nr_dirty); + } else +@@ -3082,7 +3073,7 @@ static int cache_preresume(struct dm_target *ti) + load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- if (r != -EFBIG) ++ if (r != -EFBIG && r != -EBUSY) + metadata_operation_failed(cache, "dm_cache_load_mappings", r); + return r; + } +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-fix-missing-return-in-invalidate_committed-.patch b/queue-6.18/dm-cache-fix-missing-return-in-invalidate_committed-.patch new file mode 100644 index 0000000000..7176edfa34 --- /dev/null +++ b/queue-6.18/dm-cache-fix-missing-return-in-invalidate_committed-.patch @@ -0,0 +1,51 @@ +From e8aa21cb773c2ccc0178b5a0766b2fddab409f9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 21:08:01 +0800 +Subject: dm cache: fix missing return in invalidate_committed's error path + +From: Ming-Hung Tsai + +[ Upstream commit 8c0ee19db81f0fa1ff25fd75b22b17c0cc2acde3 ] + +In passthrough mode, dm-cache defers write submission until after +metadata commit completes via the invalidate_committed() continuation. +On commit error, invalidate_committed() calls invalidate_complete() to +end the bio and free the migration struct, after which it should return +immediately. + +The patch 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +omitted this early return, causing execution to fall through into the +success path on error. This results in use-after-free on the migration +struct in the subsequent calls. + +Fix by adding the missing return after the invalidate_complete() call. + +Fixes: 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/dm-devel/adjMq6T5RRjv_uxM@stanley.mountain/ +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 9c64fe56ecb6c..bb0b484d4d687 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1521,8 +1521,10 @@ static void invalidate_committed(struct work_struct *ws) + struct bio *bio = mg->overwrite_bio; + struct per_bio_data *pb = get_per_bio_data(bio); + +- if (mg->k.input) ++ if (mg->k.input) { + invalidate_complete(mg, false); ++ return; ++ } + + init_continuation(&mg->k, invalidate_completed); + remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch b/queue-6.18/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch new file mode 100644 index 0000000000..2ac57080a0 --- /dev/null +++ b/queue-6.18/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch @@ -0,0 +1,86 @@ +From 0740f57328227d592cda345233598801905797f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:05 +0800 +Subject: dm cache: fix null-deref with concurrent writes in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 7d1f98d668ee34c1d15bdc0420fdd062f24a27c0 ] + +In passthrough mode, when dm-cache starts to invalidate a cache +entry and bio prison cell lock fails due to concurrent write to +the same cached block, mg->cell remains NULL. The error path in +invalidate_complete() attempts to unlock and free the cell +unconditionally, causing a NULL pointer dereference: + +KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +CPU: 0 UID: 0 PID: 134 Comm: fio Not tainted 6.19.0-rc7 #3 PREEMPT +RIP: 0010:dm_cell_unlock_v2+0x3f/0x210 + +Call Trace: + invalidate_complete+0xef/0x430 + map_bio+0x130f/0x1a10 + cache_map+0x320/0x6b0 + __map_bio+0x458/0x510 + dm_submit_bio+0x40e/0x16d0 + __submit_bio+0x419/0x870 + + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + +Fix by checking if mg->cell is valid before attempting to unlock it. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 7bad7cc87d370..1296965cf94cf 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1462,8 +1462,10 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + struct cache *cache = mg->cache; + + bio_list_init(&bios); +- if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) +- free_prison_cell(cache, mg->cell); ++ if (mg->cell) { ++ if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) ++ free_prison_cell(cache, mg->cell); ++ } + + if (!success && mg->overwrite_bio) + bio_io_error(mg->overwrite_bio); +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-fix-write-hang-in-passthrough-mode.patch b/queue-6.18/dm-cache-fix-write-hang-in-passthrough-mode.patch new file mode 100644 index 0000000000..8053fc6b11 --- /dev/null +++ b/queue-6.18/dm-cache-fix-write-hang-in-passthrough-mode.patch @@ -0,0 +1,88 @@ +From ac7da7f2692d729955e0d715fb475995e2b42ba1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:07 +0800 +Subject: dm cache: fix write hang in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 4ca8b8bd952df7c3ccdc68af9bd3419d0839a04b ] + +The invalidate_remove() function has incomplete logic for handling write +hit bios after cache invalidation. It sets up the remapping for the +overwrite_bio but then drops it immediately without submission, causing +write operations to hang. + +Fix by adding a new invalidate_committed() continuation that submits +the remapped writes to the cache origin after metadata commit completes, +while using the overwrite_endio hook to ensure proper completion +sequencing. This maintains existing coherency. Also improve error +handling in invalidate_complete() to preserve the original error status +instead of using bio_io_error() unconditionally. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 69fa2f6479318..b191ea1361b40 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1467,8 +1467,14 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + free_prison_cell(cache, mg->cell); + } + +- if (!success && mg->overwrite_bio) +- bio_io_error(mg->overwrite_bio); ++ if (mg->overwrite_bio) { ++ // Set generic error if the bio hasn't been issued yet, ++ // e.g., invalidation or metadata commit failed before bio ++ // submission. Otherwise preserve the bio's own error status. ++ if (!success && !mg->overwrite_bio->bi_status) ++ mg->overwrite_bio->bi_status = BLK_STS_IOERR; ++ bio_endio(mg->overwrite_bio); ++ } + + free_migration(mg); + defer_bios(cache, &bios); +@@ -1508,6 +1514,22 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock) + return r; + } + ++static void invalidate_committed(struct work_struct *ws) ++{ ++ struct dm_cache_migration *mg = ws_to_mg(ws); ++ struct cache *cache = mg->cache; ++ struct bio *bio = mg->overwrite_bio; ++ struct per_bio_data *pb = get_per_bio_data(bio); ++ ++ if (mg->k.input) ++ invalidate_complete(mg, false); ++ ++ init_continuation(&mg->k, invalidate_completed); ++ remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); ++ dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg); ++ dm_submit_bio_remap(bio, NULL); ++} ++ + static void invalidate_remove(struct work_struct *ws) + { + int r; +@@ -1520,10 +1542,8 @@ static void invalidate_remove(struct work_struct *ws) + return; + } + +- init_continuation(&mg->k, invalidate_completed); ++ init_continuation(&mg->k, invalidate_committed); + continue_after_commit(&cache->committer, &mg->k); +- remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock); +- mg->overwrite_bio = NULL; + schedule_commit(&cache->committer); + } + +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch b/queue-6.18/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch new file mode 100644 index 0000000000..48480be89b --- /dev/null +++ b/queue-6.18/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch @@ -0,0 +1,85 @@ +From 1d2ac42121169c0d14481f233420315dca34bb31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:06 +0800 +Subject: dm cache: fix write path cache coherency in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 0c5eef0aad508231d8e43ff8392692925e131b68 ] + +In passthrough mode, dm-cache defers write bio submission until cache +invalidation completes to maintain existing coherency, requiring the +target map function to return DM_MAPIO_SUBMITTED. The current map_bio() +returns DM_MAPIO_REMAPPED, violating the required ordering constraint. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into the cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first data block, and check io ordering using ftrace + +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_queue/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_complete/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_rq_complete/enable +fio --filename=/dev/mapper/cache --name=test --rw=write --bs=64k \ +--direct=1 --size 64k + +5. ftrace logs show that write operations to the cache origin (252:2) + and metadata operations (252:0) are unsynchronized: the origin write + occurs before metadata commit. + + + fio-146 [000] ..... 420.139562: block_bio_queue: 252,3 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149395: block_bio_queue: 252,2 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149763: block_bio_queue: 8,32 WS 262144 + 128 [fio] + fio-146 [000] dNh1. 420.151446: block_rq_complete: 8,32 WS () 262144 + 128 be,0,4 [0] + fio-146 [000] dNh1. 420.152731: block_bio_complete: 252,2 WS 0 + 128 [0] + fio-146 [000] dNh1. 420.154229: block_bio_complete: 252,3 WS 0 + 128 [0] + kworker/0:0-9 [000] ..... 420.160530: block_bio_queue: 252,0 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.161641: block_bio_queue: 8,32 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162533: block_bio_queue: 252,0 W 416 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162821: block_bio_queue: 8,32 W 416 + 8 [kworker/0:0] + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 1296965cf94cf..69fa2f6479318 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1703,6 +1703,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, + bio_drop_shared_lock(cache, bio); + atomic_inc(&cache->stats.demotion); + invalidate_start(cache, cblock, block, bio); ++ return DM_MAPIO_SUBMITTED; + } else + remap_to_origin_clear_discard(cache, bio, block); + } else { +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch b/queue-6.18/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch new file mode 100644 index 0000000000..a40b77ed56 --- /dev/null +++ b/queue-6.18/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch @@ -0,0 +1,121 @@ +From 3e134f476f580b0e3fadfef77236138cfe2d136c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:56:28 +0800 +Subject: dm cache metadata: fix memory leak on metadata abort retry + +From: Ming-Hung Tsai + +[ Upstream commit 044ca491d4086dc5bf233e9fcb71db52df32f633 ] + +When failing to acquire the root_lock in dm_cache_metadata_abort because +the block_manager is read-only, the temporary block_manager created +outside the root_lock is not properly released, causing a memory leak. + +Reproduce steps: + +This can be reproduced by reloading a new table while the metadata +is read-only. While the second call to dm_cache_metadata_abort is +caused by lack of support for table preload in dm-cache, mentioned +in commit 9b1cc9f251af ("dm cache: share cache-metadata object across +inactive and active DM tables"), it exposes the memory leak in +dm_cache_metadata_abort when the function is called multiple times. +Specifically, dm-cache fails to sync the new cache object's mode during +preresume, creating the reproducer condition. + +This issue could also occur through concurrent metadata_operation_failed +calls due to races in cache mode updates, but the table preload scenario +below provides a reliable reproducer. + +1. Create a cache device with some faulty trailing metadata blocks + +dmsetup create cmeta < +unreferenced object 0xffff8880080c2010 (size 16): + comm "dmsetup", pid 132, jiffies 4294982580 + hex dump (first 16 bytes): + 00 38 b9 07 80 88 ff ff 6a 6b 6b 6b 6b 6b 6b a5 ... + backtrace (crc 3118f31c): + kmemleak_alloc+0x28/0x40 + __kmalloc_cache_noprof+0x3d9/0x510 + dm_block_manager_create+0x51/0x140 + dm_cache_metadata_abort+0x85/0x320 + metadata_operation_failed+0x103/0x1e0 + cache_preresume+0xacd/0xe70 + dm_table_resume_targets+0xd3/0x320 + __dm_resume+0x1b/0xf0 + dm_resume+0x127/0x170 + + +Fixes: 352b837a5541 ("dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index cf491c8508a42..db77ba58f64ac 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1023,6 +1023,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd) + return; \ + } while (0) + ++#define WRITE_LOCK_OR_GOTO(cmd, label) \ ++ do { \ ++ if (!cmd_write_lock((cmd))) \ ++ goto label; \ ++ } while (0) ++ + #define WRITE_UNLOCK(cmd) \ + up_write(&(cmd)->root_lock) + +@@ -1780,11 +1786,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, + CACHE_MAX_CONCURRENT_LOCKS); + +- WRITE_LOCK(cmd); +- if (cmd->fail_io) { +- WRITE_UNLOCK(cmd); +- goto out; +- } ++ /* cmd_write_lock() already checks fail_io with cmd->root_lock held */ ++ WRITE_LOCK_OR_GOTO(cmd, out); + + __destroy_persistent_data_objects(cmd, false); + old_bm = cmd->bm; +-- +2.53.0 + diff --git a/queue-6.18/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch b/queue-6.18/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch new file mode 100644 index 0000000000..25f4a9bc8e --- /dev/null +++ b/queue-6.18/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch @@ -0,0 +1,91 @@ +From 111df4114b22113ac032e943edff72c32ad6feff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:08 +0800 +Subject: dm cache policy smq: fix missing locks in invalidating cache blocks + +From: Ming-Hung Tsai + +[ Upstream commit 2d1f7b65f5deedd2e6b09fdc6ea27f8375f24b45 ] + +In passthrough mode, the policy invalidate_mapping operation is called +simultaneously from multiple workers, thus it should be protected by a +lock. Otherwise, we might end up with data races on the allocated blocks +counter, or even use-after-free issues with internal data structures +when doing concurrent writes. + +Note that the existing FIXME in smq_invalidate_mapping() doesn't affect +passthrough mode since migration tasks don't exist there, but would need +attention if supporting fast device shrinking via suspend/resume without +target reloading. + +Reproduce steps: + +1. Create a cache device consisting of 1024 cache entries + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Populate the cache, and record the number of cached blocks + +fio --name=populate --filename=/dev/mapper/cache --rw=randwrite --bs=4k \ +--size=64m --direct=1 +nr_cached=$(dmsetup status cache | awk '{split($7, a, "/"); print a[1]}') + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the passthrough cache. By setting multiple jobs with I/O + size equal to the cache block size, cache blocks are invalidated + concurrently from different workers. + +fio --filename=/dev/mapper/cache --name=test --rw=randwrite --bs=64k \ +--direct=1 --numjobs=2 --randrepeat=0 --size=64m + +5. Check if demoted matches cached block count. These numbers should + match but may differ due to the data race. + +nr_demoted=$(dmsetup status cache | awk '{print $12}') +echo "$nr_cached, $nr_demoted" + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 7e1e8cc0e33a3..76a35cce85028 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1589,14 +1589,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + { + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); ++ unsigned long flags; + + if (!e->allocated) + return -ENODATA; + ++ spin_lock_irqsave(&mq->lock, flags); + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ spin_unlock_irqrestore(&mq->lock, flags); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch b/queue-6.18/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch new file mode 100644 index 0000000000..d6f9e367b7 --- /dev/null +++ b/queue-6.18/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch @@ -0,0 +1,58 @@ +From 19a517b2b6d6544d3018b0d46e3860dc5da46c6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 22:32:28 +0100 +Subject: dm init: ensure device probing has finished in dm-mod.waitfor= + +From: Guillaume Gonnet + +[ Upstream commit 99a2312f69805f4ba92d98a757625e0300a747ab ] + +The early_lookup_bdev() function returns successfully when the disk +device is present but not necessarily its partitions. In this situation, +dm_early_create() fails as the partition block device does not exist +yet. + +In my case, this phenomenon occurs quite often because the device is +an SD card with slow reading times, on which kernel takes time to +enumerate available partitions. + +Fortunately, the underlying device is back to "probing" state while +enumerating partitions. Waiting for all probing to end is enough to fix +this issue. + +That's also the reason why this problem never occurs with rootwait= +parameter: the while loop inside wait_for_root() explicitly waits for +probing to be done and then the function calls async_synchronize_full(). +These lines were omitted in 035641b, even though the commit says it's +based on the rootwait logic... + +Anyway, calling wait_for_device_probe() after our while loop does the +job (it both waits for probing and calls async_synchronize_full). + +Fixes: 035641b01e72 ("dm init: add dm-mod.waitfor to wait for asynchronously probed block devices") +Signed-off-by: Guillaume Gonnet +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-init.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c +index b37bbe7625003..423269cbdd2bb 100644 +--- a/drivers/md/dm-init.c ++++ b/drivers/md/dm-init.c +@@ -303,8 +303,10 @@ static int __init dm_init_init(void) + } + } + +- if (waitfor[0]) ++ if (waitfor[0]) { ++ wait_for_device_probe(); + DMINFO("all devices available"); ++ } + + list_for_each_entry(dev, &devices, list) { + if (dm_early_create(&dev->dmi, dev->table, +-- +2.53.0 + diff --git a/queue-6.18/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch b/queue-6.18/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch new file mode 100644 index 0000000000..a36a0bc6ef --- /dev/null +++ b/queue-6.18/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch @@ -0,0 +1,81 @@ +From 68353aaed40482a60d17f18ab28857dcbcd05a5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:05:48 +0800 +Subject: dm log: fix out-of-bounds write due to region_count overflow + +From: Junrui Luo + +[ Upstream commit c20e36b7631d83e7535877f08af8b0af72c44b1a ] + +The local variable region_count in create_log_context() is declared as +unsigned int (32-bit), but dm_sector_div_up() returns sector_t (64-bit). +When a device-mapper target has a sufficiently large ti->len with a small +region_size, the division result can exceed UINT_MAX. The truncated +value is then used to calculate bitset_size, causing clean_bits, +sync_bits, and recovering_bits to be allocated far smaller than needed +for the actual number of regions. + +Subsequent log operations (log_set_bit, log_clear_bit, log_test_bit) use +region indices derived from the full untruncated region space, causing +out-of-bounds writes to kernel heap memory allocated by vmalloc. + +This can be reproduced by creating a mirror target whose region_count +overflows 32 bits: + + dmsetup create bigzero --table '0 8589934594 zero' + dmsetup create mymirror --table '0 8589934594 mirror \ + core 2 2 nosync 2 /dev/mapper/bigzero 0 \ + /dev/mapper/bigzero 0' + +The status output confirms the truncation (sync_count=1 instead of +4294967297, because 0x100000001 was truncated to 1): + + $ dmsetup status mymirror + 0 8589934594 mirror 2 254:1 254:1 1/4294967297 ... + +This leads to a kernel crash in core_in_sync: + + BUG: scheduling while atomic: (udev-worker)/9150/0x00000000 + RIP: 0010:core_in_sync+0x14/0x30 [dm_log] + CR2: 0000000000000008 + Fixing recursive fault but reboot is needed! + +Fix by widening the local region_count to sector_t and adding an +explicit overflow check before the value is assigned to lc->region_count. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-log.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c +index bced5a783ee33..4a1369b8f44a0 100644 +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -373,7 +373,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + + struct log_c *lc; + uint32_t region_size; +- unsigned int region_count; ++ sector_t region_count; + size_t bitset_size, buf_size; + int r; + char dummy; +@@ -401,6 +401,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + } + + region_count = dm_sector_div_up(ti->len, region_size); ++ if (region_count > UINT_MAX) { ++ DMWARN("region count exceeds limit of %u", UINT_MAX); ++ return -EINVAL; ++ } + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) { +-- +2.53.0 + diff --git a/queue-6.18/dm-mpath-don-t-stop-probing-paths-at-presuspend.patch b/queue-6.18/dm-mpath-don-t-stop-probing-paths-at-presuspend.patch new file mode 100644 index 0000000000..1899c336ec --- /dev/null +++ b/queue-6.18/dm-mpath-don-t-stop-probing-paths-at-presuspend.patch @@ -0,0 +1,102 @@ +From 819a782276d59e69711bcfbc7de7d2954d4855f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:05:41 -0500 +Subject: dm-mpath: don't stop probing paths at presuspend + +From: Benjamin Marzinski + +[ Upstream commit 51d81e14fe6788dc6463064c7517480f2acd2724 ] + +Commit 5c977f102315 ("dm-mpath: Don't grab work_mutex while probing +paths"), added code to make multipath quit probing paths early, if it +was trying to suspend. This isn't necessary. It was just an optimization +to try to keep path probing from delaying a suspend. However it causes +problems with the intended user of this code, qemu. The path probing +code was added because failed ioctls to multipath devices don't cause +paths to fail in cases where a regular IO failure would. + +If an ioctl to a path failed because the path was down, and the +multipath device had passed presuspend, the M_MPATH_PROBE_PATHS ioctl +would exit early, without probing the path. The caller would then retry +the original ioctl, hoping to use a different path. But if there was +only one path in the pathgroup, it would pick the same non-working path +again, even if there were working paths in other pathgroups. + +ioctls to a suspended dm device will return -EAGAIN, notifying the +caller that the device is suspended, but ioctls to a device that is just +preparing to suspend won't (and in general, shouldn't). This means that +the caller (qemu in this case) would get into a tight loop where it +would issue an ioctl that failed, skip probing the paths because the +device had already passed presuspend, and start over issuing the ioctl +again. This would continue until the multipath device finally fully +suspended, or the caller gave up and failed the ioctl. + +multipath's path probing code could return -EAGAIN in this case, and the +caller could delay a bit before retrying, but the whole purpose of +skipping the probe after presuspend was to speed things up, and that +would just slow them down. Instead, remove the is_suspending flag, and +check dm_suspended() instead to decide whether to exit the probing code +early. This means that when the probing code exits early, future ioctls +will also be delayed, because the device is fully suspended. + +Fixes: 5c977f102315 ("dm-mpath: Don't grab work_mutex while probing paths") +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +Reviewed-by: Hanna Czenczek +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-mpath.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c +index 00df5be165759..3a25ec2993dc2 100644 +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -102,7 +102,6 @@ struct multipath { + struct bio_list queued_bios; + + struct timer_list nopath_timer; /* Timeout for queue_if_no_path */ +- bool is_suspending; + }; + + /* +@@ -1748,9 +1747,6 @@ static void multipath_presuspend(struct dm_target *ti) + { + struct multipath *m = ti->private; + +- spin_lock_irq(&m->lock); +- m->is_suspending = true; +- spin_unlock_irq(&m->lock); + /* FIXME: bio-based shouldn't need to always disable queue_if_no_path */ + if (m->queue_mode == DM_TYPE_BIO_BASED || !dm_noflush_suspending(m->ti)) + queue_if_no_path(m, false, true, __func__); +@@ -1773,7 +1769,6 @@ static void multipath_resume(struct dm_target *ti) + struct multipath *m = ti->private; + + spin_lock_irq(&m->lock); +- m->is_suspending = false; + if (test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags)) { + set_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags); + clear_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags); +@@ -2100,7 +2095,7 @@ static int probe_active_paths(struct multipath *m) + if (m->current_pg == m->last_probed_pg) + goto skip_probe; + } +- if (!m->current_pg || m->is_suspending || ++ if (!m->current_pg || dm_suspended(m->ti) || + test_bit(MPATHF_QUEUE_IO, &m->flags)) + goto skip_probe; + set_bit(MPATHF_DELAY_PG_SWITCH, &m->flags); +@@ -2109,7 +2104,7 @@ static int probe_active_paths(struct multipath *m) + + list_for_each_entry(pgpath, &pg->pgpaths, list) { + if (pg != READ_ONCE(m->current_pg) || +- READ_ONCE(m->is_suspending)) ++ dm_suspended(m->ti)) + goto out; + if (!pgpath->is_active) + continue; +-- +2.53.0 + diff --git a/queue-6.18/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch b/queue-6.18/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch new file mode 100644 index 0000000000..76bad72634 --- /dev/null +++ b/queue-6.18/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch @@ -0,0 +1,50 @@ +From 39e7676f50532abb836754ae97d522ba29db9113 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 14:02:19 +0800 +Subject: dmaengine: dw-axi-dmac: Remove unnecessary return statement from void + function + +From: Khairul Anuar Romli + +[ Upstream commit 48278a72fce8a8d30efaedeb206c9c3f05c1eb3f ] + +checkpatch.pl --strict reports a WARNING in dw-axi-dmac-platform.c: + + WARNING: void function return statements are not generally useful + FILE: drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c + +According to Linux kernel coding style [Documentation/process/ +coding-style.rst], explicit "return;" statements at the end of void +functions are redundant and should be omitted. The function will +automatically return upon reaching the closing brace, so the extra +statement adds unnecessary clutter without functional benefit. + +This patch removes the superfluous "return;" statement in +dw_axi_dma_set_hw_channel() to comply with kernel coding standards and +eliminate the checkpatch warning. + +Fixes: 32286e279385 ("dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel") +Signed-off-by: Khairul Anuar Romli +Link: https://patch.msgid.link/20260202060224.12616-4-karom.9560@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index b23536645ff7c..b0e689f48bb67 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -592,8 +592,6 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) + (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0); +- +- return; + } + + /* +-- +2.53.0 + diff --git a/queue-6.18/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch b/queue-6.18/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch new file mode 100644 index 0000000000..ce2256e188 --- /dev/null +++ b/queue-6.18/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch @@ -0,0 +1,37 @@ +From 763cb17cbfeb52b98e9c2fb8d2d163c48c1e531c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:41:38 -0500 +Subject: dmaengine: mxs-dma: Fix missing return value from + of_dma_controller_register() + +From: Frank Li + +[ Upstream commit ab2bf6d4c0a0152907b18d25c1b118ea5ea779df ] + +Propagate the return value of of_dma_controller_register() in probe() +instead of ignoring it. + +Fixes: a580b8c5429a6 ("dmaengine: mxs-dma: add dma support for i.MX23/28") +Signed-off-by: Frank Li +Link: https://patch.msgid.link/20260225-mxsdma-module-v3-2-8f798b13baa6@nxp.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mxs-dma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c +index cfb9962417ef6..53f572b6b6fc6 100644 +--- a/drivers/dma/mxs-dma.c ++++ b/drivers/dma/mxs-dma.c +@@ -824,6 +824,7 @@ static int mxs_dma_probe(struct platform_device *pdev) + if (ret) { + dev_err(mxs_dma->dma_device.dev, + "failed to register controller\n"); ++ return ret; + } + + dev_info(mxs_dma->dma_device.dev, "initialized\n"); +-- +2.53.0 + diff --git a/queue-6.18/documentation-fix-a-hugetlbfs-reservation-statement.patch b/queue-6.18/documentation-fix-a-hugetlbfs-reservation-statement.patch new file mode 100644 index 0000000000..f263e6e9d0 --- /dev/null +++ b/queue-6.18/documentation-fix-a-hugetlbfs-reservation-statement.patch @@ -0,0 +1,63 @@ +From 5f7f77084d91684376deeec9e4f5d342bf587d50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 13:10:15 -0700 +Subject: Documentation: fix a hugetlbfs reservation statement + +From: Jane Chu + +[ Upstream commit 7a197d346a44384a1a858a98ef03766840e561d4 ] + +Documentation/mm/hugetlbfs_reserv.rst has + if (resv_needed <= (resv_huge_pages - free_huge_pages)) + resv_huge_pages += resv_needed; +which describes this code in gather_surplus_pages() + needed = (h->resv_huge_pages + delta) - h->free_huge_pages; + if (needed <= 0) { + h->resv_huge_pages += delta; + return 0; + } +which means if there are enough free hugepages to account for the new +reservation, simply update the global reservation count without +further action. + +But the description is backwards, it should be + if (resv_needed <= (free_huge_pages - resv_huge_pages)) +instead. + +Link: https://lkml.kernel.org/r/20260302201015.1824798-1-jane.chu@oracle.com +Fixes: 70bc0dc578b3 ("Documentation: vm, add hugetlbfs reservation overview") +Signed-off-by: Jane Chu +Cc: David Hildenbrand +Cc: Hillf Danton +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Oscar Salvador +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/mm/hugetlbfs_reserv.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/mm/hugetlbfs_reserv.rst b/Documentation/mm/hugetlbfs_reserv.rst +index 4914fbf07966c..a49115db18c76 100644 +--- a/Documentation/mm/hugetlbfs_reserv.rst ++++ b/Documentation/mm/hugetlbfs_reserv.rst +@@ -155,7 +155,7 @@ are enough free huge pages to accommodate the reservation. If there are, + the global reservation count resv_huge_pages is adjusted something like the + following:: + +- if (resv_needed <= (resv_huge_pages - free_huge_pages)) ++ if (resv_needed <= (free_huge_pages - resv_huge_pages) + resv_huge_pages += resv_needed; + + Note that the global lock hugetlb_lock is held when checking and adjusting +-- +2.53.0 + diff --git a/queue-6.18/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch b/queue-6.18/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch new file mode 100644 index 0000000000..6095a95fdd --- /dev/null +++ b/queue-6.18/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch @@ -0,0 +1,54 @@ +From 108e1e2f8d6d0ce799cc6afc8086b597150ab3ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:06 +0000 +Subject: dpaa2: add independent dependencies for FSL_DPAA2_SWITCH + +From: Cai Xinchen + +[ Upstream commit 12589892f41c4c645c80ef9f036f7451a6045624 ] + +Since the commit 84cba72956fd ("dpaa2-switch: integrate +the MAC endpoint support") included dpaa2-mac.o in the driver, +but it didn't select PCS_LYNX, PHYLINK and FSL_XGMAC_MDIO. it +will lead to link error, such as +undefined reference to `phylink_ethtool_ksettings_set' +undefined reference to `lynx_pcs_create_fwnode' + +And the same reason as the commit d2624e70a2f53 ("dpaa2-eth: select +XGMAC_MDIO for MDIO bus support"), enable the FSL_XGMAC_MDIO Kconfig +option in order to have MDIO access to internal and external PHYs. + +Because dpaa2-switch uses fsl_mc_driver APIs, add depends on FSL_MC_BUS +&& FSL_MC_DPIO as FSL_DPAA2_SWITCH do. + +FSL_XGMAC_MDIO and FSL_MC_BUS depend on OF, thus the dependence of +FSL_MC_BUS can satisfy FSL_XGMAC_MDIO's OF requirement. + +Fixes: 84cba72956fd ("dpaa2-switch: integrate the MAC endpoint support") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-2-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/dpaa2/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig +index d029b69c3f183..36280e5d99e1f 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig ++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig +@@ -34,6 +34,10 @@ config FSL_DPAA2_SWITCH + tristate "Freescale DPAA2 Ethernet Switch" + depends on BRIDGE || BRIDGE=n + depends on NET_SWITCHDEV ++ depends on FSL_MC_BUS && FSL_MC_DPIO ++ select PHYLINK ++ select PCS_LYNX ++ select FSL_XGMAC_MDIO + help + Driver for Freescale DPAA2 Ethernet Switch. This driver manages + switch objects discovered on the Freeescale MC bus. +-- +2.53.0 + diff --git a/queue-6.18/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch b/queue-6.18/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch new file mode 100644 index 0000000000..2466301651 --- /dev/null +++ b/queue-6.18/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch @@ -0,0 +1,42 @@ +From d9db72647f12d04cd0daec51020f6404bb5c51d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:07 +0000 +Subject: dpaa2: compile dpaa2 even CONFIG_FSL_DPAA2_ETH=n + +From: Cai Xinchen + +[ Upstream commit 97daf00745f7f9f261b0e91418de6e79d7826c36 ] + +CONFIG_FSL_DPAA2_ETH and CONFIG_FSL_DPAA2_SWITCH are not +associated, but the compilation of FSL_DPAA2_SWITCH depends on +the compilation of the dpaa2 folder. The files controlled by +CONFIG_FSL_DPAA2_SWITCH in the dpaa2 folder are not controlled +by CONFIG_FSL_DPAA2_ETH, except for the files controlled by +CONFIG_FSL_DPAA2_SWITCH. Therefore, removing the restriction will +not affect the compilation of the files in the directory. + +Fixes: f48298d3fbfaa ("staging: dpaa2-switch: move the driver out of staging") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-3-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/Makefile | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile +index de7b318422330..d0a259e47960f 100644 +--- a/drivers/net/ethernet/freescale/Makefile ++++ b/drivers/net/ethernet/freescale/Makefile +@@ -22,6 +22,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o + obj-$(CONFIG_FSL_FMAN) += fman/ + obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/ + +-obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/ +- ++obj-y += dpaa2/ + obj-y += enetc/ +-- +2.53.0 + diff --git a/queue-6.18/dpll-add-notifier-chain-for-dpll-events.patch b/queue-6.18/dpll-add-notifier-chain-for-dpll-events.patch new file mode 100644 index 0000000000..89e17ec513 --- /dev/null +++ b/queue-6.18/dpll-add-notifier-chain-for-dpll-events.patch @@ -0,0 +1,240 @@ +From 8ae7a5e641b7a5e3c3a8fd07a18cc98bc6ccc281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 18:39:56 +0100 +Subject: dpll: Add notifier chain for dpll events + +From: Petr Oros + +[ Upstream commit 2be467588d6bc6ec5988fc254e62a44b865912a0 ] + +Currently, the DPLL subsystem reports events (creation, deletion, changes) +to userspace via Netlink. However, there is no mechanism for other kernel +components to be notified of these events directly. + +Add a raw notifier chain to the DPLL core protected by dpll_lock. This +allows other kernel subsystems or drivers to register callbacks and +receive notifications when DPLL devices or pins are created, deleted, +or modified. + +Define the following: +- Registration helpers: {,un}register_dpll_notifier() +- Event types: DPLL_DEVICE_CREATED, DPLL_PIN_CREATED, etc. +- Context structures: dpll_{device,pin}_notifier_info to pass relevant + data to the listeners. + +The notification chain is invoked alongside the existing Netlink event +generation to ensure in-kernel listeners are kept in sync with the +subsystem state. + +Reviewed-by: Vadim Fedorenko +Co-developed-by: Ivan Vecera +Signed-off-by: Ivan Vecera +Signed-off-by: Petr Oros +Reviewed-by: Arkadiusz Kubalewski +Reviewed-by: Aleksandr Loktionov +Link: https://patch.msgid.link/20260203174002.705176-4-ivecera@redhat.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 9e5dead140af ("ice: add dpll peer notification for paired SMA and U.FL pins") +Signed-off-by: Sasha Levin +--- + drivers/dpll/dpll_core.c | 57 +++++++++++++++++++++++++++++++++++++ + drivers/dpll/dpll_core.h | 4 +++ + drivers/dpll/dpll_netlink.c | 6 ++++ + include/linux/dpll.h | 29 +++++++++++++++++++ + 4 files changed, 96 insertions(+) + +diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c +index f04ed7195cadd..b05fe2ba46d91 100644 +--- a/drivers/dpll/dpll_core.c ++++ b/drivers/dpll/dpll_core.c +@@ -23,6 +23,8 @@ DEFINE_MUTEX(dpll_lock); + DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); + DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC); + ++static RAW_NOTIFIER_HEAD(dpll_notifier_chain); ++ + static u32 dpll_device_xa_id; + static u32 dpll_pin_xa_id; + +@@ -46,6 +48,39 @@ struct dpll_pin_registration { + void *cookie; + }; + ++static int call_dpll_notifiers(unsigned long action, void *info) ++{ ++ lockdep_assert_held(&dpll_lock); ++ return raw_notifier_call_chain(&dpll_notifier_chain, action, info); ++} ++ ++void dpll_device_notify(struct dpll_device *dpll, unsigned long action) ++{ ++ struct dpll_device_notifier_info info = { ++ .dpll = dpll, ++ .id = dpll->id, ++ .idx = dpll->device_idx, ++ .clock_id = dpll->clock_id, ++ .type = dpll->type, ++ }; ++ ++ call_dpll_notifiers(action, &info); ++} ++ ++void dpll_pin_notify(struct dpll_pin *pin, unsigned long action) ++{ ++ struct dpll_pin_notifier_info info = { ++ .pin = pin, ++ .id = pin->id, ++ .idx = pin->pin_idx, ++ .clock_id = pin->clock_id, ++ .fwnode = pin->fwnode, ++ .prop = &pin->prop, ++ }; ++ ++ call_dpll_notifiers(action, &info); ++} ++ + struct dpll_device *dpll_device_get_by_id(int id) + { + if (xa_get_mark(&dpll_device_xa, id, DPLL_REGISTERED)) +@@ -539,6 +574,28 @@ void dpll_netdev_pin_clear(struct net_device *dev) + } + EXPORT_SYMBOL(dpll_netdev_pin_clear); + ++int register_dpll_notifier(struct notifier_block *nb) ++{ ++ int ret; ++ ++ mutex_lock(&dpll_lock); ++ ret = raw_notifier_chain_register(&dpll_notifier_chain, nb); ++ mutex_unlock(&dpll_lock); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(register_dpll_notifier); ++ ++int unregister_dpll_notifier(struct notifier_block *nb) ++{ ++ int ret; ++ ++ mutex_lock(&dpll_lock); ++ ret = raw_notifier_chain_unregister(&dpll_notifier_chain, nb); ++ mutex_unlock(&dpll_lock); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(unregister_dpll_notifier); ++ + /** + * dpll_pin_get - find existing or create new dpll pin + * @clock_id: clock_id of creator +diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h +index d3e17ff0ecef0..b7b4bb251f739 100644 +--- a/drivers/dpll/dpll_core.h ++++ b/drivers/dpll/dpll_core.h +@@ -91,4 +91,8 @@ struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs); + extern struct xarray dpll_device_xa; + extern struct xarray dpll_pin_xa; + extern struct mutex dpll_lock; ++ ++void dpll_device_notify(struct dpll_device *dpll, unsigned long action); ++void dpll_pin_notify(struct dpll_pin *pin, unsigned long action); ++ + #endif +diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c +index 64944f601ee5a..fe9c3d9073f0f 100644 +--- a/drivers/dpll/dpll_netlink.c ++++ b/drivers/dpll/dpll_netlink.c +@@ -742,17 +742,20 @@ dpll_device_event_send(enum dpll_cmd event, struct dpll_device *dpll) + + int dpll_device_create_ntf(struct dpll_device *dpll) + { ++ dpll_device_notify(dpll, DPLL_DEVICE_CREATED); + return dpll_device_event_send(DPLL_CMD_DEVICE_CREATE_NTF, dpll); + } + + int dpll_device_delete_ntf(struct dpll_device *dpll) + { ++ dpll_device_notify(dpll, DPLL_DEVICE_DELETED); + return dpll_device_event_send(DPLL_CMD_DEVICE_DELETE_NTF, dpll); + } + + static int + __dpll_device_change_ntf(struct dpll_device *dpll) + { ++ dpll_device_notify(dpll, DPLL_DEVICE_CHANGED); + return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); + } + +@@ -810,16 +813,19 @@ dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin) + + int dpll_pin_create_ntf(struct dpll_pin *pin) + { ++ dpll_pin_notify(pin, DPLL_PIN_CREATED); + return dpll_pin_event_send(DPLL_CMD_PIN_CREATE_NTF, pin); + } + + int dpll_pin_delete_ntf(struct dpll_pin *pin) + { ++ dpll_pin_notify(pin, DPLL_PIN_DELETED); + return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); + } + + int __dpll_pin_change_ntf(struct dpll_pin *pin) + { ++ dpll_pin_notify(pin, DPLL_PIN_CHANGED); + return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); + } + +diff --git a/include/linux/dpll.h b/include/linux/dpll.h +index f0c31a111c304..34b005bb4df6f 100644 +--- a/include/linux/dpll.h ++++ b/include/linux/dpll.h +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + + struct dpll_device; +@@ -167,6 +168,30 @@ struct dpll_pin_properties { + u32 phase_gran; + }; + ++#define DPLL_DEVICE_CREATED 1 ++#define DPLL_DEVICE_DELETED 2 ++#define DPLL_DEVICE_CHANGED 3 ++#define DPLL_PIN_CREATED 4 ++#define DPLL_PIN_DELETED 5 ++#define DPLL_PIN_CHANGED 6 ++ ++struct dpll_device_notifier_info { ++ struct dpll_device *dpll; ++ u32 id; ++ u32 idx; ++ u64 clock_id; ++ enum dpll_type type; ++}; ++ ++struct dpll_pin_notifier_info { ++ struct dpll_pin *pin; ++ u32 id; ++ u32 idx; ++ u64 clock_id; ++ const struct fwnode_handle *fwnode; ++ const struct dpll_pin_properties *prop; ++}; ++ + #if IS_ENABLED(CONFIG_DPLL) + void dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin); + void dpll_netdev_pin_clear(struct net_device *dev); +@@ -237,4 +262,8 @@ int dpll_device_change_ntf(struct dpll_device *dpll); + + int dpll_pin_change_ntf(struct dpll_pin *pin); + ++int register_dpll_notifier(struct notifier_block *nb); ++ ++int unregister_dpll_notifier(struct notifier_block *nb); ++ + #endif +-- +2.53.0 + diff --git a/queue-6.18/dpll-allow-associating-dpll-pin-with-a-firmware-node.patch b/queue-6.18/dpll-allow-associating-dpll-pin-with-a-firmware-node.patch new file mode 100644 index 0000000000..e15935cac2 --- /dev/null +++ b/queue-6.18/dpll-allow-associating-dpll-pin-with-a-firmware-node.patch @@ -0,0 +1,174 @@ +From 48a6aaada72fe1bb59a872a6619851b6a965e097 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 18:39:54 +0100 +Subject: dpll: Allow associating dpll pin with a firmware node + +From: Ivan Vecera + +[ Upstream commit d0f4771e2befbe8de3a16a564c6bbd1d5502cec3 ] + +Extend the DPLL core to support associating a DPLL pin with a firmware +node. This association is required to allow other subsystems (such as +network drivers) to locate and request specific DPLL pins defined in +the Device Tree or ACPI. + +* Add a .fwnode field to the struct dpll_pin +* Introduce dpll_pin_fwnode_set() helper to allow the provider driver + to associate a pin with a fwnode after the pin has been allocated +* Introduce fwnode_dpll_pin_find() helper to allow consumers to search + for a registered DPLL pin using its associated fwnode handle +* Ensure the fwnode reference is properly released in dpll_pin_put() + +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Vadim Fedorenko +Signed-off-by: Ivan Vecera +Reviewed-by: Arkadiusz Kubalewski +Link: https://patch.msgid.link/20260203174002.705176-2-ivecera@redhat.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 9e5dead140af ("ice: add dpll peer notification for paired SMA and U.FL pins") +Signed-off-by: Sasha Levin +--- + drivers/dpll/dpll_core.c | 49 ++++++++++++++++++++++++++++++++++++++++ + drivers/dpll/dpll_core.h | 2 ++ + include/linux/dpll.h | 11 +++++++++ + 3 files changed, 62 insertions(+) + +diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c +index 8879a72351561..f04ed7195cadd 100644 +--- a/drivers/dpll/dpll_core.c ++++ b/drivers/dpll/dpll_core.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + #include + #include + +@@ -595,12 +596,60 @@ void dpll_pin_put(struct dpll_pin *pin) + xa_destroy(&pin->parent_refs); + xa_destroy(&pin->ref_sync_pins); + dpll_pin_prop_free(&pin->prop); ++ fwnode_handle_put(pin->fwnode); + kfree_rcu(pin, rcu); + } + mutex_unlock(&dpll_lock); + } + EXPORT_SYMBOL_GPL(dpll_pin_put); + ++/** ++ * dpll_pin_fwnode_set - set dpll pin firmware node reference ++ * @pin: pointer to a dpll pin ++ * @fwnode: firmware node handle ++ * ++ * Set firmware node handle for the given dpll pin. ++ */ ++void dpll_pin_fwnode_set(struct dpll_pin *pin, struct fwnode_handle *fwnode) ++{ ++ mutex_lock(&dpll_lock); ++ fwnode_handle_put(pin->fwnode); /* Drop fwnode previously set */ ++ pin->fwnode = fwnode_handle_get(fwnode); ++ mutex_unlock(&dpll_lock); ++} ++EXPORT_SYMBOL_GPL(dpll_pin_fwnode_set); ++ ++/** ++ * fwnode_dpll_pin_find - find dpll pin by firmware node reference ++ * @fwnode: reference to firmware node ++ * ++ * Get existing object of a pin that is associated with given firmware node ++ * reference. ++ * ++ * Context: Acquires a lock (dpll_lock) ++ * Return: ++ * * valid dpll_pin pointer on success ++ * * NULL when no such pin exists ++ */ ++struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode) ++{ ++ struct dpll_pin *pin, *ret = NULL; ++ unsigned long index; ++ ++ mutex_lock(&dpll_lock); ++ xa_for_each(&dpll_pin_xa, index, pin) { ++ if (pin->fwnode == fwnode) { ++ ret = pin; ++ refcount_inc(&ret->refcount); ++ break; ++ } ++ } ++ mutex_unlock(&dpll_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(fwnode_dpll_pin_find); ++ + static int + __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv, void *cookie) +diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h +index 8ce969bbeb64e..d3e17ff0ecef0 100644 +--- a/drivers/dpll/dpll_core.h ++++ b/drivers/dpll/dpll_core.h +@@ -42,6 +42,7 @@ struct dpll_device { + * @pin_idx: index of a pin given by dev driver + * @clock_id: clock_id of creator + * @module: module of creator ++ * @fwnode: optional reference to firmware node + * @dpll_refs: hold referencees to dplls pin was registered with + * @parent_refs: hold references to parent pins pin was registered with + * @ref_sync_pins: hold references to pins for Reference SYNC feature +@@ -54,6 +55,7 @@ struct dpll_pin { + u32 pin_idx; + u64 clock_id; + struct module *module; ++ struct fwnode_handle *fwnode; + struct xarray dpll_refs; + struct xarray parent_refs; + struct xarray ref_sync_pins; +diff --git a/include/linux/dpll.h b/include/linux/dpll.h +index 562f520b23c27..f0c31a111c304 100644 +--- a/include/linux/dpll.h ++++ b/include/linux/dpll.h +@@ -16,6 +16,7 @@ + struct dpll_device; + struct dpll_pin; + struct dpll_pin_esync; ++struct fwnode_handle; + + struct dpll_device_ops { + int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv, +@@ -173,6 +174,8 @@ void dpll_netdev_pin_clear(struct net_device *dev); + size_t dpll_netdev_pin_handle_size(const struct net_device *dev); + int dpll_netdev_add_pin_handle(struct sk_buff *msg, + const struct net_device *dev); ++ ++struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode); + #else + static inline void + dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin) { } +@@ -188,6 +191,12 @@ dpll_netdev_add_pin_handle(struct sk_buff *msg, const struct net_device *dev) + { + return 0; + } ++ ++static inline struct dpll_pin * ++fwnode_dpll_pin_find(struct fwnode_handle *fwnode) ++{ ++ return NULL; ++} + #endif + + struct dpll_device * +@@ -213,6 +222,8 @@ void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin, + + void dpll_pin_put(struct dpll_pin *pin); + ++void dpll_pin_fwnode_set(struct dpll_pin *pin, struct fwnode_handle *fwnode); ++ + int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, + const struct dpll_pin_ops *ops, void *priv); + +-- +2.53.0 + diff --git a/queue-6.18/dpll-export-__dpll_pin_change_ntf-for-use-under-dpll.patch b/queue-6.18/dpll-export-__dpll_pin_change_ntf-for-use-under-dpll.patch new file mode 100644 index 0000000000..2aaa44a7c8 --- /dev/null +++ b/queue-6.18/dpll-export-__dpll_pin_change_ntf-for-use-under-dpll.patch @@ -0,0 +1,83 @@ +From d80cdfef61564f96441968f57168e0b58646feaf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:21 -0700 +Subject: dpll: export __dpll_pin_change_ntf() for use under dpll_lock + +From: Ivan Vecera + +[ Upstream commit 620055cb1036a6125fd912e7a14b47a6572b809b ] + +Export __dpll_pin_change_ntf() so that drivers can send pin change +notifications from within pin callbacks, which are already called +under dpll_lock. Using dpll_pin_change_ntf() in that context would +deadlock. + +Add lockdep_assert_held() to catch misuse without the lock held. + +Acked-by: Vadim Fedorenko +Signed-off-by: Ivan Vecera +Signed-off-by: Petr Oros +Tested-by: Alexander Nowlin +Reviewed-by: Arkadiusz Kubalewski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-9-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 9e5dead140af ("ice: add dpll peer notification for paired SMA and U.FL pins") +Signed-off-by: Sasha Levin +--- + drivers/dpll/dpll_netlink.c | 10 ++++++++++ + drivers/dpll/dpll_netlink.h | 2 -- + include/linux/dpll.h | 1 + + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c +index fe9c3d9073f0f..de8b065280d15 100644 +--- a/drivers/dpll/dpll_netlink.c ++++ b/drivers/dpll/dpll_netlink.c +@@ -823,11 +823,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin) + return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); + } + ++/** ++ * __dpll_pin_change_ntf - notify that the pin has been changed ++ * @pin: registered pin pointer ++ * ++ * Context: caller must hold dpll_lock. Suitable for use inside pin ++ * callbacks which are already invoked under dpll_lock. ++ * Return: 0 if succeeds, error code otherwise. ++ */ + int __dpll_pin_change_ntf(struct dpll_pin *pin) + { ++ lockdep_assert_held(&dpll_lock); + dpll_pin_notify(pin, DPLL_PIN_CHANGED); + return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); + } ++EXPORT_SYMBOL_GPL(__dpll_pin_change_ntf); + + /** + * dpll_pin_change_ntf - notify that the pin has been changed +diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h +index dd28b56d27c56..a9cfd55f57fc4 100644 +--- a/drivers/dpll/dpll_netlink.h ++++ b/drivers/dpll/dpll_netlink.h +@@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll); + int dpll_pin_create_ntf(struct dpll_pin *pin); + + int dpll_pin_delete_ntf(struct dpll_pin *pin); +- +-int __dpll_pin_change_ntf(struct dpll_pin *pin); +diff --git a/include/linux/dpll.h b/include/linux/dpll.h +index 34b005bb4df6f..480ea3cbe709b 100644 +--- a/include/linux/dpll.h ++++ b/include/linux/dpll.h +@@ -260,6 +260,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin, + + int dpll_device_change_ntf(struct dpll_device *dpll); + ++int __dpll_pin_change_ntf(struct dpll_pin *pin); + int dpll_pin_change_ntf(struct dpll_pin *pin); + + int register_dpll_notifier(struct notifier_block *nb); +-- +2.53.0 + diff --git a/queue-6.18/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch b/queue-6.18/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch new file mode 100644 index 0000000000..1c2b814eb4 --- /dev/null +++ b/queue-6.18/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch @@ -0,0 +1,59 @@ +From 4193ed983fc7744c3c73411c43212d9733305a3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:40:54 -0700 +Subject: drbd: Balance RCU calls in drbd_adm_dump_devices() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bart Van Assche + +[ Upstream commit 2b31e86387e60b3689339f0f0fbb4d3623d9d494 ] + +Make drbd_adm_dump_devices() call rcu_read_lock() before +rcu_read_unlock() is called. This has been detected by the Clang +thread-safety analyzer. + +Tested-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Cc: Andreas Gruenbacher +Fixes: a55bbd375d18 ("drbd: Backport the "status" command") +Signed-off-by: Bart Van Assche +Link: https://patch.msgid.link/20260326214054.284593-1-bvanassche@acm.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_nl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index b502038be0a92..0ddbf71286a91 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -3378,8 +3378,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + cb->args[0] = (long)resource; + } + } +@@ -3628,8 +3630,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + } + cb->args[0] = (long)resource; + } +-- +2.53.0 + diff --git a/queue-6.18/drivers-vfio_pci_core-change-pxd_order-check-from-sw.patch b/queue-6.18/drivers-vfio_pci_core-change-pxd_order-check-from-sw.patch new file mode 100644 index 0000000000..0324d5a3dc --- /dev/null +++ b/queue-6.18/drivers-vfio_pci_core-change-pxd_order-check-from-sw.patch @@ -0,0 +1,93 @@ +From 644733b1c5e5714931ac5060c84c7ab860506a93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 18:08:37 +0530 +Subject: drivers/vfio_pci_core: Change PXD_ORDER check from switch case to + if/else block +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ritesh Harjani (IBM) + +[ Upstream commit 948b71aa81cd89b222942db6055e8d9c51c54e78 ] + +Architectures like PowerPC uses runtime defined values for +PMD_ORDER/PUD_ORDER. This is because it can use either RADIX or HASH MMU +at runtime using kernel cmdline. So the pXd_index_size is not known at +compile time. Without this fix, when we add huge pfn support on powerpc +in the next patch, vfio_pci_core driver compilation can fail with the +following errors. + + CC [M] drivers/vfio/vfio_main.o + CC [M] drivers/vfio/group.o + CC [M] drivers/vfio/container.o + CC [M] drivers/vfio/virqfd.o + CC [M] drivers/vfio/vfio_iommu_spapr_tce.o + CC [M] drivers/vfio/pci/vfio_pci_core.o + CC [M] drivers/vfio/pci/vfio_pci_intrs.o + CC [M] drivers/vfio/pci/vfio_pci_rdwr.o + CC [M] drivers/vfio/pci/vfio_pci_config.o + CC [M] drivers/vfio/pci/vfio_pci.o + AR kernel/built-in.a +../drivers/vfio/pci/vfio_pci_core.c: In function ‘vfio_pci_vmf_insert_pfn’: +../drivers/vfio/pci/vfio_pci_core.c:1678:9: error: case label does not reduce to an integer constant + 1678 | case PMD_ORDER: + | ^~~~ +../drivers/vfio/pci/vfio_pci_core.c:1682:9: error: case label does not reduce to an integer constant + 1682 | case PUD_ORDER: + | ^~~~ +make[6]: *** [../scripts/Makefile.build:289: drivers/vfio/pci/vfio_pci_core.o] Error 1 +make[6]: *** Waiting for unfinished jobs.... +make[5]: *** [../scripts/Makefile.build:546: drivers/vfio/pci] Error 2 +make[5]: *** Waiting for unfinished jobs.... +make[4]: *** [../scripts/Makefile.build:546: drivers/vfio] Error 2 +make[3]: *** [../scripts/Makefile.build:546: drivers] Error 2 + +Fixes: f9e54c3a2f5b7 ("vfio/pci: implement huge_fault support") +Signed-off-by: Ritesh Harjani (IBM) +Tested-by: Venkat Rao Bagalkote +Reviewed-by: Alex Williamson +Reviewed-by: Christophe Leroy (CS GROUP) +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/b155e19993ee1f5584c72050192eb468b31c5029.1773058761.git.ritesh.list@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/vfio/pci/vfio_pci_core.c | 19 +++++++------------ + 1 file changed, 7 insertions(+), 12 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index d07f0ede5d731..53a846d3e6758 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -1687,21 +1687,16 @@ vm_fault_t vfio_pci_vmf_insert_pfn(struct vfio_pci_core_device *vdev, + if (vdev->pm_runtime_engaged || !__vfio_pci_memory_enabled(vdev)) + return VM_FAULT_SIGBUS; + +- switch (order) { +- case 0: ++ if (!order) + return vmf_insert_pfn(vmf->vma, vmf->address, pfn); +-#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP +- case PMD_ORDER: ++ ++ if (IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP) && order == PMD_ORDER) + return vmf_insert_pfn_pmd(vmf, pfn, false); +-#endif +-#ifdef CONFIG_ARCH_SUPPORTS_PUD_PFNMAP +- case PUD_ORDER: ++ ++ if (IS_ENABLED(CONFIG_ARCH_SUPPORTS_PUD_PFNMAP) && order == PUD_ORDER) + return vmf_insert_pfn_pud(vmf, pfn, false); +- break; +-#endif +- default: +- return VM_FAULT_FALLBACK; +- } ++ ++ return VM_FAULT_FALLBACK; + } + EXPORT_SYMBOL_GPL(vfio_pci_vmf_insert_pfn); + +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-allow-constructing-dce6-link-encoder.patch b/queue-6.18/drm-amd-display-allow-constructing-dce6-link-encoder.patch new file mode 100644 index 0000000000..b1d808aef1 --- /dev/null +++ b/queue-6.18/drm-amd-display-allow-constructing-dce6-link-encoder.patch @@ -0,0 +1,44 @@ +From 082f4422aaed0f3eb618d9e6113d5a4c04fe5863 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:42 +0200 +Subject: drm/amd/display: Allow constructing DCE6 link encoder without DDC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 880498a1943f865529819f778df3b9945ca57262 ] + +When the DDC channel ID is set to CHANNEL_ID_UNKNOWN, +pass NULL to the AUX regs array. + +This is necessary to support embedded connectors without DDC. + +Fixes: 7c15fd86aaec ("drm/amd/display: dc/dce: add initial DCE6 support (v10)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 38a70e50b22a188ff601740d64dd75f46213121f) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +index f2e47f1ff4b33..e94af8522083c 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +@@ -728,7 +728,8 @@ static struct link_encoder *dce60_link_encoder_create( + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], +- &link_enc_aux_regs[enc_init_data->channel - 1], ++ enc_init_data->channel == CHANNEL_ID_UNKNOWN ? ++ NULL : &link_enc_aux_regs[enc_init_data->channel - 1], + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-allow-constructing-dce8-link-encoder.patch b/queue-6.18/drm-amd-display-allow-constructing-dce8-link-encoder.patch new file mode 100644 index 0000000000..0c262390b3 --- /dev/null +++ b/queue-6.18/drm-amd-display-allow-constructing-dce8-link-encoder.patch @@ -0,0 +1,44 @@ +From e3c7864c0cd941f5da17d0b86f83b86ef7927bf0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:43 +0200 +Subject: drm/amd/display: Allow constructing DCE8 link encoder without DDC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 60af4605ef35ecb7ad649a8534b83a2f7c69576d ] + +When the DDC channel ID is set to CHANNEL_ID_UNKNOWN, +pass NULL to the AUX regs array. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 155baf3038c1af50b602723022ed869b38e86a99) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +index 8822d5818d29e..b645c0c8ec3c5 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +@@ -734,7 +734,8 @@ static struct link_encoder *dce80_link_encoder_create( + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], +- &link_enc_aux_regs[enc_init_data->channel - 1], ++ enc_init_data->channel == CHANNEL_ID_UNKNOWN ? ++ NULL : &link_enc_aux_regs[enc_init_data->channel - 1], + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch b/queue-6.18/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch new file mode 100644 index 0000000000..878e5f69e9 --- /dev/null +++ b/queue-6.18/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch @@ -0,0 +1,45 @@ +From 7d8b6a0172ac67814020db13ce4ad84a40bd8871 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:41 +0200 +Subject: drm/amd/display: Allow DCE link encoder without AUX registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ] + +Allow constructing the DCE link encoder without DDC, +which means the AUX registers array will be NULL. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 87f30b101af62590faf6020d106da07efdda199b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index 0c50fe266c8a1..4103213a572ad 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -989,7 +989,9 @@ void dce110_link_encoder_hw_init( + ASSERT(result == BP_RESULT_OK); + + } +- aux_initialize(enc110); ++ ++ if (enc110->aux_regs) ++ aux_initialize(enc110); + + /* reinitialize HPD. + * hpd_initialize() will pass DIG_FE id to HW context. +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch b/queue-6.18/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch new file mode 100644 index 0000000000..ab4397c293 --- /dev/null +++ b/queue-6.18/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch @@ -0,0 +1,137 @@ +From d4430fcd5038dc1e8cf089263209592c11ec5804 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:44 +0200 +Subject: drm/amd/display: Read EDID from VBIOS embedded panel info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ] + +Some board manufacturers hardcode the EDID for the embedded +panel in the VBIOS. This EDID should be used when the panel +doesn't have a DDC. + +For reference, see the legacy non-DC display code: +amdgpu_atombios_encoder_get_lcd_info() + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364) +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ + .../display/include/grph_object_ctrl_defs.h | 4 ++ + 2 files changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index 154fd2c18e884..c800c603bf708 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1215,6 +1215,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( + return BP_RESULT_FAILURE; + } + ++static enum bp_result get_embedded_panel_extra_info( ++ struct bios_parser *bp, ++ struct embedded_panel_info *info, ++ const uint32_t table_offset) ++{ ++ uint8_t *record = bios_get_image(&bp->base, table_offset, 1); ++ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; ++ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ++ ++ while (*record != ATOM_RECORD_END_TYPE) { ++ switch (*record) { ++ case LCD_MODE_PATCH_RECORD_MODE_TYPE: ++ record += sizeof(ATOM_PATCH_RECORD_MODE); ++ break; ++ case LCD_RTS_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_RTS_RECORD); ++ break; ++ case LCD_CAP_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); ++ break; ++ case LCD_FAKE_EDID_PATCH_RECORD_TYPE: ++ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; ++ if (fake_edid_record->ucFakeEDIDLength) { ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength; ++ else ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength * 128; ++ ++ info->fake_edid = fake_edid_record->ucFakeEDIDString; ++ ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ info->fake_edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; ++ } ++ break; ++ case LCD_PANEL_RESOLUTION_RECORD_TYPE: ++ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; ++ info->panel_width_mm = panel_res_record->usHSize; ++ info->panel_height_mm = panel_res_record->usVSize; ++ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); ++ break; ++ default: ++ return BP_RESULT_BADBIOSTABLE; ++ } ++ } ++ ++ return BP_RESULT_OK; ++} ++ + static enum bp_result get_embedded_panel_info_v1_2( + struct bios_parser *bp, + struct embedded_panel_info *info) +@@ -1331,6 +1385,10 @@ static enum bp_result get_embedded_panel_info_v1_2( + if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) + info->lcd_timing.misc_info.API_ENABLED = true; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +@@ -1456,6 +1514,10 @@ static enum bp_result get_embedded_panel_info_v1_3( + (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & + lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +index cc467031651da..05eda9b28b328 100644 +--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h ++++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +@@ -153,6 +153,10 @@ struct embedded_panel_info { + uint32_t drr_enabled; + uint32_t min_drr_refresh_rate; + bool realtek_eDPToLVDS; ++ uint16_t panel_width_mm; ++ uint16_t panel_height_mm; ++ uint16_t fake_edid_size; ++ const uint8_t *fake_edid; + }; + + struct dc_firmware_info { +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch b/queue-6.18/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch new file mode 100644 index 0000000000..634b6f55a8 --- /dev/null +++ b/queue-6.18/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch @@ -0,0 +1,38 @@ +From 37321d2f84ad0c616245ec4b93647bff09f5f506 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:03 +0200 +Subject: drm/amd/pm/ci: Clear EnabledForActivity field for memory levels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 5facfd4c4c67e8500116ffec0d9da35d92b9c787 ] + +Follow what radeon did and what amdgpu does for other GPUs with SMU7. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 1d99b4f9bc03e..1494143132eb5 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1217,7 +1217,7 @@ static int ci_populate_single_memory_level( + } + + memory_level->EnabledForThrottle = 1; +- memory_level->EnabledForActivity = 1; ++ memory_level->EnabledForActivity = 0; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; + memory_level->VoltageDownH = 0; +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch b/queue-6.18/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch new file mode 100644 index 0000000000..7b3dfaf612 --- /dev/null +++ b/queue-6.18/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch @@ -0,0 +1,67 @@ +From a44deaf68f0b5c6fc4992a0e7c49d1ea49cd09b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:59 +0200 +Subject: drm/amd/pm/ci: Disable MCLK DPM on problematic CI ASICs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9851f29cb06c09f7dad3867d8b0feec3fc71b6c8 ] + +There are two known cases where MCLK DPM can causes issues: + +Radeon R9 M380 found in iMac computers from 2015. +The SMU in this GPU just hangs as soon as we send it the +PPSMC_MSG_MCLKDPM_Enable command, even when MCLK switching is +disabled, and even when we only populate one MCLK DPM level. +Apply workaround to all devices with the same subsystem ID. + +Radeon R7 260X due to old memory controller microcode. +We only flash the MC ucode when it isn't set up by the VBIOS, +therefore there is no way to make sure that it has the correct +ucode version. + +I verified that this patch fixes the SMU hang on the R9 M380 +which would previously fail to boot. This also fixes the UVD +initialization error on that GPU which happened because the +SMU couldn't ungate the UVD after it hung. + +Fixes: 86457c3b21cb ("drm/amd/powerplay: Add support for CI asics to hwmgr") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +index 2b5ac21fee399..1d6e30269d567 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) + PP_GFXOFF_MASK); + hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; ++ switch (hwmgr->chip_id) { ++ case CHIP_BONAIRE: ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM ++ * R7 260X cards with old MC ucode: MCLK DPM is unstable ++ */ ++ if (adev->pdev->subsystem_vendor == 0x106B || ++ adev->pdev->device == 0x6658) { ++ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); ++ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; ++ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; ++ } ++ break; ++ default: ++ break; ++ } + smu7_init_function_pointers(hwmgr); + break; + case AMDGPU_FAMILY_CZ: +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch b/queue-6.18/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch new file mode 100644 index 0000000000..93e31efb6f --- /dev/null +++ b/queue-6.18/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch @@ -0,0 +1,48 @@ +From 1356b0adb84b5dc5f6e38bf901288c8e26b93c7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:04 +0200 +Subject: drm/amd/pm/ci: Fill DW8 fields from SMC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit baf28ec5795c077406d6f52b8ad39e614153bce6 ] + +In ci_populate_dw8() we currently just read a value from the SMU +and then throw it away. Instead of throwing away the value, +we should use it to fill other fields in DW8 (like radeon). + +Otherwise the value of the other fiels is just cleared when +we copy this data to the SMU later. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 1494143132eb5..aea3ad523cc03 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) + { + struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); + const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; +- uint32_t temp; + + if (ci_read_smc_sram_dword(hwmgr, + fuse_table_offset + + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), +- (uint32_t *)&temp, SMC_RAM_END)) ++ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) + PP_ASSERT_WITH_CODE(false, + "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", + return -EINVAL); +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch b/queue-6.18/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch new file mode 100644 index 0000000000..787e05876e --- /dev/null +++ b/queue-6.18/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch @@ -0,0 +1,41 @@ +From f21bc50910ec6efda7a01e1bc712ba7cb2d2f994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:02 +0200 +Subject: drm/amd/pm/ci: Fix powertune defaults for Hawaii 0x67B0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit d784759c07924280f3c313f205fc48eb62d7cb71 ] + +There is no AMD GPU with the ID 0x66B0, this looks like a typo. +It should be 0x67B0 which is actually part of the PCI ID list, +and should use the Hawaii XT powertune defaults according to +the old radeon driver. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 71b1dad34926e..1d99b4f9bc03e 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) + smu_data->power_tune_defaults = &defaults_hawaii_pro; + break; + case 0x67B8: +- case 0x66B0: ++ case 0x67B0: + smu_data->power_tune_defaults = &defaults_hawaii_xt; + break; + case 0x6640: +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch b/queue-6.18/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch new file mode 100644 index 0000000000..f63cab67c5 --- /dev/null +++ b/queue-6.18/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch @@ -0,0 +1,47 @@ +From 45540878f52f4d939ccbc048abb5563dc38831e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:58 +0200 +Subject: drm/amd/pm/ci: Use highest MCLK on CI when MCLK DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 894f0d34d66cb47fe718fe2ae5c18729d22c5218 ] + +When MCLK DPM is disabled for any reason, populate the MCLK +table with the highest MCLK DPM level, so that the ASIC can +use the highest possible memory clock to get good performance +even when MCLK DPM is disabled. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 0cb7eaaba3844..71b1dad34926e 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1322,6 +1322,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) + return result; + } + ++ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { ++ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ ++ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { ++ levels[i] = levels[dpm_table->mclk_table.count - 1]; ++ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; ++ } ++ } ++ + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; + + dev_id = adev->pdev->device; +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-pm-fix-xgmi-max-speed-reporting.patch b/queue-6.18/drm-amd-pm-fix-xgmi-max-speed-reporting.patch new file mode 100644 index 0000000000..e31431b62d --- /dev/null +++ b/queue-6.18/drm-amd-pm-fix-xgmi-max-speed-reporting.patch @@ -0,0 +1,41 @@ +From ba8a22dbeecd24f7255a597fd68c3842ba9190b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 15:17:00 +0530 +Subject: drm/amd/pm: Fix xgmi max speed reporting + +From: Lijo Lazar + +[ Upstream commit da16822ce5c32b5aca848eaea521936d4410d48c ] + +Fix XGMI max bitrate/width reporting on SMUv13.0.12 SOCs. The data +format got changed when moved to static table from dynamic metrics +table. + +Fixes: 1bec2f270766 ("drm/amd/pm: Fetch SMUv13.0.12 xgmi max speed/width") +Signed-off-by: Lijo Lazar +Reviewed-by: Asad Kamal +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +index cb3fea9e8cf31..72d56cfd9d287 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +@@ -248,8 +248,9 @@ static void smu_v13_0_12_init_xgmi_data(struct smu_context *smu, + int ret; + + if (smu_table->tables[SMU_TABLE_SMU_METRICS].version >= 0x13) { +- max_width = (uint8_t)static_metrics->MaxXgmiWidth; +- max_speed = (uint16_t)static_metrics->MaxXgmiBitrate; ++ max_width = (uint8_t)SMUQ10_ROUND(static_metrics->MaxXgmiWidth); ++ max_speed = ++ (uint16_t)SMUQ10_ROUND(static_metrics->MaxXgmiBitrate); + ret = 0; + } else { + MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table; +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch b/queue-6.18/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch new file mode 100644 index 0000000000..53bbf98fc8 --- /dev/null +++ b/queue-6.18/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch @@ -0,0 +1,129 @@ +From 4385cc77b56d1af4194835ccd603a2369463632e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:05 +0200 +Subject: drm/amd/pm/smu7: Add SCLK cap for quirky Hawaii board +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 4724bc5b8d78c34b993594f9406135408ccb312a ] + +On a specific Radeon R9 390X board, the GPU can "randomly" hang +while gaming. Initially I thought this was a RADV bug and tried +to work around this in Mesa: +commit 8ea08747b86b ("radv: Mitigate GPU hang on Hawaii in Dota 2 and RotTR") + +However, I got some feedback from other users who are reporting +that the above mitigation causes a significant performance +regression for them, and they didn't experience the hang on their +GPU in the first place. + +After some further investigation, it turns out that the problem +is that the highest SCLK DPM level on this board isn't stable. +Lowering SCLK to 1040 MHz (from 1070 MHz) works around the issue, +and has a negligible impact on performance compared to the Mesa +patch. (Note that increasing the voltage can also work around it, +but we felt that lowering the SCLK is the safer option.) + +To solve the above issue, add an "sclk_cap" field to smu7_hwmgr +and set this field for the affected board. The capped SCLK value +correctly appears on the sysfs interface and shows up in GUI +tools such as LACT. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 30 ++++++++++++++++--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h | 1 + + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index 07d946c38ec04..6529a91a613b6 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.vddc_dependency_on_mclk; + struct phm_cac_leakage_table *std_voltage_table = + hwmgr->dyn_state.cac_leakage_table; +- uint32_t i; ++ uint32_t i, clk; + + PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, + "SCLK dependency table is missing. This table is mandatory", return -EINVAL); +@@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + data->dpm_table.sclk_table.count = 0; + + for (i = 0; i < allowed_vdd_sclk_table->count; i++) { ++ clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); ++ + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != +- allowed_vdd_sclk_table->entries[i].clk) { ++ clk) { + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = +- allowed_vdd_sclk_table->entries[i].clk; ++ clk; + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; + data->dpm_table.sclk_table.count++; + } +@@ -3006,6 +3008,25 @@ static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr * + return 0; + } + ++static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) ++{ ++ struct amdgpu_device *adev = hwmgr->adev; ++ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); ++ ++ data->sclk_cap = 0xffffffff; ++ ++ if (hwmgr->od_enabled) ++ return; ++ ++ /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ ++ if (adev->pdev->device == 0x67B0 && ++ adev->pdev->subsystem_vendor == 0x1043) ++ data->sclk_cap = 104000; /* 1040 MHz */ ++ ++ if (data->sclk_cap != 0xffffffff) ++ dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -3017,6 +3038,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + return -ENOMEM; + + hwmgr->backend = data; ++ smu7_set_sclk_cap(hwmgr); + smu7_patch_voltage_workaround(hwmgr); + smu7_init_dpm_defaults(hwmgr); + +@@ -3903,7 +3925,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, + + /* Performance levels are arranged from low to high. */ + performance_level->memory_clock = memory_clock; +- performance_level->engine_clock = engine_clock; ++ performance_level->engine_clock = min(engine_clock, data->sclk_cap); + + pcie_gen_from_bios = visland_clk_info->ucPCIEGen; + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +index d9e8b386bd4d3..66adabeab6a3a 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +@@ -234,6 +234,7 @@ struct smu7_hwmgr { + uint32_t pcie_gen_cap; + uint32_t pcie_lane_cap; + uint32_t pcie_spc_cap; ++ uint32_t sclk_cap; + struct smu7_leakage_voltage vddc_leakage; + struct smu7_leakage_voltage vddci_leakage; + struct smu7_leakage_voltage vddcgfx_leakage; +-- +2.53.0 + diff --git a/queue-6.18/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch b/queue-6.18/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch new file mode 100644 index 0000000000..8d7944064a --- /dev/null +++ b/queue-6.18/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch @@ -0,0 +1,192 @@ +From 56f1f8b6ba9723b8286def1e3c6fec841846f81c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:00 +0200 +Subject: drm/amd/pm/smu7: Fix SMU7 voltage dependency on display clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 0138610c14130425be53423b35336561829965e0 ] + +The DCE (display controller engine) requires a minimum voltage +in order to function correctly, depending on which clock level +it currently uses. + +Add a new table that contains display clock frequency levels +and the corresponding required voltages. The clock frequency +levels are taken from DC (and the old radeon driver's voltage +dependency table for CI in cases where its values were lower). +The voltage levels are taken from the following function: +phm_initializa_dynamic_state_adjustment_rule_settings(). +Furthermore, in case of CI, call smu7_patch_vddc() on the new +table to account for leakage voltage (like in radeon). + +Use the display clock value from amd_pp_display_configuration +to look up the voltage level needed by the DCE. Send the +voltage to the SMU via the PPSMC_MSG_VddC_Request command. + +The previous implementation of this feature was non-functional +because it relied on a "dal_power_level" field which was never +assigned; and it was not at all implemented for CI ASICs. + +I verified this on a Radeon R9 M380 which previously booted to +a black screen with DC enabled (default since Linux 6.19), but +now works correctly. + +Fixes: 599a7e9fe1b6 ("drm/amd/powerplay: implement smu7 hwmgr to manager asics with smu ip version 7.") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 88 ++++++++++++++++++- + drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h | 1 + + 2 files changed, 86 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index 9b28c07282699..07d946c38ec04 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -2802,6 +2802,10 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) + if (tmp) + return -EINVAL; + ++ tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ if (tmp) ++ return -EINVAL; ++ + tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); + if (tmp) + return -EINVAL; +@@ -2885,6 +2889,8 @@ static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) + { + kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); + hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; ++ kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; + kfree(hwmgr->backend); + hwmgr->backend = NULL; + +@@ -2955,6 +2961,51 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) + return ret; + } + ++static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) ++{ ++ struct phm_clock_voltage_dependency_table *table; ++ ++ if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) ++ return 0; ++ ++ table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); ++ if (!table) ++ return -ENOMEM; ++ ++ if (hwmgr->chip_id >= CHIP_POLARIS10) { ++ table->entries[0].clk = 38918; ++ table->entries[1].clk = 45900; ++ table->entries[2].clk = 66700; ++ table->entries[3].clk = 113200; ++ ++ table->entries[0].v = 700; ++ table->entries[1].v = 740; ++ table->entries[2].v = 800; ++ table->entries[3].v = 900; ++ } else { ++ if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { ++ table->entries[0].clk = 35200; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 46700; ++ table->entries[3].clk = 64300; ++ } else { ++ table->entries[0].clk = 0; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 54000; ++ table->entries[3].clk = 62500; ++ } ++ ++ table->entries[0].v = 0; ++ table->entries[1].v = 720; ++ table->entries[2].v = 810; ++ table->entries[3].v = 900; ++ } ++ ++ table->count = 4; ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = table; ++ return 0; ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -2983,6 +3034,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + smu7_get_elb_voltages(hwmgr); + } + ++ result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); ++ if (result) ++ goto fail; ++ + if (hwmgr->pp_table_version == PP_TABLE_V1) { + smu7_complete_dependency_tables(hwmgr); + smu7_set_private_data_based_on_pptable_v1(hwmgr); +@@ -3079,13 +3134,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) + return 0; + } + ++static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) ++{ ++ const struct amd_pp_display_configuration *cfg = hwmgr->display_config; ++ const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = ++ hwmgr->dyn_state.vddc_dependency_on_display_clock; ++ uint32_t i; ++ ++ if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || ++ !cfg || !cfg->num_display || !cfg->display_clk) ++ return 0; ++ ++ /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ ++ for (i = 1; i < vddc_dep_on_dispclk->count; ++i) ++ if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) ++ return vddc_dep_on_dispclk->entries[i].v; ++ ++ return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; ++} ++ ++static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) ++{ ++ uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_VddC_Request, ++ req_vddc * VOLTAGE_SCALE, ++ NULL); ++} ++ + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) + { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + +- if (hwmgr->pp_table_version == PP_TABLE_V1) +- phm_apply_dal_min_voltage_request(hwmgr); +-/* TO DO for v0 iceland and Ci*/ ++ smu7_apply_minimum_dce_voltage_request(hwmgr); + + if (!data->sclk_dpm_key_disabled) { + if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) +diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +index c661185753b42..2f49c95342a14 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +@@ -631,6 +631,7 @@ struct phm_dynamic_state_info { + struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; ++ struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; + struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; + struct phm_clock_array *valid_sclk_values; + struct phm_clock_array *valid_mclk_values; +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch b/queue-6.18/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch new file mode 100644 index 0000000000..599c4692de --- /dev/null +++ b/queue-6.18/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch @@ -0,0 +1,54 @@ +From c5357c68f69c20c8910d3a08db110d1fd3b6c52f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 19:29:54 +0530 +Subject: drm/amdgpu: Add default case in DVI mode validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit e6020a55b8e364d15eac27f9c788e13114eec6b7 ] + +amdgpu_connector_dvi_mode_valid() assigns max_digital_pixel_clock_khz +based on connector_object_id using a switch statement that lacks a +default case. + +In practice this code path should never be hit because the existing +cases already cover all digital connector types that this function is +used for. This is also legacy display code which is not used for new +hardware. + +Add a default case returning MODE_BAD to make the switch exhaustive and +silence the static analyzer smatch error. The new branch is effectively +defensive and should never be reached during normal operation. + +Fixes: 585b2f685c56 ("drm/amdgpu: Respect max pixel clock for HDMI and DVI-D (v2)") +Cc: Dan Carpenter +Cc: Timur Kristóf +Cc: Alex Deucher +Cc: Christian König +Signed-off-by: Srinivasan Shanmugam +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +index 47e9bfba06424..46b04e2203eba 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +@@ -1244,6 +1244,8 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector + case CONNECTOR_OBJECT_ID_HDMI_TYPE_B: + max_digital_pixel_clock_khz = max_dvi_single_link_pixel_clock * 2; + break; ++ default: ++ return MODE_BAD; + } + + /* When the display EDID claims that it's an HDMI display, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch b/queue-6.18/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch new file mode 100644 index 0000000000..22cc8020cd --- /dev/null +++ b/queue-6.18/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch @@ -0,0 +1,133 @@ +From ab67bdfbd0896d603c3ab4033b14fe161564c3d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 15:52:45 +0200 +Subject: drm/amdgpu: fix AMDGPU_INFO_READ_MMR_REG +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 0ef196a208385b7d7da79f411c161b04e97283e2 ] + +There were multiple issues in that code. + +First of all the order between the reset semaphore and the mm_lock was +wrong (e.g. copy_to_user) was called while holding the lock. + +Then we allocated memory while holding the reset semaphore which is also +a pretty big bug and can deadlock. + +Then we used down_read_trylock() instead of waiting for the reset to +finish. + +Signed-off-by: Christian König +Fixes: 9e823f307074 ("drm/amdgpu: Block MMR_READ IOCTL in reset") +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit 361b6e6b303d4b691f6c5974d3eaab67ca6dd90e) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 57 +++++++++++-------------- + 1 file changed, 24 insertions(+), 33 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +index d8c0154c5297d..915406ab9730d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +@@ -837,68 +837,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + ? -EFAULT : 0; + } + case AMDGPU_INFO_READ_MMR_REG: { +- int ret = 0; +- unsigned int n, alloc_size; +- uint32_t *regs; + unsigned int se_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SE_INDEX_MASK; + unsigned int sh_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SH_INDEX_MASK; +- +- if (!down_read_trylock(&adev->reset_domain->sem)) +- return -ENOENT; ++ unsigned int alloc_size; ++ uint32_t *regs; ++ int ret; + + /* set full masks if the userspace set all bits + * in the bitfields + */ +- if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) { ++ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) + se_num = 0xffffffff; +- } else if (se_num >= AMDGPU_GFX_MAX_SE) { +- ret = -EINVAL; +- goto out; +- } ++ else if (se_num >= AMDGPU_GFX_MAX_SE) ++ return -EINVAL; + +- if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { ++ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) + sh_num = 0xffffffff; +- } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { +- ret = -EINVAL; +- goto out; +- } ++ else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) ++ return -EINVAL; + +- if (info->read_mmr_reg.count > 128) { +- ret = -EINVAL; +- goto out; +- } ++ if (info->read_mmr_reg.count > 128) ++ return -EINVAL; + +- regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); +- if (!regs) { +- ret = -ENOMEM; +- goto out; +- } ++ regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), ++ GFP_KERNEL); ++ if (!regs) ++ return -ENOMEM; + ++ down_read(&adev->reset_domain->sem); + alloc_size = info->read_mmr_reg.count * sizeof(*regs); +- + amdgpu_gfx_off_ctrl(adev, false); ++ ret = 0; + for (i = 0; i < info->read_mmr_reg.count; i++) { + if (amdgpu_asic_read_register(adev, se_num, sh_num, + info->read_mmr_reg.dword_offset + i, + ®s[i])) { + DRM_DEBUG_KMS("unallowed offset %#x\n", + info->read_mmr_reg.dword_offset + i); +- kfree(regs); +- amdgpu_gfx_off_ctrl(adev, true); + ret = -EFAULT; +- goto out; ++ break; + } + } + amdgpu_gfx_off_ctrl(adev, true); +- n = copy_to_user(out, regs, min(size, alloc_size)); +- kfree(regs); +- ret = (n ? -EFAULT : 0); +-out: + up_read(&adev->reset_domain->sem); ++ ++ if (!ret) { ++ ret = copy_to_user(out, regs, min(size, alloc_size)) ++ ? -EFAULT : 0; ++ } ++ kfree(regs); + return ret; + } + case AMDGPU_INFO_DEV_INFO: { +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch b/queue-6.18/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch new file mode 100644 index 0000000000..a44e0c3c8f --- /dev/null +++ b/queue-6.18/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch @@ -0,0 +1,40 @@ +From 793f7a5cb18c840228840408aa5e414538d5cad6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:18:28 -0500 +Subject: drm/amdgpu/gfx10: look at the right prop for gfx queue priority +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit 355d96cdec5c61fd83f7eb54f1a28e38809645d6 ] + +Look at hqd_queue_priority rather than hqd_pipe_priority. +In practice, it didn't matter as both were always set for +kernel queues, but that will change in the future. + +Fixes: b07d1d73b09e ("drm/amd/amdgpu: Enable high priority gfx queue") +Reviewed-by:Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 003bcece715eb..234753a10361f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -6751,7 +6751,7 @@ static void gfx_v10_0_gfx_mqd_set_priority(struct amdgpu_device *adev, + /* set up default queue priority level + * 0x0 = low priority, 0x1 = high priority + */ +- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) ++ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) + priority = 1; + + tmp = RREG32_SOC15(GC, 0, mmCP_GFX_HQD_QUEUE_PRIORITY); +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch b/queue-6.18/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch new file mode 100644 index 0000000000..b356477f91 --- /dev/null +++ b/queue-6.18/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch @@ -0,0 +1,40 @@ +From 61dd36e50c42c8da8c4a16a6f0711589e79aa5d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:20:27 -0500 +Subject: drm/amdgpu/gfx11: look at the right prop for gfx queue priority +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit f9a4e81bcbd04e6f967d851f9fe69d8bb3cc08b3 ] + +Look at hqd_queue_priority rather than hqd_pipe_priority. +In practice, it didn't matter as both were always set for +kernel queues, but that will change in the future. + +Fixes: 2e216b1e6ba2 ("drm/amdgpu/gfx11: handle priority setup for gfx pipe1") +Reviewed-by:Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index feb56b6b31c9c..cf23b5da6dbbb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -4080,7 +4080,7 @@ static void gfx_v11_0_gfx_mqd_set_priority(struct amdgpu_device *adev, + /* set up default queue priority level + * 0x0 = low priority, 0x1 = high priority + */ +- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) ++ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) + priority = 1; + + tmp = regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT; +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch b/queue-6.18/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch new file mode 100644 index 0000000000..feed6b387f --- /dev/null +++ b/queue-6.18/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch @@ -0,0 +1,146 @@ +From 2e0f17ab33e0e3eba8248a4139497acc9afe7c70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:33 +0200 +Subject: drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ] + +This commit fixes amdgpu to work on the Radeon HD 7870 XT +which has never worked with the Linux open source drivers before. + +Some boards have "harvested" chips, meaning that some parts of +the chip are disabled and fused, and it's sold for cheaper and +under a different marketing name. +On a harvested chip, any of the following can be disabled: +- CUs (Compute Units) +- RBs (Render Backend, aka. ROP) +- Memory channels (ie. the chip has a lower bandwidth) +- TCCs (ie. less L2 cache) + +Handle chips with harvested TCCs by patching the registers +that configure how TCCs are mapped. + +If some TCCs are disabled, we need to make sure that +the disabled TCCs are not used, and the remaining TCCs +are used optimally. + +TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. + +Note that the TCC configuration is highly relevant to performance. +Suboptimal configuration (eg. CHAN_STEER=0) can significantly +reduce gaming performance. + +For optimal performance: +- Rely on the CHAN_STEER from the golden registers table, + only skip disabled TCCs but keep the mapping order. +- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, + which performs better than using the same TCC twice. + +v2: +- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs. + +Link: https://bugs.freedesktop.org/show_bug.cgi?id=60879 +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2664 +Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 00218d15528fab9f6b31241fe5904eea4fcaa30d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index 80565392313f1..066cdf6863e11 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -1571,6 +1571,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) + mutex_unlock(&adev->grbm_idx_mutex); + } + ++/** ++ * gfx_v6_0_setup_tcc() - setup which TCCs are used ++ * ++ * @adev: amdgpu_device pointer ++ * ++ * Verify whether the current GPU has any TCCs disabled, ++ * which can happen when the GPU is harvested and some ++ * memory channels are disabled, reducing the memory bus width. ++ * For example, on the Radeon HD 7870 XT (Tahiti LE). ++ * ++ * If some TCCs are disabled, we need to make sure that ++ * the disabled TCCs are not used, and the remaining TCCs ++ * are used optimally. ++ * ++ * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. ++ * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. ++ * ++ * For optimal performance: ++ * - Rely on the CHAN_STEER from the golden registers table, ++ * only skip disabled TCCs but keep the mapping order. ++ * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, ++ * which performs better than using the same TCC twice. ++ */ ++static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) ++{ ++ u32 i, tcc, tcp_addr_config, num_active_tcc = 0; ++ u64 chan_steer, patched_chan_steer = 0; ++ const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; ++ const u32 dis_tcc_mask = ++ amdgpu_gfx_create_bitmask(num_max_tcc) & ++ (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), ++ CGTS_TCC_DISABLE, TCC_DISABLE) | ++ REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), ++ CGTS_USER_TCC_DISABLE, TCC_DISABLE)); ++ ++ /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ ++ if (!dis_tcc_mask) ++ return; ++ ++ /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ ++ chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); ++ ++ /* Patch the TCP to TCC mapping to skip disabled TCCs */ ++ for (i = 0; i < num_max_tcc; ++i) { ++ tcc = (chan_steer >> (u64)(4 * i)) & 0xf; ++ ++ if (!((1 << tcc) & dis_tcc_mask)) { ++ /* Copy enabled TCC indices to the patched register value. */ ++ patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); ++ ++num_active_tcc; ++ } ++ } ++ ++ WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); ++ ++ /* Patch number of TCCs used by TCPs */ ++ tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), ++ TCP_ADDR_CONFIG, NUM_TCC_BANKS, ++ num_active_tcc - 1); ++ ++ WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); ++ WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); ++ WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); ++} ++ + static void gfx_v6_0_config_init(struct amdgpu_device *adev) + { + adev->gfx.config.double_offchip_lds_buf = 0; +@@ -1729,6 +1794,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) + gfx_v6_0_tiling_mode_table_init(adev); + + gfx_v6_0_setup_rb(adev); ++ gfx_v6_0_setup_tcc(adev); + + gfx_v6_0_setup_spi(adev); + +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch b/queue-6.18/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch new file mode 100644 index 0000000000..c9bfaa3f93 --- /dev/null +++ b/queue-6.18/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch @@ -0,0 +1,54 @@ +From 77d39f13c2ea8bccfe9d1755d36d79c0a37bfaae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:30 +0200 +Subject: drm/amdgpu/gmc: Fix AMDGPU_GART_PLACEMENT_LOW to not overlap with + VRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 36d65da7570bf72ce28504fa9a81abfc728e6d96 ] + +When the GART placement is set to AMDGPU_GART_PLACEMENT_LOW: +Make sure that GART does not overlap with VRAM when +VRAM is configured to be in the low address space. + +Solve this according to the following logic: +- When GART fits before VRAM, use zero address for GART +- Otherwise, put GART after the end of VRAM, aligned to 4 GiB + +Previously, I had assumed this was not possible +so it was OK to not handle it, but now we got a report +from a user who has a board that is configured this way. + +Fixes: 917f91d8d8e8 ("drm/amdgpu/gmc: add a way to force a particular placement for GART") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 3d9de5d86a1658cadb311461b001eb1df67263ad) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index b8613888c5c33..6d5f90512a74e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -313,7 +313,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, + mc->gart_start = max_mc_address - mc->gart_size + 1; + break; + case AMDGPU_GART_PLACEMENT_LOW: +- mc->gart_start = 0; ++ if (size_bf >= mc->gart_size) ++ mc->gart_start = 0; ++ else ++ mc->gart_start = ALIGN(mc->fb_end, four_gb); + break; + case AMDGPU_GART_PLACEMENT_BEST_FIT: + default: +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch new file mode 100644 index 0000000000..498ac0710f --- /dev/null +++ b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch @@ -0,0 +1,41 @@ +From 6cefaf702cc9c1a60e7174f38019542bb79d8207 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v2.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit e5f612dc91650561fe2b5b76dd6d2898ec9ad480 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 6ac27241106b ("drm/amdgpu: add JPEG v2.0 function supports") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 96179da0c6b059eb31706a0abe8dd6381c533143) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +index 27c76bd424cfb..1e214b493402c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +@@ -802,6 +802,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_0_dec_ring_get_rptr, + .get_wptr = jpeg_v2_0_dec_ring_get_wptr, + .set_wptr = jpeg_v2_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch new file mode 100644 index 0000000000..1e9de7b931 --- /dev/null +++ b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch @@ -0,0 +1,49 @@ +From 0ea5bb9389c919175ec97c61a3c5bb1e0f533446 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v2.5 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 79405e774ede411c6b47ed41c651e40b92de64a2 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 14f43e8f88c5 ("drm/amdgpu: move JPEG2.5 out from VCN2.5") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 3216a7f4e2642bda5fd14f57586e835ae9202587) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +index 20983f126b490..13a6e24c624a2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +@@ -693,6 +693,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, +@@ -724,6 +725,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch new file mode 100644 index 0000000000..84e2876a82 --- /dev/null +++ b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch @@ -0,0 +1,41 @@ +From de6656692180f83864cc34a575cf69edd006eedb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v3.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit a2baf12eec41f246689e6a3f8619af1200031576 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: dfd57dbf44dd ("drm/amdgpu: add JPEG3.0 support for Sienna_Cichlid") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 4d7d774f100efb5089c86a1fb8c5bf47c63fc9ef) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +index d1a011c40ba23..af231d093a3ce 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +@@ -594,6 +594,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v3_0_dec_ring_get_rptr, + .get_wptr = jpeg_v3_0_dec_ring_get_wptr, + .set_wptr = jpeg_v3_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch new file mode 100644 index 0000000000..891f32bf20 --- /dev/null +++ b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch @@ -0,0 +1,41 @@ +From 5c8fb3b344515ed68a78ceb17c4848748ebefd7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit e7e90b5839aeb8805ec83bb4da610b8dab8e184d ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: b13111de32a9 ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_0") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 8d0cac9478a3f046279c657d6a2545de49ae675a) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +index 33db2c1ae6cca..90582066e6a1a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +@@ -759,6 +759,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch new file mode 100644 index 0000000000..c5da5980f4 --- /dev/null +++ b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch @@ -0,0 +1,41 @@ +From fd379737a7751ce7f5f33d71a166f652a9e001a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.3 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 83e37c0987ca92f9e87789b46dd311dcf5a4a6c8 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: e684e654eba9 ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_3") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 2f6afc97d259d530f4f86c7743efbc573a8da927) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +index 47f2192fc7e7e..99e6dabc36ee8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +@@ -1214,6 +1214,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch new file mode 100644 index 0000000000..1a560e4259 --- /dev/null +++ b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch @@ -0,0 +1,41 @@ +From d57fcefdf212fca96745a585bd52dd19f4ea33d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.5 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit b65b7f3f3c18f797f81a2af7c97e2079900ad6db ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 8f98a715da8e ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_5") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit f05d0a4f21fc720116d6e238f23308b199891058) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +index 54fd9c800c40a..a43582b9c876c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +@@ -804,6 +804,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_5_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch new file mode 100644 index 0000000000..cf931c3133 --- /dev/null +++ b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch @@ -0,0 +1,41 @@ +From 46a3369f5ce601238450e2f670c538eb55390ad8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit ea7c61c5f895e8f9ea0ffffa180498ef9c740152 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: dfad65c65728 ("drm/amdgpu: Add JPEG5 support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 0f43893d3cd478fa57836697525b338817c9c23d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +index 46bf15dce2bd0..72a4b2d0676fa 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +@@ -680,6 +680,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, + .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, + .set_wptr = jpeg_v5_0_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.1-ri.patch b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.1-ri.patch new file mode 100644 index 0000000000..4944851eb9 --- /dev/null +++ b/queue-6.18/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.1-ri.patch @@ -0,0 +1,41 @@ +From 9c8dc4974391d613a8de5e0392f8e49a8de71d41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.1 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 2f8e3da71a1b469b6e157aa3972f1448b3157840 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: b8f57b69942b ("drm/amdgpu: Add JPEG5_0_1 support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 742a98e2e81702df8fe1b1eccee5223220a03dc2) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +index ab0bf880d3d8a..1fb2386352ccb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +@@ -875,6 +875,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v5_0_1_dec_ring_get_rptr, + .get_wptr = jpeg_v5_0_1_dec_ring_get_wptr, + .set_wptr = jpeg_v5_0_1_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch b/queue-6.18/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch new file mode 100644 index 0000000000..6085e740a8 --- /dev/null +++ b/queue-6.18/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch @@ -0,0 +1,65 @@ +From 9c9c810dca44507d0a3fcdb89ae7e06cc34be892 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:31 +0200 +Subject: drm/amdgpu/uvd3.1: Don't validate the firmware when already validated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ] + +UVD 3.1 firmware validation seems to always fail after +attempting it when it had already been validated. +(This works similarly with the VCE 1.0 as well.) + +Don't attempt repeating the validation when it's already done. + +This caused issues in situations when the system isn't able +to suspend the GPU properly and so the GPU isn't actually +powered down. Then amdgpu would fail when calling the IP +block resume function. + +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2887 +Fixes: bb7978111dd3 ("drm/amdgpu: fix SI UVD firmware validate resume fail") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 889a2cfd889c4a4dd9d0c89ce9a8e60b78be71dd) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index 2e79a3afc7748..1df45633e8120 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + ++ /* When the keyselect is already set, don't perturb it. */ ++ if (RREG32(mmUVD_FW_START)) ++ return; ++ + /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; +@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) + int i; + uint32_t keysel = adev->uvd.keyselect; + ++ if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { ++ dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", ++ RREG32(mmUVD_FW_START), adev->uvd.keyselect); ++ return 0; ++ } ++ + WREG32(mmUVD_FW_START, keysel); + + for (i = 0; i < 10; ++i) { +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch b/queue-6.18/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch new file mode 100644 index 0000000000..17fb0bc9f4 --- /dev/null +++ b/queue-6.18/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch @@ -0,0 +1,49 @@ +From e28678cfd15bdaaea7b89f28408159c529e0216f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:06 +0200 +Subject: drm/amdgpu/uvd4.2: Don't initialize UVD 4.2 when DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 8b3e8fa6d7bdab292447a43f70532db437d5d4f5 ] + +UVD 4.2 doesn't work at all when DPM is disabled because +the SMU is responsible for ungating it. So, Linux fails +to boot with CIK GPUs when using the amdgpu.dpm=0 parameter. + +Fix this by returning -ENOENT from uvd_v4_2_early_init() +when amdgpu_dpm isn't enabled. + +Note: amdgpu.dpm=0 is often suggested as a workaround +for issues and is useful for debugging. + +Fixes: a2e73f56fa62 ("drm/amdgpu: Add support for CIK parts") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +index 4b96fd5837720..d7302938e6662 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +@@ -93,6 +93,11 @@ static void uvd_v4_2_ring_set_wptr(struct amdgpu_ring *ring) + static int uvd_v4_2_early_init(struct amdgpu_ip_block *ip_block) + { + struct amdgpu_device *adev = ip_block->adev; ++ ++ /* UVD doesn't work without DPM, it needs DPM to ungate it. */ ++ if (!amdgpu_dpm) ++ return -ENOENT; ++ + adev->uvd.num_uvd_inst = 1; + + uvd_v4_2_set_ring_funcs(adev); +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch new file mode 100644 index 0000000000..9d1f9d4efe --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch @@ -0,0 +1,49 @@ +From 179a5f5e5cb0940bfacf031262c18ec8101b12c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v2.0 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8d80b293b41fcb5e9396db93e788b0f4ebcbafb7 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 1b61de45dfaf ("drm/amdgpu: add initial VCN2.0 support (v2)") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit e2b5499fca55f1a32960a311bbb62e35891eaf73) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index e35fae9cdaf66..0442bfcfd384d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -2113,6 +2113,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = { + static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v2_0_dec_ring_get_rptr, + .get_wptr = vcn_v2_0_dec_ring_get_wptr, +@@ -2145,6 +2146,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v2_0_enc_ring_get_rptr, + .get_wptr = vcn_v2_0_enc_ring_get_wptr, + .set_wptr = vcn_v2_0_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch new file mode 100644 index 0000000000..bf793cb0ca --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch @@ -0,0 +1,49 @@ +From 2ee6e81a06ce3c44f339f9e6b900afba5d50ea45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v2.5 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 4f317863a3ab212a027d8c8c3cc3af4e3fb95704 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 28c17d72072b ("drm/amdgpu: add VCN2.5 basic supports") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit efc9dd5590894109bce9a0bfe1fa5592dd6b20b1) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +index 006a154511971..8b8184fe6764b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +@@ -1778,6 +1778,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring) + static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v2_5_dec_ring_get_rptr, + .get_wptr = vcn_v2_5_dec_ring_get_wptr, +@@ -1879,6 +1880,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v2_5_enc_ring_get_rptr, + .get_wptr = vcn_v2_5_enc_ring_get_wptr, + .set_wptr = vcn_v2_5_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch new file mode 100644 index 0000000000..8318cd4f21 --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch @@ -0,0 +1,57 @@ +From 13f3f81df4cc3206b0ad930c658765fa7526b422 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v3.0 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit f1e5a6660d7cbf006079126d9babbf0ccf538c6b ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: cf14826cdfb5 ("drm/amdgpu: add VCN3.0 support for Sienna_Cichlid") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 663bed3c7b8b9a7624b0d95d300ddae034ad0614) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +index 8b226edfbea3e..f773f7ddfd13c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +@@ -1856,6 +1856,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0x3f, + .nop = VCN_DEC_SW_CMD_NO_OP, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v3_0_dec_ring_get_rptr, + .get_wptr = vcn_v3_0_dec_ring_get_wptr, +@@ -2037,6 +2038,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v3_0_dec_ring_get_rptr, + .get_wptr = vcn_v3_0_dec_ring_get_wptr, +@@ -2139,6 +2141,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v3_0_enc_ring_get_rptr, + .get_wptr = vcn_v3_0_enc_ring_get_wptr, + .set_wptr = vcn_v3_0_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0-enc-ri.patch b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0-enc-ri.patch new file mode 100644 index 0000000000..ce4e980e65 --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0-enc-ri.patch @@ -0,0 +1,41 @@ +From b7289268ebe85fe78993a3107ba92356a60f966f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 51f694221047c84fa185be98210eb2c354ffb8c6 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 8da1170a16e4 ("drm/amdgpu: add VCN4 ip block support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit fd852c048b46f9825e904a4f3f4538fe9d8827d9) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +index 64bda0e944a7c..21e40eb2078d1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +@@ -1995,6 +1995,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata), + .get_rptr = vcn_v4_0_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_unified_ring_get_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch new file mode 100644 index 0000000000..5be4b83ab6 --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch @@ -0,0 +1,41 @@ +From 0bf7145d50c3f496f766c744c80a3e97608f8b5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0.3 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 4532b52b34e4e4310386e6fdf6a643368599f522 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: b889ef4ac988 ("drm/amdgpu/vcn: add vcn support for VCN4_0_3") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit ff1a5a125c5a70c328806b9bc01d7d942cf3f9aa) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +index cb7123ec1a5d1..88d1139e931e2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +@@ -1628,6 +1628,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, + .set_wptr = vcn_v4_0_3_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch new file mode 100644 index 0000000000..9c9213d999 --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch @@ -0,0 +1,41 @@ +From 3dcc3571ea64065b3f08a96b658d687ef72e7412 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0.5 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 589a254bf3e88204c8402b9cbccd5e23a0af990f ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 547aad32edac ("drm/amdgpu: add VCN4 ip block support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 084d94ac93707bdda07efb5cee786f632de4219b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +index 1f6a22983c0dd..1571cc5a148c8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +@@ -1483,6 +1483,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, + .set_wptr = vcn_v4_0_5_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch new file mode 100644 index 0000000000..bf3dbc0ffb --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch @@ -0,0 +1,41 @@ +From 66e257ba2f5cb77166274f42515fafe1426af224 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v5.0.0 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8cae0ce77de492d7c31c1532a2e80c0c6e7e58cb ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: b6d1a0632051 ("drm/amdgpu: add VCN_5_0_0 IP block support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 49b1fbbb5a071197ee71e2d70959b1cb29bdc317) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +index 6109124f852e5..d5f49fa33bee4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +@@ -1207,6 +1207,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, + .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, + .set_wptr = vcn_v5_0_0_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.1-enc-.patch b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.1-enc-.patch new file mode 100644 index 0000000000..4cd645c8a5 --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.1-enc-.patch @@ -0,0 +1,41 @@ +From bd60d079a3b84135157b236e82c0478bb9682c6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v5.0.1 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8f4954722eab88e10c4ea0c0d3b1269c31421d3a ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 346492f30ce3 ("drm/amdgpu: Add VCN_5_0_1 support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit e16be95a2c3ee712b142cb27d2dca0b461181359) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +index 8bd457dea4cff..972d4a7147a12 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +@@ -1330,6 +1330,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v5_0_1_unified_ring_get_rptr, + .get_wptr = vcn_v5_0_1_unified_ring_get_wptr, + .set_wptr = vcn_v5_0_1_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn3-avoid-overflow-on-msg-bound-check.patch b/queue-6.18/drm-amdgpu-vcn3-avoid-overflow-on-msg-bound-check.patch new file mode 100644 index 0000000000..ed5afe82ca --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn3-avoid-overflow-on-msg-bound-check.patch @@ -0,0 +1,48 @@ +From 7215dbc314b2d9bca39c081f11d21019cec7ad5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 09:22:15 -0400 +Subject: drm/amdgpu/vcn3: Avoid overflow on msg bound check + +From: Benjamin Cheng + +commit e6e9faba8100628990cccd13f0f044a648c303cf upstream. + +As pointed out by SDL, the previous condition may be vulnerable to +overflow. + +Fixes: b193019860d6 ("drm/amdgpu/vcn3: Prevent OOB reads when parsing dec msg") +Cc: SDL +Signed-off-by: Benjamin Cheng +Reviewed-by: Ruijing Dong +Signed-off-by: Alex Deucher +(cherry picked from commit db00257ac9e4a51eb2515aaea161a019f7125e10) +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +index 558d3bf7fc76e..8b226edfbea3e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +@@ -1971,6 +1971,7 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, + + for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { + uint32_t offset, size, *create; ++ uint64_t buf_end; + + if (msg[0] != RDECODE_MESSAGE_CREATE) + continue; +@@ -1978,7 +1979,8 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, + offset = msg[1]; + size = msg[2]; + +- if (size < 4 || offset + size > end - addr) { ++ if (size < 4 || check_add_overflow(offset, size, &buf_end) || ++ buf_end > end - addr) { + DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); + r = -EINVAL; + goto out; +-- +2.53.0 + diff --git a/queue-6.18/drm-amdgpu-vcn4-avoid-overflow-on-msg-bound-check.patch b/queue-6.18/drm-amdgpu-vcn4-avoid-overflow-on-msg-bound-check.patch new file mode 100644 index 0000000000..e9162fa6cf --- /dev/null +++ b/queue-6.18/drm-amdgpu-vcn4-avoid-overflow-on-msg-bound-check.patch @@ -0,0 +1,48 @@ +From a7ecd869e0a0a46824103566cbedcfded5ef66d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 09:22:15 -0400 +Subject: drm/amdgpu/vcn4: Avoid overflow on msg bound check + +From: Benjamin Cheng + +commit 65bce27ea6192320448c30267ffc17ffa094e713 upstream. + +As pointed out by SDL, the previous condition may be vulnerable to +overflow. + +Fixes: 0a78f2bac142 ("drm/amdgpu/vcn4: Prevent OOB reads when parsing dec msg") +Cc: SDL +Signed-off-by: Benjamin Cheng +Reviewed-by: Ruijing Dong +Signed-off-by: Alex Deucher +(cherry picked from commit 3c5367d950140d4ec7af830b2268a5a6fdaa3885) +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +index 64f294fb1c7a0..64bda0e944a7c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +@@ -1888,6 +1888,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, + + for (i = 0, msg = &msg[6]; i < num_buffers; ++i, msg += 4) { + uint32_t offset, size, *create; ++ uint64_t buf_end; + + if (msg[0] != RDECODE_MESSAGE_CREATE) + continue; +@@ -1895,7 +1896,8 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, + offset = msg[1]; + size = msg[2]; + +- if (size < 4 || offset + size > end - addr) { ++ if (size < 4 || check_add_overflow(offset, size, &buf_end) || ++ buf_end > end - addr) { + DRM_ERROR("VCN message buffer exceeds BO bounds!\n"); + r = -EINVAL; + goto out; +-- +2.53.0 + diff --git a/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch b/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch new file mode 100644 index 0000000000..64ae04660d --- /dev/null +++ b/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch @@ -0,0 +1,75 @@ +From f913e4602811530edf7e03fd043f0afa66536224 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:28 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Add mode_valid hook to + drm_bridge_funcs + +From: Jayesh Choudhary + +[ Upstream commit 6dbff34016052b099558b76632e4983e2df13fed ] + +Add cdns_mhdp_bridge_mode_valid() to check if specific mode is valid for +this bridge or not. In the legacy usecase with +!DRM_BRIDGE_ATTACH_NO_CONNECTOR we were using the hook from +drm_connector_helper_funcs but with DRM_BRIDGE_ATTACH_NO_CONNECTOR +we need to have mode_valid() in drm_bridge_funcs. + +Without this patch, when using DRM_BRIDGE_ATTACH_NO_CONNECTOR +flag, the cdns_mhdp_bandwidth_ok() function would not be called +during mode validation, potentially allowing modes that exceed +the bridge's bandwidth capabilities to be incorrectly marked as +valid. + +Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") +Reviewed-by: Tomi Valkeinen +Signed-off-by: Jayesh Choudhary +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Link: https://patch.msgid.link/20251209120332.3559893-3-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index ef2d0ea606f78..2fb8acd363b14 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2162,6 +2162,25 @@ static const struct drm_edid *cdns_mhdp_bridge_edid_read(struct drm_bridge *brid + return cdns_mhdp_edid_read(mhdp, connector); + } + ++static enum drm_mode_status ++cdns_mhdp_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); ++ ++ mutex_lock(&mhdp->link_mutex); ++ ++ if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes, ++ mhdp->link.rate)) { ++ mutex_unlock(&mhdp->link_mutex); ++ return MODE_CLOCK_HIGH; ++ } ++ ++ mutex_unlock(&mhdp->link_mutex); ++ return MODE_OK; ++} ++ + static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { + .atomic_enable = cdns_mhdp_atomic_enable, + .atomic_disable = cdns_mhdp_atomic_disable, +@@ -2176,6 +2195,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { + .edid_read = cdns_mhdp_bridge_edid_read, + .hpd_enable = cdns_mhdp_bridge_hpd_enable, + .hpd_disable = cdns_mhdp_bridge_hpd_disable, ++ .mode_valid = cdns_mhdp_bridge_mode_valid, + }; + + static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse) +-- +2.53.0 + diff --git a/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch b/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch new file mode 100644 index 0000000000..44a320232f --- /dev/null +++ b/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch @@ -0,0 +1,75 @@ +From ad47dd5b81b1123b0789395929c5fd7774f3efd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:29 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Handle HDCP state in bridge + atomic check + +From: Harikrishna Shenoy + +[ Upstream commit 4a8edd658489ec2a3d7e20482fa9e8d366153d8d ] + +Now that we have DRM_BRIDGE_ATTACH_NO_CONNECTOR framework, handle the +HDCP state change in bridge atomic check as well to enable correct +functioning for HDCP in both DRM_BRIDGE_ATTACH_NO_CONNECTOR and +!DRM_BRIDGE_ATTACH_NO_CONNECTOR case. + +Without this patch, when using DRM_BRIDGE_ATTACH_NO_CONNECTOR flag, HDCP +state changes would not be properly handled during atomic commits, +potentially leading to HDCP authentication failures or incorrect +protection status for content requiring HDCP encryption. + +Fixes: 6a3608eae6d33 ("drm: bridge: cdns-mhdp8546: Enable HDCP") +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Reviewed-by: Tomi Valkeinen +Link: https://patch.msgid.link/20251209120332.3559893-4-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 2fb8acd363b14..7ee19b7cc92fc 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2123,6 +2123,10 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, + { + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; ++ struct drm_connector_state *old_state, *new_state; ++ struct drm_atomic_state *state = crtc_state->state; ++ struct drm_connector *conn = mhdp->connector_ptr; ++ u64 old_cp, new_cp; + + mutex_lock(&mhdp->link_mutex); + +@@ -2142,6 +2146,25 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, + if (mhdp->info) + bridge_state->input_bus_cfg.flags = *mhdp->info->input_bus_flags; + ++ if (conn && mhdp->hdcp_supported) { ++ old_state = drm_atomic_get_old_connector_state(state, conn); ++ new_state = drm_atomic_get_new_connector_state(state, conn); ++ old_cp = old_state->content_protection; ++ new_cp = new_state->content_protection; ++ ++ if (old_state->hdcp_content_type != new_state->hdcp_content_type && ++ new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { ++ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; ++ crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); ++ crtc_state->mode_changed = true; ++ } ++ ++ if (!new_state->crtc) { ++ if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ++ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; ++ } ++ } ++ + mutex_unlock(&mhdp->link_mutex); + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch b/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch new file mode 100644 index 0000000000..b42aeea00c --- /dev/null +++ b/queue-6.18/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch @@ -0,0 +1,196 @@ +From d3435da9eab14da31241a5aadba5367c55e89bed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:27 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Set the mhdp connector + earlier in atomic_enable() + +From: Jayesh Choudhary + +[ Upstream commit 43d6508ddbf9fb974fbc359a033154f78c9d4c8b ] + +In case if we get errors in cdns_mhdp_link_up() or cdns_mhdp_reg_read() +in atomic_enable, we will go to cdns_mhdp_modeset_retry_fn() and will hit +NULL pointer while trying to access the mutex. We need the connector to +be set before that. Unlike in legacy cases with flag +!DRM_BRIDGE_ATTACH_NO_CONNECTOR, we do not have connector initialised +in bridge_attach(), so add the mhdp->connector_ptr in device structure +to handle both cases with DRM_BRIDGE_ATTACH_NO_CONNECTOR and +!DRM_BRIDGE_ATTACH_NO_CONNECTOR, set it in atomic_enable() earlier to +avoid possible NULL pointer dereference in recovery paths like +modeset_retry_fn() with the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag set. + +Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") +Signed-off-by: Jayesh Choudhary +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Reviewed-by: Tomi Valkeinen +Link: https://patch.msgid.link/20251209120332.3559893-2-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 29 ++++++++++--------- + .../drm/bridge/cadence/cdns-mhdp8546-core.h | 1 + + .../drm/bridge/cadence/cdns-mhdp8546-hdcp.c | 18 +++++++++--- + 3 files changed, 30 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 38726ae1bf150..ef2d0ea606f78 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -740,7 +740,7 @@ static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context) + bridge_attached = mhdp->bridge_attached; + spin_unlock(&mhdp->start_lock); + if (bridge_attached) { +- if (mhdp->connector.dev) ++ if (mhdp->connector_ptr) + drm_kms_helper_hotplug_event(mhdp->bridge.dev); + else + drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); +@@ -1636,6 +1636,7 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp) + return ret; + } + ++ mhdp->connector_ptr = conn; + drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs); + + ret = drm_display_info_set_bus_formats(&conn->display_info, +@@ -1915,17 +1916,25 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); + struct cdns_mhdp_bridge_state *mhdp_state; + struct drm_crtc_state *crtc_state; +- struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_bridge_state *new_state; + const struct drm_display_mode *mode; + u32 resp; +- int ret; ++ int ret = 0; + + dev_dbg(mhdp->dev, "bridge enable\n"); + + mutex_lock(&mhdp->link_mutex); + ++ mhdp->connector_ptr = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); ++ if (WARN_ON(!mhdp->connector_ptr)) ++ goto out; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, mhdp->connector_ptr); ++ if (WARN_ON(!conn_state)) ++ goto out; ++ + if (mhdp->plugged && !mhdp->link_up) { + ret = cdns_mhdp_link_up(mhdp); + if (ret < 0) +@@ -1945,15 +1954,6 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, + resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN); + +- connector = drm_atomic_get_new_connector_for_encoder(state, +- bridge->encoder); +- if (WARN_ON(!connector)) +- goto out; +- +- conn_state = drm_atomic_get_new_connector_state(state, connector); +- if (WARN_ON(!conn_state)) +- goto out; +- + if (mhdp->hdcp_supported && + mhdp->hw_state == MHDP_HW_READY && + conn_state->content_protection == +@@ -2030,6 +2030,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, + if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable) + mhdp->info->ops->disable(mhdp); + ++ mhdp->connector_ptr = NULL; + mutex_unlock(&mhdp->link_mutex); + } + +@@ -2296,7 +2297,7 @@ static void cdns_mhdp_modeset_retry_fn(struct work_struct *work) + + mhdp = container_of(work, typeof(*mhdp), modeset_retry_work); + +- conn = &mhdp->connector; ++ conn = mhdp->connector_ptr; + + /* Grab the locks before changing connector property */ + mutex_lock(&conn->dev->mode_config.mutex); +@@ -2373,7 +2374,7 @@ static void cdns_mhdp_hpd_work(struct work_struct *work) + int ret; + + ret = cdns_mhdp_update_link_status(mhdp); +- if (mhdp->connector.dev) { ++ if (mhdp->connector_ptr) { + if (ret < 0) + schedule_work(&mhdp->modeset_retry_work); + else +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +index bad2fc0c73066..a76775c768956 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +@@ -376,6 +376,7 @@ struct cdns_mhdp_device { + struct mutex link_mutex; + + struct drm_connector connector; ++ struct drm_connector *connector_ptr; + struct drm_bridge bridge; + + struct cdns_mhdp_link link; +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +index 42248f179b69d..21a7d2fb266e4 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +@@ -394,7 +394,7 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) + int ret; + + dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", +- mhdp->connector.name, mhdp->connector.base.id); ++ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); + + ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); + +@@ -436,6 +436,10 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) + int ret = 0; + + mutex_lock(&mhdp->hdcp.mutex); ++ ++ if (!mhdp->connector_ptr) ++ goto out; ++ + if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + goto out; + +@@ -445,7 +449,7 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) + + dev_err(mhdp->dev, + "[%s:%d] HDCP link failed, retrying authentication\n", +- mhdp->connector.name, mhdp->connector.base.id); ++ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); + + ret = _cdns_mhdp_hdcp_disable(mhdp); + if (ret) { +@@ -487,13 +491,19 @@ static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) + struct cdns_mhdp_device *mhdp = container_of(hdcp, + struct cdns_mhdp_device, + hdcp); +- struct drm_device *dev = mhdp->connector.dev; ++ struct drm_device *dev = NULL; + struct drm_connector_state *state; + ++ if (mhdp->connector_ptr) ++ dev = mhdp->connector_ptr->dev; ++ ++ if (!dev) ++ return; ++ + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { +- state = mhdp->connector.state; ++ state = mhdp->connector_ptr->state; + state->content_protection = mhdp->hdcp.value; + } + mutex_unlock(&mhdp->hdcp.mutex); +-- +2.53.0 + diff --git a/queue-6.18/drm-color-mgmt-typo-s-r332-rgb332.patch b/queue-6.18/drm-color-mgmt-typo-s-r332-rgb332.patch new file mode 100644 index 0000000000..ccd677c853 --- /dev/null +++ b/queue-6.18/drm-color-mgmt-typo-s-r332-rgb332.patch @@ -0,0 +1,39 @@ +From 7d6c9b19ce7af93f9b47edde0158bd1cb6a6b306 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 09:48:32 +0200 +Subject: drm/color-mgmt: Typo s/R332/RGB332/ + +From: Geert Uytterhoeven + +[ Upstream commit 9d5a2b8f6281f6090002517fb9272ea07038afe8 ] + +Fix a typo of "RGB332" in kerneldoc for the drm_crtc_fill_palette_332() +helper. + +Fixes: 7ff61177b7116825 ("drm/color-mgmt: Prepare for RGB332 palettes") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Javier Martinez Canillas +Reviewed-by: Thomas Zimmermann +Signed-off-by: Thomas Zimmermann +Link: https://patch.msgid.link/c413e45c8f752a532a4ff377f7a8b9eaab4a082a.1776757681.git.geert+renesas@glider.be +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_color_mgmt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c +index 131c1c9ae92fc..302a32d050a6d 100644 +--- a/drivers/gpu/drm/drm_color_mgmt.c ++++ b/drivers/gpu/drm/drm_color_mgmt.c +@@ -831,7 +831,7 @@ static void fill_palette_332(struct drm_crtc *crtc, u16 r, u16 g, u16 b, + } + + /** +- * drm_crtc_fill_palette_332 - Programs a default palette for R332-like formats ++ * drm_crtc_fill_palette_332 - Programs a default palette for RGB332-like formats + * @crtc: The displaying CRTC + * @set_palette: Callback for programming the hardware gamma LUT + * +-- +2.53.0 + diff --git a/queue-6.18/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch b/queue-6.18/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch new file mode 100644 index 0000000000..d4a3a95693 --- /dev/null +++ b/queue-6.18/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch @@ -0,0 +1,44 @@ +From 77f50739fa1d2882cae7a68a4f7e128c8b12af61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:48:38 +0200 +Subject: drm/i915/wm: Verify the correct plane DDB entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit a97c88a176b6b8d116f4d3f508f3bd02bc77b462 ] + +Actually verify the DDB entry for the plane we're looking +at instead of always verifying the cursor DDB. + +Fixes: 7d4561722c3b ("drm/i915: Tweak plane ddb allocation tracking") +Signed-off-by: Ville Syrjälä +Link: https://patch.msgid.link/20260324134843.2364-5-ville.syrjala@linux.intel.com +Reviewed-by: Vinod Govindapillai +(cherry picked from commit f002f7c7439de18117a31ca84dc87a59719c3dd6) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index d74cbb43ae6fb..a5862998bf144 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3935,8 +3935,8 @@ void intel_wm_state_verify(struct intel_atomic_state *state, + } + + /* DDB */ +- hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; +- sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; ++ hw_ddb_entry = &hw->ddb[plane->id]; ++ sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[plane->id]; + + if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { + drm_err(display->drm, +-- +2.53.0 + diff --git a/queue-6.18/drm-imagination-switch-reset_reason-fields-from-enum.patch b/queue-6.18/drm-imagination-switch-reset_reason-fields-from-enum.patch new file mode 100644 index 0000000000..5c5307660a --- /dev/null +++ b/queue-6.18/drm-imagination-switch-reset_reason-fields-from-enum.patch @@ -0,0 +1,63 @@ +From b4be0e050bc2e492a1815c7de27bf5e6041468e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:31:29 +0200 +Subject: drm/imagination: Switch reset_reason fields from enum to u32 + +From: Alexandru Dadu + +[ Upstream commit d2f83a6cd598bf413f1acf34153bd1d71023fbab ] + +Update the reset_reason fwif structure fields from enum to u32 to remove +any ambiguity from the interface (enum is not a fixed size thus is unfit +for the purpose of the data type). + +Fixes: a26f067feac1f ("drm/imagination: Add FWIF headers") +Signed-off-by: Alexandru Dadu +Reviewed-by: Matt Coster +Link: https://patch.msgid.link/20260323-b4-firmware-context-reset-notification-handling-v3-2-1a66049a9a65@imgtec.com +Signed-off-by: Matt Coster +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imagination/pvr_rogue_fwif.h | 8 ++++++-- + drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h | 6 +++++- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h +index 172886be4c820..5d590c4c25663 100644 +--- a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h ++++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h +@@ -1347,8 +1347,12 @@ struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data { + struct rogue_fwif_fwccb_cmd_context_reset_data { + /* Context affected by the reset */ + u32 server_common_context_id; +- /* Reason for reset */ +- enum rogue_context_reset_reason reset_reason; ++ /* ++ * Reason for reset ++ * The valid values for reset_reason are the ones from ++ * enum rogue_context_reset_reason ++ */ ++ u32 reset_reason; + /* Data Master affected by the reset */ + u32 dm; + /* Job ref running at the time of reset */ +diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h +index 6c09c15bf9bd8..f95acd5a1f8e8 100644 +--- a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h ++++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h +@@ -249,7 +249,11 @@ enum rogue_context_reset_reason { + }; + + struct rogue_context_reset_reason_data { +- enum rogue_context_reset_reason reset_reason; ++ /* ++ * The valid values for reset_reason are the ones from ++ * enum rogue_context_reset_reason ++ */ ++ u32 reset_reason; + u32 reset_ext_job_ref; + }; + +-- +2.53.0 + diff --git a/queue-6.18/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch b/queue-6.18/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch new file mode 100644 index 0000000000..ce6119d1b6 --- /dev/null +++ b/queue-6.18/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch @@ -0,0 +1,60 @@ +From b128a686dde07cf373d48e1c5663d3187c6ca380 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:48:46 +0300 +Subject: drm/komeda: fix integer overflow in AFBC framebuffer size check + +From: Alexander Konyukhov + +[ Upstream commit 779ec12c85c9e4547519e3903a371a3b26a289de ] + +The AFBC framebuffer size validation calculates the minimum required +buffer size by adding the AFBC payload size to the framebuffer offset. +This addition is performed without checking for integer overflow. + +If the addition oveflows, the size check may incorrectly succed and +allow userspace to provide an undersized drm_gem_object, potentially +leading to out-of-bounds memory access. + +Add usage of check_add_overflow() to safely compute the minimum +required size and reject the framebuffer if an overflow is detected. +This makes the AFBC size validation more robust against malformed. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 65ad2392dd6d ("drm/komeda: Added AFBC support for komeda driver") +Signed-off-by: Alexander Konyukhov +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://lore.kernel.org/r/20260203134907.1587067-1-Alexander.Konyukhov@kaspersky.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +index 901f938aefe08..e4b7e2a89d044 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +@@ -4,6 +4,8 @@ + * Author: James.Qian.Wang + * + */ ++#include ++ + #include + #include + #include +@@ -92,7 +94,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file, + kfb->afbc_size = kfb->offset_payload + n_blocks * + ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, + AFBC_SUPERBLK_ALIGNMENT); +- min_size = kfb->afbc_size + fb->offsets[0]; ++ if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) { ++ goto check_failed; ++ } + if (min_size > obj->size) { + DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n", + obj->size, min_size); +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch b/queue-6.18/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch new file mode 100644 index 0000000000..c458a20e7d --- /dev/null +++ b/queue-6.18/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch @@ -0,0 +1,70 @@ +From 40f5c819835164cb5e885949d60cac1e97897126 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 16:58:37 -0400 +Subject: drm/msm/a6xx: Fix dumping A650+ debugbus blocks + +From: Connor Abbott + +[ Upstream commit cc83f71c9be0715fe93b963ffa9767d5d84354ed ] + +These should be appended after the existing debugbus blocks, instead of +replacing them. + +Fixes: 1e05bba5e2b8 ("drm/msm/a6xx: Update a6xx gpu coredump") +Signed-off-by: Connor Abbott +Patchwork: https://patchwork.freedesktop.org/patch/714270/ +Message-ID: <20260325-drm-msm-a650-debugbus-v1-1-dfbf358890a7@gmail.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index def021ba19299..918d2e504adec 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -361,7 +361,7 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + sizeof(*a6xx_state->debugbus)); + + if (a6xx_state->debugbus) { +- int i; ++ int i, j; + + for (i = 0; i < ARRAY_SIZE(a6xx_debugbus_blocks); i++) + a6xx_get_debugbus_block(gpu, +@@ -369,8 +369,6 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + &a6xx_debugbus_blocks[i], + &a6xx_state->debugbus[i]); + +- a6xx_state->nr_debugbus = ARRAY_SIZE(a6xx_debugbus_blocks); +- + /* + * GBIF has same debugbus as of other GPU blocks, fall back to + * default path if GPU uses GBIF, also GBIF uses exactly same +@@ -381,17 +379,19 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + &a6xx_gbif_debugbus_block, + &a6xx_state->debugbus[i]); + +- a6xx_state->nr_debugbus += 1; ++ i++; + } + + + if (adreno_is_a650_family(to_adreno_gpu(gpu))) { +- for (i = 0; i < ARRAY_SIZE(a650_debugbus_blocks); i++) ++ for (j = 0; j < ARRAY_SIZE(a650_debugbus_blocks); i++, j++) + a6xx_get_debugbus_block(gpu, + a6xx_state, +- &a650_debugbus_blocks[i], ++ &a650_debugbus_blocks[j], + &a6xx_state->debugbus[i]); + } ++ ++ a6xx_state->nr_debugbus = i; + } + } + +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-a6xx-fix-hlsq-register-dumping.patch b/queue-6.18/drm-msm-a6xx-fix-hlsq-register-dumping.patch new file mode 100644 index 0000000000..b6ffedc7a7 --- /dev/null +++ b/queue-6.18/drm-msm-a6xx-fix-hlsq-register-dumping.patch @@ -0,0 +1,39 @@ +From c905d24dacc8bfca04c9448ac6b44360022c6027 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:40:42 -0700 +Subject: drm/msm/a6xx: Fix HLSQ register dumping + +From: Rob Clark + +[ Upstream commit c289a6db9ba6cb974f0317da142e4f665d589566 ] + +Fix the bitfield offset of HLSQ_READ_SEL state-type bitfield. Otherwise +we are always reading TP state when we wanted SP or HLSQ state. + +Reported-by: Connor Abbott +Suggested-by: Connor Abbott +Fixes: 1707add81551 ("drm/msm/a6xx: Add a6xx gpu state") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714236/ +Message-ID: <20260325184043.1259312-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 9cec333e23e15..def021ba19299 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -1013,7 +1013,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, + u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; + int i, regcount = 0; + +- in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); ++ in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); + + for (i = 0; i < regs->count; i += 2) { + u32 count = RANGE(regs->registers, i); +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch b/queue-6.18/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch new file mode 100644 index 0000000000..8d2b0c2b76 --- /dev/null +++ b/queue-6.18/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch @@ -0,0 +1,72 @@ +From d066af6f112d08adb55f0c75f6f4d7addd2289a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:50 +0530 +Subject: drm/msm/a6xx: Use barriers while updating HFI Q headers + +From: Akhil P Oommen + +[ Upstream commit dc78b35d5ec09d1b0b8a937e6e640d2c5a030915 ] + +To avoid harmful compiler optimizations and IO reordering in the HW, use +barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI +queue index variables. + +Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714653/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-1-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +index 550de6ad68eff..ef1365afd767b 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +@@ -33,7 +33,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + struct a6xx_hfi_queue_header *header = queue->header; + u32 i, hdr, index = header->read_index; + +- if (header->read_index == header->write_index) { ++ if (header->read_index == READ_ONCE(header->write_index)) { + header->rx_request = 1; + return 0; + } +@@ -61,7 +61,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + if (!gmu->legacy) + index = ALIGN(index, 4) % header->size; + +- header->read_index = index; ++ /* Ensure all memory operations are complete before updating the read index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->read_index, index); + return HFI_HEADER_SIZE(hdr); + } + +@@ -73,7 +76,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + + spin_lock(&queue->lock); + +- space = CIRC_SPACE(header->write_index, header->read_index, ++ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), + header->size); + if (space < dwords) { + header->dropped++; +@@ -94,7 +97,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + queue->data[index] = 0xfafafafa; + } + +- header->write_index = index; ++ /* Ensure all memory operations are complete before updating the write index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->write_index, index); + spin_unlock(&queue->lock); + + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-add-missing-module_device_id-definitions.patch b/queue-6.18/drm-msm-add-missing-module_device_id-definitions.patch new file mode 100644 index 0000000000..6ba0f9469b --- /dev/null +++ b/queue-6.18/drm-msm-add-missing-module_device_id-definitions.patch @@ -0,0 +1,96 @@ +From dfb5a4e5ecc11fc2c7080a685d0fc89d4bd9f079 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 19:20:37 +0200 +Subject: drm/msm: add missing MODULE_DEVICE_ID definitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dmitry Baryshkov + +[ Upstream commit b21e85400ce763f2c6ad913e03fea5cadc323c13 ] + +The drm/msm module bundles several drivers, each of them having a +separate OF match table, however only MDSS (subsystem), KMS devices and +GPU have corresponding MODULE_DEVICE_ID tables. + +Add MODULE_DEVICE_ID to the display-related driver and to all other +drivers in this module, simplifying userspace job. + +Fixes: 060530f1ea67 ("drm/msm: use componentised device support") +Reported-by: Loïc Minier +Patchwork: https://patchwork.freedesktop.org/patch/707960/ +Link: https://lore.kernel.org/r/20260228-msm-device-id-v2-1-24b085919444@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dp/dp_display.c | 1 + + drivers/gpu/drm/msm/dsi/dsi.c | 1 + + drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 1 + + drivers/gpu/drm/msm/hdmi/hdmi.c | 1 + + drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 1 + + 5 files changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c +index f247aad553975..c79e624c11758 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.c ++++ b/drivers/gpu/drm/msm/dp/dp_display.c +@@ -201,6 +201,7 @@ static const struct of_device_id msm_dp_dt_match[] = { + { .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 }, + {} + }; ++MODULE_DEVICE_TABLE(of, msm_dp_dt_match); + + static struct msm_dp_display_private *dev_get_dp_display_private(struct device *dev) + { +diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c +index d8bb40ef820e2..3c9f01ed62713 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi.c ++++ b/drivers/gpu/drm/msm/dsi/dsi.c +@@ -198,6 +198,7 @@ static const struct of_device_id dt_match[] = { + { .compatible = "qcom,dsi-ctrl-6g-qcm2290" }, + {} + }; ++MODULE_DEVICE_TABLE(of, dt_match); + + static const struct dev_pm_ops dsi_pm_ops = { + SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL) +diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +index 4ea681130dbaf..5d627df687700 100644 +--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c ++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +@@ -580,6 +580,7 @@ static const struct of_device_id dsi_phy_dt_match[] = { + #endif + {} + }; ++MODULE_DEVICE_TABLE(of, dsi_phy_dt_match); + + /* + * Currently, we only support one SoC for each PHY type. When we have multiple +diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c +index 5afac09c0d334..d5ef5089c9e9c 100644 +--- a/drivers/gpu/drm/msm/hdmi/hdmi.c ++++ b/drivers/gpu/drm/msm/hdmi/hdmi.c +@@ -441,6 +441,7 @@ static const struct of_device_id msm_hdmi_dt_match[] = { + { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8960_config }, + {} + }; ++MODULE_DEVICE_TABLE(of, msm_hdmi_dt_match); + + static struct platform_driver msm_hdmi_driver = { + .probe = msm_hdmi_dev_probe, +diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +index 667573f1db7c6..f726555bb6810 100644 +--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c ++++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +@@ -204,6 +204,7 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = { + .data = &msm_hdmi_phy_8998_cfg }, + {} + }; ++MODULE_DEVICE_TABLE(of, msm_hdmi_phy_dt_match); + + static struct platform_driver msm_hdmi_phy_platform_driver = { + .probe = msm_hdmi_phy_probe, +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-dpu-don-t-try-using-2-lms-if-only-one-dsc-is.patch b/queue-6.18/drm-msm-dpu-don-t-try-using-2-lms-if-only-one-dsc-is.patch new file mode 100644 index 0000000000..4d697709c4 --- /dev/null +++ b/queue-6.18/drm-msm-dpu-don-t-try-using-2-lms-if-only-one-dsc-is.patch @@ -0,0 +1,42 @@ +From 0e9d33304f6d3a94123b298d5deb772f3d345a47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 17:30:05 +0200 +Subject: drm/msm/dpu: don't try using 2 LMs if only one DSC is available + +From: Dmitry Baryshkov + +[ Upstream commit b9699dd862760e642807a2bc226e4d127e35dcb7 ] + +Current topology code will try using 2 LMs with just one DSC, which +breaks cases like SC7280 / Fairphone5. Forbid using 2 LMs split in such +a case. + +Fixes: 1ce69c265a53 ("drm/msm/dpu: move resource allocation to CRTC") +Reported-by: Luca Weiss +Closes: https://lore.kernel.org/r/DH1IKLU0YZYU.2SW4WYO7H3H4R@fairphone.com/ +Tested-by: Luca Weiss # qcm6490-fairphone-fp5 +Patchwork: https://patchwork.freedesktop.org/patch/712386/ +Link: https://lore.kernel.org/r/20260317-fix-3d-dsc-v1-1-88b54f62f659@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +index 2f8156051d9b0..6f5d90b7ba7d4 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +@@ -1354,7 +1354,8 @@ static struct msm_display_topology dpu_crtc_get_topology( + topology.num_lm = 2; + else if (topology.num_dsc == 2) + topology.num_lm = 2; +- else if (dpu_kms->catalog->caps->has_3d_merge) ++ else if (dpu_kms->catalog->caps->has_3d_merge && ++ topology.num_dsc == 0) + topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; + else + topology.num_lm = 1; +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-dpu-drop-intf_0-on-msm8953.patch b/queue-6.18/drm-msm-dpu-drop-intf_0-on-msm8953.patch new file mode 100644 index 0000000000..d6cb002339 --- /dev/null +++ b/queue-6.18/drm-msm-dpu-drop-intf_0-on-msm8953.patch @@ -0,0 +1,43 @@ +From f7809535548cb7d330efa001741f83951e71dde8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 07:35:44 +0200 +Subject: drm/msm/dpu: drop INTF_0 on MSM8953 + +From: Dmitry Baryshkov + +[ Upstream commit 7090420420d5a7d7c88b21d16962f2a230be3ef3 ] + +There is no INTF_0 on MSM8953. Currently catalog lists dummy INTF_NONE +entry for it. Drop it from the catalog. + +Fixes: 7a6109ce1c2c ("drm/msm/dpu: Add support for MSM8953") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/713990/ +Link: https://lore.kernel.org/r/20260325-drop-8953-intf-v1-1-d80e214a1a75@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h +index b44d02b48418f..2162ff917b0f8 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h +@@ -121,13 +121,6 @@ static const struct dpu_dspp_cfg msm8953_dspp[] = { + + static const struct dpu_intf_cfg msm8953_intf[] = { + { +- .name = "intf_0", .id = INTF_0, +- .base = 0x6a000, .len = 0x268, +- .type = INTF_NONE, +- .prog_fetch_lines_worst_case = 14, +- .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), +- .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), +- }, { + .name = "intf_1", .id = INTF_1, + .base = 0x6a800, .len = 0x268, + .type = INTF_DSI, +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch b/queue-6.18/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch new file mode 100644 index 0000000000..9e3dffbe75 --- /dev/null +++ b/queue-6.18/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch @@ -0,0 +1,58 @@ +From 420e95c383251543a86d6ab25817b6819fe3dfbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 14:37:20 +0800 +Subject: drm/msm/dpu: fix mismatch between power and frequency + +From: Yuanjie Yang + +[ Upstream commit bc1dccc518cc5ab5140fba06c27e7188e0ed342b ] + +During DPU runtime suspend, calling dev_pm_opp_set_rate(dev, 0) drops +the MMCX rail to MIN_SVS while the core clock frequency remains at its +original (highest) rate. When runtime resume re-enables the clock, this +may result in a mismatch between the rail voltage and the clock rate. + +For example, in the DPU bind path, the sequence could be: + cpu0: dev_sync_state -> rpmhpd_sync_state + cpu1: dpu_kms_hw_init +timeline 0 ------------------------------------------------> t + +After rpmhpd_sync_state, the voltage performance is no longer guaranteed +to stay at the highest level. During dpu_kms_hw_init, calling +dev_pm_opp_set_rate(dev, 0) drops the voltage, causing the MMCX rail to +fall to MIN_SVS while the core clock is still at its maximum frequency. +When the power is re-enabled, only the clock is enabled, leading to a +situation where the MMCX rail is at MIN_SVS but the core clock is at its +highest rate. In this state, the rail cannot sustain the clock rate, +which may cause instability or system crash. + +Remove the call to dev_pm_opp_set_rate(dev, 0) from dpu_runtime_suspend +to ensure the correct vote is restored when DPU resumes. + +Fixes: b0530eb11913 ("drm/msm/dpu: Use OPP API to set clk/perf state") +Signed-off-by: Yuanjie Yang +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/710077/ +Link: https://lore.kernel.org/r/20260309063720.13572-1-yuanjie.yang@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +index 4e5a8ecd31f75..bc1a016471411 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +@@ -1461,8 +1461,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); + +- /* Drop the performance state vote */ +- dev_pm_opp_set_rate(dev, 0); + clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks); + + for (i = 0; i < dpu_kms->num_paths; i++) +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-dsi-add-the-missing-parameter-description.patch b/queue-6.18/drm-msm-dsi-add-the-missing-parameter-description.patch new file mode 100644 index 0000000000..c9c95a946d --- /dev/null +++ b/queue-6.18/drm-msm-dsi-add-the-missing-parameter-description.patch @@ -0,0 +1,40 @@ +From 4b5c72be9bb66ce99d1021ea6b03b7f4101158d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 18:02:53 +0800 +Subject: drm/msm/dsi: add the missing parameter description + +From: Pengyu Luo + +[ Upstream commit 958adefc4c0fddee3b12269da5dd7cb49bac953f ] + +Add a description for is_bonded_dsi in dsi_adjust_pclk_for_compression +to match the existing kernel-doc comment. + +Fixes: e4eb11b34d6c ("drm/msm/dsi: fix pclk rate calculation for bonded dsi") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202603080314.XeqyRZ7A-lkp@intel.com/ +Signed-off-by: Pengyu Luo +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/710112/ +Link: https://lore.kernel.org/r/20260309100254.877801-1-mitltlatltl@gmail.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index db6da99375a18..6cb634590e7a7 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -569,6 +569,7 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) + * dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case + * @mode: The selected mode for the DSI output + * @dsc: DRM DSC configuration for this DSI output ++ * @is_bonded_dsi: True if two DSI controllers are bonded + * + * Adjust the pclk rate by calculating a new hdisplay proportional to + * the compression ratio such that: +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-dsi-fix-bits_per_pclk.patch b/queue-6.18/drm-msm-dsi-fix-bits_per_pclk.patch new file mode 100644 index 0000000000..d2714e1578 --- /dev/null +++ b/queue-6.18/drm-msm-dsi-fix-bits_per_pclk.patch @@ -0,0 +1,39 @@ +From 613e1a093a1d32acf2b15fb8865b426c19d04bc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:12:48 +0800 +Subject: drm/msm/dsi: fix bits_per_pclk + +From: Pengyu Luo + +[ Upstream commit 2d51cfb77daa30b10bc68c403f8ace35783d2922 ] + +mipi_dsi_pixel_format_to_bpp return dst bpp not src bpp, dst bpp may +not be the uncompressed data size. use src bpc * 3 to get src bpp, +this aligns with pclk rate calculation. + +Fixes: ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when programming dsi registers") +Signed-off-by: Pengyu Luo +Patchwork: https://patchwork.freedesktop.org/patch/709916/ +Link: https://lore.kernel.org/r/20260307111250.105772-1-mitltlatltl@gmail.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 6cb634590e7a7..3efcc3f6c381c 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -1048,7 +1048,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + */ + h_total -= hdisplay; + if (wide_bus_enabled) +- bits_per_pclk = mipi_dsi_pixel_format_to_bpp(msm_host->format); ++ bits_per_pclk = dsc->bits_per_component * 3; + else + bits_per_pclk = 24; + +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch b/queue-6.18/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch new file mode 100644 index 0000000000..0e953164d3 --- /dev/null +++ b/queue-6.18/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch @@ -0,0 +1,61 @@ +From db715cc7f60ec98109aeb2022e90e0cadc6efb6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:12:49 +0800 +Subject: drm/msm/dsi: fix hdisplay calculation for CMD mode panel + +From: Pengyu Luo + +[ Upstream commit 82159db4371f5cef56444ebd0b8f96e2a6d709ff ] + +Commit ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when +programming dsi registers") incorrecly broke hdisplay calculation for +CMD mode by specifying incorrect number of bytes per transfer, fix it. + +Fixes: ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when programming dsi registers") +Signed-off-by: Pengyu Luo +Patchwork: https://patchwork.freedesktop.org/patch/709917/ +Link: https://lore.kernel.org/r/20260307111250.105772-2-mitltlatltl@gmail.com +[DB: fixed commit message] +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 3efcc3f6c381c..1c0841a1c1013 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -1034,8 +1034,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + /* + * DPU sends 3 bytes per pclk cycle to DSI. If widebus is + * enabled, MDP always sends out 48-bit compressed data per +- * pclk and on average, DSI consumes an amount of compressed +- * data equivalent to the uncompressed pixel depth per pclk. ++ * pclk and on average, for video mode, DSI consumes only an ++ * amount of compressed data equivalent to the uncompressed ++ * pixel depth per pclk. + * + * Calculate the number of pclks needed to transmit one line of + * the compressed data. +@@ -1047,10 +1048,14 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + * unused anyway. + */ + h_total -= hdisplay; +- if (wide_bus_enabled) +- bits_per_pclk = dsc->bits_per_component * 3; +- else ++ if (wide_bus_enabled) { ++ if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) ++ bits_per_pclk = dsc->bits_per_component * 3; ++ else ++ bits_per_pclk = 48; ++ } else { + bits_per_pclk = 24; ++ } + + hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc) * 8, bits_per_pclk); + +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch b/queue-6.18/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch new file mode 100644 index 0000000000..9d958dfca0 --- /dev/null +++ b/queue-6.18/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch @@ -0,0 +1,62 @@ +From 19a67b93b4b9bd58ef2f23c86735a12e427015b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:48:27 +0000 +Subject: drm/msm/dsi: rename MSM8998 DSI version from V2_2_0 to V2_0_0 + +From: Alexander Koskovich + +[ Upstream commit 913a709dea0eff9c7b2e9470f8c8594b9a0114ab ] + +The MSM8998 DSI controller is v2.0.0 as stated in commit 7b8c9e203039 +("drm/msm/dsi: Add support for MSM8998 DSI controller"). The value was +always correct just the name was wrong. + +Rename and reorder to maintain version sorting. + +Fixes: 7b8c9e203039 ("drm/msm/dsi: Add support for MSM8998 DSI controller") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Alexander Koskovich +Patchwork: https://patchwork.freedesktop.org/patch/713717/ +Link: https://lore.kernel.org/r/20260324-dsi-rgb101010-support-v5-3-ff6afc904115@pm.me +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_cfg.c | 4 ++-- + drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +index fed8e9b67011c..cdcf0cab7aaa2 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +@@ -306,10 +306,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { + &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, + &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, ++ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, ++ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, + &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, +- {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, +- &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +index 38f303f2ed04c..4d760ffd8b4a8 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +@@ -19,8 +19,8 @@ + #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 + #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 + #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 ++#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 +-#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 + #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 + #define MSM_DSI_6G_VER_MINOR_V2_3_1 0x20030001 +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-fix-vm_bind-unmap-locking.patch b/queue-6.18/drm-msm-fix-vm_bind-unmap-locking.patch new file mode 100644 index 0000000000..81e89595df --- /dev/null +++ b/queue-6.18/drm-msm-fix-vm_bind-unmap-locking.patch @@ -0,0 +1,42 @@ +From 5fd4d9933d19822e0b2041f13bfa59b6152266ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:05:18 -0700 +Subject: drm/msm: Fix VM_BIND UNMAP locking + +From: Rob Clark + +[ Upstream commit 85042c2cd970a6b0e686329387096fe19989ae62 ] + +Wrong argument meant that the objs involved in UNMAP ops were not always +getting locked. + +Since _NO_SHARE objs share a common resv with the VM (which is always +locked) this would only show up with non-_NO_SHARE BOs. + +Reported-by: Victoria Brekenfeld +Fixes: 2e6a8a1fe2b2 ("drm/msm: Add VM_BIND ioctl") +Closes: https://gitlab.freedesktop.org/drm/msm/-/issues/94 +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/713898/ +Message-ID: <20260324220519.1221471-2-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem_vma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c +index 44bcc2b291e47..9016ef978be5e 100644 +--- a/drivers/gpu/drm/msm/msm_gem_vma.c ++++ b/drivers/gpu/drm/msm/msm_gem_vma.c +@@ -1232,7 +1232,7 @@ vm_bind_job_lock_objects(struct msm_vm_bind_job *job, struct drm_exec *exec) + case MSM_VM_BIND_OP_UNMAP: + ret = drm_gpuvm_sm_unmap_exec_lock(job->vm, exec, + op->iova, +- op->obj_offset); ++ op->range); + break; + case MSM_VM_BIND_OP_MAP: + case MSM_VM_BIND_OP_MAP_NULL: { +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-reject-fb-creation-from-_no_share-objs.patch b/queue-6.18/drm-msm-reject-fb-creation-from-_no_share-objs.patch new file mode 100644 index 0000000000..8b8dfb7e76 --- /dev/null +++ b/queue-6.18/drm-msm-reject-fb-creation-from-_no_share-objs.patch @@ -0,0 +1,42 @@ +From 26c182db8e756d8d25f7cc980f55ac075438311c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:59:26 -0700 +Subject: drm/msm: Reject fb creation from _NO_SHARE objs + +From: Rob Clark + +[ Upstream commit cf50ccdb765b3a6f1cd8e75642b0439fea0263a5 ] + +It would be an error to map these into kms->vm. So reject this as early +as possible, when creating an fb. + +Fixes: b58e12a66e47 ("drm/msm: Add _NO_SHARE flag") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714264/ +Message-ID: <20260325185926.1265661-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_fb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c +index 1eff615ff9bff..ce1725990a48d 100644 +--- a/drivers/gpu/drm/msm/msm_fb.c ++++ b/drivers/gpu/drm/msm/msm_fb.c +@@ -219,7 +219,12 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, + + mode_cmd->offsets[i]; + + if (bos[i]->size < min_size) { +- ret = -EINVAL; ++ ret = UERR(EINVAL, dev, "plane %d too small", i); ++ goto fail; ++ } ++ ++ if (to_msm_bo(bos[i])->flags & MSM_BO_NO_SHARE) { ++ ret = UERR(EINVAL, dev, "Cannot map _NO_SHARE to kms vm"); + goto fail; + } + +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-shrinker-fix-can_block-logic.patch b/queue-6.18/drm-msm-shrinker-fix-can_block-logic.patch new file mode 100644 index 0000000000..585f5baefa --- /dev/null +++ b/queue-6.18/drm-msm-shrinker-fix-can_block-logic.patch @@ -0,0 +1,44 @@ +From f02c04e8580c1fb2b0cae99f17d2561d888211e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:41:05 -0700 +Subject: drm/msm/shrinker: Fix can_block() logic + +From: Rob Clark + +[ Upstream commit df0f439e3926817cf577ca6272aad68468ff7624 ] + +The intention here was to allow blocking if DIRECT_RECLAIM or if called +from kswapd and KSWAPD_RECLAIM is set. + +Reported by Claude code review: https://lore.gitlab.freedesktop.org/drm-ai-reviews/review-patch9-20260309151119.290217-10-boris.brezillon@collabora.com/ on a panthor patch which had copied similar logic. + +Reported-by: Boris Brezillon +Fixes: 7860d720a84c ("drm/msm: Fix build break with recent mm tree") +Signed-off-by: Rob Clark +Reviewed-by: Boris Brezillon +Patchwork: https://patchwork.freedesktop.org/patch/714238/ +Message-ID: <20260325184106.1259528-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem_shrinker.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c +index 1039e3c0a47bf..31fa51a44f86e 100644 +--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c ++++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c +@@ -26,9 +26,8 @@ static bool can_swap(void) + + static bool can_block(struct shrink_control *sc) + { +- if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM)) +- return false; +- return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); ++ return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) || ++ (current_is_kswapd() && (sc->gfp_mask & __GFP_KSWAPD_RECLAIM)); + } + + static unsigned long +-- +2.53.0 + diff --git a/queue-6.18/drm-msm-vma-avoid-lock-in-vm_bind-fence-signaling-pa.patch b/queue-6.18/drm-msm-vma-avoid-lock-in-vm_bind-fence-signaling-pa.patch new file mode 100644 index 0000000000..79b4bb5dc3 --- /dev/null +++ b/queue-6.18/drm-msm-vma-avoid-lock-in-vm_bind-fence-signaling-pa.patch @@ -0,0 +1,73 @@ +From 732f660679293ecf564ac6d6b4121730f41cd00e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:44:42 -0700 +Subject: drm/msm/vma: Avoid lock in VM_BIND fence signaling path + +From: Rob Clark + +[ Upstream commit 8a7023b035355ef5bfa096bd323256fa8abbbc6a ] + +Use msm_gem_unpin_active(), similar to what is used in the GEM_SUBMIT +path. This avoids needing to hold the obj lock, and the end result is +the same. (As with GEM_SUBMIT, we know the fence isn't signaled yet.) + +Reported-by: Akhil P Oommen +Fixes: 2e6a8a1fe2b2 ("drm/msm: Add VM_BIND ioctl") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/712230/ +Message-ID: <20260316184442.673558-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem.c | 3 +++ + drivers/gpu/drm/msm/msm_gem_vma.c | 9 ++++++--- + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c +index 9f7fbe577abb1..8636a7f031d24 100644 +--- a/drivers/gpu/drm/msm/msm_gem.c ++++ b/drivers/gpu/drm/msm/msm_gem.c +@@ -533,8 +533,11 @@ void msm_gem_unpin_locked(struct drm_gem_object *obj) + */ + void msm_gem_unpin_active(struct drm_gem_object *obj) + { ++ struct msm_drm_private *priv = obj->dev->dev_private; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + ++ GEM_WARN_ON(!mutex_is_locked(&priv->lru.lock)); ++ + msm_obj->pin_count--; + GEM_WARN_ON(msm_obj->pin_count < 0); + update_lru_active(obj); +diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c +index 89a95977f41ef..44bcc2b291e47 100644 +--- a/drivers/gpu/drm/msm/msm_gem_vma.c ++++ b/drivers/gpu/drm/msm/msm_gem_vma.c +@@ -680,6 +680,7 @@ static struct dma_fence * + msm_vma_job_run(struct drm_sched_job *_job) + { + struct msm_vm_bind_job *job = to_msm_vm_bind_job(_job); ++ struct msm_drm_private *priv = job->vm->drm->dev_private; + struct msm_gem_vm *vm = to_msm_vm(job->vm); + struct drm_gem_object *obj; + int ret = vm->unusable ? -EINVAL : 0; +@@ -722,12 +723,14 @@ msm_vma_job_run(struct drm_sched_job *_job) + if (ret) + msm_gem_vm_unusable(job->vm); + ++ mutex_lock(&priv->lru.lock); ++ + job_foreach_bo (obj, job) { +- msm_gem_lock(obj); +- msm_gem_unpin_locked(obj); +- msm_gem_unlock(obj); ++ msm_gem_unpin_active(obj); + } + ++ mutex_unlock(&priv->lru.lock); ++ + /* VM_BIND ops are synchronous, so no fence to wait on: */ + return NULL; + } +-- +2.53.0 + diff --git a/queue-6.18/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch b/queue-6.18/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch new file mode 100644 index 0000000000..3b1152ddc6 --- /dev/null +++ b/queue-6.18/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch @@ -0,0 +1,38 @@ +From ab89927de309099c29ce1ecf5ff8f210ed396f16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:21:49 +0200 +Subject: drm/panel: sharp-ls043t1le01: make use of prepare_prev_first + +From: Dmitry Baryshkov + +[ Upstream commit c222177d7c7e1b2e0433d9e47ec2da7015345d50 ] + +The DSI link must be powered up to let panel driver to talk to the panel +during prepare() callback execution. Set the prepare_prev_first flag to +guarantee this. + +Fixes: 9e15123eca79 ("drm/msm/dsi: Stop unconditionally powering up DSI hosts at modeset") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Douglas Anderson +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260323-panel-fix-v1-1-9f12b09161e8@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +index 36abfa2e65e96..dd1eaba23ad3c 100644 +--- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c ++++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +@@ -201,6 +201,7 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) + + drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev, + &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); ++ sharp_nt->base.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&sharp_nt->base); + if (ret) +-- +2.53.0 + diff --git a/queue-6.18/drm-panel-simple-correct-g190ean01-prepare-timing.patch b/queue-6.18/drm-panel-simple-correct-g190ean01-prepare-timing.patch new file mode 100644 index 0000000000..2c83b94961 --- /dev/null +++ b/queue-6.18/drm-panel-simple-correct-g190ean01-prepare-timing.patch @@ -0,0 +1,41 @@ +From e4fd990c434424ae58baac7d1671aa772c751cb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 16:25:26 +0200 +Subject: drm/panel: simple: Correct G190EAN01 prepare timing + +From: Sebastian Reichel + +[ Upstream commit f1080f82570b797598c1ba7e9c800ae9e94aafc6 ] + +The prepare timing specified by the G190EAN01 datasheet should be +between 30 and 50 ms. Considering it might take some time for the +LVDS encoder to enable the signal, we should only wait the min. +required time in the panel driver and not the max. allowed time. + +Fixes: 2f7b832fc992 ("drm/panel: simple: Add support for AUO G190EAN01 panel") +Signed-off-by: Sebastian Reichel +Signed-off-by: Ian Ray +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260217142528.68613-1-ian.ray@gehealthcare.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-simple.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 271f933991937..ef1c4b9299ee4 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1295,7 +1295,7 @@ static const struct panel_desc auo_g190ean01 = { + .height = 301, + }, + .delay = { +- .prepare = 50, ++ .prepare = 30, + .enable = 200, + .disable = 110, + .unprepare = 1000, +-- +2.53.0 + diff --git a/queue-6.18/drm-sun4i-backend-fix-error-pointer-dereference.patch b/queue-6.18/drm-sun4i-backend-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..46cd7a452e --- /dev/null +++ b/queue-6.18/drm-sun4i-backend-fix-error-pointer-dereference.patch @@ -0,0 +1,43 @@ +From 8915010c30f804d03f9f59c2be7188e86d23e8d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 19:48:01 -0600 +Subject: drm/sun4i: backend: fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit 06277983eca4a31d3c2114fa33d99a6e82484b11 ] + +The function drm_atomic_get_plane_state() can return an error pointer +and is not checked for it. Add error pointer check. + +Detected by Smatch: +drivers/gpu/drm/sun4i/sun4i_backend.c:496 sun4i_backend_atomic_check() error: +'plane_state' dereferencing possible ERR_PTR() + +Fixes: 96180dde23b79 ("drm/sun4i: backend: Add a custom atomic_check for the frontend") +Signed-off-by: Ethan Tidmore +Reviewed-by: Chen-Yu Tsai +Link: https://patch.msgid.link/20260217014801.60760-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index 2dded3b828df0..0484cc27c97ae 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -490,6 +490,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, + drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); ++ if (IS_ERR(plane_state)) ++ return PTR_ERR(plane_state); ++ + struct sun4i_layer_state *layer_state = + state_to_sun4i_layer_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; +-- +2.53.0 + diff --git a/queue-6.18/drm-sun4i-fix-resource-leaks.patch b/queue-6.18/drm-sun4i-fix-resource-leaks.patch new file mode 100644 index 0000000000..b4e69f546b --- /dev/null +++ b/queue-6.18/drm-sun4i-fix-resource-leaks.patch @@ -0,0 +1,41 @@ +From 935d481dacc9224929c617377982eb37d4828c92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:38:36 -0600 +Subject: drm/sun4i: Fix resource leaks + +From: Ethan Tidmore + +[ Upstream commit 127367ad2e0f4870de60c6d719ae82ecf68d674c ] + +Three clocks are not being released in devm_regmap_init_mmio() error +path. + +Add proper goto and set ret to the error code. + +Fixes: 8270249fbeaf0 ("drm/sun4i: backend: Create regmap after access is possible") +Signed-off-by: Ethan Tidmore +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260226163836.10335-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index 0484cc27c97ae..1518126e9fe32 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -880,7 +880,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, + &sun4i_backend_regmap_config); + if (IS_ERR(backend->engine.regs)) { + dev_err(dev, "Couldn't create the backend regmap\n"); +- return PTR_ERR(backend->engine.regs); ++ ret = PTR_ERR(backend->engine.regs); ++ goto err_disable_ram_clk; + } + + list_add_tail(&backend->engine.list, &drv->engine_list); +-- +2.53.0 + diff --git a/queue-6.18/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch b/queue-6.18/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch new file mode 100644 index 0000000000..bee6986033 --- /dev/null +++ b/queue-6.18/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch @@ -0,0 +1,55 @@ +From 12ea0919878d6f82d92d15ba61b803554dd22f36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:25:13 -0400 +Subject: drm/sysfb: ofdrm: fix PCI device reference leaks + +From: Yuho Choi + +[ Upstream commit 4aa8110000b0d215deef8eed283565dd0c1def88 ] + +display_get_pci_dev_of() gets a referenced PCI device via +pci_get_device(). Drop that reference when pci_enable_device() fails and +release it during the managed teardown path after pci_disable_device(). + +Without that, ofdrm leaks the pci_dev reference on both the error path +and the normal cleanup path. + +Fixes: c8a17756c425 ("drm/ofdrm: Add ofdrm for Open Firmware framebuffers") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Reviewed-by: Thomas Zimmermann +Signed-off-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260420002513.216-1-dbgh9129@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sysfb/ofdrm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c +index 8d8ab39c5f363..f94fddea897a5 100644 +--- a/drivers/gpu/drm/sysfb/ofdrm.c ++++ b/drivers/gpu/drm/sysfb/ofdrm.c +@@ -349,6 +349,7 @@ static void ofdrm_pci_release(void *data) + struct pci_dev *pcidev = data; + + pci_disable_device(pcidev); ++ pci_dev_put(pcidev); + } + + static int ofdrm_device_init_pci(struct ofdrm_device *odev) +@@ -374,6 +375,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev) + if (ret) { + drm_err(dev, "pci_enable_device(%s) failed: %d\n", + dev_name(&pcidev->dev), ret); ++ pci_dev_put(pcidev); + return ret; + } + ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); +-- +2.53.0 + diff --git a/queue-6.18/drm-v3d-handle-error-from-drm_sched_entity_init.patch b/queue-6.18/drm-v3d-handle-error-from-drm_sched_entity_init.patch new file mode 100644 index 0000000000..d502d0253a --- /dev/null +++ b/queue-6.18/drm-v3d-handle-error-from-drm_sched_entity_init.patch @@ -0,0 +1,69 @@ +From 3ae1aeb04b0c9d5d53e2690bb5fbafd03029343e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 08:30:33 -0300 +Subject: drm/v3d: Handle error from drm_sched_entity_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maíra Canal + +[ Upstream commit 8cf1bec37b27846ad3169744c9f1a89a06dcb3fa ] + +drm_sched_entity_init() can fail but its return value is currently being +ignored in v3d_open(). Check the return value and properly unwind +on failure by destroying any already-initialized scheduler entities. + +Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+") +Reviewed-by: Iago Toral Quiroga +Link: https://patch.msgid.link/20260306-v3d-reset-locking-improv-v3-1-49864fe00692@igalia.com +Signed-off-by: Maíra Canal +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/v3d/v3d_drv.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c +index f4da7a94e4016..7bbb2256ce7dc 100644 +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -130,7 +130,7 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + struct v3d_dev *v3d = to_v3d_dev(dev); + struct v3d_file_priv *v3d_priv; + struct drm_gpu_scheduler *sched; +- int i; ++ int i, ret; + + v3d_priv = kzalloc(sizeof(*v3d_priv), GFP_KERNEL); + if (!v3d_priv) +@@ -140,9 +140,11 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + + for (i = 0; i < V3D_MAX_QUEUES; i++) { + sched = &v3d->queue[i].sched; +- drm_sched_entity_init(&v3d_priv->sched_entity[i], +- DRM_SCHED_PRIORITY_NORMAL, &sched, +- 1, NULL); ++ ret = drm_sched_entity_init(&v3d_priv->sched_entity[i], ++ DRM_SCHED_PRIORITY_NORMAL, &sched, ++ 1, NULL); ++ if (ret) ++ goto err_sched; + + memset(&v3d_priv->stats[i], 0, sizeof(v3d_priv->stats[i])); + seqcount_init(&v3d_priv->stats[i].lock); +@@ -152,6 +154,12 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + file->driver_priv = v3d_priv; + + return 0; ++ ++err_sched: ++ for (i--; i >= 0; i--) ++ drm_sched_entity_destroy(&v3d_priv->sched_entity[i]); ++ kfree(v3d_priv); ++ return ret; + } + + static void +-- +2.53.0 + diff --git a/queue-6.18/drm-virtio-allow-importing-prime-buffers-when-3d-is-.patch b/queue-6.18/drm-virtio-allow-importing-prime-buffers-when-3d-is-.patch new file mode 100644 index 0000000000..84de84b036 --- /dev/null +++ b/queue-6.18/drm-virtio-allow-importing-prime-buffers-when-3d-is-.patch @@ -0,0 +1,42 @@ +From 978b3fa137f044c1415264e10819efd5ad95aa32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 12:39:23 -0300 +Subject: drm/virtio: Allow importing prime buffers when 3D is enabled + +From: Val Packett + +[ Upstream commit df4dc947c46bb9f80038f52c6e38cb2d40c10e50 ] + +This functionality was added for using a KMS-only virtgpu with a physical +(or SR-IOV) headless GPU in passthrough, but it should not be restricted +to KMS-only mode. It can be used with cross-domain to pass guest memfds +to the host compositor with zero copies (using udmabuf on both sides). + +Drop the check for the absence of virgl_3d to allow for more use cases. + +Fixes: ca77f27a2665 ("drm/virtio: Import prime buffers from other devices as guest blobs") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Osipenko +Signed-off-by: Dmitry Osipenko +Link: https://patch.msgid.link/20251210154755.1119861-2-val@invisiblethingslab.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/virtio/virtgpu_prime.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c +index ce49282198cbf..2fedd5d3bd62c 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_prime.c ++++ b/drivers/gpu/drm/virtio/virtgpu_prime.c +@@ -312,7 +312,7 @@ struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev, + } + } + +- if (!vgdev->has_resource_blob || vgdev->has_virgl_3d) ++ if (!vgdev->has_resource_blob) + return drm_gem_prime_import(dev, buf); + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); +-- +2.53.0 + diff --git a/queue-6.18/drm-xe-debugfs-correct-printing-of-register-whitelis.patch b/queue-6.18/drm-xe-debugfs-correct-printing-of-register-whitelis.patch new file mode 100644 index 0000000000..539480340d --- /dev/null +++ b/queue-6.18/drm-xe-debugfs-correct-printing-of-register-whitelis.patch @@ -0,0 +1,58 @@ +From aba81b31e09d4324998410c655747e69c21a4ad1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 15:27:44 -0700 +Subject: drm/xe/debugfs: Correct printing of register whitelist ranges + +From: Matt Roper + +[ Upstream commit 03f2499c51dffce611b065b2894406beb9f2ebe0 ] + +The register-save-restore debugfs prints whitelist entries as offset +ranges. E.g., + + REG[0x39319c-0x39319f]: allow read access + +for a single dword-sized register. However the GENMASK value used to +set the lower bits to '1' for the upper bound of the whitelist range +incorrectly included one more bit than it should have, causing the +whitelist ranges to sometimes appear twice as large as they really were. +For example, + + REG[0x6210-0x6217]: allow rw access + +was also intended to be a single dword-sized register whitelist (with a +range 0x6210-0x6213) but was printed incorrectly as a qword-sized range +because one too many bits was flipped on. Similar 'off by one' logic +was applied when printing 4-dword register ranges and 64-dword register +ranges as well. + +Correct the GENMASK logic to print these ranges in debugfs correctly. +No impact outside of correcting the misleading debugfs output. + +Fixes: d855d2246ea6 ("drm/xe: Print whitelist while applying") +Reviewed-by: Stuart Summers +Link: https://patch.msgid.link/20260408-regsr_wl_range-v1-1-e9a28c8b4264@intel.com +Signed-off-by: Matt Roper +(cherry picked from commit 1a2a722ff96749734a5585dfe7f0bea7719caa8b) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c +index 23f6c81d99946..21763dc51150b 100644 +--- a/drivers/gpu/drm/xe/xe_reg_whitelist.c ++++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c +@@ -174,7 +174,7 @@ void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, + } + + range_start = reg & REG_GENMASK(25, range_bit); +- range_end = range_start | REG_GENMASK(range_bit, 0); ++ range_end = range_start | REG_GENMASK(range_bit - 1, 0); + + switch (val & RING_FORCE_TO_NONPRIV_ACCESS_MASK) { + case RING_FORCE_TO_NONPRIV_ACCESS_RW: +-- +2.53.0 + diff --git a/queue-6.18/drm-xe-eustall-fix-drm_dev_put-called-before-stream-.patch b/queue-6.18/drm-xe-eustall-fix-drm_dev_put-called-before-stream-.patch new file mode 100644 index 0000000000..556b184c3d --- /dev/null +++ b/queue-6.18/drm-xe-eustall-fix-drm_dev_put-called-before-stream-.patch @@ -0,0 +1,56 @@ +From dc607ed3087ad330abda96c450242863b19ec0c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:54:28 +0000 +Subject: drm/xe/eustall: Fix drm_dev_put called before stream disable in close + +From: Shuicheng Lin + +[ Upstream commit dc2d9842c67d883d3200ae33b9c3859dd9492408 ] + +In xe_eu_stall_stream_close(), drm_dev_put() is called before the +stream is disabled and its resources are freed. If this drops the +last reference, the device structures could be freed while the +subsequent cleanup code still accesses them, leading to a +use-after-free. + +Fix this by moving drm_dev_put() after all device accesses are +complete. This matches the ordering in xe_oa_release(). + +Fixes: 9a0b11d4cf3b ("drm/xe/eustall: Add support to init, enable and disable EU stall sampling") +Cc: Harish Chegondi +Assisted-by: Claude:claude-opus-4.6 +Signed-off-by: Shuicheng Lin +Reviewed-by: Harish Chegondi +Link: https://patch.msgid.link/20260415225428.3399934-1-shuicheng.lin@intel.com +Signed-off-by: Matt Roper +(cherry picked from commit 35aff528f7297e949e5e19c9cd7fd748cf1cf21c) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_eu_stall.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c +index 33a3764e3e71b..d7392250e0b3a 100644 +--- a/drivers/gpu/drm/xe/xe_eu_stall.c ++++ b/drivers/gpu/drm/xe/xe_eu_stall.c +@@ -845,14 +845,14 @@ static int xe_eu_stall_stream_close(struct inode *inode, struct file *file) + struct xe_eu_stall_data_stream *stream = file->private_data; + struct xe_gt *gt = stream->gt; + +- drm_dev_put(>->tile->xe->drm); +- + mutex_lock(>->eu_stall->stream_lock); + xe_eu_stall_disable_locked(stream); + xe_eu_stall_data_buf_destroy(stream); + xe_eu_stall_stream_free(stream); + mutex_unlock(>->eu_stall->stream_lock); + ++ drm_dev_put(>->tile->xe->drm); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch b/queue-6.18/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch new file mode 100644 index 0000000000..e51d07ee98 --- /dev/null +++ b/queue-6.18/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch @@ -0,0 +1,80 @@ +From 8c0460083d09c0e6b4b8586eb4dcd99ae4bfba96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 02:06:47 +0000 +Subject: drm/xe: Fix error cleanup in xe_exec_queue_create_ioctl() + +From: Shuicheng Lin + +[ Upstream commit f3cc22d4df3ed58439ea7e21daa54c3608e03b78 ] + +Two error handling issues exist in xe_exec_queue_create_ioctl(): + +1. When xe_hw_engine_group_add_exec_queue() fails, the error path jumps + to put_exec_queue which skips xe_exec_queue_kill(). If the VM is in + preempt fence mode, xe_vm_add_compute_exec_queue() has already added + the queue to the VM's compute exec queue list. Skipping the kill + leaves the queue on that list, leading to a dangling pointer after + the queue is freed. + +2. When xa_alloc() fails after xe_hw_engine_group_add_exec_queue() has + succeeded, the error path does not call + xe_hw_engine_group_del_exec_queue() to remove the queue from the hw + engine group list. The queue is then freed while still linked into + the hw engine group, causing a use-after-free. + +Fix both by: +- Changing the xe_hw_engine_group_add_exec_queue() failure path to jump + to kill_exec_queue so that xe_exec_queue_kill() properly removes the + queue from the VM's compute list. +- Adding a del_hw_engine_group label before kill_exec_queue for the + xa_alloc() failure path, which removes the queue from the hw engine + group before proceeding with the rest of the cleanup. + +Fixes: 7970cb36966c ("'drm/xe/hw_engine_group: Register hw engine group's exec queues") +Cc: Francois Dugast +Cc: Matthew Brost +Cc: Niranjana Vishwanathapura +Assisted-by: Claude:claude-opus-4.6 +Reviewed-by: Matthew Brost +Link: https://patch.msgid.link/20260408020647.3397933-1-shuicheng.lin@intel.com +Signed-off-by: Shuicheng Lin +(cherry picked from commit 37c831f401746a45d510b312b0ed7a77b1e06ec8) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_exec_queue.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c +index 231d1fbe5eefa..0df11f054cfba 100644 +--- a/drivers/gpu/drm/xe/xe_exec_queue.c ++++ b/drivers/gpu/drm/xe/xe_exec_queue.c +@@ -789,7 +789,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, + if (q->vm && q->hwe->hw_engine_group) { + err = xe_hw_engine_group_add_exec_queue(q->hwe->hw_engine_group, q); + if (err) +- goto put_exec_queue; ++ goto kill_exec_queue; + } + } + +@@ -798,12 +798,15 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, + /* user id alloc must always be last in ioctl to prevent UAF */ + err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL); + if (err) +- goto kill_exec_queue; ++ goto del_hw_engine_group; + + args->exec_queue_id = id; + + return 0; + ++del_hw_engine_group: ++ if (q->vm && q->hwe && q->hwe->hw_engine_group) ++ xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); + kill_exec_queue: + xe_exec_queue_kill(q); + put_exec_queue: +-- +2.53.0 + diff --git a/queue-6.18/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch b/queue-6.18/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch new file mode 100644 index 0000000000..99fcd78f1d --- /dev/null +++ b/queue-6.18/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch @@ -0,0 +1,45 @@ +From e4cc64981eb37297c42b09f63f3cd9e6a9232fcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 16:33:08 +0000 +Subject: drm/xe/gsc: Fix BO leak on error in query_compatibility_version() + +From: Shuicheng Lin + +[ Upstream commit 3762d6c36549accea7068c4a175483fafdd03657 ] + +When xe_gsc_read_out_header() fails, query_compatibility_version() +returns directly instead of jumping to the out_bo label. This skips +the xe_bo_unpin_map_no_vm() call, leaving the BO pinned and mapped +with no remaining reference to free it. + +Fix by using goto out_bo so the error path properly cleans up the BO, +consistent with the other error handling in the same function. + +Fixes: 0881cbe04077 ("drm/xe/gsc: Query GSC compatibility version") +Cc: Daniele Ceraolo Spurio +Reviewed-by: Daniele Ceraolo Spurio +Link: https://patch.msgid.link/20260417163308.3416147-1-shuicheng.lin@intel.com +Signed-off-by: Shuicheng Lin +(cherry picked from commit 8de86d0a843c32ca9d36864bdb92f0376a830bce) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_gsc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c +index 83d61bf8ec62e..8371ec002e4ed 100644 +--- a/drivers/gpu/drm/xe/xe_gsc.c ++++ b/drivers/gpu/drm/xe/xe_gsc.c +@@ -166,7 +166,7 @@ static int query_compatibility_version(struct xe_gsc *gsc) + &rd_offset); + if (err) { + xe_gt_err(gt, "HuC: invalid GSC reply for version query (err=%d)\n", err); +- return err; ++ goto out_bo; + } + + compat->major = version_query_rd(xe, &bo->vmap, rd_offset, proj_major); +-- +2.53.0 + diff --git a/queue-6.18/dt-bindings-clock-qcom-add-gcc-video-axi-reset-clock.patch b/queue-6.18/dt-bindings-clock-qcom-add-gcc-video-axi-reset-clock.patch new file mode 100644 index 0000000000..79e07e24ef --- /dev/null +++ b/queue-6.18/dt-bindings-clock-qcom-add-gcc-video-axi-reset-clock.patch @@ -0,0 +1,36 @@ +From b6ad314660a7f76afb41b8e0a2dfdd54e0729280 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:26:50 +0530 +Subject: dt-bindings: clock: qcom: Add GCC video axi reset clock for Glymur + +From: Taniya Das + +[ Upstream commit 7c3260327fc874b7c89d7bb230cd569d2e78aff7 ] + +The global clock controller video axi reset clocks are required by +the video SW driver to assert and deassert the clock resets. + +Signed-off-by: Taniya Das +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20260202-glymur_videocc-v2-1-8f7d8b4d8edd@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: 1c8ce43e1e07 ("clk: qcom: gcc-glymur: Add video axi clock resets for glymur") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,glymur-gcc.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/dt-bindings/clock/qcom,glymur-gcc.h b/include/dt-bindings/clock/qcom,glymur-gcc.h +index 10c12b8c51c34..6907653c79927 100644 +--- a/include/dt-bindings/clock/qcom,glymur-gcc.h ++++ b/include/dt-bindings/clock/qcom,glymur-gcc.h +@@ -574,5 +574,6 @@ + #define GCC_VIDEO_AXI0_CLK_ARES 89 + #define GCC_VIDEO_AXI1_CLK_ARES 90 + #define GCC_VIDEO_BCR 91 ++#define GCC_VIDEO_AXI0C_CLK_ARES 92 + + #endif +-- +2.53.0 + diff --git a/queue-6.18/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch b/queue-6.18/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch new file mode 100644 index 0000000000..025c8a1335 --- /dev/null +++ b/queue-6.18/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch @@ -0,0 +1,52 @@ +From 4826d181a7c48312e4bdf53537f2ab85375619a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:25 +0100 +Subject: dt-bindings: clock: qcom,dispcc-sc7180: Define MDSS resets + +From: Konrad Dybcio + +[ Upstream commit fc6e29d42872680dca017f2e5169eefe971f8d89 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: 75616da71291 ("dt-bindings: clock: Introduce QCOM sc7180 display clock bindings") +Signed-off-by: Konrad Dybcio +Reviewed-by: Taniya Das +Acked-by: Krzysztof Kozlowski +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-1-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: b0bc6011c549 ("clk: qcom: dispcc-sc7180: Add missing MDSS resets") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,dispcc-sc7180.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/dt-bindings/clock/qcom,dispcc-sc7180.h b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +index b9b51617a335d..0705103060748 100644 +--- a/include/dt-bindings/clock/qcom,dispcc-sc7180.h ++++ b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +@@ -6,6 +6,7 @@ + #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + ++/* Clocks */ + #define DISP_CC_PLL0 0 + #define DISP_CC_PLL0_OUT_EVEN 1 + #define DISP_CC_MDSS_AHB_CLK 2 +@@ -40,7 +41,11 @@ + #define DISP_CC_MDSS_VSYNC_CLK_SRC 31 + #define DISP_CC_XO_CLK 32 + +-/* DISP_CC GDSCR */ ++/* Resets */ ++#define DISP_CC_MDSS_CORE_BCR 0 ++#define DISP_CC_MDSS_RSCC_BCR 1 ++ ++/* GDSCs */ + #define MDSS_GDSC 0 + + #endif +-- +2.53.0 + diff --git a/queue-6.18/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-6.18/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..736675066e --- /dev/null +++ b/queue-6.18/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,40 @@ +From a9f9e1a98a07cd7098604b5c9ef9fb15ad5d9b0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:06 -0300 +Subject: dt-bindings: clock: qcom,gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 76404ffbf07f28a5ec04748e18fce3dac2e78ef6 ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Signed-off-by: Val Packett +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20260312112321.370983-2-val@packett.cool +Signed-off-by: Bjorn Andersson +Stable-dep-of: 3565741eb985 ("clk: qcom: gcc-sc8180x: Add missing GDSCs") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,gcc-sc8180x.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/dt-bindings/clock/qcom,gcc-sc8180x.h b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +index b9d8438a15ffb..9ed7b794aacc4 100644 +--- a/include/dt-bindings/clock/qcom,gcc-sc8180x.h ++++ b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +@@ -322,5 +322,10 @@ + #define USB30_MP_GDSC 8 + #define USB30_PRIM_GDSC 9 + #define USB30_SEC_GDSC 10 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 11 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 12 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 13 ++#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 14 ++#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 15 + + #endif +-- +2.53.0 + diff --git a/queue-6.18/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch b/queue-6.18/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch new file mode 100644 index 0000000000..6907493607 --- /dev/null +++ b/queue-6.18/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch @@ -0,0 +1,42 @@ +From 7325aab7b9e4c6099f5fb7fbb6b9cfb0e9b6c40d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 11:26:20 +0100 +Subject: dt-bindings: interrupt-controller: arm,gic-v3: Fix EPPI range + +From: Geert Uytterhoeven + +[ Upstream commit 15cfc8984defc17e5e4de1f58db7b993240fcbda ] + +According to the "Arm Generic Interrupt Controller (GIC) Architecture +Specification, v3 and v4", revision H.b[1], there can be only 64 +Extended PPI interrupts. + +[1] https://developer.arm.com/documentation/ihi0069/hb/ + +Fixes: 4b049063e0bcbfd3 ("dt-bindings: interrupt-controller: arm,gic-v3: Describe EPPI range support") +Signed-off-by: Geert Uytterhoeven +Brain-farted-by: Marc Zyngier +Acked-by: Marc Zyngier +Link: https://patch.msgid.link/3e49a63c6b2b6ee48e3737adee87781f9c136c5f.1772792753.git.geert+renesas@glider.be +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/interrupt-controller/arm,gic-v3.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +index f3247a47f9eed..71e6016fe3ca0 100644 +--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml ++++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +@@ -50,7 +50,7 @@ properties: + The 2nd cell contains the interrupt number for the interrupt type. + SPI interrupts are in the range [0-987]. PPI interrupts are in the + range [0-15]. Extended SPI interrupts are in the range [0-1023]. +- Extended PPI interrupts are in the range [0-127]. ++ Extended PPI interrupts are in the range [0-63]. + + The 3rd cell is the flags, encoded as follows: + bits[3:0] trigger type and level flags. +-- +2.53.0 + diff --git a/queue-6.18/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch b/queue-6.18/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch new file mode 100644 index 0000000000..20b4edd5bb --- /dev/null +++ b/queue-6.18/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch @@ -0,0 +1,47 @@ +From 868f0d75819383e55c1cbb93b22d3ad4222947b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 14:34:33 +0200 +Subject: dt-bindings: net: dsa: nxp,sja1105: make spi-cpol optional for + sja1110 + +From: Josua Mayer + +[ Upstream commit 600f01dc4bd0c736b3ffea9f7976136d8bf1b136 ] + +Currently, the binding requires 'spi-cpha' for SJA1105 and 'spi-cpol' +for SJA1110. + +However, the SJA1110 supports both SPI modes 0 and 2. Mode 2 +(cpha=0, cpol=1) is used by the NXP LX2160 Bluebox 3. + +On the SolidRun i.MX8DXL HummingBoard Telematics, mode 0 is stable, +while forcing mode 2 introduces CRC errors especially during bursts. + +Drop the requirement on spi-cpol for SJA1110. + +Fixes: af2eab1a8243 ("dt-bindings: net: nxp,sja1105: document spi-cpol/cpha") +Signed-off-by: Josua Mayer +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260409-imx8dxl-sr-som-v2-1-83ff20629ba0@solid-run.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +index e9dd914b0734c..941f9a25bbea0 100644 +--- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml ++++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +@@ -140,8 +140,6 @@ allOf: + else: + properties: + spi-cpha: false +- required: +- - spi-cpol + + unevaluatedProperties: false + +-- +2.53.0 + diff --git a/queue-6.18/e1000e-unroll-ptp-in-probe-error-handling.patch b/queue-6.18/e1000e-unroll-ptp-in-probe-error-handling.patch new file mode 100644 index 0000000000..a68473da7f --- /dev/null +++ b/queue-6.18/e1000e-unroll-ptp-in-probe-error-handling.patch @@ -0,0 +1,41 @@ +From 4d0181accf98c337299bc608ab5758a420741f68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:36 -0700 +Subject: e1000e: Unroll PTP in probe error handling + +From: Matt Vollrath + +[ Upstream commit aa3f7fe409350857c25d050482a2eef2cfd69b58 ] + +If probe fails after registering the PTP clock and its delayed work, +these resources must be released. + +This was not an issue until a 2016 fix moved the e1000e_ptp_init() call +before the jump to err_register. + +Fixes: aa524b66c5ef ("e1000e: don't modify SYSTIM registers during SIOCSHWTSTAMP ioctl") +Signed-off-by: Matt Vollrath +Tested-by: Avigail Dahan +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-12-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 3e39032696100..833b2e7a86d8c 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -7705,6 +7705,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + err_register: + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000e_release_hw_control(adapter); ++ e1000e_ptp_remove(adapter); + err_eeprom: + if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) + e1000_phy_hw_reset(&adapter->hw); +-- +2.53.0 + diff --git a/queue-6.18/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch b/queue-6.18/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch new file mode 100644 index 0000000000..55c3e586a7 --- /dev/null +++ b/queue-6.18/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch @@ -0,0 +1,52 @@ +From 554fe2e39e7ce061f5cd09180bc357edbf5043a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:46:37 +0200 +Subject: efi/capsule-loader: fix incorrect sizeof in phys array reallocation + +From: Thomas Huth + +[ Upstream commit 48a428215782321b56956974f23593e40ce84b7a ] + +The krealloc() call for cap_info->phys in __efi_capsule_setup_info() uses +sizeof(phys_addr_t *) instead of sizeof(phys_addr_t), which might be +causing an undersized allocation. + +The allocation is also inconsistent with the initial array allocation in +efi_capsule_open() that allocates one entry with sizeof(phys_addr_t), +and the efi_capsule_write() function that stores phys_addr_t values (not +pointers) via page_to_phys(). + +On 64-bit systems where sizeof(phys_addr_t) == sizeof(phys_addr_t *), this +goes unnoticed. On 32-bit systems with PAE where phys_addr_t is 64-bit but +pointers are 32-bit, this allocates half the required space, which might +lead to a heap buffer overflow when storing physical addresses. + +This is similar to the bug fixed in commit fccfa646ef36 ("efi/capsule-loader: +fix incorrect allocation size") which fixed the same issue at the initial +allocation site. + +Fixes: f24c4d478013 ("efi/capsule-loader: Reinstate virtual capsule mapping") +Assisted-by: Claude:claude-sonnet-4-5 +Signed-off-by: Thomas Huth +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + drivers/firmware/efi/capsule-loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c +index 0c17bdd388e12..bbddeb6a09552 100644 +--- a/drivers/firmware/efi/capsule-loader.c ++++ b/drivers/firmware/efi/capsule-loader.c +@@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) + cap_info->pages = temp_page; + + temp_page = krealloc(cap_info->phys, +- pages_needed * sizeof(phys_addr_t *), ++ pages_needed * sizeof(phys_addr_t), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.18/erofs-handle-48-bit-blocks-uniaddr-for-extra-devices.patch b/queue-6.18/erofs-handle-48-bit-blocks-uniaddr-for-extra-devices.patch new file mode 100644 index 0000000000..841850b94b --- /dev/null +++ b/queue-6.18/erofs-handle-48-bit-blocks-uniaddr-for-extra-devices.patch @@ -0,0 +1,83 @@ +From 908f57950e4b0a065f329f60081b60d2939b58e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 14:36:58 +0800 +Subject: erofs: handle 48-bit blocks/uniaddr for extra devices + +From: Zhan Xusheng + +[ Upstream commit 63c2f06198ca7513433f1c92f2c654869d72417e ] + +erofs_init_device() only reads blocks_lo and uniaddr_lo from the +on-disk device slot, ignoring blocks_hi and uniaddr_hi that were +introduced alongside the 48-bit block addressing feature. + +For the primary device (dif0), erofs_read_superblock() already handles +this correctly by combining blocks_lo with blocks_hi when 48-bit +layout is enabled. But the same logic was not applied to extra +devices. + +With a 48-bit EROFS image using extra devices whose uniaddr or blocks +exceed 32-bit range, the truncated values cause erofs_map_dev() to +compute wrong physical addresses, leading to silent data corruption. + +Fix this by reading blocks_hi and uniaddr_hi in erofs_init_device() +when 48-bit layout is enabled, consistent with the primary device +handling. Also fix the erofs_deviceslot on-disk definition where +blocks_hi was incorrectly declared as __le32 instead of __le16. + +Fixes: 61ba89b57905 ("erofs: add 48-bit block addressing on-disk support") +Suggested-by: Gao Xiang +Signed-off-by: Zhan Xusheng +Reviewed-by: Gao Xiang +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/erofs_fs.h | 4 ++-- + fs/erofs/super.c | 8 ++++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h +index 3d5738f80072e..63efadf75b1c0 100644 +--- a/fs/erofs/erofs_fs.h ++++ b/fs/erofs/erofs_fs.h +@@ -44,9 +44,9 @@ struct erofs_deviceslot { + u8 tag[64]; /* digest(sha256), etc. */ + __le32 blocks_lo; /* total blocks count of this device */ + __le32 uniaddr_lo; /* unified starting block of this device */ +- __le32 blocks_hi; /* total blocks count MSB */ ++ __le16 blocks_hi; /* total blocks count MSB */ + __le16 uniaddr_hi; /* unified starting block MSB */ +- u8 reserved[50]; ++ u8 reserved[52]; + }; + #define EROFS_DEVT_SLOT_SIZE sizeof(struct erofs_deviceslot) + +diff --git a/fs/erofs/super.c b/fs/erofs/super.c +index ee37628ec99fb..f5f5d19459ecc 100644 +--- a/fs/erofs/super.c ++++ b/fs/erofs/super.c +@@ -140,6 +140,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb, + struct erofs_fscache *fscache; + struct erofs_deviceslot *dis; + struct file *file; ++ bool _48bit; + + dis = erofs_read_metabuf(buf, sb, *pos, false); + if (IS_ERR(dis)) +@@ -186,8 +187,11 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb, + dif->file = file; + } + +- dif->blocks = le32_to_cpu(dis->blocks_lo); +- dif->uniaddr = le32_to_cpu(dis->uniaddr_lo); ++ _48bit = erofs_sb_has_48bit(sbi); ++ dif->blocks = le32_to_cpu(dis->blocks_lo) | ++ (_48bit ? (u64)le16_to_cpu(dis->blocks_hi) << 32 : 0); ++ dif->uniaddr = le32_to_cpu(dis->uniaddr_lo) | ++ (_48bit ? (u64)le16_to_cpu(dis->uniaddr_hi) << 32 : 0); + sbi->total_blocks += dif->blocks; + *pos += EROFS_DEVT_SLOT_SIZE; + return 0; +-- +2.53.0 + diff --git a/queue-6.18/erofs-include-the-trailing-nul-in-fs_ioc_getfslabel.patch b/queue-6.18/erofs-include-the-trailing-nul-in-fs_ioc_getfslabel.patch new file mode 100644 index 0000000000..d12a21c76c --- /dev/null +++ b/queue-6.18/erofs-include-the-trailing-nul-in-fs_ioc_getfslabel.patch @@ -0,0 +1,45 @@ +From 00cf1a2e7bfe4f7b0f4df72ca8388a17d16f1590 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 14:13:42 +0800 +Subject: erofs: include the trailing NUL in FS_IOC_GETFSLABEL + +From: Zhan Xusheng + +[ Upstream commit d6250d49da4d8f11afc0d8991c84e0307949f92e ] + +erofs_ioctl_get_volume_label() passes strlen(sbi->volume_name) as +the length to copy_to_user(), which copies the label string without +the trailing NUL byte. Since FS_IOC_GETFSLABEL callers expect a +NUL-terminated string in the FSLABEL_MAX-sized buffer and may not +pre-zero the buffer, this can cause userspace to read past the label +into uninitialised stack memory. + +Fix this by using strlen() + 1 to include the NUL terminator, +consistent with how ext4 and xfs implement FS_IOC_GETFSLABEL. + +Signed-off-by: Zhan Xusheng +Fixes: 1cf12c717741 ("erofs: Add support for FS_IOC_GETFSLABEL") +Reviewed-by: Gao Xiang +Reviewed-by: Chunhai Guo +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c +index cb780c095d282..218ab22589228 100644 +--- a/fs/erofs/inode.c ++++ b/fs/erofs/inode.c +@@ -348,7 +348,7 @@ static int erofs_ioctl_get_volume_label(struct inode *inode, void __user *arg) + ret = clear_user(arg, 1); + else + ret = copy_to_user(arg, sbi->volume_name, +- strlen(sbi->volume_name)); ++ strlen(sbi->volume_name) + 1); + return ret ? -EFAULT : 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch b/queue-6.18/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch new file mode 100644 index 0000000000..00c0c10862 --- /dev/null +++ b/queue-6.18/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch @@ -0,0 +1,115 @@ +From be0b4255372b5f91b516ba3605cbbf87802f1b40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 18:11:42 +0800 +Subject: erofs: unify lcn as u64 for 32-bit platforms + +From: Gao Xiang + +[ Upstream commit 2d8c7edcb661812249469f4a5b62e9339118846f ] + +As sashiko reported [1], `lcn` was typed as `unsigned long` (or +`unsigned int` sometimes), which is only 32 bits wide on 32-bit +platforms, which causes `(lcn << lclusterbits)` to be truncated +at 4 GiB. + +In order to consolidate the logic, just use `u64` consistently +around the codebase. + +[1] https://sashiko.dev/r/20260420034612.1899973-1-hsiangkao%40linux.alibaba.com + +Fixes: 152a333a5895 ("staging: erofs: add compacted compression indexes support") +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zmap.c | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c +index 30775502b56da..abf7ddc64c63b 100644 +--- a/fs/erofs/zmap.c ++++ b/fs/erofs/zmap.c +@@ -10,7 +10,7 @@ + struct z_erofs_maprecorder { + struct inode *inode; + struct erofs_map_blocks *map; +- unsigned long lcn; ++ u64 lcn; + /* compression extent information gathered */ + u8 type, headtype; + u16 clusterofs; +@@ -20,8 +20,7 @@ struct z_erofs_maprecorder { + bool partialref, in_mbox; + }; + +-static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, +- unsigned long lcn) ++static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, u64 lcn) + { + struct inode *const inode = m->inode; + struct erofs_inode *const vi = EROFS_I(inode); +@@ -94,7 +93,7 @@ static int get_compacted_la_distance(unsigned int lobits, + } + + static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, +- unsigned long lcn, bool lookahead) ++ u64 lcn, bool lookahead) + { + struct inode *const inode = m->inode; + struct erofs_inode *const vi = EROFS_I(inode); +@@ -234,7 +233,7 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, + } + + static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m, +- unsigned int lcn, bool lookahead) ++ u64 lcn, bool lookahead) + { + struct erofs_inode *vi = EROFS_I(m->inode); + int err; +@@ -249,7 +248,7 @@ static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m, + return err; + + if (m->type >= Z_EROFS_LCLUSTER_TYPE_MAX) { +- erofs_err(m->inode->i_sb, "unknown type %u @ lcn %u of nid %llu", ++ erofs_err(m->inode->i_sb, "unknown type %u @ lcn %llu of nid %llu", + m->type, lcn, EROFS_I(m->inode)->nid); + DBG_BUGON(1); + return -EOPNOTSUPP; +@@ -269,7 +268,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, + const unsigned int lclusterbits = vi->z_lclusterbits; + + while (m->lcn >= lookback_distance) { +- unsigned long lcn = m->lcn - lookback_distance; ++ u64 lcn = m->lcn - lookback_distance; + int err; + + if (!lookback_distance) +@@ -286,7 +285,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, + m->map->m_la = (lcn << lclusterbits) | m->clusterofs; + return 0; + } +- erofs_err(sb, "bogus lookback distance %u @ lcn %lu of nid %llu", ++ erofs_err(sb, "bogus lookback distance %u @ lcn %llu of nid %llu", + lookback_distance, m->lcn, vi->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; +@@ -300,7 +299,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + struct erofs_inode *vi = EROFS_I(inode); + bool bigpcl1 = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1; + bool bigpcl2 = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2; +- unsigned long lcn = m->lcn + 1; ++ u64 lcn = m->lcn + 1; + int err; + + DBG_BUGON(m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD); +@@ -331,7 +330,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD); + + if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD && m->delta[0] != 1) { +- erofs_err(sb, "bogus CBLKCNT @ lcn %lu of nid %llu", lcn, vi->nid); ++ erofs_err(sb, "bogus CBLKCNT @ lcn %llu of nid %llu", lcn, vi->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; + } +-- +2.53.0 + diff --git a/queue-6.18/erofs-verify-metadata-accesses-for-file-backed-mount.patch b/queue-6.18/erofs-verify-metadata-accesses-for-file-backed-mount.patch new file mode 100644 index 0000000000..3ca9770e36 --- /dev/null +++ b/queue-6.18/erofs-verify-metadata-accesses-for-file-backed-mount.patch @@ -0,0 +1,58 @@ +From f4178da1373dec03d01f1044acb0ff49a4c7f6a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 10:29:29 +0800 +Subject: erofs: verify metadata accesses for file-backed mounts + +From: Gao Xiang + +[ Upstream commit 307210c262a29f41d7177851295ea1703bd04175 ] + +For file-backed mounts, metadata is fetched via the page cache of +backing inodes to avoid double caching and redundant copy ops out +of RO uptodate folios, which is used by Android APEXes, ComposeFS, +containerd. However, rw_verify_area() was missing prior to +metadata accesses. + +Similar to vfs_iocb_iter_read(), fix this by: + - Enabling fanotify pre-content hooks on metadata accesses; + - security_file_permission() for security modules. + +Verified that fanotify pre-content hooks now works correctly. + +Fixes: fb176750266a ("erofs: add file-backed mount support") +Acked-by: Amir Goldstein +Reviewed-by: Chunhai Guo +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/data.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/fs/erofs/data.c b/fs/erofs/data.c +index 8ca29962a3dde..58aea2b48580c 100644 +--- a/fs/erofs/data.c ++++ b/fs/erofs/data.c +@@ -29,6 +29,20 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap) + { + pgoff_t index = (buf->off + offset) >> PAGE_SHIFT; + struct folio *folio = NULL; ++ loff_t fpos; ++ int err; ++ ++ /* ++ * Metadata access for file-backed mounts reuses page cache of backing ++ * fs inodes (only folio data will be needed) to prevent double caching. ++ * However, the data access range must be verified here in advance. ++ */ ++ if (buf->file) { ++ fpos = index << PAGE_SHIFT; ++ err = rw_verify_area(READ, buf->file, &fpos, PAGE_SIZE); ++ if (err < 0) ++ return ERR_PTR(err); ++ } + + if (buf->page) { + folio = page_folio(buf->page); +-- +2.53.0 + diff --git a/queue-6.18/eth-fbnic-use-wake-instead-of-start.patch b/queue-6.18/eth-fbnic-use-wake-instead-of-start.patch new file mode 100644 index 0000000000..26ae46ce5c --- /dev/null +++ b/queue-6.18/eth-fbnic-use-wake-instead-of-start.patch @@ -0,0 +1,44 @@ +From da99f826fc4724a3178eaa80c59f795b685295d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:24:15 -0700 +Subject: eth: fbnic: Use wake instead of start + +From: Mohsin Bashir + +[ Upstream commit 12ff2a4aee6c86746623d5aed24389dbf6dffded ] + +fbnic_up() calls netif_tx_start_all_queues(), which only clears +__QUEUE_STATE_DRV_XOFF. If qdisc backlog has accumulated on any TX +queue before the reconfiguration (e.g. ring resize via ethtool -G), +start does not call __netif_schedule() to kick the qdisc, so the +pending backlog is never drained and the queue stalls. + +Switch to netif_tx_wake_all_queues(), which clears DRV_XOFF and also +calls __netif_schedule() on every queue, ensuring any backlog that +built up before the down/up cycle is promptly dequeued. + +Fixes: bc6107771bb4 ("eth: fbnic: Allocate a netdevice and napi vectors with queues") +Signed-off-by: Mohsin Bashir +Link: https://patch.msgid.link/20260408002415.2963915-1-mohsin.bashr@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +index 698b8a85afb31..99b7c0718e80e 100644 +--- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c ++++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +@@ -139,7 +139,7 @@ void fbnic_up(struct fbnic_net *fbn) + + /* Enable Tx/Rx processing */ + fbnic_napi_enable(fbn); +- netif_tx_start_all_queues(fbn->netdev); ++ netif_tx_wake_all_queues(fbn->netdev); + + fbnic_service_task_start(fbn); + } +-- +2.53.0 + diff --git a/queue-6.18/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch b/queue-6.18/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch new file mode 100644 index 0000000000..3c3ef2212f --- /dev/null +++ b/queue-6.18/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch @@ -0,0 +1,69 @@ +From 300e08ae1d210bd9ef59a78500b4a2f5aac11337 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 00:23:18 +0200 +Subject: eventpoll: drop vestigial __ prefix from ep_remove_{file,epi}() + +From: Christian Brauner + +[ Upstream commit 0feaf644f7180c4a91b6b405a881afbfd958f1cf ] + +With __ep_remove() gone, the double-underscore on __ep_remove_file() +and __ep_remove_epi() no longer contrasts with a __-less parent and +just reads as noise. Rename both to ep_remove_file() and +ep_remove_epi(). No functional change. + +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 5d982c2503d68..68607634a60df 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -830,7 +830,7 @@ static void ep_free(struct eventpoll *ep) + * Called with &file->f_lock held, + * returns with it released + */ +-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, ++static void ep_remove_file(struct eventpoll *ep, struct epitem *epi, + struct file *file) + { + struct epitems_head *to_free = NULL; +@@ -854,7 +854,7 @@ static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, + free_ephead(to_free); + } + +-static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi) ++static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi) + { + lockdep_assert_held(&ep->mtx); + +@@ -900,9 +900,9 @@ static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi) + spin_unlock(&file->f_lock); + return; + } +- __ep_remove_file(ep, epi, file); ++ ep_remove_file(ep, epi, file); + +- if (__ep_remove_epi(ep, epi)) ++ if (ep_remove_epi(ep, epi)) + WARN_ON_ONCE(ep_refcount_dec_and_test(ep)); + } + +@@ -1147,8 +1147,8 @@ void eventpoll_release_file(struct file *file) + ep_unregister_pollwait(ep, epi); + + spin_lock(&file->f_lock); +- __ep_remove_file(ep, epi, file); +- dispose = __ep_remove_epi(ep, epi); ++ ep_remove_file(ep, epi, file); ++ dispose = ep_remove_epi(ep, epi); + + mutex_unlock(&ep->mtx); + +-- +2.53.0 + diff --git a/queue-6.18/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch b/queue-6.18/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch new file mode 100644 index 0000000000..ab73c6d22f --- /dev/null +++ b/queue-6.18/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch @@ -0,0 +1,99 @@ +From c68034c33ea5f998c23c5cac752db7f3e06918d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:09 +0200 +Subject: eventpoll: fix ep_remove struct eventpoll / struct file UAF + +From: Christian Brauner + +[ Upstream commit a6dc643c69311677c574a0f17a3f4d66a5f3744b ] + +ep_remove() (via ep_remove_file()) cleared file->f_ep under +file->f_lock but then kept using @file inside the critical section +(is_file_epoll(), hlist_del_rcu() through the head, spin_unlock). +A concurrent __fput() taking the eventpoll_release() fastpath in +that window observed the transient NULL, skipped +eventpoll_release_file() and ran to f_op->release / file_free(). + +For the epoll-watches-epoll case, f_op->release is +ep_eventpoll_release() -> ep_clear_and_put() -> ep_free(), which +kfree()s the watched struct eventpoll. Its embedded ->refs +hlist_head is exactly where epi->fllink.pprev points, so the +subsequent hlist_del_rcu()'s "*pprev = next" scribbles into freed +kmalloc-192 memory. + +In addition, struct file is SLAB_TYPESAFE_BY_RCU, so the slot +backing @file could be recycled by alloc_empty_file() -- +reinitializing f_lock and f_ep -- while ep_remove() is still +nominally inside that lock. The upshot is an attacker-controllable +kmem_cache_free() against the wrong slab cache. + +Pin @file via epi_fget() at the top of ep_remove() and gate the +critical section on the pin succeeding. With the pin held @file +cannot reach refcount zero, which holds __fput() off and +transitively keeps the watched struct eventpoll alive across the +hlist_del_rcu() and the f_lock use, closing both UAFs. + +If the pin fails @file has already reached refcount zero and its +__fput() is in flight. Because we bailed before clearing f_ep, +that path takes the eventpoll_release() slow path into +eventpoll_release_file() and blocks on ep->mtx until the waiter +side's ep_clear_and_put() drops it. The bailed epi's share of +ep->refcount stays intact, so the trailing ep_refcount_dec_and_test() +in ep_clear_and_put() cannot free the eventpoll out from under +eventpoll_release_file(); the orphaned epi is then cleaned up +there. + +A successful pin also proves we are not racing +eventpoll_release_file() on this epi, so drop the now-redundant +re-check of epi->dying under f_lock. The cheap lockless +READ_ONCE(epi->dying) fast-path bailout stays. + +Fixes: 58c9b016e128 ("epoll: use refcount to reduce ep_mutex contention") +Reported-by: Jaeyoung Chung +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-6-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index df6994943e59f..e9e6938f7184a 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -912,22 +912,26 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi) + */ + static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi) + { +- struct file *file = epi->ffd.file; ++ struct file *file __free(fput) = NULL; + + lockdep_assert_irqs_enabled(); + lockdep_assert_held(&ep->mtx); + + ep_unregister_pollwait(ep, epi); + +- /* sync with eventpoll_release_file() */ ++ /* cheap sync with eventpoll_release_file() */ + if (unlikely(READ_ONCE(epi->dying))) + return; + +- spin_lock(&file->f_lock); +- if (epi->dying) { +- spin_unlock(&file->f_lock); ++ /* ++ * If we manage to grab a reference it means we're not in ++ * eventpoll_release_file() and aren't going to be. ++ */ ++ file = epi_fget(epi); ++ if (!file) + return; +- } ++ ++ spin_lock(&file->f_lock); + ep_remove_file(ep, epi, file); + + if (ep_remove_epi(ep, epi)) +-- +2.53.0 + diff --git a/queue-6.18/eventpoll-kill-__ep_remove.patch b/queue-6.18/eventpoll-kill-__ep_remove.patch new file mode 100644 index 0000000000..1dc5cc519b --- /dev/null +++ b/queue-6.18/eventpoll-kill-__ep_remove.patch @@ -0,0 +1,132 @@ +From 0e6ed6b56a9d4de211cc681c8bd24a464faac26c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:06 +0200 +Subject: eventpoll: kill __ep_remove() + +From: Christian Brauner + +[ Upstream commit e9e5cd40d7c403e19f21d0f7b8b8ba3a76b58330 ] + +Remove the boolean conditional in __ep_remove() and restructure the code +so the check for racing with eventpoll_release_file() are only done in +the ep_remove_safe() path where they belong. + +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-3-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 67 ++++++++++++++++++++++---------------------------- + 1 file changed, 30 insertions(+), 37 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 36f3545a71bfa..5d982c2503d68 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -826,49 +826,18 @@ static void ep_free(struct eventpoll *ep) + kfree_rcu(ep, rcu); + } + +-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file); +-static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi); +- +-/* +- * Removes a "struct epitem" from the eventpoll RB tree and deallocates +- * all the associated resources. Must be called with "mtx" held. +- * If the dying flag is set, do the removal only if force is true. +- * This prevents ep_clear_and_put() from dropping all the ep references +- * while running concurrently with eventpoll_release_file(). +- * Returns true if the eventpoll can be disposed. +- */ +-static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) +-{ +- struct file *file = epi->ffd.file; +- +- lockdep_assert_irqs_enabled(); +- +- /* +- * Removes poll wait queue hooks. +- */ +- ep_unregister_pollwait(ep, epi); +- +- /* Remove the current item from the list of epoll hooks */ +- spin_lock(&file->f_lock); +- if (epi->dying && !force) { +- spin_unlock(&file->f_lock); +- return false; +- } +- +- __ep_remove_file(ep, epi, file); +- return __ep_remove_epi(ep, epi); +-} +- + /* + * Called with &file->f_lock held, + * returns with it released + */ +-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file) ++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, ++ struct file *file) + { + struct epitems_head *to_free = NULL; + struct hlist_head *head = file->f_ep; + + lockdep_assert_held(&ep->mtx); ++ lockdep_assert_held(&file->f_lock); + + if (hlist_is_singular_node(&epi->fllink, head)) { + /* See eventpoll_release() for details. */ +@@ -915,7 +884,25 @@ static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi) + */ + static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi) + { +- if (__ep_remove(ep, epi, false)) ++ struct file *file = epi->ffd.file; ++ ++ lockdep_assert_irqs_enabled(); ++ lockdep_assert_held(&ep->mtx); ++ ++ ep_unregister_pollwait(ep, epi); ++ ++ /* sync with eventpoll_release_file() */ ++ if (unlikely(READ_ONCE(epi->dying))) ++ return; ++ ++ spin_lock(&file->f_lock); ++ if (epi->dying) { ++ spin_unlock(&file->f_lock); ++ return; ++ } ++ __ep_remove_file(ep, epi, file); ++ ++ if (__ep_remove_epi(ep, epi)) + WARN_ON_ONCE(ep_refcount_dec_and_test(ep)); + } + +@@ -1147,7 +1134,7 @@ void eventpoll_release_file(struct file *file) + spin_lock(&file->f_lock); + if (file->f_ep && file->f_ep->first) { + epi = hlist_entry(file->f_ep->first, struct epitem, fllink); +- epi->dying = true; ++ WRITE_ONCE(epi->dying, true); + spin_unlock(&file->f_lock); + + /* +@@ -1156,7 +1143,13 @@ void eventpoll_release_file(struct file *file) + */ + ep = epi->ep; + mutex_lock(&ep->mtx); +- dispose = __ep_remove(ep, epi, true); ++ ++ ep_unregister_pollwait(ep, epi); ++ ++ spin_lock(&file->f_lock); ++ __ep_remove_file(ep, epi, file); ++ dispose = __ep_remove_epi(ep, epi); ++ + mutex_unlock(&ep->mtx); + + if (dispose && ep_refcount_dec_and_test(ep)) +-- +2.53.0 + diff --git a/queue-6.18/eventpoll-move-epi_fget-up.patch b/queue-6.18/eventpoll-move-epi_fget-up.patch new file mode 100644 index 0000000000..2303c9efff --- /dev/null +++ b/queue-6.18/eventpoll-move-epi_fget-up.patch @@ -0,0 +1,96 @@ +From 6c8d52d1234874617995177fdaca9441fdd320e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:08 +0200 +Subject: eventpoll: move epi_fget() up + +From: Christian Brauner + +[ Upstream commit 86e87059e6d1fd5115a31949726450ed03c1073b ] + +We'll need it when removing files so move it up. No functional change. + +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-5-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 56 +++++++++++++++++++++++++------------------------- + 1 file changed, 28 insertions(+), 28 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 68607634a60df..df6994943e59f 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -826,6 +826,34 @@ static void ep_free(struct eventpoll *ep) + kfree_rcu(ep, rcu); + } + ++/* ++ * The ffd.file pointer may be in the process of being torn down due to ++ * being closed, but we may not have finished eventpoll_release() yet. ++ * ++ * Normally, even with the atomic_long_inc_not_zero, the file may have ++ * been free'd and then gotten re-allocated to something else (since ++ * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). ++ * ++ * But for epoll, users hold the ep->mtx mutex, and as such any file in ++ * the process of being free'd will block in eventpoll_release_file() ++ * and thus the underlying file allocation will not be free'd, and the ++ * file re-use cannot happen. ++ * ++ * For the same reason we can avoid a rcu_read_lock() around the ++ * operation - 'ffd.file' cannot go away even if the refcount has ++ * reached zero (but we must still not call out to ->poll() functions ++ * etc). ++ */ ++static struct file *epi_fget(const struct epitem *epi) ++{ ++ struct file *file; ++ ++ file = epi->ffd.file; ++ if (!file_ref_get(&file->f_ref)) ++ file = NULL; ++ return file; ++} ++ + /* + * Called with &file->f_lock held, + * returns with it released +@@ -1018,34 +1046,6 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep + return res; + } + +-/* +- * The ffd.file pointer may be in the process of being torn down due to +- * being closed, but we may not have finished eventpoll_release() yet. +- * +- * Normally, even with the atomic_long_inc_not_zero, the file may have +- * been free'd and then gotten re-allocated to something else (since +- * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). +- * +- * But for epoll, users hold the ep->mtx mutex, and as such any file in +- * the process of being free'd will block in eventpoll_release_file() +- * and thus the underlying file allocation will not be free'd, and the +- * file re-use cannot happen. +- * +- * For the same reason we can avoid a rcu_read_lock() around the +- * operation - 'ffd.file' cannot go away even if the refcount has +- * reached zero (but we must still not call out to ->poll() functions +- * etc). +- */ +-static struct file *epi_fget(const struct epitem *epi) +-{ +- struct file *file; +- +- file = epi->ffd.file; +- if (!file_ref_get(&file->f_ref)) +- file = NULL; +- return file; +-} +- + /* + * Differs from ep_eventpoll_poll() in that internal callers already have + * the ep->mtx so we need to start from depth=1, such that mutex_lock_nested() +-- +2.53.0 + diff --git a/queue-6.18/eventpoll-split-__ep_remove.patch b/queue-6.18/eventpoll-split-__ep_remove.patch new file mode 100644 index 0000000000..3e0bbf9d4a --- /dev/null +++ b/queue-6.18/eventpoll-split-__ep_remove.patch @@ -0,0 +1,82 @@ +From 031667f83bf20569809fdcc7bf81fcd8eb16a713 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:05 +0200 +Subject: eventpoll: split __ep_remove() + +From: Christian Brauner + +[ Upstream commit 0f7bdfd413000985de09fc39eb9efa1e091a3ce0 ] + +Split __ep_remove() to delineate file removal from epoll item removal. + +Suggested-by: Linus Torvalds +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-2-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 27 +++++++++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 23602de08fed2..36f3545a71bfa 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -826,6 +826,9 @@ static void ep_free(struct eventpoll *ep) + kfree_rcu(ep, rcu); + } + ++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file); ++static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi); ++ + /* + * Removes a "struct epitem" from the eventpoll RB tree and deallocates + * all the associated resources. Must be called with "mtx" held. +@@ -837,8 +840,6 @@ static void ep_free(struct eventpoll *ep) + static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) + { + struct file *file = epi->ffd.file; +- struct epitems_head *to_free; +- struct hlist_head *head; + + lockdep_assert_irqs_enabled(); + +@@ -854,8 +855,21 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) + return false; + } + +- to_free = NULL; +- head = file->f_ep; ++ __ep_remove_file(ep, epi, file); ++ return __ep_remove_epi(ep, epi); ++} ++ ++/* ++ * Called with &file->f_lock held, ++ * returns with it released ++ */ ++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file) ++{ ++ struct epitems_head *to_free = NULL; ++ struct hlist_head *head = file->f_ep; ++ ++ lockdep_assert_held(&ep->mtx); ++ + if (hlist_is_singular_node(&epi->fllink, head)) { + /* See eventpoll_release() for details. */ + WRITE_ONCE(file->f_ep, NULL); +@@ -869,6 +883,11 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) + hlist_del_rcu(&epi->fllink); + spin_unlock(&file->f_lock); + free_ephead(to_free); ++} ++ ++static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi) ++{ ++ lockdep_assert_held(&ep->mtx); + + rb_erase_cached(&epi->rbn, &ep->rbr); + +-- +2.53.0 + diff --git a/queue-6.18/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch b/queue-6.18/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch new file mode 100644 index 0000000000..592e09bb35 --- /dev/null +++ b/queue-6.18/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch @@ -0,0 +1,37 @@ +From 7de77e5060de9ce76b3c5f00e0c7171fd24a1aae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:04 +0200 +Subject: eventpoll: use hlist_is_singular_node() in __ep_remove() + +From: Christian Brauner + +[ Upstream commit 3d9fd0abc94d8cd430cc7cd7d37ce5e5aae2cd2b ] + +Replace the open-coded "epi is the only entry in file->f_ep" check +with hlist_is_singular_node(). Same semantics, and the helper avoids +the head-cacheline access in the common false case. + +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-1-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index a8e30414d996c..23602de08fed2 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -856,7 +856,7 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) + + to_free = NULL; + head = file->f_ep; +- if (head->first == &epi->fllink && !epi->fllink.next) { ++ if (hlist_is_singular_node(&epi->fllink, head)) { + /* See eventpoll_release() for details. */ + WRITE_ONCE(file->f_ep, NULL); + if (!is_file_epoll(file)) { +-- +2.53.0 + diff --git a/queue-6.18/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch b/queue-6.18/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch new file mode 100644 index 0000000000..b78ecc4863 --- /dev/null +++ b/queue-6.18/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch @@ -0,0 +1,70 @@ +From cb7c51f0412498e80907a8ac819fa95c4f1cda46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:30:35 +0800 +Subject: ext4: fix possible null-ptr-deref in mbt_kunit_exit() + +From: Ye Bin + +[ Upstream commit 22f53f08d9eb837ce69b1a07641d414aac8d045f ] + +There's issue as follows: + # test_new_blocks_simple: failed to initialize: -12 +KASAN: null-ptr-deref in range [0x0000000000000638-0x000000000000063f] +Tainted: [E]=UNSIGNED_MODULE, [N]=TEST +RIP: 0010:mbt_kunit_exit+0x5e/0x3e0 [ext4_test] +Call Trace: + + kunit_try_run_case_cleanup+0xbc/0x100 [kunit] + kunit_generic_run_threadfn_adapter+0x89/0x100 [kunit] + kthread+0x408/0x540 + ret_from_fork+0xa76/0xdf0 + ret_from_fork_asm+0x1a/0x30 + +If mbt_kunit_init() init testcase failed will lead to null-ptr-deref. +So add test if 'sb' is inited success in mbt_kunit_exit(). + +Fixes: 7c9fa399a369 ("ext4: add first unit test for ext4_mb_new_blocks_simple in mballoc") +Signed-off-by: Ye Bin +Reviewed-by: Ritesh Harjani (IBM) +Reviewed-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20260330133035.287842-6-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc-test.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/ext4/mballoc-test.c b/fs/ext4/mballoc-test.c +index 4abb40d4561ce..68aab8e45bc37 100644 +--- a/fs/ext4/mballoc-test.c ++++ b/fs/ext4/mballoc-test.c +@@ -362,7 +362,6 @@ static int mbt_kunit_init(struct kunit *test) + return ret; + } + +- test->priv = sb; + kunit_activate_static_stub(test, + ext4_read_block_bitmap_nowait, + ext4_read_block_bitmap_nowait_stub); +@@ -383,6 +382,8 @@ static int mbt_kunit_init(struct kunit *test) + return -ENOMEM; + } + ++ test->priv = sb; ++ + return 0; + } + +@@ -390,6 +391,9 @@ static void mbt_kunit_exit(struct kunit *test) + { + struct super_block *sb = (struct super_block *)test->priv; + ++ if (!sb) ++ return; ++ + mbt_mb_release(sb); + mbt_ctx_release(sb); + mbt_ext4_free_super_block(sb); +-- +2.53.0 + diff --git a/queue-6.18/f2fs-allow-empty-mount-string-for-opt_usr-grp-projjq.patch b/queue-6.18/f2fs-allow-empty-mount-string-for-opt_usr-grp-projjq.patch new file mode 100644 index 0000000000..d0fea36108 --- /dev/null +++ b/queue-6.18/f2fs-allow-empty-mount-string-for-opt_usr-grp-projjq.patch @@ -0,0 +1,82 @@ +From 33054e744b15d2038ece13b6a13989194994be63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 23:40:59 +0000 +Subject: f2fs: allow empty mount string for Opt_usr|grp|projjquota + +From: Jaegeuk Kim + +[ Upstream commit 2a3db1e02ce08c14af04da70bb99e8a0a31eb9e8 ] + +The fsparam_string_empty() gives an error when mounting without string, since +its type is set to fsparam_flag in VFS. So, let's allow the flag as well. + +This addresses xfstests/f2fs/015 and f2fs/021. + +Fixes: d18535132523 ("f2fs: separate the options parsing and options checking") +Reviewed-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/super.c | 27 +++++++++++++++------------ + 1 file changed, 15 insertions(+), 12 deletions(-) + +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 7e04ae8f32f0e..cb8e8a587ba9e 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -285,9 +285,12 @@ static const struct fs_parameter_spec f2fs_param_specs[] = { + fsparam_flag("usrquota", Opt_usrquota), + fsparam_flag("grpquota", Opt_grpquota), + fsparam_flag("prjquota", Opt_prjquota), +- fsparam_string_empty("usrjquota", Opt_usrjquota), +- fsparam_string_empty("grpjquota", Opt_grpjquota), +- fsparam_string_empty("prjjquota", Opt_prjjquota), ++ fsparam_string("usrjquota", Opt_usrjquota), ++ fsparam_flag("usrjquota", Opt_usrjquota), ++ fsparam_string("grpjquota", Opt_grpjquota), ++ fsparam_flag("grpjquota", Opt_grpjquota), ++ fsparam_string("prjjquota", Opt_prjjquota), ++ fsparam_flag("prjjquota", Opt_prjjquota), + fsparam_flag("nat_bits", Opt_nat_bits), + fsparam_enum("jqfmt", Opt_jqfmt, f2fs_param_jqfmt), + fsparam_enum("alloc_mode", Opt_alloc, f2fs_param_alloc_mode), +@@ -931,26 +934,26 @@ static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param) + ctx_set_opt(ctx, F2FS_MOUNT_PRJQUOTA); + break; + case Opt_usrjquota: +- if (!*param->string) +- ret = f2fs_unnote_qf_name(fc, USRQUOTA); +- else ++ if (param->type == fs_value_is_string && *param->string) + ret = f2fs_note_qf_name(fc, USRQUOTA, param); ++ else ++ ret = f2fs_unnote_qf_name(fc, USRQUOTA); + if (ret) + return ret; + break; + case Opt_grpjquota: +- if (!*param->string) +- ret = f2fs_unnote_qf_name(fc, GRPQUOTA); +- else ++ if (param->type == fs_value_is_string && *param->string) + ret = f2fs_note_qf_name(fc, GRPQUOTA, param); ++ else ++ ret = f2fs_unnote_qf_name(fc, GRPQUOTA); + if (ret) + return ret; + break; + case Opt_prjjquota: +- if (!*param->string) +- ret = f2fs_unnote_qf_name(fc, PRJQUOTA); +- else ++ if (param->type == fs_value_is_string && *param->string) + ret = f2fs_note_qf_name(fc, PRJQUOTA, param); ++ else ++ ret = f2fs_unnote_qf_name(fc, PRJQUOTA); + if (ret) + return ret; + break; +-- +2.53.0 + diff --git a/queue-6.18/f2fs-avoid-reading-already-updated-pages-during-gc.patch b/queue-6.18/f2fs-avoid-reading-already-updated-pages-during-gc.patch new file mode 100644 index 0000000000..b83eac0690 --- /dev/null +++ b/queue-6.18/f2fs-avoid-reading-already-updated-pages-during-gc.patch @@ -0,0 +1,95 @@ +From 17df792a537a2b5af19a7200b6d65c433f714b3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 09:18:10 +0800 +Subject: f2fs: avoid reading already updated pages during GC + +From: Jianan Huang + +[ Upstream commit 570e2ccc7cb35fe720106964e65060602d3d2ac4 ] + +We found the following issue during fuzz testing: + +page: refcount:3 mapcount:0 mapping:00000000b6e89c65 index:0x18b2dc pfn:0x161ba9 +memcg:f8ffff800e269c00 +aops:f2fs_meta_aops ino:2 +flags: 0x52880000000080a9(locked|waiters|uptodate|lru|private|zone=1|kasantag=0x4a) +raw: 52880000000080a9 fffffffec6e17588 fffffffec0ccc088 a7ffff8067063618 +raw: 000000000018b2dc 0000000000000009 00000003ffffffff f8ffff800e269c00 +page dumped because: VM_BUG_ON_FOLIO(folio_test_uptodate(folio)) +page_owner tracks the page as allocated + post_alloc_hook+0x58c/0x5ec + prep_new_page+0x34/0x284 + get_page_from_freelist+0x2dcc/0x2e8c + __alloc_pages_noprof+0x280/0x76c + __folio_alloc_noprof+0x18/0xac + __filemap_get_folio+0x6bc/0xdc4 + pagecache_get_page+0x3c/0x104 + do_garbage_collect+0x5c78/0x77a4 + f2fs_gc+0xd74/0x25f0 + gc_thread_func+0xb28/0x2930 + kthread+0x464/0x5d8 + ret_from_fork+0x10/0x20 +------------[ cut here ]------------ +kernel BUG at mm/filemap.c:1563! + folio_end_read+0x140/0x168 + f2fs_finish_read_bio+0x5c4/0xb80 + f2fs_read_end_io+0x64c/0x708 + bio_endio+0x85c/0x8c0 + blk_update_request+0x690/0x127c + scsi_end_request+0x9c/0xb8c + scsi_io_completion+0xf0/0x250 + scsi_finish_command+0x430/0x45c + scsi_complete+0x178/0x6d4 + blk_mq_complete_request+0xcc/0x104 + scsi_done_internal+0x214/0x454 + scsi_done+0x24/0x34 + +which is similar to the problem reported by syzbot: +https://syzkaller.appspot.com/bug?extid=3686758660f980b402dc + +This case is consistent with the description in commit 9bf1a3f +("f2fs: avoid GC causing encrypted file corrupted"): +Page 1 is moved from blkaddr A to blkaddr B by move_data_block, and after +being written it is marked as uptodate. Then, Page 1 is moved from blkaddr +B to blkaddr C, VM_BUG_ON_FOLIO was triggered in the endio initiated by +ra_data_block. + +There is no need to read Page 1 again from blkaddr B, since it has already +been updated. Therefore, avoid initiating I/O in this case. + +Fixes: 6aa58d8ad20a ("f2fs: readahead encrypted block during GC") +Signed-off-by: Jianan Huang +Signed-off-by: Sheng Yong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 5647e76c6bdb0..3d9f326ae840a 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1222,7 +1222,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index) + .encrypted_page = NULL, + .in_list = 0, + }; +- int err; ++ int err = 0; + + folio = f2fs_grab_cache_folio(mapping, index, true); + if (IS_ERR(folio)) +@@ -1275,6 +1275,9 @@ static int ra_data_block(struct inode *inode, pgoff_t index) + + fio.encrypted_page = &efolio->page; + ++ if (folio_test_uptodate(efolio)) ++ goto put_encrypted_page; ++ + err = f2fs_submit_page_bio(&fio); + if (err) + goto put_encrypted_page; +-- +2.53.0 + diff --git a/queue-6.18/f2fs-expand-scalability-of-f2fs-mount-option.patch b/queue-6.18/f2fs-expand-scalability-of-f2fs-mount-option.patch new file mode 100644 index 0000000000..f5683eed86 --- /dev/null +++ b/queue-6.18/f2fs-expand-scalability-of-f2fs-mount-option.patch @@ -0,0 +1,235 @@ +From 66a36fbc50b8472e989ab62ed0289182edcfff91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Nov 2025 20:45:59 +0800 +Subject: f2fs: expand scalability of f2fs mount option + +From: Chao Yu + +[ Upstream commit 1627a303bca692edc6552630aa2f878c8a726a01 ] + +opt field in structure f2fs_mount_info and opt_mask field in structure +f2fs_fs_context is 32-bits variable, now we're running out of available +bits in them, let's expand them to 64-bits for better scalability. + +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 01968164d947 ("f2fs: fix to preserve previous reserve_{blocks,node} value when remount") +Signed-off-by: Sasha Levin +--- + fs/f2fs/f2fs.h | 85 ++++++++++++++++++++++++++----------------------- + fs/f2fs/super.c | 36 ++++++++++----------- + 2 files changed, 63 insertions(+), 58 deletions(-) + +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index c0747dd2ce511..b3731ba46f571 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -96,47 +96,52 @@ extern const char *f2fs_fault_name[FAULT_MAX]; + /* + * For mount options + */ +-#define F2FS_MOUNT_DISABLE_ROLL_FORWARD 0x00000001 +-#define F2FS_MOUNT_DISCARD 0x00000002 +-#define F2FS_MOUNT_NOHEAP 0x00000004 +-#define F2FS_MOUNT_XATTR_USER 0x00000008 +-#define F2FS_MOUNT_POSIX_ACL 0x00000010 +-#define F2FS_MOUNT_DISABLE_EXT_IDENTIFY 0x00000020 +-#define F2FS_MOUNT_INLINE_XATTR 0x00000040 +-#define F2FS_MOUNT_INLINE_DATA 0x00000080 +-#define F2FS_MOUNT_INLINE_DENTRY 0x00000100 +-#define F2FS_MOUNT_FLUSH_MERGE 0x00000200 +-#define F2FS_MOUNT_NOBARRIER 0x00000400 +-#define F2FS_MOUNT_FASTBOOT 0x00000800 +-#define F2FS_MOUNT_READ_EXTENT_CACHE 0x00001000 +-#define F2FS_MOUNT_DATA_FLUSH 0x00002000 +-#define F2FS_MOUNT_FAULT_INJECTION 0x00004000 +-#define F2FS_MOUNT_USRQUOTA 0x00008000 +-#define F2FS_MOUNT_GRPQUOTA 0x00010000 +-#define F2FS_MOUNT_PRJQUOTA 0x00020000 +-#define F2FS_MOUNT_QUOTA 0x00040000 +-#define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00080000 +-#define F2FS_MOUNT_RESERVE_ROOT 0x00100000 +-#define F2FS_MOUNT_DISABLE_CHECKPOINT 0x00200000 +-#define F2FS_MOUNT_NORECOVERY 0x00400000 +-#define F2FS_MOUNT_ATGC 0x00800000 +-#define F2FS_MOUNT_MERGE_CHECKPOINT 0x01000000 +-#define F2FS_MOUNT_GC_MERGE 0x02000000 +-#define F2FS_MOUNT_COMPRESS_CACHE 0x04000000 +-#define F2FS_MOUNT_AGE_EXTENT_CACHE 0x08000000 +-#define F2FS_MOUNT_NAT_BITS 0x10000000 +-#define F2FS_MOUNT_INLINECRYPT 0x20000000 +-/* +- * Some f2fs environments expect to be able to pass the "lazytime" option +- * string rather than using the MS_LAZYTIME flag, so this must remain. +- */ +-#define F2FS_MOUNT_LAZYTIME 0x40000000 +-#define F2FS_MOUNT_RESERVE_NODE 0x80000000 ++enum f2fs_mount_opt { ++ F2FS_MOUNT_DISABLE_ROLL_FORWARD, ++ F2FS_MOUNT_DISCARD, ++ F2FS_MOUNT_NOHEAP, ++ F2FS_MOUNT_XATTR_USER, ++ F2FS_MOUNT_POSIX_ACL, ++ F2FS_MOUNT_DISABLE_EXT_IDENTIFY, ++ F2FS_MOUNT_INLINE_XATTR, ++ F2FS_MOUNT_INLINE_DATA, ++ F2FS_MOUNT_INLINE_DENTRY, ++ F2FS_MOUNT_FLUSH_MERGE, ++ F2FS_MOUNT_NOBARRIER, ++ F2FS_MOUNT_FASTBOOT, ++ F2FS_MOUNT_READ_EXTENT_CACHE, ++ F2FS_MOUNT_DATA_FLUSH, ++ F2FS_MOUNT_FAULT_INJECTION, ++ F2FS_MOUNT_USRQUOTA, ++ F2FS_MOUNT_GRPQUOTA, ++ F2FS_MOUNT_PRJQUOTA, ++ F2FS_MOUNT_QUOTA, ++ F2FS_MOUNT_INLINE_XATTR_SIZE, ++ F2FS_MOUNT_RESERVE_ROOT, ++ F2FS_MOUNT_DISABLE_CHECKPOINT, ++ F2FS_MOUNT_NORECOVERY, ++ F2FS_MOUNT_ATGC, ++ F2FS_MOUNT_MERGE_CHECKPOINT, ++ F2FS_MOUNT_GC_MERGE, ++ F2FS_MOUNT_COMPRESS_CACHE, ++ F2FS_MOUNT_AGE_EXTENT_CACHE, ++ F2FS_MOUNT_NAT_BITS, ++ F2FS_MOUNT_INLINECRYPT, ++ /* ++ * Some f2fs environments expect to be able to pass the "lazytime" option ++ * string rather than using the MS_LAZYTIME flag, so this must remain. ++ */ ++ F2FS_MOUNT_LAZYTIME, ++ F2FS_MOUNT_RESERVE_NODE, ++}; + + #define F2FS_OPTION(sbi) ((sbi)->mount_opt) +-#define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option) +-#define set_opt(sbi, option) (F2FS_OPTION(sbi).opt |= F2FS_MOUNT_##option) +-#define test_opt(sbi, option) (F2FS_OPTION(sbi).opt & F2FS_MOUNT_##option) ++#define clear_opt(sbi, option) \ ++ (F2FS_OPTION(sbi).opt &= ~BIT(F2FS_MOUNT_##option)) ++#define set_opt(sbi, option) \ ++ (F2FS_OPTION(sbi).opt |= BIT(F2FS_MOUNT_##option)) ++#define test_opt(sbi, option) \ ++ (F2FS_OPTION(sbi).opt & BIT(F2FS_MOUNT_##option)) + + #define ver_after(a, b) (typecheck(unsigned long long, a) && \ + typecheck(unsigned long long, b) && \ +@@ -183,7 +188,7 @@ struct f2fs_rwsem { + }; + + struct f2fs_mount_info { +- unsigned int opt; ++ unsigned long long opt; + block_t root_reserved_blocks; /* root reserved blocks */ + block_t root_reserved_nodes; /* root reserved nodes */ + kuid_t s_resuid; /* reserved blocks for uid */ +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 96325bbc70386..8790d9d4348a1 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -352,7 +352,7 @@ static match_table_t f2fs_checkpoint_tokens = { + + struct f2fs_fs_context { + struct f2fs_mount_info info; +- unsigned int opt_mask; /* Bits changed */ ++ unsigned long long opt_mask; /* Bits changed */ + unsigned int spec_mask; + unsigned short qname_mask; + }; +@@ -360,23 +360,23 @@ struct f2fs_fs_context { + #define F2FS_CTX_INFO(ctx) ((ctx)->info) + + static inline void ctx_set_opt(struct f2fs_fs_context *ctx, +- unsigned int flag) ++ enum f2fs_mount_opt flag) + { +- ctx->info.opt |= flag; +- ctx->opt_mask |= flag; ++ ctx->info.opt |= BIT(flag); ++ ctx->opt_mask |= BIT(flag); + } + + static inline void ctx_clear_opt(struct f2fs_fs_context *ctx, +- unsigned int flag) ++ enum f2fs_mount_opt flag) + { +- ctx->info.opt &= ~flag; +- ctx->opt_mask |= flag; ++ ctx->info.opt &= ~BIT(flag); ++ ctx->opt_mask |= BIT(flag); + } + + static inline bool ctx_test_opt(struct f2fs_fs_context *ctx, +- unsigned int flag) ++ enum f2fs_mount_opt flag) + { +- return ctx->info.opt & flag; ++ return ctx->info.opt & BIT(flag); + } + + void f2fs_printk(struct f2fs_sb_info *sbi, bool limit_rate, +@@ -1371,7 +1371,7 @@ static int f2fs_check_compression(struct fs_context *fc, + ctx_test_opt(ctx, F2FS_MOUNT_COMPRESS_CACHE)) + f2fs_info(sbi, "Image doesn't support compression"); + clear_compression_spec(ctx); +- ctx->opt_mask &= ~F2FS_MOUNT_COMPRESS_CACHE; ++ ctx->opt_mask &= ~BIT(F2FS_MOUNT_COMPRESS_CACHE); + return 0; + } + if (ctx->spec_mask & F2FS_SPEC_compress_extension) { +@@ -1439,42 +1439,42 @@ static int f2fs_check_opt_consistency(struct fs_context *fc, + return -EINVAL; + + if (f2fs_hw_should_discard(sbi) && +- (ctx->opt_mask & F2FS_MOUNT_DISCARD) && ++ (ctx->opt_mask & BIT(F2FS_MOUNT_DISCARD)) && + !ctx_test_opt(ctx, F2FS_MOUNT_DISCARD)) { + f2fs_warn(sbi, "discard is required for zoned block devices"); + return -EINVAL; + } + + if (!f2fs_hw_support_discard(sbi) && +- (ctx->opt_mask & F2FS_MOUNT_DISCARD) && ++ (ctx->opt_mask & BIT(F2FS_MOUNT_DISCARD)) && + ctx_test_opt(ctx, F2FS_MOUNT_DISCARD)) { + f2fs_warn(sbi, "device does not support discard"); + ctx_clear_opt(ctx, F2FS_MOUNT_DISCARD); +- ctx->opt_mask &= ~F2FS_MOUNT_DISCARD; ++ ctx->opt_mask &= ~BIT(F2FS_MOUNT_DISCARD); + } + + if (f2fs_sb_has_device_alias(sbi) && +- (ctx->opt_mask & F2FS_MOUNT_READ_EXTENT_CACHE) && ++ (ctx->opt_mask & BIT(F2FS_MOUNT_READ_EXTENT_CACHE)) && + !ctx_test_opt(ctx, F2FS_MOUNT_READ_EXTENT_CACHE)) { + f2fs_err(sbi, "device aliasing requires extent cache"); + return -EINVAL; + } + + if (test_opt(sbi, RESERVE_ROOT) && +- (ctx->opt_mask & F2FS_MOUNT_RESERVE_ROOT) && ++ (ctx->opt_mask & BIT(F2FS_MOUNT_RESERVE_ROOT)) && + ctx_test_opt(ctx, F2FS_MOUNT_RESERVE_ROOT)) { + f2fs_info(sbi, "Preserve previous reserve_root=%u", + F2FS_OPTION(sbi).root_reserved_blocks); + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_ROOT); +- ctx->opt_mask &= ~F2FS_MOUNT_RESERVE_ROOT; ++ ctx->opt_mask &= ~BIT(F2FS_MOUNT_RESERVE_ROOT); + } + if (test_opt(sbi, RESERVE_NODE) && +- (ctx->opt_mask & F2FS_MOUNT_RESERVE_NODE) && ++ (ctx->opt_mask & BIT(F2FS_MOUNT_RESERVE_NODE)) && + ctx_test_opt(ctx, F2FS_MOUNT_RESERVE_NODE)) { + f2fs_info(sbi, "Preserve previous reserve_node=%u", + F2FS_OPTION(sbi).root_reserved_nodes); + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_NODE); +- ctx->opt_mask &= ~F2FS_MOUNT_RESERVE_NODE; ++ ctx->opt_mask &= ~BIT(F2FS_MOUNT_RESERVE_NODE); + } + + err = f2fs_check_test_dummy_encryption(fc, sb); +-- +2.53.0 + diff --git a/queue-6.18/f2fs-fix-to-preserve-previous-reserve_-blocks-node-v.patch b/queue-6.18/f2fs-fix-to-preserve-previous-reserve_-blocks-node-v.patch new file mode 100644 index 0000000000..4028971a09 --- /dev/null +++ b/queue-6.18/f2fs-fix-to-preserve-previous-reserve_-blocks-node-v.patch @@ -0,0 +1,77 @@ +From e90f0919a64db68c8e4234681b5721f7b4a87000 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:22:46 +0800 +Subject: f2fs: fix to preserve previous reserve_{blocks,node} value when + remount + +From: Zhiguo Niu + +[ Upstream commit 01968164d94762db2f703647c5acfa28613844f1 ] + +The following steps will change previous value of reserve_{blocks,node}, +this dones not match the original intention. + +1.mount -t f2fs -o reserve_root=8192 imgfile test_mount/ +F2FS-fs (loop56): Mounted with checkpoint version = 1b69f8c7 +mount info: +/dev/block/loop56 on /data/test_mount type f2fs (xxx,reserve_root=8192,reserve_node=0,resuid=0,resgid=0,xxx) + +2.mount -t f2fs -o remount,reserve_root=4096 /data/test_mount +F2FS-fs (loop56): Preserve previous reserve_root=8192 +check mount info: reserve_root change to 4096 +/dev/block/loop56 on /data/test_mount type f2fs (xxx,reserve_root=4096,reserve_node=0,resuid=0,resgid=0,xxx) + +Prior to commit d18535132523 ("f2fs: separate the options parsing and options checking"), +the value of reserve_{blocks,node} was only set during the first mount, along with +the corresponding mount option F2FS_MOUNT_RESERVE_{ROOT,NODE} . If the mount option +F2FS_MOUNT_RESERVE_{ROOT,NODE} was found to have been set during the mount/remount, +the previously value of reserve_{blocks,node} would also be preserved, as shown in +the code below. + if (test_opt(sbi, RESERVE_ROOT)) { + f2fs_info(sbi, "Preserve previous reserve_root=%u", + F2FS_OPTION(sbi).root_reserved_blocks); + } else { + F2FS_OPTION(sbi).root_reserved_blocks = arg; + set_opt(sbi, RESERVE_ROOT); + } +But commit d18535132523 ("f2fs: separate the options parsing and options checking") +only preserved the previous mount option; it did not preserve the previous value of +reserve_{blocks,node}. Since value of reserve_{blocks,node} value is assigned +or not depends on ctx->spec_mask, ctx->spec_mask should be alos handled in +f2fs_check_opt_consistency. + +This patch will clear the corresponding ctx->spec_mask bits in f2fs_check_opt_consistency +to preserve the previously values of reserve_{blocks,node} if it already have a value. + +Fixes: d18535132523 ("f2fs: separate the options parsing and options checking") +Signed-off-by: Zhiguo Niu +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/super.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 8790d9d4348a1..7e04ae8f32f0e 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1467,6 +1467,7 @@ static int f2fs_check_opt_consistency(struct fs_context *fc, + F2FS_OPTION(sbi).root_reserved_blocks); + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_ROOT); + ctx->opt_mask &= ~BIT(F2FS_MOUNT_RESERVE_ROOT); ++ ctx->spec_mask &= ~F2FS_SPEC_reserve_root; + } + if (test_opt(sbi, RESERVE_NODE) && + (ctx->opt_mask & BIT(F2FS_MOUNT_RESERVE_NODE)) && +@@ -1475,6 +1476,7 @@ static int f2fs_check_opt_consistency(struct fs_context *fc, + F2FS_OPTION(sbi).root_reserved_nodes); + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_NODE); + ctx->opt_mask &= ~BIT(F2FS_MOUNT_RESERVE_NODE); ++ ctx->spec_mask &= ~F2FS_SPEC_reserve_node; + } + + err = f2fs_check_test_dummy_encryption(fc, sb); +-- +2.53.0 + diff --git a/queue-6.18/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch b/queue-6.18/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch new file mode 100644 index 0000000000..e762fb9bd4 --- /dev/null +++ b/queue-6.18/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch @@ -0,0 +1,57 @@ +From 222176dca618674286b0576941d8c63a3a582c42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:05:39 +0800 +Subject: f2fs: protect extension_list reading with sb_lock in f2fs_sbi_show() + +From: Yongpeng Yang + +[ Upstream commit 5909bedbed38c558bee7cb6758ceedf9bc3a9194 ] + +In f2fs_sbi_show(), the extension_list, extension_count and +hot_ext_count are read without holding sbi->sb_lock. If a concurrent +sysfs store modifies the extension list via f2fs_update_extension_list(), +the show path may read inconsistent count and array contents, potentially +leading to out-of-bounds access or displaying stale data. + +Fix this by holding sb_lock around the entire extension list read +and format operation. + +Fixes: b6a06cbbb5f7 ("f2fs: support hot file extension") +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/sysfs.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index a75c3ef300bd2..1f5982a0a6326 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -377,10 +377,12 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + if (!strcmp(a->attr.name, "extension_list")) { + __u8 (*extlist)[F2FS_EXTENSION_LEN] = + sbi->raw_super->extension_list; +- int cold_count = le32_to_cpu(sbi->raw_super->extension_count); +- int hot_count = sbi->raw_super->hot_ext_count; ++ int cold_count, hot_count; + int len = 0, i; + ++ f2fs_down_read(&sbi->sb_lock); ++ cold_count = le32_to_cpu(sbi->raw_super->extension_count); ++ hot_count = sbi->raw_super->hot_ext_count; + len += sysfs_emit_at(buf, len, "cold file extension:\n"); + for (i = 0; i < cold_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); +@@ -388,6 +390,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + len += sysfs_emit_at(buf, len, "hot file extension:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); ++ f2fs_up_read(&sbi->sb_lock); + + return len; + } +-- +2.53.0 + diff --git a/queue-6.18/f2fs-use-f2fs_filemap_get_folio-instead-of-f2fs_page.patch b/queue-6.18/f2fs-use-f2fs_filemap_get_folio-instead-of-f2fs_page.patch new file mode 100644 index 0000000000..c282b90eb4 --- /dev/null +++ b/queue-6.18/f2fs-use-f2fs_filemap_get_folio-instead-of-f2fs_page.patch @@ -0,0 +1,110 @@ +From 2627010f0bba5fea00e2a4d8001c546c924482c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Oct 2025 14:27:03 +0800 +Subject: f2fs: use f2fs_filemap_get_folio() instead of + f2fs_pagecache_get_page() + +From: Chao Yu + +[ Upstream commit e0b89d00ea9f846da42fc92f200c96254d0e2fef ] + +Let's use f2fs_filemap_get_folio() instead of f2fs_pagecache_get_page() in +ra_data_block() and move_data_block(), then remove f2fs_pagecache_get_page() +since it has no user. + +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 570e2ccc7cb3 ("f2fs: avoid reading already updated pages during GC") +Signed-off-by: Sasha Levin +--- + fs/f2fs/f2fs.h | 10 ---------- + fs/f2fs/gc.c | 23 +++++++++++++---------- + 2 files changed, 13 insertions(+), 20 deletions(-) + +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index 939bd1fb57070..c0747dd2ce511 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -2996,16 +2996,6 @@ static inline struct folio *f2fs_filemap_get_folio( + return __filemap_get_folio(mapping, index, fgp_flags, gfp_mask); + } + +-static inline struct page *f2fs_pagecache_get_page( +- struct address_space *mapping, pgoff_t index, +- fgf_t fgp_flags, gfp_t gfp_mask) +-{ +- if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_GET)) +- return NULL; +- +- return pagecache_get_page(mapping, index, fgp_flags, gfp_mask); +-} +- + static inline void f2fs_folio_put(struct folio *folio, bool unlock) + { + if (IS_ERR_OR_NULL(folio)) +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index 9d2f4f22fd396..5647e76c6bdb0 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1211,7 +1211,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index) + struct address_space *mapping = f2fs_is_cow_file(inode) ? + F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping; + struct dnode_of_data dn; +- struct folio *folio; ++ struct folio *folio, *efolio; + struct f2fs_io_info fio = { + .sbi = sbi, + .ino = inode->i_ino, +@@ -1266,14 +1266,15 @@ static int ra_data_block(struct inode *inode, pgoff_t index) + + f2fs_wait_on_block_writeback(inode, dn.data_blkaddr); + +- fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(sbi), +- dn.data_blkaddr, ++ efolio = f2fs_filemap_get_folio(META_MAPPING(sbi), dn.data_blkaddr, + FGP_LOCK | FGP_CREAT, GFP_NOFS); +- if (!fio.encrypted_page) { +- err = -ENOMEM; ++ if (IS_ERR(efolio)) { ++ err = PTR_ERR(efolio); + goto put_folio; + } + ++ fio.encrypted_page = &efolio->page; ++ + err = f2fs_submit_page_bio(&fio); + if (err) + goto put_encrypted_page; +@@ -1313,7 +1314,7 @@ static int move_data_block(struct inode *inode, block_t bidx, + struct dnode_of_data dn; + struct f2fs_summary sum; + struct node_info ni; +- struct folio *folio, *mfolio; ++ struct folio *folio, *mfolio, *efolio; + block_t newaddr; + int err = 0; + bool lfs_mode = f2fs_lfs_mode(fio.sbi); +@@ -1407,14 +1408,16 @@ static int move_data_block(struct inode *inode, block_t bidx, + goto up_out; + } + +- fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(fio.sbi), +- newaddr, FGP_LOCK | FGP_CREAT, GFP_NOFS); +- if (!fio.encrypted_page) { +- err = -ENOMEM; ++ efolio = f2fs_filemap_get_folio(META_MAPPING(fio.sbi), newaddr, ++ FGP_LOCK | FGP_CREAT, GFP_NOFS); ++ if (IS_ERR(efolio)) { ++ err = PTR_ERR(efolio); + f2fs_folio_put(mfolio, true); + goto recover_block; + } + ++ fio.encrypted_page = &efolio->page; ++ + /* write target block */ + f2fs_wait_on_page_writeback(fio.encrypted_page, DATA, true, true); + memcpy(page_address(fio.encrypted_page), +-- +2.53.0 + diff --git a/queue-6.18/fanotify-avoid-silence-premature-lsm-capability-chec.patch b/queue-6.18/fanotify-avoid-silence-premature-lsm-capability-chec.patch new file mode 100644 index 0000000000..9ab09b1b61 --- /dev/null +++ b/queue-6.18/fanotify-avoid-silence-premature-lsm-capability-chec.patch @@ -0,0 +1,76 @@ +From 7e507c4916530bf8dd8e5acc42c51816f0d385f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 16:06:24 +0100 +Subject: fanotify: avoid/silence premature LSM capability checks + +From: Ondrej Mosnacek + +[ Upstream commit 0d5ee3373426395478c355f3e93ba4b1118a04e9 ] + +Make sure calling capable()/ns_capable() actually leads to access denied +when false is returned, because these functions emit an audit record +when a Linux Security Module denies the capability, which makes it +difficult to avoid allowing/silencing unnecessary permissions in +security policies (namely with SELinux). + +Where the return value just used to set a flag, use the non-auditing +ns_capable_noaudit() instead. + +Fixes: 7cea2a3c505e ("fanotify: support limited functionality for unprivileged users") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Reviewed-by: Amir Goldstein +Link: https://patch.msgid.link/20260216150625.793013-2-omosnace@redhat.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 1dadda82cae51..1c05c11e3cb25 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1611,17 +1611,18 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + pr_debug("%s: flags=%x event_f_flags=%x\n", + __func__, flags, event_f_flags); + +- if (!capable(CAP_SYS_ADMIN)) { +- /* +- * An unprivileged user can setup an fanotify group with +- * limited functionality - an unprivileged group is limited to +- * notification events with file handles or mount ids and it +- * cannot use unlimited queue/marks. +- */ +- if ((flags & FANOTIFY_ADMIN_INIT_FLAGS) || +- !(flags & (FANOTIFY_FID_BITS | FAN_REPORT_MNT))) +- return -EPERM; ++ /* ++ * An unprivileged user can setup an fanotify group with limited ++ * functionality - an unprivileged group is limited to notification ++ * events with file handles or mount ids and it cannot use unlimited ++ * queue/marks. ++ */ ++ if (((flags & FANOTIFY_ADMIN_INIT_FLAGS) || ++ !(flags & (FANOTIFY_FID_BITS | FAN_REPORT_MNT))) && ++ !capable(CAP_SYS_ADMIN)) ++ return -EPERM; + ++ if (!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) { + /* + * Setting the internal flag FANOTIFY_UNPRIV on the group + * prevents setting mount/filesystem marks on this group and +@@ -2006,8 +2007,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + * A user is allowed to setup sb/mount/mntns marks only if it is + * capable in the user ns where the group was created. + */ +- if (!ns_capable(group->user_ns, CAP_SYS_ADMIN) && +- mark_type != FAN_MARK_INODE) ++ if (mark_type != FAN_MARK_INODE && ++ !ns_capable(group->user_ns, CAP_SYS_ADMIN)) + return -EPERM; + + /* +-- +2.53.0 + diff --git a/queue-6.18/fanotify-call-fanotify_events_supported-before-path_.patch b/queue-6.18/fanotify-call-fanotify_events_supported-before-path_.patch new file mode 100644 index 0000000000..51963e63c1 --- /dev/null +++ b/queue-6.18/fanotify-call-fanotify_events_supported-before-path_.patch @@ -0,0 +1,79 @@ +From ea27e25871b02682cbe6172cca51d961ab28eb8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 16:06:25 +0100 +Subject: fanotify: call fanotify_events_supported() before path_permission() + and security_path_notify() + +From: Ondrej Mosnacek + +[ Upstream commit 66052a768d4726a31e939b5ac902f2b0b452c8d5 ] + +The latter trigger LSM (e.g. SELinux) checks, which will log a denial +when permission is denied, so it's better to do them after validity +checks to avoid logging a denial when the operation would fail anyway. + +Fixes: 0b3b094ac9a7 ("fanotify: Disallow permission events for proc filesystem") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Amir Goldstein +Reviewed-by: Paul Moore +Link: https://patch.msgid.link/20260216150625.793013-3-omosnace@redhat.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 1c05c11e3cb25..5c30f4d8c7c16 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1210,6 +1210,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, + + *path = fd_file(f)->f_path; + path_get(path); ++ ret = 0; + } else { + unsigned int lookup_flags = 0; + +@@ -1219,22 +1220,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, + lookup_flags |= LOOKUP_DIRECTORY; + + ret = user_path_at(dfd, filename, lookup_flags, path); +- if (ret) +- goto out; + } +- +- /* you can only watch an inode if you have read permissions on it */ +- ret = path_permission(path, MAY_READ); +- if (ret) { +- path_put(path); +- goto out; +- } +- +- ret = security_path_notify(path, mask, obj_type); +- if (ret) +- path_put(path); +- +-out: + return ret; + } + +@@ -2074,6 +2060,15 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + goto path_put_and_out; + } + ++ /* you can only watch an inode if you have read permissions on it */ ++ ret = path_permission(&path, MAY_READ); ++ if (ret) ++ goto path_put_and_out; ++ ++ ret = security_path_notify(&path, mask, obj_type); ++ if (ret) ++ goto path_put_and_out; ++ + if (fid_mode) { + ret = fanotify_test_fsid(path.dentry, flags, &__fsid); + if (ret) +-- +2.53.0 + diff --git a/queue-6.18/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch b/queue-6.18/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch new file mode 100644 index 0000000000..17e7523a9c --- /dev/null +++ b/queue-6.18/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch @@ -0,0 +1,71 @@ +From 24f3bb0c161a476fbe8b4f477c548d6f667c7b20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 15:36:46 +0100 +Subject: fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build + break + +From: Andy Shevchenko + +[ Upstream commit caf6144053b4e1c815aa56afb54745a176f999df ] + +Clang is not happy about set but unused variable: + +drivers/video/fbdev/matrox/g450_pll.c:412:18: error: variable 'mnp' set but not used + 412 | unsigned int mnp; + | ^ +1 error generated. + +Since the commit 7b987887f97b ("video: fbdev: matroxfb: remove dead code +and set but not used variable") the 'mnp' became unused, but eliminating +that code might have side-effects. The question here is what should we do +with 'mnp'? The easiest way out is just mark it with __maybe_unused which +will shut the compiler up and won't change any possible IO flow. So does +this change. + +A dive into the history of the driver: + +The problem was revealed when the #if 0 guarded code along with unused +pixel_vco variable was removed. That code was introduced in the original +commit 213d22146d1f ("[PATCH] (1/3) matroxfb for 2.5.3"). And then guarded +in the commit 705e41f82988 ("matroxfb DVI updates: Handle DVI output on +G450/G550. Powerdown unused portions of G450/G550 DAC. Split G450/G550 DAC +from older DAC1064 handling. Modify PLL setting when both CRTCs use same +pixel clocks."). + +NOTE: The two commits mentioned above pre-date Git era and available in +history.git repository for archaeological purposes. + +Even without that guard the modern compilers may see that the pixel_vco +wasn't ever used and seems a leftover after some debug or review made +25 years ago. + +The g450_mnp2vco() doesn't have any IO and as Jason said doesn't seem +to have any side effects either than some unneeded CPU processing during +runtime. I agree that's unlikely that timeout (or heating up the CPU) has +any effect on the HW (GPU/display) functionality. + +Fixes: 7b987887f97b ("video: fbdev: matroxfb: remove dead code and set but not used variable") +Signed-off-by: Andy Shevchenko +Reviewed-by: Jason Yan +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/matrox/g450_pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c +index e2c1478aa47f9..6a08f78cd1acb 100644 +--- a/drivers/video/fbdev/matrox/g450_pll.c ++++ b/drivers/video/fbdev/matrox/g450_pll.c +@@ -409,7 +409,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, + case M_VIDEO_PLL: + { + u_int8_t tmp; +- unsigned int mnp; ++ unsigned int mnp __maybe_unused; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); +-- +2.53.0 + diff --git a/queue-6.18/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch b/queue-6.18/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch new file mode 100644 index 0000000000..3111f2d106 --- /dev/null +++ b/queue-6.18/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch @@ -0,0 +1,52 @@ +From fcb0247e39d915d3899c56733d4faa0425483fdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:01:18 -0400 +Subject: fbdev: offb: fix PCI device reference leak on probe failure + +From: Yuho Choi + +[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ] + +offb_init_nodriver() gets a referenced PCI device with pci_get_device(). +If pci_enable_device() fails, the function returns without dropping that +reference. + +Release the PCI device reference before returning from the +pci_enable_device() failure path. + +Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/offb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c +index f85428e13996b..166b2dff36f59 100644 +--- a/drivers/video/fbdev/offb.c ++++ b/drivers/video/fbdev/offb.c +@@ -640,8 +640,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod + vid = be32_to_cpup(vidp); + did = be32_to_cpup(didp); + pdev = pci_get_device(vid, did, NULL); +- if (!pdev || pci_enable_device(pdev)) ++ if (!pdev) + return; ++ ++ if (pci_enable_device(pdev)) { ++ pci_dev_put(pdev); ++ return; ++ } + } + #endif + /* kludge for valkyrie */ +-- +2.53.0 + diff --git a/queue-6.18/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch b/queue-6.18/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch new file mode 100644 index 0000000000..bee582899b --- /dev/null +++ b/queue-6.18/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch @@ -0,0 +1,39 @@ +From 2f28a67c1f591818879d3458e48999e5a5ca89d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 11:39:39 +0000 +Subject: firmware: arm_ffa: Use the correct buffer size during RXTX_MAP + +From: Sebastian Ene + +[ Upstream commit 83210251fd70d5f96bcdc8911e15f7411a6b2463 ] + +Don't use the discovered buffer size from an FFA_FEATURES call directly +since we can run on a system that has the PAGE_SIZE larger than the +returned size which makes the alloc_pages_exact for the buffer to be +rounded up. + +Fixes: 61824feae5c0 ("firmware: arm_ffa: Fetch the Rx/Tx buffer size using ffa_features()") +Signed-off-by: Sebastian Ene +Link: https://patch.msgid.link/20260402113939.930221-1-sebastianene@google.com +Signed-off-by: Sudeep Holla +Signed-off-by: Sasha Levin +--- + drivers/firmware/arm_ffa/driver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index f6ceae987acbc..d71a2ef335d1c 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -2074,7 +2074,7 @@ static int __init ffa_init(void) + + ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), + virt_to_phys(drv_info->rx_buffer), +- rxtx_bufsz / FFA_PAGE_SIZE); ++ PAGE_ALIGN(rxtx_bufsz) / FFA_PAGE_SIZE); + if (ret) { + pr_err("failed to register FFA RxTx buffers\n"); + goto free_pages; +-- +2.53.0 + diff --git a/queue-6.18/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch b/queue-6.18/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch new file mode 100644 index 0000000000..c545cc436e --- /dev/null +++ b/queue-6.18/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch @@ -0,0 +1,63 @@ +From 7a163c55a3b8b31a1473e27d9fedc9f947f15ef3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 08:10:20 -0600 +Subject: firmware: dmi: Correct an indexing error in dmi.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit c064abc68e009d2cc18416e7132d9c25e03125b6 ] + +The entries later in enum dmi_entry_type don't match the SMBIOS +specification¹. + +The entry for type 33: `64-Bit Memory Error Information` is not present and +thus the index for all later entries is incorrect. + +Add it. + +Also, add missing entry types 43-46, while at it. + + ¹ Search for "System Management BIOS (SMBIOS) Reference Specification" + + [ bp: Drop the flaky SMBIOS spec URL. ] + +Fixes: 93c890dbe5287 ("firmware: Add DMI entry types to the headers") +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Jean Delvare +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20260307141024.819807-2-superm1@kernel.org +Signed-off-by: Sasha Levin +--- + include/linux/dmi.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/dmi.h b/include/linux/dmi.h +index 927f8a8b7a1dd..2eedf44e68012 100644 +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -60,6 +60,7 @@ enum dmi_entry_type { + DMI_ENTRY_OOB_REMOTE_ACCESS, + DMI_ENTRY_BIS_ENTRY, + DMI_ENTRY_SYSTEM_BOOT, ++ DMI_ENTRY_64_MEM_ERROR, + DMI_ENTRY_MGMT_DEV, + DMI_ENTRY_MGMT_DEV_COMPONENT, + DMI_ENTRY_MGMT_DEV_THRES, +@@ -69,6 +70,10 @@ enum dmi_entry_type { + DMI_ENTRY_ADDITIONAL, + DMI_ENTRY_ONBOARD_DEV_EXT, + DMI_ENTRY_MGMT_CONTROLLER_HOST, ++ DMI_ENTRY_TPM_DEVICE, ++ DMI_ENTRY_PROCESSOR_ADDITIONAL, ++ DMI_ENTRY_FIRMWARE_INVENTORY, ++ DMI_ENTRY_STRING_PROPERTY, + DMI_ENTRY_INACTIVE = 126, + DMI_ENTRY_END_OF_TABLE = 127, + }; +-- +2.53.0 + diff --git a/queue-6.18/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch b/queue-6.18/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch new file mode 100644 index 0000000000..d2b7166d3a --- /dev/null +++ b/queue-6.18/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch @@ -0,0 +1,48 @@ +From dac77783a01330fef01ec23fd334669307761fb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 13:45:02 +0900 +Subject: fs/adfs: validate nzones in adfs_validate_bblk() + +From: Bae Yeonju + +[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ] + +Reject ADFS disc records with a zero zone count during boot block +validation, before the disc record is used. + +When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) +which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to +dm[-1], causing an out-of-bounds write before the allocated buffer. + +adfs_validate_dr0() already rejects nzones != 1 for old-format +images. Add the equivalent check to adfs_validate_bblk() for +new-format images so that a crafted image with nzones == 0 is +rejected at probe time. + +Found by syzkaller. + +Fixes: f6f14a0d71b0 ("fs/adfs: map: move map-specific sb initialisation to map.c") +Signed-off-by: Bae Yeonju +Signed-off-by: Russell King (Oracle) +Signed-off-by: Sasha Levin +--- + fs/adfs/super.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/adfs/super.c b/fs/adfs/super.c +index fdccdbbfc2130..4f5279cd456fe 100644 +--- a/fs/adfs/super.c ++++ b/fs/adfs/super.c +@@ -317,6 +317,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, + if (adfs_checkdiscrecord(dr)) + return -EILSEQ; + ++ if ((dr->nzones | dr->nzones_high << 8) == 0) ++ return -EILSEQ; ++ + *drp = dr; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch b/queue-6.18/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch new file mode 100644 index 0000000000..fb909f4f8c --- /dev/null +++ b/queue-6.18/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch @@ -0,0 +1,49 @@ +From 9e6061a65c92cd3cbf2267c0bbfba04e6bb39c4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:45:56 +0900 +Subject: fs/mbcache: cancel shrink work before destroying the cache + +From: HyungJung Joo + +[ Upstream commit d227786ab1119669df4dc333a61510c52047cce4 ] + +mb_cache_destroy() calls shrinker_free() and then frees all cache +entries and the cache itself, but it does not cancel the pending +c_shrink_work work item first. + +If mb_cache_entry_create() schedules c_shrink_work via schedule_work() +and the work item is still pending or running when mb_cache_destroy() +runs, mb_cache_shrink_worker() will access the cache after its memory +has been freed, causing a use-after-free. + +This is only reachable by a privileged user (root or CAP_SYS_ADMIN) +who can trigger the last put of a mounted ext2/ext4/ocfs2 filesystem. + +Cancel the work item with cancel_work_sync() before calling +shrinker_free(), ensuring the worker has finished and will not be +rescheduled before the cache is torn down. + +Fixes: c2f3140fe2ec ("mbcache2: limit cache size") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054556.1821600-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/mbcache.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/mbcache.c b/fs/mbcache.c +index e60a840999aa9..90b0564c62d0b 100644 +--- a/fs/mbcache.c ++++ b/fs/mbcache.c +@@ -408,6 +408,7 @@ void mb_cache_destroy(struct mb_cache *cache) + { + struct mb_cache_entry *entry, *next; + ++ cancel_work_sync(&cache->c_shrink_work); + shrinker_free(cache->c_shrink); + + /* +-- +2.53.0 + diff --git a/queue-6.18/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch b/queue-6.18/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch new file mode 100644 index 0000000000..f8cc6c920b --- /dev/null +++ b/queue-6.18/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch @@ -0,0 +1,51 @@ +From 5af8c8eff7c10215b7d6dc65d1a3898a9dbbe1ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:19:55 +0800 +Subject: fs/ntfs3: terminate the cached volume label after UTF-8 conversion + +From: Pengpeng Hou + +[ Upstream commit a6cd43fe9b083fa23fe1595666d5738856cb261a ] + +ntfs_fill_super() loads the on-disk volume label with utf16s_to_utf8s() +and stores the result in sbi->volume.label. The converted label is later +exposed through ntfs3_label_show() using %s, but utf16s_to_utf8s() only +returns the number of bytes written and does not add a trailing NUL. + +If the converted label fills the entire fixed buffer, +ntfs3_label_show() can read past the end of sbi->volume.label while +looking for a terminator. + +Terminate the cached label explicitly after a successful conversion and +clamp the exact-full case to the last byte of the buffer. + +Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") +Signed-off-by: Pengpeng Hou +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index e6c0908e27c29..9a2e3d0efd998 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1277,8 +1277,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + le32_to_cpu(attr->res.data_size) >> 1, + UTF16_LITTLE_ENDIAN, sbi->volume.label, + sizeof(sbi->volume.label)); +- if (err < 0) ++ if (err < 0) { + sbi->volume.label[0] = 0; ++ } else if (err >= sizeof(sbi->volume.label)) { ++ sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0; ++ } else { ++ sbi->volume.label[err] = 0; ++ } + } else { + /* Should we break mounting here? */ + //err = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.18/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch b/queue-6.18/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch new file mode 100644 index 0000000000..3fe4956dd7 --- /dev/null +++ b/queue-6.18/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch @@ -0,0 +1,55 @@ +From ba87271b738a4441ffe8a39ead512073aa4f761e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:48:27 +0900 +Subject: fs/omfs: reject s_sys_blocksize smaller than OMFS_DIR_START + +From: HyungJung Joo + +[ Upstream commit 0621c385fda1376e967f37ccd534c26c3e511d14 ] + +omfs_fill_super() rejects oversized s_sys_blocksize values (> PAGE_SIZE), +but it does not reject values smaller than OMFS_DIR_START (0x1b8 = 440). + +Later, omfs_make_empty() uses + + sbi->s_sys_blocksize - OMFS_DIR_START + +as the length argument to memset(). Since s_sys_blocksize is u32, +a crafted filesystem image with s_sys_blocksize < OMFS_DIR_START causes +an unsigned underflow there, wrapping to a value near 2^32. That drives +a ~4 GiB memset() from bh->b_data + OMFS_DIR_START and overwrites kernel +memory far beyond the backing block buffer. + +Add the corresponding lower-bound check alongside the existing upper-bound +check in omfs_fill_super(), so that malformed images are rejected during +superblock validation before any filesystem data is processed. + +Fixes: a3ab7155ea21 ("omfs: add directory routines") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054827.1822061-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/omfs/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c +index 135c49c5d848c..31218d89b7580 100644 +--- a/fs/omfs/inode.c ++++ b/fs/omfs/inode.c +@@ -512,6 +512,12 @@ static int omfs_fill_super(struct super_block *sb, struct fs_context *fc) + goto out_brelse_bh; + } + ++ if (sbi->s_sys_blocksize < OMFS_DIR_START) { ++ printk(KERN_ERR "omfs: sysblock size (%d) is too small\n", ++ sbi->s_sys_blocksize); ++ goto out_brelse_bh; ++ } ++ + if (sbi->s_blocksize < sbi->s_sys_blocksize || + sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { + printk(KERN_ERR "omfs: block size (%d) is out of range\n", +-- +2.53.0 + diff --git a/queue-6.18/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch b/queue-6.18/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch new file mode 100644 index 0000000000..1fb9fb314b --- /dev/null +++ b/queue-6.18/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch @@ -0,0 +1,151 @@ +From 8242728ba4b44d7f3c6f9e2d0cefd5bdd52339ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 14:58:00 +0200 +Subject: fsnotify: fix inode reference leak in fsnotify_recalc_mask() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Amir Goldstein + +[ Upstream commit 4aca914ac152f5d055ddcb36704d1e539ac08977 ] + +fsnotify_recalc_mask() fails to handle the return value of +__fsnotify_recalc_mask(), which may return an inode pointer that needs +to be released via fsnotify_drop_object() when the connector's HAS_IREF +flag transitions from set to cleared. + +This manifests as a hung task with the following call trace: + + INFO: task umount:1234 blocked for more than 120 seconds. + Call Trace: + __schedule + schedule + fsnotify_sb_delete + generic_shutdown_super + kill_anon_super + cleanup_mnt + task_work_run + do_exit + do_group_exit + +The race window that triggers the iref leak: + + Thread A (adding mark) Thread B (removing mark) + ────────────────────── ──────────────────────── + fsnotify_add_mark_locked(): + fsnotify_add_mark_list(): + spin_lock(conn->lock) + add mark_B(evictable) to list + spin_unlock(conn->lock) + return + + /* ---- gap: no lock held ---- */ + + fsnotify_detach_mark(mark_A): + spin_lock(mark_A->lock) + clear ATTACHED flag on mark_A + spin_unlock(mark_A->lock) + fsnotify_put_mark(mark_A) + + fsnotify_recalc_mask(): + spin_lock(conn->lock) + __fsnotify_recalc_mask(): + /* mark_A skipped: ATTACHED cleared */ + /* only mark_B(evictable) remains */ + want_iref = false + has_iref = true /* not yet cleared */ + -> HAS_IREF transitions true -> false + -> returns inode pointer + spin_unlock(conn->lock) + /* BUG: return value discarded! + * iput() and fsnotify_put_sb_watched_objects() + * are never called */ + +Fix this by deferring the transition true -> false of HAS_IREF flag from +fsnotify_recalc_mask() (Thread A) to fsnotify_put_mark() (thread B). + +Fixes: c3638b5b1374 ("fsnotify: allow adding an inode mark without pinning inode") +Signed-off-by: Xin Yin +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/CAOQ4uxiPsbHb0o5voUKyPFMvBsDkG914FYDcs4C5UpBMNm0Vcg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/notify/mark.c | 39 ++++++++++++++++++++++++++++++++++++--- + 1 file changed, 36 insertions(+), 3 deletions(-) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index cedd84afbede5..78338075f08a1 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -237,7 +237,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn, + return inode; + } + +-static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) ++/* ++ * Calculate mask of events for a list of marks. ++ * ++ * Return true if any of the attached marks want to hold an inode reference. ++ */ ++static bool __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + { + u32 new_mask = 0; + bool want_iref = false; +@@ -261,6 +266,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + */ + WRITE_ONCE(*fsnotify_conn_mask_p(conn), new_mask); + ++ return want_iref; ++} ++ ++/* ++ * Calculate mask of events for a list of marks after attach/modify mark ++ * and get an inode reference for the connector if needed. ++ * ++ * A concurrent add of evictable mark and detach of non-evictable mark can ++ * lead to __fsnotify_recalc_mask() returning false want_iref, but in this ++ * case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called ++ * from fsnotify_put_mark(). ++ */ ++static void fsnotify_recalc_mask_set_iref(struct fsnotify_mark_connector *conn) ++{ ++ bool has_iref = conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF; ++ bool want_iref = __fsnotify_recalc_mask(conn) || has_iref; ++ ++ (void) fsnotify_update_iref(conn, want_iref); ++} ++ ++/* ++ * Calculate mask of events for a list of marks after detach mark ++ * and return the inode object if its reference is no longer needed. ++ */ ++static void *fsnotify_recalc_mask_clear_iref(struct fsnotify_mark_connector *conn) ++{ ++ bool want_iref = __fsnotify_recalc_mask(conn); ++ + return fsnotify_update_iref(conn, want_iref); + } + +@@ -297,7 +330,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + + spin_lock(&conn->lock); + update_children = !fsnotify_conn_watches_children(conn); +- __fsnotify_recalc_mask(conn); ++ fsnotify_recalc_mask_set_iref(conn); + update_children &= fsnotify_conn_watches_children(conn); + spin_unlock(&conn->lock); + /* +@@ -415,7 +448,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) + /* Update watched objects after detaching mark */ + if (sb) + fsnotify_update_sb_watchers(sb, conn); +- objp = __fsnotify_recalc_mask(conn); ++ objp = fsnotify_recalc_mask_clear_iref(conn); + type = conn->type; + } + WRITE_ONCE(mark->connector, NULL); +-- +2.53.0 + diff --git a/queue-6.18/fuse-fix-premature-writetrhough-request-for-large-fo.patch b/queue-6.18/fuse-fix-premature-writetrhough-request-for-large-fo.patch new file mode 100644 index 0000000000..7d2cce495e --- /dev/null +++ b/queue-6.18/fuse-fix-premature-writetrhough-request-for-large-fo.patch @@ -0,0 +1,74 @@ +From f3db822557ead67948f50c3a2acc40cf2d23d8ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 10:36:07 +0800 +Subject: fuse: fix premature writetrhough request for large folio + +From: Jingbo Xu + +[ Upstream commit 5223e0470e7bb7910038fe3d31171490e00fbbb9 ] + +When large folio is enabled and the initial folio offset exceeds +PAGE_SIZE, e.g. the position resides in the second page of a large +folio, after the folio copying the offset (in the page) won't be updated +to 0 even though the expected range is successfully copied until the end +of the folio. In this case fuse_fill_write_pages() exits prematurelly +before the request has reached the max_write/max_pages limit. + +Fix this by eliminating page offset entirely and use folio offset +instead. + +Fixes: d60a6015e1a2 ("fuse: support large folios for writethrough writes") +Reviewed-by: Horst Birthelmer +Reviewed-by: Joanne Koong +Signed-off-by: Jingbo Xu +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/file.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 6014d588845cd..00ff6374dc76b 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1183,7 +1183,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, + { + struct fuse_args_pages *ap = &ia->ap; + struct fuse_conn *fc = get_fuse_conn(mapping->host); +- unsigned offset = pos & (PAGE_SIZE - 1); + size_t count = 0; + unsigned int num; + int err = 0; +@@ -1210,7 +1209,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, + if (mapping_writably_mapped(mapping)) + flush_dcache_folio(folio); + +- folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset; ++ folio_offset = offset_in_folio(folio, pos); + bytes = min(folio_size(folio) - folio_offset, num); + + tmp = copy_folio_from_iter_atomic(folio, folio_offset, bytes, ii); +@@ -1240,9 +1239,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, + count += tmp; + pos += tmp; + num -= tmp; +- offset += tmp; +- if (offset == folio_size(folio)) +- offset = 0; + + /* If we copied full folio, mark it uptodate */ + if (tmp == folio_size(folio)) +@@ -1254,7 +1250,9 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, + ia->write.folio_locked = true; + break; + } +- if (!fc->big_writes || offset != 0) ++ if (!fc->big_writes) ++ break; ++ if (folio_offset + tmp != folio_size(folio)) + break; + } + +-- +2.53.0 + diff --git a/queue-6.18/fuse-fix-uninit-value-in-fuse_dentry_revalidate.patch b/queue-6.18/fuse-fix-uninit-value-in-fuse_dentry_revalidate.patch new file mode 100644 index 0000000000..d4a28d0c72 --- /dev/null +++ b/queue-6.18/fuse-fix-uninit-value-in-fuse_dentry_revalidate.patch @@ -0,0 +1,65 @@ +From f15050259b42d22909490182f958e5e57101c090 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:48:30 +0000 +Subject: fuse: fix uninit-value in fuse_dentry_revalidate() + +From: Luis Henriques + +[ Upstream commit 5a6baf204610589f8a5b5a1cd69d1fe661d9d3cd ] + +fuse_dentry_revalidate() may be called with a dentry that didn't had +->d_time initialised. The issue was found with KMSAN, where lookup_open() +calls __d_alloc(), followed by d_revalidate(), as shown below: + +===================================================== +BUG: KMSAN: uninit-value in fuse_dentry_revalidate+0x150/0x13d0 fs/fuse/dir.c:394 + fuse_dentry_revalidate+0x150/0x13d0 fs/fuse/dir.c:394 + d_revalidate fs/namei.c:1030 [inline] + lookup_open fs/namei.c:4405 [inline] + open_last_lookups fs/namei.c:4583 [inline] + path_openat+0x1614/0x64c0 fs/namei.c:4827 + do_file_open+0x2aa/0x680 fs/namei.c:4859 +[...] + +Uninit was created at: + slab_post_alloc_hook mm/slub.c:4466 [inline] + slab_alloc_node mm/slub.c:4788 [inline] + kmem_cache_alloc_lru_noprof+0x382/0x1280 mm/slub.c:4807 + __d_alloc+0x55/0xa00 fs/dcache.c:1740 + d_alloc_parallel+0x99/0x2740 fs/dcache.c:2604 + lookup_open fs/namei.c:4398 [inline] + open_last_lookups fs/namei.c:4583 [inline] + path_openat+0x135f/0x64c0 fs/namei.c:4827 + do_file_open+0x2aa/0x680 fs/namei.c:4859 +[...] +===================================================== + +Reported-by: syzbot+fdebb2dc960aa56c600a@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69917e0d.050a0220.340abe.02e2.GAE@google.com +Fixes: 2396356a945b ("fuse: add more control over cache invalidation behaviour") +Signed-off-by: Luis Henriques +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/dir.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c +index 77982fdbcf278..98b174bd802f0 100644 +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -455,6 +455,11 @@ static int fuse_dentry_init(struct dentry *dentry) + fd->dentry = dentry; + RB_CLEAR_NODE(&fd->node); + dentry->d_fsdata = fd; ++ /* ++ * Initialising d_time (epoch) to '0' ensures the dentry is invalid ++ * if compared to fc->epoch, which is initialized to '1'. ++ */ ++ dentry->d_time = 0; + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/fuse-new-work-queue-to-periodically-invalidate-expir.patch b/queue-6.18/fuse-new-work-queue-to-periodically-invalidate-expir.patch new file mode 100644 index 0000000000..a95e0a1b83 --- /dev/null +++ b/queue-6.18/fuse-new-work-queue-to-periodically-invalidate-expir.patch @@ -0,0 +1,367 @@ +From e5da1c5c5107c7ce61e56449cb8415fa4a29ec49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Sep 2025 14:53:08 +0100 +Subject: fuse: new work queue to periodically invalidate expired dentries + +From: Luis Henriques + +[ Upstream commit ab84ad5973869a660ca3ad0c54a2b84d975d47c4 ] + +This patch adds the necessary infrastructure to keep track of all dentries +created for FUSE file systems. A set of rbtrees, protected by hashed +locks, will be used to keep all these dentries sorted by expiry time. + +A new module parameter 'inval_wq' is also added. When set, it will start +a work queue which will periodically invalidate expired dentries. The +value of this new parameter is the period, in seconds, for this work +queue. Once this parameter is set, every new dentry will be added to one +of the rbtrees. + +When the work queue is executed, it will check all the rbtrees and will +invalidate those dentries that have timed-out. + +The work queue period can not be smaller than 5 seconds, but can be +disabled by setting 'inval_wq' to zero (which is the default). + +Signed-off-by: Luis Henriques +Signed-off-by: Miklos Szeredi +Stable-dep-of: 5a6baf204610 ("fuse: fix uninit-value in fuse_dentry_revalidate()") +Signed-off-by: Sasha Levin +--- + fs/fuse/dir.c | 216 ++++++++++++++++++++++++++++++++++++++++++----- + fs/fuse/fuse_i.h | 10 +++ + fs/fuse/inode.c | 3 + + 3 files changed, 208 insertions(+), 21 deletions(-) + +diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c +index ecaec0fea3a13..77982fdbcf278 100644 +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -27,6 +27,67 @@ module_param(allow_sys_admin_access, bool, 0644); + MODULE_PARM_DESC(allow_sys_admin_access, + "Allow users with CAP_SYS_ADMIN in initial userns to bypass allow_other access check"); + ++struct dentry_bucket { ++ struct rb_root tree; ++ spinlock_t lock; ++}; ++ ++#define HASH_BITS 5 ++#define HASH_SIZE (1 << HASH_BITS) ++static struct dentry_bucket dentry_hash[HASH_SIZE]; ++struct delayed_work dentry_tree_work; ++ ++/* Minimum invalidation work queue frequency */ ++#define FUSE_DENTRY_INVAL_FREQ_MIN 5 ++ ++unsigned __read_mostly inval_wq; ++static int inval_wq_set(const char *val, const struct kernel_param *kp) ++{ ++ unsigned int num; ++ unsigned int old = inval_wq; ++ int ret; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtouint(val, 0, &num); ++ if (ret) ++ return ret; ++ ++ if ((num < FUSE_DENTRY_INVAL_FREQ_MIN) && (num != 0)) ++ return -EINVAL; ++ ++ /* This should prevent overflow in secs_to_jiffies() */ ++ if (num > USHRT_MAX) ++ return -EINVAL; ++ ++ *((unsigned int *)kp->arg) = num; ++ ++ if (num && !old) ++ schedule_delayed_work(&dentry_tree_work, ++ secs_to_jiffies(num)); ++ else if (!num && old) ++ cancel_delayed_work_sync(&dentry_tree_work); ++ ++ return 0; ++} ++static const struct kernel_param_ops inval_wq_ops = { ++ .set = inval_wq_set, ++ .get = param_get_uint, ++}; ++module_param_cb(inval_wq, &inval_wq_ops, &inval_wq, 0644); ++__MODULE_PARM_TYPE(inval_wq, "uint"); ++MODULE_PARM_DESC(inval_wq, ++ "Dentries invalidation work queue period in secs (>= " ++ __stringify(FUSE_DENTRY_INVAL_FREQ_MIN) ")."); ++ ++static inline struct dentry_bucket *get_dentry_bucket(struct dentry *dentry) ++{ ++ int i = hash_ptr(dentry, HASH_BITS); ++ ++ return &dentry_hash[i]; ++} ++ + static void fuse_advise_use_readdirplus(struct inode *dir) + { + struct fuse_inode *fi = get_fuse_inode(dir); +@@ -34,33 +95,131 @@ static void fuse_advise_use_readdirplus(struct inode *dir) + set_bit(FUSE_I_ADVISE_RDPLUS, &fi->state); + } + +-#if BITS_PER_LONG >= 64 +-static inline void __fuse_dentry_settime(struct dentry *entry, u64 time) ++struct fuse_dentry { ++ u64 time; ++ union { ++ struct rcu_head rcu; ++ struct rb_node node; ++ }; ++ struct dentry *dentry; ++}; ++ ++static void __fuse_dentry_tree_del_node(struct fuse_dentry *fd, ++ struct dentry_bucket *bucket) + { +- entry->d_fsdata = (void *) time; ++ if (!RB_EMPTY_NODE(&fd->node)) { ++ rb_erase(&fd->node, &bucket->tree); ++ RB_CLEAR_NODE(&fd->node); ++ } + } + +-static inline u64 fuse_dentry_time(const struct dentry *entry) ++static void fuse_dentry_tree_del_node(struct dentry *dentry) + { +- return (u64)entry->d_fsdata; ++ struct fuse_dentry *fd = dentry->d_fsdata; ++ struct dentry_bucket *bucket = get_dentry_bucket(dentry); ++ ++ spin_lock(&bucket->lock); ++ __fuse_dentry_tree_del_node(fd, bucket); ++ spin_unlock(&bucket->lock); + } + +-#else +-union fuse_dentry { +- u64 time; +- struct rcu_head rcu; +-}; ++static void fuse_dentry_tree_add_node(struct dentry *dentry) ++{ ++ struct fuse_dentry *fd = dentry->d_fsdata; ++ struct dentry_bucket *bucket; ++ struct fuse_dentry *cur; ++ struct rb_node **p, *parent = NULL; ++ ++ if (!inval_wq) ++ return; ++ ++ bucket = get_dentry_bucket(dentry); ++ ++ spin_lock(&bucket->lock); ++ ++ __fuse_dentry_tree_del_node(fd, bucket); ++ ++ p = &bucket->tree.rb_node; ++ while (*p) { ++ parent = *p; ++ cur = rb_entry(*p, struct fuse_dentry, node); ++ if (fd->time < cur->time) ++ p = &(*p)->rb_left; ++ else ++ p = &(*p)->rb_right; ++ } ++ rb_link_node(&fd->node, parent, p); ++ rb_insert_color(&fd->node, &bucket->tree); ++ spin_unlock(&bucket->lock); ++} ++ ++/* ++ * work queue which, when enabled, will periodically check for expired dentries ++ * in the dentries tree. ++ */ ++static void fuse_dentry_tree_work(struct work_struct *work) ++{ ++ LIST_HEAD(dispose); ++ struct fuse_dentry *fd; ++ struct rb_node *node; ++ int i; ++ ++ for (i = 0; i < HASH_SIZE; i++) { ++ spin_lock(&dentry_hash[i].lock); ++ node = rb_first(&dentry_hash[i].tree); ++ while (node) { ++ fd = rb_entry(node, struct fuse_dentry, node); ++ if (time_after64(get_jiffies_64(), fd->time)) { ++ rb_erase(&fd->node, &dentry_hash[i].tree); ++ RB_CLEAR_NODE(&fd->node); ++ spin_unlock(&dentry_hash[i].lock); ++ d_dispose_if_unused(fd->dentry, &dispose); ++ cond_resched(); ++ spin_lock(&dentry_hash[i].lock); ++ } else ++ break; ++ node = rb_first(&dentry_hash[i].tree); ++ } ++ spin_unlock(&dentry_hash[i].lock); ++ shrink_dentry_list(&dispose); ++ } ++ ++ if (inval_wq) ++ schedule_delayed_work(&dentry_tree_work, ++ secs_to_jiffies(inval_wq)); ++} ++ ++void fuse_dentry_tree_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < HASH_SIZE; i++) { ++ spin_lock_init(&dentry_hash[i].lock); ++ dentry_hash[i].tree = RB_ROOT; ++ } ++ INIT_DELAYED_WORK(&dentry_tree_work, fuse_dentry_tree_work); ++} ++ ++void fuse_dentry_tree_cleanup(void) ++{ ++ int i; ++ ++ inval_wq = 0; ++ cancel_delayed_work_sync(&dentry_tree_work); ++ ++ for (i = 0; i < HASH_SIZE; i++) ++ WARN_ON_ONCE(!RB_EMPTY_ROOT(&dentry_hash[i].tree)); ++} + + static inline void __fuse_dentry_settime(struct dentry *dentry, u64 time) + { +- ((union fuse_dentry *) dentry->d_fsdata)->time = time; ++ ((struct fuse_dentry *) dentry->d_fsdata)->time = time; + } + + static inline u64 fuse_dentry_time(const struct dentry *entry) + { +- return ((union fuse_dentry *) entry->d_fsdata)->time; ++ return ((struct fuse_dentry *) entry->d_fsdata)->time; + } +-#endif + + static void fuse_dentry_settime(struct dentry *dentry, u64 time) + { +@@ -81,6 +240,7 @@ static void fuse_dentry_settime(struct dentry *dentry, u64 time) + } + + __fuse_dentry_settime(dentry, time); ++ fuse_dentry_tree_add_node(dentry); + } + + /* +@@ -283,21 +443,36 @@ static int fuse_dentry_revalidate(struct inode *dir, const struct qstr *name, + goto out; + } + +-#if BITS_PER_LONG < 64 + static int fuse_dentry_init(struct dentry *dentry) + { +- dentry->d_fsdata = kzalloc(sizeof(union fuse_dentry), +- GFP_KERNEL_ACCOUNT | __GFP_RECLAIMABLE); ++ struct fuse_dentry *fd; + +- return dentry->d_fsdata ? 0 : -ENOMEM; ++ fd = kzalloc(sizeof(struct fuse_dentry), ++ GFP_KERNEL_ACCOUNT | __GFP_RECLAIMABLE); ++ if (!fd) ++ return -ENOMEM; ++ ++ fd->dentry = dentry; ++ RB_CLEAR_NODE(&fd->node); ++ dentry->d_fsdata = fd; ++ ++ return 0; ++} ++ ++static void fuse_dentry_prune(struct dentry *dentry) ++{ ++ struct fuse_dentry *fd = dentry->d_fsdata; ++ ++ if (!RB_EMPTY_NODE(&fd->node)) ++ fuse_dentry_tree_del_node(dentry); + } ++ + static void fuse_dentry_release(struct dentry *dentry) + { +- union fuse_dentry *fd = dentry->d_fsdata; ++ struct fuse_dentry *fd = dentry->d_fsdata; + + kfree_rcu(fd, rcu); + } +-#endif + + static int fuse_dentry_delete(const struct dentry *dentry) + { +@@ -331,10 +506,9 @@ static struct vfsmount *fuse_dentry_automount(struct path *path) + const struct dentry_operations fuse_dentry_operations = { + .d_revalidate = fuse_dentry_revalidate, + .d_delete = fuse_dentry_delete, +-#if BITS_PER_LONG < 64 + .d_init = fuse_dentry_init, ++ .d_prune = fuse_dentry_prune, + .d_release = fuse_dentry_release, +-#endif + .d_automount = fuse_dentry_automount, + }; + +diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h +index c288f28f6c6ea..276dfddce5b53 100644 +--- a/fs/fuse/fuse_i.h ++++ b/fs/fuse/fuse_i.h +@@ -54,6 +54,13 @@ + /** Frequency (in jiffies) of request timeout checks, if opted into */ + extern const unsigned long fuse_timeout_timer_freq; + ++/* ++ * Dentries invalidation workqueue period, in seconds. The value of this ++ * parameter shall be >= FUSE_DENTRY_INVAL_FREQ_MIN seconds, or 0 (zero), in ++ * which case no workqueue will be created. ++ */ ++extern unsigned inval_wq __read_mostly; ++ + /** Maximum of max_pages received in init_out */ + extern unsigned int fuse_max_pages_limit; + /* +@@ -1278,6 +1285,9 @@ void fuse_wait_aborted(struct fuse_conn *fc); + /* Check if any requests timed out */ + void fuse_check_timeout(struct work_struct *work); + ++void fuse_dentry_tree_init(void); ++void fuse_dentry_tree_cleanup(void); ++ + /** + * Invalidate inode attributes + */ +diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c +index e9ed693fc7b37..a090c91abb89d 100644 +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -2296,6 +2296,8 @@ static int __init fuse_init(void) + if (res) + goto err_sysfs_cleanup; + ++ fuse_dentry_tree_init(); ++ + sanitize_global_limit(&max_user_bgreq); + sanitize_global_limit(&max_user_congthresh); + +@@ -2315,6 +2317,7 @@ static void __exit fuse_exit(void) + { + pr_debug("exit\n"); + ++ fuse_dentry_tree_cleanup(); + fuse_ctl_cleanup(); + fuse_sysfs_cleanup(); + fuse_fs_cleanup(); +-- +2.53.0 + diff --git a/queue-6.18/futex-drop-clone_thread-requirement-for-private-defa.patch b/queue-6.18/futex-drop-clone_thread-requirement-for-private-defa.patch new file mode 100644 index 0000000000..a4f58b0fd9 --- /dev/null +++ b/queue-6.18/futex-drop-clone_thread-requirement-for-private-defa.patch @@ -0,0 +1,68 @@ +From 3f3ffd05fb6610124d567dbcc3ef3b7564703702 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 May 2026 12:41:23 -0700 +Subject: futex: Drop CLONE_THREAD requirement for private default hash alloc + +From: Davidlohr Bueso + +[ Upstream commit ee9dce44362b2d8132c32964656ab6dff7dfbc6a ] + +Currently need_futex_hash_allocate_default() depends on strict pthread +semantics, abusing CLONE_THREAD. This breaks the non-concurrency +assumptions when doing the mm->futex_ref pcpu allocations, leading to +bugs[0] when sharing the mm in other ways; ie: + + BUG: KASAN: slab-use-after-free in futex_hash_put + +... where the +1 bias can end up on a percpu counter that mm->futex_ref +no longer points at. + +Loosen the check to cover any CLONE_VM clone, except vfork(). Excluding +vfork keeps the existing paths untouched (no overhead), and we can't +race in the first place: either the parent is suspended and the child +runs alone, or mm->futex_ref is already allocated from an earlier +CLONE_VM. + +Link: https://lore.kernel.org/all/CAL_bE8LsmCQ-FAtYDuwbJhOkt9p2wwYQwAbMh=PifC=VsiBM6A@mail.gmail.com/ [0] +Fixes: d9b05321e21e ("futex: Move futex_hash_free() back to __mmput()") +Reported-by: Yiming Qian +Signed-off-by: Davidlohr Bueso +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 3ad76c2cf5af5..1215d3f52c6d2 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -1911,9 +1911,11 @@ static void rv_task_fork(struct task_struct *p) + + static bool need_futex_hash_allocate_default(u64 clone_flags) + { +- if ((clone_flags & (CLONE_THREAD | CLONE_VM)) != (CLONE_THREAD | CLONE_VM)) +- return false; +- return true; ++ /* ++ * Allocate a default futex hash for any sibling that will ++ * share the parent's mm, except vfork. ++ */ ++ return (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM; + } + + /* +@@ -2296,10 +2298,6 @@ __latent_entropy struct task_struct *copy_process( + if (retval) + goto bad_fork_cancel_cgroup; + +- /* +- * Allocate a default futex hash for the user process once the first +- * thread spawns. +- */ + if (need_futex_hash_allocate_default(clone_flags)) { + retval = futex_hash_allocate_default(); + if (retval) +-- +2.53.0 + diff --git a/queue-6.18/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch b/queue-6.18/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch new file mode 100644 index 0000000000..4da4b22b8d --- /dev/null +++ b/queue-6.18/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch @@ -0,0 +1,100 @@ +From dee972d929cf2d05982f54128fa9d970a34c48af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:34:25 +0200 +Subject: futex: Prevent lockup in requeue-PI during signal/ timeout wakeup + +From: Sebastian Andrzej Siewior + +[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ] + +During wait-requeue-pi (task A) and requeue-PI (task B) the following +race can happen: + + Task A Task B + futex_wait_requeue_pi() + futex_setup_timer() + futex_do_wait() + futex_requeue() + CLASS(hb, hb1)(&key1); + CLASS(hb, hb2)(&key2); + *timeout* + futex_requeue_pi_wakeup_sync() + requeue_state = Q_REQUEUE_PI_IGNORE + + *blocks on hb->lock* + + futex_proxy_trylock_atomic() + futex_requeue_pi_prepare() + Q_REQUEUE_PI_IGNORE => -EAGAIN + double_unlock_hb(hb1, hb2) + *retry* + +Task B acquires both hb locks and attempts to acquire the PI-lock of the +top most waiter (task B). Task A is leaving early due to a signal/ +timeout and started removing itself from the queue. It updates its +requeue_state but can not remove it from the list because this requires +the hb lock which is owned by task B. + +Usually task A is able to swoop the lock after task B unlocked it. +However if task B is of higher priority then task A may not be able to +wake up in time and acquire the lock before task B gets it again. +Especially on a UP system where A is never scheduled. + +As a result task A blocks on the lock and task B busy loops, trying to +make progress but live locks the system instead. Tragic. + +This can be fixed by removing the top most waiter from the list in this +case. This allows task B to grab the next top waiter (if any) in the +next iteration and make progress. + +Remove the top most waiter if futex_requeue_pi_prepare() fails. +Let the waiter conditionally remove itself from the list in +handle_early_requeue_pi_wakeup(). + +Fixes: 07d91ef510fb1 ("futex: Prevent requeue_pi() lock nesting issue on RT") +Reported-by: Moritz Klammler +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260428103425.dywXyPd3@linutronix.de +Closes: https://lore.kernel.org/all/VE1PR06MB6894BE61C173D802365BE19DFF4CA@VE1PR06MB6894.eurprd06.prod.outlook.com +Signed-off-by: Sasha Levin +--- + kernel/futex/requeue.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c +index d818b4d47f1ba..b597cb3d17fc1 100644 +--- a/kernel/futex/requeue.c ++++ b/kernel/futex/requeue.c +@@ -319,8 +319,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, + return -EINVAL; + + /* Ensure that this does not race against an early wakeup */ +- if (!futex_requeue_pi_prepare(top_waiter, NULL)) ++ if (!futex_requeue_pi_prepare(top_waiter, NULL)) { ++ plist_del(&top_waiter->list, &hb1->chain); ++ futex_hb_waiters_dec(hb1); + return -EAGAIN; ++ } + + /* + * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit +@@ -722,10 +725,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, + + /* + * We were woken prior to requeue by a timeout or a signal. +- * Unqueue the futex_q and determine which it was. ++ * Conditionally unqueue the futex_q and determine which it was. + */ +- plist_del(&q->list, &hb->chain); +- futex_hb_waiters_dec(hb); ++ if (!plist_node_empty(&q->list)) { ++ plist_del(&q->list, &hb->chain); ++ futex_hb_waiters_dec(hb); ++ } + + /* Handle spurious wakeups gracefully */ + ret = -EWOULDBLOCK; +-- +2.53.0 + diff --git a/queue-6.18/fwctl-fix-class-init-ordering-to-avoid-null-pointer-.patch b/queue-6.18/fwctl-fix-class-init-ordering-to-avoid-null-pointer-.patch new file mode 100644 index 0000000000..bda71494aa --- /dev/null +++ b/queue-6.18/fwctl-fix-class-init-ordering-to-avoid-null-pointer-.patch @@ -0,0 +1,47 @@ +From a3e7775ab8459d7ee35c2ad93c4c69fefbed3878 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:19:02 +0800 +Subject: fwctl: Fix class init ordering to avoid NULL pointer dereference on + device removal + +From: Richard Cheng + +[ Upstream commit a55f80233f384dc89ef3425b2e1dd0e6d44bcf29 ] + +CXL is linked before fwctl in drivers/Makefile. Both use `module_init, so +`cxl_pci_driver_init()` runs first. When `cxl_pci_probe()` calls +`fwctl_register()` and then `device_add()`, fwctl_class is not yet +registered because fwctl_init() hasn't run, causing `class_to_subsys()` to +return NULL and skip knode_class initialization. + +On device removal, `class_to_subsys()` returns non-NULL, and +`device_del()` calls `klist_del()` on the uninitialized knode, triggering +a NULL pointer dereference. + +Fixes: 858ce2f56b52 ("cxl: Add FWCTL support to CXL") +Link: https://patch.msgid.link/r/20260409051902.40218-1-icheng@nvidia.com +Signed-off-by: Richard Cheng +Reviewed-by: Kai-Heng Feng +Reviewed-by: Dave Jiang +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/fwctl/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c +index bc6378506296c..098c3824ad751 100644 +--- a/drivers/fwctl/main.c ++++ b/drivers/fwctl/main.c +@@ -415,7 +415,7 @@ static void __exit fwctl_exit(void) + unregister_chrdev_region(fwctl_dev, FWCTL_MAX_DEVICES); + } + +-module_init(fwctl_init); ++subsys_initcall(fwctl_init); + module_exit(fwctl_exit); + MODULE_DESCRIPTION("fwctl device firmware access framework"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.18/gfs2-add-some-missing-log-locking.patch b/queue-6.18/gfs2-add-some-missing-log-locking.patch new file mode 100644 index 0000000000..d1d889cc2c --- /dev/null +++ b/queue-6.18/gfs2-add-some-missing-log-locking.patch @@ -0,0 +1,109 @@ +From 8fbb5a6ff9903a60f4670e20ce57537e58ce995d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 06:13:42 +0200 +Subject: gfs2: add some missing log locking + +From: Andreas Gruenbacher + +[ Upstream commit fe2c8d051150b90b3ccb85f89e3b1d636cb88ec8 ] + +Function gfs2_logd() calls the log flushing functions gfs2_ail1_start(), +gfs2_ail1_wait(), and gfs2_ail1_empty() without holding sdp->sd_log_flush_lock, +but these functions require exclusion against concurrent transactions. + +To fix that, add a non-locking __gfs2_log_flush() function. Then, in +gfs2_logd(), take sdp->sd_log_flush_lock before calling the above mentioned log +flushing functions and __gfs2_log_flush(). + +Fixes: 5e4c7632aae1c ("gfs2: Issue revokes more intelligently") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 115c4ac457e90..592f69602e5aa 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -1027,14 +1027,15 @@ static void trans_drain(struct gfs2_trans *tr) + } + + /** +- * gfs2_log_flush - flush incore transaction(s) ++ * __gfs2_log_flush - flush incore transaction(s) + * @sdp: The filesystem + * @gl: The glock structure to flush. If NULL, flush the whole incore log + * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags + * + */ + +-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ++ u32 flags) + { + struct gfs2_trans *tr = NULL; + unsigned int reserved_blocks = 0, used_blocks = 0; +@@ -1042,7 +1043,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + unsigned int first_log_head; + unsigned int reserved_revokes = 0; + +- down_write(&sdp->sd_log_flush_lock); + trace_gfs2_log_flush(sdp, 1, flags); + + repeat: +@@ -1154,7 +1154,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + gfs2_assert_withdraw_delayed(sdp, used_blocks < reserved_blocks); + gfs2_log_release(sdp, reserved_blocks - used_blocks); + } +- up_write(&sdp->sd_log_flush_lock); + gfs2_trans_free(sdp, tr); + if (gfs2_withdrawing(sdp)) + gfs2_withdraw(sdp); +@@ -1177,6 +1176,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + goto out_end; + } + ++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++{ ++ down_write(&sdp->sd_log_flush_lock); ++ __gfs2_log_flush(sdp, gl, flags); ++ up_write(&sdp->sd_log_flush_lock); ++} ++ + /** + * gfs2_merge_trans - Merge a new transaction into a cached transaction + * @sdp: the filesystem +@@ -1319,19 +1325,25 @@ int gfs2_logd(void *data) + } + + if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_JFLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_JFLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) || + gfs2_ail_flush_reqd(sdp)) { + clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_start(sdp); + gfs2_ail1_wait(sdp); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; +-- +2.53.0 + diff --git a/queue-6.18/gfs2-call-unlock_new_inode-before-d_instantiate.patch b/queue-6.18/gfs2-call-unlock_new_inode-before-d_instantiate.patch new file mode 100644 index 0000000000..e35f099481 --- /dev/null +++ b/queue-6.18/gfs2-call-unlock_new_inode-before-d_instantiate.patch @@ -0,0 +1,48 @@ +From 9f2bcba59399168cac10b1233dea24e82709b066 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:04:05 +0100 +Subject: gfs2: Call unlock_new_inode before d_instantiate + +From: Andreas Gruenbacher + +[ Upstream commit 2ff7cf7e0640ff071ebc5c7e3dc2df024a7c91e6 ] + +As Neil Brown describes in detail in the link referenced below, new +inodes must be unlocked before they can be instantiated. + +An even better fix is to use d_instantiate_new(), which combines +d_instantiate() and unlock_new_inode(). + +Fixes: 3d36e57ff768 ("gfs2: gfs2_create_inode rework") +Reported-by: syzbot+0ea5108a1f5fb4fcc2d8@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-fsdevel/177153754005.8396.8777398743501764194@noble.neil.brown.name/ +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/inode.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index 03dd54fb7e8c8..12e5792190650 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -892,7 +892,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + goto fail_gunlock4; + + mark_inode_dirty(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + /* After instantiate, errors should result in evict which will destroy + * both inode and iopen glocks properly. */ + if (file) { +@@ -904,7 +904,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + gfs2_glock_dq_uninit(&gh); + gfs2_glock_put(io_gl); + gfs2_qa_put(dip); +- unlock_new_inode(inode); + return error; + + fail_gunlock4: +-- +2.53.0 + diff --git a/queue-6.18/gfs2-less-aggressive-low-memory-log-flushing.patch b/queue-6.18/gfs2-less-aggressive-low-memory-log-flushing.patch new file mode 100644 index 0000000000..ecd1a04893 --- /dev/null +++ b/queue-6.18/gfs2-less-aggressive-low-memory-log-flushing.patch @@ -0,0 +1,54 @@ +From d7a5ce48805de9213d29892e76390762f8d370c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 18:05:48 +0100 +Subject: gfs2: less aggressive low-memory log flushing + +From: Andreas Gruenbacher + +[ Upstream commit 7288185ce87ec70133b7bc3b694b0f74bf46a0ee ] + +It turns out that for some workloads, the fix in commit b74cd55aa9a9d +("gfs2: low-memory forced flush fixes") causes the number of forced log +flushes to increase to a degree that the overall filesystem performance +drops significantly. Address that by forcing a log flush only when +gfs2_writepages cannot make any progress rather than when it cannot make +"enough" progress. + +Fixes: b74cd55aa9a9d ("gfs2: low-memory forced flush fixes") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/aops.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c +index 47d74afd63ac9..eafe0488b10d4 100644 +--- a/fs/gfs2/aops.c ++++ b/fs/gfs2/aops.c +@@ -159,6 +159,7 @@ static int gfs2_writepages(struct address_space *mapping, + struct writeback_control *wbc) + { + struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping); ++ long initial_nr_to_write = wbc->nr_to_write; + struct iomap_writepage_ctx wpc = { + .inode = mapping->host, + .wbc = wbc, +@@ -167,13 +168,13 @@ static int gfs2_writepages(struct address_space *mapping, + int ret; + + /* +- * Even if we didn't write enough pages here, we might still be holding ++ * Even if we didn't write any pages here, we might still be holding + * dirty pages in the ail. We forcibly flush the ail because we don't + * want balance_dirty_pages() to loop indefinitely trying to write out + * pages held in the ail that it can't find. + */ + ret = iomap_writepages(&wpc); +- if (ret == 0 && wbc->nr_to_write > 0) ++ if (ret == 0 && wbc->nr_to_write == initial_nr_to_write) + set_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.18/gfs2-prevent-null-pointer-dereference-during-unmount.patch b/queue-6.18/gfs2-prevent-null-pointer-dereference-during-unmount.patch new file mode 100644 index 0000000000..ee3634aea1 --- /dev/null +++ b/queue-6.18/gfs2-prevent-null-pointer-dereference-during-unmount.patch @@ -0,0 +1,44 @@ +From 10fe148dbbf7e12a71f50251150c6bf735d9d858 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 12:14:30 +0200 +Subject: gfs2: prevent NULL pointer dereference during unmount + +From: Andreas Gruenbacher + +[ Upstream commit 74b4dbb946060a3233604d91859a9abd3708141d ] + +When flushing out outstanding glock work during an unmount, gfs2_log_flush() +can be called when sdp->sd_jdesc has already been deallocated and sdp->sd_jdesc +is NULL. Commit 35264909e9d1 ("gfs2: Fix NULL pointer dereference in +gfs2_log_flush") added a check for that to gfs2_log_flush() itself, but it +missed the sdp->sd_jdesc dereference in gfs2_log_release(). Fix that. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202604071139.HNJiCaAi-lkp@intel.com/ +Fixes: 35264909e9d1 ("gfs2: Fix NULL pointer dereference in gfs2_log_flush") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 592f69602e5aa..ecc5c59b87008 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -471,8 +471,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) + { + atomic_add(blks, &sdp->sd_log_blks_free); + trace_gfs2_log_blocks(sdp, blks); +- gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= +- sdp->sd_jdesc->jd_blocks); ++ gfs2_assert_withdraw(sdp, !sdp->sd_jdesc || ++ atomic_read(&sdp->sd_log_blks_free) <= ++ sdp->sd_jdesc->jd_blocks); + if (atomic_read(&sdp->sd_log_blks_needed)) + wake_up(&sdp->sd_log_waitq); + } +-- +2.53.0 + diff --git a/queue-6.18/gpu-nova-core-bitfield-fix-broken-default-implementa.patch b/queue-6.18/gpu-nova-core-bitfield-fix-broken-default-implementa.patch new file mode 100644 index 0000000000..2d20401eb3 --- /dev/null +++ b/queue-6.18/gpu-nova-core-bitfield-fix-broken-default-implementa.patch @@ -0,0 +1,43 @@ +From 34f71e10cb9e7bc37de17142e636290dffbcc4c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:42:28 +0900 +Subject: gpu: nova-core: bitfield: fix broken Default implementation + +From: Eliot Courtney + +[ Upstream commit de0aca13509bf47a2d49bc7a26d56079c758c95f ] + +The current implementation does not actually set the default values for +the fields in the bitfield. + +Fixes: 3fa145bef533 ("gpu: nova-core: register: generate correct `Default` implementation") +Signed-off-by: Eliot Courtney +Link: https://patch.msgid.link/20260401-fix-bitfield-v2-1-2fa68c98114a@nvidia.com +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/bitfield.rs | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitfield.rs +index fb60800898c55..1d4931c251bf4 100644 +--- a/drivers/gpu/nova-core/bitfield.rs ++++ b/drivers/gpu/nova-core/bitfield.rs +@@ -303,12 +303,11 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { + /// Returns a value for the bitfield where all fields are set to their default value. + impl ::core::default::Default for $name { + fn default() -> Self { +- #[allow(unused_mut)] +- let mut value = Self(Default::default()); ++ let value = Self(Default::default()); + + ::kernel::macros::paste!( + $( +- value.[](Default::default()); ++ let value = value.[](Default::default()); + )* + ); + +-- +2.53.0 + diff --git a/queue-6.18/gpu-nova-core-bitfield-move-bitfield-specific-code-f.patch b/queue-6.18/gpu-nova-core-bitfield-move-bitfield-specific-code-f.patch new file mode 100644 index 0000000000..f281b3b3cb --- /dev/null +++ b/queue-6.18/gpu-nova-core-bitfield-move-bitfield-specific-code-f.patch @@ -0,0 +1,701 @@ +From e6a9feb34fc2f63b64af49323a4b978f233d0869 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Oct 2025 11:13:21 -0400 +Subject: gpu: nova-core: bitfield: Move bitfield-specific code from register! + into new macro + +From: Joel Fernandes + +[ Upstream commit 71ea85be25b4f54a53ec03d5deaed52f5ee65da8 ] + +Move the bitfield-specific code from the register macro into a new macro +called bitfield. This will be used to define structs with bitfields, +similar to C language. + +Reviewed-by: Elle Rhumsaa +Reviewed-by: Alexandre Courbot +Reviewed-by: Edwin Peer +Signed-off-by: Joel Fernandes +Signed-off-by: Alexandre Courbot +Message-ID: <20251016151323.1201196-3-joelagnelf@nvidia.com> +Stable-dep-of: de0aca13509b ("gpu: nova-core: bitfield: fix broken Default implementation") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/bitfield.rs | 319 +++++++++++++++++++++++++++ + drivers/gpu/nova-core/nova_core.rs | 3 + + drivers/gpu/nova-core/regs/macros.rs | 259 +--------------------- + 3 files changed, 332 insertions(+), 249 deletions(-) + create mode 100644 drivers/gpu/nova-core/bitfield.rs + +diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitfield.rs +new file mode 100644 +index 0000000000000..fb60800898c55 +--- /dev/null ++++ b/drivers/gpu/nova-core/bitfield.rs +@@ -0,0 +1,319 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++//! Bitfield library for Rust structures ++//! ++//! Support for defining bitfields in Rust structures. Also used by the [`register!`] macro. ++ ++/// Defines a struct with accessors to access bits within an inner unsigned integer. ++/// ++/// # Syntax ++/// ++/// ```rust ++/// use nova_core::bitfield; ++/// ++/// #[derive(Debug, Clone, Copy, Default)] ++/// enum Mode { ++/// #[default] ++/// Low = 0, ++/// High = 1, ++/// Auto = 2, ++/// } ++/// ++/// impl TryFrom for Mode { ++/// type Error = u8; ++/// fn try_from(value: u8) -> Result { ++/// match value { ++/// 0 => Ok(Mode::Low), ++/// 1 => Ok(Mode::High), ++/// 2 => Ok(Mode::Auto), ++/// _ => Err(value), ++/// } ++/// } ++/// } ++/// ++/// impl From for u8 { ++/// fn from(mode: Mode) -> u8 { ++/// mode as u8 ++/// } ++/// } ++/// ++/// #[derive(Debug, Clone, Copy, Default)] ++/// enum State { ++/// #[default] ++/// Inactive = 0, ++/// Active = 1, ++/// } ++/// ++/// impl From for State { ++/// fn from(value: bool) -> Self { ++/// if value { State::Active } else { State::Inactive } ++/// } ++/// } ++/// ++/// impl From for bool { ++/// fn from(state: State) -> bool { ++/// match state { ++/// State::Inactive => false, ++/// State::Active => true, ++/// } ++/// } ++/// } ++/// ++/// bitfield! { ++/// struct ControlReg { ++/// 7:7 state as bool => State; ++/// 3:0 mode as u8 ?=> Mode; ++/// } ++/// } ++/// ``` ++/// ++/// This generates a struct with: ++/// - Field accessors: `mode()`, `state()`, etc. ++/// - Field setters: `set_mode()`, `set_state()`, etc. (supports chaining with builder pattern). ++/// - Debug and Default implementations. ++/// ++/// Fields are defined as follows: ++/// ++/// - `as ` simply returns the field value casted to , typically `u32`, `u16`, `u8` or ++/// `bool`. Note that `bool` fields must have a range of 1 bit. ++/// - `as => ` calls ``'s `From::<>` implementation and returns ++/// the result. ++/// - `as ?=> ` calls ``'s `TryFrom::<>` implementation ++/// and returns the result. This is useful with fields for which not all values are valid. ++macro_rules! bitfield { ++ // Main entry point - defines the bitfield struct with fields ++ (struct $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { ++ bitfield!(@core $name $(, $comment)? { $($fields)* }); ++ }; ++ ++ // All rules below are helpers. ++ ++ // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, ++ // `Default`, `BitOr`, and conversion to the value type) and field accessor methods. ++ (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { ++ $( ++ #[doc=$comment] ++ )? ++ #[repr(transparent)] ++ #[derive(Clone, Copy)] ++ pub(crate) struct $name(u32); ++ ++ impl ::core::ops::BitOr for $name { ++ type Output = Self; ++ ++ fn bitor(self, rhs: Self) -> Self::Output { ++ Self(self.0 | rhs.0) ++ } ++ } ++ ++ impl ::core::convert::From<$name> for u32 { ++ fn from(val: $name) -> u32 { ++ val.0 ++ } ++ } ++ ++ bitfield!(@fields_dispatcher $name { $($fields)* }); ++ }; ++ ++ // Captures the fields and passes them to all the implementers that require field information. ++ // ++ // Used to simplify the matching rules for implementers, so they don't need to match the entire ++ // complex fields rule even though they only make use of part of it. ++ (@fields_dispatcher $name:ident { ++ $($hi:tt:$lo:tt $field:ident as $type:tt ++ $(?=> $try_into_type:ty)? ++ $(=> $into_type:ty)? ++ $(, $comment:literal)? ++ ; ++ )* ++ } ++ ) => { ++ bitfield!(@field_accessors $name { ++ $( ++ $hi:$lo $field as $type ++ $(?=> $try_into_type)? ++ $(=> $into_type)? ++ $(, $comment)? ++ ; ++ )* ++ }); ++ bitfield!(@debug $name { $($field;)* }); ++ bitfield!(@default $name { $($field;)* }); ++ }; ++ ++ // Defines all the field getter/setter methods for `$name`. ++ ( ++ @field_accessors $name:ident { ++ $($hi:tt:$lo:tt $field:ident as $type:tt ++ $(?=> $try_into_type:ty)? ++ $(=> $into_type:ty)? ++ $(, $comment:literal)? ++ ; ++ )* ++ } ++ ) => { ++ $( ++ bitfield!(@check_field_bounds $hi:$lo $field as $type); ++ )* ++ ++ #[allow(dead_code)] ++ impl $name { ++ $( ++ bitfield!(@field_accessor $name $hi:$lo $field as $type ++ $(?=> $try_into_type)? ++ $(=> $into_type)? ++ $(, $comment)? ++ ; ++ ); ++ )* ++ } ++ }; ++ ++ // Boolean fields must have `$hi == $lo`. ++ (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => { ++ #[allow(clippy::eq_op)] ++ const _: () = { ++ ::kernel::build_assert!( ++ $hi == $lo, ++ concat!("boolean field `", stringify!($field), "` covers more than one bit") ++ ); ++ }; ++ }; ++ ++ // Non-boolean fields must have `$hi >= $lo`. ++ (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => { ++ #[allow(clippy::eq_op)] ++ const _: () = { ++ ::kernel::build_assert!( ++ $hi >= $lo, ++ concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB") ++ ); ++ }; ++ }; ++ ++ // Catches fields defined as `bool` and convert them into a boolean value. ++ ( ++ @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty ++ $(, $comment:literal)?; ++ ) => { ++ bitfield!( ++ @leaf_accessor $name $hi:$lo $field ++ { |f| <$into_type>::from(if f != 0 { true } else { false }) } ++ bool $into_type => $into_type $(, $comment)?; ++ ); ++ }; ++ ++ // Shortcut for fields defined as `bool` without the `=>` syntax. ++ ( ++ @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?; ++ ) => { ++ bitfield!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;); ++ }; ++ ++ // Catches the `?=>` syntax for non-boolean fields. ++ ( ++ @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty ++ $(, $comment:literal)?; ++ ) => { ++ bitfield!(@leaf_accessor $name $hi:$lo $field ++ { |f| <$try_into_type>::try_from(f as $type) } $type $try_into_type => ++ ::core::result::Result< ++ $try_into_type, ++ <$try_into_type as ::core::convert::TryFrom<$type>>::Error ++ > ++ $(, $comment)?;); ++ }; ++ ++ // Catches the `=>` syntax for non-boolean fields. ++ ( ++ @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty ++ $(, $comment:literal)?; ++ ) => { ++ bitfield!(@leaf_accessor $name $hi:$lo $field ++ { |f| <$into_type>::from(f as $type) } $type $into_type => $into_type $(, $comment)?;); ++ }; ++ ++ // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax. ++ ( ++ @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ++ $(, $comment:literal)?; ++ ) => { ++ bitfield!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;); ++ }; ++ ++ // Generates the accessor methods for a single field. ++ ( ++ @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident ++ { $process:expr } $prim_type:tt $to_type:ty => $res_type:ty $(, $comment:literal)?; ++ ) => { ++ ::kernel::macros::paste!( ++ const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive = $lo..=$hi; ++ const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); ++ const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); ++ ); ++ ++ $( ++ #[doc="Returns the value of this field:"] ++ #[doc=$comment] ++ )? ++ #[inline(always)] ++ pub(crate) fn $field(self) -> $res_type { ++ ::kernel::macros::paste!( ++ const MASK: u32 = $name::[<$field:upper _MASK>]; ++ const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; ++ ); ++ let field = ((self.0 & MASK) >> SHIFT); ++ ++ $process(field) ++ } ++ ++ ::kernel::macros::paste!( ++ $( ++ #[doc="Sets the value of this field:"] ++ #[doc=$comment] ++ )? ++ #[inline(always)] ++ pub(crate) fn [](mut self, value: $to_type) -> Self { ++ const MASK: u32 = $name::[<$field:upper _MASK>]; ++ const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; ++ let value = (u32::from($prim_type::from(value)) << SHIFT) & MASK; ++ self.0 = (self.0 & !MASK) | value; ++ ++ self ++ } ++ ); ++ }; ++ ++ // Generates the `Debug` implementation for `$name`. ++ (@debug $name:ident { $($field:ident;)* }) => { ++ impl ::kernel::fmt::Debug for $name { ++ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { ++ f.debug_struct(stringify!($name)) ++ .field("", &::kernel::prelude::fmt!("{:#x}", &self.0)) ++ $( ++ .field(stringify!($field), &self.$field()) ++ )* ++ .finish() ++ } ++ } ++ }; ++ ++ // Generates the `Default` implementation for `$name`. ++ (@default $name:ident { $($field:ident;)* }) => { ++ /// Returns a value for the bitfield where all fields are set to their default value. ++ impl ::core::default::Default for $name { ++ fn default() -> Self { ++ #[allow(unused_mut)] ++ let mut value = Self(Default::default()); ++ ++ ::kernel::macros::paste!( ++ $( ++ value.[](Default::default()); ++ )* ++ ); ++ ++ value ++ } ++ } ++ }; ++} +diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs +index fffcaee2249fe..112277c7921eb 100644 +--- a/drivers/gpu/nova-core/nova_core.rs ++++ b/drivers/gpu/nova-core/nova_core.rs +@@ -2,6 +2,9 @@ + + //! Nova Core GPU Driver + ++#[macro_use] ++mod bitfield; ++ + mod dma; + mod driver; + mod falcon; +diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs +index 1c54a4533822e..945d15a2c529d 100644 +--- a/drivers/gpu/nova-core/regs/macros.rs ++++ b/drivers/gpu/nova-core/regs/macros.rs +@@ -8,7 +8,8 @@ + //! + //! The `register!` macro in this module provides an intuitive and readable syntax for defining a + //! dedicated type for each register. Each such type comes with its own field accessors that can +-//! return an error if a field's value is invalid. ++//! return an error if a field's value is invalid. Please look at the [`bitfield`] macro for the ++//! complete syntax of fields definitions. + + /// Trait providing a base address to be added to the offset of a relative register to obtain + /// its actual offset. +@@ -54,15 +55,6 @@ pub(crate) trait RegisterBase { + /// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); + /// ``` + /// +-/// Fields are defined as follows: +-/// +-/// - `as ` simply returns the field value casted to , typically `u32`, `u16`, `u8` or +-/// `bool`. Note that `bool` fields must have a range of 1 bit. +-/// - `as => ` calls ``'s `From::<>` implementation and returns +-/// the result. +-/// - `as ?=> ` calls ``'s `TryFrom::<>` implementation +-/// and returns the result. This is useful with fields for which not all values are valid. +-/// + /// The documentation strings are optional. If present, they will be added to the type's + /// definition, or the field getter and setter methods they are attached to. + /// +@@ -284,25 +276,25 @@ pub(crate) trait RegisterBase { + macro_rules! register { + // Creates a register at a fixed offset of the MMIO space. + ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { +- register!(@core $name $(, $comment)? { $($fields)* } ); ++ bitfield!(struct $name $(, $comment)? { $($fields)* } ); + register!(@io_fixed $name @ $offset); + }; + + // Creates an alias register of fixed offset register `alias` with its own fields. + ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { +- register!(@core $name $(, $comment)? { $($fields)* } ); ++ bitfield!(struct $name $(, $comment)? { $($fields)* } ); + register!(@io_fixed $name @ $alias::OFFSET); + }; + + // Creates a register at a relative offset from a base address provider. + ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => { +- register!(@core $name $(, $comment)? { $($fields)* } ); ++ bitfield!(struct $name $(, $comment)? { $($fields)* } ); + register!(@io_relative $name @ $base [ $offset ]); + }; + + // Creates an alias register of relative offset register `alias` with its own fields. + ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => { +- register!(@core $name $(, $comment)? { $($fields)* } ); ++ bitfield!(struct $name $(, $comment)? { $($fields)* } ); + register!(@io_relative $name @ $base [ $alias::OFFSET ]); + }; + +@@ -313,7 +305,7 @@ macro_rules! register { + } + ) => { + static_assert!(::core::mem::size_of::() <= $stride); +- register!(@core $name $(, $comment)? { $($fields)* } ); ++ bitfield!(struct $name $(, $comment)? { $($fields)* } ); + register!(@io_array $name @ $offset [ $size ; $stride ]); + }; + +@@ -334,7 +326,7 @@ macro_rules! register { + $(, $comment:literal)? { $($fields:tt)* } + ) => { + static_assert!(::core::mem::size_of::() <= $stride); +- register!(@core $name $(, $comment)? { $($fields)* } ); ++ bitfield!(struct $name $(, $comment)? { $($fields)* } ); + register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]); + }; + +@@ -356,7 +348,7 @@ macro_rules! register { + } + ) => { + static_assert!($idx < $alias::SIZE); +- register!(@core $name $(, $comment)? { $($fields)* } ); ++ bitfield!(struct $name $(, $comment)? { $($fields)* } ); + register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] ); + }; + +@@ -365,241 +357,10 @@ macro_rules! register { + // to avoid it being interpreted in place of the relative register array alias rule. + ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => { + static_assert!($idx < $alias::SIZE); +- register!(@core $name $(, $comment)? { $($fields)* } ); ++ bitfield!(struct $name $(, $comment)? { $($fields)* } ); + register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE ); + }; + +- // All rules below are helpers. +- +- // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, +- // `Default`, `BitOr`, and conversion to the value type) and field accessor methods. +- (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { +- $( +- #[doc=$comment] +- )? +- #[repr(transparent)] +- #[derive(Clone, Copy)] +- pub(crate) struct $name(u32); +- +- impl ::core::ops::BitOr for $name { +- type Output = Self; +- +- fn bitor(self, rhs: Self) -> Self::Output { +- Self(self.0 | rhs.0) +- } +- } +- +- impl ::core::convert::From<$name> for u32 { +- fn from(reg: $name) -> u32 { +- reg.0 +- } +- } +- +- register!(@fields_dispatcher $name { $($fields)* }); +- }; +- +- // Captures the fields and passes them to all the implementers that require field information. +- // +- // Used to simplify the matching rules for implementers, so they don't need to match the entire +- // complex fields rule even though they only make use of part of it. +- (@fields_dispatcher $name:ident { +- $($hi:tt:$lo:tt $field:ident as $type:tt +- $(?=> $try_into_type:ty)? +- $(=> $into_type:ty)? +- $(, $comment:literal)? +- ; +- )* +- } +- ) => { +- register!(@field_accessors $name { +- $( +- $hi:$lo $field as $type +- $(?=> $try_into_type)? +- $(=> $into_type)? +- $(, $comment)? +- ; +- )* +- }); +- register!(@debug $name { $($field;)* }); +- register!(@default $name { $($field;)* }); +- }; +- +- // Defines all the field getter/methods methods for `$name`. +- ( +- @field_accessors $name:ident { +- $($hi:tt:$lo:tt $field:ident as $type:tt +- $(?=> $try_into_type:ty)? +- $(=> $into_type:ty)? +- $(, $comment:literal)? +- ; +- )* +- } +- ) => { +- $( +- register!(@check_field_bounds $hi:$lo $field as $type); +- )* +- +- #[allow(dead_code)] +- impl $name { +- $( +- register!(@field_accessor $name $hi:$lo $field as $type +- $(?=> $try_into_type)? +- $(=> $into_type)? +- $(, $comment)? +- ; +- ); +- )* +- } +- }; +- +- // Boolean fields must have `$hi == $lo`. +- (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => { +- #[allow(clippy::eq_op)] +- const _: () = { +- ::kernel::build_assert!( +- $hi == $lo, +- concat!("boolean field `", stringify!($field), "` covers more than one bit") +- ); +- }; +- }; +- +- // Non-boolean fields must have `$hi >= $lo`. +- (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => { +- #[allow(clippy::eq_op)] +- const _: () = { +- ::kernel::build_assert!( +- $hi >= $lo, +- concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB") +- ); +- }; +- }; +- +- // Catches fields defined as `bool` and convert them into a boolean value. +- ( +- @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty +- $(, $comment:literal)?; +- ) => { +- register!( +- @leaf_accessor $name $hi:$lo $field +- { |f| <$into_type>::from(if f != 0 { true } else { false }) } +- bool $into_type => $into_type $(, $comment)?; +- ); +- }; +- +- // Shortcut for fields defined as `bool` without the `=>` syntax. +- ( +- @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?; +- ) => { +- register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;); +- }; +- +- // Catches the `?=>` syntax for non-boolean fields. +- ( +- @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty +- $(, $comment:literal)?; +- ) => { +- register!(@leaf_accessor $name $hi:$lo $field +- { |f| <$try_into_type>::try_from(f as $type) } $type $try_into_type => +- ::core::result::Result< +- $try_into_type, +- <$try_into_type as ::core::convert::TryFrom<$type>>::Error +- > +- $(, $comment)?;); +- }; +- +- // Catches the `=>` syntax for non-boolean fields. +- ( +- @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty +- $(, $comment:literal)?; +- ) => { +- register!(@leaf_accessor $name $hi:$lo $field +- { |f| <$into_type>::from(f as $type) } $type $into_type => $into_type $(, $comment)?;); +- }; +- +- // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax. +- ( +- @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt +- $(, $comment:literal)?; +- ) => { +- register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;); +- }; +- +- // Generates the accessor methods for a single field. +- ( +- @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident +- { $process:expr } $prim_type:tt $to_type:ty => $res_type:ty $(, $comment:literal)?; +- ) => { +- ::kernel::macros::paste!( +- const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive = $lo..=$hi; +- const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); +- const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); +- ); +- +- $( +- #[doc="Returns the value of this field:"] +- #[doc=$comment] +- )? +- #[inline(always)] +- pub(crate) fn $field(self) -> $res_type { +- ::kernel::macros::paste!( +- const MASK: u32 = $name::[<$field:upper _MASK>]; +- const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; +- ); +- let field = ((self.0 & MASK) >> SHIFT); +- +- $process(field) +- } +- +- ::kernel::macros::paste!( +- $( +- #[doc="Sets the value of this field:"] +- #[doc=$comment] +- )? +- #[inline(always)] +- pub(crate) fn [](mut self, value: $to_type) -> Self { +- const MASK: u32 = $name::[<$field:upper _MASK>]; +- const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; +- let value = (u32::from($prim_type::from(value)) << SHIFT) & MASK; +- self.0 = (self.0 & !MASK) | value; +- +- self +- } +- ); +- }; +- +- // Generates the `Debug` implementation for `$name`. +- (@debug $name:ident { $($field:ident;)* }) => { +- impl ::kernel::fmt::Debug for $name { +- fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { +- f.debug_struct(stringify!($name)) +- .field("", &::kernel::prelude::fmt!("{:#x}", &self.0)) +- $( +- .field(stringify!($field), &self.$field()) +- )* +- .finish() +- } +- } +- }; +- +- // Generates the `Default` implementation for `$name`. +- (@default $name:ident { $($field:ident;)* }) => { +- /// Returns a value for the register where all fields are set to their default value. +- impl ::core::default::Default for $name { +- fn default() -> Self { +- #[allow(unused_mut)] +- let mut value = Self(Default::default()); +- +- ::kernel::macros::paste!( +- $( +- value.[](Default::default()); +- )* +- ); +- +- value +- } +- } +- }; +- + // Generates the IO accessors for a fixed offset register. + (@io_fixed $name:ident @ $offset:expr) => { + #[allow(dead_code)] +-- +2.53.0 + diff --git a/queue-6.18/gpu-nova-core-register-use-field-type-for-into-imple.patch b/queue-6.18/gpu-nova-core-register-use-field-type-for-into-imple.patch new file mode 100644 index 0000000000..ea828a7212 --- /dev/null +++ b/queue-6.18/gpu-nova-core-register-use-field-type-for-into-imple.patch @@ -0,0 +1,220 @@ +From 695d7fdb07241cfd8258c8fad52ec0c9f903910e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Oct 2025 11:13:20 -0400 +Subject: gpu: nova-core: register: use field type for Into implementation + +From: Alexandre Courbot + +[ Upstream commit 3f674dc4ef1b3783f9d8dae33b46bf50eaac7c79 ] + +The getter method of a field works with the field type, but its setter +expects the type of the register. This leads to an asymmetry in the +From/Into implementations required for a field with a dedicated type. +For instance, a field declared as + + pub struct ControlReg(u32) { + 3:0 mode as u8 ?=> Mode; + ... + } + +currently requires the following implementations: + + impl TryFrom for Mode { + ... + } + + impl From for u32 { + ... + } + +Change this so the `From` now needs to be implemented for `u8`, +i.e. the primitive type of the field. This is more consistent, and will +become a requirement once we start using the TryFrom/Into derive macros +to implement these automatically. + +Reported-by: Edwin Peer +Closes: https://lore.kernel.org/rust-for-linux/F3853912-2C1C-4F9B-89B0-3168689F35B3@nvidia.com/ +Reviewed-by: Joel Fernandes +Signed-off-by: Joel Fernandes +Signed-off-by: Alexandre Courbot +Message-ID: <20251016151323.1201196-2-joelagnelf@nvidia.com> +Stable-dep-of: de0aca13509b ("gpu: nova-core: bitfield: fix broken Default implementation") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/falcon.rs | 38 ++++++++++++++++++++-------- + drivers/gpu/nova-core/regs/macros.rs | 10 ++++---- + 2 files changed, 32 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs +index 37e6298195e49..3f505b8706011 100644 +--- a/drivers/gpu/nova-core/falcon.rs ++++ b/drivers/gpu/nova-core/falcon.rs +@@ -22,11 +22,11 @@ + pub(crate) mod sec2; + + // TODO[FPRI]: Replace with `ToPrimitive`. +-macro_rules! impl_from_enum_to_u32 { ++macro_rules! impl_from_enum_to_u8 { + ($enum_type:ty) => { +- impl From<$enum_type> for u32 { ++ impl From<$enum_type> for u8 { + fn from(value: $enum_type) -> Self { +- value as u32 ++ value as u8 + } + } + }; +@@ -46,7 +46,7 @@ pub(crate) enum FalconCoreRev { + Rev6 = 6, + Rev7 = 7, + } +-impl_from_enum_to_u32!(FalconCoreRev); ++impl_from_enum_to_u8!(FalconCoreRev); + + // TODO[FPRI]: replace with `FromPrimitive`. + impl TryFrom for FalconCoreRev { +@@ -81,7 +81,7 @@ pub(crate) enum FalconCoreRevSubversion { + Subversion2 = 2, + Subversion3 = 3, + } +-impl_from_enum_to_u32!(FalconCoreRevSubversion); ++impl_from_enum_to_u8!(FalconCoreRevSubversion); + + // TODO[FPRI]: replace with `FromPrimitive`. + impl TryFrom for FalconCoreRevSubversion { +@@ -125,7 +125,7 @@ pub(crate) enum FalconSecurityModel { + /// Also known as High-Secure, Privilege Level 3 or PL3. + Heavy = 3, + } +-impl_from_enum_to_u32!(FalconSecurityModel); ++impl_from_enum_to_u8!(FalconSecurityModel); + + // TODO[FPRI]: replace with `FromPrimitive`. + impl TryFrom for FalconSecurityModel { +@@ -157,7 +157,7 @@ pub(crate) enum FalconModSelAlgo { + #[default] + Rsa3k = 1, + } +-impl_from_enum_to_u32!(FalconModSelAlgo); ++impl_from_enum_to_u8!(FalconModSelAlgo); + + // TODO[FPRI]: replace with `FromPrimitive`. + impl TryFrom for FalconModSelAlgo { +@@ -179,7 +179,7 @@ pub(crate) enum DmaTrfCmdSize { + #[default] + Size256B = 0x6, + } +-impl_from_enum_to_u32!(DmaTrfCmdSize); ++impl_from_enum_to_u8!(DmaTrfCmdSize); + + // TODO[FPRI]: replace with `FromPrimitive`. + impl TryFrom for DmaTrfCmdSize { +@@ -202,7 +202,6 @@ pub(crate) enum PeregrineCoreSelect { + /// RISC-V core is active. + Riscv = 1, + } +-impl_from_enum_to_u32!(PeregrineCoreSelect); + + impl From for PeregrineCoreSelect { + fn from(value: bool) -> Self { +@@ -213,6 +212,15 @@ fn from(value: bool) -> Self { + } + } + ++impl From for bool { ++ fn from(value: PeregrineCoreSelect) -> Self { ++ match value { ++ PeregrineCoreSelect::Falcon => false, ++ PeregrineCoreSelect::Riscv => true, ++ } ++ } ++} ++ + /// Different types of memory present in a falcon core. + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub(crate) enum FalconMem { +@@ -236,7 +244,7 @@ pub(crate) enum FalconFbifTarget { + /// Non-coherent system memory (System DRAM). + NoncoherentSysmem = 2, + } +-impl_from_enum_to_u32!(FalconFbifTarget); ++impl_from_enum_to_u8!(FalconFbifTarget); + + // TODO[FPRI]: replace with `FromPrimitive`. + impl TryFrom for FalconFbifTarget { +@@ -263,7 +271,6 @@ pub(crate) enum FalconFbifMemType { + /// Physical memory addresses. + Physical = 1, + } +-impl_from_enum_to_u32!(FalconFbifMemType); + + /// Conversion from a single-bit register field. + impl From for FalconFbifMemType { +@@ -275,6 +282,15 @@ fn from(value: bool) -> Self { + } + } + ++impl From for bool { ++ fn from(value: FalconFbifMemType) -> Self { ++ match value { ++ FalconFbifMemType::Virtual => false, ++ FalconFbifMemType::Physical => true, ++ } ++ } ++} ++ + /// Type used to represent the `PFALCON` registers address base for a given falcon engine. + pub(crate) struct PFalconBase(()); + +diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs +index 8058e1696df97..1c54a4533822e 100644 +--- a/drivers/gpu/nova-core/regs/macros.rs ++++ b/drivers/gpu/nova-core/regs/macros.rs +@@ -482,7 +482,7 @@ impl $name { + register!( + @leaf_accessor $name $hi:$lo $field + { |f| <$into_type>::from(if f != 0 { true } else { false }) } +- $into_type => $into_type $(, $comment)?; ++ bool $into_type => $into_type $(, $comment)?; + ); + }; + +@@ -499,7 +499,7 @@ impl $name { + $(, $comment:literal)?; + ) => { + register!(@leaf_accessor $name $hi:$lo $field +- { |f| <$try_into_type>::try_from(f as $type) } $try_into_type => ++ { |f| <$try_into_type>::try_from(f as $type) } $type $try_into_type => + ::core::result::Result< + $try_into_type, + <$try_into_type as ::core::convert::TryFrom<$type>>::Error +@@ -513,7 +513,7 @@ impl $name { + $(, $comment:literal)?; + ) => { + register!(@leaf_accessor $name $hi:$lo $field +- { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;); ++ { |f| <$into_type>::from(f as $type) } $type $into_type => $into_type $(, $comment)?;); + }; + + // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax. +@@ -527,7 +527,7 @@ impl $name { + // Generates the accessor methods for a single field. + ( + @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident +- { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?; ++ { $process:expr } $prim_type:tt $to_type:ty => $res_type:ty $(, $comment:literal)?; + ) => { + ::kernel::macros::paste!( + const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive = $lo..=$hi; +@@ -559,7 +559,7 @@ pub(crate) fn $field(self) -> $res_type { + pub(crate) fn [](mut self, value: $to_type) -> Self { + const MASK: u32 = $name::[<$field:upper _MASK>]; + const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; +- let value = (u32::from(value) << SHIFT) & MASK; ++ let value = (u32::from($prim_type::from(value)) << SHIFT) & MASK; + self.0 = (self.0 & !MASK) | value; + + self +-- +2.53.0 + diff --git a/queue-6.18/hid-asus-do-not-abort-probe-when-not-necessary.patch b/queue-6.18/hid-asus-do-not-abort-probe-when-not-necessary.patch new file mode 100644 index 0000000000..f5f766f429 --- /dev/null +++ b/queue-6.18/hid-asus-do-not-abort-probe-when-not-necessary.patch @@ -0,0 +1,65 @@ +From 8a34fa12a374a6937b48fbf771253de447eb3706 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:09 +0100 +Subject: HID: asus: do not abort probe when not necessary + +From: Denis Benato + +[ Upstream commit 7253091766ded0fd81fe8d8be9b8b835495b06e8 ] + +In order to avoid dereferencing a NULL pointer asus_probe is aborted early +and control of some asus devices is transferred over hid-generic after +erroring out even when such NULL dereference cannot happen: only early +abort when the NULL dereference can happen. + +Also make the code shorter and more adherent to coding standards +removing square brackets enclosing single-line if-else statements. + +Fixes: d3af6ca9a8c3 ("HID: asus: fix UAF via HID_CLAIMED_INPUT validation") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index b9dfb38b0df4f..1746e8ea50ddf 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1223,22 +1223,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + * were freed during registration due to no usages being mapped, + * leaving drvdata->input pointing to freed memory. + */ +- if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { +- hid_err(hdev, "Asus input not registered\n"); +- ret = -ENOMEM; +- goto err_stop_hw; +- } +- +- if (drvdata->tp) { +- drvdata->input->name = "Asus TouchPad"; +- } else { +- drvdata->input->name = "Asus Keyboard"; +- } ++ if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) { ++ if (drvdata->tp) ++ drvdata->input->name = "Asus TouchPad"; ++ else ++ drvdata->input->name = "Asus Keyboard"; + +- if (drvdata->tp) { +- ret = asus_start_multitouch(hdev); +- if (ret) +- goto err_stop_hw; ++ if (drvdata->tp) { ++ ret = asus_start_multitouch(hdev); ++ if (ret) ++ goto err_stop_hw; ++ } + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch b/queue-6.18/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch new file mode 100644 index 0000000000..06e654c9c2 --- /dev/null +++ b/queue-6.18/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch @@ -0,0 +1,37 @@ +From 5f3907cdc09ebde4294862f631ebd093be7176fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:07 +0100 +Subject: HID: asus: make asus_resume adhere to linux kernel coding standards + +From: Denis Benato + +[ Upstream commit 51d33b42b8ae23da92819d28439fdd5636c45186 ] + +Linux kernel coding standars requires functions opening brackets to be in +a newline: move the opening bracket of asus_resume in its own line. + +Fixes: 546edbd26cff ("HID: hid-asus: reset the backlight brightness level on resume") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 5a068f6fd2ce5..b9dfb38b0df4f 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1095,7 +1095,8 @@ static int asus_start_multitouch(struct hid_device *hdev) + return 0; + } + +-static int __maybe_unused asus_resume(struct hid_device *hdev) { ++static int __maybe_unused asus_resume(struct hid_device *hdev) ++{ + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + int ret = 0; + +-- +2.53.0 + diff --git a/queue-6.18/hid-usbhid-fix-deadlock-in-hid_post_reset.patch b/queue-6.18/hid-usbhid-fix-deadlock-in-hid_post_reset.patch new file mode 100644 index 0000000000..3ed7fe09b6 --- /dev/null +++ b/queue-6.18/hid-usbhid-fix-deadlock-in-hid_post_reset.patch @@ -0,0 +1,42 @@ +From 2ee90205aff105252173a8438d4937f0b877f05e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:24:54 +0100 +Subject: HID: usbhid: fix deadlock in hid_post_reset() + +From: Oliver Neukum + +[ Upstream commit 8df2c1b47ee3cd50fd454f75c7a7e2ae8a6adf72 ] + +You can build a USB device that includes a HID component +and a storage or UAS component. The components can be reset +only together. That means that hid_pre_reset() and hid_post_reset() +are in the block IO error handling. Hence no memory allocation +used in them may do block IO because the IO can deadlock +on the mutex held while resetting a device and calling the +interface drivers. +Use GFP_NOIO for all allocations in them. + +Fixes: dc3c78e434690 ("HID: usbhid: Check HID report descriptor contents after device reset") +Signed-off-by: Oliver Neukum +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index 758eb21430cda..df3cc89dfb37f 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1552,7 +1552,7 @@ static int hid_post_reset(struct usb_interface *intf) + * configuration descriptors passed, we already know that + * the size of the HID report descriptor has not changed. + */ +- rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); ++ rdesc = kmalloc(hid->dev_rsize, GFP_NOIO); + if (!rdesc) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.18/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch b/queue-6.18/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch new file mode 100644 index 0000000000..0dd4fa6aeb --- /dev/null +++ b/queue-6.18/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch @@ -0,0 +1,46 @@ +From f82f0402bafe56305f02610ddbec7c4679a4b3ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:35:37 +0100 +Subject: hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns() + +From: Peter Zijlstra + +[ Upstream commit d19ff16c11db38f3ee179d72751fb9b340174330 ] + +Much like hrtimer_reprogram(), skip programming if the cpu_base is running +the hrtimer interrupt. + +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Juri Lelli +Reviewed-by: Thomas Gleixner +Link: https://patch.msgid.link/20260224163429.069535561@kernel.org +Stable-dep-of: f2e388a019e4 ("hrtimer: Reduce trace noise in hrtimer_start()") +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 21b6d93401480..2589cd1b2ec3a 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1261,6 +1261,14 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + } + + first = enqueue_hrtimer(timer, new_base, mode); ++ ++ /* ++ * If the hrtimer interrupt is running, then it will reevaluate the ++ * clock bases and reprogram the clock event device. ++ */ ++ if (new_base->cpu_base->in_hrtirq) ++ return false; ++ + if (!force_local) { + /* + * If the current CPU base is online, then the timer is +-- +2.53.0 + diff --git a/queue-6.18/hrtimer-reduce-trace-noise-in-hrtimer_start.patch b/queue-6.18/hrtimer-reduce-trace-noise-in-hrtimer_start.patch new file mode 100644 index 0000000000..7ffc47e840 --- /dev/null +++ b/queue-6.18/hrtimer-reduce-trace-noise-in-hrtimer_start.patch @@ -0,0 +1,216 @@ +From ccfa11f8afc347daa4ca29a4ae74efe49d79fb10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:36:59 +0100 +Subject: hrtimer: Reduce trace noise in hrtimer_start() + +From: Thomas Gleixner + +[ Upstream commit f2e388a019e4cf83a15883a3d1f1384298e9a6aa ] + +hrtimer_start() when invoked with an already armed timer traces like: + + -.. [032] d.h2. 5.002263: hrtimer_cancel: hrtimer= .... + -.. [032] d.h1. 5.002263: hrtimer_start: hrtimer= .... + +Which is incorrect as the timer doesn't get canceled. Just the expiry time +changes. The internal dequeue operation which is required for that is not +really interesting for trace analysis. But it makes it tedious to keep real +cancellations and the above case apart. + +Remove the cancel tracing in hrtimer_start() and add a 'was_armed' +indicator to the hrtimer start tracepoint, which clearly indicates what the +state of the hrtimer is when hrtimer_start() is invoked: + +-.. [032] d.h1. 6.200103: hrtimer_start: hrtimer= .... was_armed=0 + -.. [032] d.h1. 6.200558: hrtimer_start: hrtimer= .... was_armed=1 + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260224163430.208491877@kernel.org +Signed-off-by: Sasha Levin +--- + include/trace/events/timer.h | 11 +++++---- + kernel/time/hrtimer.c | 43 +++++++++++++++++------------------- + 2 files changed, 27 insertions(+), 27 deletions(-) + +diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h +index 1641ae3e6ca06..ab9a9386f7b65 100644 +--- a/include/trace/events/timer.h ++++ b/include/trace/events/timer.h +@@ -218,12 +218,13 @@ TRACE_EVENT(hrtimer_setup, + * hrtimer_start - called when the hrtimer is started + * @hrtimer: pointer to struct hrtimer + * @mode: the hrtimers mode ++ * @was_armed: Was armed when hrtimer_start*() was invoked + */ + TRACE_EVENT(hrtimer_start, + +- TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode), ++ TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode, bool was_armed), + +- TP_ARGS(hrtimer, mode), ++ TP_ARGS(hrtimer, mode, was_armed), + + TP_STRUCT__entry( + __field( void *, hrtimer ) +@@ -231,6 +232,7 @@ TRACE_EVENT(hrtimer_start, + __field( s64, expires ) + __field( s64, softexpires ) + __field( enum hrtimer_mode, mode ) ++ __field( bool, was_armed ) + ), + + TP_fast_assign( +@@ -239,13 +241,14 @@ TRACE_EVENT(hrtimer_start, + __entry->expires = hrtimer_get_expires(hrtimer); + __entry->softexpires = hrtimer_get_softexpires(hrtimer); + __entry->mode = mode; ++ __entry->was_armed = was_armed; + ), + + TP_printk("hrtimer=%p function=%ps expires=%llu softexpires=%llu " +- "mode=%s", __entry->hrtimer, __entry->function, ++ "mode=%s was_armed=%d", __entry->hrtimer, __entry->function, + (unsigned long long) __entry->expires, + (unsigned long long) __entry->softexpires, +- decode_hrtimer_mode(__entry->mode)) ++ decode_hrtimer_mode(__entry->mode), __entry->was_armed) + ); + + /** +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 2589cd1b2ec3a..1f602deeb09a4 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -471,17 +471,10 @@ static inline void debug_setup_on_stack(struct hrtimer *timer, clockid_t clockid + trace_hrtimer_setup(timer, clockid, mode); + } + +-static inline void debug_activate(struct hrtimer *timer, +- enum hrtimer_mode mode) ++static inline void debug_activate(struct hrtimer *timer, enum hrtimer_mode mode, bool was_armed) + { + debug_hrtimer_activate(timer, mode); +- trace_hrtimer_start(timer, mode); +-} +- +-static inline void debug_deactivate(struct hrtimer *timer) +-{ +- debug_hrtimer_deactivate(timer); +- trace_hrtimer_cancel(timer); ++ trace_hrtimer_start(timer, mode, was_armed); + } + + static struct hrtimer_clock_base * +@@ -1076,9 +1069,9 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); + * Returns true when the new timer is the leftmost timer in the tree. + */ + static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, +- enum hrtimer_mode mode) ++ enum hrtimer_mode mode, bool was_armed) + { +- debug_activate(timer, mode); ++ debug_activate(timer, mode, was_armed); + WARN_ON_ONCE(!base->cpu_base->online); + + base->cpu_base->active_bases |= 1 << base->index; +@@ -1138,6 +1131,8 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + if (state & HRTIMER_STATE_ENQUEUED) { + bool reprogram; + ++ debug_hrtimer_deactivate(timer); ++ + /* + * Remove the timer and force reprogramming when high + * resolution mode is active and the timer is on the current +@@ -1146,7 +1141,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + * reprogramming happens in the interrupt handler. This is a + * rare case and less expensive than a smp call. + */ +- debug_deactivate(timer); + reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); + + /* +@@ -1213,15 +1207,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + { + struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); + struct hrtimer_clock_base *new_base; +- bool force_local, first; ++ bool force_local, first, was_armed; + + /* + * If the timer is on the local cpu base and is the first expiring + * timer then this might end up reprogramming the hardware twice +- * (on removal and on enqueue). To avoid that by prevent the +- * reprogram on removal, keep the timer local to the current CPU +- * and enforce reprogramming after it is queued no matter whether +- * it is the new first expiring timer again or not. ++ * (on removal and on enqueue). To avoid that prevent the reprogram ++ * on removal, keep the timer local to the current CPU and enforce ++ * reprogramming after it is queued no matter whether it is the new ++ * first expiring timer again or not. + */ + force_local = base->cpu_base == this_cpu_base; + force_local &= base->cpu_base->next_timer == timer; +@@ -1243,7 +1237,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + * avoids programming the underlying clock event twice (once at + * removal and once after enqueue). + */ +- remove_hrtimer(timer, base, true, force_local); ++ was_armed = remove_hrtimer(timer, base, true, force_local); + + if (mode & HRTIMER_MODE_REL) + tim = ktime_add_safe(tim, __hrtimer_cb_get_time(base->clockid)); +@@ -1260,7 +1254,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + new_base = base; + } + +- first = enqueue_hrtimer(timer, new_base, mode); ++ first = enqueue_hrtimer(timer, new_base, mode, was_armed); + + /* + * If the hrtimer interrupt is running, then it will reevaluate the +@@ -1362,8 +1356,11 @@ int hrtimer_try_to_cancel(struct hrtimer *timer) + + base = lock_hrtimer_base(timer, &flags); + +- if (!hrtimer_callback_running(timer)) ++ if (!hrtimer_callback_running(timer)) { + ret = remove_hrtimer(timer, base, false, false); ++ if (ret) ++ trace_hrtimer_cancel(timer); ++ } + + unlock_hrtimer_base(timer, &flags); + +@@ -1799,7 +1796,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + */ + if (restart != HRTIMER_NORESTART && + !(timer->state & HRTIMER_STATE_ENQUEUED)) +- enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, false); + + /* + * Separate the ->running assignment from the ->state assignment. +@@ -2278,7 +2275,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + while ((node = timerqueue_getnext(&old_base->active))) { + timer = container_of(node, struct hrtimer, node); + BUG_ON(hrtimer_callback_running(timer)); +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + + /* + * Mark it as ENQUEUED not INACTIVE otherwise the +@@ -2295,7 +2292,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + * sort out already expired timers and reprogram the + * event device. + */ +- enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, true); + } + } + +-- +2.53.0 + diff --git a/queue-6.18/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch b/queue-6.18/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch new file mode 100644 index 0000000000..1d0bbf1617 --- /dev/null +++ b/queue-6.18/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch @@ -0,0 +1,47 @@ +From 6568e2c8cb7284abbfcb5823670faafd442295ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 11:46:18 +0100 +Subject: hte: tegra194: remove Kconfig dependency on Tegra194 SoC + +From: Francesco Lavra + +[ Upstream commit 92dfd92f747698352b256cd9ddd7497bb7ebe9c8 ] + +This driver runs also on other Tegra SoCs (e.g. Tegra234). +Replace Kconfig dependency on Tegra194 with more generic dependency on +Tegra, and amend the Kconfig help text to reflect the fact that this +driver works on SoCs other than Tegra194. + +Fixes: b003fb5c9df8 ("hte: Add Tegra234 provider") +Signed-off-by: Francesco Lavra +Acked-by: Dipen Patel +Signed-off-by: Dipen Patel +Signed-off-by: Sasha Levin +--- + drivers/hte/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/hte/Kconfig b/drivers/hte/Kconfig +index 641af722b555d..f57bad67deef0 100644 +--- a/drivers/hte/Kconfig ++++ b/drivers/hte/Kconfig +@@ -16,13 +16,13 @@ if HTE + + config HTE_TEGRA194 + tristate "NVIDIA Tegra194 HTE Support" +- depends on (ARCH_TEGRA_194_SOC || COMPILE_TEST) ++ depends on (ARCH_TEGRA || COMPILE_TEST) + depends on GPIOLIB + help + Enable this option for integrated hardware timestamping engine also + known as generic timestamping engine (GTE) support on NVIDIA Tegra194 +- systems-on-chip. The driver supports 352 LIC IRQs and 39 AON GPIOs +- lines for timestamping in realtime. ++ and later systems-on-chip. The driver supports 352 LIC IRQs and 39 ++ AON GPIOs lines for timestamping in realtime. + + config HTE_TEGRA194_TEST + tristate "NVIDIA Tegra194 HTE Test" +-- +2.53.0 + diff --git a/queue-6.18/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch b/queue-6.18/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch new file mode 100644 index 0000000000..4fb5d86c49 --- /dev/null +++ b/queue-6.18/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch @@ -0,0 +1,51 @@ +From cbc2112bfb30197f8d3c20b354a3a194ce141f6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 10:33:24 +0800 +Subject: hwmon: (aspeed-g6-pwm-tach): remove redundant driver remove callback + +From: Billy Tsai + +[ Upstream commit 46fef8583daa1bf78fda7eaa523c64d4440322ac ] + +Drops the remove callback as it only asserts reset and the probe already +registers a devres action (devm_add_action_or_reset()) to call +aspeed_pwm_tach_reset_assert(). + +Fixes: 7e1449cd15d1 ("hwmon: (aspeed-g6-pwm-tacho): Support for ASPEED g6 PWM/Fan tach") +Signed-off-by: Billy Tsai +Link: https://lore.kernel.org/r/20260309-pwm_fixes-v2-1-ca9768e70470@aspeedtech.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/aspeed-g6-pwm-tach.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c +index 4174b129d1fce..d1f7f43974824 100644 +--- a/drivers/hwmon/aspeed-g6-pwm-tach.c ++++ b/drivers/hwmon/aspeed-g6-pwm-tach.c +@@ -517,13 +517,6 @@ static int aspeed_pwm_tach_probe(struct platform_device *pdev) + return 0; + } + +-static void aspeed_pwm_tach_remove(struct platform_device *pdev) +-{ +- struct aspeed_pwm_tach_data *priv = platform_get_drvdata(pdev); +- +- reset_control_assert(priv->reset); +-} +- + static const struct of_device_id aspeed_pwm_tach_match[] = { + { + .compatible = "aspeed,ast2600-pwm-tach", +@@ -534,7 +527,6 @@ MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); + + static struct platform_driver aspeed_pwm_tach_driver = { + .probe = aspeed_pwm_tach_probe, +- .remove = aspeed_pwm_tach_remove, + .driver = { + .name = "aspeed-g6-pwm-tach", + .of_match_table = aspeed_pwm_tach_match, +-- +2.53.0 + diff --git a/queue-6.18/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch b/queue-6.18/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch new file mode 100644 index 0000000000..88d009792b --- /dev/null +++ b/queue-6.18/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch @@ -0,0 +1,68 @@ +From 0a843da2358304aa22ab48b448d70d589c98ea15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 18:32:30 +0800 +Subject: i3c: dw: Fix memory leak in dw_i3c_master_i3c_xfers() + +From: Felix Gu + +[ Upstream commit 256cc1f1305a8e5dcadf8ca208d04a3acadd26f1 ] + +The dw_i3c_master_i3c_xfers() function allocates memory for the xfer +structure using dw_i3c_master_alloc_xfer(). If pm_runtime_resume_and_get() +fails, the function returns without freeing the allocated xfer, resulting +in a memory leak. + +Since dw_i3c_master_free_xfer() is a thin wrapper around kfree(), use +the __free(kfree) cleanup attribute to handle the free automatically on +all exit paths. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260404-dw-i3c-2-v3-1-8f7d146549c1@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index c6cfcacb18106..585f320119741 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -6,6 +6,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -905,7 +906,6 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct dw_i3c_master *master = to_dw_i3c_master(m); + unsigned int nrxwords = 0, ntxwords = 0; +- struct dw_i3c_xfer *xfer; + int i, ret = 0; + + if (!i3c_nxfers) +@@ -925,7 +925,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, + nrxwords > master->caps.datafifodepth) + return -EOPNOTSUPP; + +- xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers); ++ struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, i3c_nxfers); + if (!xfer) + return -ENOMEM; + +@@ -976,7 +976,6 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev, + } + + ret = xfer->ret; +- dw_i3c_master_free_xfer(xfer); + + pm_runtime_put_autosuspend(master->dev); + return ret; +-- +2.53.0 + diff --git a/queue-6.18/i3c-master-adi-fix-error-propagation-for-cccs.patch b/queue-6.18/i3c-master-adi-fix-error-propagation-for-cccs.patch new file mode 100644 index 0000000000..1f1e2ec8f7 --- /dev/null +++ b/queue-6.18/i3c-master-adi-fix-error-propagation-for-cccs.patch @@ -0,0 +1,44 @@ +From 7c66aa6862cf34e383a78976f09b17aa6b518cf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:33 +0100 +Subject: i3c: master: adi: Fix error propagation for CCCs + +From: Jorge Marques + +[ Upstream commit 0b73da96b6eb6b9354654f96a9d423ab22cb222d ] + +adi_i3c_master_send_ccc_cmd() always returned 0, ignoring the transfer +result populated in the completion path. As a consequence, CCC command +errors were silently dropped, including the default -ETIMEDOUT and +later overwritten by adi_i3c_master_end_xfer_locked(). + +Fix this by returning xfer->ret so that callers correctly receive any +transfer error codes. + +Fixes: a79ac2cdc91d ("i3c: master: Add driver for Analog Devices I3C Controller IP") +Reviewed-by: Adrian Hunter +Reviewed-by: Frank Li +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-5-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/adi-i3c-master.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c +index 82ac0b3d057ab..d329faf4b3f96 100644 +--- a/drivers/i3c/master/adi-i3c-master.c ++++ b/drivers/i3c/master/adi-i3c-master.c +@@ -362,7 +362,7 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, + + cmd->err = adi_i3c_cmd_get_err(&xfer->cmds[0]); + +- return 0; ++ return xfer->ret; + } + + static int adi_i3c_master_priv_xfers(struct i3c_dev_desc *dev, +-- +2.53.0 + diff --git a/queue-6.18/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch b/queue-6.18/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch new file mode 100644 index 0000000000..75fc317137 --- /dev/null +++ b/queue-6.18/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch @@ -0,0 +1,69 @@ +From 5667d3cd0958257a41bdda958fd05c828ef4f46b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 22:18:02 +0800 +Subject: i3c: master: dw-i3c: Fix missing reset assertion in remove() callback + +From: Felix Gu + +[ Upstream commit bef1eef667186cedb0bc6d152464acb3c97d5f72 ] + +The reset line acquired during probe is currently left deasserted when +the driver is unbound. + +Switch to devm_reset_control_get_optional_exclusive_deasserted() to +ensure the reset is automatically re-asserted by the devres core when +the driver is removed. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Reviewed-by: Philipp Zabel +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260320-dw-i3c-v3-1-477040c2e3f5@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index 825eb2d20e9eb..c6cfcacb18106 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1554,13 +1554,11 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + if (IS_ERR(master->pclk)) + return PTR_ERR(master->pclk); + +- master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, +- "core_rst"); ++ master->core_rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, ++ "core_rst"); + if (IS_ERR(master->core_rst)) + return PTR_ERR(master->core_rst); + +- reset_control_deassert(master->core_rst); +- + spin_lock_init(&master->xferqueue.lock); + INIT_LIST_HEAD(&master->xferqueue.list); + +@@ -1572,7 +1570,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + dw_i3c_master_irq_handler, 0, + dev_name(&pdev->dev), master); + if (ret) +- goto err_assert_rst; ++ return ret; + + platform_set_drvdata(pdev, master); + +@@ -1610,9 +1608,6 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + +-err_assert_rst: +- reset_control_assert(master->core_rst); +- + return ret; + } + EXPORT_SYMBOL_GPL(dw_i3c_common_probe); +-- +2.53.0 + diff --git a/queue-6.18/i3c-master-fix-error-codes-at-send_ccc_cmd.patch b/queue-6.18/i3c-master-fix-error-codes-at-send_ccc_cmd.patch new file mode 100644 index 0000000000..f9c6dd05cb --- /dev/null +++ b/queue-6.18/i3c-master-fix-error-codes-at-send_ccc_cmd.patch @@ -0,0 +1,126 @@ +From c36af1862b17381fccd957f594bc526ced1570c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:32 +0100 +Subject: i3c: master: Fix error codes at send_ccc_cmd + +From: Jorge Marques + +[ Upstream commit ef8b5229348f0719aca557c4ca5530630ae4d134 ] + +i3c_master_send_ccc_cmd_locked() would propagate cmd->err (positive, +Mx codes) to the ret variable, cascading down multiple methods until +reaching methods that explicitly stated they would return 0 on success +or negative error code. For example, the call chain: + + i3c_device_enable_ibi <- i3c_dev_enable_ibi_locked <- + master->ops.enable_ibi <- i3c_master_enec_locked <- + i3c_master_enec_disec_locked <- i3c_master_send_ccc_cmd_locked + +Fix this by returning the ret value, callers can still read the cmd->err +value if ret is negative. + +All corner cases where the Mx codes do need to be handled individually, +are resolved in previous commits. Those corner cases are all scenarios +when I3C_ERROR_M2 is expected and acceptable. +The prerequisite patches for the fix are: + + i3c: master: Move rstdaa error suppression + i3c: master: Move entdaa error suppression + i3c: master: Move bus_init error suppression + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-iio/aYXvT5FW0hXQwhm_@stanley.mountain/ +Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-4-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 32 +++++++++++++------------------- + 1 file changed, 13 insertions(+), 19 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 425e36b36009b..4ecbabcec48b4 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -826,11 +826,17 @@ static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id, + cmd->err = I3C_ERROR_UNKNOWN; + } + ++/** ++ * i3c_master_send_ccc_cmd_locked() - send a CCC (Common Command Codes) ++ * @master: master used to send frames on the bus ++ * @cmd: command to send ++ * ++ * Return: 0 in case of success, or a negative error code otherwise. ++ * I3C Mx error codes are stored in cmd->err. ++ */ + static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd) + { +- int ret; +- + if (!cmd || !master) + return -EINVAL; + +@@ -848,15 +854,7 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + !master->ops->supports_ccc_cmd(master, cmd)) + return -EOPNOTSUPP; + +- ret = master->ops->send_ccc_cmd(master, cmd); +- if (ret) { +- if (cmd->err != I3C_ERROR_UNKNOWN) +- return cmd->err; +- +- return ret; +- } +- +- return 0; ++ return master->ops->send_ccc_cmd(master, cmd); + } + + static struct i2c_dev_desc * +@@ -960,8 +958,7 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_entdaa_locked(struct i3c_master_controller *master) + { +@@ -1013,8 +1010,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1034,8 +1030,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1060,8 +1055,7 @@ EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_defslvs_locked(struct i3c_master_controller *master) + { +-- +2.53.0 + diff --git a/queue-6.18/i3c-master-renesas-fix-memory-leak-in-renesas_i3c_i3.patch b/queue-6.18/i3c-master-renesas-fix-memory-leak-in-renesas_i3c_i3.patch new file mode 100644 index 0000000000..d7d2e0adee --- /dev/null +++ b/queue-6.18/i3c-master-renesas-fix-memory-leak-in-renesas_i3c_i3.patch @@ -0,0 +1,56 @@ +From 9177a8aa35298c4f590239d1d0ca4f2be8b480ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 20:43:16 +0800 +Subject: i3c: master: renesas: Fix memory leak in renesas_i3c_i3c_xfers() + +From: Felix Gu + +[ Upstream commit d7665c3b4f575251e449e2656879392346ca612b ] + +The xfer structure allocated by renesas_i3c_alloc_xfer() was never freed +in the renesas_i3c_i3c_xfers() function. Use the __free(kfree) cleanup +attribute to automatically free the memory when the variable goes out of +scope. + +Fixes: d028219a9f14 ("i3c: master: Add basic driver for the Renesas I3C controller") +Tested-by: Tommaso Merciai +Reviewed-by: Tommaso Merciai +Reviewed-by: Frank Li +Signed-off-by: Felix Gu +Link: https://patch.msgid.link/20260406-renesas-v3-1-4b724d7708f4@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/renesas-i3c.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c +index 275f7b9242886..5b1bf5a0266cc 100644 +--- a/drivers/i3c/master/renesas-i3c.c ++++ b/drivers/i3c/master/renesas-i3c.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -800,13 +801,12 @@ static int renesas_i3c_priv_xfers(struct i3c_dev_desc *dev, struct i3c_priv_xfer + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct renesas_i3c *i3c = to_renesas_i3c(m); + struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); +- struct renesas_i3c_xfer *xfer; + int i; + + /* Enable I3C bus. */ + renesas_i3c_bus_enable(m, true); + +- xfer = renesas_i3c_alloc_xfer(i3c, 1); ++ struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1); + if (!xfer) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.18/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch b/queue-6.18/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch new file mode 100644 index 0000000000..941f1264a5 --- /dev/null +++ b/queue-6.18/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch @@ -0,0 +1,56 @@ +From 8d730fff0bb06c75cdc9f2631b811f18f09afed8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:53:23 +0800 +Subject: i3c: mipi-i3c-hci: fix IBI payload length calculation for final + status + +From: Billy Tsai + +[ Upstream commit d35a6db887eeae7c57b719521e39d64f929c6dc3 ] + +In DMA mode, the IBI status descriptor encodes the payload using +CHUNKS (number of chunks) and DATA_LENGTH (valid bytes in the last +chunk). All preceding chunks are implicitly full-sized. + +The current code accumulates full chunk sizes for non-final status +descriptors, but for the final status descriptor it only adds +DATA_LENGTH. This ignores the contribution of the preceding full +chunks described by the same final status entry. + +As a result, the computed IBI payload length is truncated whenever +the final status spans multiple chunks. For example, with a chunk +size of 4 bytes, CHUNKS=2 and DATA_LENGTH=1 should result in a total +payload size of 5 bytes, but the current code reports only 1 byte. + +Fix the calculation by adding the size of (CHUNKS - 1) full chunks +plus DATA_LENGTH for the last chunk. + +Fixes: 9ad9a52cce28 ("i3c/master: introduce the mipi-i3c-hci driver") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260407-i3c-hci-dma-v2-1-a583187b9d22@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index fe8894f6fe607..42ee94767be3d 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -683,7 +683,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh) + if (!(ibi_status & IBI_LAST_STATUS)) { + ibi_size += chunks * rh->ibi_chunk_sz; + } else { +- ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ if (chunks) { ++ ibi_size += (chunks - 1) * rh->ibi_chunk_sz; ++ ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ } + last_ptr = ptr; + break; + } +-- +2.53.0 + diff --git a/queue-6.18/i40e-don-t-advertise-iff_supp_nofcs.patch b/queue-6.18/i40e-don-t-advertise-iff_supp_nofcs.patch new file mode 100644 index 0000000000..1ee9ddddfe --- /dev/null +++ b/queue-6.18/i40e-don-t-advertise-iff_supp_nofcs.patch @@ -0,0 +1,53 @@ +From 3ac7aaaf5930ae653730ff5b61ad8600b4ff06e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:33 -0700 +Subject: i40e: don't advertise IFF_SUPP_NOFCS + +From: Kohei Enju + +[ Upstream commit a24162f18825684ad04e3a5d0531f8a50d679347 ] + +i40e advertises IFF_SUPP_NOFCS, allowing users to use the SO_NOFCS +socket option. However, this option is silently ignored, as the driver +does not check skb->no_fcs, and always enables FCS insertion offload. + +Fix this by removing the advertisement of IFF_SUPP_NOFCS. + +This behavior can be reproduced with a simple AF_PACKET socket: + + import socket + s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) + s.setsockopt(socket.SOL_SOCKET, 43, 1) # SO_NOFCS + s.bind(("eth0", 0)) + s.send(b'\xff' * 64) + +Previously, send() succeeds but the driver ignores SO_NOFCS. +With this change, send() fails with -EPROTONOSUPPORT, as expected. + +Fixes: 41c445ff0f48 ("i40e: main driver core") +Signed-off-by: Kohei Enju +Reviewed-by: Aleksandr Loktionov +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-9-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index 598739220dfb9..9f19370f1c87a 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -13784,7 +13784,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) + netdev->neigh_priv_len = sizeof(u32) * 4; + + netdev->priv_flags |= IFF_UNICAST_FLT; +- netdev->priv_flags |= IFF_SUPP_NOFCS; + /* Setup netdev TC information */ + i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); + +-- +2.53.0 + diff --git a/queue-6.18/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch b/queue-6.18/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch new file mode 100644 index 0000000000..5089a4fbd6 --- /dev/null +++ b/queue-6.18/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch @@ -0,0 +1,58 @@ +From 59a4332ef878645e265e0e43f560e3506303a08f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:16 -0700 +Subject: iavf: add VIRTCHNL_OP_ADD_VLAN to success completion handler + +From: Petr Oros + +[ Upstream commit 34d33313b52eeac3a97ad2e3176d523ec70d9283 ] + +The V1 ADD_VLAN opcode had no success handler; filters sent via V1 +stayed in ADDING state permanently. Add a fallthrough case so V1 +filters also transition ADDING -> ACTIVE on PF confirmation. + +Critically, add an `if (v_retval) break` guard: the error switch in +iavf_virtchnl_completion() does NOT return after handling errors, +it falls through to the success switch. Without this guard, a +PF-rejected ADD would incorrectly mark ADDING filters as ACTIVE, +creating a driver/HW mismatch where the driver believes the filter +is installed but the PF never accepted it. + +For V2, this is harmless: iavf_vlan_add_reject() in the error +block already kfree'd all ADDING filters, so the success handler +finds nothing to transition. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-4-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 9132f16d853e5..f1a01b8e2235c 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -2872,9 +2872,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->adv_rss_lock); + } + break; ++ case VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN_V2: { + struct iavf_vlan_filter *f; + ++ if (v_retval) ++ break; ++ + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_ADDING) +-- +2.53.0 + diff --git a/queue-6.18/iavf-fix-wrong-vlan-mask-for-legacy-rx-descriptors-l.patch b/queue-6.18/iavf-fix-wrong-vlan-mask-for-legacy-rx-descriptors-l.patch new file mode 100644 index 0000000000..b00f5aa7d0 --- /dev/null +++ b/queue-6.18/iavf-fix-wrong-vlan-mask-for-legacy-rx-descriptors-l.patch @@ -0,0 +1,86 @@ +From a9fde982b0c96020145bf6cacb80c317f2d35afc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:34 -0700 +Subject: iavf: fix wrong VLAN mask for legacy Rx descriptors L2TAG2 + +From: Petr Oros + +[ Upstream commit 496d9f91062fa07956702e0f234c5203f03a974d ] + +The IAVF_RXD_LEGACY_L2TAG2_M mask was incorrectly defined as +GENMASK_ULL(63, 32), extracting 32 bits from qw2 instead of the +16-bit VLAN tag. In the legacy Rx descriptor layout, the 2nd L2TAG2 +(VLAN tag) occupies bits 63:48 of qw2, not 63:32. + +The oversized mask causes FIELD_GET to return a 32-bit value where the +actual VLAN tag sits in bits 31:16. When this value is passed to +iavf_receive_skb() as a u16 parameter, it gets truncated to the lower +16 bits (which contain the 1st L2TAG2, typically zero). As a result, +__vlan_hwaccel_put_tag() is never called and software VLAN interfaces +on VFs receive no traffic. + +This affects VFs behind ice PF (VIRTCHNL VLAN v2) when the PF +advertises VLAN stripping into L2TAG2_2 and legacy descriptors are +used. + +The flex descriptor path already uses the correct mask +(IAVF_RXD_FLEX_L2TAG2_2_M = GENMASK_ULL(63, 48)). + +Reproducer: + 1. Create 2 VFs on ice PF (echo 2 > sriov_numvfs) + 2. Disable spoofchk on both VFs + 3. Move each VF into a separate network namespace + 4. On each VF: create VLAN interface (e.g. vlan 198), assign IP, + bring up + 5. Set rx-vlan-offload OFF on both VFs + 6. Ping between VLAN interfaces -> expect PASS + (VLAN tag stays in packet data, kernel matches in-band) + 7. Set rx-vlan-offload ON on both VFs + 8. Ping between VLAN interfaces -> expect FAIL if bug present + (HW strips VLAN tag into descriptor L2TAG2 field, wrong mask + extracts bits 47:32 instead of 63:48, truncated to u16 -> zero, + __vlan_hwaccel_put_tag() never called, packet delivered to parent + interface, not VLAN interface) + +The reproducer requires legacy Rx descriptors. On modern ice + iavf +with full PTP support, flex descriptors are always negotiated and the +buggy legacy path is never reached. Flex descriptors require all of: + - CONFIG_PTP_1588_CLOCK enabled + - VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC granted by PF + - PTP capabilities negotiated (VIRTCHNL_VF_CAP_PTP) + - VIRTCHNL_1588_PTP_CAP_RX_TSTAMP supported + - VIRTCHNL_RXDID_2_FLEX_SQ_NIC present in DDP profile + +If any condition is not met, iavf_select_rx_desc_format() falls back +to legacy descriptors (RXDID=1) and the wrong L2TAG2 mask is hit. + +Fixes: 2dc8e7c36d80 ("iavf: refactor iavf_clean_rx_irq to support legacy and flex descriptors") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Paul Menzel +Reviewed-by: Jacob Keller +Tested-by: Rafal Romanowski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-10-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf_type.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf_type.h b/drivers/net/ethernet/intel/iavf/iavf_type.h +index 1d8cf29cb65ac..5bb1de1cfd33b 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_type.h ++++ b/drivers/net/ethernet/intel/iavf/iavf_type.h +@@ -277,7 +277,7 @@ struct iavf_rx_desc { + /* L2 Tag 2 Presence */ + #define IAVF_RXD_LEGACY_L2TAG2P_M BIT(0) + /* Stripped S-TAG VLAN from the receive packet */ +-#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 32) ++#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 48) + /* Stripped S-TAG VLAN from the receive packet */ + #define IAVF_RXD_FLEX_L2TAG2_2_M GENMASK_ULL(63, 48) + /* The packet is a UDP tunneled packet */ +-- +2.53.0 + diff --git a/queue-6.18/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch b/queue-6.18/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch new file mode 100644 index 0000000000..7fcb1054db --- /dev/null +++ b/queue-6.18/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch @@ -0,0 +1,87 @@ +From b1bb1ab569029fde00b096446d7ee883cbb923f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:13 -0700 +Subject: iavf: rename IAVF_VLAN_IS_NEW to IAVF_VLAN_ADDING + +From: Petr Oros + +[ Upstream commit 70d62b669f1f9080a25278fc90b64309f4ae8959 ] + +Rename the IAVF_VLAN_IS_NEW state to IAVF_VLAN_ADDING to better +describe what the state represents: an ADD request has been sent to +the PF and is waiting for a response. + +This is a pure rename with no behavioral change, preparing for a +cleanup of the VLAN filter state machine. + +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-1-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Stable-dep-of: f2ce65b9b917 ("iavf: stop removing VLAN filters from PF on interface down") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 2 +- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index e9fb0a0919e37..47a862ca5e2c3 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -158,7 +158,7 @@ struct iavf_vlan { + enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ +- IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ ++ IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ + IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ + IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 291b21230b65f..9dab61f198c0d 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) { ++ if (f->state == IAVF_VLAN_ADDING) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +@@ -811,7 +811,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + if (f->state == IAVF_VLAN_ADD) { + vvfl->vlan_id[i] = f->vlan.vid; + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + if (i == count) + break; + } +@@ -872,7 +872,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + vlan->tpid = f->vlan.tpid; + + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + } + } + +@@ -2906,7 +2906,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) ++ if (f->state == IAVF_VLAN_ADDING) + f->state = IAVF_VLAN_ACTIVE; + } + spin_unlock_bh(&adapter->mac_vlan_list_lock); +-- +2.53.0 + diff --git a/queue-6.18/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch b/queue-6.18/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch new file mode 100644 index 0000000000..2d15f95e0f --- /dev/null +++ b/queue-6.18/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch @@ -0,0 +1,233 @@ +From 861d1547a390d63a30b799d75f1e70b451ae8947 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:14 -0700 +Subject: iavf: stop removing VLAN filters from PF on interface down + +From: Petr Oros + +[ Upstream commit f2ce65b9b917474a1a6ce68d357e15fac2aca0f2 ] + +When a VF goes down, the driver currently sends DEL_VLAN to the PF for +every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then +re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING -> +ACTIVE). This round-trip is unnecessary because: + + 1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES, + which already prevents all RX/TX traffic regardless of VLAN filter + state. + + 2. The VLAN filters remaining in PF HW while the VF is down is + harmless - packets matching those filters have nowhere to go with + queues disabled. + + 3. The DEL+ADD cycle during down/up creates race windows where the + VLAN filter list is incomplete. With spoofcheck enabled, the PF + enables TX VLAN filtering on the first non-zero VLAN add, blocking + traffic for any VLANs not yet re-added. + +Remove the entire DISABLE/INACTIVE state machinery: + - Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values + - Remove iavf_restore_filters() and its call from iavf_open() + - Remove VLAN filter handling from iavf_clear_mac_vlan_filters(), + rename it to iavf_clear_mac_filters() + - Remove DEL_VLAN_FILTER scheduling from iavf_down() + - Remove all DISABLE/INACTIVE handling from iavf_del_vlans() + +VLAN filters now stay ACTIVE across down/up cycles. Only explicit +user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN +filter deletion/re-addition. + +Fixes: ed1f5b58ea01 ("i40evf: remove VLAN filters on close") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-2-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 6 +-- + drivers/net/ethernet/intel/iavf/iavf_main.c | 39 ++----------------- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 33 +++------------- + 3 files changed, 12 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 47a862ca5e2c3..5765715914d6b 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -159,10 +159,8 @@ enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ +- IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ +- IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ +- IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +- IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ ++ IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ ++ IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index 0a72d419782e5..a12ae6446c06c 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -801,27 +801,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +-/** +- * iavf_restore_filters +- * @adapter: board private structure +- * +- * Restore existing non MAC filters when VF netdev comes back up +- **/ +-static void iavf_restore_filters(struct iavf_adapter *adapter) +-{ +- struct iavf_vlan_filter *f; +- +- /* re-add all VLAN filters */ +- spin_lock_bh(&adapter->mac_vlan_list_lock); +- +- list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_INACTIVE) +- f->state = IAVF_VLAN_ADD; +- } +- +- spin_unlock_bh(&adapter->mac_vlan_list_lock); +- adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; +-} + + /** + * iavf_get_num_vlans_added - get number of VLANs added +@@ -1240,13 +1219,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) + } + + /** +- * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF +- * yet and mark other to be removed. ++ * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark ++ * others to be removed. + * @adapter: board private structure + **/ +-static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) ++static void iavf_clear_mac_filters(struct iavf_adapter *adapter) + { +- struct iavf_vlan_filter *vlf, *vlftmp; + struct iavf_mac_filter *f, *ftmp; + + spin_lock_bh(&adapter->mac_vlan_list_lock); +@@ -1265,11 +1243,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) + } + } + +- /* disable all VLAN filters */ +- list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, +- list) +- vlf->state = IAVF_VLAN_DISABLE; +- + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +@@ -1365,7 +1338,7 @@ void iavf_down(struct iavf_adapter *adapter) + iavf_napi_disable_all(adapter); + iavf_irq_disable(adapter); + +- iavf_clear_mac_vlan_filters(adapter); ++ iavf_clear_mac_filters(adapter); + iavf_clear_cloud_filters(adapter); + iavf_clear_fdir_filters(adapter); + iavf_clear_adv_rss_conf(adapter); +@@ -1382,8 +1355,6 @@ void iavf_down(struct iavf_adapter *adapter) + */ + if (!list_empty(&adapter->mac_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; +- if (!list_empty(&adapter->vlan_filter_list)) +- adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; + if (!list_empty(&adapter->cloud_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; + if (!list_empty(&adapter->fdir_list_head)) +@@ -4492,8 +4463,6 @@ static int iavf_open(struct net_device *netdev) + iavf_add_filter(adapter, adapter->hw.mac.addr); + spin_unlock_bh(&adapter->mac_vlan_list_lock); + +- /* Restore filters that were removed with IFF_DOWN */ +- iavf_restore_filters(adapter); + iavf_restore_fdir_filters(adapter); + + iavf_configure(adapter); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 9dab61f198c0d..8a856ec5ef480 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -909,22 +909,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + spin_lock_bh(&adapter->mac_vlan_list_lock); + + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- /* since VLAN capabilities are not allowed, we dont want to send +- * a VLAN delete request because it will most likely fail and +- * create unnecessary errors/noise, so just free the VLAN +- * filters marked for removal to enable bailing out before +- * sending a virtchnl message +- */ + if (f->state == IAVF_VLAN_REMOVE && + !VLAN_FILTERING_ALLOWED(adapter)) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else if (f->state == IAVF_VLAN_DISABLE && +- !VLAN_FILTERING_ALLOWED(adapter)) { +- f->state = IAVF_VLAN_INACTIVE; +- } else if (f->state == IAVF_VLAN_REMOVE || +- f->state == IAVF_VLAN_DISABLE) { ++ } else if (f->state == IAVF_VLAN_REMOVE) { + count++; + } + } +@@ -956,13 +946,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE) { +- vvfl->vlan_id[i] = f->vlan.vid; +- f->state = IAVF_VLAN_INACTIVE; +- i++; +- if (i == count) +- break; +- } else if (f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; + list_del(&f->list); + kfree(f); +@@ -1003,8 +987,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE || +- f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; + struct virtchnl_vlan *vlan; +@@ -1018,13 +1001,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- if (f->state == IAVF_VLAN_DISABLE) { +- f->state = IAVF_VLAN_INACTIVE; +- } else { +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; +- } ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; + i++; + if (i == count) + break; +-- +2.53.0 + diff --git a/queue-6.18/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch b/queue-6.18/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch new file mode 100644 index 0000000000..0d36e48ae0 --- /dev/null +++ b/queue-6.18/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch @@ -0,0 +1,189 @@ +From 71093fafd99459eb6eb64831021828ead834e132 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:15 -0700 +Subject: iavf: wait for PF confirmation before removing VLAN filters + +From: Petr Oros + +[ Upstream commit bbcbe4ed70dea948849549af7edf44bd42bbd695 ] + +The VLAN filter DELETE path was asymmetric with the ADD path: ADD +waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE +immediately frees the filter struct after sending the DEL message +without waiting for the PF response. + +This is problematic because: + - If the PF rejects the DEL, the filter remains in HW but the driver + has already freed the tracking structure, losing sync. + - Race conditions between DEL pending and other operations + (add, reset) cannot be properly resolved if the filter struct + is already gone. + +Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric: + + REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree + -> PF rejects -> ACTIVE + +In iavf_del_vlans(), transition filters from REMOVE to REMOVING +instead of immediately freeing them. The new DEL completion handler +in iavf_virtchnl_completion() frees filters on success or reverts +them to ACTIVE on error. + +Update iavf_add_vlan() to handle the REMOVING state: if a DEL is +pending and the user re-adds the same VLAN, queue it for ADD so +it gets re-programmed after the PF processes the DEL. + +The !VLAN_FILTERING_ALLOWED early-exit path still frees filters +directly since no PF message is sent in that case. + +Also update iavf_del_vlan() to skip filters already in REMOVING +state: DEL has been sent to PF and the completion handler will +free the filter when PF confirms. Without this guard, the sequence +DEL(pending) -> user-del -> second DEL could cause the PF to return +an error for the second DEL (filter already gone), causing the +completion handler to incorrectly revert a deleted filter back to +ACTIVE. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-3-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 1 + + drivers/net/ethernet/intel/iavf/iavf_main.c | 13 ++++--- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 37 +++++++++++++------ + 3 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 5765715914d6b..050f8241ef5e6 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -161,6 +161,7 @@ enum iavf_vlan_state_t { + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ ++ IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index a12ae6446c06c..d09add9a110ea 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, + adapter->num_vlan_filters++; + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); + } else if (f->state == IAVF_VLAN_REMOVE) { +- /* Re-add the filter since we cannot tell whether the +- * pending delete has already been processed by the PF. +- * A duplicate add is harmless. +- */ ++ /* DEL not yet sent to PF, cancel it */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else if (f->state == IAVF_VLAN_REMOVING) { ++ /* DEL already sent to PF, re-add after completion */ + f->state = IAVF_VLAN_ADD; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_ADD_VLAN_FILTER); +@@ -791,11 +791,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else { ++ } else if (f->state != IAVF_VLAN_REMOVING) { + f->state = IAVF_VLAN_REMOVE; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_DEL_VLAN_FILTER); + } ++ /* If REMOVING, DEL is already sent to PF; completion ++ * handler will free the filter when PF confirms. ++ */ + } + + spin_unlock_bh(&adapter->mac_vlan_list_lock); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 8a856ec5ef480..9132f16d853e5 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -945,12 +945,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -986,7 +984,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; +@@ -1001,9 +999,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -2366,10 +2362,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); + wake_up(&adapter->vc_waitqueue); + break; +- case VIRTCHNL_OP_DEL_VLAN: +- dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", +- iavf_stat_str(&adapter->hw, v_retval)); +- break; + case VIRTCHNL_OP_DEL_ETH_ADDR: + dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", + iavf_stat_str(&adapter->hw, v_retval)); +@@ -2891,6 +2883,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + break; ++ case VIRTCHNL_OP_DEL_VLAN: ++ case VIRTCHNL_OP_DEL_VLAN_V2: { ++ struct iavf_vlan_filter *f, *ftmp; ++ ++ spin_lock_bh(&adapter->mac_vlan_list_lock); ++ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, ++ list) { ++ if (f->state == IAVF_VLAN_REMOVING) { ++ if (v_retval) { ++ /* PF rejected DEL, keep filter */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else { ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; ++ } ++ } ++ } ++ spin_unlock_bh(&adapter->mac_vlan_list_lock); ++ } ++ break; + case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: + /* PF enabled vlan strip on this VF. + * Update netdev->features if needed to be in sync with ethtool. +-- +2.53.0 + diff --git a/queue-6.18/ice-add-dpll-peer-notification-for-paired-sma-and-u..patch b/queue-6.18/ice-add-dpll-peer-notification-for-paired-sma-and-u..patch new file mode 100644 index 0000000000..bc7bfd6b63 --- /dev/null +++ b/queue-6.18/ice-add-dpll-peer-notification-for-paired-sma-and-u..patch @@ -0,0 +1,101 @@ +From 5ad24981fefbffc5d10858730402038cbc336e5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:23 -0700 +Subject: ice: add dpll peer notification for paired SMA and U.FL pins + +From: Petr Oros + +[ Upstream commit 9e5dead140af10e8b5f975b8f04e46197d48d274 ] + +SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and +SMA2/U.FL2). When one pin's state changes via a PCA9575 GPIO write, +the paired pin's state also changes, but no notification is sent for +the peer pin. Userspace consumers monitoring the peer via dpll netlink +subscribe never learn about the update. + +Add ice_dpll_sw_pin_notify_peer() which sends a change notification for +the paired SW pin. Call it from ice_dpll_pin_sma_direction_set(), +ice_dpll_sma_pin_state_set(), and ice_dpll_ufl_pin_state_set() after +pf->dplls.lock is released. Use __dpll_pin_change_ntf() because +dpll_lock is still held by the dpll netlink layer (dpll_pin_pre_doit). + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Signed-off-by: Petr Oros +Tested-by: Alexander Nowlin +Reviewed-by: Arkadiusz Kubalewski +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-11-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 32 +++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index baf492f5c4925..14048ac5eff56 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -1073,6 +1073,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, + extack, ICE_DPLL_PIN_TYPE_INPUT); + } + ++/** ++ * ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change ++ * @d: pointer to dplls struct ++ * @changed: the SW pin that was explicitly changed (already notified by dpll core) ++ * ++ * SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and ++ * SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO ++ * expander, the paired pin's state may also change. Send a change ++ * notification for the peer pin so userspace consumers monitoring the ++ * peer via dpll netlink learn about the update. ++ * ++ * Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is ++ * released. Uses __dpll_pin_change_ntf() because dpll_lock is ++ * still held by the dpll netlink layer. ++ */ ++static void ice_dpll_sw_pin_notify_peer(struct ice_dplls *d, ++ struct ice_dpll_pin *changed) ++{ ++ struct ice_dpll_pin *peer; ++ ++ peer = (changed >= d->sma && changed < d->sma + ICE_DPLL_PIN_SW_NUM) ? ++ &d->ufl[changed->idx] : &d->sma[changed->idx]; ++ if (peer->pin) ++ __dpll_pin_change_ntf(peer->pin); ++} ++ + /** + * ice_dpll_sma_direction_set - set direction of SMA pin + * @p: pointer to a pin +@@ -1263,6 +1289,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + + unlock: + mutex_unlock(&pf->dplls.lock); ++ if (!ret) ++ ice_dpll_sw_pin_notify_peer(&pf->dplls, p); + + return ret; + } +@@ -1381,6 +1409,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + + unlock: + mutex_unlock(&pf->dplls.lock); ++ if (!ret) ++ ice_dpll_sw_pin_notify_peer(&pf->dplls, sma); + + return ret; + } +@@ -1576,6 +1606,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv, + mutex_lock(&pf->dplls.lock); + ret = ice_dpll_sma_direction_set(p, direction, extack); + mutex_unlock(&pf->dplls.lock); ++ if (!ret) ++ ice_dpll_sw_pin_notify_peer(&pf->dplls, p); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-adjust-timer-programming-for-e830-devices.patch b/queue-6.18/ice-fix-adjust-timer-programming-for-e830-devices.patch new file mode 100644 index 0000000000..9f5b4f5c0c --- /dev/null +++ b/queue-6.18/ice-fix-adjust-timer-programming-for-e830-devices.patch @@ -0,0 +1,74 @@ +From f843374484de75165f79cce86964cec1954e0b02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:25 -0700 +Subject: ice: fix 'adjust' timer programming for E830 devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Grzegorz Nitka + +[ Upstream commit 885c5e57924dc040b23d0ad0d8388f0e35772159 ] + +Fix incorrect 'adjust the timer' programming sequence for E830 devices +series. Only shadow registers GLTSYN_SHADJ were programmed in the +current implementation. According to the specification [1], write to +command GLTSYN_CMD register is also required with CMD field set to +"Adjust the Time" value, for the timer adjustment to take the effect. + +The flow was broken for the adjustment less than S32_MAX/MIN range +(around +/- 2 seconds). For bigger adjustment, non-atomic programming +flow is used, involving set timer programming. Non-atomic flow is +implemented correctly. + +Testing hints: +Run command: + phc_ctl /dev/ptpX get adj 2 get +Expected result: + Returned timestamps differ at least by 2 seconds + +[1] Intel® Ethernet Controller E830 Datasheet rev 1.3, chapter 9.7.5.4 +https://cdrdv2.intel.com/v1/dl/getContent/787353?explicitVersion=true + +Fixes: f00307522786 ("ice: Implement PTP support for E830 devices") +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Grzegorz Nitka +Reviewed-by: Simon Horman +Tested-by: Rinitha S +Reviewed-by: Jacob Keller +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-1-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 35680dbe4a7f7..161a0ae8599c1 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -5381,8 +5381,8 @@ int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) + */ + int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) + { ++ int err = 0; + u8 tmr_idx; +- int err; + + tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; + +@@ -5399,8 +5399,8 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) + err = ice_ptp_prep_phy_adj_e810(hw, adj); + break; + case ICE_MAC_E830: +- /* E830 sync PHYs automatically after setting GLTSYN_SHADJ */ +- return 0; ++ /* E830 sync PHYs automatically after setting cmd register */ ++ break; + case ICE_MAC_GENERIC: + err = ice_ptp_prep_phy_adj_e82x(hw, adj); + break; +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-double-free-of-tx_buf-skb.patch b/queue-6.18/ice-fix-double-free-of-tx_buf-skb.patch new file mode 100644 index 0000000000..6dd80d7b3a --- /dev/null +++ b/queue-6.18/ice-fix-double-free-of-tx_buf-skb.patch @@ -0,0 +1,76 @@ +From 554a338677f0cdb220fa8ad92f2dd06826d09f0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:28 -0700 +Subject: ice: fix double-free of tx_buf skb + +From: Michal Schmidt + +[ Upstream commit 1a303baa715e6b78d6a406aaf335f87ff35acfcd ] + +If ice_tso() or ice_tx_csum() fail, the error path in +ice_xmit_frame_ring() frees the skb, but the 'first' tx_buf still points +to it and is marked as valid (ICE_TX_BUF_SKB). +'next_to_use' remains unchanged, so the potential problem will +likely fix itself when the next packet is transmitted and the tx_buf +gets overwritten. But if there is no next packet and the interface is +brought down instead, ice_clean_tx_ring() -> ice_unmap_and_free_tx_buf() +will find the tx_buf and free the skb for the second time. + +The fix is to reset the tx_buf type to ICE_TX_BUF_EMPTY in the error +path, so that ice_unmap_and_free_tx_buf(). +Move the initialization of 'first' up, to ensure it's already valid in +case we hit the linearization error path. + +The bug was spotted by AI while I had it looking for something else. +It also proposed an initial version of the patch. + +I reproduced the bug and tested the fix by adding code to inject +failures, on a build with KASAN. + +I looked for similar bugs in related Intel drivers and did not find any. + +Fixes: d76a60ba7afb ("ice: Add support for VLANs and offloads") +Assisted-by: Claude:claude-4.6-opus-high Cursor +Signed-off-by: Michal Schmidt +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-4-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 90dbe5266ce78..e0774a640955d 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2594,6 +2594,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + ++ /* record the location of the first descriptor for this packet */ ++ first = &tx_ring->tx_buf[tx_ring->next_to_use]; ++ + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +@@ -2619,8 +2622,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + offload.tx_ring = tx_ring; + +- /* record the location of the first descriptor for this packet */ +- first = &tx_ring->tx_buf[tx_ring->next_to_use]; + first->skb = skb; + first->type = ICE_TX_BUF_SKB; + first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); +@@ -2685,6 +2686,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + out_drop: + ice_trace(xmit_frame_ring_drop, tx_ring, skb); + dev_kfree_skb_any(skb); ++ first->type = ICE_TX_BUF_EMPTY; + return NETDEV_TX_OK; + } + +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-ice_aq_link_speed_m-for-200g.patch b/queue-6.18/ice-fix-ice_aq_link_speed_m-for-200g.patch new file mode 100644 index 0000000000..da932b2b54 --- /dev/null +++ b/queue-6.18/ice-fix-ice_aq_link_speed_m-for-200g.patch @@ -0,0 +1,47 @@ +From 369e2d4ca7910e47d4fe77ffa6b0ba7084892eb3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:30 -0700 +Subject: ice: fix ICE_AQ_LINK_SPEED_M for 200G + +From: Paul Greenwalt + +[ Upstream commit 4a3a940059e98539de293a6e36e464094c2e875b ] + +When setting PHY configuration during driver initialization, 200G link +speed is not being advertised even when the PHY is capable. This is +because the get PHY capabilities link speed response is being masked by +ICE_AQ_LINK_SPEED_M, which does not include the 200G link speed bit. + +ICE_AQ_LINK_SPEED_200GB is defined as BIT(11), but the mask 0x7FF only +covers bits 0-10. Fix ICE_AQ_LINK_SPEED_M to use GENMASK(11, 0) so +that it covers all defined link speed bits including 200G. + +Fixes: 24407a01e57c ("ice: Add 200G speed/phy type use") +Signed-off-by: Paul Greenwalt +Signed-off-by: Aleksandr Loktionov +Reviewed-by: Simon Horman +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-6-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +index 859e9c66f3e7e..3cbb1b0582e32 100644 +--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h ++++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +@@ -1252,7 +1252,7 @@ struct ice_aqc_get_link_status_data { + #define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2 + #define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3 + __le16 link_speed; +-#define ICE_AQ_LINK_SPEED_M 0x7FF ++#define ICE_AQ_LINK_SPEED_M GENMASK(11, 0) + #define ICE_AQ_LINK_SPEED_10MB BIT(0) + #define ICE_AQ_LINK_SPEED_100MB BIT(1) + #define ICE_AQ_LINK_SPEED_1000MB BIT(2) +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch b/queue-6.18/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch new file mode 100644 index 0000000000..bae432515e --- /dev/null +++ b/queue-6.18/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch @@ -0,0 +1,63 @@ +From e838dab776f6695c23315d2e87018f2e7c67e82f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:28 -0700 +Subject: ice: fix ice_ptp_read_tx_hwtstamp_status_eth56g + +From: Jacob Keller + +[ Upstream commit 1f75dbc53f68f0fb2acd99f92315e426a3d0b446 ] + +The ice_ptp_read_tx_hwtstamp_status_eth56g function calls +ice_read_phy_eth56g with a PHY index. However the function actually expects +a port index. This causes the function to read the wrong PHY_PTP_INT_STATUS +registers, and effectively makes the status wrong for the second set of +ports from 4 to 7. + +The ice_read_phy_eth56g function uses the provided port index to determine +which PHY device to read. We could refactor the entire chain to take a PHY +index, but this would impact many code sites. Instead, multiply the PHY +index by the number of ports, so that we read from the first port of each +PHY. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-4-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 22d6df06b0bc7..d461e00d15e9e 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -2219,13 +2219,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) + *ts_status = 0; + + for (phy = 0; phy < params->num_phys; phy++) { ++ u8 port; + int err; + +- err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status); ++ /* ice_read_phy_eth56g expects a port index, so use the first ++ * port of the PHY ++ */ ++ port = phy * hw->ptp.ports_per_phy; ++ ++ err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status); + if (err) + return err; + +- *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy); ++ *ts_status |= (status & mask) << port; + } + + ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status); +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-infinite-recursion-in-ice_cfg_tx_topo-via-ic.patch b/queue-6.18/ice-fix-infinite-recursion-in-ice_cfg_tx_topo-via-ic.patch new file mode 100644 index 0000000000..7556920ffb --- /dev/null +++ b/queue-6.18/ice-fix-infinite-recursion-in-ice_cfg_tx_topo-via-ic.patch @@ -0,0 +1,105 @@ +From 8c776dfeb1631d85244065c290faed92619fa231 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:18 -0700 +Subject: ice: fix infinite recursion in ice_cfg_tx_topo via ice_init_dev_hw + +From: Petr Oros + +[ Upstream commit 70ad216411e030f67b1743774e245601194aee6a ] + +On certain E810 configurations where firmware supports Tx scheduler +topology switching (tx_sched_topo_comp_mode_en), ice_cfg_tx_topo() +may need to apply a new 5-layer or 9-layer topology from the DDP +package. If the AQ command to set the topology fails (e.g. due to +invalid DDP data or firmware limitations), the global configuration +lock must still be cleared via a CORER reset. + +Commit 86aae43f21cf ("ice: don't leave device non-functional if Tx +scheduler config fails") correctly fixed this by refactoring +ice_cfg_tx_topo() to always trigger CORER after acquiring the global +lock and re-initialize hardware via ice_init_hw() afterwards. + +However, commit 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end +of deinit paths") later moved ice_init_dev_hw() into ice_init_hw(), +breaking the reinit path introduced by 86aae43f21cf. This creates an +infinite recursive call chain: + + ice_init_hw() + ice_init_dev_hw() + ice_cfg_tx_topo() # topology change needed + ice_deinit_hw() + ice_init_hw() # reinit after CORER + ice_init_dev_hw() # recurse + ice_cfg_tx_topo() + ... # stack overflow + +Fix by moving ice_init_dev_hw() back out of ice_init_hw() and calling +it explicitly from ice_probe() and ice_devlink_reinit_up(). The third +caller, ice_cfg_tx_topo(), intentionally does not need ice_init_dev_hw() +during its reinit, it only needs the core HW reinitialization. This +breaks the recursion cleanly without adding flags or guards. + +The deinit ordering changes from commit 8a37f9e2ff40 ("ice: move +ice_deinit_dev() to the end of deinit paths") which fixed slow rmmod +are preserved, only the init-side placement of ice_init_dev_hw() is +reverted. + +Fixes: 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end of deinit paths") +Signed-off-by: Petr Oros +Reviewed-by: Paul Menzel +Reviewed-by: Jacob Keller +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Alexander Nowlin +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-6-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/devlink/devlink.c | 2 ++ + drivers/net/ethernet/intel/ice/ice_common.c | 2 -- + drivers/net/ethernet/intel/ice/ice_main.c | 2 ++ + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c +index 862ff1cdd46d6..839b7bfa19359 100644 +--- a/drivers/net/ethernet/intel/ice/devlink/devlink.c ++++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c +@@ -1243,6 +1243,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) + return err; + } + ++ ice_init_dev_hw(pf); ++ + /* load MSI-X values */ + ice_set_min_max_msix(pf); + +diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c +index c23a31ec3c413..4dcc3b41800b3 100644 +--- a/drivers/net/ethernet/intel/ice/ice_common.c ++++ b/drivers/net/ethernet/intel/ice/ice_common.c +@@ -1162,8 +1162,6 @@ int ice_init_hw(struct ice_hw *hw) + if (status) + goto err_unroll_fltr_mgmt_struct; + +- ice_init_dev_hw(hw->back); +- + mutex_init(&hw->tnl_lock); + ice_init_chk_recipe_reuse_support(hw); + +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index a4ae032f2161b..c064c3653c540 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -5321,6 +5321,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) + return err; + } + ++ ice_init_dev_hw(pf); ++ + adapter = ice_adapter_get(pdev); + if (IS_ERR(adapter)) { + err = PTR_ERR(adapter); +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-missing-dpll-notifications-for-sw-pins.patch b/queue-6.18/ice-fix-missing-dpll-notifications-for-sw-pins.patch new file mode 100644 index 0000000000..fe45cc6dd8 --- /dev/null +++ b/queue-6.18/ice-fix-missing-dpll-notifications-for-sw-pins.patch @@ -0,0 +1,157 @@ +From 9aa74620ff74e9012da936b9735183777119a653 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:22 -0700 +Subject: ice: fix missing dpll notifications for SW pins + +From: Petr Oros + +[ Upstream commit 1a41b58fd4dc80dca16c717e6e77c88b9d4e83a7 ] + +The SMA/U.FL pin redesign (commit 2dd5d03c77e2 ("ice: redesign dpll +sma/u.fl pins control")) introduced software-controlled pins that wrap +backing CGU input/output pins, but never updated the notification and +data paths to propagate pin events to these SW wrappers. + +The periodic work sends dpll_pin_change_ntf() only for direct CGU input +pins. SW pins that wrap these inputs never receive change or phase +offset notifications, so userspace consumers such as synce4l monitoring +SMA pins via dpll netlink never learn about state transitions or phase +offset updates. Similarly, ice_dpll_phase_offset_get() reads the SW +pin's own phase_offset field which is never updated; the PPS monitor +writes to the backing CGU input's field instead. + +Fix by introducing ice_dpll_pin_ntf(), a wrapper around +dpll_pin_change_ntf() that also notifies any registered SMA/U.FL pin +whose backing CGU input matches. Replace all direct +dpll_pin_change_ntf() calls in the periodic notification paths with +this wrapper. Fix ice_dpll_phase_offset_get() to return the backing +CGU input's phase_offset for input-direction SW pins. + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Signed-off-by: Petr Oros +Tested-by: Alexander Nowlin +Reviewed-by: Arkadiusz Kubalewski +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Ivan Vecera +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-10-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 47 +++++++++++++++++------ + 1 file changed, 36 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 3254be7b0dca8..baf492f5c4925 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -1882,7 +1882,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, + d->active_input == p->input->pin)) + *phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; + else if (d->phase_offset_monitor_period) +- *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; ++ *phase_offset = (p->input && ++ p->direction == DPLL_PIN_DIRECTION_INPUT ? ++ p->input->phase_offset : ++ p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR; + else + *phase_offset = 0; + mutex_unlock(&pf->dplls.lock); +@@ -2510,6 +2513,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) + return pci_get_dsn(pf->pdev); + } + ++/** ++ * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers ++ * @dplls: pointer to dplls struct ++ * @pin: the dpll_pin that changed ++ * ++ * Send a change notification for @pin and for any registered SMA/U.FL pin ++ * whose backing CGU input matches @pin. ++ */ ++static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin) ++{ ++ dpll_pin_change_ntf(pin); ++ for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) { ++ if (dplls->sma[i].pin && dplls->sma[i].input && ++ dplls->sma[i].input->pin == pin) ++ dpll_pin_change_ntf(dplls->sma[i].pin); ++ if (dplls->ufl[i].pin && dplls->ufl[i].input && ++ dplls->ufl[i].input->pin == pin) ++ dpll_pin_change_ntf(dplls->ufl[i].pin); ++ } ++} ++ + /** + * ice_dpll_notify_changes - notify dpll subsystem about changes + * @d: pointer do dpll +@@ -2518,6 +2542,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) + */ + static void ice_dpll_notify_changes(struct ice_dpll *d) + { ++ struct ice_dplls *dplls = &d->pf->dplls; + bool pin_notified = false; + + if (d->prev_dpll_state != d->dpll_state) { +@@ -2526,17 +2551,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) + } + if (d->prev_input != d->active_input) { + if (d->prev_input) +- dpll_pin_change_ntf(d->prev_input); ++ ice_dpll_pin_ntf(dplls, d->prev_input); + d->prev_input = d->active_input; + if (d->active_input) { +- dpll_pin_change_ntf(d->active_input); ++ ice_dpll_pin_ntf(dplls, d->active_input); + pin_notified = true; + } + } + if (d->prev_phase_offset != d->phase_offset) { + d->prev_phase_offset = d->phase_offset; + if (!pin_notified && d->active_input) +- dpll_pin_change_ntf(d->active_input); ++ ice_dpll_pin_ntf(dplls, d->active_input); + } + } + +@@ -2565,6 +2590,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) + + /** + * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes ++ * @dplls: pointer to dplls struct + * @pins: array of ice_dpll_pin pointers registered within dpll subsystem + * @pin_num: number of pins + * @phase_offset_ntf_mask: bitmask of pin indexes to notify +@@ -2574,15 +2600,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) + * + * Context: Must be called while pf->dplls.lock is released. + */ +-static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins, ++static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls, ++ struct ice_dpll_pin *pins, + u8 pin_num, + u32 phase_offset_ntf_mask) + { +- int i = 0; +- +- for (i = 0; i < pin_num; i++) +- if (phase_offset_ntf_mask & (1 << i)) +- dpll_pin_change_ntf(pins[i].pin); ++ for (int i = 0; i < pin_num; i++) ++ if (phase_offset_ntf_mask & BIT(i)) ++ ice_dpll_pin_ntf(dplls, pins[i].pin); + } + + /** +@@ -2758,7 +2783,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work) + ice_dpll_notify_changes(de); + ice_dpll_notify_changes(dp); + if (phase_offset_ntf) +- ice_dpll_pins_notify_mask(d->inputs, d->num_inputs, ++ ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs, + phase_offset_ntf); + + resched: +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-missing-sma-pin-initialization-in-dpll-subsy.patch b/queue-6.18/ice-fix-missing-sma-pin-initialization-in-dpll-subsy.patch new file mode 100644 index 0000000000..6cf34b8e7e --- /dev/null +++ b/queue-6.18/ice-fix-missing-sma-pin-initialization-in-dpll-subsy.patch @@ -0,0 +1,88 @@ +From baa80734b786944713def2949a2ba609bbef20c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:19 -0700 +Subject: ice: fix missing SMA pin initialization in DPLL subsystem +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Petr Oros + +[ Upstream commit 56a643aed0f0af5c29ebb4593d4917b78344dd48 ] + +The DPLL SMA/U.FL pin redesign introduced ice_dpll_sw_pin_frequency_get() +which gates frequency reporting on the pin's active flag. This flag is +determined by ice_dpll_sw_pins_update() from the PCA9575 GPIO expander +state. Before the redesign, SMA pins were exposed as direct HW +input/output pins and ice_dpll_frequency_get() returned the CGU +frequency unconditionally — the PCA9575 state was never consulted. + +The PCA9575 powers on with all outputs high, setting ICE_SMA1_DIR_EN, +ICE_SMA1_TX_EN, ICE_SMA2_DIR_EN and ICE_SMA2_TX_EN. Nothing in the +driver writes the register during initialization, so +ice_dpll_sw_pins_update() sees all pins as inactive and +ice_dpll_sw_pin_frequency_get() permanently returns 0 Hz for every +SW pin. + +Fix this by writing a default SMA configuration in +ice_dpll_init_info_sw_pins(): clear all SMA bits, then set SMA1 and +SMA2 as active inputs (DIR_EN=0) with U.FL1 output and U.FL2 input +disabled. Each SMA/U.FL pair shares a physical signal path so only +one pin per pair can be active at a time. U.FL pins still report +frequency 0 after this fix: U.FL1 (output-only) is disabled by +ICE_SMA1_TX_EN which keeps the TX output buffer off, and U.FL2 +(input-only) is disabled by ICE_SMA2_UFL2_RX_DIS. They can be +activated by changing the corresponding SMA pin direction via dpll +netlink. + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Signed-off-by: Petr Oros +Reviewed-by: Ivan Vecera +Reviewed-by: Arkadiusz Kubalewski +Tested-by: Alexander Nowlin +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-7-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 53b54e395a2ed..c2ad39bfe177d 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -3545,6 +3545,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) + struct ice_dpll_pin *pin; + u32 phase_adj_max, caps; + int i, ret; ++ u8 data; + + if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) + input_idx_offset = ICE_E810_RCLK_PINS_NUM; +@@ -3604,6 +3605,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) + } + ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max); + } ++ ++ /* Initialize the SMA control register to a known-good default state. ++ * Without this write the PCA9575 GPIO expander retains its power-on ++ * default (all outputs high) which makes all SW pins appear inactive. ++ * Set SMA1 and SMA2 as active inputs, disable U.FL1 output and ++ * U.FL2 input. ++ */ ++ ret = ice_read_sma_ctrl(&pf->hw, &data); ++ if (ret) ++ return ret; ++ data &= ~ICE_ALL_SMA_MASK; ++ data |= ICE_SMA1_TX_EN | ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS; ++ ret = ice_write_sma_ctrl(&pf->hw, data); ++ if (ret) ++ return ret; ++ + ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE, + NULL); + if (ret) +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch b/queue-6.18/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch new file mode 100644 index 0000000000..76eb5d9ded --- /dev/null +++ b/queue-6.18/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch @@ -0,0 +1,130 @@ +From 97b1be7af79eab354bef131788318193222c74c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:17 -0700 +Subject: ice: fix NULL pointer dereference in ice_reset_all_vfs() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Petr Oros + +[ Upstream commit 54ef02487914c24170c7e1c061e45212dc55365e ] + +ice_reset_all_vfs() ignores the return value of ice_vf_rebuild_vsi(). +When the VSI rebuild fails (e.g. during NVM firmware update via +nvmupdate64e), ice_vsi_rebuild() tears down the VSI on its error path, +leaving txq_map and rxq_map as NULL. The subsequent unconditional call +to ice_vf_post_vsi_rebuild() leads to a NULL pointer dereference in +ice_ena_vf_q_mappings() when it accesses vsi->txq_map[0]. + +The single-VF reset path in ice_reset_vf() already handles this +correctly by checking the return value of ice_vf_reconfig_vsi() and +skipping ice_vf_post_vsi_rebuild() on failure. + +Apply the same pattern to ice_reset_all_vfs(): check the return value +of ice_vf_rebuild_vsi() and skip ice_vf_post_vsi_rebuild() and +ice_eswitch_attach_vf() on failure. The VF is left safely disabled +(ICE_VF_STATE_INIT not set, VFGEN_RSTAT not set to VFACTIVE) and can +be recovered via a VFLR triggered by a PCI reset of the VF +(sysfs reset or driver rebind). + +Note that this patch does not prevent the VF VSI rebuild from failing +during NVM update — the underlying cause is firmware being in a +transitional state while the EMP reset is processed, which can cause +Admin Queue commands (ice_add_vsi, ice_cfg_vsi_lan) to fail. This +patch only prevents the subsequent NULL pointer dereference that +crashes the kernel when the rebuild does fail. + + crash> bt + PID: 50795 TASK: ff34c9ee708dc680 CPU: 1 COMMAND: "kworker/u512:5" + #0 [ff72159bcfe5bb50] machine_kexec at ffffffffaa8850ee + #1 [ff72159bcfe5bba8] __crash_kexec at ffffffffaaa15fba + #2 [ff72159bcfe5bc68] crash_kexec at ffffffffaaa16540 + #3 [ff72159bcfe5bc70] oops_end at ffffffffaa837eda + #4 [ff72159bcfe5bc90] page_fault_oops at ffffffffaa893997 + #5 [ff72159bcfe5bce8] exc_page_fault at ffffffffab528595 + #6 [ff72159bcfe5bd10] asm_exc_page_fault at ffffffffab600bb2 + [exception RIP: ice_ena_vf_q_mappings+0x79] + RIP: ffffffffc0a85b29 RSP: ff72159bcfe5bdc8 RFLAGS: 00010206 + RAX: 00000000000f0000 RBX: ff34c9efc9c00000 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: 0000000000000010 RDI: ff34c9efc9c00000 + RBP: ff34c9efc27d4828 R8: 0000000000000093 R9: 0000000000000040 + R10: ff34c9efc27d4828 R11: 0000000000000040 R12: 0000000000100000 + R13: 0000000000000010 R14: R15: + ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 + #7 [ff72159bcfe5bdf8] ice_sriov_post_vsi_rebuild at ffffffffc0a85e2e [ice] + #8 [ff72159bcfe5be08] ice_reset_all_vfs at ffffffffc0a920b4 [ice] + #9 [ff72159bcfe5be48] ice_service_task at ffffffffc0a31519 [ice] + #10 [ff72159bcfe5be88] process_one_work at ffffffffaa93dca4 + #11 [ff72159bcfe5bec8] worker_thread at ffffffffaa93e9de + #12 [ff72159bcfe5bf18] kthread at ffffffffaa946663 + #13 [ff72159bcfe5bf50] ret_from_fork at ffffffffaa8086b9 + + The panic occurs attempting to dereference the NULL pointer in RDX at + ice_sriov.c:294, which loads vsi->txq_map (offset 0x4b8 in ice_vsi). + + The faulting VSI is an allocated slab object but not fully initialized + after a failed ice_vsi_rebuild(): + + crash> struct ice_vsi 0xff34c9efc27d4828 + netdev = 0x0, + rx_rings = 0x0, + tx_rings = 0x0, + q_vectors = 0x0, + txq_map = 0x0, + rxq_map = 0x0, + alloc_txq = 0x10, + num_txq = 0x10, + alloc_rxq = 0x10, + num_rxq = 0x10, + + The nvmupdate64e process was performing NVM firmware update: + + crash> bt 0xff34c9edd1a30000 + PID: 49858 TASK: ff34c9edd1a30000 CPU: 1 COMMAND: "nvmupdate64e" + #0 [ff72159bcd617618] __schedule at ffffffffab5333f8 + #4 [ff72159bcd617750] ice_sq_send_cmd at ffffffffc0a35347 [ice] + #5 [ff72159bcd6177a8] ice_sq_send_cmd_retry at ffffffffc0a35b47 [ice] + #6 [ff72159bcd617810] ice_aq_send_cmd at ffffffffc0a38018 [ice] + #7 [ff72159bcd617848] ice_aq_read_nvm at ffffffffc0a40254 [ice] + #8 [ff72159bcd6178b8] ice_read_flat_nvm at ffffffffc0a4034c [ice] + #9 [ff72159bcd617918] ice_devlink_nvm_snapshot at ffffffffc0a6ffa5 [ice] + + dmesg: + ice 0000:13:00.0: firmware recommends not updating fw.mgmt, as it + may result in a downgrade. continuing anyways + ice 0000:13:00.1: ice_init_nvm failed -5 + ice 0000:13:00.1: Rebuild failed, unload and reload driver + +Fixes: 12bb018c538c ("ice: Refactor VF reset") +Signed-off-by: Petr Oros +Tested-by: Rafal Romanowski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-5-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +index de9e81ccee664..e53a1e4247cb1 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +@@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) + ice_vf_ctrl_invalidate_vsi(vf); + + ice_vf_pre_vsi_rebuild(vf); +- ice_vf_rebuild_vsi(vf); ++ if (ice_vf_rebuild_vsi(vf)) { ++ dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", ++ vf->vf_id); ++ mutex_unlock(&vf->cfg_lock); ++ continue; ++ } + ice_vf_post_vsi_rebuild(vf); + + ice_eswitch_attach_vf(pf, vf); +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-ready-bitmap-check-for-non-e822-devices.patch b/queue-6.18/ice-fix-ready-bitmap-check-for-non-e822-devices.patch new file mode 100644 index 0000000000..3be1ebb574 --- /dev/null +++ b/queue-6.18/ice-fix-ready-bitmap-check-for-non-e822-devices.patch @@ -0,0 +1,343 @@ +From 82981568040696b65933446b414e0ad37a13f7d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:27 -0700 +Subject: ice: fix ready bitmap check for non-E822 devices + +From: Jacob Keller + +[ Upstream commit 359dc1d41358c88955eeff1b75aee55da7a415d3 ] + +The E800 hardware (apart from E810) has a ready bitmap for the PHY +indicating which timestamp slots currently have an outstanding timestamp +waiting to be read by software. + +This bitmap is checked in multiple places using the +ice_get_phy_tx_tstamp_ready(): + + * ice_ptp_process_tx_tstamp() calls it to determine which timestamps to + attempt reading from the PHY + * ice_ptp_tx_tstamps_pending() calls it in a loop at the end of the + miscellaneous IRQ to check if new timestamps came in while the interrupt + handler was executing. + * ice_ptp_maybe_trigger_tx_interrupt() calls it in the auxiliary work task + to trigger a software interrupt in the event that the hardware logic + gets stuck. + +For E82X devices, multiple PHYs share the same block, and the parameter +passed to the ready bitmap is a block number associated with the given +port. For E825-C devices, the PHYs have their own independent blocks and do +not share, so the parameter passed needs to be the port number. For E810 +devices, the ice_get_phy_tx_tstamp_ready() always returns all 1s regardless +of what port, since this hardware does not have a ready bitmap. Finally, +for E830 devices, each PF has its own ready bitmap accessible via register, +and the block parameter is unused. + +The first call correctly uses the Tx timestamp tracker block parameter to +check the appropriate timestamp block. This works because the tracker is +setup correctly for each timestamp device type. + +The second two callers behave incorrectly for all device types other than +the older E822 devices. They both iterate in a loop using +ICE_GET_QUAD_NUM() which is a macro only used by E822 devices. This logic +is incorrect for devices other than the E822 devices. + +For E810 the calls would always return true, causing E810 devices to always +attempt to trigger a software interrupt even when they have no reason to. +For E830, this results in duplicate work as the ready bitmap is checked +once per number of quads. Finally, for E825-C, this results in the pending +checks failing to detect timestamps on ports other than the first two. + +Fix this by introducing a new hardware API function to ice_ptp_hw.c, +ice_check_phy_tx_tstamp_ready(). This function will check if any timestamps +are available and returns a positive value if any timestamps are pending. +For E810, the function always returns false, so that the re-trigger checks +never happen. For E830, check the ready bitmap just once. For E82x +hardware, check each quad. Finally, for E825-C, check every port. + +The interface function returns an integer to enable reporting of error code +if the driver is unable read the ready bitmap. This enables callers to +handle this case properly. The previous implementation assumed that +timestamps are available if they failed to read the bitmap. This is +problematic as it could lead to continuous software IRQ triggering if the +PHY timestamp registers somehow become inaccessible. + +This change is especially important for E825-C devices, as the missing +checks could leave a window open where a new timestamp could arrive while +the existing timestamps aren't completed. As a result, the hardware +threshold logic would not trigger a new interrupt. Without the check, the +timestamp is left unhandled, and new timestamps will not cause an interrupt +again until the timestamp is handled. Since both the interrupt check and +the backup check in the auxiliary task do not function properly, the device +may have Tx timestamps permanently stuck failing on a given port. + +The faulty checks originate from commit d938a8cca88a ("ice: Auxbus devices +& driver for E822 TS") and commit 712e876371f8 ("ice: periodically kick Tx +timestamp interrupt"), however at the time of the original coding, both +functions only operated on E822 hardware. This is no longer the case, and +hasn't been since the introduction of the ETH56G PHY model in commit +7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-3-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp.c | 44 +++----- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 117 ++++++++++++++++++++ + drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 1 + + 3 files changed, 136 insertions(+), 26 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c +index 02517772fb5f4..86eb3d0315a27 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp.c +@@ -2669,7 +2669,7 @@ static bool ice_any_port_has_timestamps(struct ice_pf *pf) + bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) + { + struct ice_hw *hw = &pf->hw; +- unsigned int i; ++ int ret; + + /* Check software indicator */ + switch (pf->ptp.tx_interrupt_mode) { +@@ -2690,16 +2690,19 @@ bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) + } + + /* Check hardware indicator */ +- for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { +- u64 tstamp_ready = 0; +- int err; +- +- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); +- if (err || tstamp_ready) +- return true; ++ ret = ice_check_phy_tx_tstamp_ready(hw); ++ if (ret < 0) { ++ dev_dbg(ice_pf_to_dev(pf), "Unable to read PHY Tx timestamp ready bitmap, err %d\n", ++ ret); ++ /* Stop triggering IRQs if we're unable to read PHY */ ++ return false; + } + +- return false; ++ /* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps ++ * available, 0 if there are no waiting timestamps, and a negative ++ * value if there was an error (which we checked for above). ++ */ ++ return ret > 0; + } + + /** +@@ -2783,8 +2786,7 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) + { + struct device *dev = ice_pf_to_dev(pf); + struct ice_hw *hw = &pf->hw; +- bool trigger_oicr = false; +- unsigned int i; ++ int ret; + + if (!pf->ptp.port.tx.has_ready_bitmap) + return; +@@ -2792,21 +2794,11 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) + if (!ice_pf_src_tmr_owned(pf)) + return; + +- for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { +- u64 tstamp_ready; +- int err; +- +- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); +- if (!err && tstamp_ready) { +- trigger_oicr = true; +- break; +- } +- } +- +- if (trigger_oicr) { +- /* Trigger a software interrupt, to ensure this data +- * gets processed. +- */ ++ ret = ice_check_phy_tx_tstamp_ready(hw); ++ if (ret < 0) { ++ dev_dbg(dev, "PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n", ++ ret); ++ } else if (ret) { + dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n"); + + wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M); +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 1ae795405ac3c..22d6df06b0bc7 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -2168,6 +2168,35 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port) + return 0; + } + ++/** ++ * ice_check_phy_tx_tstamp_ready_eth56g - Check Tx memory status for all ports ++ * @hw: pointer to the HW struct ++ * ++ * Check the PHY_REG_TX_MEMORY_STATUS for all ports. A set bit indicates ++ * a waiting timestamp. ++ * ++ * Return: 1 if any port has at least one timestamp ready bit set, ++ * 0 otherwise, and a negative error code if unable to read the bitmap. ++ */ ++static int ice_check_phy_tx_tstamp_ready_eth56g(struct ice_hw *hw) ++{ ++ int port; ++ ++ for (port = 0; port < hw->ptp.num_lports; port++) { ++ u64 tstamp_ready; ++ int err; ++ ++ err = ice_get_phy_tx_tstamp_ready(hw, port, &tstamp_ready); ++ if (err) ++ return err; ++ ++ if (tstamp_ready) ++ return 1; ++ } ++ ++ return 0; ++} ++ + /** + * ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status + * @hw: pointer to the HW struct +@@ -4318,6 +4347,35 @@ ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready) + return 0; + } + ++/** ++ * ice_check_phy_tx_tstamp_ready_e82x - Check Tx memory status for all quads ++ * @hw: pointer to the HW struct ++ * ++ * Check the Q_REG_TX_MEMORY_STATUS for all quads. A set bit indicates ++ * a waiting timestamp. ++ * ++ * Return: 1 if any quad has at least one timestamp ready bit set, ++ * 0 otherwise, and a negative error value if unable to read the bitmap. ++ */ ++static int ice_check_phy_tx_tstamp_ready_e82x(struct ice_hw *hw) ++{ ++ int quad; ++ ++ for (quad = 0; quad < ICE_GET_QUAD_NUM(hw->ptp.num_lports); quad++) { ++ u64 tstamp_ready; ++ int err; ++ ++ err = ice_get_phy_tx_tstamp_ready(hw, quad, &tstamp_ready); ++ if (err) ++ return err; ++ ++ if (tstamp_ready) ++ return 1; ++ } ++ ++ return 0; ++} ++ + /** + * ice_phy_cfg_intr_e82x - Configure TX timestamp interrupt + * @hw: pointer to the HW struct +@@ -4871,6 +4929,23 @@ ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready) + return 0; + } + ++/** ++ * ice_check_phy_tx_tstamp_ready_e810 - Check Tx memory status register ++ * @hw: pointer to the HW struct ++ * ++ * The E810 devices do not have a Tx memory status register. Note this is ++ * intentionally different behavior from ice_get_phy_tx_tstamp_ready_e810 ++ * which always says that all bits are ready. This function is called in cases ++ * where code will trigger interrupts if timestamps are waiting, and should ++ * not be called for E810 hardware. ++ * ++ * Return: 0. ++ */ ++static int ice_check_phy_tx_tstamp_ready_e810(struct ice_hw *hw) ++{ ++ return 0; ++} ++ + /* E810 SMA functions + * + * The following functions operate specifically on E810 hardware and are used +@@ -5125,6 +5200,21 @@ static void ice_get_phy_tx_tstamp_ready_e830(const struct ice_hw *hw, u8 port, + *tstamp_ready |= rd32(hw, E830_PRTMAC_TS_TX_MEM_VALID_L); + } + ++/** ++ * ice_check_phy_tx_tstamp_ready_e830 - Check Tx memory status register ++ * @hw: pointer to the HW struct ++ * ++ * Return: 1 if the device has waiting timestamps, 0 otherwise. ++ */ ++static int ice_check_phy_tx_tstamp_ready_e830(struct ice_hw *hw) ++{ ++ u64 tstamp_ready; ++ ++ ice_get_phy_tx_tstamp_ready_e830(hw, 0, &tstamp_ready); ++ ++ return !!tstamp_ready; ++} ++ + /** + * ice_ptp_init_phy_e830 - initialize PHY parameters + * @ptp: pointer to the PTP HW struct +@@ -5717,6 +5807,33 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) + } + } + ++/** ++ * ice_check_phy_tx_tstamp_ready - Check PHY Tx timestamp memory status ++ * @hw: pointer to the HW struct ++ * ++ * Check the PHY for Tx timestamp memory status on all ports. If you need to ++ * see individual timestamp status for each index, use ++ * ice_get_phy_tx_tstamp_ready() instead. ++ * ++ * Return: 1 if any port has timestamps available, 0 if there are no timestamps ++ * available, and a negative error code on failure. ++ */ ++int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw) ++{ ++ switch (hw->mac_type) { ++ case ICE_MAC_E810: ++ return ice_check_phy_tx_tstamp_ready_e810(hw); ++ case ICE_MAC_E830: ++ return ice_check_phy_tx_tstamp_ready_e830(hw); ++ case ICE_MAC_GENERIC: ++ return ice_check_phy_tx_tstamp_ready_e82x(hw); ++ case ICE_MAC_GENERIC_3K_E825: ++ return ice_check_phy_tx_tstamp_ready_eth56g(hw); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ + /** + * ice_cgu_get_pin_desc_e823 - get pin description array + * @hw: pointer to the hw struct +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +index 9d7acc7eb2ceb..1b58b054f4a5b 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +@@ -300,6 +300,7 @@ void ice_ptp_reset_ts_memory(struct ice_hw *hw); + int ice_ptp_init_phc(struct ice_hw *hw); + void ice_ptp_init_hw(struct ice_hw *hw); + int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready); ++int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw); + int ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, + enum ice_ptp_tmr_cmd configured_cmd); + +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-sma-and-u.fl-pin-state-changes-affecting-pai.patch b/queue-6.18/ice-fix-sma-and-u.fl-pin-state-changes-affecting-pai.patch new file mode 100644 index 0000000000..3291b1328e --- /dev/null +++ b/queue-6.18/ice-fix-sma-and-u.fl-pin-state-changes-affecting-pai.patch @@ -0,0 +1,140 @@ +From 9122c5242b6daa9e96cd71f270b8086935d37f49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:20 -0700 +Subject: ice: fix SMA and U.FL pin state changes affecting paired pin + +From: Petr Oros + +[ Upstream commit 6f9d8393c9f50fbc68b9c9e99f78ca5a7b43ff44 ] + +SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and +SMA2/U.FL2) controlled by the PCA9575 GPIO expander. Each pair can +only have one active pin at a time: SMA1 output and U.FL1 output share +the same CGU output, SMA2 input and U.FL2 input share the same CGU +input. The PCA9575 register bits determine which connector in each +pair owns the signal path. + +The driver does not account for this pairing in two places: + +ice_dpll_ufl_pin_state_set() modifies PCA9575 bits and disables the +backing CGU pin without checking whether the U.FL pin is currently +active. Disconnecting an already inactive U.FL pin flips bits that +the paired SMA pin relies on, breaking its connection. + +ice_dpll_sma_direction_set() does not propagate direction changes to +the paired U.FL pin. For SMA2/U.FL2 the ICE_SMA2_UFL2_RX_DIS bit is +never managed, so U.FL2 stays disconnected after SMA2 switches to +output. For both pairs the backing CGU pin of the U.FL side is never +enabled when a direction change activates it, so userspace sees the +pin as disconnected even though the routing is correct. + +Fix by guarding the U.FL disconnect path against inactive pins and by +updating the paired U.FL pin fully on SMA direction changes: manage +ICE_SMA2_UFL2_RX_DIS for the SMA2/U.FL2 pair and enable the backing +CGU pin whenever the peer becomes active. + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Signed-off-by: Petr Oros +Tested-by: Alexander Nowlin +Reviewed-by: Arkadiusz Kubalewski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-8-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 50 ++++++++++++++++++++++- + 1 file changed, 49 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index c2ad39bfe177d..3254be7b0dca8 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -1090,6 +1090,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, + enum dpll_pin_direction direction, + struct netlink_ext_ack *extack) + { ++ struct ice_dplls *d = &p->pf->dplls; ++ struct ice_dpll_pin *peer; + u8 data; + int ret; + +@@ -1108,8 +1110,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, + case ICE_DPLL_PIN_SW_2_IDX: + if (direction == DPLL_PIN_DIRECTION_INPUT) { + data &= ~ICE_SMA2_DIR_EN; ++ data |= ICE_SMA2_UFL2_RX_DIS; + } else { +- data &= ~ICE_SMA2_TX_EN; ++ data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS); + data |= ICE_SMA2_DIR_EN; + } + break; +@@ -1121,6 +1124,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, + ret = ice_dpll_pin_state_update(p->pf, p, + ICE_DPLL_PIN_TYPE_SOFTWARE, + extack); ++ if (ret) ++ return ret; ++ ++ /* When a direction change activates the paired U.FL pin, enable ++ * its backing CGU pin so the pin reports as connected. Without ++ * this the U.FL routing is correct but the CGU pin stays disabled ++ * and userspace sees the pin as disconnected. Do not disable the ++ * backing pin when U.FL becomes inactive because the SMA pin may ++ * still be using it. ++ */ ++ peer = &d->ufl[p->idx]; ++ if (peer->active) { ++ struct ice_dpll_pin *target; ++ enum ice_dpll_pin_type type; ++ ++ if (peer->output) { ++ target = peer->output; ++ type = ICE_DPLL_PIN_TYPE_OUTPUT; ++ } else { ++ target = peer->input; ++ type = ICE_DPLL_PIN_TYPE_INPUT; ++ } ++ ret = ice_dpll_pin_enable(&p->pf->hw, target, ++ d->eec.dpll_idx, type, extack); ++ if (!ret) ++ ret = ice_dpll_pin_state_update(p->pf, target, ++ type, extack); ++ } + + return ret; + } +@@ -1172,6 +1203,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + data &= ~ICE_SMA1_MASK; + enable = true; + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { ++ /* Skip if U.FL1 is not active, setting TX_EN ++ * while DIR_EN is set would also deactivate ++ * the paired SMA1 output. ++ */ ++ if (data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN)) { ++ ret = 0; ++ goto unlock; ++ } + data |= ICE_SMA1_TX_EN; + enable = false; + } else { +@@ -1186,6 +1225,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + data &= ~ICE_SMA2_UFL2_RX_DIS; + enable = true; + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { ++ /* Skip if U.FL2 is not active, setting ++ * UFL2_RX_DIS could also disable the paired ++ * SMA2 input. ++ */ ++ if (!(data & ICE_SMA2_DIR_EN) || ++ (data & ICE_SMA2_UFL2_RX_DIS)) { ++ ret = 0; ++ goto unlock; ++ } + data |= ICE_SMA2_UFL2_RX_DIS; + enable = false; + } else { +-- +2.53.0 + diff --git a/queue-6.18/ice-fix-timestamp-interrupt-configuration-for-e825c.patch b/queue-6.18/ice-fix-timestamp-interrupt-configuration-for-e825c.patch new file mode 100644 index 0000000000..8379fa3ef4 --- /dev/null +++ b/queue-6.18/ice-fix-timestamp-interrupt-configuration-for-e825c.patch @@ -0,0 +1,144 @@ +From d2bce5610ef6061a4d0603d07d7d2d30ce149a28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:25 -0700 +Subject: ice: fix timestamp interrupt configuration for E825C + +From: Grzegorz Nitka + +[ Upstream commit c0a575a801a2040eb1e0db54b488f8c548c8458a ] + +The E825C ice_phy_cfg_intr_eth56g() function is responsible for programming +the PHY interrupt for a given port. This function writes to the +PHY_REG_TS_INT_CONFIG register of the port. The register is responsible for +configuring whether the port interrupt logic is enabled, as well as +programming the threshold of waiting timestamps that will trigger an +interrupt from this port. + +This threshold value must not be programmed to zero while the interrupt is +enabled. Doing so puts the port in a misconfigured state where the PHY +timestamp interrupt for the quad of connected ports will become stuck. + +This occurs, because a threshold of zero results in the timestamp interrupt +status for the port becoming stuck high. The four ports in the connected +quad have their timestamp status indicators muxed together. A new interrupt +cannot be generated until the timestamp status indicators return low for +all four ports. + +Normally, the timestamp status for a port will clear once there are fewer +timestamps in that ports timestamp memory bank than the threshold. A +threshold of zero makes this impossible, so the timestamp status for the +port does not clear. + +The ice driver never intentionally programs the threshold to zero, indeed +the driver always programs it to a value of 1, intending to get an +interrupt immediately as soon as even a single packet is waiting for a +timestamp. + +However, there is a subtle flaw in the programming logic in the +ice_phy_cfg_intr_eth56g() function. Due to the way that the hardware +handles enabling the PHY interrupt. If the threshold value is modified at +the same time as the interrupt is enabled, the HW PHY state machine might +enable the interrupt before the new threshold value is actually updated. +This leaves a potential race condition caused by the hardware logic where +a PHY timestamp interrupt might be triggered before the non-zero threshold +is written, resulting in the PHY timestamp logic becoming stuck. + +Once the PHY timestamp status is stuck high, it will remain stuck even +after attempting to reprogram the PHY block by changing its threshold or +disabling the interrupt. Even a typical PF or CORE reset will not reset the +particular block of the PHY that becomes stuck. Even a warm power cycle is +not guaranteed to cause the PHY block to reset, and a cold power cycle is +required. + +Prevent this by always writing the PHY_REG_TS_INT_CONFIG in two stages. +First write the threshold value with the interrupt disabled, and only write +the enable bit after the threshold has been programmed. When disabling the +interrupt, leave the threshold unchanged. Additionally, re-read the +register after writing it to guarantee that the write to the PHY has been +flushed upon exit of the function. + +While we're modifying this function implementation, explicitly reject +programming a threshold of 0 when enabling the interrupt. No caller does +this today, but the consequences of doing so are significant. An explicit +rejection in the code makes this clear. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Signed-off-by: Grzegorz Nitka +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-1-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 36 ++++++++++++++++++--- + 1 file changed, 32 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 161a0ae8599c1..0a20ae0c2901b 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -1847,6 +1847,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port) + * @ena: enable or disable interrupt + * @threshold: interrupt threshold + * ++ * The threshold cannot be 0 while the interrupt is enabled. ++ * + * Configure TX timestamp interrupt for the specified port + * + * Return: +@@ -1858,19 +1860,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold) + int err; + u32 val; + ++ if (ena && !threshold) ++ return -EINVAL; ++ + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); + if (err) + return err; + ++ val &= ~PHY_TS_INT_CONFIG_ENA_M; + if (ena) { +- val |= PHY_TS_INT_CONFIG_ENA_M; + val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M; + val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold); +- } else { +- val &= ~PHY_TS_INT_CONFIG_ENA_M; ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, ++ val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ val |= PHY_TS_INT_CONFIG_ENA_M; + } + +- return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ ++ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ ++ return 0; + } + + /** +-- +2.53.0 + diff --git a/queue-6.18/ice-perform-phy-soft-reset-for-e825c-ports-at-initia.patch b/queue-6.18/ice-perform-phy-soft-reset-for-e825c-ports-at-initia.patch new file mode 100644 index 0000000000..aad2c320df --- /dev/null +++ b/queue-6.18/ice-perform-phy-soft-reset-for-e825c-ports-at-initia.patch @@ -0,0 +1,201 @@ +From bab1bd8e343040ecd0e8fb19bf12d136a270bc04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:26 -0700 +Subject: ice: perform PHY soft reset for E825C ports at initialization + +From: Grzegorz Nitka + +[ Upstream commit 3ec46e157c7fa420c77dfc23f7030e61f2f3fd55 ] + +In some cases the PHY timestamp block of the E825C can become stuck. This +is known to occur if the software writes 0 to the Tx timestamp threshold, +and with older versions of the ice driver the threshold configuration is +buggy and can race in such that hardware briefly operates with a zero +threshold enabled. There are no other known ways to trigger this behavior, +but once it occurs, the hardware is not recovered by normal reset, a driver +reload, or even a warm power cycle of the system. A cold power cycle is +sufficient to recover hardware, but this is extremely invasive and can +result in significant downtime on customer deployments. + +The PHY for each port has a timestamping block which has its own reset +functionality accessible by programming the PHY_REG_GLOBAL register. +Writing to the PHY_REG_GLOBAL_SOFT_RESET_BIT triggers the hardware to +perform a complete reset of the timestamping block of the PHY. This +includes clearing the timestamp status for the port, clearing all +outstanding timestamps in the memory bank, and resetting the PHY timer. + +The new ice_ptp_phy_soft_reset_eth56g() function toggles the +PHY_REG_GLOBAL soft reset bit with the required delays, ensuring the +PHY is properly reinitialized without requiring a full device reset. +The sequence clears the reset bit, asserts it, then clears it again, +with short waits between transitions to allow hardware stabilization. + +Call this function in the new ice_ptp_init_phc_e825c(), implementing the +E825C device specific variant of the ice_ptp_init_phc(). Note that if +ice_ptp_init_phc() fails, PTP functionality may be disabled, but the driver +will still load to allow basic functionality to continue. + +This causes the clock owning PF driver to perform a PHY soft reset for +every port during initialization. This ensures the driver begins life in a +known functional state regardless of how it was previously programmed. + +This ensures that we properly reconfigure the hardware after a device reset +or when loading the driver, even if it was previously misconfigured with an +out-of-date or modified driver. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Signed-off-by: Timothy Miskell +Signed-off-by: Grzegorz Nitka +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-2-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 90 ++++++++++++++++++++- + drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 4 + + 2 files changed, 93 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 0a20ae0c2901b..1ae795405ac3c 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -377,6 +377,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay) + * The following functions operate on devices with the ETH 56G PHY. + */ + ++/** ++ * ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization ++ * @hw: pointer to HW struct ++ * ++ * Perform E825C-specific PTP hardware clock initialization steps. ++ * ++ * Return: 0 on success, or a negative error value on failure. ++ */ ++static int ice_ptp_init_phc_e825c(struct ice_hw *hw) ++{ ++ int err; ++ ++ /* Soft reset all ports, to ensure everything is at a clean state */ ++ for (int port = 0; port < hw->ptp.num_lports; port++) { ++ err = ice_ptp_phy_soft_reset_eth56g(hw, port); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, "Failed to soft reset port %d, err %d\n", ++ port, err); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ + /** + * ice_ptp_get_dest_dev_e825 - get destination PHY for given port number + * @hw: pointer to the HW struct +@@ -2179,6 +2204,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) + return 0; + } + ++/** ++ * ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G ++ * @hw: pointer to the HW structure ++ * @port: PHY port number ++ * ++ * Trigger a soft reset of the ETH56G PHY by toggling the soft reset ++ * bit in the PHY global register. The reset sequence consists of: ++ * 1. Clearing the soft reset bit ++ * 2. Asserting the soft reset bit ++ * 3. Clearing the soft reset bit again ++ * ++ * Short delays are inserted between each step to allow the hardware ++ * to settle. This provides a controlled way to reinitialize the PHY ++ * without requiring a full device reset. ++ * ++ * Return: 0 on success, or a negative error code on failure when ++ * reading or writing the PHY register. ++ */ ++int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port) ++{ ++ u32 global_val; ++ int err; ++ ++ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n", ++ port, err); ++ return err; ++ } ++ ++ global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; ++ ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n", ++ port, global_val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", ++ port, err); ++ return err; ++ } ++ ++ usleep_range(5000, 6000); ++ ++ global_val |= PHY_REG_GLOBAL_SOFT_RESET_M; ++ ice_debug(hw, ICE_DBG_PTP, "Set soft reset bit for port %d, val: 0x%x\n", ++ port, global_val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", ++ port, err); ++ return err; ++ } ++ usleep_range(5000, 6000); ++ ++ global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; ++ ice_debug(hw, ICE_DBG_PTP, "Clear soft reset bit for port %d, val: 0x%x\n", ++ port, global_val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); ++ if (err) ++ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", ++ port, err); ++ return err; ++} ++ + /** + * ice_get_phy_tx_tstamp_ready_eth56g - Read the Tx memory status register + * @hw: pointer to the HW struct +@@ -5592,7 +5680,7 @@ int ice_ptp_init_phc(struct ice_hw *hw) + case ICE_MAC_GENERIC: + return ice_ptp_init_phc_e82x(hw); + case ICE_MAC_GENERIC_3K_E825: +- return 0; ++ return ice_ptp_init_phc_e825c(hw); + default: + return -EOPNOTSUPP; + } +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +index 5896b346e5790..9d7acc7eb2ceb 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +@@ -374,6 +374,7 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset); + int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port); + int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold); + int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port); ++int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port); + + #define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL + #define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL +@@ -676,6 +677,9 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw) + #define ICE_P0_GNSS_PRSNT_N BIT(4) + + /* ETH56G PHY register addresses */ ++#define PHY_REG_GLOBAL 0x0 ++#define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11) ++ + /* Timestamp PHY incval registers */ + #define PHY_REG_TIMETUS_L 0x8 + #define PHY_REG_TIMETUS_U 0xC +-- +2.53.0 + diff --git a/queue-6.18/ice-remove-jumbo_remove-step-from-tx-path.patch b/queue-6.18/ice-remove-jumbo_remove-step-from-tx-path.patch new file mode 100644 index 0000000000..151dde82df --- /dev/null +++ b/queue-6.18/ice-remove-jumbo_remove-step-from-tx-path.patch @@ -0,0 +1,41 @@ +From 255e11f8c84fb29022e8c5b03bbbcc8baa13058b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 15:39:20 +0200 +Subject: ice: Remove jumbo_remove step from TX path + +From: Alice Mikityanska + +[ Upstream commit 8b76102c5e00d1f090e0c31d17b060c76d8fa859 ] + +Now that the kernel doesn't insert HBH for BIG TCP IPv6 packets, remove +unnecessary steps from the ice TX path, that used to check and remove +HBH. + +Signed-off-by: Alice Mikityanska +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260205133925.526371-8-alice.kernel@fastmail.im +Signed-off-by: Jakub Kicinski +Stable-dep-of: 1a303baa715e ("ice: fix double-free of tx_buf skb") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 73f08d02f9c76..90dbe5266ce78 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2594,9 +2594,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + +- if (unlikely(ipv6_hopopt_jumbo_remove(skb))) +- goto out_drop; +- + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +-- +2.53.0 + diff --git a/queue-6.18/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch b/queue-6.18/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch new file mode 100644 index 0000000000..eb71dd1ccc --- /dev/null +++ b/queue-6.18/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch @@ -0,0 +1,86 @@ +From 363f361a33ceec309e8fc2eb07a9e3b984ab721a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:26 -0700 +Subject: ice: update PCS latency settings for E825 10G/25Gb modes + +From: Grzegorz Nitka + +[ Upstream commit 05567e4052732d70c7ff9655217b3d14d25f639a ] + +Update MAC Rx/Tx offset registers settings (PHY_MAC_[RX|TX]_OFFSET +registers) with the data obtained with the latest research. It applies +to PCS latency settings for the following speeds/modes: +* 10Gb NO-FEC + - TX latency changed from 71.25 ns to 73 ns + - RX latency changed from -25.6 ns to -28 ns +* 25Gb NO-FEC + - TX latency changed from 28.17 ns to 33 ns + - RX latency changed from -12.45 ns to -12 ns +* 25Gb RS-FEC + - TX latency changed from 64.5 ns to 69 ns + - RX latency changed from -3.6 ns to -3 ns + +The original data came from simulation and pre-production hardware. +The new data measures the actual delays and as such is more accurate. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Co-developed-by: Zoltan Fodor +Signed-off-by: Zoltan Fodor +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Jacob Keller +Signed-off-by: Grzegorz Nitka +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-2-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_consts.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +index 19dddd9b53ddd..4d298c27bfb27 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +@@ -78,14 +78,14 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { + .blktime = 0x666, /* 3.2 */ + .tx_offset = { + .serdes = 0x234c, /* 17.6484848 */ +- .no_fec = 0x8e80, /* 71.25 */ ++ .no_fec = 0x93d9, /* 73 */ + .fc = 0xb4a4, /* 90.32 */ + .sfd = 0x4a4, /* 2.32 */ + .onestep = 0x4ccd /* 38.4 */ + }, + .rx_offset = { + .serdes = 0xffffeb27, /* -10.42424 */ +- .no_fec = 0xffffcccd, /* -25.6 */ ++ .no_fec = 0xffffc7b6, /* -28 */ + .fc = 0xfffc557b, /* -469.26 */ + .sfd = 0x4a4, /* 2.32 */ + .bs_ds = 0x32 /* 0.0969697 */ +@@ -118,17 +118,17 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { + .mktime = 0x147b, /* 10.24, only if RS-FEC enabled */ + .tx_offset = { + .serdes = 0xe1e, /* 7.0593939 */ +- .no_fec = 0x3857, /* 28.17 */ ++ .no_fec = 0x4266, /* 33 */ + .fc = 0x48c3, /* 36.38 */ +- .rs = 0x8100, /* 64.5 */ ++ .rs = 0x8a00, /* 69 */ + .sfd = 0x1dc, /* 0.93 */ + .onestep = 0x1eb8 /* 15.36 */ + }, + .rx_offset = { + .serdes = 0xfffff7a9, /* -4.1697 */ +- .no_fec = 0xffffe71a, /* -12.45 */ ++ .no_fec = 0xffffe700, /* -12 */ + .fc = 0xfffe894d, /* -187.35 */ +- .rs = 0xfffff8cd, /* -3.6 */ ++ .rs = 0xfffff8cc, /* -3 */ + .sfd = 0x1dc, /* 0.93 */ + .bs_ds = 0x14 /* 0.0387879, RS-FEC 0 */ + } +-- +2.53.0 + diff --git a/queue-6.18/ima-check-return-value-of-crypto_shash_final-in-boot.patch b/queue-6.18/ima-check-return-value-of-crypto_shash_final-in-boot.patch new file mode 100644 index 0000000000..eb4ee6dbaf --- /dev/null +++ b/queue-6.18/ima-check-return-value-of-crypto_shash_final-in-boot.patch @@ -0,0 +1,41 @@ +From b104d30575c380ee76bdab7210f7fd2f62423369 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 18:40:15 -0800 +Subject: ima: check return value of crypto_shash_final() in boot aggregate + +From: Daniel Hodges + +[ Upstream commit 870819434c8dfcc3158033b66e7851b81bb17e21 ] + +The return value of crypto_shash_final() is not checked in +ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the +function returns success and a corrupted boot aggregate digest could +be used for IMA measurements. + +Capture the return value and propagate any error to the caller. + +Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash") +Signed-off-by: Daniel Hodges +Reviewed-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 6f5696d999d0d..8ae7821a65c26 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -832,7 +832,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, + } + } + if (!rc) +- crypto_shash_final(shash, digest); ++ rc = crypto_shash_final(shash, digest); + return rc; + } + +-- +2.53.0 + diff --git a/queue-6.18/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch b/queue-6.18/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch new file mode 100644 index 0000000000..3f0cb3ac76 --- /dev/null +++ b/queue-6.18/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch @@ -0,0 +1,130 @@ +From 98e77984ce41131d5b385e3da48b019c44e88a36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 17:40:39 +0000 +Subject: ima_fs: Correctly create securityfs files for unsupported hash algos + +From: Dmitry Safonov + +[ Upstream commit d7bd8cf0b348d3edae7bee33e74a32b21668b181 ] + +ima_tpm_chip->allocated_banks[i].crypto_id is initialized to +HASH_ALGO__LAST if the TPM algorithm is not supported. However there +are places relying on the algorithm to be valid because it is accessed +by hash_algo_name[]. + +On 6.12.40 I observe the following read out-of-bounds in hash_algo_name: + ================================================================== + BUG: KASAN: global-out-of-bounds in create_securityfs_measurement_lists+0x396/0x440 + Read of size 8 at addr ffffffff83e18138 by task swapper/0/1 + + CPU: 4 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.40 #3 + Call Trace: + + dump_stack_lvl+0x61/0x90 + print_report+0xc4/0x580 + ? kasan_addr_to_slab+0x26/0x80 + ? create_securityfs_measurement_lists+0x396/0x440 + kasan_report+0xc2/0x100 + ? create_securityfs_measurement_lists+0x396/0x440 + create_securityfs_measurement_lists+0x396/0x440 + ima_fs_init+0xa3/0x300 + ima_init+0x7d/0xd0 + init_ima+0x28/0x100 + do_one_initcall+0xa6/0x3e0 + kernel_init_freeable+0x455/0x740 + kernel_init+0x24/0x1d0 + ret_from_fork+0x38/0x80 + ret_from_fork_asm+0x11/0x20 + + + The buggy address belongs to the variable: + hash_algo_name+0xb8/0x420 + + Memory state around the buggy address: + ffffffff83e18000: 00 01 f9 f9 f9 f9 f9 f9 00 01 f9 f9 f9 f9 f9 f9 + ffffffff83e18080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + >ffffffff83e18100: 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 00 05 f9 f9 + ^ + ffffffff83e18180: f9 f9 f9 f9 00 00 00 00 00 00 00 04 f9 f9 f9 f9 + ffffffff83e18200: 00 00 00 00 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9 + ================================================================== + +Seems like the TPM chip supports sha3_256, which isn't yet in +tpm_algorithms: + tpm tpm0: TPM with unsupported bank algorithm 0x0027 + +That's TPM_ALG_SHA3_256 == 0x0027 from "Trusted Platform Module 2.0 +Library Part 2: Structures", page 51 [1]. +See also the related U-Boot algorithms update [2]. + +Thus solve the problem by creating a file name with "_tpm_alg_" +postfix if the crypto algorithm isn't initialized. + +This is how it looks on the test machine (patch ported to v6.12 release): + # ls -1 /sys/kernel/security/ima/ + ascii_runtime_measurements + ascii_runtime_measurements_tpm_alg_27 + ascii_runtime_measurements_sha1 + ascii_runtime_measurements_sha256 + binary_runtime_measurements + binary_runtime_measurements_tpm_alg_27 + binary_runtime_measurements_sha1 + binary_runtime_measurements_sha256 + policy + runtime_measurements_count + violations + +[1]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-2-Version-184_pub.pdf +[2]: https://lists.denx.de/pipermail/u-boot/2024-July/558835.html + +Fixes: 9fa8e7625008 ("ima: add crypto agility support for template-hash algorithm") +Signed-off-by: Dmitry Safonov +Cc: Enrico Bravi +Cc: Silvia Sisinni +Cc: Roberto Sassu +Cc: Mimi Zohar +Reviewed-by: Roberto Sassu +Tested-by: Roberto Sassu +Link: https://github.com/linux-integrity/linux/issues/14 +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_fs.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index 87045b09f1206..25970867f594e 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -404,16 +404,24 @@ static int __init create_securityfs_measurement_lists(void) + char file_name[NAME_MAX + 1]; + struct dentry *dentry; + +- sprintf(file_name, "ascii_runtime_measurements_%s", +- hash_algo_name[algo]); ++ if (algo == HASH_ALGO__LAST) ++ sprintf(file_name, "ascii_runtime_measurements_tpm_alg_%x", ++ ima_tpm_chip->allocated_banks[i].alg_id); ++ else ++ sprintf(file_name, "ascii_runtime_measurements_%s", ++ hash_algo_name[algo]); + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP, + ima_dir, (void *)(uintptr_t)i, + &ima_ascii_measurements_ops); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + +- sprintf(file_name, "binary_runtime_measurements_%s", +- hash_algo_name[algo]); ++ if (algo == HASH_ALGO__LAST) ++ sprintf(file_name, "binary_runtime_measurements_tpm_alg_%x", ++ ima_tpm_chip->allocated_banks[i].alg_id); ++ else ++ sprintf(file_name, "binary_runtime_measurements_%s", ++ hash_algo_name[algo]); + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP, + ima_dir, (void *)(uintptr_t)i, + &ima_measurements_ops); +-- +2.53.0 + diff --git a/queue-6.18/io_uring-napi-cap-busy_poll_to-10-msec.patch b/queue-6.18/io_uring-napi-cap-busy_poll_to-10-msec.patch new file mode 100644 index 0000000000..0bd739a0d4 --- /dev/null +++ b/queue-6.18/io_uring-napi-cap-busy_poll_to-10-msec.patch @@ -0,0 +1,41 @@ +From 30b5df489157736be8820f5d2bb2fa4213a3466a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 14:42:18 -0600 +Subject: io_uring/napi: cap busy_poll_to 10 msec + +From: Jens Axboe + +[ Upstream commit df8599ee18c0e5fe343ffe0b4c379636b8bb839a ] + +Currently there's no cap on the maximum amount of time that napi is +allowed to poll if no events are found, which can lead to kernel +complaints on a task being stuck as there's no conditional rescheduling +done within that loop. + +Just cap it to 10 msec in total, that's already way above any kind of +sane value that will reap any benefits, yet low enough that it's +nowhere near being able to trigger preemption complaints. + +Fixes: 8d0c12a80cde ("io-uring: add napi busy poll support") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/napi.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/io_uring/napi.c b/io_uring/napi.c +index 4a10de03e4269..8d68366a4b903 100644 +--- a/io_uring/napi.c ++++ b/io_uring/napi.c +@@ -276,6 +276,8 @@ static int io_napi_register_napi(struct io_ring_ctx *ctx, + /* clean the napi list for new settings */ + io_napi_free(ctx); + WRITE_ONCE(ctx->napi_track_mode, napi->op_param); ++ /* cap NAPI at 10 msec of spin time */ ++ napi->busy_poll_to = min(10000, napi->busy_poll_to); + WRITE_ONCE(ctx->napi_busy_poll_dt, napi->busy_poll_to * NSEC_PER_USEC); + WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi->prefer_busy_poll); + return 0; +-- +2.53.0 + diff --git a/queue-6.18/iommu-amd-fix-clone_alias-to-use-the-original-device.patch b/queue-6.18/iommu-amd-fix-clone_alias-to-use-the-original-device.patch new file mode 100644 index 0000000000..3561263b22 --- /dev/null +++ b/queue-6.18/iommu-amd-fix-clone_alias-to-use-the-original-device.patch @@ -0,0 +1,64 @@ +From 7a9c34291941f9753fc0f978e88dbef82bc0cce7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:00:17 +0000 +Subject: iommu/amd: Fix clone_alias() to use the original device's devid + +From: Vasant Hegde + +[ Upstream commit faad224fe0f0857a04ff2eb3c90f0de57f47d0f3 ] + +Currently clone_alias() assumes first argument (pdev) is always the +original device pointer. This function is called by +pci_for_each_dma_alias() which based on topology decides to send +original or alias device details in first argument. + +This meant that the source devid used to look up and copy the DTE +may be incorrect, leading to wrong or stale DTE entries being +propagated to alias device. + +Fix this by passing the original pdev as the opaque data argument to +both the direct clone_alias() call and pci_for_each_dma_alias(). Inside +clone_alias(), retrieve the original device from data and compute devid +from it. + +Fixes: 3332364e4ebc ("iommu/amd: Support multiple PCI DMA aliases in device table") +Signed-off-by: Vasant Hegde +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 4beef73139611..5afd1621d715e 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -381,11 +381,12 @@ struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devid) + return NULL; + } + +-static int clone_alias(struct pci_dev *pdev, u16 alias, void *data) ++static int clone_alias(struct pci_dev *pdev_origin, u16 alias, void *data) + { + struct dev_table_entry new; + struct amd_iommu *iommu; + struct iommu_dev_data *dev_data, *alias_data; ++ struct pci_dev *pdev = data; + u16 devid = pci_dev_id(pdev); + int ret = 0; + +@@ -432,9 +433,9 @@ static void clone_aliases(struct amd_iommu *iommu, struct device *dev) + * part of the PCI DMA aliases if it's bus differs + * from the original device. + */ +- clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], NULL); ++ clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], pdev); + +- pci_for_each_dma_alias(pdev, clone_alias, NULL); ++ pci_for_each_dma_alias(pdev, clone_alias, pdev); + } + + static void setup_aliases(struct amd_iommu *iommu, struct device *dev) +-- +2.53.0 + diff --git a/queue-6.18/iommu-riscv-add-iotinval-after-updating-ddt-pdt-entr.patch b/queue-6.18/iommu-riscv-add-iotinval-after-updating-ddt-pdt-entr.patch new file mode 100644 index 0000000000..60d8a091f0 --- /dev/null +++ b/queue-6.18/iommu-riscv-add-iotinval-after-updating-ddt-pdt-entr.patch @@ -0,0 +1,121 @@ +From 43573767fa8b5660391384cc23eb752eace26978 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:32:24 +0800 +Subject: iommu/riscv: Add IOTINVAL after updating DDT/PDT entries + +From: Fangyu Yu + +[ Upstream commit f5c262b544975e067ea265fc7403aefbbea8563e ] + +Add riscv_iommu_iodir_iotinval() to perform required TLB and context cache +invalidations after updating DDT or PDT entries, as mandated by the RISC-V +IOMMU specification (Section 6.3.1 and 6.3.2). + +Fixes: 488ffbf18171 ("iommu/riscv: Paging domain support") +Signed-off-by: Fangyu Yu +Reviewed-by: Andrew Jones +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu.c | 70 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 70 insertions(+) + +diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c +index ebb22979075df..c183818015813 100644 +--- a/drivers/iommu/riscv/iommu.c ++++ b/drivers/iommu/riscv/iommu.c +@@ -996,7 +996,67 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain, + } + + #define RISCV_IOMMU_FSC_BARE 0 ++/* ++ * This function sends IOTINVAL commands as required by the RISC-V ++ * IOMMU specification (Section 6.3.1 and 6.3.2 in 1.0 spec version) ++ * after modifying DDT or PDT entries ++ */ ++static void riscv_iommu_iodir_iotinval(struct riscv_iommu_device *iommu, ++ bool inval_pdt, unsigned long iohgatp, ++ struct riscv_iommu_dc *dc, ++ struct riscv_iommu_pc *pc) ++{ ++ struct riscv_iommu_command cmd; ++ ++ riscv_iommu_cmd_inval_vma(&cmd); + ++ if (FIELD_GET(RISCV_IOMMU_DC_IOHGATP_MODE, iohgatp) == ++ RISCV_IOMMU_DC_IOHGATP_MODE_BARE) { ++ if (inval_pdt) { ++ /* ++ * IOTINVAL.VMA with GV=AV=0, and PSCV=1, and ++ * PSCID=PC.PSCID ++ */ ++ riscv_iommu_cmd_inval_set_pscid(&cmd, ++ FIELD_GET(RISCV_IOMMU_PC_TA_PSCID, pc->ta)); ++ } else { ++ if (!FIELD_GET(RISCV_IOMMU_DC_TC_PDTV, dc->tc) && ++ FIELD_GET(RISCV_IOMMU_DC_FSC_MODE, dc->fsc) != ++ RISCV_IOMMU_DC_FSC_MODE_BARE) { ++ /* ++ * DC.tc.PDTV == 0 && DC.fsc.MODE != Bare ++ * IOTINVAL.VMA with GV=AV=0, and PSCV=1, and ++ * PSCID=DC.ta.PSCID ++ */ ++ riscv_iommu_cmd_inval_set_pscid(&cmd, ++ FIELD_GET(RISCV_IOMMU_DC_TA_PSCID, dc->ta)); ++ } ++ /* else: IOTINVAL.VMA with GV=AV=PSCV=0 */ ++ } ++ } else { ++ riscv_iommu_cmd_inval_set_gscid(&cmd, ++ FIELD_GET(RISCV_IOMMU_DC_IOHGATP_GSCID, iohgatp)); ++ ++ if (inval_pdt) { ++ /* ++ * IOTINVAL.VMA with GV=1, AV=0, and PSCV=1, and ++ * GSCID=DC.iohgatp.GSCID, PSCID=PC.PSCID ++ */ ++ riscv_iommu_cmd_inval_set_pscid(&cmd, ++ FIELD_GET(RISCV_IOMMU_PC_TA_PSCID, pc->ta)); ++ } ++ /* ++ * else: IOTINVAL.VMA with GV=1,AV=PSCV=0,and ++ * GSCID=DC.iohgatp.GSCID ++ * ++ * IOTINVAL.GVMA with GV=1,AV=0,and ++ * GSCID=DC.iohgatp.GSCID ++ * TODO: For now, the Second-Stage feature have not yet been merged, ++ * also issue IOTINVAL.GVMA once second-stage support is merged. ++ */ ++ } ++ riscv_iommu_cmd_send(iommu, &cmd); ++} + /* + * Update IODIR for the device. + * +@@ -1031,6 +1091,11 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu, + riscv_iommu_cmd_iodir_inval_ddt(&cmd); + riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]); + riscv_iommu_cmd_send(iommu, &cmd); ++ /* ++ * For now, the SVA and PASID features have not yet been merged, the ++ * default configuration is inval_pdt=false and pc=NULL. ++ */ ++ riscv_iommu_iodir_iotinval(iommu, false, dc->iohgatp, dc, NULL); + sync_required = true; + } + +@@ -1056,6 +1121,11 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu, + riscv_iommu_cmd_iodir_inval_ddt(&cmd); + riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]); + riscv_iommu_cmd_send(iommu, &cmd); ++ /* ++ * For now, the SVA and PASID features have not yet been merged, the ++ * default configuration is inval_pdt=false and pc=NULL. ++ */ ++ riscv_iommu_iodir_iotinval(iommu, false, dc->iohgatp, dc, NULL); + } + + riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT); +-- +2.53.0 + diff --git a/queue-6.18/iommu-riscv-add-missing-generic_msi_irq.patch b/queue-6.18/iommu-riscv-add-missing-generic_msi_irq.patch new file mode 100644 index 0000000000..0cb6d26f82 --- /dev/null +++ b/queue-6.18/iommu-riscv-add-missing-generic_msi_irq.patch @@ -0,0 +1,39 @@ +From f1518ca0b7af72471b4942326c75398670b0b456 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 11:25:40 -0400 +Subject: iommu/riscv: Add missing GENERIC_MSI_IRQ + +From: Jason Gunthorpe + +[ Upstream commit c70d20b25ca30d68b377b9363a2adca6eb2538e3 ] + +The commit below added MSI related calls to the driver that depends on +GENERIC_MSI_IRQ. It is possible to build RISC-V without this selected. + +This is also necessary to make the driver COMPILE_TEST. + +Fixes: d5f88acdd6ff ("iommu/riscv: Add support for platform msi") +Tested-by: Vincent Chen +Tested-by: Tomasz Jeznach +Signed-off-by: Jason Gunthorpe +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig +index c071816f59a67..fb8e217edc3d3 100644 +--- a/drivers/iommu/riscv/Kconfig ++++ b/drivers/iommu/riscv/Kconfig +@@ -4,6 +4,7 @@ + config RISCV_IOMMU + bool "RISC-V IOMMU Support" + depends on RISCV && 64BIT ++ depends on GENERIC_MSI_IRQ + default y + select IOMMU_API + help +-- +2.53.0 + diff --git a/queue-6.18/iommu-riscv-fix-signedness-bug.patch b/queue-6.18/iommu-riscv-fix-signedness-bug.patch new file mode 100644 index 0000000000..448b0174d6 --- /dev/null +++ b/queue-6.18/iommu-riscv-fix-signedness-bug.patch @@ -0,0 +1,52 @@ +From 3d3c3cd01c346ee97f42ee76d3c210216d2af41c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:26:44 -0500 +Subject: iommu/riscv: Fix signedness bug + +From: Ethan Tidmore + +[ Upstream commit 553a127cb66523089bc10eb54640205495f4bb5b ] + +The function platform_irq_count() returns negative error codes and +iommu->irqs_count is an unsigned integer, so the check +(iommu->irqs_count <= 0) is always impossible. + +Make the return value of platform_irq_count() be assigned to ret, check +for error, and then assign iommu->irqs_count to ret. + +Detected by Smatch: +drivers/iommu/riscv/iommu-platform.c:119 riscv_iommu_platform_probe() warn: +'iommu->irqs_count' unsigned <= 0 + +Signed-off-by: Ethan Tidmore +Fixes: 5c0ebbd3c6c6 ("iommu/riscv: Add RISC-V IOMMU platform device driver") +Reviewed-by: Andrew Jones +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu-platform.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c +index 8f15b06e84997..399ba8fe1b3e5 100644 +--- a/drivers/iommu/riscv/iommu-platform.c ++++ b/drivers/iommu/riscv/iommu-platform.c +@@ -115,10 +115,13 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev) + fallthrough; + + case RISCV_IOMMU_CAPABILITIES_IGS_WSI: +- iommu->irqs_count = platform_irq_count(pdev); +- if (iommu->irqs_count <= 0) ++ ret = platform_irq_count(pdev); ++ if (ret <= 0) + return dev_err_probe(dev, -ENODEV, + "no IRQ resources provided\n"); ++ ++ iommu->irqs_count = ret; ++ + if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT) + iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; + +-- +2.53.0 + diff --git a/queue-6.18/iommu-riscv-remove-overflows-on-the-invalidation-pat.patch b/queue-6.18/iommu-riscv-remove-overflows-on-the-invalidation-pat.patch new file mode 100644 index 0000000000..ed824821ca --- /dev/null +++ b/queue-6.18/iommu-riscv-remove-overflows-on-the-invalidation-pat.patch @@ -0,0 +1,58 @@ +From 13a55c8c9a14674f31fb90be36bf3f7a7d257c8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 12:22:10 -0300 +Subject: iommu/riscv: Remove overflows on the invalidation path + +From: Jason Gunthorpe + +[ Upstream commit 40a13b49957937427bc23e78eb50679df4396a47 ] + +Since RISC-V supports a sign extended page table it should support +a gather->end of ULONG_MAX, but if this happens it will infinite loop +because of the overflow. + +Also avoid overflow computing the length by moving the +1 to the other +side of the < + +Fixes: 488ffbf18171 ("iommu/riscv: Paging domain support") +Signed-off-by: Jason Gunthorpe +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c +index 1e8007a153c32..de286563bd44e 100644 +--- a/drivers/iommu/riscv/iommu.c ++++ b/drivers/iommu/riscv/iommu.c +@@ -931,8 +931,6 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain, + struct riscv_iommu_bond *bond; + struct riscv_iommu_device *iommu, *prev; + struct riscv_iommu_command cmd; +- unsigned long len = end - start + 1; +- unsigned long iova; + + /* + * For each IOMMU linked with this protection domain (via bonds->dev), +@@ -975,11 +973,14 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain, + + riscv_iommu_cmd_inval_vma(&cmd); + riscv_iommu_cmd_inval_set_pscid(&cmd, domain->pscid); +- if (len && len < RISCV_IOMMU_IOTLB_INVAL_LIMIT) { +- for (iova = start; iova < end; iova += PAGE_SIZE) { ++ if (end - start < RISCV_IOMMU_IOTLB_INVAL_LIMIT - 1) { ++ unsigned long iova = start; ++ ++ do { + riscv_iommu_cmd_inval_set_addr(&cmd, iova); + riscv_iommu_cmd_send(iommu, &cmd); +- } ++ } while (!check_add_overflow(iova, PAGE_SIZE, &iova) && ++ iova < end); + } else { + riscv_iommu_cmd_send(iommu, &cmd); + } +-- +2.53.0 + diff --git a/queue-6.18/iommu-riscv-skip-irq-count-check-when-using-msi-inte.patch b/queue-6.18/iommu-riscv-skip-irq-count-check-when-using-msi-inte.patch new file mode 100644 index 0000000000..3d5e874fe3 --- /dev/null +++ b/queue-6.18/iommu-riscv-skip-irq-count-check-when-using-msi-inte.patch @@ -0,0 +1,67 @@ +From b5ec316faaded615d56cd900f6b5edf6b503063e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:54:20 +0800 +Subject: iommu/riscv: Skip IRQ count check when using MSI interrupts + +From: Yaxing Guo + +[ Upstream commit 7217cee35aadbb07e12673bcf1dcf729e1b2f6c9 ] + +In RISC-V IOMMU platform devices that use MSI interrupts (indicated by the +presence of 'msi-parent' in the device tree), there are no wired interrupt +lines, so calling platform_get_irq_count() returns 0 or -ENXIO, causing the +driver to fail during probe. + +However, MSI interrupts are allocated dynamically via the MSI subsystem and +do not appear in the device tree 'interrupts' property. Therefore, the +driver should not require a non-zero IRQ count when 'msi-parent' is present. + +This patch fixes the bug where probe fails when using MSI interrupts + (which do not have an 'interrupts' property in the device tree).. + +Fixes: ("iommu/riscv: Add support for platform msi") + +Signed-off-by: Yaxing Guo +Reviewed-by: Andrew Jones +Signed-off-by: Joerg Roedel +Stable-dep-of: 553a127cb665 ("iommu/riscv: Fix signedness bug") +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu-platform.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c +index 83a28c83f9914..8f15b06e84997 100644 +--- a/drivers/iommu/riscv/iommu-platform.c ++++ b/drivers/iommu/riscv/iommu-platform.c +@@ -68,12 +68,7 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev) + iommu->caps = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_CAPABILITIES); + iommu->fctl = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_FCTL); + +- iommu->irqs_count = platform_irq_count(pdev); +- if (iommu->irqs_count <= 0) +- return dev_err_probe(dev, -ENODEV, +- "no IRQ resources provided\n"); +- if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT) +- iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; ++ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; + + igs = FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS, iommu->caps); + switch (igs) { +@@ -120,6 +115,13 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev) + fallthrough; + + case RISCV_IOMMU_CAPABILITIES_IGS_WSI: ++ iommu->irqs_count = platform_irq_count(pdev); ++ if (iommu->irqs_count <= 0) ++ return dev_err_probe(dev, -ENODEV, ++ "no IRQ resources provided\n"); ++ if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT) ++ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; ++ + for (vec = 0; vec < iommu->irqs_count; vec++) + iommu->irqs[vec] = platform_get_irq(pdev, vec); + +-- +2.53.0 + diff --git a/queue-6.18/iommu-riscv-stop-polling-when-cqcsr-reports-an-error.patch b/queue-6.18/iommu-riscv-stop-polling-when-cqcsr-reports-an-error.patch new file mode 100644 index 0000000000..1170d426e6 --- /dev/null +++ b/queue-6.18/iommu-riscv-stop-polling-when-cqcsr-reports-an-error.patch @@ -0,0 +1,55 @@ +From ee0a586be8e8e07bd6de73be0d3c853242d6c853 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 19:26:40 +0800 +Subject: iommu/riscv: Stop polling when CQCSR reports an error + +From: Fangyu Yu + +[ Upstream commit b2e5684558edf3e9bbe18d0e0043854994eab1be ] + +The cmdq wait loop busy-polls the consumer index until it advances +or the software timeout expires. If the IOMMU has already signaled +a command queue failure in CQCSR, continuing to poll for progress is +pointless. + +Make riscv_iommu_queue_wait() also terminate the poll when any of these +CQCSR error bits are observed. + +This helps the caller return earlier in failure cases and avoids +spinning until the full timeout interval when the hardware has already +reported an error. On single-core systems in particular, the current +busy-wait can delay servicing the command-timeout interrupt until the +software timeout expires (90s by default). + +Fixes: 856c0cfe5c5f ("iommu/riscv: Command and fault queue support") +Signed-off-by: Fangyu Yu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c +index c183818015813..1e8007a153c32 100644 +--- a/drivers/iommu/riscv/iommu.c ++++ b/drivers/iommu/riscv/iommu.c +@@ -368,6 +368,8 @@ static int riscv_iommu_queue_wait(struct riscv_iommu_queue *queue, + unsigned int timeout_us) + { + unsigned int cons = atomic_read(&queue->head); ++ unsigned int flags = RISCV_IOMMU_CQCSR_CQMF | RISCV_IOMMU_CQCSR_CMD_TO | ++ RISCV_IOMMU_CQCSR_CMD_ILL; + + /* Already processed by the consumer */ + if ((int)(cons - index) > 0) +@@ -375,6 +377,7 @@ static int riscv_iommu_queue_wait(struct riscv_iommu_queue *queue, + + /* Monitor consumer index */ + return readx_poll_timeout(riscv_iommu_queue_cons, queue, cons, ++ (riscv_iommu_readl(queue->iommu, queue->qcr) & flags) || + (int)(cons - index) > 0, 0, timeout_us); + } + +-- +2.53.0 + diff --git a/queue-6.18/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch b/queue-6.18/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch new file mode 100644 index 0000000000..1f66add070 --- /dev/null +++ b/queue-6.18/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch @@ -0,0 +1,65 @@ +From e7125f2229219442b00cf934dade4837b47b316e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:36:34 -0700 +Subject: iommu/tegra241-cmdqv: Set supports_cmd op in tegra241_vcmdq_hw_init() + +From: Nicolin Chen + +[ Upstream commit 803e41f36d227022ab9bbe780c82283fd4713b2e ] + +vintf->hyp_own is finalized in tegra241_vintf_hw_init(). On the other hand, +tegra241_vcmdq_alloc_smmu_cmdq() is called via an init_structures callback, +which is earlier than tegra241_vintf_hw_init(). + +This results in the supports_cmd op always being set to the guest function, +although this doesn't break any functionality nor have some noticeable perf +impact since non-invalidation commands are not issued in the perf sensitive +context. + +Fix this by moving supports_cmd to tegra241_vcmdq_hw_init(). + +After this change, + - For a guest kernel, this will be a status quo + - For a host kernel, non-invalidation commands will be issued to VCMDQ(s) + +Fixes: a9d40285bdef ("iommu/tegra241-cmdqv: Limit CMDs for VCMDQs of a guest owned VINTF") +Reported-by: Eric Auger +Reported-by: Shameer Kolothum +Closes: https://lore.kernel.org/qemu-devel/CH3PR12MB754836BEE54E39B30C7210C0AB44A@CH3PR12MB7548.namprd12.prod.outlook.com/ +Signed-off-by: Nicolin Chen +Reviewed-by: Eric Auger +Tested-by: Shameer Kolothum +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +index 04cc7a9036e43..17591d8eb64b8 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c ++++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +@@ -481,6 +481,10 @@ static int tegra241_vcmdq_hw_init(struct tegra241_vcmdq *vcmdq) + /* Reset VCMDQ */ + tegra241_vcmdq_hw_deinit(vcmdq); + ++ /* vintf->hyp_own is a HW state finalized in tegra241_vintf_hw_init() */ ++ if (!vcmdq->vintf->hyp_own) ++ vcmdq->cmdq.supports_cmd = tegra241_guest_vcmdq_supports_cmd; ++ + /* Configure and enable VCMDQ */ + writeq_relaxed(vcmdq->cmdq.q.q_base, REG_VCMDQ_PAGE1(vcmdq, BASE)); + +@@ -641,9 +645,6 @@ static int tegra241_vcmdq_alloc_smmu_cmdq(struct tegra241_vcmdq *vcmdq) + q->q_base = q->base_dma & VCMDQ_ADDR; + q->q_base |= FIELD_PREP(VCMDQ_LOG2SIZE, q->llq.max_n_shift); + +- if (!vcmdq->vintf->hyp_own) +- cmdq->supports_cmd = tegra241_guest_vcmdq_supports_cmd; +- + return arm_smmu_cmdq_init(smmu, cmdq); + } + +-- +2.53.0 + diff --git a/queue-6.18/iommu-tegra241-cmdqv-update-uapi-to-clarify-hyp_own-.patch b/queue-6.18/iommu-tegra241-cmdqv-update-uapi-to-clarify-hyp_own-.patch new file mode 100644 index 0000000000..6a0d339e5c --- /dev/null +++ b/queue-6.18/iommu-tegra241-cmdqv-update-uapi-to-clarify-hyp_own-.patch @@ -0,0 +1,48 @@ +From 7ce6b627234f28b9a75cf53cb56e989e99a8d659 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:36:35 -0700 +Subject: iommu/tegra241-cmdqv: Update uAPI to clarify HYP_OWN requirement + +From: Nicolin Chen + +[ Upstream commit 9dcef98dbee35b8ae784df04c041efffdd42a69c ] + +>From hardware implementation perspective, a guest tegra241-cmdqv hardware +is different than the host hardware: + - Host HW is backed by a VINTF (HYP_OWN=1) + - Guest HW is backed by a VINTF (HYP_OWN=0) + +The kernel driver has an implementation requirement of the HYP_OWN bit in +the VM. So, VMM must follow that to allow the same copy of Linux to work. + +Add this requirement to the uAPI, which is currently missing. + +Fixes: 4dc0d12474f9 ("iommu/tegra241-cmdqv: Add user-space use support") +Signed-off-by: Nicolin Chen +Reviewed-by: Eric Auger +Reviewed-by: Jason Gunthorpe +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + include/uapi/linux/iommufd.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h +index c218c89e0e2eb..bdd20666d1eb1 100644 +--- a/include/uapi/linux/iommufd.h ++++ b/include/uapi/linux/iommufd.h +@@ -1003,6 +1003,11 @@ struct iommu_fault_alloc { + enum iommu_viommu_type { + IOMMU_VIOMMU_TYPE_DEFAULT = 0, + IOMMU_VIOMMU_TYPE_ARM_SMMUV3 = 1, ++ /* ++ * TEGRA241_CMDQV requirements (otherwise, VCMDQs will not work) ++ * - Kernel will allocate a VINTF (HYP_OWN=0) to back this VIOMMU. So, ++ * VMM must wire the HYP_OWN bit to 0 in guest VINTF_CONFIG register ++ */ + IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2, + }; + +-- +2.53.0 + diff --git a/queue-6.18/iommufd-selftest-fix-page-leaks-in-mock_viommu_-init.patch b/queue-6.18/iommufd-selftest-fix-page-leaks-in-mock_viommu_-init.patch new file mode 100644 index 0000000000..a2fb82e11f --- /dev/null +++ b/queue-6.18/iommufd-selftest-fix-page-leaks-in-mock_viommu_-init.patch @@ -0,0 +1,50 @@ +From 59eabb4dd32ad5bfbf19ccc1e9b97898258bfc0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:40:42 +0100 +Subject: iommufd/selftest: Fix page leaks in mock_viommu_{init,destroy} + +From: Thorsten Blum + +[ Upstream commit 09c091fddb0b93297ea659ab48ee64f54ebeeaa2 ] + +mock_viommu_init() allocates two pages using __get_free_pages(..., 1), +but its error path and mock_viommu_destroy() only release the first page +using free_page(), leaking the second page. Use free_pages() with the +matching order instead to avoid any page leaks. + +Fixes: 80478a2b450e ("iommufd/selftest: Add coverage for the new mmap interface") +Link: https://patch.msgid.link/r/20260312164040.457293-3-thorsten.blum@linux.dev +Signed-off-by: Thorsten Blum +Reviewed-by: Nicolin Chen +Reviewed-by: Pranjal Shrivastava +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommufd/selftest.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c +index dc0947aaac625..8fd27f65d6237 100644 +--- a/drivers/iommu/iommufd/selftest.c ++++ b/drivers/iommu/iommufd/selftest.c +@@ -699,7 +699,7 @@ static void mock_viommu_destroy(struct iommufd_viommu *viommu) + if (mock_viommu->mmap_offset) + iommufd_viommu_destroy_mmap(&mock_viommu->core, + mock_viommu->mmap_offset); +- free_page((unsigned long)mock_viommu->page); ++ free_pages((unsigned long)mock_viommu->page, 1); + mutex_destroy(&mock_viommu->queue_mutex); + + /* iommufd core frees mock_viommu and viommu */ +@@ -933,7 +933,7 @@ static int mock_viommu_init(struct iommufd_viommu *viommu, + iommufd_viommu_destroy_mmap(&mock_viommu->core, + mock_viommu->mmap_offset); + err_free_page: +- free_page((unsigned long)mock_viommu->page); ++ free_pages((unsigned long)mock_viommu->page, 1); + return rc; + } + +-- +2.53.0 + diff --git a/queue-6.18/iommufd-vfio-compatibility-extension-check-for-noiom.patch b/queue-6.18/iommufd-vfio-compatibility-extension-check-for-noiom.patch new file mode 100644 index 0000000000..f0f190d5ab --- /dev/null +++ b/queue-6.18/iommufd-vfio-compatibility-extension-check-for-noiom.patch @@ -0,0 +1,40 @@ +From 3c9388268b35814733e86fd2e77ec5c9fce7fc4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 10:36:36 -0800 +Subject: iommufd: vfio compatibility extension check for noiommu mode + +From: Jacob Pan + +[ Upstream commit 7147ec874ea08c322d779d8eba28946e294ed1f3 ] + +VFIO_CHECK_EXTENSION should return false for TYPE1_IOMMU variants when +in NO-IOMMU mode and IOMMUFD compat container is set. This change makes +the behavior match VFIO_CONTAINER in noiommu mode. It also prevents +userspace from incorrectly attempting to use TYPE1 IOMMU operations +in a no-iommu context. + +Fixes: d624d6652a65 ("iommufd: vfio container FD ioctl compatibility") +Link: https://patch.msgid.link/r/20260213183636.3340-1-jacob.pan@linux.microsoft.com +Signed-off-by: Jacob Pan +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommufd/vfio_compat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c +index a258ee2f4579f..acb48cdd3b005 100644 +--- a/drivers/iommu/iommufd/vfio_compat.c ++++ b/drivers/iommu/iommufd/vfio_compat.c +@@ -283,7 +283,7 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx, + case VFIO_TYPE1_IOMMU: + case VFIO_TYPE1v2_IOMMU: + case VFIO_UNMAP_ALL: +- return 1; ++ return !ictx->no_iommu_mode; + + case VFIO_NOIOMMU_IOMMU: + return IS_ENABLED(CONFIG_VFIO_NOIOMMU); +-- +2.53.0 + diff --git a/queue-6.18/iopoll-fix-function-parameter-names-in-read_poll_tim.patch b/queue-6.18/iopoll-fix-function-parameter-names-in-read_poll_tim.patch new file mode 100644 index 0000000000..d2946c958b --- /dev/null +++ b/queue-6.18/iopoll-fix-function-parameter-names-in-read_poll_tim.patch @@ -0,0 +1,56 @@ +From d77d948efe9de34eef9ecd7c9231377263bd8333 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 14:10:32 -0800 +Subject: iopoll: fix function parameter names in read_poll_timeout_atomic() + +From: Randy Dunlap + +[ Upstream commit 878004e2852bc22ce0687c5597d6fe3909fb59f3 ] + +Correct the function parameter names to avoid kernel-doc warnings +and to emphasize this function is atomic (non-sleeping). + +Warning: include/linux/iopoll.h:169 function parameter 'sleep_us' not + described in 'read_poll_timeout_atomic' +Warning: ../include/linux/iopoll.h:169 function parameter + 'sleep_before_read' not described in 'read_poll_timeout_atomic' + +Fixes: 9df8043a546d ("iopoll: Generalize read_poll_timeout() into poll_timeout_us()") +Signed-off-by: Randy Dunlap +Reviewed-by: Jani Nikula +Link: https://patch.msgid.link/20260306221033.2357305-1-rdunlap@infradead.org +Signed-off-by: Jani Nikula +Signed-off-by: Sasha Levin +--- + include/linux/iopoll.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h +index bdd2e0652bc30..53edd69acb9bd 100644 +--- a/include/linux/iopoll.h ++++ b/include/linux/iopoll.h +@@ -159,7 +159,7 @@ + * + * This macro does not rely on timekeeping. Hence it is safe to call even when + * timekeeping is suspended, at the expense of an underestimation of wall clock +- * time, which is rather minimal with a non-zero delay_us. ++ * time, which is rather minimal with a non-zero @delay_us. + * + * When available, you'll probably want to use one of the specialized + * macros defined below rather than this macro directly. +@@ -167,9 +167,9 @@ + * Returns: 0 on success and -ETIMEDOUT upon a timeout. In either + * case, the last read value at @args is stored in @val. + */ +-#define read_poll_timeout_atomic(op, val, cond, sleep_us, timeout_us, \ +- sleep_before_read, args...) \ +- poll_timeout_us_atomic((val) = op(args), cond, sleep_us, timeout_us, sleep_before_read) ++#define read_poll_timeout_atomic(op, val, cond, delay_us, timeout_us, \ ++ delay_before_read, args...) \ ++ poll_timeout_us_atomic((val) = op(args), cond, delay_us, timeout_us, delay_before_read) + + /** + * readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs +-- +2.53.0 + diff --git a/queue-6.18/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch b/queue-6.18/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch new file mode 100644 index 0000000000..cb62b69ac0 --- /dev/null +++ b/queue-6.18/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch @@ -0,0 +1,114 @@ +From 46582736ceecfc0ab0b7dab37fc4fe64c264bfd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:06:01 +0800 +Subject: ipmi: ssif_bmc: change log level to dbg in irq callback + +From: Jian Zhang + +[ Upstream commit c9c99b7b7051eb7121b3224bfce181fb023b0269 ] + +Long-running tests indicate that this logging can occasionally disrupt +timing and lead to request/response corruption. + +Irq handler need to be executed as fast as possible, +most I2C slave IRQ implementations are byte-level, logging here +can significantly affect transfer behavior and timing. It is recommended +to use dev_dbg() for these messages. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-4-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index ca185793cf978..a45e80d13e10e 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -569,7 +569,7 @@ static void process_request_part(struct ssif_bmc_ctx *ssif_bmc) + len = ssif_bmc->request.len + part->length; + /* Do the bound check here, not allow the request len exceed 254 bytes */ + if (len > IPMI_SSIF_PAYLOAD_MAX) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: Request exceeded 254 bytes, aborting"); + /* Request too long, aborting */ + ssif_bmc->aborting = true; +@@ -615,7 +615,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected READ REQUESTED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -624,7 +624,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + if (!supported_read_cmd(ssif_bmc->part_buf.smbus_cmd)) { +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", + ssif_bmc->part_buf.smbus_cmd); + ssif_bmc->aborting = true; + } +@@ -659,7 +659,7 @@ static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_SMBUS_CMD) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected READ PROCESSED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -684,7 +684,7 @@ static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + } else if (ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE REQUEST in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -699,7 +699,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + { + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -709,7 +709,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + if (!supported_write_cmd(ssif_bmc->part_buf.smbus_cmd)) { +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", + ssif_bmc->part_buf.smbus_cmd); + ssif_bmc->aborting = true; + } +@@ -738,7 +738,7 @@ static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_SMBUS_CMD || + ssif_bmc->state == SSIF_ABORTING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected SLAVE STOP in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_READY; +@@ -805,7 +805,7 @@ static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 + break; + + default: +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); + break; + } + +-- +2.53.0 + diff --git a/queue-6.18/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch b/queue-6.18/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch new file mode 100644 index 0000000000..1d5e045a8c --- /dev/null +++ b/queue-6.18/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch @@ -0,0 +1,88 @@ +From 5041d6f99024c3fcc3db83831c95dd711a602f8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:06:00 +0800 +Subject: ipmi: ssif_bmc: fix message desynchronization after truncated + response + +From: Jian Zhang + +[ Upstream commit 1d38e849adb6851ee280aa1a1d687b2181549a66 ] + +A truncated response, caused by host power-off, or other conditions, +can lead to message desynchronization. + +Raw trace data (STOP loss scenario, add state transition comment): + +1. T-1: Read response phase (SSIF_RES_SENDING) +8271.955342 WR_RCV [03] <- Read polling cmd +8271.955348 RD_REQ [04] <== SSIF_RES_SENDING <- start sending response +8271.955436 RD_PRO [b4] +8271.955527 RD_PRO [00] +8271.955618 RD_PRO [c1] +8271.955707 RD_PRO [00] +8271.955814 RD_PRO [ad] <== SSIF_RES_SENDING <- last byte + <- !! STOP lost (truncated response) + +2. T: New Write request arrives, BMC still in SSIF_RES_SENDING +8271.967973 WR_REQ [] <== SSIF_RES_SENDING >> SSIF_ABORTING <- log: unexpected WR_REQ in RES_SENDING +8271.968447 WR_RCV [02] <== SSIF_ABORTING <- do nothing +8271.968452 WR_RCV [02] <== SSIF_ABORTING <- do nothing +8271.968454 WR_RCV [18] <== SSIF_ABORTING <- do nothing +8271.968456 WR_RCV [01] <== SSIF_ABORTING <- do nothing +8271.968458 WR_RCV [66] <== SSIF_ABORTING <- do nothing +8271.978714 STOP [] <== SSIF_ABORTING >> SSIF_READY <- log: unexpected SLAVE STOP in state=SSIF_ABORTING + +3. T+1: Next Read polling, treated as a fresh transaction +8271.979125 WR_REQ [] <== SSIF_READY >> SSIF_START +8271.979326 WR_RCV [03] <== SSIF_START >> SSIF_SMBUS_CMD <- smbus_cmd=0x03 +8271.979331 RD_REQ [04] <== SSIF_RES_SENDING <- sending response +8271.979427 RD_PRO [b4] <- !! this is T's stale response -> desynchronization + +When in SSIF_ABORTING state, a newly arrived command should still be +handled to avoid dropping the request or causing message +desynchronization. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-3-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index 6cc5c210799ca..ca185793cf978 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -458,6 +458,15 @@ static bool supported_write_cmd(u8 cmd) + return false; + } + ++static bool supported_write_start_cmd(u8 cmd) ++{ ++ if (cmd == SSIF_IPMI_SINGLEPART_WRITE || ++ cmd == SSIF_IPMI_MULTIPART_WRITE_START) ++ return true; ++ ++ return false; ++} ++ + /* Process the IPMI response that will be read by master */ + static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + { +@@ -709,6 +718,11 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state = SSIF_ABORTING; + else + ssif_bmc->state = SSIF_REQ_RECVING; ++ } else if (ssif_bmc->state == SSIF_ABORTING) { ++ if (supported_write_start_cmd(*val)) { ++ ssif_bmc->state = SSIF_SMBUS_CMD; ++ ssif_bmc->aborting = false; ++ } + } + + /* This is response sending state */ +-- +2.53.0 + diff --git a/queue-6.18/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch b/queue-6.18/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch new file mode 100644 index 0000000000..c4c8a3b086 --- /dev/null +++ b/queue-6.18/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch @@ -0,0 +1,42 @@ +From 88903b234f54888d83102eed0d3842c2a91fb412 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:05:59 +0800 +Subject: ipmi: ssif_bmc: fix missing check for copy_to_user() partial failure + +From: Jian Zhang + +[ Upstream commit ea641be7a4faee4351f9c5ed6b188e1bbf5586a6 ] + +copy_to_user() returns the number of bytes that could not be copied, +with a non-zero value indicating a partial or complete failure. The +current code only checks for negative return values and treats all +non-negative results as success. + +Treating any positive return value from copy_to_user() as +an error and returning -EFAULT. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-2-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index 7a52e3ea49ed8..6cc5c210799ca 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -163,6 +163,8 @@ static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + ret = copy_to_user(buf, &msg, count); ++ if (ret > 0) ++ ret = -EFAULT; + } + + return (ret < 0) ? ret : count; +-- +2.53.0 + diff --git a/queue-6.18/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch b/queue-6.18/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch new file mode 100644 index 0000000000..6d665e1ad3 --- /dev/null +++ b/queue-6.18/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch @@ -0,0 +1,71 @@ +From 6ea51f2f6e4ad64e23179b1638d01bd0c3cd7041 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 10:35:05 +0000 +Subject: ipv6: fix possible UAF in icmpv6_rcv() + +From: Eric Dumazet + +[ Upstream commit f996edd7615e686ada141b7f3395025729ff8ccb ] + +Caching saddr and daddr before pskb_pull() is problematic +since skb->head can change. + +Remove these temporary variables: + +- We only access &ipv6_hdr(skb)->saddr and &ipv6_hdr(skb)->daddr + when net_dbg_ratelimited() is called in the slow path. + +- Avoid potential future misuse after pskb_pull() call. + +Fixes: 4b3418fba0fe ("ipv6: icmp: include addresses in debug messages") +Signed-off-by: Eric Dumazet +Reviewed-by: Fernando Fernandez Mancera +Reviewed-by: Joe Damato +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260416103505.2380753-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/icmp.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index aa39aabe4417e..9cf0557d0ed29 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -904,7 +904,6 @@ static int icmpv6_rcv(struct sk_buff *skb) + struct net *net = dev_net_rcu(skb->dev); + struct net_device *dev = icmp6_dev(skb); + struct inet6_dev *idev = __in6_dev_get(dev); +- const struct in6_addr *saddr, *daddr; + struct icmp6hdr *hdr; + u8 type; + +@@ -935,12 +934,10 @@ static int icmpv6_rcv(struct sk_buff *skb) + + __ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS); + +- saddr = &ipv6_hdr(skb)->saddr; +- daddr = &ipv6_hdr(skb)->daddr; +- + if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { + net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + goto csum_error; + } + +@@ -1020,7 +1017,8 @@ static int icmpv6_rcv(struct sk_buff *skb) + break; + + net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + + /* + * error of unknown type. +-- +2.53.0 + diff --git a/queue-6.18/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch b/queue-6.18/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch new file mode 100644 index 0000000000..6a4dd1ec2e --- /dev/null +++ b/queue-6.18/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch @@ -0,0 +1,97 @@ +From 9ed66916a284372e6e5d4c741ba0350a1cd9cd7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:40:29 +0800 +Subject: ipvs: fix MTU check for GSO packets in tunnel mode + +From: Yingnan Zhang <342144303@qq.com> + +[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ] + +Currently, IPVS skips MTU checks for GSO packets by excluding them with +the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel +mode encapsulates GSO packets with IPIP headers. + +The issue manifests in two ways: + +1. MTU violation after encapsulation: + When a GSO packet passes through IPVS tunnel mode, the original MTU + check is bypassed. After adding the IPIP tunnel header, the packet + size may exceed the outgoing interface MTU, leading to unexpected + fragmentation at the IP layer. + +2. Fragmentation with problematic IP IDs: + When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments + is fragmented after encapsulation, each segment gets a sequentially + incremented IP ID (0, 1, 2, ...). This happens because: + + a) The GSO packet bypasses MTU check and gets encapsulated + b) At __ip_finish_output, the oversized GSO packet is split into + separate SKBs (one per segment), with IP IDs incrementing + c) Each SKB is then fragmented again based on the actual MTU + + This sequential IP ID allocation differs from the expected behavior + and can cause issues with fragment reassembly and packet tracking. + +Fix this by properly validating GSO packets using +skb_gso_validate_network_len(). This function correctly validates +whether the GSO segments will fit within the MTU after segmentation. If +validation fails, send an ICMP Fragmentation Needed message to enable +proper PMTU discovery. + +Fixes: 4cdd34084d53 ("netfilter: nf_conntrack_ipv6: improve fragmentation handling") +Signed-off-by: Yingnan Zhang <342144303@qq.com> +Acked-by: Julian Anastasov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index ecbcdc43263d6..fc254d1f59de9 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -103,6 +103,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest) + return dest_dst; + } + ++/* Based on ip_exceeds_mtu(). */ ++static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) ++{ ++ if (skb->len <= mtu) ++ return false; ++ ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) ++ return false; ++ ++ return true; ++} ++ + static inline bool + __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + { +@@ -112,10 +124,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + */ + if (IP6CB(skb)->frag_max_size > mtu) + return true; /* largest fragment violate MTU */ +- } +- else if (skb->len > mtu && !skb_is_gso(skb)) { ++ } else if (ip_vs_exceeds_mtu(skb, mtu)) + return true; /* Packet size violate MTU size */ +- } ++ + return false; + } + +@@ -233,7 +244,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, + return true; + + if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && +- skb->len > mtu && !skb_is_gso(skb) && ++ ip_vs_exceeds_mtu(skb, mtu) && + !ip_vs_iph_icmp(ipvsh))) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); +-- +2.53.0 + diff --git a/queue-6.18/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch b/queue-6.18/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch new file mode 100644 index 0000000000..6f646ed8d5 --- /dev/null +++ b/queue-6.18/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch @@ -0,0 +1,48 @@ +From 40bd53a39fdcfc370a41d21dadc6343c45fd2f63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Feb 2026 18:43:44 -0500 +Subject: irqchip/irq-pic32-evic: Address warning related to wrong printf() + formatter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 86be659415b0ddefebc3120e309091aa215a9064 ] + +This driver is currently only build on 32 bit MIPS systems. When building +it on x86_64, the following warning occurs: + + drivers/irqchip/irq-pic32-evic.c: In function ‘pic32_ext_irq_of_init’: + ./include/linux/kern_levels.h:5:25: error: format ‘%d’ expects argument of type + ‘int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] + +Update the printf() formatter in preparation for allowing this driver to +be compiled on all architectures. + +Fixes: aaa8666ada780 ("IRQCHIP: irq-pic32-evic: Add support for PIC32 interrupt controller") +Signed-off-by: Brian Masney +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260222-irqchip-pic32-v1-1-37f50d1f14af@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-pic32-evic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c +index 5dfda8e8df10d..0bb664e3d7c51 100644 +--- a/drivers/irqchip/irq-pic32-evic.c ++++ b/drivers/irqchip/irq-pic32-evic.c +@@ -196,7 +196,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain) + + of_property_for_each_u32(node, pname, hwirq) { + if (i >= ARRAY_SIZE(priv->ext_irqs)) { +- pr_warn("More than %d external irq, skip rest\n", ++ pr_warn("More than %zu external irq, skip rest\n", + ARRAY_SIZE(priv->ext_irqs)); + break; + } +-- +2.53.0 + diff --git a/queue-6.18/irqchip-renesas-rzg2l-fix-error-path-in-rzg2l_irqc_c.patch b/queue-6.18/irqchip-renesas-rzg2l-fix-error-path-in-rzg2l_irqc_c.patch new file mode 100644 index 0000000000..847b10eb54 --- /dev/null +++ b/queue-6.18/irqchip-renesas-rzg2l-fix-error-path-in-rzg2l_irqc_c.patch @@ -0,0 +1,41 @@ +From cf304e932222bac8a010456bebcaefba45b1755a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 19:24:18 +0000 +Subject: irqchip/renesas-rzg2l: Fix error path in rzg2l_irqc_common_probe() + +From: Biju Das + +[ Upstream commit fb74e35f78105efd8635c89b39f4389f567edbdc ] + +Replace pm_runtime_put() with pm_runtime_put_sync() when +irq_domain_create_hierarchy() fails to ensure the device suspends +synchronously before devres cleanup disables runtime PM via +pm_runtime_disable(). + +[ tglx: Fix up subject and change log to be precise ] + +Fixes: 7de11369ef30 ("irqchip/renesas-rzg2l: Use devm_pm_runtime_enable()") +Signed-off-by: Biju Das +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260325192451.172562-4-biju.das.jz@bp.renesas.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-renesas-rzg2l.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c +index 1bf19deb02c4e..c938ab1592895 100644 +--- a/drivers/irqchip/irq-renesas-rzg2l.c ++++ b/drivers/irqchip/irq-renesas-rzg2l.c +@@ -573,7 +573,7 @@ static int rzg2l_irqc_common_probe(struct platform_device *pdev, struct device_n + irq_domain = irq_domain_create_hierarchy(parent_domain, 0, IRQC_NUM_IRQ, dev_fwnode(dev), + &rzg2l_irqc_domain_ops, rzg2l_irqc_data); + if (!irq_domain) { +- pm_runtime_put(dev); ++ pm_runtime_put_sync(dev); + return -ENOMEM; + } + +-- +2.53.0 + diff --git a/queue-6.18/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch b/queue-6.18/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch new file mode 100644 index 0000000000..f03413f9bf --- /dev/null +++ b/queue-6.18/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch @@ -0,0 +1,57 @@ +From f1ed73d53e59250414cbbbcdb38b7f226917c108 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 16:51:16 +0200 +Subject: kbuild: builddeb - avoid recompiles for non-cross-compiles + +From: Mathias Krause + +[ Upstream commit 2452dcf4d740effff5aa71b7f6529ee8c04fd8f6 ] + +Commit e2c318225ac1 ("kbuild: deb-pkg: add +pkg.linux-upstream.nokernelheaders build profile") changed how +install-extmod-build gets called, making it always rebuild the host +programs below scripts/ if HOSTCC wasn't specified with its full triplet +on the make command line. That is, apparently, needed to fix up commit +f1d87664b82a ("kbuild: cross-compile linux-headers package when +possible") for cross-compiles. However, in the much more common case of +non-cross-compile builds this will lead to unnecessary rebuilding of +host tools including gcc plugins. This, in turn, will lead to a full +kernel rebuild on the next 'make bindeb-pkg' which is unfortunate. + +Avoid that by only triggering the rebuild of host tools for actual +cross-compile builds. + +Signed-off-by: Mathias Krause +Fixes: e2c318225ac1 ("kbuild: deb-pkg: add pkg.linux-upstream.nokernelheaders build profile") +Cc: Masahiro Yamada +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Link: https://patch.msgid.link/20260402145116.1010901-1-minipli@grsecurity.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + scripts/package/builddeb | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/scripts/package/builddeb b/scripts/package/builddeb +index 3627ca227e5a5..ba1defc616524 100755 +--- a/scripts/package/builddeb ++++ b/scripts/package/builddeb +@@ -139,7 +139,13 @@ install_kernel_headers () { + pdir=debian/$1 + version=${1#linux-headers-} + +- CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ # Override $CC only for cross-compiles, to not unnecessarily rebuild ++ # scripts/ including plugins, which may lead to a full kernel rebuild. ++ if [ -n "${CROSS_COMPILE}" ]; then ++ CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ else ++ "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ fi + + mkdir -p $pdir/lib/modules/$version/ + ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build +-- +2.53.0 + diff --git a/queue-6.18/kbuild-never-respect-config_werror-w-e-to-fixdep.patch b/queue-6.18/kbuild-never-respect-config_werror-w-e-to-fixdep.patch new file mode 100644 index 0000000000..ac6df35529 --- /dev/null +++ b/queue-6.18/kbuild-never-respect-config_werror-w-e-to-fixdep.patch @@ -0,0 +1,60 @@ +From 321ab1af13972f4298db4156fc4224a5ad6f522d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 17:10:27 +0200 +Subject: kbuild: Never respect CONFIG_WERROR / W=e to fixdep +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 75f7c47ccd78c947cf1b6ddb18ea453ff0555716 ] + +The fixdep hostprog may be built multiple times during a single build. +Once during the configuration phase and later during the regular phase. +As only the regular build phase respects CONFIG_WERROR / W=e, the +compiler flags might change between the phases, leading to rebuilds. + +Example, the rebuilds will happen twice on each invocation of the build: + + $ make allyesconfig prepare + make[1]: Entering directory '/tmp/deleteme' + HOSTCC scripts/basic/fixdep + # + # No change to .config + # + HOSTCC scripts/basic/fixdep + DESCEND objtool + INSTALL libsubcmd_headers + make[1]: Leaving directory '/tmp/deleteme' + +Fix the compilation flags used for scripts/basic/ before +scripts/Makefile.warn is evaluated to stop CONFIG_WERROR / W=e +influencing the fixdep build to avoid the spurious rebuilds. + +Fixes: 7ded7d37e5f5 ("scripts/Makefile.extrawarn: Respect CONFIG_WERROR / W=e for hostprogs") +Signed-off-by: Thomas Weißschuh +Reviewed-by: Nathan Chancellor +Link: https://patch.msgid.link/20260422-kbuild-scripts-basic-werror-v1-1-8c6912ff22e0@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + Makefile | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Makefile b/Makefile +index d1fcec7cf9568..70e10b29b3859 100644 +--- a/Makefile ++++ b/Makefile +@@ -655,6 +655,8 @@ export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ + + # Basic helpers built in scripts/basic/ + PHONY += scripts_basic ++scripts_basic: KBUILD_HOSTCFLAGS := $(KBUILD_HOSTCFLAGS) ++scripts_basic: KBUILD_HOSTLDFLAGS := $(KBUILD_HOSTLDFLAGS) + scripts_basic: + $(Q)$(MAKE) $(build)=scripts/basic + +-- +2.53.0 + diff --git a/queue-6.18/kho-fix-kasan-support-for-restored-vmalloc-regions.patch b/queue-6.18/kho-fix-kasan-support-for-restored-vmalloc-regions.patch new file mode 100644 index 0000000000..eb4ca90fe4 --- /dev/null +++ b/queue-6.18/kho-fix-kasan-support-for-restored-vmalloc-regions.patch @@ -0,0 +1,84 @@ +From bfb39aacbdd868b2f18049f5b04dccadf74b2b42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 17:38:57 -0500 +Subject: kho: fix KASAN support for restored vmalloc regions + +From: Pasha Tatashin + +[ Upstream commit 019fc36872374db6fd35e118c9e935374404bfbf ] + +Restored vmalloc regions are currently not properly marked for KASAN, +causing KASAN to treat accesses to these regions as out-of-bounds. + +Fix this by properly unpoisoning the restored vmalloc area using +kasan_unpoison_vmalloc(). This requires setting the VM_UNINITIALIZED flag +during the initial area allocation and clearing it after the pages have +been mapped and unpoisoned, using the clear_vm_uninitialized_flag() +helper. + +Link: https://lkml.kernel.org/r/20260225223857.1714801-3-pasha.tatashin@soleen.com +Fixes: a667300bd53f ("kho: add support for preserving vmalloc allocations") +Signed-off-by: Pasha Tatashin +Reported-by: Pratyush Yadav +Reviewed-by: Pratyush Yadav (Google) +Tested-by: Pratyush Yadav (Google) +Cc: Alexander Graf +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Suren Baghdasaryan +Cc: "Uladzislau Rezki (Sony)" +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/kexec_handover.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c +index c13b99f7c9891..2ec4c3bcec128 100644 +--- a/kernel/kexec_handover.c ++++ b/kernel/kexec_handover.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -957,6 +958,7 @@ EXPORT_SYMBOL_GPL(kho_preserve_vmalloc); + void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) + { + struct kho_vmalloc_chunk *chunk = KHOSER_LOAD_PTR(preservation->first); ++ kasan_vmalloc_flags_t kasan_flags = KASAN_VMALLOC_PROT_NORMAL; + unsigned int align, order, shift, vm_flags; + unsigned long total_pages, contig_pages; + unsigned long addr, size; +@@ -1008,7 +1010,8 @@ void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) + goto err_free_pages_array; + + area = __get_vm_area_node(total_pages * PAGE_SIZE, align, shift, +- vm_flags, VMALLOC_START, VMALLOC_END, ++ vm_flags | VM_UNINITIALIZED, ++ VMALLOC_START, VMALLOC_END, + NUMA_NO_NODE, GFP_KERNEL, + __builtin_return_address(0)); + if (!area) +@@ -1023,6 +1026,13 @@ void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) + area->nr_pages = total_pages; + area->pages = pages; + ++ if (vm_flags & VM_ALLOC) ++ kasan_flags |= KASAN_VMALLOC_VM_ALLOC; ++ ++ area->addr = kasan_unpoison_vmalloc(area->addr, total_pages * PAGE_SIZE, ++ kasan_flags); ++ clear_vm_uninitialized_flag(area); ++ + return area->addr; + + err_free_vm_area: +-- +2.53.0 + diff --git a/queue-6.18/kho-make-debugfs-interface-optional.patch b/queue-6.18/kho-make-debugfs-interface-optional.patch new file mode 100644 index 0000000000..691e788c3e --- /dev/null +++ b/queue-6.18/kho-make-debugfs-interface-optional.patch @@ -0,0 +1,812 @@ +From 400e7d994c4d83b2436dd11a5a47aac61fd4d63c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Nov 2025 10:23:17 -0400 +Subject: kho: make debugfs interface optional + +From: Pasha Tatashin + +[ Upstream commit 03d3963464a43654703938a66503cd686c5fc54e ] + +Patch series "liveupdate: Rework KHO for in-kernel users", v9. + +This series refactors the KHO framework to better support in-kernel users +like the upcoming LUO. The current design, which relies on a notifier +chain and debugfs for control, is too restrictive for direct programmatic +use. + +The core of this rework is the removal of the notifier chain in favor of a +direct registration API. This decouples clients from the shutdown-time +finalization sequence, allowing them to manage their preserved state more +flexibly and at any time. + +In support of this new model, this series also: + - Makes the debugfs interface optional. + - Introduces APIs to unpreserve memory and fixes a bug in the abort + path where client state was being incorrectly discarded. Note that + this is an interim step, as a more comprehensive fix is planned as + part of the stateless KHO work [1]. + - Moves all KHO code into a new kernel/liveupdate/ directory to + consolidate live update components. + +This patch (of 9): + +Currently, KHO is controlled via debugfs interface, but once LUO is +introduced, it can control KHO, and the debug interface becomes optional. + +Add a separate config CONFIG_KEXEC_HANDOVER_DEBUGFS that enables the +debugfs interface, and allows to inspect the tree. + +Move all debugfs related code to a new file to keep the .c files clear of +ifdefs. + +Link: https://lkml.kernel.org/r/20251101142325.1326536-1-pasha.tatashin@soleen.com +Link: https://lkml.kernel.org/r/20251101142325.1326536-2-pasha.tatashin@soleen.com +Link: https://lore.kernel.org/all/20251020100306.2709352-1-jasonmiu@google.com [1] +Co-developed-by: Mike Rapoport (Microsoft) +Signed-off-by: Mike Rapoport (Microsoft) +Signed-off-by: Pasha Tatashin +Reviewed-by: Pratyush Yadav +Cc: Alexander Graf +Cc: Christian Brauner +Cc: Jason Gunthorpe +Cc: Jonathan Corbet +Cc: Masahiro Yamada +Cc: Miguel Ojeda +Cc: Randy Dunlap +Cc: Tejun Heo +Cc: Changyuan Lyu +Cc: Jason Gunthorpe +Cc: Simon Horman +Cc: Zhu Yanjun +Signed-off-by: Andrew Morton +Stable-dep-of: 019fc3687237 ("kho: fix KASAN support for restored vmalloc regions") +Signed-off-by: Sasha Levin +--- + MAINTAINERS | 2 +- + kernel/Kconfig.kexec | 12 +- + kernel/Makefile | 1 + + kernel/kexec_handover.c | 269 +++++--------------------- + kernel/kexec_handover_debugfs.c | 216 +++++++++++++++++++++ + kernel/kexec_handover_internal.h | 35 ++++ + tools/testing/selftests/kho/vmtest.sh | 1 + + 7 files changed, 314 insertions(+), 222 deletions(-) + create mode 100644 kernel/kexec_handover_debugfs.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index e8f06145fb54c..554e881b05bea 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -13798,7 +13798,7 @@ S: Maintained + F: Documentation/admin-guide/mm/kho.rst + F: Documentation/core-api/kho/* + F: include/linux/kexec_handover.h +-F: kernel/kexec_handover.c ++F: kernel/kexec_handover* + F: lib/test_kho.c + F: tools/testing/selftests/kho/ + +diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec +index 54e5810726176..cc6743137946f 100644 +--- a/kernel/Kconfig.kexec ++++ b/kernel/Kconfig.kexec +@@ -100,7 +100,6 @@ config KEXEC_HANDOVER + depends on !DEFERRED_STRUCT_PAGE_INIT + select MEMBLOCK_KHO_SCRATCH + select KEXEC_FILE +- select DEBUG_FS + select LIBFDT + select CMA + help +@@ -118,6 +117,17 @@ config KEXEC_HANDOVER_DEBUG + scenarios and the extra code might be adding overhead it is + only optionally enabled. + ++config KEXEC_HANDOVER_DEBUGFS ++ bool "kexec handover debugfs interface" ++ default KEXEC_HANDOVER ++ depends on KEXEC_HANDOVER ++ select DEBUG_FS ++ help ++ Allow to control kexec handover device tree via debugfs ++ interface, i.e. finalize the state or aborting the finalization. ++ Also, enables inspecting the KHO fdt trees with the debugfs binary ++ blobs. ++ + config CRASH_DUMP + bool "kernel crash dumps" + default ARCH_DEFAULT_CRASH_DUMP +diff --git a/kernel/Makefile b/kernel/Makefile +index 9fe722305c9be..2cf7909a74e56 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -84,6 +84,7 @@ obj-$(CONFIG_KEXEC_FILE) += kexec_file.o + obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o + obj-$(CONFIG_KEXEC_HANDOVER) += kexec_handover.o + obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) += kexec_handover_debug.o ++obj-$(CONFIG_KEXEC_HANDOVER_DEBUGFS) += kexec_handover_debugfs.o + obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o + obj-$(CONFIG_COMPAT) += compat.o + obj-$(CONFIG_CGROUPS) += cgroup/ +diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c +index 2da4bd994322f..c13b99f7c9891 100644 +--- a/kernel/kexec_handover.c ++++ b/kernel/kexec_handover.c +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -30,6 +29,7 @@ + */ + #include "../mm/internal.h" + #include "kexec_internal.h" ++#include "kexec_handover_internal.h" + + #define KHO_FDT_COMPATIBLE "kho-v1" + #define PROP_PRESERVED_MEMORY_MAP "preserved-memory-map" +@@ -105,8 +105,6 @@ struct khoser_mem_chunk; + + struct kho_serialization { + struct page *fdt; +- struct list_head fdt_list; +- struct dentry *sub_fdt_dir; + struct kho_mem_track track; + /* First chunk of serialized preserved memory map */ + struct khoser_mem_chunk *preserved_mem_map; +@@ -114,20 +112,16 @@ struct kho_serialization { + + struct kho_out { + struct blocking_notifier_head chain_head; +- +- struct dentry *dir; +- + struct mutex lock; /* protects KHO FDT finalization */ +- + struct kho_serialization ser; + bool finalized; ++ struct kho_debugfs dbg; + }; + + static struct kho_out kho_out = { + .chain_head = BLOCKING_NOTIFIER_INIT(kho_out.chain_head), + .lock = __MUTEX_INITIALIZER(kho_out.lock), + .ser = { +- .fdt_list = LIST_HEAD_INIT(kho_out.ser.fdt_list), + .track = { + .orders = XARRAY_INIT(kho_out.ser.track.orders, 0), + }, +@@ -678,37 +672,6 @@ static void __init kho_reserve_scratch(void) + kho_enable = false; + } + +-struct fdt_debugfs { +- struct list_head list; +- struct debugfs_blob_wrapper wrapper; +- struct dentry *file; +-}; +- +-static int kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir, +- const char *name, const void *fdt) +-{ +- struct fdt_debugfs *f; +- struct dentry *file; +- +- f = kmalloc(sizeof(*f), GFP_KERNEL); +- if (!f) +- return -ENOMEM; +- +- f->wrapper.data = (void *)fdt; +- f->wrapper.size = fdt_totalsize(fdt); +- +- file = debugfs_create_blob(name, 0400, dir, &f->wrapper); +- if (IS_ERR(file)) { +- kfree(f); +- return PTR_ERR(file); +- } +- +- f->file = file; +- list_add(&f->list, list); +- +- return 0; +-} +- + /** + * kho_add_subtree - record the physical address of a sub FDT in KHO root tree. + * @ser: serialization control object passed by KHO notifiers. +@@ -720,7 +683,8 @@ static int kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir, + * by KHO for the new kernel to retrieve it after kexec. + * + * A debugfs blob entry is also created at +- * ``/sys/kernel/debug/kho/out/sub_fdts/@name``. ++ * ``/sys/kernel/debug/kho/out/sub_fdts/@name`` when kernel is configured with ++ * CONFIG_KEXEC_HANDOVER_DEBUGFS + * + * Return: 0 on success, error code on failure + */ +@@ -737,7 +701,7 @@ int kho_add_subtree(struct kho_serialization *ser, const char *name, void *fdt) + if (err) + return err; + +- return kho_debugfs_fdt_add(&ser->fdt_list, ser->sub_fdt_dir, name, fdt); ++ return kho_debugfs_fdt_add(&kho_out.dbg, name, fdt, false); + } + EXPORT_SYMBOL_GPL(kho_add_subtree); + +@@ -1069,30 +1033,7 @@ void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) + } + EXPORT_SYMBOL_GPL(kho_restore_vmalloc); + +-/* Handling for debug/kho/out */ +- +-static struct dentry *debugfs_root; +- +-static int kho_out_update_debugfs_fdt(void) +-{ +- int err = 0; +- struct fdt_debugfs *ff, *tmp; +- +- if (kho_out.finalized) { +- err = kho_debugfs_fdt_add(&kho_out.ser.fdt_list, kho_out.dir, +- "fdt", page_to_virt(kho_out.ser.fdt)); +- } else { +- list_for_each_entry_safe(ff, tmp, &kho_out.ser.fdt_list, list) { +- debugfs_remove(ff->file); +- list_del(&ff->list); +- kfree(ff); +- } +- } +- +- return err; +-} +- +-static int kho_abort(void) ++static int __kho_abort(void) + { + int err; + unsigned long order; +@@ -1125,7 +1066,28 @@ static int kho_abort(void) + return err; + } + +-static int kho_finalize(void) ++int kho_abort(void) ++{ ++ int ret = 0; ++ ++ if (!kho_enable) ++ return -EOPNOTSUPP; ++ ++ guard(mutex)(&kho_out.lock); ++ if (!kho_out.finalized) ++ return -ENOENT; ++ ++ ret = __kho_abort(); ++ if (ret) ++ return ret; ++ ++ kho_out.finalized = false; ++ kho_debugfs_cleanup(&kho_out.dbg); ++ ++ return 0; ++} ++ ++static int __kho_finalize(void) + { + int err = 0; + u64 *preserved_mem_map; +@@ -1168,118 +1130,46 @@ static int kho_finalize(void) + abort: + if (err) { + pr_err("Failed to convert KHO state tree: %d\n", err); +- kho_abort(); ++ __kho_abort(); + } + + return err; + } + +-static int kho_out_finalize_get(void *data, u64 *val) +-{ +- mutex_lock(&kho_out.lock); +- *val = kho_out.finalized; +- mutex_unlock(&kho_out.lock); +- +- return 0; +-} +- +-static int kho_out_finalize_set(void *data, u64 _val) ++int kho_finalize(void) + { +- int ret = 0; +- bool val = !!_val; +- +- mutex_lock(&kho_out.lock); ++ int ret; + +- if (val == kho_out.finalized) { +- if (kho_out.finalized) +- ret = -EEXIST; +- else +- ret = -ENOENT; +- goto unlock; +- } ++ if (!kho_enable) ++ return -EOPNOTSUPP; + +- if (val) +- ret = kho_finalize(); +- else +- ret = kho_abort(); ++ guard(mutex)(&kho_out.lock); ++ if (kho_out.finalized) ++ return -EEXIST; + ++ ret = __kho_finalize(); + if (ret) +- goto unlock; +- +- kho_out.finalized = val; +- ret = kho_out_update_debugfs_fdt(); +- +-unlock: +- mutex_unlock(&kho_out.lock); +- return ret; +-} +- +-DEFINE_DEBUGFS_ATTRIBUTE(fops_kho_out_finalize, kho_out_finalize_get, +- kho_out_finalize_set, "%llu\n"); +- +-static int scratch_phys_show(struct seq_file *m, void *v) +-{ +- for (int i = 0; i < kho_scratch_cnt; i++) +- seq_printf(m, "0x%llx\n", kho_scratch[i].addr); +- +- return 0; +-} +-DEFINE_SHOW_ATTRIBUTE(scratch_phys); ++ return ret; + +-static int scratch_len_show(struct seq_file *m, void *v) +-{ +- for (int i = 0; i < kho_scratch_cnt; i++) +- seq_printf(m, "0x%llx\n", kho_scratch[i].size); ++ kho_out.finalized = true; + +- return 0; ++ return kho_debugfs_fdt_add(&kho_out.dbg, "fdt", ++ page_to_virt(kho_out.ser.fdt), true); + } +-DEFINE_SHOW_ATTRIBUTE(scratch_len); + +-static __init int kho_out_debugfs_init(void) ++bool kho_finalized(void) + { +- struct dentry *dir, *f, *sub_fdt_dir; +- +- dir = debugfs_create_dir("out", debugfs_root); +- if (IS_ERR(dir)) +- return -ENOMEM; +- +- sub_fdt_dir = debugfs_create_dir("sub_fdts", dir); +- if (IS_ERR(sub_fdt_dir)) +- goto err_rmdir; +- +- f = debugfs_create_file("scratch_phys", 0400, dir, NULL, +- &scratch_phys_fops); +- if (IS_ERR(f)) +- goto err_rmdir; +- +- f = debugfs_create_file("scratch_len", 0400, dir, NULL, +- &scratch_len_fops); +- if (IS_ERR(f)) +- goto err_rmdir; +- +- f = debugfs_create_file("finalize", 0600, dir, NULL, +- &fops_kho_out_finalize); +- if (IS_ERR(f)) +- goto err_rmdir; +- +- kho_out.dir = dir; +- kho_out.ser.sub_fdt_dir = sub_fdt_dir; +- return 0; +- +-err_rmdir: +- debugfs_remove_recursive(dir); +- return -ENOENT; ++ guard(mutex)(&kho_out.lock); ++ return kho_out.finalized; + } + + struct kho_in { +- struct dentry *dir; + phys_addr_t fdt_phys; + phys_addr_t scratch_phys; +- struct list_head fdt_list; ++ struct kho_debugfs dbg; + }; + + static struct kho_in kho_in = { +- .fdt_list = LIST_HEAD_INIT(kho_in.fdt_list), + }; + + static const void *kho_get_fdt(void) +@@ -1343,56 +1233,6 @@ int kho_retrieve_subtree(const char *name, phys_addr_t *phys) + } + EXPORT_SYMBOL_GPL(kho_retrieve_subtree); + +-/* Handling for debugfs/kho/in */ +- +-static __init int kho_in_debugfs_init(const void *fdt) +-{ +- struct dentry *sub_fdt_dir; +- int err, child; +- +- kho_in.dir = debugfs_create_dir("in", debugfs_root); +- if (IS_ERR(kho_in.dir)) +- return PTR_ERR(kho_in.dir); +- +- sub_fdt_dir = debugfs_create_dir("sub_fdts", kho_in.dir); +- if (IS_ERR(sub_fdt_dir)) { +- err = PTR_ERR(sub_fdt_dir); +- goto err_rmdir; +- } +- +- err = kho_debugfs_fdt_add(&kho_in.fdt_list, kho_in.dir, "fdt", fdt); +- if (err) +- goto err_rmdir; +- +- fdt_for_each_subnode(child, fdt, 0) { +- int len = 0; +- const char *name = fdt_get_name(fdt, child, NULL); +- const u64 *fdt_phys; +- +- fdt_phys = fdt_getprop(fdt, child, "fdt", &len); +- if (!fdt_phys) +- continue; +- if (len != sizeof(*fdt_phys)) { +- pr_warn("node `%s`'s prop `fdt` has invalid length: %d\n", +- name, len); +- continue; +- } +- err = kho_debugfs_fdt_add(&kho_in.fdt_list, sub_fdt_dir, name, +- phys_to_virt(*fdt_phys)); +- if (err) { +- pr_warn("failed to add fdt `%s` to debugfs: %d\n", name, +- err); +- continue; +- } +- } +- +- return 0; +- +-err_rmdir: +- debugfs_remove_recursive(kho_in.dir); +- return err; +-} +- + static __init int kho_init(void) + { + int err = 0; +@@ -1407,27 +1247,16 @@ static __init int kho_init(void) + goto err_free_scratch; + } + +- debugfs_root = debugfs_create_dir("kho", NULL); +- if (IS_ERR(debugfs_root)) { +- err = -ENOENT; ++ err = kho_debugfs_init(); ++ if (err) + goto err_free_fdt; +- } + +- err = kho_out_debugfs_init(); ++ err = kho_out_debugfs_init(&kho_out.dbg); + if (err) + goto err_free_fdt; + + if (fdt) { +- err = kho_in_debugfs_init(fdt); +- /* +- * Failure to create /sys/kernel/debug/kho/in does not prevent +- * reviving state from KHO and setting up KHO for the next +- * kexec. +- */ +- if (err) +- pr_err("failed exposing handover FDT in debugfs: %d\n", +- err); +- ++ kho_in_debugfs_init(&kho_in.dbg, fdt); + return 0; + } + +diff --git a/kernel/kexec_handover_debugfs.c b/kernel/kexec_handover_debugfs.c +new file mode 100644 +index 0000000000000..a91b279f1b232 +--- /dev/null ++++ b/kernel/kexec_handover_debugfs.c +@@ -0,0 +1,216 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * kexec_handover_debugfs.c - kexec handover debugfs interfaces ++ * Copyright (C) 2023 Alexander Graf ++ * Copyright (C) 2025 Microsoft Corporation, Mike Rapoport ++ * Copyright (C) 2025 Google LLC, Changyuan Lyu ++ * Copyright (C) 2025 Google LLC, Pasha Tatashin ++ */ ++ ++#define pr_fmt(fmt) "KHO: " fmt ++ ++#include ++#include ++#include ++#include ++#include "kexec_handover_internal.h" ++ ++static struct dentry *debugfs_root; ++ ++struct fdt_debugfs { ++ struct list_head list; ++ struct debugfs_blob_wrapper wrapper; ++ struct dentry *file; ++}; ++ ++static int __kho_debugfs_fdt_add(struct list_head *list, struct dentry *dir, ++ const char *name, const void *fdt) ++{ ++ struct fdt_debugfs *f; ++ struct dentry *file; ++ ++ f = kmalloc(sizeof(*f), GFP_KERNEL); ++ if (!f) ++ return -ENOMEM; ++ ++ f->wrapper.data = (void *)fdt; ++ f->wrapper.size = fdt_totalsize(fdt); ++ ++ file = debugfs_create_blob(name, 0400, dir, &f->wrapper); ++ if (IS_ERR(file)) { ++ kfree(f); ++ return PTR_ERR(file); ++ } ++ ++ f->file = file; ++ list_add(&f->list, list); ++ ++ return 0; ++} ++ ++int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name, ++ const void *fdt, bool root) ++{ ++ struct dentry *dir; ++ ++ if (root) ++ dir = dbg->dir; ++ else ++ dir = dbg->sub_fdt_dir; ++ ++ return __kho_debugfs_fdt_add(&dbg->fdt_list, dir, name, fdt); ++} ++ ++void kho_debugfs_cleanup(struct kho_debugfs *dbg) ++{ ++ struct fdt_debugfs *ff, *tmp; ++ ++ list_for_each_entry_safe(ff, tmp, &dbg->fdt_list, list) { ++ debugfs_remove(ff->file); ++ list_del(&ff->list); ++ kfree(ff); ++ } ++} ++ ++static int kho_out_finalize_get(void *data, u64 *val) ++{ ++ *val = kho_finalized(); ++ ++ return 0; ++} ++ ++static int kho_out_finalize_set(void *data, u64 val) ++{ ++ if (val) ++ return kho_finalize(); ++ else ++ return kho_abort(); ++} ++ ++DEFINE_DEBUGFS_ATTRIBUTE(kho_out_finalize_fops, kho_out_finalize_get, ++ kho_out_finalize_set, "%llu\n"); ++ ++static int scratch_phys_show(struct seq_file *m, void *v) ++{ ++ for (int i = 0; i < kho_scratch_cnt; i++) ++ seq_printf(m, "0x%llx\n", kho_scratch[i].addr); ++ ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(scratch_phys); ++ ++static int scratch_len_show(struct seq_file *m, void *v) ++{ ++ for (int i = 0; i < kho_scratch_cnt; i++) ++ seq_printf(m, "0x%llx\n", kho_scratch[i].size); ++ ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(scratch_len); ++ ++__init void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt) ++{ ++ struct dentry *dir, *sub_fdt_dir; ++ int err, child; ++ ++ INIT_LIST_HEAD(&dbg->fdt_list); ++ ++ dir = debugfs_create_dir("in", debugfs_root); ++ if (IS_ERR(dir)) { ++ err = PTR_ERR(dir); ++ goto err_out; ++ } ++ ++ sub_fdt_dir = debugfs_create_dir("sub_fdts", dir); ++ if (IS_ERR(sub_fdt_dir)) { ++ err = PTR_ERR(sub_fdt_dir); ++ goto err_rmdir; ++ } ++ ++ err = __kho_debugfs_fdt_add(&dbg->fdt_list, dir, "fdt", fdt); ++ if (err) ++ goto err_rmdir; ++ ++ fdt_for_each_subnode(child, fdt, 0) { ++ int len = 0; ++ const char *name = fdt_get_name(fdt, child, NULL); ++ const u64 *fdt_phys; ++ ++ fdt_phys = fdt_getprop(fdt, child, "fdt", &len); ++ if (!fdt_phys) ++ continue; ++ if (len != sizeof(*fdt_phys)) { ++ pr_warn("node %s prop fdt has invalid length: %d\n", ++ name, len); ++ continue; ++ } ++ err = __kho_debugfs_fdt_add(&dbg->fdt_list, sub_fdt_dir, name, ++ phys_to_virt(*fdt_phys)); ++ if (err) { ++ pr_warn("failed to add fdt %s to debugfs: %d\n", name, ++ err); ++ continue; ++ } ++ } ++ ++ dbg->dir = dir; ++ dbg->sub_fdt_dir = sub_fdt_dir; ++ ++ return; ++err_rmdir: ++ debugfs_remove_recursive(dir); ++err_out: ++ /* ++ * Failure to create /sys/kernel/debug/kho/in does not prevent ++ * reviving state from KHO and setting up KHO for the next ++ * kexec. ++ */ ++ if (err) ++ pr_err("failed exposing handover FDT in debugfs: %d\n", err); ++} ++ ++__init int kho_out_debugfs_init(struct kho_debugfs *dbg) ++{ ++ struct dentry *dir, *f, *sub_fdt_dir; ++ ++ INIT_LIST_HEAD(&dbg->fdt_list); ++ ++ dir = debugfs_create_dir("out", debugfs_root); ++ if (IS_ERR(dir)) ++ return -ENOMEM; ++ ++ sub_fdt_dir = debugfs_create_dir("sub_fdts", dir); ++ if (IS_ERR(sub_fdt_dir)) ++ goto err_rmdir; ++ ++ f = debugfs_create_file("scratch_phys", 0400, dir, NULL, ++ &scratch_phys_fops); ++ if (IS_ERR(f)) ++ goto err_rmdir; ++ ++ f = debugfs_create_file("scratch_len", 0400, dir, NULL, ++ &scratch_len_fops); ++ if (IS_ERR(f)) ++ goto err_rmdir; ++ ++ f = debugfs_create_file("finalize", 0600, dir, NULL, ++ &kho_out_finalize_fops); ++ if (IS_ERR(f)) ++ goto err_rmdir; ++ ++ dbg->dir = dir; ++ dbg->sub_fdt_dir = sub_fdt_dir; ++ return 0; ++ ++err_rmdir: ++ debugfs_remove_recursive(dir); ++ return -ENOENT; ++} ++ ++__init int kho_debugfs_init(void) ++{ ++ debugfs_root = debugfs_create_dir("kho", NULL); ++ if (IS_ERR(debugfs_root)) ++ return -ENOENT; ++ return 0; ++} +diff --git a/kernel/kexec_handover_internal.h b/kernel/kexec_handover_internal.h +index 3c3c7148ceed4..217b8b25a5422 100644 +--- a/kernel/kexec_handover_internal.h ++++ b/kernel/kexec_handover_internal.h +@@ -3,11 +3,46 @@ + #define LINUX_KEXEC_HANDOVER_INTERNAL_H + + #include ++#include + #include + ++#ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS ++#include ++ ++struct kho_debugfs { ++ struct dentry *dir; ++ struct dentry *sub_fdt_dir; ++ struct list_head fdt_list; ++}; ++ ++#else ++struct kho_debugfs {}; ++#endif ++ + extern struct kho_scratch *kho_scratch; + extern unsigned int kho_scratch_cnt; + ++bool kho_finalized(void); ++int kho_finalize(void); ++int kho_abort(void); ++ ++#ifdef CONFIG_KEXEC_HANDOVER_DEBUGFS ++int kho_debugfs_init(void); ++void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt); ++int kho_out_debugfs_init(struct kho_debugfs *dbg); ++int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name, ++ const void *fdt, bool root); ++void kho_debugfs_cleanup(struct kho_debugfs *dbg); ++#else ++static inline int kho_debugfs_init(void) { return 0; } ++static inline void kho_in_debugfs_init(struct kho_debugfs *dbg, ++ const void *fdt) { } ++static inline int kho_out_debugfs_init(struct kho_debugfs *dbg) { return 0; } ++static inline int kho_debugfs_fdt_add(struct kho_debugfs *dbg, const char *name, ++ const void *fdt, bool root) { return 0; } ++static inline void kho_debugfs_cleanup(struct kho_debugfs *dbg) {} ++#endif /* CONFIG_KEXEC_HANDOVER_DEBUGFS */ ++ + #ifdef CONFIG_KEXEC_HANDOVER_DEBUG + bool kho_scratch_overlap(phys_addr_t phys, size_t size); + #else +diff --git a/tools/testing/selftests/kho/vmtest.sh b/tools/testing/selftests/kho/vmtest.sh +index 3f6c171668467..49fdac8e8b159 100755 +--- a/tools/testing/selftests/kho/vmtest.sh ++++ b/tools/testing/selftests/kho/vmtest.sh +@@ -59,6 +59,7 @@ function build_kernel() { + tee "$kconfig" > "$kho_config" < +Date: Wed, 29 Apr 2026 15:30:10 +0100 +Subject: kselftest/arm64: Include for user_gcs definition + +From: Leo Yan + +[ Upstream commit bb7235e226888607e6aac1288062fcb1ac105589 ] + +kselftest includes kernel uAPI headers with option: + + -isystem $(top_srcdir)/usr/include + +Include in libc-gcs.c for the definition of struct +user_gcs from the uAPI headers, and remove the redundant definition in +gcs-util.h. This fixes a compilation error on systems where the +toolchain defines NT_ARM_GCS. + +Fixes: a505a52b4e29 ("kselftest/arm64: Add a GCS test program built with the system libc") +Signed-off-by: Leo Yan +Reviewed-by: Mark Brown +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/arm64/gcs/gcs-util.h | 6 ------ + tools/testing/selftests/arm64/gcs/libc-gcs.c | 1 + + 2 files changed, 1 insertion(+), 6 deletions(-) + +diff --git a/tools/testing/selftests/arm64/gcs/gcs-util.h b/tools/testing/selftests/arm64/gcs/gcs-util.h +index c99a6b39ac147..7a81bb07ed4b8 100644 +--- a/tools/testing/selftests/arm64/gcs/gcs-util.h ++++ b/tools/testing/selftests/arm64/gcs/gcs-util.h +@@ -18,12 +18,6 @@ + + #ifndef NT_ARM_GCS + #define NT_ARM_GCS 0x410 +- +-struct user_gcs { +- __u64 features_enabled; +- __u64 features_locked; +- __u64 gcspr_el0; +-}; + #endif + + /* Shadow Stack/Guarded Control Stack interface */ +diff --git a/tools/testing/selftests/arm64/gcs/libc-gcs.c b/tools/testing/selftests/arm64/gcs/libc-gcs.c +index 17b2fabfec386..72e82bfbecc99 100644 +--- a/tools/testing/selftests/arm64/gcs/libc-gcs.c ++++ b/tools/testing/selftests/arm64/gcs/libc-gcs.c +@@ -16,6 +16,7 @@ + + #include + #include ++#include + + #include + +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch b/queue-6.18/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch new file mode 100644 index 0000000000..8950257689 --- /dev/null +++ b/queue-6.18/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch @@ -0,0 +1,54 @@ +From 2c3d154bfc84617826d8d1f8e657b7f4648ec620 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:55 +0900 +Subject: ksmbd: destroy async_ida in ksmbd_conn_free() + +From: DaeMyung Kang + +[ Upstream commit b32c8db48212a34998c36d0bbc05b29d5c407ef5 ] + +When per-connection async_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from the connection teardown path but no matching +ida_destroy() was added. The connection is therefore freed with the +IDA's backing xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +connection is freed. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/connection.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c +index b4ef62b9e660c..a03132adcc1e5 100644 +--- a/fs/smb/server/connection.c ++++ b/fs/smb/server/connection.c +@@ -41,6 +41,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn) + kfree(conn->preauth_info); + kfree(conn->mechToken); + if (atomic_dec_and_test(&conn->refcnt)) { ++ /* ++ * async_ida is embedded in struct ksmbd_conn, so pair ++ * ida_destroy() with the final kfree() rather than with ++ * the unconditional field teardown above. This keeps ++ * the IDA valid for the entire lifetime of the struct, ++ * even while other refcount holders (oplock / vfs ++ * durable handles) still reference the connection. ++ */ ++ ida_destroy(&conn->async_ida); + conn->transport->ops->free_transport(conn->transport); + kfree(conn); + } +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch b/queue-6.18/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch new file mode 100644 index 0000000000..3ea318cede --- /dev/null +++ b/queue-6.18/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch @@ -0,0 +1,71 @@ +From 72721ead5dc9742c1b803b086335a9178429e4e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:54 +0900 +Subject: ksmbd: destroy tree_conn_ida in ksmbd_session_destroy() + +From: DaeMyung Kang + +[ Upstream commit c049ee14eb4343b69b6f7755563f961f5e153423 ] + +When per-session tree_conn_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from ksmbd_session_destroy() but no matching ida_destroy() +was added. The session is therefore freed with the IDA's backing +xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +enclosing session is freed. + +Also move ida_init() to right after the session is allocated so that +it is always paired with the destroy call even on the early error +paths of __session_create() (ksmbd_init_file_table() or +__init_smb2_session() failures), both of which jump to the error +label and invoke ksmbd_session_destroy() on a partially initialised +session. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index ed343807660fa..afa0daa3f5d88 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -170,6 +170,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) + free_channel_list(sess); + kfree(sess->Preauth_HashValue); + ksmbd_release_id(&session_ida, sess->id); ++ ida_destroy(&sess->tree_conn_ida); + kfree(sess); + } + +@@ -444,6 +445,8 @@ static struct ksmbd_session *__session_create(int protocol) + if (!sess) + return NULL; + ++ ida_init(&sess->tree_conn_ida); ++ + if (ksmbd_init_file_table(&sess->file_table)) + goto error; + +@@ -463,8 +466,6 @@ static struct ksmbd_session *__session_create(int protocol) + if (ret) + goto error; + +- ida_init(&sess->tree_conn_ida); +- + down_write(&sessions_table_lock); + hash_add(sessions_table, &sess->hlist, sess->id); + up_write(&sessions_table_lock); +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch b/queue-6.18/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch new file mode 100644 index 0000000000..0cd4a50549 --- /dev/null +++ b/queue-6.18/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch @@ -0,0 +1,64 @@ +From 201eda96d7022bfff581bf43d985c21dee6294b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 03:45:11 +0900 +Subject: ksmbd: fix durable fd leak on ClientGUID mismatch in durable v2 open + +From: DaeMyung Kang + +[ Upstream commit 804054d19886ac6628883d82410f6ee42a818664 ] + +ksmbd_lookup_fd_cguid() returns a ksmbd_file with its refcount +incremented via ksmbd_fp_get(). parse_durable_handle_context() in +the DURABLE_REQ_V2 case properly releases this reference on every +path inside the ClientGUID-match branch, either by calling +ksmbd_put_durable_fd() or by transferring ownership to dh_info->fp +for a successful reconnect. However, when an entry exists in the +global file table with the same CreateGuid but a different +ClientGUID, the code simply falls through to the new-open path +without dropping the reference obtained from ksmbd_lookup_fd_cguid(). + +Per MS-SMB2 section 3.3.5.9.10 ("Handling the +SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context"), the server +MUST locate an Open whose Open.CreateGuid matches the request's +CreateGuid AND whose Open.ClientGuid matches the ClientGuid of the +connection that received the request. If no such Open is found, the +server MUST continue with the normal open execution phase. A +CreateGuid hit with a ClientGUID mismatch is therefore the +"Open not found" case: proceeding with a new open is correct, but +the reference obtained purely as a side effect of the lookup must +not be leaked. + +Repeated requests that hit this mismatch pin global_ft entries, +prevent __ksmbd_close_fd() from ever running for the corresponding +files, and defeat the durable scavenger, leading to long-lived +resource leaks. + +Release the reference in the mismatch path and clear dh_info->fp so +subsequent logic does not mistake a non-matching lookup result for +a reconnect target. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 4bfbfe53aa4eb..756624b4e90e0 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -2854,6 +2854,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work, + dh_info->reconnected = true; + goto out; + } ++ ksmbd_put_durable_fd(dh_info->fp); ++ dh_info->fp = NULL; + } + + if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch b/queue-6.18/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch new file mode 100644 index 0000000000..9e26251adc --- /dev/null +++ b/queue-6.18/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch @@ -0,0 +1,73 @@ +From 3fe4ce5212a93bf332542df0ab5bd73ab5535468 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 22:31:12 -0400 +Subject: ksmbd: fix use-after-free from async crypto on Qualcomm crypto engine + +From: Joshua Klinesmith + +[ Upstream commit 3e298897f41c61450c2e7a4f457e8b2485eb35b3 ] + +ksmbd_crypt_message() sets a NULL completion callback on AEAD requests +and does not handle the -EINPROGRESS return code from async hardware +crypto engines like the Qualcomm Crypto Engine (QCE). When QCE returns +-EINPROGRESS, ksmbd treats it as an error and immediately frees the +request while the hardware DMA operation is still in flight. The DMA +completion callback then dereferences freed memory, causing a NULL +pointer crash: + + pc : qce_skcipher_done+0x24/0x174 + lr : vchan_complete+0x230/0x27c + ... + el1h_64_irq+0x68/0x6c + ksmbd_free_work_struct+0x20/0x118 [ksmbd] + ksmbd_exit_file_cache+0x694/0xa4c [ksmbd] + +Use the standard crypto_wait_req() pattern with crypto_req_done() as +the completion callback, matching the approach used by the SMB client +in fs/smb/client/smb2ops.c. This properly handles both synchronous +engines (immediate return) and async engines (-EINPROGRESS followed +by callback notification). + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Link: https://github.com/openwrt/openwrt/issues/21822 +Signed-off-by: Joshua Klinesmith +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/auth.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index c37b86a83cac8..b63f32c692bab 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -1076,6 +1076,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int rc; ++ DECLARE_CRYPTO_WAIT(wait); + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; +@@ -1162,12 +1163,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); +- aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); ++ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | ++ CRYPTO_TFM_REQ_MAY_SLEEP, ++ crypto_req_done, &wait); + +- if (enc) +- rc = crypto_aead_encrypt(req); +- else +- rc = crypto_aead_decrypt(req); ++ rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : ++ crypto_aead_decrypt(req), &wait); + if (rc) + goto free_iv; + +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-fix-use-after-free-in-smb2_open-during-durable.patch b/queue-6.18/ksmbd-fix-use-after-free-in-smb2_open-during-durable.patch new file mode 100644 index 0000000000..d4b6d8a4c0 --- /dev/null +++ b/queue-6.18/ksmbd-fix-use-after-free-in-smb2_open-during-durable.patch @@ -0,0 +1,76 @@ +From a5e7461d20f216c32043b9ffe90b9d4063463d1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 23:57:09 +0530 +Subject: ksmbd: fix use-after-free in smb2_open during durable reconnect + +From: Akif + +[ Upstream commit 1baff47b81f94f9231c91236aa511420d0e266b9 ] + +In smb2_open, the call to ksmbd_put_durable_fd(fp) drops the reference +to the durable file descriptor early during the durable reconnect +process. If an error occurs subsequently (eg, ksmbd_iov_pin_rsp fails) +or a scavenger accesses the file, it leads to a use-after-free when +accessing fp properties (eg fp->create_time). + +Move the single put to the end of the function below err_out2 so fp +stays valid until smb2_open returns. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Signed-off-by: Akif +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 16ea123f61223..4bfbfe53aa4eb 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -3024,29 +3024,23 @@ int smb2_open(struct ksmbd_work *work) + if (dh_info.reconnected == true) { + rc = smb2_check_durable_oplock(conn, share, dh_info.fp, + lc, sess->user, name); +- if (rc) { +- ksmbd_put_durable_fd(dh_info.fp); ++ if (rc) + goto err_out2; +- } + + rc = ksmbd_reopen_durable_fd(work, dh_info.fp); +- if (rc) { +- ksmbd_put_durable_fd(dh_info.fp); ++ if (rc) + goto err_out2; +- } + + fp = dh_info.fp; + + if (ksmbd_override_fsids(work)) { + rc = -ENOMEM; +- ksmbd_put_durable_fd(dh_info.fp); + goto err_out2; + } + + file_info = FILE_OPENED; + + rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat); +- ksmbd_put_durable_fd(fp); + if (rc) + goto err_out2; + +@@ -3816,6 +3810,9 @@ int smb2_open(struct ksmbd_work *work) + ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status); + } + ++ if (dh_info.reconnected) ++ ksmbd_put_durable_fd(dh_info.fp); ++ + kfree(name); + kfree(lc); + +-- +2.53.0 + diff --git a/queue-6.18/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch b/queue-6.18/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch new file mode 100644 index 0000000000..a7de4caae1 --- /dev/null +++ b/queue-6.18/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch @@ -0,0 +1,59 @@ +From f65ccac613422325aa254be4b3f4babc2d8bd016 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 00:31:47 +0900 +Subject: ksmbd: scope conn->binding slowpath to bound sessions only + +From: Hyunwoo Kim + +[ Upstream commit b0da97c034b6107d14e537e212d4ce8b22109a58 ] + +When the binding SESSION_SETUP sets conn->binding = true, the flag stays +set after the call so that the global session lookup in +ksmbd_session_lookup_all() can find the session, which was not added to +conn->sessions. Because the flag is connection-wide, the global lookup +path will also resolve any other session by id if asked. + +Tighten the global lookup so that the returned session must have this +connection registered in its channel xarray (sess->ksmbd_chann_list). +The channel entry is installed by the existing binding_session path in +ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes +successfully, so this condition is a strict equivalent of "this +connection has been accepted as a channel of this session". Connections +that have not bound to a given session cannot reach it via the global +table. + +The existing conn->binding gate for entering the slowpath is preserved +so that non-binding connections keep the fast-path-only behavior, and +the session->state check is unchanged. + +Fixes: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel") +Signed-off-by: Hyunwoo Kim +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index afa0daa3f5d88..5bc2f18d68bbc 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -327,8 +327,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, + struct ksmbd_session *sess; + + sess = ksmbd_session_lookup(conn, id); +- if (!sess && conn->binding) ++ if (!sess && conn->binding) { + sess = ksmbd_session_lookup_slowpath(id); ++ if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) { ++ ksmbd_user_session_put(sess); ++ sess = NULL; ++ } ++ } + if (sess && sess->state != SMB2_SESSION_VALID) { + ksmbd_user_session_put(sess); + sess = NULL; +-- +2.53.0 + diff --git a/queue-6.18/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch b/queue-6.18/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch new file mode 100644 index 0000000000..9e2993280f --- /dev/null +++ b/queue-6.18/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch @@ -0,0 +1,49 @@ +From 5c4e8206a41c33954d6f71832a88a7c9bba06d8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:56 -0300 +Subject: ktest: Avoid undef warning when WARNINGS_FILE is unset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit 057854f8a595160656fe77ed7bf0d2403724b915 ] + +check_buildlog() probes $warnings_file with -f even when WARNINGS_FILE is +not configured. Perl warns about the uninitialized value and adds noise to +the test log, which can hide the output we actually care about. + +Check that WARNINGS_FILE is defined before testing whether the file exists. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-1-565d412f4925@suse.com +Fixes: 4283b169abfb ("ktest: Add make_warnings_file and process full warnings") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 88de775097fef..28643812184bc 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -2508,7 +2508,7 @@ sub check_buildlog { + my $save_no_reboot = $no_reboot; + $no_reboot = 1; + +- if (-f $warnings_file) { ++ if (defined($warnings_file) && -f $warnings_file) { + open(IN, $warnings_file) or + dodie "Error opening $warnings_file"; + +-- +2.53.0 + diff --git a/queue-6.18/ktest-honor-empty-per-test-option-overrides.patch b/queue-6.18/ktest-honor-empty-per-test-option-overrides.patch new file mode 100644 index 0000000000..9a40a14667 --- /dev/null +++ b/queue-6.18/ktest-honor-empty-per-test-option-overrides.patch @@ -0,0 +1,79 @@ +From 3325d335b9f67988ad50eba46d04025d122b43a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:59 -0300 +Subject: ktest: Honor empty per-test option overrides +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit a2de57a3c8192dcd67cccaff6c341b93748d799b ] + +A per-test override can clear an inherited default option by assigning an +empty value, but __set_test_option() still used option_defined() to decide +whether a per-test key existed. That turned an empty per-test assignment +back into "fall back to the default", so tests still could not clear +inherited settings. + +For example: + + DEFAULTS + (...) + LOG_FILE = /tmp/ktest-empty-override.log + CLEAR_LOG = 1 + ADD_CONFIG = /tmp/.config + + TEST_START + TEST_TYPE = build + BUILD_TYPE = nobuild + ADD_CONFIG = + +This would run the test with ADD_CONFIG[1] = /tmp/.config + +Fix by checking whether the per-test key exists before falling back. If it +does exist but is empty, treat it as unset for that test and stop the +fallback chain there. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-4-565d412f4925@suse.com +Fixes: 22c37a9ac49d ("ktest: Allow tests to undefine default options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 28643812184bc..924e17df56f74 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -4183,7 +4183,8 @@ sub __set_test_option { + + my $option = "$name\[$i\]"; + +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + +@@ -4191,7 +4192,8 @@ sub __set_test_option { + if ($i >= $test && + $i < $test + $repeat_tests{$test}) { + $option = "$name\[$test\]"; +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + } +-- +2.53.0 + diff --git a/queue-6.18/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch b/queue-6.18/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch new file mode 100644 index 0000000000..7b1b72e1aa --- /dev/null +++ b/queue-6.18/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch @@ -0,0 +1,105 @@ +From d25aa45190b1031ae60a3113e5dda510d50848fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:08:03 -0300 +Subject: ktest: Run POST_KTEST hooks on failure and cancellation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit bc6e165a452da909cef0efbc286e6695624db372 ] + +PRE_KTEST can be useful for setting up the environment and POST_KTEST to +tear it down, however POST_KTEST only runs on the normal end-of-run path. +It is skipped when ktest exits through dodie() or cancel_test(). Final +cleanup hooks are skipped. + +Factor the final hook execution into run_post_ktest(), call it from the +normal exit path and from the early exit paths, and guard it so the hook +runs at most once. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-8-565d412f4925@suse.com +Fixes: 921ed4c7208e ("ktest: Add PRE/POST_KTEST and TEST options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 924e17df56f74..17bdce9cafac2 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -100,6 +100,7 @@ my $test_type; + my $build_type; + my $build_options; + my $final_post_ktest; ++my $post_ktest_done = 0; + my $pre_ktest; + my $post_ktest; + my $pre_test; +@@ -1575,6 +1576,24 @@ sub get_test_name() { + return $name; + } + ++sub run_post_ktest { ++ my $cmd; ++ ++ return if ($post_ktest_done); ++ ++ if (defined($final_post_ktest)) { ++ $cmd = $final_post_ktest; ++ } elsif (defined($post_ktest)) { ++ $cmd = $post_ktest; ++ } else { ++ return; ++ } ++ ++ my $cp_post_ktest = eval_kernel_version($cmd); ++ run_command $cp_post_ktest; ++ $post_ktest_done = 1; ++} ++ + sub dodie { + # avoid recursion + return if ($in_die); +@@ -1634,6 +1653,7 @@ sub dodie { + if (defined($post_test)) { + run_command $post_test; + } ++ run_post_ktest; + + die @_, "\n"; + } +@@ -4300,6 +4320,7 @@ sub cancel_test { + send_email("KTEST: Your [$name] test was cancelled", + "Your test started at $script_start_time was cancelled: sig int"); + } ++ run_post_ktest; + die "\nCaught Sig Int, test interrupted: $!\n" + } + +@@ -4661,11 +4682,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { + success $i; + } + +-if (defined($final_post_ktest)) { +- +- my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; +- run_command $cp_final_post_ktest; +-} ++run_post_ktest; + + if ($opt{"POWEROFF_ON_SUCCESS"}) { + halt; +-- +2.53.0 + diff --git a/queue-6.18/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch b/queue-6.18/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch new file mode 100644 index 0000000000..51ef1a9300 --- /dev/null +++ b/queue-6.18/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch @@ -0,0 +1,36 @@ +From 2927c31fd3a3850790ba8e4256436ee163c3081a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:30:48 +0800 +Subject: leds: lgm-sso: Remove duplicate assignments for priv->mmap + +From: Chen Ni + +[ Upstream commit 7186d0330c3f3e86de577687a82f4ebd96dcb5ac ] + +Remove duplicate assignment of priv->mmap in intel_sso_led_probe(). + +Fixes: fba8a6f2263b ("leds: lgm-sso: Fix clock handling") +Signed-off-by: Chen Ni +Link: https://patch.msgid.link/20260226033048.3715915-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 8923d2df47049..3d9ef9a54805c 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -808,8 +808,6 @@ static int intel_sso_led_probe(struct platform_device *pdev) + + priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk); + +- priv->mmap = syscon_node_to_regmap(dev->of_node); +- + priv->mmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(priv->mmap)) { + dev_err(dev, "Failed to map iomem!\n"); +-- +2.53.0 + diff --git a/queue-6.18/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch b/queue-6.18/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch new file mode 100644 index 0000000000..ea8d17562d --- /dev/null +++ b/queue-6.18/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch @@ -0,0 +1,51 @@ +From f55904c4e593fdcc48b603d110aa04fe8eceef00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 17:21:43 +0200 +Subject: lib/hexdump: print_hex_dump_bytes() calls print_hex_dump_debug() + +From: Geert Uytterhoeven + +[ Upstream commit 36776b7f8a8955b4e75b5d490a75fee0c7a2a7ef ] + +print_hex_dump_bytes() claims to be a simple wrapper around +print_hex_dump(), but it actally calls print_hex_dump_debug(), which +means no output is printed if (dynamic) DEBUG is disabled. + +Update the documentation to match the implementation. + +Fixes: 091cb0994edd20d6 ("lib/hexdump: make print_hex_dump_bytes() a nop on !DEBUG builds") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Petr Mladek +Link: https://patch.msgid.link/3d5c3069fd9102ecaf81d044b750cd613eb72a08.1774970392.git.geert+renesas@glider.be +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + include/linux/printk.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 9a8eaed5f8778..a98d64b45bc93 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -816,7 +816,8 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, + #endif + + /** +- * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params ++ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default ++ * params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none +@@ -824,7 +825,7 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, + * @buf: data blob to dump + * @len: number of bytes in the @buf + * +- * Calls print_hex_dump(), with log level of KERN_DEBUG, ++ * Calls print_hex_dump_debug(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ + #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ +-- +2.53.0 + diff --git a/queue-6.18/lib-kunit_iov_iter-fix-memory-leaks.patch b/queue-6.18/lib-kunit_iov_iter-fix-memory-leaks.patch new file mode 100644 index 0000000000..abdc599203 --- /dev/null +++ b/queue-6.18/lib-kunit_iov_iter-fix-memory-leaks.patch @@ -0,0 +1,85 @@ +From 692e7bfab33ce3f37bfd660dadfd7eb5434571b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:49:03 +0100 +Subject: lib: kunit_iov_iter: fix memory leaks + +From: Christian A. Ehrhardt + +[ Upstream commit 0b49c7d0ae697fcecd7377cb7dda220f7cd096ff ] + +Use vfree() instead of vunmap() to free the buffer allocated by +iov_kunit_create_buffer() because vunmap() does not honour +VM_MAP_PUT_PAGES. In order for this to work the page array itself must +not be managed by kunit. + +Remove the folio_put() when destroying a folioq. This is handled by +vfree(), now. + +Pointed out by sashiko.dev on a previous iteration of this series. + +Tested by running the kunit test 10000 times in a loop. + +Link: https://lkml.kernel.org/r/20260326214905.818170-4-lk@c--e.de +Fixes: 2d71340ff1d4 ("iov_iter: Kunit tests for copying to/from an iterator") +Signed-off-by: Christian A. Ehrhardt +Cc: David Howells +Cc: David Gow +Cc: Kees Cook +Cc: Petr Mladek +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + lib/tests/kunit_iov_iter.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c +index 48342736d0164..43e63bf4c0956 100644 +--- a/lib/tests/kunit_iov_iter.c ++++ b/lib/tests/kunit_iov_iter.c +@@ -42,7 +42,7 @@ static inline u8 pattern(unsigned long x) + + static void iov_kunit_unmap(void *data) + { +- vunmap(data); ++ vfree(data); + } + + static void *__init iov_kunit_create_buffer(struct kunit *test, +@@ -53,17 +53,22 @@ static void *__init iov_kunit_create_buffer(struct kunit *test, + unsigned long got; + void *buffer; + +- pages = kunit_kcalloc(test, npages, sizeof(struct page *), GFP_KERNEL); +- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages); ++ pages = kzalloc_objs(struct page *, npages, GFP_KERNEL); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages); + *ppages = pages; + + got = alloc_pages_bulk(GFP_KERNEL, npages, pages); + if (got != npages) { + release_pages(pages, got); ++ kvfree(pages); + KUNIT_ASSERT_EQ(test, got, npages); + } + + buffer = vmap(pages, npages, VM_MAP | VM_MAP_PUT_PAGES, PAGE_KERNEL); ++ if (buffer == NULL) { ++ release_pages(pages, got); ++ kvfree(pages); ++ } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer); + + kunit_add_action_or_reset(test, iov_kunit_unmap, buffer); +@@ -369,9 +374,6 @@ static void iov_kunit_destroy_folioq(void *data) + + for (folioq = data; folioq; folioq = next) { + next = folioq->next; +- for (int i = 0; i < folioq_nr_slots(folioq); i++) +- if (folioq_folio(folioq, i)) +- folio_put(folioq_folio(folioq, i)); + kfree(folioq); + } + } +-- +2.53.0 + diff --git a/queue-6.18/libbpf-prevent-double-close-and-leak-of-btf-objects.patch b/queue-6.18/libbpf-prevent-double-close-and-leak-of-btf-objects.patch new file mode 100644 index 0000000000..1d6701ff4f --- /dev/null +++ b/queue-6.18/libbpf-prevent-double-close-and-leak-of-btf-objects.patch @@ -0,0 +1,98 @@ +From 74b4ec29be21a7cbcffe63447760834c91421906 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 12:00:34 +0200 +Subject: libbpf: Prevent double close and leak of btf objects + +From: Jiri Olsa + +[ Upstream commit 380044c40b1636a72fd8f188b5806be6ae564279 ] + +Sashiko found possible double close of btf object fd [1], +which happens when strdup in load_module_btfs fails at which +point the obj->btf_module_cnt is already incremented. + +The error path close btf fd and so does later cleanup code in +bpf_object_post_load_cleanup function. + +Also libbpf_ensure_mem failure leaves btf object not assigned +and it's leaked. + +Replacing the err_out label with break to make the error path +less confusing as suggested by Alan. + +Incrementing obj->btf_module_cnt only if there's no failure +and releasing btf object in error path. + +Fixes: 91abb4a6d79d ("libbpf: Support attachment of BPF tracing programs to kernel modules") +[1] https://sashiko.dev/#/patchset/20260324081846.2334094-1-jolsa%40kernel.org +Signed-off-by: Jiri Olsa +Link: https://lore.kernel.org/r/20260416100034.1610852-1-jolsa@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/libbpf.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 9c98c6adb6d05..84b6fb47a2f79 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -5746,11 +5746,12 @@ static int load_module_btfs(struct bpf_object *obj) + info.name = ptr_to_u64(name); + info.name_len = sizeof(name); + ++ btf = NULL; + err = bpf_btf_get_info_by_fd(fd, &info, &len); + if (err) { + err = -errno; + pr_warn("failed to get BTF object #%d info: %s\n", id, errstr(err)); +- goto err_out; ++ break; + } + + /* ignore non-module BTFs */ +@@ -5764,15 +5765,15 @@ static int load_module_btfs(struct bpf_object *obj) + if (err) { + pr_warn("failed to load module [%s]'s BTF object #%d: %s\n", + name, id, errstr(err)); +- goto err_out; ++ break; + } + + err = libbpf_ensure_mem((void **)&obj->btf_modules, &obj->btf_module_cap, + sizeof(*obj->btf_modules), obj->btf_module_cnt + 1); + if (err) +- goto err_out; ++ break; + +- mod_btf = &obj->btf_modules[obj->btf_module_cnt++]; ++ mod_btf = &obj->btf_modules[obj->btf_module_cnt]; + + mod_btf->btf = btf; + mod_btf->id = id; +@@ -5780,16 +5781,16 @@ static int load_module_btfs(struct bpf_object *obj) + mod_btf->name = strdup(name); + if (!mod_btf->name) { + err = -ENOMEM; +- goto err_out; ++ break; + } +- continue; ++ obj->btf_module_cnt++; ++ } + +-err_out: ++ if (err) { ++ btf__free(btf); + close(fd); +- return err; + } +- +- return 0; ++ return err; + } + + static struct bpf_core_cand_list * +-- +2.53.0 + diff --git a/queue-6.18/linux-6.18.32.patch b/queue-6.18/linux-6.18.32.patch new file mode 100644 index 0000000000..73cd57155b --- /dev/null +++ b/queue-6.18/linux-6.18.32.patch @@ -0,0 +1,41 @@ +From 031f0abf85b5ab1c19c62e85063cf4a5ac35cd4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 17 May 2026 17:15:37 +0200 +Subject: Linux 6.18.32 + +From: Greg Kroah-Hartman + +Link: https://lore.kernel.org/r/20260515154657.309489048@linuxfoundation.org +Tested-by: Florian Fainelli +Tested-by: Pavel Machek (CIP) +Tested-by: Shuah Khan +Tested-by: Miguel Ojeda +Tested-by: Mark Brown +Tested-by: Brett A C Sheffield +Link: https://lore.kernel.org/r/20260516102236.209957148@linuxfoundation.org +Tested-by: Brett A C Sheffield +Tested-by: Ron Economos +Tested-by: Peter Schneider +Tested-by: Miguel Ojeda +Tested-by: Wentao Guan +Signed-off-by: Greg Kroah-Hartman +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 89c614db52409..d1fcec7cf9568 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 18 +-SUBLEVEL = 31 ++SUBLEVEL = 32 + EXTRAVERSION = + NAME = Baby Opossum Posse + +-- +2.53.0 + diff --git a/queue-6.18/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch b/queue-6.18/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch new file mode 100644 index 0000000000..3538de9a5b --- /dev/null +++ b/queue-6.18/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch @@ -0,0 +1,75 @@ +From c01307c686a45e9e6b11b0f063e5372239ef04ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:15:07 -0700 +Subject: locking: Fix rwlock support in + +From: Bart Van Assche + +[ Upstream commit 756a0e011cfca0b45a48464aa25b05d9a9c2fb0b ] + +Architecture support for rwlocks must be available whether or not +CONFIG_DEBUG_SPINLOCK has been defined. Move the definitions of the +arch_{read,write}_{lock,trylock,unlock}() macros such that these become +visbile if CONFIG_DEBUG_SPINLOCK=n. + +This patch prepares for converting do_raw_{read,write}_trylock() into +inline functions. Without this patch that conversion triggers a build +failure for UP architectures, e.g. arm-ep93xx. I used the following +kernel configuration to build the kernel for that architecture: + + CONFIG_ARCH_MULTIPLATFORM=y + CONFIG_ARCH_MULTI_V7=n + CONFIG_ATAGS=y + CONFIG_MMU=y + CONFIG_ARCH_MULTI_V4T=y + CONFIG_CPU_LITTLE_ENDIAN=y + CONFIG_ARCH_EP93XX=y + +Fixes: fb1c8f93d869 ("[PATCH] spinlock consolidation") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260313171510.230998-2-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/spinlock_up.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h +index 1e84e71ca495e..3a50976471d71 100644 +--- a/include/linux/spinlock_up.h ++++ b/include/linux/spinlock_up.h +@@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + lock->slock = 1; + } + +-/* +- * Read-write spinlocks. No debug version. +- */ +-#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) +- + #else /* DEBUG_SPINLOCK */ + #define arch_spin_is_locked(lock) ((void)(lock), 0) + /* for sched/core.c and kernel_lock.c: */ +@@ -68,4 +58,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + + #define arch_spin_is_contended(lock) (((void)(lock), 0)) + ++/* ++ * Read-write spinlocks. No debug version. ++ */ ++#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) ++ + #endif /* __LINUX_SPINLOCK_UP_H */ +-- +2.53.0 + diff --git a/queue-6.18/loop-fix-partition-scan-race-between-udev-and-loop_r.patch b/queue-6.18/loop-fix-partition-scan-race-between-udev-and-loop_r.patch new file mode 100644 index 0000000000..99812bd971 --- /dev/null +++ b/queue-6.18/loop-fix-partition-scan-race-between-udev-and-loop_r.patch @@ -0,0 +1,87 @@ +From f50605721114b256b1139694e009963c1f14e06f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:51:28 +0000 +Subject: loop: fix partition scan race between udev and + loop_reread_partitions() + +From: Daan De Meyer + +[ Upstream commit 267ec4d7223a783f029a980f41b93c39b17996da ] + +When LOOP_CONFIGURE is called with LO_FLAGS_PARTSCAN, the following +sequence occurs: + + 1. disk_force_media_change() sets GD_NEED_PART_SCAN + 2. Uevent suppression is lifted and a KOBJ_CHANGE uevent is sent + 3. loop_global_unlock() releases the lock + 4. loop_reread_partitions() calls bdev_disk_changed() to scan + +There is a race between steps 2 and 4: when udev receives the uevent +and opens the device before loop_reread_partitions() runs, +blkdev_get_whole() in bdev.c sees GD_NEED_PART_SCAN set and calls +bdev_disk_changed() for a first scan. Then loop_reread_partitions() +does a second scan. The open_mutex serializes these two scans, but +does not prevent both from running. + +The second scan in bdev_disk_changed() drops all partition devices +from the first scan (via blk_drop_partitions()) before re-adding +them, causing partition block devices to briefly disappear. This +breaks any systemd unit with BindsTo= on the partition device: systemd +observes the device going dead, fails the dependent units, and does +not retry them when the device reappears. + +Fix this by removing the GD_NEED_PART_SCAN set from +disk_force_media_change() entirely. None of the current callers need +the lazy on-open partition scan triggered by this flag: + + - floppy: sets GENHD_FL_NO_PART, so disk_has_partscan() is always + false and GD_NEED_PART_SCAN has no effect. + - loop (loop_configure, loop_change_fd): when LO_FLAGS_PARTSCAN is + set, loop_reread_partitions() performs an explicit scan. When not + set, GD_SUPPRESS_PART_SCAN prevents the lazy scan path. + - loop (__loop_clr_fd): calls bdev_disk_changed() explicitly if + LO_FLAGS_PARTSCAN is set. + - nbd (nbd_clear_sock_ioctl): capacity is set to zero immediately + after; nbd manages GD_NEED_PART_SCAN explicitly elsewhere. + +With GD_NEED_PART_SCAN no longer set by disk_force_media_change(), +udev opening the loop device after the uevent no longer triggers a +redundant scan in blkdev_get_whole(), and only the single explicit +scan from loop_reread_partitions() runs. + +A regression test for this bug has been submitted to blktests: +https://github.com/linux-blktests/blktests/pull/240. + +Fixes: 9f65c489b68d ("loop: raise media_change event") +Signed-off-by: Daan De Meyer +Acked-by: Christian Brauner +Link: https://patch.msgid.link/20260331105130.1077599-1-daan@amutable.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/disk-events.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/block/disk-events.c b/block/disk-events.c +index 2f697224386aa..868823915bdc6 100644 +--- a/block/disk-events.c ++++ b/block/disk-events.c +@@ -290,13 +290,14 @@ EXPORT_SYMBOL(disk_check_media_change); + * Should be called when the media changes for @disk. Generates a uevent + * and attempts to free all dentries and inodes and invalidates all block + * device page cache entries in that case. ++ * ++ * Callers that need a partition re-scan should arrange for one explicitly. + */ + void disk_force_media_change(struct gendisk *disk) + { + disk_event_uevent(disk, DISK_EVENT_MEDIA_CHANGE); + inc_diskseq(disk); + bdev_mark_dead(disk->part0, true); +- set_bit(GD_NEED_PART_SCAN, &disk->state); + } + EXPORT_SYMBOL_GPL(disk_force_media_change); + +-- +2.53.0 + diff --git a/queue-6.18/macsec-support-vlan-filtering-lower-devices.patch b/queue-6.18/macsec-support-vlan-filtering-lower-devices.patch new file mode 100644 index 0000000000..d9b5670264 --- /dev/null +++ b/queue-6.18/macsec-support-vlan-filtering-lower-devices.patch @@ -0,0 +1,190 @@ +From d09a635b8c36ca16d97537aead699f7dd969031f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:52:40 +0300 +Subject: macsec: Support VLAN-filtering lower devices + +From: Cosmin Ratiu + +[ Upstream commit a363b1c8be879c79a688eaf93ba01b63f8b0e63c ] + +VLAN-filtering is done through two netdev features +(NETIF_F_HW_VLAN_CTAG_FILTER and NETIF_F_HW_VLAN_STAG_FILTER) and two +netdev ops (ndo_vlan_rx_add_vid and ndo_vlan_rx_kill_vid). + +Implement these and advertise the features if the lower device supports +them. This allows proper VLAN filtering to work on top of MACsec +devices, when the lower device is capable of VLAN filtering. +As a concrete example, having this chain of interfaces now works: +vlan_filtering_capable_dev(1) -> macsec_dev(2) -> macsec_vlan_dev(3) + +Before the mentioned commit this used to accidentally work because the +MACsec device (and thus the lower device) was put in promiscuous mode +and the VLAN filter was not used. But after commit [1] correctly made +the macsec driver expose the IFF_UNICAST_FLT flag, promiscuous mode was +no longer used and VLAN filters on dev 1 kicked in. Without support in +dev 2 for propagating VLAN filters down, the register_vlan_dev -> +vlan_vid_add -> __vlan_vid_add -> vlan_add_rx_filter_info call from dev +3 is silently eaten (because vlan_hw_filter_capable returns false and +vlan_add_rx_filter_info silently succeeds). + +For MACsec, VLAN filters are only relevant for offload, otherwise +the VLANs are encrypted and the lower devices don't care about them. So +VLAN filters are only passed on to lower devices in offload mode. +Flipping between offload modes now needs to offload/unoffload the +filters with vlan_{get,drop}_rx_*_filter_info(). + +To avoid the back-and-forth filter updating during rollback, the setting +of macsec->offload is moved after the add/del secy ops. This is safe +since none of the code called from those requires macsec->offload. + +In case adding the filters fails, the added ones are rolled back and an +error is returned to the operation toggling the offload state. + +Fixes: 0349659fd72f ("macsec: set IFF_UNICAST_FLT priv flag") +Signed-off-by: Cosmin Ratiu +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260408115240.1636047-5-cratiu@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macsec.c | 71 +++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 63 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c +index 5200fd5a10e5c..5d820ef619469 100644 +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -2584,7 +2584,9 @@ static void macsec_inherit_tso_max(struct net_device *dev) + netif_inherit_tso_max(dev, macsec->real_dev); + } + +-static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload) ++static int macsec_update_offload(struct net_device *dev, ++ enum macsec_offload offload, ++ struct netlink_ext_ack *extack) + { + enum macsec_offload prev_offload; + const struct macsec_ops *ops; +@@ -2616,14 +2618,35 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off + if (!ops) + return -EOPNOTSUPP; + +- macsec->offload = offload; +- + ctx.secy = &macsec->secy; + ret = offload == MACSEC_OFFLOAD_OFF ? macsec_offload(ops->mdo_del_secy, &ctx) + : macsec_offload(ops->mdo_add_secy, &ctx); +- if (ret) { +- macsec->offload = prev_offload; ++ if (ret) + return ret; ++ ++ /* Remove VLAN filters when disabling offload. */ ++ if (offload == MACSEC_OFFLOAD_OFF) { ++ vlan_drop_rx_ctag_filter_info(dev); ++ vlan_drop_rx_stag_filter_info(dev); ++ } ++ macsec->offload = offload; ++ /* Add VLAN filters when enabling offload. */ ++ if (prev_offload == MACSEC_OFFLOAD_OFF) { ++ ret = vlan_get_rx_ctag_filter_info(dev); ++ if (ret) { ++ NL_SET_ERR_MSG_FMT(extack, ++ "adding ctag VLAN filters failed, err %d", ++ ret); ++ goto rollback_offload; ++ } ++ ret = vlan_get_rx_stag_filter_info(dev); ++ if (ret) { ++ NL_SET_ERR_MSG_FMT(extack, ++ "adding stag VLAN filters failed, err %d", ++ ret); ++ vlan_drop_rx_ctag_filter_info(dev); ++ goto rollback_offload; ++ } + } + + macsec_set_head_tail_room(dev); +@@ -2633,6 +2656,12 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off + + netdev_update_features(dev); + ++ return 0; ++ ++rollback_offload: ++ macsec->offload = prev_offload; ++ macsec_offload(ops->mdo_del_secy, &ctx); ++ + return ret; + } + +@@ -2673,7 +2702,7 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info) + offload = nla_get_u8(tb_offload[MACSEC_OFFLOAD_ATTR_TYPE]); + + if (macsec->offload != offload) +- ret = macsec_update_offload(dev, offload); ++ ret = macsec_update_offload(dev, offload, info->extack); + out: + rtnl_unlock(); + return ret; +@@ -3486,7 +3515,8 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb, + } + + #define MACSEC_FEATURES \ +- (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST) ++ (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ ++ NETIF_F_HW_VLAN_STAG_FILTER | NETIF_F_HW_VLAN_CTAG_FILTER) + + #define MACSEC_OFFLOAD_FEATURES \ + (MACSEC_FEATURES | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES | \ +@@ -3707,6 +3737,29 @@ static int macsec_set_mac_address(struct net_device *dev, void *p) + return err; + } + ++static int macsec_vlan_rx_add_vid(struct net_device *dev, ++ __be16 proto, u16 vid) ++{ ++ struct macsec_dev *macsec = netdev_priv(dev); ++ ++ if (!macsec_is_offloaded(macsec)) ++ return 0; ++ ++ return vlan_vid_add(macsec->real_dev, proto, vid); ++} ++ ++static int macsec_vlan_rx_kill_vid(struct net_device *dev, ++ __be16 proto, u16 vid) ++{ ++ struct macsec_dev *macsec = netdev_priv(dev); ++ ++ if (!macsec_is_offloaded(macsec)) ++ return 0; ++ ++ vlan_vid_del(macsec->real_dev, proto, vid); ++ return 0; ++} ++ + static int macsec_change_mtu(struct net_device *dev, int new_mtu) + { + struct macsec_dev *macsec = macsec_priv(dev); +@@ -3748,6 +3801,8 @@ static const struct net_device_ops macsec_netdev_ops = { + .ndo_set_rx_mode = macsec_dev_set_rx_mode, + .ndo_change_rx_flags = macsec_dev_change_rx_flags, + .ndo_set_mac_address = macsec_set_mac_address, ++ .ndo_vlan_rx_add_vid = macsec_vlan_rx_add_vid, ++ .ndo_vlan_rx_kill_vid = macsec_vlan_rx_kill_vid, + .ndo_start_xmit = macsec_start_xmit, + .ndo_get_stats64 = macsec_get_stats64, + .ndo_get_iflink = macsec_get_iflink, +@@ -3912,7 +3967,7 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[], + offload = nla_get_u8(data[IFLA_MACSEC_OFFLOAD]); + if (macsec->offload != offload) { + macsec_offload_state_change = true; +- ret = macsec_update_offload(dev, offload); ++ ret = macsec_update_offload(dev, offload, extack); + if (ret) + goto cleanup; + } +-- +2.53.0 + diff --git a/queue-6.18/macvlan-annotate-data-races-around-port-bc_queue_len.patch b/queue-6.18/macvlan-annotate-data-races-around-port-bc_queue_len.patch new file mode 100644 index 0000000000..a86c845c2f --- /dev/null +++ b/queue-6.18/macvlan-annotate-data-races-around-port-bc_queue_len.patch @@ -0,0 +1,67 @@ +From 36109f7472eaa6cb37f20e2f133f569f088ec06e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:38:08 +0000 +Subject: macvlan: annotate data-races around port->bc_queue_len_used + +From: Eric Dumazet + +[ Upstream commit 1ef5789d9906df3771c99b7f413caaf2bf473ca5 ] + +port->bc_queue_len_used is read and written locklessly, +add READ_ONCE()/WRITE_ONCE() annotations. + +While WRITE_ONCE() in macvlan_fill_info() is not yet needed, +it is a prereq for future RTNL avoidance. + +Fixes: d4bff72c8401 ("macvlan: Support for high multicast packet rate") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401103809.3038139-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index 4433b8e95b6ac..e9d288a05e39e 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -352,6 +352,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + const struct macvlan_dev *src, + struct sk_buff *skb) + { ++ u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used); + struct sk_buff *nskb; + int err = -ENOMEM; + +@@ -362,7 +363,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + MACVLAN_SKB_CB(nskb)->src = src; + + spin_lock(&port->bc_queue.lock); +- if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) { ++ if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) { + if (src) + dev_hold(src->dev); + __skb_queue_tail(&port->bc_queue, nskb); +@@ -1727,7 +1728,8 @@ static int macvlan_fill_info(struct sk_buff *skb, + } + if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) + goto nla_put_failure; +- if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) ++ if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, ++ READ_ONCE(port->bc_queue_len_used))) + goto nla_put_failure; + if (port->bc_cutoff != 1 && + nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff)) +@@ -1787,7 +1789,7 @@ static void update_port_bc_queue_len(struct macvlan_port *port) + if (vlan->bc_queue_len_req > max_bc_queue_len_req) + max_bc_queue_len_req = vlan->bc_queue_len_req; + } +- port->bc_queue_len_used = max_bc_queue_len_req; ++ WRITE_ONCE(port->bc_queue_len_used, max_bc_queue_len_req); + } + + static int macvlan_device_event(struct notifier_block *unused, +-- +2.53.0 + diff --git a/queue-6.18/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch b/queue-6.18/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch new file mode 100644 index 0000000000..83abe26e57 --- /dev/null +++ b/queue-6.18/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch @@ -0,0 +1,56 @@ +From a59990ce885ff647a6295225048e7d37c9c5b1b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:53:49 +0800 +Subject: macvlan: fix macvlan_get_size() not reserving space for + IFLA_MACVLAN_BC_CUTOFF + +From: Dudu Lu + +[ Upstream commit fa92a77b0ed4d5f11a71665a232ac5a54a4b055d ] + +macvlan_get_size() does not account for IFLA_MACVLAN_BC_CUTOFF, but +macvlan_fill_info() conditionally includes it when port->bc_cutoff != 1. +This causes nla_put_s32() to fail with -EMSGSIZE when the netlink skb +runs out of space, triggering a WARN_ON in rtnetlink and preventing the +interface from being dumped. + +The bug can be reproduced with: + + ip link add macvlan0 link eth0 type macvlan mode bridge + ip link set macvlan0 type macvlan bc_cutoff 0 + ip -d link show macvlan0 # fails with -EMSGSIZE + +The bc_cutoff feature was added in commit 954d1fa1ac93 ("macvlan: Add +netlink attribute for broadcast cutoff"), which added the nla_put_s32() +call in macvlan_fill_info() but missed adding the corresponding +nla_total_size(4) in macvlan_get_size(). A follow-up commit +55cef78c244d ("macvlan: add forgotten nla_policy for +IFLA_MACVLAN_BC_CUTOFF") fixed the missing nla_policy entry but still +did not fix the size calculation. + +Fixes: 954d1fa1ac93 ("macvlan: Add netlink attribute for broadcast cutoff") +Signed-off-by: Dudu Lu +Reviewed-by: Vadim Fedorenko +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260413085349.73977-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index e9d288a05e39e..35dcaa985cfdc 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -1682,6 +1682,7 @@ static size_t macvlan_get_size(const struct net_device *dev) + + macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN_USED */ ++ + nla_total_size(4) /* IFLA_MACVLAN_BC_CUTOFF */ + ); + } + +-- +2.53.0 + diff --git a/queue-6.18/mailbox-add-sanity-check-for-channel-array.patch b/queue-6.18/mailbox-add-sanity-check-for-channel-array.patch new file mode 100644 index 0000000000..b5b88aa8fc --- /dev/null +++ b/queue-6.18/mailbox-add-sanity-check-for-channel-array.patch @@ -0,0 +1,40 @@ +From dc6cca91ddf4a95271a76f3c138f879aa4739cfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:42:38 +0200 +Subject: mailbox: add sanity check for channel array + +From: Wolfram Sang + +[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ] + +Fail gracefully if there is no channel array attached to the mailbox +controller. Otherwise the later dereference will cause an OOPS which +might not be seen because mailbox controllers might instantiate very +early. Remove the comment explaining the obvious while here. + +Fixes: 2b6d83e2b8b7 ("mailbox: Introduce framework for mailbox") +Signed-off-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index 617ba505691d3..b77162db509f2 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -505,8 +505,7 @@ int mbox_controller_register(struct mbox_controller *mbox) + { + int i, txdone; + +- /* Sanity check */ +- if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) ++ if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) + return -EINVAL; + + if (mbox->txdone_irq) +-- +2.53.0 + diff --git a/queue-6.18/mailbox-mailbox-test-don-t-free-the-reused-channel.patch b/queue-6.18/mailbox-mailbox-test-don-t-free-the-reused-channel.patch new file mode 100644 index 0000000000..35c75f4244 --- /dev/null +++ b/queue-6.18/mailbox-mailbox-test-don-t-free-the-reused-channel.patch @@ -0,0 +1,46 @@ +From 8a0428c4cf3d44683b238af6baad789a67acf9a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:34 +0200 +Subject: mailbox: mailbox-test: don't free the reused channel + +From: Wolfram Sang + +[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ] + +The RX channel can be aliased to the TX channel if it has a different +MMIO. This special case needs to be handled when freeing the channels +otherwise a double-free occurs. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 197cad7b3d401..210f6077f475c 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -422,7 +422,7 @@ static int mbox_test_probe(struct platform_device *pdev) + err_free_chans: + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + return ret; + } +@@ -435,7 +435,7 @@ static void mbox_test_remove(struct platform_device *pdev) + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + } + +-- +2.53.0 + diff --git a/queue-6.18/mailbox-mailbox-test-free-channels-on-probe-error.patch b/queue-6.18/mailbox-mailbox-test-free-channels-on-probe-error.patch new file mode 100644 index 0000000000..49a3f77450 --- /dev/null +++ b/queue-6.18/mailbox-mailbox-test-free-channels-on-probe-error.patch @@ -0,0 +1,60 @@ +From 822f138d3abd82852f7740f2617908e802ad59ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 14:53:00 +0200 +Subject: mailbox: mailbox-test: free channels on probe error + +From: Wolfram Sang + +[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ] + +On probe error, free the previously obtained channels. This not only +prevents a leak, but also UAF scenarios because the client structure +will be removed nonetheless because it was allocated with devm. + +Link: https://sashiko.dev/#/patchset/20260327151217.5327-2-wsa%2Brenesas%40sang-engineering.com +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 3a28ab5c42e57..197cad7b3d401 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -404,18 +404,27 @@ static int mbox_test_probe(struct platform_device *pdev) + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +- if (!tdev->rx_buffer) +- return -ENOMEM; ++ if (!tdev->rx_buffer) { ++ ret = -ENOMEM; ++ goto err_free_chans; ++ } + } + + ret = mbox_test_add_debugfs(pdev, tdev); + if (ret) +- return ret; ++ goto err_free_chans; + + init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; ++ ++err_free_chans: ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ if (tdev->rx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ return ret; + } + + static void mbox_test_remove(struct platform_device *pdev) +-- +2.53.0 + diff --git a/queue-6.18/mailbox-mailbox-test-initialize-struct-earlier.patch b/queue-6.18/mailbox-mailbox-test-initialize-struct-earlier.patch new file mode 100644 index 0000000000..121cca93ef --- /dev/null +++ b/queue-6.18/mailbox-mailbox-test-initialize-struct-earlier.patch @@ -0,0 +1,64 @@ +From fa29df9bc1d71baa6e8e50b302f4a1eaf8bc39d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:35 +0200 +Subject: mailbox: mailbox-test: initialize struct earlier + +From: Wolfram Sang + +[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ] + +The waitqueue must be initialized before the debugfs files are created +because from that time, requests from userspace can already be made. +Similarily, drvdata and spinlock needs to be initialized before we +request the channel, otherwise dangling irqs might run into problems +like a NULL pointer exception. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 210f6077f475c..a0a7908c9cc26 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -366,6 +366,12 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev) + return -ENOMEM; + ++ tdev->dev = &pdev->dev; ++ spin_lock_init(&tdev->lock); ++ mutex_init(&tdev->mutex); ++ init_waitqueue_head(&tdev->waitq); ++ platform_set_drvdata(pdev, tdev); ++ + /* It's okay for MMIO to be NULL */ + tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { +@@ -395,12 +401,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) + tdev->rx_channel = tdev->tx_channel; + +- tdev->dev = &pdev->dev; +- platform_set_drvdata(pdev, tdev); +- +- spin_lock_init(&tdev->lock); +- mutex_init(&tdev->mutex); +- + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +@@ -414,7 +414,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (ret) + goto err_free_chans; + +- init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch b/queue-6.18/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch new file mode 100644 index 0000000000..f7aab22d70 --- /dev/null +++ b/queue-6.18/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch @@ -0,0 +1,73 @@ +From 2cd4bcd29f18cfe4d91d3d6a080e3ac91ee5a647 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:36 +0200 +Subject: mailbox: mailbox-test: make data_ready a per-instance variable + +From: Wolfram Sang + +[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ] + +While not the default case, multiple tests can be run simultaneously. +Then, data_ready being a global variable will be overwritten and the +per-instance lock will not help. Turn the global variable into a +per-instance one to avoid this problem. + +Fixes: e339c80af95e ("mailbox: mailbox-test: don't rely on rx_buffer content to signal data ready") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index a0a7908c9cc26..c429acd3af87c 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -28,8 +28,6 @@ + #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ + (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) + +-static bool mbox_data_ready; +- + struct mbox_test_device { + struct device *dev; + void __iomem *tx_mmio; +@@ -42,6 +40,7 @@ struct mbox_test_device { + spinlock_t lock; + struct mutex mutex; + wait_queue_head_t waitq; ++ bool data_ready; + struct fasync_struct *async_queue; + struct dentry *root_debugfs_dir; + }; +@@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); +- data_ready = mbox_data_ready; ++ data_ready = tdev->data_ready; + spin_unlock_irqrestore(&tdev->lock, flags); + + return data_ready; +@@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, + *(touser + l) = '\0'; + + memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); +- mbox_data_ready = false; ++ tdev->data_ready = false; + + spin_unlock_irqrestore(&tdev->lock, flags); + +@@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) + message, MBOX_MAX_MSG_LEN); + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); + } +- mbox_data_ready = true; ++ tdev->data_ready = true; + spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); +-- +2.53.0 + diff --git a/queue-6.18/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch b/queue-6.18/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch new file mode 100644 index 0000000000..52ad05d259 --- /dev/null +++ b/queue-6.18/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch @@ -0,0 +1,48 @@ +From 08866b9275e28a53c662e638f672ef0f3a8f4469 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:07:11 +0800 +Subject: mailbox: mtk-cmdq: Fix CURR and END addr for task insert case + +From: Jason-JH Lin + +[ Upstream commit d2591db9c8ef19fbb4d24ed15e0c6edfa6bc7917 ] + +Fix CURR and END address calculation for inserting a cmdq task into the +task list by using cmdq_reg_shift_addr() for proper address converting. +This ensures both CURR and END addresses are set correctly when +enabling the thread. + +Fixes: a195c7ccfb7a ("mailbox: mtk-cmdq: Refine DMA address handling for the command buffer") +Signed-off-by: Jason-JH Lin +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mtk-cmdq-mailbox.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c +index 5791f80f995ab..a1360b70b83fb 100644 +--- a/drivers/mailbox/mtk-cmdq-mailbox.c ++++ b/drivers/mailbox/mtk-cmdq-mailbox.c +@@ -434,14 +434,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data) + if (curr_pa == end_pa - CMDQ_INST_SIZE || + curr_pa == end_pa) { + /* set to this task directly */ +- writel(task->pa_base >> cmdq->pdata->shift, +- thread->base + CMDQ_THR_CURR_ADDR); ++ gce_addr = cmdq_convert_gce_addr(task->pa_base, cmdq->pdata); ++ writel(gce_addr, thread->base + CMDQ_THR_CURR_ADDR); + } else { + cmdq_task_insert_into_thread(task); + smp_mb(); /* modify jump before enable thread */ + } +- writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift, +- thread->base + CMDQ_THR_END_ADDR); ++ gce_addr = cmdq_convert_gce_addr(task->pa_base + pkt->cmd_buf_size, cmdq->pdata); ++ writel(gce_addr, thread->base + CMDQ_THR_END_ADDR); + cmdq_thread_resume(thread); + } + list_move_tail(&task->list_entry, &thread->task_busy_list); +-- +2.53.0 + diff --git a/queue-6.18/md-add-fallback-to-correct-bitmap_ops-on-version-mis.patch b/queue-6.18/md-add-fallback-to-correct-bitmap_ops-on-version-mis.patch new file mode 100644 index 0000000000..638eb4d74d --- /dev/null +++ b/queue-6.18/md-add-fallback-to-correct-bitmap_ops-on-version-mis.patch @@ -0,0 +1,154 @@ +From 2dc6e050ca55dad7b09c631a75f734107a074326 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 13:46:42 +0800 +Subject: md: add fallback to correct bitmap_ops on version mismatch + +From: Yu Kuai + +[ Upstream commit 09af773650024279a60348e7319d599e6571b15c ] + +If default bitmap version and on-disk version doesn't match, and mdadm +is not the latest version to set bitmap_type, set bitmap_ops based on +the disk version. + +Link: https://lore.kernel.org/linux-raid/20260323054644.3351791-2-yukuai@fnnas.com/ +Signed-off-by: Yu Kuai +Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow") +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 110 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index b91ac1b7d7a15..4520c485c0c06 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -6329,15 +6329,124 @@ static void md_safemode_timeout(struct timer_list *t) + + static int start_dirty_degraded; + ++/* ++ * Read bitmap superblock and return the bitmap_id based on disk version. ++ * This is used as fallback when default bitmap version and on-disk version ++ * doesn't match, and mdadm is not the latest version to set bitmap_type. ++ */ ++static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev) ++{ ++ struct md_rdev *rdev; ++ struct page *sb_page; ++ bitmap_super_t *sb; ++ enum md_submodule_id id = ID_BITMAP_NONE; ++ sector_t sector; ++ u32 version; ++ ++ if (!mddev->bitmap_info.offset) ++ return ID_BITMAP_NONE; ++ ++ sb_page = alloc_page(GFP_KERNEL); ++ if (!sb_page) { ++ pr_warn("md: %s: failed to allocate memory for bitmap\n", ++ mdname(mddev)); ++ return ID_BITMAP_NONE; ++ } ++ ++ sector = mddev->bitmap_info.offset; ++ ++ rdev_for_each(rdev, mddev) { ++ u32 iosize; ++ ++ if (!test_bit(In_sync, &rdev->flags) || ++ test_bit(Faulty, &rdev->flags) || ++ test_bit(Bitmap_sync, &rdev->flags)) ++ continue; ++ ++ iosize = roundup(sizeof(bitmap_super_t), ++ bdev_logical_block_size(rdev->bdev)); ++ if (sync_page_io(rdev, sector, iosize, sb_page, REQ_OP_READ, ++ true)) ++ goto read_ok; ++ } ++ pr_warn("md: %s: failed to read bitmap from any device\n", ++ mdname(mddev)); ++ goto out; ++ ++read_ok: ++ sb = kmap_local_page(sb_page); ++ if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) { ++ pr_warn("md: %s: invalid bitmap magic 0x%x\n", ++ mdname(mddev), le32_to_cpu(sb->magic)); ++ goto out_unmap; ++ } ++ ++ version = le32_to_cpu(sb->version); ++ switch (version) { ++ case BITMAP_MAJOR_LO: ++ case BITMAP_MAJOR_HI: ++ case BITMAP_MAJOR_CLUSTERED: ++ id = ID_BITMAP; ++ break; ++ case BITMAP_MAJOR_LOCKLESS: ++ id = ID_LLBITMAP; ++ break; ++ default: ++ pr_warn("md: %s: unknown bitmap version %u\n", ++ mdname(mddev), version); ++ break; ++ } ++ ++out_unmap: ++ kunmap_local(sb); ++out: ++ __free_page(sb_page); ++ return id; ++} ++ + static int md_bitmap_create(struct mddev *mddev) + { ++ enum md_submodule_id orig_id = mddev->bitmap_id; ++ enum md_submodule_id sb_id; ++ int err; ++ + if (mddev->bitmap_id == ID_BITMAP_NONE) + return -EINVAL; + + if (!mddev_set_bitmap_ops(mddev)) + return -ENOENT; + +- return mddev->bitmap_ops->create(mddev); ++ err = mddev->bitmap_ops->create(mddev); ++ if (!err) ++ return 0; ++ ++ /* ++ * Create failed, if default bitmap version and on-disk version ++ * doesn't match, and mdadm is not the latest version to set ++ * bitmap_type, set bitmap_ops based on the disk version. ++ */ ++ mddev_clear_bitmap_ops(mddev); ++ ++ sb_id = md_bitmap_get_id_from_sb(mddev); ++ if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) ++ return err; ++ ++ pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n", ++ mdname(mddev), orig_id, sb_id); ++ ++ mddev->bitmap_id = sb_id; ++ if (!mddev_set_bitmap_ops(mddev)) { ++ mddev->bitmap_id = orig_id; ++ return -ENOENT; ++ } ++ ++ err = mddev->bitmap_ops->create(mddev); ++ if (err) { ++ mddev_clear_bitmap_ops(mddev); ++ mddev->bitmap_id = orig_id; ++ } ++ ++ return err; + } + + static void md_bitmap_destroy(struct mddev *mddev) +-- +2.53.0 + diff --git a/queue-6.18/md-factor-bitmap-creation-away-from-sysfs-handling.patch b/queue-6.18/md-factor-bitmap-creation-away-from-sysfs-handling.patch new file mode 100644 index 0000000000..1fac38d232 --- /dev/null +++ b/queue-6.18/md-factor-bitmap-creation-away-from-sysfs-handling.patch @@ -0,0 +1,176 @@ +From dcc093122b406ab425db6167f67000067a960864 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:46:13 +0800 +Subject: md: factor bitmap creation away from sysfs handling + +From: Yu Kuai + +[ Upstream commit 8776d342cf8fa0b98ca5e6fb2d956966fb5ca364 ] + +Factor bitmap creation and destruction into helpers that do not touch +bitmap sysfs registration. + +This prepares the bitmap sysfs rework so callers such as the sysfs +bitmap location path can create or destroy a bitmap backend without +coupling that to sysfs group lifetime management. + +Reviewed-by: Su Yue +Link: https://lore.kernel.org/r/20260425024615.1696892-2-yukuai@fnnas.com +Signed-off-by: Yu Kuai +Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow") +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 78 +++++++++++++++++++++++++++++++------------------ + 1 file changed, 49 insertions(+), 29 deletions(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 4520c485c0c06..3061370e959b3 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -686,7 +686,25 @@ static void active_io_release(struct percpu_ref *ref) + + static void no_op(struct percpu_ref *r) {} + +-static bool mddev_set_bitmap_ops(struct mddev *mddev) ++static void md_bitmap_sysfs_add(struct mddev *mddev) ++{ ++ if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group)) ++ pr_warn("md: cannot register extra bitmap attributes for %s\n", ++ mdname(mddev)); ++ else ++ /* ++ * Inform user with KOBJ_CHANGE about new bitmap ++ * attributes. ++ */ ++ kobject_uevent(&mddev->kobj, KOBJ_CHANGE); ++} ++ ++static void md_bitmap_sysfs_del(struct mddev *mddev) ++{ ++ sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group); ++} ++ ++static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) + { + struct bitmap_operations *old = mddev->bitmap_ops; + struct md_submodule_head *head; +@@ -710,18 +728,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev) + + mddev->bitmap_ops = (void *)head; + xa_unlock(&md_submodule); +- +- if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) { +- if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group)) +- pr_warn("md: cannot register extra bitmap attributes for %s\n", +- mdname(mddev)); +- else +- /* +- * Inform user with KOBJ_CHANGE about new bitmap +- * attributes. +- */ +- kobject_uevent(&mddev->kobj, KOBJ_CHANGE); +- } + return true; + + err: +@@ -729,15 +735,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev) + return false; + } + +-static void mddev_clear_bitmap_ops(struct mddev *mddev) +-{ +- if (!mddev_is_dm(mddev) && mddev->bitmap_ops && +- mddev->bitmap_ops->group) +- sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group); +- +- mddev->bitmap_ops = NULL; +-} +- + int mddev_init(struct mddev *mddev) + { + int err = 0; +@@ -6404,7 +6401,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev) + return id; + } + +-static int md_bitmap_create(struct mddev *mddev) ++static int md_bitmap_create_nosysfs(struct mddev *mddev) + { + enum md_submodule_id orig_id = mddev->bitmap_id; + enum md_submodule_id sb_id; +@@ -6413,7 +6410,7 @@ static int md_bitmap_create(struct mddev *mddev) + if (mddev->bitmap_id == ID_BITMAP_NONE) + return -EINVAL; + +- if (!mddev_set_bitmap_ops(mddev)) ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) + return -ENOENT; + + err = mddev->bitmap_ops->create(mddev); +@@ -6425,7 +6422,7 @@ static int md_bitmap_create(struct mddev *mddev) + * doesn't match, and mdadm is not the latest version to set + * bitmap_type, set bitmap_ops based on the disk version. + */ +- mddev_clear_bitmap_ops(mddev); ++ mddev->bitmap_ops = NULL; + + sb_id = md_bitmap_get_id_from_sb(mddev); + if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) +@@ -6435,27 +6432,50 @@ static int md_bitmap_create(struct mddev *mddev) + mdname(mddev), orig_id, sb_id); + + mddev->bitmap_id = sb_id; +- if (!mddev_set_bitmap_ops(mddev)) { ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) { + mddev->bitmap_id = orig_id; + return -ENOENT; + } + + err = mddev->bitmap_ops->create(mddev); + if (err) { +- mddev_clear_bitmap_ops(mddev); ++ mddev->bitmap_ops = NULL; + mddev->bitmap_id = orig_id; + } + + return err; + } + +-static void md_bitmap_destroy(struct mddev *mddev) ++static int md_bitmap_create(struct mddev *mddev) ++{ ++ int err; ++ ++ err = md_bitmap_create_nosysfs(mddev); ++ if (err) ++ return err; ++ ++ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) ++ md_bitmap_sysfs_add(mddev); ++ ++ return 0; ++} ++ ++static void md_bitmap_destroy_nosysfs(struct mddev *mddev) + { + if (!md_bitmap_registered(mddev)) + return; + + mddev->bitmap_ops->destroy(mddev); +- mddev_clear_bitmap_ops(mddev); ++ mddev->bitmap_ops = NULL; ++} ++ ++static void md_bitmap_destroy(struct mddev *mddev) ++{ ++ if (!mddev_is_dm(mddev) && mddev->bitmap_ops && ++ mddev->bitmap_ops->group) ++ md_bitmap_sysfs_del(mddev); ++ ++ md_bitmap_destroy_nosysfs(mddev); + } + + int md_run(struct mddev *mddev) +-- +2.53.0 + diff --git a/queue-6.18/md-fix-array_state-clear-sysfs-deadlock.patch b/queue-6.18/md-fix-array_state-clear-sysfs-deadlock.patch new file mode 100644 index 0000000000..f47ab2d8b6 --- /dev/null +++ b/queue-6.18/md-fix-array_state-clear-sysfs-deadlock.patch @@ -0,0 +1,100 @@ +From 05e3d6388394f01ef6f4c9ea28d12f1118f7044b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 13:52:13 +0800 +Subject: md: fix array_state=clear sysfs deadlock + +From: Yu Kuai + +[ Upstream commit 2aa72276fab9851dbd59c2daeb4b590c5a113908 ] + +When "clear" is written to array_state, md_attr_store() breaks sysfs +active protection so the array can delete itself from its own sysfs +store method. + +However, md_attr_store() currently drops the mddev reference before +calling sysfs_unbreak_active_protection(). Once do_md_stop(..., 0) +has made the mddev eligible for delayed deletion, the temporary +kobject reference taken by sysfs_break_active_protection() can become +the last kobject reference protecting the md kobject. + +That allows sysfs_unbreak_active_protection() to drop the last +kobject reference from the current sysfs writer context. kobject +teardown then recurses into kernfs removal while the current sysfs +node is still being unwound, and lockdep reports recursive locking on +kn->active with kernfs_drain() in the call chain. + +Reproducer on an existing level: +1. Create an md0 linear array and activate it: + mknod /dev/md0 b 9 0 + echo none > /sys/block/md0/md/metadata_version + echo linear > /sys/block/md0/md/level + echo 1 > /sys/block/md0/md/raid_disks + echo "$(cat /sys/class/block/sdb/dev)" > /sys/block/md0/md/new_dev + echo "$(($(cat /sys/class/block/sdb/size) / 2))" > \ + /sys/block/md0/md/dev-sdb/size + echo 0 > /sys/block/md0/md/dev-sdb/slot + echo active > /sys/block/md0/md/array_state +2. Wait briefly for the array to settle, then clear it: + sleep 2 + echo clear > /sys/block/md0/md/array_state + +The warning looks like: + + WARNING: possible recursive locking detected + bash/588 is trying to acquire lock: + (kn->active#65) at __kernfs_remove+0x157/0x1d0 + but task is already holding lock: + (kn->active#65) at sysfs_unbreak_active_protection+0x1f/0x40 + ... + Call Trace: + kernfs_drain + __kernfs_remove + kernfs_remove_by_name_ns + sysfs_remove_group + sysfs_remove_groups + __kobject_del + kobject_put + md_attr_store + kernfs_fop_write_iter + vfs_write + ksys_write + +Restore active protection before mddev_put() so the extra sysfs +kobject reference is dropped while the mddev is still held alive. The +actual md kobject deletion is then deferred until after the sysfs +write path has fully returned. + +Fixes: 9e59d609763f ("md: call del_gendisk in control path") +Reviewed-by: Xiao Ni +Link: https://lore.kernel.org/linux-raid/20260330055213.3976052-1-yukuai@fnnas.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 92ec4be20db85..7560e98dc35b3 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -6032,10 +6032,16 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, + } + spin_unlock(&all_mddevs_lock); + rv = entry->store(mddev, page, length); +- mddev_put(mddev); + ++ /* ++ * For "array_state=clear", dropping the extra kobject reference from ++ * sysfs_break_active_protection() can trigger md kobject deletion. ++ * Restore active protection before mddev_put() so deletion happens ++ * after the sysfs write path fully unwinds. ++ */ + if (kn) + sysfs_unbreak_active_protection(kn); ++ mddev_put(mddev); + + return rv; + } +-- +2.53.0 + diff --git a/queue-6.18/md-md-bitmap-add-a-none-backend-for-bitmap-grow.patch b/queue-6.18/md-md-bitmap-add-a-none-backend-for-bitmap-grow.patch new file mode 100644 index 0000000000..83b1e08a3c --- /dev/null +++ b/queue-6.18/md-md-bitmap-add-a-none-backend-for-bitmap-grow.patch @@ -0,0 +1,362 @@ +From 3c83b03b8db48c5b0316436f35767b86dfaacc7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:46:15 +0800 +Subject: md/md-bitmap: add a none backend for bitmap grow + +From: Yu Kuai + +[ Upstream commit f2926a533d03fe70d753b512b713e06a2aa174af ] + +Add a real none bitmap backend that exposes the common bitmap sysfs +group and use it to keep bitmap/location available when an array has no +bitmap. + +Then switch the bitmap location sysfs path to move only between none +and the classic bitmap backend, using the no-sysfs bitmap helpers while +merging or unmerging the internal bitmap sysfs group. + +This restores mdadm --grow bitmap addition through bitmap/location. + +Fixes: fb8cc3b0d9db ("md/md-bitmap: delay registration of bitmap_ops until creating bitmap") +Reviewed-by: Su Yue +Link: https://lore.kernel.org/r/20260425024615.1696892-4-yukuai@fnnas.com +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md-bitmap.c | 108 ++++++++++++++++++++++++++++++++++++++--- + drivers/md/md.c | 42 +++++++++++++--- + drivers/md/md.h | 3 ++ + 3 files changed, 137 insertions(+), 16 deletions(-) + +diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c +index 7a96600949139..35943f5f68347 100644 +--- a/drivers/md/md-bitmap.c ++++ b/drivers/md/md-bitmap.c +@@ -216,6 +216,7 @@ struct bitmap { + }; + + static struct workqueue_struct *md_bitmap_wq; ++static struct attribute_group md_bitmap_internal_group; + + static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks, + int chunksize, bool init); +@@ -2581,6 +2582,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize) + return __bitmap_resize(bitmap, blocks, chunksize, false); + } + ++static bool bitmap_none_enabled(void *data, bool flush) ++{ ++ return false; ++} ++ ++static int bitmap_none_create(struct mddev *mddev) ++{ ++ return 0; ++} ++ ++static int bitmap_none_load(struct mddev *mddev) ++{ ++ return 0; ++} ++ ++static void bitmap_none_destroy(struct mddev *mddev) ++{ ++} ++ ++static int bitmap_none_get_stats(void *data, struct md_bitmap_stats *stats) ++{ ++ return -ENOENT; ++} ++ + static ssize_t + location_show(struct mddev *mddev, char *page) + { +@@ -2619,7 +2644,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len) + goto out; + } + +- bitmap_destroy(mddev); ++ sysfs_unmerge_group(&mddev->kobj, &md_bitmap_internal_group); ++ md_bitmap_destroy_nosysfs(mddev); ++ mddev->bitmap_id = ID_BITMAP_NONE; ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ goto none_err; + mddev->bitmap_info.offset = 0; + if (mddev->bitmap_info.file) { + struct file *f = mddev->bitmap_info.file; +@@ -2655,16 +2684,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len) + } + + mddev->bitmap_info.offset = offset; +- rv = bitmap_create(mddev); ++ md_bitmap_destroy_nosysfs(mddev); ++ mddev->bitmap_id = ID_BITMAP; ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ goto bitmap_err; ++ ++ rv = md_bitmap_create_nosysfs(mddev); + if (rv) +- goto out; ++ goto create_err; + +- rv = bitmap_load(mddev); ++ rv = mddev->bitmap_ops->load(mddev); + if (rv) { + mddev->bitmap_info.offset = 0; +- bitmap_destroy(mddev); +- goto out; ++ goto load_err; + } ++ ++ rv = sysfs_merge_group(&mddev->kobj, ++ &md_bitmap_internal_group); ++ if (rv) ++ goto merge_err; + } + } + if (!mddev->external) { +@@ -2680,6 +2718,22 @@ location_store(struct mddev *mddev, const char *buf, size_t len) + if (rv) + return rv; + return len; ++ ++merge_err: ++ mddev->bitmap_info.offset = 0; ++load_err: ++ md_bitmap_destroy_nosysfs(mddev); ++create_err: ++ mddev->bitmap_info.offset = 0; ++ mddev->bitmap_id = ID_BITMAP_NONE; ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ rv = -ENOENT; ++ goto out; ++bitmap_err: ++ rv = -ENOENT; ++none_err: ++ mddev->bitmap_info.offset = 0; ++ goto out; + } + + static struct md_sysfs_entry bitmap_location = +@@ -2988,6 +3042,27 @@ static const struct attribute_group *bitmap_groups[] = { + NULL, + }; + ++static const struct attribute_group *bitmap_none_groups[] = { ++ &md_bitmap_common_group, ++ NULL, ++}; ++ ++static struct bitmap_operations bitmap_none_ops = { ++ .head = { ++ .type = MD_BITMAP, ++ .id = ID_BITMAP_NONE, ++ .name = "none", ++ }, ++ ++ .enabled = bitmap_none_enabled, ++ .create = bitmap_none_create, ++ .load = bitmap_none_load, ++ .destroy = bitmap_none_destroy, ++ .get_stats = bitmap_none_get_stats, ++ ++ .groups = bitmap_none_groups, ++}; ++ + static struct bitmap_operations bitmap_ops = { + .head = { + .type = MD_BITMAP, +@@ -3034,16 +3109,33 @@ static struct bitmap_operations bitmap_ops = { + + int md_bitmap_init(void) + { ++ int err; ++ + md_bitmap_wq = alloc_workqueue("md_bitmap", WQ_MEM_RECLAIM | WQ_UNBOUND, + 0); + if (!md_bitmap_wq) + return -ENOMEM; + +- return register_md_submodule(&bitmap_ops.head); ++ err = register_md_submodule(&bitmap_none_ops.head); ++ if (err) ++ goto err_wq; ++ ++ err = register_md_submodule(&bitmap_ops.head); ++ if (err) ++ goto err_none; ++ ++ return 0; ++ ++err_none: ++ unregister_md_submodule(&bitmap_none_ops.head); ++err_wq: ++ destroy_workqueue(md_bitmap_wq); ++ return err; + } + + void md_bitmap_exit(void) + { +- destroy_workqueue(md_bitmap_wq); + unregister_md_submodule(&bitmap_ops.head); ++ unregister_md_submodule(&bitmap_none_ops.head); ++ destroy_workqueue(md_bitmap_wq); + } +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 213221abc44c3..b7d47c018a12f 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -712,7 +712,7 @@ static void md_bitmap_sysfs_del(struct mddev *mddev) + sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]); + } + +-static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) ++bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) + { + struct md_submodule_head *head; + +@@ -4274,7 +4274,7 @@ bitmap_type_show(struct mddev *mddev, char *page) + + xa_lock(&md_submodule); + xa_for_each(&md_submodule, i, head) { +- if (head->type != MD_BITMAP) ++ if (head->type != MD_BITMAP || head->id == ID_BITMAP_NONE) + continue; + + if (mddev->bitmap_id == head->id) +@@ -6408,7 +6408,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev) + return id; + } + +-static int md_bitmap_create_nosysfs(struct mddev *mddev) ++int md_bitmap_create_nosysfs(struct mddev *mddev) + { + enum md_submodule_id orig_id = mddev->bitmap_id; + enum md_submodule_id sb_id; +@@ -6417,8 +6417,10 @@ static int md_bitmap_create_nosysfs(struct mddev *mddev) + if (mddev->bitmap_id == ID_BITMAP_NONE) + return -EINVAL; + +- if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) { ++ mddev->bitmap_id = orig_id; + return -ENOENT; ++ } + + err = mddev->bitmap_ops->create(mddev); + if (!err) +@@ -6432,8 +6434,10 @@ static int md_bitmap_create_nosysfs(struct mddev *mddev) + mddev->bitmap_ops = NULL; + + sb_id = md_bitmap_get_id_from_sb(mddev); +- if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) ++ if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) { ++ mddev->bitmap_id = orig_id; + return err; ++ } + + pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n", + mdname(mddev), orig_id, sb_id); +@@ -6467,7 +6471,7 @@ static int md_bitmap_create(struct mddev *mddev) + return 0; + } + +-static void md_bitmap_destroy_nosysfs(struct mddev *mddev) ++void md_bitmap_destroy_nosysfs(struct mddev *mddev) + { + if (!md_bitmap_registered(mddev)) + return; +@@ -6485,6 +6489,16 @@ static void md_bitmap_destroy(struct mddev *mddev) + md_bitmap_destroy_nosysfs(mddev); + } + ++static void md_bitmap_set_none(struct mddev *mddev) ++{ ++ mddev->bitmap_id = ID_BITMAP_NONE; ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ return; ++ ++ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups) ++ md_bitmap_sysfs_add(mddev); ++} ++ + int md_run(struct mddev *mddev) + { + int err; +@@ -6694,6 +6708,10 @@ int md_run(struct mddev *mddev) + if (mddev->sb_flags) + md_update_sb(mddev, 0); + ++ if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file && ++ !mddev->bitmap_info.offset) ++ md_bitmap_set_none(mddev); ++ + md_new_event(); + return 0; + +@@ -7638,7 +7656,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd) + { + int err = 0; + +- if (!md_bitmap_registered(mddev)) ++ if (!md_bitmap_registered(mddev) || ++ mddev->bitmap_id == ID_BITMAP_NONE) + return -EINVAL; + + if (mddev->pers) { +@@ -7703,10 +7722,12 @@ static int set_bitmap_file(struct mddev *mddev, int fd) + + if (err) { + md_bitmap_destroy(mddev); ++ md_bitmap_set_none(mddev); + fd = -1; + } + } else if (fd < 0) { + md_bitmap_destroy(mddev); ++ md_bitmap_set_none(mddev); + } + } + +@@ -8013,12 +8034,16 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) + mddev->bitmap_info.default_offset; + mddev->bitmap_info.space = + mddev->bitmap_info.default_space; ++ mddev->bitmap_id = ID_BITMAP; + rv = md_bitmap_create(mddev); + if (!rv) + rv = mddev->bitmap_ops->load(mddev); + +- if (rv) ++ if (rv) { + md_bitmap_destroy(mddev); ++ mddev->bitmap_info.offset = 0; ++ md_bitmap_set_none(mddev); ++ } + } else { + struct md_bitmap_stats stats; + +@@ -8046,6 +8071,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) + } + md_bitmap_destroy(mddev); + mddev->bitmap_info.offset = 0; ++ md_bitmap_set_none(mddev); + } + } + md_update_sb(mddev, 1); +diff --git a/drivers/md/md.h b/drivers/md/md.h +index 9d66afb8cc6e6..da312d4692858 100644 +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -932,6 +932,9 @@ extern void md_allow_write(struct mddev *mddev); + extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev); + extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors); + extern int md_check_no_bitmap(struct mddev *mddev); ++bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev); ++int md_bitmap_create_nosysfs(struct mddev *mddev); ++void md_bitmap_destroy_nosysfs(struct mddev *mddev); + extern int md_integrity_register(struct mddev *mddev); + extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); + +-- +2.53.0 + diff --git a/queue-6.18/md-md-bitmap-split-bitmap-sysfs-groups.patch b/queue-6.18/md-md-bitmap-split-bitmap-sysfs-groups.patch new file mode 100644 index 0000000000..c76ac1dcd9 --- /dev/null +++ b/queue-6.18/md-md-bitmap-split-bitmap-sysfs-groups.patch @@ -0,0 +1,187 @@ +From cc5848ccd61990140ef20b3ae24cacd2a6614598 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:46:14 +0800 +Subject: md/md-bitmap: split bitmap sysfs groups + +From: Yu Kuai + +[ Upstream commit aba3d6d6cb55c6e1116d1215140559dd7ecdf9a9 ] + +Split the classic bitmap sysfs files into a common bitmap group with +the location attribute and a separate internal bitmap group for the +remaining files. + +At the same time, convert bitmap operations from a single sysfs group +to a sysfs group array so backends can share part of their sysfs +layout while adding backend-specific attributes separately. + +Switch the bitmap sysfs helpers to use sysfs_update_groups() for the +add and update path, and remove groups in reverse order so shared named +groups are unmerged before the last group removes the directory. + +Also make bitmap operation lookup depend only on the currently selected +bitmap id matching the installed backend. This prepares the lookup path +for a later registered none backend. + +Reviewed-by: Su Yue +Link: https://lore.kernel.org/r/20260425024615.1696892-3-yukuai@fnnas.com +Signed-off-by: Yu Kuai +Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow") +Signed-off-by: Sasha Levin +--- + drivers/md/md-bitmap.c | 23 +++++++++++++++++++---- + drivers/md/md-bitmap.h | 2 +- + drivers/md/md-llbitmap.c | 7 ++++++- + drivers/md/md.c | 21 ++++++++++++++------- + 4 files changed, 40 insertions(+), 13 deletions(-) + +diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c +index 7bb56d0491a2f..7a96600949139 100644 +--- a/drivers/md/md-bitmap.c ++++ b/drivers/md/md-bitmap.c +@@ -2956,8 +2956,12 @@ static struct md_sysfs_entry max_backlog_used = + __ATTR(max_backlog_used, S_IRUGO | S_IWUSR, + behind_writes_used_show, behind_writes_used_reset); + +-static struct attribute *md_bitmap_attrs[] = { ++static struct attribute *md_bitmap_common_attrs[] = { + &bitmap_location.attr, ++ NULL ++}; ++ ++static struct attribute *md_bitmap_internal_attrs[] = { + &bitmap_space.attr, + &bitmap_timeout.attr, + &bitmap_backlog.attr, +@@ -2968,9 +2972,20 @@ static struct attribute *md_bitmap_attrs[] = { + NULL + }; + +-static struct attribute_group md_bitmap_group = { ++static struct attribute_group md_bitmap_common_group = { ++ .name = "bitmap", ++ .attrs = md_bitmap_common_attrs, ++}; ++ ++static struct attribute_group md_bitmap_internal_group = { + .name = "bitmap", +- .attrs = md_bitmap_attrs, ++ .attrs = md_bitmap_internal_attrs, ++}; ++ ++static const struct attribute_group *bitmap_groups[] = { ++ &md_bitmap_common_group, ++ &md_bitmap_internal_group, ++ NULL, + }; + + static struct bitmap_operations bitmap_ops = { +@@ -3014,7 +3029,7 @@ static struct bitmap_operations bitmap_ops = { + .set_pages = bitmap_set_pages, + .free = md_bitmap_free, + +- .group = &md_bitmap_group, ++ .groups = bitmap_groups, + }; + + int md_bitmap_init(void) +diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h +index b42a28fa83a0f..214f623c7e790 100644 +--- a/drivers/md/md-bitmap.h ++++ b/drivers/md/md-bitmap.h +@@ -125,7 +125,7 @@ struct bitmap_operations { + void (*set_pages)(void *data, unsigned long pages); + void (*free)(void *data); + +- struct attribute_group *group; ++ const struct attribute_group **groups; + }; + + /* the bitmap API */ +diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c +index 0526e742062ac..50eeddf7f539b 100644 +--- a/drivers/md/md-llbitmap.c ++++ b/drivers/md/md-llbitmap.c +@@ -1562,6 +1562,11 @@ static struct attribute_group md_llbitmap_group = { + .attrs = md_llbitmap_attrs, + }; + ++static const struct attribute_group *md_llbitmap_groups[] = { ++ &md_llbitmap_group, ++ NULL, ++}; ++ + static struct bitmap_operations llbitmap_ops = { + .head = { + .type = MD_BITMAP, +@@ -1598,7 +1603,7 @@ static struct bitmap_operations llbitmap_ops = { + .dirty_bits = llbitmap_dirty_bits, + .write_all = llbitmap_write_all, + +- .group = &md_llbitmap_group, ++ .groups = md_llbitmap_groups, + }; + + int md_llbitmap_init(void) +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 3061370e959b3..213221abc44c3 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -688,7 +688,7 @@ static void no_op(struct percpu_ref *r) {} + + static void md_bitmap_sysfs_add(struct mddev *mddev) + { +- if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group)) ++ if (sysfs_update_groups(&mddev->kobj, mddev->bitmap_ops->groups)) + pr_warn("md: cannot register extra bitmap attributes for %s\n", + mdname(mddev)); + else +@@ -701,16 +701,23 @@ static void md_bitmap_sysfs_add(struct mddev *mddev) + + static void md_bitmap_sysfs_del(struct mddev *mddev) + { +- sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group); ++ int nr_groups = 0; ++ ++ for (nr_groups = 0; mddev->bitmap_ops->groups[nr_groups]; nr_groups++) ++ ; ++ ++ while (--nr_groups >= 1) ++ sysfs_unmerge_group(&mddev->kobj, ++ mddev->bitmap_ops->groups[nr_groups]); ++ sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]); + } + + static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) + { +- struct bitmap_operations *old = mddev->bitmap_ops; + struct md_submodule_head *head; + +- if (mddev->bitmap_id == ID_BITMAP_NONE || +- (old && old->head.id == mddev->bitmap_id)) ++ if (mddev->bitmap_ops && ++ mddev->bitmap_ops->head.id == mddev->bitmap_id) + return true; + + xa_lock(&md_submodule); +@@ -6454,7 +6461,7 @@ static int md_bitmap_create(struct mddev *mddev) + if (err) + return err; + +- if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) ++ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups) + md_bitmap_sysfs_add(mddev); + + return 0; +@@ -6472,7 +6479,7 @@ static void md_bitmap_destroy_nosysfs(struct mddev *mddev) + static void md_bitmap_destroy(struct mddev *mddev) + { + if (!mddev_is_dm(mddev) && mddev->bitmap_ops && +- mddev->bitmap_ops->group) ++ mddev->bitmap_ops->groups) + md_bitmap_sysfs_del(mddev); + + md_bitmap_destroy_nosysfs(mddev); +-- +2.53.0 + diff --git a/queue-6.18/md-raid1-fix-the-comparing-region-of-interval-tree.patch b/queue-6.18/md-raid1-fix-the-comparing-region-of-interval-tree.patch new file mode 100644 index 0000000000..c262a3c7a1 --- /dev/null +++ b/queue-6.18/md-raid1-fix-the-comparing-region-of-interval-tree.patch @@ -0,0 +1,51 @@ +From d339fac1c489bca3b0dff82dbcf3f7c6aaa58357 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 09:18:33 +0800 +Subject: md/raid1: fix the comparing region of interval tree + +From: Xiao Ni + +[ Upstream commit de3544d2e5ea99064498de3c21ba490155864657 ] + +Interval tree uses [start, end] as a region which stores in the tree. +In raid1, it uses the wrong end value. For example: +bio(A,B) is too big and needs to be split to bio1(A,C-1), bio2(C,B). +The region of bio1 is [A,C] and the region of bio2 is [C,B]. So bio1 and +bio2 overlap which is not right. + +Fix this problem by using right end value of the region. + +Fixes: d0d2d8ba0494 ("md/raid1: introduce wait_for_serialization") +Signed-off-by: Xiao Ni +Link: https://lore.kernel.org/linux-raid/20260305011839.5118-2-xni@redhat.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid1.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index ce7fd68869566..84dbf801e9b1b 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -62,7 +62,7 @@ static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio, + unsigned long flags; + int ret = 0; + sector_t lo = r1_bio->sector; +- sector_t hi = lo + r1_bio->sectors; ++ sector_t hi = lo + r1_bio->sectors - 1; + struct serial_in_rdev *serial = &rdev->serial[idx]; + + spin_lock_irqsave(&serial->serial_lock, flags); +@@ -453,7 +453,7 @@ static void raid1_end_write_request(struct bio *bio) + int mirror = find_bio_disk(r1_bio, bio); + struct md_rdev *rdev = conf->mirrors[mirror].rdev; + sector_t lo = r1_bio->sector; +- sector_t hi = r1_bio->sector + r1_bio->sectors; ++ sector_t hi = r1_bio->sector + r1_bio->sectors - 1; + bool ignore_error = !raid1_should_handle_error(bio) || + (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD); + +-- +2.53.0 + diff --git a/queue-6.18/md-raid1-raid10-don-t-fail-devices-for-invalid-io-er.patch b/queue-6.18/md-raid1-raid10-don-t-fail-devices-for-invalid-io-er.patch new file mode 100644 index 0000000000..9d3ec9bf8c --- /dev/null +++ b/queue-6.18/md-raid1-raid10-don-t-fail-devices-for-invalid-io-er.patch @@ -0,0 +1,64 @@ +From a97c788968afb48a2abd4d4ec7bf82b0db562949 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 07:03:45 -0700 +Subject: md/raid1,raid10: don't fail devices for invalid IO errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Keith Busch + +[ Upstream commit f7b24c7b41f23b5f9caa8b913afe79cd4c397d39 ] + +BLK_STS_INVAL indicates the IO request itself was invalid, not that the +device has failed. When raid1 treats this as a device error, it retries +on alternate mirrors which fail the same way, eventually exceeding the +read error threshold and removing the device from the array. + +This happens when stacking configurations bypass bio_split_to_limits() +in the IO path: dm-raid calls md_handle_request() directly without going +through md_submit_bio(), skipping the alignment validation that would +otherwise reject invalid bios early. The invalid bio reaches the +lower block layers, which fail the bio with BLK_STS_INVAL, and raid1 +wrongly interprets this as a device failure. + +Add BLK_STS_INVAL to raid1_should_handle_error() so that invalid IO +errors are propagated back to the caller rather than triggering device +removal. This is consistent with the previous kernel behavior when +alignment checks were done earlier in the direct-io path. + +Fixes: 5ff3f74e145adc7 ("block: simplify direct io validity check") + +Reported-by: Tomáš Trnka +Closes: https://lore.kernel.org/linux-block/2982107.4sosBPzcNG@electra/ +Signed-off-by: Keith Busch +Tested-by: Tomáš Trnka +Link: https://lore.kernel.org/r/20260416140345.3872265-1-kbusch@meta.com +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid1-10.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c +index 521625756128a..aba8c751e1922 100644 +--- a/drivers/md/raid1-10.c ++++ b/drivers/md/raid1-10.c +@@ -298,8 +298,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev, + * bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is + * submitted to the underlying disks, hence don't record badblocks or retry + * in this case. ++ * ++ * BLK_STS_INVAL means the bio was not valid for the underlying device. This ++ * is a user error, not a device failure, so retrying or recording bad blocks ++ * would be wrong. + */ + static inline bool raid1_should_handle_error(struct bio *bio) + { +- return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)); ++ return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)) && ++ bio->bi_status != BLK_STS_INVAL; + } +-- +2.53.0 + diff --git a/queue-6.18/md-remove-unused-static-md_wq-workqueue.patch b/queue-6.18/md-remove-unused-static-md_wq-workqueue.patch new file mode 100644 index 0000000000..aa5995ed1d --- /dev/null +++ b/queue-6.18/md-remove-unused-static-md_wq-workqueue.patch @@ -0,0 +1,67 @@ +From c6adc0601991c1cffaf6c69d2ebeb87195761bc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 22:35:22 +0300 +Subject: md: remove unused static md_wq workqueue + +From: Abd-Alrhman Masalkhi + +[ Upstream commit e4979f4fac4d6bbe757be50441b45e28e6bf7360 ] + +The md_wq workqueue is defined as static and initialized in md_init(), +but it is not used anywhere within md.c. + +All asynchronous and deferred work in this file is handled via +md_misc_wq or dedicated md threads. + +Fixes: b75197e86e6d3 ("md: Remove flush handling") +Signed-off-by: Abd-Alrhman Masalkhi +Link: https://lore.kernel.org/linux-raid/20260328193522.3624-1-abd.masalkhi@gmail.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 0fc779493fa78..0a3152f21d488 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -84,7 +84,6 @@ static DEFINE_XARRAY(md_submodule); + static const struct kobj_type md_ktype; + + static DECLARE_WAIT_QUEUE_HEAD(resync_wait); +-static struct workqueue_struct *md_wq; + + /* + * This workqueue is used for sync_work to register new sync_thread, and for +@@ -10345,10 +10344,6 @@ static int __init md_init(void) + goto err_bitmap; + + ret = -ENOMEM; +- md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM | WQ_PERCPU, 0); +- if (!md_wq) +- goto err_wq; +- + md_misc_wq = alloc_workqueue("md_misc", WQ_PERCPU, 0); + if (!md_misc_wq) + goto err_misc_wq; +@@ -10373,8 +10368,6 @@ static int __init md_init(void) + err_md: + destroy_workqueue(md_misc_wq); + err_misc_wq: +- destroy_workqueue(md_wq); +-err_wq: + md_llbitmap_exit(); + err_bitmap: + md_bitmap_exit(); +@@ -10683,7 +10676,6 @@ static __exit void md_exit(void) + spin_unlock(&all_mddevs_lock); + + destroy_workqueue(md_misc_wq); +- destroy_workqueue(md_wq); + md_bitmap_exit(); + } + +-- +2.53.0 + diff --git a/queue-6.18/md-wake-raid456-reshape-waiters-before-suspend.patch b/queue-6.18/md-wake-raid456-reshape-waiters-before-suspend.patch new file mode 100644 index 0000000000..3f4dabbdae --- /dev/null +++ b/queue-6.18/md-wake-raid456-reshape-waiters-before-suspend.patch @@ -0,0 +1,59 @@ +From 4339d0773de2ea60d971bd8ec4fe69ce5e650609 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 22:07:29 +0800 +Subject: md: wake raid456 reshape waiters before suspend + +From: Yu Kuai + +[ Upstream commit cf86bb53b9c92354904a328e947a05ffbfdd1840 ] + +During raid456 reshape, direct IO across the reshape position can sleep +in raid5_make_request() waiting for reshape progress while still +holding an active_io reference. If userspace then freezes reshape and +writes md/suspend_lo or md/suspend_hi, mddev_suspend() kills active_io +and waits for all in-flight IO to drain. + +This can deadlock: the IO needs reshape progress to continue, but the +reshape thread is already frozen, so the active_io reference is never +dropped and suspend never completes. + +raid5_prepare_suspend() already wakes wait_for_reshape for dm-raid. Do +the same for normal md suspend when reshape is already interrupted, so +waiting raid456 IO can abort, drop its reference, and let suspend +finish. + +The mdadm test tests/25raid456-reshape-deadlock reproduces the hang. + +Fixes: 714d20150ed8 ("md: add new helpers to suspend/resume array") +Link: https://lore.kernel.org/linux-raid/20260327140729.2030564-1-yukuai@fnnas.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 0a3152f21d488..b91ac1b7d7a15 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -486,6 +486,17 @@ int mddev_suspend(struct mddev *mddev, bool interruptible) + } + + percpu_ref_kill(&mddev->active_io); ++ ++ /* ++ * RAID456 IO can sleep in wait_for_reshape while still holding an ++ * active_io reference. If reshape is already interrupted or frozen, ++ * wake those waiters so they can abort and drop the reference instead ++ * of deadlocking suspend. ++ */ ++ if (mddev->pers && mddev->pers->prepare_suspend && ++ reshape_interrupted(mddev)) ++ mddev->pers->prepare_suspend(mddev); ++ + if (interruptible) + err = wait_event_interruptible(mddev->sb_wait, + percpu_ref_is_zero(&mddev->active_io)); +-- +2.53.0 + diff --git a/queue-6.18/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch b/queue-6.18/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch new file mode 100644 index 0000000000..72472467cc --- /dev/null +++ b/queue-6.18/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch @@ -0,0 +1,72 @@ +From 9b89ebad2da22608455027c027704397e7936341 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 15:37:34 +0200 +Subject: media: i2c: og01a1b: Fix V4L2 subdevice data initialization on probe + +From: Vladimir Zapolskiy + +[ Upstream commit 535b7f106991c7d8f0e5b8e1769bfb8b1ce9d3d6 ] + +It's necessary to finalize the camera sensor subdevice initialization on +driver probe and clean V4L2 subdevice data up on error paths and driver +removal. + +The change fixes a previously reported by v4l2-compliance issue of +the failed VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT test: + + fail: v4l2-test-controls.cpp(1104): subscribe event for control 'User Controls' failed + +Fixes: 472377febf84 ("media: Add a driver for the og01a1b camera sensor") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/og01a1b.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c +index c7184de6251ae..7b892b26203c0 100644 +--- a/drivers/media/i2c/og01a1b.c ++++ b/drivers/media/i2c/og01a1b.c +@@ -1042,6 +1042,7 @@ static void og01a1b_remove(struct i2c_client *client) + struct og01a1b *og01a1b = to_og01a1b(sd); + + v4l2_async_unregister_subdev(sd); ++ v4l2_subdev_cleanup(&og01a1b->sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(og01a1b->dev); +@@ -1153,11 +1154,18 @@ static int og01a1b_probe(struct i2c_client *client) + goto probe_error_v4l2_ctrl_handler_free; + } + ++ ret = v4l2_subdev_init_finalize(&og01a1b->sd); ++ if (ret < 0) { ++ dev_err_probe(og01a1b->dev, ret, ++ "failed to finalize subdevice init\n"); ++ goto probe_error_media_entity_cleanup; ++ } ++ + ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); + if (ret < 0) { + dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d", + ret); +- goto probe_error_media_entity_cleanup; ++ goto probe_error_v4l2_subdev_cleanup; + } + + /* Enable runtime PM and turn off the device */ +@@ -1167,6 +1175,9 @@ static int og01a1b_probe(struct i2c_client *client) + + return 0; + ++probe_error_v4l2_subdev_cleanup: ++ v4l2_subdev_cleanup(&og01a1b->sd); ++ + probe_error_media_entity_cleanup: + media_entity_cleanup(&og01a1b->sd.entity); + +-- +2.53.0 + diff --git a/queue-6.18/memblock-reserve_mem-fix-end-caclulation-in-reserve_.patch b/queue-6.18/memblock-reserve_mem-fix-end-caclulation-in-reserve_.patch new file mode 100644 index 0000000000..5830531a2a --- /dev/null +++ b/queue-6.18/memblock-reserve_mem-fix-end-caclulation-in-reserve_.patch @@ -0,0 +1,40 @@ +From 00e78028217c07bb6ea1fb1c3b9c7e343aa67c82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 09:48:28 +0200 +Subject: memblock: reserve_mem: fix end caclulation in + reserve_mem_release_by_name() + +From: Mike Rapoport (Microsoft) + +[ Upstream commit c12c3e1507809ad1fc0448f51c933f52e17d13cd ] + +free_reserved_area() expects end parameter to point to the first address +after the area, but reserve_mem_release_by_name() passes it the last +address inside the area. + +Remove subtraction of one in calculation of the area end. + +Fixes: 74e2498ccf7b ("mm/memblock: Add reserved memory release function") +Link: https://patch.msgid.link/20260323074836.3653702-2-rppt@kernel.org +Signed-off-by: Mike Rapoport (Microsoft) +Signed-off-by: Sasha Levin +--- + mm/memblock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mm/memblock.c b/mm/memblock.c +index f0f2dc66e9a20..757258d68425a 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -2433,7 +2433,7 @@ int reserve_mem_release_by_name(const char *name) + return 0; + + start = phys_to_virt(map->start); +- end = start + map->size - 1; ++ end = start + map->size; + snprintf(buf, sizeof(buf), "reserve_mem:%s", name); + free_reserved_area(start, end, 0, buf); + map->size = 0; +-- +2.53.0 + diff --git a/queue-6.18/memory-tegra124-emc-fix-dll_change-check.patch b/queue-6.18/memory-tegra124-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..51b5e66b5a --- /dev/null +++ b/queue-6.18/memory-tegra124-emc-fix-dll_change-check.patch @@ -0,0 +1,38 @@ +From 8b6b7823d0a6b33c0e7da84a38b453542317dbb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:42 +0900 +Subject: memory: tegra124-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 9597ab9a8296ab337e6820f8a717ff621078b632 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: 73a7f0a90641 ("memory: tegra: Add EMC (external memory controller) driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-1-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra124-emc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c +index 03f1daa2d132a..71d20b5916d89 100644 +--- a/drivers/memory/tegra/tegra124-emc.c ++++ b/drivers/memory/tegra/tegra124-emc.c +@@ -608,7 +608,7 @@ static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, + + if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; +-- +2.53.0 + diff --git a/queue-6.18/memory-tegra30-emc-fix-dll_change-check.patch b/queue-6.18/memory-tegra30-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..5343123a25 --- /dev/null +++ b/queue-6.18/memory-tegra30-emc-fix-dll_change-check.patch @@ -0,0 +1,47 @@ +From 3dd5912738bdb27749693797cf65f4831a9c8ab9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:43 +0900 +Subject: memory: tegra30-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 0a93f2355cf4922ad2399dbef5ea1049fef116d4 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: e34212c75a68 ("memory: tegra: Introduce Tegra30 EMC driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-2-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra30-emc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c +index 921dce1b8bc63..4981b7fa0f780 100644 +--- a/drivers/memory/tegra/tegra30-emc.c ++++ b/drivers/memory/tegra/tegra30-emc.c +@@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) + emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG); + emc_dbg = readl_relaxed(emc->regs + EMC_DBG); + +- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1)) ++ if (emc->dll_on == !(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; + +- emc->dll_on = !!(timing->emc_mode_1 & 0x1); ++ emc->dll_on = !(timing->emc_mode_1 & 0x1); + + if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL)) + emc->zcal_long = true; +-- +2.53.0 + diff --git a/queue-6.18/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch b/queue-6.18/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch new file mode 100644 index 0000000000..53c6f01509 --- /dev/null +++ b/queue-6.18/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch @@ -0,0 +1,37 @@ +From 72ac4459b2a7d1868c5e2cd928b793bc1053ee49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:56:20 +0530 +Subject: mfd: mc13xxx-core: Fix memory leak in mc13xxx_add_subdevice_pdata() + +From: Abdun Nihaal + +[ Upstream commit a5a65a7fb2f7796bbe492cd6be59c92cb64377d1 ] + +The memory allocated for cell.name using kmemdup() is not freed when +mfd_add_devices() fails. Fix that by using devm_kmemdup(). + +Fixes: 8e00593557c3 ("mfd: Add mc13892 support to mc13xxx") +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20260120102622.66921-1-nihaal@cse.iitm.ac.in +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mc13xxx-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c +index 920797b806ced..786eab3b2d03c 100644 +--- a/drivers/mfd/mc13xxx-core.c ++++ b/drivers/mfd/mc13xxx-core.c +@@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return -E2BIG; + +- cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); ++ cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL); + if (!cell.name) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.18/module-fix-freeing-of-charp-module-parameters-when-c.patch b/queue-6.18/module-fix-freeing-of-charp-module-parameters-when-c.patch new file mode 100644 index 0000000000..05dca9b125 --- /dev/null +++ b/queue-6.18/module-fix-freeing-of-charp-module-parameters-when-c.patch @@ -0,0 +1,122 @@ +From 1a79cd7b342a24474c34a51e7718177fa524b79d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:48:02 +0100 +Subject: module: Fix freeing of charp module parameters when CONFIG_SYSFS=n + +From: Petr Pavlu + +[ Upstream commit deffe1edba626d474fef38007c03646ca5876a0e ] + +When setting a charp module parameter, the param_set_charp() function +allocates memory to store a copy of the input value. Later, when the module +is potentially unloaded, the destroy_params() function is called to free +this allocated memory. + +However, destroy_params() is available only when CONFIG_SYSFS=y, otherwise +only a dummy variant is present. In the unlikely case that the kernel is +configured with CONFIG_MODULES=y and CONFIG_SYSFS=n, this results in +a memory leak of charp values when a module is unloaded. + +Fix this issue by making destroy_params() always available when +CONFIG_MODULES=y. Rename the function to module_destroy_params() to clarify +that it is intended for use by the module loader. + +Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs") +Signed-off-by: Petr Pavlu +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + include/linux/moduleparam.h | 11 +++-------- + kernel/module/main.c | 4 ++-- + kernel/params.c | 27 ++++++++++++++++++--------- + 3 files changed, 23 insertions(+), 19 deletions(-) + +diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h +index 6907aedc4f748..77775fd821407 100644 +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -414,14 +414,9 @@ extern char *parse_args(const char *name, + void *arg, parse_unknown_fn unknown); + + /* Called by module remove. */ +-#ifdef CONFIG_SYSFS +-extern void destroy_params(const struct kernel_param *params, unsigned num); +-#else +-static inline void destroy_params(const struct kernel_param *params, +- unsigned num) +-{ +-} +-#endif /* !CONFIG_SYSFS */ ++#ifdef CONFIG_MODULES ++void module_destroy_params(const struct kernel_param *params, unsigned int num); ++#endif + + /* All the helper functions */ + /* The macros to do compile-time type checking stolen from Jakub +diff --git a/kernel/module/main.c b/kernel/module/main.c +index 66d4efbddfffe..3745cd02c8479 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -1408,7 +1408,7 @@ static void free_module(struct module *mod) + module_unload_free(mod); + + /* Free any allocated parameters. */ +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + + if (is_livepatch_module(mod)) + free_module_elf(mod); +@@ -3519,7 +3519,7 @@ static int load_module(struct load_info *info, const char __user *uargs, + mod_sysfs_teardown(mod); + coming_cleanup: + mod->state = MODULE_STATE_GOING; +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_GOING, mod); + klp_module_going(mod); +diff --git a/kernel/params.c b/kernel/params.c +index 7c2242f64bf08..8942884e21c43 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -746,15 +746,6 @@ void module_param_sysfs_remove(struct module *mod) + } + #endif + +-void destroy_params(const struct kernel_param *params, unsigned num) +-{ +- unsigned int i; +- +- for (i = 0; i < num; i++) +- if (params[i].ops->free) +- params[i].ops->free(params[i].arg); +-} +- + struct module_kobject * __init_or_module + lookup_or_create_module_kobject(const char *name) + { +@@ -986,3 +977,21 @@ static int __init param_sysfs_builtin_init(void) + late_initcall(param_sysfs_builtin_init); + + #endif /* CONFIG_SYSFS */ ++ ++#ifdef CONFIG_MODULES ++ ++/* ++ * module_destroy_params - free all parameters for one module ++ * @params: module parameters (array) ++ * @num: number of module parameters ++ */ ++void module_destroy_params(const struct kernel_param *params, unsigned int num) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < num; i++) ++ if (params[i].ops->free) ++ params[i].ops->free(params[i].arg); ++} ++ ++#endif /* CONFIG_MODULES */ +-- +2.53.0 + diff --git a/queue-6.18/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch b/queue-6.18/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch new file mode 100644 index 0000000000..99f45cce09 --- /dev/null +++ b/queue-6.18/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch @@ -0,0 +1,59 @@ +From 9a20faf5c870b36362b3fe130787372a015215c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:57 +0200 +Subject: mtd: parsers: ofpart: call of_node_get() for dedicated subpartitions + +From: Cosmin Tanislav + +[ Upstream commit e882626c1747653f1f01ea9d12e278e613b11d0f ] + +In order to parse sub-partitions, add_mtd_partitions() calls +parse_mtd_partitions() for all previously found partitions. + +Each partition will end up being passed to parse_fixed_partitions(), and +its of_node will be treated as the ofpart_node. + +Commit 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in +parse_fixed_partitions()") added of_node_put() calls for ofpart_node on +all exit paths. + +In the case where the partition passed to parse_fixed_partitions() has a +parent, it is treated as a dedicated partitions node, and of_node_put() +is wrongly called for it, even if of_node_get() was not called +explicitly. + +On repeated bind / unbinds of the MTD, the extra of_node_put() ends up +decrementing the refcount down to 0, which should never happen, +resulting in the following error: + +OF: ERROR: of_node_release() detected bad of_node_put() on +/soc/spi@80007000/flash@0/partitions/partition@0 + +Call of_node_get() to balance the call to of_node_put() done for +dedicated partitions nodes. + +Fixes: 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in parse_fixed_partitions()") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index a5ba78c6723ee..321002a1d0cae 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -71,7 +71,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + dedicated = false; + } + } else { /* Partition */ +- ofpart_node = mtd_node; ++ ofpart_node = of_node_get(mtd_node); + } + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); +-- +2.53.0 + diff --git a/queue-6.18/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch b/queue-6.18/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch new file mode 100644 index 0000000000..b37cdbf718 --- /dev/null +++ b/queue-6.18/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch @@ -0,0 +1,48 @@ +From f81fb7fc60231182fbaa08e4128ecf58c929d0c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:56 +0200 +Subject: mtd: parsers: ofpart: call of_node_put() only in ofpart_fail path + +From: Cosmin Tanislav + +[ Upstream commit 0c87dea1aab86116211cb37387c404c9e9231c39 ] + +ofpart_none can only be reached after the for_each_child_of_node() loop +finishes. for_each_child_of_node() correctly calls of_node_put() for all +device nodes it iterates over as long as we don't break or jump out of +the loop. + +Calling of_node_put() inside the ofpart_none path will wrongly decrement +the ref count of the last node in the for_each_child_of_node() loop. + +Move the call to of_node_put() under the ofpart_fail label to fix this. + +Fixes: ebd5a74db74e ("mtd: ofpart: Check availability of reg property instead of name property") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 09961c6f39496..a5ba78c6723ee 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -191,11 +191,11 @@ static int parse_fixed_partitions(struct mtd_info *master, + ofpart_fail: + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", + master->name, pp, mtd_node); ++ of_node_put(pp); + ret = -EINVAL; + ofpart_none: + if (dedicated) + of_node_put(ofpart_node); +- of_node_put(pp); + kfree(parts); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.18/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch b/queue-6.18/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch new file mode 100644 index 0000000000..138080f7b5 --- /dev/null +++ b/queue-6.18/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch @@ -0,0 +1,41 @@ +From 6fd5d03b8885c17159774f4be44fcdd3c8fe69a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:43:36 +0800 +Subject: mtd: physmap_of_gemini: Fix disabled pinctrl state check + +From: Chen Ni + +[ Upstream commit b7c0982184b0661f5b1b805f3a56f1bd3757b63e ] + +The condition for checking the disabled pinctrl state incorrectly checks +gf->enabled_state instead of gf->disabled_state. This causes misleading +error messages and could lead to incorrect behavior when only one of the +pinctrl states is defined. + +Fix the condition to properly check gf->disabled_state. + +Fixes: 9d3b5086f6d4 ("mtd: physmap_of_gemini: Handle pin control") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/maps/physmap-gemini.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c +index 9d3b4bf84a1ad..1c34b4ef77ea3 100644 +--- a/drivers/mtd/maps/physmap-gemini.c ++++ b/drivers/mtd/maps/physmap-gemini.c +@@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev, + dev_err(dev, "no enabled pin control state\n"); + + gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled"); +- if (IS_ERR(gf->enabled_state)) { ++ if (IS_ERR(gf->disabled_state)) { + dev_err(dev, "no disabled pin control state\n"); + } else { + ret = pinctrl_select_state(gf->p, gf->disabled_state); +-- +2.53.0 + diff --git a/queue-6.18/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch b/queue-6.18/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch new file mode 100644 index 0000000000..95e3e02784 --- /dev/null +++ b/queue-6.18/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch @@ -0,0 +1,66 @@ +From 54ecf835722fc2b7f38667c5a26595ee0de625a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:24:30 +0100 +Subject: mtd: rawnand: sunxi: fix sunxi_nfc_hw_ecc_read_extra_oob + +From: Richard Genoud + +[ Upstream commit 848c13996c55fe4ea6bf5acc3ce6c8c5c944b5f6 ] + +When dumping the OOB, the bytes at the end where actually copied from +the beginning of the OOB instead of current_offset. + +That leads to something like: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +instead of: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +(example with BCH16, user data [8,0], no scrambling) + +*cur_off (offset from the beginning of the page) was compared to offset +(offset from the beginning of the OOB), and then, the +nand_change_read_column_op() sets the current position to the beginning +of the OOB instead of OOB+offset + +Fixes: 15d6f118285f ("mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode") +Reviewed-by: Jernej Skrabec +Signed-off-by: Richard Genoud +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/sunxi_nand.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c +index f6a8e8ae819d4..75db1713e6177 100644 +--- a/drivers/mtd/nand/raw/sunxi_nand.c ++++ b/drivers/mtd/nand/raw/sunxi_nand.c +@@ -886,9 +886,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, + if (len <= 0) + return; + +- if (!cur_off || *cur_off != offset) +- nand_change_read_column_op(nand, mtd->writesize, NULL, 0, +- false); ++ if (!cur_off || *cur_off != (offset + mtd->writesize)) ++ nand_change_read_column_op(nand, mtd->writesize + offset, ++ NULL, 0, false); + + if (!randomize) + sunxi_nfc_read_buf(nand, oob + offset, len); +-- +2.53.0 + diff --git a/queue-6.18/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch b/queue-6.18/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch new file mode 100644 index 0000000000..054a03e8b9 --- /dev/null +++ b/queue-6.18/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch @@ -0,0 +1,38 @@ +From f7a80d36412ff2355f325fa1b2f06dece4123126 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 17:14:14 +0800 +Subject: mtd: spi-nor: core: correct the op.dummy.nbytes when check read + operations + +From: Haibo Chen + +[ Upstream commit 756564a536ecd8c9d33edd89f0647a91a0b03587 ] + +When check read operation, need to setting the op.dummy.nbytes based +on current read operation rather than the nor->read_proto. + +Fixes: 0e30f47232ab ("mtd: spi-nor: add support for DTR protocol") +Signed-off-by: Haibo Chen +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 20ea80450f222..19dc13faf9fd9 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -2393,7 +2393,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; +- if (spi_nor_protocol_is_dtr(nor->read_proto)) ++ if (spi_nor_protocol_is_dtr(read->proto)) + op.dummy.nbytes *= 2; + + return spi_nor_spimem_check_op(nor, &op); +-- +2.53.0 + diff --git a/queue-6.18/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch b/queue-6.18/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch new file mode 100644 index 0000000000..df4ad1580b --- /dev/null +++ b/queue-6.18/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch @@ -0,0 +1,88 @@ +From 78b0024618547f2b4540e08b87cd7e6fdd1eed18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 16:47:59 +0900 +Subject: mtd: spi-nor: sfdp: introduce smpt_map_id fixup hook + +From: Takahiro Kuwano + +[ Upstream commit f74de390557bf2bcc5dca4a357b41c0701d3f76e ] + +Certain chips have inconsistent Sector Map Parameter Table (SMPT) data, +which leads to the wrong map ID being identified, causing failures to +detect the correct sector map. + +To fix this, introduce smpt_map_id() into the struct spi_nor_fixups. +This function will be called after the initial SMPT-based detection, +allowing chip-specific logic to correct the map ID. + +Infineon S25FS512S needs this fixup as it has inconsistency between map +ID definition and configuration register value actually obtained. + +Co-developed-by: Marek Vasut +Signed-off-by: Marek Vasut +Reviewed-by: Tudor Ambarus +Tested-by: Marek Vasut # S25FS512S +Signed-off-by: Takahiro Kuwano +Reviewed-by: Tudor Ambarus > +Signed-off-by: Pratyush Yadav +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 3 +++ + drivers/mtd/spi-nor/sfdp.c | 12 ++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 5ad46d95d09cc..16b382d4f04f2 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -411,6 +411,8 @@ struct spi_nor_flash_parameter { + * @post_bfpt: called after the BFPT table has been parsed + * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the + * number of dummy cycles in read register ops. ++ * @smpt_map_id: called after map ID in SMPT table has been determined for the ++ * case the map ID is wrong and needs to be fixed. + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. +@@ -429,6 +431,7 @@ struct spi_nor_fixups { + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); + void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); ++ void (*smpt_map_id)(const struct spi_nor *nor, u8 *map_id); + int (*post_sfdp)(struct spi_nor *nor); + int (*late_init)(struct spi_nor *nor); + }; +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index 9a47dcaca06ae..a8324c2da0acf 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -730,6 +730,16 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) + return read_dummy; + } + ++static void spi_nor_smpt_map_id_fixups(const struct spi_nor *nor, u8 *map_id) ++{ ++ if (nor->manufacturer && nor->manufacturer->fixups && ++ nor->manufacturer->fixups->smpt_map_id) ++ nor->manufacturer->fixups->smpt_map_id(nor, map_id); ++ ++ if (nor->info->fixups && nor->info->fixups->smpt_map_id) ++ nor->info->fixups->smpt_map_id(nor, map_id); ++} ++ + /** + * spi_nor_get_map_in_use() - get the configuration map in use + * @nor: pointer to a 'struct spi_nor' +@@ -783,6 +793,8 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt, + map_id = map_id << 1 | !!(*buf & read_data_mask); + } + ++ spi_nor_smpt_map_id_fixups(nor, &map_id); ++ + /* + * If command descriptors are provided, they always precede map + * descriptors in the table. There is no need to start the iteration +-- +2.53.0 + diff --git a/queue-6.18/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch b/queue-6.18/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch new file mode 100644 index 0000000000..c0099c7900 --- /dev/null +++ b/queue-6.18/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch @@ -0,0 +1,92 @@ +From 18077109df30e5a40f3fad12117ee122d1a6faf4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 16:47:58 +0900 +Subject: mtd: spi-nor: sfdp: introduce smpt_read_dummy fixup hook + +From: Takahiro Kuwano + +[ Upstream commit 653f6def567c81f37302f9591ffd54df3e2a11eb ] + +SMPT contains config detection info that describes opcode, address, and +dummy cycles to read sector map config. The dummy cycles parameter can +be SMPT_CMD_READ_DUMMY_IS_VARIABLE and in that case nor->read_dummy +(initialized as 0) is used. In Infineon flash chips, Read Any Register +command with variable dummy cycle is defined in SMPT. S25Hx/S28Hx flash +has 0 dummy cycle by default to read volatile regiters and +nor->read_dummy can work. S25FS-S flash has 8 dummy cycles so we need a +hook that can fix dummy cycles with actually used value. + +Inroduce smpt_read_dummy() in struct spi_nor_fixups. It is called when +the dummy cycle field in SMPT config detection is 'varialble'. + +Reviewed-by: Tudor Ambarus +Tested-by: Marek Vasut # S25FS512S +Signed-off-by: Takahiro Kuwano +Signed-off-by: Pratyush Yadav +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 3 +++ + drivers/mtd/spi-nor/sfdp.c | 18 ++++++++++++++++-- + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index ceff412f7d65a..5ad46d95d09cc 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -409,6 +409,8 @@ struct spi_nor_flash_parameter { + * flash parameters when information provided by the flash_info + * table is incomplete or wrong. + * @post_bfpt: called after the BFPT table has been parsed ++ * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the ++ * number of dummy cycles in read register ops. + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. +@@ -426,6 +428,7 @@ struct spi_nor_fixups { + int (*post_bfpt)(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); ++ void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); + int (*post_sfdp)(struct spi_nor *nor); + int (*late_init)(struct spi_nor *nor); + }; +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index 21727f9a4ac69..9a47dcaca06ae 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -699,6 +699,17 @@ static u8 spi_nor_smpt_addr_nbytes(const struct spi_nor *nor, const u32 settings + } + } + ++static void spi_nor_smpt_read_dummy_fixups(const struct spi_nor *nor, ++ u8 *read_dummy) ++{ ++ if (nor->manufacturer && nor->manufacturer->fixups && ++ nor->manufacturer->fixups->smpt_read_dummy) ++ nor->manufacturer->fixups->smpt_read_dummy(nor, read_dummy); ++ ++ if (nor->info->fixups && nor->info->fixups->smpt_read_dummy) ++ nor->info->fixups->smpt_read_dummy(nor, read_dummy); ++} ++ + /** + * spi_nor_smpt_read_dummy() - return the configuration detection command read + * latency, in clock cycles. +@@ -711,8 +722,11 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) + { + u8 read_dummy = SMPT_CMD_READ_DUMMY(settings); + +- if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) +- return nor->read_dummy; ++ if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) { ++ read_dummy = nor->read_dummy; ++ spi_nor_smpt_read_dummy_fixups(nor, &read_dummy); ++ } ++ + return read_dummy; + } + +-- +2.53.0 + diff --git a/queue-6.18/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch b/queue-6.18/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch new file mode 100644 index 0000000000..59cc35c912 --- /dev/null +++ b/queue-6.18/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch @@ -0,0 +1,41 @@ +From 8c71b77f74620b1711f6be7cc5d8cdaa4cff753f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 20:42:56 +0800 +Subject: mtd: spi-nor: swp: check SR_TB flag when getting tb_mask + +From: Shiji Yang + +[ Upstream commit 94645aa41bf9ecb87c2ce78b1c3405bfb6074a37 ] + +When the chip does not support top/bottom block protect, the tb_mask +must be set to 0, otherwise SR1 bit5 will be unexpectedly modified. + +Signed-off-by: Shiji Yang +Fixes: 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support") +Reviewed-by: Michael Walle +Reviewed-by: Miquel Raynal +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/swp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c +index 9b07f83aeac76..e67a81dbb6bf6 100644 +--- a/drivers/mtd/spi-nor/swp.c ++++ b/drivers/mtd/spi-nor/swp.c +@@ -28,8 +28,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) + { + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + return SR_TB_BIT6; +- else ++ else if (nor->flags & SNOR_F_HAS_SR_TB) + return SR_TB_BIT5; ++ else ++ return 0; + } + + static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) +-- +2.53.0 + diff --git a/queue-6.18/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch b/queue-6.18/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch new file mode 100644 index 0000000000..5539cd0724 --- /dev/null +++ b/queue-6.18/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch @@ -0,0 +1,40 @@ +From 27633c7469ce5bf24e141b7fccacc3225fa4ddd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:54:30 +0100 +Subject: mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation + +From: Jonas Gorski + +[ Upstream commit 3620d67b48493c6252bbc873dc88dde81641d56b ] + +After commit 5273cc6df984 ("mtd: spi-nor: core: Call +spi_nor_post_sfdp_fixups() only when SFDP is defined") +spi_nor_post_sfdp_fixups() isn't called anymore if no SFDP is detected. + +Update the documentation accordingly. + +Fixes: 5273cc6df984 ("mtd: spi-nor: core: Call spi_nor_post_sfdp_fixups() only when SFDP is defined") +Signed-off-by: Jonas Gorski +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 16b382d4f04f2..e838c40a25897 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -413,7 +413,7 @@ struct spi_nor_flash_parameter { + * number of dummy cycles in read register ops. + * @smpt_map_id: called after map ID in SMPT table has been determined for the + * case the map ID is wrong and needs to be fixed. +- * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs ++ * @post_sfdp: called after SFDP has been parsed (is not called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. + * when information provided by the SFDP/flash_info tables are +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-add-missing-check.patch b/queue-6.18/mtd-spinand-add-missing-check.patch new file mode 100644 index 0000000000..2d7f0f90f8 --- /dev/null +++ b/queue-6.18/mtd-spinand-add-missing-check.patch @@ -0,0 +1,38 @@ +From 1acae605fdc4bbc41fefb829321fbf22914da1a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:03 +0100 +Subject: mtd: spinand: Add missing check + +From: Miquel Raynal + +[ Upstream commit aab8a4c656379a6a1a4ca716f48118680560eaab ] + +The update cache variant is mandatory, both read and write versions are +being checked, but not this one. All chip drivers seem to implement this +variant, so there should be no breakage. + +Reviewed-by: Tudor Ambarus +Signed-off-by: Miquel Raynal +Stable-dep-of: 25a915fad503 ("mtd: spinand: winbond: Clarify when to enable the HS bit") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/core.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 697877584a285..33e6b76944ab8 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1436,6 +1436,9 @@ int spinand_match_and_init(struct spinand_device *spinand, + + op = spinand_select_op_variant(spinand, + info->op_variants.update_cache); ++ if (!op) ++ return -ENOTSUPP; ++ + spinand->op_templates.update_cache = op; + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-add-support-for-setting-a-bus-interface.patch b/queue-6.18/mtd-spinand-add-support-for-setting-a-bus-interface.patch new file mode 100644 index 0000000000..3727ccd135 --- /dev/null +++ b/queue-6.18/mtd-spinand-add-support-for-setting-a-bus-interface.patch @@ -0,0 +1,80 @@ +From 14cb91fac946643281e828852ca03fa71f15a213 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:20 +0100 +Subject: mtd: spinand: Add support for setting a bus interface + +From: Miquel Raynal + +[ Upstream commit 20387f2fe509eba46ecf758da052786d7b1203fb ] + +Create a bus interface enumeration, currently only containing the +one we support: SSDR, for single SDR, so any operation whose command is +sent over a single data line in SDR mode, ie. any operation matching +1S-XX-XX. + +The main spinand_device structure gets a new parameter to store this +enumeration, for now unused. Of course it is set to SSDR during the SSDR +templates initialization to further clarify the state we are in at the +moment. + +This member is subject to be used to know in which bus configuration we +and be updated by the core when we switch to faster mode(s). + +Signed-off-by: Miquel Raynal +Stable-dep-of: 25a915fad503 ("mtd: spinand: winbond: Clarify when to enable the HS bit") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/core.c | 1 + + include/linux/mtd/spinand.h | 10 ++++++++++ + 2 files changed, 11 insertions(+) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index b88f30ed746fc..9f6682c0af102 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1329,6 +1329,7 @@ static void spinand_init_ssdr_templates(struct spinand_device *spinand) + tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_1S_1S_0_OP(0); + tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_1S_1S_0_OP(0); + spinand->op_templates = &spinand->ssdr_op_templates; ++ spinand->bus_iface = SSDR; + } + + static const struct spi_mem_op * +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 3825fe9e759a6..c991c6c3bdedf 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -486,6 +486,14 @@ struct spinand_user_otp { + const struct spinand_user_otp_ops *ops; + }; + ++/** ++ * enum spinand_bus_interface - SPI NAND bus interface types ++ * @SSDR: Bus configuration supporting all 1S-XX-XX operations, including dual and quad ++ */ ++enum spinand_bus_interface { ++ SSDR, ++}; ++ + /** + * struct spinand_info - Structure used to describe SPI NAND chips + * @model: model name +@@ -643,6 +651,7 @@ struct spinand_mem_ops { + * @flags: NAND flags + * @ssdr_op_templates: Templates for all single SDR SPI mem operations + * @op_templates: Templates for all SPI mem operations ++ * @bus_iface: Current bus interface + * @select_target: select a specific target/die. Usually called before sending + * a command addressing a page or an eraseblock embedded in + * this die. Only required if your chip exposes several dies +@@ -678,6 +687,7 @@ struct spinand_device { + + struct spinand_mem_ops ssdr_op_templates; + struct spinand_mem_ops *op_templates; ++ enum spinand_bus_interface bus_iface; + + struct spinand_dirmap *dirmaps; + +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-create-an-array-of-operation-templates.patch b/queue-6.18/mtd-spinand-create-an-array-of-operation-templates.patch new file mode 100644 index 0000000000..0ba50adfa3 --- /dev/null +++ b/queue-6.18/mtd-spinand-create-an-array-of-operation-templates.patch @@ -0,0 +1,245 @@ +From cc2ac25e1d428e263bfeacbfa1083f2ad6cb0092 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:07 +0100 +Subject: mtd: spinand: Create an array of operation templates + +From: Miquel Raynal + +[ Upstream commit 408015023294958407925bc50cdd85718d12a335 ] + +Currently, the SPI NAND core implementation directly calls macros to get +the various operations in shape. These macros are specific to the bus +interface, currently only supporting the single SDR interface (any +command following the 1S-XX-XX pattern). + +Introducing support for other bus interfaces (such as octal DTR) would +mean that every user of these macros should become aware of the current +bus interface and act accordingly, picking up and adapting to the +current configuration. This would add quite a bit of boilerplate, be +repetitive as well as error prone in case we miss one occurrence. + +Instead, let's create a table with all SPI NAND memory operations that +are currently supported. We initialize them with the same single SDR _OP +macros as before. This opens the possibility for users of the individual +macros to make use of these templates instead. This way, when we will add +another bus interface, we can just switch to another set of templates +and all users will magically fill in their spi_mem_op structures with +the correct ops. + +The existing read, write and update cache variants are also moved in +this template array, which is barely noticeable by callers as we also +add a structure member pointing to it. + +Reviewed-by: Tudor Ambarus +Signed-off-by: Miquel Raynal +Stable-dep-of: 25a915fad503 ("mtd: spinand: winbond: Clarify when to enable the HS bit") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/core.c | 38 ++++++++++++++++++++++-------- + drivers/mtd/nand/spi/winbond.c | 4 ++-- + include/linux/mtd/spinand.h | 43 +++++++++++++++++++++++++++------- + 3 files changed, 64 insertions(+), 21 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index d3029ce2fe9ae..5c1797946a047 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -184,9 +184,9 @@ static int spinand_init_quad_enable(struct spinand_device *spinand) + if (!(spinand->flags & SPINAND_HAS_QE_BIT)) + return 0; + +- if (spinand->op_templates.read_cache->data.buswidth == 4 || +- spinand->op_templates.write_cache->data.buswidth == 4 || +- spinand->op_templates.update_cache->data.buswidth == 4) ++ if (spinand->op_templates->read_cache->data.buswidth == 4 || ++ spinand->op_templates->write_cache->data.buswidth == 4 || ++ spinand->op_templates->update_cache->data.buswidth == 4) + enable = true; + + return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE, +@@ -1162,7 +1162,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + info.offset = plane << fls(nand->memorg.pagesize); + + info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); +- info.op_tmpl = *spinand->op_templates.update_cache; ++ info.op_tmpl = *spinand->op_templates->update_cache; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, &info); + if (IS_ERR(desc)) +@@ -1170,7 +1170,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + + spinand->dirmaps[plane].wdesc = desc; + +- info.op_tmpl = *spinand->op_templates.read_cache; ++ info.op_tmpl = *spinand->op_templates->read_cache; + desc = spinand_create_rdesc(spinand, &info); + if (IS_ERR(desc)) + return PTR_ERR(desc); +@@ -1185,7 +1185,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + } + + info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); +- info.op_tmpl = *spinand->op_templates.update_cache; ++ info.op_tmpl = *spinand->op_templates->update_cache; + info.op_tmpl.data.ecc = true; + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, &info); +@@ -1194,7 +1194,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand, + + spinand->dirmaps[plane].wdesc_ecc = desc; + +- info.op_tmpl = *spinand->op_templates.read_cache; ++ info.op_tmpl = *spinand->op_templates->read_cache; + info.op_tmpl.data.ecc = true; + desc = spinand_create_rdesc(spinand, &info); + if (IS_ERR(desc)) +@@ -1330,6 +1330,22 @@ static void spinand_manufacturer_cleanup(struct spinand_device *spinand) + return spinand->manufacturer->ops->cleanup(spinand); + } + ++static void spinand_init_ssdr_templates(struct spinand_device *spinand) ++{ ++ struct spinand_mem_ops *tmpl = &spinand->ssdr_op_templates; ++ ++ tmpl->reset = (struct spi_mem_op)SPINAND_RESET_1S_0_0_OP; ++ tmpl->readid = (struct spi_mem_op)SPINAND_READID_1S_1S_1S_OP(0, 0, NULL, 0); ++ tmpl->wr_en = (struct spi_mem_op)SPINAND_WR_EN_1S_0_0_OP; ++ tmpl->wr_dis = (struct spi_mem_op)SPINAND_WR_DIS_1S_0_0_OP; ++ tmpl->set_feature = (struct spi_mem_op)SPINAND_SET_FEATURE_1S_1S_1S_OP(0, NULL); ++ tmpl->get_feature = (struct spi_mem_op)SPINAND_GET_FEATURE_1S_1S_1S_OP(0, NULL); ++ tmpl->blk_erase = (struct spi_mem_op)SPINAND_BLK_ERASE_1S_1S_0_OP(0); ++ tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_1S_1S_0_OP(0); ++ tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_1S_1S_0_OP(0); ++ spinand->op_templates = &spinand->ssdr_op_templates; ++} ++ + static const struct spi_mem_op * + spinand_select_op_variant(struct spinand_device *spinand, + const struct spinand_op_variants *variants) +@@ -1425,21 +1441,21 @@ int spinand_match_and_init(struct spinand_device *spinand, + if (!op) + return -ENOTSUPP; + +- spinand->op_templates.read_cache = op; ++ spinand->ssdr_op_templates.read_cache = op; + + op = spinand_select_op_variant(spinand, + info->op_variants.write_cache); + if (!op) + return -ENOTSUPP; + +- spinand->op_templates.write_cache = op; ++ spinand->ssdr_op_templates.write_cache = op; + + op = spinand_select_op_variant(spinand, + info->op_variants.update_cache); + if (!op) + return -ENOTSUPP; + +- spinand->op_templates.update_cache = op; ++ spinand->ssdr_op_templates.update_cache = op; + + return 0; + } +@@ -1554,6 +1570,8 @@ static int spinand_init(struct spinand_device *spinand) + if (!spinand->scratchbuf) + return -ENOMEM; + ++ spinand_init_ssdr_templates(spinand); ++ + ret = spinand_detect(spinand); + if (ret) + goto err_free_bufs; +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index af377b917a107..b389c9ee58508 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -291,7 +291,7 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spinand) + u8 sr4; + int ret; + +- op = spinand->op_templates.read_cache; ++ op = spinand->op_templates->read_cache; + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + hs = false; + else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && +@@ -355,7 +355,7 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand) + u8 io_mode; + int ret; + +- op = spinand->op_templates.read_cache; ++ op = spinand->op_templates->read_cache; + + single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1); + dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr); +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index c74c9ba0cd0a4..3825fe9e759a6 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -604,6 +604,36 @@ struct spinand_dirmap { + struct spi_mem_dirmap_desc *rdesc_ecc; + }; + ++/** ++ * struct spinand_mem_ops - SPI NAND memory operations ++ * @reset: reset op template ++ * @readid: read ID op template ++ * @wr_en: write enable op template ++ * @wr_dis: write disable op template ++ * @set_feature: set feature op template ++ * @get_feature: get feature op template ++ * @blk_erase: blk erase op template ++ * @page_read: page read op template ++ * @prog_exec: prog exec op template ++ * @read_cache: read cache op template ++ * @write_cache: write cache op template ++ * @update_cache: update cache op template ++ */ ++struct spinand_mem_ops { ++ struct spi_mem_op reset; ++ struct spi_mem_op readid; ++ struct spi_mem_op wr_en; ++ struct spi_mem_op wr_dis; ++ struct spi_mem_op set_feature; ++ struct spi_mem_op get_feature; ++ struct spi_mem_op blk_erase; ++ struct spi_mem_op page_read; ++ struct spi_mem_op prog_exec; ++ const struct spi_mem_op *read_cache; ++ const struct spi_mem_op *write_cache; ++ const struct spi_mem_op *update_cache; ++}; ++ + /** + * struct spinand_device - SPI NAND device instance + * @base: NAND device instance +@@ -611,10 +641,8 @@ struct spinand_dirmap { + * @lock: lock used to serialize accesses to the NAND + * @id: NAND ID as returned by READ_ID + * @flags: NAND flags +- * @op_templates: various SPI mem op templates +- * @op_templates.read_cache: read cache op template +- * @op_templates.write_cache: write cache op template +- * @op_templates.update_cache: update cache op template ++ * @ssdr_op_templates: Templates for all single SDR SPI mem operations ++ * @op_templates: Templates for all SPI mem operations + * @select_target: select a specific target/die. Usually called before sending + * a command addressing a page or an eraseblock embedded in + * this die. Only required if your chip exposes several dies +@@ -648,11 +676,8 @@ struct spinand_device { + struct spinand_id id; + u32 flags; + +- struct { +- const struct spi_mem_op *read_cache; +- const struct spi_mem_op *write_cache; +- const struct spi_mem_op *update_cache; +- } op_templates; ++ struct spinand_mem_ops ssdr_op_templates; ++ struct spinand_mem_ops *op_templates; + + struct spinand_dirmap *dirmaps; + +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-decouple-write-enable-and-write-disable-.patch b/queue-6.18/mtd-spinand-decouple-write-enable-and-write-disable-.patch new file mode 100644 index 0000000000..e2fdfdee64 --- /dev/null +++ b/queue-6.18/mtd-spinand-decouple-write-enable-and-write-disable-.patch @@ -0,0 +1,91 @@ +From 7f44d7dad7444f5ff3990625c638a62ea37ff1b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:06 +0100 +Subject: mtd: spinand: Decouple write enable and write disable operations + +From: Miquel Raynal + +[ Upstream commit c0ba929cf7a960c796cc9946b3f79d8405e9b805 ] + +In order to introduce templates for all operations and not only for page +helpers (in order to introduce octal DDR support), decouple the WR_EN +and WR_DIS operations into two separate macros. + +Adapt the callers accordingly. + +There is no functional change. + +Reviewed-by: Tudor Ambarus +Signed-off-by: Miquel Raynal +Stable-dep-of: 25a915fad503 ("mtd: spinand: winbond: Clarify when to enable the HS bit") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/core.c | 2 +- + drivers/mtd/nand/spi/esmt.c | 2 +- + drivers/mtd/nand/spi/micron.c | 2 +- + include/linux/mtd/spinand.h | 10 ++++++++-- + 4 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 33e6b76944ab8..d3029ce2fe9ae 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -362,7 +362,7 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status) + + int spinand_write_enable_op(struct spinand_device *spinand) + { +- struct spi_mem_op op = SPINAND_WR_EN_DIS_1S_0_0_OP(true); ++ struct spi_mem_op op = SPINAND_WR_EN_1S_0_0_OP; + + return spi_mem_exec_op(spinand->spimem, &op); + } +diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c +index 9a9325c0bc497..f880c3b15ceab 100644 +--- a/drivers/mtd/nand/spi/esmt.c ++++ b/drivers/mtd/nand/spi/esmt.c +@@ -137,7 +137,7 @@ static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len, + static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from, + size_t len) + { +- struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true); ++ struct spi_mem_op write_op = SPINAND_WR_EN_1S_0_0_OP; + struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0); + u8 status; + int ret; +diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c +index a49d7cb6a96da..b8130e04e8e79 100644 +--- a/drivers/mtd/nand/spi/micron.c ++++ b/drivers/mtd/nand/spi/micron.c +@@ -251,7 +251,7 @@ static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand, + static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t from, + size_t len) + { +- struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true); ++ struct spi_mem_op write_op = SPINAND_WR_EN_1S_0_0_OP; + struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0); + u8 status; + int ret; +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 1c741145e4971..c74c9ba0cd0a4 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -26,8 +26,14 @@ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_NO_DATA) + +-#define SPINAND_WR_EN_DIS_1S_0_0_OP(enable) \ +- SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1), \ ++#define SPINAND_WR_EN_1S_0_0_OP \ ++ SPI_MEM_OP(SPI_MEM_OP_CMD(0x06, 1), \ ++ SPI_MEM_OP_NO_ADDR, \ ++ SPI_MEM_OP_NO_DUMMY, \ ++ SPI_MEM_OP_NO_DATA) ++ ++#define SPINAND_WR_DIS_1S_0_0_OP \ ++ SPI_MEM_OP(SPI_MEM_OP_CMD(0x04, 1), \ + SPI_MEM_OP_NO_ADDR, \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_NO_DATA) +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-gather-all-the-bus-interface-steps-in-on.patch b/queue-6.18/mtd-spinand-gather-all-the-bus-interface-steps-in-on.patch new file mode 100644 index 0000000000..5146e28eb5 --- /dev/null +++ b/queue-6.18/mtd-spinand-gather-all-the-bus-interface-steps-in-on.patch @@ -0,0 +1,140 @@ +From 9a485393c35d416de029e57aea4ee2e7a4b2a564 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:19 +0100 +Subject: mtd: spinand: Gather all the bus interface steps in one single + function + +From: Miquel Raynal + +[ Upstream commit be0b86c648bf811237cc17e274e9f9488fccb772 ] + +Writing the quad enable bit in one helper and doing the chip +configuration in another does not make much sense from a bus interface +setup point of view. + +Instead, let's create a broader helper which is going to be in charge of +all the bus configuration steps at once. This will specifically allow to +transition to octal DDR mode, and even fallback to quad (if suppoorted) +or single mode otherwise. + +Signed-off-by: Miquel Raynal +Stable-dep-of: 25a915fad503 ("mtd: spinand: winbond: Clarify when to enable the HS bit") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/core.c | 62 ++++++++++++++++++++++--------------- + 1 file changed, 37 insertions(+), 25 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 5c1797946a047..b88f30ed746fc 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -177,18 +177,9 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand) + return 0; + } + +-static int spinand_init_quad_enable(struct spinand_device *spinand) ++static int spinand_init_quad_enable(struct spinand_device *spinand, ++ bool enable) + { +- bool enable = false; +- +- if (!(spinand->flags & SPINAND_HAS_QE_BIT)) +- return 0; +- +- if (spinand->op_templates->read_cache->data.buswidth == 4 || +- spinand->op_templates->write_cache->data.buswidth == 4 || +- spinand->op_templates->update_cache->data.buswidth == 4) +- enable = true; +- + return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE, + enable ? CFG_QUAD_ENABLE : 0); + } +@@ -1314,12 +1305,6 @@ static int spinand_manufacturer_init(struct spinand_device *spinand) + return ret; + } + +- if (spinand->configure_chip) { +- ret = spinand->configure_chip(spinand); +- if (ret) +- return ret; +- } +- + return 0; + } + +@@ -1496,6 +1481,31 @@ static int spinand_detect(struct spinand_device *spinand) + return 0; + } + ++static int spinand_configure_chip(struct spinand_device *spinand) ++{ ++ bool quad_enable = false; ++ int ret; ++ ++ if (spinand->flags & SPINAND_HAS_QE_BIT) { ++ if (spinand->ssdr_op_templates.read_cache->data.buswidth == 4 || ++ spinand->ssdr_op_templates.write_cache->data.buswidth == 4 || ++ spinand->ssdr_op_templates.update_cache->data.buswidth == 4) ++ quad_enable = true; ++ } ++ ++ ret = spinand_init_quad_enable(spinand, quad_enable); ++ if (ret) ++ return ret; ++ ++ if (spinand->configure_chip) { ++ ret = spinand->configure_chip(spinand); ++ if (ret) ++ return ret; ++ } ++ ++ return ret; ++} ++ + static int spinand_init_flash(struct spinand_device *spinand) + { + struct device *dev = &spinand->spimem->spi->dev; +@@ -1506,10 +1516,6 @@ static int spinand_init_flash(struct spinand_device *spinand) + if (ret) + return ret; + +- ret = spinand_init_quad_enable(spinand); +- if (ret) +- return ret; +- + ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0); + if (ret) + return ret; +@@ -1522,19 +1528,25 @@ static int spinand_init_flash(struct spinand_device *spinand) + return ret; + } + ++ ret = spinand_configure_chip(spinand); ++ if (ret) ++ goto manuf_cleanup; ++ + /* After power up, all blocks are locked, so unlock them here. */ + for (i = 0; i < nand->memorg.ntargets; i++) { + ret = spinand_select_target(spinand, i); + if (ret) +- break; ++ goto manuf_cleanup; + + ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED); + if (ret) +- break; ++ goto manuf_cleanup; + } + +- if (ret) +- spinand_manufacturer_cleanup(spinand); ++ return 0; ++ ++manuf_cleanup: ++ spinand_manufacturer_cleanup(spinand); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-give-the-bus-interface-to-the-configurat.patch b/queue-6.18/mtd-spinand-give-the-bus-interface-to-the-configurat.patch new file mode 100644 index 0000000000..a6d79a9cb9 --- /dev/null +++ b/queue-6.18/mtd-spinand-give-the-bus-interface-to-the-configurat.patch @@ -0,0 +1,131 @@ +From 1e0ba49c2f124790cbc6bde6e2f0423f6550cb31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:22 +0100 +Subject: mtd: spinand: Give the bus interface to the configuration helper + +From: Miquel Raynal + +[ Upstream commit 0a331a1851aedd670b95a2d16c6a82496137378d ] + +The chip configuration hook is the one responsible to actually switch +the switch between bus interfaces. It is natural to give it the bus +interface we expect with a new parameter. For now the only value we can +give is SSDR, but this is subject to change in the future, so add a bit +of extra logic in the implementations of this callback to make sure +both the core and the chip driver are aligned on the request. + +Signed-off-by: Miquel Raynal +Stable-dep-of: 25a915fad503 ("mtd: spinand: winbond: Clarify when to enable the HS bit") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/core.c | 2 +- + drivers/mtd/nand/spi/winbond.c | 28 +++++++++++++++++++++------- + include/linux/mtd/spinand.h | 6 ++++-- + 3 files changed, 26 insertions(+), 10 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 9f6682c0af102..2f656a5e4af89 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1499,7 +1499,7 @@ static int spinand_configure_chip(struct spinand_device *spinand) + return ret; + + if (spinand->configure_chip) { +- ret = spinand->configure_chip(spinand); ++ ret = spinand->configure_chip(spinand, SSDR); + if (ret) + return ret; + } +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index 6cb5dd45e6fb7..0ea5b1c97d33d 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -284,13 +284,17 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand, + return -EINVAL; + } + +-static int w25n0xjw_hs_cfg(struct spinand_device *spinand) ++static int w25n0xjw_hs_cfg(struct spinand_device *spinand, ++ enum spinand_bus_interface iface) + { + const struct spi_mem_op *op; + bool hs; + u8 sr4; + int ret; + ++ if (iface != SSDR) ++ return -EOPNOTSUPP; ++ + op = spinand->op_templates->read_cache; + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + hs = false; +@@ -347,17 +351,25 @@ static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val) + return 0; + } + +-static int w35n0xjw_vcr_cfg(struct spinand_device *spinand) ++static int w35n0xjw_vcr_cfg(struct spinand_device *spinand, ++ enum spinand_bus_interface iface) + { +- const struct spi_mem_op *op; ++ const struct spi_mem_op *ref_op; + unsigned int dummy_cycles; + bool dtr, single; + u8 io_mode; + int ret; + +- op = spinand->op_templates->read_cache; ++ switch (iface) { ++ case SSDR: ++ ref_op = spinand->ssdr_op_templates.read_cache; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ }; + +- dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1); ++ dummy_cycles = ((ref_op->dummy.nbytes * 8) / ref_op->dummy.buswidth) / ++ (ref_op->dummy.dtr ? 2 : 1); + switch (dummy_cycles) { + case 8: + case 12: +@@ -373,8 +385,10 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand) + if (ret) + return ret; + +- single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1); +- dtr = (op->cmd.dtr && op->addr.dtr && op->data.dtr); ++ single = (ref_op->cmd.buswidth == 1 && ++ ref_op->addr.buswidth == 1 && ++ ref_op->data.buswidth == 1); ++ dtr = (ref_op->cmd.dtr && ref_op->addr.dtr && ref_op->data.dtr); + if (single && !dtr) + io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR; + else if (!single && !dtr) +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index c991c6c3bdedf..07e4d87019c64 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -532,7 +532,8 @@ struct spinand_info { + } op_variants; + int (*select_target)(struct spinand_device *spinand, + unsigned int target); +- int (*configure_chip)(struct spinand_device *spinand); ++ int (*configure_chip)(struct spinand_device *spinand, ++ enum spinand_bus_interface iface); + int (*set_cont_read)(struct spinand_device *spinand, + bool enable); + struct spinand_fact_otp fact_otp; +@@ -704,7 +705,8 @@ struct spinand_device { + const struct spinand_manufacturer *manufacturer; + void *priv; + +- int (*configure_chip)(struct spinand_device *spinand); ++ int (*configure_chip)(struct spinand_device *spinand, ++ enum spinand_bus_interface iface); + bool cont_read_possible; + int (*set_cont_read)(struct spinand_device *spinand, + bool enable); +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-winbond-clarify-when-to-enable-the-hs-bi.patch b/queue-6.18/mtd-spinand-winbond-clarify-when-to-enable-the-hs-bi.patch new file mode 100644 index 0000000000..051a8de34d --- /dev/null +++ b/queue-6.18/mtd-spinand-winbond-clarify-when-to-enable-the-hs-bi.patch @@ -0,0 +1,54 @@ +From 877d1bd280601a3e372e6b9380cc7dae22215f4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 11:47:50 +0100 +Subject: mtd: spinand: winbond: Clarify when to enable the HS bit + +From: Miquel Raynal + +[ Upstream commit 25a915fad503c2678902075565d47ddc2aa45db9 ] + +Above 104MHz when in fast dual or quad I/O reads, the delay between +address and data cycles is too short. It is possible to reach higher +frequencies, up to 166MHz, by adding a few more dummy cycles through the +setting of the HS bit. Improve the condition for enabling this bit, and +also make sure we set it at soon as we go over 104MHz. + +Fixes: f1a91175faaa ("mtd: spinand: winbond: Enable high-speed modes on w25n0xjw") +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/winbond.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index 0ea5b1c97d33d..578924c98b90a 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -295,16 +295,19 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spinand, + if (iface != SSDR) + return -EOPNOTSUPP; + ++ /* ++ * SDR dual and quad I/O operations over 104MHz require the HS bit to ++ * enable a few more dummy cycles. ++ */ + op = spinand->op_templates->read_cache; + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + hs = false; +- else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && +- op->dummy.buswidth == 1 && op->data.buswidth == 1) ++ else if (op->cmd.buswidth != 1 || op->addr.buswidth == 1) + hs = false; +- else if (!op->max_freq) +- hs = true; +- else ++ else if (op->max_freq && op->max_freq <= 104 * HZ_PER_MHZ) + hs = false; ++ else ++ hs = true; + + ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4); + if (ret) +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-winbond-configure-the-io-mode-after-the-.patch b/queue-6.18/mtd-spinand-winbond-configure-the-io-mode-after-the-.patch new file mode 100644 index 0000000000..02c8c616e7 --- /dev/null +++ b/queue-6.18/mtd-spinand-winbond-configure-the-io-mode-after-the-.patch @@ -0,0 +1,76 @@ +From 332d72a727f748f3be7fe05adb91093409487f3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:18 +0100 +Subject: mtd: spinand: winbond: Configure the IO mode after the dummy cycles + +From: Miquel Raynal + +[ Upstream commit ef1ed296fb9d9246256e1b5b2cf2e86e85606ac3 ] + +When we will change the bus interface, the action that actually performs +the transition is the IO mode register write. This means after the IO +mode register write, we should use the new bus interface. But the +->configure_chip() hook itself is not responsible of making this change +official, it is the caller that must act according to the return value. + +Reorganize this helper to first configure the dummy cycles before +possibly switching to another bus interface. + +Signed-off-by: Miquel Raynal +Stable-dep-of: 25a915fad503 ("mtd: spinand: winbond: Clarify when to enable the HS bit") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/winbond.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index 2361109101727..6cb5dd45e6fb7 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -357,21 +357,6 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand) + + op = spinand->op_templates->read_cache; + +- single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1); +- dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr); +- if (single && !dtr) +- io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR; +- else if (!single && !dtr) +- io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR; +- else if (!single && dtr) +- io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR; +- else +- return -EINVAL; +- +- ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE_REG, io_mode); +- if (ret) +- return ret; +- + dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1); + switch (dummy_cycles) { + case 8: +@@ -388,6 +373,21 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand) + if (ret) + return ret; + ++ single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1); ++ dtr = (op->cmd.dtr && op->addr.dtr && op->data.dtr); ++ if (single && !dtr) ++ io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR; ++ else if (!single && !dtr) ++ io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR; ++ else if (!single && dtr) ++ io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR; ++ else ++ return -EINVAL; ++ ++ ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE_REG, io_mode); ++ if (ret) ++ return ret; ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/mtd-spinand-winbond-rename-io_mode-register-macro.patch b/queue-6.18/mtd-spinand-winbond-rename-io_mode-register-macro.patch new file mode 100644 index 0000000000..92f1ba9282 --- /dev/null +++ b/queue-6.18/mtd-spinand-winbond-rename-io_mode-register-macro.patch @@ -0,0 +1,43 @@ +From af1342bd12fb867d57612194e5c835173243c14a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 18:18:17 +0100 +Subject: mtd: spinand: winbond: Rename IO_MODE register macro + +From: Miquel Raynal + +[ Upstream commit 57e1015cc9a96372f330195abe32a904ec8d1eab ] + +Suffix the macro name with *_REG to align with the rest of the driver. + +Signed-off-by: Miquel Raynal +Stable-dep-of: 25a915fad503 ("mtd: spinand: winbond: Clarify when to enable the HS bit") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/winbond.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index b389c9ee58508..2361109101727 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -22,7 +22,7 @@ + #define W25N0XJW_SR4 0xD0 + #define W25N0XJW_SR4_HS BIT(2) + +-#define W35N01JW_VCR_IO_MODE 0x00 ++#define W35N01JW_VCR_IO_MODE_REG 0x00 + #define W35N01JW_VCR_IO_MODE_SINGLE_SDR 0xFF + #define W35N01JW_VCR_IO_MODE_OCTAL_SDR 0xDF + #define W35N01JW_VCR_IO_MODE_OCTAL_DDR_DS 0xE7 +@@ -368,7 +368,7 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spinand) + else + return -EINVAL; + +- ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE, io_mode); ++ ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE_REG, io_mode); + if (ret) + return ret; + +-- +2.53.0 + diff --git a/queue-6.18/neigh-let-neigh_xmit-take-skb-ownership.patch b/queue-6.18/neigh-let-neigh_xmit-take-skb-ownership.patch new file mode 100644 index 0000000000..12bc54fdca --- /dev/null +++ b/queue-6.18/neigh-let-neigh_xmit-take-skb-ownership.patch @@ -0,0 +1,74 @@ +From 592f70c809a947f956574fb516b322b0a5901a88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 16:58:38 +0200 +Subject: neigh: let neigh_xmit take skb ownership + +From: Florian Westphal + +[ Upstream commit 4438113be604ee67a7bf4f81da6e1cca41332ce4 ] + +neigh_xmit always releases the skb, except when no neighbour table is +found. But even the first added user of neigh_xmit (mpls) relied on +neigh_xmit to release the skb (or queue it for tx). + +sashiko reported: + If neigh_xmit() is called with an uninitialized neighbor table (for + example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT + and bypasses its internal out_kfree_skb error path. Because the return + value of neigh_xmit() is ignored here, does this leak the SKB? + +Assume full ownership and remove the last code path that doesn't +xmit or free skb. + +Fixes: 4fd3d7d9e868 ("neigh: Add helper function neigh_xmit") +Signed-off-by: Florian Westphal +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260424145843.74055-1-fw@strlen.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index 6dab4d1c2263d..dabd368eaa4e7 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -3182,8 +3182,10 @@ int neigh_xmit(int index, struct net_device *dev, + + rcu_read_lock(); + tbl = rcu_dereference(neigh_tables[index]); +- if (!tbl) +- goto out_unlock; ++ if (!tbl) { ++ rcu_read_unlock(); ++ goto out_kfree_skb; ++ } + if (index == NEIGH_ARP_TABLE) { + u32 key = *((u32 *)addr); + +@@ -3199,7 +3201,6 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + } + err = READ_ONCE(neigh->output)(neigh, skb); +-out_unlock: + rcu_read_unlock(); + } + else if (index == NEIGH_LINK_TABLE) { +@@ -3209,11 +3210,10 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + err = dev_queue_xmit(skb); + } +-out: + return err; + out_kfree_skb: + kfree_skb(skb); +- goto out; ++ return err; + } + EXPORT_SYMBOL(neigh_xmit); + +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-airoha_eth_soc_data-struct.patch b/queue-6.18/net-airoha-add-airoha_eth_soc_data-struct.patch new file mode 100644 index 0000000000..91abc45eb4 --- /dev/null +++ b/queue-6.18/net-airoha-add-airoha_eth_soc_data-struct.patch @@ -0,0 +1,165 @@ +From 2fcf67625ae2b8cf88d664efe4f27d05b1882092 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Oct 2025 11:06:13 +0200 +Subject: net: airoha: Add airoha_eth_soc_data struct + +From: Lorenzo Bianconi + +[ Upstream commit 5863b4e065e2253ef05684f728a04e4972046bcb ] + +Introduce airoha_eth_soc_data struct to contain differences between +various SoC. Move XSI reset names in airoha_eth_soc_data. This is a +preliminary patch to enable AN7583 ethernet controller support in +airoha-eth driver. + +Co-developed-by: Christian Marangi +Signed-off-by: Christian Marangi +Reviewed-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251017-an7583-eth-support-v3-4-f28319666667@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 02f729643959 ("net: airoha: Fix FE_PSE_BUF_SET configuration if PPE2 is available") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 42 +++++++++++++++++++----- + drivers/net/ethernet/airoha/airoha_eth.h | 17 ++++++++-- + 2 files changed, 48 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 060865b98880e..5162f2a689000 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1406,8 +1406,7 @@ static int airoha_hw_init(struct platform_device *pdev, + int err, i; + + /* disable xsi */ +- err = reset_control_bulk_assert(ARRAY_SIZE(eth->xsi_rsts), +- eth->xsi_rsts); ++ err = reset_control_bulk_assert(eth->soc->num_xsi_rsts, eth->xsi_rsts); + if (err) + return err; + +@@ -2943,6 +2942,7 @@ static int airoha_register_gdm_devices(struct airoha_eth *eth) + + static int airoha_probe(struct platform_device *pdev) + { ++ struct reset_control_bulk_data *xsi_rsts; + struct device_node *np; + struct airoha_eth *eth; + int i, err; +@@ -2951,6 +2951,10 @@ static int airoha_probe(struct platform_device *pdev) + if (!eth) + return -ENOMEM; + ++ eth->soc = of_device_get_match_data(&pdev->dev); ++ if (!eth->soc) ++ return -EINVAL; ++ + eth->dev = &pdev->dev; + + err = dma_set_mask_and_coherent(eth->dev, DMA_BIT_MASK(32)); +@@ -2975,13 +2979,18 @@ static int airoha_probe(struct platform_device *pdev) + return err; + } + +- eth->xsi_rsts[0].id = "xsi-mac"; +- eth->xsi_rsts[1].id = "hsi0-mac"; +- eth->xsi_rsts[2].id = "hsi1-mac"; +- eth->xsi_rsts[3].id = "hsi-mac"; +- eth->xsi_rsts[4].id = "xfp-mac"; ++ xsi_rsts = devm_kzalloc(eth->dev, ++ eth->soc->num_xsi_rsts * sizeof(*xsi_rsts), ++ GFP_KERNEL); ++ if (err) ++ return err; ++ ++ eth->xsi_rsts = xsi_rsts; ++ for (i = 0; i < eth->soc->num_xsi_rsts; i++) ++ eth->xsi_rsts[i].id = eth->soc->xsi_rsts_names[i]; ++ + err = devm_reset_control_bulk_get_exclusive(eth->dev, +- ARRAY_SIZE(eth->xsi_rsts), ++ eth->soc->num_xsi_rsts, + eth->xsi_rsts); + if (err) { + dev_err(eth->dev, "failed to get bulk xsi reset lines\n"); +@@ -3074,8 +3083,23 @@ static void airoha_remove(struct platform_device *pdev) + platform_set_drvdata(pdev, NULL); + } + ++static const char * const en7581_xsi_rsts_names[] = { ++ "xsi-mac", ++ "hsi0-mac", ++ "hsi1-mac", ++ "hsi-mac", ++ "xfp-mac", ++}; ++ ++static const struct airoha_eth_soc_data en7581_soc_data = { ++ .version = 0x7581, ++ .xsi_rsts_names = en7581_xsi_rsts_names, ++ .num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names), ++ .num_ppe = 2, ++}; ++ + static const struct of_device_id of_airoha_match[] = { +- { .compatible = "airoha,en7581-eth" }, ++ { .compatible = "airoha,en7581-eth", .data = &en7581_soc_data }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, of_airoha_match); +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 3e43f01e9a652..655bc6acd80f0 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -21,7 +21,6 @@ + #define AIROHA_MAX_NUM_IRQ_BANKS 4 + #define AIROHA_MAX_DSA_PORTS 7 + #define AIROHA_MAX_NUM_RSTS 3 +-#define AIROHA_MAX_NUM_XSI_RSTS 5 + #define AIROHA_MAX_MTU 9216 + #define AIROHA_MAX_PACKET_SIZE 2048 + #define AIROHA_NUM_QOS_CHANNELS 4 +@@ -556,9 +555,18 @@ struct airoha_ppe { + struct dentry *debugfs_dir; + }; + ++struct airoha_eth_soc_data { ++ u16 version; ++ const char * const *xsi_rsts_names; ++ int num_xsi_rsts; ++ int num_ppe; ++}; ++ + struct airoha_eth { + struct device *dev; + ++ const struct airoha_eth_soc_data *soc; ++ + unsigned long state; + void __iomem *fe_regs; + +@@ -568,7 +576,7 @@ struct airoha_eth { + struct rhashtable flow_table; + + struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS]; +- struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS]; ++ struct reset_control_bulk_data *xsi_rsts; + + struct net_device *napi_dev; + +@@ -611,6 +619,11 @@ static inline bool airhoa_is_lan_gdm_port(struct airoha_gdm_port *port) + return port->id == 1; + } + ++static inline bool airoha_is_7581(struct airoha_eth *eth) ++{ ++ return eth->soc->version == 0x7581; ++} ++ + bool airoha_is_valid_gdm_port(struct airoha_eth *eth, + struct airoha_gdm_port *port); + +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-airoha_ppe_get_num_stats_entries-and-.patch b/queue-6.18/net-airoha-add-airoha_ppe_get_num_stats_entries-and-.patch new file mode 100644 index 0000000000..390bf22fa3 --- /dev/null +++ b/queue-6.18/net-airoha-add-airoha_ppe_get_num_stats_entries-and-.patch @@ -0,0 +1,252 @@ +From c9511b5303277d64eb20f4c36c5e1d35a9a6f932 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Oct 2025 11:06:12 +0200 +Subject: net: airoha: Add airoha_ppe_get_num_stats_entries() and + airoha_ppe_get_num_total_stats_entries() + +From: Lorenzo Bianconi + +[ Upstream commit 15f357cd4581ce6e02e5e97719320600783140ec ] + +Introduce airoha_ppe_get_num_stats_entries and +airoha_ppe_get_num_total_stats_entries routines in order to make the +code more readable controlling if CONFIG_NET_AIROHA_FLOW_STATS is +enabled or disabled. +Modify airoha_ppe_foe_get_flow_stats_index routine signature relying on +airoha_ppe_get_num_total_stats_entries(). + +Reviewed-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251017-an7583-eth-support-v3-3-f28319666667@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 02f729643959 ("net: airoha: Fix FE_PSE_BUF_SET configuration if PPE2 is available") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.h | 10 +-- + drivers/net/ethernet/airoha/airoha_ppe.c | 101 ++++++++++++++++++----- + 2 files changed, 81 insertions(+), 30 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index cd13c1c1224f6..3e43f01e9a652 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -50,15 +50,9 @@ + + #define PPE_NUM 2 + #define PPE1_SRAM_NUM_ENTRIES (8 * 1024) +-#define PPE_SRAM_NUM_ENTRIES (2 * PPE1_SRAM_NUM_ENTRIES) +-#ifdef CONFIG_NET_AIROHA_FLOW_STATS ++#define PPE_SRAM_NUM_ENTRIES (PPE_NUM * PPE1_SRAM_NUM_ENTRIES) + #define PPE1_STATS_NUM_ENTRIES (4 * 1024) +-#else +-#define PPE1_STATS_NUM_ENTRIES 0 +-#endif /* CONFIG_NET_AIROHA_FLOW_STATS */ +-#define PPE_STATS_NUM_ENTRIES (2 * PPE1_STATS_NUM_ENTRIES) +-#define PPE1_SRAM_NUM_DATA_ENTRIES (PPE1_SRAM_NUM_ENTRIES - PPE1_STATS_NUM_ENTRIES) +-#define PPE_SRAM_NUM_DATA_ENTRIES (2 * PPE1_SRAM_NUM_DATA_ENTRIES) ++#define PPE_STATS_NUM_ENTRIES (PPE_NUM * PPE1_STATS_NUM_ENTRIES) + #define PPE_DRAM_NUM_ENTRIES (16 * 1024) + #define PPE_NUM_ENTRIES (PPE_SRAM_NUM_ENTRIES + PPE_DRAM_NUM_ENTRIES) + #define PPE_HASH_MASK (PPE_NUM_ENTRIES - 1) +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index b3632f964a580..117dfc21d6a81 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -32,6 +32,24 @@ static const struct rhashtable_params airoha_l2_flow_table_params = { + .automatic_shrinking = true, + }; + ++static int airoha_ppe_get_num_stats_entries(struct airoha_ppe *ppe) ++{ ++ if (!IS_ENABLED(CONFIG_NET_AIROHA_FLOW_STATS)) ++ return -EOPNOTSUPP; ++ ++ return PPE1_STATS_NUM_ENTRIES; ++} ++ ++static int airoha_ppe_get_total_num_stats_entries(struct airoha_ppe *ppe) ++{ ++ int num_stats = airoha_ppe_get_num_stats_entries(ppe); ++ ++ if (num_stats > 0) ++ num_stats = num_stats * PPE_NUM; ++ ++ return num_stats; ++} ++ + static bool airoha_ppe2_is_enabled(struct airoha_eth *eth) + { + return airoha_fe_rr(eth, REG_PPE_GLO_CFG(1)) & PPE_GLO_CFG_EN_MASK; +@@ -48,7 +66,7 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + { + u32 sram_tb_size, sram_num_entries, dram_num_entries; + struct airoha_eth *eth = ppe->eth; +- int i; ++ int i, sram_num_stats_entries; + + sram_tb_size = PPE_SRAM_NUM_ENTRIES * sizeof(struct airoha_foe_entry); + dram_num_entries = PPE_RAM_NUM_ENTRIES_SHIFT(PPE_DRAM_NUM_ENTRIES); +@@ -103,8 +121,13 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + } + + if (airoha_ppe2_is_enabled(eth)) { +- sram_num_entries = +- PPE_RAM_NUM_ENTRIES_SHIFT(PPE1_SRAM_NUM_DATA_ENTRIES); ++ sram_num_entries = PPE1_SRAM_NUM_ENTRIES; ++ sram_num_stats_entries = ++ airoha_ppe_get_num_stats_entries(ppe); ++ if (sram_num_stats_entries > 0) ++ sram_num_entries -= sram_num_stats_entries; ++ sram_num_entries = PPE_RAM_NUM_ENTRIES_SHIFT(sram_num_entries); ++ + airoha_fe_rmw(eth, REG_PPE_TB_CFG(0), + PPE_SRAM_TB_NUM_ENTRY_MASK | + PPE_DRAM_TB_NUM_ENTRY_MASK, +@@ -120,8 +143,13 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, + dram_num_entries)); + } else { +- sram_num_entries = +- PPE_RAM_NUM_ENTRIES_SHIFT(PPE_SRAM_NUM_DATA_ENTRIES); ++ sram_num_entries = PPE_SRAM_NUM_ENTRIES; ++ sram_num_stats_entries = ++ airoha_ppe_get_total_num_stats_entries(ppe); ++ if (sram_num_stats_entries > 0) ++ sram_num_entries -= sram_num_stats_entries; ++ sram_num_entries = PPE_RAM_NUM_ENTRIES_SHIFT(sram_num_entries); ++ + airoha_fe_rmw(eth, REG_PPE_TB_CFG(0), + PPE_SRAM_TB_NUM_ENTRY_MASK | + PPE_DRAM_TB_NUM_ENTRY_MASK, +@@ -482,13 +510,21 @@ static u32 airoha_ppe_foe_get_entry_hash(struct airoha_foe_entry *hwe) + return hash; + } + +-static u32 airoha_ppe_foe_get_flow_stats_index(struct airoha_ppe *ppe, u32 hash) ++static int airoha_ppe_foe_get_flow_stats_index(struct airoha_ppe *ppe, ++ u32 hash, u32 *index) + { +- if (!airoha_ppe2_is_enabled(ppe->eth)) +- return hash; ++ int ppe_num_stats_entries; ++ ++ ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); ++ if (ppe_num_stats_entries < 0) ++ return ppe_num_stats_entries; + +- return hash >= PPE_STATS_NUM_ENTRIES ? hash - PPE1_STATS_NUM_ENTRIES +- : hash; ++ *index = hash; ++ if (airoha_ppe2_is_enabled(ppe->eth) && ++ hash >= ppe_num_stats_entries) ++ *index = *index - PPE_STATS_NUM_ENTRIES; ++ ++ return 0; + } + + static void airoha_ppe_foe_flow_stat_entry_reset(struct airoha_ppe *ppe, +@@ -502,9 +538,13 @@ static void airoha_ppe_foe_flow_stat_entry_reset(struct airoha_ppe *ppe, + static void airoha_ppe_foe_flow_stats_reset(struct airoha_ppe *ppe, + struct airoha_npu *npu) + { +- int i; ++ int i, ppe_num_stats_entries; ++ ++ ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); ++ if (ppe_num_stats_entries < 0) ++ return; + +- for (i = 0; i < PPE_STATS_NUM_ENTRIES; i++) ++ for (i = 0; i < ppe_num_stats_entries; i++) + airoha_ppe_foe_flow_stat_entry_reset(ppe, npu, i); + } + +@@ -515,10 +555,17 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe, + { + int type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe->ib1); + u32 index, pse_port, val, *data, *ib2, *meter; ++ int ppe_num_stats_entries; + u8 nbq; + +- index = airoha_ppe_foe_get_flow_stats_index(ppe, hash); +- if (index >= PPE_STATS_NUM_ENTRIES) ++ ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); ++ if (ppe_num_stats_entries < 0) ++ return; ++ ++ if (airoha_ppe_foe_get_flow_stats_index(ppe, hash, &index)) ++ return; ++ ++ if (index >= ppe_num_stats_entries) + return; + + if (type == PPE_PKT_TYPE_BRIDGE) { +@@ -1160,11 +1207,19 @@ static int airoha_ppe_flow_offload_destroy(struct airoha_eth *eth, + void airoha_ppe_foe_entry_get_stats(struct airoha_ppe *ppe, u32 hash, + struct airoha_foe_stats64 *stats) + { +- u32 index = airoha_ppe_foe_get_flow_stats_index(ppe, hash); + struct airoha_eth *eth = ppe->eth; ++ int ppe_num_stats_entries; + struct airoha_npu *npu; ++ u32 index; ++ ++ ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); ++ if (ppe_num_stats_entries < 0) ++ return; + +- if (index >= PPE_STATS_NUM_ENTRIES) ++ if (airoha_ppe_foe_get_flow_stats_index(ppe, hash, &index)) ++ return; ++ ++ if (index >= ppe_num_stats_entries) + return; + + rcu_read_lock(); +@@ -1259,7 +1314,7 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth) + { + struct airoha_npu *npu = airoha_ppe_npu_get(eth); + struct airoha_ppe *ppe = eth->ppe; +- int err; ++ int err, ppe_num_stats_entries; + + if (IS_ERR(npu)) + return PTR_ERR(npu); +@@ -1268,9 +1323,10 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth) + if (err) + goto error_npu_put; + +- if (PPE_STATS_NUM_ENTRIES) { ++ ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); ++ if (ppe_num_stats_entries > 0) { + err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma, +- PPE_STATS_NUM_ENTRIES); ++ ppe_num_stats_entries); + if (err) + goto error_npu_put; + } +@@ -1407,8 +1463,8 @@ EXPORT_SYMBOL_GPL(airoha_ppe_put_dev); + + int airoha_ppe_init(struct airoha_eth *eth) + { ++ int foe_size, err, ppe_num_stats_entries; + struct airoha_ppe *ppe; +- int foe_size, err; + + ppe = devm_kzalloc(eth->dev, sizeof(*ppe), GFP_KERNEL); + if (!ppe) +@@ -1433,8 +1489,9 @@ int airoha_ppe_init(struct airoha_eth *eth) + if (!ppe->foe_flow) + return -ENOMEM; + +- foe_size = PPE_STATS_NUM_ENTRIES * sizeof(*ppe->foe_stats); +- if (foe_size) { ++ ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); ++ if (ppe_num_stats_entries > 0) { ++ foe_size = ppe_num_stats_entries * sizeof(*ppe->foe_stats); + ppe->foe_stats = dmam_alloc_coherent(eth->dev, foe_size, + &ppe->foe_stats_dma, + GFP_KERNEL); +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-an7583-soc-support.patch b/queue-6.18/net-airoha-add-an7583-soc-support.patch new file mode 100644 index 0000000000..3e103999fa --- /dev/null +++ b/queue-6.18/net-airoha-add-an7583-soc-support.patch @@ -0,0 +1,200 @@ +From 5d5fb4b1e5ea084939c6ab3537f87e1d6c40f21b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Oct 2025 11:06:22 +0200 +Subject: net: airoha: Add AN7583 SoC support + +From: Lorenzo Bianconi + +[ Upstream commit e4e5ce823bdd4601bd75ae7c206ae35e7c2fa60b ] + +Introduce support for AN7583 ethernet controller to airoha-eth dirver. + +Reviewed-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251017-an7583-eth-support-v3-13-f28319666667@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 3309965fe44c ("net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 68 ++++++++++++++++++++++-- + drivers/net/ethernet/airoha/airoha_eth.h | 11 ++++ + drivers/net/ethernet/airoha/airoha_ppe.c | 3 ++ + 3 files changed, 77 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 6e7f816cd7edb..55de295e3acf2 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1753,10 +1753,8 @@ static int airoha_dev_set_macaddr(struct net_device *dev, void *p) + + static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) + { +- u32 val, pse_port, chan = port->id == AIROHA_GDM3_IDX ? 4 : 0; + struct airoha_eth *eth = port->qdma->eth; +- /* XXX: handle XSI_USB_PORT and XSI_PCE1_PORT */ +- u32 nbq = port->id == AIROHA_GDM3_IDX ? 4 : 0; ++ u32 val, pse_port, chan, nbq; + int src_port; + + /* Forward the traffic to the proper GDM port */ +@@ -1768,6 +1766,8 @@ static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) + /* Enable GDM2 loopback */ + airoha_fe_wr(eth, REG_GDM_TXCHN_EN(2), 0xffffffff); + airoha_fe_wr(eth, REG_GDM_RXCHN_EN(2), 0xffff); ++ ++ chan = port->id == AIROHA_GDM3_IDX ? airoha_is_7581(eth) ? 4 : 3 : 0; + airoha_fe_rmw(eth, REG_GDM_LPBK_CFG(2), + LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK, + FIELD_PREP(LPBK_CHAN_MASK, chan) | +@@ -1782,6 +1782,8 @@ static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) + airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(2)); + airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(2)); + ++ /* XXX: handle XSI_USB_PORT and XSI_PCE1_PORT */ ++ nbq = port->id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0; + src_port = eth->soc->ops.get_src_port_id(port, nbq); + if (src_port < 0) + return src_port; +@@ -1795,7 +1797,7 @@ static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) + SP_CPORT_MASK(val), + FE_PSE_PORT_CDM2 << __ffs(SP_CPORT_MASK(val))); + +- if (port->id != AIROHA_GDM3_IDX) ++ if (port->id != AIROHA_GDM3_IDX && airoha_is_7581(eth)) + airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, + FC_ID_OF_SRC_PORT24_MASK, + FIELD_PREP(FC_ID_OF_SRC_PORT24_MASK, 2)); +@@ -1951,6 +1953,22 @@ static bool airoha_dev_tx_queue_busy(struct airoha_queue *q, u32 nr_frags) + return index >= tail; + } + ++static int airoha_get_fe_port(struct airoha_gdm_port *port) ++{ ++ struct airoha_qdma *qdma = port->qdma; ++ struct airoha_eth *eth = qdma->eth; ++ ++ switch (eth->soc->version) { ++ case 0x7583: ++ return port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3 ++ : port->id; ++ case 0x7581: ++ default: ++ return port->id == AIROHA_GDM4_IDX ? FE_PSE_PORT_GDM4 ++ : port->id; ++ } ++} ++ + static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + struct net_device *dev) + { +@@ -1991,7 +2009,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + } + } + +- fport = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id; ++ fport = airoha_get_fe_port(port); + msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) | + FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f); + +@@ -3164,6 +3182,35 @@ static int airoha_en7581_get_src_port_id(struct airoha_gdm_port *port, int nbq) + return -EINVAL; + } + ++static const char * const an7583_xsi_rsts_names[] = { ++ "xsi-mac", ++ "hsi0-mac", ++ "hsi1-mac", ++ "xfp-mac", ++}; ++ ++static int airoha_an7583_get_src_port_id(struct airoha_gdm_port *port, int nbq) ++{ ++ switch (port->id) { ++ case 3: ++ /* 7583 SoC supports eth serdes on GDM3 port */ ++ if (!nbq) ++ return HSGMII_LAN_7583_ETH_SRCPORT; ++ break; ++ case 4: ++ /* 7583 SoC supports PCIe and USB serdes on GDM4 port */ ++ if (!nbq) ++ return HSGMII_LAN_7583_PCIE_SRCPORT; ++ if (nbq == 1) ++ return HSGMII_LAN_7583_USB_SRCPORT; ++ break; ++ default: ++ break; ++ } ++ ++ return -EINVAL; ++} ++ + static const struct airoha_eth_soc_data en7581_soc_data = { + .version = 0x7581, + .xsi_rsts_names = en7581_xsi_rsts_names, +@@ -3174,8 +3221,19 @@ static const struct airoha_eth_soc_data en7581_soc_data = { + }, + }; + ++static const struct airoha_eth_soc_data an7583_soc_data = { ++ .version = 0x7583, ++ .xsi_rsts_names = an7583_xsi_rsts_names, ++ .num_xsi_rsts = ARRAY_SIZE(an7583_xsi_rsts_names), ++ .num_ppe = 1, ++ .ops = { ++ .get_src_port_id = airoha_an7583_get_src_port_id, ++ }, ++}; ++ + static const struct of_device_id of_airoha_match[] = { + { .compatible = "airoha,en7581-eth", .data = &en7581_soc_data }, ++ { .compatible = "airoha,an7583-eth", .data = &an7583_soc_data }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, of_airoha_match); +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 8a2c68781e94b..203e6ce29dbe0 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -73,6 +73,12 @@ enum { + HSGMII_LAN_7581_USB_SRCPORT, + }; + ++enum { ++ HSGMII_LAN_7583_ETH_SRCPORT = 0x16, ++ HSGMII_LAN_7583_PCIE_SRCPORT = 0x18, ++ HSGMII_LAN_7583_USB_SRCPORT, ++}; ++ + enum { + XSI_PCIE0_VIP_PORT_MASK = BIT(22), + XSI_PCIE1_VIP_PORT_MASK = BIT(23), +@@ -630,6 +636,11 @@ static inline bool airoha_is_7581(struct airoha_eth *eth) + return eth->soc->version == 0x7581; + } + ++static inline bool airoha_is_7583(struct airoha_eth *eth) ++{ ++ return eth->soc->version == 0x7583; ++} ++ + bool airoha_is_valid_gdm_port(struct airoha_eth *eth, + struct airoha_gdm_port *port); + +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 239c43248b4f4..6cd5febce6b59 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -37,6 +37,9 @@ static int airoha_ppe_get_num_stats_entries(struct airoha_ppe *ppe) + if (!IS_ENABLED(CONFIG_NET_AIROHA_FLOW_STATS)) + return -EOPNOTSUPP; + ++ if (airoha_is_7583(ppe->eth)) ++ return -EOPNOTSUPP; ++ + return PPE_STATS_NUM_ENTRIES; + } + +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-dma_rmb-and-read_once-in-airoha_qdma_.patch b/queue-6.18/net-airoha-add-dma_rmb-and-read_once-in-airoha_qdma_.patch new file mode 100644 index 0000000000..4fc3252bf7 --- /dev/null +++ b/queue-6.18/net-airoha-add-dma_rmb-and-read_once-in-airoha_qdma_.patch @@ -0,0 +1,88 @@ +From e3de3b66b3ef0115fefadbdb96ab8e9610948003 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 08:48:04 +0200 +Subject: net: airoha: Add dma_rmb() and READ_ONCE() in + airoha_qdma_rx_process() + +From: Lorenzo Bianconi + +[ Upstream commit 4ae0604a0673e11e2075b178387151fcad5111b5 ] + +Add missing dma_rmb() in airoha_qdma_rx_process routine to make sure the +DMA read operations are completed when the NIC reports the processing on +the current descriptor is done. Moreover, add missing READ_ONCE() in +airoha_qdma_rx_process() for DMA descriptor control fields in order to +avoid any compiler reordering. + +Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260407-airoha_qdma_rx_process-fix-reordering-v3-1-91c36e9da31f@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index bdf600fea9508..060865b98880e 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -596,7 +596,7 @@ static int airoha_qdma_fill_rx_queue(struct airoha_queue *q) + static int airoha_qdma_get_gdm_port(struct airoha_eth *eth, + struct airoha_qdma_desc *desc) + { +- u32 port, sport, msg1 = le32_to_cpu(desc->msg1); ++ u32 port, sport, msg1 = le32_to_cpu(READ_ONCE(desc->msg1)); + + sport = FIELD_GET(QDMA_ETH_RXMSG_SPORT_MASK, msg1); + switch (sport) { +@@ -624,21 +624,24 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) + while (done < budget) { + struct airoha_queue_entry *e = &q->entry[q->tail]; + struct airoha_qdma_desc *desc = &q->desc[q->tail]; +- u32 hash, reason, msg1 = le32_to_cpu(desc->msg1); +- struct page *page = virt_to_head_page(e->buf); +- u32 desc_ctrl = le32_to_cpu(desc->ctrl); ++ u32 hash, reason, msg1, desc_ctrl; + struct airoha_gdm_port *port; + int data_len, len, p; ++ struct page *page; + ++ desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); + if (!(desc_ctrl & QDMA_DESC_DONE_MASK)) + break; + ++ dma_rmb(); ++ + q->tail = (q->tail + 1) % q->ndesc; + q->queued--; + + dma_sync_single_for_cpu(eth->dev, e->dma_addr, + SKB_WITH_OVERHEAD(q->buf_size), dir); + ++ page = virt_to_head_page(e->buf); + len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl); + data_len = q->skb ? q->buf_size + : SKB_WITH_OVERHEAD(q->buf_size); +@@ -682,8 +685,8 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) + * DMA descriptor. Report DSA tag to the DSA stack + * via skb dst info. + */ +- u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG, +- le32_to_cpu(desc->msg0)); ++ u32 msg0 = le32_to_cpu(READ_ONCE(desc->msg0)); ++ u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG, msg0); + + if (sptag < ARRAY_SIZE(port->dsa_meta) && + port->dsa_meta[sptag]) +@@ -691,6 +694,7 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) + &port->dsa_meta[sptag]->dst); + } + ++ msg1 = le32_to_cpu(READ_ONCE(desc->msg1)); + hash = FIELD_GET(AIROHA_RXD4_FOE_ENTRY, msg1); + if (hash != AIROHA_RXD4_FOE_ENTRY) + skb_set_hash(q->skb, jhash_1word(hash, 0), +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-missing-bits-in-airoha_qdma_cleanup_t.patch b/queue-6.18/net-airoha-add-missing-bits-in-airoha_qdma_cleanup_t.patch new file mode 100644 index 0000000000..c012788631 --- /dev/null +++ b/queue-6.18/net-airoha-add-missing-bits-in-airoha_qdma_cleanup_t.patch @@ -0,0 +1,82 @@ +From c299572da3d9aa5cb9f6b2ebeb3e1481220c1e16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 08:36:32 +0200 +Subject: net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue() + +From: Lorenzo Bianconi + +[ Upstream commit 3309965fe44c00fd65af7cef5016e9e782c021a7 ] + +Similar to airoha_qdma_cleanup_rx_queue(), reset DMA TX descriptors in +airoha_qdma_cleanup_tx_queue routine. Moreover, reset TX_DMA_IDX to +TX_CPU_IDX to notify the NIC the QDMA TX ring is empty. + +Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260417-airoha_qdma_cleanup_tx_queue-fix-net-v4-2-e04bcc2c9642@kernel.org +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 32 ++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 9f6f517b5fdf9..f088f25128eb4 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1094,12 +1094,15 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma) + + static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) + { +- struct airoha_eth *eth = q->qdma->eth; +- int i; ++ struct airoha_qdma *qdma = q->qdma; ++ struct airoha_eth *eth = qdma->eth; ++ int i, qid = q - &qdma->q_tx[0]; ++ u16 index = 0; + + spin_lock_bh(&q->lock); + for (i = 0; i < q->ndesc; i++) { + struct airoha_queue_entry *e = &q->entry[i]; ++ struct airoha_qdma_desc *desc = &q->desc[i]; + + if (!e->dma_addr) + continue; +@@ -1110,8 +1113,33 @@ static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) + e->dma_addr = 0; + e->skb = NULL; + list_add_tail(&e->list, &q->tx_list); ++ ++ /* Reset DMA descriptor */ ++ WRITE_ONCE(desc->ctrl, 0); ++ WRITE_ONCE(desc->addr, 0); ++ WRITE_ONCE(desc->data, 0); ++ WRITE_ONCE(desc->msg0, 0); ++ WRITE_ONCE(desc->msg1, 0); ++ WRITE_ONCE(desc->msg2, 0); ++ + q->queued--; + } ++ ++ if (!list_empty(&q->tx_list)) { ++ struct airoha_queue_entry *e; ++ ++ e = list_first_entry(&q->tx_list, struct airoha_queue_entry, ++ list); ++ index = e - q->entry; ++ } ++ /* Set TX_DMA_IDX to TX_CPU_IDX to notify the hw the QDMA TX ring is ++ * empty. ++ */ ++ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, ++ FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); ++ airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK, ++ FIELD_PREP(TX_RING_DMA_IDX_MASK, index)); ++ + spin_unlock_bh(&q->lock); + } + +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-missing-ppe-configurations-in-airoha_.patch b/queue-6.18/net-airoha-add-missing-ppe-configurations-in-airoha_.patch new file mode 100644 index 0000000000..c6e10029c9 --- /dev/null +++ b/queue-6.18/net-airoha-add-missing-ppe-configurations-in-airoha_.patch @@ -0,0 +1,71 @@ +From 2b4008b4a3944c3350298d0c410d9230e069575d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 10:43:26 +0200 +Subject: net: airoha: Add missing PPE configurations in airoha_ppe_hw_init() + +From: Lorenzo Bianconi + +[ Upstream commit b9d8b856689d2b968495d79fe653d87fcb8ad98c ] + +Add the following PPE configuration in airoha_ppe_hw_init routine: +- 6RD hw offloading is currently not supported by Netfilter flowtable. + Disable explicitly PPE 6RD offloading in order to prevent PPE to learn + 6RD flows and eventually interrupt the traffic. +- Add missing PPE bind rate configuration for L3 and L2 traffic. + PPE bind rate configuration specifies the pps threshold to move a PPE + entry state from UNBIND to BIND. Without this configuration this value + is random. +- Set ageing thresholds to the values used in the vendor SDK in order to + improve connection stability under load and avoid packet loss caused by + fast aging. + +Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260412-airoha_ppe_hw_init-missing-bits-v1-1-06ac670819e3@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_ppe.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 4ed244557065d..81a7056e3510a 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -83,13 +83,13 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + airoha_fe_rmw(eth, REG_PPE_BND_AGE0(i), + PPE_BIND_AGE0_DELTA_NON_L4 | + PPE_BIND_AGE0_DELTA_UDP, +- FIELD_PREP(PPE_BIND_AGE0_DELTA_NON_L4, 1) | +- FIELD_PREP(PPE_BIND_AGE0_DELTA_UDP, 12)); ++ FIELD_PREP(PPE_BIND_AGE0_DELTA_NON_L4, 60) | ++ FIELD_PREP(PPE_BIND_AGE0_DELTA_UDP, 60)); + airoha_fe_rmw(eth, REG_PPE_BND_AGE1(i), + PPE_BIND_AGE1_DELTA_TCP_FIN | + PPE_BIND_AGE1_DELTA_TCP, + FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP_FIN, 1) | +- FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP, 7)); ++ FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP, 60)); + + airoha_fe_rmw(eth, REG_PPE_TB_HASH_CFG(i), + PPE_SRAM_TABLE_EN_MASK | +@@ -111,7 +111,15 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + FIELD_PREP(PPE_TB_CFG_SEARCH_MISS_MASK, 3) | + FIELD_PREP(PPE_TB_ENTRY_SIZE_MASK, 0)); + ++ airoha_fe_rmw(eth, REG_PPE_BIND_RATE(i), ++ PPE_BIND_RATE_L2B_BIND_MASK | ++ PPE_BIND_RATE_BIND_MASK, ++ FIELD_PREP(PPE_BIND_RATE_L2B_BIND_MASK, 0x1e) | ++ FIELD_PREP(PPE_BIND_RATE_BIND_MASK, 0x1e)); ++ + airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED); ++ airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i), ++ PPE_FLOW_CFG_IP6_6RD_MASK); + + for (p = 0; p < ARRAY_SIZE(eth->ports); p++) + airoha_fe_rmw(eth, REG_PPE_MTU(i, p), +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch b/queue-6.18/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch new file mode 100644 index 0000000000..3e10411b04 --- /dev/null +++ b/queue-6.18/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch @@ -0,0 +1,44 @@ +From b13fbc32eef236ceeb947981ed649c1ba78e69d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 20:26:56 +0200 +Subject: net: airoha: Add missing RX_CPU_IDX() configuration in + airoha_qdma_cleanup_rx_queue() + +From: Lorenzo Bianconi + +[ Upstream commit 656121b155030086b01cfce9bd31b0c925ee6860 ] + +When the descriptor index written in REG_RX_CPU_IDX() is equal to the one +stored in REG_RX_DMA_IDX(), the hw will stop since the QDMA RX ring is +empty. +Add missing REG_RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue +routine during QDMA RX ring cleanup. + +Fixes: 514aac359987 ("net: airoha: Add missing cleanup bits in airoha_qdma_cleanup_rx_queue()") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260408-airoha-cpu-idx-airoha_qdma_cleanup_rx_queue-v1-1-8efa64844308@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 132a32e9e633a..cbf21e15df6dd 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -844,6 +844,11 @@ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q) + } + + q->head = q->tail; ++ /* Set RX_DMA_IDX to RX_CPU_IDX to notify the hw the QDMA RX ring is ++ * empty. ++ */ ++ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, ++ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head)); + airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, + FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail)); + } +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-size-check-for-tx-napis-in-airoha_qdm.patch b/queue-6.18/net-airoha-add-size-check-for-tx-napis-in-airoha_qdm.patch new file mode 100644 index 0000000000..b34beb0c85 --- /dev/null +++ b/queue-6.18/net-airoha-add-size-check-for-tx-napis-in-airoha_qdm.patch @@ -0,0 +1,66 @@ +From 15d7ca07cfc8793cc59599ab763353f08e7d1d0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:07:48 +0200 +Subject: net: airoha: Add size check for TX NAPIs in airoha_qdma_cleanup() + +From: Lorenzo Bianconi + +[ Upstream commit 4b91cb65789b794bfc8d50554b8994f8e0f16309 ] + +If airoha_qdma_init routine fails before airoha_qdma_tx_irq_init() runs +successfully for all TX NAPIs, airoha_qdma_cleanup() will +unconditionally runs netif_napi_del() on TX NAPIs, triggering a NULL +pointer dereference. Fix the issue relying on q_tx_irq size value to +check if the TX NAPIs is properly initialized in airoha_qdma_cleanup(). +Moreover, run netif_napi_add_tx() just if irq_q queue is properly +allocated. + +Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260420-airoha_qdma_init_rx_queue-fix-v2-2-d99347e5c18d@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 8416451f4786a..865b854bd4afc 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1051,8 +1051,6 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q, + struct airoha_eth *eth = qdma->eth; + dma_addr_t dma_addr; + +- netif_napi_add_tx(eth->napi_dev, &irq_q->napi, +- airoha_qdma_tx_napi_poll); + irq_q->q = dmam_alloc_coherent(eth->dev, size * sizeof(u32), + &dma_addr, GFP_KERNEL); + if (!irq_q->q) +@@ -1062,6 +1060,9 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q, + irq_q->size = size; + irq_q->qdma = qdma; + ++ netif_napi_add_tx(eth->napi_dev, &irq_q->napi, ++ airoha_qdma_tx_napi_poll); ++ + airoha_qdma_wr(qdma, REG_TX_IRQ_BASE(id), dma_addr); + airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK, + FIELD_PREP(TX_IRQ_DEPTH_MASK, size)); +@@ -1481,8 +1482,12 @@ static void airoha_qdma_cleanup(struct airoha_qdma *qdma) + } + } + +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) ++ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) { ++ if (!qdma->q_tx_irq[i].size) ++ continue; ++ + netif_napi_del(&qdma->q_tx_irq[i].napi); ++ } + + for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { + if (!qdma->q_tx[i].ndesc) +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-add-the-capability-to-consume-out-of-orde.patch b/queue-6.18/net-airoha-add-the-capability-to-consume-out-of-orde.patch new file mode 100644 index 0000000000..eaa054bb4a --- /dev/null +++ b/queue-6.18/net-airoha-add-the-capability-to-consume-out-of-orde.patch @@ -0,0 +1,258 @@ +From 6aa2b1422141e7f44d93187da6602bbb466138fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Nov 2025 13:53:23 +0100 +Subject: net: airoha: Add the capability to consume out-of-order DMA tx + descriptors + +From: Lorenzo Bianconi + +[ Upstream commit 3f47e67dff1f7266e112c50313d63824f6f17102 ] + +EN7581 and AN7583 SoCs are capable of DMA mapping non-linear tx skbs on +non-consecutive DMA descriptors. This feature is useful when multiple +flows are queued on the same hw tx queue since it allows to fully utilize +the available tx DMA descriptors and to avoid the starvation of +high-priority flow we have in the current codebase due to head-of-line +blocking introduced by low-priority flows. + +Tested-by: Xuegang Lu +Reviewed-by: Jacob Keller +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251106-airoha-tx-linked-list-v2-1-0706d4a322bd@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 3309965fe44c ("net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 85 +++++++++++------------- + drivers/net/ethernet/airoha/airoha_eth.h | 7 +- + 2 files changed, 45 insertions(+), 47 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 55de295e3acf2..9f6f517b5fdf9 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -952,19 +952,13 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) + + dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, + DMA_TO_DEVICE); +- memset(e, 0, sizeof(*e)); ++ e->dma_addr = 0; ++ list_add_tail(&e->list, &q->tx_list); ++ + WRITE_ONCE(desc->msg0, 0); + WRITE_ONCE(desc->msg1, 0); + q->queued--; + +- /* completion ring can report out-of-order indexes if hw QoS +- * is enabled and packets with different priority are queued +- * to same DMA ring. Take into account possible out-of-order +- * reports incrementing DMA ring tail pointer +- */ +- while (q->tail != q->head && !q->entry[q->tail].dma_addr) +- q->tail = (q->tail + 1) % q->ndesc; +- + if (skb) { + u16 queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq; +@@ -1018,6 +1012,7 @@ static int airoha_qdma_init_tx_queue(struct airoha_queue *q, + q->ndesc = size; + q->qdma = qdma; + q->free_thr = 1 + MAX_SKB_FRAGS; ++ INIT_LIST_HEAD(&q->tx_list); + + q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry), + GFP_KERNEL); +@@ -1030,9 +1025,9 @@ static int airoha_qdma_init_tx_queue(struct airoha_queue *q, + return -ENOMEM; + + for (i = 0; i < q->ndesc; i++) { +- u32 val; ++ u32 val = FIELD_PREP(QDMA_DESC_DONE_MASK, 1); + +- val = FIELD_PREP(QDMA_DESC_DONE_MASK, 1); ++ list_add_tail(&q->entry[i].list, &q->tx_list); + WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val)); + } + +@@ -1042,9 +1037,9 @@ static int airoha_qdma_init_tx_queue(struct airoha_queue *q, + + airoha_qdma_wr(qdma, REG_TX_RING_BASE(qid), dma_addr); + airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, +- FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head)); ++ FIELD_PREP(TX_RING_CPU_IDX_MASK, 0)); + airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK, +- FIELD_PREP(TX_RING_DMA_IDX_MASK, q->head)); ++ FIELD_PREP(TX_RING_DMA_IDX_MASK, 0)); + + return 0; + } +@@ -1100,17 +1095,21 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma) + static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) + { + struct airoha_eth *eth = q->qdma->eth; ++ int i; + + spin_lock_bh(&q->lock); +- while (q->queued) { +- struct airoha_queue_entry *e = &q->entry[q->tail]; ++ for (i = 0; i < q->ndesc; i++) { ++ struct airoha_queue_entry *e = &q->entry[i]; ++ ++ if (!e->dma_addr) ++ continue; + + dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, + DMA_TO_DEVICE); + dev_kfree_skb_any(e->skb); ++ e->dma_addr = 0; + e->skb = NULL; +- +- q->tail = (q->tail + 1) % q->ndesc; ++ list_add_tail(&e->list, &q->tx_list); + q->queued--; + } + spin_unlock_bh(&q->lock); +@@ -1939,20 +1938,6 @@ static u32 airoha_get_dsa_tag(struct sk_buff *skb, struct net_device *dev) + #endif + } + +-static bool airoha_dev_tx_queue_busy(struct airoha_queue *q, u32 nr_frags) +-{ +- u32 tail = q->tail <= q->head ? q->tail + q->ndesc : q->tail; +- u32 index = q->head + nr_frags; +- +- /* completion napi can free out-of-order tx descriptors if hw QoS is +- * enabled and packets with different priorities are queued to the same +- * DMA ring. Take into account possible out-of-order reports checking +- * if the tx queue is full using circular buffer head/tail pointers +- * instead of the number of queued packets. +- */ +- return index >= tail; +-} +- + static int airoha_get_fe_port(struct airoha_gdm_port *port) + { + struct airoha_qdma *qdma = port->qdma; +@@ -1975,8 +1960,10 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + struct airoha_gdm_port *port = netdev_priv(dev); + struct airoha_qdma *qdma = port->qdma; + u32 nr_frags, tag, msg0, msg1, len; ++ struct airoha_queue_entry *e; + struct netdev_queue *txq; + struct airoha_queue *q; ++ LIST_HEAD(tx_list); + void *data; + int i, qid; + u16 index; +@@ -2022,7 +2009,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + txq = netdev_get_tx_queue(dev, qid); + nr_frags = 1 + skb_shinfo(skb)->nr_frags; + +- if (airoha_dev_tx_queue_busy(q, nr_frags)) { ++ if (q->queued + nr_frags >= q->ndesc) { + /* not enough space in the queue */ + netif_tx_stop_queue(txq); + q->txq_stopped = true; +@@ -2032,11 +2019,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + + len = skb_headlen(skb); + data = skb->data; +- index = q->head; ++ ++ e = list_first_entry(&q->tx_list, struct airoha_queue_entry, ++ list); ++ index = e - q->entry; + + for (i = 0; i < nr_frags; i++) { + struct airoha_qdma_desc *desc = &q->desc[index]; +- struct airoha_queue_entry *e = &q->entry[index]; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + dma_addr_t addr; + u32 val; +@@ -2046,7 +2035,14 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + if (unlikely(dma_mapping_error(dev->dev.parent, addr))) + goto error_unmap; + +- index = (index + 1) % q->ndesc; ++ list_move_tail(&e->list, &tx_list); ++ e->skb = i ? NULL : skb; ++ e->dma_addr = addr; ++ e->dma_len = len; ++ ++ e = list_first_entry(&q->tx_list, struct airoha_queue_entry, ++ list); ++ index = e - q->entry; + + val = FIELD_PREP(QDMA_DESC_LEN_MASK, len); + if (i < nr_frags - 1) +@@ -2059,15 +2055,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + WRITE_ONCE(desc->msg1, cpu_to_le32(msg1)); + WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff)); + +- e->skb = i ? NULL : skb; +- e->dma_addr = addr; +- e->dma_len = len; +- + data = skb_frag_address(frag); + len = skb_frag_size(frag); + } +- +- q->head = index; + q->queued += i; + + skb_tx_timestamp(skb); +@@ -2076,7 +2066,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + if (netif_xmit_stopped(txq) || !netdev_xmit_more()) + airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), + TX_RING_CPU_IDX_MASK, +- FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head)); ++ FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); + + if (q->ndesc - q->queued < q->free_thr) { + netif_tx_stop_queue(txq); +@@ -2088,10 +2078,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + + error_unmap: +- for (i--; i >= 0; i--) { +- index = (q->head + i) % q->ndesc; +- dma_unmap_single(dev->dev.parent, q->entry[index].dma_addr, +- q->entry[index].dma_len, DMA_TO_DEVICE); ++ while (!list_empty(&tx_list)) { ++ e = list_first_entry(&tx_list, struct airoha_queue_entry, ++ list); ++ dma_unmap_single(dev->dev.parent, e->dma_addr, e->dma_len, ++ DMA_TO_DEVICE); ++ e->dma_addr = 0; ++ list_move_tail(&e->list, &q->tx_list); + } + + spin_unlock_bh(&q->lock); +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 203e6ce29dbe0..28dfa35a3abed 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -169,7 +169,10 @@ enum trtcm_param { + struct airoha_queue_entry { + union { + void *buf; +- struct sk_buff *skb; ++ struct { ++ struct list_head list; ++ struct sk_buff *skb; ++ }; + }; + dma_addr_t dma_addr; + u16 dma_len; +@@ -194,6 +197,8 @@ struct airoha_queue { + struct napi_struct napi; + struct page_pool *page_pool; + struct sk_buff *skb; ++ ++ struct list_head tx_list; + }; + + struct airoha_tx_irq_queue { +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-do-not-read-uninitialized-fragment-addres.patch b/queue-6.18/net-airoha-do-not-read-uninitialized-fragment-addres.patch new file mode 100644 index 0000000000..2c2c435644 --- /dev/null +++ b/queue-6.18/net-airoha-do-not-read-uninitialized-fragment-addres.patch @@ -0,0 +1,74 @@ +From dcc692415698860ddb47d6eed4f36e75fec9ae19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 11:00:28 +0200 +Subject: net: airoha: Do not read uninitialized fragment address in + airoha_dev_xmit() + +From: Lorenzo Bianconi + +[ Upstream commit bde34e84edc8b5571fbde7e941e175a4293ee1eb ] + +The transmit loop in airoha_dev_xmit() reads fragment address and length +during its final iteration, when the loop index equals +skb_shinfo(skb)->nr_frags, at which point the fragment data is +uninitialized. While these values are never consumed, the read itself is +unsafe and may trigger a page fault. Fix this by avoiding the fragment +read on the last iteration. +Additionally, move the skb pointer from the first to the last used packet +descriptor, so that airoha_qdma_tx_napi_poll() defers freeing the skb +until the final descriptor is processed. + +Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260424-airoha-xmit-fix-read-frag-v1-1-fdc0a83c79e8@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 7d7f2bf6172a3..a69544e785a2a 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2024,8 +2024,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + struct netdev_queue *txq; + struct airoha_queue *q; + LIST_HEAD(tx_list); ++ int i = 0, qid; + void *data; +- int i, qid; + u16 index; + u8 fport; + +@@ -2084,7 +2084,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + list); + index = e - q->entry; + +- for (i = 0; i < nr_frags; i++) { ++ while (true) { + struct airoha_qdma_desc *desc = &q->desc[index]; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + dma_addr_t addr; +@@ -2096,7 +2096,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + goto error_unmap; + + list_move_tail(&e->list, &tx_list); +- e->skb = i ? NULL : skb; ++ e->skb = i == nr_frags - 1 ? skb : NULL; + e->dma_addr = addr; + e->dma_len = len; + +@@ -2115,6 +2115,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + WRITE_ONCE(desc->msg1, cpu_to_le32(msg1)); + WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff)); + ++ if (++i == nr_frags) ++ break; ++ + data = skb_frag_address(frag); + len = skb_frag_size(frag); + } +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-do-not-return-err-in-ndo_stop-callback.patch b/queue-6.18/net-airoha-do-not-return-err-in-ndo_stop-callback.patch new file mode 100644 index 0000000000..b971fc12b1 --- /dev/null +++ b/queue-6.18/net-airoha-do-not-return-err-in-ndo_stop-callback.patch @@ -0,0 +1,46 @@ +From 1b96efae9d8da3bbaec815c10ea43b72a770e931 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:53:16 +0200 +Subject: net: airoha: Do not return err in ndo_stop() callback + +From: Lorenzo Bianconi + +[ Upstream commit 4ca01292ea2f2363660610a65ba0285d7c3309ed ] + +Always complete the airoha_dev_stop() routine regardless of the +airoha_set_vip_for_gdm_port() return value, since errors from +ndo_stop() are ignored by the networking stack and the interface is +always considered down after the call. + +Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260428-airoha-ndo-stop-not-err-v1-1-674506d29a91@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 6742d0d9068df..81ecfc1a1094c 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1769,13 +1769,10 @@ static int airoha_dev_stop(struct net_device *dev) + { + struct airoha_gdm_port *port = netdev_priv(dev); + struct airoha_qdma *qdma = port->qdma; +- int i, err; ++ int i; + + netif_tx_disable(dev); +- err = airoha_set_vip_for_gdm_port(port, false); +- if (err) +- return err; +- ++ airoha_set_vip_for_gdm_port(port, false); + for (i = 0; i < dev->num_tx_queues; i++) + netdev_tx_reset_subqueue(dev, i); + +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-do-not-wake-all-netdev-tx-queues-in-airoh.patch b/queue-6.18/net-airoha-do-not-wake-all-netdev-tx-queues-in-airoh.patch new file mode 100644 index 0000000000..6a05af1150 --- /dev/null +++ b/queue-6.18/net-airoha-do-not-wake-all-netdev-tx-queues-in-airoh.patch @@ -0,0 +1,87 @@ +From 40c58f19a4aadaee7b29275d4d4a1c1113a1f599 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 10:53:33 +0200 +Subject: net: airoha: Do not wake all netdev TX queues in + airoha_qdma_wake_netdev_txqs() + +From: Lorenzo Bianconi + +[ Upstream commit e070aac63b42bf81f4dc565f9f841ff47e6c992f ] + +Do not wake every netdev TX queue across all ports sharing the QDMA +running netif_tx_wake_all_queues routine in airoha_qdma_wake_netdev_txqs() +but only the ones that are mapped the specific QDMA stopped hw TX queue. +This patch can potentially avoid waking already stopped netdev TX queues +that are mapped to a different QDMA hw TX queue. +Introduce airoha_qdma_get_txq utility routine. + +Fixes: b94769eb2f30 ("net: airoha: Fix possible TX queue stall in airoha_qdma_tx_napi_poll()") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260421-airoha-wake_netdev_txqs-optmization-v1-1-e0be95115d53@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 19 +++++++++++++++---- + drivers/net/ethernet/airoha/airoha_eth.h | 5 +++++ + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 9691b4134285f..7d7f2bf6172a3 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -878,13 +878,24 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) + { + struct airoha_qdma *qdma = q->qdma; + struct airoha_eth *eth = qdma->eth; +- int i; ++ int i, qid = q - &qdma->q_tx[0]; + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; ++ int j; ++ ++ if (!port) ++ continue; + +- if (port && port->qdma == qdma) +- netif_tx_wake_all_queues(port->dev); ++ if (port->qdma != qdma) ++ continue; ++ ++ for (j = 0; j < port->dev->num_tx_queues; j++) { ++ if (airoha_qdma_get_txq(qdma, j) != qid) ++ continue; ++ ++ netif_wake_subqueue(port->dev, j); ++ } + } + q->txq_stopped = false; + } +@@ -2018,7 +2029,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + u16 index; + u8 fport; + +- qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx); ++ qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb)); + tag = airoha_get_dsa_tag(skb, dev); + + msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK, +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index abd996492cb7f..33277cc577990 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -627,6 +627,11 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val); + #define airoha_qdma_clear(qdma, offset, val) \ + airoha_rmw((qdma)->regs, (offset), (val), 0) + ++static inline u16 airoha_qdma_get_txq(struct airoha_qdma *qdma, u16 qid) ++{ ++ return qid % ARRAY_SIZE(qdma->q_tx); ++} ++ + static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port) + { + /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-fix-bql-imbalance-in-tx-path.patch b/queue-6.18/net-airoha-fix-bql-imbalance-in-tx-path.patch new file mode 100644 index 0000000000..24fc206865 --- /dev/null +++ b/queue-6.18/net-airoha-fix-bql-imbalance-in-tx-path.patch @@ -0,0 +1,70 @@ +From 0df765e5ae6ff92b39db6326ffc23e576261820f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 08:35:11 +0200 +Subject: net: airoha: fix BQL imbalance in TX path + +From: Lorenzo Bianconi + +[ Upstream commit 2d9f5a118205da2683ffcec78b9347f1f01a820e ] + +Fix a possible BQL imbalance in airoha_dev_xmit(), where inflight +packets are accounted only for the AIROHA_NUM_TX_RING netdev TX +queues. The queue index is computed as: + + qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx) + txq = netdev_get_tx_queue(dev, qid); + +However, airoha_qdma_tx_napi_poll() accounts completions across all +netdev TX queues (num_tx_queues), leading to inconsistent BQL +accounting. + +Also reset all netdev TX queues in the ndo_stop callback. + +Fixes: 1d304174106c ("net: airoha: Implement BQL support") +Fixes: c9f947769b77 ("net: airoha: Reset BQL stopping the netdevice") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260421-airoha-fix-bql-v1-1-f135afe4275b@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: 4ca01292ea2f ("net: airoha: Do not return err in ndo_stop() callback") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index a69544e785a2a..6742d0d9068df 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -971,10 +971,9 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) + q->queued--; + + if (skb) { +- u16 queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq; + +- txq = netdev_get_tx_queue(skb->dev, queue); ++ txq = skb_get_tx_queue(skb->dev, skb); + netdev_tx_completed_queue(txq, 1, skb->len); + dev_kfree_skb_any(skb); + } +@@ -1777,7 +1776,7 @@ static int airoha_dev_stop(struct net_device *dev) + if (err) + return err; + +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) ++ for (i = 0; i < dev->num_tx_queues; i++) + netdev_tx_reset_subqueue(dev, i); + + if (atomic_dec_and_test(&qdma->users)) { +@@ -2066,7 +2065,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + + spin_lock_bh(&q->lock); + +- txq = netdev_get_tx_queue(dev, qid); ++ txq = skb_get_tx_queue(dev, skb); + nr_frags = 1 + skb_shinfo(skb)->nr_frags; + + if (q->queued + nr_frags >= q->ndesc) { +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-fix-fe_pse_buf_set-configuration-if-ppe2-.patch b/queue-6.18/net-airoha-fix-fe_pse_buf_set-configuration-if-ppe2-.patch new file mode 100644 index 0000000000..4fb8819c4b --- /dev/null +++ b/queue-6.18/net-airoha-fix-fe_pse_buf_set-configuration-if-ppe2-.patch @@ -0,0 +1,54 @@ +From 047f36b50c613cf9ed53cc295c85ed4d7959e06d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 12:20:09 +0200 +Subject: net: airoha: Fix FE_PSE_BUF_SET configuration if PPE2 is available + +From: Lorenzo Bianconi + +[ Upstream commit 02f72964395911e7a09bb2ea2fe6f79eda4ea2c2 ] + +airoha_fe_set routine is used to set specified bits to 1 in the selected +register. In the FE_PSE_BUF_SET case this can due to a overestimation of +the required buffers for I/O queues since we can miss to set some bits +of PSE_ALLRSV_MASK subfield to 0. Fix the issue relying on airoha_fe_rmw +routine instead. + +Fixes: 8e38e08f2c560 ("net: airoha: fix PSE memory configuration in airoha_fe_pse_ports_init()") +Tested-by: Xuegang Lu +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260408-airoha-reg_fe_pse_buf_set-v1-1-0c4fa8f4d1d9@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 677e40001f9f2..132a32e9e633a 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -293,16 +293,18 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth) + [FE_PSE_PORT_GDM4] = 2, + [FE_PSE_PORT_CDM5] = 2, + }; +- u32 all_rsv; + int q; + +- all_rsv = airoha_fe_get_pse_all_rsv(eth); + if (airoha_ppe_is_enabled(eth, 1)) { ++ u32 all_rsv; ++ + /* hw misses PPE2 oq rsv */ ++ all_rsv = airoha_fe_get_pse_all_rsv(eth); + all_rsv += PSE_RSV_PAGES * + pse_port_num_queues[FE_PSE_PORT_PPE2]; ++ airoha_fe_rmw(eth, REG_FE_PSE_BUF_SET, PSE_ALLRSV_MASK, ++ FIELD_PREP(PSE_ALLRSV_MASK, all_rsv)); + } +- airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv); + + /* CMD1 */ + for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_CDM1]; q++) +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-fix-possible-tx-queue-stall-in-airoha_qdm.patch b/queue-6.18/net-airoha-fix-possible-tx-queue-stall-in-airoha_qdm.patch new file mode 100644 index 0000000000..3ab22d85c6 --- /dev/null +++ b/queue-6.18/net-airoha-fix-possible-tx-queue-stall-in-airoha_qdm.patch @@ -0,0 +1,116 @@ +From b570106af781967e048f12ae1bd0967e3799b59a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 12:30:12 +0200 +Subject: net: airoha: Fix possible TX queue stall in + airoha_qdma_tx_napi_poll() + +From: Lorenzo Bianconi + +[ Upstream commit b94769eb2f30e61e86cd8551c084c34134290d89 ] + +Since multiple net_device TX queues can share the same hw QDMA TX queue, +there is no guarantee we have inflight packets queued in hw belonging to a +net_device TX queue stopped in the xmit path because hw QDMA TX queue +can be full. In this corner case the net_device TX queue will never be +re-activated. In order to avoid any potential net_device TX queue stall, +we need to wake all the net_device TX queues feeding the same hw QDMA TX +queue in airoha_qdma_tx_napi_poll routine. + +Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416-airoha-txq-potential-stall-v2-1-42c732074540@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 37 ++++++++++++++++++++---- + drivers/net/ethernet/airoha/airoha_eth.h | 1 + + 2 files changed, 33 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index cbf21e15df6dd..f8db324b141fe 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -874,6 +874,21 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma) + return 0; + } + ++static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) ++{ ++ struct airoha_qdma *qdma = q->qdma; ++ struct airoha_eth *eth = qdma->eth; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { ++ struct airoha_gdm_port *port = eth->ports[i]; ++ ++ if (port && port->qdma == qdma) ++ netif_tx_wake_all_queues(port->dev); ++ } ++ q->txq_stopped = false; ++} ++ + static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) + { + struct airoha_tx_irq_queue *irq_q; +@@ -956,12 +971,21 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) + + txq = netdev_get_tx_queue(skb->dev, queue); + netdev_tx_completed_queue(txq, 1, skb->len); +- if (netif_tx_queue_stopped(txq) && +- q->ndesc - q->queued >= q->free_thr) +- netif_tx_wake_queue(txq); +- + dev_kfree_skb_any(skb); + } ++ ++ if (q->txq_stopped && q->ndesc - q->queued >= q->free_thr) { ++ /* Since multiple net_device TX queues can share the ++ * same hw QDMA TX queue, there is no guarantee we have ++ * inflight packets queued in hw belonging to a ++ * net_device TX queue stopped in the xmit path. ++ * In order to avoid any potential net_device TX queue ++ * stall, we need to wake all the net_device TX queues ++ * feeding the same hw QDMA TX queue. ++ */ ++ airoha_qdma_wake_netdev_txqs(q); ++ } ++ + unlock: + spin_unlock_bh(&q->lock); + } +@@ -1978,6 +2002,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + if (airoha_dev_tx_queue_busy(q, nr_frags)) { + /* not enough space in the queue */ + netif_tx_stop_queue(txq); ++ q->txq_stopped = true; + spin_unlock_bh(&q->lock); + return NETDEV_TX_BUSY; + } +@@ -2030,8 +2055,10 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + TX_RING_CPU_IDX_MASK, + FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head)); + +- if (q->ndesc - q->queued < q->free_thr) ++ if (q->ndesc - q->queued < q->free_thr) { + netif_tx_stop_queue(txq); ++ q->txq_stopped = true; ++ } + + spin_unlock_bh(&q->lock); + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index d76f71558f8c2..054fe86d67bd1 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -181,6 +181,7 @@ struct airoha_queue { + int ndesc; + int free_thr; + int buf_size; ++ bool txq_stopped; + + struct napi_struct napi; + struct page_pool *page_pool; +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-fix-typo-in-function-name.patch b/queue-6.18/net-airoha-fix-typo-in-function-name.patch new file mode 100644 index 0000000000..2f8c55b07d --- /dev/null +++ b/queue-6.18/net-airoha-fix-typo-in-function-name.patch @@ -0,0 +1,68 @@ +From 679ec5e4403fcce04d5a1550abd1080ee0cff861 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:37:08 +0800 +Subject: net: airoha: fix typo in function name + +From: Zhengping Zhang + +[ Upstream commit aebf15e8eb09b01e99f043e9f5d423798aac9d32 ] + +Corrected the typo in the function name from + `airhoa_is_lan_gdm_port` to `airoha_is_lan_gdm_port`. This change ensures + consistency in the API naming convention. + +Signed-off-by: Zhengping Zhang +Reviewed-by: Simon Horman +Acked-by: Lorenzo Bianconi +Link: https://patch.msgid.link/tencent_E4FD5D6BC0131E617D848896F5F9FCED6E0A@qq.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: e070aac63b42 ("net: airoha: Do not wake all netdev TX queues in airoha_qdma_wake_netdev_txqs()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 2 +- + drivers/net/ethernet/airoha/airoha_eth.h | 2 +- + drivers/net/ethernet/airoha/airoha_ppe.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index fd612cc339e13..9691b4134285f 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -76,7 +76,7 @@ static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr) + struct airoha_eth *eth = port->qdma->eth; + u32 val, reg; + +- reg = airhoa_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H ++ reg = airoha_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H + : REG_FE_WAN_MAC_H; + val = (addr[0] << 16) | (addr[1] << 8) | addr[2]; + airoha_fe_wr(eth, reg, val); +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 28dfa35a3abed..abd996492cb7f 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -627,7 +627,7 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val); + #define airoha_qdma_clear(qdma, offset, val) \ + airoha_rmw((qdma)->regs, (offset), (val), 0) + +-static inline bool airhoa_is_lan_gdm_port(struct airoha_gdm_port *port) ++static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port) + { + /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. + * GDM{2,3,4} can be used as wan port connected to an external +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 6cd5febce6b59..005128717a45c 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -331,7 +331,7 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth, + /* For downlink traffic consume SRAM memory for hw + * forwarding descriptors queue. + */ +- if (airhoa_is_lan_gdm_port(port)) ++ if (airoha_is_lan_gdm_port(port)) + val |= AIROHA_FOE_IB2_FAST_PATH; + if (dsa_port >= 0) + val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-generalize-airoha_ppe2_is_enabled-routine.patch b/queue-6.18/net-airoha-generalize-airoha_ppe2_is_enabled-routine.patch new file mode 100644 index 0000000000..d9fc9a8bf1 --- /dev/null +++ b/queue-6.18/net-airoha-generalize-airoha_ppe2_is_enabled-routine.patch @@ -0,0 +1,162 @@ +From d80373eb51f64491e98af42e593cf06c4ac9f3cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Oct 2025 11:06:14 +0200 +Subject: net: airoha: Generalize airoha_ppe2_is_enabled routine + +From: Lorenzo Bianconi + +[ Upstream commit ef9449f080b61920cdc3d3106f8ffc2d9ba8b861 ] + +Rename airoha_ppe2_is_enabled() in airoha_ppe_is_enabled() and +generalize it in order to check if each PPE module is enabled. +Rely on airoha_ppe_is_enabled routine to properly initialize PPE for +AN7583 SoC since AN7583 does not support PPE2. + +Reviewed-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251017-an7583-eth-support-v3-5-f28319666667@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 02f729643959 ("net: airoha: Fix FE_PSE_BUF_SET configuration if PPE2 is available") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 32 ++++++++++++++++-------- + drivers/net/ethernet/airoha/airoha_eth.h | 1 + + drivers/net/ethernet/airoha/airoha_ppe.c | 17 +++++++------ + 3 files changed, 32 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 5162f2a689000..677e40001f9f2 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -297,8 +297,11 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth) + int q; + + all_rsv = airoha_fe_get_pse_all_rsv(eth); +- /* hw misses PPE2 oq rsv */ +- all_rsv += PSE_RSV_PAGES * pse_port_num_queues[FE_PSE_PORT_PPE2]; ++ if (airoha_ppe_is_enabled(eth, 1)) { ++ /* hw misses PPE2 oq rsv */ ++ all_rsv += PSE_RSV_PAGES * ++ pse_port_num_queues[FE_PSE_PORT_PPE2]; ++ } + airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv); + + /* CMD1 */ +@@ -335,13 +338,17 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth) + for (q = 4; q < pse_port_num_queues[FE_PSE_PORT_CDM4]; q++) + airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_CDM4, q, + PSE_QUEUE_RSV_PAGES); +- /* PPE2 */ +- for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_PPE2]; q++) { +- if (q < pse_port_num_queues[FE_PSE_PORT_PPE2] / 2) +- airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE2, q, +- PSE_QUEUE_RSV_PAGES); +- else +- airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE2, q, 0); ++ if (airoha_ppe_is_enabled(eth, 1)) { ++ /* PPE2 */ ++ for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_PPE2]; q++) { ++ if (q < pse_port_num_queues[FE_PSE_PORT_PPE2] / 2) ++ airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE2, ++ q, ++ PSE_QUEUE_RSV_PAGES); ++ else ++ airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE2, ++ q, 0); ++ } + } + /* GMD4 */ + for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_GDM4]; q++) +@@ -1781,8 +1788,11 @@ static int airoha_dev_init(struct net_device *dev) + airhoha_set_gdm2_loopback(port); + fallthrough; + case 2: +- pse_port = FE_PSE_PORT_PPE2; +- break; ++ if (airoha_ppe_is_enabled(eth, 1)) { ++ pse_port = FE_PSE_PORT_PPE2; ++ break; ++ } ++ fallthrough; + default: + pse_port = FE_PSE_PORT_PPE1; + break; +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 655bc6acd80f0..d76f71558f8c2 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -627,6 +627,7 @@ static inline bool airoha_is_7581(struct airoha_eth *eth) + bool airoha_is_valid_gdm_port(struct airoha_eth *eth, + struct airoha_gdm_port *port); + ++bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index); + void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb, + u16 hash, bool rx_wlan); + int airoha_ppe_setup_tc_block_cb(struct airoha_ppe_dev *dev, void *type_data); +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 117dfc21d6a81..4ed244557065d 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -50,9 +50,12 @@ static int airoha_ppe_get_total_num_stats_entries(struct airoha_ppe *ppe) + return num_stats; + } + +-static bool airoha_ppe2_is_enabled(struct airoha_eth *eth) ++bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index) + { +- return airoha_fe_rr(eth, REG_PPE_GLO_CFG(1)) & PPE_GLO_CFG_EN_MASK; ++ if (index >= eth->soc->num_ppe) ++ return false; ++ ++ return airoha_fe_rr(eth, REG_PPE_GLO_CFG(index)) & PPE_GLO_CFG_EN_MASK; + } + + static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe) +@@ -120,7 +123,7 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + AIROHA_MAX_MTU)); + } + +- if (airoha_ppe2_is_enabled(eth)) { ++ if (airoha_ppe_is_enabled(eth, 1)) { + sram_num_entries = PPE1_SRAM_NUM_ENTRIES; + sram_num_stats_entries = + airoha_ppe_get_num_stats_entries(ppe); +@@ -520,7 +523,7 @@ static int airoha_ppe_foe_get_flow_stats_index(struct airoha_ppe *ppe, + return ppe_num_stats_entries; + + *index = hash; +- if (airoha_ppe2_is_enabled(ppe->eth) && ++ if (airoha_ppe_is_enabled(ppe->eth, 1) && + hash >= ppe_num_stats_entries) + *index = *index - PPE_STATS_NUM_ENTRIES; + +@@ -615,7 +618,7 @@ airoha_ppe_foe_get_entry_locked(struct airoha_ppe *ppe, u32 hash) + u32 val; + int i; + +- ppe2 = airoha_ppe2_is_enabled(ppe->eth) && ++ ppe2 = airoha_ppe_is_enabled(ppe->eth, 1) && + hash >= PPE1_SRAM_NUM_ENTRIES; + airoha_fe_wr(ppe->eth, REG_PPE_RAM_CTRL(ppe2), + FIELD_PREP(PPE_SRAM_CTRL_ENTRY_MASK, hash) | +@@ -693,7 +696,7 @@ static int airoha_ppe_foe_commit_entry(struct airoha_ppe *ppe, + + if (hash < PPE_SRAM_NUM_ENTRIES) { + dma_addr_t addr = ppe->foe_dma + hash * sizeof(*hwe); +- bool ppe2 = airoha_ppe2_is_enabled(eth) && ++ bool ppe2 = airoha_ppe_is_enabled(eth, 1) && + hash >= PPE1_SRAM_NUM_ENTRIES; + + err = npu->ops.ppe_foe_commit_entry(npu, addr, sizeof(*hwe), +@@ -1288,7 +1291,7 @@ static int airoha_ppe_flush_sram_entries(struct airoha_ppe *ppe, + int i, sram_num_entries = PPE_SRAM_NUM_ENTRIES; + struct airoha_foe_entry *hwe = ppe->foe; + +- if (airoha_ppe2_is_enabled(ppe->eth)) ++ if (airoha_ppe_is_enabled(ppe->eth, 1)) + sram_num_entries = sram_num_entries / 2; + + for (i = 0; i < sram_num_entries; i++) +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch b/queue-6.18/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch new file mode 100644 index 0000000000..d176a8cbb4 --- /dev/null +++ b/queue-6.18/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch @@ -0,0 +1,71 @@ +From e46a271e55c0d1ec43df55fe32a9884141665b6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:07:47 +0200 +Subject: net: airoha: Move ndesc initialization at end of + airoha_qdma_init_rx_queue() + +From: Lorenzo Bianconi + +[ Upstream commit 379050947a1828826ad7ea50c95245a56929b35a ] + +If queue entry or DMA descriptor list allocation fails in +airoha_qdma_init_rx_queue routine, airoha_qdma_cleanup() will trigger a +NULL pointer dereference running netif_napi_del() for RX queue NAPIs +since netif_napi_add() has never been executed to this particular RX NAPI. +The issue is due to the early ndesc initialization in +airoha_qdma_init_rx_queue() since airoha_qdma_cleanup() relies on ndesc +value to check if the queue is properly initialized. Fix the issue moving +ndesc initialization at end of airoha_qdma_init_tx routine. +Move page_pool allocation after descriptor list allocation in order to +avoid memory leaks if desc allocation fails. + +Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260420-airoha_qdma_init_rx_queue-fix-v2-1-d99347e5c18d@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index f088f25128eb4..1d5447684ecab 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -776,14 +776,18 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, + dma_addr_t dma_addr; + + q->buf_size = PAGE_SIZE / 2; +- q->ndesc = ndesc; + q->qdma = qdma; + +- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry), ++ q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry), + GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + ++ q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc), ++ &dma_addr, GFP_KERNEL); ++ if (!q->desc) ++ return -ENOMEM; ++ + q->page_pool = page_pool_create(&pp_params); + if (IS_ERR(q->page_pool)) { + int err = PTR_ERR(q->page_pool); +@@ -792,11 +796,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, + return err; + } + +- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc), +- &dma_addr, GFP_KERNEL); +- if (!q->desc) +- return -ENOMEM; +- ++ q->ndesc = ndesc; + netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll); + + airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr); +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-ppe-dynamically-allocate-foe_check_time-a.patch b/queue-6.18/net-airoha-ppe-dynamically-allocate-foe_check_time-a.patch new file mode 100644 index 0000000000..ed4502ef95 --- /dev/null +++ b/queue-6.18/net-airoha-ppe-dynamically-allocate-foe_check_time-a.patch @@ -0,0 +1,56 @@ +From cea26bd1632ece4125f32174a3970cdd9f47bd94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Oct 2025 11:06:11 +0200 +Subject: net: airoha: ppe: Dynamically allocate foe_check_time array in + airoha_ppe struct + +From: Lorenzo Bianconi + +[ Upstream commit 6d5b601d52a27aafff555b480e538507901c672c ] + +This is a preliminary patch to properly enable PPE support for AN7583 +SoC. + +Reviewed-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251017-an7583-eth-support-v3-2-f28319666667@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 3309965fe44c ("net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.h | 2 +- + drivers/net/ethernet/airoha/airoha_ppe.c | 5 +++++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 054fe86d67bd1..9929c44d84702 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -548,7 +548,7 @@ struct airoha_ppe { + struct rhashtable l2_flows; + + struct hlist_head *foe_flow; +- u16 foe_check_time[PPE_NUM_ENTRIES]; ++ u16 *foe_check_time; + + struct airoha_foe_stats *foe_stats; + dma_addr_t foe_stats_dma; +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index e9994c794c703..072cc2dd50dda 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -1538,6 +1538,11 @@ int airoha_ppe_init(struct airoha_eth *eth) + return -ENOMEM; + } + ++ ppe->foe_check_time = devm_kzalloc(eth->dev, PPE_NUM_ENTRIES, ++ GFP_KERNEL); ++ if (!ppe->foe_check_time) ++ return -ENOMEM; ++ + err = rhashtable_init(ð->flow_table, &airoha_flow_table_params); + if (err) + return err; +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-ppe-move-ppe-memory-info-in-airoha_eth_so.patch b/queue-6.18/net-airoha-ppe-move-ppe-memory-info-in-airoha_eth_so.patch new file mode 100644 index 0000000000..5fc066585e --- /dev/null +++ b/queue-6.18/net-airoha-ppe-move-ppe-memory-info-in-airoha_eth_so.patch @@ -0,0 +1,373 @@ +From d84dca8ce0375fb97bfc804e3d1adc49f87f1d00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Oct 2025 11:06:15 +0200 +Subject: net: airoha: ppe: Move PPE memory info in airoha_eth_soc_data struct + +From: Lorenzo Bianconi + +[ Upstream commit 5bd1d1fd48ea9f8300b211540d946899c7f96480 ] + +AN7583 SoC runs a single PPE device while EN7581 runs two of them. +Moreover PPE SRAM in AN7583 SoC is reduced to 8K (while SRAM is 16K on +EN7581). Take into account PPE memory layout during PPE configuration. + +Reviewed-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251017-an7583-eth-support-v3-6-f28319666667@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 3309965fe44c ("net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.h | 10 +- + drivers/net/ethernet/airoha/airoha_ppe.c | 133 +++++++++--------- + .../net/ethernet/airoha/airoha_ppe_debugfs.c | 3 +- + 3 files changed, 70 insertions(+), 76 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 9929c44d84702..8d121d12dc120 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -47,14 +47,9 @@ + #define QDMA_METER_IDX(_n) ((_n) & 0xff) + #define QDMA_METER_GROUP(_n) (((_n) >> 8) & 0x3) + +-#define PPE_NUM 2 +-#define PPE1_SRAM_NUM_ENTRIES (8 * 1024) +-#define PPE_SRAM_NUM_ENTRIES (PPE_NUM * PPE1_SRAM_NUM_ENTRIES) +-#define PPE1_STATS_NUM_ENTRIES (4 * 1024) +-#define PPE_STATS_NUM_ENTRIES (PPE_NUM * PPE1_STATS_NUM_ENTRIES) ++#define PPE_SRAM_NUM_ENTRIES (8 * 1024) ++#define PPE_STATS_NUM_ENTRIES (4 * 1024) + #define PPE_DRAM_NUM_ENTRIES (16 * 1024) +-#define PPE_NUM_ENTRIES (PPE_SRAM_NUM_ENTRIES + PPE_DRAM_NUM_ENTRIES) +-#define PPE_HASH_MASK (PPE_NUM_ENTRIES - 1) + #define PPE_ENTRY_SIZE 80 + #define PPE_RAM_NUM_ENTRIES_SHIFT(_n) (__ffs((_n) >> 10)) + +@@ -635,6 +630,7 @@ int airoha_ppe_setup_tc_block_cb(struct airoha_ppe_dev *dev, void *type_data); + int airoha_ppe_init(struct airoha_eth *eth); + void airoha_ppe_deinit(struct airoha_eth *eth); + void airoha_ppe_init_upd_mem(struct airoha_gdm_port *port); ++u32 airoha_ppe_get_total_num_entries(struct airoha_ppe *ppe); + struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe, + u32 hash); + void airoha_ppe_foe_entry_get_stats(struct airoha_ppe *ppe, u32 hash, +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 072cc2dd50dda..239c43248b4f4 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -37,19 +37,36 @@ static int airoha_ppe_get_num_stats_entries(struct airoha_ppe *ppe) + if (!IS_ENABLED(CONFIG_NET_AIROHA_FLOW_STATS)) + return -EOPNOTSUPP; + +- return PPE1_STATS_NUM_ENTRIES; ++ return PPE_STATS_NUM_ENTRIES; + } + + static int airoha_ppe_get_total_num_stats_entries(struct airoha_ppe *ppe) + { + int num_stats = airoha_ppe_get_num_stats_entries(ppe); + +- if (num_stats > 0) +- num_stats = num_stats * PPE_NUM; ++ if (num_stats > 0) { ++ struct airoha_eth *eth = ppe->eth; ++ ++ num_stats = num_stats * eth->soc->num_ppe; ++ } + + return num_stats; + } + ++static u32 airoha_ppe_get_total_sram_num_entries(struct airoha_ppe *ppe) ++{ ++ struct airoha_eth *eth = ppe->eth; ++ ++ return PPE_SRAM_NUM_ENTRIES * eth->soc->num_ppe; ++} ++ ++u32 airoha_ppe_get_total_num_entries(struct airoha_ppe *ppe) ++{ ++ u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); ++ ++ return sram_num_entries + PPE_DRAM_NUM_ENTRIES; ++} ++ + bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index) + { + if (index >= eth->soc->num_ppe) +@@ -67,14 +84,22 @@ static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe) + + static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + { +- u32 sram_tb_size, sram_num_entries, dram_num_entries; ++ u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries; ++ u32 sram_tb_size, dram_num_entries; + struct airoha_eth *eth = ppe->eth; + int i, sram_num_stats_entries; + +- sram_tb_size = PPE_SRAM_NUM_ENTRIES * sizeof(struct airoha_foe_entry); ++ sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); ++ sram_tb_size = sram_num_entries * sizeof(struct airoha_foe_entry); + dram_num_entries = PPE_RAM_NUM_ENTRIES_SHIFT(PPE_DRAM_NUM_ENTRIES); + +- for (i = 0; i < PPE_NUM; i++) { ++ sram_num_stats_entries = airoha_ppe_get_num_stats_entries(ppe); ++ if (sram_num_stats_entries > 0) ++ sram_ppe_num_data_entries -= sram_num_stats_entries; ++ sram_ppe_num_data_entries = ++ PPE_RAM_NUM_ENTRIES_SHIFT(sram_ppe_num_data_entries); ++ ++ for (i = 0; i < eth->soc->num_ppe; i++) { + int p; + + airoha_fe_wr(eth, REG_PPE_TB_BASE(i), +@@ -106,10 +131,16 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + + airoha_fe_rmw(eth, REG_PPE_TB_CFG(i), + PPE_TB_CFG_SEARCH_MISS_MASK | ++ PPE_SRAM_TB_NUM_ENTRY_MASK | ++ PPE_DRAM_TB_NUM_ENTRY_MASK | + PPE_TB_CFG_KEEPALIVE_MASK | + PPE_TB_ENTRY_SIZE_MASK, + FIELD_PREP(PPE_TB_CFG_SEARCH_MISS_MASK, 3) | +- FIELD_PREP(PPE_TB_ENTRY_SIZE_MASK, 0)); ++ FIELD_PREP(PPE_TB_ENTRY_SIZE_MASK, 0) | ++ FIELD_PREP(PPE_SRAM_TB_NUM_ENTRY_MASK, ++ sram_ppe_num_data_entries) | ++ FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, ++ dram_num_entries)); + + airoha_fe_rmw(eth, REG_PPE_BIND_RATE(i), + PPE_BIND_RATE_L2B_BIND_MASK | +@@ -130,45 +161,6 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + FIELD_PREP(FP1_EGRESS_MTU_MASK, + AIROHA_MAX_MTU)); + } +- +- if (airoha_ppe_is_enabled(eth, 1)) { +- sram_num_entries = PPE1_SRAM_NUM_ENTRIES; +- sram_num_stats_entries = +- airoha_ppe_get_num_stats_entries(ppe); +- if (sram_num_stats_entries > 0) +- sram_num_entries -= sram_num_stats_entries; +- sram_num_entries = PPE_RAM_NUM_ENTRIES_SHIFT(sram_num_entries); +- +- airoha_fe_rmw(eth, REG_PPE_TB_CFG(0), +- PPE_SRAM_TB_NUM_ENTRY_MASK | +- PPE_DRAM_TB_NUM_ENTRY_MASK, +- FIELD_PREP(PPE_SRAM_TB_NUM_ENTRY_MASK, +- sram_num_entries) | +- FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, +- dram_num_entries)); +- airoha_fe_rmw(eth, REG_PPE_TB_CFG(1), +- PPE_SRAM_TB_NUM_ENTRY_MASK | +- PPE_DRAM_TB_NUM_ENTRY_MASK, +- FIELD_PREP(PPE_SRAM_TB_NUM_ENTRY_MASK, +- sram_num_entries) | +- FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, +- dram_num_entries)); +- } else { +- sram_num_entries = PPE_SRAM_NUM_ENTRIES; +- sram_num_stats_entries = +- airoha_ppe_get_total_num_stats_entries(ppe); +- if (sram_num_stats_entries > 0) +- sram_num_entries -= sram_num_stats_entries; +- sram_num_entries = PPE_RAM_NUM_ENTRIES_SHIFT(sram_num_entries); +- +- airoha_fe_rmw(eth, REG_PPE_TB_CFG(0), +- PPE_SRAM_TB_NUM_ENTRY_MASK | +- PPE_DRAM_TB_NUM_ENTRY_MASK, +- FIELD_PREP(PPE_SRAM_TB_NUM_ENTRY_MASK, +- sram_num_entries) | +- FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, +- dram_num_entries)); +- } + } + + static void airoha_ppe_flow_mangle_eth(const struct flow_action_entry *act, void *eth) +@@ -469,9 +461,11 @@ static int airoha_ppe_foe_entry_set_ipv6_tuple(struct airoha_foe_entry *hwe, + return 0; + } + +-static u32 airoha_ppe_foe_get_entry_hash(struct airoha_foe_entry *hwe) ++static u32 airoha_ppe_foe_get_entry_hash(struct airoha_ppe *ppe, ++ struct airoha_foe_entry *hwe) + { + int type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe->ib1); ++ u32 ppe_hash_mask = airoha_ppe_get_total_num_entries(ppe) - 1; + u32 hash, hv1, hv2, hv3; + + switch (type) { +@@ -509,14 +503,14 @@ static u32 airoha_ppe_foe_get_entry_hash(struct airoha_foe_entry *hwe) + case PPE_PKT_TYPE_IPV6_6RD: + default: + WARN_ON_ONCE(1); +- return PPE_HASH_MASK; ++ return ppe_hash_mask; + } + + hash = (hv1 & hv2) | ((~hv1) & hv3); + hash = (hash >> 24) | ((hash & 0xffffff) << 8); + hash ^= hv1 ^ hv2 ^ hv3; + hash ^= hash >> 16; +- hash &= PPE_NUM_ENTRIES - 1; ++ hash &= ppe_hash_mask; + + return hash; + } +@@ -617,9 +611,11 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe, + static struct airoha_foe_entry * + airoha_ppe_foe_get_entry_locked(struct airoha_ppe *ppe, u32 hash) + { ++ u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); ++ + lockdep_assert_held(&ppe_lock); + +- if (hash < PPE_SRAM_NUM_ENTRIES) { ++ if (hash < sram_num_entries) { + u32 *hwe = ppe->foe + hash * sizeof(struct airoha_foe_entry); + struct airoha_eth *eth = ppe->eth; + bool ppe2; +@@ -627,7 +623,7 @@ airoha_ppe_foe_get_entry_locked(struct airoha_ppe *ppe, u32 hash) + int i; + + ppe2 = airoha_ppe_is_enabled(ppe->eth, 1) && +- hash >= PPE1_SRAM_NUM_ENTRIES; ++ hash >= PPE_SRAM_NUM_ENTRIES; + airoha_fe_wr(ppe->eth, REG_PPE_RAM_CTRL(ppe2), + FIELD_PREP(PPE_SRAM_CTRL_ENTRY_MASK, hash) | + PPE_SRAM_CTRL_REQ_MASK); +@@ -678,6 +674,7 @@ static int airoha_ppe_foe_commit_entry(struct airoha_ppe *ppe, + struct airoha_foe_entry *e, + u32 hash, bool rx_wlan) + { ++ u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); + struct airoha_foe_entry *hwe = ppe->foe + hash * sizeof(*hwe); + u32 ts = airoha_ppe_get_timestamp(ppe); + struct airoha_eth *eth = ppe->eth; +@@ -702,10 +699,10 @@ static int airoha_ppe_foe_commit_entry(struct airoha_ppe *ppe, + if (!rx_wlan) + airoha_ppe_foe_flow_stats_update(ppe, npu, hwe, hash); + +- if (hash < PPE_SRAM_NUM_ENTRIES) { ++ if (hash < sram_num_entries) { + dma_addr_t addr = ppe->foe_dma + hash * sizeof(*hwe); + bool ppe2 = airoha_ppe_is_enabled(eth, 1) && +- hash >= PPE1_SRAM_NUM_ENTRIES; ++ hash >= PPE_SRAM_NUM_ENTRIES; + + err = npu->ops.ppe_foe_commit_entry(npu, addr, sizeof(*hwe), + hash, ppe2); +@@ -832,7 +829,7 @@ static void airoha_ppe_foe_insert_entry(struct airoha_ppe *ppe, + if (state == AIROHA_FOE_STATE_BIND) + goto unlock; + +- index = airoha_ppe_foe_get_entry_hash(hwe); ++ index = airoha_ppe_foe_get_entry_hash(ppe, hwe); + hlist_for_each_entry_safe(e, n, &ppe->foe_flow[index], list) { + if (e->type == FLOW_TYPE_L2_SUBFLOW) { + state = FIELD_GET(AIROHA_FOE_IB1_BIND_STATE, hwe->ib1); +@@ -892,7 +889,7 @@ static int airoha_ppe_foe_flow_commit_entry(struct airoha_ppe *ppe, + if (type == PPE_PKT_TYPE_BRIDGE) + return airoha_ppe_foe_l2_flow_commit_entry(ppe, e); + +- hash = airoha_ppe_foe_get_entry_hash(&e->data); ++ hash = airoha_ppe_foe_get_entry_hash(ppe, &e->data); + e->type = FLOW_TYPE_L4; + e->hash = 0xffff; + +@@ -1296,17 +1293,15 @@ static int airoha_ppe_flow_offload_cmd(struct airoha_eth *eth, + static int airoha_ppe_flush_sram_entries(struct airoha_ppe *ppe, + struct airoha_npu *npu) + { +- int i, sram_num_entries = PPE_SRAM_NUM_ENTRIES; ++ u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); + struct airoha_foe_entry *hwe = ppe->foe; ++ int i; + +- if (airoha_ppe_is_enabled(ppe->eth, 1)) +- sram_num_entries = sram_num_entries / 2; +- +- for (i = 0; i < sram_num_entries; i++) ++ for (i = 0; i < PPE_SRAM_NUM_ENTRIES; i++) + memset(&hwe[i], 0, sizeof(*hwe)); + + return npu->ops.ppe_flush_sram_entries(npu, ppe->foe_dma, +- PPE_SRAM_NUM_ENTRIES); ++ sram_num_entries); + } + + static struct airoha_npu *airoha_ppe_npu_get(struct airoha_eth *eth) +@@ -1410,9 +1405,10 @@ void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb, + u16 hash, bool rx_wlan) + { + struct airoha_ppe *ppe = dev->priv; ++ u32 ppe_hash_mask = airoha_ppe_get_total_num_entries(ppe) - 1; + u16 now, diff; + +- if (hash > PPE_HASH_MASK) ++ if (hash > ppe_hash_mask) + return; + + now = (u16)jiffies; +@@ -1503,6 +1499,7 @@ EXPORT_SYMBOL_GPL(airoha_ppe_put_dev); + int airoha_ppe_init(struct airoha_eth *eth) + { + int foe_size, err, ppe_num_stats_entries; ++ u32 ppe_num_entries; + struct airoha_ppe *ppe; + + ppe = devm_kzalloc(eth->dev, sizeof(*ppe), GFP_KERNEL); +@@ -1512,18 +1509,18 @@ int airoha_ppe_init(struct airoha_eth *eth) + ppe->dev.ops.setup_tc_block_cb = airoha_ppe_setup_tc_block_cb; + ppe->dev.ops.check_skb = airoha_ppe_check_skb; + ppe->dev.priv = ppe; ++ ppe->eth = eth; ++ eth->ppe = ppe; + +- foe_size = PPE_NUM_ENTRIES * sizeof(struct airoha_foe_entry); ++ ppe_num_entries = airoha_ppe_get_total_num_entries(ppe); ++ foe_size = ppe_num_entries * sizeof(struct airoha_foe_entry); + ppe->foe = dmam_alloc_coherent(eth->dev, foe_size, &ppe->foe_dma, + GFP_KERNEL); + if (!ppe->foe) + return -ENOMEM; + +- ppe->eth = eth; +- eth->ppe = ppe; +- + ppe->foe_flow = devm_kzalloc(eth->dev, +- PPE_NUM_ENTRIES * sizeof(*ppe->foe_flow), ++ ppe_num_entries * sizeof(*ppe->foe_flow), + GFP_KERNEL); + if (!ppe->foe_flow) + return -ENOMEM; +@@ -1538,7 +1535,7 @@ int airoha_ppe_init(struct airoha_eth *eth) + return -ENOMEM; + } + +- ppe->foe_check_time = devm_kzalloc(eth->dev, PPE_NUM_ENTRIES, ++ ppe->foe_check_time = devm_kzalloc(eth->dev, ppe_num_entries, + GFP_KERNEL); + if (!ppe->foe_check_time) + return -ENOMEM; +diff --git a/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c +index 05a756233f6a4..0112c41150bb0 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c +@@ -53,9 +53,10 @@ static int airoha_ppe_debugfs_foe_show(struct seq_file *m, void *private, + [AIROHA_FOE_STATE_FIN] = "FIN", + }; + struct airoha_ppe *ppe = m->private; ++ u32 ppe_num_entries = airoha_ppe_get_total_num_entries(ppe); + int i; + +- for (i = 0; i < PPE_NUM_ENTRIES; i++) { ++ for (i = 0; i < ppe_num_entries; i++) { + const char *state_str, *type_str = "UNKNOWN"; + void *src_addr = NULL, *dest_addr = NULL; + u16 *src_port = NULL, *dest_port = NULL; +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-refactor-src-port-configuration-in-airhoh.patch b/queue-6.18/net-airoha-refactor-src-port-configuration-in-airhoh.patch new file mode 100644 index 0000000000..5fbf18f650 --- /dev/null +++ b/queue-6.18/net-airoha-refactor-src-port-configuration-in-airhoh.patch @@ -0,0 +1,217 @@ +From 73a75dcb31c5453fbb45f0c7853574827594cbc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Oct 2025 11:06:20 +0200 +Subject: net: airoha: Refactor src port configuration in + airhoha_set_gdm2_loopback + +From: Lorenzo Bianconi + +[ Upstream commit 9d5b5219f672c80bed4d4e15f0068e648cdca43b ] + +AN7583 chipset relies on different definitions for source-port +identifier used for hw offloading. In order to support hw offloading +in AN7583 controller, refactor src port configuration in +airhoha_set_gdm2_loopback routine and introduce get_src_port_id +callback. + +Reviewed-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251017-an7583-eth-support-v3-11-f28319666667@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 3309965fe44c ("net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 82 ++++++++++++++++------- + drivers/net/ethernet/airoha/airoha_eth.h | 18 +++-- + drivers/net/ethernet/airoha/airoha_regs.h | 6 +- + 3 files changed, 73 insertions(+), 33 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index f8db324b141fe..6e7f816cd7edb 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1751,13 +1751,17 @@ static int airoha_dev_set_macaddr(struct net_device *dev, void *p) + return 0; + } + +-static void airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) ++static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) + { +- u32 pse_port = port->id == 3 ? FE_PSE_PORT_GDM3 : FE_PSE_PORT_GDM4; ++ u32 val, pse_port, chan = port->id == AIROHA_GDM3_IDX ? 4 : 0; + struct airoha_eth *eth = port->qdma->eth; +- u32 chan = port->id == 3 ? 4 : 0; ++ /* XXX: handle XSI_USB_PORT and XSI_PCE1_PORT */ ++ u32 nbq = port->id == AIROHA_GDM3_IDX ? 4 : 0; ++ int src_port; + + /* Forward the traffic to the proper GDM port */ ++ pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3 ++ : FE_PSE_PORT_GDM4; + airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(2), pse_port); + airoha_fe_clear(eth, REG_GDM_FWD_CFG(2), GDM_STRIP_CRC); + +@@ -1778,29 +1782,25 @@ static void airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) + airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(2)); + airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(2)); + +- if (port->id == 3) { +- /* FIXME: handle XSI_PCE1_PORT */ +- airoha_fe_rmw(eth, REG_FE_WAN_PORT, +- WAN1_EN_MASK | WAN1_MASK | WAN0_MASK, +- FIELD_PREP(WAN0_MASK, HSGMII_LAN_PCIE0_SRCPORT)); +- airoha_fe_rmw(eth, +- REG_SP_DFT_CPORT(HSGMII_LAN_PCIE0_SRCPORT >> 3), +- SP_CPORT_PCIE0_MASK, +- FIELD_PREP(SP_CPORT_PCIE0_MASK, +- FE_PSE_PORT_CDM2)); +- } else { +- /* FIXME: handle XSI_USB_PORT */ ++ src_port = eth->soc->ops.get_src_port_id(port, nbq); ++ if (src_port < 0) ++ return src_port; ++ ++ airoha_fe_rmw(eth, REG_FE_WAN_PORT, ++ WAN1_EN_MASK | WAN1_MASK | WAN0_MASK, ++ FIELD_PREP(WAN0_MASK, src_port)); ++ val = src_port & SP_CPORT_DFT_MASK; ++ airoha_fe_rmw(eth, ++ REG_SP_DFT_CPORT(src_port >> fls(SP_CPORT_DFT_MASK)), ++ SP_CPORT_MASK(val), ++ FE_PSE_PORT_CDM2 << __ffs(SP_CPORT_MASK(val))); ++ ++ if (port->id != AIROHA_GDM3_IDX) + airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, + FC_ID_OF_SRC_PORT24_MASK, + FIELD_PREP(FC_ID_OF_SRC_PORT24_MASK, 2)); +- airoha_fe_rmw(eth, REG_FE_WAN_PORT, +- WAN1_EN_MASK | WAN1_MASK | WAN0_MASK, +- FIELD_PREP(WAN0_MASK, HSGMII_LAN_ETH_SRCPORT)); +- airoha_fe_rmw(eth, +- REG_SP_DFT_CPORT(HSGMII_LAN_ETH_SRCPORT >> 3), +- SP_CPORT_ETH_MASK, +- FIELD_PREP(SP_CPORT_ETH_MASK, FE_PSE_PORT_CDM2)); +- } ++ ++ return 0; + } + + static int airoha_dev_init(struct net_device *dev) +@@ -1815,8 +1815,13 @@ static int airoha_dev_init(struct net_device *dev) + case 3: + case 4: + /* If GDM2 is active we can't enable loopback */ +- if (!eth->ports[1]) +- airhoha_set_gdm2_loopback(port); ++ if (!eth->ports[1]) { ++ int err; ++ ++ err = airhoha_set_gdm2_loopback(port); ++ if (err) ++ return err; ++ } + fallthrough; + case 2: + if (airoha_ppe_is_enabled(eth, 1)) { +@@ -3135,11 +3140,38 @@ static const char * const en7581_xsi_rsts_names[] = { + "xfp-mac", + }; + ++static int airoha_en7581_get_src_port_id(struct airoha_gdm_port *port, int nbq) ++{ ++ switch (port->id) { ++ case 3: ++ /* 7581 SoC supports PCIe serdes on GDM3 port */ ++ if (nbq == 4) ++ return HSGMII_LAN_7581_PCIE0_SRCPORT; ++ if (nbq == 5) ++ return HSGMII_LAN_7581_PCIE1_SRCPORT; ++ break; ++ case 4: ++ /* 7581 SoC supports eth and usb serdes on GDM4 port */ ++ if (!nbq) ++ return HSGMII_LAN_7581_ETH_SRCPORT; ++ if (nbq == 1) ++ return HSGMII_LAN_7581_USB_SRCPORT; ++ break; ++ default: ++ break; ++ } ++ ++ return -EINVAL; ++} ++ + static const struct airoha_eth_soc_data en7581_soc_data = { + .version = 0x7581, + .xsi_rsts_names = en7581_xsi_rsts_names, + .num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names), + .num_ppe = 2, ++ .ops = { ++ .get_src_port_id = airoha_en7581_get_src_port_id, ++ }, + }; + + static const struct of_device_id of_airoha_match[] = { +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 8d121d12dc120..8a2c68781e94b 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -67,10 +67,10 @@ enum { + }; + + enum { +- HSGMII_LAN_PCIE0_SRCPORT = 0x16, +- HSGMII_LAN_PCIE1_SRCPORT, +- HSGMII_LAN_ETH_SRCPORT, +- HSGMII_LAN_USB_SRCPORT, ++ HSGMII_LAN_7581_PCIE0_SRCPORT = 0x16, ++ HSGMII_LAN_7581_PCIE1_SRCPORT, ++ HSGMII_LAN_7581_ETH_SRCPORT, ++ HSGMII_LAN_7581_USB_SRCPORT, + }; + + enum { +@@ -99,6 +99,13 @@ enum { + CRSN_25 = 0x19, + }; + ++enum airoha_gdm_index { ++ AIROHA_GDM1_IDX = 1, ++ AIROHA_GDM2_IDX = 2, ++ AIROHA_GDM3_IDX = 3, ++ AIROHA_GDM4_IDX = 4, ++}; ++ + enum { + FE_PSE_PORT_CDM1, + FE_PSE_PORT_GDM1, +@@ -556,6 +563,9 @@ struct airoha_eth_soc_data { + const char * const *xsi_rsts_names; + int num_xsi_rsts; + int num_ppe; ++ struct { ++ int (*get_src_port_id)(struct airoha_gdm_port *port, int nbq); ++ } ops; + }; + + struct airoha_eth { +diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h +index 69c5a143db8c0..ebcce00d9bc6f 100644 +--- a/drivers/net/ethernet/airoha/airoha_regs.h ++++ b/drivers/net/ethernet/airoha/airoha_regs.h +@@ -383,10 +383,8 @@ + #define REG_MC_VLAN_DATA 0x2108 + + #define REG_SP_DFT_CPORT(_n) (0x20e0 + ((_n) << 2)) +-#define SP_CPORT_PCIE1_MASK GENMASK(31, 28) +-#define SP_CPORT_PCIE0_MASK GENMASK(27, 24) +-#define SP_CPORT_USB_MASK GENMASK(7, 4) +-#define SP_CPORT_ETH_MASK GENMASK(7, 4) ++#define SP_CPORT_DFT_MASK GENMASK(2, 0) ++#define SP_CPORT_MASK(_n) GENMASK(3 + ((_n) << 2), ((_n) << 2)) + + #define REG_SRC_PORT_FC_MAP6 0x2298 + #define FC_ID_OF_SRC_PORT27_MASK GENMASK(28, 24) +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-rework-the-code-flow-in-airoha_remove-and.patch b/queue-6.18/net-airoha-rework-the-code-flow-in-airoha_remove-and.patch new file mode 100644 index 0000000000..fe60d5d81e --- /dev/null +++ b/queue-6.18/net-airoha-rework-the-code-flow-in-airoha_remove-and.patch @@ -0,0 +1,176 @@ +From 9453dd286be55e9aab42becdb48d484ddc58bc93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 15:41:44 +0100 +Subject: net: airoha: Rework the code flow in airoha_remove() and in + airoha_probe() error path + +From: Lorenzo Bianconi + +[ Upstream commit b1c803d5c8167026791abfaed96fd3e6a1fcd750 ] + +As suggested by Simon in [0], rework the code flow in airoha_remove() +and in the airoha_probe() error path in order to rely on a more common +approach un-registering configured net-devices first and destroying the +hw resources at the end of the code. +Introduce airoha_qdma_cleanup routine to release QDMA resources. + +[0] https://lore.kernel.org/netdev/20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org/ + +Suggested-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260321-airoha-remove-rework-v2-1-16c7bade5fe5@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 4b91cb65789b ("net: airoha: Add size check for TX NAPIs in airoha_qdma_cleanup()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 76 ++++++++++++++---------- + 1 file changed, 44 insertions(+), 32 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 1d5447684ecab..8416451f4786a 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1465,6 +1465,33 @@ static int airoha_qdma_init(struct platform_device *pdev, + return airoha_qdma_hw_init(qdma); + } + ++static void airoha_qdma_cleanup(struct airoha_qdma *qdma) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { ++ if (!qdma->q_rx[i].ndesc) ++ continue; ++ ++ netif_napi_del(&qdma->q_rx[i].napi); ++ airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]); ++ if (qdma->q_rx[i].page_pool) { ++ page_pool_destroy(qdma->q_rx[i].page_pool); ++ qdma->q_rx[i].page_pool = NULL; ++ } ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) ++ netif_napi_del(&qdma->q_tx_irq[i].napi); ++ ++ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { ++ if (!qdma->q_tx[i].ndesc) ++ continue; ++ ++ airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); ++ } ++} ++ + static int airoha_hw_init(struct platform_device *pdev, + struct airoha_eth *eth) + { +@@ -1492,41 +1519,30 @@ static int airoha_hw_init(struct platform_device *pdev, + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) { + err = airoha_qdma_init(pdev, eth, ð->qdma[i]); + if (err) +- return err; ++ goto error; + } + + err = airoha_ppe_init(eth); + if (err) +- return err; ++ goto error; + + set_bit(DEV_STATE_INITIALIZED, ð->state); + + return 0; ++error: ++ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) ++ airoha_qdma_cleanup(ð->qdma[i]); ++ ++ return err; + } + +-static void airoha_hw_cleanup(struct airoha_qdma *qdma) ++static void airoha_hw_cleanup(struct airoha_eth *eth) + { + int i; + +- for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { +- if (!qdma->q_rx[i].ndesc) +- continue; +- +- netif_napi_del(&qdma->q_rx[i].napi); +- airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]); +- if (qdma->q_rx[i].page_pool) +- page_pool_destroy(qdma->q_rx[i].page_pool); +- } +- +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) +- netif_napi_del(&qdma->q_tx_irq[i].napi); +- +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { +- if (!qdma->q_tx[i].ndesc) +- continue; +- +- airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); +- } ++ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) ++ airoha_qdma_cleanup(ð->qdma[i]); ++ airoha_ppe_deinit(eth); + } + + static void airoha_qdma_start_napi(struct airoha_qdma *qdma) +@@ -3096,7 +3112,7 @@ static int airoha_probe(struct platform_device *pdev) + + err = airoha_hw_init(pdev, eth); + if (err) +- goto error_hw_cleanup; ++ goto error_netdev_free; + + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_qdma_start_napi(ð->qdma[i]); +@@ -3125,10 +3141,6 @@ static int airoha_probe(struct platform_device *pdev) + error_napi_stop: + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_qdma_stop_napi(ð->qdma[i]); +- airoha_ppe_deinit(eth); +-error_hw_cleanup: +- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) +- airoha_hw_cleanup(ð->qdma[i]); + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; +@@ -3140,6 +3152,8 @@ static int airoha_probe(struct platform_device *pdev) + unregister_netdev(port->dev); + airoha_metadata_dst_free(port); + } ++ airoha_hw_cleanup(eth); ++error_netdev_free: + free_netdev(eth->napi_dev); + platform_set_drvdata(pdev, NULL); + +@@ -3151,10 +3165,8 @@ static void airoha_remove(struct platform_device *pdev) + struct airoha_eth *eth = platform_get_drvdata(pdev); + int i; + +- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) { ++ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_qdma_stop_napi(ð->qdma[i]); +- airoha_hw_cleanup(ð->qdma[i]); +- } + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; +@@ -3165,9 +3177,9 @@ static void airoha_remove(struct platform_device *pdev) + unregister_netdev(port->dev); + airoha_metadata_dst_free(port); + } +- free_netdev(eth->napi_dev); ++ airoha_hw_cleanup(eth); + +- airoha_ppe_deinit(eth); ++ free_netdev(eth->napi_dev); + platform_set_drvdata(pdev, NULL); + } + +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-stop-net_device-tx-queue-before-updating-.patch b/queue-6.18/net-airoha-stop-net_device-tx-queue-before-updating-.patch new file mode 100644 index 0000000000..261335687e --- /dev/null +++ b/queue-6.18/net-airoha-stop-net_device-tx-queue-before-updating-.patch @@ -0,0 +1,55 @@ +From da68cf012d9a4e1bfd71861b21da4b8b33fa41a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 08:43:07 +0200 +Subject: net: airoha: stop net_device TX queue before updating CPU index + +From: Lorenzo Bianconi + +[ Upstream commit 3854de7b38be742cf7558476956d12414cb274f2 ] + +Currently, airoha_eth driver updates the CPU index register prior of +verifying whether the number of free descriptors has fallen below the +threshold. +Move net_device TX queue length check before updating the TX CPU index +in order to update TX CPU index even if there are more packets to be +transmitted but the net_device TX queue is going to be stopped +accounting the inflight packets. + +Fixes: 1d304174106c ("net: airoha: Implement BQL support") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260421-airoha-xmit-stop-condition-v1-1-e670d6a48467@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 865b854bd4afc..fd612cc339e13 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2111,17 +2111,16 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + + skb_tx_timestamp(skb); + netdev_tx_sent_queue(txq, skb->len); ++ if (q->ndesc - q->queued < q->free_thr) { ++ netif_tx_stop_queue(txq); ++ q->txq_stopped = true; ++ } + + if (netif_xmit_stopped(txq) || !netdev_xmit_more()) + airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), + TX_RING_CPU_IDX_MASK, + FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); + +- if (q->ndesc - q->queued < q->free_thr) { +- netif_tx_stop_queue(txq); +- q->txq_stopped = true; +- } +- + spin_unlock_bh(&q->lock); + + return NETDEV_TX_OK; +-- +2.53.0 + diff --git a/queue-6.18/net-airoha-wait-for-npu-ppe-configuration-to-complet.patch b/queue-6.18/net-airoha-wait-for-npu-ppe-configuration-to-complet.patch new file mode 100644 index 0000000000..7928c70f61 --- /dev/null +++ b/queue-6.18/net-airoha-wait-for-npu-ppe-configuration-to-complet.patch @@ -0,0 +1,73 @@ +From 53ce914ff3ff160eb8313e9e42e58e8ad8f88861 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:08:52 +0200 +Subject: net: airoha: Wait for NPU PPE configuration to complete in + airoha_ppe_offload_setup() + +From: Lorenzo Bianconi + +[ Upstream commit f3206328bb52c2787197d80d7cbd687946047d5f ] + +In order to properly enable flowtable hw offloading, poll +REG_PPE_FLOW_CFG register in airoha_ppe_offload_setup routine and +wait for NPU PPE configuration triggered by ppe_init callback to complete +before running airoha_ppe_hw_init(). + +Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260414-airoha-wait-for-npu-config-offload-setup-v2-1-5a9bf6d43aee@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_ppe.c | 28 ++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 81a7056e3510a..e9994c794c703 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -1321,6 +1321,29 @@ static struct airoha_npu *airoha_ppe_npu_get(struct airoha_eth *eth) + return npu; + } + ++static int airoha_ppe_wait_for_npu_init(struct airoha_eth *eth) ++{ ++ int err; ++ u32 val; ++ ++ /* PPE_FLOW_CFG default register value is 0. Since we reset FE ++ * during the device probe we can just check the configured value ++ * is not 0 here. ++ */ ++ err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC, ++ 100 * USEC_PER_MSEC, false, eth, ++ REG_PPE_PPE_FLOW_CFG(0)); ++ if (err) ++ return err; ++ ++ if (airoha_ppe_is_enabled(eth, 1)) ++ err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC, ++ 100 * USEC_PER_MSEC, false, eth, ++ REG_PPE_PPE_FLOW_CFG(1)); ++ ++ return err; ++} ++ + static int airoha_ppe_offload_setup(struct airoha_eth *eth) + { + struct airoha_npu *npu = airoha_ppe_npu_get(eth); +@@ -1334,6 +1357,11 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth) + if (err) + goto error_npu_put; + ++ /* Wait for NPU PPE configuration to complete */ ++ err = airoha_ppe_wait_for_npu_init(eth); ++ if (err) ++ goto error_npu_put; ++ + ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); + if (ppe_num_stats_entries > 0) { + err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma, +-- +2.53.0 + diff --git a/queue-6.18/net-bcmgenet-fix-leaking-free_bds.patch b/queue-6.18/net-bcmgenet-fix-leaking-free_bds.patch new file mode 100644 index 0000000000..e3eca135e0 --- /dev/null +++ b/queue-6.18/net-bcmgenet-fix-leaking-free_bds.patch @@ -0,0 +1,49 @@ +From 15162157def43c9acd982801360c33e67be41ae4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:55 -0700 +Subject: net: bcmgenet: fix leaking free_bds + +From: Justin Chen + +[ Upstream commit 3f3168300efb839028328d720ab3962f91d6a0d0 ] + +While reclaiming the tx queue we fast forward the write pointer to +drop any data in flight. These dropped frames are not added back +to the pool of free bds. We also need to tell the netdev that we +are dropping said data. + +Fixes: f1bacae8b655 ("net: bcmgenet: support reclaiming unsent Tx packets") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-3-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 1791523b83383..7d4d394c6ab1e 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1981,6 +1981,7 @@ static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, + drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK; + released += drop; + ring->prod_index = ring->c_index & DMA_C_INDEX_MASK; ++ ring->free_bds += drop; + while (drop--) { + cb_ptr = bcmgenet_put_txcb(priv, ring); + skb = cb_ptr->skb; +@@ -1992,6 +1993,7 @@ static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, + } + if (skb) + dev_consume_skb_any(skb); ++ netdev_tx_reset_queue(netdev_get_tx_queue(dev, ring->index)); + bcmgenet_tdma_ring_writel(priv, ring->index, + ring->prod_index, TDMA_PROD_INDEX); + wr_ptr = ring->write_ptr * WORDS_PER_BD(priv); +-- +2.53.0 + diff --git a/queue-6.18/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch b/queue-6.18/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch new file mode 100644 index 0000000000..6ecd342a84 --- /dev/null +++ b/queue-6.18/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch @@ -0,0 +1,50 @@ +From 09cd8203a7dea0e9bcf769605c4bf0bf7c1d0467 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:54 -0700 +Subject: net: bcmgenet: fix off-by-one in bcmgenet_put_txcb + +From: Justin Chen + +[ Upstream commit 57f3f53d2c9c5a9e133596e2f7bc1c50688a6d38 ] + +The write_ptr points to the next open tx_cb. We want to return the +tx_cb that gets rewinded, so we must rewind the pointer first then +return the tx_cb that it points to. That way the txcb can be correctly +cleaned up. + +Fixes: 876dbadd53a7 ("net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()") +Signed-off-by: Justin Chen +Reviewed-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-2-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index e142939d87cbe..1791523b83383 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1815,15 +1815,15 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + { + struct enet_cb *tx_cb_ptr; + +- tx_cb_ptr = ring->cbs; +- tx_cb_ptr += ring->write_ptr - ring->cb_ptr; +- + /* Rewinding local write pointer */ + if (ring->write_ptr == ring->cb_ptr) + ring->write_ptr = ring->end_ptr; + else + ring->write_ptr--; + ++ tx_cb_ptr = ring->cbs; ++ tx_cb_ptr += ring->write_ptr - ring->cb_ptr; ++ + return tx_cb_ptr; + } + +-- +2.53.0 + diff --git a/queue-6.18/net-bcmgenet-fix-racing-timeout-handler.patch b/queue-6.18/net-bcmgenet-fix-racing-timeout-handler.patch new file mode 100644 index 0000000000..8499ac08a7 --- /dev/null +++ b/queue-6.18/net-bcmgenet-fix-racing-timeout-handler.patch @@ -0,0 +1,70 @@ +From 5088270187d9bb74f2e35b58449280e8aaf4088a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:56 -0700 +Subject: net: bcmgenet: fix racing timeout handler + +From: Justin Chen + +[ Upstream commit 5393b2b5bee2ac51a0043dc7f4ac3475f053d08d ] + +The bcmgenet_timeout handler tries to take down all tx queues when +a single queue times out. This is over zealous and causes many race +conditions with queues that are still chugging along. Instead lets +only restart the timed out queue. + +Fixes: 13ea657806cf ("net: bcmgenet: improve TX timeout") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-4-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 22 ++++++++----------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 7d4d394c6ab1e..63cdf6d9d0772 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -3475,27 +3475,23 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 int1_enable = 0; +- unsigned int q; ++ struct bcmgenet_tx_ring *ring = &priv->tx_rings[txqueue]; ++ struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue); + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- bcmgenet_dump_tx_queue(&priv->tx_rings[q]); +- +- bcmgenet_tx_reclaim_all(dev); ++ bcmgenet_dump_tx_queue(ring); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- int1_enable |= (1 << q); ++ bcmgenet_tx_reclaim(dev, ring, true); + +- /* Re-enable TX interrupts if disabled */ +- bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); ++ /* Re-enable the TX interrupt for this ring */ ++ bcmgenet_intrl2_1_writel(priv, 1 << txqueue, INTRL2_CPU_MASK_CLEAR); + +- netif_trans_update(dev); ++ txq_trans_cond_update(txq); + +- BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors); ++ BCMGENET_STATS64_INC((&ring->stats64), errors); + +- netif_tx_wake_all_queues(dev); ++ netif_tx_wake_queue(txq); + } + + #define MAX_MDF_FILTER 17 +-- +2.53.0 + diff --git a/queue-6.18/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch b/queue-6.18/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch new file mode 100644 index 0000000000..63f8771004 --- /dev/null +++ b/queue-6.18/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch @@ -0,0 +1,66 @@ +From 69fdeae296755210ade929cdb8dec132b1ea1e3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 08:55:19 +0800 +Subject: net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master + +From: Jiayuan Chen + +[ Upstream commit 1921f91298d1388a0bb9db8f83800c998b649cb3 ] + +syzkaller reported a kernel panic in bond_rr_gen_slave_id() reached via +xdp_master_redirect(). Full decoded trace: + + https://syzkaller.appspot.com/bug?extid=80e046b8da2820b6ba73 + +bond_rr_gen_slave_id() dereferences bond->rr_tx_counter, a per-CPU +counter that bonding only allocates in bond_open() when the mode is +round-robin. If the bond device was never brought up, rr_tx_counter +stays NULL. + +The XDP redirect path can still reach that code on a bond that was +never opened: bpf_master_redirect_enabled_key is a global static key, +so as soon as any bond device has native XDP attached, the +XDP_TX -> xdp_master_redirect() interception is enabled for every +slave system-wide. The path xdp_master_redirect() -> +bond_xdp_get_xmit_slave() -> bond_xdp_xmit_roundrobin_slave_get() -> +bond_rr_gen_slave_id() then runs against a bond that has no +rr_tx_counter and crashes. + +Fix this in the generic xdp_master_redirect() by refusing to call into +the master's ->ndo_xdp_get_xmit_slave() when the master device is not +up. IFF_UP is only set after ->ndo_open() has successfully returned, +so this reliably excludes masters whose XDP state has not been fully +initialized. Drop the frame with XDP_ABORTED so the exception is +visible via trace_xdp_exception() rather than silently falling through. +This is not specific to bonding: any current or future master that +defers XDP state allocation to ->ndo_open() is protected. + +Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave device") +Reported-by: syzbot+80e046b8da2820b6ba73@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/698f84c6.a70a0220.2c38d7.00cc.GAE@google.com/T/ +Suggested-by: Daniel Borkmann +Acked-by: Daniel Borkmann +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260411005524.201200-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 3d4bf4d2a1a4b..7fc01474c3781 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4385,6 +4385,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) + struct net_device *master, *slave; + + master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); ++ if (unlikely(!(master->flags & IFF_UP))) ++ return XDP_ABORTED; + slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); + if (slave && slave != xdp->rxq->dev) { + /* The target device is different from the receiving device, so +-- +2.53.0 + diff --git a/queue-6.18/net-dsa-append-ethtool-counters-of-all-hidden-ports-.patch b/queue-6.18/net-dsa-append-ethtool-counters-of-all-hidden-ports-.patch new file mode 100644 index 0000000000..1b0587a9e8 --- /dev/null +++ b/queue-6.18/net-dsa-append-ethtool-counters-of-all-hidden-ports-.patch @@ -0,0 +1,222 @@ +From 127c6f025a4381b593de794e734228a8936f34eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 22 Nov 2025 13:23:11 +0200 +Subject: net: dsa: append ethtool counters of all hidden ports to conduit + +From: Vladimir Oltean + +[ Upstream commit f647ed2ca78ec4efcc436915b441da9de0974926 ] + +Currently there is no way to see packet counters on cascade ports, and +no clarity on how the API for that would look like. + +Because it's something that is currently needed, just extend the hack +where ethtool -S on the conduit interface dumps CPU port counters, and +also use it to dump counters of cascade ports. + +Note that the "pXX_" naming convention changes to "sXX_pYY", to +distinguish between ports having the same index but belonging to +different switches. This has a slight chance of causing regressions to +existing tooling: + +- grepping for "p04_counter_name" still works, but might return more + than one string now +- grepping for " p04_counter_name" no longer works + +Signed-off-by: Vladimir Oltean +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251122112311.138784-4-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0f99e0c3e19b ("net: dsa: remove redundant netdev_lock_ops() from conduit ethtool ops") +Signed-off-by: Sasha Levin +--- + net/dsa/conduit.c | 126 ++++++++++++++++++++++++++++++++++------------ + 1 file changed, 93 insertions(+), 33 deletions(-) + +diff --git a/net/dsa/conduit.c b/net/dsa/conduit.c +index c210e31296558..a1b044467bd6f 100644 +--- a/net/dsa/conduit.c ++++ b/net/dsa/conduit.c +@@ -87,25 +87,51 @@ static void dsa_conduit_get_regs(struct net_device *dev, + } + } + ++static ssize_t dsa_conduit_append_port_stats(struct dsa_switch *ds, int port, ++ u64 *data, size_t start) ++{ ++ int count; ++ ++ if (!ds->ops->get_sset_count) ++ return 0; ++ ++ count = ds->ops->get_sset_count(ds, port, ETH_SS_STATS); ++ if (count < 0) ++ return count; ++ ++ if (ds->ops->get_ethtool_stats) ++ ds->ops->get_ethtool_stats(ds, port, data + start); ++ ++ return count; ++} ++ + static void dsa_conduit_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + u64 *data) + { +- struct dsa_port *cpu_dp = dev->dsa_ptr; ++ struct dsa_port *dp, *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; +- struct dsa_switch *ds = cpu_dp->ds; +- int port = cpu_dp->index; +- int count = 0; ++ struct dsa_switch_tree *dst = cpu_dp->dst; ++ int count, mcount = 0; + + if (ops && ops->get_sset_count && ops->get_ethtool_stats) { + netdev_lock_ops(dev); +- count = ops->get_sset_count(dev, ETH_SS_STATS); ++ mcount = ops->get_sset_count(dev, ETH_SS_STATS); + ops->get_ethtool_stats(dev, stats, data); + netdev_unlock_ops(dev); + } + +- if (ds->ops->get_ethtool_stats) +- ds->ops->get_ethtool_stats(ds, port, data + count); ++ list_for_each_entry(dp, &dst->ports, list) { ++ if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp)) ++ continue; ++ ++ count = dsa_conduit_append_port_stats(dp->ds, dp->index, ++ data, mcount); ++ if (count < 0) ++ return; ++ ++ mcount += count; ++ } + } + + static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev, +@@ -136,11 +162,18 @@ static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev, + ds->ops->get_ethtool_phy_stats(ds, port, data + count); + } + ++static void dsa_conduit_append_port_sset_count(struct dsa_switch *ds, int port, ++ int sset, int *count) ++{ ++ if (ds->ops->get_sset_count) ++ *count += ds->ops->get_sset_count(ds, port, sset); ++} ++ + static int dsa_conduit_get_sset_count(struct net_device *dev, int sset) + { +- struct dsa_port *cpu_dp = dev->dsa_ptr; ++ struct dsa_port *dp, *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; +- struct dsa_switch *ds = cpu_dp->ds; ++ struct dsa_switch_tree *dst = cpu_dp->dst; + int count = 0; + + netdev_lock_ops(dev); +@@ -154,26 +187,57 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset) + if (count < 0) + count = 0; + +- if (ds->ops->get_sset_count) +- count += ds->ops->get_sset_count(ds, cpu_dp->index, sset); ++ list_for_each_entry(dp, &dst->ports, list) { ++ if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp)) ++ continue; ++ ++ dsa_conduit_append_port_sset_count(dp->ds, dp->index, sset, ++ &count); ++ } + + return count; + } + +-static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, +- u8 *data) ++static ssize_t dsa_conduit_append_port_strings(struct dsa_switch *ds, int port, ++ u32 stringset, u8 *data, ++ size_t start) + { +- struct dsa_port *cpu_dp = dev->dsa_ptr; +- const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; +- struct dsa_switch *ds = cpu_dp->ds; +- int port = cpu_dp->index; + int len = ETH_GSTRING_LEN; +- int mcount = 0, count, i; +- u8 pfx[4], *ndata; ++ u8 pfx[8], *ndata; ++ int count, i; ++ ++ if (!ds->ops->get_strings) ++ return 0; + +- snprintf(pfx, sizeof(pfx), "p%.2d", port); ++ snprintf(pfx, sizeof(pfx), "s%.2d_p%.2d", ds->index, port); + /* We do not want to be NULL-terminated, since this is a prefix */ + pfx[sizeof(pfx) - 1] = '_'; ++ ndata = data + start * len; ++ /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle ++ * the output after to prepend our CPU port prefix we ++ * constructed earlier ++ */ ++ ds->ops->get_strings(ds, port, stringset, ndata); ++ count = ds->ops->get_sset_count(ds, port, stringset); ++ if (count < 0) ++ return count; ++ ++ for (i = 0; i < count; i++) { ++ memmove(ndata + (i * len + sizeof(pfx)), ++ ndata + i * len, len - sizeof(pfx)); ++ memcpy(ndata + i * len, pfx, sizeof(pfx)); ++ } ++ ++ return count; ++} ++ ++static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, ++ u8 *data) ++{ ++ struct dsa_port *dp, *cpu_dp = dev->dsa_ptr; ++ const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; ++ struct dsa_switch_tree *dst = cpu_dp->dst; ++ int count, mcount = 0; + + netdev_lock_ops(dev); + if (stringset == ETH_SS_PHY_STATS && dev->phydev && +@@ -191,21 +255,17 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, + } + netdev_unlock_ops(dev); + +- if (ds->ops->get_strings) { +- ndata = data + mcount * len; +- /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle +- * the output after to prepend our CPU port prefix we +- * constructed earlier +- */ +- ds->ops->get_strings(ds, port, stringset, ndata); +- count = ds->ops->get_sset_count(ds, port, stringset); ++ list_for_each_entry(dp, &dst->ports, list) { ++ if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp)) ++ continue; ++ ++ count = dsa_conduit_append_port_strings(dp->ds, dp->index, ++ stringset, data, ++ mcount); + if (count < 0) + return; +- for (i = 0; i < count; i++) { +- memmove(ndata + (i * len + sizeof(pfx)), +- ndata + i * len, len - sizeof(pfx)); +- memcpy(ndata + i * len, pfx, sizeof(pfx)); +- } ++ ++ mcount += count; + } + } + +-- +2.53.0 + diff --git a/queue-6.18/net-dsa-cpu_dp-orig_ethtool_ops-might-be-null.patch b/queue-6.18/net-dsa-cpu_dp-orig_ethtool_ops-might-be-null.patch new file mode 100644 index 0000000000..69deb6a95c --- /dev/null +++ b/queue-6.18/net-dsa-cpu_dp-orig_ethtool_ops-might-be-null.patch @@ -0,0 +1,128 @@ +From 47dfa90cdb1c53a9760b0040bea8698e94925d5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 22 Nov 2025 13:23:09 +0200 +Subject: net: dsa: cpu_dp->orig_ethtool_ops might be NULL + +From: Vladimir Oltean + +[ Upstream commit eba81b0a6de39e2466d37e410003642282b4e546 ] + +In theory this would have been seen by now, but it seems that all +drivers used as DSA conduit interfaces thus far have had ethtool_ops +set, and it's hard to even find modern Ethernet drivers (and not VF +ones) which don't use ethtool. + +Here is the unfiltered list of drivers which register any sort of +net_device but don't set its ethtool_ops pointer. I don't think any of +them 'risks' being used as a DSA conduit, maybe except for moxart, +rnpbge and icssm, I'm not sure. + +- drivers/net/can/dev/dev.c +- drivers/net/wwan/qcom_bam_dmux.c +- drivers/net/wwan/t7xx/t7xx_netdev.c +- drivers/net/arcnet/arcnet.c +- drivers/net/hamradio/ +- drivers/net/slip/slip.c +- drivers/net/ethernet/ezchip/nps_enet.c +- drivers/net/ethernet/moxa/moxart_ether.c +- drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c +- drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c +- drivers/net/ethernet/huawei/hinic3/hinic3_main.c +- drivers/net/ethernet/i825xx/ +- drivers/net/ethernet/ti/icssm/icssm_prueth.c +- drivers/net/ethernet/seeq/ +- drivers/net/ethernet/litex/litex_liteeth.c +- drivers/net/ethernet/sunplus/spl2sw_driver.c +- drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c +- drivers/net/ipa/ +- drivers/net/wireless/microchip/wilc1000/ +- drivers/net/wireless/mediatek/mt76/dma.c +- drivers/net/wireless/ath/ath12k/ +- drivers/net/wireless/ath/ath11k/ +- drivers/net/wireless/ath/ath6kl/ +- drivers/net/wireless/ath/ath10k/ +- drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +- drivers/net/wireless/virtual/mac80211_hwsim.c +- drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c +- drivers/net/wireless/realtek/rtw89/core.c +- drivers/net/wireless/realtek/rtw88/pci.c +- drivers/net/caif/ +- drivers/net/plip/ +- drivers/net/wan/ +- drivers/net/mctp/ +- drivers/net/ppp/ +- drivers/net/thunderbolt/ + +Nonetheless, it's good for the framework not to make such assumptions, +and not panic when coming across such kind of host device in the future. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251122112311.138784-2-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0f99e0c3e19b ("net: dsa: remove redundant netdev_lock_ops() from conduit ethtool ops") +Signed-off-by: Sasha Levin +--- + net/dsa/conduit.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/net/dsa/conduit.c b/net/dsa/conduit.c +index 4ae255cfb23f8..f80795b3d0460 100644 +--- a/net/dsa/conduit.c ++++ b/net/dsa/conduit.c +@@ -26,7 +26,7 @@ static int dsa_conduit_get_regs_len(struct net_device *dev) + int ret = 0; + int len; + +- if (ops->get_regs_len) { ++ if (ops && ops->get_regs_len) { + netdev_lock_ops(dev); + len = ops->get_regs_len(dev); + netdev_unlock_ops(dev); +@@ -59,7 +59,7 @@ static void dsa_conduit_get_regs(struct net_device *dev, + int port = cpu_dp->index; + int len; + +- if (ops->get_regs_len && ops->get_regs) { ++ if (ops && ops->get_regs_len && ops->get_regs) { + netdev_lock_ops(dev); + len = ops->get_regs_len(dev); + if (len < 0) { +@@ -97,7 +97,7 @@ static void dsa_conduit_get_ethtool_stats(struct net_device *dev, + int port = cpu_dp->index; + int count = 0; + +- if (ops->get_sset_count && ops->get_ethtool_stats) { ++ if (ops && ops->get_sset_count && ops->get_ethtool_stats) { + netdev_lock_ops(dev); + count = ops->get_sset_count(dev, ETH_SS_STATS); + ops->get_ethtool_stats(dev, stats, data); +@@ -118,11 +118,11 @@ static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev, + int port = cpu_dp->index; + int count = 0; + +- if (dev->phydev && !ops->get_ethtool_phy_stats) { ++ if (dev->phydev && (!ops || !ops->get_ethtool_phy_stats)) { + count = phy_ethtool_get_sset_count(dev->phydev); + if (count >= 0) + phy_ethtool_get_stats(dev->phydev, stats, data); +- } else if (ops->get_sset_count && ops->get_ethtool_phy_stats) { ++ } else if (ops && ops->get_sset_count && ops->get_ethtool_phy_stats) { + netdev_lock_ops(dev); + count = ops->get_sset_count(dev, ETH_SS_PHY_STATS); + ops->get_ethtool_phy_stats(dev, stats, data); +@@ -145,9 +145,9 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset) + + netdev_lock_ops(dev); + if (sset == ETH_SS_PHY_STATS && dev->phydev && +- !ops->get_ethtool_phy_stats) ++ (!ops || !ops->get_ethtool_phy_stats)) + count = phy_ethtool_get_sset_count(dev->phydev); +- else if (ops->get_sset_count) ++ else if (ops && ops->get_sset_count) + count = ops->get_sset_count(dev, sset); + netdev_unlock_ops(dev); + +-- +2.53.0 + diff --git a/queue-6.18/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch b/queue-6.18/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch new file mode 100644 index 0000000000..2bf018ebb6 --- /dev/null +++ b/queue-6.18/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch @@ -0,0 +1,44 @@ +From 442b3ad1db20a49ace6fff39622c460b30448769 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:37:07 +0200 +Subject: net: dsa: realtek: rtl8365mb: fix mode mask calculation + +From: Mieczyslaw Nalewaj + +[ Upstream commit 0c078021d3861966614d5e594ee03587f0c9e74d ] + +The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting +the 4-bit mask (0xF) by only (_extint % 2) bits instead of +(_extint % 2) * 4. This caused the mask to overlap with the adjacent +nibble when configuring odd-numbered external interfaces, selecting +the wrong bits entirely. + +Align the shift calculation with the existing ...MODE_OFFSET macro. + +Fixes: 4af2950c50c8 ("net: dsa: realtek-smi: add rtl8365mb subdriver for RTL8365MB-VC") +Signed-off-by: Abdulkader Alrezej +Signed-off-by: Mieczyslaw Nalewaj +Reviewed-by: Luiz Angelo Daros de Luca +Link: https://patch.msgid.link/400a6387-a444-4576-af6d-26be5410bce3@yahoo.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/realtek/rtl8365mb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index 3a48db295e7e4..e10a789e22022 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -216,7 +216,7 @@ + (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ + 0x0) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \ +- (0xF << (((_extint) % 2))) ++ (0xF << (((_extint) % 2) * 4)) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \ + (((_extint) % 2) * 4) + +-- +2.53.0 + diff --git a/queue-6.18/net-dsa-remove-redundant-netdev_lock_ops-from-condui.patch b/queue-6.18/net-dsa-remove-redundant-netdev_lock_ops-from-condui.patch new file mode 100644 index 0000000000..612ae3442f --- /dev/null +++ b/queue-6.18/net-dsa-remove-redundant-netdev_lock_ops-from-condui.patch @@ -0,0 +1,117 @@ +From ea4ec894fdc0f07c789ab2e2107c8ad62e96f3d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:10:35 -0700 +Subject: net: dsa: remove redundant netdev_lock_ops() from conduit ethtool ops + +From: Stanislav Fomichev + +[ Upstream commit 0f99e0c3e19badaf3fdced0d3feba623e59eed41 ] + +DSA replaces the conduit (master) device's ethtool_ops with its own +wrappers that aggregate stats from both the conduit and DSA switch +ports. Taking the lock again inside the DSA wrappers causes a deadlock. + +Stumbled upon this when booting qemu with fbnic and CONFIG_NET_DSA_LOOP=y +(which looks like some kind of testing device that auto-populates the ports +of eth0). `ethtool -i` is enough to deadlock. This means we have basically zero +coverage for DSA stuff with real ops locked devs. + +Remove the redundant netdev_lock_ops()/netdev_unlock_ops() calls from +the DSA conduit ethtool wrappers. + +Fixes: 2bcf4772e45a ("net: ethtool: try to protect all callback with netdev instance lock") +Signed-off-by: Stanislav Fomichev +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260414231035.1917035-1-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/dsa/conduit.c | 16 +--------------- + 1 file changed, 1 insertion(+), 15 deletions(-) + +diff --git a/net/dsa/conduit.c b/net/dsa/conduit.c +index a1b044467bd6f..8398d72d7e4d3 100644 +--- a/net/dsa/conduit.c ++++ b/net/dsa/conduit.c +@@ -27,9 +27,7 @@ static int dsa_conduit_get_regs_len(struct net_device *dev) + int len; + + if (ops && ops->get_regs_len) { +- netdev_lock_ops(dev); + len = ops->get_regs_len(dev); +- netdev_unlock_ops(dev); + if (len < 0) + return len; + ret += len; +@@ -60,15 +58,11 @@ static void dsa_conduit_get_regs(struct net_device *dev, + int len; + + if (ops && ops->get_regs_len && ops->get_regs) { +- netdev_lock_ops(dev); + len = ops->get_regs_len(dev); +- if (len < 0) { +- netdev_unlock_ops(dev); ++ if (len < 0) + return; +- } + regs->len = len; + ops->get_regs(dev, regs, data); +- netdev_unlock_ops(dev); + data += regs->len; + } + +@@ -115,10 +109,8 @@ static void dsa_conduit_get_ethtool_stats(struct net_device *dev, + int count, mcount = 0; + + if (ops && ops->get_sset_count && ops->get_ethtool_stats) { +- netdev_lock_ops(dev); + mcount = ops->get_sset_count(dev, ETH_SS_STATS); + ops->get_ethtool_stats(dev, stats, data); +- netdev_unlock_ops(dev); + } + + list_for_each_entry(dp, &dst->ports, list) { +@@ -149,10 +141,8 @@ static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev, + if (count >= 0) + phy_ethtool_get_stats(dev->phydev, stats, data); + } else if (ops && ops->get_sset_count && ops->get_ethtool_phy_stats) { +- netdev_lock_ops(dev); + count = ops->get_sset_count(dev, ETH_SS_PHY_STATS); + ops->get_ethtool_phy_stats(dev, stats, data); +- netdev_unlock_ops(dev); + } + + if (count < 0) +@@ -176,13 +166,11 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset) + struct dsa_switch_tree *dst = cpu_dp->dst; + int count = 0; + +- netdev_lock_ops(dev); + if (sset == ETH_SS_PHY_STATS && dev->phydev && + (!ops || !ops->get_ethtool_phy_stats)) + count = phy_ethtool_get_sset_count(dev->phydev); + else if (ops && ops->get_sset_count) + count = ops->get_sset_count(dev, sset); +- netdev_unlock_ops(dev); + + if (count < 0) + count = 0; +@@ -239,7 +227,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, + struct dsa_switch_tree *dst = cpu_dp->dst; + int count, mcount = 0; + +- netdev_lock_ops(dev); + if (stringset == ETH_SS_PHY_STATS && dev->phydev && + !ops->get_ethtool_phy_stats) { + mcount = phy_ethtool_get_sset_count(dev->phydev); +@@ -253,7 +240,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, + mcount = 0; + ops->get_strings(dev, stringset, data); + } +- netdev_unlock_ops(dev); + + list_for_each_entry(dp, &dst->ports, list) { + if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp)) +-- +2.53.0 + diff --git a/queue-6.18/net-dsa-use-kernel-data-types-for-ethtool-ops-on-con.patch b/queue-6.18/net-dsa-use-kernel-data-types-for-ethtool-ops-on-con.patch new file mode 100644 index 0000000000..ddb6f27f34 --- /dev/null +++ b/queue-6.18/net-dsa-use-kernel-data-types-for-ethtool-ops-on-con.patch @@ -0,0 +1,68 @@ +From 70c33af52ae4bac0653130d5770c480fdb214325 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 22 Nov 2025 13:23:10 +0200 +Subject: net: dsa: use kernel data types for ethtool ops on conduit + +From: Vladimir Oltean + +[ Upstream commit 8afabd27fe46ebf991b4aea20b74e08196c15c0c ] + +Suppress some checkpatch 'CHECK' messages about u8 being preferable over +uint8_t, etc. No functional change. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20251122112311.138784-3-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 0f99e0c3e19b ("net: dsa: remove redundant netdev_lock_ops() from conduit ethtool ops") +Signed-off-by: Sasha Levin +--- + net/dsa/conduit.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/net/dsa/conduit.c b/net/dsa/conduit.c +index f80795b3d0460..c210e31296558 100644 +--- a/net/dsa/conduit.c ++++ b/net/dsa/conduit.c +@@ -89,7 +89,7 @@ static void dsa_conduit_get_regs(struct net_device *dev, + + static void dsa_conduit_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, +- uint64_t *data) ++ u64 *data) + { + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; +@@ -110,7 +110,7 @@ static void dsa_conduit_get_ethtool_stats(struct net_device *dev, + + static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev, + struct ethtool_stats *stats, +- uint64_t *data) ++ u64 *data) + { + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; +@@ -160,8 +160,8 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset) + return count; + } + +-static void dsa_conduit_get_strings(struct net_device *dev, uint32_t stringset, +- uint8_t *data) ++static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, ++ u8 *data) + { + struct dsa_port *cpu_dp = dev->dsa_ptr; + const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops; +@@ -169,8 +169,7 @@ static void dsa_conduit_get_strings(struct net_device *dev, uint32_t stringset, + int port = cpu_dp->index; + int len = ETH_GSTRING_LEN; + int mcount = 0, count, i; +- uint8_t pfx[4]; +- uint8_t *ndata; ++ u8 pfx[4], *ndata; + + snprintf(pfx, sizeof(pfx), "p%.2d", port); + /* We do not want to be NULL-terminated, since this is a prefix */ +-- +2.53.0 + diff --git a/queue-6.18/net-enetc-correct-the-command-bd-ring-consumer-index.patch b/queue-6.18/net-enetc-correct-the-command-bd-ring-consumer-index.patch new file mode 100644 index 0000000000..48c5f2a3f6 --- /dev/null +++ b/queue-6.18/net-enetc-correct-the-command-bd-ring-consumer-index.patch @@ -0,0 +1,92 @@ +From 5561c155189aa5c01cc5f0303b005373397ce2b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:08:32 +0800 +Subject: net: enetc: correct the command BD ring consumer index + +From: Wei Fang + +[ Upstream commit 759a32900b6f3db3d0f34a3b61123742723b50b4 ] + +The command BD ring cousumer index register has the consumer index as +the lower 10 bits, and the bit 31 is SBE, which indicates whether a +system bus error occurred during execution of the CBD command. So if a +system bus error occurs, reading the register will get the SBE bit set. + +However, the current implementation directly uses the register value as +the consumer index without masking it. Therefore, if a system bus error +occurs, an incorrect consumer index will be obtained, causing errors in +the processing of the command BD ring. Thus, we need to mask out the +other bits to obtain the correct consumer index. + +In addition, this patch adds a check for the SBE bit after the polling +loop and returns an error if the bit is set. + +Fixes: 4701073c3deb ("net: enetc: add initial netc-lib driver to support NTMP") +Signed-off-by: Wei Fang +Link: https://patch.msgid.link/20260415060833.2303846-2-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/enetc/ntmp.c | 13 ++++++++++--- + drivers/net/ethernet/freescale/enetc/ntmp_private.h | 2 ++ + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c +index 0c1d343253bfb..b188eb2d40c0d 100644 +--- a/drivers/net/ethernet/freescale/enetc/ntmp.c ++++ b/drivers/net/ethernet/freescale/enetc/ntmp.c +@@ -55,7 +55,7 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev, + spin_lock_init(&cbdr->ring_lock); + + cbdr->next_to_use = netc_read(cbdr->regs.pir); +- cbdr->next_to_clean = netc_read(cbdr->regs.cir); ++ cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX; + + /* Step 1: Configure the base address of the Control BD Ring */ + netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align)); +@@ -98,7 +98,7 @@ static void ntmp_clean_cbdr(struct netc_cbdr *cbdr) + int i; + + i = cbdr->next_to_clean; +- while (netc_read(cbdr->regs.cir) != i) { ++ while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) { + cbd = ntmp_get_cbd(cbdr, i); + memset(cbd, 0, sizeof(*cbd)); + i = (i + 1) % cbdr->bd_num; +@@ -135,12 +135,19 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd) + cbdr->next_to_use = i; + netc_write(cbdr->regs.pir, i); + +- err = read_poll_timeout_atomic(netc_read, val, val == i, ++ err = read_poll_timeout_atomic(netc_read, val, ++ (val & NETC_CBDRCIR_INDEX) == i, + NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT, + true, cbdr->regs.cir); + if (unlikely(err)) + goto cbdr_unlock; + ++ if (unlikely(val & NETC_CBDRCIR_SBE)) { ++ dev_err(user->dev, "Command BD system bus error\n"); ++ err = -EIO; ++ goto cbdr_unlock; ++ } ++ + dma_rmb(); + /* Get the writeback command BD, because the caller may need + * to check some other fields of the response header. +diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h +index 34394e40fddd4..3459cc45b6103 100644 +--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h ++++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h +@@ -12,6 +12,8 @@ + + #define NTMP_EID_REQ_LEN 8 + #define NETC_CBDR_BD_NUM 256 ++#define NETC_CBDRCIR_INDEX GENMASK(9, 0) ++#define NETC_CBDRCIR_SBE BIT(31) + + union netc_cbd { + struct { +-- +2.53.0 + diff --git a/queue-6.18/net-enetc-fix-ntmp-dma-use-after-free-issue.patch b/queue-6.18/net-enetc-fix-ntmp-dma-use-after-free-issue.patch new file mode 100644 index 0000000000..1a4c28a932 --- /dev/null +++ b/queue-6.18/net-enetc-fix-ntmp-dma-use-after-free-issue.patch @@ -0,0 +1,577 @@ +From a1380a2d4edb6f3b57bff1f2226acbf05e182fdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:08:33 +0800 +Subject: net: enetc: fix NTMP DMA use-after-free issue + +From: Wei Fang + +[ Upstream commit 3cade698881eb238f88cbbfec82acc2110440a3f ] + +The AI-generated review reported a potential DMA use-after-free issue +[1]. If netc_xmit_ntmp_cmd() times out and returns an error, the pending +command is not explicitly aborted, while ntmp_free_data_mem() +unconditionally frees the DMA buffer. If the buffer has already been +reallocated elsewhere, this may lead to silent memory corruption. Because +the hardware eventually processes the pending command and perform a DMA +write of the response to the physical address of the freed buffer. + +To resolve this issue, this patch does the following modifications: + +1. Convert cbdr->ring_lock from a spinlock to a mutex + +The lock was originally a spinlock in case NTMP operations might be +invoked from atomic context. After downstream support for all NTMP +tables, no such usage has materialized. A mutex lock is now required +because the driver now needs to reclaim used BDs and release associated +DMA memory within the lock's context, while dma_free_coherent() might +sleep. + +2. Introduce software command BD (struct netc_swcbd) + +The hardware write-back overwrites the addr and len fields of the BD, +so the driver cannot rely on the hardware BD to free the associated DMA +memory. The driver now maintains a software shadow BD storing the DMA +buffer pointer, DMA address, and size. And netc_xmit_ntmp_cmd() only +reclaims older BDs when the number of used BDs reaches +NETC_CBDR_CLEAN_WORK (16). The software BD enables correct DMA memory +release. With this, struct ntmp_dma_buf and ntmp_free_data_mem() are no +longer needed and are removed. + +3. Require callers to hold ring_lock across netc_xmit_ntmp_cmd() + +netc_xmit_ntmp_cmd() releases the ring_lock before the caller finishes +consuming the response. At this point, if a concurrent thread submits +a new command, it may trigger ntmp_clean_cbdr() and free the DMA buffer +while it is still in use. Move ring_lock ownership to the caller to +ensure the response buffer cannot be reclaimed prematurely. So the +helpers ntmp_select_and_lock_cbdr() and ntmp_unlock_cbdr() are added. + +These changes eliminate the DMA use-after-free condition and ensure safe +and consistent BD reclamation and DMA buffer lifecycle management. + +Fixes: 4701073c3deb ("net: enetc: add initial netc-lib driver to support NTMP") +Link: https://lore.kernel.org/netdev/20260403011729.1795413-1-kuba@kernel.org/ # [1] +Signed-off-by: Wei Fang +Link: https://patch.msgid.link/20260415060833.2303846-3-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/enetc/ntmp.c | 214 ++++++++++-------- + .../ethernet/freescale/enetc/ntmp_private.h | 8 +- + include/linux/fsl/ntmp.h | 9 +- + 3 files changed, 134 insertions(+), 97 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c +index b188eb2d40c0d..70bbc5d2d5d42 100644 +--- a/drivers/net/ethernet/freescale/enetc/ntmp.c ++++ b/drivers/net/ethernet/freescale/enetc/ntmp.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #include "ntmp_private.h" + +@@ -42,6 +43,12 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev, + if (!cbdr->addr_base) + return -ENOMEM; + ++ cbdr->swcbd = vcalloc(cbd_num, sizeof(struct netc_swcbd)); ++ if (!cbdr->swcbd) { ++ dma_free_coherent(dev, size, cbdr->addr_base, cbdr->dma_base); ++ return -ENOMEM; ++ } ++ + cbdr->dma_size = size; + cbdr->bd_num = cbd_num; + cbdr->regs = *regs; +@@ -52,7 +59,7 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev, + cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base, + NTMP_BASE_ADDR_ALIGN); + +- spin_lock_init(&cbdr->ring_lock); ++ mutex_init(&cbdr->ring_lock); + + cbdr->next_to_use = netc_read(cbdr->regs.pir); + cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX; +@@ -71,10 +78,24 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev, + } + EXPORT_SYMBOL_GPL(ntmp_init_cbdr); + ++static void ntmp_free_data_mem(struct device *dev, struct netc_swcbd *swcbd) ++{ ++ if (unlikely(!swcbd->buf)) ++ return; ++ ++ dma_free_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN, ++ swcbd->buf, swcbd->dma); ++} ++ + void ntmp_free_cbdr(struct netc_cbdr *cbdr) + { + /* Disable the Control BD Ring */ + netc_write(cbdr->regs.mr, 0); ++ ++ for (int i = 0; i < cbdr->bd_num; i++) ++ ntmp_free_data_mem(cbdr->dev, &cbdr->swcbd[i]); ++ ++ vfree(cbdr->swcbd); + dma_free_coherent(cbdr->dev, cbdr->dma_size, cbdr->addr_base, + cbdr->dma_base); + memset(cbdr, 0, sizeof(*cbdr)); +@@ -94,40 +115,59 @@ static union netc_cbd *ntmp_get_cbd(struct netc_cbdr *cbdr, int index) + + static void ntmp_clean_cbdr(struct netc_cbdr *cbdr) + { +- union netc_cbd *cbd; +- int i; ++ int i = cbdr->next_to_clean; + +- i = cbdr->next_to_clean; + while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) { +- cbd = ntmp_get_cbd(cbdr, i); ++ union netc_cbd *cbd = ntmp_get_cbd(cbdr, i); ++ struct netc_swcbd *swcbd = &cbdr->swcbd[i]; ++ ++ ntmp_free_data_mem(cbdr->dev, swcbd); ++ memset(swcbd, 0, sizeof(*swcbd)); + memset(cbd, 0, sizeof(*cbd)); + i = (i + 1) % cbdr->bd_num; + } + ++ dma_wmb(); + cbdr->next_to_clean = i; + } + +-static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd) ++static void ntmp_select_and_lock_cbdr(struct ntmp_user *user, ++ struct netc_cbdr **cbdr) ++{ ++ /* Currently only ENETC is supported, and it has only one command ++ * BD ring. ++ */ ++ *cbdr = &user->ring[0]; ++ ++ mutex_lock(&(*cbdr)->ring_lock); ++} ++ ++static void ntmp_unlock_cbdr(struct netc_cbdr *cbdr) ++{ ++ mutex_unlock(&cbdr->ring_lock); ++} ++ ++static int netc_xmit_ntmp_cmd(struct netc_cbdr *cbdr, union netc_cbd *cbd, ++ struct netc_swcbd *swcbd) + { + union netc_cbd *cur_cbd; +- struct netc_cbdr *cbdr; +- int i, err; ++ int i, err, used_bds; + u16 status; + u32 val; + +- /* Currently only i.MX95 ENETC is supported, and it only has one +- * command BD ring +- */ +- cbdr = &user->ring[0]; +- +- spin_lock_bh(&cbdr->ring_lock); +- +- if (unlikely(!ntmp_get_free_cbd_num(cbdr))) ++ used_bds = cbdr->bd_num - ntmp_get_free_cbd_num(cbdr); ++ if (unlikely(used_bds >= NETC_CBDR_CLEAN_WORK)) { + ntmp_clean_cbdr(cbdr); ++ if (unlikely(!ntmp_get_free_cbd_num(cbdr))) { ++ ntmp_free_data_mem(cbdr->dev, swcbd); ++ return -EBUSY; ++ } ++ } + + i = cbdr->next_to_use; + cur_cbd = ntmp_get_cbd(cbdr, i); + *cur_cbd = *cbd; ++ cbdr->swcbd[i] = *swcbd; + dma_wmb(); + + /* Update producer index of both software and hardware */ +@@ -135,17 +175,16 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd) + cbdr->next_to_use = i; + netc_write(cbdr->regs.pir, i); + +- err = read_poll_timeout_atomic(netc_read, val, +- (val & NETC_CBDRCIR_INDEX) == i, +- NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT, +- true, cbdr->regs.cir); ++ err = read_poll_timeout(netc_read, val, ++ (val & NETC_CBDRCIR_INDEX) == i, ++ NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT, ++ true, cbdr->regs.cir); + if (unlikely(err)) +- goto cbdr_unlock; ++ return err; + + if (unlikely(val & NETC_CBDRCIR_SBE)) { +- dev_err(user->dev, "Command BD system bus error\n"); +- err = -EIO; +- goto cbdr_unlock; ++ dev_err(cbdr->dev, "Command BD system bus error\n"); ++ return -EIO; + } + + dma_rmb(); +@@ -157,40 +196,29 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd) + /* Check the writeback error status */ + status = le16_to_cpu(cbd->resp_hdr.error_rr) & NTMP_RESP_ERROR; + if (unlikely(status)) { +- err = -EIO; +- dev_err(user->dev, "Command BD error: 0x%04x\n", status); ++ dev_err(cbdr->dev, "Command BD error: 0x%04x\n", status); ++ return -EIO; + } + +- ntmp_clean_cbdr(cbdr); +- dma_wmb(); +- +-cbdr_unlock: +- spin_unlock_bh(&cbdr->ring_lock); +- +- return err; ++ return 0; + } + +-static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align) ++static int ntmp_alloc_data_mem(struct device *dev, struct netc_swcbd *swcbd, ++ void **buf_align) + { + void *buf; + +- buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN, +- &data->dma, GFP_KERNEL); ++ buf = dma_alloc_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN, ++ &swcbd->dma, GFP_KERNEL); + if (!buf) + return -ENOMEM; + +- data->buf = buf; ++ swcbd->buf = buf; + *buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN); + + return 0; + } + +-static void ntmp_free_data_mem(struct ntmp_dma_buf *data) +-{ +- dma_free_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN, +- data->buf, data->dma); +-} +- + static void ntmp_fill_request_hdr(union netc_cbd *cbd, dma_addr_t dma, + int len, int table_id, int cmd, + int access_method) +@@ -241,37 +269,39 @@ static int ntmp_delete_entry_by_id(struct ntmp_user *user, int tbl_id, + u8 tbl_ver, u32 entry_id, u32 req_len, + u32 resp_len) + { +- struct ntmp_dma_buf data = { +- .dev = user->dev, ++ struct netc_swcbd swcbd = { + .size = max(req_len, resp_len), + }; + struct ntmp_req_by_eid *req; ++ struct netc_cbdr *cbdr; + union netc_cbd cbd; + int err; + +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + + ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id); +- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(req_len, resp_len), ++ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(req_len, resp_len), + tbl_id, NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID); + +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd); + if (err) + dev_err(user->dev, + "Failed to delete entry 0x%x of %s, err: %pe", + entry_id, ntmp_table_name(tbl_id), ERR_PTR(err)); +- +- ntmp_free_data_mem(&data); ++ ntmp_unlock_cbdr(cbdr); + + return err; + } + +-static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id, +- u32 len, struct ntmp_req_by_eid *req, +- dma_addr_t dma, bool compare_eid) ++static int ntmp_query_entry_by_id(struct netc_cbdr *cbdr, int tbl_id, ++ struct ntmp_req_by_eid *req, ++ struct netc_swcbd *swcbd, ++ bool compare_eid) + { ++ u32 len = NTMP_LEN(sizeof(*req), swcbd->size); + struct ntmp_cmn_resp_query *resp; + int cmd = NTMP_CMD_QUERY; + union netc_cbd cbd; +@@ -283,10 +313,11 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id, + cmd = NTMP_CMD_QU; + + /* Request header */ +- ntmp_fill_request_hdr(&cbd, dma, len, tbl_id, cmd, NTMP_AM_ENTRY_ID); +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ntmp_fill_request_hdr(&cbd, swcbd->dma, len, tbl_id, cmd, ++ NTMP_AM_ENTRY_ID); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, swcbd); + if (err) { +- dev_err(user->dev, ++ dev_err(cbdr->dev, + "Failed to query entry 0x%x of %s, err: %pe\n", + entry_id, ntmp_table_name(tbl_id), ERR_PTR(err)); + return err; +@@ -300,7 +331,7 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id, + + resp = (struct ntmp_cmn_resp_query *)req; + if (unlikely(le32_to_cpu(resp->entry_id) != entry_id)) { +- dev_err(user->dev, ++ dev_err(cbdr->dev, + "%s: query EID 0x%x doesn't match response EID 0x%x\n", + ntmp_table_name(tbl_id), entry_id, le32_to_cpu(resp->entry_id)); + return -EIO; +@@ -312,15 +343,15 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id, + int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id, + struct maft_entry_data *maft) + { +- struct ntmp_dma_buf data = { +- .dev = user->dev, ++ struct netc_swcbd swcbd = { + .size = sizeof(struct maft_req_add), + }; + struct maft_req_add *req; ++ struct netc_cbdr *cbdr; + union netc_cbd cbd; + int err; + +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + +@@ -329,14 +360,15 @@ int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id, + req->keye = maft->keye; + req->cfge = maft->cfge; + +- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0), ++ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0), + NTMP_MAFT_ID, NTMP_CMD_ADD, NTMP_AM_ENTRY_ID); +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd); + if (err) + dev_err(user->dev, "Failed to add MAFT entry 0x%x, err: %pe\n", + entry_id, ERR_PTR(err)); +- +- ntmp_free_data_mem(&data); ++ ntmp_unlock_cbdr(cbdr); + + return err; + } +@@ -345,31 +377,31 @@ EXPORT_SYMBOL_GPL(ntmp_maft_add_entry); + int ntmp_maft_query_entry(struct ntmp_user *user, u32 entry_id, + struct maft_entry_data *maft) + { +- struct ntmp_dma_buf data = { +- .dev = user->dev, ++ struct netc_swcbd swcbd = { + .size = sizeof(struct maft_resp_query), + }; + struct maft_resp_query *resp; + struct ntmp_req_by_eid *req; ++ struct netc_cbdr *cbdr; + int err; + +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + + ntmp_fill_crd_eid(req, user->tbl.maft_ver, 0, 0, entry_id); +- err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID, +- NTMP_LEN(sizeof(*req), data.size), +- req, data.dma, true); ++ ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = ntmp_query_entry_by_id(cbdr, NTMP_MAFT_ID, req, &swcbd, true); + if (err) +- goto end; ++ goto unlock_cbdr; + + resp = (struct maft_resp_query *)req; + maft->keye = resp->keye; + maft->cfge = resp->cfge; + +-end: +- ntmp_free_data_mem(&data); ++unlock_cbdr: ++ ntmp_unlock_cbdr(cbdr); + + return err; + } +@@ -385,8 +417,9 @@ EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry); + int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table, + int count) + { +- struct ntmp_dma_buf data = {.dev = user->dev}; + struct rsst_req_update *req; ++ struct netc_swcbd swcbd; ++ struct netc_cbdr *cbdr; + union netc_cbd cbd; + int err, i; + +@@ -394,8 +427,8 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table, + /* HW only takes in a full 64 entry table */ + return -EINVAL; + +- data.size = struct_size(req, groups, count); +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ swcbd.size = struct_size(req, groups, count); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + +@@ -405,15 +438,15 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table, + for (i = 0; i < count; i++) + req->groups[i] = (u8)(table[i]); + +- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0), ++ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0), + NTMP_RSST_ID, NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID); + +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd); + if (err) + dev_err(user->dev, "Failed to update RSST entry, err: %pe\n", + ERR_PTR(err)); +- +- ntmp_free_data_mem(&data); ++ ntmp_unlock_cbdr(cbdr); + + return err; + } +@@ -421,8 +454,9 @@ EXPORT_SYMBOL_GPL(ntmp_rsst_update_entry); + + int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count) + { +- struct ntmp_dma_buf data = {.dev = user->dev}; + struct ntmp_req_by_eid *req; ++ struct netc_swcbd swcbd; ++ struct netc_cbdr *cbdr; + union netc_cbd cbd; + int err, i; + u8 *group; +@@ -431,21 +465,23 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count) + /* HW only takes in a full 64 entry table */ + return -EINVAL; + +- data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) + +- RSST_CFGE_DATA_SIZE(count); +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ swcbd.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) + ++ RSST_CFGE_DATA_SIZE(count); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + + /* Set the request data buffer */ + ntmp_fill_crd_eid(req, user->tbl.rsst_ver, 0, 0, 0); +- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(sizeof(*req), data.size), ++ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(sizeof(*req), swcbd.size), + NTMP_RSST_ID, NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID); +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd); + if (err) { + dev_err(user->dev, "Failed to query RSST entry, err: %pe\n", + ERR_PTR(err)); +- goto end; ++ goto unlock_cbdr; + } + + group = (u8 *)req; +@@ -453,8 +489,8 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count) + for (i = 0; i < count; i++) + table[i] = group[i]; + +-end: +- ntmp_free_data_mem(&data); ++unlock_cbdr: ++ ntmp_unlock_cbdr(cbdr); + + return err; + } +diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h +index 3459cc45b6103..f8dff3ba2c28a 100644 +--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h ++++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h +@@ -14,6 +14,7 @@ + #define NETC_CBDR_BD_NUM 256 + #define NETC_CBDRCIR_INDEX GENMASK(9, 0) + #define NETC_CBDRCIR_SBE BIT(31) ++#define NETC_CBDR_CLEAN_WORK 16 + + union netc_cbd { + struct { +@@ -56,13 +57,6 @@ union netc_cbd { + } resp_hdr; /* NTMP Response Message Header Format */ + }; + +-struct ntmp_dma_buf { +- struct device *dev; +- size_t size; +- void *buf; +- dma_addr_t dma; +-}; +- + struct ntmp_cmn_req_data { + __le16 update_act; + u8 dbg_opt; +diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h +index 916dc4fe7de3b..83a449b4d6ec4 100644 +--- a/include/linux/fsl/ntmp.h ++++ b/include/linux/fsl/ntmp.h +@@ -31,6 +31,12 @@ struct netc_tbl_vers { + u8 rsst_ver; + }; + ++struct netc_swcbd { ++ void *buf; ++ dma_addr_t dma; ++ size_t size; ++}; ++ + struct netc_cbdr { + struct device *dev; + struct netc_cbdr_regs regs; +@@ -44,9 +50,10 @@ struct netc_cbdr { + void *addr_base_align; + dma_addr_t dma_base; + dma_addr_t dma_base_align; ++ struct netc_swcbd *swcbd; + + /* Serialize the order of command BD ring */ +- spinlock_t ring_lock; ++ struct mutex ring_lock; + }; + + struct ntmp_user { +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-ti-cpsw-fix-linking-built-in-code-to-mo.patch b/queue-6.18/net-ethernet-ti-cpsw-fix-linking-built-in-code-to-mo.patch new file mode 100644 index 0000000000..1755ee87a5 --- /dev/null +++ b/queue-6.18/net-ethernet-ti-cpsw-fix-linking-built-in-code-to-mo.patch @@ -0,0 +1,1037 @@ +From 494bd093171745bfe3ff63bcc2e58b0a924b54f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:46:54 +0200 +Subject: net: ethernet: ti-cpsw: fix linking built-in code to modules + +From: Arnd Bergmann + +[ Upstream commit df75bd552a8790e83d4aeb5f112050cf3dc687bf ] + +There are six variants of the cpsw driver, sharing various parts of +the code: davinci-emac, cpsw, cpsw-switchdev, netcp, netcp_ethss and +am65-cpsw-nuss. + +I noticed that this means some files can be linked into more than +one loadable module, or even part of vmlinux but also linked into +a loadable module, both of which mess up assumptions of the build +system, and causes warnings: + +scripts/Makefile.build:279: cpsw_ale.o is added to multiple modules: ti-am65-cpsw-nuss ti_cpsw ti_cpsw_new +scripts/Makefile.build:279: cpsw_priv.o is added to multiple modules: ti_cpsw ti_cpsw_new +scripts/Makefile.build:279: cpsw_sl.o is added to multiple modules: ti-am65-cpsw-nuss ti_cpsw ti_cpsw_new +scripts/Makefile.build:279: cpsw_ethtool.o is added to multiple modules: ti_cpsw ti_cpsw_new +scripts/Makefile.build:279: davinci_cpdma.o is added to multiple modules: ti_cpsw ti_cpsw_new ti_davinci_emac + +Change this back to having separate modules for each portion that +can be linked standalone, exporting symbols as needed: + + - ti-cpsw-common.ko now contains both cpsw-common.o and + davinci_cpdma.o as they are always used together + + - ti-cpsw-priv.ko contains cpsw_priv.o, cpsw_sl.o and cpsw_ethtool.o, + which are the core of the cpsw and cpsw-new drivers. + + - ti-cpsw-sl.ko contains the cpsw-sl.o object and is used on + ti-am65-cpsw-nuss.ko in addition to the two other cpsw variants. + + - ti-cpsw-ale.o is the one standalone module that is used by all + except davinci_emac. + +Each of these will be built-in if any of its users are built-in, otherwise +it's a loadable module if there is at least one module using it. I did +not bring back the separate Kconfig symbols for this, but just handle +it using Makefile logic. + +Note: ideally this is something that Kbuild complains about, but usually +we just notice when something using THIS_MODULE misbehaves in a way that +a user notices. + +Fixes: 99f6297182729 ("net: ethernet: ti: cpsw: drop TI_DAVINCI_CPDMA config option") +Link: https://lore.kernel.org/lkml/20240417084400.3034104-1-arnd@kernel.org/ +Signed-off-by: Arnd Bergmann +Link: https://patch.msgid.link/20260402184726.3746487-2-arnd@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/Makefile | 30 ++++++++++---------- + drivers/net/ethernet/ti/cpsw_ale.c | 25 +++++++++++++++++ + drivers/net/ethernet/ti/cpsw_ethtool.c | 24 ++++++++++++++++ + drivers/net/ethernet/ti/cpsw_priv.c | 37 +++++++++++++++++++++++++ + drivers/net/ethernet/ti/cpsw_sl.c | 11 ++++++++ + drivers/net/ethernet/ti/davinci_cpdma.c | 27 ++++++++++++++++++ + 6 files changed, 139 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile +index 93c0a4d0e33a6..fec6ba62c0303 100644 +--- a/drivers/net/ethernet/ti/Makefile ++++ b/drivers/net/ethernet/ti/Makefile +@@ -6,30 +6,30 @@ + obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o + icssm-prueth-y := icssm/icssm_prueth.o + +-obj-$(CONFIG_TI_CPSW) += cpsw-common.o +-obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o +-obj-$(CONFIG_TI_CPSW_SWITCHDEV) += cpsw-common.o ++ti-cpsw-common-y += cpsw-common.o davinci_cpdma.o ++ti-cpsw-priv-y += cpsw_priv.o cpsw_ethtool.o ++ti-cpsw-ale-y += cpsw_ale.o ++ti-cpsw-sl-y += cpsw_sl.o + + obj-$(CONFIG_TLAN) += tlan.o +-obj-$(CONFIG_TI_DAVINCI_EMAC) += ti_davinci_emac.o +-ti_davinci_emac-y := davinci_emac.o davinci_cpdma.o ++obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o ti-cpsw-common.o + obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o + obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o + obj-$(CONFIG_TI_CPTS) += cpts.o +-obj-$(CONFIG_TI_CPSW) += ti_cpsw.o +-ti_cpsw-y := cpsw.o davinci_cpdma.o cpsw_ale.o cpsw_priv.o cpsw_sl.o cpsw_ethtool.o +-obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o +-ti_cpsw_new-y := cpsw_switchdev.o cpsw_new.o davinci_cpdma.o cpsw_ale.o cpsw_sl.o cpsw_priv.o cpsw_ethtool.o ++obj-$(CONFIG_TI_CPSW) += ti_cpsw.o ti-cpsw-common.o ti-cpsw-priv.o ti-cpsw-ale.o ti-cpsw-sl.o ++ti_cpsw-y := cpsw.o ++obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o ti-cpsw-common.o ti-cpsw-priv.o ti-cpsw-ale.o ti-cpsw-sl.o ++ti_cpsw_new-y := cpsw_switchdev.o cpsw_new.o + +-obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o +-keystone_netcp-y := netcp_core.o cpsw_ale.o +-obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o +-keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.o ++obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o ti-cpsw-ale.o ++keystone_netcp-y := netcp_core.o ++obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o ti-cpsw-ale.o ++keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o + + obj-$(CONFIG_TI_K3_CPPI_DESC_POOL) += k3-cppi-desc-pool.o + +-obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o +-ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o ++obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o ti-cpsw-sl.o ti-cpsw-ale.o ++ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o am65-cpsw-ethtool.o + ti-am65-cpsw-nuss-$(CONFIG_TI_AM65_CPSW_QOS) += am65-cpsw-qos.o + ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o + obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o +diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c +index 9632ad3741de1..7fb1488ca0025 100644 +--- a/drivers/net/ethernet/ti/cpsw_ale.c ++++ b/drivers/net/ethernet/ti/cpsw_ale.c +@@ -498,6 +498,7 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid) + } + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast); + + static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, + int flags, u16 vid) +@@ -535,6 +536,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast); + + int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port, + int flags, u16 vid) +@@ -550,6 +552,7 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast); + + int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, + int flags, u16 vid, int mcast_state) +@@ -583,6 +586,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast); + + int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, + int flags, u16 vid) +@@ -612,6 +616,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast); + + /* ALE NetCP NU switch specific vlan functions */ + static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry, +@@ -681,6 +686,7 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan); + + static void cpsw_ale_vlan_del_modify_int(struct cpsw_ale *ale, u32 *ale_entry, + u16 vid, int port_mask) +@@ -738,6 +744,7 @@ int cpsw_ale_vlan_del_modify(struct cpsw_ale *ale, u16 vid, int port_mask) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_vlan_del_modify); + + int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) + { +@@ -772,6 +779,7 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan); + + int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, + int untag_mask, int reg_mask, int unreg_mask) +@@ -811,6 +819,7 @@ int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_vlan_add_modify); + + void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, + bool add) +@@ -838,6 +847,7 @@ void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, + cpsw_ale_write(ale, idx, ale_entry); + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_set_unreg_mcast); + + static void cpsw_ale_vlan_set_unreg_mcast(struct cpsw_ale *ale, u32 *ale_entry, + int allmulti) +@@ -903,6 +913,7 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port) + cpsw_ale_write(ale, idx, ale_entry); + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti); + + struct ale_control_info { + const char *name; +@@ -1160,6 +1171,7 @@ int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_control_set); + + int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) + { +@@ -1183,6 +1195,7 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) + tmp = readl_relaxed(ale->params.ale_regs + offset) >> shift; + return tmp & BITMASK(info->bits); + } ++EXPORT_SYMBOL_GPL(cpsw_ale_control_get); + + int cpsw_ale_rx_ratelimit_mc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps) + +@@ -1205,6 +1218,7 @@ int cpsw_ale_rx_ratelimit_mc(struct cpsw_ale *ale, int port, unsigned int rateli + port, val * ALE_RATE_LIMIT_MIN_PPS); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_rx_ratelimit_mc); + + int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps) + +@@ -1227,6 +1241,7 @@ int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int rateli + port, val * ALE_RATE_LIMIT_MIN_PPS); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_rx_ratelimit_bc); + + static void cpsw_ale_timer(struct timer_list *t) + { +@@ -1316,6 +1331,7 @@ void cpsw_ale_start(struct cpsw_ale *ale) + + cpsw_ale_aging_start(ale); + } ++EXPORT_SYMBOL_GPL(cpsw_ale_start); + + void cpsw_ale_stop(struct cpsw_ale *ale) + { +@@ -1323,6 +1339,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale) + cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); + cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); + } ++EXPORT_SYMBOL_GPL(cpsw_ale_stop); + + static const struct reg_field ale_fields_cpsw[] = { + /* CPSW_ALE_IDVER_REG */ +@@ -1623,6 +1640,7 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) + cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); + return ale; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_create); + + void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) + { +@@ -1633,6 +1651,7 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) + data += ALE_ENTRY_WORDS; + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_dump); + + void cpsw_ale_restore(struct cpsw_ale *ale, u32 *data) + { +@@ -1643,11 +1662,13 @@ void cpsw_ale_restore(struct cpsw_ale *ale, u32 *data) + data += ALE_ENTRY_WORDS; + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_restore); + + u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale) + { + return ale ? ale->params.ale_entries : 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_get_num_entries); + + /* Reads the specified policer index into ALE POLICER registers */ + static void cpsw_ale_policer_read_idx(struct cpsw_ale *ale, u32 idx) +@@ -1750,3 +1771,7 @@ void cpsw_ale_classifier_setup_default(struct cpsw_ale *ale, int num_rx_ch) + 1); + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_classifier_setup_default); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("TI N-Port Ethernet Switch Address Lookup Engine"); +diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c +index bdc4db0d169c4..6350031e976f7 100644 +--- a/drivers/net/ethernet/ti/cpsw_ethtool.c ++++ b/drivers/net/ethernet/ti/cpsw_ethtool.c +@@ -144,6 +144,7 @@ u32 cpsw_get_msglevel(struct net_device *ndev) + + return priv->msg_enable; + } ++EXPORT_SYMBOL_GPL(cpsw_get_msglevel); + + void cpsw_set_msglevel(struct net_device *ndev, u32 value) + { +@@ -151,6 +152,7 @@ void cpsw_set_msglevel(struct net_device *ndev, u32 value) + + priv->msg_enable = value; + } ++EXPORT_SYMBOL_GPL(cpsw_set_msglevel); + + int cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, +@@ -161,6 +163,7 @@ int cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + coal->rx_coalesce_usecs = cpsw->coal_intvl; + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_coalesce); + + int cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, +@@ -220,6 +223,7 @@ int cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_set_coalesce); + + int cpsw_get_sset_count(struct net_device *ndev, int sset) + { +@@ -234,6 +238,7 @@ int cpsw_get_sset_count(struct net_device *ndev, int sset) + return -EOPNOTSUPP; + } + } ++EXPORT_SYMBOL_GPL(cpsw_get_sset_count); + + static void cpsw_add_ch_strings(u8 **p, int ch_num, int rx_dir) + { +@@ -271,6 +276,7 @@ void cpsw_get_strings(struct net_device *ndev, u32 stringset, u8 *data) + break; + } + } ++EXPORT_SYMBOL_GPL(cpsw_get_strings); + + void cpsw_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +@@ -303,6 +309,7 @@ void cpsw_get_ethtool_stats(struct net_device *ndev, + } + } + } ++EXPORT_SYMBOL_GPL(cpsw_get_ethtool_stats); + + void cpsw_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pause) +@@ -313,6 +320,7 @@ void cpsw_get_pauseparam(struct net_device *ndev, + pause->rx_pause = priv->rx_pause ? true : false; + pause->tx_pause = priv->tx_pause ? true : false; + } ++EXPORT_SYMBOL_GPL(cpsw_get_pauseparam); + + void cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + { +@@ -326,6 +334,7 @@ void cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + if (cpsw->slaves[slave_no].phy) + phy_ethtool_get_wol(cpsw->slaves[slave_no].phy, wol); + } ++EXPORT_SYMBOL_GPL(cpsw_get_wol); + + int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + { +@@ -338,6 +347,7 @@ int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + else + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_set_wol); + + int cpsw_get_regs_len(struct net_device *ndev) + { +@@ -346,6 +356,7 @@ int cpsw_get_regs_len(struct net_device *ndev) + return cpsw_ale_get_num_entries(cpsw->ale) * + ALE_ENTRY_WORDS * sizeof(u32); + } ++EXPORT_SYMBOL_GPL(cpsw_get_regs_len); + + void cpsw_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p) + { +@@ -357,6 +368,7 @@ void cpsw_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p) + + cpsw_ale_dump(cpsw->ale, reg); + } ++EXPORT_SYMBOL_GPL(cpsw_get_regs); + + int cpsw_ethtool_op_begin(struct net_device *ndev) + { +@@ -370,6 +382,7 @@ int cpsw_ethtool_op_begin(struct net_device *ndev) + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_ethtool_op_begin); + + void cpsw_ethtool_op_complete(struct net_device *ndev) + { +@@ -380,6 +393,7 @@ void cpsw_ethtool_op_complete(struct net_device *ndev) + if (ret < 0) + cpsw_err(priv, drv, "ethtool complete failed %d\n", ret); + } ++EXPORT_SYMBOL_GPL(cpsw_ethtool_op_complete); + + void cpsw_get_channels(struct net_device *ndev, struct ethtool_channels *ch) + { +@@ -394,6 +408,7 @@ void cpsw_get_channels(struct net_device *ndev, struct ethtool_channels *ch) + ch->tx_count = cpsw->tx_ch_num; + ch->combined_count = 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_channels); + + int cpsw_get_link_ksettings(struct net_device *ndev, + struct ethtool_link_ksettings *ecmd) +@@ -408,6 +423,7 @@ int cpsw_get_link_ksettings(struct net_device *ndev, + phy_ethtool_ksettings_get(cpsw->slaves[slave_no].phy, ecmd); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_link_ksettings); + + int cpsw_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *ecmd) +@@ -421,6 +437,7 @@ int cpsw_set_link_ksettings(struct net_device *ndev, + + return phy_ethtool_ksettings_set(cpsw->slaves[slave_no].phy, ecmd); + } ++EXPORT_SYMBOL_GPL(cpsw_set_link_ksettings); + + int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) + { +@@ -433,6 +450,7 @@ int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) + else + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_get_eee); + + int cpsw_nway_reset(struct net_device *ndev) + { +@@ -445,6 +463,7 @@ int cpsw_nway_reset(struct net_device *ndev) + else + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_nway_reset); + + static void cpsw_suspend_data_pass(struct net_device *ndev) + { +@@ -642,6 +661,7 @@ int cpsw_set_channels_common(struct net_device *ndev, + cpsw_fail(cpsw); + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_set_channels_common); + + void cpsw_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering, +@@ -657,6 +677,7 @@ void cpsw_get_ringparam(struct net_device *ndev, + ering->rx_max_pending = cpsw->descs_pool_size - CPSW_MAX_QUEUES; + ering->rx_pending = cpdma_get_num_rx_descs(cpsw->dma); + } ++EXPORT_SYMBOL_GPL(cpsw_get_ringparam); + + int cpsw_set_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering, +@@ -703,6 +724,7 @@ int cpsw_set_ringparam(struct net_device *ndev, + cpsw_fail(cpsw); + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_set_ringparam); + + #if IS_ENABLED(CONFIG_TI_CPTS) + int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *info) +@@ -723,6 +745,7 @@ int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *inf + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_ts_info); + #else + int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *info) + { +@@ -732,4 +755,5 @@ int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *inf + info->rx_filters = 0; + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_ts_info); + #endif +diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c +index c6eb6b785b0b5..1f6f374551cb6 100644 +--- a/drivers/net/ethernet/ti/cpsw_priv.c ++++ b/drivers/net/ethernet/ti/cpsw_priv.c +@@ -32,6 +32,7 @@ + #define CPTS_N_ETX_TS 4 + + int (*cpsw_slave_index)(struct cpsw_common *cpsw, struct cpsw_priv *priv); ++EXPORT_SYMBOL_GPL(cpsw_slave_index); + + void cpsw_intr_enable(struct cpsw_common *cpsw) + { +@@ -40,6 +41,7 @@ void cpsw_intr_enable(struct cpsw_common *cpsw) + + cpdma_ctlr_int_ctrl(cpsw->dma, true); + } ++EXPORT_SYMBOL_GPL(cpsw_intr_enable); + + void cpsw_intr_disable(struct cpsw_common *cpsw) + { +@@ -48,6 +50,7 @@ void cpsw_intr_disable(struct cpsw_common *cpsw) + + cpdma_ctlr_int_ctrl(cpsw->dma, false); + } ++EXPORT_SYMBOL_GPL(cpsw_intr_disable); + + void cpsw_tx_handler(void *token, int len, int status) + { +@@ -82,6 +85,7 @@ void cpsw_tx_handler(void *token, int len, int status) + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += len; + } ++EXPORT_SYMBOL_GPL(cpsw_tx_handler); + + irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) + { +@@ -98,6 +102,7 @@ irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) + napi_schedule(&cpsw->napi_tx); + return IRQ_HANDLED; + } ++EXPORT_SYMBOL_GPL(cpsw_tx_interrupt); + + irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) + { +@@ -114,6 +119,7 @@ irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) + napi_schedule(&cpsw->napi_rx); + return IRQ_HANDLED; + } ++EXPORT_SYMBOL_GPL(cpsw_rx_interrupt); + + irqreturn_t cpsw_misc_interrupt(int irq, void *dev_id) + { +@@ -126,6 +132,7 @@ irqreturn_t cpsw_misc_interrupt(int irq, void *dev_id) + + return IRQ_HANDLED; + } ++EXPORT_SYMBOL_GPL(cpsw_misc_interrupt); + + int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget) + { +@@ -158,6 +165,7 @@ int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget) + + return num_tx; + } ++EXPORT_SYMBOL_GPL(cpsw_tx_mq_poll); + + int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) + { +@@ -176,6 +184,7 @@ int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) + + return num_tx; + } ++EXPORT_SYMBOL_GPL(cpsw_tx_poll); + + int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget) + { +@@ -208,6 +217,7 @@ int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget) + + return num_rx; + } ++EXPORT_SYMBOL_GPL(cpsw_rx_mq_poll); + + int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) + { +@@ -226,6 +236,7 @@ int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) + + return num_rx; + } ++EXPORT_SYMBOL_GPL(cpsw_rx_poll); + + void cpsw_rx_vlan_encap(struct sk_buff *skb) + { +@@ -268,12 +279,14 @@ void cpsw_rx_vlan_encap(struct sk_buff *skb) + skb_pull(skb, VLAN_HLEN); + } + } ++EXPORT_SYMBOL_GPL(cpsw_rx_vlan_encap); + + void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv) + { + slave_write(slave, mac_hi(priv->mac_addr), SA_HI); + slave_write(slave, mac_lo(priv->mac_addr), SA_LO); + } ++EXPORT_SYMBOL_GPL(cpsw_set_slave_mac); + + void cpsw_soft_reset(const char *module, void __iomem *reg) + { +@@ -286,6 +299,7 @@ void cpsw_soft_reset(const char *module, void __iomem *reg) + + WARN(readl_relaxed(reg) & 1, "failed to soft-reset %s\n", module); + } ++EXPORT_SYMBOL_GPL(cpsw_soft_reset); + + void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) + { +@@ -305,6 +319,7 @@ void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) + netif_trans_update(ndev); + netif_tx_wake_all_queues(ndev); + } ++EXPORT_SYMBOL_GPL(cpsw_ndo_tx_timeout); + + static int cpsw_get_common_speed(struct cpsw_common *cpsw) + { +@@ -343,6 +358,7 @@ int cpsw_need_resplit(struct cpsw_common *cpsw) + + return 1; + } ++EXPORT_SYMBOL_GPL(cpsw_need_resplit); + + void cpsw_split_res(struct cpsw_common *cpsw) + { +@@ -428,6 +444,7 @@ void cpsw_split_res(struct cpsw_common *cpsw) + if (budget) + cpsw->rxv[0].budget += budget; + } ++EXPORT_SYMBOL_GPL(cpsw_split_res); + + int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, + int ale_ageout, phys_addr_t desc_mem_phys, +@@ -548,6 +565,7 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_init_common); + + #if IS_ENABLED(CONFIG_TI_CPTS) + +@@ -678,6 +696,7 @@ int cpsw_hwtstamp_set(struct net_device *dev, + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_hwtstamp_set); + + int cpsw_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *cfg) +@@ -695,12 +714,14 @@ int cpsw_hwtstamp_get(struct net_device *dev, + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_hwtstamp_get); + #else + int cpsw_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *cfg) + { + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_hwtstamp_set); + + int cpsw_hwtstamp_set(struct net_device *dev, + struct kernel_hwtstamp_config *cfg, +@@ -708,6 +729,7 @@ int cpsw_hwtstamp_set(struct net_device *dev, + { + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_hwtstamp_get); + #endif /*CONFIG_TI_CPTS*/ + + int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) +@@ -758,6 +780,7 @@ int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) + cpsw_split_res(cpsw); + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_ndo_set_tx_maxrate); + + static int cpsw_tc_to_fifo(int tc, int num_tc) + { +@@ -782,6 +805,7 @@ bool cpsw_shp_is_off(struct cpsw_priv *priv) + + return !val; + } ++EXPORT_SYMBOL_GPL(cpsw_shp_is_off); + + static void cpsw_fifo_shp_on(struct cpsw_priv *priv, int fifo, int on) + { +@@ -1043,6 +1067,7 @@ int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + return -EOPNOTSUPP; + } + } ++EXPORT_SYMBOL_GPL(cpsw_ndo_setup_tc); + + void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) + { +@@ -1056,6 +1081,7 @@ void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) + cpsw_set_fifo_rlimit(priv, fifo, bw); + } + } ++EXPORT_SYMBOL_GPL(cpsw_cbs_resume); + + void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) + { +@@ -1078,6 +1104,7 @@ void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) + + slave_write(slave, tx_prio_map, tx_prio_rg); + } ++EXPORT_SYMBOL_GPL(cpsw_mqprio_resume); + + int cpsw_fill_rx_channels(struct cpsw_priv *priv) + { +@@ -1123,6 +1150,7 @@ int cpsw_fill_rx_channels(struct cpsw_priv *priv) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_fill_rx_channels); + + static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw, + int size) +@@ -1208,6 +1236,7 @@ void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw) + cpsw->page_pool[ch] = NULL; + } + } ++EXPORT_SYMBOL_GPL(cpsw_destroy_xdp_rxqs); + + int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw) + { +@@ -1240,6 +1269,7 @@ int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw) + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_create_xdp_rxqs); + + static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf) + { +@@ -1267,6 +1297,7 @@ int cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf) + return -EINVAL; + } + } ++EXPORT_SYMBOL_GPL(cpsw_ndo_bpf); + + int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf, + struct page *page, int port) +@@ -1300,6 +1331,7 @@ int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf, + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_xdp_tx_frame); + + int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp, + struct page *page, int port, int *len) +@@ -1362,6 +1394,7 @@ int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp, + page_pool_recycle_direct(cpsw->page_pool[ch], page); + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_run_xdp); + + static int cpsw_qos_clsflower_add_policer(struct cpsw_priv *priv, + struct netlink_ext_ack *extack, +@@ -1564,3 +1597,7 @@ void cpsw_qos_clsflower_resume(struct cpsw_priv *priv) + cpsw_ale_rx_ratelimit_mc(priv->cpsw->ale, port_id, + priv->ale_mc_ratelimit.rate_packet_ps); + } ++EXPORT_SYMBOL_GPL(cpsw_qos_clsflower_resume); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("TI CPSW Ethernet Switch Driver"); +diff --git a/drivers/net/ethernet/ti/cpsw_sl.c b/drivers/net/ethernet/ti/cpsw_sl.c +index 0c7531cb0f398..761719a348fa5 100644 +--- a/drivers/net/ethernet/ti/cpsw_sl.c ++++ b/drivers/net/ethernet/ti/cpsw_sl.c +@@ -200,6 +200,7 @@ u32 cpsw_sl_reg_read(struct cpsw_sl *sl, enum cpsw_sl_regs reg) + dev_dbg(sl->dev, "cpsw_sl: reg: %04X r 0x%08X\n", sl->regs[reg], val); + return val; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_reg_read); + + void cpsw_sl_reg_write(struct cpsw_sl *sl, enum cpsw_sl_regs reg, u32 val) + { +@@ -212,6 +213,7 @@ void cpsw_sl_reg_write(struct cpsw_sl *sl, enum cpsw_sl_regs reg, u32 val) + dev_dbg(sl->dev, "cpsw_sl: reg: %04X w 0x%08X\n", sl->regs[reg], val); + writel(val, sl->sl_base + sl->regs[reg]); + } ++EXPORT_SYMBOL_GPL(cpsw_sl_reg_write); + + static const struct cpsw_sl_dev_id *cpsw_sl_match_id( + const struct cpsw_sl_dev_id *id, +@@ -252,6 +254,7 @@ struct cpsw_sl *cpsw_sl_get(const char *device_id, struct device *dev, + + return sl; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_get); + + void cpsw_sl_reset(struct cpsw_sl *sl, unsigned long tmo) + { +@@ -270,6 +273,7 @@ void cpsw_sl_reset(struct cpsw_sl *sl, unsigned long tmo) + if (cpsw_sl_reg_read(sl, CPSW_SL_SOFT_RESET) & CPSW_SL_SOFT_RESET_BIT) + dev_err(sl->dev, "cpsw_sl failed to soft-reset.\n"); + } ++EXPORT_SYMBOL_GPL(cpsw_sl_reset); + + u32 cpsw_sl_ctl_set(struct cpsw_sl *sl, u32 ctl_funcs) + { +@@ -287,6 +291,7 @@ u32 cpsw_sl_ctl_set(struct cpsw_sl *sl, u32 ctl_funcs) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_ctl_set); + + u32 cpsw_sl_ctl_clr(struct cpsw_sl *sl, u32 ctl_funcs) + { +@@ -304,11 +309,13 @@ u32 cpsw_sl_ctl_clr(struct cpsw_sl *sl, u32 ctl_funcs) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_ctl_clr); + + void cpsw_sl_ctl_reset(struct cpsw_sl *sl) + { + cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, 0); + } ++EXPORT_SYMBOL_GPL(cpsw_sl_ctl_reset); + + int cpsw_sl_wait_for_idle(struct cpsw_sl *sl, unsigned long tmo) + { +@@ -326,3 +333,7 @@ int cpsw_sl_wait_for_idle(struct cpsw_sl *sl, unsigned long tmo) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_wait_for_idle); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("TI Ethernet Switch media-access-controller (MAC) submodule"); +diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c +index d2eab5cd1e0c9..41e89a19be537 100644 +--- a/drivers/net/ethernet/ti/davinci_cpdma.c ++++ b/drivers/net/ethernet/ti/davinci_cpdma.c +@@ -531,6 +531,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params) + ctlr->num_chan = CPDMA_MAX_CHANNELS; + return ctlr; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_create); + + int cpdma_ctlr_start(struct cpdma_ctlr *ctlr) + { +@@ -591,6 +592,7 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr) + spin_unlock_irqrestore(&ctlr->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_start); + + int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) + { +@@ -623,6 +625,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) + spin_unlock_irqrestore(&ctlr->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_stop); + + int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) + { +@@ -640,6 +643,7 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) + cpdma_desc_pool_destroy(ctlr); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy); + + int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable) + { +@@ -660,21 +664,25 @@ int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable) + spin_unlock_irqrestore(&ctlr->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_int_ctrl); + + void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value) + { + dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, value); + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_eoi); + + u32 cpdma_ctrl_rxchs_state(struct cpdma_ctlr *ctlr) + { + return dma_reg_read(ctlr, CPDMA_RXINTSTATMASKED); + } ++EXPORT_SYMBOL_GPL(cpdma_ctrl_rxchs_state); + + u32 cpdma_ctrl_txchs_state(struct cpdma_ctlr *ctlr) + { + return dma_reg_read(ctlr, CPDMA_TXINTSTATMASKED); + } ++EXPORT_SYMBOL_GPL(cpdma_ctrl_txchs_state); + + static void cpdma_chan_set_descs(struct cpdma_ctlr *ctlr, + int rx, int desc_num, +@@ -802,6 +810,7 @@ int cpdma_chan_set_weight(struct cpdma_chan *ch, int weight) + spin_unlock_irqrestore(&ctlr->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_set_weight); + + /* cpdma_chan_get_min_rate - get minimum allowed rate for channel + * Should be called before cpdma_chan_set_rate. +@@ -816,6 +825,7 @@ u32 cpdma_chan_get_min_rate(struct cpdma_ctlr *ctlr) + + return DIV_ROUND_UP(divident, divisor); + } ++EXPORT_SYMBOL_GPL(cpdma_chan_get_min_rate); + + /* cpdma_chan_set_rate - limits bandwidth for transmit channel. + * The bandwidth * limited channels have to be in order beginning from lowest. +@@ -860,6 +870,7 @@ int cpdma_chan_set_rate(struct cpdma_chan *ch, u32 rate) + spin_unlock_irqrestore(&ctlr->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_set_rate); + + u32 cpdma_chan_get_rate(struct cpdma_chan *ch) + { +@@ -872,6 +883,7 @@ u32 cpdma_chan_get_rate(struct cpdma_chan *ch) + + return rate; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_get_rate); + + struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num, + cpdma_handler_fn handler, int rx_type) +@@ -931,6 +943,7 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num, + spin_unlock_irqrestore(&ctlr->lock, flags); + return chan; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_create); + + int cpdma_chan_get_rx_buf_num(struct cpdma_chan *chan) + { +@@ -943,6 +956,7 @@ int cpdma_chan_get_rx_buf_num(struct cpdma_chan *chan) + + return desc_num; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_get_rx_buf_num); + + int cpdma_chan_destroy(struct cpdma_chan *chan) + { +@@ -964,6 +978,7 @@ int cpdma_chan_destroy(struct cpdma_chan *chan) + spin_unlock_irqrestore(&ctlr->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_destroy); + + int cpdma_chan_get_stats(struct cpdma_chan *chan, + struct cpdma_chan_stats *stats) +@@ -976,6 +991,7 @@ int cpdma_chan_get_stats(struct cpdma_chan *chan, + spin_unlock_irqrestore(&chan->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_get_stats); + + static void __cpdma_chan_submit(struct cpdma_chan *chan, + struct cpdma_desc __iomem *desc) +@@ -1100,6 +1116,7 @@ int cpdma_chan_idle_submit(struct cpdma_chan *chan, void *token, void *data, + spin_unlock_irqrestore(&chan->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_idle_submit); + + int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token, + dma_addr_t data, int len, int directed) +@@ -1125,6 +1142,7 @@ int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token, + spin_unlock_irqrestore(&chan->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_idle_submit_mapped); + + int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, + int len, int directed) +@@ -1150,6 +1168,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, + spin_unlock_irqrestore(&chan->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_submit); + + int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token, + dma_addr_t data, int len, int directed) +@@ -1175,6 +1194,7 @@ int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token, + spin_unlock_irqrestore(&chan->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_submit_mapped); + + bool cpdma_check_free_tx_desc(struct cpdma_chan *chan) + { +@@ -1189,6 +1209,7 @@ bool cpdma_check_free_tx_desc(struct cpdma_chan *chan) + spin_unlock_irqrestore(&chan->lock, flags); + return free_tx_desc; + } ++EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc); + + static void __cpdma_chan_free(struct cpdma_chan *chan, + struct cpdma_desc __iomem *desc, +@@ -1289,6 +1310,7 @@ int cpdma_chan_process(struct cpdma_chan *chan, int quota) + } + return used; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_process); + + int cpdma_chan_start(struct cpdma_chan *chan) + { +@@ -1308,6 +1330,7 @@ int cpdma_chan_start(struct cpdma_chan *chan) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_start); + + int cpdma_chan_stop(struct cpdma_chan *chan) + { +@@ -1370,6 +1393,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan) + spin_unlock_irqrestore(&chan->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_stop); + + int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable) + { +@@ -1416,11 +1440,13 @@ int cpdma_get_num_rx_descs(struct cpdma_ctlr *ctlr) + { + return ctlr->num_rx_desc; + } ++EXPORT_SYMBOL_GPL(cpdma_get_num_rx_descs); + + int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr) + { + return ctlr->num_tx_desc; + } ++EXPORT_SYMBOL_GPL(cpdma_get_num_tx_descs); + + int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc) + { +@@ -1442,3 +1468,4 @@ int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc) + + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_set_num_rx_descs); +-- +2.53.0 + diff --git a/queue-6.18/net-ethernet-ti-cpsw-rename-soft_reset-function.patch b/queue-6.18/net-ethernet-ti-cpsw-rename-soft_reset-function.patch new file mode 100644 index 0000000000..2c5809325a --- /dev/null +++ b/queue-6.18/net-ethernet-ti-cpsw-rename-soft_reset-function.patch @@ -0,0 +1,82 @@ +From 690bf9e338d6e2f8564f3ef83f9e06f00809477e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:46:53 +0200 +Subject: net: ethernet: ti-cpsw:: rename soft_reset() function + +From: Arnd Bergmann + +[ Upstream commit 961f3c535608df64553f61d64ca086aa9f371bdd ] + +While looking at the glob symbols shared between the cpsw drivers, +I noticed that soft_reset() is the only one that is missing a proper +namespace prefix, and will pollute the kernel namespace, so rename +it to be consistent with the other symbols. + +Reviewed-by: Alexander Sverdlin +Signed-off-by: Arnd Bergmann +Link: https://patch.msgid.link/20260402184726.3746487-1-arnd@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: df75bd552a87 ("net: ethernet: ti-cpsw: fix linking built-in code to modules") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/cpsw.c | 2 +- + drivers/net/ethernet/ti/cpsw_new.c | 2 +- + drivers/net/ethernet/ti/cpsw_priv.c | 2 +- + drivers/net/ethernet/ti/cpsw_priv.h | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c +index b0e18bdc2c851..aa3531e844e87 100644 +--- a/drivers/net/ethernet/ti/cpsw.c ++++ b/drivers/net/ethernet/ti/cpsw.c +@@ -706,7 +706,7 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) + struct cpsw_common *cpsw = priv->cpsw; + + /* soft reset the controller and initialize ale */ +- soft_reset("cpsw", &cpsw->regs->soft_reset); ++ cpsw_soft_reset("cpsw", &cpsw->regs->soft_reset); + cpsw_ale_start(cpsw->ale); + + /* switch to vlan aware mode */ +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index fd3931d667021..c6cf7a0375e08 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -573,7 +573,7 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) + u32 control_reg; + + /* soft reset the controller and initialize ale */ +- soft_reset("cpsw", &cpsw->regs->soft_reset); ++ cpsw_soft_reset("cpsw", &cpsw->regs->soft_reset); + cpsw_ale_start(cpsw->ale); + + /* switch to vlan aware mode */ +diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c +index bc4fdf17a99ec..c6eb6b785b0b5 100644 +--- a/drivers/net/ethernet/ti/cpsw_priv.c ++++ b/drivers/net/ethernet/ti/cpsw_priv.c +@@ -275,7 +275,7 @@ void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv) + slave_write(slave, mac_lo(priv->mac_addr), SA_LO); + } + +-void soft_reset(const char *module, void __iomem *reg) ++void cpsw_soft_reset(const char *module, void __iomem *reg) + { + unsigned long timeout = jiffies + HZ; + +diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h +index acb6181c5c9e1..fddd7a79f4b0f 100644 +--- a/drivers/net/ethernet/ti/cpsw_priv.h ++++ b/drivers/net/ethernet/ti/cpsw_priv.h +@@ -458,7 +458,7 @@ int cpsw_tx_poll(struct napi_struct *napi_tx, int budget); + int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget); + int cpsw_rx_poll(struct napi_struct *napi_rx, int budget); + void cpsw_rx_vlan_encap(struct sk_buff *skb); +-void soft_reset(const char *module, void __iomem *reg); ++void cpsw_soft_reset(const char *module, void __iomem *reg); + void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv); + void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue); + int cpsw_need_resplit(struct cpsw_common *cpsw); +-- +2.53.0 + diff --git a/queue-6.18/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch b/queue-6.18/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch new file mode 100644 index 0000000000..6187b5a920 --- /dev/null +++ b/queue-6.18/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch @@ -0,0 +1,71 @@ +From 713052fae0ac6a67c5d7ad45d95c1e22168c2aeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:31:01 +0800 +Subject: net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf + +From: Mashiro Chen + +[ Upstream commit bf9a38803b2626b01cc769aaf13485d8650f576f ] + +sixpack_receive_buf() does not properly skip bytes with TTY error flags. +The while loop iterates through the flags buffer but never advances the +data pointer (cp), and passes the original count (including error bytes) +to sixpack_decode(). This causes sixpack_decode() to process bytes that +should have been skipped due to TTY errors. The TTY layer does not +guarantee that cp[i] holds a meaningful value when fp[i] is set, so +passing those positions to sixpack_decode() results in KMSAN reporting +an uninit-value read. + +Fix this by processing bytes one at a time, advancing cp on each +iteration, and only passing valid (non-error) bytes to sixpack_decode(). +This matches the pattern used by slip_receive_buf() and +mkiss_receive_buf() for the same purpose. + +Reported-by: syzbot+ecdb8c9878a81eb21e54@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ecdb8c9878a81eb21e54 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Mashiro Chen +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260407173101.107352-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 885992951e8a6..c8b2dc5c1becc 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -391,7 +391,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + const u8 *fp, size_t count) + { + struct sixpack *sp; +- size_t count1; + + if (!count) + return; +@@ -401,16 +400,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + return; + + /* Read the characters out of the buffer */ +- count1 = count; +- while (count) { +- count--; ++ while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) + sp->dev->stats.rx_errors++; ++ cp++; + continue; + } ++ sixpack_decode(sp, cp, 1); ++ cp++; + } +- sixpack_decode(sp, cp, count1); + + tty_unthrottle(tty); + } +-- +2.53.0 + diff --git a/queue-6.18/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch b/queue-6.18/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch new file mode 100644 index 0000000000..96727da097 --- /dev/null +++ b/queue-6.18/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch @@ -0,0 +1,42 @@ +From da0582c1856202547ceda58f1173ee2497dcacd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:13:32 +0200 +Subject: net: ipa: Fix decoding EV_PER_EE for IPA v5.0+ + +From: Luca Weiss + +[ Upstream commit 1335b903cf2e8aeaca87fd665683384c731ec941 ] + +Initially 'reg' and 'val' are assigned from HW_PARAM_2. + +But since IPA v5.0+ takes EV_PER_EE from HW_PARAM_4 (instead of +NUM_EV_PER_EE from HW_PARAM_2), we not only need to re-assign 'reg' but +also read the register value of that register into 'val' so that +reg_decode() works on the correct value. + +Fixes: f651334e1ef5 ("net: ipa: add HW_PARAM_4 GSI register") +Link: https://sashiko.dev/#/patchset/20260403-milos-ipa-v1-0-01e9e4e03d3e%40fairphone.com?part=2 +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260409-ipa-fixes-v1-2-a817c30678ac@fairphone.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ipa/gsi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c +index 4c3227e77898c..624649484d627 100644 +--- a/drivers/net/ipa/gsi.c ++++ b/drivers/net/ipa/gsi.c +@@ -2044,6 +2044,7 @@ static int gsi_ring_setup(struct gsi *gsi) + count = reg_decode(reg, NUM_EV_PER_EE, val); + } else { + reg = gsi_reg(gsi, HW_PARAM_4); ++ val = ioread32(gsi->virt + reg_offset(reg)); + count = reg_decode(reg, EV_PER_EE, val); + } + if (!count) { +-- +2.53.0 + diff --git a/queue-6.18/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch b/queue-6.18/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch new file mode 100644 index 0000000000..a3f5bc3e8f --- /dev/null +++ b/queue-6.18/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch @@ -0,0 +1,51 @@ +From 4360d4fc4e0065a6bea7b1b0e126c9962bfa74dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:13:31 +0200 +Subject: net: ipa: Fix programming of QTIME_TIMESTAMP_CFG + +From: Luca Weiss + +[ Upstream commit de08f9585692813bd41ee654fca0487664c4de30 ] + +The 'val' variable gets overwritten multiple times, discarding previous +values. Looking at the git log shows these should be combined with |= +instead. + +Fixes: 9265a4f0f0b4 ("net: ipa: define even more IPA register fields") +Link: https://sashiko.dev/#/patchset/20260403-milos-ipa-v1-0-01e9e4e03d3e%40fairphone.com?part=4 +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260409-ipa-fixes-v1-1-a817c30678ac@fairphone.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ipa/ipa_main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c +index 25500c5a6928e..30fe12e3582b2 100644 +--- a/drivers/net/ipa/ipa_main.c ++++ b/drivers/net/ipa/ipa_main.c +@@ -361,7 +361,7 @@ static void ipa_qtime_config(struct ipa *ipa) + { + const struct reg *reg; + u32 offset; +- u32 val; ++ u32 val = 0; + + /* Timer clock divider must be disabled when we change the rate */ + reg = ipa_reg(ipa, TIMERS_XO_CLK_DIV_CFG); +@@ -374,8 +374,8 @@ static void ipa_qtime_config(struct ipa *ipa) + val |= reg_bit(reg, DPL_TIMESTAMP_SEL); + } + /* Configure tag and NAT Qtime timestamp resolution as well */ +- val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); +- val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); ++ val |= reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); ++ val |= reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); + + iowrite32(val, ipa->reg_virt + reg_offset(reg)); + +-- +2.53.0 + diff --git a/queue-6.18/net-mana-add-standard-counter-rx_missed_errors.patch b/queue-6.18/net-mana-add-standard-counter-rx_missed_errors.patch new file mode 100644 index 0000000000..20197452d2 --- /dev/null +++ b/queue-6.18/net-mana-add-standard-counter-rx_missed_errors.patch @@ -0,0 +1,194 @@ +From b046a9c5a68799278c5ca4b51c83469e8ffa943c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Nov 2025 03:43:19 -0800 +Subject: net: mana: Add standard counter rx_missed_errors + +From: Erni Sri Satya Vennela + +[ Upstream commit be4f1d67ec56f23f37714ac73c01094e63c7ff28 ] + +Report standard counter stats->rx_missed_errors +using hc_rx_discards_no_wqe from the hardware. + +Add a global workqueue to periodically run +mana_query_gf_stats every 2 seconds to get the latest +info in eth_stats and define a driver capability flag +to notify hardware of the periodic queries. + +To avoid repeated failures and log flooding, the workqueue +is not rescheduled if mana_query_gf_stats fails on HWC timeout +error and the stats are reset to 0. Other errors are transient +which will not need a VF reset for recovery. + +Signed-off-by: Erni Sri Satya Vennela +Reviewed-by: Haiyang Zhang +Link: https://patch.msgid.link/1763120599-6331-3-git-send-email-ernis@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: a7fdaf069bd0 ("net: mana: Don't overwrite port probe error with add_adev result") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 36 +++++++++++++++++-- + .../ethernet/microsoft/mana/mana_ethtool.c | 2 -- + include/net/mana/gdma.h | 6 +++- + include/net/mana/mana.h | 6 +++- + 4 files changed, 43 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 2e5efc03cacec..b0d411ab1067f 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -534,6 +534,11 @@ static void mana_get_stats64(struct net_device *ndev, + + netdev_stats_to_stats64(st, &ndev->stats); + ++ if (apc->ac->hwc_timeout_occurred) ++ netdev_warn_once(ndev, "HWC timeout occurred\n"); ++ ++ st->rx_missed_errors = apc->ac->hc_stats.hc_rx_discards_no_wqe; ++ + for (q = 0; q < num_queues; q++) { + rx_stats = &apc->rxqs[q]->stats; + +@@ -2836,7 +2841,7 @@ int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx, + return 0; + } + +-void mana_query_gf_stats(struct mana_context *ac) ++int mana_query_gf_stats(struct mana_context *ac) + { + struct gdma_context *gc = ac->gdma_dev->gdma_context; + struct mana_query_gf_stat_resp resp = {}; +@@ -2879,14 +2884,14 @@ void mana_query_gf_stats(struct mana_context *ac) + sizeof(resp)); + if (err) { + dev_err(dev, "Failed to query GF stats: %d\n", err); +- return; ++ return err; + } + err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_GF_STAT, + sizeof(resp)); + if (err || resp.hdr.status) { + dev_err(dev, "Failed to query GF stats: %d, 0x%x\n", err, + resp.hdr.status); +- return; ++ return err; + } + + ac->hc_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe; +@@ -2921,6 +2926,8 @@ void mana_query_gf_stats(struct mana_context *ac) + ac->hc_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts; + ac->hc_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes; + ac->hc_stats.hc_tx_err_gdma = resp.tx_err_gdma; ++ ++ return 0; + } + + void mana_query_phy_stats(struct mana_port_context *apc) +@@ -3459,6 +3466,24 @@ int mana_rdma_service_event(struct gdma_context *gc, enum gdma_service_type even + return 0; + } + ++#define MANA_GF_STATS_PERIOD (2 * HZ) ++ ++static void mana_gf_stats_work_handler(struct work_struct *work) ++{ ++ struct mana_context *ac = ++ container_of(to_delayed_work(work), struct mana_context, gf_stats_work); ++ int err; ++ ++ err = mana_query_gf_stats(ac); ++ if (err == -ETIMEDOUT) { ++ /* HWC timeout detected - reset stats and stop rescheduling */ ++ ac->hwc_timeout_occurred = true; ++ memset(&ac->hc_stats, 0, sizeof(ac->hc_stats)); ++ return; ++ } ++ schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD); ++} ++ + int mana_probe(struct gdma_dev *gd, bool resuming) + { + struct gdma_context *gc = gd->gdma_context; +@@ -3551,6 +3576,10 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + } + + err = add_adev(gd, "eth"); ++ ++ INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler); ++ schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD); ++ + out: + if (err) { + mana_remove(gd, false); +@@ -3580,6 +3609,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + dev = gc->dev; + + disable_work_sync(&ac->link_change_work); ++ cancel_delayed_work_sync(&ac->gf_stats_work); + + /* adev currently doesn't support suspending, always remove it */ + if (gd->adev) +diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +index 3dfd96146424e..99e8112086833 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +@@ -213,8 +213,6 @@ static void mana_get_ethtool_stats(struct net_device *ndev, + + if (!apc->port_is_up) + return; +- /* we call mana function to update stats from GDMA */ +- mana_query_gf_stats(apc->ac); + + /* We call this mana function to get the phy stats from GDMA and includes + * aggregate tx/rx drop counters, Per-TC(Traffic Channel) tx/rx and pause +diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h +index 637f42485dba6..2e4f2f3175e55 100644 +--- a/include/net/mana/gdma.h ++++ b/include/net/mana/gdma.h +@@ -592,6 +592,9 @@ enum { + #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17) + #define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6) + ++/* Driver can send HWC periodically to query stats */ ++#define GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY BIT(21) ++ + #define GDMA_DRV_CAP_FLAGS1 \ + (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \ + GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \ +@@ -601,7 +604,8 @@ enum { + GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \ + GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \ + GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \ +- GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE) ++ GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \ ++ GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY) + + #define GDMA_DRV_CAP_FLAGS2 0 + +diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h +index 265f2d90027d6..7e946239effa9 100644 +--- a/include/net/mana/mana.h ++++ b/include/net/mana/mana.h +@@ -480,6 +480,10 @@ struct mana_context { + struct mana_eq *eqs; + struct dentry *mana_eqs_debugfs; + ++ /* Workqueue for querying hardware stats */ ++ struct delayed_work gf_stats_work; ++ bool hwc_timeout_occurred; ++ + struct net_device *ports[MAX_PORTS_IN_MANA_DEV]; + + /* Link state change work */ +@@ -582,7 +586,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq, + struct bpf_prog *mana_xdp_get(struct mana_port_context *apc); + void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog); + int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf); +-void mana_query_gf_stats(struct mana_context *ac); ++int mana_query_gf_stats(struct mana_context *ac); + int mana_query_link_cfg(struct mana_port_context *apc); + int mana_set_bw_clamp(struct mana_port_context *apc, u32 speed, + int enable_clamping); +-- +2.53.0 + diff --git a/queue-6.18/net-mana-don-t-overwrite-port-probe-error-with-add_a.patch b/queue-6.18/net-mana-don-t-overwrite-port-probe-error-with-add_a.patch new file mode 100644 index 0000000000..663cff412a --- /dev/null +++ b/queue-6.18/net-mana-don-t-overwrite-port-probe-error-with-add_a.patch @@ -0,0 +1,73 @@ +From 87f794d672469e6b7e67dcc619448b544c6cf29e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:38 -0700 +Subject: net: mana: Don't overwrite port probe error with add_adev result + +From: Erni Sri Satya Vennela + +[ Upstream commit a7fdaf069bd031fcc234581fa6a580be11bf2175 ] + +In mana_probe(), if mana_probe_port() fails for any port, the error +is stored in 'err' and the loop breaks. However, the subsequent +unconditional 'err = add_adev(gd, "eth")' overwrites this error. +If add_adev() succeeds, mana_probe() returns success despite ports +being left in a partially initialized state (ac->ports[i] == NULL). + +Only call add_adev() when there is no prior error, so the probe +correctly fails and triggers mana_remove() cleanup. + +Fixes: a69839d4327d ("net: mana: Add support for auxiliary device") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-5-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index b0d411ab1067f..02090edbd103f 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3548,10 +3548,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + if (!resuming) { + for (i = 0; i < ac->num_ports; i++) { + err = mana_probe_port(ac, i, &ac->ports[i]); +- /* we log the port for which the probe failed and stop +- * probes for subsequent ports. +- * Note that we keep running ports, for which the probes +- * were successful, unless add_adev fails too ++ /* Log the port for which the probe failed, stop probing ++ * subsequent ports, and skip add_adev. ++ * mana_remove() will clean up already-probed ports. + */ + if (err) { + dev_err(dev, "Probe Failed for port %d\n", i); +@@ -3563,10 +3562,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + rtnl_lock(); + err = mana_attach(ac->ports[i]); + rtnl_unlock(); +- /* we log the port for which the attach failed and stop +- * attach for subsequent ports +- * Note that we keep running ports, for which the attach +- * were successful, unless add_adev fails too ++ /* Log the port for which the attach failed, stop ++ * attaching subsequent ports, and skip add_adev. ++ * mana_remove() will clean up already-attached ports. + */ + if (err) { + dev_err(dev, "Attach Failed for port %d\n", i); +@@ -3575,7 +3573,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + } + } + +- err = add_adev(gd, "eth"); ++ if (!err) ++ err = add_adev(gd, "eth"); + + INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler); + schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD); +-- +2.53.0 + diff --git a/queue-6.18/net-mana-fix-eq-leak-in-mana_remove-on-null-port.patch b/queue-6.18/net-mana-fix-eq-leak-in-mana_remove-on-null-port.patch new file mode 100644 index 0000000000..c0627b5d8f --- /dev/null +++ b/queue-6.18/net-mana-fix-eq-leak-in-mana_remove-on-null-port.patch @@ -0,0 +1,56 @@ +From 51160df1e92aba8ad447f9ccdfb9d46769f04b43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:39 -0700 +Subject: net: mana: Fix EQ leak in mana_remove on NULL port + +From: Erni Sri Satya Vennela + +[ Upstream commit 65267c9c4f28199985505977bc2c628c82fc50ef ] + +In mana_remove(), when a NULL port is encountered in the port iteration +loop, 'goto out' skips the mana_destroy_eq(ac) call, leaking the event +queues allocated earlier by mana_create_eq(). + +This can happen when mana_probe_port() fails for port 0, leaving +ac->ports[0] as NULL. On driver unload or error cleanup, mana_remove() +hits the NULL entry and jumps past mana_destroy_eq(). + +Change 'goto out' to 'break' so the for-loop exits normally and +mana_destroy_eq() is always reached. Remove the now-unreferenced out: +label. + +Fixes: 1e2d0824a9c3 ("net: mana: Add support for EQ sharing") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-6-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 12952f7273eb6..4b7e5acba7f76 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3723,7 +3723,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + if (!ndev) { + if (i == 0) + dev_err(dev, "No net device to remove\n"); +- goto out; ++ break; + } + + apc = netdev_priv(ndev); +@@ -3754,7 +3754,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + } + + mana_destroy_eq(ac); +-out: ++ + if (ac->per_port_queue_reset_wq) { + destroy_workqueue(ac->per_port_queue_reset_wq); + ac->per_port_queue_reset_wq = NULL; +-- +2.53.0 + diff --git a/queue-6.18/net-mana-guard-mana_remove-against-double-invocation.patch b/queue-6.18/net-mana-guard-mana_remove-against-double-invocation.patch new file mode 100644 index 0000000000..5099dc3759 --- /dev/null +++ b/queue-6.18/net-mana-guard-mana_remove-against-double-invocation.patch @@ -0,0 +1,57 @@ +From 7138a3696aa089de71175ed763a1d7a7e162dff0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:37 -0700 +Subject: net: mana: Guard mana_remove against double invocation + +From: Erni Sri Satya Vennela + +[ Upstream commit 50271d7ec95144d26808025b508f463780517d3c ] + +If PM resume fails (e.g., mana_attach() returns an error), mana_probe() +calls mana_remove(), which tears down the device and sets +gd->gdma_context = NULL and gd->driver_data = NULL. + +However, a failed resume callback does not automatically unbind the +driver. When the device is eventually unbound, mana_remove() is invoked +a second time. Without a NULL check, it dereferences gc->dev with +gc == NULL, causing a kernel panic. + +Add an early return if gdma_context or driver_data is NULL so the second +invocation is harmless. Move the dev = gc->dev assignment after the +guard so it cannot dereference NULL. + +Fixes: 635096a86edb ("net: mana: Support hibernation and kexec") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-4-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index cd3a435485a19..d90be4142e257 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3568,11 +3568,16 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + struct gdma_context *gc = gd->gdma_context; + struct mana_context *ac = gd->driver_data; + struct mana_port_context *apc; +- struct device *dev = gc->dev; ++ struct device *dev; + struct net_device *ndev; + int err; + int i; + ++ if (!gc || !ac) ++ return; ++ ++ dev = gc->dev; ++ + disable_work_sync(&ac->link_change_work); + + /* adev currently doesn't support suspending, always remove it */ +-- +2.53.0 + diff --git a/queue-6.18/net-mana-handle-hardware-recovery-events-when-probin.patch b/queue-6.18/net-mana-handle-hardware-recovery-events-when-probin.patch new file mode 100644 index 0000000000..ad4a752108 --- /dev/null +++ b/queue-6.18/net-mana-handle-hardware-recovery-events-when-probin.patch @@ -0,0 +1,338 @@ +From 88c9ed975d917bab426b6b850626d97a5cb2d6ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 13:45:52 -0800 +Subject: net: mana: Handle hardware recovery events when probing the device + +From: Long Li + +[ Upstream commit 9bf66036d686b9a67000ba22bd94be13a4ea79ac ] + +When MANA is being probed, it's possible that hardware is in recovery +mode and the device may get GDMA_EQE_HWC_RESET_REQUEST over HWC in the +middle of the probe. Detect such condition and go through the recovery +service procedure. + +Signed-off-by: Long Li +Reviewed-by: Haiyang Zhang +Link: https://patch.msgid.link/1764193552-9712-1-git-send-email-longli@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 65267c9c4f28 ("net: mana: Fix EQ leak in mana_remove on NULL port") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/microsoft/mana/gdma_main.c | 176 ++++++++++++++++-- + include/net/mana/gdma.h | 12 +- + 2 files changed, 170 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c +index d93cfb7f4e788..0ad082b566f5e 100644 +--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c ++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c +@@ -15,6 +15,20 @@ + + struct dentry *mana_debugfs_root; + ++struct mana_dev_recovery { ++ struct list_head list; ++ struct pci_dev *pdev; ++ enum gdma_eqe_type type; ++}; ++ ++static struct mana_dev_recovery_work { ++ struct list_head dev_list; ++ struct delayed_work work; ++ ++ /* Lock for dev_list above */ ++ spinlock_t lock; ++} mana_dev_recovery_work; ++ + static u32 mana_gd_r32(struct gdma_context *g, u64 offset) + { + return readl(g->bar0_va + offset); +@@ -387,6 +401,25 @@ EXPORT_SYMBOL_NS(mana_gd_ring_cq, "NET_MANA"); + + #define MANA_SERVICE_PERIOD 10 + ++static void mana_serv_rescan(struct pci_dev *pdev) ++{ ++ struct pci_bus *parent; ++ ++ pci_lock_rescan_remove(); ++ ++ parent = pdev->bus; ++ if (!parent) { ++ dev_err(&pdev->dev, "MANA service: no parent bus\n"); ++ goto out; ++ } ++ ++ pci_stop_and_remove_bus_device(pdev); ++ pci_rescan_bus(parent); ++ ++out: ++ pci_unlock_rescan_remove(); ++} ++ + static void mana_serv_fpga(struct pci_dev *pdev) + { + struct pci_bus *bus, *parent; +@@ -419,9 +452,12 @@ static void mana_serv_reset(struct pci_dev *pdev) + { + struct gdma_context *gc = pci_get_drvdata(pdev); + struct hw_channel_context *hwc; ++ int ret; + + if (!gc) { +- dev_err(&pdev->dev, "MANA service: no GC\n"); ++ /* Perform PCI rescan on device if GC is not set up */ ++ dev_err(&pdev->dev, "MANA service: GC not setup, rescanning\n"); ++ mana_serv_rescan(pdev); + return; + } + +@@ -440,9 +476,18 @@ static void mana_serv_reset(struct pci_dev *pdev) + + msleep(MANA_SERVICE_PERIOD * 1000); + +- mana_gd_resume(pdev); ++ ret = mana_gd_resume(pdev); ++ if (ret == -ETIMEDOUT || ret == -EPROTO) { ++ /* Perform PCI rescan on device if we failed on HWC */ ++ dev_err(&pdev->dev, "MANA service: resume failed, rescanning\n"); ++ mana_serv_rescan(pdev); ++ goto out; ++ } + +- dev_info(&pdev->dev, "MANA reset cycle completed\n"); ++ if (ret) ++ dev_info(&pdev->dev, "MANA reset cycle failed err %d\n", ret); ++ else ++ dev_info(&pdev->dev, "MANA reset cycle completed\n"); + + out: + gc->in_service = false; +@@ -454,18 +499,9 @@ struct mana_serv_work { + enum gdma_eqe_type type; + }; + +-static void mana_serv_func(struct work_struct *w) ++static void mana_do_service(enum gdma_eqe_type type, struct pci_dev *pdev) + { +- struct mana_serv_work *mns_wk; +- struct pci_dev *pdev; +- +- mns_wk = container_of(w, struct mana_serv_work, serv_work); +- pdev = mns_wk->pdev; +- +- if (!pdev) +- goto out; +- +- switch (mns_wk->type) { ++ switch (type) { + case GDMA_EQE_HWC_FPGA_RECONFIG: + mana_serv_fpga(pdev); + break; +@@ -475,12 +511,48 @@ static void mana_serv_func(struct work_struct *w) + break; + + default: +- dev_err(&pdev->dev, "MANA service: unknown type %d\n", +- mns_wk->type); ++ dev_err(&pdev->dev, "MANA service: unknown type %d\n", type); + break; + } ++} ++ ++static void mana_recovery_delayed_func(struct work_struct *w) ++{ ++ struct mana_dev_recovery_work *work; ++ struct mana_dev_recovery *dev; ++ unsigned long flags; ++ ++ work = container_of(w, struct mana_dev_recovery_work, work.work); ++ ++ spin_lock_irqsave(&work->lock, flags); ++ ++ while (!list_empty(&work->dev_list)) { ++ dev = list_first_entry(&work->dev_list, ++ struct mana_dev_recovery, list); ++ list_del(&dev->list); ++ spin_unlock_irqrestore(&work->lock, flags); ++ ++ mana_do_service(dev->type, dev->pdev); ++ pci_dev_put(dev->pdev); ++ kfree(dev); ++ ++ spin_lock_irqsave(&work->lock, flags); ++ } ++ ++ spin_unlock_irqrestore(&work->lock, flags); ++} ++ ++static void mana_serv_func(struct work_struct *w) ++{ ++ struct mana_serv_work *mns_wk; ++ struct pci_dev *pdev; ++ ++ mns_wk = container_of(w, struct mana_serv_work, serv_work); ++ pdev = mns_wk->pdev; ++ ++ if (pdev) ++ mana_do_service(mns_wk->type, pdev); + +-out: + pci_dev_put(pdev); + kfree(mns_wk); + module_put(THIS_MODULE); +@@ -541,6 +613,17 @@ static void mana_gd_process_eqe(struct gdma_queue *eq) + case GDMA_EQE_HWC_RESET_REQUEST: + dev_info(gc->dev, "Recv MANA service type:%d\n", type); + ++ if (!test_and_set_bit(GC_PROBE_SUCCEEDED, &gc->flags)) { ++ /* ++ * Device is in probe and we received a hardware reset ++ * event, the probe function will detect that the flag ++ * has changed and perform service procedure. ++ */ ++ dev_info(gc->dev, ++ "Service is to be processed in probe\n"); ++ break; ++ } ++ + if (gc->in_service) { + dev_info(gc->dev, "Already in service\n"); + break; +@@ -1943,8 +2026,19 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + if (err) + goto cleanup_mana; + ++ /* ++ * If a hardware reset event has occurred over HWC during probe, ++ * rollback and perform hardware reset procedure. ++ */ ++ if (test_and_set_bit(GC_PROBE_SUCCEEDED, &gc->flags)) { ++ err = -EPROTO; ++ goto cleanup_mana_rdma; ++ } ++ + return 0; + ++cleanup_mana_rdma: ++ mana_rdma_remove(&gc->mana_ib); + cleanup_mana: + mana_remove(&gc->mana, false); + cleanup_gd: +@@ -1968,6 +2062,35 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + disable_dev: + pci_disable_device(pdev); + dev_err(&pdev->dev, "gdma probe failed: err = %d\n", err); ++ ++ /* ++ * Hardware could be in recovery mode and the HWC returns TIMEDOUT or ++ * EPROTO from mana_gd_setup(), mana_probe() or mana_rdma_probe(), or ++ * we received a hardware reset event over HWC interrupt. In this case, ++ * perform the device recovery procedure after MANA_SERVICE_PERIOD ++ * seconds. ++ */ ++ if (err == -ETIMEDOUT || err == -EPROTO) { ++ struct mana_dev_recovery *dev; ++ unsigned long flags; ++ ++ dev_info(&pdev->dev, "Start MANA recovery mode\n"); ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return err; ++ ++ dev->pdev = pci_dev_get(pdev); ++ dev->type = GDMA_EQE_HWC_RESET_REQUEST; ++ ++ spin_lock_irqsave(&mana_dev_recovery_work.lock, flags); ++ list_add_tail(&dev->list, &mana_dev_recovery_work.dev_list); ++ spin_unlock_irqrestore(&mana_dev_recovery_work.lock, flags); ++ ++ schedule_delayed_work(&mana_dev_recovery_work.work, ++ secs_to_jiffies(MANA_SERVICE_PERIOD)); ++ } ++ + return err; + } + +@@ -2072,6 +2195,10 @@ static int __init mana_driver_init(void) + { + int err; + ++ INIT_LIST_HEAD(&mana_dev_recovery_work.dev_list); ++ spin_lock_init(&mana_dev_recovery_work.lock); ++ INIT_DELAYED_WORK(&mana_dev_recovery_work.work, mana_recovery_delayed_func); ++ + mana_debugfs_root = debugfs_create_dir("mana", NULL); + + err = pci_register_driver(&mana_driver); +@@ -2085,6 +2212,21 @@ static int __init mana_driver_init(void) + + static void __exit mana_driver_exit(void) + { ++ struct mana_dev_recovery *dev; ++ unsigned long flags; ++ ++ disable_delayed_work_sync(&mana_dev_recovery_work.work); ++ ++ spin_lock_irqsave(&mana_dev_recovery_work.lock, flags); ++ while (!list_empty(&mana_dev_recovery_work.dev_list)) { ++ dev = list_first_entry(&mana_dev_recovery_work.dev_list, ++ struct mana_dev_recovery, list); ++ list_del(&dev->list); ++ pci_dev_put(dev->pdev); ++ kfree(dev); ++ } ++ spin_unlock_irqrestore(&mana_dev_recovery_work.lock, flags); ++ + pci_unregister_driver(&mana_driver); + + debugfs_remove(mana_debugfs_root); +diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h +index a4cf307859f85..eaa27483f99b2 100644 +--- a/include/net/mana/gdma.h ++++ b/include/net/mana/gdma.h +@@ -382,6 +382,10 @@ struct gdma_irq_context { + char name[MANA_IRQ_NAME_SZ]; + }; + ++enum gdma_context_flags { ++ GC_PROBE_SUCCEEDED = 0, ++}; ++ + struct gdma_context { + struct device *dev; + struct dentry *mana_pci_debugfs; +@@ -430,6 +434,8 @@ struct gdma_context { + u64 pf_cap_flags1; + + struct workqueue_struct *service_wq; ++ ++ unsigned long flags; + }; + + static inline bool mana_gd_is_mana(struct gdma_dev *gd) +@@ -600,6 +606,9 @@ enum { + /* Driver can send HWC periodically to query stats */ + #define GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY BIT(21) + ++/* Driver can handle hardware recovery events during probe */ ++#define GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY BIT(22) ++ + #define GDMA_DRV_CAP_FLAGS1 \ + (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \ + GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \ +@@ -611,7 +620,8 @@ enum { + GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \ + GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \ + GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY | \ +- GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE) ++ GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE | \ ++ GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY) + + #define GDMA_DRV_CAP_FLAGS2 0 + +-- +2.53.0 + diff --git a/queue-6.18/net-mana-handle-skb-if-tx-sges-exceed-hardware-limit.patch b/queue-6.18/net-mana-handle-skb-if-tx-sges-exceed-hardware-limit.patch new file mode 100644 index 0000000000..5b43c6f65b --- /dev/null +++ b/queue-6.18/net-mana-handle-skb-if-tx-sges-exceed-hardware-limit.patch @@ -0,0 +1,175 @@ +From 99980d7cbe697bd1b729ce8fb27603f364c06a25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 03:11:08 -0800 +Subject: net: mana: Handle SKB if TX SGEs exceed hardware limit + +From: Aditya Garg + +[ Upstream commit 934fa943b53795339486cc0026b3ab7ad39dc600 ] + +The MANA hardware supports a maximum of 30 scatter-gather entries (SGEs) +per TX WQE. Exceeding this limit can cause TX failures. +Add ndo_features_check() callback to validate SKB layout before +transmission. For GSO SKBs that would exceed the hardware SGE limit, clear +NETIF_F_GSO_MASK to enforce software segmentation in the stack. +Add a fallback in mana_start_xmit() to linearize non-GSO SKBs that still +exceed the SGE limit. + +Also, Add ethtool counter for SKBs linearized + +Co-developed-by: Dipayaan Roy +Signed-off-by: Dipayaan Roy +Signed-off-by: Aditya Garg +Reviewed-by: Eric Dumazet +Reviewed-by: Haiyang Zhang +Link: https://patch.msgid.link/1763464269-10431-2-git-send-email-gargaditya@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 65267c9c4f28 ("net: mana: Fix EQ leak in mana_remove on NULL port") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 40 ++++++++++++++++++- + .../ethernet/microsoft/mana/mana_ethtool.c | 2 + + include/net/mana/gdma.h | 8 +++- + include/net/mana/mana.h | 1 + + 4 files changed, 48 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 02090edbd103f..b9cab61d0afe2 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -329,6 +330,21 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev) + cq = &apc->tx_qp[txq_idx].tx_cq; + tx_stats = &txq->stats; + ++ BUILD_BUG_ON(MAX_TX_WQE_SGL_ENTRIES != MANA_MAX_TX_WQE_SGL_ENTRIES); ++ if (MAX_SKB_FRAGS + 2 > MAX_TX_WQE_SGL_ENTRIES && ++ skb_shinfo(skb)->nr_frags + 2 > MAX_TX_WQE_SGL_ENTRIES) { ++ /* GSO skb with Hardware SGE limit exceeded is not expected here ++ * as they are handled in mana_features_check() callback ++ */ ++ if (skb_linearize(skb)) { ++ netdev_warn_once(ndev, "Failed to linearize skb with nr_frags=%d and is_gso=%d\n", ++ skb_shinfo(skb)->nr_frags, ++ skb_is_gso(skb)); ++ goto tx_drop_count; ++ } ++ apc->eth_stats.tx_linear_pkt_cnt++; ++ } ++ + pkg.tx_oob.s_oob.vcq_num = cq->gdma_id; + pkg.tx_oob.s_oob.vsq_frame = txq->vsq_frame; + +@@ -442,8 +458,6 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev) + } + } + +- WARN_ON_ONCE(pkg.wqe_req.num_sge > MAX_TX_WQE_SGL_ENTRIES); +- + if (pkg.wqe_req.num_sge <= ARRAY_SIZE(pkg.sgl_array)) { + pkg.wqe_req.sgl = pkg.sgl_array; + } else { +@@ -518,6 +532,25 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev) + return NETDEV_TX_OK; + } + ++#if (MAX_SKB_FRAGS + 2 > MANA_MAX_TX_WQE_SGL_ENTRIES) ++static netdev_features_t mana_features_check(struct sk_buff *skb, ++ struct net_device *ndev, ++ netdev_features_t features) ++{ ++ if (skb_shinfo(skb)->nr_frags + 2 > MAX_TX_WQE_SGL_ENTRIES) { ++ /* Exceeds HW SGE limit. ++ * GSO case: ++ * Disable GSO so the stack will software-segment the skb ++ * into smaller skbs that fit the SGE budget. ++ * Non-GSO case: ++ * The xmit path will attempt skb_linearize() as a fallback. ++ */ ++ features &= ~NETIF_F_GSO_MASK; ++ } ++ return features; ++} ++#endif ++ + static void mana_get_stats64(struct net_device *ndev, + struct rtnl_link_stats64 *st) + { +@@ -890,6 +923,9 @@ static const struct net_device_ops mana_devops = { + .ndo_open = mana_open, + .ndo_stop = mana_close, + .ndo_select_queue = mana_select_queue, ++#if (MAX_SKB_FRAGS + 2 > MANA_MAX_TX_WQE_SGL_ENTRIES) ++ .ndo_features_check = mana_features_check, ++#endif + .ndo_start_xmit = mana_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_get_stats64 = mana_get_stats64, +diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +index 99e8112086833..0e2f4343ac67f 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +@@ -18,6 +18,8 @@ static const struct mana_stats_desc mana_eth_stats[] = { + {"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)}, + {"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats, + tx_cqe_unknown_type)}, ++ {"tx_linear_pkt_cnt", offsetof(struct mana_ethtool_stats, ++ tx_linear_pkt_cnt)}, + {"rx_coalesced_err", offsetof(struct mana_ethtool_stats, + rx_coalesced_err)}, + {"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats, +diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h +index 2e4f2f3175e55..a4cf307859f85 100644 +--- a/include/net/mana/gdma.h ++++ b/include/net/mana/gdma.h +@@ -486,6 +486,8 @@ struct gdma_wqe { + #define INLINE_OOB_SMALL_SIZE 8 + #define INLINE_OOB_LARGE_SIZE 24 + ++#define MANA_MAX_TX_WQE_SGL_ENTRIES 30 ++ + #define MAX_TX_WQE_SIZE 512 + #define MAX_RX_WQE_SIZE 256 + +@@ -592,6 +594,9 @@ enum { + #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17) + #define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6) + ++/* Driver supports linearizing the skb when num_sge exceeds hardware limit */ ++#define GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE BIT(20) ++ + /* Driver can send HWC periodically to query stats */ + #define GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY BIT(21) + +@@ -605,7 +610,8 @@ enum { + GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \ + GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \ + GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \ +- GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY) ++ GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY | \ ++ GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE) + + #define GDMA_DRV_CAP_FLAGS2 0 + +diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h +index 7e946239effa9..9fadff78568ea 100644 +--- a/include/net/mana/mana.h ++++ b/include/net/mana/mana.h +@@ -377,6 +377,7 @@ struct mana_ethtool_stats { + u64 wake_queue; + u64 tx_cqe_err; + u64 tx_cqe_unknown_type; ++ u64 tx_linear_pkt_cnt; + u64 rx_coalesced_err; + u64 rx_cqe_unknown_type; + }; +-- +2.53.0 + diff --git a/queue-6.18/net-mana-implement-ndo_tx_timeout-and-serialize-queu.patch b/queue-6.18/net-mana-implement-ndo_tx_timeout-and-serialize-queu.patch new file mode 100644 index 0000000000..f92eb22a95 --- /dev/null +++ b/queue-6.18/net-mana-implement-ndo_tx_timeout-and-serialize-queu.patch @@ -0,0 +1,234 @@ +From 1ef6f1172fe08d5063008161de628452d73f2582 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 05:05:52 -0800 +Subject: net: mana: Implement ndo_tx_timeout and serialize queue resets per + port. + +From: Dipayaan Roy + +[ Upstream commit 3b194343c25084a8d2fa0c0f2c9e80f3080fd732 ] + +Implement .ndo_tx_timeout for MANA so any stalled TX queue can be detected +and a device-controlled port reset for all queues can be scheduled to a +ordered workqueue. The reset for all queues on stall detection is +recomended by hardware team. + +Reviewed-by: Pavan Chebbi +Reviewed-by: Haiyang Zhang +Signed-off-by: Dipayaan Roy +Link: https://patch.msgid.link/20260112130552.GA11785@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net +Signed-off-by: Jakub Kicinski +Stable-dep-of: 65267c9c4f28 ("net: mana: Fix EQ leak in mana_remove on NULL port") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 77 ++++++++++++++++++- + include/net/mana/gdma.h | 7 +- + include/net/mana/mana.h | 3 +- + 3 files changed, 84 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index b9cab61d0afe2..12952f7273eb6 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -299,6 +299,39 @@ static int mana_get_gso_hs(struct sk_buff *skb) + return gso_hs; + } + ++static void mana_per_port_queue_reset_work_handler(struct work_struct *work) ++{ ++ struct mana_port_context *apc = container_of(work, ++ struct mana_port_context, ++ queue_reset_work); ++ struct net_device *ndev = apc->ndev; ++ int err; ++ ++ rtnl_lock(); ++ ++ /* Pre-allocate buffers to prevent failure in mana_attach later */ ++ err = mana_pre_alloc_rxbufs(apc, ndev->mtu, apc->num_queues); ++ if (err) { ++ netdev_err(ndev, "Insufficient memory for reset post tx stall detection\n"); ++ goto out; ++ } ++ ++ err = mana_detach(ndev, false); ++ if (err) { ++ netdev_err(ndev, "mana_detach failed: %d\n", err); ++ goto dealloc_pre_rxbufs; ++ } ++ ++ err = mana_attach(ndev); ++ if (err) ++ netdev_err(ndev, "mana_attach failed: %d\n", err); ++ ++dealloc_pre_rxbufs: ++ mana_pre_dealloc_rxbufs(apc); ++out: ++ rtnl_unlock(); ++} ++ + netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev) + { + enum mana_tx_pkt_format pkt_fmt = MANA_SHORT_PKT_FMT; +@@ -847,6 +880,23 @@ static int mana_change_mtu(struct net_device *ndev, int new_mtu) + return err; + } + ++static void mana_tx_timeout(struct net_device *netdev, unsigned int txqueue) ++{ ++ struct mana_port_context *apc = netdev_priv(netdev); ++ struct mana_context *ac = apc->ac; ++ struct gdma_context *gc = ac->gdma_dev->gdma_context; ++ ++ /* Already in service, hence tx queue reset is not required.*/ ++ if (gc->in_service) ++ return; ++ ++ /* Note: If there are pending queue reset work for this port(apc), ++ * subsequent request queued up from here are ignored. This is because ++ * we are using the same work instance per port(apc). ++ */ ++ queue_work(ac->per_port_queue_reset_wq, &apc->queue_reset_work); ++} ++ + static int mana_shaper_set(struct net_shaper_binding *binding, + const struct net_shaper *shaper, + struct netlink_ext_ack *extack) +@@ -932,6 +982,7 @@ static const struct net_device_ops mana_devops = { + .ndo_bpf = mana_bpf, + .ndo_xdp_xmit = mana_xdp_xmit, + .ndo_change_mtu = mana_change_mtu, ++ .ndo_tx_timeout = mana_tx_timeout, + .net_shaper_ops = &mana_shaper_ops, + }; + +@@ -3319,6 +3370,8 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, + ndev->min_mtu = ETH_MIN_MTU; + ndev->needed_headroom = MANA_HEADROOM; + ndev->dev_port = port_idx; ++ /* Recommended timeout based on HW FPGA re-config scenario. */ ++ ndev->watchdog_timeo = 15 * HZ; + SET_NETDEV_DEV(ndev, gc->dev); + + netif_set_tso_max_size(ndev, GSO_MAX_SIZE); +@@ -3335,6 +3388,10 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, + if (err) + goto reset_apc; + ++ /* Initialize the per port queue reset work.*/ ++ INIT_WORK(&apc->queue_reset_work, ++ mana_per_port_queue_reset_work_handler); ++ + netdev_lockdep_set_classes(ndev); + + ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; +@@ -3524,6 +3581,7 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + { + struct gdma_context *gc = gd->gdma_context; + struct mana_context *ac = gd->driver_data; ++ struct mana_port_context *apc = NULL; + struct device *dev = gc->dev; + u8 bm_hostmode = 0; + u16 num_ports = 0; +@@ -3581,6 +3639,14 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + if (ac->num_ports > MAX_PORTS_IN_MANA_DEV) + ac->num_ports = MAX_PORTS_IN_MANA_DEV; + ++ ac->per_port_queue_reset_wq = ++ create_singlethread_workqueue("mana_per_port_queue_reset_wq"); ++ if (!ac->per_port_queue_reset_wq) { ++ dev_err(dev, "Failed to allocate per port queue reset workqueue\n"); ++ err = -ENOMEM; ++ goto out; ++ } ++ + if (!resuming) { + for (i = 0; i < ac->num_ports; i++) { + err = mana_probe_port(ac, i, &ac->ports[i]); +@@ -3596,6 +3662,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + } else { + for (i = 0; i < ac->num_ports; i++) { + rtnl_lock(); ++ apc = netdev_priv(ac->ports[i]); ++ enable_work(&apc->queue_reset_work); + err = mana_attach(ac->ports[i]); + rtnl_unlock(); + /* Log the port for which the attach failed, stop +@@ -3652,13 +3720,15 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + + for (i = 0; i < ac->num_ports; i++) { + ndev = ac->ports[i]; +- apc = netdev_priv(ndev); + if (!ndev) { + if (i == 0) + dev_err(dev, "No net device to remove\n"); + goto out; + } + ++ apc = netdev_priv(ndev); ++ disable_work_sync(&apc->queue_reset_work); ++ + /* All cleanup actions should stay after rtnl_lock(), otherwise + * other functions may access partially cleaned up data. + */ +@@ -3685,6 +3755,11 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + + mana_destroy_eq(ac); + out: ++ if (ac->per_port_queue_reset_wq) { ++ destroy_workqueue(ac->per_port_queue_reset_wq); ++ ac->per_port_queue_reset_wq = NULL; ++ } ++ + mana_gd_deregister_device(gd); + + if (suspending) +diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h +index eaa27483f99b2..a59bd4035a992 100644 +--- a/include/net/mana/gdma.h ++++ b/include/net/mana/gdma.h +@@ -598,6 +598,10 @@ enum { + + /* Driver can self reset on FPGA Reconfig EQE notification */ + #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17) ++ ++/* Driver detects stalled send queues and recovers them */ ++#define GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY BIT(18) ++ + #define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6) + + /* Driver supports linearizing the skb when num_sge exceeds hardware limit */ +@@ -621,7 +625,8 @@ enum { + GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \ + GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY | \ + GDMA_DRV_CAP_FLAG_1_SKB_LINEARIZE | \ +- GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY) ++ GDMA_DRV_CAP_FLAG_1_PROBE_RECOVERY | \ ++ GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY) + + #define GDMA_DRV_CAP_FLAGS2 0 + +diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h +index 9fadff78568ea..e199f1d44c8e3 100644 +--- a/include/net/mana/mana.h ++++ b/include/net/mana/mana.h +@@ -480,7 +480,7 @@ struct mana_context { + struct mana_ethtool_hc_stats hc_stats; + struct mana_eq *eqs; + struct dentry *mana_eqs_debugfs; +- ++ struct workqueue_struct *per_port_queue_reset_wq; + /* Workqueue for querying hardware stats */ + struct delayed_work gf_stats_work; + bool hwc_timeout_occurred; +@@ -495,6 +495,7 @@ struct mana_context { + struct mana_port_context { + struct mana_context *ac; + struct net_device *ndev; ++ struct work_struct queue_reset_work; + + u8 mac_addr[ETH_ALEN]; + +-- +2.53.0 + diff --git a/queue-6.18/net-mana-init-link_change_work-before-potential-erro.patch b/queue-6.18/net-mana-init-link_change_work-before-potential-erro.patch new file mode 100644 index 0000000000..37896ee1cc --- /dev/null +++ b/queue-6.18/net-mana-init-link_change_work-before-potential-erro.patch @@ -0,0 +1,54 @@ +From 0c241c134b2e6e6ca4d35b35019354a2655ba2a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:35 -0700 +Subject: net: mana: Init link_change_work before potential error paths in + probe + +From: Erni Sri Satya Vennela + +[ Upstream commit cb4a90744bcd1adf12f0d0c7c4f0dd2647444ec5 ] + +Move INIT_WORK(link_change_work) to right after the mana_context +allocation, before any error path that could reach mana_remove(). + +Previously, if mana_create_eq() or mana_query_device_cfg() failed, +mana_probe() would jump to the error path which calls mana_remove(). +mana_remove() unconditionally calls disable_work_sync(link_change_work), +but the work struct had not been initialized yet. This can trigger +CONFIG_DEBUG_OBJECTS_WORK enabled. + +Fixes: 54133f9b4b53 ("net: mana: Support HW link state events") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-2-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index c770fb86fd2d3..cd3a435485a19 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3483,6 +3483,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + + ac->gdma_dev = gd; + gd->driver_data = ac; ++ ++ INIT_WORK(&ac->link_change_work, mana_link_state_handle); + } + + err = mana_create_eq(ac); +@@ -3500,8 +3502,6 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + + if (!resuming) { + ac->num_ports = num_ports; +- +- INIT_WORK(&ac->link_change_work, mana_link_state_handle); + } else { + if (ac->num_ports != num_ports) { + dev_err(dev, "The number of vPorts changed: %d->%d\n", +-- +2.53.0 + diff --git a/queue-6.18/net-mana-move-current_speed-debugfs-file-to-mana_ini.patch b/queue-6.18/net-mana-move-current_speed-debugfs-file-to-mana_ini.patch new file mode 100644 index 0000000000..3f200f8172 --- /dev/null +++ b/queue-6.18/net-mana-move-current_speed-debugfs-file-to-mana_ini.patch @@ -0,0 +1,51 @@ +From cf67195a5206cfc9c75d67d27087a8e2ab19a13f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:12:20 -0700 +Subject: net: mana: Move current_speed debugfs file to mana_init_port() + +From: Erni Sri Satya Vennela + +[ Upstream commit 3b7c7fc97aea7b4048001d12f45777201c74a17f ] + +Move the current_speed debugfs file creation from mana_probe_port() to +mana_init_port(). The file was previously created only during initial +probe, but mana_cleanup_port_context() removes the entire vPort debugfs +directory during detach/attach cycles. Since mana_init_port() recreates +the directory on re-attach, moving current_speed here ensures it survives +these cycles. + +Fixes: 75cabb46935b ("net: mana: Add support for net_shaper_ops") +Signed-off-by: Erni Sri Satya Vennela +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260408081224.302308-3-ernis@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 8277a1ac0ad74..c770fb86fd2d3 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3038,6 +3038,8 @@ static int mana_init_port(struct net_device *ndev) + eth_hw_addr_set(ndev, apc->mac_addr); + sprintf(vport, "vport%d", port_idx); + apc->mana_port_debugfs = debugfs_create_dir(vport, gc->mana_pci_debugfs); ++ debugfs_create_u32("current_speed", 0400, apc->mana_port_debugfs, ++ &apc->speed); + return 0; + + reset_apc: +@@ -3310,8 +3312,6 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, + + netif_carrier_on(ndev); + +- debugfs_create_u32("current_speed", 0400, apc->mana_port_debugfs, &apc->speed); +- + return 0; + + free_indir: +-- +2.53.0 + diff --git a/queue-6.18/net-mana-move-hardware-counter-stats-from-per-port-t.patch b/queue-6.18/net-mana-move-hardware-counter-stats-from-per-port-t.patch new file mode 100644 index 0000000000..75b8318250 --- /dev/null +++ b/queue-6.18/net-mana-move-hardware-counter-stats-from-per-port-t.patch @@ -0,0 +1,345 @@ +From 259c5accd2a3e7598ed89fe0c693a901d6752d31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Nov 2025 03:43:18 -0800 +Subject: net: mana: Move hardware counter stats from per-port to per-VF + context + +From: Erni Sri Satya Vennela + +[ Upstream commit e275d9091c01b3b46f3ec534ce4ac77cffc9e3ae ] + +Move hardware counter (HC) statistics from mana_port_context to +mana_context to enable sharing stats across multiple network ports +on the same MANA VF. Previously, each network port queried +hardware counters independently using MANA_QUERY_GF_STAT command +(GF = Generic Function stats from GDMA hardware), resulting in +redundant queries when multiple ports existed on the same device. + +Isolate hardware counter stats by introducing mana_ethtool_hc_stats +in mana_context and update the code to ensure all stats are properly +reported via ethtool -S , maintaining consistency with +previous behavior. + +Signed-off-by: Erni Sri Satya Vennela +Reviewed-by: Haiyang Zhang +Link: https://patch.msgid.link/1763120599-6331-2-git-send-email-ernis@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: a7fdaf069bd0 ("net: mana: Don't overwrite port probe error with add_adev result") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 67 ++++++++------- + .../ethernet/microsoft/mana/mana_ethtool.c | 85 ++++++++++--------- + include/net/mana/mana.h | 14 +-- + 3 files changed, 90 insertions(+), 76 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index d90be4142e257..2e5efc03cacec 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -2836,11 +2836,12 @@ int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx, + return 0; + } + +-void mana_query_gf_stats(struct mana_port_context *apc) ++void mana_query_gf_stats(struct mana_context *ac) + { ++ struct gdma_context *gc = ac->gdma_dev->gdma_context; + struct mana_query_gf_stat_resp resp = {}; + struct mana_query_gf_stat_req req = {}; +- struct net_device *ndev = apc->ndev; ++ struct device *dev = gc->dev; + int err; + + mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_GF_STAT, +@@ -2874,52 +2875,52 @@ void mana_query_gf_stats(struct mana_port_context *apc) + STATISTICS_FLAGS_HC_TX_BCAST_BYTES | + STATISTICS_FLAGS_TX_ERRORS_GDMA_ERROR; + +- err = mana_send_request(apc->ac, &req, sizeof(req), &resp, ++ err = mana_send_request(ac, &req, sizeof(req), &resp, + sizeof(resp)); + if (err) { +- netdev_err(ndev, "Failed to query GF stats: %d\n", err); ++ dev_err(dev, "Failed to query GF stats: %d\n", err); + return; + } + err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_GF_STAT, + sizeof(resp)); + if (err || resp.hdr.status) { +- netdev_err(ndev, "Failed to query GF stats: %d, 0x%x\n", err, +- resp.hdr.status); ++ dev_err(dev, "Failed to query GF stats: %d, 0x%x\n", err, ++ resp.hdr.status); + return; + } + +- apc->eth_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe; +- apc->eth_stats.hc_rx_err_vport_disabled = resp.rx_err_vport_disabled; +- apc->eth_stats.hc_rx_bytes = resp.hc_rx_bytes; +- apc->eth_stats.hc_rx_ucast_pkts = resp.hc_rx_ucast_pkts; +- apc->eth_stats.hc_rx_ucast_bytes = resp.hc_rx_ucast_bytes; +- apc->eth_stats.hc_rx_bcast_pkts = resp.hc_rx_bcast_pkts; +- apc->eth_stats.hc_rx_bcast_bytes = resp.hc_rx_bcast_bytes; +- apc->eth_stats.hc_rx_mcast_pkts = resp.hc_rx_mcast_pkts; +- apc->eth_stats.hc_rx_mcast_bytes = resp.hc_rx_mcast_bytes; +- apc->eth_stats.hc_tx_err_gf_disabled = resp.tx_err_gf_disabled; +- apc->eth_stats.hc_tx_err_vport_disabled = resp.tx_err_vport_disabled; +- apc->eth_stats.hc_tx_err_inval_vportoffset_pkt = ++ ac->hc_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe; ++ ac->hc_stats.hc_rx_err_vport_disabled = resp.rx_err_vport_disabled; ++ ac->hc_stats.hc_rx_bytes = resp.hc_rx_bytes; ++ ac->hc_stats.hc_rx_ucast_pkts = resp.hc_rx_ucast_pkts; ++ ac->hc_stats.hc_rx_ucast_bytes = resp.hc_rx_ucast_bytes; ++ ac->hc_stats.hc_rx_bcast_pkts = resp.hc_rx_bcast_pkts; ++ ac->hc_stats.hc_rx_bcast_bytes = resp.hc_rx_bcast_bytes; ++ ac->hc_stats.hc_rx_mcast_pkts = resp.hc_rx_mcast_pkts; ++ ac->hc_stats.hc_rx_mcast_bytes = resp.hc_rx_mcast_bytes; ++ ac->hc_stats.hc_tx_err_gf_disabled = resp.tx_err_gf_disabled; ++ ac->hc_stats.hc_tx_err_vport_disabled = resp.tx_err_vport_disabled; ++ ac->hc_stats.hc_tx_err_inval_vportoffset_pkt = + resp.tx_err_inval_vport_offset_pkt; +- apc->eth_stats.hc_tx_err_vlan_enforcement = ++ ac->hc_stats.hc_tx_err_vlan_enforcement = + resp.tx_err_vlan_enforcement; +- apc->eth_stats.hc_tx_err_eth_type_enforcement = ++ ac->hc_stats.hc_tx_err_eth_type_enforcement = + resp.tx_err_ethtype_enforcement; +- apc->eth_stats.hc_tx_err_sa_enforcement = resp.tx_err_SA_enforcement; +- apc->eth_stats.hc_tx_err_sqpdid_enforcement = ++ ac->hc_stats.hc_tx_err_sa_enforcement = resp.tx_err_SA_enforcement; ++ ac->hc_stats.hc_tx_err_sqpdid_enforcement = + resp.tx_err_SQPDID_enforcement; +- apc->eth_stats.hc_tx_err_cqpdid_enforcement = ++ ac->hc_stats.hc_tx_err_cqpdid_enforcement = + resp.tx_err_CQPDID_enforcement; +- apc->eth_stats.hc_tx_err_mtu_violation = resp.tx_err_mtu_violation; +- apc->eth_stats.hc_tx_err_inval_oob = resp.tx_err_inval_oob; +- apc->eth_stats.hc_tx_bytes = resp.hc_tx_bytes; +- apc->eth_stats.hc_tx_ucast_pkts = resp.hc_tx_ucast_pkts; +- apc->eth_stats.hc_tx_ucast_bytes = resp.hc_tx_ucast_bytes; +- apc->eth_stats.hc_tx_bcast_pkts = resp.hc_tx_bcast_pkts; +- apc->eth_stats.hc_tx_bcast_bytes = resp.hc_tx_bcast_bytes; +- apc->eth_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts; +- apc->eth_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes; +- apc->eth_stats.hc_tx_err_gdma = resp.tx_err_gdma; ++ ac->hc_stats.hc_tx_err_mtu_violation = resp.tx_err_mtu_violation; ++ ac->hc_stats.hc_tx_err_inval_oob = resp.tx_err_inval_oob; ++ ac->hc_stats.hc_tx_bytes = resp.hc_tx_bytes; ++ ac->hc_stats.hc_tx_ucast_pkts = resp.hc_tx_ucast_pkts; ++ ac->hc_stats.hc_tx_ucast_bytes = resp.hc_tx_ucast_bytes; ++ ac->hc_stats.hc_tx_bcast_pkts = resp.hc_tx_bcast_pkts; ++ ac->hc_stats.hc_tx_bcast_bytes = resp.hc_tx_bcast_bytes; ++ ac->hc_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts; ++ ac->hc_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes; ++ ac->hc_stats.hc_tx_err_gdma = resp.tx_err_gdma; + } + + void mana_query_phy_stats(struct mana_port_context *apc) +diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +index a1afa75a94631..3dfd96146424e 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +@@ -15,66 +15,69 @@ struct mana_stats_desc { + static const struct mana_stats_desc mana_eth_stats[] = { + {"stop_queue", offsetof(struct mana_ethtool_stats, stop_queue)}, + {"wake_queue", offsetof(struct mana_ethtool_stats, wake_queue)}, +- {"hc_rx_discards_no_wqe", offsetof(struct mana_ethtool_stats, ++ {"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)}, ++ {"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats, ++ tx_cqe_unknown_type)}, ++ {"rx_coalesced_err", offsetof(struct mana_ethtool_stats, ++ rx_coalesced_err)}, ++ {"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats, ++ rx_cqe_unknown_type)}, ++}; ++ ++static const struct mana_stats_desc mana_hc_stats[] = { ++ {"hc_rx_discards_no_wqe", offsetof(struct mana_ethtool_hc_stats, + hc_rx_discards_no_wqe)}, +- {"hc_rx_err_vport_disabled", offsetof(struct mana_ethtool_stats, ++ {"hc_rx_err_vport_disabled", offsetof(struct mana_ethtool_hc_stats, + hc_rx_err_vport_disabled)}, +- {"hc_rx_bytes", offsetof(struct mana_ethtool_stats, hc_rx_bytes)}, +- {"hc_rx_ucast_pkts", offsetof(struct mana_ethtool_stats, ++ {"hc_rx_bytes", offsetof(struct mana_ethtool_hc_stats, hc_rx_bytes)}, ++ {"hc_rx_ucast_pkts", offsetof(struct mana_ethtool_hc_stats, + hc_rx_ucast_pkts)}, +- {"hc_rx_ucast_bytes", offsetof(struct mana_ethtool_stats, ++ {"hc_rx_ucast_bytes", offsetof(struct mana_ethtool_hc_stats, + hc_rx_ucast_bytes)}, +- {"hc_rx_bcast_pkts", offsetof(struct mana_ethtool_stats, ++ {"hc_rx_bcast_pkts", offsetof(struct mana_ethtool_hc_stats, + hc_rx_bcast_pkts)}, +- {"hc_rx_bcast_bytes", offsetof(struct mana_ethtool_stats, ++ {"hc_rx_bcast_bytes", offsetof(struct mana_ethtool_hc_stats, + hc_rx_bcast_bytes)}, +- {"hc_rx_mcast_pkts", offsetof(struct mana_ethtool_stats, +- hc_rx_mcast_pkts)}, +- {"hc_rx_mcast_bytes", offsetof(struct mana_ethtool_stats, ++ {"hc_rx_mcast_pkts", offsetof(struct mana_ethtool_hc_stats, ++ hc_rx_mcast_pkts)}, ++ {"hc_rx_mcast_bytes", offsetof(struct mana_ethtool_hc_stats, + hc_rx_mcast_bytes)}, +- {"hc_tx_err_gf_disabled", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_err_gf_disabled", offsetof(struct mana_ethtool_hc_stats, + hc_tx_err_gf_disabled)}, +- {"hc_tx_err_vport_disabled", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_err_vport_disabled", offsetof(struct mana_ethtool_hc_stats, + hc_tx_err_vport_disabled)}, + {"hc_tx_err_inval_vportoffset_pkt", +- offsetof(struct mana_ethtool_stats, ++ offsetof(struct mana_ethtool_hc_stats, + hc_tx_err_inval_vportoffset_pkt)}, +- {"hc_tx_err_vlan_enforcement", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_err_vlan_enforcement", offsetof(struct mana_ethtool_hc_stats, + hc_tx_err_vlan_enforcement)}, + {"hc_tx_err_eth_type_enforcement", +- offsetof(struct mana_ethtool_stats, hc_tx_err_eth_type_enforcement)}, +- {"hc_tx_err_sa_enforcement", offsetof(struct mana_ethtool_stats, ++ offsetof(struct mana_ethtool_hc_stats, hc_tx_err_eth_type_enforcement)}, ++ {"hc_tx_err_sa_enforcement", offsetof(struct mana_ethtool_hc_stats, + hc_tx_err_sa_enforcement)}, + {"hc_tx_err_sqpdid_enforcement", +- offsetof(struct mana_ethtool_stats, hc_tx_err_sqpdid_enforcement)}, ++ offsetof(struct mana_ethtool_hc_stats, hc_tx_err_sqpdid_enforcement)}, + {"hc_tx_err_cqpdid_enforcement", +- offsetof(struct mana_ethtool_stats, hc_tx_err_cqpdid_enforcement)}, +- {"hc_tx_err_mtu_violation", offsetof(struct mana_ethtool_stats, ++ offsetof(struct mana_ethtool_hc_stats, hc_tx_err_cqpdid_enforcement)}, ++ {"hc_tx_err_mtu_violation", offsetof(struct mana_ethtool_hc_stats, + hc_tx_err_mtu_violation)}, +- {"hc_tx_err_inval_oob", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_err_inval_oob", offsetof(struct mana_ethtool_hc_stats, + hc_tx_err_inval_oob)}, +- {"hc_tx_err_gdma", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_err_gdma", offsetof(struct mana_ethtool_hc_stats, + hc_tx_err_gdma)}, +- {"hc_tx_bytes", offsetof(struct mana_ethtool_stats, hc_tx_bytes)}, +- {"hc_tx_ucast_pkts", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_bytes", offsetof(struct mana_ethtool_hc_stats, hc_tx_bytes)}, ++ {"hc_tx_ucast_pkts", offsetof(struct mana_ethtool_hc_stats, + hc_tx_ucast_pkts)}, +- {"hc_tx_ucast_bytes", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_ucast_bytes", offsetof(struct mana_ethtool_hc_stats, + hc_tx_ucast_bytes)}, +- {"hc_tx_bcast_pkts", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_bcast_pkts", offsetof(struct mana_ethtool_hc_stats, + hc_tx_bcast_pkts)}, +- {"hc_tx_bcast_bytes", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_bcast_bytes", offsetof(struct mana_ethtool_hc_stats, + hc_tx_bcast_bytes)}, +- {"hc_tx_mcast_pkts", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_mcast_pkts", offsetof(struct mana_ethtool_hc_stats, + hc_tx_mcast_pkts)}, +- {"hc_tx_mcast_bytes", offsetof(struct mana_ethtool_stats, ++ {"hc_tx_mcast_bytes", offsetof(struct mana_ethtool_hc_stats, + hc_tx_mcast_bytes)}, +- {"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)}, +- {"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats, +- tx_cqe_unknown_type)}, +- {"rx_coalesced_err", offsetof(struct mana_ethtool_stats, +- rx_coalesced_err)}, +- {"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats, +- rx_cqe_unknown_type)}, + }; + + static const struct mana_stats_desc mana_phy_stats[] = { +@@ -138,7 +141,7 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset) + if (stringset != ETH_SS_STATS) + return -EINVAL; + +- return ARRAY_SIZE(mana_eth_stats) + ARRAY_SIZE(mana_phy_stats) + ++ return ARRAY_SIZE(mana_eth_stats) + ARRAY_SIZE(mana_phy_stats) + ARRAY_SIZE(mana_hc_stats) + + num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT); + } + +@@ -150,10 +153,12 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data) + + if (stringset != ETH_SS_STATS) + return; +- + for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++) + ethtool_puts(&data, mana_eth_stats[i].name); + ++ for (i = 0; i < ARRAY_SIZE(mana_hc_stats); i++) ++ ethtool_puts(&data, mana_hc_stats[i].name); ++ + for (i = 0; i < ARRAY_SIZE(mana_phy_stats); i++) + ethtool_puts(&data, mana_phy_stats[i].name); + +@@ -186,6 +191,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev, + struct mana_port_context *apc = netdev_priv(ndev); + unsigned int num_queues = apc->num_queues; + void *eth_stats = &apc->eth_stats; ++ void *hc_stats = &apc->ac->hc_stats; + void *phy_stats = &apc->phy_stats; + struct mana_stats_rx *rx_stats; + struct mana_stats_tx *tx_stats; +@@ -208,7 +214,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev, + if (!apc->port_is_up) + return; + /* we call mana function to update stats from GDMA */ +- mana_query_gf_stats(apc); ++ mana_query_gf_stats(apc->ac); + + /* We call this mana function to get the phy stats from GDMA and includes + * aggregate tx/rx drop counters, Per-TC(Traffic Channel) tx/rx and pause +@@ -219,6 +225,9 @@ static void mana_get_ethtool_stats(struct net_device *ndev, + for (q = 0; q < ARRAY_SIZE(mana_eth_stats); q++) + data[i++] = *(u64 *)(eth_stats + mana_eth_stats[q].offset); + ++ for (q = 0; q < ARRAY_SIZE(mana_hc_stats); q++) ++ data[i++] = *(u64 *)(hc_stats + mana_hc_stats[q].offset); ++ + for (q = 0; q < ARRAY_SIZE(mana_phy_stats); q++) + data[i++] = *(u64 *)(phy_stats + mana_phy_stats[q].offset); + +diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h +index f9f264385405c..265f2d90027d6 100644 +--- a/include/net/mana/mana.h ++++ b/include/net/mana/mana.h +@@ -375,6 +375,13 @@ struct mana_tx_qp { + struct mana_ethtool_stats { + u64 stop_queue; + u64 wake_queue; ++ u64 tx_cqe_err; ++ u64 tx_cqe_unknown_type; ++ u64 rx_coalesced_err; ++ u64 rx_cqe_unknown_type; ++}; ++ ++struct mana_ethtool_hc_stats { + u64 hc_rx_discards_no_wqe; + u64 hc_rx_err_vport_disabled; + u64 hc_rx_bytes; +@@ -402,10 +409,6 @@ struct mana_ethtool_stats { + u64 hc_tx_mcast_pkts; + u64 hc_tx_mcast_bytes; + u64 hc_tx_err_gdma; +- u64 tx_cqe_err; +- u64 tx_cqe_unknown_type; +- u64 rx_coalesced_err; +- u64 rx_cqe_unknown_type; + }; + + struct mana_ethtool_phy_stats { +@@ -473,6 +476,7 @@ struct mana_context { + u16 num_ports; + u8 bm_hostmode; + ++ struct mana_ethtool_hc_stats hc_stats; + struct mana_eq *eqs; + struct dentry *mana_eqs_debugfs; + +@@ -578,7 +582,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq, + struct bpf_prog *mana_xdp_get(struct mana_port_context *apc); + void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog); + int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf); +-void mana_query_gf_stats(struct mana_port_context *apc); ++void mana_query_gf_stats(struct mana_context *ac); + int mana_query_link_cfg(struct mana_port_context *apc); + int mana_set_bw_clamp(struct mana_port_context *apc, u32 speed, + int enable_clamping); +-- +2.53.0 + diff --git a/queue-6.18/net-mana-support-hw-link-state-events.patch b/queue-6.18/net-mana-support-hw-link-state-events.patch new file mode 100644 index 0000000000..aaa3885efe --- /dev/null +++ b/queue-6.18/net-mana-support-hw-link-state-events.patch @@ -0,0 +1,250 @@ +From 19aba936e2a4b91ae009df56a786c0b4fc731d14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Oct 2025 13:43:10 -0700 +Subject: net: mana: Support HW link state events + +From: Haiyang Zhang + +[ Upstream commit 54133f9b4b53ffa2204eb27cfc9d50072c9a52d2 ] + +Handle the NIC hardware link state events received from the HW +channel, then set the proper link state accordingly. + +And, add a feature bit, GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE, +to inform the NIC hardware this handler exists. + +Our MANA NIC only sends out the link state down/up messages +when we need to let the VM rerun DHCP client and change IP +address. So, add netif_carrier_on() in the probe(), let the NIC +show the right initial state in /sys/class/net/ethX/operstate. + +Signed-off-by: Haiyang Zhang +Link: https://patch.msgid.link/1761770601-16920-1-git-send-email-haiyangz@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 3b7c7fc97aea ("net: mana: Move current_speed debugfs file to mana_init_port()") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/microsoft/mana/gdma_main.c | 1 + + .../net/ethernet/microsoft/mana/hw_channel.c | 12 +++++ + drivers/net/ethernet/microsoft/mana/mana_en.c | 54 +++++++++++++++++-- + include/net/mana/gdma.h | 4 +- + include/net/mana/hw_channel.h | 2 + + include/net/mana/mana.h | 4 ++ + 6 files changed, 71 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c +index c0de20b2183a2..d93cfb7f4e788 100644 +--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c ++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c +@@ -528,6 +528,7 @@ static void mana_gd_process_eqe(struct gdma_queue *eq) + case GDMA_EQE_HWC_INIT_DONE: + case GDMA_EQE_HWC_SOC_SERVICE: + case GDMA_EQE_RNIC_QP_FATAL: ++ case GDMA_EQE_HWC_SOC_RECONFIG_DATA: + if (!eq->eq.callback) + break; + +diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c +index 21cddafba5061..840c6b8957c90 100644 +--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c ++++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c +@@ -118,6 +118,7 @@ static void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self, + struct gdma_dev *gd = hwc->gdma_dev; + union hwc_init_type_data type_data; + union hwc_init_eq_id_db eq_db; ++ struct mana_context *ac; + u32 type, val; + int ret; + +@@ -196,6 +197,17 @@ static void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self, + hwc->hwc_timeout = val; + break; + ++ case HWC_DATA_HW_LINK_CONNECT: ++ case HWC_DATA_HW_LINK_DISCONNECT: ++ ac = gd->gdma_context->mana.driver_data; ++ if (!ac) ++ break; ++ ++ WRITE_ONCE(ac->link_event, type); ++ schedule_work(&ac->link_change_work); ++ ++ break; ++ + default: + dev_warn(hwc->dev, "Received unknown reconfig type %u\n", type); + break; +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index abb207339992b..8277a1ac0ad74 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -20,6 +20,7 @@ + + #include + #include ++#include + + static DEFINE_IDA(mana_adev_ida); + +@@ -84,7 +85,6 @@ static int mana_open(struct net_device *ndev) + /* Ensure port state updated before txq state */ + smp_wmb(); + +- netif_carrier_on(ndev); + netif_tx_wake_all_queues(ndev); + netdev_dbg(ndev, "%s successful\n", __func__); + return 0; +@@ -100,6 +100,46 @@ static int mana_close(struct net_device *ndev) + return mana_detach(ndev, true); + } + ++static void mana_link_state_handle(struct work_struct *w) ++{ ++ struct mana_context *ac; ++ struct net_device *ndev; ++ u32 link_event; ++ bool link_up; ++ int i; ++ ++ ac = container_of(w, struct mana_context, link_change_work); ++ ++ rtnl_lock(); ++ ++ link_event = READ_ONCE(ac->link_event); ++ ++ if (link_event == HWC_DATA_HW_LINK_CONNECT) ++ link_up = true; ++ else if (link_event == HWC_DATA_HW_LINK_DISCONNECT) ++ link_up = false; ++ else ++ goto out; ++ ++ /* Process all ports */ ++ for (i = 0; i < ac->num_ports; i++) { ++ ndev = ac->ports[i]; ++ if (!ndev) ++ continue; ++ ++ if (link_up) { ++ netif_carrier_on(ndev); ++ ++ __netdev_notify_peers(ndev); ++ } else { ++ netif_carrier_off(ndev); ++ } ++ } ++ ++out: ++ rtnl_unlock(); ++} ++ + static bool mana_can_tx(struct gdma_queue *wq) + { + return mana_gd_wq_avail_space(wq) >= MAX_TX_WQE_SIZE; +@@ -3086,9 +3126,6 @@ int mana_attach(struct net_device *ndev) + /* Ensure port state updated before txq state */ + smp_wmb(); + +- if (apc->port_is_up) +- netif_carrier_on(ndev); +- + netif_device_attach(ndev); + + return 0; +@@ -3183,7 +3220,6 @@ int mana_detach(struct net_device *ndev, bool from_close) + smp_wmb(); + + netif_tx_disable(ndev); +- netif_carrier_off(ndev); + + if (apc->port_st_save) { + err = mana_dealloc_queues(ndev); +@@ -3272,6 +3308,8 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, + goto free_indir; + } + ++ netif_carrier_on(ndev); ++ + debugfs_create_u32("current_speed", 0400, apc->mana_port_debugfs, &apc->speed); + + return 0; +@@ -3462,6 +3500,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + + if (!resuming) { + ac->num_ports = num_ports; ++ ++ INIT_WORK(&ac->link_change_work, mana_link_state_handle); + } else { + if (ac->num_ports != num_ports) { + dev_err(dev, "The number of vPorts changed: %d->%d\n", +@@ -3469,6 +3509,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + err = -EPROTO; + goto out; + } ++ ++ enable_work(&ac->link_change_work); + } + + if (ac->num_ports == 0) +@@ -3531,6 +3573,8 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + int err; + int i; + ++ disable_work_sync(&ac->link_change_work); ++ + /* adev currently doesn't support suspending, always remove it */ + if (gd->adev) + remove_adev(gd); +diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h +index 57df78cfbf82c..637f42485dba6 100644 +--- a/include/net/mana/gdma.h ++++ b/include/net/mana/gdma.h +@@ -590,6 +590,7 @@ enum { + + /* Driver can self reset on FPGA Reconfig EQE notification */ + #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17) ++#define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6) + + #define GDMA_DRV_CAP_FLAGS1 \ + (GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \ +@@ -599,7 +600,8 @@ enum { + GDMA_DRV_CAP_FLAG_1_DEV_LIST_HOLES_SUP | \ + GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \ + GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \ +- GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE) ++ GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \ ++ GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE) + + #define GDMA_DRV_CAP_FLAGS2 0 + +diff --git a/include/net/mana/hw_channel.h b/include/net/mana/hw_channel.h +index 83cf93338eb38..16feb39616c1b 100644 +--- a/include/net/mana/hw_channel.h ++++ b/include/net/mana/hw_channel.h +@@ -24,6 +24,8 @@ + #define HWC_INIT_DATA_PF_DEST_CQ_ID 11 + + #define HWC_DATA_CFG_HWC_TIMEOUT 1 ++#define HWC_DATA_HW_LINK_CONNECT 2 ++#define HWC_DATA_HW_LINK_DISCONNECT 3 + + #define HW_CHANNEL_WAIT_RESOURCE_TIMEOUT_MS 30000 + +diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h +index 857f45a3386cc..f9f264385405c 100644 +--- a/include/net/mana/mana.h ++++ b/include/net/mana/mana.h +@@ -477,6 +477,10 @@ struct mana_context { + struct dentry *mana_eqs_debugfs; + + struct net_device *ports[MAX_PORTS_IN_MANA_DEV]; ++ ++ /* Link state change work */ ++ struct work_struct link_change_work; ++ u32 link_event; + }; + + struct mana_port_context { +-- +2.53.0 + diff --git a/queue-6.18/net-mana-use-pci_name-for-debugfs-directory-naming.patch b/queue-6.18/net-mana-use-pci_name-for-debugfs-directory-naming.patch new file mode 100644 index 0000000000..5c373d5cb8 --- /dev/null +++ b/queue-6.18/net-mana-use-pci_name-for-debugfs-directory-naming.patch @@ -0,0 +1,55 @@ +From 07bdc514a6d865fe13170cf84c7472f133412ac1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:12:19 -0700 +Subject: net: mana: Use pci_name() for debugfs directory naming + +From: Erni Sri Satya Vennela + +[ Upstream commit c116f07ab9d22bb6f355f3cf9e44c1e6a47fe559 ] + +Use pci_name(pdev) for the per-device debugfs directory instead of +hardcoded "0" for PFs and pci_slot_name(pdev->slot) for VFs. The +previous approach had two issues: + +1. pci_slot_name() dereferences pdev->slot, which can be NULL for VFs + in environments like generic VFIO passthrough or nested KVM, + causing a NULL pointer dereference. + +2. Multiple PFs would all use "0", and VFs across different PCI + domains or buses could share the same slot name, leading to + -EEXIST errors from debugfs_create_dir(). + +pci_name(pdev) returns the unique BDF address, is always valid, and is +unique across the system. + +Fixes: 6607c17c6c5e ("net: mana: Enable debugfs files for MANA device") +Signed-off-by: Erni Sri Satya Vennela +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260408081224.302308-2-ernis@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/gdma_main.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c +index 962fdd29d6063..c0de20b2183a2 100644 +--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c ++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c +@@ -1927,11 +1927,8 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + gc->dev = &pdev->dev; + xa_init(&gc->irq_contexts); + +- if (gc->is_pf) +- gc->mana_pci_debugfs = debugfs_create_dir("0", mana_debugfs_root); +- else +- gc->mana_pci_debugfs = debugfs_create_dir(pci_slot_name(pdev->slot), +- mana_debugfs_root); ++ gc->mana_pci_debugfs = debugfs_create_dir(pci_name(pdev), ++ mana_debugfs_root); + + err = mana_gd_setup(pdev); + if (err) +-- +2.53.0 + diff --git a/queue-6.18/net-mctp-i2c-check-length-before-marking-flow-active.patch b/queue-6.18/net-mctp-i2c-check-length-before-marking-flow-active.patch new file mode 100644 index 0000000000..584dff7dcb --- /dev/null +++ b/queue-6.18/net-mctp-i2c-check-length-before-marking-flow-active.patch @@ -0,0 +1,90 @@ +From cdac9f9bc50e8170c15ee3c4c3b958f6aae05c05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:46:52 -0700 +Subject: net: mctp i2c: check length before marking flow active + +From: William A. Kennington III + +[ Upstream commit 4ca07b9239bd0478ae586632a2ed72be37ed8407 ] + +Currently, mctp_i2c_get_tx_flow_state() is called before the packet length +sanity check. This function marks a new flow as active in the MCTP core. + +If the sanity check fails, mctp_i2c_xmit() returns early without calling +mctp_i2c_lock_nest(). This results in a mismatched locking state: the +flow is active, but the I2C bus lock was never acquired for it. + +When the flow is later released, mctp_i2c_release_flow() will see the +active state and queue an unlock marker. The TX thread will then +decrement midev->i2c_lock_count from 0, causing it to underflow to -1. + +This underflow permanently breaks the driver's locking logic, allowing +future transmissions to occur without holding the I2C bus lock, leading +to bus collisions and potential hardware hangs. + +Move the mctp_i2c_get_tx_flow_state() call to after the length sanity +check to ensure we only transition the flow state if we are actually +going to proceed with the transmission and locking. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: William A. Kennington III +Acked-by: Jeremy Kerr +Link: https://patch.msgid.link/20260423074741.201460-1-william@wkennington.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 4 ++-- + net/sched/cls_flower.c | 4 +++- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index f138b0251313e..115494f15e87a 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + u8 *pecp; + int rc; + +- fs = mctp_i2c_get_tx_flow_state(midev, skb); +- + hdr = (void *)skb_mac_header(skb); + /* Sanity check that packet contents matches skb length, + * and can't exceed MCTP_I2C_BUFSZ +@@ -509,6 +507,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + return; + } + ++ fs = mctp_i2c_get_tx_flow_state(midev, skb); ++ + if (skb_tailroom(skb) >= 1) { + /* Linear case with space, we can just append the PEC */ + skb_put(skb, 1); +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index 099ff6a3e1f51..f3af0ac892a86 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -560,6 +560,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); ++ struct fl_flow_mask *mask; + + *last = false; + +@@ -576,11 +577,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- *last = fl_mask_put(head, f->mask); ++ mask = f->mask; + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); ++ *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch b/queue-6.18/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch new file mode 100644 index 0000000000..e685ad7b7c --- /dev/null +++ b/queue-6.18/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch @@ -0,0 +1,53 @@ +From f1ad3826e749345eb6daba79e39a2a3018e8c6e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 01:49:37 +0100 +Subject: net/mlx5: Fix HCA caps leak on notifier init failure + +From: Prathamesh Deshpande + +[ Upstream commit d03fc81a57956248383efec99967d0ae627390a8 ] + +mlx5_mdev_init() allocates HCA caps via mlx5_hca_caps_alloc() before +calling mlx5_notifiers_init(). If notifier initialization fails, the +error path jumps to err_hca_caps and skips mlx5_hca_caps_free(), leaking +allocated caps. + +Add a dedicated unwind label for notifier-init failure that frees HCA +caps before continuing the existing cleanup sequence. + +Fixes: b6b03097f982 ("net/mlx5: Initialize events outside devlink lock") +Signed-off-by: Prathamesh Deshpande +Reviewed-by: Cosmin Ratiu +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260415005022.34764-1-prathameshdeshpande7@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c +index 5903a4af9173b..6e10a6de8ebcc 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c +@@ -1878,7 +1878,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) + + err = mlx5_notifiers_init(dev); + if (err) +- goto err_hca_caps; ++ goto err_notifiers_init; + + /* The conjunction of sw_vhca_id with sw_owner_id will be a global + * unique id per function which uses mlx5_core. +@@ -1894,6 +1894,8 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) + + return 0; + ++err_notifiers_init: ++ mlx5_hca_caps_free(dev); + err_hca_caps: + mlx5_adev_cleanup(dev); + err_adev_init: +-- +2.53.0 + diff --git a/queue-6.18/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch b/queue-6.18/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch new file mode 100644 index 0000000000..3c868766da --- /dev/null +++ b/queue-6.18/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch @@ -0,0 +1,63 @@ +From 96e186e161ae8e3a025489b108ea9919d30c016b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 23:28:51 +0300 +Subject: net/mlx5e: Fix features not applied during netdev registration + +From: Gal Pressman + +[ Upstream commit 9994ad4df82d64e57135c0f0906897685f5a9e87 ] + +mlx5e_fix_features() returns early when the netdevice is not present. +This is correct during profile transitions where priv is cleared, but it +also incorrectly blocks feature fixups during register_netdev(), when +the device is also not yet present. + +It is not trivial to distinguish between both cases as we cannot use +priv to carry state, and in both cases reg_state == NETREG_REGISTERED. + +Force a netdev features update after register_netdev() completes, where +the device is present and fix_features() can actually work. + +This is not a pretty solution, as it results in an additional features +update call (register_netdevice() already calls +__netdev_update_features() internally), but it is the simplest, +cleanest, and most robust way I found to fix this issue after multiple +attempts. + +This fixes an issue on systems where CQE compression is enabled by +default, RXHASH remains enabled after registration despite the two +features being mutually exclusive. + +Fixes: ab4b01bfdaa6 ("net/mlx5e: Verify dev is present for fix features ndo") +Signed-off-by: Gal Pressman +Reviewed-by: Dragos Tatulea +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260409202852.158059-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index cb993ad2d9ad9..a696fb88dbef9 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -6740,6 +6740,14 @@ static int _mlx5e_probe(struct auxiliary_device *adev) + goto err_resume; + } + ++ /* mlx5e_fix_features() returns early when the device is not present ++ * to avoid dereferencing cleared priv during profile changes. ++ * This also causes it to be a no-op during register_netdev(), where ++ * the device is not yet present. ++ * Trigger an additional features update that will actually work. ++ */ ++ mlx5e_update_features(netdev); ++ + mlx5e_dcbnl_init_app(priv); + mlx5_core_uplink_netdev_set(mdev, netdev); + mlx5e_params_print_info(mdev, &priv->channels.params); +-- +2.53.0 + diff --git a/queue-6.18/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch b/queue-6.18/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch new file mode 100644 index 0000000000..4e162720e5 --- /dev/null +++ b/queue-6.18/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch @@ -0,0 +1,81 @@ +From 0211ac01b6a007f6622500de11beea177893ebff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 23:28:52 +0300 +Subject: net/mlx5e: IPsec, fix ASO poll timeout with + read_poll_timeout_atomic() + +From: Gal Pressman + +[ Upstream commit edccdd1eb94712da97a6ce71123ec27890add754 ] + +The do-while poll loop uses jiffies for its timeout: + expires = jiffies + msecs_to_jiffies(10); + +jiffies is sampled at an arbitrary point within the current tick, so the +first partial tick contributes anywhere from a full tick down to nearly +zero real time. For small msecs_to_jiffies() results this is +significant, the effective poll window can be much shorter than the +requested 10ms, and in the worst case the loop exits after a single +iteration (e.g., when HZ=100), well before the device has delivered the +CQE. + +Replace the loop with read_poll_timeout_atomic(), which counts elapsed +time via udelay() accounting rather than jiffies, guaranteeing the full +poll window regardless of HZ. + +Additionally, read_poll_timeout_atomic() executes the poll operation one +more time after the timeout has expired, giving the CQE a final chance +to be detected. The old do-while loop could exit without a final poll if +the timeout expired during the udelay() between iterations. + +Fixes: 76e463f6508b ("net/mlx5e: Overcome slow response for first IPsec ASO WQE") +Signed-off-by: Gal Pressman +Reviewed-by: Jianbo Liu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260409202852.158059-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../mellanox/mlx5/core/en_accel/ipsec_offload.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +index e0611fa827971..9e9e18f5dbc9b 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +@@ -1,6 +1,8 @@ + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB + /* Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. */ + ++#include ++ + #include "mlx5_core.h" + #include "en.h" + #include "ipsec.h" +@@ -592,7 +594,6 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, + struct mlx5_wqe_aso_ctrl_seg *ctrl; + struct mlx5e_hw_objs *res; + struct mlx5_aso_wqe *wqe; +- unsigned long expires; + u8 ds_cnt; + int ret; + +@@ -614,13 +615,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, + mlx5e_ipsec_aso_copy(ctrl, data); + + mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl); +- expires = jiffies + msecs_to_jiffies(10); +- do { +- ret = mlx5_aso_poll_cq(aso->aso, false); +- if (ret) +- /* We are in atomic context */ +- udelay(10); +- } while (ret && time_is_after_jiffies(expires)); ++ read_poll_timeout_atomic(mlx5_aso_poll_cq, ret, !ret, 10, ++ 10 * USEC_PER_MSEC, false, aso->aso, false); + if (!ret) + memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso)); + spin_unlock_bh(&aso->lock); +-- +2.53.0 + diff --git a/queue-6.18/net-phy-dp83869-fix-setting-clk_o_sel-field.patch b/queue-6.18/net-phy-dp83869-fix-setting-clk_o_sel-field.patch new file mode 100644 index 0000000000..9271fa0a39 --- /dev/null +++ b/queue-6.18/net-phy-dp83869-fix-setting-clk_o_sel-field.patch @@ -0,0 +1,64 @@ +From e7faf9648f0034367ef01bf2f0901b252d480849 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 05:13:39 +0200 +Subject: net: phy: dp83869: fix setting CLK_O_SEL field. + +From: Heiko Schocher + +[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ] + +Table 7-121 in datasheet says we have to set register 0xc6 +to value 0x10 before CLK_O_SEL can be modified. No more infos +about this field found in datasheet. With this fix, setting +of CLK_O_SEL field in IO_MUX_CFG register worked through dts +property "ti,clk-output-sel" on a DP83869HMRGZR. + +Signed-off-by: Heiko Schocher +Reviewed-by: Simon Horman +Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") +Link: https://patch.msgid.link/20260425031339.3318-1-hs@nabladev.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83869.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c +index 1f381d7b13ff3..96a7d255f50fd 100644 +--- a/drivers/net/phy/dp83869.c ++++ b/drivers/net/phy/dp83869.c +@@ -31,6 +31,7 @@ + #define DP83869_RGMIICTL 0x0032 + #define DP83869_STRAP_STS1 0x006e + #define DP83869_RGMIIDCTL 0x0086 ++#define DP83869_ANA_PLL_PROG_PI 0x00c6 + #define DP83869_RXFCFG 0x0134 + #define DP83869_RXFPMD1 0x0136 + #define DP83869_RXFPMD2 0x0137 +@@ -826,12 +827,22 @@ static int dp83869_config_init(struct phy_device *phydev) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ +- if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) ++ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { ++ /* ++ * Table 7-121 in datasheet says we have to set register 0xc6 ++ * to value 0x10 before CLK_O_SEL can be modified. ++ */ ++ ret = phy_write_mmd(phydev, DP83869_DEVADDR, ++ DP83869_ANA_PLL_PROG_PI, 0x10); ++ if (ret) ++ return ret; ++ + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); ++ } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, +-- +2.53.0 + diff --git a/queue-6.18/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch b/queue-6.18/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch new file mode 100644 index 0000000000..a2792e938b --- /dev/null +++ b/queue-6.18/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch @@ -0,0 +1,44 @@ +From 3141b72f87647d9fa732d8b9108f5402d0dc94ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 06:36:54 -0700 +Subject: net: phy: fix a return path in get_phy_c45_ids() + +From: Charles Perry + +[ Upstream commit 6f533abe7bbad2eef1e42c639b6bb9dad2b02362 ] + +The return value of phy_c45_probe_present() is stored in "ret", not +"phy_reg", fix this. "phy_reg" always has a positive value if we reach +this return path (since it would have returned earlier otherwise), which +means that the original goal of the patch of not considering -ENODEV +fatal wasn't achieved. + +Fixes: 17b447539408 ("net: phy: c45 scanning: Don't consider -ENODEV fatal") +Signed-off-by: Charles Perry +Reviewed-by: Andrew Lunn +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260409133654.3203336-1-charles.perry@microchip.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 2353d6eced68d..dea8b94286d15 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -963,8 +963,8 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr, + /* returning -ENODEV doesn't stop bus + * scanning + */ +- return (phy_reg == -EIO || +- phy_reg == -ENODEV) ? -ENODEV : -EIO; ++ return (ret == -EIO || ++ ret == -ENODEV) ? -ENODEV : -EIO; + + if (!ret) + continue; +-- +2.53.0 + diff --git a/queue-6.18/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch b/queue-6.18/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch new file mode 100644 index 0000000000..2e600f0cf5 --- /dev/null +++ b/queue-6.18/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch @@ -0,0 +1,67 @@ +From 505e5a8cffb284ef7c1d5cf519cf90f9ce910453 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:10:20 +0200 +Subject: net: phy: qcom: at803x: Use the correct bit to disable extended next + page + +From: Maxime Chevallier + +[ Upstream commit e7a62edd34b1b4bc5f979988efc2f81c075733fd ] + +As noted in the blamed commit, the AR8035 and other PHYs from this +family advertise the Extended Next Page support by default, which may be +understood by some partners as this PHY being multi-gig capable. + +The fix is to disable XNP advertising, which is done by setting bit 12 +of the Auto-Negotiation Advertisement Register (MII_ADVERTISE). + +The blamed commit incorrectly uses MDIO_AN_CTRL1_XNP, which is bit 13 as per +802.3 : 45.2.7.1 AN control register (Register 7.0) + +BIT 12 in MII_ADVERTISE is wrapped by ADVERTISE_RESV, used by some +drivers such as the aquantia one. 802.3 Clause 28 defines bit 12 as +Extended Next Page ability, at least in recent versions of the standard. + +Let's add a define for it and use it in the at803x driver. + +Fixes: 3c51fa5d2afe ("net: phy: ar803x: disable extended next page bit") +Signed-off-by: Maxime Chevallier +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260410171021.1277138-1-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/qcom/at803x.c | 2 +- + include/uapi/linux/mii.h | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c +index 338acd11a9b65..023c1fe0cd14b 100644 +--- a/drivers/net/phy/qcom/at803x.c ++++ b/drivers/net/phy/qcom/at803x.c +@@ -524,7 +524,7 @@ static int at803x_config_init(struct phy_device *phydev) + * behaviour but we still need to accommodate it. XNP is only needed + * for 10Gbps support, so disable XNP. + */ +- return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); ++ return phy_modify(phydev, MII_ADVERTISE, ADVERTISE_XNP, 0); + } + + static void at803x_link_change_notify(struct phy_device *phydev) +diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h +index 39f7c44baf535..61d6edad4b94a 100644 +--- a/include/uapi/linux/mii.h ++++ b/include/uapi/linux/mii.h +@@ -82,7 +82,8 @@ + #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ + #define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ + #define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +-#define ADVERTISE_RESV 0x1000 /* Unused... */ ++#define ADVERTISE_XNP 0x1000 /* Extended Next Page */ ++#define ADVERTISE_RESV ADVERTISE_XNP /* Used to be reserved */ + #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ + #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ + #define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +-- +2.53.0 + diff --git a/queue-6.18/net-psp-check-for-device-unregister-when-creating-as.patch b/queue-6.18/net-psp-check-for-device-unregister-when-creating-as.patch new file mode 100644 index 0000000000..d011535b06 --- /dev/null +++ b/queue-6.18/net-psp-check-for-device-unregister-when-creating-as.patch @@ -0,0 +1,64 @@ +From 9153469029d14422433f084ee7b24f4e49b3b09c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 12:06:06 -0700 +Subject: net: psp: check for device unregister when creating assoc + +From: Jakub Kicinski + +[ Upstream commit b89769f936a8fa9e66de72ddc1b71a9745a488e6 ] + +psp_assoc_device_get_locked() obtains a psp_dev reference via +psp_dev_get_for_sock() (which uses psp_dev_tryget() under RCU); +it then acquires psd->lock and drops the reference. Before +the lock is taken, psp_dev_unregister() can run to completion: +take psd->lock, clear out state, unlock, drop the registration +reference. + +The expectation is that the lock prevents device unregistration, +but much like with netdevs special care has to be taken when +"upgrading" a reference to a locked device. Add the missing +check if device is still alive. psp_dev_is_registered() exists +already but had no callers, which makes me wonder if I either +forgot to add this or lost the check during refactoring... + +Reported-by: Yiming Qian +Fixes: 6b46ca260e22 ("net: psp: add socket security association code") +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260427190606.366101-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/psp/psp_nl.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c +index 8aaca62744c3c..3f63ffbc5c575 100644 +--- a/net/psp/psp_nl.c ++++ b/net/psp/psp_nl.c +@@ -303,8 +303,13 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, + + psd = psp_dev_get_for_sock(socket->sk); + if (psd) { +- err = psp_dev_check_access(psd, genl_info_net(info)); +- if (err) { ++ /* Extra care needed here, psp_dev_get_for_sock() only gives ++ * us access to struct psp_dev's memory, which is quite weak. ++ */ ++ mutex_lock(&psd->lock); ++ if (!psp_dev_is_registered(psd) || ++ psp_dev_check_access(psd, genl_info_net(info))) { ++ mutex_unlock(&psd->lock); + psp_dev_put(psd); + psd = NULL; + } +@@ -317,7 +322,6 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, + + id = info->attrs[PSP_A_ASSOC_DEV_ID]; + if (psd) { +- mutex_lock(&psd->lock); + if (id && psd->id != nla_get_u32(id)) { + mutex_unlock(&psd->lock); + NL_SET_ERR_MSG_ATTR(info->extack, id, +-- +2.53.0 + diff --git a/queue-6.18/net-psp-require-admin-permission-for-dev-set-and-key.patch b/queue-6.18/net-psp-require-admin-permission-for-dev-set-and-key.patch new file mode 100644 index 0000000000..6325a15690 --- /dev/null +++ b/queue-6.18/net-psp-require-admin-permission-for-dev-set-and-key.patch @@ -0,0 +1,71 @@ +From cc51408742e3d36c1e8554385999cefa8931741a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 12:58:56 -0700 +Subject: net: psp: require admin permission for dev-set and key-rotate + +From: Jakub Kicinski + +[ Upstream commit b718342a7fbaa2dff5fefc31988c07af8c6cbc21 ] + +The dev-set and key-rotate netlink operations modify shared device +state (PSP version configuration and cryptographic key material, +respectively) but do not require CAP_NET_ADMIN. The only access +control is psp_dev_check_access() which merely verifies netns +membership. + +Fixes: 00c94ca2b99e ("psp: base PSP device support") +Reviewed-by: Daniel Zahka +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260427195856.401223-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + Documentation/netlink/specs/psp.yaml | 2 ++ + net/psp/psp-nl-gen.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Documentation/netlink/specs/psp.yaml b/Documentation/netlink/specs/psp.yaml +index 944429e5c9a84..d41ea6155e52e 100644 +--- a/Documentation/netlink/specs/psp.yaml ++++ b/Documentation/netlink/specs/psp.yaml +@@ -111,6 +111,7 @@ operations: + name: dev-set + doc: Set the configuration of a PSP device. + attribute-set: dev ++ flags: [admin-perm] + do: + request: + attributes: +@@ -130,6 +131,7 @@ operations: + name: key-rotate + doc: Rotate the device key. + attribute-set: dev ++ flags: [admin-perm] + do: + request: + attributes: +diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c +index 9fdd6f831803e..85cf90999c9f1 100644 +--- a/net/psp/psp-nl-gen.c ++++ b/net/psp/psp-nl-gen.c +@@ -70,7 +70,7 @@ static const struct genl_split_ops psp_nl_ops[] = { + .post_doit = psp_device_unlock, + .policy = psp_dev_set_nl_policy, + .maxattr = PSP_A_DEV_PSP_VERSIONS_ENA, +- .flags = GENL_CMD_CAP_DO, ++ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = PSP_CMD_KEY_ROTATE, +@@ -79,7 +79,7 @@ static const struct genl_split_ops psp_nl_ops[] = { + .post_doit = psp_device_unlock, + .policy = psp_key_rotate_nl_policy, + .maxattr = PSP_A_DEV_ID, +- .flags = GENL_CMD_CAP_DO, ++ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = PSP_CMD_RX_ASSOC, +-- +2.53.0 + diff --git a/queue-6.18/net-rds-optimize-rds_ib_laddr_check.patch b/queue-6.18/net-rds-optimize-rds_ib_laddr_check.patch new file mode 100644 index 0000000000..dcf8c7132d --- /dev/null +++ b/queue-6.18/net-rds-optimize-rds_ib_laddr_check.patch @@ -0,0 +1,189 @@ +From c9658126d2646b99b63c2bdc6a0aac2d26d131dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:19 -0700 +Subject: net/rds: Optimize rds_ib_laddr_check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 236f718ac885965fa886440b9898dfae185c9733 ] + +rds_ib_laddr_check() creates a CM_ID and attempts to bind the address +in question to it. This in order to qualify the allegedly local +address as a usable IB/RoCE address. + +In the field, ExaWatcher runs rds-ping to all ports in the fabric from +all local ports. This using all active ToS'es. In a full rack system, +we have 14 cell servers and eight db servers. Typically, 6 ToS'es are +used. This implies 528 rds-ping invocations per ExaWatcher's "RDSinfo" +interval. + +Adding to this, each rds-ping invocation creates eight sockets and +binds the local address to them: + +socket(AF_RDS, SOCK_SEQPACKET, 0) = 3 +bind(3, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 4 +bind(4, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 5 +bind(5, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 6 +bind(6, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 7 +bind(7, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 8 +bind(8, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 9 +bind(9, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 10 +bind(10, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 + +So, at every interval ExaWatcher executes rds-ping's, 4224 CM_IDs are +allocated, considering this full-rack system. After the a CM_ID has +been allocated, rdma_bind_addr() is called, with the port number being +zero. This implies that the CMA will attempt to search for an un-used +ephemeral port. Simplified, the algorithm is to start at a random +position in the available port space, and then if needed, iterate +until an un-used port is found. + +The book-keeping of used ports uses the idr system, which again uses +slab to allocate new struct idr_layer's. The size is 2092 bytes and +slab tries to reduce the wasted space. Hence, it chooses an order:3 +allocation, for which 15 idr_layer structs will fit and only 1388 +bytes are wasted per the 32KiB order:3 chunk. + +Although this order:3 allocation seems like a good space/speed +trade-off, it does not resonate well with how it used by the CMA. The +combination of the randomized starting point in the port space (which +has close to zero spatial locality) and the close proximity in time of +the 4224 invocations of the rds-ping's, creates a memory hog for +order:3 allocations. + +These costly allocations may need reclaims and/or compaction. At +worst, they may fail and produce a stack trace such as (from uek4): + +[] __inc_zone_page_state+0x35/0x40 +[] page_add_file_rmap+0x57/0x60 +[] remove_migration_pte+0x3f/0x3c0 [ksplice_6cn872bt_vmlinux_new] +[] rmap_walk+0xd8/0x340 +[] remove_migration_ptes+0x40/0x50 +[] migrate_pages+0x3ec/0x890 +[] compact_zone+0x32d/0x9a0 +[] compact_zone_order+0x6d/0x90 +[] try_to_compact_pages+0x102/0x270 +[] __alloc_pages_direct_compact+0x46/0x100 +[] __alloc_pages_nodemask+0x74b/0xaa0 +[] alloc_pages_current+0x91/0x110 +[] new_slab+0x38b/0x480 +[] __slab_alloc+0x3b7/0x4a0 [ksplice_s0dk66a8_vmlinux_new] +[] kmem_cache_alloc+0x1fb/0x250 +[] idr_layer_alloc+0x36/0x90 +[] idr_get_empty_slot+0x28c/0x3d0 +[] idr_alloc+0x4d/0xf0 +[] cma_alloc_port+0x4d/0xa0 [rdma_cm] +[] rdma_bind_addr+0x2ae/0x5b0 [rdma_cm] +[] rds_ib_laddr_check+0x83/0x2c0 [ksplice_6l2xst5i_rds_rdma_new] +[] rds_trans_get_preferred+0x5b/0xa0 [rds] +[] rds_bind+0x212/0x280 [rds] +[] SYSC_bind+0xe6/0x120 +[] SyS_bind+0xe/0x10 +[] system_call_fastpath+0x18/0xd4 + +To avoid these excessive calls to rdma_bind_addr(), we optimize +rds_ib_laddr_check() by simply checking if the address in question has +been used before. The rds_rdma module keeps track of addresses +associated with IB devices, and the function rds_ib_get_device() is +used to determine if the address already has been qualified as a valid +local address. If not found, we call the legacy rds_ib_laddr_check(), +now renamed to rds_ib_laddr_check_cm(). + +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Somasundaram Krishnasamy +Signed-off-by: Gerd Rausch +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-2-achender@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: ebf71dd4aff4 ("net/rds: Restrict use of RDS/IB to the initial network namespace") +Signed-off-by: Sasha Levin +--- + net/rds/ib.c | 20 ++++++++++++++++++-- + net/rds/ib.h | 1 + + net/rds/ib_rdma.c | 2 +- + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 9826fe7f9d008..996f007cd516b 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -403,8 +403,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len, + * allowed to influence which paths have priority. We could call userspace + * asserting this policy "routing". + */ +-static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, +- __u32 scope_id) ++static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) + { + int ret; + struct rdma_cm_id *cm_id; +@@ -489,6 +489,22 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + return ret; + } + ++static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) ++{ ++ struct rds_ib_device *rds_ibdev = NULL; ++ ++ if (ipv6_addr_v4mapped(addr)) { ++ rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); ++ if (rds_ibdev) { ++ rds_ib_dev_put(rds_ibdev); ++ return 0; ++ } ++ } ++ ++ return rds_ib_laddr_check_cm(net, addr, scope_id); ++} ++ + static void rds_ib_unregister_client(void) + { + ib_unregister_client(&rds_ib_client); +diff --git a/net/rds/ib.h b/net/rds/ib.h +index 8ef3178ed4d61..5ff346a1e8baa 100644 +--- a/net/rds/ib.h ++++ b/net/rds/ib.h +@@ -381,6 +381,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, + __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) + + /* ib_rdma.c */ ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr); + int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, + struct in6_addr *ipaddr); + void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); +diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c +index dd08ccc4246da..751755cd069e0 100644 +--- a/net/rds/ib_rdma.c ++++ b/net/rds/ib_rdma.c +@@ -43,7 +43,7 @@ struct workqueue_struct *rds_ib_mr_wq; + + static void rds_ib_odp_mr_worker(struct work_struct *work); + +-static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) + { + struct rds_ib_device *rds_ibdev; + struct rds_ib_ipaddr *i_ipaddr; +-- +2.53.0 + diff --git a/queue-6.18/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch b/queue-6.18/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch new file mode 100644 index 0000000000..f89dea26f8 --- /dev/null +++ b/queue-6.18/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch @@ -0,0 +1,86 @@ +From 3a85e6ce64466bf34ae52f9dfc33abfd7e7daf3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:20 -0700 +Subject: net/rds: Restrict use of RDS/IB to the initial network namespace + +From: Greg Jumper + +[ Upstream commit ebf71dd4aff46e8e421d455db3e231ba43d2fa8a ] + +Prevent using RDS/IB in network namespaces other than the initial one. +The existing RDS/IB code will not work properly in non-initial network +namespaces. + +Fixes: d5a8ac28a7ff ("RDS-TCP: Make RDS-TCP work correctly when it is set up in a netns other than init_net") +Reported-by: syzbot+da8e060735ae02c8f3d1@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=da8e060735ae02c8f3d1 +Signed-off-by: Greg Jumper +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-3-achender@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/af_rds.c | 10 ++++++++-- + net/rds/ib.c | 4 ++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c +index 4a7217fbeab6f..7a0f5150e9103 100644 +--- a/net/rds/af_rds.c ++++ b/net/rds/af_rds.c +@@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen) + return ret; + } + +-static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) ++static int rds_set_transport(struct net *net, struct rds_sock *rs, ++ sockptr_t optval, int optlen) + { + int t_type; + +@@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) + if (t_type < 0 || t_type >= RDS_TRANS_COUNT) + return -EINVAL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + rs->rs_transport = rds_trans_get(t_type); + + return rs->rs_transport ? 0 : -ENOPROTOOPT; +@@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) + { + struct rds_sock *rs = rds_sk_to_rs(sock->sk); ++ struct net *net = sock_net(sock->sk); + int ret; + + if (level != SOL_RDS) { +@@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + break; + case SO_RDS_TRANSPORT: + lock_sock(sock->sk); +- ret = rds_set_transport(rs, optval, optlen); ++ ret = rds_set_transport(net, rs, optval, optlen); + release_sock(sock->sk); + break; + case SO_TIMESTAMP_OLD: +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 996f007cd516b..ce5be43c5fbac 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -494,6 +494,10 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + { + struct rds_ib_device *rds_ibdev = NULL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (!net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + if (ipv6_addr_v4mapped(addr)) { + rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); + if (rds_ibdev) { +-- +2.53.0 + diff --git a/queue-6.18/net-rds-zero-per-item-info-buffer-before-handing-it-.patch b/queue-6.18/net-rds-zero-per-item-info-buffer-before-handing-it-.patch new file mode 100644 index 0000000000..af35630b9f --- /dev/null +++ b/queue-6.18/net-rds-zero-per-item-info-buffer-before-handing-it-.patch @@ -0,0 +1,111 @@ +From 1c5b9a6cbdaa8384a28dd4a447aa2b61dfde8405 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 10:10:47 -0400 +Subject: net/rds: zero per-item info buffer before handing it to visitors + +From: Michael Bommarito + +[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ] + +rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a +caller-allocated on-stack u64 buffer to a per-connection visitor and +then copy the full item_len bytes back to user space via +rds_info_copy() regardless of how much of the buffer the visitor +actually wrote. + +rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only +write a subset of their output struct when the underlying +rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl +and the two GIDs via explicit memsets). Several u32 fields +(max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, +cache_allocs) and the 2-byte alignment hole between sl and +cache_allocs remain as whatever stack contents preceded the visitor +call and are then memcpy_to_user()'d out to user space. + +struct rds_info_rdma_connection and struct rds6_info_rdma_connection +are the only rds_info_* structs in include/uapi/linux/rds.h that are +not marked __attribute__((packed)), so they have a real alignment +hole. The other info visitors (rds_conn_info_visitor, +rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of +their packed output struct today and are not known to be vulnerable, +but a future visitor that adds a conditional write-path would have +the same bug. + +Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y: +a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, +binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on +any netdev is sufficient), sendto()'s any peer on the same subnet +(fails cleanly but installs an rds_connection in the global hash in +RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, +RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 +bytes of stack garbage including kernel text/data pointers: + + 0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2 + 8..39 00 ... gids (memset-zeroed) + 40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr) + 48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max) + 56..59 01 00 08 00 rdma_mr_size (garbage) + 60..61 00 00 tos, sl + 62..63 00 00 alignment padding + 64..67 18 00 00 00 cache_allocs (garbage) + +Fix by zeroing the per-item buffer in both rds_for_each_conn_info() +and rds_walk_conn_path_info() before invoking the visitor. This +covers the IPv4/IPv6 IB visitors and hardens all current and future +visitors against the same class of bug. + +No functional change for visitors that fully populate their output. + +Changes in v2: +- retarget at the net tree (subject prefix "[PATCH net v2]", + net/rds: prefix in the title) +- pick up Reviewed-by tags from Sharath Srinivasan and + Allison Henderson + +Fixes: ec16227e1414 ("RDS/IB: Infiniband transport") +Signed-off-by: Michael Bommarito +Reviewed-by: Sharath Srinivasan +Reviewed-by: Allison Henderson +Assisted-by: Claude:claude-opus-4-7 +Link: https://patch.msgid.link/20260418141047.3398203-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/connection.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index dbfea6fa11260..4764628fe12a3 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -674,6 +674,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, + i++, head++) { + hlist_for_each_entry_rcu(conn, head, c_hash_node) { + ++ /* Zero the per-item buffer before handing it to the ++ * visitor so any field the visitor does not write - ++ * including implicit alignment padding - cannot leak ++ * stack contents to user space via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no c_lock usage.. */ + if (!visitor(conn, buffer)) + continue; +@@ -723,6 +730,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, + */ + cp = conn->c_path; + ++ /* Zero the per-item buffer for the same reason as ++ * rds_for_each_conn_info(): any byte the visitor ++ * does not write (including alignment padding) must ++ * not leak stack contents via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no cp_lock usage.. */ + if (!visitor(cp, buffer)) + continue; +-- +2.53.0 + diff --git a/queue-6.18/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch b/queue-6.18/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch new file mode 100644 index 0000000000..6136adc1e7 --- /dev/null +++ b/queue-6.18/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch @@ -0,0 +1,130 @@ +From 7c7723e437519e475a69f3919f5ba2d37e1ab118 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:16:27 -0400 +Subject: net/sched: act_ct: Only release RCU read lock after ct_ft + +From: Jamal Hadi Salim + +[ Upstream commit f462dca0c8415bf0058d0ffa476354c4476d0f09 ] + +When looking up a flow table in act_ct in tcf_ct_flow_table_get(), +rhashtable_lookup_fast() internally opens and closes an RCU read critical +section before returning ct_ft. +The tcf_ct_flow_table_cleanup_work() can complete before refcount_inc_not_zero() +is invoked on the returned ct_ft resulting in a UAF on the already freed ct_ft +object. This vulnerability can lead to privilege escalation. + +Analysis from zdi-disclosures@trendmicro.com: +When initializing act_ct, tcf_ct_init() is called, which internally triggers +tcf_ct_flow_table_get(). + +static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + +{ + struct zones_ht_key key = { .net = net, .zone = params->zone }; + struct tcf_ct_flow_table *ct_ft; + int err = -ENOMEM; + + mutex_lock(&zones_mutex); + ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); // [1] + if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) // [2] + goto out_unlock; + ... +} + +static __always_inline void *rhashtable_lookup_fast( + struct rhashtable *ht, const void *key, + const struct rhashtable_params params) +{ + void *obj; + + rcu_read_lock(); + obj = rhashtable_lookup(ht, key, params); + rcu_read_unlock(); + + return obj; +} + +At [1], rhashtable_lookup_fast() looks up and returns the corresponding ct_ft +from zones_ht . The lookup is performed within an RCU read critical section +through rcu_read_lock() / rcu_read_unlock(), which prevents the object from +being freed. However, at the point of function return, rcu_read_unlock() has +already been called, and there is nothing preventing ct_ft from being freed +before reaching refcount_inc_not_zero(&ct_ft->ref) at [2]. This interval becomes +the race window, during which ct_ft can be freed. + +Free Process: + +tcf_ct_flow_table_put() is executed through the path tcf_ct_cleanup() call_rcu() +tcf_ct_params_free_rcu() tcf_ct_params_free() tcf_ct_flow_table_put(). + +static void tcf_ct_flow_table_put(struct tcf_ct_flow_table *ct_ft) +{ + if (refcount_dec_and_test(&ct_ft->ref)) { + rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params); + INIT_RCU_WORK(&ct_ft->rwork, tcf_ct_flow_table_cleanup_work); // [3] + queue_rcu_work(act_ct_wq, &ct_ft->rwork); + } +} + +At [3], tcf_ct_flow_table_cleanup_work() is scheduled as RCU work + +static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) + +{ + struct tcf_ct_flow_table *ct_ft; + struct flow_block *block; + + ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, + rwork); + nf_flow_table_free(&ct_ft->nf_ft); + block = &ct_ft->nf_ft.flow_block; + down_write(&ct_ft->nf_ft.flow_block_lock); + WARN_ON(!list_empty(&block->cb_list)); + up_write(&ct_ft->nf_ft.flow_block_lock); + kfree(ct_ft); // [4] + + module_put(THIS_MODULE); +} + +tcf_ct_flow_table_cleanup_work() frees ct_ft at [4]. When this function executes +between [1] and [2], UAF occurs. + +This race condition has a very short race window, making it generally +difficult to trigger. Therefore, to trigger the vulnerability an msleep(100) was +inserted after[1] + +Fixes: 138470a9b2cc2 ("net/sched: act_ct: fix lockdep splat in tcf_ct_flow_table_get") +Reported-by: zdi-disclosures@trendmicro.com +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260410111627.46611-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/act_ct.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index b3c160ad590d2..f9cb8f7474ed3 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -326,9 +326,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + int err = -ENOMEM; + + mutex_lock(&zones_mutex); +- ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); +- if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) ++ rcu_read_lock(); ++ ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params); ++ if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) { ++ rcu_read_unlock(); + goto out_unlock; ++ } ++ rcu_read_unlock(); + + ct_ft = kzalloc(sizeof(*ct_ft), GFP_KERNEL); + if (!ct_ft) +-- +2.53.0 + diff --git a/queue-6.18/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch b/queue-6.18/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch new file mode 100644 index 0000000000..f35d8a5458 --- /dev/null +++ b/queue-6.18/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch @@ -0,0 +1,59 @@ +From 3942182871b5faa4ac1bb458be66ae8ed08c8482 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:49:27 +0800 +Subject: net/sched: act_mirred: fix wrong device for mac_header_xmit check in + tcf_blockcast_redir +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit 4510d140524ca7d6e772db962e013f26f09a63b1 ] + +In tcf_blockcast_redir(), when iterating block ports to redirect +packets to multiple devices, the mac_header_xmit flag is queried +from the wrong device. The loop sends to dev_prev but queries +dev_is_mac_header_xmit(dev) — which is the NEXT device in the +iteration, not the one being sent to. + +This causes tcf_mirred_to_dev() to make incorrect decisions about +whether to push or pull the MAC header. When the block contains +mixed device types (e.g., an ethernet veth and a tunnel device), +intermediate devices get the wrong mac_header_xmit flag, leading to +skb header corruption. In the worst case, skb_push_rcsum with an +incorrect mac_len can exhaust headroom and panic. + +The last device in the loop is handled correctly (line 365-366 uses +dev_is_mac_header_xmit(dev_prev)), confirming this is a copy-paste +oversight for the intermediate devices. + +Fix by using dev_prev instead of dev for the mac_header_xmit query, +consistent with the device actually being sent to. + +Fixes: 42f39036cda8 ("net/sched: act_mirred: Allow mirred to block") +Signed-off-by: Dudu Lu +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260413084927.71353-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/act_mirred.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index 5f01f567c934d..18d9378a9c113 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -370,7 +370,7 @@ static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m, + goto assign_prev; + + tcf_mirred_to_dev(skb, m, dev_prev, +- dev_is_mac_header_xmit(dev), ++ dev_is_mac_header_xmit(dev_prev), + mirred_eaction, retval); + assign_prev: + dev_prev = dev; +-- +2.53.0 + diff --git a/queue-6.18/net-sched-cls_flower-revert-unintended-changes.patch b/queue-6.18/net-sched-cls_flower-revert-unintended-changes.patch new file mode 100644 index 0000000000..6ada5572ec --- /dev/null +++ b/queue-6.18/net-sched-cls_flower-revert-unintended-changes.patch @@ -0,0 +1,55 @@ +From 7eccfb83de573d033cebbff45202406e6e18e3c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:39:11 +0200 +Subject: net/sched: cls_flower: revert unintended changes + +From: Paolo Abeni + +[ Upstream commit 1e01abec856593e02cd69fd95b784c10dd46880c ] + +While applying the blamed commit 4ca07b9239bd ("net: mctp i2c: check +length before marking flow active"), I unintentionally included +unrelated and unacceptable changes. + +Revert them. + +Fixes: 4ca07b9239bd ("net: mctp i2c: check length before marking flow active") +Reported-by: Jeremy Kerr +Closes: https://lore.kernel.org/netdev/bd8704fe0bd53e278add5cde4873256656623e2e.camel@codeconstruct.com.au/ +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/043026a53ff84da88b17648c4b0d17f0331749cb.1777447863.git.pabeni@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/cls_flower.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index f3af0ac892a86..099ff6a3e1f51 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -560,7 +560,6 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); +- struct fl_flow_mask *mask; + + *last = false; + +@@ -577,12 +576,11 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- mask = f->mask; ++ *last = fl_mask_put(head, f->mask); + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); +- *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/net-sched-netem-check-for-negative-latency-and-jitte.patch b/queue-6.18/net-sched-netem-check-for-negative-latency-and-jitte.patch new file mode 100644 index 0000000000..5d77aac8fc --- /dev/null +++ b/queue-6.18/net-sched-netem-check-for-negative-latency-and-jitte.patch @@ -0,0 +1,73 @@ +From ebbec0622a56740c837ad1bba695794619dfa0e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:44 -0700 +Subject: net/sched: netem: check for negative latency and jitter + +From: Stephen Hemminger + +[ Upstream commit 90be9fedb218ee95a1cf59050d1306fbfb0e8b87 ] + +Reject requests with negative latency or jitter. +A negative value added to current timestamp (u64) wraps +to an enormous time_to_send, disabling dequeue. +The original UAPI used u32 for these values; the conversion to 64-bit +time values via TCA_NETEM_LATENCY64 and TCA_NETEM_JITTER64 +allowed signed values to reach the kernel without validation. + +Jitter is already silently clamped by an abs() in netem_change(); +that abs() can be removed in a follow-up once this rejection is in +place. + +Fixes: 99803171ef04 ("netem: add uapi to express delay and jitter in nanoseconds") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-7-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 6e221bdfb3871..47db6da905c58 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -825,6 +825,16 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_time(const struct nlattr *attr, const char *name, ++ struct netlink_ext_ack *extack) ++{ ++ if (nla_get_s64(attr) < 0) { ++ NL_SET_ERR_MSG_ATTR_FMT(extack, attr, "negative %s", name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1067,6 +1077,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_LATENCY64]) { ++ ret = validate_time(tb[TCA_NETEM_LATENCY64], "latency", extack); ++ if (ret) ++ goto table_free; ++ } ++ ++ if (tb[TCA_NETEM_JITTER64]) { ++ ret = validate_time(tb[TCA_NETEM_JITTER64], "jitter", extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-6.18/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch b/queue-6.18/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch new file mode 100644 index 0000000000..43ce9b9600 --- /dev/null +++ b/queue-6.18/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch @@ -0,0 +1,67 @@ +From 94434845cde71e0766234845e9f5a97a00d865ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:39 -0700 +Subject: net/sched: netem: fix probability gaps in 4-state loss model + +From: Stephen Hemminger + +[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ] + +The 4-state Markov chain in loss_4state() has gaps at the boundaries +between transition probability ranges. The comparisons use: + + if (rnd < a4) + else if (a4 < rnd && rnd < a1 + a4) + +When rnd equals a boundary value exactly, neither branch matches and +no state transition occurs. The redundant lower-bound check (a4 < rnd) +is already implied by being in the else branch. + +Remove the unnecessary lower-bound comparisons so the ranges are +contiguous and every random value produces a transition, matching +the GI (General and Intuitive) loss model specification. + +This bug goes back to original implementation of this model. + +Fixes: 661b79725fea ("netem: revised correlated loss generator") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-2-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 6f8fcc4b504ce..4eb6ed60ee9b6 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -227,10 +227,10 @@ static bool loss_4state(struct netem_sched_data *q) + if (rnd < clg->a4) { + clg->state = LOST_IN_GAP_PERIOD; + return true; +- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { ++ } else if (rnd < clg->a1 + clg->a4) { + clg->state = LOST_IN_BURST_PERIOD; + return true; +- } else if (clg->a1 + clg->a4 < rnd) { ++ } else { + clg->state = TX_IN_GAP_PERIOD; + } + +@@ -247,9 +247,9 @@ static bool loss_4state(struct netem_sched_data *q) + case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; +- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { ++ else if (rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; +- } else if (clg->a2 + clg->a3 < rnd) { ++ } else { + clg->state = LOST_IN_BURST_PERIOD; + return true; + } +-- +2.53.0 + diff --git a/queue-6.18/net-sched-netem-fix-queue-limit-check-to-include-reo.patch b/queue-6.18/net-sched-netem-fix-queue-limit-check-to-include-reo.patch new file mode 100644 index 0000000000..5eb6ff9364 --- /dev/null +++ b/queue-6.18/net-sched-netem-fix-queue-limit-check-to-include-reo.patch @@ -0,0 +1,42 @@ +From 7e6d55bc414b16cfa9cc9399fad675d61158fa0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:40 -0700 +Subject: net/sched: netem: fix queue limit check to include reordered packets + +From: Stephen Hemminger + +[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ] + +The queue limit check in netem_enqueue() uses q->t_len which only +counts packets in the internal tfifo. Packets placed in sch->q by +the reorder path (__qdisc_enqueue_head) are not counted, allowing +the total queue occupancy to exceed sch->limit under reordering. + +Include sch->q.qlen in the limit check. + +Fixes: f8d4bc455047 ("net/sched: netem: account for backlog updates from child qdisc") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-3-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 4eb6ed60ee9b6..da8dcc9b61cc7 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -523,7 +523,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + 1 << get_random_u32_below(8); + } + +- if (unlikely(q->t_len >= sch->limit)) { ++ if (unlikely(sch->q.qlen >= sch->limit)) { + /* re-link segs, so that qdisc_drop_all() frees them all */ + skb->next = segs; + qdisc_drop_all(skb, sch, to_free); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-netem-fix-slot-delay-calculation-overflow.patch b/queue-6.18/net-sched-netem-fix-slot-delay-calculation-overflow.patch new file mode 100644 index 0000000000..38350929bf --- /dev/null +++ b/queue-6.18/net-sched-netem-fix-slot-delay-calculation-overflow.patch @@ -0,0 +1,51 @@ +From 6cd0d2003f43db5435b9c5b3b6d1558b807d0f5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:43 -0700 +Subject: net/sched: netem: fix slot delay calculation overflow + +From: Stephen Hemminger + +[ Upstream commit 51e94e1e2fef351c74d69eb53666df808d26af95 ] + +get_slot_next() computes a random delay between min_delay and +max_delay using: + + get_random_u32() * (max_delay - min_delay) >> 32 + +This overflows signed 64-bit arithmetic when the delay range exceeds +approximately 2.1 seconds (2^31 nanoseconds), producing a negative +result that effectively disables slot-based pacing. This is a +realistic configuration for WAN emulation (e.g., slot 1s 5s). + +Use mul_u64_u32_shr() which handles the widening multiply without +overflow. + +Fixes: 0a9fe5c375b5 ("netem: slotting with non-uniform distribution") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-6-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 41d60e904090d..6e221bdfb3871 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -658,9 +658,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now) + + if (!q->slot_dist) + next_delay = q->slot_config.min_delay + +- (get_random_u32() * +- (q->slot_config.max_delay - +- q->slot_config.min_delay) >> 32); ++ mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay, ++ get_random_u32(), 32); + else + next_delay = tabledist(q->slot_config.dist_delay, + (s32)(q->slot_config.dist_jitter), +-- +2.53.0 + diff --git a/queue-6.18/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch b/queue-6.18/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch new file mode 100644 index 0000000000..e808f8b5e5 --- /dev/null +++ b/queue-6.18/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch @@ -0,0 +1,60 @@ +From 18ae8220e078053cca97b063221576456e1fffb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:41 -0700 +Subject: net/sched: netem: only reseed PRNG when seed is explicitly provided + +From: Stephen Hemminger + +[ Upstream commit 986afaf809940577224a99c3a08d97a15eb37e93 ] + +netem_change() unconditionally reseeds the PRNG on every tc change +command. If TCA_NETEM_PRNG_SEED is not specified, a new random seed +is generated, destroying reproducibility for users who set a +deterministic seed on a previous change. + +Move the initial random seed generation to netem_init() and only +reseed in netem_change() when TCA_NETEM_PRNG_SEED is explicitly +provided by the user. + +Fixes: 4072d97ddc44 ("netem: add prng attribute to netem_sched_data") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-4-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index da8dcc9b61cc7..4bf65fcdaff02 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1111,11 +1111,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + /* capping jitter to the range acceptable by tabledist() */ + q->jitter = min_t(s64, abs(q->jitter), INT_MAX); + +- if (tb[TCA_NETEM_PRNG_SEED]) ++ if (tb[TCA_NETEM_PRNG_SEED]) { + q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]); +- else +- q->prng.seed = get_random_u64(); +- prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ } + + unlock: + sch_tree_unlock(sch); +@@ -1138,6 +1137,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt, + return -EINVAL; + + q->loss_model = CLG_RANDOM; ++ q->prng.seed = get_random_u64(); ++ prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ + ret = netem_change(sch, opt, extack); + if (ret) + pr_info("netem: change failed\n"); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-netem-validate-slot-configuration.patch b/queue-6.18/net-sched-netem-validate-slot-configuration.patch new file mode 100644 index 0000000000..3d542e97fb --- /dev/null +++ b/queue-6.18/net-sched-netem-validate-slot-configuration.patch @@ -0,0 +1,86 @@ +From bccdb26e970057d21ae53d3daa6c93297af58911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:42 -0700 +Subject: net/sched: netem: validate slot configuration + +From: Stephen Hemminger + +[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ] + +Reject slot configurations that have no defensible meaning: + + - negative min_delay or max_delay + - min_delay greater than max_delay + - negative dist_delay or dist_jitter + - negative max_packets or max_bytes + +Negative or out-of-order delays underflow in get_slot_next(), +producing garbage intervals. Negative limits trip the per-slot +accounting (packets_left/bytes_left <= 0) on the first packet of +every slot, defeating the rate-limiting half of the slot feature. + +Note that dist_jitter has been silently coerced to its absolute +value by get_slot() since the feature was introduced; rejecting +negatives here converts that silent coercion into -EINVAL. The +abs() can be removed in a follow-up. + +Fixes: 836af83b54e3 ("netem: support delivering packets in delayed time slots") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 4bf65fcdaff02..41d60e904090d 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -826,6 +826,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) ++{ ++ const struct tc_netem_slot *c = nla_data(attr); ++ ++ if (c->min_delay < 0 || c->max_delay < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); ++ return -EINVAL; ++ } ++ if (c->min_delay > c->max_delay) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); ++ return -EINVAL; ++ } ++ if (c->dist_delay < 0 || c->dist_jitter < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); ++ return -EINVAL; ++ } ++ if (c->max_packets < 0 || c->max_bytes < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1039,6 +1062,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_SLOT]) { ++ ret = validate_slot(tb[TCA_NETEM_SLOT], extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch b/queue-6.18/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch new file mode 100644 index 0000000000..e20e6df37c --- /dev/null +++ b/queue-6.18/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch @@ -0,0 +1,139 @@ +From 74a5cc94a3d699f1632a106a1d681f584887dcdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:04 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (III) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit 276a98a434964088fccd4745db5b34d6e831e358 ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this third patch, I add READ_ONCE()/WRITE_ONCE() annotations +for the following fields: + +- packets +- tin_dropped +- tin_ecn_mark +- ack_drops +- peak_delay +- avge_delay +- base_delay + +Other annotations are added in following patches, to ease code review. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-4-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 38 ++++++++++++++++++++------------------ + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 1a2023cd55109..7b97f6b57cb17 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -1590,7 +1590,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) + sch->qstats.backlog -= len; + + flow->dropped++; +- b->tin_dropped++; ++ WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1); + + if (q->rate_flags & CAKE_FLAG_INGRESS) + cake_advance_shaper(q, b, skb, now, true); +@@ -1808,7 +1808,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + numsegs++; + slen += segs->len; + q->buffer_used += segs->truesize; +- b->packets++; ++ WRITE_ONCE(b->packets, b->packets + 1); + } + + /* stats */ +@@ -1832,7 +1832,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + ack = cake_ack_filter(q, flow); + + if (ack) { +- b->ack_drops++; ++ WRITE_ONCE(b->ack_drops, b->ack_drops + 1); + sch->qstats.drops++; + ack_pkt_len = qdisc_pkt_len(ack); + b->bytes += ack_pkt_len; +@@ -1848,7 +1848,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + + /* stats */ +- b->packets++; ++ WRITE_ONCE(b->packets, b->packets + 1); + b->bytes += len - ack_pkt_len; + b->backlogs[idx] += len - ack_pkt_len; + b->tin_backlog += len - ack_pkt_len; +@@ -2191,7 +2191,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + b->tin_deficit -= len; + } + flow->dropped++; +- b->tin_dropped++; ++ WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1); + qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb)); + qdisc_qstats_drop(sch); + kfree_skb_reason(skb, reason); +@@ -2199,16 +2199,18 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + goto retry; + } + +- b->tin_ecn_mark += !!flow->cvars.ecn_marked; ++ WRITE_ONCE(b->tin_ecn_mark, b->tin_ecn_mark + !!flow->cvars.ecn_marked); + qdisc_bstats_update(sch, skb); + + /* collect delay stats */ + delay = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb))); +- b->avge_delay = cake_ewma(b->avge_delay, delay, 8); +- b->peak_delay = cake_ewma(b->peak_delay, delay, +- delay > b->peak_delay ? 2 : 8); +- b->base_delay = cake_ewma(b->base_delay, delay, +- delay < b->base_delay ? 2 : 8); ++ WRITE_ONCE(b->avge_delay, cake_ewma(b->avge_delay, delay, 8)); ++ WRITE_ONCE(b->peak_delay, ++ cake_ewma(b->peak_delay, delay, ++ delay > b->peak_delay ? 2 : 8)); ++ WRITE_ONCE(b->base_delay, ++ cake_ewma(b->base_delay, delay, ++ delay < b->base_delay ? 2 : 8)); + + len = cake_advance_shaper(q, b, skb, now, false); + flow->deficit -= len; +@@ -2940,17 +2942,17 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(INTERVAL_US, + ktime_to_us(ns_to_ktime(b->cparams.interval))); + +- PUT_TSTAT_U32(SENT_PACKETS, b->packets); +- PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); +- PUT_TSTAT_U32(ECN_MARKED_PACKETS, b->tin_ecn_mark); +- PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, b->ack_drops); ++ PUT_TSTAT_U32(SENT_PACKETS, READ_ONCE(b->packets)); ++ PUT_TSTAT_U32(DROPPED_PACKETS, READ_ONCE(b->tin_dropped)); ++ PUT_TSTAT_U32(ECN_MARKED_PACKETS, READ_ONCE(b->tin_ecn_mark)); ++ PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, READ_ONCE(b->ack_drops)); + + PUT_TSTAT_U32(PEAK_DELAY_US, +- ktime_to_us(ns_to_ktime(b->peak_delay))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->peak_delay)))); + PUT_TSTAT_U32(AVG_DELAY_US, +- ktime_to_us(ns_to_ktime(b->avge_delay))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->avge_delay)))); + PUT_TSTAT_U32(BASE_DELAY_US, +- ktime_to_us(ns_to_ktime(b->base_delay))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->base_delay)))); + + PUT_TSTAT_U32(WAY_INDIRECT_HITS, b->way_hits); + PUT_TSTAT_U32(WAY_MISSES, b->way_misses); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-23535 b/queue-6.18/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-23535 new file mode 100644 index 0000000000..4d40e144d0 --- /dev/null +++ b/queue-6.18/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-23535 @@ -0,0 +1,62 @@ +From c518ad6508ca09791fc2af4c79da1da91c58680c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:06 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (V) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations +for cparams.target and cparams.interval. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 7b97f6b57cb17..f2ad946a519c2 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -2305,10 +2305,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + + byte_target_ns = (byte_target * rate_ns) >> rate_shft; + +- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); +- b->cparams.interval = max(rtt_est_ns + +- b->cparams.target - target_ns, +- b->cparams.target * 2); ++ WRITE_ONCE(b->cparams.target, ++ max((byte_target_ns * 3) / 2, target_ns)); ++ WRITE_ONCE(b->cparams.interval, ++ max(rtt_est_ns + b->cparams.target - target_ns, ++ b->cparams.target * 2)); + b->cparams.mtu_time = byte_target_ns; + b->cparams.p_inc = 1 << 24; /* 1/256 */ + b->cparams.p_dec = 1 << 20; /* 1/4096 */ +@@ -2938,9 +2939,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); + + PUT_TSTAT_U32(TARGET_US, +- ktime_to_us(ns_to_ktime(b->cparams.target))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); + PUT_TSTAT_U32(INTERVAL_US, +- ktime_to_us(ns_to_ktime(b->cparams.interval))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); + + PUT_TSTAT_U32(SENT_PACKETS, READ_ONCE(b->packets)); + PUT_TSTAT_U32(DROPPED_PACKETS, READ_ONCE(b->tin_dropped)); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch b/queue-6.18/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch new file mode 100644 index 0000000000..9b9420329b --- /dev/null +++ b/queue-6.18/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch @@ -0,0 +1,64 @@ +From a5c349fc143911a280ded178de7b5910e7be6f7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:00:41 +0800 +Subject: net/sched: sch_cake: fix NAT destination port not being updated in + cake_update_flowkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit f9e40664706927d7ae22a448a3383e23c38a4c0b ] + +cake_update_flowkeys() is supposed to update the flow dissector keys +with the NAT-translated addresses and ports from conntrack, so that +CAKE's per-flow fairness correctly identifies post-NAT flows as +belonging to the same connection. + +For the source port, this works correctly: + keys->ports.src = port; + +But for the destination port, the assignment is reversed: + port = keys->ports.dst; + +This means the NAT destination port is never updated in the flow keys. +As a result, when multiple connections are NATed to the same destination, +CAKE treats them as separate flows because the original (pre-NAT) +destination ports differ. This breaks CAKE's NAT-aware flow isolation +when using the "nat" mode. + +The bug was introduced in commit b0c19ed6088a ("sch_cake: Take advantage +of skb->hash where appropriate") which refactored the original direct +assignment into a compare-and-conditionally-update pattern, but wrote +the destination port update backwards. + +Fix by reversing the assignment direction to match the source port +pattern. + +Fixes: b0c19ed6088a ("sch_cake: Take advantage of skb->hash where appropriate") +Signed-off-by: Dudu Lu +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260413110041.44704-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index d325a90cde9ee..1a2023cd55109 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -606,7 +606,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys, + } + port = rev ? tuple.src.u.all : tuple.dst.u.all; + if (port != keys->ports.dst) { +- port = keys->ports.dst; ++ keys->ports.dst = port; + upd = true; + } + } +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch b/queue-6.18/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch new file mode 100644 index 0000000000..1e1ed550de --- /dev/null +++ b/queue-6.18/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch @@ -0,0 +1,97 @@ +From 84f949216038e4892ba06dca5349d622dc3366b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:28:39 +0000 +Subject: net/sched: sch_choke: annotate data-races in choke_dump_stats() + +From: Eric Dumazet + +[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ] + +choke_dump_stats() only runs with RTNL held. +It reads fields that can be changed in qdisc fast path. +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423062839.2524324-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index 59e7bdf5063e8..ea6ef76c29658 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + /* Draw a packet at random from queue and compare flow */ + if (choke_match_random(q, skb, &idx)) { +- q->stats.matched++; ++ WRITE_ONCE(q->stats.matched, q->stats.matched + 1); + choke_drop_by_idx(sch, idx, to_free); + goto congestion_drop; + } +@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + qdisc_qstats_overlimit(sch); + if (use_harddrop(q) || !use_ecn(q) || + !INET_ECN_set_ce(skb)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + } else if (++q->vars.qcount) { + if (red_mark_probability(p, &q->vars, q->vars.qavg)) { + q->vars.qcount = 0; +@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + qdisc_qstats_overlimit(sch); + if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + } + } else + q->vars.qR = red_random(p); +@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + } + +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); + return qdisc_drop(skb, sch, to_free); + + congestion_drop: +@@ -461,10 +465,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct choke_sched_data *q = qdisc_priv(sch); + struct tc_choke_xstats st = { +- .early = q->stats.prob_drop + q->stats.forced_drop, +- .marked = q->stats.prob_mark + q->stats.forced_mark, +- .pdrop = q->stats.pdrop, +- .matched = q->stats.matched, ++ .early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop), ++ .marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark), ++ .pdrop = READ_ONCE(q->stats.pdrop), ++ .matched = READ_ONCE(q->stats.matched), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_dualpi2-drain-both-c-queue-and-l-queue.patch b/queue-6.18/net-sched-sch_dualpi2-drain-both-c-queue-and-l-queue.patch new file mode 100644 index 0000000000..a0c431c777 --- /dev/null +++ b/queue-6.18/net-sched-sch_dualpi2-drain-both-c-queue-and-l-queue.patch @@ -0,0 +1,85 @@ +From c800d64a6683e8d1e427b6de89341cddf141adde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 17:25:51 +0200 +Subject: net/sched: sch_dualpi2: drain both C-queue and L-queue in + dualpi2_change() + +From: Chia-Yu Chang + +[ Upstream commit 478ed6b7d2577439c610f91fa8759a4c878a4264 ] + +Fix dualpi2_change() to correctly enforce updated limit and memlimit +values after a configuration change of the dualpi2 qdisc. + +Before this patch, dualpi2_change() always attempted to dequeue packets +via the root qdisc (C-queue) when reducing backlog or memory usage, and +unconditionally assumed that a valid skb will be returned. When traffic +classification results in packets being queued in the L-queue while the +C-queue is empty, this leads to a NULL skb dereference during limit or +memlimit enforcement. + +This is fixed by first dequeuing from the C-queue path if it is +non-empty. Once the C-queue is empty, packets are dequeued directly from +the L-queue. Return values from qdisc_dequeue_internal() are checked for +both queues. When dequeuing from the L-queue, the parent qdisc qlen and +backlog counters are updated explicitly to keep overall qdisc statistics +consistent. + +Fixes: 320d031ad6e4 ("sched: Struct definition and parsing of dualpi2 qdisc") +Reported-by: "Kito Xu (veritas501)" +Closes: https://lore.kernel.org/netdev/20260413075740.2234828-1-hxzene@gmail.com/ +Signed-off-by: Chia-Yu Chang +Link: https://patch.msgid.link/20260417152551.71648-1-chia-yu.chang@nokia-bell-labs.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_dualpi2.c | 32 ++++++++++++++++++++++++++++---- + 1 file changed, 28 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c +index 4b975feb52b1f..efa32240c5a95 100644 +--- a/net/sched/sch_dualpi2.c ++++ b/net/sched/sch_dualpi2.c +@@ -871,11 +871,35 @@ static int dualpi2_change(struct Qdisc *sch, struct nlattr *opt, + old_backlog = sch->qstats.backlog; + while (qdisc_qlen(sch) > sch->limit || + q->memory_used > q->memory_limit) { +- struct sk_buff *skb = qdisc_dequeue_internal(sch, true); ++ struct sk_buff *skb = NULL; + +- q->memory_used -= skb->truesize; +- qdisc_qstats_backlog_dec(sch, skb); +- rtnl_qdisc_drop(skb, sch); ++ if (qdisc_qlen(sch) > qdisc_qlen(q->l_queue)) { ++ skb = qdisc_dequeue_internal(sch, true); ++ if (unlikely(!skb)) { ++ WARN_ON_ONCE(1); ++ break; ++ } ++ q->memory_used -= skb->truesize; ++ rtnl_qdisc_drop(skb, sch); ++ } else if (qdisc_qlen(q->l_queue)) { ++ skb = qdisc_dequeue_internal(q->l_queue, true); ++ if (unlikely(!skb)) { ++ WARN_ON_ONCE(1); ++ break; ++ } ++ /* L-queue packets are counted in both sch and ++ * l_queue on enqueue; qdisc_dequeue_internal() ++ * handled l_queue, so we further account for sch. ++ */ ++ --sch->q.qlen; ++ qdisc_qstats_backlog_dec(sch, skb); ++ q->memory_used -= skb->truesize; ++ rtnl_qdisc_drop(skb, q->l_queue); ++ qdisc_qstats_drop(sch); ++ } else { ++ WARN_ON_ONCE(1); ++ break; ++ } + } + qdisc_tree_reduce_backlog(sch, old_qlen - qdisc_qlen(sch), + old_backlog - sch->qstats.backlog); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch b/queue-6.18/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch new file mode 100644 index 0000000000..5c78dcc029 --- /dev/null +++ b/queue-6.18/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch @@ -0,0 +1,47 @@ +From ce81c5bcbde9378aee8bc8d5c3f40a78ed99f0aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:25:09 +0000 +Subject: net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats() + +From: Eric Dumazet + +[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill st.qdisc_stats with live data. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142509.3967231-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_codel.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index a141423929394..90e1dfac6f594 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -584,6 +584,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + }; + struct list_head *pos; + ++ sch_tree_lock(sch); ++ + st.qdisc_stats.maxpacket = q->cstats.maxpacket; + st.qdisc_stats.drop_overlimit = q->drop_overlimit; + st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; +@@ -592,7 +594,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + st.qdisc_stats.memory_usage = q->memory_usage; + st.qdisc_stats.drop_overmemory = q->drop_overmemory; + +- sch_tree_lock(sch); + list_for_each(pos, &q->new_flows) + st.qdisc_stats.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch b/queue-6.18/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch new file mode 100644 index 0000000000..b008ae65ea --- /dev/null +++ b/queue-6.18/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch @@ -0,0 +1,62 @@ +From db97223a37171e87660506804a1a7cdcb5a450a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:35:27 +0000 +Subject: net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill tc_fq_pie_xstats with live data. + +Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, +but the spinlock is needed anyway to scan q->new_flows and q->old_flows. + +Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423063527.2568262-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_pie.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index 7b96bc3ff8918..0c7b2095f8655 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -510,18 +510,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb) + static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct fq_pie_sched_data *q = qdisc_priv(sch); +- struct tc_fq_pie_xstats st = { +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .overmemory = q->overmemory, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, +- .new_flow_count = q->new_flow_count, +- .memory_usage = q->memory_usage, +- }; ++ struct tc_fq_pie_xstats st = { 0 }; + struct list_head *pos; + + sch_tree_lock(sch); ++ ++ st.packets_in = q->stats.packets_in; ++ st.overlimit = q->stats.overlimit; ++ st.overmemory = q->overmemory; ++ st.dropped = q->stats.dropped; ++ st.ecn_mark = q->stats.ecn_mark; ++ st.new_flow_count = q->new_flow_count; ++ st.memory_usage = q->memory_usage; ++ + list_for_each(pos, &q->new_flows) + st.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch b/queue-6.18/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch new file mode 100644 index 0000000000..5f5ae0d922 --- /dev/null +++ b/queue-6.18/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch @@ -0,0 +1,160 @@ +From 09feb4f11df0ef3093c2db7eaa2ae49efec93d60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:29:44 +0000 +Subject: net/sched: sch_pie: annotate data-races in pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ] + +pie_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_pie_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142944.4009941-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/pie.h | 2 +- + net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/include/net/pie.h b/include/net/pie.h +index 01cbc66825a40..1f3db0c355149 100644 +--- a/include/net/pie.h ++++ b/include/net/pie.h +@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) + vars->dq_tstamp = DTIME_INVALID; + vars->accu_prob = 0; + vars->dq_count = DQCOUNT_INVALID; +- vars->avg_dq_rate = 0; ++ WRITE_ONCE(vars->avg_dq_rate, 0); + } + + static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb) +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index 0a377313b6a9d..73650200482f4 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -90,7 +90,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + bool enqueue = false; + + if (unlikely(qdisc_qlen(sch) >= sch->limit)) { +- q->stats.overlimit++; ++ WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1); + goto out; + } + +@@ -104,7 +104,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + /* If packet is ecn capable, mark it if drop probability + * is lower than 10%, else drop it. + */ +- q->stats.ecn_mark++; ++ WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1); + enqueue = true; + } + +@@ -114,15 +114,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + if (!q->params.dq_rate_estimator) + pie_set_enqueue_time(skb); + +- q->stats.packets_in++; ++ WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1); + if (qdisc_qlen(sch) > q->stats.maxq) +- q->stats.maxq = qdisc_qlen(sch); ++ WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch)); + + return qdisc_enqueue_tail(skb, sch); + } + + out: +- q->stats.dropped++; ++ WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1); + q->vars.accu_prob = 0; + return qdisc_drop_reason(skb, sch, to_free, reason); + } +@@ -267,11 +267,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, + count = count / dtime; + + if (vars->avg_dq_rate == 0) +- vars->avg_dq_rate = count; ++ WRITE_ONCE(vars->avg_dq_rate, count); + else +- vars->avg_dq_rate = ++ WRITE_ONCE(vars->avg_dq_rate, + (vars->avg_dq_rate - +- (vars->avg_dq_rate >> 3)) + (count >> 3); ++ (vars->avg_dq_rate >> 3)) + (count >> 3)); + + /* If the queue has receded below the threshold, we hold + * on to the last drain rate calculated, else we reset +@@ -381,7 +381,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + if (delta > 0) { + /* prevent overflow */ + if (vars->prob < oldprob) { +- vars->prob = MAX_PROB; ++ WRITE_ONCE(vars->prob, MAX_PROB); + /* Prevent normalization error. If probability is at + * maximum value already, we normalize it here, and + * skip the check to do a non-linear drop in the next +@@ -392,7 +392,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + } else { + /* prevent underflow */ + if (vars->prob > oldprob) +- vars->prob = 0; ++ WRITE_ONCE(vars->prob, 0); + } + + /* Non-linear drop in probability: Reduce drop probability quickly if +@@ -403,7 +403,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + /* Reduce drop probability to 98.4% */ + vars->prob -= vars->prob / 64; + +- vars->qdelay = qdelay; ++ WRITE_ONCE(vars->qdelay, qdelay); + vars->backlog_old = backlog; + + /* We restart the measurement cycle if the following conditions are met +@@ -502,21 +502,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + struct pie_sched_data *q = qdisc_priv(sch); + struct tc_pie_xstats st = { + .prob = q->vars.prob << BITS_PER_BYTE, +- .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / ++ .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) / + NSEC_PER_USEC, +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .maxq = q->stats.maxq, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, ++ .packets_in = READ_ONCE(q->stats.packets_in), ++ .overlimit = READ_ONCE(q->stats.overlimit), ++ .maxq = READ_ONCE(q->stats.maxq), ++ .dropped = READ_ONCE(q->stats.dropped), ++ .ecn_mark = READ_ONCE(q->stats.ecn_mark), + }; + + /* avg_dq_rate is only valid if dq_rate_estimator is enabled */ + st.dq_rate_estimating = q->params.dq_rate_estimator; + + /* unscale and return dq_rate in bytes per sec */ +- if (q->params.dq_rate_estimator) +- st.avg_dq_rate = q->vars.avg_dq_rate * ++ if (st.dq_rate_estimating) ++ st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) * + (PSCHED_TICKS_PER_SEC) >> PIE_SCALE; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch b/queue-6.18/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch new file mode 100644 index 0000000000..236aec4bff --- /dev/null +++ b/queue-6.18/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch @@ -0,0 +1,112 @@ +From 4800dce79508202998d20baac00f2b6525cbdad8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:23:09 +0000 +Subject: net/sched: sch_red: annotate data-races in red_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ] + +red_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_red_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142309.3964322-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_red.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index 68ee41ce78c50..86651a68d4015 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -90,17 +90,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_PROB_MARK: + qdisc_qstats_overlimit(sch); + if (!red_use_ecn(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +@@ -111,17 +114,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + reason = SKB_DROP_REASON_QDISC_OVERLIMIT; + qdisc_qstats_overlimit(sch); + if (red_use_harddrop(q) || !red_use_ecn(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +@@ -135,7 +141,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->qstats.backlog += len; + sch->q.qlen++; + } else if (net_xmit_drop_count(ret)) { +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, ++ q->stats.pdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -463,9 +470,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, + &hw_stats_request); + } +- st.early = q->stats.prob_drop + q->stats.forced_drop; +- st.pdrop = q->stats.pdrop; +- st.marked = q->stats.prob_mark + q->stats.forced_mark; ++ st.early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop); ++ ++ st.pdrop = READ_ONCE(q->stats.pdrop); ++ ++ st.marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark); + + return gnet_stats_copy_app(d, &st, sizeof(st)); + } +-- +2.53.0 + diff --git a/queue-6.18/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch b/queue-6.18/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch new file mode 100644 index 0000000000..f6536412e6 --- /dev/null +++ b/queue-6.18/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch @@ -0,0 +1,169 @@ +From 08666639710c4c86d98904a897517c265682754c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:16:55 +0000 +Subject: net/sched: sch_sfb: annotate data-races in sfb_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ] + +sfb_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_sfb_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260421141655.3953721-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 22 deletions(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index d2835f1168e1d..00286c930b8de 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen < 0xFFFF) +- b[hash].qlen++; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen > 0) +- b[hash].qlen--; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) + + static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_minus(b->p_mark, q->decrement); ++ WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement)); + } + + static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_plus(b->p_mark, q->increment); ++ WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment)); + } + + static void sfb_zero_all_buckets(struct sfb_sched_data *q) +@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da + const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0]; + + for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) { +- if (qlen < b->qlen) +- qlen = b->qlen; +- totalpm += b->p_mark; +- if (prob < b->p_mark) +- prob = b->p_mark; ++ u32 b_qlen = READ_ONCE(b->qlen); ++ u32 b_mark = READ_ONCE(b->p_mark); ++ ++ if (qlen < b_qlen) ++ qlen = b_qlen; ++ totalpm += b_mark; ++ if (prob < b_mark) ++ prob = b_mark; + b++; + } + *prob_r = prob; +@@ -295,7 +298,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(sch->q.qlen >= q->limit)) { + qdisc_qstats_overlimit(sch); +- q->stats.queuedrop++; ++ WRITE_ONCE(q->stats.queuedrop, ++ q->stats.queuedrop + 1); + goto drop; + } + +@@ -348,7 +352,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(minqlen >= q->max)) { + qdisc_qstats_overlimit(sch); +- q->stats.bucketdrop++; ++ WRITE_ONCE(q->stats.bucketdrop, ++ q->stats.bucketdrop + 1); + goto drop; + } + +@@ -374,7 +379,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + if (sfb_rate_limit(skb, q)) { + qdisc_qstats_overlimit(sch); +- q->stats.penaltydrop++; ++ WRITE_ONCE(q->stats.penaltydrop, ++ q->stats.penaltydrop + 1); + goto drop; + } + goto enqueue; +@@ -390,14 +396,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + * In either case, we want to start dropping packets. + */ + if (r < (p_min - SFB_MAX_PROB / 2) * 2) { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } + if (INET_ECN_set_ce(skb)) { +- q->stats.marked++; ++ WRITE_ONCE(q->stats.marked, ++ q->stats.marked + 1); + } else { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } +@@ -410,7 +419,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->q.qlen++; + increment_qlen(&cb, q); + } else if (net_xmit_drop_count(ret)) { +- q->stats.childdrop++; ++ WRITE_ONCE(q->stats.childdrop, ++ q->stats.childdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -599,12 +609,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct sfb_sched_data *q = qdisc_priv(sch); + struct tc_sfb_xstats st = { +- .earlydrop = q->stats.earlydrop, +- .penaltydrop = q->stats.penaltydrop, +- .bucketdrop = q->stats.bucketdrop, +- .queuedrop = q->stats.queuedrop, +- .childdrop = q->stats.childdrop, +- .marked = q->stats.marked, ++ .earlydrop = READ_ONCE(q->stats.earlydrop), ++ .penaltydrop = READ_ONCE(q->stats.penaltydrop), ++ .bucketdrop = READ_ONCE(q->stats.bucketdrop), ++ .queuedrop = READ_ONCE(q->stats.queuedrop), ++ .childdrop = READ_ONCE(q->stats.childdrop), ++ .marked = READ_ONCE(q->stats.marked), + }; + + st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q); +-- +2.53.0 + diff --git a/queue-6.18/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch b/queue-6.18/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch new file mode 100644 index 0000000000..fec22e4b3c --- /dev/null +++ b/queue-6.18/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch @@ -0,0 +1,123 @@ +From 263ea214b2a994da40196b9382b0f2b9a55e9baa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:19:58 +0800 +Subject: net/sched: taprio: fix NULL pointer dereference in class dump + +From: Weiming Shi + +[ Upstream commit 3d07ca5c0fae311226f737963984bd94bb159a87 ] + +When a TAPRIO child qdisc is deleted via RTM_DELQDISC, taprio_graft() +is called with new == NULL and stores NULL into q->qdiscs[cl - 1]. +Subsequent RTM_GETTCLASS dump operations walk all classes via +taprio_walk() and call taprio_dump_class(), which calls taprio_leaf() +returning the NULL pointer, then dereferences it to read child->handle, +causing a kernel NULL pointer dereference. + +The bug is reachable with namespace-scoped CAP_NET_ADMIN on any kernel +with CONFIG_NET_SCH_TAPRIO enabled. On systems with unprivileged user +namespaces enabled, an unprivileged local user can trigger a kernel +panic by creating a taprio qdisc inside a new network namespace, +grafting an explicit child qdisc, deleting it, and requesting a class +dump. The RTM_GETTCLASS dump itself requires no capability. + + Oops: general protection fault, probably for non-canonical address 0xdffffc0000000007: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f] + RIP: 0010:taprio_dump_class (net/sched/sch_taprio.c:2478) + Call Trace: + + tc_fill_tclass (net/sched/sch_api.c:1966) + qdisc_class_dump (net/sched/sch_api.c:2326) + taprio_walk (net/sched/sch_taprio.c:2514) + tc_dump_tclass_qdisc (net/sched/sch_api.c:2352) + tc_dump_tclass_root (net/sched/sch_api.c:2370) + tc_dump_tclass (net/sched/sch_api.c:2431) + rtnl_dumpit (net/core/rtnetlink.c:6864) + netlink_dump (net/netlink/af_netlink.c:2325) + rtnetlink_rcv_msg (net/core/rtnetlink.c:6959) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Fix this by substituting &noop_qdisc when new is NULL in +taprio_graft(), a common pattern used by other qdiscs (e.g., +multiq_graft()) to ensure the q->qdiscs[] slots are never NULL. +This makes control-plane dump paths safe without requiring individual +NULL checks. + +Since the data-plane paths (taprio_enqueue and taprio_dequeue_from_txq) +previously had explicit NULL guards that would drop/skip the packet +cleanly, update those checks to test for &noop_qdisc instead. Without +this, packets would reach taprio_enqueue_one() which increments the root +qdisc's qlen and backlog before calling the child's enqueue; noop_qdisc +drops the packet but those counters are never rolled back, permanently +inflating the root qdisc's statistics. + +After this change *old can be a valid qdisc, NULL, or &noop_qdisc. +Only call qdisc_put(*old) in the first case to avoid decreasing +noop_qdisc's refcount, which was never increased. + +Fixes: 665338b2a7a0 ("net/sched: taprio: dump class stats for the actual q->qdiscs[]") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Acked-by: Jamal Hadi Salim +Tested-by: Weiming Shi +Link: https://patch.msgid.link/20260422161958.2517539-3-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 91b85360f8091..b3481cafa6eca 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -633,7 +633,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + queue = skb_get_queue_mapping(skb); + + child = q->qdiscs[queue]; +- if (unlikely(!child)) ++ if (unlikely(child == &noop_qdisc)) + return qdisc_drop(skb, sch, to_free); + + if (taprio_skb_exceeds_queue_max_sdu(sch, skb)) { +@@ -716,7 +716,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, + int len; + u8 tc; + +- if (unlikely(!child)) ++ if (unlikely(child == &noop_qdisc)) + return NULL; + + if (TXTIME_ASSIST_IS_ENABLED(q->flags)) +@@ -2185,6 +2185,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + if (!dev_queue) + return -EINVAL; + ++ if (!new) ++ new = &noop_qdisc; ++ + if (dev->flags & IFF_UP) + dev_deactivate(dev); + +@@ -2198,14 +2201,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + *old = q->qdiscs[cl - 1]; + if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { + WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old); +- if (new) ++ if (new != &noop_qdisc) + qdisc_refcount_inc(new); +- if (*old) ++ if (*old && *old != &noop_qdisc) + qdisc_put(*old); + } + + q->qdiscs[cl - 1] = new; +- if (new) ++ if (new != &noop_qdisc) + new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; + + if (dev->flags & IFF_UP) +-- +2.53.0 + diff --git a/queue-6.18/net-sched-taprio-fix-use-after-free-in-advance_sched.patch b/queue-6.18/net-sched-taprio-fix-use-after-free-in-advance_sched.patch new file mode 100644 index 0000000000..17f0ee2732 --- /dev/null +++ b/queue-6.18/net-sched-taprio-fix-use-after-free-in-advance_sched.patch @@ -0,0 +1,60 @@ +From c9b41ad70ede2ab5101f6dbbfff1328844576b42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 18:57:57 -0700 +Subject: net/sched: taprio: fix use-after-free in advance_sched() on schedule + switch + +From: Vinicius Costa Gomes + +[ Upstream commit 105425b1969c5affe532713cfac1c0b320d7ac2b ] + +In advance_sched(), when should_change_schedules() returns true, +switch_schedules() is called to promote the admin schedule to oper. +switch_schedules() queues the old oper schedule for RCU freeing via +call_rcu(), but 'next' still points into an entry of the old oper +schedule. The subsequent 'next->end_time = end_time' and +rcu_assign_pointer(q->current_entry, next) are use-after-free. + +Fix this by selecting 'next' from the new oper schedule immediately +after switch_schedules(), and using its pre-calculated end_time. +setup_first_end_time() sets the first entry's end_time to +base_time + interval when the schedule is installed, so the value +is already correct. + +The deleted 'end_time = sched_base_time(admin)' assignment was also +harmful independently: it would overwrite the new first entry's +pre-calculated end_time with just base_time. + +Fixes: a3d43c0d56f1 ("taprio: Add support adding an admin schedule") +Reported-by: Junxi Qian +Signed-off-by: Vinicius Costa Gomes +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 39b735386996e..91b85360f8091 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -971,11 +971,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + } + + if (should_change_schedules(admin, oper, end_time)) { +- /* Set things so the next time this runs, the new +- * schedule runs. +- */ +- end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); ++ /* After changing schedules, the next entry is the first one ++ * in the new schedule, with a pre-calculated end_time. ++ */ ++ next = list_first_entry(&oper->entries, struct sched_entry, list); ++ end_time = next->end_time; + } + + next->end_time = end_time; +-- +2.53.0 + diff --git a/queue-6.18/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch b/queue-6.18/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch new file mode 100644 index 0000000000..6367e10b03 --- /dev/null +++ b/queue-6.18/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch @@ -0,0 +1,90 @@ +From b1bb4ef79c892519ed3f731c1f23fdcbad8529df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:15:59 -0700 +Subject: net: tls: fix strparser anchor skb leak on offload RX setup failure + +From: Jakub Kicinski + +[ Upstream commit 58689498ca3384851145a754dbb1d8ed1cf9fb54 ] + +When tls_set_device_offload_rx() fails at tls_dev_add(), the error path +calls tls_sw_free_resources_rx() to clean up the SW context that was +initialized by tls_set_sw_offload(). This function calls +tls_sw_release_resources_rx() (which stops the strparser via +tls_strp_stop()) and tls_sw_free_ctx_rx() (which kfrees the context), +but never frees the anchor skb that was allocated by alloc_skb(0) in +tls_strp_init(). + +Note that tls_sw_free_resources_rx() is exclusively used for this +"failed to start offload" code path, there's no other caller. + +The leak did not exist before commit 84c61fe1a75b ("tls: rx: do not use +the standard strparser"), because the standard strparser doesn't try +to pre-allocate an skb. + +The normal close path in tls_sk_proto_close() handles cleanup by calling +tls_sw_strparser_done() (which calls tls_strp_done()) after dropping +the socket lock, because tls_strp_done() does cancel_work_sync() and +the strparser work handler takes the socket lock. + +Fixes: 84c61fe1a75b ("tls: rx: do not use the standard strparser") +Signed-off-by: Jakub Kicinski +Reviewed-by: Vadim Fedorenko +Link: https://patch.msgid.link/20260428231559.1358502-1-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls.h | 1 + + net/tls/tls_strp.c | 6 ++++++ + net/tls/tls_sw.c | 4 ++++ + 3 files changed, 11 insertions(+) + +diff --git a/net/tls/tls.h b/net/tls/tls.h +index 2f86baeb71fcb..a1d8467bece33 100644 +--- a/net/tls/tls.h ++++ b/net/tls/tls.h +@@ -188,6 +188,7 @@ int tls_strp_dev_init(void); + void tls_strp_dev_exit(void); + + void tls_strp_done(struct tls_strparser *strp); ++void __tls_strp_done(struct tls_strparser *strp); + void tls_strp_stop(struct tls_strparser *strp); + int tls_strp_init(struct tls_strparser *strp, struct sock *sk); + void tls_strp_data_ready(struct tls_strparser *strp); +diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c +index 98e12f0ff57e5..c72e883176273 100644 +--- a/net/tls/tls_strp.c ++++ b/net/tls/tls_strp.c +@@ -624,6 +624,12 @@ void tls_strp_done(struct tls_strparser *strp) + WARN_ON(!strp->stopped); + + cancel_work_sync(&strp->work); ++ __tls_strp_done(strp); ++} ++ ++/* For setup error paths where the strparser was initialized but never armed. */ ++void __tls_strp_done(struct tls_strparser *strp) ++{ + tls_strp_anchor_free(strp); + } + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 16aaf41a8cc09..f2ea190777f0b 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -2625,8 +2625,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx) + void tls_sw_free_resources_rx(struct sock *sk) + { + struct tls_context *tls_ctx = tls_get_ctx(sk); ++ struct tls_sw_context_rx *ctx; ++ ++ ctx = tls_sw_ctx_rx(tls_ctx); + + tls_sw_release_resources_rx(sk); ++ __tls_strp_done(&ctx->strp); + tls_sw_free_ctx_rx(tls_ctx); + } + +-- +2.53.0 + diff --git a/queue-6.18/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch b/queue-6.18/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch new file mode 100644 index 0000000000..73b56a768c --- /dev/null +++ b/queue-6.18/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch @@ -0,0 +1,89 @@ +From 0d42171010aab39b5f8d076fbb6a15c1ff410055 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 08:49:12 +0800 +Subject: net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit() + +From: Zhan Jun + +[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ] + +syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() +when accessing skb->len for tx statistics after usb_submit_urb() has +been called: + + BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760 + drivers/net/usb/rtl8150.c:712 + Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226 + +The URB completion handler write_bulk_callback() frees the skb via +dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU +in softirq context before usb_submit_urb() returns in the submitter, +so by the time the submitter reads skb->len the skb has already been +queued to the per-CPU completion_queue and freed by net_tx_action(): + + CPU A (xmit) CPU B (USB completion softirq) + ------------ ------------------------------ + dev->tx_skb = skb; + usb_submit_urb() --+ + |-------> write_bulk_callback() + | dev_kfree_skb_irq(dev->tx_skb) + | net_tx_action() + | napi_skb_cache_put() <-- free + netdev->stats.tx_bytes | + += skb->len; <-- UAF read + +Fix it by caching skb->len before submitting the URB and using the +cached value when updating the tx_bytes counter. + +The pre-existing tx_bytes semantics are preserved: the counter tracks +the original frame length (skb->len), not the ETH_ZLEN/USB-alignment +padded "count" value that is handed to the device. Changing that +would be a user-visible accounting change and is out of scope for +this UAF fix. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+3f46c095ac0ca048cb71@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e69ee7.050a0220.24bfd3.002b.GAE@google.com/ +Closes: https://syzkaller.appspot.com/bug?extid=3f46c095ac0ca048cb71 +Reviewed-by: Andrew Lunn +Signed-off-by: Zhan Jun +Link: https://patch.msgid.link/809895186B866C10+20260423004913.136655-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index e40b0669d9f4b..8700ae392b10a 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + rtl8150_t *dev = netdev_priv(netdev); ++ unsigned int skb_len; + int count, res; + + /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ +@@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + ++ skb_len = skb->len; ++ + netif_stop_queue(netdev); + dev->tx_skb = skb; + usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), +@@ -711,7 +714,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + } + } else { + netdev->stats.tx_packets++; +- netdev->stats.tx_bytes += skb->len; ++ netdev->stats.tx_bytes += skb_len; + netif_trans_update(netdev); + } + +-- +2.53.0 + diff --git a/queue-6.18/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch b/queue-6.18/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch new file mode 100644 index 0000000000..3f89a99b71 --- /dev/null +++ b/queue-6.18/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch @@ -0,0 +1,61 @@ +From 124e5ccac1c685c962cd529dc2f478660e4a1ff3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 09:55:17 +0800 +Subject: net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit + +From: Morduan Zang + +[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ] + +When rtl8150_start_xmit() fails to submit the tx URB, the URB is never +handed to the USB core and write_bulk_callback() will not run. The +driver returns NETDEV_TX_OK, which tells the networking stack that the +skb has been consumed, but nothing actually frees the skb on this +error path: + + dev->tx_skb = skb; + ... + if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { + ... + /* no kfree_skb here */ + } + return NETDEV_TX_OK; + +This leaks the skb on every submit failure and also leaves dev->tx_skb +pointing at memory that the driver itself may later free, which is +fragile. + +Free the skb with dev_kfree_skb_any() in the error path and clear +dev->tx_skb so no stale pointer is left behind. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reviewed-by: Andrew Lunn +Signed-off-by: Morduan Zang +Link: https://patch.msgid.link/E7D3E1C013C5A859+20260424015517.9574-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 8700ae392b10a..647f28b367b99 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -712,6 +712,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } ++ /* ++ * The URB was not submitted, so write_bulk_callback() will ++ * never run to free dev->tx_skb. Drop the skb here and ++ * clear tx_skb to avoid leaving a stale pointer. ++ */ ++ dev->tx_skb = NULL; ++ dev_kfree_skb_any(skb); + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb_len; +-- +2.53.0 + diff --git a/queue-6.18/net-validate-skb-napi_id-in-rx-tracepoints.patch b/queue-6.18/net-validate-skb-napi_id-in-rx-tracepoints.patch new file mode 100644 index 0000000000..4fb2c7c397 --- /dev/null +++ b/queue-6.18/net-validate-skb-napi_id-in-rx-tracepoints.patch @@ -0,0 +1,58 @@ +From b499fd88458cf4a10922154df776145a5fb005e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:54:23 +0000 +Subject: net: validate skb->napi_id in RX tracepoints + +From: Kohei Enju + +[ Upstream commit 3bfcf396081ace536733b454ff128d53116581e5 ] + +Since commit 2bd82484bb4c ("xps: fix xps for stacked devices"), +skb->napi_id shares storage with sender_cpu. RX tracepoints using +net_dev_rx_verbose_template read skb->napi_id directly and can therefore +report sender_cpu values as if they were NAPI IDs. + +For example, on the loopback path this can report 1 as napi_id, where 1 +comes from raw_smp_processor_id() + 1 in the XPS path: + + # bpftrace -e 'tracepoint:net:netif_rx_entry{ print(args->napi_id); }' + # taskset -c 0 ping -c 1 ::1 + +Report only valid NAPI IDs in these tracepoints and use 0 otherwise. + +Fixes: 2bd82484bb4c ("xps: fix xps for stacked devices") +Signed-off-by: Kohei Enju +Reviewed-by: Simon Horman +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260420105427.162816-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/trace/events/net.h | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/include/trace/events/net.h b/include/trace/events/net.h +index d55162c12f90a..d3fe6acf85d28 100644 +--- a/include/trace/events/net.h ++++ b/include/trace/events/net.h +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + TRACE_EVENT(net_dev_start_xmit, + +@@ -193,7 +194,8 @@ DECLARE_EVENT_CLASS(net_dev_rx_verbose_template, + TP_fast_assign( + __assign_str(name); + #ifdef CONFIG_NET_RX_BUSY_POLL +- __entry->napi_id = skb->napi_id; ++ __entry->napi_id = napi_id_valid(skb->napi_id) ? ++ skb->napi_id : 0; + #else + __entry->napi_id = 0; + #endif +-- +2.53.0 + diff --git a/queue-6.18/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch b/queue-6.18/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch new file mode 100644 index 0000000000..6bf129a0d8 --- /dev/null +++ b/queue-6.18/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch @@ -0,0 +1,92 @@ +From 1ed70f8c9857c15c6188740903667ae3dd1093c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:33:49 +0000 +Subject: net_sched: sch_hhf: annotate data-races in hhf_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ] + +hhf_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421143349.4052215-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_hhf.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index 2d4855e28a286..81c3a388c9437 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash, + return NULL; + list_del(&flow->flowchain); + kfree(flow); +- q->hh_flows_current_cnt--; ++ WRITE_ONCE(q->hh_flows_current_cnt, ++ q->hh_flows_current_cnt - 1); + } else if (flow->hash_id == hash) { + return flow; + } +@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + } + + if (q->hh_flows_current_cnt >= q->hh_flows_limit) { +- q->hh_flows_overlimit++; ++ WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); + return NULL; + } + /* Create new entry. */ +@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + if (!flow) + return NULL; + +- q->hh_flows_current_cnt++; ++ WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); + INIT_LIST_HEAD(&flow->flowchain); + list_add_tail(&flow->flowchain, head); + +@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) + return WDRR_BUCKET_FOR_NON_HH; + flow->hash_id = hash; + flow->hit_timestamp = now; +- q->hh_flows_total_cnt++; ++ WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); + + /* By returning without updating counters in q->hhf_arrays, + * we implicitly implement "shielding" (see Optimization O1). +@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + + prev_backlog = sch->qstats.backlog; +- q->drop_overlimit++; ++ WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); + /* Return Congestion Notification only if we dropped a packet from this + * bucket. + */ +@@ -687,10 +688,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct hhf_sched_data *q = qdisc_priv(sch); + struct tc_hhf_xstats st = { +- .drop_overlimit = q->drop_overlimit, +- .hh_overlimit = q->hh_flows_overlimit, +- .hh_tot_count = q->hh_flows_total_cnt, +- .hh_cur_count = q->hh_flows_current_cnt, ++ .drop_overlimit = READ_ONCE(q->drop_overlimit), ++ .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), ++ .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), ++ .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.18/netconsole-propagate-device-name-truncation-in-dev_n.patch b/queue-6.18/netconsole-propagate-device-name-truncation-in-dev_n.patch new file mode 100644 index 0000000000..757dafc1eb --- /dev/null +++ b/queue-6.18/netconsole-propagate-device-name-truncation-in-dev_n.patch @@ -0,0 +1,58 @@ +From 5653583f29e93c2b56a35f42341d28aae0455e05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 07:30:37 -0700 +Subject: netconsole: propagate device name truncation in dev_name_store() + +From: Breno Leitao + +[ Upstream commit 92ceb7bff62c2606f664c204750eca0b85d44112 ] + +dev_name_store() calls strscpy(nt->np.dev_name, buf, IFNAMSIZ) without +checking the return value. If userspace writes an interface name longer +than IFNAMSIZ - 1, strscpy() silently truncates and returns -E2BIG, but +the function ignores it and reports a fully successful write back to +userspace. + +If a real interface happens to match the truncated name, netconsole will +bind to the wrong device on the next enable, sending kernel logs and +panic output to an unintended network segment with no indication to +userspace that anything was rewritten. + +Reject writes whose length cannot fit in nt->np.dev_name up front: + + if (count >= IFNAMSIZ) + return -ENAMETOOLONG; + +This is not a big deal of a problem, but, it is still the correct +approach. + +Fixes: 0bcc1816188e57 ("[NET] netconsole: Support dynamic reconfiguration using configfs") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-3-59965f29d9cc@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 7523f7763d36a..06345487d6aac 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -694,6 +694,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + size_t count) + { + struct netconsole_target *nt = to_target(item); ++ size_t len = count; ++ ++ /* Account for a trailing newline appended by tools like echo */ ++ if (len && buf[len - 1] == '\n') ++ len--; ++ if (len >= IFNAMSIZ) ++ return -ENAMETOOLONG; + + mutex_lock(&dynamic_netconsole_mutex); + if (nt->enabled) { +-- +2.53.0 + diff --git a/queue-6.18/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch b/queue-6.18/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch new file mode 100644 index 0000000000..7b9901d8a7 --- /dev/null +++ b/queue-6.18/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch @@ -0,0 +1,43 @@ +From 63eb218c0fbb988cb811151e9212dc5f64b08876 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 23:14:34 +0300 +Subject: netdevsim: zero initialize struct iphdr in dummy sk_buff + +From: Nikola Z. Ivanov + +[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ] + +Syzbot reports a KMSAN uninit-value originating from +nsim_dev_trap_skb_build, with the allocation also +being performed in the same function. + +Fix this by calling skb_put_zero instead of skb_put to +guarantee zero initialization of the whole IP header. + +Closes: https://syzkaller.appspot.com/bug?extid=23d7fcd204e3837866ff +Fixes: da58f90f11f5 ("netdevsim: Add devlink-trap support") +Signed-off-by: Nikola Z. Ivanov +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426201434.742030-1-zlatistiv@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netdevsim/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c +index 56a47c060f2e1..4064c488439b4 100644 +--- a/drivers/net/netdevsim/dev.c ++++ b/drivers/net/netdevsim/dev.c +@@ -773,7 +773,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) + skb->protocol = htons(ETH_P_IP); + + skb_set_network_header(skb, skb->len); +- iph = skb_put(skb, sizeof(struct iphdr)); ++ iph = skb_put_zero(skb, sizeof(struct iphdr)); + iph->protocol = IPPROTO_UDP; + iph->saddr = in_aton("192.0.2.1"); + iph->daddr = in_aton("198.51.100.1"); +-- +2.53.0 + diff --git a/queue-6.18/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch b/queue-6.18/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch new file mode 100644 index 0000000000..f94082c5d2 --- /dev/null +++ b/queue-6.18/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch @@ -0,0 +1,126 @@ +From a80dc5578844161bc1db95715eec4dc2fa7791a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:15:32 +0200 +Subject: netfilter: arp_tables: fix IEEE1394 ARP payload parsing + +From: Pablo Neira Ayuso + +[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ] + +Weiming Shi says: + +"arp_packet_match() unconditionally parses the ARP payload assuming two +hardware addresses are present (source and target). However, +IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address +field, and arp_hdr_len() already accounts for this by returning a +shorter length for ARPHRD_IEEE1394 devices. + +As a result, on IEEE1394 interfaces arp_packet_match() advances past a +nonexistent target hardware address and reads the wrong bytes for both +the target device address comparison and the target IP address. This +causes arptables rules to match against garbage data, leading to +incorrect filtering decisions: packets that should be accepted may be +dropped and vice versa. + +The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already +handles this correctly by skipping the target hardware address for +ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()." + +Mangle the original patch to always return 0 (no match) in case user +matches on the target hardware address which is never present in +IEEE1394. + +Note that this returns 0 (no match) for either normal and inverse match +because matching in the target hardware address in ARPHRD_IEEE1394 has +never been supported by arptables. This is intentional, matching on the +target hardware address should never evaluate true for ARPHRD_IEEE1394. + +Moreover, adjust arpt_mangle to drop the packet too as AI suggests: + +In arpt_mangle, the logic assumes a standard ARP layout. Because +IEEE1394 (FireWire) omits the target hardware address, the linear +pointer arithmetic miscalculates the offset for the target IP address. +This causes mangling operations to write to the wrong location, leading +to packet corruption. To ensure safety, this patch drops packets +(NF_DROP) when mangling is requested for these fields on IEEE1394 +devices, as the current implementation cannot correctly map the FireWire +ARP payload. + +This omits both mangling target hardware and IP address. Even if IP +address mangling should be possible in IEEE1394, this would require +to adjust arpt_mangle offset calculation, which has never been +supported. + +Based on patch from Weiming Shi . + +Fixes: 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.") +Reported-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- + net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 1cdd9c28ab2da..97ead883e4a13 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, + arpptr += dev->addr_len; + memcpy(&src_ipaddr, arpptr, sizeof(u32)); + arpptr += sizeof(u32); +- tgt_devaddr = arpptr; +- arpptr += dev->addr_len; ++ ++ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { ++ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, ++ sizeof(arpinfo->tgt_devaddr.mask)))) ++ return 0; ++ ++ tgt_devaddr = NULL; ++ } else { ++ tgt_devaddr = arpptr; ++ arpptr += dev->addr_len; ++ } + memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); + + if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, + arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, +- dev->addr_len)) || ++ dev->addr_len))) ++ return 0; ++ ++ if (tgt_devaddr && + NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, + arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, + dev->addr_len))) +diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c +index a4e07e5e9c118..f65dd339208e8 100644 +--- a/net/ipv4/netfilter/arpt_mangle.c ++++ b/net/ipv4/netfilter/arpt_mangle.c +@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += pln; + if (mangle->flags & ARPT_MANGLE_TDEV) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_DEV_ADDR_LEN_MAX < hln || + (arpptr + hln > skb_tail_pointer(skb))) + return NF_DROP; +@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += hln; + if (mangle->flags & ARPT_MANGLE_TIP) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_MANGLE_ADDR_LEN_MAX < pln || + (arpptr + pln > skb_tail_pointer(skb))) + return NF_DROP; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-conntrack-remove-sprintf-usage.patch b/queue-6.18/netfilter-conntrack-remove-sprintf-usage.patch new file mode 100644 index 0000000000..76dbcf3788 --- /dev/null +++ b/queue-6.18/netfilter-conntrack-remove-sprintf-usage.patch @@ -0,0 +1,182 @@ +From 56babb845e003454f586a6642cc7254673cc766f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 19:13:46 +0200 +Subject: netfilter: conntrack: remove sprintf usage + +From: Florian Westphal + +[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ] + +Replace it with scnprintf, the buffer sizes are expected to be large enough +to hold the result, no need for snprintf+overflow check. + +Increase buffer size in mangle_content_len() while at it. + +BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 +Write of size 1 at addr [..] + vsnprintf+0xea5/0x1270 + sprintf+0xb1/0xe0 + mangle_content_len+0x1ac/0x280 + nf_nat_sdp_session+0x1cc/0x240 + process_sdp+0x8f8/0xb80 + process_invite_request+0x108/0x2b0 + process_sip_msg+0x5da/0xf50 + sip_help_tcp+0x45e/0x780 + nf_confirm+0x34d/0x990 + [..] + +Fixes: 9fafcd7b2032 ("[NETFILTER]: nf_conntrack/nf_nat: add SIP helper port") +Reported-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_nat_amanda.c | 2 +- + net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c +index 98deef6cde694..8f1054920a857 100644 +--- a/net/netfilter/nf_nat_amanda.c ++++ b/net/netfilter/nf_nat_amanda.c +@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb, + return NF_DROP; + } + +- sprintf(buffer, "%u", port); ++ snprintf(buffer, sizeof(buffer), "%u", port); + if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, + protoff, matchoff, matchlen, + buffer, strlen(buffer))) { +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index cf4aeb299bdef..c845b6d1a2bdf 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, + } + + static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, bool delim) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4", &addr->ip); ++ return scnprintf(buffer, size, "%pI4", &addr->ip); + else { + if (delim) +- return sprintf(buffer, "[%pI6c]", &addr->ip6); ++ return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); + else +- return sprintf(buffer, "%pI6c", &addr->ip6); ++ return scnprintf(buffer, size, "%pI6c", &addr->ip6); + } + } + + static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, u16 port) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4:%u", &addr->ip, port); ++ return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port); + else +- return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); ++ return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); + } + + static int map_addr(struct sk_buff *skb, unsigned int protoff, +@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, + if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) + return 1; + +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, true) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.dst.u3, + true); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, false) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.src.u3, + false); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +- buflen = sprintf(buffer, "%u", ntohs(p)); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle rport"); +@@ -418,7 +420,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, + + if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), ++ &newaddr, port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle packet"); +@@ -438,8 +441,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++ char buffer[sizeof("4294967295")]; + unsigned int matchoff, matchlen; +- char buffer[sizeof("65536")]; + int buflen, c_len; + + /* Get actual SDP length */ +@@ -454,7 +457,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + return 0; + +- buflen = sprintf(buffer, "%u", c_len); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -491,7 +494,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, + char buffer[INET6_ADDRSTRLEN]; + unsigned int buflen; + +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, + sdpoff, type, term, buffer, buflen)) + return 0; +@@ -509,7 +512,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + +- buflen = sprintf(buffer, "%u", port); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) + return 0; +@@ -529,7 +532,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, + SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) + return 0; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nat-use-kfree_rcu-to-release-ops.patch b/queue-6.18/netfilter-nat-use-kfree_rcu-to-release-ops.patch new file mode 100644 index 0000000000..ae1325b3fd --- /dev/null +++ b/queue-6.18/netfilter-nat-use-kfree_rcu-to-release-ops.patch @@ -0,0 +1,114 @@ +From f89c06d0b9defcd85308ab9fc8859e4421c48394 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:29:45 +0200 +Subject: netfilter: nat: use kfree_rcu to release ops + +From: Pablo Neira Ayuso + +[ Upstream commit 6eda0d771f94267f73f57c94630aa47e90957915 ] + +Florian Westphal says: + +"Historically this is not an issue, even for normal base hooks: the data +path doesn't use the original nf_hook_ops that are used to register the +callbacks. + +However, in v5.14 I added the ability to dump the active netfilter +hooks from userspace. + +This code will peek back into the nf_hook_ops that are available +at the tail of the pointer-array blob used by the datapath. + +The nat hooks are special, because they are called indirectly from +the central nat dispatcher hook. They are currently invisible to +the nfnl hook dump subsystem though. + +But once that changes the nat ops structures have to be deferred too." + +Update nf_nat_register_fn() to deal with partial exposition of the hooks +from error path which can be also an issue for nfnetlink_hook. + +Fixes: e2cf17d3774c ("netfilter: add new hook nfnl subsystem") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/iptable_nat.c | 4 ++-- + net/ipv6/netfilter/ip6table_nat.c | 4 ++-- + net/netfilter/nf_nat_core.c | 10 ++++++---- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index a5db7c67d61be..625a1ca13b1ba 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -79,7 +79,7 @@ static int ipt_nat_register_lookups(struct net *net) + while (i) + nf_nat_ipv4_unregister_fn(net, &ops[--i]); + +- kfree(ops); ++ kfree_rcu(ops, rcu); + return ret; + } + } +@@ -100,7 +100,7 @@ static void ipt_nat_unregister_lookups(struct net *net) + for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) + nf_nat_ipv4_unregister_fn(net, &ops[i]); + +- kfree(ops); ++ kfree_rcu(ops, rcu); + } + + static int iptable_nat_table_init(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index e119d4f090cc8..5be723232df8f 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -81,7 +81,7 @@ static int ip6t_nat_register_lookups(struct net *net) + while (i) + nf_nat_ipv6_unregister_fn(net, &ops[--i]); + +- kfree(ops); ++ kfree_rcu(ops, rcu); + return ret; + } + } +@@ -102,7 +102,7 @@ static void ip6t_nat_unregister_lookups(struct net *net) + for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) + nf_nat_ipv6_unregister_fn(net, &ops[i]); + +- kfree(ops); ++ kfree_rcu(ops, rcu); + } + + static int ip6table_nat_table_init(struct net *net) +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index e6b24586d2fed..8e36b4e3e5c47 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -1228,9 +1228,11 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, + ret = nf_register_net_hooks(net, nat_ops, ops_count); + if (ret < 0) { + mutex_unlock(&nf_nat_proto_mutex); +- for (i = 0; i < ops_count; i++) +- kfree(nat_ops[i].priv); +- kfree(nat_ops); ++ for (i = 0; i < ops_count; i++) { ++ priv = nat_ops[i].priv; ++ kfree_rcu(priv, rcu_head); ++ } ++ kfree_rcu(nat_ops, rcu); + return ret; + } + +@@ -1294,7 +1296,7 @@ void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, + } + + nat_proto_net->nat_hook_ops = NULL; +- kfree(nat_ops); ++ kfree_rcu(nat_ops, rcu); + } + unlock: + mutex_unlock(&nf_nat_proto_mutex); +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch b/queue-6.18/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch new file mode 100644 index 0000000000..f9d6cb1396 --- /dev/null +++ b/queue-6.18/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch @@ -0,0 +1,352 @@ +From 627cecea6a15e20ded7a9d563bfa5c56c62e7c0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 02:19:11 +0200 +Subject: netfilter: nf_conntrack_sip: don't use simple_strtoul +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Florian Westphal + +[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ] + +Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), +and ct_sip_parse_request() with a new sip_parse_port() helper that +validates each digit against the buffer limit, eliminating the use of +simple_strtoul() which assumes NUL-terminated strings. + +The previous code dereferenced pointers without bounds checks after +sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated +skb data. A port that reaches the buffer limit without a trailing +character is also rejected as malformed. + +Also get rid of all simple_strtoul() usage in conntrack, prefer a +stricter version instead. There are intentional changes: + +- Bail out if number is > UINT_MAX and indicate a failure, same for + too long sequences. + While we do accept 05535 as port 5535, we will not accept e.g. + 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, + we should restrict this to not waste cycles when presented with + malformed packets with 64k '0' characters. + +- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch + 'expire=' and 'rports='; both are expected to use base-10. + +- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k + range. + +- epaddr_len now returns 0 if the port is invalid, as it already does + for invalid ip addresses. This is intentional. nf_conntrack_sip + performs lots of guesswork to find the right parts of the message + to parse. Being stricter could break existing setups. + Connection tracking helpers are designed to allow traffic to + pass, not to block it. + +Based on an earlier patch from Jenny Guanni Qu . + +Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper") +Reported-by: Klaudia Kloc +Reported-by: Dawid Moczadło +Reported-by: Jenny Guanni Qu . +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- + net/netfilter/nf_nat_sip.c | 1 + + 2 files changed, 119 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index 939502ff7c871..6eb39285fbd6c 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, + return 1; + } + ++/* Parse optional port number after IP address. ++ * Returns false on malformed input, true otherwise. ++ * If port is non-NULL, stores parsed port in network byte order. ++ * If no port is present, sets *port to default SIP port. ++ */ ++static bool sip_parse_port(const char *dptr, const char **endp, ++ const char *limit, __be16 *port) ++{ ++ unsigned int p = 0; ++ int len = 0; ++ ++ if (dptr >= limit) ++ return false; ++ ++ if (*dptr != ':') { ++ if (port) ++ *port = htons(SIP_PORT); ++ if (endp) ++ *endp = dptr; ++ return true; ++ } ++ ++ dptr++; /* skip ':' */ ++ ++ while (dptr < limit && isdigit(*dptr)) { ++ p = p * 10 + (*dptr - '0'); ++ dptr++; ++ len++; ++ if (len > 5) /* max "65535" */ ++ return false; ++ } ++ ++ if (len == 0) ++ return false; ++ ++ /* reached limit while parsing port */ ++ if (dptr >= limit) ++ return false; ++ ++ if (p < 1024 || p > 65535) ++ return false; ++ ++ if (port) ++ *port = htons(p); ++ ++ if (endp) ++ *endp = dptr; ++ ++ return true; ++} ++ + /* skip ip address. returns its length. */ + static int epaddr_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, + return 0; + } + +- /* Port number */ +- if (*dptr == ':') { +- dptr++; +- dptr += digits_len(ct, dptr, limit, shift); +- } ++ if (!sip_parse_port(dptr, &dptr, limit, NULL)) ++ return 0; + return dptr - aux; + } + +@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, + return epaddr_len(ct, dptr, limit, shift); + } + ++/* simple_strtoul stops after first non-number character. ++ * But as we're not dealing with c-strings, we can't rely on ++ * hitting \r,\n,\0 etc. before moving past end of buffer. ++ * ++ * This is a variant of simple_strtoul, but doesn't require ++ * a c-string. ++ * ++ * If value exceeds UINT_MAX, 0 is returned. ++ */ ++static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) ++{ ++ const unsigned int max = sizeof("4294967295"); ++ unsigned int olen = len; ++ const char *s = cp; ++ u64 result = 0; ++ ++ if (len > max) ++ len = max; ++ ++ while (olen > 0 && isdigit(*s)) { ++ unsigned int value; ++ ++ if (len == 0) ++ goto err; ++ ++ value = *s - '0'; ++ result = result * 10 + value; ++ ++ if (result > UINT_MAX) ++ goto err; ++ s++; ++ len--; ++ olen--; ++ } ++ ++ if (endp) ++ *endp = (char *)s; ++ ++ return result; ++err: ++ if (endp) ++ *endp = (char *)cp; ++ return 0; ++} ++ + /* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF +@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, + { + const char *start = dptr, *limit = dptr + datalen, *end; + unsigned int mlen; +- unsigned int p; + int shift = 0; + + /* Skip method and following whitespace */ +@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, + + if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) + return -1; +- if (end < limit && *end == ':') { +- end++; +- p = simple_strtoul(end, (char **)&end, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(end, &end, limit, port)) ++ return -1; + + if (end == dptr) + return 0; +@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + union nf_inet_addr *addr, __be16 *port) + { + const char *c, *limit = dptr + datalen; +- unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, +@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + + if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) + return -1; +- if (*c == ':') { +- c++; +- p = simple_strtoul(c, (char **)&c, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(c, &c, limit, port)) ++ return -1; + + if (dataoff) + *dataoff = c - dptr; +@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + return 0; + + start += strlen(name); +- *val = simple_strtoul(start, &end, 0); ++ *val = sip_strtouint(start, limit - start, (char **)&end); + if (start == end) + return -1; + if (matchoff && matchlen) { +@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { ++ char *end; ++ + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) +@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + mediaoff += t->len; + medialen -= t->len; + +- port = simple_strtoul(*dptr + mediaoff, NULL, 10); +- if (port == 0) ++ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); ++ if (port == 0 || *dptr + mediaoff == end) + continue; + if (port < 1024 || port > 65535) { + nf_ct_helper_log(skb, ct, "wrong port %u", port); +@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, +@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + while (1) { + unsigned int c_expires = expires; +@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen, matchend; + unsigned int code, cseq, i; ++ char *end; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; +- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); ++ code = sip_strtouint(*dptr + strlen("SIP/2.0 "), ++ *datalen - strlen("SIP/2.0 "), NULL); + if (!code) { + nf_ct_helper_log(skb, ct, "cannot get code"); + return NF_DROP; +@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; ++ char *end; + + handler = &sip_handlers[i]; + if (handler->request == NULL) +@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + break; + +- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); ++ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); + if (dptr + matchoff == end) + break; + +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index c845b6d1a2bdf..9fbfc6bff0c22 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, + "rport=", &poff, &plen, + &n) > 0 && ++ n >= 1024 && n <= 65535 && + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nf_tables-use-list_del_rcu-for-netlink-hoo.patch b/queue-6.18/netfilter-nf_tables-use-list_del_rcu-for-netlink-hoo.patch new file mode 100644 index 0000000000..5249eb0127 --- /dev/null +++ b/queue-6.18/netfilter-nf_tables-use-list_del_rcu-for-netlink-hoo.patch @@ -0,0 +1,137 @@ +From f23e14bf65d343660300f3fde6c858cbb86b9bcb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 15:14:51 +0200 +Subject: netfilter: nf_tables: use list_del_rcu for netlink hooks + +From: Florian Westphal + +[ Upstream commit f3224ee463f8f6f6ced7dcdf6081add4f8128527 ] + +nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks need +to use list_del_rcu(), this list can be walked by concurrent dumpers. + +Add a new helper and use it consistently. + +Fixes: f9a43007d3f7 ("netfilter: nf_tables: double hook unregistration in netns path") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 44 ++++++++++++++--------------------- + 1 file changed, 18 insertions(+), 26 deletions(-) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 5b25b032e285d..64e6a95439abd 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -373,6 +373,12 @@ static void nft_netdev_hook_free_rcu(struct nft_hook *hook) + call_rcu(&hook->rcu, __nft_netdev_hook_free_rcu); + } + ++static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook) ++{ ++ list_del_rcu(&hook->list); ++ nft_netdev_hook_free_rcu(hook); ++} ++ + static void nft_netdev_unregister_hooks(struct net *net, + struct list_head *hook_list, + bool release_netdev) +@@ -383,10 +389,8 @@ static void nft_netdev_unregister_hooks(struct net *net, + list_for_each_entry_safe(hook, next, hook_list, list) { + list_for_each_entry(ops, &hook->ops_list, list) + nf_unregister_net_hook(net, ops); +- if (release_netdev) { +- list_del(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ if (release_netdev) ++ nft_netdev_hook_unlink_free_rcu(hook); + } + } + +@@ -2322,10 +2326,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain) + + if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) { + list_for_each_entry_safe(hook, next, +- &basechain->hook_list, list) { +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ &basechain->hook_list, list) ++ nft_netdev_hook_unlink_free_rcu(hook); + } + module_put(basechain->type->owner); + if (rcu_access_pointer(basechain->stats)) { +@@ -3025,6 +3027,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, + list_for_each_entry(ops, &h->ops_list, list) + nf_unregister_net_hook(ctx->net, ops); + } ++ /* hook.list is on stack, no need for list_del_rcu() */ + list_del(&h->list); + nft_netdev_hook_free_rcu(h); + } +@@ -9069,10 +9072,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net, + list_for_each_entry_safe(hook, next, hook_list, list) { + list_for_each_entry(ops, &hook->ops_list, list) + nft_unregister_flowtable_ops(net, flowtable, ops); +- if (release_netdev) { +- list_del(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ if (release_netdev) ++ nft_netdev_hook_unlink_free_rcu(hook); + } + } + +@@ -9143,8 +9144,7 @@ static int nft_register_flowtable_net_hooks(struct net *net, + + nft_unregister_flowtable_ops(net, flowtable, ops); + } +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); ++ nft_netdev_hook_unlink_free_rcu(hook); + } + + return err; +@@ -9154,10 +9154,8 @@ static void nft_hooks_destroy(struct list_head *hook_list) + { + struct nft_hook *hook, *next; + +- list_for_each_entry_safe(hook, next, hook_list, list) { +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ list_for_each_entry_safe(hook, next, hook_list, list) ++ nft_netdev_hook_unlink_free_rcu(hook); + } + + static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, +@@ -9245,8 +9243,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, + nft_unregister_flowtable_ops(ctx->net, + flowtable, ops); + } +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); ++ nft_netdev_hook_unlink_free_rcu(hook); + } + + return err; +@@ -9752,13 +9749,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx, + + static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable) + { +- struct nft_hook *hook, *next; +- + flowtable->data.type->free(&flowtable->data); +- list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) { +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ nft_hooks_destroy(&flowtable->hook_list); + kfree(flowtable->name); + module_put(flowtable->data.type->owner); + kfree(flowtable); +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch b/queue-6.18/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch new file mode 100644 index 0000000000..3970058a1f --- /dev/null +++ b/queue-6.18/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch @@ -0,0 +1,67 @@ +From c5f974fc405528e7e2032e38e8e88c7fa3bfdcb5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:14:01 -0700 +Subject: netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO + +From: Xiang Mei + +[ Upstream commit 2195574dc6d9017d32ac346987e12659f931d932 ] + +nf_osf_match_one() computes ctx->window % f->wss.val in the +OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A +CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a +subsequent matching TCP SYN divides by zero and panics the kernel. + +Reject the bogus fingerprint in nfnl_osf_add_callback() above the +per-option for-loop. f->wss is per-fingerprint, not per-option, so +the check must run regardless of f->opt_num (including 0). Also +reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that +as "should not happen". + +Crash: + Oops: divide error: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) + Call Trace: + + nf_osf_match (net/netfilter/nfnetlink_osf.c:220) + xt_osf_match_packet (net/netfilter/xt_osf.c:32) + ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) + nf_hook_slow (net/netfilter/core.c:622) + ip_local_deliver (net/ipv4/ip_input.c:265) + ip_rcv (include/linux/skbuff.h:1162) + __netif_receive_skb_one_core (net/core/dev.c:6181) + process_backlog (net/core/dev.c:6642) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7945) + handle_softirqs (kernel/softirq.c:622) + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Weiming Shi +Suggested-by: Florian Westphal +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Xiang Mei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 9fc9544d4bc53..2305c7d9761eb 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, + if (f->opt_num > ARRAY_SIZE(f->opt)) + return -EINVAL; + ++ if (f->wss.wc >= OSF_WSS_MAX || ++ (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) ++ return -EINVAL; ++ + for (i = 0; i < f->opt_num; i++) { + if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch b/queue-6.18/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch new file mode 100644 index 0000000000..67c4d0ae78 --- /dev/null +++ b/queue-6.18/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch @@ -0,0 +1,100 @@ +From 0f4ea83c6741487f51c216c70af2135309779176 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:56 +0200 +Subject: netfilter: nfnetlink_osf: fix out-of-bounds read on option matching + +From: Fernando Fernandez Mancera + +[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ] + +In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once +and passed by reference to nf_osf_match_one() for each fingerprint +checked. During TCP option parsing, nf_osf_match_one() advances the +shared ctx->optp pointer. + +If a fingerprint perfectly matches, the function returns early without +restoring ctx->optp to its initial state. If the user has configured +NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. +However, because ctx->optp was not restored, the next call to +nf_osf_match_one() starts parsing from the end of the options buffer. +This causes subsequent matches to read garbage data and fail +immediately, making it impossible to log more than one match or logging +incorrect matches. + +Instead of using a shared ctx->optp pointer, pass the context as a +constant pointer and use a local pointer (optp) for TCP option +traversal. This makes nf_osf_match_one() strictly stateless from the +caller's perspective, ensuring every fingerprint check starts at the +correct option offset. + +Fixes: 1a6a0951fc00 ("netfilter: nfnetlink_osf: add missing fmatch check") +Suggested-by: Florian Westphal +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 2305c7d9761eb..832a973c41777 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx { + static bool nf_osf_match_one(const struct sk_buff *skb, + const struct nf_osf_user_finger *f, + int ttl_check, +- struct nf_osf_hdr_ctx *ctx) ++ const struct nf_osf_hdr_ctx *ctx) + { +- const __u8 *optpinit = ctx->optp; ++ const __u8 *optp = ctx->optp; + unsigned int check_WSS = 0; + int fmatch = FMATCH_WRONG; + int foptsize, optnum; +@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { +- if (f->opt[optnum].kind == *ctx->optp) { ++ if (f->opt[optnum].kind == *optp) { + __u32 len = f->opt[optnum].length; +- const __u8 *optend = ctx->optp + len; ++ const __u8 *optend = optp + len; + + fmatch = FMATCH_OK; + +- switch (*ctx->optp) { ++ switch (*optp) { + case OSFOPT_MSS: +- mss = ctx->optp[3]; ++ mss = optp[3]; + mss <<= 8; +- mss |= ctx->optp[2]; ++ mss |= optp[2]; + + mss = ntohs((__force __be16)mss); + break; +@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + break; + } + +- ctx->optp = optend; ++ optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + +@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + } + } + +- if (fmatch != FMATCH_OK) +- ctx->optp = optpinit; +- + return fmatch == FMATCH_OK; + } + +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch b/queue-6.18/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch new file mode 100644 index 0000000000..c48e414152 --- /dev/null +++ b/queue-6.18/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch @@ -0,0 +1,74 @@ +From 4be6d9abc04d455238c6c65aec55bd3252b9f1b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:57 +0200 +Subject: netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check + +From: Fernando Fernandez Mancera + +[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ] + +The nf_osf_ttl() function accessed skb->dev to perform a local interface +address lookup without verifying that the device pointer was valid. + +Additionally, the implementation utilized an in_dev_for_each_ifa_rcu +loop to match the packet source address against local interface +addresses. It assumed that packets from the same subnet should not see a +decrement on the initial TTL. A packet might appear it is from the same +subnet but it actually isn't especially in modern environments with +containers and virtual switching. + +Remove the device dereference and interface loop. Replace the logic with +a switch statement that evaluates the TTL according to the ttl_check. + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Kito Xu (veritas501) +Closes: https://lore.kernel.org/netfilter-devel/20260414074556.2512750-1-hxzene@gmail.com/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 832a973c41777..c89efb951994a 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); + static inline int nf_osf_ttl(const struct sk_buff *skb, + int ttl_check, unsigned char f_ttl) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + const struct iphdr *ip = ip_hdr(skb); +- const struct in_ifaddr *ifa; +- int ret = 0; + +- if (ttl_check == NF_OSF_TTL_TRUE) ++ switch (ttl_check) { ++ case NF_OSF_TTL_TRUE: + return ip->ttl == f_ttl; +- if (ttl_check == NF_OSF_TTL_NOCHECK) +- return 1; +- else if (ip->ttl <= f_ttl) ++ break; ++ case NF_OSF_TTL_NOCHECK: + return 1; +- +- in_dev_for_each_ifa_rcu(ifa, in_dev) { +- if (inet_ifa_match(ip->saddr, ifa)) { +- ret = (ip->ttl == f_ttl); +- break; +- } ++ case NF_OSF_TTL_LESS: ++ default: ++ return ip->ttl <= f_ttl; + } +- +- return ret; + } + + struct nf_osf_hdr_ctx { +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch b/queue-6.18/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch new file mode 100644 index 0000000000..2362f03bf3 --- /dev/null +++ b/queue-6.18/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch @@ -0,0 +1,49 @@ +From 263fa7a5917f1d6f74266baf27f5b6d0f810a828 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:30:41 +0200 +Subject: netfilter: nft_fwd_netdev: check ttl/hl before forwarding + +From: Florian Westphal + +[ Upstream commit 1dfd95bdf4d18d263aa8fad06bfb9f4d9c992b18 ] + +Drop packets if their ttl/hl is too small for forwarding. + +Fixes: d32de98ea70f ("netfilter: nft_fwd_netdev: allow to forward packets via neighbour layer") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_fwd_netdev.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c +index 152a9fb4d23af..256e832f1bb99 100644 +--- a/net/netfilter/nft_fwd_netdev.c ++++ b/net/netfilter/nft_fwd_netdev.c +@@ -116,6 +116,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + iph = ip_hdr(skb); ++ if (iph->ttl <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip_decrease_ttl(iph); + neigh_table = NEIGH_ARP_TABLE; + break; +@@ -132,6 +137,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + ip6h = ipv6_hdr(skb); ++ if (ip6h->hop_limit <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip6h->hop_limit--; + neigh_table = NEIGH_ND_TABLE; + break; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-nft_osf-restrict-it-to-ipv4.patch b/queue-6.18/netfilter-nft_osf-restrict-it-to-ipv4.patch new file mode 100644 index 0000000000..10051447c5 --- /dev/null +++ b/queue-6.18/netfilter-nft_osf-restrict-it-to-ipv4.patch @@ -0,0 +1,47 @@ +From eaadcc41459bbc2f8d109f0a0ea2f5bb5a1c56c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 13:06:38 +0200 +Subject: netfilter: nft_osf: restrict it to ipv4 + +From: Pablo Neira Ayuso + +[ Upstream commit b336fdbb7103fb1484e1dcb6741151d4b5a41e35 ] + +This expression only supports for ipv4, restrict it. + +Fixes: b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf") +Acked-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_osf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c +index 1c0b493ef0a99..bdc2f6c90e2f7 100644 +--- a/net/netfilter/nft_osf.c ++++ b/net/netfilter/nft_osf.c +@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, + struct nf_osf_data data; + struct tcphdr _tcph; + ++ if (nft_pf(pkt) != NFPROTO_IPV4) { ++ regs->verdict.code = NFT_BREAK; ++ return; ++ } ++ + if (pkt->tprot != IPPROTO_TCP) { + regs->verdict.code = NFT_BREAK; + return; +@@ -114,7 +119,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx, + + switch (ctx->family) { + case NFPROTO_IPV4: +- case NFPROTO_IPV6: + case NFPROTO_INET: + hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | +-- +2.53.0 + diff --git a/queue-6.18/netfilter-skip-recording-stale-or-retransmitted-init.patch b/queue-6.18/netfilter-skip-recording-stale-or-retransmitted-init.patch new file mode 100644 index 0000000000..18ec936acf --- /dev/null +++ b/queue-6.18/netfilter-skip-recording-stale-or-retransmitted-init.patch @@ -0,0 +1,63 @@ +From b703e541d4853a335476c980d6ab096f22e56151 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:40 -0400 +Subject: netfilter: skip recording stale or retransmitted INIT + +From: Xin Long + +[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ] + +An INIT whose init_tag matches the peer's vtag does not provide new state +information. It indicates either: + +- a stale INIT (after INIT-ACK has already been seen on the same side), or +- a retransmitted INIT (after INIT has already been recorded on the same + side). + +In both cases, the INIT must not update ct->proto.sctp.init[] state, since +it does not advance the handshake tracking and may otherwise corrupt +INIT/INIT-ACK validation logic. + +Allow INIT processing only when the conntrack entry is newly created +(SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer +vtag. + +Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in +nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it +set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag. + +Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") +Signed-off-by: Xin Long +Reviewed-by: Marcelo Ricardo Leitner +Acked-by: Florian Westphal +Link: https://patch.msgid.link/ee56c3e416452b2a40589a2a85245ac2ad5e9f4b.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index 645d2c43ebf7a..7e10fa65cbdd3 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -466,9 +466,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + if (!ih) + goto out_unlock; + +- if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) +- ct->proto.sctp.init[!dir] = 0; +- ct->proto.sctp.init[dir] = 1; ++ /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ ++ if (old_state == SCTP_CONNTRACK_NONE || ++ ct->proto.sctp.vtag[!dir] != ih->init_tag) { ++ if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) ++ ct->proto.sctp.init[!dir] = 0; ++ ct->proto.sctp.init[dir] = 1; ++ } + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); + ct->proto.sctp.vtag[!dir] = ih->init_tag; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch b/queue-6.18/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch new file mode 100644 index 0000000000..2c29da466e --- /dev/null +++ b/queue-6.18/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch @@ -0,0 +1,47 @@ +From 3c54b8ae6a7578df31dc39dc2983f2b161a6012b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:25:06 +0800 +Subject: netfilter: xt_policy: fix strict mode inbound policy matching + +From: Jiexun Wang + +[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ] + +match_policy_in() walks sec_path entries from the last transform to the +first one, but strict policy matching needs to consume info->pol[] in +the same forward order as the rule layout. + +Derive the strict-match policy position from the number of transforms +already consumed so that multi-element inbound rules are matched +consistently. + +Fixes: c4b885139203 ("[NETFILTER]: x_tables: replace IPv4/IPv6 policy match by address family independant version") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Acked-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c +index cb6e8279010a4..b5fa65558318f 100644 +--- a/net/netfilter/xt_policy.c ++++ b/net/netfilter/xt_policy.c +@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, + return 0; + + for (i = sp->len - 1; i >= 0; i--) { +- pos = strict ? i - sp->len + 1 : 0; ++ pos = strict ? sp->len - i - 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; +-- +2.53.0 + diff --git a/queue-6.18/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch b/queue-6.18/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch new file mode 100644 index 0000000000..fb7daa2307 --- /dev/null +++ b/queue-6.18/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch @@ -0,0 +1,86 @@ +From 84da2290bbd534dc3ccd5d2e32b11fb40dc49fc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 12:12:59 +0200 +Subject: netfilter: xt_socket: enable defrag after all other checks + +From: Florian Westphal + +[ Upstream commit 542be3fa5aff54210a02954c38f07e53ea9bdafd ] + +Originally this did not matter because defrag was enabled once per netns +and only disabled again on netns dismantle. When this got changed I should +have adjusted checkentry to not leave defrag enabled on error. + +Fixes: de8c12110a13 ("netfilter: disable defrag once its no longer needed") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_socket.c | 23 ++++++----------------- + 1 file changed, 6 insertions(+), 17 deletions(-) + +diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c +index 76e01f292aaff..811e53bee4085 100644 +--- a/net/netfilter/xt_socket.c ++++ b/net/netfilter/xt_socket.c +@@ -168,52 +168,41 @@ static int socket_mt_enable_defrag(struct net *net, int family) + static int socket_mt_v1_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V1) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V1); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v2_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V2) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V2); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v3_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo3 *info = + (struct xt_socket_mtinfo3 *)par->matchinfo; +- int err; + +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + if (info->flags & ~XT_SOCKET_FLAGS_V3) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V3); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static void socket_mt_destroy(const struct xt_mtdtor_param *par) +-- +2.53.0 + diff --git a/queue-6.18/netfilter-xtables-restrict-several-matches-to-inet-f.patch b/queue-6.18/netfilter-xtables-restrict-several-matches-to-inet-f.patch new file mode 100644 index 0000000000..64084ab709 --- /dev/null +++ b/queue-6.18/netfilter-xtables-restrict-several-matches-to-inet-f.patch @@ -0,0 +1,208 @@ +From 59b7a99d6e1d353bd635ca187335c601d135f897 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 12:21:00 +0200 +Subject: netfilter: xtables: restrict several matches to inet family + +From: Pablo Neira Ayuso + +[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ] + +This is a partial revert of: + + commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") + +to allow ipv4 and ipv6 only. + +- xt_mac +- xt_owner +- xt_physdev + +These extensions are not used by ebtables in userspace. + +Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 +specific. + +Fixes: ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") +Reported-by: "Kito Xu (veritas501)" +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- + net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ + net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- + net/netfilter/xt_realm.c | 2 +- + 4 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index 81649da57ba5d..bd2354760895d 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + return ret; + } + +-static struct xt_match mac_mt_reg __read_mostly = { +- .name = "mac", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .match = mac_mt, +- .matchsize = sizeof(struct xt_mac_info), +- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | +- (1 << NF_INET_FORWARD), +- .me = THIS_MODULE, ++static struct xt_match mac_mt_reg[] __read_mostly = { ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV4, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV6, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init mac_mt_init(void) + { +- return xt_register_match(&mac_mt_reg); ++ return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + static void __exit mac_mt_exit(void) + { +- xt_unregister_match(&mac_mt_reg); ++ xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + module_init(mac_mt_init); +diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c +index 50332888c8d23..7be2fe22b067e 100644 +--- a/net/netfilter/xt_owner.c ++++ b/net/netfilter/xt_owner.c +@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + +-static struct xt_match owner_mt_reg __read_mostly = { +- .name = "owner", +- .revision = 1, +- .family = NFPROTO_UNSPEC, +- .checkentry = owner_check, +- .match = owner_mt, +- .matchsize = sizeof(struct xt_owner_match_info), +- .hooks = (1 << NF_INET_LOCAL_OUT) | +- (1 << NF_INET_POST_ROUTING), +- .me = THIS_MODULE, ++static struct xt_match owner_mt_reg[] __read_mostly = { ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV4, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV6, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ } + }; + + static int __init owner_mt_init(void) + { +- return xt_register_match(&owner_mt_reg); ++ return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + static void __exit owner_mt_exit(void) + { +- xt_unregister_match(&owner_mt_reg); ++ xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + module_init(owner_mt_init); +diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c +index 343e65f377d44..130842c35c6fa 100644 +--- a/net/netfilter/xt_physdev.c ++++ b/net/netfilter/xt_physdev.c +@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) + return 0; + } + +-static struct xt_match physdev_mt_reg __read_mostly = { +- .name = "physdev", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .checkentry = physdev_mt_check, +- .match = physdev_mt, +- .matchsize = sizeof(struct xt_physdev_info), +- .me = THIS_MODULE, ++static struct xt_match physdev_mt_reg[] __read_mostly = { ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV4, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV6, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init physdev_mt_init(void) + { +- return xt_register_match(&physdev_mt_reg); ++ return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + static void __exit physdev_mt_exit(void) + { +- xt_unregister_match(&physdev_mt_reg); ++ xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + module_init(physdev_mt_init); +diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c +index 6df485f4403d0..61b2f1e58d150 100644 +--- a/net/netfilter/xt_realm.c ++++ b/net/netfilter/xt_realm.c +@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { + .matchsize = sizeof(struct xt_realm_info), + .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), +- .family = NFPROTO_UNSPEC, ++ .family = NFPROTO_IPV4, + .me = THIS_MODULE + }; + +-- +2.53.0 + diff --git a/queue-6.18/netpoll-fix-ipv6-local-address-corruption.patch b/queue-6.18/netpoll-fix-ipv6-local-address-corruption.patch new file mode 100644 index 0000000000..b4407ced42 --- /dev/null +++ b/queue-6.18/netpoll-fix-ipv6-local-address-corruption.patch @@ -0,0 +1,81 @@ +From 6e1d17c55f5fedc47e43d3462628f2ac25715940 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 08:31:16 -0700 +Subject: netpoll: fix IPv6 local-address corruption + +From: Breno Leitao + +[ Upstream commit 3bc179bc7146c26c9dff75d2943d10528274e301 ] + +netpoll_setup() decides whether to auto-populate the local source +address by testing np->local_ip.ip, which only inspects the first 4 +bytes of the union inet_addr storage. + +For an IPv6 netpoll whose caller-supplied local address has a zero +high-32 bits (::1, ::, IPv4-mapped ::ffff:a.b.c.d, etc.), this +misdetects the address as unset (which they are not, but the first +4 bytes are empty), calls netpoll_take_ipv6() and overwrites it with +whatever matching link-local/global address the device happens to expose +first. + +Introduce a helper netpoll_local_ip_unset() that picks the correct +family-aware test (ipv6_addr_any() for IPv6, !.ip for IPv4) and use it +from netpoll_setup(). + +Reproducer is something like: + + echo "::2" > local_ip + echo 1 > enabled + cat local_ip + # before this fix: 2001:db8::1 (caller-supplied ::2 was clobbered) + # after this fix: ::2 + +Fixes: b7394d2429c1 ("netpoll: prepare for ipv6") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260424-netpoll_fix-v1-1-3a55348c625f@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/netpoll.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/net/core/netpoll.c b/net/core/netpoll.c +index 6b1f470264c12..854e37c41653b 100644 +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -706,6 +706,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev) + return 0; + } + ++/* ++ * Test whether the caller left np->local_ip unset, so that ++ * netpoll_setup() should auto-populate it from the egress device. ++ * ++ * np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6), ++ * so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2, ++ * IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm — ++ * doing so would misclassify a caller-supplied address as unset and ++ * silently overwrite it with whatever address the device exposes. ++ */ ++static bool netpoll_local_ip_unset(const struct netpoll *np) ++{ ++ if (np->ipv6) ++ return ipv6_addr_any(&np->local_ip.in6); ++ return !np->local_ip.ip; ++} ++ + int netpoll_setup(struct netpoll *np) + { + struct net *net = current->nsproxy->net_ns; +@@ -750,7 +767,7 @@ int netpoll_setup(struct netpoll *np) + rtnl_lock(); + } + +- if (!np->local_ip.ip) { ++ if (netpoll_local_ip_unset(np)) { + if (!np->ipv6) { + err = netpoll_take_ipv4(np, ndev); + if (err) +-- +2.53.0 + diff --git a/queue-6.18/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch b/queue-6.18/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch new file mode 100644 index 0000000000..80689d2fa7 --- /dev/null +++ b/queue-6.18/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch @@ -0,0 +1,69 @@ +From 082aa270a4d8db8a38cedc3c198887710670db13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:19 +0800 +Subject: nexthop: fix IPv6 route referencing IPv4 nexthop + +From: Jiayuan Chen + +[ Upstream commit 29c95185ba32b621fbc3800fb86e7dc3edf5c2be ] + +syzbot reported a panic [1] [2]. + +When an IPv6 nexthop is replaced with an IPv4 nexthop, the has_v4 flag +of all groups containing this nexthop is not updated. This is because +nh_group_v4_update is only called when replacing AF_INET to AF_INET6, +but the reverse direction (AF_INET6 to AF_INET) is missed. + +This allows a stale has_v4=false to bypass fib6_check_nexthop, causing +IPv6 routes to be attached to groups that effectively contain only AF_INET +members. Subsequent route lookups then call nexthop_fib6_nh() which +returns NULL for the AF_INET member, leading to a NULL pointer +dereference. + +Fix by calling nh_group_v4_update whenever the family changes, not just +AF_INET to AF_INET6. + +Reproducer: + # AF_INET6 blackhole + ip -6 nexthop add id 1 blackhole + # group with has_v4=false + ip nexthop add id 100 group 1 + # replace with AF_INET (no -6), has_v4 stays false + ip nexthop replace id 1 blackhole + # pass stale has_v4 check + ip -6 route add 2001:db8::/64 nhid 100 + # panic + ping -6 2001:db8::1 + +[1] https://syzkaller.appspot.com/bug?id=e17283eb2f8dcf3dd9b47fe6f67a95f71faadad0 +[2] https://syzkaller.appspot.com/bug?id=8699b6ae54c9f35837d925686208402949e12ef3 +Fixes: 7bf4796dd099 ("nexthops: add support for replace") +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/nexthop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c +index c958b8edfe540..5a95b64b61c59 100644 +--- a/net/ipv4/nexthop.c ++++ b/net/ipv4/nexthop.c +@@ -2469,10 +2469,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + goto err_notify; + } + +- /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially ++ /* When replacing a nexthop with one of a different family, potentially + * update IPv4 indication in all the groups using the nexthop. + */ +- if (oldi->family == AF_INET && newi->family == AF_INET6) { ++ if (oldi->family != newi->family) { + list_for_each_entry(nhge, &old->grp_list, nh_list) { + struct nexthop *nhp = nhge->nh_parent; + struct nh_group *nhg; +-- +2.53.0 + diff --git a/queue-6.18/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch b/queue-6.18/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch new file mode 100644 index 0000000000..127b4c65c2 --- /dev/null +++ b/queue-6.18/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch @@ -0,0 +1,53 @@ +From 781a7188fb4a05669d303f6f328c272c4513295b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 12:09:30 +0200 +Subject: NFC: trf7970a: Ignore antenna noise when checking for RF field + +From: Paul Geurts + +[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ] + +The main channel Received Signal Strength Indicator (RSSI) measurement +is used to determine whether an RF field is present or not. RSSI != 0 +is interpreted as an RF Field is present. This does not take RF noise +and measurement inaccuracy into account, and results in false positives +in the field. + +Define a noise level and make sure the RF field is only interpreted as +present when the RSSI is above the noise level. + +Fixes: 851ee3cbf850 ("NFC: trf7970a: Don't turn on RF if there is already an RF field") +Signed-off-by: Paul Geurts +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Mark Greer +Link: https://patch.msgid.link/20260422100930.581237-1-paul.geurts@prodrive-technologies.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/trf7970a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c +index d17c701c7888b..08c27bb438b59 100644 +--- a/drivers/nfc/trf7970a.c ++++ b/drivers/nfc/trf7970a.c +@@ -317,6 +317,7 @@ + #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) ++#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 + + #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) + #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +@@ -1300,7 +1301,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) + if (ret) + return ret; + +- if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) ++ if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) + *is_rf_field = true; + else + *is_rf_field = false; +-- +2.53.0 + diff --git a/queue-6.18/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch b/queue-6.18/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch new file mode 100644 index 0000000000..d5fd5688d1 --- /dev/null +++ b/queue-6.18/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch @@ -0,0 +1,107 @@ +From 59c103578b1b0f6db62c2ebef9bbbc92557adb69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 16:05:36 +0000 +Subject: nfp: fix swapped arguments in nfp_encode_basic_qdr() calls + +From: Alexey Kodanev + +[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ] + +There is a mismatch between the passed arguments and the actual +nfp_encode_basic_qdr() function parameter names: + + static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + int mode, bool addr40, int isld1, + int isld0) + { + ... + +But "dest_island" and "cpp_tgt" are swapped at every call-site. +For example: + + return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + mode, addr40, isld1, isld0); + +As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target +type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" +as the destination island ID, which can accidentally match or be outside +the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination). + +Since code already worked for years, also add extra pr_warn() to error +paths in nfp_encode_basic_qdr() to help identify any potential address +verification failures. + +Detected using the static analysis tool - Svace. + +Fixes: 4cb584e0ee7d ("nfp: add CPP access core") +Signed-off-by: Alexey Kodanev +Link: https://patch.msgid.link/20260422160536.61855-1-aleksei.kodanev@bell-sw.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +index 79470f198a62a..9cf19446657c6 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + + /* Full Island ID and channel bits overlap? */ + ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0); +- if (ret) ++ if (ret) { ++ pr_warn("%s: decode dest_island failed: %d\n", __func__, ret); + return ret; ++ } + + /* The current address won't go where expected? */ +- if (dest_island != -1 && dest_island != v) ++ if (dest_island != -1 && dest_island != v) { ++ pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n", ++ __func__, dest_island, v); + return -EINVAL; ++ } + + /* If dest_island was -1, we don't care where it goes. */ + return 0; +@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * the address but we can verify if the existing + * contents will point to a valid island. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + iid_lsb = addr40 ? 34 : 26; +@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + return 0; + case 1: + if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40) +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + idx_lsb = addr40 ? 39 : 31; +@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * be set before hand and with them select an island. + * So we need to confirm that it's at least plausible. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + /* Make sure we compare against isldN values +@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * iid<1> = addr<30> = channel<0> + * channel<1> = addr<31> = Index + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + isld[0] &= ~3; +-- +2.53.0 + diff --git a/queue-6.18/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch b/queue-6.18/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch new file mode 100644 index 0000000000..7cc0dd18e3 --- /dev/null +++ b/queue-6.18/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch @@ -0,0 +1,58 @@ +From 5c8b6feb53ae99c4cca20203424d2b8d40d9de15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:49 +0100 +Subject: nfs/blocklayout: Fix compilation error (`make W=1`) in + bl_write_pagelist() + +From: Andy Shevchenko + +[ Upstream commit f83c8dda456ce4863f346aa26d88efa276eda35d ] + +Clang compiler is not happy about set but unused variable +(when dprintk() is no-op): + +.../blocklayout/blocklayout.c:384:9: error: variable 'count' set but not used [-Werror,-Wunused-but-set-variable] + +Remove a leftover from the previous cleanup. + +Fixes: 3a6fd1f004fc ("pnfs/blocklayout: remove read-modify-write handling in bl_write_pagelist") +Acked-by: Anna Schumaker +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/blocklayout/blocklayout.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c +index 0e4c67373e4f9..83e4a32b30182 100644 +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -381,14 +381,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + sector_t isect, extent_length = 0; + struct parallel_io *par = NULL; + loff_t offset = header->args.offset; +- size_t count = header->args.count; + struct page **pages = header->args.pages; + int pg_index = header->args.pgbase >> PAGE_SHIFT; + unsigned int pg_len; + struct blk_plug plug; + int i; + +- dprintk("%s enter, %zu@%lld\n", __func__, count, offset); ++ dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); + + /* At this point, header->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error +@@ -429,7 +428,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + } + + offset += pg_len; +- count -= pg_len; + isect += (pg_len >> SECTOR_SHIFT); + extent_length -= (pg_len >> SECTOR_SHIFT); + } +-- +2.53.0 + diff --git a/queue-6.18/nfsd-fix-nfs4_file-access-extra-count-in-nfsd4_add_r.patch b/queue-6.18/nfsd-fix-nfs4_file-access-extra-count-in-nfsd4_add_r.patch new file mode 100644 index 0000000000..6fc855bfb6 --- /dev/null +++ b/queue-6.18/nfsd-fix-nfs4_file-access-extra-count-in-nfsd4_add_r.patch @@ -0,0 +1,55 @@ +From 83ea98f80c0e41dff2d04836812c1b8eb9616263 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 13:07:43 -0800 +Subject: NFSD: fix nfs4_file access extra count in + nfsd4_add_rdaccess_to_wrdeleg + +From: Dai Ngo + +[ Upstream commit b48f44f36e6607b2f818560f19deb86b4a9c717b ] + +In nfsd4_add_rdaccess_to_wrdeleg, if fp->fi_fds[O_RDONLY] is already +set by another thread, __nfs4_file_get_access should not be called +to increment the nfs4_file access count since that was already done +by the thread that added READ access to the file. The extra fi_access +count in nfs4_file can prevent the corresponding nfsd_file from being +freed. + +When stopping nfs-server service, these extra access counts trigger a +BUG in kmem_cache_destroy() that shows nfsd_file object remaining on +__kmem_cache_shutdown. + +This problem can be reproduced by running the Git project's test +suite over NFS. + +Fixes: 8072e34e1387 ("nfsd: fix nfsd_file reference leak in nfsd4_add_rdaccess_to_wrdeleg()") +Signed-off-by: Dai Ngo +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index c5dba49c90356..adc33830438bb 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6255,12 +6255,12 @@ nfsd4_add_rdaccess_to_wrdeleg(struct svc_rqst *rqstp, struct nfsd4_open *open, + return (false); + fp = stp->st_stid.sc_file; + spin_lock(&fp->fi_lock); +- __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ); + if (!fp->fi_fds[O_RDONLY]) { ++ __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ); + fp->fi_fds[O_RDONLY] = nf; ++ fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]); + nf = NULL; + } +- fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]); + spin_unlock(&fp->fi_lock); + if (nf) + nfsd_file_put(nf); +-- +2.53.0 + diff --git a/queue-6.18/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch b/queue-6.18/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch new file mode 100644 index 0000000000..bb6e74e154 --- /dev/null +++ b/queue-6.18/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch @@ -0,0 +1,61 @@ +From a141c12d104833bb59c47bc8b554a8164d7a36fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:52:09 +0900 +Subject: nilfs2: reject zero bd_oblocknr in nilfs_ioctl_mark_blocks_dirty() + +From: Deepanshu Kartikey + +[ Upstream commit be3e5d10643d3be1cbac9d9939f220a99253f980 ] + +nilfs_ioctl_mark_blocks_dirty() uses bd_oblocknr to detect dead blocks +by comparing it with the current block number bd_blocknr. If they differ, +the block is considered dead and skipped. + +However, bd_oblocknr should never be 0 since block 0 typically stores the +primary superblock and is never a valid GC target block. A corrupted ioctl +request with bd_oblocknr set to 0 causes the comparison to incorrectly +match when the lookup returns -ENOENT and sets bd_blocknr to 0, bypassing +the dead block check and calling nilfs_bmap_mark() on a non-existent +block. This causes nilfs_btree_do_lookup() to return -ENOENT, triggering +the WARN_ON(ret == -ENOENT). + +Fix this by rejecting ioctl requests with bd_oblocknr set to 0 at the +beginning of each iteration. + +[ryusuke: slightly modified the commit message and comments for accuracy] + +Fixes: 7942b919f732 ("nilfs2: ioctl operations") +Reported-by: syzbot+98a040252119df0506f8@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=98a040252119df0506f8 +Suggested-by: Ryusuke Konishi +Signed-off-by: Deepanshu Kartikey +Reported-by: syzbot+466a45fcfb0562f5b9a0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=466a45fcfb0562f5b9a0 +Cc: Junjie Cao +Signed-off-by: Ryusuke Konishi +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/nilfs2/ioctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index 3288c3b4be9ec..7fa02146f1e06 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -736,6 +736,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, + int ret, i; + + for (i = 0; i < nmembs; i++) { ++ /* ++ * bd_oblocknr must never be 0 as block 0 ++ * is never a valid GC target block ++ */ ++ if (unlikely(!bdescs[i].bd_oblocknr)) ++ return -EINVAL; + /* XXX: use macro or inline func to check liveness */ + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, +-- +2.53.0 + diff --git a/queue-6.18/nstree-fix-func.-parameter-kernel-doc-warnings.patch b/queue-6.18/nstree-fix-func.-parameter-kernel-doc-warnings.patch new file mode 100644 index 0000000000..9699339f20 --- /dev/null +++ b/queue-6.18/nstree-fix-func.-parameter-kernel-doc-warnings.patch @@ -0,0 +1,59 @@ +From f65fa7b3facd000767fc2e86c0436e9b00724b0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:54:29 -0700 +Subject: nstree: fix func. parameter kernel-doc warnings + +From: Randy Dunlap + +[ Upstream commit 43eb354ecb471426e97b0ce6a0c922ec20f82027 ] + +Use the correct parameter name ("__ns") for function parameter kernel-doc +to avoid 3 warnings: + +Warning: include/linux/nstree.h:68 function parameter '__ns' not described in 'ns_tree_add_raw' +Warning: include/linux/nstree.h:77 function parameter '__ns' not described in 'ns_tree_add' +Warning: include/linux/nstree.h:88 function parameter '__ns' not described in 'ns_tree_remove' + +Fixes: 885fc8ac0a4d ("nstree: make iterator generic") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260416215429.948898-1-rdunlap@infradead.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + include/linux/nstree.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/include/linux/nstree.h b/include/linux/nstree.h +index 8b86366904739..4e2af7a973684 100644 +--- a/include/linux/nstree.h ++++ b/include/linux/nstree.h +@@ -45,7 +45,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree *ns_tree) + + /** + * ns_tree_add_raw - Add a namespace to a namespace +- * @ns: Namespace to add ++ * @__ns: Namespace to add + * + * This function adds a namespace to the appropriate namespace tree + * without assigning a id. +@@ -54,7 +54,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree *ns_tree) + + /** + * ns_tree_add - Add a namespace to a namespace tree +- * @ns: Namespace to add ++ * @__ns: Namespace to add + * + * This function assigns a new id to the namespace and adds it to the + * appropriate namespace tree and list. +@@ -63,7 +63,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree *ns_tree) + + /** + * ns_tree_remove - Remove a namespace from a namespace tree +- * @ns: Namespace to remove ++ * @__ns: Namespace to remove + * + * This function removes a namespace from the appropriate namespace + * tree and list. +-- +2.53.0 + diff --git a/queue-6.18/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch b/queue-6.18/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch new file mode 100644 index 0000000000..4f723effe9 --- /dev/null +++ b/queue-6.18/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch @@ -0,0 +1,39 @@ +From a88ed0020ec226154c1498e8061a6bee50137084 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 09:14:02 -0700 +Subject: nvme-pci: fix missed admin queue sq doorbell write + +From: Keith Busch + +[ Upstream commit 1cc4cdae2a3b7730d462d69e30f213fd2efe7807 ] + +We can batch admin commands submitted through io_uring_cmd passthrough, +which means bd->last may be false and skips the doorbell write to +aggregate multiple commands per write. If a subsequent command can't be +dispatched for whatever reason, we have to provide the blk-mq ops' +commit_rqs callback in order to ensure we properly update the doorbell. + +Fixes: 58e5bdeb9c2b ("nvme: enable uring-passthrough for admin commands") +Reviewed-by: Christoph Hellwig +Reviewed-by: Kanchan Joshi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 8875855e45352..2e32242bed67c 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2028,6 +2028,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled) + static const struct blk_mq_ops nvme_mq_admin_ops = { + .queue_rq = nvme_queue_rq, + .complete = nvme_pci_complete_rq, ++ .commit_rqs = nvme_commit_rqs, + .init_hctx = nvme_admin_init_hctx, + .init_request = nvme_pci_init_request, + .timeout = nvme_timeout, +-- +2.53.0 + diff --git a/queue-6.18/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch b/queue-6.18/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch new file mode 100644 index 0000000000..07905c8fa2 --- /dev/null +++ b/queue-6.18/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch @@ -0,0 +1,162 @@ +From ba9bebe019e4f16beb0bf535efa49acd57a464a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 15:39:35 +0100 +Subject: nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its + callers + +From: Maurizio Lombardi + +[ Upstream commit ea8e356acb165cb1fd75537a52e1f66e5e76c538 ] + +Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds +PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) +and returns early. However, because the function returns void, the +callers are entirely unaware that a fatal error has occurred and +that the cmd->recv_msg.msg_iter was left uninitialized. + +Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly +overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA +Consequently, the socket receiving loop may attempt to read incoming +network data into the uninitialized iterator. + +Fix this by shifting the error handling responsibility to the callers. + +Fixes: 52a0a9854934 ("nvmet-tcp: add bounds checks in nvmet_tcp_build_pdu_iovec") +Reviewed-by: Hannes Reinecke +Reviewed-by: Yunje Shin +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Maurizio Lombardi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 51 ++++++++++++++++++++++----------------- + 1 file changed, 29 insertions(+), 22 deletions(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 3d8810b42e9dc..97d8c1d3545b0 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -351,7 +351,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); + +-static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) ++static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + { + struct bio_vec *iov = cmd->iov; + struct scatterlist *sg; +@@ -364,22 +364,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + offset = cmd->rbytes_done; + cmd->sg_idx = offset / PAGE_SIZE; + sg_offset = offset % PAGE_SIZE; +- if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) ++ return -EPROTO; ++ + sg = &cmd->req.sg[cmd->sg_idx]; + sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; + + while (length) { +- if (!sg_remaining) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } +- if (!sg->length || sg->length <= sg_offset) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!sg_remaining) ++ return -EPROTO; ++ ++ if (!sg->length || sg->length <= sg_offset) ++ return -EPROTO; ++ + u32 iov_len = min_t(u32, length, sg->length - sg_offset); + + bvec_set_page(iov, sg_page(sg), iov_len, +@@ -394,6 +391,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + + iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, + nr_pages, cmd->pdu_len); ++ return 0; + } + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) +@@ -958,7 +956,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) + return 0; + } + +-static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, ++static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) + { + size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); +@@ -974,19 +972,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + if (!nvme_is_write(cmd->req.cmd) || !data_len || + data_len > cmd->req.port->inline_data_size) { + nvmet_prepare_receive_pdu(queue); +- return; ++ return 0; + } + + ret = nvmet_tcp_map_data(cmd); + if (unlikely(ret)) { + pr_err("queue %d: failed to map data\n", queue->idx); + nvmet_tcp_fatal_error(queue); +- return; ++ return -EPROTO; + } + + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(cmd); + cmd->flags |= NVMET_TCP_F_INIT_FAILED; ++ ret = nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ ++ return ret; + } + + static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) +@@ -1038,7 +1040,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) + goto err_proto; + } + cmd->pdu_recv = 0; +- nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) { ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ goto err_proto; ++ } + queue->cmd = cmd; + queue->rcv_state = NVMET_TCP_RECV_DATA; + +@@ -1101,8 +1106,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + le32_to_cpu(req->cmd->common.dptr.sgl.length), + le16_to_cpu(req->cqe->status)); + +- nvmet_tcp_handle_req_failure(queue, queue->cmd, req); +- return 0; ++ return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); + } + + ret = nvmet_tcp_map_data(queue->cmd); +@@ -1119,8 +1123,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + if (nvmet_tcp_need_data_in(queue->cmd)) { + if (nvmet_tcp_has_inline_data(queue->cmd)) { + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(queue->cmd); +- return 0; ++ ret = nvmet_tcp_build_pdu_iovec(queue->cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", ++ queue->idx); ++ return ret; + } + /* send back R2T */ + nvmet_tcp_queue_response(&queue->cmd->req); +-- +2.53.0 + diff --git a/queue-6.18/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch b/queue-6.18/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch new file mode 100644 index 0000000000..63d7fc7535 --- /dev/null +++ b/queue-6.18/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch @@ -0,0 +1,48 @@ +From e626c5eef2a4e56e7ca13069c232e33714421c27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:09 +0800 +Subject: ocfs2/dlm: fix off-by-one in dlm_match_regions() region comparison + +From: Junrui Luo + +[ Upstream commit 01b61e8dda9b0fdb0d4cda43de25f4e390554d7b ] + +The local-vs-remote region comparison loop uses '<=' instead of '<', +causing it to read one entry past the valid range of qr_regions. The +other loops in the same function correctly use '<'. + +Fix the loop condition to use '<' for consistency and correctness. + +Link: https://lkml.kernel.org/r/SYBPR01MB78813DA26B50EC5E01F00566AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index f159785a21116..09bee7b86815e 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1002,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + for (i = 0; i < localnr; ++i) { + foundit = 0; + r = remote; +- for (j = 0; j <= qr->qr_numregions; ++j) { ++ for (j = 0; j < qr->qr_numregions; ++j) { + if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { + foundit = 1; + break; +-- +2.53.0 + diff --git a/queue-6.18/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch b/queue-6.18/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch new file mode 100644 index 0000000000..07f4206239 --- /dev/null +++ b/queue-6.18/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch @@ -0,0 +1,75 @@ +From 7336285cf6b01df36af0ca2c09cd5a2d432bc4a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:08 +0800 +Subject: ocfs2/dlm: validate qr_numregions in dlm_match_regions() + +From: Junrui Luo + +[ Upstream commit 7ab3fbb01bc6d79091bc375e5235d360cd9b78be ] + +Patch series "ocfs2/dlm: fix two bugs in dlm_match_regions()". + +In dlm_match_regions(), the qr_numregions field from a DLM_QUERY_REGION +network message is used to drive loops over the qr_regions buffer without +sufficient validation. This series fixes two issues: + +- Patch 1 adds a bounds check to reject messages where qr_numregions + exceeds O2NM_MAX_REGIONS. The o2net layer only validates message + byte length; it does not constrain field values, so a crafted message + can set qr_numregions up to 255 and trigger out-of-bounds reads past + the 1024-byte qr_regions buffer. + +- Patch 2 fixes an off-by-one in the local-vs-remote comparison loop, + which uses '<=' instead of '<', reading one entry past the valid range + even when qr_numregions is within bounds. + +This patch (of 2): + +The qr_numregions field from a DLM_QUERY_REGION network message is used +directly as loop bounds in dlm_match_regions() without checking against +O2NM_MAX_REGIONS. Since qr_regions is sized for at most O2NM_MAX_REGIONS +(32) entries, a crafted message with qr_numregions > 32 causes +out-of-bounds reads past the qr_regions buffer. + +Add a bounds check for qr_numregions before entering the loops. + +Link: https://lkml.kernel.org/r/SYBPR01MB7881A334D02ACEE5E0645801AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Link: https://lkml.kernel.org/r/SYBPR01MB788166F524AD04E262E174BEAF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 2347a50f079b7..f159785a21116 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + goto bail; + } + ++ if (qr->qr_numregions > O2NM_MAX_REGIONS) { ++ mlog(ML_ERROR, "Domain %s: Joining node %d has invalid " ++ "number of heartbeat regions %u\n", ++ qr->qr_domain, qr->qr_node, qr->qr_numregions); ++ status = -EINVAL; ++ goto bail; ++ } ++ + r = remote; + for (i = 0; i < qr->qr_numregions; ++i) { + mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); +-- +2.53.0 + diff --git a/queue-6.18/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch b/queue-6.18/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch new file mode 100644 index 0000000000..a774942c21 --- /dev/null +++ b/queue-6.18/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch @@ -0,0 +1,89 @@ +From 213501e08ff4eff733a8d56785a584b5607b69bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 12:03:39 +0800 +Subject: ocfs2: fix listxattr handling when the buffer is full + +From: ZhengYuan Huang + +[ Upstream commit d12f558e6200b3f47dbef9331ed6d115d2410e59 ] + +[BUG] +If an OCFS2 inode has both inline and block-based xattrs, listxattr() +can return a size larger than the caller's buffer when the inline names +consume that buffer exactly. + +kernel BUG at mm/usercopy.c:102! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:usercopy_abort+0xb7/0xd0 mm/usercopy.c:102 +Call Trace: + __check_heap_object+0xe3/0x120 mm/slub.c:8243 + check_heap_object mm/usercopy.c:196 [inline] + __check_object_size mm/usercopy.c:250 [inline] + __check_object_size+0x5c5/0x780 mm/usercopy.c:215 + check_object_size include/linux/ucopysize.h:22 [inline] + check_copy_size include/linux/ucopysize.h:59 [inline] + copy_to_user include/linux/uaccess.h:219 [inline] + listxattr+0xb0/0x170 fs/xattr.c:926 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x137/0x320 fs/xattr.c:988 + __do_sys_listxattr fs/xattr.c:1001 [inline] + __se_sys_listxattr fs/xattr.c:998 [inline] + __x64_sys_listxattr+0x7f/0xd0 fs/xattr.c:998 + ... + +[CAUSE] +Commit 936b8834366e ("ocfs2: Refactor xattr list and remove +ocfs2_xattr_handler().") replaced the old per-handler list accounting +with ocfs2_xattr_list_entry(), but it kept using size == 0 to detect +probe mode. + +That assumption stops being true once ocfs2_listxattr() finishes the +inline-xattr pass. If the inline names fill the caller buffer exactly, +the block-xattr pass runs with a non-NULL buffer and a remaining size of +zero. ocfs2_xattr_list_entry() then skips the bounds check, keeps +counting block names, and returns a positive size larger than the +supplied buffer. + +[FIX] +Detect probe mode by testing whether the destination buffer pointer is +NULL instead of whether the remaining size is zero. + +That restores the pre-refactor behavior and matches the OCFS2 getxattr +helpers. Once the remaining buffer reaches zero while more names are +left, the block-xattr pass now returns -ERANGE instead of reporting a +size larger than the allocated list buffer. + +Link: https://lkml.kernel.org/r/20260410040339.3837162-1-gality369@gmail.com +Fixes: 936b8834366e ("ocfs2: Refactor xattr list and remove ocfs2_xattr_handler().") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 64ba3946f8408..8f7018bad283b 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -907,8 +907,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb, + total_len = prefix_len + name_len + 1; + *result += total_len; + +- /* we are just looking for how big our buffer needs to be */ +- if (!size) ++ /* No buffer means we are only looking for the required size. */ ++ if (!buffer) + return 0; + + if (*result > size) +-- +2.53.0 + diff --git a/queue-6.18/ocfs2-validate-bg_bits-during-freefrag-scan.patch b/queue-6.18/ocfs2-validate-bg_bits-during-freefrag-scan.patch new file mode 100644 index 0000000000..191fc10d75 --- /dev/null +++ b/queue-6.18/ocfs2-validate-bg_bits-during-freefrag-scan.patch @@ -0,0 +1,121 @@ +From 2dbbec70134c0d5a9d9d6c396686e88d8424bd62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:42:20 +0800 +Subject: ocfs2: validate bg_bits during freefrag scan + +From: ZhengYuan Huang + +[ Upstream commit 8f687eeed3da3012152b0f9473f578869de0cd7b ] + +[BUG] +A crafted filesystem can trigger an out-of-bounds bitmap walk when +OCFS2_IOC_INFO is issued with OCFS2_INFO_FL_NON_COHERENT. + +BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:68 [inline] +BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] +BUG: KASAN: use-after-free in test_bit_le include/asm-generic/bitops/le.h:21 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 +Read of size 8 at addr ffff888031bce000 by task syz.0.636/1435 +Call Trace: + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xd1/0x650 mm/kasan/report.c:482 + kasan_report+0xfb/0x140 mm/kasan/report.c:595 + check_region_inline mm/kasan/generic.c:186 [inline] + kasan_check_range+0x11c/0x200 mm/kasan/generic.c:200 + __kasan_check_read+0x11/0x20 mm/kasan/shadow.c:31 + instrument_atomic_read include/linux/instrumented.h:68 [inline] + _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] + test_bit_le include/asm-generic/bitops/le.h:21 [inline] + ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] + ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] + ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] + ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 + ocfs2_info_handle+0x18d/0x2a0 fs/ocfs2/ioctl.c:828 + ocfs2_ioctl+0x632/0x6e0 fs/ocfs2/ioctl.c:913 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + ... + +[CAUSE] +ocfs2_info_freefrag_scan_chain() uses on-disk bg_bits directly as the +bitmap scan limit. The coherent path reads group descriptors through +ocfs2_read_group_descriptor(), which validates the descriptor before +use. The non-coherent path uses ocfs2_read_blocks_sync() instead and +skips that validation, so an impossible bg_bits value can drive the +bitmap walk past the end of the block. + +[FIX] +Compute the bitmap capacity from the filesystem format with +ocfs2_group_bitmap_size(), report descriptors whose bg_bits exceeds +that limit, and clamp the scan to the computed capacity. This keeps the +freefrag report going while avoiding reads beyond the buffer. + +Link: https://lkml.kernel.org/r/20260410034220.3825769-1-gality369@gmail.com +Fixes: d24a10b9f8ed ("Ocfs2: Add a new code 'OCFS2_INFO_FREEFRAG' for o2info ioctl.") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Heming Zhao +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/ioctl.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c +index b6864602814c4..b004e7117a5f3 100644 +--- a/fs/ocfs2/ioctl.c ++++ b/fs/ocfs2/ioctl.c +@@ -441,13 +441,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + struct buffer_head *bh = NULL; + struct ocfs2_group_desc *bg = NULL; + +- unsigned int max_bits, num_clusters; ++ unsigned int max_bits, max_bitmap_bits, num_clusters; + unsigned int offset = 0, cluster, chunk; + unsigned int chunk_free, last_chunksize = 0; + + if (!le32_to_cpu(rec->c_free)) + goto bail; + ++ max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0, ++ osb->s_feature_incompat); ++ + do { + if (!bg) + blkno = le64_to_cpu(rec->c_blkno); +@@ -479,6 +482,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + continue; + + max_bits = le16_to_cpu(bg->bg_bits); ++ ++ /* ++ * Non-coherent scans read raw blocks and do not get the ++ * bg_bits validation from ++ * ocfs2_read_group_descriptor(). ++ */ ++ if (max_bits > max_bitmap_bits) { ++ mlog(ML_ERROR, ++ "Group desc #%llu has %u bits, max bitmap bits %u\n", ++ (unsigned long long)blkno, max_bits, max_bitmap_bits); ++ max_bits = max_bitmap_bits; ++ } ++ + offset = 0; + + for (chunk = 0; chunk < chunks_in_group; chunk++) { +-- +2.53.0 + diff --git a/queue-6.18/ocfs2-validate-group-add-input-before-caching.patch b/queue-6.18/ocfs2-validate-group-add-input-before-caching.patch new file mode 100644 index 0000000000..3fc2af9e04 --- /dev/null +++ b/queue-6.18/ocfs2-validate-group-add-input-before-caching.patch @@ -0,0 +1,110 @@ +From fa8a46d2da64e42eb9a2f24af66751541c0837bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 10:02:08 +0800 +Subject: ocfs2: validate group add input before caching + +From: ZhengYuan Huang + +[ Upstream commit 70b672833f4025341c11b22c7f83778a5cd611bc ] + +[BUG] +OCFS2_IOC_GROUP_ADD can trigger a BUG_ON in +ocfs2_set_new_buffer_uptodate(): + +kernel BUG at fs/ocfs2/uptodate.c:509! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:ocfs2_set_new_buffer_uptodate+0x194/0x1e0 fs/ocfs2/uptodate.c:509 +Code: ffffe88f 42b9fe4c 89e64889 dfe8b4df +Call Trace: + ocfs2_group_add+0x3f1/0x1510 fs/ocfs2/resize.c:507 + ocfs2_ioctl+0x309/0x6e0 fs/ocfs2/ioctl.c:887 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + x64_sys_call+0x1144/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:17 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e +RIP: 0033:0x7bbfb55a966d + +[CAUSE] +ocfs2_group_add() calls ocfs2_set_new_buffer_uptodate() on a +user-controlled group block before ocfs2_verify_group_and_input() +validates that block number. That helper is only valid for newly +allocated metadata and asserts that the block is not already present in +the chosen metadata cache. The code also uses INODE_CACHE(inode) even +though the group descriptor belongs to main_bm_inode and later journal +accesses use that cache context instead. + +[FIX] +Validate the on-disk group descriptor before caching it, then add it to +the metadata cache tracked by INODE_CACHE(main_bm_inode). Keep the +validation failure path separate from the later cleanup path so we only +remove the buffer from that cache after it has actually been inserted. +This keeps the group buffer lifetime consistent across validation, +journaling, and cleanup. + +Link: https://lkml.kernel.org/r/20260410020209.3786348-1-gality369@gmail.com +Fixes: 7909f2bf8353 ("[PATCH 2/2] ocfs2: Implement group add for online resize") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/resize.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c +index ed7ed15ad9a73..583a411557ab9 100644 +--- a/fs/ocfs2/resize.c ++++ b/fs/ocfs2/resize.c +@@ -508,14 +508,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + goto out_unlock; + } + +- ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); +- + ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); + if (ret) { + mlog_errno(ret); + goto out_free_group_bh; + } + ++ ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh); ++ + trace_ocfs2_group_add((unsigned long long)input->group, + input->chain, input->clusters, input->frees); + +@@ -523,7 +523,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + if (IS_ERR(handle)) { + mlog_errno(PTR_ERR(handle)); + ret = -EINVAL; +- goto out_free_group_bh; ++ goto out_remove_cache; + } + + cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); +@@ -577,9 +577,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + out_commit: + ocfs2_commit_trans(osb, handle); + +-out_free_group_bh: ++out_remove_cache: + if (ret < 0) +- ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); ++ ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh); ++ ++out_free_group_bh: + brelse(group_bh); + + out_unlock: +-- +2.53.0 + diff --git a/queue-6.18/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch b/queue-6.18/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch new file mode 100644 index 0000000000..6159fccb2d --- /dev/null +++ b/queue-6.18/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch @@ -0,0 +1,132 @@ +From 6cdcb1012a93487e729e7d3363ec920f3e0f829a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 19:46:54 -0700 +Subject: openvswitch: cap upcall PID array size and pre-size vport replies + +From: Weiming Shi + +[ Upstream commit 2091c6aa0df6aba47deb5c8ab232b1cb60af3519 ] + +The vport netlink reply helpers allocate a fixed-size skb with +nlmsg_new(NLMSG_DEFAULT_SIZE, ...) but serialize the full upcall PID +array via ovs_vport_get_upcall_portids(). Since +ovs_vport_set_upcall_portids() accepts any non-zero multiple of +sizeof(u32) with no upper bound, a CAP_NET_ADMIN user can install a PID +array large enough to overflow the reply buffer, causing nla_put() to +fail with -EMSGSIZE and hitting BUG_ON(err < 0). On systems with +unprivileged user namespaces enabled (e.g., Ubuntu default), this is +reachable via unshare -Urn since OVS vport mutation operations use +GENL_UNS_ADMIN_PERM. + + kernel BUG at net/openvswitch/datapath.c:2414! + Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI + CPU: 1 UID: 0 PID: 65 Comm: poc Not tainted 7.0.0-rc7-00195-geb216e422044 #1 + RIP: 0010:ovs_vport_cmd_set+0x34c/0x400 + Call Trace: + + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1116) + genl_rcv_msg (net/netlink/genetlink.c:1194) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + genl_rcv (net/netlink/genetlink.c:1219) + netlink_unicast (net/netlink/af_netlink.c:1344) + netlink_sendmsg (net/netlink/af_netlink.c:1894) + __sys_sendto (net/socket.c:2206) + __x64_sys_sendto (net/socket.c:2209) + do_syscall_64 (arch/x86/entry/syscall_64.c:63) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + + Kernel panic - not syncing: Fatal exception + +Reject attempts to set more PIDs than nr_cpu_ids in +ovs_vport_set_upcall_portids(), and pre-compute the worst-case reply +size in ovs_vport_cmd_msg_size() based on that bound, similar to the +existing ovs_dp_cmd_msg_size(). nr_cpu_ids matches the cap already +used by the per-CPU dispatch configuration on the datapath side +(ovs_dp_cmd_fill_info() serialises at most nr_cpu_ids PIDs), so the +two sides stay consistent. + +Fixes: 5cd667b0a456 ("openvswitch: Allow each vport to have an array of 'port_id's.") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Weiming Shi +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260416024653.153456-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 35 +++++++++++++++++++++++++++++++++-- + net/openvswitch/vport.c | 3 +++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index d5b6e2002bc1f..2304c8e3be4f7 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -2186,9 +2186,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + return err; + } + ++static size_t ovs_vport_cmd_msg_size(void) ++{ ++ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); ++ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */ ++ msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */ ++ msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */ ++ ++ /* OVS_VPORT_ATTR_STATS */ ++ msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats)); ++ ++ /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + ++ * OVS_VPORT_UPCALL_ATTR_FAIL) ++ */ ++ msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) + ++ nla_total_size_64bit(sizeof(u64))); ++ ++ /* OVS_VPORT_ATTR_UPCALL_PID */ ++ msgsize += nla_total_size(nr_cpu_ids * sizeof(u32)); ++ ++ /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + ++ * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) ++ */ ++ msgsize += nla_total_size(nla_total_size(sizeof(u16)) + ++ nla_total_size(nla_total_size(0))); ++ ++ return msgsize; ++} ++ + static struct sk_buff *ovs_vport_cmd_alloc_info(void) + { +- return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL); + } + + /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ +@@ -2198,7 +2229,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, + struct sk_buff *skb; + int retval; + +- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ skb = ovs_vport_cmd_alloc_info(); + if (!skb) + return ERR_PTR(-ENOMEM); + +diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c +index f0ce8ce1dce0e..1f0c86a9f43b0 100644 +--- a/net/openvswitch/vport.c ++++ b/net/openvswitch/vport.c +@@ -407,6 +407,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids) + if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) + return -EINVAL; + ++ if (nla_len(ids) / sizeof(u32) > nr_cpu_ids) ++ return -EINVAL; ++ + old = ovsl_dereference(vport->upcall_portids); + + vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), +-- +2.53.0 + diff --git a/queue-6.18/opp-debugfs-use-performance-level-if-available-to-di.patch b/queue-6.18/opp-debugfs-use-performance-level-if-available-to-di.patch new file mode 100644 index 0000000000..b8648d9303 --- /dev/null +++ b/queue-6.18/opp-debugfs-use-performance-level-if-available-to-di.patch @@ -0,0 +1,69 @@ +From 519f752175888d36cf896bdb24e5c5e0726727d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 12:49:40 +0530 +Subject: OPP: debugfs: Use performance level if available to distinguish + between rates + +From: Manivannan Sadhasivam + +[ Upstream commit e560083c0467f86b72aecac377b27bd1e7d16c49 ] + +Some OPP tables have entries with same rate and different performance +level. For these entries, using only the rate as the debugfs directory name +causes below error: + +debugfs: 'opp:5000000' already exists in 'soc@0-1c00000.pci' + +Fix it by appending the performance level to the dir name if available. + +Reported-by: Bjorn Andersson +Closes: https://lore.kernel.org/linux-arm-msm/75lzykd37zdvrks5i2bb4zb2yzjtm25kv3hegmikndkbr772mz@w2ykff3ny45u/ +Fixes: 05db35963eef ("OPP: Add support to find OPP for a set of keys") +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/opp/debugfs.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c +index 8fc6238b17284..61506d30d5ff0 100644 +--- a/drivers/opp/debugfs.c ++++ b/drivers/opp/debugfs.c +@@ -130,22 +130,24 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) + { + struct dentry *pdentry = opp_table->dentry; + struct dentry *d; +- unsigned long id; +- char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */ ++ char name[36]; /* "opp:"(4) + u64(20) + "-" (1) + u32(10) + NULL(1) */ + + /* + * Get directory name for OPP. + * +- * - Normally rate is unique to each OPP, use it to get unique opp-name. ++ * - Normally rate is unique to each OPP, use it to get unique opp-name, ++ * together with performance level if available. + * - For some devices rate isn't available or there are multiple, use + * index instead for them. + */ +- if (likely(opp_table->clk_count == 1 && opp->rates[0])) +- id = opp->rates[0]; +- else +- id = _get_opp_count(opp_table); +- +- snprintf(name, sizeof(name), "opp:%lu", id); ++ if (likely(opp_table->clk_count == 1 && opp->rates[0])) { ++ if (opp->level == OPP_LEVEL_UNSET) ++ snprintf(name, sizeof(name), "opp:%lu", opp->rates[0]); ++ else ++ snprintf(name, sizeof(name), "opp:%lu-%u", opp->rates[0], opp->level); ++ } else { ++ snprintf(name, sizeof(name), "opp:%u", _get_opp_count(opp_table)); ++ } + + /* Create per-opp directory */ + d = debugfs_create_dir(name, pdentry); +-- +2.53.0 + diff --git a/queue-6.18/opp-move-break-out-of-scoped_guard-in-dev_pm_opp_xla.patch b/queue-6.18/opp-move-break-out-of-scoped_guard-in-dev_pm_opp_xla.patch new file mode 100644 index 0000000000..8672bacd3e --- /dev/null +++ b/queue-6.18/opp-move-break-out-of-scoped_guard-in-dev_pm_opp_xla.patch @@ -0,0 +1,44 @@ +From d9fed0ee797d399e53cdc17bef731cf8d965fdc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 11:05:59 +0530 +Subject: OPP: Move break out of scoped_guard in + dev_pm_opp_xlate_required_opp() + +From: Viresh Kumar + +[ Upstream commit 3d2398f44a2d48fb1c575a6e0bc6b38f3e689e22 ] + +The commit ff9c512041f2 ("OPP: Use mutex locking guards") +unintentionally made the for loop run longer than required. + +scoped_guard() is implemented as a for loop. The break statement now +breaks out out the scoped_guard() and not out of the outer for loop. +The outer loop always iterates to completion. + +Fix it. + +Fixes: ff9c512041f2 ("OPP: Use mutex locking guards") +Reported-by: David Lechner +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/opp/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index 775d4a36f2f54..157c84b689feb 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -2741,8 +2741,8 @@ struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, + break; + } + } +- break; + } ++ break; + } + + if (IS_ERR(dest_opp)) { +-- +2.53.0 + diff --git a/queue-6.18/padata-put-cpu-offline-callback-in-online-section-to.patch b/queue-6.18/padata-put-cpu-offline-callback-in-online-section-to.patch new file mode 100644 index 0000000000..901e74407b --- /dev/null +++ b/queue-6.18/padata-put-cpu-offline-callback-in-online-section-to.patch @@ -0,0 +1,372 @@ +From 58de779d3e7399b0d8b6f4a7ed1382b48585c33e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 11:24:33 -0400 +Subject: padata: Put CPU offline callback in ONLINE section to allow failure + +From: Daniel Jordan + +[ Upstream commit c8c4a2972f83c8b68ff03b43cecdb898939ff851 ] + +syzbot reported the following warning: + + DEAD callback error for CPU1 + WARNING: kernel/cpu.c:1463 at _cpu_down+0x759/0x1020 kernel/cpu.c:1463, CPU#0: syz.0.1960/14614 + +at commit 4ae12d8bd9a8 ("Merge tag 'kbuild-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux") +which tglx traced to padata_cpu_dead() given it's the only +sub-CPUHP_TEARDOWN_CPU callback that returns an error. + +Failure isn't allowed in hotplug states before CPUHP_TEARDOWN_CPU +so move the CPU offline callback to the ONLINE section where failure is +possible. + +Fixes: 894c9ef9780c ("padata: validate cpumask without removed CPU during offline") +Reported-by: syzbot+123e1b70473ce213f3af@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69af0a05.050a0220.310d8.002f.GAE@google.com/ +Debugged-by: Thomas Gleixner +Signed-off-by: Daniel Jordan +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + include/linux/cpuhotplug.h | 1 - + include/linux/padata.h | 8 +-- + kernel/padata.c | 120 +++++++++++++++++++------------------ + 3 files changed, 65 insertions(+), 64 deletions(-) + +diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h +index 62cd7b35a29c9..22ba327ec2278 100644 +--- a/include/linux/cpuhotplug.h ++++ b/include/linux/cpuhotplug.h +@@ -92,7 +92,6 @@ enum cpuhp_state { + CPUHP_NET_DEV_DEAD, + CPUHP_IOMMU_IOVA_DEAD, + CPUHP_AP_ARM_CACHE_B15_RAC_DEAD, +- CPUHP_PADATA_DEAD, + CPUHP_AP_DTPM_CPU_DEAD, + CPUHP_RANDOM_PREPARE, + CPUHP_WORKQUEUE_PREP, +diff --git a/include/linux/padata.h b/include/linux/padata.h +index 765f2778e264a..b6232bea6edf5 100644 +--- a/include/linux/padata.h ++++ b/include/linux/padata.h +@@ -149,23 +149,23 @@ struct padata_mt_job { + /** + * struct padata_instance - The overall control structure. + * +- * @cpu_online_node: Linkage for CPU online callback. +- * @cpu_dead_node: Linkage for CPU offline callback. ++ * @cpuhp_node: Linkage for CPU hotplug callbacks. + * @parallel_wq: The workqueue used for parallel work. + * @serial_wq: The workqueue used for serial work. + * @pslist: List of padata_shell objects attached to this instance. + * @cpumask: User supplied cpumasks for parallel and serial works. ++ * @validate_cpumask: Internal cpumask used to validate @cpumask during hotplug. + * @kobj: padata instance kernel object. + * @lock: padata instance lock. + * @flags: padata flags. + */ + struct padata_instance { +- struct hlist_node cpu_online_node; +- struct hlist_node cpu_dead_node; ++ struct hlist_node cpuhp_node; + struct workqueue_struct *parallel_wq; + struct workqueue_struct *serial_wq; + struct list_head pslist; + struct padata_cpumask cpumask; ++ cpumask_var_t validate_cpumask; + struct kobject kobj; + struct mutex lock; + u8 flags; +diff --git a/kernel/padata.c b/kernel/padata.c +index f53263d7c9d42..938c926711876 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -539,7 +539,8 @@ static void padata_init_reorder_list(struct parallel_data *pd) + } + + /* Allocate and initialize the internal cpumask dependend resources. */ +-static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) ++static struct parallel_data *padata_alloc_pd(struct padata_shell *ps, ++ int offlining_cpu) + { + struct padata_instance *pinst = ps->pinst; + struct parallel_data *pd; +@@ -565,6 +566,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) + + cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask); + cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask); ++ if (offlining_cpu >= 0) { ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.pcpu); ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.cbcpu); ++ } + + padata_init_reorder_list(pd); + padata_init_squeues(pd); +@@ -611,11 +616,11 @@ static void __padata_stop(struct padata_instance *pinst) + } + + /* Replace the internal control structure with a new one. */ +-static int padata_replace_one(struct padata_shell *ps) ++static int padata_replace_one(struct padata_shell *ps, int offlining_cpu) + { + struct parallel_data *pd_new; + +- pd_new = padata_alloc_pd(ps); ++ pd_new = padata_alloc_pd(ps, offlining_cpu); + if (!pd_new) + return -ENOMEM; + +@@ -625,7 +630,7 @@ static int padata_replace_one(struct padata_shell *ps) + return 0; + } + +-static int padata_replace(struct padata_instance *pinst) ++static int padata_replace(struct padata_instance *pinst, int offlining_cpu) + { + struct padata_shell *ps; + int err = 0; +@@ -633,7 +638,7 @@ static int padata_replace(struct padata_instance *pinst) + pinst->flags |= PADATA_RESET; + + list_for_each_entry(ps, &pinst->pslist, list) { +- err = padata_replace_one(ps); ++ err = padata_replace_one(ps, offlining_cpu); + if (err) + break; + } +@@ -650,9 +655,21 @@ static int padata_replace(struct padata_instance *pinst) + + /* If cpumask contains no active cpu, we mark the instance as invalid. */ + static bool padata_validate_cpumask(struct padata_instance *pinst, +- const struct cpumask *cpumask) ++ const struct cpumask *cpumask, ++ int offlining_cpu) + { +- if (!cpumask_intersects(cpumask, cpu_online_mask)) { ++ cpumask_copy(pinst->validate_cpumask, cpu_online_mask); ++ ++ /* ++ * @offlining_cpu is still in cpu_online_mask, so remove it here for ++ * validation. Using a sub-CPUHP_TEARDOWN_CPU hotplug state where ++ * @offlining_cpu wouldn't be in the online mask doesn't work because ++ * padata_cpu_offline() can fail but such a state doesn't allow failure. ++ */ ++ if (offlining_cpu >= 0) ++ __cpumask_clear_cpu(offlining_cpu, pinst->validate_cpumask); ++ ++ if (!cpumask_intersects(cpumask, pinst->validate_cpumask)) { + pinst->flags |= PADATA_INVALID; + return false; + } +@@ -668,13 +685,13 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + int valid; + int err; + +- valid = padata_validate_cpumask(pinst, pcpumask); ++ valid = padata_validate_cpumask(pinst, pcpumask, -1); + if (!valid) { + __padata_stop(pinst); + goto out_replace; + } + +- valid = padata_validate_cpumask(pinst, cbcpumask); ++ valid = padata_validate_cpumask(pinst, cbcpumask, -1); + if (!valid) + __padata_stop(pinst); + +@@ -682,7 +699,7 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + cpumask_copy(pinst->cpumask.pcpu, pcpumask); + cpumask_copy(pinst->cpumask.cbcpu, cbcpumask); + +- err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst); ++ err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst, -1); + + if (valid) + __padata_start(pinst); +@@ -734,26 +751,6 @@ EXPORT_SYMBOL(padata_set_cpumask); + + #ifdef CONFIG_HOTPLUG_CPU + +-static int __padata_add_cpu(struct padata_instance *pinst, int cpu) +-{ +- int err = padata_replace(pinst); +- +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- +- return err; +-} +- +-static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) +-{ +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- return padata_replace(pinst); +-} +- + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) + { + return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) || +@@ -765,27 +762,39 @@ static int padata_cpu_online(unsigned int cpu, struct hlist_node *node) + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_add_cpu(pinst, cpu); ++ ++ ret = padata_replace(pinst, -1); ++ ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu, -1) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, -1)) ++ __padata_start(pinst); ++ + mutex_unlock(&pinst->lock); + return ret; + } + +-static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node) ++static int padata_cpu_offline(unsigned int cpu, struct hlist_node *node) + { + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_remove_cpu(pinst, cpu); ++ ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu, cpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, cpu)) ++ __padata_stop(pinst); ++ ++ ret = padata_replace(pinst, cpu); ++ + mutex_unlock(&pinst->lock); + return ret; + } +@@ -796,15 +805,14 @@ static enum cpuhp_state hp_online; + static void __padata_free(struct padata_instance *pinst) + { + #ifdef CONFIG_HOTPLUG_CPU +- cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); +- cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node); ++ cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpuhp_node); + #endif + + WARN_ON(!list_empty(&pinst->pslist)); + + free_cpumask_var(pinst->cpumask.pcpu); + free_cpumask_var(pinst->cpumask.cbcpu); ++ free_cpumask_var(pinst->validate_cpumask); + destroy_workqueue(pinst->serial_wq); + destroy_workqueue(pinst->parallel_wq); + kfree(pinst); +@@ -965,10 +973,10 @@ struct padata_instance *padata_alloc(const char *name) + + if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL)) + goto err_free_serial_wq; +- if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) { +- free_cpumask_var(pinst->cpumask.pcpu); +- goto err_free_serial_wq; +- } ++ if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) ++ goto err_free_p_mask; ++ if (!alloc_cpumask_var(&pinst->validate_cpumask, GFP_KERNEL)) ++ goto err_free_cb_mask; + + INIT_LIST_HEAD(&pinst->pslist); + +@@ -976,7 +984,7 @@ struct padata_instance *padata_alloc(const char *name) + cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask); + + if (padata_setup_cpumasks(pinst)) +- goto err_free_masks; ++ goto err_free_v_mask; + + __padata_start(pinst); + +@@ -985,18 +993,19 @@ struct padata_instance *padata_alloc(const char *name) + + #ifdef CONFIG_HOTPLUG_CPU + cpuhp_state_add_instance_nocalls_cpuslocked(hp_online, +- &pinst->cpu_online_node); +- cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); ++ &pinst->cpuhp_node); + #endif + + cpus_read_unlock(); + + return pinst; + +-err_free_masks: +- free_cpumask_var(pinst->cpumask.pcpu); ++err_free_v_mask: ++ free_cpumask_var(pinst->validate_cpumask); ++err_free_cb_mask: + free_cpumask_var(pinst->cpumask.cbcpu); ++err_free_p_mask: ++ free_cpumask_var(pinst->cpumask.pcpu); + err_free_serial_wq: + destroy_workqueue(pinst->serial_wq); + err_put_cpus: +@@ -1039,7 +1048,7 @@ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst) + ps->pinst = pinst; + + cpus_read_lock(); +- pd = padata_alloc_pd(ps); ++ pd = padata_alloc_pd(ps, -1); + cpus_read_unlock(); + + if (!pd) +@@ -1088,32 +1097,25 @@ void __init padata_init(void) + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online", +- padata_cpu_online, NULL); ++ padata_cpu_online, padata_cpu_offline); + if (ret < 0) + goto err; + hp_online = ret; +- +- ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead", +- NULL, padata_cpu_dead); +- if (ret < 0) +- goto remove_online_state; + #endif + + possible_cpus = num_possible_cpus(); + padata_works = kmalloc_array(possible_cpus, sizeof(struct padata_work), + GFP_KERNEL); + if (!padata_works) +- goto remove_dead_state; ++ goto remove_online_state; + + for (i = 0; i < possible_cpus; ++i) + list_add(&padata_works[i].pw_list, &padata_free_works); + + return; + +-remove_dead_state: +-#ifdef CONFIG_HOTPLUG_CPU +- cpuhp_remove_multi_state(CPUHP_PADATA_DEAD); + remove_online_state: ++#ifdef CONFIG_HOTPLUG_CPU + cpuhp_remove_multi_state(hp_online); + err: + #endif +-- +2.53.0 + diff --git a/queue-6.18/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch b/queue-6.18/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch new file mode 100644 index 0000000000..80df4932f7 --- /dev/null +++ b/queue-6.18/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch @@ -0,0 +1,79 @@ +From 2938cd4edda65c4b8f7848cf408bed6810f02105 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 16:07:03 +0800 +Subject: padata: Remove cpu online check from cpu add and removal + +From: Chuyi Zhou + +[ Upstream commit 73117ea6470dca787f70f33c001f9faf437a1c0b ] + +During the CPU offline process, the dying CPU is cleared from the +cpu_online_mask in takedown_cpu(). After this step, various CPUHP_*_DEAD +callbacks are executed to perform cleanup jobs for the dead CPU, so this +cpu online check in padata_cpu_dead() is unnecessary. + +Similarly, when executing padata_cpu_online() during the +CPUHP_AP_ONLINE_DYN phase, the CPU has already been set in the +cpu_online_mask, the action even occurs earlier than the +CPUHP_AP_ONLINE_IDLE stage. + +Remove this unnecessary cpu online check in __padata_add_cpu() and +__padata_remove_cpu(). + +Signed-off-by: Chuyi Zhou +Acked-by: Daniel Jordan +Signed-off-by: Herbert Xu +Stable-dep-of: c8c4a2972f83 ("padata: Put CPU offline callback in ONLINE section to allow failure") +Signed-off-by: Sasha Levin +--- + kernel/padata.c | 26 ++++++++------------------ + 1 file changed, 8 insertions(+), 18 deletions(-) + +diff --git a/kernel/padata.c b/kernel/padata.c +index f4def028c48c0..f53263d7c9d42 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -736,32 +736,22 @@ EXPORT_SYMBOL(padata_set_cpumask); + + static int __padata_add_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (cpumask_test_cpu(cpu, cpu_online_mask)) { +- err = padata_replace(pinst); ++ int err = padata_replace(pinst); + +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- } ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_start(pinst); + + return err; + } + + static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (!cpumask_test_cpu(cpu, cpu_online_mask)) { +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- err = padata_replace(pinst); +- } ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_stop(pinst); + +- return err; ++ return padata_replace(pinst); + } + + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) +-- +2.53.0 + diff --git a/queue-6.18/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch b/queue-6.18/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch new file mode 100644 index 0000000000..a0305478e7 --- /dev/null +++ b/queue-6.18/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch @@ -0,0 +1,109 @@ +From c3ba079b678f6fab02f998e55ec2cb88b588f831 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 19:07:39 +0200 +Subject: page_pool: fix memory-provider leak in page_pool_create_percpu() + error path + +From: Hasan Basbunar + +[ Upstream commit 5ef343614db766acdc01c56d66e780a1b43c6ac6 ] + +When page_pool_create_percpu() fails on page_pool_list(), it falls +through to its err_uninit: label, which calls page_pool_uninit(). +At that point page_pool_init() has already taken two references +when the user requested PP_FLAG_ALLOW_UNREADABLE_NETMEM: + + pool->mp_ops->init(pool) + static_branch_inc(&page_pool_mem_providers); + +Neither is undone by page_pool_uninit(); both are only undone by +__page_pool_destroy() (success-side teardown). The error path +therefore leaks the per-provider reference taken by mp_ops->init +(io_zcrx_ifq->refs in the io_uring zcrx provider, the dmabuf +binding refcount in the devmem provider) plus one increment of +the page_pool_mem_providers static branch on every failure of +xa_alloc_cyclic() inside page_pool_list(). + +The leaked io_zcrx_ifq->refs in turn pins everything +io_zcrx_ifq_free() would release on cleanup: ifq->user (uid), +ifq->mm_account (mmdrop), ifq->dev (device refcount), +ifq->netdev_tracker (netdev refcount), and the rbuf region. +The leaked static branch increment forces all subsequent +page_pool_alloc_netmems() and page_pool_return_page() callers to +take the slow mp_ops branch for the lifetime of the kernel. + +Reachable via the io_uring zcrx path: + + io_uring_register(IORING_REGISTER_ZCRX_IFQ) /* CAP_NET_ADMIN */ + -> __io_uring_register + -> io_register_zcrx + -> zcrx_register_netdev + -> netif_mp_open_rxq + -> driver ndo_queue_mem_alloc + -> page_pool_create_percpu + -> page_pool_init succeeds (mp_ops->init runs, branch++) + -> page_pool_list fails (xa_alloc_cyclic -ENOMEM) + -> goto err_uninit <-- leak + +The same shape applies to the devmem dmabuf provider via +mp_dmabuf_devmem_init()/mp_dmabuf_devmem_destroy(). + +Restore the cleanup symmetry by moving the mp_ops->destroy() and +static_branch_dec() calls out of __page_pool_destroy() and into +page_pool_uninit(), so page_pool_uninit() is again the strict +inverse of page_pool_init(). page_pool_uninit() has only two +callers (the err_uninit: path and __page_pool_destroy()), so this +preserves the single-call invariant on the success path while +fixing the err path. The error path of page_pool_init() itself +still skips the mp_ops cleanup correctly: mp_ops->init is the +last action that takes a reference before page_pool_init() returns +0, so when it returns an error neither the refcount nor the static +branch has been touched. + +Triggering the bug requires xa_alloc_cyclic() to fail with -ENOMEM, +which under normal GFP_KERNEL retry behaviour is rare. It is +deterministic under CONFIG_FAULT_INJECTION with fail_page_alloc / +xa fault injection, or under sustained memory pressure. The leak +is silent: there is no warning, and the released kernel build +continues running with a permanently-incremented static branch. + +Fixes: 0f9214046893 ("memory-provider: dmabuf devmem memory provider") +Signed-off-by: Hasan Basbunar +Link: https://patch.msgid.link/20260428170739.34881-1-basbunarhasan@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/page_pool.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/core/page_pool.c b/net/core/page_pool.c +index 1a5edec485f14..b775b6305fb78 100644 +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -323,6 +323,11 @@ static void page_pool_uninit(struct page_pool *pool) + if (!pool->system) + free_percpu(pool->recycle_stats); + #endif ++ ++ if (pool->mp_ops) { ++ pool->mp_ops->destroy(pool); ++ static_branch_dec(&page_pool_mem_providers); ++ } + } + + /** +@@ -1122,11 +1127,6 @@ static void __page_pool_destroy(struct page_pool *pool) + page_pool_unlist(pool); + page_pool_uninit(pool); + +- if (pool->mp_ops) { +- pool->mp_ops->destroy(pool); +- static_branch_dec(&page_pool_mem_providers); +- } +- + kfree(pool); + } + +-- +2.53.0 + diff --git a/queue-6.18/params-replace-__modinit-with-__init_or_module.patch b/queue-6.18/params-replace-__modinit-with-__init_or_module.patch new file mode 100644 index 0000000000..a9ff17809e --- /dev/null +++ b/queue-6.18/params-replace-__modinit-with-__init_or_module.patch @@ -0,0 +1,67 @@ +From f77dcefee4f79f31f70f2428fc1d3dc3016a9770 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Aug 2025 14:12:09 +0200 +Subject: params: Replace __modinit with __init_or_module + +From: Petr Pavlu + +[ Upstream commit 3cb0c3bdea5388519bc1bf575dca6421b133302b ] + +Remove the custom __modinit macro from kernel/params.c and instead use the +common __init_or_module macro from include/linux/module.h. Both provide the +same functionality. + +Signed-off-by: Petr Pavlu +Reviewed-by: Aaron Tomlin +Reviewed-by: Daniel Gomez +Reviewed-by: Sami Tolvanen +Signed-off-by: Sami Tolvanen +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + kernel/params.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +diff --git a/kernel/params.c b/kernel/params.c +index b96cfd693c996..7c2242f64bf08 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -596,12 +596,6 @@ static ssize_t param_attr_store(const struct module_attribute *mattr, + } + #endif + +-#ifdef CONFIG_MODULES +-#define __modinit +-#else +-#define __modinit __init +-#endif +- + #ifdef CONFIG_SYSFS + void kernel_param_lock(struct module *mod) + { +@@ -626,9 +620,9 @@ EXPORT_SYMBOL(kernel_param_unlock); + * create file in sysfs. Returns an error on out of memory. Always cleans up + * if there's an error. + */ +-static __modinit int add_sysfs_param(struct module_kobject *mk, +- const struct kernel_param *kp, +- const char *name) ++static __init_or_module int add_sysfs_param(struct module_kobject *mk, ++ const struct kernel_param *kp, ++ const char *name) + { + struct module_param_attrs *new_mp; + struct attribute **new_attrs; +@@ -761,7 +755,8 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) ++struct module_kobject * __init_or_module ++lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +-- +2.53.0 + diff --git a/queue-6.18/pci-dpc-log-aer-error-info-for-dpc-edr-uncorrectable.patch b/queue-6.18/pci-dpc-log-aer-error-info-for-dpc-edr-uncorrectable.patch new file mode 100644 index 0000000000..30010482f2 --- /dev/null +++ b/queue-6.18/pci-dpc-log-aer-error-info-for-dpc-edr-uncorrectable.patch @@ -0,0 +1,51 @@ +From aa233cd20a37993d9a6a79ea5d6900c932bcaded Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:04:49 -0700 +Subject: PCI/DPC: Log AER error info for DPC/EDR uncorrectable errors + +From: Kuppuswamy Sathyanarayanan + +[ Upstream commit 97970e7c694356e3386a10e3b936d61eafd06bce ] + +aer_print_error() skips printing if ratelimit_print[i] is not set. In the +native AER path, ratelimit_print is initialized by add_error_device() +during source device discovery, and is set to 1 for fatal errors to bypass +rate limiting since fatal errors should always be logged. + +The DPC/EDR path uses the DPC-capable port as the error source and reads +its AER uncorrectable error status registers directly in +dpc_get_aer_uncorrect_severity(). Since it does not go through +add_error_device(), ratelimit_print[0] is left uninitialized and zero. As +a result, aer_print_error() silently drops all AER error messages for +DPC/EDR triggered events. + +Set ratelimit_print[0] to 1 to bypass rate limiting and always print AER +logs for uncorrectable errors detected by the DPC port. + +Fixes: a57f2bfb4a58 ("PCI/AER: Ratelimit correctable and non-fatal error logging") +Co-developed-by: Goudar Manjunath Ramanagouda +Signed-off-by: Goudar Manjunath Ramanagouda +Signed-off-by: Kuppuswamy Sathyanarayanan +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260318170449.2733581-1-sathyanarayanan.kuppuswamy@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/dpc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c +index fc18349614d7c..7605ddd9f0ba8 100644 +--- a/drivers/pci/pcie/dpc.c ++++ b/drivers/pci/pcie/dpc.c +@@ -256,6 +256,7 @@ static int dpc_get_aer_uncorrect_severity(struct pci_dev *dev, + + info->dev[0] = dev; + info->error_dev_num = 1; ++ info->ratelimit_print[0] = 1; + + return 1; + } +-- +2.53.0 + diff --git a/queue-6.18/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch b/queue-6.18/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch new file mode 100644 index 0000000000..155ab8bb35 --- /dev/null +++ b/queue-6.18/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch @@ -0,0 +1,63 @@ +From 6a7de488e591391a706b9c43858c4c07866e9f2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:53 +0530 +Subject: PCI: dwc: Apply ECRC workaround to DesignWare 5.00a as well + +From: Manikanta Maddireddy + +[ Upstream commit 40805f32dceadebb7381d911003100bec7b8cd51 ] + +The ECRC (TLP digest) workaround was originally added for DesignWare +version 4.90a. Tegra234 SoC has 5.00a DWC HW version, which has the same +ATU TD override behaviour, so apply the workaround for 5.00a too. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-13-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c +index 345365ea97c74..2c1dd6ffa27db 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.c ++++ b/drivers/pci/controller/dwc/pcie-designware.c +@@ -486,13 +486,13 @@ static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg + static inline u32 dw_pcie_enable_ecrc(u32 val) + { + /* +- * DesignWare core version 4.90A has a design issue where the 'TD' +- * bit in the Control register-1 of the ATU outbound region acts +- * like an override for the ECRC setting, i.e., the presence of TLP +- * Digest (ECRC) in the outgoing TLPs is solely determined by this +- * bit. This is contrary to the PCIe spec which says that the +- * enablement of the ECRC is solely determined by the AER +- * registers. ++ * DWC versions 0x3530302a and 0x3536322a have a design issue where ++ * the 'TD' bit in the Control register-1 of the ATU outbound ++ * region acts like an override for the ECRC setting, i.e., the ++ * presence of TLP Digest (ECRC) in the outgoing TLPs is solely ++ * determined by this bit. This is contrary to the PCIe spec which ++ * says that the enablement of the ECRC is solely determined by the ++ * AER registers. + * + * Because of this, even when the ECRC is enabled through AER + * registers, the transactions going through ATU won't have TLP +@@ -559,7 +559,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, + if (upper_32_bits(limit_addr) > upper_32_bits(parent_bus_addr) && + dw_pcie_ver_is_ge(pci, 460A)) + val |= PCIE_ATU_INCREASE_REGION_SIZE; +- if (dw_pcie_ver_is(pci, 490A)) ++ if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A)) + val = dw_pcie_enable_ecrc(val); + dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val); + +-- +2.53.0 + diff --git a/queue-6.18/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch b/queue-6.18/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch new file mode 100644 index 0000000000..68100bbf25 --- /dev/null +++ b/queue-6.18/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch @@ -0,0 +1,47 @@ +From bf69ae635b4480c36d54137ca4f76ffdb2f88f79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 14:08:16 +0530 +Subject: PCI: dwc: ep: Fix MSI-X Table Size configuration in + dw_pcie_ep_set_msix() + +From: Aksh Garg + +[ Upstream commit 271d0b1f058ae9815e75233d04b23e3558c3e4f4 ] + +In dw_pcie_ep_set_msix(), while updating the MSI-X Table Size value for +individual functions, Message Control register is read from the passed +function number register space using dw_pcie_ep_readw_dbi(), but always +written back to the Function 0's register space using dw_pcie_writew_dbi(). +This causes incorrect MSI-X configuration for the rest of the functions, +other than Function 0. + +Fix this by using dw_pcie_ep_writew_dbi() to write to the correct +function's register space, matching the read operation. + +Fixes: 70fa02ca1446 ("PCI: dwc: Add dw_pcie_ep_{read,write}_dbi[2] helpers") +Signed-off-by: Aksh Garg +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260224083817.916782-2-a-garg7@ti.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index e2e18beb2951d..7350a703c4d19 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -538,7 +538,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + val = dw_pcie_ep_readw_dbi(ep, func_no, reg); + val &= ~PCI_MSIX_FLAGS_QSIZE; + val |= nr_irqs - 1; /* encoded as N-1 */ +- dw_pcie_writew_dbi(pci, reg, val); ++ dw_pcie_ep_writew_dbi(ep, func_no, reg, val); + + reg = ep_func->msix_cap + PCI_MSIX_TABLE; + val = offset | bir; +-- +2.53.0 + diff --git a/queue-6.18/pci-dwc-fix-type-mismatch-for-kstrtou32_from_user-re.patch b/queue-6.18/pci-dwc-fix-type-mismatch-for-kstrtou32_from_user-re.patch new file mode 100644 index 0000000000..46a924f7df --- /dev/null +++ b/queue-6.18/pci-dwc-fix-type-mismatch-for-kstrtou32_from_user-re.patch @@ -0,0 +1,74 @@ +From 852ae29d3f71c67144860680da7b8c2d15d432b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:30:48 +0800 +Subject: PCI: dwc: Fix type mismatch for kstrtou32_from_user() return value + +From: Hans Zhang <18255117159@163.com> + +[ Upstream commit 445588a3b18bb0702d746cb61f7a443639027651 ] + +kstrtou32_from_user() returns int, but the return value was stored in +a u32 variable 'val', risking sign loss. Use a dedicated int variable +to correctly handle the return code. + +Fixes: 4fbfa17f9a07 ("PCI: dwc: Add debugfs based Silicon Debug support for DWC") +Signed-off-by: Hans Zhang <18255117159@163.com> +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260401023048.4182452-1-18255117159@163.com +Signed-off-by: Sasha Levin +--- + .../controller/dwc/pcie-designware-debugfs.c | 21 +++++++++++-------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c +index df98fee69892b..afcc08efe2531 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c ++++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c +@@ -208,10 +208,11 @@ static ssize_t lane_detect_write(struct file *file, const char __user *buf, + struct dw_pcie *pci = file->private_data; + struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info; + u32 lane, val; ++ int ret; + +- val = kstrtou32_from_user(buf, count, 0, &lane); +- if (val) +- return val; ++ ret = kstrtou32_from_user(buf, count, 0, &lane); ++ if (ret) ++ return ret; + + val = dw_pcie_readl_dbi(pci, rinfo->ras_cap_offset + SD_STATUS_L1LANE_REG); + val &= ~(LANE_SELECT); +@@ -347,10 +348,11 @@ static ssize_t counter_enable_write(struct file *file, const char __user *buf, + struct dw_pcie *pci = pdata->pci; + struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info; + u32 val, enable; ++ int ret; + +- val = kstrtou32_from_user(buf, count, 0, &enable); +- if (val) +- return val; ++ ret = kstrtou32_from_user(buf, count, 0, &enable); ++ if (ret) ++ return ret; + + mutex_lock(&rinfo->reg_event_lock); + set_event_number(pdata, pci, rinfo); +@@ -408,10 +410,11 @@ static ssize_t counter_lane_write(struct file *file, const char __user *buf, + struct dw_pcie *pci = pdata->pci; + struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info; + u32 val, lane; ++ int ret; + +- val = kstrtou32_from_user(buf, count, 0, &lane); +- if (val) +- return val; ++ ret = kstrtou32_from_user(buf, count, 0, &lane); ++ if (ret) ++ return ret; + + mutex_lock(&rinfo->reg_event_lock); + set_event_number(pdata, pci, rinfo); +-- +2.53.0 + diff --git a/queue-6.18/pci-dwc-invoke-post_init-in-dw_pcie_resume_noirq.patch b/queue-6.18/pci-dwc-invoke-post_init-in-dw_pcie_resume_noirq.patch new file mode 100644 index 0000000000..1f76616eda --- /dev/null +++ b/queue-6.18/pci-dwc-invoke-post_init-in-dw_pcie_resume_noirq.patch @@ -0,0 +1,46 @@ +From a585549a4d6e2caf9f7c2b3eba1d04e381aeb8b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Oct 2025 11:04:25 +0800 +Subject: PCI: dwc: Invoke post_init in dw_pcie_resume_noirq() + +From: Richard Zhu + +[ Upstream commit c577ce2881f9c76892de5ffc1a122e3ef427ecee ] + +In some SoCs like i.MX95, CLKREQ# is pulled low by the controller driver +before link up. After link up, if the 'supports-clkreq' property is +specified in DT, the driver will release CLKREQ# so that it can go high and +the endpoint can pull it low whenever required i.e., during exit from L1 +Substates. + +Hence, at the end of dw_pcie_resume_noirq(), invoke the '.post_init()' +callback if exists to perform the above mentioned action. + +Signed-off-by: Richard Zhu +[mani: reworded description] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20251015030428.2980427-9-hongxing.zhu@nxp.com +Stable-dep-of: edb5ca3262e2 ("PCI: dwc: Perform cleanup in the error path of dw_pcie_resume_noirq()") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-host.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c +index 894bf23529df5..3fbece96faaad 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -1236,6 +1236,9 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci) + if (ret) + return ret; + ++ if (pci->pp.ops->post_init) ++ pci->pp.ops->post_init(&pci->pp); ++ + return ret; + } + EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); +-- +2.53.0 + diff --git a/queue-6.18/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch b/queue-6.18/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch new file mode 100644 index 0000000000..6d49ca20e3 --- /dev/null +++ b/queue-6.18/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch @@ -0,0 +1,60 @@ +From e47ee32fb46e1f6fdbb739b0f96ed40150ed6809 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 19:09:51 +0530 +Subject: PCI: dwc: Perform cleanup in the error path of dw_pcie_resume_noirq() + +From: Manivannan Sadhasivam + +[ Upstream commit edb5ca3262e2255cf938a5948709d3472d4871ad ] + +If the dw_pcie_resume_noirq() API fails, it just returns the errno without +doing cleanup in the error path, leading to resource leak. + +So perform cleanup in the error path. + +Fixes: 4774faf854f5 ("PCI: dwc: Implement generic suspend/resume functionality") +Reported-by: Senchuan Zhang +Closes: https://lore.kernel.org/linux-pci/78296255.3869.19c8eb694d6.Coremail.zhangsenchuan@eswincomputing.com +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260226133951.296743-1-mani@kernel.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-host.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c +index 3fbece96faaad..48e4a887bb1bb 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -1230,15 +1230,24 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci) + + ret = dw_pcie_start_link(pci); + if (ret) +- return ret; ++ goto err_deinit; + + ret = dw_pcie_wait_for_link(pci); +- if (ret) +- return ret; ++ if (ret == -ETIMEDOUT) ++ goto err_stop_link; + + if (pci->pp.ops->post_init) + pci->pp.ops->post_init(&pci->pp); + ++ return 0; ++ ++err_stop_link: ++ dw_pcie_stop_link(pci); ++ ++err_deinit: ++ if (pci->pp.ops->deinit) ++ pci->pp.ops->deinit(&pci->pp); ++ + return ret; + } + EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); +-- +2.53.0 + diff --git a/queue-6.18/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch b/queue-6.18/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch new file mode 100644 index 0000000000..a17684906d --- /dev/null +++ b/queue-6.18/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch @@ -0,0 +1,48 @@ +From a5347d36e33c19fa72de6480a7e5fdc113fc0e12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 00:10:50 +0900 +Subject: PCI: dwc: rcar-gen4: Change EPC BAR alignment to 4K as per the + documentation + +From: Koichiro Den + +[ Upstream commit 13f55a7ca773c731a1e645934c1ae48577f48785 ] + +R-Car S4 Series (R8A779F[4-7]*) EP controller uses a 4K minimum iATU region +size (CX_ATU_MIN_REGION_SIZE = 4K) as per R19UH0161EJ0130 Rev.1.30. Also, +the controller itself can only be configured in the range 4 KB to 64 KB, so +the current 1 MB alignment requirement is incorrect. + +Hence, change the alignment to the min size 4K as per the documentation. + +This also fixes needless unusability of BAR4 on this platform when the +target address is fixed, such as for doorbell targets. + +Fixes: e311b3834dfa ("PCI: rcar-gen4: Add endpoint mode support") +Signed-off-by: Koichiro Den +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260305151050.1834007-1-den@valinux.co.jp +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c +index 80778917d2ddd..7e171526b1ded 100644 +--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c ++++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c +@@ -425,7 +425,7 @@ static const struct pci_epc_features rcar_gen4_pcie_epc_features = { + .bar[BAR_3] = { .type = BAR_RESERVED, }, + .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256 }, + .bar[BAR_5] = { .type = BAR_RESERVED, }, +- .align = SZ_1M, ++ .align = SZ_4K, + }; + + static const struct pci_epc_features* +-- +2.53.0 + diff --git a/queue-6.18/pci-enable-atomicops-only-if-root-port-supports-them.patch b/queue-6.18/pci-enable-atomicops-only-if-root-port-supports-them.patch new file mode 100644 index 0000000000..24b76ec11b --- /dev/null +++ b/queue-6.18/pci-enable-atomicops-only-if-root-port-supports-them.patch @@ -0,0 +1,110 @@ +From a9063d46ce26a4aacc68fe983310ed6c197d3fae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:09:45 +0200 +Subject: PCI: Enable AtomicOps only if Root Port supports them + +From: Gerd Bayer + +[ Upstream commit 1ae8c4ce157037e266184064a182af9ef9af278b ] + +When inspecting the config space of a Connect-X physical function in an +s390 system after it was initialized by the mlx5_core device driver, we +found the function to be enabled to request AtomicOps despite the Root Port +lacking support for completing them: + + 00:00.1 Ethernet controller: Mellanox Technologies MT2894 Family [ConnectX-6 Lx] + Subsystem: Mellanox Technologies Device 0002 + DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- + AtomicOpsCtl: ReqEn+ + +On s390 and many virtualized guests, the Endpoint is visible but the Root +Port is not. In this case, pci_enable_atomic_ops_to_root() previously +enabled AtomicOps in the Endpoint even though it can't tell whether the +Root Port supports them as a completer. + +Change pci_enable_atomic_ops_to_root() to fail if there's no Root Port or +the Root Port doesn't support AtomicOps. + +Fixes: 430a23689dea ("PCI: Add pci_enable_atomic_ops_to_root()") +Reported-by: Alexander Schmidt +Signed-off-by: Gerd Bayer +[bhelgaas: commit log, check RP first to simplify flow] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260330-fix_pciatops-v7-2-f601818417e8@linux.ibm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 41 ++++++++++++++++++++--------------------- + 1 file changed, 20 insertions(+), 21 deletions(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index a62ed5560c68f..0b6a23405f167 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -3818,8 +3818,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) + */ + int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + { +- struct pci_bus *bus = dev->bus; +- struct pci_dev *bridge; ++ struct pci_dev *root, *bridge; + u32 cap, ctl2; + + /* +@@ -3849,35 +3848,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + return -EINVAL; + } + +- while (bus->parent) { +- bridge = bus->self; ++ root = pcie_find_root_port(dev); ++ if (!root) ++ return -EINVAL; + +- pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap); ++ pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); ++ if ((cap & cap_mask) != cap_mask) ++ return -EINVAL; + ++ bridge = pci_upstream_bridge(dev); ++ while (bridge != root) { + switch (pci_pcie_type(bridge)) { +- /* Ensure switch ports support AtomicOp routing */ + case PCI_EXP_TYPE_UPSTREAM: +- case PCI_EXP_TYPE_DOWNSTREAM: +- if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) +- return -EINVAL; +- break; +- +- /* Ensure root port supports all the sizes we care about */ +- case PCI_EXP_TYPE_ROOT_PORT: +- if ((cap & cap_mask) != cap_mask) +- return -EINVAL; +- break; +- } +- +- /* Ensure upstream ports don't block AtomicOps on egress */ +- if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) { ++ /* Upstream ports must not block AtomicOps on egress */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, + &ctl2); + if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK) + return -EINVAL; ++ fallthrough; ++ ++ /* All switch ports need to route AtomicOps */ ++ case PCI_EXP_TYPE_DOWNSTREAM: ++ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, ++ &cap); ++ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) ++ return -EINVAL; ++ break; + } + +- bus = bus->parent; ++ bridge = pci_upstream_bridge(bridge); + } + + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, +-- +2.53.0 + diff --git a/queue-6.18/pci-endpoint-pci-ep-msi-fix-error-unwind-and-prevent.patch b/queue-6.18/pci-endpoint-pci-ep-msi-fix-error-unwind-and-prevent.patch new file mode 100644 index 0000000000..b385ee5c09 --- /dev/null +++ b/queue-6.18/pci-endpoint-pci-ep-msi-fix-error-unwind-and-prevent.patch @@ -0,0 +1,58 @@ +From cbb42c0d14ddf6e06b3c60b3d6c7511442daf0c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 15:38:56 +0900 +Subject: PCI: endpoint: pci-ep-msi: Fix error unwind and prevent double alloc + +From: Koichiro Den + +[ Upstream commit 1cba96c0a795124c3229293ed7b5b5765e66f259 ] + +pci_epf_alloc_doorbell() stores the allocated doorbell message array in +epf->db_msg/epf->num_db before requesting MSI vectors. If MSI allocation +fails, the array is freed but the EPF state may still point to freed +memory. + +Clear epf->db_msg and epf->num_db on the MSI allocation failure path so +that later cleanup cannot double-free the array and callers can retry +allocation. + +Also return -EBUSY when doorbells have already been allocated to prevent +leaking or overwriting an existing allocation. + +Fixes: 1c3b002c6bf6 ("PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller") +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260217063856.3759713-4-den@valinux.co.jp +Signed-off-by: Sasha Levin +--- + drivers/pci/endpoint/pci-ep-msi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c +index 1b58357b905fa..ad8a81d6ad773 100644 +--- a/drivers/pci/endpoint/pci-ep-msi.c ++++ b/drivers/pci/endpoint/pci-ep-msi.c +@@ -50,6 +50,9 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db) + return -EINVAL; + } + ++ if (epf->db_msg) ++ return -EBUSY; ++ + domain = of_msi_map_get_device_domain(epc->dev.parent, 0, + DOMAIN_BUS_PLATFORM_MSI); + if (!domain) { +@@ -79,6 +82,8 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db) + if (ret) { + dev_err(dev, "Failed to allocate MSI\n"); + kfree(msg); ++ epf->db_msg = NULL; ++ epf->num_db = 0; + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/pci-endpoint-pci-epf-test-don-t-free-doorbell-irq-un.patch b/queue-6.18/pci-endpoint-pci-epf-test-don-t-free-doorbell-irq-un.patch new file mode 100644 index 0000000000..aeb761f53f --- /dev/null +++ b/queue-6.18/pci-endpoint-pci-epf-test-don-t-free-doorbell-irq-un.patch @@ -0,0 +1,77 @@ +From b716dcd10f86e4d79c16ce6eb6aaae6612e63849 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 15:38:55 +0900 +Subject: PCI: endpoint: pci-epf-test: Don't free doorbell IRQ unless requested + +From: Koichiro Den + +[ Upstream commit e81fa70179aac6ac3a6636565d5d35968dca3900 ] + +pci_epf_test_doorbell_cleanup() unconditionally calls free_irq() for the +doorbell virq, which can trigger "Trying to free already-free IRQ" +warnings when the IRQ was never requested or when request_threaded_irq() +failed. + +Move free_irq() out of pci_epf_test_doorbell_cleanup() and invoke it +only after a successful request, so that free_irq() is not called for +an unrequested IRQ. + +Fixes: eff0c286aa91 ("PCI: endpoint: pci-epf-test: Add doorbell test support") +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260217063856.3759713-3-den@valinux.co.jp +Signed-off-by: Sasha Levin +--- + drivers/pci/endpoint/functions/pci-epf-test.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c +index b05e8db575c35..9bc6d283eae25 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-test.c ++++ b/drivers/pci/endpoint/functions/pci-epf-test.c +@@ -704,7 +704,6 @@ static void pci_epf_test_doorbell_cleanup(struct pci_epf_test *epf_test) + struct pci_epf_test_reg *reg = epf_test->reg[epf_test->test_reg_bar]; + struct pci_epf *epf = epf_test->epf; + +- free_irq(epf->db_msg[0].virq, epf_test); + reg->doorbell_bar = cpu_to_le32(NO_BAR); + + pci_epf_free_doorbell(epf); +@@ -748,7 +747,7 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test, + &epf_test->db_bar.phys_addr, &offset); + + if (ret) +- goto err_doorbell_cleanup; ++ goto err_free_irq; + + reg->doorbell_offset = cpu_to_le32(offset); + +@@ -758,12 +757,14 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test, + + ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf_test->db_bar); + if (ret) +- goto err_doorbell_cleanup; ++ goto err_free_irq; + + status |= STATUS_DOORBELL_ENABLE_SUCCESS; + reg->status = cpu_to_le32(status); + return; + ++err_free_irq: ++ free_irq(epf->db_msg[0].virq, epf_test); + err_doorbell_cleanup: + pci_epf_test_doorbell_cleanup(epf_test); + set_status_err: +@@ -783,6 +784,7 @@ static void pci_epf_test_disable_doorbell(struct pci_epf_test *epf_test, + if (bar < BAR_0) + goto set_status_err; + ++ free_irq(epf->db_msg[0].virq, epf_test); + pci_epf_test_doorbell_cleanup(epf_test); + + /* +-- +2.53.0 + diff --git a/queue-6.18/pci-fix-alignment-calculation-for-resource-size-larg.patch b/queue-6.18/pci-fix-alignment-calculation-for-resource-size-larg.patch new file mode 100644 index 0000000000..bd86b488f5 --- /dev/null +++ b/queue-6.18/pci-fix-alignment-calculation-for-resource-size-larg.patch @@ -0,0 +1,59 @@ +From 72adedaf3f565e52c87de087b461c8554be88f6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 18:56:33 +0200 +Subject: PCI: Fix alignment calculation for resource size larger than align +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit 8cb081667377709f4924ab6b3a88a0d7a761fe91 ] + +The commit bc75c8e50711 ("PCI: Rewrite bridge window head alignment +function") did not use if (r_size <= align) check from pbus_size_mem() for +the new head alignment bookkeeping structure (aligns2[]). In some +configurations, this can result in producing a gap into the bridge window +which the resource larger than its alignment cannot fill. + +The old alignment calculation algorithm was removed by the subsequent +commit 3958bf16e2fe ("PCI: Stop over-estimating bridge window size") which +renamed the aligns2[] array leaving only aligns[] array. + +Add the if (r_size <= align) check back to avoid this problem. + +Fixes: bc75c8e50711 ("PCI: Rewrite bridge window head alignment function") +Reported-by: Guenter Roeck +Closes: https://lore.kernel.org/all/b05a6f14-979d-42c9-924c-d8408cb12ae7@roeck-us.net/ +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Tested-by: Xifer +Link: https://patch.msgid.link/20260324165633.4583-11-ilpo.jarvinen@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 29ad8d8718974..522e25d725bad 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1342,7 +1342,14 @@ static void pbus_size_mem(struct pci_bus *bus, unsigned long type, + } + size += max(r_size, align); + +- aligns[order] += align; ++ /* ++ * If resource's size is larger than its alignment, ++ * some configurations result in an unwanted gap in ++ * the head space that the larger resource cannot ++ * fill. ++ */ ++ if (r_size <= align) ++ aligns[order] += align; + if (order > max_order) + max_order = order; + +-- +2.53.0 + diff --git a/queue-6.18/pci-fix-premature-removal-from-realloc_head-list-dur.patch b/queue-6.18/pci-fix-premature-removal-from-realloc_head-list-dur.patch new file mode 100644 index 0000000000..38d1f5ec0e --- /dev/null +++ b/queue-6.18/pci-fix-premature-removal-from-realloc_head-list-dur.patch @@ -0,0 +1,92 @@ +From ce3d09b9152fd4f92694b2941a2619999f1f4466 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:45:50 +0200 +Subject: PCI: Fix premature removal from realloc_head list during resource + assignment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit 1ee4716a5a28eaef81ae1f280d983258bee49623 ] + +reassign_resources_sorted() checks for two things: + +a) Resource assignment failures for mandatory resources by checking if the + resource remains unassigned, which are known to always repeat, and does + not attempt to assign them again. + +b) That resource is not among the ones being processed/assigned at this + stage, leading to skip processing such resources in + reassign_resources_sorted() as well (resource assignment progresses + one PCI hierarchy level at a time). + +The problem here is that a) is checked before b), but b) also implies the +resource is not being assigned yet, making also a) true. As a) only skips +resource assignment but still removes the resource from realloc_head, the +later stages that would need to process the information in realloc_head +cannot obtain the optional size information anymore. This leads to +considering only non-optional part for bridge windows deeper in the PCI +hierarchy. + +This problem has been observed during rescan (add_size is not considered +while attempting assignment for 0000:e2:00.0 indicating the corresponding +entry was removed from realloc_head while processing resource assignments +for 0000:e1): + + pci_bus 0000:e1: scanning bus + ... + pci 0000:e3:01.0: bridge window [mem 0x800000000-0x1000ffffff 64bit pref] to [bus e4] add_size 60c000000 add_align 800000000 + pci 0000:e3:01.0: bridge window [mem 0x00100000-0x000fffff] to [bus e4] add_size 200000 add_align 200000 + pci 0000:e3:02.0: disabling bridge window [mem 0x00000000-0x000fffff 64bit pref] to [bus e5] (unused) + pci 0000:e2:00.0: bridge window [mem 0x800000000-0x1000ffffff 64bit pref] to [bus e3-e5] add_size 60c000000 add_align 800000000 + pci 0000:e2:00.0: bridge window [mem 0x00100000-0x001fffff] to [bus e3-e5] add_size 200000 add_align 200000 + pcieport 0000:e1:02.0: bridge window [io size 0x2000]: can't assign; no space + pcieport 0000:e1:02.0: bridge window [io size 0x2000]: failed to assign + pcieport 0000:e1:02.0: bridge window [io 0x1000-0x2fff]: resource restored + pcieport 0000:e1:02.0: bridge window [io 0x1000-0x2fff]: resource restored + pcieport 0000:e1:02.0: bridge window [io size 0x2000]: can't assign; no space + pcieport 0000:e1:02.0: bridge window [io size 0x2000]: failed to assign + pci 0000:e2:00.0: bridge window [mem 0x28f000000000-0x28f800ffffff 64bit pref]: assigned + +Fixes: 96336ec70264 ("PCI: Perform reset_resource() and build fail list in sync") +Reported-by: Peter Nisbet +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Tested-by: Peter Nisbet +Link: https://patch.msgid.link/20260313084551.1934-1-ilpo.jarvinen@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 3ea6f3e726a8c..29ad8d8718974 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -428,6 +428,10 @@ static void reassign_resources_sorted(struct list_head *realloc_head, + dev = add_res->dev; + idx = pci_resource_num(dev, res); + ++ /* Skip this resource if not found in head list */ ++ if (!res_to_dev_res(head, res)) ++ continue; ++ + /* + * Skip resource that failed the earlier assignment and is + * not optional as it would just fail again. +@@ -436,10 +440,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head, + !pci_resource_is_optional(dev, idx)) + goto out; + +- /* Skip this resource if not found in head list */ +- if (!res_to_dev_res(head, res)) +- continue; +- + res_name = pci_resource_name(dev, idx); + add_size = add_res->add_size; + align = add_res->min_align; +-- +2.53.0 + diff --git a/queue-6.18/pci-imx6-fix-device-node-reference-leak-in-imx_pcie_.patch b/queue-6.18/pci-imx6-fix-device-node-reference-leak-in-imx_pcie_.patch new file mode 100644 index 0000000000..43f24c319e --- /dev/null +++ b/queue-6.18/pci-imx6-fix-device-node-reference-leak-in-imx_pcie_.patch @@ -0,0 +1,54 @@ +From ec71c82c798e30bd5fffc3d38c5bab9473b46a96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 23:42:45 +0800 +Subject: PCI: imx6: Fix device node reference leak in imx_pcie_probe() + +From: Felix Gu + +[ Upstream commit 3b55079d6387805ede687e234d84669aeb0f7e98 ] + +In imx_pcie_probe(), of_parse_phandle() returns the device node pointer +with increased refcount. The pointer reference must be dropped by the +caller when it's no longer needed. However, imx_pcie_probe() doesn't drop +the reference, causing reference leak. + +Fix this by using the __free(device_node) cleanup handler to drop the +reference when the function goes out of scope. + +Fixes: 1df82ec46600 ("PCI: imx: Add workaround for e10728, IMX7d PCIe PLL failure") +Signed-off-by: Felix Gu +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Acked-by: Richard Zhu +Link: https://patch.msgid.link/20260124-pci_imx6-v2-1-acb8d5187683@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pci-imx6.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c +index 3984c16dbec39..9083658a4287f 100644 +--- a/drivers/pci/controller/dwc/pci-imx6.c ++++ b/drivers/pci/controller/dwc/pci-imx6.c +@@ -1619,7 +1619,6 @@ static int imx_pcie_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct dw_pcie *pci; + struct imx_pcie *imx_pcie; +- struct device_node *np; + struct device_node *node = dev->of_node; + int ret, domain; + u16 val; +@@ -1646,7 +1645,8 @@ static int imx_pcie_probe(struct platform_device *pdev) + pci->pp.ops = &imx_pcie_host_dw_pme_ops; + + /* Find the PHY if one is defined, only imx7d uses it */ +- np = of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0); ++ struct device_node *np __free(device_node) = ++ of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0); + if (np) { + struct resource res; + +-- +2.53.0 + diff --git a/queue-6.18/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch b/queue-6.18/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch new file mode 100644 index 0000000000..fd8a2f1dd2 --- /dev/null +++ b/queue-6.18/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch @@ -0,0 +1,55 @@ +From 5289708e421b23c84c069e709ca80f9f38ed01ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 17:35:41 +0800 +Subject: PCI: mediatek-gen3: Prevent leaking IRQ domains when IRQ not found + +From: Chen-Yu Tsai + +[ Upstream commit 5573c44cb3fd01a9f62d569ae9ac870ef5f0e0ba ] + +In mtk_pcie_setup_irq(), the IRQ domains are allocated before the +controller's IRQ is fetched. If the latter fails, the function +directly returns an error, without cleaning up the allocated domains. + +Hence, reverse the order so that the IRQ domains are allocated after the +controller's IRQ is found. + +This was flagged by Sashiko during a review of "[PATCH v6 0/7] PCI: +mediatek-gen3: add power control support". + +Fixes: 814cceebba9b ("PCI: mediatek-gen3: Add INTx support") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Manivannan Sadhasivam +Link: https://sashiko.dev/#/patchset/20260324052002.4072430-1-wenst%40chromium.org +Link: https://patch.msgid.link/20260324093542.18523-1-wenst@chromium.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek-gen3.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c +index 75ddb8bee168f..e45c43ccc84c2 100644 +--- a/drivers/pci/controller/pcie-mediatek-gen3.c ++++ b/drivers/pci/controller/pcie-mediatek-gen3.c +@@ -851,14 +851,14 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie) + struct platform_device *pdev = to_platform_device(dev); + int err; + +- err = mtk_pcie_init_irq_domains(pcie); +- if (err) +- return err; +- + pcie->irq = platform_get_irq(pdev, 0); + if (pcie->irq < 0) + return pcie->irq; + ++ err = mtk_pcie_init_irq_domains(pcie); ++ if (err) ++ return err; ++ + irq_set_chained_handler_and_data(pcie->irq, mtk_pcie_irq_handler, pcie); + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch b/queue-6.18/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch new file mode 100644 index 0000000000..bc53b8f225 --- /dev/null +++ b/queue-6.18/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch @@ -0,0 +1,48 @@ +From 867f35dc0575de22f1725bee7225e218acd8a5dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:38:50 +0800 +Subject: PCI/NPEM: Set LED_HW_PLUGGABLE for hotplug-capable ports + +From: Richard Cheng + +[ Upstream commit 16d021c878dca22532c984668c9e8cf4722d6a49 ] + +NPEM registers LED classdevs on PCI endpoint that may be behind +hotplug-capable ports. During hot-removal, led_classdev_unregister() calls +led_set_brightness(LED_OFF) which leads to a PCI config read to a +disconnected device, which fails and returns -ENODEV (topology details in +msgid.link below): + + leds 0003:01:00.0:enclosure:ok: Setting an LED's brightness failed (-19) + +The LED core already suppresses this for devices with LED_HW_PLUGGABLE set, +but NPEM never sets it. Add the flag since NPEM LEDs are on hot-pluggable +hardware by nature. + +Fixes: 4e893545ef87 ("PCI/NPEM: Add Native PCIe Enclosure Management support") +Signed-off-by: Richard Cheng +Signed-off-by: Bjorn Helgaas +Reviewed-by: Lukas Wunner +Acked-by: Kai-Heng Feng +Link: https://patch.msgid.link/20260402093850.23075-1-icheng@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/npem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/npem.c b/drivers/pci/npem.c +index 97507e0df769b..b5d012edebf35 100644 +--- a/drivers/pci/npem.c ++++ b/drivers/pci/npem.c +@@ -504,7 +504,7 @@ static int pci_npem_set_led_classdev(struct npem *npem, struct npem_led *nled) + led->brightness_get = brightness_get; + led->max_brightness = 1; + led->default_trigger = "none"; +- led->flags = 0; ++ led->flags = LED_HW_PLUGGABLE; + + ret = led_classdev_register(&npem->dev->dev, led); + if (ret) +-- +2.53.0 + diff --git a/queue-6.18/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch b/queue-6.18/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch new file mode 100644 index 0000000000..725742be7b --- /dev/null +++ b/queue-6.18/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch @@ -0,0 +1,104 @@ +From db2f7302d1e69088c9b879862a9cd5939cb63fd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 07:26:34 +0530 +Subject: PCI: qcom: Advertise Hotplug Slot Capability with no Command + Completion support + +From: Krishna Chaitanya Chundru + +[ Upstream commit 33a76fc3c3e61386524479b99f35423bd3d9a895 ] + +Qcom PCIe Root Ports advertise hotplug capability in hardware, but do not +support hotplug command completion. As a result, the hotplug commands +issued by the pciehp driver never gets completion notification, leading to +repeated timeout warnings and multi-second delays during boot and +suspend/resume. + +Commit a54db86ddc153 ("PCI: qcom: Do not advertise hotplug capability for +IPs v2.7.0 and v1.9.0") mistakenly assumed that the Root Ports doesn't +support Hotplug due to timeouts and disabled the Hotplug functionality +altogether. But the Root Ports does support reporting Hotplug events like +DL_Up/Down events. + +So to fix the command completion timeout issues, just set the No Command +Completed Support (NCCS) bit and enable Hotplug in Slot Capability field +back. + +Fixes: a54db86ddc153 ("PCI: qcom: Do not advertise hotplug capability for IPs v2.7.0 and v1.9.0") +Signed-off-by: Krishna Chaitanya Chundru +[mani: renamed function, commit log and added comment] +Signed-off-by: Manivannan Sadhasivam +Tested-by: Konrad Dybcio # Hamoa CRD, tunneled link +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260314-hotplug-v1-1-96ac87d93867@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-qcom.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c +index 789cc0e3c10da..43555ad9e5dcf 100644 +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -341,15 +341,20 @@ static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci) + dw_pcie_dbi_ro_wr_dis(pci); + } + +-static void qcom_pcie_clear_hpc(struct dw_pcie *pci) ++static void qcom_pcie_set_slot_nccs(struct dw_pcie *pci) + { + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 val; + + dw_pcie_dbi_ro_wr_en(pci); + ++ /* ++ * Qcom PCIe Root Ports do not support generating command completion ++ * notifications for the Hot-Plug commands. So set the NCCS field to ++ * avoid waiting for the completions. ++ */ + val = readl(pci->dbi_base + offset + PCI_EXP_SLTCAP); +- val &= ~PCI_EXP_SLTCAP_HPC; ++ val |= PCI_EXP_SLTCAP_NCCS; + writel(val, pci->dbi_base + offset + PCI_EXP_SLTCAP); + + dw_pcie_dbi_ro_wr_dis(pci); +@@ -549,7 +554,7 @@ static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie) + writel(CFG_BRIDGE_SB_INIT, + pci->dbi_base + AXI_MSTR_RESP_COMP_CTRL1); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -629,7 +634,7 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT); + } + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -722,7 +727,7 @@ static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie) + val |= EN; + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -1028,7 +1033,7 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) + writel(WR_NO_SNOOP_OVERRIDE_EN | RD_NO_SNOOP_OVERRIDE_EN, + pcie->parf + PARF_NO_SNOOP_OVERRIDE); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch b/queue-6.18/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch new file mode 100644 index 0000000000..7ceb5a3676 --- /dev/null +++ b/queue-6.18/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch @@ -0,0 +1,108 @@ +From 7f1cfe78848e0522c381c410a3b2219700c54a89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:50 +0530 +Subject: PCI: tegra194: Allow system suspend when the Endpoint link is not up + +From: Vidya Sagar + +[ Upstream commit c76f8eae7d4695b1176c4ea5eb93c17e16a20272 ] + +Host software initiates the L2 sequence. PCIe link is kept in L2 state +during suspend. If Endpoint mode is enabled and the link is up, the +software cannot proceed with suspend. However, when the PCIe Endpoint +driver is probed, but the PCIe link is not up, Tegra can go into suspend +state. So, allow system to suspend in this case. + +Fixes: de2bbf2b71bb ("PCI: tegra194: Don't allow suspend when Tegra PCIe is in EP mode") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-10-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 31 +++++++++++++++++----- + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 7d3ea4309e9bb..f4784945c04bb 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2304,16 +2304,28 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev) + gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0); + } + +-static int tegra_pcie_dw_suspend_late(struct device *dev) ++static int tegra_pcie_dw_suspend(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); +- u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n"); +- return -EPERM; ++ if (pcie->ep_state == EP_STATE_ENABLED) { ++ dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n"); ++ return -EPERM; ++ } ++ ++ disable_irq(pcie->pex_rst_irq); ++ return 0; + } + ++ return 0; ++} ++ ++static int tegra_pcie_dw_suspend_late(struct device *dev) ++{ ++ struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); ++ u32 val; ++ + if (!pcie->link_state) + return 0; + +@@ -2333,6 +2345,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2347,6 +2362,9 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + int ret; + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2379,8 +2397,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev) + u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Suspend is not supported in EP mode"); +- return -ENOTSUPP; ++ enable_irq(pcie->pex_rst_irq); ++ return 0; + } + + if (!pcie->link_state) +@@ -2485,6 +2503,7 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = { + }; + + static const struct dev_pm_ops tegra_pcie_dw_pm_ops = { ++ .suspend = tegra_pcie_dw_suspend, + .suspend_late = tegra_pcie_dw_suspend_late, + .suspend_noirq = tegra_pcie_dw_suspend_noirq, + .resume_noirq = tegra_pcie_dw_resume_noirq, +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-disable-direct-speed-change-for-endpoin.patch b/queue-6.18/pci-tegra194-disable-direct-speed-change-for-endpoin.patch new file mode 100644 index 0000000000..13a9513e86 --- /dev/null +++ b/queue-6.18/pci-tegra194-disable-direct-speed-change-for-endpoin.patch @@ -0,0 +1,52 @@ +From f83a42e52c307050fda18a611b50a31050b9f410 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:48 +0530 +Subject: PCI: tegra194: Disable direct speed change for Endpoint mode + +From: Vidya Sagar + +[ Upstream commit 976f6763f57970388bcd7118931f33f447916927 ] + +Pre-silicon simulation showed the controller operating in Endpoint mode +initiating link speed change after completing Secondary Bus Reset. Ideally, +the Root Port or the Switch Downstream Port should initiate the link speed +change post SBR, not the Endpoint. + +So, as per the hardware team recommendation, disable direct speed change +for the Endpoint mode to prevent it from initiating speed change after the +physical layer link is up at Gen1, leaving speed change ownership with the +host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-8-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 2557217f9df16..698012f2a9465 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1834,6 +1834,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); ++ val &= ~PORT_LOGIC_SPEED_CHANGE; ++ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); ++ + if (pcie->update_fc_fixup) { + val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); + val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-disable-l1.2-capability-of-tegra234-ep.patch b/queue-6.18/pci-tegra194-disable-l1.2-capability-of-tegra234-ep.patch new file mode 100644 index 0000000000..95a7677cd3 --- /dev/null +++ b/queue-6.18/pci-tegra194-disable-l1.2-capability-of-tegra234-ep.patch @@ -0,0 +1,78 @@ +From 425b7802fe6a65b1147fb0e9692b4ae8f4512e03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:54 +0530 +Subject: PCI: tegra194: Disable L1.2 capability of Tegra234 EP + +From: Vidya Sagar + +[ Upstream commit f59df1d9e6bdb6bd7ef65fb5d200900ac40c20ba ] + +When Tegra234 is operating in the Endpoint mode with L1.2 enabled, PCIe +link goes down during L1.2 exit. This is because Tegra234 powers up UPHY +PLL immediately without making sure that the REFCLK is stable. + +This causes UPHY PLL to fail to lock to the correct frequency and leads to +link going down. There is no hardware fix for this, hence do not advertise +the L1.2 capability in the Endpoint mode. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-14-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 257965ada3bd0..c37be61f2b90a 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -234,6 +234,7 @@ struct tegra_pcie_dw_of_data { + bool has_sbr_reset_fix; + bool has_l1ss_exit_fix; + bool has_ltr_req_fix; ++ bool disable_l1_2; + u32 cdm_chk_int_en_bit; + u32 gen4_preset_vec; + u8 n_fts[2]; +@@ -679,6 +680,23 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie) + if (pcie->supports_clkreq) + pci->l1ss_support = true; + ++ /* ++ * Disable L1.2 capability advertisement for Tegra234 Endpoint mode. ++ * Tegra234 has a hardware bug where during L1.2 exit, the UPHY PLL is ++ * powered up immediately without waiting for REFCLK to stabilize. This ++ * causes the PLL to fail to lock to the correct frequency, resulting in ++ * PCIe link loss. Since there is no hardware fix available, we prevent ++ * the Endpoint from advertising L1.2 support by clearing the L1.2 bits ++ * in the L1 PM Substates Capabilities register. This ensures the host ++ * will not attempt to enter L1.2 state with this Endpoint. ++ */ ++ if (pcie->of_data->disable_l1_2 && ++ pcie->of_data->mode == DW_PCIE_EP_TYPE) { ++ val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP); ++ val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2); ++ dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val); ++ } ++ + /* Program L0s and L1 entrance latencies */ + val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); + val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK; +@@ -2443,6 +2461,7 @@ static const struct tegra_pcie_dw_of_data tegra234_pcie_dw_ep_of_data = { + .mode = DW_PCIE_EP_TYPE, + .has_l1ss_exit_fix = true, + .has_ltr_req_fix = true, ++ .disable_l1_2 = true, + .cdm_chk_int_en_bit = BIT(18), + /* Gen4 - 6, 8 and 9 presets enabled */ + .gen4_preset_vec = 0x340, +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-disable-ltssm-after-transition-to-detec.patch b/queue-6.18/pci-tegra194-disable-ltssm-after-transition-to-detec.patch new file mode 100644 index 0000000000..b8f78b2418 --- /dev/null +++ b/queue-6.18/pci-tegra194-disable-ltssm-after-transition-to-detec.patch @@ -0,0 +1,92 @@ +From 5db9534b06fa28c70a7c800e5ee5b5c419c2986f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:44 +0530 +Subject: PCI: tegra194: Disable LTSSM after transition to Detect on surprise + link down + +From: Manikanta Maddireddy + +[ Upstream commit 9fa0c242f8d7acf1b124d4462d18f4023573ac1c ] + +After the link reaches a Detect-related LTSSM state, disable LTSSM so it +does not keep toggling between Polling and Detect. Do this by polling for +the Detect state first, then clearing APPL_CTRL_LTSSM_EN in both +tegra_pcie_dw_pme_turnoff() and pex_ep_event_pex_rst_assert(). + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-4-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 29 ++++++++++++---------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index d2fefd5c8b08f..b3a1161f49daf 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1623,14 +1623,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_PINMUX_PEX_RST; + appl_writel(pcie, data, APPL_PINMUX); + +- /* +- * Some cards do not go to detect state even after de-asserting +- * PERST#. So, de-assert LTSSM to bring link to detect state. +- */ +- data = readl(pcie->appl_base + APPL_CTRL); +- data &= ~APPL_CTRL_LTSSM_EN; +- writel(data, pcie->appl_base + APPL_CTRL); +- + err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1639,6 +1631,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); ++ ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ data = readl(pcie->appl_base + APPL_CTRL); ++ data &= ~APPL_CTRL_LTSSM_EN; ++ writel(data, pcie->appl_base + APPL_CTRL); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1712,11 +1712,6 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (pcie->ep_state == EP_STATE_DISABLED) + return; + +- /* Disable LTSSM */ +- val = appl_readl(pcie, APPL_CTRL); +- val &= ~APPL_CTRL_LTSSM_EN; +- appl_writel(pcie, val, APPL_CTRL); +- + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1727,6 +1722,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (ret) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ val = appl_readl(pcie, APPL_CTRL); ++ val &= ~APPL_CTRL_LTSSM_EN; ++ appl_writel(pcie, val, APPL_CTRL); ++ + reset_control_assert(pcie->core_rst); + + tegra_pcie_disable_phy(pcie); +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch b/queue-6.18/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch new file mode 100644 index 0000000000..4d341ce36c --- /dev/null +++ b/queue-6.18/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch @@ -0,0 +1,52 @@ +From 26d8874d8f3f9451dcd5a73230fe82be15a518ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:46 +0530 +Subject: PCI: tegra194: Disable PERST# IRQ only in Endpoint mode + +From: Manikanta Maddireddy + +[ Upstream commit 40658a31b6e134169c648041efc84944c4c71dcd ] + +The PERST# GPIO interrupt is only registered when the controller is +operating in Endpoint mode. In Root Port mode, the PERST# GPIO is +configured as an output to control downstream devices, and no interrupt is +registered for it. + +Currently, tegra_pcie_dw_stop_link() unconditionally calls disable_irq() +on pex_rst_irq, which causes issues in Root Port mode where this IRQ is +not registered. + +Fix this by only disabling the PERST# IRQ when operating in Endpoint mode, +where the interrupt is actually registered and used to detect PERST# +assertion/deassertion from the host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-6-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 112fd5ea5a0ab..68920c6263a41 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1054,7 +1054,8 @@ static void tegra_pcie_dw_stop_link(struct dw_pcie *pci) + { + struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); + +- disable_irq(pcie->pex_rst_irq); ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ disable_irq(pcie->pex_rst_irq); + } + + static const struct dw_pcie_ops tegra_dw_pcie_ops = { +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch b/queue-6.18/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch new file mode 100644 index 0000000000..54b607c24f --- /dev/null +++ b/queue-6.18/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch @@ -0,0 +1,111 @@ +From 338034cefd4500025993e45c359842e47874600d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:45 +0530 +Subject: PCI: tegra194: Don't force the device into the D0 state before L2 + +From: Vidya Sagar + +[ Upstream commit 71d9f67701e1affc82d18ca88ae798c5361beddf ] + +As per PCIe CEM r6.0, sec 2.3, the PCIe Endpoint device should be in D3cold +to assert WAKE# pin. The previous workaround that forced downstream devices +to D0 before taking the link to L2 cited PCIe r4.0, sec 5.2, "Link State +Power Management"; however, that spec does not explicitly require putting +the device into D0 and only indicates that power removal may be initiated +without transitioning to D3hot. + +Remove the D0 workaround so that Endpoint devices can use wake +functionality (WAKE# from D3). With some Endpoints the link may not enter +L2 when they remain in D3, but the Root Port continues with the usual flow +after PME timeout, so there is no functional issue. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-5-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 41 ---------------------- + 1 file changed, 41 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index b3a1161f49daf..112fd5ea5a0ab 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1287,44 +1287,6 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, + return 0; + } + +-static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) +-{ +- struct dw_pcie_rp *pp = &pcie->pci.pp; +- struct pci_bus *child, *root_port_bus = NULL; +- struct pci_dev *pdev; +- +- /* +- * link doesn't go into L2 state with some of the endpoints with Tegra +- * if they are not in D0 state. So, need to make sure that immediate +- * downstream devices are in D0 state before sending PME_TurnOff to put +- * link into L2 state. +- * This is as per PCI Express Base r4.0 v1.0 September 27-2017, +- * 5.2 Link State Power Management (Page #428). +- */ +- +- list_for_each_entry(child, &pp->bridge->bus->children, node) { +- if (child->parent == pp->bridge->bus) { +- root_port_bus = child; +- break; +- } +- } +- +- if (!root_port_bus) { +- dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); +- return; +- } +- +- /* Bring downstream devices to D0 if they are not already in */ +- list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { +- if (PCI_SLOT(pdev->devfn) == 0) { +- if (pci_set_power_state(pdev, PCI_D0)) +- dev_err(pcie->dev, +- "Failed to transition %s to D0 state\n", +- dev_name(&pdev->dev)); +- } +- } +-} +- + static int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie) + { + pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3"); +@@ -1654,7 +1616,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + + static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) + { +- tegra_pcie_downstream_dev_to_D0(pcie); + dw_pcie_host_deinit(&pcie->pci.pp); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); +@@ -2370,7 +2331,6 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + if (!pcie->link_state) + return 0; + +- tegra_pcie_downstream_dev_to_D0(pcie); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); + +@@ -2444,7 +2404,6 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev) + return; + + debugfs_remove_recursive(pcie->debugfs); +- tegra_pcie_downstream_dev_to_D0(pcie); + + disable_irq(pcie->pci.pp.irq); + if (IS_ENABLED(CONFIG_PCI_MSI)) +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch b/queue-6.18/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch new file mode 100644 index 0000000000..f758eda839 --- /dev/null +++ b/queue-6.18/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch @@ -0,0 +1,79 @@ +From bec2a89066e52932b54fc976f41284870af8735d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:55 +0530 +Subject: PCI: tegra194: Fix CBB timeout caused by DBI access before core + power-on + +From: Manikanta Maddireddy + +[ Upstream commit 34b3eef48d980cd37b876e128bbf314f69fb5d70 ] + +When PERST# is deasserted twice (assert -> deassert -> assert -> deassert), +a CBB (Control Backbone) timeout occurs at DBI register offset 0x8bc +(PCIE_MISC_CONTROL_1_OFF). This happens because pci_epc_deinit_notify() +and dw_pcie_ep_cleanup() are called before reset_control_deassert() powers +on the controller core. + +The call chain that causes the timeout: + + pex_ep_event_pex_rst_deassert() + pci_epc_deinit_notify() + pci_epf_test_epc_deinit() + pci_epf_test_clear_bar() + pci_epc_clear_bar() + dw_pcie_ep_clear_bar() + __dw_pcie_ep_reset_bar() + dw_pcie_dbi_ro_wr_en() <- Accesses 0x8bc DBI register + reset_control_deassert(pcie->core_rst) <- Core powered on HERE + +The DBI registers, including PCIE_MISC_CONTROL_1_OFF (0x8bc), are only +accessible after the controller core is powered on via +reset_control_deassert(pcie->core_rst). Accessing them before this point +results in a CBB timeout because the hardware is not yet operational. + +Fix this by moving pci_epc_deinit_notify() and dw_pcie_ep_cleanup() to +after reset_control_deassert(pcie->core_rst), ensuring the controller is +fully powered on before any DBI register accesses occur. + +Fixes: 40e2125381dc ("PCI: tegra194: Move controller cleanups to pex_ep_event_pex_rst_deassert()") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-15-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index c37be61f2b90a..fdbf440fb3819 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1750,10 +1750,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + goto fail_phy; + } + +- /* Perform cleanup that requires refclk */ +- pci_epc_deinit_notify(pcie->pci.ep.epc); +- dw_pcie_ep_cleanup(&pcie->pci.ep); +- + /* Clear any stale interrupt statuses */ + appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0); + appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0); +@@ -1823,6 +1819,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ /* Perform cleanup that requires refclk and core reset deasserted */ ++ pci_epc_deinit_notify(pcie->pci.ep.epc); ++ dw_pcie_ep_cleanup(&pcie->pci.ep); ++ + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-fix-polling-delay-for-l2-state.patch b/queue-6.18/pci-tegra194-fix-polling-delay-for-l2-state.patch new file mode 100644 index 0000000000..875733bb94 --- /dev/null +++ b/queue-6.18/pci-tegra194-fix-polling-delay-for-l2-state.patch @@ -0,0 +1,59 @@ +From 04fec7ad4d4b8fb415c36c4c2741eb63122f580b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:42 +0530 +Subject: PCI: tegra194: Fix polling delay for L2 state + +From: Vidya Sagar + +[ Upstream commit adaffed907f14f954096555665ad6af2ae724d83 ] + +As per PCIe r7.0, sec 5.3.3.2.1, after sending PME_Turn_Off message, Root +Port should wait for 1-10 msec for PME_TO_Ack message. Currently, driver is +polling for 10 msec with 1 usec delay which is aggressive. Use existing +macro PCIE_PME_TO_L2_TIMEOUT_US to poll for 10 msec with 1 msec delay. +Since this function is used in non-atomic context only, use non-atomic poll +function. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 3934757baa30c..d2d3139e81d36 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -198,8 +198,6 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define PME_ACK_TIMEOUT 10000 +- + #define LTSSM_TIMEOUT 50000 /* 50ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 +@@ -1582,9 +1580,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) + val |= APPL_PM_XMT_TURNOFF_STATE; + appl_writel(pcie, val, APPL_RADM_STATUS); + +- return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val, +- val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, +- 1, PME_ACK_TIMEOUT); ++ return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, ++ val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, ++ PCIE_PME_TO_L2_TIMEOUT_US/10, ++ PCIE_PME_TO_L2_TIMEOUT_US); + } + + static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-free-up-endpoint-resources-during-remov.patch b/queue-6.18/pci-tegra194-free-up-endpoint-resources-during-remov.patch new file mode 100644 index 0000000000..4d21f1286f --- /dev/null +++ b/queue-6.18/pci-tegra194-free-up-endpoint-resources-during-remov.patch @@ -0,0 +1,49 @@ +From 54f8d000db265bd4dd2475bd0a4429b69291098a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:51 +0530 +Subject: PCI: tegra194: Free up Endpoint resources during remove() + +From: Vidya Sagar + +[ Upstream commit 8870f02f7868209eb9bdc5dc53540a6262cf9227 ] + +Free up the resources during remove() that were acquired by the DesignWare +driver for the Endpoint mode during probe(). + +Fixes: bb617cbd8151 ("PCI: tegra194: Clean up the exit path for Endpoint mode") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-11-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index f4784945c04bb..eb6fecf2e6f42 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2285,6 +2285,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) + static void tegra_pcie_dw_remove(struct platform_device *pdev) + { + struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev); ++ struct dw_pcie_ep *ep = &pcie->pci.ep; + + if (pcie->of_data->mode == DW_PCIE_RC_TYPE) { + if (!pcie->link_state) +@@ -2296,6 +2297,7 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev) + } else { + disable_irq(pcie->pex_rst_irq); + pex_ep_event_pex_rst_assert(pcie); ++ dw_pcie_ep_deinit(ep); + } + + pm_runtime_disable(pcie->dev); +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch b/queue-6.18/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch new file mode 100644 index 0000000000..2f7a56fa1c --- /dev/null +++ b/queue-6.18/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch @@ -0,0 +1,106 @@ +From dd5a4110511e4f675f5fcc5c8cb1085c67fcd91d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:43 +0530 +Subject: PCI: tegra194: Increase LTSSM poll time on surprise link down + +From: Manikanta Maddireddy + +[ Upstream commit 74dd8efe4d6cead433162147333af989a568aac7 ] + +On surprise link down, LTSSM state transits from L0 -> Recovery.RcvrLock -> +Recovery.RcvrSpeed -> Gen1 Recovery.RcvrLock -> Detect. Recovery.RcvrLock +and Recovery.RcvrSpeed transit times are 24 ms and 48 ms respectively, so +the total time from L0 to Detect is ~96 ms. Increase the poll timeout to +120 ms to account for this. + +While at it, add LTSSM state defines for Detect-related states and use them +in the poll condition. Use readl_poll_timeout() instead of +readl_poll_timeout_atomic() in tegra_pcie_dw_pme_turnoff() since that path +runs in non-atomic context. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-3-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 36 +++++++++++++--------- + 1 file changed, 21 insertions(+), 15 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index d2d3139e81d36..d2fefd5c8b08f 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -137,7 +137,11 @@ + #define APPL_DEBUG_PM_LINKST_IN_L0 0x11 + #define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) + #define APPL_DEBUG_LTSSM_STATE_SHIFT 3 +-#define LTSSM_STATE_PRE_DETECT 5 ++#define LTSSM_STATE_DETECT_QUIET 0x00 ++#define LTSSM_STATE_DETECT_ACT 0x08 ++#define LTSSM_STATE_PRE_DETECT_QUIET 0x28 ++#define LTSSM_STATE_DETECT_WAIT 0x30 ++#define LTSSM_STATE_L2_IDLE 0xa8 + + #define APPL_RADM_STATUS 0xE4 + #define APPL_PM_XMT_TURNOFF_STATE BIT(0) +@@ -198,7 +202,8 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define LTSSM_TIMEOUT 50000 /* 50ms */ ++#define LTSSM_DELAY_US 10000 /* 10 ms */ ++#define LTSSM_TIMEOUT_US 120000 /* 120 ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 + +@@ -1626,15 +1631,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_CTRL_LTSSM_EN; + writel(data, pcie->appl_base + APPL_CTRL); + +- err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, +- data, +- ((data & +- APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) +- dev_info(pcie->dev, "Link didn't go to detect state\n"); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1714,12 +1718,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + appl_writel(pcie, val, APPL_CTRL); + + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, +- ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (ret) +- dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + + reset_control_assert(pcie->core_rst); + +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-remove-unnecessary-l1ss-disable-code.patch b/queue-6.18/pci-tegra194-remove-unnecessary-l1ss-disable-code.patch new file mode 100644 index 0000000000..b7a2328904 --- /dev/null +++ b/queue-6.18/pci-tegra194-remove-unnecessary-l1ss-disable-code.patch @@ -0,0 +1,140 @@ +From 13b29456f795052588b59a9e747296adb9764e5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Nov 2025 15:42:16 -0600 +Subject: PCI: tegra194: Remove unnecessary L1SS disable code + +From: Bjorn Helgaas + +[ Upstream commit 07c99eac0bc2c1fe962e56d8b5dc5b1152d421bf ] + +The DWC core clears the L1 Substates Supported bits unless the driver sets +the "dw_pcie.l1ss_support" flag. + +The tegra194 init_host_aspm() sets "dw_pcie.l1ss_support" if the platform +has the "supports-clkreq" DT property. If "supports-clkreq" is absent, +"dw_pcie.l1ss_support" is not set, and the DWC core will clear the L1 +Substates Supported bits. + +The tegra194 code to clear the L1 Substates Supported bits is unnecessary, +so remove it. + +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251118214312.2598220-3-helgaas@kernel.org +Stable-dep-of: f59df1d9e6bd ("PCI: tegra194: Disable L1.2 capability of Tegra234 EP") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 45 +++------------------- + 1 file changed, 5 insertions(+), 40 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index f740e0afafa94..257965ada3bd0 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -263,7 +263,6 @@ struct tegra_pcie_dw { + u32 msi_ctrl_int; + u32 num_lanes; + u32 cid; +- u32 cfg_link_cap_l1sub; + u32 ras_des_cap; + u32 pcie_cap_base; + u32 aspm_cmrt; +@@ -478,8 +477,7 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg) + return IRQ_HANDLED; + + /* If EP doesn't advertise L1SS, just return */ +- val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub); +- if (!(val & (PCI_L1SS_CAP_ASPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_2))) ++ if (!pci->l1ss_support) + return IRQ_HANDLED; + + /* Check if BME is set to '1' */ +@@ -602,24 +600,6 @@ static struct pci_ops tegra_pci_ops = { + }; + + #if defined(CONFIG_PCIEASPM) +-static void disable_aspm_l11(struct tegra_pcie_dw *pcie) +-{ +- u32 val; +- +- val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub); +- val &= ~PCI_L1SS_CAP_ASPM_L1_1; +- dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val); +-} +- +-static void disable_aspm_l12(struct tegra_pcie_dw *pcie) +-{ +- u32 val; +- +- val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub); +- val &= ~PCI_L1SS_CAP_ASPM_L1_2; +- dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val); +-} +- + static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event) + { + u32 val; +@@ -676,10 +656,9 @@ static int aspm_state_cnt(struct seq_file *s, void *data) + static void init_host_aspm(struct tegra_pcie_dw *pcie) + { + struct dw_pcie *pci = &pcie->pci; +- u32 val; ++ u32 l1ss, val; + +- val = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS); +- pcie->cfg_link_cap_l1sub = val + PCI_L1SS_CAP; ++ l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS); + + pcie->ras_des_cap = dw_pcie_find_ext_capability(&pcie->pci, + PCI_EXT_CAP_ID_VNDR); +@@ -691,11 +670,11 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie) + PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val); + + /* Program T_cmrt and T_pwr_on values */ +- val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub); ++ val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP); + val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE); + val |= (pcie->aspm_cmrt << 8); + val |= (pcie->aspm_pwr_on_t << 19); +- dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val); ++ dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val); + + if (pcie->supports_clkreq) + pci->l1ss_support = true; +@@ -723,8 +702,6 @@ static void init_debugfs(struct tegra_pcie_dw *pcie) + aspm_state_cnt); + } + #else +-static inline void disable_aspm_l12(struct tegra_pcie_dw *pcie) { return; } +-static inline void disable_aspm_l11(struct tegra_pcie_dw *pcie) { return; } + static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; } + static inline void init_debugfs(struct tegra_pcie_dw *pcie) { return; } + #endif +@@ -928,12 +905,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp) + + init_host_aspm(pcie); + +- /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ +- if (!pcie->supports_clkreq) { +- disable_aspm_l11(pcie); +- disable_aspm_l12(pcie); +- } +- + if (!pcie->of_data->has_l1ss_exit_fix) { + val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); + val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; +@@ -1848,12 +1819,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + init_host_aspm(pcie); + +- /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ +- if (!pcie->supports_clkreq) { +- disable_aspm_l11(pcie); +- disable_aspm_l12(pcie); +- } +- + if (!pcie->of_data->has_l1ss_exit_fix) { + val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); + val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch b/queue-6.18/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch new file mode 100644 index 0000000000..cd40ec89e6 --- /dev/null +++ b/queue-6.18/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch @@ -0,0 +1,71 @@ +From da49a851ceab233286c691d2b4fe3e3251a840ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:49 +0530 +Subject: PCI: tegra194: Set LTR message request before PCIe link up in + Endpoint mode + +From: Vidya Sagar + +[ Upstream commit b256493bf8cacf0e524bf4c10b5c4901d0c6cefe ] + +LTR message should be sent as soon as the Root Port enables LTR in the +Endpoint mode. So set snoop and no-snoop LTR timing and LTR message request +before the PCIe link comes up, so that the LTR message is sent upstream as +soon as LTR is enabled. + +Without programming these values, the Endpoint would send latencies of 0 to +the host, which will be inaccurate. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Jon Hunter +Tested-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-9-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 698012f2a9465..7d3ea4309e9bb 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -487,15 +487,6 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg) + if (val & PCI_COMMAND_MASTER) { + ktime_t timeout; + +- /* 110us for both snoop and no-snoop */ +- val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) | +- FIELD_PREP(PCI_LTR_SCALE_MASK, 2) | +- LTR_MSG_REQ | +- FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) | +- FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) | +- LTR_NOSNOOP_MSG_REQ; +- appl_writel(pcie, val, APPL_LTR_MSG_1); +- + /* Send LTR upstream */ + val = appl_readl(pcie, APPL_LTR_MSG_2); + val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE; +@@ -1832,6 +1823,15 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + val |= APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN; + appl_writel(pcie, val, APPL_INTR_EN_L1_0_0); + ++ /* 110us for both snoop and no-snoop */ ++ val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) | ++ FIELD_PREP(PCI_LTR_SCALE_MASK, 2) | ++ LTR_MSG_REQ | ++ FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) | ++ FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) | ++ LTR_NOSNOOP_MSG_REQ; ++ appl_writel(pcie, val, APPL_LTR_MSG_1); ++ + reset_control_deassert(pcie->core_rst); + + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch b/queue-6.18/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch new file mode 100644 index 0000000000..841ff51578 --- /dev/null +++ b/queue-6.18/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch @@ -0,0 +1,47 @@ +From b013166d358de9ef9ee7b977337c0e2cf20ca668 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:47 +0530 +Subject: PCI: tegra194: Use devm_gpiod_get_optional() to parse + "nvidia,refclk-select" + +From: Vidya Sagar + +[ Upstream commit f62bc7917de1374dce86a852ffba8baf9cb7a56a ] + +The GPIO DT property "nvidia,refclk-select", to select the PCIe reference +clock is optional. Use devm_gpiod_get_optional() to get it. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-7-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 68920c6263a41..2557217f9df16 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1196,9 +1196,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) + return err; + } + +- pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, +- "nvidia,refclk-select", +- GPIOD_OUT_HIGH); ++ pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev, ++ "nvidia,refclk-select", ++ GPIOD_OUT_HIGH); + if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { + int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); + const char *level = KERN_ERR; +-- +2.53.0 + diff --git a/queue-6.18/pci-tegra194-use-dwc-ip-core-version.patch b/queue-6.18/pci-tegra194-use-dwc-ip-core-version.patch new file mode 100644 index 0000000000..7daa960c88 --- /dev/null +++ b/queue-6.18/pci-tegra194-use-dwc-ip-core-version.patch @@ -0,0 +1,65 @@ +From 26988832134350496d67cca18558f6aff3c3981f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:52 +0530 +Subject: PCI: tegra194: Use DWC IP core version + +From: Manikanta Maddireddy + +[ Upstream commit ea60ca067f0f098043610c96a915d162113c1aac ] + +Tegra194 PCIe driver used custom version numbers to detect Tegra194 and +Tegra234 IPs. With version detect logic added, version check results in +mismatch warnings: + + tegra194-pcie 14100000.pcie: Versions don't match (0000562a != 3536322a) + +Use HW version numbers which match to PORT_LOGIC.PCIE_VERSION_OFF in +Tegra194 driver to avoid these kernel warnings. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-12-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.h | 2 ++ + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index d32ee1fa3cf85..aa27211b68dd1 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -34,8 +34,10 @@ + #define DW_PCIE_VER_470A 0x3437302a + #define DW_PCIE_VER_480A 0x3438302a + #define DW_PCIE_VER_490A 0x3439302a ++#define DW_PCIE_VER_500A 0x3530302a + #define DW_PCIE_VER_520A 0x3532302a + #define DW_PCIE_VER_540A 0x3534302a ++#define DW_PCIE_VER_562A 0x3536322a + + #define __dw_pcie_ver_cmp(_pci, _ver, _op) \ + ((_pci)->version _op DW_PCIE_VER_ ## _ver) +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index eb6fecf2e6f42..f740e0afafa94 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -35,8 +35,8 @@ + #include + #include "../../pci.h" + +-#define TEGRA194_DWC_IP_VER 0x490A +-#define TEGRA234_DWC_IP_VER 0x562A ++#define TEGRA194_DWC_IP_VER DW_PCIE_VER_500A ++#define TEGRA234_DWC_IP_VER DW_PCIE_VER_562A + + #define APPL_PINMUX 0x0 + #define APPL_PINMUX_PEX_RST BIT(0) +-- +2.53.0 + diff --git a/queue-6.18/pci-tph-allow-tph-enable-for-rcieps.patch b/queue-6.18/pci-tph-allow-tph-enable-for-rcieps.patch new file mode 100644 index 0000000000..f5a0c44009 --- /dev/null +++ b/queue-6.18/pci-tph-allow-tph-enable-for-rcieps.patch @@ -0,0 +1,62 @@ +From fe3d30d1d113ae5d05d946929eeeab797a34776b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 10:59:23 +0530 +Subject: PCI/TPH: Allow TPH enable for RCiEPs + +From: George Abraham P + +[ Upstream commit d3e996a596967a62c8a13a279221513461f6ab97 ] + +Previously, pcie_enable_tph() only enabled TLP Processing Hints (TPH) if +both the Endpoint and its Root Port advertised TPH support. + +Root Complex Integrated Endpoints (RCiEPs) are directly integrated into a +Root Complex and do not have an associated Root Port, so pcie_enable_tph() +never enabled TPH for RCiEPs. + +PCIe r7.0 doesn't seem to include a way to learn whether a Root Complex +supports TPH, but sec 2.2.7.1.1 says Functions that lack TPH support should +ignore TPH, and maybe the same is true for Root Complexes: + + A Function that does not support the TPH Completer or Routing capability + and receives a transaction with the TH bit [which indicates the presence + of TPH in the TLP header] Set is required to ignore the TH bit and handle + the Request in the same way as Requests of the same transaction type + without the TH bit Set. + +Allow drivers to enable TPH for any RCiEP with a TPH Requester Capability. + +Fixes: f69767a1ada3 ("PCI: Add TLP Processing Hints (TPH) support") +Signed-off-by: George Abraham P +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260109052923.1170070-1-george.abraham.p@intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/tph.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/tph.c b/drivers/pci/tph.c +index cc64f93709a4f..c61456d24f61b 100644 +--- a/drivers/pci/tph.c ++++ b/drivers/pci/tph.c +@@ -397,10 +397,13 @@ int pcie_enable_tph(struct pci_dev *pdev, int mode) + else + pdev->tph_req_type = PCI_TPH_REQ_TPH_ONLY; + +- rp_req_type = get_rp_completer_type(pdev); ++ /* Check if the device is behind a Root Port */ ++ if (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END) { ++ rp_req_type = get_rp_completer_type(pdev); + +- /* Final req_type is the smallest value of two */ +- pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type); ++ /* Final req_type is the smallest value of two */ ++ pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type); ++ } + + if (pdev->tph_req_type == PCI_TPH_REQ_DISABLE) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.18/pci-use-generic-driver_override-infrastructure.patch b/queue-6.18/pci-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..cc88f9337d --- /dev/null +++ b/queue-6.18/pci-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,209 @@ +From b218cd4351122787abd89a67957878799d53a2b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:09 +0100 +Subject: PCI: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit 10a4206a24013be4d558d476010cbf2eb4c9fa64 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 782a985d7af2 ("PCI: Introduce new device binding path using pci_dev.driver_override") +Acked-by: Bjorn Helgaas +Acked-by: Alex Williamson +Tested-by: Gui-Dong Han +Reviewed-by: Gui-Dong Han +Link: https://patch.msgid.link/20260324005919.2408620-6-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/pci/pci-driver.c | 11 +++++++---- + drivers/pci/pci-sysfs.c | 28 ---------------------------- + drivers/pci/probe.c | 1 - + drivers/vfio/pci/vfio_pci_core.c | 5 ++--- + drivers/xen/xen-pciback/pci_stub.c | 6 ++++-- + include/linux/pci.h | 6 ------ + 6 files changed, 13 insertions(+), 44 deletions(-) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index b4111c92c9572..fba07a700508f 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -138,9 +138,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + { + struct pci_dynid *dynid; + const struct pci_device_id *found_id = NULL, *ids; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (dev->driver_override && strcmp(dev->driver_override, drv->name)) ++ ret = device_match_driver_override(&dev->dev, &drv->driver); ++ if (ret == 0) + return NULL; + + /* Look at the dynamic ids first, before the static ones */ +@@ -164,7 +166,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + * matching. + */ + if (found_id->override_only) { +- if (dev->driver_override) ++ if (ret > 0) + return found_id; + } else { + return found_id; +@@ -172,7 +174,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + } + + /* driver_override will always match, send a dummy id */ +- if (dev->driver_override) ++ if (ret > 0) + return &pci_device_id_any; + return NULL; + } +@@ -423,7 +425,7 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) + static inline bool pci_device_can_probe(struct pci_dev *pdev) + { + return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe || +- pdev->driver_override); ++ device_has_driver_override(&pdev->dev)); + } + #else + static inline bool pci_device_can_probe(struct pci_dev *pdev) +@@ -1695,6 +1697,7 @@ static const struct cpumask *pci_device_irq_get_affinity(struct device *dev, + + const struct bus_type pci_bus_type = { + .name = "pci", ++ .driver_override = true, + .match = pci_bus_match, + .uevent = pci_uevent, + .probe = pci_device_probe, +diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c +index 9d6f74bd95f8c..d36b46849fee2 100644 +--- a/drivers/pci/pci-sysfs.c ++++ b/drivers/pci/pci-sysfs.c +@@ -615,33 +615,6 @@ static ssize_t devspec_show(struct device *dev, + static DEVICE_ATTR_RO(devspec); + #endif + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct pci_dev *pdev = to_pci_dev(dev); +- int ret; +- +- ret = driver_set_override(dev, &pdev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct pci_dev *pdev = to_pci_dev(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", pdev->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *pci_dev_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_resource.attr, +@@ -669,7 +642,6 @@ static struct attribute *pci_dev_attrs[] = { + #ifdef CONFIG_OF + &dev_attr_devspec.attr, + #endif +- &dev_attr_driver_override.attr, + &dev_attr_ari_enabled.attr, + NULL, + }; +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 23833fd7265e2..4e4e38e626912 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2449,7 +2449,6 @@ static void pci_release_dev(struct device *dev) + pci_release_of_node(pci_dev); + pcibios_release_device(pci_dev); + pci_bus_put(pci_dev->bus); +- kfree(pci_dev->driver_override); + bitmap_free(pci_dev->dma_alias_mask); + dev_dbg(dev, "device released\n"); + kfree(pci_dev); +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index 085373d71e9c2..69476fc67ca08 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -2013,9 +2013,8 @@ static int vfio_pci_bus_notifier(struct notifier_block *nb, + pdev->is_virtfn && physfn == vdev->pdev) { + pci_info(vdev->pdev, "Captured SR-IOV VF %s driver_override\n", + pci_name(pdev)); +- pdev->driver_override = kasprintf(GFP_KERNEL, "%s", +- vdev->vdev.ops->name); +- WARN_ON(!pdev->driver_override); ++ WARN_ON(device_set_driver_override(&pdev->dev, ++ vdev->vdev.ops->name)); + } else if (action == BUS_NOTIFY_BOUND_DRIVER && + pdev->is_virtfn && physfn == vdev->pdev) { + struct pci_driver *drv = pci_dev_driver(pdev); +diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c +index 045e74847fe6b..7de2fa67743c6 100644 +--- a/drivers/xen/xen-pciback/pci_stub.c ++++ b/drivers/xen/xen-pciback/pci_stub.c +@@ -598,6 +598,8 @@ static int pcistub_seize(struct pci_dev *dev, + return err; + } + ++static struct pci_driver xen_pcibk_pci_driver; ++ + /* Called when 'bind'. This means we must _NOT_ call pci_reset_function or + * other functions that take the sysfs lock. */ + static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) +@@ -609,8 +611,8 @@ static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) + + match = pcistub_match(dev); + +- if ((dev->driver_override && +- !strcmp(dev->driver_override, PCISTUB_DRIVER_NAME)) || ++ if (device_match_driver_override(&dev->dev, ++ &xen_pcibk_pci_driver.driver) > 0 || + match) { + + if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 05aeee8c8844a..89f5a4290b6e2 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -547,12 +547,6 @@ struct pci_dev { + u8 supported_speeds; /* Supported Link Speeds Vector */ + phys_addr_t rom; /* Physical address if not from BAR */ + size_t romlen; /* Length if not from BAR */ +- /* +- * Driver name to force a match. Do not set directly, because core +- * frees it. Use driver_set_override() to set or clear it. +- */ +- const char *driver_override; +- + unsigned long priv_flags; /* Private flags for the PCI driver */ + + /* These methods index pci_reset_fn_methods[] */ +-- +2.53.0 + diff --git a/queue-6.18/pci-use-res_to_dev_res-in-reassign_resources_sorted.patch b/queue-6.18/pci-use-res_to_dev_res-in-reassign_resources_sorted.patch new file mode 100644 index 0000000000..dcbb83b7a0 --- /dev/null +++ b/queue-6.18/pci-use-res_to_dev_res-in-reassign_resources_sorted.patch @@ -0,0 +1,66 @@ +From b2a8b02cdf69249b5856c43852a9ec0ca9ec1f27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Dec 2025 19:40:21 +0200 +Subject: PCI: Use res_to_dev_res() in reassign_resources_sorted() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit 4bee4fc0f4ee1086e498f9d197352237a0232598 ] + +reassign_resources_sorted() contains a search loop for a particular +resource in the head list. res_to_dev_res() already implements the same +search so use it instead. + +Drop unused found_match and dev_res variables. + +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20251219174036.16738-9-ilpo.jarvinen@linux.intel.com +Stable-dep-of: 1ee4716a5a28 ("PCI: Fix premature removal from realloc_head list during resource assignment") +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index c2d640164f697..3ea6f3e726a8c 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -417,7 +417,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head, + struct list_head *head) + { + struct pci_dev_resource *add_res, *tmp; +- struct pci_dev_resource *dev_res; + struct pci_dev *dev; + struct resource *res; + const char *res_name; +@@ -425,8 +424,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head, + int idx; + + list_for_each_entry_safe(add_res, tmp, realloc_head, list) { +- bool found_match = false; +- + res = add_res->res; + dev = add_res->dev; + idx = pci_resource_num(dev, res); +@@ -440,13 +437,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head, + goto out; + + /* Skip this resource if not found in head list */ +- list_for_each_entry(dev_res, head, list) { +- if (dev_res->res == res) { +- found_match = true; +- break; +- } +- } +- if (!found_match) /* Just skip */ ++ if (!res_to_dev_res(head, res)) + continue; + + res_name = pci_resource_name(dev, idx); +-- +2.53.0 + diff --git a/queue-6.18/pcmcia-fix-garbled-log-messages-for-kern_cont.patch b/queue-6.18/pcmcia-fix-garbled-log-messages-for-kern_cont.patch new file mode 100644 index 0000000000..c337723ebc --- /dev/null +++ b/queue-6.18/pcmcia-fix-garbled-log-messages-for-kern_cont.patch @@ -0,0 +1,55 @@ +From 5a41ccd859d465c1314e63dba7f761d6720c2bca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 17:42:56 +0100 +Subject: PCMCIA: Fix garbled log messages for KERN_CONT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit bfeaa6814bd3f9a1f6d525b3b35a03b9a0368961 ] + +For years the PCMCIA info messages are messed up by superfluous +newlines. While f2e6cf76751d ("pcmcia: Convert dev_printk to +dev_") converted the code to pr_cont(), dev_info enforces a \n +via vprintk_store setting LOG_NEWLINE, breaking subsequent pr_cont. + +Fix by logging the device name manually to allow pr_cont to work for +more readable and not \n distorted logs. + +Fixes: f2e6cf76751d ("pcmcia: Convert dev_printk to dev_") +Signed-off-by: René Rebe +Signed-off-by: Dominik Brodowski +Signed-off-by: Sasha Levin +--- + drivers/pcmcia/rsrc_nonstatic.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c +index da494fe451baf..efc439c748862 100644 +--- a/drivers/pcmcia/rsrc_nonstatic.c ++++ b/drivers/pcmcia/rsrc_nonstatic.c +@@ -188,7 +188,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, + int any; + u_char *b, hole, most; + +- dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1); ++ pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1); + + /* First, what does a floating port look like? */ + b = kzalloc(256, GFP_KERNEL); +@@ -410,8 +410,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + struct socket_data *s_data = s->resource_data; + u_long i, j, bad, fail, step; + +- dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:", +- base, base+num-1); ++ pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:", ++ dev_name(&s->dev), base, base+num-1); + bad = fail = 0; + step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + /* don't allow too large steps */ +-- +2.53.0 + diff --git a/queue-6.18/perf-amd-ibs-avoid-calling-perf_allow_kernel-from-th.patch b/queue-6.18/perf-amd-ibs-avoid-calling-perf_allow_kernel-from-th.patch new file mode 100644 index 0000000000..00685705ce --- /dev/null +++ b/queue-6.18/perf-amd-ibs-avoid-calling-perf_allow_kernel-from-th.patch @@ -0,0 +1,62 @@ +From 4d6ed0c9747c4728667138e3e0416c82f355a704 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:15 +0000 +Subject: perf/amd/ibs: Avoid calling perf_allow_kernel() from the IBS NMI + handler + +From: Ravi Bangoria + +[ Upstream commit b0a09142622a994c4f4088c3f61db5da87cfc711 ] + +Calling perf_allow_kernel() from the NMI context is unsafe and could be +fatal. Capture the permission at event-initialization time by storing it +in event->hw.flags, and have the NMI handler rely on that cached flag +instead of making the call directly. + +Fixes: 50a53b60e141d ("perf/amd/ibs: Prevent leaking sensitive data to userspace") +Reported-by: Sadasivan Shaiju +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-5-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 5 ++++- + arch/x86/events/perf_event_flags.h | 1 + + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 10af127f779fe..56918cd91115c 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -313,6 +313,9 @@ static int perf_ibs_init(struct perf_event *event) + if (ret) + return ret; + ++ if (perf_allow_kernel()) ++ hwc->flags |= PERF_X86_EVENT_UNPRIVILEGED; ++ + if (hwc->sample_period) { + if (config & perf_ibs->cnt_mask) + /* raw max_cnt may not be set */ +@@ -1342,7 +1345,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) + * unprivileged users. + */ + if ((event->attr.sample_type & PERF_SAMPLE_RAW) && +- perf_allow_kernel()) { ++ (hwc->flags & PERF_X86_EVENT_UNPRIVILEGED)) { + perf_ibs_phyaddr_clear(perf_ibs, &ibs_data); + } + +diff --git a/arch/x86/events/perf_event_flags.h b/arch/x86/events/perf_event_flags.h +index 70078334e4a33..47f84ee8f5409 100644 +--- a/arch/x86/events/perf_event_flags.h ++++ b/arch/x86/events/perf_event_flags.h +@@ -23,3 +23,4 @@ PERF_ARCH(PEBS_LAT_HYBRID, 0x0020000) /* ld and st lat for hybrid */ + PERF_ARCH(NEEDS_BRANCH_STACK, 0x0040000) /* require branch stack setup */ + PERF_ARCH(BRANCH_COUNTERS, 0x0080000) /* logs the counters in the extra space of each branch */ + PERF_ARCH(ACR, 0x0100000) /* Auto counter reload */ ++PERF_ARCH(UNPRIVILEGED, 0x0200000) /* Unprivileged event (wrt perf_allow_kernel()) */ +-- +2.53.0 + diff --git a/queue-6.18/perf-amd-ibs-preserve-phyaddrval-bit-when-clearing-p.patch b/queue-6.18/perf-amd-ibs-preserve-phyaddrval-bit-when-clearing-p.patch new file mode 100644 index 0000000000..1f9ffe1ecc --- /dev/null +++ b/queue-6.18/perf-amd-ibs-preserve-phyaddrval-bit-when-clearing-p.patch @@ -0,0 +1,53 @@ +From 93a348270746d8a7b5f9a674ba980e96531dac9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:14 +0000 +Subject: perf/amd/ibs: Preserve PhyAddrVal bit when clearing PhyAddr MSR + +From: Ravi Bangoria + +[ Upstream commit 723a290326e015b07931eabc603d3735999377be ] + +Commit 50a53b60e141 ("perf/amd/ibs: Prevent leaking sensitive data to +userspace") zeroed the physical address and also cleared the PhyAddrVal +flag before copying the value into a perf sample to avoid exposing +physical addresses to unprivileged users. + +Clearing PhyAddrVal, however, has an unintended side-effect: several +other IBS fields are considered valid only when this bit is set. As a +result, those otherwise correct fields are discarded, reducing IBS +functionality. + +Continue to zero the physical address, but keep the PhyAddrVal bit +intact so the related fields remain usable while still preventing any +address leak. + +Fixes: 50a53b60e141 ("perf/amd/ibs: Prevent leaking sensitive data to userspace") +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-4-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 112f43b23ebf8..10af127f779fe 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -1214,12 +1214,10 @@ static void perf_ibs_phyaddr_clear(struct perf_ibs *perf_ibs, + struct perf_ibs_data *ibs_data) + { + if (perf_ibs == &perf_ibs_op) { +- ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSOPDATA3)] &= ~(1ULL << 18); + ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSDCPHYSAD)] = 0; + return; + } + +- ibs_data->regs[ibs_fetch_msr_idx(MSR_AMD64_IBSFETCHCTL)] &= ~(1ULL << 52); + ibs_data->regs[ibs_fetch_msr_idx(MSR_AMD64_IBSFETCHPHYSAD)] = 0; + } + +-- +2.53.0 + diff --git a/queue-6.18/perf-branch-avoid-incrementing-null.patch b/queue-6.18/perf-branch-avoid-incrementing-null.patch new file mode 100644 index 0000000000..609c90e3b8 --- /dev/null +++ b/queue-6.18/perf-branch-avoid-incrementing-null.patch @@ -0,0 +1,39 @@ +From 76b1e0a15c8d462f777041e69cd405f52ed420e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:31:31 -0700 +Subject: perf branch: Avoid incrementing NULL + +From: Ian Rogers + +[ Upstream commit c969a9d7bbf46f983c4a48566b3b2f7340b02296 ] + +If the entry is NULL the value is meaningless so early return NULL to +avoid an increment of NULL. This was happening in calls from +has_stitched_lbr when running the "perf record LBR tests". The return +value isn't used in that case, so returning NULL as no effect. + +Fixes: 42bbabed09ce ("perf tools: Add hw_idx in struct branch_stack") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/branch.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h +index 7429530fa7749..a1d4736497c40 100644 +--- a/tools/perf/util/branch.h ++++ b/tools/perf/util/branch.h +@@ -66,6 +66,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl + { + u64 *entry = (u64 *)sample->branch_stack; + ++ if (entry == NULL) ++ return NULL; ++ + entry++; + if (sample->no_hw_idx) + return (struct branch_entry *)entry; +-- +2.53.0 + diff --git a/queue-6.18/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch b/queue-6.18/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch new file mode 100644 index 0000000000..70c4f90d52 --- /dev/null +++ b/queue-6.18/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch @@ -0,0 +1,94 @@ +From 333ab03a29826341c0b61e6534b5a967ee2eba4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 23:05:52 -0700 +Subject: perf cgroup: Update metric leader in evlist__expand_cgroup + +From: Ian Rogers + +[ Upstream commit c9ef786c0970991578397043f1c819229e2b7197 ] + +When the evlist is expanded the metric leader wasn't being updated. As +the original evsel is deleted this creates a use-after-free in +stat-shadow's prepare_metric. This was detected running the "perf stat +--bpf-counters --for-each-cgroup test" with sanitizers. + +The change itself puts the copied evsel into the priv field (known +unused because of evsel__clone use) and then in a second pass over the +list updates the copied values using the priv pointer. + +Fixes: d1c5a0e86a4e ("perf stat: Add --for-each-cgroup option") +Signed-off-by: Ian Rogers +Acked-by: Sun Jian +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/cgroup.c | 30 +++++++++++++++++++++++------- + 1 file changed, 23 insertions(+), 7 deletions(-) + +diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c +index 25e2769b5e74f..0038d2ac647c4 100644 +--- a/tools/perf/util/cgroup.c ++++ b/tools/perf/util/cgroup.c +@@ -416,7 +416,6 @@ static bool has_pattern_string(const char *str) + int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgroup) + { + struct evlist *orig_list, *tmp_list; +- struct evsel *pos, *evsel, *leader; + struct rblist orig_metric_events; + struct cgroup *cgrp = NULL; + struct cgroup_name *cn; +@@ -451,6 +450,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro + goto out_err; + + list_for_each_entry(cn, &cgroup_list, list) { ++ struct evsel *pos; + char *name; + + if (!cn->used) +@@ -466,21 +466,37 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro + if (cgrp == NULL) + continue; + +- leader = NULL; ++ /* copy the list and set to the new cgroup. */ + evlist__for_each_entry(orig_list, pos) { +- evsel = evsel__clone(/*dest=*/NULL, pos); ++ struct evsel *evsel = evsel__clone(/*dest=*/NULL, pos); ++ + if (evsel == NULL) + goto out_err; + ++ /* stash the copy during the copying. */ ++ pos->priv = evsel; + cgroup__put(evsel->cgrp); + evsel->cgrp = cgroup__get(cgrp); + +- if (evsel__is_group_leader(pos)) +- leader = evsel; +- evsel__set_leader(evsel, leader); +- + evlist__add(tmp_list, evsel); + } ++ /* update leader information using stashed pointer to copy. */ ++ evlist__for_each_entry(orig_list, pos) { ++ struct evsel *evsel = pos->priv; ++ ++ if (evsel__leader(pos)) ++ evsel__set_leader(evsel, evsel__leader(pos)->priv); ++ ++ if (pos->metric_leader) ++ evsel->metric_leader = pos->metric_leader->priv; ++ ++ if (pos->first_wildcard_match) ++ evsel->first_wildcard_match = pos->first_wildcard_match->priv; ++ } ++ /* the stashed copy is no longer used. */ ++ evlist__for_each_entry(orig_list, pos) ++ pos->priv = NULL; ++ + /* cgroup__new() has a refcount, release it here */ + cgroup__put(cgrp); + nr_cgroups++; +-- +2.53.0 + diff --git a/queue-6.18/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch b/queue-6.18/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch new file mode 100644 index 0000000000..b1e8d59b12 --- /dev/null +++ b/queue-6.18/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch @@ -0,0 +1,57 @@ +From 985102ea62e3b6945db484138e84aeb0b6d7a3e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:04:47 +0100 +Subject: perf expr: Return -EINVAL for syntax error in expr__find_ids() + +From: Leo Yan + +[ Upstream commit 3a61fd866ef9aaa1d3158b460f852b74a2df07f4 ] + +expr__find_ids() propagates the parser return value directly. For syntax +errors, the parser can return a positive value, but callers treat it as +success, e.g., for below case on Arm64 platform: + + metric expr 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) for backend_bound + parsing metric: 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) + Failure to read '#slots' literal: #slots = nan + syntax error + +Convert positive parser returns in expr__find_ids() to -EINVAL, as a +result, the error value will be respected by callers. + +Before: + + perf stat -C 5 + Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Segmentation fault + +After: + + perf stat -C 5 + Failure to read '#slots'Cannot find metric or group `Default' + +Fixes: ded80bda8bc9 ("perf expr: Migrate expr ids table to a hashmap") +Signed-off-by: Leo Yan +Reviewed-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/expr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index 7fda0ff89c168..0893c88a4ef83 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -376,7 +376,8 @@ int expr__find_ids(const char *expr, const char *one, + if (one) + expr__del_id(ctx, one); + +- return ret; ++ /* A positive value means syntax error, convert to -EINVAL */ ++ return ret > 0 ? -EINVAL : ret; + } + + double expr_id_data__value(const struct expr_id_data *data) +-- +2.53.0 + diff --git a/queue-6.18/perf-lock-fix-option-value-type-in-parse_max_stack.patch b/queue-6.18/perf-lock-fix-option-value-type-in-parse_max_stack.patch new file mode 100644 index 0000000000..aa66eeff22 --- /dev/null +++ b/queue-6.18/perf-lock-fix-option-value-type-in-parse_max_stack.patch @@ -0,0 +1,38 @@ +From 32186b4e1259c70a52707ce7f6e1a83691e46a1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 16:33:48 -0700 +Subject: perf lock: Fix option value type in parse_max_stack + +From: Ian Rogers + +[ Upstream commit cfaade34b52aa1ec553044255702c4b31b57c005 ] + +The value is a void* and the address of an int, max_stack_depth, is +set up in the perf lock options. The parse_max_stack function treats +the int* as a long*, make this more correct by declaring the value to +be an int*. + +Fixes: 0a277b622670 ("perf lock contention: Check --max-stack option") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-lock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c +index e8962c985d34a..5585aeb97684d 100644 +--- a/tools/perf/builtin-lock.c ++++ b/tools/perf/builtin-lock.c +@@ -2250,7 +2250,7 @@ static int parse_map_entry(const struct option *opt, const char *str, + static int parse_max_stack(const struct option *opt, const char *str, + int unset __maybe_unused) + { +- unsigned long *len = (unsigned long *)opt->value; ++ int *len = opt->value; + long val; + char *endptr; + +-- +2.53.0 + diff --git a/queue-6.18/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch b/queue-6.18/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch new file mode 100644 index 0000000000..7aa601cd23 --- /dev/null +++ b/queue-6.18/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch @@ -0,0 +1,47 @@ +From 3fe1aa3d4c86b26e22f4a8f0008807d248235358 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 19:08:38 -0700 +Subject: perf maps: Fix copy_from that can break sorted by name order + +From: Ian Rogers + +[ Upstream commit f552b132e4d5248715828e7e5c2bf7889bf05b2e ] + +When an parent is copied into a child the name array is populated in +address not name order. Make sure the name array isn't flagged as sorted. + +Fixes: 659ad3492b91 ("perf maps: Switch from rbtree to lazily sorted array for addresses") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/maps.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c +index ff82d1d937b2f..23aa8a95d0454 100644 +--- a/tools/perf/util/maps.c ++++ b/tools/perf/util/maps.c +@@ -1032,16 +1032,9 @@ int maps__copy_from(struct maps *dest, struct maps *parent) + map__put(new); + } + maps__set_maps_by_address_sorted(dest, maps__maps_by_address_sorted(parent)); +- if (!err) { +- RC_CHK_ACCESS(dest)->last_search_by_name_idx = +- RC_CHK_ACCESS(parent)->last_search_by_name_idx; +- maps__set_maps_by_name_sorted(dest, +- dest_maps_by_name && +- maps__maps_by_name_sorted(parent)); +- } else { +- RC_CHK_ACCESS(dest)->last_search_by_name_idx = 0; +- maps__set_maps_by_name_sorted(dest, false); +- } ++ RC_CHK_ACCESS(dest)->last_search_by_name_idx = 0; ++ /* Values were copied into the name array in address order. */ ++ maps__set_maps_by_name_sorted(dest, false); + } else { + /* Unexpected copying to a maps containing entries. */ + for (unsigned int i = 0; !err && i < n; i++) { +-- +2.53.0 + diff --git a/queue-6.18/perf-maps-fix-fixup_overlap_and_insert-that-can-brea.patch b/queue-6.18/perf-maps-fix-fixup_overlap_and_insert-that-can-brea.patch new file mode 100644 index 0000000000..f63483b000 --- /dev/null +++ b/queue-6.18/perf-maps-fix-fixup_overlap_and_insert-that-can-brea.patch @@ -0,0 +1,45 @@ +From 6ea8944e880e21da9b8f7314d2a38a28224fef00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 19:08:37 -0700 +Subject: perf maps: Fix fixup_overlap_and_insert that can break sorted by name + order + +From: Ian Rogers + +[ Upstream commit c4f3ff3289380437d26177e8f2fe4b7507816ee3 ] + +When an entry in the address array is replaced, the corresponding name +entry is replaced. The entries names may sort differently and so it is +important that the sorted by name property be cleared on the maps. + +Fixes: 0d11fab32714 ("perf maps: Fixup maps_by_name when modifying maps_by_address") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/maps.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c +index c51ec159ac769..ff82d1d937b2f 100644 +--- a/tools/perf/util/maps.c ++++ b/tools/perf/util/maps.c +@@ -924,6 +924,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) + if (maps_by_name) { + map__put(maps_by_name[ni]); + maps_by_name[ni] = map__get(new); ++ maps__set_maps_by_name_sorted(maps, false); + } + + err = __maps__insert_sorted(maps, i + 1, after, NULL); +@@ -949,6 +950,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) + if (maps_by_name) { + map__put(maps_by_name[ni]); + maps_by_name[ni] = map__get(new); ++ maps__set_maps_by_name_sorted(maps, false); + } + + check_invariants(maps); +-- +2.53.0 + diff --git a/queue-6.18/perf-stat-fix-opt-value-type-for-parse_cache_level.patch b/queue-6.18/perf-stat-fix-opt-value-type-for-parse_cache_level.patch new file mode 100644 index 0000000000..54cf6d1506 --- /dev/null +++ b/queue-6.18/perf-stat-fix-opt-value-type-for-parse_cache_level.patch @@ -0,0 +1,120 @@ +From 078ee053c72fda70eeba5ea64a9c0ef996da9cf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 16:33:49 -0700 +Subject: perf stat: Fix opt->value type for parse_cache_level + +From: Ian Rogers + +[ Upstream commit 44311ae84ad9177fb311aee856027861c22f17b2 ] + +Commit f5803651b4a4 ("perf stat: Choose the most disaggregate command +line option") changed aggregation option handling for `perf stat` but +not `perf stat report` leading to parse_cache_level being passed a +struct in the `perf stat` case but erroneously an aggr_mode enum value +for `perf stat report`. Change the `perf stat report` aggregation +handling to use the same opt_aggr_mode as `perf stat`. Also, just pass +the boolean for consistency with other boolean argument handling. + +Fixes: f5803651b4a4 ("perf stat: Choose the most disaggregate command line option") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-stat.c | 43 +++++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 20 deletions(-) + +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index b6533dcf5465b..9eb0876633c05 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -153,7 +153,7 @@ struct opt_aggr_mode { + }; + + /* Turn command line option into most generic aggregation mode setting. */ +-static enum aggr_mode opt_aggr_mode_to_aggr_mode(struct opt_aggr_mode *opt_mode) ++static enum aggr_mode opt_aggr_mode_to_aggr_mode(const struct opt_aggr_mode *opt_mode) + { + enum aggr_mode mode = AGGR_GLOBAL; + +@@ -1161,8 +1161,8 @@ static int parse_cache_level(const struct option *opt, + int unset __maybe_unused) + { + int level; +- struct opt_aggr_mode *opt_aggr_mode = (struct opt_aggr_mode *)opt->value; +- u32 *aggr_level = (u32 *)opt->data; ++ bool *per_cache = opt->value; ++ u32 *aggr_level = opt->data; + + /* + * If no string is specified, aggregate based on the topology of +@@ -1200,7 +1200,7 @@ static int parse_cache_level(const struct option *opt, + return -EINVAL; + } + out: +- opt_aggr_mode->cache = true; ++ *per_cache = true; + *aggr_level = level; + return 0; + } +@@ -2262,24 +2262,23 @@ static struct perf_stat perf_stat = { + static int __cmd_report(int argc, const char **argv) + { + struct perf_session *session; ++ struct opt_aggr_mode opt_mode = {}; + const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", "input file name"), +- OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode, +- "aggregate counts per processor socket", AGGR_SOCKET), +- OPT_SET_UINT(0, "per-die", &perf_stat.aggr_mode, +- "aggregate counts per processor die", AGGR_DIE), +- OPT_SET_UINT(0, "per-cluster", &perf_stat.aggr_mode, +- "aggregate counts perf processor cluster", AGGR_CLUSTER), +- OPT_CALLBACK_OPTARG(0, "per-cache", &perf_stat.aggr_mode, &perf_stat.aggr_level, +- "cache level", +- "aggregate count at this cache level (Default: LLC)", ++ OPT_BOOLEAN(0, "per-thread", &opt_mode.thread, "aggregate counts per thread"), ++ OPT_BOOLEAN(0, "per-socket", &opt_mode.socket, ++ "aggregate counts per processor socket"), ++ OPT_BOOLEAN(0, "per-die", &opt_mode.die, "aggregate counts per processor die"), ++ OPT_BOOLEAN(0, "per-cluster", &opt_mode.cluster, ++ "aggregate counts per processor cluster"), ++ OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode.cache, &perf_stat.aggr_level, ++ "cache level", "aggregate count at this cache level (Default: LLC)", + parse_cache_level), +- OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode, +- "aggregate counts per physical processor core", AGGR_CORE), +- OPT_SET_UINT(0, "per-node", &perf_stat.aggr_mode, +- "aggregate counts per numa node", AGGR_NODE), +- OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode, +- "disable CPU count aggregation", AGGR_NONE), ++ OPT_BOOLEAN(0, "per-core", &opt_mode.core, ++ "aggregate counts per physical processor core"), ++ OPT_BOOLEAN(0, "per-node", &opt_mode.node, "aggregate counts per numa node"), ++ OPT_BOOLEAN('A', "no-aggr", &opt_mode.no_aggr, ++ "disable aggregation across CPUs or PMUs"), + OPT_END() + }; + struct stat st; +@@ -2287,6 +2286,10 @@ static int __cmd_report(int argc, const char **argv) + + argc = parse_options(argc, argv, options, stat_report_usage, 0); + ++ perf_stat.aggr_mode = opt_aggr_mode_to_aggr_mode(&opt_mode); ++ if (perf_stat.aggr_mode == AGGR_GLOBAL) ++ perf_stat.aggr_mode = AGGR_UNSET; /* No option found so leave unset. */ ++ + if (!input_name || !strlen(input_name)) { + if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) + input_name = "-"; +@@ -2462,7 +2465,7 @@ int cmd_stat(int argc, const char **argv) + OPT_BOOLEAN(0, "per-die", &opt_mode.die, "aggregate counts per processor die"), + OPT_BOOLEAN(0, "per-cluster", &opt_mode.cluster, + "aggregate counts per processor cluster"), +- OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode, &stat_config.aggr_level, ++ OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode.cache, &stat_config.aggr_level, + "cache level", "aggregate count at this cache level (Default: LLC)", + parse_cache_level), + OPT_BOOLEAN(0, "per-core", &opt_mode.core, +-- +2.53.0 + diff --git a/queue-6.18/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch b/queue-6.18/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch new file mode 100644 index 0000000000..d847edc841 --- /dev/null +++ b/queue-6.18/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch @@ -0,0 +1,115 @@ +From 97d26e34864575669e63803793bb15c021b4dec2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:36:39 +0000 +Subject: perf: tools: cs-etm: Fix print issue for Coresight debug in ETE/TRBE + trace + +From: Mike Leach + +[ Upstream commit 6c478e7b3eba3f387a2d6c749e3e3ee0f8ad1c53 ] + +Building perf with CORESIGHT=1 and the optional CSTRACE_RAW=1 enables +additional debug printing of raw trace data when using command:- +perf report --dump. + +This raw trace prints the CoreSight formatted trace frames, which may be +used to investigate suspected issues with trace quality / corruption / +decode. + +These frames are not present in ETE + TRBE trace. +This fix removes the unnecessary call to print these frames. + +This fix also rationalises implementation - original code had helper +function that unnecessarily repeated initialisation calls that had +already been made. + +Due to an addtional fault with the OpenCSD library, this call when ETE/TRBE +are being decoded will cause a segfault in perf. This fix also prevents +that problem for perf using older (<= 1.8.0 version) OpenCSD libraries. + +Fixes: 68ffe3902898 ("perf tools: Add decoder mechanic to support dumping trace data") +Reported-by: Leo Yan +Signed-off-by: Mike Leach +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 51 +++++-------------- + 1 file changed, 13 insertions(+), 38 deletions(-) + +diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +index b85a8837bddcd..43ac711a4e2ae 100644 +--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c ++++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +@@ -237,46 +237,24 @@ cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, + (void *)decoder, + cs_etm_decoder__print_str_cb); + if (ret != 0) +- ret = -1; +- +- return 0; +-} ++ return -1; + + #ifdef CS_LOG_RAW_FRAMES +-static void +-cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params, +- struct cs_etm_decoder *decoder) +-{ +- /* Only log these during a --dump operation */ +- if (d_params->operation == CS_ETM_OPERATION_PRINT) { +- /* set up a library default logger to process the +- * raw frame printer we add later +- */ +- ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); +- +- /* no stdout / err / file output */ +- ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); +- +- /* set the string CB for the default logger, +- * passes strings to perf print logger. +- */ +- ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, +- (void *)decoder, +- cs_etm_decoder__print_str_cb); +- ++ /* ++ * Only log raw frames if --dump operation and hardware is actually ++ * generating formatted CoreSight trace frames ++ */ ++ if ((d_params->operation == CS_ETM_OPERATION_PRINT) && ++ (d_params->formatted == true)) { + /* use the built in library printer for the raw frames */ +- ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, +- CS_RAW_DEBUG_FLAGS); ++ ret = ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, ++ CS_RAW_DEBUG_FLAGS); ++ if (ret != 0) ++ return -1; + } +-} +-#else +-static void +-cs_etm_decoder__init_raw_frame_logging( +- struct cs_etm_decoder_params *d_params __maybe_unused, +- struct cs_etm_decoder *decoder __maybe_unused) +-{ +-} + #endif ++ return 0; ++} + + static ocsd_datapath_resp_t + cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, +@@ -760,9 +738,6 @@ cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params, + if (ret != 0) + goto err_free_decoder; + +- /* init raw frame logging if required */ +- cs_etm_decoder__init_raw_frame_logging(d_params, decoder); +- + for (i = 0; i < decoders; i++) { + ret = cs_etm_decoder__create_etm_decoder(d_params, + &t_params[i], +-- +2.53.0 + diff --git a/queue-6.18/perf-tools-fix-module-symbol-resolution-for-non-zero.patch b/queue-6.18/perf-tools-fix-module-symbol-resolution-for-non-zero.patch new file mode 100644 index 0000000000..d4e1fa69a4 --- /dev/null +++ b/queue-6.18/perf-tools-fix-module-symbol-resolution-for-non-zero.patch @@ -0,0 +1,77 @@ +From 72bdba23c090314f28cb71c1e40ce1c5c7ef6f23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 11:58:04 -0400 +Subject: perf tools: Fix module symbol resolution for non-zero .text sh_addr + +From: Chuck Lever + +[ Upstream commit 9a82bfde4775b7a87cd1a7e791f46f83ae442848 ] + +When perf resolves symbols from kernel module ELF files (ET_REL), +it converts symbol addresses to file offsets so that sample IPs +can be matched to the correct symbol. The conversion adjusts each +symbol's st_value: + + sym->st_value -= shdr->sh_addr - shdr->sh_offset; + +For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr +is the section's virtual base, so subtracting sh_addr and adding +sh_offset correctly yields a file offset. + +For kernel modules (ET_REL), st_value is a section-relative +offset. The module loader ignores sh_addr entirely and places +symbols at module_base + st_value. Converting to file offset +requires only adding sh_offset; subtracting sh_addr introduces an +error equal to sh_addr bytes. + +When .text has sh_addr == 0 -- the historical norm for simple +modules -- both formulas produce the same result and the bug is +latent. As modules gain more metadata sections before .text (.note, +.static_call.text, etc.), the linker assigns .text a non-zero +sh_addr, exposing the defect. For example, nfsd.ko on this kernel +has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90. + +The effect is that all .text symbols in affected modules +shift by sh_addr bytes relative to sample IPs, causing perf +report to attribute samples to incorrect, nearby symbols. This +was observed as 13% of LLC-load-miss samples misattributed +to nfsd_file_get_dio_attrs when the actual hot function was +nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol +table. + +Use the existing dso__rel() flag (already set for ET_REL modules) +to select the correct adjustment: add sh_offset for ET_REL, +subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN. + +Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules") +Signed-off-by: Chuck Lever +Reviewed-by: Ian Rogers +Tested-by: Thomas Richter +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/symbol-elf.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c +index 9d62386464680..9602cc51dcc65 100644 +--- a/tools/perf/util/symbol-elf.c ++++ b/tools/perf/util/symbol-elf.c +@@ -1353,8 +1353,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, + char dso_name[PATH_MAX]; + + /* Adjust symbol to map to file offset */ +- if (adjust_kernel_syms) +- sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ if (adjust_kernel_syms) { ++ if (dso__rel(dso)) ++ sym->st_value += shdr->sh_offset; ++ else ++ sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ } + + if (strcmp(section_name, (dso__short_name(curr_dso) + dso__short_name_len(dso))) == 0) + return 0; +-- +2.53.0 + diff --git a/queue-6.18/perf-trace-avoid-an-err_ptr-in-syscall_stats.patch b/queue-6.18/perf-trace-avoid-an-err_ptr-in-syscall_stats.patch new file mode 100644 index 0000000000..ec49d2940d --- /dev/null +++ b/queue-6.18/perf-trace-avoid-an-err_ptr-in-syscall_stats.patch @@ -0,0 +1,78 @@ +From baa1181148da63829416830752a2dec307195e4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:45:15 -0800 +Subject: perf trace: Avoid an ERR_PTR in syscall_stats + +From: Ian Rogers + +[ Upstream commit d05073adda0f047e9b2115a2932bcb2797eab238 ] + +hashmap__new may return an ERR_PTR and previously this would be +assigned to syscall_stats meaning all use of syscall_stats needs to +test for NULL (uninitialized) or an ERR_PTR. Given the only reason +hashmap__new can fail is ENOMEM, just use NULL to indicate the +allocation failure and avoid the code having to test for NULL and +IS_ERR. + +Fixes: 96f202eab813 (perf trace: Fix IS_ERR() vs NULL check bug) +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-trace.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c +index 1f0b9ba3cdc15..96efe1fba8547 100644 +--- a/tools/perf/builtin-trace.c ++++ b/tools/perf/builtin-trace.c +@@ -1565,7 +1565,9 @@ static bool syscall_id_equal(long key1, long key2, void *ctx __maybe_unused) + + static struct hashmap *alloc_syscall_stats(void) + { +- return hashmap__new(syscall_id_hash, syscall_id_equal, NULL); ++ struct hashmap *result = hashmap__new(syscall_id_hash, syscall_id_equal, NULL); ++ ++ return IS_ERR(result) ? NULL : result; + } + + static void delete_syscall_stats(struct hashmap *syscall_stats) +@@ -1573,7 +1575,7 @@ static void delete_syscall_stats(struct hashmap *syscall_stats) + struct hashmap_entry *pos; + size_t bkt; + +- if (IS_ERR(syscall_stats)) ++ if (!syscall_stats) + return; + + hashmap__for_each_entry(syscall_stats, pos, bkt) +@@ -1589,7 +1591,7 @@ static struct thread_trace *thread_trace__new(struct trace *trace) + ttrace->files.max = -1; + if (trace->summary) { + ttrace->syscall_stats = alloc_syscall_stats(); +- if (IS_ERR(ttrace->syscall_stats)) ++ if (!ttrace->syscall_stats) + zfree(&ttrace); + } + } +@@ -4441,7 +4443,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) + + if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) { + trace->syscall_stats = alloc_syscall_stats(); +- if (IS_ERR(trace->syscall_stats)) ++ if (!trace->syscall_stats) + goto out_delete_evlist; + } + +@@ -4749,7 +4751,7 @@ static int trace__replay(struct trace *trace) + + if (trace->summary_mode == SUMMARY__BY_TOTAL) { + trace->syscall_stats = alloc_syscall_stats(); +- if (IS_ERR(trace->syscall_stats)) ++ if (!trace->syscall_stats) + goto out; + } + +-- +2.53.0 + diff --git a/queue-6.18/perf-trace-fix-is_err-vs-null-check-bug.patch b/queue-6.18/perf-trace-fix-is_err-vs-null-check-bug.patch new file mode 100644 index 0000000000..2aaecbb8ce --- /dev/null +++ b/queue-6.18/perf-trace-fix-is_err-vs-null-check-bug.patch @@ -0,0 +1,41 @@ +From ec1ae2ba97039e1ae419f4a6939d72d6e502c9dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 20:22:08 +0800 +Subject: perf trace: Fix IS_ERR() vs NULL check bug + +From: wangguangju + +[ Upstream commit 96f202eab8133f94479b14a32902c636e9bdf6af ] + +The alloc_syscall_stats() function always returns an error pointer +(ERR_PTR) on failure. + +So replace NULL check with IS_ERR() check after calling +delete_syscall_stats() function. + +Fixes: ef2da619b132c6f74 ("perf trace: Convert syscall_stats to hashmap") +Signed-off-by: wangguangju +Reviewed-by: Howard Chu +Acked-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-trace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c +index c607f39b8c8bb..1f0b9ba3cdc15 100644 +--- a/tools/perf/builtin-trace.c ++++ b/tools/perf/builtin-trace.c +@@ -1573,7 +1573,7 @@ static void delete_syscall_stats(struct hashmap *syscall_stats) + struct hashmap_entry *pos; + size_t bkt; + +- if (syscall_stats == NULL) ++ if (IS_ERR(syscall_stats)) + return; + + hashmap__for_each_entry(syscall_stats, pos, bkt) +-- +2.53.0 + diff --git a/queue-6.18/perf-util-kill-die-prototype-dead-for-a-long-time.patch b/queue-6.18/perf-util-kill-die-prototype-dead-for-a-long-time.patch new file mode 100644 index 0000000000..d563613878 --- /dev/null +++ b/queue-6.18/perf-util-kill-die-prototype-dead-for-a-long-time.patch @@ -0,0 +1,39 @@ +From 90ed73db0841bcceb3c8950bffb9aca444bfcd92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:31:57 -0300 +Subject: perf util: Kill die() prototype, dead for a long time + +From: Arnaldo Carvalho de Melo + +[ Upstream commit e5cce1b9c82fbd48e2f1f7a25a9fad8ee228176f ] + +In fef2a735167a827a ("perf tools: Kill die()") the die() function was +removed, but not the prototype in util.h, now when building with +LIBPERL=1, during a 'make -C tools/perf build-test' routine test, it is +failing as perl likes die() calls and then this clashes with this +remnant, remove it. + +Fixes: fef2a735167a827a ("perf tools: Kill die()") +Reviewed-by: Ian Rogers +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/util.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h +index 3423778e39a56..523550e7d7ed1 100644 +--- a/tools/perf/util/util.h ++++ b/tools/perf/util/util.h +@@ -29,7 +29,6 @@ extern bool perf_guest; + + /* General helper functions */ + void usage(const char *err) __noreturn; +-void die(const char *err, ...) __noreturn __printf(1, 2); + + struct dirent; + struct strlist; +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-abx500-fix-type-of-argument-variable.patch b/queue-6.18/pinctrl-abx500-fix-type-of-argument-variable.patch new file mode 100644 index 0000000000..b70b6a5f32 --- /dev/null +++ b/queue-6.18/pinctrl-abx500-fix-type-of-argument-variable.patch @@ -0,0 +1,38 @@ +From e84ab2dccaf0830f6b11f962a467581dd72a0d56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 23:15:06 +0800 +Subject: pinctrl: abx500: Fix type of 'argument' variable + +From: Yu-Chun Lin + +[ Upstream commit 34006f77890d050e6d80cbee365b5d703c1140b4 ] + +The argument variable is assigned the return value of +pinconf_to_config_argument(), which returns a u32. Change its type from +enum pin_config_param to unsigned int to correctly store the configuration +argument. + +Fixes: 03b054e9696c ("pinctrl: Pass all configs to driver on pin_config_set()") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/nomadik/pinctrl-abx500.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c +index fc7ebeda8440e..858fbaebcf8e5 100644 +--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c ++++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c +@@ -852,7 +852,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, + int ret = -EINVAL; + int i; + enum pin_config_param param; +- enum pin_config_param argument; ++ unsigned int argument; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch b/queue-6.18/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch new file mode 100644 index 0000000000..18658e3564 --- /dev/null +++ b/queue-6.18/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch @@ -0,0 +1,39 @@ +From d474778ad21815ccb762b87e41519967d438dc29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 17:43:35 +0100 +Subject: pinctrl: cy8c95x0: Avoid returning positive values to user space + +From: Andy Shevchenko + +[ Upstream commit 5ad32c3607cf241a1a2680cabd64cbcd757227aa ] + +When probe fails due to unclear interrupt status register, it returns +a positive number instead of the proper error code. Fix this accordingly. + +Fixes: e6cbbe42944d ("pinctrl: Add Cypress cy8c95x0 support") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202602271847.vVWkqLBD-lkp@intel.com/ +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index 14d927035bc0f..54b117f32f0ea 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1320,7 +1320,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); + if (ret) +- return dev_err_probe(dev, ret, "failed to clear irq status register\n"); ++ return dev_err_probe(dev, -EBUSY, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-cy8c95x0-remove-duplicate-error-message.patch b/queue-6.18/pinctrl-cy8c95x0-remove-duplicate-error-message.patch new file mode 100644 index 0000000000..a2374edf90 --- /dev/null +++ b/queue-6.18/pinctrl-cy8c95x0-remove-duplicate-error-message.patch @@ -0,0 +1,73 @@ +From 75404d45e0be83f7846ef19e591accc0592b8e73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:53 +0100 +Subject: pinctrl: cy8c95x0: remove duplicate error message + +From: Andy Shevchenko + +[ Upstream commit 970dacb3b9f0fedbbbcfd7dbf1f4f22340b3f359 ] + +The pin control core is covered to report any error via message. +The devm_request_threaded_irq() already prints an error message. +Remove the duplicates. + +While at it, drop the info message as the same information about +an IRQ in use can be retrieved differently. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 21 +++++---------------- + 1 file changed, 5 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index 5c055d344ac9d..c0f1d964f8397 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1310,6 +1310,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + { + struct gpio_irq_chip *girq = &chip->gpio_chip.irq; + DECLARE_BITMAP(pending_irqs, MAX_LINE); ++ struct device *dev = chip->dev; + int ret; + + mutex_init(&chip->irq_lock); +@@ -1336,17 +1337,9 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + girq->handler = handle_simple_irq; + girq->threaded = true; + +- ret = devm_request_threaded_irq(chip->dev, irq, +- NULL, cy8c95x0_irq_handler, +- IRQF_ONESHOT | IRQF_SHARED, +- dev_name(chip->dev), chip); +- if (ret) { +- dev_err(chip->dev, "failed to request irq %d\n", irq); +- return ret; +- } +- dev_info(chip->dev, "Registered threaded IRQ\n"); +- +- return 0; ++ return devm_request_threaded_irq(dev, irq, NULL, cy8c95x0_irq_handler, ++ IRQF_ONESHOT | IRQF_SHARED, ++ dev_name(chip->dev), chip); + } + + static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) +@@ -1362,11 +1355,7 @@ static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) + pd->owner = THIS_MODULE; + + chip->pctldev = devm_pinctrl_register(chip->dev, pd, chip); +- if (IS_ERR(chip->pctldev)) +- return dev_err_probe(chip->dev, PTR_ERR(chip->pctldev), +- "can't register controller\n"); +- +- return 0; ++ return PTR_ERR_OR_ZERO(chip->pctldev); + } + + static int cy8c95x0_detect(struct i2c_client *client, +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch b/queue-6.18/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch new file mode 100644 index 0000000000..eff1a03767 --- /dev/null +++ b/queue-6.18/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch @@ -0,0 +1,40 @@ +From 967dd890b58d31b80707160e6e75c6f6c637ab9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:54 +0100 +Subject: pinctrl: cy8c95x0: Unify messages with help of dev_err_probe() + +From: Andy Shevchenko + +[ Upstream commit 014884732095b982412d13d3220c3fe8483b9b3e ] + +Unify error messages that might appear during probe phase by +switching to use dev_err_probe(). + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index c0f1d964f8397..14d927035bc0f 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1319,10 +1319,8 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); +- if (ret) { +- dev_err(chip->dev, "failed to clear irq status register\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-pinconf-generic-fully-validate-pinmux-proper.patch b/queue-6.18/pinctrl-pinconf-generic-fully-validate-pinmux-proper.patch new file mode 100644 index 0000000000..0c4c476e53 --- /dev/null +++ b/queue-6.18/pinctrl-pinconf-generic-fully-validate-pinmux-proper.patch @@ -0,0 +1,49 @@ +From 0ab3c515bff50a9b4af6378b6a1630a434cb84d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 11:36:11 +0100 +Subject: pinctrl: pinconf-generic: Fully validate 'pinmux' property + +From: Andy Shevchenko + +[ Upstream commit c98324ea7849b6e5baa1774f71709b375a2c2f9e ] + +The pinconf_generic_parse_dt_pinmux() assumes that the 'pinmux' property +is not empty when present. This might be not true. With that, the allocator +will give a special value in return and not NULL which lead to the crash +when trying to access that (invalid) memory. Fix that by fully validating +'pinmux' value, including its length. + +Fixes: 7112c05fff83 ("pinctrl: pinconf-generic: Add API for pinmux propertity in DTS file") +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinconf-generic.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c +index cad29abe4050a..8f6a83fdc3844 100644 +--- a/drivers/pinctrl/pinconf-generic.c ++++ b/drivers/pinctrl/pinconf-generic.c +@@ -261,12 +261,17 @@ int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, + return -ENOENT; + } + ++ npins_t = prop->length / sizeof(u32); ++ if (npins_t == 0) { ++ dev_info(dev, "pinmux property doesn't have entries\n"); ++ return -ENODATA; ++ } ++ + if (!pid || !pmux || !npins) { + dev_err(dev, "parameters error\n"); + return -EINVAL; + } + +- npins_t = prop->length / sizeof(u32); + pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL); + pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL); + if (!pid_t || !pmux_t) { +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-pinctrl-pic32-fix-resource-leak.patch b/queue-6.18/pinctrl-pinctrl-pic32-fix-resource-leak.patch new file mode 100644 index 0000000000..e54766f4a4 --- /dev/null +++ b/queue-6.18/pinctrl-pinctrl-pic32-fix-resource-leak.patch @@ -0,0 +1,72 @@ +From 874665ad6722781ccad0c9d04db73d61a4cdad93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:56:23 -0600 +Subject: pinctrl: pinctrl-pic32: Fix resource leak + +From: Ethan Tidmore + +[ Upstream commit fe5560688f3ba98364c7de7b4f8dc240ffd1ff75 ] + +Fix three possible resource leaks by using the devres version of +clk_prepare_enable(). Also, update error message accordingly. + +Detected by Smatch: +drivers/pinctrl/pinctrl-pic32.c:2211 pic32_pinctrl_probe() warn: +'pctl->clk' from clk_prepare_enable() not released on lines: 2208. + +drivers/pinctrl/pinctrl-pic32.c:2274 pic32_gpio_probe() warn: +'bank->clk' from clk_prepare_enable() not released on lines: 2264,2272. + +Fixes: 2ba384e6c3810 ("pinctrl: pinctrl-pic32: Add PIC32 pin control driver") +Signed-off-by: Ethan Tidmore +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-pic32.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c +index e8b481e87c779..506e95793adf3 100644 +--- a/drivers/pinctrl/pinctrl-pic32.c ++++ b/drivers/pinctrl/pinctrl-pic32.c +@@ -2175,16 +2175,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev) + if (IS_ERR(pctl->reg_base)) + return PTR_ERR(pctl->reg_base); + +- pctl->clk = devm_clk_get(&pdev->dev, NULL); ++ pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(pctl->clk)) { + ret = PTR_ERR(pctl->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(pctl->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +@@ -2240,16 +2234,10 @@ static int pic32_gpio_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- bank->clk = devm_clk_get(&pdev->dev, NULL); ++ bank->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bank->clk)) { + ret = PTR_ERR(bank->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(bank->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-realtek-fix-function-signature-for-config-ar.patch b/queue-6.18/pinctrl-realtek-fix-function-signature-for-config-ar.patch new file mode 100644 index 0000000000..bfd843ff36 --- /dev/null +++ b/queue-6.18/pinctrl-realtek-fix-function-signature-for-config-ar.patch @@ -0,0 +1,37 @@ +From 46992e5f23d55e40a9309bcf626c9e6eebdb7689 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 19:54:03 +0800 +Subject: pinctrl: realtek: Fix function signature for config argument + +From: Yu-Chun Lin + +[ Upstream commit 1f5451844786ed203605528dca9e5d84ed378160 ] + +The argument originates from pinconf_to_config_argument(), which returns a +u32. Therefore, the arg parameter should be an unsigned int instead of enum +pin_config_param. + +Fixes: e99ce78030db ("pinctrl: realtek: Add common pinctrl driver for Realtek DHC RTD SoCs") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/realtek/pinctrl-rtd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c +index 2440604863327..4c876d1f6ad59 100644 +--- a/drivers/pinctrl/realtek/pinctrl-rtd.c ++++ b/drivers/pinctrl/realtek/pinctrl-rtd.c +@@ -279,7 +279,7 @@ static const struct rtd_pin_sconfig_desc *rtd_pinctrl_find_sconfig(struct rtd_pi + static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, + unsigned int pinnr, + enum pin_config_param param, +- enum pin_config_param arg) ++ unsigned int arg) + { + const struct rtd_pin_config_desc *config_desc; + const struct rtd_pin_sconfig_desc *sconfig_desc; +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch b/queue-6.18/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch new file mode 100644 index 0000000000..cca5b06235 --- /dev/null +++ b/queue-6.18/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch @@ -0,0 +1,47 @@ +From 1a03a274dbfe20072afd016330efc2c9732a3077 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:24:51 +0000 +Subject: pinctrl: renesas: rzg2l: Fix save/restore of {IOLH,IEN,PUPD,SMT} + registers + +From: Biju Das + +[ Upstream commit d9a60e367919752a1d398ebeba667f1e200fae1e ] + +The rzg2l_pinctrl_pm_setup_regs() handles save/restore of +{IOLH,IEN,PUPD,SMT} registers during s2ram, but only for ports where all +pins share the same pincfg. Extend the code to also support ports with +variable pincfg per pin, so that {IOLH,IEN,PUPD,SMT} registers are +correctly saved and restored for all pins. + +Fixes: 254203f9a94c ("pinctrl: renesas: rzg2l: Add suspend/resume support") +Signed-off-by: Biju Das +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260326162459.101414-1-biju.das.jz@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/renesas/pinctrl-rzg2l.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +index c2711b2de374d..ca360185740a8 100644 +--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c ++++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +@@ -2997,6 +2997,13 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen + off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg); + pincnt = hweight8(FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg)); + ++ if (cfg & RZG2L_VARIABLE_CFG) { ++ unsigned int pin = port * RZG2L_PINS_PER_PORT; ++ ++ for (unsigned int i = 0; i < RZG2L_PINS_PER_PORT; i++) ++ cfg |= *(u64 *)pctrl->desc.pins[pin + i].drv_data; ++ } ++ + caps = FIELD_GET(PIN_CFG_MASK, cfg); + has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)); + has_ien = !!(caps & PIN_CFG_IEN); +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-sophgo-pinctrl-sg2042-fix-wrong-module-descr.patch b/queue-6.18/pinctrl-sophgo-pinctrl-sg2042-fix-wrong-module-descr.patch new file mode 100644 index 0000000000..98fb7eb442 --- /dev/null +++ b/queue-6.18/pinctrl-sophgo-pinctrl-sg2042-fix-wrong-module-descr.patch @@ -0,0 +1,35 @@ +From 62e06eb31ae84b579581fd21f653502c1bcf1d17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:35:49 +0800 +Subject: pinctrl: sophgo: pinctrl-sg2042: Fix wrong module description + +From: Inochi Amaoto + +[ Upstream commit ca1c2ddff00480c213903a1479b56203536e92de ] + +Fix the SoC model in module description string, it should be +sg2042 instead of sg2002. + +Fixes: 1e67465d3b74 ("pinctrl: sophgo: add support for SG2042 SoC") +Signed-off-by: Inochi Amaoto +Reviewed-by: Chen Wang +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/sophgo/pinctrl-sg2042.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042.c b/drivers/pinctrl/sophgo/pinctrl-sg2042.c +index 185305ac897d9..8dba12e122a45 100644 +--- a/drivers/pinctrl/sophgo/pinctrl-sg2042.c ++++ b/drivers/pinctrl/sophgo/pinctrl-sg2042.c +@@ -651,5 +651,5 @@ static struct platform_driver sg2042_pinctrl_driver = { + }; + module_platform_driver(sg2042_pinctrl_driver); + +-MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC"); ++MODULE_DESCRIPTION("Pinctrl driver for the SG2042 series SoC"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.18/pinctrl-sophgo-pinctrl-sg2044-fix-wrong-module-descr.patch b/queue-6.18/pinctrl-sophgo-pinctrl-sg2044-fix-wrong-module-descr.patch new file mode 100644 index 0000000000..7913d163a1 --- /dev/null +++ b/queue-6.18/pinctrl-sophgo-pinctrl-sg2044-fix-wrong-module-descr.patch @@ -0,0 +1,35 @@ +From dd0055385b025516fe555cde772dbc5044348a91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:35:50 +0800 +Subject: pinctrl: sophgo: pinctrl-sg2044: Fix wrong module description + +From: Inochi Amaoto + +[ Upstream commit 7648112358a4207916d3e38bfee49f85552fe95f ] + +Fix the SoC model in module description string, it should be +sg2044 instead of sg2002. + +Fixes: 614a54cb5ac3 ("pinctrl: sophgo: add support for SG2044 SoC") +Signed-off-by: Inochi Amaoto +Reviewed-by: Chen Wang +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/sophgo/pinctrl-sg2044.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2044.c b/drivers/pinctrl/sophgo/pinctrl-sg2044.c +index b0c46d8954ca1..cf0b674c038f0 100644 +--- a/drivers/pinctrl/sophgo/pinctrl-sg2044.c ++++ b/drivers/pinctrl/sophgo/pinctrl-sg2044.c +@@ -714,5 +714,5 @@ static struct platform_driver sg2044_pinctrl_driver = { + }; + module_platform_driver(sg2044_pinctrl_driver); + +-MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC"); ++MODULE_DESCRIPTION("Pinctrl driver for the SG2044 series SoC"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.18/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch b/queue-6.18/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch new file mode 100644 index 0000000000..08135e15fb --- /dev/null +++ b/queue-6.18/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch @@ -0,0 +1,49 @@ +From 0bdd61412ca76aa45ac56860a30d496617050a74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:47:03 +0100 +Subject: platform/chrome: chromeos_tbmc: Drop wakeup source on remove + +From: Rafael J. Wysocki + +[ Upstream commit 5d441a4bc93642ed6f41da87327a39946b4e1455 ] + +The wakeup source added by device_init_wakeup() in chromeos_tbmc_add() +needs to be dropped during driver removal, so add a .remove() callback +to the driver for this purpose. + +Fixes: 0144c00ed86b ("platform/chrome: chromeos_tbmc: Report wake events") +Signed-off-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/6151957.MhkbZ0Pkbq@rafael.j.wysocki +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/chromeos_tbmc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c +index d1cf8f3463ce3..e248567c0a182 100644 +--- a/drivers/platform/chrome/chromeos_tbmc.c ++++ b/drivers/platform/chrome/chromeos_tbmc.c +@@ -95,6 +95,11 @@ static int chromeos_tbmc_add(struct acpi_device *adev) + return 0; + } + ++static void chromeos_tbmc_remove(struct acpi_device *adev) ++{ ++ device_init_wakeup(&adev->dev, false); ++} ++ + static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = { + { ACPI_DRV_NAME, 0 }, + { } +@@ -110,6 +115,7 @@ static struct acpi_driver chromeos_tbmc_driver = { + .ids = chromeos_tbmc_acpi_device_ids, + .ops = { + .add = chromeos_tbmc_add, ++ .remove = chromeos_tbmc_remove, + .notify = chromeos_tbmc_notify, + }, + .drv.pm = &chromeos_tbmc_pm_ops, +-- +2.53.0 + diff --git a/queue-6.18/platform-surface-surfacepro3_button-drop-wakeup-sour.patch b/queue-6.18/platform-surface-surfacepro3_button-drop-wakeup-sour.patch new file mode 100644 index 0000000000..7354e70092 --- /dev/null +++ b/queue-6.18/platform-surface-surfacepro3_button-drop-wakeup-sour.patch @@ -0,0 +1,41 @@ +From 303ef34446ed4511e2fcc5eb212c56d97152b426 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:54:08 +0100 +Subject: platform/surface: surfacepro3_button: Drop wakeup source on remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 1410a228ab2d36fe2b383415a632ae12048d4f3a ] + +The wakeup source added by device_init_wakeup() in surface_button_add() +needs to be dropped during driver removal, so update the driver to do +that. + +Fixes: 19351f340765 ("platform/x86: surfacepro3: Support for wakeup from suspend-to-idle") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/4368848.1IzOArtZ34@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/surface/surfacepro3_button.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979cd..7c7622f8f8716 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -243,6 +243,7 @@ static void surface_button_remove(struct acpi_device *device) + { + struct surface_button *button = acpi_driver_data(device); + ++ device_init_wakeup(&device->dev, false); + input_unregister_device(button->input); + kfree(button); + } +-- +2.53.0 + diff --git a/queue-6.18/platform-wmi-use-generic-driver_override-infrastruct.patch b/queue-6.18/platform-wmi-use-generic-driver_override-infrastruct.patch new file mode 100644 index 0000000000..5052f7b51a --- /dev/null +++ b/queue-6.18/platform-wmi-use-generic-driver_override-infrastruct.patch @@ -0,0 +1,135 @@ +From 9ed2343becb579ae723148901b944718ab1325b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:10 +0100 +Subject: platform/wmi: use generic driver_override infrastructure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Danilo Krummrich + +[ Upstream commit 8a700b1fc94df4d847a04f14ebc7f8532592b367 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 12046f8c77e0 ("platform/x86: wmi: Add driver_override support") +Reviewed-by: Armin Wolf +Acked-by: Ilpo Järvinen +Link: https://patch.msgid.link/20260324005919.2408620-7-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/wmi.c | 36 +++++------------------------------- + include/linux/wmi.h | 4 ---- + 2 files changed, 5 insertions(+), 35 deletions(-) + +diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c +index 4e86a422f05f1..6f8e96476fd07 100644 +--- a/drivers/platform/x86/wmi.c ++++ b/drivers/platform/x86/wmi.c +@@ -702,39 +702,11 @@ static ssize_t expensive_show(struct device *dev, + } + static DEVICE_ATTR_RO(expensive); + +-static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr, +- char *buf) +-{ +- struct wmi_device *wdev = to_wmi_device(dev); +- ssize_t ret; +- +- device_lock(dev); +- ret = sysfs_emit(buf, "%s\n", wdev->driver_override); +- device_unlock(dev); +- +- return ret; +-} +- +-static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct wmi_device *wdev = to_wmi_device(dev); +- int ret; +- +- ret = driver_set_override(dev, &wdev->driver_override, buf, count); +- if (ret < 0) +- return ret; +- +- return count; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *wmi_attrs[] = { + &dev_attr_modalias.attr, + &dev_attr_guid.attr, + &dev_attr_instance_count.attr, + &dev_attr_expensive.attr, +- &dev_attr_driver_override.attr, + NULL + }; + ATTRIBUTE_GROUPS(wmi); +@@ -803,7 +775,6 @@ static void wmi_dev_release(struct device *dev) + { + struct wmi_block *wblock = dev_to_wblock(dev); + +- kfree(wblock->dev.driver_override); + kfree(wblock); + } + +@@ -812,10 +783,12 @@ static int wmi_dev_match(struct device *dev, const struct device_driver *driver) + const struct wmi_driver *wmi_driver = to_wmi_driver(driver); + struct wmi_block *wblock = dev_to_wblock(dev); + const struct wmi_device_id *id = wmi_driver->id_table; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (wblock->dev.driver_override) +- return !strcmp(wblock->dev.driver_override, driver->name); ++ ret = device_match_driver_override(dev, driver); ++ if (ret >= 0) ++ return ret; + + if (id == NULL) + return 0; +@@ -936,6 +909,7 @@ static struct class wmi_bus_class = { + static const struct bus_type wmi_bus_type = { + .name = "wmi", + .dev_groups = wmi_groups, ++ .driver_override = true, + .match = wmi_dev_match, + .uevent = wmi_dev_uevent, + .probe = wmi_dev_probe, +diff --git a/include/linux/wmi.h b/include/linux/wmi.h +index 10751c8e5e6a0..c20bb22133381 100644 +--- a/include/linux/wmi.h ++++ b/include/linux/wmi.h +@@ -16,16 +16,12 @@ + * struct wmi_device - WMI device structure + * @dev: Device associated with this WMI device + * @setable: True for devices implementing the Set Control Method +- * @driver_override: Driver name to force a match; do not set directly, +- * because core frees it; use driver_set_override() to +- * set or clear it. + * + * This represents WMI devices discovered by the WMI driver core. + */ + struct wmi_device { + struct device dev; + bool setable; +- const char *driver_override; + }; + + /** +-- +2.53.0 + diff --git a/queue-6.18/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch b/queue-6.18/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch new file mode 100644 index 0000000000..c3ce64a411 --- /dev/null +++ b/queue-6.18/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch @@ -0,0 +1,81 @@ +From f3a2b8f7a56318e3fa883f287c5c9429288b6c2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 18:44:30 +0100 +Subject: platform/x86: asus-wmi: adjust screenpad power/brightness handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Denis Benato + +[ Upstream commit 130d29c5627cd50e786e926ad7ef66322c5a0c09 ] + +Fix illogical screen off control by hardcoding 0 and 1 depending on the +requested brightness and also do not rely on the last screenpad power +state to issue screen brightness commands. + +Fixes: 2c97d3e55b70 ("platform/x86: asus-wmi: add support for ASUS screenpad") +Signed-off-by: Denis Benato +Signed-off-by: Luke Jones +Link: https://patch.msgid.link/20260302174431.349816-2-denis.benato@linux.dev +Link: https://patch.msgid.link/20260326231154.856729-2-ethantidmore06@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 34 +++++++++++++-------------------- + 1 file changed, 13 insertions(+), 21 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 8e3300f5c2943..e6fe6ed6a63da 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -4154,32 +4154,24 @@ static int read_screenpad_brightness(struct backlight_device *bd) + + static int update_screenpad_bl_status(struct backlight_device *bd) + { +- struct asus_wmi *asus = bl_get_data(bd); +- int power, err = 0; +- u32 ctrl_param; ++ u32 ctrl_param = bd->props.brightness; ++ int err = 0; + +- power = read_screenpad_backlight_power(asus); +- if (power < 0) +- return power; ++ if (bd->props.power) { ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL); ++ if (err < 0) ++ return err; + +- if (bd->props.power != power) { +- if (power != BACKLIGHT_POWER_ON) { +- /* Only brightness > 0 can power it back on */ +- ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; +- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, +- ctrl_param, NULL); +- } else { +- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); +- } +- } else if (power == BACKLIGHT_POWER_ON) { +- /* Only set brightness if powered on or we get invalid/unsync state */ +- ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); ++ if (err < 0) ++ return err; + } + +- /* Ensure brightness is stored to turn back on with */ +- if (err == 0) +- asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; ++ if (!bd->props.power) { ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); ++ if (err < 0) ++ return err; ++ } + + return err; + } +-- +2.53.0 + diff --git a/queue-6.18/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch b/queue-6.18/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch new file mode 100644 index 0000000000..b2330df8f5 --- /dev/null +++ b/queue-6.18/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch @@ -0,0 +1,94 @@ +From d26a87d35af8d153956693e5a3346473e9d7371d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 18:44:31 +0100 +Subject: platform/x86: asus-wmi: fix screenpad brightness range +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Denis Benato + +[ Upstream commit 8d95d1f4aa5c76202b0833a70998769384612488 ] + +Fix screenpad brightness range being too limited without reason: +testing this patch on a Zenbook Duo showed the hardware minimum not being +too low, therefore allow the user to configure the entire range, and +expose to userspace the hardware brightness range and value. + +Fixes: 2c97d3e55b70 ("platform/x86: asus-wmi: add support for ASUS screenpad") +Signed-off-by: Denis Benato +Signed-off-by: Luke Jones +Link: https://patch.msgid.link/20260302174431.349816-3-denis.benato@linux.dev +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index e6fe6ed6a63da..9026744d72267 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -127,7 +127,6 @@ module_param(fnlock_default, bool, 0444); + #define NVIDIA_TEMP_MIN 75 + #define NVIDIA_TEMP_MAX 87 + +-#define ASUS_SCREENPAD_BRIGHT_MIN 20 + #define ASUS_SCREENPAD_BRIGHT_MAX 255 + #define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 + +@@ -4143,13 +4142,13 @@ static int read_screenpad_brightness(struct backlight_device *bd) + return err; + /* The device brightness can only be read if powered, so return stored */ + if (err == BACKLIGHT_POWER_OFF) +- return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; ++ return bd->props.brightness; + + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); + if (err < 0) + return err; + +- return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN; ++ return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; + } + + static int update_screenpad_bl_status(struct backlight_device *bd) +@@ -4189,22 +4188,19 @@ static int asus_screenpad_init(struct asus_wmi *asus) + int err, power; + int brightness = 0; + +- power = read_screenpad_backlight_power(asus); ++ power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); + if (power < 0) + return power; + +- if (power != BACKLIGHT_POWER_OFF) { ++ if (power) { + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); + if (err < 0) + return err; + } +- /* default to an acceptable min brightness on boot if too low */ +- if (brightness < ASUS_SCREENPAD_BRIGHT_MIN) +- brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ +- props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN; ++ props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX; + bd = backlight_device_register("asus_screenpad", + &asus->platform_device->dev, asus, + &asus_screenpad_bl_ops, &props); +@@ -4215,7 +4211,7 @@ static int asus_screenpad_init(struct asus_wmi *asus) + + asus->screenpad_backlight_device = bd; + asus->driver->screenpad_brightness = brightness; +- bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN; ++ bd->props.brightness = brightness; + bd->props.power = power; + backlight_update_status(bd); + +-- +2.53.0 + diff --git a/queue-6.18/platform-x86-barco-p50-gpio-normalize-return-value-o.patch b/queue-6.18/platform-x86-barco-p50-gpio-normalize-return-value-o.patch new file mode 100644 index 0000000000..53d7bd57fa --- /dev/null +++ b/queue-6.18/platform-x86-barco-p50-gpio-normalize-return-value-o.patch @@ -0,0 +1,48 @@ +From 0f2bb483eb0868257bbfec1f736c0b6347320a8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:56:17 -0700 +Subject: platform/x86: barco-p50-gpio: normalize return value of gpio_get +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dmitry Torokhov + +[ Upstream commit 1c9d30d37aaffe3454d70b89a77f8aaecda257bf ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by p50_gpio_get() is normalized +to the [0, 1] range. + +Fixes: 86ef402d805d606a ("gpiolib: sanitize the return value of gpio_chip::get()") +Reviewed-by: Linus Walleij +Signed-off-by: Dmitry Torokhov +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/20260318-barco-p50-gpio-set-v2-1-c0a4a6416163@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/barco-p50-gpio.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c +index 6f13e81f98fbb..360ffd8505d6c 100644 +--- a/drivers/platform/x86/barco-p50-gpio.c ++++ b/drivers/platform/x86/barco-p50-gpio.c +@@ -275,8 +275,11 @@ static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset) + mutex_lock(&p50->lock); + + ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0); +- if (ret == 0) ++ if (ret == 0) { + ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA); ++ if (ret >= 0) ++ ret = !!ret; ++ } + + mutex_unlock(&p50->lock); + +-- +2.53.0 + diff --git a/queue-6.18/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch b/queue-6.18/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch new file mode 100644 index 0000000000..cfaad6fcad --- /dev/null +++ b/queue-6.18/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch @@ -0,0 +1,99 @@ +From 3fd646f33cbeccac86ff6d8f39466eb2c3ac3caf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:38:21 +0800 +Subject: platform/x86: dell-wmi-sysman: bound enumeration string aggregation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pengpeng Hou + +[ Upstream commit 3c34471c26abc52a37f5ad90949e2e4b8027eb14 ] + +populate_enum_data() aggregates firmware-provided value-modifier +and possible-value strings into fixed 512-byte struct members. +The current code bounds each individual source string but then +appends every string and separator with raw strcat() and no +remaining-space check. + +Switch the aggregation loops to a bounded append helper and +reject enumeration packages whose combined strings do not fit +in the destination buffers. + +Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems") +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260408084501.1-dell-wmi-sysman-v2-pengpeng@iscas.ac.cn +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + .../dell/dell-wmi-sysman/enum-attributes.c | 34 +++++++++++++++---- + 1 file changed, 28 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +index fc2f58b4cbc6e..7e44ba3015627 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +@@ -6,10 +6,32 @@ + * Copyright (c) 2020 Dell Inc. + */ + ++#include ++ + #include "dell-wmi-sysman.h" + + get_instance_id(enumeration); + ++static int append_enum_string(char *dest, const char *src) ++{ ++ size_t dest_len = strlen(dest); ++ ssize_t copied; ++ ++ if (WARN_ON_ONCE(dest_len >= MAX_BUFF)) ++ return -EINVAL; ++ ++ copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ dest_len += copied; ++ copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { + int instance_id = get_enumeration_instance_id(kobj); +@@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + if (next_obj >= enum_property_count) +@@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); +-- +2.53.0 + diff --git a/queue-6.18/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch b/queue-6.18/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch new file mode 100644 index 0000000000..ddc718c17f --- /dev/null +++ b/queue-6.18/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch @@ -0,0 +1,60 @@ +From 12357ea9b67fcb7bd3f1707e509033793fe823be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:42:39 +0300 +Subject: platform/x86: dell_rbu: avoid uninit value usage in + packet_size_write() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fedor Pchelkin + +[ Upstream commit f8fd138c2363c0e2d3235c32bfb4fb5c6474e4ae ] + +Ensure the temp value has been properly parsed from the user-provided +buffer and initialized to be used in later operations. While at it, +prefer a convenient kstrtoul() helper. + +Found by Linux Verification Center (linuxtesting.org) with Svace static +analysis tool. + +Fixes: ad6ce87e5bd4 ("[PATCH] dell_rbu: changes in packet update mechanism") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260403134240.604837-1-pchelkin@ispras.ru +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/dell/dell_rbu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c +index 403df9bd9522b..69d7c0a931a7c 100644 +--- a/drivers/platform/x86/dell/dell_rbu.c ++++ b/drivers/platform/x86/dell/dell_rbu.c +@@ -30,6 +30,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -619,9 +620,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, + char *buffer, loff_t pos, size_t count) + { + unsigned long temp; ++ ++ if (kstrtoul(buffer, 10, &temp)) ++ return -EINVAL; ++ + spin_lock(&rbu_data.lock); + packet_empty_list(); +- sscanf(buffer, "%lu", &temp); + if (temp < 0xffffffff) + rbu_data.packetsize = temp; + +-- +2.53.0 + diff --git a/queue-6.18/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch b/queue-6.18/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch new file mode 100644 index 0000000000..c68c340fe8 --- /dev/null +++ b/queue-6.18/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch @@ -0,0 +1,67 @@ +From 813c34c01e6da019e13c161e83b66083a442a713 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 11:31:54 +0100 +Subject: platform/x86: panasonic-laptop: Fix OPTD notifier registration and + cleanup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 8baeff2c1d33dad8572216c6ad3a7425852507d4 ] + +An ACPI notify handler is leaked if device_create_file() returns an +error in acpi_pcc_hotkey_add(). + +Also, it is pointless to call pcc_unregister_optd_notifier() in +acpi_pcc_hotkey_remove() if pcc->platform is NULL and it is better +to arrange the cleanup code in that function in the same order as +the rollback code in acpi_pcc_hotkey_add(). + +Address the above by placing the pcc_register_optd_notifier() call in +acpi_pcc_hotkey_add() after the device_create_file() return value +check and placing the pcc_unregister_optd_notifier() call in +acpi_pcc_hotkey_remove() right before the device_remove_file() call. + +Fixes: d5a81d8e864b ("platform/x86: panasonic-laptop: Add support for optical driver power in Y and W series") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2411055.ElGaqSPkdT@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/panasonic-laptop.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c +index 937f1a5b78edf..848ebf46a59b1 100644 +--- a/drivers/platform/x86/panasonic-laptop.c ++++ b/drivers/platform/x86/panasonic-laptop.c +@@ -1093,9 +1093,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) + } + result = device_create_file(&pcc->platform->dev, + &dev_attr_cdpower); +- pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + if (result) + goto out_platform; ++ ++ pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + } else { + pcc->platform = NULL; + } +@@ -1129,10 +1130,10 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device) + i8042_remove_filter(panasonic_i8042_filter); + + if (pcc->platform) { ++ pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); + platform_device_unregister(pcc->platform); + } +- pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + + sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); + +-- +2.53.0 + diff --git a/queue-6.18/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch b/queue-6.18/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch new file mode 100644 index 0000000000..b259c890bc --- /dev/null +++ b/queue-6.18/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch @@ -0,0 +1,39 @@ +From 591affdf12abc8844ff6d190db9db3ffe9a5363b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 12:48:59 +0200 +Subject: PM: domains: De-constify fields in struct dev_pm_domain_attach_data + +From: Dmitry Baryshkov + +[ Upstream commit 1877d3f258cbb57d64e275754fb9b18b089ce72d ] + +It doesn't really make sense to keep u32 fields to be marked as const. +Having the const fields prevents their modification in the driver. Instead +the whole struct can be defined as const, if it is constant. + +Fixes: 161e16a5e50a ("PM: domains: Add helper functions to attach/detach multiple PM domains") +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + include/linux/pm_domain.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h +index f67a2cb7d7814..5ed1753a7cb47 100644 +--- a/include/linux/pm_domain.h ++++ b/include/linux/pm_domain.h +@@ -49,8 +49,8 @@ + + struct dev_pm_domain_attach_data { + const char * const *pd_names; +- const u32 num_pd_names; +- const u32 pd_flags; ++ u32 num_pd_names; ++ u32 pd_flags; + }; + + struct dev_pm_domain_list { +-- +2.53.0 + diff --git a/queue-6.18/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch b/queue-6.18/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch new file mode 100644 index 0000000000..83cb490cab --- /dev/null +++ b/queue-6.18/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch @@ -0,0 +1,38 @@ +From 6ccf29a10ae7598c3febc0ea2677e6636b15434e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 22:17:17 +0800 +Subject: pmdomain: imx: scu-pd: Fix device_node reference leak during + ->probe() + +From: Felix Gu + +[ Upstream commit c8e9b6a55702be6c6d034e973d519c52c3848415 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In imx_sc_pd_get_console_rsrc(), it does not release the reference. + +Fixes: 893cfb99734f ("firmware: imx: scu-pd: do not power off console domain") +Signed-off-by: Felix Gu +Reviewed-by: Peng Fan +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/pmdomain/imx/scu-pd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pmdomain/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c +index 01d465d88f60d..3ec33667a308c 100644 +--- a/drivers/pmdomain/imx/scu-pd.c ++++ b/drivers/pmdomain/imx/scu-pd.c +@@ -326,6 +326,7 @@ static void imx_sc_pd_get_console_rsrc(void) + return; + + imx_con_rsrc = specs.args[0]; ++ of_node_put(specs.np); + } + + static int imx_sc_get_pd_power(struct device *dev, u32 rsrc) +-- +2.53.0 + diff --git a/queue-6.18/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch b/queue-6.18/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch new file mode 100644 index 0000000000..87e6b55363 --- /dev/null +++ b/queue-6.18/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch @@ -0,0 +1,36 @@ +From faf7e9ac67424853802c96c6f4b7cff74071dd47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 20:27:47 +0800 +Subject: pmdomain: ti: omap_prm: Fix a reference leak on device node + +From: Felix Gu + +[ Upstream commit 44c28e1c52764fef6dd1c1ada3a248728812e67f ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In omap_prm_domain_attach_dev, it does not release the reference. + +Fixes: 58cbff023bfa ("soc: ti: omap-prm: Add basic power domain support") +Signed-off-by: Felix Gu +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/pmdomain/ti/omap_prm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pmdomain/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c +index 5142f064bf5cd..64a187f79a1a7 100644 +--- a/drivers/pmdomain/ti/omap_prm.c ++++ b/drivers/pmdomain/ti/omap_prm.c +@@ -655,6 +655,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, + if (pd_args.args_count != 0) + dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", + prmd->pd.name, pd_args.args_count); ++ of_node_put(pd_args.np); + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; +-- +2.53.0 + diff --git a/queue-6.18/powerpc-crash-fix-backup-region-offset-update-to-elf.patch b/queue-6.18/powerpc-crash-fix-backup-region-offset-update-to-elf.patch new file mode 100644 index 0000000000..6a9e5458f5 --- /dev/null +++ b/queue-6.18/powerpc-crash-fix-backup-region-offset-update-to-elf.patch @@ -0,0 +1,63 @@ +From 0b91891bb39ad31959e28ada9ce5240a5545be2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:49 +0530 +Subject: powerpc/crash: fix backup region offset update to elfcorehdr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sourabh Jain + +[ Upstream commit 789335cacdf37da93bb7c70322dff8c7e82881df ] + +update_backup_region_phdr() in file_load_64.c iterates over all the +program headers in the kdump kernel’s elfcorehdr and updates the +p_offset of the program header whose physical address starts at 0. + +However, the loop logic is incorrect because the program header pointer +is not updated during iteration. Since elfcorehdr typically contains +PT_NOTE entries first, the PT_LOAD program header with physical address +0 is never reached. As a result, its p_offset is not updated to point to +the backup region. + +Because of this behavior, the capture kernel exports the first 64 KB of +the crashed kernel’s memory at offset 0, even though that memory +actually lives in the backup region. When a crash happens, purgatory +copies the first 64 KB of the crashed kernel’s memory into the backup +region so the capture kernel can safely use it. + +This has not caused problems so far because the first 64 KB is usually +identical in both the crashed and capture kernels. However, this is +just an assumption and is not guaranteed to always hold true. + +Fix update_backup_region_phdr() to correctly update the p_offset of the +program header with a starting physical address of 0 by correcting the +logic used to iterate over the program headers. + +Fixes: cb350c1f1f86 ("powerpc/kexec_file: Prepare elfcore header for crashing kernel") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Reviewed-by: Hari Bathini +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-2-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kexec/file_load_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index 5f6d50e4c3d45..a7db7eca0481b 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -391,7 +391,7 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) + unsigned int i; + + phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++) { ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + if (phdr->p_paddr == BACKUP_SRC_START) { + phdr->p_offset = image->arch.backup_start; + kexec_dprintk("Backup region offset updated to 0x%lx\n", +-- +2.53.0 + diff --git a/queue-6.18/powerpc-crash-update-backup-region-offset-in-elfcore.patch b/queue-6.18/powerpc-crash-update-backup-region-offset-in-elfcore.patch new file mode 100644 index 0000000000..30b261ae91 --- /dev/null +++ b/queue-6.18/powerpc-crash-update-backup-region-offset-in-elfcore.patch @@ -0,0 +1,245 @@ +From 3c34eb9d062a39582bc29e328d963130acbc776a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:50 +0530 +Subject: powerpc/crash: Update backup region offset in elfcorehdr on memory + hotplug + +From: Sourabh Jain + +[ Upstream commit f53b24d1fa263f56155213eabab734c18d884aff ] + +When elfcorehdr is prepared for kdump, the program header representing +the first 64 KB of memory is expected to have its offset point to the +backup region. This is required because purgatory copies the first 64 KB +of the crashed kernel memory to this backup region following a kernel +crash. This allows the capture kernel to use the first 64 KB of memory +to place the exception vectors and other required data. + +When elfcorehdr is recreated due to memory hotplug, the offset of +the program header representing the first 64 KB is not updated. +As a result, the capture kernel exports the first 64 KB at offset +0, even though the data actually resides in the backup region. + +Fix this by calling sync_backup_region_phdr() to update the program +header offset in the elfcorehdr created during memory hotplug. + +sync_backup_region_phdr() works for images loaded via the +kexec_file_load syscall. However, it does not work for kexec_load, +because image->arch.backup_start is not initialized in that case. +So introduce machine_kexec_post_load() to process the elfcorehdr +prepared by kexec-tools and initialize image->arch.backup_start for +kdump images loaded via kexec_load syscall. + +Rename update_backup_region_phdr() to sync_backup_region_phdr() and +extend it to synchronize the backup region offset between the kdump +image and the ELF core header. The helper now supports updating either +the kdump image from the ELF program header or updating the ELF program +header from the kdump image, avoiding code duplication. + +Define ARCH_HAS_KIMAGE_ARCH and struct kimage_arch when +CONFIG_KEXEC_FILE or CONFIG_CRASH_DUMP is enabled so that +kimage->arch.backup_start is available with the kexec_load system call. + +This patch depends on the patch titled +"powerpc/crash: fix backup region offset update to elfcorehdr". + +Fixes: 849599b702ef ("powerpc/crash: add crash memory hotplug support") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-3-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kexec.h | 14 +++++-- + arch/powerpc/kexec/crash.c | 64 +++++++++++++++++++++++++++++++ + arch/powerpc/kexec/file_load_64.c | 29 +------------- + 3 files changed, 76 insertions(+), 31 deletions(-) + +diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h +index 4bbf9f699aaaf..d3b5028102cdd 100644 +--- a/arch/powerpc/include/asm/kexec.h ++++ b/arch/powerpc/include/asm/kexec.h +@@ -66,11 +66,9 @@ void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_co + unsigned long start_address) __noreturn; + void kexec_copy_flush(struct kimage *image); + +-#ifdef CONFIG_KEXEC_FILE +-extern const struct kexec_file_ops kexec_elf64_ops; + ++#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP) + #define ARCH_HAS_KIMAGE_ARCH +- + struct kimage_arch { + struct crash_mem *exclude_ranges; + +@@ -78,6 +76,10 @@ struct kimage_arch { + void *backup_buf; + void *fdt; + }; ++#endif ++ ++#ifdef CONFIG_KEXEC_FILE ++extern const struct kexec_file_ops kexec_elf64_ops; + + char *setup_kdump_cmdline(struct kimage *image, char *cmdline, + unsigned long cmdline_len); +@@ -143,6 +145,10 @@ int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags); + + unsigned int arch_crash_get_elfcorehdr_size(void); + #define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size ++ ++int machine_kexec_post_load(struct kimage *image); ++#define machine_kexec_post_load machine_kexec_post_load ++ + #endif /* CONFIG_CRASH_HOTPLUG */ + + extern int crashing_cpu; +@@ -157,6 +163,8 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs); + extern void crash_kexec_prepare(void); + extern void crash_kexec_secondary(struct pt_regs *regs); + ++extern void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, ++ bool phdr_to_kimage); + static inline bool kdump_in_progress(void) + { + return crashing_cpu >= 0; +diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c +index a325c1c02f96d..e6539f213b3d1 100644 +--- a/arch/powerpc/kexec/crash.c ++++ b/arch/powerpc/kexec/crash.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + /* + * The primary CPU waits a while for all secondary CPUs to enter. This is to +@@ -399,7 +400,68 @@ void default_machine_crash_shutdown(struct pt_regs *regs) + ppc_md.kexec_cpu_down(1, 0); + } + ++#ifdef CONFIG_CRASH_DUMP ++/** ++ * sync_backup_region_phdr - synchronize backup region offset between ++ * kexec image and ELF core header. ++ * @image: Kexec image. ++ * @ehdr: ELF core header. ++ * @phdr_to_kimage: If true, read the offset from the ELF program header ++ * and update the kimage backup region. If false, update ++ * the ELF program header offset from the kimage backup ++ * region. ++ * ++ * Note: During kexec_load, this is called with phdr_to_kimage = true. For ++ * kexec_file_load and ELF core header recreation during memory hotplug ++ * events, it is called with phdr_to_kimage = false. ++ * ++ * Returns nothing. ++ */ ++void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, bool phdr_to_kimage) ++{ ++ Elf64_Phdr *phdr; ++ unsigned int i; ++ ++ phdr = (Elf64_Phdr *)(ehdr + 1); ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { ++ if (phdr->p_paddr == BACKUP_SRC_START) { ++ if (phdr_to_kimage) ++ image->arch.backup_start = phdr->p_offset; ++ else ++ phdr->p_offset = image->arch.backup_start; ++ ++ kexec_dprintk("Backup region offset updated to 0x%lx\n", ++ image->arch.backup_start); ++ return; ++ } ++ } ++} ++#endif /* CONFIG_CRASH_DUMP */ ++ + #ifdef CONFIG_CRASH_HOTPLUG ++ ++int machine_kexec_post_load(struct kimage *image) ++{ ++ int i; ++ unsigned long mem; ++ unsigned char *ptr; ++ ++ if (image->type != KEXEC_TYPE_CRASH) ++ return 0; ++ ++ if (image->file_mode) ++ return 0; ++ ++ for (i = 0; i < image->nr_segments; i++) { ++ mem = image->segment[i].mem; ++ ptr = (char *)__va(mem); ++ ++ if (ptr && memcmp(ptr, ELFMAG, SELFMAG) == 0) ++ sync_backup_region_phdr(image, (Elf64_Ehdr *) ptr, true); ++ } ++ return 0; ++} ++ + #undef pr_fmt + #define pr_fmt(fmt) "crash hp: " fmt + +@@ -474,6 +536,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify * + goto out; + } + ++ sync_backup_region_phdr(image, (Elf64_Ehdr *) elfbuf, false); ++ + ptr = __va(mem); + if (ptr) { + /* Temporarily invalidate the crash image while it is replaced */ +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index a7db7eca0481b..8c72e12ea44e5 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -374,33 +374,6 @@ static int load_backup_segment(struct kimage *image, struct kexec_buf *kbuf) + return 0; + } + +-/** +- * update_backup_region_phdr - Update backup region's offset for the core to +- * export the region appropriately. +- * @image: Kexec image. +- * @ehdr: ELF core header. +- * +- * Assumes an exclusive program header is setup for the backup region +- * in the ELF headers +- * +- * Returns nothing. +- */ +-static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) +-{ +- Elf64_Phdr *phdr; +- unsigned int i; +- +- phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++, phdr++) { +- if (phdr->p_paddr == BACKUP_SRC_START) { +- phdr->p_offset = image->arch.backup_start; +- kexec_dprintk("Backup region offset updated to 0x%lx\n", +- image->arch.backup_start); +- return; +- } +- } +-} +- + static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem) + { + #if defined(CONFIG_CRASH_HOTPLUG) && defined(CONFIG_MEMORY_HOTPLUG) +@@ -445,7 +418,7 @@ static int load_elfcorehdr_segment(struct kimage *image, struct kexec_buf *kbuf) + } + + /* Fix the offset for backup region in the ELF header */ +- update_backup_region_phdr(image, headers); ++ sync_backup_region_phdr(image, headers, false); + + kbuf->buffer = headers; + kbuf->mem = KEXEC_BUF_MEM_UNKNOWN; +-- +2.53.0 + diff --git a/queue-6.18/powerpc-pgtable-frag-fix-bad-page-state-in-pte_frag_.patch b/queue-6.18/powerpc-pgtable-frag-fix-bad-page-state-in-pte_frag_.patch new file mode 100644 index 0000000000..6efb6b81b4 --- /dev/null +++ b/queue-6.18/powerpc-pgtable-frag-fix-bad-page-state-in-pte_frag_.patch @@ -0,0 +1,89 @@ +From c55d70b32fa9d9c0615211b34a2477a4b2c3d25e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 23:44:24 +0530 +Subject: powerpc/pgtable-frag: Fix bad page state in pte_frag_destroy + +From: Ritesh Harjani (IBM) + +[ Upstream commit fda4d71651f71c44b35829d13f3c8bf920032f77 ] + +powerpc uses pt_frag_refcount as a reference counter for tracking it's +pte and pmd page table fragments. For PTE table, in case of Hash with +64K pagesize, we have 16 fragments of 4K size in one 64K page. + +Patch series [1] "mm: free retracted page table by RCU" +added pte_free_defer() to defer the freeing of PTE tables when +retract_page_tables() is called for madvise MADV_COLLAPSE on shmem +range. +[1]: https://lore.kernel.org/all/7cd843a9-aa80-14f-5eb2-33427363c20@google.com/ + +pte_free_defer() sets the active flag on the corresponding fragment's +folio & calls pte_fragment_free(), which reduces the pt_frag_refcount. +When pt_frag_refcount reaches 0 (no active fragment using the folio), it +checks if the folio active flag is set, if set, it calls call_rcu to +free the folio, it the active flag is unset then it calls pte_free_now(). + +Now, this can lead to following problem in a corner case... + +[ 265.351553][ T183] BUG: Bad page state in process a.out pfn:20d62 +[ 265.353555][ T183] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x20d62 +[ 265.355457][ T183] flags: 0x3ffff800000100(active|node=0|zone=0|lastcpupid=0x7ffff) +[ 265.358719][ T183] raw: 003ffff800000100 0000000000000000 5deadbeef0000122 0000000000000000 +[ 265.360177][ T183] raw: 0000000000000000 c0000000119caf58 00000000ffffffff 0000000000000000 +[ 265.361438][ T183] page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set +[ 265.362572][ T183] Modules linked in: +[ 265.364622][ T183] CPU: 0 UID: 0 PID: 183 Comm: a.out Not tainted 6.18.0-rc3-00141-g1ddeaaace7ff-dirty #53 VOLUNTARY +[ 265.364785][ T183] Hardware name: IBM pSeries (emulated by qemu) POWER10 (architected) 0x801200 0xf000006 of:SLOF,git-ee03ae pSeries +[ 265.364908][ T183] Call Trace: +[ 265.364955][ T183] [c000000011e6f7c0] [c000000001cfaa18] dump_stack_lvl+0x130/0x148 (unreliable) +[ 265.365202][ T183] [c000000011e6f7f0] [c000000000794758] bad_page+0xb4/0x1c8 +[ 265.365384][ T183] [c000000011e6f890] [c00000000079c020] __free_frozen_pages+0x838/0xd08 +[ 265.365554][ T183] [c000000011e6f980] [c0000000000a70ac] pte_frag_destroy+0x298/0x310 +[ 265.365729][ T183] [c000000011e6fa30] [c0000000000aa764] arch_exit_mmap+0x34/0x218 +[ 265.365912][ T183] [c000000011e6fa80] [c000000000751698] exit_mmap+0xb8/0x820 +[ 265.366080][ T183] [c000000011e6fc30] [c0000000001b1258] __mmput+0x98/0x300 +[ 265.366244][ T183] [c000000011e6fc80] [c0000000001c81f8] do_exit+0x470/0x1508 +[ 265.366421][ T183] [c000000011e6fd70] [c0000000001c95e4] do_group_exit+0x88/0x148 +[ 265.366602][ T183] [c000000011e6fdc0] [c0000000001c96ec] pid_child_should_wake+0x0/0x178 +[ 265.366780][ T183] [c000000011e6fdf0] [c00000000003a270] system_call_exception+0x1b0/0x4e0 +[ 265.366958][ T183] [c000000011e6fe50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec + +The bad page state error occurs when such a folio gets freed (with +active flag set), from do_exit() path in parallel. + +... this can happen when the pte fragment was allocated from this folio, +but when all the fragments get freed, the pte_frag_refcount still had some +unused fragments. Now, if this process exits, with such folio as it's cached +pte_frag in mm->context, then during pte_frag_destroy(), we simply call +pagetable_dtor() and pagetable_free(), meaning it doesn't clear the +active flag. This, can lead to the above bug. Since we are anyway in +do_exit() path, then if the refcount is 0, then I guess it should be +ok to simply clear the folio active flag before calling pagetable_dtor() +& pagetable_free(). + +Fixes: 32cc0b7c9d50 ("powerpc: add pte_free_defer() for pgtables sharing page") +Reviewed-by: Christophe Leroy (CS GROUP) +Signed-off-by: Ritesh Harjani (IBM) +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/ee13e7f99b8f258019da2b37655b998e73e5ef8b.1773078178.git.ritesh.list@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/mm/pgtable-frag.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/powerpc/mm/pgtable-frag.c b/arch/powerpc/mm/pgtable-frag.c +index 77e55eac16e42..ae742564a3d56 100644 +--- a/arch/powerpc/mm/pgtable-frag.c ++++ b/arch/powerpc/mm/pgtable-frag.c +@@ -25,6 +25,7 @@ void pte_frag_destroy(void *pte_frag) + count = ((unsigned long)pte_frag & ~PAGE_MASK) >> PTE_FRAG_SIZE_SHIFT; + /* We allow PTE_FRAG_NR fragments from a PTE page */ + if (atomic_sub_and_test(PTE_FRAG_NR - count, &ptdesc->pt_frag_refcount)) { ++ folio_clear_active(ptdesc_folio(ptdesc)); + pagetable_dtor(ptdesc); + pagetable_free(ptdesc); + } +-- +2.53.0 + diff --git a/queue-6.18/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch b/queue-6.18/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch new file mode 100644 index 0000000000..241aa5971c --- /dev/null +++ b/queue-6.18/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch @@ -0,0 +1,50 @@ +From 34fe3d3482606a96de7f264a9196641092c95a2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:11:15 +0900 +Subject: ppp: require CAP_NET_ADMIN in target netns for unattached ioctls + +From: Taegu Ha + +[ Upstream commit 2bb6379416fd19f44c3423a00bfd8626259f6067 ] + +/dev/ppp open is currently authorized against file->f_cred->user_ns, +while unattached administrative ioctls operate on current->nsproxy->net_ns. + +As a result, a local unprivileged user can create a new user namespace +with CLONE_NEWUSER, gain CAP_NET_ADMIN only in that new user namespace, +and still issue PPPIOCNEWUNIT, PPPIOCATTACH, or PPPIOCATTCHAN against +an inherited network namespace. + +Require CAP_NET_ADMIN in the user namespace that owns the target network +namespace before handling unattached PPP administrative ioctls. + +This preserves normal pppd operation in the network namespace it is +actually privileged in, while rejecting the userns-only inherited-netns +case. + +Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2") +Signed-off-by: Taegu Ha +Link: https://patch.msgid.link/20260409071117.4354-1-hataegu0826@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index f9f0f16c41d10..7ad6c241c3295 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1057,6 +1057,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct ppp_net *pn; + int __user *p = (int __user *)arg; + ++ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ + switch (cmd) { + case PPPIOCNEWUNIT: + /* Create a new ppp unit */ +-- +2.53.0 + diff --git a/queue-6.18/pppoe-drop-pfc-frames.patch b/queue-6.18/pppoe-drop-pfc-frames.patch new file mode 100644 index 0000000000..bb3c5afc84 --- /dev/null +++ b/queue-6.18/pppoe-drop-pfc-frames.patch @@ -0,0 +1,112 @@ +From 4f380de830071dc1b1dd9a8e339dd09c2140bdaa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 10:24:51 +0800 +Subject: pppoe: drop PFC frames + +From: Qingfang Deng + +[ Upstream commit cc1ff87bce1ccd38410ab10960f576dcd17db679 ] + +RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT +RECOMMENDED for PPPoE. In practice, pppd does not support negotiating +PFC for PPPoE sessions, and the current PPPoE driver assumes an +uncompressed (2-byte) protocol field. However, the generic PPP layer +function ppp_input() is not aware of the negotiation result, and still +accepts PFC frames. + +If a peer with a broken implementation or an attacker sends a frame with +a compressed (1-byte) protocol field, the subsequent PPP payload is +shifted by one byte. This causes the network header to be 4-byte +misaligned, which may trigger unaligned access exceptions on some +architectures. + +To reduce the attack surface, drop PPPoE PFC frames. Introduce +ppp_skb_is_compressed_proto() helper function to be used in both +ppp_generic.c and pppoe.c to avoid open-coding. + +Fixes: 7fb1b8ca8fa1 ("ppp: Move PFC decompression to PPP generic layer") +Signed-off-by: Qingfang Deng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415022456.141758-2-qingfang.deng@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + drivers/net/ppp/pppoe.c | 8 +++++++- + include/linux/ppp_defs.h | 16 ++++++++++++++++ + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 7ad6c241c3295..507d216256c0d 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2240,7 +2240,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + */ + static void __ppp_decompress_proto(struct sk_buff *skb) + { +- if (skb->data[0] & 0x01) ++ if (ppp_skb_is_compressed_proto(skb)) + *(u8 *)skb_push(skb, 1) = 0x00; + } + +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index 4ac6afce267b9..dc6d139432387 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -424,7 +424,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb_mac_header_len(skb) < ETH_HLEN) + goto drop; + +- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) ++ if (!pskb_may_pull(skb, PPPOE_SES_HLEN)) + goto drop; + + ph = pppoe_hdr(skb); +@@ -434,6 +434,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb->len < len) + goto drop; + ++ /* skb->data points to the PPP protocol header after skb_pull_rcsum. ++ * Drop PFC frames. ++ */ ++ if (ppp_skb_is_compressed_proto(skb)) ++ goto drop; ++ + if (pskb_trim_rcsum(skb, len)) + goto drop; + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index b7e57fdbd4139..b1d1f46d7d3be 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -8,6 +8,7 @@ + #define _PPP_DEFS_H_ + + #include ++#include + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) +@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) + return !!((proto & 0x0101) == 0x0001); + } + ++/** ++ * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed ++ * @skb: skb to check ++ * ++ * Check if the PPP protocol field is compressed (the least significant ++ * bit of the most significant octet is 1). skb->data must point to the PPP ++ * protocol header. ++ * ++ * Return: Whether the PPP protocol field is compressed. ++ */ ++static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb) ++{ ++ return unlikely(skb->data[0] & 0x01); ++} ++ + #endif /* _PPP_DEFS_H_ */ +-- +2.53.0 + diff --git a/queue-6.18/pstore-ram-fix-resource-leak-when-ioremap-fails.patch b/queue-6.18/pstore-ram-fix-resource-leak-when-ioremap-fails.patch new file mode 100644 index 0000000000..b12a184632 --- /dev/null +++ b/queue-6.18/pstore-ram-fix-resource-leak-when-ioremap-fails.patch @@ -0,0 +1,52 @@ +From 3fe40e3f690b7a67e4bec695b3edd098d803b4f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:54:06 -0700 +Subject: pstore/ram: fix resource leak when ioremap() fails + +From: Cole Leavitt + +[ Upstream commit 2ddb69f686ef7a621645e97fc7329c50edf5d0e5 ] + +In persistent_ram_iomap(), ioremap() or ioremap_wc() may return NULL on +failure. Currently, if this happens, the function returns NULL without +releasing the memory region acquired by request_mem_region(). + +This leads to a resource leak where the memory region remains reserved +but unusable. + +Additionally, the caller persistent_ram_buffer_map() handles NULL +correctly by returning -ENOMEM, but without this check, a NULL return +combined with request_mem_region() succeeding leaves resources in an +inconsistent state. + +This is the ioremap() counterpart to commit 05363abc7625 ("pstore: +ram_core: fix incorrect success return when vmap() fails") which fixed +a similar issue in the vmap() path. + +Fixes: 404a6043385d ("staging: android: persistent_ram: handle reserving and mapping memory") +Signed-off-by: Cole Leavitt +Link: https://patch.msgid.link/20260225235406.11790-1-cole@unwrap.rs +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index 7b6d6378a3b87..95675d4bab141 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -489,6 +489,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, + else + va = ioremap_wc(start, size); + ++ /* We must release the mem region if ioremap fails. */ ++ if (!va) ++ release_mem_region(start, size); ++ + /* + * Since request_mem_region() and ioremap() are byte-granularity + * there is no need handle anything special like we do when the +-- +2.53.0 + diff --git a/queue-6.18/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch b/queue-6.18/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch new file mode 100644 index 0000000000..e192f2a38f --- /dev/null +++ b/queue-6.18/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch @@ -0,0 +1,139 @@ +From 6eaaad7c3606bced624caeac7ba6bdfbd907a742 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 17:08:38 +0900 +Subject: pwm: atmel-tcb: Cache clock rates and mark chip as atomic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sangyun Kim + +[ Upstream commit 68637b68afcc3cb4d56aca14a3a1d1b47b879369 ] + +atmel_tcb_pwm_apply() holds tcbpwmc->lock as a spinlock via +guard(spinlock)() and then calls atmel_tcb_pwm_config(), which calls +clk_get_rate() twice. clk_get_rate() acquires clk_prepare_lock (a +mutex), so this is a sleep-in-atomic-context violation. + +On CONFIG_DEBUG_ATOMIC_SLEEP kernels every pwm_apply_state() that +enables or reconfigures the PWM triggers a "BUG: sleeping function +called from invalid context" warning. + +Acquire exclusive control over the clock rates with +clk_rate_exclusive_get() at probe time and cache the rates in struct +atmel_tcb_pwm_chip, then read the cached rates from +atmel_tcb_pwm_config(). This keeps the spinlock-based mutual exclusion +introduced in commit 37f7707077f5 ("pwm: atmel-tcb: Fix race condition +and convert to guards") and removes the sleeping calls from the atomic +section. + +With no sleeping calls left in .apply() and the regmap-mmio bus already +running with fast_io=true, also mark the chip as atomic so consumers +can use pwm_apply_atomic() from atomic context. + +Fixes: 37f7707077f5 ("pwm: atmel-tcb: Fix race condition and convert to guards") +Signed-off-by: Sangyun Kim +Link: https://patch.msgid.link/20260419080838.3192357-1-sangyun.kim@snu.ac.kr +[ukleinek: Ensure .clk is enabled before calling clk_get_rate on it.] +Signed-off-by: Uwe Kleine-König +Signed-off-by: Sasha Levin +--- + drivers/pwm/pwm-atmel-tcb.c | 38 +++++++++++++++++++++++++++++++++---- + 1 file changed, 34 insertions(+), 4 deletions(-) + +diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c +index f9ff78ba122d4..3d30aeab507e0 100644 +--- a/drivers/pwm/pwm-atmel-tcb.c ++++ b/drivers/pwm/pwm-atmel-tcb.c +@@ -50,6 +50,8 @@ struct atmel_tcb_pwm_chip { + spinlock_t lock; + u8 channel; + u8 width; ++ unsigned long rate; ++ unsigned long slow_rate; + struct regmap *regmap; + struct clk *clk; + struct clk *gclk; +@@ -266,7 +268,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int slowclk = 0; + unsigned period; + unsigned duty; +- unsigned rate = clk_get_rate(tcbpwmc->clk); ++ unsigned long rate = tcbpwmc->rate; + unsigned long long min; + unsigned long long max; + +@@ -294,7 +296,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + */ + if (i == ARRAY_SIZE(atmel_tcb_divisors)) { + i = slowclk; +- rate = clk_get_rate(tcbpwmc->slow_clk); ++ rate = tcbpwmc->slow_rate; + min = div_u64(NSEC_PER_SEC, rate); + max = min << tcbpwmc->width; + +@@ -431,24 +433,49 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) + } + + chip->ops = &atmel_tcb_pwm_ops; ++ chip->atomic = true; + tcbpwmc->channel = channel; + tcbpwmc->width = config->counter_width; + +- err = clk_prepare_enable(tcbpwmc->slow_clk); ++ err = clk_prepare_enable(tcbpwmc->clk); + if (err) + goto err_gclk; + ++ err = clk_prepare_enable(tcbpwmc->slow_clk); ++ if (err) ++ goto err_disable_clk;; ++ ++ err = clk_rate_exclusive_get(tcbpwmc->clk); ++ if (err) ++ goto err_disable_slow_clk; ++ ++ err = clk_rate_exclusive_get(tcbpwmc->slow_clk); ++ if (err) ++ goto err_clk_unlock; ++ ++ tcbpwmc->rate = clk_get_rate(tcbpwmc->clk); ++ tcbpwmc->slow_rate = clk_get_rate(tcbpwmc->slow_clk); ++ + spin_lock_init(&tcbpwmc->lock); + + err = pwmchip_add(chip); + if (err < 0) +- goto err_disable_clk; ++ goto err_slow_clk_unlock; + + platform_set_drvdata(pdev, chip); + + return 0; + ++err_slow_clk_unlock: ++ clk_rate_exclusive_put(tcbpwmc->slow_clk); ++ ++err_clk_unlock: ++ clk_rate_exclusive_put(tcbpwmc->clk); ++ + err_disable_clk: ++ clk_disable_unprepare(tcbpwmc->clk); ++ ++err_disable_slow_clk: + clk_disable_unprepare(tcbpwmc->slow_clk); + + err_gclk: +@@ -470,6 +497,9 @@ static void atmel_tcb_pwm_remove(struct platform_device *pdev) + + pwmchip_remove(chip); + ++ clk_rate_exclusive_put(tcbpwmc->slow_clk); ++ clk_rate_exclusive_put(tcbpwmc->clk); ++ clk_disable_unprepare(tcbpwmc->clk); + clk_disable_unprepare(tcbpwmc->slow_clk); + clk_put(tcbpwmc->gclk); + clk_put(tcbpwmc->clk); +-- +2.53.0 + diff --git a/queue-6.18/pwm-stm32-fix-rounding-issue-for-requests-with-inver.patch b/queue-6.18/pwm-stm32-fix-rounding-issue-for-requests-with-inver.patch new file mode 100644 index 0000000000..02bfd4476a --- /dev/null +++ b/queue-6.18/pwm-stm32-fix-rounding-issue-for-requests-with-inver.patch @@ -0,0 +1,103 @@ +From c9715e92df92bccced861c8d8f831815edc1f44a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 16:50:12 +0200 +Subject: pwm: stm32: Fix rounding issue for requests with inverted polarity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 5d087c485b6ecf200a9ebb2a032bf8571d330250 ] + +The calculation of the number of pwm clk ticks from a time length in +nanoseconds involves a division and thus some rounding. That might +result in + + duty_ticks + offset_ticks < period_ticks + +despite + + duty_length_ns + duty_offset_ns >= period_length_ns + +. The stm32 PWM cannot configure offset_ticks freely, it can only select +0 or period_length_ns - duty_length_ns---that is the classic normal and +inverted polarity. The decision to select the hardware polarity must be +done using the ticks values and not the nanoseconds times to adhere to +the rounding rules by the pwm core. + +With the pwm clk running at 208900 kHz on my test machine +(stm32mp135f-dk), a test case that was handled wrong is: + + # pwmround -P 9999962 -O 24970 -D 9974992 + period_length = 9999962 + duty_length = 9974840 + duty_offset = 25123 + +With this change applied the rounding is done correctly: + + # pwmround -P 9999962 -O 24970 -D 9974992 + period_length = 9999962 + duty_length = 9974840 + duty_offset = 0 + +Fixes: deaba9cff809 ("pwm: stm32: Implementation of the waveform callbacks") +Signed-off-by: Uwe Kleine-König +Link: https://patch.msgid.link/c5e7767cee821b5f6e00f95bd14a5e13015646fb.1776264104.git.u.kleine-koenig@baylibre.com +Signed-off-by: Uwe Kleine-König +Signed-off-by: Sasha Levin +--- + drivers/pwm/pwm-stm32.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c +index 2594fb771b04a..935257a890b06 100644 +--- a/drivers/pwm/pwm-stm32.c ++++ b/drivers/pwm/pwm-stm32.c +@@ -68,7 +68,7 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip, + struct stm32_pwm *priv = to_stm32_pwm_dev(chip); + unsigned int ch = pwm->hwpwm; + unsigned long rate; +- u64 ccr, duty; ++ u64 duty_ticks, offset_ticks; + int ret; + + if (wf->period_length_ns == 0) { +@@ -164,23 +164,25 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip, + wfhw->arr = min_t(u64, arr, priv->max_arr) - 1; + } + +- duty = mul_u64_u64_div_u64(wf->duty_length_ns, rate, +- (u64)NSEC_PER_SEC * (wfhw->psc + 1)); +- duty = min_t(u64, duty, wfhw->arr + 1); ++ duty_ticks = mul_u64_u64_div_u64(wf->duty_length_ns, rate, ++ (u64)NSEC_PER_SEC * (wfhw->psc + 1)); ++ duty_ticks = min_t(u64, duty_ticks, wfhw->arr + 1); + +- if (wf->duty_length_ns && wf->duty_offset_ns && +- wf->duty_length_ns + wf->duty_offset_ns >= wf->period_length_ns) { ++ offset_ticks = mul_u64_u64_div_u64(wf->duty_offset_ns, rate, ++ (u64)NSEC_PER_SEC * (wfhw->psc + 1)); ++ offset_ticks = min_t(u64, offset_ticks, wfhw->arr + 1); ++ ++ if (duty_ticks && offset_ticks && ++ duty_ticks + offset_ticks >= wfhw->arr + 1) { + wfhw->ccer |= TIM_CCER_CCxP(ch + 1); + if (priv->have_complementary_output) + wfhw->ccer |= TIM_CCER_CCxNP(ch + 1); + +- ccr = wfhw->arr + 1 - duty; ++ wfhw->ccr = wfhw->arr + 1 - duty_ticks; + } else { +- ccr = duty; ++ wfhw->ccr = duty_ticks; + } + +- wfhw->ccr = min_t(u64, ccr, wfhw->arr + 1); +- + out: + dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> CCER: %08x, PSC: %08x, ARR: %08x, CCR: %08x\n", + pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, +-- +2.53.0 + diff --git a/queue-6.18/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch b/queue-6.18/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch new file mode 100644 index 0000000000..9517018142 --- /dev/null +++ b/queue-6.18/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch @@ -0,0 +1,148 @@ +From baea1a277e7209ce4e4b668c7f4c98de4beef49d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 14:22:16 +0100 +Subject: quota: Fix race of dquot_scan_active() with quota deactivation + +From: Jan Kara + +[ Upstream commit e93ab401da4b2e2c1b8ef2424de2f238d51c8b2d ] + +dquot_scan_active() can race with quota deactivation in +quota_release_workfn() like: + + CPU0 (quota_release_workfn) CPU1 (dquot_scan_active) + ============================== ============================== + spin_lock(&dq_list_lock); + list_replace_init( + &releasing_dquots, &rls_head); + /* dquot X on rls_head, + dq_count == 0, + DQ_ACTIVE_B still set */ + spin_unlock(&dq_list_lock); + synchronize_srcu(&dquot_srcu); + spin_lock(&dq_list_lock); + list_for_each_entry(dquot, + &inuse_list, dq_inuse) { + /* finds dquot X */ + dquot_active(X) -> true + atomic_inc(&X->dq_count); + } + spin_unlock(&dq_list_lock); + spin_lock(&dq_list_lock); + dquot = list_first_entry(&rls_head); + WARN_ON_ONCE(atomic_read(&dquot->dq_count)); + +The problem is not only a cosmetic one as under memory pressure the +caller of dquot_scan_active() can end up working on freed dquot. + +Fix the problem by making sure the dquot is removed from releasing list +when we acquire a reference to it. + +Fixes: 869b6ea1609f ("quota: Fix slow quotaoff") +Reported-by: Sam Sun +Link: https://lore.kernel.org/all/CAEkJfYPTt3uP1vAYnQ5V2ZWn5O9PLhhGi5HbOcAzyP9vbXyjeg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/dquot.c | 38 ++++++++++++++++++++++++++++++-------- + include/linux/quotaops.h | 9 +-------- + 2 files changed, 31 insertions(+), 16 deletions(-) + +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 6c4a6ee1fa2b6..45a46dc4de4ef 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -363,6 +363,31 @@ static inline int dquot_active(struct dquot *dquot) + return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); + } + ++static struct dquot *__dqgrab(struct dquot *dquot) ++{ ++ lockdep_assert_held(&dq_list_lock); ++ if (!atomic_read(&dquot->dq_count)) ++ remove_free_dquot(dquot); ++ atomic_inc(&dquot->dq_count); ++ return dquot; ++} ++ ++/* ++ * Get reference to dquot when we got pointer to it by some other means. The ++ * dquot has to be active and the caller has to make sure it cannot get ++ * deactivated under our hands. ++ */ ++struct dquot *dqgrab(struct dquot *dquot) ++{ ++ spin_lock(&dq_list_lock); ++ WARN_ON_ONCE(!dquot_active(dquot)); ++ dquot = __dqgrab(dquot); ++ spin_unlock(&dq_list_lock); ++ ++ return dquot; ++} ++EXPORT_SYMBOL_GPL(dqgrab); ++ + static inline int dquot_dirty(struct dquot *dquot) + { + return test_bit(DQ_MOD_B, &dquot->dq_flags); +@@ -641,15 +666,14 @@ int dquot_scan_active(struct super_block *sb, + continue; + if (dquot->dq_sb != sb) + continue; +- /* Now we have active dquot so we can just increase use count */ +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqput(old_dquot); + old_dquot = dquot; + /* + * ->release_dquot() can be racing with us. Our reference +- * protects us from new calls to it so just wait for any +- * outstanding call and recheck the DQ_ACTIVE_B after that. ++ * protects us from dquot_release() proceeding so just wait for ++ * any outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (dquot_active(dquot)) { +@@ -717,7 +741,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) + /* Now we have active dquot from which someone is + * holding reference so we can safely just increase + * use count */ +- dqgrab(dquot); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + err = dquot_write_dquot(dquot); + if (err && !ret) +@@ -963,9 +987,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_LOOKUPS); + } else { +- if (!atomic_read(&dquot->dq_count)) +- remove_free_dquot(dquot); +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_CACHE_HITS); + dqstats_inc(DQST_LOOKUPS); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index c334f82ed385a..f9c0f9d7c9d93 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -44,14 +44,7 @@ int dquot_initialize(struct inode *inode); + bool dquot_initialize_needed(struct inode *inode); + void dquot_drop(struct inode *inode); + struct dquot *dqget(struct super_block *sb, struct kqid qid); +-static inline struct dquot *dqgrab(struct dquot *dquot) +-{ +- /* Make sure someone else has active reference to dquot */ +- WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); +- WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); +- atomic_inc(&dquot->dq_count); +- return dquot; +-} ++struct dquot *dqgrab(struct dquot *dquot); + + static inline bool dquot_is_busy(struct dquot *dquot) + { +-- +2.53.0 + diff --git a/queue-6.18/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch b/queue-6.18/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch new file mode 100644 index 0000000000..cc38512aad --- /dev/null +++ b/queue-6.18/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch @@ -0,0 +1,41 @@ +From 855b19d494faf06e1e4f46fde976f4ae034937a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:39:23 +0800 +Subject: r8152: fix incorrect register write to USB_UPHY_XTAL + +From: Chih Kai Hsu + +[ Upstream commit 48afd5124fd6129c46fd12cb06155384b1c4a0c4 ] + +The old code used ocp_write_byte() to clear the OOBS_POLLING bit +(BIT(8)) in the USB_UPHY_XTAL register, but this doesn't correctly +clear a bit in the upper byte of the 16-bit register. + +Fix this by using ocp_write_word() instead. + +Fixes: 195aae321c82 ("r8152: support new chips") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Link: https://patch.msgid.link/20260326073925.32976-454-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 357f5c733d0b5..d610741782794 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -3896,7 +3896,7 @@ static void r8156_ups_en(struct r8152 *tp, bool enable) + case RTL_VER_15: + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL); + ocp_data &= ~OOBS_POLLING; +- ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); ++ ocp_write_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); + break; + default: + break; +-- +2.53.0 + diff --git a/queue-6.18/rdma-core-prefer-nla_nul_string.patch b/queue-6.18/rdma-core-prefer-nla_nul_string.patch new file mode 100644 index 0000000000..f88fc530f5 --- /dev/null +++ b/queue-6.18/rdma-core-prefer-nla_nul_string.patch @@ -0,0 +1,56 @@ +From b07e4d4cd467ac8d3c6d33139236a7e7307bc0cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:27:39 +0200 +Subject: RDMA/core: Prefer NLA_NUL_STRING + +From: Florian Westphal + +[ Upstream commit 6ed3d14fc45d3da6025e7fe4a6a09066856698e2 ] + +These attributes are evaluated as c-string (passed to strcmp), but +NLA_STRING doesn't check for the presence of a \0 terminator. + +Either this needs to switch to nla_strcmp() and needs to adjust printf fmt +specifier to not use plain %s, or this needs to use NLA_NUL_STRING. + +As the code has been this way for long time, it seems to me that userspace +does include the terminating nul, even tough its not enforced so far, and +thus NLA_NUL_STRING use is the simpler solution. + +Fixes: 30dc5e63d6a5 ("RDMA/core: Add support for iWARP Port Mapper user space service") +Link: https://patch.msgid.link/r/20260330122742.13315-1-fw@strlen.de +Signed-off-by: Florian Westphal +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwpm_msg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c +index 3c9a9869212bb..feb09008eb9ca 100644 +--- a/drivers/infiniband/core/iwpm_msg.c ++++ b/drivers/infiniband/core/iwpm_msg.c +@@ -365,9 +365,9 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) + /* netlink attribute policy for the received response to register pid request */ + static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { + [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, +- [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_DEVNAME_SIZE - 1 }, +- [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, + [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } +@@ -677,7 +677,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) + + /* netlink attribute policy for the received request for mapping info */ + static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { +- [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } + }; +-- +2.53.0 + diff --git a/queue-6.18/remoteproc-imx_rproc-check-return-value-of-regmap_at.patch b/queue-6.18/remoteproc-imx_rproc-check-return-value-of-regmap_at.patch new file mode 100644 index 0000000000..e39626b939 --- /dev/null +++ b/queue-6.18/remoteproc-imx_rproc-check-return-value-of-regmap_at.patch @@ -0,0 +1,47 @@ +From 2248a577bf1e2abd2038164d2d1858deb9f8d608 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 13:14:07 +0800 +Subject: remoteproc: imx_rproc: Check return value of regmap_attach_dev() in + imx_rproc_mmio_detect_mode() + +From: Chen Ni + +[ Upstream commit a48c6676912fb808d2af1b8344d8656815a3e108 ] + +Add error checking for regmap_attach_dev() call in +imx_rproc_mmio_detect_mode() function to ensure proper error +propagation. + +Return the value of regmap_attach_dev() if it fails to prevent +proceeding with an incomplete regmap setup. + +Suggested-by: Peng Fan +Signed-off-by: Chen Ni +Fixes: e14168bf3493 ("remoteproc: imx_rproc: Simplify IMX_RPROC_MMIO switch case") +Link: https://lore.kernel.org/r/20260209051407.1467660-1-nichen@iscas.ac.cn +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/imx_rproc.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c +index 7ef99eac37f1a..8fa81d3779849 100644 +--- a/drivers/remoteproc/imx_rproc.c ++++ b/drivers/remoteproc/imx_rproc.c +@@ -899,7 +899,11 @@ static int imx_rproc_mmio_detect_mode(struct rproc *rproc) + } + + priv->regmap = regmap; +- regmap_attach_dev(dev, regmap, &config); ++ ret = regmap_attach_dev(dev, regmap, &config); ++ if (ret) { ++ dev_err(dev, "regmap attach failed\n"); ++ return ret; ++ } + + if (priv->gpr) { + ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val); +-- +2.53.0 + diff --git a/queue-6.18/remoteproc-xlnx-fix-sram-property-parsing.patch b/queue-6.18/remoteproc-xlnx-fix-sram-property-parsing.patch new file mode 100644 index 0000000000..91747fc3f1 --- /dev/null +++ b/queue-6.18/remoteproc-xlnx-fix-sram-property-parsing.patch @@ -0,0 +1,42 @@ +From 5cb8b04997ea11713bfb3e0a551183d39cccca67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 12:27:30 -0800 +Subject: remoteproc: xlnx: Fix sram property parsing + +From: Tim Michals + +[ Upstream commit d116bccf6f1c199b27c9ebdf07cc3cfe868f919c ] + +As per sram bindings, "sram" property can be list of phandles. +When more than one sram phandles are listed, driver can't parse second +phandle's address correctly. Because, phandle index is passed to the API +instead of offset of address from reg property which is always 0 as per +sram.yaml bindings. Fix it by passing 0 to the API instead of sram +phandle index. + +Fixes: 77fcdf51b8ca ("remoteproc: xlnx: Add sram support") +Signed-off-by: Tim Michals +Signed-off-by: Tanmay Shah +Link: https://lore.kernel.org/r/20260204202730.3729984-1-tanmay.shah@amd.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/xlnx_r5_remoteproc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c +index b30f660a1c553..5ef586fd37bca 100644 +--- a/drivers/remoteproc/xlnx_r5_remoteproc.c ++++ b/drivers/remoteproc/xlnx_r5_remoteproc.c +@@ -1022,7 +1022,7 @@ static int zynqmp_r5_get_sram_banks(struct zynqmp_r5_core *r5_core) + } + + /* Get SRAM device address */ +- ret = of_property_read_reg(sram_np, i, &abs_addr, &size); ++ ret = of_property_read_reg(sram_np, 0, &abs_addr, &size); + if (ret) { + dev_err(dev, "failed to get reg property\n"); + goto fail_sram_get; +-- +2.53.0 + diff --git a/queue-6.18/reset-amlogic-t7-fix-null-reset-ops.patch b/queue-6.18/reset-amlogic-t7-fix-null-reset-ops.patch new file mode 100644 index 0000000000..b253824b64 --- /dev/null +++ b/queue-6.18/reset-amlogic-t7-fix-null-reset-ops.patch @@ -0,0 +1,36 @@ +From ef77d105b697863a76255128d462b5fd19d872ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:24:04 +0200 +Subject: reset: amlogic: t7: Fix null reset ops + +From: Ronald Claveau + +[ Upstream commit 9797524ef2b69c6b187b55bd844eb72a8c1cbd99 ] + +Fix missing reset ops causing kernel null pointer dereference. +This SOC's reset is currently not used yet. + +Signed-off-by: Ronald Claveau +Fixes: fb4c31587adf ("reset: amlogic: add auxiliary reset driver support") +Reviewed-by: Philipp Zabel +Signed-off-by: Philipp Zabel +Signed-off-by: Sasha Levin +--- + drivers/reset/amlogic/reset-meson.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/reset/amlogic/reset-meson.c b/drivers/reset/amlogic/reset-meson.c +index 84610365a823c..c303e8590dd68 100644 +--- a/drivers/reset/amlogic/reset-meson.c ++++ b/drivers/reset/amlogic/reset-meson.c +@@ -42,6 +42,7 @@ static const struct meson_reset_param meson_s4_param = { + }; + + static const struct meson_reset_param t7_param = { ++ .reset_ops = &meson_reset_ops, + .reset_num = 224, + .reset_offset = 0x0, + .level_offset = 0x40, +-- +2.53.0 + diff --git a/queue-6.18/revert-arm64-dts-rockchip-add-spdif-audio-to-beelink.patch b/queue-6.18/revert-arm64-dts-rockchip-add-spdif-audio-to-beelink.patch new file mode 100644 index 0000000000..ba1fdefd06 --- /dev/null +++ b/queue-6.18/revert-arm64-dts-rockchip-add-spdif-audio-to-beelink.patch @@ -0,0 +1,71 @@ +From c4c7f0a94b4194b897e2c4fd102d91620533c2b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 12:32:04 +0000 +Subject: Revert "arm64: dts: rockchip: add SPDIF audio to Beelink A1" + +From: Robin Murphy + +[ Upstream commit 03978cb18059ecd27e3d955508b18cf2a1196142 ] + +This reverts commit bdc4d388c6452498ab62ef2564589f40e0c8c262. + +While Beelink A1 mostly follows the high-end RK3328 reference design, +it does not in fact have the S/PDIF connector, only HDMI and a 3.5mm +jack for the analog audio/TV codecs - the tiny form factor literally +doesn't have room to fit more! + +Cc: Christian Hewitt +Cc: Alex Bee +Fixes: bdc4d388c645 ("arm64: dts: rockchip: add SPDIF audio to Beelink A1") +Signed-off-by: Robin Murphy +Link: https://patch.msgid.link/0af77a02c2b0806d4ca72066392a5453fcc89a8f.1767111968.git.robin.murphy@arm.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3328-a1.dts | 23 ---------------------- + 1 file changed, 23 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts +index 30bdb38f0727a..e810ed146451c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts +@@ -58,24 +58,6 @@ ir-receiver { + gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; + linux,rc-map-name = "rc-beelink-gs1"; + }; +- +- spdif_dit: spdif-dit { +- compatible = "linux,spdif-dit"; +- #sound-dai-cells = <0>; +- }; +- +- spdif_sound: spdif-sound { +- compatible = "simple-audio-card"; +- simple-audio-card,name = "SPDIF"; +- +- simple-audio-card,cpu { +- sound-dai = <&spdif>; +- }; +- +- simple-audio-card,codec { +- sound-dai = <&spdif_dit>; +- }; +- }; + }; + + &analog_sound { +@@ -343,11 +325,6 @@ &sdmmc { + status = "okay"; + }; + +-&spdif { +- pinctrl-0 = <&spdifm0_tx>; +- status = "okay"; +-}; +- + &tsadc { + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; +-- +2.53.0 + diff --git a/queue-6.18/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch b/queue-6.18/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch new file mode 100644 index 0000000000..2071f45832 --- /dev/null +++ b/queue-6.18/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch @@ -0,0 +1,51 @@ +From 1e0c0a9504631073c20fdd59fd3a7c68bd548885 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 18:00:10 +0000 +Subject: rtc: abx80x: Disable alarm feature if no interrupt attached + +From: Anthony Pighin (Nokia) + +[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ] + +Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting +alarm") exposed an issue where the rtc-abx80x driver does not clear the +alarm feature bit, but instead relies on the set_alarm operation to return +invalid. + +For example, when a RTC_UIE_ON ioctl is handled, it should abort at the +feature validation. Instead, it proceeds to the rtc_timer_enqueue(), +which used to return an error from the set_alarm call. However, +following the race condition handling, which likely should not be +discarding predecing errors, a success condition is returned to the +ioctl() caller. This results in (for example): + hwclock: select() to /dev/rtc0 to wait for clock tick timed out + +Notwithstanding the validity of the race condition handling, if an interrupt +wasn't specified, or could not be attached, the driver should clear the +alarm feature bit. + +Fixes: 718a820a303c ("rtc: abx80x: add alarm support") +Signed-off-by: Anthony Pighin +Link: https://patch.msgid.link/BN0PR08MB69510928028C933749F4139383D1A@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-abx80x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c +index 3fee27914ba80..5f3a3e60a19d0 100644 +--- a/drivers/rtc/rtc-abx80x.c ++++ b/drivers/rtc/rtc-abx80x.c +@@ -933,6 +933,8 @@ static int abx80x_probe(struct i2c_client *client) + client->irq = 0; + } + } ++ if (client->irq <= 0) ++ clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); + + err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); + if (err) { +-- +2.53.0 + diff --git a/queue-6.18/rtla-fix-c-cgroup-interface.patch b/queue-6.18/rtla-fix-c-cgroup-interface.patch new file mode 100644 index 0000000000..0a3b4ee2f1 --- /dev/null +++ b/queue-6.18/rtla-fix-c-cgroup-interface.patch @@ -0,0 +1,352 @@ +From 4e5366e1e1df5ce18c095de2e5d5d13c9a4c7d6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Nov 2025 11:19:06 -0500 +Subject: rtla: Fix -C/--cgroup interface + +From: Ivan Pravdin + +[ Upstream commit 7b71f3a6986c93defbb72bb6c143e04122720cb1 ] + +Currently, user can only specify cgroup to the tracer's thread the +following ways: + + `-C[cgroup]` + `-C[=cgroup]` + `--cgroup[=cgroup]` + +If user tries to specify cgroup as `-C [cgroup]` or `--cgroup [cgroup]`, +the parser silently fails and rtla's cgroup is used for the tracer +threads. + +To make interface more user-friendly, allow user to specify cgroup in +the aforementioned way, i.e. `-C [cgroup]` and `--cgroup [cgroup]`. + +Refactor identical logic between -t/--trace and -C/--cgroup into a +common function. + +Change documentation to reflect this user interface change. + +Fixes: a957cbc02531 ("rtla: Add -C cgroup support") +Signed-off-by: Ivan Pravdin +Reviewed-by: Tomas Glozar +Link: https://lore.kernel.org/r/16132f1565cf5142b5fbd179975be370b529ced7.1762186418.git.ipravdin.official@gmail.com +[ use capital letter in subject, as required by tracing subsystem ] +Signed-off-by: Tomas Glozar +Stable-dep-of: 5b6dc659ad79 ("rtla/utils: Fix resource leak in set_comm_sched_attr()") +Signed-off-by: Sasha Levin +--- + Documentation/tools/rtla/common_options.txt | 2 +- + tools/tracing/rtla/src/osnoise_hist.c | 26 ++++++--------------- + tools/tracing/rtla/src/osnoise_top.c | 26 ++++++--------------- + tools/tracing/rtla/src/timerlat_hist.c | 26 ++++++--------------- + tools/tracing/rtla/src/timerlat_top.c | 26 ++++++--------------- + tools/tracing/rtla/src/utils.c | 26 +++++++++++++++++++++ + tools/tracing/rtla/src/utils.h | 1 + + 7 files changed, 56 insertions(+), 77 deletions(-) + +diff --git a/Documentation/tools/rtla/common_options.txt b/Documentation/tools/rtla/common_options.txt +index 77ef35d3f8317..edc8e850f5d01 100644 +--- a/Documentation/tools/rtla/common_options.txt ++++ b/Documentation/tools/rtla/common_options.txt +@@ -42,7 +42,7 @@ + - *f:prio* - use SCHED_FIFO with *prio*; + - *d:runtime[us|ms|s]:period[us|ms|s]* - use SCHED_DEADLINE with *runtime* and *period* in nanoseconds. + +-**-C**, **--cgroup**\[*=cgroup*] ++**-C**, **--cgroup** \[*cgroup*] + + Set a *cgroup* to the tracer's threads. If the **-C** option is passed without arguments, the tracer's thread will inherit **rtla**'s *cgroup*. Otherwise, the threads will be placed on the *cgroup* passed to the option. + +diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c +index d22feb4d6cc9d..ae8426f40f8f4 100644 +--- a/tools/tracing/rtla/src/osnoise_hist.c ++++ b/tools/tracing/rtla/src/osnoise_hist.c +@@ -428,9 +428,9 @@ static void osnoise_hist_usage(char *usage) + static const char * const msg[] = { + "", + " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", +- " [-T us] [-t[file]] [-e sys[:event]] [--filter ] [--trigger ] \\", ++ " [-T us] [-t [file]] [-e sys[:event]] [--filter ] [--trigger ] \\", + " [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\", +- " [--no-index] [--with-zeros] [-C[=cgroup_name]] [--warm-up]", ++ " [--no-index] [--with-zeros] [-C [cgroup_name]] [--warm-up]", + "", + " -h/--help: print this menu", + " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", +@@ -441,10 +441,10 @@ static void osnoise_hist_usage(char *usage) + " -T/--threshold us: the minimum delta to be considered a noise", + " -c/--cpus cpu-list: list of cpus to run osnoise threads", + " -H/--house-keeping cpus: run rtla control threads only on the given cpus", +- " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", ++ " -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", + " -d/--duration time[s|m|h|d]: duration of the session", + " -D/--debug: print debug info", +- " -t/--trace[file]: save the stopped trace to [file|osnoise_trace.txt]", ++ " -t/--trace [file]: save the stopped trace to [file|osnoise_trace.txt]", + " -e/--event : enable the in the trace instance, multiple -e are allowed", + " --filter : enable a trace event filter to the previous -e event", + " --trigger : enable a trace event trigger to the previous -e event", +@@ -575,13 +575,7 @@ static struct common_params + break; + case 'C': + params->common.cgroup = 1; +- if (!optarg) { +- /* will inherit this cgroup */ +- params->common.cgroup_name = NULL; +- } else if (*optarg == '=') { +- /* skip the = */ +- params->common.cgroup_name = ++optarg; +- } ++ params->common.cgroup_name = parse_optional_arg(argc, argv); + break; + case 'D': + config_debug = 1; +@@ -647,14 +641,8 @@ static struct common_params + params->threshold = get_llong_from_str(optarg); + break; + case 't': +- if (optarg) { +- if (optarg[0] == '=') +- trace_output = &optarg[1]; +- else +- trace_output = &optarg[0]; +- } else if (optind < argc && argv[optind][0] != '0') +- trace_output = argv[optind]; +- else ++ trace_output = parse_optional_arg(argc, argv); ++ if (!trace_output) + trace_output = "osnoise_trace.txt"; + break; + case '0': /* no header */ +diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c +index a8d31030c4122..6ae7cdb3bdc0d 100644 +--- a/tools/tracing/rtla/src/osnoise_top.c ++++ b/tools/tracing/rtla/src/osnoise_top.c +@@ -263,8 +263,8 @@ static void osnoise_top_usage(struct osnoise_params *params, char *usage) + + static const char * const msg[] = { + " [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", +- " [-T us] [-t[file]] [-e sys[:event]] [--filter ] [--trigger ] \\", +- " [-c cpu-list] [-H cpu-list] [-P priority] [-C[=cgroup_name]] [--warm-up s]", ++ " [-T us] [-t [file]] [-e sys[:event]] [--filter ] [--trigger ] \\", ++ " [-c cpu-list] [-H cpu-list] [-P priority] [-C [cgroup_name]] [--warm-up s]", + "", + " -h/--help: print this menu", + " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", +@@ -275,10 +275,10 @@ static void osnoise_top_usage(struct osnoise_params *params, char *usage) + " -T/--threshold us: the minimum delta to be considered a noise", + " -c/--cpus cpu-list: list of cpus to run osnoise threads", + " -H/--house-keeping cpus: run rtla control threads only on the given cpus", +- " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", ++ " -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", + " -d/--duration time[s|m|h|d]: duration of the session", + " -D/--debug: print debug info", +- " -t/--trace[file]: save the stopped trace to [file|osnoise_trace.txt]", ++ " -t/--trace [file]: save the stopped trace to [file|osnoise_trace.txt]", + " -e/--event : enable the in the trace instance, multiple -e are allowed", + " --filter : enable a trace event filter to the previous -e event", + " --trigger : enable a trace event trigger to the previous -e event", +@@ -409,13 +409,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) + break; + case 'C': + params->common.cgroup = 1; +- if (!optarg) { +- /* will inherit this cgroup */ +- params->common.cgroup_name = NULL; +- } else if (*optarg == '=') { +- /* skip the = */ +- params->common.cgroup_name = ++optarg; +- } ++ params->common.cgroup_name = parse_optional_arg(argc, argv); + break; + case 'D': + config_debug = 1; +@@ -475,14 +469,8 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) + params->common.stop_total_us = get_llong_from_str(optarg); + break; + case 't': +- if (optarg) { +- if (optarg[0] == '=') +- trace_output = &optarg[1]; +- else +- trace_output = &optarg[0]; +- } else if (optind < argc && argv[optind][0] != '-') +- trace_output = argv[optind]; +- else ++ trace_output = parse_optional_arg(argc, argv); ++ if (!trace_output) + trace_output = "osnoise_trace.txt"; + break; + case 'T': +diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c +index 3d56df3d5fa0d..311c4f18ce4c6 100644 +--- a/tools/tracing/rtla/src/timerlat_hist.c ++++ b/tools/tracing/rtla/src/timerlat_hist.c +@@ -717,9 +717,9 @@ static void timerlat_hist_usage(char *usage) + char *msg[] = { + "", + " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\", +- " [-t[file]] [-e sys[:event]] [--filter ] [--trigger ] [-c cpu-list] [-H cpu-list]\\", ++ " [-t [file]] [-e sys[:event]] [--filter ] [--trigger ] [-c cpu-list] [-H cpu-list]\\", + " [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\", +- " [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task] [-u|-k]", ++ " [--no-index] [--with-zeros] [--dma-latency us] [-C [cgroup_name]] [--no-aa] [--dump-task] [-u|-k]", + " [--warm-up s] [--deepest-idle-state n]", + "", + " -h/--help: print this menu", +@@ -730,11 +730,11 @@ static void timerlat_hist_usage(char *usage) + " -s/--stack us: save the stack trace at the IRQ if a thread latency is higher than the argument in us", + " -c/--cpus cpus: run the tracer only on the given cpus", + " -H/--house-keeping cpus: run rtla control threads only on the given cpus", +- " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", ++ " -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", + " -d/--duration time[m|h|d]: duration of the session in seconds", + " --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)", + " -D/--debug: print debug info", +- " -t/--trace[file]: save the stopped trace to [file|timerlat_trace.txt]", ++ " -t/--trace [file]: save the stopped trace to [file|timerlat_trace.txt]", + " -e/--event : enable the in the trace instance, multiple -e are allowed", + " --filter : enable a trace event filter to the previous -e event", + " --trigger : enable a trace event trigger to the previous -e event", +@@ -890,13 +890,7 @@ static struct common_params + break; + case 'C': + params->common.cgroup = 1; +- if (!optarg) { +- /* will inherit this cgroup */ +- params->common.cgroup_name = NULL; +- } else if (*optarg == '=') { +- /* skip the = */ +- params->common.cgroup_name = ++optarg; +- } ++ params->common.cgroup_name = parse_optional_arg(argc, argv); + break; + case 'b': + params->common.hist.bucket_size = get_llong_from_str(optarg); +@@ -969,14 +963,8 @@ static struct common_params + params->common.stop_total_us = get_llong_from_str(optarg); + break; + case 't': +- if (optarg) { +- if (optarg[0] == '=') +- trace_output = &optarg[1]; +- else +- trace_output = &optarg[0]; +- } else if (optind < argc && argv[optind][0] != '-') +- trace_output = argv[optind]; +- else ++ trace_output = parse_optional_arg(argc, argv); ++ if (!trace_output) + trace_output = "timerlat_trace.txt"; + break; + case 'u': +diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c +index 6cc9a3607c665..3a3b11b5beaaa 100644 +--- a/tools/tracing/rtla/src/timerlat_top.c ++++ b/tools/tracing/rtla/src/timerlat_top.c +@@ -483,8 +483,8 @@ static void timerlat_top_usage(char *usage) + static const char *const msg[] = { + "", + " usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\", +- " [[-t[file]] [-e sys[:event]] [--filter ] [--trigger ] [-c cpu-list] [-H cpu-list]\\", +- " [-P priority] [--dma-latency us] [--aa-only us] [-C[=cgroup_name]] [-u|-k] [--warm-up s] [--deepest-idle-state n]", ++ " [[-t [file]] [-e sys[:event]] [--filter ] [--trigger ] [-c cpu-list] [-H cpu-list]\\", ++ " [-P priority] [--dma-latency us] [--aa-only us] [-C [cgroup_name]] [-u|-k] [--warm-up s] [--deepest-idle-state n]", + "", + " -h/--help: print this menu", + " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", +@@ -495,11 +495,11 @@ static void timerlat_top_usage(char *usage) + " -s/--stack us: save the stack trace at the IRQ if a thread latency is higher than the argument in us", + " -c/--cpus cpus: run the tracer only on the given cpus", + " -H/--house-keeping cpus: run rtla control threads only on the given cpus", +- " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", ++ " -C/--cgroup [cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", + " -d/--duration time[s|m|h|d]: duration of the session", + " -D/--debug: print debug info", + " --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)", +- " -t/--trace[file]: save the stopped trace to [file|timerlat_trace.txt]", ++ " -t/--trace [file]: save the stopped trace to [file|timerlat_trace.txt]", + " -e/--event : enable the in the trace instance, multiple -e are allowed", + " --filter : enable a trace event filter to the previous -e event", + " --trigger : enable a trace event trigger to the previous -e event", +@@ -654,13 +654,7 @@ static struct common_params + break; + case 'C': + params->common.cgroup = 1; +- if (!optarg) { +- /* will inherit this cgroup */ +- params->common.cgroup_name = NULL; +- } else if (*optarg == '=') { +- /* skip the = */ +- params->common.cgroup_name = ++optarg; +- } ++ params->common.cgroup_name = optarg; + break; + case 'D': + config_debug = 1; +@@ -723,14 +717,8 @@ static struct common_params + params->common.stop_total_us = get_llong_from_str(optarg); + break; + case 't': +- if (optarg) { +- if (optarg[0] == '=') +- trace_output = &optarg[1]; +- else +- trace_output = &optarg[0]; +- } else if (optind < argc && argv[optind][0] != '-') +- trace_output = argv[optind]; +- else ++ trace_output = parse_optional_arg(argc, argv); ++ if (!trace_output) + trace_output = "timerlat_trace.txt"; + break; + case 'u': +diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c +index d6ab15dcb4907..bd5f34b446480 100644 +--- a/tools/tracing/rtla/src/utils.c ++++ b/tools/tracing/rtla/src/utils.c +@@ -959,3 +959,29 @@ int auto_house_keeping(cpu_set_t *monitored_cpus) + + return 1; + } ++ ++/** ++ * parse_optional_arg - Parse optional argument value ++ * ++ * Parse optional argument value, which can be in the form of: ++ * -sarg, -s/--long=arg, -s/--long arg ++ * ++ * Returns arg value if found, NULL otherwise. ++ */ ++char *parse_optional_arg(int argc, char **argv) ++{ ++ if (optarg) { ++ if (optarg[0] == '=') { ++ /* skip the = */ ++ return &optarg[1]; ++ } else { ++ return optarg; ++ } ++ /* parse argument of form -s [arg] and --long [arg]*/ ++ } else if (optind < argc && argv[optind][0] != '-') { ++ /* consume optind */ ++ return argv[optind++]; ++ } else { ++ return NULL; ++ } ++} +diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h +index a2a6f89f342d0..d8d83abf0f0d0 100644 +--- a/tools/tracing/rtla/src/utils.h ++++ b/tools/tracing/rtla/src/utils.h +@@ -24,6 +24,7 @@ long parse_seconds_duration(char *val); + void get_duration(time_t start_time, char *output, int output_size); + + int parse_cpu_list(char *cpu_list, char **monitored_cpus); ++char *parse_optional_arg(int argc, char **argv); + long long get_llong_from_str(char *start); + + static inline void +-- +2.53.0 + diff --git a/queue-6.18/rtla-replace-atoi-with-a-robust-strtoi.patch b/queue-6.18/rtla-replace-atoi-with-a-robust-strtoi.patch new file mode 100644 index 0000000000..063f640893 --- /dev/null +++ b/queue-6.18/rtla-replace-atoi-with-a-robust-strtoi.patch @@ -0,0 +1,160 @@ +From dbe762cc39e3b04ce0f27c35bbd9a880348de3f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Jan 2026 08:49:40 -0300 +Subject: rtla: Replace atoi() with a robust strtoi() + +From: Wander Lairson Costa + +[ Upstream commit 7e9dfccf8f11c26208211457c4597a466135b56a ] + +The atoi() function does not perform error checking, which can lead to +undefined behavior when parsing invalid or out-of-range strings. This +can cause issues when parsing user-provided numerical inputs, such as +signal numbers, PIDs, or CPU lists. + +To address this, introduce a new strtoi() helper function that safely +converts a string to an integer. This function validates the input and +checks for overflows, returning a negative value on failure. + +Replace all calls to atoi() with the new strtoi() function and add +proper error handling to make the parsing more robust and prevent +potential issues. + +Signed-off-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260106133655.249887-5-wander@redhat.com +Signed-off-by: Tomas Glozar +Stable-dep-of: 5b6dc659ad79 ("rtla/utils: Fix resource leak in set_comm_sched_attr()") +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/actions.c | 7 +++--- + tools/tracing/rtla/src/utils.c | 40 ++++++++++++++++++++++++++++---- + tools/tracing/rtla/src/utils.h | 2 ++ + 3 files changed, 41 insertions(+), 8 deletions(-) + +diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c +index 15986505b4376..4274fa0894b04 100644 +--- a/tools/tracing/rtla/src/actions.c ++++ b/tools/tracing/rtla/src/actions.c +@@ -181,12 +181,13 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn) + /* Takes two arguments, num (signal) and pid */ + while (token != NULL) { + if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) { +- signal = atoi(token + 4); ++ if (strtoi(token + 4, &signal)) ++ return -1; + } else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) { + if (strncmp(token + 4, "parent", 7) == 0) + pid = -1; +- else +- pid = atoi(token + 4); ++ else if (strtoi(token + 4, &pid)) ++ return -1; + } else { + /* Invalid argument */ + return -1; +diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c +index bd5f34b446480..6b7717fcd142b 100644 +--- a/tools/tracing/rtla/src/utils.c ++++ b/tools/tracing/rtla/src/utils.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include "utils.h" + +@@ -112,16 +113,18 @@ int parse_cpu_set(char *cpu_list, cpu_set_t *set) + nr_cpus = sysconf(_SC_NPROCESSORS_CONF); + + for (p = cpu_list; *p; ) { +- cpu = atoi(p); +- if (cpu < 0 || (!cpu && *p != '0') || cpu >= nr_cpus) ++ if (strtoi(p, &cpu)) ++ goto err; ++ if (cpu < 0 || cpu >= nr_cpus) + goto err; + + while (isdigit(*p)) + p++; + if (*p == '-') { + p++; +- end_cpu = atoi(p); +- if (end_cpu < cpu || (!end_cpu && *p != '0') || end_cpu >= nr_cpus) ++ if (strtoi(p, &end_cpu)) ++ goto err; ++ if (end_cpu < cpu || end_cpu >= nr_cpus) + goto err; + while (isdigit(*p)) + p++; +@@ -322,6 +325,7 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr) + struct dirent *proc_entry; + DIR *procfs; + int retval; ++ int pid; + + if (strlen(comm_prefix) >= MAX_PATH) { + err_msg("Command prefix is too long: %d < strlen(%s)\n", +@@ -341,8 +345,12 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr) + if (!retval) + continue; + ++ if (strtoi(proc_entry->d_name, &pid)) { ++ err_msg("'%s' is not a valid pid", proc_entry->d_name); ++ goto out_err; ++ } + /* procfs_is_workload_pid confirmed it is a pid */ +- retval = __set_sched_attr(atoi(proc_entry->d_name), attr); ++ retval = __set_sched_attr(pid, attr); + if (retval) { + err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name); + goto out_err; +@@ -985,3 +993,25 @@ char *parse_optional_arg(int argc, char **argv) + return NULL; + } + } ++ ++/* ++ * strtoi - convert string to integer with error checking ++ * ++ * Returns 0 on success, -1 if conversion fails or result is out of int range. ++ */ ++int strtoi(const char *s, int *res) ++{ ++ char *end_ptr; ++ long lres; ++ ++ if (!*s) ++ return -1; ++ ++ errno = 0; ++ lres = strtol(s, &end_ptr, 0); ++ if (errno || *end_ptr || lres > INT_MAX || lres < INT_MIN) ++ return -1; ++ ++ *res = (int) lres; ++ return 0; ++} +diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h +index d8d83abf0f0d0..f11d27927223c 100644 +--- a/tools/tracing/rtla/src/utils.h ++++ b/tools/tracing/rtla/src/utils.h +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + /* + * '18446744073709551615\0' +@@ -81,6 +82,7 @@ static inline int set_deepest_cpu_idle_state(unsigned int cpu, unsigned int stat + static inline int have_libcpupower_support(void) { return 0; } + #endif /* HAVE_LIBCPUPOWER_SUPPORT */ + int auto_house_keeping(cpu_set_t *monitored_cpus); ++__attribute__((__warn_unused_result__)) int strtoi(const char *s, int *res); + + #define ns_to_usf(x) (((double)x/1000)) + #define ns_to_per(total, part) ((part * 100) / (double)total) +-- +2.53.0 + diff --git a/queue-6.18/rtla-utils-fix-resource-leak-in-set_comm_sched_attr.patch b/queue-6.18/rtla-utils-fix-resource-leak-in-set_comm_sched_attr.patch new file mode 100644 index 0000000000..fd1ecc4017 --- /dev/null +++ b/queue-6.18/rtla-utils-fix-resource-leak-in-set_comm_sched_attr.patch @@ -0,0 +1,64 @@ +From c6b4f47f5419933bb4dfc14c459e80eee7f13f0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 16:46:30 -0300 +Subject: rtla/utils: Fix resource leak in set_comm_sched_attr() + +From: Wander Lairson Costa + +[ Upstream commit 5b6dc659ad792c72b3ff1be8039ae2945e030928 ] + +The set_comm_sched_attr() function opens the /proc directory via +opendir() but fails to call closedir() on its successful exit path. +If the function iterates through all processes without error, it +returns 0 directly, leaking the DIR stream pointer. + +Fix this by refactoring the function to use a single exit path. A +retval variable is introduced to track the success or failure status. +All exit points now jump to a unified out label that calls closedir() +before the function returns, ensuring the resource is always freed. + +Fixes: dada03db9bb19 ("rtla: Remove procps-ng dependency") +Signed-off-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260309195040.1019085-18-wander@redhat.com +Signed-off-by: Tomas Glozar +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/utils.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c +index 6b7717fcd142b..bf20077cca742 100644 +--- a/tools/tracing/rtla/src/utils.c ++++ b/tools/tracing/rtla/src/utils.c +@@ -347,22 +347,23 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr) + + if (strtoi(proc_entry->d_name, &pid)) { + err_msg("'%s' is not a valid pid", proc_entry->d_name); +- goto out_err; ++ retval = 1; ++ goto out; + } + /* procfs_is_workload_pid confirmed it is a pid */ + retval = __set_sched_attr(pid, attr); + if (retval) { + err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name); +- goto out_err; ++ goto out; + } + + debug_msg("Set sched attributes for pid:%s\n", proc_entry->d_name); + } +- return 0; + +-out_err: ++ retval = 0; ++out: + closedir(procfs); +- return 1; ++ return retval; + } + + #define INVALID_VAL (~0L) +-- +2.53.0 + diff --git a/queue-6.18/rust-sync-atomic-remove-bound-t-sync-for-atomic-from.patch b/queue-6.18/rust-sync-atomic-remove-bound-t-sync-for-atomic-from.patch new file mode 100644 index 0000000000..b1d210ff4d --- /dev/null +++ b/queue-6.18/rust-sync-atomic-remove-bound-t-sync-for-atomic-from.patch @@ -0,0 +1,51 @@ +From 9f4a1f1f967a3d0a4a18913b80629da6adab51c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 12:16:49 -0800 +Subject: rust: sync: atomic: Remove bound `T: Sync` for `Atomic::from_ptr()` + +From: Boqun Feng + +[ Upstream commit 4a5dc632e0b603ec1cbbf87b78de86b4b6359cff ] + +Originally, `Atomic::from_ptr()` requires `T` being a `Sync` because I +thought having the ability to do `from_ptr()` meant multiplle +`&Atomic`s shared by different threads, which was identical (or +similar) to multiple `&T`s shared by different threads. Hence `T` was +required to be `Sync`. However this is not true, since `&Atomic` is +not the same at `&T`. Moreover, having this bound makes `Atomic::<*mut +T>::from_ptr()` impossible, which is definitely not intended. Therefore +remove the `T: Sync` bound. + +[boqun: Fix title typo spotted by Alice & Gary] + +Fixes: 29c32c405e53 ("rust: sync: atomic: Add generic atomics") +Signed-off-by: Boqun Feng +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Alice Ryhl +Reviewed-by: Gary Guo +Link: https://patch.msgid.link/20260120115207.55318-2-boqun.feng@gmail.com +Link: https://patch.msgid.link/20260303201701.12204-2-boqun@kernel.org +Signed-off-by: Sasha Levin +--- + rust/kernel/sync/atomic.rs | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs +index 016a6bcaf0807..43229f0320e92 100644 +--- a/rust/kernel/sync/atomic.rs ++++ b/rust/kernel/sync/atomic.rs +@@ -202,10 +202,7 @@ pub const fn new(v: T) -> Self { + /// // no data race. + /// unsafe { Atomic::from_ptr(foo_a_ptr) }.store(2, Release); + /// ``` +- pub unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self +- where +- T: Sync, +- { ++ pub unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self { + // CAST: `T` and `Atomic` have the same size, alignment and bit validity. + // SAFETY: Per function safety requirement, `ptr` is a valid pointer and the object will + // live long enough. It's safe to return a `&Atomic` because function safety requirement +-- +2.53.0 + diff --git a/queue-6.18/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch b/queue-6.18/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch new file mode 100644 index 0000000000..1a1f55d056 --- /dev/null +++ b/queue-6.18/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch @@ -0,0 +1,103 @@ +From 759bf15a0a8e868c094408ac075fe7ebf29f79c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 18:46:25 +0100 +Subject: s390/bpf: Zero-extend bpf prog return values and kfunc arguments + +From: Ilya Leoshkevich + +[ Upstream commit 202e42e4aa890172366354b233c42c73107a3f59 ] + +s390x ABI requires callers to zero-extend unsigned arguments and +sign-extend signed arguments, and callees to zero-extend unsigned +return values and sign-extend signed return values. + +s390 BPF JIT currently implements only sign extension. Fix this +omission and implement zero extension too. + +Fixes: 528eb2cb87bc ("s390/bpf: Implement arch_prepare_bpf_trampoline()") +Reported-by: Hari Bathini +Closes: https://lore.kernel.org/bpf/20260312080113.843408-1-hbathini@linux.ibm.com/ +Signed-off-by: Ilya Leoshkevich +Tested-by: Ihor Solodrai +Link: https://lore.kernel.org/r/20260313174807.581826-1-iii@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/s390/net/bpf_jit_comp.c | 39 ++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 15 deletions(-) + +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index cf461d76e9da3..d7cdd907ac797 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -831,25 +831,34 @@ static int bpf_jit_probe_post(struct bpf_jit *jit, struct bpf_prog *fp, + } + + /* +- * Sign-extend the register if necessary ++ * Sign- or zero-extend the register if necessary + */ +-static int sign_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) ++static int sign_zero_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) + { +- if (!(flags & BTF_FMODEL_SIGNED_ARG)) +- return 0; +- + switch (size) { + case 1: +- /* lgbr %r,%r */ +- EMIT4(0xb9060000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lgbr %r,%r */ ++ EMIT4(0xb9060000, r, r); ++ else ++ /* llgcr %r,%r */ ++ EMIT4(0xb9840000, r, r); + return 0; + case 2: +- /* lghr %r,%r */ +- EMIT4(0xb9070000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lghr %r,%r */ ++ EMIT4(0xb9070000, r, r); ++ else ++ /* llghr %r,%r */ ++ EMIT4(0xb9850000, r, r); + return 0; + case 4: +- /* lgfr %r,%r */ +- EMIT4(0xb9140000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lgfr %r,%r */ ++ EMIT4(0xb9140000, r, r); ++ else ++ /* llgfr %r,%r */ ++ EMIT4(0xb9160000, r, r); + return 0; + case 8: + return 0; +@@ -1799,9 +1808,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + return -1; + + for (j = 0; j < m->nr_args; j++) { +- if (sign_extend(jit, BPF_REG_1 + j, +- m->arg_size[j], +- m->arg_flags[j])) ++ if (sign_zero_extend(jit, BPF_REG_1 + j, ++ m->arg_size[j], ++ m->arg_flags[j])) + return -1; + } + } +@@ -2555,7 +2564,7 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit, + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, p->bpf_func); + /* stg %r2,retval_off(%r15) */ + if (save_ret) { +- if (sign_extend(jit, REG_2, m->ret_size, m->ret_flags)) ++ if (sign_zero_extend(jit, REG_2, m->ret_size, m->ret_flags)) + return -1; + EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15, + tjit->retval_off); +-- +2.53.0 + diff --git a/queue-6.18/s390-cio-use-generic-driver_override-infrastructure.patch b/queue-6.18/s390-cio-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..af914dcd3d --- /dev/null +++ b/queue-6.18/s390-cio-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,122 @@ +From 70324b6b34723fd10350bc03455e87f31062ea24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:13 +0100 +Subject: s390/cio: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit ac4d8bb6e2e13e8684a76ea48d13ebaaaf5c24c4 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: ebc3d1791503 ("s390/cio: introduce driver_override on the css bus") +Reviewed-by: Vineeth Vijayan +Link: https://patch.msgid.link/20260324005919.2408620-10-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/cio.h | 5 ----- + drivers/s390/cio/css.c | 34 ++++------------------------------ + 2 files changed, 4 insertions(+), 35 deletions(-) + +diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h +index 08a5e9380e75a..bad142c536e1e 100644 +--- a/drivers/s390/cio/cio.h ++++ b/drivers/s390/cio/cio.h +@@ -103,11 +103,6 @@ struct subchannel { + struct work_struct todo_work; + struct schib_config config; + u64 dma_mask; +- /* +- * Driver name to force a match. Do not set directly, because core +- * frees it. Use driver_set_override() to set or clear it. +- */ +- const char *driver_override; + } __attribute__ ((aligned(8))); + + DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb); +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 8a70596a55447..629d3993144e1 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -160,7 +160,6 @@ static void css_subchannel_release(struct device *dev) + + sch->config.intparm = 0; + cio_commit_config(sch); +- kfree(sch->driver_override); + kfree(sch); + } + +@@ -324,37 +323,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(modalias); + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct subchannel *sch = to_subchannel(dev); +- int ret; +- +- ret = driver_set_override(dev, &sch->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct subchannel *sch = to_subchannel(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", sch->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *subch_attrs[] = { + &dev_attr_type.attr, + &dev_attr_modalias.attr, +- &dev_attr_driver_override.attr, + NULL, + }; + +@@ -1358,9 +1329,11 @@ static int css_bus_match(struct device *dev, const struct device_driver *drv) + struct subchannel *sch = to_subchannel(dev); + const struct css_driver *driver = to_cssdriver(drv); + struct css_device_id *id; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (sch->driver_override && strcmp(sch->driver_override, drv->name)) ++ ret = device_match_driver_override(dev, drv); ++ if (ret == 0) + return 0; + + for (id = driver->subchannel_type; id->match_flags; id++) { +@@ -1417,6 +1390,7 @@ static int css_uevent(const struct device *dev, struct kobj_uevent_env *env) + + static const struct bus_type css_bus_type = { + .name = "css", ++ .driver_override = true, + .match = css_bus_match, + .probe = css_probe, + .remove = css_remove, +-- +2.53.0 + diff --git a/queue-6.18/s390-mm-fix-phys_to_folio-usage-in-do_secure_storage.patch b/queue-6.18/s390-mm-fix-phys_to_folio-usage-in-do_secure_storage.patch new file mode 100644 index 0000000000..b315f9c151 --- /dev/null +++ b/queue-6.18/s390-mm-fix-phys_to_folio-usage-in-do_secure_storage.patch @@ -0,0 +1,44 @@ +From d81efa7173dbc80dff84bd430380621d28ff320f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 07:52:44 +0200 +Subject: s390/mm: Fix phys_to_folio() usage in do_secure_storage_access() + +From: Heiko Carstens + +[ Upstream commit b95e0e792822bad8fc9eb33ea3a90005e29e75e9 ] + +In case of a Secure-Storage-Access exception the effective aka virtual +address which caused the exception is contained within the TEID. + +do_secure_storage_access() incorrectly uses phys_to_folio() instead of +virt_to_folio() to translate the virtual address to the corresponding +folio. + +Fix this by using virt_to_folio() instead of phys_to_folio(). + +Fixes: 084ea4d611a3 ("s390/mm: add (non)secure page access exceptions handlers") +Reviewed-by: Christian Borntraeger +Reviewed-by: Claudio Imbrenda +Signed-off-by: Heiko Carstens +Signed-off-by: Alexander Gordeev +Signed-off-by: Sasha Levin +--- + arch/s390/mm/fault.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c +index d1f165048055b..069f72703a915 100644 +--- a/arch/s390/mm/fault.c ++++ b/arch/s390/mm/fault.c +@@ -433,7 +433,7 @@ void do_secure_storage_access(struct pt_regs *regs) + panic("Unexpected PGM 0x3d with TEID bit 61=0"); + } + if (is_kernel_fault(regs)) { +- folio = phys_to_folio(addr); ++ folio = virt_to_folio((void *)addr); + if (unlikely(!folio_try_get(folio))) + return; + rc = uv_convert_from_secure(folio_to_phys(folio)); +-- +2.53.0 + diff --git a/queue-6.18/sched-ext-implement-cgroup_set_idle-callback.patch b/queue-6.18/sched-ext-implement-cgroup_set_idle-callback.patch new file mode 100644 index 0000000000..e76bcffcb1 --- /dev/null +++ b/queue-6.18/sched-ext-implement-cgroup_set_idle-callback.patch @@ -0,0 +1,126 @@ +From b7b9ddd52572fe8d0999457472afe0d726087584 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 12:33:21 -0400 +Subject: sched/ext: Implement cgroup_set_idle() callback + +From: zhidao su + +[ Upstream commit 347ed2d566dabb06c7970fff01129c4f59995ed6 ] + +Implement the missing cgroup_set_idle() callback that was marked as a +TODO. This allows BPF schedulers to be notified when a cgroup's idle +state changes, enabling them to adjust their scheduling behavior +accordingly. + +The implementation follows the same pattern as other cgroup callbacks +like cgroup_set_weight() and cgroup_set_bandwidth(). It checks if the +BPF scheduler has implemented the callback and invokes it with the +appropriate parameters. + +Fixes a spelling error in the cgroup_set_bandwidth() documentation. + +tj: s/scx_cgroup_rwsem/scx_cgroup_ops_rwsem/ to fix build breakage. + +Signed-off-by: zhidao su +Signed-off-by: Tejun Heo +Stable-dep-of: 80afd4c84bc8 ("sched_ext: Read scx_root under scx_cgroup_ops_rwsem in cgroup setters") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/sched/ext.h | 1 + + kernel/sched/ext.c | 16 +++++++++++++++- + kernel/sched/ext_internal.h | 13 ++++++++++++- + 3 files changed, 28 insertions(+), 2 deletions(-) + +diff --git a/include/linux/sched/ext.h b/include/linux/sched/ext.h +index d82b7a9b0658b..9848aeab27864 100644 +--- a/include/linux/sched/ext.h ++++ b/include/linux/sched/ext.h +@@ -228,6 +228,7 @@ struct scx_task_group { + u64 bw_period_us; + u64 bw_quota_us; + u64 bw_burst_us; ++ bool idle; + #endif + }; + +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index ee031ba877d9c..423098966a291 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -3118,6 +3118,7 @@ void scx_tg_init(struct task_group *tg) + tg->scx.weight = CGROUP_WEIGHT_DFL; + tg->scx.bw_period_us = default_bw_period_us(); + tg->scx.bw_quota_us = RUNTIME_INF; ++ tg->scx.idle = false; + } + + int scx_tg_online(struct task_group *tg) +@@ -3266,7 +3267,18 @@ void scx_group_set_weight(struct task_group *tg, unsigned long weight) + + void scx_group_set_idle(struct task_group *tg, bool idle) + { +- /* TODO: Implement ops->cgroup_set_idle() */ ++ struct scx_sched *sch = scx_root; ++ ++ percpu_down_read(&scx_cgroup_ops_rwsem); ++ ++ if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_idle)) ++ SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_set_idle, NULL, ++ tg_cgrp(tg), idle); ++ ++ /* Update the task group's idle state */ ++ tg->scx.idle = idle; ++ ++ percpu_up_read(&scx_cgroup_ops_rwsem); + } + + void scx_group_set_bandwidth(struct task_group *tg, +@@ -5126,6 +5138,7 @@ static void sched_ext_ops__cgroup_move(struct task_struct *p, struct cgroup *fro + static void sched_ext_ops__cgroup_cancel_move(struct task_struct *p, struct cgroup *from, struct cgroup *to) {} + static void sched_ext_ops__cgroup_set_weight(struct cgroup *cgrp, u32 weight) {} + static void sched_ext_ops__cgroup_set_bandwidth(struct cgroup *cgrp, u64 period_us, u64 quota_us, u64 burst_us) {} ++static void sched_ext_ops__cgroup_set_idle(struct cgroup *cgrp, bool idle) {} + #endif + static void sched_ext_ops__cpu_online(s32 cpu) {} + static void sched_ext_ops__cpu_offline(s32 cpu) {} +@@ -5164,6 +5177,7 @@ static struct sched_ext_ops __bpf_ops_sched_ext_ops = { + .cgroup_cancel_move = sched_ext_ops__cgroup_cancel_move, + .cgroup_set_weight = sched_ext_ops__cgroup_set_weight, + .cgroup_set_bandwidth = sched_ext_ops__cgroup_set_bandwidth, ++ .cgroup_set_idle = sched_ext_ops__cgroup_set_idle, + #endif + .cpu_online = sched_ext_ops__cpu_online, + .cpu_offline = sched_ext_ops__cpu_offline, +diff --git a/kernel/sched/ext_internal.h b/kernel/sched/ext_internal.h +index 8039a750490f8..5b2dd105fa92a 100644 +--- a/kernel/sched/ext_internal.h ++++ b/kernel/sched/ext_internal.h +@@ -697,12 +697,23 @@ struct sched_ext_ops { + * 2_500_000. @cgrp is entitled to 2.5 CPUs. @burst_us can be + * interpreted in the same fashion and specifies how much @cgrp can + * burst temporarily. The specific control mechanism and thus the +- * interpretation of @period_us and burstiness is upto to the BPF ++ * interpretation of @period_us and burstiness is up to the BPF + * scheduler. + */ + void (*cgroup_set_bandwidth)(struct cgroup *cgrp, + u64 period_us, u64 quota_us, u64 burst_us); + ++ /** ++ * @cgroup_set_idle: A cgroup's idle state is being changed ++ * @cgrp: cgroup whose idle state is being updated ++ * @idle: whether the cgroup is entering or exiting idle state ++ * ++ * Update @cgrp's idle state to @idle. This callback is invoked when ++ * a cgroup transitions between idle and non-idle states, allowing the ++ * BPF scheduler to adjust its behavior accordingly. ++ */ ++ void (*cgroup_set_idle)(struct cgroup *cgrp, bool idle); ++ + #endif /* CONFIG_EXT_GROUP_SCHED */ + + /* +-- +2.53.0 + diff --git a/queue-6.18/sched-fair-clear-rel_deadline-when-initializing-fork.patch b/queue-6.18/sched-fair-clear-rel_deadline-when-initializing-fork.patch new file mode 100644 index 0000000000..7df1ee931e --- /dev/null +++ b/queue-6.18/sched-fair-clear-rel_deadline-when-initializing-fork.patch @@ -0,0 +1,87 @@ +From d2eca7aa1fc7973b3f941693bab04f2bc5d77e44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 07:11:13 +0000 +Subject: sched/fair: Clear rel_deadline when initializing forked entities + +From: Zicheng Qu + +[ Upstream commit 3da56dc063cd77b9c0b40add930767fab4e389f3 ] + +A yield-triggered crash can happen when a newly forked sched_entity +enters the fair class with se->rel_deadline unexpectedly set. + +The failing sequence is: + + 1. A task is forked while se->rel_deadline is still set. + 2. __sched_fork() initializes vruntime, vlag and other sched_entity + state, but does not clear rel_deadline. + 3. On the first enqueue, enqueue_entity() calls place_entity(). + 4. Because se->rel_deadline is set, place_entity() treats se->deadline + as a relative deadline and converts it to an absolute deadline by + adding the current vruntime. + 5. However, the forked entity's deadline is not a valid inherited + relative deadline for this new scheduling instance, so the conversion + produces an abnormally large deadline. + 6. If the task later calls sched_yield(), yield_task_fair() advances + se->vruntime to se->deadline. + 7. The inflated vruntime is then used by the following enqueue path, + where the vruntime-derived key can overflow when multiplied by the + entity weight. + 8. This corrupts cfs_rq->sum_w_vruntime, breaks EEVDF eligibility + calculation, and can eventually make all entities appear ineligible. + pick_next_entity() may then return NULL unexpectedly, leading to a + later NULL dereference. + +A captured trace shows the effect clearly. Before yield, the entity's +vruntime was around: + + 9834017729983308 + +After yield_task_fair() executed: + + se->vruntime = se->deadline + +the vruntime jumped to: + + 19668035460670230 + +and the deadline was later advanced further to: + + 19668035463470230 + +This shows that the deadline had already become abnormally large before +yield_task_fair() copied it into vruntime. + +rel_deadline is only meaningful when se->deadline really carries a +relative deadline that still needs to be placed against vruntime. A +freshly forked sched_entity should not inherit or retain this state. +Clear se->rel_deadline in __sched_fork(), together with the other +sched_entity runtime state, so that the first enqueue does not interpret +the new entity's deadline as a stale relative deadline. + +Fixes: 82e9d0456e06 ("sched/fair: Avoid re-setting virtual deadline on 'migrations'") +Analyzed-by: Hui Tang +Analyzed-by: Zhang Qiao +Signed-off-by: Zicheng Qu +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260424071113.1199600-1-quzicheng@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 522d4bad56ad1..b42a65a79b701 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -4453,6 +4453,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p) + p->se.nr_migrations = 0; + p->se.vruntime = 0; + p->se.vlag = 0; ++ p->se.rel_deadline = 0; + INIT_LIST_HEAD(&p->se.group_node); + + /* A delayed task cannot be in clone(). */ +-- +2.53.0 + diff --git a/queue-6.18/sched-fair-fix-wakeup_preempt_fair-vs-delayed-dequeu.patch b/queue-6.18/sched-fair-fix-wakeup_preempt_fair-vs-delayed-dequeu.patch new file mode 100644 index 0000000000..d007ad7055 --- /dev/null +++ b/queue-6.18/sched-fair-fix-wakeup_preempt_fair-vs-delayed-dequeu.patch @@ -0,0 +1,118 @@ +From 246442d1dab2dae1dc658f92daa3f518967aaa1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 11:34:00 +0200 +Subject: sched/fair: Fix wakeup_preempt_fair() vs delayed dequeue + +From: Vincent Guittot + +[ Upstream commit ac8e69e693631689d74d8f1ebee6f84f737f797f ] + +Similar to how pick_next_entity() must dequeue delayed entities, so too must +wakeup_preempt_fair(). Any delayed task being found means it is eligible and +hence past the 0-lag point, ready for removal. + +Worse, by not removing delayed entities from consideration, it can skew the +preemption decision, with the end result that a short slice wakeup will not +result in a preemption. + + tip/sched/core tip/sched/core +this patch +cyclictest slice (ms) (default)2.8 8 8 +hackbench slice (ms) (default)2.8 20 20 +Total Samples | 22559 22595 22683 +Average (us) | 157 64( 59%) 59( 8%) +Median (P50) (us) | 57 57( 0%) 58(- 2%) +90th Percentile (us) | 64 60( 6%) 60( 0%) +99th Percentile (us) | 2407 67( 97%) 67( 0%) +99.9th Percentile (us) | 3400 2288( 33%) 727( 68%) +Maximum (us) | 5037 9252(-84%) 7461( 19%) + +Fixes: f12e148892ed ("sched/fair: Prepare pick_next_task() for delayed dequeue") +Signed-off-by: Vincent Guittot +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260422093400.319251-1-vincent.guittot@linaro.org +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 293a8804428b0..565a96d6811e7 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -1007,7 +1007,7 @@ static inline void cancel_protect_slice(struct sched_entity *se) + * + * Which allows tree pruning through eligibility. + */ +-static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect) ++static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect) + { + struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node; + struct sched_entity *se = __pick_first_entity(cfs_rq); +@@ -1078,11 +1078,6 @@ static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect) + return best; + } + +-static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq) +-{ +- return __pick_eevdf(cfs_rq, true); +-} +- + struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) + { + struct rb_node *last = rb_last(&cfs_rq->tasks_timeline.rb_root); +@@ -5584,11 +5579,11 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags); + * 4) do not run the "skip" process, if something else is available + */ + static struct sched_entity * +-pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq) ++pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq, bool protect) + { + struct sched_entity *se; + +- se = pick_eevdf(cfs_rq); ++ se = pick_eevdf(cfs_rq, protect); + if (se->sched_delayed) { + dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED); + /* +@@ -8868,7 +8863,7 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int + { + enum preempt_wakeup_action preempt_action = PREEMPT_WAKEUP_PICK; + struct task_struct *donor = rq->donor; +- struct sched_entity *se = &donor->se, *pse = &p->se; ++ struct sched_entity *nse, *se = &donor->se, *pse = &p->se; + struct cfs_rq *cfs_rq = task_cfs_rq(donor); + int cse_is_idle, pse_is_idle; + +@@ -8983,11 +8978,17 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int + } + + pick: ++ nse = pick_next_entity(rq, cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT); ++ /* If @p has become the most eligible task, force preemption */ ++ if (nse == pse) ++ goto preempt; ++ + /* +- * If @p has become the most eligible task, force preemption. ++ * Because p is enqueued, nse being null can only mean that we ++ * dequeued a delayed task. + */ +- if (__pick_eevdf(cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT) == pse) +- goto preempt; ++ if (!nse) ++ goto pick; + + if (sched_feat(RUN_TO_PARITY)) + update_protect_slice(cfs_rq, se); +@@ -9022,7 +9023,7 @@ static struct task_struct *pick_task_fair(struct rq *rq) + + throttled |= check_cfs_rq_runtime(cfs_rq); + +- se = pick_next_entity(rq, cfs_rq); ++ se = pick_next_entity(rq, cfs_rq, true); + if (!se) + goto again; + cfs_rq = group_cfs_rq(se); +-- +2.53.0 + diff --git a/queue-6.18/sched-fair-reimplement-next_buddy-to-align-with-eevd.patch b/queue-6.18/sched-fair-reimplement-next_buddy-to-align-with-eevd.patch new file mode 100644 index 0000000000..b7070f5dd6 --- /dev/null +++ b/queue-6.18/sched-fair-reimplement-next_buddy-to-align-with-eevd.patch @@ -0,0 +1,435 @@ +From c8b8228bffc06285b3cc061ac687ef4a70798e57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Nov 2025 12:25:21 +0000 +Subject: sched/fair: Reimplement NEXT_BUDDY to align with EEVDF goals + +From: Mel Gorman + +[ Upstream commit e837456fdca81899a3c8e47b3fd39e30eae6e291 ] + +Reimplement NEXT_BUDDY preemption to take into account the deadline and +eligibility of the wakee with respect to the waker. In the event +multiple buddies could be considered, the one with the earliest deadline +is selected. + +Sync wakeups are treated differently to every other type of wakeup. The +WF_SYNC assumption is that the waker promises to sleep in the very near +future. This is violated in enough cases that WF_SYNC should be treated +as a suggestion instead of a contract. If a waker does go to sleep almost +immediately then the delay in wakeup is negligible. In other cases, it's +throttled based on the accumulated runtime of the waker so there is a +chance that some batched wakeups have been issued before preemption. + +For all other wakeups, preemption happens if the wakee has a earlier +deadline than the waker and eligible to run. + +While many workloads were tested, the two main targets were a modified +dbench4 benchmark and hackbench because the are on opposite ends of the +spectrum -- one prefers throughput by avoiding preemption and the other +relies on preemption. + +First is the dbench throughput data even though it is a poor metric but +it is the default metric. The test machine is a 2-socket machine and the +backing filesystem is XFS as a lot of the IO work is dispatched to kernel +threads. It's important to note that these results are not representative +across all machines, especially Zen machines, as different bottlenecks +are exposed on different machines and filesystems. + +dbench4 Throughput (misleading but traditional) + 6.18-rc1 6.18-rc1 + vanilla sched-preemptnext-v5 +Hmean 1 1268.80 ( 0.00%) 1269.74 ( 0.07%) +Hmean 4 3971.74 ( 0.00%) 3950.59 ( -0.53%) +Hmean 7 5548.23 ( 0.00%) 5420.08 ( -2.31%) +Hmean 12 7310.86 ( 0.00%) 7165.57 ( -1.99%) +Hmean 21 8874.53 ( 0.00%) 9149.04 ( 3.09%) +Hmean 30 9361.93 ( 0.00%) 10530.04 ( 12.48%) +Hmean 48 9540.14 ( 0.00%) 11820.40 ( 23.90%) +Hmean 79 9208.74 ( 0.00%) 12193.79 ( 32.42%) +Hmean 110 8573.12 ( 0.00%) 11933.72 ( 39.20%) +Hmean 141 7791.33 ( 0.00%) 11273.90 ( 44.70%) +Hmean 160 7666.60 ( 0.00%) 10768.72 ( 40.46%) + +As throughput is misleading, the benchmark is modified to use a short +loadfile report the completion time duration in milliseconds. + +dbench4 Loadfile Execution Time + 6.18-rc1 6.18-rc1 + vanilla sched-preemptnext-v5 +Amean 1 14.62 ( 0.00%) 14.69 ( -0.46%) +Amean 4 18.76 ( 0.00%) 18.85 ( -0.45%) +Amean 7 23.71 ( 0.00%) 24.38 ( -2.82%) +Amean 12 31.25 ( 0.00%) 31.87 ( -1.97%) +Amean 21 45.12 ( 0.00%) 43.69 ( 3.16%) +Amean 30 61.07 ( 0.00%) 54.33 ( 11.03%) +Amean 48 95.91 ( 0.00%) 77.22 ( 19.49%) +Amean 79 163.38 ( 0.00%) 123.08 ( 24.66%) +Amean 110 243.91 ( 0.00%) 175.11 ( 28.21%) +Amean 141 343.47 ( 0.00%) 239.10 ( 30.39%) +Amean 160 401.15 ( 0.00%) 283.73 ( 29.27%) +Stddev 1 0.52 ( 0.00%) 0.51 ( 2.45%) +Stddev 4 1.36 ( 0.00%) 1.30 ( 4.04%) +Stddev 7 1.88 ( 0.00%) 1.87 ( 0.72%) +Stddev 12 3.06 ( 0.00%) 2.45 ( 19.83%) +Stddev 21 5.78 ( 0.00%) 3.87 ( 33.06%) +Stddev 30 9.85 ( 0.00%) 5.25 ( 46.76%) +Stddev 48 22.31 ( 0.00%) 8.64 ( 61.27%) +Stddev 79 35.96 ( 0.00%) 18.07 ( 49.76%) +Stddev 110 59.04 ( 0.00%) 30.93 ( 47.61%) +Stddev 141 85.38 ( 0.00%) 40.93 ( 52.06%) +Stddev 160 96.38 ( 0.00%) 39.72 ( 58.79%) + +That is still looking good and the variance is reduced quite a bit. +Finally, fairness is a concern so the next report tracks how many +milliseconds does it take for all clients to complete a workfile. This +one is tricky because dbench makes to effort to synchronise clients so +the durations at benchmark start time differ substantially from typical +runtimes. This problem could be mitigated by warming up the benchmark +for a number of minutes but it's a matter of opinion whether that +counts as an evasion of inconvenient results. + +dbench4 All Clients Loadfile Execution Time + 6.18-rc1 6.18-rc1 + vanilla sched-preemptnext-v5 +Amean 1 15.06 ( 0.00%) 15.07 ( -0.03%) +Amean 4 603.81 ( 0.00%) 524.29 ( 13.17%) +Amean 7 855.32 ( 0.00%) 1331.07 ( -55.62%) +Amean 12 1890.02 ( 0.00%) 2323.97 ( -22.96%) +Amean 21 3195.23 ( 0.00%) 2009.29 ( 37.12%) +Amean 30 13919.53 ( 0.00%) 4579.44 ( 67.10%) +Amean 48 25246.07 ( 0.00%) 5705.46 ( 77.40%) +Amean 79 29701.84 ( 0.00%) 15509.26 ( 47.78%) +Amean 110 22803.03 ( 0.00%) 23782.08 ( -4.29%) +Amean 141 36356.07 ( 0.00%) 25074.20 ( 31.03%) +Amean 160 17046.71 ( 0.00%) 13247.62 ( 22.29%) +Stddev 1 0.47 ( 0.00%) 0.49 ( -3.74%) +Stddev 4 395.24 ( 0.00%) 254.18 ( 35.69%) +Stddev 7 467.24 ( 0.00%) 764.42 ( -63.60%) +Stddev 12 1071.43 ( 0.00%) 1395.90 ( -30.28%) +Stddev 21 1694.50 ( 0.00%) 1204.89 ( 28.89%) +Stddev 30 7945.63 ( 0.00%) 2552.59 ( 67.87%) +Stddev 48 14339.51 ( 0.00%) 3227.55 ( 77.49%) +Stddev 79 16620.91 ( 0.00%) 8422.15 ( 49.33%) +Stddev 110 12912.15 ( 0.00%) 13560.95 ( -5.02%) +Stddev 141 20700.13 ( 0.00%) 14544.51 ( 29.74%) +Stddev 160 9079.16 ( 0.00%) 7400.69 ( 18.49%) + +This is more of a mixed bag but it at least shows that fairness +is not crippled. + +The hackbench results are more neutral but this is still important. +It's possible to boost the dbench figures by a large amount but only by +crippling the performance of a workload like hackbench. The WF_SYNC +behaviour is important for these workloads and is why the WF_SYNC +changes are not a separate patch. + +hackbench-process-pipes + 6.18-rc1 6.18-rc1 + vanilla sched-preemptnext-v5 +Amean 1 0.2657 ( 0.00%) 0.2150 ( 19.07%) +Amean 4 0.6107 ( 0.00%) 0.6060 ( 0.76%) +Amean 7 0.7923 ( 0.00%) 0.7440 ( 6.10%) +Amean 12 1.1500 ( 0.00%) 1.1263 ( 2.06%) +Amean 21 1.7950 ( 0.00%) 1.7987 ( -0.20%) +Amean 30 2.3207 ( 0.00%) 2.5053 ( -7.96%) +Amean 48 3.5023 ( 0.00%) 3.9197 ( -11.92%) +Amean 79 4.8093 ( 0.00%) 5.2247 ( -8.64%) +Amean 110 6.1160 ( 0.00%) 6.6650 ( -8.98%) +Amean 141 7.4763 ( 0.00%) 7.8973 ( -5.63%) +Amean 172 8.9560 ( 0.00%) 9.3593 ( -4.50%) +Amean 203 10.4783 ( 0.00%) 10.8347 ( -3.40%) +Amean 234 12.4977 ( 0.00%) 13.0177 ( -4.16%) +Amean 265 14.7003 ( 0.00%) 15.5630 ( -5.87%) +Amean 296 16.1007 ( 0.00%) 17.4023 ( -8.08%) + +Processes using pipes are impacted but the variance (not presented) indicates +it's close to noise and the results are not always reproducible. If executed +across multiple reboots, it may show neutral or small gains so the worst +measured results are presented. + +Hackbench using sockets is more reliably neutral as the wakeup +mechanisms are different between sockets and pipes. + +hackbench-process-sockets + 6.18-rc1 6.18-rc1 + vanilla sched-preemptnext-v2 +Amean 1 0.3073 ( 0.00%) 0.3263 ( -6.18%) +Amean 4 0.7863 ( 0.00%) 0.7930 ( -0.85%) +Amean 7 1.3670 ( 0.00%) 1.3537 ( 0.98%) +Amean 12 2.1337 ( 0.00%) 2.1903 ( -2.66%) +Amean 21 3.4683 ( 0.00%) 3.4940 ( -0.74%) +Amean 30 4.7247 ( 0.00%) 4.8853 ( -3.40%) +Amean 48 7.6097 ( 0.00%) 7.8197 ( -2.76%) +Amean 79 14.7957 ( 0.00%) 16.1000 ( -8.82%) +Amean 110 21.3413 ( 0.00%) 21.9997 ( -3.08%) +Amean 141 29.0503 ( 0.00%) 29.0353 ( 0.05%) +Amean 172 36.4660 ( 0.00%) 36.1433 ( 0.88%) +Amean 203 39.7177 ( 0.00%) 40.5910 ( -2.20%) +Amean 234 42.1120 ( 0.00%) 43.5527 ( -3.42%) +Amean 265 45.7830 ( 0.00%) 50.0560 ( -9.33%) +Amean 296 50.7043 ( 0.00%) 54.3657 ( -7.22%) + +As schbench has been mentioned in numerous bugs recently, the results +are interesting. A test case that represents the default schbench +behaviour is + +schbench Wakeup Latency (usec) + 6.18.0-rc1 6.18.0-rc1 + vanilla sched-preemptnext-v5 +Amean Wakeup-50th-80 7.17 ( 0.00%) 6.00 ( 16.28%) +Amean Wakeup-90th-80 46.56 ( 0.00%) 19.78 ( 57.52%) +Amean Wakeup-99th-80 119.61 ( 0.00%) 89.94 ( 24.80%) +Amean Wakeup-99.9th-80 3193.78 ( 0.00%) 328.22 ( 89.72%) + +schbench Requests Per Second (ops/sec) + 6.18.0-rc1 6.18.0-rc1 + vanilla sched-preemptnext-v5 +Hmean RPS-20th-80 8900.91 ( 0.00%) 9176.78 ( 3.10%) +Hmean RPS-50th-80 8987.41 ( 0.00%) 9217.89 ( 2.56%) +Hmean RPS-90th-80 9123.73 ( 0.00%) 9273.25 ( 1.64%) +Hmean RPS-max-80 9193.50 ( 0.00%) 9301.47 ( 1.17%) + +Signed-off-by: Mel Gorman +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20251112122521.1331238-3-mgorman@techsingularity.net +Stable-dep-of: ac8e69e69363 ("sched/fair: Fix wakeup_preempt_fair() vs delayed dequeue") +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 152 +++++++++++++++++++++++++++++++++++++------- + 1 file changed, 130 insertions(+), 22 deletions(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index d9777c81db0da..293a8804428b0 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -1021,6 +1021,16 @@ static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect) + if (cfs_rq->nr_queued == 1) + return curr && curr->on_rq ? curr : se; + ++ /* ++ * Picking the ->next buddy will affect latency but not fairness. ++ */ ++ if (sched_feat(PICK_BUDDY) && ++ cfs_rq->next && entity_eligible(cfs_rq, cfs_rq->next)) { ++ /* ->next will never be delayed */ ++ WARN_ON_ONCE(cfs_rq->next->sched_delayed); ++ return cfs_rq->next; ++ } ++ + if (curr && (!curr->on_rq || !entity_eligible(cfs_rq, curr))) + curr = NULL; + +@@ -1260,6 +1270,8 @@ static s64 update_se(struct rq *rq, struct sched_entity *se) + return delta_exec; + } + ++static void set_next_buddy(struct sched_entity *se); ++ + /* + * Used by other classes to account runtime. + */ +@@ -5576,16 +5588,6 @@ pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq) + { + struct sched_entity *se; + +- /* +- * Picking the ->next buddy will affect latency but not fairness. +- */ +- if (sched_feat(PICK_BUDDY) && +- cfs_rq->next && entity_eligible(cfs_rq, cfs_rq->next)) { +- /* ->next will never be delayed */ +- WARN_ON_ONCE(cfs_rq->next->sched_delayed); +- return cfs_rq->next; +- } +- + se = pick_eevdf(cfs_rq); + if (se->sched_delayed) { + dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED); +@@ -7099,8 +7101,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) + hrtick_update(rq); + } + +-static void set_next_buddy(struct sched_entity *se); +- + /* + * Basically dequeue_task_fair(), except it can deal with dequeue_entity() + * failing half-way through and resume the dequeue later. +@@ -8796,16 +8796,81 @@ static void set_next_buddy(struct sched_entity *se) + } + } + ++enum preempt_wakeup_action { ++ PREEMPT_WAKEUP_NONE, /* No preemption. */ ++ PREEMPT_WAKEUP_SHORT, /* Ignore slice protection. */ ++ PREEMPT_WAKEUP_PICK, /* Let __pick_eevdf() decide. */ ++ PREEMPT_WAKEUP_RESCHED, /* Force reschedule. */ ++}; ++ ++static inline bool ++set_preempt_buddy(struct cfs_rq *cfs_rq, int wake_flags, ++ struct sched_entity *pse, struct sched_entity *se) ++{ ++ /* ++ * Keep existing buddy if the deadline is sooner than pse. ++ * The older buddy may be cache cold and completely unrelated ++ * to the current wakeup but that is unpredictable where as ++ * obeying the deadline is more in line with EEVDF objectives. ++ */ ++ if (cfs_rq->next && entity_before(cfs_rq->next, pse)) ++ return false; ++ ++ set_next_buddy(pse); ++ return true; ++} ++ ++/* ++ * WF_SYNC|WF_TTWU indicates the waker expects to sleep but it is not ++ * strictly enforced because the hint is either misunderstood or ++ * multiple tasks must be woken up. ++ */ ++static inline enum preempt_wakeup_action ++preempt_sync(struct rq *rq, int wake_flags, ++ struct sched_entity *pse, struct sched_entity *se) ++{ ++ u64 threshold, delta; ++ ++ /* ++ * WF_SYNC without WF_TTWU is not expected so warn if it happens even ++ * though it is likely harmless. ++ */ ++ WARN_ON_ONCE(!(wake_flags & WF_TTWU)); ++ ++ threshold = sysctl_sched_migration_cost; ++ delta = rq_clock_task(rq) - se->exec_start; ++ if ((s64)delta < 0) ++ delta = 0; ++ ++ /* ++ * WF_RQ_SELECTED implies the tasks are stacking on a CPU when they ++ * could run on other CPUs. Reduce the threshold before preemption is ++ * allowed to an arbitrary lower value as it is more likely (but not ++ * guaranteed) the waker requires the wakee to finish. ++ */ ++ if (wake_flags & WF_RQ_SELECTED) ++ threshold >>= 2; ++ ++ /* ++ * As WF_SYNC is not strictly obeyed, allow some runtime for batch ++ * wakeups to be issued. ++ */ ++ if (entity_before(pse, se) && delta >= threshold) ++ return PREEMPT_WAKEUP_RESCHED; ++ ++ return PREEMPT_WAKEUP_NONE; ++} ++ + /* + * Preempt the current task with a newly woken task if needed: + */ + static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int wake_flags) + { ++ enum preempt_wakeup_action preempt_action = PREEMPT_WAKEUP_PICK; + struct task_struct *donor = rq->donor; + struct sched_entity *se = &donor->se, *pse = &p->se; + struct cfs_rq *cfs_rq = task_cfs_rq(donor); + int cse_is_idle, pse_is_idle; +- bool do_preempt_short = false; + + if (unlikely(se == pse)) + return; +@@ -8819,10 +8884,6 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int + if (task_is_throttled(p)) + return; + +- if (sched_feat(NEXT_BUDDY) && !(wake_flags & WF_FORK) && !pse->sched_delayed) { +- set_next_buddy(pse); +- } +- + /* + * We can come here with TIF_NEED_RESCHED already set from new task + * wake up path. +@@ -8854,7 +8915,7 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int + * When non-idle entity preempt an idle entity, + * don't give idle entity slice protection. + */ +- do_preempt_short = true; ++ preempt_action = PREEMPT_WAKEUP_SHORT; + goto preempt; + } + +@@ -8873,21 +8934,68 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int + * If @p has a shorter slice than current and @p is eligible, override + * current's slice protection in order to allow preemption. + */ +- do_preempt_short = sched_feat(PREEMPT_SHORT) && (pse->slice < se->slice); ++ if (sched_feat(PREEMPT_SHORT) && (pse->slice < se->slice)) { ++ preempt_action = PREEMPT_WAKEUP_SHORT; ++ goto pick; ++ } + ++ /* ++ * Ignore wakee preemption on WF_FORK as it is less likely that ++ * there is shared data as exec often follow fork. Do not ++ * preempt for tasks that are sched_delayed as it would violate ++ * EEVDF to forcibly queue an ineligible task. ++ */ ++ if ((wake_flags & WF_FORK) || pse->sched_delayed) ++ return; ++ ++ /* ++ * If @p potentially is completing work required by current then ++ * consider preemption. ++ * ++ * Reschedule if waker is no longer eligible. */ ++ if (in_task() && !entity_eligible(cfs_rq, se)) { ++ preempt_action = PREEMPT_WAKEUP_RESCHED; ++ goto preempt; ++ } ++ ++ /* Prefer picking wakee soon if appropriate. */ ++ if (sched_feat(NEXT_BUDDY) && ++ set_preempt_buddy(cfs_rq, wake_flags, pse, se)) { ++ ++ /* ++ * Decide whether to obey WF_SYNC hint for a new buddy. Old ++ * buddies are ignored as they may not be relevant to the ++ * waker and less likely to be cache hot. ++ */ ++ if (wake_flags & WF_SYNC) ++ preempt_action = preempt_sync(rq, wake_flags, pse, se); ++ } ++ ++ switch (preempt_action) { ++ case PREEMPT_WAKEUP_NONE: ++ return; ++ case PREEMPT_WAKEUP_RESCHED: ++ goto preempt; ++ case PREEMPT_WAKEUP_SHORT: ++ fallthrough; ++ case PREEMPT_WAKEUP_PICK: ++ break; ++ } ++ ++pick: + /* + * If @p has become the most eligible task, force preemption. + */ +- if (__pick_eevdf(cfs_rq, !do_preempt_short) == pse) ++ if (__pick_eevdf(cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT) == pse) + goto preempt; + +- if (sched_feat(RUN_TO_PARITY) && do_preempt_short) ++ if (sched_feat(RUN_TO_PARITY)) + update_protect_slice(cfs_rq, se); + + return; + + preempt: +- if (do_preempt_short) ++ if (preempt_action == PREEMPT_WAKEUP_SHORT) + cancel_protect_slice(se); + + resched_curr_lazy(rq); +-- +2.53.0 + diff --git a/queue-6.18/sched-make-class_schedulers-avoid-pushing-current-an.patch b/queue-6.18/sched-make-class_schedulers-avoid-pushing-current-an.patch new file mode 100644 index 0000000000..49709ff885 --- /dev/null +++ b/queue-6.18/sched-make-class_schedulers-avoid-pushing-current-an.patch @@ -0,0 +1,168 @@ +From d46837f7f5e87790265505bc9c21d93db312d459 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:13:16 +0000 +Subject: sched: Make class_schedulers avoid pushing current, and get rid of + proxy_tag_curr() + +From: John Stultz + +[ Upstream commit e0ca8991b2de6c9dfe6fcd8a0364951b2bd56797 ] + +With proxy-execution, the scheduler selects the donor, but for +blocked donors, we end up running the lock owner. + +This caused some complexity, because the class schedulers make +sure to remove the task they pick from their pushable task +lists, which prevents the donor from being migrated, but there +wasn't then anything to prevent rq->curr from being migrated +if rq->curr != rq->donor. + +This was sort of hacked around by calling proxy_tag_curr() on +the rq->curr task if we were running something other then the +donor. proxy_tag_curr() did a dequeue/enqueue pair on the +rq->curr task, allowing the class schedulers to remove it from +their pushable list. + +The dequeue/enqueue pair was wasteful, and additonally K Prateek +highlighted that we didn't properly undo things when we stopped +proxying, leaving the lock owner off the pushable list. + +After some alternative approaches were considered, Peter +suggested just having the RT/DL classes just avoid migrating +when task_on_cpu(). + +So rework pick_next_pushable_dl_task() and the rt +pick_next_pushable_task() functions so that they skip over the +first pushable task if it is on_cpu. + +Then just drop all of the proxy_tag_curr() logic. + +Fixes: be39617e38e0 ("sched: Fix proxy/current (push,pull)ability") +Closes: https://lore.kernel.org/lkml/e735cae0-2cc9-4bae-b761-fcb082ed3e94@amd.com/ +Reported-by: K Prateek Nayak +Suggested-by: Peter Zijlstra +Signed-off-by: John Stultz +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260324191337.1841376-2-jstultz@google.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 24 ------------------------ + kernel/sched/deadline.c | 18 ++++++++++++++++-- + kernel/sched/rt.c | 15 ++++++++++++--- + 3 files changed, 28 insertions(+), 29 deletions(-) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 421efba7db5a1..522d4bad56ad1 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -6730,23 +6730,6 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf) + } + #endif /* SCHED_PROXY_EXEC */ + +-static inline void proxy_tag_curr(struct rq *rq, struct task_struct *owner) +-{ +- if (!sched_proxy_exec()) +- return; +- /* +- * pick_next_task() calls set_next_task() on the chosen task +- * at some point, which ensures it is not push/pullable. +- * However, the chosen/donor task *and* the mutex owner form an +- * atomic pair wrt push/pull. +- * +- * Make sure owner we run is not pushable. Unfortunately we can +- * only deal with that by means of a dequeue/enqueue cycle. :-/ +- */ +- dequeue_task(rq, owner, DEQUEUE_NOCLOCK | DEQUEUE_SAVE); +- enqueue_task(rq, owner, ENQUEUE_NOCLOCK | ENQUEUE_RESTORE); +-} +- + /* + * __schedule() is the main scheduler function. + * +@@ -6896,9 +6879,6 @@ static void __sched notrace __schedule(int sched_mode) + */ + RCU_INIT_POINTER(rq->curr, next); + +- if (!task_current_donor(rq, next)) +- proxy_tag_curr(rq, next); +- + /* + * The membarrier system call requires each architecture + * to have a full memory barrier after updating +@@ -6933,10 +6913,6 @@ static void __sched notrace __schedule(int sched_mode) + /* Also unlocks the rq: */ + rq = context_switch(rq, prev, next, &rf); + } else { +- /* In case next was already curr but just got blocked_donor */ +- if (!task_current_donor(rq, next)) +- proxy_tag_curr(rq, next); +- + rq_unpin_lock(rq, &rf); + __balance_callbacks(rq); + raw_spin_rq_unlock_irq(rq); +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index d5052f238adf7..ed96b86dec04d 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -2761,12 +2761,26 @@ static int find_later_rq(struct task_struct *task) + + static struct task_struct *pick_next_pushable_dl_task(struct rq *rq) + { +- struct task_struct *p; ++ struct task_struct *i, *p = NULL; ++ struct rb_node *next_node; + + if (!has_pushable_dl_tasks(rq)) + return NULL; + +- p = __node_2_pdl(rb_first_cached(&rq->dl.pushable_dl_tasks_root)); ++ next_node = rb_first_cached(&rq->dl.pushable_dl_tasks_root); ++ while (next_node) { ++ i = __node_2_pdl(next_node); ++ /* make sure task isn't on_cpu (possible with proxy-exec) */ ++ if (!task_on_cpu(rq, i)) { ++ p = i; ++ break; ++ } ++ ++ next_node = rb_next(next_node); ++ } ++ ++ if (!p) ++ return NULL; + + WARN_ON_ONCE(rq->cpu != task_cpu(p)); + WARN_ON_ONCE(task_current(rq, p)); +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index a892a01c463e5..8cead8f37aa50 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -1847,13 +1847,22 @@ static int find_lowest_rq(struct task_struct *task) + + static struct task_struct *pick_next_pushable_task(struct rq *rq) + { +- struct task_struct *p; ++ struct plist_head *head = &rq->rt.pushable_tasks; ++ struct task_struct *i, *p = NULL; + + if (!has_pushable_tasks(rq)) + return NULL; + +- p = plist_first_entry(&rq->rt.pushable_tasks, +- struct task_struct, pushable_tasks); ++ plist_for_each_entry(i, head, pushable_tasks) { ++ /* make sure task isn't on_cpu (possible with proxy-exec) */ ++ if (!task_on_cpu(rq, i)) { ++ p = i; ++ break; ++ } ++ } ++ ++ if (!p) ++ return NULL; + + BUG_ON(rq->cpu != task_cpu(p)); + BUG_ON(task_current(rq, p)); +-- +2.53.0 + diff --git a/queue-6.18/sched-psi-fix-race-between-file-release-and-pressure.patch b/queue-6.18/sched-psi-fix-race-between-file-release-and-pressure.patch new file mode 100644 index 0000000000..4232970553 --- /dev/null +++ b/queue-6.18/sched-psi-fix-race-between-file-release-and-pressure.patch @@ -0,0 +1,184 @@ +From 26e27f6cc8ca5e7cfc502e0fbb90509374ef930d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 14:15:43 +0800 +Subject: sched/psi: fix race between file release and pressure write + +From: Edward Adam Davis + +[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ] + +A potential race condition exists between pressure write and cgroup file +release regarding the priv member of struct kernfs_open_file, which +triggers the uaf reported in [1]. + +Consider the following scenario involving execution on two separate CPUs: + + CPU0 CPU1 + ==== ==== + vfs_rmdir() + kernfs_iop_rmdir() + cgroup_rmdir() + cgroup_kn_lock_live() + cgroup_destroy_locked() + cgroup_addrm_files() + cgroup_rm_file() + kernfs_remove_by_name() + kernfs_remove_by_name_ns() + vfs_write() __kernfs_remove() + new_sync_write() kernfs_drain() + kernfs_fop_write_iter() kernfs_drain_open_files() + cgroup_file_write() kernfs_release_file() + pressure_write() cgroup_file_release() + ctx = of->priv; + kfree(ctx); + of->priv = NULL; + cgroup_kn_unlock() + cgroup_kn_lock_live() + cgroup_get(cgrp) + cgroup_kn_unlock() + if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv + +The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards +the memory deallocation of of->priv performed within cgroup_file_release(). +However, the operations involving of->priv executed within pressure_write() +are not entirely covered by the protection of cgroup_mutex. Consequently, +if the code in pressure_write(), specifically the section handling the +ctx variable executes after cgroup_file_release() has completed, a uaf +vulnerability involving of->priv is triggered. + +Therefore, the issue can be resolved by extending the scope of the +cgroup_mutex lock within pressure_write() to encompass all code paths +involving of->priv, thereby properly synchronizing the race condition +occurring between cgroup_file_release() and pressure_write(). + +And, if an live kn lock can be successfully acquired while executing +the pressure write operation, it indicates that the cgroup deletion +process has not yet reached its final stage; consequently, the priv +pointer within open_file cannot be NULL. Therefore, the operation to +retrieve the ctx value must be moved to a point *after* the live kn +lock has been successfully acquired. + +In another situation, specifically after entering cgroup_kn_lock_live() +but before acquiring cgroup_mutex, there exists a different class of +race condition: + +CPU0: write memory.pressure CPU1: write cgroup.pressure=0 +=========================== ============================= + +kernfs_fop_write_iter() + kernfs_get_active_of(of) + pressure_write() + cgroup_kn_lock_live(memory.pressure) + cgroup_tryget(cgrp) + kernfs_break_active_protection(kn) + ... blocks on cgroup_mutex + + cgroup_pressure_write() + cgroup_kn_lock_live(cgroup.pressure) + cgroup_file_show(memory.pressure, false) + kernfs_show(false) + kernfs_drain_open_files() + cgroup_file_release(of) + kfree(ctx) + of->priv = NULL + cgroup_kn_unlock() + + ... acquires cgroup_mutex + ctx = of->priv; // may now be NULL + if (ctx->psi.trigger) // NULL dereference + +Consequently, there is a possibility that of->priv is NULL, the pressure +write needs to check for this. + +Now that the scope of the cgroup_mutex has been expanded, the original +explicit cgroup_get/put operations are no longer necessary, this is +because acquiring/releasing the live kn lock inherently executes a +cgroup get/put operation. + +[1] +BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 +Call Trace: + pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 + cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 + kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 + +Allocated by task 9352: + cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 + kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 + do_dentry_open+0x83d/0x13e0 fs/open.c:949 + +Freed by task 9353: + cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 + kernfs_release_file fs/kernfs/file.c:764 [inline] + kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 + kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525 + +Fixes: 0e94682b73bf ("psi: introduce psi monitor") +Reported-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=33e571025d88efd1312c +Tested-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Reviewed-by: Chen Ridong +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index da5f6f5400afa..b60fc0b2c6036 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -3997,33 +3997,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) + static ssize_t pressure_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, enum psi_res res) + { +- struct cgroup_file_ctx *ctx = of->priv; ++ struct cgroup_file_ctx *ctx; + struct psi_trigger *new; + struct cgroup *cgrp; + struct psi_group *psi; ++ ssize_t ret = 0; + + cgrp = cgroup_kn_lock_live(of->kn, false); + if (!cgrp) + return -ENODEV; + +- cgroup_get(cgrp); +- cgroup_kn_unlock(of->kn); ++ ctx = of->priv; ++ if (!ctx) { ++ ret = -ENODEV; ++ goto out_unlock; ++ } + + /* Allow only one trigger per file descriptor */ + if (ctx->psi.trigger) { +- cgroup_put(cgrp); +- return -EBUSY; ++ ret = -EBUSY; ++ goto out_unlock; + } + + psi = cgroup_psi(cgrp); + new = psi_trigger_create(psi, buf, res, of->file, of); + if (IS_ERR(new)) { +- cgroup_put(cgrp); +- return PTR_ERR(new); ++ ret = PTR_ERR(new); ++ goto out_unlock; + } + + smp_store_release(&ctx->psi.trigger, new); +- cgroup_put(cgrp); ++ ++out_unlock: ++ cgroup_kn_unlock(of->kn); ++ if (ret) ++ return ret; + + return nbytes; + } +-- +2.53.0 + diff --git a/queue-6.18/sched-rt-skip-group-schedulable-check-with-rt_group_.patch b/queue-6.18/sched-rt-skip-group-schedulable-check-with-rt_group_.patch new file mode 100644 index 0000000000..98bf8e03a9 --- /dev/null +++ b/queue-6.18/sched-rt-skip-group-schedulable-check-with-rt_group_.patch @@ -0,0 +1,63 @@ +From d47ce8e02fb8ea7b841a8be9dd2a6e24279d4b5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 13:39:37 +0100 +Subject: sched/rt: Skip group schedulable check with rt_group_sched=0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Koutný + +[ Upstream commit 8b016dcec9365675be81d26be88f2c09cf983bd4 ] + +The warning from the commit 87f1fb77d87a6 ("sched: Add RT_GROUP WARN +checks for non-root task_groups") is wrong -- it assumes that only +task_groups with rt_rq are traversed, however, the schedulability check +would iterate all task_groups even when rt_group_sched=0 is disabled at +boot time but some non-root task_groups exist. + +The schedulability check is supposed to validate: + a) that children don't overcommit its parent, + b) no RT task group overcommits global RT limit. +but with rt_group_sched=0 there is no (non-trivial) hierarchy of RT groups, +therefore skip the validation altogether. Otherwise, writes to the +global sched_rt_runtime_us knob will be rejected with incorrect +validation error. + +This fix is immaterial with CONFIG_RT_GROUP_SCHED=n. + +Fixes: 87f1fb77d87a6 ("sched: Add RT_GROUP WARN checks for non-root task_groups") +Signed-off-by: Michal Koutný +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260323-sched-rert_groups-v3-1-1e7d5ed6b249@suse.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 8cead8f37aa50..156824baef613 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2677,9 +2677,6 @@ static int tg_rt_schedulable(struct task_group *tg, void *data) + tg->rt_bandwidth.rt_runtime && tg_has_rt_tasks(tg)) + return -EBUSY; + +- if (WARN_ON(!rt_group_sched_enabled() && tg != &root_task_group)) +- return -EBUSY; +- + total = to_ratio(period, runtime); + + /* +@@ -2823,6 +2820,8 @@ long sched_group_rt_period(struct task_group *tg) + static int sched_rt_global_constraints(void) + { + int ret = 0; ++ if (!rt_group_sched_enabled()) ++ return ret; + + mutex_lock(&rt_constraints_mutex); + ret = __rt_schedulable(NULL, 0, 0); +-- +2.53.0 + diff --git a/queue-6.18/sched-topology-compute-sd_weight-considering-cpuset-.patch b/queue-6.18/sched-topology-compute-sd_weight-considering-cpuset-.patch new file mode 100644 index 0000000000..90426b2fb4 --- /dev/null +++ b/queue-6.18/sched-topology-compute-sd_weight-considering-cpuset-.patch @@ -0,0 +1,94 @@ +From 536d6dab94def37599f6b9fbf1bb965236de736e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 04:44:26 +0000 +Subject: sched/topology: Compute sd_weight considering cpuset partitions + +From: K Prateek Nayak + +[ Upstream commit 8e8e23dea43e64ddafbd1246644c3219209be113 ] + +The "sd_weight" used for calculating the load balancing interval, and +its limits, considers the span weight of the entire topology level +without accounting for cpuset partitions. + +For example, consider a large system of 128CPUs divided into 8 * 16CPUs +partition which is typical when deploying virtual machines: + + [ PKG Domain: 128CPUs ] + + [Partition0: 16CPUs][Partition1: 16CPUs] ... [Partition7: 16CPUs] + +Although each partition only contains 16CPUs, the load balancing +interval is set to a minimum of 128 jiffies considering the span of the +entire domain with 128CPUs which can lead to longer imbalances within +the partition although balancing within is cheaper with 16CPUs. + +Compute the "sd_weight" after computing the "sd_span" considering the +cpu_map covered by the partition, and set the load balancing interval, +and its limits accordingly. + +For the above example, the balancing intervals for the partitions PKG +domain changes as follows: + + before after +balance_interval 128 16 +min_interval 128 16 +max_interval 256 32 + +Intervals are now proportional to the CPUs in the partitioned domain as +was intended by the original formula. + +Fixes: cb83b629bae03 ("sched/numa: Rewrite the CONFIG_NUMA sched domain support") +Signed-off-by: K Prateek Nayak +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Shrikanth Hegde +Reviewed-by: Chen Yu +Reviewed-by: Valentin Schneider +Reviewed-by: Dietmar Eggemann +Tested-by: Dietmar Eggemann +Link: https://patch.msgid.link/20260312044434.1974-2-kprateek.nayak@amd.com +Signed-off-by: Sasha Levin +--- + kernel/sched/topology.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c +index c7a4d2fff5718..35478aa2536fc 100644 +--- a/kernel/sched/topology.c ++++ b/kernel/sched/topology.c +@@ -1631,13 +1631,17 @@ sd_init(struct sched_domain_topology_level *tl, + int sd_id, sd_weight, sd_flags = 0; + struct cpumask *sd_span; + +- sd_weight = cpumask_weight(tl->mask(tl, cpu)); ++ sd_span = sched_domain_span(sd); ++ cpumask_and(sd_span, cpu_map, tl->mask(tl, cpu)); ++ sd_weight = cpumask_weight(sd_span); ++ sd_id = cpumask_first(sd_span); + + if (tl->sd_flags) + sd_flags = (*tl->sd_flags)(); + if (WARN_ONCE(sd_flags & ~TOPOLOGY_SD_FLAGS, +- "wrong sd_flags in topology description\n")) ++ "wrong sd_flags in topology description\n")) + sd_flags &= TOPOLOGY_SD_FLAGS; ++ sd_flags |= asym_cpu_capacity_classify(sd_span, cpu_map); + + *sd = (struct sched_domain){ + .min_interval = sd_weight, +@@ -1674,12 +1678,6 @@ sd_init(struct sched_domain_topology_level *tl, + .name = tl->name, + }; + +- sd_span = sched_domain_span(sd); +- cpumask_and(sd_span, cpu_map, tl->mask(tl, cpu)); +- sd_id = cpumask_first(sd_span); +- +- sd->flags |= asym_cpu_capacity_classify(sd_span, cpu_map); +- + WARN_ONCE((sd->flags & (SD_SHARE_CPUCAPACITY | SD_ASYM_CPUCAPACITY)) == + (SD_SHARE_CPUCAPACITY | SD_ASYM_CPUCAPACITY), + "CPU capacity asymmetry not supported on SMT\n"); +-- +2.53.0 + diff --git a/queue-6.18/sched-topology-fix-sched_domain_span.patch b/queue-6.18/sched-topology-fix-sched_domain_span.patch new file mode 100644 index 0000000000..e6bd2c88c1 --- /dev/null +++ b/queue-6.18/sched-topology-fix-sched_domain_span.patch @@ -0,0 +1,92 @@ +From 84ffc00d2af0bc043a7189799aac20b025073a88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:36:27 +0100 +Subject: sched/topology: Fix sched_domain_span() + +From: Peter Zijlstra + +[ Upstream commit e379dce8af11d8d6040b4348316a499bfd174bfb ] + +Commit 8e8e23dea43e ("sched/topology: Compute sd_weight considering +cpuset partitions") ends up relying on the fact that structure +initialization should not touch the flexible array. + +However, the official GCC specification for "Arrays of Length Zero" +[*] says: + + Although the size of a zero-length array is zero, an array member of + this kind may increase the size of the enclosing type as a result of + tail padding. + +Additionally, structure initialization will zero tail padding. With +the end result that since offsetof(*type, member) < sizeof(*type), +array initialization will clobber the flex array. + +Luckily, the way flexible array sizes are calculated is: + + sizeof(*type) + count * sizeof(*type->member) + +This means we have the complete size of the flex array *outside* of +sizeof(*type), so use that instead of relying on the broken flex array +definition. + +[*] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html + +Fixes: 8e8e23dea43e ("sched/topology: Compute sd_weight considering cpuset partitions") +Reported-by: Nathan Chancellor +Debugged-by: K Prateek Nayak +Signed-off-by: Peter Zijlstra (Intel) +Tested-by: Jon Hunter +Tested-by: Chen Yu +Tested-by: K Prateek Nayak +Tested-by: Nathan Chancellor +Link: https://patch.msgid.link/20260323093627.GY3738010@noisy.programming.kicks-ass.net +Signed-off-by: Sasha Levin +--- + include/linux/sched/topology.h | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/include/linux/sched/topology.h b/include/linux/sched/topology.h +index 45c0022b91ced..6f8a4ae860da8 100644 +--- a/include/linux/sched/topology.h ++++ b/include/linux/sched/topology.h +@@ -141,18 +141,30 @@ struct sched_domain { + + unsigned int span_weight; + /* +- * Span of all CPUs in this domain. ++ * See sched_domain_span(), on why flex arrays are broken. + * +- * NOTE: this field is variable length. (Allocated dynamically +- * by attaching extra space to the end of the structure, +- * depending on how many CPUs the kernel has booted up with) +- */ + unsigned long span[]; ++ */ + }; + + static inline struct cpumask *sched_domain_span(struct sched_domain *sd) + { +- return to_cpumask(sd->span); ++ /* ++ * Turns out that C flexible arrays are fundamentally broken since it ++ * is allowed for offsetof(*sd, span) < sizeof(*sd), this means that ++ * structure initialzation *sd = { ... }; which writes every byte ++ * inside sizeof(*type), will over-write the start of the flexible ++ * array. ++ * ++ * Luckily, the way we allocate sched_domain is by: ++ * ++ * sizeof(*sd) + cpumask_size() ++ * ++ * this means that we have sufficient space for the whole flex array ++ * *outside* of sizeof(*sd). So use that, and avoid using sd->span. ++ */ ++ unsigned long *bitmap = (void *)sd + sizeof(*sd); ++ return to_cpumask(bitmap); + } + + extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], +-- +2.53.0 + diff --git a/queue-6.18/sched_ext-fix-ops.cgroup_move-invocation-kf_mask-and.patch b/queue-6.18/sched_ext-fix-ops.cgroup_move-invocation-kf_mask-and.patch new file mode 100644 index 0000000000..1f100be29c --- /dev/null +++ b/queue-6.18/sched_ext-fix-ops.cgroup_move-invocation-kf_mask-and.patch @@ -0,0 +1,63 @@ +From 792d20cfd82b2cacf8004c77a01b1d3083eade8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:54:06 -1000 +Subject: sched_ext: Fix ops.cgroup_move() invocation kf_mask and rq tracking + +From: Tejun Heo + +[ Upstream commit b470e37c1fad72731be6f437e233cb6b16618f41 ] + +sched_move_task() invokes ops.cgroup_move() inside task_rq_lock(tsk), so +@p's rq lock is held. The SCX_CALL_OP_TASK invocation mislabels this: + + - kf_mask = SCX_KF_UNLOCKED (== 0), claiming no lock is held. + - rq = NULL, so update_locked_rq() doesn't run and scx_locked_rq() + returns NULL. + +Switch to SCX_KF_REST and pass task_rq(p), matching ops.set_cpumask() +from set_cpus_allowed_scx(). + +Three effects: + + - scx_bpf_task_cgroup() becomes callable (was rejected by + scx_kf_allowed(__SCX_KF_RQ_LOCKED)). Safe; rq lock is held. + + - scx_bpf_dsq_move() is now rejected (was allowed via the unlocked + branch). Calling it while holding an unrelated task's rq lock is + risky; rejection is correct. + + - scx_bpf_select_cpu_*() previously took the unlocked branch in + select_cpu_from_kfunc() and called task_rq_lock(p, &rf), which + would deadlock against the already-held pi_lock. Now it takes the + locked-rq branch and is rejected with -EPERM via the existing + kf_allowed(SCX_KF_SELECT_CPU | SCX_KF_ENQUEUE) check. Latent + deadlock fix. + +No in-tree scheduler is known to call any of these from ops.cgroup_move(). + +v2: Add Fixes: tag (Andrea Righi). + +Fixes: 18853ba782be ("sched_ext: Track currently locked rq") +Signed-off-by: Tejun Heo +Reviewed-by: Andrea Righi +Signed-off-by: Sasha Levin +--- + kernel/sched/ext.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index 17905ad77598c..32bb89559716e 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -3225,7 +3225,7 @@ void scx_cgroup_move_task(struct task_struct *p) + */ + if (SCX_HAS_OP(sch, cgroup_move) && + !WARN_ON_ONCE(!p->scx.cgrp_moving_from)) +- SCX_CALL_OP_TASK(sch, SCX_KF_UNLOCKED, cgroup_move, NULL, ++ SCX_CALL_OP_TASK(sch, SCX_KF_REST, cgroup_move, task_rq(p), + p, p->scx.cgrp_moving_from, + tg_cgrp(task_group(p))); + p->scx.cgrp_moving_from = NULL; +-- +2.53.0 + diff --git a/queue-6.18/sched_ext-read-scx_root-under-scx_cgroup_ops_rwsem-i.patch b/queue-6.18/sched_ext-read-scx_root-under-scx_cgroup_ops_rwsem-i.patch new file mode 100644 index 0000000000..249ae351cb --- /dev/null +++ b/queue-6.18/sched_ext-read-scx_root-under-scx_cgroup_ops_rwsem-i.patch @@ -0,0 +1,74 @@ +From 2b33f7b969d8054b2c6a303d976b3baf35d08239 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 12:33:22 -0400 +Subject: sched_ext: Read scx_root under scx_cgroup_ops_rwsem in cgroup setters + +From: Tejun Heo + +[ Upstream commit 80afd4c84bc8f5e80145ce35279f5ce53f6043db ] + +scx_group_set_{weight,idle,bandwidth}() cache scx_root before acquiring +scx_cgroup_ops_rwsem, so the pointer can be stale by the time the op runs. +If the loaded scheduler is disabled and freed (via RCU work) and another is +enabled between the naked load and the rwsem acquire, the reader sees +scx_cgroup_enabled=true (the new scheduler's) but dereferences the freed one +- UAF on SCX_HAS_OP(sch, ...) / SCX_CALL_OP(sch, ...). + +scx_cgroup_enabled is toggled only under scx_cgroup_ops_rwsem write +(scx_cgroup_{init,exit}), so reading scx_root inside the rwsem read section +correlates @sch with the enabled snapshot. + +Fixes: a5bd6ba30b33 ("sched_ext: Use cgroup_lock/unlock() to synchronize against cgroup operations") +Cc: stable@vger.kernel.org # v6.18+ +Reported-by: Chris Mason +Signed-off-by: Tejun Heo +Reviewed-by: Andrea Righi +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/sched/ext.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index 423098966a291..177bbf31116d0 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -3251,9 +3251,10 @@ void scx_cgroup_cancel_attach(struct cgroup_taskset *tset) + + void scx_group_set_weight(struct task_group *tg, unsigned long weight) + { +- struct scx_sched *sch = scx_root; ++ struct scx_sched *sch; + + percpu_down_read(&scx_cgroup_ops_rwsem); ++ sch = scx_root; + + if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_weight) && + tg->scx.weight != weight) +@@ -3267,9 +3268,10 @@ void scx_group_set_weight(struct task_group *tg, unsigned long weight) + + void scx_group_set_idle(struct task_group *tg, bool idle) + { +- struct scx_sched *sch = scx_root; ++ struct scx_sched *sch; + + percpu_down_read(&scx_cgroup_ops_rwsem); ++ sch = scx_root; + + if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_idle)) + SCX_CALL_OP(sch, SCX_KF_UNLOCKED, cgroup_set_idle, NULL, +@@ -3284,9 +3286,10 @@ void scx_group_set_idle(struct task_group *tg, bool idle) + void scx_group_set_bandwidth(struct task_group *tg, + u64 period_us, u64 quota_us, u64 burst_us) + { +- struct scx_sched *sch = scx_root; ++ struct scx_sched *sch; + + percpu_down_read(&scx_cgroup_ops_rwsem); ++ sch = scx_root; + + if (scx_cgroup_enabled && SCX_HAS_OP(sch, cgroup_set_bandwidth) && + (tg->scx.bw_period_us != period_us || +-- +2.53.0 + diff --git a/queue-6.18/sched_ext-track-p-s-rq-lock-across-set_cpus_allowed_.patch b/queue-6.18/sched_ext-track-p-s-rq-lock-across-set_cpus_allowed_.patch new file mode 100644 index 0000000000..23cdf0689e --- /dev/null +++ b/queue-6.18/sched_ext-track-p-s-rq-lock-across-set_cpus_allowed_.patch @@ -0,0 +1,40 @@ +From aa647e02bf4b547e30a3ba7d7c64a41ea5ab8a0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:54:06 -1000 +Subject: sched_ext: Track @p's rq lock across set_cpus_allowed_scx -> + ops.set_cpumask + +From: Tejun Heo + +[ Upstream commit 9fb457074f6d118b30458624223abef985725a88 ] + +The SCX_CALL_OP_TASK call site passes rq=NULL incorrectly, leaving +scx_locked_rq() unset. Pass task_rq(p) instead so update_locked_rq() +reflects reality. + +v2: Add Fixes: tag (Andrea Righi). + +Fixes: 18853ba782be ("sched_ext: Track currently locked rq") +Signed-off-by: Tejun Heo +Reviewed-by: Andrea Righi +Signed-off-by: Sasha Levin +--- + kernel/sched/ext.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index 177bbf31116d0..17905ad77598c 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -2606,7 +2606,7 @@ static void set_cpus_allowed_scx(struct task_struct *p, + * designation pointless. Cast it away when calling the operation. + */ + if (SCX_HAS_OP(sch, set_cpumask)) +- SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_cpumask, NULL, ++ SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_cpumask, task_rq(p), + p, (struct cpumask *)p->cpus_ptr); + } + +-- +2.53.0 + diff --git a/queue-6.18/scripts-gdb-timerlist-adapt-to-move-of-tk_core.patch b/queue-6.18/scripts-gdb-timerlist-adapt-to-move-of-tk_core.patch new file mode 100644 index 0000000000..a72d0f0e57 --- /dev/null +++ b/queue-6.18/scripts-gdb-timerlist-adapt-to-move-of-tk_core.patch @@ -0,0 +1,41 @@ +From 9f0466f5ff94b3fc14b6a27430705177a2860f61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 11:15:10 +0100 +Subject: scripts/gdb: timerlist: Adapt to move of tk_core +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh (Schneider Electric) + +[ Upstream commit 5aa9383813aca45b914d4a7481ca417ef13114df ] + +tk_core is a macro today which cannot be resolved by gdb. + +Use the correct symbol expression to reference tk_core. + +Fixes: 22c62b9a84b8 ("timekeeping: Introduce auxiliary timekeepers") +Signed-off-by: Thomas Weißschuh (Schneider Electric) +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260311-hrtimer-cleanups-v1-1-095357392669@linutronix.de +Signed-off-by: Sasha Levin +--- + scripts/gdb/linux/timerlist.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py +index ccc24d30de806..9fb3436a217cc 100644 +--- a/scripts/gdb/linux/timerlist.py ++++ b/scripts/gdb/linux/timerlist.py +@@ -20,7 +20,7 @@ def ktime_get(): + We can't read the hardware timer itself to add any nanoseconds + that need to be added since we last stored the time in the + timekeeper. But this is probably good enough for debug purposes.""" +- tk_core = gdb.parse_and_eval("&tk_core") ++ tk_core = gdb.parse_and_eval("&timekeeper_data[TIMEKEEPER_CORE]") + + return tk_core['timekeeper']['tkr_mono']['base'] + +-- +2.53.0 + diff --git a/queue-6.18/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch b/queue-6.18/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch new file mode 100644 index 0000000000..e44b9e02c8 --- /dev/null +++ b/queue-6.18/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch @@ -0,0 +1,45 @@ +From 0abeca450a13b622edc4da7647a20616dc406f6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:42 +0800 +Subject: scsi: sg: Fix sysctl sg-big-buff register during sg_init() + +From: Yang Erkun + +[ Upstream commit 3033c471aaf675254efaa0da431e95d91a104b41 ] + +Commit 26d1c80fd61e ("scsi/sg: move sg-big-buff sysctl to scsi/sg.c") made +a mistake. sysctl sg-big-buff was not created because the call to +register_sg_sysctls() was placed on the wrong code path. + +Fixes: 26d1c80fd61e ("scsi/sg: move sg-big-buff sysctl to scsi/sg.c") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-2-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 57fba34832ad1..c93cc9323f563 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1689,13 +1689,13 @@ init_sg(void) + sg_sysfs_valid = 1; + rc = scsi_register_interface(&sg_interface); + if (0 == rc) { ++ register_sg_sysctls(); + #ifdef CONFIG_SCSI_PROC_FS + sg_proc_init(); + #endif /* CONFIG_SCSI_PROC_FS */ + return 0; + } + class_unregister(&sg_sysfs_class); +- register_sg_sysctls(); + err_out: + unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); + return rc; +-- +2.53.0 + diff --git a/queue-6.18/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch b/queue-6.18/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch new file mode 100644 index 0000000000..857609f59d --- /dev/null +++ b/queue-6.18/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch @@ -0,0 +1,100 @@ +From b73f0be3d9ca7c307f06dd600ad646fec1b37691 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:43 +0800 +Subject: scsi: sg: Resolve soft lockup issue when opening /dev/sgX + +From: Yang Erkun + +[ Upstream commit d06a310b45e153872033dd0cf19d5a2279121099 ] + +The parameter def_reserved_size defines the default buffer size reserved +for each Sg_fd and should be restricted to a range between 0 and 1,048,576 +(see https://tldp.org/HOWTO/SCSI-Generic-HOWTO/proc.html). Although the +function sg_proc_write_dressz enforces this limit, it is possible to bypass +it by directly modifying the module parameter as shown below, which then +causes a soft lockup: + +echo -1 > /sys/module/sg/parameters/def_reserved_size +exec 4<> /dev/sg0 + +watchdog: BUG: soft lockup - CPU#5 stuck for 26 seconds! [bash:537] +Modules loaded: +CPU: 5 UID: 0 PID: 537 Command: bash, kernel version 6.19.0-rc3+ #134, +PREEMPT disabled +Hardware: QEMU Standard PC (i440FX + PIIX, 1996), BIOS version +1.16.1-2.fc37 dated 04/01/2014 +... +Call Trace: + + sg_build_reserve+0x5c/0xa0 + sg_add_sfp+0x168/0x270 + sg_open+0x16e/0x340 + chrdev_open+0xbe/0x230 + do_dentry_open+0x175/0x480 + vfs_open+0x34/0xf0 + do_open+0x265/0x3d0 + path_openat+0x110/0x290 + do_filp_open+0xc3/0x170 + do_sys_openat2+0x71/0xe0 + __x64_sys_openat+0x6d/0xa0 + do_syscall_64+0x62/0x310 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The fix is to use module_param_cb to validate and reject invalid values +assigned to def_reserved_size. + +Fixes: 6460e75a104d ("[SCSI] sg: fixes for large page_size") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-3-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index c93cc9323f563..21c3962ee1cb5 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1621,10 +1621,35 @@ sg_remove_device(struct device *cl_dev) + } + + module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +-module_param_named(def_reserved_size, def_reserved_size, int, +- S_IRUGO | S_IWUSR); + module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); + ++static int def_reserved_size_set(const char *val, const struct kernel_param *kp) ++{ ++ int size, ret; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtoint(val, 0, &size); ++ if (ret) ++ return ret; ++ ++ /* limit to 1 MB */ ++ if (size < 0 || size > 1048576) ++ return -ERANGE; ++ ++ def_reserved_size = size; ++ return 0; ++} ++ ++static const struct kernel_param_ops def_reserved_size_ops = { ++ .set = def_reserved_size_set, ++ .get = param_get_int, ++}; ++ ++module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, ++ S_IRUGO | S_IWUSR); ++ + MODULE_AUTHOR("Douglas Gilbert"); + MODULE_DESCRIPTION("SCSI generic (sg) driver"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.18/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch b/queue-6.18/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch new file mode 100644 index 0000000000..1a45760e35 --- /dev/null +++ b/queue-6.18/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch @@ -0,0 +1,42 @@ +From a65ac684f47ca184c87e2f447f07c8647607ea30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 23:42:58 +0800 +Subject: scsi: target: core: Fix integer overflow in UNMAP bounds check + +From: Junrui Luo + +[ Upstream commit 2bf2d65f76697820dbc4227d13866293576dd90a ] + +sbc_execute_unmap() checks LBA + range does not exceed the device capacity, +but does not guard against LBA + range wrapping around on 64-bit overflow. + +Add an overflow check matching the pattern already used for WRITE_SAME in +the same file. + +Fixes: 86d7182985d2 ("target: Add sbc_execute_unmap() helper") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881593C61AD52C69FBDB0BDAF7CA@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/target/target_core_sbc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c +index fe8beb7dbab12..4c828a3ac18c7 100644 +--- a/drivers/target/target_core_sbc.c ++++ b/drivers/target/target_core_sbc.c +@@ -1136,7 +1136,8 @@ sbc_execute_unmap(struct se_cmd *cmd) + goto err; + } + +- if (lba + range > dev->transport->get_blocks(dev) + 1) { ++ if (lba + range < lba || ++ lba + range > dev->transport->get_blocks(dev) + 1) { + ret = TCM_ADDRESS_OUT_OF_RANGE; + goto err; + } +-- +2.53.0 + diff --git a/queue-6.18/scsi-ufs-rockchip-rk3576-ufshc-dt-bindings-add-new-m.patch b/queue-6.18/scsi-ufs-rockchip-rk3576-ufshc-dt-bindings-add-new-m.patch new file mode 100644 index 0000000000..6837b03f06 --- /dev/null +++ b/queue-6.18/scsi-ufs-rockchip-rk3576-ufshc-dt-bindings-add-new-m.patch @@ -0,0 +1,74 @@ +From 1b01bb25390512bc0fa6696ff2c4ae614ffc4e43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:21:07 +0800 +Subject: scsi: ufs: rockchip,rk3576-ufshc: dt-bindings: Add new mphy reset + item + +From: Shawn Lin + +[ Upstream commit bdce3a69c578090dd5e3c77bcdaaca10c3a41e34 ] + +Add the mphy reset property to the devicetree bindings for the Rockchip +RK3576 UFS host controller. The mphy reset signal is used to reset the +physical adapter. Resetting other components while leaving the mphy unreset +may occasionally prevent the UFS controller from successfully linking up +with the device. + +This addresses an intermittent hardware bug where the UFS link fails to +establish under specific timing conditions with certain chips. While +difficult to reproduce initially, this issue was consistently observed in +downstream testing and requires explicit mphy reset control for full +stability. + +Although this change increases the maxItems for resets and adds a new entry +(which technically alters the binding ABI), it does not break compatibility +for existing Linux systems. The driver uses +devm_reset_control_array_get_exclusive() to manage resets, allowing it to +function correctly with both older Device Trees (without the mphy entry) +and newer ones. + +Fixes: d90e92023771 ("scsi: ufs: dt-bindings: Document Rockchip UFS host controller") +Signed-off-by: Shawn Lin +Reviewed-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/1773368467-109650-1-git-send-email-shawn.lin@rock-chips.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml b/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml +index c7d17cf4dc42b..e738153a309c8 100644 +--- a/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml ++++ b/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml +@@ -41,7 +41,7 @@ properties: + maxItems: 1 + + resets: +- maxItems: 4 ++ maxItems: 5 + + reset-names: + items: +@@ -49,6 +49,7 @@ properties: + - const: sys + - const: ufs + - const: grf ++ - const: mphy + + reset-gpios: + maxItems: 1 +@@ -98,8 +99,8 @@ examples: + interrupts = ; + power-domains = <&power RK3576_PD_USB>; + resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>, <&cru SRST_A_UFS>, +- <&cru SRST_P_UFS_GRF>; +- reset-names = "biu", "sys", "ufs", "grf"; ++ <&cru SRST_P_UFS_GRF>, <&cru SRST_MPHY_INIT>; ++ reset-names = "biu", "sys", "ufs", "grf", "mphy"; + reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.18/sctp-discard-stale-init-after-handshake-completion.patch b/queue-6.18/sctp-discard-stale-init-after-handshake-completion.patch new file mode 100644 index 0000000000..6dff353cd2 --- /dev/null +++ b/queue-6.18/sctp-discard-stale-init-after-handshake-completion.patch @@ -0,0 +1,49 @@ +From 2daf400a1a56325e5f29454e01384e8d424e5eca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:41 -0400 +Subject: sctp: discard stale INIT after handshake completion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Xin Long + +[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ] + +After an association reaches ESTABLISHED, the peer’s init_tag is already +known from the handshake. Any subsequent INIT with the same init_tag is +not a valid restart, but a delayed or duplicate INIT. + +Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of +processing them as new association attempts. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/5788c76c1ee122a3ed00189e88dcf9df1fba226c.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 7b823d7591419..8e89a870780c4 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( + /* Tag the variable length parameters. */ + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); + ++ if (asoc->state >= SCTP_STATE_ESTABLISHED) { ++ /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ ++ if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) ++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ } ++ + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, +-- +2.53.0 + diff --git a/queue-6.18/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch b/queue-6.18/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch new file mode 100644 index 0000000000..690d89d5f8 --- /dev/null +++ b/queue-6.18/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch @@ -0,0 +1,44 @@ +From f4432fedf062c824a3cd13d3e05bb0853e157052 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 14:13:51 -0400 +Subject: sctp: fix missing encap_port propagation for GSO fragments + +From: Xin Long + +[ Upstream commit bf6f95ae3b8b2638c0e1d6d802d50983ce5d0f45 ] + +encap_port in SCTP_INPUT_CB(skb) is used by sctp_vtag_verify() for +SCTP-over-UDP processing. In the GSO case, it is only set on the head +skb, while fragment skbs leave it 0. + +This results in fragment skbs seeing encap_port == 0, breaking +SCTP-over-UDP connections. + +Fix it by propagating encap_port from the head skb cb when initializing +fragment skbs in sctp_inq_pop(). + +Fixes: 046c052b475e ("sctp: enable udp tunneling socks") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/ea65ed61b3598d8b4940f0170b9aa1762307e6c3.1776017631.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/inqueue.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c +index f5a7d5a387555..a024c08432471 100644 +--- a/net/sctp/inqueue.c ++++ b/net/sctp/inqueue.c +@@ -201,6 +201,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + + cb->chunk = head_cb->chunk; + cb->af = head_cb->af; ++ cb->encap_port = head_cb->encap_port; + } + } + +-- +2.53.0 + diff --git a/queue-6.18/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch b/queue-6.18/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch new file mode 100644 index 0000000000..29e1487ac5 --- /dev/null +++ b/queue-6.18/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch @@ -0,0 +1,68 @@ +From e7a06c6a55dd36f14fcaf1cb3d1277ba035f2053 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 23:19:03 -0400 +Subject: sctp: fix OOB write to userspace in sctp_getsockopt_peer_auth_chunks + +From: Michael Bommarito + +[ Upstream commit 0cf004ffb61cd32d140531c3a84afe975f9fc7ea ] + +sctp_getsockopt_peer_auth_chunks() checks that the caller's optval +buffer is large enough for the peer AUTH chunk list with + + if (len < num_chunks) + return -EINVAL; + +but then writes num_chunks bytes to p->gauth_chunks, which lives +at offset offsetof(struct sctp_authchunks, gauth_chunks) == 8 +inside optval. The check is missing the sizeof(struct +sctp_authchunks) = 8-byte header. When the caller supplies +len == num_chunks (for any num_chunks > 0) the test passes but +copy_to_user() writes sizeof(struct sctp_authchunks) = 8 bytes +past the declared buffer. + +The sibling function sctp_getsockopt_local_auth_chunks() at the +next line already has the correct check: + + if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + +Align the peer variant with its sibling. + +Reproducer confirms on v7.0-13-generic: an unprivileged userspace +caller that opens a loopback SCTP association with AUTH enabled, +queries num_chunks with a short optval, then issues the real +getsockopt with len == num_chunks and sentinel bytes painted past +the buffer observes those sentinel bytes overwritten with the +peer's AUTH chunk type. The bytes written are under the peer's +control but land in the caller's own userspace; this is not a +kernel memory corruption, but it is a kernel-side contract +violation that can silently corrupt adjacent userspace data. + +Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260416031903.1447072-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index c57a53192beef..2c5ad53984906 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -6990,7 +6990,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, + + /* See if the user provided enough room for all the data */ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); +- if (len < num_chunks) ++ if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + + if (copy_to_user(to, ch->chunks, num_chunks)) +-- +2.53.0 + diff --git a/queue-6.18/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch b/queue-6.18/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch new file mode 100644 index 0000000000..e2ec6623a7 --- /dev/null +++ b/queue-6.18/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch @@ -0,0 +1,75 @@ +From d87e90f3e2eff043d0e3ecf84bc7331771e49c45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 16:05:26 -0400 +Subject: selftest: memcg: skip memcg_sock test if address family not supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Waiman Long + +[ Upstream commit 2d028f3e4bbbfd448928a8d3d2814b0b04c214f4 ] + +The test_memcg_sock test in memcontrol.c sets up an IPv6 socket and send +data over it to consume memory and verify that memory.stat.sock and +memory.current values are close. + +On systems where IPv6 isn't enabled or not configured to support +SOCK_STREAM, the test_memcg_sock test always fails. When the socket() +call fails, there is no way we can test the memory consumption and verify +the above claim. I believe it is better to just skip the test in this +case instead of reporting a test failure hinting that there may be +something wrong with the memcg code. + +Link: https://lkml.kernel.org/r/20260311200526.885899-1-longman@redhat.com +Fixes: 5f8f019380b8 ("selftests: cgroup/memcontrol: add basic test for socket accounting") +Signed-off-by: Waiman Long +Acked-by: Michal Koutný +Acked-by: Shakeel Butt +Cc: Johannes Weiner +Cc: Michal Hocko +Cc: Michal Koutný +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Roman Gushchin +Cc: Shuah Khan +Cc: Tejun Heo +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/cgroup/test_memcontrol.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c +index a680f773f2d54..1f64db1afa212 100644 +--- a/tools/testing/selftests/cgroup/test_memcontrol.c ++++ b/tools/testing/selftests/cgroup/test_memcontrol.c +@@ -1278,8 +1278,11 @@ static int tcp_server(const char *cgroup, void *arg) + saddr.sin6_port = htons(srv_args->port); + + sk = socket(AF_INET6, SOCK_STREAM, 0); +- if (sk < 0) ++ if (sk < 0) { ++ /* Pass back errno to the ctl_fd */ ++ write(ctl_fd, &errno, sizeof(errno)); + return ret; ++ } + + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + goto cleanup; +@@ -1409,6 +1412,12 @@ static int test_memcg_sock(const char *root) + goto cleanup; + close(args.ctl[0]); + ++ /* Skip if address family not supported by protocol */ ++ if (err == EAFNOSUPPORT) { ++ ret = KSFT_SKIP; ++ goto cleanup; ++ } ++ + if (!err) + break; + if (err != EADDRINUSE) +-- +2.53.0 + diff --git a/queue-6.18/selftests-bpf-fix-__jited_unpriv-tag-name.patch b/queue-6.18/selftests-bpf-fix-__jited_unpriv-tag-name.patch new file mode 100644 index 0000000000..a780b74d06 --- /dev/null +++ b/queue-6.18/selftests-bpf-fix-__jited_unpriv-tag-name.patch @@ -0,0 +1,39 @@ +From dbcb18d1ad885dda137f4ef2cf43b34e809817f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 00:33:44 -0700 +Subject: selftests/bpf: fix __jited_unpriv tag name + +From: Eduard Zingerman + +[ Upstream commit cdd54fe98c00549264a92613af6bb0e9a5fd0d1c ] + +__jited_unpriv was using "test_jited=" as its tag name, same as the +priv variant __jited. Fix by using "test_jited_unpriv=". + +Fixes: 7d743e4c759c ("selftests/bpf: __jited test tag to check disassembly after jit") +Acked-by: Ihor Solodrai +Reviewed-by: Puranjay Mohan +Signed-off-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260410-selftests-global-tags-ordering-v2-1-c566ec9781bf@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/progs/bpf_misc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h +index a7a1a684eed11..25172ca74b204 100644 +--- a/tools/testing/selftests/bpf/progs/bpf_misc.h ++++ b/tools/testing/selftests/bpf/progs/bpf_misc.h +@@ -137,7 +137,7 @@ + #define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" XSTR(__COUNTER__) "=" msg))) + #define __not_msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_not_msg_unpriv=" XSTR(__COUNTER__) "=" msg))) + #define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" XSTR(__COUNTER__) "=" msg))) +-#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited=" XSTR(__COUNTER__) "=" msg))) ++#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited_unpriv=" XSTR(__COUNTER__) "=" msg))) + #define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv"))) + #define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv"))) + #define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl))) +-- +2.53.0 + diff --git a/queue-6.18/selftests-bpf-fix-reg_bounds-to-match-new-tnum-based.patch b/queue-6.18/selftests-bpf-fix-reg_bounds-to-match-new-tnum-based.patch new file mode 100644 index 0000000000..3e5cb9c06d --- /dev/null +++ b/queue-6.18/selftests-bpf-fix-reg_bounds-to-match-new-tnum-based.patch @@ -0,0 +1,153 @@ +From ae2e502f88e866d33c21f0dea0eb8915c4d28e4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 22:40:50 +0200 +Subject: selftests/bpf: Fix reg_bounds to match new tnum-based refinement + +From: Paul Chaignon + +[ Upstream commit 2fefa9c81a25534464911447d51ddb44b04a8e5b ] + +Commit efc11a667878 ("bpf: Improve bounds when tnum has a single +possible value") improved the bounds refinement to detect when the tnum +and u64 range overlap in a single value (and the bounds can thus be set +to that value). + +Eduard then noticed that it broke the slow-mode reg_bounds selftests +because they don't have an equivalent logic and are therefore unable to +refine the bounds as much as the verifier. The following test case +illustrates this. + + ACTUAL TRUE1: scalar(u64=0xffffffff00000000,u32=0,s64=0xffffffff00000000,s32=0) + EXPECTED TRUE1: scalar(u64=[0xfffffffe00000001; 0xffffffff00000000],u32=0,s64=[0xfffffffe00000001; 0xffffffff00000000],s32=0) + [...] + #323/1007 reg_bounds_gen_consts_s64_s32/(s64)[0xfffffffe00000001; 0xffffffff00000000] (s32) S64_MIN:FAIL + +with the verifier logs: + + [...] + 19: w0 = w6 ; R0=scalar(smin=0,smax=umax=0xffffffff, + var_off=(0x0; 0xffffffff)) + R6=scalar(smin=0xfffffffe00000001,smax=0xffffffff00000000, + umin=0xfffffffe00000001,umax=0xffffffff00000000, + var_off=(0xfffffffe00000000; 0x1ffffffff)) + 20: w0 = w7 ; R0=0 R7=0x8000000000000000 + 21: if w6 == w7 goto pc+3 + [...] + from 21 to 25: [...] + 25: w0 = w6 ; R0=0 R6=0xffffffff00000000 + ; ^ + ; unexpected refined value + 26: w0 = w7 ; R0=0 R7=0x8000000000000000 + 27: exit + +When w6 == w7 is true, the verifier can deduce that the R6's tnum is +equal to (0xfffffffe00000000; 0x100000000) and then use that information +to refine the bounds: the tnum only overlap with the u64 range in +0xffffffff00000000. The reg_bounds selftest doesn't know about tnums +and therefore fails to perform the same refinement. + +This issue happens when the tnum carries information that cannot be +represented in the ranges, as otherwise the selftest could reach the +same refined value using just the ranges. The tnum thus needs to +represent non-contiguous values (ex., R6's tnum above, after the +condition). The only way this can happen in the reg_bounds selftest is +at the boundary between the 32 and 64bit ranges. We therefore only need +to handle that case. + +This patch fixes the selftest refinement logic by checking if the u32 +and u64 ranges overlap in a single value. If so, the ranges can be set +to that value. We need to handle two cases: either they overlap in +umin64... + + u64 values + matching u32 range: xxx xxx xxx xxx + |--------------------------------------| + u64 range: 0 xxxxx UMAX64 + +or in umax64: + + u64 values + matching u32 range: xxx xxx xxx xxx + |--------------------------------------| + u64 range: 0 xxxxx UMAX64 + +To detect the first case, we decrease umax64 to the maximum value that +matches the u32 range. If that happens to be umin64, then umin64 is the +only overlap. We proceed similarly for the second case, increasing +umin64 to the minimum value that matches the u32 range. + +Note this is similar to how the verifier handles the general case using +tnum, but we don't need to care about a single-value overlap in the +middle of the range. That case is not possible when comparing two +ranges. + +This patch also adds two test cases reproducing this bug as part of the +normal test runs (without SLOW_TESTS=1). + +Fixes: efc11a667878 ("bpf: Improve bounds when tnum has a single possible value") +Reported-by: Eduard Zingerman +Closes: https://lore.kernel.org/bpf/4e6dd64a162b3cab3635706ae6abfdd0be4db5db.camel@gmail.com/ +Signed-off-by: Paul Chaignon +Link: https://lore.kernel.org/r/ada9UuSQi2SE2IfB@mail.gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/prog_tests/reg_bounds.c | 35 +++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +index 04938d0d431b3..5f57d3c923801 100644 +--- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c ++++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +@@ -500,6 +500,39 @@ static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t, + (s64)x.a >= S32_MIN && (s64)x.b <= S32_MAX) + return range_intersection(x_t, x, y_cast); + ++ if (y_t == U32 && x_t == U64) { ++ u64 xmin_swap, xmax_swap, xmin_lower32, xmax_lower32; ++ ++ xmin_lower32 = x.a & 0xffffffff; ++ xmax_lower32 = x.b & 0xffffffff; ++ if (xmin_lower32 < y.a || xmin_lower32 > y.b) { ++ /* The 32 lower bits of the umin64 are outside the u32 ++ * range. Let's update umin64 to match the u32 range. ++ * We want to *increase* the umin64 to the *minimum* ++ * value that matches the u32 range. ++ */ ++ xmin_swap = swap_low32(x.a, y.a); ++ /* We should always only increase the minimum, so if ++ * the new value is lower than before, we need to ++ * increase the 32 upper bits by 1. ++ */ ++ if (xmin_swap < x.a) ++ xmin_swap += 0x100000000; ++ if (xmin_swap == x.b) ++ return range(x_t, x.b, x.b); ++ } else if (xmax_lower32 < y.a || xmax_lower32 > y.b) { ++ /* Same for the umax64, but we want to *decrease* ++ * umax64 to the *maximum* value that matches the u32 ++ * range. ++ */ ++ xmax_swap = swap_low32(x.b, y.b); ++ if (xmax_swap > x.b) ++ xmax_swap -= 0x100000000; ++ if (xmax_swap == x.a) ++ return range(x_t, x.a, x.a); ++ } ++ } ++ + /* the case when new range knowledge, *y*, is a 32-bit subregister + * range, while previous range knowledge, *x*, is a full register + * 64-bit range, needs special treatment to take into account upper 32 +@@ -2143,6 +2176,8 @@ static struct subtest_case crafted_cases[] = { + {U64, S64, {0x7fffffff00000001ULL, 0xffffffff00000000ULL}, {0, 0}}, + {U64, S64, {0, 0xffffffffULL}, {1, 1}}, + {U64, S64, {0, 0xffffffffULL}, {0x7fffffff, 0x7fffffff}}, ++ {U64, S32, {0xfffffffe00000001, 0xffffffff00000000}, {S64_MIN, S64_MIN}}, ++ {U64, U32, {0xfffffffe00000000, U64_MAX - 1}, {U64_MAX, U64_MAX}}, + + {U64, U32, {0, 0x100000000}, {0, 0}}, + {U64, U32, {0xfffffffe, 0x300000000}, {0x80000000, 0x80000000}}, +-- +2.53.0 + diff --git a/queue-6.18/selftests-futex-fix-incorrect-result-reporting-of-fu.patch b/queue-6.18/selftests-futex-fix-incorrect-result-reporting-of-fu.patch new file mode 100644 index 0000000000..6d1c72fd91 --- /dev/null +++ b/queue-6.18/selftests-futex-fix-incorrect-result-reporting-of-fu.patch @@ -0,0 +1,120 @@ +From a5031c375d6d5a8e5d368564b8eb3579c5d581a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:03:10 +0800 +Subject: selftests/futex: Fix incorrect result reporting of futex_requeue test + item + +From: Yuwen Chen + +[ Upstream commit d317e2ef9dcf673c9f37cda784284af7c6812757 ] + +When using the TEST_HARNESS_MAIN macro definition to declare the main +function, it is required to use the EXPECT*() and ASSERT*() macros in +conjunction and not ksft_test_result_*(). Otherwise, even if a test item +fails, the test will still return a success result because +ksft_test_result_*() does not affect the test harness state. + +Convert the code to use EXPECT/ASSERT() variants, which ensures that the +overall test result is fail if one of the EXPECT()s fails. + +[ tglx: Massaged change log to explain _why_ ksft_test_result*() is the wrong + choice ] + +Fixes: f341a20f6d7e ("selftests/futex: Refactor futex_requeue with kselftest_harness.h") +Signed-off-by: Yuwen Chen +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/tencent_51851B741CC4B5EC9C22AFF70BA82BB60805@qq.com +Signed-off-by: Sasha Levin +--- + .../futex/functional/futex_requeue.c | 49 +++---------------- + 1 file changed, 8 insertions(+), 41 deletions(-) + +diff --git a/tools/testing/selftests/futex/functional/futex_requeue.c b/tools/testing/selftests/futex/functional/futex_requeue.c +index 69e2555b60399..d6be3fbd436a4 100644 +--- a/tools/testing/selftests/futex/functional/futex_requeue.c ++++ b/tools/testing/selftests/futex/functional/futex_requeue.c +@@ -34,34 +34,18 @@ TEST(requeue_single) + volatile futex_t _f1 = 0; + volatile futex_t f2 = 0; + pthread_t waiter[10]; +- int res; + + f1 = &_f1; + + /* + * Requeue a waiter from f1 to f2, and wake f2. + */ +- if (pthread_create(&waiter[0], NULL, waiterfn, NULL)) +- ksft_exit_fail_msg("pthread_create failed\n"); ++ ASSERT_EQ(0, pthread_create(&waiter[0], NULL, waiterfn, NULL)); + + usleep(WAKE_WAIT_US); + +- ksft_print_dbg_msg("Requeuing 1 futex from f1 to f2\n"); +- res = futex_cmp_requeue(f1, 0, &f2, 0, 1, 0); +- if (res != 1) +- ksft_test_result_fail("futex_requeue simple returned: %d %s\n", +- res ? errno : res, +- res ? strerror(errno) : ""); +- +- ksft_print_dbg_msg("Waking 1 futex at f2\n"); +- res = futex_wake(&f2, 1, 0); +- if (res != 1) { +- ksft_test_result_fail("futex_requeue simple returned: %d %s\n", +- res ? errno : res, +- res ? strerror(errno) : ""); +- } else { +- ksft_test_result_pass("futex_requeue simple succeeds\n"); +- } ++ EXPECT_EQ(1, futex_cmp_requeue(f1, 0, &f2, 0, 1, 0)); ++ EXPECT_EQ(1, futex_wake(&f2, 1, 0)); + } + + TEST(requeue_multiple) +@@ -69,7 +53,7 @@ TEST(requeue_multiple) + volatile futex_t _f1 = 0; + volatile futex_t f2 = 0; + pthread_t waiter[10]; +- int res, i; ++ int i; + + f1 = &_f1; + +@@ -77,30 +61,13 @@ TEST(requeue_multiple) + * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7. + * At futex_wake, wake INT_MAX (should be exactly 7). + */ +- for (i = 0; i < 10; i++) { +- if (pthread_create(&waiter[i], NULL, waiterfn, NULL)) +- ksft_exit_fail_msg("pthread_create failed\n"); +- } ++ for (i = 0; i < 10; i++) ++ ASSERT_EQ(0, pthread_create(&waiter[i], NULL, waiterfn, NULL)); + + usleep(WAKE_WAIT_US); + +- ksft_print_dbg_msg("Waking 3 futexes at f1 and requeuing 7 futexes from f1 to f2\n"); +- res = futex_cmp_requeue(f1, 0, &f2, 3, 7, 0); +- if (res != 10) { +- ksft_test_result_fail("futex_requeue many returned: %d %s\n", +- res ? errno : res, +- res ? strerror(errno) : ""); +- } +- +- ksft_print_dbg_msg("Waking INT_MAX futexes at f2\n"); +- res = futex_wake(&f2, INT_MAX, 0); +- if (res != 7) { +- ksft_test_result_fail("futex_requeue many returned: %d %s\n", +- res ? errno : res, +- res ? strerror(errno) : ""); +- } else { +- ksft_test_result_pass("futex_requeue many succeeds\n"); +- } ++ EXPECT_EQ(10, futex_cmp_requeue(f1, 0, &f2, 3, 7, 0)); ++ EXPECT_EQ(7, futex_wake(&f2, INT_MAX, 0)); + } + + TEST_HARNESS_MAIN +-- +2.53.0 + diff --git a/queue-6.18/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch b/queue-6.18/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch new file mode 100644 index 0000000000..1ff8855244 --- /dev/null +++ b/queue-6.18/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch @@ -0,0 +1,58 @@ +From 1e12c57a24ef3453f4272986169c3577b7942fc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:39:41 -0500 +Subject: selftests/mm: skip migration tests if NUMA is unavailable + +From: AnishMulay + +[ Upstream commit 54218f10dfbe88c8e41c744fd45a756cde60b8c4 ] + +Currently, the migration test asserts that numa_available() returns 0. On +systems where NUMA is not available (returning -1), such as certain ARM64 +configurations or single-node systems, this assertion fails and crashes +the test. + +Update the test to check the return value of numa_available(). If it is +less than 0, skip the test gracefully instead of failing. + +This aligns the behavior with other MM selftests (like rmap) that skip +when NUMA support is missing. + +Link: https://lkml.kernel.org/r/20260218163941.13499-1-anishm7030@gmail.com +Fixes: 0c2d08728470 ("mm: add selftests for migration entries") +Signed-off-by: AnishMulay +Reviewed-by: SeongJae Park +Reviewed-by: Dev Jain +Reviewed-by: Anshuman Khandual +Tested-by: Sayali Patil +Acked-by: David Hildenbrand (Arm) +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/migration.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c +index ea945eebec2f6..aa556c708d6bc 100644 +--- a/tools/testing/selftests/mm/migration.c ++++ b/tools/testing/selftests/mm/migration.c +@@ -36,7 +36,8 @@ FIXTURE_SETUP(migration) + { + int n; + +- ASSERT_EQ(numa_available(), 0); ++ if (numa_available() < 0) ++ SKIP(return, "NUMA not available"); + self->nthreads = numa_num_task_cpus() - 1; + self->n1 = -1; + self->n2 = -1; +-- +2.53.0 + diff --git a/queue-6.18/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch b/queue-6.18/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch new file mode 100644 index 0000000000..9a82fb76b7 --- /dev/null +++ b/queue-6.18/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch @@ -0,0 +1,86 @@ +From 0c24f05b321f047dac3d077e97b303f4e199a18a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:45:02 +0200 +Subject: selftests: netfilter: nft_tproxy.sh: adjust to socat changes + +From: Florian Westphal + +[ Upstream commit 61119542663cac70898aef532eb57ee41ea9b477 ] + +Like e65d8b6f3092 ("selftests: drv-net: adjust to socat changes") we +need to add shut-none for this test too. + +The extra 0-packet can trigger a second (unexpected) reply from the server. + +Fixes: 7e37e0eacd22 ("selftests: netfilter: nft_tproxy.sh: add tcp tests") +Reported-by: Jakub Kicinski +Closes: https://lore.kernel.org/netdev/20260408152432.24b8ad0d@kernel.org/ +Suggested-by: Jakub Kicinski +Signed-off-by: Florian Westphal +Link: https://patch.msgid.link/20260409224506.27072-1-fw@strlen.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../selftests/net/netfilter/nft_tproxy_udp.sh | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh b/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh +index d16de13fe5a75..1dc7b04501459 100755 +--- a/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh ++++ b/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh +@@ -190,13 +190,13 @@ table inet filter { + } + EOF + +- timeout "$timeout" ip netns exec "$nsrouter" socat -u "$socat_ipproto" udp-listen:12345,fork,ip-transparent,reuseport udp:"$ns1_ip_port",ip-transparent,reuseport,bind="$ns2_ip_port" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$nsrouter" socat -u "$socat_ipproto" udp-listen:12345,fork,ip-transparent,reuseport,shut-none udp:"$ns1_ip_port",ip-transparent,reuseport,bind="$ns2_ip_port",shut-none 2>/dev/null & + local tproxy_pid=$! + +- timeout "$timeout" ip netns exec "$ns2" socat "$socat_ipproto" udp-listen:8080,fork SYSTEM:"echo PONG_NS2" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$ns2" socat "$socat_ipproto" udp-listen:8080,fork,shut-none SYSTEM:"echo PONG_NS2" 2>/dev/null & + local server2_pid=$! + +- timeout "$timeout" ip netns exec "$ns3" socat "$socat_ipproto" udp-listen:8080,fork SYSTEM:"echo PONG_NS3" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$ns3" socat "$socat_ipproto" udp-listen:8080,fork,shut-none SYSTEM:"echo PONG_NS3" 2>/dev/null & + local server3_pid=$! + + busywait "$BUSYWAIT_TIMEOUT" listener_ready "$nsrouter" 12345 "-u" +@@ -205,7 +205,7 @@ EOF + + local result + # request from ns1 to ns2 (forwarded traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",sourceport=18888) ++ result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",sourceport=18888,shut-none) + if [ "$result" == "$expect_ns1_ns2" ] ;then + echo "PASS: tproxy test $testname: ns1 got reply \"$result\" connecting to ns2" + else +@@ -214,7 +214,7 @@ EOF + fi + + # request from ns1 to ns3 (forwarded traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port",shut-none) + if [ "$result" = "$expect_ns1_ns3" ] ;then + echo "PASS: tproxy test $testname: ns1 got reply \"$result\" connecting to ns3" + else +@@ -223,7 +223,7 @@ EOF + fi + + # request from nsrouter to ns2 (localy originated traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",shut-none) + if [ "$result" == "$expect_nsrouter_ns2" ] ;then + echo "PASS: tproxy test $testname: nsrouter got reply \"$result\" connecting to ns2" + else +@@ -232,7 +232,7 @@ EOF + fi + + # request from nsrouter to ns3 (localy originated traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port",shut-none) + if [ "$result" = "$expect_nsrouter_ns3" ] ;then + echo "PASS: tproxy test $testname: nsrouter got reply \"$result\" connecting to ns3" + else +-- +2.53.0 + diff --git a/queue-6.18/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch b/queue-6.18/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch new file mode 100644 index 0000000000..5d94daca7d --- /dev/null +++ b/queue-6.18/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch @@ -0,0 +1,87 @@ +From cf932e57f1c38cf8017533dc540768c9e7139c05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:24:26 +0530 +Subject: selftests/powerpc: Suppress -Wmaybe-uninitialized with GCC 15 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Amit Machhiwal + +[ Upstream commit 6e65886fceb23605eff952d6b1975737b4c4b154 ] + +GCC 15 reports the below false positive '-Wmaybe-uninitialized' warning +in vphn_unpack_associativity() when building the powerpc selftests. + + # make -C tools/testing/selftests TARGETS="powerpc" + [...] + CC test-vphn + In file included from test-vphn.c:3: + In function ‘vphn_unpack_associativity’, + inlined from ‘test_one’ at test-vphn.c:371:2, + inlined from ‘test_vphn’ at test-vphn.c:399:9: + test-vphn.c:10:33: error: ‘be_packed’ may be used uninitialized [-Werror=maybe-uninitialized] + 10 | #define be16_to_cpup(x) bswap_16(*x) + | ^~~~~~~~ + vphn.c:42:27: note: in expansion of macro ‘be16_to_cpup’ + 42 | u16 new = be16_to_cpup(field++); + | ^~~~~~~~~~~~ + In file included from test-vphn.c:19: + vphn.c: In function ‘test_vphn’: + vphn.c:27:16: note: ‘be_packed’ declared here + 27 | __be64 be_packed[VPHN_REGISTER_COUNT]; + | ^~~~~~~~~ + cc1: all warnings being treated as errors + +When vphn_unpack_associativity() is called from hcall_vphn() in kernel +the error is not seen while building vphn.c during kernel compilation. +This is because the top level Makefile includes '-fno-strict-aliasing' +flag always. + +The issue here is that GCC 15 emits '-Wmaybe-uninitialized' due to type +punning between __be64[] and __b16* when accessing the buffer via +be16_to_cpup(). The underlying object is fully initialized but GCC 15 +fails to track the aliasing due to the strict aliasing violation here. +Please refer [1] and [2]. This results in a false positive warning which +is promoted to an error under '-Werror'. This problem is not seen when +the compilation is performed with GCC 13 and 14. An issue [1] has also +been created on GCC bugzilla. + +The selftest compiles fine with '-fno-strict-aliasing'. Since this GCC +flag is used to compile vphn.c in kernel too, the same flag should be +used to build vphn tests when compiling vphn.c in the selftest as well. + +Fix this by including '-fno-strict-aliasing' during vphn.c compilation +in the selftest. This keeps the build working while limiting the scope +of the suppression to building vphn tests. + +[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124427 +[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99768 + +Fixes: 58dae82843f5 ("selftests/powerpc: Add test for VPHN") +Reviewed-by: Vaibhav Jain +Signed-off-by: Amit Machhiwal +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260313165426.43259-1-amachhiw@linux.ibm.com +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/powerpc/vphn/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/powerpc/vphn/Makefile b/tools/testing/selftests/powerpc/vphn/Makefile +index 61d519a076c6f..778fc396340db 100644 +--- a/tools/testing/selftests/powerpc/vphn/Makefile ++++ b/tools/testing/selftests/powerpc/vphn/Makefile +@@ -5,7 +5,7 @@ top_srcdir = ../../../../.. + include ../../lib.mk + include ../flags.mk + +-CFLAGS += -m64 -I$(CURDIR) ++CFLAGS += -m64 -I$(CURDIR) -fno-strict-aliasing + + $(TEST_GEN_PROGS): ../harness.c + +-- +2.53.0 + diff --git a/queue-6.18/selftests-sched_ext-add-missing-error-check-for-exit.patch b/queue-6.18/selftests-sched_ext-add-missing-error-check-for-exit.patch new file mode 100644 index 0000000000..e9114399e0 --- /dev/null +++ b/queue-6.18/selftests-sched_ext-add-missing-error-check-for-exit.patch @@ -0,0 +1,38 @@ +From fb72bd4a738d32dfd817e0f984c171f14798358c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 05:17:55 +0000 +Subject: selftests/sched_ext: Add missing error check for exit__load() + +From: David Carlier + +[ Upstream commit 1d02346fec8d13b05e54296ddc6ae29b7e1067df ] + +exit__load(skel) was called without checking its return value. +Every other test in the suite wraps the load call with +SCX_FAIL_IF(). Add the missing check to be consistent with the +rest of the test suite. + +Fixes: a5db7817af78 ("sched_ext: Add selftests") +Signed-off-by: David Carlier +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/sched_ext/exit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/sched_ext/exit.c b/tools/testing/selftests/sched_ext/exit.c +index ee25824b1cbe6..b987611789d16 100644 +--- a/tools/testing/selftests/sched_ext/exit.c ++++ b/tools/testing/selftests/sched_ext/exit.c +@@ -33,7 +33,7 @@ static enum scx_test_status run(void *ctx) + skel = exit__open(); + SCX_ENUM_INIT(skel); + skel->rodata->exit_point = tc; +- exit__load(skel); ++ SCX_FAIL_IF(exit__load(skel), "Failed to load skel"); + link = bpf_map__attach_struct_ops(skel->maps.exit_ops); + if (!link) { + SCX_ERR("Failed to attach scheduler"); +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series new file mode 100644 index 0000000000..d51e3ab14d --- /dev/null +++ b/queue-6.18/series @@ -0,0 +1,887 @@ +spi-uniphier-simplify-clock-handling-with-devm_clk_g.patch +spi-uniphier-fix-controller-deregistration.patch +spi-tegra20-sflash-fix-controller-deregistration.patch +spi-tegra114-fix-controller-deregistration.patch +spi-zynq-qspi-simplify-clock-handling-with-devm_clk_.patch +spi-zynq-qspi-fix-controller-deregistration.patch +bluetooth-hci_conn-fix-potential-uaf-in-create_big_s.patch +sched-ext-implement-cgroup_set_idle-callback.patch +sched_ext-read-scx_root-under-scx_cgroup_ops_rwsem-i.patch +usb-dwc3-remove-of-dep-regs.patch +usb-dwc3-add-dwc-pointer-to-dwc3_readl-writel.patch +usb-dwc3-move-guid-programming-after-phy-initializat.patch +btrfs-remove-fs_info-argument-from-btrfs_sysfs_add_s.patch +btrfs-fix-double-free-in-create_space_info_sub_group.patch +btrfs-fix-btrfs_ioctl_space_info-slot_count-toctou-w.patch +tracing-fprobe-use-rhltable-for-fprobe_ip_table.patch +tracing-fprobe-optimization-for-entry-only-case.patch +tracing-fprobe-unregister-fprobe-even-if-memory-allo.patch +tracing-fprobe-remove-fprobe-from-hash-in-failure-pa.patch +batman-adv-tp_meter-fix-tp_num-leak-on-kmalloc-failu.patch +vsock-fix-buffer-size-clamping-order.patch +vsock-virtio-fix-length-and-offset-in-tap-skb-for-sp.patch +vsock-virtio-fix-empty-payload-in-tap-skb-for-non-li.patch +vsock-virtio-fix-accept-queue-count-leak-on-transpor.patch +drm-amdgpu-vcn3-avoid-overflow-on-msg-bound-check.patch +drm-amdgpu-vcn4-avoid-overflow-on-msg-bound-check.patch +linux-6.18.32.patch +blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch +fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch +fs-mbcache-cancel-shrink-work-before-destroying-the-.patch +md-raid1-fix-the-comparing-region-of-interval-tree.patch +drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch +loop-fix-partition-scan-race-between-udev-and-loop_r.patch +nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch +blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch +pstore-ram-fix-resource-leak-when-ioremap-fails.patch +erofs-verify-metadata-accesses-for-file-backed-mount.patch +erofs-include-the-trailing-nul-in-fs_ioc_getfslabel.patch +md-fix-array_state-clear-sysfs-deadlock.patch +erofs-handle-48-bit-blocks-uniaddr-for-extra-devices.patch +dm-add-wq_percpu-to-alloc_workqueue-users.patch +md-remove-unused-static-md_wq-workqueue.patch +md-wake-raid456-reshape-waiters-before-suspend.patch +btrfs-fix-deadlock-between-reflink-and-transaction-c.patch +opp-debugfs-use-performance-level-if-available-to-di.patch +opp-move-break-out-of-scoped_guard-in-dev_pm_opp_xla.patch +acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch +acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch +devres-fix-missing-node-debug-info-in-devm_krealloc.patch +thermal-drivers-spear-fix-error-condition-for-readin.patch +debugfs-check-for-null-pointer-in-debugfs_create_str.patch +debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch +soundwire-debugfs-initialize-firmware_file-to-empty-.patch +amd-pstate-fix-memory-leak-in-amd_pstate_epp_cpu_ini.patch +amd-pstate-update-cppc_req_cached-in-fast_switch-cas.patch +cpufreq-pass-the-policy-to-cpufreq_driver-adjust_per.patch +pci-use-generic-driver_override-infrastructure.patch +platform-wmi-use-generic-driver_override-infrastruct.patch +vdpa-use-generic-driver_override-infrastructure.patch +s390-cio-use-generic-driver_override-infrastructure.patch +bus-fsl-mc-use-generic-driver_override-infrastructur.patch +irqchip-irq-pic32-evic-address-warning-related-to-wr.patch +hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch +hrtimer-reduce-trace-noise-in-hrtimer_start.patch +perf-amd-ibs-preserve-phyaddrval-bit-when-clearing-p.patch +perf-amd-ibs-avoid-calling-perf_allow_kernel-from-th.patch +x86-tdx-fix-the-typo-in-tdx_attr_migrtable.patch +rust-sync-atomic-remove-bound-t-sync-for-atomic-from.patch +sparc64-vdso-link-with-z-noexecstack.patch +scripts-gdb-timerlist-adapt-to-move-of-tk_core.patch +locking-fix-rwlock-support-in-linux-spinlock_up.h.patch +sched-topology-compute-sd_weight-considering-cpuset-.patch +sched-topology-fix-sched_domain_span.patch +irqchip-renesas-rzg2l-fix-error-path-in-rzg2l_irqc_c.patch +asoc-intel-avs-check-maximum-valid-cpuid-leaf.patch +asoc-intel-avs-include-cpuid-header-at-file-scope.patch +x86-vdso-clean-up-remnants-of-vdso32_note_mask.patch +firmware-dmi-correct-an-indexing-error-in-dmi.h.patch +sched-make-class_schedulers-avoid-pushing-current-an.patch +sched-rt-skip-group-schedulable-check-with-rt_group_.patch +wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch +wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch +bpf-test_run-fix-the-null-pointer-dereference-issue-.patch +wifi-ieee80211-split-mesh-definitions-out.patch +wifi-ieee80211-split-ht-definitions-out.patch +wifi-ieee80211-split-vht-definitions-out.patch +wifi-ieee80211-split-he-definitions-out.patch +wifi-ieee80211-split-eht-definitions-out.patch +wifi-ieee80211-fix-definition-of-eht-mcs-15-in-mru.patch +dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch +dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch +s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch +powerpc-pgtable-frag-fix-bad-page-state-in-pte_frag_.patch +params-replace-__modinit-with-__init_or_module.patch +module-fix-freeing-of-charp-module-parameters-when-c.patch +wifi-libertas-use-usb-anchors-for-tracking-in-flight.patch +wifi-libertas-don-t-kill-urbs-in-interrupt-context.patch +tools-nolibc-implement-m-if-errno-is-not-defined.patch +tools-nolibc-printf-change-variables-c-to-ch-and-tmp.patch +tools-nolibc-printf-move-snprintf-length-check-to-ca.patch +wifi-mt76-mt7996-fix-the-behavior-of-radar-detection.patch +wifi-mt76-mt7996-fix-iface-combination-for-different.patch +wifi-mt76-mt7996-set-mtxq-wcid-just-for-primary-link.patch +wifi-mt76-mt7996-reset-mtxq-idx-if-primary-link-is-r.patch +wifi-mt76-mt7996-clear-wcid-pointer-in-mt7996_mac_st.patch +wifi-mt76-mt7996-reset-ampdu_state-state-in-case-of-.patch +wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch +wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch +wifi-mt76-mt7615-fix-use_cts_prot-support.patch +wifi-mt76-mt7915-fix-use_cts_prot-support.patch +wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch +wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch +wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch +wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch +wifi-mt76-fix-memory-leak-destroying-device.patch +wifi-mt76-mt7925-cqm-rssi-low-high-event-notify.patch +wifi-mt76-mt7925-drop-puncturing-handling-from-bss-c.patch +wifi-mt76-mt7925-fix-potential-deadlock-in-mt7925_ro.patch +wifi-mt76-mt7921-fix-potential-deadlock-in-mt7921_ro.patch +wifi-mt76-fix-deadlock-in-remain-on-channel.patch +arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch +wifi-mt76-mt7996-fix-wrong-dmad-length-when-using-ma.patch +wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch +wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch +wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch +wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch +wifi-mt76-mt7996-add-missing-chanctx_sta_csa-propert.patch +wifi-mt76-mt7996-remove-link-pointer-dependency-in-m.patch +wifi-mt76-mt7996-use-correct-link_id-when-filling-tx.patch +wifi-mt76-mt7996-switch-to-the-secondary-link-if-the.patch +wifi-mt76-mt7996-decrement-sta-counter-removing-the-.patch +wifi-mt76-fix-multi-radio-on-channel-scanning.patch +wifi-mt76-support-upgrading-passive-scans-to-active.patch +wifi-mt76-mt7996-fix-rro-emu-configuration.patch +bpf-fix-refcount-check-in-check_struct_ops_btf_id.patch +bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch +bpf-fix-variable-length-stack-write-over-spilled-poi.patch +bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch +wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch +vfio-refactor-vfio_pci_mmap_huge_fault-function.patch +drivers-vfio_pci_core-change-pxd_order-check-from-sw.patch +r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch +powerpc-crash-fix-backup-region-offset-update-to-elf.patch +powerpc-crash-update-backup-region-offset-in-elfcore.patch +selftests-powerpc-suppress-wmaybe-uninitialized-with.patch +bpf-fix-abuse-of-kprobe_write_ctx-via-freplace.patch +macvlan-annotate-data-races-around-port-bc_queue_len.patch +bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch +bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch +net-ethernet-ti-cpsw-rename-soft_reset-function.patch +net-ethernet-ti-cpsw-fix-linking-built-in-code-to-mo.patch +wifi-brcmfmac-fix-error-pointer-dereference.patch +wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch +bpf-drop-task_to_inode-and-inet_conn_established-fro.patch +bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch +wifi-ath10k-fix-station-lookup-failure-during-discon.patch +bpf-support-negative-offsets-bpf_sub-and-alu32-for-l.patch +bpf-fix-linked-reg-delta-tracking-when-src_reg-dst_r.patch +arm64-entry-don-t-preempt-with-serror-or-debug-maske.patch +acpi-agdi-fix-missing-newline-in-error-message.patch +arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch +macsec-support-vlan-filtering-lower-devices.patch +net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch +net-bcmgenet-fix-leaking-free_bds.patch +net-bcmgenet-fix-racing-timeout-handler.patch +net-airoha-add-dma_rmb-and-read_once-in-airoha_qdma_.patch +eth-fbnic-use-wake-instead-of-start.patch +netfilter-xt_socket-enable-defrag-after-all-other-ch.patch +netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch +bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch +bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch +bpf-return-vma-snapshot-from-task_vma-iterator.patch +bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch +net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch +net-airoha-add-airoha_ppe_get_num_stats_entries-and-.patch +net-airoha-add-airoha_eth_soc_data-struct.patch +net-airoha-generalize-airoha_ppe2_is_enabled-routine.patch +net-airoha-fix-fe_pse_buf_set-configuration-if-ppe2-.patch +bpf-relax-scalar-id-equivalence-for-state-pruning.patch +bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch +selftests-bpf-fix-__jited_unpriv-tag-name.patch +net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch +selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch +net-mana-use-pci_name-for-debugfs-directory-naming.patch +net-mana-support-hw-link-state-events.patch +net-mana-move-current_speed-debugfs-file-to-mana_ini.patch +net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch +bpf-allow-instructions-with-arena-source-and-non-are.patch +selftests-bpf-fix-reg_bounds-to-match-new-tnum-based.patch +net-rds-optimize-rds_ib_laddr_check.patch +net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch +bpf-fix-oob-in-pcpu_init_value.patch +ppp-require-cap_net_admin-in-target-netns-for-unatta.patch +net-ipa-fix-programming-of-qtime_timestamp_cfg.patch +net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch +dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch +net-phy-fix-a-return-path-in-get_phy_c45_ids.patch +net-mlx5e-fix-features-not-applied-during-netdev-reg.patch +net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch +bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch +bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch +bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch +bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch +bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch +bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch +net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch +udp-force-compute_score-to-always-inline.patch +tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch +sctp-fix-missing-encap_port-propagation-for-gso-frag.patch +net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch +net-airoha-add-missing-ppe-configurations-in-airoha_.patch +selftests-futex-fix-incorrect-result-reporting-of-fu.patch +drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch +drm-virtio-allow-importing-prime-buffers-when-3d-is-.patch +asoc-soc-compress-use-function-to-clear-symmetric-pa.patch +pci-tph-allow-tph-enable-for-rcieps.patch +pci-endpoint-pci-epf-test-don-t-free-doorbell-irq-un.patch +pci-endpoint-pci-ep-msi-fix-error-unwind-and-prevent.patch +drm-sun4i-backend-fix-error-pointer-dereference.patch +pci-imx6-fix-device-node-reference-leak-in-imx_pcie_.patch +asoc-sdca-update-counting-of-su-ge-dapm-routes.patch +crypto-inside-secure-eip93-fix-register-definition.patch +asoc-sti-return-errors-from-regmap_field_alloc.patch +asoc-sti-use-managed-regmap_field-allocations.patch +dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch +dm-cache-fix-write-path-cache-coherency-in-passthrou.patch +dm-cache-fix-write-hang-in-passthrough-mode.patch +dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch +dm-cache-fix-concurrent-write-failure-in-passthrough.patch +dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch +dm-mpath-don-t-stop-probing-paths-at-presuspend.patch +platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch +pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch +pci-dwc-invoke-post_init-in-dw_pcie_resume_noirq.patch +pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch +dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch +dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch +iopoll-fix-function-parameter-names-in-read_poll_tim.patch +drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch +drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch +drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch +spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch +spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch +media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch +drm-amd-pm-fix-xgmi-max-speed-reporting.patch +selftests-sched_ext-add-missing-error-check-for-exit.patch +drm-v3d-handle-error-from-drm_sched_entity_init.patch +drm-sun4i-fix-resource-leaks.patch +crypto-inside-secure-eip93-register-hash-before-auth.patch +iommu-riscv-add-iotinval-after-updating-ddt-pdt-entr.patch +iommu-riscv-add-missing-generic_msi_irq.patch +iommu-riscv-stop-polling-when-cqcsr-reports-an-error.patch +drm-amdgpu-add-default-case-in-dvi-mode-validation.patch +dm-init-ensure-device-probing-has-finished-in-dm-mod.patch +fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch +crypto-tegra-disable-softirqs-before-finalizing-requ.patch +crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch +crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch +padata-remove-cpu-online-check-from-cpu-add-and-remo.patch +padata-put-cpu-offline-callback-in-online-section-to.patch +pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch +drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch +drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch +spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch +drm-imagination-switch-reset_reason-fields-from-enum.patch +iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch +iommu-tegra241-cmdqv-update-uapi-to-clarify-hyp_own-.patch +drm-msm-add-missing-module_device_id-definitions.patch +drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch +drm-msm-dsi-add-the-missing-parameter-description.patch +drm-msm-dpu-don-t-try-using-2-lms-if-only-one-dsc-is.patch +drm-msm-dsi-fix-bits_per_pclk.patch +drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch +drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch +asoc-rockchip-rockchip_sai-set-slot-width-for-non-td.patch +drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch +drm-panel-simple-correct-g190ean01-prepare-timing.patch +pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch +pci-use-res_to_dev_res-in-reassign_resources_sorted.patch +pci-fix-premature-removal-from-realloc_head-list-dur.patch +crypto-hisilicon-sec2-prevent-req-used-after-free-fo.patch +pci-fix-alignment-calculation-for-resource-size-larg.patch +iommu-riscv-skip-irq-count-check-when-using-msi-inte.patch +iommu-riscv-fix-signedness-bug.patch +alsa-core-validate-compress-device-numbers-without-d.patch +asoc-amd-acp-update-dmic_num-logic-for-acp-pdm-dmic.patch +drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch +drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch +drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch +drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch +drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch +drm-amd-pm-ci-fill-dw8-fields-from-smc.patch +drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch +drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch +pci-dpc-log-aer-error-info-for-dpc-edr-uncorrectable.patch +hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch +alsa-hda-realtek-fix-code-style-error-else-should-fo.patch +asoc-sof-intel-hda-place-check-before-dereference.patch +drm-msm-vma-avoid-lock-in-vm_bind-fence-signaling-pa.patch +drm-msm-reject-fb-creation-from-_no_share-objs.patch +drm-msm-fix-vm_bind-unmap-locking.patch +drm-msm-a6xx-fix-hlsq-register-dumping.patch +drm-msm-shrinker-fix-can_block-logic.patch +drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch +drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch +alsa-hda-cmedia-remove-duplicate-pin-configuration-p.patch +pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch +pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch +pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch +drm-msm-dpu-drop-intf_0-on-msm8953.patch +asoc-fsl_micfil-add-access-property-for-vad-detected.patch +asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch +asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch +asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch +asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch +asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch +iommu-amd-fix-clone_alias-to-use-the-original-device.patch +iommu-riscv-remove-overflows-on-the-invalidation-pat.patch +asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch +pci-dwc-fix-type-mismatch-for-kstrtou32_from_user-re.patch +crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch +crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch +crypto-qat-fix-compression-instance-leak.patch +crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch +crypto-iaa-fix-per-node-cpu-counter-reset-in-rebalan.patch +crypto-qat-use-swab32-macro.patch +asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch +pci-enable-atomicops-only-if-root-port-supports-them.patch +pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch +gpu-nova-core-register-use-field-type-for-into-imple.patch +gpu-nova-core-bitfield-move-bitfield-specific-code-f.patch +gpu-nova-core-bitfield-fix-broken-default-implementa.patch +selftests-mm-skip-migration-tests-if-numa-is-unavail.patch +kho-make-debugfs-interface-optional.patch +kho-fix-kasan-support-for-restored-vmalloc-regions.patch +documentation-fix-a-hugetlbfs-reservation-statement.patch +selftest-memcg-skip-memcg_sock-test-if-address-famil.patch +alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch +asoc-sof-compress-return-the-configured-codec-from-g.patch +pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch +alsa-usb-audio-qcom-fix-incorrect-type-in-enable_aud.patch +pci-tegra194-fix-polling-delay-for-l2-state.patch +pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch +pci-tegra194-disable-ltssm-after-transition-to-detec.patch +pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch +pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch +pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch +pci-tegra194-disable-direct-speed-change-for-endpoin.patch +pci-tegra194-set-ltr-message-request-before-pcie-lin.patch +pci-tegra194-allow-system-suspend-when-the-endpoint-.patch +pci-tegra194-free-up-endpoint-resources-during-remov.patch +pci-tegra194-use-dwc-ip-core-version.patch +pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch +pci-tegra194-remove-unnecessary-l1ss-disable-code.patch +pci-tegra194-disable-l1.2-capability-of-tegra234-ep.patch +pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch +spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch +alsa-sc6000-keep-the-programmed-board-state-in-card-.patch +dm-cache-fix-missing-return-in-invalidate_committed-.patch +sched_ext-track-p-s-rq-lock-across-set_cpus_allowed_.patch +sched_ext-fix-ops.cgroup_move-invocation-kf_mask-and.patch +crypto-jitterentropy-replace-long-held-spinlock-with.patch +alsa-usb-audio-exclude-scarlett-18i20-1st-gen-from-s.patch +alsa-hda-realtek-fixed-speaker-no-sound-update.patch +gfs2-call-unlock_new_inode-before-d_instantiate.patch +fanotify-avoid-silence-premature-lsm-capability-chec.patch +fanotify-call-fanotify_events_supported-before-path_.patch +fuse-fix-premature-writetrhough-request-for-large-fo.patch +dcache-export-shrink_dentry_list-and-add-new-helper-.patch +fuse-new-work-queue-to-periodically-invalidate-expir.patch +fuse-fix-uninit-value-in-fuse_dentry_revalidate.patch +ktest-avoid-undef-warning-when-warnings_file-is-unse.patch +ktest-honor-empty-per-test-option-overrides.patch +ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch +rtla-fix-c-cgroup-interface.patch +rtla-replace-atoi-with-a-robust-strtoi.patch +rtla-utils-fix-resource-leak-in-set_comm_sched_attr.patch +gfs2-less-aggressive-low-memory-log-flushing.patch +quota-fix-race-of-dquot_scan_active-with-quota-deact.patch +vfio-unhide-vdev-debug_root.patch +gfs2-add-some-missing-log-locking.patch +gfs2-prevent-null-pointer-dereference-during-unmount.patch +efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch +ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch +arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch +arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch +memory-tegra124-emc-fix-dll_change-check.patch +memory-tegra30-emc-fix-dll_change-check.patch +arm64-dts-imx8-apalis-fix-leds-name-collision.patch +arm64-dts-imx91-11x11-evk-change-usdhc-tuning-step-f.patch +arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch +arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch +iommufd-vfio-compatibility-extension-check-for-noiom.patch +arm64-dts-qcom-sm6125-ginkgo-fix-missing-msm-id-subt.patch +arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-board-id.patch +arm64-dts-qcom-sm6125-xiaomi-ginkgo-correct-reserved.patch +arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-extcon.patch +arm64-dts-qcom-sm6125-xiaomi-ginkgo-fix-reserved-gpi.patch +arm64-dts-qcom-talos-add-missing-clock-names-to-gcc.patch +arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch +arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch +arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch +iommufd-selftest-fix-page-leaks-in-mock_viommu_-init.patch +arm64-dts-imx8mp-kontron-fix-touch-reset-configurati.patch +arm64-dts-imx8mp-kontron-drop-vmmc-supply-to-fix-sd-.patch +arm64-dts-imx8mp-hummingboard-pulse-fix-mini-hdmi-ds.patch +arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch +arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch +arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch +revert-arm64-dts-rockchip-add-spdif-audio-to-beelink.patch +arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch +arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch +soc-qcom-ocmem-make-the-core-clock-optional.patch +soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch +soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch +arm64-dts-rockchip-fix-rk3562-evb2-model-name.patch +arm64-dts-rockchip-add-mphy-reset-to-ufshc-node.patch +bus-rifsc-fix-rif-configuration-check-for-peripheral.patch +arm64-dts-qcom-hamoa-correct-iris-corners-for-the-mx.patch +arm64-dts-qcom-lemans-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-monaco-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-sm8550-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-sm8650-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8750-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch +arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch +arm64-dts-qcom-hamoa-fix-xo-clock-supply-of-platform.patch +arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch +arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch +arm64-dts-qcom-msm8917-xiaomi-riva-fix-board-id-for-.patch +arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch +arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch +arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch +arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch +arm64-dts-imx8mp-kontron-fix-boot-order-for-pmic-and.patch +arm64-dts-imx8dxl-evk-use-audio-graph-card2-for-wm89.patch +arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch +arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch +arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch +arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch +arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch +arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch +arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch +arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch +soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch +soc-tegra-cbb-fix-incorrect-array_size-in-fabric-loo.patch +soc-tegra-cbb-fix-cross-fabric-target-timeout-lookup.patch +unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch +ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch +ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch +soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch +soc-qcom-aoss-compare-against-normalized-cooling-sta.patch +arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch +arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch +arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch +slab-introduce-kmalloc_obj-and-family.patch +lib-kunit_iov_iter-fix-memory-leaks.patch +arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch +firmware-arm_ffa-use-the-correct-buffer-size-during-.patch +fwctl-fix-class-init-ordering-to-avoid-null-pointer-.patch +ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch +ocfs2-validate-bg_bits-during-freefrag-scan.patch +ocfs2-validate-group-add-input-before-caching.patch +dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch +soundwire-bus-demote-unattached-state-warnings-to-de.patch +soundwire-intel-test-bus.bpt_stream-before-assigning.patch +dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch +soundwire-cadence-clear-message-complete-before-sign.patch +tracing-remove-size-parameter-in-__trace_puts.patch +tracing-move-tracing-declarations-from-kernel.h-to-a.patch +tracing-move-__printf-attribute-on-__ftrace_vbprintk.patch +tracing-rebuild-full_name-on-each-hist_field_name-ca.patch +hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch +remoteproc-xlnx-fix-sram-property-parsing.patch +stop_machine-fix-the-documentation-for-a-null-cpus-a.patch +remoteproc-imx_rproc-check-return-value-of-regmap_at.patch +ima-check-return-value-of-crypto_shash_final-in-boot.patch +hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch +hid-asus-do-not-abort-probe-when-not-necessary.patch +mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch +ima_fs-correctly-create-securityfs-files-for-unsuppo.patch +dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch +mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch +mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch +mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch +mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch +mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch +mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch +mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch +cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch +mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch +mtd-spinand-add-missing-check.patch +mtd-spinand-decouple-write-enable-and-write-disable-.patch +mtd-spinand-create-an-array-of-operation-templates.patch +mtd-spinand-winbond-rename-io_mode-register-macro.patch +mtd-spinand-winbond-configure-the-io-mode-after-the-.patch +mtd-spinand-gather-all-the-bus-interface-steps-in-on.patch +mtd-spinand-add-support-for-setting-a-bus-interface.patch +mtd-spinand-give-the-bus-interface-to-the-configurat.patch +mtd-spinand-winbond-clarify-when-to-enable-the-hs-bi.patch +hid-usbhid-fix-deadlock-in-hid_post_reset.patch +ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch +bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch +bpf-arm64-remove-redundant-bpf_flush_icache-after-pa.patch +bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch +bpf-sockmap-fix-af_unix-iter-deadlock.patch +bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch +bpf-sockmap-take-state-lock-for-af_unix-iter.patch +bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch +bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch +bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch +libbpf-prevent-double-close-and-leak-of-btf-objects.patch +bpf-validate-node_id-in-arena_alloc_pages.patch +bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch +perf-trace-fix-is_err-vs-null-check-bug.patch +pinctrl-pinctrl-pic32-fix-resource-leak.patch +perf-trace-avoid-an-err_ptr-in-syscall_stats.patch +pinctrl-cy8c95x0-remove-duplicate-error-message.patch +pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch +pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch +perf-branch-avoid-incrementing-null.patch +perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch +pinctrl-pinconf-generic-fully-validate-pinmux-proper.patch +pinctrl-realtek-fix-function-signature-for-config-ar.patch +pinctrl-abx500-fix-type-of-argument-variable.patch +pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch +perf-lock-fix-option-value-type-in-parse_max_stack.patch +perf-stat-fix-opt-value-type-for-parse_cache_level.patch +memblock-reserve_mem-fix-end-caclulation-in-reserve_.patch +perf-tools-fix-module-symbol-resolution-for-non-zero.patch +perf-expr-return-einval-for-syntax-error-in-expr__fi.patch +ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch +ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch +ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch +perf-cgroup-update-metric-leader-in-evlist__expand_c.patch +pinctrl-sophgo-pinctrl-sg2042-fix-wrong-module-descr.patch +pinctrl-sophgo-pinctrl-sg2044-fix-wrong-module-descr.patch +perf-maps-fix-fixup_overlap_and_insert-that-can-brea.patch +perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch +perf-util-kill-die-prototype-dead-for-a-long-time.patch +i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch +i3c-master-renesas-fix-memory-leak-in-renesas_i3c_i3.patch +i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch +i3c-master-fix-error-codes-at-send_ccc_cmd.patch +i3c-master-adi-fix-error-propagation-for-cccs.patch +i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch +backlight-sky81452-backlight-check-return-value-of-d.patch +platform-surface-surfacepro3_button-drop-wakeup-sour.patch +leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch +usb-typec-fix-error-pointer-dereference.patch +tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch +usb-typec-ps883x-fix-oops-at-unbind.patch +platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch +platform-x86-barco-p50-gpio-normalize-return-value-o.patch +mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch +nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch +nfsd-fix-nfs4_file-access-extra-count-in-nfsd4_add_r.patch +platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch +platform-x86-asus-wmi-fix-screenpad-brightness-range.patch +tty-serial-ip22zilog-fix-section-mispatch-warning.patch +fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch +platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch +platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch +rdma-core-prefer-nla_nul_string.patch +dt-bindings-clock-qcom-add-gcc-video-axi-reset-clock.patch +clk-qcom-gcc-glymur-add-video-axi-clock-resets-for-g.patch +clk-qcom-dispcc-glymur-use-rcg2-ops-for-dptx1-aux-cl.patch +clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch +clk-sunxi-ng-sun55i-a523-r-add-missing-r-spi-module-.patch +scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch +scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch +clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch +clk-qcom-dispcc-glymur-fix-dsi-byte-clock-rate-setti.patch +clk-qcom-dispcc-milos-fix-dsi-byte-clock-rate-settin.patch +clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch +clk-qcom-dispcc-01-sa8775p-fix-dsi-byte-clock-rate-s.patch +clk-renesas-r9a09g057-add-clock-and-reset-entries-fo.patch +clk-renesas-r9a09g057-add-entries-for-rscis.patch +clk-renesas-r9a09g057-fix-ordering-of-module-clocks-.patch +clk-renesas-r9a09g057-remove-entries-for-wdt-0-2-3.patch +scsi-target-core-fix-integer-overflow-in-unmap-bound.patch +scsi-ufs-rockchip-rk3576-ufshc-dt-bindings-add-new-m.patch +dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch +clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch +clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch +clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch +clk-imx8mq-correct-the-csi-phy-sels.patch +x86-um-vdso-drop-vdso64-y-from-makefile.patch +x86-um-fix-vdso-installation.patch +clk-qoriq-avoid-format-string-warning.patch +clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch +dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch +clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch +clk-spacemit-ccu_mix-fix-inverted-condition-in-ccu_m.patch +f2fs-use-f2fs_filemap_get_folio-instead-of-f2fs_page.patch +f2fs-avoid-reading-already-updated-pages-during-gc.patch +clk-qcom-gdsc-fix-error-path-on-registration-of-mult.patch +lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch +f2fs-expand-scalability-of-f2fs-mount-option.patch +f2fs-fix-to-preserve-previous-reserve_-blocks-node-v.patch +clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch +clk-visconti-pll-initialize-clk_init_data-to-zero.patch +f2fs-allow-empty-mount-string-for-opt_usr-grp-projjq.patch +f2fs-protect-extension_list-reading-with-sb_lock-in-.patch +drm-i915-wm-verify-the-correct-plane-ddb-entry.patch +virt-arm-cca-guest-fix-error-check-for-rsi_incomplet.patch +crypto-eip93-fix-hmac-setkey-algo-selection.patch +crypto-sa2ul-fix-aead-fallback-algorithm-names.patch +crypto-ccp-copy-iv-using-skcipher-ivsize.patch +erofs-unify-lcn-as-u64-for-32-bit-platforms.patch +arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch +arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch +arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch +arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch +arm64-dts-imx8mp-edm-g-correct-pad-settings-for-pmic.patch +arm64-dts-imx8mp-aristainetos3a-som-v1-correct-pad-s.patch +arm64-dts-imx8mp-nitrogen-som-correct-pad-settings-f.patch +arm64-dts-imx8mp-sr-som-correct-pad-settings-for-pmi.patch +arm64-dts-imx8mp-ultra-mach-sbc-correct-pad-settings.patch +arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch +arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch +pcmcia-fix-garbled-log-messages-for-kern_cont.patch +reset-amlogic-t7-fix-null-reset-ops.patch +arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch +arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch +arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch +arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch +pwm-stm32-fix-rounding-issue-for-requests-with-inver.patch +net-sched-act_mirred-fix-wrong-device-for-mac_header.patch +macvlan-fix-macvlan_get_size-not-reserving-space-for.patch +net-sched-sch_cake-fix-nat-destination-port-not-bein.patch +nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch +net-airoha-wait-for-npu-ppe-configuration-to-complet.patch +net-sched-taprio-fix-use-after-free-in-advance_sched.patch +net-dsa-cpu_dp-orig_ethtool_ops-might-be-null.patch +net-dsa-use-kernel-data-types-for-ethtool-ops-on-con.patch +net-dsa-append-ethtool-counters-of-all-hidden-ports-.patch +net-dsa-remove-redundant-netdev_lock_ops-from-condui.patch +net-enetc-correct-the-command-bd-ring-consumer-index.patch +net-enetc-fix-ntmp-dma-use-after-free-issue.patch +smb-move-smb_version_values-to-common-smbglob.h.patch +ksmbd-fix-use-after-free-in-smb2_open-during-durable.patch +tcp-move-tp-chrono_type-next-tp-chrono_stat.patch +tcp-inline-tcp_chrono_start.patch +tcp-annotate-data-races-in-tcp_get_info_chrono_stats.patch +tcp-add-data-race-annotations-around-tp-data_segs_ou.patch +tcp-add-data-races-annotations-around-tp-reordering-.patch +tcp-annotate-data-races-around-tp-snd_ssthresh.patch +tcp-annotate-data-races-around-tp-delivered-and-tp-d.patch +tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch +tcp-annotate-data-races-around-tp-bytes_sent.patch +tcp-annotate-data-races-around-tp-bytes_retrans.patch +tcp-annotate-data-races-around-tp-dsack_dups.patch +tcp-annotate-data-races-around-tp-reord_seen.patch +tcp-better-handle-tcp_tx_delay-on-established-flows.patch +tcp-annotate-data-races-around-tp-srtt_us.patch +tcp-annotate-data-races-around-tp-timeout_rehash.patch +tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch +tcp-annotate-data-races-around-tp-plb_rehash.patch +ice-fix-adjust-timer-programming-for-e830-devices.patch +ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch +ice-remove-jumbo_remove-step-from-tx-path.patch +ice-fix-double-free-of-tx_buf-skb.patch +ice-fix-ice_aq_link_speed_m-for-200g.patch +i40e-don-t-advertise-iff_supp_nofcs.patch +iavf-fix-wrong-vlan-mask-for-legacy-rx-descriptors-l.patch +e1000e-unroll-ptp-in-probe-error-handling.patch +ipv6-fix-possible-uaf-in-icmpv6_rcv.patch +sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch +pppoe-drop-pfc-frames.patch +net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch +openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch +net-airoha-fix-possible-tx-queue-stall-in-airoha_qdm.patch +netfilter-nft_osf-restrict-it-to-ipv4.patch +netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch +netfilter-conntrack-remove-sprintf-usage.patch +netfilter-xtables-restrict-several-matches-to-inet-f.patch +netfilter-nat-use-kfree_rcu-to-release-ops.patch +ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch +netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch +netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch +slip-reject-vj-receive-packets-on-instances-with-no-.patch +slip-bound-decode-reads-against-the-compressed-packe.patch +net-sched-sch_dualpi2-drain-both-c-queue-and-l-queue.patch +arm64-dts-amlogic-meson-axg-add-missing-cache-inform.patch +arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch +pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch +ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch +ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch +ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch +ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch +net-validate-skb-napi_id-in-rx-tracepoints.patch +bnge-fix-initial-hwrm-sequence.patch +bnge-remove-unsupported-backing-store-type.patch +net-rds-zero-per-item-info-buffer-before-handing-it-.patch +ice-fix-timestamp-interrupt-configuration-for-e825c.patch +ice-perform-phy-soft-reset-for-e825c-ports-at-initia.patch +ice-fix-ready-bitmap-check-for-non-e822-devices.patch +ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch +net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch +net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch +net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch +net-sched-sch_red-annotate-data-races-in-red_dump_st.patch +net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch +net-airoha-ppe-dynamically-allocate-foe_check_time-a.patch +net-airoha-ppe-move-ppe-memory-info-in-airoha_eth_so.patch +net-airoha-refactor-src-port-configuration-in-airhoh.patch +net-airoha-add-an7583-soc-support.patch +net-airoha-add-the-capability-to-consume-out-of-orde.patch +net-airoha-add-missing-bits-in-airoha_qdma_cleanup_t.patch +net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch +net-airoha-move-ndesc-initialization-at-end-of-airoh.patch +net-airoha-rework-the-code-flow-in-airoha_remove-and.patch +net-airoha-add-size-check-for-tx-napis-in-airoha_qdm.patch +net-mana-init-link_change_work-before-potential-erro.patch +net-mana-guard-mana_remove-against-double-invocation.patch +net-mana-move-hardware-counter-stats-from-per-port-t.patch +net-mana-add-standard-counter-rx_missed_errors.patch +net-mana-don-t-overwrite-port-probe-error-with-add_a.patch +net-mana-handle-skb-if-tx-sges-exceed-hardware-limit.patch +net-mana-handle-hardware-recovery-events-when-probin.patch +net-mana-implement-ndo_tx_timeout-and-serialize-queu.patch +net-mana-fix-eq-leak-in-mana_remove-on-null-port.patch +vsock-virtio-fix-msg_zerocopy-pinned-pages-accountin.patch +virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch +nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch +tcp-send-a-challenge-ack-on-seg.ack-snd.nxt.patch +tipc-fix-double-free-in-tipc_buf_append.patch +vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch +nstree-fix-func.-parameter-kernel-doc-warnings.patch +eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch +eventpoll-split-__ep_remove.patch +eventpoll-kill-__ep_remove.patch +eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch +eventpoll-move-epi_fget-up.patch +eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch +fs-adfs-validate-nzones-in-adfs_validate_bblk.patch +rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch +kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch +fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch +tools-power-turbostat.8-document-the-force-option.patch +tools-power-turbostat-use-strtoul-for-iteration-pars.patch +tools-power-turbostat-fix-and-document-header_iterat.patch +tools-power-turbostat-fix-unrecognized-option-p.patch +kbuild-never-respect-config_werror-w-e-to-fixdep.patch +mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch +mailbox-mailbox-test-free-channels-on-probe-error.patch +sched-psi-fix-race-between-file-release-and-pressure.patch +cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch +mailbox-add-sanity-check-for-channel-array.patch +mailbox-mailbox-test-don-t-free-the-reused-channel.patch +mailbox-mailbox-test-initialize-struct-earlier.patch +mailbox-mailbox-test-make-data_ready-a-per-instance-.patch +fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch +btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch +cgroup-increment-nr_dying_subsys_-from-rmdir-context.patch +tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch +nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch +netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch +netfilter-nf_tables-use-list_del_rcu-for-netlink-hoo.patch +nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch +drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch +drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch +drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch +drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch +netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch +netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch +asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch +spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch +asoc-tas2764-mark-die-temp-register-as-volatile.patch +asoc-tas2770-fix-order-of-operations-for-temperature.patch +drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch +drm-color-mgmt-typo-s-r332-rgb332.patch +arm64-scs-fix-potential-sign-extension-issue-of-adva.patch +acpica-provide-defines-for-einjv2-error-types.patch +acpi-apei-einj-fix-einjv2-memory-error-injection.patch +cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch +netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch +net-sched-netem-fix-probability-gaps-in-4-state-loss.patch +net-sched-netem-fix-queue-limit-check-to-include-reo.patch +net-sched-netem-only-reseed-prng-when-seed-is-explic.patch +net-sched-netem-validate-slot-configuration.patch +net-sched-netem-fix-slot-delay-calculation-overflow.patch +net-sched-netem-check-for-negative-latency-and-jitte.patch +net-airoha-stop-net_device-tx-queue-before-updating-.patch +net-airoha-fix-typo-in-function-name.patch +net-airoha-do-not-wake-all-netdev-tx-queues-in-airoh.patch +net-airoha-do-not-read-uninitialized-fragment-addres.patch +net-sched-sch_choke-annotate-data-races-in-choke_dum.patch +net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch +vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch +net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch +net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch +spi-amlogic-spisg-initialize-completion-before-reque.patch +nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch +net-sched-taprio-fix-null-pointer-dereference-in-cla.patch +neigh-let-neigh_xmit-take-skb-ownership.patch +tcp-make-probe0-timer-handle-expired-user-timeout.patch +netpoll-fix-ipv6-local-address-corruption.patch +alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch +sched-fair-reimplement-next_buddy-to-align-with-eevd.patch +sched-fair-fix-wakeup_preempt_fair-vs-delayed-dequeu.patch +sched-fair-clear-rel_deadline-when-initializing-fork.patch +net-mctp-i2c-check-length-before-marking-flow-active.patch +md-raid1-raid10-don-t-fail-devices-for-invalid-io-er.patch +md-add-fallback-to-correct-bitmap_ops-on-version-mis.patch +md-factor-bitmap-creation-away-from-sysfs-handling.patch +md-md-bitmap-split-bitmap-sysfs-groups.patch +md-md-bitmap-add-a-none-backend-for-bitmap-grow.patch +s390-mm-fix-phys_to_folio-usage-in-do_secure_storage.patch +net-phy-dp83869-fix-setting-clk_o_sel-field.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0-enc-ri.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.1-enc-.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.1-ri.patch +io_uring-napi-cap-busy_poll_to-10-msec.patch +net-psp-check-for-device-unregister-when-creating-as.patch +net-psp-require-admin-permission-for-dev-set-and-key.patch +asoc-codecs-ab8500-fix-casting-of-private-data.patch +netfilter-skip-recording-stale-or-retransmitted-init.patch +sctp-discard-stale-init-after-handshake-completion.patch +bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-23535 +netconsole-propagate-device-name-truncation-in-dev_n.patch +alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch +alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch +alsa-hda-tas2781-fix-incorrect-bit-update-for-non-bo.patch +futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch +drm-amd-display-allow-dce-link-encoder-without-aux-r.patch +drm-amd-display-allow-constructing-dce6-link-encoder.patch +drm-amd-display-allow-constructing-dce8-link-encoder.patch +drm-amd-display-read-edid-from-vbios-embedded-panel-.patch +drm-xe-debugfs-correct-printing-of-register-whitelis.patch +drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch +drm-xe-eustall-fix-drm_dev_put-called-before-stream-.patch +drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch +net-airoha-fix-bql-imbalance-in-tx-path.patch +net-airoha-do-not-return-err-in-ndo_stop-callback.patch +bonding-print-churn-state-via-netlink.patch +bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch +page_pool-fix-memory-provider-leak-in-page_pool_crea.patch +iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch +iavf-stop-removing-vlan-filters-from-pf-on-interface.patch +iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch +iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch +ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch +ice-fix-infinite-recursion-in-ice_cfg_tx_topo-via-ic.patch +ice-fix-missing-sma-pin-initialization-in-dpll-subsy.patch +ice-fix-sma-and-u.fl-pin-state-changes-affecting-pai.patch +ice-fix-missing-dpll-notifications-for-sw-pins.patch +dpll-allow-associating-dpll-pin-with-a-firmware-node.patch +dpll-add-notifier-chain-for-dpll-events.patch +dpll-export-__dpll_pin_change_ntf-for-use-under-dpll.patch +ice-add-dpll-peer-notification-for-paired-sma-and-u..patch +net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch +sfc-fix-error-code-in-efx_devlink_info_running_versi.patch +net-sched-cls_flower-revert-unintended-changes.patch +kselftest-arm64-include-asm-ptrace.h-for-user_gcs-de.patch +arm64-reserve-an-extra-page-for-early-kernel-mapping.patch +futex-drop-clone_thread-requirement-for-private-defa.patch diff --git a/queue-6.18/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch b/queue-6.18/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch new file mode 100644 index 0000000000..802af2a255 --- /dev/null +++ b/queue-6.18/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch @@ -0,0 +1,37 @@ +From b3c43b61694d8ca8d657c839d6456fc5b415fc1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:48:17 +0300 +Subject: sfc: fix error code in efx_devlink_info_running_versions() + +From: Dan Carpenter + +[ Upstream commit 051ffb001b8a232cfa6e72f38bb5f51c4270a60b ] + +Return -EIO if efx_mcdi_rpc() doesn't return enough space. + +Fixes: 14743ddd2495 ("sfc: add devlink info support for ef100") +Signed-off-by: Dan Carpenter +Reviewed-by: Edward Cree +Link: https://patch.msgid.link/afGpsbLRHL4_H0KS@stanley.mountain +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sfc/efx_devlink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c +index d842c60dfc100..e5c6f81af48be 100644 +--- a/drivers/net/ethernet/sfc/efx_devlink.c ++++ b/drivers/net/ethernet/sfc/efx_devlink.c +@@ -531,7 +531,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx, + if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) { + netif_err(efx, drv, efx->net_dev, + "mcdi MC_CMD_GET_VERSION failed\n"); +- return rc; ++ return rc ?: -EIO; + } + + /* Handle previous output */ +-- +2.53.0 + diff --git a/queue-6.18/slab-introduce-kmalloc_obj-and-family.patch b/queue-6.18/slab-introduce-kmalloc_obj-and-family.patch new file mode 100644 index 0000000000..4f7940c97d --- /dev/null +++ b/queue-6.18/slab-introduce-kmalloc_obj-and-family.patch @@ -0,0 +1,166 @@ +From 4f7cfc3749e2bfe883d7f58274c594078afe2419 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Dec 2025 15:30:31 -0800 +Subject: slab: Introduce kmalloc_obj() and family + +From: Kees Cook + +[ Upstream commit 2932ba8d9c99875b98c951d9d3fd6d651d35df3a ] + +Introduce type-aware kmalloc-family helpers to replace the common +idioms for single object and arrays of objects allocation: + + ptr = kmalloc(sizeof(*ptr), gfp); + ptr = kmalloc(sizeof(struct some_obj_name), gfp); + ptr = kzalloc(sizeof(*ptr), gfp); + ptr = kmalloc_array(count, sizeof(*ptr), gfp); + ptr = kcalloc(count, sizeof(*ptr), gfp); + +These become, respectively: + + ptr = kmalloc_obj(*ptr, gfp); + ptr = kmalloc_obj(*ptr, gfp); + ptr = kzalloc_obj(*ptr, gfp); + ptr = kmalloc_objs(*ptr, count, gfp); + ptr = kzalloc_objs(*ptr, count, gfp); + +Beyond the other benefits outlined below, the primary ergonomic benefit +is the elimination of needing "sizeof" nor the type name, and the +enforcement of assignment types (they do not return "void *", but rather +a pointer to the type of the first argument). The type name _can_ be +used, though, in the case where an assignment is indirect (e.g. via +"return"). This additionally allows[1] variables to be declared via +__auto_type: + + __auto_type ptr = kmalloc_obj(struct foo, gfp); + +Internal introspection of the allocated type now becomes possible, +allowing for future alignment-aware choices to be made by the allocator +and future hardening work that can be type sensitive. For example, +adding __alignof(*ptr) as an argument to the internal allocators so that +appropriate/efficient alignment choices can be made, or being able to +correctly choose per-allocation offset randomization within a bucket +that does not break alignment requirements. + +Link: https://lore.kernel.org/all/CAHk-=wiCOTW5UftUrAnvJkr6769D29tF7Of79gUjdQHS_TkF5A@mail.gmail.com/ [1] +Acked-by: Vlastimil Babka +Link: https://patch.msgid.link/20251203233036.3212363-1-kees@kernel.org +Signed-off-by: Kees Cook +Stable-dep-of: 0b49c7d0ae69 ("lib: kunit_iov_iter: fix memory leaks") +Signed-off-by: Sasha Levin +--- + Documentation/process/deprecated.rst | 24 ++++++++++++ + include/linux/slab.h | 58 ++++++++++++++++++++++++++++ + 2 files changed, 82 insertions(+) + +diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst +index 1f7f3e6c9cda9..91c628fa2d59c 100644 +--- a/Documentation/process/deprecated.rst ++++ b/Documentation/process/deprecated.rst +@@ -372,3 +372,27 @@ The helper must be used:: + DECLARE_FLEX_ARRAY(struct type2, two); + }; + }; ++ ++Open-coded kmalloc assignments for struct objects ++------------------------------------------------- ++Performing open-coded kmalloc()-family allocation assignments prevents ++the kernel (and compiler) from being able to examine the type of the ++variable being assigned, which limits any related introspection that ++may help with alignment, wrap-around, or additional hardening. The ++kmalloc_obj()-family of macros provide this introspection, which can be ++used for the common code patterns for single, array, and flexible object ++allocations. For example, these open coded assignments:: ++ ++ ptr = kmalloc(sizeof(*ptr), gfp); ++ ptr = kzalloc(sizeof(*ptr), gfp); ++ ptr = kmalloc_array(count, sizeof(*ptr), gfp); ++ ptr = kcalloc(count, sizeof(*ptr), gfp); ++ ptr = kmalloc(sizeof(struct foo, gfp); ++ ++become, respectively:: ++ ++ ptr = kmalloc_obj(*ptr, gfp); ++ ptr = kzalloc_obj(*ptr, gfp); ++ ptr = kmalloc_objs(*ptr, count, gfp); ++ ptr = kzalloc_objs(*ptr, count, gfp); ++ __auto_type ptr = kmalloc_obj(struct foo, gfp); +diff --git a/include/linux/slab.h b/include/linux/slab.h +index 2482992248dc9..cbb64a2698f5d 100644 +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -12,6 +12,7 @@ + #ifndef _LINUX_SLAB_H + #define _LINUX_SLAB_H + ++#include + #include + #include + #include +@@ -965,6 +966,63 @@ static __always_inline __alloc_size(1) void *kmalloc_noprof(size_t size, gfp_t f + void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node); + #define kmalloc_nolock(...) alloc_hooks(kmalloc_nolock_noprof(__VA_ARGS__)) + ++/** ++ * __alloc_objs - Allocate objects of a given type using ++ * @KMALLOC: which size-based kmalloc wrapper to allocate with. ++ * @GFP: GFP flags for the allocation. ++ * @TYPE: type to allocate space for. ++ * @COUNT: how many @TYPE objects to allocate. ++ * ++ * Returns: Newly allocated pointer to (first) @TYPE of @COUNT-many ++ * allocated @TYPE objects, or NULL on failure. ++ */ ++#define __alloc_objs(KMALLOC, GFP, TYPE, COUNT) \ ++({ \ ++ const size_t __obj_size = size_mul(sizeof(TYPE), COUNT); \ ++ (TYPE *)KMALLOC(__obj_size, GFP); \ ++}) ++ ++/** ++ * kmalloc_obj - Allocate a single instance of the given type ++ * @VAR_OR_TYPE: Variable or type to allocate. ++ * @GFP: GFP flags for the allocation. ++ * ++ * Returns: newly allocated pointer to a @VAR_OR_TYPE on success, or NULL ++ * on failure. ++ */ ++#define kmalloc_obj(VAR_OR_TYPE, GFP) \ ++ __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), 1) ++ ++/** ++ * kmalloc_objs - Allocate an array of the given type ++ * @VAR_OR_TYPE: Variable or type to allocate an array of. ++ * @COUNT: How many elements in the array. ++ * @GFP: GFP flags for the allocation. ++ * ++ * Returns: newly allocated pointer to array of @VAR_OR_TYPE on success, ++ * or NULL on failure. ++ */ ++#define kmalloc_objs(VAR_OR_TYPE, COUNT, GFP) \ ++ __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), COUNT) ++ ++/* All kzalloc aliases for kmalloc_(obj|objs|flex). */ ++#define kzalloc_obj(P, GFP) \ ++ __alloc_objs(kzalloc, GFP, typeof(P), 1) ++#define kzalloc_objs(P, COUNT, GFP) \ ++ __alloc_objs(kzalloc, GFP, typeof(P), COUNT) ++ ++/* All kvmalloc aliases for kmalloc_(obj|objs|flex). */ ++#define kvmalloc_obj(P, GFP) \ ++ __alloc_objs(kvmalloc, GFP, typeof(P), 1) ++#define kvmalloc_objs(P, COUNT, GFP) \ ++ __alloc_objs(kvmalloc, GFP, typeof(P), COUNT) ++ ++/* All kvzalloc aliases for kmalloc_(obj|objs|flex). */ ++#define kvzalloc_obj(P, GFP) \ ++ __alloc_objs(kvzalloc, GFP, typeof(P), 1) ++#define kvzalloc_objs(P, COUNT, GFP) \ ++ __alloc_objs(kvzalloc, GFP, typeof(P), COUNT) ++ + #define kmem_buckets_alloc(_b, _size, _flags) \ + alloc_hooks(__kmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE)) + +-- +2.53.0 + diff --git a/queue-6.18/slip-bound-decode-reads-against-the-compressed-packe.patch b/queue-6.18/slip-bound-decode-reads-against-the-compressed-packe.patch new file mode 100644 index 0000000000..3e1ef33d71 --- /dev/null +++ b/queue-6.18/slip-bound-decode-reads-against-the-compressed-packe.patch @@ -0,0 +1,158 @@ +From 0669ba860bfe2631a60d87cdfa38ff6601e5b7f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:01:51 +0800 +Subject: slip: bound decode() reads against the compressed packet length + +From: Weiming Shi + +[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ] + +slhc_uncompress() parses a VJ-compressed TCP header by advancing a +pointer through the packet via decode() and pull16(). Neither helper +bounds-checks against isize, and decode() masks its return with +& 0xffff so it can never return the -1 that callers test for -- those +error paths are dead code. + +A short compressed frame whose change byte requests optional fields +lets decode() read past the end of the packet. The over-read bytes +are folded into the cached cstate and reflected into subsequent +reconstructed packets. + +Make decode() and pull16() take the packet end pointer and return -1 +when exhausted. Add a bounds check before the TCP-checksum read. +The existing == -1 tests now do what they were always meant to. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Simon Horman +Closes: https://lore.kernel.org/netdev/20260414134126.758795-2-horms@kernel.org/ +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416100147.531855-5-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index fcb3eebe7311c..daf086c283423 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -80,9 +80,9 @@ + #include + + static unsigned char *encode(unsigned char *cp, unsigned short n); +-static long decode(unsigned char **cpp); ++static long decode(unsigned char **cpp, const unsigned char *end); + static unsigned char * put16(unsigned char *cp, unsigned short x); +-static unsigned short pull16(unsigned char **cpp); ++static long pull16(unsigned char **cpp, const unsigned char *end); + + /* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) +@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n) + return cp; + } + +-/* Pull a 16-bit integer in host order from buffer in network byte order */ +-static unsigned short +-pull16(unsigned char **cpp) ++/* Pull a 16-bit integer in host order from buffer in network byte order. ++ * Returns -1 if the buffer is exhausted, otherwise the 16-bit value. ++ */ ++static long ++pull16(unsigned char **cpp, const unsigned char *end) + { +- short rval; ++ long rval; + ++ if (*cpp + 2 > end) ++ return -1; + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; + } + +-/* Decode a number */ ++/* Decode a number. Returns -1 if the buffer is exhausted. */ + static long +-decode(unsigned char **cpp) ++decode(unsigned char **cpp, const unsigned char *end) + { + int x; + ++ if (*cpp >= end) ++ return -1; + x = *(*cpp)++; +- if(x == 0){ +- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ +- } else { +- return x & 0xff; /* -1 if PULLCHAR returned error */ +- } ++ if (x == 0) ++ return pull16(cpp, end); ++ return x & 0xff; + } + + /* +@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; ++ const unsigned char *end = icp + isize; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; +@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + ++ if (cp + 2 > end) ++ goto bad; + thp->check = *(__sum16 *)cp; + cp += 2; + +@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + default: + if(changes & NEW_U){ + thp->urg = 1; +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); +@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + break; + } + if(changes & NEW_I){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); +-- +2.53.0 + diff --git a/queue-6.18/slip-reject-vj-receive-packets-on-instances-with-no-.patch b/queue-6.18/slip-reject-vj-receive-packets-on-instances-with-no-.patch new file mode 100644 index 0000000000..0f401e2296 --- /dev/null +++ b/queue-6.18/slip-reject-vj-receive-packets-on-instances-with-no-.patch @@ -0,0 +1,98 @@ +From e0e4f7259ded9bc9bff4925e7af8da638a1bcf45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 04:41:31 +0800 +Subject: slip: reject VJ receive packets on instances with no rstate array + +From: Weiming Shi + +[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ] + +slhc_init() accepts rslots == 0 as a valid configuration, with the +documented meaning of 'no receive compression'. In that case the +allocation loop in slhc_init() is skipped, so comp->rstate stays +NULL and comp->rslot_limit stays 0 (from the kzalloc of struct +slcompress). + +The receive helpers do not defend against that configuration. +slhc_uncompress() dereferences comp->rstate[x] when the VJ header +carries an explicit connection ID, and slhc_remember() later assigns +cs = &comp->rstate[...] after only comparing the packet's slot number +to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the +range check, and the code dereferences a NULL rstate. + +The configuration is reachable in-tree through PPP. PPPIOCSMAXCID +stores its argument in a signed int, and (val >> 16) uses arithmetic +shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 +is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because +/dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path +is reachable from an unprivileged user namespace. Once the malformed +VJ state is installed, any inbound VJ-compressed or VJ-uncompressed +frame that selects slot 0 crashes the kernel in softirq context: + + Oops: general protection fault, probably for non-canonical + address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519) + Call Trace: + + ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466) + ppp_input (drivers/net/ppp/ppp_generic.c:2359) + ppp_async_process (drivers/net/ppp/ppp_async.c:492) + tasklet_action_common (kernel/softirq.c:926) + handle_softirqs (kernel/softirq.c:623) + run_ksoftirqd (kernel/softirq.c:1055) + smpboot_thread_fn (kernel/smpboot.c:160) + kthread (kernel/kthread.c:436) + ret_from_fork (arch/x86/kernel/process.c:164) + + +Reject the receive side on such instances instead of touching rstate. +slhc_uncompress() falls through to its existing 'bad' label, which +bumps sls_i_error and enters the toss state. slhc_remember() mirrors +that with an explicit sls_i_error increment followed by slhc_toss(); +the sls_i_runt counter is not used here because a missing rstate is +an internal configuration state, not a runt packet. + +The transmit path is unaffected: the only in-tree caller that picks +rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and +slip.c always calls slhc_init(16, 16), so comp->tstate remains valid +and slhc_compress() continues to work. + +Fixes: 4ab42d78e37a ("ppp, slip: Validate VJ compression slot parameters completely") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415204130.258866-2-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index ee9fd3a94b96f..fcb3eebe7311c 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + comp->sls_i_error++; + return 0; + } ++ if (!comp->rstate) ++ goto bad; + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. +@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + unsigned int ihl; + ++ if (!comp->rstate) { ++ comp->sls_i_error++; ++ return slhc_toss(comp); ++ } + /* The packet is shorter than a legal IP header. + * Also make sure isize is positive. + */ +-- +2.53.0 + diff --git a/queue-6.18/smb-move-smb_version_values-to-common-smbglob.h.patch b/queue-6.18/smb-move-smb_version_values-to-common-smbglob.h.patch new file mode 100644 index 0000000000..c89cdaf0ea --- /dev/null +++ b/queue-6.18/smb-move-smb_version_values-to-common-smbglob.h.patch @@ -0,0 +1,339 @@ +From 70b894ca18a2a96913bf23f56e0c9af80ca75541 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Oct 2025 15:12:54 +0800 +Subject: smb: move smb_version_values to common/smbglob.h + +From: ZhangGuoDong + +[ Upstream commit 34cf191bb6a349dc88ec2c4f6355fe006ac669e0 ] + +Merge the struct members of the server and the client: + + - req_capabilities: from client + - header_preamble_size: from client + - cap_unicode: from client + - capabilities: from server, rename to req_capabilities + - max_read_size: from server + - max_write_size: from server + - max_trans_size: from server + - max_credits: from server + - create_durable_size: from server + - create_durable_v2_size: from server + - create_mxac_size: from server + - create_disk_id_size: from server + - create_posix_size: from server + +Then move duplicate definitions to common header file. + +Co-developed-by: ChenXiaoSong +Signed-off-by: ChenXiaoSong +Signed-off-by: ZhangGuoDong +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Stable-dep-of: 1baff47b81f9 ("ksmbd: fix use-after-free in smb2_open during durable reconnect") +Signed-off-by: Sasha Levin +--- + fs/smb/client/cifsglob.h | 22 ---------------------- + fs/smb/common/cifsglob.h | 31 +++++++++++++++++++++++++++++++ + fs/smb/server/smb2misc.c | 2 +- + fs/smb/server/smb2ops.c | 32 ++++++++++++++++---------------- + fs/smb/server/smb2pdu.c | 10 +++++----- + fs/smb/server/smb_common.h | 29 ----------------------------- + 6 files changed, 53 insertions(+), 73 deletions(-) + +diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h +index 3059fcf12ed13..69deb29502a8c 100644 +--- a/fs/smb/client/cifsglob.h ++++ b/fs/smb/client/cifsglob.h +@@ -634,28 +634,6 @@ struct smb_version_operations { + struct kvec *xattr_iov); + }; + +-struct smb_version_values { +- char *version_string; +- __u16 protocol_id; +- __u32 req_capabilities; +- __u32 large_lock_type; +- __u32 exclusive_lock_type; +- __u32 shared_lock_type; +- __u32 unlock_lock_type; +- size_t header_preamble_size; +- size_t header_size; +- size_t max_header_size; +- size_t read_rsp_size; +- __le16 lock_cmd; +- unsigned int cap_unix; +- unsigned int cap_nt_find; +- unsigned int cap_large_files; +- unsigned int cap_unicode; +- __u16 signing_enabled; +- __u16 signing_required; +- size_t create_lease_size; +-}; +- + #define HEADER_SIZE(server) (server->vals->header_size) + #define MAX_HEADER_SIZE(server) (server->vals->max_header_size) + #define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size) +diff --git a/fs/smb/common/cifsglob.h b/fs/smb/common/cifsglob.h +index 00fd215e3eb54..eda5e666a7617 100644 +--- a/fs/smb/common/cifsglob.h ++++ b/fs/smb/common/cifsglob.h +@@ -9,6 +9,37 @@ + #ifndef _COMMON_CIFS_GLOB_H + #define _COMMON_CIFS_GLOB_H + ++struct smb_version_values { ++ char *version_string; ++ __u16 protocol_id; ++ __le16 lock_cmd; ++ __u32 req_capabilities; ++ __u32 max_read_size; ++ __u32 max_write_size; ++ __u32 max_trans_size; ++ __u32 max_credits; ++ __u32 large_lock_type; ++ __u32 exclusive_lock_type; ++ __u32 shared_lock_type; ++ __u32 unlock_lock_type; ++ size_t header_preamble_size; ++ size_t header_size; ++ size_t max_header_size; ++ size_t read_rsp_size; ++ unsigned int cap_unix; ++ unsigned int cap_nt_find; ++ unsigned int cap_large_files; ++ unsigned int cap_unicode; ++ __u16 signing_enabled; ++ __u16 signing_required; ++ size_t create_lease_size; ++ size_t create_durable_size; ++ size_t create_durable_v2_size; ++ size_t create_mxac_size; ++ size_t create_disk_id_size; ++ size_t create_posix_size; ++}; ++ + static inline void inc_rfc1001_len(void *buf, int count) + { + be32_add_cpu((__be32 *)buf, count); +diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c +index ae501024665e1..67a2d7a793f6e 100644 +--- a/fs/smb/server/smb2misc.c ++++ b/fs/smb/server/smb2misc.c +@@ -460,7 +460,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) + } + + validate_credit: +- if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && ++ if ((work->conn->vals->req_capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && + smb2_validate_credit_charge(work->conn, hdr)) + return 1; + +diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c +index 606aa3c5189a2..bcf05caa2304d 100644 +--- a/fs/smb/server/smb2ops.c ++++ b/fs/smb/server/smb2ops.c +@@ -15,7 +15,7 @@ + static struct smb_version_values smb21_server_values = { + .version_string = SMB21_VERSION_STRING, + .protocol_id = SMB21_PROT_ID, +- .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, ++ .req_capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, + .max_read_size = SMB21_DEFAULT_IOSIZE, + .max_write_size = SMB21_DEFAULT_IOSIZE, + .max_trans_size = SMB21_DEFAULT_IOSIZE, +@@ -41,7 +41,7 @@ static struct smb_version_values smb21_server_values = { + static struct smb_version_values smb30_server_values = { + .version_string = SMB30_VERSION_STRING, + .protocol_id = SMB30_PROT_ID, +- .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, ++ .req_capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, + .max_read_size = SMB3_DEFAULT_IOSIZE, + .max_write_size = SMB3_DEFAULT_IOSIZE, + .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, +@@ -68,7 +68,7 @@ static struct smb_version_values smb30_server_values = { + static struct smb_version_values smb302_server_values = { + .version_string = SMB302_VERSION_STRING, + .protocol_id = SMB302_PROT_ID, +- .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, ++ .req_capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, + .max_read_size = SMB3_DEFAULT_IOSIZE, + .max_write_size = SMB3_DEFAULT_IOSIZE, + .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, +@@ -95,7 +95,7 @@ static struct smb_version_values smb302_server_values = { + static struct smb_version_values smb311_server_values = { + .version_string = SMB311_VERSION_STRING, + .protocol_id = SMB311_PROT_ID, +- .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, ++ .req_capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, + .max_read_size = SMB3_DEFAULT_IOSIZE, + .max_write_size = SMB3_DEFAULT_IOSIZE, + .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, +@@ -204,7 +204,7 @@ void init_smb2_1_server(struct ksmbd_conn *conn) + conn->signing_algorithm = SIGNING_ALG_HMAC_SHA256_LE; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_LEASING; + } + + /** +@@ -221,20 +221,20 @@ void init_smb3_0_server(struct ksmbd_conn *conn) + conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING | ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_LEASING | + SMB2_GLOBAL_CAP_DIRECTORY_LEASING; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && + conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || + (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) && + conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + } + + /** +@@ -251,19 +251,19 @@ void init_smb3_02_server(struct ksmbd_conn *conn) + conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING | ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_LEASING | + SMB2_GLOBAL_CAP_DIRECTORY_LEASING; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || + (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) && + conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; + } + + /** +@@ -280,14 +280,14 @@ int init_smb3_11_server(struct ksmbd_conn *conn) + conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING | ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_LEASING | + SMB2_GLOBAL_CAP_DIRECTORY_LEASING; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE) +- conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; ++ conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; + + INIT_LIST_HEAD(&conn->preauth_sess_table); + return 0; +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 006b386cf9122..16ea123f61223 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -291,7 +291,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) + /* Not setting conn guid rsp->ServerGUID, as it + * not used by client for identifying connection + */ +- rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); ++ rsp->Capabilities = cpu_to_le32(conn->vals->req_capabilities); + /* Default Max Message Size till SMB2.0, 64K*/ + rsp->MaxTransactSize = cpu_to_le32(conn->vals->max_trans_size); + rsp->MaxReadSize = cpu_to_le32(conn->vals->max_read_size); +@@ -965,7 +965,7 @@ bool smb3_encryption_negotiated(struct ksmbd_conn *conn) + * SMB 3.0 and 3.0.2 dialects use the SMB2_GLOBAL_CAP_ENCRYPTION flag. + * SMB 3.1.1 uses the cipher_type field. + */ +- return (conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) || ++ return (conn->vals->req_capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) || + conn->cipher_type; + } + +@@ -1219,7 +1219,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) + rc = -EINVAL; + goto err_out; + } +- rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); ++ rsp->Capabilities = cpu_to_le32(conn->vals->req_capabilities); + + /* For stats */ + conn->connection_type = conn->dialect; +@@ -3505,7 +3505,7 @@ int smb2_open(struct ksmbd_work *work) + share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); + if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) || + (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && +- !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) { ++ !(conn->vals->req_capabilities & SMB2_GLOBAL_CAP_LEASING))) { + if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) { + rc = share_ret; + goto err_out1; +@@ -8100,7 +8100,7 @@ static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn, + goto err_out; + } + +- neg_rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); ++ neg_rsp->Capabilities = cpu_to_le32(conn->vals->req_capabilities); + memset(neg_rsp->Guid, 0, SMB2_CLIENT_GUID_SIZE); + neg_rsp->SecurityMode = cpu_to_le16(conn->srv_sec_mode); + neg_rsp->Dialect = cpu_to_le16(conn->dialect); +diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h +index 863716207a0de..dac783b46545d 100644 +--- a/fs/smb/server/smb_common.h ++++ b/fs/smb/server/smb_common.h +@@ -338,35 +338,6 @@ struct file_id_full_dir_info { + char FileName[]; + } __packed; /* level 0x105 FF rsp data */ + +-struct smb_version_values { +- char *version_string; +- __u16 protocol_id; +- __le16 lock_cmd; +- __u32 capabilities; +- __u32 max_read_size; +- __u32 max_write_size; +- __u32 max_trans_size; +- __u32 max_credits; +- __u32 large_lock_type; +- __u32 exclusive_lock_type; +- __u32 shared_lock_type; +- __u32 unlock_lock_type; +- size_t header_size; +- size_t max_header_size; +- size_t read_rsp_size; +- unsigned int cap_unix; +- unsigned int cap_nt_find; +- unsigned int cap_large_files; +- __u16 signing_enabled; +- __u16 signing_required; +- size_t create_lease_size; +- size_t create_durable_size; +- size_t create_durable_v2_size; +- size_t create_mxac_size; +- size_t create_disk_id_size; +- size_t create_posix_size; +-}; +- + struct filesystem_posix_info { + /* For undefined recommended transfer size return -1 in that field */ + __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ +-- +2.53.0 + diff --git a/queue-6.18/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch b/queue-6.18/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch new file mode 100644 index 0000000000..d06fb63359 --- /dev/null +++ b/queue-6.18/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch @@ -0,0 +1,41 @@ +From 138e60513282293356444598a5ef76057aea5820 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 12:53:23 -0700 +Subject: soc: qcom: aoss: compare against normalized cooling state + +From: Alok Tiwari + +[ Upstream commit cd3c4670db3ffe997be9548c7a9db3952563cf14 ] + +qmp_cdev_set_cur_state() normalizes the requested state to a boolean +(cdev_state = !!state). The existing early-return check compares +qmp_cdev->state == state, which can be wrong if state is non-boolean +(any non-zero value). Compare qmp_cdev->state against cdev_state instead, +so the check matches the effective state and avoids redundant updates. + +Signed-off-by: Alok Tiwari +Fixes: 05589b30b21a ("soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260329195333.1478090-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/qcom_aoss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c +index a543ab9bee6c4..c255662b8fc3d 100644 +--- a/drivers/soc/qcom/qcom_aoss.c ++++ b/drivers/soc/qcom/qcom_aoss.c +@@ -355,7 +355,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, + /* Normalize state */ + cdev_state = !!state; + +- if (qmp_cdev->state == state) ++ if (qmp_cdev->state == cdev_state) + return 0; + + ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}", +-- +2.53.0 + diff --git a/queue-6.18/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch b/queue-6.18/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch new file mode 100644 index 0000000000..a3a20e9b3d --- /dev/null +++ b/queue-6.18/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch @@ -0,0 +1,45 @@ +From ec2b1dd956d6e291584e0ee158f620422f92650c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 02:51:11 -0700 +Subject: soc: qcom: llcc: fix v1 SB syndrome register offset + +From: Alok Tiwari + +[ Upstream commit 24e7625df5ce065393249b78930781be593bc381 ] + +The llcc_v1_edac_reg_offset table uses 0x2304c for trp_ecc_sb_err_syn0, +which is inconsistent with the surrounding TRP ECC registers (0x2034x) +and with llcc_v2_1_edac_reg_offset, where trp_ecc_sb_err_syn0 is 0x2034c +adjacent to trp_ecc_error_status0/1 at 0x20344/0x20348. + +Use 0x2034c for llcc v1 so the SB syndrome register follows the expected ++0x4 progression from trp_ecc_error_status1. This fixes EDAC reading the +wrong register for SB syndrome reporting. + +Fixes: c13d7d261e36 ("soc: qcom: llcc: Pass LLCC version based register offsets to EDAC driver") +Signed-off-by: Alok Tiwari +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260330095118.2657362-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/llcc-qcom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c +index 857ead56b37d0..d5ce09d6115f0 100644 +--- a/drivers/soc/qcom/llcc-qcom.c ++++ b/drivers/soc/qcom/llcc-qcom.c +@@ -3394,7 +3394,7 @@ static const struct llcc_slice_config x1e80100_data[] = { + static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { + .trp_ecc_error_status0 = 0x20344, + .trp_ecc_error_status1 = 0x20348, +- .trp_ecc_sb_err_syn0 = 0x2304c, ++ .trp_ecc_sb_err_syn0 = 0x2034c, + .trp_ecc_db_err_syn0 = 0x20370, + .trp_ecc_error_cntr_clear = 0x20440, + .trp_interrupt_0_status = 0x20480, +-- +2.53.0 + diff --git a/queue-6.18/soc-qcom-ocmem-make-the-core-clock-optional.patch b/queue-6.18/soc-qcom-ocmem-make-the-core-clock-optional.patch new file mode 100644 index 0000000000..875bd66144 --- /dev/null +++ b/queue-6.18/soc-qcom-ocmem-make-the-core-clock-optional.patch @@ -0,0 +1,41 @@ +From e9a9fb4b2fdb879e88ce7f77a741ec6a0a5ce9b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:57 +0200 +Subject: soc: qcom: ocmem: make the core clock optional + +From: Dmitry Baryshkov + +[ Upstream commit e8a61c51417c679d1a599fb36695e9d3b8d95514 ] + +OCMEM's core clock (aka RPM bus 2 clock) is being handled internally by +the interconnect driver. Corresponding clock has been dropped from the +SMD RPM clock driver. The users of the ocmem will vote on the ocmemnoc +interconnect paths, making sure that ocmem is on. Make the clock +optional, keeping it for compatibility with older DT. + +Fixes: d6edc31f3a68 ("clk: qcom: smd-rpm: Separate out interconnect bus clocks") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-1-ad9bcae44763@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 71130a2f62e9e..7bcd0c71d7f64 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -308,7 +308,7 @@ static int ocmem_dev_probe(struct platform_device *pdev) + ocmem->dev = dev; + ocmem->config = device_get_match_data(dev); + +- ocmem->core_clk = devm_clk_get(dev, "core"); ++ ocmem->core_clk = devm_clk_get_optional(dev, "core"); + if (IS_ERR(ocmem->core_clk)) + return dev_err_probe(dev, PTR_ERR(ocmem->core_clk), + "Unable to get core clock\n"); +-- +2.53.0 + diff --git a/queue-6.18/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch b/queue-6.18/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch new file mode 100644 index 0000000000..ee47326359 --- /dev/null +++ b/queue-6.18/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch @@ -0,0 +1,46 @@ +From cbc77ed9930a871a0c09e154807e5070be8ca68d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:58 +0200 +Subject: soc: qcom: ocmem: register reasons for probe deferrals + +From: Dmitry Baryshkov + +[ Upstream commit 9dfd69cd89cd6afa4723be9098979abeef3bb8c6 ] + +Instead of printing messages to the dmesg, let the message be recorded +as a reason for the OCMEM client deferral. + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Brian Masney +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-2-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 7bcd0c71d7f64..ed77fdc76c9b2 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -196,10 +196,10 @@ struct ocmem *of_get_ocmem(struct device *dev) + } + + pdev = of_find_device_by_node(devnode->parent); +- if (!pdev) { +- dev_err(dev, "Cannot find device node %s\n", devnode->name); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!pdev) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, ++ "Cannot find device node %s\n", ++ devnode->name); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-6.18/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch b/queue-6.18/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch new file mode 100644 index 0000000000..65b3583ebc --- /dev/null +++ b/queue-6.18/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch @@ -0,0 +1,46 @@ +From c3e40b12de4c467cfb2fac95e930f4f25701d08c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:59 +0200 +Subject: soc: qcom: ocmem: return -EPROBE_DEFER is ocmem is not available + +From: Dmitry Baryshkov + +[ Upstream commit 91b59009c7d48b58dbc50fecb27f2ad20749a05a ] + +If OCMEM is declared in DT, it is expected that it is present and +handled by the driver. The GPU driver will ignore -ENODEV error, which +typically means that OCMEM isn't defined in DT. Let ocmem return +-EPROBE_DEFER if it supposed to be used, but it is not probed (yet). + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-3-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index ed77fdc76c9b2..37ea6b86aebcb 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -203,10 +203,9 @@ struct ocmem *of_get_ocmem(struct device *dev) + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +- if (!ocmem) { +- dev_err(dev, "Cannot get ocmem\n"); +- return ERR_PTR(-ENODEV); +- } ++ if (!ocmem) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n"); ++ + return ocmem; + } + EXPORT_SYMBOL_GPL(of_get_ocmem); +-- +2.53.0 + diff --git a/queue-6.18/soc-tegra-cbb-fix-cross-fabric-target-timeout-lookup.patch b/queue-6.18/soc-tegra-cbb-fix-cross-fabric-target-timeout-lookup.patch new file mode 100644 index 0000000000..2a8c962ab7 --- /dev/null +++ b/queue-6.18/soc-tegra-cbb-fix-cross-fabric-target-timeout-lookup.patch @@ -0,0 +1,87 @@ +From 671b11e2371daec01cb69b7e4ba8ddd3044a2263 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:05 +0530 +Subject: soc/tegra: cbb: Fix cross-fabric target timeout lookup + +From: Sumit Gupta + +[ Upstream commit a5f51b04cbb3ae0f9cb2c4488952b775ebb0ccbf ] + +When a fabric receives an error interrupt, the error may have +occurred on a different fabric. The target timeout lookup was using +the wrong base address (cbb->regs) with offsets from a different +fabric's target map, causing a kernel page fault. + + Unable to handle kernel paging request at virtual address ffff80000954cc00 + pc : tegra234_cbb_get_tmo_slv+0xc/0x28 + Call trace: + tegra234_cbb_get_tmo_slv+0xc/0x28 + print_err_notifier+0x6c0/0x7d0 + tegra234_cbb_isr+0xe4/0x1b4 + +Add tegra234_cbb_get_fabric() to look up the correct fabric device +using fab_id, and use its base address for accessing target timeout +registers. + +Fixes: 25de5c8fe0801 ("soc/tegra: cbb: Improve handling for per SoC fabric data") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index 626e0e820329b..7e387fc54c6b1 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -313,12 +313,37 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *target + } + } + ++static struct tegra234_cbb *tegra234_cbb_get_fabric(u8 fab_id) ++{ ++ struct tegra_cbb *entry; ++ ++ list_for_each_entry(entry, &cbb_list, node) { ++ struct tegra234_cbb *priv = to_tegra234_cbb(entry); ++ ++ if (priv->fabric->fab_id == fab_id) ++ return priv; ++ } ++ ++ return NULL; ++} ++ + static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb, + u8 target_id, u8 fab_id) + { + const struct tegra234_target_lookup *map = cbb->fabric->fab_list[fab_id].target_map; ++ struct tegra234_cbb *target_cbb = NULL; + void __iomem *addr; + ++ if (fab_id == cbb->fabric->fab_id) ++ target_cbb = cbb; ++ else ++ target_cbb = tegra234_cbb_get_fabric(fab_id); ++ ++ if (!target_cbb) { ++ dev_err(cbb->base.dev, "could not find fabric for fab_id:%d\n", fab_id); ++ return; ++ } ++ + if (target_id >= cbb->fabric->fab_list[fab_id].max_targets) { + tegra_cbb_print_err(file, "\t Invalid target_id:%d\n", target_id); + return; +@@ -341,7 +366,7 @@ static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegr + * e) Goto step-a till all bits are set. + */ + +- addr = cbb->regs + map[target_id].offset; ++ addr = target_cbb->regs + map[target_id].offset; + + if (strstr(map[target_id].name, "AXI2APB")) { + addr += APB_BLOCK_TMO_STATUS_0; +-- +2.53.0 + diff --git a/queue-6.18/soc-tegra-cbb-fix-incorrect-array_size-in-fabric-loo.patch b/queue-6.18/soc-tegra-cbb-fix-incorrect-array_size-in-fabric-loo.patch new file mode 100644 index 0000000000..0181884411 --- /dev/null +++ b/queue-6.18/soc-tegra-cbb-fix-incorrect-array_size-in-fabric-loo.patch @@ -0,0 +1,45 @@ +From 5b4034a4195ae25107dd62d16f66039e69642686 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:04 +0530 +Subject: soc/tegra: cbb: Fix incorrect ARRAY_SIZE in fabric lookup tables + +From: Sumit Gupta + +[ Upstream commit 499f7e5ebbdd9ff0c4d532b1c432f8a61ff585b3 ] + +Fix incorrect ARRAY_SIZE usage in fabric lookup tables which could +cause out-of-bounds access during target timeout lookup. + +Fixes: 25de5c8fe0801 ("soc/tegra: cbb: Improve handling for per SoC fabric data") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index 518733a066588..626e0e820329b 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -881,7 +881,7 @@ static const struct tegra234_fabric_lookup tegra234_cbb_fab_list[] = { + ARRAY_SIZE(tegra234_common_target_map) }, + [T234_AON_FABRIC_ID] = { "aon-fabric", true, + tegra234_aon_target_map, +- ARRAY_SIZE(tegra234_bpmp_target_map) }, ++ ARRAY_SIZE(tegra234_aon_target_map) }, + [T234_PSC_FABRIC_ID] = { "psc-fabric" }, + [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true, + tegra234_bpmp_target_map, +@@ -1160,7 +1160,7 @@ static const struct tegra234_fabric_lookup tegra241_cbb_fab_list[] = { + [T234_CBB_FABRIC_ID] = { "cbb-fabric", true, + tegra241_cbb_target_map, ARRAY_SIZE(tegra241_cbb_target_map) }, + [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true, +- tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_cbb_target_map) }, ++ tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_bpmp_target_map) }, + }; + static const struct tegra234_cbb_fabric tegra241_cbb_fabric = { + .fab_id = T234_CBB_FABRIC_ID, +-- +2.53.0 + diff --git a/queue-6.18/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch b/queue-6.18/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch new file mode 100644 index 0000000000..aa1aea1e02 --- /dev/null +++ b/queue-6.18/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch @@ -0,0 +1,43 @@ +From c7a450e36922a92d35c5fe34ea8547a9a2c89f6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:03 +0530 +Subject: soc/tegra: cbb: Set ERD on resume for err interrupt + +From: Sumit Gupta + +[ Upstream commit b6ff71c5d1d4ad858ddf6f39394d169c96689596 ] + +Set the Error Response Disable (ERD) bit to mask SError responses +and use interrupt-based error reporting. When the ERD bit is set, +inband error responses to the initiator via SError are suppressed, +and fabric errors are reported via an interrupt instead. + +The register is set during boot but the info is lost during system +suspend and needs to be set again on resume. + +Fixes: fc2f151d2314 ("soc/tegra: cbb: Add driver for Tegra234 CBB 2.0") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index a9adbcecd47cc..518733a066588 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -1586,6 +1586,10 @@ static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) + { + struct tegra234_cbb *cbb = dev_get_drvdata(dev); + ++ /* set ERD bit to mask SError and generate interrupt to report error */ ++ if (cbb->fabric->off_mask_erd) ++ tegra234_cbb_mask_serror(cbb); ++ + tegra234_cbb_error_enable(&cbb->base); + + dev_dbg(dev, "%s resumed\n", cbb->fabric->fab_list[cbb->fabric->fab_id].name); +-- +2.53.0 + diff --git a/queue-6.18/soundwire-bus-demote-unattached-state-warnings-to-de.patch b/queue-6.18/soundwire-bus-demote-unattached-state-warnings-to-de.patch new file mode 100644 index 0000000000..72c51e9919 --- /dev/null +++ b/queue-6.18/soundwire-bus-demote-unattached-state-warnings-to-de.patch @@ -0,0 +1,62 @@ +From 8ce804cd22f7f0da483362b38853c29645dcfe86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:02:10 -0700 +Subject: soundwire: bus: demote UNATTACHED state warnings to dev_dbg() + +From: Cole Leavitt + +[ Upstream commit 2c96956fe764f8224f9ec93b2a9160a578949a7a ] + +The dev_warn() messages in sdw_handle_slave_status() for UNATTACHED +transitions were added in commit d1b328557058 ("soundwire: bus: add +dev_warn() messages to track UNATTACHED devices") to debug attachment +failures with dynamic debug enabled. + +These warnings fire during normal operation -- for example when a codec +driver triggers a hardware reset after firmware download, causing the +device to momentarily go UNATTACHED before re-attaching -- producing +misleading noise on every boot. + +Demote the messages to dev_dbg() so they remain available via dynamic +debug for diagnosing real attachment failures without alarming users +during expected initialization sequences. + +Fixes: d1b328557058 ("soundwire: bus: add dev_warn() messages to track UNATTACHED devices") +Signed-off-by: Cole Leavitt +Reviewed-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260218180210.9263-1-cole@unwrap.rs +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/bus.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c +index 55c1db8165340..14e1351a3f8ae 100644 +--- a/drivers/soundwire/bus.c ++++ b/drivers/soundwire/bus.c +@@ -1899,8 +1899,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + + if (status[i] == SDW_SLAVE_UNATTACHED && + slave->status != SDW_SLAVE_UNATTACHED) { +- dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", ++ i, slave->status); + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + + /* Ensure driver knows that peripheral unattached */ +@@ -1951,8 +1951,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + if (slave->status == SDW_SLAVE_UNATTACHED) + break; + +- dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", ++ i, slave->status); + + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + break; +-- +2.53.0 + diff --git a/queue-6.18/soundwire-cadence-clear-message-complete-before-sign.patch b/queue-6.18/soundwire-cadence-clear-message-complete-before-sign.patch new file mode 100644 index 0000000000..241e11dd93 --- /dev/null +++ b/queue-6.18/soundwire-cadence-clear-message-complete-before-sign.patch @@ -0,0 +1,89 @@ +From 5798e394a79e8ebf9ff1170d7a5fa2da2daf4e98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 11:31:33 +0000 +Subject: soundwire: cadence: Clear message complete before signaling waiting + thread + +From: Richard Fitzgerald + +[ Upstream commit cbfea84f820962c3c5394ff06e7e9344c96bf761 ] + +Clear the CDNS_MCP_INT_RX_WL interrupt before signaling completion. + +This is to prevent the potential race where: +- The main thread is scheduled immediately the completion is signaled, + and starts a new message +- The RX_WL IRQ for this new message happens before sdw_cdns_irq() has + been re-scheduled. +- When sdw_cdns_irq() is re-scheduled it clears the new RX_WL interrupt. + +MAIN THREAD | IRQ THREAD + | + _cdns_xfer_msg() | + { | + write data to FIFO | + wait_for_completion_timeout() | + | <---- RX_WL IRQ + | sdw_cdns_irq() + | { + | signal completion + <== RESCHEDULE <== + Handle message completion | + } | + | +Start new message | + _cdns_xfer_msg() | + { | + write data to FIFO | + wait_for_completion_timeout() | + | <---- RX_WL IRQ + ==> RESCHEDULE ==> + | // New RX_WL IRQ is cleared before + | // it has been handled. + | clear CDNS_MCP_INTSTAT + + | return IRQ_HANDLED; + | } + +Before this change, this error message was sometimes seen on kernels +that have large amounts of debugging enabled: + + SCP Msg trf timed out + +This error indicates that the completion has not been signalled after +500ms. + +Signed-off-by: Richard Fitzgerald +Fixes: 956baa1992f9 ("soundwire: cdns: Add sdw_master_ops and IO transfer support") +Reported-by: Norman Bintang +Closes: https://issuetracker.google.com/issues/477099834 +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20260310113133.1707288-1-rf@opensource.cirrus.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/cadence_master.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c +index 21bb491d026b4..d7a0a14ad9626 100644 +--- a/drivers/soundwire/cadence_master.c ++++ b/drivers/soundwire/cadence_master.c +@@ -933,6 +933,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) + + cdns_read_response(cdns); + ++ /* ++ * Clear interrupt before signalling the completion to avoid ++ * a race between this thread and the main thread starting ++ * another TX. ++ */ ++ cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_RX_WL); ++ int_status &= ~CDNS_MCP_INT_RX_WL; ++ + if (defer && defer->msg) { + cdns_fill_msg_resp(cdns, defer->msg, + defer->length, 0); +-- +2.53.0 + diff --git a/queue-6.18/soundwire-debugfs-initialize-firmware_file-to-empty-.patch b/queue-6.18/soundwire-debugfs-initialize-firmware_file-to-empty-.patch new file mode 100644 index 0000000000..329418785a --- /dev/null +++ b/queue-6.18/soundwire-debugfs-initialize-firmware_file-to-empty-.patch @@ -0,0 +1,66 @@ +From c51b6f90650979184ddc2915b12adf4bc33314b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:46 +0800 +Subject: soundwire: debugfs: initialize firmware_file to empty string + +From: Gui-Dong Han + +[ Upstream commit 7215e4552f31e53595eae56a834f7e286beecccc ] + +Passing NULL to debugfs_create_str() causes a NULL pointer dereference, +and creating debugfs nodes with NULL string pointers is no longer +permitted. + +Additionally, firmware_file is a global pointer. Previously, adding every +new slave blindly overwrote it with NULL. + +Fix these issues by initializing firmware_file to an allocated empty +string once in the subsystem init path (sdw_debugfs_init), and freeing +it in the exit path. Existing driver code handles empty strings +correctly. + +Fixes: fe46d2a4301d ("soundwire: debugfs: add interface to read/write commands") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/17647e4c.d461.19b46144a4e.Coremail.yangshiguang1011@163.com/ +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-4-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/soundwire/debugfs.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c +index 1e0f9318b6165..feb4d15102753 100644 +--- a/drivers/soundwire/debugfs.c ++++ b/drivers/soundwire/debugfs.c +@@ -350,8 +350,8 @@ void sdw_slave_debugfs_init(struct sdw_slave *slave) + debugfs_create_file("go", 0200, d, slave, &cmd_go_fops); + + debugfs_create_file("read_buffer", 0400, d, slave, &read_buffer_fops); +- firmware_file = NULL; +- debugfs_create_str("firmware_file", 0200, d, &firmware_file); ++ if (firmware_file) ++ debugfs_create_str("firmware_file", 0200, d, &firmware_file); + + slave->debugfs = d; + } +@@ -363,10 +363,15 @@ void sdw_slave_debugfs_exit(struct sdw_slave *slave) + + void sdw_debugfs_init(void) + { ++ if (!firmware_file) ++ firmware_file = kstrdup("", GFP_KERNEL); ++ + sdw_debugfs_root = debugfs_create_dir("soundwire", NULL); + } + + void sdw_debugfs_exit(void) + { + debugfs_remove_recursive(sdw_debugfs_root); ++ kfree(firmware_file); ++ firmware_file = NULL; + } +-- +2.53.0 + diff --git a/queue-6.18/soundwire-intel-test-bus.bpt_stream-before-assigning.patch b/queue-6.18/soundwire-intel-test-bus.bpt_stream-before-assigning.patch new file mode 100644 index 0000000000..f64d34044a --- /dev/null +++ b/queue-6.18/soundwire-intel-test-bus.bpt_stream-before-assigning.patch @@ -0,0 +1,50 @@ +From b19179c0173d77806f807b47f3b8814d7ac115cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:40:45 +0800 +Subject: soundwire: Intel: test bus.bpt_stream before assigning it + +From: Bard Liao + +[ Upstream commit b2c9f1d5a7eb50bcdda607afef1378e552bbb490 ] + +We only allow up to 1 bpt stream running on a SoundWire bus. +bus.bpt_stream will be assigned when it is opened and will be set to +NULL when it is closed. We do check bus->bpt_stream_refcount if the +stream type is SDW_STREAM_BPT in sdw_master_rt_alloc(), but at that +moment the bpt stream is allocated and set to bus.bpt_stream. It will +lead to the original bus.bpt_stream be changed to the new and not used +bpt stream. And it will be released and set to NULL when +sdw_slave_bpt_stream_add() return error as it supposed to. Then the +original stream will try to use the NULL bus.bpt_stream. + +Fixes: 4c1ce9f37d8a ("soundwire: intel_ace2x: add BPT send_async/wait callbacks") +Reported-by: Simon Trimmer +Signed-off-by: Bard Liao +Reviewed-by: Simon Trimmer +Reviewed-by: Ranjani Sridharan +Link: https://patch.msgid.link/20260126054045.2504103-1-yung-chuan.liao@linux.intel.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/intel_ace2x.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c +index 5d08364ad6d14..5b73bbb73be6e 100644 +--- a/drivers/soundwire/intel_ace2x.c ++++ b/drivers/soundwire/intel_ace2x.c +@@ -68,6 +68,11 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * + int dir; + int i; + ++ if (cdns->bus.bpt_stream) { ++ dev_err(cdns->dev, "%s: BPT stream already exists\n", __func__); ++ return -EAGAIN; ++ } ++ + stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT); + if (!stream) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.18/sparc64-vdso-link-with-z-noexecstack.patch b/queue-6.18/sparc64-vdso-link-with-z-noexecstack.patch new file mode 100644 index 0000000000..58e3b39d45 --- /dev/null +++ b/queue-6.18/sparc64-vdso-link-with-z-noexecstack.patch @@ -0,0 +1,47 @@ +From 51875e7a4aaa3db8b1ea92da52df75d92198425c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 08:49:01 +0100 +Subject: sparc64: vdso: Link with -z noexecstack +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit acc4f131d5d57c2aa89db914aeb6f7bb0ab4eb4a ] + +The vDSO stack does not need to be executable. Prevent the linker from +creating executable. For more background see commit ffcf9c5700e4 ("x86: +link vdso and boot with -z noexecstack --no-warn-rwx-segments"). + +Also prevent the following warning from the linker: +sparc64-linux-ld: warning: arch/sparc/vdso/vdso-note.o: missing .note.GNU-stack section implies executable stack +sparc64-linux-ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker + +Fixes: 9a08862a5d2e ("vDSO for sparc") +Suggested-by: Arnd Bergmann +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Tested-by: Andreas Larsson +Reviewed-by: Andreas Larsson +Acked-by: Andreas Larsson +Link: https://lore.kernel.org/lkml/20250707144726.4008707-1-arnd@kernel.org/ +Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-4-d8eb3b0e1410@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/sparc/vdso/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile +index 683b2d4082244..400529acd1c10 100644 +--- a/arch/sparc/vdso/Makefile ++++ b/arch/sparc/vdso/Makefile +@@ -104,4 +104,4 @@ quiet_cmd_vdso = VDSO $@ + $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ + -T $(filter %.lds,$^) $(filter %.o,$^) + +-VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined ++VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined -z noexecstack +-- +2.53.0 + diff --git a/queue-6.18/spi-amlogic-spisg-initialize-completion-before-reque.patch b/queue-6.18/spi-amlogic-spisg-initialize-completion-before-reque.patch new file mode 100644 index 0000000000..c1df690196 --- /dev/null +++ b/queue-6.18/spi-amlogic-spisg-initialize-completion-before-reque.patch @@ -0,0 +1,46 @@ +From c102a0e301c6c3070ff962af6c6dc46461484913 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 01:42:00 +0800 +Subject: spi: amlogic-spisg: initialize completion before requesting IRQ + +From: Felix Gu + +[ Upstream commit 8d0189c1ea98b56481eb809e3d1bdbf85557e819 ] + +Move init_completion(&spisg->completion) to before devm_request_irq() +to avoid a potential race condition where an interrupt could fire +before the completion structure is initialized. + +Fixes: cef9991e04ae ("spi: Add Amlogic SPISG driver") +Signed-off-by: Felix Gu +Link: https://patch.msgid.link/20260428-amlogic-spisg-v1-1-8eecc3b446d6@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-amlogic-spisg.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c +index 56a6cf8471b9f..970fddbb25857 100644 +--- a/drivers/spi/spi-amlogic-spisg.c ++++ b/drivers/spi/spi-amlogic-spisg.c +@@ -795,6 +795,7 @@ static int aml_spisg_probe(struct platform_device *pdev) + + dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX); + ++ init_completion(&spisg->completion); + ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg); + if (ret) { + dev_err(&pdev->dev, "irq request failed\n"); +@@ -807,8 +808,6 @@ static int aml_spisg_probe(struct platform_device *pdev) + goto out_clk; + } + +- init_completion(&spisg->completion); +- + pm_runtime_put(&spisg->pdev->dev); + + return 0; +-- +2.53.0 + diff --git a/queue-6.18/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch b/queue-6.18/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..5a51049314 --- /dev/null +++ b/queue-6.18/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From ac7add8f1ddea1c9eef7960959cb09b0833c3642 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:21 +0800 +Subject: spi: fsl-qspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 981b080a79724738882b0af1c5bb7ade30d94f24 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks could +get "lost" - use reinit_completion() in that case, but be aware of +other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: 84d043185dbe ("spi: Add a driver for the Freescale/NXP QuadSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-3-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-fsl-qspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c +index c887abb028d77..3904d64ed4334 100644 +--- a/drivers/spi/spi-fsl-qspi.c ++++ b/drivers/spi/spi-fsl-qspi.c +@@ -607,7 +607,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) + void __iomem *base = q->iobase; + int err = 0; + +- init_completion(&q->c); ++ reinit_completion(&q->c); + + /* + * Always start the sequence at the same index since we update +@@ -928,6 +928,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) + if (ret < 0) + return ret; + ++ init_completion(&q->c); + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { +-- +2.53.0 + diff --git a/queue-6.18/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch b/queue-6.18/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch new file mode 100644 index 0000000000..f74c97febd --- /dev/null +++ b/queue-6.18/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch @@ -0,0 +1,55 @@ +From ddcd20abd858c1df5354e254db53229bd317e2ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 11:06:41 +0800 +Subject: spi: hisi-kunpeng: prevent infinite while() loop in + hisi_spi_flush_fifo + +From: Pei Xiao + +[ Upstream commit 9f61daf2c2debe9f5cf4e1a4471e56a89a6fe45a ] + +The hisi_spi_flush_fifo()'s inner while loop that lacks any timeout +mechanism. Maybe the hardware never becomes empty, the loop will spin +forever, causing the CPU to hang. + +Fix this by adding a inner_limit based on loops_per_jiffy. The inner loop +now exits after approximately one jiffy if the FIFO remains non-empty, logs +a ratelimited warning, and breaks out of the outer loop. Additionally, add +a cpu_relax() inside the busy loop to improve power efficiency. + +Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/d834ce28172886bfaeb9c8ca00cfd9bf1c65d5a1.1773889292.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-hisi-kunpeng.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index 80a1a15de0bc3..a38dcae6271ff 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -196,8 +196,18 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs) + unsigned long limit = loops_per_jiffy << 1; + + do { +- while (hisi_spi_rx_not_empty(hs)) ++ unsigned long inner_limit = loops_per_jiffy; ++ ++ while (hisi_spi_rx_not_empty(hs) && --inner_limit) { + readl(hs->regs + HISI_SPI_DOUT); ++ cpu_relax(); ++ } ++ ++ if (!inner_limit) { ++ dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n"); ++ break; ++ } ++ + } while (hisi_spi_busy(hs) && limit--); + } + +-- +2.53.0 + diff --git a/queue-6.18/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch b/queue-6.18/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch new file mode 100644 index 0000000000..5bbcefe74d --- /dev/null +++ b/queue-6.18/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch @@ -0,0 +1,60 @@ +From ba1389557973c5b0c7604063c9dba0b75dcee185 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 15:26:59 +0800 +Subject: spi: mtk-snfi: unregister ECC engine on probe failure and remove() + callback + +From: Pei Xiao + +[ Upstream commit ab00febad191d7a4400aa1c3468279fb508258d4 ] + +mtk_snand_probe() registers the on-host NAND ECC engine, but teardown was +missing from both probe unwind and remove-time cleanup. Add a devm cleanup +action after successful registration so +nand_ecc_unregister_on_host_hw_engine() runs automatically on probe +failures and during device removal. + +Fixes: 764f1b748164 ("spi: add driver for MTK SPI NAND Flash Interface") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/20263f885f1a9c9d559f95275298cd6de4b11ed5.1775546401.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-mtk-snfi.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c +index ae38c244e2581..a026b0e61994b 100644 +--- a/drivers/spi/spi-mtk-snfi.c ++++ b/drivers/spi/spi-mtk-snfi.c +@@ -1303,6 +1303,13 @@ static const struct spi_controller_mem_caps mtk_snand_mem_caps = { + .ecc = true, + }; + ++static void mtk_unregister_ecc_engine(void *data) ++{ ++ struct nand_ecc_engine *eng = data; ++ ++ nand_ecc_unregister_on_host_hw_engine(eng); ++} ++ + static irqreturn_t mtk_snand_irq(int irq, void *id) + { + struct mtk_snand *snf = id; +@@ -1443,6 +1450,13 @@ static int mtk_snand_probe(struct platform_device *pdev) + goto release_ecc; + } + ++ ret = devm_add_action_or_reset(&pdev->dev, mtk_unregister_ecc_engine, ++ &ms->ecc_eng); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "failed to add ECC unregister action\n"); ++ goto release_ecc; ++ } ++ + ctlr->num_chipselect = 1; + ctlr->mem_ops = &mtk_snand_mem_ops; + ctlr->mem_caps = &mtk_snand_mem_caps; +-- +2.53.0 + diff --git a/queue-6.18/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch b/queue-6.18/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..7226452b92 --- /dev/null +++ b/queue-6.18/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 687f1407aeb998dd60fa0f6ba2e7fc4490d1cc56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:20 +0800 +Subject: spi: nxp-fspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 68c8c93fdb0de7e528dc3dfb1d17eb0f652259b8 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks +could get "lost" - use reinit_completion() in that case, but be +aware of other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: a5356aef6a90 ("spi: spi-mem: Add driver for NXP FlexSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-2-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-nxp-fspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c +index 50a7e4916a600..95ccb1f7dfafa 100644 +--- a/drivers/spi/spi-nxp-fspi.c ++++ b/drivers/spi/spi-nxp-fspi.c +@@ -996,7 +996,7 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op) + reg = reg | FSPI_IPRXFCR_CLR; + fspi_writel(f, reg, base + FSPI_IPRXFCR); + +- init_completion(&f->c); ++ reinit_completion(&f->c); + + fspi_writel(f, op->addr.val, base + FSPI_IPCR0); + /* +@@ -1365,6 +1365,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to disable clock"); + ++ init_completion(&f->c); + ret = devm_request_irq(dev, irq, + nxp_fspi_irq_handler, 0, pdev->name, f); + if (ret) +-- +2.53.0 + diff --git a/queue-6.18/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch b/queue-6.18/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch new file mode 100644 index 0000000000..b355aa1192 --- /dev/null +++ b/queue-6.18/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch @@ -0,0 +1,61 @@ +From f2aa76d13f403c8d0db9002b277f4860ab4a5168 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 09:29:34 +0000 +Subject: spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ + +From: John Madieu + +[ Upstream commit b4683a239a409d65f88052f5630c748a8ba070cd ] + +rockchip_spi_isr() decides whether the current interrupt was the +cs-inactive event by reading IMR: + + if (rs->cs_inactive && + readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) + ctlr->target_abort(ctlr); + +IMR is the interrupt mask register: it tells which sources are enabled, +not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables +both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true: + + if (rs->cs_inactive) + writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, + rs->regs + ROCKCHIP_SPI_IMR); + +so the IMR check is always true once cs_inactive is enabled, and every +PIO interrupt - including normal RF_FULL completions - is dispatched to +ctlr->target_abort(), aborting the transfer. The bug is reachable on +ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller +when the transfer is short enough to fall back to PIO +(rockchip_spi_can_dma() returns false below fifo_len). + +Read ISR (which is RISR masked by IMR) so the check actually reflects +which interrupt fired, and parenthesise the expression for clarity while +at it. + +Fixes: 869f2c94db92 ("spi: rockchip: Stop spi slave dma receiver when cs inactive") +Signed-off-by: John Madieu +Link: https://patch.msgid.link/20260425092936.2590132-2-john.madieu@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rockchip.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index 45b1ad40a7efc..f7001c7bbe109 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -357,7 +357,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + + /* When int_cs_inactive comes, spi target abort */ +- if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { ++ if (rs->cs_inactive && ++ (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) { + ctlr->target_abort(ctlr); + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); +-- +2.53.0 + diff --git a/queue-6.18/spi-tegra114-fix-controller-deregistration.patch b/queue-6.18/spi-tegra114-fix-controller-deregistration.patch new file mode 100644 index 0000000000..2049a22ef7 --- /dev/null +++ b/queue-6.18/spi-tegra114-fix-controller-deregistration.patch @@ -0,0 +1,61 @@ +From 6ca7c1ed3af2e5e7c68a1bd4110f956296d4488c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 23:10:37 -0400 +Subject: spi: tegra114: fix controller deregistration + +From: Johan Hovold + +[ Upstream commit 9c9c27ff2058142d8f800de3186d6864184958de ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: 5c8096439600 ("spi: tegra114: use devm_spi_register_master()") +Cc: stable@vger.kernel.org # 3.13 +Cc: Jingoo Han +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-22-johan@kernel.org +Signed-off-by: Mark Brown +[ kept `host->dev.of_node = pdev->dev.of_node;` context line above the `spi_register_controller()` conversion ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-tegra114.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c +index 48fb11fea55f2..a28597b6b80d6 100644 +--- a/drivers/spi/spi-tegra114.c ++++ b/drivers/spi/spi-tegra114.c +@@ -1416,7 +1416,7 @@ static int tegra_spi_probe(struct platform_device *pdev) + } + + host->dev.of_node = pdev->dev.of_node; +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (ret < 0) { + dev_err(&pdev->dev, "can not register to host err %d\n", ret); + goto exit_free_irq; +@@ -1442,6 +1442,10 @@ static void tegra_spi_remove(struct platform_device *pdev) + struct spi_controller *host = platform_get_drvdata(pdev); + struct tegra_spi_data *tspi = spi_controller_get_devdata(host); + ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + free_irq(tspi->irq, tspi); + + if (tspi->tx_dma_chan) +@@ -1453,6 +1457,8 @@ static void tegra_spi_remove(struct platform_device *pdev) + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_spi_runtime_suspend(&pdev->dev); ++ ++ spi_controller_put(host); + } + + #ifdef CONFIG_PM_SLEEP +-- +2.53.0 + diff --git a/queue-6.18/spi-tegra20-sflash-fix-controller-deregistration.patch b/queue-6.18/spi-tegra20-sflash-fix-controller-deregistration.patch new file mode 100644 index 0000000000..fe11d60cd9 --- /dev/null +++ b/queue-6.18/spi-tegra20-sflash-fix-controller-deregistration.patch @@ -0,0 +1,59 @@ +From 0878e77d41a1108a0870ef4e30c80974bff1ee87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 00:14:46 -0400 +Subject: spi: tegra20-sflash: fix controller deregistration + +From: Johan Hovold + +[ Upstream commit ad7310e983327f939dd6c4e801eab13238992572 ] + +Make sure to deregister the controller before disabling underlying +resources like clocks during driver unbind. + +Fixes: f12f7318c44a ("spi: tegra20-sflash: use devm_spi_register_master()") +Cc: stable@vger.kernel.org # 3.13 +Cc: Jingoo Han +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-23-johan@kernel.org +Signed-off-by: Mark Brown +[ kept the redundant `host->dev.of_node = pdev->dev.of_node;` line above the registration call ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-tegra20-sflash.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c +index d5c8ee20b8e5b..dc3fcab5faa95 100644 +--- a/drivers/spi/spi-tegra20-sflash.c ++++ b/drivers/spi/spi-tegra20-sflash.c +@@ -506,7 +506,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) + pm_runtime_put(&pdev->dev); + + host->dev.of_node = pdev->dev.of_node; +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (ret < 0) { + dev_err(&pdev->dev, "can not register to host err %d\n", ret); + goto exit_pm_disable; +@@ -529,11 +529,17 @@ static void tegra_sflash_remove(struct platform_device *pdev) + struct spi_controller *host = platform_get_drvdata(pdev); + struct tegra_sflash_data *tsd = spi_controller_get_devdata(host); + ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + free_irq(tsd->irq, tsd); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_sflash_runtime_suspend(&pdev->dev); ++ ++ spi_controller_put(host); + } + + #ifdef CONFIG_PM_SLEEP +-- +2.53.0 + diff --git a/queue-6.18/spi-uniphier-fix-controller-deregistration.patch b/queue-6.18/spi-uniphier-fix-controller-deregistration.patch new file mode 100644 index 0000000000..1ac632aafb --- /dev/null +++ b/queue-6.18/spi-uniphier-fix-controller-deregistration.patch @@ -0,0 +1,61 @@ +From 998d8ffb1e5b3eb3fff26dbda80676769e9874f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 00:58:33 -0400 +Subject: spi: uniphier: fix controller deregistration + +From: Johan Hovold + +[ Upstream commit 0245435f777264ac45945ed2f325dd095a41d1af ] + +Make sure to deregister the controller before releasing underlying +resources like DMA during driver unbind. + +Note that clocks were also disabled before the recent commit +fdca270f8f87 ("spi: uniphier: Simplify clock handling with +devm_clk_get_enabled()"). + +Fixes: 5ba155a4d4cc ("spi: add SPI controller driver for UniPhier SoC") +Cc: stable@vger.kernel.org # 4.19 +Cc: Keiji Hayashibara +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-25-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-uniphier.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c +index b517c08a13608..75b7a0d3f8657 100644 +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -747,7 +747,7 @@ static int uniphier_spi_probe(struct platform_device *pdev) + + host->max_dma_len = min(dma_tx_burst, dma_rx_burst); + +- ret = devm_spi_register_controller(&pdev->dev, host); ++ ret = spi_register_controller(host); + if (ret) + goto out_release_dma; + +@@ -772,10 +772,16 @@ static void uniphier_spi_remove(struct platform_device *pdev) + { + struct spi_controller *host = platform_get_drvdata(pdev); + ++ spi_controller_get(host); ++ ++ spi_unregister_controller(host); ++ + if (host->dma_tx) + dma_release_channel(host->dma_tx); + if (host->dma_rx) + dma_release_channel(host->dma_rx); ++ ++ spi_controller_put(host); + } + + static const struct of_device_id uniphier_spi_match[] = { +-- +2.53.0 + diff --git a/queue-6.18/spi-uniphier-simplify-clock-handling-with-devm_clk_g.patch b/queue-6.18/spi-uniphier-simplify-clock-handling-with-devm_clk_g.patch new file mode 100644 index 0000000000..c3ee78f485 --- /dev/null +++ b/queue-6.18/spi-uniphier-simplify-clock-handling-with-devm_clk_g.patch @@ -0,0 +1,101 @@ +From d4060edff1060d3f06f834c8b6a80afe0235ca40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 00:58:32 -0400 +Subject: spi: uniphier: Simplify clock handling with devm_clk_get_enabled() + +From: Pei Xiao + +[ Upstream commit fdca270f8f87cae2eb5b619234b9dd11a863ce6b ] + +Replace devm_clk_get() followed by clk_prepare_enable() with +devm_clk_get_enabled() for the clock. This removes the need for +explicit clock enable and disable calls, as the managed API automatically +handles clock disabling on device removal or probe failure. + +Remove the now-unnecessary clk_disable_unprepare() calls from the probe +error path and the remove callback. Adjust error labels accordingly. + +Signed-off-by: Pei Xiao +Reviewed-by: Kunihiko Hayashi +Link: https://patch.msgid.link/b2deeefd4ef1a4bce71116aabfcb7e81400f6d37.1775546948.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Stable-dep-of: 0245435f7772 ("spi: uniphier: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-uniphier.c | 18 ++++-------------- + 1 file changed, 4 insertions(+), 14 deletions(-) + +diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c +index ff2142f87277f..b517c08a13608 100644 +--- a/drivers/spi/spi-uniphier.c ++++ b/drivers/spi/spi-uniphier.c +@@ -666,28 +666,24 @@ static int uniphier_spi_probe(struct platform_device *pdev) + } + priv->base_dma_addr = res->start; + +- priv->clk = devm_clk_get(&pdev->dev, NULL); ++ priv->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(priv->clk); + goto out_host_put; + } + +- ret = clk_prepare_enable(priv->clk); +- if (ret) +- goto out_host_put; +- + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; +- goto out_disable_clk; ++ goto out_host_put; + } + + ret = devm_request_irq(&pdev->dev, irq, uniphier_spi_handler, + 0, "uniphier-spi", priv); + if (ret) { + dev_err(&pdev->dev, "failed to request IRQ\n"); +- goto out_disable_clk; ++ goto out_host_put; + } + + init_completion(&priv->xfer_done); +@@ -717,7 +713,7 @@ static int uniphier_spi_probe(struct platform_device *pdev) + if (IS_ERR_OR_NULL(host->dma_tx)) { + if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; +- goto out_disable_clk; ++ goto out_host_put; + } + host->dma_tx = NULL; + dma_tx_burst = INT_MAX; +@@ -767,9 +763,6 @@ static int uniphier_spi_probe(struct platform_device *pdev) + host->dma_tx = NULL; + } + +-out_disable_clk: +- clk_disable_unprepare(priv->clk); +- + out_host_put: + spi_controller_put(host); + return ret; +@@ -778,14 +771,11 @@ static int uniphier_spi_probe(struct platform_device *pdev) + static void uniphier_spi_remove(struct platform_device *pdev) + { + struct spi_controller *host = platform_get_drvdata(pdev); +- struct uniphier_spi_priv *priv = spi_controller_get_devdata(host); + + if (host->dma_tx) + dma_release_channel(host->dma_tx); + if (host->dma_rx) + dma_release_channel(host->dma_rx); +- +- clk_disable_unprepare(priv->clk); + } + + static const struct of_device_id uniphier_spi_match[] = { +-- +2.53.0 + diff --git a/queue-6.18/spi-zynq-qspi-fix-controller-deregistration.patch b/queue-6.18/spi-zynq-qspi-fix-controller-deregistration.patch new file mode 100644 index 0000000000..88f59e01f0 --- /dev/null +++ b/queue-6.18/spi-zynq-qspi-fix-controller-deregistration.patch @@ -0,0 +1,75 @@ +From db0acd3d822ea9254183ef0f61c870bce03a7aaf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 14:08:36 -0400 +Subject: spi: zynq-qspi: fix controller deregistration + +From: Johan Hovold + +[ Upstream commit c9c012706c9fa8ca6d129a9161caf92ab625a3fd ] + +Make sure to deregister the controller before disabling it during driver +unbind. + +Note that clocks were also disabled before the recent commit +1f8fd9490e31 ("spi: zynq-qspi: Simplify clock handling with +devm_clk_get_enabled()"). + +Fixes: 67dca5e580f1 ("spi: spi-mem: Add support for Zynq QSPI controller") +Cc: stable@vger.kernel.org # 5.2: 8eb2fd00f65a +Cc: stable@vger.kernel.org # 5.2 +Cc: Naga Sureshkumar Relli +Signed-off-by: Johan Hovold +Link: https://patch.msgid.link/20260410081757.503099-27-johan@kernel.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-zynq-qspi.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c +index af252500195ce..406fd9d5337ee 100644 +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -643,7 +643,7 @@ static int zynq_qspi_probe(struct platform_device *pdev) + + xqspi = spi_controller_get_devdata(ctlr); + xqspi->dev = dev; +- platform_set_drvdata(pdev, xqspi); ++ platform_set_drvdata(pdev, ctlr); + xqspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(xqspi->regs)) { + ret = PTR_ERR(xqspi->regs); +@@ -702,9 +702,9 @@ static int zynq_qspi_probe(struct platform_device *pdev) + /* QSPI controller initializations */ + zynq_qspi_init_hw(xqspi, ctlr->num_chipselect); + +- ret = devm_spi_register_controller(&pdev->dev, ctlr); ++ ret = spi_register_controller(ctlr); + if (ret) { +- dev_err(&pdev->dev, "devm_spi_register_controller failed\n"); ++ dev_err(&pdev->dev, "failed to register controller\n"); + goto remove_ctlr; + } + +@@ -728,9 +728,16 @@ static int zynq_qspi_probe(struct platform_device *pdev) + */ + static void zynq_qspi_remove(struct platform_device *pdev) + { +- struct zynq_qspi *xqspi = platform_get_drvdata(pdev); ++ struct spi_controller *ctlr = platform_get_drvdata(pdev); ++ struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr); ++ ++ spi_controller_get(ctlr); ++ ++ spi_unregister_controller(ctlr); + + zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET, 0); ++ ++ spi_controller_put(ctlr); + } + + static const struct of_device_id zynq_qspi_of_match[] = { +-- +2.53.0 + diff --git a/queue-6.18/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_.patch b/queue-6.18/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_.patch new file mode 100644 index 0000000000..ed6875c47d --- /dev/null +++ b/queue-6.18/spi-zynq-qspi-simplify-clock-handling-with-devm_clk_.patch @@ -0,0 +1,144 @@ +From e69ffe0ae9a1c4835aaab1927aa3b94f2b618076 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 14:08:35 -0400 +Subject: spi: zynq-qspi: Simplify clock handling with devm_clk_get_enabled() + +From: Pei Xiao + +[ Upstream commit 1f8fd9490e3184e9a2394df2e682901a1d57ce71 ] + +Replace devm_clk_get() followed by clk_prepare_enable() with +devm_clk_get_enabled() for both "pclk" and "ref_clk". This removes +the need for explicit clock enable and disable calls, as the managed +API automatically disables the clocks on device removal or probe +failure. + +Remove the now-unnecessary clk_disable_unprepare() calls from the +probe error paths and the remove callback. Simplify error handling +by jumping directly to the remove_ctlr label. + +Signed-off-by: Pei Xiao +Acked-by: Michal Simek +Link: https://patch.msgid.link/24043625f89376da36feca2408f990a85be7ab36.1775555500.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Stable-dep-of: c9c012706c9f ("spi: zynq-qspi: fix controller deregistration") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-zynq-qspi.c | 42 ++++++------------------------------- + 1 file changed, 6 insertions(+), 36 deletions(-) + +diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c +index 5232483c4a3a8..af252500195ce 100644 +--- a/drivers/spi/spi-zynq-qspi.c ++++ b/drivers/spi/spi-zynq-qspi.c +@@ -381,21 +381,10 @@ static int zynq_qspi_setup_op(struct spi_device *spi) + { + struct spi_controller *ctlr = spi->controller; + struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr); +- int ret; + + if (ctlr->busy) + return -EBUSY; + +- ret = clk_enable(qspi->refclk); +- if (ret) +- return ret; +- +- ret = clk_enable(qspi->pclk); +- if (ret) { +- clk_disable(qspi->refclk); +- return ret; +- } +- + zynq_qspi_write(qspi, ZYNQ_QSPI_ENABLE_OFFSET, + ZYNQ_QSPI_ENABLE_ENABLE_MASK); + +@@ -661,7 +650,7 @@ static int zynq_qspi_probe(struct platform_device *pdev) + goto remove_ctlr; + } + +- xqspi->pclk = devm_clk_get(&pdev->dev, "pclk"); ++ xqspi->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); + if (IS_ERR(xqspi->pclk)) { + dev_err(&pdev->dev, "pclk clock not found.\n"); + ret = PTR_ERR(xqspi->pclk); +@@ -670,36 +659,24 @@ static int zynq_qspi_probe(struct platform_device *pdev) + + init_completion(&xqspi->data_completion); + +- xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk"); ++ xqspi->refclk = devm_clk_get_enabled(&pdev->dev, "ref_clk"); + if (IS_ERR(xqspi->refclk)) { + dev_err(&pdev->dev, "ref_clk clock not found.\n"); + ret = PTR_ERR(xqspi->refclk); + goto remove_ctlr; + } + +- ret = clk_prepare_enable(xqspi->pclk); +- if (ret) { +- dev_err(&pdev->dev, "Unable to enable APB clock.\n"); +- goto remove_ctlr; +- } +- +- ret = clk_prepare_enable(xqspi->refclk); +- if (ret) { +- dev_err(&pdev->dev, "Unable to enable device clock.\n"); +- goto clk_dis_pclk; +- } +- + xqspi->irq = platform_get_irq(pdev, 0); + if (xqspi->irq < 0) { + ret = xqspi->irq; +- goto clk_dis_all; ++ goto remove_ctlr; + } + ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq, + 0, pdev->name, xqspi); + if (ret != 0) { + ret = -ENXIO; + dev_err(&pdev->dev, "request_irq failed\n"); +- goto clk_dis_all; ++ goto remove_ctlr; + } + + ret = of_property_read_u32(np, "num-cs", +@@ -709,7 +686,7 @@ static int zynq_qspi_probe(struct platform_device *pdev) + } else if (num_cs > ZYNQ_QSPI_MAX_NUM_CS) { + ret = -EINVAL; + dev_err(&pdev->dev, "only 2 chip selects are available\n"); +- goto clk_dis_all; ++ goto remove_ctlr; + } else { + ctlr->num_chipselect = num_cs; + } +@@ -728,15 +705,11 @@ static int zynq_qspi_probe(struct platform_device *pdev) + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret) { + dev_err(&pdev->dev, "devm_spi_register_controller failed\n"); +- goto clk_dis_all; ++ goto remove_ctlr; + } + + return ret; + +-clk_dis_all: +- clk_disable_unprepare(xqspi->refclk); +-clk_dis_pclk: +- clk_disable_unprepare(xqspi->pclk); + remove_ctlr: + spi_controller_put(ctlr); + +@@ -758,9 +731,6 @@ static void zynq_qspi_remove(struct platform_device *pdev) + struct zynq_qspi *xqspi = platform_get_drvdata(pdev); + + zynq_qspi_write(xqspi, ZYNQ_QSPI_ENABLE_OFFSET, 0); +- +- clk_disable_unprepare(xqspi->refclk); +- clk_disable_unprepare(xqspi->pclk); + } + + static const struct of_device_id zynq_qspi_of_match[] = { +-- +2.53.0 + diff --git a/queue-6.18/stop_machine-fix-the-documentation-for-a-null-cpus-a.patch b/queue-6.18/stop_machine-fix-the-documentation-for-a-null-cpus-a.patch new file mode 100644 index 0000000000..b0ebea14fb --- /dev/null +++ b/queue-6.18/stop_machine-fix-the-documentation-for-a-null-cpus-a.patch @@ -0,0 +1,55 @@ +From 3bc69a7e4a1305256411cd963f34aaff0e753b55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 14:11:11 +0100 +Subject: stop_machine: Fix the documentation for a NULL cpus argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 48f7a50c027dd2abb9e7b8a6ecc8e531d87f2c21 ] + +A recent refactoring of the kernel-docs for stop machine changed the +description of the cpus parameter from "NULL = any online cpu" +to "NULL = run on each online CPU". + +However the callback is only executed on a single CPU, not all of them. +The old wording was a bit ambiguous and could have been read both ways. + +Reword the documentation to be correct again and hopefully also clearer. + +Fixes: fc6f89dc7078 ("stop_machine: Improve kernel-doc function-header comments") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Paul E. McKenney +Reviewed-by: Sebastian Andrzej Siewior +Signed-off-by: Sasha Levin +--- + include/linux/stop_machine.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h +index 72820503514cc..01011113d2263 100644 +--- a/include/linux/stop_machine.h ++++ b/include/linux/stop_machine.h +@@ -99,7 +99,7 @@ static inline void print_stop_info(const char *log_lvl, struct task_struct *task + * stop_machine: freeze the machine on all CPUs and run this function + * @fn: the function to run + * @data: the data ptr to pass to @fn() +- * @cpus: the cpus to run @fn() on (NULL = run on each online CPU) ++ * @cpus: the cpus to run @fn() on (NULL = one unspecified online CPU) + * + * Description: This causes a thread to be scheduled on every CPU, which + * will run with interrupts disabled. Each CPU specified by @cpus will +@@ -133,7 +133,7 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); + * stop_machine_cpuslocked: freeze the machine on all CPUs and run this function + * @fn: the function to run + * @data: the data ptr to pass to @fn() +- * @cpus: the cpus to run @fn() on (NULL = run on each online CPU) ++ * @cpus: the cpus to run @fn() on (NULL = one unspecified online CPU) + * + * Same as above. Avoids nested calls to cpus_read_lock(). + * +-- +2.53.0 + diff --git a/queue-6.18/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch b/queue-6.18/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch new file mode 100644 index 0000000000..eb2ce9a3e0 --- /dev/null +++ b/queue-6.18/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch @@ -0,0 +1,75 @@ +From 3d95bd216048b4e1575c15043ebc95d8e5936487 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:07 +0000 +Subject: tcp: add data-race annotations around tp->data_segs_out and + tp->total_retrans + +From: Eric Dumazet + +[ Upstream commit 21e92a38cfd891538598ba8f805e0165a820d532 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e98102f4897 ("tcp: record pkts sent and retransmistted") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 8 +++++--- + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index a33641b9ed7e4..4695b03f866f8 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4386,9 +4386,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED, + info.tcpi_sndbuf_limited, TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT, +- tp->data_segs_out, TCP_NLA_PAD); ++ READ_ONCE(tp->data_segs_out), TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS, +- tp->total_retrans, TCP_NLA_PAD); ++ READ_ONCE(tp->total_retrans), TCP_NLA_PAD); + + rate = READ_ONCE(sk->sk_pacing_rate); + rate64 = (rate != ~0UL) ? rate : ~0ULL; +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index b00bd5044b322..c4cf76f71520f 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1603,7 +1603,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + + if (skb->len != tcp_header_size) { + tcp_event_data_sent(tp, sk); +- tp->data_segs_out += tcp_skb_pcount(skb); ++ WRITE_ONCE(tp->data_segs_out, ++ tp->data_segs_out + tcp_skb_pcount(skb)); + tp->bytes_sent += skb->len - tcp_header_size; + } + +@@ -3556,7 +3557,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); +- tp->total_retrans += segs; ++ WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); + tp->bytes_retrans += skb->len; + + /* make sure skb->data is aligned on arches that require it +@@ -4581,7 +4582,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) + * However in this case, we are dealing with a passive fastopen + * socket thus we can change total_retrans value. + */ +- tcp_sk_rw(sk)->total_retrans++; ++ WRITE_ONCE(tcp_sk_rw(sk)->total_retrans, ++ tcp_sk_rw(sk)->total_retrans + 1); + } + trace_tcp_retransmit_synack(sk, req); + WRITE_ONCE(req->num_retrans, req->num_retrans + 1); +-- +2.53.0 + diff --git a/queue-6.18/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch b/queue-6.18/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch new file mode 100644 index 0000000000..220205f347 --- /dev/null +++ b/queue-6.18/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch @@ -0,0 +1,76 @@ +From 3f3d824cd806f9adcadcf332a04b1817c99953f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:11 +0000 +Subject: tcp: add data-race annotations for TCP_NLA_SNDQ_SIZE + +From: Eric Dumazet + +[ Upstream commit 124199444de467767175a9004e1574dc42523e62 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 87ecc95d81d9 ("tcp: add send queue size stat in SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-7-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 +++- + net/ipv4/tcp_input.c | 4 ++-- + net/ipv4/tcp_output.c | 2 +- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 515313ef0c642..0d6e991155c95 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4408,7 +4408,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_DELIVERED, READ_ONCE(tp->delivered)); + nla_put_u32(stats, TCP_NLA_DELIVERED_CE, READ_ONCE(tp->delivered_ce)); + +- nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); ++ nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una))); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); + + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index b5a3c7ca2605d..3e29134a54b19 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3694,7 +3694,7 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) + sock_owned_by_me((struct sock *)tp); + tp->bytes_acked += delta; + tcp_snd_sne_update(tp, ack); +- tp->snd_una = ack; ++ WRITE_ONCE(tp->snd_una, ack); + } + + static void tcp_rcv_sne_update(struct tcp_sock *tp, u32 seq) +@@ -7035,7 +7035,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) + if (sk->sk_socket) + sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); + +- tp->snd_una = TCP_SKB_CB(skb)->ack_seq; ++ WRITE_ONCE(tp->snd_una, TCP_SKB_CB(skb)->ack_seq); + tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale; + tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); + +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 3c25292ae72d8..e6aa54d2335c0 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -4089,7 +4089,7 @@ static void tcp_connect_init(struct sock *sk) + tp->snd_wnd = 0; + tcp_init_wl(tp, 0); + tcp_write_queue_purge(sk); +- tp->snd_una = tp->write_seq; ++ WRITE_ONCE(tp->snd_una, tp->write_seq); + tp->snd_sml = tp->write_seq; + tp->snd_up = tp->write_seq; + WRITE_ONCE(tp->snd_nxt, tp->write_seq); +-- +2.53.0 + diff --git a/queue-6.18/tcp-add-data-races-annotations-around-tp-reordering-.patch b/queue-6.18/tcp-add-data-races-annotations-around-tp-reordering-.patch new file mode 100644 index 0000000000..7e3caf70cd --- /dev/null +++ b/queue-6.18/tcp-add-data-races-annotations-around-tp-reordering-.patch @@ -0,0 +1,114 @@ +From e35f9975f8abbd1fda05124a1642bb22debeadc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:08 +0000 +Subject: tcp: add data-races annotations around tp->reordering, tp->snd_cwnd + +From: Eric Dumazet + +[ Upstream commit 829ba1f329cb7cbd56d599a6d225997fba66dc32 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE(), WRITE_ONCE() data_race() annotations to keep KCSAN happy. + +Fixes: bb7c19f96012 ("tcp: add related fields into SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-4-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 2 +- + net/ipv4/tcp.c | 8 ++++---- + net/ipv4/tcp_input.c | 14 ++++++++------ + net/ipv4/tcp_metrics.c | 2 +- + 4 files changed, 14 insertions(+), 12 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 236d9e0d35ed7..18381f4086d04 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1429,7 +1429,7 @@ static inline u32 tcp_snd_cwnd(const struct tcp_sock *tp) + static inline void tcp_snd_cwnd_set(struct tcp_sock *tp, u32 val) + { + WARN_ON_ONCE((int)val <= 0); +- tp->snd_cwnd = val; ++ WRITE_ONCE(tp->snd_cwnd, val); + } + + static inline bool tcp_in_slow_start(const struct tcp_sock *tp) +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 4695b03f866f8..9e7e5ebcf14d5 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4397,13 +4397,13 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + rate64 = tcp_compute_delivery_rate(tp); + nla_put_u64_64bit(stats, TCP_NLA_DELIVERY_RATE, rate64, TCP_NLA_PAD); + +- nla_put_u32(stats, TCP_NLA_SND_CWND, tcp_snd_cwnd(tp)); +- nla_put_u32(stats, TCP_NLA_REORDERING, tp->reordering); +- nla_put_u32(stats, TCP_NLA_MIN_RTT, tcp_min_rtt(tp)); ++ nla_put_u32(stats, TCP_NLA_SND_CWND, READ_ONCE(tp->snd_cwnd)); ++ nla_put_u32(stats, TCP_NLA_REORDERING, READ_ONCE(tp->reordering)); ++ nla_put_u32(stats, TCP_NLA_MIN_RTT, data_race(tcp_min_rtt(tp))); + + nla_put_u8(stats, TCP_NLA_RECUR_RETRANS, + READ_ONCE(inet_csk(sk)->icsk_retransmits)); +- nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, !!tp->rate_app_limited); ++ nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, data_race(!!tp->rate_app_limited)); + nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, tp->snd_ssthresh); + nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered); + nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 96486eea26724..64e7bcbb42993 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1260,8 +1260,9 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq, + tp->sacked_out, + tp->undo_marker ? tp->undo_retrans : 0); + #endif +- tp->reordering = min_t(u32, (metric + mss - 1) / mss, +- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering)); ++ WRITE_ONCE(tp->reordering, ++ min_t(u32, (metric + mss - 1) / mss, ++ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering))); + } + + /* This exciting event is worth to be remembered. 8) */ +@@ -2220,8 +2221,9 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend) + if (!tcp_limit_reno_sacked(tp)) + return; + +- tp->reordering = min_t(u32, tp->packets_out + addend, +- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering)); ++ WRITE_ONCE(tp->reordering, ++ min_t(u32, tp->packets_out + addend, ++ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering))); + tp->reord_seen++; + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER); + } +@@ -2360,8 +2362,8 @@ void tcp_enter_loss(struct sock *sk) + reordering = READ_ONCE(net->ipv4.sysctl_tcp_reordering); + if (icsk->icsk_ca_state <= TCP_CA_Disorder && + tp->sacked_out >= reordering) +- tp->reordering = min_t(unsigned int, tp->reordering, +- reordering); ++ WRITE_ONCE(tp->reordering, ++ min_t(unsigned int, tp->reordering, reordering)); + + tcp_set_ca_state(sk, TCP_CA_Loss); + tp->high_seq = tp->snd_nxt; +diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c +index 45b6ecd164126..170ca11edf6b9 100644 +--- a/net/ipv4/tcp_metrics.c ++++ b/net/ipv4/tcp_metrics.c +@@ -496,7 +496,7 @@ void tcp_init_metrics(struct sock *sk) + } + val = tcp_metric_get(tm, TCP_METRIC_REORDERING); + if (val && tp->reordering != val) +- tp->reordering = val; ++ WRITE_ONCE(tp->reordering, val); + + crtt = tcp_metric_get(tm, TCP_METRIC_RTT); + rcu_read_unlock(); +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-bytes_retrans.patch b/queue-6.18/tcp-annotate-data-races-around-tp-bytes_retrans.patch new file mode 100644 index 0000000000..829c80c459 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-bytes_retrans.patch @@ -0,0 +1,53 @@ +From 98aa7ca479a0da886dd04206d6ccf4e53d598289 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:13 +0000 +Subject: tcp: annotate data-races around tp->bytes_retrans + +From: Eric Dumazet + +[ Upstream commit 5efc7b9f7cbd43401f1af81d3d7f2be00f93390d ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: fb31c9b9f6c8 ("tcp: add data bytes retransmitted stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-9-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 7d45a2aab18dd..35c444caab8a8 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4415,8 +4415,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, +- TCP_NLA_PAD); ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, ++ READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index c2492f4be2151..5a443fb14a973 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -3559,7 +3559,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); + WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); +- tp->bytes_retrans += skb->len; ++ WRITE_ONCE(tp->bytes_retrans, tp->bytes_retrans + skb->len); + + /* make sure skb->data is aligned on arches that require it + * and check if ack-trimming & collapsing extended the headroom +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-bytes_sent.patch b/queue-6.18/tcp-annotate-data-races-around-tp-bytes_sent.patch new file mode 100644 index 0000000000..797d6a8331 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-bytes_sent.patch @@ -0,0 +1,52 @@ +From 78f22ca64fddd588245cd819c8ab00e2085a3c21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:12 +0000 +Subject: tcp: annotate data-races around tp->bytes_sent + +From: Eric Dumazet + +[ Upstream commit ee43e957ce2ec77b2ec47fef28f3c0df6ab01a31 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: ba113c3aa79a ("tcp: add data bytes sent stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-8-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_output.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 0d6e991155c95..7d45a2aab18dd 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4413,7 +4413,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una))); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); + +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, + TCP_NLA_PAD); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index e6aa54d2335c0..c2492f4be2151 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1605,7 +1605,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + tcp_event_data_sent(tp, sk); + WRITE_ONCE(tp->data_segs_out, + tp->data_segs_out + tcp_skb_pcount(skb)); +- tp->bytes_sent += skb->len - tcp_header_size; ++ WRITE_ONCE(tp->bytes_sent, ++ tp->bytes_sent + skb->len - tcp_header_size); + } + + if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-delivered-and-tp-d.patch b/queue-6.18/tcp-annotate-data-races-around-tp-delivered-and-tp-d.patch new file mode 100644 index 0000000000..1a88569017 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-delivered-and-tp-d.patch @@ -0,0 +1,93 @@ +From f912e5fbdee379871b4d60cf85b28d64d359d284 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:10 +0000 +Subject: tcp: annotate data-races around tp->delivered and tp->delivered_ce + +From: Eric Dumazet + +[ Upstream commit faa886ad3ce5fc8f5156493491fe189b2b726bc9 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: feb5f2ec6464 ("tcp: export packets delivery info") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tcp_ecn.h | 2 +- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_input.c | 8 ++++---- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h +index a709fb1756eb7..59d6944f8d103 100644 +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -189,7 +189,7 @@ static inline void tcp_accecn_third_ack(struct sock *sk, + tcp_accecn_validate_syn_feedback(sk, ace, sent_ect)) { + if ((tcp_accecn_extract_syn_ect(ace) == INET_ECN_CE) && + !tp->delivered_ce) +- tp->delivered_ce++; ++ WRITE_ONCE(tp->delivered_ce, 1); + } + break; + } +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 3de09b59663d8..515313ef0c642 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4405,8 +4405,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + READ_ONCE(inet_csk(sk)->icsk_retransmits)); + nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, data_race(!!tp->rate_app_limited)); + nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, READ_ONCE(tp->snd_ssthresh)); +- nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered); +- nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce); ++ nla_put_u32(stats, TCP_NLA_DELIVERED, READ_ONCE(tp->delivered)); ++ nla_put_u32(stats, TCP_NLA_DELIVERED_CE, READ_ONCE(tp->delivered_ce)); + + nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 16bb525c04f1d..b5a3c7ca2605d 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -476,14 +476,14 @@ static bool tcp_accecn_process_option(struct tcp_sock *tp, + + static void tcp_count_delivered_ce(struct tcp_sock *tp, u32 ecn_count) + { +- tp->delivered_ce += ecn_count; ++ WRITE_ONCE(tp->delivered_ce, tp->delivered_ce + ecn_count); + } + + /* Updates the delivered and delivered_ce counts */ + static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered, + bool ece_ack) + { +- tp->delivered += delivered; ++ WRITE_ONCE(tp->delivered, tp->delivered + delivered); + if (tcp_ecn_mode_rfc3168(tp) && ece_ack) + tcp_count_delivered_ce(tp, delivered); + } +@@ -6576,7 +6576,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVE); + /* SYN-data is counted as two separate packets in tcp_ack() */ + if (tp->delivered > 1) +- --tp->delivered; ++ WRITE_ONCE(tp->delivered, tp->delivered - 1); + } + + tcp_fastopen_add_skb(sk, synack); +@@ -7007,7 +7007,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) + SKB_DR_SET(reason, NOT_SPECIFIED); + switch (sk->sk_state) { + case TCP_SYN_RECV: +- tp->delivered++; /* SYN-ACK delivery isn't tracked in tcp_ack */ ++ WRITE_ONCE(tp->delivered, tp->delivered + 1); /* SYN-ACK delivery isn't tracked in tcp_ack */ + if (!tp->srtt_us) + tcp_synack_rtt_meas(sk, req); + +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-dsack_dups.patch b/queue-6.18/tcp-annotate-data-races-around-tp-dsack_dups.patch new file mode 100644 index 0000000000..6c783af43c --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-dsack_dups.patch @@ -0,0 +1,51 @@ +From 9379414c408b3af0e7769698118b9b992e44c838 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:14 +0000 +Subject: tcp: annotate data-races around tp->dsack_dups + +From: Eric Dumazet + +[ Upstream commit a984705ca88b976bf1087978fd98b7f3993da88c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e10b6554ff2 ("tcp: add dsack blocks received stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-10-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_input.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 35c444caab8a8..3a5801ba3df1a 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4417,7 +4417,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); +- nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); ++ nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 3e29134a54b19..90727e1e581e4 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1213,7 +1213,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq, + else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq) + state->flag |= FLAG_DSACK_TLP; + +- tp->dsack_dups += dup_segs; ++ WRITE_ONCE(tp->dsack_dups, tp->dsack_dups + dup_segs); + /* Skip the DSACK if dup segs weren't retransmitted by sender */ + if (tp->dsack_dups > tp->total_retrans) + return 0; +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-plb_rehash.patch b/queue-6.18/tcp-annotate-data-races-around-tp-plb_rehash.patch new file mode 100644 index 0000000000..284260d719 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-plb_rehash.patch @@ -0,0 +1,52 @@ +From 64d9164d3f9517ba22f46dcfe88a3a8e7f23197b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:19 +0000 +Subject: tcp: annotate data-races around tp->plb_rehash + +From: Eric Dumazet + +[ Upstream commit 9e89b9d03a2d2e30dcca166d5af52f9a8eceab25 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 29c1c44646ae ("tcp: add u32 counter in tcp_sock and an SNMP counter for PLB") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-15-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + net/ipv4/tcp_plb.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index fe91675ae5678..2de4748269ca9 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4455,7 +4455,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u8(stats, TCP_NLA_TTL, + tcp_skb_ttl_or_hop_limit(ack_skb)); + +- nla_put_u32(stats, TCP_NLA_REHASH, tp->plb_rehash + tp->timeout_rehash); ++ nla_put_u32(stats, TCP_NLA_REHASH, ++ READ_ONCE(tp->plb_rehash) + READ_ONCE(tp->timeout_rehash)); + return stats; + } + +diff --git a/net/ipv4/tcp_plb.c b/net/ipv4/tcp_plb.c +index 4bcf7eff95e39..b7f9b60d8991f 100644 +--- a/net/ipv4/tcp_plb.c ++++ b/net/ipv4/tcp_plb.c +@@ -79,7 +79,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb) + + sk_rethink_txhash(sk); + plb->consec_cong_rounds = 0; +- tcp_sk(sk)->plb_rehash++; ++ WRITE_ONCE(tcp_sk(sk)->plb_rehash, tcp_sk(sk)->plb_rehash + 1); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPLBREHASH); + } + EXPORT_SYMBOL_GPL(tcp_plb_check_rehash); +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-reord_seen.patch b/queue-6.18/tcp-annotate-data-races-around-tp-reord_seen.patch new file mode 100644 index 0000000000..95b1dc46e7 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-reord_seen.patch @@ -0,0 +1,60 @@ +From 487457ea89495950af987b217bab022f6ba41ea8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:15 +0000 +Subject: tcp: annotate data-races around tp->reord_seen + +From: Eric Dumazet + +[ Upstream commit 62585690e6b2a112c408fe25f142b246ac833c42 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7ec65372ca53 ("tcp: add stat of data packet reordering events") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-11-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_input.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 3a5801ba3df1a..03299c21e4d68 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4418,7 +4418,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); +- nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); ++ nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen)); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 90727e1e581e4..5a944b1ec320c 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1266,7 +1266,7 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq, + } + + /* This exciting event is worth to be remembered. 8) */ +- tp->reord_seen++; ++ WRITE_ONCE(tp->reord_seen, tp->reord_seen + 1); + NET_INC_STATS(sock_net(sk), + ts ? LINUX_MIB_TCPTSREORDER : LINUX_MIB_TCPSACKREORDER); + } +@@ -2224,7 +2224,7 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend) + WRITE_ONCE(tp->reordering, + min_t(u32, tp->packets_out + addend, + READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering))); +- tp->reord_seen++; ++ WRITE_ONCE(tp->reord_seen, tp->reord_seen + 1); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER); + } + +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-snd_ssthresh.patch b/queue-6.18/tcp-annotate-data-races-around-tp-snd_ssthresh.patch new file mode 100644 index 0000000000..bf70ef4700 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-snd_ssthresh.patch @@ -0,0 +1,334 @@ +From c60fd72f7df6b52e5bcdcf1ece78feecc8d0485e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:09 +0000 +Subject: tcp: annotate data-races around tp->snd_ssthresh + +From: Eric Dumazet + +[ Upstream commit fd571afb05ebaeac5d8f09460a0640d4cf6755f8 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7156d194a077 ("tcp: add snd_ssthresh stat in SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-5-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_bbr.c | 6 +++--- + net/ipv4/tcp_bic.c | 2 +- + net/ipv4/tcp_cdg.c | 4 ++-- + net/ipv4/tcp_cubic.c | 6 +++--- + net/ipv4/tcp_dctcp.c | 2 +- + net/ipv4/tcp_input.c | 8 ++++---- + net/ipv4/tcp_metrics.c | 4 ++-- + net/ipv4/tcp_nv.c | 4 ++-- + net/ipv4/tcp_output.c | 4 ++-- + net/ipv4/tcp_vegas.c | 9 +++++---- + net/ipv4/tcp_westwood.c | 4 ++-- + net/ipv4/tcp_yeah.c | 3 ++- + 14 files changed, 32 insertions(+), 30 deletions(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index ae6d0453cf123..bad3fb6318461 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -5387,7 +5387,7 @@ static int bpf_sol_tcp_setsockopt(struct sock *sk, int optname, + if (val <= 0) + return -EINVAL; + tp->snd_cwnd_clamp = val; +- tp->snd_ssthresh = val; ++ WRITE_ONCE(tp->snd_ssthresh, val); + break; + case TCP_BPF_DELACK_MAX: + timeout = usecs_to_jiffies(val); +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 9e7e5ebcf14d5..3de09b59663d8 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3408,7 +3408,7 @@ int tcp_disconnect(struct sock *sk, int flags) + icsk->icsk_rto = TCP_TIMEOUT_INIT; + WRITE_ONCE(icsk->icsk_rto_min, TCP_RTO_MIN); + WRITE_ONCE(icsk->icsk_delack_max, TCP_DELACK_MAX); +- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; ++ WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH); + tcp_snd_cwnd_set(tp, TCP_INIT_CWND); + tp->snd_cwnd_cnt = 0; + tp->is_cwnd_limited = 0; +@@ -4404,7 +4404,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u8(stats, TCP_NLA_RECUR_RETRANS, + READ_ONCE(inet_csk(sk)->icsk_retransmits)); + nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, data_race(!!tp->rate_app_limited)); +- nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, tp->snd_ssthresh); ++ nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, READ_ONCE(tp->snd_ssthresh)); + nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered); + nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce); + +diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c +index 760941e55153e..3df6160f51567 100644 +--- a/net/ipv4/tcp_bbr.c ++++ b/net/ipv4/tcp_bbr.c +@@ -896,8 +896,8 @@ static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs) + + if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { + bbr->mode = BBR_DRAIN; /* drain queue we created */ +- tcp_sk(sk)->snd_ssthresh = +- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); ++ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, ++ bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT)); + } /* fall through to check if in-flight is already small: */ + if (bbr->mode == BBR_DRAIN && + bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <= +@@ -1042,7 +1042,7 @@ __bpf_kfunc static void bbr_init(struct sock *sk) + struct bbr *bbr = inet_csk_ca(sk); + + bbr->prior_cwnd = 0; +- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; ++ WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH); + bbr->rtt_cnt = 0; + bbr->next_rtt_delivered = tp->delivered; + bbr->prev_ca_state = TCP_CA_Open; +diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c +index 58358bf92e1b8..65444ff142413 100644 +--- a/net/ipv4/tcp_bic.c ++++ b/net/ipv4/tcp_bic.c +@@ -74,7 +74,7 @@ static void bictcp_init(struct sock *sk) + bictcp_reset(ca); + + if (initial_ssthresh) +- tcp_sk(sk)->snd_ssthresh = initial_ssthresh; ++ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, initial_ssthresh); + } + + /* +diff --git a/net/ipv4/tcp_cdg.c b/net/ipv4/tcp_cdg.c +index fbad6c35dee9c..37f094204b6d0 100644 +--- a/net/ipv4/tcp_cdg.c ++++ b/net/ipv4/tcp_cdg.c +@@ -162,7 +162,7 @@ static void tcp_cdg_hystart_update(struct sock *sk) + NET_ADD_STATS(sock_net(sk), + LINUX_MIB_TCPHYSTARTTRAINCWND, + tcp_snd_cwnd(tp)); +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp)); + return; + } + } +@@ -181,7 +181,7 @@ static void tcp_cdg_hystart_update(struct sock *sk) + NET_ADD_STATS(sock_net(sk), + LINUX_MIB_TCPHYSTARTDELAYCWND, + tcp_snd_cwnd(tp)); +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp)); + } + } + } +diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c +index 76c23675ae50a..f891e8d1e5458 100644 +--- a/net/ipv4/tcp_cubic.c ++++ b/net/ipv4/tcp_cubic.c +@@ -136,7 +136,7 @@ __bpf_kfunc static void cubictcp_init(struct sock *sk) + bictcp_hystart_reset(sk); + + if (!hystart && initial_ssthresh) +- tcp_sk(sk)->snd_ssthresh = initial_ssthresh; ++ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, initial_ssthresh); + } + + __bpf_kfunc static void cubictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) +@@ -423,7 +423,7 @@ static void hystart_update(struct sock *sk, u32 delay) + NET_ADD_STATS(sock_net(sk), + LINUX_MIB_TCPHYSTARTTRAINCWND, + tcp_snd_cwnd(tp)); +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp)); + } + } + } +@@ -443,7 +443,7 @@ static void hystart_update(struct sock *sk, u32 delay) + NET_ADD_STATS(sock_net(sk), + LINUX_MIB_TCPHYSTARTDELAYCWND, + tcp_snd_cwnd(tp)); +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp)); + } + } + } +diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c +index 03abe0848420d..6f103038b0152 100644 +--- a/net/ipv4/tcp_dctcp.c ++++ b/net/ipv4/tcp_dctcp.c +@@ -177,7 +177,7 @@ static void dctcp_react_to_loss(struct sock *sk) + struct tcp_sock *tp = tcp_sk(sk); + + ca->loss_cwnd = tcp_snd_cwnd(tp); +- tp->snd_ssthresh = max(tcp_snd_cwnd(tp) >> 1U, 2U); ++ WRITE_ONCE(tp->snd_ssthresh, max(tcp_snd_cwnd(tp) >> 1U, 2U)); + } + + __bpf_kfunc static void dctcp_state(struct sock *sk, u8 new_state) +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 64e7bcbb42993..16bb525c04f1d 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -2348,7 +2348,7 @@ void tcp_enter_loss(struct sock *sk) + (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) { + tp->prior_ssthresh = tcp_current_ssthresh(sk); + tp->prior_cwnd = tcp_snd_cwnd(tp); +- tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, icsk->icsk_ca_ops->ssthresh(sk)); + tcp_ca_event(sk, CA_EVENT_LOSS); + tcp_init_undo(tp); + } +@@ -2641,7 +2641,7 @@ static void tcp_undo_cwnd_reduction(struct sock *sk, bool unmark_loss) + tcp_snd_cwnd_set(tp, icsk->icsk_ca_ops->undo_cwnd(sk)); + + if (tp->prior_ssthresh > tp->snd_ssthresh) { +- tp->snd_ssthresh = tp->prior_ssthresh; ++ WRITE_ONCE(tp->snd_ssthresh, tp->prior_ssthresh); + tcp_ecn_withdraw_cwr(tp); + } + } +@@ -2759,7 +2759,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk) + tp->prior_cwnd = tcp_snd_cwnd(tp); + tp->prr_delivered = 0; + tp->prr_out = 0; +- tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, inet_csk(sk)->icsk_ca_ops->ssthresh(sk)); + tcp_ecn_queue_cwr(tp); + } + +@@ -2901,7 +2901,7 @@ static void tcp_non_congestion_loss_retransmit(struct sock *sk) + + if (icsk->icsk_ca_state != TCP_CA_Loss) { + tp->high_seq = tp->snd_nxt; +- tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk)); + tp->prior_ssthresh = 0; + tp->undo_marker = 0; + tcp_set_ca_state(sk, TCP_CA_Loss); +diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c +index 170ca11edf6b9..7b08d3e58a741 100644 +--- a/net/ipv4/tcp_metrics.c ++++ b/net/ipv4/tcp_metrics.c +@@ -490,9 +490,9 @@ void tcp_init_metrics(struct sock *sk) + val = READ_ONCE(net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) ? + 0 : tcp_metric_get(tm, TCP_METRIC_SSTHRESH); + if (val) { +- tp->snd_ssthresh = val; ++ WRITE_ONCE(tp->snd_ssthresh, val); + if (tp->snd_ssthresh > tp->snd_cwnd_clamp) +- tp->snd_ssthresh = tp->snd_cwnd_clamp; ++ WRITE_ONCE(tp->snd_ssthresh, tp->snd_cwnd_clamp); + } + val = tcp_metric_get(tm, TCP_METRIC_REORDERING); + if (val && tp->reordering != val) +diff --git a/net/ipv4/tcp_nv.c b/net/ipv4/tcp_nv.c +index a60662f4bdf92..f345897a68dfc 100644 +--- a/net/ipv4/tcp_nv.c ++++ b/net/ipv4/tcp_nv.c +@@ -396,8 +396,8 @@ static void tcpnv_acked(struct sock *sk, const struct ack_sample *sample) + + /* We have enough data to determine we are congested */ + ca->nv_allow_cwnd_growth = 0; +- tp->snd_ssthresh = +- (nv_ssthresh_factor * max_win) >> 3; ++ WRITE_ONCE(tp->snd_ssthresh, ++ (nv_ssthresh_factor * max_win) >> 3); + if (tcp_snd_cwnd(tp) - max_win > 2) { + /* gap > 2, we do exponential cwnd decrease */ + int dec; +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index c4cf76f71520f..3c25292ae72d8 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -151,7 +151,7 @@ void tcp_cwnd_restart(struct sock *sk, s32 delta) + + tcp_ca_event(sk, CA_EVENT_CWND_RESTART); + +- tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk)); + restart_cwnd = min(restart_cwnd, cwnd); + + while ((delta -= inet_csk(sk)->icsk_rto) > 0 && cwnd > restart_cwnd) +@@ -2060,7 +2060,7 @@ static void tcp_cwnd_application_limited(struct sock *sk) + u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk)); + u32 win_used = max(tp->snd_cwnd_used, init_win); + if (win_used < tcp_snd_cwnd(tp)) { +- tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk)); + tcp_snd_cwnd_set(tp, (tcp_snd_cwnd(tp) + win_used) >> 1); + } + tp->snd_cwnd_used = 0; +diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c +index 786848ad37ea8..3ec7308441a78 100644 +--- a/net/ipv4/tcp_vegas.c ++++ b/net/ipv4/tcp_vegas.c +@@ -240,7 +240,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) + */ + tcp_snd_cwnd_set(tp, min(tcp_snd_cwnd(tp), + (u32)target_cwnd + 1)); +- tp->snd_ssthresh = tcp_vegas_ssthresh(tp); ++ WRITE_ONCE(tp->snd_ssthresh, ++ tcp_vegas_ssthresh(tp)); + + } else if (tcp_in_slow_start(tp)) { + /* Slow start. */ +@@ -256,8 +257,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) + * we slow down. + */ + tcp_snd_cwnd_set(tp, tcp_snd_cwnd(tp) - 1); +- tp->snd_ssthresh +- = tcp_vegas_ssthresh(tp); ++ WRITE_ONCE(tp->snd_ssthresh, ++ tcp_vegas_ssthresh(tp)); + } else if (diff < alpha) { + /* We don't have enough extra packets + * in the network, so speed up. +@@ -275,7 +276,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) + else if (tcp_snd_cwnd(tp) > tp->snd_cwnd_clamp) + tcp_snd_cwnd_set(tp, tp->snd_cwnd_clamp); + +- tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk)); + } + + /* Wipe the slate clean for the next RTT. */ +diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c +index c6e97141eef25..b5a42adfd6ca1 100644 +--- a/net/ipv4/tcp_westwood.c ++++ b/net/ipv4/tcp_westwood.c +@@ -244,11 +244,11 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event) + + switch (event) { + case CA_EVENT_COMPLETE_CWR: +- tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_westwood_bw_rttmin(sk)); + tcp_snd_cwnd_set(tp, tp->snd_ssthresh); + break; + case CA_EVENT_LOSS: +- tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_westwood_bw_rttmin(sk)); + /* Update RTT_min when next ack arrives */ + w->reset_rtt_min = 1; + break; +diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c +index 18b07ff5d20e6..74a2538e79e06 100644 +--- a/net/ipv4/tcp_yeah.c ++++ b/net/ipv4/tcp_yeah.c +@@ -147,7 +147,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked) + tcp_snd_cwnd_set(tp, max(tcp_snd_cwnd(tp), + yeah->reno_count)); + +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, ++ tcp_snd_cwnd(tp)); + } + + if (yeah->reno_count <= 2) +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-srtt_us.patch b/queue-6.18/tcp-annotate-data-races-around-tp-srtt_us.patch new file mode 100644 index 0000000000..69cfd93925 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-srtt_us.patch @@ -0,0 +1,61 @@ +From 4289b8fbe6da31706cfe92b476b6b90df3cc6077 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:16 +0000 +Subject: tcp: annotate data-races around tp->srtt_us + +From: Eric Dumazet + +[ Upstream commit 290b693ce7c9d48588d88b15a782a3efc6fa036b ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: e8bd8fca6773 ("tcp: add SRTT to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-12-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 5 +++-- + net/ipv4/tcp_input.c | 2 +- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 2e62441515fee..a799329281532 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3605,7 +3605,8 @@ static void tcp_enable_tx_delay(struct sock *sk, int val) + if (delta && sk->sk_state == TCP_ESTABLISHED) { + s64 srtt = (s64)tp->srtt_us + delta; + +- tp->srtt_us = clamp_t(s64, srtt, 1, ~0U); ++ WRITE_ONCE(tp->srtt_us, ++ clamp_t(s64, srtt, 1, ~0U)); + + /* Note: does not deal with non zero icsk_backoff */ + tcp_set_rto(sk); +@@ -4442,7 +4443,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen)); +- nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); ++ nla_put_u32(stats, TCP_NLA_SRTT, READ_ONCE(tp->srtt_us) >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, + max_t(int, 0, tp->write_seq - tp->snd_nxt)); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index e8ba52c908da1..5fb5f3f6393c1 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1099,7 +1099,7 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us) + + tcp_bpf_rtt(sk, mrtt_us, srtt); + } +- tp->srtt_us = max(1U, srtt); ++ WRITE_ONCE(tp->srtt_us, max(1U, srtt)); + } + + void tcp_update_pacing_rate(struct sock *sk) +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-timeout_rehash.patch b/queue-6.18/tcp-annotate-data-races-around-tp-timeout_rehash.patch new file mode 100644 index 0000000000..2bbaecef00 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-timeout_rehash.patch @@ -0,0 +1,52 @@ +From d9fa0cbdb252cf888277369ce86d9a9e4eb8007f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:17 +0000 +Subject: tcp: annotate data-races around tp->timeout_rehash + +From: Eric Dumazet + +[ Upstream commit 71c675358b711bbfd8528949249419dc2dfa4ce1 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 32efcc06d2a1 ("tcp: export count for rehash attempts") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-13-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + net/ipv4/tcp_timer.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index a799329281532..888fe31e42f0b 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4444,7 +4444,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen)); + nla_put_u32(stats, TCP_NLA_SRTT, READ_ONCE(tp->srtt_us) >> 3); +- nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); ++ nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, ++ READ_ONCE(tp->timeout_rehash)); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, + max_t(int, 0, tp->write_seq - tp->snd_nxt)); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, +diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c +index 2dd73a4e8e517..b2e5848b6980a 100644 +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -296,7 +296,7 @@ static int tcp_write_timeout(struct sock *sk) + } + + if (sk_rethink_txhash(sk)) { +- tp->timeout_rehash++; ++ WRITE_ONCE(tp->timeout_rehash, tp->timeout_rehash + 1); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEOUTREHASH); + } + +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch b/queue-6.18/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch new file mode 100644 index 0000000000..31ad439c0a --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch @@ -0,0 +1,40 @@ +From 3234e2a9950fae0933a077d54dd50d9745aa20fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:18 +0000 +Subject: tcp: annotate data-races around (tp->write_seq - tp->snd_nxt) + +From: Eric Dumazet + +[ Upstream commit 3a63b3d160560ef51e43fb4c880a5cde8078053c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() annotations to keep KCSAN happy. + +WRITE_ONCE() annotations are already present. + +Fixes: e08ab0b377a1 ("tcp: add bytes not sent to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-14-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 888fe31e42f0b..fe91675ae5678 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4447,7 +4447,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, + READ_ONCE(tp->timeout_rehash)); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +- max_t(int, 0, tp->write_seq - tp->snd_nxt)); ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt))); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, + TCP_NLA_PAD); + if (ack_skb) +-- +2.53.0 + diff --git a/queue-6.18/tcp-annotate-data-races-in-tcp_get_info_chrono_stats.patch b/queue-6.18/tcp-annotate-data-races-in-tcp_get_info_chrono_stats.patch new file mode 100644 index 0000000000..38a90fa7e2 --- /dev/null +++ b/queue-6.18/tcp-annotate-data-races-in-tcp_get_info_chrono_stats.patch @@ -0,0 +1,81 @@ +From 8f6145e85bac194b5c28bc5ab5ea279d29f10fa0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:06 +0000 +Subject: tcp: annotate data-races in tcp_get_info_chrono_stats() + +From: Eric Dumazet + +[ Upstream commit 267bf3cf9a6f0ffb98b8afd983c1950e835f07c9 ] + +tcp_get_timestamping_opt_stats() does not own the socket lock, +this is intentional. + +It calls tcp_get_info_chrono_stats() while other threads could +change chrono fields in tcp_chrono_set(). + +I do not think we need coherent TCP socket state snapshot +in tcp_get_timestamping_opt_stats(), I chose to only +add annotations to keep KCSAN happy. + +Fixes: 1c885808e456 ("tcp: SOF_TIMESTAMPING_OPT_STATS option for SO_TIMESTAMPING") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 10 +++++++--- + net/ipv4/tcp.c | 14 ++++++++++---- + 2 files changed, 17 insertions(+), 7 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 6805961726dc1..236d9e0d35ed7 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -2129,10 +2129,14 @@ static inline void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new + const u32 now = tcp_jiffies32; + enum tcp_chrono old = tp->chrono_type; + ++ /* Following WRITE_ONCE()s pair with READ_ONCE()s in ++ * tcp_get_info_chrono_stats(). ++ */ + if (old > TCP_CHRONO_UNSPEC) +- tp->chrono_stat[old - 1] += now - tp->chrono_start; +- tp->chrono_start = now; +- tp->chrono_type = new; ++ WRITE_ONCE(tp->chrono_stat[old - 1], ++ tp->chrono_stat[old - 1] + now - tp->chrono_start); ++ WRITE_ONCE(tp->chrono_start, now); ++ WRITE_ONCE(tp->chrono_type, new); + } + + static inline void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type) +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 94e029c70247d..a33641b9ed7e4 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4151,12 +4151,18 @@ static void tcp_get_info_chrono_stats(const struct tcp_sock *tp, + struct tcp_info *info) + { + u64 stats[__TCP_CHRONO_MAX], total = 0; +- enum tcp_chrono i; ++ enum tcp_chrono i, cur; + ++ /* Following READ_ONCE()s pair with WRITE_ONCE()s in tcp_chrono_set(). ++ * This is because socket lock might not be owned by us at this point. ++ * This is best effort, tcp_get_timestamping_opt_stats() can ++ * see wrong values. A real fix would be too costly for TCP fast path. ++ */ ++ cur = READ_ONCE(tp->chrono_type); + for (i = TCP_CHRONO_BUSY; i < __TCP_CHRONO_MAX; ++i) { +- stats[i] = tp->chrono_stat[i - 1]; +- if (i == tp->chrono_type) +- stats[i] += tcp_jiffies32 - tp->chrono_start; ++ stats[i] = READ_ONCE(tp->chrono_stat[i - 1]); ++ if (i == cur) ++ stats[i] += tcp_jiffies32 - READ_ONCE(tp->chrono_start); + stats[i] *= USEC_PER_SEC / HZ; + total += stats[i]; + } +-- +2.53.0 + diff --git a/queue-6.18/tcp-better-handle-tcp_tx_delay-on-established-flows.patch b/queue-6.18/tcp-better-handle-tcp_tx_delay-on-established-flows.patch new file mode 100644 index 0000000000..9e57985812 --- /dev/null +++ b/queue-6.18/tcp-better-handle-tcp_tx_delay-on-established-flows.patch @@ -0,0 +1,127 @@ +From f9638a2a9af66067abcd5b26c28a4b4a01155f53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Oct 2025 14:59:26 +0000 +Subject: tcp: better handle TCP_TX_DELAY on established flows + +From: Eric Dumazet + +[ Upstream commit 1c51450f1afff1e7419797720df3fbd9ccbf610c ] + +Some applications uses TCP_TX_DELAY socket option after TCP flow +is established. + +Some metrics need to be updated, otherwise TCP might take time to +adapt to the new (emulated) RTT. + +This patch adjusts tp->srtt_us, tp->rtt_min, icsk_rto +and sk->sk_pacing_rate. + +This is best effort, and for instance icsk_rto is reset +without taking backoff into account. + +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20251013145926.833198-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 290b693ce7c9 ("tcp: annotate data-races around tp->srtt_us") +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 2 ++ + net/ipv4/tcp.c | 31 +++++++++++++++++++++++++++---- + net/ipv4/tcp_input.c | 4 ++-- + 3 files changed, 31 insertions(+), 6 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 18381f4086d04..cf507b989bff1 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -462,6 +462,8 @@ enum skb_drop_reason tcp_child_process(struct sock *parent, struct sock *child, + void tcp_enter_loss(struct sock *sk); + void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked, int newly_lost, int flag); + void tcp_clear_retrans(struct tcp_sock *tp); ++void tcp_update_pacing_rate(struct sock *sk); ++void tcp_set_rto(struct sock *sk); + void tcp_update_metrics(struct sock *sk); + void tcp_init_metrics(struct sock *sk); + void tcp_metrics_init(void); +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 03299c21e4d68..2e62441515fee 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3585,9 +3585,12 @@ static int tcp_repair_options_est(struct sock *sk, sockptr_t optbuf, + DEFINE_STATIC_KEY_FALSE(tcp_tx_delay_enabled); + EXPORT_IPV6_MOD(tcp_tx_delay_enabled); + +-static void tcp_enable_tx_delay(void) ++static void tcp_enable_tx_delay(struct sock *sk, int val) + { +- if (!static_branch_unlikely(&tcp_tx_delay_enabled)) { ++ struct tcp_sock *tp = tcp_sk(sk); ++ s32 delta = (val - tp->tcp_tx_delay) << 3; ++ ++ if (val && !static_branch_unlikely(&tcp_tx_delay_enabled)) { + static int __tcp_tx_delay_enabled = 0; + + if (cmpxchg(&__tcp_tx_delay_enabled, 0, 1) == 0) { +@@ -3595,6 +3598,22 @@ static void tcp_enable_tx_delay(void) + pr_info("TCP_TX_DELAY enabled\n"); + } + } ++ /* If we change tcp_tx_delay on a live flow, adjust tp->srtt_us, ++ * tp->rtt_min, icsk_rto and sk->sk_pacing_rate. ++ * This is best effort. ++ */ ++ if (delta && sk->sk_state == TCP_ESTABLISHED) { ++ s64 srtt = (s64)tp->srtt_us + delta; ++ ++ tp->srtt_us = clamp_t(s64, srtt, 1, ~0U); ++ ++ /* Note: does not deal with non zero icsk_backoff */ ++ tcp_set_rto(sk); ++ ++ minmax_reset(&tp->rtt_min, tcp_jiffies32, ~0U); ++ ++ tcp_update_pacing_rate(sk); ++ } + } + + /* When set indicates to always queue non-full frames. Later the user clears +@@ -4121,8 +4140,12 @@ int do_tcp_setsockopt(struct sock *sk, int level, int optname, + tp->recvmsg_inq = val; + break; + case TCP_TX_DELAY: +- if (val) +- tcp_enable_tx_delay(); ++ /* tp->srtt_us is u32, and is shifted by 3 */ ++ if (val < 0 || val >= (1U << (31 - 3))) { ++ err = -EINVAL; ++ break; ++ } ++ tcp_enable_tx_delay(sk, val); + WRITE_ONCE(tp->tcp_tx_delay, val); + break; + default: +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 5a944b1ec320c..e8ba52c908da1 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1102,7 +1102,7 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us) + tp->srtt_us = max(1U, srtt); + } + +-static void tcp_update_pacing_rate(struct sock *sk) ++void tcp_update_pacing_rate(struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + u64 rate; +@@ -1139,7 +1139,7 @@ static void tcp_update_pacing_rate(struct sock *sk) + /* Calculate rto without backoff. This is the second half of Van Jacobson's + * routine referred to above. + */ +-static void tcp_set_rto(struct sock *sk) ++void tcp_set_rto(struct sock *sk) + { + const struct tcp_sock *tp = tcp_sk(sk); + /* Old crap is replaced with new one. 8) +-- +2.53.0 + diff --git a/queue-6.18/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch b/queue-6.18/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch new file mode 100644 index 0000000000..45bb522c32 --- /dev/null +++ b/queue-6.18/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch @@ -0,0 +1,54 @@ +From 000148fbbce4b65f39e0da0b35d90432b3a1286b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:53:27 +0000 +Subject: tcp: Don't set treq->req_usec_ts in cookie_tcp_reqsk_init(). + +From: Kuniyuki Iwashima + +[ Upstream commit c058bbf05b1197c33df7204842665bd8bc70b3a8 ] + +Commit de5626b95e13 ("tcp: Factorise cookie-independent fields +initialisation in cookie_v[46]_check().") miscategorised +tcp_rsk(req)->req_usec_ts init to cookie_tcp_reqsk_init(), +which is used by both BPF/non-BPF SYN cookie reqsk. + +Rather, it should have been moved to cookie_tcp_reqsk_alloc() by +commit 8e7bab6b9652 ("tcp: Factorise cookie-dependent fields +initialisation in cookie_v[46]_check()") so that only non-BPF SYN +cookie sets tcp_rsk(req)->req_usec_ts to false. + +Let's move the initialisation to cookie_tcp_reqsk_alloc() to +respect bpf_tcp_req_attrs.usec_ts_ok. + +Fixes: e472f88891ab ("bpf: tcp: Support arbitrary SYN Cookie.") +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260410235328.1773449-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/syncookies.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c +index fc3affd9c8014..b5f0a65c67864 100644 +--- a/net/ipv4/syncookies.c ++++ b/net/ipv4/syncookies.c +@@ -286,7 +286,6 @@ static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb, + treq->rcv_isn = ntohl(th->seq) - 1; + treq->snt_isn = ntohl(th->ack_seq) - 1; + treq->syn_tos = TCP_SKB_CB(skb)->ip_dsfield; +- treq->req_usec_ts = false; + + #if IS_ENABLED(CONFIG_MPTCP) + treq->is_mptcp = sk_is_mptcp(sk); +@@ -349,6 +348,7 @@ struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, + ireq->wscale_ok = tcp_opt->wscale_ok; + ireq->ecn_ok = !!(tcp_opt->rcv_tsecr & TS_OPT_ECN); + ++ treq->req_usec_ts = false; + treq->ts_off = tsoff; + + return req; +-- +2.53.0 + diff --git a/queue-6.18/tcp-inline-tcp_chrono_start.patch b/queue-6.18/tcp-inline-tcp_chrono_start.patch new file mode 100644 index 0000000000..609abd6d1a --- /dev/null +++ b/queue-6.18/tcp-inline-tcp_chrono_start.patch @@ -0,0 +1,111 @@ +From 22683cec13abc928edd2c9461f846cda9e480404 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 12:35:49 +0000 +Subject: tcp: inline tcp_chrono_start() + +From: Eric Dumazet + +[ Upstream commit d6d4ff335db2d9242937ca474d292010acd35c38 ] + +tcp_chrono_start() is small enough, and used in TCP sendmsg() +fast path (from tcp_skb_entail()). + +Note clang is already inlining it from functions in tcp_output.c. + +Inlining it improves performance and reduces bloat : + +$ scripts/bloat-o-meter -t vmlinux.old vmlinux.new +add/remove: 0/2 grow/shrink: 1/0 up/down: 1/-84 (-83) +Function old new delta +tcp_skb_entail 280 281 +1 +__pfx_tcp_chrono_start 16 - -16 +tcp_chrono_start 68 - -68 +Total: Before=25192434, After=25192351, chg -0.00% + +Note that tcp_chrono_stop() is too big. + +Signed-off-by: Eric Dumazet +Reviewed-by: Neal Cardwell +Link: https://patch.msgid.link/20260308123549.2924460-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 267bf3cf9a6f ("tcp: annotate data-races in tcp_get_info_chrono_stats()") +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 25 ++++++++++++++++++++++++- + net/ipv4/tcp_output.c | 24 ------------------------ + 2 files changed, 24 insertions(+), 25 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 7647ed5c732c1..6805961726dc1 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -2124,7 +2124,30 @@ enum tcp_chrono { + __TCP_CHRONO_MAX, + }; + +-void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type); ++static inline void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new) ++{ ++ const u32 now = tcp_jiffies32; ++ enum tcp_chrono old = tp->chrono_type; ++ ++ if (old > TCP_CHRONO_UNSPEC) ++ tp->chrono_stat[old - 1] += now - tp->chrono_start; ++ tp->chrono_start = now; ++ tp->chrono_type = new; ++} ++ ++static inline void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* If there are multiple conditions worthy of tracking in a ++ * chronograph then the highest priority enum takes precedence ++ * over the other conditions. So that if something "more interesting" ++ * starts happening, stop the previous chrono and start a new one. ++ */ ++ if (type > tp->chrono_type) ++ tcp_chrono_set(tp, type); ++} ++ + void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type); + + /* This helper is needed, because skb->tcp_tsorted_anchor uses +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index b94efb3050d2f..b00bd5044b322 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -2813,30 +2813,6 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb, + return false; + } + +-static void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new) +-{ +- const u32 now = tcp_jiffies32; +- enum tcp_chrono old = tp->chrono_type; +- +- if (old > TCP_CHRONO_UNSPEC) +- tp->chrono_stat[old - 1] += now - tp->chrono_start; +- tp->chrono_start = now; +- tp->chrono_type = new; +-} +- +-void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type) +-{ +- struct tcp_sock *tp = tcp_sk(sk); +- +- /* If there are multiple conditions worthy of tracking in a +- * chronograph then the highest priority enum takes precedence +- * over the other conditions. So that if something "more interesting" +- * starts happening, stop the previous chrono and start a new one. +- */ +- if (type > tp->chrono_type) +- tcp_chrono_set(tp, type); +-} +- + void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type) + { + struct tcp_sock *tp = tcp_sk(sk); +-- +2.53.0 + diff --git a/queue-6.18/tcp-make-probe0-timer-handle-expired-user-timeout.patch b/queue-6.18/tcp-make-probe0-timer-handle-expired-user-timeout.patch new file mode 100644 index 0000000000..7bf44acefd --- /dev/null +++ b/queue-6.18/tcp-make-probe0-timer-handle-expired-user-timeout.patch @@ -0,0 +1,58 @@ +From 47eb9e57f9c11e53bd50be45060d4de08924bda5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 18:46:38 -0700 +Subject: tcp: make probe0 timer handle expired user timeout + +From: Altan Hacigumus + +[ Upstream commit 2b9f6f7065d4cfb65ba19126e0b35ac4544c3f3a ] + +tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies +using subtraction with an unsigned lvalue. If elapsed probing time +exceeds the configured TCP_USER_TIMEOUT, the underflow yields a large +value. + +This ends up re-arming the probe timer for a full backoff interval +instead of expiring immediately, delaying connection teardown beyond +the configured timeout. + +Fix this by preventing underflow so user-set timeout expiration is +handled correctly without extending the probe timer. + +Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes") +Link: https://lore.kernel.org/r/20260414013634.43997-1-ahacigu.linux@gmail.com +Signed-off-by: Altan Hacigumus +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260424014639.54110-1-ahacigu.linux@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp_timer.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c +index b2e5848b6980a..1e6d7d90371a9 100644 +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -49,7 +49,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) + u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) + { + const struct inet_connection_sock *icsk = inet_csk(sk); +- u32 remaining, user_timeout; ++ u32 user_timeout; ++ s32 remaining; + s32 elapsed; + + user_timeout = READ_ONCE(icsk->icsk_user_timeout); +@@ -60,7 +61,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) + if (unlikely(elapsed < 0)) + elapsed = 0; + remaining = msecs_to_jiffies(user_timeout) - elapsed; +- remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN); ++ remaining = max_t(int, remaining, TCP_TIMEOUT_MIN); + + return min_t(u32, remaining, when); + } +-- +2.53.0 + diff --git a/queue-6.18/tcp-move-tp-chrono_type-next-tp-chrono_stat.patch b/queue-6.18/tcp-move-tp-chrono_type-next-tp-chrono_stat.patch new file mode 100644 index 0000000000..57d7871301 --- /dev/null +++ b/queue-6.18/tcp-move-tp-chrono_type-next-tp-chrono_stat.patch @@ -0,0 +1,56 @@ +From 75acd8b950c8230425da255a022029d04eea9ef2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 12:23:02 +0000 +Subject: tcp: move tp->chrono_type next tp->chrono_stat[] + +From: Eric Dumazet + +[ Upstream commit 4b78c9cbd8f1fbb9517aee48b372646f4cf05442 ] + +chrono_type is currently in tcp_sock_read_txrx group, which +is supposed to hold read-mostly fields. + +But chrono_type is mostly written in tx path, it should +be moved to tcp_sock_write_tx group, close to other +chrono fields (chrono_stat[], chrono_start). + +Note this adds holes, but data locality is far more important. + +Use a full u8 for the time being, compiler can generate +more efficient code. + +Signed-off-by: Eric Dumazet +Reviewed-by: Neal Cardwell +Link: https://patch.msgid.link/20260308122302.2895067-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 267bf3cf9a6f ("tcp: annotate data-races in tcp_get_info_chrono_stats()") +Signed-off-by: Sasha Levin +--- + include/linux/tcp.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/tcp.h b/include/linux/tcp.h +index 20b8c6e21fef3..8e1266cf8ef69 100644 +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -231,8 +231,7 @@ struct tcp_sock { + u32 sacked_out; /* SACK'd packets */ + u16 tcp_header_len; /* Bytes of tcp header to send */ + u8 scaling_ratio; /* see tcp_win_from_space() */ +- u8 chrono_type : 2, /* current chronograph type */ +- repair : 1, ++ u8 repair : 1, + tcp_usec_ts : 1, /* TSval values in usec */ + is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ + is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */ +@@ -267,6 +266,7 @@ struct tcp_sock { + * total number of data bytes sent. + */ + u32 snd_sml; /* Last byte of the most recently transmitted small packet */ ++ u8 chrono_type; /* current chronograph type */ + u32 chrono_start; /* Start time in jiffies of a TCP chrono */ + u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ + u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ +-- +2.53.0 + diff --git a/queue-6.18/tcp-send-a-challenge-ack-on-seg.ack-snd.nxt.patch b/queue-6.18/tcp-send-a-challenge-ack-on-seg.ack-snd.nxt.patch new file mode 100644 index 0000000000..9cb25c4ba2 --- /dev/null +++ b/queue-6.18/tcp-send-a-challenge-ack-on-seg.ack-snd.nxt.patch @@ -0,0 +1,87 @@ +From 4503d620e8f1e6c53b1dec61289af8f6eac9deb8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 20:35:38 +0800 +Subject: tcp: send a challenge ACK on SEG.ACK > SND.NXT + +From: Jiayuan Chen + +[ Upstream commit 42726ec644cbdde0035c3e0417fee8ed9547e120 ] + +RFC 5961 Section 5.2 validates an incoming segment's ACK value +against the range [SND.UNA - MAX.SND.WND, SND.NXT] and states: + + "All incoming segments whose ACK value doesn't satisfy the above + condition MUST be discarded and an ACK sent back." + +Commit 354e4aa391ed ("tcp: RFC 5961 5.2 Blind Data Injection Attack +Mitigation") opted Linux into this mitigation and implements the +challenge ACK on the lower side (SEG.ACK < SND.UNA - MAX.SND.WND), +but the symmetric upper side (SEG.ACK > SND.NXT) still takes the +pre-RFC-5961 path and silently returns +SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, even though RFC 793 Section 3.9 +(now RFC 9293 Section 3.10.7.4) has always required: + + "If the ACK acknowledges something not yet sent (SEG.ACK > SND.NXT) + then send an ACK, drop the segment, and return." + +Complete the mitigation by sending a challenge ACK on that branch, +reusing the existing tcp_send_challenge_ack() path which already +enforces the per-socket RFC 5961 Section 7 rate limit via +__tcp_oow_rate_limited(). FLAG_NO_CHALLENGE_ACK is honoured for +symmetry with the lower-edge case. + +Update the existing tcp_ts_recent_invalid_ack.pkt selftest, which +drives this exact path, to consume the new challenge ACK. + +Fixes: 354e4aa391ed ("tcp: RFC 5961 5.2 Blind Data Injection Attack Mitigation") +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260422123605.320000-2-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp_input.c | 10 +++++++--- + .../net/packetdrill/tcp_ts_recent_invalid_ack.pkt | 4 +++- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 5fb5f3f6393c1..b5cf32a56c04a 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -4025,11 +4025,15 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + goto old_ack; + } + +- /* If the ack includes data we haven't sent yet, discard +- * this segment (RFC793 Section 3.9). ++ /* If the ack includes data we haven't sent yet, drop the ++ * segment. RFC 793 Section 3.9 and RFC 5961 Section 5.2 ++ * require us to send an ACK back in that case. + */ +- if (after(ack, tp->snd_nxt)) ++ if (after(ack, tp->snd_nxt)) { ++ if (!(flag & FLAG_NO_CHALLENGE_ACK)) ++ tcp_send_challenge_ack(sk, false); + return -SKB_DROP_REASON_TCP_ACK_UNSENT_DATA; ++ } + + if (after(ack, prior_snd_una)) { + flag |= FLAG_SND_UNA_ADVANCED; +diff --git a/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt b/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt +index 174ce9a1bfc07..ee6baf7c36cfa 100644 +--- a/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt ++++ b/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt +@@ -19,7 +19,9 @@ + + // bad packet with high tsval (its ACK sequence is above our sndnxt) + +0 < F. 1:1(0) ack 9999 win 20000 +- ++// Challenge ACK for SEG.ACK > SND.NXT (RFC 5961 5.2 / RFC 793 3.9). ++// ecr=200 (not 200000) proves ts_recent was not updated from the bad packet. ++ +0 > . 1:1(0) ack 1 + + +0 < . 1:1001(1000) ack 1 win 20000 + +0 > . 1:1(0) ack 1001 +-- +2.53.0 + diff --git a/queue-6.18/thermal-drivers-spear-fix-error-condition-for-readin.patch b/queue-6.18/thermal-drivers-spear-fix-error-condition-for-readin.patch new file mode 100644 index 0000000000..716882449a --- /dev/null +++ b/queue-6.18/thermal-drivers-spear-fix-error-condition-for-readin.patch @@ -0,0 +1,42 @@ +From ca51965132c3f9e61348023c455b63b118ae83ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:35:24 +0530 +Subject: thermal/drivers/spear: Fix error condition for reading + st,thermal-flags + +From: Gopi Krishna Menon + +[ Upstream commit da2c4f332a0504d9c284e7626a561d343c8d6f57 ] + +of_property_read_u32 returns 0 on success. The current check returns +-EINVAL if the property is read successfully. + +Fix the check by removing ! from of_property_read_u32 + +Fixes: b9c7aff481f1 ("drivers/thermal/spear_thermal.c: add Device Tree probing capability") +Signed-off-by: Gopi Krishna Menon +Signed-off-by: Daniel Lezcano +Suggested-by: Daniel Baluta +Reviewed-by: Lukasz Luba +Link: https://patch.msgid.link/20260327090526.59330-1-krishnagopi487@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/thermal/spear_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c +index 603dadcd3df58..5e3e9c1f32f8e 100644 +--- a/drivers/thermal/spear_thermal.c ++++ b/drivers/thermal/spear_thermal.c +@@ -93,7 +93,7 @@ static int spear_thermal_probe(struct platform_device *pdev) + struct device_node *np = pdev->dev.of_node; + int ret = 0, val; + +- if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) { ++ if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) { + dev_err(&pdev->dev, "Failed: DT Pdata not passed\n"); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.18/tipc-fix-double-free-in-tipc_buf_append.patch b/queue-6.18/tipc-fix-double-free-in-tipc_buf_append.patch new file mode 100644 index 0000000000..63f6dc0d15 --- /dev/null +++ b/queue-6.18/tipc-fix-double-free-in-tipc_buf_append.patch @@ -0,0 +1,60 @@ +From fc95e80b6cfc8277bb1242f390a9db48759847d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 13:45:26 +0100 +Subject: tipc: fix double-free in tipc_buf_append() + +From: Lee Jones + +[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ] + +tipc_msg_validate() can potentially reallocate the skb it is validating, +freeing the old one. In tipc_buf_append(), it was being called with a +pointer to a local variable which was a copy of the caller's skb +pointer. + +If the skb was reallocated and validation subsequently failed, the error +handling path would free the original skb pointer, which had already +been freed, leading to double-free. + +Fix this by checking if head now points to a newly allocated reassembled +skb. If it does, reassign *headbuf for later freeing operations. + +Fixes: d618d09a68e4 ("tipc: enforce valid ratio between skb truesize and contents") +Suggested-by: Tung Nguyen +Signed-off-by: Lee Jones +Reviewed-by: Tung Nguyen +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/msg.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/net/tipc/msg.c b/net/tipc/msg.c +index 76284fc538ebd..b0bba0feef564 100644 +--- a/net/tipc/msg.c ++++ b/net/tipc/msg.c +@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) + + if (fragid == LAST_FRAGMENT) { + TIPC_SKB_CB(head)->validated = 0; +- if (unlikely(!tipc_msg_validate(&head))) ++ ++ /* If the reassembled skb has been freed in ++ * tipc_msg_validate() because of an invalid truesize, ++ * then head will point to a newly allocated reassembled ++ * skb, while *headbuf points to freed reassembled skb. ++ * In such cases, correct *headbuf for freeing the newly ++ * allocated reassembled skb later. ++ */ ++ if (unlikely(!tipc_msg_validate(&head))) { ++ if (head != *headbuf) ++ *headbuf = head; + goto err; ++ } ++ + *buf = head; + TIPC_SKB_CB(head)->tail = NULL; + *headbuf = NULL; +-- +2.53.0 + diff --git a/queue-6.18/tools-nolibc-implement-m-if-errno-is-not-defined.patch b/queue-6.18/tools-nolibc-implement-m-if-errno-is-not-defined.patch new file mode 100644 index 0000000000..e0b353cb0e --- /dev/null +++ b/queue-6.18/tools-nolibc-implement-m-if-errno-is-not-defined.patch @@ -0,0 +1,46 @@ +From f46c71bd2456b3e479fde927ee877868c21dd508 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Sep 2025 16:20:52 +0200 +Subject: tools/nolibc: implement %m if errno is not defined +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Benjamin Berg + +[ Upstream commit fbd1b7f6b322a63b21ebbf00c732a17bb8bdb5d4 ] + +For improved compatibility, print %m as "unknown error" when nolibc is +compiled using NOLIBC_IGNORE_ERRNO. + +Signed-off-by: Benjamin Berg +Signed-off-by: Thomas Weißschuh +Stable-dep-of: 4045e7b19bbf ("tools/nolibc/printf: Move snprintf length check to callback") +Signed-off-by: Sasha Levin +--- + tools/include/nolibc/stdio.h | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h +index 724d05ce69624..1f16dab2ac884 100644 +--- a/tools/include/nolibc/stdio.h ++++ b/tools/include/nolibc/stdio.h +@@ -321,11 +321,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + if (!outstr) + outstr="(null)"; + } +-#ifndef NOLIBC_IGNORE_ERRNO + else if (c == 'm') { ++#ifdef NOLIBC_IGNORE_ERRNO ++ outstr = "unknown error"; ++#else + outstr = strerror(errno); +- } + #endif /* NOLIBC_IGNORE_ERRNO */ ++ } + else if (c == '%') { + /* queue it verbatim */ + continue; +-- +2.53.0 + diff --git a/queue-6.18/tools-nolibc-printf-change-variables-c-to-ch-and-tmp.patch b/queue-6.18/tools-nolibc-printf-change-variables-c-to-ch-and-tmp.patch new file mode 100644 index 0000000000..9a297aca76 --- /dev/null +++ b/queue-6.18/tools-nolibc-printf-change-variables-c-to-ch-and-tmp.patch @@ -0,0 +1,155 @@ +From 41895b80b4679af2e68cde044eb4fdfdfe483265 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 10:17:24 +0000 +Subject: tools/nolibc/printf: Change variables 'c' to 'ch' and 'tmpbuf[]' to + 'outbuf[]' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: David Laight + +[ Upstream commit f675ae28fcdf7db93a8c1a6964f062725b1e06a0 ] + +Changing 'c' makes the code slightly easier to read because the variable +stands out from the single character literals (especially 'c'). + +Change tmpbuf[] to outbuf[] because 'out' points into it. + +The following patches pretty much rewrite the function so the +churn is limited. + +Signed-off-by: David Laight +Acked-by: Willy Tarreau +Link: https://patch.msgid.link/20260223101735.2922-7-david.laight.linux@gmail.com +Signed-off-by: Thomas Weißschuh +Stable-dep-of: 4045e7b19bbf ("tools/nolibc/printf: Move snprintf length check to callback") +Signed-off-by: Sasha Levin +--- + tools/include/nolibc/stdio.h | 38 ++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h +index 1f16dab2ac884..aff11d6069f6f 100644 +--- a/tools/include/nolibc/stdio.h ++++ b/tools/include/nolibc/stdio.h +@@ -250,16 +250,16 @@ typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size); + static __attribute__((unused, format(printf, 4, 0))) + int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args) + { +- char escape, lpref, c; ++ char escape, lpref, ch; + unsigned long long v; + unsigned int written, width; + size_t len, ofs, w; +- char tmpbuf[21]; ++ char outbuf[21]; + const char *outstr; + + written = ofs = escape = lpref = 0; + while (1) { +- c = fmt[ofs++]; ++ ch = fmt[ofs++]; + width = 0; + + if (escape) { +@@ -267,17 +267,17 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + escape = 0; + + /* width */ +- while (c >= '0' && c <= '9') { ++ while (ch >= '0' && ch <= '9') { + width *= 10; +- width += c - '0'; ++ width += ch - '0'; + +- c = fmt[ofs++]; ++ ch = fmt[ofs++]; + } + +- if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') { +- char *out = tmpbuf; ++ if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') { ++ char *out = outbuf; + +- if (c == 'p') ++ if (ch == 'p') + v = va_arg(args, unsigned long); + else if (lpref) { + if (lpref > 1) +@@ -287,7 +287,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + } else + v = va_arg(args, unsigned int); + +- if (c == 'd') { ++ if (ch == 'd') { + /* sign-extend the value */ + if (lpref == 0) + v = (long long)(int)v; +@@ -295,7 +295,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + v = (long long)(long)v; + } + +- switch (c) { ++ switch (ch) { + case 'c': + out[0] = v; + out[1] = 0; +@@ -314,30 +314,30 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + u64toh_r(v, out); + break; + } +- outstr = tmpbuf; ++ outstr = outbuf; + } +- else if (c == 's') { ++ else if (ch == 's') { + outstr = va_arg(args, char *); + if (!outstr) + outstr="(null)"; + } +- else if (c == 'm') { ++ else if (ch == 'm') { + #ifdef NOLIBC_IGNORE_ERRNO + outstr = "unknown error"; + #else + outstr = strerror(errno); + #endif /* NOLIBC_IGNORE_ERRNO */ + } +- else if (c == '%') { ++ else if (ch == '%') { + /* queue it verbatim */ + continue; + } + else { + /* modifiers or final 0 */ +- if (c == 'l') { ++ if (ch == 'l') { + /* long format prefix, maintain the escape */ + lpref++; +- } else if (c == 'j') { ++ } else if (ch == 'j') { + lpref = 2; + } + escape = 1; +@@ -348,7 +348,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + } + + /* not an escape sequence */ +- if (c == 0 || c == '%') { ++ if (ch == 0 || ch == '%') { + /* flush pending data on escape or end */ + escape = 1; + lpref = 0; +@@ -369,7 +369,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + + written += len; + do_escape: +- if (c == 0) ++ if (ch == 0) + break; + fmt += ofs; + ofs = 0; +-- +2.53.0 + diff --git a/queue-6.18/tools-nolibc-printf-move-snprintf-length-check-to-ca.patch b/queue-6.18/tools-nolibc-printf-move-snprintf-length-check-to-ca.patch new file mode 100644 index 0000000000..54f15ac4c2 --- /dev/null +++ b/queue-6.18/tools-nolibc-printf-move-snprintf-length-check-to-ca.patch @@ -0,0 +1,184 @@ +From b89a3cecf50da55977b85451701b3f72837eecb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 10:17:54 +0000 +Subject: tools/nolibc/printf: Move snprintf length check to callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: David Laight + +[ Upstream commit 4045e7b19bbf7338452cda11e64cfe7ae3361964 ] + +Move output truncation to the snprintf() callback. +This simplifies the main code and fixes truncation of padded fields. + +Add a zero length callback to 'finalise' the buffer rather than +doing it in snprintf() itself. + +Fixes: e90ce42e81381 ("tools/nolibc: implement width padding in printf()") +Signed-off-by: David Laight +Acked-by: Willy Tarreau +Link: https://patch.msgid.link/20260302101815.3043-3-david.laight.linux@gmail.com +[Thomas: clean up Fixes trailer] +Signed-off-by: Thomas Weißschuh +Signed-off-by: Sasha Levin +--- + tools/include/nolibc/stdio.h | 94 +++++++++++++++++++++++++----------- + 1 file changed, 67 insertions(+), 27 deletions(-) + +diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h +index aff11d6069f6f..a2fc7c8706dfa 100644 +--- a/tools/include/nolibc/stdio.h ++++ b/tools/include/nolibc/stdio.h +@@ -244,16 +244,25 @@ char *fgets(char *s, int size, FILE *stream) + * - %[l*]{d,u,c,x,p} + * - %s + * - unknown modifiers are ignored. ++ * ++ * Called by vfprintf() and snprintf() to do the actual formatting. ++ * The callers provide a callback function to save the formatted data. ++ * The callback function is called multiple times: ++ * - for each group of literal characters in the format string. ++ * - for field padding. ++ * - for each conversion specifier. ++ * - with (NULL, 0) at the end of the __nolibc_printf. ++ * If the callback returns non-zero __nolibc_printf() immediately returns -1. + */ +-typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size); ++typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size); + +-static __attribute__((unused, format(printf, 4, 0))) +-int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args) ++static __attribute__((unused, format(printf, 3, 0))) ++int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args) + { + char escape, lpref, ch; + unsigned long long v; + unsigned int written, width; +- size_t len, ofs, w; ++ size_t len, ofs; + char outbuf[21]; + const char *outstr; + +@@ -355,17 +364,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + outstr = fmt; + len = ofs - 1; + flush_str: +- if (n) { +- w = len < n ? len : n; +- n -= w; +- while (width-- > w) { +- if (cb(state, " ", 1) != 0) +- return -1; +- written += 1; +- } +- if (cb(state, outstr, w) != 0) ++ while (width-- > len) { ++ if (cb(state, " ", 1) != 0) + return -1; ++ written += 1; + } ++ if (cb(state, outstr, len) != 0) ++ return -1; + + written += len; + do_escape: +@@ -378,18 +383,25 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + + /* literal char, just queue it */ + } ++ ++ /* Request a final '\0' be added to the snprintf() output. ++ * This may be the only call of the cb() function. ++ */ ++ if (cb(state, NULL, 0) != 0) ++ return -1; ++ + return written; + } + +-static int __nolibc_fprintf_cb(intptr_t state, const char *buf, size_t size) ++static int __nolibc_fprintf_cb(void *stream, const char *buf, size_t size) + { +- return _fwrite(buf, size, (FILE *)state); ++ return _fwrite(buf, size, stream); + } + + static __attribute__((unused, format(printf, 2, 0))) + int vfprintf(FILE *stream, const char *fmt, va_list args) + { +- return __nolibc_printf(__nolibc_fprintf_cb, (intptr_t)stream, SIZE_MAX, fmt, args); ++ return __nolibc_printf(__nolibc_fprintf_cb, stream, fmt, args); + } + + static __attribute__((unused, format(printf, 1, 0))) +@@ -447,26 +459,54 @@ int dprintf(int fd, const char *fmt, ...) + return ret; + } + +-static int __nolibc_sprintf_cb(intptr_t _state, const char *buf, size_t size) ++struct __nolibc_sprintf_cb_state { ++ char *buf; ++ size_t space; ++}; ++ ++static int __nolibc_sprintf_cb(void *v_state, const char *buf, size_t size) + { +- char **state = (char **)_state; ++ struct __nolibc_sprintf_cb_state *state = v_state; ++ size_t space = state->space; ++ char *tgt; ++ ++ /* Truncate the request to fit in the output buffer space. ++ * The last byte is reserved for the terminating '\0'. ++ * state->space can only be zero for snprintf(NULL, 0, fmt, args) ++ * so this normally lets through calls with 'size == 0'. ++ */ ++ if (size >= space) { ++ if (space <= 1) ++ return 0; ++ size = space - 1; ++ } ++ tgt = state->buf; ++ ++ /* __nolibc_printf() ends with cb(state, NULL, 0) to request the output ++ * buffer be '\0' terminated. ++ * That will be the only cb() call for, eg, snprintf(buf, sz, ""). ++ * Zero lengths can occur at other times (eg "%s" for an empty string). ++ * Unconditionally write the '\0' byte to reduce code size, it is ++ * normally overwritten by the data being output. ++ * There is no point adding a '\0' after copied data - there is always ++ * another call. ++ */ ++ *tgt = '\0'; ++ if (size) { ++ state->space = space - size; ++ state->buf = tgt + size; ++ memcpy(tgt, buf, size); ++ } + +- memcpy(*state, buf, size); +- *state += size; + return 0; + } + + static __attribute__((unused, format(printf, 3, 0))) + int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) + { +- char *state = buf; +- int ret; ++ struct __nolibc_sprintf_cb_state state = { .buf = buf, .space = size }; + +- ret = __nolibc_printf(__nolibc_sprintf_cb, (intptr_t)&state, size, fmt, args); +- if (ret < 0) +- return ret; +- buf[(size_t)ret < size ? (size_t)ret : size - 1] = '\0'; +- return ret; ++ return __nolibc_printf(__nolibc_sprintf_cb, &state, fmt, args); + } + + static __attribute__((unused, format(printf, 3, 4))) +-- +2.53.0 + diff --git a/queue-6.18/tools-power-turbostat-fix-and-document-header_iterat.patch b/queue-6.18/tools-power-turbostat-fix-and-document-header_iterat.patch new file mode 100644 index 0000000000..8d584b15d8 --- /dev/null +++ b/queue-6.18/tools-power-turbostat-fix-and-document-header_iterat.patch @@ -0,0 +1,122 @@ +From 566aca111e56cdc72366fb9826642cb846d82cf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 13:26:12 -0600 +Subject: tools/power turbostat: Fix and document --header_iterations + +From: Len Brown + +[ Upstream commit 96718ad296af4a6d984b3a09276b165ab6a3b0c8 ] + +The "header_iterations" option is commonly used to de-clutter +the screen of redundant header label rows in an interactive session: +Eg. every 10 rows: + +$ sudo turbostat --header_iterations 10 -S -q -i 1 + +But --header_iterations was missing from turbostat.8 + +Also turbostat help advertised the "-N" short option +that did not actually work: + +$ turbostat --help + -N, --header_iterations num + print header every num iterations + +Repair "-N" +Document "--header_iterations" on turbostat.8 + +Signed-off-by: Len Brown +Stable-dep-of: ce012c966b51 ("tools/power turbostat: Fix unrecognized option '-P'") +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.8 | 4 +++- + tools/power/x86/turbostat/turbostat.c | 20 +++++++++----------- + 2 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 +index 6c9428f98cd2b..3e0487cd6451e 100644 +--- a/tools/power/x86/turbostat/turbostat.8 ++++ b/tools/power/x86/turbostat/turbostat.8 +@@ -111,12 +111,14 @@ The column name "all" can be used to enable all disabled-by-default built-in cou + .PP + \fB--no-perf\fP Disable all the uses of the perf API. + .PP +-\fB--force\fPForce turbostat to run on an unsupported platform (minimal defaults). ++\fB--force\fP Force turbostat to run on an unsupported platform (minimal defaults). + .PP + \fB--interval seconds\fP overrides the default 5.0 second measurement interval. + .PP + \fB--num_iterations num\fP number of the measurement iterations. + .PP ++\fB--header_iterations num\fP print header every num iterations. ++.PP + \fB--out output_file\fP turbostat output is written to the specified output_file. + The file is truncated if it already exists, and it is created if it does not exist. + .PP +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index 29441e3c711d9..ec4b7ff8810b1 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -11040,7 +11040,7 @@ void cmdline(int argc, char **argv) + * Parse some options early, because they may make other options invalid, + * like adding the MSR counter with --add and at the same time using --no-msr. + */ +- while ((opt = getopt_long_only(argc, argv, "+MPn:", long_options, &option_index)) != -1) { ++ while ((opt = getopt_long_only(argc, argv, "+:MP", long_options, &option_index)) != -1) { + switch (opt) { + case 'M': + no_msr = 1; +@@ -11054,7 +11054,7 @@ void cmdline(int argc, char **argv) + } + optind = 0; + +- while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:o:qMST:v", long_options, &option_index)) != -1) { ++ while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMST:v", long_options, &option_index)) != -1) { + switch (opt) { + case 'a': + parse_add_command(optarg); +@@ -11097,7 +11097,6 @@ void cmdline(int argc, char **argv) + } + break; + case 'h': +- default: + help(); + exit(1); + case 'i': +@@ -11136,19 +11135,15 @@ void cmdline(int argc, char **argv) + num_iterations = strtoul(optarg, NULL, 0); + errno = 0; + +- if (errno || num_iterations == 0) { +- fprintf(outf, "invalid iteration count: %s\n", optarg); +- exit(2); +- } ++ if (errno || num_iterations == 0) ++ errx(-1, "invalid iteration count: %s", optarg); + break; + case 'N': + header_iterations = strtoul(optarg, NULL, 0); + errno = 0; + +- if (errno || header_iterations == 0) { +- fprintf(outf, "invalid header iteration count: %s\n", optarg); +- exit(2); +- } ++ if (errno || header_iterations == 0) ++ errx(-1, "invalid header iteration count: %s", optarg); + break; + case 's': + /* +@@ -11171,6 +11166,9 @@ void cmdline(int argc, char **argv) + print_version(); + exit(0); + break; ++ default: ++ help(); ++ exit(1); + } + } + } +-- +2.53.0 + diff --git a/queue-6.18/tools-power-turbostat-fix-unrecognized-option-p.patch b/queue-6.18/tools-power-turbostat-fix-unrecognized-option-p.patch new file mode 100644 index 0000000000..e9953107a2 --- /dev/null +++ b/queue-6.18/tools-power-turbostat-fix-unrecognized-option-p.patch @@ -0,0 +1,41 @@ +From d402749d98e0be3ea45791b1ec27f4cab650e4b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 10:32:17 -0400 +Subject: tools/power turbostat: Fix unrecognized option '-P' + +From: David Arcari + +[ Upstream commit ce012c966b518c53475ba9a4e979242d7322d819 ] + +The '-P' short option (shorthand for --no-perf) is not present in the +optstring of the second call to getopt_long_only(). This results in +the "unrecognized option" error when the tool reaches the main parsing +loop. + +Add 'P' to the second getopt_long_only() call to ensure it is +consistently recognized. + +Fixes: a0e86c90b83c ("tools/power turbostat: Add --no-perf option") +Signed-off-by: David Arcari +Signed-off-by: Len Brown +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index ec4b7ff8810b1..313872f64a9a9 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -11054,7 +11054,7 @@ void cmdline(int argc, char **argv) + } + optind = 0; + +- while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMST:v", long_options, &option_index)) != -1) { ++ while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMPST:v", long_options, &option_index)) != -1) { + switch (opt) { + case 'a': + parse_add_command(optarg); +-- +2.53.0 + diff --git a/queue-6.18/tools-power-turbostat-use-strtoul-for-iteration-pars.patch b/queue-6.18/tools-power-turbostat-use-strtoul-for-iteration-pars.patch new file mode 100644 index 0000000000..587b65d9b0 --- /dev/null +++ b/queue-6.18/tools-power-turbostat-use-strtoul-for-iteration-pars.patch @@ -0,0 +1,56 @@ +From a6e63c78c7de84d110f3b5d0f1c0f236742d7665 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 08:38:04 +0530 +Subject: tools/power turbostat: Use strtoul() for iteration parsing + +From: Kaushlendra Kumar + +[ Upstream commit 8e5c0cc326f2e95a71bb6e6063e65caa60c8f951 ] + +Replace strtod() with strtoul() and check errno for -n/-N options, since +num_iterations and header_iterations are unsigned long counters. Reject +zero and conversion errors; negative inputs wrap to large positive values +per standard unsigned semantics. + +Signed-off-by: Kaushlendra Kumar +Signed-off-by: Len Brown +Stable-dep-of: ce012c966b51 ("tools/power turbostat: Fix unrecognized option '-P'") +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index 48677f1846347..29441e3c711d9 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -11133,18 +11133,20 @@ void cmdline(int argc, char **argv) + /* Parsed earlier */ + break; + case 'n': +- num_iterations = strtod(optarg, NULL); ++ num_iterations = strtoul(optarg, NULL, 0); ++ errno = 0; + +- if (num_iterations <= 0) { +- fprintf(outf, "iterations %d should be positive number\n", num_iterations); ++ if (errno || num_iterations == 0) { ++ fprintf(outf, "invalid iteration count: %s\n", optarg); + exit(2); + } + break; + case 'N': +- header_iterations = strtod(optarg, NULL); ++ header_iterations = strtoul(optarg, NULL, 0); ++ errno = 0; + +- if (header_iterations <= 0) { +- fprintf(outf, "iterations %d should be positive number\n", header_iterations); ++ if (errno || header_iterations == 0) { ++ fprintf(outf, "invalid header iteration count: %s\n", optarg); + exit(2); + } + break; +-- +2.53.0 + diff --git a/queue-6.18/tools-power-turbostat.8-document-the-force-option.patch b/queue-6.18/tools-power-turbostat.8-document-the-force-option.patch new file mode 100644 index 0000000000..c0e6cfc3eb --- /dev/null +++ b/queue-6.18/tools-power-turbostat.8-document-the-force-option.patch @@ -0,0 +1,71 @@ +From cb5b398f0b72d1358d12467a0044b1726d2cd94e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 13:33:29 -0500 +Subject: tools/power turbostat.8: Document the "--force" option + +From: Len Brown + +[ Upstream commit 785953cf6e63aa5a9fcdfa9577b1411e0281c4bc ] + +Starting in turbostat v2025.01.14, turbostat refused to run +on unsupported hardware, pointing to "RUN THE LATEST VERSION" +on turbostat(8). + +At that time, turbostat supported and advertised the "--force" +parameter to run anyway (with unsupported results). + +Also document "--force" on turbostat.8. + +Signed-off-by: Len Brown +Stable-dep-of: ce012c966b51 ("tools/power turbostat: Fix unrecognized option '-P'") +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.8 | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 +index 3340def58d015..6c9428f98cd2b 100644 +--- a/tools/power/x86/turbostat/turbostat.8 ++++ b/tools/power/x86/turbostat/turbostat.8 +@@ -111,6 +111,8 @@ The column name "all" can be used to enable all disabled-by-default built-in cou + .PP + \fB--no-perf\fP Disable all the uses of the perf API. + .PP ++\fB--force\fPForce turbostat to run on an unsupported platform (minimal defaults). ++.PP + \fB--interval seconds\fP overrides the default 5.0 second measurement interval. + .PP + \fB--num_iterations num\fP number of the measurement iterations. +@@ -161,9 +163,9 @@ The system configuration dump (if --quiet is not used) is followed by statistics + .PP + \fBC1, C2, C3...\fP The number times Linux requested the C1, C2, C3 idle state during the measurement interval. The system summary line shows the sum for all CPUs. These are C-state names as exported in /sys/devices/system/cpu/cpu*/cpuidle/state*/name. While their names are generic, their attributes are processor specific. They the system description section of output shows what MWAIT sub-states they are mapped to on each system. These counters are in the "cpuidle" group, which is disabled, by default. + .PP +-\fBC1+, C2+, C3+...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a deeper idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/below file. These counters are in the "cpuidle" group, which is disabled, by default. ++\fBC1+, C2+, C3+...\fP The idle governor idle state misprediction statistics. Indicates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a deeper idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/below file. These counters are in the "cpuidle" group, which is disabled, by default. + .PP +-\fBC1-, C2-, C3-...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a shallower idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/above file. These counters are in the "cpuidle" group, which is disabled, by default. ++\fBC1-, C2-, C3-...\fP The idle governor idle state misprediction statistics. Indicates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a shallower idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/above file. These counters are in the "cpuidle" group, which is disabled, by default. + .PP + \fBC1%, C2%, C3%\fP The residency percentage that Linux requested C1, C2, C3.... The system summary is the average of all CPUs in the system. Note that these are software, reflecting what was requested. The hardware counters reflect what was actually achieved. These counters are in the "pct_idle" group, which is enabled by default. + .PP +@@ -193,7 +195,7 @@ The system configuration dump (if --quiet is not used) is followed by statistics + .PP + \fBGFX%C0\fP Percentage of time that at least one GFX compute engine is busy. + .PP +-\fBCPUGFX%\fP Percentage of time that at least one CPU is busy at the same time as at least one Graphics compute enginer is busy. ++\fBCPUGFX%\fP Percentage of time that at least one CPU is busy at the same time as at least one Graphics compute engine is busy. + .PP + \fBPkg%pc2, Pkg%pc3, Pkg%pc6, Pkg%pc7\fP percentage residency in hardware package idle states. These numbers are from hardware residency counters. + .PP +@@ -556,6 +558,8 @@ If the upstream version isn't new enough, the development tree can be found here + If the development tree doesn't work, please contact the author via chat, + or via email with the word "turbostat" on the Subject line. + ++An old turbostat binary may run on unknown hardware by using "--force", ++but results are unsupported. + .SH FILES + .ta + .nf +-- +2.53.0 + diff --git a/queue-6.18/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch b/queue-6.18/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch new file mode 100644 index 0000000000..3b7a9b5c3f --- /dev/null +++ b/queue-6.18/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch @@ -0,0 +1,69 @@ +From d9a2809dcd31d464a184ecb7adc7ca64b8261438 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 06:25:09 -0700 +Subject: tracing: branch: Fix inverted check on stat tracer registration + +From: Breno Leitao + +[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ] + +init_annotated_branch_stats() and all_annotated_branch_stats() check the +return value of register_stat_tracer() with "if (!ret)", but +register_stat_tracer() returns 0 on success and a negative errno on +failure. The inverted check causes the warning to be printed on every +successful registration, e.g.: + + Warning: could not register annotated branches stats + +while leaving real failures silent. The initcall also returned a +hard-coded 1 instead of the actual error. + +Invert the check and propagate ret so that the warning fires on real +errors and the initcall reports the correct status. + +Cc: Mathieu Desnoyers +Cc: Ingo Molnar +Cc: Frederic Weisbecker +Link: https://patch.msgid.link/20260420-tracing-v1-1-d8f4cd0d6af1@debian.org +Fixes: 002bb86d8d42 ("tracing/ftrace: separate events tracing and stats tracing engine") +Signed-off-by: Breno Leitao +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_branch.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c +index 6809b370e991d..d1564db95a8f5 100644 +--- a/kernel/trace/trace_branch.c ++++ b/kernel/trace/trace_branch.c +@@ -373,10 +373,10 @@ __init static int init_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&annotated_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "annotated branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +@@ -438,10 +438,10 @@ __init static int all_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&all_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "all branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/tracing-fprobe-optimization-for-entry-only-case.patch b/queue-6.18/tracing-fprobe-optimization-for-entry-only-case.patch new file mode 100644 index 0000000000..f30eae7f3a --- /dev/null +++ b/queue-6.18/tracing-fprobe-optimization-for-entry-only-case.patch @@ -0,0 +1,233 @@ +From 29c1c132e0a3e23f5bb4438adc3c871234831513 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 07:32:24 -0400 +Subject: tracing: fprobe: optimization for entry only case +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Menglong Dong + +[ Upstream commit 2c67dc457bc67367dc8fcd8f471ce2d5bb5f7b2b ] + +For now, fgraph is used for the fprobe, even if we need trace the entry +only. However, the performance of ftrace is better than fgraph, and we +can use ftrace_ops for this case. + +Then performance of kprobe-multi increases from 54M to 69M. Before this +commit: + + $ ./benchs/run_bench_trigger.sh kprobe-multi + kprobe-multi : 54.663 ± 0.493M/s + +After this commit: + + $ ./benchs/run_bench_trigger.sh kprobe-multi + kprobe-multi : 69.447 ± 0.143M/s + +Mitigation is disable during the bench testing above. + +Link: https://lore.kernel.org/all/20251015083238.2374294-2-dongml2@chinatelecom.cn/ + +Signed-off-by: Menglong Dong +Signed-off-by: Masami Hiramatsu (Google) +Stable-dep-of: 845947aca681 ("tracing/fprobe: Remove fprobe from hash in failure path") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/fprobe.c | 128 +++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 119 insertions(+), 9 deletions(-) + +diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c +index 9db0a4e331132..66fa49b0cf27a 100644 +--- a/kernel/trace/fprobe.c ++++ b/kernel/trace/fprobe.c +@@ -252,8 +252,106 @@ static inline int __fprobe_kprobe_handler(unsigned long ip, unsigned long parent + return ret; + } + +-static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, +- struct ftrace_regs *fregs) ++#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS ++/* ftrace_ops callback, this processes fprobes which have only entry_handler. */ ++static void fprobe_ftrace_entry(unsigned long ip, unsigned long parent_ip, ++ struct ftrace_ops *ops, struct ftrace_regs *fregs) ++{ ++ struct fprobe_hlist_node *node; ++ struct rhlist_head *head, *pos; ++ struct fprobe *fp; ++ int bit; ++ ++ bit = ftrace_test_recursion_trylock(ip, parent_ip); ++ if (bit < 0) ++ return; ++ ++ /* ++ * ftrace_test_recursion_trylock() disables preemption, but ++ * rhltable_lookup() checks whether rcu_read_lcok is held. ++ * So we take rcu_read_lock() here. ++ */ ++ rcu_read_lock(); ++ head = rhltable_lookup(&fprobe_ip_table, &ip, fprobe_rht_params); ++ ++ rhl_for_each_entry_rcu(node, pos, head, hlist) { ++ if (node->addr != ip) ++ break; ++ fp = READ_ONCE(node->fp); ++ if (unlikely(!fp || fprobe_disabled(fp) || fp->exit_handler)) ++ continue; ++ ++ if (fprobe_shared_with_kprobes(fp)) ++ __fprobe_kprobe_handler(ip, parent_ip, fp, fregs, NULL); ++ else ++ __fprobe_handler(ip, parent_ip, fp, fregs, NULL); ++ } ++ rcu_read_unlock(); ++ ftrace_test_recursion_unlock(bit); ++} ++NOKPROBE_SYMBOL(fprobe_ftrace_entry); ++ ++static struct ftrace_ops fprobe_ftrace_ops = { ++ .func = fprobe_ftrace_entry, ++ .flags = FTRACE_OPS_FL_SAVE_REGS, ++}; ++static int fprobe_ftrace_active; ++ ++static int fprobe_ftrace_add_ips(unsigned long *addrs, int num) ++{ ++ int ret; ++ ++ lockdep_assert_held(&fprobe_mutex); ++ ++ ret = ftrace_set_filter_ips(&fprobe_ftrace_ops, addrs, num, 0, 0); ++ if (ret) ++ return ret; ++ ++ if (!fprobe_ftrace_active) { ++ ret = register_ftrace_function(&fprobe_ftrace_ops); ++ if (ret) { ++ ftrace_free_filter(&fprobe_ftrace_ops); ++ return ret; ++ } ++ } ++ fprobe_ftrace_active++; ++ return 0; ++} ++ ++static void fprobe_ftrace_remove_ips(unsigned long *addrs, int num) ++{ ++ lockdep_assert_held(&fprobe_mutex); ++ ++ fprobe_ftrace_active--; ++ if (!fprobe_ftrace_active) ++ unregister_ftrace_function(&fprobe_ftrace_ops); ++ if (num) ++ ftrace_set_filter_ips(&fprobe_ftrace_ops, addrs, num, 1, 0); ++} ++ ++static bool fprobe_is_ftrace(struct fprobe *fp) ++{ ++ return !fp->exit_handler; ++} ++#else ++static int fprobe_ftrace_add_ips(unsigned long *addrs, int num) ++{ ++ return -ENOENT; ++} ++ ++static void fprobe_ftrace_remove_ips(unsigned long *addrs, int num) ++{ ++} ++ ++static bool fprobe_is_ftrace(struct fprobe *fp) ++{ ++ return false; ++} ++#endif ++ ++/* fgraph_ops callback, this processes fprobes which have exit_handler. */ ++static int fprobe_fgraph_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, ++ struct ftrace_regs *fregs) + { + unsigned long *fgraph_data = NULL; + unsigned long func = trace->func; +@@ -289,7 +387,7 @@ static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, + if (node->addr != func) + continue; + fp = READ_ONCE(node->fp); +- if (fp && !fprobe_disabled(fp)) ++ if (fp && !fprobe_disabled(fp) && !fprobe_is_ftrace(fp)) + fp->nmissed++; + } + return 0; +@@ -309,7 +407,7 @@ static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, + if (node->addr != func) + continue; + fp = READ_ONCE(node->fp); +- if (!fp || fprobe_disabled(fp)) ++ if (unlikely(!fp || fprobe_disabled(fp) || fprobe_is_ftrace(fp))) + continue; + + data_size = fp->entry_data_size; +@@ -337,7 +435,7 @@ static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, + /* If any exit_handler is set, data must be used. */ + return used != 0; + } +-NOKPROBE_SYMBOL(fprobe_entry); ++NOKPROBE_SYMBOL(fprobe_fgraph_entry); + + static void fprobe_return(struct ftrace_graph_ret *trace, + struct fgraph_ops *gops, +@@ -376,7 +474,7 @@ static void fprobe_return(struct ftrace_graph_ret *trace, + NOKPROBE_SYMBOL(fprobe_return); + + static struct fgraph_ops fprobe_graph_ops = { +- .entryfunc = fprobe_entry, ++ .entryfunc = fprobe_fgraph_entry, + .retfunc = fprobe_return, + }; + static int fprobe_graph_active; +@@ -498,9 +596,14 @@ static int fprobe_module_callback(struct notifier_block *nb, + } while (node == ERR_PTR(-EAGAIN)); + rhashtable_walk_exit(&iter); + +- if (alist.index > 0) ++ if (alist.index > 0) { + ftrace_set_filter_ips(&fprobe_graph_ops.ops, + alist.addrs, alist.index, 1, 0); ++#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS ++ ftrace_set_filter_ips(&fprobe_ftrace_ops, ++ alist.addrs, alist.index, 1, 0); ++#endif ++ } + mutex_unlock(&fprobe_mutex); + + kfree(alist.addrs); +@@ -735,7 +838,11 @@ int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num) + return ret; + + hlist_array = fp->hlist_array; +- ret = fprobe_graph_add_ips(addrs, num); ++ if (fprobe_is_ftrace(fp)) ++ ret = fprobe_ftrace_add_ips(addrs, num); ++ else ++ ret = fprobe_graph_add_ips(addrs, num); ++ + if (!ret) { + add_fprobe_hash(fp); + for (i = 0; i < hlist_array->size; i++) { +@@ -830,7 +937,10 @@ int unregister_fprobe(struct fprobe *fp) + } + del_fprobe_hash(fp); + +- fprobe_graph_remove_ips(addrs, count); ++ if (fprobe_is_ftrace(fp)) ++ fprobe_ftrace_remove_ips(addrs, count); ++ else ++ fprobe_graph_remove_ips(addrs, count); + + kfree_rcu(hlist_array, rcu); + fp->hlist_array = NULL; +-- +2.53.0 + diff --git a/queue-6.18/tracing-fprobe-remove-fprobe-from-hash-in-failure-pa.patch b/queue-6.18/tracing-fprobe-remove-fprobe-from-hash-in-failure-pa.patch new file mode 100644 index 0000000000..da828c350d --- /dev/null +++ b/queue-6.18/tracing-fprobe-remove-fprobe-from-hash-in-failure-pa.patch @@ -0,0 +1,189 @@ +From 3e6bcd8fc2d87fd4b99d2545ebecd64ab25c6f37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 07:32:26 -0400 +Subject: tracing/fprobe: Remove fprobe from hash in failure path + +From: Masami Hiramatsu (Google) + +[ Upstream commit 845947aca6814f5723ed65e556eb5ee09493f05b ] + +When register_fprobe_ips() fails, it tries to remove a list of +fprobe_hash_node from fprobe_ip_table, but it missed to remove +fprobe itself from fprobe_table. Moreover, when removing +the fprobe_hash_node which is added to rhltable once, it must +use kfree_rcu() after removing from rhltable. + +To fix these issues, this reuses unregister_fprobe() internal +code to rollback the half-way registered fprobe. + +Link: https://lore.kernel.org/all/177669366417.132053.17874946321744910456.stgit@mhiramat.tok.corp.google.com/ + +Fixes: 4346ba160409 ("fprobe: Rewrite fprobe on function-graph tracer") +Cc: stable@vger.kernel.org +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/fprobe.c | 90 ++++++++++++++++++++++--------------------- + 1 file changed, 47 insertions(+), 43 deletions(-) + +diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c +index 2e5c6b3cafc0b..8fa5bff2c26fa 100644 +--- a/kernel/trace/fprobe.c ++++ b/kernel/trace/fprobe.c +@@ -78,20 +78,27 @@ static const struct rhashtable_params fprobe_rht_params = { + }; + + /* Node insertion and deletion requires the fprobe_mutex */ +-static int insert_fprobe_node(struct fprobe_hlist_node *node) ++static int insert_fprobe_node(struct fprobe_hlist_node *node, struct fprobe *fp) + { ++ int ret; ++ + lockdep_assert_held(&fprobe_mutex); + +- return rhltable_insert(&fprobe_ip_table, &node->hlist, fprobe_rht_params); ++ ret = rhltable_insert(&fprobe_ip_table, &node->hlist, fprobe_rht_params); ++ /* Set the fprobe pointer if insertion was successful. */ ++ if (!ret) ++ WRITE_ONCE(node->fp, fp); ++ return ret; + } + + /* Return true if there are synonims */ + static bool delete_fprobe_node(struct fprobe_hlist_node *node) + { +- lockdep_assert_held(&fprobe_mutex); + bool ret; + +- /* Avoid double deleting */ ++ lockdep_assert_held(&fprobe_mutex); ++ ++ /* Avoid double deleting and non-inserted nodes */ + if (READ_ONCE(node->fp) != NULL) { + WRITE_ONCE(node->fp, NULL); + rhltable_remove(&fprobe_ip_table, &node->hlist, +@@ -748,7 +755,6 @@ static int fprobe_init(struct fprobe *fp, unsigned long *addrs, int num) + fp->hlist_array = hlist_array; + hlist_array->fp = fp; + for (i = 0; i < num; i++) { +- hlist_array->array[i].fp = fp; + addr = ftrace_location(addrs[i]); + if (!addr) { + fprobe_fail_cleanup(fp); +@@ -812,6 +818,8 @@ int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter + } + EXPORT_SYMBOL_GPL(register_fprobe); + ++static int unregister_fprobe_nolock(struct fprobe *fp); ++ + /** + * register_fprobe_ips() - Register fprobe to ftrace by address. + * @fp: A fprobe data structure to be registered. +@@ -838,28 +846,25 @@ int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num) + if (ret) + return ret; + +- hlist_array = fp->hlist_array; + if (fprobe_is_ftrace(fp)) + ret = fprobe_ftrace_add_ips(addrs, num); + else + ret = fprobe_graph_add_ips(addrs, num); +- +- if (!ret) { +- add_fprobe_hash(fp); +- for (i = 0; i < hlist_array->size; i++) { +- ret = insert_fprobe_node(&hlist_array->array[i]); +- if (ret) +- break; +- } +- /* fallback on insert error */ +- if (ret) { +- for (i--; i >= 0; i--) +- delete_fprobe_node(&hlist_array->array[i]); +- } ++ if (ret) { ++ fprobe_fail_cleanup(fp); ++ return ret; + } + +- if (ret) +- fprobe_fail_cleanup(fp); ++ hlist_array = fp->hlist_array; ++ ret = add_fprobe_hash(fp); ++ for (i = 0; i < hlist_array->size && !ret; i++) ++ ret = insert_fprobe_node(&hlist_array->array[i], fp); ++ ++ if (ret) { ++ unregister_fprobe_nolock(fp); ++ /* In error case, wait for clean up safely. */ ++ synchronize_rcu(); ++ } + + return ret; + } +@@ -903,27 +908,12 @@ bool fprobe_is_registered(struct fprobe *fp) + return true; + } + +-/** +- * unregister_fprobe() - Unregister fprobe. +- * @fp: A fprobe data structure to be unregistered. +- * +- * Unregister fprobe (and remove ftrace hooks from the function entries). +- * +- * Return 0 if @fp is unregistered successfully, -errno if not. +- */ +-int unregister_fprobe(struct fprobe *fp) ++static int unregister_fprobe_nolock(struct fprobe *fp) + { +- struct fprobe_hlist *hlist_array; ++ struct fprobe_hlist *hlist_array = fp->hlist_array; + unsigned long *addrs = NULL; +- int ret = 0, i, count; ++ int i, count; + +- mutex_lock(&fprobe_mutex); +- if (!fp || !fprobe_registered(fp)) { +- ret = -EINVAL; +- goto out; +- } +- +- hlist_array = fp->hlist_array; + addrs = kcalloc(hlist_array->size, sizeof(unsigned long), GFP_KERNEL); + /* + * This will remove fprobe_hash_node from the hash table even if +@@ -949,12 +939,26 @@ int unregister_fprobe(struct fprobe *fp) + + kfree_rcu(hlist_array, rcu); + fp->hlist_array = NULL; ++ kfree(addrs); + +-out: +- mutex_unlock(&fprobe_mutex); ++ return 0; ++} + +- kfree(addrs); +- return ret; ++/** ++ * unregister_fprobe() - Unregister fprobe. ++ * @fp: A fprobe data structure to be unregistered. ++ * ++ * Unregister fprobe (and remove ftrace hooks from the function entries). ++ * ++ * Return 0 if @fp is unregistered successfully, -errno if not. ++ */ ++int unregister_fprobe(struct fprobe *fp) ++{ ++ guard(mutex)(&fprobe_mutex); ++ if (!fp || !fprobe_registered(fp)) ++ return -EINVAL; ++ ++ return unregister_fprobe_nolock(fp); + } + EXPORT_SYMBOL_GPL(unregister_fprobe); + +-- +2.53.0 + diff --git a/queue-6.18/tracing-fprobe-unregister-fprobe-even-if-memory-allo.patch b/queue-6.18/tracing-fprobe-unregister-fprobe-even-if-memory-allo.patch new file mode 100644 index 0000000000..9a2bae1ad0 --- /dev/null +++ b/queue-6.18/tracing-fprobe-unregister-fprobe-even-if-memory-allo.patch @@ -0,0 +1,89 @@ +From 3654bc49a691f5b465ee19b02ea1ed545dc70de0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 07:32:25 -0400 +Subject: tracing/fprobe: Unregister fprobe even if memory allocation fails + +From: Masami Hiramatsu (Google) + +[ Upstream commit 1aec9e5c3e31ce1e28f914427fb7f90b91d310df ] + +unregister_fprobe() can fail under memory pressure because of memory +allocation failure, but this maybe called from module unloading, and +usually there is no way to retry it. Moreover. trace_fprobe does not +check the return value. + +To fix this problem, unregister fprobe and fprobe_hash_node even if +working memory allocation fails. +Anyway, if the last fprobe is removed, the filter will be freed. + +Link: https://lore.kernel.org/all/177669365629.132053.8433032896213721288.stgit@mhiramat.tok.corp.google.com/ + +Fixes: 4346ba160409 ("fprobe: Rewrite fprobe on function-graph tracer") +Cc: stable@vger.kernel.org +Signed-off-by: Masami Hiramatsu (Google) +Stable-dep-of: 845947aca681 ("tracing/fprobe: Remove fprobe from hash in failure path") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/fprobe.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c +index 66fa49b0cf27a..2e5c6b3cafc0b 100644 +--- a/kernel/trace/fprobe.c ++++ b/kernel/trace/fprobe.c +@@ -323,9 +323,10 @@ static void fprobe_ftrace_remove_ips(unsigned long *addrs, int num) + lockdep_assert_held(&fprobe_mutex); + + fprobe_ftrace_active--; +- if (!fprobe_ftrace_active) ++ if (!fprobe_ftrace_active) { + unregister_ftrace_function(&fprobe_ftrace_ops); +- if (num) ++ ftrace_free_filter(&fprobe_ftrace_ops); ++ } else if (num) + ftrace_set_filter_ips(&fprobe_ftrace_ops, addrs, num, 1, 0); + } + +@@ -508,10 +509,10 @@ static void fprobe_graph_remove_ips(unsigned long *addrs, int num) + + fprobe_graph_active--; + /* Q: should we unregister it ? */ +- if (!fprobe_graph_active) ++ if (!fprobe_graph_active) { + unregister_ftrace_graph(&fprobe_graph_ops); +- +- if (num) ++ ftrace_free_filter(&fprobe_graph_ops.ops); ++ } else if (num) + ftrace_set_filter_ips(&fprobe_graph_ops.ops, addrs, num, 1, 0); + } + +@@ -924,15 +925,19 @@ int unregister_fprobe(struct fprobe *fp) + + hlist_array = fp->hlist_array; + addrs = kcalloc(hlist_array->size, sizeof(unsigned long), GFP_KERNEL); +- if (!addrs) { +- ret = -ENOMEM; /* TODO: Fallback to one-by-one loop */ +- goto out; +- } ++ /* ++ * This will remove fprobe_hash_node from the hash table even if ++ * memory allocation fails. However, ftrace_ops will not be updated. ++ * Anyway, when the last fprobe is unregistered, ftrace_ops is also ++ * unregistered. ++ */ ++ if (!addrs) ++ pr_warn("Failed to allocate working array. ftrace_ops may not sync.\n"); + + /* Remove non-synonim ips from table and hash */ + count = 0; + for (i = 0; i < hlist_array->size; i++) { +- if (!delete_fprobe_node(&hlist_array->array[i])) ++ if (!delete_fprobe_node(&hlist_array->array[i]) && addrs) + addrs[count++] = hlist_array->array[i].addr; + } + del_fprobe_hash(fp); +-- +2.53.0 + diff --git a/queue-6.18/tracing-fprobe-use-rhltable-for-fprobe_ip_table.patch b/queue-6.18/tracing-fprobe-use-rhltable-for-fprobe_ip_table.patch new file mode 100644 index 0000000000..3f3d53b0f6 --- /dev/null +++ b/queue-6.18/tracing-fprobe-use-rhltable-for-fprobe_ip_table.patch @@ -0,0 +1,328 @@ +From b4165b8b624c562e7461464b3c4c871c528ba0c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 May 2026 07:32:23 -0400 +Subject: tracing: fprobe: use rhltable for fprobe_ip_table + +From: Menglong Dong + +[ Upstream commit 0de4c70d04a46a3c266547dd4275ce25f623796a ] + +For now, all the kernel functions who are hooked by the fprobe will be +added to the hash table "fprobe_ip_table". The key of it is the function +address, and the value of it is "struct fprobe_hlist_node". + +The budget of the hash table is FPROBE_IP_TABLE_SIZE, which is 256. And +this means the overhead of the hash table lookup will grow linearly if +the count of the functions in the fprobe more than 256. When we try to +hook all the kernel functions, the overhead will be huge. + +Therefore, replace the hash table with rhltable to reduce the overhead. + +Link: https://lore.kernel.org/all/20250819031825.55653-1-dongml2@chinatelecom.cn/ + +Signed-off-by: Menglong Dong +Signed-off-by: Masami Hiramatsu (Google) +Stable-dep-of: 845947aca681 ("tracing/fprobe: Remove fprobe from hash in failure path") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/fprobe.h | 3 +- + kernel/trace/fprobe.c | 157 ++++++++++++++++++++++++----------------- + 2 files changed, 93 insertions(+), 67 deletions(-) + +diff --git a/include/linux/fprobe.h b/include/linux/fprobe.h +index 7964db96e41a9..0a3bcd1718f37 100644 +--- a/include/linux/fprobe.h ++++ b/include/linux/fprobe.h +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + struct fprobe; +@@ -26,7 +27,7 @@ typedef void (*fprobe_exit_cb)(struct fprobe *fp, unsigned long entry_ip, + * @fp: The fprobe which owns this. + */ + struct fprobe_hlist_node { +- struct hlist_node hlist; ++ struct rhlist_head hlist; + unsigned long addr; + struct fprobe *fp; + }; +diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c +index 43b27f07730c2..9db0a4e331132 100644 +--- a/kernel/trace/fprobe.c ++++ b/kernel/trace/fprobe.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -42,60 +43,67 @@ + * - RCU hlist traversal under disabling preempt + */ + static struct hlist_head fprobe_table[FPROBE_TABLE_SIZE]; +-static struct hlist_head fprobe_ip_table[FPROBE_IP_TABLE_SIZE]; ++static struct rhltable fprobe_ip_table; + static DEFINE_MUTEX(fprobe_mutex); + +-/* +- * Find first fprobe in the hlist. It will be iterated twice in the entry +- * probe, once for correcting the total required size, the second time is +- * calling back the user handlers. +- * Thus the hlist in the fprobe_table must be sorted and new probe needs to +- * be added *before* the first fprobe. +- */ +-static struct fprobe_hlist_node *find_first_fprobe_node(unsigned long ip) ++static u32 fprobe_node_hashfn(const void *data, u32 len, u32 seed) + { +- struct fprobe_hlist_node *node; +- struct hlist_head *head; ++ return hash_ptr(*(unsigned long **)data, 32); ++} + +- head = &fprobe_ip_table[hash_ptr((void *)ip, FPROBE_IP_HASH_BITS)]; +- hlist_for_each_entry_rcu(node, head, hlist, +- lockdep_is_held(&fprobe_mutex)) { +- if (node->addr == ip) +- return node; +- } +- return NULL; ++static int fprobe_node_cmp(struct rhashtable_compare_arg *arg, ++ const void *ptr) ++{ ++ unsigned long key = *(unsigned long *)arg->key; ++ const struct fprobe_hlist_node *n = ptr; ++ ++ return n->addr != key; + } +-NOKPROBE_SYMBOL(find_first_fprobe_node); + +-/* Node insertion and deletion requires the fprobe_mutex */ +-static void insert_fprobe_node(struct fprobe_hlist_node *node) ++static u32 fprobe_node_obj_hashfn(const void *data, u32 len, u32 seed) + { +- unsigned long ip = node->addr; +- struct fprobe_hlist_node *next; +- struct hlist_head *head; ++ const struct fprobe_hlist_node *n = data; ++ ++ return hash_ptr((void *)n->addr, 32); ++} + ++static const struct rhashtable_params fprobe_rht_params = { ++ .head_offset = offsetof(struct fprobe_hlist_node, hlist), ++ .key_offset = offsetof(struct fprobe_hlist_node, addr), ++ .key_len = sizeof_field(struct fprobe_hlist_node, addr), ++ .hashfn = fprobe_node_hashfn, ++ .obj_hashfn = fprobe_node_obj_hashfn, ++ .obj_cmpfn = fprobe_node_cmp, ++ .automatic_shrinking = true, ++}; ++ ++/* Node insertion and deletion requires the fprobe_mutex */ ++static int insert_fprobe_node(struct fprobe_hlist_node *node) ++{ + lockdep_assert_held(&fprobe_mutex); + +- next = find_first_fprobe_node(ip); +- if (next) { +- hlist_add_before_rcu(&node->hlist, &next->hlist); +- return; +- } +- head = &fprobe_ip_table[hash_ptr((void *)ip, FPROBE_IP_HASH_BITS)]; +- hlist_add_head_rcu(&node->hlist, head); ++ return rhltable_insert(&fprobe_ip_table, &node->hlist, fprobe_rht_params); + } + + /* Return true if there are synonims */ + static bool delete_fprobe_node(struct fprobe_hlist_node *node) + { + lockdep_assert_held(&fprobe_mutex); ++ bool ret; + + /* Avoid double deleting */ + if (READ_ONCE(node->fp) != NULL) { + WRITE_ONCE(node->fp, NULL); +- hlist_del_rcu(&node->hlist); ++ rhltable_remove(&fprobe_ip_table, &node->hlist, ++ fprobe_rht_params); + } +- return !!find_first_fprobe_node(node->addr); ++ ++ rcu_read_lock(); ++ ret = !!rhltable_lookup(&fprobe_ip_table, &node->addr, ++ fprobe_rht_params); ++ rcu_read_unlock(); ++ ++ return ret; + } + + /* Check existence of the fprobe */ +@@ -247,9 +255,10 @@ static inline int __fprobe_kprobe_handler(unsigned long ip, unsigned long parent + static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, + struct ftrace_regs *fregs) + { +- struct fprobe_hlist_node *node, *first; + unsigned long *fgraph_data = NULL; + unsigned long func = trace->func; ++ struct fprobe_hlist_node *node; ++ struct rhlist_head *head, *pos; + unsigned long ret_ip; + int reserved_words; + struct fprobe *fp; +@@ -258,14 +267,11 @@ static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, + if (WARN_ON_ONCE(!fregs)) + return 0; + +- first = node = find_first_fprobe_node(func); +- if (unlikely(!first)) +- return 0; +- ++ head = rhltable_lookup(&fprobe_ip_table, &func, fprobe_rht_params); + reserved_words = 0; +- hlist_for_each_entry_from_rcu(node, hlist) { ++ rhl_for_each_entry_rcu(node, pos, head, hlist) { + if (node->addr != func) +- break; ++ continue; + fp = READ_ONCE(node->fp); + if (!fp || !fp->exit_handler) + continue; +@@ -276,13 +282,12 @@ static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, + reserved_words += + FPROBE_HEADER_SIZE_IN_LONG + SIZE_IN_LONG(fp->entry_data_size); + } +- node = first; + if (reserved_words) { + fgraph_data = fgraph_reserve_data(gops->idx, reserved_words * sizeof(long)); + if (unlikely(!fgraph_data)) { +- hlist_for_each_entry_from_rcu(node, hlist) { ++ rhl_for_each_entry_rcu(node, pos, head, hlist) { + if (node->addr != func) +- break; ++ continue; + fp = READ_ONCE(node->fp); + if (fp && !fprobe_disabled(fp)) + fp->nmissed++; +@@ -297,12 +302,12 @@ static int fprobe_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, + */ + ret_ip = ftrace_regs_get_return_address(fregs); + used = 0; +- hlist_for_each_entry_from_rcu(node, hlist) { ++ rhl_for_each_entry_rcu(node, pos, head, hlist) { + int data_size; + void *data; + + if (node->addr != func) +- break; ++ continue; + fp = READ_ONCE(node->fp); + if (!fp || fprobe_disabled(fp)) + continue; +@@ -447,25 +452,21 @@ static int fprobe_addr_list_add(struct fprobe_addr_list *alist, unsigned long ad + return 0; + } + +-static void fprobe_remove_node_in_module(struct module *mod, struct hlist_head *head, +- struct fprobe_addr_list *alist) ++static void fprobe_remove_node_in_module(struct module *mod, struct fprobe_hlist_node *node, ++ struct fprobe_addr_list *alist) + { +- struct fprobe_hlist_node *node; + int ret = 0; + +- hlist_for_each_entry_rcu(node, head, hlist, +- lockdep_is_held(&fprobe_mutex)) { +- if (!within_module(node->addr, mod)) +- continue; +- if (delete_fprobe_node(node)) +- continue; +- /* +- * If failed to update alist, just continue to update hlist. +- * Therefore, at list user handler will not hit anymore. +- */ +- if (!ret) +- ret = fprobe_addr_list_add(alist, node->addr); +- } ++ if (!within_module(node->addr, mod)) ++ return; ++ if (delete_fprobe_node(node)) ++ return; ++ /* ++ * If failed to update alist, just continue to update hlist. ++ * Therefore, at list user handler will not hit anymore. ++ */ ++ if (!ret) ++ ret = fprobe_addr_list_add(alist, node->addr); + } + + /* Handle module unloading to manage fprobe_ip_table. */ +@@ -473,8 +474,9 @@ static int fprobe_module_callback(struct notifier_block *nb, + unsigned long val, void *data) + { + struct fprobe_addr_list alist = {.size = FPROBE_IPS_BATCH_INIT}; ++ struct fprobe_hlist_node *node; ++ struct rhashtable_iter iter; + struct module *mod = data; +- int i; + + if (val != MODULE_STATE_GOING) + return NOTIFY_DONE; +@@ -485,8 +487,16 @@ static int fprobe_module_callback(struct notifier_block *nb, + return NOTIFY_DONE; + + mutex_lock(&fprobe_mutex); +- for (i = 0; i < FPROBE_IP_TABLE_SIZE; i++) +- fprobe_remove_node_in_module(mod, &fprobe_ip_table[i], &alist); ++ rhltable_walk_enter(&fprobe_ip_table, &iter); ++ do { ++ rhashtable_walk_start(&iter); ++ ++ while ((node = rhashtable_walk_next(&iter)) && !IS_ERR(node)) ++ fprobe_remove_node_in_module(mod, node, &alist); ++ ++ rhashtable_walk_stop(&iter); ++ } while (node == ERR_PTR(-EAGAIN)); ++ rhashtable_walk_exit(&iter); + + if (alist.index > 0) + ftrace_set_filter_ips(&fprobe_graph_ops.ops, +@@ -728,8 +738,16 @@ int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num) + ret = fprobe_graph_add_ips(addrs, num); + if (!ret) { + add_fprobe_hash(fp); +- for (i = 0; i < hlist_array->size; i++) +- insert_fprobe_node(&hlist_array->array[i]); ++ for (i = 0; i < hlist_array->size; i++) { ++ ret = insert_fprobe_node(&hlist_array->array[i]); ++ if (ret) ++ break; ++ } ++ /* fallback on insert error */ ++ if (ret) { ++ for (i--; i >= 0; i--) ++ delete_fprobe_node(&hlist_array->array[i]); ++ } + } + + if (ret) +@@ -824,3 +842,10 @@ int unregister_fprobe(struct fprobe *fp) + return ret; + } + EXPORT_SYMBOL_GPL(unregister_fprobe); ++ ++static int __init fprobe_initcall(void) ++{ ++ rhltable_init(&fprobe_ip_table, &fprobe_rht_params); ++ return 0; ++} ++late_initcall(fprobe_initcall); +-- +2.53.0 + diff --git a/queue-6.18/tracing-move-__printf-attribute-on-__ftrace_vbprintk.patch b/queue-6.18/tracing-move-__printf-attribute-on-__ftrace_vbprintk.patch new file mode 100644 index 0000000000..81d5f4d6b5 --- /dev/null +++ b/queue-6.18/tracing-move-__printf-attribute-on-__ftrace_vbprintk.patch @@ -0,0 +1,81 @@ +From ef528ac4be2f6b4c7521e206762c9feaa116436e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 17:45:29 +0100 +Subject: tracing: move __printf() attribute on __ftrace_vbprintk() + +From: Arnd Bergmann + +[ Upstream commit 473e470f16f98569d59adc11c4a318780fb68fe9 ] + +The sunrpc change to use trace_printk() for debugging caused +a new warning for every instance of dprintk() in some configurations, +when -Wformat-security is enabled: + +fs/nfs/getroot.c: In function 'nfs_get_root': +fs/nfs/getroot.c:90:17: error: format not a string literal and no format arguments [-Werror=format-security] + 90 | nfs_errorf(fc, "NFS: Couldn't getattr on root"); + +I've been slowly chipping away at those warnings over time with the +intention of enabling them by default in the future. While I could not +figure out why this only happens for this one instance, I see that the +__trace_bprintk() function is always called with a local variable as +the format string, rather than a literal. + +Move the __printf(2,3) annotation on this function from the declaration +to the caller. As this is can only be validated for literals, the +attribute on the declaration causes the warnings every time, but +removing it entirely introduces a new warning on the __ftrace_vbprintk() +definition. + +The format strings still get checked because the underlying literal keeps +getting passed into __trace_printk() in the "else" branch, which is not +taken but still evaluated for compile-time warnings. + +Cc: Masami Hiramatsu +Cc: Anna Schumaker +Cc: Chuck Lever +Cc: Simon Horman +Cc: Mathieu Desnoyers +Cc: Andrew Morton +Cc: Yury Norov +Cc: Randy Dunlap +Link: https://patch.msgid.link/20260203164545.3174910-1-arnd@kernel.org +Fixes: ec7d8e68ef0e ("sunrpc: add a Kconfig option to redirect dfprintk() output to trace buffer") +Acked-by: Jeff Layton +Acked-by: Steven Rostedt (Google) +Signed-off-by: Arnd Bergmann +Acked-by: Andy Shevchenko +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + include/linux/trace_printk.h | 1 - + kernel/trace/trace_printk.c | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/trace_printk.h b/include/linux/trace_printk.h +index bb5874097f24e..2670ec7f42629 100644 +--- a/include/linux/trace_printk.h ++++ b/include/linux/trace_printk.h +@@ -107,7 +107,6 @@ do { \ + __trace_printk(_THIS_IP_, fmt, ##args); \ + } while (0) + +-extern __printf(2, 3) + int __trace_bprintk(unsigned long ip, const char *fmt, ...); + + extern __printf(2, 3) +diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c +index 29f6e95439b67..48c085fcae7aa 100644 +--- a/kernel/trace/trace_printk.c ++++ b/kernel/trace/trace_printk.c +@@ -197,6 +197,7 @@ struct notifier_block module_trace_bprintk_format_nb = { + .notifier_call = module_trace_bprintk_format_notify, + }; + ++__printf(2, 3) + int __trace_bprintk(unsigned long ip, const char *fmt, ...) + { + int ret; +-- +2.53.0 + diff --git a/queue-6.18/tracing-move-tracing-declarations-from-kernel.h-to-a.patch b/queue-6.18/tracing-move-tracing-declarations-from-kernel.h-to-a.patch new file mode 100644 index 0000000000..bb3113fd8f --- /dev/null +++ b/queue-6.18/tracing-move-tracing-declarations-from-kernel.h-to-a.patch @@ -0,0 +1,468 @@ +From f30fadf3f33054111e72811abcbe93d5c886191e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 23:25:09 -0500 +Subject: tracing: move tracing declarations from kernel.h to a dedicated + header + +From: Yury Norov + +[ Upstream commit bec261fec6d41318e414c4064f2b67c6db628acd ] + +Tracing is a half of the kernel.h in terms of LOCs, although it's a +self-consistent part. It is intended for quick debugging purposes and +isn't used by the normal tracing utilities. + +Move it to a separate header. If someone needs to just throw a +trace_printk() in their driver, they will not have to pull all the heavy +tracing machinery. + +This is a pure move. + +Link: https://lkml.kernel.org/r/20260116042510.241009-7-ynorov@nvidia.com +Signed-off-by: Yury Norov +Acked-by: Steven Rostedt +Reviewed-by: Andy Shevchenko +Reviewed-by: Joel Fernandes +Cc: Aaron Tomlin +Cc: Andi Shyti +Cc: Christophe Leroy (CS GROUP) +Cc: Greg Kroah-Hartman +Cc: Jani Nikula +Cc: Petr Pavlu +Cc: Randy Dunlap +Signed-off-by: Andrew Morton +Stable-dep-of: 473e470f16f9 ("tracing: move __printf() attribute on __ftrace_vbprintk()") +Signed-off-by: Sasha Levin +--- + include/linux/kernel.h | 196 +-------------------------------- + include/linux/trace_printk.h | 204 +++++++++++++++++++++++++++++++++++ + 2 files changed, 205 insertions(+), 195 deletions(-) + create mode 100644 include/linux/trace_printk.h + +diff --git a/include/linux/kernel.h b/include/linux/kernel.h +index d5a939b8c3911..356a6f1db9dac 100644 +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -32,7 +32,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +@@ -192,200 +192,6 @@ enum system_states { + }; + extern enum system_states system_state; + +-/* +- * General tracing related utility functions - trace_printk(), +- * tracing_on/tracing_off and tracing_start()/tracing_stop +- * +- * Use tracing_on/tracing_off when you want to quickly turn on or off +- * tracing. It simply enables or disables the recording of the trace events. +- * This also corresponds to the user space /sys/kernel/tracing/tracing_on +- * file, which gives a means for the kernel and userspace to interact. +- * Place a tracing_off() in the kernel where you want tracing to end. +- * From user space, examine the trace, and then echo 1 > tracing_on +- * to continue tracing. +- * +- * tracing_stop/tracing_start has slightly more overhead. It is used +- * by things like suspend to ram where disabling the recording of the +- * trace is not enough, but tracing must actually stop because things +- * like calling smp_processor_id() may crash the system. +- * +- * Most likely, you want to use tracing_on/tracing_off. +- */ +- +-enum ftrace_dump_mode { +- DUMP_NONE, +- DUMP_ALL, +- DUMP_ORIG, +- DUMP_PARAM, +-}; +- +-#ifdef CONFIG_TRACING +-void tracing_on(void); +-void tracing_off(void); +-int tracing_is_on(void); +-void tracing_snapshot(void); +-void tracing_snapshot_alloc(void); +- +-extern void tracing_start(void); +-extern void tracing_stop(void); +- +-static inline __printf(1, 2) +-void ____trace_printk_check_format(const char *fmt, ...) +-{ +-} +-#define __trace_printk_check_format(fmt, args...) \ +-do { \ +- if (0) \ +- ____trace_printk_check_format(fmt, ##args); \ +-} while (0) +- +-/** +- * trace_printk - printf formatting in the ftrace buffer +- * @fmt: the printf format for printing +- * +- * Note: __trace_printk is an internal function for trace_printk() and +- * the @ip is passed in via the trace_printk() macro. +- * +- * This function allows a kernel developer to debug fast path sections +- * that printk is not appropriate for. By scattering in various +- * printk like tracing in the code, a developer can quickly see +- * where problems are occurring. +- * +- * This is intended as a debugging tool for the developer only. +- * Please refrain from leaving trace_printks scattered around in +- * your code. (Extra memory is used for special buffers that are +- * allocated when trace_printk() is used.) +- * +- * A little optimization trick is done here. If there's only one +- * argument, there's no need to scan the string for printf formats. +- * The trace_puts() will suffice. But how can we take advantage of +- * using trace_puts() when trace_printk() has only one argument? +- * By stringifying the args and checking the size we can tell +- * whether or not there are args. __stringify((__VA_ARGS__)) will +- * turn into "()\0" with a size of 3 when there are no args, anything +- * else will be bigger. All we need to do is define a string to this, +- * and then take its size and compare to 3. If it's bigger, use +- * do_trace_printk() otherwise, optimize it to trace_puts(). Then just +- * let gcc optimize the rest. +- */ +- +-#define trace_printk(fmt, ...) \ +-do { \ +- char _______STR[] = __stringify((__VA_ARGS__)); \ +- if (sizeof(_______STR) > 3) \ +- do_trace_printk(fmt, ##__VA_ARGS__); \ +- else \ +- trace_puts(fmt); \ +-} while (0) +- +-#define do_trace_printk(fmt, args...) \ +-do { \ +- static const char *trace_printk_fmt __used \ +- __section("__trace_printk_fmt") = \ +- __builtin_constant_p(fmt) ? fmt : NULL; \ +- \ +- __trace_printk_check_format(fmt, ##args); \ +- \ +- if (__builtin_constant_p(fmt)) \ +- __trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args); \ +- else \ +- __trace_printk(_THIS_IP_, fmt, ##args); \ +-} while (0) +- +-extern __printf(2, 3) +-int __trace_bprintk(unsigned long ip, const char *fmt, ...); +- +-extern __printf(2, 3) +-int __trace_printk(unsigned long ip, const char *fmt, ...); +- +-/** +- * trace_puts - write a string into the ftrace buffer +- * @str: the string to record +- * +- * Note: __trace_bputs is an internal function for trace_puts and +- * the @ip is passed in via the trace_puts macro. +- * +- * This is similar to trace_printk() but is made for those really fast +- * paths that a developer wants the least amount of "Heisenbug" effects, +- * where the processing of the print format is still too much. +- * +- * This function allows a kernel developer to debug fast path sections +- * that printk is not appropriate for. By scattering in various +- * printk like tracing in the code, a developer can quickly see +- * where problems are occurring. +- * +- * This is intended as a debugging tool for the developer only. +- * Please refrain from leaving trace_puts scattered around in +- * your code. (Extra memory is used for special buffers that are +- * allocated when trace_puts() is used.) +- * +- * Returns: 0 if nothing was written, positive # if string was. +- * (1 when __trace_bputs is used, strlen(str) when __trace_puts is used) +- */ +- +-#define trace_puts(str) ({ \ +- static const char *trace_printk_fmt __used \ +- __section("__trace_printk_fmt") = \ +- __builtin_constant_p(str) ? str : NULL; \ +- \ +- if (__builtin_constant_p(str)) \ +- __trace_bputs(_THIS_IP_, trace_printk_fmt); \ +- else \ +- __trace_puts(_THIS_IP_, str); \ +-}) +-extern int __trace_bputs(unsigned long ip, const char *str); +-extern int __trace_puts(unsigned long ip, const char *str); +- +-extern void trace_dump_stack(int skip); +- +-/* +- * The double __builtin_constant_p is because gcc will give us an error +- * if we try to allocate the static variable to fmt if it is not a +- * constant. Even with the outer if statement. +- */ +-#define ftrace_vprintk(fmt, vargs) \ +-do { \ +- if (__builtin_constant_p(fmt)) { \ +- static const char *trace_printk_fmt __used \ +- __section("__trace_printk_fmt") = \ +- __builtin_constant_p(fmt) ? fmt : NULL; \ +- \ +- __ftrace_vbprintk(_THIS_IP_, trace_printk_fmt, vargs); \ +- } else \ +- __ftrace_vprintk(_THIS_IP_, fmt, vargs); \ +-} while (0) +- +-extern __printf(2, 0) int +-__ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap); +- +-extern __printf(2, 0) int +-__ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap); +- +-extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode); +-#else +-static inline void tracing_start(void) { } +-static inline void tracing_stop(void) { } +-static inline void trace_dump_stack(int skip) { } +- +-static inline void tracing_on(void) { } +-static inline void tracing_off(void) { } +-static inline int tracing_is_on(void) { return 0; } +-static inline void tracing_snapshot(void) { } +-static inline void tracing_snapshot_alloc(void) { } +- +-static inline __printf(1, 2) +-int trace_printk(const char *fmt, ...) +-{ +- return 0; +-} +-static __printf(1, 0) inline int +-ftrace_vprintk(const char *fmt, va_list ap) +-{ +- return 0; +-} +-static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } +-#endif /* CONFIG_TRACING */ +- + /* Rebuild everything on CONFIG_DYNAMIC_FTRACE */ + #ifdef CONFIG_DYNAMIC_FTRACE + # define REBUILD_DUE_TO_DYNAMIC_FTRACE +diff --git a/include/linux/trace_printk.h b/include/linux/trace_printk.h +new file mode 100644 +index 0000000000000..bb5874097f24e +--- /dev/null ++++ b/include/linux/trace_printk.h +@@ -0,0 +1,204 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _LINUX_TRACE_PRINTK_H ++#define _LINUX_TRACE_PRINTK_H ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * General tracing related utility functions - trace_printk(), ++ * tracing_on/tracing_off and tracing_start()/tracing_stop ++ * ++ * Use tracing_on/tracing_off when you want to quickly turn on or off ++ * tracing. It simply enables or disables the recording of the trace events. ++ * This also corresponds to the user space /sys/kernel/tracing/tracing_on ++ * file, which gives a means for the kernel and userspace to interact. ++ * Place a tracing_off() in the kernel where you want tracing to end. ++ * From user space, examine the trace, and then echo 1 > tracing_on ++ * to continue tracing. ++ * ++ * tracing_stop/tracing_start has slightly more overhead. It is used ++ * by things like suspend to ram where disabling the recording of the ++ * trace is not enough, but tracing must actually stop because things ++ * like calling smp_processor_id() may crash the system. ++ * ++ * Most likely, you want to use tracing_on/tracing_off. ++ */ ++ ++enum ftrace_dump_mode { ++ DUMP_NONE, ++ DUMP_ALL, ++ DUMP_ORIG, ++ DUMP_PARAM, ++}; ++ ++#ifdef CONFIG_TRACING ++void tracing_on(void); ++void tracing_off(void); ++int tracing_is_on(void); ++void tracing_snapshot(void); ++void tracing_snapshot_alloc(void); ++ ++extern void tracing_start(void); ++extern void tracing_stop(void); ++ ++static inline __printf(1, 2) ++void ____trace_printk_check_format(const char *fmt, ...) ++{ ++} ++#define __trace_printk_check_format(fmt, args...) \ ++do { \ ++ if (0) \ ++ ____trace_printk_check_format(fmt, ##args); \ ++} while (0) ++ ++/** ++ * trace_printk - printf formatting in the ftrace buffer ++ * @fmt: the printf format for printing ++ * ++ * Note: __trace_printk is an internal function for trace_printk() and ++ * the @ip is passed in via the trace_printk() macro. ++ * ++ * This function allows a kernel developer to debug fast path sections ++ * that printk is not appropriate for. By scattering in various ++ * printk like tracing in the code, a developer can quickly see ++ * where problems are occurring. ++ * ++ * This is intended as a debugging tool for the developer only. ++ * Please refrain from leaving trace_printks scattered around in ++ * your code. (Extra memory is used for special buffers that are ++ * allocated when trace_printk() is used.) ++ * ++ * A little optimization trick is done here. If there's only one ++ * argument, there's no need to scan the string for printf formats. ++ * The trace_puts() will suffice. But how can we take advantage of ++ * using trace_puts() when trace_printk() has only one argument? ++ * By stringifying the args and checking the size we can tell ++ * whether or not there are args. __stringify((__VA_ARGS__)) will ++ * turn into "()\0" with a size of 3 when there are no args, anything ++ * else will be bigger. All we need to do is define a string to this, ++ * and then take its size and compare to 3. If it's bigger, use ++ * do_trace_printk() otherwise, optimize it to trace_puts(). Then just ++ * let gcc optimize the rest. ++ */ ++ ++#define trace_printk(fmt, ...) \ ++do { \ ++ char _______STR[] = __stringify((__VA_ARGS__)); \ ++ if (sizeof(_______STR) > 3) \ ++ do_trace_printk(fmt, ##__VA_ARGS__); \ ++ else \ ++ trace_puts(fmt); \ ++} while (0) ++ ++#define do_trace_printk(fmt, args...) \ ++do { \ ++ static const char *trace_printk_fmt __used \ ++ __section("__trace_printk_fmt") = \ ++ __builtin_constant_p(fmt) ? fmt : NULL; \ ++ \ ++ __trace_printk_check_format(fmt, ##args); \ ++ \ ++ if (__builtin_constant_p(fmt)) \ ++ __trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args); \ ++ else \ ++ __trace_printk(_THIS_IP_, fmt, ##args); \ ++} while (0) ++ ++extern __printf(2, 3) ++int __trace_bprintk(unsigned long ip, const char *fmt, ...); ++ ++extern __printf(2, 3) ++int __trace_printk(unsigned long ip, const char *fmt, ...); ++ ++/** ++ * trace_puts - write a string into the ftrace buffer ++ * @str: the string to record ++ * ++ * Note: __trace_bputs is an internal function for trace_puts and ++ * the @ip is passed in via the trace_puts macro. ++ * ++ * This is similar to trace_printk() but is made for those really fast ++ * paths that a developer wants the least amount of "Heisenbug" effects, ++ * where the processing of the print format is still too much. ++ * ++ * This function allows a kernel developer to debug fast path sections ++ * that printk is not appropriate for. By scattering in various ++ * printk like tracing in the code, a developer can quickly see ++ * where problems are occurring. ++ * ++ * This is intended as a debugging tool for the developer only. ++ * Please refrain from leaving trace_puts scattered around in ++ * your code. (Extra memory is used for special buffers that are ++ * allocated when trace_puts() is used.) ++ * ++ * Returns: 0 if nothing was written, positive # if string was. ++ * (1 when __trace_bputs is used, strlen(str) when __trace_puts is used) ++ */ ++ ++#define trace_puts(str) ({ \ ++ static const char *trace_printk_fmt __used \ ++ __section("__trace_printk_fmt") = \ ++ __builtin_constant_p(str) ? str : NULL; \ ++ \ ++ if (__builtin_constant_p(str)) \ ++ __trace_bputs(_THIS_IP_, trace_printk_fmt); \ ++ else \ ++ __trace_puts(_THIS_IP_, str); \ ++}) ++extern int __trace_bputs(unsigned long ip, const char *str); ++extern int __trace_puts(unsigned long ip, const char *str); ++ ++extern void trace_dump_stack(int skip); ++ ++/* ++ * The double __builtin_constant_p is because gcc will give us an error ++ * if we try to allocate the static variable to fmt if it is not a ++ * constant. Even with the outer if statement. ++ */ ++#define ftrace_vprintk(fmt, vargs) \ ++do { \ ++ if (__builtin_constant_p(fmt)) { \ ++ static const char *trace_printk_fmt __used \ ++ __section("__trace_printk_fmt") = \ ++ __builtin_constant_p(fmt) ? fmt : NULL; \ ++ \ ++ __ftrace_vbprintk(_THIS_IP_, trace_printk_fmt, vargs); \ ++ } else \ ++ __ftrace_vprintk(_THIS_IP_, fmt, vargs); \ ++} while (0) ++ ++extern __printf(2, 0) int ++__ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap); ++ ++extern __printf(2, 0) int ++__ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap); ++ ++extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode); ++#else ++static inline void tracing_start(void) { } ++static inline void tracing_stop(void) { } ++static inline void trace_dump_stack(int skip) { } ++ ++static inline void tracing_on(void) { } ++static inline void tracing_off(void) { } ++static inline int tracing_is_on(void) { return 0; } ++static inline void tracing_snapshot(void) { } ++static inline void tracing_snapshot_alloc(void) { } ++ ++static inline __printf(1, 2) ++int trace_printk(const char *fmt, ...) ++{ ++ return 0; ++} ++static __printf(1, 0) inline int ++ftrace_vprintk(const char *fmt, va_list ap) ++{ ++ return 0; ++} ++static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } ++#endif /* CONFIG_TRACING */ ++ ++#endif +-- +2.53.0 + diff --git a/queue-6.18/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch b/queue-6.18/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch new file mode 100644 index 0000000000..3d7cb8a979 --- /dev/null +++ b/queue-6.18/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch @@ -0,0 +1,56 @@ +From eff0b6dd4275682b25d51a68713198a7b34a7d14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 19:22:23 +0800 +Subject: tracing: Rebuild full_name on each hist_field_name() call + +From: Pengpeng Hou + +[ Upstream commit 5ec1d1e97de134beed3a5b08235a60fc1c51af96 ] + +hist_field_name() uses a static MAX_FILTER_STR_VAL buffer for fully +qualified variable-reference names, but it currently appends into that +buffer with strcat() without rebuilding it first. As a result, repeated +calls append a new "system.event.field" name onto the previous one, +which can eventually run past the end of full_name. + +Build the name with snprintf() on each call and return NULL if the fully +qualified name does not fit in MAX_FILTER_STR_VAL. + +Link: https://patch.msgid.link/20260401112224.85582-1-pengpeng@iscas.ac.cn +Fixes: 067fe038e70f ("tracing: Add variable reference handling to hist triggers") +Reviewed-by: Tom Zanussi +Tested-by: Tom Zanussi +Signed-off-by: Pengpeng Hou +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 2a0726e1bc97f..cb9e067138683 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -1355,12 +1355,14 @@ static const char *hist_field_name(struct hist_field *field, + field->flags & HIST_FIELD_FL_VAR_REF) { + if (field->system) { + static char full_name[MAX_FILTER_STR_VAL]; ++ int len; ++ ++ len = snprintf(full_name, sizeof(full_name), "%s.%s.%s", ++ field->system, field->event_name, ++ field->name); ++ if (len >= sizeof(full_name)) ++ return NULL; + +- strcat(full_name, field->system); +- strcat(full_name, "."); +- strcat(full_name, field->event_name); +- strcat(full_name, "."); +- strcat(full_name, field->name); + field_name = full_name; + } else + field_name = field->name; +-- +2.53.0 + diff --git a/queue-6.18/tracing-remove-size-parameter-in-__trace_puts.patch b/queue-6.18/tracing-remove-size-parameter-in-__trace_puts.patch new file mode 100644 index 0000000000..b8804f4da5 --- /dev/null +++ b/queue-6.18/tracing-remove-size-parameter-in-__trace_puts.patch @@ -0,0 +1,102 @@ +From 6f7941bc8bfddbc8efcab7b793833f90e9dc9352 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 23:25:08 -0500 +Subject: tracing: remove size parameter in __trace_puts() + +From: Steven Rostedt + +[ Upstream commit 86e685ff364394b477cd1c476029480a2a1960c5 ] + +The __trace_puts() function takes a string pointer and the size of the +string itself. All users currently simply pass in the strlen() of the +string it is also passing in. There's no reason to pass in the size. +Instead have the __trace_puts() function do the strlen() within the +function itself. + +This fixes a header recursion issue where using strlen() in the macro +calling __trace_puts() requires adding #include in order +to use strlen(). Removing the use of strlen() from the header fixes the +recursion issue. + +Link: https://lore.kernel.org/all/aUN8Hm377C5A0ILX@yury/ +Link: https://lkml.kernel.org/r/20260116042510.241009-6-ynorov@nvidia.com +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Yury Norov +Reviewed-by: Andy Shevchenko +Reviewed-by: Joel Fernandes +Cc: Aaron Tomlin +Cc: Andi Shyti +Cc: Christophe Leroy (CS GROUP) +Cc: Greg Kroah-Hartman +Cc: Jani Nikula +Cc: Petr Pavlu +Cc: Randy Dunlap +Signed-off-by: Andrew Morton +Stable-dep-of: 473e470f16f9 ("tracing: move __printf() attribute on __ftrace_vbprintk()") +Signed-off-by: Sasha Levin +--- + include/linux/kernel.h | 4 ++-- + kernel/trace/trace.c | 7 +++---- + kernel/trace/trace.h | 2 +- + 3 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/include/linux/kernel.h b/include/linux/kernel.h +index 5b46924fdff52..d5a939b8c3911 100644 +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -331,10 +331,10 @@ int __trace_printk(unsigned long ip, const char *fmt, ...); + if (__builtin_constant_p(str)) \ + __trace_bputs(_THIS_IP_, trace_printk_fmt); \ + else \ +- __trace_puts(_THIS_IP_, str, strlen(str)); \ ++ __trace_puts(_THIS_IP_, str); \ + }) + extern int __trace_bputs(unsigned long ip, const char *str); +-extern int __trace_puts(unsigned long ip, const char *str, int size); ++extern int __trace_puts(unsigned long ip, const char *str); + + extern void trace_dump_stack(int skip); + +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 2be9e47d64b08..55c9f51a2fda0 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -1180,11 +1180,10 @@ EXPORT_SYMBOL_GPL(__trace_array_puts); + * __trace_puts - write a constant string into the trace buffer. + * @ip: The address of the caller + * @str: The constant string to write +- * @size: The size of the string. + */ +-int __trace_puts(unsigned long ip, const char *str, int size) ++int __trace_puts(unsigned long ip, const char *str) + { +- return __trace_array_puts(printk_trace, ip, str, size); ++ return __trace_array_puts(printk_trace, ip, str, strlen(str)); + } + EXPORT_SYMBOL_GPL(__trace_puts); + +@@ -1203,7 +1202,7 @@ int __trace_bputs(unsigned long ip, const char *str) + int size = sizeof(struct bputs_entry); + + if (!printk_binsafe(tr)) +- return __trace_puts(ip, str, strlen(str)); ++ return __trace_puts(ip, str); + + if (!(tr->trace_flags & TRACE_ITER_PRINTK)) + return 0; +diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h +index ec372e0f2e716..62d5a5f224c4a 100644 +--- a/kernel/trace/trace.h ++++ b/kernel/trace/trace.h +@@ -2099,7 +2099,7 @@ extern void tracing_log_err(struct trace_array *tr, + * about performance). The internal_trace_puts() is for such + * a purpose. + */ +-#define internal_trace_puts(str) __trace_puts(_THIS_IP_, str, strlen(str)) ++#define internal_trace_puts(str) __trace_puts(_THIS_IP_, str) + + #undef FTRACE_ENTRY + #define FTRACE_ENTRY(call, struct_name, id, tstruct, print) \ +-- +2.53.0 + diff --git a/queue-6.18/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch b/queue-6.18/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch new file mode 100644 index 0000000000..e54b74891b --- /dev/null +++ b/queue-6.18/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch @@ -0,0 +1,50 @@ +From ecfa07707b0e900a6b3587d16d32463c2a5e25ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 23:29:37 -0800 +Subject: tty: hvc_iucv: fix off-by-one in number of supported devices + +From: Randy Dunlap + +[ Upstream commit f2a880e802ad12d1e38039d1334fb1475d0f5241 ] + +MAX_HVC_IUCV_LINES == HVC_ALLOC_TTY_ADAPTERS == 8. +This is the number of entries in: + static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; + +Sometimes hvc_iucv_table[] is limited by: +(a) if (num > hvc_iucv_devices) // for error detection +or +(b) for (i = 0; i < hvc_iucv_devices; i++) // in 2 places +(so these 2 don't agree; second one appears to be correct to me.) + +hvc_iucv_devices can be 0..8. This is a counter. +(c) if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + +If hvc_iucv_devices == 8, (a) allows the code to access hvc_iucv_table[8]. +Oops. + +Fixes: 44a01d5ba8a4 ("[S390] s390/hvc_console: z/VM IUCV hypervisor console support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260130072939.1535869-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index 4ca7472c38e01..612e13b6f22bc 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -131,7 +131,7 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if (num > hvc_iucv_devices) ++ if (num >= hvc_iucv_devices) + return NULL; + return hvc_iucv_table[num]; + } +-- +2.53.0 + diff --git a/queue-6.18/tty-serial-ip22zilog-fix-section-mispatch-warning.patch b/queue-6.18/tty-serial-ip22zilog-fix-section-mispatch-warning.patch new file mode 100644 index 0000000000..6e40e4f117 --- /dev/null +++ b/queue-6.18/tty-serial-ip22zilog-fix-section-mispatch-warning.patch @@ -0,0 +1,39 @@ +From f14f14567ceb19981e7202bfcca23ff90709ce98 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 12:21:53 +0200 +Subject: tty: serial: ip22zilog: Fix section mispatch warning + +From: Thomas Bogendoerfer + +[ Upstream commit a1a81aef99e853dec84241d701fbf587d713eb5b ] + +ip22zilog_prepare() is now called by driver probe routine, so it +shouldn't be in the __init section any longer. + +Fixes: 3fc36ae6abd2 ("tty: serial: ip22zilog: Use platform device for probing") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604020945.c9jAvCPs-lkp@intel.com/ +Signed-off-by: Thomas Bogendoerfer +Link: https://patch.msgid.link/20260402102154.136620-1-tbogendoerfer@suse.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/ip22zilog.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c +index 6e19c6713849a..a12101dc05546 100644 +--- a/drivers/tty/serial/ip22zilog.c ++++ b/drivers/tty/serial/ip22zilog.c +@@ -1025,7 +1025,7 @@ static struct uart_driver ip22zilog_reg = { + #endif + }; + +-static void __init ip22zilog_prepare(struct uart_ip22zilog_port *up) ++static void ip22zilog_prepare(struct uart_ip22zilog_port *up) + { + unsigned char sysrq_on = IS_ENABLED(CONFIG_SERIAL_IP22_ZILOG_CONSOLE); + int brg; +-- +2.53.0 + diff --git a/queue-6.18/udp-force-compute_score-to-always-inline.patch b/queue-6.18/udp-force-compute_score-to-always-inline.patch new file mode 100644 index 0000000000..a89bad5e7d --- /dev/null +++ b/queue-6.18/udp-force-compute_score-to-always-inline.patch @@ -0,0 +1,125 @@ +From bbdafd86934670622ccd66ba054df203403e30d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:59:36 -0400 +Subject: udp: Force compute_score to always inline + +From: Gabriel Krisman Bertazi + +[ Upstream commit b80a95ccf1604a882bb153c45ccb4056e44c8edb ] + +Back in 2024 I reported a 7-12% regression on an iperf3 UDP loopback +thoughput test that we traced to the extra overhead of calling +compute_score on two places, introduced by commit f0ea27e7bfe1 ("udp: +re-score reuseport groups when connected sockets are present"). At the +time, I pointed out the overhead was caused by the multiple calls, +associated with cpu-specific mitigations, and merged commit +50aee97d1511 ("udp: Avoid call to compute_score on multiple sites") to +jump back explicitly, to force the rescore call in a single place. + +Recently though, we got another regression report against a newer distro +version, which a team colleague traced back to the same root-cause. +Turns out that once we updated to gcc-13, the compiler got smart enough +to unroll the loop, undoing my previous mitigation. Let's bite the +bullet and __always_inline compute_score on both ipv4 and ipv6 to +prevent gcc from de-optimizing it again in the future. These functions +are only called in two places each, udpX_lib_lookup1 and +udpX_lib_lookup2, so the extra size shouldn't be a problem and it is hot +enough to be very visible in profilings. In fact, with gcc13, forcing +the inline will prevent gcc from unrolling the fix from commit +50aee97d1511, so we don't end up increasing udpX_lib_lookup2 at all. + +I haven't recollected the results myself, as I don't have access to the +machine at the moment. But the same colleague reported 4.67% +inprovement with this patch in the loopback benchmark, solving the +regression report within noise margins. + +Eric Dumazet reported no size change to vmlinux when built with clang. +I report the same also with gcc-13: + +scripts/bloat-o-meter vmlinux vmlinux-inline +add/remove: 0/2 grow/shrink: 4/0 up/down: 616/-416 (200) +Function old new delta +udp6_lib_lookup2 762 949 +187 +__udp6_lib_lookup 810 975 +165 +udp4_lib_lookup2 757 906 +149 +__udp4_lib_lookup 871 986 +115 +__pfx_compute_score 32 - -32 +compute_score 384 - -384 +Total: Before=35011784, After=35011984, chg +0.00% + +Fixes: 50aee97d1511 ("udp: Avoid call to compute_score on multiple sites") +Reviewed-by: Eric Dumazet +Acked-by: Willem de Bruijn +Signed-off-by: Gabriel Krisman Bertazi +Link: https://patch.msgid.link/20260410155936.654915-1-krisman@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/udp.c | 12 ++++++------ + net/ipv6/udp.c | 13 +++++++------ + 2 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index de0deded74f0a..a55642a42e82f 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -365,10 +365,10 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum) + return udp_lib_get_port(sk, snum, hash2_nulladdr); + } + +-static int compute_score(struct sock *sk, const struct net *net, +- __be32 saddr, __be16 sport, +- __be32 daddr, unsigned short hnum, +- int dif, int sdif) ++static __always_inline int ++compute_score(struct sock *sk, const struct net *net, ++ __be32 saddr, __be16 sport, __be32 daddr, ++ unsigned short hnum, int dif, int sdif) + { + int score; + struct inet_sock *inet; +@@ -508,8 +508,8 @@ static struct sock *udp4_lib_lookup2(const struct net *net, + continue; + + /* compute_score is too long of a function to be +- * inlined, and calling it again here yields +- * measurable overhead for some ++ * inlined twice here, and calling it uninlined ++ * here yields measurable overhead for some + * workloads. Work around it by jumping + * backwards to rescore 'result'. + */ +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index 813a2ba75824d..d47b4f5ac8705 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -127,10 +127,11 @@ void udp_v6_rehash(struct sock *sk) + udp_lib_rehash(sk, new_hash, new_hash4); + } + +-static int compute_score(struct sock *sk, const struct net *net, +- const struct in6_addr *saddr, __be16 sport, +- const struct in6_addr *daddr, unsigned short hnum, +- int dif, int sdif) ++static __always_inline int ++compute_score(struct sock *sk, const struct net *net, ++ const struct in6_addr *saddr, __be16 sport, ++ const struct in6_addr *daddr, unsigned short hnum, ++ int dif, int sdif) + { + int bound_dev_if, score; + struct inet_sock *inet; +@@ -260,8 +261,8 @@ static struct sock *udp6_lib_lookup2(const struct net *net, + continue; + + /* compute_score is too long of a function to be +- * inlined, and calling it again here yields +- * measurable overhead for some ++ * inlined twice here, and calling it uninlined ++ * here yields measurable overhead for some + * workloads. Work around it by jumping + * backwards to rescore 'result'. + */ +-- +2.53.0 + diff --git a/queue-6.18/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch b/queue-6.18/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch new file mode 100644 index 0000000000..93506dba18 --- /dev/null +++ b/queue-6.18/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch @@ -0,0 +1,91 @@ +From 1da203fd75443edcbcdad5b96606615f873bff21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 11:39:59 -0800 +Subject: unshare: fix nsproxy leak in ksys_unshare() on set_cred_ucounts() + failure + +From: Michal Grzedzicki + +[ Upstream commit a98621a0f187a934c115dcfe79a49520ae892111 ] + +When set_cred_ucounts() fails in ksys_unshare() new_nsproxy is leaked. + +Let's call put_nsproxy() if that happens. + +Link: https://lkml.kernel.org/r/20260213193959.2556730-1-mge@meta.com +Fixes: 905ae01c4ae2 ("Add a reference to ucounts for each cred") +Signed-off-by: Michal Grzedzicki +Reviewed-by: Andrew Morton +Cc: Alexey Gladkov (Intel) +Cc: Ben Segall +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: "Liam R. Howlett" +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 34e6b94c22129..3ad76c2cf5af5 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -3132,11 +3132,10 @@ int ksys_unshare(unsigned long unshare_flags) + new_cred, new_fs); + if (err) + goto bad_unshare_cleanup_cred; +- + if (new_cred) { + err = set_cred_ucounts(new_cred); + if (err) +- goto bad_unshare_cleanup_cred; ++ goto bad_unshare_cleanup_nsproxy; + } + + if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { +@@ -3152,8 +3151,10 @@ int ksys_unshare(unsigned long unshare_flags) + shm_init_task(current); + } + +- if (new_nsproxy) ++ if (new_nsproxy) { + switch_task_namespaces(current, new_nsproxy); ++ new_nsproxy = NULL; ++ } + + task_lock(current); + +@@ -3182,13 +3183,15 @@ int ksys_unshare(unsigned long unshare_flags) + + perf_event_namespaces(current); + ++bad_unshare_cleanup_nsproxy: ++ if (new_nsproxy) ++ put_nsproxy(new_nsproxy); + bad_unshare_cleanup_cred: + if (new_cred) + put_cred(new_cred); + bad_unshare_cleanup_fd: + if (new_fd) + put_files_struct(new_fd); +- + bad_unshare_cleanup_fs: + if (new_fs) + free_fs_struct(new_fs); +-- +2.53.0 + diff --git a/queue-6.18/usb-dwc3-add-dwc-pointer-to-dwc3_readl-writel.patch b/queue-6.18/usb-dwc3-add-dwc-pointer-to-dwc3_readl-writel.patch new file mode 100644 index 0000000000..f3171f8463 --- /dev/null +++ b/queue-6.18/usb-dwc3-add-dwc-pointer-to-dwc3_readl-writel.patch @@ -0,0 +1,1715 @@ +From 8f8d2db8e130c129af25d83ffb8ed18f7f95baea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 07:27:43 -0400 +Subject: usb: dwc3: Add dwc pointer to dwc3_readl/writel + +From: Prashanth K + +[ Upstream commit 9accc68b1cf0a2b220f51d53641128bb32598070 ] + +Use dwc pointer in dwc3_readl() dwc3_writel() instead of passing +the dwc->regs. This would help us access the dwc structure and +log the base address in traces. There's no functional changes in +this patch, just refactoring existing APIs. + +Signed-off-by: Prashanth K +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260114100748.2950103-3-prashanth.k@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: aad35f9c926e ("usb: dwc3: Move GUID programming after PHY initialization") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/core.c | 194 ++++++++++++++++++------------------- + drivers/usb/dwc3/debugfs.c | 32 +++--- + drivers/usb/dwc3/drd.c | 76 +++++++-------- + drivers/usb/dwc3/ep0.c | 20 ++-- + drivers/usb/dwc3/gadget.c | 160 +++++++++++++++--------------- + drivers/usb/dwc3/gadget.h | 4 +- + drivers/usb/dwc3/io.h | 7 +- + drivers/usb/dwc3/ulpi.c | 10 +- + 8 files changed, 253 insertions(+), 250 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index c6b7df5682b4e..c5bec0bd9cb10 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -114,23 +114,23 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable) + int i; + + for (i = 0; i < dwc->num_usb3_ports; i++) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(i)); ++ reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(i)); + if (enable && !dwc->dis_u3_susphy_quirk) + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + else + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + +- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(i), reg); ++ dwc3_writel(dwc, DWC3_GUSB3PIPECTL(i), reg); + } + + for (i = 0; i < dwc->num_usb2_ports; i++) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(i)); + if (enable && !dwc->dis_u2_susphy_quirk) + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + else + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(i), reg); + } + } + +@@ -139,7 +139,7 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy) + unsigned int hw_mode; + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_GCTL); ++ reg = dwc3_readl(dwc, DWC3_GCTL); + + /* + * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE and +@@ -154,7 +154,7 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy) + + reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); + reg |= DWC3_GCTL_PRTCAPDIR(mode); +- dwc3_writel(dwc->regs, DWC3_GCTL, reg); ++ dwc3_writel(dwc, DWC3_GCTL, reg); + + dwc->current_dr_role = mode; + trace_dwc3_set_prtcap(mode); +@@ -214,9 +214,9 @@ static void __dwc3_set_mode(struct work_struct *work) + if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) || + DWC3_VER_IS_PRIOR(DWC31, 190A)) && + desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) { +- reg = dwc3_readl(dwc->regs, DWC3_GCTL); ++ reg = dwc3_readl(dwc, DWC3_GCTL); + reg |= DWC3_GCTL_CORESOFTRESET; +- dwc3_writel(dwc->regs, DWC3_GCTL, reg); ++ dwc3_writel(dwc, DWC3_GCTL, reg); + + /* + * Wait for internal clocks to synchronized. DWC_usb31 and +@@ -226,9 +226,9 @@ static void __dwc3_set_mode(struct work_struct *work) + */ + msleep(100); + +- reg = dwc3_readl(dwc->regs, DWC3_GCTL); ++ reg = dwc3_readl(dwc, DWC3_GCTL); + reg &= ~DWC3_GCTL_CORESOFTRESET; +- dwc3_writel(dwc->regs, DWC3_GCTL, reg); ++ dwc3_writel(dwc, DWC3_GCTL, reg); + } + + spin_lock_irqsave(&dwc->lock, flags); +@@ -252,9 +252,9 @@ static void __dwc3_set_mode(struct work_struct *work) + phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); + + if (dwc->dis_split_quirk) { +- reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); ++ reg = dwc3_readl(dwc, DWC3_GUCTL3); + reg |= DWC3_GUCTL3_SPLITDISABLE; +- dwc3_writel(dwc->regs, DWC3_GUCTL3, reg); ++ dwc3_writel(dwc, DWC3_GUCTL3, reg); + } + } + break; +@@ -305,11 +305,11 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) + struct dwc3 *dwc = dep->dwc; + u32 reg; + +- dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE, +- DWC3_GDBGFIFOSPACE_NUM(dep->number) | +- DWC3_GDBGFIFOSPACE_TYPE(type)); ++ dwc3_writel(dwc, DWC3_GDBGFIFOSPACE, ++ DWC3_GDBGFIFOSPACE_NUM(dep->number) | ++ DWC3_GDBGFIFOSPACE_TYPE(type)); + +- reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE); ++ reg = dwc3_readl(dwc, DWC3_GDBGFIFOSPACE); + + return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg); + } +@@ -331,7 +331,7 @@ int dwc3_core_soft_reset(struct dwc3 *dwc) + if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) + return 0; + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg |= DWC3_DCTL_CSFTRST; + reg &= ~DWC3_DCTL_RUN_STOP; + dwc3_gadget_dctl_write_safe(dwc, reg); +@@ -346,7 +346,7 @@ int dwc3_core_soft_reset(struct dwc3 *dwc) + retries = 10; + + do { +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + if (!(reg & DWC3_DCTL_CSFTRST)) + goto done; + +@@ -386,12 +386,12 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc) + if (dwc->fladj == 0) + return; + +- reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); ++ reg = dwc3_readl(dwc, DWC3_GFLADJ); + dft = reg & DWC3_GFLADJ_30MHZ_MASK; + if (dft != dwc->fladj) { + reg &= ~DWC3_GFLADJ_30MHZ_MASK; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; +- dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); ++ dwc3_writel(dwc, DWC3_GFLADJ, reg); + } + } + +@@ -423,10 +423,10 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc) + return; + } + +- reg = dwc3_readl(dwc->regs, DWC3_GUCTL); ++ reg = dwc3_readl(dwc, DWC3_GUCTL); + reg &= ~DWC3_GUCTL_REFCLKPER_MASK; + reg |= FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, period); +- dwc3_writel(dwc->regs, DWC3_GUCTL, reg); ++ dwc3_writel(dwc, DWC3_GUCTL, reg); + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; +@@ -454,7 +454,7 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc) + */ + decr = 480000000 / rate; + +- reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); ++ reg = dwc3_readl(dwc, DWC3_GFLADJ); + reg &= ~DWC3_GFLADJ_REFCLK_FLADJ_MASK + & ~DWC3_GFLADJ_240MHZDECR + & ~DWC3_GFLADJ_240MHZDECR_PLS1; +@@ -465,7 +465,7 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc) + if (dwc->gfladj_refclk_lpm_sel) + reg |= DWC3_GFLADJ_REFCLK_LPM_SEL; + +- dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); ++ dwc3_writel(dwc, DWC3_GFLADJ, reg); + } + + /** +@@ -568,16 +568,16 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc) + + evt = dwc->ev_buf; + evt->lpos = 0; +- dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), +- lower_32_bits(evt->dma)); +- dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), +- upper_32_bits(evt->dma)); +- dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), +- DWC3_GEVNTSIZ_SIZE(evt->length)); ++ dwc3_writel(dwc, DWC3_GEVNTADRLO(0), ++ lower_32_bits(evt->dma)); ++ dwc3_writel(dwc, DWC3_GEVNTADRHI(0), ++ upper_32_bits(evt->dma)); ++ dwc3_writel(dwc, DWC3_GEVNTSIZ(0), ++ DWC3_GEVNTSIZ_SIZE(evt->length)); + + /* Clear any stale event */ +- reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); +- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg); ++ reg = dwc3_readl(dwc, DWC3_GEVNTCOUNT(0)); ++ dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), reg); + return 0; + } + +@@ -592,7 +592,7 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc) + * Exynos platforms may not be able to access event buffer if the + * controller failed to halt on dwc3_core_exit(). + */ +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + if (!(reg & DWC3_DSTS_DEVCTRLHLT)) + return; + +@@ -600,14 +600,14 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc) + + evt->lpos = 0; + +- dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0); +- dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0); +- dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK ++ dwc3_writel(dwc, DWC3_GEVNTADRLO(0), 0); ++ dwc3_writel(dwc, DWC3_GEVNTADRHI(0), 0); ++ dwc3_writel(dwc, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK + | DWC3_GEVNTSIZ_SIZE(0)); + + /* Clear any stale event */ +- reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); +- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg); ++ reg = dwc3_readl(dwc, DWC3_GEVNTCOUNT(0)); ++ dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), reg); + } + + static void dwc3_core_num_eps(struct dwc3 *dwc) +@@ -621,18 +621,18 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) + { + struct dwc3_hwparams *parms = &dwc->hwparams; + +- parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0); +- parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1); +- parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2); +- parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); +- parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4); +- parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5); +- parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); +- parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); +- parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); ++ parms->hwparams0 = dwc3_readl(dwc, DWC3_GHWPARAMS0); ++ parms->hwparams1 = dwc3_readl(dwc, DWC3_GHWPARAMS1); ++ parms->hwparams2 = dwc3_readl(dwc, DWC3_GHWPARAMS2); ++ parms->hwparams3 = dwc3_readl(dwc, DWC3_GHWPARAMS3); ++ parms->hwparams4 = dwc3_readl(dwc, DWC3_GHWPARAMS4); ++ parms->hwparams5 = dwc3_readl(dwc, DWC3_GHWPARAMS5); ++ parms->hwparams6 = dwc3_readl(dwc, DWC3_GHWPARAMS6); ++ parms->hwparams7 = dwc3_readl(dwc, DWC3_GHWPARAMS7); ++ parms->hwparams8 = dwc3_readl(dwc, DWC3_GHWPARAMS8); + + if (DWC3_IP_IS(DWC32)) +- parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9); ++ parms->hwparams9 = dwc3_readl(dwc, DWC3_GHWPARAMS9); + } + + static void dwc3_config_soc_bus(struct dwc3 *dwc) +@@ -640,10 +640,10 @@ static void dwc3_config_soc_bus(struct dwc3 *dwc) + if (dwc->gsbuscfg0_reqinfo != DWC3_GSBUSCFG0_REQINFO_UNSPECIFIED) { + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0); ++ reg = dwc3_readl(dwc, DWC3_GSBUSCFG0); + reg &= ~DWC3_GSBUSCFG0_REQINFO(~0); + reg |= DWC3_GSBUSCFG0_REQINFO(dwc->gsbuscfg0_reqinfo); +- dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg); ++ dwc3_writel(dwc, DWC3_GSBUSCFG0, reg); + } + } + +@@ -667,7 +667,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index) + { + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(index)); ++ reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(index)); + + /* + * Make sure UX_EXIT_PX is cleared as that causes issues with some +@@ -705,7 +705,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index) + if (dwc->dis_del_phy_power_chg_quirk) + reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; + +- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(index), reg); ++ dwc3_writel(dwc, DWC3_GUSB3PIPECTL(index), reg); + + return 0; + } +@@ -714,7 +714,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) + { + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(index)); + + /* Select the HS PHY interface */ + switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { +@@ -726,7 +726,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) + } else if (dwc->hsphy_interface && + !strncmp(dwc->hsphy_interface, "ulpi", 4)) { + reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg); + } else { + /* Relying on default value. */ + if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) +@@ -776,7 +776,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index) + if (dwc->ulpi_ext_vbus_drv) + reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV; + +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg); + + return 0; + } +@@ -989,7 +989,7 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) + { + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); ++ reg = dwc3_readl(dwc, DWC3_GSNPSID); + dwc->ip = DWC3_GSNPS_ID(reg); + if (dwc->ip == DWC4_IP) + dwc->ip = DWC32_IP; +@@ -998,8 +998,8 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) + if (DWC3_IP_IS(DWC3)) { + dwc->revision = reg; + } else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) { +- dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER); +- dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE); ++ dwc->revision = dwc3_readl(dwc, DWC3_VER_NUMBER); ++ dwc->version_type = dwc3_readl(dwc, DWC3_VER_TYPE); + } else { + return false; + } +@@ -1013,7 +1013,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) + unsigned int hw_mode; + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_GCTL); ++ reg = dwc3_readl(dwc, DWC3_GCTL); + reg &= ~DWC3_GCTL_SCALEDOWN_MASK; + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + power_opt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1); +@@ -1091,7 +1091,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) + if (DWC3_VER_IS_PRIOR(DWC3, 190A)) + reg |= DWC3_GCTL_U2RSTECN; + +- dwc3_writel(dwc->regs, DWC3_GCTL, reg); ++ dwc3_writel(dwc, DWC3_GCTL, reg); + } + + static int dwc3_core_get_phy(struct dwc3 *dwc); +@@ -1111,7 +1111,7 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) + int ret; + int i; + +- cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0); ++ cfg = dwc3_readl(dwc, DWC3_GSBUSCFG0); + + /* + * Handle property "snps,incr-burst-type-adjustment". +@@ -1186,7 +1186,7 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) + break; + } + +- dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg); ++ dwc3_writel(dwc, DWC3_GSBUSCFG0, cfg); + } + + static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc) +@@ -1211,12 +1211,12 @@ static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc) + * (3x or more) to be within the requirement. + */ + scale = DIV_ROUND_UP(clk_get_rate(dwc->susp_clk), 16000); +- reg = dwc3_readl(dwc->regs, DWC3_GCTL); ++ reg = dwc3_readl(dwc, DWC3_GCTL); + if ((reg & DWC3_GCTL_PWRDNSCALE_MASK) < DWC3_GCTL_PWRDNSCALE(scale) || + (reg & DWC3_GCTL_PWRDNSCALE_MASK) > DWC3_GCTL_PWRDNSCALE(scale*3)) { + reg &= ~(DWC3_GCTL_PWRDNSCALE_MASK); + reg |= DWC3_GCTL_PWRDNSCALE(scale); +- dwc3_writel(dwc->regs, DWC3_GCTL, reg); ++ dwc3_writel(dwc, DWC3_GCTL, reg); + } + } + +@@ -1239,7 +1239,7 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + tx_maxburst = dwc->tx_max_burst_prd; + + if (rx_thr_num && rx_maxburst) { +- reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); ++ reg = dwc3_readl(dwc, DWC3_GRXTHRCFG); + reg |= DWC31_RXTHRNUMPKTSEL_PRD; + + reg &= ~DWC31_RXTHRNUMPKT_PRD(~0); +@@ -1248,11 +1248,11 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + reg &= ~DWC31_MAXRXBURSTSIZE_PRD(~0); + reg |= DWC31_MAXRXBURSTSIZE_PRD(rx_maxburst); + +- dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); ++ dwc3_writel(dwc, DWC3_GRXTHRCFG, reg); + } + + if (tx_thr_num && tx_maxburst) { +- reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG); ++ reg = dwc3_readl(dwc, DWC3_GTXTHRCFG); + reg |= DWC31_TXTHRNUMPKTSEL_PRD; + + reg &= ~DWC31_TXTHRNUMPKT_PRD(~0); +@@ -1261,7 +1261,7 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + reg &= ~DWC31_MAXTXBURSTSIZE_PRD(~0); + reg |= DWC31_MAXTXBURSTSIZE_PRD(tx_maxburst); + +- dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg); ++ dwc3_writel(dwc, DWC3_GTXTHRCFG, reg); + } + } + +@@ -1272,7 +1272,7 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + + if (DWC3_IP_IS(DWC3)) { + if (rx_thr_num && rx_maxburst) { +- reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); ++ reg = dwc3_readl(dwc, DWC3_GRXTHRCFG); + reg |= DWC3_GRXTHRCFG_PKTCNTSEL; + + reg &= ~DWC3_GRXTHRCFG_RXPKTCNT(~0); +@@ -1281,11 +1281,11 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + reg &= ~DWC3_GRXTHRCFG_MAXRXBURSTSIZE(~0); + reg |= DWC3_GRXTHRCFG_MAXRXBURSTSIZE(rx_maxburst); + +- dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); ++ dwc3_writel(dwc, DWC3_GRXTHRCFG, reg); + } + + if (tx_thr_num && tx_maxburst) { +- reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG); ++ reg = dwc3_readl(dwc, DWC3_GTXTHRCFG); + reg |= DWC3_GTXTHRCFG_PKTCNTSEL; + + reg &= ~DWC3_GTXTHRCFG_TXPKTCNT(~0); +@@ -1294,11 +1294,11 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + reg &= ~DWC3_GTXTHRCFG_MAXTXBURSTSIZE(~0); + reg |= DWC3_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst); + +- dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg); ++ dwc3_writel(dwc, DWC3_GTXTHRCFG, reg); + } + } else { + if (rx_thr_num && rx_maxburst) { +- reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); ++ reg = dwc3_readl(dwc, DWC3_GRXTHRCFG); + reg |= DWC31_GRXTHRCFG_PKTCNTSEL; + + reg &= ~DWC31_GRXTHRCFG_RXPKTCNT(~0); +@@ -1307,11 +1307,11 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + reg &= ~DWC31_GRXTHRCFG_MAXRXBURSTSIZE(~0); + reg |= DWC31_GRXTHRCFG_MAXRXBURSTSIZE(rx_maxburst); + +- dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); ++ dwc3_writel(dwc, DWC3_GRXTHRCFG, reg); + } + + if (tx_thr_num && tx_maxburst) { +- reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG); ++ reg = dwc3_readl(dwc, DWC3_GTXTHRCFG); + reg |= DWC31_GTXTHRCFG_PKTCNTSEL; + + reg &= ~DWC31_GTXTHRCFG_TXPKTCNT(~0); +@@ -1320,7 +1320,7 @@ static void dwc3_config_threshold(struct dwc3 *dwc) + reg &= ~DWC31_GTXTHRCFG_MAXTXBURSTSIZE(~0); + reg |= DWC31_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst); + +- dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg); ++ dwc3_writel(dwc, DWC3_GTXTHRCFG, reg); + } + } + } +@@ -1343,7 +1343,7 @@ static int dwc3_core_init(struct dwc3 *dwc) + * Write Linux Version Code to our GUID register so it's easy to figure + * out which kernel version a bug was found. + */ +- dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); ++ dwc3_writel(dwc, DWC3_GUID, LINUX_VERSION_CODE); + + ret = dwc3_phy_setup(dwc); + if (ret) +@@ -1408,9 +1408,9 @@ static int dwc3_core_init(struct dwc3 *dwc) + * DWC_usb31 controller. + */ + if (DWC3_VER_IS_WITHIN(DWC3, 310A, ANY)) { +- reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); ++ reg = dwc3_readl(dwc, DWC3_GUCTL2); + reg |= DWC3_GUCTL2_RST_ACTBITLATER; +- dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); ++ dwc3_writel(dwc, DWC3_GUCTL2, reg); + } + + /* +@@ -1423,9 +1423,9 @@ static int dwc3_core_init(struct dwc3 *dwc) + * setting GUCTL2[19] by default; instead, use GUCTL2[19] = 0. + */ + if (DWC3_VER_IS(DWC3, 320A)) { +- reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); ++ reg = dwc3_readl(dwc, DWC3_GUCTL2); + reg &= ~DWC3_GUCTL2_LC_TIMER; +- dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); ++ dwc3_writel(dwc, DWC3_GUCTL2, reg); + } + + /* +@@ -1438,13 +1438,13 @@ static int dwc3_core_init(struct dwc3 *dwc) + * legacy ULPI PHYs. + */ + if (dwc->resume_hs_terminations) { +- reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); ++ reg = dwc3_readl(dwc, DWC3_GUCTL1); + reg |= DWC3_GUCTL1_RESUME_OPMODE_HS_HOST; +- dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); ++ dwc3_writel(dwc, DWC3_GUCTL1, reg); + } + + if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) { +- reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); ++ reg = dwc3_readl(dwc, DWC3_GUCTL1); + + /* + * Enable hardware control of sending remote wakeup +@@ -1479,7 +1479,7 @@ static int dwc3_core_init(struct dwc3 *dwc) + reg &= ~DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK; + } + +- dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); ++ dwc3_writel(dwc, DWC3_GUCTL1, reg); + } + + dwc3_config_threshold(dwc); +@@ -1494,9 +1494,9 @@ static int dwc3_core_init(struct dwc3 *dwc) + int i; + + for (i = 0; i < dwc->num_usb3_ports; i++) { +- reg = dwc3_readl(dwc->regs, DWC3_LLUCTL(i)); ++ reg = dwc3_readl(dwc, DWC3_LLUCTL(i)); + reg |= DWC3_LLUCTL_FORCE_GEN1; +- dwc3_writel(dwc->regs, DWC3_LLUCTL(i), reg); ++ dwc3_writel(dwc, DWC3_LLUCTL(i), reg); + } + } + +@@ -1515,9 +1515,9 @@ static int dwc3_core_init(struct dwc3 *dwc) + * function is available only from version 1.70a. + */ + if (DWC3_VER_IS_WITHIN(DWC31, 170A, 180A)) { +- reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); ++ reg = dwc3_readl(dwc, DWC3_GUCTL3); + reg |= DWC3_GUCTL3_USB20_RETRY_DISABLE; +- dwc3_writel(dwc->regs, DWC3_GUCTL3, reg); ++ dwc3_writel(dwc, DWC3_GUCTL3, reg); + } + + return 0; +@@ -2447,9 +2447,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) + int ret; + + if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) { +- dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) & ++ dwc->susphy_state = (dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)) & + DWC3_GUSB2PHYCFG_SUSPHY) || +- (dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)) & ++ (dwc3_readl(dwc, DWC3_GUSB3PIPECTL(0)) & + DWC3_GUSB3PIPECTL_SUSPHY); + /* + * TI AM62 platform requires SUSPHY to be +@@ -2479,10 +2479,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) + if (dwc->dis_u2_susphy_quirk || + dwc->dis_enblslpm_quirk) { + for (i = 0; i < dwc->num_usb2_ports; i++) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(i)); + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM | + DWC3_GUSB2PHYCFG_SUSPHY; +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(i), reg); + } + + /* Give some time for USB2 PHY to suspend */ +@@ -2542,14 +2542,14 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) + } + /* Restore GUSB2PHYCFG bits that were modified in suspend */ + for (i = 0; i < dwc->num_usb2_ports; i++) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(i)); + if (dwc->dis_u2_susphy_quirk) + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + + if (dwc->dis_enblslpm_quirk) + reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(i), reg); + } + + for (i = 0; i < dwc->num_usb2_ports; i++) +@@ -2732,9 +2732,9 @@ void dwc3_pm_complete(struct dwc3 *dwc) + + if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST && + dwc->dis_split_quirk) { +- reg = dwc3_readl(dwc->regs, DWC3_GUCTL3); ++ reg = dwc3_readl(dwc, DWC3_GUCTL3); + reg |= DWC3_GUCTL3_SPLITDISABLE; +- dwc3_writel(dwc->regs, DWC3_GUCTL3, reg); ++ dwc3_writel(dwc, DWC3_GUCTL3, reg); + } + } + EXPORT_SYMBOL_GPL(dwc3_pm_complete); +diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c +index 0b45ff16f575b..ffb1101f55c7b 100644 +--- a/drivers/usb/dwc3/debugfs.c ++++ b/drivers/usb/dwc3/debugfs.c +@@ -296,14 +296,14 @@ static void dwc3_host_lsp(struct seq_file *s) + + reg = DWC3_GDBGLSPMUX_HOSTSELECT(sel); + +- dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg); +- val = dwc3_readl(dwc->regs, DWC3_GDBGLSP); ++ dwc3_writel(dwc, DWC3_GDBGLSPMUX, reg); ++ val = dwc3_readl(dwc, DWC3_GDBGLSP); + seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", sel, val); + + if (dbc_enabled && sel < 256) { + reg |= DWC3_GDBGLSPMUX_ENDBC; +- dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg); +- val = dwc3_readl(dwc->regs, DWC3_GDBGLSP); ++ dwc3_writel(dwc, DWC3_GDBGLSPMUX, reg); ++ val = dwc3_readl(dwc, DWC3_GDBGLSP); + seq_printf(s, "GDBGLSP_DBC[%d] = 0x%08x\n", sel, val); + } + } +@@ -316,8 +316,8 @@ static void dwc3_gadget_lsp(struct seq_file *s) + + for (i = 0; i < 16; i++) { + reg = DWC3_GDBGLSPMUX_DEVSELECT(i); +- dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg); +- reg = dwc3_readl(dwc->regs, DWC3_GDBGLSP); ++ dwc3_writel(dwc, DWC3_GDBGLSPMUX, reg); ++ reg = dwc3_readl(dwc, DWC3_GDBGLSP); + seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", i, reg); + } + } +@@ -335,7 +335,7 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused) + return ret; + + spin_lock_irqsave(&dwc->lock, flags); +- reg = dwc3_readl(dwc->regs, DWC3_GSTS); ++ reg = dwc3_readl(dwc, DWC3_GSTS); + current_mode = DWC3_GSTS_CURMOD(reg); + + switch (current_mode) { +@@ -406,7 +406,7 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) + return ret; + + spin_lock_irqsave(&dwc->lock, flags); +- reg = dwc3_readl(dwc->regs, DWC3_GCTL); ++ reg = dwc3_readl(dwc, DWC3_GCTL); + spin_unlock_irqrestore(&dwc->lock, flags); + + mode = DWC3_GCTL_PRTCAP(reg); +@@ -478,7 +478,7 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) + return ret; + + spin_lock_irqsave(&dwc->lock, flags); +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg &= DWC3_DCTL_TSTCTRL_MASK; + reg >>= 1; + spin_unlock_irqrestore(&dwc->lock, flags); +@@ -577,7 +577,7 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) + return ret; + + spin_lock_irqsave(&dwc->lock, flags); +- reg = dwc3_readl(dwc->regs, DWC3_GSTS); ++ reg = dwc3_readl(dwc, DWC3_GSTS); + if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { + seq_puts(s, "Not available\n"); + spin_unlock_irqrestore(&dwc->lock, flags); +@@ -585,7 +585,7 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) + return 0; + } + +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + state = DWC3_DSTS_USBLNKST(reg); + speed = reg & DWC3_DSTS_CONNECTSPD; + +@@ -639,14 +639,14 @@ static ssize_t dwc3_link_state_write(struct file *file, + return ret; + + spin_lock_irqsave(&dwc->lock, flags); +- reg = dwc3_readl(dwc->regs, DWC3_GSTS); ++ reg = dwc3_readl(dwc, DWC3_GSTS); + if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { + spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_put_sync(dwc->dev); + return -EINVAL; + } + +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + speed = reg & DWC3_DSTS_CONNECTSPD; + + if (speed < DWC3_DSTS_SUPERSPEED && +@@ -942,10 +942,10 @@ static int dwc3_ep_info_register_show(struct seq_file *s, void *unused) + + spin_lock_irqsave(&dwc->lock, flags); + reg = DWC3_GDBGLSPMUX_EPSELECT(dep->number); +- dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg); ++ dwc3_writel(dwc, DWC3_GDBGLSPMUX, reg); + +- lower_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO0); +- upper_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO1); ++ lower_32_bits = dwc3_readl(dwc, DWC3_GDBGEPINFO0); ++ upper_32_bits = dwc3_readl(dwc, DWC3_GDBGEPINFO1); + + ep_info = ((u64)upper_32_bits << 32) | lower_32_bits; + seq_printf(s, "0x%016llx\n", ep_info); +diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c +index 4c91240eb4299..b229fb1fd9327 100644 +--- a/drivers/usb/dwc3/drd.c ++++ b/drivers/usb/dwc3/drd.c +@@ -18,25 +18,25 @@ + + static void dwc3_otg_disable_events(struct dwc3 *dwc, u32 disable_mask) + { +- u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN); ++ u32 reg = dwc3_readl(dwc, DWC3_OEVTEN); + + reg &= ~(disable_mask); +- dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); ++ dwc3_writel(dwc, DWC3_OEVTEN, reg); + } + + static void dwc3_otg_enable_events(struct dwc3 *dwc, u32 enable_mask) + { +- u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN); ++ u32 reg = dwc3_readl(dwc, DWC3_OEVTEN); + + reg |= (enable_mask); +- dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); ++ dwc3_writel(dwc, DWC3_OEVTEN, reg); + } + + static void dwc3_otg_clear_events(struct dwc3 *dwc) + { +- u32 reg = dwc3_readl(dwc->regs, DWC3_OEVT); ++ u32 reg = dwc3_readl(dwc, DWC3_OEVT); + +- dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); ++ dwc3_writel(dwc, DWC3_OEVTEN, reg); + } + + #define DWC3_OTG_ALL_EVENTS (DWC3_OEVTEN_XHCIRUNSTPSETEN | \ +@@ -72,18 +72,18 @@ static irqreturn_t dwc3_otg_irq(int irq, void *_dwc) + struct dwc3 *dwc = _dwc; + irqreturn_t ret = IRQ_NONE; + +- reg = dwc3_readl(dwc->regs, DWC3_OEVT); ++ reg = dwc3_readl(dwc, DWC3_OEVT); + if (reg) { + /* ignore non OTG events, we can't disable them in OEVTEN */ + if (!(reg & DWC3_OTG_ALL_EVENTS)) { +- dwc3_writel(dwc->regs, DWC3_OEVT, reg); ++ dwc3_writel(dwc, DWC3_OEVT, reg); + return IRQ_NONE; + } + + if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST && + !(reg & DWC3_OEVT_DEVICEMODE)) + dwc->otg_restart_host = true; +- dwc3_writel(dwc->regs, DWC3_OEVT, reg); ++ dwc3_writel(dwc, DWC3_OEVT, reg); + ret = IRQ_WAKE_THREAD; + } + +@@ -100,23 +100,23 @@ static void dwc3_otgregs_init(struct dwc3 *dwc) + * the signal outputs sent to the PHY, the OTG FSM logic of the + * core and also the resets to the VBUS filters inside the core. + */ +- reg = dwc3_readl(dwc->regs, DWC3_OCFG); ++ reg = dwc3_readl(dwc, DWC3_OCFG); + reg |= DWC3_OCFG_SFTRSTMASK; +- dwc3_writel(dwc->regs, DWC3_OCFG, reg); ++ dwc3_writel(dwc, DWC3_OCFG, reg); + + /* Disable hibernation for simplicity */ +- reg = dwc3_readl(dwc->regs, DWC3_GCTL); ++ reg = dwc3_readl(dwc, DWC3_GCTL); + reg &= ~DWC3_GCTL_GBLHIBERNATIONEN; +- dwc3_writel(dwc->regs, DWC3_GCTL, reg); ++ dwc3_writel(dwc, DWC3_GCTL, reg); + + /* + * Initialize OTG registers as per + * Figure 11-4 OTG Driver Overall Programming Flow + */ + /* OCFG.SRPCap = 0, OCFG.HNPCap = 0 */ +- reg = dwc3_readl(dwc->regs, DWC3_OCFG); ++ reg = dwc3_readl(dwc, DWC3_OCFG); + reg &= ~(DWC3_OCFG_SRPCAP | DWC3_OCFG_HNPCAP); +- dwc3_writel(dwc->regs, DWC3_OCFG, reg); ++ dwc3_writel(dwc, DWC3_OCFG, reg); + /* OEVT = FFFF */ + dwc3_otg_clear_events(dwc); + /* OEVTEN = 0 */ +@@ -127,11 +127,11 @@ static void dwc3_otgregs_init(struct dwc3 *dwc) + * OCTL.PeriMode = 1, OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0, + * OCTL.HNPReq = 0 + */ +- reg = dwc3_readl(dwc->regs, DWC3_OCTL); ++ reg = dwc3_readl(dwc, DWC3_OCTL); + reg |= DWC3_OCTL_PERIMODE; + reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN | + DWC3_OCTL_HNPREQ); +- dwc3_writel(dwc->regs, DWC3_OCTL, reg); ++ dwc3_writel(dwc, DWC3_OCTL, reg); + } + + static int dwc3_otg_get_irq(struct dwc3 *dwc) +@@ -175,9 +175,9 @@ void dwc3_otg_init(struct dwc3 *dwc) + /* GCTL.PrtCapDir=2'b11 */ + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true); + /* GUSB2PHYCFG0.SusPHY=0 */ +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)); + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg); + + /* Initialize OTG registers */ + dwc3_otgregs_init(dwc); +@@ -203,17 +203,17 @@ void dwc3_otg_host_init(struct dwc3 *dwc) + * OCTL.PeriMode=0, OCTL.TermSelDLPulse = 0, + * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0 + */ +- reg = dwc3_readl(dwc->regs, DWC3_OCTL); ++ reg = dwc3_readl(dwc, DWC3_OCTL); + reg &= ~(DWC3_OCTL_PERIMODE | DWC3_OCTL_TERMSELIDPULSE | + DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN); +- dwc3_writel(dwc->regs, DWC3_OCTL, reg); ++ dwc3_writel(dwc, DWC3_OCTL, reg); + + /* + * OCFG.DisPrtPwrCutoff = 0/1 + */ +- reg = dwc3_readl(dwc->regs, DWC3_OCFG); ++ reg = dwc3_readl(dwc, DWC3_OCFG); + reg &= ~DWC3_OCFG_DISPWRCUTTOFF; +- dwc3_writel(dwc->regs, DWC3_OCFG, reg); ++ dwc3_writel(dwc, DWC3_OCFG, reg); + + /* + * OCFG.SRPCap = 1, OCFG.HNPCap = GHWPARAMS6.HNP_CAP +@@ -229,15 +229,15 @@ void dwc3_otg_host_init(struct dwc3 *dwc) + + /* GUSB2PHYCFG.ULPIAutoRes = 1/0, GUSB2PHYCFG.SusPHY = 1 */ + if (!dwc->dis_u2_susphy_quirk) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg); + } + + /* Set Port Power to enable VBUS: OCTL.PrtPwrCtl = 1 */ +- reg = dwc3_readl(dwc->regs, DWC3_OCTL); ++ reg = dwc3_readl(dwc, DWC3_OCTL); + reg |= DWC3_OCTL_PRTPWRCTL; +- dwc3_writel(dwc->regs, DWC3_OCTL, reg); ++ dwc3_writel(dwc, DWC3_OCTL, reg); + } + + /* should be called after Host controller driver is stopped */ +@@ -258,9 +258,9 @@ static void dwc3_otg_host_exit(struct dwc3 *dwc) + */ + + /* OCTL.HstSetHNPEn = 0, OCTL.PrtPwrCtl=0 */ +- reg = dwc3_readl(dwc->regs, DWC3_OCTL); ++ reg = dwc3_readl(dwc, DWC3_OCTL); + reg &= ~(DWC3_OCTL_HSTSETHNPEN | DWC3_OCTL_PRTPWRCTL); +- dwc3_writel(dwc->regs, DWC3_OCTL, reg); ++ dwc3_writel(dwc, DWC3_OCTL, reg); + } + + /* should be called before the gadget controller driver is started */ +@@ -274,27 +274,27 @@ static void dwc3_otg_device_init(struct dwc3 *dwc) + * OCFG.HNPCap = GHWPARAMS6.HNP_CAP, OCFG.SRPCap = 1 + * but we keep them 0 for simple dual-role operation. + */ +- reg = dwc3_readl(dwc->regs, DWC3_OCFG); ++ reg = dwc3_readl(dwc, DWC3_OCFG); + /* OCFG.OTGSftRstMsk = 0/1 */ + reg |= DWC3_OCFG_SFTRSTMASK; +- dwc3_writel(dwc->regs, DWC3_OCFG, reg); ++ dwc3_writel(dwc, DWC3_OCFG, reg); + /* + * OCTL.PeriMode = 1 + * OCTL.TermSelDLPulse = 0/1, OCTL.HNPReq = 0 + * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0 + */ +- reg = dwc3_readl(dwc->regs, DWC3_OCTL); ++ reg = dwc3_readl(dwc, DWC3_OCTL); + reg |= DWC3_OCTL_PERIMODE; + reg &= ~(DWC3_OCTL_TERMSELIDPULSE | DWC3_OCTL_HNPREQ | + DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN); +- dwc3_writel(dwc->regs, DWC3_OCTL, reg); ++ dwc3_writel(dwc, DWC3_OCTL, reg); + /* OEVTEN.OTGBDevSesVldDetEvntEn = 1 */ + dwc3_otg_enable_events(dwc, DWC3_OEVTEN_BDEVSESSVLDDETEN); + /* GUSB2PHYCFG.ULPIAutoRes = 0, GUSB2PHYCFG0.SusPHY = 1 */ + if (!dwc->dis_u2_susphy_quirk) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg); + } + /* GCTL.GblHibernationEn = 0. Already 0. */ + } +@@ -319,10 +319,10 @@ static void dwc3_otg_device_exit(struct dwc3 *dwc) + DWC3_OEVTEN_BDEVBHOSTENDEN); + + /* OCTL.DevSetHNPEn = 0, OCTL.HNPReq = 0, OCTL.PeriMode=1 */ +- reg = dwc3_readl(dwc->regs, DWC3_OCTL); ++ reg = dwc3_readl(dwc, DWC3_OCTL); + reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HNPREQ); + reg |= DWC3_OCTL_PERIMODE; +- dwc3_writel(dwc->regs, DWC3_OCTL, reg); ++ dwc3_writel(dwc, DWC3_OCTL, reg); + } + + void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) +@@ -341,7 +341,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) + return; + + if (!ignore_idstatus) { +- reg = dwc3_readl(dwc->regs, DWC3_OSTS); ++ reg = dwc3_readl(dwc, DWC3_OSTS); + id = !!(reg & DWC3_OSTS_CONIDSTS); + + dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE : +diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c +index e0bad57086648..a8ff8db610d34 100644 +--- a/drivers/usb/dwc3/ep0.c ++++ b/drivers/usb/dwc3/ep0.c +@@ -361,7 +361,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, + + if ((dwc->speed == DWC3_DSTS_SUPERSPEED) || + (dwc->speed == DWC3_DSTS_SUPERSPEED_PLUS)) { +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + if (reg & DWC3_DCTL_INITU1ENA) + usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; + if (reg & DWC3_DCTL_INITU2ENA) +@@ -417,12 +417,12 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state, + if (set && dwc->dis_u1_entry_quirk) + return -EINVAL; + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + if (set) + reg |= DWC3_DCTL_INITU1ENA; + else + reg &= ~DWC3_DCTL_INITU1ENA; +- dwc3_writel(dwc->regs, DWC3_DCTL, reg); ++ dwc3_writel(dwc, DWC3_DCTL, reg); + + return 0; + } +@@ -441,12 +441,12 @@ static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state, + if (set && dwc->dis_u2_entry_quirk) + return -EINVAL; + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + if (set) + reg |= DWC3_DCTL_INITU2ENA; + else + reg &= ~DWC3_DCTL_INITU2ENA; +- dwc3_writel(dwc->regs, DWC3_DCTL, reg); ++ dwc3_writel(dwc, DWC3_DCTL, reg); + + return 0; + } +@@ -612,10 +612,10 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) + return -EINVAL; + } + +- reg = dwc3_readl(dwc->regs, DWC3_DCFG); ++ reg = dwc3_readl(dwc, DWC3_DCFG); + reg &= ~(DWC3_DCFG_DEVADDR_MASK); + reg |= DWC3_DCFG_DEVADDR(addr); +- dwc3_writel(dwc->regs, DWC3_DCFG, reg); ++ dwc3_writel(dwc, DWC3_DCFG, reg); + + if (addr) + usb_gadget_set_state(dwc->gadget, USB_STATE_ADDRESS); +@@ -672,12 +672,12 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) + * Enable transition to U1/U2 state when + * nothing is pending from application. + */ +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + if (!dwc->dis_u1_entry_quirk) + reg |= DWC3_DCTL_ACCEPTU1ENA; + if (!dwc->dis_u2_entry_quirk) + reg |= DWC3_DCTL_ACCEPTU2ENA; +- dwc3_writel(dwc->regs, DWC3_DCTL, reg); ++ dwc3_writel(dwc, DWC3_DCTL, reg); + } + break; + +@@ -717,7 +717,7 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) + dwc->u2sel = le16_to_cpu(timing.u2sel); + dwc->u2pel = le16_to_cpu(timing.u2pel); + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + if (reg & DWC3_DCTL_INITU2ENA) + param = dwc->u2pel; + if (reg & DWC3_DCTL_INITU1ENA) +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 04f6ab77bd7cd..89963cd77daaa 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -42,7 +42,7 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) + { + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg &= ~DWC3_DCTL_TSTCTRL_MASK; + + switch (mode) { +@@ -73,7 +73,7 @@ int dwc3_gadget_get_link_state(struct dwc3 *dwc) + { + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + + return DWC3_DSTS_USBLNKST(reg); + } +@@ -97,7 +97,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) + */ + if (!DWC3_VER_IS_PRIOR(DWC3, 194A)) { + while (--retries) { +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + if (reg & DWC3_DSTS_DCNRD) + udelay(5); + else +@@ -108,15 +108,15 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) + return -ETIMEDOUT; + } + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; + + /* set no action before sending new link state change */ +- dwc3_writel(dwc->regs, DWC3_DCTL, reg); ++ dwc3_writel(dwc, DWC3_DCTL, reg); + + /* set requested state */ + reg |= DWC3_DCTL_ULSTCHNGREQ(state); +- dwc3_writel(dwc->regs, DWC3_DCTL, reg); ++ dwc3_writel(dwc, DWC3_DCTL, reg); + + /* + * The following code is racy when called from dwc3_gadget_wakeup, +@@ -128,7 +128,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) + /* wait for a change in DSTS */ + retries = 10000; + while (--retries) { +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + + if (DWC3_DSTS_USBLNKST(reg) == state) + return 0; +@@ -260,11 +260,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, + int ret = 0; + u32 reg; + +- dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); +- dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); ++ dwc3_writel(dwc, DWC3_DGCMDPAR, param); ++ dwc3_writel(dwc, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); + + do { +- reg = dwc3_readl(dwc->regs, DWC3_DGCMD); ++ reg = dwc3_readl(dwc, DWC3_DGCMD); + if (!(reg & DWC3_DGCMD_CMDACT)) { + status = DWC3_DGCMD_STATUS(reg); + if (status) +@@ -334,7 +334,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + */ + if (dwc->gadget->speed <= USB_SPEED_HIGH || + DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)); + if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { + saved_config |= DWC3_GUSB2PHYCFG_SUSPHY; + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; +@@ -346,7 +346,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + } + + if (saved_config) +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg); + } + + /* +@@ -356,9 +356,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + * improve performance. + */ + if (DWC3_DEPCMD_CMD(cmd) != DWC3_DEPCMD_UPDATETRANSFER) { +- dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(epnum), params->param0); +- dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(epnum), params->param1); +- dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(epnum), params->param2); ++ dwc3_writel(dwc, DWC3_DEPCMDPAR0(epnum), params->param0); ++ dwc3_writel(dwc, DWC3_DEPCMDPAR1(epnum), params->param1); ++ dwc3_writel(dwc, DWC3_DEPCMDPAR2(epnum), params->param2); + } + + /* +@@ -382,7 +382,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + else + cmd |= DWC3_DEPCMD_CMDACT; + +- dwc3_writel(dwc->regs, DWC3_DEPCMD(epnum), cmd); ++ dwc3_writel(dwc, DWC3_DEPCMD(epnum), cmd); + + if (!(cmd & DWC3_DEPCMD_CMDACT) || + (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER && +@@ -392,7 +392,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + } + + do { +- reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(epnum)); ++ reg = dwc3_readl(dwc, DWC3_DEPCMD(epnum)); + if (!(reg & DWC3_DEPCMD_CMDACT)) { + cmd_status = DWC3_DEPCMD_STATUS(reg); + +@@ -448,9 +448,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + mdelay(1); + + if (saved_config) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)); + reg |= saved_config; +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg); + } + + return ret; +@@ -727,7 +727,7 @@ static int dwc3_gadget_calc_ram_depth(struct dwc3 *dwc) + u32 reg; + + /* Check if TXFIFOs start at non-zero addr */ +- reg = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); ++ reg = dwc3_readl(dwc, DWC3_GTXFIFOSIZ(0)); + fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(reg); + + ram_depth -= (fifo_0_start >> 16); +@@ -755,7 +755,7 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) + + /* Read ep0IN related TXFIFO size */ + dep = dwc->eps[1]; +- size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); ++ size = dwc3_readl(dwc, DWC3_GTXFIFOSIZ(0)); + if (DWC3_IP_IS(DWC3)) + fifo_depth = DWC3_GTXFIFOSIZ_TXFDEP(size); + else +@@ -770,10 +770,10 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc) + + /* Don't change TXFRAMNUM on usb31 version */ + size = DWC3_IP_IS(DWC3) ? 0 : +- dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) & ++ dwc3_readl(dwc, DWC3_GTXFIFOSIZ(num >> 1)) & + DWC31_GTXFIFOSIZ_TXFRAMNUM; + +- dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size); ++ dwc3_writel(dwc, DWC3_GTXFIFOSIZ(num >> 1), size); + dep->flags &= ~DWC3_EP_TXFIFO_RESIZED; + } + dwc->num_ep_resized = 0; +@@ -876,7 +876,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) + fifo_size++; + + /* Check if TXFIFOs start at non-zero addr */ +- tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); ++ tmp = dwc3_readl(dwc, DWC3_GTXFIFOSIZ(0)); + fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp); + + fifo_size |= (fifo_0_start + (dwc->last_fifo_depth << 16)); +@@ -899,7 +899,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) + return -ENOMEM; + } + +- dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size); ++ dwc3_writel(dwc, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size); + dep->flags |= DWC3_EP_TXFIFO_RESIZED; + dwc->num_ep_resized++; + +@@ -943,9 +943,9 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) + dep->type = usb_endpoint_type(desc); + dep->flags |= DWC3_EP_ENABLED; + +- reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); ++ reg = dwc3_readl(dwc, DWC3_DALEPENA); + reg |= DWC3_DALEPENA_EP(dep->number); +- dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); ++ dwc3_writel(dwc, DWC3_DALEPENA, reg); + + dep->trb_dequeue = 0; + dep->trb_enqueue = 0; +@@ -1080,9 +1080,9 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) + if (dep->flags & DWC3_EP_STALL) + __dwc3_gadget_ep_set_halt(dep, 0, false); + +- reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); ++ reg = dwc3_readl(dwc, DWC3_DALEPENA); + reg &= ~DWC3_DALEPENA_EP(dep->number); +- dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); ++ dwc3_writel(dwc, DWC3_DALEPENA, reg); + + dwc3_remove_requests(dwc, dep, -ESHUTDOWN); + +@@ -1743,7 +1743,7 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc) + { + u32 reg; + +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + return DWC3_DSTS_SOFFN(reg); + } + +@@ -2351,13 +2351,13 @@ static void dwc3_gadget_enable_linksts_evts(struct dwc3 *dwc, bool set) + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; + +- reg = dwc3_readl(dwc->regs, DWC3_DEVTEN); ++ reg = dwc3_readl(dwc, DWC3_DEVTEN); + if (set) + reg |= DWC3_DEVTEN_ULSTCNGEN; + else + reg &= ~DWC3_DEVTEN_ULSTCNGEN; + +- dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); ++ dwc3_writel(dwc, DWC3_DEVTEN, reg); + } + + static int dwc3_gadget_get_frame(struct usb_gadget *g) +@@ -2380,7 +2380,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) + * + * We can check that via USB Link State bits in DSTS register. + */ +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + + link_state = DWC3_DSTS_USBLNKST(reg); + +@@ -2408,9 +2408,9 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) + /* Recent versions do this automatically */ + if (DWC3_VER_IS_PRIOR(DWC3, 194A)) { + /* write zeroes to Link Change Request */ +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; +- dwc3_writel(dwc->regs, DWC3_DCTL, reg); ++ dwc3_writel(dwc, DWC3_DCTL, reg); + } + + /* +@@ -2530,7 +2530,7 @@ static void __dwc3_gadget_set_ssp_rate(struct dwc3 *dwc) + if (ssp_rate == USB_SSP_GEN_UNKNOWN) + ssp_rate = dwc->max_ssp_rate; + +- reg = dwc3_readl(dwc->regs, DWC3_DCFG); ++ reg = dwc3_readl(dwc, DWC3_DCFG); + reg &= ~DWC3_DCFG_SPEED_MASK; + reg &= ~DWC3_DCFG_NUMLANES(~0); + +@@ -2543,7 +2543,7 @@ static void __dwc3_gadget_set_ssp_rate(struct dwc3 *dwc) + dwc->max_ssp_rate != USB_SSP_GEN_2x1) + reg |= DWC3_DCFG_NUMLANES(1); + +- dwc3_writel(dwc->regs, DWC3_DCFG, reg); ++ dwc3_writel(dwc, DWC3_DCFG, reg); + } + + static void __dwc3_gadget_set_speed(struct dwc3 *dwc) +@@ -2561,7 +2561,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc) + return; + } + +- reg = dwc3_readl(dwc->regs, DWC3_DCFG); ++ reg = dwc3_readl(dwc, DWC3_DCFG); + reg &= ~(DWC3_DCFG_SPEED_MASK); + + /* +@@ -2612,7 +2612,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc) + speed < USB_SPEED_SUPER_PLUS) + reg &= ~DWC3_DCFG_NUMLANES(~0); + +- dwc3_writel(dwc->regs, DWC3_DCFG, reg); ++ dwc3_writel(dwc, DWC3_DCFG, reg); + } + + static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) +@@ -2637,7 +2637,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) + * mentioned in the dwc3 programming guide. It has been tested on an + * Exynos platforms. + */ +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)); + if (reg & DWC3_GUSB2PHYCFG_SUSPHY) { + saved_config |= DWC3_GUSB2PHYCFG_SUSPHY; + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; +@@ -2649,9 +2649,9 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) + } + + if (saved_config) +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg); + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + if (is_on) { + if (DWC3_VER_IS_WITHIN(DWC3, ANY, 187A)) { + reg &= ~DWC3_DCTL_TRGTULST_MASK; +@@ -2675,14 +2675,14 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) + + do { + usleep_range(1000, 2000); +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + reg &= DWC3_DSTS_DEVCTRLHLT; + } while (--timeout && !(!is_on ^ !reg)); + + if (saved_config) { +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)); + reg |= saved_config; +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg); + } + + if (!timeout) +@@ -2858,13 +2858,13 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc) + if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) + reg |= DWC3_DEVTEN_U3L2L1SUSPEN; + +- dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); ++ dwc3_writel(dwc, DWC3_DEVTEN, reg); + } + + static void dwc3_gadget_disable_irq(struct dwc3 *dwc) + { + /* mask all interrupts */ +- dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); ++ dwc3_writel(dwc, DWC3_DEVTEN, 0x00); + } + + static irqreturn_t dwc3_interrupt(int irq, void *_dwc); +@@ -2905,10 +2905,10 @@ static void dwc3_gadget_setup_nump(struct dwc3 *dwc) + nump = min_t(u32, nump, 16); + + /* update NumP */ +- reg = dwc3_readl(dwc->regs, DWC3_DCFG); ++ reg = dwc3_readl(dwc, DWC3_DCFG); + reg &= ~DWC3_DCFG_NUMP_MASK; + reg |= nump << DWC3_DCFG_NUMP_SHIFT; +- dwc3_writel(dwc->regs, DWC3_DCFG, reg); ++ dwc3_writel(dwc, DWC3_DCFG, reg); + } + + static int __dwc3_gadget_start(struct dwc3 *dwc) +@@ -2922,10 +2922,10 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) + * the core supports IMOD, disable it. + */ + if (dwc->imod_interval) { +- dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); +- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); ++ dwc3_writel(dwc, DWC3_DEV_IMOD(0), dwc->imod_interval); ++ dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); + } else if (dwc3_has_imod(dwc)) { +- dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0); ++ dwc3_writel(dwc, DWC3_DEV_IMOD(0), 0); + } + + /* +@@ -2935,13 +2935,13 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) + * This way, we maximize the chances that we'll be able to get several + * bursts of data without going through any sort of endpoint throttling. + */ +- reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); ++ reg = dwc3_readl(dwc, DWC3_GRXTHRCFG); + if (DWC3_IP_IS(DWC3)) + reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL; + else + reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL; + +- dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); ++ dwc3_writel(dwc, DWC3_GRXTHRCFG, reg); + + dwc3_gadget_setup_nump(dwc); + +@@ -2952,15 +2952,15 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) + * ACK with NumP=0 and PP=0 (for IN direction). This slightly improves + * the stream performance. + */ +- reg = dwc3_readl(dwc->regs, DWC3_DCFG); ++ reg = dwc3_readl(dwc, DWC3_DCFG); + reg |= DWC3_DCFG_IGNSTRMPP; +- dwc3_writel(dwc->regs, DWC3_DCFG, reg); ++ dwc3_writel(dwc, DWC3_DCFG, reg); + + /* Enable MST by default if the device is capable of MST */ + if (DWC3_MST_CAPABLE(&dwc->hwparams)) { +- reg = dwc3_readl(dwc->regs, DWC3_DCFG1); ++ reg = dwc3_readl(dwc, DWC3_DCFG1); + reg &= ~DWC3_DCFG1_DIS_MST_ENH; +- dwc3_writel(dwc->regs, DWC3_DCFG1, reg); ++ dwc3_writel(dwc, DWC3_DCFG1, reg); + } + + /* Start with SuperSpeed Default */ +@@ -3238,7 +3238,7 @@ static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep) + /* MDWIDTH is represented in bits, we need it in bytes */ + mdwidth /= 8; + +- size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1)); ++ size = dwc3_readl(dwc, DWC3_GTXFIFOSIZ(dep->number >> 1)); + if (DWC3_IP_IS(DWC3)) + size = DWC3_GTXFIFOSIZ_TXFDEP(size); + else +@@ -3287,7 +3287,7 @@ static int dwc3_gadget_init_out_endpoint(struct dwc3_ep *dep) + mdwidth /= 8; + + /* All OUT endpoints share a single RxFIFO space */ +- size = dwc3_readl(dwc->regs, DWC3_GRXFIFOSIZ(0)); ++ size = dwc3_readl(dwc, DWC3_GRXFIFOSIZ(0)); + if (DWC3_IP_IS(DWC3)) + size = DWC3_GRXFIFOSIZ_RXFDEP(size); + else +@@ -3740,9 +3740,9 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep, + return no_started_trb; + } + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg |= dwc->u1u2; +- dwc3_writel(dwc->regs, DWC3_DCTL, reg); ++ dwc3_writel(dwc, DWC3_DCTL, reg); + + dwc->u1u2 = 0; + } +@@ -4072,7 +4072,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) + + dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RX_DET); + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg &= ~DWC3_DCTL_INITU1ENA; + reg &= ~DWC3_DCTL_INITU2ENA; + dwc3_gadget_dctl_write_safe(dwc, reg); +@@ -4161,7 +4161,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) + dwc3_stop_active_transfers(dwc); + dwc->connected = true; + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg &= ~DWC3_DCTL_TSTCTRL_MASK; + dwc3_gadget_dctl_write_safe(dwc, reg); + dwc->test_mode = false; +@@ -4170,9 +4170,9 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) + dwc3_clear_stall_all_ep(dwc); + + /* Reset device address to zero */ +- reg = dwc3_readl(dwc->regs, DWC3_DCFG); ++ reg = dwc3_readl(dwc, DWC3_DCFG); + reg &= ~(DWC3_DCFG_DEVADDR_MASK); +- dwc3_writel(dwc->regs, DWC3_DCFG, reg); ++ dwc3_writel(dwc, DWC3_DCFG, reg); + } + + static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) +@@ -4186,7 +4186,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) + if (!dwc->softconnect) + return; + +- reg = dwc3_readl(dwc->regs, DWC3_DSTS); ++ reg = dwc3_readl(dwc, DWC3_DSTS); + speed = reg & DWC3_DSTS_CONNECTSPD; + dwc->speed = speed; + +@@ -4261,11 +4261,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) + !dwc->usb2_gadget_lpm_disable && + (speed != DWC3_DSTS_SUPERSPEED) && + (speed != DWC3_DSTS_SUPERSPEED_PLUS)) { +- reg = dwc3_readl(dwc->regs, DWC3_DCFG); ++ reg = dwc3_readl(dwc, DWC3_DCFG); + reg |= DWC3_DCFG_LPM_CAP; +- dwc3_writel(dwc->regs, DWC3_DCFG, reg); ++ dwc3_writel(dwc, DWC3_DCFG, reg); + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); + + reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold | +@@ -4288,12 +4288,12 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) + dwc3_gadget_dctl_write_safe(dwc, reg); + } else { + if (dwc->usb2_gadget_lpm_disable) { +- reg = dwc3_readl(dwc->regs, DWC3_DCFG); ++ reg = dwc3_readl(dwc, DWC3_DCFG); + reg &= ~DWC3_DCFG_LPM_CAP; +- dwc3_writel(dwc->regs, DWC3_DCFG, reg); ++ dwc3_writel(dwc, DWC3_DCFG, reg); + } + +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + reg &= ~DWC3_DCTL_HIRD_THRES_MASK; + dwc3_gadget_dctl_write_safe(dwc, reg); + } +@@ -4399,7 +4399,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, + switch (dwc->link_state) { + case DWC3_LINK_STATE_U1: + case DWC3_LINK_STATE_U2: +- reg = dwc3_readl(dwc->regs, DWC3_DCTL); ++ reg = dwc3_readl(dwc, DWC3_DCTL); + u1u2 = reg & (DWC3_DCTL_INITU2ENA + | DWC3_DCTL_ACCEPTU2ENA + | DWC3_DCTL_INITU1ENA +@@ -4556,7 +4556,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) + ret = IRQ_HANDLED; + + /* Unmask interrupt */ +- dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), ++ dwc3_writel(dwc, DWC3_GEVNTSIZ(0), + DWC3_GEVNTSIZ_SIZE(evt->length)); + + evt->flags &= ~DWC3_EVENT_PENDING; +@@ -4567,8 +4567,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) + wmb(); + + if (dwc->imod_interval) { +- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); +- dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); ++ dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); ++ dwc3_writel(dwc, DWC3_DEV_IMOD(0), dwc->imod_interval); + } + + return ret; +@@ -4617,7 +4617,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) + if (evt->flags & DWC3_EVENT_PENDING) + return IRQ_HANDLED; + +- count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); ++ count = dwc3_readl(dwc, DWC3_GEVNTCOUNT(0)); + count &= DWC3_GEVNTCOUNT_MASK; + if (!count) + return IRQ_NONE; +@@ -4632,7 +4632,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) + evt->flags |= DWC3_EVENT_PENDING; + + /* Mask interrupt */ +- dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), ++ dwc3_writel(dwc, DWC3_GEVNTSIZ(0), + DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(evt->length)); + + amount = min(count, evt->length - evt->lpos); +@@ -4641,7 +4641,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) + if (amount < count) + memcpy(evt->cache, evt->buf, count - amount); + +- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); ++ dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), count); + + return IRQ_WAKE_THREAD; + } +diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h +index c3aa9638b7a53..45f113b3c146c 100644 +--- a/drivers/usb/dwc3/gadget.h ++++ b/drivers/usb/dwc3/gadget.h +@@ -132,7 +132,7 @@ static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep) + { + u32 res_id; + +- res_id = dwc3_readl(dep->dwc->regs, DWC3_DEPCMD(dep->number)); ++ res_id = dwc3_readl(dep->dwc, DWC3_DEPCMD(dep->number)); + dep->resource_index = DWC3_DEPCMD_GET_RSC_IDX(res_id); + } + +@@ -147,7 +147,7 @@ static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep) + static inline void dwc3_gadget_dctl_write_safe(struct dwc3 *dwc, u32 value) + { + value &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; +- dwc3_writel(dwc->regs, DWC3_DCTL, value); ++ dwc3_writel(dwc, DWC3_DCTL, value); + } + + #endif /* __DRIVERS_USB_DWC3_GADGET_H */ +diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h +index 1e96ea339d48d..7dd0c1e0cf74f 100644 +--- a/drivers/usb/dwc3/io.h ++++ b/drivers/usb/dwc3/io.h +@@ -16,9 +16,10 @@ + #include "debug.h" + #include "core.h" + +-static inline u32 dwc3_readl(void __iomem *base, u32 offset) ++static inline u32 dwc3_readl(struct dwc3 *dwc, u32 offset) + { + u32 value; ++ void __iomem *base = dwc->regs; + + /* + * We requested the mem region starting from the Globals address +@@ -37,8 +38,10 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset) + return value; + } + +-static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) ++static inline void dwc3_writel(struct dwc3 *dwc, u32 offset, u32 value) + { ++ void __iomem *base = dwc->regs; ++ + /* + * We requested the mem region starting from the Globals address + * space, see dwc3_probe in core.c. +diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c +index f23f4c9a557e9..57daad15f502d 100644 +--- a/drivers/usb/dwc3/ulpi.c ++++ b/drivers/usb/dwc3/ulpi.c +@@ -33,13 +33,13 @@ static int dwc3_ulpi_busyloop(struct dwc3 *dwc, u8 addr, bool read) + if (read) + ns += DWC3_ULPI_BASE_DELAY; + +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)); + if (reg & DWC3_GUSB2PHYCFG_SUSPHY) + usleep_range(1000, 1200); + + while (count--) { + ndelay(ns); +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYACC(0)); + if (reg & DWC3_GUSB2PHYACC_DONE) + return 0; + cpu_relax(); +@@ -55,13 +55,13 @@ static int dwc3_ulpi_read(struct device *dev, u8 addr) + int ret; + + reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYACC(0), reg); + + ret = dwc3_ulpi_busyloop(dwc, addr, true); + if (ret) + return ret; + +- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0)); ++ reg = dwc3_readl(dwc, DWC3_GUSB2PHYACC(0)); + + return DWC3_GUSB2PHYACC_DATA(reg); + } +@@ -73,7 +73,7 @@ static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val) + + reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); + reg |= DWC3_GUSB2PHYACC_WRITE | val; +- dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg); ++ dwc3_writel(dwc, DWC3_GUSB2PHYACC(0), reg); + + return dwc3_ulpi_busyloop(dwc, addr, false); + } +-- +2.53.0 + diff --git a/queue-6.18/usb-dwc3-move-guid-programming-after-phy-initializat.patch b/queue-6.18/usb-dwc3-move-guid-programming-after-phy-initializat.patch new file mode 100644 index 0000000000..60303cf0f5 --- /dev/null +++ b/queue-6.18/usb-dwc3-move-guid-programming-after-phy-initializat.patch @@ -0,0 +1,64 @@ +From ba3218e095ba58e8bfd19cb21a3edabb7a018a86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 07:27:44 -0400 +Subject: usb: dwc3: Move GUID programming after PHY initialization + +From: Selvarasu Ganesan + +[ Upstream commit aad35f9c926ec220b0742af1ada45666ae667956 ] + +The Linux Version Code is currently written to the GUID register before +PHY initialization. Certain PHY implementations (such as Synopsys eUSB +PHY performing link_sw_reset) clear the GUID register to its default +value during initialization, causing the kernel version information to +be lost. + +Move the GUID register programming to occur after PHY initialization +completes to ensure the Linux version information persists. + +Fixes: fa0ea13e9f1c ("usb: dwc3: core: write LINUX_VERSION_CODE to our GUID register") +Cc: stable +Reported-by: Pritam Manohar Sutar +Signed-off-by: Selvarasu Ganesan +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260417063314.2359-1-selvarasu.g@samsung.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/core.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index c5bec0bd9cb10..a1f99c3b5f378 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -1339,12 +1339,6 @@ static int dwc3_core_init(struct dwc3 *dwc) + + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + +- /* +- * Write Linux Version Code to our GUID register so it's easy to figure +- * out which kernel version a bug was found. +- */ +- dwc3_writel(dwc, DWC3_GUID, LINUX_VERSION_CODE); +- + ret = dwc3_phy_setup(dwc); + if (ret) + return ret; +@@ -1376,6 +1370,12 @@ static int dwc3_core_init(struct dwc3 *dwc) + if (ret) + goto err_exit_phy; + ++ /* ++ * Write Linux Version Code to our GUID register so it's easy to figure ++ * out which kernel version a bug was found. ++ */ ++ dwc3_writel(dwc, DWC3_GUID, LINUX_VERSION_CODE); ++ + dwc3_core_setup_global_control(dwc); + dwc3_core_num_eps(dwc); + +-- +2.53.0 + diff --git a/queue-6.18/usb-dwc3-remove-of-dep-regs.patch b/queue-6.18/usb-dwc3-remove-of-dep-regs.patch new file mode 100644 index 0000000000..4cd10ffe35 --- /dev/null +++ b/queue-6.18/usb-dwc3-remove-of-dep-regs.patch @@ -0,0 +1,154 @@ +From 0ae89c915f634b6dff2c7662d2418fbf5b83afdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 May 2026 07:27:42 -0400 +Subject: usb: dwc3: Remove of dep->regs + +From: Prashanth K + +[ Upstream commit abdd1eef04f0cb3b1707cd1fa243d574d5e07024 ] + +Remove dep->regs from struct dwc3_ep and reuse dwc->regs instead. +Thus eliminating redundant iomem addresses and making register +access more consistent across the driver. + +Signed-off-by: Prashanth K +Acked-by: Thinh Nguyen +Link: https://patch.msgid.link/20260114100748.2950103-2-prashanth.k@oss.qualcomm.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: aad35f9c926e ("usb: dwc3: Move GUID programming after PHY initialization") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/core.h | 10 ++++------ + drivers/usb/dwc3/debugfs.c | 12 ++++-------- + drivers/usb/dwc3/gadget.c | 12 ++++++------ + drivers/usb/dwc3/gadget.h | 2 +- + 4 files changed, 15 insertions(+), 21 deletions(-) + +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index 9cfc36d4bc259..a35b3db1f9f3e 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -165,10 +165,10 @@ + #define DWC3_DCFG1 0xc740 /* DWC_usb32 only */ + + #define DWC3_DEP_BASE(n) (0xc800 + ((n) * 0x10)) +-#define DWC3_DEPCMDPAR2 0x00 +-#define DWC3_DEPCMDPAR1 0x04 +-#define DWC3_DEPCMDPAR0 0x08 +-#define DWC3_DEPCMD 0x0c ++#define DWC3_DEPCMDPAR2(n) (DWC3_DEP_BASE(n) + 0x00) ++#define DWC3_DEPCMDPAR1(n) (DWC3_DEP_BASE(n) + 0x04) ++#define DWC3_DEPCMDPAR0(n) (DWC3_DEP_BASE(n) + 0x08) ++#define DWC3_DEPCMD(n) (DWC3_DEP_BASE(n) + 0x0c) + + #define DWC3_DEV_IMOD(n) (0xca00 + ((n) * 0x4)) + +@@ -749,8 +749,6 @@ struct dwc3_ep { + struct list_head pending_list; + struct list_head started_list; + +- void __iomem *regs; +- + struct dwc3_trb *trb_pool; + dma_addr_t trb_pool_dma; + struct dwc3 *dwc; +diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c +index d18bf5e32cc8c..0b45ff16f575b 100644 +--- a/drivers/usb/dwc3/debugfs.c ++++ b/drivers/usb/dwc3/debugfs.c +@@ -36,23 +36,19 @@ + #define dump_ep_register_set(n) \ + { \ + .name = "DEPCMDPAR2("__stringify(n)")", \ +- .offset = DWC3_DEP_BASE(n) + \ +- DWC3_DEPCMDPAR2, \ ++ .offset = DWC3_DEPCMDPAR2(n), \ + }, \ + { \ + .name = "DEPCMDPAR1("__stringify(n)")", \ +- .offset = DWC3_DEP_BASE(n) + \ +- DWC3_DEPCMDPAR1, \ ++ .offset = DWC3_DEPCMDPAR1(n), \ + }, \ + { \ + .name = "DEPCMDPAR0("__stringify(n)")", \ +- .offset = DWC3_DEP_BASE(n) + \ +- DWC3_DEPCMDPAR0, \ ++ .offset = DWC3_DEPCMDPAR0(n), \ + }, \ + { \ + .name = "DEPCMD("__stringify(n)")", \ +- .offset = DWC3_DEP_BASE(n) + \ +- DWC3_DEPCMD, \ ++ .offset = DWC3_DEPCMD(n), \ + } + + +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index db5e5b77b1eac..04f6ab77bd7cd 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -320,6 +320,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + + int cmd_status = 0; + int ret = -EINVAL; ++ u8 epnum = dep->number; + + /* + * When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or +@@ -355,9 +356,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + * improve performance. + */ + if (DWC3_DEPCMD_CMD(cmd) != DWC3_DEPCMD_UPDATETRANSFER) { +- dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0); +- dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1); +- dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2); ++ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(epnum), params->param0); ++ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(epnum), params->param1); ++ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(epnum), params->param2); + } + + /* +@@ -381,7 +382,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + else + cmd |= DWC3_DEPCMD_CMDACT; + +- dwc3_writel(dep->regs, DWC3_DEPCMD, cmd); ++ dwc3_writel(dwc->regs, DWC3_DEPCMD(epnum), cmd); + + if (!(cmd & DWC3_DEPCMD_CMDACT) || + (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER && +@@ -391,7 +392,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, + } + + do { +- reg = dwc3_readl(dep->regs, DWC3_DEPCMD); ++ reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(epnum)); + if (!(reg & DWC3_DEPCMD_CMDACT)) { + cmd_status = DWC3_DEPCMD_STATUS(reg); + +@@ -3379,7 +3380,6 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) + dep->dwc = dwc; + dep->number = epnum; + dep->direction = direction; +- dep->regs = dwc->regs + DWC3_DEP_BASE(epnum); + dwc->eps[epnum] = dep; + dep->combo_num = 0; + dep->start_cmd_status = 0; +diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h +index d73e735e40810..c3aa9638b7a53 100644 +--- a/drivers/usb/dwc3/gadget.h ++++ b/drivers/usb/dwc3/gadget.h +@@ -132,7 +132,7 @@ static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep) + { + u32 res_id; + +- res_id = dwc3_readl(dep->regs, DWC3_DEPCMD); ++ res_id = dwc3_readl(dep->dwc->regs, DWC3_DEPCMD(dep->number)); + dep->resource_index = DWC3_DEPCMD_GET_RSC_IDX(res_id); + } + +-- +2.53.0 + diff --git a/queue-6.18/usb-typec-fix-error-pointer-dereference.patch b/queue-6.18/usb-typec-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..29e553f2d3 --- /dev/null +++ b/queue-6.18/usb-typec-fix-error-pointer-dereference.patch @@ -0,0 +1,58 @@ +From 2f01ef9c87dfd2e80e6640ca7fdb9620593f3810 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 15:46:21 -0600 +Subject: usb: typec: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit f2529d08fcb429ea01bb87c326342f41483f8b2f ] + +The variable tps->partner is checked for an error pointer and then if it +is, it sends an error message but does not return and then immediately +dereferenced a few lines below: + +tps->partner = typec_register_partner(tps->port, &desc); +if (IS_ERR(tps->partner)) + dev_warn(tps->dev, "%s: failed to register partnet\n", __func__); + +if (desc.identity) { + typec_partner_set_identity(tps->partner); + cd321x->cur_partner_identity = st.partner_identity; +} + +Add early return and fix spelling mistake in error message. + +Detected by Smatch: +drivers/usb/typec/tipd/core.c:827 cd321x_update_work() error: +'tps->partner' dereferencing possible ERR_PTR() + +Fixes: 82432bbfb9e83 ("usb: typec: tipd: Handle mode transitions for CD321x") +Signed-off-by: Ethan Tidmore +Reviewed-by: Heikki Krogerus +Link: https://patch.msgid.link/20260218214621.38154-1-ethantidmore06@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/tipd/core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c +index 2b1049c9a6f3c..01c657bc84e68 100644 +--- a/drivers/usb/typec/tipd/core.c ++++ b/drivers/usb/typec/tipd/core.c +@@ -814,8 +814,10 @@ static void cd321x_update_work(struct work_struct *work) + desc.identity = &st.partner_identity; + + tps->partner = typec_register_partner(tps->port, &desc); +- if (IS_ERR(tps->partner)) +- dev_warn(tps->dev, "%s: failed to register partnet\n", __func__); ++ if (IS_ERR(tps->partner)) { ++ dev_warn(tps->dev, "%s: failed to register partner\n", __func__); ++ return; ++ } + + if (desc.identity) { + typec_partner_set_identity(tps->partner); +-- +2.53.0 + diff --git a/queue-6.18/usb-typec-ps883x-fix-oops-at-unbind.patch b/queue-6.18/usb-typec-ps883x-fix-oops-at-unbind.patch new file mode 100644 index 0000000000..3444eeac43 --- /dev/null +++ b/queue-6.18/usb-typec-ps883x-fix-oops-at-unbind.patch @@ -0,0 +1,67 @@ +From 06c254c640d188e73c83a2385aaf4281e2b7a7cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:55:34 +0000 +Subject: usb: typec: ps883x: Fix Oops at unbind + +From: Mostafa Saleh + +[ Upstream commit 381133848a033c2086cf9cafb226f425bd0414ff ] + +When trying to unbind a device in order to bind to it vfio-platform as: + + echo bc0000.geniqup > /sys/bus/platform/devices/bc0000.geniqup/driver/unbind + +I get the following Oops: + +[ 436.478639] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020 +[ 436.487762] Mem abort info: +[ 436.490716] ESR = 0x0000000096000004 +[ 436.494595] EC = 0x25: DABT (current EL), IL = 32 bits +[ 436.500071] SET = 0, FnV = 0 +[ 436.503250] EA = 0, S1PTW = 0 +[ 436.506505] FSC = 0x04: level 0 translation fault +[ 436.511533] Data abort info: +[ 436.514558] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 +[ 436.520215] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 +[ 436.525436] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 436.530918] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008861a9000 +[ 436.537554] [0000000000000020] pgd=0000000000000000, p4d=0000000000000000 +[ 436.544548] Internal error: Oops: 0000000096000004 [#1] SMP +[ 436.550374] Modules linked in: +[ 436.553542] CPU: 2 UID: 0 PID: 671 Comm: bash Tainted: G W 7.0.0-rc3-g56fcdd0911a5-dirty #2 PREEMPT +[ 436.564440] Tainted: [W]=WARN +[ 436.567515] Hardware name: LENOVO 91B6CTO1WW/3796, BIOS O6NKT3BA 05/02/2025 +[ 436.574675] pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) +[ 436.581841] pc : ps883x_retimer_remove+0x14/0x94 +[ 436.586605] lr : i2c_device_remove+0x28/0x84 +[ 436.591017] sp : ffff8000847137c0 + +That's because the ps883x_retimer_remove() retrieves the driver data +from i2c_get_clientdata() which was never set at probe. So, add +i2c_set_clientdata() at the end of the probe. + +Signed-off-by: Mostafa Saleh +Reviewed-by: Konrad Dybcio +Fixes: 257a087c8b52 ("usb: typec: Add support for Parade PS8830 Type-C Retimer") +Link: https://patch.msgid.link/20260313155534.1916773-1-smostafa@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/mux/ps883x.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/usb/typec/mux/ps883x.c b/drivers/usb/typec/mux/ps883x.c +index ad59babf7ccec..f1f65d4e5729b 100644 +--- a/drivers/usb/typec/mux/ps883x.c ++++ b/drivers/usb/typec/mux/ps883x.c +@@ -411,6 +411,7 @@ static int ps883x_retimer_probe(struct i2c_client *client) + goto err_switch_unregister; + } + ++ i2c_set_clientdata(client, retimer); + return 0; + + err_switch_unregister: +-- +2.53.0 + diff --git a/queue-6.18/vdpa-use-generic-driver_override-infrastructure.patch b/queue-6.18/vdpa-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..e3d2fc7eff --- /dev/null +++ b/queue-6.18/vdpa-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,136 @@ +From 3f39fab57933f2fbae30afc44d5c31b393a76078 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:12 +0100 +Subject: vdpa: use generic driver_override infrastructure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Danilo Krummrich + +[ Upstream commit 85bb534ff12aab6916058897b39c748940a7a4c6 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 539fec78edb4 ("vdpa: add driver_override support") +Acked-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260324005919.2408620-9-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/vdpa/vdpa.c | 48 +++++--------------------------------------- + include/linux/vdpa.h | 4 ---- + 2 files changed, 5 insertions(+), 47 deletions(-) + +diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c +index 34874beb0152e..caf0ee5d6856c 100644 +--- a/drivers/vdpa/vdpa.c ++++ b/drivers/vdpa/vdpa.c +@@ -67,57 +67,20 @@ static void vdpa_dev_remove(struct device *d) + + static int vdpa_dev_match(struct device *dev, const struct device_driver *drv) + { +- struct vdpa_device *vdev = dev_to_vdpa(dev); ++ int ret; + + /* Check override first, and if set, only use the named driver */ +- if (vdev->driver_override) +- return strcmp(vdev->driver_override, drv->name) == 0; ++ ret = device_match_driver_override(dev, drv); ++ if (ret >= 0) ++ return ret; + + /* Currently devices must be supported by all vDPA bus drivers */ + return 1; + } + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct vdpa_device *vdev = dev_to_vdpa(dev); +- int ret; +- +- ret = driver_set_override(dev, &vdev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct vdpa_device *vdev = dev_to_vdpa(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", vdev->driver_override); +- device_unlock(dev); +- +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- +-static struct attribute *vdpa_dev_attrs[] = { +- &dev_attr_driver_override.attr, +- NULL, +-}; +- +-static const struct attribute_group vdpa_dev_group = { +- .attrs = vdpa_dev_attrs, +-}; +-__ATTRIBUTE_GROUPS(vdpa_dev); +- + static const struct bus_type vdpa_bus = { + .name = "vdpa", +- .dev_groups = vdpa_dev_groups, ++ .driver_override = true, + .match = vdpa_dev_match, + .probe = vdpa_dev_probe, + .remove = vdpa_dev_remove, +@@ -132,7 +95,6 @@ static void vdpa_release_dev(struct device *d) + ops->free(vdev); + + ida_free(&vdpa_index_ida, vdev->index); +- kfree(vdev->driver_override); + kfree(vdev); + } + +diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h +index 4cf21d6e9cfde..0d8373adc1e46 100644 +--- a/include/linux/vdpa.h ++++ b/include/linux/vdpa.h +@@ -72,9 +72,6 @@ struct vdpa_mgmt_dev; + * struct vdpa_device - representation of a vDPA device + * @dev: underlying device + * @vmap: the metadata passed to upper layer to be used for mapping +- * @driver_override: driver name to force a match; do not set directly, +- * because core frees it; use driver_set_override() to +- * set or clear it. + * @config: the configuration ops for this device. + * @map: the map ops for this device + * @cf_lock: Protects get and set access to configuration layout. +@@ -90,7 +87,6 @@ struct vdpa_mgmt_dev; + struct vdpa_device { + struct device dev; + union virtio_map vmap; +- const char *driver_override; + const struct vdpa_config_ops *config; + const struct virtio_map_ops *map; + struct rw_semaphore cf_lock; /* Protects get/set config */ +-- +2.53.0 + diff --git a/queue-6.18/vfio-refactor-vfio_pci_mmap_huge_fault-function.patch b/queue-6.18/vfio-refactor-vfio_pci_mmap_huge_fault-function.patch new file mode 100644 index 0000000000..7f817405d1 --- /dev/null +++ b/queue-6.18/vfio-refactor-vfio_pci_mmap_huge_fault-function.patch @@ -0,0 +1,146 @@ +From 70d990674678d4c3c96cb8eadc788e30d1ddae7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Nov 2025 17:06:27 +0000 +Subject: vfio: refactor vfio_pci_mmap_huge_fault function + +From: Ankit Agrawal + +[ Upstream commit 9b92bc7554b543dc00a0a0b62904a9ef2ad5c4b0 ] + +Refactor vfio_pci_mmap_huge_fault to take out the implementation +to map the VMA to the PTE/PMD/PUD as a separate function. + +Export the new function to be used by nvgrace-gpu module. + +Move the alignment check code to verify that pfn and VMA VA is +aligned to the page order to the header file and make it inline. + +No functional change is intended. + +Cc: Shameer Kolothum +Cc: Alex Williamson +Cc: Jason Gunthorpe +Reviewed-by: Shameer Kolothum +Signed-off-by: Ankit Agrawal +Link: https://lore.kernel.org/r/20251127170632.3477-2-ankita@nvidia.com +Signed-off-by: Alex Williamson +Stable-dep-of: 948b71aa81cd ("drivers/vfio_pci_core: Change PXD_ORDER check from switch case to if/else block") +Signed-off-by: Sasha Levin +--- + drivers/vfio/pci/vfio_pci_core.c | 54 ++++++++++++++++---------------- + include/linux/vfio_pci_core.h | 13 ++++++++ + 2 files changed, 40 insertions(+), 27 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index 69476fc67ca08..d07f0ede5d731 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -1677,49 +1677,49 @@ static unsigned long vma_to_pfn(struct vm_area_struct *vma) + return (pci_resource_start(vdev->pdev, index) >> PAGE_SHIFT) + pgoff; + } + +-static vm_fault_t vfio_pci_mmap_huge_fault(struct vm_fault *vmf, +- unsigned int order) ++vm_fault_t vfio_pci_vmf_insert_pfn(struct vfio_pci_core_device *vdev, ++ struct vm_fault *vmf, ++ unsigned long pfn, ++ unsigned int order) + { +- struct vm_area_struct *vma = vmf->vma; +- struct vfio_pci_core_device *vdev = vma->vm_private_data; +- unsigned long addr = vmf->address & ~((PAGE_SIZE << order) - 1); +- unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; +- unsigned long pfn = vma_to_pfn(vma) + pgoff; +- vm_fault_t ret = VM_FAULT_SIGBUS; +- +- if (order && (addr < vma->vm_start || +- addr + (PAGE_SIZE << order) > vma->vm_end || +- pfn & ((1 << order) - 1))) { +- ret = VM_FAULT_FALLBACK; +- goto out; +- } +- +- down_read(&vdev->memory_lock); ++ lockdep_assert_held_read(&vdev->memory_lock); + + if (vdev->pm_runtime_engaged || !__vfio_pci_memory_enabled(vdev)) +- goto out_unlock; ++ return VM_FAULT_SIGBUS; + + switch (order) { + case 0: +- ret = vmf_insert_pfn(vma, vmf->address, pfn); +- break; ++ return vmf_insert_pfn(vmf->vma, vmf->address, pfn); + #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP + case PMD_ORDER: +- ret = vmf_insert_pfn_pmd(vmf, pfn, false); +- break; ++ return vmf_insert_pfn_pmd(vmf, pfn, false); + #endif + #ifdef CONFIG_ARCH_SUPPORTS_PUD_PFNMAP + case PUD_ORDER: +- ret = vmf_insert_pfn_pud(vmf, pfn, false); ++ return vmf_insert_pfn_pud(vmf, pfn, false); + break; + #endif + default: +- ret = VM_FAULT_FALLBACK; ++ return VM_FAULT_FALLBACK; ++ } ++} ++EXPORT_SYMBOL_GPL(vfio_pci_vmf_insert_pfn); ++ ++static vm_fault_t vfio_pci_mmap_huge_fault(struct vm_fault *vmf, ++ unsigned int order) ++{ ++ struct vm_area_struct *vma = vmf->vma; ++ struct vfio_pci_core_device *vdev = vma->vm_private_data; ++ unsigned long addr = vmf->address & ~((PAGE_SIZE << order) - 1); ++ unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; ++ unsigned long pfn = vma_to_pfn(vma) + pgoff; ++ vm_fault_t ret = VM_FAULT_FALLBACK; ++ ++ if (is_aligned_for_order(vma, addr, pfn, order)) { ++ scoped_guard(rwsem_read, &vdev->memory_lock) ++ ret = vfio_pci_vmf_insert_pfn(vdev, vmf, pfn, order); + } + +-out_unlock: +- up_read(&vdev->memory_lock); +-out: + dev_dbg_ratelimited(&vdev->pdev->dev, + "%s(,order = %d) BAR %ld page offset 0x%lx: 0x%x\n", + __func__, order, +diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h +index 7aa29428982aa..0ddc42732647e 100644 +--- a/include/linux/vfio_pci_core.h ++++ b/include/linux/vfio_pci_core.h +@@ -132,6 +132,9 @@ ssize_t vfio_pci_core_read(struct vfio_device *core_vdev, char __user *buf, + size_t count, loff_t *ppos); + ssize_t vfio_pci_core_write(struct vfio_device *core_vdev, const char __user *buf, + size_t count, loff_t *ppos); ++vm_fault_t vfio_pci_vmf_insert_pfn(struct vfio_pci_core_device *vdev, ++ struct vm_fault *vmf, unsigned long pfn, ++ unsigned int order); + int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma); + void vfio_pci_core_request(struct vfio_device *core_vdev, unsigned int count); + int vfio_pci_core_match(struct vfio_device *core_vdev, char *buf); +@@ -175,4 +178,14 @@ VFIO_IOREAD_DECLARATION(32) + VFIO_IOREAD_DECLARATION(64) + #endif + ++static inline bool is_aligned_for_order(struct vm_area_struct *vma, ++ unsigned long addr, ++ unsigned long pfn, ++ unsigned int order) ++{ ++ return !(order && (addr < vma->vm_start || ++ addr + (PAGE_SIZE << order) > vma->vm_end || ++ !IS_ALIGNED(pfn, 1 << order))); ++} ++ + #endif /* VFIO_PCI_CORE_H */ +-- +2.53.0 + diff --git a/queue-6.18/vfio-unhide-vdev-debug_root.patch b/queue-6.18/vfio-unhide-vdev-debug_root.patch new file mode 100644 index 0000000000..1aaee53237 --- /dev/null +++ b/queue-6.18/vfio-unhide-vdev-debug_root.patch @@ -0,0 +1,50 @@ +From ecbc13138336ef42fe0fc026434948b697ab39ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 17:55:08 +0100 +Subject: vfio: unhide vdev->debug_root + +From: Arnd Bergmann + +[ Upstream commit 555aa178f8d22261d71da74df6267e6e6e97f95a ] + +When debugfs is disabled, the hisilicon driver now fails to build: + +drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c: In function 'hisi_acc_vfio_debug_init': +drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1671:62: error: 'struct vfio_device' has no member named 'debug_root' + 1671 | vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root); + | ^~ + +The driver otherwise relies on dead-code elimination, but this reference +fails. The single struct member is not going to make much of a difference +for memory consumption, so just keep this visible unconditionally. + +Signed-off-by: Arnd Bergmann +Fixes: b398f91779b8 ("hisi_acc_vfio_pci: register debugfs for hisilicon migration driver") +Link: https://lore.kernel.org/r/20260327165521.3779707-1-arnd@kernel.org +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + include/linux/vfio.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/include/linux/vfio.h b/include/linux/vfio.h +index eb563f538dee5..18fc36aadc326 100644 +--- a/include/linux/vfio.h ++++ b/include/linux/vfio.h +@@ -71,13 +71,11 @@ struct vfio_device { + u8 iommufd_attached:1; + #endif + u8 cdev_opened:1; +-#ifdef CONFIG_DEBUG_FS + /* + * debug_root is a static property of the vfio_device + * which must be set prior to registering the vfio_device. + */ + struct dentry *debug_root; +-#endif + }; + + /** +-- +2.53.0 + diff --git a/queue-6.18/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch b/queue-6.18/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch new file mode 100644 index 0000000000..dbc81e77f6 --- /dev/null +++ b/queue-6.18/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch @@ -0,0 +1,64 @@ +From 00ddf17672825fdc063002b1811ba7bd8868548d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 02:30:24 +0000 +Subject: vhost_net: fix sleeping with preempt-disabled in + vhost_net_busy_poll() + +From: Kohei Enju + +[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ] + +syzbot reported "sleeping function called from invalid context" in +vhost_net_busy_poll(). + +Commit 030881372460 ("vhost_net: basic polling support") introduced a +busy-poll loop and preempt_{disable,enable}() around it, where each +iteration calls a sleepable function inside the loop. + +The purpose of disabling preemption was to keep local_clock()-based +timeout accounting on a single CPU, rather than as a requirement of +busy-poll itself: + +https://lore.kernel.org/1448435489-5949-4-git-send-email-jasowang@redhat.com + +From this perspective, migrate_disable() is sufficient here, so replace +preempt_disable() with migrate_disable(), avoiding sleepable accesses +from a preempt-disabled context. + +Fixes: 030881372460 ("vhost_net: basic polling support") +Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/ +Signed-off-by: Kohei Enju +Acked-by: Michael S. Tsirkin +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/vhost/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index 1e77c0482b849..e11b46a1c9374 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -562,7 +562,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + busyloop_timeout = poll_rx ? rvq->busyloop_timeout: + tvq->busyloop_timeout; + +- preempt_disable(); ++ migrate_disable(); + endtime = busy_clock() + busyloop_timeout; + + while (vhost_can_busy_poll(endtime)) { +@@ -579,7 +579,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + cpu_relax(); + } + +- preempt_enable(); ++ migrate_enable(); + + if (poll_rx || sock_has_rx_data(sock)) + vhost_net_busy_poll_try_queue(net, vq); +-- +2.53.0 + diff --git a/queue-6.18/virt-arm-cca-guest-fix-error-check-for-rsi_incomplet.patch b/queue-6.18/virt-arm-cca-guest-fix-error-check-for-rsi_incomplet.patch new file mode 100644 index 0000000000..f9dbb73c9b --- /dev/null +++ b/queue-6.18/virt-arm-cca-guest-fix-error-check-for-rsi_incomplet.patch @@ -0,0 +1,51 @@ +From 3e317c4bb59c96dc74ae7e76ef6e67c17df35496 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:36:36 +0100 +Subject: virt: arm-cca-guest: fix error check for RSI_INCOMPLETE + +From: Sami Mujawar + +[ Upstream commit e534e9d13d0b7bdbb2cccdace7b96b769a10540e ] + +The RSI interface can return RSI_INCOMPLETE when a report spans +multiple granules. This is an expected condition and should not be +treated as a fatal error. + +Currently, arm_cca_report_new() checks for `info.result != RSI_SUCCESS` +and bails out, which incorrectly flags RSI_INCOMPLETE as a failure. +Fix the check to only break out on results other than RSI_SUCCESS or +RSI_INCOMPLETE. + +This ensures partial reports are handled correctly and avoids spurious +-ENXIO errors when generating attestation reports. + +Fixes: 7999edc484ca ("virt: arm-cca-guest: TSM_REPORT support for realms") +Signed-off-by: Sami Mujawar +Reported-by: Jagdish Gediya +Reviewed-by: Steven Price +Reviewed-by: Gavin Shan +Reviewed-by: Suzuki K Poulose +Reviewed-by: Yeoreum Yun +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + drivers/virt/coco/arm-cca-guest/arm-cca-guest.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c +index 0c9ea24a200c9..66d00b6ceb789 100644 +--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c ++++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c +@@ -157,7 +157,8 @@ static int arm_cca_report_new(struct tsm_report *report, void *data) + } while (info.result == RSI_INCOMPLETE && + info.offset < RSI_GRANULE_SIZE); + +- if (info.result != RSI_SUCCESS) { ++ /* Break out in case of failure */ ++ if (info.result != RSI_SUCCESS && info.result != RSI_INCOMPLETE) { + ret = -ENXIO; + token_size = 0; + goto exit_free_granule_page; +-- +2.53.0 + diff --git a/queue-6.18/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch b/queue-6.18/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch new file mode 100644 index 0000000000..2f5b84884e --- /dev/null +++ b/queue-6.18/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch @@ -0,0 +1,63 @@ +From 9e411f3ef8bd7dabb800dfb2f59dd483dd3c3637 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:21:21 -0700 +Subject: virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via + VQ_PAIRS_SET + +From: Brett Creeley + +[ Upstream commit 3bc06da858ef17cfe94b49efc0d9713727012835 ] + +When netif_is_rxfh_configured() is true (i.e., the user has explicitly +configured the RSS indirection table), virtnet_set_queues() skips the +RSS update path and falls through to the VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET +command to change the number of queue pairs. However, it does not update +vi->rss_trailer.max_tx_vq to reflect the new queue_pairs value. + +This causes a mismatch between vi->curr_queue_pairs and +vi->rss_trailer.max_tx_vq. Any subsequent RSS reconfiguration (e.g., +via ethtool -X) calls virtnet_commit_rss_command(), which sends the +stale max_tx_vq to the device, silently reverting the queue count. + +Reproduction: +1. User configured RSS + ethtool -X eth0 equal 8 +2. VQ_PAIRS_SET path; max_tx_vq stays 16 + ethtool -L eth0 combined 12 +3. RSS commit uses max_tx_vq=16 instead of 12 + ethtool -X eth0 equal 4 + +Fix this by updating vi->rss_trailer.max_tx_vq after a successful +VQ_PAIRS_SET command when RSS is enabled, keeping it in sync with +curr_queue_pairs. + +Fixes: 50bfcaedd78e ("virtio_net: Update rss when set queue") +Signed-off-by: Brett Creeley +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260416212121.29073-1-brett.creeley@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/virtio_net.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 0cfe7ab59412c..aed65dbf3fca0 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -3828,6 +3828,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) + queue_pairs); + return -EINVAL; + } ++ ++ /* Keep max_tx_vq in sync so that a later RSS command does not ++ * revert queue_pairs to a stale value. ++ */ ++ if (vi->has_rss) ++ vi->rss_trailer.max_tx_vq = cpu_to_le16(queue_pairs); + succ: + vi->curr_queue_pairs = queue_pairs; + if (dev->flags & IFF_UP) { +-- +2.53.0 + diff --git a/queue-6.18/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch b/queue-6.18/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch new file mode 100644 index 0000000000..ce7641da2f --- /dev/null +++ b/queue-6.18/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch @@ -0,0 +1,115 @@ +From 1e7f489687ef4f9e2ba4fcb71820332996a64734 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 09:36:07 +0300 +Subject: vrf: Fix a potential NPD when removing a port from a VRF + +From: Ido Schimmel + +[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ] + +RCU readers that identified a net device as a VRF port using +netif_is_l3_slave() assume that a subsequent call to +netdev_master_upper_dev_get_rcu() will return a VRF device. They then +continue to dereference its l3mdev operations. + +This assumption is not always correct and can result in a NPD [1]. There +is no RCU synchronization when removing a port from a VRF, so it is +possible for an RCU reader to see a new master device (e.g., a bridge) +that does not have l3mdev operations. + +Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE +flag. Skip this synchronization when a net device is removed from a VRF +as part of its deletion and when the VRF device itself is deleted. In +the latter case an RCU grace period will pass by the time RTNL is +released. + +[1] +BUG: kernel NULL pointer dereference, address: 0000000000000000 +[...] +RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) +[...] +Call Trace: + +l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) +__inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) +inet_bind_sk (net/ipv4/af_inet.c:469) +__sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) +__x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Fixes: fdeea7be88b1 ("net: vrf: Set slave's private flag before linking") +Reported-by: Haoze Xie +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/netdev/20260419145332.3988923-1-n05ec@lzu.edu.cn/ +Signed-off-by: Ido Schimmel +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260423063607.1208202-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vrf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index 571847a7f86d7..4b62b167650ea 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -1084,6 +1084,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + + err: + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ synchronize_net(); + return ret; + } + +@@ -1103,10 +1104,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + } + + /* inverse of do_vrf_add_slave */ +-static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) ++static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, ++ bool needs_sync) + { + netdev_upper_dev_unlink(port_dev, dev); + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ /* Make sure that concurrent RCU readers that identified the device ++ * as a VRF port see a VRF master or no master at all. ++ */ ++ if (needs_sync) ++ synchronize_net(); + + cycle_netdev(port_dev, NULL); + +@@ -1115,7 +1122,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + + static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + { +- return do_vrf_del_slave(dev, port_dev); ++ return do_vrf_del_slave(dev, port_dev, true); + } + + static void vrf_dev_uninit(struct net_device *dev) +@@ -1669,7 +1676,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) + struct list_head *iter; + + netdev_for_each_lower_dev(dev, port_dev, iter) +- vrf_del_slave(dev, port_dev); ++ do_vrf_del_slave(dev, port_dev, false); + + vrf_map_unregister_dev(dev); + +@@ -1801,7 +1808,7 @@ static int vrf_device_event(struct notifier_block *unused, + goto out; + + vrf_dev = netdev_master_upper_dev_get(dev); +- vrf_del_slave(vrf_dev, dev); ++ do_vrf_del_slave(vrf_dev, dev, false); + } + out: + return NOTIFY_DONE; +-- +2.53.0 + diff --git a/queue-6.18/vsock-fix-buffer-size-clamping-order.patch b/queue-6.18/vsock-fix-buffer-size-clamping-order.patch new file mode 100644 index 0000000000..297bb92967 --- /dev/null +++ b/queue-6.18/vsock-fix-buffer-size-clamping-order.patch @@ -0,0 +1,55 @@ +From 3e4ccdfdf50046dd71190022ad5aeaf341611f9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 18:34:12 +0200 +Subject: vsock: fix buffer size clamping order + +From: Norbert Szetei + +commit d114bfdc9b76bf93b881e195b7ec957c14227bab upstream. + +In vsock_update_buffer_size(), the buffer size was being clamped to the +maximum first, and then to the minimum. If a user sets a minimum buffer +size larger than the maximum, the minimum check overrides the maximum +check, inverting the constraint. + +This breaks the intended socket memory boundaries by allowing the +vsk->buffer_size to grow beyond the configured vsk->buffer_max_size. + +Fix this by checking the minimum first, and then the maximum. This +ensures the buffer size never exceeds the buffer_max_size. + +Fixes: b9f2b0ffde0c ("vsock: handle buffer_size sockopts in the core") +Suggested-by: Stefano Garzarella +Signed-off-by: Norbert Szetei +Reviewed-by: Stefano Garzarella +Link: https://patch.msgid.link/180118C5-8BCF-4A63-A305-4EE53A34AB9C@doyensec.com +Signed-off-by: Jakub Kicinski +Cc: Luigi Leonardi +Signed-off-by: Greg Kroah-Hartman +--- + net/vmw_vsock/af_vsock.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c +index cbd649bf01459..9d0e1915abbe8 100644 +--- a/net/vmw_vsock/af_vsock.c ++++ b/net/vmw_vsock/af_vsock.c +@@ -1846,12 +1846,12 @@ static void vsock_update_buffer_size(struct vsock_sock *vsk, + const struct vsock_transport *transport, + u64 val) + { +- if (val > vsk->buffer_max_size) +- val = vsk->buffer_max_size; +- + if (val < vsk->buffer_min_size) + val = vsk->buffer_min_size; + ++ if (val > vsk->buffer_max_size) ++ val = vsk->buffer_max_size; ++ + if (val != vsk->buffer_size && + transport && transport->notify_buffer_size) + transport->notify_buffer_size(vsk, &val); +-- +2.53.0 + diff --git a/queue-6.18/vsock-virtio-fix-accept-queue-count-leak-on-transpor.patch b/queue-6.18/vsock-virtio-fix-accept-queue-count-leak-on-transpor.patch new file mode 100644 index 0000000000..e5b1db05be --- /dev/null +++ b/queue-6.18/vsock-virtio-fix-accept-queue-count-leak-on-transpor.patch @@ -0,0 +1,59 @@ +From bb960936b97d51f78f28df113b45ec2a9c3b35ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 21:14:09 +0800 +Subject: vsock/virtio: fix accept queue count leak on transport mismatch + +From: Dudu Lu + +commit 52bcb57a4e8a0865a76c587c2451906342ae1b2d upstream. + +virtio_transport_recv_listen() calls sk_acceptq_added() before +vsock_assign_transport(). If vsock_assign_transport() fails or +selects a different transport, the error path returns without +calling sk_acceptq_removed(), permanently incrementing +sk_ack_backlog. + +After approximately backlog+1 such failures, sk_acceptq_is_full() +returns true, causing the listener to reject all new connections. + +Fix by moving sk_acceptq_added() to after the transport validation, +matching the pattern used by vmci_transport and hyperv_transport. + +Fixes: c0cfa2d8a788 ("vsock: add multi-transports support") +Signed-off-by: Dudu Lu +Reviewed-by: Bobby Eshleman +Reviewed-by: Luigi Leonardi +Reviewed-by: Stefano Garzarella +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260413131409.19022-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Cc: Luigi Leonardi +Signed-off-by: Greg Kroah-Hartman +--- + net/vmw_vsock/virtio_transport_common.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index 3e148c39d1076..41be06c4bd7ff 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -1528,8 +1528,6 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb, + return -ENOMEM; + } + +- sk_acceptq_added(sk); +- + lock_sock_nested(child, SINGLE_DEPTH_NESTING); + + child->sk_state = TCP_ESTABLISHED; +@@ -1551,6 +1549,7 @@ virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb, + return ret; + } + ++ sk_acceptq_added(sk); + if (virtio_transport_space_update(child, skb)) + child->sk_write_space(child); + +-- +2.53.0 + diff --git a/queue-6.18/vsock-virtio-fix-empty-payload-in-tap-skb-for-non-li.patch b/queue-6.18/vsock-virtio-fix-empty-payload-in-tap-skb-for-non-li.patch new file mode 100644 index 0000000000..4ac8889ecc --- /dev/null +++ b/queue-6.18/vsock-virtio-fix-empty-payload-in-tap-skb-for-non-li.patch @@ -0,0 +1,101 @@ +From a14dcdcc3927cd2bdbc1334b85fedf3307d72bd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 18:44:11 +0200 +Subject: vsock/virtio: fix empty payload in tap skb for non-linear buffers + +From: Stefano Garzarella + +commit 3a3e3d90cbc79600544536723911657730759af3 upstream. + +For non-linear skbs, virtio_transport_build_skb() goes through +virtio_transport_copy_nonlinear_skb() to copy the original payload +in the new skb to be delivered to the vsockmon tap device. +This manually initializes an iov_iter but does not set iov_iter.count. +Since the iov_iter is zero-initialized, the copy length is zero and no +payload is actually copied to the monitor interface, leaving data +un-initialized. + +Fix this by removing the linear vs non-linear split and using +skb_copy_datagram_iter() with iov_iter_kvec() for all cases, as +vhost-vsock already does. This handles both linear and non-linear skbs, +properly initializes the iov_iter, and removes the now unused +virtio_transport_copy_nonlinear_skb(). + +While touching this code, let's also check the return value of +skb_copy_datagram_iter(), even though it's unlikely to fail. + +Fixes: 4b0bf10eb077 ("vsock/virtio: non-linear skb handling for tap") +Reported-by: Yiqi Sun +Signed-off-by: Stefano Garzarella +Reviewed-by: Bobby Eshleman +Reviewed-by: Arseniy Krasnov +Link: https://patch.msgid.link/20260508164411.261440-3-sgarzare@redhat.com +Acked-by: Michael S. Tsirkin +Signed-off-by: Paolo Abeni +Cc: Luigi Leonardi +Signed-off-by: Greg Kroah-Hartman +--- + net/vmw_vsock/virtio_transport_common.c | 40 ++++++++----------------- + 1 file changed, 12 insertions(+), 28 deletions(-) + +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index 57b69b7e895f7..3e148c39d1076 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -139,27 +139,6 @@ static void virtio_transport_init_hdr(struct sk_buff *skb, + hdr->fwd_cnt = cpu_to_le32(0); + } + +-static void virtio_transport_copy_nonlinear_skb(const struct sk_buff *skb, +- void *dst, +- size_t len) +-{ +- struct iov_iter iov_iter = { 0 }; +- struct kvec kvec; +- size_t to_copy; +- +- kvec.iov_base = dst; +- kvec.iov_len = len; +- +- iov_iter.iter_type = ITER_KVEC; +- iov_iter.kvec = &kvec; +- iov_iter.nr_segs = 1; +- +- to_copy = min_t(size_t, len, skb->len); +- +- skb_copy_datagram_iter(skb, VIRTIO_VSOCK_SKB_CB(skb)->offset, +- &iov_iter, to_copy); +-} +- + /* Packet capture */ + static struct sk_buff *virtio_transport_build_skb(void *opaque) + { +@@ -217,13 +196,18 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque) + skb_put_data(skb, pkt_hdr, sizeof(*pkt_hdr)); + + if (payload_len) { +- if (skb_is_nonlinear(pkt)) { +- void *data = skb_put(skb, payload_len); +- +- virtio_transport_copy_nonlinear_skb(pkt, data, payload_len); +- } else { +- skb_put_data(skb, pkt->data + VIRTIO_VSOCK_SKB_CB(pkt)->offset, +- payload_len); ++ struct iov_iter iov_iter; ++ struct kvec kvec; ++ void *data = skb_put(skb, payload_len); ++ ++ kvec.iov_base = data; ++ kvec.iov_len = payload_len; ++ iov_iter_kvec(&iov_iter, ITER_DEST, &kvec, 1, payload_len); ++ ++ if (skb_copy_datagram_iter(pkt, VIRTIO_VSOCK_SKB_CB(pkt)->offset, ++ &iov_iter, payload_len)) { ++ kfree_skb(skb); ++ return NULL; + } + } + +-- +2.53.0 + diff --git a/queue-6.18/vsock-virtio-fix-length-and-offset-in-tap-skb-for-sp.patch b/queue-6.18/vsock-virtio-fix-length-and-offset-in-tap-skb-for-sp.patch new file mode 100644 index 0000000000..604fc56e61 --- /dev/null +++ b/queue-6.18/vsock-virtio-fix-length-and-offset-in-tap-skb-for-sp.patch @@ -0,0 +1,70 @@ +From 6aa2c01195f4ad4abcca3004727ee6854947a917 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 May 2026 18:44:10 +0200 +Subject: vsock/virtio: fix length and offset in tap skb for split packets + +From: Stefano Garzarella + +commit 5f344d809e015fba3709e5219428c00b8ac5d7df upstream. + +virtio_transport_build_skb() builds a new skb to be delivered to the +vsockmon tap device. To build the new skb, it uses the original skb +data length as payload length, but as the comment notes, the original +packet stored in the skb may have been split in multiple packets, so we +need to use the length in the header, which is correctly updated before +the packet is delivered to the tap, and the offset for the data. + +This was also similar to what we did before commit 71dc9ec9ac7d +("virtio/vsock: replace virtio_vsock_pkt with sk_buff") where we probably +missed something during the skb conversion. + +Also update the comment above, which was left stale by the skb +conversion and still mentioned a buffer pointer that no longer exists. + +Fixes: 71dc9ec9ac7d ("virtio/vsock: replace virtio_vsock_pkt with sk_buff") +Signed-off-by: Stefano Garzarella +Reviewed-by: Bobby Eshleman +Reviewed-by: Arseniy Krasnov +Link: https://patch.msgid.link/20260508164411.261440-2-sgarzare@redhat.com +Acked-by: Michael S. Tsirkin +Signed-off-by: Paolo Abeni +Cc: Luigi Leonardi +Signed-off-by: Greg Kroah-Hartman +--- + net/vmw_vsock/virtio_transport_common.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index a807a4aa62d3f..57b69b7e895f7 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -169,12 +169,12 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque) + struct sk_buff *skb; + size_t payload_len; + +- /* A packet could be split to fit the RX buffer, so we can retrieve +- * the payload length from the header and the buffer pointer taking +- * care of the offset in the original packet. ++ /* A packet could be split to fit the RX buffer, so we use ++ * the payload length from the header, which has been updated ++ * by the sender to reflect the fragment size. + */ + pkt_hdr = virtio_vsock_hdr(pkt); +- payload_len = pkt->len; ++ payload_len = le32_to_cpu(pkt_hdr->len); + + skb = alloc_skb(sizeof(*hdr) + sizeof(*pkt_hdr) + payload_len, + GFP_ATOMIC); +@@ -222,7 +222,8 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque) + + virtio_transport_copy_nonlinear_skb(pkt, data, payload_len); + } else { +- skb_put_data(skb, pkt->data, payload_len); ++ skb_put_data(skb, pkt->data + VIRTIO_VSOCK_SKB_CB(pkt)->offset, ++ payload_len); + } + } + +-- +2.53.0 + diff --git a/queue-6.18/vsock-virtio-fix-msg_zerocopy-pinned-pages-accountin.patch b/queue-6.18/vsock-virtio-fix-msg_zerocopy-pinned-pages-accountin.patch new file mode 100644 index 0000000000..b1910ab929 --- /dev/null +++ b/queue-6.18/vsock-virtio-fix-msg_zerocopy-pinned-pages-accountin.patch @@ -0,0 +1,81 @@ +From 6c09a4c76440c318e275a049e20ad88bc081cf28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 15:20:51 +0200 +Subject: vsock/virtio: fix MSG_ZEROCOPY pinned-pages accounting + +From: Stefano Garzarella + +[ Upstream commit 1cb36e252211506f51095fe7ced8286cc77b4c80 ] + +virtio_transport_init_zcopy_skb() uses iter->count as the size argument +for msg_zerocopy_realloc(), which in turn passes it to +mm_account_pinned_pages() for RLIMIT_MEMLOCK accounting. However, this +function is called after virtio_transport_fill_skb() has already consumed +the iterator via __zerocopy_sg_from_iter(), so on the last skb, iter->count +will be 0, skipping the RLIMIT_MEMLOCK enforcement. + +Pass pkt_len (the total bytes being sent) as an explicit parameter to +virtio_transport_init_zcopy_skb() instead of reading the already-consumed +iter->count. + +This matches TCP and UDP, which both call msg_zerocopy_realloc() with +the original message size. + +Fixes: 581512a6dc93 ("vsock/virtio: MSG_ZEROCOPY flag support") +Reported-by: Yiming Qian +Signed-off-by: Stefano Garzarella +Reviewed-by: Bobby Eshleman +Link: https://patch.msgid.link/20260420132051.217589-1-sgarzare@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/virtio_transport_common.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index 41be06c4bd7ff..495c93cddcdc0 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -75,6 +75,7 @@ static bool virtio_transport_can_zcopy(const struct virtio_transport *t_ops, + static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk, + struct sk_buff *skb, + struct msghdr *msg, ++ size_t pkt_len, + bool zerocopy) + { + struct ubuf_info *uarg; +@@ -83,12 +84,10 @@ static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk, + uarg = msg->msg_ubuf; + net_zcopy_get(uarg); + } else { +- struct iov_iter *iter = &msg->msg_iter; + struct ubuf_info_msgzc *uarg_zc; + + uarg = msg_zerocopy_realloc(sk_vsock(vsk), +- iter->count, +- NULL, false); ++ pkt_len, NULL, false); + if (!uarg) + return -1; + +@@ -385,11 +384,17 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, + * each iteration. If this is last skb for this buffer + * and MSG_ZEROCOPY mode is in use - we must allocate + * completion for the current syscall. ++ * ++ * Pass pkt_len because msg iter is already consumed ++ * by virtio_transport_fill_skb(), so iter->count ++ * can not be used for RLIMIT_MEMLOCK pinned-pages ++ * accounting done by msg_zerocopy_realloc(). + */ + if (info->msg && info->msg->msg_flags & MSG_ZEROCOPY && + skb_len == rest_len && info->op == VIRTIO_VSOCK_OP_RW) { + if (virtio_transport_init_zcopy_skb(vsk, skb, + info->msg, ++ pkt_len, + can_zcopy)) { + kfree_skb(skb); + ret = -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.18/wifi-ath10k-fix-station-lookup-failure-during-discon.patch b/queue-6.18/wifi-ath10k-fix-station-lookup-failure-during-discon.patch new file mode 100644 index 0000000000..62ae7554a3 --- /dev/null +++ b/queue-6.18/wifi-ath10k-fix-station-lookup-failure-during-discon.patch @@ -0,0 +1,140 @@ +From 626403513a314341b0866bdbf48a1cb195c43cc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:05:01 +0800 +Subject: wifi: ath10k: fix station lookup failure during disconnect + +From: Baochen Qiang + +[ Upstream commit 9a34a59c6086ae731a06b3e61b0951feef758648 ] + +Recent commit [1] moved station statistics collection to an earlier stage +of the disconnect flow. With this change in place, ath10k fails to resolve +the station entry when handling a peer stats event triggered during +disconnect, resulting in log messages such as: + +wlp58s0: deauthenticating from 74:1a:e0:e7:b4:c8 by local choice (Reason: 3=DEAUTH_LEAVING) +ath10k_pci 0000:3a:00.0: not found station for peer stats +ath10k_pci 0000:3a:00.0: failed to parse stats info tlv: -22 + +The failure occurs because ath10k relies on ieee80211_find_sta_by_ifaddr() +for station lookup. That function uses local->sta_hash, but by the time +the peer stats request is triggered during disconnect, mac80211 has +already removed the station from that hash table, leading to lookup +failure. + +Before commit [1], this issue was not visible because the transition from +IEEE80211_STA_NONE to IEEE80211_STA_NOTEXIST prevented ath10k from sending +a peer stats request at all: ath10k_mac_sta_get_peer_stats_info() would +fail early to find the peer and skip requesting statistics. + +Fix this by switching the lookup path to ath10k_peer_find(), which queries +ath10k's internal peer table. At the point where the firmware emits the +peer stats event, the peer entry is still present in the driver's list, +ensuring lookup succeeds. + +Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00309-QCARMSWPZ-1 + +Fixes: a203dbeeca15 ("wifi: mac80211: collect station statistics earlier when disconnect") # [1] +Reported-by: Paul Menzel +Closes: https://lore.kernel.org/ath10k/57671b89-ec9f-4e6c-992c-45eb8e75929c@molgen.mpg.de +Signed-off-by: Baochen Qiang +Reviewed-by: Rameshkumar Sundaram +Reviewed-by: Paul Menzel +Tested-by: Paul Menzel +Link: https://patch.msgid.link/20260325-ath10k-station-lookup-failure-v1-1-2e0c970f25d5@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/wmi-tlv.c | 26 +++++++++++++---------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +index 16d07d619b4df..ba1294c8ee39f 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +@@ -3,7 +3,7 @@ + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +- * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + #include "core.h" + #include "debug.h" +@@ -14,6 +14,7 @@ + #include "wmi-tlv.h" + #include "p2p.h" + #include "testmode.h" ++#include "txrx.h" + #include + + /***************/ +@@ -224,8 +225,9 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 + const void *ptr, void *data) + { + const struct wmi_tlv_peer_stats_info *stat = ptr; +- struct ieee80211_sta *sta; ++ u32 vdev_id = *(u32 *)data; + struct ath10k_sta *arsta; ++ struct ath10k_peer *peer; + + if (tag != WMI_TLV_TAG_STRUCT_PEER_STATS_INFO) + return -EPROTO; +@@ -241,20 +243,20 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 + __le32_to_cpu(stat->last_tx_rate_code), + __le32_to_cpu(stat->last_tx_bitrate_kbps)); + +- rcu_read_lock(); +- sta = ieee80211_find_sta_by_ifaddr(ar->hw, stat->peer_macaddr.addr, NULL); +- if (!sta) { +- rcu_read_unlock(); +- ath10k_warn(ar, "not found station for peer stats\n"); ++ guard(spinlock_bh)(&ar->data_lock); ++ ++ peer = ath10k_peer_find(ar, vdev_id, stat->peer_macaddr.addr); ++ if (!peer || !peer->sta) { ++ ath10k_warn(ar, "not found %s with vdev id %u mac addr %pM for peer stats\n", ++ peer ? "sta" : "peer", vdev_id, stat->peer_macaddr.addr); + return -EINVAL; + } + +- arsta = (struct ath10k_sta *)sta->drv_priv; ++ arsta = (struct ath10k_sta *)peer->sta->drv_priv; + arsta->rx_rate_code = __le32_to_cpu(stat->last_rx_rate_code); + arsta->rx_bitrate_kbps = __le32_to_cpu(stat->last_rx_bitrate_kbps); + arsta->tx_rate_code = __le32_to_cpu(stat->last_tx_rate_code); + arsta->tx_bitrate_kbps = __le32_to_cpu(stat->last_tx_bitrate_kbps); +- rcu_read_unlock(); + + return 0; + } +@@ -266,6 +268,7 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar, + const struct wmi_tlv_peer_stats_info_ev *ev; + const void *data; + u32 num_peer_stats; ++ u32 vdev_id; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +@@ -284,15 +287,16 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar, + } + + num_peer_stats = __le32_to_cpu(ev->num_peers); ++ vdev_id = __le32_to_cpu(ev->vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv peer stats info update peer vdev id %d peers %i more data %d\n", +- __le32_to_cpu(ev->vdev_id), ++ vdev_id, + num_peer_stats, + __le32_to_cpu(ev->more_data)); + + ret = ath10k_wmi_tlv_iter(ar, data, ath10k_wmi_tlv_len(data), +- ath10k_wmi_tlv_parse_peer_stats_info, NULL); ++ ath10k_wmi_tlv_parse_peer_stats_info, &vdev_id); + if (ret) + ath10k_warn(ar, "failed to parse stats info tlv: %d\n", ret); + +-- +2.53.0 + diff --git a/queue-6.18/wifi-brcmfmac-fix-error-pointer-dereference.patch b/queue-6.18/wifi-brcmfmac-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..5e0d45c74f --- /dev/null +++ b/queue-6.18/wifi-brcmfmac-fix-error-pointer-dereference.patch @@ -0,0 +1,80 @@ +From 719b561469512b5b4c8294d677e417ce4d280ff4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 20:30:43 -0600 +Subject: wifi: brcmfmac: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit dd8592fc6007a451c3e4b9025de365e39de8178a ] + +The function brcmf_chip_add_core() can return an error pointer and is +not checked. Add checks for error pointer. + +Detected by Smatch: +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1010 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1013 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1016 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1019 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1022 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +Fixes: cb7cf7be9eba7 ("brcmfmac: make chip related functions host interface independent") +Signed-off-by: Ethan Tidmore +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260217023043.73631-1-ethantidmore06@gmail.com +[add missing wifi: prefix] +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 4239f2b21e542..dcd8a296de106 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -1007,18 +1007,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + + core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, + SI_ENUM_BASE_DEFAULT, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, + BCM4329_CORE_BUS_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, + BCM4329_CORE_SOCRAM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, + BCM4329_CORE_ARM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + + core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + } else if (socitype == SOCI_AI) { + ci->iscoreup = brcmf_chip_ai_iscoreup; +-- +2.53.0 + diff --git a/queue-6.18/wifi-ieee80211-fix-definition-of-eht-mcs-15-in-mru.patch b/queue-6.18/wifi-ieee80211-fix-definition-of-eht-mcs-15-in-mru.patch new file mode 100644 index 0000000000..c899c14f58 --- /dev/null +++ b/queue-6.18/wifi-ieee80211-fix-definition-of-eht-mcs-15-in-mru.patch @@ -0,0 +1,47 @@ +From dab1f1b1f4bee71d0618ecc69e8722d47314efe3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:21:49 +0800 +Subject: wifi: ieee80211: fix definition of EHT-MCS 15 in MRU +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shayne Chen + +[ Upstream commit cb0caadb64ca0894c4a24e1a34841f260d462f90 ] + +According to the definition in IEEE Std 802.11be-2024, Table 9-417r, each +bit indicates support for the transmission and reception of EHT-MCS 15 in: +- B0: 52+26-tone and 106+26-tone MRUs. +- B1: a 484+242-tone MRU if 80 MHz is supported. +- B2: a 996+484-tone MRU and a 996+484+242-tone MRU if 160 MHz is + supported. +- B3: a 3×996-tone MRU if 320 MHz is supported. + +Fixes: 6239da18d2f9 ("wifi: mac80211: adjust EHT capa when lowering bandwidth") +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260313062150.3165433-1-shayne.chen@mediatek.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + include/linux/ieee80211-eht.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/ieee80211-eht.h b/include/linux/ieee80211-eht.h +index f9782e46c5e52..cd9abf5193966 100644 +--- a/include/linux/ieee80211-eht.h ++++ b/include/linux/ieee80211-eht.h +@@ -251,8 +251,8 @@ struct ieee80211_eht_operation_info { + #define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x40 + #define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x07 + +-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x08 +-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x30 ++#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x10 ++#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x20 + #define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ 0x40 + #define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x78 + #define IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP 0x80 +-- +2.53.0 + diff --git a/queue-6.18/wifi-ieee80211-split-eht-definitions-out.patch b/queue-6.18/wifi-ieee80211-split-eht-definitions-out.patch new file mode 100644 index 0000000000..bc8eff7149 --- /dev/null +++ b/queue-6.18/wifi-ieee80211-split-eht-definitions-out.patch @@ -0,0 +1,2423 @@ +From 1d784c79b625c8e4d33a9abec47204aa108fee28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 15:36:53 +0100 +Subject: wifi: ieee80211: split EHT definitions out + +From: Johannes Berg + +[ Upstream commit 86bc0c662322b4749cd666678d2fdce7015bcae3 ] + +The ieee80211.h file has gotten very long, continue splitting +it by putting EHT definitions into a separate file. + +Link: https://patch.msgid.link/20251105153843.bf77fe169140.I691267e0edd914c604a5bfd447d33be00044c9b4@changeid +Signed-off-by: Johannes Berg +Stable-dep-of: cb0caadb64ca ("wifi: ieee80211: fix definition of EHT-MCS 15 in MRU") +Signed-off-by: Sasha Levin +--- + include/linux/ieee80211-eht.h | 1182 +++++++++++++++++++++++++++++++++ + include/linux/ieee80211.h | 1164 +------------------------------- + 2 files changed, 1184 insertions(+), 1162 deletions(-) + create mode 100644 include/linux/ieee80211-eht.h + +diff --git a/include/linux/ieee80211-eht.h b/include/linux/ieee80211-eht.h +new file mode 100644 +index 0000000000000..f9782e46c5e52 +--- /dev/null ++++ b/include/linux/ieee80211-eht.h +@@ -0,0 +1,1182 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * IEEE 802.11 EHT definitions ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Copyright (c) 2005, Devicescape Software, Inc. ++ * Copyright (c) 2006, Michael Wu ++ * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH ++ * Copyright (c) 2016 - 2017 Intel Deutschland GmbH ++ * Copyright (c) 2018 - 2025 Intel Corporation ++ */ ++ ++#ifndef LINUX_IEEE80211_EHT_H ++#define LINUX_IEEE80211_EHT_H ++ ++#include ++#include ++/* need HE definitions for the inlines here */ ++#include ++ ++#define IEEE80211_TTLM_MAX_CNT 2 ++#define IEEE80211_TTLM_CONTROL_DIRECTION 0x03 ++#define IEEE80211_TTLM_CONTROL_DEF_LINK_MAP 0x04 ++#define IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT 0x08 ++#define IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT 0x10 ++#define IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE 0x20 ++ ++#define IEEE80211_TTLM_DIRECTION_DOWN 0 ++#define IEEE80211_TTLM_DIRECTION_UP 1 ++#define IEEE80211_TTLM_DIRECTION_BOTH 2 ++ ++/** ++ * struct ieee80211_ttlm_elem - TID-To-Link Mapping element ++ * ++ * Defined in section 9.4.2.314 in P802.11be_D4 ++ * ++ * @control: the first part of control field ++ * @optional: the second part of control field ++ */ ++struct ieee80211_ttlm_elem { ++ u8 control; ++ u8 optional[]; ++} __packed; ++ ++#define IEEE80211_EHT_MCS_NSS_RX 0x0f ++#define IEEE80211_EHT_MCS_NSS_TX 0xf0 ++ ++/** ++ * struct ieee80211_eht_mcs_nss_supp_20mhz_only - EHT 20MHz only station max ++ * supported NSS for per MCS. ++ * ++ * For each field below, bits 0 - 3 indicate the maximal number of spatial ++ * streams for Rx, and bits 4 - 7 indicate the maximal number of spatial streams ++ * for Tx. ++ * ++ * @rx_tx_mcs7_max_nss: indicates the maximum number of spatial streams ++ * supported for reception and the maximum number of spatial streams ++ * supported for transmission for MCS 0 - 7. ++ * @rx_tx_mcs9_max_nss: indicates the maximum number of spatial streams ++ * supported for reception and the maximum number of spatial streams ++ * supported for transmission for MCS 8 - 9. ++ * @rx_tx_mcs11_max_nss: indicates the maximum number of spatial streams ++ * supported for reception and the maximum number of spatial streams ++ * supported for transmission for MCS 10 - 11. ++ * @rx_tx_mcs13_max_nss: indicates the maximum number of spatial streams ++ * supported for reception and the maximum number of spatial streams ++ * supported for transmission for MCS 12 - 13. ++ * @rx_tx_max_nss: array of the previous fields for easier loop access ++ */ ++struct ieee80211_eht_mcs_nss_supp_20mhz_only { ++ union { ++ struct { ++ u8 rx_tx_mcs7_max_nss; ++ u8 rx_tx_mcs9_max_nss; ++ u8 rx_tx_mcs11_max_nss; ++ u8 rx_tx_mcs13_max_nss; ++ }; ++ u8 rx_tx_max_nss[4]; ++ }; ++}; ++ ++/** ++ * struct ieee80211_eht_mcs_nss_supp_bw - EHT max supported NSS per MCS (except ++ * 20MHz only stations). ++ * ++ * For each field below, bits 0 - 3 indicate the maximal number of spatial ++ * streams for Rx, and bits 4 - 7 indicate the maximal number of spatial streams ++ * for Tx. ++ * ++ * @rx_tx_mcs9_max_nss: indicates the maximum number of spatial streams ++ * supported for reception and the maximum number of spatial streams ++ * supported for transmission for MCS 0 - 9. ++ * @rx_tx_mcs11_max_nss: indicates the maximum number of spatial streams ++ * supported for reception and the maximum number of spatial streams ++ * supported for transmission for MCS 10 - 11. ++ * @rx_tx_mcs13_max_nss: indicates the maximum number of spatial streams ++ * supported for reception and the maximum number of spatial streams ++ * supported for transmission for MCS 12 - 13. ++ * @rx_tx_max_nss: array of the previous fields for easier loop access ++ */ ++struct ieee80211_eht_mcs_nss_supp_bw { ++ union { ++ struct { ++ u8 rx_tx_mcs9_max_nss; ++ u8 rx_tx_mcs11_max_nss; ++ u8 rx_tx_mcs13_max_nss; ++ }; ++ u8 rx_tx_max_nss[3]; ++ }; ++}; ++ ++/** ++ * struct ieee80211_eht_cap_elem_fixed - EHT capabilities fixed data ++ * ++ * This structure is the "EHT Capabilities element" fixed fields as ++ * described in P802.11be_D2.0 section 9.4.2.313. ++ * ++ * @mac_cap_info: MAC capabilities, see IEEE80211_EHT_MAC_CAP* ++ * @phy_cap_info: PHY capabilities, see IEEE80211_EHT_PHY_CAP* ++ */ ++struct ieee80211_eht_cap_elem_fixed { ++ u8 mac_cap_info[2]; ++ u8 phy_cap_info[9]; ++} __packed; ++ ++/** ++ * struct ieee80211_eht_cap_elem - EHT capabilities element ++ * @fixed: fixed parts, see &ieee80211_eht_cap_elem_fixed ++ * @optional: optional parts ++ */ ++struct ieee80211_eht_cap_elem { ++ struct ieee80211_eht_cap_elem_fixed fixed; ++ ++ /* ++ * Followed by: ++ * Supported EHT-MCS And NSS Set field: 4, 3, 6 or 9 octets. ++ * EHT PPE Thresholds field: variable length. ++ */ ++ u8 optional[]; ++} __packed; ++ ++#define IEEE80211_EHT_OPER_INFO_PRESENT 0x01 ++#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x02 ++#define IEEE80211_EHT_OPER_EHT_DEF_PE_DURATION 0x04 ++#define IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_LIMIT 0x08 ++#define IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_EXP_MASK 0x30 ++#define IEEE80211_EHT_OPER_MCS15_DISABLE 0x40 ++ ++/** ++ * struct ieee80211_eht_operation - eht operation element ++ * ++ * This structure is the "EHT Operation Element" fields as ++ * described in P802.11be_D2.0 section 9.4.2.311 ++ * ++ * @params: EHT operation element parameters. See &IEEE80211_EHT_OPER_* ++ * @basic_mcs_nss: indicates the EHT-MCSs for each number of spatial streams in ++ * EHT PPDUs that are supported by all EHT STAs in the BSS in transmit and ++ * receive. ++ * @optional: optional parts ++ */ ++struct ieee80211_eht_operation { ++ u8 params; ++ struct ieee80211_eht_mcs_nss_supp_20mhz_only basic_mcs_nss; ++ u8 optional[]; ++} __packed; ++ ++/** ++ * struct ieee80211_eht_operation_info - eht operation information ++ * ++ * @control: EHT operation information control. ++ * @ccfs0: defines a channel center frequency for a 20, 40, 80, 160, or 320 MHz ++ * EHT BSS. ++ * @ccfs1: defines a channel center frequency for a 160 or 320 MHz EHT BSS. ++ * @optional: optional parts ++ */ ++struct ieee80211_eht_operation_info { ++ u8 control; ++ u8 ccfs0; ++ u8 ccfs1; ++ u8 optional[]; ++} __packed; ++ ++/* EHT MAC capabilities as defined in P802.11be_D2.0 section 9.4.2.313.2 */ ++#define IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS 0x01 ++#define IEEE80211_EHT_MAC_CAP0_OM_CONTROL 0x02 ++#define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 0x04 ++#define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 0x08 ++#define IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT 0x10 ++#define IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC 0x20 ++#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK 0xc0 ++#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895 0 ++#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991 1 ++#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454 2 ++ ++#define IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK 0x01 ++#define IEEE80211_EHT_MAC_CAP1_EHT_TRS 0x02 ++#define IEEE80211_EHT_MAC_CAP1_TXOP_RET 0x04 ++#define IEEE80211_EHT_MAC_CAP1_TWO_BQRS 0x08 ++#define IEEE80211_EHT_MAC_CAP1_EHT_LINK_ADAPT_MASK 0x30 ++#define IEEE80211_EHT_MAC_CAP1_UNSOL_EPCS_PRIO_ACCESS 0x40 ++ ++/* EHT PHY capabilities as defined in P802.11be_D2.0 section 9.4.2.313.3 */ ++#define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ 0x02 ++#define IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ 0x04 ++#define IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI 0x08 ++#define IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO 0x10 ++#define IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER 0x20 ++#define IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE 0x40 ++ ++/* EHT beamformee number of spatial streams <= 80MHz is split */ ++#define IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK 0x80 ++#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK 0x03 ++ ++#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK 0x1c ++#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK 0xe0 ++ ++#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK 0x07 ++#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK 0x38 ++ ++/* EHT number of sounding dimensions for 320MHz is split */ ++#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK 0xc0 ++#define IEEE80211_EHT_PHY_CAP3_SOUNDING_DIM_320MHZ_MASK 0x01 ++#define IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK 0x02 ++#define IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK 0x04 ++#define IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK 0x08 ++#define IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK 0x10 ++#define IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK 0x20 ++#define IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK 0x40 ++#define IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK 0x80 ++ ++#define IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO 0x01 ++#define IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP 0x02 ++#define IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP 0x04 ++#define IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI 0x08 ++#define IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK 0xf0 ++ ++#define IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK 0x01 ++#define IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP 0x02 ++#define IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP 0x04 ++#define IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT 0x08 ++#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK 0x30 ++#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_0US 0 ++#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US 1 ++#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US 2 ++#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US 3 ++ ++/* Maximum number of supported EHT LTF is split */ ++#define IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK 0xc0 ++#define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x40 ++#define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x07 ++ ++#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x08 ++#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x30 ++#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ 0x40 ++#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x78 ++#define IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP 0x80 ++ ++#define IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW 0x01 ++#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ 0x02 ++#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ 0x04 ++#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ 0x08 ++#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ 0x10 ++#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ 0x20 ++#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ 0x40 ++#define IEEE80211_EHT_PHY_CAP7_TB_SOUNDING_FDBK_RATE_LIMIT 0x80 ++ ++#define IEEE80211_EHT_PHY_CAP8_RX_1024QAM_WIDER_BW_DL_OFDMA 0x01 ++#define IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA 0x02 ++ ++/* ++ * EHT operation channel width as defined in P802.11be_D2.0 section 9.4.2.311 ++ */ ++#define IEEE80211_EHT_OPER_CHAN_WIDTH 0x7 ++#define IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ 0 ++#define IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ 1 ++#define IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ 2 ++#define IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ 3 ++#define IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ 4 ++ ++/* Calculate 802.11be EHT capabilities IE Tx/Rx EHT MCS NSS Support Field size */ ++static inline u8 ++ieee80211_eht_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap, ++ const struct ieee80211_eht_cap_elem_fixed *eht_cap, ++ bool from_ap) ++{ ++ u8 count = 0; ++ ++ /* on 2.4 GHz, if it supports 40 MHz, the result is 3 */ ++ if (he_cap->phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) ++ return 3; ++ ++ /* on 2.4 GHz, these three bits are reserved, so should be 0 */ ++ if (he_cap->phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G) ++ count += 3; ++ ++ if (he_cap->phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) ++ count += 3; ++ ++ if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) ++ count += 3; ++ ++ if (count) ++ return count; ++ ++ return from_ap ? 3 : 4; ++} ++ ++/* 802.11be EHT PPE Thresholds */ ++#define IEEE80211_EHT_PPE_THRES_NSS_POS 0 ++#define IEEE80211_EHT_PPE_THRES_NSS_MASK 0xf ++#define IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK 0x1f0 ++#define IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE 3 ++#define IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE 9 ++ ++/* ++ * Calculate 802.11be EHT capabilities IE EHT field size ++ */ ++static inline u8 ++ieee80211_eht_ppe_size(u16 ppe_thres_hdr, const u8 *phy_cap_info) ++{ ++ u32 n; ++ ++ if (!(phy_cap_info[5] & ++ IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT)) ++ return 0; ++ ++ n = hweight16(ppe_thres_hdr & ++ IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); ++ n *= 1 + u16_get_bits(ppe_thres_hdr, IEEE80211_EHT_PPE_THRES_NSS_MASK); ++ ++ /* ++ * Each pair is 6 bits, and we need to add the 9 "header" bits to the ++ * total size. ++ */ ++ n = n * IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2 + ++ IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE; ++ return DIV_ROUND_UP(n, 8); ++} ++ ++static inline bool ++ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len, ++ bool from_ap) ++{ ++ const struct ieee80211_eht_cap_elem_fixed *elem = (const void *)data; ++ u8 needed = sizeof(struct ieee80211_eht_cap_elem_fixed); ++ ++ if (len < needed || !he_capa) ++ return false; ++ ++ needed += ieee80211_eht_mcs_nss_size((const void *)he_capa, ++ (const void *)data, ++ from_ap); ++ if (len < needed) ++ return false; ++ ++ if (elem->phy_cap_info[5] & ++ IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) { ++ u16 ppe_thres_hdr; ++ ++ if (len < needed + sizeof(ppe_thres_hdr)) ++ return false; ++ ++ ppe_thres_hdr = get_unaligned_le16(data + needed); ++ needed += ieee80211_eht_ppe_size(ppe_thres_hdr, ++ elem->phy_cap_info); ++ } ++ ++ return len >= needed; ++} ++ ++static inline bool ++ieee80211_eht_oper_size_ok(const u8 *data, u8 len) ++{ ++ const struct ieee80211_eht_operation *elem = (const void *)data; ++ u8 needed = sizeof(*elem); ++ ++ if (len < needed) ++ return false; ++ ++ if (elem->params & IEEE80211_EHT_OPER_INFO_PRESENT) { ++ needed += 3; ++ ++ if (elem->params & ++ IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT) ++ needed += 2; ++ } ++ ++ return len >= needed; ++} ++ ++/* must validate ieee80211_eht_oper_size_ok() first */ ++static inline u16 ++ieee80211_eht_oper_dis_subchan_bitmap(const struct ieee80211_eht_operation *eht_oper) ++{ ++ const struct ieee80211_eht_operation_info *info = ++ (const void *)eht_oper->optional; ++ ++ if (!(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) ++ return 0; ++ ++ if (!(eht_oper->params & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) ++ return 0; ++ ++ return get_unaligned_le16(info->optional); ++} ++ ++#define IEEE80211_BW_IND_DIS_SUBCH_PRESENT BIT(1) ++ ++struct ieee80211_bandwidth_indication { ++ u8 params; ++ struct ieee80211_eht_operation_info info; ++} __packed; ++ ++static inline bool ++ieee80211_bandwidth_indication_size_ok(const u8 *data, u8 len) ++{ ++ const struct ieee80211_bandwidth_indication *bwi = (const void *)data; ++ ++ if (len < sizeof(*bwi)) ++ return false; ++ ++ if (bwi->params & IEEE80211_BW_IND_DIS_SUBCH_PRESENT && ++ len < sizeof(*bwi) + 2) ++ return false; ++ ++ return true; ++} ++ ++/* Protected EHT action codes */ ++enum ieee80211_protected_eht_actioncode { ++ WLAN_PROTECTED_EHT_ACTION_TTLM_REQ = 0, ++ WLAN_PROTECTED_EHT_ACTION_TTLM_RES = 1, ++ WLAN_PROTECTED_EHT_ACTION_TTLM_TEARDOWN = 2, ++ WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_REQ = 3, ++ WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_RESP = 4, ++ WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_TEARDOWN = 5, ++ WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF = 6, ++ WLAN_PROTECTED_EHT_ACTION_LINK_RECOMMEND = 7, ++ WLAN_PROTECTED_EHT_ACTION_ML_OP_UPDATE_REQ = 8, ++ WLAN_PROTECTED_EHT_ACTION_ML_OP_UPDATE_RESP = 9, ++ WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_NOTIF = 10, ++ WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_REQ = 11, ++ WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_RESP = 12, ++}; ++ ++/* multi-link device */ ++#define IEEE80211_MLD_MAX_NUM_LINKS 15 ++ ++#define IEEE80211_ML_CONTROL_TYPE 0x0007 ++#define IEEE80211_ML_CONTROL_TYPE_BASIC 0 ++#define IEEE80211_ML_CONTROL_TYPE_PREQ 1 ++#define IEEE80211_ML_CONTROL_TYPE_RECONF 2 ++#define IEEE80211_ML_CONTROL_TYPE_TDLS 3 ++#define IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS 4 ++#define IEEE80211_ML_CONTROL_PRESENCE_MASK 0xfff0 ++ ++struct ieee80211_multi_link_elem { ++ __le16 control; ++ u8 variable[]; ++} __packed; ++ ++#define IEEE80211_MLC_BASIC_PRES_LINK_ID 0x0010 ++#define IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT 0x0020 ++#define IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY 0x0040 ++#define IEEE80211_MLC_BASIC_PRES_EML_CAPA 0x0080 ++#define IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP 0x0100 ++#define IEEE80211_MLC_BASIC_PRES_MLD_ID 0x0200 ++#define IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP 0x0400 ++ ++#define IEEE80211_MED_SYNC_DELAY_DURATION 0x00ff ++#define IEEE80211_MED_SYNC_DELAY_SYNC_OFDM_ED_THRESH 0x0f00 ++#define IEEE80211_MED_SYNC_DELAY_SYNC_MAX_NUM_TXOPS 0xf000 ++ ++/* ++ * Described in P802.11be_D3.0 ++ * dot11MSDTimerDuration should default to 5484 (i.e. 171.375) ++ * dot11MSDOFDMEDthreshold defaults to -72 (i.e. 0) ++ * dot11MSDTXOPMAX defaults to 1 ++ */ ++#define IEEE80211_MED_SYNC_DELAY_DEFAULT 0x10ac ++ ++#define IEEE80211_EML_CAP_EMLSR_SUPP 0x0001 ++#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY 0x000e ++#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_0US 0 ++#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US 1 ++#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_64US 2 ++#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_128US 3 ++#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US 4 ++#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY 0x0070 ++#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_0US 0 ++#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_16US 1 ++#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_32US 2 ++#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US 3 ++#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_128US 4 ++#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US 5 ++#define IEEE80211_EML_CAP_EMLMR_SUPPORT 0x0080 ++#define IEEE80211_EML_CAP_EMLMR_DELAY 0x0700 ++#define IEEE80211_EML_CAP_EMLMR_DELAY_0US 0 ++#define IEEE80211_EML_CAP_EMLMR_DELAY_32US 1 ++#define IEEE80211_EML_CAP_EMLMR_DELAY_64US 2 ++#define IEEE80211_EML_CAP_EMLMR_DELAY_128US 3 ++#define IEEE80211_EML_CAP_EMLMR_DELAY_256US 4 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT 0x7800 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_0 0 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128US 1 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_256US 2 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_512US 3 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_1TU 4 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_2TU 5 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_4TU 6 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_8TU 7 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_16TU 8 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_32TU 9 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_64TU 10 ++#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU 11 ++ ++#define IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS 0x000f ++#define IEEE80211_MLD_CAP_OP_SRS_SUPPORT 0x0010 ++#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP 0x0060 ++#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_NO_SUPP 0 ++#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME 1 ++#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_RESERVED 2 ++#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_DIFF 3 ++#define IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND 0x0f80 ++#define IEEE80211_MLD_CAP_OP_AAR_SUPPORT 0x1000 ++#define IEEE80211_MLD_CAP_OP_LINK_RECONF_SUPPORT 0x2000 ++#define IEEE80211_MLD_CAP_OP_ALIGNED_TWT_SUPPORT 0x4000 ++ ++struct ieee80211_mle_basic_common_info { ++ u8 len; ++ u8 mld_mac_addr[ETH_ALEN]; ++ u8 variable[]; ++} __packed; ++ ++#define IEEE80211_MLC_PREQ_PRES_MLD_ID 0x0010 ++ ++struct ieee80211_mle_preq_common_info { ++ u8 len; ++ u8 variable[]; ++} __packed; ++ ++#define IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR 0x0010 ++#define IEEE80211_MLC_RECONF_PRES_EML_CAPA 0x0020 ++#define IEEE80211_MLC_RECONF_PRES_MLD_CAPA_OP 0x0040 ++#define IEEE80211_MLC_RECONF_PRES_EXT_MLD_CAPA_OP 0x0080 ++ ++/* no fixed fields in RECONF */ ++ ++struct ieee80211_mle_tdls_common_info { ++ u8 len; ++ u8 ap_mld_mac_addr[ETH_ALEN]; ++} __packed; ++ ++#define IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR 0x0010 ++ ++/* no fixed fields in PRIO_ACCESS */ ++ ++/** ++ * ieee80211_mle_common_size - check multi-link element common size ++ * @data: multi-link element, must already be checked for size using ++ * ieee80211_mle_size_ok() ++ * Return: the size of the multi-link element's "common" subfield ++ */ ++static inline u8 ieee80211_mle_common_size(const u8 *data) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control = le16_to_cpu(mle->control); ++ ++ switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) { ++ case IEEE80211_ML_CONTROL_TYPE_BASIC: ++ case IEEE80211_ML_CONTROL_TYPE_PREQ: ++ case IEEE80211_ML_CONTROL_TYPE_TDLS: ++ case IEEE80211_ML_CONTROL_TYPE_RECONF: ++ case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS: ++ /* ++ * The length is the first octet pointed by mle->variable so no ++ * need to add anything ++ */ ++ break; ++ default: ++ WARN_ON(1); ++ return 0; ++ } ++ ++ return sizeof(*mle) + mle->variable[0]; ++} ++ ++/** ++ * ieee80211_mle_get_link_id - returns the link ID ++ * @data: the basic multi link element ++ * Return: the link ID, or -1 if not present ++ * ++ * The element is assumed to be of the correct type (BASIC) and big enough, ++ * this must be checked using ieee80211_mle_type_ok(). ++ */ ++static inline int ieee80211_mle_get_link_id(const u8 *data) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control = le16_to_cpu(mle->control); ++ const u8 *common = mle->variable; ++ ++ /* common points now at the beginning of ieee80211_mle_basic_common_info */ ++ common += sizeof(struct ieee80211_mle_basic_common_info); ++ ++ if (!(control & IEEE80211_MLC_BASIC_PRES_LINK_ID)) ++ return -1; ++ ++ return *common; ++} ++ ++/** ++ * ieee80211_mle_get_bss_param_ch_cnt - returns the BSS parameter change count ++ * @data: pointer to the basic multi link element ++ * Return: the BSS Parameter Change Count field value, or -1 if not present ++ * ++ * The element is assumed to be of the correct type (BASIC) and big enough, ++ * this must be checked using ieee80211_mle_type_ok(). ++ */ ++static inline int ++ieee80211_mle_get_bss_param_ch_cnt(const u8 *data) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control = le16_to_cpu(mle->control); ++ const u8 *common = mle->variable; ++ ++ /* common points now at the beginning of ieee80211_mle_basic_common_info */ ++ common += sizeof(struct ieee80211_mle_basic_common_info); ++ ++ if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)) ++ return -1; ++ ++ if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) ++ common += 1; ++ ++ return *common; ++} ++ ++/** ++ * ieee80211_mle_get_eml_med_sync_delay - returns the medium sync delay ++ * @data: pointer to the multi-link element ++ * Return: the medium synchronization delay field value from the multi-link ++ * element, or the default value (%IEEE80211_MED_SYNC_DELAY_DEFAULT) ++ * if not present ++ * ++ * The element is assumed to be of the correct type (BASIC) and big enough, ++ * this must be checked using ieee80211_mle_type_ok(). ++ */ ++static inline u16 ieee80211_mle_get_eml_med_sync_delay(const u8 *data) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control = le16_to_cpu(mle->control); ++ const u8 *common = mle->variable; ++ ++ /* common points now at the beginning of ieee80211_mle_basic_common_info */ ++ common += sizeof(struct ieee80211_mle_basic_common_info); ++ ++ if (!(control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) ++ return IEEE80211_MED_SYNC_DELAY_DEFAULT; ++ ++ if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) ++ common += 1; ++ ++ return get_unaligned_le16(common); ++} ++ ++/** ++ * ieee80211_mle_get_eml_cap - returns the EML capability ++ * @data: pointer to the multi-link element ++ * Return: the EML capability field value from the multi-link element, ++ * or 0 if not present ++ * ++ * The element is assumed to be of the correct type (BASIC) and big enough, ++ * this must be checked using ieee80211_mle_type_ok(). ++ */ ++static inline u16 ieee80211_mle_get_eml_cap(const u8 *data) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control = le16_to_cpu(mle->control); ++ const u8 *common = mle->variable; ++ ++ /* common points now at the beginning of ieee80211_mle_basic_common_info */ ++ common += sizeof(struct ieee80211_mle_basic_common_info); ++ ++ if (!(control & IEEE80211_MLC_BASIC_PRES_EML_CAPA)) ++ return 0; ++ ++ if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) ++ common += 2; ++ ++ return get_unaligned_le16(common); ++} ++ ++/** ++ * ieee80211_mle_get_mld_capa_op - returns the MLD capabilities and operations. ++ * @data: pointer to the multi-link element ++ * Return: the MLD capabilities and operations field value from the multi-link ++ * element, or 0 if not present ++ * ++ * The element is assumed to be of the correct type (BASIC) and big enough, ++ * this must be checked using ieee80211_mle_type_ok(). ++ */ ++static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control = le16_to_cpu(mle->control); ++ const u8 *common = mle->variable; ++ ++ /* ++ * common points now at the beginning of ++ * ieee80211_mle_basic_common_info ++ */ ++ common += sizeof(struct ieee80211_mle_basic_common_info); ++ ++ if (!(control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)) ++ return 0; ++ ++ if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) ++ common += 2; ++ ++ return get_unaligned_le16(common); ++} ++ ++/* Defined in Figure 9-1074t in P802.11be_D7.0 */ ++#define IEEE80211_EHT_ML_EXT_MLD_CAPA_OP_PARAM_UPDATE 0x0001 ++#define IEEE80211_EHT_ML_EXT_MLD_CAPA_OP_RECO_MAX_LINKS_MASK 0x001e ++#define IEEE80211_EHT_ML_EXT_MLD_CAPA_NSTR_UPDATE 0x0020 ++#define IEEE80211_EHT_ML_EXT_MLD_CAPA_EMLSR_ENA_ON_ONE_LINK 0x0040 ++#define IEEE80211_EHT_ML_EXT_MLD_CAPA_BTM_MLD_RECO_MULTI_AP 0x0080 ++ ++/** ++ * ieee80211_mle_get_ext_mld_capa_op - returns the extended MLD capabilities ++ * and operations. ++ * @data: pointer to the multi-link element ++ * Return: the extended MLD capabilities and operations field value from ++ * the multi-link element, or 0 if not present ++ * ++ * The element is assumed to be of the correct type (BASIC) and big enough, ++ * this must be checked using ieee80211_mle_type_ok(). ++ */ ++static inline u16 ieee80211_mle_get_ext_mld_capa_op(const u8 *data) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control = le16_to_cpu(mle->control); ++ const u8 *common = mle->variable; ++ ++ /* ++ * common points now at the beginning of ++ * ieee80211_mle_basic_common_info ++ */ ++ common += sizeof(struct ieee80211_mle_basic_common_info); ++ ++ if (!(control & IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP)) ++ return 0; ++ ++ if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID) ++ common += 1; ++ ++ return get_unaligned_le16(common); ++} ++ ++/** ++ * ieee80211_mle_get_mld_id - returns the MLD ID ++ * @data: pointer to the multi-link element ++ * Return: The MLD ID in the given multi-link element, or 0 if not present ++ * ++ * The element is assumed to be of the correct type (BASIC) and big enough, ++ * this must be checked using ieee80211_mle_type_ok(). ++ */ ++static inline u8 ieee80211_mle_get_mld_id(const u8 *data) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control = le16_to_cpu(mle->control); ++ const u8 *common = mle->variable; ++ ++ /* ++ * common points now at the beginning of ++ * ieee80211_mle_basic_common_info ++ */ ++ common += sizeof(struct ieee80211_mle_basic_common_info); ++ ++ if (!(control & IEEE80211_MLC_BASIC_PRES_MLD_ID)) ++ return 0; ++ ++ if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) ++ common += 2; ++ ++ return *common; ++} ++ ++/** ++ * ieee80211_mle_size_ok - validate multi-link element size ++ * @data: pointer to the element data ++ * @len: length of the containing element ++ * Return: whether or not the multi-link element size is OK ++ */ ++static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u8 fixed = sizeof(*mle); ++ u8 common = 0; ++ bool check_common_len = false; ++ u16 control; ++ ++ if (!data || len < fixed) ++ return false; ++ ++ control = le16_to_cpu(mle->control); ++ ++ switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) { ++ case IEEE80211_ML_CONTROL_TYPE_BASIC: ++ common += sizeof(struct ieee80211_mle_basic_common_info); ++ check_common_len = true; ++ if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) ++ common += 2; ++ if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID) ++ common += 1; ++ if (control & IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP) ++ common += 2; ++ break; ++ case IEEE80211_ML_CONTROL_TYPE_PREQ: ++ common += sizeof(struct ieee80211_mle_preq_common_info); ++ if (control & IEEE80211_MLC_PREQ_PRES_MLD_ID) ++ common += 1; ++ check_common_len = true; ++ break; ++ case IEEE80211_ML_CONTROL_TYPE_RECONF: ++ if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR) ++ common += ETH_ALEN; ++ if (control & IEEE80211_MLC_RECONF_PRES_EML_CAPA) ++ common += 2; ++ if (control & IEEE80211_MLC_RECONF_PRES_MLD_CAPA_OP) ++ common += 2; ++ if (control & IEEE80211_MLC_RECONF_PRES_EXT_MLD_CAPA_OP) ++ common += 2; ++ break; ++ case IEEE80211_ML_CONTROL_TYPE_TDLS: ++ common += sizeof(struct ieee80211_mle_tdls_common_info); ++ check_common_len = true; ++ break; ++ case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS: ++ common = ETH_ALEN + 1; ++ break; ++ default: ++ /* we don't know this type */ ++ return true; ++ } ++ ++ if (len < fixed + common) ++ return false; ++ ++ if (!check_common_len) ++ return true; ++ ++ /* if present, common length is the first octet there */ ++ return mle->variable[0] >= common; ++} ++ ++/** ++ * ieee80211_mle_type_ok - validate multi-link element type and size ++ * @data: pointer to the element data ++ * @type: expected type of the element ++ * @len: length of the containing element ++ * Return: whether or not the multi-link element type matches and size is OK ++ */ ++static inline bool ieee80211_mle_type_ok(const u8 *data, u8 type, size_t len) ++{ ++ const struct ieee80211_multi_link_elem *mle = (const void *)data; ++ u16 control; ++ ++ if (!ieee80211_mle_size_ok(data, len)) ++ return false; ++ ++ control = le16_to_cpu(mle->control); ++ ++ if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) == type) ++ return true; ++ ++ return false; ++} ++ ++enum ieee80211_mle_subelems { ++ IEEE80211_MLE_SUBELEM_PER_STA_PROFILE = 0, ++ IEEE80211_MLE_SUBELEM_FRAGMENT = 254, ++}; ++ ++#define IEEE80211_MLE_STA_CONTROL_LINK_ID 0x000f ++#define IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE 0x0010 ++#define IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT 0x0020 ++#define IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT 0x0040 ++#define IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT 0x0080 ++#define IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT 0x0100 ++#define IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT 0x0200 ++#define IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE 0x0400 ++#define IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT 0x0800 ++ ++struct ieee80211_mle_per_sta_profile { ++ __le16 control; ++ u8 sta_info_len; ++ u8 variable[]; ++} __packed; ++ ++/** ++ * ieee80211_mle_basic_sta_prof_size_ok - validate basic multi-link element sta ++ * profile size ++ * @data: pointer to the sub element data ++ * @len: length of the containing sub element ++ * Return: %true if the STA profile is large enough, %false otherwise ++ */ ++static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, ++ size_t len) ++{ ++ const struct ieee80211_mle_per_sta_profile *prof = (const void *)data; ++ u16 control; ++ u8 fixed = sizeof(*prof); ++ u8 info_len = 1; ++ ++ if (len < fixed) ++ return false; ++ ++ control = le16_to_cpu(prof->control); ++ ++ if (control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT) ++ info_len += 6; ++ if (control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT) ++ info_len += 2; ++ if (control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT) ++ info_len += 8; ++ if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT) ++ info_len += 2; ++ if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE && ++ control & IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT) { ++ if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) ++ info_len += 2; ++ else ++ info_len += 1; ++ } ++ if (control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT) ++ info_len += 1; ++ ++ return prof->sta_info_len >= info_len && ++ fixed + prof->sta_info_len - 1 <= len; ++} ++ ++/** ++ * ieee80211_mle_basic_sta_prof_bss_param_ch_cnt - get per-STA profile BSS ++ * parameter change count ++ * @prof: the per-STA profile, having been checked with ++ * ieee80211_mle_basic_sta_prof_size_ok() for the correct length ++ * ++ * Return: The BSS parameter change count value if present, 0 otherwise. ++ */ ++static inline u8 ++ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(const struct ieee80211_mle_per_sta_profile *prof) ++{ ++ u16 control = le16_to_cpu(prof->control); ++ const u8 *pos = prof->variable; ++ ++ if (!(control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT)) ++ return 0; ++ ++ if (control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT) ++ pos += 6; ++ if (control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT) ++ pos += 2; ++ if (control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT) ++ pos += 8; ++ if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT) ++ pos += 2; ++ if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE && ++ control & IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT) { ++ if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) ++ pos += 2; ++ else ++ pos += 1; ++ } ++ ++ return *pos; ++} ++ ++#define IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID 0x000f ++#define IEEE80211_MLE_STA_RECONF_CONTROL_COMPLETE_PROFILE 0x0010 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT 0x0020 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_AP_REM_TIMER_PRESENT 0x0040 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE 0x0780 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_AP_REM 0 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_OP_PARAM_UPDATE 1 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_ADD_LINK 2 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_DEL_LINK 3 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_NSTR_STATUS 4 ++#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_PARAMS_PRESENT 0x0800 ++ ++/** ++ * ieee80211_mle_reconf_sta_prof_size_ok - validate reconfiguration multi-link ++ * element sta profile size. ++ * @data: pointer to the sub element data ++ * @len: length of the containing sub element ++ * Return: %true if the STA profile is large enough, %false otherwise ++ */ ++static inline bool ieee80211_mle_reconf_sta_prof_size_ok(const u8 *data, ++ size_t len) ++{ ++ const struct ieee80211_mle_per_sta_profile *prof = (const void *)data; ++ u16 control; ++ u8 fixed = sizeof(*prof); ++ u8 info_len = 1; ++ ++ if (len < fixed) ++ return false; ++ ++ control = le16_to_cpu(prof->control); ++ ++ if (control & IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT) ++ info_len += ETH_ALEN; ++ if (control & IEEE80211_MLE_STA_RECONF_CONTROL_AP_REM_TIMER_PRESENT) ++ info_len += 2; ++ if (control & IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_PARAMS_PRESENT) ++ info_len += 2; ++ ++ return prof->sta_info_len >= info_len && ++ fixed + prof->sta_info_len - 1 <= len; ++} ++ ++#define IEEE80211_MLE_STA_EPCS_CONTROL_LINK_ID 0x000f ++#define IEEE80211_EPCS_ENA_RESP_BODY_LEN 3 ++ ++static inline bool ieee80211_tid_to_link_map_size_ok(const u8 *data, size_t len) ++{ ++ const struct ieee80211_ttlm_elem *t2l = (const void *)data; ++ u8 control, fixed = sizeof(*t2l), elem_len = 0; ++ ++ if (len < fixed) ++ return false; ++ ++ control = t2l->control; ++ ++ if (control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT) ++ elem_len += 2; ++ if (control & IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT) ++ elem_len += 3; ++ ++ if (!(control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP)) { ++ u8 bm_size; ++ ++ elem_len += 1; ++ if (len < fixed + elem_len) ++ return false; ++ ++ if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE) ++ bm_size = 1; ++ else ++ bm_size = 2; ++ ++ elem_len += hweight8(t2l->optional[0]) * bm_size; ++ } ++ ++ return len >= fixed + elem_len; ++} ++ ++/** ++ * ieee80211_emlsr_pad_delay_in_us - Fetch the EMLSR Padding delay ++ * in microseconds ++ * @eml_cap: EML capabilities field value from common info field of ++ * the Multi-link element ++ * Return: the EMLSR Padding delay (in microseconds) encoded in the ++ * EML Capabilities field ++ */ ++ ++static inline u32 ieee80211_emlsr_pad_delay_in_us(u16 eml_cap) ++{ ++ /* IEEE Std 802.11be-2024 Table 9-417i—Encoding of the EMLSR ++ * Padding Delay subfield. ++ */ ++ u32 pad_delay = u16_get_bits(eml_cap, ++ IEEE80211_EML_CAP_EMLSR_PADDING_DELAY); ++ ++ if (!pad_delay || ++ pad_delay > IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US) ++ return 0; ++ ++ return 32 * (1 << (pad_delay - 1)); ++} ++ ++/** ++ * ieee80211_emlsr_trans_delay_in_us - Fetch the EMLSR Transition ++ * delay in microseconds ++ * @eml_cap: EML capabilities field value from common info field of ++ * the Multi-link element ++ * Return: the EMLSR Transition delay (in microseconds) encoded in the ++ * EML Capabilities field ++ */ ++ ++static inline u32 ieee80211_emlsr_trans_delay_in_us(u16 eml_cap) ++{ ++ /* IEEE Std 802.11be-2024 Table 9-417j—Encoding of the EMLSR ++ * Transition Delay subfield. ++ */ ++ u32 trans_delay = ++ u16_get_bits(eml_cap, ++ IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY); ++ ++ /* invalid values also just use 0 */ ++ if (!trans_delay || ++ trans_delay > IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US) ++ return 0; ++ ++ return 16 * (1 << (trans_delay - 1)); ++} ++ ++/** ++ * ieee80211_eml_trans_timeout_in_us - Fetch the EMLSR Transition ++ * timeout value in microseconds ++ * @eml_cap: EML capabilities field value from common info field of ++ * the Multi-link element ++ * Return: the EMLSR Transition timeout (in microseconds) encoded in ++ * the EML Capabilities field ++ */ ++ ++static inline u32 ieee80211_eml_trans_timeout_in_us(u16 eml_cap) ++{ ++ /* IEEE Std 802.11be-2024 Table 9-417m—Encoding of the ++ * Transition Timeout subfield. ++ */ ++ u8 timeout = u16_get_bits(eml_cap, ++ IEEE80211_EML_CAP_TRANSITION_TIMEOUT); ++ ++ /* invalid values also just use 0 */ ++ if (!timeout || timeout > IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU) ++ return 0; ++ ++ return 128 * (1 << (timeout - 1)); ++} ++ ++#define for_each_mle_subelement(_elem, _data, _len) \ ++ if (ieee80211_mle_size_ok(_data, _len)) \ ++ for_each_element(_elem, \ ++ _data + ieee80211_mle_common_size(_data),\ ++ _len - ieee80211_mle_common_size(_data)) ++ ++#endif /* LINUX_IEEE80211_H */ +diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h +index 2f3d0412ca759..992a0c09c1e53 100644 +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -1141,30 +1141,6 @@ ieee80211_s1g_optional_len(__le16 fc) + return len; + } + +-#define IEEE80211_TTLM_MAX_CNT 2 +-#define IEEE80211_TTLM_CONTROL_DIRECTION 0x03 +-#define IEEE80211_TTLM_CONTROL_DEF_LINK_MAP 0x04 +-#define IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT 0x08 +-#define IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT 0x10 +-#define IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE 0x20 +- +-#define IEEE80211_TTLM_DIRECTION_DOWN 0 +-#define IEEE80211_TTLM_DIRECTION_UP 1 +-#define IEEE80211_TTLM_DIRECTION_BOTH 2 +- +-/** +- * struct ieee80211_ttlm_elem - TID-To-Link Mapping element +- * +- * Defined in section 9.4.2.314 in P802.11be_D4 +- * +- * @control: the first part of control field +- * @optional: the second part of control field +- */ +-struct ieee80211_ttlm_elem { +- u8 control; +- u8 optional[]; +-} __packed; +- + /** + * struct ieee80211_bss_load_elem - BSS Load elemen + * +@@ -1591,144 +1567,6 @@ struct ieee80211_p2p_noa_attr { + #define IEEE80211_P2P_OPPPS_ENABLE_BIT BIT(7) + #define IEEE80211_P2P_OPPPS_CTWINDOW_MASK 0x7F + +-#define IEEE80211_EHT_MCS_NSS_RX 0x0f +-#define IEEE80211_EHT_MCS_NSS_TX 0xf0 +- +-/** +- * struct ieee80211_eht_mcs_nss_supp_20mhz_only - EHT 20MHz only station max +- * supported NSS for per MCS. +- * +- * For each field below, bits 0 - 3 indicate the maximal number of spatial +- * streams for Rx, and bits 4 - 7 indicate the maximal number of spatial streams +- * for Tx. +- * +- * @rx_tx_mcs7_max_nss: indicates the maximum number of spatial streams +- * supported for reception and the maximum number of spatial streams +- * supported for transmission for MCS 0 - 7. +- * @rx_tx_mcs9_max_nss: indicates the maximum number of spatial streams +- * supported for reception and the maximum number of spatial streams +- * supported for transmission for MCS 8 - 9. +- * @rx_tx_mcs11_max_nss: indicates the maximum number of spatial streams +- * supported for reception and the maximum number of spatial streams +- * supported for transmission for MCS 10 - 11. +- * @rx_tx_mcs13_max_nss: indicates the maximum number of spatial streams +- * supported for reception and the maximum number of spatial streams +- * supported for transmission for MCS 12 - 13. +- * @rx_tx_max_nss: array of the previous fields for easier loop access +- */ +-struct ieee80211_eht_mcs_nss_supp_20mhz_only { +- union { +- struct { +- u8 rx_tx_mcs7_max_nss; +- u8 rx_tx_mcs9_max_nss; +- u8 rx_tx_mcs11_max_nss; +- u8 rx_tx_mcs13_max_nss; +- }; +- u8 rx_tx_max_nss[4]; +- }; +-}; +- +-/** +- * struct ieee80211_eht_mcs_nss_supp_bw - EHT max supported NSS per MCS (except +- * 20MHz only stations). +- * +- * For each field below, bits 0 - 3 indicate the maximal number of spatial +- * streams for Rx, and bits 4 - 7 indicate the maximal number of spatial streams +- * for Tx. +- * +- * @rx_tx_mcs9_max_nss: indicates the maximum number of spatial streams +- * supported for reception and the maximum number of spatial streams +- * supported for transmission for MCS 0 - 9. +- * @rx_tx_mcs11_max_nss: indicates the maximum number of spatial streams +- * supported for reception and the maximum number of spatial streams +- * supported for transmission for MCS 10 - 11. +- * @rx_tx_mcs13_max_nss: indicates the maximum number of spatial streams +- * supported for reception and the maximum number of spatial streams +- * supported for transmission for MCS 12 - 13. +- * @rx_tx_max_nss: array of the previous fields for easier loop access +- */ +-struct ieee80211_eht_mcs_nss_supp_bw { +- union { +- struct { +- u8 rx_tx_mcs9_max_nss; +- u8 rx_tx_mcs11_max_nss; +- u8 rx_tx_mcs13_max_nss; +- }; +- u8 rx_tx_max_nss[3]; +- }; +-}; +- +-/** +- * struct ieee80211_eht_cap_elem_fixed - EHT capabilities fixed data +- * +- * This structure is the "EHT Capabilities element" fixed fields as +- * described in P802.11be_D2.0 section 9.4.2.313. +- * +- * @mac_cap_info: MAC capabilities, see IEEE80211_EHT_MAC_CAP* +- * @phy_cap_info: PHY capabilities, see IEEE80211_EHT_PHY_CAP* +- */ +-struct ieee80211_eht_cap_elem_fixed { +- u8 mac_cap_info[2]; +- u8 phy_cap_info[9]; +-} __packed; +- +-/** +- * struct ieee80211_eht_cap_elem - EHT capabilities element +- * @fixed: fixed parts, see &ieee80211_eht_cap_elem_fixed +- * @optional: optional parts +- */ +-struct ieee80211_eht_cap_elem { +- struct ieee80211_eht_cap_elem_fixed fixed; +- +- /* +- * Followed by: +- * Supported EHT-MCS And NSS Set field: 4, 3, 6 or 9 octets. +- * EHT PPE Thresholds field: variable length. +- */ +- u8 optional[]; +-} __packed; +- +-#define IEEE80211_EHT_OPER_INFO_PRESENT 0x01 +-#define IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT 0x02 +-#define IEEE80211_EHT_OPER_EHT_DEF_PE_DURATION 0x04 +-#define IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_LIMIT 0x08 +-#define IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_EXP_MASK 0x30 +-#define IEEE80211_EHT_OPER_MCS15_DISABLE 0x40 +- +-/** +- * struct ieee80211_eht_operation - eht operation element +- * +- * This structure is the "EHT Operation Element" fields as +- * described in P802.11be_D2.0 section 9.4.2.311 +- * +- * @params: EHT operation element parameters. See &IEEE80211_EHT_OPER_* +- * @basic_mcs_nss: indicates the EHT-MCSs for each number of spatial streams in +- * EHT PPDUs that are supported by all EHT STAs in the BSS in transmit and +- * receive. +- * @optional: optional parts +- */ +-struct ieee80211_eht_operation { +- u8 params; +- struct ieee80211_eht_mcs_nss_supp_20mhz_only basic_mcs_nss; +- u8 optional[]; +-} __packed; +- +-/** +- * struct ieee80211_eht_operation_info - eht operation information +- * +- * @control: EHT operation information control. +- * @ccfs0: defines a channel center frequency for a 20, 40, 80, 160, or 320 MHz +- * EHT BSS. +- * @ccfs1: defines a channel center frequency for a 160 or 320 MHz EHT BSS. +- * @optional: optional parts +- */ +-struct ieee80211_eht_operation_info { +- u8 control; +- u8 ccfs0; +- u8 ccfs1; +- u8 optional[]; +-} __packed; +- + /* S1G Capabilities Information field */ + #define IEEE80211_S1G_CAPABILITY_LEN 15 + +@@ -1815,258 +1653,6 @@ struct ieee80211_eht_operation_info { + #define S1G_2M_PRIMARY_LOCATION_LOWER 0 + #define S1G_2M_PRIMARY_LOCATION_UPPER 1 + +-/* EHT MAC capabilities as defined in P802.11be_D2.0 section 9.4.2.313.2 */ +-#define IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS 0x01 +-#define IEEE80211_EHT_MAC_CAP0_OM_CONTROL 0x02 +-#define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 0x04 +-#define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 0x08 +-#define IEEE80211_EHT_MAC_CAP0_RESTRICTED_TWT 0x10 +-#define IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC 0x20 +-#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK 0xc0 +-#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895 0 +-#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991 1 +-#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454 2 +- +-#define IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK 0x01 +-#define IEEE80211_EHT_MAC_CAP1_EHT_TRS 0x02 +-#define IEEE80211_EHT_MAC_CAP1_TXOP_RET 0x04 +-#define IEEE80211_EHT_MAC_CAP1_TWO_BQRS 0x08 +-#define IEEE80211_EHT_MAC_CAP1_EHT_LINK_ADAPT_MASK 0x30 +-#define IEEE80211_EHT_MAC_CAP1_UNSOL_EPCS_PRIO_ACCESS 0x40 +- +-/* EHT PHY capabilities as defined in P802.11be_D2.0 section 9.4.2.313.3 */ +-#define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ 0x02 +-#define IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ 0x04 +-#define IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI 0x08 +-#define IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO 0x10 +-#define IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER 0x20 +-#define IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE 0x40 +- +-/* EHT beamformee number of spatial streams <= 80MHz is split */ +-#define IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK 0x80 +-#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK 0x03 +- +-#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK 0x1c +-#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK 0xe0 +- +-#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK 0x07 +-#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK 0x38 +- +-/* EHT number of sounding dimensions for 320MHz is split */ +-#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK 0xc0 +-#define IEEE80211_EHT_PHY_CAP3_SOUNDING_DIM_320MHZ_MASK 0x01 +-#define IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK 0x02 +-#define IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK 0x04 +-#define IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK 0x08 +-#define IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK 0x10 +-#define IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK 0x20 +-#define IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK 0x40 +-#define IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK 0x80 +- +-#define IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO 0x01 +-#define IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP 0x02 +-#define IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP 0x04 +-#define IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI 0x08 +-#define IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK 0xf0 +- +-#define IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK 0x01 +-#define IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP 0x02 +-#define IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP 0x04 +-#define IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT 0x08 +-#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK 0x30 +-#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_0US 0 +-#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US 1 +-#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US 2 +-#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US 3 +- +-/* Maximum number of supported EHT LTF is split */ +-#define IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK 0xc0 +-#define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x40 +-#define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x07 +- +-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x08 +-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x30 +-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ 0x40 +-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x78 +-#define IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP 0x80 +- +-#define IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW 0x01 +-#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ 0x02 +-#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ 0x04 +-#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ 0x08 +-#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ 0x10 +-#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ 0x20 +-#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ 0x40 +-#define IEEE80211_EHT_PHY_CAP7_TB_SOUNDING_FDBK_RATE_LIMIT 0x80 +- +-#define IEEE80211_EHT_PHY_CAP8_RX_1024QAM_WIDER_BW_DL_OFDMA 0x01 +-#define IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA 0x02 +- +-/* +- * EHT operation channel width as defined in P802.11be_D2.0 section 9.4.2.311 +- */ +-#define IEEE80211_EHT_OPER_CHAN_WIDTH 0x7 +-#define IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ 0 +-#define IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ 1 +-#define IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ 2 +-#define IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ 3 +-#define IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ 4 +- +-/* need HE definitions for EHT functions */ +-#include "ieee80211-he.h" +- +-/* Calculate 802.11be EHT capabilities IE Tx/Rx EHT MCS NSS Support Field size */ +-static inline u8 +-ieee80211_eht_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap, +- const struct ieee80211_eht_cap_elem_fixed *eht_cap, +- bool from_ap) +-{ +- u8 count = 0; +- +- /* on 2.4 GHz, if it supports 40 MHz, the result is 3 */ +- if (he_cap->phy_cap_info[0] & +- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) +- return 3; +- +- /* on 2.4 GHz, these three bits are reserved, so should be 0 */ +- if (he_cap->phy_cap_info[0] & +- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G) +- count += 3; +- +- if (he_cap->phy_cap_info[0] & +- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) +- count += 3; +- +- if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) +- count += 3; +- +- if (count) +- return count; +- +- return from_ap ? 3 : 4; +-} +- +-/* 802.11be EHT PPE Thresholds */ +-#define IEEE80211_EHT_PPE_THRES_NSS_POS 0 +-#define IEEE80211_EHT_PPE_THRES_NSS_MASK 0xf +-#define IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK 0x1f0 +-#define IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE 3 +-#define IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE 9 +- +-/* +- * Calculate 802.11be EHT capabilities IE EHT field size +- */ +-static inline u8 +-ieee80211_eht_ppe_size(u16 ppe_thres_hdr, const u8 *phy_cap_info) +-{ +- u32 n; +- +- if (!(phy_cap_info[5] & +- IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT)) +- return 0; +- +- n = hweight16(ppe_thres_hdr & +- IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); +- n *= 1 + u16_get_bits(ppe_thres_hdr, IEEE80211_EHT_PPE_THRES_NSS_MASK); +- +- /* +- * Each pair is 6 bits, and we need to add the 9 "header" bits to the +- * total size. +- */ +- n = n * IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2 + +- IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE; +- return DIV_ROUND_UP(n, 8); +-} +- +-static inline bool +-ieee80211_eht_capa_size_ok(const u8 *he_capa, const u8 *data, u8 len, +- bool from_ap) +-{ +- const struct ieee80211_eht_cap_elem_fixed *elem = (const void *)data; +- u8 needed = sizeof(struct ieee80211_eht_cap_elem_fixed); +- +- if (len < needed || !he_capa) +- return false; +- +- needed += ieee80211_eht_mcs_nss_size((const void *)he_capa, +- (const void *)data, +- from_ap); +- if (len < needed) +- return false; +- +- if (elem->phy_cap_info[5] & +- IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) { +- u16 ppe_thres_hdr; +- +- if (len < needed + sizeof(ppe_thres_hdr)) +- return false; +- +- ppe_thres_hdr = get_unaligned_le16(data + needed); +- needed += ieee80211_eht_ppe_size(ppe_thres_hdr, +- elem->phy_cap_info); +- } +- +- return len >= needed; +-} +- +-static inline bool +-ieee80211_eht_oper_size_ok(const u8 *data, u8 len) +-{ +- const struct ieee80211_eht_operation *elem = (const void *)data; +- u8 needed = sizeof(*elem); +- +- if (len < needed) +- return false; +- +- if (elem->params & IEEE80211_EHT_OPER_INFO_PRESENT) { +- needed += 3; +- +- if (elem->params & +- IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT) +- needed += 2; +- } +- +- return len >= needed; +-} +- +-/* must validate ieee80211_eht_oper_size_ok() first */ +-static inline u16 +-ieee80211_eht_oper_dis_subchan_bitmap(const struct ieee80211_eht_operation *eht_oper) +-{ +- const struct ieee80211_eht_operation_info *info = +- (const void *)eht_oper->optional; +- +- if (!(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) +- return 0; +- +- if (!(eht_oper->params & IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) +- return 0; +- +- return get_unaligned_le16(info->optional); +-} +- +-#define IEEE80211_BW_IND_DIS_SUBCH_PRESENT BIT(1) +- +-struct ieee80211_bandwidth_indication { +- u8 params; +- struct ieee80211_eht_operation_info info; +-} __packed; +- +-static inline bool +-ieee80211_bandwidth_indication_size_ok(const u8 *data, u8 len) +-{ +- const struct ieee80211_bandwidth_indication *bwi = (const void *)data; +- +- if (len < sizeof(*bwi)) +- return false; +- +- if (bwi->params & IEEE80211_BW_IND_DIS_SUBCH_PRESENT && +- len < sizeof(*bwi) + 2) +- return false; +- +- return true; +-} +- + #define LISTEN_INT_USF GENMASK(15, 14) + #define LISTEN_INT_UI GENMASK(13, 0) + +@@ -2587,23 +2173,6 @@ enum ieee80211_unprotected_wnm_actioncode { + WLAN_UNPROTECTED_WNM_ACTION_TIMING_MEASUREMENT_RESPONSE = 1, + }; + +-/* Protected EHT action codes */ +-enum ieee80211_protected_eht_actioncode { +- WLAN_PROTECTED_EHT_ACTION_TTLM_REQ = 0, +- WLAN_PROTECTED_EHT_ACTION_TTLM_RES = 1, +- WLAN_PROTECTED_EHT_ACTION_TTLM_TEARDOWN = 2, +- WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_REQ = 3, +- WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_RESP = 4, +- WLAN_PROTECTED_EHT_ACTION_EPCS_ENABLE_TEARDOWN = 5, +- WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF = 6, +- WLAN_PROTECTED_EHT_ACTION_LINK_RECOMMEND = 7, +- WLAN_PROTECTED_EHT_ACTION_ML_OP_UPDATE_REQ = 8, +- WLAN_PROTECTED_EHT_ACTION_ML_OP_UPDATE_RESP = 9, +- WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_NOTIF = 10, +- WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_REQ = 11, +- WLAN_PROTECTED_EHT_ACTION_LINK_RECONFIG_RESP = 12, +-}; +- + /* Security key length */ + enum ieee80211_key_len { + WLAN_KEY_LEN_WEP40 = 5, +@@ -3855,737 +3424,6 @@ struct ieee80211_tbtt_info_ge_11 { + struct ieee80211_rnr_mld_params mld_params; + } __packed; + +-/* multi-link device */ +-#define IEEE80211_MLD_MAX_NUM_LINKS 15 +- +-#define IEEE80211_ML_CONTROL_TYPE 0x0007 +-#define IEEE80211_ML_CONTROL_TYPE_BASIC 0 +-#define IEEE80211_ML_CONTROL_TYPE_PREQ 1 +-#define IEEE80211_ML_CONTROL_TYPE_RECONF 2 +-#define IEEE80211_ML_CONTROL_TYPE_TDLS 3 +-#define IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS 4 +-#define IEEE80211_ML_CONTROL_PRESENCE_MASK 0xfff0 +- +-struct ieee80211_multi_link_elem { +- __le16 control; +- u8 variable[]; +-} __packed; +- +-#define IEEE80211_MLC_BASIC_PRES_LINK_ID 0x0010 +-#define IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT 0x0020 +-#define IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY 0x0040 +-#define IEEE80211_MLC_BASIC_PRES_EML_CAPA 0x0080 +-#define IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP 0x0100 +-#define IEEE80211_MLC_BASIC_PRES_MLD_ID 0x0200 +-#define IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP 0x0400 +- +-#define IEEE80211_MED_SYNC_DELAY_DURATION 0x00ff +-#define IEEE80211_MED_SYNC_DELAY_SYNC_OFDM_ED_THRESH 0x0f00 +-#define IEEE80211_MED_SYNC_DELAY_SYNC_MAX_NUM_TXOPS 0xf000 +- +-/* +- * Described in P802.11be_D3.0 +- * dot11MSDTimerDuration should default to 5484 (i.e. 171.375) +- * dot11MSDOFDMEDthreshold defaults to -72 (i.e. 0) +- * dot11MSDTXOPMAX defaults to 1 +- */ +-#define IEEE80211_MED_SYNC_DELAY_DEFAULT 0x10ac +- +-#define IEEE80211_EML_CAP_EMLSR_SUPP 0x0001 +-#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY 0x000e +-#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_0US 0 +-#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US 1 +-#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_64US 2 +-#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_128US 3 +-#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US 4 +-#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY 0x0070 +-#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_0US 0 +-#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_16US 1 +-#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_32US 2 +-#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US 3 +-#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_128US 4 +-#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US 5 +-#define IEEE80211_EML_CAP_EMLMR_SUPPORT 0x0080 +-#define IEEE80211_EML_CAP_EMLMR_DELAY 0x0700 +-#define IEEE80211_EML_CAP_EMLMR_DELAY_0US 0 +-#define IEEE80211_EML_CAP_EMLMR_DELAY_32US 1 +-#define IEEE80211_EML_CAP_EMLMR_DELAY_64US 2 +-#define IEEE80211_EML_CAP_EMLMR_DELAY_128US 3 +-#define IEEE80211_EML_CAP_EMLMR_DELAY_256US 4 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT 0x7800 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_0 0 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128US 1 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_256US 2 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_512US 3 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_1TU 4 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_2TU 5 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_4TU 6 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_8TU 7 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_16TU 8 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_32TU 9 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_64TU 10 +-#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU 11 +- +-#define IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS 0x000f +-#define IEEE80211_MLD_CAP_OP_SRS_SUPPORT 0x0010 +-#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP 0x0060 +-#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_NO_SUPP 0 +-#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME 1 +-#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_RESERVED 2 +-#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_DIFF 3 +-#define IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND 0x0f80 +-#define IEEE80211_MLD_CAP_OP_AAR_SUPPORT 0x1000 +-#define IEEE80211_MLD_CAP_OP_LINK_RECONF_SUPPORT 0x2000 +-#define IEEE80211_MLD_CAP_OP_ALIGNED_TWT_SUPPORT 0x4000 +- +-struct ieee80211_mle_basic_common_info { +- u8 len; +- u8 mld_mac_addr[ETH_ALEN]; +- u8 variable[]; +-} __packed; +- +-#define IEEE80211_MLC_PREQ_PRES_MLD_ID 0x0010 +- +-struct ieee80211_mle_preq_common_info { +- u8 len; +- u8 variable[]; +-} __packed; +- +-#define IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR 0x0010 +-#define IEEE80211_MLC_RECONF_PRES_EML_CAPA 0x0020 +-#define IEEE80211_MLC_RECONF_PRES_MLD_CAPA_OP 0x0040 +-#define IEEE80211_MLC_RECONF_PRES_EXT_MLD_CAPA_OP 0x0080 +- +-/* no fixed fields in RECONF */ +- +-struct ieee80211_mle_tdls_common_info { +- u8 len; +- u8 ap_mld_mac_addr[ETH_ALEN]; +-} __packed; +- +-#define IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR 0x0010 +- +-/* no fixed fields in PRIO_ACCESS */ +- +-/** +- * ieee80211_mle_common_size - check multi-link element common size +- * @data: multi-link element, must already be checked for size using +- * ieee80211_mle_size_ok() +- * Return: the size of the multi-link element's "common" subfield +- */ +-static inline u8 ieee80211_mle_common_size(const u8 *data) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control = le16_to_cpu(mle->control); +- +- switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) { +- case IEEE80211_ML_CONTROL_TYPE_BASIC: +- case IEEE80211_ML_CONTROL_TYPE_PREQ: +- case IEEE80211_ML_CONTROL_TYPE_TDLS: +- case IEEE80211_ML_CONTROL_TYPE_RECONF: +- case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS: +- /* +- * The length is the first octet pointed by mle->variable so no +- * need to add anything +- */ +- break; +- default: +- WARN_ON(1); +- return 0; +- } +- +- return sizeof(*mle) + mle->variable[0]; +-} +- +-/** +- * ieee80211_mle_get_link_id - returns the link ID +- * @data: the basic multi link element +- * Return: the link ID, or -1 if not present +- * +- * The element is assumed to be of the correct type (BASIC) and big enough, +- * this must be checked using ieee80211_mle_type_ok(). +- */ +-static inline int ieee80211_mle_get_link_id(const u8 *data) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control = le16_to_cpu(mle->control); +- const u8 *common = mle->variable; +- +- /* common points now at the beginning of ieee80211_mle_basic_common_info */ +- common += sizeof(struct ieee80211_mle_basic_common_info); +- +- if (!(control & IEEE80211_MLC_BASIC_PRES_LINK_ID)) +- return -1; +- +- return *common; +-} +- +-/** +- * ieee80211_mle_get_bss_param_ch_cnt - returns the BSS parameter change count +- * @data: pointer to the basic multi link element +- * Return: the BSS Parameter Change Count field value, or -1 if not present +- * +- * The element is assumed to be of the correct type (BASIC) and big enough, +- * this must be checked using ieee80211_mle_type_ok(). +- */ +-static inline int +-ieee80211_mle_get_bss_param_ch_cnt(const u8 *data) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control = le16_to_cpu(mle->control); +- const u8 *common = mle->variable; +- +- /* common points now at the beginning of ieee80211_mle_basic_common_info */ +- common += sizeof(struct ieee80211_mle_basic_common_info); +- +- if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)) +- return -1; +- +- if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) +- common += 1; +- +- return *common; +-} +- +-/** +- * ieee80211_mle_get_eml_med_sync_delay - returns the medium sync delay +- * @data: pointer to the multi-link element +- * Return: the medium synchronization delay field value from the multi-link +- * element, or the default value (%IEEE80211_MED_SYNC_DELAY_DEFAULT) +- * if not present +- * +- * The element is assumed to be of the correct type (BASIC) and big enough, +- * this must be checked using ieee80211_mle_type_ok(). +- */ +-static inline u16 ieee80211_mle_get_eml_med_sync_delay(const u8 *data) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control = le16_to_cpu(mle->control); +- const u8 *common = mle->variable; +- +- /* common points now at the beginning of ieee80211_mle_basic_common_info */ +- common += sizeof(struct ieee80211_mle_basic_common_info); +- +- if (!(control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) +- return IEEE80211_MED_SYNC_DELAY_DEFAULT; +- +- if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) +- common += 1; +- +- return get_unaligned_le16(common); +-} +- +-/** +- * ieee80211_mle_get_eml_cap - returns the EML capability +- * @data: pointer to the multi-link element +- * Return: the EML capability field value from the multi-link element, +- * or 0 if not present +- * +- * The element is assumed to be of the correct type (BASIC) and big enough, +- * this must be checked using ieee80211_mle_type_ok(). +- */ +-static inline u16 ieee80211_mle_get_eml_cap(const u8 *data) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control = le16_to_cpu(mle->control); +- const u8 *common = mle->variable; +- +- /* common points now at the beginning of ieee80211_mle_basic_common_info */ +- common += sizeof(struct ieee80211_mle_basic_common_info); +- +- if (!(control & IEEE80211_MLC_BASIC_PRES_EML_CAPA)) +- return 0; +- +- if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) +- common += 2; +- +- return get_unaligned_le16(common); +-} +- +-/** +- * ieee80211_mle_get_mld_capa_op - returns the MLD capabilities and operations. +- * @data: pointer to the multi-link element +- * Return: the MLD capabilities and operations field value from the multi-link +- * element, or 0 if not present +- * +- * The element is assumed to be of the correct type (BASIC) and big enough, +- * this must be checked using ieee80211_mle_type_ok(). +- */ +-static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control = le16_to_cpu(mle->control); +- const u8 *common = mle->variable; +- +- /* +- * common points now at the beginning of +- * ieee80211_mle_basic_common_info +- */ +- common += sizeof(struct ieee80211_mle_basic_common_info); +- +- if (!(control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)) +- return 0; +- +- if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) +- common += 2; +- +- return get_unaligned_le16(common); +-} +- +-/* Defined in Figure 9-1074t in P802.11be_D7.0 */ +-#define IEEE80211_EHT_ML_EXT_MLD_CAPA_OP_PARAM_UPDATE 0x0001 +-#define IEEE80211_EHT_ML_EXT_MLD_CAPA_OP_RECO_MAX_LINKS_MASK 0x001e +-#define IEEE80211_EHT_ML_EXT_MLD_CAPA_NSTR_UPDATE 0x0020 +-#define IEEE80211_EHT_ML_EXT_MLD_CAPA_EMLSR_ENA_ON_ONE_LINK 0x0040 +-#define IEEE80211_EHT_ML_EXT_MLD_CAPA_BTM_MLD_RECO_MULTI_AP 0x0080 +- +-/** +- * ieee80211_mle_get_ext_mld_capa_op - returns the extended MLD capabilities +- * and operations. +- * @data: pointer to the multi-link element +- * Return: the extended MLD capabilities and operations field value from +- * the multi-link element, or 0 if not present +- * +- * The element is assumed to be of the correct type (BASIC) and big enough, +- * this must be checked using ieee80211_mle_type_ok(). +- */ +-static inline u16 ieee80211_mle_get_ext_mld_capa_op(const u8 *data) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control = le16_to_cpu(mle->control); +- const u8 *common = mle->variable; +- +- /* +- * common points now at the beginning of +- * ieee80211_mle_basic_common_info +- */ +- common += sizeof(struct ieee80211_mle_basic_common_info); +- +- if (!(control & IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP)) +- return 0; +- +- if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID) +- common += 1; +- +- return get_unaligned_le16(common); +-} +- +-/** +- * ieee80211_mle_get_mld_id - returns the MLD ID +- * @data: pointer to the multi-link element +- * Return: The MLD ID in the given multi-link element, or 0 if not present +- * +- * The element is assumed to be of the correct type (BASIC) and big enough, +- * this must be checked using ieee80211_mle_type_ok(). +- */ +-static inline u8 ieee80211_mle_get_mld_id(const u8 *data) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control = le16_to_cpu(mle->control); +- const u8 *common = mle->variable; +- +- /* +- * common points now at the beginning of +- * ieee80211_mle_basic_common_info +- */ +- common += sizeof(struct ieee80211_mle_basic_common_info); +- +- if (!(control & IEEE80211_MLC_BASIC_PRES_MLD_ID)) +- return 0; +- +- if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) +- common += 2; +- +- return *common; +-} +- +-/** +- * ieee80211_mle_size_ok - validate multi-link element size +- * @data: pointer to the element data +- * @len: length of the containing element +- * Return: whether or not the multi-link element size is OK +- */ +-static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u8 fixed = sizeof(*mle); +- u8 common = 0; +- bool check_common_len = false; +- u16 control; +- +- if (!data || len < fixed) +- return false; +- +- control = le16_to_cpu(mle->control); +- +- switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) { +- case IEEE80211_ML_CONTROL_TYPE_BASIC: +- common += sizeof(struct ieee80211_mle_basic_common_info); +- check_common_len = true; +- if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) +- common += 2; +- if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID) +- common += 1; +- if (control & IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP) +- common += 2; +- break; +- case IEEE80211_ML_CONTROL_TYPE_PREQ: +- common += sizeof(struct ieee80211_mle_preq_common_info); +- if (control & IEEE80211_MLC_PREQ_PRES_MLD_ID) +- common += 1; +- check_common_len = true; +- break; +- case IEEE80211_ML_CONTROL_TYPE_RECONF: +- if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR) +- common += ETH_ALEN; +- if (control & IEEE80211_MLC_RECONF_PRES_EML_CAPA) +- common += 2; +- if (control & IEEE80211_MLC_RECONF_PRES_MLD_CAPA_OP) +- common += 2; +- if (control & IEEE80211_MLC_RECONF_PRES_EXT_MLD_CAPA_OP) +- common += 2; +- break; +- case IEEE80211_ML_CONTROL_TYPE_TDLS: +- common += sizeof(struct ieee80211_mle_tdls_common_info); +- check_common_len = true; +- break; +- case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS: +- common = ETH_ALEN + 1; +- break; +- default: +- /* we don't know this type */ +- return true; +- } +- +- if (len < fixed + common) +- return false; +- +- if (!check_common_len) +- return true; +- +- /* if present, common length is the first octet there */ +- return mle->variable[0] >= common; +-} +- +-/** +- * ieee80211_mle_type_ok - validate multi-link element type and size +- * @data: pointer to the element data +- * @type: expected type of the element +- * @len: length of the containing element +- * Return: whether or not the multi-link element type matches and size is OK +- */ +-static inline bool ieee80211_mle_type_ok(const u8 *data, u8 type, size_t len) +-{ +- const struct ieee80211_multi_link_elem *mle = (const void *)data; +- u16 control; +- +- if (!ieee80211_mle_size_ok(data, len)) +- return false; +- +- control = le16_to_cpu(mle->control); +- +- if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) == type) +- return true; +- +- return false; +-} +- +-enum ieee80211_mle_subelems { +- IEEE80211_MLE_SUBELEM_PER_STA_PROFILE = 0, +- IEEE80211_MLE_SUBELEM_FRAGMENT = 254, +-}; +- +-#define IEEE80211_MLE_STA_CONTROL_LINK_ID 0x000f +-#define IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE 0x0010 +-#define IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT 0x0020 +-#define IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT 0x0040 +-#define IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT 0x0080 +-#define IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT 0x0100 +-#define IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT 0x0200 +-#define IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE 0x0400 +-#define IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT 0x0800 +- +-struct ieee80211_mle_per_sta_profile { +- __le16 control; +- u8 sta_info_len; +- u8 variable[]; +-} __packed; +- +-/** +- * ieee80211_mle_basic_sta_prof_size_ok - validate basic multi-link element sta +- * profile size +- * @data: pointer to the sub element data +- * @len: length of the containing sub element +- * Return: %true if the STA profile is large enough, %false otherwise +- */ +-static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, +- size_t len) +-{ +- const struct ieee80211_mle_per_sta_profile *prof = (const void *)data; +- u16 control; +- u8 fixed = sizeof(*prof); +- u8 info_len = 1; +- +- if (len < fixed) +- return false; +- +- control = le16_to_cpu(prof->control); +- +- if (control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT) +- info_len += 6; +- if (control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT) +- info_len += 2; +- if (control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT) +- info_len += 8; +- if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT) +- info_len += 2; +- if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE && +- control & IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT) { +- if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) +- info_len += 2; +- else +- info_len += 1; +- } +- if (control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT) +- info_len += 1; +- +- return prof->sta_info_len >= info_len && +- fixed + prof->sta_info_len - 1 <= len; +-} +- +-/** +- * ieee80211_mle_basic_sta_prof_bss_param_ch_cnt - get per-STA profile BSS +- * parameter change count +- * @prof: the per-STA profile, having been checked with +- * ieee80211_mle_basic_sta_prof_size_ok() for the correct length +- * +- * Return: The BSS parameter change count value if present, 0 otherwise. +- */ +-static inline u8 +-ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(const struct ieee80211_mle_per_sta_profile *prof) +-{ +- u16 control = le16_to_cpu(prof->control); +- const u8 *pos = prof->variable; +- +- if (!(control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT)) +- return 0; +- +- if (control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT) +- pos += 6; +- if (control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT) +- pos += 2; +- if (control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT) +- pos += 8; +- if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT) +- pos += 2; +- if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE && +- control & IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT) { +- if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) +- pos += 2; +- else +- pos += 1; +- } +- +- return *pos; +-} +- +-#define IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID 0x000f +-#define IEEE80211_MLE_STA_RECONF_CONTROL_COMPLETE_PROFILE 0x0010 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT 0x0020 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_AP_REM_TIMER_PRESENT 0x0040 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE 0x0780 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_AP_REM 0 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_OP_PARAM_UPDATE 1 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_ADD_LINK 2 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_DEL_LINK 3 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_NSTR_STATUS 4 +-#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_PARAMS_PRESENT 0x0800 +- +-/** +- * ieee80211_mle_reconf_sta_prof_size_ok - validate reconfiguration multi-link +- * element sta profile size. +- * @data: pointer to the sub element data +- * @len: length of the containing sub element +- * Return: %true if the STA profile is large enough, %false otherwise +- */ +-static inline bool ieee80211_mle_reconf_sta_prof_size_ok(const u8 *data, +- size_t len) +-{ +- const struct ieee80211_mle_per_sta_profile *prof = (const void *)data; +- u16 control; +- u8 fixed = sizeof(*prof); +- u8 info_len = 1; +- +- if (len < fixed) +- return false; +- +- control = le16_to_cpu(prof->control); +- +- if (control & IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT) +- info_len += ETH_ALEN; +- if (control & IEEE80211_MLE_STA_RECONF_CONTROL_AP_REM_TIMER_PRESENT) +- info_len += 2; +- if (control & IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_PARAMS_PRESENT) +- info_len += 2; +- +- return prof->sta_info_len >= info_len && +- fixed + prof->sta_info_len - 1 <= len; +-} +- +-#define IEEE80211_MLE_STA_EPCS_CONTROL_LINK_ID 0x000f +-#define IEEE80211_EPCS_ENA_RESP_BODY_LEN 3 +- +-static inline bool ieee80211_tid_to_link_map_size_ok(const u8 *data, size_t len) +-{ +- const struct ieee80211_ttlm_elem *t2l = (const void *)data; +- u8 control, fixed = sizeof(*t2l), elem_len = 0; +- +- if (len < fixed) +- return false; +- +- control = t2l->control; +- +- if (control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT) +- elem_len += 2; +- if (control & IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT) +- elem_len += 3; +- +- if (!(control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP)) { +- u8 bm_size; +- +- elem_len += 1; +- if (len < fixed + elem_len) +- return false; +- +- if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE) +- bm_size = 1; +- else +- bm_size = 2; +- +- elem_len += hweight8(t2l->optional[0]) * bm_size; +- } +- +- return len >= fixed + elem_len; +-} +- +-/** +- * ieee80211_emlsr_pad_delay_in_us - Fetch the EMLSR Padding delay +- * in microseconds +- * @eml_cap: EML capabilities field value from common info field of +- * the Multi-link element +- * Return: the EMLSR Padding delay (in microseconds) encoded in the +- * EML Capabilities field +- */ +- +-static inline u32 ieee80211_emlsr_pad_delay_in_us(u16 eml_cap) +-{ +- /* IEEE Std 802.11be-2024 Table 9-417i—Encoding of the EMLSR +- * Padding Delay subfield. +- */ +- u32 pad_delay = u16_get_bits(eml_cap, +- IEEE80211_EML_CAP_EMLSR_PADDING_DELAY); +- +- if (!pad_delay || +- pad_delay > IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US) +- return 0; +- +- return 32 * (1 << (pad_delay - 1)); +-} +- +-/** +- * ieee80211_emlsr_trans_delay_in_us - Fetch the EMLSR Transition +- * delay in microseconds +- * @eml_cap: EML capabilities field value from common info field of +- * the Multi-link element +- * Return: the EMLSR Transition delay (in microseconds) encoded in the +- * EML Capabilities field +- */ +- +-static inline u32 ieee80211_emlsr_trans_delay_in_us(u16 eml_cap) +-{ +- /* IEEE Std 802.11be-2024 Table 9-417j—Encoding of the EMLSR +- * Transition Delay subfield. +- */ +- u32 trans_delay = +- u16_get_bits(eml_cap, +- IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY); +- +- /* invalid values also just use 0 */ +- if (!trans_delay || +- trans_delay > IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US) +- return 0; +- +- return 16 * (1 << (trans_delay - 1)); +-} +- +-/** +- * ieee80211_eml_trans_timeout_in_us - Fetch the EMLSR Transition +- * timeout value in microseconds +- * @eml_cap: EML capabilities field value from common info field of +- * the Multi-link element +- * Return: the EMLSR Transition timeout (in microseconds) encoded in +- * the EML Capabilities field +- */ +- +-static inline u32 ieee80211_eml_trans_timeout_in_us(u16 eml_cap) +-{ +- /* IEEE Std 802.11be-2024 Table 9-417m—Encoding of the +- * Transition Timeout subfield. +- */ +- u8 timeout = u16_get_bits(eml_cap, +- IEEE80211_EML_CAP_TRANSITION_TIMEOUT); +- +- /* invalid values also just use 0 */ +- if (!timeout || timeout > IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU) +- return 0; +- +- return 128 * (1 << (timeout - 1)); +-} +- +-#define for_each_mle_subelement(_elem, _data, _len) \ +- if (ieee80211_mle_size_ok(_data, _len)) \ +- for_each_element(_elem, \ +- _data + ieee80211_mle_common_size(_data),\ +- _len - ieee80211_mle_common_size(_data)) +- + /* NAN operation mode, as defined in Wi-Fi Aware (TM) specification Table 81 */ + #define NAN_OP_MODE_PHY_MODE_VHT 0x01 + #define NAN_OP_MODE_PHY_MODE_HE 0x10 +@@ -4605,6 +3443,8 @@ static inline u32 ieee80211_eml_trans_timeout_in_us(u16 eml_cap) + + #include "ieee80211-ht.h" + #include "ieee80211-vht.h" ++#include "ieee80211-he.h" ++#include "ieee80211-eht.h" + #include "ieee80211-mesh.h" + + #endif /* LINUX_IEEE80211_H */ +-- +2.53.0 + diff --git a/queue-6.18/wifi-ieee80211-split-he-definitions-out.patch b/queue-6.18/wifi-ieee80211-split-he-definitions-out.patch new file mode 100644 index 0000000000..4fc60967ef --- /dev/null +++ b/queue-6.18/wifi-ieee80211-split-he-definitions-out.patch @@ -0,0 +1,1700 @@ +From 4119bb6a54574ae4425728e5313407881291eef4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 15:36:52 +0100 +Subject: wifi: ieee80211: split HE definitions out + +From: Johannes Berg + +[ Upstream commit 02a2cf302557eb59794bba0b05d6755f44928d78 ] + +The ieee80211.h file has gotten very long, continue splitting +it by putting HE definitions into a separate file. + +Link: https://patch.msgid.link/20251105153843.6998c0802104.I3dd7cfea6abbd118b999ecdedd48437d39cb0533@changeid +Signed-off-by: Johannes Berg +Stable-dep-of: cb0caadb64ca ("wifi: ieee80211: fix definition of EHT-MCS 15 in MRU") +Signed-off-by: Sasha Levin +--- + include/linux/ieee80211-he.h | 824 +++++++++++++++++++++++++++++++++++ + include/linux/ieee80211.h | 806 +--------------------------------- + 2 files changed, 827 insertions(+), 803 deletions(-) + create mode 100644 include/linux/ieee80211-he.h + +diff --git a/include/linux/ieee80211-he.h b/include/linux/ieee80211-he.h +new file mode 100644 +index 0000000000000..904d50db5bb80 +--- /dev/null ++++ b/include/linux/ieee80211-he.h +@@ -0,0 +1,824 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * IEEE 802.11 HE definitions ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Copyright (c) 2005, Devicescape Software, Inc. ++ * Copyright (c) 2006, Michael Wu ++ * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH ++ * Copyright (c) 2016 - 2017 Intel Deutschland GmbH ++ * Copyright (c) 2018 - 2025 Intel Corporation ++ */ ++ ++#ifndef LINUX_IEEE80211_HE_H ++#define LINUX_IEEE80211_HE_H ++ ++#include ++#include ++ ++#define IEEE80211_TWT_CONTROL_NDP BIT(0) ++#define IEEE80211_TWT_CONTROL_RESP_MODE BIT(1) ++#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST BIT(3) ++#define IEEE80211_TWT_CONTROL_RX_DISABLED BIT(4) ++#define IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT BIT(5) ++ ++#define IEEE80211_TWT_REQTYPE_REQUEST BIT(0) ++#define IEEE80211_TWT_REQTYPE_SETUP_CMD GENMASK(3, 1) ++#define IEEE80211_TWT_REQTYPE_TRIGGER BIT(4) ++#define IEEE80211_TWT_REQTYPE_IMPLICIT BIT(5) ++#define IEEE80211_TWT_REQTYPE_FLOWTYPE BIT(6) ++#define IEEE80211_TWT_REQTYPE_FLOWID GENMASK(9, 7) ++#define IEEE80211_TWT_REQTYPE_WAKE_INT_EXP GENMASK(14, 10) ++#define IEEE80211_TWT_REQTYPE_PROTECTION BIT(15) ++ ++enum ieee80211_twt_setup_cmd { ++ TWT_SETUP_CMD_REQUEST, ++ TWT_SETUP_CMD_SUGGEST, ++ TWT_SETUP_CMD_DEMAND, ++ TWT_SETUP_CMD_GROUPING, ++ TWT_SETUP_CMD_ACCEPT, ++ TWT_SETUP_CMD_ALTERNATE, ++ TWT_SETUP_CMD_DICTATE, ++ TWT_SETUP_CMD_REJECT, ++}; ++ ++struct ieee80211_twt_params { ++ __le16 req_type; ++ __le64 twt; ++ u8 min_twt_dur; ++ __le16 mantissa; ++ u8 channel; ++} __packed; ++ ++struct ieee80211_twt_setup { ++ u8 dialog_token; ++ u8 element_id; ++ u8 length; ++ u8 control; ++ u8 params[]; ++} __packed; ++ ++/** ++ * struct ieee80211_he_cap_elem - HE capabilities element ++ * @mac_cap_info: HE MAC Capabilities Information ++ * @phy_cap_info: HE PHY Capabilities Information ++ * ++ * This structure represents the fixed fields of the payload of the ++ * "HE capabilities element" as described in IEEE Std 802.11ax-2021 ++ * sections 9.4.2.248.2 and 9.4.2.248.3. ++ */ ++struct ieee80211_he_cap_elem { ++ u8 mac_cap_info[6]; ++ u8 phy_cap_info[11]; ++} __packed; ++ ++#define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5 ++ ++/** ++ * enum ieee80211_he_mcs_support - HE MCS support definitions ++ * @IEEE80211_HE_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the ++ * number of streams ++ * @IEEE80211_HE_MCS_SUPPORT_0_9: MCSes 0-9 are supported ++ * @IEEE80211_HE_MCS_SUPPORT_0_11: MCSes 0-11 are supported ++ * @IEEE80211_HE_MCS_NOT_SUPPORTED: This number of streams isn't supported ++ * ++ * These definitions are used in each 2-bit subfield of the rx_mcs_* ++ * and tx_mcs_* fields of &struct ieee80211_he_mcs_nss_supp, which are ++ * both split into 8 subfields by number of streams. These values indicate ++ * which MCSes are supported for the number of streams the value appears ++ * for. ++ */ ++enum ieee80211_he_mcs_support { ++ IEEE80211_HE_MCS_SUPPORT_0_7 = 0, ++ IEEE80211_HE_MCS_SUPPORT_0_9 = 1, ++ IEEE80211_HE_MCS_SUPPORT_0_11 = 2, ++ IEEE80211_HE_MCS_NOT_SUPPORTED = 3, ++}; ++ ++/** ++ * struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field ++ * ++ * This structure holds the data required for the Tx/Rx HE MCS NSS Support Field ++ * described in P802.11ax_D2.0 section 9.4.2.237.4 ++ * ++ * @rx_mcs_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel ++ * widths less than 80MHz. ++ * @tx_mcs_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel ++ * widths less than 80MHz. ++ * @rx_mcs_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel ++ * width 160MHz. ++ * @tx_mcs_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel ++ * width 160MHz. ++ * @rx_mcs_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for ++ * channel width 80p80MHz. ++ * @tx_mcs_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for ++ * channel width 80p80MHz. ++ */ ++struct ieee80211_he_mcs_nss_supp { ++ __le16 rx_mcs_80; ++ __le16 tx_mcs_80; ++ __le16 rx_mcs_160; ++ __le16 tx_mcs_160; ++ __le16 rx_mcs_80p80; ++ __le16 tx_mcs_80p80; ++} __packed; ++ ++/** ++ * struct ieee80211_he_operation - HE Operation element ++ * @he_oper_params: HE Operation Parameters + BSS Color Information ++ * @he_mcs_nss_set: Basic HE-MCS And NSS Set ++ * @optional: Optional fields VHT Operation Information, Max Co-Hosted ++ * BSSID Indicator, and 6 GHz Operation Information ++ * ++ * This structure represents the payload of the "HE Operation ++ * element" as described in IEEE Std 802.11ax-2021 section 9.4.2.249. ++ */ ++struct ieee80211_he_operation { ++ __le32 he_oper_params; ++ __le16 he_mcs_nss_set; ++ u8 optional[]; ++} __packed; ++ ++/** ++ * struct ieee80211_he_spr - Spatial Reuse Parameter Set element ++ * @he_sr_control: SR Control ++ * @optional: Optional fields Non-SRG OBSS PD Max Offset, SRG OBSS PD ++ * Min Offset, SRG OBSS PD Max Offset, SRG BSS Color ++ * Bitmap, and SRG Partial BSSID Bitmap ++ * ++ * This structure represents the payload of the "Spatial Reuse ++ * Parameter Set element" as described in IEEE Std 802.11ax-2021 ++ * section 9.4.2.252. ++ */ ++struct ieee80211_he_spr { ++ u8 he_sr_control; ++ u8 optional[]; ++} __packed; ++ ++/** ++ * struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field ++ * @aifsn: ACI/AIFSN ++ * @ecw_min_max: ECWmin/ECWmax ++ * @mu_edca_timer: MU EDCA Timer ++ * ++ * This structure represents the "MU AC Parameter Record" as described ++ * in IEEE Std 802.11ax-2021 section 9.4.2.251, Figure 9-788p. ++ */ ++struct ieee80211_he_mu_edca_param_ac_rec { ++ u8 aifsn; ++ u8 ecw_min_max; ++ u8 mu_edca_timer; ++} __packed; ++ ++/** ++ * struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element ++ * @mu_qos_info: QoS Info ++ * @ac_be: MU AC_BE Parameter Record ++ * @ac_bk: MU AC_BK Parameter Record ++ * @ac_vi: MU AC_VI Parameter Record ++ * @ac_vo: MU AC_VO Parameter Record ++ * ++ * This structure represents the payload of the "MU EDCA Parameter Set ++ * element" as described in IEEE Std 802.11ax-2021 section 9.4.2.251. ++ */ ++struct ieee80211_mu_edca_param_set { ++ u8 mu_qos_info; ++ struct ieee80211_he_mu_edca_param_ac_rec ac_be; ++ struct ieee80211_he_mu_edca_param_ac_rec ac_bk; ++ struct ieee80211_he_mu_edca_param_ac_rec ac_vi; ++ struct ieee80211_he_mu_edca_param_ac_rec ac_vo; ++} __packed; ++ ++/* 802.11ax HE MAC capabilities */ ++#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01 ++#define IEEE80211_HE_MAC_CAP0_TWT_REQ 0x02 ++#define IEEE80211_HE_MAC_CAP0_TWT_RES 0x04 ++#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_NOT_SUPP 0x00 ++#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_1 0x08 ++#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_2 0x10 ++#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_3 0x18 ++#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_MASK 0x18 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_1 0x00 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_2 0x20 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_4 0x40 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_8 0x60 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_16 0x80 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_32 0xa0 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_64 0xc0 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_UNLIMITED 0xe0 ++#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_MASK 0xe0 ++ ++#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_UNLIMITED 0x00 ++#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_128 0x01 ++#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_256 0x02 ++#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_512 0x03 ++#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_MASK 0x03 ++#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US 0x00 ++#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US 0x04 ++#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US 0x08 ++#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK 0x0c ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1 0x00 ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_2 0x10 ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_3 0x20 ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_4 0x30 ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_5 0x40 ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_6 0x50 ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_7 0x60 ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8 0x70 ++#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_MASK 0x70 ++ ++/* Link adaptation is split between byte HE_MAC_CAP1 and ++ * HE_MAC_CAP2. It should be set only if IEEE80211_HE_MAC_CAP0_HTC_HE ++ * in which case the following values apply: ++ * 0 = No feedback. ++ * 1 = reserved. ++ * 2 = Unsolicited feedback. ++ * 3 = both ++ */ ++#define IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION 0x80 ++ ++#define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION 0x01 ++#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02 ++#define IEEE80211_HE_MAC_CAP2_TRS 0x04 ++#define IEEE80211_HE_MAC_CAP2_BSR 0x08 ++#define IEEE80211_HE_MAC_CAP2_BCAST_TWT 0x10 ++#define IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP 0x20 ++#define IEEE80211_HE_MAC_CAP2_MU_CASCADING 0x40 ++#define IEEE80211_HE_MAC_CAP2_ACK_EN 0x80 ++ ++#define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x02 ++#define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x04 ++ ++/* The maximum length of an A-MDPU is defined by the combination of the Maximum ++ * A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and the ++ * same field in the HE capabilities. ++ */ ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_0 0x00 ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1 0x08 ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2 0x10 ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3 0x18 ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x18 ++#define IEEE80211_HE_MAC_CAP3_AMSDU_FRAG 0x20 ++#define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40 ++#define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80 ++ ++#define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01 ++#define IEEE80211_HE_MAC_CAP4_QTP 0x02 ++#define IEEE80211_HE_MAC_CAP4_BQR 0x04 ++#define IEEE80211_HE_MAC_CAP4_PSR_RESP 0x08 ++#define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10 ++#define IEEE80211_HE_MAC_CAP4_OPS 0x20 ++#define IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU 0x40 ++/* Multi TID agg TX is split between byte #4 and #5 ++ * The value is a combination of B39,B40,B41 ++ */ ++#define IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39 0x80 ++ ++#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 0x01 ++#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 0x02 ++#define IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECTIVE_TRANSMISSION 0x04 ++#define IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU 0x08 ++#define IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX 0x10 ++#define IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS 0x20 ++#define IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING 0x40 ++#define IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX 0x80 ++ ++#define IEEE80211_HE_VHT_MAX_AMPDU_FACTOR 20 ++#define IEEE80211_HE_HT_MAX_AMPDU_FACTOR 16 ++#define IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR 13 ++ ++/* 802.11ax HE PHY capabilities */ ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02 ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04 ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 0x08 ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G 0x10 ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL 0x1e ++ ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G 0x20 ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G 0x40 ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK 0xfe ++ ++#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ 0x01 ++#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ 0x02 ++#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ 0x04 ++#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ 0x08 ++#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK 0x0f ++#define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A 0x10 ++#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20 ++#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40 ++/* Midamble RX/TX Max NSTS is split between byte #2 and byte #3 */ ++#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80 ++ ++#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS 0x01 ++#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02 ++#define IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ 0x04 ++#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08 ++#define IEEE80211_HE_PHY_CAP2_DOPPLER_TX 0x10 ++#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20 ++ ++/* Note that the meaning of UL MU below is different between an AP and a non-AP ++ * sta, where in the AP case it indicates support for Rx and in the non-AP sta ++ * case it indicates support for Tx. ++ */ ++#define IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO 0x40 ++#define IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO 0x80 ++ ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM 0x00 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK 0x01 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK 0x02 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM 0x03 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK 0x03 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 0x00 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2 0x04 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM 0x00 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK 0x08 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK 0x10 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK 0x18 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2 0x20 ++#define IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU 0x40 ++#define IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER 0x80 ++ ++#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01 ++#define IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER 0x02 ++ ++/* Minimal allowed value of Max STS under 80MHz is 3 */ ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 0x10 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_6 0x14 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_7 0x18 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8 0x1c ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK 0x1c ++ ++/* Minimal allowed value of Max STS above 80MHz is 3 */ ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 0x60 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5 0x80 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_6 0xa0 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_7 0xc0 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 0xe0 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK 0xe0 ++ ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_1 0x00 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 0x01 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_3 0x02 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4 0x03 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_5 0x04 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_6 0x05 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_7 0x06 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_8 0x07 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK 0x07 ++ ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_1 0x00 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 0x08 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_3 0x10 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_4 0x18 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_5 0x20 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_6 0x28 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_7 0x30 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_8 0x38 ++#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK 0x38 ++ ++#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40 ++#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80 ++ ++#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01 ++#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02 ++#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB 0x04 ++#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB 0x08 ++#define IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB 0x10 ++#define IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE 0x20 ++#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40 ++#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80 ++ ++#define IEEE80211_HE_PHY_CAP7_PSR_BASED_SR 0x01 ++#define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP 0x02 ++#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04 ++#define IEEE80211_HE_PHY_CAP7_MAX_NC_1 0x08 ++#define IEEE80211_HE_PHY_CAP7_MAX_NC_2 0x10 ++#define IEEE80211_HE_PHY_CAP7_MAX_NC_3 0x18 ++#define IEEE80211_HE_PHY_CAP7_MAX_NC_4 0x20 ++#define IEEE80211_HE_PHY_CAP7_MAX_NC_5 0x28 ++#define IEEE80211_HE_PHY_CAP7_MAX_NC_6 0x30 ++#define IEEE80211_HE_PHY_CAP7_MAX_NC_7 0x38 ++#define IEEE80211_HE_PHY_CAP7_MAX_NC_MASK 0x38 ++#define IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ 0x40 ++#define IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ 0x80 ++ ++#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI 0x01 ++#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02 ++#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU 0x04 ++#define IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU 0x08 ++#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI 0x10 ++#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_TX_2X_AND_1XLTF 0x20 ++#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242 0x00 ++#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484 0x40 ++#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996 0x80 ++#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996 0xc0 ++#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK 0xc0 ++ ++#define IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM 0x01 ++#define IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK 0x02 ++#define IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU 0x04 ++#define IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU 0x08 ++#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10 ++#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20 ++#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_0US 0x0 ++#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_8US 0x1 ++#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US 0x2 ++#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED 0x3 ++#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS 6 ++#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK 0xc0 ++ ++#define IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF 0x01 ++ ++/* 802.11ax HE TX/RX MCS NSS Support */ ++#define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3) ++#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_POS (6) ++#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_POS (11) ++#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_MASK 0x07c0 ++#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_MASK 0xf800 ++ ++/* TX/RX HE MCS Support field Highest MCS subfield encoding */ ++enum ieee80211_he_highest_mcs_supported_subfield_enc { ++ HIGHEST_MCS_SUPPORTED_MCS7 = 0, ++ HIGHEST_MCS_SUPPORTED_MCS8, ++ HIGHEST_MCS_SUPPORTED_MCS9, ++ HIGHEST_MCS_SUPPORTED_MCS10, ++ HIGHEST_MCS_SUPPORTED_MCS11, ++}; ++ ++/* Calculate 802.11ax HE capabilities IE Tx/Rx HE MCS NSS Support Field size */ ++static inline u8 ++ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap) ++{ ++ u8 count = 4; ++ ++ if (he_cap->phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) ++ count += 4; ++ ++ if (he_cap->phy_cap_info[0] & ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) ++ count += 4; ++ ++ return count; ++} ++ ++/* 802.11ax HE PPE Thresholds */ ++#define IEEE80211_PPE_THRES_NSS_SUPPORT_2NSS (1) ++#define IEEE80211_PPE_THRES_NSS_POS (0) ++#define IEEE80211_PPE_THRES_NSS_MASK (7) ++#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_2x966_AND_966_RU \ ++ (BIT(5) | BIT(6)) ++#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK 0x78 ++#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS (3) ++#define IEEE80211_PPE_THRES_INFO_PPET_SIZE (3) ++#define IEEE80211_HE_PPE_THRES_INFO_HEADER_SIZE (7) ++ ++/* ++ * Calculate 802.11ax HE capabilities IE PPE field size ++ * Input: Header byte of ppe_thres (first byte), and HE capa IE's PHY cap u8* ++ */ ++static inline u8 ++ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) ++{ ++ u8 n; ++ ++ if ((phy_cap_info[6] & ++ IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) ++ return 0; ++ ++ n = hweight8(ppe_thres_hdr & ++ IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK); ++ n *= (1 + ((ppe_thres_hdr & IEEE80211_PPE_THRES_NSS_MASK) >> ++ IEEE80211_PPE_THRES_NSS_POS)); ++ ++ /* ++ * Each pair is 6 bits, and we need to add the 7 "header" bits to the ++ * total size. ++ */ ++ n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7; ++ n = DIV_ROUND_UP(n, 8); ++ ++ return n; ++} ++ ++static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len) ++{ ++ const struct ieee80211_he_cap_elem *he_cap_ie_elem = (const void *)data; ++ u8 needed = sizeof(*he_cap_ie_elem); ++ ++ if (len < needed) ++ return false; ++ ++ needed += ieee80211_he_mcs_nss_size(he_cap_ie_elem); ++ if (len < needed) ++ return false; ++ ++ if (he_cap_ie_elem->phy_cap_info[6] & ++ IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { ++ if (len < needed + 1) ++ return false; ++ needed += ieee80211_he_ppe_size(data[needed], ++ he_cap_ie_elem->phy_cap_info); ++ } ++ ++ return len >= needed; ++} ++ ++/* HE Operation defines */ ++#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK 0x00000007 ++#define IEEE80211_HE_OPERATION_TWT_REQUIRED 0x00000008 ++#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK 0x00003ff0 ++#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET 4 ++#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00004000 ++#define IEEE80211_HE_OPERATION_CO_HOSTED_BSS 0x00008000 ++#define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000 ++#define IEEE80211_HE_OPERATION_6GHZ_OP_INFO 0x00020000 ++#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000 ++#define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24 ++#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000 ++#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000 ++ ++#define IEEE80211_6GHZ_CTRL_REG_LPI_AP 0 ++#define IEEE80211_6GHZ_CTRL_REG_SP_AP 1 ++#define IEEE80211_6GHZ_CTRL_REG_VLP_AP 2 ++#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP 3 ++#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD 4 ++#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP 8 ++ ++/** ++ * struct ieee80211_he_6ghz_oper - HE 6 GHz operation Information field ++ * @primary: primary channel ++ * @control: control flags ++ * @ccfs0: channel center frequency segment 0 ++ * @ccfs1: channel center frequency segment 1 ++ * @minrate: minimum rate (in 1 Mbps units) ++ */ ++struct ieee80211_he_6ghz_oper { ++ u8 primary; ++#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH 0x3 ++#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ 0 ++#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ 1 ++#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ 2 ++#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ 3 ++#define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4 ++#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x78 ++ u8 control; ++ u8 ccfs0; ++ u8 ccfs1; ++ u8 minrate; ++} __packed; ++ ++/** ++ * enum ieee80211_reg_conn_bits - represents Regulatory connectivity field bits. ++ * ++ * This enumeration defines bit flags used to represent regulatory connectivity ++ * field bits. ++ * ++ * @IEEE80211_REG_CONN_LPI_VALID: Indicates whether the LPI bit is valid. ++ * @IEEE80211_REG_CONN_LPI_VALUE: Represents the value of the LPI bit. ++ * @IEEE80211_REG_CONN_SP_VALID: Indicates whether the SP bit is valid. ++ * @IEEE80211_REG_CONN_SP_VALUE: Represents the value of the SP bit. ++ */ ++enum ieee80211_reg_conn_bits { ++ IEEE80211_REG_CONN_LPI_VALID = BIT(0), ++ IEEE80211_REG_CONN_LPI_VALUE = BIT(1), ++ IEEE80211_REG_CONN_SP_VALID = BIT(2), ++ IEEE80211_REG_CONN_SP_VALUE = BIT(3), ++}; ++ ++/* transmit power interpretation type of transmit power envelope element */ ++enum ieee80211_tx_power_intrpt_type { ++ IEEE80211_TPE_LOCAL_EIRP, ++ IEEE80211_TPE_LOCAL_EIRP_PSD, ++ IEEE80211_TPE_REG_CLIENT_EIRP, ++ IEEE80211_TPE_REG_CLIENT_EIRP_PSD, ++}; ++ ++/* category type of transmit power envelope element */ ++enum ieee80211_tx_power_category_6ghz { ++ IEEE80211_TPE_CAT_6GHZ_DEFAULT = 0, ++ IEEE80211_TPE_CAT_6GHZ_SUBORDINATE = 1, ++}; ++ ++/* ++ * For IEEE80211_TPE_LOCAL_EIRP / IEEE80211_TPE_REG_CLIENT_EIRP, ++ * setting to 63.5 dBm means no constraint. ++ */ ++#define IEEE80211_TPE_MAX_TX_PWR_NO_CONSTRAINT 127 ++ ++/* ++ * For IEEE80211_TPE_LOCAL_EIRP_PSD / IEEE80211_TPE_REG_CLIENT_EIRP_PSD, ++ * setting to 127 indicates no PSD limit for the 20 MHz channel. ++ */ ++#define IEEE80211_TPE_PSD_NO_LIMIT 127 ++ ++/** ++ * struct ieee80211_tx_pwr_env - Transmit Power Envelope ++ * @info: Transmit Power Information field ++ * @variable: Maximum Transmit Power field ++ * ++ * This structure represents the payload of the "Transmit Power ++ * Envelope element" as described in IEEE Std 802.11ax-2021 section ++ * 9.4.2.161 ++ */ ++struct ieee80211_tx_pwr_env { ++ u8 info; ++ u8 variable[]; ++} __packed; ++ ++#define IEEE80211_TX_PWR_ENV_INFO_COUNT 0x7 ++#define IEEE80211_TX_PWR_ENV_INFO_INTERPRET 0x38 ++#define IEEE80211_TX_PWR_ENV_INFO_CATEGORY 0xC0 ++ ++#define IEEE80211_TX_PWR_ENV_EXT_COUNT 0xF ++ ++static inline bool ieee80211_valid_tpe_element(const u8 *data, u8 len) ++{ ++ const struct ieee80211_tx_pwr_env *env = (const void *)data; ++ u8 count, interpret, category; ++ u8 needed = sizeof(*env); ++ u8 N; /* also called N in the spec */ ++ ++ if (len < needed) ++ return false; ++ ++ count = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_COUNT); ++ interpret = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_INTERPRET); ++ category = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_CATEGORY); ++ ++ switch (category) { ++ case IEEE80211_TPE_CAT_6GHZ_DEFAULT: ++ case IEEE80211_TPE_CAT_6GHZ_SUBORDINATE: ++ break; ++ default: ++ return false; ++ } ++ ++ switch (interpret) { ++ case IEEE80211_TPE_LOCAL_EIRP: ++ case IEEE80211_TPE_REG_CLIENT_EIRP: ++ if (count > 3) ++ return false; ++ ++ /* count == 0 encodes 1 value for 20 MHz, etc. */ ++ needed += count + 1; ++ ++ if (len < needed) ++ return false; ++ ++ /* there can be extension fields not accounted for in 'count' */ ++ ++ return true; ++ case IEEE80211_TPE_LOCAL_EIRP_PSD: ++ case IEEE80211_TPE_REG_CLIENT_EIRP_PSD: ++ if (count > 4) ++ return false; ++ ++ N = count ? 1 << (count - 1) : 1; ++ needed += N; ++ ++ if (len < needed) ++ return false; ++ ++ if (len > needed) { ++ u8 K = u8_get_bits(env->variable[N], ++ IEEE80211_TX_PWR_ENV_EXT_COUNT); ++ ++ needed += 1 + K; ++ if (len < needed) ++ return false; ++ } ++ ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size ++ * @he_oper_ie: byte data of the He Operations IE, stating from the byte ++ * after the ext ID byte. It is assumed that he_oper_ie has at least ++ * sizeof(struct ieee80211_he_operation) bytes, the caller must have ++ * validated this. ++ * @return the actual size of the IE data (not including header), or 0 on error ++ */ ++static inline u8 ++ieee80211_he_oper_size(const u8 *he_oper_ie) ++{ ++ const struct ieee80211_he_operation *he_oper = (const void *)he_oper_ie; ++ u8 oper_len = sizeof(struct ieee80211_he_operation); ++ u32 he_oper_params; ++ ++ /* Make sure the input is not NULL */ ++ if (!he_oper_ie) ++ return 0; ++ ++ /* Calc required length */ ++ he_oper_params = le32_to_cpu(he_oper->he_oper_params); ++ if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO) ++ oper_len += 3; ++ if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS) ++ oper_len++; ++ if (he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO) ++ oper_len += sizeof(struct ieee80211_he_6ghz_oper); ++ ++ /* Add the first byte (extension ID) to the total length */ ++ oper_len++; ++ ++ return oper_len; ++} ++ ++/** ++ * ieee80211_he_6ghz_oper - obtain 6 GHz operation field ++ * @he_oper: HE operation element (must be pre-validated for size) ++ * but may be %NULL ++ * ++ * Return: a pointer to the 6 GHz operation field, or %NULL ++ */ ++static inline const struct ieee80211_he_6ghz_oper * ++ieee80211_he_6ghz_oper(const struct ieee80211_he_operation *he_oper) ++{ ++ const u8 *ret; ++ u32 he_oper_params; ++ ++ if (!he_oper) ++ return NULL; ++ ++ ret = (const void *)&he_oper->optional; ++ ++ he_oper_params = le32_to_cpu(he_oper->he_oper_params); ++ ++ if (!(he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO)) ++ return NULL; ++ if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO) ++ ret += 3; ++ if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS) ++ ret++; ++ ++ return (const void *)ret; ++} ++ ++/* HE Spatial Reuse defines */ ++#define IEEE80211_HE_SPR_PSR_DISALLOWED BIT(0) ++#define IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1) ++#define IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT BIT(2) ++#define IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT BIT(3) ++#define IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED BIT(4) ++ ++/* ++ * ieee80211_he_spr_size - calculate 802.11ax HE Spatial Reuse IE size ++ * @he_spr_ie: byte data of the He Spatial Reuse IE, stating from the byte ++ * after the ext ID byte. It is assumed that he_spr_ie has at least ++ * sizeof(struct ieee80211_he_spr) bytes, the caller must have validated ++ * this ++ * @return the actual size of the IE data (not including header), or 0 on error ++ */ ++static inline u8 ++ieee80211_he_spr_size(const u8 *he_spr_ie) ++{ ++ const struct ieee80211_he_spr *he_spr = (const void *)he_spr_ie; ++ u8 spr_len = sizeof(struct ieee80211_he_spr); ++ u8 he_spr_params; ++ ++ /* Make sure the input is not NULL */ ++ if (!he_spr_ie) ++ return 0; ++ ++ /* Calc required length */ ++ he_spr_params = he_spr->he_sr_control; ++ if (he_spr_params & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT) ++ spr_len++; ++ if (he_spr_params & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) ++ spr_len += 18; ++ ++ /* Add the first byte (extension ID) to the total length */ ++ spr_len++; ++ ++ return spr_len; ++} ++ ++struct ieee80211_he_6ghz_capa { ++ /* uses IEEE80211_HE_6GHZ_CAP_* below */ ++ __le16 capa; ++} __packed; ++ ++/* HE 6 GHz band capabilities */ ++/* uses enum ieee80211_min_mpdu_spacing values */ ++#define IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START 0x0007 ++/* uses enum ieee80211_vht_max_ampdu_length_exp values */ ++#define IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP 0x0038 ++/* uses IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_* values */ ++#define IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN 0x00c0 ++/* WLAN_HT_CAP_SM_PS_* values */ ++#define IEEE80211_HE_6GHZ_CAP_SM_PS 0x0600 ++#define IEEE80211_HE_6GHZ_CAP_RD_RESPONDER 0x0800 ++#define IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS 0x1000 ++#define IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS 0x2000 ++ ++#endif /* LINUX_IEEE80211_HE_H */ +diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h +index fb399b7833736..2f3d0412ca759 100644 +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -1141,48 +1141,6 @@ ieee80211_s1g_optional_len(__le16 fc) + return len; + } + +-#define IEEE80211_TWT_CONTROL_NDP BIT(0) +-#define IEEE80211_TWT_CONTROL_RESP_MODE BIT(1) +-#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST BIT(3) +-#define IEEE80211_TWT_CONTROL_RX_DISABLED BIT(4) +-#define IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT BIT(5) +- +-#define IEEE80211_TWT_REQTYPE_REQUEST BIT(0) +-#define IEEE80211_TWT_REQTYPE_SETUP_CMD GENMASK(3, 1) +-#define IEEE80211_TWT_REQTYPE_TRIGGER BIT(4) +-#define IEEE80211_TWT_REQTYPE_IMPLICIT BIT(5) +-#define IEEE80211_TWT_REQTYPE_FLOWTYPE BIT(6) +-#define IEEE80211_TWT_REQTYPE_FLOWID GENMASK(9, 7) +-#define IEEE80211_TWT_REQTYPE_WAKE_INT_EXP GENMASK(14, 10) +-#define IEEE80211_TWT_REQTYPE_PROTECTION BIT(15) +- +-enum ieee80211_twt_setup_cmd { +- TWT_SETUP_CMD_REQUEST, +- TWT_SETUP_CMD_SUGGEST, +- TWT_SETUP_CMD_DEMAND, +- TWT_SETUP_CMD_GROUPING, +- TWT_SETUP_CMD_ACCEPT, +- TWT_SETUP_CMD_ALTERNATE, +- TWT_SETUP_CMD_DICTATE, +- TWT_SETUP_CMD_REJECT, +-}; +- +-struct ieee80211_twt_params { +- __le16 req_type; +- __le64 twt; +- u8 min_twt_dur; +- __le16 mantissa; +- u8 channel; +-} __packed; +- +-struct ieee80211_twt_setup { +- u8 dialog_token; +- u8 element_id; +- u8 length; +- u8 control; +- u8 params[]; +-} __packed; +- + #define IEEE80211_TTLM_MAX_CNT 2 + #define IEEE80211_TTLM_CONTROL_DIRECTION 0x03 + #define IEEE80211_TTLM_CONTROL_DEF_LINK_MAP 0x04 +@@ -1633,137 +1591,6 @@ struct ieee80211_p2p_noa_attr { + #define IEEE80211_P2P_OPPPS_ENABLE_BIT BIT(7) + #define IEEE80211_P2P_OPPPS_CTWINDOW_MASK 0x7F + +-/** +- * struct ieee80211_he_cap_elem - HE capabilities element +- * @mac_cap_info: HE MAC Capabilities Information +- * @phy_cap_info: HE PHY Capabilities Information +- * +- * This structure represents the fixed fields of the payload of the +- * "HE capabilities element" as described in IEEE Std 802.11ax-2021 +- * sections 9.4.2.248.2 and 9.4.2.248.3. +- */ +-struct ieee80211_he_cap_elem { +- u8 mac_cap_info[6]; +- u8 phy_cap_info[11]; +-} __packed; +- +-#define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5 +- +-/** +- * enum ieee80211_he_mcs_support - HE MCS support definitions +- * @IEEE80211_HE_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the +- * number of streams +- * @IEEE80211_HE_MCS_SUPPORT_0_9: MCSes 0-9 are supported +- * @IEEE80211_HE_MCS_SUPPORT_0_11: MCSes 0-11 are supported +- * @IEEE80211_HE_MCS_NOT_SUPPORTED: This number of streams isn't supported +- * +- * These definitions are used in each 2-bit subfield of the rx_mcs_* +- * and tx_mcs_* fields of &struct ieee80211_he_mcs_nss_supp, which are +- * both split into 8 subfields by number of streams. These values indicate +- * which MCSes are supported for the number of streams the value appears +- * for. +- */ +-enum ieee80211_he_mcs_support { +- IEEE80211_HE_MCS_SUPPORT_0_7 = 0, +- IEEE80211_HE_MCS_SUPPORT_0_9 = 1, +- IEEE80211_HE_MCS_SUPPORT_0_11 = 2, +- IEEE80211_HE_MCS_NOT_SUPPORTED = 3, +-}; +- +-/** +- * struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field +- * +- * This structure holds the data required for the Tx/Rx HE MCS NSS Support Field +- * described in P802.11ax_D2.0 section 9.4.2.237.4 +- * +- * @rx_mcs_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel +- * widths less than 80MHz. +- * @tx_mcs_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel +- * widths less than 80MHz. +- * @rx_mcs_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel +- * width 160MHz. +- * @tx_mcs_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel +- * width 160MHz. +- * @rx_mcs_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for +- * channel width 80p80MHz. +- * @tx_mcs_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for +- * channel width 80p80MHz. +- */ +-struct ieee80211_he_mcs_nss_supp { +- __le16 rx_mcs_80; +- __le16 tx_mcs_80; +- __le16 rx_mcs_160; +- __le16 tx_mcs_160; +- __le16 rx_mcs_80p80; +- __le16 tx_mcs_80p80; +-} __packed; +- +-/** +- * struct ieee80211_he_operation - HE Operation element +- * @he_oper_params: HE Operation Parameters + BSS Color Information +- * @he_mcs_nss_set: Basic HE-MCS And NSS Set +- * @optional: Optional fields VHT Operation Information, Max Co-Hosted +- * BSSID Indicator, and 6 GHz Operation Information +- * +- * This structure represents the payload of the "HE Operation +- * element" as described in IEEE Std 802.11ax-2021 section 9.4.2.249. +- */ +-struct ieee80211_he_operation { +- __le32 he_oper_params; +- __le16 he_mcs_nss_set; +- u8 optional[]; +-} __packed; +- +-/** +- * struct ieee80211_he_spr - Spatial Reuse Parameter Set element +- * @he_sr_control: SR Control +- * @optional: Optional fields Non-SRG OBSS PD Max Offset, SRG OBSS PD +- * Min Offset, SRG OBSS PD Max Offset, SRG BSS Color +- * Bitmap, and SRG Partial BSSID Bitmap +- * +- * This structure represents the payload of the "Spatial Reuse +- * Parameter Set element" as described in IEEE Std 802.11ax-2021 +- * section 9.4.2.252. +- */ +-struct ieee80211_he_spr { +- u8 he_sr_control; +- u8 optional[]; +-} __packed; +- +-/** +- * struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field +- * @aifsn: ACI/AIFSN +- * @ecw_min_max: ECWmin/ECWmax +- * @mu_edca_timer: MU EDCA Timer +- * +- * This structure represents the "MU AC Parameter Record" as described +- * in IEEE Std 802.11ax-2021 section 9.4.2.251, Figure 9-788p. +- */ +-struct ieee80211_he_mu_edca_param_ac_rec { +- u8 aifsn; +- u8 ecw_min_max; +- u8 mu_edca_timer; +-} __packed; +- +-/** +- * struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element +- * @mu_qos_info: QoS Info +- * @ac_be: MU AC_BE Parameter Record +- * @ac_bk: MU AC_BK Parameter Record +- * @ac_vi: MU AC_VI Parameter Record +- * @ac_vo: MU AC_VO Parameter Record +- * +- * This structure represents the payload of the "MU EDCA Parameter Set +- * element" as described in IEEE Std 802.11ax-2021 section 9.4.2.251. +- */ +-struct ieee80211_mu_edca_param_set { +- u8 mu_qos_info; +- struct ieee80211_he_mu_edca_param_ac_rec ac_be; +- struct ieee80211_he_mu_edca_param_ac_rec ac_bk; +- struct ieee80211_he_mu_edca_param_ac_rec ac_vi; +- struct ieee80211_he_mu_edca_param_ac_rec ac_vo; +-} __packed; +- + #define IEEE80211_EHT_MCS_NSS_RX 0x0f + #define IEEE80211_EHT_MCS_NSS_TX 0xf0 + +@@ -1902,618 +1729,6 @@ struct ieee80211_eht_operation_info { + u8 optional[]; + } __packed; + +-/* 802.11ax HE MAC capabilities */ +-#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01 +-#define IEEE80211_HE_MAC_CAP0_TWT_REQ 0x02 +-#define IEEE80211_HE_MAC_CAP0_TWT_RES 0x04 +-#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_NOT_SUPP 0x00 +-#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_1 0x08 +-#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_2 0x10 +-#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_3 0x18 +-#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_MASK 0x18 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_1 0x00 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_2 0x20 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_4 0x40 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_8 0x60 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_16 0x80 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_32 0xa0 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_64 0xc0 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_UNLIMITED 0xe0 +-#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_MASK 0xe0 +- +-#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_UNLIMITED 0x00 +-#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_128 0x01 +-#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_256 0x02 +-#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_512 0x03 +-#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_MASK 0x03 +-#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US 0x00 +-#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US 0x04 +-#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US 0x08 +-#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK 0x0c +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1 0x00 +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_2 0x10 +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_3 0x20 +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_4 0x30 +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_5 0x40 +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_6 0x50 +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_7 0x60 +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8 0x70 +-#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_MASK 0x70 +- +-/* Link adaptation is split between byte HE_MAC_CAP1 and +- * HE_MAC_CAP2. It should be set only if IEEE80211_HE_MAC_CAP0_HTC_HE +- * in which case the following values apply: +- * 0 = No feedback. +- * 1 = reserved. +- * 2 = Unsolicited feedback. +- * 3 = both +- */ +-#define IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION 0x80 +- +-#define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION 0x01 +-#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02 +-#define IEEE80211_HE_MAC_CAP2_TRS 0x04 +-#define IEEE80211_HE_MAC_CAP2_BSR 0x08 +-#define IEEE80211_HE_MAC_CAP2_BCAST_TWT 0x10 +-#define IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP 0x20 +-#define IEEE80211_HE_MAC_CAP2_MU_CASCADING 0x40 +-#define IEEE80211_HE_MAC_CAP2_ACK_EN 0x80 +- +-#define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x02 +-#define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x04 +- +-/* The maximum length of an A-MDPU is defined by the combination of the Maximum +- * A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and the +- * same field in the HE capabilities. +- */ +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_0 0x00 +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1 0x08 +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2 0x10 +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3 0x18 +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x18 +-#define IEEE80211_HE_MAC_CAP3_AMSDU_FRAG 0x20 +-#define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40 +-#define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80 +- +-#define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01 +-#define IEEE80211_HE_MAC_CAP4_QTP 0x02 +-#define IEEE80211_HE_MAC_CAP4_BQR 0x04 +-#define IEEE80211_HE_MAC_CAP4_PSR_RESP 0x08 +-#define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10 +-#define IEEE80211_HE_MAC_CAP4_OPS 0x20 +-#define IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU 0x40 +-/* Multi TID agg TX is split between byte #4 and #5 +- * The value is a combination of B39,B40,B41 +- */ +-#define IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39 0x80 +- +-#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 0x01 +-#define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 0x02 +-#define IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECTIVE_TRANSMISSION 0x04 +-#define IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU 0x08 +-#define IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX 0x10 +-#define IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS 0x20 +-#define IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING 0x40 +-#define IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX 0x80 +- +-#define IEEE80211_HE_VHT_MAX_AMPDU_FACTOR 20 +-#define IEEE80211_HE_HT_MAX_AMPDU_FACTOR 16 +-#define IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR 13 +- +-/* 802.11ax HE PHY capabilities */ +-#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02 +-#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04 +-#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 0x08 +-#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G 0x10 +-#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL 0x1e +- +-#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G 0x20 +-#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G 0x40 +-#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK 0xfe +- +-#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ 0x01 +-#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ 0x02 +-#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ 0x04 +-#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ 0x08 +-#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK 0x0f +-#define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A 0x10 +-#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20 +-#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40 +-/* Midamble RX/TX Max NSTS is split between byte #2 and byte #3 */ +-#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80 +- +-#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS 0x01 +-#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02 +-#define IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ 0x04 +-#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08 +-#define IEEE80211_HE_PHY_CAP2_DOPPLER_TX 0x10 +-#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20 +- +-/* Note that the meaning of UL MU below is different between an AP and a non-AP +- * sta, where in the AP case it indicates support for Rx and in the non-AP sta +- * case it indicates support for Tx. +- */ +-#define IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO 0x40 +-#define IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO 0x80 +- +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM 0x00 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK 0x01 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK 0x02 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM 0x03 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK 0x03 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 0x00 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2 0x04 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM 0x00 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK 0x08 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK 0x10 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK 0x18 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00 +-#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2 0x20 +-#define IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU 0x40 +-#define IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER 0x80 +- +-#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01 +-#define IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER 0x02 +- +-/* Minimal allowed value of Max STS under 80MHz is 3 */ +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 0x10 +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_6 0x14 +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_7 0x18 +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8 0x1c +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK 0x1c +- +-/* Minimal allowed value of Max STS above 80MHz is 3 */ +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 0x60 +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5 0x80 +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_6 0xa0 +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_7 0xc0 +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 0xe0 +-#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK 0xe0 +- +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_1 0x00 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 0x01 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_3 0x02 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4 0x03 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_5 0x04 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_6 0x05 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_7 0x06 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_8 0x07 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK 0x07 +- +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_1 0x00 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 0x08 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_3 0x10 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_4 0x18 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_5 0x20 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_6 0x28 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_7 0x30 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_8 0x38 +-#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK 0x38 +- +-#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40 +-#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80 +- +-#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01 +-#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02 +-#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB 0x04 +-#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB 0x08 +-#define IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB 0x10 +-#define IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE 0x20 +-#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40 +-#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80 +- +-#define IEEE80211_HE_PHY_CAP7_PSR_BASED_SR 0x01 +-#define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP 0x02 +-#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04 +-#define IEEE80211_HE_PHY_CAP7_MAX_NC_1 0x08 +-#define IEEE80211_HE_PHY_CAP7_MAX_NC_2 0x10 +-#define IEEE80211_HE_PHY_CAP7_MAX_NC_3 0x18 +-#define IEEE80211_HE_PHY_CAP7_MAX_NC_4 0x20 +-#define IEEE80211_HE_PHY_CAP7_MAX_NC_5 0x28 +-#define IEEE80211_HE_PHY_CAP7_MAX_NC_6 0x30 +-#define IEEE80211_HE_PHY_CAP7_MAX_NC_7 0x38 +-#define IEEE80211_HE_PHY_CAP7_MAX_NC_MASK 0x38 +-#define IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ 0x40 +-#define IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ 0x80 +- +-#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI 0x01 +-#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02 +-#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU 0x04 +-#define IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU 0x08 +-#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI 0x10 +-#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_TX_2X_AND_1XLTF 0x20 +-#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242 0x00 +-#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484 0x40 +-#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996 0x80 +-#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996 0xc0 +-#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK 0xc0 +- +-#define IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM 0x01 +-#define IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK 0x02 +-#define IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU 0x04 +-#define IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU 0x08 +-#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10 +-#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20 +-#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_0US 0x0 +-#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_8US 0x1 +-#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US 0x2 +-#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED 0x3 +-#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS 6 +-#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK 0xc0 +- +-#define IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF 0x01 +- +-/* 802.11ax HE TX/RX MCS NSS Support */ +-#define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3) +-#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_POS (6) +-#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_POS (11) +-#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_MASK 0x07c0 +-#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_MASK 0xf800 +- +-/* TX/RX HE MCS Support field Highest MCS subfield encoding */ +-enum ieee80211_he_highest_mcs_supported_subfield_enc { +- HIGHEST_MCS_SUPPORTED_MCS7 = 0, +- HIGHEST_MCS_SUPPORTED_MCS8, +- HIGHEST_MCS_SUPPORTED_MCS9, +- HIGHEST_MCS_SUPPORTED_MCS10, +- HIGHEST_MCS_SUPPORTED_MCS11, +-}; +- +-/* Calculate 802.11ax HE capabilities IE Tx/Rx HE MCS NSS Support Field size */ +-static inline u8 +-ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap) +-{ +- u8 count = 4; +- +- if (he_cap->phy_cap_info[0] & +- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) +- count += 4; +- +- if (he_cap->phy_cap_info[0] & +- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) +- count += 4; +- +- return count; +-} +- +-/* 802.11ax HE PPE Thresholds */ +-#define IEEE80211_PPE_THRES_NSS_SUPPORT_2NSS (1) +-#define IEEE80211_PPE_THRES_NSS_POS (0) +-#define IEEE80211_PPE_THRES_NSS_MASK (7) +-#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_2x966_AND_966_RU \ +- (BIT(5) | BIT(6)) +-#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK 0x78 +-#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS (3) +-#define IEEE80211_PPE_THRES_INFO_PPET_SIZE (3) +-#define IEEE80211_HE_PPE_THRES_INFO_HEADER_SIZE (7) +- +-/* +- * Calculate 802.11ax HE capabilities IE PPE field size +- * Input: Header byte of ppe_thres (first byte), and HE capa IE's PHY cap u8* +- */ +-static inline u8 +-ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) +-{ +- u8 n; +- +- if ((phy_cap_info[6] & +- IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) +- return 0; +- +- n = hweight8(ppe_thres_hdr & +- IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK); +- n *= (1 + ((ppe_thres_hdr & IEEE80211_PPE_THRES_NSS_MASK) >> +- IEEE80211_PPE_THRES_NSS_POS)); +- +- /* +- * Each pair is 6 bits, and we need to add the 7 "header" bits to the +- * total size. +- */ +- n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7; +- n = DIV_ROUND_UP(n, 8); +- +- return n; +-} +- +-static inline bool ieee80211_he_capa_size_ok(const u8 *data, u8 len) +-{ +- const struct ieee80211_he_cap_elem *he_cap_ie_elem = (const void *)data; +- u8 needed = sizeof(*he_cap_ie_elem); +- +- if (len < needed) +- return false; +- +- needed += ieee80211_he_mcs_nss_size(he_cap_ie_elem); +- if (len < needed) +- return false; +- +- if (he_cap_ie_elem->phy_cap_info[6] & +- IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { +- if (len < needed + 1) +- return false; +- needed += ieee80211_he_ppe_size(data[needed], +- he_cap_ie_elem->phy_cap_info); +- } +- +- return len >= needed; +-} +- +-/* HE Operation defines */ +-#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK 0x00000007 +-#define IEEE80211_HE_OPERATION_TWT_REQUIRED 0x00000008 +-#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK 0x00003ff0 +-#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET 4 +-#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00004000 +-#define IEEE80211_HE_OPERATION_CO_HOSTED_BSS 0x00008000 +-#define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000 +-#define IEEE80211_HE_OPERATION_6GHZ_OP_INFO 0x00020000 +-#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000 +-#define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24 +-#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000 +-#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000 +- +-#define IEEE80211_6GHZ_CTRL_REG_LPI_AP 0 +-#define IEEE80211_6GHZ_CTRL_REG_SP_AP 1 +-#define IEEE80211_6GHZ_CTRL_REG_VLP_AP 2 +-#define IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP 3 +-#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD 4 +-#define IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP 8 +- +-/** +- * struct ieee80211_he_6ghz_oper - HE 6 GHz operation Information field +- * @primary: primary channel +- * @control: control flags +- * @ccfs0: channel center frequency segment 0 +- * @ccfs1: channel center frequency segment 1 +- * @minrate: minimum rate (in 1 Mbps units) +- */ +-struct ieee80211_he_6ghz_oper { +- u8 primary; +-#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH 0x3 +-#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ 0 +-#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ 1 +-#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ 2 +-#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ 3 +-#define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4 +-#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x78 +- u8 control; +- u8 ccfs0; +- u8 ccfs1; +- u8 minrate; +-} __packed; +- +-/** +- * enum ieee80211_reg_conn_bits - represents Regulatory connectivity field bits. +- * +- * This enumeration defines bit flags used to represent regulatory connectivity +- * field bits. +- * +- * @IEEE80211_REG_CONN_LPI_VALID: Indicates whether the LPI bit is valid. +- * @IEEE80211_REG_CONN_LPI_VALUE: Represents the value of the LPI bit. +- * @IEEE80211_REG_CONN_SP_VALID: Indicates whether the SP bit is valid. +- * @IEEE80211_REG_CONN_SP_VALUE: Represents the value of the SP bit. +- */ +-enum ieee80211_reg_conn_bits { +- IEEE80211_REG_CONN_LPI_VALID = BIT(0), +- IEEE80211_REG_CONN_LPI_VALUE = BIT(1), +- IEEE80211_REG_CONN_SP_VALID = BIT(2), +- IEEE80211_REG_CONN_SP_VALUE = BIT(3), +-}; +- +-/* transmit power interpretation type of transmit power envelope element */ +-enum ieee80211_tx_power_intrpt_type { +- IEEE80211_TPE_LOCAL_EIRP, +- IEEE80211_TPE_LOCAL_EIRP_PSD, +- IEEE80211_TPE_REG_CLIENT_EIRP, +- IEEE80211_TPE_REG_CLIENT_EIRP_PSD, +-}; +- +-/* category type of transmit power envelope element */ +-enum ieee80211_tx_power_category_6ghz { +- IEEE80211_TPE_CAT_6GHZ_DEFAULT = 0, +- IEEE80211_TPE_CAT_6GHZ_SUBORDINATE = 1, +-}; +- +-/* +- * For IEEE80211_TPE_LOCAL_EIRP / IEEE80211_TPE_REG_CLIENT_EIRP, +- * setting to 63.5 dBm means no constraint. +- */ +-#define IEEE80211_TPE_MAX_TX_PWR_NO_CONSTRAINT 127 +- +-/* +- * For IEEE80211_TPE_LOCAL_EIRP_PSD / IEEE80211_TPE_REG_CLIENT_EIRP_PSD, +- * setting to 127 indicates no PSD limit for the 20 MHz channel. +- */ +-#define IEEE80211_TPE_PSD_NO_LIMIT 127 +- +-/** +- * struct ieee80211_tx_pwr_env - Transmit Power Envelope +- * @info: Transmit Power Information field +- * @variable: Maximum Transmit Power field +- * +- * This structure represents the payload of the "Transmit Power +- * Envelope element" as described in IEEE Std 802.11ax-2021 section +- * 9.4.2.161 +- */ +-struct ieee80211_tx_pwr_env { +- u8 info; +- u8 variable[]; +-} __packed; +- +-#define IEEE80211_TX_PWR_ENV_INFO_COUNT 0x7 +-#define IEEE80211_TX_PWR_ENV_INFO_INTERPRET 0x38 +-#define IEEE80211_TX_PWR_ENV_INFO_CATEGORY 0xC0 +- +-#define IEEE80211_TX_PWR_ENV_EXT_COUNT 0xF +- +-static inline bool ieee80211_valid_tpe_element(const u8 *data, u8 len) +-{ +- const struct ieee80211_tx_pwr_env *env = (const void *)data; +- u8 count, interpret, category; +- u8 needed = sizeof(*env); +- u8 N; /* also called N in the spec */ +- +- if (len < needed) +- return false; +- +- count = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_COUNT); +- interpret = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_INTERPRET); +- category = u8_get_bits(env->info, IEEE80211_TX_PWR_ENV_INFO_CATEGORY); +- +- switch (category) { +- case IEEE80211_TPE_CAT_6GHZ_DEFAULT: +- case IEEE80211_TPE_CAT_6GHZ_SUBORDINATE: +- break; +- default: +- return false; +- } +- +- switch (interpret) { +- case IEEE80211_TPE_LOCAL_EIRP: +- case IEEE80211_TPE_REG_CLIENT_EIRP: +- if (count > 3) +- return false; +- +- /* count == 0 encodes 1 value for 20 MHz, etc. */ +- needed += count + 1; +- +- if (len < needed) +- return false; +- +- /* there can be extension fields not accounted for in 'count' */ +- +- return true; +- case IEEE80211_TPE_LOCAL_EIRP_PSD: +- case IEEE80211_TPE_REG_CLIENT_EIRP_PSD: +- if (count > 4) +- return false; +- +- N = count ? 1 << (count - 1) : 1; +- needed += N; +- +- if (len < needed) +- return false; +- +- if (len > needed) { +- u8 K = u8_get_bits(env->variable[N], +- IEEE80211_TX_PWR_ENV_EXT_COUNT); +- +- needed += 1 + K; +- if (len < needed) +- return false; +- } +- +- return true; +- } +- +- return false; +-} +- +-/* +- * ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size +- * @he_oper_ie: byte data of the He Operations IE, stating from the byte +- * after the ext ID byte. It is assumed that he_oper_ie has at least +- * sizeof(struct ieee80211_he_operation) bytes, the caller must have +- * validated this. +- * @return the actual size of the IE data (not including header), or 0 on error +- */ +-static inline u8 +-ieee80211_he_oper_size(const u8 *he_oper_ie) +-{ +- const struct ieee80211_he_operation *he_oper = (const void *)he_oper_ie; +- u8 oper_len = sizeof(struct ieee80211_he_operation); +- u32 he_oper_params; +- +- /* Make sure the input is not NULL */ +- if (!he_oper_ie) +- return 0; +- +- /* Calc required length */ +- he_oper_params = le32_to_cpu(he_oper->he_oper_params); +- if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO) +- oper_len += 3; +- if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS) +- oper_len++; +- if (he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO) +- oper_len += sizeof(struct ieee80211_he_6ghz_oper); +- +- /* Add the first byte (extension ID) to the total length */ +- oper_len++; +- +- return oper_len; +-} +- +-/** +- * ieee80211_he_6ghz_oper - obtain 6 GHz operation field +- * @he_oper: HE operation element (must be pre-validated for size) +- * but may be %NULL +- * +- * Return: a pointer to the 6 GHz operation field, or %NULL +- */ +-static inline const struct ieee80211_he_6ghz_oper * +-ieee80211_he_6ghz_oper(const struct ieee80211_he_operation *he_oper) +-{ +- const u8 *ret; +- u32 he_oper_params; +- +- if (!he_oper) +- return NULL; +- +- ret = (const void *)&he_oper->optional; +- +- he_oper_params = le32_to_cpu(he_oper->he_oper_params); +- +- if (!(he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO)) +- return NULL; +- if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO) +- ret += 3; +- if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS) +- ret++; +- +- return (const void *)ret; +-} +- +-/* HE Spatial Reuse defines */ +-#define IEEE80211_HE_SPR_PSR_DISALLOWED BIT(0) +-#define IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1) +-#define IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT BIT(2) +-#define IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT BIT(3) +-#define IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED BIT(4) +- +-/* +- * ieee80211_he_spr_size - calculate 802.11ax HE Spatial Reuse IE size +- * @he_spr_ie: byte data of the He Spatial Reuse IE, stating from the byte +- * after the ext ID byte. It is assumed that he_spr_ie has at least +- * sizeof(struct ieee80211_he_spr) bytes, the caller must have validated +- * this +- * @return the actual size of the IE data (not including header), or 0 on error +- */ +-static inline u8 +-ieee80211_he_spr_size(const u8 *he_spr_ie) +-{ +- const struct ieee80211_he_spr *he_spr = (const void *)he_spr_ie; +- u8 spr_len = sizeof(struct ieee80211_he_spr); +- u8 he_spr_params; +- +- /* Make sure the input is not NULL */ +- if (!he_spr_ie) +- return 0; +- +- /* Calc required length */ +- he_spr_params = he_spr->he_sr_control; +- if (he_spr_params & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT) +- spr_len++; +- if (he_spr_params & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) +- spr_len += 18; +- +- /* Add the first byte (extension ID) to the total length */ +- spr_len++; +- +- return spr_len; +-} +- + /* S1G Capabilities Information field */ + #define IEEE80211_S1G_CAPABILITY_LEN 15 + +@@ -2697,6 +1912,9 @@ ieee80211_he_spr_size(const u8 *he_spr_ie) + #define IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ 3 + #define IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ 4 + ++/* need HE definitions for EHT functions */ ++#include "ieee80211-he.h" ++ + /* Calculate 802.11be EHT capabilities IE Tx/Rx EHT MCS NSS Support Field size */ + static inline u8 + ieee80211_eht_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap, +@@ -3815,24 +3033,6 @@ struct ieee80211_tspec_ie { + __le16 medium_time; + } __packed; + +-struct ieee80211_he_6ghz_capa { +- /* uses IEEE80211_HE_6GHZ_CAP_* below */ +- __le16 capa; +-} __packed; +- +-/* HE 6 GHz band capabilities */ +-/* uses enum ieee80211_min_mpdu_spacing values */ +-#define IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START 0x0007 +-/* uses enum ieee80211_vht_max_ampdu_length_exp values */ +-#define IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP 0x0038 +-/* uses IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_* values */ +-#define IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN 0x00c0 +-/* WLAN_HT_CAP_SM_PS_* values */ +-#define IEEE80211_HE_6GHZ_CAP_SM_PS 0x0600 +-#define IEEE80211_HE_6GHZ_CAP_RD_RESPONDER 0x0800 +-#define IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS 0x1000 +-#define IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS 0x2000 +- + /** + * ieee80211_get_qos_ctl - get pointer to qos control bytes + * @hdr: the frame +-- +2.53.0 + diff --git a/queue-6.18/wifi-ieee80211-split-ht-definitions-out.patch b/queue-6.18/wifi-ieee80211-split-ht-definitions-out.patch new file mode 100644 index 0000000000..5087800339 --- /dev/null +++ b/queue-6.18/wifi-ieee80211-split-ht-definitions-out.patch @@ -0,0 +1,655 @@ +From c5f29d28549aa127f4631bedb2a69dadccb79e57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 15:36:50 +0100 +Subject: wifi: ieee80211: split HT definitions out + +From: Johannes Berg + +[ Upstream commit fdc1c141f3ef4dc94e3880e973061681843f62c0 ] + +The ieee80211.h file has gotten very long, continue splitting +it by putting HT definitions into a separate file. + +Link: https://patch.msgid.link/20251105153843.7532471178d0.Id956a5433ad8658e4e5c0272dbcbb59587206142@changeid +Signed-off-by: Johannes Berg +Stable-dep-of: cb0caadb64ca ("wifi: ieee80211: fix definition of EHT-MCS 15 in MRU") +Signed-off-by: Sasha Levin +--- + include/linux/ieee80211-ht.h | 292 +++++++++++++++++++++++++++++++++++ + include/linux/ieee80211.h | 272 +------------------------------- + 2 files changed, 293 insertions(+), 271 deletions(-) + create mode 100644 include/linux/ieee80211-ht.h + +diff --git a/include/linux/ieee80211-ht.h b/include/linux/ieee80211-ht.h +new file mode 100644 +index 0000000000000..21bbf470540f6 +--- /dev/null ++++ b/include/linux/ieee80211-ht.h +@@ -0,0 +1,292 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * IEEE 802.11 HT definitions ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Copyright (c) 2005, Devicescape Software, Inc. ++ * Copyright (c) 2006, Michael Wu ++ * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH ++ * Copyright (c) 2016 - 2017 Intel Deutschland GmbH ++ * Copyright (c) 2018 - 2025 Intel Corporation ++ */ ++ ++#ifndef LINUX_IEEE80211_HT_H ++#define LINUX_IEEE80211_HT_H ++ ++#include ++#include ++ ++/* Maximal size of an A-MSDU that can be transported in a HT BA session */ ++#define IEEE80211_MAX_MPDU_LEN_HT_BA 4095 ++ ++/* Maximal size of an A-MSDU */ ++#define IEEE80211_MAX_MPDU_LEN_HT_3839 3839 ++#define IEEE80211_MAX_MPDU_LEN_HT_7935 7935 ++ ++#define IEEE80211_HT_CTL_LEN 4 ++ ++enum ieee80211_ht_chanwidth_values { ++ IEEE80211_HT_CHANWIDTH_20MHZ = 0, ++ IEEE80211_HT_CHANWIDTH_ANY = 1, ++}; ++ ++/** ++ * struct ieee80211_bar - Block Ack Request frame format ++ * @frame_control: Frame Control ++ * @duration: Duration ++ * @ra: RA ++ * @ta: TA ++ * @control: BAR Control ++ * @start_seq_num: Starting Sequence Number (see Figure 9-37) ++ * ++ * This structure represents the "BlockAckReq frame format" ++ * as described in IEEE Std 802.11-2020 section 9.3.1.7. ++*/ ++struct ieee80211_bar { ++ __le16 frame_control; ++ __le16 duration; ++ __u8 ra[ETH_ALEN]; ++ __u8 ta[ETH_ALEN]; ++ __le16 control; ++ __le16 start_seq_num; ++} __packed; ++ ++/* 802.11 BAR control masks */ ++#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 ++#define IEEE80211_BAR_CTRL_MULTI_TID 0x0002 ++#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004 ++#define IEEE80211_BAR_CTRL_TID_INFO_MASK 0xf000 ++#define IEEE80211_BAR_CTRL_TID_INFO_SHIFT 12 ++ ++#define IEEE80211_HT_MCS_MASK_LEN 10 ++ ++/** ++ * struct ieee80211_mcs_info - Supported MCS Set field ++ * @rx_mask: RX mask ++ * @rx_highest: highest supported RX rate. If set represents ++ * the highest supported RX data rate in units of 1 Mbps. ++ * If this field is 0 this value should not be used to ++ * consider the highest RX data rate supported. ++ * @tx_params: TX parameters ++ * @reserved: Reserved bits ++ * ++ * This structure represents the "Supported MCS Set field" as ++ * described in IEEE Std 802.11-2020 section 9.4.2.55.4. ++ */ ++struct ieee80211_mcs_info { ++ u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN]; ++ __le16 rx_highest; ++ u8 tx_params; ++ u8 reserved[3]; ++} __packed; ++ ++/* 802.11n HT capability MSC set */ ++#define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff ++#define IEEE80211_HT_MCS_TX_DEFINED 0x01 ++#define IEEE80211_HT_MCS_TX_RX_DIFF 0x02 ++/* value 0 == 1 stream etc */ ++#define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK 0x0C ++#define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT 2 ++#define IEEE80211_HT_MCS_TX_MAX_STREAMS 4 ++#define IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION 0x10 ++ ++#define IEEE80211_HT_MCS_CHAINS(mcs) ((mcs) == 32 ? 1 : (1 + ((mcs) >> 3))) ++ ++/* ++ * 802.11n D5.0 20.3.5 / 20.6 says: ++ * - indices 0 to 7 and 32 are single spatial stream ++ * - 8 to 31 are multiple spatial streams using equal modulation ++ * [8..15 for two streams, 16..23 for three and 24..31 for four] ++ * - remainder are multiple spatial streams using unequal modulation ++ */ ++#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START 33 ++#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE \ ++ (IEEE80211_HT_MCS_UNEQUAL_MODULATION_START / 8) ++ ++/** ++ * struct ieee80211_ht_cap - HT capabilities element ++ * @cap_info: HT Capability Information ++ * @ampdu_params_info: A-MPDU Parameters ++ * @mcs: Supported MCS Set ++ * @extended_ht_cap_info: HT Extended Capabilities ++ * @tx_BF_cap_info: Transmit Beamforming Capabilities ++ * @antenna_selection_info: ASEL Capability ++ * ++ * This structure represents the payload of the "HT Capabilities ++ * element" as described in IEEE Std 802.11-2020 section 9.4.2.55. ++ */ ++struct ieee80211_ht_cap { ++ __le16 cap_info; ++ u8 ampdu_params_info; ++ ++ /* 16 bytes MCS information */ ++ struct ieee80211_mcs_info mcs; ++ ++ __le16 extended_ht_cap_info; ++ __le32 tx_BF_cap_info; ++ u8 antenna_selection_info; ++} __packed; ++ ++/* 802.11n HT capabilities masks (for cap_info) */ ++#define IEEE80211_HT_CAP_LDPC_CODING 0x0001 ++#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002 ++#define IEEE80211_HT_CAP_SM_PS 0x000C ++#define IEEE80211_HT_CAP_SM_PS_SHIFT 2 ++#define IEEE80211_HT_CAP_GRN_FLD 0x0010 ++#define IEEE80211_HT_CAP_SGI_20 0x0020 ++#define IEEE80211_HT_CAP_SGI_40 0x0040 ++#define IEEE80211_HT_CAP_TX_STBC 0x0080 ++#define IEEE80211_HT_CAP_RX_STBC 0x0300 ++#define IEEE80211_HT_CAP_RX_STBC_SHIFT 8 ++#define IEEE80211_HT_CAP_DELAY_BA 0x0400 ++#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 ++#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 ++#define IEEE80211_HT_CAP_RESERVED 0x2000 ++#define IEEE80211_HT_CAP_40MHZ_INTOLERANT 0x4000 ++#define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 ++ ++/* 802.11n HT extended capabilities masks (for extended_ht_cap_info) */ ++#define IEEE80211_HT_EXT_CAP_PCO 0x0001 ++#define IEEE80211_HT_EXT_CAP_PCO_TIME 0x0006 ++#define IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT 1 ++#define IEEE80211_HT_EXT_CAP_MCS_FB 0x0300 ++#define IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT 8 ++#define IEEE80211_HT_EXT_CAP_HTC_SUP 0x0400 ++#define IEEE80211_HT_EXT_CAP_RD_RESPONDER 0x0800 ++ ++/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ ++#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 ++#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C ++#define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2 ++ ++/* ++ * Maximum length of AMPDU that the STA can receive in high-throughput (HT). ++ * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) ++ */ ++enum ieee80211_max_ampdu_length_exp { ++ IEEE80211_HT_MAX_AMPDU_8K = 0, ++ IEEE80211_HT_MAX_AMPDU_16K = 1, ++ IEEE80211_HT_MAX_AMPDU_32K = 2, ++ IEEE80211_HT_MAX_AMPDU_64K = 3 ++}; ++ ++#define IEEE80211_HT_MAX_AMPDU_FACTOR 13 ++ ++/* Minimum MPDU start spacing */ ++enum ieee80211_min_mpdu_spacing { ++ IEEE80211_HT_MPDU_DENSITY_NONE = 0, /* No restriction */ ++ IEEE80211_HT_MPDU_DENSITY_0_25 = 1, /* 1/4 usec */ ++ IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 usec */ ++ IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 usec */ ++ IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 usec */ ++ IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4 usec */ ++ IEEE80211_HT_MPDU_DENSITY_8 = 6, /* 8 usec */ ++ IEEE80211_HT_MPDU_DENSITY_16 = 7 /* 16 usec */ ++}; ++ ++/** ++ * struct ieee80211_ht_operation - HT operation IE ++ * @primary_chan: Primary Channel ++ * @ht_param: HT Operation Information parameters ++ * @operation_mode: HT Operation Information operation mode ++ * @stbc_param: HT Operation Information STBC params ++ * @basic_set: Basic HT-MCS Set ++ * ++ * This structure represents the payload of the "HT Operation ++ * element" as described in IEEE Std 802.11-2020 section 9.4.2.56. ++ */ ++struct ieee80211_ht_operation { ++ u8 primary_chan; ++ u8 ht_param; ++ __le16 operation_mode; ++ __le16 stbc_param; ++ u8 basic_set[16]; ++} __packed; ++ ++/* for ht_param */ ++#define IEEE80211_HT_PARAM_CHA_SEC_OFFSET 0x03 ++#define IEEE80211_HT_PARAM_CHA_SEC_NONE 0x00 ++#define IEEE80211_HT_PARAM_CHA_SEC_ABOVE 0x01 ++#define IEEE80211_HT_PARAM_CHA_SEC_BELOW 0x03 ++#define IEEE80211_HT_PARAM_CHAN_WIDTH_ANY 0x04 ++#define IEEE80211_HT_PARAM_RIFS_MODE 0x08 ++ ++/* for operation_mode */ ++#define IEEE80211_HT_OP_MODE_PROTECTION 0x0003 ++#define IEEE80211_HT_OP_MODE_PROTECTION_NONE 0 ++#define IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER 1 ++#define IEEE80211_HT_OP_MODE_PROTECTION_20MHZ 2 ++#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3 ++#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004 ++#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010 ++#define IEEE80211_HT_OP_MODE_CCFS2_SHIFT 5 ++#define IEEE80211_HT_OP_MODE_CCFS2_MASK 0x1fe0 ++ ++/* for stbc_param */ ++#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040 ++#define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT 0x0080 ++#define IEEE80211_HT_STBC_PARAM_STBC_BEACON 0x0100 ++#define IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT 0x0200 ++#define IEEE80211_HT_STBC_PARAM_PCO_ACTIVE 0x0400 ++#define IEEE80211_HT_STBC_PARAM_PCO_PHASE 0x0800 ++ ++ ++/* block-ack parameters */ ++#define IEEE80211_ADDBA_PARAM_AMSDU_MASK 0x0001 ++#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 ++#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C ++#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0 ++#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 ++#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 ++ ++/* ++ * A-MPDU buffer sizes ++ * According to HT size varies from 8 to 64 frames ++ * HE adds the ability to have up to 256 frames. ++ * EHT adds the ability to have up to 1K frames. ++ */ ++#define IEEE80211_MIN_AMPDU_BUF 0x8 ++#define IEEE80211_MAX_AMPDU_BUF_HT 0x40 ++#define IEEE80211_MAX_AMPDU_BUF_HE 0x100 ++#define IEEE80211_MAX_AMPDU_BUF_EHT 0x400 ++ ++ ++/* Spatial Multiplexing Power Save Modes (for capability) */ ++#define WLAN_HT_CAP_SM_PS_STATIC 0 ++#define WLAN_HT_CAP_SM_PS_DYNAMIC 1 ++#define WLAN_HT_CAP_SM_PS_INVALID 2 ++#define WLAN_HT_CAP_SM_PS_DISABLED 3 ++ ++/* for SM power control field lower two bits */ ++#define WLAN_HT_SMPS_CONTROL_DISABLED 0 ++#define WLAN_HT_SMPS_CONTROL_STATIC 1 ++#define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 ++ ++/* HT action codes */ ++enum ieee80211_ht_actioncode { ++ WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0, ++ WLAN_HT_ACTION_SMPS = 1, ++ WLAN_HT_ACTION_PSMP = 2, ++ WLAN_HT_ACTION_PCO_PHASE = 3, ++ WLAN_HT_ACTION_CSI = 4, ++ WLAN_HT_ACTION_NONCOMPRESSED_BF = 5, ++ WLAN_HT_ACTION_COMPRESSED_BF = 6, ++ WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, ++}; ++ ++/* BACK action code */ ++enum ieee80211_back_actioncode { ++ WLAN_ACTION_ADDBA_REQ = 0, ++ WLAN_ACTION_ADDBA_RESP = 1, ++ WLAN_ACTION_DELBA = 2, ++}; ++ ++/* BACK (block-ack) parties */ ++enum ieee80211_back_parties { ++ WLAN_BACK_RECIPIENT = 0, ++ WLAN_BACK_INITIATOR = 1, ++}; ++ ++#endif /* LINUX_IEEE80211_HT_H */ +diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h +index ebc12d1939273..f0a7899fb6626 100644 +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -239,13 +239,6 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) + /* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ + #define IEEE80211_MAX_FRAME_LEN 2352 + +-/* Maximal size of an A-MSDU that can be transported in a HT BA session */ +-#define IEEE80211_MAX_MPDU_LEN_HT_BA 4095 +- +-/* Maximal size of an A-MSDU */ +-#define IEEE80211_MAX_MPDU_LEN_HT_3839 3839 +-#define IEEE80211_MAX_MPDU_LEN_HT_7935 7935 +- + #define IEEE80211_MAX_MPDU_LEN_VHT_3895 3895 + #define IEEE80211_MAX_MPDU_LEN_VHT_7991 7991 + #define IEEE80211_MAX_MPDU_LEN_VHT_11454 11454 +@@ -302,8 +295,6 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) + #define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x03 + #define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT 5 + +-#define IEEE80211_HT_CTL_LEN 4 +- + /* trigger type within common_info of trigger frame */ + #define IEEE80211_TRIGGER_TYPE_MASK 0xf + #define IEEE80211_TRIGGER_TYPE_BASIC 0x0 +@@ -997,11 +988,6 @@ struct ieee80211_tim_ie { + }; + } __packed; + +-enum ieee80211_ht_chanwidth_values { +- IEEE80211_HT_CHANWIDTH_20MHZ = 0, +- IEEE80211_HT_CHANWIDTH_ANY = 1, +-}; +- + /** + * enum ieee80211_vht_opmode_bits - VHT operating mode field bits + * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK: channel width mask +@@ -1677,146 +1663,6 @@ struct ieee80211_p2p_noa_attr { + #define IEEE80211_P2P_OPPPS_ENABLE_BIT BIT(7) + #define IEEE80211_P2P_OPPPS_CTWINDOW_MASK 0x7F + +-/** +- * struct ieee80211_bar - Block Ack Request frame format +- * @frame_control: Frame Control +- * @duration: Duration +- * @ra: RA +- * @ta: TA +- * @control: BAR Control +- * @start_seq_num: Starting Sequence Number (see Figure 9-37) +- * +- * This structure represents the "BlockAckReq frame format" +- * as described in IEEE Std 802.11-2020 section 9.3.1.7. +-*/ +-struct ieee80211_bar { +- __le16 frame_control; +- __le16 duration; +- __u8 ra[ETH_ALEN]; +- __u8 ta[ETH_ALEN]; +- __le16 control; +- __le16 start_seq_num; +-} __packed; +- +-/* 802.11 BAR control masks */ +-#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 +-#define IEEE80211_BAR_CTRL_MULTI_TID 0x0002 +-#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004 +-#define IEEE80211_BAR_CTRL_TID_INFO_MASK 0xf000 +-#define IEEE80211_BAR_CTRL_TID_INFO_SHIFT 12 +- +-#define IEEE80211_HT_MCS_MASK_LEN 10 +- +-/** +- * struct ieee80211_mcs_info - Supported MCS Set field +- * @rx_mask: RX mask +- * @rx_highest: highest supported RX rate. If set represents +- * the highest supported RX data rate in units of 1 Mbps. +- * If this field is 0 this value should not be used to +- * consider the highest RX data rate supported. +- * @tx_params: TX parameters +- * @reserved: Reserved bits +- * +- * This structure represents the "Supported MCS Set field" as +- * described in IEEE Std 802.11-2020 section 9.4.2.55.4. +- */ +-struct ieee80211_mcs_info { +- u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN]; +- __le16 rx_highest; +- u8 tx_params; +- u8 reserved[3]; +-} __packed; +- +-/* 802.11n HT capability MSC set */ +-#define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff +-#define IEEE80211_HT_MCS_TX_DEFINED 0x01 +-#define IEEE80211_HT_MCS_TX_RX_DIFF 0x02 +-/* value 0 == 1 stream etc */ +-#define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK 0x0C +-#define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT 2 +-#define IEEE80211_HT_MCS_TX_MAX_STREAMS 4 +-#define IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION 0x10 +- +-#define IEEE80211_HT_MCS_CHAINS(mcs) ((mcs) == 32 ? 1 : (1 + ((mcs) >> 3))) +- +-/* +- * 802.11n D5.0 20.3.5 / 20.6 says: +- * - indices 0 to 7 and 32 are single spatial stream +- * - 8 to 31 are multiple spatial streams using equal modulation +- * [8..15 for two streams, 16..23 for three and 24..31 for four] +- * - remainder are multiple spatial streams using unequal modulation +- */ +-#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START 33 +-#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE \ +- (IEEE80211_HT_MCS_UNEQUAL_MODULATION_START / 8) +- +-/** +- * struct ieee80211_ht_cap - HT capabilities element +- * @cap_info: HT Capability Information +- * @ampdu_params_info: A-MPDU Parameters +- * @mcs: Supported MCS Set +- * @extended_ht_cap_info: HT Extended Capabilities +- * @tx_BF_cap_info: Transmit Beamforming Capabilities +- * @antenna_selection_info: ASEL Capability +- * +- * This structure represents the payload of the "HT Capabilities +- * element" as described in IEEE Std 802.11-2020 section 9.4.2.55. +- */ +-struct ieee80211_ht_cap { +- __le16 cap_info; +- u8 ampdu_params_info; +- +- /* 16 bytes MCS information */ +- struct ieee80211_mcs_info mcs; +- +- __le16 extended_ht_cap_info; +- __le32 tx_BF_cap_info; +- u8 antenna_selection_info; +-} __packed; +- +-/* 802.11n HT capabilities masks (for cap_info) */ +-#define IEEE80211_HT_CAP_LDPC_CODING 0x0001 +-#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002 +-#define IEEE80211_HT_CAP_SM_PS 0x000C +-#define IEEE80211_HT_CAP_SM_PS_SHIFT 2 +-#define IEEE80211_HT_CAP_GRN_FLD 0x0010 +-#define IEEE80211_HT_CAP_SGI_20 0x0020 +-#define IEEE80211_HT_CAP_SGI_40 0x0040 +-#define IEEE80211_HT_CAP_TX_STBC 0x0080 +-#define IEEE80211_HT_CAP_RX_STBC 0x0300 +-#define IEEE80211_HT_CAP_RX_STBC_SHIFT 8 +-#define IEEE80211_HT_CAP_DELAY_BA 0x0400 +-#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +-#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 +-#define IEEE80211_HT_CAP_RESERVED 0x2000 +-#define IEEE80211_HT_CAP_40MHZ_INTOLERANT 0x4000 +-#define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 +- +-/* 802.11n HT extended capabilities masks (for extended_ht_cap_info) */ +-#define IEEE80211_HT_EXT_CAP_PCO 0x0001 +-#define IEEE80211_HT_EXT_CAP_PCO_TIME 0x0006 +-#define IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT 1 +-#define IEEE80211_HT_EXT_CAP_MCS_FB 0x0300 +-#define IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT 8 +-#define IEEE80211_HT_EXT_CAP_HTC_SUP 0x0400 +-#define IEEE80211_HT_EXT_CAP_RD_RESPONDER 0x0800 +- +-/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ +-#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 +-#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C +-#define IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT 2 +- +-/* +- * Maximum length of AMPDU that the STA can receive in high-throughput (HT). +- * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) +- */ +-enum ieee80211_max_ampdu_length_exp { +- IEEE80211_HT_MAX_AMPDU_8K = 0, +- IEEE80211_HT_MAX_AMPDU_16K = 1, +- IEEE80211_HT_MAX_AMPDU_32K = 2, +- IEEE80211_HT_MAX_AMPDU_64K = 3 +-}; +- + /* + * Maximum length of AMPDU that the STA can receive in VHT. + * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) +@@ -1832,98 +1678,6 @@ enum ieee80211_vht_max_ampdu_length_exp { + IEEE80211_VHT_MAX_AMPDU_1024K = 7 + }; + +-#define IEEE80211_HT_MAX_AMPDU_FACTOR 13 +- +-/* Minimum MPDU start spacing */ +-enum ieee80211_min_mpdu_spacing { +- IEEE80211_HT_MPDU_DENSITY_NONE = 0, /* No restriction */ +- IEEE80211_HT_MPDU_DENSITY_0_25 = 1, /* 1/4 usec */ +- IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 usec */ +- IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 usec */ +- IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 usec */ +- IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4 usec */ +- IEEE80211_HT_MPDU_DENSITY_8 = 6, /* 8 usec */ +- IEEE80211_HT_MPDU_DENSITY_16 = 7 /* 16 usec */ +-}; +- +-/** +- * struct ieee80211_ht_operation - HT operation IE +- * @primary_chan: Primary Channel +- * @ht_param: HT Operation Information parameters +- * @operation_mode: HT Operation Information operation mode +- * @stbc_param: HT Operation Information STBC params +- * @basic_set: Basic HT-MCS Set +- * +- * This structure represents the payload of the "HT Operation +- * element" as described in IEEE Std 802.11-2020 section 9.4.2.56. +- */ +-struct ieee80211_ht_operation { +- u8 primary_chan; +- u8 ht_param; +- __le16 operation_mode; +- __le16 stbc_param; +- u8 basic_set[16]; +-} __packed; +- +-/* for ht_param */ +-#define IEEE80211_HT_PARAM_CHA_SEC_OFFSET 0x03 +-#define IEEE80211_HT_PARAM_CHA_SEC_NONE 0x00 +-#define IEEE80211_HT_PARAM_CHA_SEC_ABOVE 0x01 +-#define IEEE80211_HT_PARAM_CHA_SEC_BELOW 0x03 +-#define IEEE80211_HT_PARAM_CHAN_WIDTH_ANY 0x04 +-#define IEEE80211_HT_PARAM_RIFS_MODE 0x08 +- +-/* for operation_mode */ +-#define IEEE80211_HT_OP_MODE_PROTECTION 0x0003 +-#define IEEE80211_HT_OP_MODE_PROTECTION_NONE 0 +-#define IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER 1 +-#define IEEE80211_HT_OP_MODE_PROTECTION_20MHZ 2 +-#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3 +-#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004 +-#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010 +-#define IEEE80211_HT_OP_MODE_CCFS2_SHIFT 5 +-#define IEEE80211_HT_OP_MODE_CCFS2_MASK 0x1fe0 +- +-/* for stbc_param */ +-#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040 +-#define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT 0x0080 +-#define IEEE80211_HT_STBC_PARAM_STBC_BEACON 0x0100 +-#define IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT 0x0200 +-#define IEEE80211_HT_STBC_PARAM_PCO_ACTIVE 0x0400 +-#define IEEE80211_HT_STBC_PARAM_PCO_PHASE 0x0800 +- +- +-/* block-ack parameters */ +-#define IEEE80211_ADDBA_PARAM_AMSDU_MASK 0x0001 +-#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 +-#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C +-#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0 +-#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 +-#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 +- +-/* +- * A-MPDU buffer sizes +- * According to HT size varies from 8 to 64 frames +- * HE adds the ability to have up to 256 frames. +- * EHT adds the ability to have up to 1K frames. +- */ +-#define IEEE80211_MIN_AMPDU_BUF 0x8 +-#define IEEE80211_MAX_AMPDU_BUF_HT 0x40 +-#define IEEE80211_MAX_AMPDU_BUF_HE 0x100 +-#define IEEE80211_MAX_AMPDU_BUF_EHT 0x400 +- +- +-/* Spatial Multiplexing Power Save Modes (for capability) */ +-#define WLAN_HT_CAP_SM_PS_STATIC 0 +-#define WLAN_HT_CAP_SM_PS_DYNAMIC 1 +-#define WLAN_HT_CAP_SM_PS_INVALID 2 +-#define WLAN_HT_CAP_SM_PS_DISABLED 3 +- +-/* for SM power control field lower two bits */ +-#define WLAN_HT_SMPS_CONTROL_DISABLED 0 +-#define WLAN_HT_SMPS_CONTROL_STATIC 1 +-#define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 +- + /** + * struct ieee80211_vht_mcs_info - VHT MCS information + * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams +@@ -3807,18 +3561,6 @@ enum ieee80211_spectrum_mgmt_actioncode { + WLAN_ACTION_SPCT_CHL_SWITCH = 4, + }; + +-/* HT action codes */ +-enum ieee80211_ht_actioncode { +- WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0, +- WLAN_HT_ACTION_SMPS = 1, +- WLAN_HT_ACTION_PSMP = 2, +- WLAN_HT_ACTION_PCO_PHASE = 3, +- WLAN_HT_ACTION_CSI = 4, +- WLAN_HT_ACTION_NONCOMPRESSED_BF = 5, +- WLAN_HT_ACTION_COMPRESSED_BF = 6, +- WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7, +-}; +- + /* VHT action codes */ + enum ieee80211_vht_actioncode { + WLAN_VHT_ACTION_COMPRESSED_BF = 0, +@@ -4155,19 +3897,6 @@ struct ieee80211_bss_max_idle_period_ie { + u8 idle_options; + } __packed; + +-/* BACK action code */ +-enum ieee80211_back_actioncode { +- WLAN_ACTION_ADDBA_REQ = 0, +- WLAN_ACTION_ADDBA_RESP = 1, +- WLAN_ACTION_DELBA = 2, +-}; +- +-/* BACK (block-ack) parties */ +-enum ieee80211_back_parties { +- WLAN_BACK_RECIPIENT = 0, +- WLAN_BACK_INITIATOR = 1, +-}; +- + /* SA Query action */ + enum ieee80211_sa_query_action { + WLAN_ACTION_SA_QUERY_REQUEST = 0, +@@ -5889,6 +5618,7 @@ static inline u32 ieee80211_eml_trans_timeout_in_us(u16 eml_cap) + #define NAN_DEV_CAPA_NDPE_SUPPORTED 0x08 + #define NAN_DEV_CAPA_S3_SUPPORTED 0x10 + ++#include "ieee80211-ht.h" + #include "ieee80211-mesh.h" + + #endif /* LINUX_IEEE80211_H */ +-- +2.53.0 + diff --git a/queue-6.18/wifi-ieee80211-split-mesh-definitions-out.patch b/queue-6.18/wifi-ieee80211-split-mesh-definitions-out.patch new file mode 100644 index 0000000000..7c35bea98e --- /dev/null +++ b/queue-6.18/wifi-ieee80211-split-mesh-definitions-out.patch @@ -0,0 +1,523 @@ +From 7e8ed175f11622b3aa79833c9dd748d4f9662e95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 15:36:49 +0100 +Subject: wifi: ieee80211: split mesh definitions out + +From: Johannes Berg + +[ Upstream commit 69674282fc97fffd98a85ab5b4837edbc5898145 ] + +The ieee80211.h file has gotten very long, start splitting it +by putting mesh definitions into a separate file. + +Link: https://patch.msgid.link/20251105153843.489713ca8b34.I3befb4bf6ace0315758a1794224ddd18c4652e32@changeid +Signed-off-by: Johannes Berg +Stable-dep-of: cb0caadb64ca ("wifi: ieee80211: fix definition of EHT-MCS 15 in MRU") +Signed-off-by: Sasha Levin +--- + include/linux/ieee80211-mesh.h | 230 +++++++++++++++++++++++++++++++++ + include/linux/ieee80211.h | 211 +----------------------------- + 2 files changed, 232 insertions(+), 209 deletions(-) + create mode 100644 include/linux/ieee80211-mesh.h + +diff --git a/include/linux/ieee80211-mesh.h b/include/linux/ieee80211-mesh.h +new file mode 100644 +index 0000000000000..4b829bcb38b61 +--- /dev/null ++++ b/include/linux/ieee80211-mesh.h +@@ -0,0 +1,230 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * IEEE 802.11 mesh definitions ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Copyright (c) 2005, Devicescape Software, Inc. ++ * Copyright (c) 2006, Michael Wu ++ * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH ++ * Copyright (c) 2016 - 2017 Intel Deutschland GmbH ++ * Copyright (c) 2018 - 2025 Intel Corporation ++ */ ++ ++#ifndef LINUX_IEEE80211_MESH_H ++#define LINUX_IEEE80211_MESH_H ++ ++#include ++#include ++ ++#define IEEE80211_MAX_MESH_ID_LEN 32 ++ ++struct ieee80211s_hdr { ++ u8 flags; ++ u8 ttl; ++ __le32 seqnum; ++ u8 eaddr1[ETH_ALEN]; ++ u8 eaddr2[ETH_ALEN]; ++} __packed __aligned(2); ++ ++/* Mesh flags */ ++#define MESH_FLAGS_AE_A4 0x1 ++#define MESH_FLAGS_AE_A5_A6 0x2 ++#define MESH_FLAGS_AE 0x3 ++#define MESH_FLAGS_PS_DEEP 0x4 ++ ++/** ++ * enum ieee80211_preq_flags - mesh PREQ element flags ++ * ++ * @IEEE80211_PREQ_PROACTIVE_PREP_FLAG: proactive PREP subfield ++ */ ++enum ieee80211_preq_flags { ++ IEEE80211_PREQ_PROACTIVE_PREP_FLAG = 1<<2, ++}; ++ ++/** ++ * enum ieee80211_preq_target_flags - mesh PREQ element per target flags ++ * ++ * @IEEE80211_PREQ_TO_FLAG: target only subfield ++ * @IEEE80211_PREQ_USN_FLAG: unknown target HWMP sequence number subfield ++ */ ++enum ieee80211_preq_target_flags { ++ IEEE80211_PREQ_TO_FLAG = 1<<0, ++ IEEE80211_PREQ_USN_FLAG = 1<<2, ++}; ++ ++/** ++ * struct ieee80211_mesh_chansw_params_ie - mesh channel switch parameters IE ++ * @mesh_ttl: Time To Live ++ * @mesh_flags: Flags ++ * @mesh_reason: Reason Code ++ * @mesh_pre_value: Precedence Value ++ * ++ * This structure represents the payload of the "Mesh Channel Switch ++ * Parameters element" as described in IEEE Std 802.11-2020 section ++ * 9.4.2.102. ++ */ ++struct ieee80211_mesh_chansw_params_ie { ++ u8 mesh_ttl; ++ u8 mesh_flags; ++ __le16 mesh_reason; ++ __le16 mesh_pre_value; ++} __packed; ++ ++/** ++ * struct ieee80211_meshconf_ie - Mesh Configuration element ++ * @meshconf_psel: Active Path Selection Protocol Identifier ++ * @meshconf_pmetric: Active Path Selection Metric Identifier ++ * @meshconf_congest: Congestion Control Mode Identifier ++ * @meshconf_synch: Synchronization Method Identifier ++ * @meshconf_auth: Authentication Protocol Identifier ++ * @meshconf_form: Mesh Formation Info ++ * @meshconf_cap: Mesh Capability (see &enum mesh_config_capab_flags) ++ * ++ * This structure represents the payload of the "Mesh Configuration ++ * element" as described in IEEE Std 802.11-2020 section 9.4.2.97. ++ */ ++struct ieee80211_meshconf_ie { ++ u8 meshconf_psel; ++ u8 meshconf_pmetric; ++ u8 meshconf_congest; ++ u8 meshconf_synch; ++ u8 meshconf_auth; ++ u8 meshconf_form; ++ u8 meshconf_cap; ++} __packed; ++ ++/** ++ * enum mesh_config_capab_flags - Mesh Configuration IE capability field flags ++ * ++ * @IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish ++ * additional mesh peerings with other mesh STAs ++ * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs ++ * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure ++ * is ongoing ++ * @IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL: STA is in deep sleep mode or has ++ * neighbors in deep sleep mode ++ * ++ * Enumerates the "Mesh Capability" as described in IEEE Std ++ * 802.11-2020 section 9.4.2.97.7. ++ */ ++enum mesh_config_capab_flags { ++ IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS = 0x01, ++ IEEE80211_MESHCONF_CAPAB_FORWARDING = 0x08, ++ IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING = 0x20, ++ IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL = 0x40, ++}; ++ ++#define IEEE80211_MESHCONF_FORM_CONNECTED_TO_GATE 0x1 ++ ++/* ++ * mesh channel switch parameters element's flag indicator ++ * ++ */ ++#define WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT BIT(0) ++#define WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR BIT(1) ++#define WLAN_EID_CHAN_SWITCH_PARAM_REASON BIT(2) ++ ++/** ++ * struct ieee80211_rann_ie - RANN (root announcement) element ++ * @rann_flags: Flags ++ * @rann_hopcount: Hop Count ++ * @rann_ttl: Element TTL ++ * @rann_addr: Root Mesh STA Address ++ * @rann_seq: HWMP Sequence Number ++ * @rann_interval: Interval ++ * @rann_metric: Metric ++ * ++ * This structure represents the payload of the "RANN element" as ++ * described in IEEE Std 802.11-2020 section 9.4.2.111. ++ */ ++struct ieee80211_rann_ie { ++ u8 rann_flags; ++ u8 rann_hopcount; ++ u8 rann_ttl; ++ u8 rann_addr[ETH_ALEN]; ++ __le32 rann_seq; ++ __le32 rann_interval; ++ __le32 rann_metric; ++} __packed; ++ ++enum ieee80211_rann_flags { ++ RANN_FLAG_IS_GATE = 1 << 0, ++}; ++ ++/* Mesh action codes */ ++enum ieee80211_mesh_actioncode { ++ WLAN_MESH_ACTION_LINK_METRIC_REPORT, ++ WLAN_MESH_ACTION_HWMP_PATH_SELECTION, ++ WLAN_MESH_ACTION_GATE_ANNOUNCEMENT, ++ WLAN_MESH_ACTION_CONGESTION_CONTROL_NOTIFICATION, ++ WLAN_MESH_ACTION_MCCA_SETUP_REQUEST, ++ WLAN_MESH_ACTION_MCCA_SETUP_REPLY, ++ WLAN_MESH_ACTION_MCCA_ADVERTISEMENT_REQUEST, ++ WLAN_MESH_ACTION_MCCA_ADVERTISEMENT, ++ WLAN_MESH_ACTION_MCCA_TEARDOWN, ++ WLAN_MESH_ACTION_TBTT_ADJUSTMENT_REQUEST, ++ WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE, ++}; ++ ++/** ++ * enum ieee80211_mesh_sync_method - mesh synchronization method identifier ++ * ++ * @IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET: the default synchronization method ++ * @IEEE80211_SYNC_METHOD_VENDOR: a vendor specific synchronization method ++ * that will be specified in a vendor specific information element ++ */ ++enum ieee80211_mesh_sync_method { ++ IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET = 1, ++ IEEE80211_SYNC_METHOD_VENDOR = 255, ++}; ++ ++/** ++ * enum ieee80211_mesh_path_protocol - mesh path selection protocol identifier ++ * ++ * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol ++ * @IEEE80211_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will ++ * be specified in a vendor specific information element ++ */ ++enum ieee80211_mesh_path_protocol { ++ IEEE80211_PATH_PROTOCOL_HWMP = 1, ++ IEEE80211_PATH_PROTOCOL_VENDOR = 255, ++}; ++ ++/** ++ * enum ieee80211_mesh_path_metric - mesh path selection metric identifier ++ * ++ * @IEEE80211_PATH_METRIC_AIRTIME: the default path selection metric ++ * @IEEE80211_PATH_METRIC_VENDOR: a vendor specific metric that will be ++ * specified in a vendor specific information element ++ */ ++enum ieee80211_mesh_path_metric { ++ IEEE80211_PATH_METRIC_AIRTIME = 1, ++ IEEE80211_PATH_METRIC_VENDOR = 255, ++}; ++ ++/** ++ * enum ieee80211_root_mode_identifier - root mesh STA mode identifier ++ * ++ * These attribute are used by dot11MeshHWMPRootMode to set root mesh STA mode ++ * ++ * @IEEE80211_ROOTMODE_NO_ROOT: the mesh STA is not a root mesh STA (default) ++ * @IEEE80211_ROOTMODE_ROOT: the mesh STA is a root mesh STA if greater than ++ * this value ++ * @IEEE80211_PROACTIVE_PREQ_NO_PREP: the mesh STA is a root mesh STA supports ++ * the proactive PREQ with proactive PREP subfield set to 0 ++ * @IEEE80211_PROACTIVE_PREQ_WITH_PREP: the mesh STA is a root mesh STA ++ * supports the proactive PREQ with proactive PREP subfield set to 1 ++ * @IEEE80211_PROACTIVE_RANN: the mesh STA is a root mesh STA supports ++ * the proactive RANN ++ */ ++enum ieee80211_root_mode_identifier { ++ IEEE80211_ROOTMODE_NO_ROOT = 0, ++ IEEE80211_ROOTMODE_ROOT = 1, ++ IEEE80211_PROACTIVE_PREQ_NO_PREP = 2, ++ IEEE80211_PROACTIVE_PREQ_WITH_PREP = 3, ++ IEEE80211_PROACTIVE_RANN = 4, ++}; ++ ++#endif /* LINUX_IEEE80211_MESH_H */ +diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h +index 1f4679092e69d..ebc12d1939273 100644 +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -252,8 +252,6 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) + + #define IEEE80211_MAX_SSID_LEN 32 + +-#define IEEE80211_MAX_MESH_ID_LEN 32 +- + #define IEEE80211_FIRST_TSPEC_TSID 8 + #define IEEE80211_NUM_TIDS 16 + +@@ -881,40 +879,6 @@ static inline u16 ieee80211_get_sn(struct ieee80211_hdr *hdr) + return le16_get_bits(hdr->seq_ctrl, IEEE80211_SCTL_SEQ); + } + +-struct ieee80211s_hdr { +- u8 flags; +- u8 ttl; +- __le32 seqnum; +- u8 eaddr1[ETH_ALEN]; +- u8 eaddr2[ETH_ALEN]; +-} __packed __aligned(2); +- +-/* Mesh flags */ +-#define MESH_FLAGS_AE_A4 0x1 +-#define MESH_FLAGS_AE_A5_A6 0x2 +-#define MESH_FLAGS_AE 0x3 +-#define MESH_FLAGS_PS_DEEP 0x4 +- +-/** +- * enum ieee80211_preq_flags - mesh PREQ element flags +- * +- * @IEEE80211_PREQ_PROACTIVE_PREP_FLAG: proactive PREP subfield +- */ +-enum ieee80211_preq_flags { +- IEEE80211_PREQ_PROACTIVE_PREP_FLAG = 1<<2, +-}; +- +-/** +- * enum ieee80211_preq_target_flags - mesh PREQ element per target flags +- * +- * @IEEE80211_PREQ_TO_FLAG: target only subfield +- * @IEEE80211_PREQ_USN_FLAG: unknown target HWMP sequence number subfield +- */ +-enum ieee80211_preq_target_flags { +- IEEE80211_PREQ_TO_FLAG = 1<<0, +- IEEE80211_PREQ_USN_FLAG = 1<<2, +-}; +- + /** + * struct ieee80211_quiet_ie - Quiet element + * @count: Quiet Count +@@ -993,24 +957,6 @@ struct ieee80211_sec_chan_offs_ie { + u8 sec_chan_offs; + } __packed; + +-/** +- * struct ieee80211_mesh_chansw_params_ie - mesh channel switch parameters IE +- * @mesh_ttl: Time To Live +- * @mesh_flags: Flags +- * @mesh_reason: Reason Code +- * @mesh_pre_value: Precedence Value +- * +- * This structure represents the payload of the "Mesh Channel Switch +- * Parameters element" as described in IEEE Std 802.11-2020 section +- * 9.4.2.102. +- */ +-struct ieee80211_mesh_chansw_params_ie { +- u8 mesh_ttl; +- u8 mesh_flags; +- __le16 mesh_reason; +- __le16 mesh_pre_value; +-} __packed; +- + /** + * struct ieee80211_wide_bw_chansw_ie - wide bandwidth channel switch IE + * @new_channel_width: New Channel Width +@@ -1051,87 +997,6 @@ struct ieee80211_tim_ie { + }; + } __packed; + +-/** +- * struct ieee80211_meshconf_ie - Mesh Configuration element +- * @meshconf_psel: Active Path Selection Protocol Identifier +- * @meshconf_pmetric: Active Path Selection Metric Identifier +- * @meshconf_congest: Congestion Control Mode Identifier +- * @meshconf_synch: Synchronization Method Identifier +- * @meshconf_auth: Authentication Protocol Identifier +- * @meshconf_form: Mesh Formation Info +- * @meshconf_cap: Mesh Capability (see &enum mesh_config_capab_flags) +- * +- * This structure represents the payload of the "Mesh Configuration +- * element" as described in IEEE Std 802.11-2020 section 9.4.2.97. +- */ +-struct ieee80211_meshconf_ie { +- u8 meshconf_psel; +- u8 meshconf_pmetric; +- u8 meshconf_congest; +- u8 meshconf_synch; +- u8 meshconf_auth; +- u8 meshconf_form; +- u8 meshconf_cap; +-} __packed; +- +-/** +- * enum mesh_config_capab_flags - Mesh Configuration IE capability field flags +- * +- * @IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish +- * additional mesh peerings with other mesh STAs +- * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs +- * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure +- * is ongoing +- * @IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL: STA is in deep sleep mode or has +- * neighbors in deep sleep mode +- * +- * Enumerates the "Mesh Capability" as described in IEEE Std +- * 802.11-2020 section 9.4.2.97.7. +- */ +-enum mesh_config_capab_flags { +- IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS = 0x01, +- IEEE80211_MESHCONF_CAPAB_FORWARDING = 0x08, +- IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING = 0x20, +- IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL = 0x40, +-}; +- +-#define IEEE80211_MESHCONF_FORM_CONNECTED_TO_GATE 0x1 +- +-/* +- * mesh channel switch parameters element's flag indicator +- * +- */ +-#define WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT BIT(0) +-#define WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR BIT(1) +-#define WLAN_EID_CHAN_SWITCH_PARAM_REASON BIT(2) +- +-/** +- * struct ieee80211_rann_ie - RANN (root announcement) element +- * @rann_flags: Flags +- * @rann_hopcount: Hop Count +- * @rann_ttl: Element TTL +- * @rann_addr: Root Mesh STA Address +- * @rann_seq: HWMP Sequence Number +- * @rann_interval: Interval +- * @rann_metric: Metric +- * +- * This structure represents the payload of the "RANN element" as +- * described in IEEE Std 802.11-2020 section 9.4.2.111. +- */ +-struct ieee80211_rann_ie { +- u8 rann_flags; +- u8 rann_hopcount; +- u8 rann_ttl; +- u8 rann_addr[ETH_ALEN]; +- __le32 rann_seq; +- __le32 rann_interval; +- __le32 rann_metric; +-} __packed; +- +-enum ieee80211_rann_flags { +- RANN_FLAG_IS_GATE = 1 << 0, +-}; +- + enum ieee80211_ht_chanwidth_values { + IEEE80211_HT_CHANWIDTH_20MHZ = 0, + IEEE80211_HT_CHANWIDTH_ANY = 1, +@@ -3971,21 +3836,6 @@ enum ieee80211_self_protected_actioncode { + WLAN_SP_MGK_ACK = 5, + }; + +-/* Mesh action codes */ +-enum ieee80211_mesh_actioncode { +- WLAN_MESH_ACTION_LINK_METRIC_REPORT, +- WLAN_MESH_ACTION_HWMP_PATH_SELECTION, +- WLAN_MESH_ACTION_GATE_ANNOUNCEMENT, +- WLAN_MESH_ACTION_CONGESTION_CONTROL_NOTIFICATION, +- WLAN_MESH_ACTION_MCCA_SETUP_REQUEST, +- WLAN_MESH_ACTION_MCCA_SETUP_REPLY, +- WLAN_MESH_ACTION_MCCA_ADVERTISEMENT_REQUEST, +- WLAN_MESH_ACTION_MCCA_ADVERTISEMENT, +- WLAN_MESH_ACTION_MCCA_TEARDOWN, +- WLAN_MESH_ACTION_TBTT_ADJUSTMENT_REQUEST, +- WLAN_MESH_ACTION_TBTT_ADJUSTMENT_RESPONSE, +-}; +- + /* Unprotected WNM action codes */ + enum ieee80211_unprotected_wnm_actioncode { + WLAN_UNPROTECTED_WNM_ACTION_TIM = 0, +@@ -4198,65 +4048,6 @@ enum ieee80211_tdls_actioncode { + /* BSS Coex IE information field bits */ + #define WLAN_BSS_COEX_INFORMATION_REQUEST BIT(0) + +-/** +- * enum ieee80211_mesh_sync_method - mesh synchronization method identifier +- * +- * @IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET: the default synchronization method +- * @IEEE80211_SYNC_METHOD_VENDOR: a vendor specific synchronization method +- * that will be specified in a vendor specific information element +- */ +-enum ieee80211_mesh_sync_method { +- IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET = 1, +- IEEE80211_SYNC_METHOD_VENDOR = 255, +-}; +- +-/** +- * enum ieee80211_mesh_path_protocol - mesh path selection protocol identifier +- * +- * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol +- * @IEEE80211_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will +- * be specified in a vendor specific information element +- */ +-enum ieee80211_mesh_path_protocol { +- IEEE80211_PATH_PROTOCOL_HWMP = 1, +- IEEE80211_PATH_PROTOCOL_VENDOR = 255, +-}; +- +-/** +- * enum ieee80211_mesh_path_metric - mesh path selection metric identifier +- * +- * @IEEE80211_PATH_METRIC_AIRTIME: the default path selection metric +- * @IEEE80211_PATH_METRIC_VENDOR: a vendor specific metric that will be +- * specified in a vendor specific information element +- */ +-enum ieee80211_mesh_path_metric { +- IEEE80211_PATH_METRIC_AIRTIME = 1, +- IEEE80211_PATH_METRIC_VENDOR = 255, +-}; +- +-/** +- * enum ieee80211_root_mode_identifier - root mesh STA mode identifier +- * +- * These attribute are used by dot11MeshHWMPRootMode to set root mesh STA mode +- * +- * @IEEE80211_ROOTMODE_NO_ROOT: the mesh STA is not a root mesh STA (default) +- * @IEEE80211_ROOTMODE_ROOT: the mesh STA is a root mesh STA if greater than +- * this value +- * @IEEE80211_PROACTIVE_PREQ_NO_PREP: the mesh STA is a root mesh STA supports +- * the proactive PREQ with proactive PREP subfield set to 0 +- * @IEEE80211_PROACTIVE_PREQ_WITH_PREP: the mesh STA is a root mesh STA +- * supports the proactive PREQ with proactive PREP subfield set to 1 +- * @IEEE80211_PROACTIVE_RANN: the mesh STA is a root mesh STA supports +- * the proactive RANN +- */ +-enum ieee80211_root_mode_identifier { +- IEEE80211_ROOTMODE_NO_ROOT = 0, +- IEEE80211_ROOTMODE_ROOT = 1, +- IEEE80211_PROACTIVE_PREQ_NO_PREP = 2, +- IEEE80211_PROACTIVE_PREQ_WITH_PREP = 3, +- IEEE80211_PROACTIVE_RANN = 4, +-}; +- + /* + * IEEE 802.11-2007 7.3.2.9 Country information element + * +@@ -6098,4 +5889,6 @@ static inline u32 ieee80211_eml_trans_timeout_in_us(u16 eml_cap) + #define NAN_DEV_CAPA_NDPE_SUPPORTED 0x08 + #define NAN_DEV_CAPA_S3_SUPPORTED 0x10 + ++#include "ieee80211-mesh.h" ++ + #endif /* LINUX_IEEE80211_H */ +-- +2.53.0 + diff --git a/queue-6.18/wifi-ieee80211-split-vht-definitions-out.patch b/queue-6.18/wifi-ieee80211-split-vht-definitions-out.patch new file mode 100644 index 0000000000..3704fb45c4 --- /dev/null +++ b/queue-6.18/wifi-ieee80211-split-vht-definitions-out.patch @@ -0,0 +1,529 @@ +From d7cbcb0835bdb0b002c14be99624cd64c6adcd8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 15:36:51 +0100 +Subject: wifi: ieee80211: split VHT definitions out + +From: Johannes Berg + +[ Upstream commit 7cb14da1d7bbfa4a6417ed7f1bc07dd77bcd9c83 ] + +The ieee80211.h file has gotten very long, continue splitting +it by putting VHT definitions into a separate file. + +Link: https://patch.msgid.link/20251105153843.c31cb771a250.I787a13064db7d80440101de3445be17881daf1b6@changeid +Signed-off-by: Johannes Berg +Stable-dep-of: cb0caadb64ca ("wifi: ieee80211: fix definition of EHT-MCS 15 in MRU") +Signed-off-by: Sasha Levin +--- + include/linux/ieee80211-vht.h | 236 ++++++++++++++++++++++++++++++++++ + include/linux/ieee80211.h | 216 +------------------------------ + 2 files changed, 237 insertions(+), 215 deletions(-) + create mode 100644 include/linux/ieee80211-vht.h + +diff --git a/include/linux/ieee80211-vht.h b/include/linux/ieee80211-vht.h +new file mode 100644 +index 0000000000000..898dfb561fef2 +--- /dev/null ++++ b/include/linux/ieee80211-vht.h +@@ -0,0 +1,236 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * IEEE 802.11 VHT definitions ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Copyright (c) 2005, Devicescape Software, Inc. ++ * Copyright (c) 2006, Michael Wu ++ * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH ++ * Copyright (c) 2016 - 2017 Intel Deutschland GmbH ++ * Copyright (c) 2018 - 2025 Intel Corporation ++ */ ++ ++#ifndef LINUX_IEEE80211_VHT_H ++#define LINUX_IEEE80211_VHT_H ++ ++#include ++#include ++ ++#define IEEE80211_MAX_MPDU_LEN_VHT_3895 3895 ++#define IEEE80211_MAX_MPDU_LEN_VHT_7991 7991 ++#define IEEE80211_MAX_MPDU_LEN_VHT_11454 11454 ++ ++/** ++ * enum ieee80211_vht_opmode_bits - VHT operating mode field bits ++ * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK: channel width mask ++ * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: 20 MHz channel width ++ * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: 40 MHz channel width ++ * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 80 MHz channel width ++ * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: 160 MHz or 80+80 MHz channel width ++ * @IEEE80211_OPMODE_NOTIF_BW_160_80P80: 160 / 80+80 MHz indicator flag ++ * @IEEE80211_OPMODE_NOTIF_RX_NSS_MASK: number of spatial streams mask ++ * (the NSS value is the value of this field + 1) ++ * @IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT: number of spatial streams shift ++ * @IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF: indicates streams in SU-MIMO PPDU ++ * using a beamforming steering matrix ++ */ ++enum ieee80211_vht_opmode_bits { ++ IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK = 0x03, ++ IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ = 0, ++ IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ = 1, ++ IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ = 2, ++ IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ = 3, ++ IEEE80211_OPMODE_NOTIF_BW_160_80P80 = 0x04, ++ IEEE80211_OPMODE_NOTIF_RX_NSS_MASK = 0x70, ++ IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT = 4, ++ IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80, ++}; ++ ++/* ++ * Maximum length of AMPDU that the STA can receive in VHT. ++ * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) ++ */ ++enum ieee80211_vht_max_ampdu_length_exp { ++ IEEE80211_VHT_MAX_AMPDU_8K = 0, ++ IEEE80211_VHT_MAX_AMPDU_16K = 1, ++ IEEE80211_VHT_MAX_AMPDU_32K = 2, ++ IEEE80211_VHT_MAX_AMPDU_64K = 3, ++ IEEE80211_VHT_MAX_AMPDU_128K = 4, ++ IEEE80211_VHT_MAX_AMPDU_256K = 5, ++ IEEE80211_VHT_MAX_AMPDU_512K = 6, ++ IEEE80211_VHT_MAX_AMPDU_1024K = 7 ++}; ++ ++/** ++ * struct ieee80211_vht_mcs_info - VHT MCS information ++ * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams ++ * @rx_highest: Indicates highest long GI VHT PPDU data rate ++ * STA can receive. Rate expressed in units of 1 Mbps. ++ * If this field is 0 this value should not be used to ++ * consider the highest RX data rate supported. ++ * The top 3 bits of this field indicate the Maximum NSTS,total ++ * (a beamformee capability.) ++ * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams ++ * @tx_highest: Indicates highest long GI VHT PPDU data rate ++ * STA can transmit. Rate expressed in units of 1 Mbps. ++ * If this field is 0 this value should not be used to ++ * consider the highest TX data rate supported. ++ * The top 2 bits of this field are reserved, the ++ * 3rd bit from the top indiciates VHT Extended NSS BW ++ * Capability. ++ */ ++struct ieee80211_vht_mcs_info { ++ __le16 rx_mcs_map; ++ __le16 rx_highest; ++ __le16 tx_mcs_map; ++ __le16 tx_highest; ++} __packed; ++ ++/* for rx_highest */ ++#define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT 13 ++#define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK (7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT) ++ ++/* for tx_highest */ ++#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) ++ ++/** ++ * enum ieee80211_vht_mcs_support - VHT MCS support definitions ++ * @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the ++ * number of streams ++ * @IEEE80211_VHT_MCS_SUPPORT_0_8: MCSes 0-8 are supported ++ * @IEEE80211_VHT_MCS_SUPPORT_0_9: MCSes 0-9 are supported ++ * @IEEE80211_VHT_MCS_NOT_SUPPORTED: This number of streams isn't supported ++ * ++ * These definitions are used in each 2-bit subfield of the @rx_mcs_map ++ * and @tx_mcs_map fields of &struct ieee80211_vht_mcs_info, which are ++ * both split into 8 subfields by number of streams. These values indicate ++ * which MCSes are supported for the number of streams the value appears ++ * for. ++ */ ++enum ieee80211_vht_mcs_support { ++ IEEE80211_VHT_MCS_SUPPORT_0_7 = 0, ++ IEEE80211_VHT_MCS_SUPPORT_0_8 = 1, ++ IEEE80211_VHT_MCS_SUPPORT_0_9 = 2, ++ IEEE80211_VHT_MCS_NOT_SUPPORTED = 3, ++}; ++ ++/** ++ * struct ieee80211_vht_cap - VHT capabilities ++ * ++ * This structure is the "VHT capabilities element" as ++ * described in 802.11ac D3.0 8.4.2.160 ++ * @vht_cap_info: VHT capability info ++ * @supp_mcs: VHT MCS supported rates ++ */ ++struct ieee80211_vht_cap { ++ __le32 vht_cap_info; ++ struct ieee80211_vht_mcs_info supp_mcs; ++} __packed; ++ ++/** ++ * enum ieee80211_vht_chanwidth - VHT channel width ++ * @IEEE80211_VHT_CHANWIDTH_USE_HT: use the HT operation IE to ++ * determine the channel width (20 or 40 MHz) ++ * @IEEE80211_VHT_CHANWIDTH_80MHZ: 80 MHz bandwidth ++ * @IEEE80211_VHT_CHANWIDTH_160MHZ: 160 MHz bandwidth ++ * @IEEE80211_VHT_CHANWIDTH_80P80MHZ: 80+80 MHz bandwidth ++ */ ++enum ieee80211_vht_chanwidth { ++ IEEE80211_VHT_CHANWIDTH_USE_HT = 0, ++ IEEE80211_VHT_CHANWIDTH_80MHZ = 1, ++ IEEE80211_VHT_CHANWIDTH_160MHZ = 2, ++ IEEE80211_VHT_CHANWIDTH_80P80MHZ = 3, ++}; ++ ++/** ++ * struct ieee80211_vht_operation - VHT operation IE ++ * ++ * This structure is the "VHT operation element" as ++ * described in 802.11ac D3.0 8.4.2.161 ++ * @chan_width: Operating channel width ++ * @center_freq_seg0_idx: center freq segment 0 index ++ * @center_freq_seg1_idx: center freq segment 1 index ++ * @basic_mcs_set: VHT Basic MCS rate set ++ */ ++struct ieee80211_vht_operation { ++ u8 chan_width; ++ u8 center_freq_seg0_idx; ++ u8 center_freq_seg1_idx; ++ __le16 basic_mcs_set; ++} __packed; ++ ++/* 802.11ac VHT Capabilities */ ++#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 ++#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001 ++#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 ++#define IEEE80211_VHT_CAP_MAX_MPDU_MASK 0x00000003 ++#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 ++#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 ++#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C ++#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 2 ++#define IEEE80211_VHT_CAP_RXLDPC 0x00000010 ++#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 ++#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 ++#define IEEE80211_VHT_CAP_TXSTBC 0x00000080 ++#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100 ++#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 ++#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 ++#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 ++#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700 ++#define IEEE80211_VHT_CAP_RXSTBC_SHIFT 8 ++#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 ++#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 ++#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT 13 ++#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK \ ++ (7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT) ++#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16 ++#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK \ ++ (7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) ++#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 ++#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 ++#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 ++#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000 ++#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 23 ++#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \ ++ (7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT) ++#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000 ++#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 ++#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 ++#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 ++#define IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT 30 ++#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK 0xc0000000 ++ ++/** ++ * ieee80211_get_vht_max_nss - return max NSS for a given bandwidth/MCS ++ * @cap: VHT capabilities of the peer ++ * @bw: bandwidth to use ++ * @mcs: MCS index to use ++ * @ext_nss_bw_capable: indicates whether or not the local transmitter ++ * (rate scaling algorithm) can deal with the new logic ++ * (dot11VHTExtendedNSSBWCapable) ++ * @max_vht_nss: current maximum NSS as advertised by the STA in ++ * operating mode notification, can be 0 in which case the ++ * capability data will be used to derive this (from MCS support) ++ * Return: The maximum NSS that can be used for the given bandwidth/MCS ++ * combination ++ * ++ * Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can ++ * vary for a given BW/MCS. This function parses the data. ++ * ++ * Note: This function is exported by cfg80211. ++ */ ++int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, ++ enum ieee80211_vht_chanwidth bw, ++ int mcs, bool ext_nss_bw_capable, ++ unsigned int max_vht_nss); ++ ++/* VHT action codes */ ++enum ieee80211_vht_actioncode { ++ WLAN_VHT_ACTION_COMPRESSED_BF = 0, ++ WLAN_VHT_ACTION_GROUPID_MGMT = 1, ++ WLAN_VHT_ACTION_OPMODE_NOTIF = 2, ++}; ++ ++#endif /* LINUX_IEEE80211_VHT_H */ +diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h +index f0a7899fb6626..fb399b7833736 100644 +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -239,10 +239,6 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) + /* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ + #define IEEE80211_MAX_FRAME_LEN 2352 + +-#define IEEE80211_MAX_MPDU_LEN_VHT_3895 3895 +-#define IEEE80211_MAX_MPDU_LEN_VHT_7991 7991 +-#define IEEE80211_MAX_MPDU_LEN_VHT_11454 11454 +- + #define IEEE80211_MAX_SSID_LEN 32 + + #define IEEE80211_FIRST_TSPEC_TSID 8 +@@ -988,32 +984,6 @@ struct ieee80211_tim_ie { + }; + } __packed; + +-/** +- * enum ieee80211_vht_opmode_bits - VHT operating mode field bits +- * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK: channel width mask +- * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: 20 MHz channel width +- * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: 40 MHz channel width +- * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 80 MHz channel width +- * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: 160 MHz or 80+80 MHz channel width +- * @IEEE80211_OPMODE_NOTIF_BW_160_80P80: 160 / 80+80 MHz indicator flag +- * @IEEE80211_OPMODE_NOTIF_RX_NSS_MASK: number of spatial streams mask +- * (the NSS value is the value of this field + 1) +- * @IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT: number of spatial streams shift +- * @IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF: indicates streams in SU-MIMO PPDU +- * using a beamforming steering matrix +- */ +-enum ieee80211_vht_opmode_bits { +- IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK = 0x03, +- IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ = 0, +- IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ = 1, +- IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ = 2, +- IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ = 3, +- IEEE80211_OPMODE_NOTIF_BW_160_80P80 = 0x04, +- IEEE80211_OPMODE_NOTIF_RX_NSS_MASK = 0x70, +- IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT = 4, +- IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80, +-}; +- + /** + * enum ieee80211_s1g_chanwidth - S1G channel widths + * These are defined in IEEE802.11-2016ah Table 10-20 +@@ -1663,119 +1633,6 @@ struct ieee80211_p2p_noa_attr { + #define IEEE80211_P2P_OPPPS_ENABLE_BIT BIT(7) + #define IEEE80211_P2P_OPPPS_CTWINDOW_MASK 0x7F + +-/* +- * Maximum length of AMPDU that the STA can receive in VHT. +- * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) +- */ +-enum ieee80211_vht_max_ampdu_length_exp { +- IEEE80211_VHT_MAX_AMPDU_8K = 0, +- IEEE80211_VHT_MAX_AMPDU_16K = 1, +- IEEE80211_VHT_MAX_AMPDU_32K = 2, +- IEEE80211_VHT_MAX_AMPDU_64K = 3, +- IEEE80211_VHT_MAX_AMPDU_128K = 4, +- IEEE80211_VHT_MAX_AMPDU_256K = 5, +- IEEE80211_VHT_MAX_AMPDU_512K = 6, +- IEEE80211_VHT_MAX_AMPDU_1024K = 7 +-}; +- +-/** +- * struct ieee80211_vht_mcs_info - VHT MCS information +- * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams +- * @rx_highest: Indicates highest long GI VHT PPDU data rate +- * STA can receive. Rate expressed in units of 1 Mbps. +- * If this field is 0 this value should not be used to +- * consider the highest RX data rate supported. +- * The top 3 bits of this field indicate the Maximum NSTS,total +- * (a beamformee capability.) +- * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams +- * @tx_highest: Indicates highest long GI VHT PPDU data rate +- * STA can transmit. Rate expressed in units of 1 Mbps. +- * If this field is 0 this value should not be used to +- * consider the highest TX data rate supported. +- * The top 2 bits of this field are reserved, the +- * 3rd bit from the top indiciates VHT Extended NSS BW +- * Capability. +- */ +-struct ieee80211_vht_mcs_info { +- __le16 rx_mcs_map; +- __le16 rx_highest; +- __le16 tx_mcs_map; +- __le16 tx_highest; +-} __packed; +- +-/* for rx_highest */ +-#define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT 13 +-#define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK (7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT) +- +-/* for tx_highest */ +-#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) +- +-/** +- * enum ieee80211_vht_mcs_support - VHT MCS support definitions +- * @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the +- * number of streams +- * @IEEE80211_VHT_MCS_SUPPORT_0_8: MCSes 0-8 are supported +- * @IEEE80211_VHT_MCS_SUPPORT_0_9: MCSes 0-9 are supported +- * @IEEE80211_VHT_MCS_NOT_SUPPORTED: This number of streams isn't supported +- * +- * These definitions are used in each 2-bit subfield of the @rx_mcs_map +- * and @tx_mcs_map fields of &struct ieee80211_vht_mcs_info, which are +- * both split into 8 subfields by number of streams. These values indicate +- * which MCSes are supported for the number of streams the value appears +- * for. +- */ +-enum ieee80211_vht_mcs_support { +- IEEE80211_VHT_MCS_SUPPORT_0_7 = 0, +- IEEE80211_VHT_MCS_SUPPORT_0_8 = 1, +- IEEE80211_VHT_MCS_SUPPORT_0_9 = 2, +- IEEE80211_VHT_MCS_NOT_SUPPORTED = 3, +-}; +- +-/** +- * struct ieee80211_vht_cap - VHT capabilities +- * +- * This structure is the "VHT capabilities element" as +- * described in 802.11ac D3.0 8.4.2.160 +- * @vht_cap_info: VHT capability info +- * @supp_mcs: VHT MCS supported rates +- */ +-struct ieee80211_vht_cap { +- __le32 vht_cap_info; +- struct ieee80211_vht_mcs_info supp_mcs; +-} __packed; +- +-/** +- * enum ieee80211_vht_chanwidth - VHT channel width +- * @IEEE80211_VHT_CHANWIDTH_USE_HT: use the HT operation IE to +- * determine the channel width (20 or 40 MHz) +- * @IEEE80211_VHT_CHANWIDTH_80MHZ: 80 MHz bandwidth +- * @IEEE80211_VHT_CHANWIDTH_160MHZ: 160 MHz bandwidth +- * @IEEE80211_VHT_CHANWIDTH_80P80MHZ: 80+80 MHz bandwidth +- */ +-enum ieee80211_vht_chanwidth { +- IEEE80211_VHT_CHANWIDTH_USE_HT = 0, +- IEEE80211_VHT_CHANWIDTH_80MHZ = 1, +- IEEE80211_VHT_CHANWIDTH_160MHZ = 2, +- IEEE80211_VHT_CHANWIDTH_80P80MHZ = 3, +-}; +- +-/** +- * struct ieee80211_vht_operation - VHT operation IE +- * +- * This structure is the "VHT operation element" as +- * described in 802.11ac D3.0 8.4.2.161 +- * @chan_width: Operating channel width +- * @center_freq_seg0_idx: center freq segment 0 index +- * @center_freq_seg1_idx: center freq segment 1 index +- * @basic_mcs_set: VHT Basic MCS rate set +- */ +-struct ieee80211_vht_operation { +- u8 chan_width; +- u8 center_freq_seg0_idx; +- u8 center_freq_seg1_idx; +- __le16 basic_mcs_set; +-} __packed; +- + /** + * struct ieee80211_he_cap_elem - HE capabilities element + * @mac_cap_info: HE MAC Capabilities Information +@@ -2045,71 +1902,6 @@ struct ieee80211_eht_operation_info { + u8 optional[]; + } __packed; + +-/* 802.11ac VHT Capabilities */ +-#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 +-#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001 +-#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 +-#define IEEE80211_VHT_CAP_MAX_MPDU_MASK 0x00000003 +-#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 +-#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 +-#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C +-#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 2 +-#define IEEE80211_VHT_CAP_RXLDPC 0x00000010 +-#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 +-#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 +-#define IEEE80211_VHT_CAP_TXSTBC 0x00000080 +-#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100 +-#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 +-#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 +-#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 +-#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700 +-#define IEEE80211_VHT_CAP_RXSTBC_SHIFT 8 +-#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 +-#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 +-#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT 13 +-#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK \ +- (7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT) +-#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16 +-#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK \ +- (7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) +-#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 +-#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 +-#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 +-#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000 +-#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 23 +-#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \ +- (7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT) +-#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000 +-#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 +-#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 +-#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 +-#define IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT 30 +-#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK 0xc0000000 +- +-/** +- * ieee80211_get_vht_max_nss - return max NSS for a given bandwidth/MCS +- * @cap: VHT capabilities of the peer +- * @bw: bandwidth to use +- * @mcs: MCS index to use +- * @ext_nss_bw_capable: indicates whether or not the local transmitter +- * (rate scaling algorithm) can deal with the new logic +- * (dot11VHTExtendedNSSBWCapable) +- * @max_vht_nss: current maximum NSS as advertised by the STA in +- * operating mode notification, can be 0 in which case the +- * capability data will be used to derive this (from MCS support) +- * Return: The maximum NSS that can be used for the given bandwidth/MCS +- * combination +- * +- * Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can +- * vary for a given BW/MCS. This function parses the data. +- * +- * Note: This function is exported by cfg80211. +- */ +-int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, +- enum ieee80211_vht_chanwidth bw, +- int mcs, bool ext_nss_bw_capable, +- unsigned int max_vht_nss); +- + /* 802.11ax HE MAC capabilities */ + #define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01 + #define IEEE80211_HE_MAC_CAP0_TWT_REQ 0x02 +@@ -3561,13 +3353,6 @@ enum ieee80211_spectrum_mgmt_actioncode { + WLAN_ACTION_SPCT_CHL_SWITCH = 4, + }; + +-/* VHT action codes */ +-enum ieee80211_vht_actioncode { +- WLAN_VHT_ACTION_COMPRESSED_BF = 0, +- WLAN_VHT_ACTION_GROUPID_MGMT = 1, +- WLAN_VHT_ACTION_OPMODE_NOTIF = 2, +-}; +- + /* Self Protected Action codes */ + enum ieee80211_self_protected_actioncode { + WLAN_SP_RESERVED = 0, +@@ -5619,6 +5404,7 @@ static inline u32 ieee80211_eml_trans_timeout_in_us(u16 eml_cap) + #define NAN_DEV_CAPA_S3_SUPPORTED 0x10 + + #include "ieee80211-ht.h" ++#include "ieee80211-vht.h" + #include "ieee80211-mesh.h" + + #endif /* LINUX_IEEE80211_H */ +-- +2.53.0 + diff --git a/queue-6.18/wifi-libertas-don-t-kill-urbs-in-interrupt-context.patch b/queue-6.18/wifi-libertas-don-t-kill-urbs-in-interrupt-context.patch new file mode 100644 index 0000000000..f352ba63d9 --- /dev/null +++ b/queue-6.18/wifi-libertas-don-t-kill-urbs-in-interrupt-context.patch @@ -0,0 +1,51 @@ +From 900e34ffb20713893c554557fda609bb3cad34c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 18:27:58 -0300 +Subject: wifi: libertas: don't kill URBs in interrupt context + +From: Heitor Alves de Siqueira + +[ Upstream commit 7c5c2b661bdb78c1472b8833265c9ed1ee880039 ] + +Serialization for the TX path was enforced by calling +usb_kill_urb()/usb_kill_anchored_urbs(), to prevent transmission before +a previous URB was completed. usb_tx_block() can be called from +interrupt context (e.g. in the HCD giveback path), so we can't always +use it to kill in-flight URBs. + +Prevent sleeping during interrupt context by checking the tx_submitted +anchor for existing URBs. We now return -EBUSY, to indicate there's +a pending request. + +Reported-by: syzbot+74afbb6355826ffc2239@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=74afbb6355826ffc2239 +Fixes: d66676e6ca96 ("wifi: libertas: fix WARNING in usb_tx_block") +Signed-off-by: Heitor Alves de Siqueira +Link: https://patch.msgid.link/20260313-libertas-usb-anchors-v1-2-915afbe988d7@igalia.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/libertas/if_usb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c +index 60bfff523b918..f6b9a3c43c93c 100644 +--- a/drivers/net/wireless/marvell/libertas/if_usb.c ++++ b/drivers/net/wireless/marvell/libertas/if_usb.c +@@ -429,7 +429,12 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb + goto tx_ret; + } + +- usb_kill_anchored_urbs(&cardp->tx_submitted); ++ /* check if there are pending URBs */ ++ if (!usb_anchor_empty(&cardp->tx_submitted)) { ++ lbs_deb_usbd(&cardp->udev->dev, "%s failed: pending URB\n", __func__); ++ ret = -EBUSY; ++ goto tx_ret; ++ } + + usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, + usb_sndbulkpipe(cardp->udev, +-- +2.53.0 + diff --git a/queue-6.18/wifi-libertas-use-usb-anchors-for-tracking-in-flight.patch b/queue-6.18/wifi-libertas-use-usb-anchors-for-tracking-in-flight.patch new file mode 100644 index 0000000000..b6bb4437dd --- /dev/null +++ b/queue-6.18/wifi-libertas-use-usb-anchors-for-tracking-in-flight.patch @@ -0,0 +1,138 @@ +From 55b9b659c42485b3c2afbba4c8db7373585a89e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 18:27:57 -0300 +Subject: wifi: libertas: use USB anchors for tracking in-flight URBs + +From: Heitor Alves de Siqueira + +[ Upstream commit a57f35fc19add4dfe33703af575a2c19c2cef9c7 ] + +The libertas driver currently handles URB lifecycles manually, which +makes it non-trivial to check if specific URBs are pending or not. Add +anchors for TX/RX URBs, and use those to track in-flight requests. + +Signed-off-by: Heitor Alves de Siqueira +Link: https://patch.msgid.link/20260313-libertas-usb-anchors-v1-1-915afbe988d7@igalia.com +Signed-off-by: Johannes Berg +Stable-dep-of: 7c5c2b661bdb ("wifi: libertas: don't kill URBs in interrupt context") +Signed-off-by: Sasha Levin +--- + .../net/wireless/marvell/libertas/if_usb.c | 27 ++++++++++++------- + .../net/wireless/marvell/libertas/if_usb.h | 3 +++ + 2 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c +index 924ab93b7b671..60bfff523b918 100644 +--- a/drivers/net/wireless/marvell/libertas/if_usb.c ++++ b/drivers/net/wireless/marvell/libertas/if_usb.c +@@ -114,8 +114,8 @@ static void if_usb_write_bulk_callback(struct urb *urb) + static void if_usb_free(struct if_usb_card *cardp) + { + /* Unlink tx & rx urb */ +- usb_kill_urb(cardp->tx_urb); +- usb_kill_urb(cardp->rx_urb); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); + + usb_free_urb(cardp->tx_urb); + cardp->tx_urb = NULL; +@@ -221,6 +221,9 @@ static int if_usb_probe(struct usb_interface *intf, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol); + ++ init_usb_anchor(&cardp->rx_submitted); ++ init_usb_anchor(&cardp->tx_submitted); ++ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if (usb_endpoint_is_bulk_in(endpoint)) { +@@ -426,7 +429,7 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb + goto tx_ret; + } + +- usb_kill_urb(cardp->tx_urb); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); + + usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, + usb_sndbulkpipe(cardp->udev, +@@ -435,8 +438,10 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb + + cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; + ++ usb_anchor_urb(cardp->tx_urb, &cardp->tx_submitted); + if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { + lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret); ++ usb_unanchor_urb(cardp->tx_urb); + } else { + lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n"); + ret = 0; +@@ -467,8 +472,10 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, + cardp); + + lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); ++ usb_anchor_urb(cardp->rx_urb, &cardp->rx_submitted); + if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { + lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret); ++ usb_unanchor_urb(cardp->rx_urb); + kfree_skb(skb); + cardp->rx_skb = NULL; + ret = -1; +@@ -838,8 +845,8 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret, + } + + /* Cancel any pending usb business */ +- usb_kill_urb(cardp->rx_urb); +- usb_kill_urb(cardp->tx_urb); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); + + cardp->fwlastblksent = 0; + cardp->fwdnldover = 0; +@@ -869,8 +876,8 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret, + if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) { + /* Return to normal operation */ + ret = -EOPNOTSUPP; +- usb_kill_urb(cardp->rx_urb); +- usb_kill_urb(cardp->tx_urb); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); + if (if_usb_submit_rx_urb(cardp) < 0) + ret = -EIO; + goto done; +@@ -900,7 +907,7 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret, + wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover); + + timer_delete_sync(&cardp->fw_timeout); +- usb_kill_urb(cardp->rx_urb); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); + + if (!cardp->fwdnldover) { + pr_info("failed to load fw, resetting device!\n"); +@@ -960,8 +967,8 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) + goto out; + + /* Unlink tx & rx urb */ +- usb_kill_urb(cardp->tx_urb); +- usb_kill_urb(cardp->rx_urb); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); + + out: + return ret; +diff --git a/drivers/net/wireless/marvell/libertas/if_usb.h b/drivers/net/wireless/marvell/libertas/if_usb.h +index 7d0daeb33c3f7..a0cd36197c2b0 100644 +--- a/drivers/net/wireless/marvell/libertas/if_usb.h ++++ b/drivers/net/wireless/marvell/libertas/if_usb.h +@@ -48,6 +48,9 @@ struct if_usb_card { + struct urb *rx_urb, *tx_urb; + struct lbs_private *priv; + ++ struct usb_anchor rx_submitted; ++ struct usb_anchor tx_submitted; ++ + struct sk_buff *rx_skb; + + uint8_t ep_in; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch b/queue-6.18/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch new file mode 100644 index 0000000000..c65166f457 --- /dev/null +++ b/queue-6.18/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch @@ -0,0 +1,46 @@ +From 111d0009d8261fe780deead797ee1e6f78d9827f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:02:56 +0100 +Subject: wifi: mac80211: handle VHT EXT NSS in + ieee80211_determine_our_sta_mode() + +From: Nicolas Escande + +[ Upstream commit b5b8e295973083abf823fb66647a7c702a8db8a7 ] + +A station which has a NSS ratio on the number of streams it is capable of +in 160MHz VHT operation is supposed to use the 'Extended NSS BW Support' +as defined by section '9.4.2.156.2 VHT Capabilities Information field'. + +This was missing in ieee80211_determine_our_sta_mode() and so we would +wrongfully downgrade our bandwidth when connecting to an AP that supported +160MHz with messages such as: + + [ 37.638346] wlan1: AP XX:XX:XX:XX:XX:XX changed bandwidth in assoc response, new used config is 5280.000 MHz, width 3 (5290.000/0 MHz) + +Fixes: 310c8387c638 ("wifi: mac80211: clean up connection process") +Signed-off-by: Nicolas Escande +Link: https://patch.msgid.link/20260327100256.3101348-1-nico.escande@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index deef15c074c83..bcc4090ddc1a5 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -5897,7 +5897,8 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata, + + if (is_5ghz && + !(vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | +- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { ++ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | ++ IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))) { + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80; + mlme_link_id_dbg(sdata, link_id, + "no VHT 160 MHz capability on 5 GHz, limiting to 80 MHz"); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-fix-deadlock-in-remain-on-channel.patch b/queue-6.18/wifi-mt76-fix-deadlock-in-remain-on-channel.patch new file mode 100644 index 0000000000..932cd493e0 --- /dev/null +++ b/queue-6.18/wifi-mt76-fix-deadlock-in-remain-on-channel.patch @@ -0,0 +1,68 @@ +From b429abdb1adaf23a5f0e8577ee6f516756395547 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 14:31:32 +0000 +Subject: wifi: mt76: fix deadlock in remain-on-channel + +From: Chad Monroe + +[ Upstream commit 6939b97ddad3cf3dfbb3b5a0a12ef79cb886747e ] + +mt76_remain_on_channel() and mt76_roc_complete() call mt76_set_channel() +while already holding dev->mutex. Since mt76_set_channel() also acquires +dev->mutex, this results in a deadlock. + +Use __mt76_set_channel() instead of mt76_set_channel(). +Add cancel_delayed_work_sync() for mac_work before acquiring the mutex +in mt76_remain_on_channel() to prevent a secondary deadlock with the +mac_work workqueue. + +Fixes: a8f424c1287c ("wifi: mt76: add multi-radio remain_on_channel functions") +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/ace737e7b621af7c2adb33b0188011a5c1de2166.1765204256.git.chad@monroe.io +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/channel.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c +index 130af1b254dbf..eccaee1fd434f 100644 +--- a/drivers/net/wireless/mediatek/mt76/channel.c ++++ b/drivers/net/wireless/mediatek/mt76/channel.c +@@ -326,7 +326,7 @@ void mt76_roc_complete(struct mt76_phy *phy) + mlink->mvif->roc_phy = NULL; + if (phy->main_chandef.chan && + !test_bit(MT76_MCU_RESET, &dev->phy.state)) +- mt76_set_channel(phy, &phy->main_chandef, false); ++ __mt76_set_channel(phy, &phy->main_chandef, false); + mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); + phy->roc_vif = NULL; + phy->roc_link = NULL; +@@ -370,6 +370,8 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + if (!phy) + return -EINVAL; + ++ cancel_delayed_work_sync(&phy->mac_work); ++ + mutex_lock(&dev->mutex); + + if (phy->roc_vif || dev->scan.phy == phy || +@@ -388,7 +390,14 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + phy->roc_vif = vif; + phy->roc_link = mlink; + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); +- mt76_set_channel(phy, &chandef, true); ++ ret = __mt76_set_channel(phy, &chandef, true); ++ if (ret) { ++ mlink->mvif->roc_phy = NULL; ++ phy->roc_vif = NULL; ++ phy->roc_link = NULL; ++ mt76_put_vif_phy_link(phy, vif, mlink); ++ goto out; ++ } + ieee80211_ready_on_channel(hw); + ieee80211_queue_delayed_work(phy->hw, &phy->roc_work, + msecs_to_jiffies(duration)); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-fix-memory-leak-destroying-device.patch b/queue-6.18/wifi-mt76-fix-memory-leak-destroying-device.patch new file mode 100644 index 0000000000..0cde77f848 --- /dev/null +++ b/queue-6.18/wifi-mt76-fix-memory-leak-destroying-device.patch @@ -0,0 +1,56 @@ +From 8b501b59756feee61f6cd315dfb9b98dc98d5629 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 19:54:08 +0100 +Subject: wifi: mt76: Fix memory leak destroying device + +From: Lorenzo Bianconi + +[ Upstream commit 6b470f36616e3448d44b0ef4b1de2a3e3a31b5be ] + +All MT76 rx queues have an associated page_pool even if the queue is not +associated to a NAPI (e.g. WED RRO queues with WED enabled). Destroy the +page_pool running mt76_dma_cleanup routine during module unload. +Moreover returns pages to the page pool if WED is not enabled for WED RRO +queues. + +Fixes: 950d0abb5cd94 ("wifi: mt76: mt7996: add wed rx support") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251208-mt76-fix-memory-leak-v1-1-cba813fc62b8@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/dma.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c +index 1fa7de1d2c45e..9ef073c27f309 100644 +--- a/drivers/net/wireless/mediatek/mt76/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/dma.c +@@ -878,7 +878,12 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) + if (!buf) + break; + +- if (!mt76_queue_is_wed_rro(q)) ++ if (mtk_wed_device_active(&dev->mmio.wed) && ++ mt76_queue_is_wed_rro(q)) ++ continue; ++ ++ if (!mt76_queue_is_wed_rro_rxdmad_c(q) && ++ !mt76_queue_is_wed_rro_ind(q)) + mt76_put_page_pool_buf(buf, false); + } while (1); + +@@ -1169,10 +1174,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev) + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + +- if (mtk_wed_device_active(&dev->mmio.wed) && +- mt76_queue_is_wed_rro(q)) +- continue; +- + netif_napi_del(&dev->napi[i]); + mt76_dma_rx_cleanup(dev, q); + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-fix-multi-radio-on-channel-scanning.patch b/queue-6.18/wifi-mt76-fix-multi-radio-on-channel-scanning.patch new file mode 100644 index 0000000000..2de280268e --- /dev/null +++ b/queue-6.18/wifi-mt76-fix-multi-radio-on-channel-scanning.patch @@ -0,0 +1,85 @@ +From e45db32e227a3544a25d75435bf455b9f96b9417 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 06:07:20 +0000 +Subject: wifi: mt76: fix multi-radio on-channel scanning + +From: Chad Monroe + +[ Upstream commit 0420180df092419a96351fb2afec1e2a74d385c3 ] + +avoid unnecessary channel switch when performing an on-channel scan +using a multi-radio device. + +Fixes: c56d6edebc1f ("wifi: mt76: mt7996: use emulated hardware scan support") +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/20251118102723.47997-1-nbd@nbd.name +Link: https://patch.msgid.link/20260309060730.87840-1-nbd@nbd.name +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/scan.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c +index 3d9cf6f5e137f..efcf79d9d60e0 100644 +--- a/drivers/net/wireless/mediatek/mt76/scan.c ++++ b/drivers/net/wireless/mediatek/mt76/scan.c +@@ -16,7 +16,7 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) + + clear_bit(MT76_SCANNING, &phy->state); + +- if (dev->scan.chan && phy->main_chandef.chan && ++ if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel && + !test_bit(MT76_MCU_RESET, &dev->phy.state)) + mt76_set_channel(phy, &phy->main_chandef, false); + mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); +@@ -85,6 +85,7 @@ void mt76_scan_work(struct work_struct *work) + struct cfg80211_chan_def chandef = {}; + struct mt76_phy *phy = dev->scan.phy; + int duration = HZ / 9; /* ~110 ms */ ++ bool offchannel = true; + int i; + + if (dev->scan.chan_idx >= req->n_channels) { +@@ -92,7 +93,7 @@ void mt76_scan_work(struct work_struct *work) + return; + } + +- if (dev->scan.chan && phy->num_sta) { ++ if (dev->scan.chan && phy->num_sta && phy->offchannel) { + dev->scan.chan = NULL; + mt76_set_channel(phy, &phy->main_chandef, false); + goto out; +@@ -100,20 +101,26 @@ void mt76_scan_work(struct work_struct *work) + + dev->scan.chan = req->channels[dev->scan.chan_idx++]; + cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20); +- mt76_set_channel(phy, &chandef, true); ++ if (phy->main_chandef.chan == dev->scan.chan) { ++ chandef = phy->main_chandef; ++ offchannel = false; ++ } ++ ++ mt76_set_channel(phy, &chandef, offchannel); + + if (!req->n_ssids || + chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) + goto out; + +- duration = HZ / 16; /* ~60 ms */ ++ if (phy->offchannel) ++ duration = HZ / 16; /* ~60 ms */ + local_bh_disable(); + for (i = 0; i < req->n_ssids; i++) + mt76_scan_send_probe(dev, &req->ssids[i]); + local_bh_enable(); + + out: +- if (dev->scan.chan) ++ if (dev->scan.chan && phy->offchannel) + duration = max_t(int, duration, + msecs_to_jiffies(req->duration + + (req->duration >> 5))); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7615-fix-use_cts_prot-support.patch b/queue-6.18/wifi-mt76-mt7615-fix-use_cts_prot-support.patch new file mode 100644 index 0000000000..047e91e740 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7615-fix-use_cts_prot-support.patch @@ -0,0 +1,173 @@ +From 7384a984d854286663f4600a4fe8a80063850cb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 09:41:56 -0800 +Subject: wifi: mt76: mt7615: fix use_cts_prot support + +From: Ryder Lee + +[ Upstream commit 1974a67d9b65c29a0a9426e32e8cd8c056de48b7 ] + +Driver should not directly write WTBL to prevent overwritten issues. + +With this fix, when driver needs to adjust its behavior for compatibility, +especially concerning older 11g/n devices, by enabling or disabling CTS +protection frames, often for hidden SSIDs or to manage legacy clients. + +Fixes: e34235ccc5e3 ("wifi: mt76: mt7615: enable use_cts_prot support") +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/edb87088b0111b32fafc6c4179f54a5286dd37d8.1768879119.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7615/mac.c | 15 ------ + .../net/wireless/mediatek/mt76/mt7615/main.c | 7 +-- + .../net/wireless/mediatek/mt76/mt7615/mcu.c | 47 +++++++++++++++++++ + .../wireless/mediatek/mt76/mt7615/mt7615.h | 5 +- + .../net/wireless/mediatek/mt76/mt7615/regs.h | 2 - + 5 files changed, 53 insertions(+), 23 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +index f8d2cc94b742c..13c9dbeaee84e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +@@ -1167,21 +1167,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, + } + EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); + +-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, +- struct ieee80211_vif *vif, bool enable) +-{ +- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; +- u32 addr; +- +- addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4; +- +- if (enable) +- mt76_set(dev, addr, MT_WTBL_W3_RTS); +- else +- mt76_clear(dev, addr, MT_WTBL_W3_RTS); +-} +-EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); +- + static int + mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c +index 15fe155ac3f3b..87a2e5163699c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c +@@ -583,9 +583,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, + } + } + +- if (changed & BSS_CHANGED_ERP_CTS_PROT) +- mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot); +- + if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { + mt7615_mcu_add_bss_info(phy, vif, NULL, true); + mt7615_mcu_sta_add(phy, vif, NULL, true); +@@ -598,6 +595,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, + BSS_CHANGED_BEACON_ENABLED)) + mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); + ++ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) ++ mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode, ++ info->use_cts_prot); ++ + if (changed & BSS_CHANGED_PS) + mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +index 08ee2e861c4e2..91c9d787d553c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +@@ -2564,3 +2564,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, + return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), + &req, sizeof(req), false); + } ++ ++int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot) ++{ ++ struct mt7615_dev *dev = phy->dev; ++ struct { ++ u8 prot_idx; ++ u8 band; ++ u8 rsv[2]; ++ ++ bool long_nav; ++ bool prot_mm; ++ bool prot_gf; ++ bool prot_bw40; ++ bool prot_rifs; ++ bool prot_bw80; ++ bool prot_bw160; ++ u8 prot_erp_mask; ++ } __packed req = { ++ .prot_idx = 0x2, ++ .band = phy != &dev->phy, ++ }; ++ ++ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: ++ req.prot_mm = true; ++ req.prot_gf = true; ++ fallthrough; ++ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: ++ req.prot_bw40 = true; ++ break; ++ } ++ ++ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) ++ req.prot_gf = true; ++ ++ if (use_cts_prot) { ++ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; ++ u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; ++ ++ req.prot_erp_mask = BIT(i); ++ } ++ ++ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req, ++ sizeof(req), true); ++} +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +index 9bdd29e8d25e9..c655f64772de2 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +@@ -466,8 +466,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy); + void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); + void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); + void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); +-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, +- struct ieee80211_vif *vif, bool enable); + void mt7615_mac_sta_poll(struct mt7615_dev *dev); + int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, +@@ -522,7 +520,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); + int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); + int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); + int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); +- ++int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot); + int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +index 806b3887c541c..9e6d55c91b269 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +@@ -455,8 +455,6 @@ enum mt7615_reg_base { + #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) + #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) + +-#define MT_WTBL_W3_RTS BIT(22) +- + #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) + #define MT_WTBL_W5_SHORT_GI_20 BIT(8) + #define MT_WTBL_W5_SHORT_GI_40 BIT(9) +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch b/queue-6.18/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch new file mode 100644 index 0000000000..f2f20c6d7f --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch @@ -0,0 +1,53 @@ +From 3b5d3fd568f41dd1096cd261c03f40a731928fc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 22:57:59 +0800 +Subject: wifi: mt76: mt7915: fix use-after-free bugs in mt7915_mac_dump_work() + +From: Duoming Zhou + +[ Upstream commit 1146d0946b5358fad24812bd39d68f31cd40cc34 ] + +When the mt7915 pci chip is detaching, the mt7915_crash_data is +released in mt7915_coredump_unregister(). However, the work item +dump_work may still be running or pending, leading to UAF bugs +when the already freed crash_data is dereferenced again in +mt7915_mac_dump_work(). + +The race condition can occur as follows: + +CPU 0 (removal path) | CPU 1 (workqueue) +mt7915_pci_remove() | mt7915_sys_recovery_set() + mt7915_unregister_device() | mt7915_reset() + mt7915_coredump_unregister() | queue_work() + vfree(dev->coredump.crash_data) | mt7915_mac_dump_work() + | crash_data-> // UAF + +Fix this by ensuring dump_work is properly canceled before +the crash_data is deallocated. Add cancel_work_sync() in +mt7915_unregister_device() to synchronize with any pending +or executing dump work. + +Fixes: 4dbcb9125cc3 ("wifi: mt76: mt7915: enable coredump support") +Signed-off-by: Duoming Zhou +Link: https://patch.msgid.link/20260130145759.84272-1-duoming@zju.edu.cn +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +index 5ea8b46e092ef..d2b163a5fce5b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -1287,6 +1287,7 @@ int mt7915_register_device(struct mt7915_dev *dev) + + void mt7915_unregister_device(struct mt7915_dev *dev) + { ++ cancel_work_sync(&dev->dump_work); + mt7915_unregister_ext_phy(dev); + mt7915_coredump_unregister(dev); + mt7915_unregister_thermal(&dev->phy); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7915-fix-use_cts_prot-support.patch b/queue-6.18/wifi-mt76-mt7915-fix-use_cts_prot-support.patch new file mode 100644 index 0000000000..8f977ddcbe --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7915-fix-use_cts_prot-support.patch @@ -0,0 +1,195 @@ +From ee95a6b51afcf74dcb0d26a2a66b2121930e4873 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 09:41:57 -0800 +Subject: wifi: mt76: mt7915: fix use_cts_prot support + +From: Ryder Lee + +[ Upstream commit 8b2c26562b95c6397e132d21f2bd3d73aaee0c0a ] + +With this fix, when driver needs to adjust its behavior for compatibility, +especially concerning older 11g/n devices, by enabling or disabling CTS +protection frames, often for hidden SSIDs or to manage legacy clients. + +Fixes: 150b91419d3d ("wifi: mt76: mt7915: enable use_cts_prot support") +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/eb8db4d0bf1c89b7486e89facb788ae3e510dd8b.1768879119.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7915/mac.c | 13 ---- + .../net/wireless/mediatek/mt76/mt7915/main.c | 7 ++- + .../net/wireless/mediatek/mt76/mt7915/mcu.c | 62 +++++++++++++++++++ + .../net/wireless/mediatek/mt76/mt7915/mcu.h | 11 ++++ + .../wireless/mediatek/mt76/mt7915/mt7915.h | 4 ++ + 5 files changed, 81 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +index 5caf818e82834..9364e8673eb9d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +@@ -232,19 +232,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) + rcu_read_unlock(); + } + +-void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, +- struct ieee80211_vif *vif, bool enable) +-{ +- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; +- u32 addr; +- +- addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); +- if (enable) +- mt76_set(dev, addr, BIT(5)); +- else +- mt76_clear(dev, addr, BIT(5)); +-} +- + static void + mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, + struct mt7915_sta *msta, struct sk_buff *skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +index fe0639c14bf9b..6f594677474b0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +@@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw) + if (ret) + goto out; + +- ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, ++ ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES, + phy->mt76->band_idx); + if (ret) + goto out; +@@ -633,8 +633,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + if (set_sta == 1) + mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); + +- if (changed & BSS_CHANGED_ERP_CTS_PROT) +- mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); ++ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) ++ mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode, ++ info->use_cts_prot); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = 9; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +index c1fdd3c4f1ba6..79e021ac0bdbc 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -3852,6 +3852,68 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, + return ret; + } + ++int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot) ++{ ++ struct mt7915_dev *dev = phy->dev; ++ int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot); ++ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; ++ struct bss_info_prot *prot; ++ struct sk_buff *skb; ++ struct tlv *tlv; ++ enum { ++ PROT_NONMEMBER = BIT(1), ++ PROT_20MHZ = BIT(2), ++ PROT_NONHT_MIXED = BIT(3), ++ PROT_LEGACY_ERP = BIT(5), ++ PROT_NONGF_STA = BIT(7), ++ }; ++ u32 rts_threshold; ++ ++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, ++ NULL, len); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO, ++ sizeof(*prot)); ++ prot = (struct bss_info_prot *)tlv; ++ ++ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: ++ prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); ++ break; ++ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: ++ prot->prot_mode = cpu_to_le32(PROT_20MHZ); ++ break; ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: ++ prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); ++ break; ++ } ++ ++ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) ++ prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); ++ ++ if (use_cts_prot) ++ prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); ++ ++ /* reuse current RTS setting */ ++ rts_threshold = phy->mt76->hw->wiphy->rts_threshold; ++ if (rts_threshold == (u32)-1) ++ prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES); ++ else ++ prot->rts_len_thres = cpu_to_le32(rts_threshold); ++ ++ prot->rts_pkt_thres = 0x2; ++ ++ prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); ++ if (!prot->he_rts_thres) ++ prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); ++ ++ return mt76_mcu_skb_send_msg(&dev->mt76, skb, ++ MCU_EXT_CMD(BSS_INFO_UPDATE), true); ++} ++ + int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct cfg80211_he_bss_color *he_bss_color) + { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +index 086ad89ecd914..4049ed864003d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +@@ -399,6 +399,17 @@ struct bss_info_inband_discovery { + __le16 prob_rsp_len; + } __packed __aligned(4); + ++struct bss_info_prot { ++ __le16 tag; ++ __le16 len; ++ __le32 prot_type; ++ __le32 prot_mode; ++ __le32 rts_len_thres; ++ __le16 he_rts_thres; ++ u8 rts_pkt_thres; ++ u8 rsv[5]; ++} __packed; ++ + enum { + BSS_INFO_BCN_CSA, + BSS_INFO_BCN_BCC, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +index 2e94347c46d62..f1194d147dc89 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +@@ -83,6 +83,8 @@ + #define MT7915_CRIT_TEMP 110 + #define MT7915_MAX_TEMP 120 + ++#define MT7915_RTS_LEN_THRES 0x92b ++ + struct mt7915_vif; + struct mt7915_sta; + struct mt7915_dfs_pulse; +@@ -469,6 +471,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v + u32 changed); + int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int enable, u32 changed); ++int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot); + int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd); + int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch b/queue-6.18/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch new file mode 100644 index 0000000000..eae471b98b --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch @@ -0,0 +1,39 @@ +From 96bb89a19cf3f6b06aa3a44869dc0dd3ed588779 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 17:50:25 +0800 +Subject: wifi: mt76: mt7921: fix 6GHz regulatory update on connection + +From: Michael Lo + +[ Upstream commit 3dc0c40d7806c72cfe88cf4e1e2650c1673f9db4 ] + +Call mt7921_regd_update() instead of mt7921_mcu_set_clc() when setting +the 6GHz power type after connection, so that regulatory limits and SAR +power are also applied. + +Fixes: 51ba0e3a15eb ("wifi: mt76: mt7921: add 6GHz power type support for clc") +Signed-off-by: Michael Lo +Link: https://patch.msgid.link/20260211095025.2415624-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index 07495c97f1c12..ce11666a32db9 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -800,7 +800,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) + } + + out: +- mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env); ++ if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ) ++ mt7921_regd_update(dev); + } + + int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7921-fix-potential-deadlock-in-mt7921_ro.patch b/queue-6.18/wifi-mt76-mt7921-fix-potential-deadlock-in-mt7921_ro.patch new file mode 100644 index 0000000000..20cddd7fc1 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7921-fix-potential-deadlock-in-mt7921_ro.patch @@ -0,0 +1,61 @@ +From 84b781fe2ec0bec15e93df542e8dc76637f6ac54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 12:00:13 -0600 +Subject: wifi: mt76: mt7921: fix potential deadlock in mt7921_roc_abort_sync + +From: Sean Wang + +[ Upstream commit d5059e52fd8bc624ec4255c9fa01a266513d126b ] + +roc_abort_sync() can deadlock with roc_work(). roc_work() holds +dev->mt76.mutex, while cancel_work_sync() waits for roc_work() +to finish. If the caller already owns the same mutex, both +sides block and no progress is possible. + +This deadlock can occur during station removal when +mt76_sta_state() -> mt76_sta_remove() -> mt7921_mac_sta_remove() -> +mt7921_roc_abort_sync() invokes cancel_work_sync() while +roc_work() is still running and holding dev->mt76.mutex. + +This avoids the mutex deadlock and preserves exactly-once +work ownership. + +Fixes: 352d966126e6 ("wifi: mt76: mt7921: fix a potential association failure upon resuming") +Co-developed-by: Quan Zhou +Signed-off-by: Quan Zhou +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20260126180013.8167-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index ea6ff4c6bc90b..07495c97f1c12 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -371,12 +371,15 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev) + { + struct mt792x_phy *phy = &dev->phy; + ++ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) ++ return; ++ + timer_delete_sync(&phy->roc_timer); +- cancel_work_sync(&phy->roc_work); +- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) +- ieee80211_iterate_interfaces(mt76_hw(dev), +- IEEE80211_IFACE_ITER_RESUME_ALL, +- mt7921_roc_iter, (void *)phy); ++ cancel_work(&phy->roc_work); ++ ++ ieee80211_iterate_interfaces(mt76_hw(dev), ++ IEEE80211_IFACE_ITER_RESUME_ALL, ++ mt7921_roc_iter, (void *)phy); + } + EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync); + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch b/queue-6.18/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch new file mode 100644 index 0000000000..06c6a95751 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch @@ -0,0 +1,73 @@ +From b3209182015ce47602347d32ca2b2251080853ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Sep 2025 17:07:11 -0700 +Subject: wifi: mt76: mt7921: Place upper limit on station AID + +From: Rory Little + +[ Upstream commit 4d0bf21e3e20619d51d06c0c36207aabab8b712c ] + +Any station configured with an AID over 20 causes a firmware crash. +This situation occurred in our testing using an AP interface on 7922 +hardware, with a modified hostapd, sourced from Mediatek's OpenWRT +feeds. + +In stock hostapd, station AIDs begin counting at 1, and this +configuration is prevented with an upper limit on associated stations. +However, the modified hostapd began allocation at 65, which caused the +firmware to crash. This fix does not allow these AIDs to work, but will +prevent the firmware crash. + +This crash was only seen on IFTYPE_AP interfaces, and the fix does not +appear to have an effect on IFTYPE_STATION behavior. + +Fixes: 5c14a5f944b9 ("mt76: mt7921: introduce mt7921e support") +Signed-off-by: Rory Little +Link: https://patch.msgid.link/20250904000711.3033860-1-rory@candelatech.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 6 ++++++ + drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++ + 2 files changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index 5e676916593d3..ea6ff4c6bc90b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -808,6 +808,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + int ret, idx; + ++ if (sta->aid > MT7921_MAX_AID) ++ return -ENOENT; ++ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); + if (idx < 0) + return -ENOSPC; +@@ -851,6 +854,9 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + ++ if (sta->aid > MT7921_MAX_AID) ++ return -ENOENT; ++ + if (ev != MT76_STA_EVENT_ASSOC) + return 0; + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +index c88793fcec643..faa0d93982144 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +@@ -7,6 +7,8 @@ + #include "../mt792x.h" + #include "regs.h" + ++#define MT7921_MAX_AID 20 ++ + #define MT7921_TX_RING_SIZE 2048 + #define MT7921_TX_MCU_RING_SIZE 256 + #define MT7921_TX_FWDL_RING_SIZE 128 +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch b/queue-6.18/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch new file mode 100644 index 0000000000..a9befd24c0 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch @@ -0,0 +1,43 @@ +From ad557a19c8be2e1cdcaf33534b5bb11e79656419 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 18:59:30 -0600 +Subject: wifi: mt76: mt7921: Reset ampdu_state state in case of failure in + mt76_connac2_tx_check_aggr() + +From: Sean Wang + +[ Upstream commit 53ffffeb9624ffab6d9a3b1da8635a23f1172b5e ] + +Reset ampdu_state if ieee80211_start_tx_ba_session() fails in +mt76_connac2_tx_check_aggr(), otherwise the driver may incorrectly +assume aggregation is active and skip future BA setup attempts. + +Fixes: 163f4d22c118 ("mt76: mt7921: add MAC support") +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20251216005930.9412-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +index 837bd0f136fa1..b78cfa1324f3f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +@@ -1150,8 +1150,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) + return; + + wcid = (struct mt76_wcid *)sta->drv_priv; +- if (!test_and_set_bit(tid, &wcid->ampdu_state)) +- ieee80211_start_tx_ba_session(sta, tid, 0); ++ if (!test_and_set_bit(tid, &wcid->ampdu_state)) { ++ if (ieee80211_start_tx_ba_session(sta, tid, 0)) ++ clear_bit(tid, &wcid->ampdu_state); ++ } + } + EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7925-cqm-rssi-low-high-event-notify.patch b/queue-6.18/wifi-mt76-mt7925-cqm-rssi-low-high-event-notify.patch new file mode 100644 index 0000000000..e5fee5eaeb --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7925-cqm-rssi-low-high-event-notify.patch @@ -0,0 +1,222 @@ +From 08be20e39b0213a7f3deb0700c88fb3d94651b0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Oct 2025 09:25:06 +0800 +Subject: wifi: mt76: mt7925: cqm rssi low/high event notify + +From: Jack Kao + +[ Upstream commit 2a035ae2062f38dc5183002d1c5a64ca682170c1 ] + +The implementation amounts to setting the driver flag +IEEE80211_VIF_SUPPORTS_CQM_RSSI, and then providing +mechanisms for continuously updating enough information +to be able to provide notifications to userspace when +RSSI drops below a certain threshold + +Signed-off-by: Jack Kao +Signed-off-by: Ming Yen Hsieh +Link: https://patch.msgid.link/20251001012506.2168037-1-mingyen.hsieh@mediatek.com +Signed-off-by: Felix Fietkau +Stable-dep-of: 59a1864509d0 ("wifi: mt76: mt7925: drop puncturing handling from BSS change path") +Signed-off-by: Sasha Levin +--- + .../wireless/mediatek/mt76/mt76_connac_mcu.h | 2 + + .../net/wireless/mediatek/mt76/mt7925/main.c | 6 ++ + .../net/wireless/mediatek/mt76/mt7925/mcu.c | 82 +++++++++++++++++++ + .../net/wireless/mediatek/mt76/mt7925/mcu.h | 8 ++ + .../wireless/mediatek/mt76/mt7925/mt7925.h | 7 ++ + 5 files changed, 105 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +index 27daf419560a5..0b02f34c40a40 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +@@ -1062,6 +1062,7 @@ enum { + MCU_UNI_EVENT_ROC = 0x27, + MCU_UNI_EVENT_TX_DONE = 0x2d, + MCU_UNI_EVENT_THERMAL = 0x35, ++ MCU_UNI_EVENT_RSSI_MONITOR = 0x41, + MCU_UNI_EVENT_NIC_CAPAB = 0x43, + MCU_UNI_EVENT_WED_RRO = 0x57, + MCU_UNI_EVENT_PER_STA_INFO = 0x6d, +@@ -1300,6 +1301,7 @@ enum { + MCU_UNI_CMD_THERMAL = 0x35, + MCU_UNI_CMD_VOW = 0x37, + MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, ++ MCU_UNI_CMD_RSSI_MONITOR = 0x41, + MCU_UNI_CMD_TESTMODE_CTRL = 0x46, + MCU_UNI_CMD_RRO = 0x57, + MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index d1f63c81ceb99..f503e861a7e63 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -430,6 +430,9 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) + goto out; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; ++ if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN) ++ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI; ++ + out: + mt792x_mutex_release(dev); + +@@ -1958,6 +1961,9 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, + mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76, + link_conf, NULL); + ++ if (changed & BSS_CHANGED_CQM) ++ mt7925_mcu_set_rssimonitor(dev, vif); ++ + mt792x_mutex_release(dev); + } + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +index 130f1742546bc..d887aa9a3dff7 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +@@ -450,6 +450,56 @@ mt7925_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb) + } + } + ++static void ++mt7925_mcu_rssi_monitor_iter(void *priv, u8 *mac, ++ struct ieee80211_vif *vif) ++{ ++ struct mt7925_uni_rssi_monitor_event *event = priv; ++ enum nl80211_cqm_rssi_threshold_event nl_event; ++ s32 rssi = le32_to_cpu(event->rssi); ++ ++ if (vif->type != NL80211_IFTYPE_STATION) ++ return; ++ ++ if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) ++ return; ++ ++ if (rssi > vif->bss_conf.cqm_rssi_thold) ++ nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; ++ else ++ nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; ++ ++ ieee80211_cqm_rssi_notify(vif, nl_event, rssi, GFP_KERNEL); ++} ++ ++static void ++mt7925_mcu_rssi_monitor_event(struct mt792x_dev *dev, struct sk_buff *skb) ++{ ++ struct tlv *tlv; ++ u32 tlv_len; ++ struct mt7925_uni_rssi_monitor_event *event; ++ ++ skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); ++ tlv = (struct tlv *)skb->data; ++ tlv_len = skb->len; ++ ++ while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { ++ switch (le16_to_cpu(tlv->tag)) { ++ case UNI_EVENT_RSSI_MONITOR_INFO: ++ event = (struct mt7925_uni_rssi_monitor_event *)skb->data; ++ ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, ++ IEEE80211_IFACE_ITER_RESUME_ALL, ++ mt7925_mcu_rssi_monitor_iter, ++ event); ++ break; ++ default: ++ break; ++ } ++ tlv_len -= le16_to_cpu(tlv->len); ++ tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); ++ } ++} ++ + static void + mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb) + { +@@ -546,6 +596,9 @@ mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev, + case MCU_UNI_EVENT_BSS_BEACON_LOSS: + mt7925_mcu_connection_loss_event(dev, skb); + break; ++ case MCU_UNI_EVENT_RSSI_MONITOR: ++ mt7925_mcu_rssi_monitor_event(dev, skb); ++ break; + case MCU_UNI_EVENT_COREDUMP: + dev->fw_assert = true; + mt76_connac_mcu_coredump_event(&dev->mt76, skb, &dev->coredump); +@@ -3821,3 +3874,32 @@ int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG), + &req, sizeof(req), true); + } ++ ++int mt7925_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif) ++{ ++ struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(&vif->bss_conf); ++ struct { ++ struct { ++ u8 bss_idx; ++ u8 pad[3]; ++ } __packed hdr; ++ __le16 tag; ++ __le16 len; ++ u8 enable; ++ s8 cqm_rssi_high; ++ s8 cqm_rssi_low; ++ u8 rsv; ++ } req = { ++ .hdr = { ++ .bss_idx = mconf->mt76.idx, ++ }, ++ .tag = cpu_to_le16(UNI_CMD_RSSI_MONITOR_SET), ++ .len = cpu_to_le16(sizeof(req) - 4), ++ .enable = vif->cfg.assoc, ++ .cqm_rssi_high = (s8)(vif->bss_conf.cqm_rssi_thold + vif->bss_conf.cqm_rssi_hyst), ++ .cqm_rssi_low = (s8)(vif->bss_conf.cqm_rssi_thold - vif->bss_conf.cqm_rssi_hyst), ++ }; ++ ++ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(RSSI_MONITOR), &req, ++ sizeof(req), false); ++} +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +index a40764d89a1ff..148aa3c05c8c4 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +@@ -152,6 +152,14 @@ enum { + UNI_EVENT_SCAN_DONE_NLO = 3, + }; + ++enum { ++ UNI_CMD_RSSI_MONITOR_SET = 0, ++}; ++ ++enum { ++ UNI_EVENT_RSSI_MONITOR_INFO = 0, ++}; ++ + enum connac3_mcu_cipher_type { + CONNAC3_CIPHER_NONE = 0, + CONNAC3_CIPHER_WEP40 = 1, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +index 1c5ab3ea247d8..7f67e0a978726 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +@@ -103,6 +103,12 @@ struct mt7925_uni_beacon_loss_event { + struct mt7925_beacon_loss_tlv beacon_loss; + } __packed; + ++struct mt7925_uni_rssi_monitor_event { ++ __le16 tag; ++ __le16 len; ++ __le32 rssi; ++} __packed; ++ + #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) + #define to_rcpi(rssi) (2 * (rssi) + 220) + +@@ -372,4 +378,5 @@ int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int mt7925_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, + struct netlink_callback *cb, void *data, int len); + ++int mt7925_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif); + #endif +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7925-drop-puncturing-handling-from-bss-c.patch b/queue-6.18/wifi-mt76-mt7925-drop-puncturing-handling-from-bss-c.patch new file mode 100644 index 0000000000..67facaa642 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7925-drop-puncturing-handling-from-bss-c.patch @@ -0,0 +1,54 @@ +From f78863c601511ebc52b858703e20531069081bec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 20:20:17 -0600 +Subject: wifi: mt76: mt7925: drop puncturing handling from BSS change path + +From: Sean Wang + +[ Upstream commit 59a1864509d084a4b34117e693951c06b846b00a ] + +IEEE80211_CHANCTX_CHANGE_PUNCTURING is a channel context change +flag and should not be checked in the BSS change handler, where +the changed mask represents enum ieee80211_bss_change. + +Remove the puncturing handling from the BSS path and rely on +mt7925_change_chanctx() to update puncturing configuration. + +Fixes: cadebdad959b ("wifi: mt76: mt7925: add EHT preamble puncturing") +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20251216022017.23870-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index f503e861a7e63..ebb746f4072de 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1912,10 +1912,8 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; +- struct ieee80211_bss_conf *link_conf; + + mconf = mt792x_vif_to_link(mvif, info->link_id); +- link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); + + mt792x_mutex_acquire(dev); + +@@ -1957,10 +1955,6 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, + mvif->mlo_pm_state = MT792x_MLO_CHANGED_PS; + } + +- if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) +- mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76, +- link_conf, NULL); +- + if (changed & BSS_CHANGED_CQM) + mt7925_mcu_set_rssimonitor(dev, vif); + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch b/queue-6.18/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch new file mode 100644 index 0000000000..b066726b4a --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch @@ -0,0 +1,89 @@ +From cb1de6c7a1aa85f76e81dd380eeae95ff844cc99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 20:38:36 +0800 +Subject: wifi: mt76: mt7925: Fix incorrect MLO mode in firmware control + +From: Leon Yen + +[ Upstream commit 1695f662329faa07c860c73453c097823852df28 ] + +The selection of MLO mode should depend on the capabilities of the STA +rather than those of the peer AP to avoid compatibility issues with +certain APs, such as Xiaomi BE5000 WiFi7 router. + +Fixes: 69acd6d910b0c ("wifi: mt76: mt7925: add mt7925_change_vif_links") +Signed-off-by: Leon Yen +Link: https://patch.msgid.link/20251211123836.4169436-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 +- + drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 9 ++++++--- + drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 4 ++-- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index ac3d485a2f78f..d1f63c81ceb99 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -533,7 +533,7 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy, + + phy->roc_grant = false; + +- err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id); ++ err = mt7925_mcu_set_mlo_roc(phy, mconf, sel_links, 5, ++phy->roc_token_id); + if (err < 0) { + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + goto out; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +index e44c9ba168878..130f1742546bc 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +@@ -1243,8 +1243,8 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, + return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); + } + +-int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, +- int duration, u8 token_id) ++int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, ++ u16 sel_links, int duration, u8 token_id) + { + struct mt792x_vif *mvif = mconf->vif; + struct ieee80211_vif *vif = container_of((void *)mvif, +@@ -1279,6 +1279,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + .roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)) + }; + ++ struct wiphy *wiphy = phy->mt76->hw->wiphy; ++ + if (!mconf || hweight16(vif->valid_links) < 2 || + hweight16(sel_links) != 2) + return -EPERM; +@@ -1301,7 +1303,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ; + } + +- if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) ++ if (!(wiphy->iftype_ext_capab[0].mld_capa_and_ops & ++ IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS)) + type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : + MT7925_ROC_REQ_MLSR_AA; + else +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +index 1b165d0d8bd39..1c5ab3ea247d8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +@@ -345,8 +345,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, + int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); + int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap env_cap); +-int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, +- int duration, u8 token_id); ++int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, ++ u16 sel_links, int duration, u8 token_id); + int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + struct ieee80211_channel *chan, int duration, + enum mt7925_roc_req type, u8 token_id); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7925-fix-potential-deadlock-in-mt7925_ro.patch b/queue-6.18/wifi-mt76-mt7925-fix-potential-deadlock-in-mt7925_ro.patch new file mode 100644 index 0000000000..3ce1e60243 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7925-fix-potential-deadlock-in-mt7925_ro.patch @@ -0,0 +1,63 @@ +From 591c6718edad6cdd23277f13a48353eabb93f833 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 19:38:49 -0600 +Subject: wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync + +From: Sean Wang + +[ Upstream commit dd08ca3f092f4185ece69ce2a835c23198b1628a ] + +roc_abort_sync() can deadlock with roc_work(). roc_work() holds +dev->mt76.mutex, while cancel_work_sync() waits for roc_work() +to finish. If the caller already owns the same mutex, both +sides block and no progress is possible. + +This deadlock can occur during station removal when +mt76_sta_state() -> mt76_sta_remove() -> +mt7925_mac_sta_remove_link() -> mt7925_mac_link_sta_remove() -> +mt7925_roc_abort_sync() invokes cancel_work_sync() while +roc_work() is still running and holding dev->mt76.mutex. + +This avoids the mutex deadlock and preserves exactly-once +work ownership. + +Fixes: 45064d19fd3a ("wifi: mt76: mt7925: fix a potential association failure upon resuming") +Co-developed-by: Quan Zhou +Signed-off-by: Quan Zhou +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20251216013849.17976-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index ebb746f4072de..00126f563dfd9 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -452,12 +452,16 @@ void mt7925_roc_abort_sync(struct mt792x_dev *dev) + { + struct mt792x_phy *phy = &dev->phy; + ++ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) ++ return; ++ + timer_delete_sync(&phy->roc_timer); +- cancel_work_sync(&phy->roc_work); +- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) +- ieee80211_iterate_interfaces(mt76_hw(dev), +- IEEE80211_IFACE_ITER_RESUME_ALL, +- mt7925_roc_iter, (void *)phy); ++ ++ cancel_work(&phy->roc_work); ++ ++ ieee80211_iterate_interfaces(mt76_hw(dev), ++ IEEE80211_IFACE_ITER_RESUME_ALL, ++ mt7925_roc_iter, (void *)phy); + } + EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync); + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch b/queue-6.18/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch new file mode 100644 index 0000000000..4cd9717f89 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch @@ -0,0 +1,45 @@ +From fa3667b2c6176f69ae9f69b0e0fc57d2f86b187a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 11:06:48 +0800 +Subject: wifi: mt76: mt7925: prevent NULL pointer dereference in + mt7925_tx_check_aggr() + +From: Ming Yen Hsieh + +[ Upstream commit 83ae3a18ba957257b4c406273d2da2caeea2b439 ] + +Move the NULL check for 'sta' before dereferencing it to prevent a +possible crash. + +Fixes: 44eb173bdd4f ("wifi: mt76: mt7925: add link handling in mt7925_txwi_free") +Signed-off-by: Ming Yen Hsieh +Link: https://patch.msgid.link/20250904030649.655436-4-mingyen.hsieh@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +index a048ab1feef05..f12b8db739653 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +@@ -845,11 +845,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, + bool is_8023; + u16 fc, tid; + ++ if (!sta) ++ return; ++ + link_sta = rcu_dereference(sta->link[wcid->link_id]); + if (!link_sta) + return; + +- if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) ++ if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) + return; + + tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch b/queue-6.18/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch new file mode 100644 index 0000000000..2136365f3c --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch @@ -0,0 +1,41 @@ +From 82b80b3ea321584812ddb5582ef9bdd27e6705e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 11:06:47 +0800 +Subject: wifi: mt76: mt7925: prevent NULL vif dereference in + mt7925_mac_write_txwi + +From: Ming Yen Hsieh + +[ Upstream commit 962eb04e67552be406c906c83099c1d736aae3b6 ] + +Check for a NULL `vif` before accessing `ieee80211_vif_is_mld(vif)` to +avoid a potential kernel panic in scenarios where `vif` might not be +initialized. + +Fixes: ebb1406813c6 ("wifi: mt76: mt7925: add link handling to txwi") +Signed-off-by: Ming Yen Hsieh +Link: https://patch.msgid.link/20250904030649.655436-3-mingyen.hsieh@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +index f12b8db739653..0608f0c1fd2c2 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +@@ -803,8 +803,8 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, + txwi[5] = cpu_to_le32(val); + + val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); +- if (!ieee80211_vif_is_mld(vif) || +- (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)) ++ if (vif && (!ieee80211_vif_is_mld(vif) || ++ (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))) + val |= MT_TXD6_DIS_MAT; + txwi[6] = cpu_to_le32(val); + txwi[7] = 0; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-add-missing-chanctx_sta_csa-propert.patch b/queue-6.18/wifi-mt76-mt7996-add-missing-chanctx_sta_csa-propert.patch new file mode 100644 index 0000000000..91254a3b57 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-add-missing-chanctx_sta_csa-propert.patch @@ -0,0 +1,36 @@ +From 054425f6be3483d54802487db553683f275f7161 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Sep 2025 18:27:01 +0200 +Subject: wifi: mt76: mt7996: Add missing CHANCTX_STA_CSA property + +From: Lorenzo Bianconi + +[ Upstream commit c0a47ffc4caaf5161955add553322112c3a211b0 ] + +Enable missing CHANCTX_STA_CSA property required for MLO. + +Fixes: f5160304d57c ("wifi: mt76: mt7996: Enable MLO support for client interfaces") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20250928-mt7996_chanctx_sta_csa-v1-1-82e455185990@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index ba769e6de76d2..817acfad31d06 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -536,6 +536,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) + ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); + ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ++ ieee80211_hw_set(hw, CHANCTX_STA_CSA); + + hw->max_tx_fragments = 4; + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-clear-wcid-pointer-in-mt7996_mac_st.patch b/queue-6.18/wifi-mt76-mt7996-clear-wcid-pointer-in-mt7996_mac_st.patch new file mode 100644 index 0000000000..71621b1641 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-clear-wcid-pointer-in-mt7996_mac_st.patch @@ -0,0 +1,37 @@ +From cf02f106d0ba93db154714258137bdc0a96e7517 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:24:39 +0100 +Subject: wifi: mt76: mt7996: Clear wcid pointer in + mt7996_mac_sta_deinit_link() + +From: Lorenzo Bianconi + +[ Upstream commit 88973240dc7c976dd320b36a9e6d925c9be083ae ] + +Clear WCID pointer removing the sta link in mt7996_mac_sta_deinit_link +routine. + +Fixes: dd82a9e02c054 ("wifi: mt76: mt7996: Rely on mt7996_sta_link in sta_add/sta_remove callbacks") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251205-mt76-txq-wicd-fix-v2-4-f19ba48af7c1@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index 5d4b1d8f3335b..589b228a4eb0c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -1032,6 +1032,7 @@ void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, + list_del_init(&msta_link->rc_list); + spin_unlock_bh(&dev->mt76.sta_poll_lock); + ++ rcu_assign_pointer(dev->mt76.wcid[msta_link->wcid.idx], NULL); + mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); + mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx); + } +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-decrement-sta-counter-removing-the-.patch b/queue-6.18/wifi-mt76-mt7996-decrement-sta-counter-removing-the-.patch new file mode 100644 index 0000000000..fa4e1fd832 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-decrement-sta-counter-removing-the-.patch @@ -0,0 +1,47 @@ +From 0df38962170577c3a23e7c8c1fc6abc81d1d43f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 14:25:20 +0100 +Subject: wifi: mt76: mt7996: Decrement sta counter removing the link in + mt7996_mac_reset_sta_iter() + +From: Lorenzo Bianconi + +[ Upstream commit e648051d52afbdb360bd586218961f5fffff63e8 ] + +Fixes tracking per-phy stations for offchannel switching. + +Fixes: ace5d3b6b49e8 ("wifi: mt76: mt7996: improve hardware restart reliability") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260308-mt7996_mac_reset_vif_iter-fix-v1-1-57f640aa2dcf@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 3280446f7caa8..dce9f48637927 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2399,6 +2399,7 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) + + for (i = 0; i < ARRAY_SIZE(msta->link); i++) { + struct mt7996_sta_link *msta_link = NULL; ++ struct mt7996_phy *phy; + + msta_link = rcu_replace_pointer(msta->link[i], msta_link, + lockdep_is_held(&dev->mt76.mutex)); +@@ -2406,6 +2407,10 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) + continue; + + mt7996_mac_sta_deinit_link(dev, msta_link); ++ phy = __mt7996_phy(dev, msta_link->wcid.phy_idx); ++ if (phy) ++ phy->mt76->num_sta--; ++ + if (msta_link != &msta->deflink) + kfree_rcu(msta_link, rcu_head); + } +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch b/queue-6.18/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch new file mode 100644 index 0000000000..e80ec89154 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch @@ -0,0 +1,44 @@ +From 4f3593629bf5adbadd4101de74aac99f04ff9070 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Oct 2025 02:08:24 -0700 +Subject: wifi: mt76: mt7996: fix FCS error flag check in RX descriptor + +From: Alok Tiwari + +[ Upstream commit d8db56142e531f060c938fa0b5175ed6c8cabb11 ] + +The mt7996 driver currently checks the MT_RXD3_NORMAL_FCS_ERR bit in +rxd1 whereas other Connac3-based drivers(mt7925) correctly check this +bit in rxd3. + +Since the MT_RXD3_NORMAL_FCS_ERR bit is defined in the fourth RX +descriptor word (rxd3), update mt7996 to use the proper descriptor +field. This change aligns mt7996 with mt7925 and the rest of the +Connac3 family. + +Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: Alok Tiwari +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251013090826.753992-1-alok.a.tiwari@oracle.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 15d796702a589..2aa8bb779b228 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -527,7 +527,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + +- if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) ++ if (rxd3 & MT_RXD3_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-iface-combination-for-different.patch b/queue-6.18/wifi-mt76-mt7996-fix-iface-combination-for-different.patch new file mode 100644 index 0000000000..827ecd9e32 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-iface-combination-for-different.patch @@ -0,0 +1,58 @@ +From d18c1d95f21c40bacb88af45038da8206767d5d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 14:37:28 +0800 +Subject: wifi: mt76: mt7996: fix iface combination for different chipsets + +From: Shayne Chen + +[ Upstream commit 5ef0e8e2653b1ba325eb883ffb94073f19cb669a ] + +MT7992 and MT7990 support up to 19 interfaces per band and 32 in total. + +Fixes: 8df63a4bbe3d ("wifi: mt76: mt7996: adjust interface num and wtbl size for mt7992") +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20251215063728.3013365-7-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/init.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index b136b9a669769..e26f8e9e4f8fc 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -34,6 +34,20 @@ static const struct ieee80211_iface_combination if_comb_global = { + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), ++ .beacon_int_min_gcd = 100, ++}; ++ ++static const struct ieee80211_iface_combination if_comb_global_7992 = { ++ .limits = &if_limits_global, ++ .n_limits = 1, ++ .max_interfaces = 32, ++ .num_different_channels = MT7996_MAX_RADIOS - 1, ++ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | ++ BIT(NL80211_CHAN_WIDTH_20) | ++ BIT(NL80211_CHAN_WIDTH_40) | ++ BIT(NL80211_CHAN_WIDTH_80) | ++ BIT(NL80211_CHAN_WIDTH_160), ++ .beacon_int_min_gcd = 100, + }; + + static const struct ieee80211_iface_limit if_limits[] = { +@@ -485,7 +499,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) + hw->vif_data_size = sizeof(struct mt7996_vif); + hw->chanctx_data_size = sizeof(struct mt76_chanctx); + +- wiphy->iface_combinations = &if_comb_global; ++ wiphy->iface_combinations = is_mt7996(&dev->mt76) ? &if_comb_global : ++ &if_comb_global_7992; + wiphy->n_iface_combinations = 1; + + wiphy->radio = dev->radios; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-rro-emu-configuration.patch b/queue-6.18/wifi-mt76-mt7996-fix-rro-emu-configuration.patch new file mode 100644 index 0000000000..7c853688f1 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-rro-emu-configuration.patch @@ -0,0 +1,54 @@ +From 965522a3ac498f86213ac2c141568272db50bba2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:57:19 +0800 +Subject: wifi: mt76: mt7996: fix RRO EMU configuration + +From: Peter Chiu + +[ Upstream commit 73b46379e5231138025b271ce8e158d2a8aa0768 ] + +Use the correct helper to update specific bitfields instead of +overwriting the entire register. + +Fixes: eedb427eb260 ("wifi: mt76: mt7996: Enable HW RRO for MT7992 chipset") +Signed-off-by: Peter Chiu +Signed-off-by: Shayne Chen +Acked-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260312095724.2117448-1-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +-- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index 817acfad31d06..efbd46d649017 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -857,8 +857,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev) + } + } else { + /* set emul 3.0 function */ +- mt76_wr(dev, MT_RRO_3_0_EMU_CONF, +- MT_RRO_3_0_EMU_CONF_EN_MASK); ++ mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); + + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0, + dev->wed_rro.addr_elem[0].phy_addr); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index c375b4dd68a20..149d8d711fc4c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2597,7 +2597,7 @@ void mt7996_mac_reset_work(struct work_struct *work) + mt7996_dma_start(dev, false, false); + + if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3) +- mt76_wr(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); ++ mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 | +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch b/queue-6.18/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch new file mode 100644 index 0000000000..ddd73e951d --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch @@ -0,0 +1,53 @@ +From cd47409bdc923cf855adba34fc02b7ee3e67e4df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:30 +0800 +Subject: wifi: mt76: mt7996: fix struct mt7996_mcu_uni_event + +From: StanleyYP Wang + +[ Upstream commit efbd5bf395f4e6b45a87f3835d4c2e28170c77c5 ] + +The cid field is defined as a two-byte value in the firmware. + +Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: StanleyYP Wang +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-2-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 321098496a39e..c2d15128784bc 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -233,7 +233,7 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + event = (struct mt7996_mcu_uni_event *)skb->data; + ret = le32_to_cpu(event->status); + /* skip invalid event */ +- if (mcu_cmd != event->cid) ++ if (mcu_cmd != le16_to_cpu(event->cid)) + ret = -EAGAIN; + } else { + skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +index abfd7e5a775b3..7b51d7346bcaa 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +@@ -25,8 +25,8 @@ struct mt7996_mcu_rxd { + }; + + struct mt7996_mcu_uni_event { +- u8 cid; +- u8 __rsv[3]; ++ __le16 cid; ++ u8 __rsv[2]; + __le32 status; /* 0: success, others: fail */ + } __packed; + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-the-behavior-of-radar-detection.patch b/queue-6.18/wifi-mt76-mt7996-fix-the-behavior-of-radar-detection.patch new file mode 100644 index 0000000000..9058e3fefe --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-the-behavior-of-radar-detection.patch @@ -0,0 +1,214 @@ +From cdcf4c5353e03c5ceb3c486fc1eb040ab6a4fde8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 14:37:23 +0800 +Subject: wifi: mt76: mt7996: fix the behavior of radar detection + +From: StanleyYP Wang + +[ Upstream commit 45a09251d610f3b8a1fb02039146e42f1f4efe90 ] + +RDD_DET_MODE is a firmware command intended for testing and does not +pause TX after radar detection, so remove it from the normal flow; +instead, use the MAC_ENABLE_CTRL firmware command to resume TX after +the radar-triggered channel switch completes. + +Fixes: 1529e335f93d ("wifi: mt76: mt7996: rework radar HWRDD idx") +Co-developed-by: Shayne Chen +Signed-off-by: Shayne Chen +Signed-off-by: StanleyYP Wang +Link: https://patch.msgid.link/20251215063728.3013365-2-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/mac.c | 8 +-- + .../net/wireless/mediatek/mt76/mt7996/main.c | 20 ++++++++ + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 49 ++++++++++++++++--- + .../net/wireless/mediatek/mt76/mt7996/mcu.h | 1 + + .../wireless/mediatek/mt76/mt7996/mt7996.h | 2 + + 5 files changed, 68 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 0958961d2758e..24b404f35409b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2944,7 +2944,7 @@ static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy) + + static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) + { +- int err, region; ++ int region; + + switch (dev->mt76.region) { + case NL80211_DFS_ETSI: +@@ -2959,11 +2959,7 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) + break; + } + +- err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); +- if (err < 0) +- return err; +- +- return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1); ++ return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); + } + + static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index 2ad52ae2c5f55..2c8a088a170c6 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -79,6 +79,7 @@ static void mt7996_stop_phy(struct mt7996_phy *phy) + + mutex_lock(&dev->mt76.mutex); + ++ mt7996_mcu_rdd_resume_tx(phy); + mt7996_mcu_set_radio_en(phy, false); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); +@@ -933,6 +934,24 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw, + mutex_unlock(&dev->mt76.mutex); + } + ++static int ++mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ struct ieee80211_bss_conf *link_conf) ++{ ++ struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; ++ struct mt7996_dev *dev = mt7996_hw_dev(hw); ++ struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band); ++ int ret; ++ ++ mutex_lock(&dev->mt76.mutex); ++ ++ ret = mt7996_mcu_rdd_resume_tx(phy); ++ ++ mutex_unlock(&dev->mt76.mutex); ++ ++ return ret; ++} ++ + static int + mt7996_mac_sta_init_link(struct mt7996_dev *dev, + struct ieee80211_bss_conf *link_conf, +@@ -2295,6 +2314,7 @@ const struct ieee80211_ops mt7996_ops = { + .release_buffered_frames = mt76_release_buffered_frames, + .get_txpower = mt7996_get_txpower, + .channel_switch_beacon = mt7996_channel_switch_beacon, ++ .post_channel_switch = mt7996_post_channel_switch, + .get_stats = mt7996_get_stats, + .get_et_sset_count = mt7996_get_et_sset_count, + .get_et_stats = mt7996_get_et_stats, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 5bde9959bbb99..321098496a39e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -413,24 +413,32 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) + break; + case MT_RDD_IDX_BACKGROUND: + if (!dev->rdd2_phy) +- return; ++ goto err; + mphy = dev->rdd2_phy->mt76; + break; + default: +- dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx); +- return; ++ goto err; + } + + if (!mphy) +- return; ++ goto err; + +- if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) ++ if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) { + cfg80211_background_radar_event(mphy->hw->wiphy, + &dev->rdd2_chandef, + GFP_ATOMIC); +- else ++ } else { ++ struct mt7996_phy *phy = mphy->priv; ++ ++ phy->rdd_tx_paused = true; + ieee80211_radar_detected(mphy->hw, NULL); ++ } + dev->hw_pattern++; ++ ++ return; ++ ++err: ++ dev_err(dev->mt76.dev, "Invalid RDD idx %d\n", r->rdd_idx); + } + + static void +@@ -4554,6 +4562,35 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable) + &req, sizeof(req), true); + } + ++int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy) ++{ ++ struct { ++ u8 band_idx; ++ u8 _rsv[3]; ++ ++ __le16 tag; ++ __le16 len; ++ u8 mac_enable; ++ u8 _rsv2[3]; ++ } __packed req = { ++ .band_idx = phy->mt76->band_idx, ++ .tag = cpu_to_le16(UNI_BAND_CONFIG_MAC_ENABLE_CTRL), ++ .len = cpu_to_le16(sizeof(req) - 4), ++ .mac_enable = 2, ++ }; ++ int ret; ++ ++ if (!phy->rdd_tx_paused) ++ return 0; ++ ++ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG), ++ &req, sizeof(req), true); ++ if (!ret) ++ phy->rdd_tx_paused = false; ++ ++ return ret; ++} ++ + int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val) + { + struct { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +index c841da1c60e5d..abfd7e5a775b3 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +@@ -837,6 +837,7 @@ enum { + enum { + UNI_BAND_CONFIG_RADIO_ENABLE, + UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, ++ UNI_BAND_CONFIG_MAC_ENABLE_CTRL = 0x0c, + }; + + enum { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +index b942928c79e28..6190fbcd4df7e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +@@ -376,6 +376,7 @@ struct mt7996_phy { + + bool has_aux_rx; + bool counter_reset; ++ bool rdd_tx_paused; + }; + + struct mt7996_dev { +@@ -725,6 +726,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy); + int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); + int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); + int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); ++int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy); + int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val); + int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, + struct cfg80211_chan_def *chandef); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch b/queue-6.18/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch new file mode 100644 index 0000000000..2676ca1285 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch @@ -0,0 +1,53 @@ +From f9344435701d076731dfe1a3d589f7878f0f3685 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 10:47:31 +0800 +Subject: wifi: mt76: mt7996: fix use-after-free bugs in mt7996_mac_dump_work() + +From: Duoming Zhou + +[ Upstream commit c8f62f73bbced3a79894655bdb0b625462d956fc ] + +When the mt7996 pci chip is detaching, the mt7996_crash_data is +released in mt7996_coredump_unregister(). However, the work item +dump_work may still be running or pending, leading to UAF bugs +when the already freed crash_data is dereferenced again in +mt7996_mac_dump_work(). + +The race condition can occur as follows: + +CPU 0 (removal path) | CPU 1 (workqueue) +mt7996_pci_remove() | mt7996_sys_recovery_set() + mt7996_unregister_device() | mt7996_reset() + mt7996_coredump_unregister() | queue_work() + vfree(dev->coredump.crash_data) | mt7996_mac_dump_work() + | crash_data-> // UAF + +Fix this by ensuring dump_work is properly canceled before +the crash_data is deallocated. Add cancel_work_sync() in +mt7996_unregister_device() to synchronize with any pending +or executing dump work. + +Fixes: 878161d5d4a4 ("wifi: mt76: mt7996: enable coredump support") +Signed-off-by: Duoming Zhou +Link: https://patch.msgid.link/20260131024731.18741-1-duoming@zju.edu.cn +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index e26f8e9e4f8fc..ba769e6de76d2 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -1732,6 +1732,7 @@ int mt7996_register_device(struct mt7996_dev *dev) + + void mt7996_unregister_device(struct mt7996_dev *dev) + { ++ cancel_work_sync(&dev->dump_work); + cancel_work_sync(&dev->wed_rro.work); + mt7996_unregister_phy(mt7996_phy3(dev)); + mt7996_unregister_phy(mt7996_phy2(dev)); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-fix-wrong-dmad-length-when-using-ma.patch b/queue-6.18/wifi-mt76-mt7996-fix-wrong-dmad-length-when-using-ma.patch new file mode 100644 index 0000000000..5a7cca088d --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-fix-wrong-dmad-length-when-using-ma.patch @@ -0,0 +1,50 @@ +From 6b8b811adc43bf61c665946f8daa2a6b3374eeb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:29 +0800 +Subject: wifi: mt76: mt7996: fix wrong DMAD length when using MAC TXP + +From: Shayne Chen + +[ Upstream commit 97b9f9831bf297f3ffa62018721601ed2736f2c3 ] + +The struct mt76_connac_fw_txp is used for HIF TXP. Change to use the +struct mt76_connac_hw_txp to fix the wrong DMAD length for MAC TXP. + +Fixes: cb6ebbdffef2 ("wifi: mt76: mt7996: support writing MAC TXD for AddBA Request") +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-1-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 2aa8bb779b228..0b5194e708b3a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -1109,10 +1109,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + * req + */ + if (le32_to_cpu(ptr[7]) & MT_TXD7_MAC_TXD) { +- u32 val; ++ u32 val, mac_txp_size = sizeof(struct mt76_connac_hw_txp); + + ptr = (__le32 *)(txwi + MT_TXD_SIZE); +- memset((void *)ptr, 0, sizeof(struct mt76_connac_fw_txp)); ++ memset((void *)ptr, 0, mac_txp_size); + + val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) | + MT_TXP0_TOKEN_ID0_VALID_MASK; +@@ -1131,6 +1131,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + tx_info->buf[1].addr >> 32); + #endif + ptr[3] = cpu_to_le32(val); ++ ++ tx_info->buf[0].len = MT_TXD_SIZE + mac_txp_size; + } else { + struct mt76_connac_txp_common *txp; + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-remove-link-pointer-dependency-in-m.patch b/queue-6.18/wifi-mt76-mt7996-remove-link-pointer-dependency-in-m.patch new file mode 100644 index 0000000000..d9236e51e6 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-remove-link-pointer-dependency-in-m.patch @@ -0,0 +1,62 @@ +From 32b54344b684d19664fe7004d99efce37f1e09f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 11:27:52 +0100 +Subject: wifi: mt76: mt7996: Remove link pointer dependency in + mt7996_mac_sta_remove_links() + +From: Lorenzo Bianconi + +[ Upstream commit 569ce4340268915911fc356ec9ad27e92fb82289 ] + +Remove link pointer dependency in mt7996_mac_sta_remove_links routine to +get the mt7996_phy pointer since the link can be already offchannel +running mt7996_mac_sta_remove_links(). Rely on __mt7996_phy routine +instead. + +Fixes: 344dd6a4c919 ("wifi: mt76: mt7996: Move num_sta accounting in mt7996_mac_sta_{add,remove}_links") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260306-mt7996-deflink-lookup-link-remove-v1-1-7162b332873c@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 14 ++++---------- + 1 file changed, 4 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index 589b228a4eb0c..32d44540605fc 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -1047,8 +1047,7 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_sta_link *msta_link = NULL; +- struct mt7996_vif_link *link; +- struct mt76_phy *mphy; ++ struct mt7996_phy *phy; + + msta_link = rcu_replace_pointer(msta->link[link_id], msta_link, + lockdep_is_held(&mdev->mutex)); +@@ -1057,17 +1056,12 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + + mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); +- + mt7996_mac_sta_deinit_link(dev, msta_link); +- link = mt7996_vif_link(dev, vif, link_id); +- if (!link) +- continue; + +- mphy = mt76_vif_link_phy(&link->mt76); +- if (!mphy) +- continue; ++ phy = __mt7996_phy(dev, msta_link->wcid.phy_idx); ++ if (phy) ++ phy->mt76->num_sta--; + +- mphy->num_sta--; + if (msta->deflink_id == link_id) { + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + continue; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-reset-ampdu_state-state-in-case-of-.patch b/queue-6.18/wifi-mt76-mt7996-reset-ampdu_state-state-in-case-of-.patch new file mode 100644 index 0000000000..30bc1d21ec --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-reset-ampdu_state-state-in-case-of-.patch @@ -0,0 +1,41 @@ +From 7b79762e9ccfdf57947f232e69562dc57c3c07b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 10:55:30 +0100 +Subject: wifi: mt76: mt7996: Reset ampdu_state state in case of failure in + mt7996_tx_check_aggr() + +From: Lorenzo Bianconi + +[ Upstream commit c0747db7c10c2dfbdcff0e8e97021e3df1f1e362 ] + +Reset the ampdu_state configured state if ieee80211_start_tx_ba_session +routine fails in mt7996_tx_check_aggr() + +Fixes: 98686cd21624c ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251214-mt7996-aggr-check-fix-v1-1-33a8b62ec0fc@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 24b404f35409b..15d796702a589 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -1243,8 +1243,9 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta, + if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) + return; + +- if (!test_and_set_bit(tid, &wcid->ampdu_state)) +- ieee80211_start_tx_ba_session(link_sta->sta, tid, 0); ++ if (!test_and_set_bit(tid, &wcid->ampdu_state) && ++ ieee80211_start_tx_ba_session(link_sta->sta, tid, 0)) ++ clear_bit(tid, &wcid->ampdu_state); + } + + static void +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-reset-mtxq-idx-if-primary-link-is-r.patch b/queue-6.18/wifi-mt76-mt7996-reset-mtxq-idx-if-primary-link-is-r.patch new file mode 100644 index 0000000000..a364e816ab --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-reset-mtxq-idx-if-primary-link-is-r.patch @@ -0,0 +1,63 @@ +From fa4214324d7a2b8cabc3561b4f6d69aa911cc0b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:24:37 +0100 +Subject: wifi: mt76: mt7996: Reset mtxq->idx if primary link is removed in + mt7996_vif_link_remove() + +From: Lorenzo Bianconi + +[ Upstream commit 751a2679b15e3a0fa8fc9175862f0ec40643db68 ] + +Reset WCID index in mt76_txq struct if primary link is removed in +mt7996_vif_link_remove routine. + +Fixes: a3316d2fc669f ("wifi: mt76: mt7996: set vif default link_id adding/removing vif links") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251205-mt76-txq-wicd-fix-v2-2-f19ba48af7c1@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/main.c | 21 ++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index 44c52062c640b..5d4b1d8f3335b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -402,17 +402,28 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, + + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + +- if (!mlink->wcid->offchannel && ++ if (vif->txq && !mlink->wcid->offchannel && + mvif->mt76.deflink_id == link_conf->link_id) { + struct ieee80211_bss_conf *iter; ++ struct mt76_txq *mtxq; + unsigned int link_id; + + mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED; ++ mtxq = (struct mt76_txq *)vif->txq->drv_priv; ++ /* Primary link will be removed, look for a new one */ + for_each_vif_active_link(vif, iter, link_id) { +- if (link_id != IEEE80211_LINK_UNSPECIFIED) { +- mvif->mt76.deflink_id = link_id; +- break; +- } ++ struct mt7996_vif_link *link; ++ ++ if (link_id == link_conf->link_id) ++ continue; ++ ++ link = mt7996_vif_link(dev, vif, link_id); ++ if (!link) ++ continue; ++ ++ mtxq->wcid = link->msta_link.wcid.idx; ++ mvif->mt76.deflink_id = link_id; ++ break; + } + } + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-set-mtxq-wcid-just-for-primary-link.patch b/queue-6.18/wifi-mt76-mt7996-set-mtxq-wcid-just-for-primary-link.patch new file mode 100644 index 0000000000..9f92cd698d --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-set-mtxq-wcid-just-for-primary-link.patch @@ -0,0 +1,64 @@ +From 2c8d090fb8a0a9dc08ff8a345b32554882e1de0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:24:36 +0100 +Subject: wifi: mt76: mt7996: Set mtxq->wcid just for primary link + +From: Lorenzo Bianconi + +[ Upstream commit 654abcbe4528f74428b69292fad5c4224414fa1b ] + +Set WCID index in mt76_txq struct just for the primary link in +mt7996_vif_link_add routine. + +Fixes: 69d54ce7491d0 ("wifi: mt76: mt7996: switch to single multi-radio wiphy") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251205-mt76-txq-wicd-fix-v2-1-f19ba48af7c1@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index 2c8a088a170c6..44c52062c640b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -301,7 +301,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + .cmd = SET_KEY, + .link_id = link_conf->link_id, + }; +- struct mt76_txq *mtxq; + int mld_idx, idx, ret; + + mlink->idx = __ffs64(~dev->mt76.vif_mask); +@@ -344,11 +343,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + mt7996_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + +- if (vif->txq) { +- mtxq = (struct mt76_txq *)vif->txq->drv_priv; +- mtxq->wcid = idx; +- } +- + if (vif->type != NL80211_IFTYPE_AP && + (!mlink->omac_idx || mlink->omac_idx > 3)) + vif->offload_flags = 0; +@@ -371,9 +365,13 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + + ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); + +- if (!mlink->wcid->offchannel && +- mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) ++ if (vif->txq && !mlink->wcid->offchannel && ++ mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) { ++ struct mt76_txq *mtxq = (struct mt76_txq *)vif->txq->drv_priv; ++ + mvif->mt76.deflink_id = link_conf->link_id; ++ mtxq->wcid = idx; ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-switch-to-the-secondary-link-if-the.patch b/queue-6.18/wifi-mt76-mt7996-switch-to-the-secondary-link-if-the.patch new file mode 100644 index 0000000000..cf437a1a4d --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-switch-to-the-secondary-link-if-the.patch @@ -0,0 +1,134 @@ +From d93b218f9a75f59e7a7f1b6af525fe484123a71d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:24:38 +0100 +Subject: wifi: mt76: mt7996: Switch to the secondary link if the default one + is removed + +From: Lorenzo Bianconi + +[ Upstream commit 5ef44c200618430b004233cbfc1b0929a13d5ac8 ] + +Switch to the secondary link if available in mt7996_mac_sta_remove_links +routine if the primary one is removed. +Moreover reset secondary link index for single link scenario. + +Fixes: 85cd5534a3f2e ("wifi: mt76: mt7996: use correct link_id when filling TXD and TXP") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251205-mt76-txq-wicd-fix-v2-3-f19ba48af7c1@kernel.org +Signed-off-by: Felix Fietkau +Stable-dep-of: e648051d52af ("wifi: mt76: mt7996: Decrement sta counter removing the link in mt7996_mac_reset_sta_iter()") +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/mac.c | 12 ++--- + .../net/wireless/mediatek/mt76/mt7996/main.c | 51 +++++++++++++------ + 2 files changed, 41 insertions(+), 22 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 13a3b521437be..3280446f7caa8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2406,14 +2406,12 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) + continue; + + mt7996_mac_sta_deinit_link(dev, msta_link); +- +- if (msta->deflink_id == i) { +- msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; +- continue; +- } +- +- kfree_rcu(msta_link, rcu_head); ++ if (msta_link != &msta->deflink) ++ kfree_rcu(msta_link, rcu_head); + } ++ ++ msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; ++ msta->seclink_id = msta->deflink_id; + } + + static void +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index af322f505f8ab..d714b7f3efe56 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -961,6 +961,22 @@ mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + return ret; + } + ++static void ++mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { ++ struct mt76_txq *mtxq; ++ ++ if (!sta->txq[i]) ++ continue; ++ ++ mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; ++ mtxq->wcid = idx; ++ } ++} ++ + static int + mt7996_mac_sta_init_link(struct mt7996_dev *dev, + struct ieee80211_bss_conf *link_conf, +@@ -978,21 +994,10 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, + return -ENOSPC; + + if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { +- int i; +- + msta_link = &msta->deflink; + msta->deflink_id = link_id; + msta->seclink_id = msta->deflink_id; +- +- for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { +- struct mt76_txq *mtxq; +- +- if (!sta->txq[i]) +- continue; +- +- mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; +- mtxq->wcid = idx; +- } ++ mt7996_sta_init_txq_wcid(sta, idx); + } else { + msta_link = kzalloc(sizeof(*msta_link), GFP_KERNEL); + if (!msta_link) +@@ -1070,12 +1075,28 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + + if (msta->deflink_id == link_id) { + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; +- continue; ++ if (msta->seclink_id == link_id) { ++ /* no secondary link available */ ++ msta->seclink_id = msta->deflink_id; ++ } else { ++ struct mt7996_sta_link *msta_seclink; ++ ++ /* switch to the secondary link */ ++ msta_seclink = mt76_dereference( ++ msta->link[msta->seclink_id], ++ mdev); ++ if (msta_seclink) { ++ msta->deflink_id = msta->seclink_id; ++ mt7996_sta_init_txq_wcid(sta, ++ msta_seclink->wcid.idx); ++ } ++ } + } else if (msta->seclink_id == link_id) { +- msta->seclink_id = IEEE80211_LINK_UNSPECIFIED; ++ msta->seclink_id = msta->deflink_id; + } + +- kfree_rcu(msta_link, rcu_head); ++ if (msta_link != &msta->deflink) ++ kfree_rcu(msta_link, rcu_head); + } + } + +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-mt7996-use-correct-link_id-when-filling-tx.patch b/queue-6.18/wifi-mt76-mt7996-use-correct-link_id-when-filling-tx.patch new file mode 100644 index 0000000000..2645f843a8 --- /dev/null +++ b/queue-6.18/wifi-mt76-mt7996-use-correct-link_id-when-filling-tx.patch @@ -0,0 +1,171 @@ +From 396b4a9dbd9a58938d088c75465c72a0ebfe9b1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Nov 2025 14:41:59 +0800 +Subject: wifi: mt76: mt7996: use correct link_id when filling TXD and TXP + +From: Shayne Chen + +[ Upstream commit 85cd5534a3f2ec93e7d88713a77df5b4255520df ] + +Obtain the correct link ID and, if needed, switch to the corresponding +wcid before populating the TX descriptor and TX payload. + +Rules for link id: +- For QoS data of MLD peers (excluding EAPOL), select the primary or + secondary wcid based on whether the TID is odd or even to meet FW/HW + requirements +- For other packets, use IEEE80211_TX_CTRL_MLO_LINK if specified + (such as multicast and broadcast packets) + +Signed-off-by: Shayne Chen +Acked-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251106064203.1000505-8-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Stable-dep-of: e648051d52af ("wifi: mt76: mt7996: Decrement sta counter removing the link in mt7996_mac_reset_sta_iter()") +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/mac.c | 34 ++++++++++++++++--- + .../net/wireless/mediatek/mt76/mt7996/main.c | 9 +++++ + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 4 +-- + .../wireless/mediatek/mt76/mt7996/mt7996.h | 1 + + 4 files changed, 42 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 0b5194e708b3a..13a3b521437be 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -1040,15 +1040,20 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) + { ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; + struct ieee80211_vif *vif = info->control.vif; ++ struct mt7996_vif *mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL; ++ struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : NULL; ++ struct mt76_vif_link *mlink = NULL; + struct mt76_txwi_cache *t; + int id, i, pid, nbuf = tx_info->nbuf - 1; + bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + __le32 *ptr = (__le32 *)txwi_ptr; + u8 *txwi = (u8 *)txwi_ptr; ++ u8 link_id; + + if (unlikely(tx_info->skb->len <= ETH_HLEN)) + return -EINVAL; +@@ -1056,6 +1061,30 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + if (!wcid) + wcid = &dev->mt76.global_wcid; + ++ if ((is_8023 || ieee80211_is_data_qos(hdr->frame_control)) && sta->mlo && ++ likely(tx_info->skb->protocol != cpu_to_be16(ETH_P_PAE))) { ++ u8 tid = tx_info->skb->priority & IEEE80211_QOS_CTL_TID_MASK; ++ ++ link_id = (tid % 2) ? msta->seclink_id : msta->deflink_id; ++ } else { ++ link_id = u32_get_bits(info->control.flags, ++ IEEE80211_TX_CTRL_MLO_LINK); ++ } ++ ++ if (link_id != wcid->link_id && link_id != IEEE80211_LINK_UNSPECIFIED) { ++ if (msta) { ++ struct mt7996_sta_link *msta_link = ++ rcu_dereference(msta->link[link_id]); ++ ++ if (msta_link) ++ wcid = &msta_link->wcid; ++ } else if (mvif) { ++ mlink = rcu_dereference(mvif->mt76.link[link_id]); ++ if (mlink && mlink->wcid) ++ wcid = mlink->wcid; ++ } ++ } ++ + t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); + t->skb = tx_info->skb; + +@@ -1162,10 +1191,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + if (!is_8023 && mt7996_tx_use_mgmt(dev, tx_info->skb)) + txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); + +- if (vif) { +- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; +- struct mt76_vif_link *mlink = NULL; +- ++ if (mvif) { + if (wcid->offchannel) + mlink = rcu_dereference(mvif->mt76.offchannel_link); + if (!mlink) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index 32d44540605fc..af322f505f8ab 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -982,6 +982,7 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, + + msta_link = &msta->deflink; + msta->deflink_id = link_id; ++ msta->seclink_id = msta->deflink_id; + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { + struct mt76_txq *mtxq; +@@ -996,6 +997,11 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, + msta_link = kzalloc(sizeof(*msta_link), GFP_KERNEL); + if (!msta_link) + return -ENOMEM; ++ ++ if (msta->seclink_id == msta->deflink_id && ++ (sta->valid_links & ~BIT(msta->deflink_id))) ++ msta->seclink_id = __ffs(sta->valid_links & ++ ~BIT(msta->deflink_id)); + } + + INIT_LIST_HEAD(&msta_link->rc_list); +@@ -1065,6 +1071,8 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + if (msta->deflink_id == link_id) { + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + continue; ++ } else if (msta->seclink_id == link_id) { ++ msta->seclink_id = IEEE80211_LINK_UNSPECIFIED; + } + + kfree_rcu(msta_link, rcu_head); +@@ -1160,6 +1168,7 @@ mt7996_mac_sta_add(struct mt7996_dev *dev, struct ieee80211_vif *vif, + mutex_lock(&dev->mt76.mutex); + + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; ++ msta->seclink_id = IEEE80211_LINK_UNSPECIFIED; + msta->vif = mvif; + err = mt7996_mac_sta_add_links(dev, vif, sta, links); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index c2d15128784bc..38b8743409a0c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -2399,8 +2399,8 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, + mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx); + + if (nlinks > 1) { +- link_id = __ffs(sta->valid_links & ~BIT(msta->deflink_id)); +- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); ++ msta_link = mt76_dereference(msta->link[msta->seclink_id], ++ &dev->mt76); + if (!msta_link) + return; + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +index 6190fbcd4df7e..6793161ed198c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +@@ -243,6 +243,7 @@ struct mt7996_sta { + struct mt7996_sta_link deflink; /* must be first */ + struct mt7996_sta_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + u8 deflink_id; ++ u8 seclink_id; + + struct mt7996_vif *vif; + }; +-- +2.53.0 + diff --git a/queue-6.18/wifi-mt76-support-upgrading-passive-scans-to-active.patch b/queue-6.18/wifi-mt76-support-upgrading-passive-scans-to-active.patch new file mode 100644 index 0000000000..15c15ef397 --- /dev/null +++ b/queue-6.18/wifi-mt76-support-upgrading-passive-scans-to-active.patch @@ -0,0 +1,172 @@ +From 9450dc40aea4125a5bf6d6a8731193a2ffc3c490 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 06:07:21 +0000 +Subject: wifi: mt76: support upgrading passive scans to active + +From: Chad Monroe + +[ Upstream commit 360552c8592dab3c69e0bbff786b55137f1a81bb ] + +On channels with NO_IR or RADAR flags, wait for beacon before sending +probe requests. Allows active scanning and WPS on restricted channels +if another AP is already present. + +Fixes: c56d6edebc1f ("wifi: mt76: mt7996: use emulated hardware scan support") +Tested-by: Piotr Kubik +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/20251118102723.47997-2-nbd@nbd.name +Link: https://patch.msgid.link/20260309060730.87840-2-nbd@nbd.name +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + + drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++ + .../net/wireless/mediatek/mt76/mt7996/mac.c | 3 ++ + drivers/net/wireless/mediatek/mt76/scan.c | 51 +++++++++++++++++-- + 4 files changed, 56 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index 5e75861bf6f99..76eb740428b8d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -724,6 +724,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size, + INIT_LIST_HEAD(&dev->rxwi_cache); + dev->token_size = dev->drv->token_size; + INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work); ++ spin_lock_init(&dev->scan_lock); + + for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) + skb_queue_head_init(&dev->rx_skb[i]); +diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h +index 7753afa3d883d..125ac1eb2d541 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -985,6 +985,7 @@ struct mt76_dev { + u32 rxfilter; + + struct delayed_work scan_work; ++ spinlock_t scan_lock; + struct { + struct cfg80211_scan_request *req; + struct ieee80211_channel *chan; +@@ -992,6 +993,8 @@ struct mt76_dev { + struct mt76_vif_link *mlink; + struct mt76_phy *phy; + int chan_idx; ++ bool beacon_wait; ++ bool beacon_received; + } scan; + + #ifdef CONFIG_NL80211_TESTMODE +@@ -1571,6 +1574,7 @@ int mt76_get_rate(struct mt76_dev *dev, + int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req); + void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); ++void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan); + void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac); + void mt76_sw_scan_complete(struct ieee80211_hw *hw, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index dce9f48637927..c375b4dd68a20 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -554,6 +554,9 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2); + seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2); + ++ if (ieee80211_is_beacon(fc)) ++ mt76_scan_rx_beacon(&dev->mt76, mphy->chandef.chan); ++ + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; +diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c +index efcf79d9d60e0..6cfca5108bc7e 100644 +--- a/drivers/net/wireless/mediatek/mt76/scan.c ++++ b/drivers/net/wireless/mediatek/mt76/scan.c +@@ -27,6 +27,10 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) + + void mt76_abort_scan(struct mt76_dev *dev) + { ++ spin_lock_bh(&dev->scan_lock); ++ dev->scan.beacon_wait = false; ++ spin_unlock_bh(&dev->scan_lock); ++ + cancel_delayed_work_sync(&dev->scan_work); + mt76_scan_complete(dev, true); + } +@@ -77,6 +81,28 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) + rcu_read_unlock(); + } + ++void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan) ++{ ++ struct mt76_phy *phy; ++ ++ spin_lock(&dev->scan_lock); ++ ++ if (!dev->scan.beacon_wait || dev->scan.beacon_received || ++ dev->scan.chan != chan) ++ goto out; ++ ++ phy = dev->scan.phy; ++ if (!phy) ++ goto out; ++ ++ dev->scan.beacon_received = true; ++ ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0); ++ ++out: ++ spin_unlock(&dev->scan_lock); ++} ++EXPORT_SYMBOL_GPL(mt76_scan_rx_beacon); ++ + void mt76_scan_work(struct work_struct *work) + { + struct mt76_dev *dev = container_of(work, struct mt76_dev, +@@ -85,9 +111,20 @@ void mt76_scan_work(struct work_struct *work) + struct cfg80211_chan_def chandef = {}; + struct mt76_phy *phy = dev->scan.phy; + int duration = HZ / 9; /* ~110 ms */ +- bool offchannel = true; ++ bool beacon_rx, offchannel = true; + int i; + ++ if (!phy || !req) ++ return; ++ ++ spin_lock_bh(&dev->scan_lock); ++ beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received; ++ dev->scan.beacon_wait = false; ++ spin_unlock_bh(&dev->scan_lock); ++ ++ if (beacon_rx) ++ goto probe; ++ + if (dev->scan.chan_idx >= req->n_channels) { + mt76_scan_complete(dev, false); + return; +@@ -108,10 +145,18 @@ void mt76_scan_work(struct work_struct *work) + + mt76_set_channel(phy, &chandef, offchannel); + +- if (!req->n_ssids || +- chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) ++ if (!req->n_ssids) + goto out; + ++ if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) { ++ spin_lock_bh(&dev->scan_lock); ++ dev->scan.beacon_received = false; ++ dev->scan.beacon_wait = true; ++ spin_unlock_bh(&dev->scan_lock); ++ goto out; ++ } ++ ++probe: + if (phy->offchannel) + duration = HZ / 16; /* ~60 ms */ + local_bh_disable(); +-- +2.53.0 + diff --git a/queue-6.18/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch b/queue-6.18/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch new file mode 100644 index 0000000000..58c0945cc1 --- /dev/null +++ b/queue-6.18/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch @@ -0,0 +1,49 @@ +From 89633ee114298eda8e4585fb44206f349079b8f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 09:26:25 +0000 +Subject: wifi: mwifiex: Fix memory leak in mwifiex_11n_aggregate_pkt() + +From: Zilin Guan + +[ Upstream commit 990a73dec3fdc145fef6c827c29205437d533ece ] + +In mwifiex_11n_aggregate_pkt(), skb_aggr is allocated via +mwifiex_alloc_dma_align_buf(). If mwifiex_is_ralist_valid() returns false, +the function currently returns -1 immediately without freeing the +previously allocated skb_aggr, causing a memory leak. + +Since skb_aggr has not yet been queued via skb_queue_tail(), no other +references to this memory exist. Therefore, it has to be freed locally +before returning the error. + +Fix this by calling mwifiex_write_data_complete() to free skb_aggr before +returning the error status. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") +Signed-off-by: Zilin Guan +Reviewed-by: Jeff Chen +Link: https://patch.msgid.link/20260119092625.1349934-1-zilin@seu.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +index 34b4b34276d6d..042b1fe5f0d67 100644 +--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +@@ -203,6 +203,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); ++ mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); + return -1; + } + +-- +2.53.0 + diff --git a/queue-6.18/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch b/queue-6.18/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch new file mode 100644 index 0000000000..73e95cb50c --- /dev/null +++ b/queue-6.18/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch @@ -0,0 +1,49 @@ +From 086e5749d67e007f3fc7df0ac02a94cd717af299 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:55:22 +0800 +Subject: wifi: rtlwifi: pci: fix possible use-after-free caused by unfinished + irq_prepare_bcn_tasklet + +From: Duoming Zhou + +[ Upstream commit 039cd522dc70151da13329a5e3ae19b1736f468a ] + +The irq_prepare_bcn_tasklet is initialized in rtl_pci_init() and +scheduled when RTL_IMR_BCNINT interrupt is triggered by hardware. +But it is never killed in rtl_pci_deinit(). When the rtlwifi card +probe fails or is being detached, the ieee80211_hw is deallocated. +However, irq_prepare_bcn_tasklet may still be running or pending, +leading to use-after-free when the freed ieee80211_hw is accessed +in _rtl_pci_prepare_bcn_tasklet(). + +Similar to irq_tasklet, add tasklet_kill() in rtl_pci_deinit() to +ensure that irq_prepare_bcn_tasklet is properly terminated before +the ieee80211_hw is released. + +The issue was identified through static analysis. + +Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") +Signed-off-by: Duoming Zhou +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260223045522.48377-1-duoming@zju.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtlwifi/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index d080469264cf8..f0010336e78c1 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -1674,6 +1674,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); ++ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + } + +-- +2.53.0 + diff --git a/queue-6.18/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch b/queue-6.18/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch new file mode 100644 index 0000000000..b061a5caef --- /dev/null +++ b/queue-6.18/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch @@ -0,0 +1,48 @@ +From a0e331eaa32b8b029c31da86f3e0255454c297fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:05:53 +0300 +Subject: wifi: rtw89: phy: fix uninitialized variable access in + rtw89_phy_cfo_set_crystal_cap() + +From: Alexey Velichayshiy + +[ Upstream commit 047cddf88c611e616d49a00311d4722e46286234 ] + +In the rtw89_phy_cfo_set_crystal_cap() function, for chips other than +RTL8852A/RTL8851B, the values read by rtw89_mac_read_xtal_si() are +stored into the local variables sc_xi_val and sc_xo_val. If either +read fails, these variables remain uninitialized, they are later +used to update cfo->crystal_cap and in debug print statements. This +can lead to undefined behavior. + +Fix the issue by initializing sc_xi_val and sc_xo_val to zero, +like is implemented in vendor driver. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 8379fa611536 ("rtw89: 8852c: add write/read crystal function in CFO tracking") +Signed-off-by: Alexey Velichayshiy +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260323140613.1615574-1-a.velichayshiy@ispras.ru +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/phy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c +index ba7feadd75828..36dee482bc34b 100644 +--- a/drivers/net/wireless/realtek/rtw89/phy.c ++++ b/drivers/net/wireless/realtek/rtw89/phy.c +@@ -4499,7 +4499,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, + { + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + const struct rtw89_chip_info *chip = rtwdev->chip; +- u8 sc_xi_val, sc_xo_val; ++ u8 sc_xi_val = 0, sc_xo_val = 0; + + if (!force && cfo->crystal_cap == crystal_cap) + return; +-- +2.53.0 + diff --git a/queue-6.18/x86-tdx-fix-the-typo-in-tdx_attr_migrtable.patch b/queue-6.18/x86-tdx-fix-the-typo-in-tdx_attr_migrtable.patch new file mode 100644 index 0000000000..03edd3c022 --- /dev/null +++ b/queue-6.18/x86-tdx-fix-the-typo-in-tdx_attr_migrtable.patch @@ -0,0 +1,67 @@ +From 84e09446a5ad9a4b58b4fe6b361b9b26ef8af8cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:03:32 +0800 +Subject: x86/tdx: Fix the typo in TDX_ATTR_MIGRTABLE + +From: Xiaoyao Li + +[ Upstream commit 3aecb2e7b948400354399b26f3f1653bd2c1bae0 ] + +The TD scoped TDCS attributes are defined by bit positions. In the guest +side of the TDX code, the 'tdx_attributes' string array holds pretty +print names for these attributes, which are generated via macros and +defines. Today these pretty print names are only used to print the +attribute names to dmesg. + +Unfortunately there is a typo in the define for the migratable bit. +Change the defines TDX_ATTR_MIGRTABLE* to TDX_ATTR_MIGRATABLE*. Update +the sole user, the tdx_attributes array, to use the fixed name. + +Since these defines control the string printed to dmesg, the change is +user visible. But the risk of breakage is almost zero since it is not +exposed in any interface expected to be consumed programmatically. + +Fixes: 564ea84c8c14 ("x86/tdx: Dump attributes and TD_CTLS on boot") +Signed-off-by: Xiaoyao Li +Signed-off-by: Dave Hansen +Reviewed-by: Kirill A. Shutemov +Reviewed-by: Kai Huang +Acked-by: Sean Christopherson +Link: https://patch.msgid.link/20260303030335.766779-2-xiaoyao.li@intel.com +Signed-off-by: Sasha Levin +--- + arch/x86/coco/tdx/debug.c | 2 +- + arch/x86/include/asm/shared/tdx.h | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/x86/coco/tdx/debug.c b/arch/x86/coco/tdx/debug.c +index cef847c8bb67f..28990c2ab0a14 100644 +--- a/arch/x86/coco/tdx/debug.c ++++ b/arch/x86/coco/tdx/debug.c +@@ -17,7 +17,7 @@ static __initdata const char *tdx_attributes[] = { + DEF_TDX_ATTR_NAME(ICSSD), + DEF_TDX_ATTR_NAME(LASS), + DEF_TDX_ATTR_NAME(SEPT_VE_DISABLE), +- DEF_TDX_ATTR_NAME(MIGRTABLE), ++ DEF_TDX_ATTR_NAME(MIGRATABLE), + DEF_TDX_ATTR_NAME(PKS), + DEF_TDX_ATTR_NAME(KL), + DEF_TDX_ATTR_NAME(TPA), +diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h +index 8bc074c8d7c6a..11f3cf30b1ac8 100644 +--- a/arch/x86/include/asm/shared/tdx.h ++++ b/arch/x86/include/asm/shared/tdx.h +@@ -35,8 +35,8 @@ + #define TDX_ATTR_LASS BIT_ULL(TDX_ATTR_LASS_BIT) + #define TDX_ATTR_SEPT_VE_DISABLE_BIT 28 + #define TDX_ATTR_SEPT_VE_DISABLE BIT_ULL(TDX_ATTR_SEPT_VE_DISABLE_BIT) +-#define TDX_ATTR_MIGRTABLE_BIT 29 +-#define TDX_ATTR_MIGRTABLE BIT_ULL(TDX_ATTR_MIGRTABLE_BIT) ++#define TDX_ATTR_MIGRATABLE_BIT 29 ++#define TDX_ATTR_MIGRATABLE BIT_ULL(TDX_ATTR_MIGRATABLE_BIT) + #define TDX_ATTR_PKS_BIT 30 + #define TDX_ATTR_PKS BIT_ULL(TDX_ATTR_PKS_BIT) + #define TDX_ATTR_KL_BIT 31 +-- +2.53.0 + diff --git a/queue-6.18/x86-um-fix-vdso-installation.patch b/queue-6.18/x86-um-fix-vdso-installation.patch new file mode 100644 index 0000000000..adb2e18896 --- /dev/null +++ b/queue-6.18/x86-um-fix-vdso-installation.patch @@ -0,0 +1,57 @@ +From 0271b021c5d5dc2bde496edd1db3a72726191a40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 22:03:26 +0100 +Subject: x86/um: fix vDSO installation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit d1895c15fc7d90a615bc8c455feb02acaf08ef1e ] + +The generic vDSO installation logic used by 'make vdso_install' requires +that $(vdso-install-y) is defined by the top-level architecture Makefile +and that it contains a path relative to the root of the tree. +For UML neither of these is satisfied. + +Move the definition of $(vdso-install-y) to a place which is included by +the arch/um/Makefile and use the full relative path. + +Fixes: f1c2bb8b9964 ("um: implement a x86_64 vDSO") +Signed-off-by: Thomas Weißschuh +Link: https://patch.msgid.link/20260318-um-vdso-install-v1-1-26a4ca5c4210@weissschuh.net +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/x86/Makefile.um | 2 ++ + arch/x86/um/vdso/Makefile | 2 -- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/Makefile.um b/arch/x86/Makefile.um +index c86cbd9cbba38..19c13afa474e9 100644 +--- a/arch/x86/Makefile.um ++++ b/arch/x86/Makefile.um +@@ -60,4 +60,6 @@ ELF_FORMAT := elf64-x86-64 + LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib64 + LINK-y += -m64 + ++vdso-install-y += arch/x86/um/vdso/vdso.so.dbg ++ + endif +diff --git a/arch/x86/um/vdso/Makefile b/arch/x86/um/vdso/Makefile +index 8a7c8b37cb6eb..7664cbedbe30f 100644 +--- a/arch/x86/um/vdso/Makefile ++++ b/arch/x86/um/vdso/Makefile +@@ -3,8 +3,6 @@ + # Building vDSO images for x86. + # + +-vdso-install-y += vdso.so +- + # files to link into the vdso + vobjs-y := vdso-note.o um_vdso.o + +-- +2.53.0 + diff --git a/queue-6.18/x86-um-vdso-drop-vdso64-y-from-makefile.patch b/queue-6.18/x86-um-vdso-drop-vdso64-y-from-makefile.patch new file mode 100644 index 0000000000..eb2e3a900b --- /dev/null +++ b/queue-6.18/x86-um-vdso-drop-vdso64-y-from-makefile.patch @@ -0,0 +1,49 @@ +From bddaf2f07bb84d5d05132f006070cd2694614ae5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Oct 2025 12:40:21 +0200 +Subject: x86/um/vdso: Drop VDSO64-y from Makefile +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 3c9b904f9033fb250db72d258bbdec791dc89405 ] + +This symbol is unnecessary, remove it. + +Signed-off-by: Thomas Weißschuh +Link: https://patch.msgid.link/20251013-uml-vdso-cleanup-v1-4-a079c7adcc69@weissschuh.net +Signed-off-by: Johannes Berg +Stable-dep-of: d1895c15fc7d ("x86/um: fix vDSO installation") +Signed-off-by: Sasha Levin +--- + arch/x86/um/vdso/Makefile | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/um/vdso/Makefile b/arch/x86/um/vdso/Makefile +index 7478d11dacb71..8a7c8b37cb6eb 100644 +--- a/arch/x86/um/vdso/Makefile ++++ b/arch/x86/um/vdso/Makefile +@@ -3,16 +3,13 @@ + # Building vDSO images for x86. + # + +-VDSO64-y := y +- +-vdso-install-$(VDSO64-y) += vdso.so +- ++vdso-install-y += vdso.so + + # files to link into the vdso + vobjs-y := vdso-note.o um_vdso.o + + # files to link into kernel +-obj-$(VDSO64-y) += vdso.o vma.o ++obj-y += vdso.o vma.o + + vobjs := $(foreach F,$(vobjs-y),$(obj)/$F) + +-- +2.53.0 + diff --git a/queue-6.18/x86-vdso-clean-up-remnants-of-vdso32_note_mask.patch b/queue-6.18/x86-vdso-clean-up-remnants-of-vdso32_note_mask.patch new file mode 100644 index 0000000000..b6a9a05432 --- /dev/null +++ b/queue-6.18/x86-vdso-clean-up-remnants-of-vdso32_note_mask.patch @@ -0,0 +1,54 @@ +From 0550f0fe931823634f66c5f43995fa55877bc140 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:07:55 +0200 +Subject: x86/vdso: Clean up remnants of VDSO32_NOTE_MASK +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 6517f293b2c6774d21b6e7e26a55fae60c6ec4cf ] + +VDSO32_NOTE_MASK is not used or provided anymore, remove it. + +Fixes: a13f2ef168cb ("x86/xen: remove 32-bit Xen PV guest support") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Ingo Molnar +Cc: H. Peter Anvin +Cc: Boris Ostrovsky +Cc: Juergen Gross +Link: https://patch.msgid.link/20260330-vdso-x86-vdso32_note_mask-v1-1-2f5c473327bf@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/x86/entry/vdso/vdso2c.c | 1 - + arch/x86/include/asm/vdso.h | 1 - + 2 files changed, 2 deletions(-) + +diff --git a/arch/x86/entry/vdso/vdso2c.c b/arch/x86/entry/vdso/vdso2c.c +index f84e8f8fa5fe6..b8a555763f437 100644 +--- a/arch/x86/entry/vdso/vdso2c.c ++++ b/arch/x86/entry/vdso/vdso2c.c +@@ -75,7 +75,6 @@ struct vdso_sym { + }; + + struct vdso_sym required_syms[] = { +- {"VDSO32_NOTE_MASK", true}, + {"__kernel_vsyscall", true}, + {"__kernel_sigreturn", true}, + {"__kernel_rt_sigreturn", true}, +diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h +index b7253ef3205a6..7bc290ae99334 100644 +--- a/arch/x86/include/asm/vdso.h ++++ b/arch/x86/include/asm/vdso.h +@@ -18,7 +18,6 @@ struct vdso_image { + unsigned long extable_base, extable_len; + const void *extable; + +- long sym_VDSO32_NOTE_MASK; + long sym___kernel_sigreturn; + long sym___kernel_rt_sigreturn; + long sym___kernel_vsyscall; +-- +2.53.0 + diff --git a/queue-6.6/6pack-propagage-new-tty-types.patch b/queue-6.6/6pack-propagage-new-tty-types.patch new file mode 100644 index 0000000000..33c4e0a22e --- /dev/null +++ b/queue-6.6/6pack-propagage-new-tty-types.patch @@ -0,0 +1,136 @@ +From c27a2ef5b009a1eb981fbb420eec20b9d68033b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 12:35:47 +0200 +Subject: 6pack: propagage new tty types + +From: Jiri Slaby (SUSE) + +[ Upstream commit 1241b384efa53f4b7a95fe2b34d69359bb3ae1b5 ] + +In tty, u8 is now used for data, ssize_t for sizes (with possible +negative error codes). Propagate these types to 6pack. + +Signed-off-by: Jiri Slaby (SUSE) +Cc: Greg Kroah-Hartman +Cc: Andreas Koensgen +Cc: David S. Miller +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: linux-hams@vger.kernel.org +Cc: netdev@vger.kernel.org +Reviewed-by: Jeremy Kerr +Link: https://lore.kernel.org/r/20240808103549.429349-12-jirislaby@kernel.org +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bf9a38803b26 ("net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf") +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 6cecdfa8631d7..3145dadf99290 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -94,8 +94,8 @@ struct sixpack { + unsigned char *xhead; /* next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + +- unsigned char raw_buf[4]; +- unsigned char cooked_buf[400]; ++ u8 raw_buf[4]; ++ u8 cooked_buf[400]; + + unsigned int rx_count; + unsigned int rx_count_cooked; +@@ -113,8 +113,8 @@ struct sixpack { + unsigned char slottime; + unsigned char duplex; + unsigned char led_state; +- unsigned char status; +- unsigned char status1; ++ u8 status; ++ u8 status1; + unsigned char status2; + unsigned char tx_enable; + unsigned char tnc_state; +@@ -126,7 +126,7 @@ struct sixpack { + + #define AX25_6PACK_HEADER_LEN 0 + +-static void sixpack_decode(struct sixpack *, const unsigned char[], int); ++static void sixpack_decode(struct sixpack *, const u8 *, size_t); + static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); + + /* +@@ -331,7 +331,7 @@ static void sp_bump(struct sixpack *sp, char cmd) + { + struct sk_buff *skb; + int count; +- unsigned char *ptr; ++ u8 *ptr; + + count = sp->rcount + 1; + +@@ -397,7 +397,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + const u8 *fp, size_t count) + { + struct sixpack *sp; +- int count1; ++ size_t count1; + + if (!count) + return; +@@ -773,9 +773,9 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, + + /* decode 4 sixpack-encoded bytes into 3 data bytes */ + +-static void decode_data(struct sixpack *sp, unsigned char inbyte) ++static void decode_data(struct sixpack *sp, u8 inbyte) + { +- unsigned char *buf; ++ u8 *buf; + + if (sp->rx_count != 3) { + sp->raw_buf[sp->rx_count++] = inbyte; +@@ -801,9 +801,9 @@ static void decode_data(struct sixpack *sp, unsigned char inbyte) + + /* identify and execute a 6pack priority command byte */ + +-static void decode_prio_command(struct sixpack *sp, unsigned char cmd) ++static void decode_prio_command(struct sixpack *sp, u8 cmd) + { +- int actual; ++ ssize_t actual; + + if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ + +@@ -851,9 +851,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd) + + /* identify and execute a standard 6pack command byte */ + +-static void decode_std_command(struct sixpack *sp, unsigned char cmd) ++static void decode_std_command(struct sixpack *sp, u8 cmd) + { +- unsigned char checksum = 0, rest = 0; ++ u8 checksum = 0, rest = 0; + short i; + + switch (cmd & SIXP_CMD_MASK) { /* normal command */ +@@ -901,10 +901,10 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd) + /* decode a 6pack packet */ + + static void +-sixpack_decode(struct sixpack *sp, const unsigned char *pre_rbuff, int count) ++sixpack_decode(struct sixpack *sp, const u8 *pre_rbuff, size_t count) + { +- unsigned char inbyte; +- int count1; ++ size_t count1; ++ u8 inbyte; + + for (count1 = 0; count1 < count; count1++) { + inbyte = pre_rbuff[count1]; +-- +2.53.0 + diff --git a/queue-6.6/acpi-agdi-fix-missing-newline-in-error-message.patch b/queue-6.6/acpi-agdi-fix-missing-newline-in-error-message.patch new file mode 100644 index 0000000000..17ce73892c --- /dev/null +++ b/queue-6.6/acpi-agdi-fix-missing-newline-in-error-message.patch @@ -0,0 +1,40 @@ +From 9573b112212d84284f7d53ab10fa30766ab783ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:31:15 +0800 +Subject: ACPI: AGDI: fix missing newline in error message + +From: Haoyu Lu + +[ Upstream commit b178330b67abb7293b6de28b2a49d49c83962db5 ] + +Add the missing trailing newline to the dev_err() message +printed when SDEI event registration fails. + +This keeps the error output as a properly terminated log line. + +Fixes: a2a591fb76e6 ("ACPI: AGDI: Add driver for Arm Generic Diagnostic Dump and Reset device") +Reviewed-by: Ilkka Koskinen +Signed-off-by: Haoyu Lu +Reviewed-by: Hanjun Guo +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + drivers/acpi/arm64/agdi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c +index 8b3c7d42b41bc..419a9f6c0a827 100644 +--- a/drivers/acpi/arm64/agdi.c ++++ b/drivers/acpi/arm64/agdi.c +@@ -32,7 +32,7 @@ static int agdi_sdei_probe(struct platform_device *pdev, + + err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev); + if (err) { +- dev_err(&pdev->dev, "Failed to register for SDEI event %d", ++ dev_err(&pdev->dev, "Failed to register for SDEI event %d\n", + adata->sdei_event); + return err; + } +-- +2.53.0 + diff --git a/queue-6.6/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch b/queue-6.6/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch new file mode 100644 index 0000000000..8a1aaf30af --- /dev/null +++ b/queue-6.6/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch @@ -0,0 +1,145 @@ +From 8e42530eee3fd5825756de3ed722ede47d6ba898 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:28:15 +0100 +Subject: ACPI: x86: cmos_rtc: Clean up address space handler driver + +From: Rafael J. Wysocki + +[ Upstream commit ba0b236736dde4059bdcb8e99beaa50d6e5b6e7e ] + +Make multiple changes that do not alter functionality to the CMOS RTC +ACPI address space handler driver, including the following: + + - Drop the unused .detach() callback from cmos_rtc_handler. + + - Rename acpi_cmos_rtc_attach_handler() to acpi_cmos_rtc_attach(). + + - Rearrange acpi_cmos_rtc_space_handler() to reduce the number of + redundant checks and make white space follow the coding style. + + - Adjust an error message in acpi_install_cmos_rtc_space_handler() + and make the white space follow the coding style. + + - Rearrange acpi_remove_cmos_rtc_space_handler() and adjust an error + message in it. + +No intentional functional impact. + +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/5094429.31r3eYUQgx@rafael.j.wysocki +Stable-dep-of: 6cee29ad9d7e ("ACPI: x86: cmos_rtc: Improve coordination with ACPI TAD driver") +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpi_cmos_rtc.c | 61 +++++++++++++++++++----------------- + 1 file changed, 32 insertions(+), 29 deletions(-) + +diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c +index 9b55d1593d160..65e89e23c5c84 100644 +--- a/drivers/acpi/acpi_cmos_rtc.c ++++ b/drivers/acpi/acpi_cmos_rtc.c +@@ -24,31 +24,35 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + {} + }; + +-static acpi_status +-acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, +- u32 bits, u64 *value64, +- void *handler_context, void *region_context) ++static acpi_status acpi_cmos_rtc_space_handler(u32 function, ++ acpi_physical_address address, ++ u32 bits, u64 *value64, ++ void *handler_context, ++ void *region_context) + { +- int i; ++ unsigned int i, bytes = DIV_ROUND_UP(bits, 8); + u8 *value = (u8 *)value64; + + if (address > 0xff || !value64) + return AE_BAD_PARAMETER; + +- if (function != ACPI_WRITE && function != ACPI_READ) +- return AE_BAD_PARAMETER; ++ guard(spinlock_irq)(&rtc_lock); ++ ++ if (function == ACPI_WRITE) { ++ for (i = 0; i < bytes; i++, address++, value++) ++ CMOS_WRITE(*value, address); + +- spin_lock_irq(&rtc_lock); ++ return AE_OK; ++ } + +- for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) +- if (function == ACPI_READ) ++ if (function == ACPI_READ) { ++ for (i = 0; i < bytes; i++, address++, value++) + *value = CMOS_READ(address); +- else +- CMOS_WRITE(*value, address); + +- spin_unlock_irq(&rtc_lock); ++ return AE_OK; ++ } + +- return AE_OK; ++ return AE_BAD_PARAMETER; + } + + int acpi_install_cmos_rtc_space_handler(acpi_handle handle) +@@ -56,11 +60,11 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + acpi_status status; + + status = acpi_install_address_space_handler(handle, +- ACPI_ADR_SPACE_CMOS, +- &acpi_cmos_rtc_space_handler, +- NULL, NULL); ++ ACPI_ADR_SPACE_CMOS, ++ acpi_cmos_rtc_space_handler, ++ NULL, NULL); + if (ACPI_FAILURE(status)) { +- pr_err("Error installing CMOS-RTC region handler\n"); ++ pr_err("Failed to install CMOS-RTC address space handler\n"); + return -ENODEV; + } + +@@ -70,26 +74,25 @@ EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); + + void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) + { +- if (ACPI_FAILURE(acpi_remove_address_space_handler(handle, +- ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) +- pr_err("Error removing CMOS-RTC region handler\n"); ++ acpi_status status; ++ ++ status = acpi_remove_address_space_handler(handle, ++ ACPI_ADR_SPACE_CMOS, ++ acpi_cmos_rtc_space_handler); ++ if (ACPI_FAILURE(status)) ++ pr_err("Failed to remove CMOS-RTC address space handler\n"); + } + EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + +-static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id) ++static int acpi_cmos_rtc_attach(struct acpi_device *adev, ++ const struct acpi_device_id *id) + { + return acpi_install_cmos_rtc_space_handler(adev->handle); + } + +-static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev) +-{ +- acpi_remove_cmos_rtc_space_handler(adev->handle); +-} +- + static struct acpi_scan_handler cmos_rtc_handler = { + .ids = acpi_cmos_rtc_ids, +- .attach = acpi_cmos_rtc_attach_handler, +- .detach = acpi_cmos_rtc_detach_handler, ++ .attach = acpi_cmos_rtc_attach, + }; + + void __init acpi_cmos_rtc_init(void) +-- +2.53.0 + diff --git a/queue-6.6/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch b/queue-6.6/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch new file mode 100644 index 0000000000..d31c498901 --- /dev/null +++ b/queue-6.6/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch @@ -0,0 +1,86 @@ +From 9f2aca96077c0b7469a1cc6b745fced64a4f923f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:28:57 +0100 +Subject: ACPI: x86: cmos_rtc: Improve coordination with ACPI TAD driver + +From: Rafael J. Wysocki + +[ Upstream commit 6cee29ad9d7e400d39ae0b1a54447fedcb62eecd ] + +If a CMOS RTC (PNP0B00/PNP0B01/PNP0B02) device coexists with an ACPI +TAD (timer and event alarm device, ACPI000E), the ACPI TAD driver will +attempt to install the CMOS RTC address space hanlder that has been +installed already and the TAD probing will fail. + +Avoid that by changing acpi_install_cmos_rtc_space_handler() to return +zero and acpi_remove_cmos_rtc_space_handler() to do nothing if the CMOS +RTC address space handler has been installed already. + +Fixes: 596ca52a56da ("ACPI: TAD: Install SystemCMOS address space handler for ACPI000E") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2415111.ElGaqSPkdT@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpi_cmos_rtc.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c +index 65e89e23c5c84..594753203fdf0 100644 +--- a/drivers/acpi/acpi_cmos_rtc.c ++++ b/drivers/acpi/acpi_cmos_rtc.c +@@ -24,6 +24,8 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + {} + }; + ++static bool cmos_rtc_space_handler_present __read_mostly; ++ + static acpi_status acpi_cmos_rtc_space_handler(u32 function, + acpi_physical_address address, + u32 bits, u64 *value64, +@@ -59,6 +61,9 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + { + acpi_status status; + ++ if (cmos_rtc_space_handler_present) ++ return 0; ++ + status = acpi_install_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler, +@@ -68,6 +73,8 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + return -ENODEV; + } + ++ cmos_rtc_space_handler_present = true; ++ + return 1; + } + EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); +@@ -76,6 +83,9 @@ void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) + { + acpi_status status; + ++ if (cmos_rtc_space_handler_present) ++ return; ++ + status = acpi_remove_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler); +@@ -87,7 +97,13 @@ EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + static int acpi_cmos_rtc_attach(struct acpi_device *adev, + const struct acpi_device_id *id) + { +- return acpi_install_cmos_rtc_space_handler(adev->handle); ++ int ret; ++ ++ ret = acpi_install_cmos_rtc_space_handler(adev->handle); ++ if (ret < 0) ++ return ret; ++ ++ return 1; + } + + static struct acpi_scan_handler cmos_rtc_handler = { +-- +2.53.0 + diff --git a/queue-6.6/alsa-core-validate-compress-device-numbers-without-d.patch b/queue-6.6/alsa-core-validate-compress-device-numbers-without-d.patch new file mode 100644 index 0000000000..513a1515ae --- /dev/null +++ b/queue-6.6/alsa-core-validate-compress-device-numbers-without-d.patch @@ -0,0 +1,81 @@ +From 58a16bef5b7cbfe6dd46b45d02db4f07f5c6ef14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 02:24:04 -0300 +Subject: ALSA: core: Validate compress device numbers without dynamic minors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 796e119e9b14763be905ad0d023c71a14bc2e931 ] + +Without CONFIG_SND_DYNAMIC_MINORS, ALSA reserves only two fixed minors +for compress devices on each card: comprD0 and comprD1. + +snd_find_free_minor() currently computes the compress minor as +type + dev without validating dev first, so device numbers greater than +1 spill into the HWDEP minor range instead of failing registration. + +ASoC passes rtd->id to snd_compress_new(), so this can happen on real +non-dynamic-minor builds. + +Add a dedicated fixed-minor check for SNDRV_DEVICE_TYPE_COMPRESS in +snd_find_free_minor() and reject out-of-range device numbers with +-EINVAL before constructing the minor. + +Also remove the stale TODO in compress_offload.c that still claims +multiple compress nodes are missing. + +Fixes: 3eafc959b32f ("ALSA: core: add support for compressed devices") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-alsa-compress-static-minors-v1-1-0628573bee1c@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 7 ------- + sound/core/sound.c | 7 +++++++ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 619371aa9964d..8545c7bbc58e3 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -40,13 +40,6 @@ + #define COMPR_CODEC_CAPS_OVERFLOW + #endif + +-/* TODO: +- * - add substream support for multiple devices in case of +- * SND_DYNAMIC_MINORS is not used +- * - Multiple node representation +- * driver should be able to register multiple nodes +- */ +- + struct snd_compr_file { + unsigned long caps; + struct snd_compr_stream stream; +diff --git a/sound/core/sound.c b/sound/core/sound.c +index df5571d986295..f3bb0adf37cce 100644 +--- a/sound/core/sound.c ++++ b/sound/core/sound.c +@@ -219,9 +219,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev) + case SNDRV_DEVICE_TYPE_RAWMIDI: + case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: + case SNDRV_DEVICE_TYPE_PCM_CAPTURE: ++ if (snd_BUG_ON(!card)) ++ return -EINVAL; ++ minor = SNDRV_MINOR(card->number, type + dev); ++ break; + case SNDRV_DEVICE_TYPE_COMPRESS: + if (snd_BUG_ON(!card)) + return -EINVAL; ++ if (dev < 0 || ++ dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS) ++ return -EINVAL; + minor = SNDRV_MINOR(card->number, type + dev); + break; + default: +-- +2.53.0 + diff --git a/queue-6.6/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch b/queue-6.6/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch new file mode 100644 index 0000000000..cf0d20972b --- /dev/null +++ b/queue-6.6/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch @@ -0,0 +1,60 @@ +From 2e159a3f22af7c954bb05fa691f4fa3abc44bd89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:04:50 +0800 +Subject: ALSA: hda/conexant: Fix missing error check for jack detection + +From: wangdicheng + +[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ] + +In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() +is ignored. This function returns a pointer, and if it fails (e.g., due +to memory allocation failure), it returns an error pointer which must +be checked using IS_ERR(). + +If the registration fails, the driver continues to probe, but the jack +detection callback will not be registered. This can lead to a kernel +crash later when the driver attempts to handle jack events or accesses +the uninitialized structure. + +Check the return value using IS_ERR() and propagate the error via +PTR_ERR() to the probe caller. + +Fixes: 7aeb25908648 ("ALSA: hda/conexant: Fix headset auto detect fail in cx8070 and SN6140") +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428080450.108801-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index abcad66356d59..f6e563e03edf2 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -1186,6 +1186,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) + static int patch_conexant_auto(struct hda_codec *codec) + { + struct conexant_spec *spec; ++ struct hda_jack_callback *callback; + int err; + + codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); +@@ -1202,7 +1203,12 @@ static int patch_conexant_auto(struct hda_codec *codec) + case 0x14f11f86: + case 0x14f11f87: + spec->is_cx11880_sn6140 = true; +- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); ++ callback = snd_hda_jack_detect_enable_callback(codec, 0x19, ++ cx_update_headset_mic_vref); ++ if (IS_ERR(callback)) { ++ err = PTR_ERR(callback); ++ goto error; ++ } + break; + } + +-- +2.53.0 + diff --git a/queue-6.6/alsa-hda-conexant-fix-some-typos.patch b/queue-6.6/alsa-hda-conexant-fix-some-typos.patch new file mode 100644 index 0000000000..c25e608596 --- /dev/null +++ b/queue-6.6/alsa-hda-conexant-fix-some-typos.patch @@ -0,0 +1,64 @@ +From 323e68b0167177d2025e499d5590bc7f74b100f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 16:41:32 +0800 +Subject: ALSA: hda/conexant: fix some typos + +From: Oldherl Oh + +[ Upstream commit 73253f2fd1d0a44708735c842e37163712e3f03b ] + +Fix some typos in patch_conexant.c + +Signed-off-by: Oldherl Oh +Link: https://patch.msgid.link/20240930084132.3373750-1-me@oldherl.one +Signed-off-by: Takashi Iwai +Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 355b26583eb4e..08e2c836fd07e 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -166,18 +166,18 @@ static void cxt_init_gpio_led(struct hda_codec *codec) + + static void cx_fixup_headset_recog(struct hda_codec *codec) + { +- unsigned int mic_persent; ++ unsigned int mic_present; + + /* fix some headset type recognize fail issue, such as EDIFIER headset */ +- /* set micbiasd output current comparator threshold from 66% to 55%. */ ++ /* set micbias output current comparator threshold from 66% to 55%. */ + snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010); +- /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias registor ++ /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register + * value adjustment trim from 2.2K ohms to 2.0K ohms. + */ + snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10); + /* fix reboot headset type recognize fail issue */ +- mic_persent = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); +- if (mic_persent & AC_PINSENSE_PRESENCE) ++ mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); ++ if (mic_present & AC_PINSENSE_PRESENCE) + /* enable headset mic VREF */ + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); + else +@@ -247,9 +247,9 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ + { + unsigned int mic_present; + +- /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled, +- * the node 19 can only be config to microphone or disabled. +- * Check hp&mic tag to process headset pulgin&plugout. ++ /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, ++ * the node 19 can only be configured to microphone or disabled. ++ * Check hp&mic tag to process headset plugin & plugout. + */ + mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); + if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ +-- +2.53.0 + diff --git a/queue-6.6/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch b/queue-6.6/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch new file mode 100644 index 0000000000..0e66bcd411 --- /dev/null +++ b/queue-6.6/alsa-hda-conexant-renaming-the-codec-with-device-id-.patch @@ -0,0 +1,79 @@ +From c0535f432d1cf1a23fde388d3c790888815c83a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Jun 2025 15:43:31 +0800 +Subject: ALSA: hda/conexant: Renaming the codec with device ID 0x1f86 and + 0x1f87 + +From: wangdicheng + +[ Upstream commit 7f4c540e0859e2025675d2c5c5c6ab88eaf817e2 ] + +Due to changes in the manufacturer's plan, all 0x14f11f86 will be +named CX11880, and 0x14f11f87 will be named SN6140 + +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20250616074331.581309-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection") +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_conexant.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index 08e2c836fd07e..abcad66356d59 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -42,7 +42,7 @@ struct conexant_spec { + unsigned int gpio_led; + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; +- bool is_cx8070_sn6140; ++ bool is_cx11880_sn6140; + }; + + +@@ -195,7 +195,7 @@ static int cx_auto_init(struct hda_codec *codec) + cxt_init_gpio_led(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + +- if (spec->is_cx8070_sn6140) ++ if (spec->is_cx11880_sn6140) + cx_fixup_headset_recog(codec); + + return 0; +@@ -247,7 +247,7 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ + { + unsigned int mic_present; + +- /* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, ++ /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled, + * the node 19 can only be configured to microphone or disabled. + * Check hp&mic tag to process headset plugin & plugout. + */ +@@ -1197,11 +1197,11 @@ static int patch_conexant_auto(struct hda_codec *codec) + codec->spec = spec; + codec->patch_ops = cx_auto_patch_ops; + +- /* init cx8070/sn6140 flag and reset headset_present_flag */ ++ /* init cx11880/sn6140 flag and reset headset_present_flag */ + switch (codec->core.vendor_id) { + case 0x14f11f86: + case 0x14f11f87: +- spec->is_cx8070_sn6140 = true; ++ spec->is_cx11880_sn6140 = true; + snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); + break; + } +@@ -1289,7 +1289,7 @@ static int patch_conexant_auto(struct hda_codec *codec) + */ + + static const struct hda_device_id snd_hda_id_conexant[] = { +- HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto), ++ HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto), + HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto), +-- +2.53.0 + diff --git a/queue-6.6/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch b/queue-6.6/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch new file mode 100644 index 0000000000..f85870bc92 --- /dev/null +++ b/queue-6.6/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch @@ -0,0 +1,45 @@ +From e405d10d456563b1b0b56e42771f54c0ed96cd5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 15:54:05 +0800 +Subject: ALSA: hda/realtek: fix code style (ERROR: else should follow close + brace '}') + +From: Lei Huang + +[ Upstream commit d1888bf848ade6a9e71c7ba516fd215aa1bd8d65 ] + +Fix checkpatch code style errors: + + ERROR: else should follow close brace '}' + #2300: FILE: sound/hda/codecs/realtek/alc269.c:2300: + + } + + else + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Lei Huang +Link: https://patch.msgid.link/20260331075405.78148-1-huanglei814@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/hda/patch_realtek.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 6ef859f59f8d1..937f3fdbab252 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -6043,9 +6043,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } +- else ++ } else { + alc_fixup_headset_mode(codec, fix, action); ++ } + } + + static void alc288_update_headset_jack_cb(struct hda_codec *codec, +-- +2.53.0 + diff --git a/queue-6.6/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch b/queue-6.6/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch new file mode 100644 index 0000000000..baed327555 --- /dev/null +++ b/queue-6.6/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch @@ -0,0 +1,289 @@ +From c4c315b575ad1e10671759286bf5c6e35e5e2f37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:54:32 -0300 +Subject: ALSA: sc6000: Keep the programmed board state in card-private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit fb79bf127ac2577b4876132da6dba768018aad4c ] + +The driver may auto-select IRQ and DMA resources at probe time, but +sc6000_init_board() still derives the SC-6000 soft configuration from +the module parameter arrays. When irq=auto or dma=auto is used, the +codec is created with the selected resources while the board is +programmed with the unresolved values. + +Store the mapped ports and generated SC-6000 board configuration in +card-private data, build that configuration from the live probe +results instead of the raw module parameters, and keep the probe-time +board programming in a shared helper. + +This fixes the resource-programming mismatch and leaves the driver +with a stable board-state block that can be reused by suspend/resume. + +Fixes: c282866101bf ("ALSA: sc6000: add support for SC-6600 and SC-7000") +Signed-off-by: Cássio Gabriel +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260410-alsa-sc6000-pm-v1-1-4d9e95493d26@gmail.com +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 152 +++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 60 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 3115c32b4061b..4066b68a102e2 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -100,6 +100,15 @@ MODULE_PARM_DESC(joystick, "Enable gameport."); + #define PFX "sc6000: " + #define DRV_NAME "SC-6000" + ++struct snd_sc6000 { ++ char __iomem *vport; ++ char __iomem *vmss_port; ++ u8 mss_config; ++ u8 config; ++ u8 hw_cfg[2]; ++ bool old_dsp; ++}; ++ + /* hardware dependent functions */ + + /* +@@ -267,7 +276,7 @@ static int sc6000_dsp_reset(char __iomem *vport) + + /* detection and initialization */ + static int sc6000_hw_cfg_write(struct device *devptr, +- char __iomem *vport, const int *cfg) ++ char __iomem *vport, const u8 *cfg) + { + if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { + dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); +@@ -353,8 +362,7 @@ static int sc6000_init_mss(struct device *devptr, + return 0; + } + +-static void sc6000_hw_cfg_encode(struct device *devptr, +- char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, u8 *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -376,27 +384,83 @@ static void sc6000_hw_cfg_encode(struct device *devptr, + dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(struct device *devptr, +- char __iomem *vport, +- char __iomem *vmss_port, int dev) ++static void sc6000_prepare_board(struct device *devptr, ++ struct snd_sc6000 *sc6000, ++ unsigned int dev, int xirq, int xdma) ++{ ++ sc6000->mss_config = sc6000_irq_to_softcfg(xirq) | ++ sc6000_dma_to_softcfg(xdma); ++ sc6000->config = sc6000->mss_config | ++ sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); ++ sc6000_hw_cfg_encode(devptr, sc6000->hw_cfg, port[dev], mpu_port[dev], ++ mss_port[dev], joystick[dev]); ++} ++ ++static void sc6000_detect_old_dsp(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ sc6000_write(devptr, sc6000->vport, COMMAND_5C); ++ sc6000->old_dsp = sc6000_read(sc6000->vport) < 0; ++} ++ ++static int sc6000_program_board(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ int err; ++ ++ if (!sc6000->old_dsp) { ++ if (sc6000_hw_cfg_write(devptr, sc6000->vport, ++ sc6000->hw_cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); ++ return -EIO; ++ } ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ sc6000_dsp_reset(sc6000->vport); ++ ++ if (!sc6000->old_dsp) { ++ sc6000_write(devptr, sc6000->vport, COMMAND_60); ++ sc6000_write(devptr, sc6000->vport, 0x02); ++ sc6000_dsp_reset(sc6000->vport); ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ err = sc6000_init_mss(devptr, sc6000->vport, sc6000->config, ++ sc6000->vmss_port, sc6000->mss_config); ++ if (err < 0) { ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int sc6000_init_board(struct device *devptr, struct snd_sc6000 *sc6000) + { + char answer[15]; + char version[2]; +- int mss_config = sc6000_irq_to_softcfg(irq[dev]) | +- sc6000_dma_to_softcfg(dma[dev]); +- int config = mss_config | +- sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); + int err; +- int old = 0; + +- err = sc6000_dsp_reset(vport); ++ err = sc6000_dsp_reset(sc6000->vport); + if (err < 0) { + dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, sc6000->vport, GET_DSP_COPYRIGHT, ++ answer, 15); + if (err <= 0) { + dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; +@@ -408,54 +472,17 @@ static int sc6000_init_board(struct device *devptr, + if (strncmp("SC-6000", answer, 7)) + dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ if (sc6000_dsp_get_answer(devptr, sc6000->vport, ++ GET_DSP_VERSION, version, 2) < 2) { + dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } + dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + +- /* set configuration */ +- sc6000_write(devptr, vport, COMMAND_5C); +- if (sc6000_read(vport) < 0) +- old = 1; +- +- if (!old) { +- int cfg[2]; +- sc6000_hw_cfg_encode(devptr, +- vport, &cfg[0], port[dev], mpu_port[dev], +- mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { +- dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); +- return -EIO; +- } +- } +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- +- sc6000_dsp_reset(vport); +- +- if (!old) { +- sc6000_write(devptr, vport, COMMAND_60); +- sc6000_write(devptr, vport, 0x02); +- sc6000_dsp_reset(vport); +- } ++ sc6000_detect_old_dsp(devptr, sc6000); + +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); +- if (err < 0) { +- dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); +- return -ENODEV; +- } +- +- return 0; ++ return sc6000_program_board(devptr, sc6000); + } + + static int snd_sc6000_mixer(struct snd_wss *chip) +@@ -538,10 +565,10 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + + static void snd_sc6000_free(struct snd_card *card) + { +- char __iomem *vport = (char __force __iomem *)card->private_data; ++ struct snd_sc6000 *sc6000 = card->private_data; + +- if (vport) +- sc6000_setup_board(card->dev, vport, 0); ++ if (sc6000->vport) ++ sc6000_setup_board(card->dev, sc6000->vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -552,15 +579,17 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + int xirq = irq[dev]; + int xdma = dma[dev]; + struct snd_card *card; ++ struct snd_sc6000 *sc6000; + struct snd_wss *chip; + struct snd_opl3 *opl3; + char __iomem *vport; + char __iomem *vmss_port; + + err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE, +- 0, &card); ++ sizeof(*sc6000), &card); + if (err < 0) + return err; ++ sc6000 = card->private_data; + + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); +@@ -587,7 +616,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } +- card->private_data = (void __force *)vport; ++ sc6000->vport = vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +@@ -600,12 +629,15 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } ++ sc6000->vmss_port = vmss_port; + + dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(devptr, vport, vmss_port, dev); ++ sc6000_prepare_board(devptr, sc6000, dev, xirq, xdma); ++ ++ err = sc6000_init_board(devptr, sc6000); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +-- +2.53.0 + diff --git a/queue-6.6/alsa-sc6000-use-standard-print-api.patch b/queue-6.6/alsa-sc6000-use-standard-print-api.patch new file mode 100644 index 0000000000..3c61f211c8 --- /dev/null +++ b/queue-6.6/alsa-sc6000-use-standard-print-api.patch @@ -0,0 +1,453 @@ +From 3d93c8b6d23f27e5e01f0397713cbac7d782e948 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Aug 2024 15:34:23 +0200 +Subject: ALSA: sc6000: Use standard print API + +From: Takashi Iwai + +[ Upstream commit e7c475b92043c02c3e6cd0c20e308fbb6f03ebde ] + +Use the standard print API with dev_*() instead of the old house-baked +one. It gives better information and allows dynamically control of +debug prints. + +Some functions are changed to receive a device pointer to be passed to +dev_*() calls. + +Reviewed-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20240807133452.9424-34-tiwai@suse.de +Stable-dep-of: fb79bf127ac2 ("ALSA: sc6000: Keep the programmed board state in card-private data") +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 177 +++++++++++++++++++++++---------------------- + 1 file changed, 90 insertions(+), 87 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 60398fced046b..3115c32b4061b 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -204,7 +204,7 @@ static int sc6000_read(char __iomem *vport) + + } + +-static int sc6000_write(char __iomem *vport, int cmd) ++static int sc6000_write(struct device *devptr, char __iomem *vport, int cmd) + { + unsigned char val; + int loop = 500000; +@@ -221,18 +221,19 @@ static int sc6000_write(char __iomem *vport, int cmd) + cpu_relax(); + } while (loop--); + +- snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd); ++ dev_err(devptr, "DSP Command (0x%x) timeout.\n", cmd); + + return -EIO; + } + +-static int sc6000_dsp_get_answer(char __iomem *vport, int command, ++static int sc6000_dsp_get_answer(struct device *devptr, ++ char __iomem *vport, int command, + char *data, int data_len) + { + int len = 0; + +- if (sc6000_write(vport, command)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command); ++ if (sc6000_write(devptr, vport, command)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", command); + return -EIO; + } + +@@ -265,82 +266,86 @@ static int sc6000_dsp_reset(char __iomem *vport) + } + + /* detection and initialization */ +-static int sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) ++static int sc6000_hw_cfg_write(struct device *devptr, ++ char __iomem *vport, const int *cfg) + { +- if (sc6000_write(vport, COMMAND_6C) < 0) { +- snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C); ++ if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { ++ dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); + return -EIO; + } +- if (sc6000_write(vport, COMMAND_5C) < 0) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C); ++ if (sc6000_write(devptr, vport, COMMAND_5C) < 0) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_5C); + return -EIO; + } +- if (sc6000_write(vport, cfg[0]) < 0) { +- snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]); ++ if (sc6000_write(devptr, vport, cfg[0]) < 0) { ++ dev_err(devptr, "DATA 0x%x: failed!\n", cfg[0]); + return -EIO; + } +- if (sc6000_write(vport, cfg[1]) < 0) { +- snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]); ++ if (sc6000_write(devptr, vport, cfg[1]) < 0) { ++ dev_err(devptr, "DATA 0x%x: failed!\n", cfg[1]); + return -EIO; + } +- if (sc6000_write(vport, COMMAND_C5) < 0) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5); ++ if (sc6000_write(devptr, vport, COMMAND_C5) < 0) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", COMMAND_C5); + return -EIO; + } + + return 0; + } + +-static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg) ++static int sc6000_cfg_write(struct device *devptr, ++ char __iomem *vport, unsigned char softcfg) + { + +- if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); ++ if (sc6000_write(devptr, vport, WRITE_MDIRQ_CFG)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); + return -EIO; + } +- if (sc6000_write(vport, softcfg)) { +- snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); ++ if (sc6000_write(devptr, vport, softcfg)) { ++ dev_err(devptr, "%s: failed!\n", __func__); + return -EIO; + } + return 0; + } + +-static int sc6000_setup_board(char __iomem *vport, int config) ++static int sc6000_setup_board(struct device *devptr, ++ char __iomem *vport, int config) + { + int loop = 10; + + do { +- if (sc6000_write(vport, COMMAND_88)) { +- snd_printk(KERN_ERR "CMD 0x%x: failed!\n", +- COMMAND_88); ++ if (sc6000_write(devptr, vport, COMMAND_88)) { ++ dev_err(devptr, "CMD 0x%x: failed!\n", ++ COMMAND_88); + return -EIO; + } + } while ((sc6000_wait_data(vport) < 0) && loop--); + + if (sc6000_read(vport) < 0) { +- snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n", +- COMMAND_88); ++ dev_err(devptr, "sc6000_read after CMD 0x%x: failed\n", ++ COMMAND_88); + return -EIO; + } + +- if (sc6000_cfg_write(vport, config)) ++ if (sc6000_cfg_write(devptr, vport, config)) + return -ENODEV; + + return 0; + } + +-static int sc6000_init_mss(char __iomem *vport, int config, ++static int sc6000_init_mss(struct device *devptr, ++ char __iomem *vport, int config, + char __iomem *vmss_port, int mss_config) + { +- if (sc6000_write(vport, DSP_INIT_MSS)) { +- snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n", +- DSP_INIT_MSS); ++ if (sc6000_write(devptr, vport, DSP_INIT_MSS)) { ++ dev_err(devptr, "%s [0x%x]: failed!\n", __func__, ++ DSP_INIT_MSS); + return -EIO; + } + + msleep(10); + +- if (sc6000_cfg_write(vport, config)) ++ if (sc6000_cfg_write(devptr, vport, config)) + return -EIO; + + iowrite8(mss_config, vmss_port); +@@ -348,7 +353,8 @@ static int sc6000_init_mss(char __iomem *vport, int config, + return 0; + } + +-static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, ++ char __iomem *vport, int *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -367,10 +373,11 @@ static void sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, + cfg[0] |= 0x02; + cfg[1] |= 0x80; /* enable WSS system */ + cfg[1] &= ~0x40; /* disable IDE */ +- snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]); ++ dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(char __iomem *vport, ++static int sc6000_init_board(struct device *devptr, ++ char __iomem *vport, + char __iomem *vmss_port, int dev) + { + char answer[15]; +@@ -384,14 +391,14 @@ static int sc6000_init_board(char __iomem *vport, + + err = sc6000_dsp_reset(vport); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n"); ++ dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); + if (err <= 0) { +- snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n"); ++ dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; + } + /* +@@ -399,52 +406,52 @@ static int sc6000_init_board(char __iomem *vport, + * if we have something different, we have to be warned. + */ + if (strncmp("SC-6000", answer, 7)) +- snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); ++ dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) { +- snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n"); ++ if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } +- printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", ++ dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + + /* set configuration */ +- sc6000_write(vport, COMMAND_5C); ++ sc6000_write(devptr, vport, COMMAND_5C); + if (sc6000_read(vport) < 0) + old = 1; + + if (!old) { + int cfg[2]; +- sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev], ++ sc6000_hw_cfg_encode(devptr, ++ vport, &cfg[0], port[dev], mpu_port[dev], + mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(vport, cfg) < 0) { +- snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n"); ++ if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); + return -EIO; + } + } +- err = sc6000_setup_board(vport, config); ++ err = sc6000_setup_board(devptr, vport, config); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); + return -ENODEV; + } + + sc6000_dsp_reset(vport); + + if (!old) { +- sc6000_write(vport, COMMAND_60); +- sc6000_write(vport, 0x02); ++ sc6000_write(devptr, vport, COMMAND_60); ++ sc6000_write(devptr, vport, 0x02); + sc6000_dsp_reset(vport); + } + +- err = sc6000_setup_board(vport, config); ++ err = sc6000_setup_board(devptr, vport, config); + if (err < 0) { +- snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); + return -ENODEV; + } +- err = sc6000_init_mss(vport, config, vmss_port, mss_config); ++ err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); + if (err < 0) { +- snd_printk(KERN_ERR "Cannot initialize " +- "Microsoft Sound System mode.\n"); ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); + return -ENODEV; + } + +@@ -491,39 +498,39 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + if (!enable[dev]) + return 0; + if (port[dev] == SNDRV_AUTO_PORT) { +- printk(KERN_ERR PFX "specify IO port\n"); ++ dev_err(devptr, "specify IO port\n"); + return 0; + } + if (mss_port[dev] == SNDRV_AUTO_PORT) { +- printk(KERN_ERR PFX "specify MSS port\n"); ++ dev_err(devptr, "specify MSS port\n"); + return 0; + } + if (port[dev] != 0x220 && port[dev] != 0x240) { +- printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n"); ++ dev_err(devptr, "Port must be 0x220 or 0x240\n"); + return 0; + } + if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) { +- printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n"); ++ dev_err(devptr, "MSS port must be 0x530 or 0xe80\n"); + return 0; + } + if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) { +- printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]); ++ dev_err(devptr, "invalid IRQ %d\n", irq[dev]); + return 0; + } + if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) { +- printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]); ++ dev_err(devptr, "invalid DMA %d\n", dma[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + (mpu_port[dev] & ~0x30L) != 0x300) { +- printk(KERN_ERR PFX "invalid MPU-401 port %lx\n", ++ dev_err(devptr, "invalid MPU-401 port %lx\n", + mpu_port[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 && + !sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) { +- printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); ++ dev_err(devptr, "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); + return 0; + } + return 1; +@@ -534,7 +541,7 @@ static void snd_sc6000_free(struct snd_card *card) + char __iomem *vport = (char __force __iomem *)card->private_data; + + if (vport) +- sc6000_setup_board(vport, 0); ++ sc6000_setup_board(card->dev, vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -558,7 +565,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); + if (xirq < 0) { +- snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); ++ dev_err(devptr, "unable to find a free IRQ\n"); + return -EBUSY; + } + } +@@ -566,42 +573,39 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + if (xdma == SNDRV_AUTO_DMA) { + xdma = snd_legacy_find_free_dma(possible_dmas); + if (xdma < 0) { +- snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); ++ dev_err(devptr, "unable to find a free DMA\n"); + return -EBUSY; + } + } + + if (!devm_request_region(devptr, port[dev], 0x10, DRV_NAME)) { +- snd_printk(KERN_ERR PFX +- "I/O port region is already in use.\n"); ++ dev_err(devptr, "I/O port region is already in use.\n"); + return -EBUSY; + } + vport = devm_ioport_map(devptr, port[dev], 0x10); + if (!vport) { +- snd_printk(KERN_ERR PFX +- "I/O port cannot be iomapped.\n"); ++ dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } + card->private_data = (void __force *)vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +- snd_printk(KERN_ERR PFX +- "SC-6000 port I/O port region is already in use.\n"); ++ dev_err(devptr, ++ "SC-6000 port I/O port region is already in use.\n"); + return -EBUSY; + } + vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); + if (!vmss_port) { +- snd_printk(KERN_ERR PFX +- "MSS port I/O cannot be iomapped.\n"); ++ dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } + +- snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", +- port[dev], xirq, xdma, +- mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); ++ dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", ++ port[dev], xirq, xdma, ++ mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(vport, vmss_port, dev); ++ err = sc6000_init_board(devptr, vport, vmss_port, dev); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +@@ -613,25 +617,24 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + + err = snd_wss_pcm(chip, 0); + if (err < 0) { +- snd_printk(KERN_ERR PFX +- "error creating new WSS PCM device\n"); ++ dev_err(devptr, "error creating new WSS PCM device\n"); + return err; + } + err = snd_wss_mixer(chip); + if (err < 0) { +- snd_printk(KERN_ERR PFX "error creating new WSS mixer\n"); ++ dev_err(devptr, "error creating new WSS mixer\n"); + return err; + } + err = snd_sc6000_mixer(chip); + if (err < 0) { +- snd_printk(KERN_ERR PFX "the mixer rewrite failed\n"); ++ dev_err(devptr, "the mixer rewrite failed\n"); + return err; + } + if (snd_opl3_create(card, + 0x388, 0x388 + 2, + OPL3_HW_AUTO, 0, &opl3) < 0) { +- snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n", +- 0x388, 0x388 + 2); ++ dev_err(devptr, "no OPL device at 0x%x-0x%x ?\n", ++ 0x388, 0x388 + 2); + } else { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) +@@ -645,8 +648,8 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + MPU401_HW_MPU401, + mpu_port[dev], 0, + mpu_irq[dev], NULL) < 0) +- snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", +- mpu_port[dev]); ++ dev_err(devptr, "no MPU-401 device at 0x%lx ?\n", ++ mpu_port[dev]); + } + + strcpy(card->driver, DRV_NAME); +-- +2.53.0 + diff --git a/queue-6.6/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch b/queue-6.6/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch new file mode 100644 index 0000000000..5afc84774e --- /dev/null +++ b/queue-6.6/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch @@ -0,0 +1,39 @@ +From 65b88d32eb8f56195874262eb9baea71ea243aa8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 01:25:48 +0300 +Subject: ALSA: scarlett2: Add missing sentinel initializer field + +From: Panagiotis Petrakopoulos + +[ Upstream commit 2428cd6e8b6fa80c36db4652702ca0acd2ce3f08 ] + +A "-Wmissing-field-initializers" warning was emitted when compiling the +module using the W=2 option. There is a sentinel initializer field +missing in the end of scarlett2_devices[]. Tested using a +Scarlett Solo 4th gen. + +Fixes: d98cc489029d ("ALSA: scarlett2: Move USB IDs out from device_info struct") +Signed-off-by: Panagiotis Petrakopoulos +Link: https://patch.msgid.link/20260405222548.8903-1-npetrakopoulos2003@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_scarlett2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index c4b29b3670cd4..8aa7414d0b2fa 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -1011,7 +1011,7 @@ static const struct scarlett2_device_entry scarlett2_devices[] = { + { USB_ID(0x1235, 0x820c), &clarett_8pre_info, "Clarett+" }, + + /* End of list */ +- { 0, NULL }, ++ { 0, NULL, NULL }, + }; + + /* get the starting port index number for a given port type/direction */ +-- +2.53.0 + diff --git a/queue-6.6/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch b/queue-6.6/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch new file mode 100644 index 0000000000..ba3dac08b4 --- /dev/null +++ b/queue-6.6/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch @@ -0,0 +1,205 @@ +From 82ccd2956ac78a7f53ae8f98fd88666edfeef484 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 17:15:04 +0200 +Subject: ALSA: usb-audio: Fix potential leak of pd at parsing UAC3 streams + +From: Takashi Iwai + +[ Upstream commit c39f0bc03f84ba64c9144c95714df1dc36150f6d ] + +At parsing UAC3 streams, we allocate a PD object at each time, and +either assign or free it. But there is a case where the PD object may +be leaked; namely, in __snd_usb_parse_audio_interface() loop, when an +audioformat shares the same endpoint with others, it's put to a link +and returns from snd_usb_add_audio_stream(), but the PD is forgotten +afterwards. Overall, the treatment of PD object in the parser code is +a bit flaky, and we should be more careful about the object ownership. + +This patch tries to fix the above case and improve the code a bit. +The pd object is now managed with the auto-cleanup in the loop, and +the ownership is updated when the pd object gets assigned to the +stream, which guarantees the release of the leftover object. + +Fixes: 7edf3b5e6a45 ("ALSA: usb-audio: AudioStreaming Power Domain parsing") +Link: https://patch.msgid.link/20260427151508.12544-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 +- + sound/usb/stream.c | 58 ++++++++++++++++++---------------------------- + sound/usb/stream.h | 3 ++- + 3 files changed, 25 insertions(+), 38 deletions(-) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 847878438b8b7..ed625d5bbe9ab 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip, + + snd_usb_audioformat_set_sync_ep(chip, fp); + +- err = snd_usb_add_audio_stream(chip, stream, fp); ++ err = snd_usb_add_audio_stream(chip, stream, fp, NULL); + if (err < 0) + return err; + +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index 920a718f91e68..f964082da3a63 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) + static void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, + struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++ struct snd_usb_power_domain **pdptr) + { + struct snd_usb_substream *subs = &as->substream[stream]; + +@@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, + if (fp->channels > subs->channels_max) + subs->channels_max = fp->channels; + +- if (pd) { +- subs->str_pd = pd; ++ if (pdptr && *pdptr) { ++ subs->str_pd = *pdptr; ++ *pdptr = NULL; /* assigned */ + /* Initialize Power Domain to idle status D1 */ +- snd_usb_power_domain_set(subs->stream->chip, pd, ++ snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, + UAC3_PD_STATE_D1); + } + +@@ -486,11 +487,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor + * if not, create a new pcm stream. note, fp is added to the substream + * fmt_list and will be freed on the chip instance release. do not free + * fp or do remove it from the substream fmt_list to avoid double-free. ++ * ++ * pdptr is optional and can be NULL. When it's non-NULL and the PD gets ++ * assigned to the stream, *pdptr is cleared to NULL upon return. + */ +-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++int snd_usb_add_audio_stream(struct snd_usb_audio *chip, ++ int stream, ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr) + + { + struct snd_usb_stream *as; +@@ -523,7 +527,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + err = snd_pcm_new_stream(as->pcm, stream, 1); + if (err < 0) + return err; +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + return add_chmap(as->pcm, stream, subs); + } + +@@ -551,7 +555,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + else + strcpy(pcm->name, "USB Audio"); + +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + + /* + * Keep using head insertion for M-Audio Audiophile USB (tm) which has a +@@ -569,21 +573,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + return add_chmap(pcm, stream, &as->substream[stream]); + } + +-int snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, NULL); +-} +- +-static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, pd); +-} +- + static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, + struct usb_host_interface *alts, + int protocol, int iface_no) +@@ -1102,8 +1091,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + } + } + +- if (pd) +- *pd_out = pd; ++ *pd_out = pd; + + return fp; + } +@@ -1118,7 +1106,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + struct usb_interface_descriptor *altsd; + int i, altno, err, stream; + struct audioformat *fp = NULL; +- struct snd_usb_power_domain *pd = NULL; + bool set_iface_first; + int num, protocol; + +@@ -1160,6 +1147,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) + continue; + ++ /* pd may be allocated at snd_usb_get_audioformat_uac3() and ++ * assigned at snd_usb_add_audio_stream(); otherwise it'll be ++ * freed automatically by cleanup at each loop. ++ */ ++ struct snd_usb_power_domain *pd __free(kfree) = NULL; ++ + /* + * Roland audio streaming interfaces are marked with protocols + * 0/1/2, but are UAC 1 compatible. +@@ -1215,23 +1208,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + *has_non_pcm = true; + if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { + audioformat_free(fp); +- kfree(pd); + fp = NULL; +- pd = NULL; + continue; + } + + snd_usb_audioformat_set_sync_ep(chip, fp); + + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); +- if (protocol == UAC_VERSION_3) +- err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); +- else +- err = snd_usb_add_audio_stream(chip, stream, fp); +- ++ err = snd_usb_add_audio_stream(chip, stream, fp, &pd); + if (err < 0) { + audioformat_free(fp); +- kfree(pd); + return err; + } + +diff --git a/sound/usb/stream.h b/sound/usb/stream.h +index d92e18d5818fe..61b9a133da018 100644 +--- a/sound/usb/stream.h ++++ b/sound/usb/stream.h +@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + + int snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, +- struct audioformat *fp); ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr); + + #endif /* __USBAUDIO_STREAM_H */ + +-- +2.53.0 + diff --git a/queue-6.6/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch b/queue-6.6/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch new file mode 100644 index 0000000000..35af0cac28 --- /dev/null +++ b/queue-6.6/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch @@ -0,0 +1,76 @@ +From 79bf3afa839ff2c7cd4102e863599c6cf5c57133 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 18:12:55 -0500 +Subject: ARM: dts: imx27-eukrea: replace interrupts with interrupts-extended + +From: Frank Li + +[ Upstream commit 0477a6b31e2874e554e3bcfac9883684b8f8ca2d ] + +The property interrupts use default interrupt controllers. But pass down +gpio as phandle. Correct it by use interrupts-extended. + +Fixes: d8cae888aa2bc ("ARM: dts: Add support for the cpuimx27 board from Eukrea and its baseboard") +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi | 8 ++++---- + .../boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +index c7e9235848782..9f0e65526d5f9 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +@@ -106,7 +106,7 @@ uart8250@3,200000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x200000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -119,7 +119,7 @@ uart8250@3,400000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x400000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -132,7 +132,7 @@ uart8250@3,800000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x800000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -145,7 +145,7 @@ uart8250@3,1000000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x1000000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +index d78793601306c..c71f802983304 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +@@ -76,7 +76,7 @@ ads7846@0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_touch>; + reg = <0>; +- interrupts = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; + spi-cpol; + spi-max-frequency = <1500000>; + ti,keep-vref-on; +-- +2.53.0 + diff --git a/queue-6.6/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch b/queue-6.6/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch new file mode 100644 index 0000000000..f709db87f0 --- /dev/null +++ b/queue-6.6/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch @@ -0,0 +1,46 @@ +From 5952e82d795b60246cdf5063ac4a175161f6d242 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 09:25:41 +0100 +Subject: ARM: dts: mediatek: mt7623: fix efuse fallback compatible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafał Miłecki + +[ Upstream commit 5978ff33cc6f0988388a2830dc5cd2ea4e81f36a ] + +Fix following validation error: +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: compatible: 'oneOf' conditional failed, one must be fixed: + ['mediatek,mt7623-efuse', 'mediatek,mt8173-efuse'] is too long + 'mediatek,mt8173-efuse' was expected + 'mediatek,efuse' was expected + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: Unevaluated properties are not allowed ('compatible' was unexpected) + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# + +Fixes: 43c7a91b4b3a ("arm: dts: mt7623: add efuse nodes to the mt7623.dtsi file") +Signed-off-by: Rafał Miłecki +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/mediatek/mt7623.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi +index 9c5a52ce9351a..748f9b3668975 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623.dtsi ++++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi +@@ -328,7 +328,7 @@ sysirq: interrupt-controller@10200100 { + + efuse: efuse@10206000 { + compatible = "mediatek,mt7623-efuse", +- "mediatek,mt8173-efuse"; ++ "mediatek,efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.6/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch b/queue-6.6/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch new file mode 100644 index 0000000000..d96452611b --- /dev/null +++ b/queue-6.6/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch @@ -0,0 +1,40 @@ +From af063935a6c1f12cd7ad5146afeb4b8cc4f665ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 19:15:10 +0200 +Subject: ARM: OMAP1: Fix DEBUG_LL and earlyprintk on OMAP16XX + +From: Aaro Koskinen + +[ Upstream commit 7e74b606dd39c46d4378d6f6563f560a00ab8694 ] + +On OMAP16XX, the UART enable bit shifts are written instead of the actual +bits. This breaks the boot when DEBUG_LL and earlyprintk is enabled; +the UART gets disabled and some random bits get enabled. Fix that. + +Fixes: 34c86239b184 ("ARM: OMAP1: clock: Fix early UART rate issues") +Signed-off-by: Aaro Koskinen +Link: https://patch.msgid.link/aca7HnXZ-aCSJPW7@darkstar.musicnaut.iki.fi +Signed-off-by: Kevin Hilman +Signed-off-by: Sasha Levin +--- + arch/arm/mach-omap1/clock_data.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c +index c58d200e4816b..5203b047deac8 100644 +--- a/arch/arm/mach-omap1/clock_data.c ++++ b/arch/arm/mach-omap1/clock_data.c +@@ -700,8 +700,8 @@ int __init omap1_clk_init(void) + /* Make sure UART clocks are enabled early */ + if (cpu_is_omap16xx()) + omap_writel(omap_readl(MOD_CONF_CTRL_0) | +- CONF_MOD_UART1_CLK_MODE_R | +- CONF_MOD_UART3_CLK_MODE_R, MOD_CONF_CTRL_0); ++ (1 << CONF_MOD_UART1_CLK_MODE_R) | ++ (1 << CONF_MOD_UART3_CLK_MODE_R), MOD_CONF_CTRL_0); + #endif + + /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ +-- +2.53.0 + diff --git a/queue-6.6/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch b/queue-6.6/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch new file mode 100644 index 0000000000..d6ad84094a --- /dev/null +++ b/queue-6.6/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch @@ -0,0 +1,56 @@ +From 086e64c21eee31a15565477bf6ffcb6ea4d91691 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:28:18 +0000 +Subject: arm64: cpufeature: Make PMUVer and PerfMon unsigned + +From: James Clark + +[ Upstream commit d1dcc20bcc40efe1f1c71639376c91dafa489222 ] + +On the host, this change doesn't make a difference because the fields +are defined as FTR_EXACT. However, KVM allows userspace to set these +fields for a guest and overrides the type to be FTR_LOWER_SAFE. And +while KVM used to do an unsigned comparison to validate that the new +value is lower than what the hardware provides, since the linked commit +it uses the generic sanitization framework which does a signed +comparison. + +Fix it by defining these fields as unsigned. In theory, without this +fix, userspace could set a higher PMU version than the hardware supports +by providing any value with the top bit set. + +Fixes: c118cead07a7 ("KVM: arm64: Use generic sanitisation for ID_(AA64)DFR0_EL1") +Signed-off-by: James Clark +Reviewed-by: Marc Zyngier +Reviewed-by: Colton Lewis +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/cpufeature.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c +index 4561c4a670afb..5db25bfb854ff 100644 +--- a/arch/arm64/kernel/cpufeature.c ++++ b/arch/arm64/kernel/cpufeature.c +@@ -453,7 +453,7 @@ static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = { + * We can instantiate multiple PMU instances with different levels + * of support. + */ +- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), ++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_EL1_DebugVer_SHIFT, 4, 0x6), + ARM64_FTR_END, + }; +@@ -597,7 +597,7 @@ static const struct arm64_ftr_bits ftr_id_pfr2[] = { + + static const struct arm64_ftr_bits ftr_id_dfr0[] = { + /* [31:28] TraceFilt */ +- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), ++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MProfDbg_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MMapTrc_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopTrc_SHIFT, 4, 0), +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8-apalis-fix-leds-name-collision.patch b/queue-6.6/arm64-dts-imx8-apalis-fix-leds-name-collision.patch new file mode 100644 index 0000000000..d4417457c1 --- /dev/null +++ b/queue-6.6/arm64-dts-imx8-apalis-fix-leds-name-collision.patch @@ -0,0 +1,103 @@ +From d00e8a0e8186180ed38339787bec40b2591da018 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:34:09 +0100 +Subject: arm64: dts: imx8-apalis: Fix LEDs name collision + +From: Francesco Dolcini + +[ Upstream commit 92ab53b9bb2a72581c32073755077af916eb9aee ] + +Ixora boards have multiple instances of status leds, to avoid a name +collision add the function-enumerator property. + +This fixes the following Linux kernel warnings: + + leds-gpio leds: Led green:status renamed to green:status_1 due to name collision + leds-gpio leds: Led red:status renamed to red:status_1 due to name collision + +Fixes: c083131c9021 ("arm64: dts: freescale: add apalis imx8 aka quadmax carrier board support") +Signed-off-by: Francesco Dolcini +Reviewed-by: Frank Li +Reviewed-by: Daniel Baluta +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi | 4 ++++ + arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +index c6d51f1162985..4802834e26a86 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +@@ -21,6 +21,7 @@ led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; + }; + +@@ -29,6 +30,7 @@ led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; + }; + +@@ -37,6 +39,7 @@ led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; + }; + +@@ -45,6 +48,7 @@ led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +index 40067ab8aa74b..b28dd1cece8ab 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +@@ -21,6 +21,7 @@ led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; + }; + +@@ -29,6 +30,7 @@ led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; + }; + +@@ -37,6 +39,7 @@ led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; + }; + +@@ -45,6 +48,7 @@ led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; + }; + }; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch b/queue-6.6/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..b592eb25e5 --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch @@ -0,0 +1,48 @@ +From d6f917256dcf880330aa38ca6cdedd281e672078 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:11 +0800 +Subject: arm64: dts: imx8mm-emtop-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 721dec3ee9ff5231d13a412ff87df63b966d137b ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +While at here, also correct interrupt type as IRQ_TYPE_LEVEL_LOW. + +Fixes: cbd3ef64eb9d1 ("arm64: dts: Add support for Emtop SoM & Baseboard") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +index 67d22d3768aa8..507d1824d99d9 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +@@ -60,7 +60,7 @@ pmic@25 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; +- interrupts = <3 IRQ_TYPE_EDGE_RISING>; ++ interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + regulators { + buck1: BUCK1 { +@@ -194,7 +194,7 @@ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 + + pinctrl_pmic: emtop-pmic-grp { + fsl,pins = < +- MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41 ++ MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x141 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch b/queue-6.6/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..52ea63d109 --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From d435ae30efc2bd7bef97e0e6614c6c1afc174fdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:13 +0800 +Subject: arm64: dts: imx8mm-tqma8mqml: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 42a9f5a16328ed78a88e0498556965b6c6ec515c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: dfcd1b6f7620e ("arm64: dts: freescale: add initial device tree for TQMa8MQML with i.MX8MM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +index b4466a26d838a..6d79447b8fa08 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +@@ -282,7 +282,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch b/queue-6.6/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..e2e8c66dc2 --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 0f423487ec15f42ff894068ec927fc1d016690e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:12 +0800 +Subject: arm64: dts: imx8mn-tqma8mqnl: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 0fb37990774113afd943eaa91323679388584b6d ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: 3e56e354db6d3 ("arm64: dts: freescale: add initial device tree for TQMa8MQNL with i.MX8MN") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +index 78aaa04ebbc08..ca02f7ff37645 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +@@ -284,7 +284,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch b/queue-6.6/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch new file mode 100644 index 0000000000..c8a71fc4c7 --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch @@ -0,0 +1,38 @@ +From 8f904f85331e667281f26cb6076aacd888993328 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:16 +0800 +Subject: arm64: dts: imx8mp-data-modul-edm-sbc: Correct PAD settings for + PMIC_nINT + +From: Peng Fan + +[ Upstream commit 8ff145577e93f312ff398cb950ee3bd44835f5be ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 562d222f23f0f ("arm64: dts: imx8mp: Add support for Data Modul i.MX8M Plus eDM SBC") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +index 678ecc9f81dbb..816469fcd5d76 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +@@ -780,7 +780,7 @@ MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_PDM_BIT_STREAM00 0x0 + pinctrl_pmic: pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch b/queue-6.6/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch new file mode 100644 index 0000000000..88882a3a1b --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch @@ -0,0 +1,42 @@ +From acb4d338d0d681f6d357625bb817e9b191bd0a06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:05 +0800 +Subject: arm64: dts: imx8mp-debix-model-a: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 3b778178997aee24537b521a8cb60970bc1ce01c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there is interrupt storm for i.MX8MP DEBIX Model A. Per schematic, there +is no on board PULL-UP resistors for GPIO1_IO03, so need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: c86d350aae68e ("arm64: dts: Add device tree for the Debix Model A Board") +Reported-by: Laurent Pinchart +Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/ +Reviewed-by: Laurent Pinchart +Tested-by: Laurent Pinchart +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +index 267ceffc02d84..5525240ff351e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +@@ -395,7 +395,7 @@ MX8MP_IOMUXC_SAI5_RXC__I2C6_SDA 0x400001c3 + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch b/queue-6.6/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..e78d23e741 --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch @@ -0,0 +1,56 @@ +From a64c7801fec083d631cae0684a0bff5f38ae42bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:06 +0800 +Subject: arm64: dts: imx8mp-debix-som-a: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 2ea7872048a179b0ea8dadc67771961df3f0fc4a ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there is interrupt storm for i.MX8MP DEBIX SOM A. Need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: 21baf0b47f81b ("arm64: dts: freescale: Add DEBIX SOM A and SOM A I/O Board support") +Reported-by: Laurent Pinchart +Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/ +Reported-by: Kieran Bingham +Closes: https://lore.kernel.org/imx/20260324194353.GB2352505@killaraus.ideasonboard.com/T/#m9a07fdc75496369a7d76d52c5e34ed140dcabfe3 +Signed-off-by: Peng Fan +Reviewed-by: Kieran Bingham +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts | 2 +- + arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +index 0b0c95432bdc4..3ee28e9f99877 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +@@ -409,7 +409,7 @@ MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x140 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +index bc312aa1bfc8b..ad3e22008b697 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +@@ -219,7 +219,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch b/queue-6.6/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..80432f2c9b --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 4449b009b49411f1337fb680e6cb310bbfb97faf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:15 +0800 +Subject: arm64: dts: imx8mp-dhcom-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit f9ed5afc988da3e22543725e35be6addbb0497bc ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 8d6712695bc8e ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +index 2ff47f6ec7979..e1b2b1d4ff39f 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +@@ -902,7 +902,7 @@ MX8MP_IOMUXC_HDMI_DDC_SDA__GPIO3_IO27 0x84 + pinctrl_pmic: dhcom-pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch b/queue-6.6/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch new file mode 100644 index 0000000000..bd28805f4a --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch @@ -0,0 +1,43 @@ +From 1c4dcf83e06aaaba741affa6da47c01ba4ddfc8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 15:34:53 +0800 +Subject: arm64: dts: imx8mp-evk: Enable pull select bit for PCIe regulator + GPIO (M.2 W_DISABLE1) + +From: Sherry Sun + +[ Upstream commit d1e7eab6033f9885a02c4b4e8f09e34d8e9d21ab ] + +The current pin configuration for MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 +sets the weak pull-up but does not enable the pull select field. +Bit 8 in the IOMUX register must be set in order for the weak pull-up +to actually take effect. + +Update the pinctrl setting from 0x40 to 0x140 to enable both the pull +select and the weak pull-up, ensuring the line behaves as expected. + +Fixes: d50650500064 ("arm64: dts: imx8mp-evk: Add PCIe support") +Signed-off-by: Sherry Sun +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +index 92f8cc05fe9da..e29b6e9a70276 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +@@ -764,7 +764,7 @@ MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07 0x40 + + pinctrl_pcie0_reg: pcie0reggrp { + fsl,pins = < +- MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x40 ++ MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x140 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch b/queue-6.6/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..9bd2c9e0e0 --- /dev/null +++ b/queue-6.6/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch @@ -0,0 +1,37 @@ +From a347d6bc2cf06cf5734b862adca0d6117f7ece92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:09 +0800 +Subject: arm64: dts: imx8mp-icore-mx8mp: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit ea8c90f5c7ceeb6657a8fe564aa7b190dce298a6 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: eefe06b295087 ("arm64: dts: imx8mp: Add Engicam i.Core MX8M Plus SoM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +index a6319824ea2eb..69558ffefa9a6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +@@ -132,7 +132,7 @@ MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x41 ++ MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch b/queue-6.6/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch new file mode 100644 index 0000000000..9f14b2f7a3 --- /dev/null +++ b/queue-6.6/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch @@ -0,0 +1,57 @@ +From f26185ac88fed6f815c977d8c7bba0113a8e7a3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:04:59 +0800 +Subject: arm64: dts: imx8qxp-mek: switch Type-C connector power-role to dual + +From: Xu Yang + +[ Upstream commit 825b8c7e1d2918d89eb378b761530d1e51dba82e ] + +When attach to PC Type-A port, the USB device controller does not function +at all. Because it is configured as source-only and a Type-A port doesn't +support PD capability, a data role swap is impossible. + +Actually, PTN5110THQ is configured for Source role only at POR, but after +POR it can operate as a DRP (Dual-Role Power). By switching the power-role +to dual, the port can operate as a sink and enter device mode when attach +to Type-A port. + +Since the board design uses EN_SRC to control the 5V VBUS path and EN_SNK +to control the 12V VBUS output, to avoid outputting a higher VBUS when in +sink role, we set the operation current limit to 0mA so that SW will not +control EN_SNK at all. + +Fixes: 2faf4ebcee2e5 ("arm64: dts: freescale: imx8qxp-mek: enable cadence usb3") +Signed-off-by: Xu Yang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +index 7924b0969ad8f..3814568e4ee50 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts ++++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +@@ -161,9 +161,17 @@ typec_dr_sw: endpoint { + usb_con1: connector { + compatible = "usb-c-connector"; + label = "USB-C"; +- power-role = "source"; ++ power-role = "dual"; + data-role = "dual"; ++ try-power-role = "sink"; + source-pdos = ; ++ /* ++ * Set operational current to 0mA as we don't want EN_SNK ++ * enable 12V VBUS switch when it work as a sink. ++ */ ++ sink-pdos = ; ++ op-sink-microwatt = <0>; ++ self-powered; + + ports { + #address-cells = <1>; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch b/queue-6.6/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..ef26580d40 --- /dev/null +++ b/queue-6.6/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From bf9e0d866e1e4353236c86f94570a5176ccdf903 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:28 +0900 +Subject: arm64: dts: mediatek: mt6795: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit c4c4823c8a5baa10b8100b01f49d7c3f4a871689 ] + +The gpio-ranges in the MT6795 pinctrl node were incorrectly defined, +therefore, GPIO196 cannot be used. +Correct the range count to match the driver. + +Fixes: b888886a4536 ("arm64: dts: mediatek: mt6795: Add pinctrl controller node") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt6795.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +index 597bce2fed729..228c15b962ea0 100644 +--- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +@@ -353,7 +353,7 @@ pio: pinctrl@10005000 { + ; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 196>; ++ gpio-ranges = <&pio 0 0 197>; + interrupt-controller; + #interrupt-cells = <2>; + }; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch b/queue-6.6/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..e3a02992d2 --- /dev/null +++ b/queue-6.6/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From ef09eb34f42200c05e66ee5f5f2e161773b74e61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:30 +0900 +Subject: arm64: dts: mediatek: mt7986a: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit 820ed0c1a13c5fafb36232538d793f99a0986ef3 ] + +The gpio-ranges in the MT7986A pinctrl node were incorrectly defined, +therefore, pin 100 cannot be used. +Correct the range count to match the driver. + +Fixes: c3a064a32ed9 ("arm64: dts: mediatek: add pinctrl support for mt7986a") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 559990dcd1d17..05bd2938242fc 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -187,7 +187,7 @@ pio: pinctrl@1001f000 { + "iocfg_lb", "iocfg_tr", "iocfg_tl", "eint"; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 100>; ++ gpio-ranges = <&pio 0 0 101>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch b/queue-6.6/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch new file mode 100644 index 0000000000..673a2295cb --- /dev/null +++ b/queue-6.6/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch @@ -0,0 +1,44 @@ +From 4a913b08e7ec886cd7a77495fe1c220cc6ff0e68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:51:11 +0800 +Subject: arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number + +From: Jun Yan + +[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ] + +Correct the interrupt number assigned to the Realtek PHY in the p230 + +following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm: +fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY +interrupt improvements [1]. + +[1] https://lore.kernel.org/all/20171202214037.17017-1-martin.blumenstingl@googlemail.com/ + +Fixes: b94d22d94ad2 ("ARM64: dts: meson-gx: add external PHY interrupt on some platforms") +Signed-off-by: Jun Yan +Reviewed-by: Martin Blumenstingl +Link: https://patch.msgid.link/20260330145111.115318-1-jerrysteve1101@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +index c1470416faade..36e97ed585ae7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +@@ -84,7 +84,8 @@ external_phy: ethernet-phy@0 { + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; +- interrupts = <29 IRQ_TYPE_LEVEL_LOW>; ++ /* MAC_INTR on GPIOZ_15 */ ++ interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + eee-broken-1000t; + }; + }; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch b/queue-6.6/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch new file mode 100644 index 0000000000..2b0876f22b --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch @@ -0,0 +1,44 @@ +From 2e8efce8d00d0dae5f164f2a6fbc68b086f2027b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:39 +0100 +Subject: arm64: dts: qcom: msm8953-xiaomi-daisy: fix backlight +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 7131f6d909a6546329b71f2bacfdc60cb3e6020e ] + +The backlight on this device is connected via 3 strings. Currently, +the DT claims only two are present, which results in visible stripes +on the display (since every third backlight string remains unconfigured). + +Fix the number of strings to avoid that. + +Fixes: 38d779c26395 ("arm64: dts: qcom: msm8953: Add device tree for Xiaomi Mi A2 Lite") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-7-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +index a5957e79b818c..eaea9d843f2ff 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +@@ -157,7 +157,7 @@ &pm8953_resin { + + &pmi8950_wled { + qcom,current-limit-microamp = <20000>; +- qcom,num-strings = <2>; ++ qcom,num-strings = <3>; + + status = "okay"; + }; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch b/queue-6.6/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch new file mode 100644 index 0000000000..71622d56f5 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch @@ -0,0 +1,41 @@ +From 2c0fec6dba953c4eb54d21e0b07bbe3af31d9a15 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:37 +0100 +Subject: arm64: dts: qcom: msm8953-xiaomi-vince: correct wled ovp value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 9e87f0eaadccc3fecdf3c3c0334e05694804b5f5 ] + +PMI8950 doesn't actually support setting an OVP threshold value of +29.6 V. The closest allowed value is 29.5 V. Set that instead. + +Fixes: aa17e707e04a ("arm64: dts: qcom: msm8953: Add device tree for Xiaomi Redmi 5 Plus") +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-5-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +index b0588f30f8f1a..4318d11df322b 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +@@ -169,7 +169,7 @@ &pm8953_resin { + + &pmi8950_wled { + qcom,current-limit-microamp = <20000>; +- qcom,ovp-millivolt = <29600>; ++ qcom,ovp-millivolt = <29500>; + qcom,num-strings = <2>; + qcom,external-pfet; + qcom,cabc; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch b/queue-6.6/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch new file mode 100644 index 0000000000..e1c480961d --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch @@ -0,0 +1,38 @@ +From 21b8c0c075c01d19eb51a31e55eac286069a7be4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 18:33:11 +0100 +Subject: arm64: dts: qcom: sdm845-xiaomi-beryllium: Mark l1a regulator as + powered during boot + +From: David Heidelberg + +[ Upstream commit 3b0dd81eea6b7a239fce456ce4545af76f1a9715 ] + +The regulator must be on, since it provides the display subsystem and +therefore the bootloader had turned it on before Linux booted. + +Fixes: 77809cf74a8c ("arm64: dts: qcom: Add support for Xiaomi Poco F1 (Beryllium)") +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260320-beryllium-booton-v2-1-931d1be21eae@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +index 9d6faeb656244..f0a185b559ec0 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +@@ -147,6 +147,7 @@ vreg_l1a_0p875: ldo1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l5a_0p8: ldo5 { +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch b/queue-6.6/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch new file mode 100644 index 0000000000..0e27592ac6 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch @@ -0,0 +1,63 @@ +From 7d920c4d59798ee00204a9007c0122d4c1167101 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 09:55:00 +0100 +Subject: arm64: dts: qcom: sm7225-fairphone-fp4: Fix conflicting bias pinctrl + +From: Luca Weiss + +[ Upstream commit be7c1badb0b934cfe88427b1d4ec3eb9f52ba587 ] + +The pinctrl nodes from sm6350.dtsi already contain a bias-* property, so +that needs to be deleted, otherwise the dtb will contain two conflicting +bias-* properties. + +Reported-by: Conor Dooley +Closes: https://lore.kernel.org/r/20260310-maritime-silly-05e7b7e03aa6@spud/ +Fixes: c4ef464b24c5 ("arm64: dts: qcom: sm7225-fairphone-fp4: Add Bluetooth") +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Reviewed-by: Conor Dooley +Link: https://lore.kernel.org/r/20260319-fp4-uart1-fix-v1-1-f6b3fedef583@fairphone.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +index c010e86134ff9..606f7a6f41791 100644 +--- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts ++++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +@@ -533,12 +533,14 @@ &qup_uart1_cts { + * the Bluetooth module drives the pin in either + * direction or leaves the pin fully unpowered. + */ ++ /delete-property/ bias-disable; + bias-bus-hold; + }; + + &qup_uart1_rts { + /* We'll drive RTS, so no pull */ + drive-strength = <2>; ++ /delete-property/ bias-pull-down; + bias-disable; + }; + +@@ -549,12 +551,14 @@ &qup_uart1_rx { + * in tri-state (module powered off or not driving the + * signal yet). + */ ++ /delete-property/ bias-disable; + bias-pull-up; + }; + + &qup_uart1_tx { + /* We'll drive TX, so no pull */ + drive-strength = <2>; ++ /delete-property/ bias-pull-up; + bias-disable; + }; + +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch b/queue-6.6/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch new file mode 100644 index 0000000000..756e3297de --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch @@ -0,0 +1,43 @@ +From d3ed71dbb645d7adf16176e2daa5eb28fac8509d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 04:26:37 +0000 +Subject: arm64: dts: qcom: sm8250: Add missing CPU7 3.09GHz OPP + +From: Alexander Koskovich + +[ Upstream commit b683730e27ba4f91986c4c92f5cb7297f1e01a6d ] + +This resolves the following error seen on the ASUS ROG Phone 3: + +cpu cpu7: Voltage update failed freq=3091200 +cpu cpu7: failed to update OPP for freq=3091200 + +Fixes: 8e0e8016cb79 ("arm64: dts: qcom: sm8250: Add CPU opp tables") +Signed-off-by: Alexander Koskovich +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260307-sm8250-cpu7-opp-v1-1-435f5f6628a1@pm.me +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8250.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi +index c9a7d1b75c658..d8086dae6e4f8 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi +@@ -659,6 +659,11 @@ cpu7_opp20: opp-2841600000 { + opp-hz = /bits/ 64 <2841600000>; + opp-peak-kBps = <8368000 51609600>; + }; ++ ++ cpu7_opp21: opp-3091200000 { ++ opp-hz = /bits/ 64 <3091200000>; ++ opp-peak-kBps = <8368000 51609600>; ++ }; + }; + + firmware { +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.6/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..47f5cc2e96 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,75 @@ +From e20d5bd621f2554ea629717902975752f669b610 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:13 +0200 +Subject: arm64: dts: qcom: sm8450: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit db0c5ef1abda6effdc5c85d6688fb6af2b351ae5 ] + +The reported problem of some non-working UHS-I speed modes on SM8450 +originates in commit 0a631a36f724 ("arm64: dts: qcom: Add device tree +for Sony Xperia 1 IV"), and then it was spread to all SM8450 powered +platforms by commit 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable +SDHCI SDR104/SDR50 on all boards"). + +The tests show that the rootcause of the problem was related to an +overclocking of SD cards, and it's fixed later on by commit a27ac3806b0a +("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs"). + +Since then both SDR50 and SDR104 speed modes are working fine on SM8450, +tested on SM8450-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 24.6254 s, 43.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 12.3266 s, 87.1 MB/s + +Remove the restrictions on SD card speed modes from the SM8450 platform +dtsi file and enable UHS-I speed modes. + +Fixes: 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable SDHCI SDR104/SDR50 on all boards") +Reviewed-by: Neil Armstrong +Reviewed-by: Konrad Dybcio +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-5-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index b745d8b476408..c1c62c6d34bd1 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -4279,9 +4279,6 @@ sdhc_2: mmc@8804000 { + bus-width = <4>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0x0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch b/queue-6.6/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..85ed961753 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From f2f11d441c4e38415c9b3278b4ec21faf60758d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:16 +0100 +Subject: arm64: dts: qcom: sm8450: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 14044fa192c50265bc1f636108371044bbdcf7b7 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: fc8b0b9b630d ("arm64: dts: qcom: sm8450 add ITS device tree node") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-3-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index c1ed39cac8c5b..b745d8b476408 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -3947,7 +3947,7 @@ intc: interrupt-controller@17100000 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x17140000 0x0 0x20000>; ++ reg = <0x0 0x17140000 0x0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-6.6/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..828caeaadc --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,67 @@ +From f3900376c5a1caf81c54e9fc08de89f90f040b12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:14 +0200 +Subject: arm64: dts: qcom: sm8550: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit 66b0f024fba0728ddce6916dce173bb1bdd4eab0 ] + +The restriction on UHS-I speed modes was added to all SM8550 platforms +by copying it from SM8450 dtsi file, and due to the overclocking of SD +cards it was an actually reproducible problem. Since the latter issue +has been fixed, UHS-I speed modes are working fine on SM8550 boards, +below is the test performed on SM8550-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 23.5468 s, 45.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 11.9819 s, 89.6 MB/s + +Unset the UHS-I speed mode restrictions from the SM8550 platform dtsi +file, there is no indication that the SDHC controller is broken. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Reviewed-by: Neil Armstrong +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-6-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index 3d14575e5aace..5a79adbe8da12 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -2535,9 +2535,6 @@ sdhc_2: mmc@8804000 { + bus-width = <4>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch b/queue-6.6/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..74b5bdd5a2 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From 6c10ad1661492c85276f1520b3f63cdccb5fc2f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:17 +0100 +Subject: arm64: dts: qcom: sm8550: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 357c559e386705609b6b9dc0544c420e3f91f3a0 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-4-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index 2f0f1c2ab7391..beab9fd10da87 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -3830,7 +3830,7 @@ intc: interrupt-controller@17100000 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0 0x17140000 0 0x20000>; ++ reg = <0 0x17140000 0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-6.6/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch b/queue-6.6/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch new file mode 100644 index 0000000000..82d3d2b367 --- /dev/null +++ b/queue-6.6/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch @@ -0,0 +1,46 @@ +From d0aacedffef145cb565045d336d9f7a363236999 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:10 +0200 +Subject: arm64: dts: qcom: sm8550: Fix xo clock supply of platform SD host + controller + +From: Vladimir Zapolskiy + +[ Upstream commit 30ac651c69bddbc83cab6d52fc5d2e03bed83282 ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-2-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index beab9fd10da87..3d14575e5aace 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -2521,7 +2521,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", "core", "xo"; + iommus = <&apps_smmu 0x540 0>; + qcom,dll-config = <0x0007642c>; +-- +2.53.0 + diff --git a/queue-6.6/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch b/queue-6.6/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch new file mode 100644 index 0000000000..6a11562cb0 --- /dev/null +++ b/queue-6.6/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch @@ -0,0 +1,38 @@ +From 84868f289e92043e791e38f1372542f9b1d355fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 19:42:31 +0800 +Subject: arm64: kexec: Remove duplicate allocation for trans_pgd + +From: Wang Wensheng + +[ Upstream commit ee020bf6f14094c9ae434bb37e6957a1fdad513c ] + +trans_pgd would be allocated in trans_pgd_create_copy(), so remove the +duplicate allocation before calling trans_pgd_create_copy(). + +Fixes: 3744b5280e67 ("arm64: kexec: install a copy of the linear-map") +Signed-off-by: Wang Wensheng +Reviewed-by: Pasha Tatashin +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/machine_kexec.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c +index 078910db77a41..9307a1421d67e 100644 +--- a/arch/arm64/kernel/machine_kexec.c ++++ b/arch/arm64/kernel/machine_kexec.c +@@ -143,9 +143,6 @@ int machine_kexec_post_load(struct kimage *kimage) + } + + /* Create a copy of the linear map */ +- trans_pgd = kexec_page_alloc(kimage); +- if (!trans_pgd) +- return -ENOMEM; + rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END); + if (rc) + return rc; +-- +2.53.0 + diff --git a/queue-6.6/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch b/queue-6.6/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch new file mode 100644 index 0000000000..831ca30949 --- /dev/null +++ b/queue-6.6/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch @@ -0,0 +1,47 @@ +From 902b301fbd9b5d752b66f969b7e2bac999a27c37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 17:54:59 +0800 +Subject: arm64/scs: Fix potential sign extension issue of advance_loc4 + +From: Wentao Guan + +[ Upstream commit 4023b7424ecd5d38cc75b650d6c1bf630ef8cb40 ] + +The expression (*opcode++ << 24) and exp * code_alignment_factor +may overflow signed int and becomes negative. + +Fix this by casting each byte to u64 before shifting. Also fix +the misaligned break statement while we are here. + +Example of the result can be seen here: +Link: https://godbolt.org/z/zhY8d3595 + +It maybe not a real problem, but could be a issue in future. + +Fixes: d499e9627d70 ("arm64/scs: Fix handling of advance_loc4") +Signed-off-by: Wentao Guan +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/patch-scs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/patch-scs.c b/arch/arm64/kernel/patch-scs.c +index 6d656179ea03b..d6e8ad142f75c 100644 +--- a/arch/arm64/kernel/patch-scs.c ++++ b/arch/arm64/kernel/patch-scs.c +@@ -175,9 +175,9 @@ static int noinstr scs_handle_fde_frame(const struct eh_frame *frame, + loc += *opcode++ * code_alignment_factor; + loc += (*opcode++ << 8) * code_alignment_factor; + loc += (*opcode++ << 16) * code_alignment_factor; +- loc += (*opcode++ << 24) * code_alignment_factor; ++ loc += ((u64)*opcode++ << 24) * code_alignment_factor; + size -= 4; +- break; ++ break; + + case DW_CFA_def_cfa: + case DW_CFA_offset_extended: +-- +2.53.0 + diff --git a/queue-6.6/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch b/queue-6.6/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch new file mode 100644 index 0000000000..8d145eacdf --- /dev/null +++ b/queue-6.6/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch @@ -0,0 +1,79 @@ +From b0c880e11deb94c5ca6b275009fb79b6b21923cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 07:16:35 +0100 +Subject: arm64/xor: fix conflicting attributes for xor_block_template + +From: Christoph Hellwig + +[ Upstream commit 675a0dd596e712404557286d0a883b54ee28e4f4 ] + +Commit 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +changes the definition to __ro_after_init instead of const, but failed to +update the external declaration in xor.h. This was not found because +xor-neon.c doesn't include , and can't easily do that due to +current architecture of the XOR code. + +Link: https://lkml.kernel.org/r/20260327061704.3707577-4-hch@lst.de +Fixes: 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +Signed-off-by: Christoph Hellwig +Reviewed-by: Eric Biggers +Tested-by: Eric Biggers +Cc: Albert Ou +Cc: Alexander Gordeev +Cc: Alexandre Ghiti +Cc: Andreas Larsson +Cc: Anton Ivanov +Cc: Ard Biesheuvel +Cc: Arnd Bergmann +Cc: "Borislav Petkov (AMD)" +Cc: Catalin Marinas +Cc: Chris Mason +Cc: Christian Borntraeger +Cc: Dan Williams +Cc: David S. Miller +Cc: David Sterba +Cc: Heiko Carstens +Cc: Herbert Xu +Cc: "H. Peter Anvin" +Cc: Huacai Chen +Cc: Ingo Molnar +Cc: Jason A. Donenfeld +Cc: Johannes Berg +Cc: Li Nan +Cc: Madhavan Srinivasan +Cc: Magnus Lindholm +Cc: Matt Turner +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: Palmer Dabbelt +Cc: Richard Henderson +Cc: Richard Weinberger +Cc: Russell King +Cc: Song Liu +Cc: Sven Schnelle +Cc: Ted Ts'o +Cc: Vasily Gorbik +Cc: WANG Xuerui +Cc: Will Deacon +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/xor.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/xor.h b/arch/arm64/include/asm/xor.h +index befcd8a7abc98..7c03207157196 100644 +--- a/arch/arm64/include/asm/xor.h ++++ b/arch/arm64/include/asm/xor.h +@@ -13,7 +13,7 @@ + + #ifdef CONFIG_KERNEL_MODE_NEON + +-extern struct xor_block_template const xor_block_inner_neon; ++extern struct xor_block_template xor_block_inner_neon __ro_after_init; + + static void + xor_neon_2(unsigned long bytes, unsigned long * __restrict p1, +-- +2.53.0 + diff --git a/queue-6.6/asoc-codecs-ab8500-fix-casting-of-private-data.patch b/queue-6.6/asoc-codecs-ab8500-fix-casting-of-private-data.patch new file mode 100644 index 0000000000..31611577d6 --- /dev/null +++ b/queue-6.6/asoc-codecs-ab8500-fix-casting-of-private-data.patch @@ -0,0 +1,56 @@ +From d2d43794ef4db5e4b812711389e5df4de6bc4e99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 21:22:49 +0200 +Subject: ASoC: codecs: ab8500: Fix casting of private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian A. Ehrhardt + +[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ] + +ab8500_filter_controls[i].private_value is initialized using + + .private_value = (unsigned long)&(struct filter_control) + {.count = xcount, .min = xmin, .max = xmax} + +thus it's a pointer to a struct filter_control casted to unsigned long. + +So to get back that pointer .private_data must be cast back, not its +address. + +Fixes: 679d7abdc754 ("ASoC: codecs: Add AB8500 codec-driver") +Signed-off-by: Christian A. Ehrhardt +Signed-off-by: Uwe Kleine-König (The Capable Hub) +Link: https://patch.msgid.link/20260428192255.2294705-2-u.kleine-koenig@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/ab8500-codec.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c +index 68342917419e4..42e448978c4a0 100644 +--- a/sound/soc/codecs/ab8500-codec.c ++++ b/sound/soc/codecs/ab8500-codec.c +@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) + return status; + } + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; + drvdata->anc_fir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; + drvdata->anc_iir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; + drvdata->sid_fir_values = (long *)fc->value; + + snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch b/queue-6.6/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch new file mode 100644 index 0000000000..b892f1db37 --- /dev/null +++ b/queue-6.6/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch @@ -0,0 +1,189 @@ +From d53706dee9d86d79a7e52744d518e5bb2d2208ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:26 +0800 +Subject: ASoC: fsl_easrc: Change the type for iec958 channel status controls + +From: Shengjiu Wang + +[ Upstream commit 47f28a5bd154a95d5aa563dde02a801bd32ddb81 ] + +Use the type SNDRV_CTL_ELEM_TYPE_IEC958 for iec958 channel status +controls, the original type will cause mixer-test to iterate all 32bit +values, which costs a lot of time. And using IEC958 type can reduce the +control numbers. + +Also enable pm runtime before updating registers to make the regmap cache +data align with the value in hardware. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-12-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 118 +++++++++++++++++++++++++++----------- + 1 file changed, 84 insertions(+), 34 deletions(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index c33cad8f07a3f..16aa0063aa65c 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -78,17 +78,47 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + return 0; + } + ++static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ + static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; +- unsigned int regval; ++ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ int ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]); ++ if (ret) ++ return ret; + +- regval = snd_soc_component_read(component, mc->regbase); ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]); ++ if (ret) ++ return ret; + +- ucontrol->value.integer.value[0] = regval; ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]); ++ if (ret) ++ return ret; + + return 0; + } +@@ -100,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); +- unsigned int regval = ucontrol->value.integer.value[0]; +- bool changed; ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ bool changed, changed_all = false; + int ret; + +- ret = regmap_update_bits_check(easrc->regmap, mc->regbase, +- GENMASK(31, 0), regval, &changed); +- if (ret != 0) ++ ret = pm_runtime_resume_and_get(component->dev); ++ if (ret) + return ret; + +- return changed; ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase), ++ GENMASK(31, 0), regval[0], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase), ++ GENMASK(31, 0), regval[1], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase), ++ GENMASK(31, 0), regval[2], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase), ++ GENMASK(31, 0), regval[3], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase), ++ GENMASK(31, 0), regval[4], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase), ++ GENMASK(31, 0), regval[5], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++err: ++ pm_runtime_put_autosuspend(component->dev); ++ ++ if (ret != 0) ++ return ret; ++ else ++ return changed_all; + } + + #define SOC_SINGLE_REG_RW(xname, xreg) \ + { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ +- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ ++ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \ + .put = fsl_easrc_set_reg, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ +@@ -146,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { + SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), + SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), + +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), ++ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0), ++ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1), ++ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2), ++ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3), + }; + + /* +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch b/queue-6.6/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch new file mode 100644 index 0000000000..df7985e313 --- /dev/null +++ b/queue-6.6/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch @@ -0,0 +1,39 @@ +From 6a560bde8f3c08e4d92285f3348a4ddf75fbcce1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:24 +0800 +Subject: ASoC: fsl_easrc: Check the variable range in + fsl_easrc_iec958_put_bits() + +From: Shengjiu Wang + +[ Upstream commit 00541b86fb578d4949cfdd6aff1f82d43fcf07af ] + +Add check of input value's range in fsl_easrc_iec958_put_bits(), +otherwise the wrong value may be written from user space. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-10-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index c78abf7698e0f..48d7a3e109129 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, + unsigned int regval = ucontrol->value.integer.value[0]; + int ret; + ++ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT) ++ return -EINVAL; ++ + ret = (easrc_priv->bps_iec958[mc->regbase] != regval); + + easrc_priv->bps_iec958[mc->regbase] = regval; +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch b/queue-6.6/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch new file mode 100644 index 0000000000..4bd861ef4e --- /dev/null +++ b/queue-6.6/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch @@ -0,0 +1,37 @@ +From 63598a45da8ed78fa637424c4cace174f696cfcb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:25 +0800 +Subject: ASoC: fsl_easrc: Fix value type in fsl_easrc_iec958_get_bits() + +From: Shengjiu Wang + +[ Upstream commit aa21fe4a81458cf469c2615b08cbde5997dde25a ] + +The value type of controls "Context 0 IEC958 Bits Per Sample" should be +integer, not enumerated, the issue is found by the mixer-test. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-11-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 48d7a3e109129..c33cad8f07a3f 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -73,7 +73,7 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + +- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; ++ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_micfil-add-access-property-for-vad-detected.patch b/queue-6.6/asoc-fsl_micfil-add-access-property-for-vad-detected.patch new file mode 100644 index 0000000000..f27d2dcc4b --- /dev/null +++ b/queue-6.6/asoc-fsl_micfil-add-access-property-for-vad-detected.patch @@ -0,0 +1,44 @@ +From 40ee46c010e0998ebac1cf1cbe203c14d697f322 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:16 +0800 +Subject: ASoC: fsl_micfil: Add access property for "VAD Detected" + +From: Shengjiu Wang + +[ Upstream commit c7661bfc7422443df394c01e069ae4e5c3a7f04c ] + +Add access property SNDRV_CTL_ELEM_ACCESS_READ for control "VAD +Detected", which doesn't support put operation, otherwise there will be +issue with mixer-test. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-2-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 80ff1d1359f64..56ee7cbf371c1 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -395,7 +395,13 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { + SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0), + SOC_SINGLE("HWVAD ZCD And Behavior Switch", + REG_MICFIL_VAD0_ZCD, 4, 1, 0), +- SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .name = "VAD Detected", ++ .info = snd_soc_info_bool_ext, ++ .get = hwvad_detected, ++ }, + }; + + static int fsl_micfil_use_verid(struct device *dev) +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch b/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch new file mode 100644 index 0000000000..bd0dd4b970 --- /dev/null +++ b/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch @@ -0,0 +1,49 @@ +From 35b0bb74be9a4100b9aa3aae65011f0511e6213c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:17 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in hwvad_put_enable() + +From: Shengjiu Wang + +[ Upstream commit 59b9061824f2179fe133e2636203548eaba3e528 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation hwvad_put_enable() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the vad_enabled +variable. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-3-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 56ee7cbf371c1..8eb5f553aa209 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -277,10 +277,15 @@ static int hwvad_put_enable(struct snd_kcontrol *kcontrol, + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); ++ bool change = false; + ++ if (val < 0 || val > 1) ++ return -EINVAL; ++ ++ change = (micfil->vad_enabled != val); + micfil->vad_enabled = val; + +- return 0; ++ return change; + } + + static int hwvad_get_enable(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch b/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch new file mode 100644 index 0000000000..45594ce4a1 --- /dev/null +++ b/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch @@ -0,0 +1,52 @@ +From 458e3fe02df40764a11307b5937927a0d228857e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:18 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in hwvad_put_init_mode() + +From: Shengjiu Wang + +[ Upstream commit 7e226209906906421f0d952d7304e48fdb0adabc ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation hwvad_put_init_mode() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the vad_init_mode +variable. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-4-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 8eb5f553aa209..88553f0c0de86 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -307,13 +307,18 @@ static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol, + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); ++ bool change = false; ++ ++ if (val < MICFIL_HWVAD_ENVELOPE_MODE || val > MICFIL_HWVAD_ENERGY_MODE) ++ return -EINVAL; + + /* 0 - Envelope-based Mode + * 1 - Energy-based Mode + */ ++ change = (micfil->vad_init_mode != val); + micfil->vad_init_mode = val; + +- return 0; ++ return change; + } + + static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch b/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch new file mode 100644 index 0000000000..25671abe0f --- /dev/null +++ b/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch @@ -0,0 +1,62 @@ +From ae0e0a1d216152bca257085f5aab205189fcb32e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:20 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in + micfil_put_dc_remover_state() + +From: Shengjiu Wang + +[ Upstream commit 7d2bd35100de370dc326b250e8f6b66bee06a2f3 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_put_dc_remover_state() only returns 0 or a +negative error code, causing ALSA to not generate any change events. + +return the value of snd_soc_component_update_bits() directly, as it has +the capability of return check status of changed or not. + +Also enable pm runtime before calling the function +snd_soc_component_update_bits() to make the regmap cache data align with +the value in hardware. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-6-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 88553f0c0de86..32ee7093c8110 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -243,6 +243,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + if (val < 0 || val > 3) + return -EINVAL; + ++ ret = pm_runtime_resume_and_get(comp->dev); ++ if (ret) ++ return ret; ++ + micfil->dc_remover = val; + + /* Calculate total value for all channels */ +@@ -252,10 +256,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + /* Update DC Remover mode for all channels */ + ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL, + MICFIL_DC_CTRL_CONFIG, reg_val); +- if (ret < 0) +- return ret; + +- return 0; ++ pm_runtime_put_autosuspend(comp->dev); ++ ++ return ret; + } + + static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch b/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch new file mode 100644 index 0000000000..3565bb2072 --- /dev/null +++ b/queue-6.6/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch @@ -0,0 +1,71 @@ +From cba10e32d204d3a1bb4f5abbdbf417213618f537 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:21 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in micfil_quality_set() + +From: Shengjiu Wang + +[ Upstream commit e5785093b1b45af7ee57d18619b2854a8aed073a ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_quality_set() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the quality variable. + +Also enable pm runtime before calling the function micfil_set_quality() +to make the regmap cache data align with the value in hardware. + +Fixes: bea1d61d5892 ("ASoC: fsl_micfil: rework quality setting") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-7-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 32ee7093c8110..189f65989fcfe 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -181,10 +181,34 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol, + { + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); ++ int val = ucontrol->value.integer.value[0]; ++ bool change = false; ++ int old_val; ++ int ret; ++ ++ if (val < QUALITY_HIGH || val > QUALITY_VLOW2) ++ return -EINVAL; ++ ++ if (micfil->quality != val) { ++ ret = pm_runtime_resume_and_get(cmpnt->dev); ++ if (ret) ++ return ret; ++ ++ old_val = micfil->quality; ++ micfil->quality = val; ++ ret = micfil_set_quality(micfil); + +- micfil->quality = ucontrol->value.integer.value[0]; ++ pm_runtime_put_autosuspend(cmpnt->dev); + +- return micfil_set_quality(micfil); ++ if (ret) { ++ micfil->quality = old_val; ++ return ret; ++ } ++ ++ change = true; ++ } ++ ++ return change; + } + + static const char * const micfil_hwvad_enable[] = { +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch b/queue-6.6/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch new file mode 100644 index 0000000000..2c6a88ced0 --- /dev/null +++ b/queue-6.6/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch @@ -0,0 +1,52 @@ +From fc490cdecf5953c0ce2ec1e7dd562e54d93f1528 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:22 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_arc_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 1b61c8103c9317a9c37fe544c2d83cee1c281149 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_arc_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the arc_mode +variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-8-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index 90a0a24c05d84..87ea3abc4416f 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -98,10 +98,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); ++ int ret; + +- xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]); ++ if (val < 0 || val > 1) ++ return -EINVAL; + +- return 0; ++ ret = (xcvr->arc_mode != val); ++ ++ xcvr->arc_mode = val; ++ ++ return ret; + } + + static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.6/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch b/queue-6.6/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch new file mode 100644 index 0000000000..b1cd38d666 --- /dev/null +++ b/queue-6.6/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch @@ -0,0 +1,59 @@ +From 62f806b4e7f0ae121c18a0f12fc8b383b3591493 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:23 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 64a496ba976324615b845d60739dfcdae3d57434 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the mode variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-9-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index 87ea3abc4416f..d6aa9c30978f4 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -208,10 +208,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); + struct snd_soc_card *card = dai->component->card; + struct snd_soc_pcm_runtime *rtd; ++ int ret; ++ ++ if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC) ++ return -EINVAL; + +- xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); ++ ret = (xcvr->mode != val); ++ ++ xcvr->mode = val; + + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_ARC)); +@@ -221,7 +228,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + rtd = snd_soc_get_pcm_runtime(card, card->dai_link); + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = + (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0); +- return 0; ++ return ret; + } + + static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-6.6/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch b/queue-6.6/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch new file mode 100644 index 0000000000..59229e2d4c --- /dev/null +++ b/queue-6.6/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch @@ -0,0 +1,51 @@ +From 90ed0fb663682471cc1917bd02edbc03a45b70c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 08:11:08 +0000 +Subject: ASoC: qcom: qdsp6: topology: check widget type before accessing data + +From: Srinivas Kandagatla + +[ Upstream commit d5bfdd28e0cdd45043ae6e0ac168a451d59283dc ] + +Check widget type before accessing the private data, as this could a +virtual widget which is no associated with a dsp graph, container and +module. Accessing witout check could lead to incorrect memory access. + +Fixes: 36ad9bf1d93d ("ASoC: qdsp6: audioreach: add topology support") +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260402081118.348071-4-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/topology.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c +index d4c3bc85fb356..51d1926ea3c2b 100644 +--- a/sound/soc/qcom/qdsp6/topology.c ++++ b/sound/soc/qcom/qdsp6/topology.c +@@ -903,9 +903,6 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + struct audioreach_container *cont; + struct audioreach_module *mod; + +- mod = dobj->private; +- cont = mod->container; +- + if (w->id == snd_soc_dapm_mixer) { + /* virtual widget */ + struct snd_ar_control *scontrol = dobj->private; +@@ -914,6 +911,11 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + kfree(scontrol); + return 0; + } ++ mod = dobj->private; ++ if (!mod) ++ return 0; ++ ++ cont = mod->container; + + mutex_lock(&apm->lock); + idr_remove(&apm->modules_idr, mod->instance_id); +-- +2.53.0 + diff --git a/queue-6.6/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch b/queue-6.6/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch new file mode 100644 index 0000000000..16d1771e07 --- /dev/null +++ b/queue-6.6/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch @@ -0,0 +1,45 @@ +From cda9568b0dfc3d8986504f1b5c4fb8ad42ec2a31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 13:33:11 +0300 +Subject: ASoC: rsnd: Fix potential out-of-bounds access of component_dais[] + +From: Denis Rastyogin + +[ Upstream commit f9e437cddf6cf9e603bdaefe148c1f4792aaf39c ] + +component_dais[RSND_MAX_COMPONENT] is initially zero-initialized +and later populated in rsnd_dai_of_node(). However, the existing boundary check: + if (i >= RSND_MAX_COMPONENT) + +does not guarantee that the last valid element remains zero. As a result, +the loop can rely on component_dais[RSND_MAX_COMPONENT] being zero, +which may lead to an out-of-bounds access. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 547b02f74e4a ("ASoC: rsnd: enable multi Component support for Audio Graph Card/Card2") +Signed-off-by: Denis Rastyogin +Acked-by: Kuninori Morimoto +Link: https://patch.msgid.link/20260327103311.459239-1-gerben@altlinux.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sh/rcar/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c +index 3cd14fbca28ea..68f91fc543493 100644 +--- a/sound/soc/sh/rcar/core.c ++++ b/sound/soc/sh/rcar/core.c +@@ -1995,7 +1995,7 @@ static int rsnd_probe(struct platform_device *pdev) + * asoc register + */ + ci = 0; +- for (i = 0; priv->component_dais[i] > 0; i++) { ++ for (i = 0; i < RSND_MAX_COMPONENT && priv->component_dais[i] > 0; i++) { + int nr = priv->component_dais[i]; + + ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, +-- +2.53.0 + diff --git a/queue-6.6/asoc-sof-compress-return-the-configured-codec-from-g.patch b/queue-6.6/asoc-sof-compress-return-the-configured-codec-from-g.patch new file mode 100644 index 0000000000..c7e694a2be --- /dev/null +++ b/queue-6.6/asoc-sof-compress-return-the-configured-codec-from-g.patch @@ -0,0 +1,88 @@ +From a63e3ce9b59e9c6138750a6e48bcaf3d9c4efa4d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 17:05:11 -0300 +Subject: ASoC: SOF: compress: return the configured codec from get_params +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 2c4fdd055f92a2fc8602dcd88bcea08c374b7e8b ] + +The SOF compressed offload path accepts codec parameters in +sof_compr_set_params() and forwards them to firmware as +extended data in the SOF IPC stream params message. + +However, sof_compr_get_params() still returns success without +filling the snd_codec structure. Since the compress core allocates +that structure zeroed and copies it back to userspace on success, +SNDRV_COMPRESS_GET_PARAMS returns an all-zero codec description +even after the stream has been configured successfully. + +The stale TODO in this callback conflates get_params() with capability +discovery. Supported codec enumeration belongs in get_caps() and +get_codec_caps(). get_params() should report the current codec settings. + +Cache the codec accepted by sof_compr_set_params() in the per-stream SOF +compress state and return it from sof_compr_get_params(). + +Fixes: 6324cf901e14 ("ASoC: SOF: compr: Add compress ops implementation") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-sof-compr-get-params-v1-1-0758815f13c7@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/compress.c | 8 +++++--- + sound/soc/sof/sof-priv.h | 2 ++ + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c +index c469bb706e4a4..b64a5d99fe608 100644 +--- a/sound/soc/sof/compress.c ++++ b/sound/soc/sof/compress.c +@@ -247,6 +247,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, + sstream->sampling_rate = params->codec.sample_rate; + sstream->channels = params->codec.ch_out; + sstream->sample_container_bytes = pcm->params.sample_container_bytes; ++ sstream->codec_params = params->codec; + + spcm->prepared[cstream->direction] = true; + +@@ -259,9 +260,10 @@ static int sof_compr_set_params(struct snd_soc_component *component, + static int sof_compr_get_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_codec *params) + { +- /* TODO: we don't query the supported codecs for now, if the +- * application asks for an unsupported codec the set_params() will fail. +- */ ++ struct sof_compr_stream *sstream = cstream->runtime->private_data; ++ ++ *params = sstream->codec_params; ++ + return 0; + } + +diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h +index d4f6702e93dcb..6bf461506ce37 100644 +--- a/sound/soc/sof/sof-priv.h ++++ b/sound/soc/sof/sof-priv.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -119,6 +120,7 @@ struct sof_compr_stream { + u32 sampling_rate; + u16 channels; + u16 sample_container_bytes; ++ struct snd_codec codec_params; + size_t posn_offset; + }; + +-- +2.53.0 + diff --git a/queue-6.6/asoc-sof-intel-hda-place-check-before-dereference.patch b/queue-6.6/asoc-sof-intel-hda-place-check-before-dereference.patch new file mode 100644 index 0000000000..e417955a05 --- /dev/null +++ b/queue-6.6/asoc-sof-intel-hda-place-check-before-dereference.patch @@ -0,0 +1,60 @@ +From 4643df18fddad1ebbc397c8c04bc2425117e2b74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 12:38:30 -0500 +Subject: ASoC: SOF: Intel: hda: Place check before dereference + +From: Ethan Tidmore + +[ Upstream commit 6cbc8360f51a3df2ea16a786b262b9fe44d4c68c ] + +The struct hext_stream is dereferenced before it is checked for NULL. +Although it can never be NULL due to a check prior to +hda_dsp_iccmax_stream_hw_params() being called, this change clears any +confusion regarding hext_stream possibly being NULL. + +Check hext_stream for NULL and then assign its members. + +Detected by Smatch: +sound/soc/sof/intel/hda-stream.c:488 hda_dsp_iccmax_stream_hw_params() warn: +variable dereferenced before check 'hext_stream' (see line 486) + +Fixes: aca961f196e5d ("ASoC: SOF: Intel: hda: Add helper function to program ICCMAX stream") +Signed-off-by: Ethan Tidmore +Link: https://patch.msgid.link/20260324173830.17563-1-ethantidmore06@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/intel/hda-stream.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c +index 3bb743cb167a5..924cef8d96c60 100644 +--- a/sound/soc/sof/intel/hda-stream.c ++++ b/sound/soc/sof/intel/hda-stream.c +@@ -415,16 +415,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params) + { +- struct hdac_stream *hstream = &hext_stream->hstream; +- int sd_offset = SOF_STREAM_SD_OFFSET(hstream); ++ struct hdac_stream *hstream; ++ int sd_offset; + int ret; +- u32 mask = 0x1 << hstream->index; ++ u32 mask; + + if (!hext_stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + ++ hstream = &hext_stream->hstream; ++ sd_offset = SOF_STREAM_SD_OFFSET(hstream); ++ mask = 0x1 << hstream->index; ++ + if (!dmab) { + dev_err(sdev->dev, "error: no dma buffer allocated!\n"); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-6.6/asoc-sti-return-errors-from-regmap_field_alloc.patch b/queue-6.6/asoc-sti-return-errors-from-regmap_field_alloc.patch new file mode 100644 index 0000000000..0ff6107063 --- /dev/null +++ b/queue-6.6/asoc-sti-return-errors-from-regmap_field_alloc.patch @@ -0,0 +1,50 @@ +From 1b865f38e0130de246c68e933760245cae1c703e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:33 +0100 +Subject: ASoC: sti: Return errors from regmap_field_alloc() + +From: Sander Vanheule + +[ Upstream commit 272aabef50bc3fe58edd26de000f4cdd41bdbe60 ] + +When regmap_field_alloc() fails, it can return an error. Specifically, +it will return PTR_ERR(-ENOMEM) when the allocation returns a NULL +pointer. The code then uses these allocations with a simple NULL check: + + if (player->clk_sel) { + // May dereference invalid pointer (-ENOMEM) + err = regmap_field_write(player->clk_sel, ...); + } + +Ensure initialization fails by forwarding the errors from +regmap_field_alloc(), thus avoiding the use of the invalid pointers. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-2-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index 6d1ce030963c6..f1b7e76f97b58 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1029,7 +1029,12 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + } + + player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ if (IS_ERR(player->clk_sel)) ++ return PTR_ERR(player->clk_sel); ++ + player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ if (IS_ERR(player->valid_sel)) ++ return PTR_ERR(player->valid_sel); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/asoc-sti-use-managed-regmap_field-allocations.patch b/queue-6.6/asoc-sti-use-managed-regmap_field-allocations.patch new file mode 100644 index 0000000000..f82027646c --- /dev/null +++ b/queue-6.6/asoc-sti-use-managed-regmap_field-allocations.patch @@ -0,0 +1,45 @@ +From a2f5308024a2c5a515cf6192568c5bc084ebd7b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:34 +0100 +Subject: ASoC: sti: use managed regmap_field allocations + +From: Sander Vanheule + +[ Upstream commit 1696fad8b259a2d46e51cd6e17e4bcdbe02279fa ] + +The regmap_field objects allocated at player init are never freed and +may leak resources if the driver is removed. + +Switch to devm_regmap_field_alloc() to automatically limit the lifetime +of the allocations the lifetime of the device. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-3-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index f1b7e76f97b58..45d35b887e4eb 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1028,11 +1028,11 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + return PTR_ERR(regmap); + } + +- player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]); + if (IS_ERR(player->clk_sel)) + return PTR_ERR(player->clk_sel); + +- player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]); + if (IS_ERR(player->valid_sel)) + return PTR_ERR(player->valid_sel); + +-- +2.53.0 + diff --git a/queue-6.6/backlight-sky81452-backlight-check-return-value-of-d.patch b/queue-6.6/backlight-sky81452-backlight-check-return-value-of-d.patch new file mode 100644 index 0000000000..ed75c5edc6 --- /dev/null +++ b/queue-6.6/backlight-sky81452-backlight-check-return-value-of-d.patch @@ -0,0 +1,46 @@ +From c8db8dd95f2b60b6a78615f42b7bff3df4ac533c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:16:25 +0800 +Subject: backlight: sky81452-backlight: Check return value of + devm_gpiod_get_optional() in sky81452_bl_parse_dt() + +From: Chen Ni + +[ Upstream commit 797cc011ae02bda26f93d25a4442d7a1a77d84df ] + +The devm_gpiod_get_optional() function may return an ERR_PTR in case of +genuine GPIO acquisition errors, not just NULL which indicates the +legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the call in sky81452_bl_parse_dt(). On +error, return the error code to ensure proper failure handling rather +than proceeding with invalid pointers. + +Fixes: e1915eec54a6 ("backlight: sky81452: Convert to GPIO descriptors") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260203021625.578678-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/sky81452-backlight.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c +index eb18c6eb0ff0d..6ce1c3c5f5676 100644 +--- a/drivers/video/backlight/sky81452-backlight.c ++++ b/drivers/video/backlight/sky81452-backlight.c +@@ -204,6 +204,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( + pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode"); + pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift"); + pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); ++ if (IS_ERR(pdata->gpiod_enable)) ++ return dev_err_cast_probe(dev, pdata->gpiod_enable, ++ "failed to get gpio\n"); + + ret = of_property_count_u32_elems(np, "led-sources"); + if (ret < 0) { +-- +2.53.0 + diff --git a/queue-6.6/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch b/queue-6.6/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch new file mode 100644 index 0000000000..be28d0fc7c --- /dev/null +++ b/queue-6.6/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch @@ -0,0 +1,60 @@ +From 2b930c3b9b3baa8415da921c9815acac91400495 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 09:53:51 -0700 +Subject: bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst() + +From: Weiming Shi + +[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ] + +bareudp_fill_metadata_dst() passes bareudp->sock to +udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. +The socket is only created in bareudp_open() and NULLed in +bareudp_stop(), so calling this function while the device is down +triggers a NULL dereference via sock->sk. + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) + Call Trace: + + bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) + do_execute_actions (net/openvswitch/actions.c:901) + ovs_execute_actions (net/openvswitch/actions.c:1589) + ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) + genl_rcv_msg (net/netlink/genetlink.c:1209) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths +in the same driver. + +Fixes: 571912c69f0e ("net: UDP tunnel encapsulation module for tunnelling different protocols like MPLS, IP, NSH etc.") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426165350.1663137-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 150049d9a81a7..b181c03368153 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -520,6 +520,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + ++ if (!sock) ++ return -ESHUTDOWN; ++ + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, + &saddr, info, IPPROTO_UDP, + use_cache); +-- +2.53.0 + diff --git a/queue-6.6/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch b/queue-6.6/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch new file mode 100644 index 0000000000..2980f28c0a --- /dev/null +++ b/queue-6.6/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch @@ -0,0 +1,47 @@ +From 3b0b6f07f31756e1d633c555fda16a51a365e8f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:50:54 +0800 +Subject: blk-cgroup: fix disk reference leak in blkcg_maybe_throttle_current() + +From: Jackie Liu + +[ Upstream commit 23308af722fefed00af5f238024c11710938fba3 ] + +Add the missing put_disk() on the error path in +blkcg_maybe_throttle_current(). When blkcg lookup, blkg lookup, or +blkg_tryget() fails, the function jumps to the out label which only +calls rcu_read_unlock() but does not release the disk reference acquired +by blkcg_schedule_throttle() via get_device(). Since current->throttle_disk +is already set to NULL before the lookup, blkcg_exit() cannot release +this reference either, causing the disk to never be freed. + +Restore the reference release that was present as blk_put_queue() in the +original code but was inadvertently dropped during the conversion from +request_queue to gendisk. + +Fixes: f05837ed73d0 ("blk-cgroup: store a gendisk to throttle in struct task_struct") +Signed-off-by: Jackie Liu +Acked-by: Tejun Heo +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260331085054.46857-1-liu.yun@linux.dev +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 40c9d5805b88b..4ac2f53e7f51f 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -1993,6 +1993,7 @@ void blkcg_maybe_throttle_current(void) + return; + out: + rcu_read_unlock(); ++ put_disk(disk); + } + + /** +-- +2.53.0 + diff --git a/queue-6.6/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch b/queue-6.6/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch new file mode 100644 index 0000000000..b12033eef3 --- /dev/null +++ b/queue-6.6/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch @@ -0,0 +1,75 @@ +From 6df73792522b56f03a3bd5ed0ee93330044e1b29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 11:28:37 +0800 +Subject: blk-cgroup: wait for blkcg cleanup before initializing new disk + +From: Ming Lei + +[ Upstream commit 3dbaacf6ab68f81e3375fe769a2ecdbd3ce386fd ] + +When a queue is shared across disk rebind (e.g., SCSI unbind/bind), the +previous disk's blkcg state is cleaned up asynchronously via +disk_release() -> blkcg_exit_disk(). If the new disk's blkcg_init_disk() +runs before that cleanup finishes, we may overwrite q->root_blkg while +the old one is still alive, and radix_tree_insert() in blkg_create() +fails with -EEXIST because the old blkg entries still occupy the same +queue id slot in blkcg->blkg_tree. This causes the sd probe to fail +with -ENOMEM. + +Fix it by waiting in blkcg_init_disk() for root_blkg to become NULL, +which indicates the previous disk's blkcg cleanup has completed. + +Fixes: 1059699f87eb ("block: move blkcg initialization/destroy into disk allocation/release handler") +Cc: Yi Zhang +Signed-off-by: Ming Lei +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260311032837.2368714-1-ming.lei@redhat.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 75e9d5a9d707c..40c9d5805b88b 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -618,6 +619,8 @@ static void blkg_destroy_all(struct gendisk *disk) + + q->root_blkg = NULL; + spin_unlock_irq(&q->queue_lock); ++ ++ wake_up_var(&q->root_blkg); + } + + static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) +@@ -1459,6 +1462,18 @@ int blkcg_init_disk(struct gendisk *disk) + bool preloaded; + int ret; + ++ /* ++ * If the queue is shared across disk rebind (e.g., SCSI), the ++ * previous disk's blkcg state is cleaned up asynchronously via ++ * disk_release() -> blkcg_exit_disk(). Wait for that cleanup to ++ * finish (indicated by root_blkg becoming NULL) before setting up ++ * new blkcg state. Otherwise, we may overwrite q->root_blkg while ++ * the old one is still alive, and radix_tree_insert() in ++ * blkg_create() will fail with -EEXIST because the old entries ++ * still occupy the same queue id slot in blkcg->blkg_tree. ++ */ ++ wait_var_event(&q->root_blkg, !READ_ONCE(q->root_blkg)); ++ + new_blkg = blkg_alloc(&blkcg_root, disk, GFP_KERNEL); + if (!new_blkg) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch b/queue-6.6/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch new file mode 100644 index 0000000000..9f1585c920 --- /dev/null +++ b/queue-6.6/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch @@ -0,0 +1,52 @@ +From f267651103403b89062ae65be0c55d2ba875960d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:42:59 +0300 +Subject: Bluetooth: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER + +From: Pauli Virtanen + +[ Upstream commit 5c7209a341ff2ac338b2b0375c34a307b37c9ac2 ] + +When protocol sets HCI_PROTO_DEFER, hci_conn_request_evt() calls +hci_connect_cfm(conn) without hdev->lock. Generally hci_connect_cfm() +assumes it is held, and if conn is deleted concurrently -> UAF. + +Only SCO and ISO set HCI_PROTO_DEFER and only for defer setup listen, +and HCI_EV_CONN_REQUEST is not generated for ISO. In the non-deferred +listening socket code paths, hci_connect_cfm(conn) is called with +hdev->lock held. + +Fix by holding the lock. + +Fixes: 70c464256310 ("Bluetooth: Refactor connection request handling") +Signed-off-by: Pauli Virtanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index f6285c4325d63..4607db3037bd9 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -3282,8 +3282,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + + memcpy(conn->dev_class, ev->dev_class, 3); + +- hci_dev_unlock(hdev); +- + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; +@@ -3317,7 +3315,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + hci_connect_cfm(conn, 0); + } + +- return; + unlock: + hci_dev_unlock(hdev); + } +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch b/queue-6.6/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch new file mode 100644 index 0000000000..5211cd2352 --- /dev/null +++ b/queue-6.6/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch @@ -0,0 +1,49 @@ +From 4faa0dc959842078e640cabc9eda4c3657b5a715 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:20 +0100 +Subject: Bluetooth: hci_ldisc: Clear HCI_UART_PROTO_INIT on error + +From: Jonathan Rissanen + +[ Upstream commit 68d39ea5e0adc9ecaea1ce8abd842ec972eb8718 ] + +When hci_register_dev() fails in hci_uart_register_dev() +HCI_UART_PROTO_INIT is not cleared before calling hu->proto->close(hu) +and setting hu->hdev to NULL. This means incoming UART data will reach +the protocol-specific recv handler in hci_uart_tty_receive() after +resources are freed. + +Clear HCI_UART_PROTO_INIT with a write lock before calling +hu->proto->close() and setting hu->hdev to NULL. The write lock ensures +all active readers have completed and no new reader can enter the +protocol recv path before resources are freed. + +This allows the protocol-specific recv functions to remove the +"HCI_UART_REGISTERED" guard without risking a null pointer dereference +if hci_register_dev() fails. + +Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization") +Signed-off-by: Jonathan Rissanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ldisc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index e38f3c4458c90..85baba91aaa97 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -689,6 +689,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device"); ++ percpu_down_write(&hu->proto_lock); ++ clear_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ percpu_up_write(&hu->proto_lock); + hu->proto->close(hu); + hu->hdev = NULL; + hci_free_dev(hdev); +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch b/queue-6.6/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch new file mode 100644 index 0000000000..d29487a06d --- /dev/null +++ b/queue-6.6/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch @@ -0,0 +1,48 @@ +From 7cc854d029cffd16dff5a6e15a0d7bebf57797dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 23:47:41 +0800 +Subject: Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp + +From: Dudu Lu + +[ Upstream commit 42776497cdbc9a665b384a6dcb85f0d4bd927eab ] + +l2cap_ecred_reconf_rsp() calls l2cap_chan_del() without holding +l2cap_chan_lock(). Every other l2cap_chan_del() caller in the file +acquires the lock first. A remote BLE device can send a crafted +L2CAP ECRED reconfiguration response to corrupt the channel list +while another thread is iterating it. + +Add l2cap_chan_hold() and l2cap_chan_lock() before l2cap_chan_del(), +and l2cap_chan_unlock() and l2cap_chan_put() after, matching the +pattern used in l2cap_ecred_conn_rsp() and l2cap_conn_del(). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 2a15863a882d6..bbaf0070ca617 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5400,7 +5400,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + if (chan->ident != cmd->ident) + continue; + ++ l2cap_chan_hold(chan); ++ l2cap_chan_lock(chan); ++ + l2cap_chan_del(chan, ECONNRESET); ++ ++ l2cap_chan_unlock(chan); ++ l2cap_chan_put(chan); + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch b/queue-6.6/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch new file mode 100644 index 0000000000..6623d21eba --- /dev/null +++ b/queue-6.6/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch @@ -0,0 +1,38 @@ +From 245a5c896e404ac3c0c067916859f1862c5aa59d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 14:34:13 -0400 +Subject: Bluetooth: L2CAP: Fix printing wrong information if SDU length + exceeds MTU + +From: Luiz Augusto von Dentz + +[ Upstream commit 15bf35a660eb82a49f8397fc3d3acada8dae13db ] + +The code was printing skb->len and sdu_len in the places where it should +be sdu_len and chan->imtu respectively to match the if conditions. + +Link: https://lore.kernel.org/linux-bluetooth/20260315132013.75ab40c5@kernel.org/T/#m1418f9c82eeff8510c1beaa21cf53af20db96c06 +Fixes: e1d9a6688986 ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU") +Signed-off-by: Luiz Augusto von Dentz +Reviewed-by: Paul Menzel +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 3da3e9fddd049..2a15863a882d6 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6658,7 +6658,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + + if (sdu_len > chan->imtu) { + BT_ERR("Too big LE L2CAP SDU length: len %u > %u", +- skb->len, sdu_len); ++ sdu_len, chan->imtu); + l2cap_send_disconn_req(chan, ECONNRESET); + err = -EMSGSIZE; + goto failed; +-- +2.53.0 + diff --git a/queue-6.6/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch b/queue-6.6/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch new file mode 100644 index 0000000000..299121b08b --- /dev/null +++ b/queue-6.6/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch @@ -0,0 +1,572 @@ +From 685da58353902c8eaa2dc56659b19e5a0ed3c23b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:32:07 +0000 +Subject: bonding: 3ad: implement proper RCU rules for port->aggregator + +From: Eric Dumazet + +[ Upstream commit c4f050ce06c56cfb5993268af4a5cb66ed1cd04e ] + +syzbot found a data-race in bond_3ad_get_active_agg_info / +bond_3ad_state_machine_handler [1] which hints at lack of proper +RCU implementation. + +Add __rcu qualifier to port->aggregator, and add proper RCU API. + +[1] + +BUG: KCSAN: data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler + +write to 0xffff88813cf5c4b0 of 8 bytes by task 36 on cpu 0: + ad_port_selection_logic drivers/net/bonding/bond_3ad.c:1659 [inline] + bond_3ad_state_machine_handler+0x9d5/0x2d60 drivers/net/bonding/bond_3ad.c:2569 + process_one_work kernel/workqueue.c:3302 [inline] + process_scheduled_works+0x4f0/0x9c0 kernel/workqueue.c:3385 + worker_thread+0x58a/0x780 kernel/workqueue.c:3466 + kthread+0x22a/0x280 kernel/kthread.c:436 + ret_from_fork+0x146/0x330 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +read to 0xffff88813cf5c4b0 of 8 bytes by task 22063 on cpu 1: + __bond_3ad_get_active_agg_info drivers/net/bonding/bond_3ad.c:2858 [inline] + bond_3ad_get_active_agg_info+0x8c/0x230 drivers/net/bonding/bond_3ad.c:2881 + bond_fill_info+0xe0f/0x10f0 drivers/net/bonding/bond_netlink.c:853 + rtnl_link_info_fill net/core/rtnetlink.c:906 [inline] + rtnl_link_fill+0x1d7/0x4e0 net/core/rtnetlink.c:927 + rtnl_fill_ifinfo+0xf8e/0x1380 net/core/rtnetlink.c:2168 + rtmsg_ifinfo_build_skb+0x11c/0x1b0 net/core/rtnetlink.c:4453 + rtmsg_ifinfo_event net/core/rtnetlink.c:4486 [inline] + rtmsg_ifinfo+0x6d/0x110 net/core/rtnetlink.c:4495 + __dev_notify_flags+0x76/0x390 net/core/dev.c:9790 + netif_change_flags+0xac/0xd0 net/core/dev.c:9823 + do_setlink+0x905/0x2950 net/core/rtnetlink.c:3180 + rtnl_group_changelink net/core/rtnetlink.c:3813 [inline] + __rtnl_newlink net/core/rtnetlink.c:3981 [inline] + rtnl_newlink+0xf55/0x1400 net/core/rtnetlink.c:4109 + rtnetlink_rcv_msg+0x64b/0x720 net/core/rtnetlink.c:6995 + netlink_rcv_skb+0x123/0x220 net/netlink/af_netlink.c:2550 + rtnetlink_rcv+0x1c/0x30 net/core/rtnetlink.c:7022 + netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline] + netlink_unicast+0x5a8/0x680 net/netlink/af_netlink.c:1344 + netlink_sendmsg+0x5c8/0x6f0 net/netlink/af_netlink.c:1894 + sock_sendmsg_nosec net/socket.c:787 [inline] + __sock_sendmsg net/socket.c:802 [inline] + ____sys_sendmsg+0x563/0x5b0 net/socket.c:2698 + ___sys_sendmsg+0x195/0x1e0 net/socket.c:2752 + __sys_sendmsg net/socket.c:2784 [inline] + __do_sys_sendmsg net/socket.c:2789 [inline] + __se_sys_sendmsg net/socket.c:2787 [inline] + __x64_sys_sendmsg+0xd4/0x160 net/socket.c:2787 + x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x12c/0x3b0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +value changed: 0x0000000000000000 -> 0xffff88813cf5c400 + +Reported by Kernel Concurrency Sanitizer on: +CPU: 1 UID: 0 PID: 22063 Comm: syz.0.31122 Tainted: G W syzkaller #0 PREEMPT(full) +Tainted: [W]=WARN +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 + +Fixes: 47e91f56008b ("bonding: use RCU protection for 3ad xmit path") +Reported-by: syzbot+9bb2ff2a4ab9e17307e1@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/69f0a82f.050a0220.3aadc4.0000.GAE@google.com/ +Signed-off-by: Eric Dumazet +Cc: Jay Vosburgh +Cc: Andrew Lunn +Link: https://patch.msgid.link/20260428123207.3809211-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_3ad.c | 109 ++++++++++++++----------- + drivers/net/bonding/bond_main.c | 8 +- + drivers/net/bonding/bond_netlink.c | 16 ++-- + drivers/net/bonding/bond_procfs.c | 3 +- + drivers/net/bonding/bond_sysfs_slave.c | 17 ++-- + include/net/bond_3ad.h | 2 +- + 6 files changed, 89 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index a897836ad21a3..d1da96f3efd40 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -991,6 +991,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) + static void ad_mux_machine(struct port *port, bool *update_slave_arr) + { + struct bonding *bond = __get_bond_by_port(port); ++ struct aggregator *aggregator; + mux_states_t last_state; + + /* keep current State Machine state to compare later if it was +@@ -998,6 +999,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + */ + last_state = port->sm_mux_state; + ++ aggregator = rcu_dereference(port->aggregator); + if (port->sm_vars & AD_PORT_BEGIN) { + port->sm_mux_state = AD_MUX_DETACHED; + } else { +@@ -1017,7 +1019,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * cycle to update ready variable, we check + * READY_N and update READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + port->sm_mux_state = AD_MUX_DETACHED; + break; + } +@@ -1032,7 +1034,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * update ready variable, we check READY_N and update + * READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + + /* if the wait_while_timer expired, and the port is + * in READY state, move to ATTACHED state +@@ -1048,7 +1050,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + if ((port->sm_vars & AD_PORT_SELECTED) && + (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && + !__check_agg_selection_timer(port)) { +- if (port->aggregator->is_active) { ++ if (aggregator->is_active) { + int state = AD_MUX_COLLECTING_DISTRIBUTING; + + if (!bond->params.coupled_control) +@@ -1064,9 +1066,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * cycle to update ready variable, we check + * READY_N and update READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + port->sm_mux_state = AD_MUX_DETACHED; +- } else if (port->aggregator->is_active) { ++ } else if (aggregator->is_active) { + port->actor_oper_port_state |= + LACP_STATE_SYNCHRONIZATION; + } +@@ -1077,7 +1079,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * sure that a collecting distributing + * port in an active aggregator is enabled + */ +- if (port->aggregator->is_active && ++ if (aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; +@@ -1096,7 +1098,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + */ + struct slave *slave = port->slave; + +- if (port->aggregator->is_active && ++ if (aggregator->is_active && + bond_is_slave_rx_disabled(slave)) { + ad_enable_collecting(port); + *update_slave_arr = true; +@@ -1116,8 +1118,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * sure that a collecting distributing + * port in an active aggregator is enabled + */ +- if (port->aggregator && +- port->aggregator->is_active && ++ if (aggregator && ++ aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; +@@ -1149,7 +1151,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); + break; + case AD_MUX_ATTACHED: +- if (port->aggregator->is_active) ++ if (aggregator->is_active) + port->actor_oper_port_state |= + LACP_STATE_SYNCHRONIZATION; + else +@@ -1522,9 +1524,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + bond = __get_bond_by_port(port); + + /* if the port is connected to other aggregator, detach it */ +- if (port->aggregator) { ++ temp_aggregator = rcu_dereference(port->aggregator); ++ if (temp_aggregator) { + /* detach the port from its former aggregator */ +- temp_aggregator = port->aggregator; + for (curr_port = temp_aggregator->lag_ports; curr_port; + last_port = curr_port, + curr_port = curr_port->next_port_in_aggregator) { +@@ -1547,7 +1549,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + /* clear the port's relations to this + * aggregator + */ +- port->aggregator = NULL; ++ RCU_INIT_POINTER(port->aggregator, NULL); + port->next_port_in_aggregator = NULL; + port->actor_port_aggregator_identifier = 0; + +@@ -1570,7 +1572,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + port->slave->bond->dev->name, + port->slave->dev->name, + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ temp_aggregator->aggregator_identifier); + } + } + /* search on all aggregators for a suitable aggregator for this port */ +@@ -1594,15 +1596,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + ) + ) { + /* attach to the founded aggregator */ +- port->aggregator = aggregator; ++ rcu_assign_pointer(port->aggregator, aggregator); + port->actor_port_aggregator_identifier = +- port->aggregator->aggregator_identifier; ++ aggregator->aggregator_identifier; + port->next_port_in_aggregator = aggregator->lag_ports; +- port->aggregator->num_of_ports++; ++ aggregator->num_of_ports++; + aggregator->lag_ports = port; + slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + + /* mark this port as selected */ + port->sm_vars |= AD_PORT_SELECTED; +@@ -1617,39 +1619,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + if (!found) { + if (free_aggregator) { + /* assign port a new aggregator */ +- port->aggregator = free_aggregator; + port->actor_port_aggregator_identifier = +- port->aggregator->aggregator_identifier; ++ free_aggregator->aggregator_identifier; + + /* update the new aggregator's parameters + * if port was responsed from the end-user + */ + if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) + /* if port is full duplex */ +- port->aggregator->is_individual = false; ++ free_aggregator->is_individual = false; + else +- port->aggregator->is_individual = true; ++ free_aggregator->is_individual = true; + +- port->aggregator->actor_admin_aggregator_key = ++ free_aggregator->actor_admin_aggregator_key = + port->actor_admin_port_key; +- port->aggregator->actor_oper_aggregator_key = ++ free_aggregator->actor_oper_aggregator_key = + port->actor_oper_port_key; +- port->aggregator->partner_system = ++ free_aggregator->partner_system = + port->partner_oper.system; +- port->aggregator->partner_system_priority = ++ free_aggregator->partner_system_priority = + port->partner_oper.system_priority; +- port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; +- port->aggregator->receive_state = 1; +- port->aggregator->transmit_state = 1; +- port->aggregator->lag_ports = port; +- port->aggregator->num_of_ports++; ++ free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; ++ free_aggregator->receive_state = 1; ++ free_aggregator->transmit_state = 1; ++ free_aggregator->lag_ports = port; ++ free_aggregator->num_of_ports++; ++ ++ rcu_assign_pointer(port->aggregator, free_aggregator); + + /* mark this port as selected */ + port->sm_vars |= AD_PORT_SELECTED; + + slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ free_aggregator->aggregator_identifier); + } else { + slave_err(bond->dev, port->slave->dev, + "Port %d did not find a suitable aggregator\n", +@@ -1661,13 +1664,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + * in all aggregator's ports, else set ready=FALSE in all + * aggregator's ports + */ +- __set_agg_ports_ready(port->aggregator, +- __agg_ports_are_ready(port->aggregator)); ++ aggregator = rcu_dereference(port->aggregator); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + +- aggregator = __get_first_agg(port); +- ad_agg_selection_logic(aggregator, update_slave_arr); ++ ad_agg_selection_logic(__get_first_agg(port), update_slave_arr); + +- if (!port->aggregator->is_active) ++ if (!aggregator->is_active) + port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION; + } + +@@ -2021,13 +2023,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond + */ + static void ad_enable_collecting(struct port *port) + { +- if (port->aggregator->is_active) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator->is_active) { + struct slave *slave = port->slave; + + slave_dbg(slave->bond->dev, slave->dev, + "Enabling collecting on port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __enable_collecting_port(port); + } + } +@@ -2039,11 +2043,13 @@ static void ad_enable_collecting(struct port *port) + */ + static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + { +- if (port->aggregator && __agg_has_partner(port->aggregator)) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator && __agg_has_partner(aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling distributing on port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __disable_distributing_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; +@@ -2060,11 +2066,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + static void ad_enable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator->is_active) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator->is_active) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Enabling port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __enable_port(port); + /* Slave array needs update */ + *update_slave_arr = true; +@@ -2079,11 +2087,13 @@ static void ad_enable_collecting_distributing(struct port *port, + static void ad_disable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator && __agg_has_partner(port->aggregator)) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator && __agg_has_partner(aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __disable_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; +@@ -2323,7 +2333,7 @@ void bond_3ad_unbind_slave(struct slave *slave) + */ + for (temp_port = aggregator->lag_ports; temp_port; + temp_port = temp_port->next_port_in_aggregator) { +- temp_port->aggregator = new_aggregator; ++ rcu_assign_pointer(temp_port->aggregator, new_aggregator); + temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; + } + +@@ -2792,15 +2802,16 @@ int bond_3ad_set_carrier(struct bonding *bond) + int __bond_3ad_get_active_agg_info(struct bonding *bond, + struct ad_info *ad_info) + { +- struct aggregator *aggregator = NULL; ++ struct aggregator *aggregator = NULL, *tmp; + struct list_head *iter; + struct slave *slave; + struct port *port; + + bond_for_each_slave_rcu(bond, slave, iter) { + port = &(SLAVE_AD_INFO(slave)->port); +- if (port->aggregator && port->aggregator->is_active) { +- aggregator = port->aggregator; ++ tmp = rcu_dereference(port->aggregator); ++ if (tmp && tmp->is_active) { ++ aggregator = tmp; + break; + } + } +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 70718bf6e716c..029a7f001dd8a 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1394,7 +1394,7 @@ static void bond_poll_controller(struct net_device *bond_dev) + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + struct aggregator *agg = +- SLAVE_AD_INFO(slave)->port.aggregator; ++ rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + + if (agg && + agg->aggregator_identifier != ad_info.aggregator_id) +@@ -5196,15 +5196,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) + spin_unlock_bh(&bond->mode_lock); + agg_id = ad_info.aggregator_id; + } ++ rcu_read_lock(); + bond_for_each_slave(bond, slave, iter) { + if (skipslave == slave) + continue; + + all_slaves->arr[all_slaves->count++] = slave; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { +- struct aggregator *agg; ++ const struct aggregator *agg; + +- agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (!agg || agg->aggregator_identifier != agg_id) + continue; + } +@@ -5216,6 +5217,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) + + usable_slaves->arr[usable_slaves->count++] = slave; + } ++ rcu_read_unlock(); + + bond_set_slave_arr(bond, usable_slaves, all_slaves); + return ret; +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index 086233dce9c8d..0eaf4b0e06ffb 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -65,27 +65,29 @@ static int bond_fill_slave_info(struct sk_buff *skb, + const struct port *ad_port; + + ad_port = &SLAVE_AD_INFO(slave)->port; +- agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ rcu_read_lock(); ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (agg) { + if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, + agg->aggregator_identifier)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u8(skb, + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, + ad_port->actor_oper_port_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u16(skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, + ad_port->sm_churn_actor_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + ad_port->sm_churn_partner_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + } ++ rcu_read_unlock(); + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + SLAVE_AD_INFO(slave)->port_priority)) +@@ -94,6 +96,8 @@ static int bond_fill_slave_info(struct sk_buff *skb, + + return 0; + ++nla_put_failure_rcu: ++ rcu_read_unlock(); + nla_put_failure: + return -EMSGSIZE; + } +diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c +index 43be458422b3f..bc919814eb504 100644 +--- a/drivers/net/bonding/bond_procfs.c ++++ b/drivers/net/bonding/bond_procfs.c +@@ -187,6 +187,7 @@ static void bond_info_show_master(struct seq_file *seq) + } + } + ++/* Note: runs under rcu_read_lock() */ + static void bond_info_show_slave(struct seq_file *seq, + const struct slave *slave) + { +@@ -213,7 +214,7 @@ static void bond_info_show_slave(struct seq_file *seq, + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + const struct port *port = &SLAVE_AD_INFO(slave)->port; +- const struct aggregator *agg = port->aggregator; ++ const struct aggregator *agg = rcu_dereference(port->aggregator); + + if (agg) { + seq_printf(seq, "Aggregator ID: %d\n", +diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c +index 313866f2c0e49..75df3e21b804d 100644 +--- a/drivers/net/bonding/bond_sysfs_slave.c ++++ b/drivers/net/bonding/bond_sysfs_slave.c +@@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf) + const struct aggregator *agg; + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { +- agg = SLAVE_AD_INFO(slave)->port.aggregator; +- if (agg) +- return sysfs_emit(buf, "%d\n", +- agg->aggregator_identifier); ++ rcu_read_lock(); ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); ++ if (agg) { ++ ssize_t res = sysfs_emit(buf, "%d\n", ++ agg->aggregator_identifier); ++ rcu_read_unlock(); ++ return res; ++ } ++ rcu_read_unlock(); + } + + return sysfs_emit(buf, "N/A\n"); +@@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf) + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; +- if (ad_port->aggregator) ++ if (rcu_access_pointer(ad_port->aggregator)) + return sysfs_emit(buf, "%u\n", + ad_port->actor_oper_port_state); + } +@@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf) + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; +- if (ad_port->aggregator) ++ if (rcu_access_pointer(ad_port->aggregator)) + return sysfs_emit(buf, "%u\n", + ad_port->partner_oper.port_state); + } +diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h +index 84fe87314bd9c..728aec9bda4a4 100644 +--- a/include/net/bond_3ad.h ++++ b/include/net/bond_3ad.h +@@ -239,7 +239,7 @@ typedef struct port { + churn_state_t sm_churn_actor_state; + churn_state_t sm_churn_partner_state; + struct slave *slave; /* pointer to the bond slave that this port belongs to */ +- struct aggregator *aggregator; /* pointer to an aggregator that this port related to */ ++ struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */ + struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ + u32 transaction_id; /* continuous number for identification of Marker PDU's; */ + struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ +-- +2.53.0 + diff --git a/queue-6.6/bonding-802.3ad-replace-mac_address_equal-with-__agg.patch b/queue-6.6/bonding-802.3ad-replace-mac_address_equal-with-__agg.patch new file mode 100644 index 0000000000..9e7b786b11 --- /dev/null +++ b/queue-6.6/bonding-802.3ad-replace-mac_address_equal-with-__agg.patch @@ -0,0 +1,87 @@ +From 82005621c9ec9dc59d5ea94aafbd138ae06af7eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Feb 2024 02:24:52 +0000 +Subject: bonding: 802.3ad replace MAC_ADDRESS_EQUAL with __agg_has_partner +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jones Syue 薛懷宗 + +[ Upstream commit 4440873f3655325f849366d75382aa05d09b5575 ] + +Replace macro MAC_ADDRESS_EQUAL() for null_mac_addr checking with inline +function__agg_has_partner(). When MAC_ADDRESS_EQUAL() is verifiying +aggregator's partner mac addr with null_mac_addr, means that seeing if +aggregator has a valid partner or not. Using __agg_has_partner() makes it +more clear to understand. + +In ad_port_selection_logic(), since aggregator->partner_system and +port->partner_oper.system has been compared first as a prerequisite, it is +safe to replace the upcoming MAC_ADDRESS_EQUAL() for null_mac_addr checking +with __agg_has_partner(). + +Delete null_mac_addr, which is not required anymore in bond_3ad.c, since +all references to it are gone. + +Signed-off-by: Jones Syue +Reviewed-by: Hangbin Liu +Reviewed-by: Jiri Pirko +Acked-by: Jay Vosburgh +Link: https://lore.kernel.org/r/SI2PR04MB5097BCA8FF2A2F03D9A5A3EEDC5A2@SI2PR04MB5097.apcprd04.prod.outlook.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_3ad.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index d02a91cefec89..4c2560ae8866a 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -82,10 +82,6 @@ enum ad_link_speed_type { + #define MAC_ADDRESS_EQUAL(A, B) \ + ether_addr_equal_64bits((const u8 *)A, (const u8 *)B) + +-static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = { +- 0, 0, 0, 0, 0, 0 +-}; +- + static const u16 ad_ticks_per_sec = 1000 / AD_TIMER_INTERVAL; + static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; + +@@ -1592,7 +1588,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + (aggregator->partner_system_priority == port->partner_oper.system_priority) && + (aggregator->partner_oper_aggregator_key == port->partner_oper.key) + ) && +- ((!MAC_ADDRESS_EQUAL(&(port->partner_oper.system), &(null_mac_addr)) && /* partner answers */ ++ ((__agg_has_partner(aggregator) && /* partner answers */ + !aggregator->is_individual) /* but is not individual OR */ + ) + ) { +@@ -2042,9 +2038,7 @@ static void ad_enable_collecting(struct port *port) + */ + static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + { +- if (port->aggregator && +- !MAC_ADDRESS_EQUAL(&port->aggregator->partner_system, +- &(null_mac_addr))) { ++ if (port->aggregator && __agg_has_partner(port->aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling distributing on port %d (LAG %d)\n", + port->actor_port_number, +@@ -2084,9 +2078,7 @@ static void ad_enable_collecting_distributing(struct port *port, + static void ad_disable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator && +- !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system), +- &(null_mac_addr))) { ++ if (port->aggregator && __agg_has_partner(port->aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling port %d (LAG %d)\n", + port->actor_port_number, +-- +2.53.0 + diff --git a/queue-6.6/bonding-add-support-for-per-port-lacp-actor-priority.patch b/queue-6.6/bonding-add-support-for-per-port-lacp-actor-priority.patch new file mode 100644 index 0000000000..7e419effae --- /dev/null +++ b/queue-6.6/bonding-add-support-for-per-port-lacp-actor-priority.patch @@ -0,0 +1,229 @@ +From e8ce9f5dbfedae085832155c89bbcc27120e31d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Sep 2025 06:44:59 +0000 +Subject: bonding: add support for per-port LACP actor priority + +From: Hangbin Liu + +[ Upstream commit 6b6dc81ee7e8ca87c71a533e1d69cf96a4f1e986 ] + +Introduce a new netlink attribute 'actor_port_prio' to allow setting +the LACP actor port priority on a per-slave basis. This extends the +existing bonding infrastructure to support more granular control over +LACP negotiations. + +The priority value is embedded in LACPDU packets and will be used by +subsequent patches to influence aggregator selection policies. + +Signed-off-by: Hangbin Liu +Link: https://patch.msgid.link/20250902064501.360822-2-liuhangbin@gmail.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + Documentation/networking/bonding.rst | 9 +++++++ + drivers/net/bonding/bond_3ad.c | 4 ++++ + drivers/net/bonding/bond_netlink.c | 16 +++++++++++++ + drivers/net/bonding/bond_options.c | 36 ++++++++++++++++++++++++++++ + include/net/bond_3ad.h | 1 + + include/net/bond_options.h | 1 + + include/uapi/linux/if_link.h | 1 + + 7 files changed, 68 insertions(+) + +diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst +index 1a9439488c531..94ef39457a622 100644 +--- a/Documentation/networking/bonding.rst ++++ b/Documentation/networking/bonding.rst +@@ -193,6 +193,15 @@ ad_actor_sys_prio + This parameter has effect only in 802.3ad mode and is available through + SysFs interface. + ++actor_port_prio ++ ++ In an AD system, this specifies the port priority. The allowed range ++ is 1 - 65535. If the value is not specified, it takes 255 as the ++ default value. ++ ++ This parameter has effect only in 802.3ad mode and is available through ++ netlink interface. ++ + ad_actor_system + + In an AD system, this specifies the mac-address for the actor in +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index 4c2560ae8866a..a897836ad21a3 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -436,6 +436,7 @@ static void __ad_actor_update_port(struct port *port) + + port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr; + port->actor_system_priority = BOND_AD_INFO(bond).system.sys_priority; ++ port->actor_port_priority = SLAVE_AD_INFO(port->slave)->port_priority; + } + + /* Conversions */ +@@ -2195,6 +2196,9 @@ void bond_3ad_bind_slave(struct slave *slave) + + ad_initialize_port(port, &bond->params); + ++ /* Port priority is initialized. Update it to slave's ad info */ ++ SLAVE_AD_INFO(slave)->port_priority = port->actor_port_priority; ++ + port->slave = slave; + port->actor_port_number = SLAVE_AD_INFO(slave)->id; + /* key is determined according to the link speed, duplex and +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index aebc814ad495d..7e47d405d74aa 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -28,6 +28,7 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, + nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ + nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ ++ nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ + 0; + } + +@@ -76,6 +77,10 @@ static int bond_fill_slave_info(struct sk_buff *skb, + ad_port->partner_oper.port_state)) + goto nla_put_failure; + } ++ ++ if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, ++ SLAVE_AD_INFO(slave)->port_priority)) ++ goto nla_put_failure; + } + + return 0; +@@ -128,6 +133,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { + static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { + [IFLA_BOND_SLAVE_QUEUE_ID] = { .type = NLA_U16 }, + [IFLA_BOND_SLAVE_PRIO] = { .type = NLA_S32 }, ++ [IFLA_BOND_SLAVE_ACTOR_PORT_PRIO] = { .type = NLA_U16 }, + }; + + static int bond_validate(struct nlattr *tb[], struct nlattr *data[], +@@ -178,6 +184,16 @@ static int bond_slave_changelink(struct net_device *bond_dev, + return err; + } + ++ if (data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO]) { ++ u16 ad_prio = nla_get_u16(data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO]); ++ ++ bond_opt_slave_initval(&newval, &slave_dev, ad_prio); ++ err = __bond_opt_set(bond, BOND_OPT_ACTOR_PORT_PRIO, &newval, ++ data[IFLA_BOND_SLAVE_ACTOR_PORT_PRIO], extack); ++ if (err) ++ return err; ++ } ++ + return 0; + } + +diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c +index fe955ba5c9685..f4ad0fc624c98 100644 +--- a/drivers/net/bonding/bond_options.c ++++ b/drivers/net/bonding/bond_options.c +@@ -79,6 +79,8 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, + const struct bond_opt_value *newval); + static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, + const struct bond_opt_value *newval); ++static int bond_option_actor_port_prio_set(struct bonding *bond, ++ const struct bond_opt_value *newval); + static int bond_option_ad_actor_system_set(struct bonding *bond, + const struct bond_opt_value *newval); + static int bond_option_ad_user_port_key_set(struct bonding *bond, +@@ -223,6 +225,13 @@ static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = { + { NULL, -1, 0}, + }; + ++static const struct bond_opt_value bond_actor_port_prio_tbl[] = { ++ { "minval", 0, BOND_VALFLAG_MIN}, ++ { "maxval", 65535, BOND_VALFLAG_MAX}, ++ { "default", 255, BOND_VALFLAG_DEFAULT}, ++ { NULL, -1, 0}, ++}; ++ + static const struct bond_opt_value bond_ad_user_port_key_tbl[] = { + { "minval", 0, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT}, + { "maxval", 1023, BOND_VALFLAG_MAX}, +@@ -484,6 +493,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { + .values = bond_ad_actor_sys_prio_tbl, + .set = bond_option_ad_actor_sys_prio_set, + }, ++ [BOND_OPT_ACTOR_PORT_PRIO] = { ++ .id = BOND_OPT_ACTOR_PORT_PRIO, ++ .name = "actor_port_prio", ++ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), ++ .values = bond_actor_port_prio_tbl, ++ .set = bond_option_actor_port_prio_set, ++ }, + [BOND_OPT_AD_ACTOR_SYSTEM] = { + .id = BOND_OPT_AD_ACTOR_SYSTEM, + .name = "ad_actor_system", +@@ -1819,6 +1835,26 @@ static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, + return 0; + } + ++static int bond_option_actor_port_prio_set(struct bonding *bond, ++ const struct bond_opt_value *newval) ++{ ++ struct slave *slave; ++ ++ slave = bond_slave_get_rtnl(newval->slave_dev); ++ if (!slave) { ++ netdev_dbg(bond->dev, "%s called on NULL slave\n", __func__); ++ return -ENODEV; ++ } ++ ++ netdev_dbg(newval->slave_dev, "Setting actor_port_prio to %llu\n", ++ newval->value); ++ ++ SLAVE_AD_INFO(slave)->port_priority = newval->value; ++ bond_3ad_update_ad_actor_settings(bond); ++ ++ return 0; ++} ++ + static int bond_option_ad_actor_system_set(struct bonding *bond, + const struct bond_opt_value *newval) + { +diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h +index 078e16d2512a5..84fe87314bd9c 100644 +--- a/include/net/bond_3ad.h ++++ b/include/net/bond_3ad.h +@@ -271,6 +271,7 @@ struct ad_slave_info { + struct port port; /* 802.3ad port structure */ + struct bond_3ad_stats stats; + u16 id; ++ u16 port_priority; + }; + + static inline const char *bond_3ad_churn_desc(churn_state_t state) +diff --git a/include/net/bond_options.h b/include/net/bond_options.h +index 022b122a9fb61..e6eedf23aea1a 100644 +--- a/include/net/bond_options.h ++++ b/include/net/bond_options.h +@@ -78,6 +78,7 @@ enum { + BOND_OPT_PRIO, + BOND_OPT_COUPLED_CONTROL, + BOND_OPT_BROADCAST_NEIGH, ++ BOND_OPT_ACTOR_PORT_PRIO, + BOND_OPT_LAST + }; + +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index 6750911da4f06..3533368f16472 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -979,6 +979,7 @@ enum { + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + IFLA_BOND_SLAVE_PRIO, ++ IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + __IFLA_BOND_SLAVE_MAX, + }; + +-- +2.53.0 + diff --git a/queue-6.6/bonding-print-churn-state-via-netlink.patch b/queue-6.6/bonding-print-churn-state-via-netlink.patch new file mode 100644 index 0000000000..a33fb26a8c --- /dev/null +++ b/queue-6.6/bonding-print-churn-state-via-netlink.patch @@ -0,0 +1,65 @@ +From 8d21f8564c8eaa53b77692453d82c1fdcc1a292d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 02:02:14 +0000 +Subject: bonding: print churn state via netlink + +From: Hangbin Liu + +[ Upstream commit 4916f2e2f3fc9aef289fcd07949301e5c29094c2 ] + +Currently, the churn state is printed only in sysfs. Add netlink support +so users could get the state via netlink. + +Signed-off-by: Hangbin Liu +Link: https://patch.msgid.link/20260224020215.6012-1-liuhangbin@gmail.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_netlink.c | 9 +++++++++ + include/uapi/linux/if_link.h | 2 ++ + 2 files changed, 11 insertions(+) + +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index 7e47d405d74aa..086233dce9c8d 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -29,6 +29,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ + nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ ++ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE */ ++ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE */ + 0; + } + +@@ -76,6 +78,13 @@ static int bond_fill_slave_info(struct sk_buff *skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) + goto nla_put_failure; ++ ++ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, ++ ad_port->sm_churn_actor_state)) ++ goto nla_put_failure; ++ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, ++ ad_port->sm_churn_partner_state)) ++ goto nla_put_failure; + } + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index 3533368f16472..7c1fb14197024 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -980,6 +980,8 @@ enum { + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + IFLA_BOND_SLAVE_PRIO, + IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, ++ IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, ++ IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + __IFLA_BOND_SLAVE_MAX, + }; + +-- +2.53.0 + diff --git a/queue-6.6/bpf-add-checksum_complete-to-bpf-test-progs.patch b/queue-6.6/bpf-add-checksum_complete-to-bpf-test-progs.patch new file mode 100644 index 0000000000..960cad8c1c --- /dev/null +++ b/queue-6.6/bpf-add-checksum_complete-to-bpf-test-progs.patch @@ -0,0 +1,117 @@ +From 006936991a536a49bc71f315262dda605a956936 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2024 07:58:50 -0700 +Subject: bpf: Add CHECKSUM_COMPLETE to bpf test progs + +From: Vadim Fedorenko + +[ Upstream commit a3cfe84cca28f205761a0450016593b0d728165e ] + +Add special flag to validate that TC BPF program properly updates +checksum information in skb. + +Signed-off-by: Vadim Fedorenko +Signed-off-by: Daniel Borkmann +Reviewed-by: Jakub Kicinski +Acked-by: Daniel Borkmann +Link: https://lore.kernel.org/bpf/20240606145851.229116-1-vadfed@meta.com +Stable-dep-of: 972787479ee7 ("bpf: test_run: Fix the null pointer dereference issue in bpf_lwt_xmit_push_encap") +Signed-off-by: Sasha Levin +--- + include/uapi/linux/bpf.h | 2 ++ + net/bpf/test_run.c | 28 +++++++++++++++++++++++++++- + tools/include/uapi/linux/bpf.h | 2 ++ + 3 files changed, 31 insertions(+), 1 deletion(-) + +diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h +index 08a0494736e6e..6950169329ef1 100644 +--- a/include/uapi/linux/bpf.h ++++ b/include/uapi/linux/bpf.h +@@ -1344,6 +1344,8 @@ enum { + #define BPF_F_TEST_RUN_ON_CPU (1U << 0) + /* If set, XDP frames will be transmitted after processing */ + #define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1) ++/* If set, apply CHECKSUM_COMPLETE to skb and validate the checksum */ ++#define BPF_F_TEST_SKB_CHECKSUM_COMPLETE (1U << 2) + + /* type for BPF_ENABLE_STATS */ + enum bpf_stats_type { +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 3a1c82b797a30..774287ac17955 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -966,7 +966,8 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + void *data; + int ret; + +- if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size) ++ if ((kattr->test.flags & ~BPF_F_TEST_SKB_CHECKSUM_COMPLETE) || ++ kattr->test.cpu || kattr->test.batch_size) + return -EINVAL; + + if (size < ETH_HLEN) +@@ -1017,6 +1018,7 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + __skb_put(skb, size); ++ + if (ctx && ctx->ifindex > 1) { + dev = dev_get_by_index(net, ctx->ifindex); + if (!dev) { +@@ -1052,9 +1054,19 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + __skb_push(skb, hh_len); + if (is_direct_pkt_access) + bpf_compute_data_pointers(skb); ++ + ret = convert___skb_to_skb(skb, ctx); + if (ret) + goto out; ++ ++ if (kattr->test.flags & BPF_F_TEST_SKB_CHECKSUM_COMPLETE) { ++ const int off = skb_network_offset(skb); ++ int len = skb->len - off; ++ ++ skb->csum = skb_checksum(skb, off, len, 0); ++ skb->ip_summed = CHECKSUM_COMPLETE; ++ } ++ + ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false); + if (ret) + goto out; +@@ -1069,6 +1081,20 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + } + memset(__skb_push(skb, hh_len), 0, hh_len); + } ++ ++ if (kattr->test.flags & BPF_F_TEST_SKB_CHECKSUM_COMPLETE) { ++ const int off = skb_network_offset(skb); ++ int len = skb->len - off; ++ __wsum csum; ++ ++ csum = skb_checksum(skb, off, len, 0); ++ ++ if (csum_fold(skb->csum) != csum_fold(csum)) { ++ ret = -EBADMSG; ++ goto out; ++ } ++ } ++ + convert_skb_to___skb(skb, ctx); + + size = skb->len; +diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h +index 2e064a1032a05..8967952de0c2e 100644 +--- a/tools/include/uapi/linux/bpf.h ++++ b/tools/include/uapi/linux/bpf.h +@@ -1344,6 +1344,8 @@ enum { + #define BPF_F_TEST_RUN_ON_CPU (1U << 0) + /* If set, XDP frames will be transmitted after processing */ + #define BPF_F_TEST_XDP_LIVE_FRAMES (1U << 1) ++/* If set, apply CHECKSUM_COMPLETE to skb and validate the checksum */ ++#define BPF_F_TEST_SKB_CHECKSUM_COMPLETE (1U << 2) + + /* type for BPF_ENABLE_STATS */ + enum bpf_stats_type { +-- +2.53.0 + diff --git a/queue-6.6/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch b/queue-6.6/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch new file mode 100644 index 0000000000..5f29cde345 --- /dev/null +++ b/queue-6.6/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch @@ -0,0 +1,84 @@ +From 3f7897525c489a85ec33ba8ad5e5fc91a0647e01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:01:41 +0800 +Subject: bpf: allow UTF-8 literals in bpf_bprintf_prepare() + +From: Yihan Ding + +[ Upstream commit b960430ea8862ef37ce53c8bf74a8dc79d3f2404 ] + +bpf_bprintf_prepare() only needs ASCII parsing for conversion +specifiers. Plain text can safely carry bytes >= 0x80, so allow +UTF-8 literals outside '%' sequences while keeping ASCII control +bytes rejected and format specifiers ASCII-only. + +This keeps existing parsing rules for format directives unchanged, +while allowing helpers such as bpf_trace_printk() to emit UTF-8 +literal text. + +Update test_snprintf_negative() in the same commit so selftests keep +matching the new plain-text vs format-specifier split during bisection. + +Fixes: 48cac3f4a96d ("bpf: Implement formatted output helpers with bstr_printf") +Signed-off-by: Yihan Ding +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416120142.1420646-2-dingyihan@uniontech.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/helpers.c | 17 ++++++++++++++++- + .../testing/selftests/bpf/prog_tests/snprintf.c | 3 ++- + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index 2cfbc48b82425..885ff0710a8b9 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -849,7 +849,13 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, + data->buf = buffers->buf; + + for (i = 0; i < fmt_size; i++) { +- if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { ++ unsigned char c = fmt[i]; ++ ++ /* ++ * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass ++ * through unchanged, while still rejecting ASCII control bytes. ++ */ ++ if (isascii(c) && !isprint(c) && !isspace(c)) { + err = -EINVAL; + goto out; + } +@@ -871,6 +877,15 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, + * always access fmt[i + 1], in the worst case it will be a 0 + */ + i++; ++ c = fmt[i]; ++ /* ++ * The format parser below only understands ASCII conversion ++ * specifiers and modifiers, so reject non-ASCII after '%'. ++ */ ++ if (!isascii(c)) { ++ err = -EINVAL; ++ goto out; ++ } + + /* skip optional "[0 +-][num]" width formatting field */ + while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || +diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c +index 4be6fdb78c6a1..20a3c622bd28a 100644 +--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c ++++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c +@@ -114,7 +114,8 @@ static void test_snprintf_negative(void) + ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5"); + ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6"); + ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7"); +- ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character"); ++ ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text"); ++ ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier"); + ASSERT_ERR(load_single_snprintf("\x1"), "non printable character"); + } + +-- +2.53.0 + diff --git a/queue-6.6/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch b/queue-6.6/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch new file mode 100644 index 0000000000..8aaa245622 --- /dev/null +++ b/queue-6.6/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch @@ -0,0 +1,96 @@ +From 6e9f20b6ea5d8be6cff83374053fef52e0066881 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 07:33:52 -0700 +Subject: bpf, arm32: Reject BPF-to-BPF calls and callbacks in the JIT + +From: Puranjay Mohan + +[ Upstream commit e1d486445af3c392628532229f7ce5f5cf7891b6 ] + +The ARM32 BPF JIT does not support BPF-to-BPF function calls +(BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does +not reject them either. + +When a program with subprograms is loaded (e.g. libxdp's XDP +dispatcher uses __noinline__ subprograms, or any program using +callbacks like bpf_loop or bpf_for_each_map_elem), the verifier +invokes bpf_jit_subprogs() which calls bpf_int_jit_compile() +for each subprogram. + +For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT +silently emits code using the wrong address computation: + + func = __bpf_call_base + imm + +where imm is a pc-relative subprogram offset, producing a bogus +function pointer. + +For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and +loads the immediate as a normal 64-bit value without error. + +In both cases, build_body() reports success and a JIT image is +allocated. ARM32 lacks the jit_data/extra_pass mechanism needed +for the second JIT pass in bpf_jit_subprogs(). On the second +pass, bpf_int_jit_compile() performs a full fresh compilation, +allocating a new JIT binary and overwriting prog->bpf_func. The +first allocation is never freed. bpf_jit_subprogs() then detects +the function pointer changed and aborts with -ENOTSUPP, but the +original JIT binary has already been leaked. Each program +load/unload cycle leaks one JIT binary allocation, as reported +by kmemleak: + + unreferenced object 0xbf0a1000 (size 4096): + backtrace: + bpf_jit_binary_alloc+0x64/0xfc + bpf_int_jit_compile+0x14c/0x348 + bpf_jit_subprogs+0x4fc/0xa60 + +Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL +handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling +through to the existing 'notyet' path. This causes build_body() +to fail before any JIT binary is allocated, so +bpf_int_jit_compile() returns the original program unjitted. +bpf_jit_subprogs() then sees !prog->jited and cleanly falls +back to the interpreter with no leak. + +Acked-by: Daniel Borkmann +Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs") +Reported-by: Jonas Rebmann +Closes: https://lore.kernel.org/bpf/b63e9174-7a3d-4e22-8294-16df07a4af89@pengutronix.de +Tested-by: Jonas Rebmann +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417143353.838911-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm/net/bpf_jit_32.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c +index 6a1c9fca5260b..2292245cfe7a9 100644 +--- a/arch/arm/net/bpf_jit_32.c ++++ b/arch/arm/net/bpf_jit_32.c +@@ -1594,6 +1594,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + { + u64 val = (u32)imm | (u64)insn[1].imm << 32; + ++ if (insn->src_reg == BPF_PSEUDO_FUNC) ++ goto notyet; ++ + emit_a32_mov_i64(dst, val, ctx); + + return 1; +@@ -1785,6 +1788,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + const s8 *r5 = bpf2a32[BPF_REG_5]; + const u32 func = (u32)__bpf_call_base + (u32)imm; + ++ if (insn->src_reg == BPF_PSEUDO_CALL) ++ goto notyet; ++ + emit_a32_mov_r64(true, r0, r1, ctx); + emit_a32_mov_r64(true, r1, r2, ctx); + emit_push_r64(r5, ctx); +-- +2.53.0 + diff --git a/queue-6.6/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch b/queue-6.6/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch new file mode 100644 index 0000000000..eb9350c6b5 --- /dev/null +++ b/queue-6.6/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch @@ -0,0 +1,57 @@ +From 8ca07909fac17141e79807339a2411360cb33fe7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:14:03 +0200 +Subject: bpf, arm64: Fix off-by-one in check_imm signed range check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Borkmann + +[ Upstream commit 1dd8be4ec722ce54e4cace59f3a4ba658111b3ec ] + +check_imm(bits, imm) is used in the arm64 BPF JIT to verify that +a branch displacement (in arm64 instruction units) fits into the +signed N-bit immediate field of a B, B.cond or CBZ/CBNZ encoding +before it is handed to the encoder. The macro currently tests for +(imm > 0 && imm >> bits) || (imm < 0 && ~imm >> bits) which admits +values in [-2^N, 2^N) — effectively a signed (N+1)-bit range. A +signed N-bit field only holds [-2^(N-1), 2^(N-1)), so the check +admits one extra bit of range on each side. + +In particular, for check_imm19(), values in [2^18, 2^19) slip past +the check but do not fit into the 19-bit signed imm19 field of +B.cond. aarch64_insn_encode_immediate() then masks the raw value +into the 19-bit field, setting bit 18 (the sign bit) and flipping +a forward branch into a backward one. Same class of issue exists +for check_imm26() and the B/BL encoding. Shift by (bits - 1) +instead of bits so the actual signed N-bit range is enforced. + +Fixes: e54bcde3d69d ("arm64: eBPF JIT compiler") +Signed-off-by: Daniel Borkmann +Reviewed-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260415121403.639619-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index f11de7484ced8..9fd0b658e4602 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -33,8 +33,8 @@ + #define FP_BOTTOM (MAX_BPF_JIT_REG + 4) + + #define check_imm(bits, imm) do { \ +- if ((((imm) > 0) && ((imm) >> (bits))) || \ +- (((imm) < 0) && (~(imm) >> (bits)))) { \ ++ if ((((imm) > 0) && ((imm) >> ((bits) - 1))) || \ ++ (((imm) < 0) && (~(imm) >> ((bits) - 1)))) { \ + pr_info("[%2d] imm=%d(0x%x) out of range\n", \ + i, imm, imm); \ + return -EINVAL; \ +-- +2.53.0 + diff --git a/queue-6.6/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch b/queue-6.6/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch new file mode 100644 index 0000000000..0bd5ebc6b3 --- /dev/null +++ b/queue-6.6/bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch @@ -0,0 +1,46 @@ +From d37b6c26e60e7d2cc38e1eabf56e21de9f3ead28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 May 2024 12:19:01 +0200 +Subject: bpf, devmap: Remove unnecessary if check in for loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thorsten Blum + +[ Upstream commit 2317dc2c22cc353b699c7d1db47b2fe91f54055c ] + +The iterator variable dst cannot be NULL and the if check can be removed. +Remove it and fix the following Coccinelle/coccicheck warning reported +by itnull.cocci: + + ERROR: iterator variable bound on line 762 cannot be NULL + +Signed-off-by: Thorsten Blum +Signed-off-by: Daniel Borkmann +Reviewed-by: Toke Høiland-Jørgensen +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/bpf/20240529101900.103913-2-thorsten.blum@toblux.com +Stable-dep-of: 8ed82f807bb0 ("bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path") +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 3bdec239be610..3939221bd6098 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -765,9 +765,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_safe(dst, next, head, index_hlist) { +- if (!dst) +- continue; +- + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-6.6/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch b/queue-6.6/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch new file mode 100644 index 0000000000..37d6a26cf2 --- /dev/null +++ b/queue-6.6/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch @@ -0,0 +1,43 @@ +From 0c7cf3625373b10b8438dfaf83b485cf842651bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 20:23:33 +0800 +Subject: bpf: Drop task_to_inode and inet_conn_established from lsm sleepable + hooks + +From: Jiayuan Chen + +[ Upstream commit beaf0e96b1da74549a6cabd040f9667d83b2e97e ] + +bpf_lsm_task_to_inode() is called under rcu_read_lock() and +bpf_lsm_inet_conn_established() is called from softirq context, so +neither hook can be used by sleepable LSM programs. + +Fixes: 423f16108c9d8 ("bpf: Augment the set of sleepable LSM hooks") +Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/3ab69731-24d1-431a-a351-452aafaaf2a5@std.uestc.edu.cn/T/#u +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260407122334.344072-1-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_lsm.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c +index e14c822f8911c..92486a7b916e3 100644 +--- a/kernel/bpf/bpf_lsm.c ++++ b/kernel/bpf/bpf_lsm.c +@@ -340,7 +340,6 @@ BTF_ID(func, bpf_lsm_current_getsecid_subj) + BTF_ID(func, bpf_lsm_task_getsecid_obj) + BTF_ID(func, bpf_lsm_task_prctl) + BTF_ID(func, bpf_lsm_task_setscheduler) +-BTF_ID(func, bpf_lsm_task_to_inode) + BTF_ID(func, bpf_lsm_userns_create) + BTF_SET_END(sleepable_lsm_hooks) + +-- +2.53.0 + diff --git a/queue-6.6/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch b/queue-6.6/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch new file mode 100644 index 0000000000..742f693ea6 --- /dev/null +++ b/queue-6.6/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch @@ -0,0 +1,47 @@ +From 38e8d83d6b525f4b10102406b5ae02a2f000f940 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 21:29:50 +0800 +Subject: bpf: fix end-of-list detection in cgroup_storage_get_next_key() + +From: Weiming Shi + +[ Upstream commit 5828b9e5b272ecff7cf5d345128d3de7324117f7 ] + +list_next_entry() never returns NULL -- when the current element is the +last entry it wraps to the list head via container_of(). The subsequent +NULL check is therefore dead code and get_next_key() never returns +-ENOENT for the last element, instead reading storage->key from a bogus +pointer that aliases internal map fields and copying the result to +userspace. + +Replace it with list_entry_is_head() so the function correctly returns +-ENOENT when there are no more entries. + +Fixes: de9cbbaadba5 ("bpf: introduce cgroup storage maps") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Sun Jian +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260403132951.43533-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/local_storage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c +index a04f505aefe9b..c8b8dcc37ed4a 100644 +--- a/kernel/bpf/local_storage.c ++++ b/kernel/bpf/local_storage.c +@@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, + goto enoent; + + storage = list_next_entry(storage, list_map); +- if (!storage) ++ if (list_entry_is_head(storage, &map->list, list_map)) + goto enoent; + } else { + storage = list_first_entry(&map->list, +-- +2.53.0 + diff --git a/queue-6.6/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch b/queue-6.6/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch new file mode 100644 index 0000000000..65cda2355b --- /dev/null +++ b/queue-6.6/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch @@ -0,0 +1,56 @@ +From 6a3fa2866a7d033c1da5879a6e7bd9bbd8504ce6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 11:08:07 -0700 +Subject: bpf: Fix NULL deref in map_kptr_match_type for scalar regs + +From: Mykyta Yatsenko + +[ Upstream commit 4d0a375887ab4d49e4da1ff10f9606cab8f7c3ad ] + +Commit ab6c637ad027 ("bpf: Fix a bpf_kptr_xchg() issue with local +kptr") refactored map_kptr_match_type() to branch on btf_is_kernel() +before checking base_type(). A scalar register stored into a kptr +slot has no btf, so the btf_is_kernel(reg->btf) call dereferences +NULL. + +Move the base_type() != PTR_TO_BTF_ID guard before any reg->btf +access. + +Fixes: ab6c637ad027 ("bpf: Fix a bpf_kptr_xchg() issue with local kptr") +Reported-by: Hiker Cl +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221372 +Signed-off-by: Mykyta Yatsenko +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416-kptr_crash-v1-1-5589356584b4@meta.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index b7fd3995538bf..0d90236d0ad94 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5336,6 +5336,9 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + int perm_flags; + const char *reg_name = ""; + ++ if (base_type(reg->type) != PTR_TO_BTF_ID) ++ goto bad_type; ++ + if (btf_is_kernel(reg->btf)) { + perm_flags = PTR_MAYBE_NULL | PTR_TRUSTED | MEM_RCU; + +@@ -5346,7 +5349,7 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + perm_flags = PTR_MAYBE_NULL | MEM_ALLOC; + } + +- if (base_type(reg->type) != PTR_TO_BTF_ID || (type_flag(reg->type) & ~perm_flags)) ++ if (type_flag(reg->type) & ~perm_flags) + goto bad_type; + + /* We need to verify reg->type and reg->btf, before accessing reg->btf */ +-- +2.53.0 + diff --git a/queue-6.6/bpf-fix-oob-in-pcpu_init_value.patch b/queue-6.6/bpf-fix-oob-in-pcpu_init_value.patch new file mode 100644 index 0000000000..f981f0e93d --- /dev/null +++ b/queue-6.6/bpf-fix-oob-in-pcpu_init_value.patch @@ -0,0 +1,54 @@ +From 66f6a14b76fd1f36bd111cd32706220ae1d71c74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 15:42:35 +0800 +Subject: bpf: Fix OOB in pcpu_init_value + +From: Lang Xu + +[ Upstream commit 576afddfee8d1108ee299bf10f581593540d1a36 ] + +An out-of-bounds read occurs when copying element from a +BPF_MAP_TYPE_CGROUP_STORAGE map to another pcpu map with the +same value_size that is not rounded up to 8 bytes. + +The issue happens when: +1. A CGROUP_STORAGE map is created with value_size not aligned to + 8 bytes (e.g., 4 bytes) +2. A pcpu map is created with the same value_size (e.g., 4 bytes) +3. Update element in 2 with data in 1 + +pcpu_init_value assumes that all sources are rounded up to 8 bytes, +and invokes copy_map_value_long to make a data copy, However, the +assumption doesn't stand since there are some cases where the source +may not be rounded up to 8 bytes, e.g., CGROUP_STORAGE, skb->data. +the verifier verifies exactly the size that the source claims, not +the size rounded up to 8 bytes by kernel, an OOB happens when the +source has only 4 bytes while the copy size(4) is rounded up to 8. + +Fixes: d3bec0138bfb ("bpf: Zero-fill re-used per-cpu map element") +Reported-by: Kaiyan Mei +Closes: https://lore.kernel.org/all/14e6c70c.6c121.19c0399d948.Coremail.kaiyanm@hust.edu.cn/ +Link: https://lore.kernel.org/r/420FEEDDC768A4BE+20260402074236.2187154-1-xulang@uniontech.com +Signed-off-by: Lang Xu +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/hashtab.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c +index 8bac6ae1204dc..934fdc688d7c1 100644 +--- a/kernel/bpf/hashtab.c ++++ b/kernel/bpf/hashtab.c +@@ -991,7 +991,7 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr, + + for_each_possible_cpu(cpu) { + if (cpu == current_cpu) +- copy_map_value_long(&htab->map, per_cpu_ptr(pptr, cpu), value); ++ copy_map_value(&htab->map, per_cpu_ptr(pptr, cpu), value); + else /* Since elem is preallocated, we cannot touch special fields */ + zero_map_value(&htab->map, per_cpu_ptr(pptr, cpu)); + } +-- +2.53.0 + diff --git a/queue-6.6/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch b/queue-6.6/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch new file mode 100644 index 0000000000..a920d33794 --- /dev/null +++ b/queue-6.6/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch @@ -0,0 +1,46 @@ +From 8866a7699428ccd9718d02eccb3b3b4c43a695ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:27:19 +0200 +Subject: bpf: Fix precedence bug in convert_bpf_ld_abs alignment check + +From: Daniel Borkmann + +[ Upstream commit e5f635edd393aeaa7cad9e42831d397e6e2e1eed ] + +Fix an operator precedence issue in convert_bpf_ld_abs() where the +expression offset + ip_align % size evaluates as offset + (ip_align % size) +due to % having higher precedence than +. That latter evaluation does +not make any sense. The intended check is (offset + ip_align) % size == 0 +to verify that the packet load offset is properly aligned for direct +access. + +With NET_IP_ALIGN == 2, the bug causes the inline fast-path for direct +packet loads to almost never be taken on !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +platforms. This forces nearly all cBPF BPF_LD_ABS packet loads through +the bpf_skb_load_helper slow path on the affected archs. + +Fixes: e0cea7ce988c ("bpf: implement ld_abs/ld_ind in native bpf") +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260416122719.661033-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index c24510037334c..371f4e789998d 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -492,7 +492,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp) + ((unaligned_ok && offset >= 0) || + (!unaligned_ok && offset >= 0 && + offset + ip_align >= 0 && +- offset + ip_align % size == 0))) { ++ (offset + ip_align) % size == 0))) { + bool ldx_off_ok = offset <= S16_MAX; + + *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H); +-- +2.53.0 + diff --git a/queue-6.6/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch b/queue-6.6/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch new file mode 100644 index 0000000000..eb05f41191 --- /dev/null +++ b/queue-6.6/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch @@ -0,0 +1,62 @@ +From bcad4d74064d8ca7fc4a6970f67606834e084626 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 10:38:23 +0000 +Subject: bpf: Fix RCU stall in bpf_fd_array_map_clear() + +From: Sechang Lim + +[ Upstream commit 4406942e65ca128c56c67443832988873c21d2e9 ] + +Add a missing cond_resched() in bpf_fd_array_map_clear() loop. + +For PROG_ARRAY maps with many entries this loop calls +prog_array_map_poke_run() per entry which can be expensive, and +without yielding this can cause RCU stalls under load: + + rcu: Stack dump where RCU GP kthread last ran: + CPU: 0 UID: 0 PID: 30932 Comm: kworker/0:2 Not tainted 6.14.0-13195-g967e8def1100 #2 PREEMPT(undef) + Workqueue: events prog_array_map_clear_deferred + RIP: 0010:write_comp_data+0x38/0x90 kernel/kcov.c:246 + Call Trace: + + prog_array_map_poke_run+0x77/0x380 kernel/bpf/arraymap.c:1096 + __fd_array_map_delete_elem+0x197/0x310 kernel/bpf/arraymap.c:925 + bpf_fd_array_map_clear kernel/bpf/arraymap.c:1000 [inline] + prog_array_map_clear_deferred+0x119/0x1b0 kernel/bpf/arraymap.c:1141 + process_one_work+0x898/0x19d0 kernel/workqueue.c:3238 + process_scheduled_works kernel/workqueue.c:3319 [inline] + worker_thread+0x770/0x10b0 kernel/workqueue.c:3400 + kthread+0x465/0x880 kernel/kthread.c:464 + ret_from_fork+0x4d/0x80 arch/x86/kernel/process.c:153 + ret_from_fork_asm+0x19/0x30 arch/x86/entry/entry_64.S:245 + + +Reviewed-by: Sun Jian +Fixes: da765a2f5993 ("bpf: Add poke dependency tracking for prog array maps") +Signed-off-by: Sechang Lim +Link: https://lore.kernel.org/r/20260407103823.3942156-1-rhkrqnwk98@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/arraymap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c +index 1811efcfbd6e3..ec5c489ed3131 100644 +--- a/kernel/bpf/arraymap.c ++++ b/kernel/bpf/arraymap.c +@@ -938,8 +938,10 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer) + struct bpf_array *array = container_of(map, struct bpf_array, map); + int i; + +- for (i = 0; i < array->map.max_entries; i++) ++ for (i = 0; i < array->map.max_entries; i++) { + __fd_array_map_delete_elem(map, &i, need_defer); ++ cond_resched(); ++ } + } + + static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key, +-- +2.53.0 + diff --git a/queue-6.6/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch b/queue-6.6/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch new file mode 100644 index 0000000000..bcee4ee9d1 --- /dev/null +++ b/queue-6.6/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch @@ -0,0 +1,72 @@ +From 7ee8e7bb0f394cc393a87ff53b45f90ca42082ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:18:50 +0800 +Subject: bpf: Fix stale offload->prog pointer after constant blinding + +From: MingTao Huang + +[ Upstream commit a1aa9ef47c299c5bbc30594d3c2f0589edf908e6 ] + +When a dev-bound-only BPF program (BPF_F_XDP_DEV_BOUND_ONLY) undergoes +JIT compilation with constant blinding enabled (bpf_jit_harden >= 2), +bpf_jit_blind_constants() clones the program. The original prog is then +freed in bpf_jit_prog_release_other(), which updates aux->prog to point +to the surviving clone, but fails to update offload->prog. + +This leaves offload->prog pointing to the freed original program. When +the network namespace is subsequently destroyed, cleanup_net() triggers +bpf_dev_bound_netdev_unregister(), which iterates ondev->progs and calls +__bpf_prog_offload_destroy(offload->prog). Accessing the freed prog +causes a page fault: + +BUG: unable to handle page fault for address: ffffc900085f1038 +Workqueue: netns cleanup_net +RIP: 0010:__bpf_prog_offload_destroy+0xc/0x80 +Call Trace: +__bpf_offload_dev_netdev_unregister+0x257/0x350 +bpf_dev_bound_netdev_unregister+0x4a/0x90 +unregister_netdevice_many_notify+0x2a2/0x660 +... +cleanup_net+0x21a/0x320 + +The test sequence that triggers this reliably is: + +1. Set net.core.bpf_jit_harden=2 (echo 2 > /proc/sys/net/core/bpf_jit_harden) +2. Run xdp_metadata selftest, which creates a dev-bound-only XDP + program on a veth inside a netns (./test_progs -t xdp_metadata) +3. cleanup_net -> page fault in __bpf_prog_offload_destroy + +Dev-bound-only programs are unique in that they have an offload structure +but go through the normal JIT path instead of bpf_prog_offload_compile(). +This means they are subject to constant blinding's prog clone-and-replace, +while also having offload->prog that must stay in sync. + +Fix this by updating offload->prog in bpf_jit_prog_release_other(), +alongside the existing aux->prog update. Both are back-pointers to +the prog that must be kept in sync when the prog is replaced. + +Fixes: 2b3486bc2d23 ("bpf: Introduce device-bound XDP programs") +Signed-off-by: MingTao Huang +Link: https://lore.kernel.org/r/tencent_BCF692F45859CCE6C22B7B0B64827947D406@qq.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 3011add7c4a88..d708cf3e6207f 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1422,6 +1422,8 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other) + * know whether fp here is the clone or the original. + */ + fp->aux->prog = fp; ++ if (fp->aux->offload) ++ fp->aux->offload->prog = fp; + bpf_prog_clone_free(fp_other); + } + +-- +2.53.0 + diff --git a/queue-6.6/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch b/queue-6.6/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch new file mode 100644 index 0000000000..4e3f0d2283 --- /dev/null +++ b/queue-6.6/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch @@ -0,0 +1,74 @@ +From 42a793b0c4588753b2088ab82888709d03056973 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 00:12:20 +0800 +Subject: bpf: reject negative CO-RE accessor indices in bpf_core_parse_spec() + +From: Weiming Shi + +[ Upstream commit 1c22483a2c4bbf747787f328392ca3e68619c4dc ] + +CO-RE accessor strings are colon-separated indices that describe a path +from a root BTF type to a target field, e.g. "0:1:2" walks through +nested struct members. bpf_core_parse_spec() parses each component with +sscanf("%d"), so negative values like -1 are silently accepted. The +subsequent bounds checks (access_idx >= btf_vlen(t)) only guard the +upper bound and always pass for negative values because C integer +promotion converts the __u16 btf_vlen result to int, making the +comparison (int)(-1) >= (int)(N) false for any positive N. + +When -1 reaches btf_member_bit_offset() it gets cast to u32 0xffffffff, +producing an out-of-bounds read far past the members array. A crafted +BPF program with a negative CO-RE accessor on any struct that exists in +vmlinux BTF (e.g. task_struct) crashes the kernel deterministically +during BPF_PROG_LOAD on any system with CONFIG_DEBUG_INFO_BTF=y +(default on major distributions). The bug is reachable with CAP_BPF: + + BUG: unable to handle page fault for address: ffffed11818b6626 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + Oops: Oops: 0000 [#1] SMP KASAN NOPTI + CPU: 0 UID: 0 PID: 85 Comm: poc Not tainted 7.0.0-rc6 #18 PREEMPT(full) + RIP: 0010:bpf_core_parse_spec (tools/lib/bpf/relo_core.c:354) + RAX: 00000000ffffffff + Call Trace: + + bpf_core_calc_relo_insn (tools/lib/bpf/relo_core.c:1321) + bpf_core_apply (kernel/bpf/btf.c:9507) + check_core_relo (kernel/bpf/verifier.c:19475) + bpf_check (kernel/bpf/verifier.c:26031) + bpf_prog_load (kernel/bpf/syscall.c:3089) + __sys_bpf (kernel/bpf/syscall.c:6228) + + +CO-RE accessor indices are inherently non-negative (struct member index, +array element index, or enumerator index), so reject them immediately +after parsing. + +Fixes: ddc7c3042614 ("libbpf: implement BPF CO-RE offset relocation algorithm") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Emil Tsalapatis +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260404161221.961828-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/relo_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c +index 63a4d5ad12d1a..04c8febfc0aa7 100644 +--- a/tools/lib/bpf/relo_core.c ++++ b/tools/lib/bpf/relo_core.c +@@ -293,6 +293,8 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf, + ++spec_str; + if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1) + return -EINVAL; ++ if (access_idx < 0) ++ return -EINVAL; + if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) + return -E2BIG; + spec_str += parsed_len; +-- +2.53.0 + diff --git a/queue-6.6/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch b/queue-6.6/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch new file mode 100644 index 0000000000..c9bb122899 --- /dev/null +++ b/queue-6.6/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch @@ -0,0 +1,72 @@ +From 79522c907b4a01a5fbbda6de69ca6158b7681a51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 11:46:22 +0800 +Subject: bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb + +From: Sun Jian + +[ Upstream commit 12bec2bd4b76d81c5d3996bd14ec1b7f4d983747 ] + +bpf_prog_test_run_skb() calls eth_type_trans() first and then uses +skb->protocol to initialize sk family and address fields for the test +run. + +For IPv4 and IPv6 packets, it may access ip_hdr(skb) or ipv6_hdr(skb) +even when the provided test input only contains an Ethernet header. + +Reject the input earlier if the Ethernet frame carries IPv4/IPv6 +EtherType but the L3 header is too short. + +Fold the IPv4/IPv6 header length checks into the existing protocol +switch and return -EINVAL before accessing the network headers. + +Fixes: fa5cb548ced6 ("bpf: Setup socket family and addresses in bpf_prog_test_run_skb") +Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc +Signed-off-by: Sun Jian +Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index c9c6f675d8e21..8e665cee22503 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1031,19 +1031,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + switch (skb->protocol) { + case htons(ETH_P_IP): +- sk->sk_family = AF_INET; +- if (sizeof(struct iphdr) <= skb_headlen(skb)) { +- sk->sk_rcv_saddr = ip_hdr(skb)->saddr; +- sk->sk_daddr = ip_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct iphdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET; ++ sk->sk_rcv_saddr = ip_hdr(skb)->saddr; ++ sk->sk_daddr = ip_hdr(skb)->daddr; + break; + #if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +- sk->sk_family = AF_INET6; +- if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { +- sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; +- sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET6; ++ sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; ++ sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + break; + #endif + default: +-- +2.53.0 + diff --git a/queue-6.6/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch b/queue-6.6/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch new file mode 100644 index 0000000000..3c3abd7501 --- /dev/null +++ b/queue-6.6/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch @@ -0,0 +1,82 @@ +From 6023208edd50de03f11dc6283e02f0543a4349d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:11:09 -0700 +Subject: bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator + finalize + +From: Puranjay Mohan + +[ Upstream commit 46ee1342b887c9387a933397d846ff6c9584322c ] + +bpf_flush_icache() calls flush_icache_range() to clean the data cache +and invalidate the instruction cache for the JITed code region. However, +since commit 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the +BPF JIT"), this flush is redundant. + +bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX +region via bpf_arch_text_copy() -> patch_text_nosync(), and +patch_text_nosync() already calls flush_icache_range() on the written +range. The subsequent bpf_flush_icache() repeats the same cache +maintenance on an overlapping range. + +Remove the redundant bpf_flush_icache() call and its now-unused +definition. + +Fixes: 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT") +Acked-by: Song Liu +Signed-off-by: Puranjay Mohan +Reviewed-by: Pu Lehui +Tested-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260413191111.3426023-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/riscv/net/bpf_jit.h | 6 ------ + arch/riscv/net/bpf_jit_core.c | 7 ------- + 2 files changed, 13 deletions(-) + +diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h +index a5ce1ab76ecee..c444c79596703 100644 +--- a/arch/riscv/net/bpf_jit.h ++++ b/arch/riscv/net/bpf_jit.h +@@ -11,7 +11,6 @@ + + #include + #include +-#include + + static inline bool rvc_enabled(void) + { +@@ -97,11 +96,6 @@ static inline void bpf_fill_ill_insns(void *area, unsigned int size) + memset(area, 0, size); + } + +-static inline void bpf_flush_icache(void *start, void *end) +-{ +- flush_icache_range((unsigned long)start, (unsigned long)end); +-} +- + /* Emit a 4-byte riscv instruction. */ + static inline void emit(const u32 insn, struct rv_jit_context *ctx) + { +diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c +index 7b70ccb7fec34..f57b95e830ac0 100644 +--- a/arch/riscv/net/bpf_jit_core.c ++++ b/arch/riscv/net/bpf_jit_core.c +@@ -182,13 +182,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + prog = orig_prog; + goto out_offset; + } +- /* +- * The instructions have now been copied to the ROX region from +- * where they will execute. +- * Write any modified data cache blocks out to memory and +- * invalidate the corresponding blocks in the instruction cache. +- */ +- bpf_flush_icache(jit_data->ro_header, ctx->ro_insns + ctx->ninsns); + for (i = 0; i < prog->len; i++) + ctx->offset[i] = ninsns_rvoff(ctx->offset[i]); + bpf_prog_fill_jited_linfo(prog, ctx->offset); +-- +2.53.0 + diff --git a/queue-6.6/bpf-sockmap-fix-af_unix-iter-deadlock.patch b/queue-6.6/bpf-sockmap-fix-af_unix-iter-deadlock.patch new file mode 100644 index 0000000000..1b5f48453e --- /dev/null +++ b/queue-6.6/bpf-sockmap-fix-af_unix-iter-deadlock.patch @@ -0,0 +1,101 @@ +From ba46be8d6367984197c89bcb6e8da28125c19a80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:16 +0200 +Subject: bpf, sockmap: Fix af_unix iter deadlock + +From: Michal Luczaj + +[ Upstream commit 4d328dd695383224aa750ddee6b4ad40c0f8d205 ] + +bpf_iter_unix_seq_show() may deadlock when lock_sock_fast() takes the fast +path and the iter prog attempts to update a sockmap. Which ends up spinning +at sock_map_update_elem()'s bh_lock_sock(): + +WARNING: possible recursive locking detected +test_progs/1393 is trying to acquire lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: sock_map_update_elem+0xdb/0x1f0 + +but task is already holding lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + +other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(slock-AF_UNIX); + lock(slock-AF_UNIX); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + +4 locks held by test_progs/1393: + #0: ffff88814b59c790 (&p->lock){+.+.}-{4:4}, at: bpf_seq_read+0x59/0x10d0 + #1: ffff88811ec25fd8 (sk_lock-AF_UNIX){+.+.}-{0:0}, at: bpf_seq_read+0x42c/0x10d0 + #2: ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + #3: ffffffff85a6a7c0 (rcu_read_lock){....}-{1:3}, at: bpf_iter_run_prog+0x51d/0xb00 + +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_deadlock_bug.cold+0xc0/0xce + __lock_acquire+0x130f/0x2590 + lock_acquire+0x14e/0x2b0 + _raw_spin_lock+0x30/0x40 + sock_map_update_elem+0xdb/0x1f0 + bpf_prog_2d0075e5d9b721cd_dump_unix+0x55/0x4f4 + bpf_iter_run_prog+0x5b9/0xb00 + bpf_iter_unix_seq_show+0x1f7/0x2e0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-2-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 651c7debe799d..8bf6c2b7215e8 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3561,15 +3561,14 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + struct bpf_prog *prog; + struct sock *sk = v; + uid_t uid; +- bool slow; + int ret; + + if (v == SEQ_START_TOKEN) + return 0; + +- slow = lock_sock_fast(sk); ++ lock_sock(sk); + +- if (unlikely(sk_unhashed(sk))) { ++ if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; + goto unlock; + } +@@ -3579,7 +3578,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: +- unlock_sock_fast(sk, slow); ++ release_sock(sk); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.6/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch b/queue-6.6/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch new file mode 100644 index 0000000000..d4a7e2a4c6 --- /dev/null +++ b/queue-6.6/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch @@ -0,0 +1,200 @@ +From 7b19e64134daf8cb421370349772ea049618e8c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:18 +0200 +Subject: bpf, sockmap: Fix af_unix null-ptr-deref in proto update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Luczaj + +[ Upstream commit dca38b7734d2ea00af4818ff3ae836fab33d5d5a ] + +unix_stream_connect() sets sk_state (`WRITE_ONCE(sk->sk_state, +TCP_ESTABLISHED)`) _before_ it assigns a peer (`unix_peer(sk) = newsk`). +sk_state == TCP_ESTABLISHED makes sock_map_sk_state_allowed() believe that +socket is properly set up, which would include having a defined peer. IOW, +there's a window when unix_stream_bpf_update_proto() can be called on +socket which still has unix_peer(sk) == NULL. + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) +sock_map_sk_state_allowed(sk) +... +sk_pair = unix_peer(sk) +sock_hold(sk_pair) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + +BUG: kernel NULL pointer dereference, address: 0000000000000080 +RIP: 0010:unix_stream_bpf_update_proto+0xa0/0x1b0 +Call Trace: + sock_map_link+0x564/0x8b0 + sock_map_update_common+0x6e/0x340 + sock_map_update_elem_sys+0x17d/0x240 + __sys_bpf+0x26db/0x3250 + __x64_sys_bpf+0x21/0x30 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Initial idea was to move peer assignment _before_ the sk_state update[1], +but that involved an additional memory barrier, and changing the hot path +was rejected. +Then a NULL check during proto update in unix_stream_bpf_update_proto() was +considered[2], but the follow-up discussion[3] focused on the root cause, +i.e. sockmap update taking a wrong lock. Or, more specifically, missing +unix_state_lock()[4]. +In the end it was concluded that teaching sockmap about the af_unix locking +would be unnecessarily complex[5]. +Complexity aside, since BPF_PROG_TYPE_SCHED_CLS and BPF_PROG_TYPE_SCHED_ACT +are allowed to update sockmaps, sock_map_update_elem() taking the unix +lock, as it is currently implemented in unix_state_lock(): +spin_lock(&unix_sk(s)->lock), would be problematic. unix_state_lock() taken +in a process context, followed by a softirq-context TC BPF program +attempting to take the same spinlock -- deadlock[6]. +This way we circled back to the peer check idea[2]. + +[1]: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +[2]: https://lore.kernel.org/netdev/20240610174906.32921-1-kuniyu@amazon.com/ +[3]: https://lore.kernel.org/netdev/7603c0e6-cd5b-452b-b710-73b64bd9de26@linux.dev/ +[4]: https://lore.kernel.org/netdev/CAAVpQUA+8GL_j63CaKb8hbxoL21izD58yr1NvhOhU=j+35+3og@mail.gmail.com/ +[5]: https://lore.kernel.org/bpf/CAAVpQUAHijOMext28Gi10dSLuMzGYh+jK61Ujn+fZ-wvcODR2A@mail.gmail.com/ +[6]: https://lore.kernel.org/bpf/dd043c69-4d03-46fe-8325-8f97101435cf@linux.dev/ + +Summary of scenarios where af_unix/stream connect() may race a sockmap +update: + +1. connect() vs. bpf(BPF_MAP_UPDATE_ELEM), i.e. sock_map_update_elem_sys() + + Implemented NULL check is sufficient. Once assigned, socket peer won't + be released until socket fd is released. And that's not an issue because + sock_map_update_elem_sys() bumps fd refcnf. + +2. connect() vs BPF program doing update + + Update restricted per verifier.c:may_update_sockmap() to + + BPF_PROG_TYPE_TRACING/BPF_TRACE_ITER + BPF_PROG_TYPE_SOCK_OPS (bpf_sock_map_update() only) + BPF_PROG_TYPE_SOCKET_FILTER + BPF_PROG_TYPE_SCHED_CLS + BPF_PROG_TYPE_SCHED_ACT + BPF_PROG_TYPE_XDP + BPF_PROG_TYPE_SK_REUSEPORT + BPF_PROG_TYPE_FLOW_DISSECTOR + BPF_PROG_TYPE_SK_LOOKUP + + Plus one more race to consider: + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) + sock_map_sk_state_allowed(sk) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + sk_pair = unix_peer(sk) + if (unlikely(!sk_pair)) + return -EINVAL; + + CPU1 close + ---------- + + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) + // use after free? + sock_hold(sk_pair) + + 2.1 BPF program invoking helper function bpf_sock_map_update() -> + BPF_CALL_4(bpf_sock_map_update(), ...) + + Helper limited to BPF_PROG_TYPE_SOCK_OPS. Nevertheless, a unix sock + might be accessible via bpf_map_lookup_elem(). Which implies sk + already having psock, which in turn implies sk already having + sk_pair. Since sk_psock_destroy() is queued as RCU work, sk_pair + won't go away while BPF executes the update. + + 2.2 BPF program invoking helper function bpf_map_update_elem() -> + sock_map_update_elem() + + 2.2.1 Unix sock accessible to BPF prog only via sockmap lookup in + BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_SK_REUSEPORT, BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_SK_LOOKUP. + + Pretty much the same as case 2.1. + + 2.2.2 Unix sock accessible to BPF program directly: + BPF_PROG_TYPE_TRACING, narrowed down to BPF_TRACE_ITER. + + Sockmap iterator (sock_map_seq_ops) is safe: unix sock + residing in a sockmap means that the sock already went through + the proto update step. + + Unix sock iterator (bpf_iter_unix_seq_ops), on the other hand, + gives access to socks that may still be unconnected. Which + means iterator prog can race sockmap/proto update against + connect(). + + BUG: KASAN: null-ptr-deref in unix_stream_bpf_update_proto+0x253/0x4d0 + Write of size 4 at addr 0000000000000080 by task test_progs/3140 + Call Trace: + dump_stack_lvl+0x5d/0x80 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x253/0x4d0 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + While the introduced NULL check prevents null-ptr-deref in the + BPF program path as well, it is insufficient to guard against + a poorly timed close() leading to a use-after-free. This will + be addressed in a subsequent patch. + +Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()") +Closes: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +Reported-by: Michal Luczaj +Reported-by: 钱一铭 +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-4-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/unix_bpf.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c +index bca2d86ba97d8..976e035053e5a 100644 +--- a/net/unix/unix_bpf.c ++++ b/net/unix/unix_bpf.c +@@ -184,6 +184,9 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r + */ + if (!psock->sk_pair) { + sk_pair = unix_peer(sk); ++ if (unlikely(!sk_pair)) ++ return -EINVAL; ++ + sock_hold(sk_pair); + psock->sk_pair = sk_pair; + } +-- +2.53.0 + diff --git a/queue-6.6/bpf-sockmap-take-state-lock-for-af_unix-iter.patch b/queue-6.6/bpf-sockmap-take-state-lock-for-af_unix-iter.patch new file mode 100644 index 0000000000..d5c2dd1941 --- /dev/null +++ b/queue-6.6/bpf-sockmap-take-state-lock-for-af_unix-iter.patch @@ -0,0 +1,115 @@ +From 318ed323581a282acb154fdf7ba6e2561152cbc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:19 +0200 +Subject: bpf, sockmap: Take state lock for af_unix iter + +From: Michal Luczaj + +[ Upstream commit 64c2f93fc3254d3bf5de4445fb732ee5c451edb6 ] + +When a BPF iterator program updates a sockmap, there is a race condition in +unix_stream_bpf_update_proto() where the `peer` pointer can become stale[1] +during a state transition TCP_ESTABLISHED -> TCP_CLOSE. + + CPU0 bpf CPU1 close + -------- ---------- +// unix_stream_bpf_update_proto() +sk_pair = unix_peer(sk) +if (unlikely(!sk_pair)) + return -EINVAL; + // unix_release_sock() + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) +sock_hold(sk_pair) // UaF + +More practically, this fix guarantees that the iterator program is +consistently provided with a unix socket that remains stable during +iterator execution. + +[1]: +BUG: KASAN: slab-use-after-free in unix_stream_bpf_update_proto+0x155/0x490 +Write of size 4 at addr ffff8881178c9a00 by task test_progs/2231 +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x170/0x4f3 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x155/0x490 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Allocated by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + __kasan_slab_alloc+0x63/0x80 + kmem_cache_alloc_noprof+0x1d5/0x680 + sk_prot_alloc+0x59/0x210 + sk_alloc+0x34/0x470 + unix_create1+0x86/0x8a0 + unix_stream_connect+0x318/0x15b0 + __sys_connect+0xfd/0x130 + __x64_sys_connect+0x72/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Freed by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + kasan_save_free_info+0x3b/0x70 + __kasan_slab_free+0x47/0x70 + kmem_cache_free+0x11c/0x590 + __sk_destruct+0x432/0x6e0 + unix_release_sock+0x9b3/0xf60 + unix_release+0x8a/0xf0 + __sock_release+0xb0/0x270 + sock_close+0x18/0x20 + __fput+0x36e/0xac0 + fput_close_sync+0xe5/0x1a0 + __x64_sys_close+0x7d/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-5-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 8bf6c2b7215e8..87908ae74efb3 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3567,6 +3567,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + return 0; + + lock_sock(sk); ++ unix_state_lock(sk); + + if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; +@@ -3578,6 +3579,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: ++ unix_state_unlock(sk); + release_sock(sk); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.6/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch b/queue-6.6/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch new file mode 100644 index 0000000000..13e728cc99 --- /dev/null +++ b/queue-6.6/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch @@ -0,0 +1,100 @@ +From 716231ac2f7777740540c6e35a709cccdf973738 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 17:44:28 +0800 +Subject: bpf: test_run: Fix the null pointer dereference issue in + bpf_lwt_xmit_push_encap + +From: Feng Yang + +[ Upstream commit 972787479ee73006fddb5e59ab5c8e733810ff42 ] + +The bpf_lwt_xmit_push_encap helper needs to access skb_dst(skb)->dev to +calculate the needed headroom: + + err = skb_cow_head(skb, + len + LL_RESERVED_SPACE(skb_dst(skb)->dev)); + +But skb->_skb_refdst may not be initialized when the skb is set up by +bpf_prog_test_run_skb function. Executing bpf_lwt_push_ip_encap function +in this scenario will trigger null pointer dereference, causing a kernel +crash as Yinhao reported: + +[ 105.186365] BUG: kernel NULL pointer dereference, address: 0000000000000000 +[ 105.186382] #PF: supervisor read access in kernel mode +[ 105.186388] #PF: error_code(0x0000) - not-present page +[ 105.186393] PGD 121d3d067 P4D 121d3d067 PUD 106c83067 PMD 0 +[ 105.186404] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 105.186412] CPU: 3 PID: 3250 Comm: poc Kdump: loaded Not tainted 6.19.0-rc5 #1 +[ 105.186423] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 105.186427] RIP: 0010:bpf_lwt_push_ip_encap+0x1eb/0x520 +[ 105.186443] Code: 0f 84 de 01 00 00 0f b7 4a 04 66 85 c9 0f 85 47 01 00 00 31 c0 5b 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8b 73 58 48 83 e6 fe <48> 8b 36 0f b7 be ec 00 00 00 0f b7 b6 e6 00 00 00 01 fe 83 e6 f0 +[ 105.186449] RSP: 0018:ffffbb0e0387bc50 EFLAGS: 00010246 +[ 105.186455] RAX: 000000000000004e RBX: ffff94c74e036500 RCX: ffff94c74874da00 +[ 105.186460] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff94c74e036500 +[ 105.186463] RBP: 0000000000000001 R08: 0000000000000002 R09: 0000000000000000 +[ 105.186467] R10: ffffbb0e0387bd50 R11: 0000000000000000 R12: ffffbb0e0387bc98 +[ 105.186471] R13: 0000000000000014 R14: 0000000000000000 R15: 0000000000000002 +[ 105.186484] FS: 00007f166aa4d680(0000) GS:ffff94c8b7780000(0000) knlGS:0000000000000000 +[ 105.186490] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 105.186494] CR2: 0000000000000000 CR3: 000000015eade001 CR4: 0000000000770ee0 +[ 105.186499] PKRU: 55555554 +[ 105.186502] Call Trace: +[ 105.186507] +[ 105.186513] bpf_lwt_xmit_push_encap+0x2b/0x40 +[ 105.186522] bpf_prog_a75eaad51e517912+0x41/0x49 +[ 105.186536] ? kvm_clock_get_cycles+0x18/0x30 +[ 105.186547] ? ktime_get+0x3c/0xa0 +[ 105.186554] bpf_test_run+0x195/0x320 +[ 105.186563] ? bpf_test_run+0x10f/0x320 +[ 105.186579] bpf_prog_test_run_skb+0x2f5/0x4f0 +[ 105.186590] __sys_bpf+0x69c/0xa40 +[ 105.186603] __x64_sys_bpf+0x1e/0x30 +[ 105.186611] do_syscall_64+0x59/0x110 +[ 105.186620] entry_SYSCALL_64_after_hwframe+0x76/0xe0 +[ 105.186649] RIP: 0033:0x7f166a97455d + +Temporarily add the setting of skb->_skb_refdst before bpf_test_run to resolve the issue. + +Fixes: 52f278774e79 ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap") +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Closes: https://groups.google.com/g/hust-os-kernel-patches/c/8-a0kPpBW2s +Signed-off-by: Yun Lu +Signed-off-by: Feng Yang +Signed-off-by: Martin KaFai Lau +Tested-by: syzbot@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260304094429.168521-2-yangfeng59949@163.com +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 774287ac17955..c9c6f675d8e21 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1067,6 +1067,21 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + skb->ip_summed = CHECKSUM_COMPLETE; + } + ++ if (prog->type == BPF_PROG_TYPE_LWT_XMIT) { ++ if (!ipv6_bpf_stub) { ++ pr_warn_once("Please test this program with the IPv6 module loaded\n"); ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ /* For CONFIG_IPV6=n, ipv6_bpf_stub is NULL which is ++ * handled by the above if statement. ++ */ ++ dst_hold(&net->ipv6.ip6_null_entry->dst); ++ skb_dst_set(skb, &net->ipv6.ip6_null_entry->dst); ++#endif ++ } ++ + ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false); + if (ret) + goto out; +-- +2.53.0 + diff --git a/queue-6.6/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch b/queue-6.6/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch new file mode 100644 index 0000000000..0d38473281 --- /dev/null +++ b/queue-6.6/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch @@ -0,0 +1,71 @@ +From bd57d277342bd641169a394034692bcfb83ade8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 07:26:45 +0000 +Subject: bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path + +From: David Carlier + +[ Upstream commit 8ed82f807bb09d2c8455aaa665f2c6cb17bc6a19 ] + +The DEVMAP_HASH branch in dev_map_redirect_multi() uses +hlist_for_each_entry_safe() to iterate hash buckets, but this function +runs under RCU protection (called from xdp_do_generic_redirect_map() +in softirq context). Concurrent writers (__dev_map_hash_update_elem, +dev_map_hash_delete_elem) modify the list using RCU primitives +(hlist_add_head_rcu, hlist_del_rcu). + +hlist_for_each_entry_safe() performs plain pointer dereferences without +rcu_dereference(), missing the acquire barrier needed to pair with +writers' rcu_assign_pointer(). On weakly-ordered architectures (ARM64, +POWER), a reader can observe a partially-constructed node. It also +defeats CONFIG_PROVE_RCU lockdep validation and KCSAN data-race +detection. + +Replace with hlist_for_each_entry_rcu() using rcu_read_lock_bh_held() +as the lockdep condition, consistent with the rcu_dereference_check() +used in the DEVMAP (non-hash) branch of the same functions. Also fix +the same incorrect lockdep_is_held(&dtab->index_lock) condition in +dev_map_enqueue_multi(), where the lock is not held either. + +Fixes: e624d4ed4aa8 ("xdp: Extend xdp_redirect_map with broadcast support") +Signed-off-by: David Carlier +Signed-off-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260320072645.16731-1-devnexen@gmail.com +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 3939221bd6098..c169f0624e100 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -642,7 +642,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_rcu(dst, head, index_hlist, +- lockdep_is_held(&dtab->index_lock)) { ++ rcu_read_lock_bh_held()) { + if (!is_valid_dst(dst, xdpf)) + continue; + +@@ -724,7 +724,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + struct bpf_dtab_netdev *dst, *last_dst = NULL; + int excluded_devices[1+MAX_NEST_DEV]; + struct hlist_head *head; +- struct hlist_node *next; + int num_excluded = 0; + unsigned int i; + int err; +@@ -764,7 +763,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + } else { /* BPF_MAP_TYPE_DEVMAP_HASH */ + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); +- hlist_for_each_entry_safe(dst, next, head, index_hlist) { ++ hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) { + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-6.6/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch b/queue-6.6/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch new file mode 100644 index 0000000000..ecc397924c --- /dev/null +++ b/queue-6.6/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch @@ -0,0 +1,48 @@ +From 0d949101f82c2e1126fa06a54261f9fb87c63fea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:15:23 +0100 +Subject: btrfs: fix double-decrement of bytes_may_use in + submit_one_async_extent() + +From: Mark Harmstone + +[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ] + +submit_one_async_extent() calls btrfs_reserve_extent(), which decrements +bytes_may_use. If the call btrfs_create_io_em() fails, we jump to +out_free_reserve, which calls extent_clear_unlock_delalloc(). + +Because we're specifying EXTENT_DO_ACCOUNTING, i.e. +EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases +bytes_may_use again. This can lead to problems later on, as an initial +write can fail only for the writeback to silently ENOSPC. + +Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. +This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved +extents in cow_one_range()"), which is the same fix in cow_one_range(). + +Fixes: 151a41bc46df ("Btrfs: fix what bits we clear when erroring out from delalloc") +Reviewed-by: Qu Wenruo +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 46df425ab7bae..00cd932791c8d 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1209,7 +1209,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk, + extent_clear_unlock_delalloc(inode, start, end, + NULL, EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | +- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, ++ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, + PAGE_UNLOCK | PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK); + free_async_extent_pages(async_extent); +-- +2.53.0 + diff --git a/queue-6.6/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch b/queue-6.6/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch new file mode 100644 index 0000000000..8f67d6e583 --- /dev/null +++ b/queue-6.6/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch @@ -0,0 +1,237 @@ +From 27455f0bf314637d4dffe2ab2c1aa49d22553034 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:01:39 +0100 +Subject: cdrom, scsi: sr: propagate read-only status to block layer via + set_disk_ro() + +From: Daan De Meyer + +[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ] + +The cdrom core never calls set_disk_ro() for a registered device, so +BLKROGET on a CD-ROM device always returns 0 (writable), even when the +drive has no write capabilities and writes will inevitably fail. This +causes problems for userspace that relies on BLKROGET to determine +whether a block device is read-only. For example, systemd's loop device +setup uses BLKROGET to decide whether to create a loop device with +LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the +loop device to the CD-ROM and fail with I/O errors. systemd-fsck +similarly checks BLKROGET to decide whether to run fsck in no-repair +mode (-n). + +The write-capability bits in cdi->mask come from two different sources: +CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE +SENSE capabilities page (page 0x2A) before register_cdrom() is called, +while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command +and were only probed by cdrom_open_write() at device open time. This +meant that any attempt to compute the writable state from the full +mask at probe time was incorrect, because the GET CONFIGURATION bits +were still unset (and cdi->mask is initialized such that capabilities +are assumed present). + +Fix this by factoring the GET CONFIGURATION probing out of +cdrom_open_write() into a new exported helper, +cdrom_probe_write_features(), and having sr call it from sr_probe() +right after get_capabilities() has populated the MODE SENSE bits. +register_cdrom() then calls set_disk_ro() based on the full +write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) +so the block layer reflects the drive's actual write support. The +feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with +RT=00) report drive-level capabilities that are persistent across +media, so a single probe before register_cdrom() is sufficient and the +redundant probe at open time is dropped. + +With set_disk_ro() now accurate, the long-vestigial cd->writeable flag +in sr can go: get_capabilities() used to set cd->writeable based on +the same four mask bits, but because CDC_MRW_W and CDC_RAM default to +"capability present" in cdi->mask and aren't touched by MODE SENSE, +the condition that gated cd->writeable was always true, making it +unconditionally 1. Replace the corresponding gate in sr_init_command() +with get_disk_ro(cd->disk), which turns a previously no-op check into +a real one and also catches kernel-internal bio writers that bypass +blkdev_write_iter()'s bdev_read_only() check. + +The sd driver (SCSI disks) does not have this problem because it +checks the MODE SENSE Write Protect bit and calls set_disk_ro() +accordingly. The sr driver cannot use the same approach because the +MMC specification does not define the WP bit in the MODE SENSE +device-specific parameter byte for CD-ROM devices. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Daan De Meyer +Reviewed-by: Phillip Potter +Reviewed-by: Martin K. Petersen +Signed-off-by: Phillip Potter +Link: https://patch.msgid.link/20260427210139.1400-2-phil@philpotter.co.uk +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- + drivers/scsi/sr.c | 11 ++----- + drivers/scsi/sr.h | 1 - + include/linux/cdrom.h | 1 + + 4 files changed, 51 insertions(+), 35 deletions(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index 54b80911f3e28..2283fd91ff5f8 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -634,6 +634,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) + + WARN_ON(!cdo->generic_packet); + ++ /* ++ * Propagate the drive's write support to the block layer so BLKROGET ++ * reflects actual write capability. Drivers that use GET CONFIGURATION ++ * features (CDC_MRW_W, CDC_RAM) must have called ++ * cdrom_probe_write_features() before register_cdrom() so the mask is ++ * complete here. ++ */ ++ set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | ++ CDC_CD_RW)); ++ + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + mutex_lock(&cdrom_mutex); + list_add(&cdi->list, &cdrom_list); +@@ -748,6 +758,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) + return 0; + } + ++/* ++ * Probe write-related MMC features via GET CONFIGURATION and update ++ * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE ++ * capabilities page (e.g. sr) should call this after those MODE SENSE bits ++ * have been set but before register_cdrom(), so that the full set of ++ * write-capability bits is known by the time register_cdrom() decides on the ++ * initial read-only state of the disk. ++ */ ++void cdrom_probe_write_features(struct cdrom_device_info *cdi) ++{ ++ int mrw, mrw_write, ram_write; ++ ++ mrw = 0; ++ if (!cdrom_is_mrw(cdi, &mrw_write)) ++ mrw = 1; ++ ++ if (CDROM_CAN(CDC_MO_DRIVE)) ++ ram_write = 1; ++ else ++ (void) cdrom_is_random_writable(cdi, &ram_write); ++ ++ if (mrw) ++ cdi->mask &= ~CDC_MRW; ++ else ++ cdi->mask |= CDC_MRW; ++ ++ if (mrw_write) ++ cdi->mask &= ~CDC_MRW_W; ++ else ++ cdi->mask |= CDC_MRW_W; ++ ++ if (ram_write) ++ cdi->mask &= ~CDC_RAM; ++ else ++ cdi->mask |= CDC_RAM; ++} ++EXPORT_SYMBOL(cdrom_probe_write_features); ++ + static int cdrom_media_erasable(struct cdrom_device_info *cdi) + { + disc_information di; +@@ -900,33 +948,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) + */ + static int cdrom_open_write(struct cdrom_device_info *cdi) + { +- int mrw, mrw_write, ram_write; + int ret = 1; + +- mrw = 0; +- if (!cdrom_is_mrw(cdi, &mrw_write)) +- mrw = 1; +- +- if (CDROM_CAN(CDC_MO_DRIVE)) +- ram_write = 1; +- else +- (void) cdrom_is_random_writable(cdi, &ram_write); +- +- if (mrw) +- cdi->mask &= ~CDC_MRW; +- else +- cdi->mask |= CDC_MRW; +- +- if (mrw_write) +- cdi->mask &= ~CDC_MRW_W; +- else +- cdi->mask |= CDC_MRW_W; +- +- if (ram_write) +- cdi->mask &= ~CDC_RAM; +- else +- cdi->mask |= CDC_RAM; +- + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index 07ef3db3d1a14..34f243fd2c589 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) + + switch (req_op(rq)) { + case REQ_OP_WRITE: +- if (!cd->writeable) ++ if (get_disk_ro(cd->disk)) + goto out; + SCpnt->cmnd[0] = WRITE_10; + cd->cdi.media_written = 1; +@@ -670,6 +670,7 @@ static int sr_probe(struct device *dev) + error = -ENOMEM; + if (get_capabilities(cd)) + goto fail_minor; ++ cdrom_probe_write_features(&cd->cdi); + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -888,14 +889,6 @@ static int get_capabilities(struct scsi_cd *cd) + /*else I don't think it can close its tray + cd->cdi.mask |= CDC_CLOSE_TRAY; */ + +- /* +- * if DVD-RAM, MRW-W or CD-RW, we are randomly writable +- */ +- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != +- (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { +- cd->writeable = 1; +- } +- + kfree(buffer); + return 0; + } +diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h +index dc899277b3a44..2d92f9cb6fec7 100644 +--- a/drivers/scsi/sr.h ++++ b/drivers/scsi/sr.h +@@ -35,7 +35,6 @@ typedef struct scsi_cd { + struct scsi_device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ +- unsigned writeable : 1; + unsigned use:1; /* is this device still supportable */ + unsigned xa_flag:1; /* CD has XA sectors ? */ + unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ +diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h +index fdfb61ccf55ae..b4f2b23744413 100644 +--- a/include/linux/cdrom.h ++++ b/include/linux/cdrom.h +@@ -109,6 +109,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, + extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing); + ++extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); + extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); + extern void unregister_cdrom(struct cdrom_device_info *cdi); + +-- +2.53.0 + diff --git a/queue-6.6/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch b/queue-6.6/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch new file mode 100644 index 0000000000..3456082d28 --- /dev/null +++ b/queue-6.6/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch @@ -0,0 +1,47 @@ +From 23a4996b032388be332c402d70f65234498e2447 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 09:53:27 +0800 +Subject: cgroup/rdma: fix integer overflow in rdmacg_try_charge() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: cuitao + +[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ] + +The expression `rpool->resources[index].usage + 1` is computed in int +arithmetic before being assigned to s64 variable `new`. When usage equals +INT_MAX (the default "max" value), the addition overflows to INT_MIN. +This negative value then passes the `new > max` check incorrectly, +allowing a charge that should be rejected and corrupting usage to +negative. + +Fix by casting usage to s64 before the addition so the arithmetic is +done in 64-bit. + +Fixes: 39d3e7584a68 ("rdmacg: Added rdma cgroup controller") +Signed-off-by: cuitao +Reviewed-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c +index ef5878fb20057..d544a747f3954 100644 +--- a/kernel/cgroup/rdma.c ++++ b/kernel/cgroup/rdma.c +@@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, + ret = PTR_ERR(rpool); + goto err; + } else { +- new = rpool->resources[index].usage + 1; ++ new = (s64)rpool->resources[index].usage + 1; + if (new > rpool->resources[index].max) { + ret = -EAGAIN; + goto err; +-- +2.53.0 + diff --git a/queue-6.6/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch b/queue-6.6/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch new file mode 100644 index 0000000000..5ec6872256 --- /dev/null +++ b/queue-6.6/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch @@ -0,0 +1,58 @@ +From 34d10de9e2307ef70489aeae245297f68068d33c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:58 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in + of_assigned_ldb_sels() + +From: Felix Gu + +[ Upstream commit 9faf207208951460f3f7eefbc112246c8d28ff1b ] + +The function of_assigned_ldb_sels() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing a memory +leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 5d283b083800 ("clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-2-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index ba696cf34fe3b..048e2ddba490b 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -188,9 +188,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + } + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: parent clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + parent = clkspec.args[0]; ++ of_node_put(clkspec.np); + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); +@@ -198,9 +200,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + return; + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: child clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + child = clkspec.args[0]; ++ of_node_put(clkspec.np); + + if (child != IMX6QDL_CLK_LDB_DI0_SEL && + child != IMX6QDL_CLK_LDB_DI1_SEL) +-- +2.53.0 + diff --git a/queue-6.6/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch b/queue-6.6/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch new file mode 100644 index 0000000000..4d2a3599f5 --- /dev/null +++ b/queue-6.6/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch @@ -0,0 +1,56 @@ +From 5771a78c0807c6c833591e50f5854ae296ac54b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:57 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in pll6_bypassed() + +From: Felix Gu + +[ Upstream commit 4b84d496c804b470124cd3a08e928df6801d8eae ] + +The function pll6_bypassed() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing +a memory leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 3cc48976e9763 ("clk: imx6q: handle ENET PLL bypass") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-1-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index bf4c1d9c99287..ba696cf34fe3b 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -238,8 +238,11 @@ static bool pll6_bypassed(struct device_node *node) + return false; + + if (clkspec.np == node && +- clkspec.args[0] == IMX6QDL_PLL6_BYPASS) ++ clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { ++ of_node_put(clkspec.np); + break; ++ } ++ of_node_put(clkspec.np); + } + + /* PLL6 bypass is not part of the assigned clock list */ +@@ -249,6 +252,9 @@ static bool pll6_bypassed(struct device_node *node) + ret = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + ++ if (!ret) ++ of_node_put(clkspec.np); ++ + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) + return true; + +-- +2.53.0 + diff --git a/queue-6.6/clk-imx8mq-correct-the-csi-phy-sels.patch b/queue-6.6/clk-imx8mq-correct-the-csi-phy-sels.patch new file mode 100644 index 0000000000..4212a12c7d --- /dev/null +++ b/queue-6.6/clk-imx8mq-correct-the-csi-phy-sels.patch @@ -0,0 +1,49 @@ +From 293ce62662a372ab8a2be04048271ef8cd457d7a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 00:47:21 +0100 +Subject: clk: imx8mq: Correct the CSI PHY sels + +From: Sebastian Krzyszkowiak + +[ Upstream commit d16f57caa78776e6e8a88b96cb2597797b376138 ] + +According to i.MX 8M Quad Reference Manual (Section 5.1.2 Table 5-1) +MIPI_CSI1_PHY_REF_CLK_ROOT and MIPI_CSI2_PHY_REF_CLK_ROOT have +SYSTEM_PLL2_DIV3 available as their second source, which corresponds +to sys2_pll_333m rather than sys2_pll_125m. + +Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") +Signed-off-by: Sebastian Krzyszkowiak +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260128-imx8mq-csi-clk-v1-1-ac028ed26e8c@puri.sm +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index f70ed231b92d6..cedc8a02aa1f0 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " + static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +@@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", + static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch b/queue-6.6/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch new file mode 100644 index 0000000000..3fee0a5992 --- /dev/null +++ b/queue-6.6/clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch @@ -0,0 +1,59 @@ +From 26cd67813ca00074375bf5ba034dcb3514be8695 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:26 +0100 +Subject: clk: qcom: dispcc-sc7180: Add missing MDSS resets + +From: Konrad Dybcio + +[ Upstream commit b0bc6011c5499bdfddd0390262bfa13dce1eff74 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: dd3d06622138 ("clk: qcom: Add display clock controller driver for SC7180") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Taniya Das +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-2-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc7180.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c +index 9536bfc72a43c..166a4170e76f7 100644 +--- a/drivers/clk/qcom/dispcc-sc7180.c ++++ b/drivers/clk/qcom/dispcc-sc7180.c +@@ -16,6 +16,7 @@ + #include "clk-regmap-divider.h" + #include "common.h" + #include "gdsc.h" ++#include "reset.h" + + enum { + P_BI_TCXO, +@@ -635,6 +636,11 @@ static struct gdsc mdss_gdsc = { + .flags = HW_CTRL, + }; + ++static const struct qcom_reset_map disp_cc_sc7180_resets[] = { ++ [DISP_CC_MDSS_CORE_BCR] = { 0x2000 }, ++ [DISP_CC_MDSS_RSCC_BCR] = { 0x4000 }, ++}; ++ + static struct gdsc *disp_cc_sc7180_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, + }; +@@ -686,6 +692,8 @@ static const struct qcom_cc_desc disp_cc_sc7180_desc = { + .config = &disp_cc_sc7180_regmap_config, + .clks = disp_cc_sc7180_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sc7180_clocks), ++ .resets = disp_cc_sc7180_resets, ++ .num_resets = ARRAY_SIZE(disp_cc_sc7180_resets), + .gdscs = disp_cc_sc7180_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sc7180_gdscs), + }; +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch b/queue-6.6/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch new file mode 100644 index 0000000000..4319c4ac1b --- /dev/null +++ b/queue-6.6/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch @@ -0,0 +1,74 @@ +From 82d312fd545f6964cb5921d89fe49463d2921e8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 19:55:50 +0800 +Subject: clk: qcom: dispcc-sc8280xp: remove CLK_SET_RATE_PARENT from + byte_div_clk_src dividers + +From: White Lewis + +[ Upstream commit 0b151a6307205eb867250985a910a88787cbf12e ] + +The four byte_div_clk_src dividers (disp{0,1}_cc_mdss_byte{0,1}_div_clk_src) +had CLK_SET_RATE_PARENT set. When the DSI driver calls clk_set_rate() on +byte_intf_clk, the rate-change propagates through the divider up to the +parent PLL (byte_clk_src), halving the byte clock rate. + +A simiar issue had been also encountered on SM8750. +b8501febdc51 ("clk: qcom: dispcc-sm8750: Drop incorrect CLK_SET_RATE_PARENT on byte intf parent"). + +Likewise, remove CLK_SET_RATE_PARENT from all four byte divider clocks +so that clk_set_rate() on the divider adjusts only the divider ratio, +leaving the parent PLL untouched. + +Fixes: 4a66e76fdb6d ("clk: qcom: Add SC8280XP display clock controller") +Signed-off-by: White Lewis +[pengyu: reword] +Signed-off-by: Pengyu Luo +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260303115550.9279-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc8280xp.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sc8280xp.c b/drivers/clk/qcom/dispcc-sc8280xp.c +index 30f636b9f0ec8..7f8819ece5eb0 100644 +--- a/drivers/clk/qcom/dispcc-sc8280xp.c ++++ b/drivers/clk/qcom/dispcc-sc8280xp.c +@@ -1161,7 +1161,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte0_div_clk_src = { + &disp0_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1176,7 +1175,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte0_div_clk_src = { + &disp1_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1191,7 +1189,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte1_div_clk_src = { + &disp0_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1206,7 +1203,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte1_div_clk_src = { + &disp1_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch b/queue-6.6/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..fb7bf91524 --- /dev/null +++ b/queue-6.6/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,48 @@ +From b02063e4e3468b99f1c503ca865575c43e562c17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:13 -0300 +Subject: clk: qcom: dispcc-sm8250: Enable parents for pixel clocks + +From: Val Packett + +[ Upstream commit acf7a91d0b0e9e3ef374944021de62062125b7e4 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-9-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index cd6df240953fd..7aa84c341f598 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -578,7 +578,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -592,7 +592,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch b/queue-6.6/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch new file mode 100644 index 0000000000..cd5281de73 --- /dev/null +++ b/queue-6.6/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch @@ -0,0 +1,45 @@ +From 6063391d4fb77c504747369cbadf98a702746261 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:12 -0300 +Subject: clk: qcom: dispcc-sm8250: Use shared ops on the mdss vsync clk + +From: Val Packett + +[ Upstream commit 8c522da70f0c2e5148c4c13ccb1c64cca57a6fdb ] + +mdss_gdsc can get stuck on boot due to RCGs being left on from last boot. +As a fix, commit 01a0a6cc8cfd ("clk: qcom: Park shared RCGs upon +registration") introduced a callback to ensure the RCG is off upon init. +However, the fix depends on all shared RCGs being marked as such in code. + +For SM8150/SC8180X/SM8250 the MDSS vsync clock was using regular ops, +unlike the same clock in the SC7180 code. This was causing display to +frequently fail to initialize after rebooting on the Surface Pro X. +Fix by using shared ops for this clock. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-8-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index 317a7e2b50bfb..cd6df240953fd 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -632,7 +632,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch b/queue-6.6/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch new file mode 100644 index 0000000000..942ab3cc73 --- /dev/null +++ b/queue-6.6/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch @@ -0,0 +1,41 @@ +From 3e9b26e1c9aa7dea2a467c748bf558a19c596ab9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 04:12:23 +0200 +Subject: clk: qcom: dispcc-sm8450: use RCG2 ops for DPTX1 AUX clock source + +From: Dmitry Baryshkov + +[ Upstream commit 141af1be817c42c7f1e1605348d4b1983d319bea ] + +The clk_dp_ops are supposed to be used for DP-related clocks with a +proper MND divier. Use standard RCG2 ops for dptx1_aux_clk_src, the same +as all other DPTX AUX clocks in this driver. + +Fixes: 16fb89f92ec4 ("clk: qcom: Add support for Display Clock Controller on SM8450") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260112-dp-aux-clks-v1-2-456b0c11b069@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8450.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c +index 239cc726c7e29..ab796f4f0ac03 100644 +--- a/drivers/clk/qcom/dispcc-sm8450.c ++++ b/drivers/clk/qcom/dispcc-sm8450.c +@@ -364,7 +364,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_dp_ops, ++ .ops = &clk_rcg2_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-6.6/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..95de893403 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,94 @@ +From 4779b288f01c6086f2f4986081e17955682c2608 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:07 -0300 +Subject: clk: qcom: gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 3565741eb985a8a7cc6656eb33496195468cb99e ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-3-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 50 ++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index ec0c45881c67a..08011db603503 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4199,6 +4199,51 @@ static struct gdsc usb30_mp_gdsc = { + .flags = POLL_CFG_GDSCR, + }; + ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { ++ .gdscr = 0x7d050, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { ++ .gdscr = 0x7d058, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { ++ .gdscr = 0x7d054, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { ++ .gdscr = 0x7d05c, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { ++ .gdscr = 0x7d060, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ + static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, +@@ -4499,6 +4544,11 @@ static struct gdsc *gcc_sc8180x_gdscs[] = { + [USB30_MP_GDSC] = &usb30_mp_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB30_SEC_GDSC] = &usb30_sec_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, + }; + + static const struct regmap_config gcc_sc8180x_regmap_config = { +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch b/queue-6.6/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch new file mode 100644 index 0000000000..58989092b9 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch @@ -0,0 +1,74 @@ +From 918dd3d8f8ecd1d7a8801f02d57a9c13d7fda948 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:09 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for PCIe power domains + +From: Val Packett + +[ Upstream commit ccb92c78b42edd26225b4d5920847dfee3e1b093 ] + +As the PCIe host controller driver does not yet support dealing with the +loss of state during suspend, use retention for relevant GDSCs. + +This fixes the link not surviving upon resume: + + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS read failed (134) + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: Disabling device after reset failure: -19 + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260312112321.370983-5-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 889c1ab6d63f2..dd21a5898c5a5 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4132,7 +4132,7 @@ static struct gdsc pcie_0_gdsc = { + .pd = { + .name = "pcie_0_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4159,7 +4159,7 @@ static struct gdsc pcie_1_gdsc = { + .pd = { + .name = "pcie_1_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4168,7 +4168,7 @@ static struct gdsc pcie_2_gdsc = { + .pd = { + .name = "pcie_2_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4186,7 +4186,7 @@ static struct gdsc pcie_3_gdsc = { + .pd = { + .name = "pcie_3_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-6.6/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch b/queue-6.6/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch new file mode 100644 index 0000000000..814d71a803 --- /dev/null +++ b/queue-6.6/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch @@ -0,0 +1,65 @@ +From 00537de63ca843b6b39671b5113e2f5728d43ea3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:08 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for USB power domains + +From: Val Packett + +[ Upstream commit 25bc96f26cd6c19dde13a0b9859183e531d6fbfc ] + +The USB subsystem does not expect to lose its state on suspend: + + xhci-hcd xhci-hcd.0.auto: xHC error in resume, USBSTS 0x401, Reinit + usb usb1: root hub lost power or was reset + +(The reinitialization usually succeeds, but it does slow down resume.) + +To maintain state during suspend, the relevant GDSCs need to stay in +retention mode, like they do on other similar SoCs. Change the mode to +PWRSTS_RET_ON to fix. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-4-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 08011db603503..889c1ab6d63f2 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4105,7 +4105,7 @@ static struct gdsc usb30_sec_gdsc = { + .pd = { + .name = "usb30_sec_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4123,7 +4123,7 @@ static struct gdsc usb30_prim_gdsc = { + .pd = { + .name = "usb30_prim_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4195,7 +4195,7 @@ static struct gdsc usb30_mp_gdsc = { + .pd = { + .name = "usb30_mp_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-6.6/clk-qoriq-avoid-format-string-warning.patch b/queue-6.6/clk-qoriq-avoid-format-string-warning.patch new file mode 100644 index 0000000000..df5ed091a4 --- /dev/null +++ b/queue-6.6/clk-qoriq-avoid-format-string-warning.patch @@ -0,0 +1,86 @@ +From 75786e2d175206beb9ccff69c889a12a3bc5d3bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:18:49 +0100 +Subject: clk: qoriq: avoid format string warning + +From: Arnd Bergmann + +[ Upstream commit 096abbb6682ee031a0f5ce9f4c71ead9fa63d31e ] + +clang-22 warns about the use of non-variadic format arguments passed into +snprintf(): + +drivers/clk/clk-qoriq.c:925:39: error: diagnostic behavior may be improved by adding the + 'format(printf, 7, 8)' attribute to the declaration of 'create_mux_common' [-Werror,-Wmissing-format-attribute] + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + | __attribute__((format(printf, 7, 8))) + 911 | struct mux_hwclock *hwc, + 912 | const struct clk_ops *ops, + 913 | unsigned long min_rate, + 914 | unsigned long max_rate, + 915 | unsigned long pct80_rate, + 916 | const char *fmt, int idx) + 917 | { + 918 | struct clk_init_data init = {}; + 919 | struct clk *clk; + 920 | const struct clockgen_pll_div *div; + 921 | const char *parent_names[NUM_MUX_PARENTS]; + 922 | char name[32]; + 923 | int i, j; + 924 | + 925 | snprintf(name, sizeof(name), fmt, idx); + | ^ +drivers/clk/clk-qoriq.c:910:28: note: 'create_mux_common' declared here + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + +Rework this to pass the 'int idx' as a varargs argument, allowing the +format string to be verified at the caller location. + +Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") +Signed-off-by: Arnd Bergmann +Reviewed-by: Kees Cook +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-qoriq.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c +index 4dcde305944c4..318acd176a2ef 100644 +--- a/drivers/clk/clk-qoriq.c ++++ b/drivers/clk/clk-qoriq.c +@@ -906,13 +906,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg, + return &cg->pll[pll].div[div]; + } + +-static struct clk * __init create_mux_common(struct clockgen *cg, +- struct mux_hwclock *hwc, +- const struct clk_ops *ops, +- unsigned long min_rate, +- unsigned long max_rate, +- unsigned long pct80_rate, +- const char *fmt, int idx) ++static struct clk * __init __printf(7, 8) ++create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, ++ const struct clk_ops *ops, unsigned long min_rate, ++ unsigned long max_rate, unsigned long pct80_rate, ++ const char *fmt, ...) + { + struct clk_init_data init = {}; + struct clk *clk; +@@ -920,8 +918,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg, + const char *parent_names[NUM_MUX_PARENTS]; + char name[32]; + int i, j; ++ va_list args; + +- snprintf(name, sizeof(name), fmt, idx); ++ va_start(args, fmt); ++ vsnprintf(name, sizeof(name), fmt, args); ++ va_end(args); + + for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) { + unsigned long rate; +-- +2.53.0 + diff --git a/queue-6.6/clk-visconti-pll-initialize-clk_init_data-to-zero.patch b/queue-6.6/clk-visconti-pll-initialize-clk_init_data-to-zero.patch new file mode 100644 index 0000000000..0a0652e59d --- /dev/null +++ b/queue-6.6/clk-visconti-pll-initialize-clk_init_data-to-zero.patch @@ -0,0 +1,52 @@ +From 04063051bb1ee317e7afea315e77a5f6e785bba4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 10:32:37 -0400 +Subject: clk: visconti: pll: initialize clk_init_data to zero +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 1603cbb64173a0e9fa7500f2a686f4aa011c58b9 ] + +Sashiko reported the following: + +> The struct clk_init_data init is declared on the stack without being +> fully zero-initialized. While fields like name, flags, parent_names, +> num_parents, and ops are explicitly assigned, the parent_data and +> parent_hws fields are left containing stack garbage. + +clk_core_populate_parent_map() currently prefers the parent names over +the parent data and hws, so this isn't a problem at the moment. If that +ordering ever changed in the future, then this could lead to some +unexpected crashes. Let's just go ahead and make sure that the struct +clk_init_data is initialized to zero as a good practice. + +Fixes: b4cbe606dc367 ("clk: visconti: Add support common clock driver and reset driver") +Link: https://sashiko.dev/#/patchset/20260326042317.122536-1-rosenp%40gmail.com +Signed-off-by: Brian Masney +Reviewed-by: Benoît Monin +Reviewed-by: Nobuhiro Iwamatsu +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/visconti/pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c +index e9cd80e085dc3..a540936196ca3 100644 +--- a/drivers/clk/visconti/pll.c ++++ b/drivers/clk/visconti/pll.c +@@ -244,7 +244,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, + const struct visconti_pll_rate_table *rate_table, + spinlock_t *lock) + { +- struct clk_init_data init; ++ struct clk_init_data init = {}; + struct visconti_pll *pll; + struct clk_hw *pll_hw_clk; + size_t len; +-- +2.53.0 + diff --git a/queue-6.6/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch b/queue-6.6/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch new file mode 100644 index 0000000000..2d252006fb --- /dev/null +++ b/queue-6.6/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch @@ -0,0 +1,37 @@ +From 9fc68ee7a3f01c81a9c028bd71d8b085f73eca4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:11:16 +0100 +Subject: clk: xgene: Fix mapping leak in xgene_pllclk_init() + +From: Geert Uytterhoeven + +[ Upstream commit f520a492e07bc6718e26cfb7543ab4cadd8bb0e2 ] + +If xgene_register_clk_pll() fails, the mapped register block is never +unmapped. + +Fixes: 308964caeebc45eb ("clk: Add APM X-Gene SoC clock driver") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-xgene.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c +index 0c3d0cee98c83..a542b78d9c731 100644 +--- a/drivers/clk/clk-xgene.c ++++ b/drivers/clk/clk-xgene.c +@@ -187,6 +187,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); ++ } else { ++ iounmap(reg); + } + } + +-- +2.53.0 + diff --git a/queue-6.6/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch b/queue-6.6/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch new file mode 100644 index 0000000000..250ac95a08 --- /dev/null +++ b/queue-6.6/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch @@ -0,0 +1,49 @@ +From 34e6251799f367cb73eeed9d7b6910e45054e769 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 12:39:28 +0100 +Subject: crypto: atmel-aes - guard unregister on error in + atmel_aes_register_algs + +From: Thorsten Blum + +[ Upstream commit 57a13941c0bb06ae24e3b34672d7b6f2172b253f ] + +Ensure the device supports XTS and GCM with 'has_xts' and 'has_gcm' +before unregistering algorithms when XTS or authenc registration fails, +which would trigger a WARN in crypto_unregister_alg(). + +Currently, with the capabilities defined in atmel_aes_get_cap(), this +bug cannot happen because all devices that support XTS and authenc also +support GCM, but the error handling should still be correct regardless +of hardware capabilities. + +Fixes: d52db5188a87 ("crypto: atmel-aes - add support to the XTS mode") +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/atmel-aes.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c +index 9bd18825e1bf2..3402cf3f017f1 100644 +--- a/drivers/crypto/atmel-aes.c ++++ b/drivers/crypto/atmel-aes.c +@@ -2269,10 +2269,12 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + /* i = ARRAY_SIZE(aes_authenc_algs); */ + err_aes_authenc_alg: + crypto_unregister_aeads(aes_authenc_algs, i); +- crypto_unregister_skcipher(&aes_xts_alg); ++ if (dd->caps.has_xts) ++ crypto_unregister_skcipher(&aes_xts_alg); + #endif + err_aes_xts_alg: +- crypto_unregister_aead(&aes_gcm_alg); ++ if (dd->caps.has_gcm) ++ crypto_unregister_aead(&aes_gcm_alg); + err_aes_gcm_alg: + i = ARRAY_SIZE(aes_algs); + err_aes_algs: +-- +2.53.0 + diff --git a/queue-6.6/crypto-atmel-remove-cfb-and-ofb.patch b/queue-6.6/crypto-atmel-remove-cfb-and-ofb.patch new file mode 100644 index 0000000000..56a541feb8 --- /dev/null +++ b/queue-6.6/crypto-atmel-remove-cfb-and-ofb.patch @@ -0,0 +1,645 @@ +From 5715b8677149989a565b9e3f4e5e36e162123e1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 Sep 2023 17:33:56 +0800 +Subject: crypto: atmel - Remove cfb and ofb + +From: Herbert Xu + +[ Upstream commit a16144bda9c332079b6a1db52725e9c22007114d ] + +Remove the unused CFB/OFB implementation. + +Signed-off-by: Herbert Xu +Stable-dep-of: 57a13941c0bb ("crypto: atmel-aes - guard unregister on error in atmel_aes_register_algs") +Signed-off-by: Sasha Levin +--- + drivers/crypto/atmel-aes.c | 214 +----------------------------------- + drivers/crypto/atmel-tdes.c | 205 +--------------------------------- + 2 files changed, 8 insertions(+), 411 deletions(-) + +diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c +index 97fcde0126766..f023f27468c0d 100644 +--- a/drivers/crypto/atmel-aes.c ++++ b/drivers/crypto/atmel-aes.c +@@ -46,11 +46,6 @@ + #define ATMEL_AES_BUFFER_ORDER 2 + #define ATMEL_AES_BUFFER_SIZE (PAGE_SIZE << ATMEL_AES_BUFFER_ORDER) + +-#define CFB8_BLOCK_SIZE 1 +-#define CFB16_BLOCK_SIZE 2 +-#define CFB32_BLOCK_SIZE 4 +-#define CFB64_BLOCK_SIZE 8 +- + #define SIZE_IN_WORDS(x) ((x) >> 2) + + /* AES flags */ +@@ -60,12 +55,6 @@ + #define AES_FLAGS_OPMODE_MASK (AES_MR_OPMOD_MASK | AES_MR_CFBS_MASK) + #define AES_FLAGS_ECB AES_MR_OPMOD_ECB + #define AES_FLAGS_CBC AES_MR_OPMOD_CBC +-#define AES_FLAGS_OFB AES_MR_OPMOD_OFB +-#define AES_FLAGS_CFB128 (AES_MR_OPMOD_CFB | AES_MR_CFBS_128b) +-#define AES_FLAGS_CFB64 (AES_MR_OPMOD_CFB | AES_MR_CFBS_64b) +-#define AES_FLAGS_CFB32 (AES_MR_OPMOD_CFB | AES_MR_CFBS_32b) +-#define AES_FLAGS_CFB16 (AES_MR_OPMOD_CFB | AES_MR_CFBS_16b) +-#define AES_FLAGS_CFB8 (AES_MR_OPMOD_CFB | AES_MR_CFBS_8b) + #define AES_FLAGS_CTR AES_MR_OPMOD_CTR + #define AES_FLAGS_GCM AES_MR_OPMOD_GCM + #define AES_FLAGS_XTS AES_MR_OPMOD_XTS +@@ -87,7 +76,6 @@ + + struct atmel_aes_caps { + bool has_dualbuff; +- bool has_cfb64; + bool has_gcm; + bool has_xts; + bool has_authenc; +@@ -860,22 +848,6 @@ static int atmel_aes_dma_start(struct atmel_aes_dev *dd, + int err; + + switch (dd->ctx->block_size) { +- case CFB8_BLOCK_SIZE: +- addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; +- maxburst = 1; +- break; +- +- case CFB16_BLOCK_SIZE: +- addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; +- maxburst = 1; +- break; +- +- case CFB32_BLOCK_SIZE: +- case CFB64_BLOCK_SIZE: +- addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +- maxburst = 1; +- break; +- + case AES_BLOCK_SIZE: + addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + maxburst = dd->caps.max_burst_size; +@@ -1103,7 +1075,7 @@ static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) + } + + /* +- * ECB, CBC, CFB, OFB or CTR mode require the plaintext and ciphertext ++ * ECB, CBC or CTR mode require the plaintext and ciphertext + * to have a positve integer length. + */ + if (!req->cryptlen && opmode != AES_FLAGS_XTS) +@@ -1113,27 +1085,7 @@ static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) + !IS_ALIGNED(req->cryptlen, crypto_skcipher_blocksize(skcipher))) + return -EINVAL; + +- switch (mode & AES_FLAGS_OPMODE_MASK) { +- case AES_FLAGS_CFB8: +- ctx->block_size = CFB8_BLOCK_SIZE; +- break; +- +- case AES_FLAGS_CFB16: +- ctx->block_size = CFB16_BLOCK_SIZE; +- break; +- +- case AES_FLAGS_CFB32: +- ctx->block_size = CFB32_BLOCK_SIZE; +- break; +- +- case AES_FLAGS_CFB64: +- ctx->block_size = CFB64_BLOCK_SIZE; +- break; +- +- default: +- ctx->block_size = AES_BLOCK_SIZE; +- break; +- } ++ ctx->block_size = AES_BLOCK_SIZE; + ctx->is_aead = false; + + rctx = skcipher_request_ctx(req); +@@ -1188,66 +1140,6 @@ static int atmel_aes_cbc_decrypt(struct skcipher_request *req) + return atmel_aes_crypt(req, AES_FLAGS_CBC); + } + +-static int atmel_aes_ofb_encrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_OFB | AES_FLAGS_ENCRYPT); +-} +- +-static int atmel_aes_ofb_decrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_OFB); +-} +- +-static int atmel_aes_cfb_encrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB128 | AES_FLAGS_ENCRYPT); +-} +- +-static int atmel_aes_cfb_decrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB128); +-} +- +-static int atmel_aes_cfb64_encrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB64 | AES_FLAGS_ENCRYPT); +-} +- +-static int atmel_aes_cfb64_decrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB64); +-} +- +-static int atmel_aes_cfb32_encrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB32 | AES_FLAGS_ENCRYPT); +-} +- +-static int atmel_aes_cfb32_decrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB32); +-} +- +-static int atmel_aes_cfb16_encrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB16 | AES_FLAGS_ENCRYPT); +-} +- +-static int atmel_aes_cfb16_decrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB16); +-} +- +-static int atmel_aes_cfb8_encrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB8 | AES_FLAGS_ENCRYPT); +-} +- +-static int atmel_aes_cfb8_decrypt(struct skcipher_request *req) +-{ +- return atmel_aes_crypt(req, AES_FLAGS_CFB8); +-} +- + static int atmel_aes_ctr_encrypt(struct skcipher_request *req) + { + return atmel_aes_crypt(req, AES_FLAGS_CTR | AES_FLAGS_ENCRYPT); +@@ -1318,76 +1210,6 @@ static struct skcipher_alg aes_algs[] = { + .decrypt = atmel_aes_cbc_decrypt, + .ivsize = AES_BLOCK_SIZE, + }, +-{ +- .base.cra_name = "ofb(aes)", +- .base.cra_driver_name = "atmel-ofb-aes", +- .base.cra_blocksize = 1, +- .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), +- +- .init = atmel_aes_init_tfm, +- .min_keysize = AES_MIN_KEY_SIZE, +- .max_keysize = AES_MAX_KEY_SIZE, +- .setkey = atmel_aes_setkey, +- .encrypt = atmel_aes_ofb_encrypt, +- .decrypt = atmel_aes_ofb_decrypt, +- .ivsize = AES_BLOCK_SIZE, +-}, +-{ +- .base.cra_name = "cfb(aes)", +- .base.cra_driver_name = "atmel-cfb-aes", +- .base.cra_blocksize = 1, +- .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), +- +- .init = atmel_aes_init_tfm, +- .min_keysize = AES_MIN_KEY_SIZE, +- .max_keysize = AES_MAX_KEY_SIZE, +- .setkey = atmel_aes_setkey, +- .encrypt = atmel_aes_cfb_encrypt, +- .decrypt = atmel_aes_cfb_decrypt, +- .ivsize = AES_BLOCK_SIZE, +-}, +-{ +- .base.cra_name = "cfb32(aes)", +- .base.cra_driver_name = "atmel-cfb32-aes", +- .base.cra_blocksize = CFB32_BLOCK_SIZE, +- .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), +- +- .init = atmel_aes_init_tfm, +- .min_keysize = AES_MIN_KEY_SIZE, +- .max_keysize = AES_MAX_KEY_SIZE, +- .setkey = atmel_aes_setkey, +- .encrypt = atmel_aes_cfb32_encrypt, +- .decrypt = atmel_aes_cfb32_decrypt, +- .ivsize = AES_BLOCK_SIZE, +-}, +-{ +- .base.cra_name = "cfb16(aes)", +- .base.cra_driver_name = "atmel-cfb16-aes", +- .base.cra_blocksize = CFB16_BLOCK_SIZE, +- .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), +- +- .init = atmel_aes_init_tfm, +- .min_keysize = AES_MIN_KEY_SIZE, +- .max_keysize = AES_MAX_KEY_SIZE, +- .setkey = atmel_aes_setkey, +- .encrypt = atmel_aes_cfb16_encrypt, +- .decrypt = atmel_aes_cfb16_decrypt, +- .ivsize = AES_BLOCK_SIZE, +-}, +-{ +- .base.cra_name = "cfb8(aes)", +- .base.cra_driver_name = "atmel-cfb8-aes", +- .base.cra_blocksize = CFB8_BLOCK_SIZE, +- .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), +- +- .init = atmel_aes_init_tfm, +- .min_keysize = AES_MIN_KEY_SIZE, +- .max_keysize = AES_MAX_KEY_SIZE, +- .setkey = atmel_aes_setkey, +- .encrypt = atmel_aes_cfb8_encrypt, +- .decrypt = atmel_aes_cfb8_decrypt, +- .ivsize = AES_BLOCK_SIZE, +-}, + { + .base.cra_name = "ctr(aes)", + .base.cra_driver_name = "atmel-ctr-aes", +@@ -1404,21 +1226,6 @@ static struct skcipher_alg aes_algs[] = { + }, + }; + +-static struct skcipher_alg aes_cfb64_alg = { +- .base.cra_name = "cfb64(aes)", +- .base.cra_driver_name = "atmel-cfb64-aes", +- .base.cra_blocksize = CFB64_BLOCK_SIZE, +- .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), +- +- .init = atmel_aes_init_tfm, +- .min_keysize = AES_MIN_KEY_SIZE, +- .max_keysize = AES_MAX_KEY_SIZE, +- .setkey = atmel_aes_setkey, +- .encrypt = atmel_aes_cfb64_encrypt, +- .decrypt = atmel_aes_cfb64_decrypt, +- .ivsize = AES_BLOCK_SIZE, +-}; +- + + /* gcm aead functions */ + +@@ -2407,9 +2214,6 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) + if (dd->caps.has_gcm) + crypto_unregister_aead(&aes_gcm_alg); + +- if (dd->caps.has_cfb64) +- crypto_unregister_skcipher(&aes_cfb64_alg); +- + for (i = 0; i < ARRAY_SIZE(aes_algs); i++) + crypto_unregister_skcipher(&aes_algs[i]); + } +@@ -2434,14 +2238,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + goto err_aes_algs; + } + +- if (dd->caps.has_cfb64) { +- atmel_aes_crypto_alg_init(&aes_cfb64_alg.base); +- +- err = crypto_register_skcipher(&aes_cfb64_alg); +- if (err) +- goto err_aes_cfb64_alg; +- } +- + if (dd->caps.has_gcm) { + atmel_aes_crypto_alg_init(&aes_gcm_alg.base); + +@@ -2482,8 +2278,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + err_aes_xts_alg: + crypto_unregister_aead(&aes_gcm_alg); + err_aes_gcm_alg: +- crypto_unregister_skcipher(&aes_cfb64_alg); +-err_aes_cfb64_alg: + i = ARRAY_SIZE(aes_algs); + err_aes_algs: + for (j = 0; j < i; j++) +@@ -2495,7 +2289,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + static void atmel_aes_get_cap(struct atmel_aes_dev *dd) + { + dd->caps.has_dualbuff = 0; +- dd->caps.has_cfb64 = 0; + dd->caps.has_gcm = 0; + dd->caps.has_xts = 0; + dd->caps.has_authenc = 0; +@@ -2507,7 +2300,6 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) + case 0x600: + case 0x500: + dd->caps.has_dualbuff = 1; +- dd->caps.has_cfb64 = 1; + dd->caps.has_gcm = 1; + dd->caps.has_xts = 1; + dd->caps.has_authenc = 1; +@@ -2515,13 +2307,11 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) + break; + case 0x200: + dd->caps.has_dualbuff = 1; +- dd->caps.has_cfb64 = 1; + dd->caps.has_gcm = 1; + dd->caps.max_burst_size = 4; + break; + case 0x130: + dd->caps.has_dualbuff = 1; +- dd->caps.has_cfb64 = 1; + dd->caps.max_burst_size = 4; + break; + case 0x120: +diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c +index 6870a13342e22..48888b2ff7936 100644 +--- a/drivers/crypto/atmel-tdes.c ++++ b/drivers/crypto/atmel-tdes.c +@@ -45,11 +45,6 @@ + #define TDES_FLAGS_OPMODE_MASK (TDES_MR_OPMOD_MASK | TDES_MR_CFBS_MASK) + #define TDES_FLAGS_ECB TDES_MR_OPMOD_ECB + #define TDES_FLAGS_CBC TDES_MR_OPMOD_CBC +-#define TDES_FLAGS_OFB TDES_MR_OPMOD_OFB +-#define TDES_FLAGS_CFB64 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_64b) +-#define TDES_FLAGS_CFB32 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_32b) +-#define TDES_FLAGS_CFB16 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_16b) +-#define TDES_FLAGS_CFB8 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_8b) + + #define TDES_FLAGS_MODE_MASK (TDES_FLAGS_OPMODE_MASK | TDES_FLAGS_ENCRYPT) + +@@ -60,13 +55,8 @@ + + #define ATMEL_TDES_QUEUE_LENGTH 50 + +-#define CFB8_BLOCK_SIZE 1 +-#define CFB16_BLOCK_SIZE 2 +-#define CFB32_BLOCK_SIZE 4 +- + struct atmel_tdes_caps { + bool has_dma; +- u32 has_cfb_3keys; + }; + + struct atmel_tdes_dev; +@@ -376,7 +366,6 @@ static int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd, + dma_addr_t dma_addr_in, + dma_addr_t dma_addr_out, int length) + { +- struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req); + int len32; + + dd->dma_size = length; +@@ -386,19 +375,7 @@ static int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd, + DMA_TO_DEVICE); + } + +- switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) { +- case TDES_FLAGS_CFB8: +- len32 = DIV_ROUND_UP(length, sizeof(u8)); +- break; +- +- case TDES_FLAGS_CFB16: +- len32 = DIV_ROUND_UP(length, sizeof(u16)); +- break; +- +- default: +- len32 = DIV_ROUND_UP(length, sizeof(u32)); +- break; +- } ++ len32 = DIV_ROUND_UP(length, sizeof(u32)); + + atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS); + atmel_tdes_write(dd, TDES_TPR, dma_addr_in); +@@ -419,7 +396,6 @@ static int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd, + dma_addr_t dma_addr_in, + dma_addr_t dma_addr_out, int length) + { +- struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req); + struct scatterlist sg[2]; + struct dma_async_tx_descriptor *in_desc, *out_desc; + enum dma_slave_buswidth addr_width; +@@ -431,19 +407,7 @@ static int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd, + DMA_TO_DEVICE); + } + +- switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) { +- case TDES_FLAGS_CFB8: +- addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; +- break; +- +- case TDES_FLAGS_CFB16: +- addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; +- break; +- +- default: +- addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +- break; +- } ++ addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + dd->dma_lch_in.dma_conf.dst_addr_width = addr_width; + dd->dma_lch_out.dma_conf.src_addr_width = addr_width; +@@ -680,39 +644,11 @@ static int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode) + if (!req->cryptlen) + return 0; + +- switch (mode & TDES_FLAGS_OPMODE_MASK) { +- case TDES_FLAGS_CFB8: +- if (!IS_ALIGNED(req->cryptlen, CFB8_BLOCK_SIZE)) { +- dev_dbg(dev, "request size is not exact amount of CFB8 blocks\n"); +- return -EINVAL; +- } +- ctx->block_size = CFB8_BLOCK_SIZE; +- break; +- +- case TDES_FLAGS_CFB16: +- if (!IS_ALIGNED(req->cryptlen, CFB16_BLOCK_SIZE)) { +- dev_dbg(dev, "request size is not exact amount of CFB16 blocks\n"); +- return -EINVAL; +- } +- ctx->block_size = CFB16_BLOCK_SIZE; +- break; +- +- case TDES_FLAGS_CFB32: +- if (!IS_ALIGNED(req->cryptlen, CFB32_BLOCK_SIZE)) { +- dev_dbg(dev, "request size is not exact amount of CFB32 blocks\n"); +- return -EINVAL; +- } +- ctx->block_size = CFB32_BLOCK_SIZE; +- break; +- +- default: +- if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) { +- dev_dbg(dev, "request size is not exact amount of DES blocks\n"); +- return -EINVAL; +- } +- ctx->block_size = DES_BLOCK_SIZE; +- break; ++ if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) { ++ dev_dbg(dev, "request size is not exact amount of DES blocks\n"); ++ return -EINVAL; + } ++ ctx->block_size = DES_BLOCK_SIZE; + + rctx->mode = mode; + +@@ -832,55 +768,6 @@ static int atmel_tdes_cbc_decrypt(struct skcipher_request *req) + { + return atmel_tdes_crypt(req, TDES_FLAGS_CBC); + } +-static int atmel_tdes_cfb_encrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_CFB64 | TDES_FLAGS_ENCRYPT); +-} +- +-static int atmel_tdes_cfb_decrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_CFB64); +-} +- +-static int atmel_tdes_cfb8_encrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_CFB8 | TDES_FLAGS_ENCRYPT); +-} +- +-static int atmel_tdes_cfb8_decrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_CFB8); +-} +- +-static int atmel_tdes_cfb16_encrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_CFB16 | TDES_FLAGS_ENCRYPT); +-} +- +-static int atmel_tdes_cfb16_decrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_CFB16); +-} +- +-static int atmel_tdes_cfb32_encrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_CFB32 | TDES_FLAGS_ENCRYPT); +-} +- +-static int atmel_tdes_cfb32_decrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_CFB32); +-} +- +-static int atmel_tdes_ofb_encrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_OFB | TDES_FLAGS_ENCRYPT); +-} +- +-static int atmel_tdes_ofb_decrypt(struct skcipher_request *req) +-{ +- return atmel_tdes_crypt(req, TDES_FLAGS_OFB); +-} + + static int atmel_tdes_init_tfm(struct crypto_skcipher *tfm) + { +@@ -931,71 +818,6 @@ static struct skcipher_alg tdes_algs[] = { + .encrypt = atmel_tdes_cbc_encrypt, + .decrypt = atmel_tdes_cbc_decrypt, + }, +-{ +- .base.cra_name = "cfb(des)", +- .base.cra_driver_name = "atmel-cfb-des", +- .base.cra_blocksize = DES_BLOCK_SIZE, +- .base.cra_alignmask = 0x7, +- +- .min_keysize = DES_KEY_SIZE, +- .max_keysize = DES_KEY_SIZE, +- .ivsize = DES_BLOCK_SIZE, +- .setkey = atmel_des_setkey, +- .encrypt = atmel_tdes_cfb_encrypt, +- .decrypt = atmel_tdes_cfb_decrypt, +-}, +-{ +- .base.cra_name = "cfb8(des)", +- .base.cra_driver_name = "atmel-cfb8-des", +- .base.cra_blocksize = CFB8_BLOCK_SIZE, +- .base.cra_alignmask = 0, +- +- .min_keysize = DES_KEY_SIZE, +- .max_keysize = DES_KEY_SIZE, +- .ivsize = DES_BLOCK_SIZE, +- .setkey = atmel_des_setkey, +- .encrypt = atmel_tdes_cfb8_encrypt, +- .decrypt = atmel_tdes_cfb8_decrypt, +-}, +-{ +- .base.cra_name = "cfb16(des)", +- .base.cra_driver_name = "atmel-cfb16-des", +- .base.cra_blocksize = CFB16_BLOCK_SIZE, +- .base.cra_alignmask = 0x1, +- +- .min_keysize = DES_KEY_SIZE, +- .max_keysize = DES_KEY_SIZE, +- .ivsize = DES_BLOCK_SIZE, +- .setkey = atmel_des_setkey, +- .encrypt = atmel_tdes_cfb16_encrypt, +- .decrypt = atmel_tdes_cfb16_decrypt, +-}, +-{ +- .base.cra_name = "cfb32(des)", +- .base.cra_driver_name = "atmel-cfb32-des", +- .base.cra_blocksize = CFB32_BLOCK_SIZE, +- .base.cra_alignmask = 0x3, +- +- .min_keysize = DES_KEY_SIZE, +- .max_keysize = DES_KEY_SIZE, +- .ivsize = DES_BLOCK_SIZE, +- .setkey = atmel_des_setkey, +- .encrypt = atmel_tdes_cfb32_encrypt, +- .decrypt = atmel_tdes_cfb32_decrypt, +-}, +-{ +- .base.cra_name = "ofb(des)", +- .base.cra_driver_name = "atmel-ofb-des", +- .base.cra_blocksize = 1, +- .base.cra_alignmask = 0x7, +- +- .min_keysize = DES_KEY_SIZE, +- .max_keysize = DES_KEY_SIZE, +- .ivsize = DES_BLOCK_SIZE, +- .setkey = atmel_des_setkey, +- .encrypt = atmel_tdes_ofb_encrypt, +- .decrypt = atmel_tdes_ofb_decrypt, +-}, + { + .base.cra_name = "ecb(des3_ede)", + .base.cra_driver_name = "atmel-ecb-tdes", +@@ -1021,19 +843,6 @@ static struct skcipher_alg tdes_algs[] = { + .decrypt = atmel_tdes_cbc_decrypt, + .ivsize = DES_BLOCK_SIZE, + }, +-{ +- .base.cra_name = "ofb(des3_ede)", +- .base.cra_driver_name = "atmel-ofb-tdes", +- .base.cra_blocksize = DES_BLOCK_SIZE, +- .base.cra_alignmask = 0x7, +- +- .min_keysize = DES3_EDE_KEY_SIZE, +- .max_keysize = DES3_EDE_KEY_SIZE, +- .setkey = atmel_tdes_setkey, +- .encrypt = atmel_tdes_ofb_encrypt, +- .decrypt = atmel_tdes_ofb_decrypt, +- .ivsize = DES_BLOCK_SIZE, +-}, + }; + + static void atmel_tdes_queue_task(unsigned long data) +@@ -1121,14 +930,12 @@ static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd) + { + + dd->caps.has_dma = 0; +- dd->caps.has_cfb_3keys = 0; + + /* keep only major version number */ + switch (dd->hw_version & 0xf00) { + case 0x800: + case 0x700: + dd->caps.has_dma = 1; +- dd->caps.has_cfb_3keys = 1; + break; + case 0x600: + break; +-- +2.53.0 + diff --git a/queue-6.6/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch b/queue-6.6/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch new file mode 100644 index 0000000000..bb28b57b4c --- /dev/null +++ b/queue-6.6/crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch @@ -0,0 +1,205 @@ +From 54d59d586278f9a6a92ac5297b72f15c2d36faff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 18:47:03 +0100 +Subject: crypto: atmel - Use unregister_{aeads,ahashes,skciphers} + +From: Thorsten Blum + +[ Upstream commit 2ffc1ef4e826f0c3274f9ff5eb42bc70a5571afd ] + +Replace multiple for loops with calls to crypto_unregister_aeads(), +crypto_unregister_ahashes(), and crypto_unregister_skciphers(). + +Remove the definition of atmel_tdes_unregister_algs() because it is +equivalent to calling crypto_unregister_skciphers() directly, and the +function parameter 'struct atmel_tdes_dev *' is unused anyway. + +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Stable-dep-of: 57a13941c0bb ("crypto: atmel-aes - guard unregister on error in atmel_aes_register_algs") +Signed-off-by: Sasha Levin +--- + drivers/crypto/atmel-aes.c | 17 ++++++----------- + drivers/crypto/atmel-sha.c | 27 ++++++++++----------------- + drivers/crypto/atmel-tdes.c | 25 ++++++------------------- + 3 files changed, 22 insertions(+), 47 deletions(-) + +diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c +index f023f27468c0d..9bd18825e1bf2 100644 +--- a/drivers/crypto/atmel-aes.c ++++ b/drivers/crypto/atmel-aes.c +@@ -2200,12 +2200,10 @@ static irqreturn_t atmel_aes_irq(int irq, void *dev_id) + + static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) + { +- int i; +- + #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) + if (dd->caps.has_authenc) +- for (i = 0; i < ARRAY_SIZE(aes_authenc_algs); i++) +- crypto_unregister_aead(&aes_authenc_algs[i]); ++ crypto_unregister_aeads(aes_authenc_algs, ++ ARRAY_SIZE(aes_authenc_algs)); + #endif + + if (dd->caps.has_xts) +@@ -2214,8 +2212,7 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) + if (dd->caps.has_gcm) + crypto_unregister_aead(&aes_gcm_alg); + +- for (i = 0; i < ARRAY_SIZE(aes_algs); i++) +- crypto_unregister_skcipher(&aes_algs[i]); ++ crypto_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs)); + } + + static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) +@@ -2228,7 +2225,7 @@ static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) + + static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { + atmel_aes_crypto_alg_init(&aes_algs[i].base); +@@ -2271,8 +2268,7 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) + /* i = ARRAY_SIZE(aes_authenc_algs); */ + err_aes_authenc_alg: +- for (j = 0; j < i; j++) +- crypto_unregister_aead(&aes_authenc_algs[j]); ++ crypto_unregister_aeads(aes_authenc_algs, i); + crypto_unregister_skcipher(&aes_xts_alg); + #endif + err_aes_xts_alg: +@@ -2280,8 +2276,7 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + err_aes_gcm_alg: + i = ARRAY_SIZE(aes_algs); + err_aes_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_skcipher(&aes_algs[j]); ++ crypto_unregister_skciphers(aes_algs, i); + + return err; + } +diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c +index 3622120add625..d32fb4e770119 100644 +--- a/drivers/crypto/atmel-sha.c ++++ b/drivers/crypto/atmel-sha.c +@@ -2418,27 +2418,23 @@ EXPORT_SYMBOL_GPL(atmel_sha_authenc_abort); + + static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) + { +- int i; +- + if (dd->caps.has_hmac) +- for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) +- crypto_unregister_ahash(&sha_hmac_algs[i]); ++ crypto_unregister_ahashes(sha_hmac_algs, ++ ARRAY_SIZE(sha_hmac_algs)); + +- for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) +- crypto_unregister_ahash(&sha_1_256_algs[i]); ++ crypto_unregister_ahashes(sha_1_256_algs, ARRAY_SIZE(sha_1_256_algs)); + + if (dd->caps.has_sha224) + crypto_unregister_ahash(&sha_224_alg); + +- if (dd->caps.has_sha_384_512) { +- for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) +- crypto_unregister_ahash(&sha_384_512_algs[i]); +- } ++ if (dd->caps.has_sha_384_512) ++ crypto_unregister_ahashes(sha_384_512_algs, ++ ARRAY_SIZE(sha_384_512_algs)); + } + + static int atmel_sha_register_algs(struct atmel_sha_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) { + atmel_sha_alg_init(&sha_1_256_algs[i]); +@@ -2480,18 +2476,15 @@ static int atmel_sha_register_algs(struct atmel_sha_dev *dd) + + /*i = ARRAY_SIZE(sha_hmac_algs);*/ + err_sha_hmac_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_hmac_algs[j]); ++ crypto_unregister_ahashes(sha_hmac_algs, i); + i = ARRAY_SIZE(sha_384_512_algs); + err_sha_384_512_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_384_512_algs[j]); ++ crypto_unregister_ahashes(sha_384_512_algs, i); + crypto_unregister_ahash(&sha_224_alg); + err_sha_224_algs: + i = ARRAY_SIZE(sha_1_256_algs); + err_sha_1_256_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_ahash(&sha_1_256_algs[j]); ++ crypto_unregister_ahashes(sha_1_256_algs, i); + + return err; + } +diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c +index 48888b2ff7936..0bf485f350c8f 100644 +--- a/drivers/crypto/atmel-tdes.c ++++ b/drivers/crypto/atmel-tdes.c +@@ -897,38 +897,25 @@ static irqreturn_t atmel_tdes_irq(int irq, void *dev_id) + return IRQ_NONE; + } + +-static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) +- crypto_unregister_skcipher(&tdes_algs[i]); +-} +- + static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd) + { +- int err, i, j; ++ int err, i; + + for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) { + atmel_tdes_skcipher_alg_init(&tdes_algs[i]); + + err = crypto_register_skcipher(&tdes_algs[i]); +- if (err) +- goto err_tdes_algs; ++ if (err) { ++ crypto_unregister_skciphers(tdes_algs, i); ++ return err; ++ } + } + + return 0; +- +-err_tdes_algs: +- for (j = 0; j < i; j++) +- crypto_unregister_skcipher(&tdes_algs[j]); +- +- return err; + } + + static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd) + { +- + dd->caps.has_dma = 0; + + /* keep only major version number */ +@@ -1061,7 +1048,7 @@ static int atmel_tdes_remove(struct platform_device *pdev) + list_del(&tdes_dd->list); + spin_unlock(&atmel_tdes.lock); + +- atmel_tdes_unregister_algs(tdes_dd); ++ crypto_unregister_skciphers(tdes_algs, ARRAY_SIZE(tdes_algs)); + + tasklet_kill(&tdes_dd->done_task); + tasklet_kill(&tdes_dd->queue_task); +-- +2.53.0 + diff --git a/queue-6.6/crypto-ccp-copy-iv-using-skcipher-ivsize.patch b/queue-6.6/crypto-ccp-copy-iv-using-skcipher-ivsize.patch new file mode 100644 index 0000000000..6fb81f4dff --- /dev/null +++ b/queue-6.6/crypto-ccp-copy-iv-using-skcipher-ivsize.patch @@ -0,0 +1,47 @@ +From 7ae2cd3da9f2446309748a173ae78fc47cb002f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 03:07:49 -0500 +Subject: crypto: ccp - copy IV using skcipher ivsize + +From: Paul Moses + +[ Upstream commit a7a1f3cdd64d8a165d9b8c9e9ad7fb46ac19dfc4 ] + +AF_ALG rfc3686-ctr-aes-ccp requests pass an 8-byte IV to the driver. + +ccp_aes_complete() restores AES_BLOCK_SIZE bytes into the caller's IV +buffer while RFC3686 skciphers expose an 8-byte IV, so the restore +overruns the provided buffer. + +Use crypto_skcipher_ivsize() to copy only the algorithm's IV length. + +Fixes: 2b789435d7f3 ("crypto: ccp - CCP AES crypto API support") +Signed-off-by: Paul Moses +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-crypto-aes.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c +index 918e223f21b65..5a48155ea796a 100644 +--- a/drivers/crypto/ccp/ccp-crypto-aes.c ++++ b/drivers/crypto/ccp/ccp-crypto-aes.c +@@ -29,8 +29,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) + if (ret) + return ret; + +- if (ctx->u.aes.mode != CCP_AES_MODE_ECB) +- memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE); ++ if (ctx->u.aes.mode != CCP_AES_MODE_ECB) { ++ size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); ++ ++ memcpy(req->iv, rctx->iv, ivsize); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/crypto-jitterentropy-replace-long-held-spinlock-with.patch b/queue-6.6/crypto-jitterentropy-replace-long-held-spinlock-with.patch new file mode 100644 index 0000000000..8b3e339961 --- /dev/null +++ b/queue-6.6/crypto-jitterentropy-replace-long-held-spinlock-with.patch @@ -0,0 +1,109 @@ +From f819a58796f213d1b6e6ab534d65b8d49870f076 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:23:46 +0800 +Subject: crypto: jitterentropy - replace long-held spinlock with mutex + +From: Haixin Xu + +[ Upstream commit 01d798e9feb30212952d4e992801ba6bd6a82351 ] + +jent_kcapi_random() serializes the shared jitterentropy state, but it +currently holds a spinlock across the jent_read_entropy() call. That +path performs expensive jitter collection and SHA3 conditioning, so +parallel readers can trigger stalls as contending waiters spin for +the same lock. + +To prevent non-preemptible lock hold, replace rng->jent_lock with a +mutex so contended readers sleep instead of spinning on a shared lock +held across expensive entropy generation. + +Fixes: bb5530e40824 ("crypto: jitterentropy - add jitterentropy RNG") +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Haixin Xu +Reviewed-by: Stephan Mueller +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/jitterentropy-kcapi.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c +index dd05faf00571f..8ae5245081f6a 100644 +--- a/crypto/jitterentropy-kcapi.c ++++ b/crypto/jitterentropy-kcapi.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -182,7 +183,7 @@ int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len) + ***************************************************************************/ + + struct jitterentropy { +- spinlock_t jent_lock; ++ struct mutex jent_lock; + struct rand_data *entropy_collector; + struct crypto_shash *tfm; + struct shash_desc *sdesc; +@@ -192,7 +193,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) + { + struct jitterentropy *rng = crypto_tfm_ctx(tfm); + +- spin_lock(&rng->jent_lock); ++ mutex_lock(&rng->jent_lock); + + if (rng->sdesc) { + shash_desc_zero(rng->sdesc); +@@ -207,7 +208,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) + if (rng->entropy_collector) + jent_entropy_collector_free(rng->entropy_collector); + rng->entropy_collector = NULL; +- spin_unlock(&rng->jent_lock); ++ mutex_unlock(&rng->jent_lock); + } + + static int jent_kcapi_init(struct crypto_tfm *tfm) +@@ -217,7 +218,7 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) + struct shash_desc *sdesc; + int size, ret = 0; + +- spin_lock_init(&rng->jent_lock); ++ mutex_init(&rng->jent_lock); + + /* + * Use SHA3-256 as conditioner. We allocate only the generic +@@ -252,7 +253,6 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) + goto err; + } + +- spin_lock_init(&rng->jent_lock); + return 0; + + err: +@@ -267,7 +267,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, + struct jitterentropy *rng = crypto_rng_ctx(tfm); + int ret = 0; + +- spin_lock(&rng->jent_lock); ++ mutex_lock(&rng->jent_lock); + + ret = jent_read_entropy(rng->entropy_collector, rdata, dlen); + +@@ -293,7 +293,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, + ret = -EINVAL; + } + +- spin_unlock(&rng->jent_lock); ++ mutex_unlock(&rng->jent_lock); + + return ret; + } +-- +2.53.0 + diff --git a/queue-6.6/crypto-qat-use-swab32-macro.patch b/queue-6.6/crypto-qat-use-swab32-macro.patch new file mode 100644 index 0000000000..9dcc0344d3 --- /dev/null +++ b/queue-6.6/crypto-qat-use-swab32-macro.patch @@ -0,0 +1,82 @@ +From 68ae2cf2d28213d4a4beafe89ab45693e0bbb412 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 22:29:46 +0000 +Subject: crypto: qat - use swab32 macro + +From: Giovanni Cabiddu + +[ Upstream commit 35ecb77ae0749a2f1b04872c9978d9d7ddbbeb79 ] + +Replace __builtin_bswap32() with swab32 in icp_qat_hw_20_comp.h to fix +the following build errors on architectures without native byte-swap +support: + + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.o: in function `adf_gen4_build_decomp_block': + drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:141:(.text+0xeec): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:141:(.text+0xef8): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.o: in function `adf_gen4_build_comp_block': + drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:57:(.text+0xf64): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:57:(.text+0xf7c): undefined reference to `__bswapsi2' + +Fixes: 5b14b2b307e4 ("crypto: qat - enable deflate for QAT GEN4") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202603290259.Ig9kDOmI-lkp@intel.com/ +Signed-off-by: Giovanni Cabiddu +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +index 7ea8962272f2f..d28732225c9e0 100644 +--- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h ++++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +@@ -3,6 +3,8 @@ + #ifndef _ICP_QAT_HW_20_COMP_H_ + #define _ICP_QAT_HW_20_COMP_H_ + ++#include ++ + #include "icp_qat_hw_20_comp_defs.h" + #include "icp_qat_fw.h" + +@@ -54,7 +56,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_comp_20_config_csr_lower + QAT_FIELD_SET(val32, csr.abd, ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_comp_20_config_csr_upper { +@@ -106,7 +108,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_comp_20_config_csr_upper + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_decomp_20_config_csr_lower { +@@ -138,7 +140,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_decomp_20_config_csr_l + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_decomp_20_config_csr_upper { +@@ -158,7 +160,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_decomp_20_config_csr_u + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + #endif +-- +2.53.0 + diff --git a/queue-6.6/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch b/queue-6.6/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch new file mode 100644 index 0000000000..f6efdd4435 --- /dev/null +++ b/queue-6.6/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch @@ -0,0 +1,47 @@ +From 1f076eeffa2f974ac12ba8a555d452898c5c445d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 20:06:58 +0530 +Subject: crypto: sa2ul - Fix AEAD fallback algorithm names + +From: T Pratham + +[ Upstream commit 8451ab6ad686ffdcdf9ddadaa446a79ab48e5590 ] + +For authenc AEAD algorithms, sa2ul is trying to register very specific +-ce version as a fallback. This causes registration failure on SoCs +which do not have ARMv8-CE enabled/available. Change the fallback +algorithm from the specific driver name to generic algorithm name so +that the kernel can allocate any available fallback. + +Fixes: d2c8ac187fc92 ("crypto: sa2ul - Add AEAD algorithm support") +Signed-off-by: T Pratham +Reviewed-by: Manorit Chawdhry +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/sa2ul.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c +index 94eb6f6afa257..af221d5d999f2 100644 +--- a/drivers/crypto/sa2ul.c ++++ b/drivers/crypto/sa2ul.c +@@ -1775,13 +1775,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, + static int sa_cra_init_aead_sha1(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha1", +- "authenc(hmac(sha1-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha1),cbc(aes))"); + } + + static int sa_cra_init_aead_sha256(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha256", +- "authenc(hmac(sha256-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha256),cbc(aes))"); + } + + static void sa_exit_tfm_aead(struct crypto_aead *tfm) +-- +2.53.0 + diff --git a/queue-6.6/debugfs-check-for-null-pointer-in-debugfs_create_str.patch b/queue-6.6/debugfs-check-for-null-pointer-in-debugfs_create_str.patch new file mode 100644 index 0000000000..ab0679191c --- /dev/null +++ b/queue-6.6/debugfs-check-for-null-pointer-in-debugfs_create_str.patch @@ -0,0 +1,52 @@ +From 9963521ee70d348df381960dba624305388bdeb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:44 +0800 +Subject: debugfs: check for NULL pointer in debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 31de83980d3764d784f79ff1bc93c42b324f4013 ] + +Passing a NULL pointer to debugfs_create_str() leads to a NULL pointer +dereference when the debugfs file is read. Following upstream +discussions, forbid the creation of debugfs string files with NULL +pointers. Add a WARN_ON() to expose offending callers and return early. + +Fixes: 9af0440ec86e ("debugfs: Implement debugfs_create_str()") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/2025122221-gag-malt-75ba@gregkh/ +Suggested-by: Greg Kroah-Hartman +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-2-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index e40229c47fe58..3089d7146f366 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -987,7 +987,7 @@ static const struct file_operations fops_str_wo = { + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write +- * from. ++ * from. This pointer and the string it points to must not be %NULL. + * + * This function creates a file in debugfs with the given name that + * contains the value of the variable @value. If the @mode variable is so +@@ -996,6 +996,9 @@ static const struct file_operations fops_str_wo = { + void debugfs_create_str(const char *name, umode_t mode, + struct dentry *parent, char **value) + { ++ if (WARN_ON(!value || !*value)) ++ return; ++ + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } +-- +2.53.0 + diff --git a/queue-6.6/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch b/queue-6.6/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch new file mode 100644 index 0000000000..bb82aac3e5 --- /dev/null +++ b/queue-6.6/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch @@ -0,0 +1,45 @@ +From 5f507df41e2b7e951c25155db02701d69020229e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:45 +0800 +Subject: debugfs: fix placement of EXPORT_SYMBOL_GPL for debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 4afc929c0f74c4f22b055a82b371d50586da58ca ] + +The EXPORT_SYMBOL_GPL() for debugfs_create_str was placed incorrectly +away from the function definition. Move it immediately below the +debugfs_create_str() function where it belongs. + +Fixes: d60b59b96795 ("debugfs: Export debugfs_create_str symbol") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-3-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index 3089d7146f366..a9097a6c7b5a3 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -907,7 +907,6 @@ ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf, + + return ret; + } +-EXPORT_SYMBOL_GPL(debugfs_create_str); + + static ssize_t debugfs_write_file_str(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +@@ -1002,6 +1001,7 @@ void debugfs_create_str(const char *name, umode_t mode, + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } ++EXPORT_SYMBOL_GPL(debugfs_create_str); + + static ssize_t read_file_blob(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +-- +2.53.0 + diff --git a/queue-6.6/dev_printk-add-new-dev_err_probe-helpers.patch b/queue-6.6/dev_printk-add-new-dev_err_probe-helpers.patch new file mode 100644 index 0000000000..16ca558d73 --- /dev/null +++ b/queue-6.6/dev_printk-add-new-dev_err_probe-helpers.patch @@ -0,0 +1,47 @@ +From e163c7c3add28116365a997bc6ac86efa157dae6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Jun 2024 09:22:37 +0200 +Subject: dev_printk: add new dev_err_probe() helpers + +From: Nuno Sa + +[ Upstream commit dbbe7eaf0e4795bf003ac06872aaf52b6b6b1310 ] + +This is similar to dev_err_probe() but for cases where an ERR_PTR() or +ERR_CAST() is to be returned simplifying patterns like: + + dev_err_probe(dev, ret, ...); + return ERR_PTR(ret) +or + dev_err_probe(dev, PTR_ERR(ptr), ...); + return ERR_CAST(ptr) + +Signed-off-by: Nuno Sa +Link: https://patch.msgid.link/20240606-dev-add_dev_errp_probe-v3-1-51bb229edd79@analog.com +Signed-off-by: Jonathan Cameron +Stable-dep-of: 797cc011ae02 ("backlight: sky81452-backlight: Check return value of devm_gpiod_get_optional() in sky81452_bl_parse_dt()") +Signed-off-by: Sasha Levin +--- + include/linux/dev_printk.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/include/linux/dev_printk.h b/include/linux/dev_printk.h +index ae80a303c216b..ca32b5bb28eb5 100644 +--- a/include/linux/dev_printk.h ++++ b/include/linux/dev_printk.h +@@ -277,4 +277,12 @@ do { \ + + __printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...); + ++/* Simple helper for dev_err_probe() when ERR_PTR() is to be returned. */ ++#define dev_err_ptr_probe(dev, ___err, fmt, ...) \ ++ ERR_PTR(dev_err_probe(dev, ___err, fmt, ##__VA_ARGS__)) ++ ++/* Simple helper for dev_err_probe() when ERR_CAST() is to be returned. */ ++#define dev_err_cast_probe(dev, ___err_ptr, fmt, ...) \ ++ ERR_PTR(dev_err_probe(dev, PTR_ERR(___err_ptr), fmt, ##__VA_ARGS__)) ++ + #endif /* _DEVICE_PRINTK_H_ */ +-- +2.53.0 + diff --git a/queue-6.6/devres-fix-missing-node-debug-info-in-devm_krealloc.patch b/queue-6.6/devres-fix-missing-node-debug-info-in-devm_krealloc.patch new file mode 100644 index 0000000000..c5dcfb26c9 --- /dev/null +++ b/queue-6.6/devres-fix-missing-node-debug-info-in-devm_krealloc.patch @@ -0,0 +1,37 @@ +From 1d08c3fcdfa0b57187d3f9771d76614d5bc13f27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 00:48:14 +0100 +Subject: devres: fix missing node debug info in devm_krealloc() + +From: Danilo Krummrich + +[ Upstream commit f813ec9e84b4d0ca81ec1da94ab07bfb4a29266c ] + +Fix missing call to set_node_dbginfo() for new devres nodes created by +devm_krealloc(). + +Fixes: f82485722e5d ("devres: provide devm_krealloc()") +Reviewed-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/20260202235210.55176-2-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/base/devres.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index 8a0f000221271..8069b7ca26fbc 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -913,6 +913,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) + if (!new_dr) + return NULL; + ++ set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size); ++ + /* + * The spinlock protects the linked list against concurrent + * modifications but not the resource itself. +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-fix-concurrent-write-failure-in-passthrough.patch b/queue-6.6/dm-cache-fix-concurrent-write-failure-in-passthrough.patch new file mode 100644 index 0000000000..a447ff5ed8 --- /dev/null +++ b/queue-6.6/dm-cache-fix-concurrent-write-failure-in-passthrough.patch @@ -0,0 +1,84 @@ +From a2c81f99aa740d9fb84ba4e72cedaf2b53f8012f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:09 +0800 +Subject: dm cache: fix concurrent write failure in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit e4f66341779d0cf4c83c74793753a84094286d9e ] + +When bio prison cell lock acquisition fails due to concurrent writes to +the same block in passthrough mode, dm-cache incorrectly returns an I/O +error instead of properly handling the concurrency. This can occur in +both process and workqueue contexts when invalidate_lock() is called for +exclusive access to a data block. Fix this by deferring the write bios +to ensure proper block device behavior. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently. Sometimes one of the + processes will receive I/O errors. + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + + + fio-3.41 + fio: io_u error on file /dev/mapper/cache: Input/output error: write offset=4096, buflen=4096 + fio: pid=106, err=5/file:io_u.c:2008, func=io_u error, error=Input/output error + test: (groupid=0, jobs=1): err= 0: pid=105 + test: (groupid=0, jobs=1): err= 5 (file:io_u.c:2008, func=io_u error, error=Input/output error): pid=106 + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index a3a8623eff297..65ae94f64c11b 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1557,6 +1557,15 @@ static int invalidate_lock(struct dm_cache_migration *mg) + READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell); + if (r < 0) { + free_prison_cell(cache, prealloc); ++ ++ /* Defer the bio for retrying the cell lock */ ++ if (mg->overwrite_bio) { ++ struct bio *bio = mg->overwrite_bio; ++ ++ mg->overwrite_bio = NULL; ++ defer_bio(cache, bio); ++ } ++ + invalidate_complete(mg, false); + return r; + } +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch b/queue-6.6/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch new file mode 100644 index 0000000000..db09904746 --- /dev/null +++ b/queue-6.6/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch @@ -0,0 +1,151 @@ +From 5dc0d39cb4264e320c83385efcfa1fe2d54642f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:10 +0800 +Subject: dm cache: fix dirty mapping checking in passthrough mode switching + +From: Ming-Hung Tsai + +[ Upstream commit 322586745bd1a0e5f3559fd1635fdeb4dbd1d6b8 ] + +As mentioned in commit 9b1cc9f251af ("dm cache: share cache-metadata +object across inactive and active DM tables"), dm-cache assumed table +reload occurs after suspension, while LVM's table preload breaks this +assumption. The dirty mapping check for passthrough mode was designed +around this assumption and is performed during table creation, causing +the check to fail with preload while metadata updates are ongoing. This +risks loading dirty mappings into passthrough mode, resulting in data +loss. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty mappings + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Preload a table in passthrough mode + +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" + +3. Write to the first cache block to make it dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +4. Resume the inactive table. Now it's possible to load the dirty block + into passthrough mode. + +dmsetup resume cache + +Fix by moving the checks to the preresume phase to support table +preloading. Also remove the unused function dm_cache_metadata_all_clean. + +Fixes: 2ee57d587357 ("dm cache: add passthrough mode") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 11 ----------- + drivers/md/dm-cache-metadata.h | 5 ----- + drivers/md/dm-cache-target.c | 25 ++++++++----------------- + 3 files changed, 8 insertions(+), 33 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index acffed750e3ed..c9d13a30ce86d 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1756,17 +1756,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * + return r; + } + +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) +-{ +- int r; +- +- READ_LOCK(cmd); +- r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); +- READ_UNLOCK(cmd); +- +- return r; +-} +- + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) + { + WRITE_LOCK_VOID(cmd); +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 57afc70479472..24e4af14fcca4 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -138,11 +138,6 @@ void dm_cache_dump(struct dm_cache_metadata *cmd); + */ + int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p); + +-/* +- * Query method. Are all the blocks in the cache clean? +- */ +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); +- + int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); + int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 77953a171860e..8db906ea3bef0 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2510,23 +2510,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) + goto bad; + } + +- if (passthrough_mode(cache)) { +- bool all_clean; +- +- r = dm_cache_metadata_all_clean(cache->cmd, &all_clean); +- if (r) { +- *error = "dm_cache_metadata_all_clean() failed"; +- goto bad; +- } +- +- if (!all_clean) { +- *error = "Cannot enter passthrough mode unless all blocks are clean"; +- r = -EINVAL; +- goto bad; +- } +- ++ if (passthrough_mode(cache)) + policy_allow_migrations(cache->policy, false); +- } + + spin_lock_init(&cache->lock); + bio_list_init(&cache->deferred_bios); +@@ -2852,6 +2837,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + struct cache *cache = context; + + if (dirty) { ++ if (passthrough_mode(cache)) { ++ DMERR("%s: cannot enter passthrough mode unless all blocks are clean", ++ cache_device_name(cache)); ++ return -EBUSY; ++ } ++ + set_bit(from_cblock(cblock), cache->dirty_bitset); + atomic_inc(&cache->nr_dirty); + } else +@@ -3085,7 +3076,7 @@ static int cache_preresume(struct dm_target *ti) + load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- if (r != -EFBIG) ++ if (r != -EFBIG && r != -EBUSY) + metadata_operation_failed(cache, "dm_cache_load_mappings", r); + return r; + } +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-fix-missing-return-in-invalidate_committed-.patch b/queue-6.6/dm-cache-fix-missing-return-in-invalidate_committed-.patch new file mode 100644 index 0000000000..dc98c12f68 --- /dev/null +++ b/queue-6.6/dm-cache-fix-missing-return-in-invalidate_committed-.patch @@ -0,0 +1,51 @@ +From e61a8add3d2fb7f14d4fcaf8e13c10d0af450a2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 21:08:01 +0800 +Subject: dm cache: fix missing return in invalidate_committed's error path + +From: Ming-Hung Tsai + +[ Upstream commit 8c0ee19db81f0fa1ff25fd75b22b17c0cc2acde3 ] + +In passthrough mode, dm-cache defers write submission until after +metadata commit completes via the invalidate_committed() continuation. +On commit error, invalidate_committed() calls invalidate_complete() to +end the bio and free the migration struct, after which it should return +immediately. + +The patch 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +omitted this early return, causing execution to fall through into the +success path on error. This results in use-after-free on the migration +struct in the subsequent calls. + +Fix by adding the missing return after the invalidate_complete() call. + +Fixes: 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/dm-devel/adjMq6T5RRjv_uxM@stanley.mountain/ +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 8db906ea3bef0..5522f8e9443f2 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1523,8 +1523,10 @@ static void invalidate_committed(struct work_struct *ws) + struct bio *bio = mg->overwrite_bio; + struct per_bio_data *pb = get_per_bio_data(bio); + +- if (mg->k.input) ++ if (mg->k.input) { + invalidate_complete(mg, false); ++ return; ++ } + + init_continuation(&mg->k, invalidate_completed); + remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch b/queue-6.6/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch new file mode 100644 index 0000000000..abdd2157cf --- /dev/null +++ b/queue-6.6/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch @@ -0,0 +1,86 @@ +From 4c4a527dbe4c2b1dcc91e2a1d647386a9bbe66ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:05 +0800 +Subject: dm cache: fix null-deref with concurrent writes in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 7d1f98d668ee34c1d15bdc0420fdd062f24a27c0 ] + +In passthrough mode, when dm-cache starts to invalidate a cache +entry and bio prison cell lock fails due to concurrent write to +the same cached block, mg->cell remains NULL. The error path in +invalidate_complete() attempts to unlock and free the cell +unconditionally, causing a NULL pointer dereference: + +KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +CPU: 0 UID: 0 PID: 134 Comm: fio Not tainted 6.19.0-rc7 #3 PREEMPT +RIP: 0010:dm_cell_unlock_v2+0x3f/0x210 + +Call Trace: + invalidate_complete+0xef/0x430 + map_bio+0x130f/0x1a10 + cache_map+0x320/0x6b0 + __map_bio+0x458/0x510 + dm_submit_bio+0x40e/0x16d0 + __submit_bio+0x419/0x870 + + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + +Fix by checking if mg->cell is valid before attempting to unlock it. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 0d002d50329da..9c4aa5180a70e 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1458,8 +1458,10 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + struct cache *cache = mg->cache; + + bio_list_init(&bios); +- if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) +- free_prison_cell(cache, mg->cell); ++ if (mg->cell) { ++ if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) ++ free_prison_cell(cache, mg->cell); ++ } + + if (!success && mg->overwrite_bio) + bio_io_error(mg->overwrite_bio); +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-fix-write-hang-in-passthrough-mode.patch b/queue-6.6/dm-cache-fix-write-hang-in-passthrough-mode.patch new file mode 100644 index 0000000000..a88fb5b272 --- /dev/null +++ b/queue-6.6/dm-cache-fix-write-hang-in-passthrough-mode.patch @@ -0,0 +1,88 @@ +From aab6681686f2b739597761e3694db98e1fe27c50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:07 +0800 +Subject: dm cache: fix write hang in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 4ca8b8bd952df7c3ccdc68af9bd3419d0839a04b ] + +The invalidate_remove() function has incomplete logic for handling write +hit bios after cache invalidation. It sets up the remapping for the +overwrite_bio but then drops it immediately without submission, causing +write operations to hang. + +Fix by adding a new invalidate_committed() continuation that submits +the remapped writes to the cache origin after metadata commit completes, +while using the overwrite_endio hook to ensure proper completion +sequencing. This maintains existing coherency. Also improve error +handling in invalidate_complete() to preserve the original error status +instead of using bio_io_error() unconditionally. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index a2fba4ce40d7d..a3a8623eff297 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1463,8 +1463,14 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + free_prison_cell(cache, mg->cell); + } + +- if (!success && mg->overwrite_bio) +- bio_io_error(mg->overwrite_bio); ++ if (mg->overwrite_bio) { ++ // Set generic error if the bio hasn't been issued yet, ++ // e.g., invalidation or metadata commit failed before bio ++ // submission. Otherwise preserve the bio's own error status. ++ if (!success && !mg->overwrite_bio->bi_status) ++ mg->overwrite_bio->bi_status = BLK_STS_IOERR; ++ bio_endio(mg->overwrite_bio); ++ } + + free_migration(mg); + defer_bios(cache, &bios); +@@ -1504,6 +1510,22 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock) + return r; + } + ++static void invalidate_committed(struct work_struct *ws) ++{ ++ struct dm_cache_migration *mg = ws_to_mg(ws); ++ struct cache *cache = mg->cache; ++ struct bio *bio = mg->overwrite_bio; ++ struct per_bio_data *pb = get_per_bio_data(bio); ++ ++ if (mg->k.input) ++ invalidate_complete(mg, false); ++ ++ init_continuation(&mg->k, invalidate_completed); ++ remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); ++ dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg); ++ dm_submit_bio_remap(bio, NULL); ++} ++ + static void invalidate_remove(struct work_struct *ws) + { + int r; +@@ -1516,10 +1538,8 @@ static void invalidate_remove(struct work_struct *ws) + return; + } + +- init_continuation(&mg->k, invalidate_completed); ++ init_continuation(&mg->k, invalidate_committed); + continue_after_commit(&cache->committer, &mg->k); +- remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock); +- mg->overwrite_bio = NULL; + schedule_commit(&cache->committer); + } + +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch b/queue-6.6/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch new file mode 100644 index 0000000000..6ee5d50d41 --- /dev/null +++ b/queue-6.6/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch @@ -0,0 +1,85 @@ +From eb6f1cce03f0ae2eca60c9d0dfca1c1833096680 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:06 +0800 +Subject: dm cache: fix write path cache coherency in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 0c5eef0aad508231d8e43ff8392692925e131b68 ] + +In passthrough mode, dm-cache defers write bio submission until cache +invalidation completes to maintain existing coherency, requiring the +target map function to return DM_MAPIO_SUBMITTED. The current map_bio() +returns DM_MAPIO_REMAPPED, violating the required ordering constraint. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into the cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first data block, and check io ordering using ftrace + +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_queue/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_complete/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_rq_complete/enable +fio --filename=/dev/mapper/cache --name=test --rw=write --bs=64k \ +--direct=1 --size 64k + +5. ftrace logs show that write operations to the cache origin (252:2) + and metadata operations (252:0) are unsynchronized: the origin write + occurs before metadata commit. + + + fio-146 [000] ..... 420.139562: block_bio_queue: 252,3 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149395: block_bio_queue: 252,2 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149763: block_bio_queue: 8,32 WS 262144 + 128 [fio] + fio-146 [000] dNh1. 420.151446: block_rq_complete: 8,32 WS () 262144 + 128 be,0,4 [0] + fio-146 [000] dNh1. 420.152731: block_bio_complete: 252,2 WS 0 + 128 [0] + fio-146 [000] dNh1. 420.154229: block_bio_complete: 252,3 WS 0 + 128 [0] + kworker/0:0-9 [000] ..... 420.160530: block_bio_queue: 252,0 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.161641: block_bio_queue: 8,32 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162533: block_bio_queue: 252,0 W 416 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162821: block_bio_queue: 8,32 W 416 + 8 [kworker/0:0] + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 9c4aa5180a70e..a2fba4ce40d7d 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1699,6 +1699,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, + bio_drop_shared_lock(cache, bio); + atomic_inc(&cache->stats.demotion); + invalidate_start(cache, cblock, block, bio); ++ return DM_MAPIO_SUBMITTED; + } else + remap_to_origin_clear_discard(cache, bio, block); + } else { +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch b/queue-6.6/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch new file mode 100644 index 0000000000..2ed8725f5a --- /dev/null +++ b/queue-6.6/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch @@ -0,0 +1,121 @@ +From c25c8385ae3a68c39f6661c3da8f7c8737abefd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:56:28 +0800 +Subject: dm cache metadata: fix memory leak on metadata abort retry + +From: Ming-Hung Tsai + +[ Upstream commit 044ca491d4086dc5bf233e9fcb71db52df32f633 ] + +When failing to acquire the root_lock in dm_cache_metadata_abort because +the block_manager is read-only, the temporary block_manager created +outside the root_lock is not properly released, causing a memory leak. + +Reproduce steps: + +This can be reproduced by reloading a new table while the metadata +is read-only. While the second call to dm_cache_metadata_abort is +caused by lack of support for table preload in dm-cache, mentioned +in commit 9b1cc9f251af ("dm cache: share cache-metadata object across +inactive and active DM tables"), it exposes the memory leak in +dm_cache_metadata_abort when the function is called multiple times. +Specifically, dm-cache fails to sync the new cache object's mode during +preresume, creating the reproducer condition. + +This issue could also occur through concurrent metadata_operation_failed +calls due to races in cache mode updates, but the table preload scenario +below provides a reliable reproducer. + +1. Create a cache device with some faulty trailing metadata blocks + +dmsetup create cmeta < +unreferenced object 0xffff8880080c2010 (size 16): + comm "dmsetup", pid 132, jiffies 4294982580 + hex dump (first 16 bytes): + 00 38 b9 07 80 88 ff ff 6a 6b 6b 6b 6b 6b 6b a5 ... + backtrace (crc 3118f31c): + kmemleak_alloc+0x28/0x40 + __kmalloc_cache_noprof+0x3d9/0x510 + dm_block_manager_create+0x51/0x140 + dm_cache_metadata_abort+0x85/0x320 + metadata_operation_failed+0x103/0x1e0 + cache_preresume+0xacd/0xe70 + dm_table_resume_targets+0xd3/0x320 + __dm_resume+0x1b/0xf0 + dm_resume+0x127/0x170 + + +Fixes: 352b837a5541 ("dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index c9d13a30ce86d..74078b90653f3 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1023,6 +1023,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd) + return; \ + } while (0) + ++#define WRITE_LOCK_OR_GOTO(cmd, label) \ ++ do { \ ++ if (!cmd_write_lock((cmd))) \ ++ goto label; \ ++ } while (0) ++ + #define WRITE_UNLOCK(cmd) \ + up_write(&(cmd)->root_lock) + +@@ -1822,11 +1828,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, + CACHE_MAX_CONCURRENT_LOCKS); + +- WRITE_LOCK(cmd); +- if (cmd->fail_io) { +- WRITE_UNLOCK(cmd); +- goto out; +- } ++ /* cmd_write_lock() already checks fail_io with cmd->root_lock held */ ++ WRITE_LOCK_OR_GOTO(cmd, out); + + __destroy_persistent_data_objects(cmd, false); + old_bm = cmd->bm; +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch b/queue-6.6/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch new file mode 100644 index 0000000000..eda8444447 --- /dev/null +++ b/queue-6.6/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch @@ -0,0 +1,91 @@ +From 22747615b6870bbd1998ba0a63632adc1ffb1cfb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:08 +0800 +Subject: dm cache policy smq: fix missing locks in invalidating cache blocks + +From: Ming-Hung Tsai + +[ Upstream commit 2d1f7b65f5deedd2e6b09fdc6ea27f8375f24b45 ] + +In passthrough mode, the policy invalidate_mapping operation is called +simultaneously from multiple workers, thus it should be protected by a +lock. Otherwise, we might end up with data races on the allocated blocks +counter, or even use-after-free issues with internal data structures +when doing concurrent writes. + +Note that the existing FIXME in smq_invalidate_mapping() doesn't affect +passthrough mode since migration tasks don't exist there, but would need +attention if supporting fast device shrinking via suspend/resume without +target reloading. + +Reproduce steps: + +1. Create a cache device consisting of 1024 cache entries + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Populate the cache, and record the number of cached blocks + +fio --name=populate --filename=/dev/mapper/cache --rw=randwrite --bs=4k \ +--size=64m --direct=1 +nr_cached=$(dmsetup status cache | awk '{split($7, a, "/"); print a[1]}') + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the passthrough cache. By setting multiple jobs with I/O + size equal to the cache block size, cache blocks are invalidated + concurrently from different workers. + +fio --filename=/dev/mapper/cache --name=test --rw=randwrite --bs=64k \ +--direct=1 --numjobs=2 --randrepeat=0 --size=64m + +5. Check if demoted matches cached block count. These numbers should + match but may differ due to the data race. + +nr_demoted=$(dmsetup status cache | awk '{print $12}') +echo "$nr_cached, $nr_demoted" + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index 8bd2ad743d9ae..1566e040f7aac 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1589,14 +1589,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + { + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); ++ unsigned long flags; + + if (!e->allocated) + return -ENODATA; + ++ spin_lock_irqsave(&mq->lock, flags); + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ spin_unlock_irqrestore(&mq->lock, flags); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.6/dm-cache-support-shrinking-the-origin-device.patch b/queue-6.6/dm-cache-support-shrinking-the-origin-device.patch new file mode 100644 index 0000000000..9a3f437146 --- /dev/null +++ b/queue-6.6/dm-cache-support-shrinking-the-origin-device.patch @@ -0,0 +1,197 @@ +From 17642af84a1e2a3dd337d6daa6b3b73b7c9619b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 16:41:51 +0800 +Subject: dm cache: support shrinking the origin device + +From: Ming-Hung Tsai + +[ Upstream commit c2662b1544cbd8ea3181381bb899b8e681dfedc7 ] + +This patch introduces formal support for shrinking the cache origin by +reducing the cache target length via table reloads. Cache blocks mapped +beyond the new target length must be clean and are invalidated during +preresume. If any dirty blocks exist in the area being removed, the +preresume operation fails without setting the NEEDS_CHECK flag in +superblock, and the resume ioctl returns EFBIG. The cache device remains +suspended until a table reload with target length that fits existing +mappings is performed. + +Without this patch, reducing the cache target length could result in +io errors (RHBZ: 2134334), out-of-bounds memory access to the discard +bitset, and security concerns regarding data leakage. + +Verification steps: + +1. create a cache metadata with some cached blocks mapped to the tail + of the origin device. Here we use cache_restore v1.0 to build a + metadata with one clean block mapped to the last origin block. + +cat <> cmeta.xml + + + + + +EOF +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +cache_restore -i cmeta.xml -o /dev/mapper/cmeta --metadata-version=2 +dmsetup remove cmeta + +2. bring up the cache whilst shrinking the cache origin by one block: + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" +dmsetup create corig --table "0 524160 linear /dev/sdc 262144" +dmsetup create cache --table "0 524160 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +3. check the number of cached data blocks via dmsetup status. It is + expected to be zero. + +dmsetup status cache | cut -d ' ' -f 7 + +In addition to the script above, this patch can be verified using the +"cache/resize" tests in dmtest-python: + +./dmtest run --rx cache/resize/shrink_origin --result-set default + +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Stable-dep-of: 322586745bd1 ("dm cache: fix dirty mapping checking in passthrough mode switching") +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 72 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 69 insertions(+), 3 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 65ae94f64c11b..77953a171860e 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -407,6 +407,12 @@ struct cache { + mempool_t migration_pool; + + struct bio_set bs; ++ ++ /* ++ * Cache_size entries. Set bits indicate blocks mapped beyond the ++ * target length, which are marked for invalidation. ++ */ ++ unsigned long *invalid_bitset; + }; + + struct per_bio_data { +@@ -1958,6 +1964,9 @@ static void __destroy(struct cache *cache) + if (cache->discard_bitset) + free_bitset(cache->discard_bitset); + ++ if (cache->invalid_bitset) ++ free_bitset(cache->invalid_bitset); ++ + if (cache->copier) + dm_kcopyd_client_destroy(cache->copier); + +@@ -2546,6 +2555,13 @@ static int cache_create(struct cache_args *ca, struct cache **result) + } + clear_bitset(cache->discard_bitset, from_dblock(cache->discard_nr_blocks)); + ++ cache->invalid_bitset = alloc_bitset(from_cblock(cache->cache_size)); ++ if (!cache->invalid_bitset) { ++ *error = "could not allocate bitset for invalid blocks"; ++ goto bad; ++ } ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + cache->copier = dm_kcopyd_client_create(&dm_kcopyd_throttle); + if (IS_ERR(cache->copier)) { + *error = "could not create kcopyd client"; +@@ -2844,6 +2860,24 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + return policy_load_mapping(cache->policy, oblock, cblock, dirty, hint, hint_valid); + } + ++static int load_filtered_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, ++ bool dirty, uint32_t hint, bool hint_valid) ++{ ++ struct cache *cache = context; ++ ++ if (from_oblock(oblock) >= from_oblock(cache->origin_blocks)) { ++ if (dirty) { ++ DMERR("%s: unable to shrink origin; cache block %u is dirty", ++ cache_device_name(cache), from_cblock(cblock)); ++ return -EFBIG; ++ } ++ set_bit(from_cblock(cblock), cache->invalid_bitset); ++ return 0; ++ } ++ ++ return load_mapping(context, oblock, cblock, dirty, hint, hint_valid); ++} ++ + /* + * The discard block size in the on disk metadata is not + * necessarily the same as we're currently using. So we have to +@@ -2998,6 +3032,24 @@ static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size) + return 0; + } + ++static int truncate_oblocks(struct cache *cache) ++{ ++ uint32_t nr_blocks = from_cblock(cache->cache_size); ++ uint32_t i; ++ int r; ++ ++ for_each_set_bit(i, cache->invalid_bitset, nr_blocks) { ++ r = dm_cache_remove_mapping(cache->cmd, to_cblock(i)); ++ if (r) { ++ DMERR_LIMIT("%s: invalidation failed; couldn't update on disk metadata", ++ cache_device_name(cache)); ++ return r; ++ } ++ } ++ ++ return 0; ++} ++ + static int cache_preresume(struct dm_target *ti) + { + int r = 0; +@@ -3022,11 +3074,25 @@ static int cache_preresume(struct dm_target *ti) + } + + if (!cache->loaded_mappings) { ++ /* ++ * The fast device could have been resized since the last ++ * failed preresume attempt. To be safe we start by a blank ++ * bitset for cache blocks. ++ */ ++ clear_bitset(cache->invalid_bitset, from_cblock(cache->cache_size)); ++ + r = dm_cache_load_mappings(cache->cmd, cache->policy, +- load_mapping, cache); ++ load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ if (r != -EFBIG) ++ metadata_operation_failed(cache, "dm_cache_load_mappings", r); ++ return r; ++ } ++ ++ r = truncate_oblocks(cache); ++ if (r) { ++ metadata_operation_failed(cache, "dm_cache_remove_mapping", r); + return r; + } + +@@ -3492,7 +3558,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits) + + static struct target_type cache_target = { + .name = "cache", +- .version = {2, 2, 0}, ++ .version = {2, 3, 0}, + .module = THIS_MODULE, + .ctr = cache_ctr, + .dtr = cache_dtr, +-- +2.53.0 + diff --git a/queue-6.6/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch b/queue-6.6/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch new file mode 100644 index 0000000000..2ea9da7e1c --- /dev/null +++ b/queue-6.6/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch @@ -0,0 +1,58 @@ +From 501ffd584a6025cf3ea6af63198f2118812f7982 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 22:32:28 +0100 +Subject: dm init: ensure device probing has finished in dm-mod.waitfor= + +From: Guillaume Gonnet + +[ Upstream commit 99a2312f69805f4ba92d98a757625e0300a747ab ] + +The early_lookup_bdev() function returns successfully when the disk +device is present but not necessarily its partitions. In this situation, +dm_early_create() fails as the partition block device does not exist +yet. + +In my case, this phenomenon occurs quite often because the device is +an SD card with slow reading times, on which kernel takes time to +enumerate available partitions. + +Fortunately, the underlying device is back to "probing" state while +enumerating partitions. Waiting for all probing to end is enough to fix +this issue. + +That's also the reason why this problem never occurs with rootwait= +parameter: the while loop inside wait_for_root() explicitly waits for +probing to be done and then the function calls async_synchronize_full(). +These lines were omitted in 035641b, even though the commit says it's +based on the rootwait logic... + +Anyway, calling wait_for_device_probe() after our while loop does the +job (it both waits for probing and calls async_synchronize_full). + +Fixes: 035641b01e72 ("dm init: add dm-mod.waitfor to wait for asynchronously probed block devices") +Signed-off-by: Guillaume Gonnet +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-init.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c +index b37bbe7625003..423269cbdd2bb 100644 +--- a/drivers/md/dm-init.c ++++ b/drivers/md/dm-init.c +@@ -303,8 +303,10 @@ static int __init dm_init_init(void) + } + } + +- if (waitfor[0]) ++ if (waitfor[0]) { ++ wait_for_device_probe(); + DMINFO("all devices available"); ++ } + + list_for_each_entry(dev, &devices, list) { + if (dm_early_create(&dev->dmi, dev->table, +-- +2.53.0 + diff --git a/queue-6.6/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch b/queue-6.6/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch new file mode 100644 index 0000000000..7237876544 --- /dev/null +++ b/queue-6.6/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch @@ -0,0 +1,81 @@ +From 3079a8cd0d4389353116fa7a7b8c9aa780afd9b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:05:48 +0800 +Subject: dm log: fix out-of-bounds write due to region_count overflow + +From: Junrui Luo + +[ Upstream commit c20e36b7631d83e7535877f08af8b0af72c44b1a ] + +The local variable region_count in create_log_context() is declared as +unsigned int (32-bit), but dm_sector_div_up() returns sector_t (64-bit). +When a device-mapper target has a sufficiently large ti->len with a small +region_size, the division result can exceed UINT_MAX. The truncated +value is then used to calculate bitset_size, causing clean_bits, +sync_bits, and recovering_bits to be allocated far smaller than needed +for the actual number of regions. + +Subsequent log operations (log_set_bit, log_clear_bit, log_test_bit) use +region indices derived from the full untruncated region space, causing +out-of-bounds writes to kernel heap memory allocated by vmalloc. + +This can be reproduced by creating a mirror target whose region_count +overflows 32 bits: + + dmsetup create bigzero --table '0 8589934594 zero' + dmsetup create mymirror --table '0 8589934594 mirror \ + core 2 2 nosync 2 /dev/mapper/bigzero 0 \ + /dev/mapper/bigzero 0' + +The status output confirms the truncation (sync_count=1 instead of +4294967297, because 0x100000001 was truncated to 1): + + $ dmsetup status mymirror + 0 8589934594 mirror 2 254:1 254:1 1/4294967297 ... + +This leads to a kernel crash in core_in_sync: + + BUG: scheduling while atomic: (udev-worker)/9150/0x00000000 + RIP: 0010:core_in_sync+0x14/0x30 [dm_log] + CR2: 0000000000000008 + Fixing recursive fault but reboot is needed! + +Fix by widening the local region_count to sector_t and adding an +explicit overflow check before the value is assigned to lc->region_count. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-log.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c +index e215478bcee04..94d3f13e673e9 100644 +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -373,7 +373,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + + struct log_c *lc; + uint32_t region_size; +- unsigned int region_count; ++ sector_t region_count; + size_t bitset_size, buf_size; + int r; + char dummy; +@@ -401,6 +401,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + } + + region_count = dm_sector_div_up(ti->len, region_size); ++ if (region_count > UINT_MAX) { ++ DMWARN("region count exceeds limit of %u", UINT_MAX); ++ return -EINVAL; ++ } + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) { +-- +2.53.0 + diff --git a/queue-6.6/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch b/queue-6.6/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch new file mode 100644 index 0000000000..fad3dcd716 --- /dev/null +++ b/queue-6.6/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch @@ -0,0 +1,50 @@ +From 1c9824473eb86f3ff6e22ca88d37cead2c2ead77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 14:02:19 +0800 +Subject: dmaengine: dw-axi-dmac: Remove unnecessary return statement from void + function + +From: Khairul Anuar Romli + +[ Upstream commit 48278a72fce8a8d30efaedeb206c9c3f05c1eb3f ] + +checkpatch.pl --strict reports a WARNING in dw-axi-dmac-platform.c: + + WARNING: void function return statements are not generally useful + FILE: drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c + +According to Linux kernel coding style [Documentation/process/ +coding-style.rst], explicit "return;" statements at the end of void +functions are redundant and should be omitted. The function will +automatically return upon reaching the closing brace, so the extra +statement adds unnecessary clutter without functional benefit. + +This patch removes the superfluous "return;" statement in +dw_axi_dma_set_hw_channel() to comply with kernel coding standards and +eliminate the checkpatch warning. + +Fixes: 32286e279385 ("dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel") +Signed-off-by: Khairul Anuar Romli +Link: https://patch.msgid.link/20260202060224.12616-4-karom.9560@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index 72fb40de58b3f..3ea3e203253a9 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -546,8 +546,6 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) + (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0); +- +- return; + } + + /* +-- +2.53.0 + diff --git a/queue-6.6/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch b/queue-6.6/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch new file mode 100644 index 0000000000..3fefed525c --- /dev/null +++ b/queue-6.6/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch @@ -0,0 +1,37 @@ +From 73ad1a733c1513a1ad1f6a653b521f0629ef9232 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:41:38 -0500 +Subject: dmaengine: mxs-dma: Fix missing return value from + of_dma_controller_register() + +From: Frank Li + +[ Upstream commit ab2bf6d4c0a0152907b18d25c1b118ea5ea779df ] + +Propagate the return value of of_dma_controller_register() in probe() +instead of ignoring it. + +Fixes: a580b8c5429a6 ("dmaengine: mxs-dma: add dma support for i.MX23/28") +Signed-off-by: Frank Li +Link: https://patch.msgid.link/20260225-mxsdma-module-v3-2-8f798b13baa6@nxp.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mxs-dma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c +index cfb9962417ef6..53f572b6b6fc6 100644 +--- a/drivers/dma/mxs-dma.c ++++ b/drivers/dma/mxs-dma.c +@@ -824,6 +824,7 @@ static int mxs_dma_probe(struct platform_device *pdev) + if (ret) { + dev_err(mxs_dma->dma_device.dev, + "failed to register controller\n"); ++ return ret; + } + + dev_info(mxs_dma->dma_device.dev, "initialized\n"); +-- +2.53.0 + diff --git a/queue-6.6/documentation-fix-a-hugetlbfs-reservation-statement.patch b/queue-6.6/documentation-fix-a-hugetlbfs-reservation-statement.patch new file mode 100644 index 0000000000..7af3bb417c --- /dev/null +++ b/queue-6.6/documentation-fix-a-hugetlbfs-reservation-statement.patch @@ -0,0 +1,63 @@ +From 5cea1cae566900f533987ff3b70fbac97ea193c5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 13:10:15 -0700 +Subject: Documentation: fix a hugetlbfs reservation statement + +From: Jane Chu + +[ Upstream commit 7a197d346a44384a1a858a98ef03766840e561d4 ] + +Documentation/mm/hugetlbfs_reserv.rst has + if (resv_needed <= (resv_huge_pages - free_huge_pages)) + resv_huge_pages += resv_needed; +which describes this code in gather_surplus_pages() + needed = (h->resv_huge_pages + delta) - h->free_huge_pages; + if (needed <= 0) { + h->resv_huge_pages += delta; + return 0; + } +which means if there are enough free hugepages to account for the new +reservation, simply update the global reservation count without +further action. + +But the description is backwards, it should be + if (resv_needed <= (free_huge_pages - resv_huge_pages)) +instead. + +Link: https://lkml.kernel.org/r/20260302201015.1824798-1-jane.chu@oracle.com +Fixes: 70bc0dc578b3 ("Documentation: vm, add hugetlbfs reservation overview") +Signed-off-by: Jane Chu +Cc: David Hildenbrand +Cc: Hillf Danton +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Oscar Salvador +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/mm/hugetlbfs_reserv.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/mm/hugetlbfs_reserv.rst b/Documentation/mm/hugetlbfs_reserv.rst +index 4914fbf07966c..a49115db18c76 100644 +--- a/Documentation/mm/hugetlbfs_reserv.rst ++++ b/Documentation/mm/hugetlbfs_reserv.rst +@@ -155,7 +155,7 @@ are enough free huge pages to accommodate the reservation. If there are, + the global reservation count resv_huge_pages is adjusted something like the + following:: + +- if (resv_needed <= (resv_huge_pages - free_huge_pages)) ++ if (resv_needed <= (free_huge_pages - resv_huge_pages) + resv_huge_pages += resv_needed; + + Note that the global lock hugetlb_lock is held when checking and adjusting +-- +2.53.0 + diff --git a/queue-6.6/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch b/queue-6.6/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch new file mode 100644 index 0000000000..050874dc94 --- /dev/null +++ b/queue-6.6/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch @@ -0,0 +1,54 @@ +From ff686342f0158cd1ced4ab0d9a1331275b98f89a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:06 +0000 +Subject: dpaa2: add independent dependencies for FSL_DPAA2_SWITCH + +From: Cai Xinchen + +[ Upstream commit 12589892f41c4c645c80ef9f036f7451a6045624 ] + +Since the commit 84cba72956fd ("dpaa2-switch: integrate +the MAC endpoint support") included dpaa2-mac.o in the driver, +but it didn't select PCS_LYNX, PHYLINK and FSL_XGMAC_MDIO. it +will lead to link error, such as +undefined reference to `phylink_ethtool_ksettings_set' +undefined reference to `lynx_pcs_create_fwnode' + +And the same reason as the commit d2624e70a2f53 ("dpaa2-eth: select +XGMAC_MDIO for MDIO bus support"), enable the FSL_XGMAC_MDIO Kconfig +option in order to have MDIO access to internal and external PHYs. + +Because dpaa2-switch uses fsl_mc_driver APIs, add depends on FSL_MC_BUS +&& FSL_MC_DPIO as FSL_DPAA2_SWITCH do. + +FSL_XGMAC_MDIO and FSL_MC_BUS depend on OF, thus the dependence of +FSL_MC_BUS can satisfy FSL_XGMAC_MDIO's OF requirement. + +Fixes: 84cba72956fd ("dpaa2-switch: integrate the MAC endpoint support") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-2-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/dpaa2/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig +index d029b69c3f183..36280e5d99e1f 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig ++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig +@@ -34,6 +34,10 @@ config FSL_DPAA2_SWITCH + tristate "Freescale DPAA2 Ethernet Switch" + depends on BRIDGE || BRIDGE=n + depends on NET_SWITCHDEV ++ depends on FSL_MC_BUS && FSL_MC_DPIO ++ select PHYLINK ++ select PCS_LYNX ++ select FSL_XGMAC_MDIO + help + Driver for Freescale DPAA2 Ethernet Switch. This driver manages + switch objects discovered on the Freeescale MC bus. +-- +2.53.0 + diff --git a/queue-6.6/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch b/queue-6.6/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch new file mode 100644 index 0000000000..9e7cc44b63 --- /dev/null +++ b/queue-6.6/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch @@ -0,0 +1,42 @@ +From bbd1af18440e309fd404a8570ffc573631268849 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:07 +0000 +Subject: dpaa2: compile dpaa2 even CONFIG_FSL_DPAA2_ETH=n + +From: Cai Xinchen + +[ Upstream commit 97daf00745f7f9f261b0e91418de6e79d7826c36 ] + +CONFIG_FSL_DPAA2_ETH and CONFIG_FSL_DPAA2_SWITCH are not +associated, but the compilation of FSL_DPAA2_SWITCH depends on +the compilation of the dpaa2 folder. The files controlled by +CONFIG_FSL_DPAA2_SWITCH in the dpaa2 folder are not controlled +by CONFIG_FSL_DPAA2_ETH, except for the files controlled by +CONFIG_FSL_DPAA2_SWITCH. Therefore, removing the restriction will +not affect the compilation of the files in the directory. + +Fixes: f48298d3fbfaa ("staging: dpaa2-switch: move the driver out of staging") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-3-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/Makefile | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile +index de7b318422330..d0a259e47960f 100644 +--- a/drivers/net/ethernet/freescale/Makefile ++++ b/drivers/net/ethernet/freescale/Makefile +@@ -22,6 +22,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o + obj-$(CONFIG_FSL_FMAN) += fman/ + obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/ + +-obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/ +- ++obj-y += dpaa2/ + obj-y += enetc/ +-- +2.53.0 + diff --git a/queue-6.6/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch b/queue-6.6/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch new file mode 100644 index 0000000000..204d581d17 --- /dev/null +++ b/queue-6.6/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch @@ -0,0 +1,59 @@ +From 258471c8a87a85a38dc514dbad25698bbb72d9fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:40:54 -0700 +Subject: drbd: Balance RCU calls in drbd_adm_dump_devices() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bart Van Assche + +[ Upstream commit 2b31e86387e60b3689339f0f0fbb4d3623d9d494 ] + +Make drbd_adm_dump_devices() call rcu_read_lock() before +rcu_read_unlock() is called. This has been detected by the Clang +thread-safety analyzer. + +Tested-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Cc: Andreas Gruenbacher +Fixes: a55bbd375d18 ("drbd: Backport the "status" command") +Signed-off-by: Bart Van Assche +Link: https://patch.msgid.link/20260326214054.284593-1-bvanassche@acm.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_nl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index d3538bd83fb3b..1ba81a5e77215 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -3368,8 +3368,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + cb->args[0] = (long)resource; + } + } +@@ -3618,8 +3620,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + } + cb->args[0] = (long)resource; + } +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch b/queue-6.6/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch new file mode 100644 index 0000000000..80c325e442 --- /dev/null +++ b/queue-6.6/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch @@ -0,0 +1,45 @@ +From 6c7632a1625ff15ca1199b728c2a44f046fcb118 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:41 +0200 +Subject: drm/amd/display: Allow DCE link encoder without AUX registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ] + +Allow constructing the DCE link encoder without DDC, +which means the AUX registers array will be NULL. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 87f30b101af62590faf6020d106da07efdda199b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index 0a33f8f117e92..623abdf7065e7 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -989,7 +989,9 @@ void dce110_link_encoder_hw_init( + ASSERT(result == BP_RESULT_OK); + + } +- aux_initialize(enc110); ++ ++ if (enc110->aux_regs) ++ aux_initialize(enc110); + + /* reinitialize HPD. + * hpd_initialize() will pass DIG_FE id to HW context. +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch b/queue-6.6/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch new file mode 100644 index 0000000000..f1d974ab86 --- /dev/null +++ b/queue-6.6/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch @@ -0,0 +1,137 @@ +From 81f81e0fa246d1ab318b50a25c1236b654776041 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:44 +0200 +Subject: drm/amd/display: Read EDID from VBIOS embedded panel info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ] + +Some board manufacturers hardcode the EDID for the embedded +panel in the VBIOS. This EDID should be used when the panel +doesn't have a DDC. + +For reference, see the legacy non-DC display code: +amdgpu_atombios_encoder_get_lcd_info() + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364) +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ + .../display/include/grph_object_ctrl_defs.h | 4 ++ + 2 files changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index 684b005f564c4..ac2a71e80723d 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1220,6 +1220,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( + return BP_RESULT_FAILURE; + } + ++static enum bp_result get_embedded_panel_extra_info( ++ struct bios_parser *bp, ++ struct embedded_panel_info *info, ++ const uint32_t table_offset) ++{ ++ uint8_t *record = bios_get_image(&bp->base, table_offset, 1); ++ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; ++ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ++ ++ while (*record != ATOM_RECORD_END_TYPE) { ++ switch (*record) { ++ case LCD_MODE_PATCH_RECORD_MODE_TYPE: ++ record += sizeof(ATOM_PATCH_RECORD_MODE); ++ break; ++ case LCD_RTS_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_RTS_RECORD); ++ break; ++ case LCD_CAP_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); ++ break; ++ case LCD_FAKE_EDID_PATCH_RECORD_TYPE: ++ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; ++ if (fake_edid_record->ucFakeEDIDLength) { ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength; ++ else ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength * 128; ++ ++ info->fake_edid = fake_edid_record->ucFakeEDIDString; ++ ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ info->fake_edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; ++ } ++ break; ++ case LCD_PANEL_RESOLUTION_RECORD_TYPE: ++ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; ++ info->panel_width_mm = panel_res_record->usHSize; ++ info->panel_height_mm = panel_res_record->usVSize; ++ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); ++ break; ++ default: ++ return BP_RESULT_BADBIOSTABLE; ++ } ++ } ++ ++ return BP_RESULT_OK; ++} ++ + static enum bp_result get_embedded_panel_info_v1_2( + struct bios_parser *bp, + struct embedded_panel_info *info) +@@ -1336,6 +1390,10 @@ static enum bp_result get_embedded_panel_info_v1_2( + if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) + info->lcd_timing.misc_info.API_ENABLED = true; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +@@ -1461,6 +1519,10 @@ static enum bp_result get_embedded_panel_info_v1_3( + (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & + lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +index 813463ffe15c5..8e776c90d21bf 100644 +--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h ++++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +@@ -153,6 +153,10 @@ struct embedded_panel_info { + uint32_t drr_enabled; + uint32_t min_drr_refresh_rate; + bool realtek_eDPToLVDS; ++ uint16_t panel_width_mm; ++ uint16_t panel_height_mm; ++ uint16_t fake_edid_size; ++ const uint8_t *fake_edid; + }; + + struct dc_firmware_info { +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch b/queue-6.6/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch new file mode 100644 index 0000000000..9cbd1f6454 --- /dev/null +++ b/queue-6.6/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch @@ -0,0 +1,38 @@ +From d7d11a8588082cd750f45203fac67ea780fc8ee6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:03 +0200 +Subject: drm/amd/pm/ci: Clear EnabledForActivity field for memory levels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 5facfd4c4c67e8500116ffec0d9da35d92b9c787 ] + +Follow what radeon did and what amdgpu does for other GPUs with SMU7. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index b600a87fbb005..4a0e8887fa74b 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1217,7 +1217,7 @@ static int ci_populate_single_memory_level( + } + + memory_level->EnabledForThrottle = 1; +- memory_level->EnabledForActivity = 1; ++ memory_level->EnabledForActivity = 0; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; + memory_level->VoltageDownH = 0; +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch b/queue-6.6/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch new file mode 100644 index 0000000000..c95aff9a17 --- /dev/null +++ b/queue-6.6/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch @@ -0,0 +1,67 @@ +From 864f6e4f3d5f39a6b674160def47bbb138034e0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:59 +0200 +Subject: drm/amd/pm/ci: Disable MCLK DPM on problematic CI ASICs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9851f29cb06c09f7dad3867d8b0feec3fc71b6c8 ] + +There are two known cases where MCLK DPM can causes issues: + +Radeon R9 M380 found in iMac computers from 2015. +The SMU in this GPU just hangs as soon as we send it the +PPSMC_MSG_MCLKDPM_Enable command, even when MCLK switching is +disabled, and even when we only populate one MCLK DPM level. +Apply workaround to all devices with the same subsystem ID. + +Radeon R7 260X due to old memory controller microcode. +We only flash the MC ucode when it isn't set up by the VBIOS, +therefore there is no way to make sure that it has the correct +ucode version. + +I verified that this patch fixes the SMU hang on the R9 M380 +which would previously fail to boot. This also fixes the UVD +initialization error on that GPU which happened because the +SMU couldn't ungate the UVD after it hung. + +Fixes: 86457c3b21cb ("drm/amd/powerplay: Add support for CI asics to hwmgr") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +index 2b5ac21fee399..1d6e30269d567 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) + PP_GFXOFF_MASK); + hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; ++ switch (hwmgr->chip_id) { ++ case CHIP_BONAIRE: ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM ++ * R7 260X cards with old MC ucode: MCLK DPM is unstable ++ */ ++ if (adev->pdev->subsystem_vendor == 0x106B || ++ adev->pdev->device == 0x6658) { ++ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); ++ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; ++ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; ++ } ++ break; ++ default: ++ break; ++ } + smu7_init_function_pointers(hwmgr); + break; + case AMDGPU_FAMILY_CZ: +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch b/queue-6.6/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch new file mode 100644 index 0000000000..970873719b --- /dev/null +++ b/queue-6.6/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch @@ -0,0 +1,48 @@ +From 21f5b2e6f0359a6d3f6b728b3f96ab0cb6043e7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:04 +0200 +Subject: drm/amd/pm/ci: Fill DW8 fields from SMC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit baf28ec5795c077406d6f52b8ad39e614153bce6 ] + +In ci_populate_dw8() we currently just read a value from the SMU +and then throw it away. Instead of throwing away the value, +we should use it to fill other fields in DW8 (like radeon). + +Otherwise the value of the other fiels is just cleared when +we copy this data to the SMU later. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 4a0e8887fa74b..741ebeb276b84 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) + { + struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); + const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; +- uint32_t temp; + + if (ci_read_smc_sram_dword(hwmgr, + fuse_table_offset + + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), +- (uint32_t *)&temp, SMC_RAM_END)) ++ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) + PP_ASSERT_WITH_CODE(false, + "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", + return -EINVAL); +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch b/queue-6.6/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch new file mode 100644 index 0000000000..c493dd0485 --- /dev/null +++ b/queue-6.6/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch @@ -0,0 +1,41 @@ +From 495c645148f47811283eaf56cff9affaed71778f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:02 +0200 +Subject: drm/amd/pm/ci: Fix powertune defaults for Hawaii 0x67B0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit d784759c07924280f3c313f205fc48eb62d7cb71 ] + +There is no AMD GPU with the ID 0x66B0, this looks like a typo. +It should be 0x67B0 which is actually part of the PCI ID list, +and should use the Hawaii XT powertune defaults according to +the old radeon driver. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index fa9ab4144d308..b600a87fbb005 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) + smu_data->power_tune_defaults = &defaults_hawaii_pro; + break; + case 0x67B8: +- case 0x66B0: ++ case 0x67B0: + smu_data->power_tune_defaults = &defaults_hawaii_xt; + break; + case 0x6640: +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch b/queue-6.6/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch new file mode 100644 index 0000000000..83241547b0 --- /dev/null +++ b/queue-6.6/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch @@ -0,0 +1,47 @@ +From e85694b5fb1fdf57327aa4bf1a64974b06f708d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:58 +0200 +Subject: drm/amd/pm/ci: Use highest MCLK on CI when MCLK DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 894f0d34d66cb47fe718fe2ae5c18729d22c5218 ] + +When MCLK DPM is disabled for any reason, populate the MCLK +table with the highest MCLK DPM level, so that the ASIC can +use the highest possible memory clock to get good performance +even when MCLK DPM is disabled. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 23f991dd065f3..fa9ab4144d308 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1322,6 +1322,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) + return result; + } + ++ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { ++ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ ++ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { ++ levels[i] = levels[dpm_table->mclk_table.count - 1]; ++ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; ++ } ++ } ++ + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; + + dev_id = adev->pdev->device; +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch b/queue-6.6/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch new file mode 100644 index 0000000000..9dfced6841 --- /dev/null +++ b/queue-6.6/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch @@ -0,0 +1,129 @@ +From 529db59027b354c19993650ab1cdf65d5b83ad9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:05 +0200 +Subject: drm/amd/pm/smu7: Add SCLK cap for quirky Hawaii board +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 4724bc5b8d78c34b993594f9406135408ccb312a ] + +On a specific Radeon R9 390X board, the GPU can "randomly" hang +while gaming. Initially I thought this was a RADV bug and tried +to work around this in Mesa: +commit 8ea08747b86b ("radv: Mitigate GPU hang on Hawaii in Dota 2 and RotTR") + +However, I got some feedback from other users who are reporting +that the above mitigation causes a significant performance +regression for them, and they didn't experience the hang on their +GPU in the first place. + +After some further investigation, it turns out that the problem +is that the highest SCLK DPM level on this board isn't stable. +Lowering SCLK to 1040 MHz (from 1070 MHz) works around the issue, +and has a negligible impact on performance compared to the Mesa +patch. (Note that increasing the voltage can also work around it, +but we felt that lowering the SCLK is the safer option.) + +To solve the above issue, add an "sclk_cap" field to smu7_hwmgr +and set this field for the affected board. The capped SCLK value +correctly appears on the sysfs interface and shows up in GUI +tools such as LACT. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 30 ++++++++++++++++--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h | 1 + + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index 9c2a2c46dea02..9dc01de3e7207 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.vddc_dependency_on_mclk; + struct phm_cac_leakage_table *std_voltage_table = + hwmgr->dyn_state.cac_leakage_table; +- uint32_t i; ++ uint32_t i, clk; + + PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, + "SCLK dependency table is missing. This table is mandatory", return -EINVAL); +@@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + data->dpm_table.sclk_table.count = 0; + + for (i = 0; i < allowed_vdd_sclk_table->count; i++) { ++ clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); ++ + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != +- allowed_vdd_sclk_table->entries[i].clk) { ++ clk) { + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = +- allowed_vdd_sclk_table->entries[i].clk; ++ clk; + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; + data->dpm_table.sclk_table.count++; + } +@@ -3006,6 +3008,25 @@ static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr * + return 0; + } + ++static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) ++{ ++ struct amdgpu_device *adev = hwmgr->adev; ++ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); ++ ++ data->sclk_cap = 0xffffffff; ++ ++ if (hwmgr->od_enabled) ++ return; ++ ++ /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ ++ if (adev->pdev->device == 0x67B0 && ++ adev->pdev->subsystem_vendor == 0x1043) ++ data->sclk_cap = 104000; /* 1040 MHz */ ++ ++ if (data->sclk_cap != 0xffffffff) ++ dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -3017,6 +3038,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + return -ENOMEM; + + hwmgr->backend = data; ++ smu7_set_sclk_cap(hwmgr); + smu7_patch_voltage_workaround(hwmgr); + smu7_init_dpm_defaults(hwmgr); + +@@ -3903,7 +3925,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, + + /* Performance levels are arranged from low to high. */ + performance_level->memory_clock = memory_clock; +- performance_level->engine_clock = engine_clock; ++ performance_level->engine_clock = min(engine_clock, data->sclk_cap); + + pcie_gen_from_bios = visland_clk_info->ucPCIEGen; + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +index d9e8b386bd4d3..66adabeab6a3a 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +@@ -234,6 +234,7 @@ struct smu7_hwmgr { + uint32_t pcie_gen_cap; + uint32_t pcie_lane_cap; + uint32_t pcie_spc_cap; ++ uint32_t sclk_cap; + struct smu7_leakage_voltage vddc_leakage; + struct smu7_leakage_voltage vddci_leakage; + struct smu7_leakage_voltage vddcgfx_leakage; +-- +2.53.0 + diff --git a/queue-6.6/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch b/queue-6.6/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch new file mode 100644 index 0000000000..3992aaa13f --- /dev/null +++ b/queue-6.6/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch @@ -0,0 +1,192 @@ +From 906c89bec0439b79a58d864361ab3c42e7f8c642 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:00 +0200 +Subject: drm/amd/pm/smu7: Fix SMU7 voltage dependency on display clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 0138610c14130425be53423b35336561829965e0 ] + +The DCE (display controller engine) requires a minimum voltage +in order to function correctly, depending on which clock level +it currently uses. + +Add a new table that contains display clock frequency levels +and the corresponding required voltages. The clock frequency +levels are taken from DC (and the old radeon driver's voltage +dependency table for CI in cases where its values were lower). +The voltage levels are taken from the following function: +phm_initializa_dynamic_state_adjustment_rule_settings(). +Furthermore, in case of CI, call smu7_patch_vddc() on the new +table to account for leakage voltage (like in radeon). + +Use the display clock value from amd_pp_display_configuration +to look up the voltage level needed by the DCE. Send the +voltage to the SMU via the PPSMC_MSG_VddC_Request command. + +The previous implementation of this feature was non-functional +because it relied on a "dal_power_level" field which was never +assigned; and it was not at all implemented for CI ASICs. + +I verified this on a Radeon R9 M380 which previously booted to +a black screen with DC enabled (default since Linux 6.19), but +now works correctly. + +Fixes: 599a7e9fe1b6 ("drm/amd/powerplay: implement smu7 hwmgr to manager asics with smu ip version 7.") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 88 ++++++++++++++++++- + drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h | 1 + + 2 files changed, 86 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index 965ffcac17f86..9c2a2c46dea02 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -2802,6 +2802,10 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) + if (tmp) + return -EINVAL; + ++ tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ if (tmp) ++ return -EINVAL; ++ + tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); + if (tmp) + return -EINVAL; +@@ -2885,6 +2889,8 @@ static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) + { + kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); + hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; ++ kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; + kfree(hwmgr->backend); + hwmgr->backend = NULL; + +@@ -2955,6 +2961,51 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) + return ret; + } + ++static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) ++{ ++ struct phm_clock_voltage_dependency_table *table; ++ ++ if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) ++ return 0; ++ ++ table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); ++ if (!table) ++ return -ENOMEM; ++ ++ if (hwmgr->chip_id >= CHIP_POLARIS10) { ++ table->entries[0].clk = 38918; ++ table->entries[1].clk = 45900; ++ table->entries[2].clk = 66700; ++ table->entries[3].clk = 113200; ++ ++ table->entries[0].v = 700; ++ table->entries[1].v = 740; ++ table->entries[2].v = 800; ++ table->entries[3].v = 900; ++ } else { ++ if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { ++ table->entries[0].clk = 35200; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 46700; ++ table->entries[3].clk = 64300; ++ } else { ++ table->entries[0].clk = 0; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 54000; ++ table->entries[3].clk = 62500; ++ } ++ ++ table->entries[0].v = 0; ++ table->entries[1].v = 720; ++ table->entries[2].v = 810; ++ table->entries[3].v = 900; ++ } ++ ++ table->count = 4; ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = table; ++ return 0; ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -2983,6 +3034,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + smu7_get_elb_voltages(hwmgr); + } + ++ result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); ++ if (result) ++ goto fail; ++ + if (hwmgr->pp_table_version == PP_TABLE_V1) { + smu7_complete_dependency_tables(hwmgr); + smu7_set_private_data_based_on_pptable_v1(hwmgr); +@@ -3079,13 +3134,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) + return 0; + } + ++static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) ++{ ++ const struct amd_pp_display_configuration *cfg = hwmgr->display_config; ++ const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = ++ hwmgr->dyn_state.vddc_dependency_on_display_clock; ++ uint32_t i; ++ ++ if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || ++ !cfg || !cfg->num_display || !cfg->display_clk) ++ return 0; ++ ++ /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ ++ for (i = 1; i < vddc_dep_on_dispclk->count; ++i) ++ if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) ++ return vddc_dep_on_dispclk->entries[i].v; ++ ++ return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; ++} ++ ++static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) ++{ ++ uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_VddC_Request, ++ req_vddc * VOLTAGE_SCALE, ++ NULL); ++} ++ + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) + { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + +- if (hwmgr->pp_table_version == PP_TABLE_V1) +- phm_apply_dal_min_voltage_request(hwmgr); +-/* TO DO for v0 iceland and Ci*/ ++ smu7_apply_minimum_dce_voltage_request(hwmgr); + + if (!data->sclk_dpm_key_disabled) { + if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) +diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +index 81650727a5def..6e7e6318b9505 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +@@ -632,6 +632,7 @@ struct phm_dynamic_state_info { + struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; ++ struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; + struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; + struct phm_clock_array *valid_sclk_values; + struct phm_clock_array *valid_mclk_values; +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch b/queue-6.6/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch new file mode 100644 index 0000000000..fc8a3f8c8a --- /dev/null +++ b/queue-6.6/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch @@ -0,0 +1,54 @@ +From d70581f5917f754ff016a6c350c6ba3f68bc7acd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 19:29:54 +0530 +Subject: drm/amdgpu: Add default case in DVI mode validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit e6020a55b8e364d15eac27f9c788e13114eec6b7 ] + +amdgpu_connector_dvi_mode_valid() assigns max_digital_pixel_clock_khz +based on connector_object_id using a switch statement that lacks a +default case. + +In practice this code path should never be hit because the existing +cases already cover all digital connector types that this function is +used for. This is also legacy display code which is not used for new +hardware. + +Add a default case returning MODE_BAD to make the switch exhaustive and +silence the static analyzer smatch error. The new branch is effectively +defensive and should never be reached during normal operation. + +Fixes: 585b2f685c56 ("drm/amdgpu: Respect max pixel clock for HDMI and DVI-D (v2)") +Cc: Dan Carpenter +Cc: Timur Kristóf +Cc: Alex Deucher +Cc: Christian König +Signed-off-by: Srinivasan Shanmugam +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +index 52c093e42531b..5f4fef27177b4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +@@ -1257,6 +1257,8 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector + case CONNECTOR_OBJECT_ID_HDMI_TYPE_B: + max_digital_pixel_clock_khz = max_dvi_single_link_pixel_clock * 2; + break; ++ default: ++ return MODE_BAD; + } + + /* When the display EDID claims that it's an HDMI display, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch b/queue-6.6/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch new file mode 100644 index 0000000000..0e15db52c3 --- /dev/null +++ b/queue-6.6/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch @@ -0,0 +1,133 @@ +From 49f7107285723e55505344eb96d6ab2acd18cc95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 15:52:45 +0200 +Subject: drm/amdgpu: fix AMDGPU_INFO_READ_MMR_REG +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 0ef196a208385b7d7da79f411c161b04e97283e2 ] + +There were multiple issues in that code. + +First of all the order between the reset semaphore and the mm_lock was +wrong (e.g. copy_to_user) was called while holding the lock. + +Then we allocated memory while holding the reset semaphore which is also +a pretty big bug and can deadlock. + +Then we used down_read_trylock() instead of waiting for the reset to +finish. + +Signed-off-by: Christian König +Fixes: 9e823f307074 ("drm/amdgpu: Block MMR_READ IOCTL in reset") +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit 361b6e6b303d4b691f6c5974d3eaab67ca6dd90e) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 57 +++++++++++-------------- + 1 file changed, 24 insertions(+), 33 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +index 10730f256ae0f..4c678048be63b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +@@ -724,68 +724,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + ? -EFAULT : 0; + } + case AMDGPU_INFO_READ_MMR_REG: { +- int ret = 0; +- unsigned int n, alloc_size; +- uint32_t *regs; + unsigned int se_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SE_INDEX_MASK; + unsigned int sh_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SH_INDEX_MASK; +- +- if (!down_read_trylock(&adev->reset_domain->sem)) +- return -ENOENT; ++ unsigned int alloc_size; ++ uint32_t *regs; ++ int ret; + + /* set full masks if the userspace set all bits + * in the bitfields + */ +- if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) { ++ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) + se_num = 0xffffffff; +- } else if (se_num >= AMDGPU_GFX_MAX_SE) { +- ret = -EINVAL; +- goto out; +- } ++ else if (se_num >= AMDGPU_GFX_MAX_SE) ++ return -EINVAL; + +- if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { ++ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) + sh_num = 0xffffffff; +- } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { +- ret = -EINVAL; +- goto out; +- } ++ else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) ++ return -EINVAL; + +- if (info->read_mmr_reg.count > 128) { +- ret = -EINVAL; +- goto out; +- } ++ if (info->read_mmr_reg.count > 128) ++ return -EINVAL; + +- regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); +- if (!regs) { +- ret = -ENOMEM; +- goto out; +- } ++ regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), ++ GFP_KERNEL); ++ if (!regs) ++ return -ENOMEM; + ++ down_read(&adev->reset_domain->sem); + alloc_size = info->read_mmr_reg.count * sizeof(*regs); +- + amdgpu_gfx_off_ctrl(adev, false); ++ ret = 0; + for (i = 0; i < info->read_mmr_reg.count; i++) { + if (amdgpu_asic_read_register(adev, se_num, sh_num, + info->read_mmr_reg.dword_offset + i, + ®s[i])) { + DRM_DEBUG_KMS("unallowed offset %#x\n", + info->read_mmr_reg.dword_offset + i); +- kfree(regs); +- amdgpu_gfx_off_ctrl(adev, true); + ret = -EFAULT; +- goto out; ++ break; + } + } + amdgpu_gfx_off_ctrl(adev, true); +- n = copy_to_user(out, regs, min(size, alloc_size)); +- kfree(regs); +- ret = (n ? -EFAULT : 0); +-out: + up_read(&adev->reset_domain->sem); ++ ++ if (!ret) { ++ ret = copy_to_user(out, regs, min(size, alloc_size)) ++ ? -EFAULT : 0; ++ } ++ kfree(regs); + return ret; + } + case AMDGPU_INFO_DEV_INFO: { +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-fix-spelling-typos.patch b/queue-6.6/drm-amdgpu-fix-spelling-typos.patch new file mode 100644 index 0000000000..d68b00b687 --- /dev/null +++ b/queue-6.6/drm-amdgpu-fix-spelling-typos.patch @@ -0,0 +1,103 @@ +From 6db1e937d528bd2cf40c1508392dab73720e5386 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Feb 2025 00:05:04 -0500 +Subject: drm/amdgpu: fix spelling typos + +From: Alexandre Demers + +[ Upstream commit ce43abd7ec9464cf954f90e1c69e11768b02fa0a ] + +Found some typos while exploring amdgpu code. + +Signed-off-by: Alexandre Demers +Signed-off-by: Alex Deucher +Stable-dep-of: 13e4cf116dbf ("drm/amdgpu/uvd3.1: Don't validate the firmware when already validated") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 6 +++--- + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 3 ++- + drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | 2 +- + 4 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index 8cb192636368f..1584936f29510 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -264,7 +264,7 @@ void amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc + * @adev: amdgpu device structure holding all necessary information + * @mc: memory controller structure holding memory information + * +- * Function will place try to place GART before or after VRAM. ++ * Function will try to place GART before or after VRAM. + * If GART size is bigger than space left then we ajust GART size. + * Thus function will never fails. + */ +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index 1e0189f90fd6a..191057db58db3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -98,7 +98,7 @@ static void uvd_v3_1_ring_emit_ib(struct amdgpu_ring *ring, + } + + /** +- * uvd_v3_1_ring_emit_fence - emit an fence & trap command ++ * uvd_v3_1_ring_emit_fence - emit a fence & trap command + * + * @ring: amdgpu_ring pointer + * @addr: address +@@ -242,7 +242,7 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + +- /* programm the VCPU memory controller bits 0-27 */ ++ /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; + WREG32(mmUVD_VCPU_CACHE_OFFSET0, addr); +@@ -416,7 +416,7 @@ static int uvd_v3_1_start(struct amdgpu_device *adev) + /* Set the write pointer delay */ + WREG32(mmUVD_RBC_RB_WPTR_CNTL, 0); + +- /* programm the 4GB memory segment for rptr and ring buffer */ ++ /* Program the 4GB memory segment for rptr and ring buffer */ + WREG32(mmUVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) | + (0x7 << 16) | (0x1 << 31)); + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +index c108b83817951..01d8e7d2caf97 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +@@ -298,7 +298,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) + /* enable VCPU clock */ + WREG32(mmUVD_VCPU_CNTL, 1 << 9); + +- /* disable interupt */ ++ /* disable interrupt */ + WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1)); + + #ifdef __BIG_ENDIAN +@@ -308,6 +308,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) + #endif + WREG32(mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl); + WREG32(mmUVD_MP_SWAP_CNTL, mp_swap_cntl); ++ + /* initialize UVD memory controller */ + WREG32(mmUVD_LMI_CTRL, 0x203108); + +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +index 67eb01fef789b..479eb9382c77e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +@@ -278,7 +278,7 @@ static int vce_v2_0_stop(struct amdgpu_device *adev) + int status; + + if (vce_v2_0_lmi_clean(adev)) { +- DRM_INFO("vce is not idle \n"); ++ DRM_INFO("VCE is not idle \n"); + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch b/queue-6.6/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch new file mode 100644 index 0000000000..e5733f7469 --- /dev/null +++ b/queue-6.6/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch @@ -0,0 +1,40 @@ +From e85c19f2e9382de07ecd5bd2f5c099b7963e68b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:18:28 -0500 +Subject: drm/amdgpu/gfx10: look at the right prop for gfx queue priority +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit 355d96cdec5c61fd83f7eb54f1a28e38809645d6 ] + +Look at hqd_queue_priority rather than hqd_pipe_priority. +In practice, it didn't matter as both were always set for +kernel queues, but that will change in the future. + +Fixes: b07d1d73b09e ("drm/amd/amdgpu: Enable high priority gfx queue") +Reviewed-by:Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 1c29b4d04a2ca..afa9eb7050751 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -6338,7 +6338,7 @@ static void gfx_v10_0_gfx_mqd_set_priority(struct amdgpu_device *adev, + /* set up default queue priority level + * 0x0 = low priority, 0x1 = high priority + */ +- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) ++ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) + priority = 1; + + tmp = RREG32_SOC15(GC, 0, mmCP_GFX_HQD_QUEUE_PRIORITY); +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch b/queue-6.6/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch new file mode 100644 index 0000000000..c30b3b92c6 --- /dev/null +++ b/queue-6.6/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch @@ -0,0 +1,146 @@ +From 1ce50596236f5edcf3f2489c855ea97c56e9db5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:33 +0200 +Subject: drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ] + +This commit fixes amdgpu to work on the Radeon HD 7870 XT +which has never worked with the Linux open source drivers before. + +Some boards have "harvested" chips, meaning that some parts of +the chip are disabled and fused, and it's sold for cheaper and +under a different marketing name. +On a harvested chip, any of the following can be disabled: +- CUs (Compute Units) +- RBs (Render Backend, aka. ROP) +- Memory channels (ie. the chip has a lower bandwidth) +- TCCs (ie. less L2 cache) + +Handle chips with harvested TCCs by patching the registers +that configure how TCCs are mapped. + +If some TCCs are disabled, we need to make sure that +the disabled TCCs are not used, and the remaining TCCs +are used optimally. + +TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. + +Note that the TCC configuration is highly relevant to performance. +Suboptimal configuration (eg. CHAN_STEER=0) can significantly +reduce gaming performance. + +For optimal performance: +- Rely on the CHAN_STEER from the golden registers table, + only skip disabled TCCs but keep the mapping order. +- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, + which performs better than using the same TCC twice. + +v2: +- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs. + +Link: https://bugs.freedesktop.org/show_bug.cgi?id=60879 +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2664 +Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 00218d15528fab9f6b31241fe5904eea4fcaa30d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index 34f9211b26793..d4f0437001089 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -1554,6 +1554,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) + mutex_unlock(&adev->grbm_idx_mutex); + } + ++/** ++ * gfx_v6_0_setup_tcc() - setup which TCCs are used ++ * ++ * @adev: amdgpu_device pointer ++ * ++ * Verify whether the current GPU has any TCCs disabled, ++ * which can happen when the GPU is harvested and some ++ * memory channels are disabled, reducing the memory bus width. ++ * For example, on the Radeon HD 7870 XT (Tahiti LE). ++ * ++ * If some TCCs are disabled, we need to make sure that ++ * the disabled TCCs are not used, and the remaining TCCs ++ * are used optimally. ++ * ++ * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. ++ * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. ++ * ++ * For optimal performance: ++ * - Rely on the CHAN_STEER from the golden registers table, ++ * only skip disabled TCCs but keep the mapping order. ++ * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, ++ * which performs better than using the same TCC twice. ++ */ ++static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) ++{ ++ u32 i, tcc, tcp_addr_config, num_active_tcc = 0; ++ u64 chan_steer, patched_chan_steer = 0; ++ const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; ++ const u32 dis_tcc_mask = ++ amdgpu_gfx_create_bitmask(num_max_tcc) & ++ (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), ++ CGTS_TCC_DISABLE, TCC_DISABLE) | ++ REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), ++ CGTS_USER_TCC_DISABLE, TCC_DISABLE)); ++ ++ /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ ++ if (!dis_tcc_mask) ++ return; ++ ++ /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ ++ chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); ++ ++ /* Patch the TCP to TCC mapping to skip disabled TCCs */ ++ for (i = 0; i < num_max_tcc; ++i) { ++ tcc = (chan_steer >> (u64)(4 * i)) & 0xf; ++ ++ if (!((1 << tcc) & dis_tcc_mask)) { ++ /* Copy enabled TCC indices to the patched register value. */ ++ patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); ++ ++num_active_tcc; ++ } ++ } ++ ++ WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); ++ ++ /* Patch number of TCCs used by TCPs */ ++ tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), ++ TCP_ADDR_CONFIG, NUM_TCC_BANKS, ++ num_active_tcc - 1); ++ ++ WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); ++ WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); ++ WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); ++} ++ + static void gfx_v6_0_config_init(struct amdgpu_device *adev) + { + adev->gfx.config.double_offchip_lds_buf = 0; +@@ -1712,6 +1777,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) + gfx_v6_0_tiling_mode_table_init(adev); + + gfx_v6_0_setup_rb(adev); ++ gfx_v6_0_setup_tcc(adev); + + gfx_v6_0_setup_spi(adev); + +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch new file mode 100644 index 0000000000..7bac88e746 --- /dev/null +++ b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch @@ -0,0 +1,41 @@ +From a0d7db6d113a0d1b3e926062639d35a5d77a62e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v2.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit e5f612dc91650561fe2b5b76dd6d2898ec9ad480 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 6ac27241106b ("drm/amdgpu: add JPEG v2.0 function supports") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 96179da0c6b059eb31706a0abe8dd6381c533143) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +index fbe57499495ec..c2b9829c12fd9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +@@ -764,6 +764,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_0_dec_ring_get_rptr, + .get_wptr = jpeg_v2_0_dec_ring_get_wptr, + .set_wptr = jpeg_v2_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch new file mode 100644 index 0000000000..343b88faa7 --- /dev/null +++ b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch @@ -0,0 +1,49 @@ +From a002a95fcef9010c3febbaafc98d580b82d0ed56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v2.5 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 79405e774ede411c6b47ed41c651e40b92de64a2 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 14f43e8f88c5 ("drm/amdgpu: move JPEG2.5 out from VCN2.5") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 3216a7f4e2642bda5fd14f57586e835ae9202587) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +index aadb74de52bcf..1d2e5201bbca1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +@@ -657,6 +657,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, +@@ -686,6 +687,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch new file mode 100644 index 0000000000..8e2df479df --- /dev/null +++ b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch @@ -0,0 +1,41 @@ +From b17541b8182823d48a1cbdabf83c3764ebcd5149 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v3.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit a2baf12eec41f246689e6a3f8619af1200031576 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: dfd57dbf44dd ("drm/amdgpu: add JPEG3.0 support for Sienna_Cichlid") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 4d7d774f100efb5089c86a1fb8c5bf47c63fc9ef) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +index df4440c21bbf4..f587664cf31a7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +@@ -562,6 +562,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v3_0_dec_ring_get_rptr, + .get_wptr = jpeg_v3_0_dec_ring_get_wptr, + .set_wptr = jpeg_v3_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch new file mode 100644 index 0000000000..4101ab9d1a --- /dev/null +++ b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch @@ -0,0 +1,41 @@ +From 80f88bfe21be49383e61396b3e85ddd7a5239968 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit e7e90b5839aeb8805ec83bb4da610b8dab8e184d ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: b13111de32a9 ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_0") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 8d0cac9478a3f046279c657d6a2545de49ae675a) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +index 3eb3dcd56b579..9d4eb9c8885f1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +@@ -722,6 +722,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch new file mode 100644 index 0000000000..465d2ce700 --- /dev/null +++ b/queue-6.6/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch @@ -0,0 +1,41 @@ +From bf52a1466f7af16467ff2580eddaa0d295a5c613 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.3 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 83e37c0987ca92f9e87789b46dd311dcf5a4a6c8 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: e684e654eba9 ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_3") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 2f6afc97d259d530f4f86c7743efbc573a8da927) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +index 78aaaee492e11..210177c738554 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +@@ -1054,6 +1054,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch b/queue-6.6/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch new file mode 100644 index 0000000000..402d510d7e --- /dev/null +++ b/queue-6.6/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch @@ -0,0 +1,65 @@ +From 15b0461930dbeda3a5c307a84a88e90c8a3e97a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:31 +0200 +Subject: drm/amdgpu/uvd3.1: Don't validate the firmware when already validated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ] + +UVD 3.1 firmware validation seems to always fail after +attempting it when it had already been validated. +(This works similarly with the VCE 1.0 as well.) + +Don't attempt repeating the validation when it's already done. + +This caused issues in situations when the system isn't able +to suspend the GPU properly and so the GPU isn't actually +powered down. Then amdgpu would fail when calling the IP +block resume function. + +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2887 +Fixes: bb7978111dd3 ("drm/amdgpu: fix SI UVD firmware validate resume fail") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 889a2cfd889c4a4dd9d0c89ce9a8e60b78be71dd) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index 191057db58db3..49a0d66d5b2c0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + ++ /* When the keyselect is already set, don't perturb it. */ ++ if (RREG32(mmUVD_FW_START)) ++ return; ++ + /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; +@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) + int i; + uint32_t keysel = adev->uvd.keyselect; + ++ if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { ++ dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", ++ RREG32(mmUVD_FW_START), adev->uvd.keyselect); ++ return 0; ++ } ++ + WREG32(mmUVD_FW_START, keysel); + + for (i = 0; i < 10; ++i) { +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch b/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch new file mode 100644 index 0000000000..02281a9c60 --- /dev/null +++ b/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch @@ -0,0 +1,49 @@ +From 20961a1c352a3278394349436282aabe61f091f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v2.0 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8d80b293b41fcb5e9396db93e788b0f4ebcbafb7 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 1b61de45dfaf ("drm/amdgpu: add initial VCN2.0 support (v2)") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit e2b5499fca55f1a32960a311bbb62e35891eaf73) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index 2505951ad06a0..1a9c8e9e854df 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -2014,6 +2014,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = { + static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v2_0_dec_ring_get_rptr, + .get_wptr = vcn_v2_0_dec_ring_get_wptr, +@@ -2045,6 +2046,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v2_0_enc_ring_get_rptr, + .get_wptr = vcn_v2_0_enc_ring_get_wptr, + .set_wptr = vcn_v2_0_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch b/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch new file mode 100644 index 0000000000..e77cecc166 --- /dev/null +++ b/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch @@ -0,0 +1,49 @@ +From a51c2f11fa85464f61a7b83b38e7785ef0428eca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v2.5 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 4f317863a3ab212a027d8c8c3cc3af4e3fb95704 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 28c17d72072b ("drm/amdgpu: add VCN2.5 basic supports") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit efc9dd5590894109bce9a0bfe1fa5592dd6b20b1) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +index 6fbea38f4d3e1..fa0459ed079ca 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +@@ -1573,6 +1573,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring) + static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v2_5_dec_ring_get_rptr, + .get_wptr = vcn_v2_5_dec_ring_get_wptr, +@@ -1673,6 +1674,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v2_5_enc_ring_get_rptr, + .get_wptr = vcn_v2_5_enc_ring_get_wptr, + .set_wptr = vcn_v2_5_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch b/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch new file mode 100644 index 0000000000..531ee8e4e5 --- /dev/null +++ b/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch @@ -0,0 +1,57 @@ +From 404c3049e24828577a147667822264387d3039eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v3.0 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit f1e5a6660d7cbf006079126d9babbf0ccf538c6b ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: cf14826cdfb5 ("drm/amdgpu: add VCN3.0 support for Sienna_Cichlid") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 663bed3c7b8b9a7624b0d95d300ddae034ad0614) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +index c9345da548a61..37b93af917fe2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +@@ -1737,6 +1737,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0x3f, + .nop = VCN_DEC_SW_CMD_NO_OP, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v3_0_dec_ring_get_rptr, + .get_wptr = vcn_v3_0_dec_ring_get_wptr, +@@ -1918,6 +1919,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v3_0_dec_ring_get_rptr, + .get_wptr = vcn_v3_0_dec_ring_get_wptr, +@@ -2019,6 +2021,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v3_0_enc_ring_get_rptr, + .get_wptr = vcn_v3_0_enc_ring_get_wptr, + .set_wptr = vcn_v3_0_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch b/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch new file mode 100644 index 0000000000..21864dd6a6 --- /dev/null +++ b/queue-6.6/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch @@ -0,0 +1,41 @@ +From b821d4783d1e5c13e5809b2b159039542464cc37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0.3 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 4532b52b34e4e4310386e6fdf6a643368599f522 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: b889ef4ac988 ("drm/amdgpu/vcn: add vcn support for VCN4_0_3") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit ff1a5a125c5a70c328806b9bc01d7d942cf3f9aa) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +index d1141a9baa916..3379469ab04c1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +@@ -1423,6 +1423,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, + .set_wptr = vcn_v4_0_3_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch b/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch new file mode 100644 index 0000000000..9a9e1b17fa --- /dev/null +++ b/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch @@ -0,0 +1,75 @@ +From 4f8d19031947ce34f0145d868f9b36deffad4142 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:28 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Add mode_valid hook to + drm_bridge_funcs + +From: Jayesh Choudhary + +[ Upstream commit 6dbff34016052b099558b76632e4983e2df13fed ] + +Add cdns_mhdp_bridge_mode_valid() to check if specific mode is valid for +this bridge or not. In the legacy usecase with +!DRM_BRIDGE_ATTACH_NO_CONNECTOR we were using the hook from +drm_connector_helper_funcs but with DRM_BRIDGE_ATTACH_NO_CONNECTOR +we need to have mode_valid() in drm_bridge_funcs. + +Without this patch, when using DRM_BRIDGE_ATTACH_NO_CONNECTOR +flag, the cdns_mhdp_bandwidth_ok() function would not be called +during mode validation, potentially allowing modes that exceed +the bridge's bandwidth capabilities to be incorrectly marked as +valid. + +Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") +Reviewed-by: Tomi Valkeinen +Signed-off-by: Jayesh Choudhary +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Link: https://patch.msgid.link/20251209120332.3559893-3-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 8037a41f9afd2..34a3348375171 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2234,6 +2234,25 @@ static struct edid *cdns_mhdp_bridge_get_edid(struct drm_bridge *bridge, + return cdns_mhdp_get_edid(mhdp, connector); + } + ++static enum drm_mode_status ++cdns_mhdp_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); ++ ++ mutex_lock(&mhdp->link_mutex); ++ ++ if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes, ++ mhdp->link.rate)) { ++ mutex_unlock(&mhdp->link_mutex); ++ return MODE_CLOCK_HIGH; ++ } ++ ++ mutex_unlock(&mhdp->link_mutex); ++ return MODE_OK; ++} ++ + static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { + .atomic_enable = cdns_mhdp_atomic_enable, + .atomic_disable = cdns_mhdp_atomic_disable, +@@ -2248,6 +2267,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { + .get_edid = cdns_mhdp_bridge_get_edid, + .hpd_enable = cdns_mhdp_bridge_hpd_enable, + .hpd_disable = cdns_mhdp_bridge_hpd_disable, ++ .mode_valid = cdns_mhdp_bridge_mode_valid, + }; + + static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse) +-- +2.53.0 + diff --git a/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch b/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch new file mode 100644 index 0000000000..22f05f0bf7 --- /dev/null +++ b/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch @@ -0,0 +1,75 @@ +From ffee45d3955ae1a494511e8e80f7141a2dc40e89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:29 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Handle HDCP state in bridge + atomic check + +From: Harikrishna Shenoy + +[ Upstream commit 4a8edd658489ec2a3d7e20482fa9e8d366153d8d ] + +Now that we have DRM_BRIDGE_ATTACH_NO_CONNECTOR framework, handle the +HDCP state change in bridge atomic check as well to enable correct +functioning for HDCP in both DRM_BRIDGE_ATTACH_NO_CONNECTOR and +!DRM_BRIDGE_ATTACH_NO_CONNECTOR case. + +Without this patch, when using DRM_BRIDGE_ATTACH_NO_CONNECTOR flag, HDCP +state changes would not be properly handled during atomic commits, +potentially leading to HDCP authentication failures or incorrect +protection status for content requiring HDCP encryption. + +Fixes: 6a3608eae6d33 ("drm: bridge: cdns-mhdp8546: Enable HDCP") +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Reviewed-by: Tomi Valkeinen +Link: https://patch.msgid.link/20251209120332.3559893-4-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 34a3348375171..44955601a9dfc 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2196,6 +2196,10 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, + { + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; ++ struct drm_connector_state *old_state, *new_state; ++ struct drm_atomic_state *state = crtc_state->state; ++ struct drm_connector *conn = mhdp->connector_ptr; ++ u64 old_cp, new_cp; + + mutex_lock(&mhdp->link_mutex); + +@@ -2215,6 +2219,25 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, + if (mhdp->info) + bridge_state->input_bus_cfg.flags = *mhdp->info->input_bus_flags; + ++ if (conn && mhdp->hdcp_supported) { ++ old_state = drm_atomic_get_old_connector_state(state, conn); ++ new_state = drm_atomic_get_new_connector_state(state, conn); ++ old_cp = old_state->content_protection; ++ new_cp = new_state->content_protection; ++ ++ if (old_state->hdcp_content_type != new_state->hdcp_content_type && ++ new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { ++ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; ++ crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); ++ crtc_state->mode_changed = true; ++ } ++ ++ if (!new_state->crtc) { ++ if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ++ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; ++ } ++ } ++ + mutex_unlock(&mhdp->link_mutex); + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch b/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch new file mode 100644 index 0000000000..ad635cbae5 --- /dev/null +++ b/queue-6.6/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch @@ -0,0 +1,196 @@ +From c8ce002de35bd23171a5d07353e5da7cbbe82d65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:27 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Set the mhdp connector + earlier in atomic_enable() + +From: Jayesh Choudhary + +[ Upstream commit 43d6508ddbf9fb974fbc359a033154f78c9d4c8b ] + +In case if we get errors in cdns_mhdp_link_up() or cdns_mhdp_reg_read() +in atomic_enable, we will go to cdns_mhdp_modeset_retry_fn() and will hit +NULL pointer while trying to access the mutex. We need the connector to +be set before that. Unlike in legacy cases with flag +!DRM_BRIDGE_ATTACH_NO_CONNECTOR, we do not have connector initialised +in bridge_attach(), so add the mhdp->connector_ptr in device structure +to handle both cases with DRM_BRIDGE_ATTACH_NO_CONNECTOR and +!DRM_BRIDGE_ATTACH_NO_CONNECTOR, set it in atomic_enable() earlier to +avoid possible NULL pointer dereference in recovery paths like +modeset_retry_fn() with the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag set. + +Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") +Signed-off-by: Jayesh Choudhary +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Reviewed-by: Tomi Valkeinen +Link: https://patch.msgid.link/20251209120332.3559893-2-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 29 ++++++++++--------- + .../drm/bridge/cadence/cdns-mhdp8546-core.h | 1 + + .../drm/bridge/cadence/cdns-mhdp8546-hdcp.c | 18 +++++++++--- + 3 files changed, 30 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index bdb9fc00c776b..8037a41f9afd2 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -810,7 +810,7 @@ static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context) + bridge_attached = mhdp->bridge_attached; + spin_unlock(&mhdp->start_lock); + if (bridge_attached) { +- if (mhdp->connector.dev) ++ if (mhdp->connector_ptr) + drm_kms_helper_hotplug_event(mhdp->bridge.dev); + else + drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); +@@ -1709,6 +1709,7 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp) + return ret; + } + ++ mhdp->connector_ptr = conn; + drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs); + + ret = drm_display_info_set_bus_formats(&conn->display_info, +@@ -1988,17 +1989,25 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state = bridge_state->base.state; + struct cdns_mhdp_bridge_state *mhdp_state; + struct drm_crtc_state *crtc_state; +- struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_bridge_state *new_state; + const struct drm_display_mode *mode; + u32 resp; +- int ret; ++ int ret = 0; + + dev_dbg(mhdp->dev, "bridge enable\n"); + + mutex_lock(&mhdp->link_mutex); + ++ mhdp->connector_ptr = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); ++ if (WARN_ON(!mhdp->connector_ptr)) ++ goto out; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, mhdp->connector_ptr); ++ if (WARN_ON(!conn_state)) ++ goto out; ++ + if (mhdp->plugged && !mhdp->link_up) { + ret = cdns_mhdp_link_up(mhdp); + if (ret < 0) +@@ -2018,15 +2027,6 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, + resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN); + +- connector = drm_atomic_get_new_connector_for_encoder(state, +- bridge->encoder); +- if (WARN_ON(!connector)) +- goto out; +- +- conn_state = drm_atomic_get_new_connector_state(state, connector); +- if (WARN_ON(!conn_state)) +- goto out; +- + if (mhdp->hdcp_supported && + mhdp->hw_state == MHDP_HW_READY && + conn_state->content_protection == +@@ -2103,6 +2103,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, + if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable) + mhdp->info->ops->disable(mhdp); + ++ mhdp->connector_ptr = NULL; + mutex_unlock(&mhdp->link_mutex); + } + +@@ -2368,7 +2369,7 @@ static void cdns_mhdp_modeset_retry_fn(struct work_struct *work) + + mhdp = container_of(work, typeof(*mhdp), modeset_retry_work); + +- conn = &mhdp->connector; ++ conn = mhdp->connector_ptr; + + /* Grab the locks before changing connector property */ + mutex_lock(&conn->dev->mode_config.mutex); +@@ -2445,7 +2446,7 @@ static void cdns_mhdp_hpd_work(struct work_struct *work) + int ret; + + ret = cdns_mhdp_update_link_status(mhdp); +- if (mhdp->connector.dev) { ++ if (mhdp->connector_ptr) { + if (ret < 0) + schedule_work(&mhdp->modeset_retry_work); + else +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +index bad2fc0c73066..a76775c768956 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +@@ -376,6 +376,7 @@ struct cdns_mhdp_device { + struct mutex link_mutex; + + struct drm_connector connector; ++ struct drm_connector *connector_ptr; + struct drm_bridge bridge; + + struct cdns_mhdp_link link; +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +index 5e3b8edcf7948..2866069805524 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +@@ -394,7 +394,7 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) + int ret; + + dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", +- mhdp->connector.name, mhdp->connector.base.id); ++ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); + + ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); + +@@ -436,6 +436,10 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) + int ret = 0; + + mutex_lock(&mhdp->hdcp.mutex); ++ ++ if (!mhdp->connector_ptr) ++ goto out; ++ + if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + goto out; + +@@ -445,7 +449,7 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) + + dev_err(mhdp->dev, + "[%s:%d] HDCP link failed, retrying authentication\n", +- mhdp->connector.name, mhdp->connector.base.id); ++ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); + + ret = _cdns_mhdp_hdcp_disable(mhdp); + if (ret) { +@@ -487,13 +491,19 @@ static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) + struct cdns_mhdp_device *mhdp = container_of(hdcp, + struct cdns_mhdp_device, + hdcp); +- struct drm_device *dev = mhdp->connector.dev; ++ struct drm_device *dev = NULL; + struct drm_connector_state *state; + ++ if (mhdp->connector_ptr) ++ dev = mhdp->connector_ptr->dev; ++ ++ if (!dev) ++ return; ++ + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { +- state = mhdp->connector.state; ++ state = mhdp->connector_ptr->state; + state->content_protection = mhdp->hdcp.value; + } + mutex_unlock(&mhdp->hdcp.mutex); +-- +2.53.0 + diff --git a/queue-6.6/drm-i915-constify-watermark-state-checker.patch b/queue-6.6/drm-i915-constify-watermark-state-checker.patch new file mode 100644 index 0000000000..4b09b9805b --- /dev/null +++ b/queue-6.6/drm-i915-constify-watermark-state-checker.patch @@ -0,0 +1,54 @@ +From 8f527762e8f19f9ea5867418b8a2dc566e43940d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Oct 2023 18:56:00 +0300 +Subject: drm/i915: Constify watermark state checker +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 487a2db8bc4eb79c53c9ff8fca65a7fc8350df6c ] + +The skl+ wm state checker has no reason to modify the crtc state, +so make it const. + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20231004155607.7719-6-ville.syrjala@linux.intel.com +Reviewed-by: Jani Nikula +Stable-dep-of: a97c88a176b6 ("drm/i915/wm: Verify the correct plane DDB entry") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 2 +- + drivers/gpu/drm/i915/display/skl_watermark.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index 063929a42a42f..8a82576ca0289 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3133,7 +3133,7 @@ static void skl_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915) + } + + void intel_wm_state_verify(struct intel_crtc *crtc, +- struct intel_crtc_state *new_crtc_state) ++ const struct intel_crtc_state *new_crtc_state) + { + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct skl_hw_state { +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h +index f91a3d4ddc075..3aa138d387900 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.h ++++ b/drivers/gpu/drm/i915/display/skl_watermark.h +@@ -39,7 +39,7 @@ bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb, + int num_entries, int ignore_idx); + + void intel_wm_state_verify(struct intel_crtc *crtc, +- struct intel_crtc_state *new_crtc_state); ++ const struct intel_crtc_state *new_crtc_state); + + void skl_watermark_ipc_init(struct drm_i915_private *i915); + void skl_watermark_ipc_update(struct drm_i915_private *i915); +-- +2.53.0 + diff --git a/queue-6.6/drm-i915-extract-intel_dbuf_mdclk_cdclk_ratio_update.patch b/queue-6.6/drm-i915-extract-intel_dbuf_mdclk_cdclk_ratio_update.patch new file mode 100644 index 0000000000..bf16bd26bc --- /dev/null +++ b/queue-6.6/drm-i915-extract-intel_dbuf_mdclk_cdclk_ratio_update.patch @@ -0,0 +1,101 @@ +From e20fbb3cb11658208d381ec2cc09f4092dfc1dff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Mar 2024 13:36:35 -0300 +Subject: drm/i915: Extract intel_dbuf_mdclk_cdclk_ratio_update() + +From: Gustavo Sousa + +[ Upstream commit 66a0e0681392420b326f00ba732e6bda099eda29 ] + +As of Xe2LPD, it is now possible to select the source of the MDCLK +as either the CD2XCLK or the CDCLK PLL. + +Previous display IPs were hardcoded to use the CD2XCLK. For those, the +ratio between MDCLK and CDCLK remained constant, namely 2. For Xe2LPD, +when we select the CDCLK PLL as the source, the ratio will vary +according to the squashing configuration (since the cd2x divisor is +fixed for all supported configurations). + +To help the transition to supporting changes in the ratio, extract the +function intel_dbuf_mdclk_cdclk_ratio_update() from the existing logic +and call it using 2 as hardcoded ratio. Upcoming changes will use that +function for updates in the ratio due to CDCLK changes. + +Bspec: 50057, 69445, 49213, 68868 +Reviewed-by: Matt Roper +Signed-off-by: Gustavo Sousa +Link: https://patchwork.freedesktop.org/patch/msgid/20240312163639.172321-5-gustavo.sousa@intel.com +Signed-off-by: Lucas De Marchi +Stable-dep-of: a97c88a176b6 ("drm/i915/wm: Verify the correct plane DDB entry") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 30 +++++++++++++------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index d77e598deb2d9..6c657ef8b45b4 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3472,6 +3472,21 @@ int intel_dbuf_init(struct drm_i915_private *i915) + return 0; + } + ++static void intel_dbuf_mdclk_cdclk_ratio_update(struct drm_i915_private *i915, ++ u8 ratio, ++ bool joined_mbus) ++{ ++ enum dbuf_slice slice; ++ ++ if (joined_mbus) ++ ratio *= 2; ++ ++ for_each_dbuf_slice(i915, slice) ++ intel_de_rmw(i915, DBUF_CTL_S(slice), ++ DBUF_MIN_TRACKER_STATE_SERVICE_MASK, ++ DBUF_MIN_TRACKER_STATE_SERVICE(ratio - 1)); ++} ++ + /* + * Configure MBUS_CTL and all DBUF_CTL_S of each slice to join_mbus state before + * update the request state of all DBUS slices. +@@ -3479,8 +3494,7 @@ int intel_dbuf_init(struct drm_i915_private *i915) + static void update_mbus_pre_enable(struct intel_atomic_state *state) + { + struct drm_i915_private *i915 = to_i915(state->base.dev); +- u32 mbus_ctl, dbuf_min_tracker_val; +- enum dbuf_slice slice; ++ u32 mbus_ctl; + const struct intel_dbuf_state *dbuf_state = + intel_atomic_get_new_dbuf_state(state); + +@@ -3491,24 +3505,18 @@ static void update_mbus_pre_enable(struct intel_atomic_state *state) + * TODO: Implement vblank synchronized MBUS joining changes. + * Must be properly coordinated with dbuf reprogramming. + */ +- if (dbuf_state->joined_mbus) { ++ if (dbuf_state->joined_mbus) + mbus_ctl = MBUS_HASHING_MODE_1x4 | MBUS_JOIN | + MBUS_JOIN_PIPE_SELECT_NONE; +- dbuf_min_tracker_val = DBUF_MIN_TRACKER_STATE_SERVICE(3); +- } else { ++ else + mbus_ctl = MBUS_HASHING_MODE_2x2 | + MBUS_JOIN_PIPE_SELECT_NONE; +- dbuf_min_tracker_val = DBUF_MIN_TRACKER_STATE_SERVICE(1); +- } + + intel_de_rmw(i915, MBUS_CTL, + MBUS_HASHING_MODE_MASK | MBUS_JOIN | + MBUS_JOIN_PIPE_SELECT_MASK, mbus_ctl); + +- for_each_dbuf_slice(i915, slice) +- intel_de_rmw(i915, DBUF_CTL_S(slice), +- DBUF_MIN_TRACKER_STATE_SERVICE_MASK, +- dbuf_min_tracker_val); ++ intel_dbuf_mdclk_cdclk_ratio_update(i915, 2, dbuf_state->joined_mbus); + } + + void intel_dbuf_pre_plane_update(struct intel_atomic_state *state) +-- +2.53.0 + diff --git a/queue-6.6/drm-i915-loop-over-all-active-pipes-in-intel_mbus_db.patch b/queue-6.6/drm-i915-loop-over-all-active-pipes-in-intel_mbus_db.patch new file mode 100644 index 0000000000..a308f92b83 --- /dev/null +++ b/queue-6.6/drm-i915-loop-over-all-active-pipes-in-intel_mbus_db.patch @@ -0,0 +1,58 @@ +From 92186478d3de122479a0d9f876d20d7077bb3f2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Apr 2024 18:50:07 +0300 +Subject: drm/i915: Loop over all active pipes in intel_mbus_dbox_update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Stanislav Lisovskiy + +[ Upstream commit e8333ab22cd8c750b7c14d3da7c0eef3ba85527f ] + +We need to loop through all active pipes, not just the ones, that +are in current state, because disabling and enabling even a particular +pipe affects credits in another one. + +Reviewed-by: Uma Shankar +Signed-off-by: Stanislav Lisovskiy +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20240402155016.13733-6-ville.syrjala@linux.intel.com +Stable-dep-of: a97c88a176b6 ("drm/i915/wm: Verify the correct plane DDB entry") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index 6c657ef8b45b4..9653ed8726935 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3582,10 +3582,8 @@ void intel_mbus_dbox_update(struct intel_atomic_state *state) + { + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state; +- const struct intel_crtc_state *new_crtc_state; + const struct intel_crtc *crtc; + u32 val = 0; +- int i; + + if (DISPLAY_VER(i915) < 11) + return; +@@ -3629,12 +3627,9 @@ void intel_mbus_dbox_update(struct intel_atomic_state *state) + val |= MBUS_DBOX_B_CREDIT(8); + } + +- for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { ++ for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, new_dbuf_state->active_pipes) { + u32 pipe_val = val; + +- if (!new_crtc_state->hw.active) +- continue; +- + if (DISPLAY_VER(i915) >= 14) { + if (xelpdp_is_only_pipe_per_dbuf_bank(crtc->pipe, + new_dbuf_state->active_pipes)) +-- +2.53.0 + diff --git a/queue-6.6/drm-i915-simplify-watermark-state-checker-calling-co.patch b/queue-6.6/drm-i915-simplify-watermark-state-checker-calling-co.patch new file mode 100644 index 0000000000..4401cc6fe7 --- /dev/null +++ b/queue-6.6/drm-i915-simplify-watermark-state-checker-calling-co.patch @@ -0,0 +1,81 @@ +From d541560fa6205a8dba49b33b2c98e752150fb548 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Oct 2023 15:27:13 +0300 +Subject: drm/i915: Simplify watermark state checker calling convention +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 8f0994d47e89711e654df4e31eabb8881079880a ] + +There is never any reason to pass in both the crtc and its state +as one can always dig out the crtc from its state. But for more +consistency across the whole state checker let's just pass the +overall atomic state+crtc here as well. + +v2: Also pass state+crtc here (Jani) + +Reviewed-by: Jani Nikula +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20231005122713.3531-1-ville.syrjala@linux.intel.com +Stable-dep-of: a97c88a176b6 ("drm/i915/wm: Verify the correct plane DDB entry") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_modeset_verify.c | 2 +- + drivers/gpu/drm/i915/display/skl_watermark.c | 8 +++++--- + drivers/gpu/drm/i915/display/skl_watermark.h | 4 ++-- + 3 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c +index 138144a65a457..6e65b867137e7 100644 +--- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c ++++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c +@@ -234,7 +234,7 @@ void intel_modeset_verify_crtc(struct intel_crtc *crtc, + !intel_crtc_needs_fastset(new_crtc_state)) + return; + +- intel_wm_state_verify(crtc, new_crtc_state); ++ intel_wm_state_verify(state, crtc); + verify_connector_state(state, crtc); + verify_crtc_state(crtc, old_crtc_state, new_crtc_state); + intel_shared_dpll_state_verify(crtc, old_crtc_state, new_crtc_state); +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index 8a82576ca0289..d77e598deb2d9 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3132,10 +3132,12 @@ static void skl_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915) + skl_wm_sanitize(i915); + } + +-void intel_wm_state_verify(struct intel_crtc *crtc, +- const struct intel_crtc_state *new_crtc_state) ++void intel_wm_state_verify(struct intel_atomic_state *state, ++ struct intel_crtc *crtc) + { +- struct drm_i915_private *i915 = to_i915(crtc->base.dev); ++ struct drm_i915_private *i915 = to_i915(state->base.dev); ++ const struct intel_crtc_state *new_crtc_state = ++ intel_atomic_get_new_crtc_state(state, crtc); + struct skl_hw_state { + struct skl_ddb_entry ddb[I915_MAX_PLANES]; + struct skl_ddb_entry ddb_y[I915_MAX_PLANES]; +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h +index 3aa138d387900..c7de2b3b2f915 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.h ++++ b/drivers/gpu/drm/i915/display/skl_watermark.h +@@ -38,8 +38,8 @@ bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb, + const struct skl_ddb_entry *entries, + int num_entries, int ignore_idx); + +-void intel_wm_state_verify(struct intel_crtc *crtc, +- const struct intel_crtc_state *new_crtc_state); ++void intel_wm_state_verify(struct intel_atomic_state *state, ++ struct intel_crtc *crtc); + + void skl_watermark_ipc_init(struct drm_i915_private *i915); + void skl_watermark_ipc_update(struct drm_i915_private *i915); +-- +2.53.0 + diff --git a/queue-6.6/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch b/queue-6.6/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch new file mode 100644 index 0000000000..379bc94cb0 --- /dev/null +++ b/queue-6.6/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch @@ -0,0 +1,44 @@ +From ef5d1650741d7366f72e765b85b50235ba59b210 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:48:38 +0200 +Subject: drm/i915/wm: Verify the correct plane DDB entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit a97c88a176b6b8d116f4d3f508f3bd02bc77b462 ] + +Actually verify the DDB entry for the plane we're looking +at instead of always verifying the cursor DDB. + +Fixes: 7d4561722c3b ("drm/i915: Tweak plane ddb allocation tracking") +Signed-off-by: Ville Syrjälä +Link: https://patch.msgid.link/20260324134843.2364-5-ville.syrjala@linux.intel.com +Reviewed-by: Vinod Govindapillai +(cherry picked from commit f002f7c7439de18117a31ca84dc87a59719c3dd6) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index 9653ed8726935..3b30776b73b21 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3239,8 +3239,8 @@ void intel_wm_state_verify(struct intel_atomic_state *state, + } + + /* DDB */ +- hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; +- sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; ++ hw_ddb_entry = &hw->ddb[plane->id]; ++ sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[plane->id]; + + if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { + drm_err(&i915->drm, +-- +2.53.0 + diff --git a/queue-6.6/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch b/queue-6.6/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch new file mode 100644 index 0000000000..8214067518 --- /dev/null +++ b/queue-6.6/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch @@ -0,0 +1,60 @@ +From d94228b122799bfdbedee16012167885af344c60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:48:46 +0300 +Subject: drm/komeda: fix integer overflow in AFBC framebuffer size check + +From: Alexander Konyukhov + +[ Upstream commit 779ec12c85c9e4547519e3903a371a3b26a289de ] + +The AFBC framebuffer size validation calculates the minimum required +buffer size by adding the AFBC payload size to the framebuffer offset. +This addition is performed without checking for integer overflow. + +If the addition oveflows, the size check may incorrectly succed and +allow userspace to provide an undersized drm_gem_object, potentially +leading to out-of-bounds memory access. + +Add usage of check_add_overflow() to safely compute the minimum +required size and reject the framebuffer if an overflow is detected. +This makes the AFBC size validation more robust against malformed. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 65ad2392dd6d ("drm/komeda: Added AFBC support for komeda driver") +Signed-off-by: Alexander Konyukhov +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://lore.kernel.org/r/20260203134907.1587067-1-Alexander.Konyukhov@kaspersky.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +index df5da5a447555..b4f2b89651ff2 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +@@ -4,6 +4,8 @@ + * Author: James.Qian.Wang + * + */ ++#include ++ + #include + #include + #include +@@ -92,7 +94,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file, + kfb->afbc_size = kfb->offset_payload + n_blocks * + ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, + AFBC_SUPERBLK_ALIGNMENT); +- min_size = kfb->afbc_size + fb->offsets[0]; ++ if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) { ++ goto check_failed; ++ } + if (min_size > obj->size) { + DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n", + obj->size, min_size); +-- +2.53.0 + diff --git a/queue-6.6/drm-msm-a6xx-fix-hlsq-register-dumping.patch b/queue-6.6/drm-msm-a6xx-fix-hlsq-register-dumping.patch new file mode 100644 index 0000000000..c4aec1ce0f --- /dev/null +++ b/queue-6.6/drm-msm-a6xx-fix-hlsq-register-dumping.patch @@ -0,0 +1,39 @@ +From 6c46cf1f5b12bbcee485b6d9515bf95fd09cc4a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:40:42 -0700 +Subject: drm/msm/a6xx: Fix HLSQ register dumping + +From: Rob Clark + +[ Upstream commit c289a6db9ba6cb974f0317da142e4f665d589566 ] + +Fix the bitfield offset of HLSQ_READ_SEL state-type bitfield. Otherwise +we are always reading TP state when we wanted SP or HLSQ state. + +Reported-by: Connor Abbott +Suggested-by: Connor Abbott +Fixes: 1707add81551 ("drm/msm/a6xx: Add a6xx gpu state") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714236/ +Message-ID: <20260325184043.1259312-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 258de1bfc5700..6ebb7e6254175 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -672,7 +672,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, + u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; + int i, regcount = 0; + +- in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); ++ in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); + + for (i = 0; i < regs->count; i += 2) { + u32 count = RANGE(regs->registers, i); +-- +2.53.0 + diff --git a/queue-6.6/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch b/queue-6.6/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch new file mode 100644 index 0000000000..8a9225b59c --- /dev/null +++ b/queue-6.6/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch @@ -0,0 +1,72 @@ +From 0cf23bab418bc7758180129eaabeaf1ba7648178 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:50 +0530 +Subject: drm/msm/a6xx: Use barriers while updating HFI Q headers + +From: Akhil P Oommen + +[ Upstream commit dc78b35d5ec09d1b0b8a937e6e640d2c5a030915 ] + +To avoid harmful compiler optimizations and IO reordering in the HW, use +barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI +queue index variables. + +Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714653/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-1-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +index 25b235b49ebc2..14a0ec4a56fda 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +@@ -29,7 +29,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + struct a6xx_hfi_queue_header *header = queue->header; + u32 i, hdr, index = header->read_index; + +- if (header->read_index == header->write_index) { ++ if (header->read_index == READ_ONCE(header->write_index)) { + header->rx_request = 1; + return 0; + } +@@ -57,7 +57,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + if (!gmu->legacy) + index = ALIGN(index, 4) % header->size; + +- header->read_index = index; ++ /* Ensure all memory operations are complete before updating the read index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->read_index, index); + return HFI_HEADER_SIZE(hdr); + } + +@@ -69,7 +72,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + + spin_lock(&queue->lock); + +- space = CIRC_SPACE(header->write_index, header->read_index, ++ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), + header->size); + if (space < dwords) { + header->dropped++; +@@ -90,7 +93,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + queue->data[index] = 0xfafafafa; + } + +- header->write_index = index; ++ /* Ensure all memory operations are complete before updating the write index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->write_index, index); + spin_unlock(&queue->lock); + + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); +-- +2.53.0 + diff --git a/queue-6.6/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch b/queue-6.6/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch new file mode 100644 index 0000000000..8543bcb532 --- /dev/null +++ b/queue-6.6/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch @@ -0,0 +1,58 @@ +From 7a7a866ed57626c60ebf7b15f9da05c9b6e71884 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 14:37:20 +0800 +Subject: drm/msm/dpu: fix mismatch between power and frequency + +From: Yuanjie Yang + +[ Upstream commit bc1dccc518cc5ab5140fba06c27e7188e0ed342b ] + +During DPU runtime suspend, calling dev_pm_opp_set_rate(dev, 0) drops +the MMCX rail to MIN_SVS while the core clock frequency remains at its +original (highest) rate. When runtime resume re-enables the clock, this +may result in a mismatch between the rail voltage and the clock rate. + +For example, in the DPU bind path, the sequence could be: + cpu0: dev_sync_state -> rpmhpd_sync_state + cpu1: dpu_kms_hw_init +timeline 0 ------------------------------------------------> t + +After rpmhpd_sync_state, the voltage performance is no longer guaranteed +to stay at the highest level. During dpu_kms_hw_init, calling +dev_pm_opp_set_rate(dev, 0) drops the voltage, causing the MMCX rail to +fall to MIN_SVS while the core clock is still at its maximum frequency. +When the power is re-enabled, only the clock is enabled, leading to a +situation where the MMCX rail is at MIN_SVS but the core clock is at its +highest rate. In this state, the rail cannot sustain the clock rate, +which may cause instability or system crash. + +Remove the call to dev_pm_opp_set_rate(dev, 0) from dpu_runtime_suspend +to ensure the correct vote is restored when DPU resumes. + +Fixes: b0530eb11913 ("drm/msm/dpu: Use OPP API to set clk/perf state") +Signed-off-by: Yuanjie Yang +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/710077/ +Link: https://lore.kernel.org/r/20260309063720.13572-1-yuanjie.yang@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +index 6ba289e04b3b2..4d93b5f78893e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +@@ -1316,8 +1316,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); + +- /* Drop the performance state vote */ +- dev_pm_opp_set_rate(dev, 0); + clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks); + + for (i = 0; i < dpu_kms->num_paths; i++) +-- +2.53.0 + diff --git a/queue-6.6/drm-msm-dsi-add-the-missing-parameter-description.patch b/queue-6.6/drm-msm-dsi-add-the-missing-parameter-description.patch new file mode 100644 index 0000000000..972d7679ad --- /dev/null +++ b/queue-6.6/drm-msm-dsi-add-the-missing-parameter-description.patch @@ -0,0 +1,40 @@ +From b8316565c8aaa6e1330845907881fb3a72c38fe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 18:02:53 +0800 +Subject: drm/msm/dsi: add the missing parameter description + +From: Pengyu Luo + +[ Upstream commit 958adefc4c0fddee3b12269da5dd7cb49bac953f ] + +Add a description for is_bonded_dsi in dsi_adjust_pclk_for_compression +to match the existing kernel-doc comment. + +Fixes: e4eb11b34d6c ("drm/msm/dsi: fix pclk rate calculation for bonded dsi") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202603080314.XeqyRZ7A-lkp@intel.com/ +Signed-off-by: Pengyu Luo +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/710112/ +Link: https://lore.kernel.org/r/20260309100254.877801-1-mitltlatltl@gmail.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 6077331deba97..771ac34561037 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -533,6 +533,7 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) + * dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case + * @mode: The selected mode for the DSI output + * @dsc: DRM DSC configuration for this DSI output ++ * @is_bonded_dsi: True if two DSI controllers are bonded + * + * Adjust the pclk rate by calculating a new hdisplay proportional to + * the compression ratio such that: +-- +2.53.0 + diff --git a/queue-6.6/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch b/queue-6.6/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch new file mode 100644 index 0000000000..473ddbea2e --- /dev/null +++ b/queue-6.6/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch @@ -0,0 +1,62 @@ +From 88a8d7f0c0584b41d71c4cdcf4b4e84d510fa989 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:48:27 +0000 +Subject: drm/msm/dsi: rename MSM8998 DSI version from V2_2_0 to V2_0_0 + +From: Alexander Koskovich + +[ Upstream commit 913a709dea0eff9c7b2e9470f8c8594b9a0114ab ] + +The MSM8998 DSI controller is v2.0.0 as stated in commit 7b8c9e203039 +("drm/msm/dsi: Add support for MSM8998 DSI controller"). The value was +always correct just the name was wrong. + +Rename and reorder to maintain version sorting. + +Fixes: 7b8c9e203039 ("drm/msm/dsi: Add support for MSM8998 DSI controller") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Alexander Koskovich +Patchwork: https://patchwork.freedesktop.org/patch/713717/ +Link: https://lore.kernel.org/r/20260324-dsi-rgb101010-support-v5-3-ff6afc904115@pm.me +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_cfg.c | 4 ++-- + drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +index 1f98ff74ceb09..39940685681b9 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +@@ -263,10 +263,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { + &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, + &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, ++ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, ++ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, + &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, +- {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, +- &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +index 43f0dd74edb65..32eff45744624 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +@@ -19,8 +19,8 @@ + #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 + #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 + #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 ++#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 +-#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 + #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 + #define MSM_DSI_6G_VER_MINOR_V2_4_0 0x20040000 +-- +2.53.0 + diff --git a/queue-6.6/drm-msm-shrinker-fix-can_block-logic.patch b/queue-6.6/drm-msm-shrinker-fix-can_block-logic.patch new file mode 100644 index 0000000000..0fe0bcd872 --- /dev/null +++ b/queue-6.6/drm-msm-shrinker-fix-can_block-logic.patch @@ -0,0 +1,44 @@ +From 0544ed6b15d630983eec8de3c218d34e7c6b9990 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:41:05 -0700 +Subject: drm/msm/shrinker: Fix can_block() logic + +From: Rob Clark + +[ Upstream commit df0f439e3926817cf577ca6272aad68468ff7624 ] + +The intention here was to allow blocking if DIRECT_RECLAIM or if called +from kswapd and KSWAPD_RECLAIM is set. + +Reported by Claude code review: https://lore.gitlab.freedesktop.org/drm-ai-reviews/review-patch9-20260309151119.290217-10-boris.brezillon@collabora.com/ on a panthor patch which had copied similar logic. + +Reported-by: Boris Brezillon +Fixes: 7860d720a84c ("drm/msm: Fix build break with recent mm tree") +Signed-off-by: Rob Clark +Reviewed-by: Boris Brezillon +Patchwork: https://patchwork.freedesktop.org/patch/714238/ +Message-ID: <20260325184106.1259528-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem_shrinker.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c +index 0641f5bb8649a..5d5cf51cde65a 100644 +--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c ++++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c +@@ -26,9 +26,8 @@ static bool can_swap(void) + + static bool can_block(struct shrink_control *sc) + { +- if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM)) +- return false; +- return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); ++ return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) || ++ (current_is_kswapd() && (sc->gfp_mask & __GFP_KSWAPD_RECLAIM)); + } + + static unsigned long +-- +2.53.0 + diff --git a/queue-6.6/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch b/queue-6.6/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch new file mode 100644 index 0000000000..2b973689ac --- /dev/null +++ b/queue-6.6/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch @@ -0,0 +1,38 @@ +From c94e07b79352b7333e433002f90419057d0a18b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:21:49 +0200 +Subject: drm/panel: sharp-ls043t1le01: make use of prepare_prev_first + +From: Dmitry Baryshkov + +[ Upstream commit c222177d7c7e1b2e0433d9e47ec2da7015345d50 ] + +The DSI link must be powered up to let panel driver to talk to the panel +during prepare() callback execution. Set the prepare_prev_first flag to +guarantee this. + +Fixes: 9e15123eca79 ("drm/msm/dsi: Stop unconditionally powering up DSI hosts at modeset") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Douglas Anderson +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260323-panel-fix-v1-1-9f12b09161e8@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +index 855e64444daa6..58f201720e699 100644 +--- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c ++++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +@@ -224,6 +224,7 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) + + drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev, + &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); ++ sharp_nt->base.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&sharp_nt->base); + if (ret) +-- +2.53.0 + diff --git a/queue-6.6/drm-panel-simple-correct-g190ean01-prepare-timing.patch b/queue-6.6/drm-panel-simple-correct-g190ean01-prepare-timing.patch new file mode 100644 index 0000000000..5504f61154 --- /dev/null +++ b/queue-6.6/drm-panel-simple-correct-g190ean01-prepare-timing.patch @@ -0,0 +1,41 @@ +From 0909efa0842ae7d6f95f63a91db773549cd06fb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 16:25:26 +0200 +Subject: drm/panel: simple: Correct G190EAN01 prepare timing + +From: Sebastian Reichel + +[ Upstream commit f1080f82570b797598c1ba7e9c800ae9e94aafc6 ] + +The prepare timing specified by the G190EAN01 datasheet should be +between 30 and 50 ms. Considering it might take some time for the +LVDS encoder to enable the signal, we should only wait the min. +required time in the panel driver and not the max. allowed time. + +Fixes: 2f7b832fc992 ("drm/panel: simple: Add support for AUO G190EAN01 panel") +Signed-off-by: Sebastian Reichel +Signed-off-by: Ian Ray +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260217142528.68613-1-ian.ray@gehealthcare.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-simple.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 8a94eee57d943..7620ac20393b7 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1157,7 +1157,7 @@ static const struct panel_desc auo_g190ean01 = { + .height = 301, + }, + .delay = { +- .prepare = 50, ++ .prepare = 30, + .enable = 200, + .disable = 110, + .unprepare = 1000, +-- +2.53.0 + diff --git a/queue-6.6/drm-sun4i-backend-fix-error-pointer-dereference.patch b/queue-6.6/drm-sun4i-backend-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..9dbea79cc0 --- /dev/null +++ b/queue-6.6/drm-sun4i-backend-fix-error-pointer-dereference.patch @@ -0,0 +1,43 @@ +From 793982ab60a82a2fdf806d6178b6ee7600686422 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 19:48:01 -0600 +Subject: drm/sun4i: backend: fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit 06277983eca4a31d3c2114fa33d99a6e82484b11 ] + +The function drm_atomic_get_plane_state() can return an error pointer +and is not checked for it. Add error pointer check. + +Detected by Smatch: +drivers/gpu/drm/sun4i/sun4i_backend.c:496 sun4i_backend_atomic_check() error: +'plane_state' dereferencing possible ERR_PTR() + +Fixes: 96180dde23b79 ("drm/sun4i: backend: Add a custom atomic_check for the frontend") +Signed-off-by: Ethan Tidmore +Reviewed-by: Chen-Yu Tsai +Link: https://patch.msgid.link/20260217014801.60760-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index 335fd0edb904c..6a2ffaa477ab8 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -488,6 +488,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, + drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); ++ if (IS_ERR(plane_state)) ++ return PTR_ERR(plane_state); ++ + struct sun4i_layer_state *layer_state = + state_to_sun4i_layer_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; +-- +2.53.0 + diff --git a/queue-6.6/drm-sun4i-fix-resource-leaks.patch b/queue-6.6/drm-sun4i-fix-resource-leaks.patch new file mode 100644 index 0000000000..2eb5518232 --- /dev/null +++ b/queue-6.6/drm-sun4i-fix-resource-leaks.patch @@ -0,0 +1,41 @@ +From 6f89a2816d556efe6abf35fb5b7dc72bf75e3c7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:38:36 -0600 +Subject: drm/sun4i: Fix resource leaks + +From: Ethan Tidmore + +[ Upstream commit 127367ad2e0f4870de60c6d719ae82ecf68d674c ] + +Three clocks are not being released in devm_regmap_init_mmio() error +path. + +Add proper goto and set ret to the error code. + +Fixes: 8270249fbeaf0 ("drm/sun4i: backend: Create regmap after access is possible") +Signed-off-by: Ethan Tidmore +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260226163836.10335-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index 6a2ffaa477ab8..4943577ec7fb8 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -878,7 +878,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, + &sun4i_backend_regmap_config); + if (IS_ERR(backend->engine.regs)) { + dev_err(dev, "Couldn't create the backend regmap\n"); +- return PTR_ERR(backend->engine.regs); ++ ret = PTR_ERR(backend->engine.regs); ++ goto err_disable_ram_clk; + } + + list_add_tail(&backend->engine.list, &drv->engine_list); +-- +2.53.0 + diff --git a/queue-6.6/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch b/queue-6.6/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch new file mode 100644 index 0000000000..d945caf088 --- /dev/null +++ b/queue-6.6/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch @@ -0,0 +1,55 @@ +From ab5f571c819a79520518c1a3410660064ed6ec99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:25:13 -0400 +Subject: drm/sysfb: ofdrm: fix PCI device reference leaks + +From: Yuho Choi + +[ Upstream commit 4aa8110000b0d215deef8eed283565dd0c1def88 ] + +display_get_pci_dev_of() gets a referenced PCI device via +pci_get_device(). Drop that reference when pci_enable_device() fails and +release it during the managed teardown path after pci_disable_device(). + +Without that, ofdrm leaks the pci_dev reference on both the error path +and the normal cleanup path. + +Fixes: c8a17756c425 ("drm/ofdrm: Add ofdrm for Open Firmware framebuffers") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Reviewed-by: Thomas Zimmermann +Signed-off-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260420002513.216-1-dbgh9129@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/tiny/ofdrm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c +index 2d999a0facdee..fe2d3b7c61258 100644 +--- a/drivers/gpu/drm/tiny/ofdrm.c ++++ b/drivers/gpu/drm/tiny/ofdrm.c +@@ -351,6 +351,7 @@ static void ofdrm_pci_release(void *data) + struct pci_dev *pcidev = data; + + pci_disable_device(pcidev); ++ pci_dev_put(pcidev); + } + + static int ofdrm_device_init_pci(struct ofdrm_device *odev) +@@ -376,6 +377,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev) + if (ret) { + drm_err(dev, "pci_enable_device(%s) failed: %d\n", + dev_name(&pcidev->dev), ret); ++ pci_dev_put(pcidev); + return ret; + } + ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); +-- +2.53.0 + diff --git a/queue-6.6/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch b/queue-6.6/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch new file mode 100644 index 0000000000..a6686a285f --- /dev/null +++ b/queue-6.6/dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch @@ -0,0 +1,52 @@ +From 41fd6b9aa728299d077fc56d33f09dfce50ddcb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 12:19:25 +0100 +Subject: dt-bindings: clock: qcom,dispcc-sc7180: Define MDSS resets + +From: Konrad Dybcio + +[ Upstream commit fc6e29d42872680dca017f2e5169eefe971f8d89 ] + +The MDSS resets have so far been left undescribed. Fix that. + +Fixes: 75616da71291 ("dt-bindings: clock: Introduce QCOM sc7180 display clock bindings") +Signed-off-by: Konrad Dybcio +Reviewed-by: Taniya Das +Acked-by: Krzysztof Kozlowski +Tested-by: Val Packett # sc7180-ecs-liva-qc710 +Link: https://lore.kernel.org/r/20260120-topic-7180_dispcc_bcr-v1-1-0b1b442156c3@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: b0bc6011c549 ("clk: qcom: dispcc-sc7180: Add missing MDSS resets") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,dispcc-sc7180.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/dt-bindings/clock/qcom,dispcc-sc7180.h b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +index b9b51617a335d..0705103060748 100644 +--- a/include/dt-bindings/clock/qcom,dispcc-sc7180.h ++++ b/include/dt-bindings/clock/qcom,dispcc-sc7180.h +@@ -6,6 +6,7 @@ + #ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + #define _DT_BINDINGS_CLK_QCOM_DISP_CC_SC7180_H + ++/* Clocks */ + #define DISP_CC_PLL0 0 + #define DISP_CC_PLL0_OUT_EVEN 1 + #define DISP_CC_MDSS_AHB_CLK 2 +@@ -40,7 +41,11 @@ + #define DISP_CC_MDSS_VSYNC_CLK_SRC 31 + #define DISP_CC_XO_CLK 32 + +-/* DISP_CC GDSCR */ ++/* Resets */ ++#define DISP_CC_MDSS_CORE_BCR 0 ++#define DISP_CC_MDSS_RSCC_BCR 1 ++ ++/* GDSCs */ + #define MDSS_GDSC 0 + + #endif +-- +2.53.0 + diff --git a/queue-6.6/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-6.6/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..f388ae4ed5 --- /dev/null +++ b/queue-6.6/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,40 @@ +From 82577e4b734e6e790cf8a8fed9f9901d718d1e21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:06 -0300 +Subject: dt-bindings: clock: qcom,gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 76404ffbf07f28a5ec04748e18fce3dac2e78ef6 ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Signed-off-by: Val Packett +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20260312112321.370983-2-val@packett.cool +Signed-off-by: Bjorn Andersson +Stable-dep-of: 3565741eb985 ("clk: qcom: gcc-sc8180x: Add missing GDSCs") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,gcc-sc8180x.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/dt-bindings/clock/qcom,gcc-sc8180x.h b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +index 2569f874fe13c..be97a0ca2ade4 100644 +--- a/include/dt-bindings/clock/qcom,gcc-sc8180x.h ++++ b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +@@ -308,5 +308,10 @@ + #define USB30_MP_GDSC 8 + #define USB30_PRIM_GDSC 9 + #define USB30_SEC_GDSC 10 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 11 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 12 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 13 ++#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 14 ++#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 15 + + #endif +-- +2.53.0 + diff --git a/queue-6.6/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch b/queue-6.6/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch new file mode 100644 index 0000000000..8b0c62a0d5 --- /dev/null +++ b/queue-6.6/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch @@ -0,0 +1,42 @@ +From d5ae31b7ccc9ef8613eb10f6180cde3d280d06aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 11:26:20 +0100 +Subject: dt-bindings: interrupt-controller: arm,gic-v3: Fix EPPI range + +From: Geert Uytterhoeven + +[ Upstream commit 15cfc8984defc17e5e4de1f58db7b993240fcbda ] + +According to the "Arm Generic Interrupt Controller (GIC) Architecture +Specification, v3 and v4", revision H.b[1], there can be only 64 +Extended PPI interrupts. + +[1] https://developer.arm.com/documentation/ihi0069/hb/ + +Fixes: 4b049063e0bcbfd3 ("dt-bindings: interrupt-controller: arm,gic-v3: Describe EPPI range support") +Signed-off-by: Geert Uytterhoeven +Brain-farted-by: Marc Zyngier +Acked-by: Marc Zyngier +Link: https://patch.msgid.link/3e49a63c6b2b6ee48e3737adee87781f9c136c5f.1772792753.git.geert+renesas@glider.be +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/interrupt-controller/arm,gic-v3.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +index 0f4a062c9d6fe..72e70f9d4b4a2 100644 +--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml ++++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +@@ -50,7 +50,7 @@ properties: + The 2nd cell contains the interrupt number for the interrupt type. + SPI interrupts are in the range [0-987]. PPI interrupts are in the + range [0-15]. Extended SPI interrupts are in the range [0-1023]. +- Extended PPI interrupts are in the range [0-127]. ++ Extended PPI interrupts are in the range [0-63]. + + The 3rd cell is the flags, encoded as follows: + bits[3:0] trigger type and level flags. +-- +2.53.0 + diff --git a/queue-6.6/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch b/queue-6.6/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch new file mode 100644 index 0000000000..edf8608c9a --- /dev/null +++ b/queue-6.6/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch @@ -0,0 +1,47 @@ +From 2024807dc2591d9e60011e9c713b6efcaae460dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 14:34:33 +0200 +Subject: dt-bindings: net: dsa: nxp,sja1105: make spi-cpol optional for + sja1110 + +From: Josua Mayer + +[ Upstream commit 600f01dc4bd0c736b3ffea9f7976136d8bf1b136 ] + +Currently, the binding requires 'spi-cpha' for SJA1105 and 'spi-cpol' +for SJA1110. + +However, the SJA1110 supports both SPI modes 0 and 2. Mode 2 +(cpha=0, cpol=1) is used by the NXP LX2160 Bluebox 3. + +On the SolidRun i.MX8DXL HummingBoard Telematics, mode 0 is stable, +while forcing mode 2 introduces CRC errors especially during bursts. + +Drop the requirement on spi-cpol for SJA1110. + +Fixes: af2eab1a8243 ("dt-bindings: net: nxp,sja1105: document spi-cpol/cpha") +Signed-off-by: Josua Mayer +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260409-imx8dxl-sr-som-v2-1-83ff20629ba0@solid-run.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +index 4d5f5cc6d031e..155719453b704 100644 +--- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml ++++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +@@ -129,8 +129,6 @@ allOf: + else: + properties: + spi-cpha: false +- required: +- - spi-cpol + + unevaluatedProperties: false + +-- +2.53.0 + diff --git a/queue-6.6/e1000e-unroll-ptp-in-probe-error-handling.patch b/queue-6.6/e1000e-unroll-ptp-in-probe-error-handling.patch new file mode 100644 index 0000000000..1d1d0913ca --- /dev/null +++ b/queue-6.6/e1000e-unroll-ptp-in-probe-error-handling.patch @@ -0,0 +1,41 @@ +From 9b3261d39c4a7f1726bd31b246e270e2dee7daf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:36 -0700 +Subject: e1000e: Unroll PTP in probe error handling + +From: Matt Vollrath + +[ Upstream commit aa3f7fe409350857c25d050482a2eef2cfd69b58 ] + +If probe fails after registering the PTP clock and its delayed work, +these resources must be released. + +This was not an issue until a 2016 fix moved the e1000e_ptp_init() call +before the jump to err_register. + +Fixes: aa524b66c5ef ("e1000e: don't modify SYSTIM registers during SIOCSHWTSTAMP ioctl") +Signed-off-by: Matt Vollrath +Tested-by: Avigail Dahan +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-12-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 9e9138ccac421..3b1d142ebf276 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -7700,6 +7700,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + err_register: + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000e_release_hw_control(adapter); ++ e1000e_ptp_remove(adapter); + err_eeprom: + if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) + e1000_phy_hw_reset(&adapter->hw); +-- +2.53.0 + diff --git a/queue-6.6/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch b/queue-6.6/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch new file mode 100644 index 0000000000..f2d48530ab --- /dev/null +++ b/queue-6.6/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch @@ -0,0 +1,52 @@ +From 8b8e36e4bc08ea738bb8da71d2c88619f6c0f251 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:46:37 +0200 +Subject: efi/capsule-loader: fix incorrect sizeof in phys array reallocation + +From: Thomas Huth + +[ Upstream commit 48a428215782321b56956974f23593e40ce84b7a ] + +The krealloc() call for cap_info->phys in __efi_capsule_setup_info() uses +sizeof(phys_addr_t *) instead of sizeof(phys_addr_t), which might be +causing an undersized allocation. + +The allocation is also inconsistent with the initial array allocation in +efi_capsule_open() that allocates one entry with sizeof(phys_addr_t), +and the efi_capsule_write() function that stores phys_addr_t values (not +pointers) via page_to_phys(). + +On 64-bit systems where sizeof(phys_addr_t) == sizeof(phys_addr_t *), this +goes unnoticed. On 32-bit systems with PAE where phys_addr_t is 64-bit but +pointers are 32-bit, this allocates half the required space, which might +lead to a heap buffer overflow when storing physical addresses. + +This is similar to the bug fixed in commit fccfa646ef36 ("efi/capsule-loader: +fix incorrect allocation size") which fixed the same issue at the initial +allocation site. + +Fixes: f24c4d478013 ("efi/capsule-loader: Reinstate virtual capsule mapping") +Assisted-by: Claude:claude-sonnet-4-5 +Signed-off-by: Thomas Huth +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + drivers/firmware/efi/capsule-loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c +index 97bafb5f70389..c6a8bdbcae71b 100644 +--- a/drivers/firmware/efi/capsule-loader.c ++++ b/drivers/firmware/efi/capsule-loader.c +@@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) + cap_info->pages = temp_page; + + temp_page = krealloc(cap_info->phys, +- pages_needed * sizeof(phys_addr_t *), ++ pages_needed * sizeof(phys_addr_t), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-6.6/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch b/queue-6.6/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch new file mode 100644 index 0000000000..a1cabc0365 --- /dev/null +++ b/queue-6.6/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch @@ -0,0 +1,57 @@ +From 31188687f3d4fa3b95e9c1f8bf762120623c836a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:05:39 +0800 +Subject: f2fs: protect extension_list reading with sb_lock in f2fs_sbi_show() + +From: Yongpeng Yang + +[ Upstream commit 5909bedbed38c558bee7cb6758ceedf9bc3a9194 ] + +In f2fs_sbi_show(), the extension_list, extension_count and +hot_ext_count are read without holding sbi->sb_lock. If a concurrent +sysfs store modifies the extension list via f2fs_update_extension_list(), +the show path may read inconsistent count and array contents, potentially +leading to out-of-bounds access or displaying stale data. + +Fix this by holding sb_lock around the entire extension list read +and format operation. + +Fixes: b6a06cbbb5f7 ("f2fs: support hot file extension") +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/sysfs.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index 7d377da9c2631..4cd2d4bde217a 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -318,10 +318,12 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + if (!strcmp(a->attr.name, "extension_list")) { + __u8 (*extlist)[F2FS_EXTENSION_LEN] = + sbi->raw_super->extension_list; +- int cold_count = le32_to_cpu(sbi->raw_super->extension_count); +- int hot_count = sbi->raw_super->hot_ext_count; ++ int cold_count, hot_count; + int len = 0, i; + ++ f2fs_down_read(&sbi->sb_lock); ++ cold_count = le32_to_cpu(sbi->raw_super->extension_count); ++ hot_count = sbi->raw_super->hot_ext_count; + len += sysfs_emit_at(buf, len, "cold file extension:\n"); + for (i = 0; i < cold_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); +@@ -329,6 +331,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + len += sysfs_emit_at(buf, len, "hot file extension:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); ++ f2fs_up_read(&sbi->sb_lock); + + return len; + } +-- +2.53.0 + diff --git a/queue-6.6/f2fs-use-sysfs_emit_at-to-simplify-code.patch b/queue-6.6/f2fs-use-sysfs_emit_at-to-simplify-code.patch new file mode 100644 index 0000000000..bc73f47eb0 --- /dev/null +++ b/queue-6.6/f2fs-use-sysfs_emit_at-to-simplify-code.patch @@ -0,0 +1,120 @@ +From feb61905e014b92bd7b5ebc42bd634a8c4d5e0d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Aug 2024 08:47:28 +0800 +Subject: f2fs: Use sysfs_emit_at() to simplify code + +From: Christophe JAILLET + +[ Upstream commit f7a678bbe5a8f22cfcef5369757cc9b95f73e027 ] + +This file already uses sysfs_emit(). So be consistent and also use +sysfs_emit_at(). + +This slightly simplifies the code and makes it more readable. + +Reviewed-by: Chao Yu +Signed-off-by: Christophe JAILLET +Signed-off-by: Jaegeuk Kim +Stable-dep-of: 5909bedbed38 ("f2fs: protect extension_list reading with sb_lock in f2fs_sbi_show()") +Signed-off-by: Sasha Levin +--- + fs/f2fs/sysfs.c | 45 +++++++++++++++++++++------------------------ + 1 file changed, 21 insertions(+), 24 deletions(-) + +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index 436bbf23f8e7c..7d377da9c2631 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -162,50 +162,50 @@ static ssize_t features_show(struct f2fs_attr *a, + int len = 0; + + if (f2fs_sb_has_encrypt(sbi)) +- len += scnprintf(buf, PAGE_SIZE - len, "%s", ++ len += sysfs_emit_at(buf, len, "%s", + "encryption"); + if (f2fs_sb_has_blkzoned(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "blkzoned"); + if (f2fs_sb_has_extra_attr(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "extra_attr"); + if (f2fs_sb_has_project_quota(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "projquota"); + if (f2fs_sb_has_inode_chksum(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "inode_checksum"); + if (f2fs_sb_has_flexible_inline_xattr(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "flexible_inline_xattr"); + if (f2fs_sb_has_quota_ino(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "quota_ino"); + if (f2fs_sb_has_inode_crtime(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "inode_crtime"); + if (f2fs_sb_has_lost_found(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "lost_found"); + if (f2fs_sb_has_verity(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "verity"); + if (f2fs_sb_has_sb_chksum(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "sb_checksum"); + if (f2fs_sb_has_casefold(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "casefold"); + if (f2fs_sb_has_readonly(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "readonly"); + if (f2fs_sb_has_compression(sbi)) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "compression"); +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s", ++ len += sysfs_emit_at(buf, len, "%s%s", + len ? ", " : "", "pin_file"); +- len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); ++ len += sysfs_emit_at(buf, len, "\n"); + return len; + } + +@@ -322,17 +322,14 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + int hot_count = sbi->raw_super->hot_ext_count; + int len = 0, i; + +- len += scnprintf(buf + len, PAGE_SIZE - len, +- "cold file extension:\n"); ++ len += sysfs_emit_at(buf, len, "cold file extension:\n"); + for (i = 0; i < cold_count; i++) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", +- extlist[i]); ++ len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); + +- len += scnprintf(buf + len, PAGE_SIZE - len, +- "hot file extension:\n"); ++ len += sysfs_emit_at(buf, len, "hot file extension:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) +- len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", +- extlist[i]); ++ len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); ++ + return len; + } + +-- +2.53.0 + diff --git a/queue-6.6/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch b/queue-6.6/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch new file mode 100644 index 0000000000..4f47b3884a --- /dev/null +++ b/queue-6.6/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch @@ -0,0 +1,71 @@ +From 0699cb0c58ae48d89c9f28be24b2e52e2e4f948b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 15:36:46 +0100 +Subject: fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build + break + +From: Andy Shevchenko + +[ Upstream commit caf6144053b4e1c815aa56afb54745a176f999df ] + +Clang is not happy about set but unused variable: + +drivers/video/fbdev/matrox/g450_pll.c:412:18: error: variable 'mnp' set but not used + 412 | unsigned int mnp; + | ^ +1 error generated. + +Since the commit 7b987887f97b ("video: fbdev: matroxfb: remove dead code +and set but not used variable") the 'mnp' became unused, but eliminating +that code might have side-effects. The question here is what should we do +with 'mnp'? The easiest way out is just mark it with __maybe_unused which +will shut the compiler up and won't change any possible IO flow. So does +this change. + +A dive into the history of the driver: + +The problem was revealed when the #if 0 guarded code along with unused +pixel_vco variable was removed. That code was introduced in the original +commit 213d22146d1f ("[PATCH] (1/3) matroxfb for 2.5.3"). And then guarded +in the commit 705e41f82988 ("matroxfb DVI updates: Handle DVI output on +G450/G550. Powerdown unused portions of G450/G550 DAC. Split G450/G550 DAC +from older DAC1064 handling. Modify PLL setting when both CRTCs use same +pixel clocks."). + +NOTE: The two commits mentioned above pre-date Git era and available in +history.git repository for archaeological purposes. + +Even without that guard the modern compilers may see that the pixel_vco +wasn't ever used and seems a leftover after some debug or review made +25 years ago. + +The g450_mnp2vco() doesn't have any IO and as Jason said doesn't seem +to have any side effects either than some unneeded CPU processing during +runtime. I agree that's unlikely that timeout (or heating up the CPU) has +any effect on the HW (GPU/display) functionality. + +Fixes: 7b987887f97b ("video: fbdev: matroxfb: remove dead code and set but not used variable") +Signed-off-by: Andy Shevchenko +Reviewed-by: Jason Yan +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/matrox/g450_pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c +index ff8e321a22cef..b2d3f7328ea83 100644 +--- a/drivers/video/fbdev/matrox/g450_pll.c ++++ b/drivers/video/fbdev/matrox/g450_pll.c +@@ -407,7 +407,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, + case M_VIDEO_PLL: + { + u_int8_t tmp; +- unsigned int mnp; ++ unsigned int mnp __maybe_unused; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); +-- +2.53.0 + diff --git a/queue-6.6/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch b/queue-6.6/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch new file mode 100644 index 0000000000..c60c8cb699 --- /dev/null +++ b/queue-6.6/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch @@ -0,0 +1,52 @@ +From 729bf6fbb3ec47e707f1bff2973d3489466fcd8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:01:18 -0400 +Subject: fbdev: offb: fix PCI device reference leak on probe failure + +From: Yuho Choi + +[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ] + +offb_init_nodriver() gets a referenced PCI device with pci_get_device(). +If pci_enable_device() fails, the function returns without dropping that +reference. + +Release the PCI device reference before returning from the +pci_enable_device() failure path. + +Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/offb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c +index dcb1b81d35db5..0e81d68378935 100644 +--- a/drivers/video/fbdev/offb.c ++++ b/drivers/video/fbdev/offb.c +@@ -643,8 +643,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod + vid = be32_to_cpup(vidp); + did = be32_to_cpup(didp); + pdev = pci_get_device(vid, did, NULL); +- if (!pdev || pci_enable_device(pdev)) ++ if (!pdev) + return; ++ ++ if (pci_enable_device(pdev)) { ++ pci_dev_put(pdev); ++ return; ++ } + } + #endif + /* kludge for valkyrie */ +-- +2.53.0 + diff --git a/queue-6.6/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch b/queue-6.6/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch new file mode 100644 index 0000000000..7e7ff39b14 --- /dev/null +++ b/queue-6.6/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch @@ -0,0 +1,63 @@ +From 7f63d4279787704ccd674921a1417f0896670876 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 08:10:20 -0600 +Subject: firmware: dmi: Correct an indexing error in dmi.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit c064abc68e009d2cc18416e7132d9c25e03125b6 ] + +The entries later in enum dmi_entry_type don't match the SMBIOS +specification¹. + +The entry for type 33: `64-Bit Memory Error Information` is not present and +thus the index for all later entries is incorrect. + +Add it. + +Also, add missing entry types 43-46, while at it. + + ¹ Search for "System Management BIOS (SMBIOS) Reference Specification" + + [ bp: Drop the flaky SMBIOS spec URL. ] + +Fixes: 93c890dbe5287 ("firmware: Add DMI entry types to the headers") +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Jean Delvare +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20260307141024.819807-2-superm1@kernel.org +Signed-off-by: Sasha Levin +--- + include/linux/dmi.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/dmi.h b/include/linux/dmi.h +index 927f8a8b7a1dd..2eedf44e68012 100644 +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -60,6 +60,7 @@ enum dmi_entry_type { + DMI_ENTRY_OOB_REMOTE_ACCESS, + DMI_ENTRY_BIS_ENTRY, + DMI_ENTRY_SYSTEM_BOOT, ++ DMI_ENTRY_64_MEM_ERROR, + DMI_ENTRY_MGMT_DEV, + DMI_ENTRY_MGMT_DEV_COMPONENT, + DMI_ENTRY_MGMT_DEV_THRES, +@@ -69,6 +70,10 @@ enum dmi_entry_type { + DMI_ENTRY_ADDITIONAL, + DMI_ENTRY_ONBOARD_DEV_EXT, + DMI_ENTRY_MGMT_CONTROLLER_HOST, ++ DMI_ENTRY_TPM_DEVICE, ++ DMI_ENTRY_PROCESSOR_ADDITIONAL, ++ DMI_ENTRY_FIRMWARE_INVENTORY, ++ DMI_ENTRY_STRING_PROPERTY, + DMI_ENTRY_INACTIVE = 126, + DMI_ENTRY_END_OF_TABLE = 127, + }; +-- +2.53.0 + diff --git a/queue-6.6/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch b/queue-6.6/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch new file mode 100644 index 0000000000..8258ec68a5 --- /dev/null +++ b/queue-6.6/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch @@ -0,0 +1,48 @@ +From d501da070ea7694528cf9fc1836486d5b823f4c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 13:45:02 +0900 +Subject: fs/adfs: validate nzones in adfs_validate_bblk() + +From: Bae Yeonju + +[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ] + +Reject ADFS disc records with a zero zone count during boot block +validation, before the disc record is used. + +When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) +which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to +dm[-1], causing an out-of-bounds write before the allocated buffer. + +adfs_validate_dr0() already rejects nzones != 1 for old-format +images. Add the equivalent check to adfs_validate_bblk() for +new-format images so that a crafted image with nzones == 0 is +rejected at probe time. + +Found by syzkaller. + +Fixes: f6f14a0d71b0 ("fs/adfs: map: move map-specific sb initialisation to map.c") +Signed-off-by: Bae Yeonju +Signed-off-by: Russell King (Oracle) +Signed-off-by: Sasha Levin +--- + fs/adfs/super.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/adfs/super.c b/fs/adfs/super.c +index e8bfc38239cd5..76e37c6d4cad4 100644 +--- a/fs/adfs/super.c ++++ b/fs/adfs/super.c +@@ -343,6 +343,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, + if (adfs_checkdiscrecord(dr)) + return -EILSEQ; + ++ if ((dr->nzones | dr->nzones_high << 8) == 0) ++ return -EILSEQ; ++ + *drp = dr; + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch b/queue-6.6/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch new file mode 100644 index 0000000000..7b48fec449 --- /dev/null +++ b/queue-6.6/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch @@ -0,0 +1,51 @@ +From a83b7410386af2a548052450b52e6a2d789cf824 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:19:55 +0800 +Subject: fs/ntfs3: terminate the cached volume label after UTF-8 conversion + +From: Pengpeng Hou + +[ Upstream commit a6cd43fe9b083fa23fe1595666d5738856cb261a ] + +ntfs_fill_super() loads the on-disk volume label with utf16s_to_utf8s() +and stores the result in sbi->volume.label. The converted label is later +exposed through ntfs3_label_show() using %s, but utf16s_to_utf8s() only +returns the number of bytes written and does not add a trailing NUL. + +If the converted label fills the entire fixed buffer, +ntfs3_label_show() can read past the end of sbi->volume.label while +looking for a terminator. + +Terminate the cached label explicitly after a successful conversion and +clamp the exact-full case to the last byte of the buffer. + +Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") +Signed-off-by: Pengpeng Hou +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 0b96d0f995c61..a4cc56df549a6 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1228,8 +1228,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + le32_to_cpu(attr->res.data_size) >> 1, + UTF16_LITTLE_ENDIAN, sbi->volume.label, + sizeof(sbi->volume.label)); +- if (err < 0) ++ if (err < 0) { + sbi->volume.label[0] = 0; ++ } else if (err >= sizeof(sbi->volume.label)) { ++ sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0; ++ } else { ++ sbi->volume.label[err] = 0; ++ } + } else { + /* Should we break mounting here? */ + //err = -EINVAL; +-- +2.53.0 + diff --git a/queue-6.6/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch b/queue-6.6/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch new file mode 100644 index 0000000000..320cc09552 --- /dev/null +++ b/queue-6.6/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch @@ -0,0 +1,55 @@ +From 49669fd99c6406cb47817aa067d9569f2dec64cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:48:27 +0900 +Subject: fs/omfs: reject s_sys_blocksize smaller than OMFS_DIR_START + +From: HyungJung Joo + +[ Upstream commit 0621c385fda1376e967f37ccd534c26c3e511d14 ] + +omfs_fill_super() rejects oversized s_sys_blocksize values (> PAGE_SIZE), +but it does not reject values smaller than OMFS_DIR_START (0x1b8 = 440). + +Later, omfs_make_empty() uses + + sbi->s_sys_blocksize - OMFS_DIR_START + +as the length argument to memset(). Since s_sys_blocksize is u32, +a crafted filesystem image with s_sys_blocksize < OMFS_DIR_START causes +an unsigned underflow there, wrapping to a value near 2^32. That drives +a ~4 GiB memset() from bh->b_data + OMFS_DIR_START and overwrites kernel +memory far beyond the backing block buffer. + +Add the corresponding lower-bound check alongside the existing upper-bound +check in omfs_fill_super(), so that malformed images are rejected during +superblock validation before any filesystem data is processed. + +Fixes: a3ab7155ea21 ("omfs: add directory routines") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054827.1822061-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/omfs/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c +index 2f8c1882f45c8..60ef691aeb702 100644 +--- a/fs/omfs/inode.c ++++ b/fs/omfs/inode.c +@@ -514,6 +514,12 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) + goto out_brelse_bh; + } + ++ if (sbi->s_sys_blocksize < OMFS_DIR_START) { ++ printk(KERN_ERR "omfs: sysblock size (%d) is too small\n", ++ sbi->s_sys_blocksize); ++ goto out_brelse_bh; ++ } ++ + if (sbi->s_blocksize < sbi->s_sys_blocksize || + sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { + printk(KERN_ERR "omfs: block size (%d) is out of range\n", +-- +2.53.0 + diff --git a/queue-6.6/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch b/queue-6.6/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch new file mode 100644 index 0000000000..7dc43d9bdd --- /dev/null +++ b/queue-6.6/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch @@ -0,0 +1,100 @@ +From 3c36d0e45ff0cf2b4cf76c2295a5790da8381531 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:34:25 +0200 +Subject: futex: Prevent lockup in requeue-PI during signal/ timeout wakeup + +From: Sebastian Andrzej Siewior + +[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ] + +During wait-requeue-pi (task A) and requeue-PI (task B) the following +race can happen: + + Task A Task B + futex_wait_requeue_pi() + futex_setup_timer() + futex_do_wait() + futex_requeue() + CLASS(hb, hb1)(&key1); + CLASS(hb, hb2)(&key2); + *timeout* + futex_requeue_pi_wakeup_sync() + requeue_state = Q_REQUEUE_PI_IGNORE + + *blocks on hb->lock* + + futex_proxy_trylock_atomic() + futex_requeue_pi_prepare() + Q_REQUEUE_PI_IGNORE => -EAGAIN + double_unlock_hb(hb1, hb2) + *retry* + +Task B acquires both hb locks and attempts to acquire the PI-lock of the +top most waiter (task B). Task A is leaving early due to a signal/ +timeout and started removing itself from the queue. It updates its +requeue_state but can not remove it from the list because this requires +the hb lock which is owned by task B. + +Usually task A is able to swoop the lock after task B unlocked it. +However if task B is of higher priority then task A may not be able to +wake up in time and acquire the lock before task B gets it again. +Especially on a UP system where A is never scheduled. + +As a result task A blocks on the lock and task B busy loops, trying to +make progress but live locks the system instead. Tragic. + +This can be fixed by removing the top most waiter from the list in this +case. This allows task B to grab the next top waiter (if any) in the +next iteration and make progress. + +Remove the top most waiter if futex_requeue_pi_prepare() fails. +Let the waiter conditionally remove itself from the list in +handle_early_requeue_pi_wakeup(). + +Fixes: 07d91ef510fb1 ("futex: Prevent requeue_pi() lock nesting issue on RT") +Reported-by: Moritz Klammler +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260428103425.dywXyPd3@linutronix.de +Closes: https://lore.kernel.org/all/VE1PR06MB6894BE61C173D802365BE19DFF4CA@VE1PR06MB6894.eurprd06.prod.outlook.com +Signed-off-by: Sasha Levin +--- + kernel/futex/requeue.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c +index 7e43839ca7b05..60b08247b07dd 100644 +--- a/kernel/futex/requeue.c ++++ b/kernel/futex/requeue.c +@@ -307,8 +307,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, + return -EINVAL; + + /* Ensure that this does not race against an early wakeup */ +- if (!futex_requeue_pi_prepare(top_waiter, NULL)) ++ if (!futex_requeue_pi_prepare(top_waiter, NULL)) { ++ plist_del(&top_waiter->list, &hb1->chain); ++ futex_hb_waiters_dec(hb1); + return -EAGAIN; ++ } + + /* + * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit +@@ -707,10 +710,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, + + /* + * We were woken prior to requeue by a timeout or a signal. +- * Unqueue the futex_q and determine which it was. ++ * Conditionally unqueue the futex_q and determine which it was. + */ +- plist_del(&q->list, &hb->chain); +- futex_hb_waiters_dec(hb); ++ if (!plist_node_empty(&q->list)) { ++ plist_del(&q->list, &hb->chain); ++ futex_hb_waiters_dec(hb); ++ } + + /* Handle spurious wakeups gracefully */ + ret = -EWOULDBLOCK; +-- +2.53.0 + diff --git a/queue-6.6/gfs2-add-some-missing-log-locking.patch b/queue-6.6/gfs2-add-some-missing-log-locking.patch new file mode 100644 index 0000000000..268eef8711 --- /dev/null +++ b/queue-6.6/gfs2-add-some-missing-log-locking.patch @@ -0,0 +1,109 @@ +From 34f63f41d1e8a70828502a41da25ed4b6aefafc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 06:13:42 +0200 +Subject: gfs2: add some missing log locking + +From: Andreas Gruenbacher + +[ Upstream commit fe2c8d051150b90b3ccb85f89e3b1d636cb88ec8 ] + +Function gfs2_logd() calls the log flushing functions gfs2_ail1_start(), +gfs2_ail1_wait(), and gfs2_ail1_empty() without holding sdp->sd_log_flush_lock, +but these functions require exclusion against concurrent transactions. + +To fix that, add a non-locking __gfs2_log_flush() function. Then, in +gfs2_logd(), take sdp->sd_log_flush_lock before calling the above mentioned log +flushing functions and __gfs2_log_flush(). + +Fixes: 5e4c7632aae1c ("gfs2: Issue revokes more intelligently") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 2be5551241b3a..01fa92ac9ab20 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -1024,14 +1024,15 @@ static void trans_drain(struct gfs2_trans *tr) + } + + /** +- * gfs2_log_flush - flush incore transaction(s) ++ * __gfs2_log_flush - flush incore transaction(s) + * @sdp: The filesystem + * @gl: The glock structure to flush. If NULL, flush the whole incore log + * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags + * + */ + +-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ++ u32 flags) + { + struct gfs2_trans *tr = NULL; + unsigned int reserved_blocks = 0, used_blocks = 0; +@@ -1039,7 +1040,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + unsigned int first_log_head; + unsigned int reserved_revokes = 0; + +- down_write(&sdp->sd_log_flush_lock); + trace_gfs2_log_flush(sdp, 1, flags); + + repeat: +@@ -1151,7 +1151,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + gfs2_assert_withdraw_delayed(sdp, used_blocks < reserved_blocks); + gfs2_log_release(sdp, reserved_blocks - used_blocks); + } +- up_write(&sdp->sd_log_flush_lock); + gfs2_trans_free(sdp, tr); + if (gfs2_withdrawing(sdp)) + gfs2_withdraw(sdp); +@@ -1174,6 +1173,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + goto out_end; + } + ++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++{ ++ down_write(&sdp->sd_log_flush_lock); ++ __gfs2_log_flush(sdp, gl, flags); ++ up_write(&sdp->sd_log_flush_lock); ++} ++ + /** + * gfs2_merge_trans - Merge a new transaction into a cached transaction + * @sdp: the filesystem +@@ -1315,19 +1321,25 @@ int gfs2_logd(void *data) + } + + if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_JFLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_JFLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) || + gfs2_ail_flush_reqd(sdp)) { + clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_start(sdp); + gfs2_ail1_wait(sdp); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; +-- +2.53.0 + diff --git a/queue-6.6/gfs2-call-unlock_new_inode-before-d_instantiate.patch b/queue-6.6/gfs2-call-unlock_new_inode-before-d_instantiate.patch new file mode 100644 index 0000000000..b60cc44334 --- /dev/null +++ b/queue-6.6/gfs2-call-unlock_new_inode-before-d_instantiate.patch @@ -0,0 +1,48 @@ +From 46120eac6f9037be341d156097f33bdf9d0b1282 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:04:05 +0100 +Subject: gfs2: Call unlock_new_inode before d_instantiate + +From: Andreas Gruenbacher + +[ Upstream commit 2ff7cf7e0640ff071ebc5c7e3dc2df024a7c91e6 ] + +As Neil Brown describes in detail in the link referenced below, new +inodes must be unlocked before they can be instantiated. + +An even better fix is to use d_instantiate_new(), which combines +d_instantiate() and unlock_new_inode(). + +Fixes: 3d36e57ff768 ("gfs2: gfs2_create_inode rework") +Reported-by: syzbot+0ea5108a1f5fb4fcc2d8@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-fsdevel/177153754005.8396.8777398743501764194@noble.neil.brown.name/ +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/inode.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index 45040622d316e..18f75beea0890 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -805,7 +805,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + goto fail_gunlock4; + + mark_inode_dirty(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + /* After instantiate, errors should result in evict which will destroy + * both inode and iopen glocks properly. */ + if (file) { +@@ -817,7 +817,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + gfs2_glock_dq_uninit(&gh); + gfs2_glock_put(io_gl); + gfs2_qa_put(dip); +- unlock_new_inode(inode); + return error; + + fail_gunlock4: +-- +2.53.0 + diff --git a/queue-6.6/gfs2-prevent-null-pointer-dereference-during-unmount.patch b/queue-6.6/gfs2-prevent-null-pointer-dereference-during-unmount.patch new file mode 100644 index 0000000000..1e697a892d --- /dev/null +++ b/queue-6.6/gfs2-prevent-null-pointer-dereference-during-unmount.patch @@ -0,0 +1,44 @@ +From b8e45874a8a191c116d829f01aa3db8821775924 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 12:14:30 +0200 +Subject: gfs2: prevent NULL pointer dereference during unmount + +From: Andreas Gruenbacher + +[ Upstream commit 74b4dbb946060a3233604d91859a9abd3708141d ] + +When flushing out outstanding glock work during an unmount, gfs2_log_flush() +can be called when sdp->sd_jdesc has already been deallocated and sdp->sd_jdesc +is NULL. Commit 35264909e9d1 ("gfs2: Fix NULL pointer dereference in +gfs2_log_flush") added a check for that to gfs2_log_flush() itself, but it +missed the sdp->sd_jdesc dereference in gfs2_log_release(). Fix that. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202604071139.HNJiCaAi-lkp@intel.com/ +Fixes: 35264909e9d1 ("gfs2: Fix NULL pointer dereference in gfs2_log_flush") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 01fa92ac9ab20..b8be6c1c942d4 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -478,8 +478,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) + { + atomic_add(blks, &sdp->sd_log_blks_free); + trace_gfs2_log_blocks(sdp, blks); +- gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= +- sdp->sd_jdesc->jd_blocks); ++ gfs2_assert_withdraw(sdp, !sdp->sd_jdesc || ++ atomic_read(&sdp->sd_log_blks_free) <= ++ sdp->sd_jdesc->jd_blocks); + if (atomic_read(&sdp->sd_log_blks_needed)) + wake_up(&sdp->sd_log_waitq); + } +-- +2.53.0 + diff --git a/queue-6.6/hid-asus-do-not-abort-probe-when-not-necessary.patch b/queue-6.6/hid-asus-do-not-abort-probe-when-not-necessary.patch new file mode 100644 index 0000000000..dc43b53faf --- /dev/null +++ b/queue-6.6/hid-asus-do-not-abort-probe-when-not-necessary.patch @@ -0,0 +1,65 @@ +From 315612ab15ca48b70a3535a87f5364f289c33b42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:09 +0100 +Subject: HID: asus: do not abort probe when not necessary + +From: Denis Benato + +[ Upstream commit 7253091766ded0fd81fe8d8be9b8b835495b06e8 ] + +In order to avoid dereferencing a NULL pointer asus_probe is aborted early +and control of some asus devices is transferred over hid-generic after +erroring out even when such NULL dereference cannot happen: only early +abort when the NULL dereference can happen. + +Also make the code shorter and more adherent to coding standards +removing square brackets enclosing single-line if-else statements. + +Fixes: d3af6ca9a8c3 ("HID: asus: fix UAF via HID_CLAIMED_INPUT validation") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index e4ea87cdb05fd..d3913f70d263d 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1118,22 +1118,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + * were freed during registration due to no usages being mapped, + * leaving drvdata->input pointing to freed memory. + */ +- if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { +- hid_err(hdev, "Asus input not registered\n"); +- ret = -ENOMEM; +- goto err_stop_hw; +- } +- +- if (drvdata->tp) { +- drvdata->input->name = "Asus TouchPad"; +- } else { +- drvdata->input->name = "Asus Keyboard"; +- } ++ if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) { ++ if (drvdata->tp) ++ drvdata->input->name = "Asus TouchPad"; ++ else ++ drvdata->input->name = "Asus Keyboard"; + +- if (drvdata->tp) { +- ret = asus_start_multitouch(hdev); +- if (ret) +- goto err_stop_hw; ++ if (drvdata->tp) { ++ ret = asus_start_multitouch(hdev); ++ if (ret) ++ goto err_stop_hw; ++ } + } + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch b/queue-6.6/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch new file mode 100644 index 0000000000..a8653e8684 --- /dev/null +++ b/queue-6.6/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch @@ -0,0 +1,37 @@ +From 9fdb4ee6f03a41a1b65551c60b2c63df7eb348ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:07 +0100 +Subject: HID: asus: make asus_resume adhere to linux kernel coding standards + +From: Denis Benato + +[ Upstream commit 51d33b42b8ae23da92819d28439fdd5636c45186 ] + +Linux kernel coding standars requires functions opening brackets to be in +a newline: move the opening bracket of asus_resume in its own line. + +Fixes: 546edbd26cff ("HID: hid-asus: reset the backlight brightness level on resume") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 544b74eda284a..e4ea87cdb05fd 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -990,7 +990,8 @@ static int asus_start_multitouch(struct hid_device *hdev) + return 0; + } + +-static int __maybe_unused asus_resume(struct hid_device *hdev) { ++static int __maybe_unused asus_resume(struct hid_device *hdev) ++{ + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + int ret = 0; + +-- +2.53.0 + diff --git a/queue-6.6/hid-usbhid-fix-deadlock-in-hid_post_reset.patch b/queue-6.6/hid-usbhid-fix-deadlock-in-hid_post_reset.patch new file mode 100644 index 0000000000..5e03d18633 --- /dev/null +++ b/queue-6.6/hid-usbhid-fix-deadlock-in-hid_post_reset.patch @@ -0,0 +1,42 @@ +From e339a7be883272c23bb6c469b958a6e6addcfc29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:24:54 +0100 +Subject: HID: usbhid: fix deadlock in hid_post_reset() + +From: Oliver Neukum + +[ Upstream commit 8df2c1b47ee3cd50fd454f75c7a7e2ae8a6adf72 ] + +You can build a USB device that includes a HID component +and a storage or UAS component. The components can be reset +only together. That means that hid_pre_reset() and hid_post_reset() +are in the block IO error handling. Hence no memory allocation +used in them may do block IO because the IO can deadlock +on the mutex held while resetting a device and calling the +interface drivers. +Use GFP_NOIO for all allocations in them. + +Fixes: dc3c78e434690 ("HID: usbhid: Check HID report descriptor contents after device reset") +Signed-off-by: Oliver Neukum +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index 5e3bd615066c1..415d44ac14807 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1549,7 +1549,7 @@ static int hid_post_reset(struct usb_interface *intf) + * configuration descriptors passed, we already know that + * the size of the HID report descriptor has not changed. + */ +- rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); ++ rdesc = kmalloc(hid->dev_rsize, GFP_NOIO); + if (!rdesc) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.6/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch b/queue-6.6/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch new file mode 100644 index 0000000000..a27e1d7acc --- /dev/null +++ b/queue-6.6/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch @@ -0,0 +1,46 @@ +From 4381777eea3ac840c0367451bce39b2947d036d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:35:37 +0100 +Subject: hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns() + +From: Peter Zijlstra + +[ Upstream commit d19ff16c11db38f3ee179d72751fb9b340174330 ] + +Much like hrtimer_reprogram(), skip programming if the cpu_base is running +the hrtimer interrupt. + +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Juri Lelli +Reviewed-by: Thomas Gleixner +Link: https://patch.msgid.link/20260224163429.069535561@kernel.org +Stable-dep-of: f2e388a019e4 ("hrtimer: Reduce trace noise in hrtimer_start()") +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 9f41327d3a6d6..3bc3111ca5317 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1287,6 +1287,14 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + } + + first = enqueue_hrtimer(timer, new_base, mode); ++ ++ /* ++ * If the hrtimer interrupt is running, then it will reevaluate the ++ * clock bases and reprogram the clock event device. ++ */ ++ if (new_base->cpu_base->in_hrtirq) ++ return false; ++ + if (!force_local) { + /* + * If the current CPU base is online, then the timer is +-- +2.53.0 + diff --git a/queue-6.6/hrtimer-reduce-trace-noise-in-hrtimer_start.patch b/queue-6.6/hrtimer-reduce-trace-noise-in-hrtimer_start.patch new file mode 100644 index 0000000000..6d2343f42a --- /dev/null +++ b/queue-6.6/hrtimer-reduce-trace-noise-in-hrtimer_start.patch @@ -0,0 +1,216 @@ +From 7bf8fc93d3aff903ebe398a2f9747580a09ccdc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:36:59 +0100 +Subject: hrtimer: Reduce trace noise in hrtimer_start() + +From: Thomas Gleixner + +[ Upstream commit f2e388a019e4cf83a15883a3d1f1384298e9a6aa ] + +hrtimer_start() when invoked with an already armed timer traces like: + + -.. [032] d.h2. 5.002263: hrtimer_cancel: hrtimer= .... + -.. [032] d.h1. 5.002263: hrtimer_start: hrtimer= .... + +Which is incorrect as the timer doesn't get canceled. Just the expiry time +changes. The internal dequeue operation which is required for that is not +really interesting for trace analysis. But it makes it tedious to keep real +cancellations and the above case apart. + +Remove the cancel tracing in hrtimer_start() and add a 'was_armed' +indicator to the hrtimer start tracepoint, which clearly indicates what the +state of the hrtimer is when hrtimer_start() is invoked: + +-.. [032] d.h1. 6.200103: hrtimer_start: hrtimer= .... was_armed=0 + -.. [032] d.h1. 6.200558: hrtimer_start: hrtimer= .... was_armed=1 + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260224163430.208491877@kernel.org +Signed-off-by: Sasha Levin +--- + include/trace/events/timer.h | 11 +++++---- + kernel/time/hrtimer.c | 43 +++++++++++++++++------------------- + 2 files changed, 27 insertions(+), 27 deletions(-) + +diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h +index b4bc2828fa09f..ec8d0de1ad225 100644 +--- a/include/trace/events/timer.h ++++ b/include/trace/events/timer.h +@@ -198,12 +198,13 @@ TRACE_EVENT(hrtimer_init, + * hrtimer_start - called when the hrtimer is started + * @hrtimer: pointer to struct hrtimer + * @mode: the hrtimers mode ++ * @was_armed: Was armed when hrtimer_start*() was invoked + */ + TRACE_EVENT(hrtimer_start, + +- TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode), ++ TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode, bool was_armed), + +- TP_ARGS(hrtimer, mode), ++ TP_ARGS(hrtimer, mode, was_armed), + + TP_STRUCT__entry( + __field( void *, hrtimer ) +@@ -211,6 +212,7 @@ TRACE_EVENT(hrtimer_start, + __field( s64, expires ) + __field( s64, softexpires ) + __field( enum hrtimer_mode, mode ) ++ __field( bool, was_armed ) + ), + + TP_fast_assign( +@@ -219,13 +221,14 @@ TRACE_EVENT(hrtimer_start, + __entry->expires = hrtimer_get_expires(hrtimer); + __entry->softexpires = hrtimer_get_softexpires(hrtimer); + __entry->mode = mode; ++ __entry->was_armed = was_armed; + ), + + TP_printk("hrtimer=%p function=%ps expires=%llu softexpires=%llu " +- "mode=%s", __entry->hrtimer, __entry->function, ++ "mode=%s was_armed=%d", __entry->hrtimer, __entry->function, + (unsigned long long) __entry->expires, + (unsigned long long) __entry->softexpires, +- decode_hrtimer_mode(__entry->mode)) ++ decode_hrtimer_mode(__entry->mode), __entry->was_armed) + ); + + /** +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 3bc3111ca5317..d3071b81c0640 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -499,17 +499,10 @@ debug_init(struct hrtimer *timer, clockid_t clockid, + trace_hrtimer_init(timer, clockid, mode); + } + +-static inline void debug_activate(struct hrtimer *timer, +- enum hrtimer_mode mode) ++static inline void debug_activate(struct hrtimer *timer, enum hrtimer_mode mode, bool was_armed) + { + debug_hrtimer_activate(timer, mode); +- trace_hrtimer_start(timer, mode); +-} +- +-static inline void debug_deactivate(struct hrtimer *timer) +-{ +- debug_hrtimer_deactivate(timer); +- trace_hrtimer_cancel(timer); ++ trace_hrtimer_start(timer, mode, was_armed); + } + + static struct hrtimer_clock_base * +@@ -1102,9 +1095,9 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); + * Returns true when the new timer is the leftmost timer in the tree. + */ + static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, +- enum hrtimer_mode mode) ++ enum hrtimer_mode mode, bool was_armed) + { +- debug_activate(timer, mode); ++ debug_activate(timer, mode, was_armed); + WARN_ON_ONCE(!base->cpu_base->online); + + base->cpu_base->active_bases |= 1 << base->index; +@@ -1164,6 +1157,8 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + if (state & HRTIMER_STATE_ENQUEUED) { + bool reprogram; + ++ debug_hrtimer_deactivate(timer); ++ + /* + * Remove the timer and force reprogramming when high + * resolution mode is active and the timer is on the current +@@ -1172,7 +1167,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + * reprogramming happens in the interrupt handler. This is a + * rare case and less expensive than a smp call. + */ +- debug_deactivate(timer); + reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); + + /* +@@ -1239,15 +1233,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + { + struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); + struct hrtimer_clock_base *new_base; +- bool force_local, first; ++ bool force_local, first, was_armed; + + /* + * If the timer is on the local cpu base and is the first expiring + * timer then this might end up reprogramming the hardware twice +- * (on removal and on enqueue). To avoid that by prevent the +- * reprogram on removal, keep the timer local to the current CPU +- * and enforce reprogramming after it is queued no matter whether +- * it is the new first expiring timer again or not. ++ * (on removal and on enqueue). To avoid that prevent the reprogram ++ * on removal, keep the timer local to the current CPU and enforce ++ * reprogramming after it is queued no matter whether it is the new ++ * first expiring timer again or not. + */ + force_local = base->cpu_base == this_cpu_base; + force_local &= base->cpu_base->next_timer == timer; +@@ -1269,7 +1263,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + * avoids programming the underlying clock event twice (once at + * removal and once after enqueue). + */ +- remove_hrtimer(timer, base, true, force_local); ++ was_armed = remove_hrtimer(timer, base, true, force_local); + + if (mode & HRTIMER_MODE_REL) + tim = ktime_add_safe(tim, base->get_time()); +@@ -1286,7 +1280,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + new_base = base; + } + +- first = enqueue_hrtimer(timer, new_base, mode); ++ first = enqueue_hrtimer(timer, new_base, mode, was_armed); + + /* + * If the hrtimer interrupt is running, then it will reevaluate the +@@ -1390,8 +1384,11 @@ int hrtimer_try_to_cancel(struct hrtimer *timer) + + base = lock_hrtimer_base(timer, &flags); + +- if (!hrtimer_callback_running(timer)) ++ if (!hrtimer_callback_running(timer)) { + ret = remove_hrtimer(timer, base, false, false); ++ if (ret) ++ trace_hrtimer_cancel(timer); ++ } + + unlock_hrtimer_base(timer, &flags); + +@@ -1771,7 +1768,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + */ + if (restart != HRTIMER_NORESTART && + !(timer->state & HRTIMER_STATE_ENQUEUED)) +- enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, false); + + /* + * Separate the ->running assignment from the ->state assignment. +@@ -2253,7 +2250,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + while ((node = timerqueue_getnext(&old_base->active))) { + timer = container_of(node, struct hrtimer, node); + BUG_ON(hrtimer_callback_running(timer)); +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + + /* + * Mark it as ENQUEUED not INACTIVE otherwise the +@@ -2270,7 +2267,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + * sort out already expired timers and reprogram the + * event device. + */ +- enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, true); + } + } + +-- +2.53.0 + diff --git a/queue-6.6/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch b/queue-6.6/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch new file mode 100644 index 0000000000..8d2c66bd3a --- /dev/null +++ b/queue-6.6/hrtimers-update-the-return-type-of-enqueue_hrtimer.patch @@ -0,0 +1,49 @@ +From d8a9cf796d9a4014b3ef5fc8288135e955aebdc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Dec 2024 15:57:03 +0800 +Subject: hrtimers: Update the return type of enqueue_hrtimer() + +From: Richard Clark + +[ Upstream commit da7100d3bf7d6f5c49ef493ea963766898e9b069 ] + +The return type should be 'bool' instead of 'int' according to the calling +context in the kernel, and its internal implementation, i.e. : + + return timerqueue_add(); + +which is a bool-return function. + +[ tglx: Adjust function arguments ] + +Signed-off-by: Richard Clark +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/all/Z2ppT7me13dtxm1a@MBC02GN1V4Q05P +Stable-dep-of: f2e388a019e4 ("hrtimer: Reduce trace noise in hrtimer_start()") +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 03f488f93cddf..9f41327d3a6d6 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1099,11 +1099,10 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); + * The timer is inserted in expiry order. Insertion into the + * red black tree is O(log(n)). Must hold the base lock. + * +- * Returns 1 when the new timer is the leftmost timer in the tree. ++ * Returns true when the new timer is the leftmost timer in the tree. + */ +-static int enqueue_hrtimer(struct hrtimer *timer, +- struct hrtimer_clock_base *base, +- enum hrtimer_mode mode) ++static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, ++ enum hrtimer_mode mode) + { + debug_activate(timer, mode); + WARN_ON_ONCE(!base->cpu_base->online); +-- +2.53.0 + diff --git a/queue-6.6/i3c-master-fix-error-codes-at-send_ccc_cmd.patch b/queue-6.6/i3c-master-fix-error-codes-at-send_ccc_cmd.patch new file mode 100644 index 0000000000..a6cd9e9d82 --- /dev/null +++ b/queue-6.6/i3c-master-fix-error-codes-at-send_ccc_cmd.patch @@ -0,0 +1,126 @@ +From d9962e7bc034eaa1e792e44f018edcedeb4ae755 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:32 +0100 +Subject: i3c: master: Fix error codes at send_ccc_cmd + +From: Jorge Marques + +[ Upstream commit ef8b5229348f0719aca557c4ca5530630ae4d134 ] + +i3c_master_send_ccc_cmd_locked() would propagate cmd->err (positive, +Mx codes) to the ret variable, cascading down multiple methods until +reaching methods that explicitly stated they would return 0 on success +or negative error code. For example, the call chain: + + i3c_device_enable_ibi <- i3c_dev_enable_ibi_locked <- + master->ops.enable_ibi <- i3c_master_enec_locked <- + i3c_master_enec_disec_locked <- i3c_master_send_ccc_cmd_locked + +Fix this by returning the ret value, callers can still read the cmd->err +value if ret is negative. + +All corner cases where the Mx codes do need to be handled individually, +are resolved in previous commits. Those corner cases are all scenarios +when I3C_ERROR_M2 is expected and acceptable. +The prerequisite patches for the fix are: + + i3c: master: Move rstdaa error suppression + i3c: master: Move entdaa error suppression + i3c: master: Move bus_init error suppression + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-iio/aYXvT5FW0hXQwhm_@stanley.mountain/ +Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-4-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 32 +++++++++++++------------------- + 1 file changed, 13 insertions(+), 19 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index f74ef65d257d7..84fe0de5a9bc7 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -792,11 +792,17 @@ static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id, + cmd->err = I3C_ERROR_UNKNOWN; + } + ++/** ++ * i3c_master_send_ccc_cmd_locked() - send a CCC (Common Command Codes) ++ * @master: master used to send frames on the bus ++ * @cmd: command to send ++ * ++ * Return: 0 in case of success, or a negative error code otherwise. ++ * I3C Mx error codes are stored in cmd->err. ++ */ + static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd) + { +- int ret; +- + if (!cmd || !master) + return -EINVAL; + +@@ -814,15 +820,7 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + !master->ops->supports_ccc_cmd(master, cmd)) + return -ENOTSUPP; + +- ret = master->ops->send_ccc_cmd(master, cmd); +- if (ret) { +- if (cmd->err != I3C_ERROR_UNKNOWN) +- return cmd->err; +- +- return ret; +- } +- +- return 0; ++ return master->ops->send_ccc_cmd(master, cmd); + } + + static struct i2c_dev_desc * +@@ -926,8 +924,7 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_entdaa_locked(struct i3c_master_controller *master) + { +@@ -979,8 +976,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1000,8 +996,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1026,8 +1021,7 @@ EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_defslvs_locked(struct i3c_master_controller *master) + { +-- +2.53.0 + diff --git a/queue-6.6/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch b/queue-6.6/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch new file mode 100644 index 0000000000..7da453ab53 --- /dev/null +++ b/queue-6.6/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch @@ -0,0 +1,56 @@ +From 81ac6a1495ad6d5650a6d35b9bb6bfd1921d368a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:53:23 +0800 +Subject: i3c: mipi-i3c-hci: fix IBI payload length calculation for final + status + +From: Billy Tsai + +[ Upstream commit d35a6db887eeae7c57b719521e39d64f929c6dc3 ] + +In DMA mode, the IBI status descriptor encodes the payload using +CHUNKS (number of chunks) and DATA_LENGTH (valid bytes in the last +chunk). All preceding chunks are implicitly full-sized. + +The current code accumulates full chunk sizes for non-final status +descriptors, but for the final status descriptor it only adds +DATA_LENGTH. This ignores the contribution of the preceding full +chunks described by the same final status entry. + +As a result, the computed IBI payload length is truncated whenever +the final status spans multiple chunks. For example, with a chunk +size of 4 bytes, CHUNKS=2 and DATA_LENGTH=1 should result in a total +payload size of 5 bytes, but the current code reports only 1 byte. + +Fix the calculation by adding the size of (CHUNKS - 1) full chunks +plus DATA_LENGTH for the last chunk. + +Fixes: 9ad9a52cce28 ("i3c/master: introduce the mipi-i3c-hci driver") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260407-i3c-hci-dma-v2-1-a583187b9d22@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index e270fcd0f7c38..624d00b853a51 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -636,7 +636,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh) + if (!(ibi_status & IBI_LAST_STATUS)) { + ibi_size += chunks * rh->ibi_chunk_sz; + } else { +- ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ if (chunks) { ++ ibi_size += (chunks - 1) * rh->ibi_chunk_sz; ++ ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ } + last_ptr = ptr; + break; + } +-- +2.53.0 + diff --git a/queue-6.6/i40e-don-t-advertise-iff_supp_nofcs.patch b/queue-6.6/i40e-don-t-advertise-iff_supp_nofcs.patch new file mode 100644 index 0000000000..ea834a85ac --- /dev/null +++ b/queue-6.6/i40e-don-t-advertise-iff_supp_nofcs.patch @@ -0,0 +1,53 @@ +From 54711f2d170fdde4192273fb4036cd77ba50ff70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:33 -0700 +Subject: i40e: don't advertise IFF_SUPP_NOFCS + +From: Kohei Enju + +[ Upstream commit a24162f18825684ad04e3a5d0531f8a50d679347 ] + +i40e advertises IFF_SUPP_NOFCS, allowing users to use the SO_NOFCS +socket option. However, this option is silently ignored, as the driver +does not check skb->no_fcs, and always enables FCS insertion offload. + +Fix this by removing the advertisement of IFF_SUPP_NOFCS. + +This behavior can be reproduced with a simple AF_PACKET socket: + + import socket + s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) + s.setsockopt(socket.SOL_SOCKET, 43, 1) # SO_NOFCS + s.bind(("eth0", 0)) + s.send(b'\xff' * 64) + +Previously, send() succeeds but the driver ignores SO_NOFCS. +With this change, send() fails with -EPROTONOSUPPORT, as expected. + +Fixes: 41c445ff0f48 ("i40e: main driver core") +Signed-off-by: Kohei Enju +Reviewed-by: Aleksandr Loktionov +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-9-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index 9bcd32d31da77..24879ddd603e5 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -13940,7 +13940,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) + netdev->neigh_priv_len = sizeof(u32) * 4; + + netdev->priv_flags |= IFF_UNICAST_FLT; +- netdev->priv_flags |= IFF_SUPP_NOFCS; + /* Setup netdev TC information */ + i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); + +-- +2.53.0 + diff --git a/queue-6.6/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch b/queue-6.6/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch new file mode 100644 index 0000000000..a46b6d47fe --- /dev/null +++ b/queue-6.6/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch @@ -0,0 +1,58 @@ +From fb5cdcc91b7a9cb9f2436acdfa4037d1afe79fc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:16 -0700 +Subject: iavf: add VIRTCHNL_OP_ADD_VLAN to success completion handler + +From: Petr Oros + +[ Upstream commit 34d33313b52eeac3a97ad2e3176d523ec70d9283 ] + +The V1 ADD_VLAN opcode had no success handler; filters sent via V1 +stayed in ADDING state permanently. Add a fallthrough case so V1 +filters also transition ADDING -> ACTIVE on PF confirmation. + +Critically, add an `if (v_retval) break` guard: the error switch in +iavf_virtchnl_completion() does NOT return after handling errors, +it falls through to the success switch. Without this guard, a +PF-rejected ADD would incorrectly mark ADDING filters as ACTIVE, +creating a driver/HW mismatch where the driver believes the filter +is installed but the PF never accepted it. + +For V2, this is harmless: iavf_vlan_add_reject() in the error +block already kfree'd all ADDING filters, so the success handler +finds nothing to transition. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-4-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 4a197bc4b86a7..b6bc5609e118c 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -2486,9 +2486,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->adv_rss_lock); + } + break; ++ case VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN_V2: { + struct iavf_vlan_filter *f; + ++ if (v_retval) ++ break; ++ + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_ADDING) +-- +2.53.0 + diff --git a/queue-6.6/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch b/queue-6.6/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch new file mode 100644 index 0000000000..cd4fecc9f6 --- /dev/null +++ b/queue-6.6/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch @@ -0,0 +1,87 @@ +From fb9dce1795e8d2798d2628790f9f19a5150df8c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:13 -0700 +Subject: iavf: rename IAVF_VLAN_IS_NEW to IAVF_VLAN_ADDING + +From: Petr Oros + +[ Upstream commit 70d62b669f1f9080a25278fc90b64309f4ae8959 ] + +Rename the IAVF_VLAN_IS_NEW state to IAVF_VLAN_ADDING to better +describe what the state represents: an ADD request has been sent to +the PF and is waiting for a response. + +This is a pure rename with no behavioral change, preparing for a +cleanup of the VLAN filter state machine. + +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-1-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Stable-dep-of: f2ce65b9b917 ("iavf: stop removing VLAN filters from PF on interface down") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 2 +- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 431d9d62c8c66..c09ec8cc1e9fb 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -158,7 +158,7 @@ struct iavf_vlan { + enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ +- IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ ++ IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ + IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ + IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index b95a4f903204b..bc8285f77a7be 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -637,7 +637,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) { ++ if (f->state == IAVF_VLAN_ADDING) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +@@ -702,7 +702,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + if (f->state == IAVF_VLAN_ADD) { + vvfl->vlan_id[i] = f->vlan.vid; + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + if (i == count) + break; + } +@@ -763,7 +763,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + vlan->tpid = f->vlan.tpid; + + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + } + } + +@@ -2520,7 +2520,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) ++ if (f->state == IAVF_VLAN_ADDING) + f->state = IAVF_VLAN_ACTIVE; + } + spin_unlock_bh(&adapter->mac_vlan_list_lock); +-- +2.53.0 + diff --git a/queue-6.6/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch b/queue-6.6/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch new file mode 100644 index 0000000000..a346c049d4 --- /dev/null +++ b/queue-6.6/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch @@ -0,0 +1,233 @@ +From 6edc851d30d73188d53448f3a6ede63fe6f4f1ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:14 -0700 +Subject: iavf: stop removing VLAN filters from PF on interface down + +From: Petr Oros + +[ Upstream commit f2ce65b9b917474a1a6ce68d357e15fac2aca0f2 ] + +When a VF goes down, the driver currently sends DEL_VLAN to the PF for +every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then +re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING -> +ACTIVE). This round-trip is unnecessary because: + + 1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES, + which already prevents all RX/TX traffic regardless of VLAN filter + state. + + 2. The VLAN filters remaining in PF HW while the VF is down is + harmless - packets matching those filters have nowhere to go with + queues disabled. + + 3. The DEL+ADD cycle during down/up creates race windows where the + VLAN filter list is incomplete. With spoofcheck enabled, the PF + enables TX VLAN filtering on the first non-zero VLAN add, blocking + traffic for any VLANs not yet re-added. + +Remove the entire DISABLE/INACTIVE state machinery: + - Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values + - Remove iavf_restore_filters() and its call from iavf_open() + - Remove VLAN filter handling from iavf_clear_mac_vlan_filters(), + rename it to iavf_clear_mac_filters() + - Remove DEL_VLAN_FILTER scheduling from iavf_down() + - Remove all DISABLE/INACTIVE handling from iavf_del_vlans() + +VLAN filters now stay ACTIVE across down/up cycles. Only explicit +user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN +filter deletion/re-addition. + +Fixes: ed1f5b58ea01 ("i40evf: remove VLAN filters on close") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-2-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 6 +-- + drivers/net/ethernet/intel/iavf/iavf_main.c | 39 ++----------------- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 33 +++------------- + 3 files changed, 12 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index c09ec8cc1e9fb..d1f39befc8b8c 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -159,10 +159,8 @@ enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ +- IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ +- IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ +- IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +- IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ ++ IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ ++ IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index 02e07fe6a0528..c7fecd7261140 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -846,27 +846,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +-/** +- * iavf_restore_filters +- * @adapter: board private structure +- * +- * Restore existing non MAC filters when VF netdev comes back up +- **/ +-static void iavf_restore_filters(struct iavf_adapter *adapter) +-{ +- struct iavf_vlan_filter *f; +- +- /* re-add all VLAN filters */ +- spin_lock_bh(&adapter->mac_vlan_list_lock); +- +- list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_INACTIVE) +- f->state = IAVF_VLAN_ADD; +- } +- +- spin_unlock_bh(&adapter->mac_vlan_list_lock); +- adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; +-} + + /** + * iavf_get_num_vlans_added - get number of VLANs added +@@ -1289,13 +1268,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) + } + + /** +- * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF +- * yet and mark other to be removed. ++ * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark ++ * others to be removed. + * @adapter: board private structure + **/ +-static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) ++static void iavf_clear_mac_filters(struct iavf_adapter *adapter) + { +- struct iavf_vlan_filter *vlf, *vlftmp; + struct iavf_mac_filter *f, *ftmp; + + spin_lock_bh(&adapter->mac_vlan_list_lock); +@@ -1314,11 +1292,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) + } + } + +- /* disable all VLAN filters */ +- list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, +- list) +- vlf->state = IAVF_VLAN_DISABLE; +- + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +@@ -1414,7 +1387,7 @@ void iavf_down(struct iavf_adapter *adapter) + iavf_napi_disable_all(adapter); + iavf_irq_disable(adapter); + +- iavf_clear_mac_vlan_filters(adapter); ++ iavf_clear_mac_filters(adapter); + iavf_clear_cloud_filters(adapter); + iavf_clear_fdir_filters(adapter); + iavf_clear_adv_rss_conf(adapter); +@@ -1429,8 +1402,6 @@ void iavf_down(struct iavf_adapter *adapter) + */ + if (!list_empty(&adapter->mac_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; +- if (!list_empty(&adapter->vlan_filter_list)) +- adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; + if (!list_empty(&adapter->cloud_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; + if (!list_empty(&adapter->fdir_list_head)) +@@ -4295,8 +4266,6 @@ static int iavf_open(struct net_device *netdev) + + spin_unlock_bh(&adapter->mac_vlan_list_lock); + +- /* Restore filters that were removed with IFF_DOWN */ +- iavf_restore_filters(adapter); + iavf_restore_fdir_filters(adapter); + + iavf_configure(adapter); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index bc8285f77a7be..1d03cc452df2c 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -800,22 +800,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + spin_lock_bh(&adapter->mac_vlan_list_lock); + + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- /* since VLAN capabilities are not allowed, we dont want to send +- * a VLAN delete request because it will most likely fail and +- * create unnecessary errors/noise, so just free the VLAN +- * filters marked for removal to enable bailing out before +- * sending a virtchnl message +- */ + if (f->state == IAVF_VLAN_REMOVE && + !VLAN_FILTERING_ALLOWED(adapter)) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else if (f->state == IAVF_VLAN_DISABLE && +- !VLAN_FILTERING_ALLOWED(adapter)) { +- f->state = IAVF_VLAN_INACTIVE; +- } else if (f->state == IAVF_VLAN_REMOVE || +- f->state == IAVF_VLAN_DISABLE) { ++ } else if (f->state == IAVF_VLAN_REMOVE) { + count++; + } + } +@@ -847,13 +837,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE) { +- vvfl->vlan_id[i] = f->vlan.vid; +- f->state = IAVF_VLAN_INACTIVE; +- i++; +- if (i == count) +- break; +- } else if (f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; + list_del(&f->list); + kfree(f); +@@ -894,8 +878,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE || +- f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; + struct virtchnl_vlan *vlan; +@@ -909,13 +892,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- if (f->state == IAVF_VLAN_DISABLE) { +- f->state = IAVF_VLAN_INACTIVE; +- } else { +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; +- } ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; + i++; + if (i == count) + break; +-- +2.53.0 + diff --git a/queue-6.6/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch b/queue-6.6/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch new file mode 100644 index 0000000000..6e56da0cda --- /dev/null +++ b/queue-6.6/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch @@ -0,0 +1,189 @@ +From 8556cffd639a08bf9c6db7a30e47ff2ecbe7e2d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:15 -0700 +Subject: iavf: wait for PF confirmation before removing VLAN filters + +From: Petr Oros + +[ Upstream commit bbcbe4ed70dea948849549af7edf44bd42bbd695 ] + +The VLAN filter DELETE path was asymmetric with the ADD path: ADD +waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE +immediately frees the filter struct after sending the DEL message +without waiting for the PF response. + +This is problematic because: + - If the PF rejects the DEL, the filter remains in HW but the driver + has already freed the tracking structure, losing sync. + - Race conditions between DEL pending and other operations + (add, reset) cannot be properly resolved if the filter struct + is already gone. + +Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric: + + REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree + -> PF rejects -> ACTIVE + +In iavf_del_vlans(), transition filters from REMOVE to REMOVING +instead of immediately freeing them. The new DEL completion handler +in iavf_virtchnl_completion() frees filters on success or reverts +them to ACTIVE on error. + +Update iavf_add_vlan() to handle the REMOVING state: if a DEL is +pending and the user re-adds the same VLAN, queue it for ADD so +it gets re-programmed after the PF processes the DEL. + +The !VLAN_FILTERING_ALLOWED early-exit path still frees filters +directly since no PF message is sent in that case. + +Also update iavf_del_vlan() to skip filters already in REMOVING +state: DEL has been sent to PF and the completion handler will +free the filter when PF confirms. Without this guard, the sequence +DEL(pending) -> user-del -> second DEL could cause the PF to return +an error for the second DEL (filter already gone), causing the +completion handler to incorrectly revert a deleted filter back to +ACTIVE. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-3-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 1 + + drivers/net/ethernet/intel/iavf/iavf_main.c | 13 ++++--- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 37 +++++++++++++------ + 3 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index d1f39befc8b8c..c9553fa475ae1 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -161,6 +161,7 @@ enum iavf_vlan_state_t { + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ ++ IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index c7fecd7261140..b9b855a35fc85 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -802,10 +802,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, + adapter->num_vlan_filters++; + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); + } else if (f->state == IAVF_VLAN_REMOVE) { +- /* Re-add the filter since we cannot tell whether the +- * pending delete has already been processed by the PF. +- * A duplicate add is harmless. +- */ ++ /* DEL not yet sent to PF, cancel it */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else if (f->state == IAVF_VLAN_REMOVING) { ++ /* DEL already sent to PF, re-add after completion */ + f->state = IAVF_VLAN_ADD; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_ADD_VLAN_FILTER); +@@ -836,11 +836,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else { ++ } else if (f->state != IAVF_VLAN_REMOVING) { + f->state = IAVF_VLAN_REMOVE; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_DEL_VLAN_FILTER); + } ++ /* If REMOVING, DEL is already sent to PF; completion ++ * handler will free the filter when PF confirms. ++ */ + } + + spin_unlock_bh(&adapter->mac_vlan_list_lock); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 1d03cc452df2c..4a197bc4b86a7 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -836,12 +836,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -877,7 +875,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; +@@ -892,9 +890,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -2019,10 +2015,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); + wake_up(&adapter->vc_waitqueue); + break; +- case VIRTCHNL_OP_DEL_VLAN: +- dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", +- iavf_stat_str(&adapter->hw, v_retval)); +- break; + case VIRTCHNL_OP_DEL_ETH_ADDR: + dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", + iavf_stat_str(&adapter->hw, v_retval)); +@@ -2505,6 +2497,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + break; ++ case VIRTCHNL_OP_DEL_VLAN: ++ case VIRTCHNL_OP_DEL_VLAN_V2: { ++ struct iavf_vlan_filter *f, *ftmp; ++ ++ spin_lock_bh(&adapter->mac_vlan_list_lock); ++ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, ++ list) { ++ if (f->state == IAVF_VLAN_REMOVING) { ++ if (v_retval) { ++ /* PF rejected DEL, keep filter */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else { ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; ++ } ++ } ++ } ++ spin_unlock_bh(&adapter->mac_vlan_list_lock); ++ } ++ break; + case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: + /* PF enabled vlan strip on this VF. + * Update netdev->features if needed to be in sync with ethtool. +-- +2.53.0 + diff --git a/queue-6.6/ice-fix-double-free-of-tx_buf-skb.patch b/queue-6.6/ice-fix-double-free-of-tx_buf-skb.patch new file mode 100644 index 0000000000..a596fabd4a --- /dev/null +++ b/queue-6.6/ice-fix-double-free-of-tx_buf-skb.patch @@ -0,0 +1,76 @@ +From c627cbd90ca55c2b784b896e359fad0bf5869006 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:28 -0700 +Subject: ice: fix double-free of tx_buf skb + +From: Michal Schmidt + +[ Upstream commit 1a303baa715e6b78d6a406aaf335f87ff35acfcd ] + +If ice_tso() or ice_tx_csum() fail, the error path in +ice_xmit_frame_ring() frees the skb, but the 'first' tx_buf still points +to it and is marked as valid (ICE_TX_BUF_SKB). +'next_to_use' remains unchanged, so the potential problem will +likely fix itself when the next packet is transmitted and the tx_buf +gets overwritten. But if there is no next packet and the interface is +brought down instead, ice_clean_tx_ring() -> ice_unmap_and_free_tx_buf() +will find the tx_buf and free the skb for the second time. + +The fix is to reset the tx_buf type to ICE_TX_BUF_EMPTY in the error +path, so that ice_unmap_and_free_tx_buf(). +Move the initialization of 'first' up, to ensure it's already valid in +case we hit the linearization error path. + +The bug was spotted by AI while I had it looking for something else. +It also proposed an initial version of the patch. + +I reproduced the bug and tested the fix by adding code to inject +failures, on a build with KASAN. + +I looked for similar bugs in related Intel drivers and did not find any. + +Fixes: d76a60ba7afb ("ice: Add support for VLANs and offloads") +Assisted-by: Claude:claude-4.6-opus-high Cursor +Signed-off-by: Michal Schmidt +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-4-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 66da8a34be0f1..4e110a008a257 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2364,6 +2364,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + ++ /* record the location of the first descriptor for this packet */ ++ first = &tx_ring->tx_buf[tx_ring->next_to_use]; ++ + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +@@ -2389,8 +2392,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + offload.tx_ring = tx_ring; + +- /* record the location of the first descriptor for this packet */ +- first = &tx_ring->tx_buf[tx_ring->next_to_use]; + first->skb = skb; + first->type = ICE_TX_BUF_SKB; + first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); +@@ -2452,6 +2453,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + out_drop: + ice_trace(xmit_frame_ring_drop, tx_ring, skb); + dev_kfree_skb_any(skb); ++ first->type = ICE_TX_BUF_EMPTY; + return NETDEV_TX_OK; + } + +-- +2.53.0 + diff --git a/queue-6.6/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch b/queue-6.6/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch new file mode 100644 index 0000000000..d610f47308 --- /dev/null +++ b/queue-6.6/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch @@ -0,0 +1,130 @@ +From 7704cbce71538fdfb8fa918e9dea4ba4744fc5c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:17 -0700 +Subject: ice: fix NULL pointer dereference in ice_reset_all_vfs() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Petr Oros + +[ Upstream commit 54ef02487914c24170c7e1c061e45212dc55365e ] + +ice_reset_all_vfs() ignores the return value of ice_vf_rebuild_vsi(). +When the VSI rebuild fails (e.g. during NVM firmware update via +nvmupdate64e), ice_vsi_rebuild() tears down the VSI on its error path, +leaving txq_map and rxq_map as NULL. The subsequent unconditional call +to ice_vf_post_vsi_rebuild() leads to a NULL pointer dereference in +ice_ena_vf_q_mappings() when it accesses vsi->txq_map[0]. + +The single-VF reset path in ice_reset_vf() already handles this +correctly by checking the return value of ice_vf_reconfig_vsi() and +skipping ice_vf_post_vsi_rebuild() on failure. + +Apply the same pattern to ice_reset_all_vfs(): check the return value +of ice_vf_rebuild_vsi() and skip ice_vf_post_vsi_rebuild() and +ice_eswitch_attach_vf() on failure. The VF is left safely disabled +(ICE_VF_STATE_INIT not set, VFGEN_RSTAT not set to VFACTIVE) and can +be recovered via a VFLR triggered by a PCI reset of the VF +(sysfs reset or driver rebind). + +Note that this patch does not prevent the VF VSI rebuild from failing +during NVM update — the underlying cause is firmware being in a +transitional state while the EMP reset is processed, which can cause +Admin Queue commands (ice_add_vsi, ice_cfg_vsi_lan) to fail. This +patch only prevents the subsequent NULL pointer dereference that +crashes the kernel when the rebuild does fail. + + crash> bt + PID: 50795 TASK: ff34c9ee708dc680 CPU: 1 COMMAND: "kworker/u512:5" + #0 [ff72159bcfe5bb50] machine_kexec at ffffffffaa8850ee + #1 [ff72159bcfe5bba8] __crash_kexec at ffffffffaaa15fba + #2 [ff72159bcfe5bc68] crash_kexec at ffffffffaaa16540 + #3 [ff72159bcfe5bc70] oops_end at ffffffffaa837eda + #4 [ff72159bcfe5bc90] page_fault_oops at ffffffffaa893997 + #5 [ff72159bcfe5bce8] exc_page_fault at ffffffffab528595 + #6 [ff72159bcfe5bd10] asm_exc_page_fault at ffffffffab600bb2 + [exception RIP: ice_ena_vf_q_mappings+0x79] + RIP: ffffffffc0a85b29 RSP: ff72159bcfe5bdc8 RFLAGS: 00010206 + RAX: 00000000000f0000 RBX: ff34c9efc9c00000 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: 0000000000000010 RDI: ff34c9efc9c00000 + RBP: ff34c9efc27d4828 R8: 0000000000000093 R9: 0000000000000040 + R10: ff34c9efc27d4828 R11: 0000000000000040 R12: 0000000000100000 + R13: 0000000000000010 R14: R15: + ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 + #7 [ff72159bcfe5bdf8] ice_sriov_post_vsi_rebuild at ffffffffc0a85e2e [ice] + #8 [ff72159bcfe5be08] ice_reset_all_vfs at ffffffffc0a920b4 [ice] + #9 [ff72159bcfe5be48] ice_service_task at ffffffffc0a31519 [ice] + #10 [ff72159bcfe5be88] process_one_work at ffffffffaa93dca4 + #11 [ff72159bcfe5bec8] worker_thread at ffffffffaa93e9de + #12 [ff72159bcfe5bf18] kthread at ffffffffaa946663 + #13 [ff72159bcfe5bf50] ret_from_fork at ffffffffaa8086b9 + + The panic occurs attempting to dereference the NULL pointer in RDX at + ice_sriov.c:294, which loads vsi->txq_map (offset 0x4b8 in ice_vsi). + + The faulting VSI is an allocated slab object but not fully initialized + after a failed ice_vsi_rebuild(): + + crash> struct ice_vsi 0xff34c9efc27d4828 + netdev = 0x0, + rx_rings = 0x0, + tx_rings = 0x0, + q_vectors = 0x0, + txq_map = 0x0, + rxq_map = 0x0, + alloc_txq = 0x10, + num_txq = 0x10, + alloc_rxq = 0x10, + num_rxq = 0x10, + + The nvmupdate64e process was performing NVM firmware update: + + crash> bt 0xff34c9edd1a30000 + PID: 49858 TASK: ff34c9edd1a30000 CPU: 1 COMMAND: "nvmupdate64e" + #0 [ff72159bcd617618] __schedule at ffffffffab5333f8 + #4 [ff72159bcd617750] ice_sq_send_cmd at ffffffffc0a35347 [ice] + #5 [ff72159bcd6177a8] ice_sq_send_cmd_retry at ffffffffc0a35b47 [ice] + #6 [ff72159bcd617810] ice_aq_send_cmd at ffffffffc0a38018 [ice] + #7 [ff72159bcd617848] ice_aq_read_nvm at ffffffffc0a40254 [ice] + #8 [ff72159bcd6178b8] ice_read_flat_nvm at ffffffffc0a4034c [ice] + #9 [ff72159bcd617918] ice_devlink_nvm_snapshot at ffffffffc0a6ffa5 [ice] + + dmesg: + ice 0000:13:00.0: firmware recommends not updating fw.mgmt, as it + may result in a downgrade. continuing anyways + ice 0000:13:00.1: ice_init_nvm failed -5 + ice 0000:13:00.1: Rebuild failed, unload and reload driver + +Fixes: 12bb018c538c ("ice: Refactor VF reset") +Signed-off-by: Petr Oros +Tested-by: Rafal Romanowski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-5-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +index 58f9ac81dfbb2..1463fee451efc 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +@@ -787,7 +787,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) + ice_vf_ctrl_invalidate_vsi(vf); + + ice_vf_pre_vsi_rebuild(vf); +- ice_vf_rebuild_vsi(vf); ++ if (ice_vf_rebuild_vsi(vf)) { ++ dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", ++ vf->vf_id); ++ mutex_unlock(&vf->cfg_lock); ++ continue; ++ } + ice_vf_post_vsi_rebuild(vf); + + mutex_unlock(&vf->cfg_lock); +-- +2.53.0 + diff --git a/queue-6.6/ice-remove-jumbo_remove-step-from-tx-path.patch b/queue-6.6/ice-remove-jumbo_remove-step-from-tx-path.patch new file mode 100644 index 0000000000..1b3bea8fa6 --- /dev/null +++ b/queue-6.6/ice-remove-jumbo_remove-step-from-tx-path.patch @@ -0,0 +1,41 @@ +From cd88c22ce5bc58694360ef70aa974e7162715a78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 15:39:20 +0200 +Subject: ice: Remove jumbo_remove step from TX path + +From: Alice Mikityanska + +[ Upstream commit 8b76102c5e00d1f090e0c31d17b060c76d8fa859 ] + +Now that the kernel doesn't insert HBH for BIG TCP IPv6 packets, remove +unnecessary steps from the ice TX path, that used to check and remove +HBH. + +Signed-off-by: Alice Mikityanska +Acked-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260205133925.526371-8-alice.kernel@fastmail.im +Signed-off-by: Jakub Kicinski +Stable-dep-of: 1a303baa715e ("ice: fix double-free of tx_buf skb") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index eae4376c68595..66da8a34be0f1 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2364,9 +2364,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + +- if (unlikely(ipv6_hopopt_jumbo_remove(skb))) +- goto out_drop; +- + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +-- +2.53.0 + diff --git a/queue-6.6/ima-check-return-value-of-crypto_shash_final-in-boot.patch b/queue-6.6/ima-check-return-value-of-crypto_shash_final-in-boot.patch new file mode 100644 index 0000000000..19f6268b3e --- /dev/null +++ b/queue-6.6/ima-check-return-value-of-crypto_shash_final-in-boot.patch @@ -0,0 +1,41 @@ +From f7d847dbf04084274bef22a845b4feb8ed5826b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 18:40:15 -0800 +Subject: ima: check return value of crypto_shash_final() in boot aggregate + +From: Daniel Hodges + +[ Upstream commit 870819434c8dfcc3158033b66e7851b81bb17e21 ] + +The return value of crypto_shash_final() is not checked in +ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the +function returns success and a corrupted boot aggregate digest could +be used for IMA measurements. + +Capture the return value and propagate any error to the caller. + +Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash") +Signed-off-by: Daniel Hodges +Reviewed-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index 51ad29940f05c..2b611bf169dd9 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -837,7 +837,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, + } + } + if (!rc) +- crypto_shash_final(shash, digest); ++ rc = crypto_shash_final(shash, digest); + return rc; + } + +-- +2.53.0 + diff --git a/queue-6.6/iommufd-vfio-compatibility-extension-check-for-noiom.patch b/queue-6.6/iommufd-vfio-compatibility-extension-check-for-noiom.patch new file mode 100644 index 0000000000..c8865c77aa --- /dev/null +++ b/queue-6.6/iommufd-vfio-compatibility-extension-check-for-noiom.patch @@ -0,0 +1,40 @@ +From cbb90594362fa9518f052b711146a58a22b18808 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 10:36:36 -0800 +Subject: iommufd: vfio compatibility extension check for noiommu mode + +From: Jacob Pan + +[ Upstream commit 7147ec874ea08c322d779d8eba28946e294ed1f3 ] + +VFIO_CHECK_EXTENSION should return false for TYPE1_IOMMU variants when +in NO-IOMMU mode and IOMMUFD compat container is set. This change makes +the behavior match VFIO_CONTAINER in noiommu mode. It also prevents +userspace from incorrectly attempting to use TYPE1 IOMMU operations +in a no-iommu context. + +Fixes: d624d6652a65 ("iommufd: vfio container FD ioctl compatibility") +Link: https://patch.msgid.link/r/20260213183636.3340-1-jacob.pan@linux.microsoft.com +Signed-off-by: Jacob Pan +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommufd/vfio_compat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c +index 6c810bf80f99a..7351320394c85 100644 +--- a/drivers/iommu/iommufd/vfio_compat.c ++++ b/drivers/iommu/iommufd/vfio_compat.c +@@ -283,7 +283,7 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx, + case VFIO_TYPE1_IOMMU: + case VFIO_TYPE1v2_IOMMU: + case VFIO_UNMAP_ALL: +- return 1; ++ return !ictx->no_iommu_mode; + + case VFIO_NOIOMMU_IOMMU: + return IS_ENABLED(CONFIG_VFIO_NOIOMMU); +-- +2.53.0 + diff --git a/queue-6.6/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch b/queue-6.6/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch new file mode 100644 index 0000000000..ea3bcaccbe --- /dev/null +++ b/queue-6.6/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch @@ -0,0 +1,114 @@ +From 4f1e39b91efe065a0d2ff7638e1b90fcfe5438fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:06:01 +0800 +Subject: ipmi: ssif_bmc: change log level to dbg in irq callback + +From: Jian Zhang + +[ Upstream commit c9c99b7b7051eb7121b3224bfce181fb023b0269 ] + +Long-running tests indicate that this logging can occasionally disrupt +timing and lead to request/response corruption. + +Irq handler need to be executed as fast as possible, +most I2C slave IRQ implementations are byte-level, logging here +can significantly affect transfer behavior and timing. It is recommended +to use dev_dbg() for these messages. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-4-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index a13dc48120581..5d5444b567a04 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -568,7 +568,7 @@ static void process_request_part(struct ssif_bmc_ctx *ssif_bmc) + len = ssif_bmc->request.len + part->length; + /* Do the bound check here, not allow the request len exceed 254 bytes */ + if (len > IPMI_SSIF_PAYLOAD_MAX) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: Request exceeded 254 bytes, aborting"); + /* Request too long, aborting */ + ssif_bmc->aborting = true; +@@ -614,7 +614,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected READ REQUESTED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -623,7 +623,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + if (!supported_read_cmd(ssif_bmc->part_buf.smbus_cmd)) { +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", + ssif_bmc->part_buf.smbus_cmd); + ssif_bmc->aborting = true; + } +@@ -658,7 +658,7 @@ static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_SMBUS_CMD) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected READ PROCESSED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -683,7 +683,7 @@ static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + } else if (ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE REQUEST in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -698,7 +698,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + { + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -708,7 +708,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + if (!supported_write_cmd(ssif_bmc->part_buf.smbus_cmd)) { +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", + ssif_bmc->part_buf.smbus_cmd); + ssif_bmc->aborting = true; + } +@@ -737,7 +737,7 @@ static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_SMBUS_CMD || + ssif_bmc->state == SSIF_ABORTING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected SLAVE STOP in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_READY; +@@ -804,7 +804,7 @@ static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 + break; + + default: +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); + break; + } + +-- +2.53.0 + diff --git a/queue-6.6/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch b/queue-6.6/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch new file mode 100644 index 0000000000..21eea40b64 --- /dev/null +++ b/queue-6.6/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch @@ -0,0 +1,88 @@ +From 69cc0dc98d1defb16732ff0b9f42beefa0908a9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:06:00 +0800 +Subject: ipmi: ssif_bmc: fix message desynchronization after truncated + response + +From: Jian Zhang + +[ Upstream commit 1d38e849adb6851ee280aa1a1d687b2181549a66 ] + +A truncated response, caused by host power-off, or other conditions, +can lead to message desynchronization. + +Raw trace data (STOP loss scenario, add state transition comment): + +1. T-1: Read response phase (SSIF_RES_SENDING) +8271.955342 WR_RCV [03] <- Read polling cmd +8271.955348 RD_REQ [04] <== SSIF_RES_SENDING <- start sending response +8271.955436 RD_PRO [b4] +8271.955527 RD_PRO [00] +8271.955618 RD_PRO [c1] +8271.955707 RD_PRO [00] +8271.955814 RD_PRO [ad] <== SSIF_RES_SENDING <- last byte + <- !! STOP lost (truncated response) + +2. T: New Write request arrives, BMC still in SSIF_RES_SENDING +8271.967973 WR_REQ [] <== SSIF_RES_SENDING >> SSIF_ABORTING <- log: unexpected WR_REQ in RES_SENDING +8271.968447 WR_RCV [02] <== SSIF_ABORTING <- do nothing +8271.968452 WR_RCV [02] <== SSIF_ABORTING <- do nothing +8271.968454 WR_RCV [18] <== SSIF_ABORTING <- do nothing +8271.968456 WR_RCV [01] <== SSIF_ABORTING <- do nothing +8271.968458 WR_RCV [66] <== SSIF_ABORTING <- do nothing +8271.978714 STOP [] <== SSIF_ABORTING >> SSIF_READY <- log: unexpected SLAVE STOP in state=SSIF_ABORTING + +3. T+1: Next Read polling, treated as a fresh transaction +8271.979125 WR_REQ [] <== SSIF_READY >> SSIF_START +8271.979326 WR_RCV [03] <== SSIF_START >> SSIF_SMBUS_CMD <- smbus_cmd=0x03 +8271.979331 RD_REQ [04] <== SSIF_RES_SENDING <- sending response +8271.979427 RD_PRO [b4] <- !! this is T's stale response -> desynchronization + +When in SSIF_ABORTING state, a newly arrived command should still be +handled to avoid dropping the request or causing message +desynchronization. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-3-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index 6928adb5df5ab..a13dc48120581 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -457,6 +457,15 @@ static bool supported_write_cmd(u8 cmd) + return false; + } + ++static bool supported_write_start_cmd(u8 cmd) ++{ ++ if (cmd == SSIF_IPMI_SINGLEPART_WRITE || ++ cmd == SSIF_IPMI_MULTIPART_WRITE_START) ++ return true; ++ ++ return false; ++} ++ + /* Process the IPMI response that will be read by master */ + static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + { +@@ -708,6 +717,11 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state = SSIF_ABORTING; + else + ssif_bmc->state = SSIF_REQ_RECVING; ++ } else if (ssif_bmc->state == SSIF_ABORTING) { ++ if (supported_write_start_cmd(*val)) { ++ ssif_bmc->state = SSIF_SMBUS_CMD; ++ ssif_bmc->aborting = false; ++ } + } + + /* This is response sending state */ +-- +2.53.0 + diff --git a/queue-6.6/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch b/queue-6.6/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch new file mode 100644 index 0000000000..042054fec5 --- /dev/null +++ b/queue-6.6/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch @@ -0,0 +1,42 @@ +From e22ebb2163612b16ccf7e9b5046f3f5ac843d05a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:05:59 +0800 +Subject: ipmi: ssif_bmc: fix missing check for copy_to_user() partial failure + +From: Jian Zhang + +[ Upstream commit ea641be7a4faee4351f9c5ed6b188e1bbf5586a6 ] + +copy_to_user() returns the number of bytes that could not be copied, +with a non-zero value indicating a partial or complete failure. The +current code only checks for negative return values and treats all +non-negative results as success. + +Treating any positive return value from copy_to_user() as +an error and returning -EFAULT. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-2-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index e8460e966b83e..6928adb5df5ab 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -163,6 +163,8 @@ static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + ret = copy_to_user(buf, &msg, count); ++ if (ret > 0) ++ ret = -EFAULT; + } + + return (ret < 0) ? ret : count; +-- +2.53.0 + diff --git a/queue-6.6/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch b/queue-6.6/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch new file mode 100644 index 0000000000..d896672f26 --- /dev/null +++ b/queue-6.6/ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch @@ -0,0 +1,145 @@ +From 3cb7307ea7ad1744fda59f22c9fb35c2f1423716 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:22 +0200 +Subject: ipv4: add new arguments to udp_tunnel_dst_lookup() + +From: Beniamino Galvani + +[ Upstream commit 72fc68c6356b663a8763f02d9b0ec773d59a4949 ] + +We want to make the function more generic so that it can be used by +other UDP tunnel implementations such as geneve and vxlan. To do that, +add the following arguments: + + - source and destination UDP port; + - ifindex of the output interface, needed by vxlan; + - the tos, because in some cases it is not taken from struct + ip_tunnel_info (for example, when it's inherited from the inner + packet); + - the dst cache, because not all tunnel types (e.g. vxlan) want to + use the one from struct ip_tunnel_info. + +With these parameters, the function no longer needs the full struct +ip_tunnel_info as argument and we can pass only the relevant part of +it (struct ip_tunnel_key). + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 11 +++++++---- + include/net/udp_tunnel.h | 8 +++++--- + net/ipv4/udp_tunnel_core.c | 26 +++++++++++++------------- + 3 files changed, 25 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 1a9a43ed462a8..385cc386ecaee 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -325,8 +325,10 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, +- use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, &info->key, ++ 0, 0, key->tos, ++ use_cache ? ++ (struct dst_cache *)&info->dst_cache : NULL); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -505,8 +507,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct rtable *rt; + __be32 saddr; + +- rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, +- info, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, ++ &info->key, 0, 0, info->key.tos, ++ use_cache ? &info->dst_cache : NULL); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index fd664b2001053..a8ff2613fabc2 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -163,9 +163,11 @@ void udp_tunnel_sock_release(struct socket *sock); + + struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- bool use_cache); ++ struct net *net, int oif, ++ __be32 *saddr, ++ const struct ip_tunnel_key *key, ++ __be16 sport, __be16 dport, u8 tos, ++ struct dst_cache *dst_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 9b0cfd72d5fda..494685e828563 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -206,31 +206,31 @@ EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + + struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- bool use_cache) ++ struct net *net, int oif, ++ __be32 *saddr, ++ const struct ip_tunnel_key *key, ++ __be16 sport, __be16 dport, u8 tos, ++ struct dst_cache *dst_cache) + { +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif + struct rtable *rt = NULL; + struct flowi4 fl4; +- __u8 tos; + + #ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { ++ if (dst_cache) { + rt = dst_cache_get_ip4(dst_cache, saddr); + if (rt) + return rt; + } + #endif ++ + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; + fl4.flowi4_proto = IPPROTO_UDP; +- fl4.daddr = info->key.u.ipv4.dst; +- fl4.saddr = info->key.u.ipv4.src; +- tos = info->key.tos; ++ fl4.flowi4_oif = oif; ++ fl4.daddr = key->u.ipv4.dst; ++ fl4.saddr = key->u.ipv4.src; ++ fl4.fl4_dport = dport; ++ fl4.fl4_sport = sport; + fl4.flowi4_tos = RT_TOS(tos); + + rt = ip_route_output_key(net, &fl4); +@@ -244,7 +244,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + return ERR_PTR(-ELOOP); + } + #ifdef CONFIG_DST_CACHE +- if (use_cache) ++ if (dst_cache) + dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); + #endif + *saddr = fl4.saddr; +-- +2.53.0 + diff --git a/queue-6.6/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch b/queue-6.6/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch new file mode 100644 index 0000000000..217f6b5d11 --- /dev/null +++ b/queue-6.6/ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch @@ -0,0 +1,83 @@ +From ff1957c1a4badad8693259b5df292637e4ba5c3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:21 +0200 +Subject: ipv4: remove "proto" argument from udp_tunnel_dst_lookup() + +From: Beniamino Galvani + +[ Upstream commit 78f3655adcb52412275f282267ee771421731632 ] + +The function is now UDP-specific, the protocol is always IPPROTO_UDP. + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 4 ++-- + include/net/udp_tunnel.h | 2 +- + net/ipv4/udp_tunnel_core.c | 4 ++-- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index bbc246d27f88a..1a9a43ed462a8 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -326,7 +326,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + return -ESHUTDOWN; + + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, +- IPPROTO_UDP, use_cache); ++ use_cache); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -506,7 +506,7 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + __be32 saddr; + + rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, +- info, IPPROTO_UDP, use_cache); ++ info, use_cache); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index 42a03485c5975..fd664b2001053 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -165,7 +165,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, __be32 *saddr, + const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); ++ bool use_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 96f93f92b6ced..9b0cfd72d5fda 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -208,7 +208,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + struct net_device *dev, + struct net *net, __be32 *saddr, + const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache) ++ bool use_cache) + { + #ifdef CONFIG_DST_CACHE + struct dst_cache *dst_cache; +@@ -227,7 +227,7 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + #endif + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_mark = skb->mark; +- fl4.flowi4_proto = protocol; ++ fl4.flowi4_proto = IPPROTO_UDP; + fl4.daddr = info->key.u.ipv4.dst; + fl4.saddr = info->key.u.ipv4.src; + tos = info->key.tos; +-- +2.53.0 + diff --git a/queue-6.6/ipv4-rename-and-move-ip_route_output_tunnel.patch b/queue-6.6/ipv4-rename-and-move-ip_route_output_tunnel.patch new file mode 100644 index 0000000000..e87a561b53 --- /dev/null +++ b/queue-6.6/ipv4-rename-and-move-ip_route_output_tunnel.patch @@ -0,0 +1,211 @@ +From acb10b54a56e44725f59284631f2750d07148247 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Oct 2023 09:15:20 +0200 +Subject: ipv4: rename and move ip_route_output_tunnel() + +From: Beniamino Galvani + +[ Upstream commit bf3fcbf7e7a08015d3b169bad6281b29d45c272d ] + +At the moment ip_route_output_tunnel() is used only by bareudp. +Ideally, other UDP tunnel implementations should use it, but to do so +the function needs to accept new parameters that are specific for UDP +tunnels, such as the ports. + +Prepare for these changes by renaming the function to +udp_tunnel_dst_lookup() and move it to file +net/ipv4/udp_tunnel_core.c. + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 8 +++---- + include/net/route.h | 6 ----- + include/net/udp_tunnel.h | 6 +++++ + net/ipv4/route.c | 48 -------------------------------------- + net/ipv4/udp_tunnel_core.c | 48 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 58 insertions(+), 58 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index cfbc0240126ef..bbc246d27f88a 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -325,8 +325,8 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, info, +- IPPROTO_UDP, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, info, ++ IPPROTO_UDP, use_cache); + + if (IS_ERR(rt)) + return PTR_ERR(rt); +@@ -505,8 +505,8 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct rtable *rt; + __be32 saddr; + +- rt = ip_route_output_tunnel(skb, dev, bareudp->net, &saddr, +- info, IPPROTO_UDP, use_cache); ++ rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, &saddr, ++ info, IPPROTO_UDP, use_cache); + if (IS_ERR(rt)) + return PTR_ERR(rt); + +diff --git a/include/net/route.h b/include/net/route.h +index 27c17aff0bbe1..22d8095a3a81e 100644 +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -136,12 +136,6 @@ static inline struct rtable *__ip_route_output_key(struct net *net, + + struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp, + const struct sock *sk); +-struct rtable *ip_route_output_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); +- + struct dst_entry *ipv4_blackhole_route(struct net *net, + struct dst_entry *dst_orig); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index 0e6eb40cd7778..42a03485c5975 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -161,6 +161,12 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + + void udp_tunnel_sock_release(struct socket *sock); + ++struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, __be32 *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache); ++ + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, + int md_size); +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 55ea367f95b3b..f134c59f839e2 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -2918,54 +2918,6 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4, + } + EXPORT_SYMBOL_GPL(ip_route_output_flow); + +-struct rtable *ip_route_output_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, __be32 *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache) +-{ +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif +- struct rtable *rt = NULL; +- struct flowi4 fl4; +- __u8 tos; +- +-#ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { +- rt = dst_cache_get_ip4(dst_cache, saddr); +- if (rt) +- return rt; +- } +-#endif +- memset(&fl4, 0, sizeof(fl4)); +- fl4.flowi4_mark = skb->mark; +- fl4.flowi4_proto = protocol; +- fl4.daddr = info->key.u.ipv4.dst; +- fl4.saddr = info->key.u.ipv4.src; +- tos = info->key.tos; +- fl4.flowi4_tos = RT_TOS(tos); +- +- rt = ip_route_output_key(net, &fl4); +- if (IS_ERR(rt)) { +- netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); +- return ERR_PTR(-ENETUNREACH); +- } +- if (rt->dst.dev == dev) { /* is this necessary? */ +- netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); +- ip_rt_put(rt); +- return ERR_PTR(-ELOOP); +- } +-#ifdef CONFIG_DST_CACHE +- if (use_cache) +- dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); +-#endif +- *saddr = fl4.saddr; +- return rt; +-} +-EXPORT_SYMBOL_GPL(ip_route_output_tunnel); +- + /* called with rcu_read_lock held */ + static int rt_fill_info(struct net *net, __be32 dst, __be32 src, + struct rtable *rt, u32 table_id, dscp_t dscp, +diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c +index 1e7e4aecdc48a..96f93f92b6ced 100644 +--- a/net/ipv4/udp_tunnel_core.c ++++ b/net/ipv4/udp_tunnel_core.c +@@ -204,4 +204,52 @@ struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + } + EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + ++struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, __be32 *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache) ++{ ++#ifdef CONFIG_DST_CACHE ++ struct dst_cache *dst_cache; ++#endif ++ struct rtable *rt = NULL; ++ struct flowi4 fl4; ++ __u8 tos; ++ ++#ifdef CONFIG_DST_CACHE ++ dst_cache = (struct dst_cache *)&info->dst_cache; ++ if (use_cache) { ++ rt = dst_cache_get_ip4(dst_cache, saddr); ++ if (rt) ++ return rt; ++ } ++#endif ++ memset(&fl4, 0, sizeof(fl4)); ++ fl4.flowi4_mark = skb->mark; ++ fl4.flowi4_proto = protocol; ++ fl4.daddr = info->key.u.ipv4.dst; ++ fl4.saddr = info->key.u.ipv4.src; ++ tos = info->key.tos; ++ fl4.flowi4_tos = RT_TOS(tos); ++ ++ rt = ip_route_output_key(net, &fl4); ++ if (IS_ERR(rt)) { ++ netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); ++ return ERR_PTR(-ENETUNREACH); ++ } ++ if (rt->dst.dev == dev) { /* is this necessary? */ ++ netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); ++ ip_rt_put(rt); ++ return ERR_PTR(-ELOOP); ++ } ++#ifdef CONFIG_DST_CACHE ++ if (use_cache) ++ dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr); ++#endif ++ *saddr = fl4.saddr; ++ return rt; ++} ++EXPORT_SYMBOL_GPL(udp_tunnel_dst_lookup); ++ + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.6/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch b/queue-6.6/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch new file mode 100644 index 0000000000..3cc6986c2d --- /dev/null +++ b/queue-6.6/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch @@ -0,0 +1,71 @@ +From 04074122fe113450665aae1a5a09596b382613e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 10:35:05 +0000 +Subject: ipv6: fix possible UAF in icmpv6_rcv() + +From: Eric Dumazet + +[ Upstream commit f996edd7615e686ada141b7f3395025729ff8ccb ] + +Caching saddr and daddr before pskb_pull() is problematic +since skb->head can change. + +Remove these temporary variables: + +- We only access &ipv6_hdr(skb)->saddr and &ipv6_hdr(skb)->daddr + when net_dbg_ratelimited() is called in the slow path. + +- Avoid potential future misuse after pskb_pull() call. + +Fixes: 4b3418fba0fe ("ipv6: icmp: include addresses in debug messages") +Signed-off-by: Eric Dumazet +Reviewed-by: Fernando Fernandez Mancera +Reviewed-by: Joe Damato +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260416103505.2380753-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/icmp.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index 0002fe04e0409..9c56612c66211 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -907,7 +907,6 @@ static int icmpv6_rcv(struct sk_buff *skb) + struct net *net = dev_net_rcu(skb->dev); + struct net_device *dev = icmp6_dev(skb); + struct inet6_dev *idev = __in6_dev_get(dev); +- const struct in6_addr *saddr, *daddr; + struct icmp6hdr *hdr; + u8 type; + +@@ -938,12 +937,10 @@ static int icmpv6_rcv(struct sk_buff *skb) + + __ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS); + +- saddr = &ipv6_hdr(skb)->saddr; +- daddr = &ipv6_hdr(skb)->daddr; +- + if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { + net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + goto csum_error; + } + +@@ -1026,7 +1023,8 @@ static int icmpv6_rcv(struct sk_buff *skb) + break; + + net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + + /* + * error of unknown type. +-- +2.53.0 + diff --git a/queue-6.6/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch b/queue-6.6/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch new file mode 100644 index 0000000000..06383a0220 --- /dev/null +++ b/queue-6.6/ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch @@ -0,0 +1,262 @@ +From ab54df345bbbc4b49a87875ab1e6bce505435379 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Oct 2023 13:55:25 +0200 +Subject: ipv6: rename and move ip6_dst_lookup_tunnel() + +From: Beniamino Galvani + +[ Upstream commit fc47e86dbfb75a864c0c9dd8e78affb6506296bb ] + +At the moment ip6_dst_lookup_tunnel() is used only by bareudp. +Ideally, other UDP tunnel implementations should use it, but to do so +the function needs to accept new parameters that are specific for UDP +tunnels, such as the ports. + +Prepare for these changes by renaming the function to +udp_tunnel6_dst_lookup() and move it to file +net/ipv6/ip6_udp_tunnel.c. + +This is similar to what already done for IPv4 in commit bf3fcbf7e7a0 +("ipv4: rename and move ip_route_output_tunnel()"). + +Suggested-by: Guillaume Nault +Signed-off-by: Beniamino Galvani +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: aa6c6d9ee064 ("bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()") +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 10 +++--- + include/net/ipv6.h | 6 ---- + include/net/udp_tunnel.h | 7 ++++ + net/ipv6/ip6_output.c | 68 -------------------------------------- + net/ipv6/ip6_udp_tunnel.c | 69 +++++++++++++++++++++++++++++++++++++++ + 5 files changed, 81 insertions(+), 79 deletions(-) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 385cc386ecaee..150049d9a81a7 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -393,8 +393,8 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (!sock) + return -ESHUTDOWN; + +- dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, &saddr, info, +- IPPROTO_UDP, use_cache); ++ dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, &saddr, info, ++ IPPROTO_UDP, use_cache); + if (IS_ERR(dst)) + return PTR_ERR(dst); + +@@ -520,9 +520,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + +- dst = ip6_dst_lookup_tunnel(skb, dev, bareudp->net, sock, +- &saddr, info, IPPROTO_UDP, +- use_cache); ++ dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, ++ &saddr, info, IPPROTO_UDP, ++ use_cache); + if (IS_ERR(dst)) + return PTR_ERR(dst); + +diff --git a/include/net/ipv6.h b/include/net/ipv6.h +index d98f5390ffad3..3645776d71c9c 100644 +--- a/include/net/ipv6.h ++++ b/include/net/ipv6.h +@@ -1133,12 +1133,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, st + struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, + const struct in6_addr *final_dst, + bool connected); +-struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, struct socket *sock, +- struct in6_addr *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, bool use_cache); + struct dst_entry *ip6_blackhole_route(struct net *net, + struct dst_entry *orig_dst); + +diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h +index a8ff2613fabc2..6818a59a1ebcb 100644 +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -168,6 +168,13 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb, + const struct ip_tunnel_key *key, + __be16 sport, __be16 dport, u8 tos, + struct dst_cache *dst_cache); ++struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, ++ struct socket *sock, ++ struct in6_addr *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, bool use_cache); + + struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index a824c707dffff..710aadbb2e267 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1307,74 +1307,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, + } + EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); + +-/** +- * ip6_dst_lookup_tunnel - perform route lookup on tunnel +- * @skb: Packet for which lookup is done +- * @dev: Tunnel device +- * @net: Network namespace of tunnel device +- * @sock: Socket which provides route info +- * @saddr: Memory to store the src ip address +- * @info: Tunnel information +- * @protocol: IP protocol +- * @use_cache: Flag to enable cache usage +- * This function performs a route lookup on a tunnel +- * +- * It returns a valid dst pointer and stores src address to be used in +- * tunnel in param saddr on success, else a pointer encoded error code. +- */ +- +-struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +- struct net_device *dev, +- struct net *net, +- struct socket *sock, +- struct in6_addr *saddr, +- const struct ip_tunnel_info *info, +- u8 protocol, +- bool use_cache) +-{ +- struct dst_entry *dst = NULL; +-#ifdef CONFIG_DST_CACHE +- struct dst_cache *dst_cache; +-#endif +- struct flowi6 fl6; +- __u8 prio; +- +-#ifdef CONFIG_DST_CACHE +- dst_cache = (struct dst_cache *)&info->dst_cache; +- if (use_cache) { +- dst = dst_cache_get_ip6(dst_cache, saddr); +- if (dst) +- return dst; +- } +-#endif +- memset(&fl6, 0, sizeof(fl6)); +- fl6.flowi6_mark = skb->mark; +- fl6.flowi6_proto = protocol; +- fl6.daddr = info->key.u.ipv6.dst; +- fl6.saddr = info->key.u.ipv6.src; +- prio = info->key.tos; +- fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); +- +- dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, +- NULL); +- if (IS_ERR(dst)) { +- netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); +- return ERR_PTR(-ENETUNREACH); +- } +- if (dst->dev == dev) { /* is this necessary? */ +- netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); +- dst_release(dst); +- return ERR_PTR(-ELOOP); +- } +-#ifdef CONFIG_DST_CACHE +- if (use_cache) +- dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); +-#endif +- *saddr = fl6.saddr; +- return dst; +-} +-EXPORT_SYMBOL_GPL(ip6_dst_lookup_tunnel); +- + static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, + gfp_t gfp) + { +diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c +index cdc4d4ee24206..7aef559e60ec5 100644 +--- a/net/ipv6/ip6_udp_tunnel.c ++++ b/net/ipv6/ip6_udp_tunnel.c +@@ -1,3 +1,4 @@ ++ + // SPDX-License-Identifier: GPL-2.0-only + #include + #include +@@ -111,4 +112,72 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + } + EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); + ++/** ++ * udp_tunnel6_dst_lookup - perform route lookup on UDP tunnel ++ * @skb: Packet for which lookup is done ++ * @dev: Tunnel device ++ * @net: Network namespace of tunnel device ++ * @sock: Socket which provides route info ++ * @saddr: Memory to store the src ip address ++ * @info: Tunnel information ++ * @protocol: IP protocol ++ * @use_cache: Flag to enable cache usage ++ * This function performs a route lookup on a UDP tunnel ++ * ++ * It returns a valid dst pointer and stores src address to be used in ++ * tunnel in param saddr on success, else a pointer encoded error code. ++ */ ++ ++struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb, ++ struct net_device *dev, ++ struct net *net, ++ struct socket *sock, ++ struct in6_addr *saddr, ++ const struct ip_tunnel_info *info, ++ u8 protocol, ++ bool use_cache) ++{ ++ struct dst_entry *dst = NULL; ++#ifdef CONFIG_DST_CACHE ++ struct dst_cache *dst_cache; ++#endif ++ struct flowi6 fl6; ++ __u8 prio; ++ ++#ifdef CONFIG_DST_CACHE ++ dst_cache = (struct dst_cache *)&info->dst_cache; ++ if (use_cache) { ++ dst = dst_cache_get_ip6(dst_cache, saddr); ++ if (dst) ++ return dst; ++ } ++#endif ++ memset(&fl6, 0, sizeof(fl6)); ++ fl6.flowi6_mark = skb->mark; ++ fl6.flowi6_proto = protocol; ++ fl6.daddr = info->key.u.ipv6.dst; ++ fl6.saddr = info->key.u.ipv6.src; ++ prio = info->key.tos; ++ fl6.flowlabel = ip6_make_flowinfo(prio, info->key.label); ++ ++ dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, ++ NULL); ++ if (IS_ERR(dst)) { ++ netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); ++ return ERR_PTR(-ENETUNREACH); ++ } ++ if (dst->dev == dev) { /* is this necessary? */ ++ netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); ++ dst_release(dst); ++ return ERR_PTR(-ELOOP); ++ } ++#ifdef CONFIG_DST_CACHE ++ if (use_cache) ++ dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); ++#endif ++ *saddr = fl6.saddr; ++ return dst; ++} ++EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup); ++ + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.6/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch b/queue-6.6/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch new file mode 100644 index 0000000000..ec40c39ace --- /dev/null +++ b/queue-6.6/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch @@ -0,0 +1,97 @@ +From 028d2040ec5d3a0a8ca713ef7e9407447d62d101 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:40:29 +0800 +Subject: ipvs: fix MTU check for GSO packets in tunnel mode + +From: Yingnan Zhang <342144303@qq.com> + +[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ] + +Currently, IPVS skips MTU checks for GSO packets by excluding them with +the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel +mode encapsulates GSO packets with IPIP headers. + +The issue manifests in two ways: + +1. MTU violation after encapsulation: + When a GSO packet passes through IPVS tunnel mode, the original MTU + check is bypassed. After adding the IPIP tunnel header, the packet + size may exceed the outgoing interface MTU, leading to unexpected + fragmentation at the IP layer. + +2. Fragmentation with problematic IP IDs: + When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments + is fragmented after encapsulation, each segment gets a sequentially + incremented IP ID (0, 1, 2, ...). This happens because: + + a) The GSO packet bypasses MTU check and gets encapsulated + b) At __ip_finish_output, the oversized GSO packet is split into + separate SKBs (one per segment), with IP IDs incrementing + c) Each SKB is then fragmented again based on the actual MTU + + This sequential IP ID allocation differs from the expected behavior + and can cause issues with fragment reassembly and packet tracking. + +Fix this by properly validating GSO packets using +skb_gso_validate_network_len(). This function correctly validates +whether the GSO segments will fit within the MTU after segmentation. If +validation fails, send an ICMP Fragmentation Needed message to enable +proper PMTU discovery. + +Fixes: 4cdd34084d53 ("netfilter: nf_conntrack_ipv6: improve fragmentation handling") +Signed-off-by: Yingnan Zhang <342144303@qq.com> +Acked-by: Julian Anastasov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index 2877706f0162f..819538d2e4600 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -103,6 +103,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest) + return dest_dst; + } + ++/* Based on ip_exceeds_mtu(). */ ++static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) ++{ ++ if (skb->len <= mtu) ++ return false; ++ ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) ++ return false; ++ ++ return true; ++} ++ + static inline bool + __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + { +@@ -112,10 +124,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + */ + if (IP6CB(skb)->frag_max_size > mtu) + return true; /* largest fragment violate MTU */ +- } +- else if (skb->len > mtu && !skb_is_gso(skb)) { ++ } else if (ip_vs_exceeds_mtu(skb, mtu)) + return true; /* Packet size violate MTU size */ +- } ++ + return false; + } + +@@ -233,7 +244,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, + return true; + + if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && +- skb->len > mtu && !skb_is_gso(skb) && ++ ip_vs_exceeds_mtu(skb, mtu) && + !ip_vs_iph_icmp(ipvsh))) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); +-- +2.53.0 + diff --git a/queue-6.6/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch b/queue-6.6/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch new file mode 100644 index 0000000000..44f542deca --- /dev/null +++ b/queue-6.6/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch @@ -0,0 +1,48 @@ +From 1f91b06c25228261363be28c8a93b7e2a9b3ddbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Feb 2026 18:43:44 -0500 +Subject: irqchip/irq-pic32-evic: Address warning related to wrong printf() + formatter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 86be659415b0ddefebc3120e309091aa215a9064 ] + +This driver is currently only build on 32 bit MIPS systems. When building +it on x86_64, the following warning occurs: + + drivers/irqchip/irq-pic32-evic.c: In function ‘pic32_ext_irq_of_init’: + ./include/linux/kern_levels.h:5:25: error: format ‘%d’ expects argument of type + ‘int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] + +Update the printf() formatter in preparation for allowing this driver to +be compiled on all architectures. + +Fixes: aaa8666ada780 ("IRQCHIP: irq-pic32-evic: Add support for PIC32 interrupt controller") +Signed-off-by: Brian Masney +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260222-irqchip-pic32-v1-1-37f50d1f14af@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-pic32-evic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c +index 5d6b8e025bb87..3cc6b439f5f90 100644 +--- a/drivers/irqchip/irq-pic32-evic.c ++++ b/drivers/irqchip/irq-pic32-evic.c +@@ -196,7 +196,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain) + + of_property_for_each_u32(node, pname, hwirq) { + if (i >= ARRAY_SIZE(priv->ext_irqs)) { +- pr_warn("More than %d external irq, skip rest\n", ++ pr_warn("More than %zu external irq, skip rest\n", + ARRAY_SIZE(priv->ext_irqs)); + break; + } +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-add-support-for-supplementary-groups.patch b/queue-6.6/ksmbd-add-support-for-supplementary-groups.patch new file mode 100644 index 0000000000..c284c733e8 --- /dev/null +++ b/queue-6.6/ksmbd-add-support-for-supplementary-groups.patch @@ -0,0 +1,388 @@ +From 5f0cbc572efea65f7c5923955a8c14a5801fe1d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Oct 2024 10:39:16 +0900 +Subject: ksmbd: add support for supplementary groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Namjae Jeon + +[ Upstream commit a77e0e02af1c2db5fc040511aa78a58a52e116ab ] + +Even though system user has a supplementary group, It gets +NT_STATUS_ACCESS_DENIED when attempting to create file or directory. +This patch add KSMBD_EVENT_LOGIN_REQUEST_EXT/RESPONSE_EXT netlink events +to get supplementary groups list. The new netlink event doesn't break +backward compatibility when using old ksmbd-tools. + +Co-developed-by: Atte Heikkilä +Signed-off-by: Atte Heikkilä +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Stable-dep-of: b32c8db48212 ("ksmbd: destroy async_ida in ksmbd_conn_free()") +Signed-off-by: Sasha Levin +--- + fs/smb/server/auth.c | 6 ++- + fs/smb/server/ksmbd_netlink.h | 17 +++++++++ + fs/smb/server/mgmt/user_config.c | 45 ++++++++++++++++++---- + fs/smb/server/mgmt/user_config.h | 5 ++- + fs/smb/server/smb_common.c | 15 ++++++-- + fs/smb/server/transport_ipc.c | 64 ++++++++++++++++++++++++++++++-- + fs/smb/server/transport_ipc.h | 2 + + 7 files changed, 137 insertions(+), 17 deletions(-) + +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index d28b34e1d047a..825cc03692754 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -514,6 +514,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, + int in_len, char *out_blob, int *out_len) + { + struct ksmbd_spnego_authen_response *resp; ++ struct ksmbd_login_response_ext *resp_ext = NULL; + struct ksmbd_user *user = NULL; + int retval; + +@@ -542,7 +543,10 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, + goto out; + } + +- user = ksmbd_alloc_user(&resp->login_response); ++ if (resp->login_response.status & KSMBD_USER_FLAG_EXTENSION) ++ resp_ext = ksmbd_ipc_login_request_ext(resp->login_response.account); ++ ++ user = ksmbd_alloc_user(&resp->login_response, resp_ext); + if (!user) { + ksmbd_debug(AUTH, "login failure\n"); + retval = -ENOMEM; +diff --git a/fs/smb/server/ksmbd_netlink.h b/fs/smb/server/ksmbd_netlink.h +index 363501fc308aa..125ea1b9839ef 100644 +--- a/fs/smb/server/ksmbd_netlink.h ++++ b/fs/smb/server/ksmbd_netlink.h +@@ -51,6 +51,9 @@ + * - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response) + * This event is to make kerberos authentication to be processed in + * userspace. ++ * ++ * - KSMBD_EVENT_LOGIN_REQUEST_EXT/RESPONSE_EXT(ksmbd_login_request_ext/response_ext) ++ * This event is to get user account extension info to user IPC daemon. + */ + + #define KSMBD_GENL_NAME "SMBD_GENL" +@@ -147,6 +150,16 @@ struct ksmbd_login_response { + __u32 reserved[16]; /* Reserved room */ + }; + ++/* ++ * IPC user login response extension. ++ */ ++struct ksmbd_login_response_ext { ++ __u32 handle; ++ __s32 ngroups; /* supplementary group count */ ++ __s8 reserved[128]; /* Reserved room */ ++ __s8 ____payload[]; ++}; ++ + /* + * IPC request to fetch net share config. + */ +@@ -308,6 +321,9 @@ enum ksmbd_event { + KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, + KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15, + ++ KSMBD_EVENT_LOGIN_REQUEST_EXT, ++ KSMBD_EVENT_LOGIN_RESPONSE_EXT, ++ + __KSMBD_EVENT_MAX, + KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1 + }; +@@ -338,6 +354,7 @@ enum KSMBD_TREE_CONN_STATUS { + #define KSMBD_USER_FLAG_BAD_USER BIT(3) + #define KSMBD_USER_FLAG_GUEST_ACCOUNT BIT(4) + #define KSMBD_USER_FLAG_DELAY_SESSION BIT(5) ++#define KSMBD_USER_FLAG_EXTENSION BIT(6) + + /* + * Share config flags. +diff --git a/fs/smb/server/mgmt/user_config.c b/fs/smb/server/mgmt/user_config.c +index 279d00feff216..421a4a95e216a 100644 +--- a/fs/smb/server/mgmt/user_config.c ++++ b/fs/smb/server/mgmt/user_config.c +@@ -12,6 +12,7 @@ + struct ksmbd_user *ksmbd_login_user(const char *account) + { + struct ksmbd_login_response *resp; ++ struct ksmbd_login_response_ext *resp_ext = NULL; + struct ksmbd_user *user = NULL; + + resp = ksmbd_ipc_login_request(account); +@@ -21,15 +22,19 @@ struct ksmbd_user *ksmbd_login_user(const char *account) + if (!(resp->status & KSMBD_USER_FLAG_OK)) + goto out; + +- user = ksmbd_alloc_user(resp); ++ if (resp->status & KSMBD_USER_FLAG_EXTENSION) ++ resp_ext = ksmbd_ipc_login_request_ext(account); ++ ++ user = ksmbd_alloc_user(resp, resp_ext); + out: + kvfree(resp); + return user; + } + +-struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp) ++struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp, ++ struct ksmbd_login_response_ext *resp_ext) + { +- struct ksmbd_user *user = NULL; ++ struct ksmbd_user *user; + + user = kmalloc(sizeof(struct ksmbd_user), GFP_KERNEL); + if (!user) +@@ -44,18 +49,42 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp) + if (user->passkey) + memcpy(user->passkey, resp->hash, resp->hash_sz); + +- if (!user->name || !user->passkey) { +- kfree(user->name); +- kfree(user->passkey); +- kfree(user); +- user = NULL; ++ user->ngroups = 0; ++ user->sgid = NULL; ++ ++ if (!user->name || !user->passkey) ++ goto err_free; ++ ++ if (resp_ext) { ++ if (resp_ext->ngroups > NGROUPS_MAX) { ++ pr_err("ngroups(%u) from login response exceeds max groups(%d)\n", ++ resp_ext->ngroups, NGROUPS_MAX); ++ goto err_free; ++ } ++ ++ user->sgid = kmemdup(resp_ext->____payload, ++ resp_ext->ngroups * sizeof(gid_t), ++ GFP_KERNEL); ++ if (!user->sgid) ++ goto err_free; ++ ++ user->ngroups = resp_ext->ngroups; ++ ksmbd_debug(SMB, "supplementary groups : %d\n", user->ngroups); + } ++ + return user; ++ ++err_free: ++ kfree(user->name); ++ kfree(user->passkey); ++ kfree(user); ++ return NULL; + } + + void ksmbd_free_user(struct ksmbd_user *user) + { + ksmbd_ipc_logout_request(user->name, user->flags); ++ kfree(user->sgid); + kfree(user->name); + kfree(user->passkey); + kfree(user); +diff --git a/fs/smb/server/mgmt/user_config.h b/fs/smb/server/mgmt/user_config.h +index e068a19fd9049..8c227b8d49543 100644 +--- a/fs/smb/server/mgmt/user_config.h ++++ b/fs/smb/server/mgmt/user_config.h +@@ -18,6 +18,8 @@ struct ksmbd_user { + + size_t passkey_sz; + char *passkey; ++ int ngroups; ++ gid_t *sgid; + }; + + static inline bool user_guest(struct ksmbd_user *user) +@@ -60,7 +62,8 @@ static inline unsigned int user_gid(struct ksmbd_user *user) + } + + struct ksmbd_user *ksmbd_login_user(const char *account); +-struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp); ++struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp, ++ struct ksmbd_login_response_ext *resp_ext); + void ksmbd_free_user(struct ksmbd_user *user); + int ksmbd_anonymous_user(struct ksmbd_user *user); + bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2); +diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c +index 2839c704110cd..c64d1fc34d6bf 100644 +--- a/fs/smb/server/smb_common.c ++++ b/fs/smb/server/smb_common.c +@@ -740,13 +740,15 @@ int __ksmbd_override_fsids(struct ksmbd_work *work, + struct ksmbd_share_config *share) + { + struct ksmbd_session *sess = work->sess; ++ struct ksmbd_user *user = sess->user; + struct cred *cred; + struct group_info *gi; + unsigned int uid; + unsigned int gid; ++ int i; + +- uid = user_uid(sess->user); +- gid = user_gid(sess->user); ++ uid = user_uid(user); ++ gid = user_gid(user); + if (share->force_uid != KSMBD_SHARE_INVALID_UID) + uid = share->force_uid; + if (share->force_gid != KSMBD_SHARE_INVALID_GID) +@@ -759,11 +761,18 @@ int __ksmbd_override_fsids(struct ksmbd_work *work, + cred->fsuid = make_kuid(&init_user_ns, uid); + cred->fsgid = make_kgid(&init_user_ns, gid); + +- gi = groups_alloc(0); ++ gi = groups_alloc(user->ngroups); + if (!gi) { + abort_creds(cred); + return -ENOMEM; + } ++ ++ for (i = 0; i < user->ngroups; i++) ++ gi->gid[i] = make_kgid(&init_user_ns, user->sgid[i]); ++ ++ if (user->ngroups) ++ groups_sort(gi); ++ + set_groups(cred, gi); + put_group_info(gi); + +diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c +index 53bfcf57f167a..f0f93f76bc43d 100644 +--- a/fs/smb/server/transport_ipc.c ++++ b/fs/smb/server/transport_ipc.c +@@ -120,6 +120,12 @@ static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = { + }, + [KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = { + }, ++ [KSMBD_EVENT_LOGIN_REQUEST_EXT] = { ++ .len = sizeof(struct ksmbd_login_request), ++ }, ++ [KSMBD_EVENT_LOGIN_RESPONSE_EXT] = { ++ .len = sizeof(struct ksmbd_login_response_ext), ++ }, + }; + + static struct genl_ops ksmbd_genl_ops[] = { +@@ -187,6 +193,14 @@ static struct genl_ops ksmbd_genl_ops[] = { + .cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE, + .doit = handle_generic_event, + }, ++ { ++ .cmd = KSMBD_EVENT_LOGIN_REQUEST_EXT, ++ .doit = handle_unsupported_event, ++ }, ++ { ++ .cmd = KSMBD_EVENT_LOGIN_RESPONSE_EXT, ++ .doit = handle_generic_event, ++ }, + }; + + static struct genl_family ksmbd_genl_family = { +@@ -198,7 +212,7 @@ static struct genl_family ksmbd_genl_family = { + .module = THIS_MODULE, + .ops = ksmbd_genl_ops, + .n_ops = ARRAY_SIZE(ksmbd_genl_ops), +- .resv_start_op = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1, ++ .resv_start_op = KSMBD_EVENT_LOGIN_RESPONSE_EXT + 1, + }; + + static void ksmbd_nl_init_fixup(void) +@@ -478,16 +492,24 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) + { + unsigned int msg_sz = entry->msg_sz; + +- if (entry->type == KSMBD_EVENT_RPC_REQUEST) { ++ switch (entry->type) { ++ case KSMBD_EVENT_RPC_REQUEST: ++ { + struct ksmbd_rpc_command *resp = entry->response; + + msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; +- } else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) { ++ break; ++ } ++ case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST: ++ { + struct ksmbd_spnego_authen_response *resp = entry->response; + + msg_sz = sizeof(struct ksmbd_spnego_authen_response) + + resp->session_key_len + resp->spnego_blob_len; +- } else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) { ++ break; ++ } ++ case KSMBD_EVENT_SHARE_CONFIG_REQUEST: ++ { + struct ksmbd_share_config_response *resp = entry->response; + + if (resp->payload_sz) { +@@ -497,6 +519,17 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) + msg_sz = sizeof(struct ksmbd_share_config_response) + + resp->payload_sz; + } ++ break; ++ } ++ case KSMBD_EVENT_LOGIN_REQUEST_EXT: ++ { ++ struct ksmbd_login_response_ext *resp = entry->response; ++ ++ if (resp->ngroups) { ++ msg_sz = sizeof(struct ksmbd_login_response_ext) + ++ resp->ngroups * sizeof(gid_t); ++ } ++ } + } + + return entry->msg_sz != msg_sz ? -EINVAL : 0; +@@ -582,6 +615,29 @@ struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account) + return resp; + } + ++struct ksmbd_login_response_ext *ksmbd_ipc_login_request_ext(const char *account) ++{ ++ struct ksmbd_ipc_msg *msg; ++ struct ksmbd_login_request *req; ++ struct ksmbd_login_response_ext *resp; ++ ++ if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) ++ return NULL; ++ ++ msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request)); ++ if (!msg) ++ return NULL; ++ ++ msg->type = KSMBD_EVENT_LOGIN_REQUEST_EXT; ++ req = (struct ksmbd_login_request *)msg->payload; ++ req->handle = ksmbd_acquire_id(&ipc_ida); ++ strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); ++ resp = ipc_msg_send_request(msg, req->handle); ++ ipc_msg_handle_free(req->handle); ++ ipc_msg_free(msg); ++ return resp; ++} ++ + struct ksmbd_spnego_authen_response * + ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len) + { +diff --git a/fs/smb/server/transport_ipc.h b/fs/smb/server/transport_ipc.h +index 5e5b90a0c1879..d9b6737f8cd03 100644 +--- a/fs/smb/server/transport_ipc.h ++++ b/fs/smb/server/transport_ipc.h +@@ -12,6 +12,8 @@ + + struct ksmbd_login_response * + ksmbd_ipc_login_request(const char *account); ++struct ksmbd_login_response_ext * ++ksmbd_ipc_login_request_ext(const char *account); + + struct ksmbd_session; + struct ksmbd_share_config; +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch b/queue-6.6/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch new file mode 100644 index 0000000000..7370d138cd --- /dev/null +++ b/queue-6.6/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch @@ -0,0 +1,54 @@ +From 3056a3e7947918ff08e0643c8564fb35e4bccad5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:55 +0900 +Subject: ksmbd: destroy async_ida in ksmbd_conn_free() + +From: DaeMyung Kang + +[ Upstream commit b32c8db48212a34998c36d0bbc05b29d5c407ef5 ] + +When per-connection async_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from the connection teardown path but no matching +ida_destroy() was added. The connection is therefore freed with the +IDA's backing xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +connection is freed. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/connection.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c +index a5209abb004a4..bbb0be5524dbe 100644 +--- a/fs/smb/server/connection.c ++++ b/fs/smb/server/connection.c +@@ -41,6 +41,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn) + kfree(conn->preauth_info); + kfree(conn->mechToken); + if (atomic_dec_and_test(&conn->refcnt)) { ++ /* ++ * async_ida is embedded in struct ksmbd_conn, so pair ++ * ida_destroy() with the final kfree() rather than with ++ * the unconditional field teardown above. This keeps ++ * the IDA valid for the entire lifetime of the struct, ++ * even while other refcount holders (oplock / vfs ++ * durable handles) still reference the connection. ++ */ ++ ida_destroy(&conn->async_ida); + conn->transport->ops->free_transport(conn->transport); + kfree(conn); + } +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch b/queue-6.6/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch new file mode 100644 index 0000000000..3b861dbd64 --- /dev/null +++ b/queue-6.6/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch @@ -0,0 +1,71 @@ +From 713980525bc04557d7a3bbd741b71b33dd15712a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:54 +0900 +Subject: ksmbd: destroy tree_conn_ida in ksmbd_session_destroy() + +From: DaeMyung Kang + +[ Upstream commit c049ee14eb4343b69b6f7755563f961f5e153423 ] + +When per-session tree_conn_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from ksmbd_session_destroy() but no matching ida_destroy() +was added. The session is therefore freed with the IDA's backing +xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +enclosing session is freed. + +Also move ida_init() to right after the session is allocated so that +it is always paired with the destroy call even on the early error +paths of __session_create() (ksmbd_init_file_table() or +__init_smb2_session() failures), both of which jump to the error +label and invoke ksmbd_session_destroy() on a partially initialised +session. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index e344475a41bd1..d0a13a5cccece 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -168,6 +168,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) + free_channel_list(sess); + kfree(sess->Preauth_HashValue); + ksmbd_release_id(&session_ida, sess->id); ++ ida_destroy(&sess->tree_conn_ida); + kfree(sess); + } + +@@ -438,6 +439,8 @@ static struct ksmbd_session *__session_create(int protocol) + if (!sess) + return NULL; + ++ ida_init(&sess->tree_conn_ida); ++ + if (ksmbd_init_file_table(&sess->file_table)) + goto error; + +@@ -456,8 +459,6 @@ static struct ksmbd_session *__session_create(int protocol) + if (ret) + goto error; + +- ida_init(&sess->tree_conn_ida); +- + down_write(&sessions_table_lock); + hash_add(sessions_table, &sess->hlist, sess->id); + up_write(&sessions_table_lock); +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch b/queue-6.6/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch new file mode 100644 index 0000000000..01e6c1c920 --- /dev/null +++ b/queue-6.6/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch @@ -0,0 +1,64 @@ +From 0adb20b672ac13f8d4a53e2e937165d30ac59876 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 03:45:11 +0900 +Subject: ksmbd: fix durable fd leak on ClientGUID mismatch in durable v2 open + +From: DaeMyung Kang + +[ Upstream commit 804054d19886ac6628883d82410f6ee42a818664 ] + +ksmbd_lookup_fd_cguid() returns a ksmbd_file with its refcount +incremented via ksmbd_fp_get(). parse_durable_handle_context() in +the DURABLE_REQ_V2 case properly releases this reference on every +path inside the ClientGUID-match branch, either by calling +ksmbd_put_durable_fd() or by transferring ownership to dh_info->fp +for a successful reconnect. However, when an entry exists in the +global file table with the same CreateGuid but a different +ClientGUID, the code simply falls through to the new-open path +without dropping the reference obtained from ksmbd_lookup_fd_cguid(). + +Per MS-SMB2 section 3.3.5.9.10 ("Handling the +SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context"), the server +MUST locate an Open whose Open.CreateGuid matches the request's +CreateGuid AND whose Open.ClientGuid matches the ClientGuid of the +connection that received the request. If no such Open is found, the +server MUST continue with the normal open execution phase. A +CreateGuid hit with a ClientGUID mismatch is therefore the +"Open not found" case: proceeding with a new open is correct, but +the reference obtained purely as a side effect of the lookup must +not be leaked. + +Repeated requests that hit this mismatch pin global_ft entries, +prevent __ksmbd_close_fd() from ever running for the corresponding +files, and defeat the durable scavenger, leading to long-lived +resource leaks. + +Release the reference in the mismatch path and clear dh_info->fp so +subsequent logic does not mistake a non-matching lookup result for +a reconnect target. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 6c41a67be725d..d68fe617369e0 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -2827,6 +2827,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work, + dh_info->reconnected = true; + goto out; + } ++ ksmbd_put_durable_fd(dh_info->fp); ++ dh_info->fp = NULL; + } + + if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch b/queue-6.6/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch new file mode 100644 index 0000000000..d746ae1123 --- /dev/null +++ b/queue-6.6/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch @@ -0,0 +1,73 @@ +From 4cfe0842ad66227d810bcb558d301eedbbb5efd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 22:31:12 -0400 +Subject: ksmbd: fix use-after-free from async crypto on Qualcomm crypto engine + +From: Joshua Klinesmith + +[ Upstream commit 3e298897f41c61450c2e7a4f457e8b2485eb35b3 ] + +ksmbd_crypt_message() sets a NULL completion callback on AEAD requests +and does not handle the -EINPROGRESS return code from async hardware +crypto engines like the Qualcomm Crypto Engine (QCE). When QCE returns +-EINPROGRESS, ksmbd treats it as an error and immediately frees the +request while the hardware DMA operation is still in flight. The DMA +completion callback then dereferences freed memory, causing a NULL +pointer crash: + + pc : qce_skcipher_done+0x24/0x174 + lr : vchan_complete+0x230/0x27c + ... + el1h_64_irq+0x68/0x6c + ksmbd_free_work_struct+0x20/0x118 [ksmbd] + ksmbd_exit_file_cache+0x694/0xa4c [ksmbd] + +Use the standard crypto_wait_req() pattern with crypto_req_done() as +the completion callback, matching the approach used by the SMB client +in fs/smb/client/smb2ops.c. This properly handles both synchronous +engines (immediate return) and async engines (-EINPROGRESS followed +by callback notification). + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Link: https://github.com/openwrt/openwrt/issues/21822 +Signed-off-by: Joshua Klinesmith +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/auth.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index 16a57425099de..d28b34e1d047a 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -1106,6 +1106,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base); + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int rc; ++ DECLARE_CRYPTO_WAIT(wait); + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; +@@ -1192,12 +1193,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); +- aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); ++ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | ++ CRYPTO_TFM_REQ_MAY_SLEEP, ++ crypto_req_done, &wait); + +- if (enc) +- rc = crypto_aead_encrypt(req); +- else +- rc = crypto_aead_decrypt(req); ++ rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : ++ crypto_aead_decrypt(req), &wait); + if (rc) + goto free_iv; + +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch b/queue-6.6/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch new file mode 100644 index 0000000000..2c148981e7 --- /dev/null +++ b/queue-6.6/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch @@ -0,0 +1,59 @@ +From 2221c1fa1a033d64e15a4880b48b846ef8aefe18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 00:31:47 +0900 +Subject: ksmbd: scope conn->binding slowpath to bound sessions only + +From: Hyunwoo Kim + +[ Upstream commit b0da97c034b6107d14e537e212d4ce8b22109a58 ] + +When the binding SESSION_SETUP sets conn->binding = true, the flag stays +set after the call so that the global session lookup in +ksmbd_session_lookup_all() can find the session, which was not added to +conn->sessions. Because the flag is connection-wide, the global lookup +path will also resolve any other session by id if asked. + +Tighten the global lookup so that the returned session must have this +connection registered in its channel xarray (sess->ksmbd_chann_list). +The channel entry is installed by the existing binding_session path in +ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes +successfully, so this condition is a strict equivalent of "this +connection has been accepted as a channel of this session". Connections +that have not bound to a given session cannot reach it via the global +table. + +The existing conn->binding gate for entering the slowpath is preserved +so that non-binding connections keep the fast-path-only behavior, and +the session->state check is unchanged. + +Fixes: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel") +Signed-off-by: Hyunwoo Kim +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index d0a13a5cccece..6c7fbd589087e 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -323,8 +323,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, + struct ksmbd_session *sess; + + sess = ksmbd_session_lookup(conn, id); +- if (!sess && conn->binding) ++ if (!sess && conn->binding) { + sess = ksmbd_session_lookup_slowpath(id); ++ if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) { ++ ksmbd_user_session_put(sess); ++ sess = NULL; ++ } ++ } + if (sess && sess->state != SMB2_SESSION_VALID) { + ksmbd_user_session_put(sess); + sess = NULL; +-- +2.53.0 + diff --git a/queue-6.6/ksmbd-use-struct_size-to-improve-smb_direct_rdma_xmi.patch b/queue-6.6/ksmbd-use-struct_size-to-improve-smb_direct_rdma_xmi.patch new file mode 100644 index 0000000000..b60f3f9d1d --- /dev/null +++ b/queue-6.6/ksmbd-use-struct_size-to-improve-smb_direct_rdma_xmi.patch @@ -0,0 +1,39 @@ +From f32e4b738ceb0bd588e872c66f2b36a0f49bc0eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Sep 2024 17:00:30 +0200 +Subject: ksmbd: Use struct_size() to improve smb_direct_rdma_xmit() + +From: Thorsten Blum + +[ Upstream commit 9c383396362a4d1db99ed5240f4708d443361ef3 ] + +Use struct_size() to calculate the number of bytes to allocate for a +new message. + +Signed-off-by: Thorsten Blum +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Stable-dep-of: b32c8db48212 ("ksmbd: destroy async_ida in ksmbd_conn_free()") +Signed-off-by: Sasha Levin +--- + fs/smb/server/transport_rdma.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c +index 3528ec33919d5..10ceade590529 100644 +--- a/fs/smb/server/transport_rdma.c ++++ b/fs/smb/server/transport_rdma.c +@@ -1407,8 +1407,8 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, + /* build rdma_rw_ctx for each descriptor */ + desc_buf = buf; + for (i = 0; i < desc_num; i++) { +- msg = kzalloc(offsetof(struct smb_direct_rdma_rw_msg, sg_list) + +- sizeof(struct scatterlist) * SG_CHUNK_SIZE, GFP_KERNEL); ++ msg = kzalloc(struct_size(msg, sg_list, SG_CHUNK_SIZE), ++ GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto out; +-- +2.53.0 + diff --git a/queue-6.6/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch b/queue-6.6/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch new file mode 100644 index 0000000000..02bbbc2775 --- /dev/null +++ b/queue-6.6/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch @@ -0,0 +1,49 @@ +From 4ff072cc5d7251b4d3bf3fd799a5b9a1877d14fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:56 -0300 +Subject: ktest: Avoid undef warning when WARNINGS_FILE is unset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit 057854f8a595160656fe77ed7bf0d2403724b915 ] + +check_buildlog() probes $warnings_file with -f even when WARNINGS_FILE is +not configured. Perl warns about the uninitialized value and adds noise to +the test log, which can hide the output we actually care about. + +Check that WARNINGS_FILE is defined before testing whether the file exists. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-1-565d412f4925@suse.com +Fixes: 4283b169abfb ("ktest: Add make_warnings_file and process full warnings") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index e93ac83270dad..4eca66310d9b4 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -2472,7 +2472,7 @@ sub check_buildlog { + my $save_no_reboot = $no_reboot; + $no_reboot = 1; + +- if (-f $warnings_file) { ++ if (defined($warnings_file) && -f $warnings_file) { + open(IN, $warnings_file) or + dodie "Error opening $warnings_file"; + +-- +2.53.0 + diff --git a/queue-6.6/ktest-honor-empty-per-test-option-overrides.patch b/queue-6.6/ktest-honor-empty-per-test-option-overrides.patch new file mode 100644 index 0000000000..8a2b34447b --- /dev/null +++ b/queue-6.6/ktest-honor-empty-per-test-option-overrides.patch @@ -0,0 +1,79 @@ +From c3f948deade4520933bf80cef06569f58e5a7c30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:59 -0300 +Subject: ktest: Honor empty per-test option overrides +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit a2de57a3c8192dcd67cccaff6c341b93748d799b ] + +A per-test override can clear an inherited default option by assigning an +empty value, but __set_test_option() still used option_defined() to decide +whether a per-test key existed. That turned an empty per-test assignment +back into "fall back to the default", so tests still could not clear +inherited settings. + +For example: + + DEFAULTS + (...) + LOG_FILE = /tmp/ktest-empty-override.log + CLEAR_LOG = 1 + ADD_CONFIG = /tmp/.config + + TEST_START + TEST_TYPE = build + BUILD_TYPE = nobuild + ADD_CONFIG = + +This would run the test with ADD_CONFIG[1] = /tmp/.config + +Fix by checking whether the per-test key exists before falling back. If it +does exist but is empty, treat it as unset for that test and stop the +fallback chain there. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-4-565d412f4925@suse.com +Fixes: 22c37a9ac49d ("ktest: Allow tests to undefine default options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 4eca66310d9b4..13686e7629c4d 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -4113,7 +4113,8 @@ sub __set_test_option { + + my $option = "$name\[$i\]"; + +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + +@@ -4121,7 +4122,8 @@ sub __set_test_option { + if ($i >= $test && + $i < $test + $repeat_tests{$test}) { + $option = "$name\[$test\]"; +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + } +-- +2.53.0 + diff --git a/queue-6.6/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch b/queue-6.6/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch new file mode 100644 index 0000000000..a1c626ceb4 --- /dev/null +++ b/queue-6.6/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch @@ -0,0 +1,105 @@ +From 4656be66a7f4c5720a4ebf5d8f3064777cf1d498 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:08:03 -0300 +Subject: ktest: Run POST_KTEST hooks on failure and cancellation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit bc6e165a452da909cef0efbc286e6695624db372 ] + +PRE_KTEST can be useful for setting up the environment and POST_KTEST to +tear it down, however POST_KTEST only runs on the normal end-of-run path. +It is skipped when ktest exits through dodie() or cancel_test(). Final +cleanup hooks are skipped. + +Factor the final hook execution into run_post_ktest(), call it from the +normal exit path and from the early exit paths, and guard it so the hook +runs at most once. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-8-565d412f4925@suse.com +Fixes: 921ed4c7208e ("ktest: Add PRE/POST_KTEST and TEST options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 13686e7629c4d..d78d5f3b0a55e 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -98,6 +98,7 @@ my $test_type; + my $build_type; + my $build_options; + my $final_post_ktest; ++my $post_ktest_done = 0; + my $pre_ktest; + my $post_ktest; + my $pre_test; +@@ -1537,6 +1538,24 @@ sub get_test_name() { + return $name; + } + ++sub run_post_ktest { ++ my $cmd; ++ ++ return if ($post_ktest_done); ++ ++ if (defined($final_post_ktest)) { ++ $cmd = $final_post_ktest; ++ } elsif (defined($post_ktest)) { ++ $cmd = $post_ktest; ++ } else { ++ return; ++ } ++ ++ my $cp_post_ktest = eval_kernel_version($cmd); ++ run_command $cp_post_ktest; ++ $post_ktest_done = 1; ++} ++ + sub dodie { + # avoid recursion + return if ($in_die); +@@ -1596,6 +1615,7 @@ sub dodie { + if (defined($post_test)) { + run_command $post_test; + } ++ run_post_ktest; + + die @_, "\n"; + } +@@ -4230,6 +4250,7 @@ sub cancel_test { + send_email("KTEST: Your [$name] test was cancelled", + "Your test started at $script_start_time was cancelled: sig int"); + } ++ run_post_ktest; + die "\nCaught Sig Int, test interrupted: $!\n" + } + +@@ -4540,11 +4561,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { + success $i; + } + +-if (defined($final_post_ktest)) { +- +- my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; +- run_command $cp_final_post_ktest; +-} ++run_post_ktest; + + if ($opt{"POWEROFF_ON_SUCCESS"}) { + halt; +-- +2.53.0 + diff --git a/queue-6.6/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch b/queue-6.6/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch new file mode 100644 index 0000000000..884585aa98 --- /dev/null +++ b/queue-6.6/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch @@ -0,0 +1,36 @@ +From 009f466761ac3f927b9fafd3e8f5f484446c19b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:30:48 +0800 +Subject: leds: lgm-sso: Remove duplicate assignments for priv->mmap + +From: Chen Ni + +[ Upstream commit 7186d0330c3f3e86de577687a82f4ebd96dcb5ac ] + +Remove duplicate assignment of priv->mmap in intel_sso_led_probe(). + +Fixes: fba8a6f2263b ("leds: lgm-sso: Fix clock handling") +Signed-off-by: Chen Ni +Link: https://patch.msgid.link/20260226033048.3715915-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 35c61311e7fd8..e104010345b18 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -806,8 +806,6 @@ static int intel_sso_led_probe(struct platform_device *pdev) + + priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk); + +- priv->mmap = syscon_node_to_regmap(dev->of_node); +- + priv->mmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(priv->mmap)) { + dev_err(dev, "Failed to map iomem!\n"); +-- +2.53.0 + diff --git a/queue-6.6/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch b/queue-6.6/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch new file mode 100644 index 0000000000..3beebae89d --- /dev/null +++ b/queue-6.6/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch @@ -0,0 +1,51 @@ +From 04249da14db9ca2177820c8c1e0b21f50355070f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 17:21:43 +0200 +Subject: lib/hexdump: print_hex_dump_bytes() calls print_hex_dump_debug() + +From: Geert Uytterhoeven + +[ Upstream commit 36776b7f8a8955b4e75b5d490a75fee0c7a2a7ef ] + +print_hex_dump_bytes() claims to be a simple wrapper around +print_hex_dump(), but it actally calls print_hex_dump_debug(), which +means no output is printed if (dynamic) DEBUG is disabled. + +Update the documentation to match the implementation. + +Fixes: 091cb0994edd20d6 ("lib/hexdump: make print_hex_dump_bytes() a nop on !DEBUG builds") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Petr Mladek +Link: https://patch.msgid.link/3d5c3069fd9102ecaf81d044b750cd613eb72a08.1774970392.git.geert+renesas@glider.be +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + include/linux/printk.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 478203bb2369c..794476418ccef 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -759,7 +759,8 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, + #endif + + /** +- * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params ++ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default ++ * params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none +@@ -767,7 +768,7 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, + * @buf: data blob to dump + * @len: number of bytes in the @buf + * +- * Calls print_hex_dump(), with log level of KERN_DEBUG, ++ * Calls print_hex_dump_debug(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ + #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ +-- +2.53.0 + diff --git a/queue-6.6/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch b/queue-6.6/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch new file mode 100644 index 0000000000..8ff5a0d51a --- /dev/null +++ b/queue-6.6/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch @@ -0,0 +1,75 @@ +From 1e3c0a7fce2a6c1f97744a61c88bc10c98632add Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:15:07 -0700 +Subject: locking: Fix rwlock support in + +From: Bart Van Assche + +[ Upstream commit 756a0e011cfca0b45a48464aa25b05d9a9c2fb0b ] + +Architecture support for rwlocks must be available whether or not +CONFIG_DEBUG_SPINLOCK has been defined. Move the definitions of the +arch_{read,write}_{lock,trylock,unlock}() macros such that these become +visbile if CONFIG_DEBUG_SPINLOCK=n. + +This patch prepares for converting do_raw_{read,write}_trylock() into +inline functions. Without this patch that conversion triggers a build +failure for UP architectures, e.g. arm-ep93xx. I used the following +kernel configuration to build the kernel for that architecture: + + CONFIG_ARCH_MULTIPLATFORM=y + CONFIG_ARCH_MULTI_V7=n + CONFIG_ATAGS=y + CONFIG_MMU=y + CONFIG_ARCH_MULTI_V4T=y + CONFIG_CPU_LITTLE_ENDIAN=y + CONFIG_ARCH_EP93XX=y + +Fixes: fb1c8f93d869 ("[PATCH] spinlock consolidation") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260313171510.230998-2-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/spinlock_up.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h +index c87204247592f..a132fc562297a 100644 +--- a/include/linux/spinlock_up.h ++++ b/include/linux/spinlock_up.h +@@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + lock->slock = 1; + } + +-/* +- * Read-write spinlocks. No debug version. +- */ +-#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) +- + #else /* DEBUG_SPINLOCK */ + #define arch_spin_is_locked(lock) ((void)(lock), 0) + /* for sched/core.c and kernel_lock.c: */ +@@ -68,4 +58,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + + #define arch_spin_is_contended(lock) (((void)(lock), 0)) + ++/* ++ * Read-write spinlocks. No debug version. ++ */ ++#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) ++ + #endif /* __LINUX_SPINLOCK_UP_H */ +-- +2.53.0 + diff --git a/queue-6.6/loop-fix-partition-scan-race-between-udev-and-loop_r.patch b/queue-6.6/loop-fix-partition-scan-race-between-udev-and-loop_r.patch new file mode 100644 index 0000000000..774db8a64f --- /dev/null +++ b/queue-6.6/loop-fix-partition-scan-race-between-udev-and-loop_r.patch @@ -0,0 +1,87 @@ +From a266886ba452a5ca973f0ce6a6570f9dc829d7f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:51:28 +0000 +Subject: loop: fix partition scan race between udev and + loop_reread_partitions() + +From: Daan De Meyer + +[ Upstream commit 267ec4d7223a783f029a980f41b93c39b17996da ] + +When LOOP_CONFIGURE is called with LO_FLAGS_PARTSCAN, the following +sequence occurs: + + 1. disk_force_media_change() sets GD_NEED_PART_SCAN + 2. Uevent suppression is lifted and a KOBJ_CHANGE uevent is sent + 3. loop_global_unlock() releases the lock + 4. loop_reread_partitions() calls bdev_disk_changed() to scan + +There is a race between steps 2 and 4: when udev receives the uevent +and opens the device before loop_reread_partitions() runs, +blkdev_get_whole() in bdev.c sees GD_NEED_PART_SCAN set and calls +bdev_disk_changed() for a first scan. Then loop_reread_partitions() +does a second scan. The open_mutex serializes these two scans, but +does not prevent both from running. + +The second scan in bdev_disk_changed() drops all partition devices +from the first scan (via blk_drop_partitions()) before re-adding +them, causing partition block devices to briefly disappear. This +breaks any systemd unit with BindsTo= on the partition device: systemd +observes the device going dead, fails the dependent units, and does +not retry them when the device reappears. + +Fix this by removing the GD_NEED_PART_SCAN set from +disk_force_media_change() entirely. None of the current callers need +the lazy on-open partition scan triggered by this flag: + + - floppy: sets GENHD_FL_NO_PART, so disk_has_partscan() is always + false and GD_NEED_PART_SCAN has no effect. + - loop (loop_configure, loop_change_fd): when LO_FLAGS_PARTSCAN is + set, loop_reread_partitions() performs an explicit scan. When not + set, GD_SUPPRESS_PART_SCAN prevents the lazy scan path. + - loop (__loop_clr_fd): calls bdev_disk_changed() explicitly if + LO_FLAGS_PARTSCAN is set. + - nbd (nbd_clear_sock_ioctl): capacity is set to zero immediately + after; nbd manages GD_NEED_PART_SCAN explicitly elsewhere. + +With GD_NEED_PART_SCAN no longer set by disk_force_media_change(), +udev opening the loop device after the uevent no longer triggers a +redundant scan in blkdev_get_whole(), and only the single explicit +scan from loop_reread_partitions() runs. + +A regression test for this bug has been submitted to blktests: +https://github.com/linux-blktests/blktests/pull/240. + +Fixes: 9f65c489b68d ("loop: raise media_change event") +Signed-off-by: Daan De Meyer +Acked-by: Christian Brauner +Link: https://patch.msgid.link/20260331105130.1077599-1-daan@amutable.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/disk-events.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/block/disk-events.c b/block/disk-events.c +index 13c3372c465a3..6987e4dd8d417 100644 +--- a/block/disk-events.c ++++ b/block/disk-events.c +@@ -294,13 +294,14 @@ EXPORT_SYMBOL(disk_check_media_change); + * Should be called when the media changes for @disk. Generates a uevent + * and attempts to free all dentries and inodes and invalidates all block + * device page cache entries in that case. ++ * ++ * Callers that need a partition re-scan should arrange for one explicitly. + */ + void disk_force_media_change(struct gendisk *disk) + { + disk_event_uevent(disk, DISK_EVENT_MEDIA_CHANGE); + inc_diskseq(disk); + bdev_mark_dead(disk->part0, true); +- set_bit(GD_NEED_PART_SCAN, &disk->state); + } + EXPORT_SYMBOL_GPL(disk_force_media_change); + +-- +2.53.0 + diff --git a/queue-6.6/macvlan-annotate-data-races-around-port-bc_queue_len.patch b/queue-6.6/macvlan-annotate-data-races-around-port-bc_queue_len.patch new file mode 100644 index 0000000000..bf2020218c --- /dev/null +++ b/queue-6.6/macvlan-annotate-data-races-around-port-bc_queue_len.patch @@ -0,0 +1,67 @@ +From e0f8cfb4167da6d612d7f93db4f9a43984c70f00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:38:08 +0000 +Subject: macvlan: annotate data-races around port->bc_queue_len_used + +From: Eric Dumazet + +[ Upstream commit 1ef5789d9906df3771c99b7f413caaf2bf473ca5 ] + +port->bc_queue_len_used is read and written locklessly, +add READ_ONCE()/WRITE_ONCE() annotations. + +While WRITE_ONCE() in macvlan_fill_info() is not yet needed, +it is a prereq for future RTNL avoidance. + +Fixes: d4bff72c8401 ("macvlan: Support for high multicast packet rate") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401103809.3038139-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index 4e28fcbf13c74..1035a95beee6f 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -351,6 +351,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + const struct macvlan_dev *src, + struct sk_buff *skb) + { ++ u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used); + struct sk_buff *nskb; + int err = -ENOMEM; + +@@ -361,7 +362,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + MACVLAN_SKB_CB(nskb)->src = src; + + spin_lock(&port->bc_queue.lock); +- if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) { ++ if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) { + if (src) + dev_hold(src->dev); + __skb_queue_tail(&port->bc_queue, nskb); +@@ -1732,7 +1733,8 @@ static int macvlan_fill_info(struct sk_buff *skb, + } + if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) + goto nla_put_failure; +- if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) ++ if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, ++ READ_ONCE(port->bc_queue_len_used))) + goto nla_put_failure; + if (port->bc_cutoff != 1 && + nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff)) +@@ -1792,7 +1794,7 @@ static void update_port_bc_queue_len(struct macvlan_port *port) + if (vlan->bc_queue_len_req > max_bc_queue_len_req) + max_bc_queue_len_req = vlan->bc_queue_len_req; + } +- port->bc_queue_len_used = max_bc_queue_len_req; ++ WRITE_ONCE(port->bc_queue_len_used, max_bc_queue_len_req); + } + + static int macvlan_device_event(struct notifier_block *unused, +-- +2.53.0 + diff --git a/queue-6.6/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch b/queue-6.6/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch new file mode 100644 index 0000000000..64e876d4b2 --- /dev/null +++ b/queue-6.6/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch @@ -0,0 +1,56 @@ +From 2d68b9248d038512d8b0b5ad273fd8755dafc072 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:53:49 +0800 +Subject: macvlan: fix macvlan_get_size() not reserving space for + IFLA_MACVLAN_BC_CUTOFF + +From: Dudu Lu + +[ Upstream commit fa92a77b0ed4d5f11a71665a232ac5a54a4b055d ] + +macvlan_get_size() does not account for IFLA_MACVLAN_BC_CUTOFF, but +macvlan_fill_info() conditionally includes it when port->bc_cutoff != 1. +This causes nla_put_s32() to fail with -EMSGSIZE when the netlink skb +runs out of space, triggering a WARN_ON in rtnetlink and preventing the +interface from being dumped. + +The bug can be reproduced with: + + ip link add macvlan0 link eth0 type macvlan mode bridge + ip link set macvlan0 type macvlan bc_cutoff 0 + ip -d link show macvlan0 # fails with -EMSGSIZE + +The bc_cutoff feature was added in commit 954d1fa1ac93 ("macvlan: Add +netlink attribute for broadcast cutoff"), which added the nla_put_s32() +call in macvlan_fill_info() but missed adding the corresponding +nla_total_size(4) in macvlan_get_size(). A follow-up commit +55cef78c244d ("macvlan: add forgotten nla_policy for +IFLA_MACVLAN_BC_CUTOFF") fixed the missing nla_policy entry but still +did not fix the size calculation. + +Fixes: 954d1fa1ac93 ("macvlan: Add netlink attribute for broadcast cutoff") +Signed-off-by: Dudu Lu +Reviewed-by: Vadim Fedorenko +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260413085349.73977-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index 1035a95beee6f..399c8deb35103 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -1687,6 +1687,7 @@ static size_t macvlan_get_size(const struct net_device *dev) + + macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN_USED */ ++ + nla_total_size(4) /* IFLA_MACVLAN_BC_CUTOFF */ + ); + } + +-- +2.53.0 + diff --git a/queue-6.6/mailbox-add-sanity-check-for-channel-array.patch b/queue-6.6/mailbox-add-sanity-check-for-channel-array.patch new file mode 100644 index 0000000000..02ffa4617e --- /dev/null +++ b/queue-6.6/mailbox-add-sanity-check-for-channel-array.patch @@ -0,0 +1,40 @@ +From 000d8a26a51ac1731dbb5faa345df59a5d75bb62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:42:38 +0200 +Subject: mailbox: add sanity check for channel array + +From: Wolfram Sang + +[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ] + +Fail gracefully if there is no channel array attached to the mailbox +controller. Otherwise the later dereference will cause an OOPS which +might not be seen because mailbox controllers might instantiate very +early. Remove the comment explaining the obvious while here. + +Fixes: 2b6d83e2b8b7 ("mailbox: Introduce framework for mailbox") +Signed-off-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index b4d52b814055b..39269359e3a64 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -520,8 +520,7 @@ int mbox_controller_register(struct mbox_controller *mbox) + { + int i, txdone; + +- /* Sanity check */ +- if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) ++ if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) + return -EINVAL; + + if (mbox->txdone_irq) +-- +2.53.0 + diff --git a/queue-6.6/mailbox-mailbox-test-don-t-free-the-reused-channel.patch b/queue-6.6/mailbox-mailbox-test-don-t-free-the-reused-channel.patch new file mode 100644 index 0000000000..6282cdbcd6 --- /dev/null +++ b/queue-6.6/mailbox-mailbox-test-don-t-free-the-reused-channel.patch @@ -0,0 +1,46 @@ +From 03de43bf1041d4a1fc1b7b1e41f8eee218d2eea8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:34 +0200 +Subject: mailbox: mailbox-test: don't free the reused channel + +From: Wolfram Sang + +[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ] + +The RX channel can be aliased to the TX channel if it has a different +MMIO. This special case needs to be handled when freeing the channels +otherwise a double-free occurs. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 6d431a8b275c7..c06d128c44764 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -422,7 +422,7 @@ static int mbox_test_probe(struct platform_device *pdev) + err_free_chans: + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + return ret; + } +@@ -435,7 +435,7 @@ static int mbox_test_remove(struct platform_device *pdev) + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/mailbox-mailbox-test-free-channels-on-probe-error.patch b/queue-6.6/mailbox-mailbox-test-free-channels-on-probe-error.patch new file mode 100644 index 0000000000..10b581604e --- /dev/null +++ b/queue-6.6/mailbox-mailbox-test-free-channels-on-probe-error.patch @@ -0,0 +1,60 @@ +From a9f47ed2dddd0185ecd6e35b64ac78056e146781 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 14:53:00 +0200 +Subject: mailbox: mailbox-test: free channels on probe error + +From: Wolfram Sang + +[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ] + +On probe error, free the previously obtained channels. This not only +prevents a leak, but also UAF scenarios because the client structure +will be removed nonetheless because it was allocated with devm. + +Link: https://sashiko.dev/#/patchset/20260327151217.5327-2-wsa%2Brenesas%40sang-engineering.com +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 6bdee87f30836..6d431a8b275c7 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -404,18 +404,27 @@ static int mbox_test_probe(struct platform_device *pdev) + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +- if (!tdev->rx_buffer) +- return -ENOMEM; ++ if (!tdev->rx_buffer) { ++ ret = -ENOMEM; ++ goto err_free_chans; ++ } + } + + ret = mbox_test_add_debugfs(pdev, tdev); + if (ret) +- return ret; ++ goto err_free_chans; + + init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; ++ ++err_free_chans: ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ if (tdev->rx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ return ret; + } + + static int mbox_test_remove(struct platform_device *pdev) +-- +2.53.0 + diff --git a/queue-6.6/mailbox-mailbox-test-initialize-struct-earlier.patch b/queue-6.6/mailbox-mailbox-test-initialize-struct-earlier.patch new file mode 100644 index 0000000000..514d2a82b6 --- /dev/null +++ b/queue-6.6/mailbox-mailbox-test-initialize-struct-earlier.patch @@ -0,0 +1,64 @@ +From 5f8cbdbc38f155a517c310d9e3f30bf6cfb56f99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:35 +0200 +Subject: mailbox: mailbox-test: initialize struct earlier + +From: Wolfram Sang + +[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ] + +The waitqueue must be initialized before the debugfs files are created +because from that time, requests from userspace can already be made. +Similarily, drvdata and spinlock needs to be initialized before we +request the channel, otherwise dangling irqs might run into problems +like a NULL pointer exception. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index c06d128c44764..2c98c300ba33b 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -366,6 +366,12 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev) + return -ENOMEM; + ++ tdev->dev = &pdev->dev; ++ spin_lock_init(&tdev->lock); ++ mutex_init(&tdev->mutex); ++ init_waitqueue_head(&tdev->waitq); ++ platform_set_drvdata(pdev, tdev); ++ + /* It's okay for MMIO to be NULL */ + tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { +@@ -395,12 +401,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) + tdev->rx_channel = tdev->tx_channel; + +- tdev->dev = &pdev->dev; +- platform_set_drvdata(pdev, tdev); +- +- spin_lock_init(&tdev->lock); +- mutex_init(&tdev->mutex); +- + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +@@ -414,7 +414,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (ret) + goto err_free_chans; + +- init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch b/queue-6.6/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch new file mode 100644 index 0000000000..0712ad939c --- /dev/null +++ b/queue-6.6/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch @@ -0,0 +1,73 @@ +From c3376cad934f9549147f1650cdb0b9bc4a3f509b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:36 +0200 +Subject: mailbox: mailbox-test: make data_ready a per-instance variable + +From: Wolfram Sang + +[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ] + +While not the default case, multiple tests can be run simultaneously. +Then, data_ready being a global variable will be overwritten and the +per-instance lock will not help. Turn the global variable into a +per-instance one to avoid this problem. + +Fixes: e339c80af95e ("mailbox: mailbox-test: don't rely on rx_buffer content to signal data ready") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 2c98c300ba33b..f2ed7f884a575 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -28,8 +28,6 @@ + #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ + (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) + +-static bool mbox_data_ready; +- + struct mbox_test_device { + struct device *dev; + void __iomem *tx_mmio; +@@ -42,6 +40,7 @@ struct mbox_test_device { + spinlock_t lock; + struct mutex mutex; + wait_queue_head_t waitq; ++ bool data_ready; + struct fasync_struct *async_queue; + struct dentry *root_debugfs_dir; + }; +@@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); +- data_ready = mbox_data_ready; ++ data_ready = tdev->data_ready; + spin_unlock_irqrestore(&tdev->lock, flags); + + return data_ready; +@@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, + *(touser + l) = '\0'; + + memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); +- mbox_data_ready = false; ++ tdev->data_ready = false; + + spin_unlock_irqrestore(&tdev->lock, flags); + +@@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) + message, MBOX_MAX_MSG_LEN); + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); + } +- mbox_data_ready = true; ++ tdev->data_ready = true; + spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); +-- +2.53.0 + diff --git a/queue-6.6/memory-tegra124-emc-fix-dll_change-check.patch b/queue-6.6/memory-tegra124-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..3029ce3351 --- /dev/null +++ b/queue-6.6/memory-tegra124-emc-fix-dll_change-check.patch @@ -0,0 +1,38 @@ +From 429b8933835d706e163901083a02f9cc598cc37c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:42 +0900 +Subject: memory: tegra124-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 9597ab9a8296ab337e6820f8a717ff621078b632 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: 73a7f0a90641 ("memory: tegra: Add EMC (external memory controller) driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-1-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra124-emc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c +index 00ed2b6a0d1b2..ca2714b0a521a 100644 +--- a/drivers/memory/tegra/tegra124-emc.c ++++ b/drivers/memory/tegra/tegra124-emc.c +@@ -608,7 +608,7 @@ static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, + + if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; +-- +2.53.0 + diff --git a/queue-6.6/memory-tegra30-emc-fix-dll_change-check.patch b/queue-6.6/memory-tegra30-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..74ae796764 --- /dev/null +++ b/queue-6.6/memory-tegra30-emc-fix-dll_change-check.patch @@ -0,0 +1,47 @@ +From 4f2885d0cd8dd3d631a19e89111d5b50f6222fee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:43 +0900 +Subject: memory: tegra30-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 0a93f2355cf4922ad2399dbef5ea1049fef116d4 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: e34212c75a68 ("memory: tegra: Introduce Tegra30 EMC driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-2-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra30-emc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c +index 9eae25c57ec6e..b5cf2df6b1933 100644 +--- a/drivers/memory/tegra/tegra30-emc.c ++++ b/drivers/memory/tegra/tegra30-emc.c +@@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) + emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG); + emc_dbg = readl_relaxed(emc->regs + EMC_DBG); + +- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1)) ++ if (emc->dll_on == !(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; + +- emc->dll_on = !!(timing->emc_mode_1 & 0x1); ++ emc->dll_on = !(timing->emc_mode_1 & 0x1); + + if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL)) + emc->zcal_long = true; +-- +2.53.0 + diff --git a/queue-6.6/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch b/queue-6.6/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch new file mode 100644 index 0000000000..b9ebb36950 --- /dev/null +++ b/queue-6.6/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch @@ -0,0 +1,37 @@ +From 4f1c7c69d9ec8b5001ab42be7fac47751079680b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:56:20 +0530 +Subject: mfd: mc13xxx-core: Fix memory leak in mc13xxx_add_subdevice_pdata() + +From: Abdun Nihaal + +[ Upstream commit a5a65a7fb2f7796bbe492cd6be59c92cb64377d1 ] + +The memory allocated for cell.name using kmemdup() is not freed when +mfd_add_devices() fails. Fix that by using devm_kmemdup(). + +Fixes: 8e00593557c3 ("mfd: Add mc13892 support to mc13xxx") +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20260120102622.66921-1-nihaal@cse.iitm.ac.in +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mc13xxx-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c +index 1000572761a84..ddc90cbb7be52 100644 +--- a/drivers/mfd/mc13xxx-core.c ++++ b/drivers/mfd/mc13xxx-core.c +@@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return -E2BIG; + +- cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); ++ cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL); + if (!cell.name) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-6.6/module-fix-freeing-of-charp-module-parameters-when-c.patch b/queue-6.6/module-fix-freeing-of-charp-module-parameters-when-c.patch new file mode 100644 index 0000000000..431d19f4be --- /dev/null +++ b/queue-6.6/module-fix-freeing-of-charp-module-parameters-when-c.patch @@ -0,0 +1,122 @@ +From 6ea12e39e07869969550d0ff8e0bbf08422eb7b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:48:02 +0100 +Subject: module: Fix freeing of charp module parameters when CONFIG_SYSFS=n + +From: Petr Pavlu + +[ Upstream commit deffe1edba626d474fef38007c03646ca5876a0e ] + +When setting a charp module parameter, the param_set_charp() function +allocates memory to store a copy of the input value. Later, when the module +is potentially unloaded, the destroy_params() function is called to free +this allocated memory. + +However, destroy_params() is available only when CONFIG_SYSFS=y, otherwise +only a dummy variant is present. In the unlikely case that the kernel is +configured with CONFIG_MODULES=y and CONFIG_SYSFS=n, this results in +a memory leak of charp values when a module is unloaded. + +Fix this issue by making destroy_params() always available when +CONFIG_MODULES=y. Rename the function to module_destroy_params() to clarify +that it is intended for use by the module loader. + +Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs") +Signed-off-by: Petr Pavlu +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + include/linux/moduleparam.h | 11 +++-------- + kernel/module/main.c | 4 ++-- + kernel/params.c | 27 ++++++++++++++++++--------- + 3 files changed, 23 insertions(+), 19 deletions(-) + +diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h +index 061e19c94a6bc..f73ca4d62683b 100644 +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -392,14 +392,9 @@ extern char *parse_args(const char *name, + const char *doing, void *arg)); + + /* Called by module remove. */ +-#ifdef CONFIG_SYSFS +-extern void destroy_params(const struct kernel_param *params, unsigned num); +-#else +-static inline void destroy_params(const struct kernel_param *params, +- unsigned num) +-{ +-} +-#endif /* !CONFIG_SYSFS */ ++#ifdef CONFIG_MODULES ++void module_destroy_params(const struct kernel_param *params, unsigned int num); ++#endif + + /* All the helper functions */ + /* The macros to do compile-time type checking stolen from Jakub +diff --git a/kernel/module/main.c b/kernel/module/main.c +index 76d90c20de674..ac528fbb62824 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -1261,7 +1261,7 @@ static void free_module(struct module *mod) + module_unload_free(mod); + + /* Free any allocated parameters. */ +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + + if (is_livepatch_module(mod)) + free_module_elf(mod); +@@ -2998,7 +2998,7 @@ static int load_module(struct load_info *info, const char __user *uargs, + mod_sysfs_teardown(mod); + coming_cleanup: + mod->state = MODULE_STATE_GOING; +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_GOING, mod); + klp_module_going(mod); +diff --git a/kernel/params.c b/kernel/params.c +index 2cfa12404ed0b..9d09ea99363fc 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -744,15 +744,6 @@ void module_param_sysfs_remove(struct module *mod) + } + #endif + +-void destroy_params(const struct kernel_param *params, unsigned num) +-{ +- unsigned int i; +- +- for (i = 0; i < num; i++) +- if (params[i].ops->free) +- params[i].ops->free(params[i].arg); +-} +- + struct module_kobject * __init_or_module + lookup_or_create_module_kobject(const char *name) + { +@@ -987,3 +978,21 @@ static int __init param_sysfs_builtin_init(void) + late_initcall(param_sysfs_builtin_init); + + #endif /* CONFIG_SYSFS */ ++ ++#ifdef CONFIG_MODULES ++ ++/* ++ * module_destroy_params - free all parameters for one module ++ * @params: module parameters (array) ++ * @num: number of module parameters ++ */ ++void module_destroy_params(const struct kernel_param *params, unsigned int num) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < num; i++) ++ if (params[i].ops->free) ++ params[i].ops->free(params[i].arg); ++} ++ ++#endif /* CONFIG_MODULES */ +-- +2.53.0 + diff --git a/queue-6.6/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch b/queue-6.6/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch new file mode 100644 index 0000000000..5ade57b46b --- /dev/null +++ b/queue-6.6/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch @@ -0,0 +1,59 @@ +From 77a0f216a78731f03e05aa57387cb8239cb24fb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:57 +0200 +Subject: mtd: parsers: ofpart: call of_node_get() for dedicated subpartitions + +From: Cosmin Tanislav + +[ Upstream commit e882626c1747653f1f01ea9d12e278e613b11d0f ] + +In order to parse sub-partitions, add_mtd_partitions() calls +parse_mtd_partitions() for all previously found partitions. + +Each partition will end up being passed to parse_fixed_partitions(), and +its of_node will be treated as the ofpart_node. + +Commit 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in +parse_fixed_partitions()") added of_node_put() calls for ofpart_node on +all exit paths. + +In the case where the partition passed to parse_fixed_partitions() has a +parent, it is treated as a dedicated partitions node, and of_node_put() +is wrongly called for it, even if of_node_get() was not called +explicitly. + +On repeated bind / unbinds of the MTD, the extra of_node_put() ends up +decrementing the refcount down to 0, which should never happen, +resulting in the following error: + +OF: ERROR: of_node_release() detected bad of_node_put() on +/soc/spi@80007000/flash@0/partitions/partition@0 + +Call of_node_get() to balance the call to of_node_put() done for +dedicated partitions nodes. + +Fixes: 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in parse_fixed_partitions()") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 110994b1e02f5..c18fa1b3e3276 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -71,7 +71,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + dedicated = false; + } + } else { /* Partition */ +- ofpart_node = mtd_node; ++ ofpart_node = of_node_get(mtd_node); + } + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); +-- +2.53.0 + diff --git a/queue-6.6/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch b/queue-6.6/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch new file mode 100644 index 0000000000..1d0693e086 --- /dev/null +++ b/queue-6.6/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch @@ -0,0 +1,48 @@ +From 5068b01e3ea3884c9221dc31dc744888db9795ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:56 +0200 +Subject: mtd: parsers: ofpart: call of_node_put() only in ofpart_fail path + +From: Cosmin Tanislav + +[ Upstream commit 0c87dea1aab86116211cb37387c404c9e9231c39 ] + +ofpart_none can only be reached after the for_each_child_of_node() loop +finishes. for_each_child_of_node() correctly calls of_node_put() for all +device nodes it iterates over as long as we don't break or jump out of +the loop. + +Calling of_node_put() inside the ofpart_none path will wrongly decrement +the ref count of the last node in the for_each_child_of_node() loop. + +Move the call to of_node_put() under the ofpart_fail label to fix this. + +Fixes: ebd5a74db74e ("mtd: ofpart: Check availability of reg property instead of name property") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 3cf75b56d5a2e..110994b1e02f5 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -191,11 +191,11 @@ static int parse_fixed_partitions(struct mtd_info *master, + ofpart_fail: + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", + master->name, pp, mtd_node); ++ of_node_put(pp); + ret = -EINVAL; + ofpart_none: + if (dedicated) + of_node_put(ofpart_node); +- of_node_put(pp); + kfree(parts); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.6/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch b/queue-6.6/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch new file mode 100644 index 0000000000..02c46b7fbb --- /dev/null +++ b/queue-6.6/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch @@ -0,0 +1,41 @@ +From 02f66b7ea63b5bade5d464148c5ffed5f3a91580 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:43:36 +0800 +Subject: mtd: physmap_of_gemini: Fix disabled pinctrl state check + +From: Chen Ni + +[ Upstream commit b7c0982184b0661f5b1b805f3a56f1bd3757b63e ] + +The condition for checking the disabled pinctrl state incorrectly checks +gf->enabled_state instead of gf->disabled_state. This causes misleading +error messages and could lead to incorrect behavior when only one of the +pinctrl states is defined. + +Fix the condition to properly check gf->disabled_state. + +Fixes: 9d3b5086f6d4 ("mtd: physmap_of_gemini: Handle pin control") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/maps/physmap-gemini.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c +index 9d3b4bf84a1ad..1c34b4ef77ea3 100644 +--- a/drivers/mtd/maps/physmap-gemini.c ++++ b/drivers/mtd/maps/physmap-gemini.c +@@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev, + dev_err(dev, "no enabled pin control state\n"); + + gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled"); +- if (IS_ERR(gf->enabled_state)) { ++ if (IS_ERR(gf->disabled_state)) { + dev_err(dev, "no disabled pin control state\n"); + } else { + ret = pinctrl_select_state(gf->p, gf->disabled_state); +-- +2.53.0 + diff --git a/queue-6.6/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch b/queue-6.6/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch new file mode 100644 index 0000000000..6a58ad8c29 --- /dev/null +++ b/queue-6.6/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch @@ -0,0 +1,66 @@ +From 59fee08fc89df9ee46c68f1d11f2bf6435c74277 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:24:30 +0100 +Subject: mtd: rawnand: sunxi: fix sunxi_nfc_hw_ecc_read_extra_oob + +From: Richard Genoud + +[ Upstream commit 848c13996c55fe4ea6bf5acc3ce6c8c5c944b5f6 ] + +When dumping the OOB, the bytes at the end where actually copied from +the beginning of the OOB instead of current_offset. + +That leads to something like: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +instead of: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +(example with BCH16, user data [8,0], no scrambling) + +*cur_off (offset from the beginning of the page) was compared to offset +(offset from the beginning of the OOB), and then, the +nand_change_read_column_op() sets the current position to the beginning +of the OOB instead of OOB+offset + +Fixes: 15d6f118285f ("mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode") +Reviewed-by: Jernej Skrabec +Signed-off-by: Richard Genoud +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/sunxi_nand.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c +index 4469618ee6033..8d31cb0133acc 100644 +--- a/drivers/mtd/nand/raw/sunxi_nand.c ++++ b/drivers/mtd/nand/raw/sunxi_nand.c +@@ -886,9 +886,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, + if (len <= 0) + return; + +- if (!cur_off || *cur_off != offset) +- nand_change_read_column_op(nand, mtd->writesize, NULL, 0, +- false); ++ if (!cur_off || *cur_off != (offset + mtd->writesize)) ++ nand_change_read_column_op(nand, mtd->writesize + offset, ++ NULL, 0, false); + + if (!randomize) + sunxi_nfc_read_buf(nand, oob + offset, len); +-- +2.53.0 + diff --git a/queue-6.6/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch b/queue-6.6/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch new file mode 100644 index 0000000000..c8eaeff68f --- /dev/null +++ b/queue-6.6/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch @@ -0,0 +1,38 @@ +From dcf94f0b7b9f0774c3a5c81ad091fb1b4c354443 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 17:14:14 +0800 +Subject: mtd: spi-nor: core: correct the op.dummy.nbytes when check read + operations + +From: Haibo Chen + +[ Upstream commit 756564a536ecd8c9d33edd89f0647a91a0b03587 ] + +When check read operation, need to setting the op.dummy.nbytes based +on current read operation rather than the nor->read_proto. + +Fixes: 0e30f47232ab ("mtd: spi-nor: add support for DTR protocol") +Signed-off-by: Haibo Chen +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 6e135581ec62a..6f8a9c6253205 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -2477,7 +2477,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; +- if (spi_nor_protocol_is_dtr(nor->read_proto)) ++ if (spi_nor_protocol_is_dtr(read->proto)) + op.dummy.nbytes *= 2; + + return spi_nor_spimem_check_op(nor, &op); +-- +2.53.0 + diff --git a/queue-6.6/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch b/queue-6.6/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch new file mode 100644 index 0000000000..91485e370d --- /dev/null +++ b/queue-6.6/mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch @@ -0,0 +1,88 @@ +From 58788273a61f138ab087f9b9249728a1aebc36c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 16:47:59 +0900 +Subject: mtd: spi-nor: sfdp: introduce smpt_map_id fixup hook + +From: Takahiro Kuwano + +[ Upstream commit f74de390557bf2bcc5dca4a357b41c0701d3f76e ] + +Certain chips have inconsistent Sector Map Parameter Table (SMPT) data, +which leads to the wrong map ID being identified, causing failures to +detect the correct sector map. + +To fix this, introduce smpt_map_id() into the struct spi_nor_fixups. +This function will be called after the initial SMPT-based detection, +allowing chip-specific logic to correct the map ID. + +Infineon S25FS512S needs this fixup as it has inconsistency between map +ID definition and configuration register value actually obtained. + +Co-developed-by: Marek Vasut +Signed-off-by: Marek Vasut +Reviewed-by: Tudor Ambarus +Tested-by: Marek Vasut # S25FS512S +Signed-off-by: Takahiro Kuwano +Reviewed-by: Tudor Ambarus > +Signed-off-by: Pratyush Yadav +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 3 +++ + drivers/mtd/spi-nor/sfdp.c | 12 ++++++++++++ + 2 files changed, 15 insertions(+) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index a68cf82498ed8..6c478331e494e 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -418,6 +418,8 @@ struct spi_nor_flash_parameter { + * @post_bfpt: called after the BFPT table has been parsed + * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the + * number of dummy cycles in read register ops. ++ * @smpt_map_id: called after map ID in SMPT table has been determined for the ++ * case the map ID is wrong and needs to be fixed. + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. +@@ -436,6 +438,7 @@ struct spi_nor_fixups { + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); + void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); ++ void (*smpt_map_id)(const struct spi_nor *nor, u8 *map_id); + int (*post_sfdp)(struct spi_nor *nor); + int (*late_init)(struct spi_nor *nor); + }; +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index f1ec785628bfb..dcf88ad2a00b2 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -705,6 +705,16 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) + return read_dummy; + } + ++static void spi_nor_smpt_map_id_fixups(const struct spi_nor *nor, u8 *map_id) ++{ ++ if (nor->manufacturer && nor->manufacturer->fixups && ++ nor->manufacturer->fixups->smpt_map_id) ++ nor->manufacturer->fixups->smpt_map_id(nor, map_id); ++ ++ if (nor->info->fixups && nor->info->fixups->smpt_map_id) ++ nor->info->fixups->smpt_map_id(nor, map_id); ++} ++ + /** + * spi_nor_get_map_in_use() - get the configuration map in use + * @nor: pointer to a 'struct spi_nor' +@@ -758,6 +768,8 @@ static const u32 *spi_nor_get_map_in_use(struct spi_nor *nor, const u32 *smpt, + map_id = map_id << 1 | !!(*buf & read_data_mask); + } + ++ spi_nor_smpt_map_id_fixups(nor, &map_id); ++ + /* + * If command descriptors are provided, they always precede map + * descriptors in the table. There is no need to start the iteration +-- +2.53.0 + diff --git a/queue-6.6/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch b/queue-6.6/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch new file mode 100644 index 0000000000..4ce6826d61 --- /dev/null +++ b/queue-6.6/mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch @@ -0,0 +1,92 @@ +From 77ccccf2024470a727515f257dc67fdd91c012ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Nov 2025 16:47:58 +0900 +Subject: mtd: spi-nor: sfdp: introduce smpt_read_dummy fixup hook + +From: Takahiro Kuwano + +[ Upstream commit 653f6def567c81f37302f9591ffd54df3e2a11eb ] + +SMPT contains config detection info that describes opcode, address, and +dummy cycles to read sector map config. The dummy cycles parameter can +be SMPT_CMD_READ_DUMMY_IS_VARIABLE and in that case nor->read_dummy +(initialized as 0) is used. In Infineon flash chips, Read Any Register +command with variable dummy cycle is defined in SMPT. S25Hx/S28Hx flash +has 0 dummy cycle by default to read volatile regiters and +nor->read_dummy can work. S25FS-S flash has 8 dummy cycles so we need a +hook that can fix dummy cycles with actually used value. + +Inroduce smpt_read_dummy() in struct spi_nor_fixups. It is called when +the dummy cycle field in SMPT config detection is 'varialble'. + +Reviewed-by: Tudor Ambarus +Tested-by: Marek Vasut # S25FS512S +Signed-off-by: Takahiro Kuwano +Signed-off-by: Pratyush Yadav +Stable-dep-of: 3620d67b4849 ("mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation") +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 3 +++ + drivers/mtd/spi-nor/sfdp.c | 18 ++++++++++++++++-- + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 9217379b9cfef..a68cf82498ed8 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -416,6 +416,8 @@ struct spi_nor_flash_parameter { + * flash parameters when information provided by the flash_info + * table is incomplete or wrong. + * @post_bfpt: called after the BFPT table has been parsed ++ * @smpt_read_dummy: called during SMPT table is being parsed. Used to fix the ++ * number of dummy cycles in read register ops. + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. +@@ -433,6 +435,7 @@ struct spi_nor_fixups { + int (*post_bfpt)(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + const struct sfdp_bfpt *bfpt); ++ void (*smpt_read_dummy)(const struct spi_nor *nor, u8 *read_dummy); + int (*post_sfdp)(struct spi_nor *nor); + int (*late_init)(struct spi_nor *nor); + }; +diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c +index b3b11dfed7893..f1ec785628bfb 100644 +--- a/drivers/mtd/spi-nor/sfdp.c ++++ b/drivers/mtd/spi-nor/sfdp.c +@@ -674,6 +674,17 @@ static u8 spi_nor_smpt_addr_nbytes(const struct spi_nor *nor, const u32 settings + } + } + ++static void spi_nor_smpt_read_dummy_fixups(const struct spi_nor *nor, ++ u8 *read_dummy) ++{ ++ if (nor->manufacturer && nor->manufacturer->fixups && ++ nor->manufacturer->fixups->smpt_read_dummy) ++ nor->manufacturer->fixups->smpt_read_dummy(nor, read_dummy); ++ ++ if (nor->info->fixups && nor->info->fixups->smpt_read_dummy) ++ nor->info->fixups->smpt_read_dummy(nor, read_dummy); ++} ++ + /** + * spi_nor_smpt_read_dummy() - return the configuration detection command read + * latency, in clock cycles. +@@ -686,8 +697,11 @@ static u8 spi_nor_smpt_read_dummy(const struct spi_nor *nor, const u32 settings) + { + u8 read_dummy = SMPT_CMD_READ_DUMMY(settings); + +- if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) +- return nor->read_dummy; ++ if (read_dummy == SMPT_CMD_READ_DUMMY_IS_VARIABLE) { ++ read_dummy = nor->read_dummy; ++ spi_nor_smpt_read_dummy_fixups(nor, &read_dummy); ++ } ++ + return read_dummy; + } + +-- +2.53.0 + diff --git a/queue-6.6/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch b/queue-6.6/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch new file mode 100644 index 0000000000..2c3e8c83a3 --- /dev/null +++ b/queue-6.6/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch @@ -0,0 +1,41 @@ +From d49738b072d846237207ebbb53dd199c24f3af97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 20:42:56 +0800 +Subject: mtd: spi-nor: swp: check SR_TB flag when getting tb_mask + +From: Shiji Yang + +[ Upstream commit 94645aa41bf9ecb87c2ce78b1c3405bfb6074a37 ] + +When the chip does not support top/bottom block protect, the tb_mask +must be set to 0, otherwise SR1 bit5 will be unexpectedly modified. + +Signed-off-by: Shiji Yang +Fixes: 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support") +Reviewed-by: Michael Walle +Reviewed-by: Miquel Raynal +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/swp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c +index a186d1fde8694..4f34283603587 100644 +--- a/drivers/mtd/spi-nor/swp.c ++++ b/drivers/mtd/spi-nor/swp.c +@@ -27,8 +27,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) + { + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + return SR_TB_BIT6; +- else ++ else if (nor->flags & SNOR_F_HAS_SR_TB) + return SR_TB_BIT5; ++ else ++ return 0; + } + + static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) +-- +2.53.0 + diff --git a/queue-6.6/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch b/queue-6.6/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch new file mode 100644 index 0000000000..2b09ac9cf8 --- /dev/null +++ b/queue-6.6/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch @@ -0,0 +1,40 @@ +From 10646229e78d2e7b6fb6ec08a7f9f8c33d8fb083 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:54:30 +0100 +Subject: mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation + +From: Jonas Gorski + +[ Upstream commit 3620d67b48493c6252bbc873dc88dde81641d56b ] + +After commit 5273cc6df984 ("mtd: spi-nor: core: Call +spi_nor_post_sfdp_fixups() only when SFDP is defined") +spi_nor_post_sfdp_fixups() isn't called anymore if no SFDP is detected. + +Update the documentation accordingly. + +Fixes: 5273cc6df984 ("mtd: spi-nor: core: Call spi_nor_post_sfdp_fixups() only when SFDP is defined") +Signed-off-by: Jonas Gorski +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 6c478331e494e..398383ba0d8d6 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -420,7 +420,7 @@ struct spi_nor_flash_parameter { + * number of dummy cycles in read register ops. + * @smpt_map_id: called after map ID in SMPT table has been determined for the + * case the map ID is wrong and needs to be fixed. +- * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs ++ * @post_sfdp: called after SFDP has been parsed (is not called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. + * when information provided by the SFDP/flash_info tables are +-- +2.53.0 + diff --git a/queue-6.6/neigh-let-neigh_xmit-take-skb-ownership.patch b/queue-6.6/neigh-let-neigh_xmit-take-skb-ownership.patch new file mode 100644 index 0000000000..0f0ae84e68 --- /dev/null +++ b/queue-6.6/neigh-let-neigh_xmit-take-skb-ownership.patch @@ -0,0 +1,74 @@ +From 6664f18ffc9f0629e0be4a2997676a58132d9cfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 16:58:38 +0200 +Subject: neigh: let neigh_xmit take skb ownership + +From: Florian Westphal + +[ Upstream commit 4438113be604ee67a7bf4f81da6e1cca41332ce4 ] + +neigh_xmit always releases the skb, except when no neighbour table is +found. But even the first added user of neigh_xmit (mpls) relied on +neigh_xmit to release the skb (or queue it for tx). + +sashiko reported: + If neigh_xmit() is called with an uninitialized neighbor table (for + example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT + and bypasses its internal out_kfree_skb error path. Because the return + value of neigh_xmit() is ignored here, does this leak the SKB? + +Assume full ownership and remove the last code path that doesn't +xmit or free skb. + +Fixes: 4fd3d7d9e868 ("neigh: Add helper function neigh_xmit") +Signed-off-by: Florian Westphal +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260424145843.74055-1-fw@strlen.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index 8f45692265ce3..bc9690a3d60e9 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -3164,8 +3164,10 @@ int neigh_xmit(int index, struct net_device *dev, + + rcu_read_lock(); + tbl = rcu_dereference(neigh_tables[index]); +- if (!tbl) +- goto out_unlock; ++ if (!tbl) { ++ rcu_read_unlock(); ++ goto out_kfree_skb; ++ } + if (index == NEIGH_ARP_TABLE) { + u32 key = *((u32 *)addr); + +@@ -3181,7 +3183,6 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + } + err = READ_ONCE(neigh->output)(neigh, skb); +-out_unlock: + rcu_read_unlock(); + } + else if (index == NEIGH_LINK_TABLE) { +@@ -3191,11 +3192,10 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + err = dev_queue_xmit(skb); + } +-out: + return err; + out_kfree_skb: + kfree_skb(skb); +- goto out; ++ return err; + } + EXPORT_SYMBOL(neigh_xmit); + +-- +2.53.0 + diff --git a/queue-6.6/neighbour-add-rcu-protection-to-neigh_tables.patch b/queue-6.6/neighbour-add-rcu-protection-to-neigh_tables.patch new file mode 100644 index 0000000000..8a89f4619e --- /dev/null +++ b/queue-6.6/neighbour-add-rcu-protection-to-neigh_tables.patch @@ -0,0 +1,126 @@ +From 1a72ceba5289a9fd6fef41aa46832e2a8727d432 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Apr 2024 09:51:04 +0000 +Subject: neighbour: add RCU protection to neigh_tables[] + +From: Eric Dumazet + +[ Upstream commit f8f2eb9de69a1119117d198547c13d7a1123a5a9 ] + +In order to remove RTNL protection from neightbl_dump_info() +and neigh_dump_info() later, we need to add +RCU protection to neigh_tables[]. + +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +Stable-dep-of: 4438113be604 ("neigh: let neigh_xmit take skb ownership") +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 30 +++++++++++++++++++----------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index e6b36df482bc7..8f45692265ce3 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -1774,7 +1774,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms) + + static struct lock_class_key neigh_table_proxy_queue_class; + +-static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly; ++static struct neigh_table __rcu *neigh_tables[NEIGH_NR_TABLES] __read_mostly; + + void neigh_table_init(int index, struct neigh_table *tbl) + { +@@ -1831,13 +1831,19 @@ void neigh_table_init(int index, struct neigh_table *tbl) + tbl->last_flush = now; + tbl->last_rand = now + tbl->parms.reachable_time * 20; + +- neigh_tables[index] = tbl; ++ rcu_assign_pointer(neigh_tables[index], tbl); + } + EXPORT_SYMBOL(neigh_table_init); + ++/* ++ * Only called from ndisc_cleanup(), which means this is dead code ++ * because we no longer can unload IPv6 module. ++ */ + int neigh_table_clear(int index, struct neigh_table *tbl) + { +- neigh_tables[index] = NULL; ++ RCU_INIT_POINTER(neigh_tables[index], NULL); ++ synchronize_rcu(); ++ + /* It is not clean... Fix it to unload IPv6 module safely */ + cancel_delayed_work_sync(&tbl->managed_work); + cancel_delayed_work_sync(&tbl->gc_work); +@@ -1869,10 +1875,10 @@ static struct neigh_table *neigh_find_table(int family) + + switch (family) { + case AF_INET: +- tbl = neigh_tables[NEIGH_ARP_TABLE]; ++ tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ARP_TABLE]); + break; + case AF_INET6: +- tbl = neigh_tables[NEIGH_ND_TABLE]; ++ tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ND_TABLE]); + break; + } + +@@ -2338,7 +2344,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, + ndtmsg = nlmsg_data(nlh); + + for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { +- tbl = neigh_tables[tidx]; ++ tbl = rcu_dereference_rtnl(neigh_tables[tidx]); + if (!tbl) + continue; + if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) +@@ -2526,7 +2532,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) + for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { + struct neigh_parms *p; + +- tbl = neigh_tables[tidx]; ++ tbl = rcu_dereference_rtnl(neigh_tables[tidx]); + if (!tbl) + continue; + +@@ -2887,7 +2893,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) + s_t = cb->args[0]; + + for (t = 0; t < NEIGH_NR_TABLES; t++) { +- tbl = neigh_tables[t]; ++ tbl = rcu_dereference_rtnl(neigh_tables[t]); + + if (!tbl) + continue; +@@ -3151,14 +3157,15 @@ int neigh_xmit(int index, struct net_device *dev, + const void *addr, struct sk_buff *skb) + { + int err = -EAFNOSUPPORT; ++ + if (likely(index < NEIGH_NR_TABLES)) { + struct neigh_table *tbl; + struct neighbour *neigh; + +- tbl = neigh_tables[index]; +- if (!tbl) +- goto out; + rcu_read_lock(); ++ tbl = rcu_dereference(neigh_tables[index]); ++ if (!tbl) ++ goto out_unlock; + if (index == NEIGH_ARP_TABLE) { + u32 key = *((u32 *)addr); + +@@ -3174,6 +3181,7 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + } + err = READ_ONCE(neigh->output)(neigh, skb); ++out_unlock: + rcu_read_unlock(); + } + else if (index == NEIGH_LINK_TABLE) { +-- +2.53.0 + diff --git a/queue-6.6/net-bcmgenet-add-bcmgenet_has_-helpers.patch b/queue-6.6/net-bcmgenet-add-bcmgenet_has_-helpers.patch new file mode 100644 index 0000000000..b7b5efa541 --- /dev/null +++ b/queue-6.6/net-bcmgenet-add-bcmgenet_has_-helpers.patch @@ -0,0 +1,192 @@ +From e4ecbf362a1d994733343ed8365986fcfb7a4c85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:30 -0800 +Subject: net: bcmgenet: add bcmgenet_has_* helpers + +From: Doug Berger + +[ Upstream commit 07c1a756a50b1180a085ab61819a388bbb906a95 ] + +Introduce helper functions to indicate whether the driver should +make use of a particular feature that it supports. These helpers +abstract the implementation of how the feature availability is +encoded. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-3-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 20 +++++++------- + .../net/ethernet/broadcom/genet/bcmgenet.h | 27 ++++++++++++++++++- + drivers/net/ethernet/broadcom/genet/bcmmii.c | 6 ++--- + 3 files changed, 39 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 6ba26feed4588..1046b4f8544c9 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -104,7 +104,7 @@ static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, + * the platform is explicitly configured for 64-bits/LPAE. + */ + #ifdef CONFIG_PHYS_ADDR_T_64BIT +- if (priv->hw_params->flags & GENET_HAS_40BITS) ++ if (bcmgenet_has_40bits(priv)) + bcmgenet_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI); + #endif + } +@@ -1653,9 +1653,9 @@ static int bcmgenet_power_down(struct bcmgenet_priv *priv, + + case GENET_POWER_PASSIVE: + /* Power down LED */ +- if (priv->hw_params->flags & GENET_HAS_EXT) { ++ if (bcmgenet_has_ext(priv)) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); +- if (GENET_IS_V5(priv) && !priv->ephy_16nm) ++ if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) + reg |= EXT_PWR_DOWN_PHY_EN | + EXT_PWR_DOWN_PHY_RD | + EXT_PWR_DOWN_PHY_SD | +@@ -1683,7 +1683,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, + { + u32 reg; + +- if (!(priv->hw_params->flags & GENET_HAS_EXT)) ++ if (!bcmgenet_has_ext(priv)) + return; + + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); +@@ -1692,7 +1692,7 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, + case GENET_POWER_PASSIVE: + reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS | + EXT_ENERGY_DET_MASK); +- if (GENET_IS_V5(priv) && !priv->ephy_16nm) { ++ if (GENET_IS_V5(priv) && !bcmgenet_has_ephy_16nm(priv)) { + reg &= ~(EXT_PWR_DOWN_PHY_EN | + EXT_PWR_DOWN_PHY_RD | + EXT_PWR_DOWN_PHY_SD | +@@ -2525,7 +2525,7 @@ static void bcmgenet_link_intr_enable(struct bcmgenet_priv *priv) + } else if (priv->ext_phy) { + int0_enable |= UMAC_IRQ_LINK_EVENT; + } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { +- if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) ++ if (bcmgenet_has_moca_link_det(priv)) + int0_enable |= UMAC_IRQ_LINK_EVENT; + } + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); +@@ -2590,7 +2590,7 @@ static void init_umac(struct bcmgenet_priv *priv) + } + + /* Enable MDIO interrupts on GENET v3+ */ +- if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) ++ if (bcmgenet_has_mdio_intr(priv)) + int0_enable |= (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); + + bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); +@@ -3230,7 +3230,7 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + } + } + +- if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && ++ if (bcmgenet_has_mdio_intr(priv) && + status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + wake_up(&priv->wq); + } +@@ -3900,7 +3900,7 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) + } + + #ifdef CONFIG_PHYS_ADDR_T_64BIT +- if (!(params->flags & GENET_HAS_40BITS)) ++ if (!bcmgenet_has_40bits(priv)) + pr_warn("GENET does not support 40-bits PA\n"); + #endif + +@@ -4079,7 +4079,7 @@ static int bcmgenet_probe(struct platform_device *pdev) + bcmgenet_set_hw_params(priv); + + err = -EIO; +- if (priv->hw_params->flags & GENET_HAS_40BITS) ++ if (bcmgenet_has_40bits(priv)) + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + if (err) + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index 28e2c94ef835c..ba83819210aa8 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0-only */ + /* +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #ifndef __BCMGENET_H__ +@@ -650,6 +650,31 @@ struct bcmgenet_priv { + struct ethtool_eee eee; + }; + ++static inline bool bcmgenet_has_40bits(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_40BITS); ++} ++ ++static inline bool bcmgenet_has_ext(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_EXT); ++} ++ ++static inline bool bcmgenet_has_mdio_intr(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_MDIO_INTR); ++} ++ ++static inline bool bcmgenet_has_moca_link_det(struct bcmgenet_priv *priv) ++{ ++ return !!(priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET); ++} ++ ++static inline bool bcmgenet_has_ephy_16nm(struct bcmgenet_priv *priv) ++{ ++ return priv->ephy_16nm; ++} ++ + #define GENET_IO_MACRO(name, offset) \ + static inline u32 bcmgenet_##name##_readl(struct bcmgenet_priv *priv, \ + u32 off) \ +diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c +index e7c659cd39746..e4b498d6bd914 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c +@@ -2,7 +2,7 @@ + /* + * Broadcom GENET MDIO routines + * +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #include +@@ -153,7 +153,7 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable) + u32 reg = 0; + + /* EXT_GPHY_CTRL is only valid for GENETv4 and onward */ +- if (GENET_IS_V4(priv) || priv->ephy_16nm) { ++ if (GENET_IS_V4(priv) || bcmgenet_has_ephy_16nm(priv)) { + reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL); + if (enable) { + reg &= ~EXT_CK25_DIS; +@@ -183,7 +183,7 @@ void bcmgenet_phy_power_set(struct net_device *dev, bool enable) + + static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) + { +- if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) ++ if (bcmgenet_has_moca_link_det(priv)) + fixed_phy_set_link_update(priv->dev->phydev, + bcmgenet_fixed_phy_link_update); + } +-- +2.53.0 + diff --git a/queue-6.6/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch b/queue-6.6/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch new file mode 100644 index 0000000000..7f4e257c10 --- /dev/null +++ b/queue-6.6/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch @@ -0,0 +1,50 @@ +From 48b437b11e125ba8421fb9a76c29da3daf92386d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:54 -0700 +Subject: net: bcmgenet: fix off-by-one in bcmgenet_put_txcb + +From: Justin Chen + +[ Upstream commit 57f3f53d2c9c5a9e133596e2f7bc1c50688a6d38 ] + +The write_ptr points to the next open tx_cb. We want to return the +tx_cb that gets rewinded, so we must rewind the pointer first then +return the tx_cb that it points to. That way the txcb can be correctly +cleaned up. + +Fixes: 876dbadd53a7 ("net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()") +Signed-off-by: Justin Chen +Reviewed-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-2-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 79d096a371ae7..cdbe47c7ba280 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1749,15 +1749,15 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + { + struct enet_cb *tx_cb_ptr; + +- tx_cb_ptr = ring->cbs; +- tx_cb_ptr += ring->write_ptr - ring->cb_ptr; +- + /* Rewinding local write pointer */ + if (ring->write_ptr == ring->cb_ptr) + ring->write_ptr = ring->end_ptr; + else + ring->write_ptr--; + ++ tx_cb_ptr = ring->cbs; ++ tx_cb_ptr += ring->write_ptr - ring->cb_ptr; ++ + return tx_cb_ptr; + } + +-- +2.53.0 + diff --git a/queue-6.6/net-bcmgenet-fix-racing-timeout-handler.patch b/queue-6.6/net-bcmgenet-fix-racing-timeout-handler.patch new file mode 100644 index 0000000000..bbc7a98249 --- /dev/null +++ b/queue-6.6/net-bcmgenet-fix-racing-timeout-handler.patch @@ -0,0 +1,70 @@ +From ccec4f4e20fa6bce2988b2ee809bc9a7461167c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:56 -0700 +Subject: net: bcmgenet: fix racing timeout handler + +From: Justin Chen + +[ Upstream commit 5393b2b5bee2ac51a0043dc7f4ac3475f053d08d ] + +The bcmgenet_timeout handler tries to take down all tx queues when +a single queue times out. This is over zealous and causes many race +conditions with queues that are still chugging along. Instead lets +only restart the timed out queue. + +Fixes: 13ea657806cf ("net: bcmgenet: improve TX timeout") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-4-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 22 ++++++++----------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index a5166582e0ab7..e08abde4685ac 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -3474,27 +3474,23 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 int1_enable = 0; +- unsigned int q; ++ struct bcmgenet_tx_ring *ring = &priv->tx_rings[txqueue]; ++ struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue); + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- bcmgenet_dump_tx_queue(&priv->tx_rings[q]); +- +- bcmgenet_tx_reclaim_all(dev); ++ bcmgenet_dump_tx_queue(ring); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- int1_enable |= (1 << q); ++ bcmgenet_tx_reclaim(dev, ring, true); + +- /* Re-enable TX interrupts if disabled */ +- bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); ++ /* Re-enable the TX interrupt for this ring */ ++ bcmgenet_intrl2_1_writel(priv, 1 << txqueue, INTRL2_CPU_MASK_CLEAR); + +- netif_trans_update(dev); ++ txq_trans_cond_update(txq); + +- BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors); ++ BCMGENET_STATS64_INC((&ring->stats64), errors); + +- netif_tx_wake_all_queues(dev); ++ netif_tx_wake_queue(txq); + } + + #define MAX_MDF_FILTER 17 +-- +2.53.0 + diff --git a/queue-6.6/net-bcmgenet-move-desc_index-flow-to-ring-0.patch b/queue-6.6/net-bcmgenet-move-desc_index-flow-to-ring-0.patch new file mode 100644 index 0000000000..f1cb766bee --- /dev/null +++ b/queue-6.6/net-bcmgenet-move-desc_index-flow-to-ring-0.patch @@ -0,0 +1,947 @@ +From baf5e0e39705da06385704bfd9ad8ce6acdc1999 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:34 -0800 +Subject: net: bcmgenet: move DESC_INDEX flow to ring 0 + +From: Doug Berger + +[ Upstream commit 3b5d4f5a820d362dd46472542b2e961fb1f93515 ] + +The default transmit and receive packet handling is moved from +the DESC_INDEX (i.e. 16) descriptor rings to the Ring 0 queues. +This saves a fair amount of special case code by unifying the +handling. + +A default dummy filter is enabled in the Hardware Filter Block +to route default receive packets to Ring 0. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-7-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 369 +++++------------- + .../net/ethernet/broadcom/genet/bcmgenet.h | 12 +- + .../ethernet/broadcom/genet/bcmgenet_wol.c | 4 +- + 3 files changed, 110 insertions(+), 275 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 1046b4f8544c9..ed66ae393100e 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -41,15 +41,13 @@ + + #include "bcmgenet.h" + +-/* Maximum number of hardware queues, downsized if needed */ +-#define GENET_MAX_MQ_CNT 4 +- + /* Default highest priority queue for multi queue support */ +-#define GENET_Q0_PRIORITY 0 ++#define GENET_Q1_PRIORITY 0 ++#define GENET_Q0_PRIORITY 1 + +-#define GENET_Q16_RX_BD_CNT \ ++#define GENET_Q0_RX_BD_CNT \ + (TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q) +-#define GENET_Q16_TX_BD_CNT \ ++#define GENET_Q0_TX_BD_CNT \ + (TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->tx_bds_per_q) + + #define RX_BUF_LENGTH 2048 +@@ -585,7 +583,7 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, + u16 mask_16; + size_t size; + +- f = fs->location; ++ f = fs->location + 1; + if (fs->flow_type & FLOW_MAC_EXT) { + bcmgenet_hfb_insert_data(priv, f, 0, + &fs->h_ext.h_dest, &fs->m_ext.h_dest, +@@ -667,19 +665,14 @@ static void bcmgenet_hfb_create_rxnfc_filter(struct bcmgenet_priv *priv, + } + + bcmgenet_hfb_set_filter_length(priv, f, 2 * f_length); +- if (!fs->ring_cookie || fs->ring_cookie == RX_CLS_FLOW_WAKE) { +- /* Ring 0 flows can be handled by the default Descriptor Ring +- * We'll map them to ring 0, but don't enable the filter +- */ ++ if (fs->ring_cookie == RX_CLS_FLOW_WAKE) + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, 0); +- rule->state = BCMGENET_RXNFC_STATE_DISABLED; +- } else { ++ else + /* Other Rx rings are direct mapped here */ + bcmgenet_hfb_set_filter_rx_queue_mapping(priv, f, + fs->ring_cookie); +- bcmgenet_hfb_enable_filter(priv, f); +- rule->state = BCMGENET_RXNFC_STATE_ENABLED; +- } ++ bcmgenet_hfb_enable_filter(priv, f); ++ rule->state = BCMGENET_RXNFC_STATE_ENABLED; + } + + /* bcmgenet_hfb_clear +@@ -715,6 +708,10 @@ static void bcmgenet_hfb_clear(struct bcmgenet_priv *priv) + + for (i = 0; i < priv->hw_params->hfb_filter_cnt; i++) + bcmgenet_hfb_clear_filter(priv, i); ++ ++ /* Enable filter 0 to send default flow to ring 0 */ ++ bcmgenet_hfb_set_filter_length(priv, 0, 4); ++ bcmgenet_hfb_enable_filter(priv, 0); + } + + static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) +@@ -819,20 +816,16 @@ static int bcmgenet_get_coalesce(struct net_device *dev, + unsigned int i; + + ec->tx_max_coalesced_frames = +- bcmgenet_tdma_ring_readl(priv, DESC_INDEX, +- DMA_MBUF_DONE_THRESH); ++ bcmgenet_tdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); + ec->rx_max_coalesced_frames = +- bcmgenet_rdma_ring_readl(priv, DESC_INDEX, +- DMA_MBUF_DONE_THRESH); ++ bcmgenet_rdma_ring_readl(priv, 0, DMA_MBUF_DONE_THRESH); + ec->rx_coalesce_usecs = +- bcmgenet_rdma_readl(priv, DMA_RING16_TIMEOUT) * 8192 / 1000; ++ bcmgenet_rdma_readl(priv, DMA_RING0_TIMEOUT) * 8192 / 1000; + +- for (i = 0; i < priv->hw_params->rx_queues; i++) { ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) { + ring = &priv->rx_rings[i]; + ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; + } +- ring = &priv->rx_rings[DESC_INDEX]; +- ec->use_adaptive_rx_coalesce |= ring->dim.use_dim; + + return 0; + } +@@ -902,17 +895,13 @@ static int bcmgenet_set_coalesce(struct net_device *dev, + /* Program all TX queues with the same values, as there is no + * ethtool knob to do coalescing on a per-queue basis + */ +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + bcmgenet_tdma_ring_writel(priv, i, + ec->tx_max_coalesced_frames, + DMA_MBUF_DONE_THRESH); +- bcmgenet_tdma_ring_writel(priv, DESC_INDEX, +- ec->tx_max_coalesced_frames, +- DMA_MBUF_DONE_THRESH); + +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[i], ec); +- bcmgenet_set_ring_rx_coalesce(&priv->rx_rings[DESC_INDEX], ec); + + return 0; + } +@@ -1120,7 +1109,7 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + STAT_GENET_Q(1), + STAT_GENET_Q(2), + STAT_GENET_Q(3), +- STAT_GENET_Q(16), ++ STAT_GENET_Q(4), + }; + + #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) +@@ -1474,10 +1463,10 @@ static int bcmgenet_insert_flow(struct net_device *dev, + loc_rule = &priv->rxnfc_rules[cmd->fs.location]; + } + if (loc_rule->state == BCMGENET_RXNFC_STATE_ENABLED) +- bcmgenet_hfb_disable_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); + if (loc_rule->state != BCMGENET_RXNFC_STATE_UNUSED) { + list_del(&loc_rule->list); +- bcmgenet_hfb_clear_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); + } + loc_rule->state = BCMGENET_RXNFC_STATE_UNUSED; + memcpy(&loc_rule->fs, &cmd->fs, +@@ -1507,10 +1496,10 @@ static int bcmgenet_delete_flow(struct net_device *dev, + } + + if (rule->state == BCMGENET_RXNFC_STATE_ENABLED) +- bcmgenet_hfb_disable_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_disable_filter(priv, cmd->fs.location + 1); + if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) { + list_del(&rule->list); +- bcmgenet_hfb_clear_filter(priv, cmd->fs.location); ++ bcmgenet_hfb_clear_filter(priv, cmd->fs.location + 1); + } + rule->state = BCMGENET_RXNFC_STATE_UNUSED; + memset(&rule->fs, 0, sizeof(struct ethtool_rx_flow_spec)); +@@ -1761,18 +1750,6 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + return tx_cb_ptr; + } + +-static inline void bcmgenet_rx_ring16_int_disable(struct bcmgenet_rx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_MASK_SET); +-} +- +-static inline void bcmgenet_rx_ring16_int_enable(struct bcmgenet_rx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_MASK_CLEAR); +-} +- + static inline void bcmgenet_rx_ring_int_disable(struct bcmgenet_rx_ring *ring) + { + bcmgenet_intrl2_1_writel(ring->priv, +@@ -1787,18 +1764,6 @@ static inline void bcmgenet_rx_ring_int_enable(struct bcmgenet_rx_ring *ring) + INTRL2_CPU_MASK_CLEAR); + } + +-static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_tx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_MASK_SET); +-} +- +-static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_tx_ring *ring) +-{ +- bcmgenet_intrl2_0_writel(ring->priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_MASK_CLEAR); +-} +- + static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_tx_ring *ring) + { + bcmgenet_intrl2_1_writel(ring->priv, 1 << ring->index, +@@ -1879,12 +1844,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + struct sk_buff *skb; + + /* Clear status before servicing to reduce spurious interrupts */ +- if (ring->index == DESC_INDEX) +- bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_TXDMA_DONE, +- INTRL2_CPU_CLEAR); +- else +- bcmgenet_intrl2_1_writel(priv, (1 << ring->index), +- INTRL2_CPU_CLEAR); ++ bcmgenet_intrl2_1_writel(priv, (1 << ring->index), INTRL2_CPU_CLEAR); + + /* Compute how many buffers are transmitted since last xmit call */ + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX) +@@ -1918,7 +1878,7 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + ring->packets += pkts_compl; + ring->bytes += bytes_compl; + +- netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->queue), ++ netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->index), + pkts_compl, bytes_compl); + + return txbds_processed; +@@ -1946,14 +1906,14 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) + spin_lock(&ring->lock); + work_done = __bcmgenet_tx_reclaim(ring->priv->dev, ring); + if (ring->free_bds > (MAX_SKB_FRAGS + 1)) { +- txq = netdev_get_tx_queue(ring->priv->dev, ring->queue); ++ txq = netdev_get_tx_queue(ring->priv->dev, ring->index); + netif_tx_wake_queue(txq); + } + spin_unlock(&ring->lock); + + if (work_done == 0) { + napi_complete(napi); +- ring->int_enable(ring); ++ bcmgenet_tx_ring_int_enable(ring); + + return 0; + } +@@ -1964,14 +1924,11 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget) + static void bcmgenet_tx_reclaim_all(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- int i; +- +- if (netif_is_multiqueue(dev)) { +- for (i = 0; i < priv->hw_params->tx_queues; i++) +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[i]); +- } ++ int i = 0; + +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]); ++ do { ++ bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++]); ++ } while (i <= priv->hw_params->tx_queues && netif_is_multiqueue(dev)); + } + + /* Reallocate the SKB to put enough headroom in front of it and insert +@@ -2059,19 +2016,14 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) + + index = skb_get_queue_mapping(skb); + /* Mapping strategy: +- * queue_mapping = 0, unclassified, packet xmited through ring16 +- * queue_mapping = 1, goes to ring 0. (highest priority queue +- * queue_mapping = 2, goes to ring 1. +- * queue_mapping = 3, goes to ring 2. +- * queue_mapping = 4, goes to ring 3. ++ * queue_mapping = 0, unclassified, packet xmited through ring 0 ++ * queue_mapping = 1, goes to ring 1. (highest priority queue) ++ * queue_mapping = 2, goes to ring 2. ++ * queue_mapping = 3, goes to ring 3. ++ * queue_mapping = 4, goes to ring 4. + */ +- if (index == 0) +- index = DESC_INDEX; +- else +- index -= 1; +- + ring = &priv->tx_rings[index]; +- txq = netdev_get_tx_queue(dev, ring->queue); ++ txq = netdev_get_tx_queue(dev, index); + + nr_frags = skb_shinfo(skb)->nr_frags; + +@@ -2244,15 +2196,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + unsigned int discards; + + /* Clear status before servicing to reduce spurious interrupts */ +- if (ring->index == DESC_INDEX) { +- bcmgenet_intrl2_0_writel(priv, UMAC_IRQ_RXDMA_DONE, +- INTRL2_CPU_CLEAR); +- } else { +- mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); +- bcmgenet_intrl2_1_writel(priv, +- mask, +- INTRL2_CPU_CLEAR); +- } ++ mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); ++ bcmgenet_intrl2_1_writel(priv, mask, INTRL2_CPU_CLEAR); + + p_index = bcmgenet_rdma_ring_readl(priv, ring->index, RDMA_PROD_INDEX); + +@@ -2401,7 +2346,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) + + if (work_done < budget) { + napi_complete_done(napi, work_done); +- ring->int_enable(ring); ++ bcmgenet_rx_ring_int_enable(ring); + } + + if (ring->dim.use_dim) { +@@ -2641,15 +2586,6 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, + spin_lock_init(&ring->lock); + ring->priv = priv; + ring->index = index; +- if (index == DESC_INDEX) { +- ring->queue = 0; +- ring->int_enable = bcmgenet_tx_ring16_int_enable; +- ring->int_disable = bcmgenet_tx_ring16_int_disable; +- } else { +- ring->queue = index + 1; +- ring->int_enable = bcmgenet_tx_ring_int_enable; +- ring->int_disable = bcmgenet_tx_ring_int_disable; +- } + ring->cbs = priv->tx_cbs + start_ptr; + ring->size = size; + ring->clean_ptr = start_ptr; +@@ -2660,8 +2596,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, + ring->end_ptr = end_ptr - 1; + ring->prod_index = 0; + +- /* Set flow period for ring != 16 */ +- if (index != DESC_INDEX) ++ /* Set flow period for ring != 0 */ ++ if (index) + flow_period_val = ENET_MAX_MTU_SIZE << 16; + + bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); +@@ -2699,13 +2635,6 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, + + ring->priv = priv; + ring->index = index; +- if (index == DESC_INDEX) { +- ring->int_enable = bcmgenet_rx_ring16_int_enable; +- ring->int_disable = bcmgenet_rx_ring16_int_disable; +- } else { +- ring->int_enable = bcmgenet_rx_ring_int_enable; +- ring->int_disable = bcmgenet_rx_ring_int_disable; +- } + ring->cbs = priv->rx_cbs + start_ptr; + ring->size = size; + ring->c_index = 0; +@@ -2751,15 +2680,11 @@ static void bcmgenet_enable_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + napi_enable(&ring->napi); +- ring->int_enable(ring); ++ bcmgenet_tx_ring_int_enable(ring); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- napi_enable(&ring->napi); +- ring->int_enable(ring); + } + + static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) +@@ -2767,13 +2692,10 @@ static void bcmgenet_disable_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + napi_disable(&ring->napi); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- napi_disable(&ring->napi); + } + + static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) +@@ -2781,33 +2703,31 @@ static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_tx_ring *ring; + +- for (i = 0; i < priv->hw_params->tx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->tx_queues; ++i) { + ring = &priv->tx_rings[i]; + netif_napi_del(&ring->napi); + } +- +- ring = &priv->tx_rings[DESC_INDEX]; +- netif_napi_del(&ring->napi); + } + + /* Initialize Tx queues + * +- * Queues 0-3 are priority-based, each one has 32 descriptors, +- * with queue 0 being the highest priority queue. ++ * Queues 1-4 are priority-based, each one has 32 descriptors, ++ * with queue 1 being the highest priority queue. + * +- * Queue 16 is the default Tx queue with +- * GENET_Q16_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. ++ * Queue 0 is the default Tx queue with ++ * GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. + * + * The transmit control block pool is then partitioned as follows: +- * - Tx queue 0 uses tx_cbs[0..31] +- * - Tx queue 1 uses tx_cbs[32..63] +- * - Tx queue 2 uses tx_cbs[64..95] +- * - Tx queue 3 uses tx_cbs[96..127] +- * - Tx queue 16 uses tx_cbs[128..255] ++ * - Tx queue 0 uses tx_cbs[0..127] ++ * - Tx queue 1 uses tx_cbs[128..159] ++ * - Tx queue 2 uses tx_cbs[160..191] ++ * - Tx queue 3 uses tx_cbs[192..223] ++ * - Tx queue 4 uses tx_cbs[224..255] + */ + static void bcmgenet_init_tx_queues(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); ++ unsigned int start = 0, end = GENET_Q0_TX_BD_CNT; + u32 i, dma_enable; + u32 dma_ctrl, ring_cfg; + u32 dma_priority[3] = {0, 0, 0}; +@@ -2824,27 +2744,17 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) + bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL); + + /* Initialize Tx priority queues */ +- for (i = 0; i < priv->hw_params->tx_queues; i++) { +- bcmgenet_init_tx_ring(priv, i, priv->hw_params->tx_bds_per_q, +- i * priv->hw_params->tx_bds_per_q, +- (i + 1) * priv->hw_params->tx_bds_per_q); ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) { ++ bcmgenet_init_tx_ring(priv, i, end - start, start, end); ++ start = end; ++ end += priv->hw_params->tx_bds_per_q; + ring_cfg |= (1 << i); + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + dma_priority[DMA_PRIO_REG_INDEX(i)] |= +- ((GENET_Q0_PRIORITY + i) << DMA_PRIO_REG_SHIFT(i)); ++ (i ? GENET_Q1_PRIORITY : GENET_Q0_PRIORITY) ++ << DMA_PRIO_REG_SHIFT(i); + } + +- /* Initialize Tx default queue 16 */ +- bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_Q16_TX_BD_CNT, +- priv->hw_params->tx_queues * +- priv->hw_params->tx_bds_per_q, +- TOTAL_DESC); +- ring_cfg |= (1 << DESC_INDEX); +- dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); +- dma_priority[DMA_PRIO_REG_INDEX(DESC_INDEX)] |= +- ((GENET_Q0_PRIORITY + priv->hw_params->tx_queues) << +- DMA_PRIO_REG_SHIFT(DESC_INDEX)); +- + /* Set Tx queue priorities */ + bcmgenet_tdma_writel(priv, dma_priority[0], DMA_PRIORITY_0); + bcmgenet_tdma_writel(priv, dma_priority[1], DMA_PRIORITY_1); +@@ -2864,15 +2774,11 @@ static void bcmgenet_enable_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + napi_enable(&ring->napi); +- ring->int_enable(ring); ++ bcmgenet_rx_ring_int_enable(ring); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- napi_enable(&ring->napi); +- ring->int_enable(ring); + } + + static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) +@@ -2880,15 +2786,11 @@ static void bcmgenet_disable_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + napi_disable(&ring->napi); + cancel_work_sync(&ring->dim.dim.work); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- napi_disable(&ring->napi); +- cancel_work_sync(&ring->dim.dim.work); + } + + static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) +@@ -2896,13 +2798,10 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) + unsigned int i; + struct bcmgenet_rx_ring *ring; + +- for (i = 0; i < priv->hw_params->rx_queues; ++i) { ++ for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + netif_napi_del(&ring->napi); + } +- +- ring = &priv->rx_rings[DESC_INDEX]; +- netif_napi_del(&ring->napi); + } + + /* Initialize Rx queues +@@ -2910,15 +2809,13 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) + * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be + * used to direct traffic to these queues. + * +- * Queue 16 is the default Rx queue with GENET_Q16_RX_BD_CNT descriptors. ++ * Queue 0 is also the default Rx queue with GENET_Q0_RX_BD_CNT descriptors. + */ + static int bcmgenet_init_rx_queues(struct net_device *dev) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 i; +- u32 dma_enable; +- u32 dma_ctrl; +- u32 ring_cfg; ++ unsigned int start = 0, end = GENET_Q0_RX_BD_CNT; ++ u32 i, dma_enable, dma_ctrl = 0, ring_cfg = 0; + int ret; + + dma_ctrl = bcmgenet_rdma_readl(priv, DMA_CTRL); +@@ -2930,34 +2827,21 @@ static int bcmgenet_init_rx_queues(struct net_device *dev) + ring_cfg = 0; + + /* Initialize Rx priority queues */ +- for (i = 0; i < priv->hw_params->rx_queues; i++) { +- ret = bcmgenet_init_rx_ring(priv, i, +- priv->hw_params->rx_bds_per_q, +- i * priv->hw_params->rx_bds_per_q, +- (i + 1) * +- priv->hw_params->rx_bds_per_q); ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) { ++ ret = bcmgenet_init_rx_ring(priv, i, end - start, start, end); + if (ret) + return ret; + ++ start = end; ++ end += priv->hw_params->rx_bds_per_q; + ring_cfg |= (1 << i); + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + } + +- /* Initialize Rx default queue 16 */ +- ret = bcmgenet_init_rx_ring(priv, DESC_INDEX, GENET_Q16_RX_BD_CNT, +- priv->hw_params->rx_queues * +- priv->hw_params->rx_bds_per_q, +- TOTAL_DESC); +- if (ret) +- return ret; +- +- ring_cfg |= (1 << DESC_INDEX); +- dma_ctrl |= (1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT)); +- +- /* Enable rings */ ++ /* Configure Rx queues as descriptor rings */ + bcmgenet_rdma_writel(priv, ring_cfg, DMA_RING_CFG); + +- /* Configure ring as descriptor ring and re-enable DMA if enabled */ ++ /* Enable Rx rings */ + if (dma_enable) + dma_ctrl |= DMA_EN; + bcmgenet_rdma_writel(priv, dma_ctrl, DMA_CTRL); +@@ -3016,14 +2900,14 @@ static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) + } + + dma_ctrl = 0; +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; + bcmgenet_rdma_writel(priv, reg, DMA_CTRL); + + dma_ctrl = 0; +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; +@@ -3044,14 +2928,11 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) + dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, + priv->tx_cbs + i)); + +- for (i = 0; i < priv->hw_params->tx_queues; i++) { +- txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[i].queue); ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) { ++ txq = netdev_get_tx_queue(priv->dev, i); + netdev_tx_reset_queue(txq); + } + +- txq = netdev_get_tx_queue(priv->dev, priv->tx_rings[DESC_INDEX].queue); +- netdev_tx_reset_queue(txq); +- + bcmgenet_free_rx_buffers(priv); + kfree(priv->rx_cbs); + kfree(priv->tx_cbs); +@@ -3144,7 +3025,7 @@ static void bcmgenet_irq_task(struct work_struct *work) + + } + +-/* bcmgenet_isr1: handle Rx and Tx priority queues */ ++/* bcmgenet_isr1: handle Rx and Tx queues */ + static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + { + struct bcmgenet_priv *priv = dev_id; +@@ -3163,7 +3044,7 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + "%s: IRQ=0x%x\n", __func__, status); + + /* Check Rx priority queue interrupts */ +- for (index = 0; index < priv->hw_params->rx_queues; index++) { ++ for (index = 0; index <= priv->hw_params->rx_queues; index++) { + if (!(status & BIT(UMAC_IRQ1_RX_INTR_SHIFT + index))) + continue; + +@@ -3171,20 +3052,20 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + rx_ring->dim.event_ctr++; + + if (likely(napi_schedule_prep(&rx_ring->napi))) { +- rx_ring->int_disable(rx_ring); ++ bcmgenet_rx_ring_int_disable(rx_ring); + __napi_schedule_irqoff(&rx_ring->napi); + } + } + + /* Check Tx priority queue interrupts */ +- for (index = 0; index < priv->hw_params->tx_queues; index++) { ++ for (index = 0; index <= priv->hw_params->tx_queues; index++) { + if (!(status & BIT(index))) + continue; + + tx_ring = &priv->tx_rings[index]; + + if (likely(napi_schedule_prep(&tx_ring->napi))) { +- tx_ring->int_disable(tx_ring); ++ bcmgenet_tx_ring_int_disable(tx_ring); + __napi_schedule_irqoff(&tx_ring->napi); + } + } +@@ -3192,12 +3073,10 @@ static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) + return IRQ_HANDLED; + } + +-/* bcmgenet_isr0: handle Rx and Tx default queues + other stuff */ ++/* bcmgenet_isr0: handle other stuff */ + static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + { + struct bcmgenet_priv *priv = dev_id; +- struct bcmgenet_rx_ring *rx_ring; +- struct bcmgenet_tx_ring *tx_ring; + unsigned int status; + unsigned long flags; + +@@ -3211,25 +3090,6 @@ static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) + netif_dbg(priv, intr, priv->dev, + "IRQ=0x%x\n", status); + +- if (status & UMAC_IRQ_RXDMA_DONE) { +- rx_ring = &priv->rx_rings[DESC_INDEX]; +- rx_ring->dim.event_ctr++; +- +- if (likely(napi_schedule_prep(&rx_ring->napi))) { +- rx_ring->int_disable(rx_ring); +- __napi_schedule_irqoff(&rx_ring->napi); +- } +- } +- +- if (status & UMAC_IRQ_TXDMA_DONE) { +- tx_ring = &priv->tx_rings[DESC_INDEX]; +- +- if (likely(napi_schedule_prep(&tx_ring->napi))) { +- tx_ring->int_disable(tx_ring); +- __napi_schedule_irqoff(&tx_ring->napi); +- } +- } +- + if (bcmgenet_has_mdio_intr(priv) && + status & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + wake_up(&priv->wq); +@@ -3295,15 +3155,15 @@ static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv, bool flush_rx) + u32 dma_ctrl; + + /* disable DMA */ +- dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; +- for (i = 0; i < priv->hw_params->tx_queues; i++) ++ dma_ctrl = DMA_EN; ++ for (i = 0; i <= priv->hw_params->tx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); + +- dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ dma_ctrl = DMA_EN; ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT)); + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; +@@ -3386,6 +3246,9 @@ static int bcmgenet_open(struct net_device *dev) + + bcmgenet_set_hw_addr(priv, dev->dev_addr); + ++ /* HFB init */ ++ bcmgenet_hfb_init(priv); ++ + /* Disable RX/TX DMA and flush TX and RX queues */ + dma_ctrl = bcmgenet_dma_disable(priv, true); + +@@ -3396,12 +3259,8 @@ static int bcmgenet_open(struct net_device *dev) + goto err_clk_disable; + } + +- /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + +- /* HFB init */ +- bcmgenet_hfb_init(priv); +- + ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED, + dev->name, priv); + if (ret < 0) { +@@ -3508,16 +3367,11 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + if (!netif_msg_tx_err(priv)) + return; + +- txq = netdev_get_tx_queue(priv->dev, ring->queue); ++ txq = netdev_get_tx_queue(priv->dev, ring->index); + + spin_lock(&ring->lock); +- if (ring->index == DESC_INDEX) { +- intsts = ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); +- intmsk = UMAC_IRQ_TXDMA_DONE | UMAC_IRQ_TXDMA_MBDONE; +- } else { +- intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); +- intmsk = 1 << ring->index; +- } ++ intsts = ~bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_MASK_STATUS); ++ intmsk = 1 << ring->index; + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); + p_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_PROD_INDEX); + txq_stopped = netif_tx_queue_stopped(txq); +@@ -3531,7 +3385,7 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + "(sw)c_index: %d (hw)c_index: %d\n" + "(sw)clean_p: %d (sw)write_p: %d\n" + "(sw)cb_ptr: %d (sw)end_ptr: %d\n", +- ring->index, ring->queue, ++ ring->index, ring->index, + txq_stopped ? "stopped" : "active", + intsts & intmsk ? "enabled" : "disabled", + free_bds, ring->size, +@@ -3544,25 +3398,20 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 int0_enable = 0; + u32 int1_enable = 0; + unsigned int q; + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + +- for (q = 0; q < priv->hw_params->tx_queues; q++) ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) + bcmgenet_dump_tx_queue(&priv->tx_rings[q]); +- bcmgenet_dump_tx_queue(&priv->tx_rings[DESC_INDEX]); + + bcmgenet_tx_reclaim_all(dev); + +- for (q = 0; q < priv->hw_params->tx_queues; q++) ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) + int1_enable |= (1 << q); + +- int0_enable = UMAC_IRQ_TXDMA_DONE; +- + /* Re-enable TX interrupts if disabled */ +- bcmgenet_intrl2_0_writel(priv, int0_enable, INTRL2_CPU_MASK_CLEAR); + bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); + + netif_trans_update(dev); +@@ -3666,16 +3515,13 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) + struct bcmgenet_rx_ring *rx_ring; + unsigned int q; + +- for (q = 0; q < priv->hw_params->tx_queues; q++) { ++ for (q = 0; q <= priv->hw_params->tx_queues; q++) { + tx_ring = &priv->tx_rings[q]; + tx_bytes += tx_ring->bytes; + tx_packets += tx_ring->packets; + } +- tx_ring = &priv->tx_rings[DESC_INDEX]; +- tx_bytes += tx_ring->bytes; +- tx_packets += tx_ring->packets; + +- for (q = 0; q < priv->hw_params->rx_queues; q++) { ++ for (q = 0; q <= priv->hw_params->rx_queues; q++) { + rx_ring = &priv->rx_rings[q]; + + rx_bytes += rx_ring->bytes; +@@ -3683,11 +3529,6 @@ static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) + rx_errors += rx_ring->errors; + rx_dropped += rx_ring->dropped; + } +- rx_ring = &priv->rx_rings[DESC_INDEX]; +- rx_bytes += rx_ring->bytes; +- rx_packets += rx_ring->packets; +- rx_errors += rx_ring->errors; +- rx_dropped += rx_ring->dropped; + + dev->stats.tx_bytes = tx_bytes; + dev->stats.tx_packets = tx_packets; +@@ -4134,16 +3975,13 @@ static int bcmgenet_probe(struct platform_device *pdev) + if (err) + goto err_clk_disable; + +- /* setup number of real queues + 1 (GENET_V1 has 0 hardware queues +- * just the ring 16 descriptor based TX +- */ ++ /* setup number of real queues + 1 */ + netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1); + netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); + + /* Set default coalescing parameters */ +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i <= priv->hw_params->rx_queues; i++) + priv->rx_rings[i].rx_max_coalesced_frames = 1; +- priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1; + + /* libphy will determine the link state */ + netif_carrier_off(dev); +@@ -4268,7 +4106,6 @@ static int bcmgenet_resume(struct device *d) + goto out_clk_disable; + } + +- /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + + if (!device_may_wakeup(d)) +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index ba83819210aa8..f3a1139cb7108 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -18,6 +18,9 @@ + + #include "../unimac.h" + ++/* Maximum number of hardware queues, downsized if needed */ ++#define GENET_MAX_MQ_CNT 4 ++ + /* total number of Buffer Descriptors, same for Rx/Tx */ + #define TOTAL_DESC 256 + +@@ -513,7 +516,6 @@ struct bcmgenet_tx_ring { + unsigned long packets; + unsigned long bytes; + unsigned int index; /* ring index */ +- unsigned int queue; /* queue index */ + struct enet_cb *cbs; /* tx ring buffer control block*/ + unsigned int size; /* size of each tx ring */ + unsigned int clean_ptr; /* Tx ring clean pointer */ +@@ -523,8 +525,6 @@ struct bcmgenet_tx_ring { + unsigned int prod_index; /* Tx ring producer index SW copy */ + unsigned int cb_ptr; /* Tx ring initial CB ptr */ + unsigned int end_ptr; /* Tx ring end CB ptr */ +- void (*int_enable)(struct bcmgenet_tx_ring *); +- void (*int_disable)(struct bcmgenet_tx_ring *); + struct bcmgenet_priv *priv; + }; + +@@ -553,8 +553,6 @@ struct bcmgenet_rx_ring { + struct bcmgenet_net_dim dim; + u32 rx_max_coalesced_frames; + u32 rx_coalesce_usecs; +- void (*int_enable)(struct bcmgenet_rx_ring *); +- void (*int_disable)(struct bcmgenet_rx_ring *); + struct bcmgenet_priv *priv; + }; + +@@ -583,7 +581,7 @@ struct bcmgenet_priv { + struct enet_cb *tx_cbs; + unsigned int num_tx_bds; + +- struct bcmgenet_tx_ring tx_rings[DESC_INDEX + 1]; ++ struct bcmgenet_tx_ring tx_rings[GENET_MAX_MQ_CNT + 1]; + + /* receive variables */ + void __iomem *rx_bds; +@@ -593,7 +591,7 @@ struct bcmgenet_priv { + struct bcmgenet_rxnfc_rule rxnfc_rules[MAX_NUM_OF_FS_RULES]; + struct list_head rxnfc_list; + +- struct bcmgenet_rx_ring rx_rings[DESC_INDEX + 1]; ++ struct bcmgenet_rx_ring rx_rings[GENET_MAX_MQ_CNT + 1]; + + /* other misc variables */ + struct bcmgenet_hw_params *hw_params; +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +index 2033fb9d893e0..98358b71cef5c 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +@@ -2,7 +2,7 @@ + /* + * Broadcom GENET (Gigabit Ethernet) Wake-on-LAN support + * +- * Copyright (c) 2014-2024 Broadcom ++ * Copyright (c) 2014-2025 Broadcom + */ + + #define pr_fmt(fmt) "bcmgenet_wol: " fmt +@@ -180,7 +180,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv, + if (priv->wolopts & WAKE_FILTER) { + list_for_each_entry(rule, &priv->rxnfc_list, list) + if (rule->fs.ring_cookie == RX_CLS_FLOW_WAKE) +- hfb_enable |= (1 << rule->fs.location); ++ hfb_enable |= (1 << (rule->fs.location + 1)); + reg = (hfb_ctrl_reg & ~RBUF_HFB_EN) | RBUF_ACPI_EN; + bcmgenet_hfb_reg_writel(priv, reg, HFB_CTRL); + } +-- +2.53.0 + diff --git a/queue-6.6/net-bcmgenet-remove-custom-ndo_poll_controller.patch b/queue-6.6/net-bcmgenet-remove-custom-ndo_poll_controller.patch new file mode 100644 index 0000000000..151e76b564 --- /dev/null +++ b/queue-6.6/net-bcmgenet-remove-custom-ndo_poll_controller.patch @@ -0,0 +1,64 @@ +From ba39ad4b6858891c78fe4ec21425cf304af7680d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Oct 2023 11:17:47 -0700 +Subject: net: bcmgenet: Remove custom ndo_poll_controller() + +From: Florian Fainelli + +[ Upstream commit 19537e125cc7cf2da43a606f5bcebbe0c9aea4cc ] + +The driver gained a .ndo_poll_controller() at a time where the TX +cleaning process was always done from NAPI which makes this unnecessary. +See commit ac3d9dd034e5 ("netpoll: make ndo_poll_controller() optional") +for more background. + +Signed-off-by: Florian Fainelli +Reviewed-by: Eric Dumazet +Signed-off-by: David S. Miller +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 20 ------------------- + 1 file changed, 20 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index cdbe47c7ba280..6ba26feed4588 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -3255,23 +3255,6 @@ static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) + return IRQ_HANDLED; + } + +-#ifdef CONFIG_NET_POLL_CONTROLLER +-static void bcmgenet_poll_controller(struct net_device *dev) +-{ +- struct bcmgenet_priv *priv = netdev_priv(dev); +- +- /* Invoke the main RX/TX interrupt handler */ +- disable_irq(priv->irq0); +- bcmgenet_isr0(priv->irq0, priv); +- enable_irq(priv->irq0); +- +- /* And the interrupt handler for RX/TX priority queues */ +- disable_irq(priv->irq1); +- bcmgenet_isr1(priv->irq1, priv); +- enable_irq(priv->irq1); +-} +-#endif +- + static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) + { + u32 reg; +@@ -3741,9 +3724,6 @@ static const struct net_device_ops bcmgenet_netdev_ops = { + .ndo_set_mac_address = bcmgenet_set_mac_addr, + .ndo_eth_ioctl = phy_do_ioctl_running, + .ndo_set_features = bcmgenet_set_features, +-#ifdef CONFIG_NET_POLL_CONTROLLER +- .ndo_poll_controller = bcmgenet_poll_controller, +-#endif + .ndo_get_stats = bcmgenet_get_stats, + .ndo_change_carrier = bcmgenet_change_carrier, + }; +-- +2.53.0 + diff --git a/queue-6.6/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch b/queue-6.6/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch new file mode 100644 index 0000000000..cad5999330 --- /dev/null +++ b/queue-6.6/net-bcmgenet-support-reclaiming-unsent-tx-packets.patch @@ -0,0 +1,92 @@ +From 4b6dfabff5fdb2b9cd6b72b62c02f3ad37a42aed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 6 Mar 2025 11:26:39 -0800 +Subject: net: bcmgenet: support reclaiming unsent Tx packets + +From: Doug Berger + +[ Upstream commit f1bacae8b655163dcbc3c54b9e714ef1a8986d7b ] + +When disabling the transmitter any outstanding packets can now +be reclaimed by bcmgenet_tx_reclaim_all() rather than by the +bcmgenet_fini_dma() function. + +Signed-off-by: Doug Berger +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250306192643.2383632-12-opendmb@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 37 +++++++++++++++---- + 1 file changed, 30 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index ed66ae393100e..de15243c52a62 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1885,12 +1885,39 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + } + + static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, +- struct bcmgenet_tx_ring *ring) ++ struct bcmgenet_tx_ring *ring, ++ bool all) + { +- unsigned int released; ++ struct bcmgenet_priv *priv = netdev_priv(dev); ++ struct device *kdev = &priv->pdev->dev; ++ unsigned int released, drop, wr_ptr; ++ struct enet_cb *cb_ptr; ++ struct sk_buff *skb; + + spin_lock_bh(&ring->lock); + released = __bcmgenet_tx_reclaim(dev, ring); ++ if (all) { ++ skb = NULL; ++ drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK; ++ released += drop; ++ ring->prod_index = ring->c_index & DMA_C_INDEX_MASK; ++ while (drop--) { ++ cb_ptr = bcmgenet_put_txcb(priv, ring); ++ skb = cb_ptr->skb; ++ bcmgenet_free_tx_cb(kdev, cb_ptr); ++ if (skb && cb_ptr == GENET_CB(skb)->first_cb) { ++ dev_consume_skb_any(skb); ++ skb = NULL; ++ } ++ } ++ if (skb) ++ dev_consume_skb_any(skb); ++ bcmgenet_tdma_ring_writel(priv, ring->index, ++ ring->prod_index, TDMA_PROD_INDEX); ++ wr_ptr = ring->write_ptr * WORDS_PER_BD(priv); ++ bcmgenet_tdma_ring_writel(priv, ring->index, wr_ptr, ++ TDMA_WRITE_PTR); ++ } + spin_unlock_bh(&ring->lock); + + return released; +@@ -1927,7 +1954,7 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev) + int i = 0; + + do { +- bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++]); ++ bcmgenet_tx_reclaim(dev, &priv->tx_rings[i++], true); + } while (i <= priv->hw_params->tx_queues && netif_is_multiqueue(dev)); + } + +@@ -2924,10 +2951,6 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) + bcmgenet_fini_rx_napi(priv); + bcmgenet_fini_tx_napi(priv); + +- for (i = 0; i < priv->num_tx_bds; i++) +- dev_kfree_skb(bcmgenet_free_tx_cb(&priv->pdev->dev, +- priv->tx_cbs + i)); +- + for (i = 0; i <= priv->hw_params->tx_queues; i++) { + txq = netdev_get_tx_queue(priv->dev, i); + netdev_tx_reset_queue(txq); +-- +2.53.0 + diff --git a/queue-6.6/net-bcmgenet-switch-to-use-64bit-statistics.patch b/queue-6.6/net-bcmgenet-switch-to-use-64bit-statistics.patch new file mode 100644 index 0000000000..f7c940540d --- /dev/null +++ b/queue-6.6/net-bcmgenet-switch-to-use-64bit-statistics.patch @@ -0,0 +1,527 @@ +From af5b07a8b8e090c3f9d2a529bdce5c27b7a86c81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 May 2025 12:32:55 +0100 +Subject: net: bcmgenet: switch to use 64bit statistics + +From: Zak Kemble + +[ Upstream commit 59aa6e3072aa7e51e9040e8c342d0c0825c5f48f ] + +Update the driver to use ndo_get_stats64, rtnl_link_stats64 and +u64_stats_t counters for statistics. + +Signed-off-by: Zak Kemble +Tested-by: Florian Fainelli +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20250519113257.1031-2-zakkemble@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 5393b2b5bee2 ("net: bcmgenet: fix racing timeout handler") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 246 ++++++++++++------ + .../net/ethernet/broadcom/genet/bcmgenet.h | 29 ++- + 2 files changed, 187 insertions(+), 88 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index de15243c52a62..a5166582e0ab7 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -950,12 +950,13 @@ static int bcmgenet_set_pauseparam(struct net_device *dev, + + /* standard ethtool support functions. */ + enum bcmgenet_stat_type { +- BCMGENET_STAT_NETDEV = -1, ++ BCMGENET_STAT_RTNL = -1, + BCMGENET_STAT_MIB_RX, + BCMGENET_STAT_MIB_TX, + BCMGENET_STAT_RUNT, + BCMGENET_STAT_MISC, + BCMGENET_STAT_SOFT, ++ BCMGENET_STAT_SOFT64, + }; + + struct bcmgenet_stats { +@@ -965,13 +966,15 @@ struct bcmgenet_stats { + enum bcmgenet_stat_type type; + /* reg offset from UMAC base for misc counters */ + u16 reg_offset; ++ /* sync for u64 stats counters */ ++ int syncp_offset; + }; + +-#define STAT_NETDEV(m) { \ ++#define STAT_RTNL(m) { \ + .stat_string = __stringify(m), \ +- .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \ +- .stat_offset = offsetof(struct net_device_stats, m), \ +- .type = BCMGENET_STAT_NETDEV, \ ++ .stat_sizeof = sizeof(((struct rtnl_link_stats64 *)0)->m), \ ++ .stat_offset = offsetof(struct rtnl_link_stats64, m), \ ++ .type = BCMGENET_STAT_RTNL, \ + } + + #define STAT_GENET_MIB(str, m, _type) { \ +@@ -981,6 +984,14 @@ struct bcmgenet_stats { + .type = _type, \ + } + ++#define STAT_GENET_SOFT_MIB64(str, s, m) { \ ++ .stat_string = str, \ ++ .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->s.m), \ ++ .stat_offset = offsetof(struct bcmgenet_priv, s.m), \ ++ .type = BCMGENET_STAT_SOFT64, \ ++ .syncp_offset = offsetof(struct bcmgenet_priv, s.syncp), \ ++} ++ + #define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX) + #define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX) + #define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT) +@@ -995,18 +1006,18 @@ struct bcmgenet_stats { + } + + #define STAT_GENET_Q(num) \ +- STAT_GENET_SOFT_MIB("txq" __stringify(num) "_packets", \ +- tx_rings[num].packets), \ +- STAT_GENET_SOFT_MIB("txq" __stringify(num) "_bytes", \ +- tx_rings[num].bytes), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_bytes", \ +- rx_rings[num].bytes), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_packets", \ +- rx_rings[num].packets), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_errors", \ +- rx_rings[num].errors), \ +- STAT_GENET_SOFT_MIB("rxq" __stringify(num) "_dropped", \ +- rx_rings[num].dropped) ++ STAT_GENET_SOFT_MIB64("txq" __stringify(num) "_packets", \ ++ tx_rings[num].stats64, packets), \ ++ STAT_GENET_SOFT_MIB64("txq" __stringify(num) "_bytes", \ ++ tx_rings[num].stats64, bytes), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_bytes", \ ++ rx_rings[num].stats64, bytes), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_packets", \ ++ rx_rings[num].stats64, packets), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_errors", \ ++ rx_rings[num].stats64, errors), \ ++ STAT_GENET_SOFT_MIB64("rxq" __stringify(num) "_dropped", \ ++ rx_rings[num].stats64, dropped) + + /* There is a 0xC gap between the end of RX and beginning of TX stats and then + * between the end of TX stats and the beginning of the RX RUNT +@@ -1018,15 +1029,15 @@ struct bcmgenet_stats { + */ + static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + /* general stats */ +- STAT_NETDEV(rx_packets), +- STAT_NETDEV(tx_packets), +- STAT_NETDEV(rx_bytes), +- STAT_NETDEV(tx_bytes), +- STAT_NETDEV(rx_errors), +- STAT_NETDEV(tx_errors), +- STAT_NETDEV(rx_dropped), +- STAT_NETDEV(tx_dropped), +- STAT_NETDEV(multicast), ++ STAT_RTNL(rx_packets), ++ STAT_RTNL(tx_packets), ++ STAT_RTNL(rx_bytes), ++ STAT_RTNL(tx_bytes), ++ STAT_RTNL(rx_errors), ++ STAT_RTNL(tx_errors), ++ STAT_RTNL(rx_dropped), ++ STAT_RTNL(tx_dropped), ++ STAT_RTNL(multicast), + /* UniMAC RSV counters */ + STAT_GENET_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64), + STAT_GENET_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127), +@@ -1114,6 +1125,20 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + + #define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) + ++#define BCMGENET_STATS64_ADD(stats, m, v) \ ++ do { \ ++ u64_stats_update_begin(&stats->syncp); \ ++ u64_stats_add(&stats->m, v); \ ++ u64_stats_update_end(&stats->syncp); \ ++ } while (0) ++ ++#define BCMGENET_STATS64_INC(stats, m) \ ++ do { \ ++ u64_stats_update_begin(&stats->syncp); \ ++ u64_stats_inc(&stats->m); \ ++ u64_stats_update_end(&stats->syncp); \ ++ } while (0) ++ + static void bcmgenet_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) + { +@@ -1197,8 +1222,9 @@ static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) + + s = &bcmgenet_gstrings_stats[i]; + switch (s->type) { +- case BCMGENET_STAT_NETDEV: ++ case BCMGENET_STAT_RTNL: + case BCMGENET_STAT_SOFT: ++ case BCMGENET_STAT_SOFT64: + continue; + case BCMGENET_STAT_RUNT: + offset += BCMGENET_STAT_OFFSET; +@@ -1236,28 +1262,40 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev, + u64 *data) + { + struct bcmgenet_priv *priv = netdev_priv(dev); ++ struct rtnl_link_stats64 stats64; ++ struct u64_stats_sync *syncp; ++ unsigned int start; + int i; + + if (netif_running(dev)) + bcmgenet_update_mib_counters(priv); + +- dev->netdev_ops->ndo_get_stats(dev); ++ dev_get_stats(dev, &stats64); + + for (i = 0; i < BCMGENET_STATS_LEN; i++) { + const struct bcmgenet_stats *s; + char *p; + + s = &bcmgenet_gstrings_stats[i]; +- if (s->type == BCMGENET_STAT_NETDEV) +- p = (char *)&dev->stats; +- else +- p = (char *)priv; +- p += s->stat_offset; +- if (sizeof(unsigned long) != sizeof(u32) && +- s->stat_sizeof == sizeof(unsigned long)) +- data[i] = *(unsigned long *)p; +- else +- data[i] = *(u32 *)p; ++ p = (char *)priv; ++ ++ if (s->type == BCMGENET_STAT_SOFT64) { ++ syncp = (struct u64_stats_sync *)(p + s->syncp_offset); ++ do { ++ start = u64_stats_fetch_begin(syncp); ++ data[i] = u64_stats_read((u64_stats_t *)(p + s->stat_offset)); ++ } while (u64_stats_fetch_retry(syncp, start)); ++ } else { ++ if (s->type == BCMGENET_STAT_RTNL) ++ p = (char *)&stats64; ++ ++ p += s->stat_offset; ++ if (sizeof(unsigned long) != sizeof(u32) && ++ s->stat_sizeof == sizeof(unsigned long)) ++ data[i] = *(unsigned long *)p; ++ else ++ data[i] = *(u32 *)p; ++ } + } + } + +@@ -1835,6 +1873,7 @@ static struct sk_buff *bcmgenet_free_rx_cb(struct device *dev, + static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + struct bcmgenet_tx_ring *ring) + { ++ struct bcmgenet_tx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned int txbds_processed = 0; + unsigned int bytes_compl = 0; +@@ -1875,8 +1914,10 @@ static unsigned int __bcmgenet_tx_reclaim(struct net_device *dev, + ring->free_bds += txbds_processed; + ring->c_index = c_index; + +- ring->packets += pkts_compl; +- ring->bytes += bytes_compl; ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_add(&stats->packets, pkts_compl); ++ u64_stats_add(&stats->bytes, bytes_compl); ++ u64_stats_update_end(&stats->syncp); + + netdev_tx_completed_queue(netdev_get_tx_queue(dev, ring->index), + pkts_compl, bytes_compl); +@@ -1962,8 +2003,10 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev) + * the transmit checksum offsets in the descriptors + */ + static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, +- struct sk_buff *skb) ++ struct sk_buff *skb, ++ struct bcmgenet_tx_ring *ring) + { ++ struct bcmgenet_tx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = netdev_priv(dev); + struct status_64 *status = NULL; + struct sk_buff *new_skb; +@@ -1980,7 +2023,7 @@ static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev, + if (!new_skb) { + dev_kfree_skb_any(skb); + priv->mib.tx_realloc_tsb_failed++; +- dev->stats.tx_dropped++; ++ BCMGENET_STATS64_INC(stats, dropped); + return NULL; + } + dev_consume_skb_any(skb); +@@ -2068,7 +2111,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) + GENET_CB(skb)->bytes_sent = skb->len; + + /* add the Transmit Status Block */ +- skb = bcmgenet_add_tsb(dev, skb); ++ skb = bcmgenet_add_tsb(dev, skb, ring); + if (!skb) { + ret = NETDEV_TX_OK; + goto out; +@@ -2210,6 +2253,7 @@ static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv, + static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + unsigned int budget) + { ++ struct bcmgenet_rx_stats64 *stats = &ring->stats64; + struct bcmgenet_priv *priv = ring->priv; + struct net_device *dev = priv->dev; + struct enet_cb *cb; +@@ -2232,7 +2276,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + DMA_P_INDEX_DISCARD_CNT_MASK; + if (discards > ring->old_discards) { + discards = discards - ring->old_discards; +- ring->errors += discards; ++ BCMGENET_STATS64_ADD(stats, errors, discards); + ring->old_discards += discards; + + /* Clear HW register when we reach 75% of maximum 0xFFFF */ +@@ -2258,7 +2302,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + skb = bcmgenet_rx_refill(priv, cb); + + if (unlikely(!skb)) { +- ring->dropped++; ++ BCMGENET_STATS64_INC(stats, dropped); + goto next; + } + +@@ -2285,8 +2329,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + + if (unlikely(len > RX_BUF_LENGTH)) { + netif_err(priv, rx_status, dev, "oversized packet\n"); +- dev->stats.rx_length_errors++; +- dev->stats.rx_errors++; ++ BCMGENET_STATS64_INC(stats, length_errors); + dev_kfree_skb_any(skb); + goto next; + } +@@ -2294,7 +2337,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { + netif_err(priv, rx_status, dev, + "dropping fragmented packet!\n"); +- ring->errors++; ++ BCMGENET_STATS64_INC(stats, errors); + dev_kfree_skb_any(skb); + goto next; + } +@@ -2307,15 +2350,22 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + DMA_RX_RXER))) { + netif_err(priv, rx_status, dev, "dma_flag=0x%x\n", + (unsigned int)dma_flag); ++ u64_stats_update_begin(&stats->syncp); + if (dma_flag & DMA_RX_CRC_ERROR) +- dev->stats.rx_crc_errors++; ++ u64_stats_inc(&stats->crc_errors); + if (dma_flag & DMA_RX_OV) +- dev->stats.rx_over_errors++; ++ u64_stats_inc(&stats->over_errors); + if (dma_flag & DMA_RX_NO) +- dev->stats.rx_frame_errors++; ++ u64_stats_inc(&stats->frame_errors); + if (dma_flag & DMA_RX_LG) +- dev->stats.rx_length_errors++; +- dev->stats.rx_errors++; ++ u64_stats_inc(&stats->length_errors); ++ if ((dma_flag & (DMA_RX_CRC_ERROR | ++ DMA_RX_OV | ++ DMA_RX_NO | ++ DMA_RX_LG | ++ DMA_RX_RXER)) == DMA_RX_RXER) ++ u64_stats_inc(&stats->errors); ++ u64_stats_update_end(&stats->syncp); + dev_kfree_skb_any(skb); + goto next; + } /* error packet */ +@@ -2335,10 +2385,13 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, + + /*Finish setting up the received SKB and send it to the kernel*/ + skb->protocol = eth_type_trans(skb, priv->dev); +- ring->packets++; +- ring->bytes += len; ++ ++ u64_stats_update_begin(&stats->syncp); ++ u64_stats_inc(&stats->packets); ++ u64_stats_add(&stats->bytes, len); + if (dma_flag & DMA_RX_MULT) +- dev->stats.multicast++; ++ u64_stats_inc(&stats->multicast); ++ u64_stats_update_end(&stats->syncp); + + /* Notify kernel */ + napi_gro_receive(&ring->napi, skb); +@@ -3439,7 +3492,7 @@ static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + + netif_trans_update(dev); + +- dev->stats.tx_errors++; ++ BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors); + + netif_tx_wake_all_queues(dev); + } +@@ -3528,39 +3581,68 @@ static int bcmgenet_set_mac_addr(struct net_device *dev, void *p) + return 0; + } + +-static struct net_device_stats *bcmgenet_get_stats(struct net_device *dev) ++static void bcmgenet_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- unsigned long tx_bytes = 0, tx_packets = 0; +- unsigned long rx_bytes = 0, rx_packets = 0; +- unsigned long rx_errors = 0, rx_dropped = 0; +- struct bcmgenet_tx_ring *tx_ring; +- struct bcmgenet_rx_ring *rx_ring; ++ struct bcmgenet_tx_stats64 *tx_stats; ++ struct bcmgenet_rx_stats64 *rx_stats; ++ u64 rx_length_errors, rx_over_errors; ++ u64 rx_crc_errors, rx_frame_errors; ++ u64 tx_errors, tx_dropped; ++ u64 rx_errors, rx_dropped; ++ u64 tx_bytes, tx_packets; ++ u64 rx_bytes, rx_packets; ++ unsigned int start; + unsigned int q; ++ u64 multicast; + + for (q = 0; q <= priv->hw_params->tx_queues; q++) { +- tx_ring = &priv->tx_rings[q]; +- tx_bytes += tx_ring->bytes; +- tx_packets += tx_ring->packets; ++ tx_stats = &priv->tx_rings[q].stats64; ++ do { ++ start = u64_stats_fetch_begin(&tx_stats->syncp); ++ tx_bytes = u64_stats_read(&tx_stats->bytes); ++ tx_packets = u64_stats_read(&tx_stats->packets); ++ tx_errors = u64_stats_read(&tx_stats->errors); ++ tx_dropped = u64_stats_read(&tx_stats->dropped); ++ } while (u64_stats_fetch_retry(&tx_stats->syncp, start)); ++ ++ stats->tx_bytes += tx_bytes; ++ stats->tx_packets += tx_packets; ++ stats->tx_errors += tx_errors; ++ stats->tx_dropped += tx_dropped; + } + + for (q = 0; q <= priv->hw_params->rx_queues; q++) { +- rx_ring = &priv->rx_rings[q]; +- +- rx_bytes += rx_ring->bytes; +- rx_packets += rx_ring->packets; +- rx_errors += rx_ring->errors; +- rx_dropped += rx_ring->dropped; ++ rx_stats = &priv->rx_rings[q].stats64; ++ do { ++ start = u64_stats_fetch_begin(&rx_stats->syncp); ++ rx_bytes = u64_stats_read(&rx_stats->bytes); ++ rx_packets = u64_stats_read(&rx_stats->packets); ++ rx_errors = u64_stats_read(&rx_stats->errors); ++ rx_dropped = u64_stats_read(&rx_stats->dropped); ++ rx_length_errors = u64_stats_read(&rx_stats->length_errors); ++ rx_over_errors = u64_stats_read(&rx_stats->over_errors); ++ rx_crc_errors = u64_stats_read(&rx_stats->crc_errors); ++ rx_frame_errors = u64_stats_read(&rx_stats->frame_errors); ++ multicast = u64_stats_read(&rx_stats->multicast); ++ } while (u64_stats_fetch_retry(&rx_stats->syncp, start)); ++ ++ rx_errors += rx_length_errors; ++ rx_errors += rx_crc_errors; ++ rx_errors += rx_frame_errors; ++ ++ stats->rx_bytes += rx_bytes; ++ stats->rx_packets += rx_packets; ++ stats->rx_errors += rx_errors; ++ stats->rx_dropped += rx_dropped; ++ stats->rx_missed_errors += rx_errors; ++ stats->rx_length_errors += rx_length_errors; ++ stats->rx_over_errors += rx_over_errors; ++ stats->rx_crc_errors += rx_crc_errors; ++ stats->rx_frame_errors += rx_frame_errors; ++ stats->multicast += multicast; + } +- +- dev->stats.tx_bytes = tx_bytes; +- dev->stats.tx_packets = tx_packets; +- dev->stats.rx_bytes = rx_bytes; +- dev->stats.rx_packets = rx_packets; +- dev->stats.rx_errors = rx_errors; +- dev->stats.rx_missed_errors = rx_errors; +- dev->stats.rx_dropped = rx_dropped; +- return &dev->stats; + } + + static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier) +@@ -3588,7 +3670,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = { + .ndo_set_mac_address = bcmgenet_set_mac_addr, + .ndo_eth_ioctl = phy_do_ioctl_running, + .ndo_set_features = bcmgenet_set_features, +- .ndo_get_stats = bcmgenet_get_stats, ++ .ndo_get_stats64 = bcmgenet_get_stats64, + .ndo_change_carrier = bcmgenet_change_carrier, + }; + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +index f3a1139cb7108..94957dfa55b6f 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -155,6 +155,27 @@ struct bcmgenet_mib_counters { + u32 tx_realloc_tsb_failed; + }; + ++struct bcmgenet_tx_stats64 { ++ struct u64_stats_sync syncp; ++ u64_stats_t packets; ++ u64_stats_t bytes; ++ u64_stats_t errors; ++ u64_stats_t dropped; ++}; ++ ++struct bcmgenet_rx_stats64 { ++ struct u64_stats_sync syncp; ++ u64_stats_t bytes; ++ u64_stats_t packets; ++ u64_stats_t errors; ++ u64_stats_t dropped; ++ u64_stats_t multicast; ++ u64_stats_t length_errors; ++ u64_stats_t over_errors; ++ u64_stats_t crc_errors; ++ u64_stats_t frame_errors; ++}; ++ + #define UMAC_MIB_START 0x400 + + #define UMAC_MDIO_CMD 0x614 +@@ -513,8 +534,7 @@ struct bcmgenet_skb_cb { + struct bcmgenet_tx_ring { + spinlock_t lock; /* ring lock */ + struct napi_struct napi; /* NAPI per tx queue */ +- unsigned long packets; +- unsigned long bytes; ++ struct bcmgenet_tx_stats64 stats64; + unsigned int index; /* ring index */ + struct enet_cb *cbs; /* tx ring buffer control block*/ + unsigned int size; /* size of each tx ring */ +@@ -538,10 +558,7 @@ struct bcmgenet_net_dim { + + struct bcmgenet_rx_ring { + struct napi_struct napi; /* Rx NAPI struct */ +- unsigned long bytes; +- unsigned long packets; +- unsigned long errors; +- unsigned long dropped; ++ struct bcmgenet_rx_stats64 stats64; + unsigned int index; /* Rx ring index */ + struct enet_cb *cbs; /* Rx ring buffer control block */ + unsigned int size; /* Rx ring size */ +-- +2.53.0 + diff --git a/queue-6.6/net-bonding-add-broadcast_neighbor-option-for-802.3a.patch b/queue-6.6/net-bonding-add-broadcast_neighbor-option-for-802.3a.patch new file mode 100644 index 0000000000..5ccd5cc4a0 --- /dev/null +++ b/queue-6.6/net-bonding-add-broadcast_neighbor-option-for-802.3a.patch @@ -0,0 +1,342 @@ +From 2f2f7575fe0244466c7b02265c3b429d65e8b6e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Jun 2025 21:49:28 +0800 +Subject: net: bonding: add broadcast_neighbor option for 802.3ad + +From: Tonghao Zhang + +[ Upstream commit ce7a381697cb3958ffe0b45e5028ac69444e9288 ] + +Stacking technology is a type of technology used to expand ports on +Ethernet switches. It is widely used as a common access method in +large-scale Internet data center architectures. Years of practice +have proved that stacking technology has advantages and disadvantages +in high-reliability network architecture scenarios. For instance, +in stacking networking arch, conventional switch system upgrades +require multiple stacked devices to restart at the same time. +Therefore, it is inevitable that the business will be interrupted +for a while. It is for this reason that "no-stacking" in data centers +has become a trend. Additionally, when the stacking link connecting +the switches fails or is abnormal, the stack will split. Although it is +not common, it still happens in actual operation. The problem is that +after the split, it is equivalent to two switches with the same +configuration appearing in the network, causing network configuration +conflicts and ultimately interrupting the services carried by the +stacking system. + +To improve network stability, "non-stacking" solutions have been +increasingly adopted, particularly by public cloud providers and +tech companies like Alibaba, Tencent, and Didi. "non-stacking" is +a method of mimicing switch stacking that convinces a LACP peer, +bonding in this case, connected to a set of "non-stacked" switches +that all of its ports are connected to a single switch +(i.e., LACP aggregator), as if those switches were stacked. This +enables the LACP peer's ports to aggregate together, and requires +(a) special switch configuration, described in the linked article, +and (b) modifications to the bonding 802.3ad (LACP) mode to send +all ARP/ND packets across all ports of the active aggregator. + +Note that, with multiple aggregators, the current broadcast mode +logic will send only packets to the selected aggregator(s). + + +-----------+ +-----------+ + | switch1 | | switch2 | + +-----------+ +-----------+ + ^ ^ + | | + +-----------------+ + | bond4 lacp | + +-----------------+ + | | + | NIC1 | NIC2 + +-----------------+ + | server | + +-----------------+ + +- https://www.ruijie.com/fr-fr/support/tech-gallery/de-stack-data-center-network-architecture/ + +Cc: Jay Vosburgh +Cc: "David S. Miller" +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: Simon Horman +Cc: Jonathan Corbet +Cc: Andrew Lunn +Cc: Steven Rostedt +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Nikolay Aleksandrov +Signed-off-by: Tonghao Zhang +Signed-off-by: Zengbing Tu +Link: https://patch.msgid.link/84d0a044514157bb856a10b6d03a1028c4883561.1751031306.git.tonghao@bamaicloud.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + Documentation/networking/bonding.rst | 6 +++ + drivers/net/bonding/bond_main.c | 66 +++++++++++++++++++++++++--- + drivers/net/bonding/bond_options.c | 42 ++++++++++++++++++ + include/net/bond_options.h | 1 + + include/net/bonding.h | 3 ++ + 5 files changed, 112 insertions(+), 6 deletions(-) + +diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst +index e774b48de9f51..1a9439488c531 100644 +--- a/Documentation/networking/bonding.rst ++++ b/Documentation/networking/bonding.rst +@@ -562,6 +562,12 @@ lacp_rate + + The default is slow. + ++broadcast_neighbor ++ ++ Option specifying whether to broadcast ARP/ND packets to all ++ active slaves. This option has no effect in modes other than ++ 802.3ad mode. The default is off (0). ++ + max_bonds + + Specifies the number of bonding devices to create for this +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 8d481a6495e89..70718bf6e716c 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -211,6 +211,8 @@ atomic_t netpoll_block_tx = ATOMIC_INIT(0); + + unsigned int bond_net_id __read_mostly; + ++DEFINE_STATIC_KEY_FALSE(bond_bcast_neigh_enabled); ++ + static const struct flow_dissector_key flow_keys_bonding_keys[] = { + { + .key_id = FLOW_DISSECTOR_KEY_CONTROL, +@@ -4397,6 +4399,9 @@ static int bond_open(struct net_device *bond_dev) + + bond_for_each_slave(bond, slave, iter) + dev_mc_add(slave->dev, lacpdu_mcast_addr); ++ ++ if (bond->params.broadcast_neighbor) ++ static_branch_inc(&bond_bcast_neigh_enabled); + } + + if (bond_mode_can_use_xmit_hash(bond)) +@@ -4420,6 +4425,10 @@ static int bond_close(struct net_device *bond_dev) + if (bond_is_lb(bond)) + bond_alb_deinitialize(bond); + ++ if (BOND_MODE(bond) == BOND_MODE_8023AD && ++ bond->params.broadcast_neighbor) ++ static_branch_dec(&bond_bcast_neigh_enabled); ++ + if (bond_uses_primary(bond)) { + rcu_read_lock(); + slave = rcu_dereference(bond->curr_active_slave); +@@ -5256,6 +5265,37 @@ static struct slave *bond_xdp_xmit_3ad_xor_slave_get(struct bonding *bond, + return slaves->arr[hash % count]; + } + ++static bool bond_should_broadcast_neighbor(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct bonding *bond = netdev_priv(dev); ++ struct { ++ struct ipv6hdr ip6; ++ struct icmp6hdr icmp6; ++ } *combined, _combined; ++ ++ if (!static_branch_unlikely(&bond_bcast_neigh_enabled)) ++ return false; ++ ++ if (!bond->params.broadcast_neighbor) ++ return false; ++ ++ if (skb->protocol == htons(ETH_P_ARP)) ++ return true; ++ ++ if (skb->protocol == htons(ETH_P_IPV6)) { ++ combined = skb_header_pointer(skb, skb_mac_header_len(skb), ++ sizeof(_combined), ++ &_combined); ++ if (combined && combined->ip6.nexthdr == NEXTHDR_ICMP && ++ (combined->icmp6.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION || ++ combined->icmp6.icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT)) ++ return true; ++ } ++ ++ return false; ++} ++ + /* Use this Xmit function for 3AD as well as XOR modes. The current + * usable slave array is formed in the control path. The xmit function + * just calculates hash and sends the packet out. +@@ -5275,17 +5315,27 @@ static netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb, + return bond_tx_drop(dev, skb); + } + +-/* in broadcast mode, we send everything to all usable interfaces. */ ++/* in broadcast mode, we send everything to all or usable slave interfaces. ++ * under rcu_read_lock when this function is called. ++ */ + static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, +- struct net_device *bond_dev) ++ struct net_device *bond_dev, ++ bool all_slaves) + { + struct bonding *bond = netdev_priv(bond_dev); +- struct slave *slave = NULL; +- struct list_head *iter; ++ struct bond_up_slave *slaves; + bool xmit_suc = false; + bool skb_used = false; ++ int slaves_count, i; + +- bond_for_each_slave_rcu(bond, slave, iter) { ++ if (all_slaves) ++ slaves = rcu_dereference(bond->all_slaves); ++ else ++ slaves = rcu_dereference(bond->usable_slaves); ++ ++ slaves_count = slaves ? READ_ONCE(slaves->count) : 0; ++ for (i = 0; i < slaves_count; i++) { ++ struct slave *slave = slaves->arr[i]; + struct sk_buff *skb2; + + if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)) +@@ -5523,10 +5573,13 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev + case BOND_MODE_ACTIVEBACKUP: + return bond_xmit_activebackup(skb, dev); + case BOND_MODE_8023AD: ++ if (bond_should_broadcast_neighbor(skb, dev)) ++ return bond_xmit_broadcast(skb, dev, false); ++ fallthrough; + case BOND_MODE_XOR: + return bond_3ad_xor_xmit(skb, dev); + case BOND_MODE_BROADCAST: +- return bond_xmit_broadcast(skb, dev); ++ return bond_xmit_broadcast(skb, dev, true); + case BOND_MODE_ALB: + return bond_alb_xmit(skb, dev); + case BOND_MODE_TLB: +@@ -6426,6 +6479,7 @@ static int __init bond_check_params(struct bond_params *params) + eth_zero_addr(params->ad_actor_system); + params->ad_user_port_key = ad_user_port_key; + params->coupled_control = 1; ++ params->broadcast_neighbor = 0; + if (packets_per_slave > 0) { + params->reciprocal_packets_per_slave = + reciprocal_value(packets_per_slave); +diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c +index b823425ad7f69..fe955ba5c9685 100644 +--- a/drivers/net/bonding/bond_options.c ++++ b/drivers/net/bonding/bond_options.c +@@ -87,6 +87,8 @@ static int bond_option_missed_max_set(struct bonding *bond, + const struct bond_opt_value *newval); + static int bond_option_coupled_control_set(struct bonding *bond, + const struct bond_opt_value *newval); ++static int bond_option_broadcast_neigh_set(struct bonding *bond, ++ const struct bond_opt_value *newval); + + static const struct bond_opt_value bond_mode_tbl[] = { + { "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT}, +@@ -240,6 +242,12 @@ static const struct bond_opt_value bond_coupled_control_tbl[] = { + { NULL, -1, 0}, + }; + ++static const struct bond_opt_value bond_broadcast_neigh_tbl[] = { ++ { "off", 0, BOND_VALFLAG_DEFAULT}, ++ { "on", 1, 0}, ++ { NULL, -1, 0} ++}; ++ + static const struct bond_option bond_opts[BOND_OPT_LAST] = { + [BOND_OPT_MODE] = { + .id = BOND_OPT_MODE, +@@ -513,6 +521,14 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { + .flags = BOND_OPTFLAG_IFDOWN, + .values = bond_coupled_control_tbl, + .set = bond_option_coupled_control_set, ++ }, ++ [BOND_OPT_BROADCAST_NEIGH] = { ++ .id = BOND_OPT_BROADCAST_NEIGH, ++ .name = "broadcast_neighbor", ++ .desc = "Broadcast neighbor packets to all active slaves", ++ .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), ++ .values = bond_broadcast_neigh_tbl, ++ .set = bond_option_broadcast_neigh_set, + } + }; + +@@ -894,6 +910,13 @@ static int bond_option_mode_set(struct bonding *bond, + bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; + bond->params.mode = newval->value; + ++ /* When changing mode, the bond device is down, we may reduce ++ * the bond_bcast_neigh_enabled in bond_close() if broadcast_neighbor ++ * enabled in 8023ad mode. Therefore, only clear broadcast_neighbor ++ * to 0. ++ */ ++ bond->params.broadcast_neighbor = 0; ++ + if (bond->dev->reg_state == NETREG_REGISTERED) { + bool update = false; + +@@ -1843,3 +1866,22 @@ static int bond_option_coupled_control_set(struct bonding *bond, + bond->params.coupled_control = newval->value; + return 0; + } ++ ++static int bond_option_broadcast_neigh_set(struct bonding *bond, ++ const struct bond_opt_value *newval) ++{ ++ if (bond->params.broadcast_neighbor == newval->value) ++ return 0; ++ ++ bond->params.broadcast_neighbor = newval->value; ++ if (bond->dev->flags & IFF_UP) { ++ if (bond->params.broadcast_neighbor) ++ static_branch_inc(&bond_bcast_neigh_enabled); ++ else ++ static_branch_dec(&bond_bcast_neigh_enabled); ++ } ++ ++ netdev_dbg(bond->dev, "Setting broadcast_neighbor to %s (%llu)\n", ++ newval->string, newval->value); ++ return 0; ++} +diff --git a/include/net/bond_options.h b/include/net/bond_options.h +index 18687ccf06383..022b122a9fb61 100644 +--- a/include/net/bond_options.h ++++ b/include/net/bond_options.h +@@ -77,6 +77,7 @@ enum { + BOND_OPT_NS_TARGETS, + BOND_OPT_PRIO, + BOND_OPT_COUPLED_CONTROL, ++ BOND_OPT_BROADCAST_NEIGH, + BOND_OPT_LAST + }; + +diff --git a/include/net/bonding.h b/include/net/bonding.h +index 66940d41d4854..0d9c1eb40d12b 100644 +--- a/include/net/bonding.h ++++ b/include/net/bonding.h +@@ -115,6 +115,8 @@ static inline int is_netpoll_tx_blocked(struct net_device *dev) + #define is_netpoll_tx_blocked(dev) (0) + #endif + ++DECLARE_STATIC_KEY_FALSE(bond_bcast_neigh_enabled); ++ + struct bond_params { + int mode; + int xmit_policy; +@@ -149,6 +151,7 @@ struct bond_params { + struct in6_addr ns_targets[BOND_MAX_NS_TARGETS]; + #endif + int coupled_control; ++ int broadcast_neighbor; + + /* 2 bytes of padding : see ether_addr_equal_64bits() */ + u8 ad_actor_system[ETH_ALEN + 2]; +-- +2.53.0 + diff --git a/queue-6.6/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch b/queue-6.6/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch new file mode 100644 index 0000000000..76494690f8 --- /dev/null +++ b/queue-6.6/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch @@ -0,0 +1,66 @@ +From ac1bdb89a91d4de3795c207446e571c258419e5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 08:55:19 +0800 +Subject: net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master + +From: Jiayuan Chen + +[ Upstream commit 1921f91298d1388a0bb9db8f83800c998b649cb3 ] + +syzkaller reported a kernel panic in bond_rr_gen_slave_id() reached via +xdp_master_redirect(). Full decoded trace: + + https://syzkaller.appspot.com/bug?extid=80e046b8da2820b6ba73 + +bond_rr_gen_slave_id() dereferences bond->rr_tx_counter, a per-CPU +counter that bonding only allocates in bond_open() when the mode is +round-robin. If the bond device was never brought up, rr_tx_counter +stays NULL. + +The XDP redirect path can still reach that code on a bond that was +never opened: bpf_master_redirect_enabled_key is a global static key, +so as soon as any bond device has native XDP attached, the +XDP_TX -> xdp_master_redirect() interception is enabled for every +slave system-wide. The path xdp_master_redirect() -> +bond_xdp_get_xmit_slave() -> bond_xdp_xmit_roundrobin_slave_get() -> +bond_rr_gen_slave_id() then runs against a bond that has no +rr_tx_counter and crashes. + +Fix this in the generic xdp_master_redirect() by refusing to call into +the master's ->ndo_xdp_get_xmit_slave() when the master device is not +up. IFF_UP is only set after ->ndo_open() has successfully returned, +so this reliably excludes masters whose XDP state has not been fully +initialized. Drop the frame with XDP_ABORTED so the exception is +visible via trace_xdp_exception() rather than silently falling through. +This is not specific to bonding: any current or future master that +defers XDP state allocation to ->ndo_open() is protected. + +Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave device") +Reported-by: syzbot+80e046b8da2820b6ba73@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/698f84c6.a70a0220.2c38d7.00cc.GAE@google.com/T/ +Suggested-by: Daniel Borkmann +Acked-by: Daniel Borkmann +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260411005524.201200-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 2cd58d1d4a7aa..c24510037334c 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4354,6 +4354,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) + struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info); + + master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); ++ if (unlikely(!(master->flags & IFF_UP))) ++ return XDP_ABORTED; + slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); + if (slave && slave != xdp->rxq->dev) { + /* The target device is different from the receiving device, so +-- +2.53.0 + diff --git a/queue-6.6/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch b/queue-6.6/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch new file mode 100644 index 0000000000..fb979b84b8 --- /dev/null +++ b/queue-6.6/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch @@ -0,0 +1,44 @@ +From 482775a3b0340d855a9679539de6f624235b1313 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:37:07 +0200 +Subject: net: dsa: realtek: rtl8365mb: fix mode mask calculation + +From: Mieczyslaw Nalewaj + +[ Upstream commit 0c078021d3861966614d5e594ee03587f0c9e74d ] + +The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting +the 4-bit mask (0xF) by only (_extint % 2) bits instead of +(_extint % 2) * 4. This caused the mask to overlap with the adjacent +nibble when configuring odd-numbered external interfaces, selecting +the wrong bits entirely. + +Align the shift calculation with the existing ...MODE_OFFSET macro. + +Fixes: 4af2950c50c8 ("net: dsa: realtek-smi: add rtl8365mb subdriver for RTL8365MB-VC") +Signed-off-by: Abdulkader Alrezej +Signed-off-by: Mieczyslaw Nalewaj +Reviewed-by: Luiz Angelo Daros de Luca +Link: https://patch.msgid.link/400a6387-a444-4576-af6d-26be5410bce3@yahoo.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/realtek/rtl8365mb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index 9d59d93807825..625d1d4d17a20 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -213,7 +213,7 @@ + (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ + 0x0) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \ +- (0xF << (((_extint) % 2))) ++ (0xF << (((_extint) % 2) * 4)) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \ + (((_extint) % 2) * 4) + +-- +2.53.0 + diff --git a/queue-6.6/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch b/queue-6.6/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch new file mode 100644 index 0000000000..eed9c60ca7 --- /dev/null +++ b/queue-6.6/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch @@ -0,0 +1,71 @@ +From e0d5128dddc23b6df9599ba4be4742021028cfc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:31:01 +0800 +Subject: net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf + +From: Mashiro Chen + +[ Upstream commit bf9a38803b2626b01cc769aaf13485d8650f576f ] + +sixpack_receive_buf() does not properly skip bytes with TTY error flags. +The while loop iterates through the flags buffer but never advances the +data pointer (cp), and passes the original count (including error bytes) +to sixpack_decode(). This causes sixpack_decode() to process bytes that +should have been skipped due to TTY errors. The TTY layer does not +guarantee that cp[i] holds a meaningful value when fp[i] is set, so +passing those positions to sixpack_decode() results in KMSAN reporting +an uninit-value read. + +Fix this by processing bytes one at a time, advancing cp on each +iteration, and only passing valid (non-error) bytes to sixpack_decode(). +This matches the pattern used by slip_receive_buf() and +mkiss_receive_buf() for the same purpose. + +Reported-by: syzbot+ecdb8c9878a81eb21e54@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ecdb8c9878a81eb21e54 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Mashiro Chen +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260407173101.107352-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 3145dadf99290..1b8680923919d 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -397,7 +397,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + const u8 *fp, size_t count) + { + struct sixpack *sp; +- size_t count1; + + if (!count) + return; +@@ -407,16 +406,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + return; + + /* Read the characters out of the buffer */ +- count1 = count; +- while (count) { +- count--; ++ while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) + sp->dev->stats.rx_errors++; ++ cp++; + continue; + } ++ sixpack_decode(sp, cp, 1); ++ cp++; + } +- sixpack_decode(sp, cp, count1); + + tty_unthrottle(tty); + } +-- +2.53.0 + diff --git a/queue-6.6/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch b/queue-6.6/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch new file mode 100644 index 0000000000..8c85f7ed04 --- /dev/null +++ b/queue-6.6/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch @@ -0,0 +1,42 @@ +From 4ea3c621cfa4161b915b68db9a882652a5341517 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:13:32 +0200 +Subject: net: ipa: Fix decoding EV_PER_EE for IPA v5.0+ + +From: Luca Weiss + +[ Upstream commit 1335b903cf2e8aeaca87fd665683384c731ec941 ] + +Initially 'reg' and 'val' are assigned from HW_PARAM_2. + +But since IPA v5.0+ takes EV_PER_EE from HW_PARAM_4 (instead of +NUM_EV_PER_EE from HW_PARAM_2), we not only need to re-assign 'reg' but +also read the register value of that register into 'val' so that +reg_decode() works on the correct value. + +Fixes: f651334e1ef5 ("net: ipa: add HW_PARAM_4 GSI register") +Link: https://sashiko.dev/#/patchset/20260403-milos-ipa-v1-0-01e9e4e03d3e%40fairphone.com?part=2 +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260409-ipa-fixes-v1-2-a817c30678ac@fairphone.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ipa/gsi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c +index 9a0b1fe4a93a8..05157492f99b4 100644 +--- a/drivers/net/ipa/gsi.c ++++ b/drivers/net/ipa/gsi.c +@@ -2046,6 +2046,7 @@ static int gsi_ring_setup(struct gsi *gsi) + count = reg_decode(reg, NUM_EV_PER_EE, val); + } else { + reg = gsi_reg(gsi, HW_PARAM_4); ++ val = ioread32(gsi->virt + reg_offset(reg)); + count = reg_decode(reg, EV_PER_EE, val); + } + if (!count) { +-- +2.53.0 + diff --git a/queue-6.6/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch b/queue-6.6/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch new file mode 100644 index 0000000000..57ae914afd --- /dev/null +++ b/queue-6.6/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch @@ -0,0 +1,51 @@ +From 6c278aee6630f8f56163fc62e1f68e3b8a3d1c8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:13:31 +0200 +Subject: net: ipa: Fix programming of QTIME_TIMESTAMP_CFG + +From: Luca Weiss + +[ Upstream commit de08f9585692813bd41ee654fca0487664c4de30 ] + +The 'val' variable gets overwritten multiple times, discarding previous +values. Looking at the git log shows these should be combined with |= +instead. + +Fixes: 9265a4f0f0b4 ("net: ipa: define even more IPA register fields") +Link: https://sashiko.dev/#/patchset/20260403-milos-ipa-v1-0-01e9e4e03d3e%40fairphone.com?part=4 +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260409-ipa-fixes-v1-1-a817c30678ac@fairphone.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ipa/ipa_main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c +index da853353a5c72..f5924142021d2 100644 +--- a/drivers/net/ipa/ipa_main.c ++++ b/drivers/net/ipa/ipa_main.c +@@ -369,7 +369,7 @@ static void ipa_qtime_config(struct ipa *ipa) + { + const struct reg *reg; + u32 offset; +- u32 val; ++ u32 val = 0; + + /* Timer clock divider must be disabled when we change the rate */ + reg = ipa_reg(ipa, TIMERS_XO_CLK_DIV_CFG); +@@ -380,8 +380,8 @@ static void ipa_qtime_config(struct ipa *ipa) + val = reg_encode(reg, DPL_TIMESTAMP_LSB, DPL_TIMESTAMP_SHIFT); + val |= reg_bit(reg, DPL_TIMESTAMP_SEL); + /* Configure tag and NAT Qtime timestamp resolution as well */ +- val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); +- val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); ++ val |= reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); ++ val |= reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); + + iowrite32(val, ipa->reg_virt + reg_offset(reg)); + +-- +2.53.0 + diff --git a/queue-6.6/net-mctp-i2c-check-length-before-marking-flow-active.patch b/queue-6.6/net-mctp-i2c-check-length-before-marking-flow-active.patch new file mode 100644 index 0000000000..a6955e9a26 --- /dev/null +++ b/queue-6.6/net-mctp-i2c-check-length-before-marking-flow-active.patch @@ -0,0 +1,90 @@ +From 6369f202245d960885fe9bd7af2ba568b9f6b193 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:46:52 -0700 +Subject: net: mctp i2c: check length before marking flow active + +From: William A. Kennington III + +[ Upstream commit 4ca07b9239bd0478ae586632a2ed72be37ed8407 ] + +Currently, mctp_i2c_get_tx_flow_state() is called before the packet length +sanity check. This function marks a new flow as active in the MCTP core. + +If the sanity check fails, mctp_i2c_xmit() returns early without calling +mctp_i2c_lock_nest(). This results in a mismatched locking state: the +flow is active, but the I2C bus lock was never acquired for it. + +When the flow is later released, mctp_i2c_release_flow() will see the +active state and queue an unlock marker. The TX thread will then +decrement midev->i2c_lock_count from 0, causing it to underflow to -1. + +This underflow permanently breaks the driver's locking logic, allowing +future transmissions to occur without holding the I2C bus lock, leading +to bus collisions and potential hardware hangs. + +Move the mctp_i2c_get_tx_flow_state() call to after the length sanity +check to ensure we only transition the flow state if we are actually +going to proceed with the transmission and locking. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: William A. Kennington III +Acked-by: Jeremy Kerr +Link: https://patch.msgid.link/20260423074741.201460-1-william@wkennington.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 4 ++-- + net/sched/cls_flower.c | 4 +++- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index 1a7e7397ba75c..8f0b4eb5b6f89 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -461,8 +461,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + u8 *pecp; + int rc; + +- fs = mctp_i2c_get_tx_flow_state(midev, skb); +- + hdr = (void *)skb_mac_header(skb); + /* Sanity check that packet contents matches skb length, + * and can't exceed MCTP_I2C_BUFSZ +@@ -474,6 +472,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + return; + } + ++ fs = mctp_i2c_get_tx_flow_state(midev, skb); ++ + if (skb_tailroom(skb) >= 1) { + /* Linear case with space, we can just append the PEC */ + skb_put(skb, 1); +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index b00e491e8130d..07259b403e108 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -549,6 +549,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); ++ struct fl_flow_mask *mask; + + *last = false; + +@@ -565,11 +566,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- *last = fl_mask_put(head, f->mask); ++ mask = f->mask; + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); ++ *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch b/queue-6.6/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch new file mode 100644 index 0000000000..b3fbd510ce --- /dev/null +++ b/queue-6.6/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch @@ -0,0 +1,63 @@ +From ffcba95f8ae2e670e80170ce528d7a241b57dc37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 23:28:51 +0300 +Subject: net/mlx5e: Fix features not applied during netdev registration + +From: Gal Pressman + +[ Upstream commit 9994ad4df82d64e57135c0f0906897685f5a9e87 ] + +mlx5e_fix_features() returns early when the netdevice is not present. +This is correct during profile transitions where priv is cleared, but it +also incorrectly blocks feature fixups during register_netdev(), when +the device is also not yet present. + +It is not trivial to distinguish between both cases as we cannot use +priv to carry state, and in both cases reg_state == NETREG_REGISTERED. + +Force a netdev features update after register_netdev() completes, where +the device is present and fix_features() can actually work. + +This is not a pretty solution, as it results in an additional features +update call (register_netdevice() already calls +__netdev_update_features() internally), but it is the simplest, +cleanest, and most robust way I found to fix this issue after multiple +attempts. + +This fixes an issue on systems where CQE compression is enabled by +default, RXHASH remains enabled after registration despite the two +features being mutually exclusive. + +Fixes: ab4b01bfdaa6 ("net/mlx5e: Verify dev is present for fix features ndo") +Signed-off-by: Gal Pressman +Reviewed-by: Dragos Tatulea +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260409202852.158059-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index 71749497ec27a..97fa2095498cc 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -6093,6 +6093,14 @@ static int mlx5e_probe(struct auxiliary_device *adev, + goto err_resume; + } + ++ /* mlx5e_fix_features() returns early when the device is not present ++ * to avoid dereferencing cleared priv during profile changes. ++ * This also causes it to be a no-op during register_netdev(), where ++ * the device is not yet present. ++ * Trigger an additional features update that will actually work. ++ */ ++ mlx5e_update_features(netdev); ++ + mlx5e_dcbnl_init_app(priv); + mlx5_core_uplink_netdev_set(mdev, netdev); + mlx5e_params_print_info(mdev, &priv->channels.params); +-- +2.53.0 + diff --git a/queue-6.6/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch b/queue-6.6/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch new file mode 100644 index 0000000000..ff57e991d8 --- /dev/null +++ b/queue-6.6/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch @@ -0,0 +1,81 @@ +From f0146447b8b354f5ae19afed58c4bb4992c68809 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 23:28:52 +0300 +Subject: net/mlx5e: IPsec, fix ASO poll timeout with + read_poll_timeout_atomic() + +From: Gal Pressman + +[ Upstream commit edccdd1eb94712da97a6ce71123ec27890add754 ] + +The do-while poll loop uses jiffies for its timeout: + expires = jiffies + msecs_to_jiffies(10); + +jiffies is sampled at an arbitrary point within the current tick, so the +first partial tick contributes anywhere from a full tick down to nearly +zero real time. For small msecs_to_jiffies() results this is +significant, the effective poll window can be much shorter than the +requested 10ms, and in the worst case the loop exits after a single +iteration (e.g., when HZ=100), well before the device has delivered the +CQE. + +Replace the loop with read_poll_timeout_atomic(), which counts elapsed +time via udelay() accounting rather than jiffies, guaranteeing the full +poll window regardless of HZ. + +Additionally, read_poll_timeout_atomic() executes the poll operation one +more time after the timeout has expired, giving the CQE a final chance +to be detected. The old do-while loop could exit without a final poll if +the timeout expired during the udelay() between iterations. + +Fixes: 76e463f6508b ("net/mlx5e: Overcome slow response for first IPsec ASO WQE") +Signed-off-by: Gal Pressman +Reviewed-by: Jianbo Liu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260409202852.158059-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../mellanox/mlx5/core/en_accel/ipsec_offload.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +index fd03aa4f47b5a..004cf295eb249 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +@@ -1,6 +1,8 @@ + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB + /* Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. */ + ++#include ++ + #include "mlx5_core.h" + #include "en.h" + #include "ipsec.h" +@@ -591,7 +593,6 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, + struct mlx5_wqe_aso_ctrl_seg *ctrl; + struct mlx5e_hw_objs *res; + struct mlx5_aso_wqe *wqe; +- unsigned long expires; + u8 ds_cnt; + int ret; + +@@ -613,13 +614,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, + mlx5e_ipsec_aso_copy(ctrl, data); + + mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl); +- expires = jiffies + msecs_to_jiffies(10); +- do { +- ret = mlx5_aso_poll_cq(aso->aso, false); +- if (ret) +- /* We are in atomic context */ +- udelay(10); +- } while (ret && time_is_after_jiffies(expires)); ++ read_poll_timeout_atomic(mlx5_aso_poll_cq, ret, !ret, 10, ++ 10 * USEC_PER_MSEC, false, aso->aso, false); + if (!ret) + memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso)); + spin_unlock_bh(&aso->lock); +-- +2.53.0 + diff --git a/queue-6.6/net-netconsole-move-newline-trimming-to-function.patch b/queue-6.6/net-netconsole-move-newline-trimming-to-function.patch new file mode 100644 index 0000000000..e2400c7f05 --- /dev/null +++ b/queue-6.6/net-netconsole-move-newline-trimming-to-function.patch @@ -0,0 +1,65 @@ +From af7c8e67e7470565346c9763eb39a00d5bbe7f0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 4 Feb 2024 15:27:34 -0800 +Subject: net: netconsole: move newline trimming to function + +From: Matthew Wood + +[ Upstream commit ae001dc67907618423fd15bbab2014308c00ad0b ] + +Move newline trimming logic from `dev_name_store()` to a new function +(trim_newline()) for shared use in netconsole.c + +Signed-off-by: Matthew Wood +Signed-off-by: David S. Miller +Stable-dep-of: 92ceb7bff62c ("netconsole: propagate device name truncation in dev_name_store()") +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 9c2e71b9c0324..2045872de5328 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -272,6 +272,16 @@ static struct netconsole_target *to_target(struct config_item *item) + NULL; + } + ++/* Get rid of possible trailing newline, returning the new length */ ++static void trim_newline(char *s, size_t maxlen) ++{ ++ size_t len; ++ ++ len = strnlen(s, maxlen); ++ if (s[len - 1] == '\n') ++ s[len - 1] = '\0'; ++} ++ + /* + * Attribute operations for netconsole_target. + */ +@@ -466,7 +476,6 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + size_t count) + { + struct netconsole_target *nt = to_target(item); +- size_t len; + + mutex_lock(&dynamic_netconsole_mutex); + if (nt->enabled) { +@@ -477,11 +486,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + } + + strscpy(nt->np.dev_name, buf, IFNAMSIZ); +- +- /* Get rid of possible trailing newline from echo(1) */ +- len = strnlen(nt->np.dev_name, IFNAMSIZ); +- if (nt->np.dev_name[len - 1] == '\n') +- nt->np.dev_name[len - 1] = '\0'; ++ trim_newline(nt->np.dev_name, IFNAMSIZ); + + mutex_unlock(&dynamic_netconsole_mutex); + return strnlen(buf, count); +-- +2.53.0 + diff --git a/queue-6.6/net-phy-add-rust-asix-phy-driver.patch b/queue-6.6/net-phy-add-rust-asix-phy-driver.patch new file mode 100644 index 0000000000..e930852ae4 --- /dev/null +++ b/queue-6.6/net-phy-add-rust-asix-phy-driver.patch @@ -0,0 +1,239 @@ +From c55b8c4b3833658315fd8d0649f22f1103e66ccb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Dec 2023 09:42:11 +0900 +Subject: net: phy: add Rust Asix PHY driver + +From: FUJITA Tomonori + +[ Upstream commit cbe0e415089636170aa6eb540ca4af5dc9842a60 ] + +This is the Rust implementation of drivers/net/phy/ax88796b.c. The +features are equivalent. You can choose C or Rust version kernel +configuration. + +Signed-off-by: FUJITA Tomonori +Reviewed-by: Trevor Gross +Reviewed-by: Benno Lossin +Reviewed-by: Andrew Lunn +Reviewed-by: Alice Ryhl +Signed-off-by: David S. Miller +Stable-dep-of: e7a62edd34b1 ("net: phy: qcom: at803x: Use the correct bit to disable extended next page") +Signed-off-by: Sasha Levin +--- + MAINTAINERS | 8 ++ + drivers/net/phy/Kconfig | 8 ++ + drivers/net/phy/Makefile | 6 +- + drivers/net/phy/ax88796b_rust.rs | 135 +++++++++++++++++++++++++++++++ + rust/uapi/uapi_helper.h | 2 + + 5 files changed, 158 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/phy/ax88796b_rust.rs + +diff --git a/MAINTAINERS b/MAINTAINERS +index e700dca4974b3..8b1ee5b11eca2 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3060,6 +3060,14 @@ S: Maintained + F: Documentation/devicetree/bindings/net/asix,ax88796c.yaml + F: drivers/net/ethernet/asix/ax88796c_* + ++ASIX PHY DRIVER [RUST] ++M: FUJITA Tomonori ++R: Trevor Gross ++L: netdev@vger.kernel.org ++L: rust-for-linux@vger.kernel.org ++S: Maintained ++F: drivers/net/phy/ax88796b_rust.rs ++ + ASPEED CRYPTO DRIVER + M: Neal Liu + L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index aa5491aaaab40..466d3dff60744 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -104,6 +104,14 @@ config AX88796B_PHY + Currently supports the Asix Electronics PHY found in the X-Surf 100 + AX88796B package. + ++config AX88796B_RUST_PHY ++ bool "Rust reference driver for Asix PHYs" ++ depends on RUST_PHYLIB_ABSTRACTIONS && AX88796B_PHY ++ help ++ Uses the Rust reference driver for Asix PHYs (ax88796b_rust.ko). ++ The features are equivalent. It supports the Asix Electronics PHY ++ found in the X-Surf 100 AX88796B package. ++ + config BROADCOM_PHY + tristate "Broadcom 54XX PHYs" + select BCM_NET_PHYLIB +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index f65e85c91fc10..ab450a46b8550 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -37,7 +37,11 @@ obj-$(CONFIG_ADIN1100_PHY) += adin1100.o + obj-$(CONFIG_AMD_PHY) += amd.o + obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ + obj-$(CONFIG_AT803X_PHY) += at803x.o +-obj-$(CONFIG_AX88796B_PHY) += ax88796b.o ++ifdef CONFIG_AX88796B_RUST_PHY ++ obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o ++else ++ obj-$(CONFIG_AX88796B_PHY) += ax88796b.o ++endif + obj-$(CONFIG_BCM54140_PHY) += bcm54140.o + obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o + obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o +diff --git a/drivers/net/phy/ax88796b_rust.rs b/drivers/net/phy/ax88796b_rust.rs +new file mode 100644 +index 0000000000000..5c92572962dce +--- /dev/null ++++ b/drivers/net/phy/ax88796b_rust.rs +@@ -0,0 +1,135 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (C) 2023 FUJITA Tomonori ++ ++//! Rust Asix PHYs driver ++//! ++//! C version of this driver: [`drivers/net/phy/ax88796b.c`](./ax88796b.c) ++use kernel::{ ++ c_str, ++ net::phy::{self, DeviceId, Driver}, ++ prelude::*, ++ uapi, ++}; ++ ++kernel::module_phy_driver! { ++ drivers: [PhyAX88772A, PhyAX88772C, PhyAX88796B], ++ device_table: [ ++ DeviceId::new_with_driver::(), ++ DeviceId::new_with_driver::(), ++ DeviceId::new_with_driver::() ++ ], ++ name: "rust_asix_phy", ++ author: "FUJITA Tomonori ", ++ description: "Rust Asix PHYs driver", ++ license: "GPL", ++} ++ ++const MII_BMCR: u16 = uapi::MII_BMCR as u16; ++const BMCR_SPEED100: u16 = uapi::BMCR_SPEED100 as u16; ++const BMCR_FULLDPLX: u16 = uapi::BMCR_FULLDPLX as u16; ++ ++// Performs a software PHY reset using the standard ++// BMCR_RESET bit and poll for the reset bit to be cleared. ++// Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation ++// such as used on the Individual Computers' X-Surf 100 Zorro card. ++fn asix_soft_reset(dev: &mut phy::Device) -> Result { ++ dev.write(uapi::MII_BMCR as u16, 0)?; ++ dev.genphy_soft_reset() ++} ++ ++struct PhyAX88772A; ++ ++#[vtable] ++impl Driver for PhyAX88772A { ++ const FLAGS: u32 = phy::flags::IS_INTERNAL; ++ const NAME: &'static CStr = c_str!("Asix Electronics AX88772A"); ++ const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1861); ++ ++ // AX88772A is not working properly with some old switches (NETGEAR EN 108TP): ++ // after autoneg is done and the link status is reported as active, the MII_LPA ++ // register is 0. This issue is not reproducible on AX88772C. ++ fn read_status(dev: &mut phy::Device) -> Result { ++ dev.genphy_update_link()?; ++ if !dev.is_link_up() { ++ return Ok(0); ++ } ++ // If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve ++ // linkmode so use MII_BMCR as default values. ++ let ret = dev.read(MII_BMCR)?; ++ ++ if ret & BMCR_SPEED100 != 0 { ++ dev.set_speed(uapi::SPEED_100); ++ } else { ++ dev.set_speed(uapi::SPEED_10); ++ } ++ ++ let duplex = if ret & BMCR_FULLDPLX != 0 { ++ phy::DuplexMode::Full ++ } else { ++ phy::DuplexMode::Half ++ }; ++ dev.set_duplex(duplex); ++ ++ dev.genphy_read_lpa()?; ++ ++ if dev.is_autoneg_enabled() && dev.is_autoneg_completed() { ++ dev.resolve_aneg_linkmode(); ++ } ++ ++ Ok(0) ++ } ++ ++ fn suspend(dev: &mut phy::Device) -> Result { ++ dev.genphy_suspend() ++ } ++ ++ fn resume(dev: &mut phy::Device) -> Result { ++ dev.genphy_resume() ++ } ++ ++ fn soft_reset(dev: &mut phy::Device) -> Result { ++ asix_soft_reset(dev) ++ } ++ ++ fn link_change_notify(dev: &mut phy::Device) { ++ // Reset PHY, otherwise MII_LPA will provide outdated information. ++ // This issue is reproducible only with some link partner PHYs. ++ if dev.state() == phy::DeviceState::NoLink { ++ let _ = dev.init_hw(); ++ let _ = dev.start_aneg(); ++ } ++ } ++} ++ ++struct PhyAX88772C; ++ ++#[vtable] ++impl Driver for PhyAX88772C { ++ const FLAGS: u32 = phy::flags::IS_INTERNAL; ++ const NAME: &'static CStr = c_str!("Asix Electronics AX88772C"); ++ const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1881); ++ ++ fn suspend(dev: &mut phy::Device) -> Result { ++ dev.genphy_suspend() ++ } ++ ++ fn resume(dev: &mut phy::Device) -> Result { ++ dev.genphy_resume() ++ } ++ ++ fn soft_reset(dev: &mut phy::Device) -> Result { ++ asix_soft_reset(dev) ++ } ++} ++ ++struct PhyAX88796B; ++ ++#[vtable] ++impl Driver for PhyAX88796B { ++ const NAME: &'static CStr = c_str!("Asix Electronics AX88796B"); ++ const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_model_mask(0x003b1841); ++ ++ fn soft_reset(dev: &mut phy::Device) -> Result { ++ asix_soft_reset(dev) ++ } ++} +diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h +index 301f5207f0238..08f5e9334c9e8 100644 +--- a/rust/uapi/uapi_helper.h ++++ b/rust/uapi/uapi_helper.h +@@ -7,3 +7,5 @@ + */ + + #include ++#include ++#include +-- +2.53.0 + diff --git a/queue-6.6/net-phy-aquantia-move-to-separate-directory.patch b/queue-6.6/net-phy-aquantia-move-to-separate-directory.patch new file mode 100644 index 0000000000..9cc7001905 --- /dev/null +++ b/queue-6.6/net-phy-aquantia-move-to-separate-directory.patch @@ -0,0 +1,103 @@ +From c052ed458da80925bb8afab07f7ddcdf5d121a8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Nov 2023 15:08:41 +0100 +Subject: net: phy: aquantia: move to separate directory + +From: Christian Marangi + +[ Upstream commit d2213db3f49bce8e7a87c8de05b9a091f78f654e ] + +Move aquantia PHY driver to separate driectory in preparation for +firmware loading support to keep things tidy. + +Signed-off-by: Christian Marangi +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +Stable-dep-of: e7a62edd34b1 ("net: phy: qcom: at803x: Use the correct bit to disable extended next page") +Signed-off-by: Sasha Levin +--- + drivers/net/phy/Kconfig | 5 +---- + drivers/net/phy/Makefile | 6 +----- + drivers/net/phy/aquantia/Kconfig | 5 +++++ + drivers/net/phy/aquantia/Makefile | 6 ++++++ + drivers/net/phy/{ => aquantia}/aquantia.h | 0 + drivers/net/phy/{ => aquantia}/aquantia_hwmon.c | 0 + drivers/net/phy/{ => aquantia}/aquantia_main.c | 0 + 7 files changed, 13 insertions(+), 9 deletions(-) + create mode 100644 drivers/net/phy/aquantia/Kconfig + create mode 100644 drivers/net/phy/aquantia/Makefile + rename drivers/net/phy/{ => aquantia}/aquantia.h (100%) + rename drivers/net/phy/{ => aquantia}/aquantia_hwmon.c (100%) + rename drivers/net/phy/{ => aquantia}/aquantia_main.c (100%) + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 107880d13d219..aa5491aaaab40 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -96,10 +96,7 @@ config ADIN1100_PHY + Currently supports the: + - ADIN1100 - Robust,Industrial, Low Power 10BASE-T1L Ethernet PHY + +-config AQUANTIA_PHY +- tristate "Aquantia PHYs" +- help +- Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 ++source "drivers/net/phy/aquantia/Kconfig" + + config AX88796B_PHY + tristate "Asix PHYs" +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index c945ed9bd14b3..f65e85c91fc10 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -35,11 +35,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) + obj-$(CONFIG_ADIN_PHY) += adin.o + obj-$(CONFIG_ADIN1100_PHY) += adin1100.o + obj-$(CONFIG_AMD_PHY) += amd.o +-aquantia-objs += aquantia_main.o +-ifdef CONFIG_HWMON +-aquantia-objs += aquantia_hwmon.o +-endif +-obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o ++obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ + obj-$(CONFIG_AT803X_PHY) += at803x.o + obj-$(CONFIG_AX88796B_PHY) += ax88796b.o + obj-$(CONFIG_BCM54140_PHY) += bcm54140.o +diff --git a/drivers/net/phy/aquantia/Kconfig b/drivers/net/phy/aquantia/Kconfig +new file mode 100644 +index 0000000000000..226146417a6a7 +--- /dev/null ++++ b/drivers/net/phy/aquantia/Kconfig +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config AQUANTIA_PHY ++ tristate "Aquantia PHYs" ++ help ++ Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 +diff --git a/drivers/net/phy/aquantia/Makefile b/drivers/net/phy/aquantia/Makefile +new file mode 100644 +index 0000000000000..346f350bc0846 +--- /dev/null ++++ b/drivers/net/phy/aquantia/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++aquantia-objs += aquantia_main.o ++ifdef CONFIG_HWMON ++aquantia-objs += aquantia_hwmon.o ++endif ++obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o +diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia/aquantia.h +similarity index 100% +rename from drivers/net/phy/aquantia.h +rename to drivers/net/phy/aquantia/aquantia.h +diff --git a/drivers/net/phy/aquantia_hwmon.c b/drivers/net/phy/aquantia/aquantia_hwmon.c +similarity index 100% +rename from drivers/net/phy/aquantia_hwmon.c +rename to drivers/net/phy/aquantia/aquantia_hwmon.c +diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c +similarity index 100% +rename from drivers/net/phy/aquantia_main.c +rename to drivers/net/phy/aquantia/aquantia_main.c +-- +2.53.0 + diff --git a/queue-6.6/net-phy-dp83869-fix-setting-clk_o_sel-field.patch b/queue-6.6/net-phy-dp83869-fix-setting-clk_o_sel-field.patch new file mode 100644 index 0000000000..bfdd865aa9 --- /dev/null +++ b/queue-6.6/net-phy-dp83869-fix-setting-clk_o_sel-field.patch @@ -0,0 +1,64 @@ +From 63d4ae007b6640198637754731e21d477458aadc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 05:13:39 +0200 +Subject: net: phy: dp83869: fix setting CLK_O_SEL field. + +From: Heiko Schocher + +[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ] + +Table 7-121 in datasheet says we have to set register 0xc6 +to value 0x10 before CLK_O_SEL can be modified. No more infos +about this field found in datasheet. With this fix, setting +of CLK_O_SEL field in IO_MUX_CFG register worked through dts +property "ti,clk-output-sel" on a DP83869HMRGZR. + +Signed-off-by: Heiko Schocher +Reviewed-by: Simon Horman +Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") +Link: https://patch.msgid.link/20260425031339.3318-1-hs@nabladev.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83869.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c +index 5f056d7db83ee..760785160ab49 100644 +--- a/drivers/net/phy/dp83869.c ++++ b/drivers/net/phy/dp83869.c +@@ -31,6 +31,7 @@ + #define DP83869_RGMIICTL 0x0032 + #define DP83869_STRAP_STS1 0x006e + #define DP83869_RGMIIDCTL 0x0086 ++#define DP83869_ANA_PLL_PROG_PI 0x00c6 + #define DP83869_RXFCFG 0x0134 + #define DP83869_RXFPMD1 0x0136 + #define DP83869_RXFPMD2 0x0137 +@@ -814,12 +815,22 @@ static int dp83869_config_init(struct phy_device *phydev) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ +- if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) ++ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { ++ /* ++ * Table 7-121 in datasheet says we have to set register 0xc6 ++ * to value 0x10 before CLK_O_SEL can be modified. ++ */ ++ ret = phy_write_mmd(phydev, DP83869_DEVADDR, ++ DP83869_ANA_PLL_PROG_PI, 0x10); ++ if (ret) ++ return ret; ++ + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); ++ } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, +-- +2.53.0 + diff --git a/queue-6.6/net-phy-move-at803x-phy-driver-to-dedicated-director.patch b/queue-6.6/net-phy-move-at803x-phy-driver-to-dedicated-director.patch new file mode 100644 index 0000000000..9eeb140bc4 --- /dev/null +++ b/queue-6.6/net-phy-move-at803x-phy-driver-to-dedicated-director.patch @@ -0,0 +1,97 @@ +From 41cf81e8748351f71d3f98a5877836d8008a7224 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Jan 2024 15:15:19 +0100 +Subject: net: phy: move at803x PHY driver to dedicated directory + +From: Christian Marangi + +[ Upstream commit 9e56ff53b4115875667760445b028357848b4748 ] + +In preparation for addition of other Qcom PHY and to tidy things up, +move the at803x PHY driver to dedicated directory. + +The same order in the Kconfig selection is saved. + +Signed-off-by: Christian Marangi +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/20240129141600.2592-2-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: e7a62edd34b1 ("net: phy: qcom: at803x: Use the correct bit to disable extended next page") +Signed-off-by: Sasha Levin +--- + drivers/net/phy/Kconfig | 7 +------ + drivers/net/phy/Makefile | 2 +- + drivers/net/phy/qcom/Kconfig | 7 +++++++ + drivers/net/phy/qcom/Makefile | 2 ++ + drivers/net/phy/{ => qcom}/at803x.c | 0 + 5 files changed, 11 insertions(+), 7 deletions(-) + create mode 100644 drivers/net/phy/qcom/Kconfig + create mode 100644 drivers/net/phy/qcom/Makefile + rename drivers/net/phy/{ => qcom}/at803x.c (100%) + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 466d3dff60744..e49131cef9570 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -326,12 +326,7 @@ config NCN26000_PHY + Currently supports the NCN26000 10BASE-T1S Industrial PHY + with MII interface. + +-config AT803X_PHY +- tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" +- depends on REGULATOR +- help +- Currently supports the AR8030, AR8031, AR8033, AR8035 and internal +- QCA8337(Internal qca8k PHY) model ++source "drivers/net/phy/qcom/Kconfig" + + config QSEMI_PHY + tristate "Quality Semiconductor PHYs" +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index ab450a46b8550..6e4493e26816d 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -36,7 +36,6 @@ obj-$(CONFIG_ADIN_PHY) += adin.o + obj-$(CONFIG_ADIN1100_PHY) += adin1100.o + obj-$(CONFIG_AMD_PHY) += amd.o + obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ +-obj-$(CONFIG_AT803X_PHY) += at803x.o + ifdef CONFIG_AX88796B_RUST_PHY + obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o + else +@@ -86,6 +85,7 @@ obj-$(CONFIG_NCN26000_PHY) += ncn26000.o + obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o + obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o + obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o ++obj-y += qcom/ + obj-$(CONFIG_QSEMI_PHY) += qsemi.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_RENESAS_PHY) += uPD60620.o +diff --git a/drivers/net/phy/qcom/Kconfig b/drivers/net/phy/qcom/Kconfig +new file mode 100644 +index 0000000000000..2c274fbbe410d +--- /dev/null ++++ b/drivers/net/phy/qcom/Kconfig +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config AT803X_PHY ++ tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" ++ depends on REGULATOR ++ help ++ Currently supports the AR8030, AR8031, AR8033, AR8035 and internal ++ QCA8337(Internal qca8k PHY) model +diff --git a/drivers/net/phy/qcom/Makefile b/drivers/net/phy/qcom/Makefile +new file mode 100644 +index 0000000000000..6a68da8aaa7bf +--- /dev/null ++++ b/drivers/net/phy/qcom/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_AT803X_PHY) += at803x.o +diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/qcom/at803x.c +similarity index 100% +rename from drivers/net/phy/at803x.c +rename to drivers/net/phy/qcom/at803x.c +-- +2.53.0 + diff --git a/queue-6.6/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch b/queue-6.6/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch new file mode 100644 index 0000000000..f575d64014 --- /dev/null +++ b/queue-6.6/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch @@ -0,0 +1,67 @@ +From 44cb3fff505a4f7a245188ebc39755f336de3109 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:10:20 +0200 +Subject: net: phy: qcom: at803x: Use the correct bit to disable extended next + page + +From: Maxime Chevallier + +[ Upstream commit e7a62edd34b1b4bc5f979988efc2f81c075733fd ] + +As noted in the blamed commit, the AR8035 and other PHYs from this +family advertise the Extended Next Page support by default, which may be +understood by some partners as this PHY being multi-gig capable. + +The fix is to disable XNP advertising, which is done by setting bit 12 +of the Auto-Negotiation Advertisement Register (MII_ADVERTISE). + +The blamed commit incorrectly uses MDIO_AN_CTRL1_XNP, which is bit 13 as per +802.3 : 45.2.7.1 AN control register (Register 7.0) + +BIT 12 in MII_ADVERTISE is wrapped by ADVERTISE_RESV, used by some +drivers such as the aquantia one. 802.3 Clause 28 defines bit 12 as +Extended Next Page ability, at least in recent versions of the standard. + +Let's add a define for it and use it in the at803x driver. + +Fixes: 3c51fa5d2afe ("net: phy: ar803x: disable extended next page bit") +Signed-off-by: Maxime Chevallier +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260410171021.1277138-1-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/qcom/at803x.c | 2 +- + include/uapi/linux/mii.h | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c +index ef203b0807e58..0b01b6ff0a4b5 100644 +--- a/drivers/net/phy/qcom/at803x.c ++++ b/drivers/net/phy/qcom/at803x.c +@@ -1064,7 +1064,7 @@ static int at803x_config_init(struct phy_device *phydev) + * behaviour but we still need to accommodate it. XNP is only needed + * for 10Gbps support, so disable XNP. + */ +- return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); ++ return phy_modify(phydev, MII_ADVERTISE, ADVERTISE_XNP, 0); + } + + static int at803x_ack_interrupt(struct phy_device *phydev) +diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h +index 39f7c44baf535..61d6edad4b94a 100644 +--- a/include/uapi/linux/mii.h ++++ b/include/uapi/linux/mii.h +@@ -82,7 +82,8 @@ + #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ + #define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ + #define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +-#define ADVERTISE_RESV 0x1000 /* Unused... */ ++#define ADVERTISE_XNP 0x1000 /* Extended Next Page */ ++#define ADVERTISE_RESV ADVERTISE_XNP /* Used to be reserved */ + #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ + #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ + #define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +-- +2.53.0 + diff --git a/queue-6.6/net-rds-optimize-rds_ib_laddr_check.patch b/queue-6.6/net-rds-optimize-rds_ib_laddr_check.patch new file mode 100644 index 0000000000..3ecd124be1 --- /dev/null +++ b/queue-6.6/net-rds-optimize-rds_ib_laddr_check.patch @@ -0,0 +1,189 @@ +From 24e6aae99b7280ec5cfdfa0e087d245d60d01f26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:19 -0700 +Subject: net/rds: Optimize rds_ib_laddr_check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 236f718ac885965fa886440b9898dfae185c9733 ] + +rds_ib_laddr_check() creates a CM_ID and attempts to bind the address +in question to it. This in order to qualify the allegedly local +address as a usable IB/RoCE address. + +In the field, ExaWatcher runs rds-ping to all ports in the fabric from +all local ports. This using all active ToS'es. In a full rack system, +we have 14 cell servers and eight db servers. Typically, 6 ToS'es are +used. This implies 528 rds-ping invocations per ExaWatcher's "RDSinfo" +interval. + +Adding to this, each rds-ping invocation creates eight sockets and +binds the local address to them: + +socket(AF_RDS, SOCK_SEQPACKET, 0) = 3 +bind(3, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 4 +bind(4, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 5 +bind(5, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 6 +bind(6, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 7 +bind(7, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 8 +bind(8, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 9 +bind(9, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 10 +bind(10, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 + +So, at every interval ExaWatcher executes rds-ping's, 4224 CM_IDs are +allocated, considering this full-rack system. After the a CM_ID has +been allocated, rdma_bind_addr() is called, with the port number being +zero. This implies that the CMA will attempt to search for an un-used +ephemeral port. Simplified, the algorithm is to start at a random +position in the available port space, and then if needed, iterate +until an un-used port is found. + +The book-keeping of used ports uses the idr system, which again uses +slab to allocate new struct idr_layer's. The size is 2092 bytes and +slab tries to reduce the wasted space. Hence, it chooses an order:3 +allocation, for which 15 idr_layer structs will fit and only 1388 +bytes are wasted per the 32KiB order:3 chunk. + +Although this order:3 allocation seems like a good space/speed +trade-off, it does not resonate well with how it used by the CMA. The +combination of the randomized starting point in the port space (which +has close to zero spatial locality) and the close proximity in time of +the 4224 invocations of the rds-ping's, creates a memory hog for +order:3 allocations. + +These costly allocations may need reclaims and/or compaction. At +worst, they may fail and produce a stack trace such as (from uek4): + +[] __inc_zone_page_state+0x35/0x40 +[] page_add_file_rmap+0x57/0x60 +[] remove_migration_pte+0x3f/0x3c0 [ksplice_6cn872bt_vmlinux_new] +[] rmap_walk+0xd8/0x340 +[] remove_migration_ptes+0x40/0x50 +[] migrate_pages+0x3ec/0x890 +[] compact_zone+0x32d/0x9a0 +[] compact_zone_order+0x6d/0x90 +[] try_to_compact_pages+0x102/0x270 +[] __alloc_pages_direct_compact+0x46/0x100 +[] __alloc_pages_nodemask+0x74b/0xaa0 +[] alloc_pages_current+0x91/0x110 +[] new_slab+0x38b/0x480 +[] __slab_alloc+0x3b7/0x4a0 [ksplice_s0dk66a8_vmlinux_new] +[] kmem_cache_alloc+0x1fb/0x250 +[] idr_layer_alloc+0x36/0x90 +[] idr_get_empty_slot+0x28c/0x3d0 +[] idr_alloc+0x4d/0xf0 +[] cma_alloc_port+0x4d/0xa0 [rdma_cm] +[] rdma_bind_addr+0x2ae/0x5b0 [rdma_cm] +[] rds_ib_laddr_check+0x83/0x2c0 [ksplice_6l2xst5i_rds_rdma_new] +[] rds_trans_get_preferred+0x5b/0xa0 [rds] +[] rds_bind+0x212/0x280 [rds] +[] SYSC_bind+0xe6/0x120 +[] SyS_bind+0xe/0x10 +[] system_call_fastpath+0x18/0xd4 + +To avoid these excessive calls to rdma_bind_addr(), we optimize +rds_ib_laddr_check() by simply checking if the address in question has +been used before. The rds_rdma module keeps track of addresses +associated with IB devices, and the function rds_ib_get_device() is +used to determine if the address already has been qualified as a valid +local address. If not found, we call the legacy rds_ib_laddr_check(), +now renamed to rds_ib_laddr_check_cm(). + +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Somasundaram Krishnasamy +Signed-off-by: Gerd Rausch +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-2-achender@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: ebf71dd4aff4 ("net/rds: Restrict use of RDS/IB to the initial network namespace") +Signed-off-by: Sasha Levin +--- + net/rds/ib.c | 20 ++++++++++++++++++-- + net/rds/ib.h | 1 + + net/rds/ib_rdma.c | 2 +- + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 9826fe7f9d008..996f007cd516b 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -403,8 +403,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len, + * allowed to influence which paths have priority. We could call userspace + * asserting this policy "routing". + */ +-static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, +- __u32 scope_id) ++static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) + { + int ret; + struct rdma_cm_id *cm_id; +@@ -489,6 +489,22 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + return ret; + } + ++static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) ++{ ++ struct rds_ib_device *rds_ibdev = NULL; ++ ++ if (ipv6_addr_v4mapped(addr)) { ++ rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); ++ if (rds_ibdev) { ++ rds_ib_dev_put(rds_ibdev); ++ return 0; ++ } ++ } ++ ++ return rds_ib_laddr_check_cm(net, addr, scope_id); ++} ++ + static void rds_ib_unregister_client(void) + { + ib_unregister_client(&rds_ib_client); +diff --git a/net/rds/ib.h b/net/rds/ib.h +index 2ba71102b1f1f..d6c1197731c1c 100644 +--- a/net/rds/ib.h ++++ b/net/rds/ib.h +@@ -384,6 +384,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, + __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) + + /* ib_rdma.c */ ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr); + int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, + struct in6_addr *ipaddr); + void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); +diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c +index 30fca2169aa7a..468fd60d818ff 100644 +--- a/net/rds/ib_rdma.c ++++ b/net/rds/ib_rdma.c +@@ -47,7 +47,7 @@ struct rds_ib_dereg_odp_mr { + + static void rds_ib_odp_mr_worker(struct work_struct *work); + +-static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) + { + struct rds_ib_device *rds_ibdev; + struct rds_ib_ipaddr *i_ipaddr; +-- +2.53.0 + diff --git a/queue-6.6/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch b/queue-6.6/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch new file mode 100644 index 0000000000..6d3c80ecd7 --- /dev/null +++ b/queue-6.6/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch @@ -0,0 +1,86 @@ +From 4d12a3c482b6c9ec7aac61edadf801f9bca33258 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:20 -0700 +Subject: net/rds: Restrict use of RDS/IB to the initial network namespace + +From: Greg Jumper + +[ Upstream commit ebf71dd4aff46e8e421d455db3e231ba43d2fa8a ] + +Prevent using RDS/IB in network namespaces other than the initial one. +The existing RDS/IB code will not work properly in non-initial network +namespaces. + +Fixes: d5a8ac28a7ff ("RDS-TCP: Make RDS-TCP work correctly when it is set up in a netns other than init_net") +Reported-by: syzbot+da8e060735ae02c8f3d1@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=da8e060735ae02c8f3d1 +Signed-off-by: Greg Jumper +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-3-achender@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/af_rds.c | 10 ++++++++-- + net/rds/ib.c | 4 ++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c +index 8435a20968ef5..f0840169d5e31 100644 +--- a/net/rds/af_rds.c ++++ b/net/rds/af_rds.c +@@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen) + return ret; + } + +-static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) ++static int rds_set_transport(struct net *net, struct rds_sock *rs, ++ sockptr_t optval, int optlen) + { + int t_type; + +@@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) + if (t_type < 0 || t_type >= RDS_TRANS_COUNT) + return -EINVAL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + rs->rs_transport = rds_trans_get(t_type); + + return rs->rs_transport ? 0 : -ENOPROTOOPT; +@@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) + { + struct rds_sock *rs = rds_sk_to_rs(sock->sk); ++ struct net *net = sock_net(sock->sk); + int ret; + + if (level != SOL_RDS) { +@@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + break; + case SO_RDS_TRANSPORT: + lock_sock(sock->sk); +- ret = rds_set_transport(rs, optval, optlen); ++ ret = rds_set_transport(net, rs, optval, optlen); + release_sock(sock->sk); + break; + case SO_TIMESTAMP_OLD: +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 996f007cd516b..ce5be43c5fbac 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -494,6 +494,10 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + { + struct rds_ib_device *rds_ibdev = NULL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (!net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + if (ipv6_addr_v4mapped(addr)) { + rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); + if (rds_ibdev) { +-- +2.53.0 + diff --git a/queue-6.6/net-rds-zero-per-item-info-buffer-before-handing-it-.patch b/queue-6.6/net-rds-zero-per-item-info-buffer-before-handing-it-.patch new file mode 100644 index 0000000000..a0d52970b3 --- /dev/null +++ b/queue-6.6/net-rds-zero-per-item-info-buffer-before-handing-it-.patch @@ -0,0 +1,111 @@ +From 1fdb6cbba37c7b8d48f8a9c496ef48a3da407985 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 10:10:47 -0400 +Subject: net/rds: zero per-item info buffer before handing it to visitors + +From: Michael Bommarito + +[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ] + +rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a +caller-allocated on-stack u64 buffer to a per-connection visitor and +then copy the full item_len bytes back to user space via +rds_info_copy() regardless of how much of the buffer the visitor +actually wrote. + +rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only +write a subset of their output struct when the underlying +rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl +and the two GIDs via explicit memsets). Several u32 fields +(max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, +cache_allocs) and the 2-byte alignment hole between sl and +cache_allocs remain as whatever stack contents preceded the visitor +call and are then memcpy_to_user()'d out to user space. + +struct rds_info_rdma_connection and struct rds6_info_rdma_connection +are the only rds_info_* structs in include/uapi/linux/rds.h that are +not marked __attribute__((packed)), so they have a real alignment +hole. The other info visitors (rds_conn_info_visitor, +rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of +their packed output struct today and are not known to be vulnerable, +but a future visitor that adds a conditional write-path would have +the same bug. + +Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y: +a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, +binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on +any netdev is sufficient), sendto()'s any peer on the same subnet +(fails cleanly but installs an rds_connection in the global hash in +RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, +RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 +bytes of stack garbage including kernel text/data pointers: + + 0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2 + 8..39 00 ... gids (memset-zeroed) + 40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr) + 48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max) + 56..59 01 00 08 00 rdma_mr_size (garbage) + 60..61 00 00 tos, sl + 62..63 00 00 alignment padding + 64..67 18 00 00 00 cache_allocs (garbage) + +Fix by zeroing the per-item buffer in both rds_for_each_conn_info() +and rds_walk_conn_path_info() before invoking the visitor. This +covers the IPv4/IPv6 IB visitors and hardens all current and future +visitors against the same class of bug. + +No functional change for visitors that fully populate their output. + +Changes in v2: +- retarget at the net tree (subject prefix "[PATCH net v2]", + net/rds: prefix in the title) +- pick up Reviewed-by tags from Sharath Srinivasan and + Allison Henderson + +Fixes: ec16227e1414 ("RDS/IB: Infiniband transport") +Signed-off-by: Michael Bommarito +Reviewed-by: Sharath Srinivasan +Reviewed-by: Allison Henderson +Assisted-by: Claude:claude-opus-4-7 +Link: https://patch.msgid.link/20260418141047.3398203-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/connection.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index 98c0d5ff9de9c..cd41f83863c89 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -673,6 +673,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, + i++, head++) { + hlist_for_each_entry_rcu(conn, head, c_hash_node) { + ++ /* Zero the per-item buffer before handing it to the ++ * visitor so any field the visitor does not write - ++ * including implicit alignment padding - cannot leak ++ * stack contents to user space via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no c_lock usage.. */ + if (!visitor(conn, buffer)) + continue; +@@ -722,6 +729,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, + */ + cp = conn->c_path; + ++ /* Zero the per-item buffer for the same reason as ++ * rds_for_each_conn_info(): any byte the visitor ++ * does not write (including alignment padding) must ++ * not leak stack contents via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no cp_lock usage.. */ + if (!visitor(cp, buffer)) + continue; +-- +2.53.0 + diff --git a/queue-6.6/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch b/queue-6.6/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch new file mode 100644 index 0000000000..8342ef3512 --- /dev/null +++ b/queue-6.6/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch @@ -0,0 +1,130 @@ +From 1466ad57af22518af8a3d060bd2ec686c72116d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:16:27 -0400 +Subject: net/sched: act_ct: Only release RCU read lock after ct_ft + +From: Jamal Hadi Salim + +[ Upstream commit f462dca0c8415bf0058d0ffa476354c4476d0f09 ] + +When looking up a flow table in act_ct in tcf_ct_flow_table_get(), +rhashtable_lookup_fast() internally opens and closes an RCU read critical +section before returning ct_ft. +The tcf_ct_flow_table_cleanup_work() can complete before refcount_inc_not_zero() +is invoked on the returned ct_ft resulting in a UAF on the already freed ct_ft +object. This vulnerability can lead to privilege escalation. + +Analysis from zdi-disclosures@trendmicro.com: +When initializing act_ct, tcf_ct_init() is called, which internally triggers +tcf_ct_flow_table_get(). + +static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + +{ + struct zones_ht_key key = { .net = net, .zone = params->zone }; + struct tcf_ct_flow_table *ct_ft; + int err = -ENOMEM; + + mutex_lock(&zones_mutex); + ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); // [1] + if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) // [2] + goto out_unlock; + ... +} + +static __always_inline void *rhashtable_lookup_fast( + struct rhashtable *ht, const void *key, + const struct rhashtable_params params) +{ + void *obj; + + rcu_read_lock(); + obj = rhashtable_lookup(ht, key, params); + rcu_read_unlock(); + + return obj; +} + +At [1], rhashtable_lookup_fast() looks up and returns the corresponding ct_ft +from zones_ht . The lookup is performed within an RCU read critical section +through rcu_read_lock() / rcu_read_unlock(), which prevents the object from +being freed. However, at the point of function return, rcu_read_unlock() has +already been called, and there is nothing preventing ct_ft from being freed +before reaching refcount_inc_not_zero(&ct_ft->ref) at [2]. This interval becomes +the race window, during which ct_ft can be freed. + +Free Process: + +tcf_ct_flow_table_put() is executed through the path tcf_ct_cleanup() call_rcu() +tcf_ct_params_free_rcu() tcf_ct_params_free() tcf_ct_flow_table_put(). + +static void tcf_ct_flow_table_put(struct tcf_ct_flow_table *ct_ft) +{ + if (refcount_dec_and_test(&ct_ft->ref)) { + rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params); + INIT_RCU_WORK(&ct_ft->rwork, tcf_ct_flow_table_cleanup_work); // [3] + queue_rcu_work(act_ct_wq, &ct_ft->rwork); + } +} + +At [3], tcf_ct_flow_table_cleanup_work() is scheduled as RCU work + +static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) + +{ + struct tcf_ct_flow_table *ct_ft; + struct flow_block *block; + + ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, + rwork); + nf_flow_table_free(&ct_ft->nf_ft); + block = &ct_ft->nf_ft.flow_block; + down_write(&ct_ft->nf_ft.flow_block_lock); + WARN_ON(!list_empty(&block->cb_list)); + up_write(&ct_ft->nf_ft.flow_block_lock); + kfree(ct_ft); // [4] + + module_put(THIS_MODULE); +} + +tcf_ct_flow_table_cleanup_work() frees ct_ft at [4]. When this function executes +between [1] and [2], UAF occurs. + +This race condition has a very short race window, making it generally +difficult to trigger. Therefore, to trigger the vulnerability an msleep(100) was +inserted after[1] + +Fixes: 138470a9b2cc2 ("net/sched: act_ct: fix lockdep splat in tcf_ct_flow_table_get") +Reported-by: zdi-disclosures@trendmicro.com +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260410111627.46611-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/act_ct.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index a5f4a27c8dd31..7810c9d64ff3a 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -328,9 +328,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + int err = -ENOMEM; + + mutex_lock(&zones_mutex); +- ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); +- if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) ++ rcu_read_lock(); ++ ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params); ++ if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) { ++ rcu_read_unlock(); + goto out_unlock; ++ } ++ rcu_read_unlock(); + + ct_ft = kzalloc(sizeof(*ct_ft), GFP_KERNEL); + if (!ct_ft) +-- +2.53.0 + diff --git a/queue-6.6/net-sched-cls_flower-revert-unintended-changes.patch b/queue-6.6/net-sched-cls_flower-revert-unintended-changes.patch new file mode 100644 index 0000000000..cb75a163d2 --- /dev/null +++ b/queue-6.6/net-sched-cls_flower-revert-unintended-changes.patch @@ -0,0 +1,55 @@ +From fc73cf2289d5c8e371ac6474b530296c4274406e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:39:11 +0200 +Subject: net/sched: cls_flower: revert unintended changes + +From: Paolo Abeni + +[ Upstream commit 1e01abec856593e02cd69fd95b784c10dd46880c ] + +While applying the blamed commit 4ca07b9239bd ("net: mctp i2c: check +length before marking flow active"), I unintentionally included +unrelated and unacceptable changes. + +Revert them. + +Fixes: 4ca07b9239bd ("net: mctp i2c: check length before marking flow active") +Reported-by: Jeremy Kerr +Closes: https://lore.kernel.org/netdev/bd8704fe0bd53e278add5cde4873256656623e2e.camel@codeconstruct.com.au/ +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/043026a53ff84da88b17648c4b0d17f0331749cb.1777447863.git.pabeni@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/cls_flower.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index 07259b403e108..b00e491e8130d 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -549,7 +549,6 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); +- struct fl_flow_mask *mask; + + *last = false; + +@@ -566,12 +565,11 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- mask = f->mask; ++ *last = fl_mask_put(head, f->mask); + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); +- *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/net-sched-netem-check-for-negative-latency-and-jitte.patch b/queue-6.6/net-sched-netem-check-for-negative-latency-and-jitte.patch new file mode 100644 index 0000000000..1eadf5f03b --- /dev/null +++ b/queue-6.6/net-sched-netem-check-for-negative-latency-and-jitte.patch @@ -0,0 +1,73 @@ +From b9eab2c92ab9e4eea68b6c46e3b8209d714d15c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:44 -0700 +Subject: net/sched: netem: check for negative latency and jitter + +From: Stephen Hemminger + +[ Upstream commit 90be9fedb218ee95a1cf59050d1306fbfb0e8b87 ] + +Reject requests with negative latency or jitter. +A negative value added to current timestamp (u64) wraps +to an enormous time_to_send, disabling dequeue. +The original UAPI used u32 for these values; the conversion to 64-bit +time values via TCA_NETEM_LATENCY64 and TCA_NETEM_JITTER64 +allowed signed values to reach the kernel without validation. + +Jitter is already silently clamped by an abs() in netem_change(); +that abs() can be removed in a follow-up once this rejection is in +place. + +Fixes: 99803171ef04 ("netem: add uapi to express delay and jitter in nanoseconds") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-7-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index b632e6678881a..f8c5c50618085 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -824,6 +824,16 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_time(const struct nlattr *attr, const char *name, ++ struct netlink_ext_ack *extack) ++{ ++ if (nla_get_s64(attr) < 0) { ++ NL_SET_ERR_MSG_ATTR_FMT(extack, attr, "negative %s", name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1066,6 +1076,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_LATENCY64]) { ++ ret = validate_time(tb[TCA_NETEM_LATENCY64], "latency", extack); ++ if (ret) ++ goto table_free; ++ } ++ ++ if (tb[TCA_NETEM_JITTER64]) { ++ ret = validate_time(tb[TCA_NETEM_JITTER64], "jitter", extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-6.6/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch b/queue-6.6/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch new file mode 100644 index 0000000000..aa859bf231 --- /dev/null +++ b/queue-6.6/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch @@ -0,0 +1,67 @@ +From 6670612367f0581dae6107d5dc721f0b2d1cc94e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:39 -0700 +Subject: net/sched: netem: fix probability gaps in 4-state loss model + +From: Stephen Hemminger + +[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ] + +The 4-state Markov chain in loss_4state() has gaps at the boundaries +between transition probability ranges. The comparisons use: + + if (rnd < a4) + else if (a4 < rnd && rnd < a1 + a4) + +When rnd equals a boundary value exactly, neither branch matches and +no state transition occurs. The redundant lower-bound check (a4 < rnd) +is already implied by being in the else branch. + +Remove the unnecessary lower-bound comparisons so the ranges are +contiguous and every random value produces a transition, matching +the GI (General and Intuitive) loss model specification. + +This bug goes back to original implementation of this model. + +Fixes: 661b79725fea ("netem: revised correlated loss generator") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-2-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 7361f90c8c1a1..a1b2912e2b6c7 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -226,10 +226,10 @@ static bool loss_4state(struct netem_sched_data *q) + if (rnd < clg->a4) { + clg->state = LOST_IN_GAP_PERIOD; + return true; +- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { ++ } else if (rnd < clg->a1 + clg->a4) { + clg->state = LOST_IN_BURST_PERIOD; + return true; +- } else if (clg->a1 + clg->a4 < rnd) { ++ } else { + clg->state = TX_IN_GAP_PERIOD; + } + +@@ -246,9 +246,9 @@ static bool loss_4state(struct netem_sched_data *q) + case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; +- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { ++ else if (rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; +- } else if (clg->a2 + clg->a3 < rnd) { ++ } else { + clg->state = LOST_IN_BURST_PERIOD; + return true; + } +-- +2.53.0 + diff --git a/queue-6.6/net-sched-netem-fix-queue-limit-check-to-include-reo.patch b/queue-6.6/net-sched-netem-fix-queue-limit-check-to-include-reo.patch new file mode 100644 index 0000000000..b7a5157daa --- /dev/null +++ b/queue-6.6/net-sched-netem-fix-queue-limit-check-to-include-reo.patch @@ -0,0 +1,42 @@ +From f4d27789406820cd43df69315a5b115bafa320e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:40 -0700 +Subject: net/sched: netem: fix queue limit check to include reordered packets + +From: Stephen Hemminger + +[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ] + +The queue limit check in netem_enqueue() uses q->t_len which only +counts packets in the internal tfifo. Packets placed in sch->q by +the reorder path (__qdisc_enqueue_head) are not counted, allowing +the total queue occupancy to exceed sch->limit under reordering. + +Include sch->q.qlen in the limit check. + +Fixes: f8d4bc455047 ("net/sched: netem: account for backlog updates from child qdisc") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-3-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index a1b2912e2b6c7..b3af6a50b43be 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -522,7 +522,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + 1 << get_random_u32_below(8); + } + +- if (unlikely(q->t_len >= sch->limit)) { ++ if (unlikely(sch->q.qlen >= sch->limit)) { + /* re-link segs, so that qdisc_drop_all() frees them all */ + skb->next = segs; + qdisc_drop_all(skb, sch, to_free); +-- +2.53.0 + diff --git a/queue-6.6/net-sched-netem-fix-slot-delay-calculation-overflow.patch b/queue-6.6/net-sched-netem-fix-slot-delay-calculation-overflow.patch new file mode 100644 index 0000000000..e03dba854e --- /dev/null +++ b/queue-6.6/net-sched-netem-fix-slot-delay-calculation-overflow.patch @@ -0,0 +1,51 @@ +From 4af2ad0db98f9e09c760313423647b64e822ecd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:43 -0700 +Subject: net/sched: netem: fix slot delay calculation overflow + +From: Stephen Hemminger + +[ Upstream commit 51e94e1e2fef351c74d69eb53666df808d26af95 ] + +get_slot_next() computes a random delay between min_delay and +max_delay using: + + get_random_u32() * (max_delay - min_delay) >> 32 + +This overflows signed 64-bit arithmetic when the delay range exceeds +approximately 2.1 seconds (2^31 nanoseconds), producing a negative +result that effectively disables slot-based pacing. This is a +realistic configuration for WAN emulation (e.g., slot 1s 5s). + +Use mul_u64_u32_shr() which handles the widening multiply without +overflow. + +Fixes: 0a9fe5c375b5 ("netem: slotting with non-uniform distribution") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-6-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 1bb399cf40328..b632e6678881a 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -657,9 +657,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now) + + if (!q->slot_dist) + next_delay = q->slot_config.min_delay + +- (get_random_u32() * +- (q->slot_config.max_delay - +- q->slot_config.min_delay) >> 32); ++ mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay, ++ get_random_u32(), 32); + else + next_delay = tabledist(q->slot_config.dist_delay, + (s32)(q->slot_config.dist_jitter), +-- +2.53.0 + diff --git a/queue-6.6/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch b/queue-6.6/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch new file mode 100644 index 0000000000..f58b5b9d8a --- /dev/null +++ b/queue-6.6/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch @@ -0,0 +1,60 @@ +From b01428b2206008d945237e9dafab9aeba232cf49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:41 -0700 +Subject: net/sched: netem: only reseed PRNG when seed is explicitly provided + +From: Stephen Hemminger + +[ Upstream commit 986afaf809940577224a99c3a08d97a15eb37e93 ] + +netem_change() unconditionally reseeds the PRNG on every tc change +command. If TCA_NETEM_PRNG_SEED is not specified, a new random seed +is generated, destroying reproducibility for users who set a +deterministic seed on a previous change. + +Move the initial random seed generation to netem_init() and only +reseed in netem_change() when TCA_NETEM_PRNG_SEED is explicitly +provided by the user. + +Fixes: 4072d97ddc44 ("netem: add prng attribute to netem_sched_data") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-4-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index b3af6a50b43be..e778eb1d1a510 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1110,11 +1110,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + /* capping jitter to the range acceptable by tabledist() */ + q->jitter = min_t(s64, abs(q->jitter), INT_MAX); + +- if (tb[TCA_NETEM_PRNG_SEED]) ++ if (tb[TCA_NETEM_PRNG_SEED]) { + q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]); +- else +- q->prng.seed = get_random_u64(); +- prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ } + + unlock: + sch_tree_unlock(sch); +@@ -1137,6 +1136,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt, + return -EINVAL; + + q->loss_model = CLG_RANDOM; ++ q->prng.seed = get_random_u64(); ++ prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ + ret = netem_change(sch, opt, extack); + if (ret) + pr_info("netem: change failed\n"); +-- +2.53.0 + diff --git a/queue-6.6/net-sched-netem-validate-slot-configuration.patch b/queue-6.6/net-sched-netem-validate-slot-configuration.patch new file mode 100644 index 0000000000..4984f64146 --- /dev/null +++ b/queue-6.6/net-sched-netem-validate-slot-configuration.patch @@ -0,0 +1,86 @@ +From 4362209cbf93f19297032651ba77edd95df063b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:42 -0700 +Subject: net/sched: netem: validate slot configuration + +From: Stephen Hemminger + +[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ] + +Reject slot configurations that have no defensible meaning: + + - negative min_delay or max_delay + - min_delay greater than max_delay + - negative dist_delay or dist_jitter + - negative max_packets or max_bytes + +Negative or out-of-order delays underflow in get_slot_next(), +producing garbage intervals. Negative limits trip the per-slot +accounting (packets_left/bytes_left <= 0) on the first packet of +every slot, defeating the rate-limiting half of the slot feature. + +Note that dist_jitter has been silently coerced to its absolute +value by get_slot() since the feature was introduced; rejecting +negatives here converts that silent coercion into -EINVAL. The +abs() can be removed in a follow-up. + +Fixes: 836af83b54e3 ("netem: support delivering packets in delayed time slots") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index e778eb1d1a510..1bb399cf40328 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -825,6 +825,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) ++{ ++ const struct tc_netem_slot *c = nla_data(attr); ++ ++ if (c->min_delay < 0 || c->max_delay < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); ++ return -EINVAL; ++ } ++ if (c->min_delay > c->max_delay) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); ++ return -EINVAL; ++ } ++ if (c->dist_delay < 0 || c->dist_jitter < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); ++ return -EINVAL; ++ } ++ if (c->max_packets < 0 || c->max_bytes < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1038,6 +1061,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_SLOT]) { ++ ret = validate_slot(tb[TCA_NETEM_SLOT], extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch b/queue-6.6/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch new file mode 100644 index 0000000000..8b987ab3be --- /dev/null +++ b/queue-6.6/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch @@ -0,0 +1,62 @@ +From ffa2c3b5ffbb07beebeac168d6842071593382ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:06 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (V) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations +for cparams.target and cparams.interval. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 55e8b682ec14c..0b85971165d2a 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -2314,10 +2314,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + + byte_target_ns = (byte_target * rate_ns) >> rate_shft; + +- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); +- b->cparams.interval = max(rtt_est_ns + +- b->cparams.target - target_ns, +- b->cparams.target * 2); ++ WRITE_ONCE(b->cparams.target, ++ max((byte_target_ns * 3) / 2, target_ns)); ++ WRITE_ONCE(b->cparams.interval, ++ max(rtt_est_ns + b->cparams.target - target_ns, ++ b->cparams.target * 2)); + b->cparams.mtu_time = byte_target_ns; + b->cparams.p_inc = 1 << 24; /* 1/256 */ + b->cparams.p_dec = 1 << 20; /* 1/4096 */ +@@ -2931,9 +2932,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); + + PUT_TSTAT_U32(TARGET_US, +- ktime_to_us(ns_to_ktime(b->cparams.target))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); + PUT_TSTAT_U32(INTERVAL_US, +- ktime_to_us(ns_to_ktime(b->cparams.interval))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); + + PUT_TSTAT_U32(SENT_PACKETS, b->packets); + PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch b/queue-6.6/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch new file mode 100644 index 0000000000..32d9f865b7 --- /dev/null +++ b/queue-6.6/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch @@ -0,0 +1,64 @@ +From bc835e0578232697716395ad68db44b394db54f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:00:41 +0800 +Subject: net/sched: sch_cake: fix NAT destination port not being updated in + cake_update_flowkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit f9e40664706927d7ae22a448a3383e23c38a4c0b ] + +cake_update_flowkeys() is supposed to update the flow dissector keys +with the NAT-translated addresses and ports from conntrack, so that +CAKE's per-flow fairness correctly identifies post-NAT flows as +belonging to the same connection. + +For the source port, this works correctly: + keys->ports.src = port; + +But for the destination port, the assignment is reversed: + port = keys->ports.dst; + +This means the NAT destination port is never updated in the flow keys. +As a result, when multiple connections are NATed to the same destination, +CAKE treats them as separate flows because the original (pre-NAT) +destination ports differ. This breaks CAKE's NAT-aware flow isolation +when using the "nat" mode. + +The bug was introduced in commit b0c19ed6088a ("sch_cake: Take advantage +of skb->hash where appropriate") which refactored the original direct +assignment into a compare-and-conditionally-update pattern, but wrote +the destination port update backwards. + +Fix by reversing the assignment direction to match the source port +pattern. + +Fixes: b0c19ed6088a ("sch_cake: Take advantage of skb->hash where appropriate") +Signed-off-by: Dudu Lu +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260413110041.44704-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 14e06f474b6ca..55e8b682ec14c 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -620,7 +620,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys, + } + port = rev ? tuple.src.u.all : tuple.dst.u.all; + if (port != keys->ports.dst) { +- port = keys->ports.dst; ++ keys->ports.dst = port; + upd = true; + } + } +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch b/queue-6.6/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch new file mode 100644 index 0000000000..b5a323eb10 --- /dev/null +++ b/queue-6.6/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch @@ -0,0 +1,97 @@ +From 6a6c52696198fb28b236e707454dee858fd15682 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:28:39 +0000 +Subject: net/sched: sch_choke: annotate data-races in choke_dump_stats() + +From: Eric Dumazet + +[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ] + +choke_dump_stats() only runs with RTNL held. +It reads fields that can be changed in qdisc fast path. +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423062839.2524324-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index a919591422085..b27da148ca744 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + /* Draw a packet at random from queue and compare flow */ + if (choke_match_random(q, skb, &idx)) { +- q->stats.matched++; ++ WRITE_ONCE(q->stats.matched, q->stats.matched + 1); + choke_drop_by_idx(sch, idx, to_free); + goto congestion_drop; + } +@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + qdisc_qstats_overlimit(sch); + if (use_harddrop(q) || !use_ecn(q) || + !INET_ECN_set_ce(skb)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + } else if (++q->vars.qcount) { + if (red_mark_probability(p, &q->vars, q->vars.qavg)) { + q->vars.qcount = 0; +@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + qdisc_qstats_overlimit(sch); + if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + } + } else + q->vars.qR = red_random(p); +@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + } + +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); + return qdisc_drop(skb, sch, to_free); + + congestion_drop: +@@ -460,10 +464,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct choke_sched_data *q = qdisc_priv(sch); + struct tc_choke_xstats st = { +- .early = q->stats.prob_drop + q->stats.forced_drop, +- .marked = q->stats.prob_mark + q->stats.forced_mark, +- .pdrop = q->stats.pdrop, +- .matched = q->stats.matched, ++ .early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop), ++ .marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark), ++ .pdrop = READ_ONCE(q->stats.pdrop), ++ .matched = READ_ONCE(q->stats.matched), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch b/queue-6.6/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch new file mode 100644 index 0000000000..fa856b3c57 --- /dev/null +++ b/queue-6.6/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch @@ -0,0 +1,47 @@ +From eb92a9d2282a09ab97ff604e805e199b056011ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:25:09 +0000 +Subject: net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats() + +From: Eric Dumazet + +[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill st.qdisc_stats with live data. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142509.3967231-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_codel.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 47b5a056165cb..056895df17854 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -568,6 +568,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + }; + struct list_head *pos; + ++ sch_tree_lock(sch); ++ + st.qdisc_stats.maxpacket = q->cstats.maxpacket; + st.qdisc_stats.drop_overlimit = q->drop_overlimit; + st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; +@@ -576,7 +578,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + st.qdisc_stats.memory_usage = q->memory_usage; + st.qdisc_stats.drop_overmemory = q->drop_overmemory; + +- sch_tree_lock(sch); + list_for_each(pos, &q->new_flows) + st.qdisc_stats.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch b/queue-6.6/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch new file mode 100644 index 0000000000..70d9b7f969 --- /dev/null +++ b/queue-6.6/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch @@ -0,0 +1,62 @@ +From 63d9e5491a79c1ed05ee2e0d1ff16633a36047aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:35:27 +0000 +Subject: net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill tc_fq_pie_xstats with live data. + +Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, +but the spinlock is needed anyway to scan q->new_flows and q->old_flows. + +Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423063527.2568262-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_pie.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index 607c580d75e4b..4bd5ca9acc53f 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -498,18 +498,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb) + static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct fq_pie_sched_data *q = qdisc_priv(sch); +- struct tc_fq_pie_xstats st = { +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .overmemory = q->overmemory, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, +- .new_flow_count = q->new_flow_count, +- .memory_usage = q->memory_usage, +- }; ++ struct tc_fq_pie_xstats st = { 0 }; + struct list_head *pos; + + sch_tree_lock(sch); ++ ++ st.packets_in = q->stats.packets_in; ++ st.overlimit = q->stats.overlimit; ++ st.overmemory = q->overmemory; ++ st.dropped = q->stats.dropped; ++ st.ecn_mark = q->stats.ecn_mark; ++ st.new_flow_count = q->new_flow_count; ++ st.memory_usage = q->memory_usage; ++ + list_for_each(pos, &q->new_flows) + st.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch b/queue-6.6/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch new file mode 100644 index 0000000000..f364ce014c --- /dev/null +++ b/queue-6.6/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch @@ -0,0 +1,160 @@ +From ba167e3580f343d1baf707501ac82be5666fe81f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:29:44 +0000 +Subject: net/sched: sch_pie: annotate data-races in pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ] + +pie_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_pie_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142944.4009941-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/pie.h | 2 +- + net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/include/net/pie.h b/include/net/pie.h +index 01cbc66825a40..1f3db0c355149 100644 +--- a/include/net/pie.h ++++ b/include/net/pie.h +@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) + vars->dq_tstamp = DTIME_INVALID; + vars->accu_prob = 0; + vars->dq_count = DQCOUNT_INVALID; +- vars->avg_dq_rate = 0; ++ WRITE_ONCE(vars->avg_dq_rate, 0); + } + + static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb) +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index 48c5ab8ec143c..4c69b44fc3aa8 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -89,7 +89,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + bool enqueue = false; + + if (unlikely(qdisc_qlen(sch) >= sch->limit)) { +- q->stats.overlimit++; ++ WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1); + goto out; + } + +@@ -101,7 +101,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + /* If packet is ecn capable, mark it if drop probability + * is lower than 10%, else drop it. + */ +- q->stats.ecn_mark++; ++ WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1); + enqueue = true; + } + +@@ -111,15 +111,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + if (!q->params.dq_rate_estimator) + pie_set_enqueue_time(skb); + +- q->stats.packets_in++; ++ WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1); + if (qdisc_qlen(sch) > q->stats.maxq) +- q->stats.maxq = qdisc_qlen(sch); ++ WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch)); + + return qdisc_enqueue_tail(skb, sch); + } + + out: +- q->stats.dropped++; ++ WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1); + q->vars.accu_prob = 0; + return qdisc_drop(skb, sch, to_free); + } +@@ -260,11 +260,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, + count = count / dtime; + + if (vars->avg_dq_rate == 0) +- vars->avg_dq_rate = count; ++ WRITE_ONCE(vars->avg_dq_rate, count); + else +- vars->avg_dq_rate = ++ WRITE_ONCE(vars->avg_dq_rate, + (vars->avg_dq_rate - +- (vars->avg_dq_rate >> 3)) + (count >> 3); ++ (vars->avg_dq_rate >> 3)) + (count >> 3)); + + /* If the queue has receded below the threshold, we hold + * on to the last drain rate calculated, else we reset +@@ -374,7 +374,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + if (delta > 0) { + /* prevent overflow */ + if (vars->prob < oldprob) { +- vars->prob = MAX_PROB; ++ WRITE_ONCE(vars->prob, MAX_PROB); + /* Prevent normalization error. If probability is at + * maximum value already, we normalize it here, and + * skip the check to do a non-linear drop in the next +@@ -385,7 +385,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + } else { + /* prevent underflow */ + if (vars->prob > oldprob) +- vars->prob = 0; ++ WRITE_ONCE(vars->prob, 0); + } + + /* Non-linear drop in probability: Reduce drop probability quickly if +@@ -396,7 +396,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + /* Reduce drop probability to 98.4% */ + vars->prob -= vars->prob / 64; + +- vars->qdelay = qdelay; ++ WRITE_ONCE(vars->qdelay, qdelay); + vars->backlog_old = backlog; + + /* We restart the measurement cycle if the following conditions are met +@@ -494,21 +494,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + struct pie_sched_data *q = qdisc_priv(sch); + struct tc_pie_xstats st = { + .prob = q->vars.prob << BITS_PER_BYTE, +- .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / ++ .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) / + NSEC_PER_USEC, +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .maxq = q->stats.maxq, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, ++ .packets_in = READ_ONCE(q->stats.packets_in), ++ .overlimit = READ_ONCE(q->stats.overlimit), ++ .maxq = READ_ONCE(q->stats.maxq), ++ .dropped = READ_ONCE(q->stats.dropped), ++ .ecn_mark = READ_ONCE(q->stats.ecn_mark), + }; + + /* avg_dq_rate is only valid if dq_rate_estimator is enabled */ + st.dq_rate_estimating = q->params.dq_rate_estimator; + + /* unscale and return dq_rate in bytes per sec */ +- if (q->params.dq_rate_estimator) +- st.avg_dq_rate = q->vars.avg_dq_rate * ++ if (st.dq_rate_estimating) ++ st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) * + (PSCHED_TICKS_PER_SEC) >> PIE_SCALE; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch b/queue-6.6/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch new file mode 100644 index 0000000000..bb8deb8a56 --- /dev/null +++ b/queue-6.6/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch @@ -0,0 +1,112 @@ +From a6f01603eba2b0a3ea9a6b0dbe8477621debe464 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:23:09 +0000 +Subject: net/sched: sch_red: annotate data-races in red_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ] + +red_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_red_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142309.3964322-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_red.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index ea3580d1d19e8..5348b61053068 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -89,17 +89,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_PROB_MARK: + qdisc_qstats_overlimit(sch); + if (!red_use_ecn(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +@@ -109,17 +112,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_HARD_MARK: + qdisc_qstats_overlimit(sch); + if (red_use_harddrop(q) || !red_use_ecn(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +@@ -133,7 +139,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->qstats.backlog += len; + sch->q.qlen++; + } else if (net_xmit_drop_count(ret)) { +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, ++ q->stats.pdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -461,9 +468,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, + &hw_stats_request); + } +- st.early = q->stats.prob_drop + q->stats.forced_drop; +- st.pdrop = q->stats.pdrop; +- st.marked = q->stats.prob_mark + q->stats.forced_mark; ++ st.early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop); ++ ++ st.pdrop = READ_ONCE(q->stats.pdrop); ++ ++ st.marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark); + + return gnet_stats_copy_app(d, &st, sizeof(st)); + } +-- +2.53.0 + diff --git a/queue-6.6/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch b/queue-6.6/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch new file mode 100644 index 0000000000..778182849e --- /dev/null +++ b/queue-6.6/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch @@ -0,0 +1,169 @@ +From a2f7ed8406c79d4799a7659a3649a53edcfd5eb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:16:55 +0000 +Subject: net/sched: sch_sfb: annotate data-races in sfb_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ] + +sfb_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_sfb_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260421141655.3953721-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 22 deletions(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index 1871a1c0224d4..ce67826fdf9b6 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen < 0xFFFF) +- b[hash].qlen++; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen > 0) +- b[hash].qlen--; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) + + static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_minus(b->p_mark, q->decrement); ++ WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement)); + } + + static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_plus(b->p_mark, q->increment); ++ WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment)); + } + + static void sfb_zero_all_buckets(struct sfb_sched_data *q) +@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da + const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0]; + + for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) { +- if (qlen < b->qlen) +- qlen = b->qlen; +- totalpm += b->p_mark; +- if (prob < b->p_mark) +- prob = b->p_mark; ++ u32 b_qlen = READ_ONCE(b->qlen); ++ u32 b_mark = READ_ONCE(b->p_mark); ++ ++ if (qlen < b_qlen) ++ qlen = b_qlen; ++ totalpm += b_mark; ++ if (prob < b_mark) ++ prob = b_mark; + b++; + } + *prob_r = prob; +@@ -294,7 +297,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(sch->q.qlen >= q->limit)) { + qdisc_qstats_overlimit(sch); +- q->stats.queuedrop++; ++ WRITE_ONCE(q->stats.queuedrop, ++ q->stats.queuedrop + 1); + goto drop; + } + +@@ -347,7 +351,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(minqlen >= q->max)) { + qdisc_qstats_overlimit(sch); +- q->stats.bucketdrop++; ++ WRITE_ONCE(q->stats.bucketdrop, ++ q->stats.bucketdrop + 1); + goto drop; + } + +@@ -373,7 +378,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + if (sfb_rate_limit(skb, q)) { + qdisc_qstats_overlimit(sch); +- q->stats.penaltydrop++; ++ WRITE_ONCE(q->stats.penaltydrop, ++ q->stats.penaltydrop + 1); + goto drop; + } + goto enqueue; +@@ -388,14 +394,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + * In either case, we want to start dropping packets. + */ + if (r < (p_min - SFB_MAX_PROB / 2) * 2) { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } + if (INET_ECN_set_ce(skb)) { +- q->stats.marked++; ++ WRITE_ONCE(q->stats.marked, ++ q->stats.marked + 1); + } else { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } +@@ -408,7 +417,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->q.qlen++; + increment_qlen(&cb, q); + } else if (net_xmit_drop_count(ret)) { +- q->stats.childdrop++; ++ WRITE_ONCE(q->stats.childdrop, ++ q->stats.childdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -597,12 +607,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct sfb_sched_data *q = qdisc_priv(sch); + struct tc_sfb_xstats st = { +- .earlydrop = q->stats.earlydrop, +- .penaltydrop = q->stats.penaltydrop, +- .bucketdrop = q->stats.bucketdrop, +- .queuedrop = q->stats.queuedrop, +- .childdrop = q->stats.childdrop, +- .marked = q->stats.marked, ++ .earlydrop = READ_ONCE(q->stats.earlydrop), ++ .penaltydrop = READ_ONCE(q->stats.penaltydrop), ++ .bucketdrop = READ_ONCE(q->stats.bucketdrop), ++ .queuedrop = READ_ONCE(q->stats.queuedrop), ++ .childdrop = READ_ONCE(q->stats.childdrop), ++ .marked = READ_ONCE(q->stats.marked), + }; + + st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q); +-- +2.53.0 + diff --git a/queue-6.6/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch b/queue-6.6/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch new file mode 100644 index 0000000000..6e3b81ca27 --- /dev/null +++ b/queue-6.6/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch @@ -0,0 +1,123 @@ +From 17cbbeaac2828eca0f23b2834a94dd7d68c6d5cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:19:58 +0800 +Subject: net/sched: taprio: fix NULL pointer dereference in class dump + +From: Weiming Shi + +[ Upstream commit 3d07ca5c0fae311226f737963984bd94bb159a87 ] + +When a TAPRIO child qdisc is deleted via RTM_DELQDISC, taprio_graft() +is called with new == NULL and stores NULL into q->qdiscs[cl - 1]. +Subsequent RTM_GETTCLASS dump operations walk all classes via +taprio_walk() and call taprio_dump_class(), which calls taprio_leaf() +returning the NULL pointer, then dereferences it to read child->handle, +causing a kernel NULL pointer dereference. + +The bug is reachable with namespace-scoped CAP_NET_ADMIN on any kernel +with CONFIG_NET_SCH_TAPRIO enabled. On systems with unprivileged user +namespaces enabled, an unprivileged local user can trigger a kernel +panic by creating a taprio qdisc inside a new network namespace, +grafting an explicit child qdisc, deleting it, and requesting a class +dump. The RTM_GETTCLASS dump itself requires no capability. + + Oops: general protection fault, probably for non-canonical address 0xdffffc0000000007: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f] + RIP: 0010:taprio_dump_class (net/sched/sch_taprio.c:2478) + Call Trace: + + tc_fill_tclass (net/sched/sch_api.c:1966) + qdisc_class_dump (net/sched/sch_api.c:2326) + taprio_walk (net/sched/sch_taprio.c:2514) + tc_dump_tclass_qdisc (net/sched/sch_api.c:2352) + tc_dump_tclass_root (net/sched/sch_api.c:2370) + tc_dump_tclass (net/sched/sch_api.c:2431) + rtnl_dumpit (net/core/rtnetlink.c:6864) + netlink_dump (net/netlink/af_netlink.c:2325) + rtnetlink_rcv_msg (net/core/rtnetlink.c:6959) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Fix this by substituting &noop_qdisc when new is NULL in +taprio_graft(), a common pattern used by other qdiscs (e.g., +multiq_graft()) to ensure the q->qdiscs[] slots are never NULL. +This makes control-plane dump paths safe without requiring individual +NULL checks. + +Since the data-plane paths (taprio_enqueue and taprio_dequeue_from_txq) +previously had explicit NULL guards that would drop/skip the packet +cleanly, update those checks to test for &noop_qdisc instead. Without +this, packets would reach taprio_enqueue_one() which increments the root +qdisc's qlen and backlog before calling the child's enqueue; noop_qdisc +drops the packet but those counters are never rolled back, permanently +inflating the root qdisc's statistics. + +After this change *old can be a valid qdisc, NULL, or &noop_qdisc. +Only call qdisc_put(*old) in the first case to avoid decreasing +noop_qdisc's refcount, which was never increased. + +Fixes: 665338b2a7a0 ("net/sched: taprio: dump class stats for the actual q->qdiscs[]") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Acked-by: Jamal Hadi Salim +Tested-by: Weiming Shi +Link: https://patch.msgid.link/20260422161958.2517539-3-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 6df93d5c2e9d9..c14f9e2d8dc51 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -644,7 +644,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + queue = skb_get_queue_mapping(skb); + + child = q->qdiscs[queue]; +- if (unlikely(!child)) ++ if (unlikely(child == &noop_qdisc)) + return qdisc_drop(skb, sch, to_free); + + if (taprio_skb_exceeds_queue_max_sdu(sch, skb)) { +@@ -727,7 +727,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, + int len; + u8 tc; + +- if (unlikely(!child)) ++ if (unlikely(child == &noop_qdisc)) + return NULL; + + if (TXTIME_ASSIST_IS_ENABLED(q->flags)) +@@ -2214,6 +2214,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + if (!dev_queue) + return -EINVAL; + ++ if (!new) ++ new = &noop_qdisc; ++ + if (dev->flags & IFF_UP) + dev_deactivate(dev); + +@@ -2227,14 +2230,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + *old = q->qdiscs[cl - 1]; + if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { + WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old); +- if (new) ++ if (new != &noop_qdisc) + qdisc_refcount_inc(new); +- if (*old) ++ if (*old && *old != &noop_qdisc) + qdisc_put(*old); + } + + q->qdiscs[cl - 1] = new; +- if (new) ++ if (new != &noop_qdisc) + new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; + + if (dev->flags & IFF_UP) +-- +2.53.0 + diff --git a/queue-6.6/net-sched-taprio-fix-use-after-free-in-advance_sched.patch b/queue-6.6/net-sched-taprio-fix-use-after-free-in-advance_sched.patch new file mode 100644 index 0000000000..d96e0b8510 --- /dev/null +++ b/queue-6.6/net-sched-taprio-fix-use-after-free-in-advance_sched.patch @@ -0,0 +1,60 @@ +From 72fc0ffca121650039ba345a77af0d41128a5089 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 18:57:57 -0700 +Subject: net/sched: taprio: fix use-after-free in advance_sched() on schedule + switch + +From: Vinicius Costa Gomes + +[ Upstream commit 105425b1969c5affe532713cfac1c0b320d7ac2b ] + +In advance_sched(), when should_change_schedules() returns true, +switch_schedules() is called to promote the admin schedule to oper. +switch_schedules() queues the old oper schedule for RCU freeing via +call_rcu(), but 'next' still points into an entry of the old oper +schedule. The subsequent 'next->end_time = end_time' and +rcu_assign_pointer(q->current_entry, next) are use-after-free. + +Fix this by selecting 'next' from the new oper schedule immediately +after switch_schedules(), and using its pre-calculated end_time. +setup_first_end_time() sets the first entry's end_time to +base_time + interval when the schedule is installed, so the value +is already correct. + +The deleted 'end_time = sched_base_time(admin)' assignment was also +harmful independently: it would overwrite the new first entry's +pre-calculated end_time with just base_time. + +Fixes: a3d43c0d56f1 ("taprio: Add support adding an admin schedule") +Reported-by: Junxi Qian +Signed-off-by: Vinicius Costa Gomes +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index a01d17d03bf57..6df93d5c2e9d9 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -982,11 +982,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + } + + if (should_change_schedules(admin, oper, end_time)) { +- /* Set things so the next time this runs, the new +- * schedule runs. +- */ +- end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); ++ /* After changing schedules, the next entry is the first one ++ * in the new schedule, with a pre-calculated end_time. ++ */ ++ next = list_first_entry(&oper->entries, struct sched_entry, list); ++ end_time = next->end_time; + } + + next->end_time = end_time; +-- +2.53.0 + diff --git a/queue-6.6/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch b/queue-6.6/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch new file mode 100644 index 0000000000..d2c30f7305 --- /dev/null +++ b/queue-6.6/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch @@ -0,0 +1,90 @@ +From fd2435e3c4e3690055711d8027fec08ffd46a166 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:15:59 -0700 +Subject: net: tls: fix strparser anchor skb leak on offload RX setup failure + +From: Jakub Kicinski + +[ Upstream commit 58689498ca3384851145a754dbb1d8ed1cf9fb54 ] + +When tls_set_device_offload_rx() fails at tls_dev_add(), the error path +calls tls_sw_free_resources_rx() to clean up the SW context that was +initialized by tls_set_sw_offload(). This function calls +tls_sw_release_resources_rx() (which stops the strparser via +tls_strp_stop()) and tls_sw_free_ctx_rx() (which kfrees the context), +but never frees the anchor skb that was allocated by alloc_skb(0) in +tls_strp_init(). + +Note that tls_sw_free_resources_rx() is exclusively used for this +"failed to start offload" code path, there's no other caller. + +The leak did not exist before commit 84c61fe1a75b ("tls: rx: do not use +the standard strparser"), because the standard strparser doesn't try +to pre-allocate an skb. + +The normal close path in tls_sk_proto_close() handles cleanup by calling +tls_sw_strparser_done() (which calls tls_strp_done()) after dropping +the socket lock, because tls_strp_done() does cancel_work_sync() and +the strparser work handler takes the socket lock. + +Fixes: 84c61fe1a75b ("tls: rx: do not use the standard strparser") +Signed-off-by: Jakub Kicinski +Reviewed-by: Vadim Fedorenko +Link: https://patch.msgid.link/20260428231559.1358502-1-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls.h | 1 + + net/tls/tls_strp.c | 6 ++++++ + net/tls/tls_sw.c | 4 ++++ + 3 files changed, 11 insertions(+) + +diff --git a/net/tls/tls.h b/net/tls/tls.h +index a3c5c5a59fda6..718508e923eec 100644 +--- a/net/tls/tls.h ++++ b/net/tls/tls.h +@@ -183,6 +183,7 @@ int tls_strp_dev_init(void); + void tls_strp_dev_exit(void); + + void tls_strp_done(struct tls_strparser *strp); ++void __tls_strp_done(struct tls_strparser *strp); + void tls_strp_stop(struct tls_strparser *strp); + int tls_strp_init(struct tls_strparser *strp, struct sock *sk); + void tls_strp_data_ready(struct tls_strparser *strp); +diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c +index ae723cd6af397..7d85feebdfd93 100644 +--- a/net/tls/tls_strp.c ++++ b/net/tls/tls_strp.c +@@ -623,6 +623,12 @@ void tls_strp_done(struct tls_strparser *strp) + WARN_ON(!strp->stopped); + + cancel_work_sync(&strp->work); ++ __tls_strp_done(strp); ++} ++ ++/* For setup error paths where the strparser was initialized but never armed. */ ++void __tls_strp_done(struct tls_strparser *strp) ++{ + tls_strp_anchor_free(strp); + } + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index d86a487065e92..937aa78eed0e4 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -2595,8 +2595,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx) + void tls_sw_free_resources_rx(struct sock *sk) + { + struct tls_context *tls_ctx = tls_get_ctx(sk); ++ struct tls_sw_context_rx *ctx; ++ ++ ctx = tls_sw_ctx_rx(tls_ctx); + + tls_sw_release_resources_rx(sk); ++ __tls_strp_done(&ctx->strp); + tls_sw_free_ctx_rx(tls_ctx); + } + +-- +2.53.0 + diff --git a/queue-6.6/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch b/queue-6.6/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch new file mode 100644 index 0000000000..6ec0e8726a --- /dev/null +++ b/queue-6.6/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch @@ -0,0 +1,89 @@ +From fe61e0f7298a9e37077025f5096f5054eb4503c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 08:49:12 +0800 +Subject: net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit() + +From: Zhan Jun + +[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ] + +syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() +when accessing skb->len for tx statistics after usb_submit_urb() has +been called: + + BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760 + drivers/net/usb/rtl8150.c:712 + Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226 + +The URB completion handler write_bulk_callback() frees the skb via +dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU +in softirq context before usb_submit_urb() returns in the submitter, +so by the time the submitter reads skb->len the skb has already been +queued to the per-CPU completion_queue and freed by net_tx_action(): + + CPU A (xmit) CPU B (USB completion softirq) + ------------ ------------------------------ + dev->tx_skb = skb; + usb_submit_urb() --+ + |-------> write_bulk_callback() + | dev_kfree_skb_irq(dev->tx_skb) + | net_tx_action() + | napi_skb_cache_put() <-- free + netdev->stats.tx_bytes | + += skb->len; <-- UAF read + +Fix it by caching skb->len before submitting the URB and using the +cached value when updating the tx_bytes counter. + +The pre-existing tx_bytes semantics are preserved: the counter tracks +the original frame length (skb->len), not the ETH_ZLEN/USB-alignment +padded "count" value that is handed to the device. Changing that +would be a user-visible accounting change and is out of scope for +this UAF fix. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+3f46c095ac0ca048cb71@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e69ee7.050a0220.24bfd3.002b.GAE@google.com/ +Closes: https://syzkaller.appspot.com/bug?extid=3f46c095ac0ca048cb71 +Reviewed-by: Andrew Lunn +Signed-off-by: Zhan Jun +Link: https://patch.msgid.link/809895186B866C10+20260423004913.136655-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index e40b0669d9f4b..8700ae392b10a 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + rtl8150_t *dev = netdev_priv(netdev); ++ unsigned int skb_len; + int count, res; + + /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ +@@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + ++ skb_len = skb->len; ++ + netif_stop_queue(netdev); + dev->tx_skb = skb; + usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), +@@ -711,7 +714,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + } + } else { + netdev->stats.tx_packets++; +- netdev->stats.tx_bytes += skb->len; ++ netdev->stats.tx_bytes += skb_len; + netif_trans_update(netdev); + } + +-- +2.53.0 + diff --git a/queue-6.6/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch b/queue-6.6/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch new file mode 100644 index 0000000000..15a09d0719 --- /dev/null +++ b/queue-6.6/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch @@ -0,0 +1,61 @@ +From 94afaecbc03b6eeb67c9544b1e1fa5e411e1ef2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 09:55:17 +0800 +Subject: net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit + +From: Morduan Zang + +[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ] + +When rtl8150_start_xmit() fails to submit the tx URB, the URB is never +handed to the USB core and write_bulk_callback() will not run. The +driver returns NETDEV_TX_OK, which tells the networking stack that the +skb has been consumed, but nothing actually frees the skb on this +error path: + + dev->tx_skb = skb; + ... + if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { + ... + /* no kfree_skb here */ + } + return NETDEV_TX_OK; + +This leaks the skb on every submit failure and also leaves dev->tx_skb +pointing at memory that the driver itself may later free, which is +fragile. + +Free the skb with dev_kfree_skb_any() in the error path and clear +dev->tx_skb so no stale pointer is left behind. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reviewed-by: Andrew Lunn +Signed-off-by: Morduan Zang +Link: https://patch.msgid.link/E7D3E1C013C5A859+20260424015517.9574-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 8700ae392b10a..647f28b367b99 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -712,6 +712,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } ++ /* ++ * The URB was not submitted, so write_bulk_callback() will ++ * never run to free dev->tx_skb. Drop the skb here and ++ * clear tx_skb to avoid leaving a stale pointer. ++ */ ++ dev->tx_skb = NULL; ++ dev_kfree_skb_any(skb); + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb_len; +-- +2.53.0 + diff --git a/queue-6.6/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch b/queue-6.6/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch new file mode 100644 index 0000000000..3d3f8b57e8 --- /dev/null +++ b/queue-6.6/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch @@ -0,0 +1,92 @@ +From 69b522e436521f19fcb489c4d08a16715f7b2b39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:33:49 +0000 +Subject: net_sched: sch_hhf: annotate data-races in hhf_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ] + +hhf_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421143349.4052215-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_hhf.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index 83fc44f20e31c..67b555c02f2c0 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash, + return NULL; + list_del(&flow->flowchain); + kfree(flow); +- q->hh_flows_current_cnt--; ++ WRITE_ONCE(q->hh_flows_current_cnt, ++ q->hh_flows_current_cnt - 1); + } else if (flow->hash_id == hash) { + return flow; + } +@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + } + + if (q->hh_flows_current_cnt >= q->hh_flows_limit) { +- q->hh_flows_overlimit++; ++ WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); + return NULL; + } + /* Create new entry. */ +@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + if (!flow) + return NULL; + +- q->hh_flows_current_cnt++; ++ WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); + INIT_LIST_HEAD(&flow->flowchain); + list_add_tail(&flow->flowchain, head); + +@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) + return WDRR_BUCKET_FOR_NON_HH; + flow->hash_id = hash; + flow->hit_timestamp = now; +- q->hh_flows_total_cnt++; ++ WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); + + /* By returning without updating counters in q->hhf_arrays, + * we implicitly implement "shielding" (see Optimization O1). +@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + + prev_backlog = sch->qstats.backlog; +- q->drop_overlimit++; ++ WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); + /* Return Congestion Notification only if we dropped a packet from this + * bucket. + */ +@@ -678,10 +679,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct hhf_sched_data *q = qdisc_priv(sch); + struct tc_hhf_xstats st = { +- .drop_overlimit = q->drop_overlimit, +- .hh_overlimit = q->hh_flows_overlimit, +- .hh_tot_count = q->hh_flows_total_cnt, +- .hh_cur_count = q->hh_flows_current_cnt, ++ .drop_overlimit = READ_ONCE(q->drop_overlimit), ++ .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), ++ .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), ++ .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-6.6/netconsole-propagate-device-name-truncation-in-dev_n.patch b/queue-6.6/netconsole-propagate-device-name-truncation-in-dev_n.patch new file mode 100644 index 0000000000..7a39335947 --- /dev/null +++ b/queue-6.6/netconsole-propagate-device-name-truncation-in-dev_n.patch @@ -0,0 +1,58 @@ +From 1f82489f73187b0cbdbeb7c54b88dc893a973957 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 07:30:37 -0700 +Subject: netconsole: propagate device name truncation in dev_name_store() + +From: Breno Leitao + +[ Upstream commit 92ceb7bff62c2606f664c204750eca0b85d44112 ] + +dev_name_store() calls strscpy(nt->np.dev_name, buf, IFNAMSIZ) without +checking the return value. If userspace writes an interface name longer +than IFNAMSIZ - 1, strscpy() silently truncates and returns -E2BIG, but +the function ignores it and reports a fully successful write back to +userspace. + +If a real interface happens to match the truncated name, netconsole will +bind to the wrong device on the next enable, sending kernel logs and +panic output to an unintended network segment with no indication to +userspace that anything was rewritten. + +Reject writes whose length cannot fit in nt->np.dev_name up front: + + if (count >= IFNAMSIZ) + return -ENAMETOOLONG; + +This is not a big deal of a problem, but, it is still the correct +approach. + +Fixes: 0bcc1816188e57 ("[NET] netconsole: Support dynamic reconfiguration using configfs") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-3-59965f29d9cc@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 2045872de5328..f58643bdafc5c 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -476,6 +476,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + size_t count) + { + struct netconsole_target *nt = to_target(item); ++ size_t len = count; ++ ++ /* Account for a trailing newline appended by tools like echo */ ++ if (len && buf[len - 1] == '\n') ++ len--; ++ if (len >= IFNAMSIZ) ++ return -ENAMETOOLONG; + + mutex_lock(&dynamic_netconsole_mutex); + if (nt->enabled) { +-- +2.53.0 + diff --git a/queue-6.6/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch b/queue-6.6/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch new file mode 100644 index 0000000000..db1ed42a0a --- /dev/null +++ b/queue-6.6/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch @@ -0,0 +1,43 @@ +From ce218e5cb09c3b4201732dd34dc34065fe560c3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 23:14:34 +0300 +Subject: netdevsim: zero initialize struct iphdr in dummy sk_buff + +From: Nikola Z. Ivanov + +[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ] + +Syzbot reports a KMSAN uninit-value originating from +nsim_dev_trap_skb_build, with the allocation also +being performed in the same function. + +Fix this by calling skb_put_zero instead of skb_put to +guarantee zero initialization of the whole IP header. + +Closes: https://syzkaller.appspot.com/bug?extid=23d7fcd204e3837866ff +Fixes: da58f90f11f5 ("netdevsim: Add devlink-trap support") +Signed-off-by: Nikola Z. Ivanov +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426201434.742030-1-zlatistiv@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netdevsim/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c +index 2614d6509954c..daec92570c2e3 100644 +--- a/drivers/net/netdevsim/dev.c ++++ b/drivers/net/netdevsim/dev.c +@@ -758,7 +758,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) + skb->protocol = htons(ETH_P_IP); + + skb_set_network_header(skb, skb->len); +- iph = skb_put(skb, sizeof(struct iphdr)); ++ iph = skb_put_zero(skb, sizeof(struct iphdr)); + iph->protocol = IPPROTO_UDP; + iph->saddr = in_aton("192.0.2.1"); + iph->daddr = in_aton("198.51.100.1"); +-- +2.53.0 + diff --git a/queue-6.6/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch b/queue-6.6/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch new file mode 100644 index 0000000000..1160147165 --- /dev/null +++ b/queue-6.6/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch @@ -0,0 +1,126 @@ +From e3d5af9d8e6bdd767de82771dada0f8301190066 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:15:32 +0200 +Subject: netfilter: arp_tables: fix IEEE1394 ARP payload parsing + +From: Pablo Neira Ayuso + +[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ] + +Weiming Shi says: + +"arp_packet_match() unconditionally parses the ARP payload assuming two +hardware addresses are present (source and target). However, +IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address +field, and arp_hdr_len() already accounts for this by returning a +shorter length for ARPHRD_IEEE1394 devices. + +As a result, on IEEE1394 interfaces arp_packet_match() advances past a +nonexistent target hardware address and reads the wrong bytes for both +the target device address comparison and the target IP address. This +causes arptables rules to match against garbage data, leading to +incorrect filtering decisions: packets that should be accepted may be +dropped and vice versa. + +The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already +handles this correctly by skipping the target hardware address for +ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()." + +Mangle the original patch to always return 0 (no match) in case user +matches on the target hardware address which is never present in +IEEE1394. + +Note that this returns 0 (no match) for either normal and inverse match +because matching in the target hardware address in ARPHRD_IEEE1394 has +never been supported by arptables. This is intentional, matching on the +target hardware address should never evaluate true for ARPHRD_IEEE1394. + +Moreover, adjust arpt_mangle to drop the packet too as AI suggests: + +In arpt_mangle, the logic assumes a standard ARP layout. Because +IEEE1394 (FireWire) omits the target hardware address, the linear +pointer arithmetic miscalculates the offset for the target IP address. +This causes mangling operations to write to the wrong location, leading +to packet corruption. To ensure safety, this patch drops packets +(NF_DROP) when mangling is requested for these fields on IEEE1394 +devices, as the current implementation cannot correctly map the FireWire +ARP payload. + +This omits both mangling target hardware and IP address. Even if IP +address mangling should be possible in IEEE1394, this would require +to adjust arpt_mangle offset calculation, which has never been +supported. + +Based on patch from Weiming Shi . + +Fixes: 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.") +Reported-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- + net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 14365b20f1c5c..564054123772a 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, + arpptr += dev->addr_len; + memcpy(&src_ipaddr, arpptr, sizeof(u32)); + arpptr += sizeof(u32); +- tgt_devaddr = arpptr; +- arpptr += dev->addr_len; ++ ++ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { ++ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, ++ sizeof(arpinfo->tgt_devaddr.mask)))) ++ return 0; ++ ++ tgt_devaddr = NULL; ++ } else { ++ tgt_devaddr = arpptr; ++ arpptr += dev->addr_len; ++ } + memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); + + if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, + arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, +- dev->addr_len)) || ++ dev->addr_len))) ++ return 0; ++ ++ if (tgt_devaddr && + NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, + arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, + dev->addr_len))) +diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c +index a4e07e5e9c118..f65dd339208e8 100644 +--- a/net/ipv4/netfilter/arpt_mangle.c ++++ b/net/ipv4/netfilter/arpt_mangle.c +@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += pln; + if (mangle->flags & ARPT_MANGLE_TDEV) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_DEV_ADDR_LEN_MAX < hln || + (arpptr + hln > skb_tail_pointer(skb))) + return NF_DROP; +@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += hln; + if (mangle->flags & ARPT_MANGLE_TIP) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_MANGLE_ADDR_LEN_MAX < pln || + (arpptr + pln > skb_tail_pointer(skb))) + return NF_DROP; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-conntrack-remove-sprintf-usage.patch b/queue-6.6/netfilter-conntrack-remove-sprintf-usage.patch new file mode 100644 index 0000000000..4e200f43f2 --- /dev/null +++ b/queue-6.6/netfilter-conntrack-remove-sprintf-usage.patch @@ -0,0 +1,182 @@ +From e7da2e17bb47c8dbcac4f9fb9ae146cdf9ab92b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 19:13:46 +0200 +Subject: netfilter: conntrack: remove sprintf usage + +From: Florian Westphal + +[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ] + +Replace it with scnprintf, the buffer sizes are expected to be large enough +to hold the result, no need for snprintf+overflow check. + +Increase buffer size in mangle_content_len() while at it. + +BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 +Write of size 1 at addr [..] + vsnprintf+0xea5/0x1270 + sprintf+0xb1/0xe0 + mangle_content_len+0x1ac/0x280 + nf_nat_sdp_session+0x1cc/0x240 + process_sdp+0x8f8/0xb80 + process_invite_request+0x108/0x2b0 + process_sip_msg+0x5da/0xf50 + sip_help_tcp+0x45e/0x780 + nf_confirm+0x34d/0x990 + [..] + +Fixes: 9fafcd7b2032 ("[NETFILTER]: nf_conntrack/nf_nat: add SIP helper port") +Reported-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_nat_amanda.c | 2 +- + net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c +index 98deef6cde694..8f1054920a857 100644 +--- a/net/netfilter/nf_nat_amanda.c ++++ b/net/netfilter/nf_nat_amanda.c +@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb, + return NF_DROP; + } + +- sprintf(buffer, "%u", port); ++ snprintf(buffer, sizeof(buffer), "%u", port); + if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, + protoff, matchoff, matchlen, + buffer, strlen(buffer))) { +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index cf4aeb299bdef..c845b6d1a2bdf 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, + } + + static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, bool delim) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4", &addr->ip); ++ return scnprintf(buffer, size, "%pI4", &addr->ip); + else { + if (delim) +- return sprintf(buffer, "[%pI6c]", &addr->ip6); ++ return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); + else +- return sprintf(buffer, "%pI6c", &addr->ip6); ++ return scnprintf(buffer, size, "%pI6c", &addr->ip6); + } + } + + static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, u16 port) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4:%u", &addr->ip, port); ++ return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port); + else +- return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); ++ return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); + } + + static int map_addr(struct sk_buff *skb, unsigned int protoff, +@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, + if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) + return 1; + +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, true) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.dst.u3, + true); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, false) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.src.u3, + false); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +- buflen = sprintf(buffer, "%u", ntohs(p)); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle rport"); +@@ -418,7 +420,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, + + if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), ++ &newaddr, port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle packet"); +@@ -438,8 +441,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++ char buffer[sizeof("4294967295")]; + unsigned int matchoff, matchlen; +- char buffer[sizeof("65536")]; + int buflen, c_len; + + /* Get actual SDP length */ +@@ -454,7 +457,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + return 0; + +- buflen = sprintf(buffer, "%u", c_len); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -491,7 +494,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, + char buffer[INET6_ADDRSTRLEN]; + unsigned int buflen; + +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, + sdpoff, type, term, buffer, buflen)) + return 0; +@@ -509,7 +512,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + +- buflen = sprintf(buffer, "%u", port); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) + return 0; +@@ -529,7 +532,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, + SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) + return 0; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch b/queue-6.6/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch new file mode 100644 index 0000000000..8f0d489f1e --- /dev/null +++ b/queue-6.6/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch @@ -0,0 +1,352 @@ +From 943cabe0c0553f3b594ffc73747cda653780b86e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 02:19:11 +0200 +Subject: netfilter: nf_conntrack_sip: don't use simple_strtoul +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Florian Westphal + +[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ] + +Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), +and ct_sip_parse_request() with a new sip_parse_port() helper that +validates each digit against the buffer limit, eliminating the use of +simple_strtoul() which assumes NUL-terminated strings. + +The previous code dereferenced pointers without bounds checks after +sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated +skb data. A port that reaches the buffer limit without a trailing +character is also rejected as malformed. + +Also get rid of all simple_strtoul() usage in conntrack, prefer a +stricter version instead. There are intentional changes: + +- Bail out if number is > UINT_MAX and indicate a failure, same for + too long sequences. + While we do accept 05535 as port 5535, we will not accept e.g. + 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, + we should restrict this to not waste cycles when presented with + malformed packets with 64k '0' characters. + +- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch + 'expire=' and 'rports='; both are expected to use base-10. + +- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k + range. + +- epaddr_len now returns 0 if the port is invalid, as it already does + for invalid ip addresses. This is intentional. nf_conntrack_sip + performs lots of guesswork to find the right parts of the message + to parse. Being stricter could break existing setups. + Connection tracking helpers are designed to allow traffic to + pass, not to block it. + +Based on an earlier patch from Jenny Guanni Qu . + +Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper") +Reported-by: Klaudia Kloc +Reported-by: Dawid Moczadło +Reported-by: Jenny Guanni Qu . +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- + net/netfilter/nf_nat_sip.c | 1 + + 2 files changed, 119 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index fda6fc1fc4c58..4b32ee408ea15 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, + return 1; + } + ++/* Parse optional port number after IP address. ++ * Returns false on malformed input, true otherwise. ++ * If port is non-NULL, stores parsed port in network byte order. ++ * If no port is present, sets *port to default SIP port. ++ */ ++static bool sip_parse_port(const char *dptr, const char **endp, ++ const char *limit, __be16 *port) ++{ ++ unsigned int p = 0; ++ int len = 0; ++ ++ if (dptr >= limit) ++ return false; ++ ++ if (*dptr != ':') { ++ if (port) ++ *port = htons(SIP_PORT); ++ if (endp) ++ *endp = dptr; ++ return true; ++ } ++ ++ dptr++; /* skip ':' */ ++ ++ while (dptr < limit && isdigit(*dptr)) { ++ p = p * 10 + (*dptr - '0'); ++ dptr++; ++ len++; ++ if (len > 5) /* max "65535" */ ++ return false; ++ } ++ ++ if (len == 0) ++ return false; ++ ++ /* reached limit while parsing port */ ++ if (dptr >= limit) ++ return false; ++ ++ if (p < 1024 || p > 65535) ++ return false; ++ ++ if (port) ++ *port = htons(p); ++ ++ if (endp) ++ *endp = dptr; ++ ++ return true; ++} ++ + /* skip ip address. returns its length. */ + static int epaddr_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, + return 0; + } + +- /* Port number */ +- if (*dptr == ':') { +- dptr++; +- dptr += digits_len(ct, dptr, limit, shift); +- } ++ if (!sip_parse_port(dptr, &dptr, limit, NULL)) ++ return 0; + return dptr - aux; + } + +@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, + return epaddr_len(ct, dptr, limit, shift); + } + ++/* simple_strtoul stops after first non-number character. ++ * But as we're not dealing with c-strings, we can't rely on ++ * hitting \r,\n,\0 etc. before moving past end of buffer. ++ * ++ * This is a variant of simple_strtoul, but doesn't require ++ * a c-string. ++ * ++ * If value exceeds UINT_MAX, 0 is returned. ++ */ ++static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) ++{ ++ const unsigned int max = sizeof("4294967295"); ++ unsigned int olen = len; ++ const char *s = cp; ++ u64 result = 0; ++ ++ if (len > max) ++ len = max; ++ ++ while (olen > 0 && isdigit(*s)) { ++ unsigned int value; ++ ++ if (len == 0) ++ goto err; ++ ++ value = *s - '0'; ++ result = result * 10 + value; ++ ++ if (result > UINT_MAX) ++ goto err; ++ s++; ++ len--; ++ olen--; ++ } ++ ++ if (endp) ++ *endp = (char *)s; ++ ++ return result; ++err: ++ if (endp) ++ *endp = (char *)cp; ++ return 0; ++} ++ + /* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF +@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, + { + const char *start = dptr, *limit = dptr + datalen, *end; + unsigned int mlen; +- unsigned int p; + int shift = 0; + + /* Skip method and following whitespace */ +@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, + + if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) + return -1; +- if (end < limit && *end == ':') { +- end++; +- p = simple_strtoul(end, (char **)&end, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(end, &end, limit, port)) ++ return -1; + + if (end == dptr) + return 0; +@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + union nf_inet_addr *addr, __be16 *port) + { + const char *c, *limit = dptr + datalen; +- unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, +@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + + if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) + return -1; +- if (*c == ':') { +- c++; +- p = simple_strtoul(c, (char **)&c, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(c, &c, limit, port)) ++ return -1; + + if (dataoff) + *dataoff = c - dptr; +@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + return 0; + + start += strlen(name); +- *val = simple_strtoul(start, &end, 0); ++ *val = sip_strtouint(start, limit - start, (char **)&end); + if (start == end) + return -1; + if (matchoff && matchlen) { +@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { ++ char *end; ++ + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) +@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + mediaoff += t->len; + medialen -= t->len; + +- port = simple_strtoul(*dptr + mediaoff, NULL, 10); +- if (port == 0) ++ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); ++ if (port == 0 || *dptr + mediaoff == end) + continue; + if (port < 1024 || port > 65535) { + nf_ct_helper_log(skb, ct, "wrong port %u", port); +@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, +@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + while (1) { + unsigned int c_expires = expires; +@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen, matchend; + unsigned int code, cseq, i; ++ char *end; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; +- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); ++ code = sip_strtouint(*dptr + strlen("SIP/2.0 "), ++ *datalen - strlen("SIP/2.0 "), NULL); + if (!code) { + nf_ct_helper_log(skb, ct, "cannot get code"); + return NF_DROP; +@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; ++ char *end; + + handler = &sip_handlers[i]; + if (handler->request == NULL) +@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + break; + +- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); ++ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); + if (dptr + matchoff == end) + break; + +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index c845b6d1a2bdf..9fbfc6bff0c22 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, + "rport=", &poff, &plen, + &n) > 0 && ++ n >= 1024 && n <= 65535 && + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch b/queue-6.6/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch new file mode 100644 index 0000000000..d3c4e63d68 --- /dev/null +++ b/queue-6.6/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch @@ -0,0 +1,67 @@ +From f9272e732123d11324b7a662ff61da9a907726d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:14:01 -0700 +Subject: netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO + +From: Xiang Mei + +[ Upstream commit 2195574dc6d9017d32ac346987e12659f931d932 ] + +nf_osf_match_one() computes ctx->window % f->wss.val in the +OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A +CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a +subsequent matching TCP SYN divides by zero and panics the kernel. + +Reject the bogus fingerprint in nfnl_osf_add_callback() above the +per-option for-loop. f->wss is per-fingerprint, not per-option, so +the check must run regardless of f->opt_num (including 0). Also +reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that +as "should not happen". + +Crash: + Oops: divide error: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) + Call Trace: + + nf_osf_match (net/netfilter/nfnetlink_osf.c:220) + xt_osf_match_packet (net/netfilter/xt_osf.c:32) + ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) + nf_hook_slow (net/netfilter/core.c:622) + ip_local_deliver (net/ipv4/ip_input.c:265) + ip_rcv (include/linux/skbuff.h:1162) + __netif_receive_skb_one_core (net/core/dev.c:6181) + process_backlog (net/core/dev.c:6642) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7945) + handle_softirqs (kernel/softirq.c:622) + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Weiming Shi +Suggested-by: Florian Westphal +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Xiang Mei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index da9d5d6de98f4..000a5c280ef96 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, + if (f->opt_num > ARRAY_SIZE(f->opt)) + return -EINVAL; + ++ if (f->wss.wc >= OSF_WSS_MAX || ++ (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) ++ return -EINVAL; ++ + for (i = 0; i < f->opt_num; i++) { + if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch b/queue-6.6/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch new file mode 100644 index 0000000000..b53c7b90e9 --- /dev/null +++ b/queue-6.6/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch @@ -0,0 +1,100 @@ +From 676d9e113a65b4ddfc22bb929f77101f968899d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:56 +0200 +Subject: netfilter: nfnetlink_osf: fix out-of-bounds read on option matching + +From: Fernando Fernandez Mancera + +[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ] + +In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once +and passed by reference to nf_osf_match_one() for each fingerprint +checked. During TCP option parsing, nf_osf_match_one() advances the +shared ctx->optp pointer. + +If a fingerprint perfectly matches, the function returns early without +restoring ctx->optp to its initial state. If the user has configured +NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. +However, because ctx->optp was not restored, the next call to +nf_osf_match_one() starts parsing from the end of the options buffer. +This causes subsequent matches to read garbage data and fail +immediately, making it impossible to log more than one match or logging +incorrect matches. + +Instead of using a shared ctx->optp pointer, pass the context as a +constant pointer and use a local pointer (optp) for TCP option +traversal. This makes nf_osf_match_one() strictly stateless from the +caller's perspective, ensuring every fingerprint check starts at the +correct option offset. + +Fixes: 1a6a0951fc00 ("netfilter: nfnetlink_osf: add missing fmatch check") +Suggested-by: Florian Westphal +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 000a5c280ef96..2207bda442d54 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx { + static bool nf_osf_match_one(const struct sk_buff *skb, + const struct nf_osf_user_finger *f, + int ttl_check, +- struct nf_osf_hdr_ctx *ctx) ++ const struct nf_osf_hdr_ctx *ctx) + { +- const __u8 *optpinit = ctx->optp; ++ const __u8 *optp = ctx->optp; + unsigned int check_WSS = 0; + int fmatch = FMATCH_WRONG; + int foptsize, optnum; +@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { +- if (f->opt[optnum].kind == *ctx->optp) { ++ if (f->opt[optnum].kind == *optp) { + __u32 len = f->opt[optnum].length; +- const __u8 *optend = ctx->optp + len; ++ const __u8 *optend = optp + len; + + fmatch = FMATCH_OK; + +- switch (*ctx->optp) { ++ switch (*optp) { + case OSFOPT_MSS: +- mss = ctx->optp[3]; ++ mss = optp[3]; + mss <<= 8; +- mss |= ctx->optp[2]; ++ mss |= optp[2]; + + mss = ntohs((__force __be16)mss); + break; +@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + break; + } + +- ctx->optp = optend; ++ optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + +@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + } + } + +- if (fmatch != FMATCH_OK) +- ctx->optp = optpinit; +- + return fmatch == FMATCH_OK; + } + +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch b/queue-6.6/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch new file mode 100644 index 0000000000..f4b987990f --- /dev/null +++ b/queue-6.6/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch @@ -0,0 +1,74 @@ +From 7aa78466c8c3a87b906cb831812113e5ba0d0978 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:57 +0200 +Subject: netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check + +From: Fernando Fernandez Mancera + +[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ] + +The nf_osf_ttl() function accessed skb->dev to perform a local interface +address lookup without verifying that the device pointer was valid. + +Additionally, the implementation utilized an in_dev_for_each_ifa_rcu +loop to match the packet source address against local interface +addresses. It assumed that packets from the same subnet should not see a +decrement on the initial TTL. A packet might appear it is from the same +subnet but it actually isn't especially in modern environments with +containers and virtual switching. + +Remove the device dereference and interface loop. Replace the logic with +a switch statement that evaluates the TTL according to the ttl_check. + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Kito Xu (veritas501) +Closes: https://lore.kernel.org/netfilter-devel/20260414074556.2512750-1-hxzene@gmail.com/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 2207bda442d54..6d3dfbeb398cb 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); + static inline int nf_osf_ttl(const struct sk_buff *skb, + int ttl_check, unsigned char f_ttl) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + const struct iphdr *ip = ip_hdr(skb); +- const struct in_ifaddr *ifa; +- int ret = 0; + +- if (ttl_check == NF_OSF_TTL_TRUE) ++ switch (ttl_check) { ++ case NF_OSF_TTL_TRUE: + return ip->ttl == f_ttl; +- if (ttl_check == NF_OSF_TTL_NOCHECK) +- return 1; +- else if (ip->ttl <= f_ttl) ++ break; ++ case NF_OSF_TTL_NOCHECK: + return 1; +- +- in_dev_for_each_ifa_rcu(ifa, in_dev) { +- if (inet_ifa_match(ip->saddr, ifa)) { +- ret = (ip->ttl == f_ttl); +- break; +- } ++ case NF_OSF_TTL_LESS: ++ default: ++ return ip->ttl <= f_ttl; + } +- +- return ret; + } + + struct nf_osf_hdr_ctx { +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch b/queue-6.6/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch new file mode 100644 index 0000000000..56905ce928 --- /dev/null +++ b/queue-6.6/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch @@ -0,0 +1,49 @@ +From 44e7fa79ba6d9985c508add6e9912cb60c8a6deb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:30:41 +0200 +Subject: netfilter: nft_fwd_netdev: check ttl/hl before forwarding + +From: Florian Westphal + +[ Upstream commit 1dfd95bdf4d18d263aa8fad06bfb9f4d9c992b18 ] + +Drop packets if their ttl/hl is too small for forwarding. + +Fixes: d32de98ea70f ("netfilter: nft_fwd_netdev: allow to forward packets via neighbour layer") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_fwd_netdev.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c +index 42ba31dfc0359..1223bdea1f00d 100644 +--- a/net/netfilter/nft_fwd_netdev.c ++++ b/net/netfilter/nft_fwd_netdev.c +@@ -116,6 +116,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + iph = ip_hdr(skb); ++ if (iph->ttl <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip_decrease_ttl(iph); + neigh_table = NEIGH_ARP_TABLE; + break; +@@ -132,6 +137,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + ip6h = ipv6_hdr(skb); ++ if (ip6h->hop_limit <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip6h->hop_limit--; + neigh_table = NEIGH_ND_TABLE; + break; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-nft_osf-restrict-it-to-ipv4.patch b/queue-6.6/netfilter-nft_osf-restrict-it-to-ipv4.patch new file mode 100644 index 0000000000..9cf723c9f4 --- /dev/null +++ b/queue-6.6/netfilter-nft_osf-restrict-it-to-ipv4.patch @@ -0,0 +1,47 @@ +From ee5529e1460aa269c09966bee06772c99eba1e25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 13:06:38 +0200 +Subject: netfilter: nft_osf: restrict it to ipv4 + +From: Pablo Neira Ayuso + +[ Upstream commit b336fdbb7103fb1484e1dcb6741151d4b5a41e35 ] + +This expression only supports for ipv4, restrict it. + +Fixes: b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf") +Acked-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_osf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c +index 123b4f47ccef4..23ec9b397f1eb 100644 +--- a/net/netfilter/nft_osf.c ++++ b/net/netfilter/nft_osf.c +@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, + struct nf_osf_data data; + struct tcphdr _tcph; + ++ if (nft_pf(pkt) != NFPROTO_IPV4) { ++ regs->verdict.code = NFT_BREAK; ++ return; ++ } ++ + if (pkt->tprot != IPPROTO_TCP) { + regs->verdict.code = NFT_BREAK; + return; +@@ -119,7 +124,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx, + + switch (ctx->family) { + case NFPROTO_IPV4: +- case NFPROTO_IPV6: + case NFPROTO_INET: + hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | +-- +2.53.0 + diff --git a/queue-6.6/netfilter-skip-recording-stale-or-retransmitted-init.patch b/queue-6.6/netfilter-skip-recording-stale-or-retransmitted-init.patch new file mode 100644 index 0000000000..b9225cb187 --- /dev/null +++ b/queue-6.6/netfilter-skip-recording-stale-or-retransmitted-init.patch @@ -0,0 +1,63 @@ +From cc84ec574313854864f2767f6914346f13920b74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:40 -0400 +Subject: netfilter: skip recording stale or retransmitted INIT + +From: Xin Long + +[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ] + +An INIT whose init_tag matches the peer's vtag does not provide new state +information. It indicates either: + +- a stale INIT (after INIT-ACK has already been seen on the same side), or +- a retransmitted INIT (after INIT has already been recorded on the same + side). + +In both cases, the INIT must not update ct->proto.sctp.init[] state, since +it does not advance the handshake tracking and may otherwise corrupt +INIT/INIT-ACK validation logic. + +Allow INIT processing only when the conntrack entry is newly created +(SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer +vtag. + +Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in +nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it +set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag. + +Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") +Signed-off-by: Xin Long +Reviewed-by: Marcelo Ricardo Leitner +Acked-by: Florian Westphal +Link: https://patch.msgid.link/ee56c3e416452b2a40589a2a85245ac2ad5e9f4b.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index fabb2c1ca00ab..0dd55d3fba38d 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -471,9 +471,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + if (!ih) + goto out_unlock; + +- if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) +- ct->proto.sctp.init[!dir] = 0; +- ct->proto.sctp.init[dir] = 1; ++ /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ ++ if (old_state == SCTP_CONNTRACK_NONE || ++ ct->proto.sctp.vtag[!dir] != ih->init_tag) { ++ if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) ++ ct->proto.sctp.init[!dir] = 0; ++ ct->proto.sctp.init[dir] = 1; ++ } + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); + ct->proto.sctp.vtag[!dir] = ih->init_tag; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch b/queue-6.6/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch new file mode 100644 index 0000000000..05ac78a0d1 --- /dev/null +++ b/queue-6.6/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch @@ -0,0 +1,47 @@ +From d33ecfd0089fffb182313efcd34d05fccf2ab2b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:25:06 +0800 +Subject: netfilter: xt_policy: fix strict mode inbound policy matching + +From: Jiexun Wang + +[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ] + +match_policy_in() walks sec_path entries from the last transform to the +first one, but strict policy matching needs to consume info->pol[] in +the same forward order as the rule layout. + +Derive the strict-match policy position from the number of transforms +already consumed so that multi-element inbound rules are matched +consistently. + +Fixes: c4b885139203 ("[NETFILTER]: x_tables: replace IPv4/IPv6 policy match by address family independant version") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Acked-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c +index cb6e8279010a4..b5fa65558318f 100644 +--- a/net/netfilter/xt_policy.c ++++ b/net/netfilter/xt_policy.c +@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, + return 0; + + for (i = sp->len - 1; i >= 0; i--) { +- pos = strict ? i - sp->len + 1 : 0; ++ pos = strict ? sp->len - i - 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; +-- +2.53.0 + diff --git a/queue-6.6/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch b/queue-6.6/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch new file mode 100644 index 0000000000..fe0da5b268 --- /dev/null +++ b/queue-6.6/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch @@ -0,0 +1,86 @@ +From 48d8b6310fe4a11f4930b303a52e6652cb87e249 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 12:12:59 +0200 +Subject: netfilter: xt_socket: enable defrag after all other checks + +From: Florian Westphal + +[ Upstream commit 542be3fa5aff54210a02954c38f07e53ea9bdafd ] + +Originally this did not matter because defrag was enabled once per netns +and only disabled again on netns dismantle. When this got changed I should +have adjusted checkentry to not leave defrag enabled on error. + +Fixes: de8c12110a13 ("netfilter: disable defrag once its no longer needed") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_socket.c | 23 ++++++----------------- + 1 file changed, 6 insertions(+), 17 deletions(-) + +diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c +index 76e01f292aaff..811e53bee4085 100644 +--- a/net/netfilter/xt_socket.c ++++ b/net/netfilter/xt_socket.c +@@ -168,52 +168,41 @@ static int socket_mt_enable_defrag(struct net *net, int family) + static int socket_mt_v1_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V1) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V1); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v2_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V2) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V2); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v3_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo3 *info = + (struct xt_socket_mtinfo3 *)par->matchinfo; +- int err; + +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + if (info->flags & ~XT_SOCKET_FLAGS_V3) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V3); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static void socket_mt_destroy(const struct xt_mtdtor_param *par) +-- +2.53.0 + diff --git a/queue-6.6/netfilter-xtables-restrict-several-matches-to-inet-f.patch b/queue-6.6/netfilter-xtables-restrict-several-matches-to-inet-f.patch new file mode 100644 index 0000000000..5b0b072c3a --- /dev/null +++ b/queue-6.6/netfilter-xtables-restrict-several-matches-to-inet-f.patch @@ -0,0 +1,208 @@ +From 18870be3b0b8c363da0e85b2b57b688f43ff07fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 12:21:00 +0200 +Subject: netfilter: xtables: restrict several matches to inet family + +From: Pablo Neira Ayuso + +[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ] + +This is a partial revert of: + + commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") + +to allow ipv4 and ipv6 only. + +- xt_mac +- xt_owner +- xt_physdev + +These extensions are not used by ebtables in userspace. + +Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 +specific. + +Fixes: ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") +Reported-by: "Kito Xu (veritas501)" +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- + net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ + net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- + net/netfilter/xt_realm.c | 2 +- + 4 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index 81649da57ba5d..bd2354760895d 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + return ret; + } + +-static struct xt_match mac_mt_reg __read_mostly = { +- .name = "mac", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .match = mac_mt, +- .matchsize = sizeof(struct xt_mac_info), +- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | +- (1 << NF_INET_FORWARD), +- .me = THIS_MODULE, ++static struct xt_match mac_mt_reg[] __read_mostly = { ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV4, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV6, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init mac_mt_init(void) + { +- return xt_register_match(&mac_mt_reg); ++ return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + static void __exit mac_mt_exit(void) + { +- xt_unregister_match(&mac_mt_reg); ++ xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + module_init(mac_mt_init); +diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c +index 50332888c8d23..7be2fe22b067e 100644 +--- a/net/netfilter/xt_owner.c ++++ b/net/netfilter/xt_owner.c +@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + +-static struct xt_match owner_mt_reg __read_mostly = { +- .name = "owner", +- .revision = 1, +- .family = NFPROTO_UNSPEC, +- .checkentry = owner_check, +- .match = owner_mt, +- .matchsize = sizeof(struct xt_owner_match_info), +- .hooks = (1 << NF_INET_LOCAL_OUT) | +- (1 << NF_INET_POST_ROUTING), +- .me = THIS_MODULE, ++static struct xt_match owner_mt_reg[] __read_mostly = { ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV4, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV6, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ } + }; + + static int __init owner_mt_init(void) + { +- return xt_register_match(&owner_mt_reg); ++ return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + static void __exit owner_mt_exit(void) + { +- xt_unregister_match(&owner_mt_reg); ++ xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + module_init(owner_mt_init); +diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c +index 343e65f377d44..130842c35c6fa 100644 +--- a/net/netfilter/xt_physdev.c ++++ b/net/netfilter/xt_physdev.c +@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) + return 0; + } + +-static struct xt_match physdev_mt_reg __read_mostly = { +- .name = "physdev", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .checkentry = physdev_mt_check, +- .match = physdev_mt, +- .matchsize = sizeof(struct xt_physdev_info), +- .me = THIS_MODULE, ++static struct xt_match physdev_mt_reg[] __read_mostly = { ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV4, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV6, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init physdev_mt_init(void) + { +- return xt_register_match(&physdev_mt_reg); ++ return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + static void __exit physdev_mt_exit(void) + { +- xt_unregister_match(&physdev_mt_reg); ++ xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + module_init(physdev_mt_init); +diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c +index 6df485f4403d0..61b2f1e58d150 100644 +--- a/net/netfilter/xt_realm.c ++++ b/net/netfilter/xt_realm.c +@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { + .matchsize = sizeof(struct xt_realm_info), + .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), +- .family = NFPROTO_UNSPEC, ++ .family = NFPROTO_IPV4, + .me = THIS_MODULE + }; + +-- +2.53.0 + diff --git a/queue-6.6/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch b/queue-6.6/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch new file mode 100644 index 0000000000..488f7e8416 --- /dev/null +++ b/queue-6.6/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch @@ -0,0 +1,69 @@ +From d91965b85d03b5a8f84f62ef8cb5b92f706b4429 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:19 +0800 +Subject: nexthop: fix IPv6 route referencing IPv4 nexthop + +From: Jiayuan Chen + +[ Upstream commit 29c95185ba32b621fbc3800fb86e7dc3edf5c2be ] + +syzbot reported a panic [1] [2]. + +When an IPv6 nexthop is replaced with an IPv4 nexthop, the has_v4 flag +of all groups containing this nexthop is not updated. This is because +nh_group_v4_update is only called when replacing AF_INET to AF_INET6, +but the reverse direction (AF_INET6 to AF_INET) is missed. + +This allows a stale has_v4=false to bypass fib6_check_nexthop, causing +IPv6 routes to be attached to groups that effectively contain only AF_INET +members. Subsequent route lookups then call nexthop_fib6_nh() which +returns NULL for the AF_INET member, leading to a NULL pointer +dereference. + +Fix by calling nh_group_v4_update whenever the family changes, not just +AF_INET to AF_INET6. + +Reproducer: + # AF_INET6 blackhole + ip -6 nexthop add id 1 blackhole + # group with has_v4=false + ip nexthop add id 100 group 1 + # replace with AF_INET (no -6), has_v4 stays false + ip nexthop replace id 1 blackhole + # pass stale has_v4 check + ip -6 route add 2001:db8::/64 nhid 100 + # panic + ping -6 2001:db8::1 + +[1] https://syzkaller.appspot.com/bug?id=e17283eb2f8dcf3dd9b47fe6f67a95f71faadad0 +[2] https://syzkaller.appspot.com/bug?id=8699b6ae54c9f35837d925686208402949e12ef3 +Fixes: 7bf4796dd099 ("nexthops: add support for replace") +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/nexthop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c +index 99385fe34a1e5..4f30ddd2016b6 100644 +--- a/net/ipv4/nexthop.c ++++ b/net/ipv4/nexthop.c +@@ -2183,10 +2183,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + goto err_notify; + } + +- /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially ++ /* When replacing a nexthop with one of a different family, potentially + * update IPv4 indication in all the groups using the nexthop. + */ +- if (oldi->family == AF_INET && newi->family == AF_INET6) { ++ if (oldi->family != newi->family) { + list_for_each_entry(nhge, &old->grp_list, nh_list) { + struct nexthop *nhp = nhge->nh_parent; + struct nh_group *nhg; +-- +2.53.0 + diff --git a/queue-6.6/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch b/queue-6.6/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch new file mode 100644 index 0000000000..3414933083 --- /dev/null +++ b/queue-6.6/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch @@ -0,0 +1,53 @@ +From 488d66e744b5d6645c7503ea10a8674b805c78a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 12:09:30 +0200 +Subject: NFC: trf7970a: Ignore antenna noise when checking for RF field + +From: Paul Geurts + +[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ] + +The main channel Received Signal Strength Indicator (RSSI) measurement +is used to determine whether an RF field is present or not. RSSI != 0 +is interpreted as an RF Field is present. This does not take RF noise +and measurement inaccuracy into account, and results in false positives +in the field. + +Define a noise level and make sure the RF field is only interpreted as +present when the RSSI is above the noise level. + +Fixes: 851ee3cbf850 ("NFC: trf7970a: Don't turn on RF if there is already an RF field") +Signed-off-by: Paul Geurts +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Mark Greer +Link: https://patch.msgid.link/20260422100930.581237-1-paul.geurts@prodrive-technologies.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/trf7970a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c +index 9e1a34e23af26..6b8311f526a5e 100644 +--- a/drivers/nfc/trf7970a.c ++++ b/drivers/nfc/trf7970a.c +@@ -311,6 +311,7 @@ + #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) ++#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 + + #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) + #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +@@ -1253,7 +1254,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) + if (ret) + return ret; + +- if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) ++ if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) + *is_rf_field = true; + else + *is_rf_field = false; +-- +2.53.0 + diff --git a/queue-6.6/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch b/queue-6.6/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch new file mode 100644 index 0000000000..0c04d7e146 --- /dev/null +++ b/queue-6.6/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch @@ -0,0 +1,107 @@ +From 5322ff04ff7fd12775aba6b472d5b19d7164d162 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 16:05:36 +0000 +Subject: nfp: fix swapped arguments in nfp_encode_basic_qdr() calls + +From: Alexey Kodanev + +[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ] + +There is a mismatch between the passed arguments and the actual +nfp_encode_basic_qdr() function parameter names: + + static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + int mode, bool addr40, int isld1, + int isld0) + { + ... + +But "dest_island" and "cpp_tgt" are swapped at every call-site. +For example: + + return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + mode, addr40, isld1, isld0); + +As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target +type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" +as the destination island ID, which can accidentally match or be outside +the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination). + +Since code already worked for years, also add extra pr_warn() to error +paths in nfp_encode_basic_qdr() to help identify any potential address +verification failures. + +Detected using the static analysis tool - Svace. + +Fixes: 4cb584e0ee7d ("nfp: add CPP access core") +Signed-off-by: Alexey Kodanev +Link: https://patch.msgid.link/20260422160536.61855-1-aleksei.kodanev@bell-sw.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +index 79470f198a62a..9cf19446657c6 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + + /* Full Island ID and channel bits overlap? */ + ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0); +- if (ret) ++ if (ret) { ++ pr_warn("%s: decode dest_island failed: %d\n", __func__, ret); + return ret; ++ } + + /* The current address won't go where expected? */ +- if (dest_island != -1 && dest_island != v) ++ if (dest_island != -1 && dest_island != v) { ++ pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n", ++ __func__, dest_island, v); + return -EINVAL; ++ } + + /* If dest_island was -1, we don't care where it goes. */ + return 0; +@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * the address but we can verify if the existing + * contents will point to a valid island. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + iid_lsb = addr40 ? 34 : 26; +@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + return 0; + case 1: + if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40) +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + idx_lsb = addr40 ? 39 : 31; +@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * be set before hand and with them select an island. + * So we need to confirm that it's at least plausible. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + /* Make sure we compare against isldN values +@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * iid<1> = addr<30> = channel<0> + * channel<1> = addr<31> = Index + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + isld[0] &= ~3; +-- +2.53.0 + diff --git a/queue-6.6/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch b/queue-6.6/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch new file mode 100644 index 0000000000..5364e4a527 --- /dev/null +++ b/queue-6.6/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch @@ -0,0 +1,58 @@ +From 4897834440ccf0edba9f992fe25afdb94df0906e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:49 +0100 +Subject: nfs/blocklayout: Fix compilation error (`make W=1`) in + bl_write_pagelist() + +From: Andy Shevchenko + +[ Upstream commit f83c8dda456ce4863f346aa26d88efa276eda35d ] + +Clang compiler is not happy about set but unused variable +(when dprintk() is no-op): + +.../blocklayout/blocklayout.c:384:9: error: variable 'count' set but not used [-Werror,-Wunused-but-set-variable] + +Remove a leftover from the previous cleanup. + +Fixes: 3a6fd1f004fc ("pnfs/blocklayout: remove read-modify-write handling in bl_write_pagelist") +Acked-by: Anna Schumaker +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/blocklayout/blocklayout.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c +index e498aade8c479..15f66d949adda 100644 +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -381,14 +381,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + sector_t isect, extent_length = 0; + struct parallel_io *par = NULL; + loff_t offset = header->args.offset; +- size_t count = header->args.count; + struct page **pages = header->args.pages; + int pg_index = header->args.pgbase >> PAGE_SHIFT; + unsigned int pg_len; + struct blk_plug plug; + int i; + +- dprintk("%s enter, %zu@%lld\n", __func__, count, offset); ++ dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); + + /* At this point, header->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error +@@ -429,7 +428,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + } + + offset += pg_len; +- count -= pg_len; + isect += (pg_len >> SECTOR_SHIFT); + extent_length -= (pg_len >> SECTOR_SHIFT); + } +-- +2.53.0 + diff --git a/queue-6.6/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch b/queue-6.6/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch new file mode 100644 index 0000000000..e29cc7d568 --- /dev/null +++ b/queue-6.6/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch @@ -0,0 +1,61 @@ +From 17e226b98fbb90154198d8b915fa5290fd941753 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:52:09 +0900 +Subject: nilfs2: reject zero bd_oblocknr in nilfs_ioctl_mark_blocks_dirty() + +From: Deepanshu Kartikey + +[ Upstream commit be3e5d10643d3be1cbac9d9939f220a99253f980 ] + +nilfs_ioctl_mark_blocks_dirty() uses bd_oblocknr to detect dead blocks +by comparing it with the current block number bd_blocknr. If they differ, +the block is considered dead and skipped. + +However, bd_oblocknr should never be 0 since block 0 typically stores the +primary superblock and is never a valid GC target block. A corrupted ioctl +request with bd_oblocknr set to 0 causes the comparison to incorrectly +match when the lookup returns -ENOENT and sets bd_blocknr to 0, bypassing +the dead block check and calling nilfs_bmap_mark() on a non-existent +block. This causes nilfs_btree_do_lookup() to return -ENOENT, triggering +the WARN_ON(ret == -ENOENT). + +Fix this by rejecting ioctl requests with bd_oblocknr set to 0 at the +beginning of each iteration. + +[ryusuke: slightly modified the commit message and comments for accuracy] + +Fixes: 7942b919f732 ("nilfs2: ioctl operations") +Reported-by: syzbot+98a040252119df0506f8@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=98a040252119df0506f8 +Suggested-by: Ryusuke Konishi +Signed-off-by: Deepanshu Kartikey +Reported-by: syzbot+466a45fcfb0562f5b9a0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=466a45fcfb0562f5b9a0 +Cc: Junjie Cao +Signed-off-by: Ryusuke Konishi +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/nilfs2/ioctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index 53022bfe0b72d..1a6868afa9143 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -751,6 +751,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, + int ret, i; + + for (i = 0; i < nmembs; i++) { ++ /* ++ * bd_oblocknr must never be 0 as block 0 ++ * is never a valid GC target block ++ */ ++ if (unlikely(!bdescs[i].bd_oblocknr)) ++ return -EINVAL; + /* XXX: use macro or inline func to check liveness */ + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, +-- +2.53.0 + diff --git a/queue-6.6/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch b/queue-6.6/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch new file mode 100644 index 0000000000..9fcc5b40ef --- /dev/null +++ b/queue-6.6/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch @@ -0,0 +1,39 @@ +From 50f94ba4545a428c496192fd4e332f44d659522e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 09:14:02 -0700 +Subject: nvme-pci: fix missed admin queue sq doorbell write + +From: Keith Busch + +[ Upstream commit 1cc4cdae2a3b7730d462d69e30f213fd2efe7807 ] + +We can batch admin commands submitted through io_uring_cmd passthrough, +which means bd->last may be false and skips the doorbell write to +aggregate multiple commands per write. If a subsequent command can't be +dispatched for whatever reason, we have to provide the blk-mq ops' +commit_rqs callback in order to ensure we properly update the doorbell. + +Fixes: 58e5bdeb9c2b ("nvme: enable uring-passthrough for admin commands") +Reviewed-by: Christoph Hellwig +Reviewed-by: Kanchan Joshi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 40d9be6468b5e..87d30aaa35f10 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1715,6 +1715,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled) + static const struct blk_mq_ops nvme_mq_admin_ops = { + .queue_rq = nvme_queue_rq, + .complete = nvme_pci_complete_rq, ++ .commit_rqs = nvme_commit_rqs, + .init_hctx = nvme_admin_init_hctx, + .init_request = nvme_pci_init_request, + .timeout = nvme_timeout, +-- +2.53.0 + diff --git a/queue-6.6/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch b/queue-6.6/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch new file mode 100644 index 0000000000..57e5127c3d --- /dev/null +++ b/queue-6.6/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch @@ -0,0 +1,162 @@ +From 684835686ae37974a0c40d2a016ca9228cff8504 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 15:39:35 +0100 +Subject: nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its + callers + +From: Maurizio Lombardi + +[ Upstream commit ea8e356acb165cb1fd75537a52e1f66e5e76c538 ] + +Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds +PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) +and returns early. However, because the function returns void, the +callers are entirely unaware that a fatal error has occurred and +that the cmd->recv_msg.msg_iter was left uninitialized. + +Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly +overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA +Consequently, the socket receiving loop may attempt to read incoming +network data into the uninitialized iterator. + +Fix this by shifting the error handling responsibility to the callers. + +Fixes: 52a0a9854934 ("nvmet-tcp: add bounds checks in nvmet_tcp_build_pdu_iovec") +Reviewed-by: Hannes Reinecke +Reviewed-by: Yunje Shin +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Maurizio Lombardi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 51 ++++++++++++++++++++++----------------- + 1 file changed, 29 insertions(+), 22 deletions(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 4d1f260ae60ab..5f85c4a812abc 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -335,7 +335,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); + +-static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) ++static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + { + struct bio_vec *iov = cmd->iov; + struct scatterlist *sg; +@@ -348,22 +348,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + offset = cmd->rbytes_done; + cmd->sg_idx = offset / PAGE_SIZE; + sg_offset = offset % PAGE_SIZE; +- if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) ++ return -EPROTO; ++ + sg = &cmd->req.sg[cmd->sg_idx]; + sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; + + while (length) { +- if (!sg_remaining) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } +- if (!sg->length || sg->length <= sg_offset) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!sg_remaining) ++ return -EPROTO; ++ ++ if (!sg->length || sg->length <= sg_offset) ++ return -EPROTO; ++ + u32 iov_len = min_t(u32, length, sg->length - sg_offset); + + bvec_set_page(iov, sg_page(sg), iov_len, +@@ -378,6 +375,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + + iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, + nr_pages, cmd->pdu_len); ++ return 0; + } + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) +@@ -945,7 +943,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) + return 0; + } + +-static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, ++static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) + { + size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); +@@ -961,19 +959,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + if (!nvme_is_write(cmd->req.cmd) || !data_len || + data_len > cmd->req.port->inline_data_size) { + nvmet_prepare_receive_pdu(queue); +- return; ++ return 0; + } + + ret = nvmet_tcp_map_data(cmd); + if (unlikely(ret)) { + pr_err("queue %d: failed to map data\n", queue->idx); + nvmet_tcp_fatal_error(queue); +- return; ++ return -EPROTO; + } + + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(cmd); + cmd->flags |= NVMET_TCP_F_INIT_FAILED; ++ ret = nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ ++ return ret; + } + + static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) +@@ -1025,7 +1027,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) + goto err_proto; + } + cmd->pdu_recv = 0; +- nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) { ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ goto err_proto; ++ } + queue->cmd = cmd; + queue->rcv_state = NVMET_TCP_RECV_DATA; + +@@ -1088,8 +1093,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + req->cmd->common.opcode, + le32_to_cpu(req->cmd->common.dptr.sgl.length)); + +- nvmet_tcp_handle_req_failure(queue, queue->cmd, req); +- return 0; ++ return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); + } + + ret = nvmet_tcp_map_data(queue->cmd); +@@ -1106,8 +1110,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + if (nvmet_tcp_need_data_in(queue->cmd)) { + if (nvmet_tcp_has_inline_data(queue->cmd)) { + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(queue->cmd); +- return 0; ++ ret = nvmet_tcp_build_pdu_iovec(queue->cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", ++ queue->idx); ++ return ret; + } + /* send back R2T */ + nvmet_tcp_queue_response(&queue->cmd->req); +-- +2.53.0 + diff --git a/queue-6.6/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch b/queue-6.6/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch new file mode 100644 index 0000000000..06ea6ed4ef --- /dev/null +++ b/queue-6.6/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch @@ -0,0 +1,48 @@ +From 252c83630664617029a87840de79db7f560f2958 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:09 +0800 +Subject: ocfs2/dlm: fix off-by-one in dlm_match_regions() region comparison + +From: Junrui Luo + +[ Upstream commit 01b61e8dda9b0fdb0d4cda43de25f4e390554d7b ] + +The local-vs-remote region comparison loop uses '<=' instead of '<', +causing it to read one entry past the valid range of qr_regions. The +other loops in the same function correctly use '<'. + +Fix the loop condition to use '<' for consistency and correctness. + +Link: https://lkml.kernel.org/r/SYBPR01MB78813DA26B50EC5E01F00566AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 5b6c893d9f489..8e4b575a2bc9f 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1002,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + for (i = 0; i < localnr; ++i) { + foundit = 0; + r = remote; +- for (j = 0; j <= qr->qr_numregions; ++j) { ++ for (j = 0; j < qr->qr_numregions; ++j) { + if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { + foundit = 1; + break; +-- +2.53.0 + diff --git a/queue-6.6/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch b/queue-6.6/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch new file mode 100644 index 0000000000..f6e37faa4f --- /dev/null +++ b/queue-6.6/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch @@ -0,0 +1,75 @@ +From d2eb7be24ec8462783c95fb4caf27466fa9522bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:08 +0800 +Subject: ocfs2/dlm: validate qr_numregions in dlm_match_regions() + +From: Junrui Luo + +[ Upstream commit 7ab3fbb01bc6d79091bc375e5235d360cd9b78be ] + +Patch series "ocfs2/dlm: fix two bugs in dlm_match_regions()". + +In dlm_match_regions(), the qr_numregions field from a DLM_QUERY_REGION +network message is used to drive loops over the qr_regions buffer without +sufficient validation. This series fixes two issues: + +- Patch 1 adds a bounds check to reject messages where qr_numregions + exceeds O2NM_MAX_REGIONS. The o2net layer only validates message + byte length; it does not constrain field values, so a crafted message + can set qr_numregions up to 255 and trigger out-of-bounds reads past + the 1024-byte qr_regions buffer. + +- Patch 2 fixes an off-by-one in the local-vs-remote comparison loop, + which uses '<=' instead of '<', reading one entry past the valid range + even when qr_numregions is within bounds. + +This patch (of 2): + +The qr_numregions field from a DLM_QUERY_REGION network message is used +directly as loop bounds in dlm_match_regions() without checking against +O2NM_MAX_REGIONS. Since qr_regions is sized for at most O2NM_MAX_REGIONS +(32) entries, a crafted message with qr_numregions > 32 causes +out-of-bounds reads past the qr_regions buffer. + +Add a bounds check for qr_numregions before entering the loops. + +Link: https://lkml.kernel.org/r/SYBPR01MB7881A334D02ACEE5E0645801AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Link: https://lkml.kernel.org/r/SYBPR01MB788166F524AD04E262E174BEAF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 5c04dde99981c..5b6c893d9f489 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + goto bail; + } + ++ if (qr->qr_numregions > O2NM_MAX_REGIONS) { ++ mlog(ML_ERROR, "Domain %s: Joining node %d has invalid " ++ "number of heartbeat regions %u\n", ++ qr->qr_domain, qr->qr_node, qr->qr_numregions); ++ status = -EINVAL; ++ goto bail; ++ } ++ + r = remote; + for (i = 0; i < qr->qr_numregions; ++i) { + mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); +-- +2.53.0 + diff --git a/queue-6.6/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch b/queue-6.6/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch new file mode 100644 index 0000000000..8360fb6c82 --- /dev/null +++ b/queue-6.6/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch @@ -0,0 +1,89 @@ +From fef00b459037d7bc5aff8c239233e38d91b4f02b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 12:03:39 +0800 +Subject: ocfs2: fix listxattr handling when the buffer is full + +From: ZhengYuan Huang + +[ Upstream commit d12f558e6200b3f47dbef9331ed6d115d2410e59 ] + +[BUG] +If an OCFS2 inode has both inline and block-based xattrs, listxattr() +can return a size larger than the caller's buffer when the inline names +consume that buffer exactly. + +kernel BUG at mm/usercopy.c:102! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:usercopy_abort+0xb7/0xd0 mm/usercopy.c:102 +Call Trace: + __check_heap_object+0xe3/0x120 mm/slub.c:8243 + check_heap_object mm/usercopy.c:196 [inline] + __check_object_size mm/usercopy.c:250 [inline] + __check_object_size+0x5c5/0x780 mm/usercopy.c:215 + check_object_size include/linux/ucopysize.h:22 [inline] + check_copy_size include/linux/ucopysize.h:59 [inline] + copy_to_user include/linux/uaccess.h:219 [inline] + listxattr+0xb0/0x170 fs/xattr.c:926 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x137/0x320 fs/xattr.c:988 + __do_sys_listxattr fs/xattr.c:1001 [inline] + __se_sys_listxattr fs/xattr.c:998 [inline] + __x64_sys_listxattr+0x7f/0xd0 fs/xattr.c:998 + ... + +[CAUSE] +Commit 936b8834366e ("ocfs2: Refactor xattr list and remove +ocfs2_xattr_handler().") replaced the old per-handler list accounting +with ocfs2_xattr_list_entry(), but it kept using size == 0 to detect +probe mode. + +That assumption stops being true once ocfs2_listxattr() finishes the +inline-xattr pass. If the inline names fill the caller buffer exactly, +the block-xattr pass runs with a non-NULL buffer and a remaining size of +zero. ocfs2_xattr_list_entry() then skips the bounds check, keeps +counting block names, and returns a positive size larger than the +supplied buffer. + +[FIX] +Detect probe mode by testing whether the destination buffer pointer is +NULL instead of whether the remaining size is zero. + +That restores the pre-refactor behavior and matches the OCFS2 getxattr +helpers. Once the remaining buffer reaches zero while more names are +left, the block-xattr pass now returns -ERANGE instead of reporting a +size larger than the allocated list buffer. + +Link: https://lkml.kernel.org/r/20260410040339.3837162-1-gality369@gmail.com +Fixes: 936b8834366e ("ocfs2: Refactor xattr list and remove ocfs2_xattr_handler().") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index d0cb529b612a7..750c1fc70d25a 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -907,8 +907,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb, + total_len = prefix_len + name_len + 1; + *result += total_len; + +- /* we are just looking for how big our buffer needs to be */ +- if (!size) ++ /* No buffer means we are only looking for the required size. */ ++ if (!buffer) + return 0; + + if (*result > size) +-- +2.53.0 + diff --git a/queue-6.6/ocfs2-validate-bg_bits-during-freefrag-scan.patch b/queue-6.6/ocfs2-validate-bg_bits-during-freefrag-scan.patch new file mode 100644 index 0000000000..a67d799070 --- /dev/null +++ b/queue-6.6/ocfs2-validate-bg_bits-during-freefrag-scan.patch @@ -0,0 +1,121 @@ +From 7466d5137092ad14382d330e21bcbc1e764af44f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:42:20 +0800 +Subject: ocfs2: validate bg_bits during freefrag scan + +From: ZhengYuan Huang + +[ Upstream commit 8f687eeed3da3012152b0f9473f578869de0cd7b ] + +[BUG] +A crafted filesystem can trigger an out-of-bounds bitmap walk when +OCFS2_IOC_INFO is issued with OCFS2_INFO_FL_NON_COHERENT. + +BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:68 [inline] +BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] +BUG: KASAN: use-after-free in test_bit_le include/asm-generic/bitops/le.h:21 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 +Read of size 8 at addr ffff888031bce000 by task syz.0.636/1435 +Call Trace: + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xd1/0x650 mm/kasan/report.c:482 + kasan_report+0xfb/0x140 mm/kasan/report.c:595 + check_region_inline mm/kasan/generic.c:186 [inline] + kasan_check_range+0x11c/0x200 mm/kasan/generic.c:200 + __kasan_check_read+0x11/0x20 mm/kasan/shadow.c:31 + instrument_atomic_read include/linux/instrumented.h:68 [inline] + _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] + test_bit_le include/asm-generic/bitops/le.h:21 [inline] + ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] + ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] + ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] + ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 + ocfs2_info_handle+0x18d/0x2a0 fs/ocfs2/ioctl.c:828 + ocfs2_ioctl+0x632/0x6e0 fs/ocfs2/ioctl.c:913 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + ... + +[CAUSE] +ocfs2_info_freefrag_scan_chain() uses on-disk bg_bits directly as the +bitmap scan limit. The coherent path reads group descriptors through +ocfs2_read_group_descriptor(), which validates the descriptor before +use. The non-coherent path uses ocfs2_read_blocks_sync() instead and +skips that validation, so an impossible bg_bits value can drive the +bitmap walk past the end of the block. + +[FIX] +Compute the bitmap capacity from the filesystem format with +ocfs2_group_bitmap_size(), report descriptors whose bg_bits exceeds +that limit, and clamp the scan to the computed capacity. This keeps the +freefrag report going while avoiding reads beyond the buffer. + +Link: https://lkml.kernel.org/r/20260410034220.3825769-1-gality369@gmail.com +Fixes: d24a10b9f8ed ("Ocfs2: Add a new code 'OCFS2_INFO_FREEFRAG' for o2info ioctl.") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Heming Zhao +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/ioctl.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c +index b1550ba73f963..f34f404af2f77 100644 +--- a/fs/ocfs2/ioctl.c ++++ b/fs/ocfs2/ioctl.c +@@ -442,13 +442,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + struct buffer_head *bh = NULL; + struct ocfs2_group_desc *bg = NULL; + +- unsigned int max_bits, num_clusters; ++ unsigned int max_bits, max_bitmap_bits, num_clusters; + unsigned int offset = 0, cluster, chunk; + unsigned int chunk_free, last_chunksize = 0; + + if (!le32_to_cpu(rec->c_free)) + goto bail; + ++ max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0, ++ osb->s_feature_incompat); ++ + do { + if (!bg) + blkno = le64_to_cpu(rec->c_blkno); +@@ -480,6 +483,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + continue; + + max_bits = le16_to_cpu(bg->bg_bits); ++ ++ /* ++ * Non-coherent scans read raw blocks and do not get the ++ * bg_bits validation from ++ * ocfs2_read_group_descriptor(). ++ */ ++ if (max_bits > max_bitmap_bits) { ++ mlog(ML_ERROR, ++ "Group desc #%llu has %u bits, max bitmap bits %u\n", ++ (unsigned long long)blkno, max_bits, max_bitmap_bits); ++ max_bits = max_bitmap_bits; ++ } ++ + offset = 0; + + for (chunk = 0; chunk < chunks_in_group; chunk++) { +-- +2.53.0 + diff --git a/queue-6.6/ocfs2-validate-group-add-input-before-caching.patch b/queue-6.6/ocfs2-validate-group-add-input-before-caching.patch new file mode 100644 index 0000000000..7d520dc403 --- /dev/null +++ b/queue-6.6/ocfs2-validate-group-add-input-before-caching.patch @@ -0,0 +1,110 @@ +From cee4f58fd1509a5cc481e677adfb3f495089e4e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 10:02:08 +0800 +Subject: ocfs2: validate group add input before caching + +From: ZhengYuan Huang + +[ Upstream commit 70b672833f4025341c11b22c7f83778a5cd611bc ] + +[BUG] +OCFS2_IOC_GROUP_ADD can trigger a BUG_ON in +ocfs2_set_new_buffer_uptodate(): + +kernel BUG at fs/ocfs2/uptodate.c:509! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:ocfs2_set_new_buffer_uptodate+0x194/0x1e0 fs/ocfs2/uptodate.c:509 +Code: ffffe88f 42b9fe4c 89e64889 dfe8b4df +Call Trace: + ocfs2_group_add+0x3f1/0x1510 fs/ocfs2/resize.c:507 + ocfs2_ioctl+0x309/0x6e0 fs/ocfs2/ioctl.c:887 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + x64_sys_call+0x1144/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:17 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e +RIP: 0033:0x7bbfb55a966d + +[CAUSE] +ocfs2_group_add() calls ocfs2_set_new_buffer_uptodate() on a +user-controlled group block before ocfs2_verify_group_and_input() +validates that block number. That helper is only valid for newly +allocated metadata and asserts that the block is not already present in +the chosen metadata cache. The code also uses INODE_CACHE(inode) even +though the group descriptor belongs to main_bm_inode and later journal +accesses use that cache context instead. + +[FIX] +Validate the on-disk group descriptor before caching it, then add it to +the metadata cache tracked by INODE_CACHE(main_bm_inode). Keep the +validation failure path separate from the later cleanup path so we only +remove the buffer from that cache after it has actually been inserted. +This keeps the group buffer lifetime consistent across validation, +journaling, and cleanup. + +Link: https://lkml.kernel.org/r/20260410020209.3786348-1-gality369@gmail.com +Fixes: 7909f2bf8353 ("[PATCH 2/2] ocfs2: Implement group add for online resize") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/resize.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c +index 42c0d314f95e8..acf2769f4c8c7 100644 +--- a/fs/ocfs2/resize.c ++++ b/fs/ocfs2/resize.c +@@ -500,14 +500,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + goto out_unlock; + } + +- ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); +- + ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); + if (ret) { + mlog_errno(ret); + goto out_free_group_bh; + } + ++ ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh); ++ + trace_ocfs2_group_add((unsigned long long)input->group, + input->chain, input->clusters, input->frees); + +@@ -515,7 +515,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + if (IS_ERR(handle)) { + mlog_errno(PTR_ERR(handle)); + ret = -EINVAL; +- goto out_free_group_bh; ++ goto out_remove_cache; + } + + cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); +@@ -569,9 +569,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + out_commit: + ocfs2_commit_trans(osb, handle); + +-out_free_group_bh: ++out_remove_cache: + if (ret < 0) +- ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); ++ ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh); ++ ++out_free_group_bh: + brelse(group_bh); + + out_unlock: +-- +2.53.0 + diff --git a/queue-6.6/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch b/queue-6.6/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch new file mode 100644 index 0000000000..bff774ec45 --- /dev/null +++ b/queue-6.6/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch @@ -0,0 +1,132 @@ +From d1250464475fd123e24a118d248f342c6590d861 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 19:46:54 -0700 +Subject: openvswitch: cap upcall PID array size and pre-size vport replies + +From: Weiming Shi + +[ Upstream commit 2091c6aa0df6aba47deb5c8ab232b1cb60af3519 ] + +The vport netlink reply helpers allocate a fixed-size skb with +nlmsg_new(NLMSG_DEFAULT_SIZE, ...) but serialize the full upcall PID +array via ovs_vport_get_upcall_portids(). Since +ovs_vport_set_upcall_portids() accepts any non-zero multiple of +sizeof(u32) with no upper bound, a CAP_NET_ADMIN user can install a PID +array large enough to overflow the reply buffer, causing nla_put() to +fail with -EMSGSIZE and hitting BUG_ON(err < 0). On systems with +unprivileged user namespaces enabled (e.g., Ubuntu default), this is +reachable via unshare -Urn since OVS vport mutation operations use +GENL_UNS_ADMIN_PERM. + + kernel BUG at net/openvswitch/datapath.c:2414! + Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI + CPU: 1 UID: 0 PID: 65 Comm: poc Not tainted 7.0.0-rc7-00195-geb216e422044 #1 + RIP: 0010:ovs_vport_cmd_set+0x34c/0x400 + Call Trace: + + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1116) + genl_rcv_msg (net/netlink/genetlink.c:1194) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + genl_rcv (net/netlink/genetlink.c:1219) + netlink_unicast (net/netlink/af_netlink.c:1344) + netlink_sendmsg (net/netlink/af_netlink.c:1894) + __sys_sendto (net/socket.c:2206) + __x64_sys_sendto (net/socket.c:2209) + do_syscall_64 (arch/x86/entry/syscall_64.c:63) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + + Kernel panic - not syncing: Fatal exception + +Reject attempts to set more PIDs than nr_cpu_ids in +ovs_vport_set_upcall_portids(), and pre-compute the worst-case reply +size in ovs_vport_cmd_msg_size() based on that bound, similar to the +existing ovs_dp_cmd_msg_size(). nr_cpu_ids matches the cap already +used by the per-CPU dispatch configuration on the datapath side +(ovs_dp_cmd_fill_info() serialises at most nr_cpu_ids PIDs), so the +two sides stay consistent. + +Fixes: 5cd667b0a456 ("openvswitch: Allow each vport to have an array of 'port_id's.") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Weiming Shi +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260416024653.153456-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 35 +++++++++++++++++++++++++++++++++-- + net/openvswitch/vport.c | 3 +++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index cb52fac7caa3c..7803e7548d920 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -2158,9 +2158,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + return err; + } + ++static size_t ovs_vport_cmd_msg_size(void) ++{ ++ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); ++ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */ ++ msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */ ++ msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */ ++ ++ /* OVS_VPORT_ATTR_STATS */ ++ msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats)); ++ ++ /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + ++ * OVS_VPORT_UPCALL_ATTR_FAIL) ++ */ ++ msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) + ++ nla_total_size_64bit(sizeof(u64))); ++ ++ /* OVS_VPORT_ATTR_UPCALL_PID */ ++ msgsize += nla_total_size(nr_cpu_ids * sizeof(u32)); ++ ++ /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + ++ * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) ++ */ ++ msgsize += nla_total_size(nla_total_size(sizeof(u16)) + ++ nla_total_size(nla_total_size(0))); ++ ++ return msgsize; ++} ++ + static struct sk_buff *ovs_vport_cmd_alloc_info(void) + { +- return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL); + } + + /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ +@@ -2170,7 +2201,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, + struct sk_buff *skb; + int retval; + +- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ skb = ovs_vport_cmd_alloc_info(); + if (!skb) + return ERR_PTR(-ENOMEM); + +diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c +index 0faa6e097829c..a0a8854e9f19e 100644 +--- a/net/openvswitch/vport.c ++++ b/net/openvswitch/vport.c +@@ -407,6 +407,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids) + if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) + return -EINVAL; + ++ if (nla_len(ids) / sizeof(u32) > nr_cpu_ids) ++ return -EINVAL; ++ + old = ovsl_dereference(vport->upcall_portids); + + vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), +-- +2.53.0 + diff --git a/queue-6.6/padata-put-cpu-offline-callback-in-online-section-to.patch b/queue-6.6/padata-put-cpu-offline-callback-in-online-section-to.patch new file mode 100644 index 0000000000..b415458bb0 --- /dev/null +++ b/queue-6.6/padata-put-cpu-offline-callback-in-online-section-to.patch @@ -0,0 +1,372 @@ +From 8381a0a1a8fe2eb2e40c927bf78dc99b3b0b0c25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 11:24:33 -0400 +Subject: padata: Put CPU offline callback in ONLINE section to allow failure + +From: Daniel Jordan + +[ Upstream commit c8c4a2972f83c8b68ff03b43cecdb898939ff851 ] + +syzbot reported the following warning: + + DEAD callback error for CPU1 + WARNING: kernel/cpu.c:1463 at _cpu_down+0x759/0x1020 kernel/cpu.c:1463, CPU#0: syz.0.1960/14614 + +at commit 4ae12d8bd9a8 ("Merge tag 'kbuild-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux") +which tglx traced to padata_cpu_dead() given it's the only +sub-CPUHP_TEARDOWN_CPU callback that returns an error. + +Failure isn't allowed in hotplug states before CPUHP_TEARDOWN_CPU +so move the CPU offline callback to the ONLINE section where failure is +possible. + +Fixes: 894c9ef9780c ("padata: validate cpumask without removed CPU during offline") +Reported-by: syzbot+123e1b70473ce213f3af@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69af0a05.050a0220.310d8.002f.GAE@google.com/ +Debugged-by: Thomas Gleixner +Signed-off-by: Daniel Jordan +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + include/linux/cpuhotplug.h | 1 - + include/linux/padata.h | 8 +-- + kernel/padata.c | 120 +++++++++++++++++++------------------ + 3 files changed, 65 insertions(+), 64 deletions(-) + +diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h +index 624d4a38c358a..72070333026b9 100644 +--- a/include/linux/cpuhotplug.h ++++ b/include/linux/cpuhotplug.h +@@ -98,7 +98,6 @@ enum cpuhp_state { + CPUHP_IOMMU_IOVA_DEAD, + CPUHP_LUSTRE_CFS_DEAD, + CPUHP_AP_ARM_CACHE_B15_RAC_DEAD, +- CPUHP_PADATA_DEAD, + CPUHP_AP_DTPM_CPU_DEAD, + CPUHP_RANDOM_PREPARE, + CPUHP_WORKQUEUE_PREP, +diff --git a/include/linux/padata.h b/include/linux/padata.h +index 6f07e12a43819..72f5899cc7a95 100644 +--- a/include/linux/padata.h ++++ b/include/linux/padata.h +@@ -147,23 +147,23 @@ struct padata_mt_job { + /** + * struct padata_instance - The overall control structure. + * +- * @cpu_online_node: Linkage for CPU online callback. +- * @cpu_dead_node: Linkage for CPU offline callback. ++ * @cpuhp_node: Linkage for CPU hotplug callbacks. + * @parallel_wq: The workqueue used for parallel work. + * @serial_wq: The workqueue used for serial work. + * @pslist: List of padata_shell objects attached to this instance. + * @cpumask: User supplied cpumasks for parallel and serial works. ++ * @validate_cpumask: Internal cpumask used to validate @cpumask during hotplug. + * @kobj: padata instance kernel object. + * @lock: padata instance lock. + * @flags: padata flags. + */ + struct padata_instance { +- struct hlist_node cpu_online_node; +- struct hlist_node cpu_dead_node; ++ struct hlist_node cpuhp_node; + struct workqueue_struct *parallel_wq; + struct workqueue_struct *serial_wq; + struct list_head pslist; + struct padata_cpumask cpumask; ++ cpumask_var_t validate_cpumask; + struct kobject kobj; + struct mutex lock; + u8 flags; +diff --git a/kernel/padata.c b/kernel/padata.c +index 4fd48905c60df..9e4037a0fd334 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -548,7 +548,8 @@ static void padata_init_reorder_list(struct parallel_data *pd) + } + + /* Allocate and initialize the internal cpumask dependend resources. */ +-static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) ++static struct parallel_data *padata_alloc_pd(struct padata_shell *ps, ++ int offlining_cpu) + { + struct padata_instance *pinst = ps->pinst; + struct parallel_data *pd; +@@ -574,6 +575,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) + + cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask); + cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask); ++ if (offlining_cpu >= 0) { ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.pcpu); ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.cbcpu); ++ } + + padata_init_reorder_list(pd); + padata_init_squeues(pd); +@@ -620,11 +625,11 @@ static void __padata_stop(struct padata_instance *pinst) + } + + /* Replace the internal control structure with a new one. */ +-static int padata_replace_one(struct padata_shell *ps) ++static int padata_replace_one(struct padata_shell *ps, int offlining_cpu) + { + struct parallel_data *pd_new; + +- pd_new = padata_alloc_pd(ps); ++ pd_new = padata_alloc_pd(ps, offlining_cpu); + if (!pd_new) + return -ENOMEM; + +@@ -634,7 +639,7 @@ static int padata_replace_one(struct padata_shell *ps) + return 0; + } + +-static int padata_replace(struct padata_instance *pinst) ++static int padata_replace(struct padata_instance *pinst, int offlining_cpu) + { + struct padata_shell *ps; + int err = 0; +@@ -642,7 +647,7 @@ static int padata_replace(struct padata_instance *pinst) + pinst->flags |= PADATA_RESET; + + list_for_each_entry(ps, &pinst->pslist, list) { +- err = padata_replace_one(ps); ++ err = padata_replace_one(ps, offlining_cpu); + if (err) + break; + } +@@ -659,9 +664,21 @@ static int padata_replace(struct padata_instance *pinst) + + /* If cpumask contains no active cpu, we mark the instance as invalid. */ + static bool padata_validate_cpumask(struct padata_instance *pinst, +- const struct cpumask *cpumask) ++ const struct cpumask *cpumask, ++ int offlining_cpu) + { +- if (!cpumask_intersects(cpumask, cpu_online_mask)) { ++ cpumask_copy(pinst->validate_cpumask, cpu_online_mask); ++ ++ /* ++ * @offlining_cpu is still in cpu_online_mask, so remove it here for ++ * validation. Using a sub-CPUHP_TEARDOWN_CPU hotplug state where ++ * @offlining_cpu wouldn't be in the online mask doesn't work because ++ * padata_cpu_offline() can fail but such a state doesn't allow failure. ++ */ ++ if (offlining_cpu >= 0) ++ __cpumask_clear_cpu(offlining_cpu, pinst->validate_cpumask); ++ ++ if (!cpumask_intersects(cpumask, pinst->validate_cpumask)) { + pinst->flags |= PADATA_INVALID; + return false; + } +@@ -677,13 +694,13 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + int valid; + int err; + +- valid = padata_validate_cpumask(pinst, pcpumask); ++ valid = padata_validate_cpumask(pinst, pcpumask, -1); + if (!valid) { + __padata_stop(pinst); + goto out_replace; + } + +- valid = padata_validate_cpumask(pinst, cbcpumask); ++ valid = padata_validate_cpumask(pinst, cbcpumask, -1); + if (!valid) + __padata_stop(pinst); + +@@ -691,7 +708,7 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + cpumask_copy(pinst->cpumask.pcpu, pcpumask); + cpumask_copy(pinst->cpumask.cbcpu, cbcpumask); + +- err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst); ++ err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst, -1); + + if (valid) + __padata_start(pinst); +@@ -743,26 +760,6 @@ EXPORT_SYMBOL(padata_set_cpumask); + + #ifdef CONFIG_HOTPLUG_CPU + +-static int __padata_add_cpu(struct padata_instance *pinst, int cpu) +-{ +- int err = padata_replace(pinst); +- +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- +- return err; +-} +- +-static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) +-{ +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- return padata_replace(pinst); +-} +- + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) + { + return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) || +@@ -774,27 +771,39 @@ static int padata_cpu_online(unsigned int cpu, struct hlist_node *node) + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_add_cpu(pinst, cpu); ++ ++ ret = padata_replace(pinst, -1); ++ ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu, -1) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, -1)) ++ __padata_start(pinst); ++ + mutex_unlock(&pinst->lock); + return ret; + } + +-static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node) ++static int padata_cpu_offline(unsigned int cpu, struct hlist_node *node) + { + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_remove_cpu(pinst, cpu); ++ ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu, cpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, cpu)) ++ __padata_stop(pinst); ++ ++ ret = padata_replace(pinst, cpu); ++ + mutex_unlock(&pinst->lock); + return ret; + } +@@ -805,15 +814,14 @@ static enum cpuhp_state hp_online; + static void __padata_free(struct padata_instance *pinst) + { + #ifdef CONFIG_HOTPLUG_CPU +- cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); +- cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node); ++ cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpuhp_node); + #endif + + WARN_ON(!list_empty(&pinst->pslist)); + + free_cpumask_var(pinst->cpumask.pcpu); + free_cpumask_var(pinst->cpumask.cbcpu); ++ free_cpumask_var(pinst->validate_cpumask); + destroy_workqueue(pinst->serial_wq); + destroy_workqueue(pinst->parallel_wq); + kfree(pinst); +@@ -973,10 +981,10 @@ struct padata_instance *padata_alloc(const char *name) + + if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL)) + goto err_free_serial_wq; +- if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) { +- free_cpumask_var(pinst->cpumask.pcpu); +- goto err_free_serial_wq; +- } ++ if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) ++ goto err_free_p_mask; ++ if (!alloc_cpumask_var(&pinst->validate_cpumask, GFP_KERNEL)) ++ goto err_free_cb_mask; + + INIT_LIST_HEAD(&pinst->pslist); + +@@ -984,7 +992,7 @@ struct padata_instance *padata_alloc(const char *name) + cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask); + + if (padata_setup_cpumasks(pinst)) +- goto err_free_masks; ++ goto err_free_v_mask; + + __padata_start(pinst); + +@@ -993,18 +1001,19 @@ struct padata_instance *padata_alloc(const char *name) + + #ifdef CONFIG_HOTPLUG_CPU + cpuhp_state_add_instance_nocalls_cpuslocked(hp_online, +- &pinst->cpu_online_node); +- cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); ++ &pinst->cpuhp_node); + #endif + + cpus_read_unlock(); + + return pinst; + +-err_free_masks: +- free_cpumask_var(pinst->cpumask.pcpu); ++err_free_v_mask: ++ free_cpumask_var(pinst->validate_cpumask); ++err_free_cb_mask: + free_cpumask_var(pinst->cpumask.cbcpu); ++err_free_p_mask: ++ free_cpumask_var(pinst->cpumask.pcpu); + err_free_serial_wq: + destroy_workqueue(pinst->serial_wq); + err_put_cpus: +@@ -1047,7 +1056,7 @@ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst) + ps->pinst = pinst; + + cpus_read_lock(); +- pd = padata_alloc_pd(ps); ++ pd = padata_alloc_pd(ps, -1); + cpus_read_unlock(); + + if (!pd) +@@ -1096,32 +1105,25 @@ void __init padata_init(void) + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online", +- padata_cpu_online, NULL); ++ padata_cpu_online, padata_cpu_offline); + if (ret < 0) + goto err; + hp_online = ret; +- +- ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead", +- NULL, padata_cpu_dead); +- if (ret < 0) +- goto remove_online_state; + #endif + + possible_cpus = num_possible_cpus(); + padata_works = kmalloc_array(possible_cpus, sizeof(struct padata_work), + GFP_KERNEL); + if (!padata_works) +- goto remove_dead_state; ++ goto remove_online_state; + + for (i = 0; i < possible_cpus; ++i) + list_add(&padata_works[i].pw_list, &padata_free_works); + + return; + +-remove_dead_state: +-#ifdef CONFIG_HOTPLUG_CPU +- cpuhp_remove_multi_state(CPUHP_PADATA_DEAD); + remove_online_state: ++#ifdef CONFIG_HOTPLUG_CPU + cpuhp_remove_multi_state(hp_online); + err: + #endif +-- +2.53.0 + diff --git a/queue-6.6/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch b/queue-6.6/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch new file mode 100644 index 0000000000..7a156eebd1 --- /dev/null +++ b/queue-6.6/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch @@ -0,0 +1,79 @@ +From 320965cc19086aaea335453886a607b4be309e6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 16:07:03 +0800 +Subject: padata: Remove cpu online check from cpu add and removal + +From: Chuyi Zhou + +[ Upstream commit 73117ea6470dca787f70f33c001f9faf437a1c0b ] + +During the CPU offline process, the dying CPU is cleared from the +cpu_online_mask in takedown_cpu(). After this step, various CPUHP_*_DEAD +callbacks are executed to perform cleanup jobs for the dead CPU, so this +cpu online check in padata_cpu_dead() is unnecessary. + +Similarly, when executing padata_cpu_online() during the +CPUHP_AP_ONLINE_DYN phase, the CPU has already been set in the +cpu_online_mask, the action even occurs earlier than the +CPUHP_AP_ONLINE_IDLE stage. + +Remove this unnecessary cpu online check in __padata_add_cpu() and +__padata_remove_cpu(). + +Signed-off-by: Chuyi Zhou +Acked-by: Daniel Jordan +Signed-off-by: Herbert Xu +Stable-dep-of: c8c4a2972f83 ("padata: Put CPU offline callback in ONLINE section to allow failure") +Signed-off-by: Sasha Levin +--- + kernel/padata.c | 26 ++++++++------------------ + 1 file changed, 8 insertions(+), 18 deletions(-) + +diff --git a/kernel/padata.c b/kernel/padata.c +index 44ea75bfd8681..4fd48905c60df 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -745,32 +745,22 @@ EXPORT_SYMBOL(padata_set_cpumask); + + static int __padata_add_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (cpumask_test_cpu(cpu, cpu_online_mask)) { +- err = padata_replace(pinst); ++ int err = padata_replace(pinst); + +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- } ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_start(pinst); + + return err; + } + + static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (!cpumask_test_cpu(cpu, cpu_online_mask)) { +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- err = padata_replace(pinst); +- } ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_stop(pinst); + +- return err; ++ return padata_replace(pinst); + } + + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) +-- +2.53.0 + diff --git a/queue-6.6/params-replace-__modinit-with-__init_or_module.patch b/queue-6.6/params-replace-__modinit-with-__init_or_module.patch new file mode 100644 index 0000000000..ae1f0b0fb6 --- /dev/null +++ b/queue-6.6/params-replace-__modinit-with-__init_or_module.patch @@ -0,0 +1,67 @@ +From d18d6e5db129bb5328bed2600d231647026036fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Aug 2025 14:12:09 +0200 +Subject: params: Replace __modinit with __init_or_module + +From: Petr Pavlu + +[ Upstream commit 3cb0c3bdea5388519bc1bf575dca6421b133302b ] + +Remove the custom __modinit macro from kernel/params.c and instead use the +common __init_or_module macro from include/linux/module.h. Both provide the +same functionality. + +Signed-off-by: Petr Pavlu +Reviewed-by: Aaron Tomlin +Reviewed-by: Daniel Gomez +Reviewed-by: Sami Tolvanen +Signed-off-by: Sami Tolvanen +Stable-dep-of: deffe1edba62 ("module: Fix freeing of charp module parameters when CONFIG_SYSFS=n") +Signed-off-by: Sasha Levin +--- + kernel/params.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +diff --git a/kernel/params.c b/kernel/params.c +index e39ac5420cd6d..2cfa12404ed0b 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -593,12 +593,6 @@ static ssize_t param_attr_store(struct module_attribute *mattr, + } + #endif + +-#ifdef CONFIG_MODULES +-#define __modinit +-#else +-#define __modinit __init +-#endif +- + #ifdef CONFIG_SYSFS + void kernel_param_lock(struct module *mod) + { +@@ -623,9 +617,9 @@ EXPORT_SYMBOL(kernel_param_unlock); + * create file in sysfs. Returns an error on out of memory. Always cleans up + * if there's an error. + */ +-static __modinit int add_sysfs_param(struct module_kobject *mk, +- const struct kernel_param *kp, +- const char *name) ++static __init_or_module int add_sysfs_param(struct module_kobject *mk, ++ const struct kernel_param *kp, ++ const char *name) + { + struct module_param_attrs *new_mp; + struct attribute **new_attrs; +@@ -759,7 +753,8 @@ void destroy_params(const struct kernel_param *params, unsigned num) + params[i].ops->free(params[i].arg); + } + +-struct module_kobject __modinit * lookup_or_create_module_kobject(const char *name) ++struct module_kobject * __init_or_module ++lookup_or_create_module_kobject(const char *name) + { + struct module_kobject *mk; + struct kobject *kobj; +-- +2.53.0 + diff --git a/queue-6.6/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch b/queue-6.6/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch new file mode 100644 index 0000000000..0018c5a13b --- /dev/null +++ b/queue-6.6/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch @@ -0,0 +1,63 @@ +From 43c46c03cb79f672d39a83b2614781bd180e0f9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:53 +0530 +Subject: PCI: dwc: Apply ECRC workaround to DesignWare 5.00a as well + +From: Manikanta Maddireddy + +[ Upstream commit 40805f32dceadebb7381d911003100bec7b8cd51 ] + +The ECRC (TLP digest) workaround was originally added for DesignWare +version 4.90a. Tegra234 SoC has 5.00a DWC HW version, which has the same +ATU TD override behaviour, so apply the workaround for 5.00a too. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-13-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c +index 46b12e157bebe..504450a8b6a45 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.c ++++ b/drivers/pci/controller/dwc/pcie-designware.c +@@ -426,13 +426,13 @@ static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg + static inline u32 dw_pcie_enable_ecrc(u32 val) + { + /* +- * DesignWare core version 4.90A has a design issue where the 'TD' +- * bit in the Control register-1 of the ATU outbound region acts +- * like an override for the ECRC setting, i.e., the presence of TLP +- * Digest (ECRC) in the outgoing TLPs is solely determined by this +- * bit. This is contrary to the PCIe spec which says that the +- * enablement of the ECRC is solely determined by the AER +- * registers. ++ * DWC versions 0x3530302a and 0x3536322a have a design issue where ++ * the 'TD' bit in the Control register-1 of the ATU outbound ++ * region acts like an override for the ECRC setting, i.e., the ++ * presence of TLP Digest (ECRC) in the outgoing TLPs is solely ++ * determined by this bit. This is contrary to the PCIe spec which ++ * says that the enablement of the ECRC is solely determined by the ++ * AER registers. + * + * Because of this, even when the ECRC is enabled through AER + * registers, the transactions going through ATU won't have TLP +@@ -502,7 +502,7 @@ static int __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, + if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) && + dw_pcie_ver_is_ge(pci, 460A)) + val |= PCIE_ATU_INCREASE_REGION_SIZE; +- if (dw_pcie_ver_is(pci, 490A)) ++ if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A)) + val = dw_pcie_enable_ecrc(val); + dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL1, val); + +-- +2.53.0 + diff --git a/queue-6.6/pci-enable-atomicops-only-if-root-port-supports-them.patch b/queue-6.6/pci-enable-atomicops-only-if-root-port-supports-them.patch new file mode 100644 index 0000000000..80e70647c2 --- /dev/null +++ b/queue-6.6/pci-enable-atomicops-only-if-root-port-supports-them.patch @@ -0,0 +1,110 @@ +From 315003f6a12684d5d4e5a016f07f86ccbbf87eb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:09:45 +0200 +Subject: PCI: Enable AtomicOps only if Root Port supports them + +From: Gerd Bayer + +[ Upstream commit 1ae8c4ce157037e266184064a182af9ef9af278b ] + +When inspecting the config space of a Connect-X physical function in an +s390 system after it was initialized by the mlx5_core device driver, we +found the function to be enabled to request AtomicOps despite the Root Port +lacking support for completing them: + + 00:00.1 Ethernet controller: Mellanox Technologies MT2894 Family [ConnectX-6 Lx] + Subsystem: Mellanox Technologies Device 0002 + DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- + AtomicOpsCtl: ReqEn+ + +On s390 and many virtualized guests, the Endpoint is visible but the Root +Port is not. In this case, pci_enable_atomic_ops_to_root() previously +enabled AtomicOps in the Endpoint even though it can't tell whether the +Root Port supports them as a completer. + +Change pci_enable_atomic_ops_to_root() to fail if there's no Root Port or +the Root Port doesn't support AtomicOps. + +Fixes: 430a23689dea ("PCI: Add pci_enable_atomic_ops_to_root()") +Reported-by: Alexander Schmidt +Signed-off-by: Gerd Bayer +[bhelgaas: commit log, check RP first to simplify flow] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260330-fix_pciatops-v7-2-f601818417e8@linux.ibm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 41 ++++++++++++++++++++--------------------- + 1 file changed, 20 insertions(+), 21 deletions(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index a21192ec5689b..e7648a1abfdbf 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -3956,8 +3956,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) + */ + int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + { +- struct pci_bus *bus = dev->bus; +- struct pci_dev *bridge; ++ struct pci_dev *root, *bridge; + u32 cap, ctl2; + + /* +@@ -3987,35 +3986,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + return -EINVAL; + } + +- while (bus->parent) { +- bridge = bus->self; ++ root = pcie_find_root_port(dev); ++ if (!root) ++ return -EINVAL; + +- pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap); ++ pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); ++ if ((cap & cap_mask) != cap_mask) ++ return -EINVAL; + ++ bridge = pci_upstream_bridge(dev); ++ while (bridge != root) { + switch (pci_pcie_type(bridge)) { +- /* Ensure switch ports support AtomicOp routing */ + case PCI_EXP_TYPE_UPSTREAM: +- case PCI_EXP_TYPE_DOWNSTREAM: +- if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) +- return -EINVAL; +- break; +- +- /* Ensure root port supports all the sizes we care about */ +- case PCI_EXP_TYPE_ROOT_PORT: +- if ((cap & cap_mask) != cap_mask) +- return -EINVAL; +- break; +- } +- +- /* Ensure upstream ports don't block AtomicOps on egress */ +- if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) { ++ /* Upstream ports must not block AtomicOps on egress */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, + &ctl2); + if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK) + return -EINVAL; ++ fallthrough; ++ ++ /* All switch ports need to route AtomicOps */ ++ case PCI_EXP_TYPE_DOWNSTREAM: ++ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, ++ &cap); ++ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) ++ return -EINVAL; ++ break; + } + +- bus = bus->parent; ++ bridge = pci_upstream_bridge(bridge); + } + + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, +-- +2.53.0 + diff --git a/queue-6.6/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch b/queue-6.6/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch new file mode 100644 index 0000000000..3ff382fa51 --- /dev/null +++ b/queue-6.6/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch @@ -0,0 +1,55 @@ +From 4c70fdca95a35ea11979e71db3eb2c0a92e5240a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 17:35:41 +0800 +Subject: PCI: mediatek-gen3: Prevent leaking IRQ domains when IRQ not found + +From: Chen-Yu Tsai + +[ Upstream commit 5573c44cb3fd01a9f62d569ae9ac870ef5f0e0ba ] + +In mtk_pcie_setup_irq(), the IRQ domains are allocated before the +controller's IRQ is fetched. If the latter fails, the function +directly returns an error, without cleaning up the allocated domains. + +Hence, reverse the order so that the IRQ domains are allocated after the +controller's IRQ is found. + +This was flagged by Sashiko during a review of "[PATCH v6 0/7] PCI: +mediatek-gen3: add power control support". + +Fixes: 814cceebba9b ("PCI: mediatek-gen3: Add INTx support") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Manivannan Sadhasivam +Link: https://sashiko.dev/#/patchset/20260324052002.4072430-1-wenst%40chromium.org +Link: https://patch.msgid.link/20260324093542.18523-1-wenst@chromium.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek-gen3.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c +index 975b3024fb08c..822d9b8e09f60 100644 +--- a/drivers/pci/controller/pcie-mediatek-gen3.c ++++ b/drivers/pci/controller/pcie-mediatek-gen3.c +@@ -760,14 +760,14 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie) + struct platform_device *pdev = to_platform_device(dev); + int err; + +- err = mtk_pcie_init_irq_domains(pcie); +- if (err) +- return err; +- + pcie->irq = platform_get_irq(pdev, 0); + if (pcie->irq < 0) + return pcie->irq; + ++ err = mtk_pcie_init_irq_domains(pcie); ++ if (err) ++ return err; ++ + irq_set_chained_handler_and_data(pcie->irq, mtk_pcie_irq_handler, pcie); + + return 0; +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch b/queue-6.6/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch new file mode 100644 index 0000000000..b23fd781fb --- /dev/null +++ b/queue-6.6/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch @@ -0,0 +1,108 @@ +From e49eb8e001d4575c2f74fea67eb9e0b151e7e486 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:50 +0530 +Subject: PCI: tegra194: Allow system suspend when the Endpoint link is not up + +From: Vidya Sagar + +[ Upstream commit c76f8eae7d4695b1176c4ea5eb93c17e16a20272 ] + +Host software initiates the L2 sequence. PCIe link is kept in L2 state +during suspend. If Endpoint mode is enabled and the link is up, the +software cannot proceed with suspend. However, when the PCIe Endpoint +driver is probed, but the PCIe link is not up, Tegra can go into suspend +state. So, allow system to suspend in this case. + +Fixes: de2bbf2b71bb ("PCI: tegra194: Don't allow suspend when Tegra PCIe is in EP mode") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-10-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 31 +++++++++++++++++----- + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index b29d1edd4c9bd..cab6cd5b8f3cd 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2307,16 +2307,28 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev) + gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0); + } + +-static int tegra_pcie_dw_suspend_late(struct device *dev) ++static int tegra_pcie_dw_suspend(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); +- u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n"); +- return -EPERM; ++ if (pcie->ep_state == EP_STATE_ENABLED) { ++ dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n"); ++ return -EPERM; ++ } ++ ++ disable_irq(pcie->pex_rst_irq); ++ return 0; + } + ++ return 0; ++} ++ ++static int tegra_pcie_dw_suspend_late(struct device *dev) ++{ ++ struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); ++ u32 val; ++ + if (!pcie->link_state) + return 0; + +@@ -2336,6 +2348,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2350,6 +2365,9 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + int ret; + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2382,8 +2400,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev) + u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Suspend is not supported in EP mode"); +- return -ENOTSUPP; ++ enable_irq(pcie->pex_rst_irq); ++ return 0; + } + + if (!pcie->link_state) +@@ -2488,6 +2506,7 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = { + }; + + static const struct dev_pm_ops tegra_pcie_dw_pm_ops = { ++ .suspend = tegra_pcie_dw_suspend, + .suspend_late = tegra_pcie_dw_suspend_late, + .suspend_noirq = tegra_pcie_dw_suspend_noirq, + .resume_noirq = tegra_pcie_dw_resume_noirq, +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-disable-direct-speed-change-for-endpoin.patch b/queue-6.6/pci-tegra194-disable-direct-speed-change-for-endpoin.patch new file mode 100644 index 0000000000..a603f6e972 --- /dev/null +++ b/queue-6.6/pci-tegra194-disable-direct-speed-change-for-endpoin.patch @@ -0,0 +1,52 @@ +From 69188cb51284878ed198744e18ab4fc511556475 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:48 +0530 +Subject: PCI: tegra194: Disable direct speed change for Endpoint mode + +From: Vidya Sagar + +[ Upstream commit 976f6763f57970388bcd7118931f33f447916927 ] + +Pre-silicon simulation showed the controller operating in Endpoint mode +initiating link speed change after completing Secondary Bus Reset. Ideally, +the Root Port or the Switch Downstream Port should initiate the link speed +change post SBR, not the Endpoint. + +So, as per the hardware team recommendation, disable direct speed change +for the Endpoint mode to prevent it from initiating speed change after the +physical layer link is up at Gen1, leaving speed change ownership with the +host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-8-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index dba73a0ea4210..b29d1edd4c9bd 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1839,6 +1839,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); ++ val &= ~PORT_LOGIC_SPEED_CHANGE; ++ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); ++ + if (pcie->update_fc_fixup) { + val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); + val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-disable-ltssm-after-transition-to-detec.patch b/queue-6.6/pci-tegra194-disable-ltssm-after-transition-to-detec.patch new file mode 100644 index 0000000000..8d55f17754 --- /dev/null +++ b/queue-6.6/pci-tegra194-disable-ltssm-after-transition-to-detec.patch @@ -0,0 +1,92 @@ +From 24cf3f51b59edc6fd4684b8a4503c8a594af6d82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:44 +0530 +Subject: PCI: tegra194: Disable LTSSM after transition to Detect on surprise + link down + +From: Manikanta Maddireddy + +[ Upstream commit 9fa0c242f8d7acf1b124d4462d18f4023573ac1c ] + +After the link reaches a Detect-related LTSSM state, disable LTSSM so it +does not keep toggling between Polling and Detect. Do this by polling for +the Detect state first, then clearing APPL_CTRL_LTSSM_EN in both +tegra_pcie_dw_pme_turnoff() and pex_ep_event_pex_rst_assert(). + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-4-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 29 ++++++++++++---------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index db5af8d32d18a..e79f77c3152da 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1624,14 +1624,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_PINMUX_PEX_RST; + appl_writel(pcie, data, APPL_PINMUX); + +- /* +- * Some cards do not go to detect state even after de-asserting +- * PERST#. So, de-assert LTSSM to bring link to detect state. +- */ +- data = readl(pcie->appl_base + APPL_CTRL); +- data &= ~APPL_CTRL_LTSSM_EN; +- writel(data, pcie->appl_base + APPL_CTRL); +- + err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1640,6 +1632,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); ++ ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ data = readl(pcie->appl_base + APPL_CTRL); ++ data &= ~APPL_CTRL_LTSSM_EN; ++ writel(data, pcie->appl_base + APPL_CTRL); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1721,11 +1721,6 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (pcie->ep_state == EP_STATE_DISABLED) + return; + +- /* Disable LTSSM */ +- val = appl_readl(pcie, APPL_CTRL); +- val &= ~APPL_CTRL_LTSSM_EN; +- appl_writel(pcie, val, APPL_CTRL); +- + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1736,6 +1731,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (ret) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ val = appl_readl(pcie, APPL_CTRL); ++ val &= ~APPL_CTRL_LTSSM_EN; ++ appl_writel(pcie, val, APPL_CTRL); ++ + reset_control_assert(pcie->core_rst); + + tegra_pcie_disable_phy(pcie); +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch b/queue-6.6/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch new file mode 100644 index 0000000000..32509f3af7 --- /dev/null +++ b/queue-6.6/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch @@ -0,0 +1,52 @@ +From 8a749c35580b49c44a0d2ddf2f5f6a8ff935c771 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:46 +0530 +Subject: PCI: tegra194: Disable PERST# IRQ only in Endpoint mode + +From: Manikanta Maddireddy + +[ Upstream commit 40658a31b6e134169c648041efc84944c4c71dcd ] + +The PERST# GPIO interrupt is only registered when the controller is +operating in Endpoint mode. In Root Port mode, the PERST# GPIO is +configured as an output to control downstream devices, and no interrupt is +registered for it. + +Currently, tegra_pcie_dw_stop_link() unconditionally calls disable_irq() +on pex_rst_irq, which causes issues in Root Port mode where this IRQ is +not registered. + +Fix this by only disabling the PERST# IRQ when operating in Endpoint mode, +where the interrupt is actually registered and used to detect PERST# +assertion/deassertion from the host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-6-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 23c7c6e691b26..ed0d12ab579d8 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1055,7 +1055,8 @@ static void tegra_pcie_dw_stop_link(struct dw_pcie *pci) + { + struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); + +- disable_irq(pcie->pex_rst_irq); ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ disable_irq(pcie->pex_rst_irq); + } + + static const struct dw_pcie_ops tegra_dw_pcie_ops = { +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch b/queue-6.6/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch new file mode 100644 index 0000000000..0d711b151b --- /dev/null +++ b/queue-6.6/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch @@ -0,0 +1,111 @@ +From c59bb6203eb4a1a54ef2b267632dbb37d8ed941d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:45 +0530 +Subject: PCI: tegra194: Don't force the device into the D0 state before L2 + +From: Vidya Sagar + +[ Upstream commit 71d9f67701e1affc82d18ca88ae798c5361beddf ] + +As per PCIe CEM r6.0, sec 2.3, the PCIe Endpoint device should be in D3cold +to assert WAKE# pin. The previous workaround that forced downstream devices +to D0 before taking the link to L2 cited PCIe r4.0, sec 5.2, "Link State +Power Management"; however, that spec does not explicitly require putting +the device into D0 and only indicates that power removal may be initiated +without transitioning to D3hot. + +Remove the D0 workaround so that Endpoint devices can use wake +functionality (WAKE# from D3). With some Endpoints the link may not enter +L2 when they remain in D3, but the Root Port continues with the usual flow +after PME timeout, so there is no functional issue. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-5-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 41 ---------------------- + 1 file changed, 41 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 47421796cc147..23c7c6e691b26 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1288,44 +1288,6 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, + return 0; + } + +-static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) +-{ +- struct dw_pcie_rp *pp = &pcie->pci.pp; +- struct pci_bus *child, *root_port_bus = NULL; +- struct pci_dev *pdev; +- +- /* +- * link doesn't go into L2 state with some of the endpoints with Tegra +- * if they are not in D0 state. So, need to make sure that immediate +- * downstream devices are in D0 state before sending PME_TurnOff to put +- * link into L2 state. +- * This is as per PCI Express Base r4.0 v1.0 September 27-2017, +- * 5.2 Link State Power Management (Page #428). +- */ +- +- list_for_each_entry(child, &pp->bridge->bus->children, node) { +- if (child->parent == pp->bridge->bus) { +- root_port_bus = child; +- break; +- } +- } +- +- if (!root_port_bus) { +- dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); +- return; +- } +- +- /* Bring downstream devices to D0 if they are not already in */ +- list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { +- if (PCI_SLOT(pdev->devfn) == 0) { +- if (pci_set_power_state(pdev, PCI_D0)) +- dev_err(pcie->dev, +- "Failed to transition %s to D0 state\n", +- dev_name(&pdev->dev)); +- } +- } +-} +- + static int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie) + { + pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3"); +@@ -1655,7 +1617,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + + static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) + { +- tegra_pcie_downstream_dev_to_D0(pcie); + dw_pcie_host_deinit(&pcie->pci.pp); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); +@@ -2373,7 +2334,6 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + if (!pcie->link_state) + return 0; + +- tegra_pcie_downstream_dev_to_D0(pcie); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); + +@@ -2447,7 +2407,6 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev) + return; + + debugfs_remove_recursive(pcie->debugfs); +- tegra_pcie_downstream_dev_to_D0(pcie); + + disable_irq(pcie->pci.pp.irq); + if (IS_ENABLED(CONFIG_PCI_MSI)) +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-fix-polling-delay-for-l2-state.patch b/queue-6.6/pci-tegra194-fix-polling-delay-for-l2-state.patch new file mode 100644 index 0000000000..fae32789ce --- /dev/null +++ b/queue-6.6/pci-tegra194-fix-polling-delay-for-l2-state.patch @@ -0,0 +1,59 @@ +From f62e21007064b499019dca9807184aaf888108a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:42 +0530 +Subject: PCI: tegra194: Fix polling delay for L2 state + +From: Vidya Sagar + +[ Upstream commit adaffed907f14f954096555665ad6af2ae724d83 ] + +As per PCIe r7.0, sec 5.3.3.2.1, after sending PME_Turn_Off message, Root +Port should wait for 1-10 msec for PME_TO_Ack message. Currently, driver is +polling for 10 msec with 1 usec delay which is aggressive. Use existing +macro PCIE_PME_TO_L2_TIMEOUT_US to poll for 10 msec with 1 msec delay. +Since this function is used in non-atomic context only, use non-atomic poll +function. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index ce2a7a6dab90c..6a4e0dc0d1dce 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -205,8 +205,6 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define PME_ACK_TIMEOUT 10000 +- + #define LTSSM_TIMEOUT 50000 /* 50ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 +@@ -1583,9 +1581,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) + val |= APPL_PM_XMT_TURNOFF_STATE; + appl_writel(pcie, val, APPL_RADM_STATUS); + +- return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val, +- val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, +- 1, PME_ACK_TIMEOUT); ++ return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, ++ val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, ++ PCIE_PME_TO_L2_TIMEOUT_US/10, ++ PCIE_PME_TO_L2_TIMEOUT_US); + } + + static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch b/queue-6.6/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch new file mode 100644 index 0000000000..56dbb99db1 --- /dev/null +++ b/queue-6.6/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch @@ -0,0 +1,106 @@ +From 41825bbcf38646fe0264d50eb22d2d4307584550 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:43 +0530 +Subject: PCI: tegra194: Increase LTSSM poll time on surprise link down + +From: Manikanta Maddireddy + +[ Upstream commit 74dd8efe4d6cead433162147333af989a568aac7 ] + +On surprise link down, LTSSM state transits from L0 -> Recovery.RcvrLock -> +Recovery.RcvrSpeed -> Gen1 Recovery.RcvrLock -> Detect. Recovery.RcvrLock +and Recovery.RcvrSpeed transit times are 24 ms and 48 ms respectively, so +the total time from L0 to Detect is ~96 ms. Increase the poll timeout to +120 ms to account for this. + +While at it, add LTSSM state defines for Detect-related states and use them +in the poll condition. Use readl_poll_timeout() instead of +readl_poll_timeout_atomic() in tegra_pcie_dw_pme_turnoff() since that path +runs in non-atomic context. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-3-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 36 +++++++++++++--------- + 1 file changed, 21 insertions(+), 15 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 6a4e0dc0d1dce..db5af8d32d18a 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -139,7 +139,11 @@ + #define APPL_DEBUG_PM_LINKST_IN_L0 0x11 + #define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) + #define APPL_DEBUG_LTSSM_STATE_SHIFT 3 +-#define LTSSM_STATE_PRE_DETECT 5 ++#define LTSSM_STATE_DETECT_QUIET 0x00 ++#define LTSSM_STATE_DETECT_ACT 0x08 ++#define LTSSM_STATE_PRE_DETECT_QUIET 0x28 ++#define LTSSM_STATE_DETECT_WAIT 0x30 ++#define LTSSM_STATE_L2_IDLE 0xa8 + + #define APPL_RADM_STATUS 0xE4 + #define APPL_PM_XMT_TURNOFF_STATE BIT(0) +@@ -205,7 +209,8 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define LTSSM_TIMEOUT 50000 /* 50ms */ ++#define LTSSM_DELAY_US 10000 /* 10 ms */ ++#define LTSSM_TIMEOUT_US 120000 /* 120 ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 + +@@ -1627,15 +1632,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_CTRL_LTSSM_EN; + writel(data, pcie->appl_base + APPL_CTRL); + +- err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, +- data, +- ((data & +- APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) +- dev_info(pcie->dev, "Link didn't go to detect state\n"); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1723,12 +1727,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + appl_writel(pcie, val, APPL_CTRL); + + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, +- ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (ret) +- dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + + reset_control_assert(pcie->core_rst); + +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch b/queue-6.6/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch new file mode 100644 index 0000000000..601b359a55 --- /dev/null +++ b/queue-6.6/pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch @@ -0,0 +1,69 @@ +From 4547e9674e7fc99706bc7767d70198a18f242871 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Sep 2025 13:40:57 +0530 +Subject: PCI: tegra194: Rename 'root_bus' to 'root_port_bus' in + tegra_pcie_downstream_dev_to_D0() + +From: Manivannan Sadhasivam + +[ Upstream commit e1bd928479fb1fa60e9034b0fdb1ab9f3fa92f33 ] + +In tegra_pcie_downstream_dev_to_D0(), PCI devices are transitioned to D0 +state. For iterating over the devices, first the downstream bus of the Root +Port is searched from the root bus. But the name of the variable that holds +the Root Port downstream bus is named as 'root_bus', which is wrong. + +Rename the variable to 'root_port_bus'. Also, move the comment on 'bringing +the devices to D0' to where the state is set exactly. + +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20250922081057.15209-1-mani@kernel.org +Stable-dep-of: 71d9f67701e1 ("PCI: tegra194: Don't force the device into the D0 state before L2") +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index e79f77c3152da..47421796cc147 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1291,7 +1291,7 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, + static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) + { + struct dw_pcie_rp *pp = &pcie->pci.pp; +- struct pci_bus *child, *root_bus = NULL; ++ struct pci_bus *child, *root_port_bus = NULL; + struct pci_dev *pdev; + + /* +@@ -1304,19 +1304,19 @@ static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) + */ + + list_for_each_entry(child, &pp->bridge->bus->children, node) { +- /* Bring downstream devices to D0 if they are not already in */ + if (child->parent == pp->bridge->bus) { +- root_bus = child; ++ root_port_bus = child; + break; + } + } + +- if (!root_bus) { +- dev_err(pcie->dev, "Failed to find downstream devices\n"); ++ if (!root_port_bus) { ++ dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); + return; + } + +- list_for_each_entry(pdev, &root_bus->devices, bus_list) { ++ /* Bring downstream devices to D0 if they are not already in */ ++ list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { + if (PCI_SLOT(pdev->devfn) == 0) { + if (pci_set_power_state(pdev, PCI_D0)) + dev_err(pcie->dev, +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch b/queue-6.6/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch new file mode 100644 index 0000000000..bd0b6c36ee --- /dev/null +++ b/queue-6.6/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch @@ -0,0 +1,47 @@ +From d3790a46c5bb918166de271516a0d15b6db7a507 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:47 +0530 +Subject: PCI: tegra194: Use devm_gpiod_get_optional() to parse + "nvidia,refclk-select" + +From: Vidya Sagar + +[ Upstream commit f62bc7917de1374dce86a852ffba8baf9cb7a56a ] + +The GPIO DT property "nvidia,refclk-select", to select the PCIe reference +clock is optional. Use devm_gpiod_get_optional() to get it. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-7-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index ed0d12ab579d8..dba73a0ea4210 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1197,9 +1197,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) + return err; + } + +- pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, +- "nvidia,refclk-select", +- GPIOD_OUT_HIGH); ++ pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev, ++ "nvidia,refclk-select", ++ GPIOD_OUT_HIGH); + if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { + int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); + const char *level = KERN_ERR; +-- +2.53.0 + diff --git a/queue-6.6/pci-tegra194-use-dwc-ip-core-version.patch b/queue-6.6/pci-tegra194-use-dwc-ip-core-version.patch new file mode 100644 index 0000000000..e3e5936cda --- /dev/null +++ b/queue-6.6/pci-tegra194-use-dwc-ip-core-version.patch @@ -0,0 +1,65 @@ +From e3f2042911f5c6a897622b6d0431a04a49bdf8b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:52 +0530 +Subject: PCI: tegra194: Use DWC IP core version + +From: Manikanta Maddireddy + +[ Upstream commit ea60ca067f0f098043610c96a915d162113c1aac ] + +Tegra194 PCIe driver used custom version numbers to detect Tegra194 and +Tegra234 IPs. With version detect logic added, version check results in +mismatch warnings: + + tegra194-pcie 14100000.pcie: Versions don't match (0000562a != 3536322a) + +Use HW version numbers which match to PORT_LOGIC.PCIE_VERSION_OFF in +Tegra194 driver to avoid these kernel warnings. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-12-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.h | 2 ++ + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index fec9473869bce..1ffa31797a17c 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -31,8 +31,10 @@ + #define DW_PCIE_VER_470A 0x3437302a + #define DW_PCIE_VER_480A 0x3438302a + #define DW_PCIE_VER_490A 0x3439302a ++#define DW_PCIE_VER_500A 0x3530302a + #define DW_PCIE_VER_520A 0x3532302a + #define DW_PCIE_VER_540A 0x3534302a ++#define DW_PCIE_VER_562A 0x3536322a + + #define __dw_pcie_ver_cmp(_pci, _ver, _op) \ + ((_pci)->version _op DW_PCIE_VER_ ## _ver) +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index cab6cd5b8f3cd..89109e380635c 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -37,8 +37,8 @@ + #include + #include "../../pci.h" + +-#define TEGRA194_DWC_IP_VER 0x490A +-#define TEGRA234_DWC_IP_VER 0x562A ++#define TEGRA194_DWC_IP_VER DW_PCIE_VER_500A ++#define TEGRA234_DWC_IP_VER DW_PCIE_VER_562A + + #define APPL_PINMUX 0x0 + #define APPL_PINMUX_PEX_RST BIT(0) +-- +2.53.0 + diff --git a/queue-6.6/pcmcia-fix-garbled-log-messages-for-kern_cont.patch b/queue-6.6/pcmcia-fix-garbled-log-messages-for-kern_cont.patch new file mode 100644 index 0000000000..00f5d6eda6 --- /dev/null +++ b/queue-6.6/pcmcia-fix-garbled-log-messages-for-kern_cont.patch @@ -0,0 +1,55 @@ +From 5226df8e229c497c8c773783450215b4fe554c7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 17:42:56 +0100 +Subject: PCMCIA: Fix garbled log messages for KERN_CONT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit bfeaa6814bd3f9a1f6d525b3b35a03b9a0368961 ] + +For years the PCMCIA info messages are messed up by superfluous +newlines. While f2e6cf76751d ("pcmcia: Convert dev_printk to +dev_") converted the code to pr_cont(), dev_info enforces a \n +via vprintk_store setting LOG_NEWLINE, breaking subsequent pr_cont. + +Fix by logging the device name manually to allow pr_cont to work for +more readable and not \n distorted logs. + +Fixes: f2e6cf76751d ("pcmcia: Convert dev_printk to dev_") +Signed-off-by: René Rebe +Signed-off-by: Dominik Brodowski +Signed-off-by: Sasha Levin +--- + drivers/pcmcia/rsrc_nonstatic.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c +index da494fe451baf..efc439c748862 100644 +--- a/drivers/pcmcia/rsrc_nonstatic.c ++++ b/drivers/pcmcia/rsrc_nonstatic.c +@@ -188,7 +188,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, + int any; + u_char *b, hole, most; + +- dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1); ++ pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1); + + /* First, what does a floating port look like? */ + b = kzalloc(256, GFP_KERNEL); +@@ -410,8 +410,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + struct socket_data *s_data = s->resource_data; + u_long i, j, bad, fail, step; + +- dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:", +- base, base+num-1); ++ pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:", ++ dev_name(&s->dev), base, base+num-1); + bad = fail = 0; + step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + /* don't allow too large steps */ +-- +2.53.0 + diff --git a/queue-6.6/perf-branch-avoid-incrementing-null.patch b/queue-6.6/perf-branch-avoid-incrementing-null.patch new file mode 100644 index 0000000000..89c88751b8 --- /dev/null +++ b/queue-6.6/perf-branch-avoid-incrementing-null.patch @@ -0,0 +1,39 @@ +From eaeb390ca7761696273407a02685d488f03e0b86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:31:31 -0700 +Subject: perf branch: Avoid incrementing NULL + +From: Ian Rogers + +[ Upstream commit c969a9d7bbf46f983c4a48566b3b2f7340b02296 ] + +If the entry is NULL the value is meaningless so early return NULL to +avoid an increment of NULL. This was happening in calls from +has_stitched_lbr when running the "perf record LBR tests". The return +value isn't used in that case, so returning NULL as no effect. + +Fixes: 42bbabed09ce ("perf tools: Add hw_idx in struct branch_stack") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/branch.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h +index e41bfffe22170..31ad6ded983ec 100644 +--- a/tools/perf/util/branch.h ++++ b/tools/perf/util/branch.h +@@ -64,6 +64,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl + { + u64 *entry = (u64 *)sample->branch_stack; + ++ if (entry == NULL) ++ return NULL; ++ + entry++; + if (sample->no_hw_idx) + return (struct branch_entry *)entry; +-- +2.53.0 + diff --git a/queue-6.6/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch b/queue-6.6/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch new file mode 100644 index 0000000000..779a16014a --- /dev/null +++ b/queue-6.6/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch @@ -0,0 +1,57 @@ +From 463ae5b3aa045e1afb3d32ab78490e5d7696a2a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:04:47 +0100 +Subject: perf expr: Return -EINVAL for syntax error in expr__find_ids() + +From: Leo Yan + +[ Upstream commit 3a61fd866ef9aaa1d3158b460f852b74a2df07f4 ] + +expr__find_ids() propagates the parser return value directly. For syntax +errors, the parser can return a positive value, but callers treat it as +success, e.g., for below case on Arm64 platform: + + metric expr 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) for backend_bound + parsing metric: 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) + Failure to read '#slots' literal: #slots = nan + syntax error + +Convert positive parser returns in expr__find_ids() to -EINVAL, as a +result, the error value will be respected by callers. + +Before: + + perf stat -C 5 + Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Segmentation fault + +After: + + perf stat -C 5 + Failure to read '#slots'Cannot find metric or group `Default' + +Fixes: ded80bda8bc9 ("perf expr: Migrate expr ids table to a hashmap") +Signed-off-by: Leo Yan +Reviewed-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/expr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index fa0473f7a4ff4..d952ce37c873b 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -377,7 +377,8 @@ int expr__find_ids(const char *expr, const char *one, + if (one) + expr__del_id(ctx, one); + +- return ret; ++ /* A positive value means syntax error, convert to -EINVAL */ ++ return ret > 0 ? -EINVAL : ret; + } + + double expr_id_data__value(const struct expr_id_data *data) +-- +2.53.0 + diff --git a/queue-6.6/perf-lock-fix-option-value-type-in-parse_max_stack.patch b/queue-6.6/perf-lock-fix-option-value-type-in-parse_max_stack.patch new file mode 100644 index 0000000000..851d8c3ee1 --- /dev/null +++ b/queue-6.6/perf-lock-fix-option-value-type-in-parse_max_stack.patch @@ -0,0 +1,38 @@ +From 90866ab0bd523303d999ba6b8398f67dedf74e0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 16:33:48 -0700 +Subject: perf lock: Fix option value type in parse_max_stack + +From: Ian Rogers + +[ Upstream commit cfaade34b52aa1ec553044255702c4b31b57c005 ] + +The value is a void* and the address of an int, max_stack_depth, is +set up in the perf lock options. The parse_max_stack function treats +the int* as a long*, make this more correct by declaring the value to +be an int*. + +Fixes: 0a277b622670 ("perf lock contention: Check --max-stack option") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-lock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c +index bd24ed0af208a..bd294fd574972 100644 +--- a/tools/perf/builtin-lock.c ++++ b/tools/perf/builtin-lock.c +@@ -2271,7 +2271,7 @@ static int parse_map_entry(const struct option *opt, const char *str, + static int parse_max_stack(const struct option *opt, const char *str, + int unset __maybe_unused) + { +- unsigned long *len = (unsigned long *)opt->value; ++ int *len = opt->value; + long val; + char *endptr; + +-- +2.53.0 + diff --git a/queue-6.6/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch b/queue-6.6/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch new file mode 100644 index 0000000000..d55a91f264 --- /dev/null +++ b/queue-6.6/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch @@ -0,0 +1,115 @@ +From dd248ac441b52618a37018c9c48948d316665b62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:36:39 +0000 +Subject: perf: tools: cs-etm: Fix print issue for Coresight debug in ETE/TRBE + trace + +From: Mike Leach + +[ Upstream commit 6c478e7b3eba3f387a2d6c749e3e3ee0f8ad1c53 ] + +Building perf with CORESIGHT=1 and the optional CSTRACE_RAW=1 enables +additional debug printing of raw trace data when using command:- +perf report --dump. + +This raw trace prints the CoreSight formatted trace frames, which may be +used to investigate suspected issues with trace quality / corruption / +decode. + +These frames are not present in ETE + TRBE trace. +This fix removes the unnecessary call to print these frames. + +This fix also rationalises implementation - original code had helper +function that unnecessarily repeated initialisation calls that had +already been made. + +Due to an addtional fault with the OpenCSD library, this call when ETE/TRBE +are being decoded will cause a segfault in perf. This fix also prevents +that problem for perf using older (<= 1.8.0 version) OpenCSD libraries. + +Fixes: 68ffe3902898 ("perf tools: Add decoder mechanic to support dumping trace data") +Reported-by: Leo Yan +Signed-off-by: Mike Leach +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 51 +++++-------------- + 1 file changed, 13 insertions(+), 38 deletions(-) + +diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +index e917985bbbe6d..640e383cef441 100644 +--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c ++++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +@@ -237,46 +237,24 @@ cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, + (void *)decoder, + cs_etm_decoder__print_str_cb); + if (ret != 0) +- ret = -1; +- +- return 0; +-} ++ return -1; + + #ifdef CS_LOG_RAW_FRAMES +-static void +-cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params, +- struct cs_etm_decoder *decoder) +-{ +- /* Only log these during a --dump operation */ +- if (d_params->operation == CS_ETM_OPERATION_PRINT) { +- /* set up a library default logger to process the +- * raw frame printer we add later +- */ +- ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); +- +- /* no stdout / err / file output */ +- ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); +- +- /* set the string CB for the default logger, +- * passes strings to perf print logger. +- */ +- ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, +- (void *)decoder, +- cs_etm_decoder__print_str_cb); +- ++ /* ++ * Only log raw frames if --dump operation and hardware is actually ++ * generating formatted CoreSight trace frames ++ */ ++ if ((d_params->operation == CS_ETM_OPERATION_PRINT) && ++ (d_params->formatted == true)) { + /* use the built in library printer for the raw frames */ +- ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, +- CS_RAW_DEBUG_FLAGS); ++ ret = ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, ++ CS_RAW_DEBUG_FLAGS); ++ if (ret != 0) ++ return -1; + } +-} +-#else +-static void +-cs_etm_decoder__init_raw_frame_logging( +- struct cs_etm_decoder_params *d_params __maybe_unused, +- struct cs_etm_decoder *decoder __maybe_unused) +-{ +-} + #endif ++ return 0; ++} + + static ocsd_datapath_resp_t + cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, +@@ -755,9 +733,6 @@ cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params, + if (ret != 0) + goto err_free_decoder; + +- /* init raw frame logging if required */ +- cs_etm_decoder__init_raw_frame_logging(d_params, decoder); +- + for (i = 0; i < decoders; i++) { + ret = cs_etm_decoder__create_etm_decoder(d_params, + &t_params[i], +-- +2.53.0 + diff --git a/queue-6.6/perf-tools-fix-module-symbol-resolution-for-non-zero.patch b/queue-6.6/perf-tools-fix-module-symbol-resolution-for-non-zero.patch new file mode 100644 index 0000000000..6bc5a8abfa --- /dev/null +++ b/queue-6.6/perf-tools-fix-module-symbol-resolution-for-non-zero.patch @@ -0,0 +1,77 @@ +From 7dc199b1240fbd280bb59ace2f4472758f5aab10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 11:58:04 -0400 +Subject: perf tools: Fix module symbol resolution for non-zero .text sh_addr + +From: Chuck Lever + +[ Upstream commit 9a82bfde4775b7a87cd1a7e791f46f83ae442848 ] + +When perf resolves symbols from kernel module ELF files (ET_REL), +it converts symbol addresses to file offsets so that sample IPs +can be matched to the correct symbol. The conversion adjusts each +symbol's st_value: + + sym->st_value -= shdr->sh_addr - shdr->sh_offset; + +For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr +is the section's virtual base, so subtracting sh_addr and adding +sh_offset correctly yields a file offset. + +For kernel modules (ET_REL), st_value is a section-relative +offset. The module loader ignores sh_addr entirely and places +symbols at module_base + st_value. Converting to file offset +requires only adding sh_offset; subtracting sh_addr introduces an +error equal to sh_addr bytes. + +When .text has sh_addr == 0 -- the historical norm for simple +modules -- both formulas produce the same result and the bug is +latent. As modules gain more metadata sections before .text (.note, +.static_call.text, etc.), the linker assigns .text a non-zero +sh_addr, exposing the defect. For example, nfsd.ko on this kernel +has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90. + +The effect is that all .text symbols in affected modules +shift by sh_addr bytes relative to sample IPs, causing perf +report to attribute samples to incorrect, nearby symbols. This +was observed as 13% of LLC-load-miss samples misattributed +to nfsd_file_get_dio_attrs when the actual hot function was +nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol +table. + +Use the existing dso__rel() flag (already set for ET_REL modules) +to select the correct adjustment: add sh_offset for ET_REL, +subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN. + +Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules") +Signed-off-by: Chuck Lever +Reviewed-by: Ian Rogers +Tested-by: Thomas Richter +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/symbol-elf.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c +index 95e99c332d7e3..af610cb00a987 100644 +--- a/tools/perf/util/symbol-elf.c ++++ b/tools/perf/util/symbol-elf.c +@@ -1375,8 +1375,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, + char dso_name[PATH_MAX]; + + /* Adjust symbol to map to file offset */ +- if (adjust_kernel_syms) +- sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ if (adjust_kernel_syms) { ++ if (dso__rel(dso)) ++ sym->st_value += shdr->sh_offset; ++ else ++ sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ } + + if (strcmp(section_name, (curr_dso->short_name + dso->short_name_len)) == 0) + return 0; +-- +2.53.0 + diff --git a/queue-6.6/perf-util-kill-die-prototype-dead-for-a-long-time.patch b/queue-6.6/perf-util-kill-die-prototype-dead-for-a-long-time.patch new file mode 100644 index 0000000000..8ea7f39df9 --- /dev/null +++ b/queue-6.6/perf-util-kill-die-prototype-dead-for-a-long-time.patch @@ -0,0 +1,39 @@ +From ebb3060717d338c6aa9f1d7bb98fc93b3487a190 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:31:57 -0300 +Subject: perf util: Kill die() prototype, dead for a long time + +From: Arnaldo Carvalho de Melo + +[ Upstream commit e5cce1b9c82fbd48e2f1f7a25a9fad8ee228176f ] + +In fef2a735167a827a ("perf tools: Kill die()") the die() function was +removed, but not the prototype in util.h, now when building with +LIBPERL=1, during a 'make -C tools/perf build-test' routine test, it is +failing as perl likes die() calls and then this clashes with this +remnant, remove it. + +Fixes: fef2a735167a827a ("perf tools: Kill die()") +Reviewed-by: Ian Rogers +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/util.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h +index 7c8915d92dca2..d49f66a986ae7 100644 +--- a/tools/perf/util/util.h ++++ b/tools/perf/util/util.h +@@ -25,7 +25,6 @@ extern bool perf_guest; + + /* General helper functions */ + void usage(const char *err) __noreturn; +-void die(const char *err, ...) __noreturn __printf(1, 2); + + struct dirent; + struct strlist; +-- +2.53.0 + diff --git a/queue-6.6/pinctrl-abx500-fix-type-of-argument-variable.patch b/queue-6.6/pinctrl-abx500-fix-type-of-argument-variable.patch new file mode 100644 index 0000000000..11e68bc8c3 --- /dev/null +++ b/queue-6.6/pinctrl-abx500-fix-type-of-argument-variable.patch @@ -0,0 +1,38 @@ +From 7f4d341bfb6a2d920c58e0a586d32b6c72c9be85 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 23:15:06 +0800 +Subject: pinctrl: abx500: Fix type of 'argument' variable + +From: Yu-Chun Lin + +[ Upstream commit 34006f77890d050e6d80cbee365b5d703c1140b4 ] + +The argument variable is assigned the return value of +pinconf_to_config_argument(), which returns a u32. Change its type from +enum pin_config_param to unsigned int to correctly store the configuration +argument. + +Fixes: 03b054e9696c ("pinctrl: Pass all configs to driver on pin_config_set()") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/nomadik/pinctrl-abx500.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c +index 0cfa74365733c..a4940199f2ad0 100644 +--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c ++++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c +@@ -853,7 +853,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, + int ret = -EINVAL; + int i; + enum pin_config_param param; +- enum pin_config_param argument; ++ unsigned int argument; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); +-- +2.53.0 + diff --git a/queue-6.6/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch b/queue-6.6/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch new file mode 100644 index 0000000000..49478b105b --- /dev/null +++ b/queue-6.6/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch @@ -0,0 +1,39 @@ +From 9b1993657d2af7aae43be73eba0ba6c90f6ce753 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 17:43:35 +0100 +Subject: pinctrl: cy8c95x0: Avoid returning positive values to user space + +From: Andy Shevchenko + +[ Upstream commit 5ad32c3607cf241a1a2680cabd64cbcd757227aa ] + +When probe fails due to unclear interrupt status register, it returns +a positive number instead of the proper error code. Fix this accordingly. + +Fixes: e6cbbe42944d ("pinctrl: Add Cypress cy8c95x0 support") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202602271847.vVWkqLBD-lkp@intel.com/ +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index 1432b6714dc69..727f3c5605ced 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1263,7 +1263,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); + if (ret) +- return dev_err_probe(dev, ret, "failed to clear irq status register\n"); ++ return dev_err_probe(dev, -EBUSY, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-6.6/pinctrl-cy8c95x0-remove-duplicate-error-message.patch b/queue-6.6/pinctrl-cy8c95x0-remove-duplicate-error-message.patch new file mode 100644 index 0000000000..37313d8aa0 --- /dev/null +++ b/queue-6.6/pinctrl-cy8c95x0-remove-duplicate-error-message.patch @@ -0,0 +1,73 @@ +From 47738a2612eed635ef4f139a73b40aa0f7968085 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:53 +0100 +Subject: pinctrl: cy8c95x0: remove duplicate error message + +From: Andy Shevchenko + +[ Upstream commit 970dacb3b9f0fedbbbcfd7dbf1f4f22340b3f359 ] + +The pin control core is covered to report any error via message. +The devm_request_threaded_irq() already prints an error message. +Remove the duplicates. + +While at it, drop the info message as the same information about +an IRQ in use can be retrieved differently. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 21 +++++---------------- + 1 file changed, 5 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index d2488d80912c9..97eeaae17f669 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1253,6 +1253,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + { + struct gpio_irq_chip *girq = &chip->gpio_chip.irq; + DECLARE_BITMAP(pending_irqs, MAX_LINE); ++ struct device *dev = chip->dev; + int ret; + + mutex_init(&chip->irq_lock); +@@ -1279,17 +1280,9 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + girq->handler = handle_simple_irq; + girq->threaded = true; + +- ret = devm_request_threaded_irq(chip->dev, irq, +- NULL, cy8c95x0_irq_handler, +- IRQF_ONESHOT | IRQF_SHARED, +- dev_name(chip->dev), chip); +- if (ret) { +- dev_err(chip->dev, "failed to request irq %d\n", irq); +- return ret; +- } +- dev_info(chip->dev, "Registered threaded IRQ\n"); +- +- return 0; ++ return devm_request_threaded_irq(dev, irq, NULL, cy8c95x0_irq_handler, ++ IRQF_ONESHOT | IRQF_SHARED, ++ dev_name(chip->dev), chip); + } + + static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) +@@ -1305,11 +1298,7 @@ static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) + pd->owner = THIS_MODULE; + + chip->pctldev = devm_pinctrl_register(chip->dev, pd, chip); +- if (IS_ERR(chip->pctldev)) +- return dev_err_probe(chip->dev, PTR_ERR(chip->pctldev), +- "can't register controller\n"); +- +- return 0; ++ return PTR_ERR_OR_ZERO(chip->pctldev); + } + + static int cy8c95x0_detect(struct i2c_client *client, +-- +2.53.0 + diff --git a/queue-6.6/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch b/queue-6.6/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch new file mode 100644 index 0000000000..250e0faf5c --- /dev/null +++ b/queue-6.6/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch @@ -0,0 +1,40 @@ +From 2e0a3f8f7debe2a3a40854b8881f59efa0902fe3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:54 +0100 +Subject: pinctrl: cy8c95x0: Unify messages with help of dev_err_probe() + +From: Andy Shevchenko + +[ Upstream commit 014884732095b982412d13d3220c3fe8483b9b3e ] + +Unify error messages that might appear during probe phase by +switching to use dev_err_probe(). + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index 97eeaae17f669..1432b6714dc69 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1262,10 +1262,8 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); +- if (ret) { +- dev_err(chip->dev, "failed to clear irq status register\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-6.6/pinctrl-pinctrl-pic32-fix-resource-leak.patch b/queue-6.6/pinctrl-pinctrl-pic32-fix-resource-leak.patch new file mode 100644 index 0000000000..4cf57b820f --- /dev/null +++ b/queue-6.6/pinctrl-pinctrl-pic32-fix-resource-leak.patch @@ -0,0 +1,72 @@ +From 2c2904d2afc459e9c3fc06b96831ef3837e307a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:56:23 -0600 +Subject: pinctrl: pinctrl-pic32: Fix resource leak + +From: Ethan Tidmore + +[ Upstream commit fe5560688f3ba98364c7de7b4f8dc240ffd1ff75 ] + +Fix three possible resource leaks by using the devres version of +clk_prepare_enable(). Also, update error message accordingly. + +Detected by Smatch: +drivers/pinctrl/pinctrl-pic32.c:2211 pic32_pinctrl_probe() warn: +'pctl->clk' from clk_prepare_enable() not released on lines: 2208. + +drivers/pinctrl/pinctrl-pic32.c:2274 pic32_gpio_probe() warn: +'bank->clk' from clk_prepare_enable() not released on lines: 2264,2272. + +Fixes: 2ba384e6c3810 ("pinctrl: pinctrl-pic32: Add PIC32 pin control driver") +Signed-off-by: Ethan Tidmore +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-pic32.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c +index bf827ab081a1d..f87b5964e8b31 100644 +--- a/drivers/pinctrl/pinctrl-pic32.c ++++ b/drivers/pinctrl/pinctrl-pic32.c +@@ -2173,16 +2173,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev) + if (IS_ERR(pctl->reg_base)) + return PTR_ERR(pctl->reg_base); + +- pctl->clk = devm_clk_get(&pdev->dev, NULL); ++ pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(pctl->clk)) { + ret = PTR_ERR(pctl->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(pctl->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +@@ -2238,16 +2232,10 @@ static int pic32_gpio_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- bank->clk = devm_clk_get(&pdev->dev, NULL); ++ bank->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bank->clk)) { + ret = PTR_ERR(bank->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(bank->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +-- +2.53.0 + diff --git a/queue-6.6/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch b/queue-6.6/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch new file mode 100644 index 0000000000..abc169ec28 --- /dev/null +++ b/queue-6.6/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch @@ -0,0 +1,49 @@ +From 7e03857bd19763b7e9f18c82efb01bb262be2af0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:47:03 +0100 +Subject: platform/chrome: chromeos_tbmc: Drop wakeup source on remove + +From: Rafael J. Wysocki + +[ Upstream commit 5d441a4bc93642ed6f41da87327a39946b4e1455 ] + +The wakeup source added by device_init_wakeup() in chromeos_tbmc_add() +needs to be dropped during driver removal, so add a .remove() callback +to the driver for this purpose. + +Fixes: 0144c00ed86b ("platform/chrome: chromeos_tbmc: Report wake events") +Signed-off-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/6151957.MhkbZ0Pkbq@rafael.j.wysocki +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/chromeos_tbmc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c +index d1cf8f3463ce3..e248567c0a182 100644 +--- a/drivers/platform/chrome/chromeos_tbmc.c ++++ b/drivers/platform/chrome/chromeos_tbmc.c +@@ -95,6 +95,11 @@ static int chromeos_tbmc_add(struct acpi_device *adev) + return 0; + } + ++static void chromeos_tbmc_remove(struct acpi_device *adev) ++{ ++ device_init_wakeup(&adev->dev, false); ++} ++ + static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = { + { ACPI_DRV_NAME, 0 }, + { } +@@ -110,6 +115,7 @@ static struct acpi_driver chromeos_tbmc_driver = { + .ids = chromeos_tbmc_acpi_device_ids, + .ops = { + .add = chromeos_tbmc_add, ++ .remove = chromeos_tbmc_remove, + .notify = chromeos_tbmc_notify, + }, + .drv.pm = &chromeos_tbmc_pm_ops, +-- +2.53.0 + diff --git a/queue-6.6/platform-surface-surfacepro3_button-drop-wakeup-sour.patch b/queue-6.6/platform-surface-surfacepro3_button-drop-wakeup-sour.patch new file mode 100644 index 0000000000..b60499877a --- /dev/null +++ b/queue-6.6/platform-surface-surfacepro3_button-drop-wakeup-sour.patch @@ -0,0 +1,41 @@ +From b01dfa7f335f7dcc941df55314857ce55ad510ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:54:08 +0100 +Subject: platform/surface: surfacepro3_button: Drop wakeup source on remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 1410a228ab2d36fe2b383415a632ae12048d4f3a ] + +The wakeup source added by device_init_wakeup() in surface_button_add() +needs to be dropped during driver removal, so update the driver to do +that. + +Fixes: 19351f340765 ("platform/x86: surfacepro3: Support for wakeup from suspend-to-idle") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/4368848.1IzOArtZ34@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/surface/surfacepro3_button.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f979cd..7c7622f8f8716 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -243,6 +243,7 @@ static void surface_button_remove(struct acpi_device *device) + { + struct surface_button *button = acpi_driver_data(device); + ++ device_init_wakeup(&device->dev, false); + input_unregister_device(button->input); + kfree(button); + } +-- +2.53.0 + diff --git a/queue-6.6/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch b/queue-6.6/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch new file mode 100644 index 0000000000..c6629f9601 --- /dev/null +++ b/queue-6.6/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch @@ -0,0 +1,99 @@ +From 76e8efdfbebf32545f58f17922fb69b84cb63736 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:38:21 +0800 +Subject: platform/x86: dell-wmi-sysman: bound enumeration string aggregation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pengpeng Hou + +[ Upstream commit 3c34471c26abc52a37f5ad90949e2e4b8027eb14 ] + +populate_enum_data() aggregates firmware-provided value-modifier +and possible-value strings into fixed 512-byte struct members. +The current code bounds each individual source string but then +appends every string and separator with raw strcat() and no +remaining-space check. + +Switch the aggregation loops to a bounded append helper and +reject enumeration packages whose combined strings do not fit +in the destination buffers. + +Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems") +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260408084501.1-dell-wmi-sysman-v2-pengpeng@iscas.ac.cn +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + .../dell/dell-wmi-sysman/enum-attributes.c | 34 +++++++++++++++---- + 1 file changed, 28 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +index fc2f58b4cbc6e..7e44ba3015627 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +@@ -6,10 +6,32 @@ + * Copyright (c) 2020 Dell Inc. + */ + ++#include ++ + #include "dell-wmi-sysman.h" + + get_instance_id(enumeration); + ++static int append_enum_string(char *dest, const char *src) ++{ ++ size_t dest_len = strlen(dest); ++ ssize_t copied; ++ ++ if (WARN_ON_ONCE(dest_len >= MAX_BUFF)) ++ return -EINVAL; ++ ++ copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ dest_len += copied; ++ copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { + int instance_id = get_enumeration_instance_id(kobj); +@@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + if (next_obj >= enum_property_count) +@@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); +-- +2.53.0 + diff --git a/queue-6.6/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch b/queue-6.6/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch new file mode 100644 index 0000000000..1a6be5f278 --- /dev/null +++ b/queue-6.6/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch @@ -0,0 +1,60 @@ +From e0ee416e04f0fbfb85af2ea2d3c257a2dc668bcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:42:39 +0300 +Subject: platform/x86: dell_rbu: avoid uninit value usage in + packet_size_write() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fedor Pchelkin + +[ Upstream commit f8fd138c2363c0e2d3235c32bfb4fb5c6474e4ae ] + +Ensure the temp value has been properly parsed from the user-provided +buffer and initialized to be used in later operations. While at it, +prefer a convenient kstrtoul() helper. + +Found by Linux Verification Center (linuxtesting.org) with Svace static +analysis tool. + +Fixes: ad6ce87e5bd4 ("[PATCH] dell_rbu: changes in packet update mechanism") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260403134240.604837-1-pchelkin@ispras.ru +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/dell/dell_rbu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c +index fee20866b41e4..9039e494131fd 100644 +--- a/drivers/platform/x86/dell/dell_rbu.c ++++ b/drivers/platform/x86/dell/dell_rbu.c +@@ -30,6 +30,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -617,9 +618,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, + char *buffer, loff_t pos, size_t count) + { + unsigned long temp; ++ ++ if (kstrtoul(buffer, 10, &temp)) ++ return -EINVAL; ++ + spin_lock(&rbu_data.lock); + packet_empty_list(); +- sscanf(buffer, "%lu", &temp); + if (temp < 0xffffffff) + rbu_data.packetsize = temp; + +-- +2.53.0 + diff --git a/queue-6.6/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch b/queue-6.6/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch new file mode 100644 index 0000000000..5b9f490e70 --- /dev/null +++ b/queue-6.6/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch @@ -0,0 +1,67 @@ +From 737b931cdd7add1d6bba86ec34e0c7727fbcf11d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 11:31:54 +0100 +Subject: platform/x86: panasonic-laptop: Fix OPTD notifier registration and + cleanup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 8baeff2c1d33dad8572216c6ad3a7425852507d4 ] + +An ACPI notify handler is leaked if device_create_file() returns an +error in acpi_pcc_hotkey_add(). + +Also, it is pointless to call pcc_unregister_optd_notifier() in +acpi_pcc_hotkey_remove() if pcc->platform is NULL and it is better +to arrange the cleanup code in that function in the same order as +the rollback code in acpi_pcc_hotkey_add(). + +Address the above by placing the pcc_register_optd_notifier() call in +acpi_pcc_hotkey_add() after the device_create_file() return value +check and placing the pcc_unregister_optd_notifier() call in +acpi_pcc_hotkey_remove() right before the device_remove_file() call. + +Fixes: d5a81d8e864b ("platform/x86: panasonic-laptop: Add support for optical driver power in Y and W series") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2411055.ElGaqSPkdT@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/panasonic-laptop.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c +index ad907c558997a..f6dcf8d6a1dbb 100644 +--- a/drivers/platform/x86/panasonic-laptop.c ++++ b/drivers/platform/x86/panasonic-laptop.c +@@ -1081,9 +1081,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) + } + result = device_create_file(&pcc->platform->dev, + &dev_attr_cdpower); +- pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + if (result) + goto out_platform; ++ ++ pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + } else { + pcc->platform = NULL; + } +@@ -1117,10 +1118,10 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device) + i8042_remove_filter(panasonic_i8042_filter); + + if (pcc->platform) { ++ pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); + platform_device_unregister(pcc->platform); + } +- pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + + sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); + +-- +2.53.0 + diff --git a/queue-6.6/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch b/queue-6.6/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch new file mode 100644 index 0000000000..aaee45d6b3 --- /dev/null +++ b/queue-6.6/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch @@ -0,0 +1,38 @@ +From 56f73a972f98fb0619c5f35ba3975fab5ce7d49c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 22:17:17 +0800 +Subject: pmdomain: imx: scu-pd: Fix device_node reference leak during + ->probe() + +From: Felix Gu + +[ Upstream commit c8e9b6a55702be6c6d034e973d519c52c3848415 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In imx_sc_pd_get_console_rsrc(), it does not release the reference. + +Fixes: 893cfb99734f ("firmware: imx: scu-pd: do not power off console domain") +Signed-off-by: Felix Gu +Reviewed-by: Peng Fan +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/pmdomain/imx/scu-pd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pmdomain/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c +index 368918e562f55..606d6bdccf94a 100644 +--- a/drivers/pmdomain/imx/scu-pd.c ++++ b/drivers/pmdomain/imx/scu-pd.c +@@ -326,6 +326,7 @@ static void imx_sc_pd_get_console_rsrc(void) + return; + + imx_con_rsrc = specs.args[0]; ++ of_node_put(specs.np); + } + + static int imx_sc_get_pd_power(struct device *dev, u32 rsrc) +-- +2.53.0 + diff --git a/queue-6.6/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch b/queue-6.6/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch new file mode 100644 index 0000000000..f152971e2d --- /dev/null +++ b/queue-6.6/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch @@ -0,0 +1,36 @@ +From c5c78283b7f5ccd4772abe8b5847d8973e467cf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 20:27:47 +0800 +Subject: pmdomain: ti: omap_prm: Fix a reference leak on device node + +From: Felix Gu + +[ Upstream commit 44c28e1c52764fef6dd1c1ada3a248728812e67f ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In omap_prm_domain_attach_dev, it does not release the reference. + +Fixes: 58cbff023bfa ("soc: ti: omap-prm: Add basic power domain support") +Signed-off-by: Felix Gu +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/pmdomain/ti/omap_prm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pmdomain/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c +index b8ceb3c2b81c2..f4e52e92dcbf6 100644 +--- a/drivers/pmdomain/ti/omap_prm.c ++++ b/drivers/pmdomain/ti/omap_prm.c +@@ -651,6 +651,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, + if (pd_args.args_count != 0) + dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", + prmd->pd.name, pd_args.args_count); ++ of_node_put(pd_args.np); + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; +-- +2.53.0 + diff --git a/queue-6.6/powerpc-crash-fix-backup-region-offset-update-to-elf.patch b/queue-6.6/powerpc-crash-fix-backup-region-offset-update-to-elf.patch new file mode 100644 index 0000000000..ab36495728 --- /dev/null +++ b/queue-6.6/powerpc-crash-fix-backup-region-offset-update-to-elf.patch @@ -0,0 +1,63 @@ +From 2d3725ea096c647979970b87c631284dfa5250fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:49 +0530 +Subject: powerpc/crash: fix backup region offset update to elfcorehdr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sourabh Jain + +[ Upstream commit 789335cacdf37da93bb7c70322dff8c7e82881df ] + +update_backup_region_phdr() in file_load_64.c iterates over all the +program headers in the kdump kernel’s elfcorehdr and updates the +p_offset of the program header whose physical address starts at 0. + +However, the loop logic is incorrect because the program header pointer +is not updated during iteration. Since elfcorehdr typically contains +PT_NOTE entries first, the PT_LOAD program header with physical address +0 is never reached. As a result, its p_offset is not updated to point to +the backup region. + +Because of this behavior, the capture kernel exports the first 64 KB of +the crashed kernel’s memory at offset 0, even though that memory +actually lives in the backup region. When a crash happens, purgatory +copies the first 64 KB of the crashed kernel’s memory into the backup +region so the capture kernel can safely use it. + +This has not caused problems so far because the first 64 KB is usually +identical in both the crashed and capture kernels. However, this is +just an assumption and is not guaranteed to always hold true. + +Fix update_backup_region_phdr() to correctly update the p_offset of the +program header with a starting physical address of 0 by correcting the +logic used to iterate over the program headers. + +Fixes: cb350c1f1f86 ("powerpc/kexec_file: Prepare elfcore header for crashing kernel") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Reviewed-by: Hari Bathini +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-2-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kexec/file_load_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index 7b71737ae24cc..12cbfc9fce451 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -773,7 +773,7 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) + unsigned int i; + + phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++) { ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + if (phdr->p_paddr == BACKUP_SRC_START) { + phdr->p_offset = image->arch.backup_start; + pr_debug("Backup region offset updated to 0x%lx\n", +-- +2.53.0 + diff --git a/queue-6.6/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch b/queue-6.6/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch new file mode 100644 index 0000000000..56672b705a --- /dev/null +++ b/queue-6.6/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch @@ -0,0 +1,50 @@ +From 6031cf62f30ea9c5af92b3d5a684663632d0178d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:11:15 +0900 +Subject: ppp: require CAP_NET_ADMIN in target netns for unattached ioctls + +From: Taegu Ha + +[ Upstream commit 2bb6379416fd19f44c3423a00bfd8626259f6067 ] + +/dev/ppp open is currently authorized against file->f_cred->user_ns, +while unattached administrative ioctls operate on current->nsproxy->net_ns. + +As a result, a local unprivileged user can create a new user namespace +with CLONE_NEWUSER, gain CAP_NET_ADMIN only in that new user namespace, +and still issue PPPIOCNEWUNIT, PPPIOCATTACH, or PPPIOCATTCHAN against +an inherited network namespace. + +Require CAP_NET_ADMIN in the user namespace that owns the target network +namespace before handling unattached PPP administrative ioctls. + +This preserves normal pppd operation in the network namespace it is +actually privileged in, while rejecting the userns-only inherited-netns +case. + +Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2") +Signed-off-by: Taegu Ha +Link: https://patch.msgid.link/20260409071117.4354-1-hataegu0826@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 46ac51217114b..7c863cb99383b 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1062,6 +1062,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct ppp_net *pn; + int __user *p = (int __user *)arg; + ++ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ + switch (cmd) { + case PPPIOCNEWUNIT: + /* Create a new ppp unit */ +-- +2.53.0 + diff --git a/queue-6.6/pppoe-drop-pfc-frames.patch b/queue-6.6/pppoe-drop-pfc-frames.patch new file mode 100644 index 0000000000..f782485cc8 --- /dev/null +++ b/queue-6.6/pppoe-drop-pfc-frames.patch @@ -0,0 +1,112 @@ +From 96e592c635a84139a4fd1f81da471ab8964c3d6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 10:24:51 +0800 +Subject: pppoe: drop PFC frames + +From: Qingfang Deng + +[ Upstream commit cc1ff87bce1ccd38410ab10960f576dcd17db679 ] + +RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT +RECOMMENDED for PPPoE. In practice, pppd does not support negotiating +PFC for PPPoE sessions, and the current PPPoE driver assumes an +uncompressed (2-byte) protocol field. However, the generic PPP layer +function ppp_input() is not aware of the negotiation result, and still +accepts PFC frames. + +If a peer with a broken implementation or an attacker sends a frame with +a compressed (1-byte) protocol field, the subsequent PPP payload is +shifted by one byte. This causes the network header to be 4-byte +misaligned, which may trigger unaligned access exceptions on some +architectures. + +To reduce the attack surface, drop PPPoE PFC frames. Introduce +ppp_skb_is_compressed_proto() helper function to be used in both +ppp_generic.c and pppoe.c to avoid open-coding. + +Fixes: 7fb1b8ca8fa1 ("ppp: Move PFC decompression to PPP generic layer") +Signed-off-by: Qingfang Deng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415022456.141758-2-qingfang.deng@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + drivers/net/ppp/pppoe.c | 8 +++++++- + include/linux/ppp_defs.h | 16 ++++++++++++++++ + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 7c863cb99383b..2b5843d14cbb8 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2245,7 +2245,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + */ + static void __ppp_decompress_proto(struct sk_buff *skb) + { +- if (skb->data[0] & 0x01) ++ if (ppp_skb_is_compressed_proto(skb)) + *(u8 *)skb_push(skb, 1) = 0x00; + } + +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index 96cca4ee470a4..bc726b54ca745 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -425,7 +425,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb_mac_header_len(skb) < ETH_HLEN) + goto drop; + +- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) ++ if (!pskb_may_pull(skb, PPPOE_SES_HLEN)) + goto drop; + + ph = pppoe_hdr(skb); +@@ -435,6 +435,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb->len < len) + goto drop; + ++ /* skb->data points to the PPP protocol header after skb_pull_rcsum. ++ * Drop PFC frames. ++ */ ++ if (ppp_skb_is_compressed_proto(skb)) ++ goto drop; ++ + if (pskb_trim_rcsum(skb, len)) + goto drop; + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index b7e57fdbd4139..b1d1f46d7d3be 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -8,6 +8,7 @@ + #define _PPP_DEFS_H_ + + #include ++#include + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) +@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) + return !!((proto & 0x0101) == 0x0001); + } + ++/** ++ * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed ++ * @skb: skb to check ++ * ++ * Check if the PPP protocol field is compressed (the least significant ++ * bit of the most significant octet is 1). skb->data must point to the PPP ++ * protocol header. ++ * ++ * Return: Whether the PPP protocol field is compressed. ++ */ ++static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb) ++{ ++ return unlikely(skb->data[0] & 0x01); ++} ++ + #endif /* _PPP_DEFS_H_ */ +-- +2.53.0 + diff --git a/queue-6.6/pstore-ram-fix-resource-leak-when-ioremap-fails.patch b/queue-6.6/pstore-ram-fix-resource-leak-when-ioremap-fails.patch new file mode 100644 index 0000000000..dab864953a --- /dev/null +++ b/queue-6.6/pstore-ram-fix-resource-leak-when-ioremap-fails.patch @@ -0,0 +1,52 @@ +From 0c92f38ded2a7f640c52d4c28e6805cd0ea458fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:54:06 -0700 +Subject: pstore/ram: fix resource leak when ioremap() fails + +From: Cole Leavitt + +[ Upstream commit 2ddb69f686ef7a621645e97fc7329c50edf5d0e5 ] + +In persistent_ram_iomap(), ioremap() or ioremap_wc() may return NULL on +failure. Currently, if this happens, the function returns NULL without +releasing the memory region acquired by request_mem_region(). + +This leads to a resource leak where the memory region remains reserved +but unusable. + +Additionally, the caller persistent_ram_buffer_map() handles NULL +correctly by returning -ENOMEM, but without this check, a NULL return +combined with request_mem_region() succeeding leaves resources in an +inconsistent state. + +This is the ioremap() counterpart to commit 05363abc7625 ("pstore: +ram_core: fix incorrect success return when vmap() fails") which fixed +a similar issue in the vmap() path. + +Fixes: 404a6043385d ("staging: android: persistent_ram: handle reserving and mapping memory") +Signed-off-by: Cole Leavitt +Link: https://patch.msgid.link/20260225235406.11790-1-cole@unwrap.rs +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index 7b6d6378a3b87..95675d4bab141 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -489,6 +489,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, + else + va = ioremap_wc(start, size); + ++ /* We must release the mem region if ioremap fails. */ ++ if (!va) ++ release_mem_region(start, size); ++ + /* + * Since request_mem_region() and ioremap() are byte-granularity + * there is no need handle anything special like we do when the +-- +2.53.0 + diff --git a/queue-6.6/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch b/queue-6.6/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch new file mode 100644 index 0000000000..470a2d4b8c --- /dev/null +++ b/queue-6.6/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch @@ -0,0 +1,148 @@ +From 91cdb5a92b7a5357aacb524c16f439a282c8e58e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 14:22:16 +0100 +Subject: quota: Fix race of dquot_scan_active() with quota deactivation + +From: Jan Kara + +[ Upstream commit e93ab401da4b2e2c1b8ef2424de2f238d51c8b2d ] + +dquot_scan_active() can race with quota deactivation in +quota_release_workfn() like: + + CPU0 (quota_release_workfn) CPU1 (dquot_scan_active) + ============================== ============================== + spin_lock(&dq_list_lock); + list_replace_init( + &releasing_dquots, &rls_head); + /* dquot X on rls_head, + dq_count == 0, + DQ_ACTIVE_B still set */ + spin_unlock(&dq_list_lock); + synchronize_srcu(&dquot_srcu); + spin_lock(&dq_list_lock); + list_for_each_entry(dquot, + &inuse_list, dq_inuse) { + /* finds dquot X */ + dquot_active(X) -> true + atomic_inc(&X->dq_count); + } + spin_unlock(&dq_list_lock); + spin_lock(&dq_list_lock); + dquot = list_first_entry(&rls_head); + WARN_ON_ONCE(atomic_read(&dquot->dq_count)); + +The problem is not only a cosmetic one as under memory pressure the +caller of dquot_scan_active() can end up working on freed dquot. + +Fix the problem by making sure the dquot is removed from releasing list +when we acquire a reference to it. + +Fixes: 869b6ea1609f ("quota: Fix slow quotaoff") +Reported-by: Sam Sun +Link: https://lore.kernel.org/all/CAEkJfYPTt3uP1vAYnQ5V2ZWn5O9PLhhGi5HbOcAzyP9vbXyjeg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/dquot.c | 38 ++++++++++++++++++++++++++++++-------- + include/linux/quotaops.h | 9 +-------- + 2 files changed, 31 insertions(+), 16 deletions(-) + +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 42a7d0a71b22e..7562ee4ff2929 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -364,6 +364,31 @@ static inline int dquot_active(struct dquot *dquot) + return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); + } + ++static struct dquot *__dqgrab(struct dquot *dquot) ++{ ++ lockdep_assert_held(&dq_list_lock); ++ if (!atomic_read(&dquot->dq_count)) ++ remove_free_dquot(dquot); ++ atomic_inc(&dquot->dq_count); ++ return dquot; ++} ++ ++/* ++ * Get reference to dquot when we got pointer to it by some other means. The ++ * dquot has to be active and the caller has to make sure it cannot get ++ * deactivated under our hands. ++ */ ++struct dquot *dqgrab(struct dquot *dquot) ++{ ++ spin_lock(&dq_list_lock); ++ WARN_ON_ONCE(!dquot_active(dquot)); ++ dquot = __dqgrab(dquot); ++ spin_unlock(&dq_list_lock); ++ ++ return dquot; ++} ++EXPORT_SYMBOL_GPL(dqgrab); ++ + static inline int dquot_dirty(struct dquot *dquot) + { + return test_bit(DQ_MOD_B, &dquot->dq_flags); +@@ -642,15 +667,14 @@ int dquot_scan_active(struct super_block *sb, + continue; + if (dquot->dq_sb != sb) + continue; +- /* Now we have active dquot so we can just increase use count */ +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqput(old_dquot); + old_dquot = dquot; + /* + * ->release_dquot() can be racing with us. Our reference +- * protects us from new calls to it so just wait for any +- * outstanding call and recheck the DQ_ACTIVE_B after that. ++ * protects us from dquot_release() proceeding so just wait for ++ * any outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (dquot_active(dquot)) { +@@ -718,7 +742,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) + /* Now we have active dquot from which someone is + * holding reference so we can safely just increase + * use count */ +- dqgrab(dquot); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + err = dquot_write_dquot(dquot); + if (err && !ret) +@@ -973,9 +997,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_LOOKUPS); + } else { +- if (!atomic_read(&dquot->dq_count)) +- remove_free_dquot(dquot); +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_CACHE_HITS); + dqstats_inc(DQST_LOOKUPS); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 4fa4ef0a173a3..a9be09f96b10e 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -44,14 +44,7 @@ int dquot_initialize(struct inode *inode); + bool dquot_initialize_needed(struct inode *inode); + void dquot_drop(struct inode *inode); + struct dquot *dqget(struct super_block *sb, struct kqid qid); +-static inline struct dquot *dqgrab(struct dquot *dquot) +-{ +- /* Make sure someone else has active reference to dquot */ +- WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); +- WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); +- atomic_inc(&dquot->dq_count); +- return dquot; +-} ++struct dquot *dqgrab(struct dquot *dquot); + + static inline bool dquot_is_busy(struct dquot *dquot) + { +-- +2.53.0 + diff --git a/queue-6.6/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch b/queue-6.6/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch new file mode 100644 index 0000000000..53f9eb24e0 --- /dev/null +++ b/queue-6.6/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch @@ -0,0 +1,41 @@ +From 63b75d8eb3ee003d8b3a09d12f3cc70feaf5761f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:39:23 +0800 +Subject: r8152: fix incorrect register write to USB_UPHY_XTAL + +From: Chih Kai Hsu + +[ Upstream commit 48afd5124fd6129c46fd12cb06155384b1c4a0c4 ] + +The old code used ocp_write_byte() to clear the OOBS_POLLING bit +(BIT(8)) in the USB_UPHY_XTAL register, but this doesn't correctly +clear a bit in the upper byte of the 16-bit register. + +Fix this by using ocp_write_word() instead. + +Fixes: 195aae321c82 ("r8152: support new chips") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Link: https://patch.msgid.link/20260326073925.32976-454-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 91cf24fb5531f..d39d66e25b01b 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -3859,7 +3859,7 @@ static void r8156_ups_en(struct r8152 *tp, bool enable) + case RTL_VER_15: + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL); + ocp_data &= ~OOBS_POLLING; +- ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); ++ ocp_write_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); + break; + default: + break; +-- +2.53.0 + diff --git a/queue-6.6/rdma-core-prefer-nla_nul_string.patch b/queue-6.6/rdma-core-prefer-nla_nul_string.patch new file mode 100644 index 0000000000..32c0d68dca --- /dev/null +++ b/queue-6.6/rdma-core-prefer-nla_nul_string.patch @@ -0,0 +1,56 @@ +From 16aefb6c5d11c8fd871c6f3ff76442b0d5a0bcc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:27:39 +0200 +Subject: RDMA/core: Prefer NLA_NUL_STRING + +From: Florian Westphal + +[ Upstream commit 6ed3d14fc45d3da6025e7fe4a6a09066856698e2 ] + +These attributes are evaluated as c-string (passed to strcmp), but +NLA_STRING doesn't check for the presence of a \0 terminator. + +Either this needs to switch to nla_strcmp() and needs to adjust printf fmt +specifier to not use plain %s, or this needs to use NLA_NUL_STRING. + +As the code has been this way for long time, it seems to me that userspace +does include the terminating nul, even tough its not enforced so far, and +thus NLA_NUL_STRING use is the simpler solution. + +Fixes: 30dc5e63d6a5 ("RDMA/core: Add support for iWARP Port Mapper user space service") +Link: https://patch.msgid.link/r/20260330122742.13315-1-fw@strlen.de +Signed-off-by: Florian Westphal +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwpm_msg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c +index 3c9a9869212bb..feb09008eb9ca 100644 +--- a/drivers/infiniband/core/iwpm_msg.c ++++ b/drivers/infiniband/core/iwpm_msg.c +@@ -365,9 +365,9 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) + /* netlink attribute policy for the received response to register pid request */ + static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { + [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, +- [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_DEVNAME_SIZE - 1 }, +- [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, + [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } +@@ -677,7 +677,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) + + /* netlink attribute policy for the received request for mapping info */ + static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { +- [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } + }; +-- +2.53.0 + diff --git a/queue-6.6/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch b/queue-6.6/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch new file mode 100644 index 0000000000..06ade284ba --- /dev/null +++ b/queue-6.6/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch @@ -0,0 +1,51 @@ +From ceeaa4ce86d0722955702408bb8576a6b0e700e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 18:00:10 +0000 +Subject: rtc: abx80x: Disable alarm feature if no interrupt attached + +From: Anthony Pighin (Nokia) + +[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ] + +Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting +alarm") exposed an issue where the rtc-abx80x driver does not clear the +alarm feature bit, but instead relies on the set_alarm operation to return +invalid. + +For example, when a RTC_UIE_ON ioctl is handled, it should abort at the +feature validation. Instead, it proceeds to the rtc_timer_enqueue(), +which used to return an error from the set_alarm call. However, +following the race condition handling, which likely should not be +discarding predecing errors, a success condition is returned to the +ioctl() caller. This results in (for example): + hwclock: select() to /dev/rtc0 to wait for clock tick timed out + +Notwithstanding the validity of the race condition handling, if an interrupt +wasn't specified, or could not be attached, the driver should clear the +alarm feature bit. + +Fixes: 718a820a303c ("rtc: abx80x: add alarm support") +Signed-off-by: Anthony Pighin +Link: https://patch.msgid.link/BN0PR08MB69510928028C933749F4139383D1A@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-abx80x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c +index 3fee27914ba80..5f3a3e60a19d0 100644 +--- a/drivers/rtc/rtc-abx80x.c ++++ b/drivers/rtc/rtc-abx80x.c +@@ -933,6 +933,8 @@ static int abx80x_probe(struct i2c_client *client) + client->irq = 0; + } + } ++ if (client->irq <= 0) ++ clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); + + err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); + if (err) { +-- +2.53.0 + diff --git a/queue-6.6/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch b/queue-6.6/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch new file mode 100644 index 0000000000..e9620a0969 --- /dev/null +++ b/queue-6.6/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch @@ -0,0 +1,103 @@ +From f57906f879766151e82933eefc1503402bb59aa9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 18:46:25 +0100 +Subject: s390/bpf: Zero-extend bpf prog return values and kfunc arguments + +From: Ilya Leoshkevich + +[ Upstream commit 202e42e4aa890172366354b233c42c73107a3f59 ] + +s390x ABI requires callers to zero-extend unsigned arguments and +sign-extend signed arguments, and callees to zero-extend unsigned +return values and sign-extend signed return values. + +s390 BPF JIT currently implements only sign extension. Fix this +omission and implement zero extension too. + +Fixes: 528eb2cb87bc ("s390/bpf: Implement arch_prepare_bpf_trampoline()") +Reported-by: Hari Bathini +Closes: https://lore.kernel.org/bpf/20260312080113.843408-1-hbathini@linux.ibm.com/ +Signed-off-by: Ilya Leoshkevich +Tested-by: Ihor Solodrai +Link: https://lore.kernel.org/r/20260313174807.581826-1-iii@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/s390/net/bpf_jit_comp.c | 39 ++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 15 deletions(-) + +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index 5a64d34a37482..491789420d7c0 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -759,25 +759,34 @@ static int bpf_jit_probe_mem(struct bpf_jit *jit, struct bpf_prog *fp, + } + + /* +- * Sign-extend the register if necessary ++ * Sign- or zero-extend the register if necessary + */ +-static int sign_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) ++static int sign_zero_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) + { +- if (!(flags & BTF_FMODEL_SIGNED_ARG)) +- return 0; +- + switch (size) { + case 1: +- /* lgbr %r,%r */ +- EMIT4(0xb9060000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lgbr %r,%r */ ++ EMIT4(0xb9060000, r, r); ++ else ++ /* llgcr %r,%r */ ++ EMIT4(0xb9840000, r, r); + return 0; + case 2: +- /* lghr %r,%r */ +- EMIT4(0xb9070000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lghr %r,%r */ ++ EMIT4(0xb9070000, r, r); ++ else ++ /* llghr %r,%r */ ++ EMIT4(0xb9850000, r, r); + return 0; + case 4: +- /* lgfr %r,%r */ +- EMIT4(0xb9140000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lgfr %r,%r */ ++ EMIT4(0xb9140000, r, r); ++ else ++ /* llgfr %r,%r */ ++ EMIT4(0xb9160000, r, r); + return 0; + case 8: + return 0; +@@ -1452,9 +1461,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + return -1; + + for (j = 0; j < m->nr_args; j++) { +- if (sign_extend(jit, BPF_REG_1 + j, +- m->arg_size[j], +- m->arg_flags[j])) ++ if (sign_zero_extend(jit, BPF_REG_1 + j, ++ m->arg_size[j], ++ m->arg_flags[j])) + return -1; + } + } +@@ -2186,7 +2195,7 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit, + call_r1(jit); + /* stg %r2,retval_off(%r15) */ + if (save_ret) { +- if (sign_extend(jit, REG_2, m->ret_size, m->ret_flags)) ++ if (sign_zero_extend(jit, REG_2, m->ret_size, m->ret_flags)) + return -1; + EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15, + tjit->retval_off); +-- +2.53.0 + diff --git a/queue-6.6/s390-cio-convert-sprintf-snprintf-to-sysfs_emit.patch b/queue-6.6/s390-cio-convert-sprintf-snprintf-to-sysfs_emit.patch new file mode 100644 index 0000000000..e008d758a0 --- /dev/null +++ b/queue-6.6/s390-cio-convert-sprintf-snprintf-to-sysfs_emit.patch @@ -0,0 +1,96 @@ +From ac2e52c08b41067a50c7b97095cbbbcc1dc81d1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Mar 2024 17:52:09 +0800 +Subject: s390/cio: convert sprintf()/snprintf() to sysfs_emit() + +From: Li Zhijian + +[ Upstream commit aaebea959efb2cccd870990f1b6016ff324b0fb6 ] + +Per filesystems/sysfs.rst, show() should only use sysfs_emit() +or sysfs_emit_at() when formatting the value to be returned to user space. + +coccinelle complains that there are still a couple of functions that use +snprintf(). Convert them to sysfs_emit(). + +Generally, this patch is generated by +make coccicheck M= MODE=patch \ +COCCI=scripts/coccinelle/api/device_attr_show.cocci + +No functional change intended. + +Cc: Vineeth Vijayan +Cc: Peter Oberparleiter +Signed-off-by: Li Zhijian +Link: https://lore.kernel.org/r/20240314095209.1325229-1-lizhijian@fujitsu.com +Signed-off-by: Heiko Carstens +Signed-off-by: Alexander Gordeev +Stable-dep-of: ac4d8bb6e2e1 ("s390/cio: use generic driver_override infrastructure") +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/css.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 4e63e6d45e6e1..36c46c7f2fb80 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -309,7 +309,7 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr, + { + struct subchannel *sch = to_subchannel(dev); + +- return sprintf(buf, "%01x\n", sch->st); ++ return sysfs_emit(buf, "%01x\n", sch->st); + } + + static DEVICE_ATTR_RO(type); +@@ -319,7 +319,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + { + struct subchannel *sch = to_subchannel(dev); + +- return sprintf(buf, "css:t%01X\n", sch->st); ++ return sysfs_emit(buf, "css:t%01X\n", sch->st); + } + + static DEVICE_ATTR_RO(modalias); +@@ -345,7 +345,7 @@ static ssize_t driver_override_show(struct device *dev, + ssize_t len; + + device_lock(dev); +- len = snprintf(buf, PAGE_SIZE, "%s\n", sch->driver_override); ++ len = sysfs_emit(buf, "%s\n", sch->driver_override); + device_unlock(dev); + return len; + } +@@ -396,8 +396,8 @@ static ssize_t pimpampom_show(struct device *dev, + struct subchannel *sch = to_subchannel(dev); + struct pmcw *pmcw = &sch->schib.pmcw; + +- return sprintf(buf, "%02x %02x %02x\n", +- pmcw->pim, pmcw->pam, pmcw->pom); ++ return sysfs_emit(buf, "%02x %02x %02x\n", ++ pmcw->pim, pmcw->pam, pmcw->pom); + } + static DEVICE_ATTR_RO(pimpampom); + +@@ -881,7 +881,7 @@ static ssize_t real_cssid_show(struct device *dev, struct device_attribute *a, + if (!css->id_valid) + return -EINVAL; + +- return sprintf(buf, "%x\n", css->cssid); ++ return sysfs_emit(buf, "%x\n", css->cssid); + } + static DEVICE_ATTR_RO(real_cssid); + +@@ -904,7 +904,7 @@ static ssize_t cm_enable_show(struct device *dev, struct device_attribute *a, + int ret; + + mutex_lock(&css->mutex); +- ret = sprintf(buf, "%x\n", css->cm_enabled); ++ ret = sysfs_emit(buf, "%x\n", css->cm_enabled); + mutex_unlock(&css->mutex); + return ret; + } +-- +2.53.0 + diff --git a/queue-6.6/s390-cio-make-sch-lock-spinlock-pointer-a-member.patch b/queue-6.6/s390-cio-make-sch-lock-spinlock-pointer-a-member.patch new file mode 100644 index 0000000000..7aa63a8303 --- /dev/null +++ b/queue-6.6/s390-cio-make-sch-lock-spinlock-pointer-a-member.patch @@ -0,0 +1,821 @@ +From cbfd4d5c42cb087394c8e0cf190d724e9f5e2390 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Nov 2023 12:57:51 +0100 +Subject: s390/cio: make sch->lock spinlock pointer a member + +From: Halil Pasic + +[ Upstream commit b8fa3e90965eeb2f83aa637ba0d0d6fd2a524004 ] + +The lock member of struct subchannel used to be a spinlock, but became +a pointer to a spinlock with commit 2ec2298412e1 ("[S390] subchannel +lock conversion."). This might have been justified back then, but with +the current state of affairs, there is no reason to manage a separate +spinlock object. + +Let's simplify things and pull the spinlock back into struct subchannel. + +Signed-off-by: Halil Pasic +Reviewed-by: Vineeth Vijayan +Link: https://lore.kernel.org/r/20231101115751.2308307-1-pasic@linux.ibm.com +Signed-off-by: Vasily Gorbik +Signed-off-by: Alexander Gordeev +Stable-dep-of: ac4d8bb6e2e1 ("s390/cio: use generic driver_override infrastructure") +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/chsc.c | 18 ++++----- + drivers/s390/cio/chsc_sch.c | 6 +-- + drivers/s390/cio/cio.c | 6 +-- + drivers/s390/cio/cio.h | 2 +- + drivers/s390/cio/css.c | 36 +++++------------- + drivers/s390/cio/device.c | 66 ++++++++++++++++----------------- + drivers/s390/cio/device_pgid.c | 12 +++--- + drivers/s390/cio/eadm_sch.c | 36 +++++++++--------- + drivers/s390/cio/vfio_ccw_drv.c | 8 ++-- + drivers/s390/cio/vfio_ccw_fsm.c | 24 ++++++------ + 10 files changed, 99 insertions(+), 115 deletions(-) + +diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c +index 0abd77f4b6646..2988a699e3ef2 100644 +--- a/drivers/s390/cio/chsc.c ++++ b/drivers/s390/cio/chsc.c +@@ -219,16 +219,16 @@ EXPORT_SYMBOL_GPL(chsc_sadc); + + static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) + { +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + if (sch->driver && sch->driver->chp_event) + if (sch->driver->chp_event(sch, data, CHP_OFFLINE) != 0) + goto out_unreg; +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + return 0; + + out_unreg: + sch->lpm = 0; +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + css_schedule_eval(sch->schid); + return 0; + } +@@ -258,10 +258,10 @@ void chsc_chp_offline(struct chp_id chpid) + + static int __s390_process_res_acc(struct subchannel *sch, void *data) + { +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + if (sch->driver && sch->driver->chp_event) + sch->driver->chp_event(sch, data, CHP_ONLINE); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + + return 0; + } +@@ -292,10 +292,10 @@ static void s390_process_res_acc(struct chp_link *link) + + static int process_fces_event(struct subchannel *sch, void *data) + { +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + if (sch->driver && sch->driver->chp_event) + sch->driver->chp_event(sch, data, CHP_FCES_EVENT); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + return 0; + } + +@@ -769,11 +769,11 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, + + memset(&link, 0, sizeof(struct chp_link)); + link.chpid = chpid; +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + if (sch->driver && sch->driver->chp_event) + sch->driver->chp_event(sch, &link, + on ? CHP_VARY_ON : CHP_VARY_OFF); +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + } + + static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data) +diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c +index 180ab899289c5..902237d0baefe 100644 +--- a/drivers/s390/cio/chsc_sch.c ++++ b/drivers/s390/cio/chsc_sch.c +@@ -211,10 +211,10 @@ static int chsc_async(struct chsc_async_area *chsc_area, + + chsc_area->header.key = PAGE_DEFAULT_KEY >> 4; + while ((sch = chsc_get_next_subchannel(sch))) { +- spin_lock(sch->lock); ++ spin_lock(&sch->lock); + private = dev_get_drvdata(&sch->dev); + if (private->request) { +- spin_unlock(sch->lock); ++ spin_unlock(&sch->lock); + ret = -EBUSY; + continue; + } +@@ -239,7 +239,7 @@ static int chsc_async(struct chsc_async_area *chsc_area, + default: + ret = -ENODEV; + } +- spin_unlock(sch->lock); ++ spin_unlock(&sch->lock); + CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n", + sch->schid.ssid, sch->schid.sch_no, cc); + if (ret == -EINPROGRESS) +diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c +index 81ef9002f0640..7843c69abee6c 100644 +--- a/drivers/s390/cio/cio.c ++++ b/drivers/s390/cio/cio.c +@@ -550,7 +550,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) + return IRQ_HANDLED; + } + sch = phys_to_virt(tpi_info->intparm); +- spin_lock(sch->lock); ++ spin_lock(&sch->lock); + /* Store interrupt response block to lowcore. */ + if (tsch(tpi_info->schid, irb) == 0) { + /* Keep subchannel information word up to date. */ +@@ -562,7 +562,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) + inc_irq_stat(IRQIO_CIO); + } else + inc_irq_stat(IRQIO_CIO); +- spin_unlock(sch->lock); ++ spin_unlock(&sch->lock); + + return IRQ_HANDLED; + } +@@ -667,7 +667,7 @@ struct subchannel *cio_probe_console(void) + if (IS_ERR(sch)) + return sch; + +- lockdep_set_class(sch->lock, &console_sch_key); ++ lockdep_set_class(&sch->lock, &console_sch_key); + isc_register(CONSOLE_ISC); + sch->config.isc = CONSOLE_ISC; + sch->config.intparm = (u32)virt_to_phys(sch); +diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h +index fa8df50bb49e3..a9057a5b670a6 100644 +--- a/drivers/s390/cio/cio.h ++++ b/drivers/s390/cio/cio.h +@@ -83,7 +83,7 @@ enum sch_todo { + /* subchannel data structure used by I/O subroutines */ + struct subchannel { + struct subchannel_id schid; +- spinlock_t *lock; /* subchannel lock */ ++ spinlock_t lock; /* subchannel lock */ + struct mutex reg_mutex; + enum { + SUBCHANNEL_TYPE_IO = 0, +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index e50592c3d30ca..4e63e6d45e6e1 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -148,16 +148,10 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), + + static void css_sch_todo(struct work_struct *work); + +-static int css_sch_create_locks(struct subchannel *sch) ++static void css_sch_create_locks(struct subchannel *sch) + { +- sch->lock = kmalloc(sizeof(*sch->lock), GFP_KERNEL); +- if (!sch->lock) +- return -ENOMEM; +- +- spin_lock_init(sch->lock); ++ spin_lock_init(&sch->lock); + mutex_init(&sch->reg_mutex); +- +- return 0; + } + + static void css_subchannel_release(struct device *dev) +@@ -167,7 +161,6 @@ static void css_subchannel_release(struct device *dev) + sch->config.intparm = 0; + cio_commit_config(sch); + kfree(sch->driver_override); +- kfree(sch->lock); + kfree(sch); + } + +@@ -219,9 +212,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + sch->schib = *schib; + sch->st = schib->pmcw.st; + +- ret = css_sch_create_locks(sch); +- if (ret) +- goto err; ++ css_sch_create_locks(sch); + + INIT_WORK(&sch->todo_work, css_sch_todo); + sch->dev.release = &css_subchannel_release; +@@ -233,19 +224,17 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid, + */ + ret = dma_set_coherent_mask(&sch->dev, DMA_BIT_MASK(31)); + if (ret) +- goto err_lock; ++ goto err; + /* + * But we don't have such restrictions imposed on the stuff that + * is handled by the streaming API. + */ + ret = dma_set_mask(&sch->dev, DMA_BIT_MASK(64)); + if (ret) +- goto err_lock; ++ goto err; + + return sch; + +-err_lock: +- kfree(sch->lock); + err: + put_device(&sch->dev); + return ERR_PTR(ret); +@@ -604,12 +593,12 @@ static void css_sch_todo(struct work_struct *work) + + sch = container_of(work, struct subchannel, todo_work); + /* Find out todo. */ +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + todo = sch->todo; + CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid, + sch->schid.sch_no, todo); + sch->todo = SCH_TODO_NOTHING; +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + /* Perform todo. */ + switch (todo) { + case SCH_TODO_NOTHING: +@@ -617,9 +606,9 @@ static void css_sch_todo(struct work_struct *work) + case SCH_TODO_EVAL: + ret = css_evaluate_known_subchannel(sch, 1); + if (ret == -EAGAIN) { +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + css_sched_sch_todo(sch, todo); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + } + break; + case SCH_TODO_UNREG: +@@ -1028,12 +1017,7 @@ static int __init setup_css(int nr) + css->pseudo_subchannel->dev.parent = &css->device; + css->pseudo_subchannel->dev.release = css_subchannel_release; + mutex_init(&css->pseudo_subchannel->reg_mutex); +- ret = css_sch_create_locks(css->pseudo_subchannel); +- if (ret) { +- kfree(css->pseudo_subchannel); +- device_unregister(&css->device); +- goto out_err; +- } ++ css_sch_create_locks(css->pseudo_subchannel); + + dev_set_name(&css->pseudo_subchannel->dev, "defunct"); + ret = device_register(&css->pseudo_subchannel->dev); +diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c +index 3942aa4921769..93307ca75c10b 100644 +--- a/drivers/s390/cio/device.c ++++ b/drivers/s390/cio/device.c +@@ -751,7 +751,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, + mutex_init(&cdev->reg_mutex); + + atomic_set(&priv->onoff, 0); +- cdev->ccwlock = sch->lock; ++ cdev->ccwlock = &sch->lock; + cdev->dev.parent = &sch->dev; + cdev->dev.release = ccw_device_release; + cdev->dev.bus = &ccw_bus_type; +@@ -767,9 +767,9 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, + goto out_put; + } + priv->flags.initialized = 1; +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + sch_set_cdev(sch, cdev); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + return 0; + + out_put: +@@ -854,9 +854,9 @@ static void io_subchannel_register(struct ccw_device *cdev) + CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + sch_set_cdev(sch, NULL); +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + mutex_unlock(&cdev->reg_mutex); + /* Release initial device reference. */ + put_device(&cdev->dev); +@@ -907,9 +907,9 @@ static void io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) + atomic_inc(&ccw_device_init_count); + + /* Start async. device sensing. */ +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + ccw_device_recognition(cdev); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + } + + static int ccw_device_move_to_sch(struct ccw_device *cdev, +@@ -924,12 +924,12 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev, + return -ENODEV; + + if (!sch_is_pseudo_sch(old_sch)) { +- spin_lock_irq(old_sch->lock); ++ spin_lock_irq(&old_sch->lock); + old_enabled = old_sch->schib.pmcw.ena; + rc = 0; + if (old_enabled) + rc = cio_disable_subchannel(old_sch); +- spin_unlock_irq(old_sch->lock); ++ spin_unlock_irq(&old_sch->lock); + if (rc == -EBUSY) { + /* Release child reference for new parent. */ + put_device(&sch->dev); +@@ -947,9 +947,9 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev, + sch->schib.pmcw.dev, rc); + if (old_enabled) { + /* Try to re-enable the old subchannel. */ +- spin_lock_irq(old_sch->lock); ++ spin_lock_irq(&old_sch->lock); + cio_enable_subchannel(old_sch, (u32)virt_to_phys(old_sch)); +- spin_unlock_irq(old_sch->lock); ++ spin_unlock_irq(&old_sch->lock); + } + /* Release child reference for new parent. */ + put_device(&sch->dev); +@@ -957,19 +957,19 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev, + } + /* Clean up old subchannel. */ + if (!sch_is_pseudo_sch(old_sch)) { +- spin_lock_irq(old_sch->lock); ++ spin_lock_irq(&old_sch->lock); + sch_set_cdev(old_sch, NULL); +- spin_unlock_irq(old_sch->lock); ++ spin_unlock_irq(&old_sch->lock); + css_schedule_eval(old_sch->schid); + } + /* Release child reference for old parent. */ + put_device(&old_sch->dev); + /* Initialize new subchannel. */ +- spin_lock_irq(sch->lock); +- cdev->ccwlock = sch->lock; ++ spin_lock_irq(&sch->lock); ++ cdev->ccwlock = &sch->lock; + if (!sch_is_pseudo_sch(sch)) + sch_set_cdev(sch, cdev); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + if (!sch_is_pseudo_sch(sch)) + css_update_ssd_info(sch); + return 0; +@@ -1080,9 +1080,9 @@ static int io_subchannel_probe(struct subchannel *sch) + return 0; + + out_schedule: +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + css_sched_sch_todo(sch, SCH_TODO_UNREG); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + return 0; + } + +@@ -1096,10 +1096,10 @@ static void io_subchannel_remove(struct subchannel *sch) + goto out_free; + + ccw_device_unregister(cdev); +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + sch_set_cdev(sch, NULL); + set_io_private(sch, NULL); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + out_free: + dma_free_coherent(&sch->dev, sizeof(*io_priv->dma_area), + io_priv->dma_area, io_priv->dma_area_dma); +@@ -1206,7 +1206,7 @@ static void io_subchannel_quiesce(struct subchannel *sch) + struct ccw_device *cdev; + int ret; + +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + cdev = sch_get_cdev(sch); + if (cio_is_console(sch->schid)) + goto out_unlock; +@@ -1223,15 +1223,15 @@ static void io_subchannel_quiesce(struct subchannel *sch) + ret = ccw_device_cancel_halt_clear(cdev); + if (ret == -EBUSY) { + ccw_device_set_timeout(cdev, HZ/10); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + wait_event(cdev->private->wait_q, + cdev->private->state != DEV_STATE_QUIESCE); +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + } + ret = cio_disable_subchannel(sch); + } + out_unlock: +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + } + + static void io_subchannel_shutdown(struct subchannel *sch) +@@ -1467,7 +1467,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) + enum io_sch_action action; + int rc = -EAGAIN; + +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + if (!device_is_registered(&sch->dev)) + goto out_unlock; + if (work_pending(&sch->todo_work)) +@@ -1521,7 +1521,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) + default: + break; + } +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + /* All other actions require process context. */ + if (!process) + goto out; +@@ -1537,9 +1537,9 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) + break; + case IO_SCH_UNREG_CDEV: + case IO_SCH_UNREG_ATTACH: +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + sch_set_cdev(sch, NULL); +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + /* Unregister ccw device. */ + ccw_device_unregister(cdev); + break; +@@ -1568,9 +1568,9 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) + put_device(&cdev->dev); + goto out; + } +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + ccw_device_trigger_reprobe(cdev); +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + /* Release reference from get_ccwdev_by_dev_id() */ + put_device(&cdev->dev); + break; +@@ -1580,7 +1580,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) + return 0; + + out_unlock: +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + out: + return rc; + } +@@ -1876,9 +1876,9 @@ static void ccw_device_todo(struct work_struct *work) + css_schedule_eval(sch->schid); + fallthrough; + case CDEV_TODO_UNREG: +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + sch_set_cdev(sch, NULL); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + ccw_device_unregister(cdev); + break; + default: +diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c +index 3862961697eb6..ad90045873e25 100644 +--- a/drivers/s390/cio/device_pgid.c ++++ b/drivers/s390/cio/device_pgid.c +@@ -698,29 +698,29 @@ int ccw_device_stlck(struct ccw_device *cdev) + return -ENOMEM; + init_completion(&data.done); + data.rc = -EIO; +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + rc = cio_enable_subchannel(sch, (u32)virt_to_phys(sch)); + if (rc) + goto out_unlock; + /* Perform operation. */ + cdev->private->state = DEV_STATE_STEAL_LOCK; + ccw_device_stlck_start(cdev, &data, &buffer[0], &buffer[32]); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + /* Wait for operation to finish. */ + if (wait_for_completion_interruptible(&data.done)) { + /* Got a signal. */ +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + ccw_request_cancel(cdev); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + wait_for_completion(&data.done); + } + rc = data.rc; + /* Check results. */ +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + cio_disable_subchannel(sch); + cdev->private->state = DEV_STATE_BOXED; + out_unlock: +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + kfree(buffer); + + return rc; +diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c +index 826364d2facd8..1caedf931a5f0 100644 +--- a/drivers/s390/cio/eadm_sch.c ++++ b/drivers/s390/cio/eadm_sch.c +@@ -101,12 +101,12 @@ static void eadm_subchannel_timeout(struct timer_list *t) + struct eadm_private *private = from_timer(private, t, timer); + struct subchannel *sch = private->sch; + +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + EADM_LOG(1, "timeout"); + EADM_LOG_HEX(1, &sch->schid, sizeof(sch->schid)); + if (eadm_subchannel_clear(sch)) + EADM_LOG(0, "clear failed"); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + } + + static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires) +@@ -163,16 +163,16 @@ static struct subchannel *eadm_get_idle_sch(void) + spin_lock_irqsave(&list_lock, flags); + list_for_each_entry(private, &eadm_list, head) { + sch = private->sch; +- spin_lock(sch->lock); ++ spin_lock(&sch->lock); + if (private->state == EADM_IDLE) { + private->state = EADM_BUSY; + list_move_tail(&private->head, &eadm_list); +- spin_unlock(sch->lock); ++ spin_unlock(&sch->lock); + spin_unlock_irqrestore(&list_lock, flags); + + return sch; + } +- spin_unlock(sch->lock); ++ spin_unlock(&sch->lock); + } + spin_unlock_irqrestore(&list_lock, flags); + +@@ -190,7 +190,7 @@ int eadm_start_aob(struct aob *aob) + if (!sch) + return -EBUSY; + +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + eadm_subchannel_set_timeout(sch, EADM_TIMEOUT); + ret = eadm_subchannel_start(sch, aob); + if (!ret) +@@ -203,7 +203,7 @@ int eadm_start_aob(struct aob *aob) + css_sched_sch_todo(sch, SCH_TODO_EVAL); + + out_unlock: +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + + return ret; + } +@@ -221,7 +221,7 @@ static int eadm_subchannel_probe(struct subchannel *sch) + INIT_LIST_HEAD(&private->head); + timer_setup(&private->timer, eadm_subchannel_timeout, 0); + +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + set_eadm_private(sch, private); + private->state = EADM_IDLE; + private->sch = sch; +@@ -229,11 +229,11 @@ static int eadm_subchannel_probe(struct subchannel *sch) + ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch)); + if (ret) { + set_eadm_private(sch, NULL); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + kfree(private); + goto out; + } +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + + spin_lock_irq(&list_lock); + list_add(&private->head, &eadm_list); +@@ -248,7 +248,7 @@ static void eadm_quiesce(struct subchannel *sch) + DECLARE_COMPLETION_ONSTACK(completion); + int ret; + +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + if (private->state != EADM_BUSY) + goto disable; + +@@ -256,11 +256,11 @@ static void eadm_quiesce(struct subchannel *sch) + goto disable; + + private->completion = &completion; +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + + wait_for_completion_io(&completion); + +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + private->completion = NULL; + + disable: +@@ -269,7 +269,7 @@ static void eadm_quiesce(struct subchannel *sch) + ret = cio_disable_subchannel(sch); + } while (ret == -EBUSY); + +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + } + + static void eadm_subchannel_remove(struct subchannel *sch) +@@ -282,9 +282,9 @@ static void eadm_subchannel_remove(struct subchannel *sch) + + eadm_quiesce(sch); + +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + set_eadm_private(sch, NULL); +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + + kfree(private); + } +@@ -309,7 +309,7 @@ static int eadm_subchannel_sch_event(struct subchannel *sch, int process) + struct eadm_private *private; + unsigned long flags; + +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + if (!device_is_registered(&sch->dev)) + goto out_unlock; + +@@ -325,7 +325,7 @@ static int eadm_subchannel_sch_event(struct subchannel *sch, int process) + private->state = EADM_IDLE; + + out_unlock: +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + + return 0; + } +diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c +index 43601816ea4e4..a3e25bdd6a76b 100644 +--- a/drivers/s390/cio/vfio_ccw_drv.c ++++ b/drivers/s390/cio/vfio_ccw_drv.c +@@ -65,14 +65,14 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch) + * cancel/halt/clear completion. + */ + private->completion = &completion; +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + + if (ret == -EBUSY) + wait_for_completion_timeout(&completion, 3*HZ); + + private->completion = NULL; + flush_workqueue(vfio_ccw_work_q); +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + ret = cio_disable_subchannel(sch); + } while (ret == -EBUSY); + +@@ -249,7 +249,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process) + unsigned long flags; + int rc = -EAGAIN; + +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + if (!device_is_registered(&sch->dev)) + goto out_unlock; + +@@ -264,7 +264,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process) + } + + out_unlock: +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + + return rc; + } +diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c +index 757b73141246d..09877b46181d4 100644 +--- a/drivers/s390/cio/vfio_ccw_fsm.c ++++ b/drivers/s390/cio/vfio_ccw_fsm.c +@@ -25,7 +25,7 @@ static int fsm_io_helper(struct vfio_ccw_private *private) + unsigned long flags; + int ret; + +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + + orb = cp_get_orb(&private->cp, sch); + if (!orb) { +@@ -72,7 +72,7 @@ static int fsm_io_helper(struct vfio_ccw_private *private) + ret = ccode; + } + out: +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + return ret; + } + +@@ -83,7 +83,7 @@ static int fsm_do_halt(struct vfio_ccw_private *private) + int ccode; + int ret; + +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + + VFIO_CCW_TRACE_EVENT(2, "haltIO"); + VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); +@@ -111,7 +111,7 @@ static int fsm_do_halt(struct vfio_ccw_private *private) + default: + ret = ccode; + } +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + return ret; + } + +@@ -122,7 +122,7 @@ static int fsm_do_clear(struct vfio_ccw_private *private) + int ccode; + int ret; + +- spin_lock_irqsave(sch->lock, flags); ++ spin_lock_irqsave(&sch->lock, flags); + + VFIO_CCW_TRACE_EVENT(2, "clearIO"); + VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); +@@ -147,7 +147,7 @@ static int fsm_do_clear(struct vfio_ccw_private *private) + default: + ret = ccode; + } +- spin_unlock_irqrestore(sch->lock, flags); ++ spin_unlock_irqrestore(&sch->lock, flags); + return ret; + } + +@@ -376,18 +376,18 @@ static void fsm_open(struct vfio_ccw_private *private, + struct subchannel *sch = to_subchannel(private->vdev.dev->parent); + int ret; + +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + sch->isc = VFIO_CCW_ISC; + ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); + if (ret) + goto err_unlock; + + private->state = VFIO_CCW_STATE_IDLE; +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + return; + + err_unlock: +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER); + } + +@@ -397,7 +397,7 @@ static void fsm_close(struct vfio_ccw_private *private, + struct subchannel *sch = to_subchannel(private->vdev.dev->parent); + int ret; + +- spin_lock_irq(sch->lock); ++ spin_lock_irq(&sch->lock); + + if (!sch->schib.pmcw.ena) + goto err_unlock; +@@ -409,12 +409,12 @@ static void fsm_close(struct vfio_ccw_private *private, + goto err_unlock; + + private->state = VFIO_CCW_STATE_STANDBY; +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + cp_free(&private->cp); + return; + + err_unlock: +- spin_unlock_irq(sch->lock); ++ spin_unlock_irq(&sch->lock); + vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER); + } + +-- +2.53.0 + diff --git a/queue-6.6/s390-cio-use-generic-driver_override-infrastructure.patch b/queue-6.6/s390-cio-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..5e4196febd --- /dev/null +++ b/queue-6.6/s390-cio-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,122 @@ +From f446fc8f88779368d7997beb7bdb59ae27efc8b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:13 +0100 +Subject: s390/cio: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit ac4d8bb6e2e13e8684a76ea48d13ebaaaf5c24c4 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: ebc3d1791503 ("s390/cio: introduce driver_override on the css bus") +Reviewed-by: Vineeth Vijayan +Link: https://patch.msgid.link/20260324005919.2408620-10-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/cio.h | 5 ----- + drivers/s390/cio/css.c | 34 ++++------------------------------ + 2 files changed, 4 insertions(+), 35 deletions(-) + +diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h +index a9057a5b670a6..23374604c6b01 100644 +--- a/drivers/s390/cio/cio.h ++++ b/drivers/s390/cio/cio.h +@@ -103,11 +103,6 @@ struct subchannel { + struct work_struct todo_work; + struct schib_config config; + u64 dma_mask; +- /* +- * Driver name to force a match. Do not set directly, because core +- * frees it. Use driver_set_override() to set or clear it. +- */ +- const char *driver_override; + } __attribute__ ((aligned(8))); + + DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb); +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 36c46c7f2fb80..97a2c23f4ce0f 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -160,7 +160,6 @@ static void css_subchannel_release(struct device *dev) + + sch->config.intparm = 0; + cio_commit_config(sch); +- kfree(sch->driver_override); + kfree(sch); + } + +@@ -324,37 +323,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(modalias); + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct subchannel *sch = to_subchannel(dev); +- int ret; +- +- ret = driver_set_override(dev, &sch->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct subchannel *sch = to_subchannel(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", sch->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *subch_attrs[] = { + &dev_attr_type.attr, + &dev_attr_modalias.attr, +- &dev_attr_driver_override.attr, + NULL, + }; + +@@ -1352,9 +1323,11 @@ static int css_bus_match(struct device *dev, struct device_driver *drv) + struct subchannel *sch = to_subchannel(dev); + struct css_driver *driver = to_cssdriver(drv); + struct css_device_id *id; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (sch->driver_override && strcmp(sch->driver_override, drv->name)) ++ ret = device_match_driver_override(dev, drv); ++ if (ret == 0) + return 0; + + for (id = driver->subchannel_type; id->match_flags; id++) { +@@ -1411,6 +1384,7 @@ static int css_uevent(const struct device *dev, struct kobj_uevent_env *env) + + static struct bus_type css_bus_type = { + .name = "css", ++ .driver_override = true, + .match = css_bus_match, + .probe = css_probe, + .remove = css_remove, +-- +2.53.0 + diff --git a/queue-6.6/sched-psi-fix-race-between-file-release-and-pressure.patch b/queue-6.6/sched-psi-fix-race-between-file-release-and-pressure.patch new file mode 100644 index 0000000000..ce79d30242 --- /dev/null +++ b/queue-6.6/sched-psi-fix-race-between-file-release-and-pressure.patch @@ -0,0 +1,184 @@ +From 1c746520840ca3a2a0f07f13fd47ec229016bc52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 14:15:43 +0800 +Subject: sched/psi: fix race between file release and pressure write + +From: Edward Adam Davis + +[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ] + +A potential race condition exists between pressure write and cgroup file +release regarding the priv member of struct kernfs_open_file, which +triggers the uaf reported in [1]. + +Consider the following scenario involving execution on two separate CPUs: + + CPU0 CPU1 + ==== ==== + vfs_rmdir() + kernfs_iop_rmdir() + cgroup_rmdir() + cgroup_kn_lock_live() + cgroup_destroy_locked() + cgroup_addrm_files() + cgroup_rm_file() + kernfs_remove_by_name() + kernfs_remove_by_name_ns() + vfs_write() __kernfs_remove() + new_sync_write() kernfs_drain() + kernfs_fop_write_iter() kernfs_drain_open_files() + cgroup_file_write() kernfs_release_file() + pressure_write() cgroup_file_release() + ctx = of->priv; + kfree(ctx); + of->priv = NULL; + cgroup_kn_unlock() + cgroup_kn_lock_live() + cgroup_get(cgrp) + cgroup_kn_unlock() + if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv + +The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards +the memory deallocation of of->priv performed within cgroup_file_release(). +However, the operations involving of->priv executed within pressure_write() +are not entirely covered by the protection of cgroup_mutex. Consequently, +if the code in pressure_write(), specifically the section handling the +ctx variable executes after cgroup_file_release() has completed, a uaf +vulnerability involving of->priv is triggered. + +Therefore, the issue can be resolved by extending the scope of the +cgroup_mutex lock within pressure_write() to encompass all code paths +involving of->priv, thereby properly synchronizing the race condition +occurring between cgroup_file_release() and pressure_write(). + +And, if an live kn lock can be successfully acquired while executing +the pressure write operation, it indicates that the cgroup deletion +process has not yet reached its final stage; consequently, the priv +pointer within open_file cannot be NULL. Therefore, the operation to +retrieve the ctx value must be moved to a point *after* the live kn +lock has been successfully acquired. + +In another situation, specifically after entering cgroup_kn_lock_live() +but before acquiring cgroup_mutex, there exists a different class of +race condition: + +CPU0: write memory.pressure CPU1: write cgroup.pressure=0 +=========================== ============================= + +kernfs_fop_write_iter() + kernfs_get_active_of(of) + pressure_write() + cgroup_kn_lock_live(memory.pressure) + cgroup_tryget(cgrp) + kernfs_break_active_protection(kn) + ... blocks on cgroup_mutex + + cgroup_pressure_write() + cgroup_kn_lock_live(cgroup.pressure) + cgroup_file_show(memory.pressure, false) + kernfs_show(false) + kernfs_drain_open_files() + cgroup_file_release(of) + kfree(ctx) + of->priv = NULL + cgroup_kn_unlock() + + ... acquires cgroup_mutex + ctx = of->priv; // may now be NULL + if (ctx->psi.trigger) // NULL dereference + +Consequently, there is a possibility that of->priv is NULL, the pressure +write needs to check for this. + +Now that the scope of the cgroup_mutex has been expanded, the original +explicit cgroup_get/put operations are no longer necessary, this is +because acquiring/releasing the live kn lock inherently executes a +cgroup get/put operation. + +[1] +BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 +Call Trace: + pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 + cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 + kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 + +Allocated by task 9352: + cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 + kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 + do_dentry_open+0x83d/0x13e0 fs/open.c:949 + +Freed by task 9353: + cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 + kernfs_release_file fs/kernfs/file.c:764 [inline] + kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 + kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525 + +Fixes: 0e94682b73bf ("psi: introduce psi monitor") +Reported-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=33e571025d88efd1312c +Tested-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Reviewed-by: Chen Ridong +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index e787dc0eacd7d..97812c0b04dd6 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -3775,33 +3775,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) + static ssize_t pressure_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, enum psi_res res) + { +- struct cgroup_file_ctx *ctx = of->priv; ++ struct cgroup_file_ctx *ctx; + struct psi_trigger *new; + struct cgroup *cgrp; + struct psi_group *psi; ++ ssize_t ret = 0; + + cgrp = cgroup_kn_lock_live(of->kn, false); + if (!cgrp) + return -ENODEV; + +- cgroup_get(cgrp); +- cgroup_kn_unlock(of->kn); ++ ctx = of->priv; ++ if (!ctx) { ++ ret = -ENODEV; ++ goto out_unlock; ++ } + + /* Allow only one trigger per file descriptor */ + if (ctx->psi.trigger) { +- cgroup_put(cgrp); +- return -EBUSY; ++ ret = -EBUSY; ++ goto out_unlock; + } + + psi = cgroup_psi(cgrp); + new = psi_trigger_create(psi, buf, res, of->file, of); + if (IS_ERR(new)) { +- cgroup_put(cgrp); +- return PTR_ERR(new); ++ ret = PTR_ERR(new); ++ goto out_unlock; + } + + smp_store_release(&ctx->psi.trigger, new); +- cgroup_put(cgrp); ++ ++out_unlock: ++ cgroup_kn_unlock(of->kn); ++ if (ret) ++ return ret; + + return nbytes; + } +-- +2.53.0 + diff --git a/queue-6.6/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch b/queue-6.6/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch new file mode 100644 index 0000000000..8dce3607c1 --- /dev/null +++ b/queue-6.6/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch @@ -0,0 +1,45 @@ +From 1d40e3f465edf69e288eb8204284205132e86522 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:42 +0800 +Subject: scsi: sg: Fix sysctl sg-big-buff register during sg_init() + +From: Yang Erkun + +[ Upstream commit 3033c471aaf675254efaa0da431e95d91a104b41 ] + +Commit 26d1c80fd61e ("scsi/sg: move sg-big-buff sysctl to scsi/sg.c") made +a mistake. sysctl sg-big-buff was not created because the call to +register_sg_sysctls() was placed on the wrong code path. + +Fixes: 26d1c80fd61e ("scsi/sg: move sg-big-buff sysctl to scsi/sg.c") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-2-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 799773a879188..f958bdf09587d 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1693,13 +1693,13 @@ init_sg(void) + sg_sysfs_valid = 1; + rc = scsi_register_interface(&sg_interface); + if (0 == rc) { ++ register_sg_sysctls(); + #ifdef CONFIG_SCSI_PROC_FS + sg_proc_init(); + #endif /* CONFIG_SCSI_PROC_FS */ + return 0; + } + class_unregister(&sg_sysfs_class); +- register_sg_sysctls(); + err_out: + unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); + return rc; +-- +2.53.0 + diff --git a/queue-6.6/scsi-sg-make-sg_sysfs_class-constant.patch b/queue-6.6/scsi-sg-make-sg_sysfs_class-constant.patch new file mode 100644 index 0000000000..b1546a9420 --- /dev/null +++ b/queue-6.6/scsi-sg-make-sg_sysfs_class-constant.patch @@ -0,0 +1,94 @@ +From 944ca1378dacf4e535ecb9e9d24a9312faf3f7a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 2 Mar 2024 13:47:22 -0300 +Subject: scsi: sg: Make sg_sysfs_class constant + +From: Ricardo B. Marliere + +[ Upstream commit f1fb41765d0bff77514ffeaef37bbb45608f6c62 ] + +Since commit 43a7206b0963 ("driver core: class: make class_register() take +a const *"), the driver core allows for struct class to be in read-only +memory, so move the sg_sysfs_class structure to be declared at build time +placing it into read-only memory, instead of having to be dynamically +allocated at boot time. + +Cc: Greg Kroah-Hartman +Suggested-by: Greg Kroah-Hartman +Signed-off-by: Ricardo B. Marliere +Link: https://lore.kernel.org/r/20240302-class_cleanup-scsi-v1-1-b9096b990e27@marliere.net +Signed-off-by: Martin K. Petersen +Stable-dep-of: 3033c471aaf6 ("scsi: sg: Fix sysctl sg-big-buff register during sg_init()") +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 0dd8b9f8d6717..799773a879188 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1421,7 +1421,9 @@ static const struct file_operations sg_fops = { + .llseek = no_llseek, + }; + +-static struct class *sg_sysfs_class; ++static const struct class sg_sysfs_class = { ++ .name = "scsi_generic" ++}; + + static int sg_sysfs_valid = 0; + +@@ -1523,7 +1525,7 @@ sg_add_device(struct device *cl_dev) + if (sg_sysfs_valid) { + struct device *sg_class_member; + +- sg_class_member = device_create(sg_sysfs_class, cl_dev->parent, ++ sg_class_member = device_create(&sg_sysfs_class, cl_dev->parent, + MKDEV(SCSI_GENERIC_MAJOR, + sdp->index), + sdp, "%s", sdp->name); +@@ -1613,7 +1615,7 @@ sg_remove_device(struct device *cl_dev) + read_unlock_irqrestore(&sdp->sfd_lock, iflags); + + sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); +- device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); ++ device_destroy(&sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); + cdev_del(sdp->cdev); + sdp->cdev = NULL; + +@@ -1685,11 +1687,9 @@ init_sg(void) + SG_MAX_DEVS, "sg"); + if (rc) + return rc; +- sg_sysfs_class = class_create("scsi_generic"); +- if ( IS_ERR(sg_sysfs_class) ) { +- rc = PTR_ERR(sg_sysfs_class); ++ rc = class_register(&sg_sysfs_class); ++ if (rc) + goto err_out; +- } + sg_sysfs_valid = 1; + rc = scsi_register_interface(&sg_interface); + if (0 == rc) { +@@ -1698,7 +1698,7 @@ init_sg(void) + #endif /* CONFIG_SCSI_PROC_FS */ + return 0; + } +- class_destroy(sg_sysfs_class); ++ class_unregister(&sg_sysfs_class); + register_sg_sysctls(); + err_out: + unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); +@@ -1713,7 +1713,7 @@ exit_sg(void) + remove_proc_subtree("scsi/sg", NULL); + #endif /* CONFIG_SCSI_PROC_FS */ + scsi_unregister_interface(&sg_interface); +- class_destroy(sg_sysfs_class); ++ class_unregister(&sg_sysfs_class); + sg_sysfs_valid = 0; + unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), + SG_MAX_DEVS); +-- +2.53.0 + diff --git a/queue-6.6/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch b/queue-6.6/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch new file mode 100644 index 0000000000..de05cda008 --- /dev/null +++ b/queue-6.6/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch @@ -0,0 +1,100 @@ +From 54077bda28be5f55f2e8e895e1a886a3bfb09ca6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:43 +0800 +Subject: scsi: sg: Resolve soft lockup issue when opening /dev/sgX + +From: Yang Erkun + +[ Upstream commit d06a310b45e153872033dd0cf19d5a2279121099 ] + +The parameter def_reserved_size defines the default buffer size reserved +for each Sg_fd and should be restricted to a range between 0 and 1,048,576 +(see https://tldp.org/HOWTO/SCSI-Generic-HOWTO/proc.html). Although the +function sg_proc_write_dressz enforces this limit, it is possible to bypass +it by directly modifying the module parameter as shown below, which then +causes a soft lockup: + +echo -1 > /sys/module/sg/parameters/def_reserved_size +exec 4<> /dev/sg0 + +watchdog: BUG: soft lockup - CPU#5 stuck for 26 seconds! [bash:537] +Modules loaded: +CPU: 5 UID: 0 PID: 537 Command: bash, kernel version 6.19.0-rc3+ #134, +PREEMPT disabled +Hardware: QEMU Standard PC (i440FX + PIIX, 1996), BIOS version +1.16.1-2.fc37 dated 04/01/2014 +... +Call Trace: + + sg_build_reserve+0x5c/0xa0 + sg_add_sfp+0x168/0x270 + sg_open+0x16e/0x340 + chrdev_open+0xbe/0x230 + do_dentry_open+0x175/0x480 + vfs_open+0x34/0xf0 + do_open+0x265/0x3d0 + path_openat+0x110/0x290 + do_filp_open+0xc3/0x170 + do_sys_openat2+0x71/0xe0 + __x64_sys_openat+0x6d/0xa0 + do_syscall_64+0x62/0x310 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The fix is to use module_param_cb to validate and reject invalid values +assigned to def_reserved_size. + +Fixes: 6460e75a104d ("[SCSI] sg: fixes for large page_size") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-3-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index f958bdf09587d..96921a661f64c 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1623,10 +1623,35 @@ sg_remove_device(struct device *cl_dev) + } + + module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +-module_param_named(def_reserved_size, def_reserved_size, int, +- S_IRUGO | S_IWUSR); + module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); + ++static int def_reserved_size_set(const char *val, const struct kernel_param *kp) ++{ ++ int size, ret; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtoint(val, 0, &size); ++ if (ret) ++ return ret; ++ ++ /* limit to 1 MB */ ++ if (size < 0 || size > 1048576) ++ return -ERANGE; ++ ++ def_reserved_size = size; ++ return 0; ++} ++ ++static const struct kernel_param_ops def_reserved_size_ops = { ++ .set = def_reserved_size_set, ++ .get = param_get_int, ++}; ++ ++module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, ++ S_IRUGO | S_IWUSR); ++ + MODULE_AUTHOR("Douglas Gilbert"); + MODULE_DESCRIPTION("SCSI generic (sg) driver"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-6.6/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch b/queue-6.6/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch new file mode 100644 index 0000000000..1053c0f05c --- /dev/null +++ b/queue-6.6/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch @@ -0,0 +1,42 @@ +From f176e5debb8278c8d830a4d03ea3825e5416671a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 23:42:58 +0800 +Subject: scsi: target: core: Fix integer overflow in UNMAP bounds check + +From: Junrui Luo + +[ Upstream commit 2bf2d65f76697820dbc4227d13866293576dd90a ] + +sbc_execute_unmap() checks LBA + range does not exceed the device capacity, +but does not guard against LBA + range wrapping around on 64-bit overflow. + +Add an overflow check matching the pattern already used for WRITE_SAME in +the same file. + +Fixes: 86d7182985d2 ("target: Add sbc_execute_unmap() helper") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881593C61AD52C69FBDB0BDAF7CA@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/target/target_core_sbc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c +index 6a02561cc20ce..ad091a216b076 100644 +--- a/drivers/target/target_core_sbc.c ++++ b/drivers/target/target_core_sbc.c +@@ -1136,7 +1136,8 @@ sbc_execute_unmap(struct se_cmd *cmd) + goto err; + } + +- if (lba + range > dev->transport->get_blocks(dev) + 1) { ++ if (lba + range < lba || ++ lba + range > dev->transport->get_blocks(dev) + 1) { + ret = TCM_ADDRESS_OUT_OF_RANGE; + goto err; + } +-- +2.53.0 + diff --git a/queue-6.6/sctp-discard-stale-init-after-handshake-completion.patch b/queue-6.6/sctp-discard-stale-init-after-handshake-completion.patch new file mode 100644 index 0000000000..627ea9fe3d --- /dev/null +++ b/queue-6.6/sctp-discard-stale-init-after-handshake-completion.patch @@ -0,0 +1,49 @@ +From 536de5c113fa37fcb757f46931ed8144752b9598 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:41 -0400 +Subject: sctp: discard stale INIT after handshake completion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Xin Long + +[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ] + +After an association reaches ESTABLISHED, the peer’s init_tag is already +known from the handshake. Any subsequent INIT with the same init_tag is +not a valid restart, but a delayed or duplicate INIT. + +Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of +processing them as new association attempts. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/5788c76c1ee122a3ed00189e88dcf9df1fba226c.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index e0e626dc79535..5e9449b0c7907 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -1555,6 +1555,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( + /* Tag the variable length parameters. */ + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); + ++ if (asoc->state >= SCTP_STATE_ESTABLISHED) { ++ /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ ++ if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) ++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ } ++ + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, +-- +2.53.0 + diff --git a/queue-6.6/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch b/queue-6.6/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch new file mode 100644 index 0000000000..53da9d0915 --- /dev/null +++ b/queue-6.6/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch @@ -0,0 +1,44 @@ +From 879f8b172f4231fb4f167f7f42afedff68dedff6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 14:13:51 -0400 +Subject: sctp: fix missing encap_port propagation for GSO fragments + +From: Xin Long + +[ Upstream commit bf6f95ae3b8b2638c0e1d6d802d50983ce5d0f45 ] + +encap_port in SCTP_INPUT_CB(skb) is used by sctp_vtag_verify() for +SCTP-over-UDP processing. In the GSO case, it is only set on the head +skb, while fragment skbs leave it 0. + +This results in fragment skbs seeing encap_port == 0, breaking +SCTP-over-UDP connections. + +Fix it by propagating encap_port from the head skb cb when initializing +fragment skbs in sctp_inq_pop(). + +Fixes: 046c052b475e ("sctp: enable udp tunneling socks") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/ea65ed61b3598d8b4940f0170b9aa1762307e6c3.1776017631.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/inqueue.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c +index f5a7d5a387555..a024c08432471 100644 +--- a/net/sctp/inqueue.c ++++ b/net/sctp/inqueue.c +@@ -201,6 +201,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + + cb->chunk = head_cb->chunk; + cb->af = head_cb->af; ++ cb->encap_port = head_cb->encap_port; + } + } + +-- +2.53.0 + diff --git a/queue-6.6/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch b/queue-6.6/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch new file mode 100644 index 0000000000..9bb1952b8a --- /dev/null +++ b/queue-6.6/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch @@ -0,0 +1,68 @@ +From 15601050507056ebe792f6bc816f03aa0add39c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 23:19:03 -0400 +Subject: sctp: fix OOB write to userspace in sctp_getsockopt_peer_auth_chunks + +From: Michael Bommarito + +[ Upstream commit 0cf004ffb61cd32d140531c3a84afe975f9fc7ea ] + +sctp_getsockopt_peer_auth_chunks() checks that the caller's optval +buffer is large enough for the peer AUTH chunk list with + + if (len < num_chunks) + return -EINVAL; + +but then writes num_chunks bytes to p->gauth_chunks, which lives +at offset offsetof(struct sctp_authchunks, gauth_chunks) == 8 +inside optval. The check is missing the sizeof(struct +sctp_authchunks) = 8-byte header. When the caller supplies +len == num_chunks (for any num_chunks > 0) the test passes but +copy_to_user() writes sizeof(struct sctp_authchunks) = 8 bytes +past the declared buffer. + +The sibling function sctp_getsockopt_local_auth_chunks() at the +next line already has the correct check: + + if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + +Align the peer variant with its sibling. + +Reproducer confirms on v7.0-13-generic: an unprivileged userspace +caller that opens a loopback SCTP association with AUTH enabled, +queries num_chunks with a short optval, then issues the real +getsockopt with len == num_chunks and sentinel bytes painted past +the buffer observes those sentinel bytes overwritten with the +peer's AUTH chunk type. The bytes written are under the peer's +control but land in the caller's own userspace; this is not a +kernel memory corruption, but it is a kernel-side contract +violation that can silently corrupt adjacent userspace data. + +Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260416031903.1447072-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index b3c19210667fb..98586bcf83ceb 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -6997,7 +6997,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, + + /* See if the user provided enough room for all the data */ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); +- if (len < num_chunks) ++ if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + + if (copy_to_user(to, ch->chunks, num_chunks)) +-- +2.53.0 + diff --git a/queue-6.6/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch b/queue-6.6/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch new file mode 100644 index 0000000000..2afbc17241 --- /dev/null +++ b/queue-6.6/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch @@ -0,0 +1,75 @@ +From 1f2e0ae5a7dba5752fe91aec5da4c2a80cef46b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 16:05:26 -0400 +Subject: selftest: memcg: skip memcg_sock test if address family not supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Waiman Long + +[ Upstream commit 2d028f3e4bbbfd448928a8d3d2814b0b04c214f4 ] + +The test_memcg_sock test in memcontrol.c sets up an IPv6 socket and send +data over it to consume memory and verify that memory.stat.sock and +memory.current values are close. + +On systems where IPv6 isn't enabled or not configured to support +SOCK_STREAM, the test_memcg_sock test always fails. When the socket() +call fails, there is no way we can test the memory consumption and verify +the above claim. I believe it is better to just skip the test in this +case instead of reporting a test failure hinting that there may be +something wrong with the memcg code. + +Link: https://lkml.kernel.org/r/20260311200526.885899-1-longman@redhat.com +Fixes: 5f8f019380b8 ("selftests: cgroup/memcontrol: add basic test for socket accounting") +Signed-off-by: Waiman Long +Acked-by: Michal Koutný +Acked-by: Shakeel Butt +Cc: Johannes Weiner +Cc: Michal Hocko +Cc: Michal Koutný +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Roman Gushchin +Cc: Shuah Khan +Cc: Tejun Heo +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/cgroup/test_memcontrol.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c +index b462416b38061..6efa26a8383e1 100644 +--- a/tools/testing/selftests/cgroup/test_memcontrol.c ++++ b/tools/testing/selftests/cgroup/test_memcontrol.c +@@ -940,8 +940,11 @@ static int tcp_server(const char *cgroup, void *arg) + saddr.sin6_port = htons(srv_args->port); + + sk = socket(AF_INET6, SOCK_STREAM, 0); +- if (sk < 0) ++ if (sk < 0) { ++ /* Pass back errno to the ctl_fd */ ++ write(ctl_fd, &errno, sizeof(errno)); + return ret; ++ } + + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + goto cleanup; +@@ -1071,6 +1074,12 @@ static int test_memcg_sock(const char *root) + goto cleanup; + close(args.ctl[0]); + ++ /* Skip if address family not supported by protocol */ ++ if (err == EAFNOSUPPORT) { ++ ret = KSFT_SKIP; ++ goto cleanup; ++ } ++ + if (!err) + break; + if (err != EADDRINUSE) +-- +2.53.0 + diff --git a/queue-6.6/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch b/queue-6.6/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch new file mode 100644 index 0000000000..12ee9276c6 --- /dev/null +++ b/queue-6.6/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch @@ -0,0 +1,58 @@ +From 6d6e4070548ea8139cc820a42f0f0ede501dd8e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:39:41 -0500 +Subject: selftests/mm: skip migration tests if NUMA is unavailable + +From: AnishMulay + +[ Upstream commit 54218f10dfbe88c8e41c744fd45a756cde60b8c4 ] + +Currently, the migration test asserts that numa_available() returns 0. On +systems where NUMA is not available (returning -1), such as certain ARM64 +configurations or single-node systems, this assertion fails and crashes +the test. + +Update the test to check the return value of numa_available(). If it is +less than 0, skip the test gracefully instead of failing. + +This aligns the behavior with other MM selftests (like rmap) that skip +when NUMA support is missing. + +Link: https://lkml.kernel.org/r/20260218163941.13499-1-anishm7030@gmail.com +Fixes: 0c2d08728470 ("mm: add selftests for migration entries") +Signed-off-by: AnishMulay +Reviewed-by: SeongJae Park +Reviewed-by: Dev Jain +Reviewed-by: Anshuman Khandual +Tested-by: Sayali Patil +Acked-by: David Hildenbrand (Arm) +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/migration.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c +index 6908569ef4065..877ee32d04c82 100644 +--- a/tools/testing/selftests/mm/migration.c ++++ b/tools/testing/selftests/mm/migration.c +@@ -33,7 +33,8 @@ FIXTURE_SETUP(migration) + { + int n; + +- ASSERT_EQ(numa_available(), 0); ++ if (numa_available() < 0) ++ SKIP(return, "NUMA not available"); + self->nthreads = numa_num_task_cpus() - 1; + self->n1 = -1; + self->n2 = -1; +-- +2.53.0 + diff --git a/queue-6.6/selftests-powerpc-re-order-flags-to-follow-lib.mk.patch b/queue-6.6/selftests-powerpc-re-order-flags-to-follow-lib.mk.patch new file mode 100644 index 0000000000..eee4655808 --- /dev/null +++ b/queue-6.6/selftests-powerpc-re-order-flags-to-follow-lib.mk.patch @@ -0,0 +1,313 @@ +From ab722045e016301656fa3e75f4c74f862d30412b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Feb 2024 15:07:09 +0530 +Subject: selftests/powerpc: Re-order *FLAGS to follow lib.mk + +From: Madhavan Srinivasan + +[ Upstream commit 37496845c812db2a470d51088a59ee38156e8058 ] + +In some powerpc/ sub-folder Makefiles, CFLAGS are defined before lib.mk +include. Clean it up by re-ordering the flags to follow after the mk +include. This is needed to support sub-folders in powerpc/ buildable on +its own. + +Signed-off-by: Madhavan Srinivasan +Signed-off-by: Michael Ellerman +Link: https://msgid.link/20240229093711.581230-1-maddy@linux.ibm.com +Stable-dep-of: 6e65886fceb2 ("selftests/powerpc: Suppress -Wmaybe-uninitialized with GCC 15") +Signed-off-by: Sasha Levin +--- + .../selftests/powerpc/benchmarks/Makefile | 4 ++-- + .../selftests/powerpc/copyloops/Makefile | 20 +++++++++---------- + .../selftests/powerpc/nx-gzip/Makefile | 4 ++-- + .../selftests/powerpc/pmu/ebb/Makefile | 20 +++++++++---------- + .../powerpc/pmu/event_code_tests/Makefile | 4 ++-- + .../powerpc/pmu/sampling_tests/Makefile | 4 ++-- + .../selftests/powerpc/primitives/Makefile | 4 ++-- + .../selftests/powerpc/security/Makefile | 4 ++-- + .../testing/selftests/powerpc/signal/Makefile | 3 ++- + .../selftests/powerpc/stringloops/Makefile | 10 +++++----- + .../selftests/powerpc/switch_endian/Makefile | 4 ++-- + .../selftests/powerpc/syscalls/Makefile | 4 ++-- + tools/testing/selftests/powerpc/vphn/Makefile | 4 ++-- + 13 files changed, 45 insertions(+), 44 deletions(-) + +diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile +index a32a6ab899144..75f5232c3aeca 100644 +--- a/tools/testing/selftests/powerpc/benchmarks/Makefile ++++ b/tools/testing/selftests/powerpc/benchmarks/Makefile +@@ -4,11 +4,11 @@ TEST_GEN_FILES := exec_target + + TEST_FILES := settings + +-CFLAGS += -O2 +- + top_srcdir = ../../../../.. + include ../../lib.mk + ++CFLAGS += -O2 ++ + $(TEST_GEN_PROGS): ../harness.c + + $(OUTPUT)/context_switch: ../utils.c +diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile +index 77594e697f2fa..72684ed589c0a 100644 +--- a/tools/testing/selftests/powerpc/copyloops/Makefile ++++ b/tools/testing/selftests/powerpc/copyloops/Makefile +@@ -1,14 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 +-# The loops are all 64-bit code +-CFLAGS += -m64 +-CFLAGS += -I$(CURDIR) +-CFLAGS += -D SELFTEST +-CFLAGS += -maltivec +-CFLAGS += -mcpu=power4 +- +-# Use our CFLAGS for the implicit .S rule & set the asm machine type +-ASFLAGS = $(CFLAGS) -Wa,-mpower4 +- + TEST_GEN_PROGS := copyuser_64_t0 copyuser_64_t1 copyuser_64_t2 \ + copyuser_p7_t0 copyuser_p7_t1 \ + memcpy_64_t0 memcpy_64_t1 memcpy_64_t2 \ +@@ -21,6 +11,16 @@ EXTRA_SOURCES := validate.c ../harness.c stubs.S + top_srcdir = ../../../../.. + include ../../lib.mk + ++# The loops are all 64-bit code ++CFLAGS += -m64 ++CFLAGS += -I$(CURDIR) ++CFLAGS += -D SELFTEST ++CFLAGS += -maltivec ++CFLAGS += -mcpu=power4 ++ ++# Use our CFLAGS for the implicit .S rule & set the asm machine type ++ASFLAGS = $(CFLAGS) -Wa,-mpower4 ++ + $(OUTPUT)/copyuser_64_t%: copyuser_64.S $(EXTRA_SOURCES) + $(CC) $(CPPFLAGS) $(CFLAGS) \ + -D COPY_LOOP=test___copy_tofrom_user_base \ +diff --git a/tools/testing/selftests/powerpc/nx-gzip/Makefile b/tools/testing/selftests/powerpc/nx-gzip/Makefile +index 0785c2e99d407..b40991f902b2c 100644 +--- a/tools/testing/selftests/powerpc/nx-gzip/Makefile ++++ b/tools/testing/selftests/powerpc/nx-gzip/Makefile +@@ -1,8 +1,8 @@ +-CFLAGS = -O3 -m64 -I./include -I../include +- + TEST_GEN_FILES := gzfht_test gunz_test + TEST_PROGS := nx-gzip-test.sh + + include ../../lib.mk + ++CFLAGS = -O3 -m64 -I./include -I../include ++ + $(TEST_GEN_FILES): gzip_vas.c ../utils.c +diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile +index 0101606902272..b3946ce17e0c1 100644 +--- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile ++++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile +@@ -4,16 +4,6 @@ include ../../../../../build/Build.include + noarg: + $(MAKE) -C ../../ + +-# The EBB handler is 64-bit code and everything links against it +-CFLAGS += -m64 +- +-TMPOUT = $(OUTPUT)/TMPDIR/ +-# Toolchains may build PIE by default which breaks the assembly +-no-pie-option := $(call try-run, echo 'int main() { return 0; }' | \ +- $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -no-pie -x c - -o "$$TMP", -no-pie) +- +-LDFLAGS += $(no-pie-option) +- + TEST_GEN_PROGS := reg_access_test event_attributes_test cycles_test \ + cycles_with_freeze_test pmc56_overflow_test \ + ebb_vs_cpu_event_test cpu_event_vs_ebb_test \ +@@ -29,6 +19,16 @@ TEST_GEN_PROGS := reg_access_test event_attributes_test cycles_test \ + top_srcdir = ../../../../../.. + include ../../../lib.mk + ++# The EBB handler is 64-bit code and everything links against it ++CFLAGS += -m64 ++ ++TMPOUT = $(OUTPUT)/TMPDIR/ ++# Toolchains may build PIE by default which breaks the assembly ++no-pie-option := $(call try-run, echo 'int main() { return 0; }' | \ ++ $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -no-pie -x c - -o "$$TMP", -no-pie) ++ ++LDFLAGS += $(no-pie-option) ++ + $(TEST_GEN_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c \ + ebb.c ebb_handler.S trace.c busy_loop.S + +diff --git a/tools/testing/selftests/powerpc/pmu/event_code_tests/Makefile b/tools/testing/selftests/powerpc/pmu/event_code_tests/Makefile +index 4e07d70464574..509d4b235b9e5 100644 +--- a/tools/testing/selftests/powerpc/pmu/event_code_tests/Makefile ++++ b/tools/testing/selftests/powerpc/pmu/event_code_tests/Makefile +@@ -1,6 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 +-CFLAGS += -m64 +- + TEST_GEN_PROGS := group_constraint_pmc56_test group_pmc56_exclude_constraints_test group_constraint_pmc_count_test \ + group_constraint_repeat_test group_constraint_radix_scope_qual_test reserved_bits_mmcra_sample_elig_mode_test \ + group_constraint_mmcra_sample_test invalid_event_code_test reserved_bits_mmcra_thresh_ctl_test \ +@@ -12,4 +10,6 @@ TEST_GEN_PROGS := group_constraint_pmc56_test group_pmc56_exclude_constraints_te + top_srcdir = ../../../../../.. + include ../../../lib.mk + ++CFLAGS += -m64 ++ + $(TEST_GEN_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c ../sampling_tests/misc.h ../sampling_tests/misc.c +diff --git a/tools/testing/selftests/powerpc/pmu/sampling_tests/Makefile b/tools/testing/selftests/powerpc/pmu/sampling_tests/Makefile +index 9e67351fb252b..d45892151e05d 100644 +--- a/tools/testing/selftests/powerpc/pmu/sampling_tests/Makefile ++++ b/tools/testing/selftests/powerpc/pmu/sampling_tests/Makefile +@@ -1,6 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 +-CFLAGS += -m64 +- + TEST_GEN_PROGS := mmcr0_exceptionbits_test mmcr0_cc56run_test mmcr0_pmccext_test \ + mmcr0_pmcjce_test mmcr0_fc56_pmc1ce_test mmcr0_fc56_pmc56_test \ + mmcr1_comb_test mmcr2_l2l3_test mmcr2_fcs_fch_test \ +@@ -12,4 +10,6 @@ TEST_GEN_PROGS := mmcr0_exceptionbits_test mmcr0_cc56run_test mmcr0_pmccext_test + top_srcdir = ../../../../../.. + include ../../../lib.mk + ++CFLAGS += -m64 ++ + $(TEST_GEN_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c misc.c misc.h ../loop.S ../branch_loops.S +diff --git a/tools/testing/selftests/powerpc/primitives/Makefile b/tools/testing/selftests/powerpc/primitives/Makefile +index 9b9491a632136..6dc5c5a42ca95 100644 +--- a/tools/testing/selftests/powerpc/primitives/Makefile ++++ b/tools/testing/selftests/powerpc/primitives/Makefile +@@ -1,9 +1,9 @@ + # SPDX-License-Identifier: GPL-2.0-only +-CFLAGS += -I$(CURDIR) +- + TEST_GEN_PROGS := load_unaligned_zeropad + + top_srcdir = ../../../../.. + include ../../lib.mk + ++CFLAGS += -I$(CURDIR) ++ + $(TEST_GEN_PROGS): ../harness.c +diff --git a/tools/testing/selftests/powerpc/security/Makefile b/tools/testing/selftests/powerpc/security/Makefile +index e0d979ab02040..0a08386be9696 100644 +--- a/tools/testing/selftests/powerpc/security/Makefile ++++ b/tools/testing/selftests/powerpc/security/Makefile +@@ -5,10 +5,10 @@ TEST_PROGS := mitigation-patching.sh + + top_srcdir = ../../../../.. + +-CFLAGS += $(KHDR_INCLUDES) +- + include ../../lib.mk + ++CFLAGS += $(KHDR_INCLUDES) ++ + $(TEST_GEN_PROGS): ../harness.c ../utils.c + + $(OUTPUT)/spectre_v2: CFLAGS += -m64 +diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile +index f679d260afc87..b15d5dbccc24b 100644 +--- a/tools/testing/selftests/powerpc/signal/Makefile ++++ b/tools/testing/selftests/powerpc/signal/Makefile +@@ -3,7 +3,6 @@ TEST_GEN_PROGS := signal signal_tm sigfuz sigreturn_vdso sig_sc_double_restart + TEST_GEN_PROGS += sigreturn_kernel + TEST_GEN_PROGS += sigreturn_unaligned + +-CFLAGS += -maltivec + $(OUTPUT)/signal_tm: CFLAGS += -mhtm + $(OUTPUT)/sigfuz: CFLAGS += -pthread -m64 + +@@ -12,4 +11,6 @@ TEST_FILES := settings + top_srcdir = ../../../../.. + include ../../lib.mk + ++CFLAGS += -maltivec ++ + $(TEST_GEN_PROGS): ../harness.c ../utils.c signal.S +diff --git a/tools/testing/selftests/powerpc/stringloops/Makefile b/tools/testing/selftests/powerpc/stringloops/Makefile +index 9c39f55a58ff3..87c8c8f238daa 100644 +--- a/tools/testing/selftests/powerpc/stringloops/Makefile ++++ b/tools/testing/selftests/powerpc/stringloops/Makefile +@@ -1,7 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 +-# The loops are all 64-bit code +-CFLAGS += -I$(CURDIR) +- + EXTRA_SOURCES := ../harness.c + + build_32bit = $(shell if ($(CC) $(CFLAGS) -m32 -o /dev/null memcmp.c >/dev/null 2>&1) then echo "1"; fi) +@@ -27,9 +24,12 @@ $(OUTPUT)/strlen_32: CFLAGS += -m32 + TEST_GEN_PROGS += strlen_32 + endif + +-ASFLAGS = $(CFLAGS) +- + top_srcdir = ../../../../.. + include ../../lib.mk + ++# The loops are all 64-bit code ++CFLAGS += -I$(CURDIR) ++ ++ASFLAGS = $(CFLAGS) ++ + $(TEST_GEN_PROGS): $(EXTRA_SOURCES) +diff --git a/tools/testing/selftests/powerpc/switch_endian/Makefile b/tools/testing/selftests/powerpc/switch_endian/Makefile +index bdc081afedb0f..8f0c2a1d3333b 100644 +--- a/tools/testing/selftests/powerpc/switch_endian/Makefile ++++ b/tools/testing/selftests/powerpc/switch_endian/Makefile +@@ -1,13 +1,13 @@ + # SPDX-License-Identifier: GPL-2.0 + TEST_GEN_PROGS := switch_endian_test + +-ASFLAGS += -O2 -Wall -g -nostdlib -m64 +- + EXTRA_CLEAN = $(OUTPUT)/*.o $(OUTPUT)/check-reversed.S + + top_srcdir = ../../../../.. + include ../../lib.mk + ++ASFLAGS += -O2 -Wall -g -nostdlib -m64 ++ + $(OUTPUT)/switch_endian_test: ASFLAGS += -I $(OUTPUT) + $(OUTPUT)/switch_endian_test: $(OUTPUT)/check-reversed.S + +diff --git a/tools/testing/selftests/powerpc/syscalls/Makefile b/tools/testing/selftests/powerpc/syscalls/Makefile +index ee1740ddfb0c2..83dc335007732 100644 +--- a/tools/testing/selftests/powerpc/syscalls/Makefile ++++ b/tools/testing/selftests/powerpc/syscalls/Makefile +@@ -1,9 +1,9 @@ + # SPDX-License-Identifier: GPL-2.0-only + TEST_GEN_PROGS := ipc_unmuxed rtas_filter + +-CFLAGS += $(KHDR_INCLUDES) +- + top_srcdir = ../../../../.. + include ../../lib.mk + ++CFLAGS += $(KHDR_INCLUDES) ++ + $(TEST_GEN_PROGS): ../harness.c ../utils.c +diff --git a/tools/testing/selftests/powerpc/vphn/Makefile b/tools/testing/selftests/powerpc/vphn/Makefile +index cf65cbf33085a..ddc09a20b80fb 100644 +--- a/tools/testing/selftests/powerpc/vphn/Makefile ++++ b/tools/testing/selftests/powerpc/vphn/Makefile +@@ -1,10 +1,10 @@ + # SPDX-License-Identifier: GPL-2.0-only + TEST_GEN_PROGS := test-vphn + +-CFLAGS += -m64 -I$(CURDIR) +- + top_srcdir = ../../../../.. + include ../../lib.mk + ++CFLAGS += -m64 -I$(CURDIR) ++ + $(TEST_GEN_PROGS): ../harness.c + +-- +2.53.0 + diff --git a/queue-6.6/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch b/queue-6.6/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch new file mode 100644 index 0000000000..650866f85c --- /dev/null +++ b/queue-6.6/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch @@ -0,0 +1,87 @@ +From 08e5125d3a806052aa561e59eb20dbc2747792dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:24:26 +0530 +Subject: selftests/powerpc: Suppress -Wmaybe-uninitialized with GCC 15 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Amit Machhiwal + +[ Upstream commit 6e65886fceb23605eff952d6b1975737b4c4b154 ] + +GCC 15 reports the below false positive '-Wmaybe-uninitialized' warning +in vphn_unpack_associativity() when building the powerpc selftests. + + # make -C tools/testing/selftests TARGETS="powerpc" + [...] + CC test-vphn + In file included from test-vphn.c:3: + In function ‘vphn_unpack_associativity’, + inlined from ‘test_one’ at test-vphn.c:371:2, + inlined from ‘test_vphn’ at test-vphn.c:399:9: + test-vphn.c:10:33: error: ‘be_packed’ may be used uninitialized [-Werror=maybe-uninitialized] + 10 | #define be16_to_cpup(x) bswap_16(*x) + | ^~~~~~~~ + vphn.c:42:27: note: in expansion of macro ‘be16_to_cpup’ + 42 | u16 new = be16_to_cpup(field++); + | ^~~~~~~~~~~~ + In file included from test-vphn.c:19: + vphn.c: In function ‘test_vphn’: + vphn.c:27:16: note: ‘be_packed’ declared here + 27 | __be64 be_packed[VPHN_REGISTER_COUNT]; + | ^~~~~~~~~ + cc1: all warnings being treated as errors + +When vphn_unpack_associativity() is called from hcall_vphn() in kernel +the error is not seen while building vphn.c during kernel compilation. +This is because the top level Makefile includes '-fno-strict-aliasing' +flag always. + +The issue here is that GCC 15 emits '-Wmaybe-uninitialized' due to type +punning between __be64[] and __b16* when accessing the buffer via +be16_to_cpup(). The underlying object is fully initialized but GCC 15 +fails to track the aliasing due to the strict aliasing violation here. +Please refer [1] and [2]. This results in a false positive warning which +is promoted to an error under '-Werror'. This problem is not seen when +the compilation is performed with GCC 13 and 14. An issue [1] has also +been created on GCC bugzilla. + +The selftest compiles fine with '-fno-strict-aliasing'. Since this GCC +flag is used to compile vphn.c in kernel too, the same flag should be +used to build vphn tests when compiling vphn.c in the selftest as well. + +Fix this by including '-fno-strict-aliasing' during vphn.c compilation +in the selftest. This keeps the build working while limiting the scope +of the suppression to building vphn tests. + +[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124427 +[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99768 + +Fixes: 58dae82843f5 ("selftests/powerpc: Add test for VPHN") +Reviewed-by: Vaibhav Jain +Signed-off-by: Amit Machhiwal +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260313165426.43259-1-amachhiw@linux.ibm.com +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/powerpc/vphn/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/powerpc/vphn/Makefile b/tools/testing/selftests/powerpc/vphn/Makefile +index ddc09a20b80fb..873bc6b3739a6 100644 +--- a/tools/testing/selftests/powerpc/vphn/Makefile ++++ b/tools/testing/selftests/powerpc/vphn/Makefile +@@ -4,7 +4,7 @@ TEST_GEN_PROGS := test-vphn + top_srcdir = ../../../../.. + include ../../lib.mk + +-CFLAGS += -m64 -I$(CURDIR) ++CFLAGS += -m64 -I$(CURDIR) -fno-strict-aliasing + + $(TEST_GEN_PROGS): ../harness.c + +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series new file mode 100644 index 0000000000..09433a9694 --- /dev/null +++ b/queue-6.6/series @@ -0,0 +1,437 @@ +blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch +fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch +drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch +loop-fix-partition-scan-race-between-udev-and-loop_r.patch +nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch +blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch +pstore-ram-fix-resource-leak-when-ioremap-fails.patch +acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch +acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch +devres-fix-missing-node-debug-info-in-devm_krealloc.patch +thermal-drivers-spear-fix-error-condition-for-readin.patch +debugfs-check-for-null-pointer-in-debugfs_create_str.patch +debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch +s390-cio-make-sch-lock-spinlock-pointer-a-member.patch +s390-cio-convert-sprintf-snprintf-to-sysfs_emit.patch +s390-cio-use-generic-driver_override-infrastructure.patch +irqchip-irq-pic32-evic-address-warning-related-to-wr.patch +hrtimers-update-the-return-type-of-enqueue_hrtimer.patch +hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch +hrtimer-reduce-trace-noise-in-hrtimer_start.patch +locking-fix-rwlock-support-in-linux-spinlock_up.h.patch +firmware-dmi-correct-an-indexing-error-in-dmi.h.patch +wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch +wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch +bpf-add-checksum_complete-to-bpf-test-progs.patch +bpf-test_run-fix-the-null-pointer-dereference-issue-.patch +dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch +dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch +s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch +params-replace-__modinit-with-__init_or_module.patch +module-fix-freeing-of-charp-module-parameters-when-c.patch +wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch +wifi-mt76-mt7615-fix-use_cts_prot-support.patch +wifi-mt76-mt7915-fix-use_cts_prot-support.patch +wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch +arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch +wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch +wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch +bpf-devmap-remove-unnecessary-if-check-in-for-loop.patch +bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch +wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch +r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch +powerpc-crash-fix-backup-region-offset-update-to-elf.patch +selftests-powerpc-re-order-flags-to-follow-lib.mk.patch +selftests-powerpc-suppress-wmaybe-uninitialized-with.patch +macvlan-annotate-data-races-around-port-bc_queue_len.patch +bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch +bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch +wifi-brcmfmac-fix-error-pointer-dereference.patch +bpf-drop-task_to_inode-and-inet_conn_established-fro.patch +bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch +acpi-agdi-fix-missing-newline-in-error-message.patch +arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch +net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch +net-bcmgenet-remove-custom-ndo_poll_controller.patch +net-bcmgenet-add-bcmgenet_has_-helpers.patch +net-bcmgenet-move-desc_index-flow-to-ring-0.patch +net-bcmgenet-support-reclaiming-unsent-tx-packets.patch +net-bcmgenet-switch-to-use-64bit-statistics.patch +net-bcmgenet-fix-racing-timeout-handler.patch +netfilter-xt_socket-enable-defrag-after-all-other-ch.patch +netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch +bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch +6pack-propagage-new-tty-types.patch +net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch +net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch +net-rds-optimize-rds_ib_laddr_check.patch +net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch +bpf-fix-oob-in-pcpu_init_value.patch +ppp-require-cap_net_admin-in-target-netns-for-unatta.patch +net-ipa-fix-programming-of-qtime_timestamp_cfg.patch +net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch +dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch +net-mlx5e-fix-features-not-applied-during-netdev-reg.patch +net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch +bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch +bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch +bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch +bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch +bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch +net-phy-aquantia-move-to-separate-directory.patch +net-phy-add-rust-asix-phy-driver.patch +net-phy-move-at803x-phy-driver-to-dedicated-director.patch +net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch +sctp-fix-missing-encap_port-propagation-for-gso-frag.patch +net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch +drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch +drm-sun4i-backend-fix-error-pointer-dereference.patch +asoc-sti-return-errors-from-regmap_field_alloc.patch +asoc-sti-use-managed-regmap_field-allocations.patch +dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch +dm-cache-fix-write-path-cache-coherency-in-passthrou.patch +dm-cache-fix-write-hang-in-passthrough-mode.patch +dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch +dm-cache-fix-concurrent-write-failure-in-passthrough.patch +dm-cache-support-shrinking-the-origin-device.patch +dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch +platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch +dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch +dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch +drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch +drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch +drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch +spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch +drm-sun4i-fix-resource-leaks.patch +drm-amdgpu-add-default-case-in-dvi-mode-validation.patch +dm-init-ensure-device-probing-has-finished-in-dm-mod.patch +fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch +crypto-atmel-remove-cfb-and-ofb.patch +crypto-atmel-use-unregister_-aeads-ahashes-skciphers.patch +crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch +padata-remove-cpu-online-check-from-cpu-add-and-remo.patch +padata-put-cpu-offline-callback-in-online-section-to.patch +drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch +spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch +drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch +drm-msm-dsi-add-the-missing-parameter-description.patch +drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch +drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch +drm-panel-simple-correct-g190ean01-prepare-timing.patch +alsa-core-validate-compress-device-numbers-without-d.patch +drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch +drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch +drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch +drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch +drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch +drm-amd-pm-ci-fill-dw8-fields-from-smc.patch +drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch +alsa-hda-realtek-fix-code-style-error-else-should-fo.patch +asoc-sof-intel-hda-place-check-before-dereference.patch +drm-msm-a6xx-fix-hlsq-register-dumping.patch +drm-msm-shrinker-fix-can_block-logic.patch +drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch +pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch +pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch +asoc-fsl_micfil-add-access-property-for-vad-detected.patch +asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch +asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch +asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch +asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch +asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch +asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch +crypto-qat-use-swab32-macro.patch +asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch +pci-enable-atomicops-only-if-root-port-supports-them.patch +pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch +selftests-mm-skip-migration-tests-if-numa-is-unavail.patch +documentation-fix-a-hugetlbfs-reservation-statement.patch +selftest-memcg-skip-memcg_sock-test-if-address-famil.patch +alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch +asoc-sof-compress-return-the-configured-codec-from-g.patch +pci-tegra194-fix-polling-delay-for-l2-state.patch +pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch +pci-tegra194-disable-ltssm-after-transition-to-detec.patch +pci-tegra194-rename-root_bus-to-root_port_bus-in-teg.patch +pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch +pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch +pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch +pci-tegra194-disable-direct-speed-change-for-endpoin.patch +pci-tegra194-allow-system-suspend-when-the-endpoint-.patch +pci-tegra194-use-dwc-ip-core-version.patch +pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch +spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch +alsa-sc6000-use-standard-print-api.patch +alsa-sc6000-keep-the-programmed-board-state-in-card-.patch +dm-cache-fix-missing-return-in-invalidate_committed-.patch +crypto-jitterentropy-replace-long-held-spinlock-with.patch +gfs2-call-unlock_new_inode-before-d_instantiate.patch +ktest-avoid-undef-warning-when-warnings_file-is-unse.patch +ktest-honor-empty-per-test-option-overrides.patch +ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch +quota-fix-race-of-dquot_scan_active-with-quota-deact.patch +gfs2-add-some-missing-log-locking.patch +gfs2-prevent-null-pointer-dereference-during-unmount.patch +efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch +ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch +arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch +memory-tegra124-emc-fix-dll_change-check.patch +memory-tegra30-emc-fix-dll_change-check.patch +arm64-dts-imx8-apalis-fix-leds-name-collision.patch +arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch +iommufd-vfio-compatibility-extension-check-for-noiom.patch +arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch +arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch +arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch +arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch +soc-qcom-ocmem-make-the-core-clock-optional.patch +soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch +soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch +soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch +arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch +arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch +arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch +arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch +soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch +unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch +ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch +ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch +soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch +soc-qcom-aoss-compare-against-normalized-cooling-sta.patch +arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch +arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch +arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch +arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch +ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch +ocfs2-validate-bg_bits-during-freefrag-scan.patch +ocfs2-validate-group-add-input-before-caching.patch +dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch +soundwire-bus-demote-unattached-state-warnings-to-de.patch +dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch +soundwire-cadence-clear-message-complete-before-sign.patch +tracing-rebuild-full_name-on-each-hist_field_name-ca.patch +ima-check-return-value-of-crypto_shash_final-in-boot.patch +hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch +hid-asus-do-not-abort-probe-when-not-necessary.patch +mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch +dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch +mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch +mtd-spi-nor-sfdp-introduce-smpt_read_dummy-fixup-hoo.patch +mtd-spi-nor-sfdp-introduce-smpt_map_id-fixup-hook.patch +mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch +mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch +mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch +mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch +mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch +hid-usbhid-fix-deadlock-in-hid_post_reset.patch +bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch +bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch +bpf-sockmap-fix-af_unix-iter-deadlock.patch +bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch +bpf-sockmap-take-state-lock-for-af_unix-iter.patch +bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch +bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch +bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch +bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch +pinctrl-pinctrl-pic32-fix-resource-leak.patch +pinctrl-cy8c95x0-remove-duplicate-error-message.patch +pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch +pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch +perf-branch-avoid-incrementing-null.patch +perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch +pinctrl-abx500-fix-type-of-argument-variable.patch +perf-lock-fix-option-value-type-in-parse_max_stack.patch +perf-tools-fix-module-symbol-resolution-for-non-zero.patch +perf-expr-return-einval-for-syntax-error-in-expr__fi.patch +ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch +ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch +ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch +perf-util-kill-die-prototype-dead-for-a-long-time.patch +i3c-master-fix-error-codes-at-send_ccc_cmd.patch +i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch +dev_printk-add-new-dev_err_probe-helpers.patch +backlight-sky81452-backlight-check-return-value-of-d.patch +platform-surface-surfacepro3_button-drop-wakeup-sour.patch +leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch +tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch +platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch +mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch +nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch +fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch +platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch +platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch +rdma-core-prefer-nla_nul_string.patch +clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch +scsi-sg-make-sg_sysfs_class-constant.patch +scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch +scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch +clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch +scsi-target-core-fix-integer-overflow-in-unmap-bound.patch +dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch +clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch +clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch +clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch +clk-imx8mq-correct-the-csi-phy-sels.patch +clk-qoriq-avoid-format-string-warning.patch +clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch +dt-bindings-clock-qcom-dispcc-sc7180-define-mdss-res.patch +clk-qcom-dispcc-sc7180-add-missing-mdss-resets.patch +lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch +clk-visconti-pll-initialize-clk_init_data-to-zero.patch +f2fs-use-sysfs_emit_at-to-simplify-code.patch +f2fs-protect-extension_list-reading-with-sb_lock-in-.patch +drm-i915-constify-watermark-state-checker.patch +drm-i915-simplify-watermark-state-checker-calling-co.patch +drm-i915-extract-intel_dbuf_mdclk_cdclk_ratio_update.patch +drm-i915-loop-over-all-active-pipes-in-intel_mbus_db.patch +drm-i915-wm-verify-the-correct-plane-ddb-entry.patch +crypto-sa2ul-fix-aead-fallback-algorithm-names.patch +crypto-ccp-copy-iv-using-skcipher-ivsize.patch +arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch +arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch +arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch +arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch +arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch +pcmcia-fix-garbled-log-messages-for-kern_cont.patch +arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch +arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch +arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch +macvlan-fix-macvlan_get_size-not-reserving-space-for.patch +net-sched-sch_cake-fix-nat-destination-port-not-bein.patch +nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch +net-sched-taprio-fix-use-after-free-in-advance_sched.patch +tcp-add-data-race-annotations-around-tp-data_segs_ou.patch +tcp-annotate-data-races-around-tp-bytes_sent.patch +tcp-annotate-data-races-around-tp-bytes_retrans.patch +tcp-annotate-data-races-around-tp-dsack_dups.patch +tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch +tcp-annotate-data-races-around-tp-plb_rehash.patch +ice-remove-jumbo_remove-step-from-tx-path.patch +ice-fix-double-free-of-tx_buf-skb.patch +i40e-don-t-advertise-iff_supp_nofcs.patch +e1000e-unroll-ptp-in-probe-error-handling.patch +ipv6-fix-possible-uaf-in-icmpv6_rcv.patch +sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch +pppoe-drop-pfc-frames.patch +openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch +netfilter-nft_osf-restrict-it-to-ipv4.patch +netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch +netfilter-conntrack-remove-sprintf-usage.patch +netfilter-xtables-restrict-several-matches-to-inet-f.patch +ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch +netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch +netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch +slip-reject-vj-receive-packets-on-instances-with-no-.patch +slip-bound-decode-reads-against-the-compressed-packe.patch +arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch +ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch +ksmbd-use-struct_size-to-improve-smb_direct_rdma_xmi.patch +ksmbd-add-support-for-supplementary-groups.patch +ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch +ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch +ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch +net-rds-zero-per-item-info-buffer-before-handing-it-.patch +net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch +net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch +net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch +net-sched-sch_red-annotate-data-races-in-red_dump_st.patch +net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch +net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch +nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch +tipc-fix-double-free-in-tipc_buf_append.patch +vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch +fs-adfs-validate-nzones-in-adfs_validate_bblk.patch +rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch +fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch +mailbox-mailbox-test-free-channels-on-probe-error.patch +sched-psi-fix-race-between-file-release-and-pressure.patch +cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch +mailbox-add-sanity-check-for-channel-array.patch +mailbox-mailbox-test-don-t-free-the-reused-channel.patch +mailbox-mailbox-test-initialize-struct-earlier.patch +mailbox-mailbox-test-make-data_ready-a-per-instance-.patch +btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch +tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch +nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch +netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch +nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch +drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch +drm-amdgpu-fix-spelling-typos.patch +drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch +drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch +netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch +netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch +spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch +drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch +arm64-scs-fix-potential-sign-extension-issue-of-adva.patch +cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch +netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch +net-sched-netem-fix-probability-gaps-in-4-state-loss.patch +net-sched-netem-fix-queue-limit-check-to-include-reo.patch +net-sched-netem-only-reseed-prng-when-seed-is-explic.patch +net-sched-netem-validate-slot-configuration.patch +net-sched-netem-fix-slot-delay-calculation-overflow.patch +net-sched-netem-check-for-negative-latency-and-jitte.patch +net-sched-sch_choke-annotate-data-races-in-choke_dum.patch +net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch +vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch +net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch +net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch +nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch +net-sched-taprio-fix-null-pointer-dereference-in-cla.patch +neighbour-add-rcu-protection-to-neigh_tables.patch +neigh-let-neigh_xmit-take-skb-ownership.patch +alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch +net-mctp-i2c-check-length-before-marking-flow-active.patch +net-phy-dp83869-fix-setting-clk_o_sel-field.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch +asoc-codecs-ab8500-fix-casting-of-private-data.patch +netfilter-skip-recording-stale-or-retransmitted-init.patch +sctp-discard-stale-init-after-handshake-completion.patch +ipv4-rename-and-move-ip_route_output_tunnel.patch +ipv4-remove-proto-argument-from-udp_tunnel_dst_looku.patch +ipv4-add-new-arguments-to-udp_tunnel_dst_lookup.patch +ipv6-rename-and-move-ip6_dst_lookup_tunnel.patch +bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch +net-netconsole-move-newline-trimming-to-function.patch +netconsole-propagate-device-name-truncation-in-dev_n.patch +alsa-hda-conexant-fix-some-typos.patch +alsa-hda-conexant-renaming-the-codec-with-device-id-.patch +alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch +futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch +drm-amd-display-allow-dce-link-encoder-without-aux-r.patch +drm-amd-display-read-edid-from-vbios-embedded-panel-.patch +bonding-802.3ad-replace-mac_address_equal-with-__agg.patch +net-bonding-add-broadcast_neighbor-option-for-802.3a.patch +bonding-add-support-for-per-port-lacp-actor-priority.patch +bonding-print-churn-state-via-netlink.patch +bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch +iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch +iavf-stop-removing-vlan-filters-from-pf-on-interface.patch +iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch +iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch +ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch +net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch +sfc-fix-error-code-in-efx_devlink_info_running_versi.patch +net-sched-cls_flower-revert-unintended-changes.patch diff --git a/queue-6.6/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch b/queue-6.6/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch new file mode 100644 index 0000000000..a1fc711e1f --- /dev/null +++ b/queue-6.6/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch @@ -0,0 +1,37 @@ +From ff1ce46e8ad07ec463e15013cb37dfad779d25e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:48:17 +0300 +Subject: sfc: fix error code in efx_devlink_info_running_versions() + +From: Dan Carpenter + +[ Upstream commit 051ffb001b8a232cfa6e72f38bb5f51c4270a60b ] + +Return -EIO if efx_mcdi_rpc() doesn't return enough space. + +Fixes: 14743ddd2495 ("sfc: add devlink info support for ef100") +Signed-off-by: Dan Carpenter +Reviewed-by: Edward Cree +Link: https://patch.msgid.link/afGpsbLRHL4_H0KS@stanley.mountain +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sfc/efx_devlink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c +index 3cd750820fdde..d5a4b3cf94544 100644 +--- a/drivers/net/ethernet/sfc/efx_devlink.c ++++ b/drivers/net/ethernet/sfc/efx_devlink.c +@@ -530,7 +530,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx, + if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) { + netif_err(efx, drv, efx->net_dev, + "mcdi MC_CMD_GET_VERSION failed\n"); +- return rc; ++ return rc ?: -EIO; + } + + /* Handle previous output */ +-- +2.53.0 + diff --git a/queue-6.6/slip-bound-decode-reads-against-the-compressed-packe.patch b/queue-6.6/slip-bound-decode-reads-against-the-compressed-packe.patch new file mode 100644 index 0000000000..6b45b6f46e --- /dev/null +++ b/queue-6.6/slip-bound-decode-reads-against-the-compressed-packe.patch @@ -0,0 +1,158 @@ +From 785e3b2f4be619f463302426db570413b0be467d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:01:51 +0800 +Subject: slip: bound decode() reads against the compressed packet length + +From: Weiming Shi + +[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ] + +slhc_uncompress() parses a VJ-compressed TCP header by advancing a +pointer through the packet via decode() and pull16(). Neither helper +bounds-checks against isize, and decode() masks its return with +& 0xffff so it can never return the -1 that callers test for -- those +error paths are dead code. + +A short compressed frame whose change byte requests optional fields +lets decode() read past the end of the packet. The over-read bytes +are folded into the cached cstate and reflected into subsequent +reconstructed packets. + +Make decode() and pull16() take the packet end pointer and return -1 +when exhausted. Add a bounds check before the TCP-checksum read. +The existing == -1 tests now do what they were always meant to. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Simon Horman +Closes: https://lore.kernel.org/netdev/20260414134126.758795-2-horms@kernel.org/ +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416100147.531855-5-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index 3474792a37a67..ef586ab250747 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -80,9 +80,9 @@ + #include + + static unsigned char *encode(unsigned char *cp, unsigned short n); +-static long decode(unsigned char **cpp); ++static long decode(unsigned char **cpp, const unsigned char *end); + static unsigned char * put16(unsigned char *cp, unsigned short x); +-static unsigned short pull16(unsigned char **cpp); ++static long pull16(unsigned char **cpp, const unsigned char *end); + + /* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) +@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n) + return cp; + } + +-/* Pull a 16-bit integer in host order from buffer in network byte order */ +-static unsigned short +-pull16(unsigned char **cpp) ++/* Pull a 16-bit integer in host order from buffer in network byte order. ++ * Returns -1 if the buffer is exhausted, otherwise the 16-bit value. ++ */ ++static long ++pull16(unsigned char **cpp, const unsigned char *end) + { +- short rval; ++ long rval; + ++ if (*cpp + 2 > end) ++ return -1; + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; + } + +-/* Decode a number */ ++/* Decode a number. Returns -1 if the buffer is exhausted. */ + static long +-decode(unsigned char **cpp) ++decode(unsigned char **cpp, const unsigned char *end) + { + int x; + ++ if (*cpp >= end) ++ return -1; + x = *(*cpp)++; +- if(x == 0){ +- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ +- } else { +- return x & 0xff; /* -1 if PULLCHAR returned error */ +- } ++ if (x == 0) ++ return pull16(cpp, end); ++ return x & 0xff; + } + + /* +@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; ++ const unsigned char *end = icp + isize; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; +@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + ++ if (cp + 2 > end) ++ goto bad; + thp->check = *(__sum16 *)cp; + cp += 2; + +@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + default: + if(changes & NEW_U){ + thp->urg = 1; +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); +@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + break; + } + if(changes & NEW_I){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); +-- +2.53.0 + diff --git a/queue-6.6/slip-reject-vj-receive-packets-on-instances-with-no-.patch b/queue-6.6/slip-reject-vj-receive-packets-on-instances-with-no-.patch new file mode 100644 index 0000000000..a2e6765e4b --- /dev/null +++ b/queue-6.6/slip-reject-vj-receive-packets-on-instances-with-no-.patch @@ -0,0 +1,98 @@ +From 7c7ea9a400e76971282e45a132d443ea80fbce6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 04:41:31 +0800 +Subject: slip: reject VJ receive packets on instances with no rstate array + +From: Weiming Shi + +[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ] + +slhc_init() accepts rslots == 0 as a valid configuration, with the +documented meaning of 'no receive compression'. In that case the +allocation loop in slhc_init() is skipped, so comp->rstate stays +NULL and comp->rslot_limit stays 0 (from the kzalloc of struct +slcompress). + +The receive helpers do not defend against that configuration. +slhc_uncompress() dereferences comp->rstate[x] when the VJ header +carries an explicit connection ID, and slhc_remember() later assigns +cs = &comp->rstate[...] after only comparing the packet's slot number +to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the +range check, and the code dereferences a NULL rstate. + +The configuration is reachable in-tree through PPP. PPPIOCSMAXCID +stores its argument in a signed int, and (val >> 16) uses arithmetic +shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 +is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because +/dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path +is reachable from an unprivileged user namespace. Once the malformed +VJ state is installed, any inbound VJ-compressed or VJ-uncompressed +frame that selects slot 0 crashes the kernel in softirq context: + + Oops: general protection fault, probably for non-canonical + address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519) + Call Trace: + + ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466) + ppp_input (drivers/net/ppp/ppp_generic.c:2359) + ppp_async_process (drivers/net/ppp/ppp_async.c:492) + tasklet_action_common (kernel/softirq.c:926) + handle_softirqs (kernel/softirq.c:623) + run_ksoftirqd (kernel/softirq.c:1055) + smpboot_thread_fn (kernel/smpboot.c:160) + kthread (kernel/kthread.c:436) + ret_from_fork (arch/x86/kernel/process.c:164) + + +Reject the receive side on such instances instead of touching rstate. +slhc_uncompress() falls through to its existing 'bad' label, which +bumps sls_i_error and enters the toss state. slhc_remember() mirrors +that with an explicit sls_i_error increment followed by slhc_toss(); +the sls_i_runt counter is not used here because a missing rstate is +an internal configuration state, not a runt packet. + +The transmit path is unaffected: the only in-tree caller that picks +rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and +slip.c always calls slhc_init(16, 16), so comp->tstate remains valid +and slhc_compress() continues to work. + +Fixes: 4ab42d78e37a ("ppp, slip: Validate VJ compression slot parameters completely") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415204130.258866-2-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index bf9e801cc61cc..3474792a37a67 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + comp->sls_i_error++; + return 0; + } ++ if (!comp->rstate) ++ goto bad; + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. +@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + unsigned int ihl; + ++ if (!comp->rstate) { ++ comp->sls_i_error++; ++ return slhc_toss(comp); ++ } + /* The packet is shorter than a legal IP header. + * Also make sure isize is positive. + */ +-- +2.53.0 + diff --git a/queue-6.6/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch b/queue-6.6/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch new file mode 100644 index 0000000000..102b69024c --- /dev/null +++ b/queue-6.6/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch @@ -0,0 +1,41 @@ +From 6d5d3d1b06c86a469674ad4eee99ac28d2e8c77f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 12:53:23 -0700 +Subject: soc: qcom: aoss: compare against normalized cooling state + +From: Alok Tiwari + +[ Upstream commit cd3c4670db3ffe997be9548c7a9db3952563cf14 ] + +qmp_cdev_set_cur_state() normalizes the requested state to a boolean +(cdev_state = !!state). The existing early-return check compares +qmp_cdev->state == state, which can be wrong if state is non-boolean +(any non-zero value). Compare qmp_cdev->state against cdev_state instead, +so the check matches the effective state and avoids redundant updates. + +Signed-off-by: Alok Tiwari +Fixes: 05589b30b21a ("soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260329195333.1478090-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/qcom_aoss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c +index 77f0cf126629e..078561b9314ad 100644 +--- a/drivers/soc/qcom/qcom_aoss.c ++++ b/drivers/soc/qcom/qcom_aoss.c +@@ -340,7 +340,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, + /* Normalize state */ + cdev_state = !!state; + +- if (qmp_cdev->state == state) ++ if (qmp_cdev->state == cdev_state) + return 0; + + ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}", +-- +2.53.0 + diff --git a/queue-6.6/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch b/queue-6.6/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch new file mode 100644 index 0000000000..9765a6027b --- /dev/null +++ b/queue-6.6/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch @@ -0,0 +1,45 @@ +From 99a0c0db46949af0e4e612a5c9d0d67ab6ef554d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 02:51:11 -0700 +Subject: soc: qcom: llcc: fix v1 SB syndrome register offset + +From: Alok Tiwari + +[ Upstream commit 24e7625df5ce065393249b78930781be593bc381 ] + +The llcc_v1_edac_reg_offset table uses 0x2304c for trp_ecc_sb_err_syn0, +which is inconsistent with the surrounding TRP ECC registers (0x2034x) +and with llcc_v2_1_edac_reg_offset, where trp_ecc_sb_err_syn0 is 0x2034c +adjacent to trp_ecc_error_status0/1 at 0x20344/0x20348. + +Use 0x2034c for llcc v1 so the SB syndrome register follows the expected ++0x4 progression from trp_ecc_error_status1. This fixes EDAC reading the +wrong register for SB syndrome reporting. + +Fixes: c13d7d261e36 ("soc: qcom: llcc: Pass LLCC version based register offsets to EDAC driver") +Signed-off-by: Alok Tiwari +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260330095118.2657362-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/llcc-qcom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c +index 03d5de759b256..191da9350ca62 100644 +--- a/drivers/soc/qcom/llcc-qcom.c ++++ b/drivers/soc/qcom/llcc-qcom.c +@@ -359,7 +359,7 @@ static const struct llcc_slice_config sm8550_data[] = { + static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { + .trp_ecc_error_status0 = 0x20344, + .trp_ecc_error_status1 = 0x20348, +- .trp_ecc_sb_err_syn0 = 0x2304c, ++ .trp_ecc_sb_err_syn0 = 0x2034c, + .trp_ecc_db_err_syn0 = 0x20370, + .trp_ecc_error_cntr_clear = 0x20440, + .trp_interrupt_0_status = 0x20480, +-- +2.53.0 + diff --git a/queue-6.6/soc-qcom-ocmem-make-the-core-clock-optional.patch b/queue-6.6/soc-qcom-ocmem-make-the-core-clock-optional.patch new file mode 100644 index 0000000000..168cf58e1a --- /dev/null +++ b/queue-6.6/soc-qcom-ocmem-make-the-core-clock-optional.patch @@ -0,0 +1,41 @@ +From 59ca2cbe0a7aa601539f04a93001e455cdb65e11 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:57 +0200 +Subject: soc: qcom: ocmem: make the core clock optional + +From: Dmitry Baryshkov + +[ Upstream commit e8a61c51417c679d1a599fb36695e9d3b8d95514 ] + +OCMEM's core clock (aka RPM bus 2 clock) is being handled internally by +the interconnect driver. Corresponding clock has been dropped from the +SMD RPM clock driver. The users of the ocmem will vote on the ocmemnoc +interconnect paths, making sure that ocmem is on. Make the clock +optional, keeping it for compatibility with older DT. + +Fixes: d6edc31f3a68 ("clk: qcom: smd-rpm: Separate out interconnect bus clocks") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-1-ad9bcae44763@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 1511d19643d41..c5fc6db9870a2 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -313,7 +313,7 @@ static int ocmem_dev_probe(struct platform_device *pdev) + ocmem->dev = dev; + ocmem->config = device_get_match_data(dev); + +- ocmem->core_clk = devm_clk_get(dev, "core"); ++ ocmem->core_clk = devm_clk_get_optional(dev, "core"); + if (IS_ERR(ocmem->core_clk)) + return dev_err_probe(dev, PTR_ERR(ocmem->core_clk), + "Unable to get core clock\n"); +-- +2.53.0 + diff --git a/queue-6.6/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch b/queue-6.6/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch new file mode 100644 index 0000000000..082981715a --- /dev/null +++ b/queue-6.6/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch @@ -0,0 +1,46 @@ +From cb204fd0283589b1d87d2afe404bb24852e01e62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:58 +0200 +Subject: soc: qcom: ocmem: register reasons for probe deferrals + +From: Dmitry Baryshkov + +[ Upstream commit 9dfd69cd89cd6afa4723be9098979abeef3bb8c6 ] + +Instead of printing messages to the dmesg, let the message be recorded +as a reason for the OCMEM client deferral. + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Brian Masney +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-2-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 697c8a6a400b1..b37f21793687c 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -195,10 +195,10 @@ struct ocmem *of_get_ocmem(struct device *dev) + } + + pdev = of_find_device_by_node(devnode->parent); +- if (!pdev) { +- dev_err(dev, "Cannot find device node %s\n", devnode->name); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!pdev) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, ++ "Cannot find device node %s\n", ++ devnode->name); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-6.6/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch b/queue-6.6/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch new file mode 100644 index 0000000000..6ff3e118d2 --- /dev/null +++ b/queue-6.6/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch @@ -0,0 +1,46 @@ +From d42c8305ed66962f50230f59521893cf42d1f88d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:59 +0200 +Subject: soc: qcom: ocmem: return -EPROBE_DEFER is ocmem is not available + +From: Dmitry Baryshkov + +[ Upstream commit 91b59009c7d48b58dbc50fecb27f2ad20749a05a ] + +If OCMEM is declared in DT, it is expected that it is present and +handled by the driver. The GPU driver will ignore -ENODEV error, which +typically means that OCMEM isn't defined in DT. Let ocmem return +-EPROBE_DEFER if it supposed to be used, but it is not probed (yet). + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-3-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index b37f21793687c..1b7fc1fe671bb 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -202,10 +202,9 @@ struct ocmem *of_get_ocmem(struct device *dev) + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +- if (!ocmem) { +- dev_err(dev, "Cannot get ocmem\n"); +- return ERR_PTR(-ENODEV); +- } ++ if (!ocmem) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n"); ++ + return ocmem; + } + EXPORT_SYMBOL(of_get_ocmem); +-- +2.53.0 + diff --git a/queue-6.6/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch b/queue-6.6/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch new file mode 100644 index 0000000000..177b43c75b --- /dev/null +++ b/queue-6.6/soc-qcom-ocmem-use-scoped-device-node-handling-to-si.patch @@ -0,0 +1,55 @@ +From 4fa9039c90909ee2186bebb17abf45552c2fc3c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Aug 2024 15:09:50 +0200 +Subject: soc: qcom: ocmem: use scoped device node handling to simplify error + paths + +From: Krzysztof Kozlowski + +[ Upstream commit f4c1c19f5c0e5cf2870df91dedc6b40400fd9c8a ] + +Obtain the device node reference with scoped/cleanup.h to reduce error +handling and make the code a bit simpler. + +Signed-off-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20240813-b4-cleanup-h-of-node-put-other-v1-4-cfb67323a95c@linaro.org +Signed-off-by: Bjorn Andersson +Stable-dep-of: 9dfd69cd89cd ("soc: qcom: ocmem: register reasons for probe deferrals") +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index c5fc6db9870a2..697c8a6a400b1 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -185,23 +185,20 @@ static void update_range(struct ocmem *ocmem, struct ocmem_buf *buf, + struct ocmem *of_get_ocmem(struct device *dev) + { + struct platform_device *pdev; +- struct device_node *devnode; + struct ocmem *ocmem; + +- devnode = of_parse_phandle(dev->of_node, "sram", 0); ++ struct device_node *devnode __free(device_node) = of_parse_phandle(dev->of_node, ++ "sram", 0); + if (!devnode || !devnode->parent) { + dev_err(dev, "Cannot look up sram phandle\n"); +- of_node_put(devnode); + return ERR_PTR(-ENODEV); + } + + pdev = of_find_device_by_node(devnode->parent); + if (!pdev) { + dev_err(dev, "Cannot find device node %s\n", devnode->name); +- of_node_put(devnode); + return ERR_PTR(-EPROBE_DEFER); + } +- of_node_put(devnode); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-6.6/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch b/queue-6.6/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch new file mode 100644 index 0000000000..9a27afaa94 --- /dev/null +++ b/queue-6.6/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch @@ -0,0 +1,43 @@ +From 4d63f5d17cd2e625ff5ddd5d433042ae90f05b35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:03 +0530 +Subject: soc/tegra: cbb: Set ERD on resume for err interrupt + +From: Sumit Gupta + +[ Upstream commit b6ff71c5d1d4ad858ddf6f39394d169c96689596 ] + +Set the Error Response Disable (ERD) bit to mask SError responses +and use interrupt-based error reporting. When the ERD bit is set, +inband error responses to the initiator via SError are suppressed, +and fabric errors are reported via an interrupt instead. + +The register is set during boot but the info is lost during system +suspend and needs to be set again on resume. + +Fixes: fc2f151d2314 ("soc/tegra: cbb: Add driver for Tegra234 CBB 2.0") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index e8cc46874c729..eace89ed16176 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -1176,6 +1176,10 @@ static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) + { + struct tegra234_cbb *cbb = dev_get_drvdata(dev); + ++ /* set ERD bit to mask SError and generate interrupt to report error */ ++ if (cbb->fabric->off_mask_erd) ++ tegra234_cbb_mask_serror(cbb); ++ + tegra234_cbb_error_enable(&cbb->base); + + dev_dbg(dev, "%s resumed\n", cbb->fabric->name); +-- +2.53.0 + diff --git a/queue-6.6/soundwire-bus-demote-unattached-state-warnings-to-de.patch b/queue-6.6/soundwire-bus-demote-unattached-state-warnings-to-de.patch new file mode 100644 index 0000000000..bd3f3787a9 --- /dev/null +++ b/queue-6.6/soundwire-bus-demote-unattached-state-warnings-to-de.patch @@ -0,0 +1,62 @@ +From cf07a623f5019bdb28f38b116235ef7d154c2a53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:02:10 -0700 +Subject: soundwire: bus: demote UNATTACHED state warnings to dev_dbg() + +From: Cole Leavitt + +[ Upstream commit 2c96956fe764f8224f9ec93b2a9160a578949a7a ] + +The dev_warn() messages in sdw_handle_slave_status() for UNATTACHED +transitions were added in commit d1b328557058 ("soundwire: bus: add +dev_warn() messages to track UNATTACHED devices") to debug attachment +failures with dynamic debug enabled. + +These warnings fire during normal operation -- for example when a codec +driver triggers a hardware reset after firmware download, causing the +device to momentarily go UNATTACHED before re-attaching -- producing +misleading noise on every boot. + +Demote the messages to dev_dbg() so they remain available via dynamic +debug for diagnosing real attachment failures without alarming users +during expected initialization sequences. + +Fixes: d1b328557058 ("soundwire: bus: add dev_warn() messages to track UNATTACHED devices") +Signed-off-by: Cole Leavitt +Reviewed-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260218180210.9263-1-cole@unwrap.rs +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/bus.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c +index e7397fd8e9ad9..50448a4dd0b38 100644 +--- a/drivers/soundwire/bus.c ++++ b/drivers/soundwire/bus.c +@@ -1864,8 +1864,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + + if (status[i] == SDW_SLAVE_UNATTACHED && + slave->status != SDW_SLAVE_UNATTACHED) { +- dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", ++ i, slave->status); + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + + /* Ensure driver knows that peripheral unattached */ +@@ -1916,8 +1916,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + if (slave->status == SDW_SLAVE_UNATTACHED) + break; + +- dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", ++ i, slave->status); + + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + break; +-- +2.53.0 + diff --git a/queue-6.6/soundwire-cadence-clear-message-complete-before-sign.patch b/queue-6.6/soundwire-cadence-clear-message-complete-before-sign.patch new file mode 100644 index 0000000000..c344fe4d1f --- /dev/null +++ b/queue-6.6/soundwire-cadence-clear-message-complete-before-sign.patch @@ -0,0 +1,89 @@ +From 6a43cd5bad7efe98e0dd5c711b639808cdef811d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 11:31:33 +0000 +Subject: soundwire: cadence: Clear message complete before signaling waiting + thread + +From: Richard Fitzgerald + +[ Upstream commit cbfea84f820962c3c5394ff06e7e9344c96bf761 ] + +Clear the CDNS_MCP_INT_RX_WL interrupt before signaling completion. + +This is to prevent the potential race where: +- The main thread is scheduled immediately the completion is signaled, + and starts a new message +- The RX_WL IRQ for this new message happens before sdw_cdns_irq() has + been re-scheduled. +- When sdw_cdns_irq() is re-scheduled it clears the new RX_WL interrupt. + +MAIN THREAD | IRQ THREAD + | + _cdns_xfer_msg() | + { | + write data to FIFO | + wait_for_completion_timeout() | + | <---- RX_WL IRQ + | sdw_cdns_irq() + | { + | signal completion + <== RESCHEDULE <== + Handle message completion | + } | + | +Start new message | + _cdns_xfer_msg() | + { | + write data to FIFO | + wait_for_completion_timeout() | + | <---- RX_WL IRQ + ==> RESCHEDULE ==> + | // New RX_WL IRQ is cleared before + | // it has been handled. + | clear CDNS_MCP_INTSTAT + + | return IRQ_HANDLED; + | } + +Before this change, this error message was sometimes seen on kernels +that have large amounts of debugging enabled: + + SCP Msg trf timed out + +This error indicates that the completion has not been signalled after +500ms. + +Signed-off-by: Richard Fitzgerald +Fixes: 956baa1992f9 ("soundwire: cdns: Add sdw_master_ops and IO transfer support") +Reported-by: Norman Bintang +Closes: https://issuetracker.google.com/issues/477099834 +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20260310113133.1707288-1-rf@opensource.cirrus.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/cadence_master.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c +index e69982dbd449b..fdbd5d477a68e 100644 +--- a/drivers/soundwire/cadence_master.c ++++ b/drivers/soundwire/cadence_master.c +@@ -932,6 +932,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) + + cdns_read_response(cdns); + ++ /* ++ * Clear interrupt before signalling the completion to avoid ++ * a race between this thread and the main thread starting ++ * another TX. ++ */ ++ cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_RX_WL); ++ int_status &= ~CDNS_MCP_INT_RX_WL; ++ + if (defer && defer->msg) { + cdns_fill_msg_resp(cdns, defer->msg, + defer->length, 0); +-- +2.53.0 + diff --git a/queue-6.6/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch b/queue-6.6/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..d70cd58348 --- /dev/null +++ b/queue-6.6/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 6374a7bee8b5b1f727acc0cebf2fa11314b3f54e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:21 +0800 +Subject: spi: fsl-qspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 981b080a79724738882b0af1c5bb7ade30d94f24 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks could +get "lost" - use reinit_completion() in that case, but be aware of +other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: 84d043185dbe ("spi: Add a driver for the Freescale/NXP QuadSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-3-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-fsl-qspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c +index 21e357966d2a2..cb2e5413dd32b 100644 +--- a/drivers/spi/spi-fsl-qspi.c ++++ b/drivers/spi/spi-fsl-qspi.c +@@ -606,7 +606,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) + void __iomem *base = q->iobase; + int err = 0; + +- init_completion(&q->c); ++ reinit_completion(&q->c); + + /* + * Always start the sequence at the same index since we update +@@ -924,6 +924,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) + if (ret < 0) + goto err_disable_clk; + ++ init_completion(&q->c); + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { +-- +2.53.0 + diff --git a/queue-6.6/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch b/queue-6.6/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch new file mode 100644 index 0000000000..d9895fe5fa --- /dev/null +++ b/queue-6.6/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch @@ -0,0 +1,55 @@ +From a527b66b1bf0a1ff49fb79be1991197fdc8271ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 11:06:41 +0800 +Subject: spi: hisi-kunpeng: prevent infinite while() loop in + hisi_spi_flush_fifo + +From: Pei Xiao + +[ Upstream commit 9f61daf2c2debe9f5cf4e1a4471e56a89a6fe45a ] + +The hisi_spi_flush_fifo()'s inner while loop that lacks any timeout +mechanism. Maybe the hardware never becomes empty, the loop will spin +forever, causing the CPU to hang. + +Fix this by adding a inner_limit based on loops_per_jiffy. The inner loop +now exits after approximately one jiffy if the FIFO remains non-empty, logs +a ratelimited warning, and breaks out of the outer loop. Additionally, add +a cpu_relax() inside the busy loop to improve power efficiency. + +Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/d834ce28172886bfaeb9c8ca00cfd9bf1c65d5a1.1773889292.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-hisi-kunpeng.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index f0a50f40a3ba1..77526f7940688 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -196,8 +196,18 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs) + unsigned long limit = loops_per_jiffy << 1; + + do { +- while (hisi_spi_rx_not_empty(hs)) ++ unsigned long inner_limit = loops_per_jiffy; ++ ++ while (hisi_spi_rx_not_empty(hs) && --inner_limit) { + readl(hs->regs + HISI_SPI_DOUT); ++ cpu_relax(); ++ } ++ ++ if (!inner_limit) { ++ dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n"); ++ break; ++ } ++ + } while (hisi_spi_busy(hs) && limit--); + } + +-- +2.53.0 + diff --git a/queue-6.6/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch b/queue-6.6/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch new file mode 100644 index 0000000000..c4d33fa251 --- /dev/null +++ b/queue-6.6/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch @@ -0,0 +1,60 @@ +From 837bb118a3661fedb2af9bffa5d22f7d0fec20ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 15:26:59 +0800 +Subject: spi: mtk-snfi: unregister ECC engine on probe failure and remove() + callback + +From: Pei Xiao + +[ Upstream commit ab00febad191d7a4400aa1c3468279fb508258d4 ] + +mtk_snand_probe() registers the on-host NAND ECC engine, but teardown was +missing from both probe unwind and remove-time cleanup. Add a devm cleanup +action after successful registration so +nand_ecc_unregister_on_host_hw_engine() runs automatically on probe +failures and during device removal. + +Fixes: 764f1b748164 ("spi: add driver for MTK SPI NAND Flash Interface") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/20263f885f1a9c9d559f95275298cd6de4b11ed5.1775546401.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-mtk-snfi.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c +index 4433a8a9299f6..22f3b22d77ad8 100644 +--- a/drivers/spi/spi-mtk-snfi.c ++++ b/drivers/spi/spi-mtk-snfi.c +@@ -1307,6 +1307,13 @@ static const struct spi_controller_mem_caps mtk_snand_mem_caps = { + .ecc = true, + }; + ++static void mtk_unregister_ecc_engine(void *data) ++{ ++ struct nand_ecc_engine *eng = data; ++ ++ nand_ecc_unregister_on_host_hw_engine(eng); ++} ++ + static irqreturn_t mtk_snand_irq(int irq, void *id) + { + struct mtk_snand *snf = id; +@@ -1487,6 +1494,13 @@ static int mtk_snand_probe(struct platform_device *pdev) + goto disable_clk; + } + ++ ret = devm_add_action_or_reset(&pdev->dev, mtk_unregister_ecc_engine, ++ &ms->ecc_eng); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "failed to add ECC unregister action\n"); ++ goto release_ecc; ++ } ++ + ctlr->num_chipselect = 1; + ctlr->mem_ops = &mtk_snand_mem_ops; + ctlr->mem_caps = &mtk_snand_mem_caps; +-- +2.53.0 + diff --git a/queue-6.6/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch b/queue-6.6/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch new file mode 100644 index 0000000000..d1367982fb --- /dev/null +++ b/queue-6.6/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch @@ -0,0 +1,61 @@ +From aac9c1f7ce7b1a6134e8401cb381b3e29d276882 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 09:29:34 +0000 +Subject: spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ + +From: John Madieu + +[ Upstream commit b4683a239a409d65f88052f5630c748a8ba070cd ] + +rockchip_spi_isr() decides whether the current interrupt was the +cs-inactive event by reading IMR: + + if (rs->cs_inactive && + readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) + ctlr->target_abort(ctlr); + +IMR is the interrupt mask register: it tells which sources are enabled, +not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables +both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true: + + if (rs->cs_inactive) + writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, + rs->regs + ROCKCHIP_SPI_IMR); + +so the IMR check is always true once cs_inactive is enabled, and every +PIO interrupt - including normal RF_FULL completions - is dispatched to +ctlr->target_abort(), aborting the transfer. The bug is reachable on +ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller +when the transfer is short enough to fall back to PIO +(rockchip_spi_can_dma() returns false below fifo_len). + +Read ISR (which is RISR masked by IMR) so the check actually reflects +which interrupt fired, and parenthesise the expression for clarity while +at it. + +Fixes: 869f2c94db92 ("spi: rockchip: Stop spi slave dma receiver when cs inactive") +Signed-off-by: John Madieu +Link: https://patch.msgid.link/20260425092936.2590132-2-john.madieu@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rockchip.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index 9e160cba1ff37..03a11aed055ee 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -352,7 +352,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + + /* When int_cs_inactive comes, spi target abort */ +- if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { ++ if (rs->cs_inactive && ++ (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) { + ctlr->target_abort(ctlr); + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); +-- +2.53.0 + diff --git a/queue-6.6/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch b/queue-6.6/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch new file mode 100644 index 0000000000..56c8cb6a8c --- /dev/null +++ b/queue-6.6/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch @@ -0,0 +1,75 @@ +From 842b21ea2b388f5b176acd27e0c5fc161b695788 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:07 +0000 +Subject: tcp: add data-race annotations around tp->data_segs_out and + tp->total_retrans + +From: Eric Dumazet + +[ Upstream commit 21e92a38cfd891538598ba8f805e0165a820d532 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e98102f4897 ("tcp: record pkts sent and retransmistted") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 8 +++++--- + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 33b724dcde6ed..8187fefa52206 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3962,9 +3962,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED, + info.tcpi_sndbuf_limited, TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT, +- tp->data_segs_out, TCP_NLA_PAD); ++ READ_ONCE(tp->data_segs_out), TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS, +- tp->total_retrans, TCP_NLA_PAD); ++ READ_ONCE(tp->total_retrans), TCP_NLA_PAD); + + rate = READ_ONCE(sk->sk_pacing_rate); + rate64 = (rate != ~0UL) ? rate : ~0ULL; +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index db8f2830c67bf..5e2e14df787d4 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1400,7 +1400,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + + if (skb->len != tcp_header_size) { + tcp_event_data_sent(tp, sk); +- tp->data_segs_out += tcp_skb_pcount(skb); ++ WRITE_ONCE(tp->data_segs_out, ++ tp->data_segs_out + tcp_skb_pcount(skb)); + tp->bytes_sent += skb->len - tcp_header_size; + } + +@@ -3347,7 +3348,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); +- tp->total_retrans += segs; ++ WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); + tp->bytes_retrans += skb->len; + + /* make sure skb->data is aligned on arches that require it +@@ -4285,7 +4286,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) + * However in this case, we are dealing with a passive fastopen + * socket thus we can change total_retrans value. + */ +- tcp_sk_rw(sk)->total_retrans++; ++ WRITE_ONCE(tcp_sk_rw(sk)->total_retrans, ++ tcp_sk_rw(sk)->total_retrans + 1); + } + trace_tcp_retransmit_synack(sk, req); + } +-- +2.53.0 + diff --git a/queue-6.6/tcp-annotate-data-races-around-tp-bytes_retrans.patch b/queue-6.6/tcp-annotate-data-races-around-tp-bytes_retrans.patch new file mode 100644 index 0000000000..4775883fc3 --- /dev/null +++ b/queue-6.6/tcp-annotate-data-races-around-tp-bytes_retrans.patch @@ -0,0 +1,53 @@ +From 4289eb1a91faf6acb0ebb4a593ae220126e8fbfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:13 +0000 +Subject: tcp: annotate data-races around tp->bytes_retrans + +From: Eric Dumazet + +[ Upstream commit 5efc7b9f7cbd43401f1af81d3d7f2be00f93390d ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: fb31c9b9f6c8 ("tcp: add data bytes retransmitted stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-9-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index c6b58bbb43c8a..2ab4b8f4d8d10 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3988,8 +3988,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, +- TCP_NLA_PAD); ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, ++ READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 1fd807236c651..ea982c3670d33 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -3350,7 +3350,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); + WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); +- tp->bytes_retrans += skb->len; ++ WRITE_ONCE(tp->bytes_retrans, tp->bytes_retrans + skb->len); + + /* make sure skb->data is aligned on arches that require it + * and check if ack-trimming & collapsing extended the headroom +-- +2.53.0 + diff --git a/queue-6.6/tcp-annotate-data-races-around-tp-bytes_sent.patch b/queue-6.6/tcp-annotate-data-races-around-tp-bytes_sent.patch new file mode 100644 index 0000000000..744904e795 --- /dev/null +++ b/queue-6.6/tcp-annotate-data-races-around-tp-bytes_sent.patch @@ -0,0 +1,52 @@ +From 928ca3d80d4aebffbae2f89721a5a7b6409779a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:12 +0000 +Subject: tcp: annotate data-races around tp->bytes_sent + +From: Eric Dumazet + +[ Upstream commit ee43e957ce2ec77b2ec47fef28f3c0df6ab01a31 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: ba113c3aa79a ("tcp: add data bytes sent stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-8-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_output.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 8187fefa52206..c6b58bbb43c8a 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3986,7 +3986,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); + +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, + TCP_NLA_PAD); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 5e2e14df787d4..1fd807236c651 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1402,7 +1402,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + tcp_event_data_sent(tp, sk); + WRITE_ONCE(tp->data_segs_out, + tp->data_segs_out + tcp_skb_pcount(skb)); +- tp->bytes_sent += skb->len - tcp_header_size; ++ WRITE_ONCE(tp->bytes_sent, ++ tp->bytes_sent + skb->len - tcp_header_size); + } + + if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) +-- +2.53.0 + diff --git a/queue-6.6/tcp-annotate-data-races-around-tp-dsack_dups.patch b/queue-6.6/tcp-annotate-data-races-around-tp-dsack_dups.patch new file mode 100644 index 0000000000..1dadd64e0a --- /dev/null +++ b/queue-6.6/tcp-annotate-data-races-around-tp-dsack_dups.patch @@ -0,0 +1,51 @@ +From 1830c81be917c92ddf585ca13e6f862c0e94fcf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:14 +0000 +Subject: tcp: annotate data-races around tp->dsack_dups + +From: Eric Dumazet + +[ Upstream commit a984705ca88b976bf1087978fd98b7f3993da88c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e10b6554ff2 ("tcp: add dsack blocks received stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-10-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_input.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 2ab4b8f4d8d10..51e71407f4b89 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3990,7 +3990,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); +- nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); ++ nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 359d36be04829..eb1bf58634741 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1041,7 +1041,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq, + else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq) + state->flag |= FLAG_DSACK_TLP; + +- tp->dsack_dups += dup_segs; ++ WRITE_ONCE(tp->dsack_dups, tp->dsack_dups + dup_segs); + /* Skip the DSACK if dup segs weren't retransmitted by sender */ + if (tp->dsack_dups > tp->total_retrans) + return 0; +-- +2.53.0 + diff --git a/queue-6.6/tcp-annotate-data-races-around-tp-plb_rehash.patch b/queue-6.6/tcp-annotate-data-races-around-tp-plb_rehash.patch new file mode 100644 index 0000000000..6cb2e2efdf --- /dev/null +++ b/queue-6.6/tcp-annotate-data-races-around-tp-plb_rehash.patch @@ -0,0 +1,52 @@ +From 02bd237a475ed708e8dd1313b1a7d2c3bdef4f59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:19 +0000 +Subject: tcp: annotate data-races around tp->plb_rehash + +From: Eric Dumazet + +[ Upstream commit 9e89b9d03a2d2e30dcca166d5af52f9a8eceab25 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 29c1c44646ae ("tcp: add u32 counter in tcp_sock and an SNMP counter for PLB") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-15-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + net/ipv4/tcp_plb.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index a8cba4dc7df5c..5b1fbb0ca2ff6 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4003,7 +4003,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u8(stats, TCP_NLA_TTL, + tcp_skb_ttl_or_hop_limit(ack_skb)); + +- nla_put_u32(stats, TCP_NLA_REHASH, tp->plb_rehash + tp->timeout_rehash); ++ nla_put_u32(stats, TCP_NLA_REHASH, ++ READ_ONCE(tp->plb_rehash) + READ_ONCE(tp->timeout_rehash)); + return stats; + } + +diff --git a/net/ipv4/tcp_plb.c b/net/ipv4/tcp_plb.c +index 4bcf7eff95e39..b7f9b60d8991f 100644 +--- a/net/ipv4/tcp_plb.c ++++ b/net/ipv4/tcp_plb.c +@@ -79,7 +79,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb) + + sk_rethink_txhash(sk); + plb->consec_cong_rounds = 0; +- tcp_sk(sk)->plb_rehash++; ++ WRITE_ONCE(tcp_sk(sk)->plb_rehash, tcp_sk(sk)->plb_rehash + 1); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPLBREHASH); + } + EXPORT_SYMBOL_GPL(tcp_plb_check_rehash); +-- +2.53.0 + diff --git a/queue-6.6/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch b/queue-6.6/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch new file mode 100644 index 0000000000..d49e31a317 --- /dev/null +++ b/queue-6.6/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch @@ -0,0 +1,40 @@ +From d82988e1654142b0dd94b20d774d724f2943553c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:18 +0000 +Subject: tcp: annotate data-races around (tp->write_seq - tp->snd_nxt) + +From: Eric Dumazet + +[ Upstream commit 3a63b3d160560ef51e43fb4c880a5cde8078053c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() annotations to keep KCSAN happy. + +WRITE_ONCE() annotations are already present. + +Fixes: e08ab0b377a1 ("tcp: add bytes not sent to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-14-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 51e71407f4b89..a8cba4dc7df5c 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3995,7 +3995,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +- max_t(int, 0, tp->write_seq - tp->snd_nxt)); ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt))); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, + TCP_NLA_PAD); + if (ack_skb) +-- +2.53.0 + diff --git a/queue-6.6/thermal-drivers-spear-fix-error-condition-for-readin.patch b/queue-6.6/thermal-drivers-spear-fix-error-condition-for-readin.patch new file mode 100644 index 0000000000..b8a0e9f933 --- /dev/null +++ b/queue-6.6/thermal-drivers-spear-fix-error-condition-for-readin.patch @@ -0,0 +1,42 @@ +From 8cc3bc4f1eed307e42d2dac2236a0a4d469e7b82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:35:24 +0530 +Subject: thermal/drivers/spear: Fix error condition for reading + st,thermal-flags + +From: Gopi Krishna Menon + +[ Upstream commit da2c4f332a0504d9c284e7626a561d343c8d6f57 ] + +of_property_read_u32 returns 0 on success. The current check returns +-EINVAL if the property is read successfully. + +Fix the check by removing ! from of_property_read_u32 + +Fixes: b9c7aff481f1 ("drivers/thermal/spear_thermal.c: add Device Tree probing capability") +Signed-off-by: Gopi Krishna Menon +Signed-off-by: Daniel Lezcano +Suggested-by: Daniel Baluta +Reviewed-by: Lukasz Luba +Link: https://patch.msgid.link/20260327090526.59330-1-krishnagopi487@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/thermal/spear_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c +index 96d99289799a1..a935002c2bdbe 100644 +--- a/drivers/thermal/spear_thermal.c ++++ b/drivers/thermal/spear_thermal.c +@@ -93,7 +93,7 @@ static int spear_thermal_probe(struct platform_device *pdev) + struct device_node *np = pdev->dev.of_node; + int ret = 0, val; + +- if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) { ++ if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) { + dev_err(&pdev->dev, "Failed: DT Pdata not passed\n"); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-6.6/tipc-fix-double-free-in-tipc_buf_append.patch b/queue-6.6/tipc-fix-double-free-in-tipc_buf_append.patch new file mode 100644 index 0000000000..dbef953ee4 --- /dev/null +++ b/queue-6.6/tipc-fix-double-free-in-tipc_buf_append.patch @@ -0,0 +1,60 @@ +From 066764c0ec6d6d92780a8752b78d146124767481 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 13:45:26 +0100 +Subject: tipc: fix double-free in tipc_buf_append() + +From: Lee Jones + +[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ] + +tipc_msg_validate() can potentially reallocate the skb it is validating, +freeing the old one. In tipc_buf_append(), it was being called with a +pointer to a local variable which was a copy of the caller's skb +pointer. + +If the skb was reallocated and validation subsequently failed, the error +handling path would free the original skb pointer, which had already +been freed, leading to double-free. + +Fix this by checking if head now points to a newly allocated reassembled +skb. If it does, reassign *headbuf for later freeing operations. + +Fixes: d618d09a68e4 ("tipc: enforce valid ratio between skb truesize and contents") +Suggested-by: Tung Nguyen +Signed-off-by: Lee Jones +Reviewed-by: Tung Nguyen +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/msg.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/net/tipc/msg.c b/net/tipc/msg.c +index 76284fc538ebd..b0bba0feef564 100644 +--- a/net/tipc/msg.c ++++ b/net/tipc/msg.c +@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) + + if (fragid == LAST_FRAGMENT) { + TIPC_SKB_CB(head)->validated = 0; +- if (unlikely(!tipc_msg_validate(&head))) ++ ++ /* If the reassembled skb has been freed in ++ * tipc_msg_validate() because of an invalid truesize, ++ * then head will point to a newly allocated reassembled ++ * skb, while *headbuf points to freed reassembled skb. ++ * In such cases, correct *headbuf for freeing the newly ++ * allocated reassembled skb later. ++ */ ++ if (unlikely(!tipc_msg_validate(&head))) { ++ if (head != *headbuf) ++ *headbuf = head; + goto err; ++ } ++ + *buf = head; + TIPC_SKB_CB(head)->tail = NULL; + *headbuf = NULL; +-- +2.53.0 + diff --git a/queue-6.6/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch b/queue-6.6/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch new file mode 100644 index 0000000000..c24c7f75a2 --- /dev/null +++ b/queue-6.6/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch @@ -0,0 +1,69 @@ +From c01fd9be32a99dae449e456dc3e428e13af5f684 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 06:25:09 -0700 +Subject: tracing: branch: Fix inverted check on stat tracer registration + +From: Breno Leitao + +[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ] + +init_annotated_branch_stats() and all_annotated_branch_stats() check the +return value of register_stat_tracer() with "if (!ret)", but +register_stat_tracer() returns 0 on success and a negative errno on +failure. The inverted check causes the warning to be printed on every +successful registration, e.g.: + + Warning: could not register annotated branches stats + +while leaving real failures silent. The initcall also returned a +hard-coded 1 instead of the actual error. + +Invert the check and propagate ret so that the warning fires on real +errors and the initcall reports the correct status. + +Cc: Mathieu Desnoyers +Cc: Ingo Molnar +Cc: Frederic Weisbecker +Link: https://patch.msgid.link/20260420-tracing-v1-1-d8f4cd0d6af1@debian.org +Fixes: 002bb86d8d42 ("tracing/ftrace: separate events tracing and stats tracing engine") +Signed-off-by: Breno Leitao +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_branch.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c +index e47fdb4c92fbc..30f72e0ecb5d4 100644 +--- a/kernel/trace/trace_branch.c ++++ b/kernel/trace/trace_branch.c +@@ -379,10 +379,10 @@ __init static int init_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&annotated_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "annotated branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +@@ -444,10 +444,10 @@ __init static int all_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&all_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "all branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch b/queue-6.6/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch new file mode 100644 index 0000000000..2d8821c211 --- /dev/null +++ b/queue-6.6/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch @@ -0,0 +1,56 @@ +From 73a47a5f432119c7c802aa0b6287305f1664f9ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 19:22:23 +0800 +Subject: tracing: Rebuild full_name on each hist_field_name() call + +From: Pengpeng Hou + +[ Upstream commit 5ec1d1e97de134beed3a5b08235a60fc1c51af96 ] + +hist_field_name() uses a static MAX_FILTER_STR_VAL buffer for fully +qualified variable-reference names, but it currently appends into that +buffer with strcat() without rebuilding it first. As a result, repeated +calls append a new "system.event.field" name onto the previous one, +which can eventually run past the end of full_name. + +Build the name with snprintf() on each call and return NULL if the fully +qualified name does not fit in MAX_FILTER_STR_VAL. + +Link: https://patch.msgid.link/20260401112224.85582-1-pengpeng@iscas.ac.cn +Fixes: 067fe038e70f ("tracing: Add variable reference handling to hist triggers") +Reviewed-by: Tom Zanussi +Tested-by: Tom Zanussi +Signed-off-by: Pengpeng Hou +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 19b3d388fbc69..597f47397c726 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -1349,12 +1349,14 @@ static const char *hist_field_name(struct hist_field *field, + field->flags & HIST_FIELD_FL_VAR_REF) { + if (field->system) { + static char full_name[MAX_FILTER_STR_VAL]; ++ int len; ++ ++ len = snprintf(full_name, sizeof(full_name), "%s.%s.%s", ++ field->system, field->event_name, ++ field->name); ++ if (len >= sizeof(full_name)) ++ return NULL; + +- strcat(full_name, field->system); +- strcat(full_name, "."); +- strcat(full_name, field->event_name); +- strcat(full_name, "."); +- strcat(full_name, field->name); + field_name = full_name; + } else + field_name = field->name; +-- +2.53.0 + diff --git a/queue-6.6/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch b/queue-6.6/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch new file mode 100644 index 0000000000..0e97f0ad40 --- /dev/null +++ b/queue-6.6/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch @@ -0,0 +1,50 @@ +From 2f59b13c2c52b1e4bac569af3f8072e7e7ca54c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 23:29:37 -0800 +Subject: tty: hvc_iucv: fix off-by-one in number of supported devices + +From: Randy Dunlap + +[ Upstream commit f2a880e802ad12d1e38039d1334fb1475d0f5241 ] + +MAX_HVC_IUCV_LINES == HVC_ALLOC_TTY_ADAPTERS == 8. +This is the number of entries in: + static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; + +Sometimes hvc_iucv_table[] is limited by: +(a) if (num > hvc_iucv_devices) // for error detection +or +(b) for (i = 0; i < hvc_iucv_devices; i++) // in 2 places +(so these 2 don't agree; second one appears to be correct to me.) + +hvc_iucv_devices can be 0..8. This is a counter. +(c) if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + +If hvc_iucv_devices == 8, (a) allows the code to access hvc_iucv_table[8]. +Oops. + +Fixes: 44a01d5ba8a4 ("[S390] s390/hvc_console: z/VM IUCV hypervisor console support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260130072939.1535869-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index 543f35ddf523c..26953f0daa9fc 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if (num > hvc_iucv_devices) ++ if (num >= hvc_iucv_devices) + return NULL; + return hvc_iucv_table[num]; + } +-- +2.53.0 + diff --git a/queue-6.6/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch b/queue-6.6/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch new file mode 100644 index 0000000000..512863c86c --- /dev/null +++ b/queue-6.6/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch @@ -0,0 +1,91 @@ +From ef0bdf096cd8718cfb6d6747fb53fe7819f2b0cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 11:39:59 -0800 +Subject: unshare: fix nsproxy leak in ksys_unshare() on set_cred_ucounts() + failure + +From: Michal Grzedzicki + +[ Upstream commit a98621a0f187a934c115dcfe79a49520ae892111 ] + +When set_cred_ucounts() fails in ksys_unshare() new_nsproxy is leaked. + +Let's call put_nsproxy() if that happens. + +Link: https://lkml.kernel.org/r/20260213193959.2556730-1-mge@meta.com +Fixes: 905ae01c4ae2 ("Add a reference to ucounts for each cred") +Signed-off-by: Michal Grzedzicki +Reviewed-by: Andrew Morton +Cc: Alexey Gladkov (Intel) +Cc: Ben Segall +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: "Liam R. Howlett" +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index c65a70581af73..e280f02b6446a 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -3443,11 +3443,10 @@ int ksys_unshare(unsigned long unshare_flags) + new_cred, new_fs); + if (err) + goto bad_unshare_cleanup_cred; +- + if (new_cred) { + err = set_cred_ucounts(new_cred); + if (err) +- goto bad_unshare_cleanup_cred; ++ goto bad_unshare_cleanup_nsproxy; + } + + if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { +@@ -3463,8 +3462,10 @@ int ksys_unshare(unsigned long unshare_flags) + shm_init_task(current); + } + +- if (new_nsproxy) ++ if (new_nsproxy) { + switch_task_namespaces(current, new_nsproxy); ++ new_nsproxy = NULL; ++ } + + task_lock(current); + +@@ -3493,13 +3494,15 @@ int ksys_unshare(unsigned long unshare_flags) + + perf_event_namespaces(current); + ++bad_unshare_cleanup_nsproxy: ++ if (new_nsproxy) ++ put_nsproxy(new_nsproxy); + bad_unshare_cleanup_cred: + if (new_cred) + put_cred(new_cred); + bad_unshare_cleanup_fd: + if (new_fd) + put_files_struct(new_fd); +- + bad_unshare_cleanup_fs: + if (new_fs) + free_fs_struct(new_fs); +-- +2.53.0 + diff --git a/queue-6.6/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch b/queue-6.6/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch new file mode 100644 index 0000000000..ef78d81d46 --- /dev/null +++ b/queue-6.6/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch @@ -0,0 +1,64 @@ +From ce52a09cc2fa6384f5d6113f2ee8d9251c778e1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 02:30:24 +0000 +Subject: vhost_net: fix sleeping with preempt-disabled in + vhost_net_busy_poll() + +From: Kohei Enju + +[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ] + +syzbot reported "sleeping function called from invalid context" in +vhost_net_busy_poll(). + +Commit 030881372460 ("vhost_net: basic polling support") introduced a +busy-poll loop and preempt_{disable,enable}() around it, where each +iteration calls a sleepable function inside the loop. + +The purpose of disabling preemption was to keep local_clock()-based +timeout accounting on a single CPU, rather than as a requirement of +busy-poll itself: + +https://lore.kernel.org/1448435489-5949-4-git-send-email-jasowang@redhat.com + +From this perspective, migrate_disable() is sufficient here, so replace +preempt_disable() with migrate_disable(), avoiding sleepable accesses +from a preempt-disabled context. + +Fixes: 030881372460 ("vhost_net: basic polling support") +Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/ +Signed-off-by: Kohei Enju +Acked-by: Michael S. Tsirkin +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/vhost/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index 5ad237d77a9a9..b26d9a8e4e055 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -547,7 +547,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + busyloop_timeout = poll_rx ? rvq->busyloop_timeout: + tvq->busyloop_timeout; + +- preempt_disable(); ++ migrate_disable(); + endtime = busy_clock() + busyloop_timeout; + + while (vhost_can_busy_poll(endtime)) { +@@ -564,7 +564,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + cpu_relax(); + } + +- preempt_enable(); ++ migrate_enable(); + + if (poll_rx || sock_has_rx_data(sock)) + vhost_net_busy_poll_try_queue(net, vq); +-- +2.53.0 + diff --git a/queue-6.6/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch b/queue-6.6/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch new file mode 100644 index 0000000000..28fa324050 --- /dev/null +++ b/queue-6.6/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch @@ -0,0 +1,115 @@ +From 26d922f93518e8582983468e7b814ff8d76cf866 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 09:36:07 +0300 +Subject: vrf: Fix a potential NPD when removing a port from a VRF + +From: Ido Schimmel + +[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ] + +RCU readers that identified a net device as a VRF port using +netif_is_l3_slave() assume that a subsequent call to +netdev_master_upper_dev_get_rcu() will return a VRF device. They then +continue to dereference its l3mdev operations. + +This assumption is not always correct and can result in a NPD [1]. There +is no RCU synchronization when removing a port from a VRF, so it is +possible for an RCU reader to see a new master device (e.g., a bridge) +that does not have l3mdev operations. + +Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE +flag. Skip this synchronization when a net device is removed from a VRF +as part of its deletion and when the VRF device itself is deleted. In +the latter case an RCU grace period will pass by the time RTNL is +released. + +[1] +BUG: kernel NULL pointer dereference, address: 0000000000000000 +[...] +RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) +[...] +Call Trace: + +l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) +__inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) +inet_bind_sk (net/ipv4/af_inet.c:469) +__sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) +__x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Fixes: fdeea7be88b1 ("net: vrf: Set slave's private flag before linking") +Reported-by: Haoze Xie +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/netdev/20260419145332.3988923-1-n05ec@lzu.edu.cn/ +Signed-off-by: Ido Schimmel +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260423063607.1208202-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vrf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index 64114e98d75d0..9f7b05a010519 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -1126,6 +1126,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + + err: + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ synchronize_net(); + return ret; + } + +@@ -1145,10 +1146,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + } + + /* inverse of do_vrf_add_slave */ +-static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) ++static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, ++ bool needs_sync) + { + netdev_upper_dev_unlink(port_dev, dev); + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ /* Make sure that concurrent RCU readers that identified the device ++ * as a VRF port see a VRF master or no master at all. ++ */ ++ if (needs_sync) ++ synchronize_net(); + + cycle_netdev(port_dev, NULL); + +@@ -1157,7 +1164,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + + static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + { +- return do_vrf_del_slave(dev, port_dev); ++ return do_vrf_del_slave(dev, port_dev, true); + } + + static void vrf_dev_uninit(struct net_device *dev) +@@ -1714,7 +1721,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) + struct list_head *iter; + + netdev_for_each_lower_dev(dev, port_dev, iter) +- vrf_del_slave(dev, port_dev); ++ do_vrf_del_slave(dev, port_dev, false); + + vrf_map_unregister_dev(dev); + +@@ -1845,7 +1852,7 @@ static int vrf_device_event(struct notifier_block *unused, + goto out; + + vrf_dev = netdev_master_upper_dev_get(dev); +- vrf_del_slave(vrf_dev, dev); ++ do_vrf_del_slave(vrf_dev, dev, false); + } + out: + return NOTIFY_DONE; +-- +2.53.0 + diff --git a/queue-6.6/wifi-brcmfmac-fix-error-pointer-dereference.patch b/queue-6.6/wifi-brcmfmac-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..ccdefb6504 --- /dev/null +++ b/queue-6.6/wifi-brcmfmac-fix-error-pointer-dereference.patch @@ -0,0 +1,80 @@ +From 7eedf5527469b8b2672cd92f7767709d3aa4accd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 20:30:43 -0600 +Subject: wifi: brcmfmac: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit dd8592fc6007a451c3e4b9025de365e39de8178a ] + +The function brcmf_chip_add_core() can return an error pointer and is +not checked. Add checks for error pointer. + +Detected by Smatch: +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1010 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1013 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1016 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1019 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1022 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +Fixes: cb7cf7be9eba7 ("brcmfmac: make chip related functions host interface independent") +Signed-off-by: Ethan Tidmore +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260217023043.73631-1-ethantidmore06@gmail.com +[add missing wifi: prefix] +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index 2ef92ef25517e..4dbb1898f3065 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -1006,18 +1006,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + + core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, + SI_ENUM_BASE_DEFAULT, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, + BCM4329_CORE_BUS_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, + BCM4329_CORE_SOCRAM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, + BCM4329_CORE_ARM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + + core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + } else if (socitype == SOCI_AI) { + ci->iscoreup = brcmf_chip_ai_iscoreup; +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt7615-fix-use_cts_prot-support.patch b/queue-6.6/wifi-mt76-mt7615-fix-use_cts_prot-support.patch new file mode 100644 index 0000000000..33b58e621b --- /dev/null +++ b/queue-6.6/wifi-mt76-mt7615-fix-use_cts_prot-support.patch @@ -0,0 +1,173 @@ +From 261d1d5b175830c5484c9fef4aaef642c012f97a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 09:41:56 -0800 +Subject: wifi: mt76: mt7615: fix use_cts_prot support + +From: Ryder Lee + +[ Upstream commit 1974a67d9b65c29a0a9426e32e8cd8c056de48b7 ] + +Driver should not directly write WTBL to prevent overwritten issues. + +With this fix, when driver needs to adjust its behavior for compatibility, +especially concerning older 11g/n devices, by enabling or disabling CTS +protection frames, often for hidden SSIDs or to manage legacy clients. + +Fixes: e34235ccc5e3 ("wifi: mt76: mt7615: enable use_cts_prot support") +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/edb87088b0111b32fafc6c4179f54a5286dd37d8.1768879119.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7615/mac.c | 15 ------ + .../net/wireless/mediatek/mt76/mt7615/main.c | 7 +-- + .../net/wireless/mediatek/mt76/mt7615/mcu.c | 47 +++++++++++++++++++ + .../wireless/mediatek/mt76/mt7615/mt7615.h | 5 +- + .../net/wireless/mediatek/mt76/mt7615/regs.h | 2 - + 5 files changed, 53 insertions(+), 23 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +index 7ba789834e8df..1e473f490b4bd 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +@@ -1174,21 +1174,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, + } + EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); + +-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, +- struct ieee80211_vif *vif, bool enable) +-{ +- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; +- u32 addr; +- +- addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4; +- +- if (enable) +- mt76_set(dev, addr, MT_WTBL_W3_RTS); +- else +- mt76_clear(dev, addr, MT_WTBL_W3_RTS); +-} +-EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); +- + static int + mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c +index dab16b5fc3861..b908ccfa48778 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c +@@ -597,9 +597,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, + } + } + +- if (changed & BSS_CHANGED_ERP_CTS_PROT) +- mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot); +- + if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { + mt7615_mcu_add_bss_info(phy, vif, NULL, true); + mt7615_mcu_sta_add(phy, vif, NULL, true); +@@ -612,6 +609,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, + BSS_CHANGED_BEACON_ENABLED)) + mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); + ++ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) ++ mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode, ++ info->use_cts_prot); ++ + if (changed & BSS_CHANGED_PS) + mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +index 94adb22f8570f..d5071981014ee 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +@@ -2560,3 +2560,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, + return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), + &req, sizeof(req), false); + } ++ ++int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot) ++{ ++ struct mt7615_dev *dev = phy->dev; ++ struct { ++ u8 prot_idx; ++ u8 band; ++ u8 rsv[2]; ++ ++ bool long_nav; ++ bool prot_mm; ++ bool prot_gf; ++ bool prot_bw40; ++ bool prot_rifs; ++ bool prot_bw80; ++ bool prot_bw160; ++ u8 prot_erp_mask; ++ } __packed req = { ++ .prot_idx = 0x2, ++ .band = phy != &dev->phy, ++ }; ++ ++ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: ++ req.prot_mm = true; ++ req.prot_gf = true; ++ fallthrough; ++ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: ++ req.prot_bw40 = true; ++ break; ++ } ++ ++ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) ++ req.prot_gf = true; ++ ++ if (use_cts_prot) { ++ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; ++ u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; ++ ++ req.prot_erp_mask = BIT(i); ++ } ++ ++ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req, ++ sizeof(req), true); ++} +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +index fa83b255e180c..39388acfb94ba 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +@@ -466,8 +466,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy); + void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); + void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); + void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); +-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, +- struct ieee80211_vif *vif, bool enable); + void mt7615_mac_sta_poll(struct mt7615_dev *dev); + int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, +@@ -522,7 +520,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); + int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); + int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); + int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); +- ++int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot); + int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +index 806b3887c541c..9e6d55c91b269 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +@@ -455,8 +455,6 @@ enum mt7615_reg_base { + #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) + #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) + +-#define MT_WTBL_W3_RTS BIT(22) +- + #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) + #define MT_WTBL_W5_SHORT_GI_20 BIT(8) + #define MT_WTBL_W5_SHORT_GI_40 BIT(9) +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch b/queue-6.6/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch new file mode 100644 index 0000000000..3d69e68e22 --- /dev/null +++ b/queue-6.6/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch @@ -0,0 +1,53 @@ +From 5fda1fbcba5f24890d88a0ca2ede20263784e5b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 22:57:59 +0800 +Subject: wifi: mt76: mt7915: fix use-after-free bugs in mt7915_mac_dump_work() + +From: Duoming Zhou + +[ Upstream commit 1146d0946b5358fad24812bd39d68f31cd40cc34 ] + +When the mt7915 pci chip is detaching, the mt7915_crash_data is +released in mt7915_coredump_unregister(). However, the work item +dump_work may still be running or pending, leading to UAF bugs +when the already freed crash_data is dereferenced again in +mt7915_mac_dump_work(). + +The race condition can occur as follows: + +CPU 0 (removal path) | CPU 1 (workqueue) +mt7915_pci_remove() | mt7915_sys_recovery_set() + mt7915_unregister_device() | mt7915_reset() + mt7915_coredump_unregister() | queue_work() + vfree(dev->coredump.crash_data) | mt7915_mac_dump_work() + | crash_data-> // UAF + +Fix this by ensuring dump_work is properly canceled before +the crash_data is deallocated. Add cancel_work_sync() in +mt7915_unregister_device() to synchronize with any pending +or executing dump work. + +Fixes: 4dbcb9125cc3 ("wifi: mt76: mt7915: enable coredump support") +Signed-off-by: Duoming Zhou +Link: https://patch.msgid.link/20260130145759.84272-1-duoming@zju.edu.cn +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +index e9068718b3d1f..529a3640944b5 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -1254,6 +1254,7 @@ int mt7915_register_device(struct mt7915_dev *dev) + + void mt7915_unregister_device(struct mt7915_dev *dev) + { ++ cancel_work_sync(&dev->dump_work); + mt7915_unregister_ext_phy(dev); + mt7915_coredump_unregister(dev); + mt7915_unregister_thermal(&dev->phy); +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt7915-fix-use_cts_prot-support.patch b/queue-6.6/wifi-mt76-mt7915-fix-use_cts_prot-support.patch new file mode 100644 index 0000000000..afcc570c0c --- /dev/null +++ b/queue-6.6/wifi-mt76-mt7915-fix-use_cts_prot-support.patch @@ -0,0 +1,195 @@ +From 0bd75c50443b9a929ef2f6e071a5db053a24ad8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 09:41:57 -0800 +Subject: wifi: mt76: mt7915: fix use_cts_prot support + +From: Ryder Lee + +[ Upstream commit 8b2c26562b95c6397e132d21f2bd3d73aaee0c0a ] + +With this fix, when driver needs to adjust its behavior for compatibility, +especially concerning older 11g/n devices, by enabling or disabling CTS +protection frames, often for hidden SSIDs or to manage legacy clients. + +Fixes: 150b91419d3d ("wifi: mt76: mt7915: enable use_cts_prot support") +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/eb8db4d0bf1c89b7486e89facb788ae3e510dd8b.1768879119.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7915/mac.c | 13 ---- + .../net/wireless/mediatek/mt76/mt7915/main.c | 7 ++- + .../net/wireless/mediatek/mt76/mt7915/mcu.c | 62 +++++++++++++++++++ + .../net/wireless/mediatek/mt76/mt7915/mcu.h | 11 ++++ + .../wireless/mediatek/mt76/mt7915/mt7915.h | 4 ++ + 5 files changed, 81 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +index 92d7dc8e3cc55..e2983dbf05a90 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +@@ -228,19 +228,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) + rcu_read_unlock(); + } + +-void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, +- struct ieee80211_vif *vif, bool enable) +-{ +- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; +- u32 addr; +- +- addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); +- if (enable) +- mt76_set(dev, addr, BIT(5)); +- else +- mt76_clear(dev, addr, BIT(5)); +-} +- + static void + mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, + struct mt7915_sta *msta, struct sk_buff *skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +index c312a0fa199ae..bad92fa4c8fc6 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +@@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw) + if (ret) + goto out; + +- ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, ++ ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES, + phy->mt76->band_idx); + if (ret) + goto out; +@@ -623,8 +623,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + if (set_sta == 1) + mt7915_mcu_add_sta(dev, vif, NULL, true); + +- if (changed & BSS_CHANGED_ERP_CTS_PROT) +- mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); ++ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) ++ mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode, ++ info->use_cts_prot); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +index fae9ec98da3b9..f826089396e48 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -3730,6 +3730,68 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, + return ret; + } + ++int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot) ++{ ++ struct mt7915_dev *dev = phy->dev; ++ int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot); ++ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; ++ struct bss_info_prot *prot; ++ struct sk_buff *skb; ++ struct tlv *tlv; ++ enum { ++ PROT_NONMEMBER = BIT(1), ++ PROT_20MHZ = BIT(2), ++ PROT_NONHT_MIXED = BIT(3), ++ PROT_LEGACY_ERP = BIT(5), ++ PROT_NONGF_STA = BIT(7), ++ }; ++ u32 rts_threshold; ++ ++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, ++ NULL, len); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO, ++ sizeof(*prot)); ++ prot = (struct bss_info_prot *)tlv; ++ ++ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: ++ prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); ++ break; ++ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: ++ prot->prot_mode = cpu_to_le32(PROT_20MHZ); ++ break; ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: ++ prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); ++ break; ++ } ++ ++ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) ++ prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); ++ ++ if (use_cts_prot) ++ prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); ++ ++ /* reuse current RTS setting */ ++ rts_threshold = phy->mt76->hw->wiphy->rts_threshold; ++ if (rts_threshold == (u32)-1) ++ prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES); ++ else ++ prot->rts_len_thres = cpu_to_le32(rts_threshold); ++ ++ prot->rts_pkt_thres = 0x2; ++ ++ prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); ++ if (!prot->he_rts_thres) ++ prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); ++ ++ return mt76_mcu_skb_send_msg(&dev->mt76, skb, ++ MCU_EXT_CMD(BSS_INFO_UPDATE), true); ++} ++ + int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct cfg80211_he_bss_color *he_bss_color) + { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +index 1592b5d6751a0..acc1371a94b10 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +@@ -399,6 +399,17 @@ struct bss_info_inband_discovery { + __le16 prob_rsp_len; + } __packed __aligned(4); + ++struct bss_info_prot { ++ __le16 tag; ++ __le16 len; ++ __le32 prot_type; ++ __le32 prot_mode; ++ __le32 rts_len_thres; ++ __le16 he_rts_thres; ++ u8 rts_pkt_thres; ++ u8 rsv[5]; ++} __packed; ++ + enum { + BSS_INFO_BCN_CSA, + BSS_INFO_BCN_BCC, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +index 14d4bbeae9d63..b16c798ec2824 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +@@ -83,6 +83,8 @@ + #define MT7915_CRIT_TEMP 110 + #define MT7915_MAX_TEMP 120 + ++#define MT7915_RTS_LEN_THRES 0x92b ++ + struct mt7915_vif; + struct mt7915_sta; + struct mt7915_dfs_pulse; +@@ -453,6 +455,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v + u32 changed); + int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int enable, u32 changed); ++int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot); + int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd); + int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch b/queue-6.6/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch new file mode 100644 index 0000000000..16b7915a4f --- /dev/null +++ b/queue-6.6/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch @@ -0,0 +1,43 @@ +From b4e85ada0952ce59f06409449fee2ee225b93658 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 18:59:30 -0600 +Subject: wifi: mt76: mt7921: Reset ampdu_state state in case of failure in + mt76_connac2_tx_check_aggr() + +From: Sean Wang + +[ Upstream commit 53ffffeb9624ffab6d9a3b1da8635a23f1172b5e ] + +Reset ampdu_state if ieee80211_start_tx_ba_session() fails in +mt76_connac2_tx_check_aggr(), otherwise the driver may incorrectly +assume aggregation is active and skip future BA setup attempts. + +Fixes: 163f4d22c118 ("mt76: mt7921: add MAC support") +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20251216005930.9412-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +index 6a637d4f42360..a24b2fd3c7b82 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +@@ -1121,8 +1121,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) + return; + + wcid = (struct mt76_wcid *)sta->drv_priv; +- if (!test_and_set_bit(tid, &wcid->ampdu_state)) +- ieee80211_start_tx_ba_session(sta, tid, 0); ++ if (!test_and_set_bit(tid, &wcid->ampdu_state)) { ++ if (ieee80211_start_tx_ba_session(sta, tid, 0)) ++ clear_bit(tid, &wcid->ampdu_state); ++ } + } + EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); + +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch b/queue-6.6/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch new file mode 100644 index 0000000000..4597e5ec6a --- /dev/null +++ b/queue-6.6/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch @@ -0,0 +1,44 @@ +From efee24278a999654a2b8d6d30b5d2be2b8009a99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Oct 2025 02:08:24 -0700 +Subject: wifi: mt76: mt7996: fix FCS error flag check in RX descriptor + +From: Alok Tiwari + +[ Upstream commit d8db56142e531f060c938fa0b5175ed6c8cabb11 ] + +The mt7996 driver currently checks the MT_RXD3_NORMAL_FCS_ERR bit in +rxd1 whereas other Connac3-based drivers(mt7925) correctly check this +bit in rxd3. + +Since the MT_RXD3_NORMAL_FCS_ERR bit is defined in the fourth RX +descriptor word (rxd3), update mt7996 to use the proper descriptor +field. This change aligns mt7996 with mt7925 and the rest of the +Connac3 family. + +Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: Alok Tiwari +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251013090826.753992-1-alok.a.tiwari@oracle.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 3dd503b363ce0..9270a68e6a38d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -528,7 +528,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) + !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + +- if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) ++ if (rxd3 & MT_RXD3_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) +-- +2.53.0 + diff --git a/queue-6.6/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch b/queue-6.6/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch new file mode 100644 index 0000000000..3ec3b61e4c --- /dev/null +++ b/queue-6.6/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch @@ -0,0 +1,53 @@ +From f5d9f49754918a33096271e455c7332fbeadb887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:30 +0800 +Subject: wifi: mt76: mt7996: fix struct mt7996_mcu_uni_event + +From: StanleyYP Wang + +[ Upstream commit efbd5bf395f4e6b45a87f3835d4c2e28170c77c5 ] + +The cid field is defined as a two-byte value in the firmware. + +Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: StanleyYP Wang +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-2-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 8ab55fc705f07..9f8c312b64d75 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -204,7 +204,7 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + event = (struct mt7996_mcu_uni_event *)skb->data; + ret = le32_to_cpu(event->status); + /* skip invalid event */ +- if (mcu_cmd != event->cid) ++ if (mcu_cmd != le16_to_cpu(event->cid)) + ret = -EAGAIN; + } else { + skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +index 58504b80eae8b..fee79666fe162 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +@@ -25,8 +25,8 @@ struct mt7996_mcu_rxd { + }; + + struct mt7996_mcu_uni_event { +- u8 cid; +- u8 __rsv[3]; ++ __le16 cid; ++ u8 __rsv[2]; + __le32 status; /* 0: success, others: fail */ + } __packed; + +-- +2.53.0 + diff --git a/queue-6.6/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch b/queue-6.6/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch new file mode 100644 index 0000000000..eb093032bd --- /dev/null +++ b/queue-6.6/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch @@ -0,0 +1,49 @@ +From bfbe768aef3d79f8615f3c0a2f875e77805f26aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 09:26:25 +0000 +Subject: wifi: mwifiex: Fix memory leak in mwifiex_11n_aggregate_pkt() + +From: Zilin Guan + +[ Upstream commit 990a73dec3fdc145fef6c827c29205437d533ece ] + +In mwifiex_11n_aggregate_pkt(), skb_aggr is allocated via +mwifiex_alloc_dma_align_buf(). If mwifiex_is_ralist_valid() returns false, +the function currently returns -1 immediately without freeing the +previously allocated skb_aggr, causing a memory leak. + +Since skb_aggr has not yet been queued via skb_queue_tail(), no other +references to this memory exist. Therefore, it has to be freed locally +before returning the error. + +Fix this by calling mwifiex_write_data_complete() to free skb_aggr before +returning the error status. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") +Signed-off-by: Zilin Guan +Reviewed-by: Jeff Chen +Link: https://patch.msgid.link/20260119092625.1349934-1-zilin@seu.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +index 34b4b34276d6d..042b1fe5f0d67 100644 +--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +@@ -203,6 +203,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); ++ mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); + return -1; + } + +-- +2.53.0 + diff --git a/queue-6.6/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch b/queue-6.6/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch new file mode 100644 index 0000000000..9da0c1051e --- /dev/null +++ b/queue-6.6/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch @@ -0,0 +1,49 @@ +From b3fd2ff300479dcfa1f6315aba6dd1b34004a069 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:55:22 +0800 +Subject: wifi: rtlwifi: pci: fix possible use-after-free caused by unfinished + irq_prepare_bcn_tasklet + +From: Duoming Zhou + +[ Upstream commit 039cd522dc70151da13329a5e3ae19b1736f468a ] + +The irq_prepare_bcn_tasklet is initialized in rtl_pci_init() and +scheduled when RTL_IMR_BCNINT interrupt is triggered by hardware. +But it is never killed in rtl_pci_deinit(). When the rtlwifi card +probe fails or is being detached, the ieee80211_hw is deallocated. +However, irq_prepare_bcn_tasklet may still be running or pending, +leading to use-after-free when the freed ieee80211_hw is accessed +in _rtl_pci_prepare_bcn_tasklet(). + +Similar to irq_tasklet, add tasklet_kill() in rtl_pci_deinit() to +ensure that irq_prepare_bcn_tasklet is properly terminated before +the ieee80211_hw is released. + +The issue was identified through static analysis. + +Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") +Signed-off-by: Duoming Zhou +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260223045522.48377-1-duoming@zju.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtlwifi/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index 40112b2c37775..b978d31e47ca9 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -1675,6 +1675,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); ++ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + } + +-- +2.53.0 + diff --git a/queue-6.6/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch b/queue-6.6/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch new file mode 100644 index 0000000000..d1f296215e --- /dev/null +++ b/queue-6.6/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch @@ -0,0 +1,48 @@ +From b0680401188f03ff9b3a400405c98407868a05d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:05:53 +0300 +Subject: wifi: rtw89: phy: fix uninitialized variable access in + rtw89_phy_cfo_set_crystal_cap() + +From: Alexey Velichayshiy + +[ Upstream commit 047cddf88c611e616d49a00311d4722e46286234 ] + +In the rtw89_phy_cfo_set_crystal_cap() function, for chips other than +RTL8852A/RTL8851B, the values read by rtw89_mac_read_xtal_si() are +stored into the local variables sc_xi_val and sc_xo_val. If either +read fails, these variables remain uninitialized, they are later +used to update cfo->crystal_cap and in debug print statements. This +can lead to undefined behavior. + +Fix the issue by initializing sc_xi_val and sc_xo_val to zero, +like is implemented in vendor driver. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 8379fa611536 ("rtw89: 8852c: add write/read crystal function in CFO tracking") +Signed-off-by: Alexey Velichayshiy +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260323140613.1615574-1-a.velichayshiy@ispras.ru +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/phy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c +index 457c1dd31bf9d..3da2f623c01c6 100644 +--- a/drivers/net/wireless/realtek/rtw89/phy.c ++++ b/drivers/net/wireless/realtek/rtw89/phy.c +@@ -2434,7 +2434,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, + { + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + const struct rtw89_chip_info *chip = rtwdev->chip; +- u8 sc_xi_val, sc_xo_val; ++ u8 sc_xi_val = 0, sc_xo_val = 0; + + if (!force && cfo->crystal_cap == crystal_cap) + return; +-- +2.53.0 + diff --git a/queue-7.0/accel-amdxdna-fix-missing-newline-in-pr_err-message.patch b/queue-7.0/accel-amdxdna-fix-missing-newline-in-pr_err-message.patch new file mode 100644 index 0000000000..4c9997d32b --- /dev/null +++ b/queue-7.0/accel-amdxdna-fix-missing-newline-in-pr_err-message.patch @@ -0,0 +1,38 @@ +From 8d942e5ffe8bfabc6d5397ed09adc913c9ba2b0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 11:49:32 +0800 +Subject: accel/amdxdna: fix missing newline in pr_err message + +From: haoyu.lu + +[ Upstream commit d1c73884858cb3ce2a0f761988a6f279bff32b91 ] + +Add missing newline to pr_err message in amdxdna_mailbox.c. + +Fixes: b87f920b9344 ("accel/amdxdna: Support hardware mailbox") +Signed-off-by: haoyu.lu +Reviewed-by: Lizhi.hou +Signed-off-by: Lizhi.hou +Signed-off-by: Lizhi Hou +Link: https://patch.msgid.link/20260323034933.216-1-hechushiguitu666@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/accel/amdxdna/amdxdna_mailbox.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c +index 46d844a73a948..e681a090752df 100644 +--- a/drivers/accel/amdxdna/amdxdna_mailbox.c ++++ b/drivers/accel/amdxdna/amdxdna_mailbox.c +@@ -499,7 +499,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann, + int ret; + + if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) { +- pr_err("Ring buf size must be power of 2"); ++ pr_err("Ring buf size must be power of 2\n"); + return -EINVAL; + } + +-- +2.53.0 + diff --git a/queue-7.0/acpi-agdi-fix-missing-newline-in-error-message.patch b/queue-7.0/acpi-agdi-fix-missing-newline-in-error-message.patch new file mode 100644 index 0000000000..cc5ea84c91 --- /dev/null +++ b/queue-7.0/acpi-agdi-fix-missing-newline-in-error-message.patch @@ -0,0 +1,40 @@ +From 04af1cb188d1ff42cd37070d0153366c4f02f9f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 11:31:15 +0800 +Subject: ACPI: AGDI: fix missing newline in error message + +From: Haoyu Lu + +[ Upstream commit b178330b67abb7293b6de28b2a49d49c83962db5 ] + +Add the missing trailing newline to the dev_err() message +printed when SDEI event registration fails. + +This keeps the error output as a properly terminated log line. + +Fixes: a2a591fb76e6 ("ACPI: AGDI: Add driver for Arm Generic Diagnostic Dump and Reset device") +Reviewed-by: Ilkka Koskinen +Signed-off-by: Haoyu Lu +Reviewed-by: Hanjun Guo +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + drivers/acpi/arm64/agdi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c +index feb4b2cb4618e..0c2d9d6c160be 100644 +--- a/drivers/acpi/arm64/agdi.c ++++ b/drivers/acpi/arm64/agdi.c +@@ -36,7 +36,7 @@ static int agdi_sdei_probe(struct platform_device *pdev, + + err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev); + if (err) { +- dev_err(&pdev->dev, "Failed to register for SDEI event %d", ++ dev_err(&pdev->dev, "Failed to register for SDEI event %d\n", + adata->sdei_event); + return err; + } +-- +2.53.0 + diff --git a/queue-7.0/acpi-apei-einj-fix-einjv2-memory-error-injection.patch b/queue-7.0/acpi-apei-einj-fix-einjv2-memory-error-injection.patch new file mode 100644 index 0000000000..d7aa7301cb --- /dev/null +++ b/queue-7.0/acpi-apei-einj-fix-einjv2-memory-error-injection.patch @@ -0,0 +1,135 @@ +From 0fdff959d0f8ac276ef455fd550e8bd1026d71a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 08:02:16 -0700 +Subject: ACPI: APEI: EINJ: Fix EINJV2 memory error injection + +From: Tony Luck + +[ Upstream commit 0c00cfbcfcffa7085e4f0c7fd7a4caada4e7a90f ] + +Error types in EINJV2 use different bit positions for each flavor of +injection from legacy EINJ. + +Two issues: + + 1) The address sanity checks in einj_error_inject() were skipped for + EINJV2 injections. Noted by sashiko[1] + 2) __einj_error_trigger() failed to drop the entry of the target + physical address from the list of resources that need to be + requested. + +Add a helper function that checks if an injection is to memory and use it +to solve each of these issues. + +Note that the old test in __einj_error_trigger() checked that param2 was +not zero. This isn't needed because the sanity checks in einj_error_inject() +reject memory injections with param2 == 0. + +Fixes: b47610296d17 ("ACPI: APEI: EINJ: Enable EINJv2 error injections") +Reported-by: sashiko +Reported-by: Herman Li +Signed-off-by: Tony Luck +Tested-by: "Lai, Yi1" +Link: https://sashiko.dev/#/patchset/20260415163620.12957-1-tony.luck%40intel.com # [1] +Reviewed-by: Jiaqi Yan +Reviewed-by: Zaid Alali +Link: https://patch.msgid.link/20260421150216.11666-3-tony.luck@intel.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/apei/einj-core.c | 45 +++++++++++++++++++---------------- + 1 file changed, 25 insertions(+), 20 deletions(-) + +diff --git a/drivers/acpi/apei/einj-core.c b/drivers/acpi/apei/einj-core.c +index a9248af078f69..1f3fa2278584b 100644 +--- a/drivers/acpi/apei/einj-core.c ++++ b/drivers/acpi/apei/einj-core.c +@@ -401,8 +401,18 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region( + + return NULL; + } ++ ++static bool is_memory_injection(u32 type, u32 flags) ++{ ++ if (flags & SETWA_FLAGS_EINJV2) ++ return !!(type & ACPI_EINJV2_MEMORY); ++ if (type & ACPI5_VENDOR_BIT) ++ return !!(vendor_flags & SETWA_FLAGS_MEM); ++ return !!(type & MEM_ERROR_MASK) || !!(flags & SETWA_FLAGS_MEM); ++} ++ + /* Execute instructions in trigger error action table */ +-static int __einj_error_trigger(u64 trigger_paddr, u32 type, ++static int __einj_error_trigger(u64 trigger_paddr, u32 type, u32 flags, + u64 param1, u64 param2) + { + struct acpi_einj_trigger trigger_tab; +@@ -480,7 +490,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, + * This will cause resource conflict with regular memory. So + * remove it from trigger table resources. + */ +- if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) { ++ if ((param_extension || acpi5) && is_memory_injection(type, flags)) { + struct apei_resources addr_resources; + + apei_resources_init(&addr_resources); +@@ -660,7 +670,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, + return rc; + trigger_paddr = apei_exec_ctx_get_output(&ctx); + if (notrigger == 0) { +- rc = __einj_error_trigger(trigger_paddr, type, param1, param2); ++ rc = __einj_error_trigger(trigger_paddr, type, flags, param1, param2); + if (rc) + return rc; + } +@@ -718,35 +728,30 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, + SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2))) + return -EINVAL; + ++ /* ++ * Injections targeting a CXL 1.0/1.1 port have to be injected ++ * via the einj_cxl_rch_error_inject() path as that does the proper ++ * validation of the given RCRB base (MMIO) address. ++ */ ++ if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)) ++ return -EINVAL; ++ + /* check if type is a valid EINJv2 error type */ + if (is_v2) { + if (!(type & available_error_type_v2)) + return -EINVAL; + } +- /* +- * We need extra sanity checks for memory errors. +- * Other types leap directly to injection. +- */ + + /* ensure param1/param2 existed */ + if (!(param_extension || acpi5)) + goto inject; + +- /* ensure injection is memory related */ +- if (type & ACPI5_VENDOR_BIT) { +- if (vendor_flags != SETWA_FLAGS_MEM) +- goto inject; +- } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) { +- goto inject; +- } +- + /* +- * Injections targeting a CXL 1.0/1.1 port have to be injected +- * via the einj_cxl_rch_error_inject() path as that does the proper +- * validation of the given RCRB base (MMIO) address. ++ * We need extra sanity checks for memory errors. ++ * Other types leap directly to injection. + */ +- if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)) +- return -EINVAL; ++ if (!is_memory_injection(type, flags)) ++ goto inject; + + /* + * Disallow crazy address masks that give BIOS leeway to pick +-- +2.53.0 + diff --git a/queue-7.0/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch b/queue-7.0/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch new file mode 100644 index 0000000000..f9a994d13f --- /dev/null +++ b/queue-7.0/acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch @@ -0,0 +1,145 @@ +From cbc5e17492dd529f3f55cea3eea5e7f570411323 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:28:15 +0100 +Subject: ACPI: x86: cmos_rtc: Clean up address space handler driver + +From: Rafael J. Wysocki + +[ Upstream commit ba0b236736dde4059bdcb8e99beaa50d6e5b6e7e ] + +Make multiple changes that do not alter functionality to the CMOS RTC +ACPI address space handler driver, including the following: + + - Drop the unused .detach() callback from cmos_rtc_handler. + + - Rename acpi_cmos_rtc_attach_handler() to acpi_cmos_rtc_attach(). + + - Rearrange acpi_cmos_rtc_space_handler() to reduce the number of + redundant checks and make white space follow the coding style. + + - Adjust an error message in acpi_install_cmos_rtc_space_handler() + and make the white space follow the coding style. + + - Rearrange acpi_remove_cmos_rtc_space_handler() and adjust an error + message in it. + +No intentional functional impact. + +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/5094429.31r3eYUQgx@rafael.j.wysocki +Stable-dep-of: 6cee29ad9d7e ("ACPI: x86: cmos_rtc: Improve coordination with ACPI TAD driver") +Signed-off-by: Sasha Levin +--- + drivers/acpi/x86/cmos_rtc.c | 61 +++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 29 deletions(-) + +diff --git a/drivers/acpi/x86/cmos_rtc.c b/drivers/acpi/x86/cmos_rtc.c +index 51643ff6fe5fc..977234da9fc11 100644 +--- a/drivers/acpi/x86/cmos_rtc.c ++++ b/drivers/acpi/x86/cmos_rtc.c +@@ -24,31 +24,35 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + {} + }; + +-static acpi_status +-acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, +- u32 bits, u64 *value64, +- void *handler_context, void *region_context) ++static acpi_status acpi_cmos_rtc_space_handler(u32 function, ++ acpi_physical_address address, ++ u32 bits, u64 *value64, ++ void *handler_context, ++ void *region_context) + { +- int i; ++ unsigned int i, bytes = DIV_ROUND_UP(bits, 8); + u8 *value = (u8 *)value64; + + if (address > 0xff || !value64) + return AE_BAD_PARAMETER; + +- if (function != ACPI_WRITE && function != ACPI_READ) +- return AE_BAD_PARAMETER; ++ guard(spinlock_irq)(&rtc_lock); ++ ++ if (function == ACPI_WRITE) { ++ for (i = 0; i < bytes; i++, address++, value++) ++ CMOS_WRITE(*value, address); + +- spin_lock_irq(&rtc_lock); ++ return AE_OK; ++ } + +- for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) +- if (function == ACPI_READ) ++ if (function == ACPI_READ) { ++ for (i = 0; i < bytes; i++, address++, value++) + *value = CMOS_READ(address); +- else +- CMOS_WRITE(*value, address); + +- spin_unlock_irq(&rtc_lock); ++ return AE_OK; ++ } + +- return AE_OK; ++ return AE_BAD_PARAMETER; + } + + int acpi_install_cmos_rtc_space_handler(acpi_handle handle) +@@ -56,11 +60,11 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + acpi_status status; + + status = acpi_install_address_space_handler(handle, +- ACPI_ADR_SPACE_CMOS, +- &acpi_cmos_rtc_space_handler, +- NULL, NULL); ++ ACPI_ADR_SPACE_CMOS, ++ acpi_cmos_rtc_space_handler, ++ NULL, NULL); + if (ACPI_FAILURE(status)) { +- pr_err("Error installing CMOS-RTC region handler\n"); ++ pr_err("Failed to install CMOS-RTC address space handler\n"); + return -ENODEV; + } + +@@ -70,26 +74,25 @@ EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); + + void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) + { +- if (ACPI_FAILURE(acpi_remove_address_space_handler(handle, +- ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) +- pr_err("Error removing CMOS-RTC region handler\n"); ++ acpi_status status; ++ ++ status = acpi_remove_address_space_handler(handle, ++ ACPI_ADR_SPACE_CMOS, ++ acpi_cmos_rtc_space_handler); ++ if (ACPI_FAILURE(status)) ++ pr_err("Failed to remove CMOS-RTC address space handler\n"); + } + EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + +-static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id) ++static int acpi_cmos_rtc_attach(struct acpi_device *adev, ++ const struct acpi_device_id *id) + { + return acpi_install_cmos_rtc_space_handler(adev->handle); + } + +-static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev) +-{ +- acpi_remove_cmos_rtc_space_handler(adev->handle); +-} +- + static struct acpi_scan_handler cmos_rtc_handler = { + .ids = acpi_cmos_rtc_ids, +- .attach = acpi_cmos_rtc_attach_handler, +- .detach = acpi_cmos_rtc_detach_handler, ++ .attach = acpi_cmos_rtc_attach, + }; + + void __init acpi_cmos_rtc_init(void) +-- +2.53.0 + diff --git a/queue-7.0/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch b/queue-7.0/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch new file mode 100644 index 0000000000..c6fd576cc4 --- /dev/null +++ b/queue-7.0/acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch @@ -0,0 +1,86 @@ +From b01058e40dac14c6e069d99f334fd0a52e3ef3ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:28:57 +0100 +Subject: ACPI: x86: cmos_rtc: Improve coordination with ACPI TAD driver + +From: Rafael J. Wysocki + +[ Upstream commit 6cee29ad9d7e400d39ae0b1a54447fedcb62eecd ] + +If a CMOS RTC (PNP0B00/PNP0B01/PNP0B02) device coexists with an ACPI +TAD (timer and event alarm device, ACPI000E), the ACPI TAD driver will +attempt to install the CMOS RTC address space hanlder that has been +installed already and the TAD probing will fail. + +Avoid that by changing acpi_install_cmos_rtc_space_handler() to return +zero and acpi_remove_cmos_rtc_space_handler() to do nothing if the CMOS +RTC address space handler has been installed already. + +Fixes: 596ca52a56da ("ACPI: TAD: Install SystemCMOS address space handler for ACPI000E") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2415111.ElGaqSPkdT@rafael.j.wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/x86/cmos_rtc.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/drivers/acpi/x86/cmos_rtc.c b/drivers/acpi/x86/cmos_rtc.c +index 977234da9fc11..45db7e51cbe60 100644 +--- a/drivers/acpi/x86/cmos_rtc.c ++++ b/drivers/acpi/x86/cmos_rtc.c +@@ -24,6 +24,8 @@ static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + {} + }; + ++static bool cmos_rtc_space_handler_present __read_mostly; ++ + static acpi_status acpi_cmos_rtc_space_handler(u32 function, + acpi_physical_address address, + u32 bits, u64 *value64, +@@ -59,6 +61,9 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + { + acpi_status status; + ++ if (cmos_rtc_space_handler_present) ++ return 0; ++ + status = acpi_install_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler, +@@ -68,6 +73,8 @@ int acpi_install_cmos_rtc_space_handler(acpi_handle handle) + return -ENODEV; + } + ++ cmos_rtc_space_handler_present = true; ++ + return 1; + } + EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); +@@ -76,6 +83,9 @@ void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) + { + acpi_status status; + ++ if (cmos_rtc_space_handler_present) ++ return; ++ + status = acpi_remove_address_space_handler(handle, + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler); +@@ -87,7 +97,13 @@ EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + static int acpi_cmos_rtc_attach(struct acpi_device *adev, + const struct acpi_device_id *id) + { +- return acpi_install_cmos_rtc_space_handler(adev->handle); ++ int ret; ++ ++ ret = acpi_install_cmos_rtc_space_handler(adev->handle); ++ if (ret < 0) ++ return ret; ++ ++ return 1; + } + + static struct acpi_scan_handler cmos_rtc_handler = { +-- +2.53.0 + diff --git a/queue-7.0/acpica-provide-defines-for-einjv2-error-types.patch b/queue-7.0/acpica-provide-defines-for-einjv2-error-types.patch new file mode 100644 index 0000000000..35b96ac2c1 --- /dev/null +++ b/queue-7.0/acpica-provide-defines-for-einjv2-error-types.patch @@ -0,0 +1,45 @@ +From 890662bc965fe4d838c615d01afcb7bc2323f8f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 08:02:15 -0700 +Subject: ACPICA: Provide #defines for EINJV2 error types + +From: Tony Luck + +[ Upstream commit 1f6008538384453eb4c13a3d7ff9e37ee8aee6b9 ] + +EINJV2 defined new error types by moving the severity (correctable, +uncorrectable non-fatal, uncorrectable fatal) out of the "type". + +ACPI 6.5 introduced EINJV2 and defined a vendor defined error type +using bit 31. This was dropped in ACPI 6.6. + +Link: https://github.com/acpica/acpica/commit/e82d2d2fd145 +Signed-off-by: Tony Luck +Link: https://patch.msgid.link/20260421150216.11666-2-tony.luck@intel.com +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 0c00cfbcfcff ("ACPI: APEI: EINJ: Fix EINJV2 memory error injection") +Signed-off-by: Sasha Levin +--- + include/acpi/actbl1.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h +index 4e15583e0d254..f72e00517eb3d 100644 +--- a/include/acpi/actbl1.h ++++ b/include/acpi/actbl1.h +@@ -1386,6 +1386,12 @@ enum acpi_einj_command_status { + #define ACPI_EINJ_CXL_MEM_FATAL (1<<17) + #define ACPI_EINJ_VENDOR_DEFINED (1<<31) + ++/* EINJV2 error types from EINJV2_GET_ERROR_TYPE (ACPI 6.6) */ ++ ++#define ACPI_EINJV2_PROCESSOR (1) ++#define ACPI_EINJV2_MEMORY (1<<1) ++#define ACPI_EINJV2_PCIE (1<<2) ++ + /******************************************************************************* + * + * ERST - Error Record Serialization Table (ACPI 4.0) +-- +2.53.0 + diff --git a/queue-7.0/af_unix-drop-all-scm-attributes-for-sockmap.patch b/queue-7.0/af_unix-drop-all-scm-attributes-for-sockmap.patch new file mode 100644 index 0000000000..5cb55f10f2 --- /dev/null +++ b/queue-7.0/af_unix-drop-all-scm-attributes-for-sockmap.patch @@ -0,0 +1,179 @@ +From 05adbf67b1d3fcd1204b990fc5fbc5609f94ada0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:48:29 +0000 +Subject: af_unix: Drop all SCM attributes for SOCKMAP. + +From: Kuniyuki Iwashima + +[ Upstream commit 965dc93481d1b80d341bdd16c27b16fe197175ee ] + +SOCKMAP can hide inflight fd from AF_UNIX GC. + +When a socket in SOCKMAP receives skb with inflight fd, +sk_psock_verdict_data_ready() looks up the mapped socket and +enqueue skb to its psock->ingress_skb. + +Since neither the old nor the new GC can inspect the psock +queue, the hidden skb leaks the inflight sockets. Note that +this cannot be detected via kmemleak because inflight sockets +are linked to a global list. + +In addition, SOCKMAP redirect breaks the Tarjan-based GC's +assumption that unix_edge.successor is always alive, which +is no longer true once skb is redirected, resulting in +use-after-free below. [0] + +Moreover, SOCKMAP does not call scm_stat_del() properly, +so unix_show_fdinfo() could report an incorrect fd count. + +sk_msg_recvmsg() does not support any SCM attributes in the +first place. + +Let's drop all SCM attributes before passing skb to the +SOCKMAP layer. + +[0]: +BUG: KASAN: slab-use-after-free in unix_del_edges (net/unix/garbage.c:118 net/unix/garbage.c:181 net/unix/garbage.c:251) +Read of size 8 at addr ffff888125362670 by task kworker/56:1/496 + +CPU: 56 UID: 0 PID: 496 Comm: kworker/56:1 Not tainted 7.0.0-rc7-00263-gb9d8b856689d #3 PREEMPT(lazy) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 +Workqueue: events sk_psock_backlog +Call Trace: + + dump_stack_lvl (lib/dump_stack.c:122) + print_report (mm/kasan/report.c:379) + kasan_report (mm/kasan/report.c:597) + unix_del_edges (net/unix/garbage.c:118 net/unix/garbage.c:181 net/unix/garbage.c:251) + unix_destroy_fpl (net/unix/garbage.c:317) + unix_destruct_scm (./include/net/scm.h:80 ./include/net/scm.h:86 net/unix/af_unix.c:1976) + sk_psock_backlog (./include/linux/skbuff.h:?) + process_scheduled_works (kernel/workqueue.c:?) + worker_thread (kernel/workqueue.c:?) + kthread (kernel/kthread.c:438) + ret_from_fork (arch/x86/kernel/process.c:164) + ret_from_fork_asm (arch/x86/entry/entry_64.S:258) + + +Allocated by task 955: + kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78) + __kasan_slab_alloc (mm/kasan/common.c:369) + kmem_cache_alloc_noprof (mm/slub.c:4539) + sk_prot_alloc (net/core/sock.c:2240) + sk_alloc (net/core/sock.c:2301) + unix_create1 (net/unix/af_unix.c:1099) + unix_create (net/unix/af_unix.c:1169) + __sock_create (net/socket.c:1606) + __sys_socketpair (net/socket.c:1811) + __x64_sys_socketpair (net/socket.c:1863 net/socket.c:1860 net/socket.c:1860) + do_syscall_64 (arch/x86/entry/syscall_64.c:?) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Freed by task 496: + kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78) + kasan_save_free_info (mm/kasan/generic.c:587) + __kasan_slab_free (mm/kasan/common.c:287) + kmem_cache_free (mm/slub.c:6165) + __sk_destruct (net/core/sock.c:2282 net/core/sock.c:2384) + sk_psock_destroy (./include/net/sock.h:?) + process_scheduled_works (kernel/workqueue.c:?) + worker_thread (kernel/workqueue.c:?) + kthread (kernel/kthread.c:438) + ret_from_fork (arch/x86/kernel/process.c:164) + ret_from_fork_asm (arch/x86/entry/entry_64.S:258) + +Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()") +Fixes: 77462de14a43 ("af_unix: Add read_sock for stream socket types") +Reported-by: Xingyu Jin +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260415184830.3988432-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 35 +++++++++++++++++++++++++++-------- + 1 file changed, 27 insertions(+), 8 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 660c7c441e0db..001f6602a6659 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1964,16 +1964,19 @@ static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) + + static void unix_destruct_scm(struct sk_buff *skb) + { +- struct scm_cookie scm; ++ struct scm_cookie scm = {}; ++ ++ swap(scm.pid, UNIXCB(skb).pid); + +- memset(&scm, 0, sizeof(scm)); +- scm.pid = UNIXCB(skb).pid; + if (UNIXCB(skb).fp) + unix_detach_fds(&scm, skb); + +- /* Alas, it calls VFS */ +- /* So fscking what? fput() had been SMP-safe since the last Summer */ + scm_destroy(&scm); ++} ++ ++static void unix_wfree(struct sk_buff *skb) ++{ ++ unix_destruct_scm(skb); + sock_wfree(skb); + } + +@@ -1989,7 +1992,7 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen + if (scm->fp && send_fds) + err = unix_attach_fds(scm, skb); + +- skb->destructor = unix_destruct_scm; ++ skb->destructor = unix_wfree; + return err; + } + +@@ -2066,6 +2069,13 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb) + } + } + ++static void unix_orphan_scm(struct sock *sk, struct sk_buff *skb) ++{ ++ scm_stat_del(sk, skb); ++ unix_destruct_scm(skb); ++ skb->destructor = sock_wfree; ++} ++ + /* + * Send AF_UNIX data. + */ +@@ -2679,10 +2689,16 @@ static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor) + int err; + + mutex_lock(&u->iolock); ++ + skb = skb_recv_datagram(sk, MSG_DONTWAIT, &err); +- mutex_unlock(&u->iolock); +- if (!skb) ++ if (!skb) { ++ mutex_unlock(&u->iolock); + return err; ++ } ++ ++ unix_orphan_scm(sk, skb); ++ ++ mutex_unlock(&u->iolock); + + return recv_actor(sk, skb); + } +@@ -2882,6 +2898,9 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor) + #endif + + spin_unlock(&queue->lock); ++ ++ unix_orphan_scm(sk, skb); ++ + mutex_unlock(&u->iolock); + + return recv_actor(sk, skb); +-- +2.53.0 + diff --git a/queue-7.0/alsa-core-validate-compress-device-numbers-without-d.patch b/queue-7.0/alsa-core-validate-compress-device-numbers-without-d.patch new file mode 100644 index 0000000000..79f31ee9e4 --- /dev/null +++ b/queue-7.0/alsa-core-validate-compress-device-numbers-without-d.patch @@ -0,0 +1,81 @@ +From 781ca6ff01e44b1bfc78bb58449320a532f78211 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 02:24:04 -0300 +Subject: ALSA: core: Validate compress device numbers without dynamic minors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 796e119e9b14763be905ad0d023c71a14bc2e931 ] + +Without CONFIG_SND_DYNAMIC_MINORS, ALSA reserves only two fixed minors +for compress devices on each card: comprD0 and comprD1. + +snd_find_free_minor() currently computes the compress minor as +type + dev without validating dev first, so device numbers greater than +1 spill into the HWDEP minor range instead of failing registration. + +ASoC passes rtd->id to snd_compress_new(), so this can happen on real +non-dynamic-minor builds. + +Add a dedicated fixed-minor check for SNDRV_DEVICE_TYPE_COMPRESS in +snd_find_free_minor() and reject out-of-range device numbers with +-EINVAL before constructing the minor. + +Also remove the stale TODO in compress_offload.c that still claims +multiple compress nodes are missing. + +Fixes: 3eafc959b32f ("ALSA: core: add support for compressed devices") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-alsa-compress-static-minors-v1-1-0628573bee1c@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/compress_offload.c | 7 ------- + sound/core/sound.c | 7 +++++++ + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index fdba6e4b25fdc..5a0308eb4e31d 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -41,13 +41,6 @@ + #define COMPR_CODEC_CAPS_OVERFLOW + #endif + +-/* TODO: +- * - add substream support for multiple devices in case of +- * SND_DYNAMIC_MINORS is not used +- * - Multiple node representation +- * driver should be able to register multiple nodes +- */ +- + struct snd_compr_file { + unsigned long caps; + struct snd_compr_stream stream; +diff --git a/sound/core/sound.c b/sound/core/sound.c +index 93436db24710b..8d05fe0d263b2 100644 +--- a/sound/core/sound.c ++++ b/sound/core/sound.c +@@ -216,9 +216,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev) + case SNDRV_DEVICE_TYPE_RAWMIDI: + case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: + case SNDRV_DEVICE_TYPE_PCM_CAPTURE: ++ if (snd_BUG_ON(!card)) ++ return -EINVAL; ++ minor = SNDRV_MINOR(card->number, type + dev); ++ break; + case SNDRV_DEVICE_TYPE_COMPRESS: + if (snd_BUG_ON(!card)) + return -EINVAL; ++ if (dev < 0 || ++ dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS) ++ return -EINVAL; + minor = SNDRV_MINOR(card->number, type + dev); + break; + default: +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-cmedia-remove-duplicate-pin-configuration-p.patch b/queue-7.0/alsa-hda-cmedia-remove-duplicate-pin-configuration-p.patch new file mode 100644 index 0000000000..22f52ac284 --- /dev/null +++ b/queue-7.0/alsa-hda-cmedia-remove-duplicate-pin-configuration-p.patch @@ -0,0 +1,43 @@ +From 02f4456625a758b14cd718613c27292699ca3450 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 16:26:25 +0800 +Subject: ALSA: hda/cmedia: Remove duplicate pin configuration parsing + +From: wangdicheng + +[ Upstream commit 579e7b820de5dd5124585413bb5e9c278d255436 ] + +The cmedia_probe() function calls snd_hda_parse_pin_defcfg() and +snd_hda_gen_parse_auto_config() twice unnecessarily. Remove The +duplicate code. + +Fixes: 0f1e8306dcbe ("ALSA: hda/cmedia: Rewrite to new probe method") +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260401082625.157868-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/cmedia.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/sound/hda/codecs/cmedia.c b/sound/hda/codecs/cmedia.c +index e6e12c01339f6..88dd80d987d41 100644 +--- a/sound/hda/codecs/cmedia.c ++++ b/sound/hda/codecs/cmedia.c +@@ -39,13 +39,6 @@ static int cmedia_probe(struct hda_codec *codec, const struct hda_device_id *id) + spec->out_vol_mask = (1ULL << 0x10); + } + +- err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); +- if (err < 0) +- goto error; +- err = snd_hda_gen_parse_auto_config(codec, cfg); +- if (err < 0) +- goto error; +- + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + goto error; +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch b/queue-7.0/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch new file mode 100644 index 0000000000..026cb6e21c --- /dev/null +++ b/queue-7.0/alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch @@ -0,0 +1,60 @@ +From 991d96c62eaa81b3eaaf244623ce8eab39970cf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:04:50 +0800 +Subject: ALSA: hda/conexant: Fix missing error check for jack detection + +From: wangdicheng + +[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ] + +In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() +is ignored. This function returns a pointer, and if it fails (e.g., due +to memory allocation failure), it returns an error pointer which must +be checked using IS_ERR(). + +If the registration fails, the driver continues to probe, but the jack +detection callback will not be registered. This can lead to a kernel +crash later when the driver attempts to handle jack events or accesses +the uninitialized structure. + +Check the return value using IS_ERR() and propagate the error via +PTR_ERR() to the probe caller. + +Fixes: 7aeb25908648 ("ALSA: hda/conexant: Fix headset auto detect fail in cx8070 and SN6140") +Signed-off-by: wangdicheng +Link: https://patch.msgid.link/20260428080450.108801-1-wangdich9700@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/conexant.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c +index aa726eb323ebe..a7689f9ef9675 100644 +--- a/sound/hda/codecs/conexant.c ++++ b/sound/hda/codecs/conexant.c +@@ -1183,6 +1183,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) + static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) + { + struct conexant_spec *spec; ++ struct hda_jack_callback *callback; + int err; + + codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name); +@@ -1198,7 +1199,12 @@ static int cx_probe(struct hda_codec *codec, const struct hda_device_id *id) + case 0x14f11f86: + case 0x14f11f87: + spec->is_cx11880_sn6140 = true; +- snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); ++ callback = snd_hda_jack_detect_enable_callback(codec, 0x19, ++ cx_update_headset_mic_vref); ++ if (IS_ERR(callback)) { ++ err = PTR_ERR(callback); ++ goto error; ++ } + break; + } + +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch b/queue-7.0/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch new file mode 100644 index 0000000000..5222b4bb99 --- /dev/null +++ b/queue-7.0/alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch @@ -0,0 +1,95 @@ +From d682204fcb3c0878bd24755b6ad2d713082b7875 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 14:05:31 +0100 +Subject: ALSA: hda: cs35l56: Fix uninitialized value in + cs35l56_hda_read_acpi() + +From: Richard Fitzgerald + +[ Upstream commit 90df4957a3271adf391b3432cd76a40887cf3273 ] + +Eliminate the uninitialized 'nval' in cs35l56_hda_read_acpi() if a +system-specific quirk overrides processing of the dev-index property. +The value is now stored in a new 'num_amps' member of struct cs35l56_hda +so that the quirk handler can set the value. + +The quirk for the Lenovo Yoga Book 9i GenX replaces the values from the +dev-index property with hardcoded indexes. So cs35l56_hda_read_acpi() would +then skip reading the property. But this left the 'nval' local variable +uninitialized when it is later passed to cirrus_scodec_get_speaker_id(). + +Fixes: 40b1c2f9b299 ("ALSA: hda/cs35l56: Workaround bad dev-index on Lenovo Yoga Book 9i GenX") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-sound/aenFesLAStjrVNy8@stanley.mountain/T/#u +Signed-off-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260428130531.169600-1-rf@opensource.cirrus.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/cs35l56_hda.c | 12 +++++++----- + sound/hda/codecs/side-codecs/cs35l56_hda.h | 1 + + 2 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c +index dc25960a4f231..4c8d01799931c 100644 +--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c ++++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c +@@ -976,6 +976,7 @@ static int cs35l56_hda_system_resume(struct device *dev) + static int cs35l56_hda_fixup_yoga9(struct cs35l56_hda *cs35l56, int *bus_addr) + { + /* The cirrus,dev-index property has the wrong values */ ++ cs35l56->num_amps = 2; + switch (*bus_addr) { + case 0x30: + cs35l56->index = 1; +@@ -1025,7 +1026,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + char hid_string[8]; + struct acpi_device *adev; + const char *property, *sub; +- size_t nval; + int i, ret; + + /* +@@ -1061,13 +1061,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + ret = -EINVAL; + goto err; + } +- nval = ret; ++ cs35l56->num_amps = ret; + +- ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval); ++ ret = device_property_read_u32_array(cs35l56->base.dev, property, values, ++ cs35l56->num_amps); + if (ret) + goto err; + +- for (i = 0; i < nval; i++) { ++ for (i = 0; i < cs35l56->num_amps; i++) { + if (values[i] == id) { + cs35l56->index = i; + break; +@@ -1090,7 +1091,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) + "Read ACPI _SUB failed(%ld): fallback to generic firmware\n", + PTR_ERR(sub)); + } else { +- ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1); ++ ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, ++ cs35l56->num_amps, -1); + if (ret == -ENOENT) { + cs35l56->system_name = sub; + } else if (ret >= 0) { +diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h +index cb4b5e7356a35..3705af7c186b3 100644 +--- a/sound/hda/codecs/side-codecs/cs35l56_hda.h ++++ b/sound/hda/codecs/side-codecs/cs35l56_hda.h +@@ -26,6 +26,7 @@ struct cs35l56_hda { + struct work_struct dsp_work; + + int index; ++ int num_amps; + const char *system_name; + const char *amp_name; + +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-notify-iec958-default-pcm-switch-state-chan.patch b/queue-7.0/alsa-hda-notify-iec958-default-pcm-switch-state-chan.patch new file mode 100644 index 0000000000..be52e94393 --- /dev/null +++ b/queue-7.0/alsa-hda-notify-iec958-default-pcm-switch-state-chan.patch @@ -0,0 +1,160 @@ +From 2b0b7a38be39dddd7a133dbbc71d57d48d9737ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 00:21:34 -0300 +Subject: ALSA: hda: Notify IEC958 Default PCM switch state changes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 6692ed9b4ced29aa819c95cc4ad9e2dc8720c081 ] + +The "IEC958 Default PCM Playback Switch" control is backed directly by +mout->share_spdif. The share-switch callbacks currently access that state +without serialization, and spdif_share_sw_put() always returns 0, so +normal userspace writes never emit the standard ALSA control value +notification. + +snd_hda_multi_out_analog_open() may also clear mout->share_spdif when the +analog PCM capabilities and the SPDIF capabilities no longer intersect. +That fallback is still needed to avoid creating an impossible hw +constraint set, but it changes the mixer backing value without notifying +subscribers. + +Protect the share-switch callbacks with spdif_mutex like the other SPDIF +control handlers, return the actual change value from spdif_share_sw_put(), +and notify the cached control when the open path forcibly disables +shared SPDIF mode after dropping spdif_mutex. + +This keeps the existing auto-disable behavior while making switch state +changes visible to userspace. + +Fixes: 9a08160bdbe3 ("[ALSA] hda-codec - Add "IEC958 Default PCM" switch") +Fixes: 022b466fc353 ("ALSA: hda - Avoid invalid formats and rates with shared SPDIF") +Suggested-by: Takashi Iwai +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260403-hda-spdif-share-notify-v3-1-4eb1356b0f17@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/common/codec.c | 46 +++++++++++++++++++++++++++++------- + sound/hda/common/hda_local.h | 1 + + 2 files changed, 39 insertions(+), 8 deletions(-) + +diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c +index 09b1329bb8f35..5123df32ad89f 100644 +--- a/sound/hda/common/codec.c ++++ b/sound/hda/common/codec.c +@@ -2529,7 +2529,10 @@ EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_assign); + static int spdif_share_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { +- struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol); ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct hda_multi_out *mout = (void *)kcontrol->private_value; ++ ++ guard(mutex)(&codec->spdif_mutex); + ucontrol->value.integer.value[0] = mout->share_spdif; + return 0; + } +@@ -2537,9 +2540,15 @@ static int spdif_share_sw_get(struct snd_kcontrol *kcontrol, + static int spdif_share_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { +- struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol); +- mout->share_spdif = !!ucontrol->value.integer.value[0]; +- return 0; ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct hda_multi_out *mout = (void *)kcontrol->private_value; ++ bool val = !!ucontrol->value.integer.value[0]; ++ int change; ++ ++ guard(mutex)(&codec->spdif_mutex); ++ change = mout->share_spdif != val; ++ mout->share_spdif = val; ++ return change; + } + + static const struct snd_kcontrol_new spdif_share_sw = { +@@ -2550,6 +2559,14 @@ static const struct snd_kcontrol_new spdif_share_sw = { + .put = spdif_share_sw_put, + }; + ++static void notify_spdif_share_sw(struct hda_codec *codec, ++ struct hda_multi_out *mout) ++{ ++ if (mout->share_spdif_kctl) ++ snd_ctl_notify_one(codec->card, SNDRV_CTL_EVENT_MASK_VALUE, ++ mout->share_spdif_kctl, 0); ++} ++ + /** + * snd_hda_create_spdif_share_sw - create Default PCM switch + * @codec: the HDA codec +@@ -2559,15 +2576,24 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, + struct hda_multi_out *mout) + { + struct snd_kcontrol *kctl; ++ int err; + + if (!mout->dig_out_nid) + return 0; + +- kctl = snd_ctl_new1(&spdif_share_sw, mout); ++ kctl = snd_ctl_new1(&spdif_share_sw, codec); + if (!kctl) + return -ENOMEM; +- /* ATTENTION: here mout is passed as private_data, instead of codec */ +- return snd_hda_ctl_add(codec, mout->dig_out_nid, kctl); ++ /* snd_ctl_new1() stores @codec in private_data; stash @mout in ++ * private_value for the share-switch callbacks and cache the ++ * assigned control for forced-disable notifications. ++ */ ++ kctl->private_value = (unsigned long)mout; ++ err = snd_hda_ctl_add(codec, mout->dig_out_nid, kctl); ++ if (err < 0) ++ return err; ++ mout->share_spdif_kctl = kctl; ++ return 0; + } + EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw); + +@@ -3701,6 +3727,8 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, + struct hda_pcm_stream *hinfo) + { + struct snd_pcm_runtime *runtime = substream->runtime; ++ bool notify_share_sw = false; ++ + runtime->hw.channels_max = mout->max_channels; + if (mout->dig_out_nid) { + if (!mout->analog_rates) { +@@ -3729,10 +3757,12 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, + hinfo->maxbps = mout->spdif_maxbps; + } else { + mout->share_spdif = 0; +- /* FIXME: need notify? */ ++ notify_share_sw = true; + } + } + } ++ if (notify_share_sw) ++ notify_spdif_share_sw(codec, mout); + return snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); + } +diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h +index ab423f1cef549..98b2c4acebc27 100644 +--- a/sound/hda/common/hda_local.h ++++ b/sound/hda/common/hda_local.h +@@ -221,6 +221,7 @@ struct hda_multi_out { + unsigned int spdif_rates; + unsigned int spdif_maxbps; + u64 spdif_formats; ++ struct snd_kcontrol *share_spdif_kctl; /* cached shared SPDIF switch */ + }; + + int snd_hda_create_spdif_share_sw(struct hda_codec *codec, +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-fix-bad-indentation-for-alc269.patch b/queue-7.0/alsa-hda-realtek-fix-bad-indentation-for-alc269.patch new file mode 100644 index 0000000000..77bddeee02 --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-fix-bad-indentation-for-alc269.patch @@ -0,0 +1,48 @@ +From 2b9fc29d4ce79213e9c704422b4bc5bbeb2045d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:40:36 +0800 +Subject: ALSA: hda/realtek: fix bad indentation for alc269 + +From: Lei Huang + +[ Upstream commit c1258a2924d3a2453a6e7a6581acd8d6e5c6ba70 ] + +Mention complains about this coding style: + + ERROR: code indent should use tabs where possible + #6640: FILE: sound/hda/codecs/realtek/alc269.c:6640: + + [ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY] = {$ + +fix it up. + +Fixes: 5de5db35350d ("ALSA: hda/realtek - Enable Mute LED for Lenovo platform") +Signed-off-by: Lei Huang +Link: https://patch.msgid.link/20260331024036.30782-1-huanglei814@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index ded6e78142a07..8e135bcaa28e6 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -6657,10 +6657,10 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc288_fixup_surface_swap_dacs, + }, +- [ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY] = { +- .type = HDA_FIXUP_FUNC, +- .v.func = alc233_fixup_lenovo_gpio2_mic_hotkey, +- }, ++ [ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc233_fixup_lenovo_gpio2_mic_hotkey, ++ }, + [ALC245_FIXUP_BASS_HP_DAC] = { + .type = HDA_FIXUP_FUNC, + /* Borrow the DAC routing selected for those Thinkpads */ +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch b/queue-7.0/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch new file mode 100644 index 0000000000..7c719362ae --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-fix-code-style-error-else-should-fo.patch @@ -0,0 +1,45 @@ +From a1743c576ef57a9ece9a7c6ca9faba2ab9bf93a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 15:54:05 +0800 +Subject: ALSA: hda/realtek: fix code style (ERROR: else should follow close + brace '}') + +From: Lei Huang + +[ Upstream commit d1888bf848ade6a9e71c7ba516fd215aa1bd8d65 ] + +Fix checkpatch code style errors: + + ERROR: else should follow close brace '}' + #2300: FILE: sound/hda/codecs/realtek/alc269.c:2300: + + } + + else + +Fixes: 31278997add6 ("ALSA: hda/realtek - Add headset quirk for Dell DT") +Signed-off-by: Lei Huang +Link: https://patch.msgid.link/20260331075405.78148-1-huanglei814@163.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index 8e135bcaa28e6..cbc24d71a1115 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -2296,9 +2296,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } +- else ++ } else { + alc_fixup_headset_mode(codec, fix, action); ++ } + } + + static void alc288_update_headset_jack_cb(struct hda_codec *codec, +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-realtek-fixed-speaker-no-sound-update.patch b/queue-7.0/alsa-hda-realtek-fixed-speaker-no-sound-update.patch new file mode 100644 index 0000000000..a4c2c785b4 --- /dev/null +++ b/queue-7.0/alsa-hda-realtek-fixed-speaker-no-sound-update.patch @@ -0,0 +1,67 @@ +From 3f4eadd290b6f43bb5bb290d02d6c3b48b99f883 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:44:04 +0800 +Subject: ALSA: hda/realtek - fixed speaker no sound update + +From: Kailang Yang + +[ Upstream commit 46c862f5419e0a86b60b9f9558d247f6084c99f9 ] + +Fixed speaker has pop noise on Lenovo Thinkpad X11 Carbon Gen 12. + +Fixes: 630fbc6e870e ("ALSA: hda/realtek - fixed speaker no sound") +Reported-and-tested-by: Jeremy Bethmont +Closes: https://lore.kernel.org/CAC88DfsHrhyhy0Pn1O-z9egBvMYu=6NYgcvcC6KCgwh_-Ldkxg@mail.gmail.com +Signed-off-by: Kailang Yang +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/realtek/alc269.c | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c +index cbc24d71a1115..d8698c20a3cae 100644 +--- a/sound/hda/codecs/realtek/alc269.c ++++ b/sound/hda/codecs/realtek/alc269.c +@@ -3674,22 +3674,11 @@ static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct snd_pcm_substream *substream, + int action) + { +- static const struct coef_fw dis_coefs[] = { +- WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), +- WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023), +- }; /* Disable AMP silence detection */ +- static const struct coef_fw en_coefs[] = { +- WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), +- WRITE_COEF(0x28, 0x0084), WRITE_COEF(0x29, 0xb023), +- }; /* Enable AMP silence detection */ +- + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: +- alc_process_coef_fw(codec, dis_coefs); + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */ + break; + case HDA_GEN_PCM_ACT_CLOSE: +- alc_process_coef_fw(codec, en_coefs); + alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */ + break; + } +@@ -3712,10 +3701,15 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec, + WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301), + WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023), + }; ++ static const struct coef_fw dis_coefs[] = { ++ WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203), ++ WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023), ++ }; /* Disable AMP silence detection */ + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11); ++ alc_process_coef_fw(codec, dis_coefs); + alc_process_coef_fw(codec, coefs); + spec->power_hook = alc287_s4_power_gpio3_default; + spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook; +-- +2.53.0 + diff --git a/queue-7.0/alsa-hda-tas2781-fix-incorrect-bit-update-for-non-bo.patch b/queue-7.0/alsa-hda-tas2781-fix-incorrect-bit-update-for-non-bo.patch new file mode 100644 index 0000000000..a10aeaca01 --- /dev/null +++ b/queue-7.0/alsa-hda-tas2781-fix-incorrect-bit-update-for-non-bo.patch @@ -0,0 +1,52 @@ +From 1a86a60e4db7480bb715094eb8131622f65e95b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 13:42:06 +0800 +Subject: ALSA: hda/tas2781: Fix incorrect bit update for non-book-zero or book + 0 pages >1 + +From: Shenghao Ding + +[ Upstream commit e052a1f7199260eda4d6ca08a59c3b98738f8491 ] + +In TAS2781 SPI mode, when accessing non-book-zero or page numbers greater +than 1 in book 0, an additional byte must be read. The first byte in such +cases is a dummy byte and should be ignored. + +Fixes: 9fa6a693ad8d ("ALSA: hda/tas2781: Remove tas2781_spi_fwlib.c and leverage SND_SOC_TAS2781_FMWLIB") +Signed-off-by: Shenghao Ding +Link: https://patch.msgid.link/20260429054206.429-1-shenghao-ding@ti.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/hda/codecs/side-codecs/tas2781_hda_spi.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c +index f860e0eb7602a..6c736b17c9831 100644 +--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c ++++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c +@@ -132,10 +132,18 @@ static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv, + int ret, val; + + /* +- * In our TAS2781 SPI mode, read/write was masked in last bit of +- * address, it cause regmap_update_bits() not work as expected. ++ * In TAS2781 SPI mode, when accessing non-book-zero or page numbers ++ * greater than 1 in book 0, an additional byte must be read. The ++ * first byte in such cases is a dummy byte and should be ignored. + */ +- ret = tasdevice_dev_read(tas_priv, chn, reg, &val); ++ if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) { ++ unsigned char buf[2]; ++ ++ ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, buf, 2); ++ val = buf[1]; ++ } else { ++ ret = tasdevice_dev_read(tas_priv, chn, reg, &val); ++ } + if (ret < 0) { + dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); + return ret; +-- +2.53.0 + diff --git a/queue-7.0/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch b/queue-7.0/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch new file mode 100644 index 0000000000..f9bd59ca98 --- /dev/null +++ b/queue-7.0/alsa-sc6000-keep-the-programmed-board-state-in-card-.patch @@ -0,0 +1,289 @@ +From bd112b6820432762474b8b0708207ae0965aece0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:54:32 -0300 +Subject: ALSA: sc6000: Keep the programmed board state in card-private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit fb79bf127ac2577b4876132da6dba768018aad4c ] + +The driver may auto-select IRQ and DMA resources at probe time, but +sc6000_init_board() still derives the SC-6000 soft configuration from +the module parameter arrays. When irq=auto or dma=auto is used, the +codec is created with the selected resources while the board is +programmed with the unresolved values. + +Store the mapped ports and generated SC-6000 board configuration in +card-private data, build that configuration from the live probe +results instead of the raw module parameters, and keep the probe-time +board programming in a shared helper. + +This fixes the resource-programming mismatch and leaves the driver +with a stable board-state block that can be reused by suspend/resume. + +Fixes: c282866101bf ("ALSA: sc6000: add support for SC-6600 and SC-7000") +Signed-off-by: Cássio Gabriel +Signed-off-by: Takashi Iwai +Link: https://patch.msgid.link/20260410-alsa-sc6000-pm-v1-1-4d9e95493d26@gmail.com +Signed-off-by: Sasha Levin +--- + sound/isa/sc6000.c | 152 +++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 60 deletions(-) + +diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c +index 6d618cc2ba457..9949e06403f61 100644 +--- a/sound/isa/sc6000.c ++++ b/sound/isa/sc6000.c +@@ -100,6 +100,15 @@ MODULE_PARM_DESC(joystick, "Enable gameport."); + #define PFX "sc6000: " + #define DRV_NAME "SC-6000" + ++struct snd_sc6000 { ++ char __iomem *vport; ++ char __iomem *vmss_port; ++ u8 mss_config; ++ u8 config; ++ u8 hw_cfg[2]; ++ bool old_dsp; ++}; ++ + /* hardware dependent functions */ + + /* +@@ -267,7 +276,7 @@ static int sc6000_dsp_reset(char __iomem *vport) + + /* detection and initialization */ + static int sc6000_hw_cfg_write(struct device *devptr, +- char __iomem *vport, const int *cfg) ++ char __iomem *vport, const u8 *cfg) + { + if (sc6000_write(devptr, vport, COMMAND_6C) < 0) { + dev_warn(devptr, "CMD 0x%x: failed!\n", COMMAND_6C); +@@ -353,8 +362,7 @@ static int sc6000_init_mss(struct device *devptr, + return 0; + } + +-static void sc6000_hw_cfg_encode(struct device *devptr, +- char __iomem *vport, int *cfg, ++static void sc6000_hw_cfg_encode(struct device *devptr, u8 *cfg, + long xport, long xmpu, + long xmss_port, int joystick) + { +@@ -376,27 +384,83 @@ static void sc6000_hw_cfg_encode(struct device *devptr, + dev_dbg(devptr, "hw cfg %x, %x\n", cfg[0], cfg[1]); + } + +-static int sc6000_init_board(struct device *devptr, +- char __iomem *vport, +- char __iomem *vmss_port, int dev) ++static void sc6000_prepare_board(struct device *devptr, ++ struct snd_sc6000 *sc6000, ++ unsigned int dev, int xirq, int xdma) ++{ ++ sc6000->mss_config = sc6000_irq_to_softcfg(xirq) | ++ sc6000_dma_to_softcfg(xdma); ++ sc6000->config = sc6000->mss_config | ++ sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); ++ sc6000_hw_cfg_encode(devptr, sc6000->hw_cfg, port[dev], mpu_port[dev], ++ mss_port[dev], joystick[dev]); ++} ++ ++static void sc6000_detect_old_dsp(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ sc6000_write(devptr, sc6000->vport, COMMAND_5C); ++ sc6000->old_dsp = sc6000_read(sc6000->vport) < 0; ++} ++ ++static int sc6000_program_board(struct device *devptr, ++ struct snd_sc6000 *sc6000) ++{ ++ int err; ++ ++ if (!sc6000->old_dsp) { ++ if (sc6000_hw_cfg_write(devptr, sc6000->vport, ++ sc6000->hw_cfg) < 0) { ++ dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); ++ return -EIO; ++ } ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ sc6000_dsp_reset(sc6000->vport); ++ ++ if (!sc6000->old_dsp) { ++ sc6000_write(devptr, sc6000->vport, COMMAND_60); ++ sc6000_write(devptr, sc6000->vport, 0x02); ++ sc6000_dsp_reset(sc6000->vport); ++ } ++ ++ err = sc6000_setup_board(devptr, sc6000->vport, sc6000->config); ++ if (err < 0) { ++ dev_err(devptr, "sc6000_setup_board: failed!\n"); ++ return -ENODEV; ++ } ++ ++ err = sc6000_init_mss(devptr, sc6000->vport, sc6000->config, ++ sc6000->vmss_port, sc6000->mss_config); ++ if (err < 0) { ++ dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int sc6000_init_board(struct device *devptr, struct snd_sc6000 *sc6000) + { + char answer[15]; + char version[2]; +- int mss_config = sc6000_irq_to_softcfg(irq[dev]) | +- sc6000_dma_to_softcfg(dma[dev]); +- int config = mss_config | +- sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); + int err; +- int old = 0; + +- err = sc6000_dsp_reset(vport); ++ err = sc6000_dsp_reset(sc6000->vport); + if (err < 0) { + dev_err(devptr, "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); +- err = sc6000_dsp_get_answer(devptr, vport, GET_DSP_COPYRIGHT, answer, 15); ++ err = sc6000_dsp_get_answer(devptr, sc6000->vport, GET_DSP_COPYRIGHT, ++ answer, 15); + if (err <= 0) { + dev_err(devptr, "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; +@@ -408,54 +472,17 @@ static int sc6000_init_board(struct device *devptr, + if (strncmp("SC-6000", answer, 7)) + dev_warn(devptr, "Warning: non SC-6000 audio card!\n"); + +- if (sc6000_dsp_get_answer(devptr, vport, GET_DSP_VERSION, version, 2) < 2) { ++ if (sc6000_dsp_get_answer(devptr, sc6000->vport, ++ GET_DSP_VERSION, version, 2) < 2) { + dev_err(devptr, "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } + dev_info(devptr, "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + +- /* set configuration */ +- sc6000_write(devptr, vport, COMMAND_5C); +- if (sc6000_read(vport) < 0) +- old = 1; +- +- if (!old) { +- int cfg[2]; +- sc6000_hw_cfg_encode(devptr, +- vport, &cfg[0], port[dev], mpu_port[dev], +- mss_port[dev], joystick[dev]); +- if (sc6000_hw_cfg_write(devptr, vport, cfg) < 0) { +- dev_err(devptr, "sc6000_hw_cfg_write: failed!\n"); +- return -EIO; +- } +- } +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- +- sc6000_dsp_reset(vport); +- +- if (!old) { +- sc6000_write(devptr, vport, COMMAND_60); +- sc6000_write(devptr, vport, 0x02); +- sc6000_dsp_reset(vport); +- } ++ sc6000_detect_old_dsp(devptr, sc6000); + +- err = sc6000_setup_board(devptr, vport, config); +- if (err < 0) { +- dev_err(devptr, "sc6000_setup_board: failed!\n"); +- return -ENODEV; +- } +- err = sc6000_init_mss(devptr, vport, config, vmss_port, mss_config); +- if (err < 0) { +- dev_err(devptr, "Cannot initialize Microsoft Sound System mode.\n"); +- return -ENODEV; +- } +- +- return 0; ++ return sc6000_program_board(devptr, sc6000); + } + + static int snd_sc6000_mixer(struct snd_wss *chip) +@@ -538,10 +565,10 @@ static int snd_sc6000_match(struct device *devptr, unsigned int dev) + + static void snd_sc6000_free(struct snd_card *card) + { +- char __iomem *vport = (char __force __iomem *)card->private_data; ++ struct snd_sc6000 *sc6000 = card->private_data; + +- if (vport) +- sc6000_setup_board(card->dev, vport, 0); ++ if (sc6000->vport) ++ sc6000_setup_board(card->dev, sc6000->vport, 0); + } + + static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) +@@ -552,15 +579,17 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + int xirq = irq[dev]; + int xdma = dma[dev]; + struct snd_card *card; ++ struct snd_sc6000 *sc6000; + struct snd_wss *chip; + struct snd_opl3 *opl3; + char __iomem *vport; + char __iomem *vmss_port; + + err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE, +- 0, &card); ++ sizeof(*sc6000), &card); + if (err < 0) + return err; ++ sc6000 = card->private_data; + + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); +@@ -587,7 +616,7 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "I/O port cannot be iomapped.\n"); + return -EBUSY; + } +- card->private_data = (void __force *)vport; ++ sc6000->vport = vport; + + /* to make it marked as used */ + if (!devm_request_region(devptr, mss_port[dev], 4, DRV_NAME)) { +@@ -600,12 +629,15 @@ static int __snd_sc6000_probe(struct device *devptr, unsigned int dev) + dev_err(devptr, "MSS port I/O cannot be iomapped.\n"); + return -EBUSY; + } ++ sc6000->vmss_port = vmss_port; + + dev_dbg(devptr, "Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + +- err = sc6000_init_board(devptr, vport, vmss_port, dev); ++ sc6000_prepare_board(devptr, sc6000, dev, xirq, xdma); ++ ++ err = sc6000_init_board(devptr, sc6000); + if (err < 0) + return err; + card->private_free = snd_sc6000_free; +-- +2.53.0 + diff --git a/queue-7.0/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch b/queue-7.0/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch new file mode 100644 index 0000000000..6333334aea --- /dev/null +++ b/queue-7.0/alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch @@ -0,0 +1,39 @@ +From 8ba3f693d48a993534e9d1b21e5469f1d748f8e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 01:25:48 +0300 +Subject: ALSA: scarlett2: Add missing sentinel initializer field + +From: Panagiotis Petrakopoulos + +[ Upstream commit 2428cd6e8b6fa80c36db4652702ca0acd2ce3f08 ] + +A "-Wmissing-field-initializers" warning was emitted when compiling the +module using the W=2 option. There is a sentinel initializer field +missing in the end of scarlett2_devices[]. Tested using a +Scarlett Solo 4th gen. + +Fixes: d98cc489029d ("ALSA: scarlett2: Move USB IDs out from device_info struct") +Signed-off-by: Panagiotis Petrakopoulos +Link: https://patch.msgid.link/20260405222548.8903-1-npetrakopoulos2003@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_scarlett2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index fd1fb668929a2..8eaa962227596 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -2262,7 +2262,7 @@ static const struct scarlett2_device_entry scarlett2_devices[] = { + { USB_ID(0x1235, 0x820c), &clarett_8pre_info, "Clarett+" }, + + /* End of list */ +- { 0, NULL }, ++ { 0, NULL, NULL }, + }; + + /* get the starting port index number for a given port type/direction */ +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-exclude-scarlett-18i20-1st-gen-from-s.patch b/queue-7.0/alsa-usb-audio-exclude-scarlett-18i20-1st-gen-from-s.patch new file mode 100644 index 0000000000..3c99ba6458 --- /dev/null +++ b/queue-7.0/alsa-usb-audio-exclude-scarlett-18i20-1st-gen-from-s.patch @@ -0,0 +1,37 @@ +From d709137d63fb05f57c4426cb68f32fa9dc853f75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 03:03:00 +0930 +Subject: ALSA: usb-audio: Exclude Scarlett 18i20 1st Gen from SKIP_IFACE_SETUP + +From: Geoffrey D. Bennett + +[ Upstream commit a47306a74c31557b1e5cab54642950bbb20294cb ] + +Same issue as the other 1st Gen Scarletts: QUIRK_FLAG_SKIP_IFACE_SETUP +causes distorted audio on the Scarlett 18i20 1st Gen (1235:800c). + +Fixes: 38c322068a26 ("ALSA: usb-audio: Add QUIRK_FLAG_SKIP_IFACE_SETUP") +Reported-by: tucktuckg00se [https://github.com/geoffreybennett/linux-fcp/issues/54] +Signed-off-by: Geoffrey D. Bennett +Link: https://patch.msgid.link/ad0ozNnkcFrcjVQz@m.b4.vu +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 4cfa24c06fcdf..6f2a053d971c9 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -2435,6 +2435,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { + QUIRK_FLAG_VALIDATE_RATES), + DEVICE_FLG(0x1235, 0x8006, 0), /* Focusrite Scarlett 2i2 1st Gen */ + DEVICE_FLG(0x1235, 0x800a, 0), /* Focusrite Scarlett 2i4 1st Gen */ ++ DEVICE_FLG(0x1235, 0x800c, 0), /* Focusrite Scarlett 18i20 1st Gen */ + DEVICE_FLG(0x1235, 0x8016, 0), /* Focusrite Scarlett 2i2 1st Gen */ + DEVICE_FLG(0x1235, 0x801c, 0), /* Focusrite Scarlett Solo 1st Gen */ + VENDOR_FLG(0x1235, /* Focusrite Novation */ +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch b/queue-7.0/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch new file mode 100644 index 0000000000..cdbbf7e25d --- /dev/null +++ b/queue-7.0/alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch @@ -0,0 +1,205 @@ +From 445ac3ba87006cc60b2788bc25f0481d0e8b8a8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 17:15:04 +0200 +Subject: ALSA: usb-audio: Fix potential leak of pd at parsing UAC3 streams + +From: Takashi Iwai + +[ Upstream commit c39f0bc03f84ba64c9144c95714df1dc36150f6d ] + +At parsing UAC3 streams, we allocate a PD object at each time, and +either assign or free it. But there is a case where the PD object may +be leaked; namely, in __snd_usb_parse_audio_interface() loop, when an +audioformat shares the same endpoint with others, it's put to a link +and returns from snd_usb_add_audio_stream(), but the PD is forgotten +afterwards. Overall, the treatment of PD object in the parser code is +a bit flaky, and we should be more careful about the object ownership. + +This patch tries to fix the above case and improve the code a bit. +The pd object is now managed with the auto-cleanup in the loop, and +the ownership is updated when the pd object gets assigned to the +stream, which guarantees the release of the leftover object. + +Fixes: 7edf3b5e6a45 ("ALSA: usb-audio: AudioStreaming Power Domain parsing") +Link: https://patch.msgid.link/20260427151508.12544-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks.c | 2 +- + sound/usb/stream.c | 58 ++++++++++++++++++---------------------------- + sound/usb/stream.h | 3 ++- + 3 files changed, 25 insertions(+), 38 deletions(-) + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 6f2a053d971c9..e8ae3464887b2 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip, + + snd_usb_audioformat_set_sync_ep(chip, fp); + +- err = snd_usb_add_audio_stream(chip, stream, fp); ++ err = snd_usb_add_audio_stream(chip, stream, fp, NULL); + if (err < 0) + return err; + +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index b07e2ec661c16..03a939cdd07ac 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -79,7 +79,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) + static void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, + struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++ struct snd_usb_power_domain **pdptr) + { + struct snd_usb_substream *subs = &as->substream[stream]; + +@@ -105,10 +105,11 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, + if (fp->channels > subs->channels_max) + subs->channels_max = fp->channels; + +- if (pd) { +- subs->str_pd = pd; ++ if (pdptr && *pdptr) { ++ subs->str_pd = *pdptr; ++ *pdptr = NULL; /* assigned */ + /* Initialize Power Domain to idle status D1 */ +- snd_usb_power_domain_set(subs->stream->chip, pd, ++ snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, + UAC3_PD_STATE_D1); + } + +@@ -486,11 +487,14 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor + * if not, create a new pcm stream. note, fp is added to the substream + * fmt_list and will be freed on the chip instance release. do not free + * fp or do remove it from the substream fmt_list to avoid double-free. ++ * ++ * pdptr is optional and can be NULL. When it's non-NULL and the PD gets ++ * assigned to the stream, *pdptr is cleared to NULL upon return. + */ +-static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) ++int snd_usb_add_audio_stream(struct snd_usb_audio *chip, ++ int stream, ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr) + + { + struct snd_usb_stream *as; +@@ -523,7 +527,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + err = snd_pcm_new_stream(as->pcm, stream, 1); + if (err < 0) + return err; +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + return add_chmap(as->pcm, stream, subs); + } + +@@ -552,7 +556,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + else + strscpy(pcm->name, "USB Audio"); + +- snd_usb_init_substream(as, stream, fp, pd); ++ snd_usb_init_substream(as, stream, fp, pdptr); + + /* + * Keep using head insertion for M-Audio Audiophile USB (tm) which has a +@@ -570,21 +574,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, + return add_chmap(pcm, stream, &as->substream[stream]); + } + +-int snd_usb_add_audio_stream(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, NULL); +-} +- +-static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, +- int stream, +- struct audioformat *fp, +- struct snd_usb_power_domain *pd) +-{ +- return __snd_usb_add_audio_stream(chip, stream, fp, pd); +-} +- + static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, + struct usb_host_interface *alts, + int protocol, int iface_no) +@@ -1107,8 +1096,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + } + } + +- if (pd) +- *pd_out = pd; ++ *pd_out = pd; + + return fp; + } +@@ -1123,7 +1111,6 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + struct usb_interface_descriptor *altsd; + int i, altno, err, stream; + struct audioformat *fp = NULL; +- struct snd_usb_power_domain *pd = NULL; + bool set_iface_first; + int num, protocol; + +@@ -1165,6 +1152,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + if (snd_usb_apply_interface_quirk(chip, iface_no, altno)) + continue; + ++ /* pd may be allocated at snd_usb_get_audioformat_uac3() and ++ * assigned at snd_usb_add_audio_stream(); otherwise it'll be ++ * freed automatically by cleanup at each loop. ++ */ ++ struct snd_usb_power_domain *pd __free(kfree) = NULL; ++ + /* + * Roland audio streaming interfaces are marked with protocols + * 0/1/2, but are UAC 1 compatible. +@@ -1220,23 +1213,16 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + *has_non_pcm = true; + if ((fp->fmt_type == UAC_FORMAT_TYPE_I) == non_pcm) { + audioformat_free(fp); +- kfree(pd); + fp = NULL; +- pd = NULL; + continue; + } + + snd_usb_audioformat_set_sync_ep(chip, fp); + + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); +- if (protocol == UAC_VERSION_3) +- err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); +- else +- err = snd_usb_add_audio_stream(chip, stream, fp); +- ++ err = snd_usb_add_audio_stream(chip, stream, fp, &pd); + if (err < 0) { + audioformat_free(fp); +- kfree(pd); + return err; + } + +diff --git a/sound/usb/stream.h b/sound/usb/stream.h +index d92e18d5818fe..61b9a133da018 100644 +--- a/sound/usb/stream.h ++++ b/sound/usb/stream.h +@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, + + int snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, +- struct audioformat *fp); ++ struct audioformat *fp, ++ struct snd_usb_power_domain **pdptr); + + #endif /* __USBAUDIO_STREAM_H */ + +-- +2.53.0 + diff --git a/queue-7.0/alsa-usb-audio-qcom-fix-incorrect-type-in-enable_aud.patch b/queue-7.0/alsa-usb-audio-qcom-fix-incorrect-type-in-enable_aud.patch new file mode 100644 index 0000000000..a7eabcd77b --- /dev/null +++ b/queue-7.0/alsa-usb-audio-qcom-fix-incorrect-type-in-enable_aud.patch @@ -0,0 +1,42 @@ +From b8e5efa06770077852acf78c74977b719c808bf0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 16:33:11 +0800 +Subject: ALSA: usb-audio: qcom: Fix incorrect type in enable_audio_stream + +From: songxiebing + +[ Upstream commit 292286b2d229fb732421429b027d38ac3f969383 ] + +Fix sparse warning: +sound/usb/qcom/qc_audio_offload.c:943:27: sparse: incorrect type in argument 2 +expected unsigned int val but got snd_pcm_format_t. + +Explicitly cast pcm_format to unsigned int for snd_mask_leave(). + +Fixes: 326bbc348298 ("ALSA: usb-audio: qcom: Introduce QC USB SND offloading support") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604062109.Oxi8JjWW-lkp@intel.com/ +Signed-off-by: songxiebing +Link: https://patch.msgid.link/20260408083311.774173-1-songxiebing@kylinos.cn +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/qcom/qc_audio_offload.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c +index 2ac813d57f4f5..5f993b88448c7 100644 +--- a/sound/usb/qcom/qc_audio_offload.c ++++ b/sound/usb/qcom/qc_audio_offload.c +@@ -948,7 +948,7 @@ static int enable_audio_stream(struct snd_usb_substream *subs, + _snd_pcm_hw_params_any(¶ms); + + m = hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT); +- snd_mask_leave(m, pcm_format); ++ snd_mask_leave(m, (__force unsigned int)pcm_format); + + i = hw_param_interval(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_setinteger(i); +-- +2.53.0 + diff --git a/queue-7.0/amd-pstate-fix-memory-leak-in-amd_pstate_epp_cpu_ini.patch b/queue-7.0/amd-pstate-fix-memory-leak-in-amd_pstate_epp_cpu_ini.patch new file mode 100644 index 0000000000..0a53b992e7 --- /dev/null +++ b/queue-7.0/amd-pstate-fix-memory-leak-in-amd_pstate_epp_cpu_ini.patch @@ -0,0 +1,46 @@ +From cf109ece69bf968de2ebe7791c4c2bd218e7d46d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:17:45 +0530 +Subject: amd-pstate: Fix memory leak in amd_pstate_epp_cpu_init() + +From: Gautham R. Shenoy + +[ Upstream commit beda3b363546a423e4e29a7395e04c0ac4ff677e ] + +On failure to set the epp, the function amd_pstate_epp_cpu_init() +returns with an error code without freeing the cpudata object that was +allocated at the beginning of the function. + +Ensure that the cpudata object is freed before returning from the +function. + +This memory leak was discovered by Claude Opus 4.6 with the aid of +Chris Mason's AI review-prompts +(https://github.com/masoncl/review-prompts/tree/main/kernel). + +Assisted-by: Claude:claude-opus-4.6 review-prompts/linux +Fixes: f9a378ff6443 ("cpufreq/amd-pstate: Set different default EPP policy for Epyc and Ryzen") +Reviewed-by: Mario Limonciello (AMD) +Signed-off-by: Gautham R. Shenoy +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/amd-pstate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c +index 5aa9fcd80cf51..d57969c72c9dc 100644 +--- a/drivers/cpufreq/amd-pstate.c ++++ b/drivers/cpufreq/amd-pstate.c +@@ -1533,7 +1533,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) + + ret = amd_pstate_set_epp(policy, cpudata->epp_default); + if (ret) +- return ret; ++ goto free_cpudata1; + + current_pstate_driver->adjust_perf = NULL; + +-- +2.53.0 + diff --git a/queue-7.0/amd-pstate-update-cppc_req_cached-in-fast_switch-cas.patch b/queue-7.0/amd-pstate-update-cppc_req_cached-in-fast_switch-cas.patch new file mode 100644 index 0000000000..831b56aa4f --- /dev/null +++ b/queue-7.0/amd-pstate-update-cppc_req_cached-in-fast_switch-cas.patch @@ -0,0 +1,45 @@ +From 3b39cc5d84524a5016ecf66ff1231ec0b6a96f66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:17:46 +0530 +Subject: amd-pstate: Update cppc_req_cached in fast_switch case + +From: Gautham R. Shenoy + +[ Upstream commit fcc25a291fbdca2c06c2c6602532050873f0c9de ] + +The function msr_update_perf() does not cache the new value that is +written to MSR_AMD_CPPC_REQ into the variable cpudata->cppc_req_cached +when the update is happening from the fast path. + +Fix that by caching the value everytime the MSR_AMD_CPPC_REQ gets +updated. + +This issue was discovered by Claude Opus 4.6 with the aid of Chris +Mason's AI review-prompts +(https://github.com/masoncl/review-prompts/tree/main/kernel). + +Assisted-by: Claude:claude-opus-4.6 review-prompts/linux +Reviewed-by: Mario Limonciello (AMD) +Fixes: fff395796917 ("cpufreq/amd-pstate: Always write EPP value when updating perf") +Signed-off-by: Gautham R. Shenoy +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/amd-pstate.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c +index d57969c72c9dc..24cdeffbcd40e 100644 +--- a/drivers/cpufreq/amd-pstate.c ++++ b/drivers/cpufreq/amd-pstate.c +@@ -261,7 +261,6 @@ static int msr_update_perf(struct cpufreq_policy *policy, u8 min_perf, + + if (fast_switch) { + wrmsrq(MSR_AMD_CPPC_REQ, value); +- return 0; + } else { + int ret = wrmsrq_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value); + +-- +2.53.0 + diff --git a/queue-7.0/arm-dts-bcm5301x-drop-extra-nand-controller-compatib.patch b/queue-7.0/arm-dts-bcm5301x-drop-extra-nand-controller-compatib.patch new file mode 100644 index 0000000000..399c1138e8 --- /dev/null +++ b/queue-7.0/arm-dts-bcm5301x-drop-extra-nand-controller-compatib.patch @@ -0,0 +1,39 @@ +From f455cdf3389925708a438ef6d87162ecaa857ee4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 10:15:30 +0100 +Subject: ARM: dts: BCM5301X: Drop extra NAND controller compatible + +From: Miquel Raynal + +[ Upstream commit f699e0aa7a1382f52fb6f3e8e26754e7aaad6db6 ] + +Fix the dtbs_check warning introduced when the brcm,brcmnand fallback +compatible got removed for iProc machines. + +Fixes: 4db35366d6dc ("dt-bindings: mtd: brcm,brcmnand: Drop "brcm,brcmnand" compatible for iProc") +Signed-off-by: Miquel Raynal +Acked-by: Rob Herring (Arm) +Acked-by: William Zhang +Link: https://lore.kernel.org/r/20260204091530.624230-1-miquel.raynal@bootlin.com +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/broadcom/bcm-ns.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi +index d0d5f7e52a917..46b650abdb904 100644 +--- a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi ++++ b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi +@@ -479,7 +479,7 @@ thermal: thermal@2c0 { + }; + + nand_controller: nand-controller@18028000 { +- compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1", "brcm,brcmnand"; ++ compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1"; + reg = <0x18028000 0x600>, <0x1811a408 0x600>, <0x18028f00 0x20>; + reg-names = "nand", "iproc-idm", "iproc-ext"; + interrupts = ; +-- +2.53.0 + diff --git a/queue-7.0/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch b/queue-7.0/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch new file mode 100644 index 0000000000..62102a9344 --- /dev/null +++ b/queue-7.0/arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch @@ -0,0 +1,76 @@ +From 2427d405079dc07e7b944b428c7134a441b9625e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 18:12:55 -0500 +Subject: ARM: dts: imx27-eukrea: replace interrupts with interrupts-extended + +From: Frank Li + +[ Upstream commit 0477a6b31e2874e554e3bcfac9883684b8f8ca2d ] + +The property interrupts use default interrupt controllers. But pass down +gpio as phandle. Correct it by use interrupts-extended. + +Fixes: d8cae888aa2bc ("ARM: dts: Add support for the cpuimx27 board from Eukrea and its baseboard") +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi | 8 ++++---- + .../boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +index c7e9235848782..9f0e65526d5f9 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +@@ -106,7 +106,7 @@ uart8250@3,200000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 23 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x200000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -119,7 +119,7 @@ uart8250@3,400000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x400000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -132,7 +132,7 @@ uart8250@3,800000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 27 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x800000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +@@ -145,7 +145,7 @@ uart8250@3,1000000 { + compatible = "ns8250"; + clocks = <&clk14745600>; + fsl,weim-cs-timing = <0x0000d603 0x0d1d0d01 0x00d20000>; +- interrupts = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio2 30 IRQ_TYPE_LEVEL_LOW>; + reg = <3 0x1000000 0x1000>; + reg-shift = <1>; + reg-io-width = <1>; +diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +index d78793601306c..c71f802983304 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts ++++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +@@ -76,7 +76,7 @@ ads7846@0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_touch>; + reg = <0>; +- interrupts = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; ++ interrupts-extended = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; + spi-cpol; + spi-max-frequency = <1500000>; + ti,keep-vref-on; +-- +2.53.0 + diff --git a/queue-7.0/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch b/queue-7.0/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch new file mode 100644 index 0000000000..f1e29e4ac3 --- /dev/null +++ b/queue-7.0/arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch @@ -0,0 +1,46 @@ +From 65bbca3ff160390590540f75047356256f8dea3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 09:25:41 +0100 +Subject: ARM: dts: mediatek: mt7623: fix efuse fallback compatible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafał Miłecki + +[ Upstream commit 5978ff33cc6f0988388a2830dc5cd2ea4e81f36a ] + +Fix following validation error: +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: compatible: 'oneOf' conditional failed, one must be fixed: + ['mediatek,mt7623-efuse', 'mediatek,mt8173-efuse'] is too long + 'mediatek,mt8173-efuse' was expected + 'mediatek,efuse' was expected + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# +arch/arm/boot/dts/mediatek/mt7623a-rfb-emmc.dtb: efuse@10206000: Unevaluated properties are not allowed ('compatible' was unexpected) + from schema $id: http://devicetree.org/schemas/nvmem/mediatek,efuse.yaml# + +Fixes: 43c7a91b4b3a ("arm: dts: mt7623: add efuse nodes to the mt7623.dtsi file") +Signed-off-by: Rafał Miłecki +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/mediatek/mt7623.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi +index 4b1685b939891..71ac2b94c6ba3 100644 +--- a/arch/arm/boot/dts/mediatek/mt7623.dtsi ++++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi +@@ -328,7 +328,7 @@ sysirq: interrupt-controller@10200100 { + + efuse: efuse@10206000 { + compatible = "mediatek,mt7623-efuse", +- "mediatek,mt8173-efuse"; ++ "mediatek,efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch b/queue-7.0/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch new file mode 100644 index 0000000000..03efc98655 --- /dev/null +++ b/queue-7.0/arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch @@ -0,0 +1,40 @@ +From 1126e2a5b2d7441e4f4307a29d7b8709cb25b30c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 19:15:10 +0200 +Subject: ARM: OMAP1: Fix DEBUG_LL and earlyprintk on OMAP16XX + +From: Aaro Koskinen + +[ Upstream commit 7e74b606dd39c46d4378d6f6563f560a00ab8694 ] + +On OMAP16XX, the UART enable bit shifts are written instead of the actual +bits. This breaks the boot when DEBUG_LL and earlyprintk is enabled; +the UART gets disabled and some random bits get enabled. Fix that. + +Fixes: 34c86239b184 ("ARM: OMAP1: clock: Fix early UART rate issues") +Signed-off-by: Aaro Koskinen +Link: https://patch.msgid.link/aca7HnXZ-aCSJPW7@darkstar.musicnaut.iki.fi +Signed-off-by: Kevin Hilman +Signed-off-by: Sasha Levin +--- + arch/arm/mach-omap1/clock_data.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c +index c58d200e4816b..5203b047deac8 100644 +--- a/arch/arm/mach-omap1/clock_data.c ++++ b/arch/arm/mach-omap1/clock_data.c +@@ -700,8 +700,8 @@ int __init omap1_clk_init(void) + /* Make sure UART clocks are enabled early */ + if (cpu_is_omap16xx()) + omap_writel(omap_readl(MOD_CONF_CTRL_0) | +- CONF_MOD_UART1_CLK_MODE_R | +- CONF_MOD_UART3_CLK_MODE_R, MOD_CONF_CTRL_0); ++ (1 << CONF_MOD_UART1_CLK_MODE_R) | ++ (1 << CONF_MOD_UART3_CLK_MODE_R), MOD_CONF_CTRL_0); + #endif + + /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ +-- +2.53.0 + diff --git a/queue-7.0/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch b/queue-7.0/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch new file mode 100644 index 0000000000..70a53adeaa --- /dev/null +++ b/queue-7.0/arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch @@ -0,0 +1,56 @@ +From fd6f9547668a27940a79826bb15e81530bcf6fb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 16:28:18 +0000 +Subject: arm64: cpufeature: Make PMUVer and PerfMon unsigned + +From: James Clark + +[ Upstream commit d1dcc20bcc40efe1f1c71639376c91dafa489222 ] + +On the host, this change doesn't make a difference because the fields +are defined as FTR_EXACT. However, KVM allows userspace to set these +fields for a guest and overrides the type to be FTR_LOWER_SAFE. And +while KVM used to do an unsigned comparison to validate that the new +value is lower than what the hardware provides, since the linked commit +it uses the generic sanitization framework which does a signed +comparison. + +Fix it by defining these fields as unsigned. In theory, without this +fix, userspace could set a higher PMU version than the hardware supports +by providing any value with the top bit set. + +Fixes: c118cead07a7 ("KVM: arm64: Use generic sanitisation for ID_(AA64)DFR0_EL1") +Signed-off-by: James Clark +Reviewed-by: Marc Zyngier +Reviewed-by: Colton Lewis +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/cpufeature.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c +index 32c2dbcc0c641..348197d9b6017 100644 +--- a/arch/arm64/kernel/cpufeature.c ++++ b/arch/arm64/kernel/cpufeature.c +@@ -565,7 +565,7 @@ static const struct arm64_ftr_bits ftr_id_aa64dfr0[] = { + * We can instantiate multiple PMU instances with different levels + * of support. + */ +- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), ++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_AA64DFR0_EL1_PMUVer_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64DFR0_EL1_DebugVer_SHIFT, 4, 0x6), + ARM64_FTR_END, + }; +@@ -709,7 +709,7 @@ static const struct arm64_ftr_bits ftr_id_pfr2[] = { + + static const struct arm64_ftr_bits ftr_id_dfr0[] = { + /* [31:28] TraceFilt */ +- S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), ++ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_EXACT, ID_DFR0_EL1_PerfMon_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MProfDbg_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_MMapTrc_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_DFR0_EL1_CopTrc_SHIFT, 4, 0), +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-amlogic-meson-axg-add-missing-cache-inform.patch b/queue-7.0/arm64-dts-amlogic-meson-axg-add-missing-cache-inform.patch new file mode 100644 index 0000000000..855b62bc1e --- /dev/null +++ b/queue-7.0/arm64-dts-amlogic-meson-axg-add-missing-cache-inform.patch @@ -0,0 +1,41 @@ +From 835e16fbc2694f91a8249a7ebf644c51e8f929d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 16:05:46 +0530 +Subject: arm64: dts: amlogic: meson-axg: Add missing cache information to cpu0 + +From: Anand Moon + +[ Upstream commit 918273be0885362a9a00615b46e03f15f8b55667 ] + +Add missing L1 data and instruction cache parameters to the CPU node 0 +for the Cortex-A53 caches on the Meson AXG SoC. + +Fixes: 3b6ad2a43367 ("arm64: dts: amlogic: Add cache information to the Amlogic AXG SoCS") +Signed-off-by: Anand Moon +Link: https://patch.msgid.link/20260219103548.18392-1-linux.amoon@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index cc72491eaf6f5..f1f53fd98ae25 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -72,6 +72,12 @@ cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + reg = <0x0 0x0>; + enable-method = "psci"; ++ d-cache-line-size = <32>; ++ d-cache-size = <0x8000>; ++ d-cache-sets = <32>; ++ i-cache-line-size = <32>; ++ i-cache-size = <0x8000>; ++ i-cache-sets = <32>; + next-level-cache = <&l2>; + clocks = <&scpi_dvfs 0>; + dynamic-power-coefficient = <140>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch b/queue-7.0/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch new file mode 100644 index 0000000000..be4d40ba91 --- /dev/null +++ b/queue-7.0/arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch @@ -0,0 +1,45 @@ +From 151cc8eff1e26b0ad37b4951ac7902e23a983c89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 09:45:48 +0100 +Subject: arm64: dts: freescale: imx8mp-tqma8mpql-mba8mp-ras314: fix UART1 + RTS/CTS muxing + +From: Nora Schiffer + +[ Upstream commit b8d785a9f360abcd6a6f8f10a2adf222f8494d66 ] + +UART1 operates in DCE mode, but the RTS/CTS pins were incorrectly +configured using the DTE pinmux setting. + +Correct the pinmux to match DCE mode. Switching the RTS and CTS signals +is fine for this board, as UART1 is routed to a pin header. Existing +functionality is unaffected, as RTS/CTS could never have worked with +the incorrect pinmux. + +Fixes: ddabb3ce3f90 ("arm64: dts: freescale: add TQMa8MPQL on MBa8MP-RAS314") +Signed-off-by: Nora Schiffer +Reviewed-by: Alexander Stein +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +index b7f69c92b7748..1665a5030b993 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mp-ras314.dts +@@ -848,8 +848,8 @@ pinctrl_tlv320aic3x04: tlv320aic3x04grp { + pinctrl_uart1: uart1grp { + fsl,pins = , + , +- , +- ; ++ , ++ ; + }; + + pinctrl_uart1_gpio: uart1gpiogrp { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8-apalis-fix-leds-name-collision.patch b/queue-7.0/arm64-dts-imx8-apalis-fix-leds-name-collision.patch new file mode 100644 index 0000000000..d5f8aaabc2 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8-apalis-fix-leds-name-collision.patch @@ -0,0 +1,103 @@ +From d307373208a89ab4e6d2b8b3d38ae5603c02f6c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 11:34:09 +0100 +Subject: arm64: dts: imx8-apalis: Fix LEDs name collision + +From: Francesco Dolcini + +[ Upstream commit 92ab53b9bb2a72581c32073755077af916eb9aee ] + +Ixora boards have multiple instances of status leds, to avoid a name +collision add the function-enumerator property. + +This fixes the following Linux kernel warnings: + + leds-gpio leds: Led green:status renamed to green:status_1 due to name collision + leds-gpio leds: Led red:status renamed to red:status_1 due to name collision + +Fixes: c083131c9021 ("arm64: dts: freescale: add apalis imx8 aka quadmax carrier board support") +Signed-off-by: Francesco Dolcini +Reviewed-by: Frank Li +Reviewed-by: Daniel Baluta +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi | 4 ++++ + arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +index 7022de46b8bff..abb131d247c30 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +@@ -21,6 +21,7 @@ led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; + }; + +@@ -29,6 +30,7 @@ led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; + }; + +@@ -37,6 +39,7 @@ led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; + }; + +@@ -45,6 +48,7 @@ led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +index 12732ed7f8119..a0b452b92b3e6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +@@ -21,6 +21,7 @@ led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 27 GPIO_ACTIVE_HIGH>; + }; + +@@ -29,6 +30,7 @@ led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <1>; + gpios = <&lsio_gpio5 29 GPIO_ACTIVE_HIGH>; + }; + +@@ -37,6 +39,7 @@ led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 20 GPIO_ACTIVE_HIGH>; + }; + +@@ -45,6 +48,7 @@ led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; ++ function-enumerator = <2>; + gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8dxl-evk-use-audio-graph-card2-for-wm89.patch b/queue-7.0/arm64-dts-imx8dxl-evk-use-audio-graph-card2-for-wm89.patch new file mode 100644 index 0000000000..5d612454ef --- /dev/null +++ b/queue-7.0/arm64-dts-imx8dxl-evk-use-audio-graph-card2-for-wm89.patch @@ -0,0 +1,189 @@ +From 9a71ee78b92e34a500ee29aa8a2a80084f21a6bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:37:38 +0800 +Subject: arm64: dts: imx8dxl-evk: Use audio-graph-card2 for wm8960-2 and + wm8960-3 + +From: Shengjiu Wang + +[ Upstream commit e8341b0245736619f8d6a2cc311c9e8ad8e82390 ] + +The sound card wm8960-2 and wm8960-3 only support capture mode for the +reason of connection on the EVK board. But fsl-asoc-card don't support +capture_only setting, the sound card creation will fail. + +fsl-sai 59060000.sai: Missing dma channel for stream: 0 +fsl-sai 59060000.sai: ASoC error (-22): at snd_soc_pcm_component_new() on 59060000.sai +fsl-sai 59070000.sai: Missing dma channel for stream: 0 +fsl-sai 59070000.sai: ASoC error (-22): at snd_soc_pcm_component_new() on 59070000.sai + +so switch to use audio-graph-card2 which supports 'capture_only' +property for wm8960-2 and wm8960-3 cards. + +Fixes: b41c45eb990a ("arm64: dts: imx8dxl-evk: add audio nodes") +Signed-off-by: Shengjiu Wang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8dxl-evk.dts | 114 ++++++++++++++---- + 1 file changed, 90 insertions(+), 24 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts +index 5c68d33e19f22..bc62ae5ca812d 100644 +--- a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts +@@ -259,33 +259,37 @@ sound-wm8960-1 { + }; + + sound-wm8960-2 { +- compatible = "fsl,imx-audio-wm8960"; +- model = "wm8960-audio-2"; +- audio-cpu = <&sai2>; +- audio-codec = <&wm8960_2>; +- audio-routing = "Headphone Jack", "HP_L", +- "Headphone Jack", "HP_R", +- "Ext Spk", "SPK_LP", +- "Ext Spk", "SPK_LN", +- "Ext Spk", "SPK_RP", +- "Ext Spk", "SPK_RN", +- "LINPUT1", "Mic Jack", +- "Mic Jack", "MICB"; ++ compatible = "audio-graph-card2"; ++ label = "wm8960-audio-2"; ++ links = <&sai2_port2>; ++ routing = "Headphones", "HP_L", ++ "Headphones", "HP_R", ++ "Ext Spk", "SPK_LP", ++ "Ext Spk", "SPK_LN", ++ "Ext Spk", "SPK_RP", ++ "Ext Spk", "SPK_RN", ++ "LINPUT1", "Mic Jack", ++ "Mic Jack", "MICB"; ++ widgets = "Headphone", "Headphones", ++ "Speaker", "Ext Spk", ++ "Microphone", "Mic Jack"; + }; + + sound-wm8960-3 { +- compatible = "fsl,imx-audio-wm8960"; +- model = "wm8960-audio-3"; +- audio-cpu = <&sai3>; +- audio-codec = <&wm8960_3>; +- audio-routing = "Headphone Jack", "HP_L", +- "Headphone Jack", "HP_R", +- "Ext Spk", "SPK_LP", +- "Ext Spk", "SPK_LN", +- "Ext Spk", "SPK_RP", +- "Ext Spk", "SPK_RN", +- "LINPUT1", "Mic Jack", +- "Mic Jack", "MICB"; ++ compatible = "audio-graph-card2"; ++ label = "wm8960-audio-3"; ++ links = <&sai3_port2>; ++ routing = "Headphones", "HP_L", ++ "Headphones", "HP_R", ++ "Ext Spk", "SPK_LP", ++ "Ext Spk", "SPK_LN", ++ "Ext Spk", "SPK_RP", ++ "Ext Spk", "SPK_RN", ++ "LINPUT1", "Mic Jack", ++ "Mic Jack", "MICB"; ++ widgets = "Headphone", "Headphones", ++ "Speaker", "Ext Spk", ++ "Microphone", "Mic Jack"; + }; + }; + +@@ -481,6 +485,16 @@ wm8960_2: audio-codec@1a { + DCVDD-supply = <®_audio_1v8>; + SPKVDD1-supply = <®_audio_5v>; + SPKVDD2-supply = <®_audio_5v>; ++ ++ port { ++ capture-only; ++ ++ wm8960_2_ep: endpoint { ++ bitclock-master; ++ frame-master; ++ remote-endpoint = <&sai2_endpoint2>; ++ }; ++ }; + }; + }; + +@@ -510,6 +524,16 @@ wm8960_3: audio-codec@1a { + DCVDD-supply = <®_audio_1v8>; + SPKVDD1-supply = <®_audio_5v>; + SPKVDD2-supply = <®_audio_5v>; ++ ++ port { ++ capture-only; ++ ++ wm8960_3_ep: endpoint { ++ bitclock-master; ++ frame-master; ++ remote-endpoint = <&sai3_endpoint2>; ++ }; ++ }; + }; + }; + +@@ -700,6 +724,27 @@ &sai2 { + pinctrl-0 = <&pinctrl_sai2>; + fsl,sai-asynchronous; + status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sai2_port1: port@1 { ++ reg = <1>; ++ endpoint { /* not used */ }; ++ }; ++ ++ sai2_port2: port@2 { ++ reg = <2>; ++ capture-only; ++ ++ sai2_endpoint2: endpoint { ++ dai-format = "i2s"; ++ remote-endpoint = <&wm8960_2_ep>; ++ system-clock-direction-out; ++ }; ++ }; ++ }; + }; + + &sai3 { +@@ -712,6 +757,27 @@ &sai3 { + pinctrl-0 = <&pinctrl_sai3>; + fsl,sai-asynchronous; + status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sai3_port1: port@1 { ++ reg = <1>; ++ endpoint { /* not used */ }; ++ }; ++ ++ sai3_port2: port@2 { ++ reg = <2>; ++ capture-only; ++ ++ sai3_endpoint2: endpoint { ++ dai-format = "i2s"; ++ remote-endpoint = <&wm8960_3_ep>; ++ system-clock-direction-out; ++ }; ++ }; ++ }; + }; + + &thermal_zones { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch b/queue-7.0/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..c50acee3d5 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch @@ -0,0 +1,48 @@ +From f0805afe5ad9edac74c15c790ce384ce2d9496bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:11 +0800 +Subject: arm64: dts: imx8mm-emtop-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 721dec3ee9ff5231d13a412ff87df63b966d137b ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +While at here, also correct interrupt type as IRQ_TYPE_LEVEL_LOW. + +Fixes: cbd3ef64eb9d1 ("arm64: dts: Add support for Emtop SoM & Baseboard") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +index 67d22d3768aa8..507d1824d99d9 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-emtop-som.dtsi +@@ -60,7 +60,7 @@ pmic@25 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; +- interrupts = <3 IRQ_TYPE_EDGE_RISING>; ++ interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + regulators { + buck1: BUCK1 { +@@ -194,7 +194,7 @@ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 + + pinctrl_pmic: emtop-pmic-grp { + fsl,pins = < +- MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x41 ++ MX8MM_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x141 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch b/queue-7.0/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..55a1e95354 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From c37d370d8501785df50fd0a6c39fcd98351f78ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:13 +0800 +Subject: arm64: dts: imx8mm-tqma8mqml: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 42a9f5a16328ed78a88e0498556965b6c6ec515c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: dfcd1b6f7620e ("arm64: dts: freescale: add initial device tree for TQMa8MQML with i.MX8MM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +index 29b298af0d739..1b5ba3c47164f 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml.dtsi +@@ -292,7 +292,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch b/queue-7.0/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..d4503a5ace --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 037aea57efab7e573e3681775517d2d6299a8a14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 21:00:12 +0800 +Subject: arm64: dts: imx8mn-tqma8mqnl: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 0fb37990774113afd943eaa91323679388584b6d ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: 3e56e354db6d3 ("arm64: dts: freescale: add initial device tree for TQMa8MQNL with i.MX8MN") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +index 31a3ca137e636..48a687926aa1b 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +@@ -283,7 +283,7 @@ pinctrl_i2c1_gpio: i2c1gpiogrp { + }; + + pinctrl_pmic: pmicgrp { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-aristainetos3a-som-v1-correct-pad-s.patch b/queue-7.0/arm64-dts-imx8mp-aristainetos3a-som-v1-correct-pad-s.patch new file mode 100644 index 0000000000..c93382a5eb --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-aristainetos3a-som-v1-correct-pad-s.patch @@ -0,0 +1,38 @@ +From 934f986ebc8839d557dfc77bc46c4af14050b836 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:11 +0800 +Subject: arm64: dts: imx8mp-aristainetos3a-som-v1: Correct PAD settings for + PMIC_nINT + +From: Peng Fan + +[ Upstream commit e6d2d8e49ca34bb39126a69128794d08ffd7c83e ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: eead8f3536d5c ("arm64: dts: imx8mp: add aristainetos3 board support") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi +index f654d866e58c0..e7666e54310be 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-aristainetos3a-som-v1.dtsi +@@ -903,7 +903,7 @@ MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20 0x41 + + pinctrl_pmic: aristainetos3-pmic-grp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch b/queue-7.0/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch new file mode 100644 index 0000000000..c98819c6c9 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch @@ -0,0 +1,38 @@ +From cfbb7bd32b1a7f10f285b311c56b22b11dc600aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:16 +0800 +Subject: arm64: dts: imx8mp-data-modul-edm-sbc: Correct PAD settings for + PMIC_nINT + +From: Peng Fan + +[ Upstream commit 8ff145577e93f312ff398cb950ee3bd44835f5be ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 562d222f23f0f ("arm64: dts: imx8mp: Add support for Data Modul i.MX8M Plus eDM SBC") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +index 7e46537a22a01..cb28cf1cdd23f 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +@@ -1001,7 +1001,7 @@ MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_PDM_BIT_STREAM00 0x0 + pinctrl_pmic: pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch b/queue-7.0/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch new file mode 100644 index 0000000000..2d26bd9550 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch @@ -0,0 +1,42 @@ +From 8b9220a3479c0ba142a1b933bd0471f693a7fabe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:05 +0800 +Subject: arm64: dts: imx8mp-debix-model-a: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 3b778178997aee24537b521a8cb60970bc1ce01c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there is interrupt storm for i.MX8MP DEBIX Model A. Per schematic, there +is no on board PULL-UP resistors for GPIO1_IO03, so need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: c86d350aae68e ("arm64: dts: Add device tree for the Debix Model A Board") +Reported-by: Laurent Pinchart +Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/ +Reviewed-by: Laurent Pinchart +Tested-by: Laurent Pinchart +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +index 9422beee30b29..201cf7f5eb0ea 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +@@ -440,7 +440,7 @@ MX8MP_IOMUXC_SAI5_RXC__I2C6_SDA 0x400001c3 + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch b/queue-7.0/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..fb00d43177 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch @@ -0,0 +1,56 @@ +From b6659f20db587705d64d111fb4a4e3d84a94d30e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:06 +0800 +Subject: arm64: dts: imx8mp-debix-som-a: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 2ea7872048a179b0ea8dadc67771961df3f0fc4a ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there is interrupt storm for i.MX8MP DEBIX SOM A. Need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: 21baf0b47f81b ("arm64: dts: freescale: Add DEBIX SOM A and SOM A I/O Board support") +Reported-by: Laurent Pinchart +Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/ +Reported-by: Kieran Bingham +Closes: https://lore.kernel.org/imx/20260324194353.GB2352505@killaraus.ideasonboard.com/T/#m9a07fdc75496369a7d76d52c5e34ed140dcabfe3 +Signed-off-by: Peng Fan +Reviewed-by: Kieran Bingham +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts | 2 +- + arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +index 04619a7229065..1471ff361b54c 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +@@ -499,7 +499,7 @@ MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x140 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +index 91094c2277443..b31e8fe95ca74 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +@@ -241,7 +241,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch b/queue-7.0/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch new file mode 100644 index 0000000000..680c67f6a6 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch @@ -0,0 +1,37 @@ +From 9f02c73e7e95a429c6253de2a9c986421f4ea449 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:15 +0800 +Subject: arm64: dts: imx8mp-dhcom-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit f9ed5afc988da3e22543725e35be6addbb0497bc ] + +PMIC_nINT is low level triggered, but the current PAD settings is +PE=0,PUE=0,FSEL_1_FAST_SLEW_RATE=1,SION=1. So PAD needs to be configured +as PULL UP with PULL Enable, no need SION. Correct it. + +Fixes: 8d6712695bc8e ("arm64: dts: imx8mp: Add support for DH electronics i.MX8M Plus DHCOM and PDK2") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +index f8303b7e2bd22..0a6a60670f762 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +@@ -989,7 +989,7 @@ MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20 0x22 + pinctrl_pmic: dhcom-pmic-grp { + fsl,pins = < + /* PMIC_nINT */ +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40000090 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-edm-g-correct-pad-settings-for-pmic.patch b/queue-7.0/arm64-dts-imx8mp-edm-g-correct-pad-settings-for-pmic.patch new file mode 100644 index 0000000000..2d85cce113 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-edm-g-correct-pad-settings-for-pmic.patch @@ -0,0 +1,37 @@ +From d619da5d05cc434ab66e7f3eb9551f2a9ef912d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:10 +0800 +Subject: arm64: dts: imx8mp-edm-g: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit c46c5a54443440ce0f71de9f4df9dd860f5c2afd ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: 95e882c021c8b ("arm64: dts: imx8mp: Add TechNexion EDM-G-IMX8M-PLUS SOM on WB-EDM-G carrier board") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi +index 3f1e0837f349f..91b87a7248dd1 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-edm-g.dtsi +@@ -563,7 +563,7 @@ MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x41 /* PCIE RST */ + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch b/queue-7.0/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch new file mode 100644 index 0000000000..315c8c59a1 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch @@ -0,0 +1,43 @@ +From e0e2f0c9b39907cffa2fc3bfcf3346a82d8c1af0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Feb 2026 15:34:53 +0800 +Subject: arm64: dts: imx8mp-evk: Enable pull select bit for PCIe regulator + GPIO (M.2 W_DISABLE1) + +From: Sherry Sun + +[ Upstream commit d1e7eab6033f9885a02c4b4e8f09e34d8e9d21ab ] + +The current pin configuration for MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 +sets the weak pull-up but does not enable the pull select field. +Bit 8 in the IOMUX register must be set in order for the weak pull-up +to actually take effect. + +Update the pinctrl setting from 0x40 to 0x140 to enable both the pull +select and the weak pull-up, ensuring the line behaves as expected. + +Fixes: d50650500064 ("arm64: dts: imx8mp-evk: Add PCIe support") +Signed-off-by: Sherry Sun +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +index b256be710ea12..31f03436137dc 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +@@ -1064,7 +1064,7 @@ MX8MP_IOMUXC_SD1_DATA5__GPIO2_IO07 0x40 + + pinctrl_pcie0_reg: pcie0reggrp { + fsl,pins = < +- MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x40 ++ MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06 0x140 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-evk-specify-adv7535-register-addres.patch b/queue-7.0/arm64-dts-imx8mp-evk-specify-adv7535-register-addres.patch new file mode 100644 index 0000000000..c7d37908bb --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-evk-specify-adv7535-register-addres.patch @@ -0,0 +1,39 @@ +From 14910d0805e51d3f28bbe6dfd30c1c48ac7006e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:52:03 +0800 +Subject: arm64: dts: imx8mp-evk: Specify ADV7535 register addresses + +From: Liu Ying + +[ Upstream commit bfb91be0eba426913f2950ed8b3d963f0de53fcc ] + +MIPI DSI to HDMI bridge ADV7535 CEC default register address is 0x3c +on an I2C bus. And, OV5640 camera uses the same address on the same +I2C bus. To resolve this conflict, use 0x3b as ADV7535 CEC register +address by specifying all ADV7535 register addresses. + +Fixes: 6f6c18cba16f ("arm64: dts: imx8mp-evk: add camera ov5640 and related nodes") +Signed-off-by: Liu Ying +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +index 31f03436137dc..f981504f019d1 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +@@ -595,7 +595,8 @@ ov5640_mipi_0_ep: endpoint { + + hdmi@3d { + compatible = "adi,adv7535"; +- reg = <0x3d>; ++ reg = <0x3d>, <0x3f>, <0x3b>, <0x38>; ++ reg-names = "main", "edid", "cec", "packet"; + interrupt-parent = <&gpio1>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + adi,dsi-lanes = <4>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-hummingboard-pulse-cubox-m-fix-vmmc.patch b/queue-7.0/arm64-dts-imx8mp-hummingboard-pulse-cubox-m-fix-vmmc.patch new file mode 100644 index 0000000000..9230e4cc04 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-hummingboard-pulse-cubox-m-fix-vmmc.patch @@ -0,0 +1,54 @@ +From 419b68972b7f293ccdbca9f1fe9fc672fbbba1bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 18:36:31 +0200 +Subject: arm64: dts: imx8mp-hummingboard-pulse/cubox-m: fix vmmc gpio polarity + +From: Josua Mayer + +[ Upstream commit 70ecea46d36b3b0ddcbe71f9cde8d0df00c11f87 ] + +Fix the polarity in vmmc regulator node for the gpio from active-high to +active-low. This is a cosmetic change as regulator default to active-low +unless property enable-active-high was also specified - ignoring the +flag on gpio handle. + +Fixes: a009c0c66ecb ("arm64: dts: add description for solidrun imx8mp som and cubox-m") +Fixes: 2a222aa2bee9 ("arm64: dts: add description for solidrun imx8mp hummingboard variants") +Reviewed-by: Frank Li +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts | 2 +- + .../boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts b/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts +index 8290f187b79fd..7bc213499f094 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-cubox-m.dts +@@ -68,7 +68,7 @@ vmmc: regulator-mmc { + regulator-name = "vmmc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +- gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; ++ gpio = <&gpio2 19 GPIO_ACTIVE_LOW>; + startup-delay-us = <250>; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi +index fa7cb9759d01c..0b4e5f300eb16 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-common.dtsi +@@ -73,7 +73,7 @@ vmmc: regulator-mmc { + regulator-name = "vmmc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +- gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; ++ gpio = <&gpio2 19 GPIO_ACTIVE_LOW>; + startup-delay-us = <250>; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-hummingboard-pulse-fix-mini-hdmi-ds.patch b/queue-7.0/arm64-dts-imx8mp-hummingboard-pulse-fix-mini-hdmi-ds.patch new file mode 100644 index 0000000000..997621079a --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-hummingboard-pulse-fix-mini-hdmi-ds.patch @@ -0,0 +1,61 @@ +From 432ab4429d6c84e1def204b0aefda4a2938f1735 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 18:36:32 +0200 +Subject: arm64: dts: imx8mp-hummingboard-pulse: fix mini-hdmi dsi port + reference + +From: Josua Mayer + +[ Upstream commit 1d1d14d4253e6f373c247e67f3716768910be81e ] + +imx8mp.dtsi includes a default port@1 node with an empty placeholder +endpoint intended for linking to a dsi bridge or panel. + +HummingBoard Pulse mini-hdmi dtsi described a new endpoint node with a +different label attached. + +This duplicate label causes confusion and is suspected to also cause +errors during dsi_attach. + +Remove the duplicate node and link to the one defined in soc dtsi. +Further remove the unnecessary attach-bridge property. + +Fixes: 2a222aa2bee9 ("arm64: dts: add description for solidrun imx8mp hummingboard variants") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../imx8mp-hummingboard-pulse-mini-hdmi.dtsi | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi +index 46916ddc05335..0e5f4607c7c1b 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-hummingboard-pulse-mini-hdmi.dtsi +@@ -41,7 +41,7 @@ port@0 { + reg = <0>; + + adv7535_from_dsim: endpoint { +- remote-endpoint = <&dsim_to_adv7535>; ++ remote-endpoint = <&mipi_dsi_out>; + }; + }; + +@@ -71,11 +71,8 @@ &lcdif1 { + &mipi_dsi { + samsung,esc-clock-frequency = <10000000>; + status = "okay"; ++}; + +- port@1 { +- dsim_to_adv7535: endpoint { +- remote-endpoint = <&adv7535_from_dsim>; +- attach-bridge; +- }; +- }; ++&mipi_dsi_out { ++ remote-endpoint = <&adv7535_from_dsim>; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch b/queue-7.0/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch new file mode 100644 index 0000000000..d3309034d1 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch @@ -0,0 +1,37 @@ +From ff34b08f4b51172cbbe365b0dfa0a425eac26ce8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:09 +0800 +Subject: arm64: dts: imx8mp-icore-mx8mp: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit ea8c90f5c7ceeb6657a8fe564aa7b190dce298a6 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: eefe06b295087 ("arm64: dts: imx8mp: Add Engicam i.Core MX8M Plus SoM") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +index a6319824ea2eb..69558ffefa9a6 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp.dtsi +@@ -132,7 +132,7 @@ MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x41 ++ MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-kontron-drop-vmmc-supply-to-fix-sd-.patch b/queue-7.0/arm64-dts-imx8mp-kontron-drop-vmmc-supply-to-fix-sd-.patch new file mode 100644 index 0000000000..6debf967bc --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-kontron-drop-vmmc-supply-to-fix-sd-.patch @@ -0,0 +1,40 @@ +From 2ba0691602339a75aeea955b2b2410d5b15ea848 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:36:17 +0100 +Subject: arm64: dts: imx8mp-kontron: Drop vmmc-supply to fix SD card on SMARC + eval carrier + +From: Frieder Schrempf + +[ Upstream commit d2ce84eecf081056b1d18d7524de52f849281ba7 ] + +The SMARC evaluation carrier provides an SD card power switch that +complies with the OSM standard definition. The OSM base devicetree +already describes this correctly. + +Stop overriding the vmmc-supply in the board devicetree and rely on +the definition from the OSM base DTS instead to fix the power supply +configuration for the SD card. + +Fixes: 6fe1ced5ccab7 ("arm64: dts: Add support for Kontron i.MX8MP SMARC module and eval carrier") +Signed-off-by: Frieder Schrempf +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts +index 2173a36ff6917..74d620dd06b7b 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts +@@ -249,6 +249,5 @@ &usb3_phy1 { + }; + + &usdhc2 { +- vmmc-supply = <®_vdd_3v3>; + status = "okay"; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-kontron-fix-boot-order-for-pmic-and.patch b/queue-7.0/arm64-dts-imx8mp-kontron-fix-boot-order-for-pmic-and.patch new file mode 100644 index 0000000000..a0b4c76812 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-kontron-fix-boot-order-for-pmic-and.patch @@ -0,0 +1,48 @@ +From b9414bea5ebd7d04212700cc332633cebe3fa844 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 09:57:43 +0100 +Subject: arm64: dts: imx8mp-kontron: Fix boot order for PMIC and RTC + +From: Annette Kobou + +[ Upstream commit 130d90114c5255a7a729158da8fd8298a02017f1 ] + +The PMIC provides a level-shifter for the I2C lines to the RTC. As the +level shifter needs to be enabled before the RTC can be accessed, make sure +that the PMIC driver is probed first. + +As the PMIC also provides the supply voltage for the RTC through the 3.3V +regulator, simply express this in the DT to create the required dependency. + +Avoid sporadic boot hangs that occurred when the RTC was accessed before +the level-shifter was enabled. + +Fixes: 946ab10e3f40f ("arm64: dts: Add support for Kontron OSM-S i.MX8MP SoM and BL carrier board") +Signed-off-by: Annette Kobou +Signed-off-by: Frieder Schrempf +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi +index b97bfeb1c30f8..bc1a261bb000e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi +@@ -330,6 +330,12 @@ rv3028: rtc@52 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rtc>; + interrupts-extended = <&gpio3 24 IRQ_TYPE_LEVEL_LOW>; ++ /* ++ * While specifying the vdd-supply is normally not strictly necessary, ++ * here it also makes sure that the PMIC driver enables the level- ++ * shifter for the RTC before the RTC is probed. ++ */ ++ vdd-supply = <®_vdd_3v3>; + }; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-kontron-fix-touch-reset-configurati.patch b/queue-7.0/arm64-dts-imx8mp-kontron-fix-touch-reset-configurati.patch new file mode 100644 index 0000000000..bb6cf59941 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-kontron-fix-touch-reset-configurati.patch @@ -0,0 +1,71 @@ +From 1e357ca135e28f11ac4a9d9e06b6a07af776d771 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 11:36:16 +0100 +Subject: arm64: dts: imx8mp-kontron: Fix touch reset configuration on DL + devices + +From: Frieder Schrempf + +[ Upstream commit 058c53476dde9937877e93d964a283bbb5e1e4c7 ] + +The reset signal needs a pullup, but there is no hardware pullup. +As a workaround, enable the internal pullup to fix the touchscreen. + +As this deviates from the default generic GPIO settings in the OSM +devicetree, add a new node for the touch pinctrl and redefine the +generic gpio1 pinctrl. + +Fixes: 946ab10e3f40f ("arm64: dts: Add support for Kontron OSM-S i.MX8MP SoM and BL carrier board") +Signed-off-by: Frieder Schrempf +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../boot/dts/freescale/imx8mp-kontron-dl.dtso | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso b/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso +index a3cba41d2b531..7131e9a499ae1 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso ++++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso +@@ -77,6 +77,8 @@ &i2c1 { + touchscreen@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_touch>; + interrupt-parent = <&gpio1>; + interrupts = <6 8>; + irq-gpios = <&gpio1 6 0>; +@@ -98,6 +100,16 @@ &lvds_bridge { + status = "okay"; + }; + ++/* redefine to remove touch controller GPIOs */ ++&pinctrl_gpio1 { ++ fsl,pins = < ++ MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00 0x19 /* GPIO_A_0 */ ++ MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x19 /* GPIO_A_1 */ ++ MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05 0x19 /* GPIO_A_2 */ ++ MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08 0x19 /* GPIO_A_5 */ ++ >; ++}; ++ + &pwm1 { + status = "okay"; + }; +@@ -108,4 +120,11 @@ pinctrl_panel_stby: panelstbygrp { + MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28 0x19 + >; + }; ++ ++ pinctrl_touch: touchgrp { ++ fsl,pins = < ++ MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06 0x19 ++ MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x150 ++ >; ++ }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch b/queue-7.0/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch new file mode 100644 index 0000000000..6b27ee16ce --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch @@ -0,0 +1,38 @@ +From be0180fa84401286382eb1d32933050cc66924c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:07 +0800 +Subject: arm64: dts: imx8mp-navqp: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 741d6ac1a2a2e0f3e2cae5eef3516cdd75119e83 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there will be interrupt storm for i.MX8MP NAVQP. Per schematic, there +is no on board PULL-UP resistors for GPIO1_IO03, so need to set PAD +PUE and PU together to make pull up work properly. + +Fixes: 682729a9d506d ("arm64: dts: freescale: Add device tree for Emcraft Systems NavQ+ Kit") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-navqp.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts +index 4a4f7c1adc23f..9dedb9f11145e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts +@@ -356,7 +356,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicgrp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-nitrogen-som-correct-pad-settings-f.patch b/queue-7.0/arm64-dts-imx8mp-nitrogen-som-correct-pad-settings-f.patch new file mode 100644 index 0000000000..9e35f6ea86 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-nitrogen-som-correct-pad-settings-f.patch @@ -0,0 +1,37 @@ +From d30ab43a64ce201c5b30b51552fa61b70e652d5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:12 +0800 +Subject: arm64: dts: imx8mp-nitrogen-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 16611eda2c7584a1a7d6f80511d825e5108f026c ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: ab4d874c9f44e ("arm64: dts: imx8mp: Add device tree for Nitrogen8M Plus ENC Carrier Board") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi +index f658309612eff..8465b36d440ae 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-som.dtsi +@@ -296,7 +296,7 @@ MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < +- MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00 0x41 ++ MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-sr-som-correct-pad-settings-for-pmi.patch b/queue-7.0/arm64-dts-imx8mp-sr-som-correct-pad-settings-for-pmi.patch new file mode 100644 index 0000000000..04999ce683 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-sr-som-correct-pad-settings-for-pmi.patch @@ -0,0 +1,47 @@ +From ea7a729b9ff956e23379be612cda328c31714c95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:13 +0800 +Subject: arm64: dts: imx8mp-sr-som: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit 695a476275cfb9c798a696aeaa43967701d5c78a ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: a009c0c66ecb4 ("arm64: dts: add description for solidrun imx8mp som and cubox-m") +Signed-off-by: Peng Fan +Reviewed-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi +index 3cdb0bc0ab721..c3f7daa773eaf 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mp-sr-som.dtsi +@@ -174,7 +174,7 @@ pmic: pmic@25 { + pinctrl-0 = <&pmic_pins>; + pinctrl-names = "default"; + interrupt-parent = <&gpio1>; +- interrupts = <3 GPIO_ACTIVE_LOW>; ++ interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + nxp,i2c-lt-enable; + + regulators { +@@ -417,7 +417,7 @@ MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x160 + + pmic_pins: pinctrl-pmic-grp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8mp-ultra-mach-sbc-correct-pad-settings.patch b/queue-7.0/arm64-dts-imx8mp-ultra-mach-sbc-correct-pad-settings.patch new file mode 100644 index 0000000000..0203a0c792 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8mp-ultra-mach-sbc-correct-pad-settings.patch @@ -0,0 +1,46 @@ +From a500e1f18b99baec339eb528132f6150761626c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:28:14 +0800 +Subject: arm64: dts: imx8mp-ultra-mach-sbc: Correct PAD settings for PMIC_nINT + +From: Peng Fan + +[ Upstream commit daaf41ee72fb5fad936e7051a015cccae9b33937 ] + +With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"), +there might be interrupt storm for this board. Need to set PAD PUE and PU +together to make pull up work properly. + +Fixes: d1c1400bd3b8b ("arm64: dts: imx8mp: Add initial support for Ultratronik imx8mp-ultra-mach-sbc board") +Signed-off-by: Peng Fan +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts +index 9ecec1a418781..3e6f9c88cc200 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-ultra-mach-sbc.dts +@@ -275,7 +275,7 @@ pmic@25 { + reg = <0x25>; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; +- interrupts = <3 GPIO_ACTIVE_LOW>; ++ interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + /* + * i.MX 8M Plus Data Sheet for Consumer Products +@@ -739,7 +739,7 @@ MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x40 /* NFC_INT */ + + pinctrl_pmic: pmic-grp { + fsl,pins = < +- MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x40 /* #PMIC_INT */ ++ MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 /* #PMIC_INT */ + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch b/queue-7.0/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch new file mode 100644 index 0000000000..b1cabf65f2 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch @@ -0,0 +1,57 @@ +From 414c939f7428c706940a3bdb5d46822dd9e63665 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:04:58 +0800 +Subject: arm64: dts: imx8qm-mek: switch Type-C connector power-role to dual + +From: Xu Yang + +[ Upstream commit e3d3d19d1c0050789a4813ce836a641a3387d916 ] + +When attach to PC Type-A port, the USB device controller does not function +at all. Because it is configured as source-only and a Type-A port doesn't +support PD capability, a data role swap is impossible. + +Actually, PTN5110THQ is configured for Source role only at POR, but after +POR it can operate as a DRP (Dual-Role Power). By switching the power-role +to dual, the port can operate as a sink and enter device mode when attach +to Type-A port. + +Since the board design uses EN_SRC to control the 5V VBUS path and EN_SNK +to control the 12V VBUS output, to avoid outputting a higher VBUS when in +sink role, we set the operation current limit to 0mA so that SW will not +control EN_SNK at all. + +Fixes: b237975b2cd58 ("arm64: dts: imx8qm-mek: add usb 3.0 and related type C nodes") +Signed-off-by: Xu Yang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8qm-mek.dts | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +index dadc136aec6e6..011a89d85961d 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts ++++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +@@ -611,9 +611,17 @@ ptn5110: tcpc@51 { + usb_con1: connector { + compatible = "usb-c-connector"; + label = "USB-C"; +- power-role = "source"; ++ power-role = "dual"; + data-role = "dual"; ++ try-power-role = "sink"; + source-pdos = ; ++ /* ++ * Set operational current to 0mA as we don't want EN_SNK ++ * enable 12V VBUS switch when it work as a sink. ++ */ ++ sink-pdos = ; ++ op-sink-microwatt = <0>; ++ self-powered; + + ports { + #address-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch b/queue-7.0/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch new file mode 100644 index 0000000000..29ca48e0a2 --- /dev/null +++ b/queue-7.0/arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch @@ -0,0 +1,57 @@ +From d65ff50c510d336afa6ff3f7c2fd0605abf4a130 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:04:59 +0800 +Subject: arm64: dts: imx8qxp-mek: switch Type-C connector power-role to dual + +From: Xu Yang + +[ Upstream commit 825b8c7e1d2918d89eb378b761530d1e51dba82e ] + +When attach to PC Type-A port, the USB device controller does not function +at all. Because it is configured as source-only and a Type-A port doesn't +support PD capability, a data role swap is impossible. + +Actually, PTN5110THQ is configured for Source role only at POR, but after +POR it can operate as a DRP (Dual-Role Power). By switching the power-role +to dual, the port can operate as a sink and enter device mode when attach +to Type-A port. + +Since the board design uses EN_SRC to control the 5V VBUS path and EN_SNK +to control the 12V VBUS output, to avoid outputting a higher VBUS when in +sink role, we set the operation current limit to 0mA so that SW will not +control EN_SNK at all. + +Fixes: 2faf4ebcee2e5 ("arm64: dts: freescale: imx8qxp-mek: enable cadence usb3") +Signed-off-by: Xu Yang +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +index 40a0bc9f4e848..623169f7ddb5f 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts ++++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +@@ -566,9 +566,17 @@ ptn5110: tcpc@50 { + usb_con1: connector { + compatible = "usb-c-connector"; + label = "USB-C"; +- power-role = "source"; ++ power-role = "dual"; + data-role = "dual"; ++ try-power-role = "sink"; + source-pdos = ; ++ /* ++ * Set operational current to 0mA as we don't want EN_SNK ++ * enable 12V VBUS switch when it work as a sink. ++ */ ++ sink-pdos = ; ++ op-sink-microwatt = <0>; ++ self-powered; + + ports { + #address-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx91-11x11-evk-change-usdhc-tuning-step-f.patch b/queue-7.0/arm64-dts-imx91-11x11-evk-change-usdhc-tuning-step-f.patch new file mode 100644 index 0000000000..30c56ae3a2 --- /dev/null +++ b/queue-7.0/arm64-dts-imx91-11x11-evk-change-usdhc-tuning-step-f.patch @@ -0,0 +1,56 @@ +From 55b74bcda158fc5e9b4d601143567f39cda5ef4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 19:23:10 +0800 +Subject: arm64: dts: imx91-11x11-evk: change usdhc tuning step for eMMC and SD + +From: Luke Wang + +[ Upstream commit 5ab0c76df2403137a6d0fb27a55e03cedf47f44c ] + +During system resume, the following errors occurred: + + [ 430.638625] mmc1: error -84 writing Cache Enable bit + [ 430.643618] mmc1: error -84 doing runtime resume + +For eMMC and SD, there are two tuning pass windows and the gap between +those two windows may only have one cell. If tuning step > 1, the gap may +just be skipped and host assumes those two windows as a continuous +windows. This will cause a wrong delay cell near the gap to be selected. + +Set the tuning step to 1 to avoid selecting the wrong delay cell. + +For SDIO, the gap is sufficiently large, so the default tuning step does +not cause this issue. + +Fixes: 6772c4cffd87 ("arm64: dts: freescale: add i.MX91 11x11 EVK basic support") +Signed-off-by: Luke Wang +Reviewed-by: Frank Li +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts +index 03f460d62f7a5..6a066a0d86bc2 100644 +--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts +@@ -514,6 +514,7 @@ &usdhc1 { + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ fsl,tuning-step = <1>; + status = "okay"; + }; + +@@ -528,6 +529,7 @@ &usdhc2 { + pinctrl-3 = <&pinctrl_usdhc2_sleep>, <&pinctrl_usdhc2_gpio_sleep>; + pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; + vmmc-supply = <®_usdhc2_vmmc>; ++ fsl,tuning-step = <1>; + status = "okay"; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-imx91-remove-tmu-s-superfluous-sensor-id.patch b/queue-7.0/arm64-dts-imx91-remove-tmu-s-superfluous-sensor-id.patch new file mode 100644 index 0000000000..287860eb47 --- /dev/null +++ b/queue-7.0/arm64-dts-imx91-remove-tmu-s-superfluous-sensor-id.patch @@ -0,0 +1,38 @@ +From 122b5b3fc1f20f60c96a99a0a8412fba828c3917 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 17:42:22 +0100 +Subject: arm64: dts: imx91: Remove TMU's superfluous sensor ID + +From: Alexander Stein + +[ Upstream commit 53a0485304f11f5371fddf9fb06b95268154bf82 ] + +Currently a sensor ID is added to the reference, but +thermal-sensor@44482000 has #thermal-sensor-cells = <0>, so parsing fails. +This also has the effect that other hwmon sensors (jc42) fail to probe. +Fix this by removing the superfluous sensor ID. + +Fixes: f0ed0e844452 ("arm64: dts: imx91: Add thermal-sensor and thermal-zone support") +Signed-off-by: Alexander Stein +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/imx91.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/freescale/imx91.dtsi b/arch/arm64/boot/dts/freescale/imx91.dtsi +index f075592bfc01f..d63569b39bbc5 100644 +--- a/arch/arm64/boot/dts/freescale/imx91.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx91.dtsi +@@ -11,7 +11,7 @@ thermal-zones { + cpu-thermal { + polling-delay-passive = <250>; + polling-delay = <2000>; +- thermal-sensors = <&tmu 0>; ++ thermal-sensors = <&tmu>; + + trips { + cpu_alert: cpu-alert { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch b/queue-7.0/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch new file mode 100644 index 0000000000..3a34a8b5d4 --- /dev/null +++ b/queue-7.0/arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch @@ -0,0 +1,99 @@ +From c8b099dcf683a1eaa56f3eeff980ca149fb954f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:59 +0100 +Subject: arm64: dts: lx2160a: add sda gpio references for i2c bus recovery + +From: Josua Mayer + +[ Upstream commit 89ea0dbd701f89805499d26bd90657468c789545 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +In particular i2c sda/scl pins are always configured together. Therefore +bus recovery may control both sda and scl. + +When pinmux nodes and bus recovery was enabled originally for LX2160, +only the scl-gpios were added to the i2c controller nodes. + +Add references to sda-gpios for each i2c controller. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 28500e8873909..53b9c5f1f1935 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -753,6 +753,7 @@ i2c0: i2c@2000000 { + pinctrl-0 = <&i2c0_pins>; + pinctrl-1 = <&gpio0_3_2_pins>; + scl-gpios = <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -769,6 +770,7 @@ i2c1: i2c@2010000 { + pinctrl-0 = <&i2c1_pins>; + pinctrl-1 = <&gpio0_31_30_pins>; + scl-gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -785,6 +787,7 @@ i2c2: i2c@2020000 { + pinctrl-0 = <&i2c2_pins>; + pinctrl-1 = <&gpio0_29_28_pins>; + scl-gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 28 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -801,6 +804,7 @@ i2c3: i2c@2030000 { + pinctrl-0 = <&i2c3_pins>; + pinctrl-1 = <&gpio0_27_26_pins>; + scl-gpios = <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -817,6 +821,7 @@ i2c4: i2c@2040000 { + pinctrl-0 = <&i2c4_pins>; + pinctrl-1 = <&gpio0_25_24_pins>; + scl-gpios = <&gpio0 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -833,6 +838,7 @@ i2c5: i2c@2050000 { + pinctrl-0 = <&i2c5_pins>; + pinctrl-1 = <&gpio0_23_22_pins>; + scl-gpios = <&gpio0 23 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -849,6 +855,7 @@ i2c6: i2c@2060000 { + pinctrl-0 = <&i2c6_i2c7_pins>; + pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio1 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +@@ -865,6 +872,7 @@ i2c7: i2c@2070000 { + pinctrl-0 = <&i2c6_i2c7_pins>; + pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; ++ sda-gpios = <&gpio1 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch b/queue-7.0/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch new file mode 100644 index 0000000000..7ebdf9c7d2 --- /dev/null +++ b/queue-7.0/arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch @@ -0,0 +1,55 @@ +From 65f066b0500ba083deb323c50582dedddbc331e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:56 +0100 +Subject: arm64: dts: lx2160a: change i2c0 (iic1) pinmux mask to one bit + +From: Josua Mayer + +[ Upstream commit 7a3cc49ad1fc8d063abb7f5de8f1b981b99d2978 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +The first i2c bus (called IIC1 in reference manual) is configured through +field IIC1_PMUX in register RCWSR14 bit 10 which is described in the +reference manual as a single bit, unlike the other i2c buses. + +Change the bitmask for the pinmux nodes from 0x7 to 0x1 to ensure only +single bit is modified. + +Further change the zero in the same line to hexadecimal format for +consistency. + +Align with documentation by avoiding writes to reserved bits. No functional +change, as writing the extra two reserved bits is not known to cause +issues. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index af74e77efabc5..d5bb55df03216 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1794,11 +1794,11 @@ i2c7_scl_gpio: i2c7-scl-gpio-pins { + }; + + i2c0_scl: i2c0-scl-pins { +- pinctrl-single,bits = <0x8 0 (0x7 << 10)>; ++ pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; + + i2c0_scl_gpio: i2c0-scl-gpio-pins { +- pinctrl-single,bits = <0x8 (0x1 << 10) (0x7 << 10)>; ++ pinctrl-single,bits = <0x8 (0x1 << 10) (0x1 << 10)>; + }; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch b/queue-7.0/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch new file mode 100644 index 0000000000..82884deb10 --- /dev/null +++ b/queue-7.0/arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch @@ -0,0 +1,74 @@ +From 6c7ca41d7d54d7813535fea4fe2d20eca58b3f49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:41:00 +0100 +Subject: arm64: dts: lx2160a: change zeros to hexadecimal in pinmux nodes + +From: Josua Mayer + +[ Upstream commit 03241620d2b9915c9e3463dbc56e9eb95ad43c08 ] + +Replace some stray zeros from decimal to hexadecimal format within +pinmux nodes. + +No functional change intended. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 53b9c5f1f1935..d266bf96e2c6a 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1722,7 +1722,7 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,function-mask = <0x7>; + + i2c1_pins: iic2-i2c-pins { +- pinctrl-single,bits = <0x0 0 0x7>; ++ pinctrl-single,bits = <0x0 0x0 0x7>; + }; + + gpio0_31_30_pins: iic2-gpio-pins { +@@ -1734,7 +1734,7 @@ esdhc0_cd_wp_pins: iic2-sdhc-pins { + }; + + i2c2_pins: iic3-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 3)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 3)>; + }; + + gpio0_29_28_pins: iic3-gpio-pins { +@@ -1742,7 +1742,7 @@ gpio0_29_28_pins: iic3-gpio-pins { + }; + + i2c3_pins: iic4-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 6)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 6)>; + }; + + gpio0_27_26_pins: iic4-gpio-pins { +@@ -1750,7 +1750,7 @@ gpio0_27_26_pins: iic4-gpio-pins { + }; + + i2c4_pins: iic5-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 9)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 9)>; + }; + + gpio0_25_24_pins: iic5-gpio-pins { +@@ -1758,7 +1758,7 @@ gpio0_25_24_pins: iic5-gpio-pins { + }; + + i2c5_pins: iic6-i2c-pins { +- pinctrl-single,bits = <0x0 0 (0x7 << 12)>; ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 12)>; + }; + + gpio0_23_22_pins: iic6-gpio-pins { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch b/queue-7.0/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch new file mode 100644 index 0000000000..0e7562c4a8 --- /dev/null +++ b/queue-7.0/arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch @@ -0,0 +1,190 @@ +From ab47ca07e96882822f79ab55be3d42e62ab0f312 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:41:01 +0100 +Subject: arm64: dts: lx2160a: complete pinmux for rcwsr12 configuration word + +From: Josua Mayer + +[ Upstream commit 284ad7064aaa1badde022785cd925af29c696b21 ] + +Commit 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to +support bus recovery") introduced pinmux nodes for lx2160 i2c +interfaces, allowing runtime change between i2c and gpio functions +implementing bus recovery. + +However, the dynamic configuration area (overwrite MUX) used by the +pinctrl-single driver initially reads as zero and does not reflect the +actual hardware state set by the Reset Configuration Word (RCW) at +power-on. + +Because multiple groups of pins are configured from a single 32-bit +register, the first write from the pinctrl driver unintentionally clears +all other bits to zero. + +Add description for all bits of RCWSR12 register, allowing boards to +explicitly define and restore their intended hardware state. + +This includes i2c, gpio, flextimer, spi, can and sdhc functions. + +Other configuration words, i.e. RCWSR13 & RCWSR14 may be added in the +future for boards setting non-zero values there. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 75 +++++++++++++++++++ + 1 file changed, 75 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index d266bf96e2c6a..479982948ee53 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -1721,6 +1721,7 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x7>; + ++ /* RCWSR12 */ + i2c1_pins: iic2-i2c-pins { + pinctrl-single,bits = <0x0 0x0 0x7>; + }; +@@ -1729,6 +1730,10 @@ gpio0_31_30_pins: iic2-gpio-pins { + pinctrl-single,bits = <0x0 0x1 0x7>; + }; + ++ ftm0_ch10_pins: iic2-ftm-pins { ++ pinctrl-single,bits = <0x0 0x2 0x7>; ++ }; ++ + esdhc0_cd_wp_pins: iic2-sdhc-pins { + pinctrl-single,bits = <0x0 0x6 0x7>; + }; +@@ -1741,6 +1746,14 @@ gpio0_29_28_pins: iic3-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 3) (0x7 << 3)>; + }; + ++ can0_pins: iic3-can-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 3) (0x7 << 3)>; ++ }; ++ ++ event65_pins: iic3-event-pins { ++ pinctrl-single,bits = <0x0 (0x6 << 3) (0x7 << 3)>; ++ }; ++ + i2c3_pins: iic4-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 6)>; + }; +@@ -1749,6 +1762,14 @@ gpio0_27_26_pins: iic4-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 6) (0x7 << 6)>; + }; + ++ can1_pins: iic4-can-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 6) (0x7 << 6)>; ++ }; ++ ++ event87_pins: iic4-event-pins { ++ pinctrl-single,bits = <0x0 (0x6 << 6) (0x7 << 6)>; ++ }; ++ + i2c4_pins: iic5-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 9)>; + }; +@@ -1757,6 +1778,14 @@ gpio0_25_24_pins: iic5-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 9) (0x7 << 9)>; + }; + ++ esdhc0_clksync_pins: iic5-sdhc-clk-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 9) (0x7 << 9)>; ++ }; ++ ++ dspi2_miso_mosi_pins: iic5-spi3-pins { ++ pinctrl-single,bits = <0x3 (0x2 << 9) (0x7 << 9)>; ++ }; ++ + i2c5_pins: iic6-i2c-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 12)>; + }; +@@ -1765,26 +1794,71 @@ gpio0_23_22_pins: iic6-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 12) (0x7 << 12)>; + }; + ++ esdhc1_clksync_pins: iic6-sdhc-clk-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 12) (0x7 << 12)>; ++ }; ++ + fspi_data74_pins: xspi1-data74-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 15)>; + }; + ++ gpio1_31_28_pins: xspi1-data74-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 15)>; ++ }; ++ + fspi_data30_pins: xspi1-data30-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 18)>; + }; + ++ gpio1_27_24_pins: xspi1-data30-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 18)>; ++ }; ++ + fspi_dqs_sck_cs10_pins: xspi1-base-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 21)>; + }; + ++ gpio1_23_20_pins: xspi1-base-gpio-pins { ++ pinctrl-single,bits = <0x0 0x1 (0x7 << 21)>; ++ }; ++ + esdhc0_cmd_data30_clk_vsel_pins: sdhc1-base-sdhc-vsel-pins { + pinctrl-single,bits = <0x0 0x0 (0x7 << 24)>; + }; + ++ gpio0_21_15_pins: sdhc1-base-gpio-pins { ++ pinctrl-single,bits = <0x0 (0x1 << 24) (0x7 << 24)>; ++ }; ++ ++ dspi0_pins: sdhc1-base-spi1-pins { ++ pinctrl-single,bits = <0x0 (0x2 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_cmd_data30_clk_dspi2_cs0_pins: sdhc1-base-sdhc-spi3-pins { ++ pinctrl-single,bits = <0x0 (0x3 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_cmd_data30_clk_data4_pins: sdhc1-base-sdhc-data4-pins { ++ pinctrl-single,bits = <0x0 (0x4 << 24) (0x7 << 24)>; ++ }; ++ ++ esdhc0_dir_pins: sdhc1-dir-pins { ++ pinctrl-single,bits = <0x0 0x0 (0x7 << 27)>; ++ }; ++ + gpio0_14_12_pins: sdhc1-dir-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 27) (0x7 << 27)>; + }; + ++ dspi2_cs31_pins: sdhc1-dir-spi3-pins { ++ pinctrl-single,bits = <0x0 (0x3 << 27) (0x7 << 27)>; ++ }; ++ ++ esdhc0_data75_pins: sdhc1-dir-sdhc-pins { ++ pinctrl-single,bits = <0x0 (0x4 << 27) (0x7 << 27)>; ++ }; ++ ++ /* RCWSR13 */ + gpio1_18_15_pins: iic8-iic7-gpio-pins { + pinctrl-single,bits = <0x4 0x1 0x7>; + }; +@@ -1793,6 +1867,7 @@ i2c6_i2c7_pins: iic8-iic7-i2c-pins { + pinctrl-single,bits = <0x4 0x2 0x7>; + }; + ++ /* RCWSR14 */ + i2c0_pins: iic1-i2c-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch b/queue-7.0/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch new file mode 100644 index 0000000000..6f9c3229b7 --- /dev/null +++ b/queue-7.0/arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch @@ -0,0 +1,62 @@ +From 6e5a144e227e9e5babc63cbaded5d51598eccb8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:57 +0100 +Subject: arm64: dts: lx2160a: remove duplicate pinmux nodes + +From: Josua Mayer + +[ Upstream commit 325ca511ca3dda936207ce737e0afe837d45a674 ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +The pinmux nodes i2c7-scl-pins and i2c7-scl-gpio-pins are duplicates of +i2c6-scl-gpio and i2c6-scl-gpio-pins, writing to the same register and +bits. + +These two i2c buses i2c6/i2c7 (IIC7/IIC8) are configured together in +register RCWSR13 bits 3-0. + +Drop the duplicate node name and change references to the i2c6 node. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index d5bb55df03216..41c9b4253f4a5 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -862,8 +862,8 @@ i2c7: i2c@2070000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c7_scl>; +- pinctrl-1 = <&i2c7_scl_gpio>; ++ pinctrl-0 = <&i2c6_scl>; ++ pinctrl-1 = <&i2c6_scl_gpio>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -1785,14 +1785,6 @@ i2c6_scl_gpio: i2c6-scl-gpio-pins { + pinctrl-single,bits = <0x4 0x1 0x7>; + }; + +- i2c7_scl: i2c7-scl-pins { +- pinctrl-single,bits = <0x4 0x2 0x7>; +- }; +- +- i2c7_scl_gpio: i2c7-scl-gpio-pins { +- pinctrl-single,bits = <0x4 0x1 0x7>; +- }; +- + i2c0_scl: i2c0-scl-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch b/queue-7.0/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch new file mode 100644 index 0000000000..1fc45d83ad --- /dev/null +++ b/queue-7.0/arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch @@ -0,0 +1,219 @@ +From 5b19c376b704dc242018b857d11c25955b3db7e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 13:40:58 +0100 +Subject: arm64: dts: lx2160a: rename pinmux nodes for readability + +From: Josua Mayer + +[ Upstream commit 456eb494746afd56d3a9dc30271300136e55b96e ] + +LX2160A pinmux is done in groups by various length bitfields within +configuration registers. + +Each group of pins is named in the reference manual after a primary +function using soc-specific naming, e.g. IIC1 (for i2c0). + +Hardware block numbering starts from zero in device-tree but one in the +reference manual. + +Rename the already defined pinmux nodes originally added for changing +i2c pins between i2c and gpio functions reflecting the reference manual +name (IIC) in the node name, and the device-tree name (i2c, gpio) in the +label. + +Specifically, drop the "_scl" suffix from the I2C labels because the +nodes actually configure both SDA and SCL pins together. Instead add +"_pins" suffix to avoid conflicts with I2C controller labels. + +For GPIO functions, include the specific controller and pin numbers in +the label to clarify they are generic GPIOs and help spot mistakes. + +No functional change intended. + +Fixes: 8a1365c7bbc1 ("arm64: dts: lx2160a: add pinmux and i2c gpio to support bus recovery") +Signed-off-by: Josua Mayer +Signed-off-by: Frank Li +Signed-off-by: Sasha Levin +--- + .../arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 64 +++++++++---------- + 1 file changed, 32 insertions(+), 32 deletions(-) + +diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +index 41c9b4253f4a5..28500e8873909 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +@@ -750,8 +750,8 @@ i2c0: i2c@2000000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c0_scl>; +- pinctrl-1 = <&i2c0_scl_gpio>; ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-1 = <&gpio0_3_2_pins>; + scl-gpios = <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -766,8 +766,8 @@ i2c1: i2c@2010000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c1_scl>; +- pinctrl-1 = <&i2c1_scl_gpio>; ++ pinctrl-0 = <&i2c1_pins>; ++ pinctrl-1 = <&gpio0_31_30_pins>; + scl-gpios = <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -782,8 +782,8 @@ i2c2: i2c@2020000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c2_scl>; +- pinctrl-1 = <&i2c2_scl_gpio>; ++ pinctrl-0 = <&i2c2_pins>; ++ pinctrl-1 = <&gpio0_29_28_pins>; + scl-gpios = <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -798,8 +798,8 @@ i2c3: i2c@2030000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c3_scl>; +- pinctrl-1 = <&i2c3_scl_gpio>; ++ pinctrl-0 = <&i2c3_pins>; ++ pinctrl-1 = <&gpio0_27_26_pins>; + scl-gpios = <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -814,8 +814,8 @@ i2c4: i2c@2040000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c4_scl>; +- pinctrl-1 = <&i2c4_scl_gpio>; ++ pinctrl-0 = <&i2c4_pins>; ++ pinctrl-1 = <&gpio0_25_24_pins>; + scl-gpios = <&gpio0 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -830,8 +830,8 @@ i2c5: i2c@2050000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c5_scl>; +- pinctrl-1 = <&i2c5_scl_gpio>; ++ pinctrl-0 = <&i2c5_pins>; ++ pinctrl-1 = <&gpio0_23_22_pins>; + scl-gpios = <&gpio0 23 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -846,8 +846,8 @@ i2c6: i2c@2060000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c6_scl>; +- pinctrl-1 = <&i2c6_scl_gpio>; ++ pinctrl-0 = <&i2c6_i2c7_pins>; ++ pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -862,8 +862,8 @@ i2c7: i2c@2070000 { + clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL + QORIQ_CLK_PLL_DIV(16)>; + pinctrl-names = "default", "gpio"; +- pinctrl-0 = <&i2c6_scl>; +- pinctrl-1 = <&i2c6_scl_gpio>; ++ pinctrl-0 = <&i2c6_i2c7_pins>; ++ pinctrl-1 = <&gpio1_18_15_pins>; + scl-gpios = <&gpio1 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "disabled"; + }; +@@ -1713,11 +1713,11 @@ pinmux_i2crv: pinmux@70010012c { + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x7>; + +- i2c1_scl: i2c1-scl-pins { ++ i2c1_pins: iic2-i2c-pins { + pinctrl-single,bits = <0x0 0 0x7>; + }; + +- i2c1_scl_gpio: i2c1-scl-gpio-pins { ++ gpio0_31_30_pins: iic2-gpio-pins { + pinctrl-single,bits = <0x0 0x1 0x7>; + }; + +@@ -1725,35 +1725,35 @@ esdhc0_cd_wp_pins: iic2-sdhc-pins { + pinctrl-single,bits = <0x0 0x6 0x7>; + }; + +- i2c2_scl: i2c2-scl-pins { ++ i2c2_pins: iic3-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 3)>; + }; + +- i2c2_scl_gpio: i2c2-scl-gpio-pins { ++ gpio0_29_28_pins: iic3-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 3) (0x7 << 3)>; + }; + +- i2c3_scl: i2c3-scl-pins { ++ i2c3_pins: iic4-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 6)>; + }; + +- i2c3_scl_gpio: i2c3-scl-gpio-pins { ++ gpio0_27_26_pins: iic4-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 6) (0x7 << 6)>; + }; + +- i2c4_scl: i2c4-scl-pins { ++ i2c4_pins: iic5-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 9)>; + }; + +- i2c4_scl_gpio: i2c4-scl-gpio-pins { ++ gpio0_25_24_pins: iic5-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 9) (0x7 << 9)>; + }; + +- i2c5_scl: i2c5-scl-pins { ++ i2c5_pins: iic6-i2c-pins { + pinctrl-single,bits = <0x0 0 (0x7 << 12)>; + }; + +- i2c5_scl_gpio: i2c5-scl-gpio-pins { ++ gpio0_23_22_pins: iic6-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 12) (0x7 << 12)>; + }; + +@@ -1777,19 +1777,19 @@ gpio0_14_12_pins: sdhc1-dir-gpio-pins { + pinctrl-single,bits = <0x0 (0x1 << 27) (0x7 << 27)>; + }; + +- i2c6_scl: i2c6-scl-pins { +- pinctrl-single,bits = <0x4 0x2 0x7>; ++ gpio1_18_15_pins: iic8-iic7-gpio-pins { ++ pinctrl-single,bits = <0x4 0x1 0x7>; + }; + +- i2c6_scl_gpio: i2c6-scl-gpio-pins { +- pinctrl-single,bits = <0x4 0x1 0x7>; ++ i2c6_i2c7_pins: iic8-iic7-i2c-pins { ++ pinctrl-single,bits = <0x4 0x2 0x7>; + }; + +- i2c0_scl: i2c0-scl-pins { ++ i2c0_pins: iic1-i2c-pins { + pinctrl-single,bits = <0x8 0x0 (0x1 << 10)>; + }; + +- i2c0_scl_gpio: i2c0-scl-gpio-pins { ++ gpio0_3_2_pins: iic1-gpio-pins { + pinctrl-single,bits = <0x8 (0x1 << 10) (0x1 << 10)>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch b/queue-7.0/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch new file mode 100644 index 0000000000..7f48628711 --- /dev/null +++ b/queue-7.0/arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch @@ -0,0 +1,59 @@ +From dfd45f3e99ee8abd9d46d566ff9435439ca02f56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 17:25:16 +0200 +Subject: arm64: dts: marvell: armada-37xx: use 'usb2-phy' in USB3 controller's + phy-names + +From: Gabor Juhos + +[ Upstream commit 0fef19844624f8bc07651b4d26088d8940affba3 ] + +Instead of the generic 'usb2-phy' name, the Armada 37xx device trees +are using a custom 'usb2-utmi-otg-phy' name for the USB2 PHY in the USB3 +controller node. Since commit 53a2d95df836 ("usb: core: add phy notify +connect and disconnect"), this triggers a bug [1] in the USB core which +causes double use of the USB3 PHY. + +Change the PHY name to 'usb2-phy' in the SoC and in the uDPU specific +dtsi files in order to avoid triggering the bug and also to keep the +names in line with the ones used by other platforms. + +Link: https://lore.kernel.org/r/20260330-usb-avoid-usb3-phy-double-use-v1-1-d2113aecb535@gmail.com # [1] +Fixes: 53a2d95df836 ("usb: core: add phy notify connect and disconnect") +Signed-off-by: Gabor Juhos +Signed-off-by: Gregory CLEMENT +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi | 2 +- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +index cd856c0aba71e..12deacb741ccb 100644 +--- a/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-3720-uDPU.dtsi +@@ -161,7 +161,7 @@ ð1 { + &usb3 { + status = "okay"; + phys = <&usb2_utmi_otg_phy>; +- phy-names = "usb2-utmi-otg-phy"; ++ phy-names = "usb2-phy"; + }; + + &uart0 { +diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +index 87f9367aec122..cbc411bfa3810 100644 +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -373,7 +373,7 @@ usb3: usb@58000 { + interrupts = ; + clocks = <&sb_periph_clk 12>; + phys = <&comphy0 0>, <&usb2_utmi_otg_phy>; +- phy-names = "usb3-phy", "usb2-utmi-otg-phy"; ++ phy-names = "usb3-phy", "usb2-phy"; + status = "disabled"; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch b/queue-7.0/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..3987a1de54 --- /dev/null +++ b/queue-7.0/arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From 1a829c785f2d73014e1184a30bd411d742168b3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:28 +0900 +Subject: arm64: dts: mediatek: mt6795: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit c4c4823c8a5baa10b8100b01f49d7c3f4a871689 ] + +The gpio-ranges in the MT6795 pinctrl node were incorrectly defined, +therefore, GPIO196 cannot be used. +Correct the range count to match the driver. + +Fixes: b888886a4536 ("arm64: dts: mediatek: mt6795: Add pinctrl controller node") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt6795.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +index ae2aaa51c9ad2..134cfa77e3b1f 100644 +--- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi +@@ -371,7 +371,7 @@ pio: pinctrl@10005000 { + ; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 196>; ++ gpio-ranges = <&pio 0 0 197>; + interrupt-controller; + #interrupt-cells = <2>; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch b/queue-7.0/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..bcd6545921 --- /dev/null +++ b/queue-7.0/arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From d02a2fa9af08f40e1a5dbac61e0a5482715c7345 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:29 +0900 +Subject: arm64: dts: mediatek: mt7981b: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit b62a927f4a46a7f58d88ba3d5fb6e88e1a4b4603 ] + +The gpio-ranges in the MT7981B pinctrl node were incorrectly defined, +therefore, pin 56 cannot be used. +Correct the range count to match the driver. + +Fixes: 62b24c7fdf0a ("arm64: dts: mediatek: mt7981: add pinctrl") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +index 4084f4dfa3e5e..1bbe219380f99 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +@@ -332,7 +332,7 @@ pio: pinctrl@11d00000 { + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; +- gpio-ranges = <&pio 0 0 56>; ++ gpio-ranges = <&pio 0 0 57>; + gpio-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch b/queue-7.0/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch new file mode 100644 index 0000000000..538ac5ecbc --- /dev/null +++ b/queue-7.0/arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch @@ -0,0 +1,37 @@ +From 5e9f2a052b5c4d43a8e0ea6d9e3b2a3155387df3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 13:15:30 +0900 +Subject: arm64: dts: mediatek: mt7986a: Fix gpio-ranges pin count + +From: Akari Tsuyukusa + +[ Upstream commit 820ed0c1a13c5fafb36232538d793f99a0986ef3 ] + +The gpio-ranges in the MT7986A pinctrl node were incorrectly defined, +therefore, pin 100 cannot be used. +Correct the range count to match the driver. + +Fixes: c3a064a32ed9 ("arm64: dts: mediatek: add pinctrl support for mt7986a") +Signed-off-by: Akari Tsuyukusa +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index 9693f62fd0136..9ebc196107e5a 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -187,7 +187,7 @@ pio: pinctrl@1001f000 { + "iocfg_lb", "iocfg_tr", "iocfg_tl", "eint"; + gpio-controller; + #gpio-cells = <2>; +- gpio-ranges = <&pio 0 0 100>; ++ gpio-ranges = <&pio 0 0 101>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-mediatek-mt7988a-bpi-r4pro-fix-model-strin.patch b/queue-7.0/arm64-dts-mediatek-mt7988a-bpi-r4pro-fix-model-strin.patch new file mode 100644 index 0000000000..5868e89a77 --- /dev/null +++ b/queue-7.0/arm64-dts-mediatek-mt7988a-bpi-r4pro-fix-model-strin.patch @@ -0,0 +1,49 @@ +From f42b069efa35e7c732ac92c1f4c8b5315070f531 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 08:46:08 +0100 +Subject: arm64: dts: mediatek: mt7988a-bpi-r4pro: fix model string + +From: Frank Wunderlich + +[ Upstream commit e4e6f0c5a4dc238684acef079e792c81d37e3226 ] + +Fix incorrect model string in Devicetree for BPI-R4-Pro. + +Fixes: f397471a6a8c ("arm64: dts: mediatek: mt7988: Add devicetree for BananaPi R4 Pro") +Signed-off-by: Frank Wunderlich +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts | 2 +- + arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts +index c7ea6e88c4f48..621d01e3cd896 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-4e.dts +@@ -9,7 +9,7 @@ + #include "mt7988a-bananapi-bpi-r4-pro.dtsi" + + / { +- model = "Bananapi BPI-R4"; ++ model = "Bananapi BPI-R4 Pro 4E"; + compatible = "bananapi,bpi-r4-pro-4e", + "bananapi,bpi-r4-pro", + "mediatek,mt7988a"; +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts +index c9a0e69e9dd51..bb15bfa5e6ae5 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-pro-8x.dts +@@ -9,7 +9,7 @@ + #include "mt7988a-bananapi-bpi-r4-pro.dtsi" + + / { +- model = "Bananapi BPI-R4"; ++ model = "Bananapi BPI-R4 Pro 8X"; + compatible = "bananapi,bpi-r4-pro-8x", + "bananapi,bpi-r4-pro", + "mediatek,mt7988a"; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch b/queue-7.0/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch new file mode 100644 index 0000000000..e6c315be4c --- /dev/null +++ b/queue-7.0/arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch @@ -0,0 +1,58 @@ +From 4e2375f8ef7ddd48a4e276cac5005692d1e36492 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 May 2025 12:43:22 -0400 +Subject: arm64: dts: mediatek: mt8365: Describe infracfg-nao as a pure syscon +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nícolas F. R. A. Prado + +[ Upstream commit 0651c24658360706c30588cec0a12c05edb03e9a ] + +The infracfg-nao register space at 0x1020e000 has different registers +than the infracfg space at 0x10001000, and most importantly, doesn't +contain any clock controls. Therefore it shouldn't use the same +compatible used for the mt8365 infracfg clocks driver: +mediatek,mt8365-infracfg. Since it currently does, probe errors are +reported in the kernel logs: + + [ 0.245959] Failed to register clk ifr_pmic_tmr: -EEXIST + [ 0.245998] clk-mt8365 1020e000.infracfg: probe with driver clk-mt8365 failed with error -17 + +This register space is used only as a syscon for bus control by the +power domain controller, so in order to properly describe it and fix the +errors, set its compatible to a distinct compatible used exclusively as +a syscon, drop the clock-cells, and while at it rename the node to +'syscon' following the naming convention. + +Fixes: 6ff945376556 ("arm64: dts: mediatek: Initial mt8365-evk support") +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: David Lechner +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/mediatek/mt8365.dtsi | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt8365.dtsi b/arch/arm64/boot/dts/mediatek/mt8365.dtsi +index a5ca3cda6ef30..2e782558fb776 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8365.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8365.dtsi +@@ -536,10 +536,9 @@ iommu: iommu@10205000 { + #iommu-cells = <1>; + }; + +- infracfg_nao: infracfg@1020e000 { +- compatible = "mediatek,mt8365-infracfg", "syscon"; ++ infracfg_nao: syscon@1020e000 { ++ compatible = "mediatek,mt8365-infracfg-nao", "syscon"; + reg = <0 0x1020e000 0 0x1000>; +- #clock-cells = <1>; + }; + + rng: rng@1020f000 { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch b/queue-7.0/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch new file mode 100644 index 0000000000..94cd821ec6 --- /dev/null +++ b/queue-7.0/arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch @@ -0,0 +1,44 @@ +From 7ec4fb739ff62a1fbe567614b1b581b30f680ee4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 22:51:11 +0800 +Subject: arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number + +From: Jun Yan + +[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ] + +Correct the interrupt number assigned to the Realtek PHY in the p230 + +following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm: +fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY +interrupt improvements [1]. + +[1] https://lore.kernel.org/all/20171202214037.17017-1-martin.blumenstingl@googlemail.com/ + +Fixes: b94d22d94ad2 ("ARM64: dts: meson-gx: add external PHY interrupt on some platforms") +Signed-off-by: Jun Yan +Reviewed-by: Martin Blumenstingl +Link: https://patch.msgid.link/20260330145111.115318-1-jerrysteve1101@gmail.com +Signed-off-by: Neil Armstrong +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +index 7dffeb5931c9b..701de57ff0f37 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +@@ -84,7 +84,8 @@ external_phy: ethernet-phy@0 { + reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; + + interrupt-parent = <&gpio_intc>; +- interrupts = <29 IRQ_TYPE_LEVEL_LOW>; ++ /* MAC_INTR on GPIOZ_15 */ ++ interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + eee-broken-1000t; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-add-missing-denali-oled.dtb-to-makefi.patch b/queue-7.0/arm64-dts-qcom-add-missing-denali-oled.dtb-to-makefi.patch new file mode 100644 index 0000000000..05a3a29700 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-add-missing-denali-oled.dtb-to-makefi.patch @@ -0,0 +1,42 @@ +From 683bd9d953c4bc33e902e56736d8c4e60d05637c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 15:04:30 +0100 +Subject: arm64: dts: qcom: add missing denali-oled.dtb to Makefile + +From: Tobias Heider + +[ Upstream commit 9ffb2dfcc955faa5072cf8de547ae5909544fdad ] + +The DeviceTree for the OLED variant of the Microsoft Surface Pro 11th +Edition was originally added in commit '0d72ccaa1e84 ("arm64: dts: qcom: +Add support for X1-based Surface Pro 11")'. The original patch on the +mailing list also added the new device tree to the Makefile but that +part seems to have been dropped (by accident) when it got merged. + +Signed-off-by: Tobias Heider +Fixes: 0d72ccaa1e84 ("arm64: dts: qcom: Add support for X1-based Surface Pro 11") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260226140429.232544-3-tobias.heider@canonical.com +[bjorn: Rewrote commit message reference to offending commit] +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/Makefile | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile +index f80b5d9cf1e80..b05e8adc02f65 100644 +--- a/arch/arm64/boot/dts/qcom/Makefile ++++ b/arch/arm64/boot/dts/qcom/Makefile +@@ -374,6 +374,8 @@ x1e80100-lenovo-yoga-slim7x-el2-dtbs := x1e80100-lenovo-yoga-slim7x.dtb x1-el2.d + dtb-$(CONFIG_ARCH_QCOM) += x1e80100-lenovo-yoga-slim7x.dtb x1e80100-lenovo-yoga-slim7x-el2.dtb + x1e80100-medion-sprchrgd-14-s1-el2-dtbs := x1e80100-medion-sprchrgd-14-s1.dtb x1-el2.dtbo + dtb-$(CONFIG_ARCH_QCOM) += x1e80100-medion-sprchrgd-14-s1.dtb x1e80100-medion-sprchrgd-14-s1-el2.dtb ++x1e80100-microsoft-denali-oled-el2-dtbs := x1e80100-microsoft-denali-oled.dtb x1-el2.dtbo ++dtb-$(CONFIG_ARCH_QCOM) += x1e80100-microsoft-denali-oled.dtb x1e80100-microsoft-denali-oled-el2.dtb + x1e80100-microsoft-romulus13-el2-dtbs := x1e80100-microsoft-romulus13.dtb x1-el2.dtbo + dtb-$(CONFIG_ARCH_QCOM) += x1e80100-microsoft-romulus13.dtb x1e80100-microsoft-romulus13-el2.dtb + x1e80100-microsoft-romulus15-el2-dtbs := x1e80100-microsoft-romulus15.dtb x1-el2.dtbo +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-arduino-imola-fix-faulty-spidev-node.patch b/queue-7.0/arm64-dts-qcom-arduino-imola-fix-faulty-spidev-node.patch new file mode 100644 index 0000000000..23d585abb6 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-arduino-imola-fix-faulty-spidev-node.patch @@ -0,0 +1,53 @@ +From 4457222ded5bf6d66295ffb9d39d17f9aecf8a17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 11:10:02 +0100 +Subject: arm64: dts: qcom: arduino-imola: fix faulty spidev node + +From: Riccardo Mereu + +[ Upstream commit 1a040df09fab28b31399fce14a76455b536a2b08 ] + +CS pin added on pinctrl0 property is causing spidev to return -ENODEV +since that GPIO is already part of spi5 pinmuxing. + +Fixes: 3f745bc0f11f ("arm64: dts: qcom: qrb2210: add dts for Arduino unoq") +Signed-off-by: Riccardo Mereu +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260213101002.105238-1-r.mereu.kernel@arduino.cc +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts +index 197ab6eb1666f..5ab605cc56c80 100644 +--- a/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts ++++ b/arch/arm64/boot/dts/qcom/qrb2210-arduino-imola.dts +@@ -325,21 +325,13 @@ &sdhc_1 { + &spi5 { + status = "okay"; + +- spidev@0 { +- reg = <0>; ++ mcu@0 { + compatible = "arduino,unoq-mcu"; +- pinctrl-0 = <&spidev_cs>; +- pinctrl-names = "default"; ++ reg = <0>; + }; + }; + + &tlmm { +- spidev_cs: spidev-cs-state { +- pins = "gpio17"; +- function = "gpio"; +- drive-strength = <16>; +- }; +- + jmisc_gpio18: jmisc-gpio18-state { + pins = "gpio18"; + function = "gpio"; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-hamoa-correct-iris-corners-for-the-mx.patch b/queue-7.0/arm64-dts-qcom-hamoa-correct-iris-corners-for-the-mx.patch new file mode 100644 index 0000000000..87c9b7541c --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-hamoa-correct-iris-corners-for-the-mx.patch @@ -0,0 +1,53 @@ +From 10260428afab82e20dacf10185d59b0f73e92970 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:08 +0200 +Subject: arm64: dts: qcom: hamoa: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit baac8b5e43f42b632b912a6a837d94fd5bca48f2 ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: 9065340ac04d ("arm64: dts: qcom: x1e80100: Add IRIS video codec") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-1-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/hamoa.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi +index 4b0784af4bd39..f01b363009826 100644 +--- a/arch/arm64/boot/dts/qcom/hamoa.dtsi ++++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi +@@ -5432,19 +5432,19 @@ opp-338000000 { + + opp-366000000 { + opp-hz = /bits/ 64 <366000000>; +- required-opps = <&rpmhpd_opp_svs_l1>, ++ required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_svs_l1>; + }; + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-481000000 { + opp-hz = /bits/ 64 <481000000>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_turbo>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-hamoa-fix-xo-clock-supply-of-platform.patch b/queue-7.0/arm64-dts-qcom-hamoa-fix-xo-clock-supply-of-platform.patch new file mode 100644 index 0000000000..0ebb1cede2 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-hamoa-fix-xo-clock-supply-of-platform.patch @@ -0,0 +1,56 @@ +From b432658bc6b1b9bbe4f13808f9a79a78162b3784 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:12 +0200 +Subject: arm64: dts: qcom: hamoa: Fix xo clock supply of platform SD host + controller + +From: Vladimir Zapolskiy + +[ Upstream commit d094f79960e1da20c1380083c95945371baa3668 ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: ffb21c1e19b1 ("arm64: dts: qcom: x1e80100: Describe the SDHC controllers") +Reported-by: Neil Armstrong +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-4-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/hamoa.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi +index f01b363009826..cb95549275ca8 100644 +--- a/arch/arm64/boot/dts/qcom/hamoa.dtsi ++++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi +@@ -4714,7 +4714,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", "core", "xo"; + iommus = <&apps_smmu 0x520 0>; + qcom,dll-config = <0x0007642c>; +@@ -4767,7 +4767,7 @@ sdhc_4: mmc@8844000 { + + clocks = <&gcc GCC_SDCC4_AHB_CLK>, + <&gcc GCC_SDCC4_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", "core", "xo"; + iommus = <&apps_smmu 0x160 0>; + qcom,dll-config = <0x0007642c>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-kaanapali-fix-gic_its-range-length.patch b/queue-7.0/arm64-dts-qcom-kaanapali-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..bf661e14aa --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-kaanapali-fix-gic_its-range-length.patch @@ -0,0 +1,37 @@ +From eb85a3414b8f99e1c8320484ae0fba80dd2ca2ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:14 +0100 +Subject: arm64: dts: qcom: kaanapali: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 51cf2818376f5ebbc5f8753d5be547b1e7206021 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: 2eeb5767d53f ("arm64: dts: qcom: Introduce Kaanapali SoC") +Signed-off-by: Konrad Dybcio +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-1-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/kaanapali.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/kaanapali.dtsi b/arch/arm64/boot/dts/qcom/kaanapali.dtsi +index 9ef57ad0ca71d..9be86479ceef1 100644 +--- a/arch/arm64/boot/dts/qcom/kaanapali.dtsi ++++ b/arch/arm64/boot/dts/qcom/kaanapali.dtsi +@@ -1239,7 +1239,7 @@ intc: interrupt-controller@17000000 { + + gic_its: msi-controller@17040000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x17040000 0x0 0x20000>; ++ reg = <0x0 0x17040000 0x0 0x40000>; + + msi-controller; + #msi-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-lemans-correct-iris-corners-for-the-m.patch b/queue-7.0/arm64-dts-qcom-lemans-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..135a32da54 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-lemans-correct-iris-corners-for-the-m.patch @@ -0,0 +1,53 @@ +From e4db6799c61fdfd867ed386af8b9ea427ded1283 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:09 +0200 +Subject: arm64: dts: qcom: lemans: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit 85a6cf5ef8cf6e6de948fbba56101fa05049417f ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: 7bc95052c64f ("arm64: dts: qcom: sa8775p: add support for video node") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-2-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/lemans.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi +index 2db2ab9cb2e06..be8c8c59ef5ab 100644 +--- a/arch/arm64/boot/dts/qcom/lemans.dtsi ++++ b/arch/arm64/boot/dts/qcom/lemans.dtsi +@@ -4625,19 +4625,19 @@ opp-366000000 { + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-533000000 { + opp-hz = /bits/ 64 <533000000>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo>; + }; + + opp-560000000 { + opp-hz = /bits/ 64 <560000000>; +- required-opps = <&rpmhpd_opp_turbo_l1>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo_l1>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-milos-add-missing-cx-power-domain-to-.patch b/queue-7.0/arm64-dts-qcom-milos-add-missing-cx-power-domain-to-.patch new file mode 100644 index 0000000000..c226f4333e --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-milos-add-missing-cx-power-domain-to-.patch @@ -0,0 +1,42 @@ +From 877ed212524dad9aa6d26fd63271d2d9412c1543 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:13:41 +0200 +Subject: arm64: dts: qcom: milos: Add missing CX power domain to GCC + +From: Abel Vesa + +[ Upstream commit e46b48b853122626806d989d5db4ce97eaaac2ca ] + +Unless CX is declared as the power-domain of GCC, votes (power and +performance) on the GDSCs it provides will not propagate to the CX, +which might result in under-voltage conditions. + +Add the missing power-domains property to associate GCC with RPMHPD_CX. + +Fixes: d9d59d105f98 ("arm64: dts: qcom: Add initial Milos dtsi") +Signed-off-by: Abel Vesa +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260327-dt-fix-milos-eliza-gcc-power-domains-v1-2-f14a22c73fe9@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/milos.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/milos.dtsi b/arch/arm64/boot/dts/qcom/milos.dtsi +index 084be5316e0d5..098f9ceaa4f38 100644 +--- a/arch/arm64/boot/dts/qcom/milos.dtsi ++++ b/arch/arm64/boot/dts/qcom/milos.dtsi +@@ -802,6 +802,8 @@ gcc: clock-controller@100000 { + <0>, /* ufs_phy_tx_symbol_0_clk */ + <0>; /* usb3_phy_wrapper_gcc_usb30_pipe_clk */ + ++ power-domains = <&rpmhpd RPMHPD_CX>; ++ + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-milos-fix-gic_its-range-length.patch b/queue-7.0/arm64-dts-qcom-milos-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..c87d53e1a5 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-milos-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From 4e590ba50821181e8ebe97c57d95cf43d6041b70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:15 +0100 +Subject: arm64: dts: qcom: milos: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 1831b64854bd8adfccfef4f949534f9e8163293a ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: d9d59d105f98 ("arm64: dts: qcom: Add initial Milos dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Luca Weiss +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-2-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/milos.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/milos.dtsi b/arch/arm64/boot/dts/qcom/milos.dtsi +index e1a51d43943ff..084be5316e0d5 100644 +--- a/arch/arm64/boot/dts/qcom/milos.dtsi ++++ b/arch/arm64/boot/dts/qcom/milos.dtsi +@@ -1911,7 +1911,7 @@ ppi_cluster1: interrupt-partition-1 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x17140000 0x0 0x20000>; ++ reg = <0x0 0x17140000 0x0 0x40000>; + + msi-controller; + #msi-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-monaco-correct-iris-corners-for-the-m.patch b/queue-7.0/arm64-dts-qcom-monaco-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..c1f5a2d954 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-monaco-correct-iris-corners-for-the-m.patch @@ -0,0 +1,52 @@ +From aa3935d2feee63817d9b86b8668b8a512544d754 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:10 +0200 +Subject: arm64: dts: qcom: monaco: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit bba8d9ba7df8f6592552377049fc84958fd0575a ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: bf6ec39c3f36 ("arm64: dts: qcom: qcs8300: add video node") +Signed-off-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-3-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/monaco.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi +index 0cb9fd154b684..37d0515e88936 100644 +--- a/arch/arm64/boot/dts/qcom/monaco.dtsi ++++ b/arch/arm64/boot/dts/qcom/monaco.dtsi +@@ -5293,19 +5293,19 @@ opp-366000000 { + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-533000000 { + opp-hz = /bits/ 64 <533000000>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo>; + }; + + opp-560000000 { + opp-hz = /bits/ 64 <560000000>; +- required-opps = <&rpmhpd_opp_turbo_l1>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo_l1>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-msm8917-xiaomi-riva-fix-board-id-for-.patch b/queue-7.0/arm64-dts-qcom-msm8917-xiaomi-riva-fix-board-id-for-.patch new file mode 100644 index 0000000000..6e5a084837 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-msm8917-xiaomi-riva-fix-board-id-for-.patch @@ -0,0 +1,45 @@ +From d3c1f32ea810be74069436de2c1c6a8b3688fb34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 17:26:19 +0100 +Subject: arm64: dts: qcom: msm8917-xiaomi-riva: Fix board-id for all + bootloader +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit a49cd243503c528ea99e31a7853cf438ccc9032d ] + +Redmi 5A comes with multiple bootloader versions where the expected +board-id is different. +Change the board-id to unified form what works on both bootloader +version. + +Fixes: 26633b582056 ("arm64: dts: qcom: Add Xiaomi Redmi 5A") +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260315-riva-common-v3-1-897f130786ed@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts b/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts +index 9db503e218886..1bfb16f90ddd5 100644 +--- a/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts ++++ b/arch/arm64/boot/dts/qcom/msm8917-xiaomi-riva.dts +@@ -18,7 +18,7 @@ / { + chassis-type = "handset"; + + qcom,msm-id = ; +- qcom,board-id = <0x1000b 2>, <0x2000b 2>; ++ qcom,board-id = <0x1000b 1>, <0x1000b 2>; + + pwm_backlight: backlight { + compatible = "pwm-backlight"; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-msm8937-xiaomi-land-correct-wled-ovp-.patch b/queue-7.0/arm64-dts-qcom-msm8937-xiaomi-land-correct-wled-ovp-.patch new file mode 100644 index 0000000000..81858acd4c --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-msm8937-xiaomi-land-correct-wled-ovp-.patch @@ -0,0 +1,41 @@ +From 01bfc4d13ed789af33972f987a16994b7c4c91c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:38 +0100 +Subject: arm64: dts: qcom: msm8937-xiaomi-land: correct wled ovp value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 9bc4b18a425e8cf1bca190a136a11c3be516f513 ] + +PMI8950 doesn't actually support setting an OVP threshold value of +29.6 V. The closest allowed value is 29.5 V. Set that instead. + +Fixes: 2144f6d57d8e ("arm64: dts: qcom: Add Xiaomi Redmi 3S") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-6-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts b/arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts +index 91837ff940f1b..4f301e7c65171 100644 +--- a/arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts ++++ b/arch/arm64/boot/dts/qcom/msm8937-xiaomi-land.dts +@@ -178,7 +178,7 @@ &pmi8950_wled { + qcom,num-strings = <2>; + qcom,external-pfet; + qcom,current-limit-microamp = <20000>; +- qcom,ovp-millivolt = <29600>; ++ qcom,ovp-millivolt = <29500>; + + status = "okay"; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch b/queue-7.0/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch new file mode 100644 index 0000000000..9acbb40700 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch @@ -0,0 +1,44 @@ +From 8fb5101e06f1b484bd5af21a8bc4c7e8a513cec2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:39 +0100 +Subject: arm64: dts: qcom: msm8953-xiaomi-daisy: fix backlight +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 7131f6d909a6546329b71f2bacfdc60cb3e6020e ] + +The backlight on this device is connected via 3 strings. Currently, +the DT claims only two are present, which results in visible stripes +on the display (since every third backlight string remains unconfigured). + +Fix the number of strings to avoid that. + +Fixes: 38d779c26395 ("arm64: dts: qcom: msm8953: Add device tree for Xiaomi Mi A2 Lite") +Signed-off-by: Barnabás Czémán +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-7-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +index ddd7af6167942..59f873a06e4dd 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-daisy.dts +@@ -157,7 +157,7 @@ &pm8953_resin { + + &pmi8950_wled { + qcom,current-limit-microamp = <20000>; +- qcom,num-strings = <2>; ++ qcom,num-strings = <3>; + + status = "okay"; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch b/queue-7.0/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch new file mode 100644 index 0000000000..66d5ddbc62 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch @@ -0,0 +1,41 @@ +From 033a220d4d2fcdd121ef111ed13c75ff7ccaf2da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 08:07:37 +0100 +Subject: arm64: dts: qcom: msm8953-xiaomi-vince: correct wled ovp value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 9e87f0eaadccc3fecdf3c3c0334e05694804b5f5 ] + +PMI8950 doesn't actually support setting an OVP threshold value of +29.6 V. The closest allowed value is 29.5 V. Set that instead. + +Fixes: aa17e707e04a ("arm64: dts: qcom: msm8953: Add device tree for Xiaomi Redmi 5 Plus") +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260116-pmi8950-wled-v3-5-e6c93de84079@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +index d46325e799176..c2a290bf493c1 100644 +--- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts ++++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +@@ -169,7 +169,7 @@ &pm8953_resin { + + &pmi8950_wled { + qcom,current-limit-microamp = <20000>; +- qcom,ovp-millivolt = <29600>; ++ qcom,ovp-millivolt = <29500>; + qcom,num-strings = <2>; + qcom,external-pfet; + qcom,cabc; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-qcs6490-rubikpi3-use-lt9611-dsi-port-.patch b/queue-7.0/arm64-dts-qcom-qcs6490-rubikpi3-use-lt9611-dsi-port-.patch new file mode 100644 index 0000000000..145b2ae45d --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-qcs6490-rubikpi3-use-lt9611-dsi-port-.patch @@ -0,0 +1,55 @@ +From 7d8dab4eab42cb85ee034a2f72f544ace204b90e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Feb 2026 15:32:56 +0800 +Subject: arm64: dts: qcom: qcs6490-rubikpi3: Use lt9611 DSI Port B + +From: Hongyang Zhao + +[ Upstream commit ebcf2240a2494faf202ce5ec80ef159a38b1e542 ] + +The LT9611 HDMI bridge on RubikPi3 has DSI physically connected to +Port B. Update the devicetree to use port@1 which corresponds to +Port B input on the LT9611. + +Fixes: f055a39f6874 ("arm64: dts: qcom: Add qcs6490-rubikpi3 board dts") +Reviewed-by: Konrad Dybcio +Signed-off-by: Hongyang Zhao +Reviewed-by: Roger Shimizu +Tested-by: Roger Shimizu +Link: https://lore.kernel.org/r/20260207-rubikpi-next-20260116-v3-3-23b9aa189a3a@thundersoft.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts +index 0b64a0b912021..f47efca42d48d 100644 +--- a/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts ++++ b/arch/arm64/boot/dts/qcom/qcs6490-thundercomm-rubikpi3.dts +@@ -755,10 +755,10 @@ ports { + #address-cells = <1>; + #size-cells = <0>; + +- port@0 { +- reg = <0>; ++ port@1 { ++ reg = <1>; + +- lt9611_a: endpoint { ++ lt9611_b: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; +@@ -801,7 +801,7 @@ &mdss_dsi { + }; + + &mdss_dsi0_out { +- remote-endpoint = <<9611_a>; ++ remote-endpoint = <<9611_b>; + data-lanes = <0 1 2 3>; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch b/queue-7.0/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch new file mode 100644 index 0000000000..383013aecc --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch @@ -0,0 +1,38 @@ +From 763f6b04b48b42bdd7fd50596e5a3aae0f3d83a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 18:33:11 +0100 +Subject: arm64: dts: qcom: sdm845-xiaomi-beryllium: Mark l1a regulator as + powered during boot + +From: David Heidelberg + +[ Upstream commit 3b0dd81eea6b7a239fce456ce4545af76f1a9715 ] + +The regulator must be on, since it provides the display subsystem and +therefore the bootloader had turned it on before Linux booted. + +Fixes: 77809cf74a8c ("arm64: dts: qcom: Add support for Xiaomi Poco F1 (Beryllium)") +Signed-off-by: David Heidelberg +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260320-beryllium-booton-v2-1-931d1be21eae@ixit.cz +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +index 01b570d0880d6..1298485c42142 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +@@ -148,6 +148,7 @@ vreg_l1a_0p875: ldo1 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; ++ regulator-boot-on; + }; + + vreg_l5a_0p8: ldo5 { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-correct-reserved.patch b/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-correct-reserved.patch new file mode 100644 index 0000000000..c3348120c6 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-correct-reserved.patch @@ -0,0 +1,100 @@ +From 02c11a9aaef30dac6c2af37a41815a2d12756643 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 17:34:52 +0100 +Subject: arm64: dts: qcom: sm6125-xiaomi-ginkgo: Correct reserved memory + ranges +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 242801cc24e865cb525ef7d826ce6ebeffcad606 ] + +The device was crashing on high memory load because the reserved memory +ranges was wrongly defined. Correct the ranges for avoid the crashes. +Change the ramoops memory range to match with the values from the recovery +to be able to get the results from the device. + +Fixes: 9b1a6c925c88 ("arm64: dts: qcom: sm6125: Initial support for xiaomi-ginkgo") +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260126-xiaomi-willow-v3-2-aad7b106c311@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + .../boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 41 +++++++++++++------ + 1 file changed, 29 insertions(+), 12 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index bf03226a6f854..d5e5abdb3b2ff 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -13,6 +13,12 @@ + #include "sm6125.dtsi" + #include "pm6125.dtsi" + ++/delete-node/ &adsp_pil_mem; ++/delete-node/ &cont_splash_mem; ++/delete-node/ &gpu_mem; ++/delete-node/ &ipa_fw_mem; ++/delete-node/ &ipa_gsi_mem; ++ + / { + model = "Xiaomi Redmi Note 8"; + compatible = "xiaomi,ginkgo", "qcom,sm6125"; +@@ -36,28 +42,39 @@ framebuffer0: framebuffer@5c000000 { + }; + + reserved-memory { +- debug_mem: debug@ffb00000 { +- reg = <0x0 0xffb00000 0x0 0xc0000>; ++ adsp_pil_mem: adsp_pil_mem@55300000 { ++ reg = <0x0 0x55300000 0x0 0x2200000>; + no-map; + }; + +- last_log_mem: lastlog@ffbc0000 { +- reg = <0x0 0xffbc0000 0x0 0x80000>; ++ ipa_fw_mem: ipa_fw_mem@57500000 { ++ reg = <0x0 0x57500000 0x0 0x10000>; + no-map; + }; + +- pstore_mem: ramoops@ffc00000 { +- compatible = "ramoops"; +- reg = <0x0 0xffc40000 0x0 0xc0000>; +- record-size = <0x1000>; +- console-size = <0x40000>; +- pmsg-size = <0x20000>; ++ ipa_gsi_mem: ipa_gsi_mem@57510000 { ++ reg = <0x0 0x57510000 0x0 0x5000>; ++ no-map; + }; + +- cmdline_mem: memory@ffd00000 { +- reg = <0x0 0xffd40000 0x0 0x1000>; ++ gpu_mem: gpu_mem@57515000 { ++ reg = <0x0 0x57515000 0x0 0x2000>; + no-map; + }; ++ ++ framebuffer@5c000000 { ++ reg = <0x0 0x5c000000 0x0 (2340 * 1080 * 4)>; ++ no-map; ++ }; ++ ++ /* Matching with recovery values to be able to get the results. */ ++ ramoops@61600000 { ++ compatible = "ramoops"; ++ reg = <0x0 0x61600000 0x0 0x400000>; ++ record-size = <0x80000>; ++ pmsg-size = <0x200000>; ++ console-size = <0x100000>; ++ }; + }; + + extcon_usb: extcon-usb { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-fix-reserved-gpi.patch b/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-fix-reserved-gpi.patch new file mode 100644 index 0000000000..7d5deacedd --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-fix-reserved-gpi.patch @@ -0,0 +1,42 @@ +From 2f72d4b8ccdc8e6b1b8eb69c363e66748af5e013 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 17:34:55 +0100 +Subject: arm64: dts: qcom: sm6125-xiaomi-ginkgo: Fix reserved gpio ranges +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit e8669e010991154bedadd1cd67700544e0362e99 ] + +The device was crashing on boot because the reserved gpio ranges +was wrongly defined. Correct the ranges for avoid pinctrl crashing. + +Fixes: 9b1a6c925c88 ("arm64: dts: qcom: sm6125: Initial support for xiaomi-ginkgo") +Tested-by: Biswapriyo Nath +Reviewed-by: Konrad Dybcio +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260126-xiaomi-willow-v3-5-aad7b106c311@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index 418cfe67a2da8..c3edeee3af3ef 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -293,7 +293,7 @@ &sdhc_2 { + }; + + &tlmm { +- gpio-reserved-ranges = <22 2>, <28 6>; ++ gpio-reserved-ranges = <0 4>, <30 4>; + }; + + &usb3 { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-board-id.patch b/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-board-id.patch new file mode 100644 index 0000000000..d62535ef0f --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-board-id.patch @@ -0,0 +1,42 @@ +From 4d8c3e27720401a6733c1bf3d2f5cbeaebc031cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 17:34:51 +0100 +Subject: arm64: dts: qcom: sm6125-xiaomi-ginkgo: Remove board-id +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 535e5741bc9acef5ea2561aa300f28370599e7e2 ] + +Remove board-id it is not necessary for the bootloader. + +Fixes: 9b1a6c925c88 ("arm64: dts: qcom: sm6125: Initial support for xiaomi-ginkgo") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260126-xiaomi-willow-v3-1-aad7b106c311@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index 6b68e391cf3ea..bf03226a6f854 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -18,9 +18,7 @@ / { + compatible = "xiaomi,ginkgo", "qcom,sm6125"; + chassis-type = "handset"; + +- /* required for bootloader to select correct board */ + qcom,msm-id = ; +- qcom,board-id = <22 0>; + + chosen { + #address-cells = <2>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-extcon.patch b/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-extcon.patch new file mode 100644 index 0000000000..e952ac3c93 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-extcon.patch @@ -0,0 +1,54 @@ +From b5a30e29290693050717c6a947a58f94fafbbdb3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 17:34:54 +0100 +Subject: arm64: dts: qcom: sm6125-xiaomi-ginkgo: Remove extcon +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Czémán + +[ Upstream commit 79664600fd3ed3972ad9321e13d1f80267730447 ] + +GPIO pin 102 is related to DisplayPort what is not supported +by this device and it is also disabled at downstream, +remove the unnecessary extcon-usb node. + +Fixes: 9b1a6c925c88 ("arm64: dts: qcom: sm6125: Initial support for xiaomi-ginkgo") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Barnabás Czémán +Link: https://lore.kernel.org/r/20260126-xiaomi-willow-v3-4-aad7b106c311@mainlining.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +index d5e5abdb3b2ff..418cfe67a2da8 100644 +--- a/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts ++++ b/arch/arm64/boot/dts/qcom/sm6125-xiaomi-ginkgo.dts +@@ -77,11 +77,6 @@ ramoops@61600000 { + }; + }; + +- extcon_usb: extcon-usb { +- compatible = "linux,extcon-usb-gpio"; +- id-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>; +- }; +- + gpio-keys { + compatible = "gpio-keys"; + +@@ -304,7 +299,3 @@ &tlmm { + &usb3 { + status = "okay"; + }; +- +-&usb3_dwc3 { +- extcon = <&extcon_usb>; +-}; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch b/queue-7.0/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch new file mode 100644 index 0000000000..5b61b4762d --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch @@ -0,0 +1,63 @@ +From 1e9e63e2503369ad23608450e5185861402eaca2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 09:55:00 +0100 +Subject: arm64: dts: qcom: sm7225-fairphone-fp4: Fix conflicting bias pinctrl + +From: Luca Weiss + +[ Upstream commit be7c1badb0b934cfe88427b1d4ec3eb9f52ba587 ] + +The pinctrl nodes from sm6350.dtsi already contain a bias-* property, so +that needs to be deleted, otherwise the dtb will contain two conflicting +bias-* properties. + +Reported-by: Conor Dooley +Closes: https://lore.kernel.org/r/20260310-maritime-silly-05e7b7e03aa6@spud/ +Fixes: c4ef464b24c5 ("arm64: dts: qcom: sm7225-fairphone-fp4: Add Bluetooth") +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Reviewed-by: Conor Dooley +Link: https://lore.kernel.org/r/20260319-fp4-uart1-fix-v1-1-f6b3fedef583@fairphone.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +index a3c2b26736f47..3964aae47fd4e 100644 +--- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts ++++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +@@ -1019,12 +1019,14 @@ &qup_uart1_cts { + * the Bluetooth module drives the pin in either + * direction or leaves the pin fully unpowered. + */ ++ /delete-property/ bias-disable; + bias-bus-hold; + }; + + &qup_uart1_rts { + /* We'll drive RTS, so no pull */ + drive-strength = <2>; ++ /delete-property/ bias-pull-down; + bias-disable; + }; + +@@ -1035,12 +1037,14 @@ &qup_uart1_rx { + * in tri-state (module powered off or not driving the + * signal yet). + */ ++ /delete-property/ bias-disable; + bias-pull-up; + }; + + &qup_uart1_tx { + /* We'll drive TX, so no pull */ + drive-strength = <2>; ++ /delete-property/ bias-pull-up; + bias-disable; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch b/queue-7.0/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch new file mode 100644 index 0000000000..c7291fe255 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch @@ -0,0 +1,43 @@ +From dc71b39a6399f109c179b890603ac8bd0e247779 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 04:26:37 +0000 +Subject: arm64: dts: qcom: sm8250: Add missing CPU7 3.09GHz OPP + +From: Alexander Koskovich + +[ Upstream commit b683730e27ba4f91986c4c92f5cb7297f1e01a6d ] + +This resolves the following error seen on the ASUS ROG Phone 3: + +cpu cpu7: Voltage update failed freq=3091200 +cpu cpu7: failed to update OPP for freq=3091200 + +Fixes: 8e0e8016cb79 ("arm64: dts: qcom: sm8250: Add CPU opp tables") +Signed-off-by: Alexander Koskovich +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260307-sm8250-cpu7-opp-v1-1-435f5f6628a1@pm.me +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8250.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi +index c7dffa4400740..37c41cc1abdd0 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi +@@ -665,6 +665,11 @@ cpu7_opp20: opp-2841600000 { + opp-hz = /bits/ 64 <2841600000>; + opp-peak-kBps = <8368000 51609600>; + }; ++ ++ cpu7_opp21: opp-3091200000 { ++ opp-hz = /bits/ 64 <3091200000>; ++ opp-peak-kBps = <8368000 51609600>; ++ }; + }; + + firmware { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-7.0/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..1520e5e3fa --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,75 @@ +From 834cf1a438a874d0181ecf331f95c4185a6c3c1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:13 +0200 +Subject: arm64: dts: qcom: sm8450: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit db0c5ef1abda6effdc5c85d6688fb6af2b351ae5 ] + +The reported problem of some non-working UHS-I speed modes on SM8450 +originates in commit 0a631a36f724 ("arm64: dts: qcom: Add device tree +for Sony Xperia 1 IV"), and then it was spread to all SM8450 powered +platforms by commit 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable +SDHCI SDR104/SDR50 on all boards"). + +The tests show that the rootcause of the problem was related to an +overclocking of SD cards, and it's fixed later on by commit a27ac3806b0a +("clk: qcom: gcc-sm8450: Use floor ops for SDCC RCGs"). + +Since then both SDR50 and SDR104 speed modes are working fine on SM8450, +tested on SM8450-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 24.6254 s, 43.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 12.3266 s, 87.1 MB/s + +Remove the restrictions on SD card speed modes from the SM8450 platform +dtsi file and enable UHS-I speed modes. + +Fixes: 9d561dc4e5cc ("arm64: dts: qcom: sm8450: disable SDHCI SDR104/SDR50 on all boards") +Reviewed-by: Neil Armstrong +Reviewed-by: Konrad Dybcio +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-5-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 1ac74ff586b86..dd60843e022ef 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -5429,9 +5429,6 @@ sdhc_2: mmc@8804000 { + bus-width = <4>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0x0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch b/queue-7.0/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..c17aa7d3ff --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From 23d4bb293e00270f7c17764651593be9274b1ef3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:16 +0100 +Subject: arm64: dts: qcom: sm8450: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 14044fa192c50265bc1f636108371044bbdcf7b7 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: fc8b0b9b630d ("arm64: dts: qcom: sm8450 add ITS device tree node") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-3-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8450.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 920a2d1c04d0c..1ac74ff586b86 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -5104,7 +5104,7 @@ intc: interrupt-controller@17100000 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x17140000 0x0 0x20000>; ++ reg = <0x0 0x17140000 0x0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8550-correct-iris-corners-for-the-m.patch b/queue-7.0/arm64-dts-qcom-sm8550-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..0c4852252a --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8550-correct-iris-corners-for-the-m.patch @@ -0,0 +1,53 @@ +From e3f4d3a3f2ff7f49074b1b716dc253a5d6be7068 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:11 +0200 +Subject: arm64: dts: qcom: sm8550: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit ff8edb5bc8bdf8bdf4573d8dc062b09cc1e6bc76 ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: 41661853ae8e ("arm64: dts: qcom: sm8550: add iris DT node") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-4-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index e3f93f4f412de..6a338c522ee92 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -3320,19 +3320,19 @@ opp-338000000 { + + opp-366000000 { + opp-hz = /bits/ 64 <366000000>; +- required-opps = <&rpmhpd_opp_svs_l1>, ++ required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_svs_l1>; + }; + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-533333334 { + opp-hz = /bits/ 64 <533333334>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-7.0/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..d15f5a679d --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,67 @@ +From 5070a8a775093d63387da035cc30d6d109eca177 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:14 +0200 +Subject: arm64: dts: qcom: sm8550: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit 66b0f024fba0728ddce6916dce173bb1bdd4eab0 ] + +The restriction on UHS-I speed modes was added to all SM8550 platforms +by copying it from SM8450 dtsi file, and due to the overclocking of SD +cards it was an actually reproducible problem. Since the latter issue +has been fixed, UHS-I speed modes are working fine on SM8550 boards, +below is the test performed on SM8550-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 23.5468 s, 45.6 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 11.9819 s, 89.6 MB/s + +Unset the UHS-I speed mode restrictions from the SM8550 platform dtsi +file, there is no indication that the SDHC controller is broken. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Reviewed-by: Neil Armstrong +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-6-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index a23f01ebe45d3..42f9deaadd86a 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -3227,9 +3227,6 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + max-sd-hs-hz = <37500000>; + dma-coherent; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0>; +- + status = "disabled"; + + sdhc2_opp_table: opp-table { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch b/queue-7.0/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..e5298375aa --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From c29603acb7110e81e2a6d1db4a340c7286e362b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:17 +0100 +Subject: arm64: dts: qcom: sm8550: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 357c559e386705609b6b9dc0544c420e3f91f3a0 ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-4-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index 6a338c522ee92..1f088219b2dae 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -5274,7 +5274,7 @@ ppi_cluster3: interrupt-partition-3 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0 0x17140000 0 0x20000>; ++ reg = <0 0x17140000 0 0x40000>; + msi-controller; + #msi-cells = <1>; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch b/queue-7.0/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch new file mode 100644 index 0000000000..c7bf0df8a2 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch @@ -0,0 +1,46 @@ +From 08b67a63b64b751d1f3d4ac700ac7e2a8ba734a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:10 +0200 +Subject: arm64: dts: qcom: sm8550: Fix xo clock supply of platform SD host + controller + +From: Vladimir Zapolskiy + +[ Upstream commit 30ac651c69bddbc83cab6d52fc5d2e03bed83282 ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: ffc50b2d3828 ("arm64: dts: qcom: Add base SM8550 dtsi") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-2-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index 1f088219b2dae..a23f01ebe45d3 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -3210,7 +3210,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", "core", "xo"; + iommus = <&apps_smmu 0x540 0>; + qcom,dll-config = <0x0007642c>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8650-correct-iris-corners-for-the-m.patch b/queue-7.0/arm64-dts-qcom-sm8650-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..cdb372aaf9 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8650-correct-iris-corners-for-the-m.patch @@ -0,0 +1,62 @@ +From d3720723d00e876d7553af71579aef812d9d89d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:12 +0200 +Subject: arm64: dts: qcom: sm8650: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit 7c302a2a6c1a4644e798ecfc4e72ddc4acec653f ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: 56cf5ad39a55 ("arm64: dts: qcom: sm8650: add iris DT node") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-5-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 357e43b907405..9437360ea2153 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -5236,13 +5236,13 @@ opp-196000000 { + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; +- required-opps = <&rpmhpd_opp_low_svs>, ++ required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_low_svs>; + }; + + opp-380000000 { + opp-hz = /bits/ 64 <380000000>; +- required-opps = <&rpmhpd_opp_svs>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs>; + }; + +@@ -5254,13 +5254,13 @@ opp-435000000 { + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-533333334 { + opp-hz = /bits/ 64 <533333334>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_turbo>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch b/queue-7.0/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch new file mode 100644 index 0000000000..69c0ed88df --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch @@ -0,0 +1,68 @@ +From c20f40aeb5f7f2446cabc04bad1968b7712004f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:15 +0200 +Subject: arm64: dts: qcom: sm8650: Enable UHS-I SDR50 and SDR104 SD card modes + +From: Vladimir Zapolskiy + +[ Upstream commit 93f823e7d48232e62fb8fb74481696609c90244a ] + +The restriction on UHS-I speed modes was added to all SM8650 platforms +by copying it from SM8450 and SM8550 dtsi files, and it was an actually +reproducible problem due to the overclocking of SD cards. Since the latter +issue has been fixed in the SM8650 GCC driver, UHS-I speed modes are +working fine on SM8650 boards, below is the test performed on SM8650-HDK: + +SDR50 speed mode: + + mmc0: new UHS-I speed SDR50 SDHC card at address 0001 + mmcblk0: mmc0:0001 00000 14.6 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 24.8086 s, 43.3 MB/s + +SDR104 speed mode: + + mmc0: new UHS-I speed SDR104 SDHC card at address 59b4 + mmcblk0: mmc0:59b4 USDU1 28.3 GiB + mmcblk0: p1 + + % dd if=/dev/mmcblk0p1 of=/dev/null bs=1M count=1024 + 1024+0 records in + 1024+0 records out + 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 12.9448 s, 82.9 MB/s + +Unset the UHS-I speed mode restrictions from the SM8550 platform dtsi +file, there is no indication that the SDHC controller is broken. + +Fixes: 10e024671295 ("arm64: dts: qcom: sm8650: add interconnect dependent device nodes") +Reviewed-by: Neil Armstrong +Reviewed-by: Konrad Dybcio +Signed-off-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20260314023715.357512-7-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 75de839f7a2df..64a7480291d84 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -4976,9 +4976,6 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + + bus-width = <4>; + +- /* Forbid SDR104/SDR50 - broken hw! */ +- sdhci-caps-mask = <0x3 0>; +- + qcom,dll-config = <0x0007642c>; + qcom,ddr-config = <0x80040868>; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch b/queue-7.0/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..9cef749f7c --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch @@ -0,0 +1,38 @@ +From 37e7df822cf1bf65ce84a39959dd93209c8e3b53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:18 +0100 +Subject: arm64: dts: qcom: sm8650: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit 6c8e2ca1263d0da5976418ed285eaec430e8d87f ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: d2350377997f ("arm64: dts: qcom: add initial SM8650 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-5-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 9437360ea2153..070e8f706c239 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -7219,7 +7219,7 @@ ppi_cluster2: interrupt-partition-2 { + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; +- reg = <0 0x17140000 0 0x20000>; ++ reg = <0 0x17140000 0 0x40000>; + + msi-controller; + #msi-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch b/queue-7.0/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch new file mode 100644 index 0000000000..0584aa559e --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch @@ -0,0 +1,45 @@ +From 5f3d3ff6ee9bc3d8cdbcc22828a2640288dcb64d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 04:37:11 +0200 +Subject: arm64: dts: qcom: sm8650: Fix xo clock supply of SD host controller + +From: Vladimir Zapolskiy + +[ Upstream commit 390903efaa057c44fd80e7d9839419c50092018e ] + +The expected frequency of SD host controller core supply clock is 19.2MHz, +while RPMH_CXO_CLK clock frequency on SM8650 platform is 38.4MHz. + +Apparently the overclocked supply clock could be good enough on some +boards and even with the most of SD cards, however some low-end UHS-I +SD cards in SDR104 mode of the host controller produce I/O errors in +runtime, fortunately this problem is gone, if the "xo" clock frequency +matches the expected 19.2MHz clock rate. + +Fixes: 10e024671295 ("arm64: dts: qcom: sm8650: add interconnect dependent device nodes") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Konrad Dybcio +Reviewed-by: Neil Armstrong +Link: https://lore.kernel.org/r/20260314023715.357512-3-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8650.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 070e8f706c239..75de839f7a2df 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -4957,7 +4957,7 @@ sdhc_2: mmc@8804000 { + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, +- <&rpmhcc RPMH_CXO_CLK>; ++ <&bi_tcxo_div2>; + clock-names = "iface", + "core", + "xo"; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8750-correct-iris-corners-for-the-m.patch b/queue-7.0/arm64-dts-qcom-sm8750-correct-iris-corners-for-the-m.patch new file mode 100644 index 0000000000..9e97670b67 --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8750-correct-iris-corners-for-the-m.patch @@ -0,0 +1,76 @@ +From f488098f63f0dc971bfc2193fee00baa29e9f890 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 17:27:13 +0200 +Subject: arm64: dts: qcom: sm8750: correct Iris corners for the MXC rail + +From: Dmitry Baryshkov + +[ Upstream commit 2755bdd02a43c204fb0ca02b93787a863c1cf9d2 ] + +The corners of the MVS0 / MVS0C clocks on the MMCX rail don't always +match the PLL corners on the MXC rail. Correct the performance corners +for the MXC rail following the PLL documentation. + +Fixes: c0d11ff90475 ("arm64: dts: qcom: sm8750: Add Iris VPU v3.5") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Dikshita Agarwal +Link: https://lore.kernel.org/r/20260313-iris-fix-corners-v1-6-32a393c25dda@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8750.dtsi | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi +index f56b1f889b857..f34f112d3aa34 100644 +--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi +@@ -2945,19 +2945,19 @@ iris_opp_table: opp-table { + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; +- required-opps = <&rpmhpd_opp_low_svs_d1>, ++ required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_low_svs_d1>; + }; + + opp-338000000 { + opp-hz = /bits/ 64 <338000000>; +- required-opps = <&rpmhpd_opp_low_svs>, ++ required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_low_svs>; + }; + + opp-420000000 { + opp-hz = /bits/ 64 <420000000>; +- required-opps = <&rpmhpd_opp_svs>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs>; + }; + +@@ -2969,19 +2969,19 @@ opp-444000000 { + + opp-533333334 { + opp-hz = /bits/ 64 <533333334>; +- required-opps = <&rpmhpd_opp_nom>, ++ required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_nom>; + }; + + opp-570000000 { + opp-hz = /bits/ 64 <570000000>; +- required-opps = <&rpmhpd_opp_nom_l1>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_nom_l1>; + }; + + opp-630000000 { + opp-hz = /bits/ 64 <630000000>; +- required-opps = <&rpmhpd_opp_turbo>, ++ required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_turbo>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-sm8750-fix-gic_its-range-length.patch b/queue-7.0/arm64-dts-qcom-sm8750-fix-gic_its-range-length.patch new file mode 100644 index 0000000000..39ba9983de --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-sm8750-fix-gic_its-range-length.patch @@ -0,0 +1,37 @@ +From 4409a2aef21aa7251a2e767277438b8b5fd13a5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:41:19 +0100 +Subject: arm64: dts: qcom: sm8750: Fix GIC_ITS range length + +From: Konrad Dybcio + +[ Upstream commit c2f1f8874fda674af1efaa9a90efbdea8b6834ff ] + +Currently, the GITS_SGIR register is cut off. Fix it up. + +Fixes: 068c3d3c83be ("arm64: dts: qcom: Add base SM8750 dtsi") +Signed-off-by: Konrad Dybcio +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260317-topic-its_range_fixup-v1-6-49be8076adb1@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/sm8750.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/qcom/sm8750.dtsi b/arch/arm64/boot/dts/qcom/sm8750.dtsi +index f34f112d3aa34..4efdead3583f9 100644 +--- a/arch/arm64/boot/dts/qcom/sm8750.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8750.dtsi +@@ -4658,7 +4658,7 @@ intc: interrupt-controller@16000000 { + + gic_its: msi-controller@16040000 { + compatible = "arm,gic-v3-its"; +- reg = <0x0 0x16040000 0x0 0x20000>; ++ reg = <0x0 0x16040000 0x0 0x40000>; + + msi-controller; + #msi-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-qcom-talos-add-missing-clock-names-to-gcc.patch b/queue-7.0/arm64-dts-qcom-talos-add-missing-clock-names-to-gcc.patch new file mode 100644 index 0000000000..af8695e5cf --- /dev/null +++ b/queue-7.0/arm64-dts-qcom-talos-add-missing-clock-names-to-gcc.patch @@ -0,0 +1,46 @@ +From 7077af0d624efa6ee2c19d44f9f0ca06a5f23dfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 10:45:03 +0100 +Subject: arm64: dts: qcom: talos: Add missing clock-names to GCC + +From: Konrad Dybcio + +[ Upstream commit c653607929bb4e0d8b80573bdb523adab5b975c2 ] + +The binding for this clock controller requires that clock-names are +present. They're not really used by the kernel driver, but they're +marked as required, so someone might have assumed it's done on purpose +(where in reality we try to stay away from that since index-based +references are faster, take up less space and are already widely used) +and referenced it in drivers for another OS. + +Hence, do the least painful thing and add the missing entries. + +Fixes: 8e266654a2fe ("arm64: dts: qcom: add QCS615 platform") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260126-topic-talos_dt_warn-v1-1-c452afc647ad@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/qcom/talos.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi +index 75716b4a58d6d..6dab0d5dcbb8a 100644 +--- a/arch/arm64/boot/dts/qcom/talos.dtsi ++++ b/arch/arm64/boot/dts/qcom/talos.dtsi +@@ -666,6 +666,9 @@ gcc: clock-controller@100000 { + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>; ++ clock-names = "bi_tcxo", ++ "bi_tcxo_ao", ++ "sleep_clk"; + + #clock-cells = <1>; + #reset-cells = <1>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-rockchip-add-mphy-reset-to-ufshc-node.patch b/queue-7.0/arm64-dts-rockchip-add-mphy-reset-to-ufshc-node.patch new file mode 100644 index 0000000000..022d3a05c2 --- /dev/null +++ b/queue-7.0/arm64-dts-rockchip-add-mphy-reset-to-ufshc-node.patch @@ -0,0 +1,47 @@ +From 9f4d245465b46bd2361c5402802e9c5357492986 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 09:11:53 +0800 +Subject: arm64: dts: rockchip: Add mphy reset to ufshc node + +From: Shawn Lin + +[ Upstream commit 792c42da47fa199f90492784e3c57280acd57f22 ] + +The mphy reset signal is used to reset the physical adapter. Resetting +other components while leaving the mphy unreset may occasionally prevent +the UFS controller from successfully linking up with the device. + +This addresses an intermittent hardware bug where the UFS link fails to +establish under specific timing conditions with certain chips. While +difficult to reproduce initially, this issue was consistently observed in +downstream testing and requires explicit mphy reset control for full +stability. + +Fixes: c75e5e010fef ("scsi: arm64: dts: rockchip: Add UFS support for RK3576 SoC") +Signed-off-by: Shawn Lin +Link: https://patch.msgid.link/1773277913-29580-1-git-send-email-shawn.lin@rock-chips.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3576.dtsi | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi +index 49ccdf12ef7eb..8149e2bbde79a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi +@@ -1868,8 +1868,9 @@ ufshc: ufshc@2a2d0000 { + pinctrl-0 = <&ufs_refclk &ufs_rstgpio>; + pinctrl-names = "default"; + resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>, +- <&cru SRST_A_UFS>, <&cru SRST_P_UFS_GRF>; +- reset-names = "biu", "sys", "ufs", "grf"; ++ <&cru SRST_A_UFS>, <&cru SRST_P_UFS_GRF>, ++ <&cru SRST_MPHY_INIT>; ++ reset-names = "biu", "sys", "ufs", "grf", "mphy"; + reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>; + status = "disabled"; + }; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch b/queue-7.0/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch new file mode 100644 index 0000000000..9f80b57f48 --- /dev/null +++ b/queue-7.0/arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch @@ -0,0 +1,39 @@ +From daa2b9411aecb5a8e17139a135efde339b77f274 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 08:46:48 -0500 +Subject: arm64: dts: rockchip: Correct Fan Supply for Gameforce Ace + +From: Chris Morgan + +[ Upstream commit c7079215b7dbf88b84a95ff13982bf3dab3cfbe1 ] + +Correct the regulator providing power to the PWM controlled fan. +Without this fix the fan only runs when the audio path is playing +audio (because the speaker amplifier and PWM fan share the same +regulator). + +Fixes: 4e946c447a04 ("arm64: dts: rockchip: Add GameForce Ace") +Signed-off-by: Chris Morgan +Link: https://patch.msgid.link/20260310134648.550006-1-macroalpha82@gmail.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +index e8ad525ba3f9b..59d2494c45100 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +@@ -318,7 +318,7 @@ pwm_fan: pwm-fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + cooling-levels = <0 120 150 180 210 240 255>; +- fan-supply = <&vcc5v0_sys>; ++ fan-supply = <&vcc5v0_spk>; + interrupt-parent = <&gpio4>; + interrupts = ; + pulses-per-revolution = <4>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch b/queue-7.0/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch new file mode 100644 index 0000000000..c674b716f2 --- /dev/null +++ b/queue-7.0/arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch @@ -0,0 +1,70 @@ +From 34b9969a6e81140c582b2d68fa15cf437b454fcc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 08:49:19 -0500 +Subject: arm64: dts: rockchip: Correct Joystick Axes on Gameforce Ace + +From: Chris Morgan + +[ Upstream commit c337c1b561c1c3016d30776d7dc2032ea4979334 ] + +The Gameforce Ace's joystick axes were set incorrectly initially, +getting the X/Y and RX/RY axes backwards. Additionally, correct the +RY axis so that it is inverted. + +All axes tested with evtest and outputting correct values. + +Fixes: 4e946c447a04 ("arm64: dts: rockchip: Add GameForce Ace") +Reported-by: sydarn +Signed-off-by: Chris Morgan +Link: https://patch.msgid.link/20260310134919.550023-1-macroalpha82@gmail.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +index 59d2494c45100..89618394c0bfb 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +@@ -60,8 +60,8 @@ axis@0 { + reg = <0>; + abs-flat = <40>; + abs-fuzz = <30>; +- abs-range = <0 4095>; +- linux,code = ; ++ abs-range = <4095 0>; ++ linux,code = ; + }; + + axis@1 { +@@ -69,7 +69,7 @@ axis@1 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + + axis@2 { +@@ -77,7 +77,7 @@ axis@2 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + + axis@3 { +@@ -85,7 +85,7 @@ axis@3 { + abs-flat = <40>; + abs-fuzz = <30>; + abs-range = <0 4095>; +- linux,code = ; ++ linux,code = ; + }; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch b/queue-7.0/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch new file mode 100644 index 0000000000..eb4c18e33e --- /dev/null +++ b/queue-7.0/arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch @@ -0,0 +1,49 @@ +From 5d58e2afdd52cc7185a85118d5ed53b35940ff89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Feb 2026 17:04:53 +0800 +Subject: arm64: dts: rockchip: Fix Bluetooth stability on LCKFB TaiShan Pi + +From: Ming Wang + +[ Upstream commit 861a9593e10bb6ab2a492b315c8a2a3aad70ac00 ] + +The AP6212 WiFi/BT module on the LCKFB TaiShan Pi (RK3566) is prone to +communication timeouts and reset failures (error -110) when operating at +3 Mbps. + +This patch stabilizes the Bluetooth interface by: +1. Updating the compatible string to 'brcm,bcm43430a1-bt' to better reflect + the actual chip revision used in the AP6212 module. +2. Lowering the maximum UART baud rate from 3,000,000 to 1,500,000 bps. + Tests show that 1.5 Mbps is the reliable upper limit for this board's + UART configuration, eliminating the initialization timeouts. + +Fixes: 251e5ade9ba4 ("arm64: dts: rockchip: add dts for LCKFB Taishan Pi RK3566") +Signed-off-by: Ming Wang +Link: https://patch.msgid.link/20260206090453.1041919-1-wming126@126.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts +index ed65d31204446..18a560a6e2a4a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts +@@ -635,10 +635,10 @@ &uart1 { + status = "okay"; + + bluetooth: bluetooth { +- compatible = "brcm,bcm43438-bt"; ++ compatible = "brcm,bcm43430a1-bt"; + clocks = <&rk809 1>; + clock-names = "lpo"; +- max-speed = <3000000>; ++ max-speed = <1500000>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_host_wake_l &bt_wake_l &bt_enable_h>; + shutdown-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-rockchip-fix-rk3562-evb2-model-name.patch b/queue-7.0/arm64-dts-rockchip-fix-rk3562-evb2-model-name.patch new file mode 100644 index 0000000000..7a1c79feae --- /dev/null +++ b/queue-7.0/arm64-dts-rockchip-fix-rk3562-evb2-model-name.patch @@ -0,0 +1,39 @@ +From d0a3c2f71bf3d68626a1861dfb33d6411a1060c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:55:00 +0000 +Subject: arm64: dts: rockchip: Fix RK3562 EVB2 model name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: 谢致邦 (XIE Zhibang) + +[ Upstream commit ede6a05606892bab4f6d785ffcfc124150c2eb32 ] + +The model name should be "Rockchip RK3562 EVB2 V10 Board". + +Fixes: ceb6ef1ea900 ("arm64: dts: rockchip: Add RK3562 evb2 devicetree") +Signed-off-by: 谢致邦 (XIE Zhibang) +Link: https://patch.msgid.link/tencent_78E7E3F6991FB4403D5ADC9E6A6BC3BF8307@qq.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts b/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts +index 6a84db154a7d5..387062eea5208 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3562-evb2-v10.dts +@@ -13,7 +13,7 @@ + #include "rk3562.dtsi" + + / { +- model = "Rockchip RK3562 EVB V20 Board"; ++ model = "Rockchip RK3562 EVB2 V10 Board"; + compatible = "rockchip,rk3562-evb2-v10", "rockchip,rk3562"; + + chosen: chosen { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch b/queue-7.0/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch new file mode 100644 index 0000000000..57ee7e9637 --- /dev/null +++ b/queue-7.0/arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch @@ -0,0 +1,42 @@ +From acc53029d4ea51048e664aa8685c623d1511d1f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 09:03:02 +0100 +Subject: arm64: dts: rockchip: Make Jaguar PCIe-refclk pin use pull-up config + +From: Heiko Stuebner + +[ Upstream commit f45d4356feeba1c8dac3414b688f59292ddfc9f9 ] + +The hardware PU/PD config of the pin after reset is to pull-up and on +Jaguar this will also keep the device in reset until the driver actually +enables the pin. So restore this boot pull-up config of the pin on Jaguar +instead of setting it to pull-none. + +Suggested-by: Quentin Schulz +Fixes: 0ec7e1096332 ("arm64: dts: rockchip: add PCIe3 support on rk3588-jaguar") +Signed-off-by: Heiko Stuebner +Reviewed-by: Shawn Lin +Reviewed-by: Quentin Schulz +Link: https://patch.msgid.link/20260210080303.680403-5-heiko@sntech.de +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts +index 952affaf455cf..500a0bad1ea30 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts +@@ -588,7 +588,7 @@ led1_pin: led1-pin { + + pcie30x4 { + pcie30x4_clkreqn_m0: pcie30x4-clkreqn-m0 { +- rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; ++ rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + pcie30x4_perstn_m0: pcie30x4-perstn-m0 { +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch b/queue-7.0/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch new file mode 100644 index 0000000000..f86c2a09fe --- /dev/null +++ b/queue-7.0/arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch @@ -0,0 +1,58 @@ +From d1c6a1b54d8d44ccf35463de285fc7db014a3911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 17:37:31 -0600 +Subject: arm64: dts: ti: k3-am62-lp-sk: Enable internal pulls for MMC0 data + pins + +From: Judith Mendez + +[ Upstream commit ee2a9d9c9e6c9643fb7e45febcaedfbc038e483a ] + +AM62 LP SK board does not have external pullups on MMC0 DAT1-DAT7 +pins [0]. Enable internal pullups on DAT1-DAT7 considering: +- without a host-side pullup, these lines rely solely on the eMMC + device's internal pullup (R_int, 10-150K per JEDEC), which may + exceed the recommended 50K max for 1.8V VCCQ +- JEDEC JESD84-B51 Table 200 requires host-side pullups (R_DAT, + 10K-100K) on all data lines to prevent bus floating + +[0] https://www.ti.com/lit/zip/SPRR471 + +Fixes: a0b8da04153e ("arm64: dts: ti: k3-am62*: Move eMMC pinmux to top level board file") +Signed-off-by: Judith Mendez +Reviewed-by: Moteen Shah +Link: https://patch.msgid.link/20260223233731.2690472-4-jm@ti.com +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts +index 3e2d8f6695351..8a556fbbe08b7 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62-lp-sk.dts +@@ -88,13 +88,13 @@ main_mmc0_pins_default: main-mmc0-default-pins { + AM62X_IOPAD(0x220, PIN_INPUT, 0) /* (V3) MMC0_CMD */ + AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (Y1) MMC0_CLK */ + AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (V2) MMC0_DAT0 */ +- AM62X_IOPAD(0x210, PIN_INPUT, 0) /* (V1) MMC0_DAT1 */ +- AM62X_IOPAD(0x20c, PIN_INPUT, 0) /* (W2) MMC0_DAT2 */ +- AM62X_IOPAD(0x208, PIN_INPUT, 0) /* (W1) MMC0_DAT3 */ +- AM62X_IOPAD(0x204, PIN_INPUT, 0) /* (Y2) MMC0_DAT4 */ +- AM62X_IOPAD(0x200, PIN_INPUT, 0) /* (W3) MMC0_DAT5 */ +- AM62X_IOPAD(0x1fc, PIN_INPUT, 0) /* (W4) MMC0_DAT6 */ +- AM62X_IOPAD(0x1f8, PIN_INPUT, 0) /* (V4) MMC0_DAT7 */ ++ AM62X_IOPAD(0x210, PIN_INPUT_PULLUP, 0) /* (V1) MMC0_DAT1 */ ++ AM62X_IOPAD(0x20c, PIN_INPUT_PULLUP, 0) /* (W2) MMC0_DAT2 */ ++ AM62X_IOPAD(0x208, PIN_INPUT_PULLUP, 0) /* (W1) MMC0_DAT3 */ ++ AM62X_IOPAD(0x204, PIN_INPUT_PULLUP, 0) /* (Y2) MMC0_DAT4 */ ++ AM62X_IOPAD(0x200, PIN_INPUT_PULLUP, 0) /* (W3) MMC0_DAT5 */ ++ AM62X_IOPAD(0x1fc, PIN_INPUT_PULLUP, 0) /* (W4) MMC0_DAT6 */ ++ AM62X_IOPAD(0x1f8, PIN_INPUT_PULLUP, 0) /* (V4) MMC0_DAT7 */ + >; + }; + +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch b/queue-7.0/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch new file mode 100644 index 0000000000..c429e9f5d7 --- /dev/null +++ b/queue-7.0/arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch @@ -0,0 +1,39 @@ +From f8fc9a2718e16ab1ea2bcdc4735fef9555842be4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:36:57 +0100 +Subject: arm64: dts: ti: k3-am62-verdin: Fix SPI_1 GPIO CS pinctrl label + +From: Francesco Dolcini + +[ Upstream commit 944dffaec1ef0f21c203728de77b5618ed70df6e ] + +Fix SPI_1_CS GPIO pinmux label, this is spi1_cs, not qspi1_io4. + +There are no user of this label yet, therefore this change does not +create any compatibility issue. + +Fixes: fcb335934c51 ("arm64: dts: ti: verdin-am62: Improve spi1 chip-select pinctrl") +Signed-off-by: Francesco Dolcini +Link: https://patch.msgid.link/20260324093705.26730-3-francesco@dolcini.it +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +index 09840a3b9fe75..20dbfa3001eac 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +@@ -278,7 +278,7 @@ AM62X_IOPAD(0x0018, PIN_INPUT, 7) /* (F24) OSPI0_D3.GPIO0_6 */ /* SODIMM 62 */ + }; + + /* Verdin SPI_1 CS as GPIO */ +- pinctrl_qspi1_io4_gpio: main-gpio0-7-default-pins { ++ pinctrl_spi1_cs_gpio: main-gpio0-7-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 7) /* (J23) OSPI0_D4.GPIO0_7 */ /* SODIMM 202 */ + >; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-ti-k3-am62l-include-wkup_uart0-in-wakeup-p.patch b/queue-7.0/arm64-dts-ti-k3-am62l-include-wkup_uart0-in-wakeup-p.patch new file mode 100644 index 0000000000..b01fa4f671 --- /dev/null +++ b/queue-7.0/arm64-dts-ti-k3-am62l-include-wkup_uart0-in-wakeup-p.patch @@ -0,0 +1,49 @@ +From 54178cb78a600a3e01fb5df2a7899ac6224983cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 13:43:16 -0600 +Subject: arm64: dts: ti: k3-am62l: include WKUP_UART0 in wakeup peripheral + window + +From: Kendall Willis + +[ Upstream commit e5452968a4b04f93bf9b778ccfd00f79e4d4f529 ] + +WKUP_UART0 is apart of the wakeup peripherals and has a range from +0x002B300000 to 0x002B3001FF. Expand the wakeup peripheral window to +include WKUP_UART0. + +Fixes: 5f016758b0ab ("arm64: dts: ti: k3-am62l: add initial infrastructure") +Reviewed-by: Dhruva Gole +Signed-off-by: Kendall Willis +Link: https://patch.msgid.link/20260219-v6-19-wkup-uart-wakeup-v4-1-eda09dce5623@ti.com +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62l.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62l.dtsi b/arch/arm64/boot/dts/ti/k3-am62l.dtsi +index 23acdbb301fe3..e01e342c26daa 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62l.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62l.dtsi +@@ -92,7 +92,7 @@ cbass_main: bus@f0000 { + <0x00 0x00b00000 0x00 0x00b00000 0x00 0x00001400>, /* VTM */ + <0x00 0x04080000 0x00 0x04080000 0x00 0x00008000>, /* PDCFG */ + <0x00 0x04201000 0x00 0x04201000 0x00 0x00000100>, /* GPIO */ +- <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00100100>, /* Wakeup Peripheral Window */ ++ <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00200200>, /* Wakeup Peripheral Window */ + <0x00 0x40800000 0x00 0x40800000 0x00 0x00014000>, /* DMA */ + <0x00 0x43000000 0x00 0x43000000 0x00 0x00080000>; /* CTRL MMRs */ + #address-cells = <2>; +@@ -104,7 +104,7 @@ cbass_wakeup: bus@a80000 { + <0x00 0x00b00000 0x00 0x00b00000 0x00 0x00001400>, /* VTM */ + <0x00 0x04080000 0x00 0x04080000 0x00 0x00008000>, /* PDCFG */ + <0x00 0x04201000 0x00 0x04201000 0x00 0x00000100>, /* GPIO */ +- <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00100100>, /* Wakeup Peripheral Window */ ++ <0x00 0x2b100000 0x00 0x2b100000 0x00 0x00200200>, /* Wakeup Peripheral Window */ + <0x00 0x40800000 0x00 0x40800000 0x00 0x00014000>, /* DMA */ + <0x00 0x43000000 0x00 0x43000000 0x00 0x00080000>; /* CTRL MMRs */ + #address-cells = <2>; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-ti-k3-am62l3-evm-disable-mmc1-internal-pul.patch b/queue-7.0/arm64-dts-ti-k3-am62l3-evm-disable-mmc1-internal-pul.patch new file mode 100644 index 0000000000..7cfbb25f63 --- /dev/null +++ b/queue-7.0/arm64-dts-ti-k3-am62l3-evm-disable-mmc1-internal-pul.patch @@ -0,0 +1,53 @@ +From 220fcd08e77436eb7a2ed3f4b76549d3db9e9fb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 17:37:30 -0600 +Subject: arm64: dts: ti: k3-am62l3-evm: Disable MMC1 internal pulls on data + pins + +From: Judith Mendez + +[ Upstream commit 02532ba56362907b6aca3e8289c4a9247ef83325 ] + +AM62L EVM has external 47K pullups on MMC1 DAT1-DAT3 pins [0]. +Disable internal pullups on DAT1-DAT3 so that each line has a +single pullup source: +- with both pullups enabled, the effective parallel resistance on + DAT1-3 (~24.2K) creates a ~2x mismatch vs DAT0 (47K external + only). Removing internal pullups results in DAT1-3 matching DAT0 at 47K +- 47K external alone is within the recommended range for 1.8V + signaling (10K min, 50K recommended max) +- both internal and external pullups enabled equals unnecessary power + consumption + +[0] https://www.ti.com/lit/zip/SPRCAL6 + +Fixes: 00fb4c73b67d ("arm64: dts: ti: k3-am62l: add initial reference board file") +Signed-off-by: Judith Mendez +Reviewed-by: Moteen Shah +Link: https://patch.msgid.link/20260223233731.2690472-3-jm@ti.com +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62l3-evm.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts b/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts +index cae04cce33736..bd876c68aa347 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62l3-evm.dts +@@ -272,9 +272,9 @@ mmc1_pins_default: mmc1-default-pins { + AM62LX_IOPAD(0x0230, PIN_INPUT, 0) /* (Y3) MMC1_CMD */ + AM62LX_IOPAD(0x0228, PIN_OUTPUT, 0) /* (Y2) MMC1_CLK */ + AM62LX_IOPAD(0x0224, PIN_INPUT, 0) /* (AA1) MMC1_DAT0 */ +- AM62LX_IOPAD(0x0220, PIN_INPUT_PULLUP, 0) /* (Y4) MMC1_DAT1 */ +- AM62LX_IOPAD(0x021c, PIN_INPUT_PULLUP, 0) /* (AA2) MMC1_DAT2 */ +- AM62LX_IOPAD(0x0218, PIN_INPUT_PULLUP, 0) /* (AB2) MMC1_DAT3 */ ++ AM62LX_IOPAD(0x0220, PIN_INPUT, 0) /* (Y4) MMC1_DAT1 */ ++ AM62LX_IOPAD(0x021c, PIN_INPUT, 0) /* (AA2) MMC1_DAT2 */ ++ AM62LX_IOPAD(0x0218, PIN_INPUT, 0) /* (AB2) MMC1_DAT3 */ + AM62LX_IOPAD(0x0234, PIN_INPUT, 0) /* (B6) MMC1_SDCD */ + >; + bootph-all; +-- +2.53.0 + diff --git a/queue-7.0/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch b/queue-7.0/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch new file mode 100644 index 0000000000..6714ec3d66 --- /dev/null +++ b/queue-7.0/arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch @@ -0,0 +1,53 @@ +From c361fb083412b1dc115f3080b1ef4cdbff49718f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 17:37:29 -0600 +Subject: arm64: dts: ti: k3-am62p5-sk: Disable MMC1 internal pulls on data + pins + +From: Judith Mendez + +[ Upstream commit 6d4441be969bea89bb9702781f5dfb3a8f2a02a4 ] + +AM62P SK has external 10K pullups on MMC1 DAT1-DAT3 pins [0]. +Disable internal pullups on DAT1-DAT3 so that each line has a +single pullup source: +- with both pullups enabled, the effective parallel resistance on + DAT1-3 (~8.33K) drops below the 10K minimum pullup requirement + for data lines (per SD Physical Layer Specification) +- removing internal pullups makes DAT1-3 match DAT0 10K + external pullup so its consistent and within spec +- both internal and external pullups enabled equals unnecessary power + consumption + +[0] https://www.ti.com/lit/zip/SPRR487 + +Fixes: c00504ea42c0 ("arm64: dts: ti: k3-am62p5-sk: Updates for SK EVM") +Signed-off-by: Judith Mendez +Reviewed-by: Moteen Shah +Link: https://patch.msgid.link/20260223233731.2690472-2-jm@ti.com +Signed-off-by: Vignesh Raghavendra +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/ti/k3-am62p5-sk.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +index 4f7f6f95b02ef..35baa777b9121 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +@@ -271,9 +271,9 @@ main_mmc1_pins_default: main-mmc1-default-pins { + AM62PX_IOPAD(0x023c, PIN_INPUT, 0) /* (H20) MMC1_CMD */ + AM62PX_IOPAD(0x0234, PIN_OUTPUT, 0) /* (J24) MMC1_CLK */ + AM62PX_IOPAD(0x0230, PIN_INPUT, 0) /* (H21) MMC1_DAT0 */ +- AM62PX_IOPAD(0x022c, PIN_INPUT_PULLUP, 0) /* (H23) MMC1_DAT1 */ +- AM62PX_IOPAD(0x0228, PIN_INPUT_PULLUP, 0) /* (H22) MMC1_DAT2 */ +- AM62PX_IOPAD(0x0224, PIN_INPUT_PULLUP, 0) /* (H25) MMC1_DAT3 */ ++ AM62PX_IOPAD(0x022c, PIN_INPUT, 0) /* (H23) MMC1_DAT1 */ ++ AM62PX_IOPAD(0x0228, PIN_INPUT, 0) /* (H22) MMC1_DAT2 */ ++ AM62PX_IOPAD(0x0224, PIN_INPUT, 0) /* (H25) MMC1_DAT3 */ + AM62PX_IOPAD(0x0240, PIN_INPUT, 0) /* (D23) MMC1_SDCD */ + >; + bootph-all; +-- +2.53.0 + diff --git a/queue-7.0/arm64-entry-don-t-preempt-with-serror-or-debug-maske.patch b/queue-7.0/arm64-entry-don-t-preempt-with-serror-or-debug-maske.patch new file mode 100644 index 0000000000..61b51a50b7 --- /dev/null +++ b/queue-7.0/arm64-entry-don-t-preempt-with-serror-or-debug-maske.patch @@ -0,0 +1,87 @@ +From 7401913543ad390bb84baecb31bbae2d8026db9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 14:16:46 +0100 +Subject: arm64: entry: Don't preempt with SError or Debug masked + +From: Mark Rutland + +[ Upstream commit 2371bd83b3df9d833191fe58dadb0e69a794a1cd ] + +On arm64, involuntary kernel preemption has been subtly broken since the +move to the generic irqentry code. When preemption occurs, the new task +may run with SError and Debug exceptions masked unexpectedly, leading to +a loss of RAS events, breakpoints, watchpoints, and single-step +exceptions. + +Prior to moving to the generic irqentry code, involuntary preemption of +kernel mode would only occur when returning from regular interrupts, in +a state where interrupts were masked and all other arm64-specific +exceptions (SError, Debug, and pseudo-NMI) were unmasked. This is the +only state in which it is valid to switch tasks. + +As part of moving to the generic irqentry code, the involuntary +preemption logic was moved such that involuntary preemption could occur +when returning from any (non-NMI) exception. As most exception handlers +mask all arm64-specific exceptions before this point, preemption could +occur in a state where arm64-specific exceptions were masked. This is +not a valid state to switch tasks, and resulted in the loss of +exceptions described above. + +As a temporary bodge, avoid the loss of exceptions by avoiding +involuntary preemption when SError and/or Debug exceptions are masked. +Practically speaking this means that involuntary preemption will only +occur when returning from regular interrupts, as was the case before +moving to the generic irqentry code. + +Fixes: 99eb057ccd67 ("arm64: entry: Move arm64_preempt_schedule_irq() into __exit_to_kernel_mode()") +Reported-by: Ada Couprie Diaz +Reported-by: Vladimir Murzin +Signed-off-by: Mark Rutland +Cc: Andy Lutomirski +Cc: Jinjie Ruan +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Cc: Will Deacon +Reviewed-by: Jinjie Ruan +Acked-by: Peter Zijlstra (Intel) +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/entry-common.h | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/arch/arm64/include/asm/entry-common.h b/arch/arm64/include/asm/entry-common.h +index cab8cd78f6938..20f0a7c7bde15 100644 +--- a/arch/arm64/include/asm/entry-common.h ++++ b/arch/arm64/include/asm/entry-common.h +@@ -29,14 +29,19 @@ static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs, + + static inline bool arch_irqentry_exit_need_resched(void) + { +- /* +- * DAIF.DA are cleared at the start of IRQ/FIQ handling, and when GIC +- * priority masking is used the GIC irqchip driver will clear DAIF.IF +- * using gic_arch_enable_irqs() for normal IRQs. If anything is set in +- * DAIF we must have handled an NMI, so skip preemption. +- */ +- if (system_uses_irq_prio_masking() && read_sysreg(daif)) +- return false; ++ if (system_uses_irq_prio_masking()) { ++ /* ++ * DAIF.DA are cleared at the start of IRQ/FIQ handling, and when GIC ++ * priority masking is used the GIC irqchip driver will clear DAIF.IF ++ * using gic_arch_enable_irqs() for normal IRQs. If anything is set in ++ * DAIF we must have handled an NMI, so skip preemption. ++ */ ++ if (read_sysreg(daif)) ++ return false; ++ } else { ++ if (read_sysreg(daif) & (PSR_D_BIT | PSR_A_BIT)) ++ return false; ++ } + + /* + * Preempting a task from an IRQ means we leave copies of PSTATE +-- +2.53.0 + diff --git a/queue-7.0/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch b/queue-7.0/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch new file mode 100644 index 0000000000..a21a54874a --- /dev/null +++ b/queue-7.0/arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch @@ -0,0 +1,38 @@ +From cad9af52fb39d84531fea42a8884d3eed7c6b561 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 19:42:31 +0800 +Subject: arm64: kexec: Remove duplicate allocation for trans_pgd + +From: Wang Wensheng + +[ Upstream commit ee020bf6f14094c9ae434bb37e6957a1fdad513c ] + +trans_pgd would be allocated in trans_pgd_create_copy(), so remove the +duplicate allocation before calling trans_pgd_create_copy(). + +Fixes: 3744b5280e67 ("arm64: kexec: install a copy of the linear-map") +Signed-off-by: Wang Wensheng +Reviewed-by: Pasha Tatashin +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/machine_kexec.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c +index 239c16e3d02f2..c5693a32e49b0 100644 +--- a/arch/arm64/kernel/machine_kexec.c ++++ b/arch/arm64/kernel/machine_kexec.c +@@ -129,9 +129,6 @@ int machine_kexec_post_load(struct kimage *kimage) + } + + /* Create a copy of the linear map */ +- trans_pgd = kexec_page_alloc(kimage); +- if (!trans_pgd) +- return -ENOMEM; + rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END); + if (rc) + return rc; +-- +2.53.0 + diff --git a/queue-7.0/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch b/queue-7.0/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch new file mode 100644 index 0000000000..9356bada91 --- /dev/null +++ b/queue-7.0/arm64-reserve-an-extra-page-for-early-kernel-mapping.patch @@ -0,0 +1,86 @@ +From 0f34ff125ea58ca3770ae13b9f076a3f5ae9a5b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Apr 2026 16:58:08 +0800 +Subject: arm64: Reserve an extra page for early kernel mapping + +From: Zhaoyang Huang + +[ Upstream commit 4d8e74ad4585672489da6145b3328d415f50db82 ] + +The final part of [data, end) segment may overflow into the next page of +init_pg_end[1] which is the gap page before early_init_stack[2]: + +[1] +crash_arm64_v9.0.1> vtop ffffffed00601000 +VIRTUAL PHYSICAL +ffffffed00601000 83401000 + +PAGE DIRECTORY: ffffffecffd62000 + PGD: ffffffecffd62da0 => 10000000833fb003 + PMD: ffffff80033fb018 => 10000000833fe003 + PTE: ffffff80033fe008 => 68000083401f03 + PAGE: 83401000 + + PTE PHYSICAL FLAGS +68000083401f03 83401000 (VALID|SHARED|AF|NG|PXN|UXN) + + PAGE PHYSICAL MAPPING INDEX CNT FLAGS +fffffffec00d0040 83401000 0 0 1 4000 reserved + +[2] +ffffffed002c8000 (r) __pi__data +ffffffed0054e000 (d) __pi___bss_start +ffffffed005f5000 (b) __pi_init_pg_dir +ffffffed005fe000 (b) __pi_init_pg_end +ffffffed005ff000 (B) early_init_stack +ffffffed00608000 (b) __pi__end + +For 4K pages, the early kernel mapping may use 2MB block entries but the +kernel segments are only 64KB aligned. Segment boundaries that fall +within a 2MB block therefore require a PTE table so that different +attributes can be applied on either side of the boundary. + +KERNEL_SEGMENT_COUNT still correctly counts the five permanent kernel +VMAs registered by declare_kernel_vmas(). However, since commit +5973a62efa34 ("arm64: map [_text, _stext) virtual address range +non-executable+read-only"), the early mapper also maps [_text, _stext) +separately from [_stext, _etext). This adds one more early-only split +and can require one more page-table page than the existing +EARLY_SEGMENT_EXTRA_PAGES allowance reserves. + +Increase the 4K-page early mapping allowance by one page to cover that +additional split. + +Fixes: 5973a62efa34 ("arm64: map [_text, _stext) virtual address range non-executable+read-only") +Assisted-by: TRAE:GLM-5.1 +Suggested-by: Ard Biesheuvel +Signed-off-by: Zhaoyang Huang +[catalin.marinas@arm.com: rewrote part of the commit log] +[catalin.marinas@arm.com: expanded the code comment] +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/kernel-pgtable.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h +index 74a4f738c5f52..229ee7976f693 100644 +--- a/arch/arm64/include/asm/kernel-pgtable.h ++++ b/arch/arm64/include/asm/kernel-pgtable.h +@@ -68,7 +68,12 @@ + #define KERNEL_SEGMENT_COUNT 5 + + #if SWAPPER_BLOCK_SIZE > SEGMENT_ALIGN +-#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1) ++/* ++ * KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping ++ * has one additional split, [_text, _stext). Reserve one more page for the ++ * SWAPPER_BLOCK_SIZE-unaligned boundaries. ++ */ ++#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2) + /* + * The initial ID map consists of the kernel image, mapped as two separate + * segments, and may appear misaligned wrt the swapper block size. This means +-- +2.53.0 + diff --git a/queue-7.0/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch b/queue-7.0/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch new file mode 100644 index 0000000000..b3444b8cfa --- /dev/null +++ b/queue-7.0/arm64-scs-fix-potential-sign-extension-issue-of-adva.patch @@ -0,0 +1,47 @@ +From 4a2cf46860011d97a342eecbd85c0c9b13daabb4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 17:54:59 +0800 +Subject: arm64/scs: Fix potential sign extension issue of advance_loc4 + +From: Wentao Guan + +[ Upstream commit 4023b7424ecd5d38cc75b650d6c1bf630ef8cb40 ] + +The expression (*opcode++ << 24) and exp * code_alignment_factor +may overflow signed int and becomes negative. + +Fix this by casting each byte to u64 before shifting. Also fix +the misaligned break statement while we are here. + +Example of the result can be seen here: +Link: https://godbolt.org/z/zhY8d3595 + +It maybe not a real problem, but could be a issue in future. + +Fixes: d499e9627d70 ("arm64/scs: Fix handling of advance_loc4") +Signed-off-by: Wentao Guan +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/pi/patch-scs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/pi/patch-scs.c b/arch/arm64/kernel/pi/patch-scs.c +index dac568e4a54f2..3944ad899021c 100644 +--- a/arch/arm64/kernel/pi/patch-scs.c ++++ b/arch/arm64/kernel/pi/patch-scs.c +@@ -196,9 +196,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, + loc += *opcode++ * code_alignment_factor; + loc += (*opcode++ << 8) * code_alignment_factor; + loc += (*opcode++ << 16) * code_alignment_factor; +- loc += (*opcode++ << 24) * code_alignment_factor; ++ loc += ((u64)*opcode++ << 24) * code_alignment_factor; + size -= 4; +- break; ++ break; + + case DW_CFA_def_cfa: + case DW_CFA_offset_extended: +-- +2.53.0 + diff --git a/queue-7.0/arm64-tegra-fix-rtc-aliases.patch b/queue-7.0/arm64-tegra-fix-rtc-aliases.patch new file mode 100644 index 0000000000..023d959e6d --- /dev/null +++ b/queue-7.0/arm64-tegra-fix-rtc-aliases.patch @@ -0,0 +1,54 @@ +From 9829af325ea440947bb9a7efe92ae8a2ed99178b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 15:16:59 +0000 +Subject: arm64: tegra: Fix RTC aliases + +From: Jon Hunter + +[ Upstream commit 69ec77b3f1074f3000d28f67f7629303e7999b84 ] + +The following warning is observed on the Tegra234 Jetson platforms ... + + rtc-nvidia-vrs10 4-003c: /aliases ID 0 not available + +This happens because the 'rtc@c2a0000' device is registered before the +vrs10 RTC and so is assigned the 'rtc0' alias. We want the vrs10 RTC to +be the default RTC because this RTC maintains time across power cycles. +Fix this by adding a 'rtc1' alias for the 'rtc@c2a0000' device. + +Fixes: b1806f2b4e78 ("arm64: tegra: Add device-tree node for NVVRS RTC") +Signed-off-by: Jon Hunter +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi | 1 + + arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi +index 58bf55c0e414c..c10d041c183be 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3701.dtsi +@@ -9,6 +9,7 @@ aliases { + mmc0 = "/bus@0/mmc@3460000"; + mmc1 = "/bus@0/mmc@3400000"; + rtc0 = "/bpmp/i2c/pmic@3c"; ++ rtc1 = "/bus@0/rtc@c2a0000"; + }; + + bus@0 { +diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi +index ab391a71c3d33..9e9e80d57623c 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234-p3767.dtsi +@@ -8,6 +8,7 @@ / { + aliases { + mmc0 = "/bus@0/mmc@3400000"; + rtc0 = "/bpmp/i2c/pmic@3c"; ++ rtc1 = "/bus@0/rtc@c2a0000"; + }; + + bus@0 { +-- +2.53.0 + diff --git a/queue-7.0/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch b/queue-7.0/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch new file mode 100644 index 0000000000..1c75ff4d45 --- /dev/null +++ b/queue-7.0/arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch @@ -0,0 +1,79 @@ +From c6e1604c7ab8ffb6b0af20a39d617fd444af7dbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 07:16:35 +0100 +Subject: arm64/xor: fix conflicting attributes for xor_block_template + +From: Christoph Hellwig + +[ Upstream commit 675a0dd596e712404557286d0a883b54ee28e4f4 ] + +Commit 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +changes the definition to __ro_after_init instead of const, but failed to +update the external declaration in xor.h. This was not found because +xor-neon.c doesn't include , and can't easily do that due to +current architecture of the XOR code. + +Link: https://lkml.kernel.org/r/20260327061704.3707577-4-hch@lst.de +Fixes: 2c54b423cf85 ("arm64/xor: use EOR3 instructions when available") +Signed-off-by: Christoph Hellwig +Reviewed-by: Eric Biggers +Tested-by: Eric Biggers +Cc: Albert Ou +Cc: Alexander Gordeev +Cc: Alexandre Ghiti +Cc: Andreas Larsson +Cc: Anton Ivanov +Cc: Ard Biesheuvel +Cc: Arnd Bergmann +Cc: "Borislav Petkov (AMD)" +Cc: Catalin Marinas +Cc: Chris Mason +Cc: Christian Borntraeger +Cc: Dan Williams +Cc: David S. Miller +Cc: David Sterba +Cc: Heiko Carstens +Cc: Herbert Xu +Cc: "H. Peter Anvin" +Cc: Huacai Chen +Cc: Ingo Molnar +Cc: Jason A. Donenfeld +Cc: Johannes Berg +Cc: Li Nan +Cc: Madhavan Srinivasan +Cc: Magnus Lindholm +Cc: Matt Turner +Cc: Michael Ellerman +Cc: Nicholas Piggin +Cc: Palmer Dabbelt +Cc: Richard Henderson +Cc: Richard Weinberger +Cc: Russell King +Cc: Song Liu +Cc: Sven Schnelle +Cc: Ted Ts'o +Cc: Vasily Gorbik +Cc: WANG Xuerui +Cc: Will Deacon +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/xor.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/include/asm/xor.h b/arch/arm64/include/asm/xor.h +index c38e3d017a79e..bb7428d4ebc65 100644 +--- a/arch/arm64/include/asm/xor.h ++++ b/arch/arm64/include/asm/xor.h +@@ -13,7 +13,7 @@ + + #ifdef CONFIG_KERNEL_MODE_NEON + +-extern struct xor_block_template const xor_block_inner_neon; ++extern struct xor_block_template xor_block_inner_neon __ro_after_init; + + static void + xor_neon_2(unsigned long bytes, unsigned long * __restrict p1, +-- +2.53.0 + diff --git a/queue-7.0/arm_mpam-ensure-in_reset_state-is-false-after-applyi.patch b/queue-7.0/arm_mpam-ensure-in_reset_state-is-false-after-applyi.patch new file mode 100644 index 0000000000..a48d628d5e --- /dev/null +++ b/queue-7.0/arm_mpam-ensure-in_reset_state-is-false-after-applyi.patch @@ -0,0 +1,58 @@ +From 682eb0cf809fd8229ae1dc1fe79ac91c262ae165 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:45:38 +0000 +Subject: arm_mpam: Ensure in_reset_state is false after applying configuration + +From: Zeng Heng + +[ Upstream commit f91e913355f49c878fc77f995fd71b7800352bd2 ] + +The per-RIS flag, in_reset_state, indicates whether or not the MSC +registers are in reset state, and allows avoiding resetting when they are +already in reset state. However, when mpam_apply_config() updates the +configuration it doesn't update the in_reset_state flag and so even after +the configuration update in_reset_state can be true and mpam_reset_ris() +will skip the actual register restoration on subsequent resets. + +Once resctrl has a MPAM backend it will use resctrl_arch_reset_all_ctrls() +to reset the MSC configuration on unmount and, if the in_reset_state flag +is bogusly true, fail to reset the MSC configuration. The resulting +non-reset MSC configuration can lead to persistent performance restrictions +even after resctrl is unmounted. + +Fix by clearing in_reset_state to false immediately after successful +configuration application, ensuring that the next reset operation +properly restores MSC register defaults. + +Fixes: 09b89d2a72f3 ("arm_mpam: Allow configuration to be applied and restored during cpu online") +Signed-off-by: Zeng Heng +Acked-by: Ben Horgan +[Horgan: rewrite commit message to not be specific to resctrl unmount] +Signed-off-by: Ben Horgan +Reviewed-by: Gavin Shan +Reviewed-by: Jonathan Cameron +Reviewed-by: James Morse +Tested-by: Gavin Shan +Tested-by: Shaopeng Tan +Tested-by: Jesse Chick +Signed-off-by: James Morse +Signed-off-by: Sasha Levin +--- + drivers/resctrl/mpam_devices.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c +index 0666be6b0e88d..3c7e69de753ef 100644 +--- a/drivers/resctrl/mpam_devices.c ++++ b/drivers/resctrl/mpam_devices.c +@@ -2694,6 +2694,7 @@ int mpam_apply_config(struct mpam_component *comp, u16 partid, + srcu_read_lock_held(&mpam_srcu)) { + arg.ris = ris; + mpam_touch_msc(msc, __write_config, &arg); ++ ris->in_reset_state = false; + } + mutex_unlock(&msc->cfg_lock); + } +-- +2.53.0 + diff --git a/queue-7.0/arm_mpam-reset-when-feature-configuration-bit-unset.patch b/queue-7.0/arm_mpam-reset-when-feature-configuration-bit-unset.patch new file mode 100644 index 0000000000..221a7d324c --- /dev/null +++ b/queue-7.0/arm_mpam-reset-when-feature-configuration-bit-unset.patch @@ -0,0 +1,137 @@ +From 08e58ba71f20fc67405e18a69244376593709fee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:45:39 +0000 +Subject: arm_mpam: Reset when feature configuration bit unset + +From: Ben Horgan + +[ Upstream commit a1cb6577f575ba5ec2583caf4f791a86754dbf69 ] + +To indicate that the configuration, of the controls used by resctrl, in a +RIS need resetting to driver defaults the reset flags in mpam_config are +set. However, these flags are only ever set temporarily at RIS scope in +mpam_reset_ris() and hence mpam_cpu_online() will never reset these +controls to default. As the hardware reset is unknown this leads to unknown +configuration when the control values haven't been configured away from the +defaults. + +Use the policy that an unset feature configuration bit means reset. In this +way the mpam_config in the component can encode that it should be in reset +state and mpam_reprogram_msc() will reset controls as needed. + +Fixes: 09b89d2a72f3 ("arm_mpam: Allow configuration to be applied and restored during cpu online") +Signed-off-by: Ben Horgan +Reviewed-by: Gavin Shan +Reviewed-by: James Morse +Tested-by: Gavin Shan +Tested-by: Shaopeng Tan +Tested-by: Jesse Chick +[ morse: Removed unused reset flags from config structure ] +Signed-off-by: James Morse +Signed-off-by: Sasha Levin +--- + drivers/resctrl/mpam_devices.c | 40 ++++++++++----------------------- + drivers/resctrl/mpam_internal.h | 4 ---- + 2 files changed, 12 insertions(+), 32 deletions(-) + +diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c +index 3c7e69de753ef..740d99dc847eb 100644 +--- a/drivers/resctrl/mpam_devices.c ++++ b/drivers/resctrl/mpam_devices.c +@@ -1364,17 +1364,15 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, + __mpam_intpart_sel(ris->ris_idx, partid, msc); + } + +- if (mpam_has_feature(mpam_feat_cpor_part, rprops) && +- mpam_has_feature(mpam_feat_cpor_part, cfg)) { +- if (cfg->reset_cpbm) +- mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, rprops->cpbm_wd); +- else ++ if (mpam_has_feature(mpam_feat_cpor_part, rprops)) { ++ if (mpam_has_feature(mpam_feat_cpor_part, cfg)) + mpam_write_partsel_reg(msc, CPBM, cfg->cpbm); ++ else ++ mpam_reset_msc_bitmap(msc, MPAMCFG_CPBM, rprops->cpbm_wd); + } + +- if (mpam_has_feature(mpam_feat_mbw_part, rprops) && +- mpam_has_feature(mpam_feat_mbw_part, cfg)) { +- if (cfg->reset_mbw_pbm) ++ if (mpam_has_feature(mpam_feat_mbw_part, rprops)) { ++ if (mpam_has_feature(mpam_feat_mbw_part, cfg)) + mpam_reset_msc_bitmap(msc, MPAMCFG_MBW_PBM, rprops->mbw_pbm_bits); + else + mpam_write_partsel_reg(msc, MBW_PBM, cfg->mbw_pbm); +@@ -1384,16 +1382,14 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, + mpam_has_feature(mpam_feat_mbw_min, cfg)) + mpam_write_partsel_reg(msc, MBW_MIN, 0); + +- if (mpam_has_feature(mpam_feat_mbw_max, rprops) && +- mpam_has_feature(mpam_feat_mbw_max, cfg)) { +- if (cfg->reset_mbw_max) +- mpam_write_partsel_reg(msc, MBW_MAX, MPAMCFG_MBW_MAX_MAX); +- else ++ if (mpam_has_feature(mpam_feat_mbw_max, rprops)) { ++ if (mpam_has_feature(mpam_feat_mbw_max, cfg)) + mpam_write_partsel_reg(msc, MBW_MAX, cfg->mbw_max); ++ else ++ mpam_write_partsel_reg(msc, MBW_MAX, MPAMCFG_MBW_MAX_MAX); + } + +- if (mpam_has_feature(mpam_feat_mbw_prop, rprops) && +- mpam_has_feature(mpam_feat_mbw_prop, cfg)) ++ if (mpam_has_feature(mpam_feat_mbw_prop, rprops)) + mpam_write_partsel_reg(msc, MBW_PROP, 0); + + if (mpam_has_feature(mpam_feat_cmax_cmax, rprops)) +@@ -1493,16 +1489,6 @@ static int mpam_save_mbwu_state(void *arg) + return 0; + } + +-static void mpam_init_reset_cfg(struct mpam_config *reset_cfg) +-{ +- *reset_cfg = (struct mpam_config) { +- .reset_cpbm = true, +- .reset_mbw_pbm = true, +- .reset_mbw_max = true, +- }; +- bitmap_fill(reset_cfg->features, MPAM_FEATURE_LAST); +-} +- + /* + * Called via smp_call_on_cpu() to prevent migration, while still being + * pre-emptible. Caller must hold mpam_srcu. +@@ -1510,14 +1496,12 @@ static void mpam_init_reset_cfg(struct mpam_config *reset_cfg) + static int mpam_reset_ris(void *arg) + { + u16 partid, partid_max; +- struct mpam_config reset_cfg; ++ struct mpam_config reset_cfg = {}; + struct mpam_msc_ris *ris = arg; + + if (ris->in_reset_state) + return 0; + +- mpam_init_reset_cfg(&reset_cfg); +- + spin_lock(&partid_max_lock); + partid_max = mpam_partid_max; + spin_unlock(&partid_max_lock); +diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h +index e8971842b124f..7af762c98efc4 100644 +--- a/drivers/resctrl/mpam_internal.h ++++ b/drivers/resctrl/mpam_internal.h +@@ -266,10 +266,6 @@ struct mpam_config { + u32 mbw_pbm; + u16 mbw_max; + +- bool reset_cpbm; +- bool reset_mbw_pbm; +- bool reset_mbw_max; +- + struct mpam_garbage garbage; + }; + +-- +2.53.0 + diff --git a/queue-7.0/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch b/queue-7.0/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch new file mode 100644 index 0000000000..925104044c --- /dev/null +++ b/queue-7.0/asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch @@ -0,0 +1,177 @@ +From 8f169ce8a207833e3162cb1016bf5d5e1fa70c97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 15:30:58 -0300 +Subject: ASoC: amd: acp: Add DMI quirk for Valve Steam Deck OLED + +From: Guilherme G. Piccoli + +[ Upstream commit b0f6f4ac7d5d04fe2adcdd63ed1cd1ad505b8958 ] + +Commit 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") +introduced a change that "broke" Steam Deck's audio probe, in the OLED +model, as observed in the following dmesg snippet: + +[...] +snd_sof_amd_vangogh 0000:04:00.5: Topology: ABI 3:26:0 Kernel ABI 3:23:1 +sof_mach nau8821-max: ASoC: physical link acp-bt-codec (id 2) not exist +sof_mach nau8821-max: ASoC: topology: could not load header: -22 +snd_sof_amd_vangogh 0000:04:00.5: tplg amd/sof-tplg/sof-vangogh-nau8821-max.tplg component load failed -22 +snd_sof_amd_vangogh 0000:04:00.5: error: failed to load DSP topology -22 +snd_sof_amd_vangogh 0000:04:00.5: ASoC error (-22): at snd_soc_component_probe() on 0000:04:00.5 +sof_mach nau8821-max: ASoC: failed to instantiate card -22 +sof_mach nau8821-max: error -EINVAL: Failed to register card(sof-nau8821-max) +sof_mach nau8821-max: probe with driver sof_mach failed with error -22 +[...] + +Notice the quotes in "broke": it's not really a bug in such commit, +but instead a problem with a topology file from Steam Deck OLED. This +was discussed to great extent in [1], and Cristian proposed a pretty +simple and functional change that resolved the issue for the Deck's +issue. That change, though, would break other devices, so it wasn't +accepted upstream. And the proper suggested solution (fix the topology) +was never implemented, so Valve's kernel (and anyone that wants to boot +the mainline on Steam Deck OLED) is carrying that fix downstream. + +So, we propose hereby a different approach: a DMI quirk, as many already +present in the sound drivers, to address this issue solely on Steam Deck +OLED, not breaking other devices and as a bonus, allowing simple patch +up in case eventually the topology file gets fixed (we'd just need to +check against any DMI info reflecting that or the topology/FW versions). + +The motivation of such upstream quirk is related to users that want +to test latest kernel trees on their devices and get no only non-working +sound device, but seems some games (like Ori and the Blind Forest) +can't properly work without a proper functional audio device. +Example of such report can be seen at [2]. + +Cc: Mark Brown +Cc: Robert Beckett +Cc: Umang Jain +Fixes: 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") +Link: https://lore.kernel.org/r/20231209205351.880797-11-cristian.ciocaltea@collabora.com/ [1] +Link: https://bugzilla.kernel.org/show_bug.cgi?id=218677 [2] +Reviewed-by: Cristian Ciocaltea +Reviewed-by: Mario Limonciello +Tested-by: Melissa Wen +Signed-off-by: Guilherme G. Piccoli +Link: https://patch.msgid.link/20260423183505.116445-1-gpiccoli@igalia.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/acp/acp-legacy-mach.c | 2 +- + sound/soc/amd/acp/acp-mach-common.c | 22 +++++++++++++++++++--- + sound/soc/amd/acp/acp-mach.h | 4 ++++ + sound/soc/amd/acp/acp-sof-mach.c | 2 +- + 4 files changed, 25 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c +index a7a551366a409..235d6cc83fa98 100644 +--- a/sound/soc/amd/acp/acp-legacy-mach.c ++++ b/sound/soc/amd/acp/acp-legacy-mach.c +@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev) + acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; + + dmi_id = dmi_first_match(acp_quirk_table); +- if (dmi_id && dmi_id->driver_data) ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE) + acp_card_drvdata->tdm_mode = dmi_id->driver_data; + + ret = acp_legacy_dai_links_create(card); +diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c +index 09f6c9a2c0410..ef784cca13f2b 100644 +--- a/sound/soc/amd/acp/acp-mach-common.c ++++ b/sound/soc/amd/acp/acp-mach-common.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "../../codecs/rt5682.h" + #include "../../codecs/rt1019.h" +@@ -37,15 +38,21 @@ + #define NAU8821_FREQ_OUT 12288000 + #define MAX98388_CODEC_DAI "max98388-aif1" + +-#define TDM_MODE_ENABLE 1 +- + const struct dmi_system_id acp_quirk_table[] = { + { + /* Google skyrim proto-0 */ + .matches = { + DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "Google_Skyrim"), + }, +- .driver_data = (void *)TDM_MODE_ENABLE, ++ .driver_data = (void *)QUIRK_TDM_MODE_ENABLE, ++ }, ++ { ++ /* Valve Steam Deck OLED */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Valve"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), ++ }, ++ .driver_data = (void *)QUIRK_REMAP_DMIC_BT, + }, + {} + }; +@@ -1401,6 +1408,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + struct snd_soc_dai_link *links; + struct device *dev = card->dev; + struct acp_card_drvdata *drv_data = card->drvdata; ++ const struct dmi_system_id *dmi_id = dmi_first_match(acp_quirk_table); + int i = 0, num_links = 0; + + if (drv_data->hs_cpu_id) +@@ -1572,6 +1580,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + links[i].codecs = &snd_soc_dummy_dlc; + links[i].num_codecs = 1; + } ++ ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) ++ links[i].id = DMIC_BE_ID; + i++; + } + +@@ -1587,6 +1598,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) + links[i].capture_only = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; ++ ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT) { ++ links[i].id = BT_BE_ID; ++ dev_dbg(dev, "quirk REMAP_DMIC_BT enabled\n"); ++ } + } + + card->dai_link = links; +diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h +index f94c30c20f20b..7177d3fd96192 100644 +--- a/sound/soc/amd/acp/acp-mach.h ++++ b/sound/soc/amd/acp/acp-mach.h +@@ -26,6 +26,10 @@ + + #define acp_get_drvdata(card) ((struct acp_card_drvdata *)(card)->drvdata) + ++/* List of DMI quirks - check acp-mach-common.c for usage. */ ++#define QUIRK_TDM_MODE_ENABLE 1 ++#define QUIRK_REMAP_DMIC_BT 2 ++ + enum be_id { + HEADSET_BE_ID = 0, + AMP_BE_ID, +diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c +index 6215e31eceddf..36ecef7013b9c 100644 +--- a/sound/soc/amd/acp/acp-sof-mach.c ++++ b/sound/soc/amd/acp/acp-sof-mach.c +@@ -110,7 +110,7 @@ static int acp_sof_probe(struct platform_device *pdev) + + acp_card_drvdata = card->drvdata; + dmi_id = dmi_first_match(acp_quirk_table); +- if (dmi_id && dmi_id->driver_data) ++ if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE) + acp_card_drvdata->tdm_mode = dmi_id->driver_data; + + acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; +-- +2.53.0 + diff --git a/queue-7.0/asoc-amd-acp-update-dmic_num-logic-for-acp-pdm-dmic.patch b/queue-7.0/asoc-amd-acp-update-dmic_num-logic-for-acp-pdm-dmic.patch new file mode 100644 index 0000000000..daf89ff252 --- /dev/null +++ b/queue-7.0/asoc-amd-acp-update-dmic_num-logic-for-acp-pdm-dmic.patch @@ -0,0 +1,46 @@ +From 41ca5b3fe064bcf69e55e4a5e049e66efa2f28f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 12:50:27 +0530 +Subject: ASoC: amd: acp: update dmic_num logic for acp pdm dmic + +From: Vijendar Mukunda + +[ Upstream commit 5902e1f3c501375797dcd7ca21b58e2c9abbe317 ] + +Currently there is no mechanism to read dmic_num in mach_params +structure. In this scenario mach_params->dmic_num check always +returns 0 which fails to add component string for dmic. +Update the condition check with acp pdm dmic quirk check and +pass the dmic_num as 1. + +Fixes: 2981d9b0789c ("ASoC: amd: acp: add soundwire machine driver for legacy stack") + +Signed-off-by: Vijendar Mukunda +Link: https://patch.msgid.link/20260330072431.3512358-2-Vijendar.Mukunda@amd.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/acp/acp-sdw-legacy-mach.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c +index cd7b1acc7216d..a9c8d9545281e 100644 +--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c ++++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c +@@ -551,11 +551,11 @@ static int mc_probe(struct platform_device *pdev) + " cfg-amp:%d", amp_num); + if (!card->components) + return -ENOMEM; +- if (mach->mach_params.dmic_num) { ++ if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) { + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:dmic cfg-mics:%d", + card->components, +- mach->mach_params.dmic_num); ++ 1); + if (!card->components) + return -ENOMEM; + } +-- +2.53.0 + diff --git a/queue-7.0/asoc-amd-name-back-to-pcm_new-pcm_free.patch b/queue-7.0/asoc-amd-name-back-to-pcm_new-pcm_free.patch new file mode 100644 index 0000000000..5b86413608 --- /dev/null +++ b/queue-7.0/asoc-amd-name-back-to-pcm_new-pcm_free.patch @@ -0,0 +1,142 @@ +From 0f4b07188020317e88bc2c499dca56e871f9c898 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 02:24:51 +0000 +Subject: ASoC: amd: name back to pcm_new()/pcm_free() + +From: Kuninori Morimoto + +[ Upstream commit fe33a69681e343999e18893f97bb6cd99b883992 ] + +We have been used pcm_new()/pcm_free(), but switched to +pcm_construct()/pcm_destruct() to use extra parameters [1]. + +pcm_new()/free() had been removed [2], but each drivers are still +using such function naming. Let's name back to pcm_new()/pcm_free() +again. + +[1] commit c64bfc906600 ("ASoC: soc-core: add new pcm_construct/pcm_destruct") +[2] commit e9067bb50278 ("ASoC: soc-component: remove snd_pcm_ops fromcomponent driver") + +Signed-off-by: Kuninori Morimoto +Link: https://patch.msgid.link/878qbslddx.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +Stable-dep-of: 3666dc0c47c3 ("ASoC: amd: ps: fix the pcm device numbering for acp pdm dmic") +Signed-off-by: Sasha Levin +--- + sound/soc/amd/acp-pcm-dma.c | 2 +- + sound/soc/amd/acp/acp-platform.c | 2 +- + sound/soc/amd/ps/ps-pdm-dma.c | 2 +- + sound/soc/amd/ps/ps-sdw-dma.c | 2 +- + sound/soc/amd/raven/acp3x-pcm-dma.c | 2 +- + sound/soc/amd/renoir/acp3x-pdm-dma.c | 2 +- + sound/soc/amd/vangogh/acp5x-pcm-dma.c | 2 +- + sound/soc/amd/yc/acp6x-pdm-dma.c | 2 +- + 8 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c +index c76a4bcc96459..6ad70aa0ea837 100644 +--- a/sound/soc/amd/acp-pcm-dma.c ++++ b/sound/soc/amd/acp-pcm-dma.c +@@ -1252,7 +1252,7 @@ static const struct snd_soc_component_driver acp_asoc_platform = { + .pointer = acp_dma_pointer, + .delay = acp_dma_delay, + .prepare = acp_dma_prepare, +- .pcm_construct = acp_dma_new, ++ .pcm_new = acp_dma_new, + }; + + static int acp_audio_probe(struct platform_device *pdev) +diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c +index 88613569fd64f..6b1e18b31c1c6 100644 +--- a/sound/soc/amd/acp/acp-platform.c ++++ b/sound/soc/amd/acp/acp-platform.c +@@ -321,7 +321,7 @@ static const struct snd_soc_component_driver acp_pcm_component = { + .close = acp_dma_close, + .hw_params = acp_dma_hw_params, + .pointer = acp_dma_pointer, +- .pcm_construct = acp_dma_new, ++ .pcm_new = acp_dma_new, + .legacy_dai_naming = 1, + }; + +diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c +index 7c529fc6ba997..c6cd844d458c8 100644 +--- a/sound/soc/amd/ps/ps-pdm-dma.c ++++ b/sound/soc/amd/ps/ps-pdm-dma.c +@@ -351,7 +351,7 @@ static const struct snd_soc_component_driver acp63_pdm_component = { + .close = acp63_pdm_dma_close, + .hw_params = acp63_pdm_dma_hw_params, + .pointer = acp63_pdm_dma_pointer, +- .pcm_construct = acp63_pdm_dma_new, ++ .pcm_new = acp63_pdm_dma_new, + }; + + static int acp63_pdm_audio_probe(struct platform_device *pdev) +diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c +index 366d7c4bb07e9..f27ebbd213798 100644 +--- a/sound/soc/amd/ps/ps-sdw-dma.c ++++ b/sound/soc/amd/ps/ps-sdw-dma.c +@@ -634,7 +634,7 @@ static const struct snd_soc_component_driver acp63_sdw_component = { + .hw_params = acp63_sdw_dma_hw_params, + .trigger = acp63_sdw_dma_trigger, + .pointer = acp63_sdw_dma_pointer, +- .pcm_construct = acp63_sdw_dma_new, ++ .pcm_new = acp63_sdw_dma_new, + .use_dai_pcm_id = true, + + }; +diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c +index 4529404ebd935..37ea5c572eb94 100644 +--- a/sound/soc/amd/raven/acp3x-pcm-dma.c ++++ b/sound/soc/amd/raven/acp3x-pcm-dma.c +@@ -363,7 +363,7 @@ static const struct snd_soc_component_driver acp3x_i2s_component = { + .close = acp3x_dma_close, + .hw_params = acp3x_dma_hw_params, + .pointer = acp3x_dma_pointer, +- .pcm_construct = acp3x_dma_new, ++ .pcm_new = acp3x_dma_new, + }; + + static int acp3x_audio_probe(struct platform_device *pdev) +diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c +index e832c7c4b96fa..e60e3821703cc 100644 +--- a/sound/soc/amd/renoir/acp3x-pdm-dma.c ++++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c +@@ -376,7 +376,7 @@ static const struct snd_soc_component_driver acp_pdm_component = { + .close = acp_pdm_dma_close, + .hw_params = acp_pdm_dma_hw_params, + .pointer = acp_pdm_dma_pointer, +- .pcm_construct = acp_pdm_dma_new, ++ .pcm_new = acp_pdm_dma_new, + .legacy_dai_naming = 1, + }; + +diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c +index 6ce82cd8859b8..831e30e9b0426 100644 +--- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c ++++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c +@@ -357,7 +357,7 @@ static const struct snd_soc_component_driver acp5x_i2s_component = { + .close = acp5x_dma_close, + .hw_params = acp5x_dma_hw_params, + .pointer = acp5x_dma_pointer, +- .pcm_construct = acp5x_dma_new, ++ .pcm_new = acp5x_dma_new, + }; + + static int acp5x_audio_probe(struct platform_device *pdev) +diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c +index 1c8aad8499164..710db721ffa48 100644 +--- a/sound/soc/amd/yc/acp6x-pdm-dma.c ++++ b/sound/soc/amd/yc/acp6x-pdm-dma.c +@@ -346,7 +346,7 @@ static const struct snd_soc_component_driver acp6x_pdm_component = { + .close = acp6x_pdm_dma_close, + .hw_params = acp6x_pdm_dma_hw_params, + .pointer = acp6x_pdm_dma_pointer, +- .pcm_construct = acp6x_pdm_dma_new, ++ .pcm_new = acp6x_pdm_dma_new, + .legacy_dai_naming = 1, + }; + +-- +2.53.0 + diff --git a/queue-7.0/asoc-amd-ps-fix-the-pcm-device-numbering-for-acp-pdm.patch b/queue-7.0/asoc-amd-ps-fix-the-pcm-device-numbering-for-acp-pdm.patch new file mode 100644 index 0000000000..2d55353ed1 --- /dev/null +++ b/queue-7.0/asoc-amd-ps-fix-the-pcm-device-numbering-for-acp-pdm.patch @@ -0,0 +1,39 @@ +From a60dabd8a9a3ecadc4efc9f4bccc6c1c46e51530 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 15:36:17 +0530 +Subject: ASoC: amd: ps: fix the pcm device numbering for acp pdm dmic + +From: Syed Saba Kareem + +[ Upstream commit 3666dc0c47c399695d01fde7c36e08b14f834fa0 ] + +Fixed PCM device numbering is required for acp pdm dmic pcm device +to have a common UCM changes. +Set the 'use_dai_pcm_id' flag true in acp pdm dma driver for acp 6.3 +platform. This will fix the pcm device numbering based on dai_link->id. + +Fixes: 33cea6bbe488 ("ASoC: amd: add acp6.2 pdm platform driver") +Signed-off-by: Syed Saba Kareem +Fixes: tag. +Link: https://patch.msgid.link/20260403100624.676953-1-syed.sabakareem@amd.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/amd/ps/ps-pdm-dma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c +index c6cd844d458c8..04c014349347e 100644 +--- a/sound/soc/amd/ps/ps-pdm-dma.c ++++ b/sound/soc/amd/ps/ps-pdm-dma.c +@@ -352,6 +352,7 @@ static const struct snd_soc_component_driver acp63_pdm_component = { + .hw_params = acp63_pdm_dma_hw_params, + .pointer = acp63_pdm_dma_pointer, + .pcm_new = acp63_pdm_dma_new, ++ .use_dai_pcm_id = true, + }; + + static int acp63_pdm_audio_probe(struct platform_device *pdev) +-- +2.53.0 + diff --git a/queue-7.0/asoc-codecs-ab8500-fix-casting-of-private-data.patch b/queue-7.0/asoc-codecs-ab8500-fix-casting-of-private-data.patch new file mode 100644 index 0000000000..bb5a597594 --- /dev/null +++ b/queue-7.0/asoc-codecs-ab8500-fix-casting-of-private-data.patch @@ -0,0 +1,56 @@ +From 58c39595f3990a467f24dc2c63abeac9060f2707 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 21:22:49 +0200 +Subject: ASoC: codecs: ab8500: Fix casting of private data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian A. Ehrhardt + +[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ] + +ab8500_filter_controls[i].private_value is initialized using + + .private_value = (unsigned long)&(struct filter_control) + {.count = xcount, .min = xmin, .max = xmax} + +thus it's a pointer to a struct filter_control casted to unsigned long. + +So to get back that pointer .private_data must be cast back, not its +address. + +Fixes: 679d7abdc754 ("ASoC: codecs: Add AB8500 codec-driver") +Signed-off-by: Christian A. Ehrhardt +Signed-off-by: Uwe Kleine-König (The Capable Hub) +Link: https://patch.msgid.link/20260428192255.2294705-2-u.kleine-koenig@baylibre.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/ab8500-codec.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c +index fdda1b747bf7e..8ab2e60f80b4f 100644 +--- a/sound/soc/codecs/ab8500-codec.c ++++ b/sound/soc/codecs/ab8500-codec.c +@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component) + return status; + } + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; + drvdata->anc_fir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; + drvdata->anc_iir_values = (long *)fc->value; + fc = (struct filter_control *) +- &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; ++ ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; + drvdata->sid_fir_values = (long *)fc->value; + + snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); +-- +2.53.0 + diff --git a/queue-7.0/asoc-cs35l56-fix-illegal-writes-to-otp_mem-registers.patch b/queue-7.0/asoc-cs35l56-fix-illegal-writes-to-otp_mem-registers.patch new file mode 100644 index 0000000000..296eb97914 --- /dev/null +++ b/queue-7.0/asoc-cs35l56-fix-illegal-writes-to-otp_mem-registers.patch @@ -0,0 +1,64 @@ +From 3bf255bdeeb73a18b08aae8c0e6e9bba01f81eb3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:52:28 +0100 +Subject: ASoC: cs35l56: Fix illegal writes to OTP_MEM registers + +From: Richard Fitzgerald + +[ Upstream commit be102efb832ef7e30e4cd4c2edf22bbf64ddf35a ] + +Mark the OTP_MEM registers as volatile so that regcache_sync() will not +attempt to write to them. + +These registers hold a constant, and originally they were marked as +readable non-volatile so that this value would be read into the regmap +cache. The problem with this is regcache_sync() issues a write for any +cached register that does not have a reg_default. + +Though these registers are constants and writing them in normal use +cannot change OTP, it is illegal for the host to write to them. + +Fixes: e1830f66f6c6 ("ASoC: cs35l56: Add helper functions for amp calibration") +Signed-off-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260428115228.158252-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/cs35l56-shared.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c +index af87ebae98cb0..0ddf9a8d39a07 100644 +--- a/sound/soc/codecs/cs35l56-shared.c ++++ b/sound/soc/codecs/cs35l56-shared.c +@@ -108,8 +108,6 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) + EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED"); + + static const struct reg_default cs35l56_reg_defaults[] = { +- /* no defaults for OTP_MEM - first read populates cache */ +- + { CS35L56_ASP1_ENABLES1, 0x00000000 }, + { CS35L56_ASP1_CONTROL1, 0x00000028 }, + { CS35L56_ASP1_CONTROL2, 0x18180200 }, +@@ -138,8 +136,6 @@ static const struct reg_default cs35l56_reg_defaults[] = { + }; + + static const struct reg_default cs35l63_reg_defaults[] = { +- /* no defaults for OTP_MEM - first read populates cache */ +- + { CS35L56_ASP1_ENABLES1, 0x00000000 }, + { CS35L56_ASP1_CONTROL1, 0x00000028 }, + { CS35L56_ASP1_CONTROL2, 0x18180200 }, +@@ -282,6 +278,9 @@ static bool cs35l56_common_volatile_reg(unsigned int reg) + case CS35L56_GLOBAL_ENABLES: /* owned by firmware */ + case CS35L56_BLOCK_ENABLES: /* owned by firmware */ + case CS35L56_BLOCK_ENABLES2: /* owned by firmware */ ++ case CS35L56_OTP_MEM_53: ++ case CS35L56_OTP_MEM_54: ++ case CS35L56_OTP_MEM_55: + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: + case CS35L56_UPDATE_REGS: + case CS35L56_REFCLK_INPUT: /* owned by firmware */ +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch b/queue-7.0/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch new file mode 100644 index 0000000000..f2fcf86cc7 --- /dev/null +++ b/queue-7.0/asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch @@ -0,0 +1,189 @@ +From 8be7f1b449862eae347090eae0196ae2f9a31cee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:26 +0800 +Subject: ASoC: fsl_easrc: Change the type for iec958 channel status controls + +From: Shengjiu Wang + +[ Upstream commit 47f28a5bd154a95d5aa563dde02a801bd32ddb81 ] + +Use the type SNDRV_CTL_ELEM_TYPE_IEC958 for iec958 channel status +controls, the original type will cause mixer-test to iterate all 32bit +values, which costs a lot of time. And using IEC958 type can reduce the +control numbers. + +Also enable pm runtime before updating registers to make the regmap cache +data align with the value in hardware. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-12-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 118 +++++++++++++++++++++++++++----------- + 1 file changed, 84 insertions(+), 34 deletions(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 3086cb758beb6..114a6c0b6b730 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -78,17 +78,47 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + return 0; + } + ++static int fsl_easrc_iec958_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ + static int fsl_easrc_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; +- unsigned int regval; ++ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ int ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS0(mc->regbase), ®val[0]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS1(mc->regbase), ®val[1]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS2(mc->regbase), ®val[2]); ++ if (ret) ++ return ret; + +- regval = snd_soc_component_read(component, mc->regbase); ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS3(mc->regbase), ®val[3]); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS4(mc->regbase), ®val[4]); ++ if (ret) ++ return ret; + +- ucontrol->value.integer.value[0] = regval; ++ ret = regmap_read(easrc->regmap, REG_EASRC_CS5(mc->regbase), ®val[5]); ++ if (ret) ++ return ret; + + return 0; + } +@@ -100,22 +130,62 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component); +- unsigned int regval = ucontrol->value.integer.value[0]; +- bool changed; ++ unsigned int *regval = (unsigned int *)ucontrol->value.iec958.status; ++ bool changed, changed_all = false; + int ret; + +- ret = regmap_update_bits_check(easrc->regmap, mc->regbase, +- GENMASK(31, 0), regval, &changed); +- if (ret != 0) ++ ret = pm_runtime_resume_and_get(component->dev); ++ if (ret) + return ret; + +- return changed; ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS0(mc->regbase), ++ GENMASK(31, 0), regval[0], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS1(mc->regbase), ++ GENMASK(31, 0), regval[1], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS2(mc->regbase), ++ GENMASK(31, 0), regval[2], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS3(mc->regbase), ++ GENMASK(31, 0), regval[3], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS4(mc->regbase), ++ GENMASK(31, 0), regval[4], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++ ++ ret = regmap_update_bits_check(easrc->regmap, REG_EASRC_CS5(mc->regbase), ++ GENMASK(31, 0), regval[5], &changed); ++ if (ret != 0) ++ goto err; ++ changed_all |= changed; ++err: ++ pm_runtime_put_autosuspend(component->dev); ++ ++ if (ret != 0) ++ return ret; ++ else ++ return changed_all; + } + + #define SOC_SINGLE_REG_RW(xname, xreg) \ + { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ +- .info = snd_soc_info_xr_sx, .get = fsl_easrc_get_reg, \ ++ .info = fsl_easrc_iec958_info, .get = fsl_easrc_get_reg, \ + .put = fsl_easrc_set_reg, \ + .private_value = (unsigned long)&(struct soc_mreg_control) \ + { .regbase = xreg, .regcount = 1, .nbits = 32, \ +@@ -146,30 +216,10 @@ static const struct snd_kcontrol_new fsl_easrc_snd_controls[] = { + SOC_SINGLE_VAL_RW("Context 2 IEC958 Bits Per Sample", 2), + SOC_SINGLE_VAL_RW("Context 3 IEC958 Bits Per Sample", 3), + +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS0", REG_EASRC_CS0(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS0", REG_EASRC_CS0(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS0", REG_EASRC_CS0(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS0", REG_EASRC_CS0(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS1", REG_EASRC_CS1(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS1", REG_EASRC_CS1(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS1", REG_EASRC_CS1(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS1", REG_EASRC_CS1(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS2", REG_EASRC_CS2(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS2", REG_EASRC_CS2(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS2", REG_EASRC_CS2(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS2", REG_EASRC_CS2(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS3", REG_EASRC_CS3(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS3", REG_EASRC_CS3(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS3", REG_EASRC_CS3(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS3", REG_EASRC_CS3(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS4", REG_EASRC_CS4(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS4", REG_EASRC_CS4(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS4", REG_EASRC_CS4(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS4", REG_EASRC_CS4(3)), +- SOC_SINGLE_REG_RW("Context 0 IEC958 CS5", REG_EASRC_CS5(0)), +- SOC_SINGLE_REG_RW("Context 1 IEC958 CS5", REG_EASRC_CS5(1)), +- SOC_SINGLE_REG_RW("Context 2 IEC958 CS5", REG_EASRC_CS5(2)), +- SOC_SINGLE_REG_RW("Context 3 IEC958 CS5", REG_EASRC_CS5(3)), ++ SOC_SINGLE_REG_RW("Context 0 IEC958 CS", 0), ++ SOC_SINGLE_REG_RW("Context 1 IEC958 CS", 1), ++ SOC_SINGLE_REG_RW("Context 2 IEC958 CS", 2), ++ SOC_SINGLE_REG_RW("Context 3 IEC958 CS", 3), + }; + + /* +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch b/queue-7.0/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch new file mode 100644 index 0000000000..3d88c529ff --- /dev/null +++ b/queue-7.0/asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch @@ -0,0 +1,39 @@ +From ff518465efd21f7fd0fb90738eeb3b87e57675d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:24 +0800 +Subject: ASoC: fsl_easrc: Check the variable range in + fsl_easrc_iec958_put_bits() + +From: Shengjiu Wang + +[ Upstream commit 00541b86fb578d4949cfdd6aff1f82d43fcf07af ] + +Add check of input value's range in fsl_easrc_iec958_put_bits(), +otherwise the wrong value may be written from user space. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-10-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index 599e439b359a9..f48e43a0edcfc 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -54,6 +54,9 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol, + unsigned int regval = ucontrol->value.integer.value[0]; + int ret; + ++ if (regval < EASRC_WIDTH_16_BIT || regval > EASRC_WIDTH_24_BIT) ++ return -EINVAL; ++ + ret = (easrc_priv->bps_iec958[mc->regbase] != regval); + + easrc_priv->bps_iec958[mc->regbase] = regval; +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch b/queue-7.0/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch new file mode 100644 index 0000000000..79b8ba8a72 --- /dev/null +++ b/queue-7.0/asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch @@ -0,0 +1,37 @@ +From 178c7ca80987574fdd89533caa8dedf894339802 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:25 +0800 +Subject: ASoC: fsl_easrc: Fix value type in fsl_easrc_iec958_get_bits() + +From: Shengjiu Wang + +[ Upstream commit aa21fe4a81458cf469c2615b08cbde5997dde25a ] + +The value type of controls "Context 0 IEC958 Bits Per Sample" should be +integer, not enumerated, the issue is found by the mixer-test. + +Fixes: 955ac624058f ("ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-11-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_easrc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c +index f48e43a0edcfc..3086cb758beb6 100644 +--- a/sound/soc/fsl/fsl_easrc.c ++++ b/sound/soc/fsl/fsl_easrc.c +@@ -73,7 +73,7 @@ static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol, + struct soc_mreg_control *mc = + (struct soc_mreg_control *)kcontrol->private_value; + +- ucontrol->value.enumerated.item[0] = easrc_priv->bps_iec958[mc->regbase]; ++ ucontrol->value.integer.value[0] = easrc_priv->bps_iec958[mc->regbase]; + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_micfil-add-access-property-for-vad-detected.patch b/queue-7.0/asoc-fsl_micfil-add-access-property-for-vad-detected.patch new file mode 100644 index 0000000000..2027604d69 --- /dev/null +++ b/queue-7.0/asoc-fsl_micfil-add-access-property-for-vad-detected.patch @@ -0,0 +1,44 @@ +From 07ce3d5192a301447a111cdbf8ec0b853330bb1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:16 +0800 +Subject: ASoC: fsl_micfil: Add access property for "VAD Detected" + +From: Shengjiu Wang + +[ Upstream commit c7661bfc7422443df394c01e069ae4e5c3a7f04c ] + +Add access property SNDRV_CTL_ELEM_ACCESS_READ for control "VAD +Detected", which doesn't support put operation, otherwise there will be +issue with mixer-test. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-2-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index d6cde2757c6d5..79850211742cb 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -503,7 +503,13 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { + SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0), + SOC_SINGLE("HWVAD ZCD And Behavior Switch", + REG_MICFIL_VAD0_ZCD, 4, 1, 0), +- SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .name = "VAD Detected", ++ .info = snd_soc_info_bool_ext, ++ .get = hwvad_detected, ++ }, + }; + + static int fsl_micfil_use_verid(struct device *dev) +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch new file mode 100644 index 0000000000..1ea9429482 --- /dev/null +++ b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch @@ -0,0 +1,49 @@ +From 80a252c8fb0f76b123e1ff1a763ccd43e200cee7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:17 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in hwvad_put_enable() + +From: Shengjiu Wang + +[ Upstream commit 59b9061824f2179fe133e2636203548eaba3e528 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation hwvad_put_enable() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the vad_enabled +variable. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-3-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 79850211742cb..97f24c9bdd68b 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -377,10 +377,15 @@ static int hwvad_put_enable(struct snd_kcontrol *kcontrol, + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); ++ bool change = false; + ++ if (val < 0 || val > 1) ++ return -EINVAL; ++ ++ change = (micfil->vad_enabled != val); + micfil->vad_enabled = val; + +- return 0; ++ return change; + } + + static int hwvad_get_enable(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch new file mode 100644 index 0000000000..1440c58cdf --- /dev/null +++ b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch @@ -0,0 +1,52 @@ +From 922ebf22fe6132c46f253eb6fd6e361e47da2076 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:18 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in hwvad_put_init_mode() + +From: Shengjiu Wang + +[ Upstream commit 7e226209906906421f0d952d7304e48fdb0adabc ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation hwvad_put_init_mode() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the vad_init_mode +variable. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-4-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 97f24c9bdd68b..1c826e0cb1d5e 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -407,13 +407,18 @@ static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol, + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); ++ bool change = false; ++ ++ if (val < MICFIL_HWVAD_ENVELOPE_MODE || val > MICFIL_HWVAD_ENERGY_MODE) ++ return -EINVAL; + + /* 0 - Envelope-based Mode + * 1 - Energy-based Mode + */ ++ change = (micfil->vad_init_mode != val); + micfil->vad_init_mode = val; + +- return 0; ++ return change; + } + + static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch new file mode 100644 index 0000000000..5a4edc8b84 --- /dev/null +++ b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch @@ -0,0 +1,62 @@ +From b7de1c1a2a789468a68811c5895dd77158445d57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:20 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in + micfil_put_dc_remover_state() + +From: Shengjiu Wang + +[ Upstream commit 7d2bd35100de370dc326b250e8f6b66bee06a2f3 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_put_dc_remover_state() only returns 0 or a +negative error code, causing ALSA to not generate any change events. + +return the value of snd_soc_component_update_bits() directly, as it has +the capability of return check status of changed or not. + +Also enable pm runtime before calling the function +snd_soc_component_update_bits() to make the regmap cache data align with +the value in hardware. + +Fixes: 29dbfeecab85 ("ASoC: fsl_micfil: Add Hardware Voice Activity Detector support") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-6-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 0cfdd6343291a..983805bbaae27 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -351,6 +351,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + if (val < 0 || val > 3) + return -EINVAL; + ++ ret = pm_runtime_resume_and_get(comp->dev); ++ if (ret) ++ return ret; ++ + micfil->dc_remover = val; + + /* Calculate total value for all channels */ +@@ -360,10 +364,10 @@ static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + /* Update DC Remover mode for all channels */ + ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL, + MICFIL_DC_CTRL_CONFIG, reg_val); +- if (ret < 0) +- return ret; + +- return 0; ++ pm_runtime_put_autosuspend(comp->dev); ++ ++ return ret; + } + + static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch new file mode 100644 index 0000000000..6b3772ffbb --- /dev/null +++ b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch @@ -0,0 +1,71 @@ +From fe0e832571b7d183aa4071a7e788a6a29038adee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:21 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in micfil_quality_set() + +From: Shengjiu Wang + +[ Upstream commit e5785093b1b45af7ee57d18619b2854a8aed073a ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_quality_set() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the quality variable. + +Also enable pm runtime before calling the function micfil_set_quality() +to make the regmap cache data align with the value in hardware. + +Fixes: bea1d61d5892 ("ASoC: fsl_micfil: rework quality setting") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-7-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 983805bbaae27..2e887f1f1f361 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -289,10 +289,34 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol, + { + struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); ++ int val = ucontrol->value.integer.value[0]; ++ bool change = false; ++ int old_val; ++ int ret; ++ ++ if (val < QUALITY_HIGH || val > QUALITY_VLOW2) ++ return -EINVAL; ++ ++ if (micfil->quality != val) { ++ ret = pm_runtime_resume_and_get(cmpnt->dev); ++ if (ret) ++ return ret; ++ ++ old_val = micfil->quality; ++ micfil->quality = val; ++ ret = micfil_set_quality(micfil); + +- micfil->quality = ucontrol->value.integer.value[0]; ++ pm_runtime_put_autosuspend(cmpnt->dev); + +- return micfil_set_quality(micfil); ++ if (ret) { ++ micfil->quality = old_val; ++ return ret; ++ } ++ ++ change = true; ++ } ++ ++ return change; + } + + static const char * const micfil_hwvad_enable[] = { +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_range.patch b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_range.patch new file mode 100644 index 0000000000..b3876c4c6b --- /dev/null +++ b/queue-7.0/asoc-fsl_micfil-fix-event-generation-in-micfil_range.patch @@ -0,0 +1,63 @@ +From 7294c9efef0b40988290c6b4a3d220ca339c97e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:19 +0800 +Subject: ASoC: fsl_micfil: Fix event generation in micfil_range_set() + +From: Shengjiu Wang + +[ Upstream commit fc4daaddb276d370b7da3819872044df446a1911 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation micfil_range_set() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Use snd_soc_component_update_bits() function to replace the +regmap_update_bits(), for snd_soc_component_update_bits() has the +capability of return check status. + +Also enable pm runtime before calling the function +snd_soc_component_update_bits() to make the regmap cache data align with +the value in hardware. + +Fixes: ef1a7e02fdb7 ("ASoC: fsl_micfil: Set channel range control") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-5-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_micfil.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c +index 1c826e0cb1d5e..0cfdd6343291a 100644 +--- a/sound/soc/fsl/fsl_micfil.c ++++ b/sound/soc/fsl/fsl_micfil.c +@@ -210,15 +210,23 @@ static int micfil_range_set(struct snd_kcontrol *kcontrol, + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int shift = mc->shift; + int max_range, new_range; ++ int ret; + + new_range = ucontrol->value.integer.value[0]; + max_range = micfil_get_max_range(micfil); + if (new_range > max_range) + dev_warn(&micfil->pdev->dev, "range makes channel %d data unreliable\n", shift / 4); + +- regmap_update_bits(micfil->regmap, REG_MICFIL_OUT_CTRL, 0xF << shift, new_range << shift); ++ ret = pm_runtime_resume_and_get(cmpnt->dev); ++ if (ret) ++ return ret; + +- return 0; ++ ret = snd_soc_component_update_bits(cmpnt, REG_MICFIL_OUT_CTRL, 0xF << shift, ++ new_range << shift); ++ ++ pm_runtime_put_autosuspend(cmpnt->dev); ++ ++ return ret; + } + + static int micfil_set_quality(struct fsl_micfil *micfil) +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch b/queue-7.0/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch new file mode 100644 index 0000000000..7a74f880f1 --- /dev/null +++ b/queue-7.0/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch @@ -0,0 +1,52 @@ +From e7249a1b7c4397c73ce1effb3214baa7d4ee949d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:22 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_arc_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 1b61c8103c9317a9c37fe544c2d83cee1c281149 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_arc_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the arc_mode +variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-8-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index a268fb81a2f86..008e45009c83f 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -115,10 +115,17 @@ static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); ++ int ret; + +- xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]); ++ if (val < 0 || val > 1) ++ return -EINVAL; + +- return 0; ++ ret = (xcvr->arc_mode != val); ++ ++ xcvr->arc_mode = val; ++ ++ return ret; + } + + static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-7.0/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch b/queue-7.0/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch new file mode 100644 index 0000000000..9b123d9254 --- /dev/null +++ b/queue-7.0/asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch @@ -0,0 +1,59 @@ +From 75c718a4e6e8bab1a7743c40952a4977f6525d73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 17:42:23 +0800 +Subject: ASoC: fsl_xcvr: Fix event generation in fsl_xcvr_mode_put() + +From: Shengjiu Wang + +[ Upstream commit 64a496ba976324615b845d60739dfcdae3d57434 ] + +ALSA controls should return 1 if the value in the control changed but the +control put operation fsl_xcvr_mode_put() only returns 0 or a negative +error code, causing ALSA to not generate any change events. + +Add a suitable check in the function before updating the mode variable. + +Fixes: 28564486866f ("ASoC: fsl_xcvr: Add XCVR ASoC CPU DAI driver") +Signed-off-by: Shengjiu Wang +Link: https://patch.msgid.link/20260401094226.2900532-9-shengjiu.wang@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/fsl/fsl_xcvr.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c +index 008e45009c83f..d7a823384c08a 100644 +--- a/sound/soc/fsl/fsl_xcvr.c ++++ b/sound/soc/fsl/fsl_xcvr.c +@@ -225,10 +225,17 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; ++ int val = snd_soc_enum_item_to_val(e, item[0]); + struct snd_soc_card *card = dai->component->card; + struct snd_soc_pcm_runtime *rtd; ++ int ret; ++ ++ if (val < FSL_XCVR_MODE_SPDIF || val > FSL_XCVR_MODE_EARC) ++ return -EINVAL; + +- xcvr->mode = snd_soc_enum_item_to_val(e, item[0]); ++ ret = (xcvr->mode != val); ++ ++ xcvr->mode = val; + + fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, + (xcvr->mode == FSL_XCVR_MODE_ARC)); +@@ -238,7 +245,7 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol, + rtd = snd_soc_get_pcm_runtime(card, card->dai_link); + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count = + (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0); +- return 0; ++ return ret; + } + + static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol, +-- +2.53.0 + diff --git a/queue-7.0/asoc-intel-avs-check-maximum-valid-cpuid-leaf.patch b/queue-7.0/asoc-intel-avs-check-maximum-valid-cpuid-leaf.patch new file mode 100644 index 0000000000..9db814061b --- /dev/null +++ b/queue-7.0/asoc-intel-avs-check-maximum-valid-cpuid-leaf.patch @@ -0,0 +1,62 @@ +From 46a5f1df4301729653e860a111c2e1424e2386cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 03:15:15 +0100 +Subject: ASoC: Intel: avs: Check maximum valid CPUID leaf + +From: Ahmed S. Darwish + +[ Upstream commit 93a1f0e61329f538cfc7122d7fa0e7a1803e326d ] + +The Intel AVS driver queries CPUID(0x15) before checking if the CPUID leaf +is available. Check the maximum-valid CPU standard leaf beforehand. + +Use the CPUID_LEAF_TSC macro instead of the custom local one for the +CPUID(0x15) leaf number. + +Fixes: cbe37a4d2b3c ("ASoC: Intel: avs: Configure basefw on TGL-based platforms") +Signed-off-by: Ahmed S. Darwish +Signed-off-by: Borislav Petkov (AMD) +Acked-by: Cezary Rojewski +Link: https://patch.msgid.link/20260327021645.555257-2-darwi@linutronix.de +Signed-off-by: Sasha Levin +--- + sound/soc/intel/avs/tgl.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c +index afb0665161010..4649d749b41e0 100644 +--- a/sound/soc/intel/avs/tgl.c ++++ b/sound/soc/intel/avs/tgl.c +@@ -11,8 +11,6 @@ + #include "debug.h" + #include "messages.h" + +-#define CPUID_TSC_LEAF 0x15 +- + static int avs_tgl_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) + { + core_mask &= AVS_MAIN_CORE_MASK; +@@ -49,7 +47,11 @@ static int avs_tgl_config_basefw(struct avs_dev *adev) + unsigned int ecx; + + #include +- ecx = cpuid_ecx(CPUID_TSC_LEAF); ++ ++ if (boot_cpu_data.cpuid_level < CPUID_LEAF_TSC) ++ goto no_cpuid; ++ ++ ecx = cpuid_ecx(CPUID_LEAF_TSC); + if (ecx) { + ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx); + if (ret) +@@ -57,6 +59,7 @@ static int avs_tgl_config_basefw(struct avs_dev *adev) + } + #endif + ++no_cpuid: + hwid.device = pci->device; + hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16); + hwid.revision = pci->revision; +-- +2.53.0 + diff --git a/queue-7.0/asoc-intel-avs-include-cpuid-header-at-file-scope.patch b/queue-7.0/asoc-intel-avs-include-cpuid-header-at-file-scope.patch new file mode 100644 index 0000000000..d63ba037bd --- /dev/null +++ b/queue-7.0/asoc-intel-avs-include-cpuid-header-at-file-scope.patch @@ -0,0 +1,116 @@ +From 76f9886d4972fe0761b6b9d8b8b9605094cd1725 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 03:15:16 +0100 +Subject: ASoC: Intel: avs: Include CPUID header at file scope + +From: Ahmed S. Darwish + +[ Upstream commit 7f78e0b46e9984e955cb73ffada8dace8b4dd059 ] + +Commit + + cbe37a4d2b3c ("ASoC: Intel: avs: Configure basefw on TGL-based platforms") + +includes the main CPUID header from within a C function. This works by +luck and forbids valid refactoring inside that header. + +Include the CPUID header at file scope instead. + +Remove the COMPILE_TEST build flag so that the CONFIG_X86 conditionals can +be removed. The driver gets enough compilation testing already on x86. + +For clarity, refactor the CPUID(0x15) code into its own function without +changing any of the driver's logic. + +Fixes: cbe37a4d2b3c ("ASoC: Intel: avs: Configure basefw on TGL-based platforms") +Suggested-by: Borislav Petkov # CONFIG_X86 removal +Signed-off-by: Ahmed S. Darwish +Signed-off-by: Borislav Petkov (AMD) +Acked-by: Cezary Rojewski +Link: https://lore.kernel.org/all/20250612234010.572636-3-darwi@linutronix.de +Signed-off-by: Sasha Levin +--- + sound/soc/intel/Kconfig | 2 +- + sound/soc/intel/avs/tgl.c | 37 ++++++++++++++++++++++++------------- + 2 files changed, 25 insertions(+), 14 deletions(-) + +diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig +index 412555e626b81..63367364916ae 100644 +--- a/sound/soc/intel/Kconfig ++++ b/sound/soc/intel/Kconfig +@@ -95,7 +95,7 @@ config SND_SOC_INTEL_KEEMBAY + + config SND_SOC_INTEL_AVS + tristate "Intel AVS driver" +- depends on X86 || COMPILE_TEST ++ depends on X86 + depends on PCI + depends on COMMON_CLK + select ACPI_NHLT if ACPI +diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c +index 4649d749b41e0..a7123639de431 100644 +--- a/sound/soc/intel/avs/tgl.c ++++ b/sound/soc/intel/avs/tgl.c +@@ -7,6 +7,7 @@ + // + + #include ++#include + #include "avs.h" + #include "debug.h" + #include "messages.h" +@@ -38,28 +39,38 @@ static int avs_tgl_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stal + return avs_dsp_core_stall(adev, core_mask, stall); + } + +-static int avs_tgl_config_basefw(struct avs_dev *adev) ++/* ++ * Succeed if CPUID(0x15) is not available, or if the nominal core crystal clock ++ * frequency cannot be enumerated from it. There is nothing to do in both cases. ++ */ ++static int avs_tgl_set_xtal_freq(struct avs_dev *adev) + { +- struct pci_dev *pci = adev->base.pci; +- struct avs_bus_hwid hwid; ++ unsigned int freq; + int ret; +-#ifdef CONFIG_X86 +- unsigned int ecx; +- +-#include + + if (boot_cpu_data.cpuid_level < CPUID_LEAF_TSC) +- goto no_cpuid; ++ return 0; + +- ecx = cpuid_ecx(CPUID_LEAF_TSC); +- if (ecx) { +- ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx); ++ freq = cpuid_ecx(CPUID_LEAF_TSC); ++ if (freq) { ++ ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(freq), &freq); + if (ret) + return AVS_IPC_RET(ret); + } +-#endif + +-no_cpuid: ++ return 0; ++} ++ ++static int avs_tgl_config_basefw(struct avs_dev *adev) ++{ ++ struct pci_dev *pci = adev->base.pci; ++ struct avs_bus_hwid hwid; ++ int ret; ++ ++ ret = avs_tgl_set_xtal_freq(adev); ++ if (ret) ++ return ret; ++ + hwid.device = pci->device; + hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16); + hwid.revision = pci->revision; +-- +2.53.0 + diff --git a/queue-7.0/asoc-qcom-audioreach-explicitly-enable-speaker-prote.patch b/queue-7.0/asoc-qcom-audioreach-explicitly-enable-speaker-prote.patch new file mode 100644 index 0000000000..c32ea7c177 --- /dev/null +++ b/queue-7.0/asoc-qcom-audioreach-explicitly-enable-speaker-prote.patch @@ -0,0 +1,45 @@ +From d647e03edb3b1b48bcef7ddbb62c2f1a6ae7190b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 17:05:31 +0530 +Subject: ASoC: qcom: audioreach: explicitly enable speaker protection modules + +From: Ravi Hothi + +[ Upstream commit b481eabe5a193ba8499f446c2ab7e0ac042f8776 ] + +Speaker protection and VI feedback modules are disabled by default. +Explicitly enable them when configuring speaker protection. + +Fixes: 3e43a8c033c3 ("ASoC: qcom: audioreach: Add support for VI Sense module") +Fixes: 0db76f5b2235 ("ASoC: qcom: audioreach: Add support for Speaker Protection module") +Signed-off-by: Ravi Hothi +Reviewed-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260326113531.3144998-1-ravi.hothi@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/audioreach.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c +index 241c3b4479c6f..ff8cd55b0d898 100644 +--- a/sound/soc/qcom/qdsp6/audioreach.c ++++ b/sound/soc/qcom/qdsp6/audioreach.c +@@ -1365,9 +1365,14 @@ int audioreach_set_media_format(struct q6apm_graph *graph, + case MODULE_ID_SPEAKER_PROTECTION: + rc = audioreach_speaker_protection(graph, module, + PARAM_ID_SP_OP_MODE_NORMAL); ++ if (!rc) ++ rc = audioreach_module_enable(graph, module, true); ++ + break; + case MODULE_ID_SPEAKER_PROTECTION_VI: + rc = audioreach_speaker_protection_vi(graph, module, cfg); ++ if (!rc) ++ rc = audioreach_module_enable(graph, module, true); + break; + + default: +-- +2.53.0 + diff --git a/queue-7.0/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch b/queue-7.0/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch new file mode 100644 index 0000000000..257e5df782 --- /dev/null +++ b/queue-7.0/asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch @@ -0,0 +1,51 @@ +From be0978822b0bfb314aaa6d9b23105e19b238544a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 08:11:08 +0000 +Subject: ASoC: qcom: qdsp6: topology: check widget type before accessing data + +From: Srinivas Kandagatla + +[ Upstream commit d5bfdd28e0cdd45043ae6e0ac168a451d59283dc ] + +Check widget type before accessing the private data, as this could a +virtual widget which is no associated with a dsp graph, container and +module. Accessing witout check could lead to incorrect memory access. + +Fixes: 36ad9bf1d93d ("ASoC: qdsp6: audioreach: add topology support") +Signed-off-by: Srinivas Kandagatla +Link: https://patch.msgid.link/20260402081118.348071-4-srinivas.kandagatla@oss.qualcomm.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/qcom/qdsp6/topology.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c +index e732fac9b8ca0..1f69fba6de26d 100644 +--- a/sound/soc/qcom/qdsp6/topology.c ++++ b/sound/soc/qcom/qdsp6/topology.c +@@ -952,9 +952,6 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + struct audioreach_container *cont; + struct audioreach_module *mod; + +- mod = dobj->private; +- cont = mod->container; +- + if (w->id == snd_soc_dapm_mixer) { + /* virtual widget */ + struct snd_ar_control *scontrol = dobj->private; +@@ -963,6 +960,11 @@ static int audioreach_widget_unload(struct snd_soc_component *scomp, + kfree(scontrol); + return 0; + } ++ mod = dobj->private; ++ if (!mod) ++ return 0; ++ ++ cont = mod->container; + + mutex_lock(&apm->lock); + idr_remove(&apm->modules_idr, mod->instance_id); +-- +2.53.0 + diff --git a/queue-7.0/asoc-rockchip-rockchip_sai-set-slot-width-for-non-td.patch b/queue-7.0/asoc-rockchip-rockchip_sai-set-slot-width-for-non-td.patch new file mode 100644 index 0000000000..75671727d5 --- /dev/null +++ b/queue-7.0/asoc-rockchip-rockchip_sai-set-slot-width-for-non-td.patch @@ -0,0 +1,52 @@ +From 8a94bb25bf090867640fcd5d1db32bb703d6b072 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:50:25 +0400 +Subject: ASoC: rockchip: rockchip_sai: Set slot width for non-TDM mode + +From: Alexey Charkov + +[ Upstream commit 8a6391ec669366cbe7bde92b468c561e8b309fd6 ] + +Currently the slot width in non-TDM mode is always kept at the POR value +of 32 bits, regardless of the sample width, which doesn't work well for +some codecs such as NAU8822. + +Set the slot width according to the sample width in non-TDM mode, which +is what other CPU DAI drivers do. + +Tested on the following RK3576 configurations: +- SAI2 + NAU8822 (codec as the clock master), custom board +- SAI1 + ES8388 (codec as the clock master), RK3576 EVB1 +- SAI2 + RT5616 (SAI as the clock master), FriendlyElec NanoPi M5 + +NAU8822 didn't work prior to this patch but works after the patch. Other +two configurations work both before and after the patch. + +Fixes: cc78d1eaabad ("ASoC: rockchip: add Serial Audio Interface (SAI) driver") +Signed-off-by: Alexey Charkov +Tested-by: Nicolas Frattaroli +Link: https://patch.msgid.link/20260318-sai-slot-width-v1-1-1f68186f71e3@flipper.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/rockchip/rockchip_sai.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c +index 1bf614dbdf4d0..ed393e5034a49 100644 +--- a/sound/soc/rockchip/rockchip_sai.c ++++ b/sound/soc/rockchip/rockchip_sai.c +@@ -628,6 +628,10 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, + + regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val); + ++ if (!sai->is_tdm) ++ regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK, ++ SAI_XCR_SBW(params_physical_width(params))); ++ + regmap_read(sai->regmap, reg, &val); + + slot_width = SAI_XCR_SBW_V(val); +-- +2.53.0 + diff --git a/queue-7.0/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch b/queue-7.0/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch new file mode 100644 index 0000000000..5b6ae99ec3 --- /dev/null +++ b/queue-7.0/asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch @@ -0,0 +1,45 @@ +From 62955492ce2cad4d06eb9f76e0988e579ab0d75d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 13:33:11 +0300 +Subject: ASoC: rsnd: Fix potential out-of-bounds access of component_dais[] + +From: Denis Rastyogin + +[ Upstream commit f9e437cddf6cf9e603bdaefe148c1f4792aaf39c ] + +component_dais[RSND_MAX_COMPONENT] is initially zero-initialized +and later populated in rsnd_dai_of_node(). However, the existing boundary check: + if (i >= RSND_MAX_COMPONENT) + +does not guarantee that the last valid element remains zero. As a result, +the loop can rely on component_dais[RSND_MAX_COMPONENT] being zero, +which may lead to an out-of-bounds access. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 547b02f74e4a ("ASoC: rsnd: enable multi Component support for Audio Graph Card/Card2") +Signed-off-by: Denis Rastyogin +Acked-by: Kuninori Morimoto +Link: https://patch.msgid.link/20260327103311.459239-1-gerben@altlinux.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/renesas/rcar/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c +index 69fb19964a71d..2dc078358612d 100644 +--- a/sound/soc/renesas/rcar/core.c ++++ b/sound/soc/renesas/rcar/core.c +@@ -1974,7 +1974,7 @@ static int rsnd_probe(struct platform_device *pdev) + * asoc register + */ + ci = 0; +- for (i = 0; priv->component_dais[i] > 0; i++) { ++ for (i = 0; i < RSND_MAX_COMPONENT && priv->component_dais[i] > 0; i++) { + int nr = priv->component_dais[i]; + + ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, +-- +2.53.0 + diff --git a/queue-7.0/asoc-sdca-add-default-value-for-mipi-sdca-function-r.patch b/queue-7.0/asoc-sdca-add-default-value-for-mipi-sdca-function-r.patch new file mode 100644 index 0000000000..e2d379d881 --- /dev/null +++ b/queue-7.0/asoc-sdca-add-default-value-for-mipi-sdca-function-r.patch @@ -0,0 +1,61 @@ +From 9897f5fc76f6ea1ee0b4105a27c27da102dda65c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 14:01:15 +0000 +Subject: ASoC: SDCA: Add default value for mipi-sdca-function-reset-max-delay + +From: Charles Keepax + +[ Upstream commit 1bbbda5b178a1399339139eb3c326300008b72d6 ] + +Add a default value for the function reset timeout since version 1.0 +of the SDCA specification doesn't actually include this property, it +was added later. + +Fixes: 7b6be935e7ef ("ASoC: SDCA: Parse Function Reset max delay") +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260225140118.402695-2-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_fdl.c | 5 ----- + sound/soc/sdca/sdca_functions.c | 6 +++++- + 2 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c +index 07892bc3a44e6..994821a6df617 100644 +--- a/sound/soc/sdca/sdca_fdl.c ++++ b/sound/soc/sdca/sdca_fdl.c +@@ -46,11 +46,6 @@ int sdca_reset_function(struct device *dev, struct sdca_function_data *function, + if (ret) // Allowed for function reset to not be implemented + return 0; + +- if (!function->reset_max_delay) { +- dev_err(dev, "No reset delay specified in DisCo\n"); +- return -EINVAL; +- } +- + /* + * Poll up to 16 times but no more than once per ms, these are just + * arbitrarily selected values, so may be fine tuned in future. +diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c +index dca60ee8e62c3..fd6a254c95305 100644 +--- a/sound/soc/sdca/sdca_functions.c ++++ b/sound/soc/sdca/sdca_functions.c +@@ -2176,8 +2176,12 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, + + ret = fwnode_property_read_u32(function_desc->node, + "mipi-sdca-function-reset-max-delay", &tmp); +- if (!ret) ++ if (ret || tmp == 0) { ++ dev_dbg(dev, "reset delay missing, defaulting to 100mS\n"); ++ function->reset_max_delay = 100000; ++ } else { + function->reset_max_delay = tmp; ++ } + + dev_dbg(dev, "%pfwP: name %s busy delay %dus reset delay %dus\n", + function->desc->node, function->desc->name, +-- +2.53.0 + diff --git a/queue-7.0/asoc-sdca-fix-cleanup-inversion-in-class-driver.patch b/queue-7.0/asoc-sdca-fix-cleanup-inversion-in-class-driver.patch new file mode 100644 index 0000000000..1045202464 --- /dev/null +++ b/queue-7.0/asoc-sdca-fix-cleanup-inversion-in-class-driver.patch @@ -0,0 +1,117 @@ +From 2b6c0b1bb777530ccf233ba056284aabdf81c273 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 17:43:26 +0100 +Subject: ASoC: SDCA: Fix cleanup inversion in class driver + +From: Richard Fitzgerald + +[ Upstream commit 7936490e04733ade80d0d445529c0a6de0f95515 ] + +Fix inverted cleanup of the SoundWire IRQ and the function drivers +that use it. + +The devm cleanup function to call sdca_dev_unregister_functions() was +being registered at the end of class_sdw_probe(). The bus core +creates the parent SoundWire IRQ handler after class_sdw_probe() has +returned, and it registers a devm cleanup handler at the same time. + +This led to a cleanup inversion where the devm cleanup for the parent +Soundwire IRQ runs before the handler that removes the function drivers. +So the parent IRQ is destroyed before the function drivers had a chance +to do any cleanup and remove their IRQ handlers. + +Move the registrations of the function driver cleanup into +class_boot_work() after the function drivers are registered, so that it +runs before the cleanup of the parent SoundWire IRQ handler. + +Fixes: 2d877d0659cb ("ASoC: SDCA: Add basic SDCA class driver") +Signed-off-by: Richard Fitzgerald +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260409164328.3999434-3-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_class.c | 34 +++++++++++++++++++++------------- + 1 file changed, 21 insertions(+), 13 deletions(-) + +diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c +index 918b638acb577..5def6ae2d99f0 100644 +--- a/sound/soc/sdca/sdca_class.c ++++ b/sound/soc/sdca/sdca_class.c +@@ -137,6 +137,13 @@ static const struct regmap_config class_dev_regmap_config = { + .unlock = class_regmap_unlock, + }; + ++static void class_remove_functions(void *data) ++{ ++ struct sdca_class_drv *drv = data; ++ ++ sdca_dev_unregister_functions(drv->sdw); ++} ++ + static void class_boot_work(struct work_struct *work) + { + struct sdca_class_drv *drv = container_of(work, +@@ -157,6 +164,11 @@ static void class_boot_work(struct work_struct *work) + if (ret) + goto err; + ++ /* Ensure function drivers are removed before the IRQ is destroyed */ ++ ret = devm_add_action_or_reset(drv->dev, class_remove_functions, drv); ++ if (ret) ++ goto err; ++ + dev_dbg(drv->dev, "boot work complete\n"); + + pm_runtime_mark_last_busy(drv->dev); +@@ -168,15 +180,6 @@ static void class_boot_work(struct work_struct *work) + pm_runtime_put_sync(drv->dev); + } + +-static void class_dev_remove(void *data) +-{ +- struct sdca_class_drv *drv = data; +- +- cancel_work_sync(&drv->boot_work); +- +- sdca_dev_unregister_functions(drv->sdw); +-} +- + static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id) + { + struct device *dev = &sdw->dev; +@@ -230,15 +233,19 @@ static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id + if (ret) + return ret; + +- ret = devm_add_action_or_reset(dev, class_dev_remove, drv); +- if (ret) +- return ret; +- + queue_work(system_long_wq, &drv->boot_work); + + return 0; + } + ++static void class_sdw_remove(struct sdw_slave *sdw) ++{ ++ struct device *dev = &sdw->dev; ++ struct sdca_class_drv *drv = dev_get_drvdata(dev); ++ ++ cancel_work_sync(&drv->boot_work); ++} ++ + static int class_suspend(struct device *dev) + { + struct sdca_class_drv *drv = dev_get_drvdata(dev); +@@ -328,6 +335,7 @@ static struct sdw_driver class_sdw_driver = { + }, + + .probe = class_sdw_probe, ++ .remove = class_sdw_remove, + .id_table = class_sdw_id, + .ops = &class_sdw_ops, + }; +-- +2.53.0 + diff --git a/queue-7.0/asoc-sdca-update-counting-of-su-ge-dapm-routes.patch b/queue-7.0/asoc-sdca-update-counting-of-su-ge-dapm-routes.patch new file mode 100644 index 0000000000..7f59261f92 --- /dev/null +++ b/queue-7.0/asoc-sdca-update-counting-of-su-ge-dapm-routes.patch @@ -0,0 +1,137 @@ +From 4d07850d4871fda6985882dc0cc70c0d137e8662 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 14:01:16 +0000 +Subject: ASoC: SDCA: Update counting of SU/GE DAPM routes + +From: Charles Keepax + +[ Upstream commit 1fb720d33eecdb9a90ee340b3000ba378d49f5ca ] + +Device Layer Selector Unit's are controlled by a Group Entity control +rather than by the host directly. For the purposes of the ASoC class +driver the number of input routes to the SU is controlled by the number +of options within the Group Entity Selected Mode Control. ie. One valid +DAPM route for each valid route defined in the Group Entity. + +Currently the code assumes that a Device Layer SU will have a number of +routes equal to the number of potential sources for the SU. ie. it +counts the routes using the SU, but then creates the routes using the +GE. However, this isn't actually true, it is perfectly allowed for the +GE to only define options for some of the potential sources of the SU.o +In such a case the number of routes return will not match those created, +leading to either an overflow of the routes array or undefined routes to +be past to the ASoC core, both of which generally lead to the sound card +failing to probe. + +Update the handling for the counting of routes to count the connected +routes on the GE itself and then ignore the source routes on the SU. +This makes it match the logic generating the routes and ensuring that +both remain in sync. + +Fixes: 2c8b3a8e6aa8 ("ASoC: SDCA: Create DAPM widgets and routes from DisCo") +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Charles Keepax +Link: https://patch.msgid.link/20260225140118.402695-3-ckeepax@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sdca/sdca_asoc.c | 41 +++++++++++++++++++++++++++++++------- + 1 file changed, 34 insertions(+), 7 deletions(-) + +diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c +index a0191e5a5a7dd..b6536eeecf58f 100644 +--- a/sound/soc/sdca/sdca_asoc.c ++++ b/sound/soc/sdca/sdca_asoc.c +@@ -51,6 +51,25 @@ static bool readonly_control(struct sdca_control *control) + return control->has_fixed || control->mode == SDCA_ACCESS_MODE_RO; + } + ++static int ge_count_routes(struct sdca_entity *entity) ++{ ++ int count = 0; ++ int i, j; ++ ++ for (i = 0; i < entity->ge.num_modes; i++) { ++ struct sdca_ge_mode *mode = &entity->ge.modes[i]; ++ ++ for (j = 0; j < mode->num_controls; j++) { ++ struct sdca_ge_control *affected = &mode->controls[j]; ++ ++ if (affected->sel != SDCA_CTL_SU_SELECTOR || affected->val) ++ count++; ++ } ++ } ++ ++ return count; ++} ++ + /** + * sdca_asoc_count_component - count the various component parts + * @dev: Pointer to the device against which allocations will be done. +@@ -74,6 +93,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + int *num_widgets, int *num_routes, int *num_controls, + int *num_dais) + { ++ struct sdca_control *control; + int i, j; + + *num_widgets = function->num_entities - 1; +@@ -83,6 +103,7 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + + for (i = 0; i < function->num_entities - 1; i++) { + struct sdca_entity *entity = &function->entities[i]; ++ bool skip_primary_routes = false; + + /* Add supply/DAI widget connections */ + switch (entity->type) { +@@ -96,6 +117,17 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + case SDCA_ENTITY_TYPE_PDE: + *num_routes += entity->pde.num_managed; + break; ++ case SDCA_ENTITY_TYPE_GE: ++ *num_routes += ge_count_routes(entity); ++ skip_primary_routes = true; ++ break; ++ case SDCA_ENTITY_TYPE_SU: ++ control = sdca_selector_find_control(dev, entity, SDCA_CTL_SU_SELECTOR); ++ if (!control) ++ return -EINVAL; ++ ++ skip_primary_routes = (control->layers == SDCA_ACCESS_LAYER_DEVICE); ++ break; + default: + break; + } +@@ -104,7 +136,8 @@ int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *fun + (*num_routes)++; + + /* Add primary entity connections from DisCo */ +- *num_routes += entity->num_sources; ++ if (!skip_primary_routes) ++ *num_routes += entity->num_sources; + + for (j = 0; j < entity->num_controls; j++) { + if (exported_control(entity, &entity->controls[j])) +@@ -442,7 +475,6 @@ static int entity_parse_su_device(struct device *dev, + struct snd_soc_dapm_route **route) + { + struct sdca_control_range *range; +- int num_routes = 0; + int i, j; + + if (!entity->group) { +@@ -478,11 +510,6 @@ static int entity_parse_su_device(struct device *dev, + return -EINVAL; + } + +- if (++num_routes > entity->num_sources) { +- dev_err(dev, "%s: too many input routes\n", entity->label); +- return -EINVAL; +- } +- + term = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX, + mode->val, SDCA_SELECTED_MODE_TERM_TYPE); + if (!term) { +-- +2.53.0 + diff --git a/queue-7.0/asoc-soc-component-re-add-pcm_new-pcm_free.patch b/queue-7.0/asoc-soc-component-re-add-pcm_new-pcm_free.patch new file mode 100644 index 0000000000..83a675401b --- /dev/null +++ b/queue-7.0/asoc-soc-component-re-add-pcm_new-pcm_free.patch @@ -0,0 +1,91 @@ +From 72a485ffe51375e79ebbe7e2f643a8ce3cf182d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 02:24:43 +0000 +Subject: ASoC: soc-component: re-add pcm_new()/pcm_free() + +From: Kuninori Morimoto + +[ Upstream commit 68130eef1e0d3c1770952e738f7f8d9f340bd42d ] + +Because old pcm_new()/pcm_free() didn't care about parameter component, +to avoid name collisions, we have added pcm_construct()/pcm_destruct() by +commit c64bfc9066007 ("ASoC: soc-core: add new pcm_construct/pcm_destruct") + +Because all driver switch to new pcm_construct()/pcm_destruct(), old +pcm_new()/pcm_free() were remoted by commit e9067bb502787 ("ASoC: +soc-component: remove snd_pcm_ops from component driver") + +But naming of pcm_construct()/pcm_destruct() are not goot. re-add +pcm_new()/pcm_free(), and switch to use it, again. + +Signed-off-by: Kuninori Morimoto +Link: https://patch.msgid.link/87a4w8lde4.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +Stable-dep-of: 3666dc0c47c3 ("ASoC: amd: ps: fix the pcm device numbering for acp pdm dmic") +Signed-off-by: Sasha Levin +--- + include/sound/soc-component.h | 4 ++++ + sound/soc/generic/audio-graph-card.c | 1 + + sound/soc/soc-component.c | 10 +++++++++- + 3 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h +index 2a2b74b24a609..0435ba376369a 100644 +--- a/include/sound/soc-component.h ++++ b/include/sound/soc-component.h +@@ -90,6 +90,10 @@ struct snd_soc_component_driver { + struct snd_soc_pcm_runtime *rtd); + void (*pcm_destruct)(struct snd_soc_component *component, + struct snd_pcm *pcm); ++ int (*pcm_new)(struct snd_soc_component *component, ++ struct snd_soc_pcm_runtime *rtd); ++ void (*pcm_free)(struct snd_soc_component *component, ++ struct snd_pcm *pcm); + + /* component wide operations */ + int (*set_sysclk)(struct snd_soc_component *component, +diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c +index 8a5f417047397..74e8f2ab7ffc9 100644 +--- a/sound/soc/generic/audio-graph-card.c ++++ b/sound/soc/generic/audio-graph-card.c +@@ -77,6 +77,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc) + struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc); + + if (dai && (dai->component->driver->pcm_construct || ++ dai->component->driver->pcm_new || + (dai->driver->ops && dai->driver->ops->pcm_new))) + return true; + +diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c +index 89f236ab30341..77ad333839744 100644 +--- a/sound/soc/soc-component.c ++++ b/sound/soc/soc-component.c +@@ -1042,6 +1042,11 @@ int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd) + if (ret < 0) + return soc_component_ret(component, ret); + } ++ if (component->driver->pcm_new) { ++ ret = component->driver->pcm_new(component, rtd); ++ if (ret < 0) ++ return soc_component_ret(component, ret); ++ } + } + + return 0; +@@ -1055,9 +1060,12 @@ void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd) + if (!rtd->pcm) + return; + +- for_each_rtd_components(rtd, i, component) ++ for_each_rtd_components(rtd, i, component) { + if (component->driver->pcm_destruct) + component->driver->pcm_destruct(component, rtd->pcm); ++ if (component->driver->pcm_free) ++ component->driver->pcm_free(component, rtd->pcm); ++ } + } + + int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream) +-- +2.53.0 + diff --git a/queue-7.0/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch b/queue-7.0/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch new file mode 100644 index 0000000000..2a93bfb11a --- /dev/null +++ b/queue-7.0/asoc-soc-compress-use-function-to-clear-symmetric-pa.patch @@ -0,0 +1,97 @@ +From eaf208baf24bea83b3192fff03fe486d28d4bd89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 04:53:52 +0000 +Subject: ASoC: soc-compress: use function to clear symmetric params + +From: Kuninori Morimoto + +[ Upstream commit 07c774dd64ba0c605dbf844132122e3edbdbea93 ] + +Current soc-compress.c clears symmetric_rate, but it clears rate only, +not clear other symmetric_channels/sample_bits. + + static int soc_compr_clean(...) + { + ... + if (!snd_soc_dai_active(cpu_dai)) +=> cpu_dai->symmetric_rate = 0; + + if (!snd_soc_dai_active(codec_dai)) +=> codec_dai->symmetric_rate = 0; + ... + }; + +This feature was added when v3.7 kernel [1], and there was only +symmetric_rate, no symmetric_channels/sample_bits in that timing. + +symmetric_channels/sample_bits were added in v3.14 [2], +but I guess it didn't notice that soc-compress.c is updating symmetric_xxx. + +We are clearing symmetry_xxx by soc_pcm_set_dai_params(), but is soc-pcm.c +local function. Makes it global function and clear symmetry_xxx by it. + +[1] commit 1245b7005de02 ("ASoC: add compress stream support") +[2] commit 3635bf09a89cf ("ASoC: soc-pcm: add symmetry for channels and + sample bits") + +Fixes: 3635bf09a89c ("ASoC: soc-pcm: add symmetry for channels and sample bits") +Cc: Nicolin Chen +Signed-off-by: Kuninori Morimoto +Link: https://patch.msgid.link/87ms15e3kv.wl-kuninori.morimoto.gx@renesas.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + include/sound/soc.h | 3 +++ + sound/soc/soc-compress.c | 4 ++-- + sound/soc/soc-pcm.c | 4 ++-- + 3 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/include/sound/soc.h b/include/sound/soc.h +index 7d8376c8e1bed..1e0b7cd8d956e 100644 +--- a/include/sound/soc.h ++++ b/include/sound/soc.h +@@ -1412,6 +1412,9 @@ struct snd_soc_dai *snd_soc_find_dai( + struct snd_soc_dai *snd_soc_find_dai_with_mutex( + const struct snd_soc_dai_link_component *dlc); + ++void soc_pcm_set_dai_params(struct snd_soc_dai *dai, ++ struct snd_pcm_hw_params *params); ++ + #include + + static inline +diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c +index 7b81dffc6a935..b8402802ae784 100644 +--- a/sound/soc/soc-compress.c ++++ b/sound/soc/soc-compress.c +@@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) + snd_soc_dai_digital_mute(codec_dai, 1, stream); + + if (!snd_soc_dai_active(cpu_dai)) +- cpu_dai->symmetric_rate = 0; ++ soc_pcm_set_dai_params(cpu_dai, NULL); + + if (!snd_soc_dai_active(codec_dai)) +- codec_dai->symmetric_rate = 0; ++ soc_pcm_set_dai_params(codec_dai, NULL); + + snd_soc_link_compr_shutdown(cstream, rollback); + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index afa9fad4457f2..9b12eedb77c33 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -423,8 +423,8 @@ void dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event) + snd_soc_dapm_stream_event(fe, dir, event); + } + +-static void soc_pcm_set_dai_params(struct snd_soc_dai *dai, +- struct snd_pcm_hw_params *params) ++void soc_pcm_set_dai_params(struct snd_soc_dai *dai, ++ struct snd_pcm_hw_params *params) + { + if (params) { + dai->symmetric_rate = params_rate(params); +-- +2.53.0 + diff --git a/queue-7.0/asoc-sof-compress-return-the-configured-codec-from-g.patch b/queue-7.0/asoc-sof-compress-return-the-configured-codec-from-g.patch new file mode 100644 index 0000000000..d5ca7238ac --- /dev/null +++ b/queue-7.0/asoc-sof-compress-return-the-configured-codec-from-g.patch @@ -0,0 +1,88 @@ +From 335d26003ff0f3951c0a16eceed5802cb5826214 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 17:05:11 -0300 +Subject: ASoC: SOF: compress: return the configured codec from get_params +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +[ Upstream commit 2c4fdd055f92a2fc8602dcd88bcea08c374b7e8b ] + +The SOF compressed offload path accepts codec parameters in +sof_compr_set_params() and forwards them to firmware as +extended data in the SOF IPC stream params message. + +However, sof_compr_get_params() still returns success without +filling the snd_codec structure. Since the compress core allocates +that structure zeroed and copies it back to userspace on success, +SNDRV_COMPRESS_GET_PARAMS returns an all-zero codec description +even after the stream has been configured successfully. + +The stale TODO in this callback conflates get_params() with capability +discovery. Supported codec enumeration belongs in get_caps() and +get_codec_caps(). get_params() should report the current codec settings. + +Cache the codec accepted by sof_compr_set_params() in the per-stream SOF +compress state and return it from sof_compr_get_params(). + +Fixes: 6324cf901e14 ("ASoC: SOF: compr: Add compress ops implementation") +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260325-sof-compr-get-params-v1-1-0758815f13c7@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/compress.c | 8 +++++--- + sound/soc/sof/sof-priv.h | 2 ++ + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c +index 90f056eae1c33..a676ffc2379df 100644 +--- a/sound/soc/sof/compress.c ++++ b/sound/soc/sof/compress.c +@@ -255,6 +255,7 @@ static int sof_compr_set_params(struct snd_soc_component *component, + sstream->sampling_rate = params->codec.sample_rate; + sstream->channels = params->codec.ch_out; + sstream->sample_container_bytes = pcm->params.sample_container_bytes; ++ sstream->codec_params = params->codec; + + spcm->prepared[cstream->direction] = true; + +@@ -267,9 +268,10 @@ static int sof_compr_set_params(struct snd_soc_component *component, + static int sof_compr_get_params(struct snd_soc_component *component, + struct snd_compr_stream *cstream, struct snd_codec *params) + { +- /* TODO: we don't query the supported codecs for now, if the +- * application asks for an unsupported codec the set_params() will fail. +- */ ++ struct sof_compr_stream *sstream = cstream->runtime->private_data; ++ ++ *params = sstream->codec_params; ++ + return 0; + } + +diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h +index 693d063830fae..38753b088fc1d 100644 +--- a/sound/soc/sof/sof-priv.h ++++ b/sound/soc/sof/sof-priv.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -111,6 +112,7 @@ struct sof_compr_stream { + u32 sampling_rate; + u16 channels; + u16 sample_container_bytes; ++ struct snd_codec codec_params; + size_t posn_offset; + }; + +-- +2.53.0 + diff --git a/queue-7.0/asoc-sof-intel-add-an-empty-adr_link.patch b/queue-7.0/asoc-sof-intel-add-an-empty-adr_link.patch new file mode 100644 index 0000000000..1169aa42ca --- /dev/null +++ b/queue-7.0/asoc-sof-intel-add-an-empty-adr_link.patch @@ -0,0 +1,40 @@ +From c5ad47b40ad69407ff57b10b2ede79aa4ed41f23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 18:50:31 +0800 +Subject: ASoC: SOF: Intel: add an empty adr_link + +From: Bard Liao + +[ Upstream commit 3c6f06a200796ae7b2b1065e8a6499b138e27a50 ] + +An empty adr_link is expected to terminate the +for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) loop. +Allocate link_num + 1 links to add an empty adr_link. + +Fixes: 5226d19d4cae5 ("ASoC: SOF: Intel: use sof_sdw as default SDW machine driver") +Signed-off-by: Bard Liao +Reviewed-by: Charles Keepax +Link: https://patch.msgid.link/20260424105031.114053-1-yung-chuan.liao@linux.intel.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/intel/hda.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c +index 8a240dcb7fcb3..5fa773bb26788 100644 +--- a/sound/soc/sof/intel/hda.c ++++ b/sound/soc/sof/intel/hda.c +@@ -1399,7 +1399,8 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev + link_mask |= BIT(peripherals->array[i]->bus->link_id); + + link_num = hweight32(link_mask); +- links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL); ++ /* An empty adr_link is needed to terminate the adr_link loop */ ++ links = devm_kcalloc(sdev->dev, link_num + 1, sizeof(*links), GFP_KERNEL); + if (!links) + return NULL; + +-- +2.53.0 + diff --git a/queue-7.0/asoc-sof-intel-hda-place-check-before-dereference.patch b/queue-7.0/asoc-sof-intel-hda-place-check-before-dereference.patch new file mode 100644 index 0000000000..580e4b9c83 --- /dev/null +++ b/queue-7.0/asoc-sof-intel-hda-place-check-before-dereference.patch @@ -0,0 +1,60 @@ +From ba6a238d95e145bee62ecc4e4a4185ca8abfc73d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 12:38:30 -0500 +Subject: ASoC: SOF: Intel: hda: Place check before dereference + +From: Ethan Tidmore + +[ Upstream commit 6cbc8360f51a3df2ea16a786b262b9fe44d4c68c ] + +The struct hext_stream is dereferenced before it is checked for NULL. +Although it can never be NULL due to a check prior to +hda_dsp_iccmax_stream_hw_params() being called, this change clears any +confusion regarding hext_stream possibly being NULL. + +Check hext_stream for NULL and then assign its members. + +Detected by Smatch: +sound/soc/sof/intel/hda-stream.c:488 hda_dsp_iccmax_stream_hw_params() warn: +variable dereferenced before check 'hext_stream' (see line 486) + +Fixes: aca961f196e5d ("ASoC: SOF: Intel: hda: Add helper function to program ICCMAX stream") +Signed-off-by: Ethan Tidmore +Link: https://patch.msgid.link/20260324173830.17563-1-ethantidmore06@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sof/intel/hda-stream.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c +index 1c04b5d9c0d8b..5c1f3b427cdb8 100644 +--- a/sound/soc/sof/intel/hda-stream.c ++++ b/sound/soc/sof/intel/hda-stream.c +@@ -480,16 +480,20 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params) + { +- struct hdac_stream *hstream = &hext_stream->hstream; +- int sd_offset = SOF_STREAM_SD_OFFSET(hstream); ++ struct hdac_stream *hstream; ++ int sd_offset; + int ret; +- u32 mask = 0x1 << hstream->index; ++ u32 mask; + + if (!hext_stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + ++ hstream = &hext_stream->hstream; ++ sd_offset = SOF_STREAM_SD_OFFSET(hstream); ++ mask = 0x1 << hstream->index; ++ + if (!dmab) { + dev_err(sdev->dev, "error: no dma buffer allocated!\n"); + return -ENODEV; +-- +2.53.0 + diff --git a/queue-7.0/asoc-sti-return-errors-from-regmap_field_alloc.patch b/queue-7.0/asoc-sti-return-errors-from-regmap_field_alloc.patch new file mode 100644 index 0000000000..77b0201e17 --- /dev/null +++ b/queue-7.0/asoc-sti-return-errors-from-regmap_field_alloc.patch @@ -0,0 +1,50 @@ +From 2a0eefea0ae08748dd4cf68c7bd55d521a77c37d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:33 +0100 +Subject: ASoC: sti: Return errors from regmap_field_alloc() + +From: Sander Vanheule + +[ Upstream commit 272aabef50bc3fe58edd26de000f4cdd41bdbe60 ] + +When regmap_field_alloc() fails, it can return an error. Specifically, +it will return PTR_ERR(-ENOMEM) when the allocation returns a NULL +pointer. The code then uses these allocations with a simple NULL check: + + if (player->clk_sel) { + // May dereference invalid pointer (-ENOMEM) + err = regmap_field_write(player->clk_sel, ...); + } + +Ensure initialization fails by forwarding the errors from +regmap_field_alloc(), thus avoiding the use of the invalid pointers. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-2-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index 6d1ce030963c6..f1b7e76f97b58 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1029,7 +1029,12 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + } + + player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ if (IS_ERR(player->clk_sel)) ++ return PTR_ERR(player->clk_sel); ++ + player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ if (IS_ERR(player->valid_sel)) ++ return PTR_ERR(player->valid_sel); + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/asoc-sti-use-managed-regmap_field-allocations.patch b/queue-7.0/asoc-sti-use-managed-regmap_field-allocations.patch new file mode 100644 index 0000000000..2d6a2214ee --- /dev/null +++ b/queue-7.0/asoc-sti-use-managed-regmap_field-allocations.patch @@ -0,0 +1,45 @@ +From bf85d90d794f76e9d21341a2ca6309a5f9a60d5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 16:26:34 +0100 +Subject: ASoC: sti: use managed regmap_field allocations + +From: Sander Vanheule + +[ Upstream commit 1696fad8b259a2d46e51cd6e17e4bcdbe02279fa ] + +The regmap_field objects allocated at player init are never freed and +may leak resources if the driver is removed. + +Switch to devm_regmap_field_alloc() to automatically limit the lifetime +of the allocations the lifetime of the device. + +Fixes: 76c2145ded6b ("ASoC: sti: Add CPU DAI driver for playback") +Signed-off-by: Sander Vanheule +Link: https://patch.msgid.link/20260220152634.480766-3-sander@svanheule.net +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/sti/uniperif_player.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c +index f1b7e76f97b58..45d35b887e4eb 100644 +--- a/sound/soc/sti/uniperif_player.c ++++ b/sound/soc/sti/uniperif_player.c +@@ -1028,11 +1028,11 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, + return PTR_ERR(regmap); + } + +- player->clk_sel = regmap_field_alloc(regmap, regfield[0]); ++ player->clk_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[0]); + if (IS_ERR(player->clk_sel)) + return PTR_ERR(player->clk_sel); + +- player->valid_sel = regmap_field_alloc(regmap, regfield[1]); ++ player->valid_sel = devm_regmap_field_alloc(&pdev->dev, regmap, regfield[1]); + if (IS_ERR(player->valid_sel)) + return PTR_ERR(player->valid_sel); + +-- +2.53.0 + diff --git a/queue-7.0/asoc-tas2764-mark-die-temp-register-as-volatile.patch b/queue-7.0/asoc-tas2764-mark-die-temp-register-as-volatile.patch new file mode 100644 index 0000000000..b0b7bb3456 --- /dev/null +++ b/queue-7.0/asoc-tas2764-mark-die-temp-register-as-volatile.patch @@ -0,0 +1,39 @@ +From 259c76b7e384a6caaa59b90d255b1fdaea301a37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:44:03 +1000 +Subject: ASoC: tas2764: Mark die temp register as volatile + +From: James Calligeros + +[ Upstream commit 4cfb5971c2fbfac061c23fb4224a3a008199de81 ] + +Reading the temperature register always returns the first value +read from the chip due to regcache. + +Mark TAS2764_TEMP as volatile to prevent returning stale, cached +values when reading the die temp. + +Fixes: 186dfc85f9a8 ("ASoC: tas2764: expose die temp to hwmon") +Signed-off-by: James Calligeros +Link: https://patch.msgid.link/20260425-tas27xx-hwmon-fixes-v1-1-83c13b8e8f54@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2764.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c +index 36e25e48b3546..9f351565dc82d 100644 +--- a/sound/soc/codecs/tas2764.c ++++ b/sound/soc/codecs/tas2764.c +@@ -809,6 +809,7 @@ static bool tas2764_volatile_register(struct device *dev, unsigned int reg) + { + switch (reg) { + case TAS2764_SW_RST: ++ case TAS2764_TEMP: + case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: + case TAS2764_INT_CLK_CFG: + return true; +-- +2.53.0 + diff --git a/queue-7.0/asoc-tas2770-fix-order-of-operations-for-temperature.patch b/queue-7.0/asoc-tas2770-fix-order-of-operations-for-temperature.patch new file mode 100644 index 0000000000..0806108825 --- /dev/null +++ b/queue-7.0/asoc-tas2770-fix-order-of-operations-for-temperature.patch @@ -0,0 +1,52 @@ +From 2711814dbb513bb854199972537fb6494c3036fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:44:05 +1000 +Subject: ASoC: tas2770: Fix order of operations for temperature calculation + +From: James Calligeros + +[ Upstream commit c7ecb6a61908c2604dda6e42da66724d256de7b9 ] + +The order of operations to derive the temperature from the temp +register values was wrong, since 1000 / 16 is not an integer. This +resulted in the calculated temperature value deviating from the +value represented by the registers slightly, which was most obvious +when the registers were zeroed (-92.265 *C vs the expected -93.000 *C). + +Scale the reading before dividing the whole thing by 16 to correct +this. + +Fixes: ff73e2780169 ("ASoC: tas2770: expose die temp to hwmon") +Signed-off-by: James Calligeros +Link: https://patch.msgid.link/20260425-tas27xx-hwmon-fixes-v1-3-83c13b8e8f54@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/tas2770.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c +index 6f878b01716f7..2ce3011119bdb 100644 +--- a/sound/soc/codecs/tas2770.c ++++ b/sound/soc/codecs/tas2770.c +@@ -549,7 +549,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result) + /* + * As per datasheet: divide register by 16 and subtract 93 to get + * degrees Celsius. hwmon requires millidegrees. Let's avoid rounding +- * errors by subtracting 93 * 16 then multiplying by 1000 / 16. ++ * errors by subtracting 93 * 16 and scaling before dividing. + * + * NOTE: The ADC registers are initialised to 0 on reset. This means + * that the temperature will read -93 *C until the chip is brought out +@@ -558,7 +558,7 @@ static int tas2770_read_die_temp(struct tas2770_priv *tas2770, long *result) + * value read back from its registers will be the last value sampled + * before entering software shutdown. + */ +- *result = (reading - (93 * 16)) * (1000 / 16); ++ *result = (reading - (93 * 16)) * 1000 / 16; + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/backlight-sky81452-backlight-check-return-value-of-d.patch b/queue-7.0/backlight-sky81452-backlight-check-return-value-of-d.patch new file mode 100644 index 0000000000..341e6d8f4e --- /dev/null +++ b/queue-7.0/backlight-sky81452-backlight-check-return-value-of-d.patch @@ -0,0 +1,46 @@ +From 6995c266024fafb90a23aba457120fad2dd3fa19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 10:16:25 +0800 +Subject: backlight: sky81452-backlight: Check return value of + devm_gpiod_get_optional() in sky81452_bl_parse_dt() + +From: Chen Ni + +[ Upstream commit 797cc011ae02bda26f93d25a4442d7a1a77d84df ] + +The devm_gpiod_get_optional() function may return an ERR_PTR in case of +genuine GPIO acquisition errors, not just NULL which indicates the +legitimate absence of an optional GPIO. + +Add an IS_ERR() check after the call in sky81452_bl_parse_dt(). On +error, return the error code to ensure proper failure handling rather +than proceeding with invalid pointers. + +Fixes: e1915eec54a6 ("backlight: sky81452: Convert to GPIO descriptors") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Reviewed-by: Daniel Thompson (RISCstar) +Link: https://patch.msgid.link/20260203021625.578678-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/video/backlight/sky81452-backlight.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c +index 2749231f03854..b2679b24de14b 100644 +--- a/drivers/video/backlight/sky81452-backlight.c ++++ b/drivers/video/backlight/sky81452-backlight.c +@@ -202,6 +202,9 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( + pdata->dpwm_mode = of_property_read_bool(np, "skyworks,dpwm-mode"); + pdata->phase_shift = of_property_read_bool(np, "skyworks,phase-shift"); + pdata->gpiod_enable = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH); ++ if (IS_ERR(pdata->gpiod_enable)) ++ return dev_err_cast_probe(dev, pdata->gpiod_enable, ++ "failed to get gpio\n"); + + ret = of_property_count_u32_elems(np, "led-sources"); + if (ret < 0) { +-- +2.53.0 + diff --git a/queue-7.0/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch b/queue-7.0/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch new file mode 100644 index 0000000000..33c3107035 --- /dev/null +++ b/queue-7.0/bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch @@ -0,0 +1,60 @@ +From 175b45f9fc17159f8ec807127605843af820eacb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 09:53:51 -0700 +Subject: bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst() + +From: Weiming Shi + +[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ] + +bareudp_fill_metadata_dst() passes bareudp->sock to +udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. +The socket is only created in bareudp_open() and NULLed in +bareudp_stop(), so calling this function while the device is down +triggers a NULL dereference via sock->sk. + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) + Call Trace: + + bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) + do_execute_actions (net/openvswitch/actions.c:901) + ovs_execute_actions (net/openvswitch/actions.c:1589) + ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) + genl_rcv_msg (net/netlink/genetlink.c:1209) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths +in the same driver. + +Fixes: 571912c69f0e ("net: UDP tunnel encapsulation module for tunnelling different protocols like MPLS, IP, NSH etc.") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426165350.1663137-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bareudp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c +index 0df3208783ad9..da5866ba06999 100644 +--- a/drivers/net/bareudp.c ++++ b/drivers/net/bareudp.c +@@ -529,6 +529,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev, + struct in6_addr saddr; + struct socket *sock = rcu_dereference(bareudp->sock); + ++ if (!sock) ++ return -ESHUTDOWN; ++ + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, + 0, &saddr, &info->key, + sport, bareudp->port, info->key.tos, +-- +2.53.0 + diff --git a/queue-7.0/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch b/queue-7.0/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch new file mode 100644 index 0000000000..cc2045fe3b --- /dev/null +++ b/queue-7.0/blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch @@ -0,0 +1,47 @@ +From 46f43958f6a0f06b2191c6f0f56eba6c8c77e3bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:50:54 +0800 +Subject: blk-cgroup: fix disk reference leak in blkcg_maybe_throttle_current() + +From: Jackie Liu + +[ Upstream commit 23308af722fefed00af5f238024c11710938fba3 ] + +Add the missing put_disk() on the error path in +blkcg_maybe_throttle_current(). When blkcg lookup, blkg lookup, or +blkg_tryget() fails, the function jumps to the out label which only +calls rcu_read_unlock() but does not release the disk reference acquired +by blkcg_schedule_throttle() via get_device(). Since current->throttle_disk +is already set to NULL before the lookup, blkcg_exit() cannot release +this reference either, causing the disk to never be freed. + +Restore the reference release that was present as blk_put_queue() in the +original code but was inadvertently dropped during the conversion from +request_queue to gendisk. + +Fixes: f05837ed73d0 ("blk-cgroup: store a gendisk to throttle in struct task_struct") +Signed-off-by: Jackie Liu +Acked-by: Tejun Heo +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260331085054.46857-1-liu.yun@linux.dev +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index 2d7b18eb72915..554c87bb4a865 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -2037,6 +2037,7 @@ void blkcg_maybe_throttle_current(void) + return; + out: + rcu_read_unlock(); ++ put_disk(disk); + } + + /** +-- +2.53.0 + diff --git a/queue-7.0/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch b/queue-7.0/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch new file mode 100644 index 0000000000..a7a2e94de8 --- /dev/null +++ b/queue-7.0/blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch @@ -0,0 +1,75 @@ +From 691ac218ac4e20148c5e249ecf87366aa43fbcc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 11:28:37 +0800 +Subject: blk-cgroup: wait for blkcg cleanup before initializing new disk + +From: Ming Lei + +[ Upstream commit 3dbaacf6ab68f81e3375fe769a2ecdbd3ce386fd ] + +When a queue is shared across disk rebind (e.g., SCSI unbind/bind), the +previous disk's blkcg state is cleaned up asynchronously via +disk_release() -> blkcg_exit_disk(). If the new disk's blkcg_init_disk() +runs before that cleanup finishes, we may overwrite q->root_blkg while +the old one is still alive, and radix_tree_insert() in blkg_create() +fails with -EEXIST because the old blkg entries still occupy the same +queue id slot in blkcg->blkg_tree. This causes the sd probe to fail +with -ENOMEM. + +Fix it by waiting in blkcg_init_disk() for root_blkg to become NULL, +which indicates the previous disk's blkcg cleanup has completed. + +Fixes: 1059699f87eb ("block: move blkcg initialization/destroy into disk allocation/release handler") +Cc: Yi Zhang +Signed-off-by: Ming Lei +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260311032837.2368714-1-ming.lei@redhat.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-cgroup.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c +index b70096497d389..2d7b18eb72915 100644 +--- a/block/blk-cgroup.c ++++ b/block/blk-cgroup.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -611,6 +612,8 @@ static void blkg_destroy_all(struct gendisk *disk) + + q->root_blkg = NULL; + spin_unlock_irq(&q->queue_lock); ++ ++ wake_up_var(&q->root_blkg); + } + + static void blkg_iostat_set(struct blkg_iostat *dst, struct blkg_iostat *src) +@@ -1498,6 +1501,18 @@ int blkcg_init_disk(struct gendisk *disk) + struct blkcg_gq *new_blkg, *blkg; + bool preloaded; + ++ /* ++ * If the queue is shared across disk rebind (e.g., SCSI), the ++ * previous disk's blkcg state is cleaned up asynchronously via ++ * disk_release() -> blkcg_exit_disk(). Wait for that cleanup to ++ * finish (indicated by root_blkg becoming NULL) before setting up ++ * new blkcg state. Otherwise, we may overwrite q->root_blkg while ++ * the old one is still alive, and radix_tree_insert() in ++ * blkg_create() will fail with -EEXIST because the old entries ++ * still occupy the same queue id slot in blkcg->blkg_tree. ++ */ ++ wait_var_event(&q->root_blkg, !READ_ONCE(q->root_blkg)); ++ + new_blkg = blkg_alloc(&blkcg_root, disk, GFP_KERNEL); + if (!new_blkg) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-7.0/blk-wbt-remove-warn_on_once-from-wbt_init_enable_def.patch b/queue-7.0/blk-wbt-remove-warn_on_once-from-wbt_init_enable_def.patch new file mode 100644 index 0000000000..8f5b727c7f --- /dev/null +++ b/queue-7.0/blk-wbt-remove-warn_on_once-from-wbt_init_enable_def.patch @@ -0,0 +1,61 @@ +From 0511d572242a8411392c642811c5711e9940cb2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 07:03:59 +0000 +Subject: blk-wbt: remove WARN_ON_ONCE from wbt_init_enable_default() + +From: Yuto Ohnuki + +[ Upstream commit e9b004ff83067cdf96774b45aea4b239ace99a2f ] + +wbt_init_enable_default() uses WARN_ON_ONCE to check for failures from +wbt_alloc() and wbt_init(). However, both are expected failure paths: + +- wbt_alloc() can return NULL under memory pressure (-ENOMEM) +- wbt_init() can fail with -EBUSY if wbt is already registered + +syzbot triggers this by injecting memory allocation failures during MTD +partition creation via ioctl(BLKPG), causing a spurious warning. + +wbt_init_enable_default() is a best-effort initialization called from +blk_register_queue() with a void return type. Failure simply means the +disk operates without writeback throttling, which is harmless. + +Replace WARN_ON_ONCE with plain if-checks, consistent with how +wbt_set_lat() in the same file already handles these failures. Add a +pr_warn() for the wbt_init() failure to retain diagnostic information +without triggering a full stack trace. + +Reported-by: syzbot+71fcf20f7c1e5043d78c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=71fcf20f7c1e5043d78c +Fixes: 41afaeeda509 ("blk-wbt: fix possible deadlock to nest pcpu_alloc_mutex under q_usage_counter") +Signed-off-by: Yuto Ohnuki +Reviewed-by: Yu Kuai +Reviewed-by: Nilay Shroff +Link: https://patch.msgid.link/20260316070358.65225-2-ytohnuki@amazon.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-wbt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/block/blk-wbt.c b/block/blk-wbt.c +index 33006edfccd44..dcc2438ca16dc 100644 +--- a/block/blk-wbt.c ++++ b/block/blk-wbt.c +@@ -782,10 +782,11 @@ void wbt_init_enable_default(struct gendisk *disk) + return; + + rwb = wbt_alloc(); +- if (WARN_ON_ONCE(!rwb)) ++ if (!rwb) + return; + +- if (WARN_ON_ONCE(wbt_init(disk, rwb))) { ++ if (wbt_init(disk, rwb)) { ++ pr_warn("%s: failed to enable wbt\n", disk->disk_name); + wbt_free(rwb); + return; + } +-- +2.53.0 + diff --git a/queue-7.0/block-fix-zones_cond-memory-leak-on-zone-revalidatio.patch b/queue-7.0/block-fix-zones_cond-memory-leak-on-zone-revalidatio.patch new file mode 100644 index 0000000000..d5f7b4fa28 --- /dev/null +++ b/queue-7.0/block-fix-zones_cond-memory-leak-on-zone-revalidatio.patch @@ -0,0 +1,97 @@ +From 220de5cb7548f0778bf5c2dc6cd6fc6b02da0972 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 19:12:16 +0800 +Subject: block: fix zones_cond memory leak on zone revalidation error paths + +From: Jackie Liu + +[ Upstream commit 2a2f520fda824b5a25c93f2249578ea150c24e06 ] + +When blk_revalidate_disk_zones() fails after disk_revalidate_zone_resources() +has allocated args.zones_cond, the memory is leaked because no error path +frees it. + +Fixes: 6e945ffb6555 ("block: use zone condition to determine conventional zones") +Suggested-by: Damien Le Moal +Signed-off-by: Jackie Liu +Link: https://patch.msgid.link/20260331111216.24242-1-liu.yun@linux.dev +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-zoned.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/block/blk-zoned.c b/block/blk-zoned.c +index 7aae3c236cad6..a4d82342e37ac 100644 +--- a/block/blk-zoned.c ++++ b/block/blk-zoned.c +@@ -1877,6 +1877,7 @@ static int disk_revalidate_zone_resources(struct gendisk *disk, + { + struct queue_limits *lim = &disk->queue->limits; + unsigned int pool_size; ++ int ret = 0; + + args->disk = disk; + args->nr_zones = +@@ -1899,10 +1900,13 @@ static int disk_revalidate_zone_resources(struct gendisk *disk, + pool_size = + min(BLK_ZONE_WPLUG_DEFAULT_POOL_SIZE, args->nr_zones); + +- if (!disk->zone_wplugs_hash) +- return disk_alloc_zone_resources(disk, pool_size); ++ if (!disk->zone_wplugs_hash) { ++ ret = disk_alloc_zone_resources(disk, pool_size); ++ if (ret) ++ kfree(args->zones_cond); ++ } + +- return 0; ++ return ret; + } + + /* +@@ -1934,6 +1938,7 @@ static int disk_update_zone_resources(struct gendisk *disk, + disk->zone_capacity = args->zone_capacity; + disk->last_zone_capacity = args->last_zone_capacity; + disk_set_zones_cond_array(disk, args->zones_cond); ++ args->zones_cond = NULL; + + /* + * Some devices can advertise zone resource limits that are larger than +@@ -2216,21 +2221,30 @@ int blk_revalidate_disk_zones(struct gendisk *disk) + } + memalloc_noio_restore(noio_flag); + ++ if (ret <= 0) ++ goto free_resources; ++ + /* + * If zones where reported, make sure that the entire disk capacity + * has been checked. + */ +- if (ret > 0 && args.sector != capacity) { ++ if (args.sector != capacity) { + pr_warn("%s: Missing zones from sector %llu\n", + disk->disk_name, args.sector); + ret = -ENODEV; ++ goto free_resources; + } + +- if (ret > 0) +- return disk_update_zone_resources(disk, &args); ++ ret = disk_update_zone_resources(disk, &args); ++ if (ret) ++ goto free_resources; ++ ++ return 0; + ++free_resources: + pr_warn("%s: failed to revalidate zones\n", disk->disk_name); + ++ kfree(args.zones_cond); + memflags = blk_mq_freeze_queue(q); + disk_free_zone_resources(disk); + blk_mq_unfreeze_queue(q, memflags); +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch b/queue-7.0/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch new file mode 100644 index 0000000000..c2c1151c75 --- /dev/null +++ b/queue-7.0/bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch @@ -0,0 +1,52 @@ +From 7d3c749312aed958f239a7935f0a6d30da19e647 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 16:42:59 +0300 +Subject: Bluetooth: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER + +From: Pauli Virtanen + +[ Upstream commit 5c7209a341ff2ac338b2b0375c34a307b37c9ac2 ] + +When protocol sets HCI_PROTO_DEFER, hci_conn_request_evt() calls +hci_connect_cfm(conn) without hdev->lock. Generally hci_connect_cfm() +assumes it is held, and if conn is deleted concurrently -> UAF. + +Only SCO and ISO set HCI_PROTO_DEFER and only for defer setup listen, +and HCI_EV_CONN_REQUEST is not generated for ISO. In the non-deferred +listening socket code paths, hci_connect_cfm(conn) is called with +hdev->lock held. + +Fix by holding the lock. + +Fixes: 70c464256310 ("Bluetooth: Refactor connection request handling") +Signed-off-by: Pauli Virtanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 0df1c0cbc8f78..1b3b9131affaa 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -3340,8 +3340,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + + memcpy(conn->dev_class, ev->dev_class, 3); + +- hci_dev_unlock(hdev); +- + if (ev->link_type == ACL_LINK || + (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; +@@ -3375,7 +3373,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, + hci_connect_cfm(conn, 0); + } + +- return; + unlock: + hci_dev_unlock(hdev); + } +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch b/queue-7.0/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch new file mode 100644 index 0000000000..4a0a49967a --- /dev/null +++ b/queue-7.0/bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch @@ -0,0 +1,49 @@ +From 80233eb89c1bb746826caf220684d1c293ee0e81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:47:20 +0100 +Subject: Bluetooth: hci_ldisc: Clear HCI_UART_PROTO_INIT on error + +From: Jonathan Rissanen + +[ Upstream commit 68d39ea5e0adc9ecaea1ce8abd842ec972eb8718 ] + +When hci_register_dev() fails in hci_uart_register_dev() +HCI_UART_PROTO_INIT is not cleared before calling hu->proto->close(hu) +and setting hu->hdev to NULL. This means incoming UART data will reach +the protocol-specific recv handler in hci_uart_tty_receive() after +resources are freed. + +Clear HCI_UART_PROTO_INIT with a write lock before calling +hu->proto->close() and setting hu->hdev to NULL. The write lock ensures +all active readers have completed and no new reader can enter the +protocol recv path before resources are freed. + +This allows the protocol-specific recv functions to remove the +"HCI_UART_REGISTERED" guard without risking a null pointer dereference +if hci_register_dev() fails. + +Fixes: 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during initialization") +Signed-off-by: Jonathan Rissanen +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/hci_ldisc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c +index 71c1997a0f734..275ea865bc297 100644 +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -692,6 +692,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) + + if (hci_register_dev(hdev) < 0) { + BT_ERR("Can't register HCI device"); ++ percpu_down_write(&hu->proto_lock); ++ clear_bit(HCI_UART_PROTO_INIT, &hu->flags); ++ percpu_up_write(&hu->proto_lock); + hu->proto->close(hu); + hu->hdev = NULL; + hci_free_dev(hdev); +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch b/queue-7.0/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch new file mode 100644 index 0000000000..08855f5403 --- /dev/null +++ b/queue-7.0/bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch @@ -0,0 +1,48 @@ +From 4d98e5f5478e1b6197e1c61b66ab64a940fa2cfd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 23:47:41 +0800 +Subject: Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp + +From: Dudu Lu + +[ Upstream commit 42776497cdbc9a665b384a6dcb85f0d4bd927eab ] + +l2cap_ecred_reconf_rsp() calls l2cap_chan_del() without holding +l2cap_chan_lock(). Every other l2cap_chan_del() caller in the file +acquires the lock first. A remote BLE device can send a crafted +L2CAP ECRED reconfiguration response to corrupt the channel list +while another thread is iterating it. + +Add l2cap_chan_hold() and l2cap_chan_lock() before l2cap_chan_del(), +and l2cap_chan_unlock() and l2cap_chan_put() after, matching the +pattern used in l2cap_ecred_conn_rsp() and l2cap_conn_del(). + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Signed-off-by: Dudu Lu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 1c82612679e60..0d8053a3fc0a6 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -5473,7 +5473,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, + if (chan->ident != cmd->ident) + continue; + ++ l2cap_chan_hold(chan); ++ l2cap_chan_lock(chan); ++ + l2cap_chan_del(chan, ECONNRESET); ++ ++ l2cap_chan_unlock(chan); ++ l2cap_chan_put(chan); + } + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch b/queue-7.0/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch new file mode 100644 index 0000000000..bebf550199 --- /dev/null +++ b/queue-7.0/bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch @@ -0,0 +1,38 @@ +From c6966e295d419fd6c94853bea901e24d91b7d812 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 14:34:13 -0400 +Subject: Bluetooth: L2CAP: Fix printing wrong information if SDU length + exceeds MTU + +From: Luiz Augusto von Dentz + +[ Upstream commit 15bf35a660eb82a49f8397fc3d3acada8dae13db ] + +The code was printing skb->len and sdu_len in the places where it should +be sdu_len and chan->imtu respectively to match the if conditions. + +Link: https://lore.kernel.org/linux-bluetooth/20260315132013.75ab40c5@kernel.org/T/#m1418f9c82eeff8510c1beaa21cf53af20db96c06 +Fixes: e1d9a6688986 ("Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU") +Signed-off-by: Luiz Augusto von Dentz +Reviewed-by: Paul Menzel +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 95c65fece39bd..1c82612679e60 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6733,7 +6733,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) + + if (sdu_len > chan->imtu) { + BT_ERR("Too big LE L2CAP SDU length: len %u > %u", +- skb->len, sdu_len); ++ sdu_len, chan->imtu); + l2cap_send_disconn_req(chan, ECONNRESET); + err = -EMSGSIZE; + goto failed; +-- +2.53.0 + diff --git a/queue-7.0/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch b/queue-7.0/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch new file mode 100644 index 0000000000..0eb5a23b54 --- /dev/null +++ b/queue-7.0/bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch @@ -0,0 +1,70 @@ +From 742b833a3fcb9e7cee77ba3bbf07a8e4e7140d7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:13:45 +0200 +Subject: Bluetooth: SCO: check for codecs->num_codecs == 1 before assigning to + sco_pi(sk)->codec + +From: Stefan Metzmacher + +[ Upstream commit 4e10a9ebbf081c16517cdd9366ac618bf38d7d0c ] + +copy_struct_from_sockptr() fill 'buffer' in +sco_sock_setsockopt() with zeros, so there's no +real problem. + +But it actually looks strange to do this, +without checking all of codecs->codecs[0] +really comes from userspace: + + sco_pi(sk)->codec = codecs->codecs[0]; + +As only optlen < sizeof(struct bt_codecs) is checked +and codecs->num_codecs is not checked against != 1, +but only <= 1, and the space for the additional struct bt_codec +is not checked. + +Note I don't understand bluetooth and I didn't do any runtime +tests with this! I just found it when debugging a problem +in copy_struct_from_sockptr(). + +I just added this to check the size is as expected: + + BUILD_BUG_ON(struct_size(codecs, codecs, 0) != 1); + BUILD_BUG_ON(struct_size(codecs, codecs, 1) != 8); + +And made sure it still compiles using this: + + make CF=-D__CHECK_ENDIAN__ W=1ce C=1 net/bluetooth/sco.o + +Fixes: 3e643e4efa1e ("Bluetooth: Improve setsockopt() handling of malformed user input") +Cc: Michal Luczaj +Cc: Luiz Augusto von Dentz +Cc: Luiz Augusto von Dentz +Cc: Marcel Holtmann +Cc: David Wei +Cc: linux-bluetooth@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Stefan Metzmacher +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/sco.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index b84587811ef4f..18826d4b9c0bf 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -1045,7 +1045,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, + + codecs = (void *)buffer; + +- if (codecs->num_codecs > 1) { ++ if (codecs->num_codecs != 1 || ++ optlen < struct_size(codecs, codecs, codecs->num_codecs)) { + hci_dev_put(hdev); + err = -EINVAL; + break; +-- +2.53.0 + diff --git a/queue-7.0/bnge-fix-initial-hwrm-sequence.patch b/queue-7.0/bnge-fix-initial-hwrm-sequence.patch new file mode 100644 index 0000000000..05838cc7c6 --- /dev/null +++ b/queue-7.0/bnge-fix-initial-hwrm-sequence.patch @@ -0,0 +1,92 @@ +From c39882f36dbff1f412ada5828b89438be3441110 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 08:04:37 +0530 +Subject: bnge: fix initial HWRM sequence + +From: Vikas Gupta + +[ Upstream commit 70d7c905a07ae8415b955569620bf2bf77423553 ] + +Firmware may not advertize correct resources if backing store is not +enabled before resource information is queried. +Fix the initial sequence of HWRMs so that driver gets capabilities +and resource information correctly. + +Fixes: 3fa9e977a0cd ("bng_en: Initialize default configuration") +Signed-off-by: Vikas Gupta +Reviewed-by: Rahul Gupta +Link: https://patch.msgid.link/20260418023438.1597876-2-vikas.gupta@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/bnge/bnge_core.c | 30 ++++++++++++++----- + 1 file changed, 22 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_core.c b/drivers/net/ethernet/broadcom/bnge/bnge_core.c +index b4090283df0f2..99d7aeeb2ddcd 100644 +--- a/drivers/net/ethernet/broadcom/bnge/bnge_core.c ++++ b/drivers/net/ethernet/broadcom/bnge/bnge_core.c +@@ -73,6 +73,13 @@ static int bnge_func_qcaps(struct bnge_dev *bd) + return rc; + } + ++ return 0; ++} ++ ++static int bnge_func_qrcaps_qcfg(struct bnge_dev *bd) ++{ ++ int rc; ++ + rc = bnge_hwrm_func_resc_qcaps(bd); + if (rc) { + dev_err(bd->dev, "query resc caps failure rc: %d\n", rc); +@@ -132,23 +139,28 @@ static int bnge_fw_register_dev(struct bnge_dev *bd) + + bnge_hwrm_fw_set_time(bd); + +- rc = bnge_hwrm_func_drv_rgtr(bd); ++ /* Get the resources and configuration from firmware */ ++ rc = bnge_func_qcaps(bd); + if (rc) { +- dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc); ++ dev_err(bd->dev, "Failed querying caps rc: %d\n", rc); + return rc; + } + + rc = bnge_alloc_ctx_mem(bd); + if (rc) { + dev_err(bd->dev, "Failed to allocate ctx mem rc: %d\n", rc); +- goto err_func_unrgtr; ++ goto err_free_ctx_mem; + } + +- /* Get the resources and configuration from firmware */ +- rc = bnge_func_qcaps(bd); ++ rc = bnge_hwrm_func_drv_rgtr(bd); + if (rc) { +- dev_err(bd->dev, "Failed initial configuration rc: %d\n", rc); +- rc = -ENODEV; ++ dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc); ++ goto err_free_ctx_mem; ++ } ++ ++ rc = bnge_func_qrcaps_qcfg(bd); ++ if (rc) { ++ dev_err(bd->dev, "Failed querying resources rc: %d\n", rc); + goto err_func_unrgtr; + } + +@@ -157,7 +169,9 @@ static int bnge_fw_register_dev(struct bnge_dev *bd) + return 0; + + err_func_unrgtr: +- bnge_fw_unregister_dev(bd); ++ bnge_hwrm_func_drv_unrgtr(bd); ++err_free_ctx_mem: ++ bnge_free_ctx_mem(bd); + return rc; + } + +-- +2.53.0 + diff --git a/queue-7.0/bnge-remove-unsupported-backing-store-type.patch b/queue-7.0/bnge-remove-unsupported-backing-store-type.patch new file mode 100644 index 0000000000..e17d917d6f --- /dev/null +++ b/queue-7.0/bnge-remove-unsupported-backing-store-type.patch @@ -0,0 +1,61 @@ +From 1e4e708d9dbd05d1eaf5396184da6df652e4bf67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 08:04:38 +0530 +Subject: bnge: remove unsupported backing store type + +From: Vikas Gupta + +[ Upstream commit c6b34add67a5402f53359580956b5c318965a893 ] + +The backing store type, BNGE_CTX_MRAV, is not applicable in Thor Ultra +devices. Remove it from the backing store configuration, as the firmware +will not populate entities in this backing store type, due to which the +driver load fails. + +Fixes: 29c5b358f385 ("bng_en: Add backing store support") +Signed-off-by: Vikas Gupta +Reviewed-by: Dharmender Garg +Link: https://patch.msgid.link/20260418023438.1597876-3-vikas.gupta@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnge/bnge_rmem.c | 16 ---------------- + 1 file changed, 16 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c b/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c +index 94f15e08a88c1..b066ee887a099 100644 +--- a/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c ++++ b/drivers/net/ethernet/broadcom/bnge/bnge_rmem.c +@@ -324,7 +324,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd) + u32 l2_qps, qp1_qps, max_qps; + u32 ena, entries_sp, entries; + u32 srqs, max_srqs, min; +- u32 num_mr, num_ah; + u32 extra_srqs = 0; + u32 extra_qps = 0; + u32 fast_qpmd_qps; +@@ -390,21 +389,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd) + if (!bnge_is_roce_en(bd)) + goto skip_rdma; + +- ctxm = &ctx->ctx_arr[BNGE_CTX_MRAV]; +- /* 128K extra is needed to accommodate static AH context +- * allocation by f/w. +- */ +- num_mr = min_t(u32, ctxm->max_entries / 2, 1024 * 256); +- num_ah = min_t(u32, num_mr, 1024 * 128); +- ctxm->split_entry_cnt = BNGE_CTX_MRAV_AV_SPLIT_ENTRY + 1; +- if (!ctxm->mrav_av_entries || ctxm->mrav_av_entries > num_ah) +- ctxm->mrav_av_entries = num_ah; +- +- rc = bnge_setup_ctxm_pg_tbls(bd, ctxm, num_mr + num_ah, 2); +- if (rc) +- return rc; +- ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV; +- + ctxm = &ctx->ctx_arr[BNGE_CTX_TIM]; + rc = bnge_setup_ctxm_pg_tbls(bd, ctxm, l2_qps + qp1_qps + extra_qps, 1); + if (rc) +-- +2.53.0 + diff --git a/queue-7.0/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch b/queue-7.0/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch new file mode 100644 index 0000000000..9a3b449b57 --- /dev/null +++ b/queue-7.0/bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch @@ -0,0 +1,572 @@ +From 2c39aab887da74a8ba2ee47518b61fd12d7d9fd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:32:07 +0000 +Subject: bonding: 3ad: implement proper RCU rules for port->aggregator + +From: Eric Dumazet + +[ Upstream commit c4f050ce06c56cfb5993268af4a5cb66ed1cd04e ] + +syzbot found a data-race in bond_3ad_get_active_agg_info / +bond_3ad_state_machine_handler [1] which hints at lack of proper +RCU implementation. + +Add __rcu qualifier to port->aggregator, and add proper RCU API. + +[1] + +BUG: KCSAN: data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler + +write to 0xffff88813cf5c4b0 of 8 bytes by task 36 on cpu 0: + ad_port_selection_logic drivers/net/bonding/bond_3ad.c:1659 [inline] + bond_3ad_state_machine_handler+0x9d5/0x2d60 drivers/net/bonding/bond_3ad.c:2569 + process_one_work kernel/workqueue.c:3302 [inline] + process_scheduled_works+0x4f0/0x9c0 kernel/workqueue.c:3385 + worker_thread+0x58a/0x780 kernel/workqueue.c:3466 + kthread+0x22a/0x280 kernel/kthread.c:436 + ret_from_fork+0x146/0x330 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + +read to 0xffff88813cf5c4b0 of 8 bytes by task 22063 on cpu 1: + __bond_3ad_get_active_agg_info drivers/net/bonding/bond_3ad.c:2858 [inline] + bond_3ad_get_active_agg_info+0x8c/0x230 drivers/net/bonding/bond_3ad.c:2881 + bond_fill_info+0xe0f/0x10f0 drivers/net/bonding/bond_netlink.c:853 + rtnl_link_info_fill net/core/rtnetlink.c:906 [inline] + rtnl_link_fill+0x1d7/0x4e0 net/core/rtnetlink.c:927 + rtnl_fill_ifinfo+0xf8e/0x1380 net/core/rtnetlink.c:2168 + rtmsg_ifinfo_build_skb+0x11c/0x1b0 net/core/rtnetlink.c:4453 + rtmsg_ifinfo_event net/core/rtnetlink.c:4486 [inline] + rtmsg_ifinfo+0x6d/0x110 net/core/rtnetlink.c:4495 + __dev_notify_flags+0x76/0x390 net/core/dev.c:9790 + netif_change_flags+0xac/0xd0 net/core/dev.c:9823 + do_setlink+0x905/0x2950 net/core/rtnetlink.c:3180 + rtnl_group_changelink net/core/rtnetlink.c:3813 [inline] + __rtnl_newlink net/core/rtnetlink.c:3981 [inline] + rtnl_newlink+0xf55/0x1400 net/core/rtnetlink.c:4109 + rtnetlink_rcv_msg+0x64b/0x720 net/core/rtnetlink.c:6995 + netlink_rcv_skb+0x123/0x220 net/netlink/af_netlink.c:2550 + rtnetlink_rcv+0x1c/0x30 net/core/rtnetlink.c:7022 + netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline] + netlink_unicast+0x5a8/0x680 net/netlink/af_netlink.c:1344 + netlink_sendmsg+0x5c8/0x6f0 net/netlink/af_netlink.c:1894 + sock_sendmsg_nosec net/socket.c:787 [inline] + __sock_sendmsg net/socket.c:802 [inline] + ____sys_sendmsg+0x563/0x5b0 net/socket.c:2698 + ___sys_sendmsg+0x195/0x1e0 net/socket.c:2752 + __sys_sendmsg net/socket.c:2784 [inline] + __do_sys_sendmsg net/socket.c:2789 [inline] + __se_sys_sendmsg net/socket.c:2787 [inline] + __x64_sys_sendmsg+0xd4/0x160 net/socket.c:2787 + x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x12c/0x3b0 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +value changed: 0x0000000000000000 -> 0xffff88813cf5c400 + +Reported by Kernel Concurrency Sanitizer on: +CPU: 1 UID: 0 PID: 22063 Comm: syz.0.31122 Tainted: G W syzkaller #0 PREEMPT(full) +Tainted: [W]=WARN +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 + +Fixes: 47e91f56008b ("bonding: use RCU protection for 3ad xmit path") +Reported-by: syzbot+9bb2ff2a4ab9e17307e1@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/69f0a82f.050a0220.3aadc4.0000.GAE@google.com/ +Signed-off-by: Eric Dumazet +Cc: Jay Vosburgh +Cc: Andrew Lunn +Link: https://patch.msgid.link/20260428123207.3809211-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_3ad.c | 109 ++++++++++++++----------- + drivers/net/bonding/bond_main.c | 8 +- + drivers/net/bonding/bond_netlink.c | 16 ++-- + drivers/net/bonding/bond_procfs.c | 3 +- + drivers/net/bonding/bond_sysfs_slave.c | 17 ++-- + include/net/bond_3ad.h | 2 +- + 6 files changed, 89 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c +index af7f74cfdc086..f0aa7d2f21717 100644 +--- a/drivers/net/bonding/bond_3ad.c ++++ b/drivers/net/bonding/bond_3ad.c +@@ -1029,6 +1029,7 @@ static void ad_cond_set_peer_notif(struct port *port) + static void ad_mux_machine(struct port *port, bool *update_slave_arr) + { + struct bonding *bond = __get_bond_by_port(port); ++ struct aggregator *aggregator; + mux_states_t last_state; + + /* keep current State Machine state to compare later if it was +@@ -1036,6 +1037,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + */ + last_state = port->sm_mux_state; + ++ aggregator = rcu_dereference(port->aggregator); + if (port->sm_vars & AD_PORT_BEGIN) { + port->sm_mux_state = AD_MUX_DETACHED; + } else { +@@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * cycle to update ready variable, we check + * READY_N and update READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + port->sm_mux_state = AD_MUX_DETACHED; + break; + } +@@ -1070,7 +1072,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * update ready variable, we check READY_N and update + * READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + + /* if the wait_while_timer expired, and the port is + * in READY state, move to ATTACHED state +@@ -1086,7 +1088,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + if ((port->sm_vars & AD_PORT_SELECTED) && + (port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) && + !__check_agg_selection_timer(port)) { +- if (port->aggregator->is_active) { ++ if (aggregator->is_active) { + int state = AD_MUX_COLLECTING_DISTRIBUTING; + + if (!bond->params.coupled_control) +@@ -1102,9 +1104,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * cycle to update ready variable, we check + * READY_N and update READY here + */ +- __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + port->sm_mux_state = AD_MUX_DETACHED; +- } else if (port->aggregator->is_active) { ++ } else if (aggregator->is_active) { + port->actor_oper_port_state |= + LACP_STATE_SYNCHRONIZATION; + } +@@ -1115,7 +1117,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * sure that a collecting distributing + * port in an active aggregator is enabled + */ +- if (port->aggregator->is_active && ++ if (aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; +@@ -1134,7 +1136,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + */ + struct slave *slave = port->slave; + +- if (port->aggregator->is_active && ++ if (aggregator->is_active && + bond_is_slave_rx_disabled(slave)) { + ad_enable_collecting(port); + *update_slave_arr = true; +@@ -1154,8 +1156,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + * sure that a collecting distributing + * port in an active aggregator is enabled + */ +- if (port->aggregator && +- port->aggregator->is_active && ++ if (aggregator && ++ aggregator->is_active && + !__port_is_collecting_distributing(port)) { + __enable_port(port); + *update_slave_arr = true; +@@ -1187,7 +1189,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) + port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); + break; + case AD_MUX_ATTACHED: +- if (port->aggregator->is_active) ++ if (aggregator->is_active) + port->actor_oper_port_state |= + LACP_STATE_SYNCHRONIZATION; + else +@@ -1561,9 +1563,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + bond = __get_bond_by_port(port); + + /* if the port is connected to other aggregator, detach it */ +- if (port->aggregator) { ++ temp_aggregator = rcu_dereference(port->aggregator); ++ if (temp_aggregator) { + /* detach the port from its former aggregator */ +- temp_aggregator = port->aggregator; + for (curr_port = temp_aggregator->lag_ports; curr_port; + last_port = curr_port, + curr_port = curr_port->next_port_in_aggregator) { +@@ -1586,7 +1588,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + /* clear the port's relations to this + * aggregator + */ +- port->aggregator = NULL; ++ RCU_INIT_POINTER(port->aggregator, NULL); + port->next_port_in_aggregator = NULL; + port->actor_port_aggregator_identifier = 0; + +@@ -1609,7 +1611,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + port->slave->bond->dev->name, + port->slave->dev->name, + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ temp_aggregator->aggregator_identifier); + } + } + /* search on all aggregators for a suitable aggregator for this port */ +@@ -1633,15 +1635,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + ) + ) { + /* attach to the founded aggregator */ +- port->aggregator = aggregator; ++ rcu_assign_pointer(port->aggregator, aggregator); + port->actor_port_aggregator_identifier = +- port->aggregator->aggregator_identifier; ++ aggregator->aggregator_identifier; + port->next_port_in_aggregator = aggregator->lag_ports; +- port->aggregator->num_of_ports++; ++ aggregator->num_of_ports++; + aggregator->lag_ports = port; + slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + + /* mark this port as selected */ + port->sm_vars |= AD_PORT_SELECTED; +@@ -1656,39 +1658,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + if (!found) { + if (free_aggregator) { + /* assign port a new aggregator */ +- port->aggregator = free_aggregator; + port->actor_port_aggregator_identifier = +- port->aggregator->aggregator_identifier; ++ free_aggregator->aggregator_identifier; + + /* update the new aggregator's parameters + * if port was responsed from the end-user + */ + if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) + /* if port is full duplex */ +- port->aggregator->is_individual = false; ++ free_aggregator->is_individual = false; + else +- port->aggregator->is_individual = true; ++ free_aggregator->is_individual = true; + +- port->aggregator->actor_admin_aggregator_key = ++ free_aggregator->actor_admin_aggregator_key = + port->actor_admin_port_key; +- port->aggregator->actor_oper_aggregator_key = ++ free_aggregator->actor_oper_aggregator_key = + port->actor_oper_port_key; +- port->aggregator->partner_system = ++ free_aggregator->partner_system = + port->partner_oper.system; +- port->aggregator->partner_system_priority = ++ free_aggregator->partner_system_priority = + port->partner_oper.system_priority; +- port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; +- port->aggregator->receive_state = 1; +- port->aggregator->transmit_state = 1; +- port->aggregator->lag_ports = port; +- port->aggregator->num_of_ports++; ++ free_aggregator->partner_oper_aggregator_key = port->partner_oper.key; ++ free_aggregator->receive_state = 1; ++ free_aggregator->transmit_state = 1; ++ free_aggregator->lag_ports = port; ++ free_aggregator->num_of_ports++; ++ ++ rcu_assign_pointer(port->aggregator, free_aggregator); + + /* mark this port as selected */ + port->sm_vars |= AD_PORT_SELECTED; + + slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ free_aggregator->aggregator_identifier); + } else { + slave_err(bond->dev, port->slave->dev, + "Port %d did not find a suitable aggregator\n", +@@ -1700,13 +1703,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr) + * in all aggregator's ports, else set ready=FALSE in all + * aggregator's ports + */ +- __set_agg_ports_ready(port->aggregator, +- __agg_ports_are_ready(port->aggregator)); ++ aggregator = rcu_dereference(port->aggregator); ++ __set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator)); + +- aggregator = __get_first_agg(port); +- ad_agg_selection_logic(aggregator, update_slave_arr); ++ ad_agg_selection_logic(__get_first_agg(port), update_slave_arr); + +- if (!port->aggregator->is_active) ++ if (!aggregator->is_active) + port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION; + } + +@@ -2075,13 +2077,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond + */ + static void ad_enable_collecting(struct port *port) + { +- if (port->aggregator->is_active) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator->is_active) { + struct slave *slave = port->slave; + + slave_dbg(slave->bond->dev, slave->dev, + "Enabling collecting on port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __enable_collecting_port(port); + } + } +@@ -2093,11 +2097,13 @@ static void ad_enable_collecting(struct port *port) + */ + static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + { +- if (port->aggregator && __agg_has_partner(port->aggregator)) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator && __agg_has_partner(aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling distributing on port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __disable_distributing_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; +@@ -2114,11 +2120,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) + static void ad_enable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator->is_active) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator->is_active) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Enabling port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __enable_port(port); + /* Slave array needs update */ + *update_slave_arr = true; +@@ -2135,11 +2143,13 @@ static void ad_enable_collecting_distributing(struct port *port, + static void ad_disable_collecting_distributing(struct port *port, + bool *update_slave_arr) + { +- if (port->aggregator && __agg_has_partner(port->aggregator)) { ++ struct aggregator *aggregator = rcu_dereference(port->aggregator); ++ ++ if (aggregator && __agg_has_partner(aggregator)) { + slave_dbg(port->slave->bond->dev, port->slave->dev, + "Disabling port %d (LAG %d)\n", + port->actor_port_number, +- port->aggregator->aggregator_identifier); ++ aggregator->aggregator_identifier); + __disable_port(port); + /* Slave array needs an update */ + *update_slave_arr = true; +@@ -2379,7 +2389,7 @@ void bond_3ad_unbind_slave(struct slave *slave) + */ + for (temp_port = aggregator->lag_ports; temp_port; + temp_port = temp_port->next_port_in_aggregator) { +- temp_port->aggregator = new_aggregator; ++ rcu_assign_pointer(temp_port->aggregator, new_aggregator); + temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; + } + +@@ -2848,15 +2858,16 @@ int bond_3ad_set_carrier(struct bonding *bond) + int __bond_3ad_get_active_agg_info(struct bonding *bond, + struct ad_info *ad_info) + { +- struct aggregator *aggregator = NULL; ++ struct aggregator *aggregator = NULL, *tmp; + struct list_head *iter; + struct slave *slave; + struct port *port; + + bond_for_each_slave_rcu(bond, slave, iter) { + port = &(SLAVE_AD_INFO(slave)->port); +- if (port->aggregator && port->aggregator->is_active) { +- aggregator = port->aggregator; ++ tmp = rcu_dereference(port->aggregator); ++ if (tmp && tmp->is_active) { ++ aggregator = tmp; + break; + } + } +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index a5484d11553d1..eb49ce486992d 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -1435,7 +1435,7 @@ static void bond_poll_controller(struct net_device *bond_dev) + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + struct aggregator *agg = +- SLAVE_AD_INFO(slave)->port.aggregator; ++ rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + + if (agg && + agg->aggregator_identifier != ad_info.aggregator_id) +@@ -5181,15 +5181,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) + spin_unlock_bh(&bond->mode_lock); + agg_id = ad_info.aggregator_id; + } ++ rcu_read_lock(); + bond_for_each_slave(bond, slave, iter) { + if (skipslave == slave) + continue; + + all_slaves->arr[all_slaves->count++] = slave; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { +- struct aggregator *agg; ++ const struct aggregator *agg; + +- agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (!agg || agg->aggregator_identifier != agg_id) + continue; + } +@@ -5201,6 +5202,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) + + usable_slaves->arr[usable_slaves->count++] = slave; + } ++ rcu_read_unlock(); + + bond_set_slave_arr(bond, usable_slaves, all_slaves); + return ret; +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index ea1a80e658aeb..c7d3e0602c831 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -66,27 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb, + const struct port *ad_port; + + ad_port = &SLAVE_AD_INFO(slave)->port; +- agg = SLAVE_AD_INFO(slave)->port.aggregator; ++ rcu_read_lock(); ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); + if (agg) { + if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, + agg->aggregator_identifier)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u8(skb, + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, + ad_port->actor_oper_port_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u16(skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, + ad_port->sm_churn_actor_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + ad_port->sm_churn_partner_state)) +- goto nla_put_failure; ++ goto nla_put_failure_rcu; + } ++ rcu_read_unlock(); + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + SLAVE_AD_INFO(slave)->port_priority)) +@@ -95,6 +97,8 @@ static int bond_fill_slave_info(struct sk_buff *skb, + + return 0; + ++nla_put_failure_rcu: ++ rcu_read_unlock(); + nla_put_failure: + return -EMSGSIZE; + } +diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c +index 7edf72ec816ab..0c0146b761772 100644 +--- a/drivers/net/bonding/bond_procfs.c ++++ b/drivers/net/bonding/bond_procfs.c +@@ -187,6 +187,7 @@ static void bond_info_show_master(struct seq_file *seq) + } + } + ++/* Note: runs under rcu_read_lock() */ + static void bond_info_show_slave(struct seq_file *seq, + const struct slave *slave) + { +@@ -213,7 +214,7 @@ static void bond_info_show_slave(struct seq_file *seq, + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + const struct port *port = &SLAVE_AD_INFO(slave)->port; +- const struct aggregator *agg = port->aggregator; ++ const struct aggregator *agg = rcu_dereference(port->aggregator); + + if (agg) { + seq_printf(seq, "Aggregator ID: %d\n", +diff --git a/drivers/net/bonding/bond_sysfs_slave.c b/drivers/net/bonding/bond_sysfs_slave.c +index 36d0e8440b5b9..fc6fe7181789d 100644 +--- a/drivers/net/bonding/bond_sysfs_slave.c ++++ b/drivers/net/bonding/bond_sysfs_slave.c +@@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf) + const struct aggregator *agg; + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { +- agg = SLAVE_AD_INFO(slave)->port.aggregator; +- if (agg) +- return sysfs_emit(buf, "%d\n", +- agg->aggregator_identifier); ++ rcu_read_lock(); ++ agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator); ++ if (agg) { ++ ssize_t res = sysfs_emit(buf, "%d\n", ++ agg->aggregator_identifier); ++ rcu_read_unlock(); ++ return res; ++ } ++ rcu_read_unlock(); + } + + return sysfs_emit(buf, "N/A\n"); +@@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf) + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; +- if (ad_port->aggregator) ++ if (rcu_access_pointer(ad_port->aggregator)) + return sysfs_emit(buf, "%u\n", + ad_port->actor_oper_port_state); + } +@@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf) + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; +- if (ad_port->aggregator) ++ if (rcu_access_pointer(ad_port->aggregator)) + return sysfs_emit(buf, "%u\n", + ad_port->partner_oper.port_state); + } +diff --git a/include/net/bond_3ad.h b/include/net/bond_3ad.h +index c92d4a976246d..05572c19e14b7 100644 +--- a/include/net/bond_3ad.h ++++ b/include/net/bond_3ad.h +@@ -243,7 +243,7 @@ typedef struct port { + churn_state_t sm_churn_actor_state; + churn_state_t sm_churn_partner_state; + struct slave *slave; /* pointer to the bond slave that this port belongs to */ +- struct aggregator *aggregator; /* pointer to an aggregator that this port related to */ ++ struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */ + struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ + u32 transaction_id; /* continuous number for identification of Marker PDU's; */ + struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ +-- +2.53.0 + diff --git a/queue-7.0/bonding-print-churn-state-via-netlink.patch b/queue-7.0/bonding-print-churn-state-via-netlink.patch new file mode 100644 index 0000000000..e838b6e089 --- /dev/null +++ b/queue-7.0/bonding-print-churn-state-via-netlink.patch @@ -0,0 +1,65 @@ +From 9ff8fec88292a21256dc670ac25ab5d1223978a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 02:02:14 +0000 +Subject: bonding: print churn state via netlink + +From: Hangbin Liu + +[ Upstream commit 4916f2e2f3fc9aef289fcd07949301e5c29094c2 ] + +Currently, the churn state is printed only in sysfs. Add netlink support +so users could get the state via netlink. + +Signed-off-by: Hangbin Liu +Link: https://patch.msgid.link/20260224020215.6012-1-liuhangbin@gmail.com +Signed-off-by: Paolo Abeni +Stable-dep-of: c4f050ce06c5 ("bonding: 3ad: implement proper RCU rules for port->aggregator") +Signed-off-by: Sasha Levin +--- + drivers/net/bonding/bond_netlink.c | 9 +++++++++ + include/uapi/linux/if_link.h | 2 ++ + 2 files changed, 11 insertions(+) + +diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c +index 286f11c517f76..ea1a80e658aeb 100644 +--- a/drivers/net/bonding/bond_netlink.c ++++ b/drivers/net/bonding/bond_netlink.c +@@ -29,6 +29,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ + nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_ACTOR_PORT_PRIO */ ++ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE */ ++ nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE */ + 0; + } + +@@ -77,6 +79,13 @@ static int bond_fill_slave_info(struct sk_buff *skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) + goto nla_put_failure; ++ ++ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, ++ ad_port->sm_churn_actor_state)) ++ goto nla_put_failure; ++ if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, ++ ad_port->sm_churn_partner_state)) ++ goto nla_put_failure; + } + + if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, +diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h +index e9b5f79e1ee17..83a96c56b8cad 100644 +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -1568,6 +1568,8 @@ enum { + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + IFLA_BOND_SLAVE_PRIO, + IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, ++ IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, ++ IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, + __IFLA_BOND_SLAVE_MAX, + }; + +-- +2.53.0 + diff --git a/queue-7.0/bpf-allow-instructions-with-arena-source-and-non-are.patch b/queue-7.0/bpf-allow-instructions-with-arena-source-and-non-are.patch new file mode 100644 index 0000000000..00839643e4 --- /dev/null +++ b/queue-7.0/bpf-allow-instructions-with-arena-source-and-non-are.patch @@ -0,0 +1,64 @@ +From 288fed1de2f04fd77cb1aba8ff4c898b9e2a634c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 13:45:38 -0400 +Subject: bpf: Allow instructions with arena source and non-arena dest + registers + +From: Emil Tsalapatis + +[ Upstream commit ac61bffe91d4bda08806e12957c6d64756d042db ] + +The compiler sometimes stores the result of a PTR_TO_ARENA and SCALAR +operation into the scalar register rather than the pointer register. +Relax the verifier to allow operations between a source arena register +and a destination non-arena register, marking the destination's value +as a PTR_TO_ARENA. + +Signed-off-by: Emil Tsalapatis +Acked-by: Song Liu +Fixes: 6082b6c328b5 ("bpf: Recognize addr_space_cast instruction in the verifier.") +Link: https://lore.kernel.org/r/20260412174546.18684-2-emil@etsalapatis.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 5eaba53162d20..b26a599be947f 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -16222,11 +16222,20 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + int err; + + dst_reg = ®s[insn->dst_reg]; +- src_reg = NULL; ++ if (BPF_SRC(insn->code) == BPF_X) ++ src_reg = ®s[insn->src_reg]; ++ else ++ src_reg = NULL; + +- if (dst_reg->type == PTR_TO_ARENA) { ++ /* Case where at least one operand is an arena. */ ++ if (dst_reg->type == PTR_TO_ARENA || (src_reg && src_reg->type == PTR_TO_ARENA)) { + struct bpf_insn_aux_data *aux = cur_aux(env); + ++ if (dst_reg->type != PTR_TO_ARENA) ++ *dst_reg = *src_reg; ++ ++ dst_reg->subreg_def = env->insn_idx + 1; ++ + if (BPF_CLASS(insn->code) == BPF_ALU64) + /* + * 32-bit operations zero upper bits automatically. +@@ -16242,7 +16251,6 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + ptr_reg = dst_reg; + + if (BPF_SRC(insn->code) == BPF_X) { +- src_reg = ®s[insn->src_reg]; + if (src_reg->type != SCALAR_VALUE) { + if (dst_reg->type != SCALAR_VALUE) { + /* Combining two pointers by any ALU op yields +-- +2.53.0 + diff --git a/queue-7.0/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch b/queue-7.0/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch new file mode 100644 index 0000000000..828b0ad8cc --- /dev/null +++ b/queue-7.0/bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch @@ -0,0 +1,84 @@ +From f838ffdc52a9fddd95c6ce77e6a79c89838b9a6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:01:41 +0800 +Subject: bpf: allow UTF-8 literals in bpf_bprintf_prepare() + +From: Yihan Ding + +[ Upstream commit b960430ea8862ef37ce53c8bf74a8dc79d3f2404 ] + +bpf_bprintf_prepare() only needs ASCII parsing for conversion +specifiers. Plain text can safely carry bytes >= 0x80, so allow +UTF-8 literals outside '%' sequences while keeping ASCII control +bytes rejected and format specifiers ASCII-only. + +This keeps existing parsing rules for format directives unchanged, +while allowing helpers such as bpf_trace_printk() to emit UTF-8 +literal text. + +Update test_snprintf_negative() in the same commit so selftests keep +matching the new plain-text vs format-specifier split during bisection. + +Fixes: 48cac3f4a96d ("bpf: Implement formatted output helpers with bstr_printf") +Signed-off-by: Yihan Ding +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416120142.1420646-2-dingyihan@uniontech.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/helpers.c | 17 ++++++++++++++++- + .../testing/selftests/bpf/prog_tests/snprintf.c | 3 ++- + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index 6eb6c82ed2ee1..d51f1b612f1d9 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -845,7 +845,13 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args, + data->buf = buffers->buf; + + for (i = 0; i < fmt_size; i++) { +- if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { ++ unsigned char c = fmt[i]; ++ ++ /* ++ * Permit bytes >= 0x80 in plain text so UTF-8 literals can pass ++ * through unchanged, while still rejecting ASCII control bytes. ++ */ ++ if (isascii(c) && !isprint(c) && !isspace(c)) { + err = -EINVAL; + goto out; + } +@@ -867,6 +873,15 @@ int bpf_bprintf_prepare(const char *fmt, u32 fmt_size, const u64 *raw_args, + * always access fmt[i + 1], in the worst case it will be a 0 + */ + i++; ++ c = fmt[i]; ++ /* ++ * The format parser below only understands ASCII conversion ++ * specifiers and modifiers, so reject non-ASCII after '%'. ++ */ ++ if (!isascii(c)) { ++ err = -EINVAL; ++ goto out; ++ } + + /* skip optional "[0 +-][num]" width formatting field */ + while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || +diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c +index 594441acb7071..4e4a82d54f799 100644 +--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c ++++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c +@@ -114,7 +114,8 @@ static void test_snprintf_negative(void) + ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5"); + ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6"); + ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7"); +- ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character"); ++ ASSERT_OK(load_single_snprintf("\x80"), "non ascii plain text"); ++ ASSERT_ERR(load_single_snprintf("%\x80"), "non ascii in specifier"); + ASSERT_ERR(load_single_snprintf("\x1"), "non printable character"); + ASSERT_ERR(load_single_snprintf("%p%"), "invalid specifier 8"); + ASSERT_ERR(load_single_snprintf("%s%"), "invalid specifier 9"); +-- +2.53.0 + diff --git a/queue-7.0/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch b/queue-7.0/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch new file mode 100644 index 0000000000..ee3d1bdfca --- /dev/null +++ b/queue-7.0/bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch @@ -0,0 +1,63 @@ +From 8889dd89fd2be1c38f5cd5a1b1f13433dfc5bdc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 20:27:02 +0800 +Subject: bpf,arc_jit: Fix missing newline in pr_err messages + +From: haoyu.lu + +[ Upstream commit b6b5e0ebd429d66ce37ae5af649a74ea1f041d92 ] + +Add missing newline to pr_err messages in ARC JIT. + +Fixes: f122668ddcce ("ARC: Add eBPF JIT support") +Signed-off-by: haoyu.lu +Link: https://lore.kernel.org/r/20260324122703.641-1-hechushiguitu666@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arc/net/bpf_jit_arcv2.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch/arc/net/bpf_jit_arcv2.c b/arch/arc/net/bpf_jit_arcv2.c +index 6d989b6d88c69..7ee50aeae5a45 100644 +--- a/arch/arc/net/bpf_jit_arcv2.c ++++ b/arch/arc/net/bpf_jit_arcv2.c +@@ -2427,7 +2427,7 @@ u8 arc_prologue(u8 *buf, u32 usage, u16 frame_size) + + #ifdef ARC_BPF_JIT_DEBUG + if ((usage & BIT(ARC_R_FP)) && frame_size == 0) { +- pr_err("FP is being saved while there is no frame."); ++ pr_err("FP is being saved while there is no frame.\n"); + BUG(); + } + #endif +@@ -2454,7 +2454,7 @@ u8 arc_epilogue(u8 *buf, u32 usage, u16 frame_size) + + #ifdef ARC_BPF_JIT_DEBUG + if ((usage & BIT(ARC_R_FP)) && frame_size == 0) { +- pr_err("FP is being saved while there is no frame."); ++ pr_err("FP is being saved while there is no frame.\n"); + BUG(); + } + #endif +@@ -2868,7 +2868,7 @@ u8 gen_jmp_64(u8 *buf, u8 rd, u8 rs, u8 cond, u32 curr_off, u32 targ_off) + break; + default: + #ifdef ARC_BPF_JIT_DEBUG +- pr_err("64-bit jump condition is not known."); ++ pr_err("64-bit jump condition is not known.\n"); + BUG(); + #endif + } +@@ -2948,7 +2948,7 @@ u8 gen_jmp_32(u8 *buf, u8 rd, u8 rs, u8 cond, u32 curr_off, u32 targ_off) + */ + if (cond >= ARC_CC_LAST) { + #ifdef ARC_BPF_JIT_DEBUG +- pr_err("32-bit jump condition is not known."); ++ pr_err("32-bit jump condition is not known.\n"); + BUG(); + #endif + return 0; +-- +2.53.0 + diff --git a/queue-7.0/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch b/queue-7.0/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch new file mode 100644 index 0000000000..a8053e45a1 --- /dev/null +++ b/queue-7.0/bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch @@ -0,0 +1,96 @@ +From 2e612bbdc72c18b02e39f74782fefa3da37b74e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 07:33:52 -0700 +Subject: bpf, arm32: Reject BPF-to-BPF calls and callbacks in the JIT + +From: Puranjay Mohan + +[ Upstream commit e1d486445af3c392628532229f7ce5f5cf7891b6 ] + +The ARM32 BPF JIT does not support BPF-to-BPF function calls +(BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does +not reject them either. + +When a program with subprograms is loaded (e.g. libxdp's XDP +dispatcher uses __noinline__ subprograms, or any program using +callbacks like bpf_loop or bpf_for_each_map_elem), the verifier +invokes bpf_jit_subprogs() which calls bpf_int_jit_compile() +for each subprogram. + +For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT +silently emits code using the wrong address computation: + + func = __bpf_call_base + imm + +where imm is a pc-relative subprogram offset, producing a bogus +function pointer. + +For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and +loads the immediate as a normal 64-bit value without error. + +In both cases, build_body() reports success and a JIT image is +allocated. ARM32 lacks the jit_data/extra_pass mechanism needed +for the second JIT pass in bpf_jit_subprogs(). On the second +pass, bpf_int_jit_compile() performs a full fresh compilation, +allocating a new JIT binary and overwriting prog->bpf_func. The +first allocation is never freed. bpf_jit_subprogs() then detects +the function pointer changed and aborts with -ENOTSUPP, but the +original JIT binary has already been leaked. Each program +load/unload cycle leaks one JIT binary allocation, as reported +by kmemleak: + + unreferenced object 0xbf0a1000 (size 4096): + backtrace: + bpf_jit_binary_alloc+0x64/0xfc + bpf_int_jit_compile+0x14c/0x348 + bpf_jit_subprogs+0x4fc/0xa60 + +Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL +handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling +through to the existing 'notyet' path. This causes build_body() +to fail before any JIT binary is allocated, so +bpf_int_jit_compile() returns the original program unjitted. +bpf_jit_subprogs() then sees !prog->jited and cleanly falls +back to the interpreter with no leak. + +Acked-by: Daniel Borkmann +Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs") +Reported-by: Jonas Rebmann +Closes: https://lore.kernel.org/bpf/b63e9174-7a3d-4e22-8294-16df07a4af89@pengutronix.de +Tested-by: Jonas Rebmann +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417143353.838911-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm/net/bpf_jit_32.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c +index deeb8f292454b..a900aa9738855 100644 +--- a/arch/arm/net/bpf_jit_32.c ++++ b/arch/arm/net/bpf_jit_32.c +@@ -1852,6 +1852,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + { + u64 val = (u32)imm | (u64)insn[1].imm << 32; + ++ if (insn->src_reg == BPF_PSEUDO_FUNC) ++ goto notyet; ++ + emit_a32_mov_i64(dst, val, ctx); + + return 1; +@@ -2055,6 +2058,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) + const s8 *r5 = bpf2a32[BPF_REG_5]; + const u32 func = (u32)__bpf_call_base + (u32)imm; + ++ if (insn->src_reg == BPF_PSEUDO_CALL) ++ goto notyet; ++ + emit_a32_mov_r64(true, r0, r1, ctx); + emit_a32_mov_r64(true, r1, r2, ctx); + emit_push_r64(r5, ctx); +-- +2.53.0 + diff --git a/queue-7.0/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch b/queue-7.0/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch new file mode 100644 index 0000000000..35eb56466b --- /dev/null +++ b/queue-7.0/bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch @@ -0,0 +1,57 @@ +From ce695b0a875596c562103da8ac566c00352a0e06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:14:03 +0200 +Subject: bpf, arm64: Fix off-by-one in check_imm signed range check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Borkmann + +[ Upstream commit 1dd8be4ec722ce54e4cace59f3a4ba658111b3ec ] + +check_imm(bits, imm) is used in the arm64 BPF JIT to verify that +a branch displacement (in arm64 instruction units) fits into the +signed N-bit immediate field of a B, B.cond or CBZ/CBNZ encoding +before it is handed to the encoder. The macro currently tests for +(imm > 0 && imm >> bits) || (imm < 0 && ~imm >> bits) which admits +values in [-2^N, 2^N) — effectively a signed (N+1)-bit range. A +signed N-bit field only holds [-2^(N-1), 2^(N-1)), so the check +admits one extra bit of range on each side. + +In particular, for check_imm19(), values in [2^18, 2^19) slip past +the check but do not fit into the 19-bit signed imm19 field of +B.cond. aarch64_insn_encode_immediate() then masks the raw value +into the 19-bit field, setting bit 18 (the sign bit) and flipping +a forward branch into a backward one. Same class of issue exists +for check_imm26() and the B/BL encoding. Shift by (bits - 1) +instead of bits so the actual signed N-bit range is enforced. + +Fixes: e54bcde3d69d ("arm64: eBPF JIT compiler") +Signed-off-by: Daniel Borkmann +Reviewed-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260415121403.639619-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index adf84962d579d..4aad9483f8a50 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -35,8 +35,8 @@ + #define ARENA_VM_START (MAX_BPF_JIT_REG + 5) + + #define check_imm(bits, imm) do { \ +- if ((((imm) > 0) && ((imm) >> (bits))) || \ +- (((imm) < 0) && (~(imm) >> (bits)))) { \ ++ if ((((imm) > 0) && ((imm) >> ((bits) - 1))) || \ ++ (((imm) < 0) && (~(imm) >> ((bits) - 1)))) { \ + pr_info("[%2d] imm=%d(0x%x) out of range\n", \ + i, imm, imm); \ + return -EINVAL; \ +-- +2.53.0 + diff --git a/queue-7.0/bpf-arm64-reject-out-of-range-b.cond-targets.patch b/queue-7.0/bpf-arm64-reject-out-of-range-b.cond-targets.patch new file mode 100644 index 0000000000..35454d6184 --- /dev/null +++ b/queue-7.0/bpf-arm64-reject-out-of-range-b.cond-targets.patch @@ -0,0 +1,58 @@ +From 43e38975f33668371e59ea1a8fe7677fa1197bcc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:14:02 +0200 +Subject: bpf, arm64: Reject out-of-range B.cond targets + +From: Daniel Borkmann + +[ Upstream commit 48d83d94930eb4db4c93d2de44838b9455cff626 ] + +aarch64_insn_gen_cond_branch_imm() calls label_imm_common() to +compute a 19-bit signed byte offset for a conditional branch, +but unlike its siblings aarch64_insn_gen_branch_imm() and +aarch64_insn_gen_comp_branch_imm(), it does not check whether +label_imm_common() returned its out-of-range sentinel (range) +before feeding the value to aarch64_insn_encode_immediate(). + +aarch64_insn_encode_immediate() unconditionally masks the value +with the 19-bit field mask, so an offset that was rejected by +label_imm_common() gets silently truncated. With the sentinel +value SZ_1M, the resulting field ends up with bit 18 (the sign +bit of the 19-bit signed displacement) set, and the CPU decodes +it as a ~1 MiB *backward* branch, producing an incorrectly +targeted B.cond instruction. For code-gen locations like the +emit_bpf_tail_call() this function is the only barrier between +an overflowing displacement and a silently miscompiled branch. + +Fix it by returning AARCH64_BREAK_FAULT when the offset is out +of range, so callers see a loud failure instead of a silently +misencoded branch. validate_code() scans the generated image +for any AARCH64_BREAK_FAULT and then lets the JIT fail. + +Fixes: 345e0d35ecdd ("arm64: introduce aarch64_insn_gen_cond_branch_imm()") +Fixes: c94ae4f7c5ec ("arm64: insn: remove BUG_ON from codegen") +Signed-off-by: Daniel Borkmann +Reviewed-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260415121403.639619-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm64/lib/insn.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/lib/insn.c b/arch/arm64/lib/insn.c +index cc5b40917d0dd..37ce75f7f1f08 100644 +--- a/arch/arm64/lib/insn.c ++++ b/arch/arm64/lib/insn.c +@@ -338,6 +338,8 @@ u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr, + long offset; + + offset = label_imm_common(pc, addr, SZ_1M); ++ if (offset >= SZ_1M) ++ return AARCH64_BREAK_FAULT; + + insn = aarch64_insn_get_bcond_value(); + +-- +2.53.0 + diff --git a/queue-7.0/bpf-arm64-remove-redundant-bpf_flush_icache-after-pa.patch b/queue-7.0/bpf-arm64-remove-redundant-bpf_flush_icache-after-pa.patch new file mode 100644 index 0000000000..811c57750d --- /dev/null +++ b/queue-7.0/bpf-arm64-remove-redundant-bpf_flush_icache-after-pa.patch @@ -0,0 +1,76 @@ +From d6c65ccca7b04af57c48b958d15673f64359cebf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:11:08 -0700 +Subject: bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator + finalize + +From: Puranjay Mohan + +[ Upstream commit 42f18ae53011826cfd3c84d041817e7f07bc645b ] + +bpf_flush_icache() calls flush_icache_range() to clean the data cache +and invalidate the instruction cache for the JITed code region. However, +since commit 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory +management"), this flush is redundant. + +bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX +region via bpf_arch_text_copy() -> aarch64_insn_copy() -> __text_poke(), +and __text_poke() already calls flush_icache_range() on the written +range. The subsequent bpf_flush_icache() repeats the same cache +maintenance on an overlapping range, including an unnecessary second +synchronous IPI to all CPUs via kick_all_cpus_sync(). + +Remove the redundant bpf_flush_icache() call and its now-unused +definition. + +Fixes: 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management") +Acked-by: Song Liu +Signed-off-by: Puranjay Mohan +Acked-by: Breno Leitao +Link: https://lore.kernel.org/r/20260413191111.3426023-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 4aad9483f8a50..524b67c0867e7 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -18,7 +18,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -1961,11 +1960,6 @@ static int validate_ctx(struct jit_ctx *ctx) + return 0; + } + +-static inline void bpf_flush_icache(void *start, void *end) +-{ +- flush_icache_range((unsigned long)start, (unsigned long)end); +-} +- + static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size) + { + int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3; +@@ -2204,12 +2198,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + prog = orig_prog; + goto out_off; + } +- /* +- * The instructions have now been copied to the ROX region from +- * where they will execute. Now the data cache has to be cleaned to +- * the PoU and the I-cache has to be invalidated for the VAs. +- */ +- bpf_flush_icache(ro_header, ctx.ro_image + ctx.idx); + } else { + jit_data->ctx = ctx; + jit_data->ro_image = ro_image_ptr; +-- +2.53.0 + diff --git a/queue-7.0/bpf-do-not-allow-deleting-local-storage-in-nmi.patch b/queue-7.0/bpf-do-not-allow-deleting-local-storage-in-nmi.patch new file mode 100644 index 0000000000..6c19ea730d --- /dev/null +++ b/queue-7.0/bpf-do-not-allow-deleting-local-storage-in-nmi.patch @@ -0,0 +1,55 @@ +From 9992fb4725d3f6c43ec1858af09f0667ebe71bff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:57:16 -0700 +Subject: bpf: Do not allow deleting local storage in NMI + +From: Amery Hung + +[ Upstream commit 350de5b8a9befaa2a68861c51f671d4f5f751ca5 ] + +Currently, local storage may deadlock when deferring freeing selem or +local storage through kfree_rcu(), call_rcu() or call_rcu_tasks_trace() +in NMI or reentrant. Since deleting selem in NMI is an unlikely use +case, partially mitigate it by returning error when calling from +bpf_xxx_storage_delete() helpers in NMI. Note that, it is still possible +to deadlock through reentrant. A full mitigation requires returning +error when irqs_disabled() is true, which, however is too heavy-handed +for bpf_xxx_storage_delete(). + +The long-term solution requires _nolock versions of call_rcu. Another +possible solution is to defer the free through irq_work [0], but it +would grow the size of selem, which is non-ideal. + +The check is only needed in bpf_selem_unlink(), which is used by helpers +and syscalls. bpf_selem_unlink_nofail() is fine as it is called during +map and owner tear down that never run in NMI or reentrant. + +[0] https://lore.kernel.org/bpf/20260205190233.912-1-alexei.starovoitov@gmail.com/ + +Fixes: a10787e6d58c ("bpf: Enable task local storage for tracing programs") +Signed-off-by: Amery Hung +Signed-off-by: Martin KaFai Lau +Acked-by: Kumar Kartikeya Dwivedi +Link: https://patch.msgid.link/20260319025716.2361065-1-ameryhung@gmail.com +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_local_storage.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c +index 9c96a4477f81a..4c6079d2cf28d 100644 +--- a/kernel/bpf/bpf_local_storage.c ++++ b/kernel/bpf/bpf_local_storage.c +@@ -393,6 +393,9 @@ int bpf_selem_unlink(struct bpf_local_storage_elem *selem) + unsigned long flags; + int err; + ++ if (in_nmi()) ++ return -EOPNOTSUPP; ++ + if (unlikely(!selem_linked_to_storage_lockless(selem))) + /* selem has already been unlinked from sk */ + return 0; +-- +2.53.0 + diff --git a/queue-7.0/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch b/queue-7.0/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch new file mode 100644 index 0000000000..7170a28015 --- /dev/null +++ b/queue-7.0/bpf-drop-task_to_inode-and-inet_conn_established-fro.patch @@ -0,0 +1,52 @@ +From fbb9b4f2e5bbe9d189564e304a1e13c48a061102 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 20:23:33 +0800 +Subject: bpf: Drop task_to_inode and inet_conn_established from lsm sleepable + hooks + +From: Jiayuan Chen + +[ Upstream commit beaf0e96b1da74549a6cabd040f9667d83b2e97e ] + +bpf_lsm_task_to_inode() is called under rcu_read_lock() and +bpf_lsm_inet_conn_established() is called from softirq context, so +neither hook can be used by sleepable LSM programs. + +Fixes: 423f16108c9d8 ("bpf: Augment the set of sleepable LSM hooks") +Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/3ab69731-24d1-431a-a351-452aafaaf2a5@std.uestc.edu.cn/T/#u +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260407122334.344072-1-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/bpf_lsm.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c +index 0c4a0c8e6f703..0aa9378fae4f7 100644 +--- a/kernel/bpf/bpf_lsm.c ++++ b/kernel/bpf/bpf_lsm.c +@@ -359,8 +359,6 @@ BTF_ID(func, bpf_lsm_sb_umount) + BTF_ID(func, bpf_lsm_settime) + + #ifdef CONFIG_SECURITY_NETWORK +-BTF_ID(func, bpf_lsm_inet_conn_established) +- + BTF_ID(func, bpf_lsm_socket_accept) + BTF_ID(func, bpf_lsm_socket_bind) + BTF_ID(func, bpf_lsm_socket_connect) +@@ -381,7 +379,6 @@ BTF_ID(func, bpf_lsm_syslog) + BTF_ID(func, bpf_lsm_task_alloc) + BTF_ID(func, bpf_lsm_task_prctl) + BTF_ID(func, bpf_lsm_task_setscheduler) +-BTF_ID(func, bpf_lsm_task_to_inode) + BTF_ID(func, bpf_lsm_userns_create) + BTF_SET_END(sleepable_lsm_hooks) + +-- +2.53.0 + diff --git a/queue-7.0/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch b/queue-7.0/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch new file mode 100644 index 0000000000..eae342cf4c --- /dev/null +++ b/queue-7.0/bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch @@ -0,0 +1,77 @@ +From 687595281a837f575100a196e34ff975b811e48e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 01:26:50 +0200 +Subject: bpf: Enforce regsafe base id consistency for BPF_ADD_CONST scalars + +From: Daniel Borkmann + +[ Upstream commit 2f2ec8e7730e21fc9bd49e0de9cdd58213ea24d0 ] + +When regsafe() compares two scalar registers that both carry +BPF_ADD_CONST, check_scalar_ids() maps their full compound id +(aka base | BPF_ADD_CONST flag) as one idmap entry. However, +it never verifies that the underlying base ids, that is, with +the flag stripped are consistent with existing idmap mappings. + +This allows construction of two verifier states where the old +state has R3 = R2 + 10 (both sharing base id A) while the current +state has R3 = R4 + 10 (base id C, unrelated to R2). The idmap +creates two independent entries: A->B (for R2) and A|flag->C|flag +(for R3), without catching that A->C conflicts with A->B. State +pruning then incorrectly succeeds. + +Fix this by additionally verifying base ID mapping consistency +whenever BPF_ADD_CONST is set: after mapping the compound ids, +also invoke check_ids() on the base IDs (flag bits stripped). +This ensures that if A was already mapped to B from comparing +the source register, any ADD_CONST derivative must also derive +from B, not an unrelated C. + +Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260410232651.559778-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index bf5e146692e0a..5eaba53162d20 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -19674,6 +19674,13 @@ static bool check_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + * and r7.id=0 (both independent), without temp IDs both would map old_id=X + * to cur_id=0 and pass. With temp IDs: r6 maps X->temp1, r7 tries to map + * X->temp2, but X is already mapped to temp1, so the check fails correctly. ++ * ++ * When old_id has BPF_ADD_CONST set, the compound id (base | flag) and the ++ * base id (flag stripped) must both map consistently. Example: old has ++ * r2.id=A, r3.id=A|flag (r3 = r2 + delta), cur has r2.id=B, r3.id=C|flag ++ * (r3 derived from unrelated r4). Without the base check, idmap gets two ++ * independent entries A->B and A|flag->C|flag, missing that A->C conflicts ++ * with A->B. The base ID cross-check catches this. + */ + static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + { +@@ -19682,7 +19689,15 @@ static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) + + cur_id = cur_id ? cur_id : ++idmap->tmp_id_gen; + +- return check_ids(old_id, cur_id, idmap); ++ if (!check_ids(old_id, cur_id, idmap)) ++ return false; ++ if (old_id & BPF_ADD_CONST) { ++ old_id &= ~BPF_ADD_CONST; ++ cur_id &= ~BPF_ADD_CONST; ++ if (!check_ids(old_id, cur_id, idmap)) ++ return false; ++ } ++ return true; + } + + static void clean_func_state(struct bpf_verifier_env *env, +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-abuse-of-kprobe_write_ctx-via-freplace.patch b/queue-7.0/bpf-fix-abuse-of-kprobe_write_ctx-via-freplace.patch new file mode 100644 index 0000000000..9f9ce3145e --- /dev/null +++ b/queue-7.0/bpf-fix-abuse-of-kprobe_write_ctx-via-freplace.patch @@ -0,0 +1,82 @@ +From 3114a21aeb42a7c10f8ca9170b948d65b793c8dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 22:53:52 +0800 +Subject: bpf: Fix abuse of kprobe_write_ctx via freplace + +From: Leon Hwang + +[ Upstream commit 611fe4b79af72d00d80f2223354284447daafae9 ] + +uprobe programs are allowed to modify struct pt_regs. + +Since the actual program type of uprobe is KPROBE, it can be abused to +modify struct pt_regs via kprobe+freplace when the kprobe attaches to +kernel functions. + +For example, + +SEC("?kprobe") +int kprobe(struct pt_regs *regs) +{ + return 0; +} + +SEC("?freplace") +int freplace_kprobe(struct pt_regs *regs) +{ + regs->di = 0; + return 0; +} + +freplace_kprobe prog will attach to kprobe prog. +kprobe prog will attach to a kernel function. + +Without this patch, when the kernel function runs, its first arg will +always be set as 0 via the freplace_kprobe prog. + +To fix the abuse of kprobe_write_ctx=true via kprobe+freplace, disallow +attaching freplace programs on kprobe programs with different +kprobe_write_ctx values. + +Fixes: 7384893d970e ("bpf: Allow uprobe program to change context registers") +Acked-by: Jiri Olsa +Acked-by: Song Liu +Signed-off-by: Leon Hwang +Link: https://lore.kernel.org/r/20260331145353.87606-2-leon.hwang@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index 700938782bed2..ed595159f1c53 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -3754,6 +3754,23 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog, + tr = prog->aux->dst_trampoline; + tgt_prog = prog->aux->dst_prog; + } ++ /* ++ * It is to prevent modifying struct pt_regs via kprobe_write_ctx=true ++ * freplace prog. Without this check, kprobe_write_ctx=true freplace ++ * prog is allowed to attach to kprobe_write_ctx=false kprobe prog, and ++ * then modify the registers of the kprobe prog's target kernel ++ * function. ++ * ++ * This also blocks the combination of uprobe+freplace, because it is ++ * unable to recognize the use of the tgt_prog as an uprobe or a kprobe ++ * by tgt_prog itself. At attach time, uprobe/kprobe is recognized by ++ * the target perf event flags in __perf_event_set_bpf_prog(). ++ */ ++ if (prog->type == BPF_PROG_TYPE_EXT && ++ prog->aux->kprobe_write_ctx != tgt_prog->aux->kprobe_write_ctx) { ++ err = -EINVAL; ++ goto out_unlock; ++ } + + err = bpf_link_prime(&link->link.link, &link_primer); + if (err) +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch b/queue-7.0/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch new file mode 100644 index 0000000000..e6e8e6cab2 --- /dev/null +++ b/queue-7.0/bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch @@ -0,0 +1,47 @@ +From e7fdd6c8b990357e59a4cd3c26cc821febb65bd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 21:29:50 +0800 +Subject: bpf: fix end-of-list detection in cgroup_storage_get_next_key() + +From: Weiming Shi + +[ Upstream commit 5828b9e5b272ecff7cf5d345128d3de7324117f7 ] + +list_next_entry() never returns NULL -- when the current element is the +last entry it wraps to the list head via container_of(). The subsequent +NULL check is therefore dead code and get_next_key() never returns +-ENOENT for the last element, instead reading storage->key from a bogus +pointer that aliases internal map fields and copying the result to +userspace. + +Replace it with list_entry_is_head() so the function correctly returns +-ENOENT when there are no more entries. + +Fixes: de9cbbaadba5 ("bpf: introduce cgroup storage maps") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Sun Jian +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260403132951.43533-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/local_storage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c +index 8fca0c64f7b1c..23267213a17fb 100644 +--- a/kernel/bpf/local_storage.c ++++ b/kernel/bpf/local_storage.c +@@ -270,7 +270,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, + goto enoent; + + storage = list_next_entry(storage, list_map); +- if (!storage) ++ if (list_entry_is_head(storage, &map->list, list_map)) + goto enoent; + } else { + storage = list_first_entry(&map->list, +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch b/queue-7.0/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch new file mode 100644 index 0000000000..902f955440 --- /dev/null +++ b/queue-7.0/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch @@ -0,0 +1,103 @@ +From 4937b68c9c890e8ec30d7b3e949a1138f3c507e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 21:12:40 +0200 +Subject: bpf: Fix ld_{abs,ind} failure path analysis in subprogs + +From: Daniel Borkmann + +[ Upstream commit ee861486e377edc55361c08dcbceab3f6b6577bd ] + +Usage of ld_{abs,ind} instructions got extended into subprogs some time +ago via commit 09b28d76eac4 ("bpf: Add abnormal return checks."). These +are only allowed in subprograms when the latter are BTF annotated and +have scalar return types. + +The code generator in bpf_gen_ld_abs() has an abnormal exit path (r0=0 + +exit) from legacy cBPF times. While the enforcement is on scalar return +types, the verifier must also simulate the path of abnormal exit if the +packet data load via ld_{abs,ind} failed. + +This is currently not the case. Fix it by having the verifier simulate +both success and failure paths, and extend it in similar ways as we do +for tail calls. The success path (r0=unknown, continue to next insn) is +pushed onto stack for later validation and the r0=0 and return to the +caller is done on the fall-through side. + +Fixes: 09b28d76eac4 ("bpf: Add abnormal return checks.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 33 +++++++++++++++++++++++++++++++-- + 1 file changed, 31 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 2949cdc7565f7..71c078d18683a 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -17943,6 +17943,23 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) + mark_reg_unknown(env, regs, BPF_REG_0); + /* ld_abs load up to 32-bit skb data. */ + regs[BPF_REG_0].subreg_def = env->insn_idx + 1; ++ /* ++ * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0 ++ * which must be explored by the verifier when in a subprog. ++ */ ++ if (env->cur_state->curframe) { ++ struct bpf_verifier_state *branch; ++ ++ mark_reg_scratched(env, BPF_REG_0); ++ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); ++ if (IS_ERR(branch)) ++ return PTR_ERR(branch); ++ mark_reg_known_zero(env, regs, BPF_REG_0); ++ err = prepare_func_exit(env, &env->insn_idx); ++ if (err) ++ return err; ++ env->insn_idx--; ++ } + return 0; + } + +@@ -18815,7 +18832,12 @@ static int visit_gotox_insn(int t, struct bpf_verifier_env *env) + return keep_exploring ? KEEP_EXPLORING : DONE_EXPLORING; + } + +-static int visit_tailcall_insn(struct bpf_verifier_env *env, int t) ++/* ++ * Instructions that can abnormally return from a subprog (tail_call ++ * upon success, ld_{abs,ind} upon load failure) have a hidden exit ++ * that the verifier must account for. ++ */ ++static int visit_abnormal_return_insn(struct bpf_verifier_env *env, int t) + { + static struct bpf_subprog_info *subprog; + struct bpf_iarray *jt; +@@ -18850,6 +18872,13 @@ static int visit_insn(int t, struct bpf_verifier_env *env) + /* All non-branch instructions have a single fall-through edge. */ + if (BPF_CLASS(insn->code) != BPF_JMP && + BPF_CLASS(insn->code) != BPF_JMP32) { ++ if (BPF_CLASS(insn->code) == BPF_LD && ++ (BPF_MODE(insn->code) == BPF_ABS || ++ BPF_MODE(insn->code) == BPF_IND)) { ++ ret = visit_abnormal_return_insn(env, t); ++ if (ret) ++ return ret; ++ } + insn_sz = bpf_is_ldimm64(insn) ? 2 : 1; + return push_insn(t, t + insn_sz, FALLTHROUGH, env); + } +@@ -18895,7 +18924,7 @@ static int visit_insn(int t, struct bpf_verifier_env *env) + if (bpf_helper_changes_pkt_data(insn->imm)) + mark_subprog_changes_pkt_data(env, t); + if (insn->imm == BPF_FUNC_tail_call) { +- ret = visit_tailcall_insn(env, t); ++ ret = visit_abnormal_return_insn(env, t); + if (ret) + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-linked-reg-delta-tracking-when-src_reg-dst_r.patch b/queue-7.0/bpf-fix-linked-reg-delta-tracking-when-src_reg-dst_r.patch new file mode 100644 index 0000000000..16e8c845b1 --- /dev/null +++ b/queue-7.0/bpf-fix-linked-reg-delta-tracking-when-src_reg-dst_r.patch @@ -0,0 +1,46 @@ +From 72d67974fc123e97cc2e50df37afc3e0e505305a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 21:24:18 +0200 +Subject: bpf: Fix linked reg delta tracking when src_reg == dst_reg + +From: Daniel Borkmann + +[ Upstream commit d7f14173c0d5866c3cae759dee560ad1bed10d2e ] + +Consider the case of rX += rX where src_reg and dst_reg are pointers to +the same bpf_reg_state in adjust_reg_min_max_vals(). The latter first +modifies the dst_reg in-place, and later in the delta tracking, the +subsequent is_reg_const(src_reg)/reg_const_value(src_reg) reads the +post-{add,sub} value instead of the original source. + +This is problematic since it sets an incorrect delta, which sync_linked_regs() +then propagates to linked registers, thus creating a verifier-vs-runtime +mismatch. Fix it by just skipping this corner case. + +Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260407192421.508817-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 8d00bd0f8b79d..0507df13fe2d6 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -16325,7 +16325,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, + */ + if (env->bpf_capable && + (BPF_OP(insn->code) == BPF_ADD || BPF_OP(insn->code) == BPF_SUB) && +- dst_reg->id && is_reg_const(src_reg, alu32)) { ++ dst_reg->id && is_reg_const(src_reg, alu32) && ++ !(BPF_SRC(insn->code) == BPF_X && insn->src_reg == insn->dst_reg)) { + u64 val = reg_const_value(src_reg, alu32); + s32 off; + +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch b/queue-7.0/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch new file mode 100644 index 0000000000..462f4f4831 --- /dev/null +++ b/queue-7.0/bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch @@ -0,0 +1,148 @@ +From 8b264a8bcd9d20fabf1fae74a1ec7a838bddaaec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:35 -0700 +Subject: bpf: fix mm lifecycle in open-coded task_vma iterator + +From: Puranjay Mohan + +[ Upstream commit d8e27d2d22b6e2df3a0125b8c08e9aace38c954c ] + +The open-coded task_vma iterator reads task->mm locklessly and acquires +mmap_read_trylock() but never calls mmget(). If the task exits +concurrently, the mm_struct can be freed as it is not +SLAB_TYPESAFE_BY_RCU, resulting in a use-after-free. + +Safely read task->mm with a trylock on alloc_lock and acquire an mm +reference. Drop the reference via bpf_iter_mmput_async() in _destroy() +and error paths. bpf_iter_mmput_async() is a local wrapper around +mmput_async() with a fallback to mmput() on !CONFIG_MMU. + +Reject irqs-disabled contexts (including NMI) up front. Operations used +by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) +take spinlocks with IRQs disabled (pool->lock, pi_lock). Running from +NMI or from a tracepoint that fires with those locks held could +deadlock. + +A trylock on alloc_lock is used instead of the blocking task_lock() +(get_task_mm) to avoid a deadlock when a softirq BPF program iterates +a task that already holds its alloc_lock on the same CPU. + +Fixes: 4ac454682158 ("bpf: Introduce task_vma open-coded iterator kfuncs") +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260408154539.3832150-2-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 54 +++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 51 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index 98d9b4c0daff3..c1f5fbe9dc2f3 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include "mmap_unlock_work.h" + + static const char * const iter_task_type_names[] = { +@@ -794,6 +795,15 @@ const struct bpf_func_proto bpf_find_vma_proto = { + .arg5_type = ARG_ANYTHING, + }; + ++static inline void bpf_iter_mmput_async(struct mm_struct *mm) ++{ ++#ifdef CONFIG_MMU ++ mmput_async(mm); ++#else ++ mmput(mm); ++#endif ++} ++ + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +@@ -825,6 +835,24 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + BUILD_BUG_ON(sizeof(struct bpf_iter_task_vma_kern) != sizeof(struct bpf_iter_task_vma)); + BUILD_BUG_ON(__alignof__(struct bpf_iter_task_vma_kern) != __alignof__(struct bpf_iter_task_vma)); + ++ /* bpf_iter_mmput_async() needs mmput_async() which requires CONFIG_MMU */ ++ if (!IS_ENABLED(CONFIG_MMU)) { ++ kit->data = NULL; ++ return -EOPNOTSUPP; ++ } ++ ++ /* ++ * Reject irqs-disabled contexts including NMI. Operations used ++ * by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) ++ * can take spinlocks with IRQs disabled (pi_lock, pool->lock). ++ * Running from NMI or from a tracepoint that fires with those ++ * locks held could deadlock. ++ */ ++ if (irqs_disabled()) { ++ kit->data = NULL; ++ return -EBUSY; ++ } ++ + /* is_iter_reg_valid_uninit guarantees that kit hasn't been initialized + * before, so non-NULL kit->data doesn't point to previously + * bpf_mem_alloc'd bpf_iter_task_vma_kern_data +@@ -834,7 +862,25 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + return -ENOMEM; + + kit->data->task = get_task_struct(task); ++ /* ++ * Safely read task->mm and acquire an mm reference. ++ * ++ * Cannot use get_task_mm() because its task_lock() is a ++ * blocking spin_lock that would deadlock if the target task ++ * already holds alloc_lock on this CPU (e.g. a softirq BPF ++ * program iterating a task interrupted while holding its ++ * alloc_lock). ++ */ ++ if (!spin_trylock(&task->alloc_lock)) { ++ err = -EBUSY; ++ goto err_cleanup_iter; ++ } + kit->data->mm = task->mm; ++ if (kit->data->mm && !(task->flags & PF_KTHREAD)) ++ mmget(kit->data->mm); ++ else ++ kit->data->mm = NULL; ++ spin_unlock(&task->alloc_lock); + if (!kit->data->mm) { + err = -ENOENT; + goto err_cleanup_iter; +@@ -844,15 +890,16 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work); + if (irq_work_busy || !mmap_read_trylock(kit->data->mm)) { + err = -EBUSY; +- goto err_cleanup_iter; ++ goto err_cleanup_mmget; + } + + vma_iter_init(&kit->data->vmi, kit->data->mm, addr); + return 0; + ++err_cleanup_mmget: ++ bpf_iter_mmput_async(kit->data->mm); + err_cleanup_iter: +- if (kit->data->task) +- put_task_struct(kit->data->task); ++ put_task_struct(kit->data->task); + bpf_mem_free(&bpf_global_ma, kit->data); + /* NULL kit->data signals failed bpf_iter_task_vma initialization */ + kit->data = NULL; +@@ -875,6 +922,7 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + if (kit->data) { + bpf_mmap_unlock_mm(kit->data->work, kit->data->mm); + put_task_struct(kit->data->task); ++ bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); + } + } +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch b/queue-7.0/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch new file mode 100644 index 0000000000..3eae40ef44 --- /dev/null +++ b/queue-7.0/bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch @@ -0,0 +1,56 @@ +From d215d488d92bcb7ac9032399c37cdd3c0e74169b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 11:08:07 -0700 +Subject: bpf: Fix NULL deref in map_kptr_match_type for scalar regs + +From: Mykyta Yatsenko + +[ Upstream commit 4d0a375887ab4d49e4da1ff10f9606cab8f7c3ad ] + +Commit ab6c637ad027 ("bpf: Fix a bpf_kptr_xchg() issue with local +kptr") refactored map_kptr_match_type() to branch on btf_is_kernel() +before checking base_type(). A scalar register stored into a kptr +slot has no btf, so the btf_is_kernel(reg->btf) call dereferences +NULL. + +Move the base_type() != PTR_TO_BTF_ID guard before any reg->btf +access. + +Fixes: ab6c637ad027 ("bpf: Fix a bpf_kptr_xchg() issue with local kptr") +Reported-by: Hiker Cl +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221372 +Signed-off-by: Mykyta Yatsenko +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260416-kptr_crash-v1-1-5589356584b4@meta.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index b26a599be947f..77ddd452b8035 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -6000,6 +6000,9 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + int perm_flags; + const char *reg_name = ""; + ++ if (base_type(reg->type) != PTR_TO_BTF_ID) ++ goto bad_type; ++ + if (btf_is_kernel(reg->btf)) { + perm_flags = PTR_MAYBE_NULL | PTR_TRUSTED | MEM_RCU; + +@@ -6012,7 +6015,7 @@ static int map_kptr_match_type(struct bpf_verifier_env *env, + perm_flags |= MEM_PERCPU; + } + +- if (base_type(reg->type) != PTR_TO_BTF_ID || (type_flag(reg->type) & ~perm_flags)) ++ if (type_flag(reg->type) & ~perm_flags) + goto bad_type; + + /* We need to verify reg->type and reg->btf, before accessing reg->btf */ +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-oob-in-pcpu_init_value.patch b/queue-7.0/bpf-fix-oob-in-pcpu_init_value.patch new file mode 100644 index 0000000000..c706dfc7e3 --- /dev/null +++ b/queue-7.0/bpf-fix-oob-in-pcpu_init_value.patch @@ -0,0 +1,54 @@ +From e44c4261db13a81bb159dd281053572b8e36a0f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 15:42:35 +0800 +Subject: bpf: Fix OOB in pcpu_init_value + +From: Lang Xu + +[ Upstream commit 576afddfee8d1108ee299bf10f581593540d1a36 ] + +An out-of-bounds read occurs when copying element from a +BPF_MAP_TYPE_CGROUP_STORAGE map to another pcpu map with the +same value_size that is not rounded up to 8 bytes. + +The issue happens when: +1. A CGROUP_STORAGE map is created with value_size not aligned to + 8 bytes (e.g., 4 bytes) +2. A pcpu map is created with the same value_size (e.g., 4 bytes) +3. Update element in 2 with data in 1 + +pcpu_init_value assumes that all sources are rounded up to 8 bytes, +and invokes copy_map_value_long to make a data copy, However, the +assumption doesn't stand since there are some cases where the source +may not be rounded up to 8 bytes, e.g., CGROUP_STORAGE, skb->data. +the verifier verifies exactly the size that the source claims, not +the size rounded up to 8 bytes by kernel, an OOB happens when the +source has only 4 bytes while the copy size(4) is rounded up to 8. + +Fixes: d3bec0138bfb ("bpf: Zero-fill re-used per-cpu map element") +Reported-by: Kaiyan Mei +Closes: https://lore.kernel.org/all/14e6c70c.6c121.19c0399d948.Coremail.kaiyanm@hust.edu.cn/ +Link: https://lore.kernel.org/r/420FEEDDC768A4BE+20260402074236.2187154-1-xulang@uniontech.com +Signed-off-by: Lang Xu +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/hashtab.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c +index f7ac1ec7be8bf..3dd9b4924ae4f 100644 +--- a/kernel/bpf/hashtab.c ++++ b/kernel/bpf/hashtab.c +@@ -1056,7 +1056,7 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr, + + for_each_possible_cpu(cpu) { + if (cpu == current_cpu) +- copy_map_value_long(&htab->map, per_cpu_ptr(pptr, cpu), value); ++ copy_map_value(&htab->map, per_cpu_ptr(pptr, cpu), value); + else /* Since elem is preallocated, we cannot touch special fields */ + zero_map_value(&htab->map, per_cpu_ptr(pptr, cpu)); + } +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch b/queue-7.0/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch new file mode 100644 index 0000000000..7fd2c92698 --- /dev/null +++ b/queue-7.0/bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch @@ -0,0 +1,46 @@ +From 79a957a0b11c91d9174e7eb1fdba2e786308424e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:27:19 +0200 +Subject: bpf: Fix precedence bug in convert_bpf_ld_abs alignment check + +From: Daniel Borkmann + +[ Upstream commit e5f635edd393aeaa7cad9e42831d397e6e2e1eed ] + +Fix an operator precedence issue in convert_bpf_ld_abs() where the +expression offset + ip_align % size evaluates as offset + (ip_align % size) +due to % having higher precedence than +. That latter evaluation does +not make any sense. The intended check is (offset + ip_align) % size == 0 +to verify that the packet load offset is properly aligned for direct +access. + +With NET_IP_ALIGN == 2, the bug causes the inline fast-path for direct +packet loads to almost never be taken on !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS +platforms. This forces nearly all cBPF BPF_LD_ABS packet loads through +the bpf_skb_load_helper slow path on the affected archs. + +Fixes: e0cea7ce988c ("bpf: implement ld_abs/ld_ind in native bpf") +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260416122719.661033-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 90ae4f314b6c3..d4fe9e4a45d11 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -508,7 +508,7 @@ static bool convert_bpf_ld_abs(struct sock_filter *fp, struct bpf_insn **insnp) + ((unaligned_ok && offset >= 0) || + (!unaligned_ok && offset >= 0 && + offset + ip_align >= 0 && +- offset + ip_align % size == 0))) { ++ (offset + ip_align) % size == 0))) { + bool ldx_off_ok = offset <= S16_MAX; + + *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_H); +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch b/queue-7.0/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch new file mode 100644 index 0000000000..d9a53b711c --- /dev/null +++ b/queue-7.0/bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch @@ -0,0 +1,62 @@ +From e56d11fc76a4cfade26a0db011ed3fef52a2c2d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 10:38:23 +0000 +Subject: bpf: Fix RCU stall in bpf_fd_array_map_clear() + +From: Sechang Lim + +[ Upstream commit 4406942e65ca128c56c67443832988873c21d2e9 ] + +Add a missing cond_resched() in bpf_fd_array_map_clear() loop. + +For PROG_ARRAY maps with many entries this loop calls +prog_array_map_poke_run() per entry which can be expensive, and +without yielding this can cause RCU stalls under load: + + rcu: Stack dump where RCU GP kthread last ran: + CPU: 0 UID: 0 PID: 30932 Comm: kworker/0:2 Not tainted 6.14.0-13195-g967e8def1100 #2 PREEMPT(undef) + Workqueue: events prog_array_map_clear_deferred + RIP: 0010:write_comp_data+0x38/0x90 kernel/kcov.c:246 + Call Trace: + + prog_array_map_poke_run+0x77/0x380 kernel/bpf/arraymap.c:1096 + __fd_array_map_delete_elem+0x197/0x310 kernel/bpf/arraymap.c:925 + bpf_fd_array_map_clear kernel/bpf/arraymap.c:1000 [inline] + prog_array_map_clear_deferred+0x119/0x1b0 kernel/bpf/arraymap.c:1141 + process_one_work+0x898/0x19d0 kernel/workqueue.c:3238 + process_scheduled_works kernel/workqueue.c:3319 [inline] + worker_thread+0x770/0x10b0 kernel/workqueue.c:3400 + kthread+0x465/0x880 kernel/kthread.c:464 + ret_from_fork+0x4d/0x80 arch/x86/kernel/process.c:153 + ret_from_fork_asm+0x19/0x30 arch/x86/entry/entry_64.S:245 + + +Reviewed-by: Sun Jian +Fixes: da765a2f5993 ("bpf: Add poke dependency tracking for prog array maps") +Signed-off-by: Sechang Lim +Link: https://lore.kernel.org/r/20260407103823.3942156-1-rhkrqnwk98@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/arraymap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c +index 33de68c95ad8c..5e25e03535094 100644 +--- a/kernel/bpf/arraymap.c ++++ b/kernel/bpf/arraymap.c +@@ -1015,8 +1015,10 @@ static void bpf_fd_array_map_clear(struct bpf_map *map, bool need_defer) + struct bpf_array *array = container_of(map, struct bpf_array, map); + int i; + +- for (i = 0; i < array->map.max_entries; i++) ++ for (i = 0; i < array->map.max_entries; i++) { + __fd_array_map_delete_elem(map, &i, need_defer); ++ cond_resched(); ++ } + } + + static void prog_array_map_seq_show_elem(struct bpf_map *map, void *key, +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-refcount-check-in-check_struct_ops_btf_id.patch b/queue-7.0/bpf-fix-refcount-check-in-check_struct_ops_btf_id.patch new file mode 100644 index 0000000000..390cdc2c95 --- /dev/null +++ b/queue-7.0/bpf-fix-refcount-check-in-check_struct_ops_btf_id.patch @@ -0,0 +1,39 @@ +From 9ff112644fbaec9b6afe1b90f2a18fe72e05956b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 14:02:20 +0100 +Subject: bpf: Fix refcount check in check_struct_ops_btf_id() + +From: Keisuke Nishimura + +[ Upstream commit 25e3e1f1096089a64901ae1faa7b7b13446653db ] + +The current implementation only checks whether the first argument is +refcounted. Fix this by iterating over all arguments. + +Signed-off-by: Keisuke Nishimura +Fixes: 38f1e66abd184 ("bpf: Do not allow tail call in strcut_ops program with __ref argument") +Reviewed-by: Emil Tsalapatis +Acked-by: Amery Hung +Link: https://lore.kernel.org/r/20260320130219.63711-1-keisuke.nishimura@inria.fr +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index e3814152b52f8..23b35605ae377 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -24897,7 +24897,7 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) + } + + for (i = 0; i < st_ops_desc->arg_info[member_idx].cnt; i++) { +- if (st_ops_desc->arg_info[member_idx].info->refcounted) { ++ if (st_ops_desc->arg_info[member_idx].info[i].refcounted) { + has_refcounted_arg = true; + break; + } +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-same-register-dst-src-oob-read-and-pointer-l.patch b/queue-7.0/bpf-fix-same-register-dst-src-oob-read-and-pointer-l.patch new file mode 100644 index 0000000000..6dffb5e58d --- /dev/null +++ b/queue-7.0/bpf-fix-same-register-dst-src-oob-read-and-pointer-l.patch @@ -0,0 +1,84 @@ +From f0042f653c5a04b0ab40443abed9efb09c11bfc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 10:26:27 +0800 +Subject: bpf: Fix same-register dst/src OOB read and pointer leak in sock_ops + +From: Jiayuan Chen + +[ Upstream commit 10f86a2a5c91fc4c4d001960f1c21abe52545ef6 ] + +When a BPF sock_ops program accesses ctx fields with dst_reg == src_reg, +the SOCK_OPS_GET_SK() and SOCK_OPS_GET_FIELD() macros fail to zero the +destination register in the !fullsock / !locked_tcp_sock path. + +Both macros borrow a temporary register to check is_fullsock / +is_locked_tcp_sock when dst_reg == src_reg, because dst_reg holds the +ctx pointer. When the check is false (e.g., TCP_NEW_SYN_RECV state with +a request_sock), dst_reg should be zeroed but is not, leaving the stale +ctx pointer: + + - SOCK_OPS_GET_SK: dst_reg retains the ctx pointer, passes NULL checks + as PTR_TO_SOCKET_OR_NULL, and can be used as a bogus socket pointer, + leading to stack-out-of-bounds access in helpers like + bpf_skc_to_tcp6_sock(). + + - SOCK_OPS_GET_FIELD: dst_reg retains the ctx pointer which the + verifier believes is a SCALAR_VALUE, leaking a kernel pointer. + +Fix both macros by: + - Changing JMP_A(1) to JMP_A(2) in the fullsock path to skip the + added instruction. + - Adding BPF_MOV64_IMM(si->dst_reg, 0) after the temp register + restore in the !fullsock path, placed after the restore because + dst_reg == src_reg means we need src_reg intact to read ctx->temp. + +Fixes: fd09af010788 ("bpf: sock_ops ctx access may stomp registers in corner case") +Fixes: 84f44df664e9 ("bpf: sock_ops sk access may stomp registers when dst_reg = src_reg") +Reported-by: Quan Sun <2022090917019@std.uestc.edu.cn> +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reported-by: Dongliang Mu +Reviewed-by: Emil Tsalapatis +Closes: https://lore.kernel.org/bpf/6fe1243e-149b-4d3b-99c7-fcc9e2f75787@std.uestc.edu.cn/T/#u +Signed-off-by: Jiayuan Chen +Acked-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260407022720.162151-2-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 78b548158fb05..53ce06ed4a88e 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -10581,10 +10581,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, + si->dst_reg, si->dst_reg, \ + offsetof(OBJ, OBJ_FIELD)); \ + if (si->dst_reg == si->src_reg) { \ +- *insn++ = BPF_JMP_A(1); \ ++ *insn++ = BPF_JMP_A(2); \ + *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \ + offsetof(struct bpf_sock_ops_kern, \ + temp)); \ ++ *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \ + } \ + } while (0) + +@@ -10618,10 +10619,11 @@ static u32 sock_ops_convert_ctx_access(enum bpf_access_type type, + si->dst_reg, si->src_reg, \ + offsetof(struct bpf_sock_ops_kern, sk));\ + if (si->dst_reg == si->src_reg) { \ +- *insn++ = BPF_JMP_A(1); \ ++ *insn++ = BPF_JMP_A(2); \ + *insn++ = BPF_LDX_MEM(BPF_DW, reg, si->src_reg, \ + offsetof(struct bpf_sock_ops_kern, \ + temp)); \ ++ *insn++ = BPF_MOV64_IMM(si->dst_reg, 0); \ + } \ + } while (0) + +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch b/queue-7.0/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch new file mode 100644 index 0000000000..57202b5d09 --- /dev/null +++ b/queue-7.0/bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch @@ -0,0 +1,72 @@ +From b2341d5c353ffc80b751c59c562f6912f2433e0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:18:50 +0800 +Subject: bpf: Fix stale offload->prog pointer after constant blinding + +From: MingTao Huang + +[ Upstream commit a1aa9ef47c299c5bbc30594d3c2f0589edf908e6 ] + +When a dev-bound-only BPF program (BPF_F_XDP_DEV_BOUND_ONLY) undergoes +JIT compilation with constant blinding enabled (bpf_jit_harden >= 2), +bpf_jit_blind_constants() clones the program. The original prog is then +freed in bpf_jit_prog_release_other(), which updates aux->prog to point +to the surviving clone, but fails to update offload->prog. + +This leaves offload->prog pointing to the freed original program. When +the network namespace is subsequently destroyed, cleanup_net() triggers +bpf_dev_bound_netdev_unregister(), which iterates ondev->progs and calls +__bpf_prog_offload_destroy(offload->prog). Accessing the freed prog +causes a page fault: + +BUG: unable to handle page fault for address: ffffc900085f1038 +Workqueue: netns cleanup_net +RIP: 0010:__bpf_prog_offload_destroy+0xc/0x80 +Call Trace: +__bpf_offload_dev_netdev_unregister+0x257/0x350 +bpf_dev_bound_netdev_unregister+0x4a/0x90 +unregister_netdevice_many_notify+0x2a2/0x660 +... +cleanup_net+0x21a/0x320 + +The test sequence that triggers this reliably is: + +1. Set net.core.bpf_jit_harden=2 (echo 2 > /proc/sys/net/core/bpf_jit_harden) +2. Run xdp_metadata selftest, which creates a dev-bound-only XDP + program on a veth inside a netns (./test_progs -t xdp_metadata) +3. cleanup_net -> page fault in __bpf_prog_offload_destroy + +Dev-bound-only programs are unique in that they have an offload structure +but go through the normal JIT path instead of bpf_prog_offload_compile(). +This means they are subject to constant blinding's prog clone-and-replace, +while also having offload->prog that must stay in sync. + +Fix this by updating offload->prog in bpf_jit_prog_release_other(), +alongside the existing aux->prog update. Both are back-pointers to +the prog that must be kept in sync when the prog is replaced. + +Fixes: 2b3486bc2d23 ("bpf: Introduce device-bound XDP programs") +Signed-off-by: MingTao Huang +Link: https://lore.kernel.org/r/tencent_BCF692F45859CCE6C22B7B0B64827947D406@qq.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 7b675a451ec8e..048d275accae2 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1487,6 +1487,8 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other) + * know whether fp here is the clone or the original. + */ + fp->aux->prog = fp; ++ if (fp->aux->offload) ++ fp->aux->offload->prog = fp; + bpf_prog_clone_free(fp_other); + } + +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-use-after-free-in-offloaded-map-prog-info-fi.patch b/queue-7.0/bpf-fix-use-after-free-in-offloaded-map-prog-info-fi.patch new file mode 100644 index 0000000000..4a0f434797 --- /dev/null +++ b/queue-7.0/bpf-fix-use-after-free-in-offloaded-map-prog-info-fi.patch @@ -0,0 +1,72 @@ +From 47475e143cf74e5dbe970bebb3b2f393fca39bd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:37:32 +0800 +Subject: bpf: Fix use-after-free in offloaded map/prog info fill + +From: Jiayuan Chen + +[ Upstream commit a0c584fc18056709c8e047a82a6045d6c209f4ce ] + +When querying info for an offloaded BPF map or program, +bpf_map_offload_info_fill_ns() and bpf_prog_offload_info_fill_ns() +obtain the network namespace with get_net(dev_net(offmap->netdev)). +However, the associated netdev's netns may be racing with teardown +during netns destruction. If the netns refcount has already reached 0, +get_net() performs a refcount_t increment on 0, triggering: + + refcount_t: addition on 0; use-after-free. + +Although rtnl_lock and bpf_devs_lock ensure the netdev pointer remains +valid, they cannot prevent the netns refcount from reaching zero. + +Fix this by using maybe_get_net() instead of get_net(). maybe_get_net() +uses refcount_inc_not_zero() and returns NULL if the refcount is already +zero, which causes ns_get_path_cb() to fail and the caller to return +-ENOENT -- the correct behavior when the netns is being destroyed. + +Fixes: 675fc275a3a2d ("bpf: offload: report device information for offloaded programs") +Fixes: 52775b33bb507 ("bpf: offload: report device information about offloaded maps") +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Reviewed-by: Dongliang Mu +Closes: https://lore.kernel.org/bpf/f0aa3678-79c9-47ae-9e8c-02a3d1df160a@hust.edu.cn/ +Signed-off-by: Jiayuan Chen +Acked-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260409023733.168050-1-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/offload.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c +index 0ad97d643bf49..0d6f5569588c3 100644 +--- a/kernel/bpf/offload.c ++++ b/kernel/bpf/offload.c +@@ -435,9 +435,8 @@ static struct ns_common *bpf_prog_offload_info_fill_ns(void *private_data) + + if (aux->offload) { + args->info->ifindex = aux->offload->netdev->ifindex; +- net = dev_net(aux->offload->netdev); +- get_net(net); +- ns = &net->ns; ++ net = maybe_get_net(dev_net(aux->offload->netdev)); ++ ns = net ? &net->ns : NULL; + } else { + args->info->ifindex = 0; + ns = NULL; +@@ -647,9 +646,8 @@ static struct ns_common *bpf_map_offload_info_fill_ns(void *private_data) + + if (args->offmap->netdev) { + args->info->ifindex = args->offmap->netdev->ifindex; +- net = dev_net(args->offmap->netdev); +- get_net(net); +- ns = &net->ns; ++ net = maybe_get_net(dev_net(args->offmap->netdev)); ++ ns = net ? &net->ns : NULL; + } else { + args->info->ifindex = 0; + ns = NULL; +-- +2.53.0 + diff --git a/queue-7.0/bpf-fix-variable-length-stack-write-over-spilled-poi.patch b/queue-7.0/bpf-fix-variable-length-stack-write-over-spilled-poi.patch new file mode 100644 index 0000000000..94fb34c4d2 --- /dev/null +++ b/queue-7.0/bpf-fix-variable-length-stack-write-over-spilled-poi.patch @@ -0,0 +1,80 @@ +From e86cea6950c5da838fa522805f7d35a3b1361ef3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 14:59:36 -0700 +Subject: bpf: Fix variable length stack write over spilled pointers + +From: Alexei Starovoitov + +[ Upstream commit 4639eb9e30ab10c7935c7c19e872facf9a94713f ] + +Scrub slots if variable-offset stack write goes over spilled pointers. +Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT +and valid program is rejected by check_stack_read_fixed_off() +with obscure "invalid size of register fill" message. + +Fixes: 01f810ace9ed ("bpf: Allow variable-offset stack access") +Acked-by: Eduard Zingerman +Acked-by: Kumar Kartikeya Dwivedi +Link: https://lore.kernel.org/r/20260324215938.81733-1-alexei.starovoitov@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 23b35605ae377..8d00bd0f8b79d 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -5241,6 +5241,18 @@ static void check_fastcall_stack_contract(struct bpf_verifier_env *env, + } + } + ++static void scrub_special_slot(struct bpf_func_state *state, int spi) ++{ ++ int i; ++ ++ /* regular write of data into stack destroys any spilled ptr */ ++ state->stack[spi].spilled_ptr.type = NOT_INIT; ++ /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */ ++ if (is_stack_slot_special(&state->stack[spi])) ++ for (i = 0; i < BPF_REG_SIZE; i++) ++ scrub_spilled_slot(&state->stack[spi].slot_type[i]); ++} ++ + /* check_stack_{read,write}_fixed_off functions track spill/fill of registers, + * stack boundary and alignment are checked in check_mem_access() + */ +@@ -5338,12 +5350,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env, + } else { + u8 type = STACK_MISC; + +- /* regular write of data into stack destroys any spilled ptr */ +- state->stack[spi].spilled_ptr.type = NOT_INIT; +- /* Mark slots as STACK_MISC if they belonged to spilled ptr/dynptr/iter. */ +- if (is_stack_slot_special(&state->stack[spi])) +- for (i = 0; i < BPF_REG_SIZE; i++) +- scrub_spilled_slot(&state->stack[spi].slot_type[i]); ++ scrub_special_slot(state, spi); + + /* when we zero initialize stack slots mark them as such */ + if ((reg && register_is_null(reg)) || +@@ -5467,8 +5474,13 @@ static int check_stack_write_var_off(struct bpf_verifier_env *env, + } + } + +- /* Erase all other spilled pointers. */ +- state->stack[spi].spilled_ptr.type = NOT_INIT; ++ /* ++ * Scrub slots if variable-offset stack write goes over spilled pointers. ++ * Otherwise is_spilled_reg() may == true && spilled_ptr.type == NOT_INIT ++ * and valid program is rejected by check_stack_read_fixed_off() ++ * with obscure "invalid size of register fill" message. ++ */ ++ scrub_special_slot(state, spi); + + /* Update the slot type. */ + new_type = STACK_MISC; +-- +2.53.0 + diff --git a/queue-7.0/bpf-prefer-vmlinux-symbols-over-module-symbols-for-u.patch b/queue-7.0/bpf-prefer-vmlinux-symbols-over-module-symbols-for-u.patch new file mode 100644 index 0000000000..51ccd46bbb --- /dev/null +++ b/queue-7.0/bpf-prefer-vmlinux-symbols-over-module-symbols-for-u.patch @@ -0,0 +1,58 @@ +From d2637c8e477ef08329775e4455166065445c9065 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:39:11 -0400 +Subject: bpf: Prefer vmlinux symbols over module symbols for unqualified + kprobes + +From: Andrey Grodzovsky + +[ Upstream commit 1870ddcd94b061f54613b90d6300a350f29fc2f4 ] + +When an unqualified kprobe target exists in both vmlinux and a loaded +module, number_of_same_symbols() returns a count greater than 1, +causing kprobe attachment to fail with -EADDRNOTAVAIL even though the +vmlinux symbol is unambiguous. + +When no module qualifier is given and the symbol is found in vmlinux, +return the vmlinux-only count without scanning loaded modules. This +preserves the existing behavior for all other cases: +- Symbol only in a module: vmlinux count is 0, falls through to module + scan as before. +- Symbol qualified with MOD:SYM: mod != NULL, unchanged path. +- Symbol ambiguous within vmlinux itself: count > 1 is returned as-is. + +Fixes: 926fe783c8a6 ("tracing/kprobes: Fix symbol counting logic by looking at modules as well") +Fixes: 9d8616034f16 ("tracing/kprobes: Add symbol counting check when module loads") +Suggested-by: Ihor Solodrai +Acked-by: Jiri Olsa +Acked-by: Ihor Solodrai +Signed-off-by: Andrey Grodzovsky +Link: https://lore.kernel.org/r/20260407203912.1787502-2-andrey.grodzovsky@crowdstrike.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_kprobe.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c +index a5dbb72528e0c..058724c41c469 100644 +--- a/kernel/trace/trace_kprobe.c ++++ b/kernel/trace/trace_kprobe.c +@@ -765,6 +765,14 @@ static unsigned int number_of_same_symbols(const char *mod, const char *func_nam + if (!mod) + kallsyms_on_each_match_symbol(count_symbols, func_name, &ctx.count); + ++ /* ++ * If the symbol is found in vmlinux, use vmlinux resolution only. ++ * This prevents module symbols from shadowing vmlinux symbols ++ * and causing -EADDRNOTAVAIL for unqualified kprobe targets. ++ */ ++ if (!mod && ctx.count > 0) ++ return ctx.count; ++ + module_kallsyms_on_each_symbol(mod, count_mod_symbols, &ctx); + + return ctx.count; +-- +2.53.0 + diff --git a/queue-7.0/bpf-propagate-error-from-visit_tailcall_insn.patch b/queue-7.0/bpf-propagate-error-from-visit_tailcall_insn.patch new file mode 100644 index 0000000000..587792507f --- /dev/null +++ b/queue-7.0/bpf-propagate-error-from-visit_tailcall_insn.patch @@ -0,0 +1,42 @@ +From b390a3b9e06ce46775343f5c080f83aaf080a1ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 21:12:39 +0200 +Subject: bpf: Propagate error from visit_tailcall_insn + +From: Daniel Borkmann + +[ Upstream commit 6bd96e40f31dde8f8cd79772b4df0f171cf8a915 ] + +Commit e40f5a6bf88a ("bpf: correct stack liveness for tail calls") added +visit_tailcall_insn() but did not check its return value. + +Fixes: e40f5a6bf88a ("bpf: correct stack liveness for tail calls") +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-1-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 0507df13fe2d6..2949cdc7565f7 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -18894,8 +18894,11 @@ static int visit_insn(int t, struct bpf_verifier_env *env) + mark_subprog_might_sleep(env, t); + if (bpf_helper_changes_pkt_data(insn->imm)) + mark_subprog_changes_pkt_data(env, t); +- if (insn->imm == BPF_FUNC_tail_call) +- visit_tailcall_insn(env, t); ++ if (insn->imm == BPF_FUNC_tail_call) { ++ ret = visit_tailcall_insn(env, t); ++ if (ret) ++ return ret; ++ } + } else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) { + struct bpf_kfunc_call_arg_meta meta; + +-- +2.53.0 + diff --git a/queue-7.0/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch b/queue-7.0/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch new file mode 100644 index 0000000000..007e58cfea --- /dev/null +++ b/queue-7.0/bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch @@ -0,0 +1,74 @@ +From 2f583ccf798809d97c455a10a7f308cbcc888a73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 00:12:20 +0800 +Subject: bpf: reject negative CO-RE accessor indices in bpf_core_parse_spec() + +From: Weiming Shi + +[ Upstream commit 1c22483a2c4bbf747787f328392ca3e68619c4dc ] + +CO-RE accessor strings are colon-separated indices that describe a path +from a root BTF type to a target field, e.g. "0:1:2" walks through +nested struct members. bpf_core_parse_spec() parses each component with +sscanf("%d"), so negative values like -1 are silently accepted. The +subsequent bounds checks (access_idx >= btf_vlen(t)) only guard the +upper bound and always pass for negative values because C integer +promotion converts the __u16 btf_vlen result to int, making the +comparison (int)(-1) >= (int)(N) false for any positive N. + +When -1 reaches btf_member_bit_offset() it gets cast to u32 0xffffffff, +producing an out-of-bounds read far past the members array. A crafted +BPF program with a negative CO-RE accessor on any struct that exists in +vmlinux BTF (e.g. task_struct) crashes the kernel deterministically +during BPF_PROG_LOAD on any system with CONFIG_DEBUG_INFO_BTF=y +(default on major distributions). The bug is reachable with CAP_BPF: + + BUG: unable to handle page fault for address: ffffed11818b6626 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + Oops: Oops: 0000 [#1] SMP KASAN NOPTI + CPU: 0 UID: 0 PID: 85 Comm: poc Not tainted 7.0.0-rc6 #18 PREEMPT(full) + RIP: 0010:bpf_core_parse_spec (tools/lib/bpf/relo_core.c:354) + RAX: 00000000ffffffff + Call Trace: + + bpf_core_calc_relo_insn (tools/lib/bpf/relo_core.c:1321) + bpf_core_apply (kernel/bpf/btf.c:9507) + check_core_relo (kernel/bpf/verifier.c:19475) + bpf_check (kernel/bpf/verifier.c:26031) + bpf_prog_load (kernel/bpf/syscall.c:3089) + __sys_bpf (kernel/bpf/syscall.c:6228) + + +CO-RE accessor indices are inherently non-negative (struct member index, +array element index, or enumerator index), so reject them immediately +after parsing. + +Fixes: ddc7c3042614 ("libbpf: implement BPF CO-RE offset relocation algorithm") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Emil Tsalapatis +Acked-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260404161221.961828-2-bestswngs@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/relo_core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c +index 6eea5edba58a5..0ccc8f548cbaa 100644 +--- a/tools/lib/bpf/relo_core.c ++++ b/tools/lib/bpf/relo_core.c +@@ -292,6 +292,8 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf, + ++spec_str; + if (sscanf(spec_str, "%d%n", &access_idx, &parsed_len) != 1) + return -EINVAL; ++ if (access_idx < 0) ++ return -EINVAL; + if (spec->raw_len == BPF_CORE_SPEC_MAX_LEN) + return -E2BIG; + spec_str += parsed_len; +-- +2.53.0 + diff --git a/queue-7.0/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch b/queue-7.0/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch new file mode 100644 index 0000000000..b00b362240 --- /dev/null +++ b/queue-7.0/bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch @@ -0,0 +1,72 @@ +From ecede7753c3c1fb4b0f24116881f17e5bc248734 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 11:46:22 +0800 +Subject: bpf: reject short IPv4/IPv6 inputs in bpf_prog_test_run_skb + +From: Sun Jian + +[ Upstream commit 12bec2bd4b76d81c5d3996bd14ec1b7f4d983747 ] + +bpf_prog_test_run_skb() calls eth_type_trans() first and then uses +skb->protocol to initialize sk family and address fields for the test +run. + +For IPv4 and IPv6 packets, it may access ip_hdr(skb) or ipv6_hdr(skb) +even when the provided test input only contains an Ethernet header. + +Reject the input earlier if the Ethernet frame carries IPv4/IPv6 +EtherType but the L3 header is too short. + +Fold the IPv4/IPv6 header length checks into the existing protocol +switch and return -EINVAL before accessing the network headers. + +Fixes: fa5cb548ced6 ("bpf: Setup socket family and addresses in bpf_prog_test_run_skb") +Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc +Signed-off-by: Sun Jian +Link: https://lore.kernel.org/r/20260408034623.180320-2-sun.jian.kdev@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 56bc8dc1e2811..2988175a47f26 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1120,19 +1120,23 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + + switch (skb->protocol) { + case htons(ETH_P_IP): +- sk->sk_family = AF_INET; +- if (sizeof(struct iphdr) <= skb_headlen(skb)) { +- sk->sk_rcv_saddr = ip_hdr(skb)->saddr; +- sk->sk_daddr = ip_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct iphdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET; ++ sk->sk_rcv_saddr = ip_hdr(skb)->saddr; ++ sk->sk_daddr = ip_hdr(skb)->daddr; + break; + #if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +- sk->sk_family = AF_INET6; +- if (sizeof(struct ipv6hdr) <= skb_headlen(skb)) { +- sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; +- sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; ++ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) { ++ ret = -EINVAL; ++ goto out; + } ++ sk->sk_family = AF_INET6; ++ sk->sk_v6_rcv_saddr = ipv6_hdr(skb)->saddr; ++ sk->sk_v6_daddr = ipv6_hdr(skb)->daddr; + break; + #endif + default: +-- +2.53.0 + diff --git a/queue-7.0/bpf-remove-static-qualifier-from-local-subprog-point.patch b/queue-7.0/bpf-remove-static-qualifier-from-local-subprog-point.patch new file mode 100644 index 0000000000..8bc564bf84 --- /dev/null +++ b/queue-7.0/bpf-remove-static-qualifier-from-local-subprog-point.patch @@ -0,0 +1,52 @@ +From 96b1752f4361abbba68d34769f122b9d443f3a24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 21:12:41 +0200 +Subject: bpf: Remove static qualifier from local subprog pointer + +From: Daniel Borkmann + +[ Upstream commit 9dba0ae973e75051b63cbdd5b3532bb24aa63b3f ] + +The local subprog pointer in create_jt() and visit_abnormal_return_insn() +was declared static. + +It is unconditionally assigned via bpf_find_containing_subprog() before +every use. Thus, the static qualifier serves no purpose and rather creates +confusion. Just remove it. + +Fixes: e40f5a6bf88a ("bpf: correct stack liveness for tail calls") +Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps") +Signed-off-by: Daniel Borkmann +Acked-by: Anton Protopopov +Link: https://lore.kernel.org/r/20260408191242.526279-3-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 71c078d18683a..bf5e146692e0a 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -18764,7 +18764,7 @@ static struct bpf_iarray *jt_from_subprog(struct bpf_verifier_env *env, + static struct bpf_iarray * + create_jt(int t, struct bpf_verifier_env *env) + { +- static struct bpf_subprog_info *subprog; ++ struct bpf_subprog_info *subprog; + int subprog_start, subprog_end; + struct bpf_iarray *jt; + int i; +@@ -18839,7 +18839,7 @@ static int visit_gotox_insn(int t, struct bpf_verifier_env *env) + */ + static int visit_abnormal_return_insn(struct bpf_verifier_env *env, int t) + { +- static struct bpf_subprog_info *subprog; ++ struct bpf_subprog_info *subprog; + struct bpf_iarray *jt; + + if (env->insn_aux_data[t].jt) +-- +2.53.0 + diff --git a/queue-7.0/bpf-return-vma-snapshot-from-task_vma-iterator.patch b/queue-7.0/bpf-return-vma-snapshot-from-task_vma-iterator.patch new file mode 100644 index 0000000000..d14597269f --- /dev/null +++ b/queue-7.0/bpf-return-vma-snapshot-from-task_vma-iterator.patch @@ -0,0 +1,133 @@ +From 88be273f05705214fcee8d226a447fd023b6ea00 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:37 -0700 +Subject: bpf: return VMA snapshot from task_vma iterator + +From: Puranjay Mohan + +[ Upstream commit 4cbee026db54cad39c39db4d356100cb133412b3 ] + +Holding the per-VMA lock across the BPF program body creates a lock +ordering problem when helpers acquire locks that depend on mmap_lock: + + vm_lock -> i_rwsem -> mmap_lock -> vm_lock + +Snapshot the VMA under the per-VMA lock in _next() via memcpy(), then +drop the lock before returning. The BPF program accesses only the +snapshot. + +The verifier only trusts vm_mm and vm_file pointers (see +BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). vm_file is reference- +counted with get_file() under the lock and released via fput() on the +next iteration or in _destroy(). vm_mm is already correct because +lock_vma_under_rcu() verifies vma->vm_mm == mm. All other pointers +are left as-is by memcpy() since the verifier treats them as untrusted. + +Fixes: 4ac454682158 ("bpf: Introduce task_vma open-coded iterator kfuncs") +Signed-off-by: Puranjay Mohan +Acked-by: Andrii Nakryiko +Acked-by: Mykyta Yatsenko +Link: https://lore.kernel.org/r/20260408154539.3832150-4-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 42 ++++++++++++++++++++++++++++++------------ + 1 file changed, 30 insertions(+), 12 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index 87e87f18913d9..e791ae065c39b 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -808,7 +808,7 @@ static inline void bpf_iter_mmput_async(struct mm_struct *mm) + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +- struct vm_area_struct *locked_vma; ++ struct vm_area_struct snapshot; + u64 next_addr; + }; + +@@ -842,7 +842,7 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + + /* + * Reject irqs-disabled contexts including NMI. Operations used +- * by _next() and _destroy() (vma_end_read, bpf_iter_mmput_async) ++ * by _next() and _destroy() (vma_end_read, fput, bpf_iter_mmput_async) + * can take spinlocks with IRQs disabled (pi_lock, pool->lock). + * Running from NMI or from a tracepoint that fires with those + * locks held could deadlock. +@@ -885,7 +885,7 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + goto err_cleanup_iter; + } + +- kit->data->locked_vma = NULL; ++ kit->data->snapshot.vm_file = NULL; + kit->data->next_addr = addr; + return 0; + +@@ -947,26 +947,45 @@ bpf_iter_task_vma_find_next(struct bpf_iter_task_vma_kern_data *data) + return vma; + } + ++static void bpf_iter_task_vma_snapshot_reset(struct vm_area_struct *snap) ++{ ++ if (snap->vm_file) { ++ fput(snap->vm_file); ++ snap->vm_file = NULL; ++ } ++} ++ + __bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; +- struct vm_area_struct *vma; ++ struct vm_area_struct *snap, *vma; + + if (!kit->data) /* bpf_iter_task_vma_new failed */ + return NULL; + +- if (kit->data->locked_vma) { +- vma_end_read(kit->data->locked_vma); +- kit->data->locked_vma = NULL; +- } ++ snap = &kit->data->snapshot; ++ ++ bpf_iter_task_vma_snapshot_reset(snap); + + vma = bpf_iter_task_vma_find_next(kit->data); + if (!vma) + return NULL; + +- kit->data->locked_vma = vma; ++ memcpy(snap, vma, sizeof(*snap)); ++ ++ /* ++ * The verifier only trusts vm_mm and vm_file (see ++ * BTF_TYPE_SAFE_TRUSTED_OR_NULL in verifier.c). Take a reference ++ * on vm_file; vm_mm is already correct because lock_vma_under_rcu() ++ * verifies vma->vm_mm == mm. All other pointers are untrusted by ++ * the verifier and left as-is. ++ */ ++ if (snap->vm_file) ++ get_file(snap->vm_file); ++ + kit->data->next_addr = vma->vm_end; +- return vma; ++ vma_end_read(vma); ++ return snap; + } + + __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) +@@ -974,8 +993,7 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + struct bpf_iter_task_vma_kern *kit = (void *)it; + + if (kit->data) { +- if (kit->data->locked_vma) +- vma_end_read(kit->data->locked_vma); ++ bpf_iter_task_vma_snapshot_reset(&kit->data->snapshot); + put_task_struct(kit->data->task); + bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); +-- +2.53.0 + diff --git a/queue-7.0/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch b/queue-7.0/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch new file mode 100644 index 0000000000..0ebba2cee4 --- /dev/null +++ b/queue-7.0/bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch @@ -0,0 +1,82 @@ +From 7b40ab0628adf88c9a9cab999195e8b8dd2a890d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:11:09 -0700 +Subject: bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator + finalize + +From: Puranjay Mohan + +[ Upstream commit 46ee1342b887c9387a933397d846ff6c9584322c ] + +bpf_flush_icache() calls flush_icache_range() to clean the data cache +and invalidate the instruction cache for the JITed code region. However, +since commit 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the +BPF JIT"), this flush is redundant. + +bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX +region via bpf_arch_text_copy() -> patch_text_nosync(), and +patch_text_nosync() already calls flush_icache_range() on the written +range. The subsequent bpf_flush_icache() repeats the same cache +maintenance on an overlapping range. + +Remove the redundant bpf_flush_icache() call and its now-unused +definition. + +Fixes: 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT") +Acked-by: Song Liu +Signed-off-by: Puranjay Mohan +Reviewed-by: Pu Lehui +Tested-by: Paul Chaignon +Link: https://lore.kernel.org/r/20260413191111.3426023-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/riscv/net/bpf_jit.h | 6 ------ + arch/riscv/net/bpf_jit_core.c | 7 ------- + 2 files changed, 13 deletions(-) + +diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h +index 632ced07bca44..da02717902442 100644 +--- a/arch/riscv/net/bpf_jit.h ++++ b/arch/riscv/net/bpf_jit.h +@@ -11,7 +11,6 @@ + + #include + #include +-#include + + /* verify runtime detection extension status */ + #define rv_ext_enabled(ext) \ +@@ -105,11 +104,6 @@ static inline void bpf_fill_ill_insns(void *area, unsigned int size) + memset(area, 0, size); + } + +-static inline void bpf_flush_icache(void *start, void *end) +-{ +- flush_icache_range((unsigned long)start, (unsigned long)end); +-} +- + /* Emit a 4-byte riscv instruction. */ + static inline void emit(const u32 insn, struct rv_jit_context *ctx) + { +diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c +index b3581e9264362..f7fd4afc3ca3f 100644 +--- a/arch/riscv/net/bpf_jit_core.c ++++ b/arch/riscv/net/bpf_jit_core.c +@@ -183,13 +183,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + prog = orig_prog; + goto out_offset; + } +- /* +- * The instructions have now been copied to the ROX region from +- * where they will execute. +- * Write any modified data cache blocks out to memory and +- * invalidate the corresponding blocks in the instruction cache. +- */ +- bpf_flush_icache(jit_data->ro_header, ctx->ro_insns + ctx->ninsns); + for (i = 0; i < prog->len; i++) + ctx->offset[i] = ninsns_rvoff(ctx->offset[i]); + bpf_prog_fill_jited_linfo(prog, ctx->offset); +-- +2.53.0 + diff --git a/queue-7.0/bpf-sockmap-fix-af_unix-iter-deadlock.patch b/queue-7.0/bpf-sockmap-fix-af_unix-iter-deadlock.patch new file mode 100644 index 0000000000..8e31267769 --- /dev/null +++ b/queue-7.0/bpf-sockmap-fix-af_unix-iter-deadlock.patch @@ -0,0 +1,101 @@ +From 58effa4bea5a33655390ad55c4caf6a9962cd7ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:16 +0200 +Subject: bpf, sockmap: Fix af_unix iter deadlock + +From: Michal Luczaj + +[ Upstream commit 4d328dd695383224aa750ddee6b4ad40c0f8d205 ] + +bpf_iter_unix_seq_show() may deadlock when lock_sock_fast() takes the fast +path and the iter prog attempts to update a sockmap. Which ends up spinning +at sock_map_update_elem()'s bh_lock_sock(): + +WARNING: possible recursive locking detected +test_progs/1393 is trying to acquire lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: sock_map_update_elem+0xdb/0x1f0 + +but task is already holding lock: +ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + +other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(slock-AF_UNIX); + lock(slock-AF_UNIX); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + +4 locks held by test_progs/1393: + #0: ffff88814b59c790 (&p->lock){+.+.}-{4:4}, at: bpf_seq_read+0x59/0x10d0 + #1: ffff88811ec25fd8 (sk_lock-AF_UNIX){+.+.}-{0:0}, at: bpf_seq_read+0x42c/0x10d0 + #2: ffff88811ec25f58 (slock-AF_UNIX){+...}-{3:3}, at: __lock_sock_fast+0x37/0xe0 + #3: ffffffff85a6a7c0 (rcu_read_lock){....}-{1:3}, at: bpf_iter_run_prog+0x51d/0xb00 + +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_deadlock_bug.cold+0xc0/0xce + __lock_acquire+0x130f/0x2590 + lock_acquire+0x14e/0x2b0 + _raw_spin_lock+0x30/0x40 + sock_map_update_elem+0xdb/0x1f0 + bpf_prog_2d0075e5d9b721cd_dump_unix+0x55/0x4f4 + bpf_iter_run_prog+0x5b9/0xb00 + bpf_iter_unix_seq_show+0x1f7/0x2e0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Jiayuan Chen +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-2-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 09d43b4813b1a..b1ec96512bf72 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3734,15 +3734,14 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + struct bpf_prog *prog; + struct sock *sk = v; + uid_t uid; +- bool slow; + int ret; + + if (v == SEQ_START_TOKEN) + return 0; + +- slow = lock_sock_fast(sk); ++ lock_sock(sk); + +- if (unlikely(sk_unhashed(sk))) { ++ if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; + goto unlock; + } +@@ -3752,7 +3751,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: +- unlock_sock_fast(sk, slow); ++ release_sock(sk); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch b/queue-7.0/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch new file mode 100644 index 0000000000..cbdf45217b --- /dev/null +++ b/queue-7.0/bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch @@ -0,0 +1,200 @@ +From 9edfb32c84c9345b3ff90209854830bec150363b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:18 +0200 +Subject: bpf, sockmap: Fix af_unix null-ptr-deref in proto update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Luczaj + +[ Upstream commit dca38b7734d2ea00af4818ff3ae836fab33d5d5a ] + +unix_stream_connect() sets sk_state (`WRITE_ONCE(sk->sk_state, +TCP_ESTABLISHED)`) _before_ it assigns a peer (`unix_peer(sk) = newsk`). +sk_state == TCP_ESTABLISHED makes sock_map_sk_state_allowed() believe that +socket is properly set up, which would include having a defined peer. IOW, +there's a window when unix_stream_bpf_update_proto() can be called on +socket which still has unix_peer(sk) == NULL. + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) +sock_map_sk_state_allowed(sk) +... +sk_pair = unix_peer(sk) +sock_hold(sk_pair) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + +BUG: kernel NULL pointer dereference, address: 0000000000000080 +RIP: 0010:unix_stream_bpf_update_proto+0xa0/0x1b0 +Call Trace: + sock_map_link+0x564/0x8b0 + sock_map_update_common+0x6e/0x340 + sock_map_update_elem_sys+0x17d/0x240 + __sys_bpf+0x26db/0x3250 + __x64_sys_bpf+0x21/0x30 + do_syscall_64+0x6b/0x3a0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Initial idea was to move peer assignment _before_ the sk_state update[1], +but that involved an additional memory barrier, and changing the hot path +was rejected. +Then a NULL check during proto update in unix_stream_bpf_update_proto() was +considered[2], but the follow-up discussion[3] focused on the root cause, +i.e. sockmap update taking a wrong lock. Or, more specifically, missing +unix_state_lock()[4]. +In the end it was concluded that teaching sockmap about the af_unix locking +would be unnecessarily complex[5]. +Complexity aside, since BPF_PROG_TYPE_SCHED_CLS and BPF_PROG_TYPE_SCHED_ACT +are allowed to update sockmaps, sock_map_update_elem() taking the unix +lock, as it is currently implemented in unix_state_lock(): +spin_lock(&unix_sk(s)->lock), would be problematic. unix_state_lock() taken +in a process context, followed by a softirq-context TC BPF program +attempting to take the same spinlock -- deadlock[6]. +This way we circled back to the peer check idea[2]. + +[1]: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +[2]: https://lore.kernel.org/netdev/20240610174906.32921-1-kuniyu@amazon.com/ +[3]: https://lore.kernel.org/netdev/7603c0e6-cd5b-452b-b710-73b64bd9de26@linux.dev/ +[4]: https://lore.kernel.org/netdev/CAAVpQUA+8GL_j63CaKb8hbxoL21izD58yr1NvhOhU=j+35+3og@mail.gmail.com/ +[5]: https://lore.kernel.org/bpf/CAAVpQUAHijOMext28Gi10dSLuMzGYh+jK61Ujn+fZ-wvcODR2A@mail.gmail.com/ +[6]: https://lore.kernel.org/bpf/dd043c69-4d03-46fe-8325-8f97101435cf@linux.dev/ + +Summary of scenarios where af_unix/stream connect() may race a sockmap +update: + +1. connect() vs. bpf(BPF_MAP_UPDATE_ELEM), i.e. sock_map_update_elem_sys() + + Implemented NULL check is sufficient. Once assigned, socket peer won't + be released until socket fd is released. And that's not an issue because + sock_map_update_elem_sys() bumps fd refcnf. + +2. connect() vs BPF program doing update + + Update restricted per verifier.c:may_update_sockmap() to + + BPF_PROG_TYPE_TRACING/BPF_TRACE_ITER + BPF_PROG_TYPE_SOCK_OPS (bpf_sock_map_update() only) + BPF_PROG_TYPE_SOCKET_FILTER + BPF_PROG_TYPE_SCHED_CLS + BPF_PROG_TYPE_SCHED_ACT + BPF_PROG_TYPE_XDP + BPF_PROG_TYPE_SK_REUSEPORT + BPF_PROG_TYPE_FLOW_DISSECTOR + BPF_PROG_TYPE_SK_LOOKUP + + Plus one more race to consider: + + CPU0 bpf CPU1 connect + -------- ------------ + + WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED) + sock_map_sk_state_allowed(sk) + sock_hold(newsk) + smp_mb__after_atomic() + unix_peer(sk) = newsk + sk_pair = unix_peer(sk) + if (unlikely(!sk_pair)) + return -EINVAL; + + CPU1 close + ---------- + + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) + // use after free? + sock_hold(sk_pair) + + 2.1 BPF program invoking helper function bpf_sock_map_update() -> + BPF_CALL_4(bpf_sock_map_update(), ...) + + Helper limited to BPF_PROG_TYPE_SOCK_OPS. Nevertheless, a unix sock + might be accessible via bpf_map_lookup_elem(). Which implies sk + already having psock, which in turn implies sk already having + sk_pair. Since sk_psock_destroy() is queued as RCU work, sk_pair + won't go away while BPF executes the update. + + 2.2 BPF program invoking helper function bpf_map_update_elem() -> + sock_map_update_elem() + + 2.2.1 Unix sock accessible to BPF prog only via sockmap lookup in + BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_SK_REUSEPORT, BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_SK_LOOKUP. + + Pretty much the same as case 2.1. + + 2.2.2 Unix sock accessible to BPF program directly: + BPF_PROG_TYPE_TRACING, narrowed down to BPF_TRACE_ITER. + + Sockmap iterator (sock_map_seq_ops) is safe: unix sock + residing in a sockmap means that the sock already went through + the proto update step. + + Unix sock iterator (bpf_iter_unix_seq_ops), on the other hand, + gives access to socks that may still be unconnected. Which + means iterator prog can race sockmap/proto update against + connect(). + + BUG: KASAN: null-ptr-deref in unix_stream_bpf_update_proto+0x253/0x4d0 + Write of size 4 at addr 0000000000000080 by task test_progs/3140 + Call Trace: + dump_stack_lvl+0x5d/0x80 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x253/0x4d0 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + + While the introduced NULL check prevents null-ptr-deref in the + BPF program path as well, it is insufficient to guard against + a poorly timed close() leading to a use-after-free. This will + be addressed in a subsequent patch. + +Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()") +Closes: https://lore.kernel.org/netdev/ba5c50aa-1df4-40c2-ab33-a72022c5a32e@rbox.co/ +Reported-by: Michal Luczaj +Reported-by: 钱一铭 +Suggested-by: Kuniyuki Iwashima +Suggested-by: Martin KaFai Lau +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-4-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/unix_bpf.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/unix/unix_bpf.c b/net/unix/unix_bpf.c +index e0d30d6d22acb..57f3124c9d8db 100644 +--- a/net/unix/unix_bpf.c ++++ b/net/unix/unix_bpf.c +@@ -185,6 +185,9 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r + */ + if (!psock->sk_pair) { + sk_pair = unix_peer(sk); ++ if (unlikely(!sk_pair)) ++ return -EINVAL; ++ + sock_hold(sk_pair); + psock->sk_pair = sk_pair; + } +-- +2.53.0 + diff --git a/queue-7.0/bpf-sockmap-take-state-lock-for-af_unix-iter.patch b/queue-7.0/bpf-sockmap-take-state-lock-for-af_unix-iter.patch new file mode 100644 index 0000000000..186cf89195 --- /dev/null +++ b/queue-7.0/bpf-sockmap-take-state-lock-for-af_unix-iter.patch @@ -0,0 +1,115 @@ +From 1a447cb777437eaecc12478307a4fb36e450026e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:13:19 +0200 +Subject: bpf, sockmap: Take state lock for af_unix iter + +From: Michal Luczaj + +[ Upstream commit 64c2f93fc3254d3bf5de4445fb732ee5c451edb6 ] + +When a BPF iterator program updates a sockmap, there is a race condition in +unix_stream_bpf_update_proto() where the `peer` pointer can become stale[1] +during a state transition TCP_ESTABLISHED -> TCP_CLOSE. + + CPU0 bpf CPU1 close + -------- ---------- +// unix_stream_bpf_update_proto() +sk_pair = unix_peer(sk) +if (unlikely(!sk_pair)) + return -EINVAL; + // unix_release_sock() + skpair = unix_peer(sk); + unix_peer(sk) = NULL; + sock_put(skpair) +sock_hold(sk_pair) // UaF + +More practically, this fix guarantees that the iterator program is +consistently provided with a unix socket that remains stable during +iterator execution. + +[1]: +BUG: KASAN: slab-use-after-free in unix_stream_bpf_update_proto+0x155/0x490 +Write of size 4 at addr ffff8881178c9a00 by task test_progs/2231 +Call Trace: + dump_stack_lvl+0x5d/0x80 + print_report+0x170/0x4f3 + kasan_report+0xe4/0x1c0 + kasan_check_range+0x125/0x200 + unix_stream_bpf_update_proto+0x155/0x490 + sock_map_link+0x71c/0xec0 + sock_map_update_common+0xbc/0x600 + sock_map_update_elem+0x19a/0x1f0 + bpf_prog_bbbf56096cdd4f01_selective_dump_unix+0x20c/0x217 + bpf_iter_run_prog+0x21e/0xae0 + bpf_iter_unix_seq_show+0x1e0/0x2a0 + bpf_seq_read+0x42c/0x10d0 + vfs_read+0x171/0xb20 + ksys_read+0xff/0x200 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Allocated by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + __kasan_slab_alloc+0x63/0x80 + kmem_cache_alloc_noprof+0x1d5/0x680 + sk_prot_alloc+0x59/0x210 + sk_alloc+0x34/0x470 + unix_create1+0x86/0x8a0 + unix_stream_connect+0x318/0x15b0 + __sys_connect+0xfd/0x130 + __x64_sys_connect+0x72/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Freed by task 2236: + kasan_save_stack+0x30/0x50 + kasan_save_track+0x14/0x30 + kasan_save_free_info+0x3b/0x70 + __kasan_slab_free+0x47/0x70 + kmem_cache_free+0x11c/0x590 + __sk_destruct+0x432/0x6e0 + unix_release_sock+0x9b3/0xf60 + unix_release+0x8a/0xf0 + __sock_release+0xb0/0x270 + sock_close+0x18/0x20 + __fput+0x36e/0xac0 + fput_close_sync+0xe5/0x1a0 + __x64_sys_close+0x7d/0xd0 + do_syscall_64+0xf7/0x5e0 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 2c860a43dd77 ("bpf: af_unix: Implement BPF iterator for UNIX domain socket.") +Suggested-by: Kuniyuki Iwashima +Signed-off-by: Michal Luczaj +Signed-off-by: Martin KaFai Lau +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-5-2af6fe97918e@rbox.co +Signed-off-by: Sasha Levin +--- + net/unix/af_unix.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index b1ec96512bf72..660c7c441e0db 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -3740,6 +3740,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + return 0; + + lock_sock(sk); ++ unix_state_lock(sk); + + if (unlikely(sock_flag(sk, SOCK_DEAD))) { + ret = SEQ_SKIP; +@@ -3751,6 +3752,7 @@ static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) + prog = bpf_iter_get_info(&meta, false); + ret = unix_prog_seq_show(prog, &meta, v, uid); + unlock: ++ unix_state_unlock(sk); + release_sock(sk); + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/bpf-switch-config_cfi_clang-to-config_cfi.patch b/queue-7.0/bpf-switch-config_cfi_clang-to-config_cfi.patch new file mode 100644 index 0000000000..8ed09e9770 --- /dev/null +++ b/queue-7.0/bpf-switch-config_cfi_clang-to-config_cfi.patch @@ -0,0 +1,41 @@ +From 663a7f66045ff2fea133f20cd7a667e353e148a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 18:38:17 +0000 +Subject: bpf: Switch CONFIG_CFI_CLANG to CONFIG_CFI + +From: Carlos Llamas + +[ Upstream commit 9b0cf064ea0a6bac5e1a5fb43b004fd52fbe2b3b ] + +This was renamed in commit 23ef9d439769 ("kcfi: Rename CONFIG_CFI_CLANG +to CONFIG_CFI") as it is now a compiler-agnostic option. Using the wrong +name results in the code getting compiled out. Meaning the CFI failures +for btf_dtor_kfunc_t would still trigger. + +Fixes: 99fde4d06261 ("bpf, btf: Enforce destructor kfunc type with CFI") +Signed-off-by: Carlos Llamas +Reviewed-by: Sami Tolvanen +Acked-by: Yonghong Song +Link: https://lore.kernel.org/r/20260312183818.2721750-1-cmllamas@google.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/btf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c +index 71f9143fe90f3..63d075f374591 100644 +--- a/kernel/bpf/btf.c ++++ b/kernel/bpf/btf.c +@@ -9019,7 +9019,7 @@ static int btf_check_dtor_kfuncs(struct btf *btf, const struct btf_id_dtor_kfunc + if (!t || !btf_type_is_ptr(t)) + return -EINVAL; + +- if (IS_ENABLED(CONFIG_CFI_CLANG)) { ++ if (IS_ENABLED(CONFIG_CFI)) { + /* Ensure the destructor kfunc type matches btf_dtor_kfunc_t */ + t = btf_type_by_id(btf, t->type); + if (!btf_type_is_void(t)) +-- +2.53.0 + diff --git a/queue-7.0/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch b/queue-7.0/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch new file mode 100644 index 0000000000..3f883f4818 --- /dev/null +++ b/queue-7.0/bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch @@ -0,0 +1,199 @@ +From 26402752b4be93e379a2b81adc732b29a1a7aab2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:45:36 -0700 +Subject: bpf: switch task_vma iterator from mmap_lock to per-VMA locks + +From: Puranjay Mohan + +[ Upstream commit bee9ef4a40a277bf401be43d39ba7f7f063cf39c ] + +The open-coded task_vma iterator holds mmap_lock for the entire duration +of iteration, increasing contention on this highly contended lock. + +Switch to per-VMA locking. Find the next VMA via an RCU-protected maple +tree walk and lock it with lock_vma_under_rcu(). lock_next_vma() is not +used because its fallback takes mmap_read_lock(), and the iterator must +work in non-sleepable contexts. + +lock_vma_under_rcu() is a point lookup (mas_walk) that finds the VMA +containing a given address but cannot iterate across gaps. An +RCU-protected vma_next() walk (mas_find) first locates the next VMA's +vm_start to pass to lock_vma_under_rcu(). + +Between the RCU walk and the lock, the VMA may be removed, shrunk, or +write-locked. On failure, advance past it using vm_end from the RCU +walk. Because the VMA slab is SLAB_TYPESAFE_BY_RCU, vm_end may be +stale; fall back to PAGE_SIZE advancement when it does not make forward +progress. Concurrent VMA insertions at addresses already passed by the +iterator are not detected. + +CONFIG_PER_VMA_LOCK is required; return -EOPNOTSUPP without it. + +Signed-off-by: Puranjay Mohan +Link: https://lore.kernel.org/r/20260408154539.3832150-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Stable-dep-of: 4cbee026db54 ("bpf: return VMA snapshot from task_vma iterator") +Signed-off-by: Sasha Levin +--- + kernel/bpf/task_iter.c | 91 +++++++++++++++++++++++++++++++++--------- + 1 file changed, 73 insertions(+), 18 deletions(-) + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index c1f5fbe9dc2f3..87e87f18913d9 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include "mmap_unlock_work.h" + +@@ -807,8 +808,8 @@ static inline void bpf_iter_mmput_async(struct mm_struct *mm) + struct bpf_iter_task_vma_kern_data { + struct task_struct *task; + struct mm_struct *mm; +- struct mmap_unlock_irq_work *work; +- struct vma_iterator vmi; ++ struct vm_area_struct *locked_vma; ++ u64 next_addr; + }; + + struct bpf_iter_task_vma { +@@ -829,21 +830,19 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + struct task_struct *task, u64 addr) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; +- bool irq_work_busy = false; + int err; + + BUILD_BUG_ON(sizeof(struct bpf_iter_task_vma_kern) != sizeof(struct bpf_iter_task_vma)); + BUILD_BUG_ON(__alignof__(struct bpf_iter_task_vma_kern) != __alignof__(struct bpf_iter_task_vma)); + +- /* bpf_iter_mmput_async() needs mmput_async() which requires CONFIG_MMU */ +- if (!IS_ENABLED(CONFIG_MMU)) { ++ if (!IS_ENABLED(CONFIG_PER_VMA_LOCK)) { + kit->data = NULL; + return -EOPNOTSUPP; + } + + /* + * Reject irqs-disabled contexts including NMI. Operations used +- * by _next() and _destroy() (mmap_read_unlock, bpf_iter_mmput_async) ++ * by _next() and _destroy() (vma_end_read, bpf_iter_mmput_async) + * can take spinlocks with IRQs disabled (pi_lock, pool->lock). + * Running from NMI or from a tracepoint that fires with those + * locks held could deadlock. +@@ -886,18 +885,10 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + goto err_cleanup_iter; + } + +- /* kit->data->work == NULL is valid after bpf_mmap_unlock_get_irq_work */ +- irq_work_busy = bpf_mmap_unlock_get_irq_work(&kit->data->work); +- if (irq_work_busy || !mmap_read_trylock(kit->data->mm)) { +- err = -EBUSY; +- goto err_cleanup_mmget; +- } +- +- vma_iter_init(&kit->data->vmi, kit->data->mm, addr); ++ kit->data->locked_vma = NULL; ++ kit->data->next_addr = addr; + return 0; + +-err_cleanup_mmget: +- bpf_iter_mmput_async(kit->data->mm); + err_cleanup_iter: + put_task_struct(kit->data->task); + bpf_mem_free(&bpf_global_ma, kit->data); +@@ -906,13 +897,76 @@ __bpf_kfunc int bpf_iter_task_vma_new(struct bpf_iter_task_vma *it, + return err; + } + ++/* ++ * Find and lock the next VMA at or after data->next_addr. ++ * ++ * lock_vma_under_rcu() is a point lookup (mas_walk): it finds the VMA ++ * containing a given address but cannot iterate. An RCU-protected ++ * maple tree walk with vma_next() (mas_find) is needed first to locate ++ * the next VMA's vm_start across any gap. ++ * ++ * Between the RCU walk and the lock, the VMA may be removed, shrunk, ++ * or write-locked. On failure, advance past it using vm_end from the ++ * RCU walk. SLAB_TYPESAFE_BY_RCU can make vm_end stale, so fall back ++ * to PAGE_SIZE advancement to guarantee forward progress. ++ */ ++static struct vm_area_struct * ++bpf_iter_task_vma_find_next(struct bpf_iter_task_vma_kern_data *data) ++{ ++ struct vm_area_struct *vma; ++ struct vma_iterator vmi; ++ unsigned long start, end; ++ ++retry: ++ rcu_read_lock(); ++ vma_iter_init(&vmi, data->mm, data->next_addr); ++ vma = vma_next(&vmi); ++ if (!vma) { ++ rcu_read_unlock(); ++ return NULL; ++ } ++ start = vma->vm_start; ++ end = vma->vm_end; ++ rcu_read_unlock(); ++ ++ vma = lock_vma_under_rcu(data->mm, start); ++ if (!vma) { ++ if (end <= data->next_addr) ++ data->next_addr += PAGE_SIZE; ++ else ++ data->next_addr = end; ++ goto retry; ++ } ++ ++ if (unlikely(vma->vm_end <= data->next_addr)) { ++ data->next_addr += PAGE_SIZE; ++ vma_end_read(vma); ++ goto retry; ++ } ++ ++ return vma; ++} ++ + __bpf_kfunc struct vm_area_struct *bpf_iter_task_vma_next(struct bpf_iter_task_vma *it) + { + struct bpf_iter_task_vma_kern *kit = (void *)it; ++ struct vm_area_struct *vma; + + if (!kit->data) /* bpf_iter_task_vma_new failed */ + return NULL; +- return vma_next(&kit->data->vmi); ++ ++ if (kit->data->locked_vma) { ++ vma_end_read(kit->data->locked_vma); ++ kit->data->locked_vma = NULL; ++ } ++ ++ vma = bpf_iter_task_vma_find_next(kit->data); ++ if (!vma) ++ return NULL; ++ ++ kit->data->locked_vma = vma; ++ kit->data->next_addr = vma->vm_end; ++ return vma; + } + + __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) +@@ -920,7 +974,8 @@ __bpf_kfunc void bpf_iter_task_vma_destroy(struct bpf_iter_task_vma *it) + struct bpf_iter_task_vma_kern *kit = (void *)it; + + if (kit->data) { +- bpf_mmap_unlock_mm(kit->data->work, kit->data->mm); ++ if (kit->data->locked_vma) ++ vma_end_read(kit->data->locked_vma); + put_task_struct(kit->data->task); + bpf_iter_mmput_async(kit->data->mm); + bpf_mem_free(&bpf_global_ma, kit->data); +-- +2.53.0 + diff --git a/queue-7.0/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch b/queue-7.0/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch new file mode 100644 index 0000000000..bb50834ab1 --- /dev/null +++ b/queue-7.0/bpf-test_run-fix-the-null-pointer-dereference-issue-.patch @@ -0,0 +1,100 @@ +From 1c58a174c972b7a11fbc4038e153bd8132ecdd27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 17:44:28 +0800 +Subject: bpf: test_run: Fix the null pointer dereference issue in + bpf_lwt_xmit_push_encap + +From: Feng Yang + +[ Upstream commit 972787479ee73006fddb5e59ab5c8e733810ff42 ] + +The bpf_lwt_xmit_push_encap helper needs to access skb_dst(skb)->dev to +calculate the needed headroom: + + err = skb_cow_head(skb, + len + LL_RESERVED_SPACE(skb_dst(skb)->dev)); + +But skb->_skb_refdst may not be initialized when the skb is set up by +bpf_prog_test_run_skb function. Executing bpf_lwt_push_ip_encap function +in this scenario will trigger null pointer dereference, causing a kernel +crash as Yinhao reported: + +[ 105.186365] BUG: kernel NULL pointer dereference, address: 0000000000000000 +[ 105.186382] #PF: supervisor read access in kernel mode +[ 105.186388] #PF: error_code(0x0000) - not-present page +[ 105.186393] PGD 121d3d067 P4D 121d3d067 PUD 106c83067 PMD 0 +[ 105.186404] Oops: 0000 [#1] PREEMPT SMP NOPTI +[ 105.186412] CPU: 3 PID: 3250 Comm: poc Kdump: loaded Not tainted 6.19.0-rc5 #1 +[ 105.186423] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 +[ 105.186427] RIP: 0010:bpf_lwt_push_ip_encap+0x1eb/0x520 +[ 105.186443] Code: 0f 84 de 01 00 00 0f b7 4a 04 66 85 c9 0f 85 47 01 00 00 31 c0 5b 5d 41 5c 41 5d 41 5e c3 cc cc cc cc 48 8b 73 58 48 83 e6 fe <48> 8b 36 0f b7 be ec 00 00 00 0f b7 b6 e6 00 00 00 01 fe 83 e6 f0 +[ 105.186449] RSP: 0018:ffffbb0e0387bc50 EFLAGS: 00010246 +[ 105.186455] RAX: 000000000000004e RBX: ffff94c74e036500 RCX: ffff94c74874da00 +[ 105.186460] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff94c74e036500 +[ 105.186463] RBP: 0000000000000001 R08: 0000000000000002 R09: 0000000000000000 +[ 105.186467] R10: ffffbb0e0387bd50 R11: 0000000000000000 R12: ffffbb0e0387bc98 +[ 105.186471] R13: 0000000000000014 R14: 0000000000000000 R15: 0000000000000002 +[ 105.186484] FS: 00007f166aa4d680(0000) GS:ffff94c8b7780000(0000) knlGS:0000000000000000 +[ 105.186490] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 105.186494] CR2: 0000000000000000 CR3: 000000015eade001 CR4: 0000000000770ee0 +[ 105.186499] PKRU: 55555554 +[ 105.186502] Call Trace: +[ 105.186507] +[ 105.186513] bpf_lwt_xmit_push_encap+0x2b/0x40 +[ 105.186522] bpf_prog_a75eaad51e517912+0x41/0x49 +[ 105.186536] ? kvm_clock_get_cycles+0x18/0x30 +[ 105.186547] ? ktime_get+0x3c/0xa0 +[ 105.186554] bpf_test_run+0x195/0x320 +[ 105.186563] ? bpf_test_run+0x10f/0x320 +[ 105.186579] bpf_prog_test_run_skb+0x2f5/0x4f0 +[ 105.186590] __sys_bpf+0x69c/0xa40 +[ 105.186603] __x64_sys_bpf+0x1e/0x30 +[ 105.186611] do_syscall_64+0x59/0x110 +[ 105.186620] entry_SYSCALL_64_after_hwframe+0x76/0xe0 +[ 105.186649] RIP: 0033:0x7f166a97455d + +Temporarily add the setting of skb->_skb_refdst before bpf_test_run to resolve the issue. + +Fixes: 52f278774e79 ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap") +Reported-by: Yinhao Hu +Reported-by: Kaiyan Mei +Closes: https://groups.google.com/g/hust-os-kernel-patches/c/8-a0kPpBW2s +Signed-off-by: Yun Lu +Signed-off-by: Feng Yang +Signed-off-by: Martin KaFai Lau +Tested-by: syzbot@syzkaller.appspotmail.com +Link: https://patch.msgid.link/20260304094429.168521-2-yangfeng59949@163.com +Signed-off-by: Sasha Levin +--- + net/bpf/test_run.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index 178c4738e63be..56bc8dc1e2811 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -1156,6 +1156,21 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr, + skb->ip_summed = CHECKSUM_COMPLETE; + } + ++ if (prog->type == BPF_PROG_TYPE_LWT_XMIT) { ++ if (!ipv6_bpf_stub) { ++ pr_warn_once("Please test this program with the IPv6 module loaded\n"); ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ /* For CONFIG_IPV6=n, ipv6_bpf_stub is NULL which is ++ * handled by the above if statement. ++ */ ++ dst_hold(&net->ipv6.ip6_null_entry->dst); ++ skb_dst_set(skb, &net->ipv6.ip6_null_entry->dst); ++#endif ++ } ++ + ret = bpf_test_run(prog, skb, repeat, &retval, &duration, false); + if (ret) + goto out; +-- +2.53.0 + diff --git a/queue-7.0/bpf-use-copy_map_value_locked-in-alloc_htab_elem-for.patch b/queue-7.0/bpf-use-copy_map_value_locked-in-alloc_htab_elem-for.patch new file mode 100644 index 0000000000..0e7b03ff59 --- /dev/null +++ b/queue-7.0/bpf-use-copy_map_value_locked-in-alloc_htab_elem-for.patch @@ -0,0 +1,50 @@ +From d03a443027146a0ba5545070c9336080ef583f13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 06:50:36 -0700 +Subject: bpf: Use copy_map_value_locked() in alloc_htab_elem() for BPF_F_LOCK + +From: Mykyta Yatsenko + +[ Upstream commit 07738bc566c38e0a8c82084e962890d1d59715c8 ] + +When a BPF_F_LOCK update races with a concurrent delete, the freed +element can be immediately recycled by alloc_htab_elem(). The fast path +in htab_map_update_elem() performs a lockless lookup and then calls +copy_map_value_locked() under the element's spin_lock. If +alloc_htab_elem() recycles the same memory, it overwrites the value +with plain copy_map_value(), without taking the spin_lock, causing +torn writes. + +Use copy_map_value_locked() when BPF_F_LOCK is set so the new element's +value is written under the embedded spin_lock, serializing against any +stale lock holders. + +Fixes: 96049f3afd50 ("bpf: introduce BPF_F_LOCK flag") +Reported-by: Aaron Esau +Closes: https://lore.kernel.org/all/CADucPGRvSRpkneb94dPP08YkOHgNgBnskTK6myUag_Mkjimihg@mail.gmail.com/ +Signed-off-by: Mykyta Yatsenko +Link: https://lore.kernel.org/r/20260401-bpf_map_torn_writes-v1-1-782d071c55e7@meta.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/hashtab.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c +index bc6bc8bb871d4..f7ac1ec7be8bf 100644 +--- a/kernel/bpf/hashtab.c ++++ b/kernel/bpf/hashtab.c +@@ -1138,6 +1138,10 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key, + } else if (fd_htab_map_needs_adjust(htab)) { + size = round_up(size, 8); + memcpy(htab_elem_value(l_new, key_size), value, size); ++ } else if (map_flags & BPF_F_LOCK) { ++ copy_map_value_locked(&htab->map, ++ htab_elem_value(l_new, key_size), ++ value, false); + } else { + copy_map_value(&htab->map, htab_elem_value(l_new, key_size), value); + } +-- +2.53.0 + diff --git a/queue-7.0/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch b/queue-7.0/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch new file mode 100644 index 0000000000..263b61e579 --- /dev/null +++ b/queue-7.0/bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch @@ -0,0 +1,71 @@ +From 2a7a08db8232c58a22721c0c1b4e59b676083f43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 07:26:45 +0000 +Subject: bpf: Use RCU-safe iteration in dev_map_redirect_multi() SKB path + +From: David Carlier + +[ Upstream commit 8ed82f807bb09d2c8455aaa665f2c6cb17bc6a19 ] + +The DEVMAP_HASH branch in dev_map_redirect_multi() uses +hlist_for_each_entry_safe() to iterate hash buckets, but this function +runs under RCU protection (called from xdp_do_generic_redirect_map() +in softirq context). Concurrent writers (__dev_map_hash_update_elem, +dev_map_hash_delete_elem) modify the list using RCU primitives +(hlist_add_head_rcu, hlist_del_rcu). + +hlist_for_each_entry_safe() performs plain pointer dereferences without +rcu_dereference(), missing the acquire barrier needed to pair with +writers' rcu_assign_pointer(). On weakly-ordered architectures (ARM64, +POWER), a reader can observe a partially-constructed node. It also +defeats CONFIG_PROVE_RCU lockdep validation and KCSAN data-race +detection. + +Replace with hlist_for_each_entry_rcu() using rcu_read_lock_bh_held() +as the lockdep condition, consistent with the rcu_dereference_check() +used in the DEVMAP (non-hash) branch of the same functions. Also fix +the same incorrect lockdep_is_held(&dtab->index_lock) condition in +dev_map_enqueue_multi(), where the lock is not held either. + +Fixes: e624d4ed4aa8 ("xdp: Extend xdp_redirect_map with broadcast support") +Signed-off-by: David Carlier +Signed-off-by: Martin KaFai Lau +Link: https://patch.msgid.link/20260320072645.16731-1-devnexen@gmail.com +Signed-off-by: Sasha Levin +--- + kernel/bpf/devmap.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index 3d619d01088e3..cc0a43ebab6b9 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -665,7 +665,7 @@ int dev_map_enqueue_multi(struct xdp_frame *xdpf, struct net_device *dev_rx, + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); + hlist_for_each_entry_rcu(dst, head, index_hlist, +- lockdep_is_held(&dtab->index_lock)) { ++ rcu_read_lock_bh_held()) { + if (!is_valid_dst(dst, xdpf)) + continue; + +@@ -747,7 +747,6 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + struct bpf_dtab_netdev *dst, *last_dst = NULL; + int excluded_devices[1+MAX_NEST_DEV]; + struct hlist_head *head; +- struct hlist_node *next; + int num_excluded = 0; + unsigned int i; + int err; +@@ -787,7 +786,7 @@ int dev_map_redirect_multi(struct net_device *dev, struct sk_buff *skb, + } else { /* BPF_MAP_TYPE_DEVMAP_HASH */ + for (i = 0; i < dtab->n_buckets; i++) { + head = dev_map_index_hash(dtab, i); +- hlist_for_each_entry_safe(dst, next, head, index_hlist) { ++ hlist_for_each_entry_rcu(dst, head, index_hlist, rcu_read_lock_bh_held()) { + if (is_ifindex_excluded(excluded_devices, num_excluded, + dst->dev->ifindex)) + continue; +-- +2.53.0 + diff --git a/queue-7.0/bpf-validate-node_id-in-arena_alloc_pages.patch b/queue-7.0/bpf-validate-node_id-in-arena_alloc_pages.patch new file mode 100644 index 0000000000..97281a7564 --- /dev/null +++ b/queue-7.0/bpf-validate-node_id-in-arena_alloc_pages.patch @@ -0,0 +1,43 @@ +From 7e125296e145dd09cf048cb14812aa73466411bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 08:21:33 -0700 +Subject: bpf: Validate node_id in arena_alloc_pages() + +From: Puranjay Mohan + +[ Upstream commit 2845989f2ebaf7848e4eccf9a779daf3156ea0a5 ] + +arena_alloc_pages() accepts a plain int node_id and forwards it through +the entire allocation chain without any bounds checking. + +Validate node_id before passing it down the allocation chain in +arena_alloc_pages(). + +Fixes: 317460317a02 ("bpf: Introduce bpf_arena.") +Signed-off-by: Puranjay Mohan +Reviewed-by: Emil Tsalapatis +Link: https://lore.kernel.org/r/20260417152135.1383754-1-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + kernel/bpf/arena.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c +index 9c68c9b0b24ad..523c3a61063bf 100644 +--- a/kernel/bpf/arena.c ++++ b/kernel/bpf/arena.c +@@ -562,6 +562,10 @@ static long arena_alloc_pages(struct bpf_arena *arena, long uaddr, long page_cnt + u32 uaddr32; + int ret, i; + ++ if (node_id != NUMA_NO_NODE && ++ ((unsigned int)node_id >= nr_node_ids || !node_online(node_id))) ++ return 0; ++ + if (page_cnt > page_cnt_max) + return 0; + +-- +2.53.0 + diff --git a/queue-7.0/btrfs-do-not-reject-a-valid-running-dev-replace.patch b/queue-7.0/btrfs-do-not-reject-a-valid-running-dev-replace.patch new file mode 100644 index 0000000000..ceb49508db --- /dev/null +++ b/queue-7.0/btrfs-do-not-reject-a-valid-running-dev-replace.patch @@ -0,0 +1,69 @@ +From 689478f26e9ae66995f7d0a6ff216ba8d1b48560 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 09:32:57 +1030 +Subject: btrfs: do not reject a valid running dev-replace +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Qu Wenruo + +[ Upstream commit 3c0c45a4dff73845ba93d41365fc14e45ee32bd7 ] + +[BUG] +There is a bug report that a btrfs with running dev-replace got rejected +with the following messages: + + BTRFS error (device sdk1): devid 0 path /dev/sdk1 is registered but not found in chunk tree + BTRFS error (device sdk1): remove the above devices or use 'btrfs device scan --forget ' to unregister them before mount + BTRFS error (device sdk1): open_ctree failed: -117 + +[CAUSE] +The tree and super block dumps show the fs is completely sane, except +one thing, there is no dev item for devid 0 in chunk tree. + +However this is not a bug, as we do not insert dev item for devid 0 in +the first place. +Since the devid 0 is only there temporarily we do not really need to +insert a dev item for it and then later remove it again. + +It is the commit 34308187395f ("btrfs: add extra device item checks at +mount") adding a overly strict check that triggers a false alert and +rejected the valid filesystem. + +[FIX] +Add a special handling for devid 0, and doesn't require devid 0 to +have a device item in chunk tree. + +Reported-by: Jaron Viëtor +Link: https://lore.kernel.org/linux-btrfs/CAF1bhLVYLZvD=j2XyuxXDKD-NWNJAwDnpVN+UYeQW-HbzNRn1A@mail.gmail.com/ +Fixes: 34308187395f ("btrfs: add extra device item checks at mount") +Signed-off-by: Qu Wenruo +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/volumes.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 6b8e810a35ce1..fd400fbc654d9 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -8457,7 +8457,12 @@ bool btrfs_verify_dev_items(const struct btrfs_fs_info *fs_info) + + mutex_lock(&uuid_mutex); + list_for_each_entry(dev, &fs_info->fs_devices->devices, dev_list) { +- if (!test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) { ++ /* ++ * Replace target dev item (devid 0) is not inserted into chunk tree. ++ * So skip the DEV_STATE_ITEM check. ++ */ ++ if (dev->devid != BTRFS_DEV_REPLACE_DEVID && ++ !test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) { + btrfs_err(fs_info, + "devid %llu path %s is registered but not found in chunk tree", + dev->devid, btrfs_dev_name(dev)); +-- +2.53.0 + diff --git a/queue-7.0/btrfs-don-t-clobber-errors-in-add_remap_tree_entries.patch b/queue-7.0/btrfs-don-t-clobber-errors-in-add_remap_tree_entries.patch new file mode 100644 index 0000000000..bdccc16500 --- /dev/null +++ b/queue-7.0/btrfs-don-t-clobber-errors-in-add_remap_tree_entries.patch @@ -0,0 +1,44 @@ +From 0d11fdcb36c616eb66422a4e123fcff7642542f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:17:01 +0000 +Subject: btrfs: don't clobber errors in add_remap_tree_entries() + +From: Mark Harmstone + +[ Upstream commit 44366af74061793ee5ceef455a4f0e465892d0de ] + +In add_remap_tree_entries(), we only process a certain number of entries +at a time, meaning we may need to loop. + +But because we weren't checking the return value of btrfs_insert_empty_items() +within the loop, this meant that if the last iteration of the loop +succeeded but a previous iteration failed, we were erroneously returning +0. + +Fix this by breaking the loop early if btrfs_insert_empty_items() fails. + +Fixes: b56f35560b82 ("btrfs: handle setting up relocation of block group with remap-tree") +Signed-off-by: Mark Harmstone +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/relocation.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index a6965abbab719..d8cd04fe9a4cd 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -3884,7 +3884,7 @@ static int add_remap_tree_entries(struct btrfs_trans_handle *trans, struct btrfs + ret = btrfs_insert_empty_items(trans, fs_info->remap_root, path, &batch); + btrfs_release_path(path); + +- if (num_entries <= max_items) ++ if (ret || num_entries <= max_items) + break; + + num_entries -= max_items; +-- +2.53.0 + diff --git a/queue-7.0/btrfs-fix-bytes_may_use-leak-in-do_remap_reloc_trans.patch b/queue-7.0/btrfs-fix-bytes_may_use-leak-in-do_remap_reloc_trans.patch new file mode 100644 index 0000000000..3364b065da --- /dev/null +++ b/queue-7.0/btrfs-fix-bytes_may_use-leak-in-do_remap_reloc_trans.patch @@ -0,0 +1,43 @@ +From e665c5a5a9fc6efec8008a888382781c3d9aaf1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 12:59:57 +0000 +Subject: btrfs: fix bytes_may_use leak in do_remap_reloc_trans() + +From: Mark Harmstone + +[ Upstream commit 9b8824533d75fb199a3fb0f6147ffcca64b5caf8 ] + +If the call to btrfs_reserve_extent() in do_remap_reloc_trans() returns +a smaller extent than we asked for, currently we're not undoing the +bytes_may_use change that we made. Fix this by calling +btrfs_space_info_update_bytes_may_use() again for the difference. + +Fixes: fd6594b1446c ("btrfs: replace identity remaps with actual remaps when doing relocations") +Reviewed-by: Boris Burkov +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/relocation.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 6e260ccbf50ac..a6965abbab719 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -5014,6 +5014,12 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info, + return ret; + } + ++ if (ins.offset < remap_length) { ++ spin_lock(&sinfo->lock); ++ btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - remap_length); ++ spin_unlock(&sinfo->lock); ++ } ++ + made_reservation = true; + + new_addr = ins.objectid; +-- +2.53.0 + diff --git a/queue-7.0/btrfs-fix-bytes_may_use-leak-in-move_existing_remap.patch b/queue-7.0/btrfs-fix-bytes_may_use-leak-in-move_existing_remap.patch new file mode 100644 index 0000000000..b36f8bcc15 --- /dev/null +++ b/queue-7.0/btrfs-fix-bytes_may_use-leak-in-move_existing_remap.patch @@ -0,0 +1,43 @@ +From 813bbcbc0d40eebfa76c123f54bf2ba918ee2507 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 12:59:47 +0000 +Subject: btrfs: fix bytes_may_use leak in move_existing_remap() + +From: Mark Harmstone + +[ Upstream commit 68a135013bf73dfd6a277f76fc4e088b0f3dfa79 ] + +If the call to btrfs_reserve_extent() in move_existing_remap() returns a +smaller extent than we asked for, currently we're not undoing the +bytes_may_use change that we made. Fix this by calling +btrfs_space_info_update_bytes_may_use() again for the difference. + +Fixes: bbea42dfb91f ("btrfs: move existing remaps before relocating block group") +Reviewed-by: Boris Burkov +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/relocation.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 033f74fd6225c..6e260ccbf50ac 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -4182,6 +4182,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info, + return ret; + } + ++ if (ins.offset < length) { ++ spin_lock(&sinfo->lock); ++ btrfs_space_info_update_bytes_may_use(sinfo, ins.offset - length); ++ spin_unlock(&sinfo->lock); ++ } ++ + dest_addr = ins.objectid; + dest_length = ins.offset; + +-- +2.53.0 + diff --git a/queue-7.0/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch b/queue-7.0/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch new file mode 100644 index 0000000000..98aa135537 --- /dev/null +++ b/queue-7.0/btrfs-fix-deadlock-between-reflink-and-transaction-c.patch @@ -0,0 +1,216 @@ +From db8b3f449ba829e117c26b8c45f5fca6be2c7cec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 15:50:13 +0000 +Subject: btrfs: fix deadlock between reflink and transaction commit when using + flushoncommit + +From: Filipe Manana + +[ Upstream commit b48c980b6a7e409050bb3067165db31cc6205e3e ] + +When using the flushoncommit mount option, we can have a deadlock between +a transaction commit and a reflink operation that copied an inline extent +to an offset beyond the current i_size of the destination node. + +The deadlock happens like this: + +1) Task A clones an inline extent from inode X to an offset of inode Y + that is beyond Y's current i_size. This means we copied the inline + extent's data to a folio of inode Y that is beyond its EOF, using a + call to copy_inline_to_page(); + +2) Task B starts a transaction commit and calls + btrfs_start_delalloc_flush() to flush delalloc; + +3) The delalloc flushing sees the new dirty folio of inode Y and when it + attempts to flush it, it ends up at extent_writepage() and sees that + the offset of the folio is beyond the i_size of inode Y, so it attempts + to invalidate the folio by calling folio_invalidate(), which ends up at + btrfs' folio invalidate callback - btrfs_invalidate_folio(). There it + tries to lock the folio's range in inode Y's extent io tree, but it + blocks since it's currently locked by task A - during a reflink we lock + the inodes and the source and destination ranges after flushing all + delalloc and waiting for ordered extent completion - after that we + don't expect to have dirty folios in the ranges, the exception is if + we have to copy an inline extent's data (because the destination offset + is not zero); + +4) Task A then attempts to start a transaction to update the inode item, + and then it's blocked since the current transaction is in the + TRANS_STATE_COMMIT_START state. Therefore task A has to wait for the + current transaction to become unblocked (its state >= + TRANS_STATE_UNBLOCKED). + + So task A is waiting for the transaction commit done by task B, and + the later waiting on the extent lock of inode Y that is currently + held by task A. + +Syzbot recently reported this with the following stack traces: + + INFO: task kworker/u8:7:1053 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:kworker/u8:7 state:D stack:23520 pid:1053 tgid:1053 ppid:2 task_flags:0x4208060 flags:0x00080000 + Workqueue: writeback wb_workfn (flush-btrfs-46) + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wait_extent_bit fs/btrfs/extent-io-tree.c:811 [inline] + btrfs_lock_extent_bits+0x59c/0x700 fs/btrfs/extent-io-tree.c:1914 + btrfs_lock_extent fs/btrfs/extent-io-tree.h:152 [inline] + btrfs_invalidate_folio+0x43d/0xc40 fs/btrfs/inode.c:7704 + extent_writepage fs/btrfs/extent_io.c:1852 [inline] + extent_write_cache_pages fs/btrfs/extent_io.c:2580 [inline] + btrfs_writepages+0x12ff/0x2440 fs/btrfs/extent_io.c:2713 + do_writepages+0x32e/0x550 mm/page-writeback.c:2554 + __writeback_single_inode+0x133/0x11a0 fs/fs-writeback.c:1750 + writeback_sb_inodes+0x995/0x19d0 fs/fs-writeback.c:2042 + wb_writeback+0x456/0xb70 fs/fs-writeback.c:2227 + wb_do_writeback fs/fs-writeback.c:2374 [inline] + wb_workfn+0x41a/0xf60 fs/fs-writeback.c:2414 + process_one_work kernel/workqueue.c:3276 [inline] + process_scheduled_works+0xb6e/0x18c0 kernel/workqueue.c:3359 + worker_thread+0xa53/0xfc0 kernel/workqueue.c:3440 + kthread+0x388/0x470 kernel/kthread.c:436 + ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + + INFO: task syz.4.64:6910 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:syz.4.64 state:D stack:22752 pid:6910 tgid:6905 ppid:5944 task_flags:0x400140 flags:0x00080002 + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wait_current_trans+0x39f/0x590 fs/btrfs/transaction.c:535 + start_transaction+0x6a7/0x1650 fs/btrfs/transaction.c:705 + clone_copy_inline_extent fs/btrfs/reflink.c:299 [inline] + btrfs_clone+0x128a/0x24d0 fs/btrfs/reflink.c:529 + btrfs_clone_files+0x271/0x3f0 fs/btrfs/reflink.c:750 + btrfs_remap_file_range+0x76b/0x1320 fs/btrfs/reflink.c:903 + vfs_copy_file_range+0xda7/0x1390 fs/read_write.c:1600 + __do_sys_copy_file_range fs/read_write.c:1683 [inline] + __se_sys_copy_file_range+0x2fb/0x480 fs/read_write.c:1650 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7f5f73afc799 + RSP: 002b:00007f5f7315e028 EFLAGS: 00000246 ORIG_RAX: 0000000000000146 + RAX: ffffffffffffffda RBX: 00007f5f73d75fa0 RCX: 00007f5f73afc799 + RDX: 0000000000000005 RSI: 0000000000000000 RDI: 0000000000000005 + RBP: 00007f5f73b92c99 R08: 0000000000000863 R09: 0000000000000000 + R10: 00002000000000c0 R11: 0000000000000246 R12: 0000000000000000 + R13: 00007f5f73d76038 R14: 00007f5f73d75fa0 R15: 00007fff138a5068 + + INFO: task syz.4.64:6975 blocked for more than 143 seconds. + Not tainted syzkaller #0 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:syz.4.64 state:D stack:24736 pid:6975 tgid:6905 ppid:5944 task_flags:0x400040 flags:0x00080002 + Call Trace: + + context_switch kernel/sched/core.c:5298 [inline] + __schedule+0x1553/0x5240 kernel/sched/core.c:6911 + __schedule_loop kernel/sched/core.c:6993 [inline] + schedule+0x164/0x360 kernel/sched/core.c:7008 + wb_wait_for_completion+0x3e8/0x790 fs/fs-writeback.c:227 + __writeback_inodes_sb_nr+0x24c/0x2d0 fs/fs-writeback.c:2838 + try_to_writeback_inodes_sb+0x9a/0xc0 fs/fs-writeback.c:2886 + btrfs_start_delalloc_flush fs/btrfs/transaction.c:2175 [inline] + btrfs_commit_transaction+0x82e/0x31a0 fs/btrfs/transaction.c:2364 + btrfs_ioctl+0xca7/0xd00 fs/btrfs/ioctl.c:5206 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7f5f73afc799 + RSP: 002b:00007f5f7313d028 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 + RAX: ffffffffffffffda RBX: 00007f5f73d76090 RCX: 00007f5f73afc799 + RDX: 0000000000000000 RSI: 0000000000009408 RDI: 0000000000000004 + RBP: 00007f5f73b92c99 R08: 0000000000000000 R09: 0000000000000000 + R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 + R13: 00007f5f73d76128 R14: 00007f5f73d76090 R15: 00007fff138a5068 + + +Fix this by updating the i_size of the destination inode of a reflink +operation after we copy an inline extent's data to an offset beyond the +i_size and before attempting to start a transaction to update the inode's +item. + +Reported-by: syzbot+63056bf627663701bbbf@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-btrfs/69bba3fe.050a0220.227207.002f.GAE@google.com/ +Fixes: 05a5a7621ce6 ("Btrfs: implement full reflink support for inline extents") +Reviewed-by: Boris Burkov +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/reflink.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 45 insertions(+) + +diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c +index 314cb95ba846d..55d8d238e5862 100644 +--- a/fs/btrfs/reflink.c ++++ b/fs/btrfs/reflink.c +@@ -322,6 +322,51 @@ static int clone_copy_inline_extent(struct btrfs_inode *inode, + + ret = copy_inline_to_page(inode, new_key->offset, + inline_data, size, datal, comp_type); ++ ++ /* ++ * If we copied the inline extent data to a page/folio beyond the i_size ++ * of the destination inode, then we need to increase the i_size before ++ * we start a transaction to update the inode item. This is to prevent a ++ * deadlock when the flushoncommit mount option is used, which happens ++ * like this: ++ * ++ * 1) Task A clones an inline extent from inode X to an offset of inode ++ * Y that is beyond Y's current i_size. This means we copied the ++ * inline extent's data to a folio of inode Y that is beyond its EOF, ++ * using the call above to copy_inline_to_page(); ++ * ++ * 2) Task B starts a transaction commit and calls ++ * btrfs_start_delalloc_flush() to flush delalloc; ++ * ++ * 3) The delalloc flushing sees the new dirty folio of inode Y and when ++ * it attempts to flush it, it ends up at extent_writepage() and sees ++ * that the offset of the folio is beyond the i_size of inode Y, so ++ * it attempts to invalidate the folio by calling folio_invalidate(), ++ * which ends up at btrfs' folio invalidate callback - ++ * btrfs_invalidate_folio(). There it tries to lock the folio's range ++ * in inode Y's extent io tree, but it blocks since it's currently ++ * locked by task A - during reflink we lock the inodes and the ++ * source and destination ranges after flushing all delalloc and ++ * waiting for ordered extent completion - after that we don't expect ++ * to have dirty folios in the ranges, the exception is if we have to ++ * copy an inline extent's data (because the destination offset is ++ * not zero); ++ * ++ * 4) Task A then does the 'goto out' below and attempts to start a ++ * transaction to update the inode item, and then it's blocked since ++ * the current transaction is in the TRANS_STATE_COMMIT_START state. ++ * Therefore task A has to wait for the current transaction to become ++ * unblocked (its state >= TRANS_STATE_UNBLOCKED). ++ * ++ * This leads to a deadlock - the task committing the transaction ++ * waiting for the delalloc flushing which is blocked during folio ++ * invalidation on the inode's extent lock and the reflink task waiting ++ * for the current transaction to be unblocked so that it can start a ++ * a new one to update the inode item (while holding the extent lock). ++ */ ++ if (ret == 0 && new_key->offset + datal > i_size_read(&inode->vfs_inode)) ++ i_size_write(&inode->vfs_inode, new_key->offset + datal); ++ + goto out; + } + +-- +2.53.0 + diff --git a/queue-7.0/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch b/queue-7.0/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch new file mode 100644 index 0000000000..c8b8c20cc6 --- /dev/null +++ b/queue-7.0/btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch @@ -0,0 +1,48 @@ +From f4105f25d2ba483ba40f47c9c1e9f3480d9d4b66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:15:23 +0100 +Subject: btrfs: fix double-decrement of bytes_may_use in + submit_one_async_extent() + +From: Mark Harmstone + +[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ] + +submit_one_async_extent() calls btrfs_reserve_extent(), which decrements +bytes_may_use. If the call btrfs_create_io_em() fails, we jump to +out_free_reserve, which calls extent_clear_unlock_delalloc(). + +Because we're specifying EXTENT_DO_ACCOUNTING, i.e. +EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases +bytes_may_use again. This can lead to problems later on, as an initial +write can fail only for the writeback to silently ENOSPC. + +Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. +This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved +extents in cow_one_range()"), which is the same fix in cow_one_range(). + +Fixes: 151a41bc46df ("Btrfs: fix what bits we clear when erroring out from delalloc") +Reviewed-by: Qu Wenruo +Signed-off-by: Mark Harmstone +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index c5b291ddb4776..dc2b22e65bad5 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -1245,7 +1245,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk, + NULL, &cached, + EXTENT_LOCKED | EXTENT_DELALLOC | + EXTENT_DELALLOC_NEW | +- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, ++ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV, + PAGE_UNLOCK | PAGE_START_WRITEBACK | + PAGE_END_WRITEBACK); + if (async_extent->cb) +-- +2.53.0 + diff --git a/queue-7.0/btrfs-fix-the-inline-compressed-extent-check-in-inod.patch b/queue-7.0/btrfs-fix-the-inline-compressed-extent-check-in-inod.patch new file mode 100644 index 0000000000..5aa6e02481 --- /dev/null +++ b/queue-7.0/btrfs-fix-the-inline-compressed-extent-check-in-inod.patch @@ -0,0 +1,92 @@ +From c59dfdaa070021cd3cb008d309aa054917caf485 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 10:51:09 +1030 +Subject: btrfs: fix the inline compressed extent check in + inode_need_compress() + +From: Qu Wenruo + +[ Upstream commit 883adb6dcff0f96dbbdb6488842a38b121ebd68c ] + +[BUG] +Since commit 59615e2c1f63 ("btrfs: reject single block sized compression +early"), the following script will result the inode to have NOCOMPRESS +flag, meanwhile old kernels don't: + + # mkfs.btrfs -f $dev + # mount $dev $mnt -o max_inline=2k,compress=zstd + # truncate -s 8k $mnt/foobar + # xfs_io -f -c "pwrite 0 2k" $mnt/foobar + # sync + +Before that commit, the inode will not have NOCOMPRESS flag: + + item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160 + generation 9 transid 9 size 8192 nbytes 4096 + block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0 + sequence 3 flags 0x0(none) + +But after that commit, the inode will have NOCOMPRESS flag: + + item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160 + generation 9 transid 10 size 8192 nbytes 4096 + block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0 + sequence 3 flags 0x8(NOCOMPRESS) + +This will make a lot of files no longer to be compressed. + +[CAUSE] +The old compressed inline check looks like this: + + if (total_compressed <= blocksize && + (start > 0 || end + 1 < inode->disk_i_size)) + goto cleanup_and_bail_uncompressed; + +That inline part check is equal to "!(start == 0 && end + 1 >= +inode->disk_i_size)", but the new check no longer has that disk_i_size +check. + +Thus it means any single block sized write at file offset 0 will pass +the inline check, which is wrong. + +Furthermore, since we have merged the old check into +inode_need_compress(), there is no disk_i_size based inline check +anymore, we will always try compressing that single block at file offset +0, then later find out it's not a net win and go to the +mark_incompressible tag. + +This results the inode to have NOCOMPRESS flag. + +[FIX] +Add back the missing disk_i_size based check into inode_need_compress(). + +Now the same script will no longer cause NOCOMPRESS flag. + +Fixes: 59615e2c1f63 ("btrfs: reject single block sized compression early") +Reported-by: Chris Mason +Link: https://lore.kernel.org/linux-btrfs/20260208183840.975975-1-clm@meta.com/ +Reviewed-by: Filipe Manana +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 2ad2d503e79af..c5b291ddb4776 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -811,7 +811,8 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start, + * do not even bother try compression, as there will be no space saving + * and will always fallback to regular write later. + */ +- if (start != 0 && end + 1 - start <= fs_info->sectorsize) ++ if (end + 1 - start <= fs_info->sectorsize && ++ (start > 0 || end + 1 < inode->disk_i_size)) + return 0; + /* Defrag ioctl takes precedence over mount options and properties. */ + if (inode->defrag_compress == BTRFS_DEFRAG_DONT_COMPRESS) +-- +2.53.0 + diff --git a/queue-7.0/bus-fsl-mc-use-generic-driver_override-infrastructur.patch b/queue-7.0/bus-fsl-mc-use-generic-driver_override-infrastructur.patch new file mode 100644 index 0000000000..046a6552f6 --- /dev/null +++ b/queue-7.0/bus-fsl-mc-use-generic-driver_override-infrastructur.patch @@ -0,0 +1,156 @@ +From cd575ca75b875884a44baedb0a4d7b2025e35e61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:06 +0100 +Subject: bus: fsl-mc: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit 6c8dfb0362732bf1e4829867a2a5239fedc592d0 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Tested-by: Ioana Ciornei +Acked-by: Ioana Ciornei +Acked-by: Christophe Leroy (CS GROUP) +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 1f86a00c1159 ("bus/fsl-mc: add support for 'driver_override' in the mc-bus") +Link: https://patch.msgid.link/20260324005919.2408620-3-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/bus/fsl-mc/fsl-mc-bus.c | 43 +++++-------------------------- + drivers/vfio/fsl-mc/vfio_fsl_mc.c | 4 +-- + include/linux/fsl/mc.h | 4 --- + 3 files changed, 8 insertions(+), 43 deletions(-) + +diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c +index c117745cf2065..221146e4860be 100644 +--- a/drivers/bus/fsl-mc/fsl-mc-bus.c ++++ b/drivers/bus/fsl-mc/fsl-mc-bus.c +@@ -86,12 +86,16 @@ static int fsl_mc_bus_match(struct device *dev, const struct device_driver *drv) + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); + const struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); + bool found = false; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (mc_dev->driver_override) { +- found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); ++ ret = device_match_driver_override(dev, drv); ++ if (ret > 0) { ++ found = true; + goto out; + } ++ if (ret == 0) ++ goto out; + + if (!mc_drv->match_id_table) + goto out; +@@ -210,39 +214,8 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + } + static DEVICE_ATTR_RO(modalias); + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- int ret; +- +- if (WARN_ON(dev->bus != &fsl_mc_bus_type)) +- return -EINVAL; +- +- ret = driver_set_override(dev, &mc_dev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", mc_dev->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *fsl_mc_dev_attrs[] = { + &dev_attr_modalias.attr, +- &dev_attr_driver_override.attr, + NULL, + }; + +@@ -345,6 +318,7 @@ ATTRIBUTE_GROUPS(fsl_mc_bus); + + const struct bus_type fsl_mc_bus_type = { + .name = "fsl-mc", ++ .driver_override = true, + .match = fsl_mc_bus_match, + .uevent = fsl_mc_bus_uevent, + .probe = fsl_mc_probe, +@@ -910,9 +884,6 @@ static struct notifier_block fsl_mc_nb; + */ + void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) + { +- kfree(mc_dev->driver_override); +- mc_dev->driver_override = NULL; +- + /* + * The device-specific remove callback will get invoked by device_del() + */ +diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c +index 462fae1aa5385..b4c3958201b25 100644 +--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c ++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c +@@ -424,9 +424,7 @@ static int vfio_fsl_mc_bus_notifier(struct notifier_block *nb, + + if (action == BUS_NOTIFY_ADD_DEVICE && + vdev->mc_dev == mc_cont) { +- mc_dev->driver_override = kasprintf(GFP_KERNEL, "%s", +- vfio_fsl_mc_ops.name); +- if (!mc_dev->driver_override) ++ if (device_set_driver_override(dev, vfio_fsl_mc_ops.name)) + dev_warn(dev, "VFIO_FSL_MC: Setting driver override for device in dprc %s failed\n", + dev_name(&mc_cont->dev)); + else +diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h +index 897d6211c1635..1da63f2d70401 100644 +--- a/include/linux/fsl/mc.h ++++ b/include/linux/fsl/mc.h +@@ -178,9 +178,6 @@ struct fsl_mc_obj_desc { + * @regions: pointer to array of MMIO region entries + * @irqs: pointer to array of pointers to interrupts allocated to this device + * @resource: generic resource associated with this MC object device, if any. +- * @driver_override: driver name to force a match; do not set directly, +- * because core frees it; use driver_set_override() to +- * set or clear it. + * + * Generic device object for MC object devices that are "attached" to a + * MC bus. +@@ -214,7 +211,6 @@ struct fsl_mc_device { + struct fsl_mc_device_irq **irqs; + struct fsl_mc_resource *resource; + struct device_link *consumer_link; +- const char *driver_override; + }; + + #define to_fsl_mc_device(_dev) \ +-- +2.53.0 + diff --git a/queue-7.0/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch b/queue-7.0/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch new file mode 100644 index 0000000000..b204ffe871 --- /dev/null +++ b/queue-7.0/bus-rifsc-fix-rif-configuration-check-for-peripheral.patch @@ -0,0 +1,102 @@ +From c67f07c6e6ff90579787f9253da9d1743e74d5aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 13:56:17 +0100 +Subject: bus: rifsc: fix RIF configuration check for peripherals + +From: Gatien Chevallier + +[ Upstream commit d5ce3b4e951bc41a6ce877c8500bb4fe42146669 ] + +Peripheral holding CID0 cannot be accessed, remove this completely +incorrect check. While there, fix and simplify the semaphore checking +that should be performed when the CID filtering is enabled. + +Fixes: a18208457253 ("bus: rifsc: introduce RIFSC firewall controller driver") +Signed-off-by: Gatien Chevallier +Link: https://lore.kernel.org/r/20260129-fix_cid_check_rifsc-v1-1-ef280ccf764d@foss.st.com +Signed-off-by: Alexandre Torgue +Signed-off-by: Sasha Levin +--- + drivers/bus/stm32_rifsc.c | 52 ++++++++++++++------------------------- + 1 file changed, 18 insertions(+), 34 deletions(-) + +diff --git a/drivers/bus/stm32_rifsc.c b/drivers/bus/stm32_rifsc.c +index debeaf8ea1bd2..5682c086ba1e8 100644 +--- a/drivers/bus/stm32_rifsc.c ++++ b/drivers/bus/stm32_rifsc.c +@@ -688,34 +688,6 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 + sec_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_SECCFGR0 + 0x4 * reg_id); + cid_reg_value = readl(rifsc_controller->mmio + RIFSC_RISC_PER0_CIDCFGR + 0x8 * firewall_id); + +- /* First check conditions for semaphore mode, which doesn't take into account static CID. */ +- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) { +- if (cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT)) { +- /* Static CID is irrelevant if semaphore mode */ +- goto skip_cid_check; +- } else { +- dev_dbg(rifsc_controller->dev, +- "Invalid bus semaphore configuration: index %d\n", firewall_id); +- return -EACCES; +- } +- } +- +- /* +- * Skip CID check if CID filtering isn't enabled or filtering is enabled on CID0, which +- * corresponds to whatever CID. +- */ +- if (!(cid_reg_value & CIDCFGR_CFEN) || +- FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) == RIF_CID0) +- goto skip_cid_check; +- +- /* Coherency check with the CID configuration */ +- if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) { +- dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n", +- firewall_id); +- return -EACCES; +- } +- +-skip_cid_check: + /* Check security configuration */ + if (sec_reg_value & BIT(reg_offset)) { + dev_dbg(rifsc_controller->dev, +@@ -723,19 +695,31 @@ static int stm32_rifsc_grant_access(struct stm32_firewall_controller *ctrl, u32 + return -EACCES; + } + +- /* +- * If the peripheral is in semaphore mode, take the semaphore so that +- * the CID1 has the ownership. +- */ +- if ((cid_reg_value & CIDCFGR_SEMEN) && (cid_reg_value & CIDCFGR_CFEN)) { ++ /* Skip CID check if CID filtering isn't enabled */ ++ if (!(cid_reg_value & CIDCFGR_CFEN)) ++ goto skip_cid_check; ++ ++ /* First check conditions for semaphore mode, which doesn't take into account static CID. */ ++ if (cid_reg_value & CIDCFGR_SEMEN) { ++ if (!(cid_reg_value & BIT(RIF_CID1 + SEMWL_SHIFT))) { ++ dev_dbg(rifsc_controller->dev, ++ "Invalid bus semaphore configuration: index %d\n", firewall_id); ++ return -EACCES; ++ } ++ + rc = stm32_rif_acquire_semaphore(rifsc_controller, firewall_id); + if (rc) { +- dev_err(rifsc_controller->dev, ++ dev_dbg(rifsc_controller->dev, + "Couldn't acquire semaphore for peripheral: %d\n", firewall_id); + return rc; + } ++ } else if (FIELD_GET(RIFSC_RISC_SCID_MASK, cid_reg_value) != RIF_CID1) { ++ dev_dbg(rifsc_controller->dev, "Invalid CID configuration for peripheral: %d\n", ++ firewall_id); ++ return -EACCES; + } + ++skip_cid_check: + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch b/queue-7.0/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch new file mode 100644 index 0000000000..c3243f616a --- /dev/null +++ b/queue-7.0/cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch @@ -0,0 +1,237 @@ +From 8a7780d1ec2c5c3bd40b6ae828526d246fda2ee9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:01:39 +0100 +Subject: cdrom, scsi: sr: propagate read-only status to block layer via + set_disk_ro() + +From: Daan De Meyer + +[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ] + +The cdrom core never calls set_disk_ro() for a registered device, so +BLKROGET on a CD-ROM device always returns 0 (writable), even when the +drive has no write capabilities and writes will inevitably fail. This +causes problems for userspace that relies on BLKROGET to determine +whether a block device is read-only. For example, systemd's loop device +setup uses BLKROGET to decide whether to create a loop device with +LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the +loop device to the CD-ROM and fail with I/O errors. systemd-fsck +similarly checks BLKROGET to decide whether to run fsck in no-repair +mode (-n). + +The write-capability bits in cdi->mask come from two different sources: +CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE +SENSE capabilities page (page 0x2A) before register_cdrom() is called, +while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command +and were only probed by cdrom_open_write() at device open time. This +meant that any attempt to compute the writable state from the full +mask at probe time was incorrect, because the GET CONFIGURATION bits +were still unset (and cdi->mask is initialized such that capabilities +are assumed present). + +Fix this by factoring the GET CONFIGURATION probing out of +cdrom_open_write() into a new exported helper, +cdrom_probe_write_features(), and having sr call it from sr_probe() +right after get_capabilities() has populated the MODE SENSE bits. +register_cdrom() then calls set_disk_ro() based on the full +write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) +so the block layer reflects the drive's actual write support. The +feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with +RT=00) report drive-level capabilities that are persistent across +media, so a single probe before register_cdrom() is sufficient and the +redundant probe at open time is dropped. + +With set_disk_ro() now accurate, the long-vestigial cd->writeable flag +in sr can go: get_capabilities() used to set cd->writeable based on +the same four mask bits, but because CDC_MRW_W and CDC_RAM default to +"capability present" in cdi->mask and aren't touched by MODE SENSE, +the condition that gated cd->writeable was always true, making it +unconditionally 1. Replace the corresponding gate in sr_init_command() +with get_disk_ro(cd->disk), which turns a previously no-op check into +a real one and also catches kernel-internal bio writers that bypass +blkdev_write_iter()'s bdev_read_only() check. + +The sd driver (SCSI disks) does not have this problem because it +checks the MODE SENSE Write Protect bit and calls set_disk_ro() +accordingly. The sr driver cannot use the same approach because the +MMC specification does not define the WP bit in the MODE SENSE +device-specific parameter byte for CD-ROM devices. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Daan De Meyer +Reviewed-by: Phillip Potter +Reviewed-by: Martin K. Petersen +Signed-off-by: Phillip Potter +Link: https://patch.msgid.link/20260427210139.1400-2-phil@philpotter.co.uk +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- + drivers/scsi/sr.c | 11 ++----- + drivers/scsi/sr.h | 1 - + include/linux/cdrom.h | 1 + + 4 files changed, 51 insertions(+), 35 deletions(-) + +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index fc049612d6dc1..62934cf4b10de 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi) + + WARN_ON(!cdo->generic_packet); + ++ /* ++ * Propagate the drive's write support to the block layer so BLKROGET ++ * reflects actual write capability. Drivers that use GET CONFIGURATION ++ * features (CDC_MRW_W, CDC_RAM) must have called ++ * cdrom_probe_write_features() before register_cdrom() so the mask is ++ * complete here. ++ */ ++ set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | ++ CDC_CD_RW)); ++ + cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + mutex_lock(&cdrom_mutex); + list_add(&cdi->list, &cdrom_list); +@@ -742,6 +752,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) + return 0; + } + ++/* ++ * Probe write-related MMC features via GET CONFIGURATION and update ++ * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE ++ * capabilities page (e.g. sr) should call this after those MODE SENSE bits ++ * have been set but before register_cdrom(), so that the full set of ++ * write-capability bits is known by the time register_cdrom() decides on the ++ * initial read-only state of the disk. ++ */ ++void cdrom_probe_write_features(struct cdrom_device_info *cdi) ++{ ++ int mrw, mrw_write, ram_write; ++ ++ mrw = 0; ++ if (!cdrom_is_mrw(cdi, &mrw_write)) ++ mrw = 1; ++ ++ if (CDROM_CAN(CDC_MO_DRIVE)) ++ ram_write = 1; ++ else ++ (void) cdrom_is_random_writable(cdi, &ram_write); ++ ++ if (mrw) ++ cdi->mask &= ~CDC_MRW; ++ else ++ cdi->mask |= CDC_MRW; ++ ++ if (mrw_write) ++ cdi->mask &= ~CDC_MRW_W; ++ else ++ cdi->mask |= CDC_MRW_W; ++ ++ if (ram_write) ++ cdi->mask &= ~CDC_RAM; ++ else ++ cdi->mask |= CDC_RAM; ++} ++EXPORT_SYMBOL(cdrom_probe_write_features); ++ + static int cdrom_media_erasable(struct cdrom_device_info *cdi) + { + disc_information di; +@@ -894,33 +942,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) + */ + static int cdrom_open_write(struct cdrom_device_info *cdi) + { +- int mrw, mrw_write, ram_write; + int ret = 1; + +- mrw = 0; +- if (!cdrom_is_mrw(cdi, &mrw_write)) +- mrw = 1; +- +- if (CDROM_CAN(CDC_MO_DRIVE)) +- ram_write = 1; +- else +- (void) cdrom_is_random_writable(cdi, &ram_write); +- +- if (mrw) +- cdi->mask &= ~CDC_MRW; +- else +- cdi->mask |= CDC_MRW; +- +- if (mrw_write) +- cdi->mask &= ~CDC_MRW_W; +- else +- cdi->mask |= CDC_MRW_W; +- +- if (ram_write) +- cdi->mask &= ~CDC_RAM; +- else +- cdi->mask |= CDC_RAM; +- + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index 7adb2573f50d4..c36c54ecd354b 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) + + switch (req_op(rq)) { + case REQ_OP_WRITE: +- if (!cd->writeable) ++ if (get_disk_ro(cd->disk)) + goto out; + SCpnt->cmnd[0] = WRITE_10; + cd->cdi.media_written = 1; +@@ -681,6 +681,7 @@ static int sr_probe(struct scsi_device *sdev) + error = -ENOMEM; + if (get_capabilities(cd)) + goto fail_minor; ++ cdrom_probe_write_features(&cd->cdi); + sr_vendor_init(cd); + + set_capacity(disk, cd->capacity); +@@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd) + /*else I don't think it can close its tray + cd->cdi.mask |= CDC_CLOSE_TRAY; */ + +- /* +- * if DVD-RAM, MRW-W or CD-RW, we are randomly writable +- */ +- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != +- (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { +- cd->writeable = 1; +- } +- + kfree(buffer); + return 0; + } +diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h +index dc899277b3a44..2d92f9cb6fec7 100644 +--- a/drivers/scsi/sr.h ++++ b/drivers/scsi/sr.h +@@ -35,7 +35,6 @@ typedef struct scsi_cd { + struct scsi_device *device; + unsigned int vendor; /* vendor code, see sr_vendor.c */ + unsigned long ms_offset; /* for reading multisession-CD's */ +- unsigned writeable : 1; + unsigned use:1; /* is this device still supportable */ + unsigned xa_flag:1; /* CD has XA sectors ? */ + unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ +diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h +index b907e6c2307d8..260d7968cf720 100644 +--- a/include/linux/cdrom.h ++++ b/include/linux/cdrom.h +@@ -108,6 +108,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, + extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, + unsigned int clearing); + ++extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); + extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); + extern void unregister_cdrom(struct cdrom_device_info *cdi); + +-- +2.53.0 + diff --git a/queue-7.0/cgroup-cpuset-record-dl-bw-alloc-cpu-for-attach-roll.patch b/queue-7.0/cgroup-cpuset-record-dl-bw-alloc-cpu-for-attach-roll.patch new file mode 100644 index 0000000000..d2f5caff57 --- /dev/null +++ b/queue-7.0/cgroup-cpuset-record-dl-bw-alloc-cpu-for-attach-roll.patch @@ -0,0 +1,107 @@ +From c7f5ac66e4501befa6e340676dfa13fdcd84ef0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 11:37:41 +0800 +Subject: cgroup/cpuset: record DL BW alloc CPU for attach rollback + +From: Guopeng Zhang + +[ Upstream commit 41d701ddc36d5301b44ea79529f3cf03c541c1e1 ] + +cpuset_can_attach() allocates DL bandwidth only when migrating +deadline tasks to a disjoint CPU mask, but cpuset_cancel_attach() +rolls back based only on nr_migrate_dl_tasks. This makes the DL +bandwidth alloc/free paths asymmetric: rollback can call dl_bw_free() +even when no dl_bw_alloc() was done. + +Rollback also needs to undo the reservation against the same CPU/root +domain that was charged. Record the CPU used by dl_bw_alloc() and use +that state in cpuset_cancel_attach(). If no allocation happened, +dl_bw_cpu stays at -1 and rollback skips dl_bw_free(). If allocation +did happen, bandwidth is returned to the same CPU/root domain. + +Successful attach paths are unchanged. This only fixes failed attach +rollback accounting. + +Fixes: 2ef269ef1ac0 ("cgroup/cpuset: Free DL BW in case can_attach() fails") +Signed-off-by: Guopeng Zhang +Reviewed-by: Waiman Long +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cpuset-internal.h | 5 +++++ + kernel/cgroup/cpuset.c | 13 +++++++++---- + 2 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h +index fd7d19842ded7..bb4e692bea300 100644 +--- a/kernel/cgroup/cpuset-internal.h ++++ b/kernel/cgroup/cpuset-internal.h +@@ -168,6 +168,11 @@ struct cpuset { + int nr_deadline_tasks; + int nr_migrate_dl_tasks; + u64 sum_migrate_dl_bw; ++ /* ++ * CPU used for temporary DL bandwidth allocation during attach; ++ * -1 if no DL bandwidth was allocated in the current attach. ++ */ ++ int dl_bw_cpu; + + /* Invalid partition error code, not lock protected */ + enum prs_errcode prs_err; +diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c +index 1335e437098e8..e3a081a07c6d5 100644 +--- a/kernel/cgroup/cpuset.c ++++ b/kernel/cgroup/cpuset.c +@@ -288,6 +288,7 @@ struct cpuset top_cpuset = { + .flags = BIT(CS_CPU_EXCLUSIVE) | + BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE), + .partition_root_state = PRS_ROOT, ++ .dl_bw_cpu = -1, + }; + + /** +@@ -579,6 +580,8 @@ static struct cpuset *dup_or_alloc_cpuset(struct cpuset *cs) + if (!trial) + return NULL; + ++ trial->dl_bw_cpu = -1; ++ + /* Setup cpumask pointer array */ + cpumask_var_t *pmask[4] = { + &trial->cpus_allowed, +@@ -2980,6 +2983,7 @@ static void reset_migrate_dl_data(struct cpuset *cs) + { + cs->nr_migrate_dl_tasks = 0; + cs->sum_migrate_dl_bw = 0; ++ cs->dl_bw_cpu = -1; + } + + /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */ +@@ -3056,6 +3060,8 @@ static int cpuset_can_attach(struct cgroup_taskset *tset) + reset_migrate_dl_data(cs); + goto out_unlock; + } ++ ++ cs->dl_bw_cpu = cpu; + } + + out_success: +@@ -3080,12 +3086,11 @@ static void cpuset_cancel_attach(struct cgroup_taskset *tset) + mutex_lock(&cpuset_mutex); + dec_attach_in_progress_locked(cs); + +- if (cs->nr_migrate_dl_tasks) { +- int cpu = cpumask_any(cs->effective_cpus); ++ if (cs->dl_bw_cpu >= 0) ++ dl_bw_free(cs->dl_bw_cpu, cs->sum_migrate_dl_bw); + +- dl_bw_free(cpu, cs->sum_migrate_dl_bw); ++ if (cs->nr_migrate_dl_tasks) + reset_migrate_dl_data(cs); +- } + + mutex_unlock(&cpuset_mutex); + } +-- +2.53.0 + diff --git a/queue-7.0/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch b/queue-7.0/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch new file mode 100644 index 0000000000..59a45c7bc1 --- /dev/null +++ b/queue-7.0/cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch @@ -0,0 +1,47 @@ +From 712c14f41d9b839789eeb512731d737a987b641f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 09:53:27 +0800 +Subject: cgroup/rdma: fix integer overflow in rdmacg_try_charge() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: cuitao + +[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ] + +The expression `rpool->resources[index].usage + 1` is computed in int +arithmetic before being assigned to s64 variable `new`. When usage equals +INT_MAX (the default "max" value), the addition overflows to INT_MIN. +This negative value then passes the `new > max` check incorrectly, +allowing a charge that should be rejected and corrupting usage to +negative. + +Fix by casting usage to s64 before the addition so the arithmetic is +done in 64-bit. + +Fixes: 39d3e7584a68 ("rdmacg: Added rdma cgroup controller") +Signed-off-by: cuitao +Reviewed-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c +index 09258eebb5c74..7d21a0db3cef0 100644 +--- a/kernel/cgroup/rdma.c ++++ b/kernel/cgroup/rdma.c +@@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, + ret = PTR_ERR(rpool); + goto err; + } else { +- new = rpool->resources[index].usage + 1; ++ new = (s64)rpool->resources[index].usage + 1; + if (new > rpool->resources[index].max) { + ret = -EAGAIN; + goto err; +-- +2.53.0 + diff --git a/queue-7.0/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch b/queue-7.0/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch new file mode 100644 index 0000000000..d5122fd13e --- /dev/null +++ b/queue-7.0/clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch @@ -0,0 +1,58 @@ +From 1b3994e39bb95d2d91a3d6daebafc0dc6cf6d23d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:58 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in + of_assigned_ldb_sels() + +From: Felix Gu + +[ Upstream commit 9faf207208951460f3f7eefbc112246c8d28ff1b ] + +The function of_assigned_ldb_sels() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing a memory +leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 5d283b083800 ("clk: imx6: Fix procedure to switch the parent of LDB_DI_CLK") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-2-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index 5549ef6c31173..35e6b59c01dbe 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -188,9 +188,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + } + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: parent clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + parent = clkspec.args[0]; ++ of_node_put(clkspec.np); + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); +@@ -198,9 +200,11 @@ static void of_assigned_ldb_sels(struct device_node *node, + return; + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: child clock %d not in ccm\n", index); ++ of_node_put(clkspec.np); + return; + } + child = clkspec.args[0]; ++ of_node_put(clkspec.np); + + if (child != IMX6QDL_CLK_LDB_DI0_SEL && + child != IMX6QDL_CLK_LDB_DI1_SEL) +-- +2.53.0 + diff --git a/queue-7.0/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch b/queue-7.0/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch new file mode 100644 index 0000000000..55f70d01cf --- /dev/null +++ b/queue-7.0/clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch @@ -0,0 +1,56 @@ +From 75994c0385b81ba9751acfb7539928daad8d1a20 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 22:07:57 +0800 +Subject: clk: imx: imx6q: Fix device node reference leak in pll6_bypassed() + +From: Felix Gu + +[ Upstream commit 4b84d496c804b470124cd3a08e928df6801d8eae ] + +The function pll6_bypassed() calls of_parse_phandle_with_args() +but never calls of_node_put() to release the reference, causing +a memory leak. + +Fix this by adding proper cleanup calls on all exit paths. + +Fixes: 3cc48976e9763 ("clk: imx6q: handle ENET PLL bypass") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260203-clk-imx6q-v3-1-6cd2696bb371@gmail.com +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx6q.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c +index f726c00aba721..5549ef6c31173 100644 +--- a/drivers/clk/imx/clk-imx6q.c ++++ b/drivers/clk/imx/clk-imx6q.c +@@ -238,8 +238,11 @@ static bool pll6_bypassed(struct device_node *node) + return false; + + if (clkspec.np == node && +- clkspec.args[0] == IMX6QDL_PLL6_BYPASS) ++ clkspec.args[0] == IMX6QDL_PLL6_BYPASS) { ++ of_node_put(clkspec.np); + break; ++ } ++ of_node_put(clkspec.np); + } + + /* PLL6 bypass is not part of the assigned clock list */ +@@ -249,6 +252,9 @@ static bool pll6_bypassed(struct device_node *node) + ret = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + ++ if (!ret) ++ of_node_put(clkspec.np); ++ + if (clkspec.args[0] != IMX6QDL_CLK_PLL6) + return true; + +-- +2.53.0 + diff --git a/queue-7.0/clk-imx8mq-correct-the-csi-phy-sels.patch b/queue-7.0/clk-imx8mq-correct-the-csi-phy-sels.patch new file mode 100644 index 0000000000..811d2d8582 --- /dev/null +++ b/queue-7.0/clk-imx8mq-correct-the-csi-phy-sels.patch @@ -0,0 +1,49 @@ +From 86d8abe67bbe486039eb46a6087509a112ffaa02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 00:47:21 +0100 +Subject: clk: imx8mq: Correct the CSI PHY sels + +From: Sebastian Krzyszkowiak + +[ Upstream commit d16f57caa78776e6e8a88b96cb2597797b376138 ] + +According to i.MX 8M Quad Reference Manual (Section 5.1.2 Table 5-1) +MIPI_CSI1_PHY_REF_CLK_ROOT and MIPI_CSI2_PHY_REF_CLK_ROOT have +SYSTEM_PLL2_DIV3 available as their second source, which corresponds +to sys2_pll_333m rather than sys2_pll_125m. + +Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") +Signed-off-by: Sebastian Krzyszkowiak +Reviewed-by: Peng Fan +Link: https://patch.msgid.link/20260128-imx8mq-csi-clk-v1-1-ac028ed26e8c@puri.sm +Signed-off-by: Abel Vesa +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c +index f70ed231b92d6..cedc8a02aa1f0 100644 +--- a/drivers/clk/imx/clk-imx8mq.c ++++ b/drivers/clk/imx/clk-imx8mq.c +@@ -237,7 +237,7 @@ static const char * const imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", " + static const char * const imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +@@ -246,7 +246,7 @@ static const char * const imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", + static const char * const imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m", + "sys2_pll_1000m", "sys3_pll_out", "audio_pll2_out", "video_pll1_out", }; + +-static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m", ++static const char * const imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_333m", "sys2_pll_100m", "sys1_pll_800m", + "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", }; + + static const char * const imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m", +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-01-sa8775p-fix-dsi-byte-clock-rate-s.patch b/queue-7.0/clk-qcom-dispcc-01-sa8775p-fix-dsi-byte-clock-rate-s.patch new file mode 100644 index 0000000000..8d6dd47a82 --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-01-sa8775p-fix-dsi-byte-clock-rate-s.patch @@ -0,0 +1,81 @@ +From 5bbae06caa90057ee89cc8465f48802be730e27a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:31 +0100 +Subject: clk: qcom: dispcc[01]-sa8775p: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit 2851b6c6a42e22c243aa4cd606a49e2b9acfb6d6 ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: e700bfd2f976 ("clk: qcom: Add support for Display clock Controllers on SA8775P") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-5-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc0-sa8775p.c | 2 -- + drivers/clk/qcom/dispcc1-sa8775p.c | 2 -- + 2 files changed, 4 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc0-sa8775p.c b/drivers/clk/qcom/dispcc0-sa8775p.c +index aeda9cf4bfee8..b248fa9705873 100644 +--- a/drivers/clk/qcom/dispcc0-sa8775p.c ++++ b/drivers/clk/qcom/dispcc0-sa8775p.c +@@ -591,7 +591,6 @@ static struct clk_regmap_div mdss_0_disp_cc_mdss_byte0_div_clk_src = { + &mdss_0_disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -606,7 +605,6 @@ static struct clk_regmap_div mdss_0_disp_cc_mdss_byte1_div_clk_src = { + &mdss_0_disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +diff --git a/drivers/clk/qcom/dispcc1-sa8775p.c b/drivers/clk/qcom/dispcc1-sa8775p.c +index cd55d1c119024..9882edbb79f9e 100644 +--- a/drivers/clk/qcom/dispcc1-sa8775p.c ++++ b/drivers/clk/qcom/dispcc1-sa8775p.c +@@ -591,7 +591,6 @@ static struct clk_regmap_div mdss_1_disp_cc_mdss_byte0_div_clk_src = { + &mdss_1_disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -606,7 +605,6 @@ static struct clk_regmap_div mdss_1_disp_cc_mdss_byte1_div_clk_src = { + &mdss_1_disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-glymur-fix-dsi-byte-clock-rate-setti.patch b/queue-7.0/clk-qcom-dispcc-glymur-fix-dsi-byte-clock-rate-setti.patch new file mode 100644 index 0000000000..6b7fb45cc5 --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-glymur-fix-dsi-byte-clock-rate-setti.patch @@ -0,0 +1,60 @@ +From dafdae8a1c1a730b3e0a9aca4e754860bcce5d78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:27 +0100 +Subject: clk: qcom: dispcc-glymur: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit 98ea9eda030587601db56425efcd32263d853591 ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: b4d15211c408 ("clk: qcom: dispcc-glymur: Add support for Display Clock Controller") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-1-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-glymur.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-glymur.c b/drivers/clk/qcom/dispcc-glymur.c +index f352165bf56fc..bef74f58405ba 100644 +--- a/drivers/clk/qcom/dispcc-glymur.c ++++ b/drivers/clk/qcom/dispcc-glymur.c +@@ -747,7 +747,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -762,7 +761,6 @@ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-glymur-use-rcg2-ops-for-dptx1-aux-cl.patch b/queue-7.0/clk-qcom-dispcc-glymur-use-rcg2-ops-for-dptx1-aux-cl.patch new file mode 100644 index 0000000000..e2c71c1164 --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-glymur-use-rcg2-ops-for-dptx1-aux-cl.patch @@ -0,0 +1,41 @@ +From d00aa73f5783f27524d55f658f3e085a7c21ac70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 04:12:22 +0200 +Subject: clk: qcom: dispcc-glymur: use RCG2 ops for DPTX1 AUX clock source + +From: Dmitry Baryshkov + +[ Upstream commit e7c8eb1646db5d967d77ee67793dd95a2c5ff451 ] + +The clk_dp_ops are supposed to be used for DP-related clocks with a +proper MND divier. Use shared RCG2 ops for dptx1_aux_clk_src, the same +as all other DPTX AUX clocks in this driver. + +Fixes: b4d15211c408 ("clk: qcom: dispcc-glymur: Add support for Display Clock Controller") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260112-dp-aux-clks-v1-1-456b0c11b069@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-glymur.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-glymur.c b/drivers/clk/qcom/dispcc-glymur.c +index 5203fa6383f6a..f352165bf56fc 100644 +--- a/drivers/clk/qcom/dispcc-glymur.c ++++ b/drivers/clk/qcom/dispcc-glymur.c +@@ -417,7 +417,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_dp_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-kaanapali-fix-dsi-byte-clock-rate-se.patch b/queue-7.0/clk-qcom-dispcc-kaanapali-fix-dsi-byte-clock-rate-se.patch new file mode 100644 index 0000000000..638c29972f --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-kaanapali-fix-dsi-byte-clock-rate-se.patch @@ -0,0 +1,60 @@ +From 6cac91ae858c903240e95829f56b6d1fd09fd38c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:28 +0100 +Subject: clk: qcom: dispcc-kaanapali: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit e892f4e3f3d558ce5d7595dca7cce2bd170a19fa ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: 6c6750b7061c ("clk: qcom: dispcc: Add support for display clock controller Kaanapali") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-2-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-kaanapali.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-kaanapali.c b/drivers/clk/qcom/dispcc-kaanapali.c +index baae2ec1f72aa..c1578cd07041b 100644 +--- a/drivers/clk/qcom/dispcc-kaanapali.c ++++ b/drivers/clk/qcom/dispcc-kaanapali.c +@@ -800,7 +800,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -815,7 +814,6 @@ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { + &disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-milos-fix-dsi-byte-clock-rate-settin.patch b/queue-7.0/clk-qcom-dispcc-milos-fix-dsi-byte-clock-rate-settin.patch new file mode 100644 index 0000000000..fe9a12c733 --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-milos-fix-dsi-byte-clock-rate-settin.patch @@ -0,0 +1,52 @@ +From 160e89829c4c9e072041bb70f11b939ae1ef22f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:29 +0100 +Subject: clk: qcom: dispcc-milos: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit dd5b76257b4048151006620c9895e2f5f0d997eb ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: f40b5217dce1 ("clk: qcom: Add Display Clock controller (DISPCC) driver for Milos") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-3-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-milos.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-milos.c b/drivers/clk/qcom/dispcc-milos.c +index 95b6dd89d9ae3..339cb1c63ba77 100644 +--- a/drivers/clk/qcom/dispcc-milos.c ++++ b/drivers/clk/qcom/dispcc-milos.c +@@ -394,7 +394,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch b/queue-7.0/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch new file mode 100644 index 0000000000..9e87047246 --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch @@ -0,0 +1,74 @@ +From e766ddc43cde8512ebb4edec29d8712de731ee12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 19:55:50 +0800 +Subject: clk: qcom: dispcc-sc8280xp: remove CLK_SET_RATE_PARENT from + byte_div_clk_src dividers + +From: White Lewis + +[ Upstream commit 0b151a6307205eb867250985a910a88787cbf12e ] + +The four byte_div_clk_src dividers (disp{0,1}_cc_mdss_byte{0,1}_div_clk_src) +had CLK_SET_RATE_PARENT set. When the DSI driver calls clk_set_rate() on +byte_intf_clk, the rate-change propagates through the divider up to the +parent PLL (byte_clk_src), halving the byte clock rate. + +A simiar issue had been also encountered on SM8750. +b8501febdc51 ("clk: qcom: dispcc-sm8750: Drop incorrect CLK_SET_RATE_PARENT on byte intf parent"). + +Likewise, remove CLK_SET_RATE_PARENT from all four byte divider clocks +so that clk_set_rate() on the divider adjusts only the divider ratio, +leaving the parent PLL untouched. + +Fixes: 4a66e76fdb6d ("clk: qcom: Add SC8280XP display clock controller") +Signed-off-by: White Lewis +[pengyu: reword] +Signed-off-by: Pengyu Luo +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260303115550.9279-1-mitltlatltl@gmail.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sc8280xp.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sc8280xp.c b/drivers/clk/qcom/dispcc-sc8280xp.c +index 5903a759d4af4..e91dfed0f37e9 100644 +--- a/drivers/clk/qcom/dispcc-sc8280xp.c ++++ b/drivers/clk/qcom/dispcc-sc8280xp.c +@@ -1160,7 +1160,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte0_div_clk_src = { + &disp0_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1175,7 +1174,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte0_div_clk_src = { + &disp1_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1190,7 +1188,6 @@ static struct clk_regmap_div disp0_cc_mdss_byte1_div_clk_src = { + &disp0_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +@@ -1205,7 +1202,6 @@ static struct clk_regmap_div disp1_cc_mdss_byte1_div_clk_src = { + &disp1_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch b/queue-7.0/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch new file mode 100644 index 0000000000..014015f5a5 --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch @@ -0,0 +1,52 @@ +From 5429413fa9e9f4028a8d777c2b5394a727a1b705 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 14:48:30 +0100 +Subject: clk: qcom: dispcc-sm4450: Fix DSI byte clock rate setting +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Konrad Dybcio + +[ Upstream commit 7bc48fcdf9e77bf68ef04af015d50df2a9acac00 ] + +The clock tree for byte_clk_src is as follows: + + ┌──────byte0_clk_src─────┐ + │ │ +byte0_clk byte0_div_clk_src + │ + byte0_intf_clk + +If both of its direct children have CLK_SET_RATE_PARENT with different +requests, byte0_clk_src (and its parent) will be reconfigured. In this +case, byte0_intf should strictly follow the rate of byte0_clk (with +some adjustments based on PHY mode). + +Remove CLK_SET_RATE_PARENT from byte0_div_clk_src to avoid this issue. + +Fixes: 76f05f1ec766 ("clk: qcom: Add DISPCC driver support for SM4450") +Signed-off-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260304-topic-dsi_byte_fixup-v1-4-b79b29f83176@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm4450.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm4450.c b/drivers/clk/qcom/dispcc-sm4450.c +index e8752d01c8e62..2fdacc26df698 100644 +--- a/drivers/clk/qcom/dispcc-sm4450.c ++++ b/drivers/clk/qcom/dispcc-sm4450.c +@@ -335,7 +335,6 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { + &disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, +- .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch b/queue-7.0/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch new file mode 100644 index 0000000000..0a07d3cf47 --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch @@ -0,0 +1,48 @@ +From 38a09651387b6f410aaa658e42eb749fa287d808 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:13 -0300 +Subject: clk: qcom: dispcc-sm8250: Enable parents for pixel clocks + +From: Val Packett + +[ Upstream commit acf7a91d0b0e9e3ef374944021de62062125b7e4 ] + +Add CLK_OPS_PARENT_ENABLE to MDSS pixel clock sources to ensure parent +clocks are enabled during clock operations, preventing potential +stability issues during display configuration. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-9-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index cdfdb2cfb02b2..e59cdadd56479 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -578,7 +578,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { + .name = "disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +@@ -592,7 +592,7 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { + .name = "disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_6), +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + .ops = &clk_pixel_ops, + }, + }; +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch b/queue-7.0/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch new file mode 100644 index 0000000000..2587c1ed93 --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch @@ -0,0 +1,45 @@ +From 3ca64979422eb7cb668c5e652c04276baa920ab6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:12 -0300 +Subject: clk: qcom: dispcc-sm8250: Use shared ops on the mdss vsync clk + +From: Val Packett + +[ Upstream commit 8c522da70f0c2e5148c4c13ccb1c64cca57a6fdb ] + +mdss_gdsc can get stuck on boot due to RCGs being left on from last boot. +As a fix, commit 01a0a6cc8cfd ("clk: qcom: Park shared RCGs upon +registration") introduced a callback to ensure the RCG is off upon init. +However, the fix depends on all shared RCGs being marked as such in code. + +For SM8150/SC8180X/SM8250 the MDSS vsync clock was using regular ops, +unlike the same clock in the SC7180 code. This was causing display to +frequently fail to initialize after rebooting on the Surface Pro X. +Fix by using shared ops for this clock. + +Fixes: 80a18f4a8567 ("clk: qcom: Add display clock controller driver for SM8150 and SM8250") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20260312112321.370983-8-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8250.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c +index 8f433e1e70283..cdfdb2cfb02b2 100644 +--- a/drivers/clk/qcom/dispcc-sm8250.c ++++ b/drivers/clk/qcom/dispcc-sm8250.c +@@ -632,7 +632,7 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_rcg2_ops, ++ .ops = &clk_rcg2_shared_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch b/queue-7.0/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch new file mode 100644 index 0000000000..beff4122da --- /dev/null +++ b/queue-7.0/clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch @@ -0,0 +1,41 @@ +From 08a64c2d46d94def476ff6f2e3bf9c1e35ffa791 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jan 2026 04:12:23 +0200 +Subject: clk: qcom: dispcc-sm8450: use RCG2 ops for DPTX1 AUX clock source + +From: Dmitry Baryshkov + +[ Upstream commit 141af1be817c42c7f1e1605348d4b1983d319bea ] + +The clk_dp_ops are supposed to be used for DP-related clocks with a +proper MND divier. Use standard RCG2 ops for dptx1_aux_clk_src, the same +as all other DPTX AUX clocks in this driver. + +Fixes: 16fb89f92ec4 ("clk: qcom: Add support for Display Clock Controller on SM8450") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Abel Vesa +Reviewed-by: Konrad Dybcio +Reviewed-by: Taniya Das +Link: https://lore.kernel.org/r/20260112-dp-aux-clks-v1-2-456b0c11b069@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/dispcc-sm8450.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c +index 9ce9fd28e55b2..2e91332dd92ab 100644 +--- a/drivers/clk/qcom/dispcc-sm8450.c ++++ b/drivers/clk/qcom/dispcc-sm8450.c +@@ -409,7 +409,7 @@ static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = { + .parent_data = disp_cc_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, +- .ops = &clk_dp_ops, ++ .ops = &clk_rcg2_ops, + }, + }; + +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-gcc-glymur-add-video-axi-clock-resets-for-g.patch b/queue-7.0/clk-qcom-gcc-glymur-add-video-axi-clock-resets-for-g.patch new file mode 100644 index 0000000000..e6a508bd17 --- /dev/null +++ b/queue-7.0/clk-qcom-gcc-glymur-add-video-axi-clock-resets-for-g.patch @@ -0,0 +1,39 @@ +From 1cc59d70baac6d1b69ca74d25efef0af98d0a506 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:26:52 +0530 +Subject: clk: qcom: gcc-glymur: Add video axi clock resets for glymur + +From: Taniya Das + +[ Upstream commit 1c8ce43e1e07ecc531fb517f95620ed85e998608 ] + +The global clock controller video axi reset clocks are required by +the video SW driver to assert and deassert the clock resets during +their power down sequence. Hence add these clock resets. + +Fixes: efe504300a17 ("clk: qcom: gcc: Add support for Global Clock Controller") +Signed-off-by: Taniya Das +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260202-glymur_videocc-v2-3-8f7d8b4d8edd@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-glymur.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c +index 238e205735ed5..cd11470a75f3f 100644 +--- a/drivers/clk/qcom/gcc-glymur.c ++++ b/drivers/clk/qcom/gcc-glymur.c +@@ -8507,6 +8507,7 @@ static const struct qcom_reset_map gcc_glymur_resets[] = { + [GCC_VIDEO_AXI0_CLK_ARES] = { 0x3201c, 2 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { 0x32044, 2 }, + [GCC_VIDEO_BCR] = { 0x32000 }, ++ [GCC_VIDEO_AXI0C_CLK_ARES] = { 0x32030, 2 }, + }; + + static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-7.0/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..aa441c64e2 --- /dev/null +++ b/queue-7.0/clk-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,94 @@ +From 27c8724dd223dc3f71995e9f3a6724cf2154924e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:07 -0300 +Subject: clk: qcom: gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 3565741eb985a8a7cc6656eb33496195468cb99e ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-3-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 50 ++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 31e788e22ab4a..55dabf6259b29 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4266,6 +4266,51 @@ static struct gdsc usb30_mp_gdsc = { + .flags = POLL_CFG_GDSCR, + }; + ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { ++ .gdscr = 0x7d050, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { ++ .gdscr = 0x7d058, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { ++ .gdscr = 0x7d054, ++ .pd = { ++ .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { ++ .gdscr = 0x7d05c, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu0_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ ++static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { ++ .gdscr = 0x7d060, ++ .pd = { ++ .name = "hlos1_vote_turing_mmu_tbu1_gdsc", ++ }, ++ .pwrsts = PWRSTS_OFF_ON, ++ .flags = VOTABLE, ++}; ++ + static struct clk_regmap *gcc_sc8180x_clocks[] = { + [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, +@@ -4595,6 +4640,11 @@ static struct gdsc *gcc_sc8180x_gdscs[] = { + [USB30_MP_GDSC] = &usb30_mp_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB30_SEC_GDSC] = &usb30_sec_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, ++ [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, ++ [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, + }; + + static const struct regmap_config gcc_sc8180x_regmap_config = { +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch b/queue-7.0/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch new file mode 100644 index 0000000000..5afe9ec78c --- /dev/null +++ b/queue-7.0/clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch @@ -0,0 +1,74 @@ +From de0a785cbfda1d03cc92ee717819fa8591328638 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:09 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for PCIe power domains + +From: Val Packett + +[ Upstream commit ccb92c78b42edd26225b4d5920847dfee3e1b093 ] + +As the PCIe host controller driver does not yet support dealing with the +loss of state during suspend, use retention for relevant GDSCs. + +This fixes the link not surviving upon resume: + + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS read failed (134) + nvme 0002:01:00.0: Unable to change power state from D3cold to D0, device inaccessible + nvme nvme0: Disabling device after reset failure: -19 + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Val Packett +Reviewed-by: Konrad Dybcio +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20260312112321.370983-5-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index b116a9c0b2d94..4095a1f54a099 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4199,7 +4199,7 @@ static struct gdsc pcie_0_gdsc = { + .pd = { + .name = "pcie_0_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4226,7 +4226,7 @@ static struct gdsc pcie_1_gdsc = { + .pd = { + .name = "pcie_1_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4235,7 +4235,7 @@ static struct gdsc pcie_2_gdsc = { + .pd = { + .name = "pcie_2_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4253,7 +4253,7 @@ static struct gdsc pcie_3_gdsc = { + .pd = { + .name = "pcie_3_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch b/queue-7.0/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch new file mode 100644 index 0000000000..79b57af3ba --- /dev/null +++ b/queue-7.0/clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch @@ -0,0 +1,65 @@ +From bf687bd54d4136f2b2e16e6e3483ea9c95ac3615 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:08 -0300 +Subject: clk: qcom: gcc-sc8180x: Use retention for USB power domains + +From: Val Packett + +[ Upstream commit 25bc96f26cd6c19dde13a0b9859183e531d6fbfc ] + +The USB subsystem does not expect to lose its state on suspend: + + xhci-hcd xhci-hcd.0.auto: xHC error in resume, USBSTS 0x401, Reinit + usb usb1: root hub lost power or was reset + +(The reinitialization usually succeeds, but it does slow down resume.) + +To maintain state during suspend, the relevant GDSCs need to stay in +retention mode, like they do on other similar SoCs. Change the mode to +PWRSTS_RET_ON to fix. + +Fixes: 4433594bbe5d ("clk: qcom: gcc: Add global clock controller driver for SC8180x") +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Signed-off-by: Val Packett +Link: https://lore.kernel.org/r/20260312112321.370983-4-val@packett.cool +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-sc8180x.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/qcom/gcc-sc8180x.c b/drivers/clk/qcom/gcc-sc8180x.c +index 55dabf6259b29..b116a9c0b2d94 100644 +--- a/drivers/clk/qcom/gcc-sc8180x.c ++++ b/drivers/clk/qcom/gcc-sc8180x.c +@@ -4172,7 +4172,7 @@ static struct gdsc usb30_sec_gdsc = { + .pd = { + .name = "usb30_sec_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4190,7 +4190,7 @@ static struct gdsc usb30_prim_gdsc = { + .pd = { + .name = "usb30_prim_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +@@ -4262,7 +4262,7 @@ static struct gdsc usb30_mp_gdsc = { + .pd = { + .name = "usb30_mp_gdsc", + }, +- .pwrsts = PWRSTS_OFF_ON, ++ .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR, + }; + +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch b/queue-7.0/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch new file mode 100644 index 0000000000..a118219b80 --- /dev/null +++ b/queue-7.0/clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch @@ -0,0 +1,44 @@ +From 43595e49cf2628ce613aa5cba8d436c3fd7da3fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 20:36:46 +0530 +Subject: clk: qcom: gcc-x1e80100: Keep GCC USB QTB clock always ON + +From: Jagadeesh Kona + +[ Upstream commit 05566ebcc0cd170bd4f50c907ee3ed8e106251e3 ] + +In Hamoa, SMMU invalidation requires the GCC_AGGRE_USB_NOC_AXI_CLK +to be on for the USB QTB to be functional. This is currently +explicitly enabled by the DWC3 glue driver, so an invalidation +happening while the USB controller is suspended will fault. + +Solve this by voting for the GCC MMU USB QTB clock. + +Fixes: 161b7c401f4b ("clk: qcom: Add Global Clock controller (GCC) driver for X1E80100") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Jagadeesh Kona +Reviewed-by: Taniya Das +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20260327-hamoa-usb-qtb-clk-always-on-v2-1-7d8a406e650f@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gcc-x1e80100.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c +index 74afd12c158c0..73a2a5112623e 100644 +--- a/drivers/clk/qcom/gcc-x1e80100.c ++++ b/drivers/clk/qcom/gcc-x1e80100.c +@@ -7480,6 +7480,7 @@ static int gcc_x1e80100_probe(struct platform_device *pdev) + qcom_branch_set_clk_en(regmap, 0x32004); /* GCC_VIDEO_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x32030); /* GCC_VIDEO_XO_CLK */ + qcom_branch_set_clk_en(regmap, 0x71004); /* GCC_GPU_CFG_AHB_CLK */ ++ qcom_branch_set_clk_en(regmap, 0x7d01c); /* GCC_HLOS1_VOTE_AGGRE_NOC_MMU_USB_QTB_CLK */ + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52224, 0x0); +-- +2.53.0 + diff --git a/queue-7.0/clk-qcom-gdsc-fix-error-path-on-registration-of-mult.patch b/queue-7.0/clk-qcom-gdsc-fix-error-path-on-registration-of-mult.patch new file mode 100644 index 0000000000..a433f2549e --- /dev/null +++ b/queue-7.0/clk-qcom-gdsc-fix-error-path-on-registration-of-mult.patch @@ -0,0 +1,54 @@ +From 234d81a9c10afd5545921d7c1a4e38d142b53eb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 03:26:19 +0200 +Subject: clk: qcom: gdsc: Fix error path on registration of multiple pm + subdomains + +From: Vladimir Zapolskiy + +[ Upstream commit 16ba98dace9e7cfe25ad8a314e34befacd91f86f ] + +Some pm subdomains may be left in added to a parent domain state, if +gdsc_add_subdomain_list() function fails in the middle and bails from +a GDSC power domain controller registration out. + +Fixes: b489235b4dc0 ("clk: qcom: Support attaching GDSCs to multiple parents") +Signed-off-by: Vladimir Zapolskiy +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Bryan O'Donoghue +Link: https://lore.kernel.org/r/20260328012619.832770-1-vladimir.zapolskiy@linaro.org +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/clk/qcom/gdsc.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c +index 7deabf8400cf6..95aa071202455 100644 +--- a/drivers/clk/qcom/gdsc.c ++++ b/drivers/clk/qcom/gdsc.c +@@ -518,10 +518,20 @@ static int gdsc_add_subdomain_list(struct dev_pm_domain_list *pd_list, + + ret = pm_genpd_add_subdomain(genpd, subdomain); + if (ret) +- return ret; ++ goto remove_added_subdomains; + } + + return 0; ++ ++remove_added_subdomains: ++ for (i--; i >= 0; i--) { ++ struct device *dev = pd_list->pd_devs[i]; ++ struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain); ++ ++ pm_genpd_remove_subdomain(genpd, subdomain); ++ } ++ ++ return ret; + } + + static void gdsc_remove_subdomain_list(struct dev_pm_domain_list *pd_list, +-- +2.53.0 + diff --git a/queue-7.0/clk-qoriq-avoid-format-string-warning.patch b/queue-7.0/clk-qoriq-avoid-format-string-warning.patch new file mode 100644 index 0000000000..c9a1416981 --- /dev/null +++ b/queue-7.0/clk-qoriq-avoid-format-string-warning.patch @@ -0,0 +1,86 @@ +From 4eafe4422bdfec7de055dded1157da15a326fa2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 16:18:49 +0100 +Subject: clk: qoriq: avoid format string warning + +From: Arnd Bergmann + +[ Upstream commit 096abbb6682ee031a0f5ce9f4c71ead9fa63d31e ] + +clang-22 warns about the use of non-variadic format arguments passed into +snprintf(): + +drivers/clk/clk-qoriq.c:925:39: error: diagnostic behavior may be improved by adding the + 'format(printf, 7, 8)' attribute to the declaration of 'create_mux_common' [-Werror,-Wmissing-format-attribute] + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + | __attribute__((format(printf, 7, 8))) + 911 | struct mux_hwclock *hwc, + 912 | const struct clk_ops *ops, + 913 | unsigned long min_rate, + 914 | unsigned long max_rate, + 915 | unsigned long pct80_rate, + 916 | const char *fmt, int idx) + 917 | { + 918 | struct clk_init_data init = {}; + 919 | struct clk *clk; + 920 | const struct clockgen_pll_div *div; + 921 | const char *parent_names[NUM_MUX_PARENTS]; + 922 | char name[32]; + 923 | int i, j; + 924 | + 925 | snprintf(name, sizeof(name), fmt, idx); + | ^ +drivers/clk/clk-qoriq.c:910:28: note: 'create_mux_common' declared here + 910 | static struct clk * __init create_mux_common(struct clockgen *cg, + +Rework this to pass the 'int idx' as a varargs argument, allowing the +format string to be verified at the caller location. + +Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") +Signed-off-by: Arnd Bergmann +Reviewed-by: Kees Cook +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-qoriq.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c +index f05631e553106..2524c5c0eb460 100644 +--- a/drivers/clk/clk-qoriq.c ++++ b/drivers/clk/clk-qoriq.c +@@ -907,13 +907,11 @@ static const struct clockgen_pll_div *get_pll_div(struct clockgen *cg, + return &cg->pll[pll].div[div]; + } + +-static struct clk * __init create_mux_common(struct clockgen *cg, +- struct mux_hwclock *hwc, +- const struct clk_ops *ops, +- unsigned long min_rate, +- unsigned long max_rate, +- unsigned long pct80_rate, +- const char *fmt, int idx) ++static struct clk * __init __printf(7, 8) ++create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, ++ const struct clk_ops *ops, unsigned long min_rate, ++ unsigned long max_rate, unsigned long pct80_rate, ++ const char *fmt, ...) + { + struct clk_init_data init = {}; + struct clk *clk; +@@ -921,8 +919,11 @@ static struct clk * __init create_mux_common(struct clockgen *cg, + const char *parent_names[NUM_MUX_PARENTS]; + char name[32]; + int i, j; ++ va_list args; + +- snprintf(name, sizeof(name), fmt, idx); ++ va_start(args, fmt); ++ vsnprintf(name, sizeof(name), fmt, args); ++ va_end(args); + + for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) { + unsigned long rate; +-- +2.53.0 + diff --git a/queue-7.0/clk-renesas-r9a09g056-fix-ordering-of-module-clocks-.patch b/queue-7.0/clk-renesas-r9a09g056-fix-ordering-of-module-clocks-.patch new file mode 100644 index 0000000000..0ddb0d3b4d --- /dev/null +++ b/queue-7.0/clk-renesas-r9a09g056-fix-ordering-of-module-clocks-.patch @@ -0,0 +1,80 @@ +From 48273245b2a24b78d01e41977a39173391818243 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Jan 2026 19:27:01 +0000 +Subject: clk: renesas: r9a09g056: Fix ordering of module clocks array + +From: Ovidiu Panait + +[ Upstream commit dc71d92f0d36dcb68fcf0ef126131a2dedef9393 ] + +The r9a09g056_mod_clks array is sorted by CPG_CLKON register number and +bit position. Move the RSPI 0/1/2 module clock entries to their correct +position to restore the array sort order. + +Fixes: 1f76689d1715 ("clk: renesas: r9a09g056: Add entries for RSCIs") +Signed-off-by: Ovidiu Panait +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260125192706.27099-2-ovidiu.panait.rb@renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a09g056-cpg.c | 36 ++++++++++++++--------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/clk/renesas/r9a09g056-cpg.c b/drivers/clk/renesas/r9a09g056-cpg.c +index fead173cae8b2..70de6bb929b91 100644 +--- a/drivers/clk/renesas/r9a09g056-cpg.c ++++ b/drivers/clk/renesas/r9a09g056-cpg.c +@@ -289,6 +289,24 @@ static const struct rzv2h_mod_clk r9a09g056_mod_clks[] __initconst = { + BUS_MSTOP(5, BIT(13))), + DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18, + BUS_MSTOP(5, BIT(13))), ++ DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26, ++ BUS_MSTOP(11, BIT(2))), ++ DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27, ++ BUS_MSTOP(11, BIT(2))), ++ DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28, ++ BUS_MSTOP(11, BIT(2))), + DEF_MOD("rsci0_pclk", CLK_PLLCLN_DIV16, 5, 13, 2, 29, + BUS_MSTOP(11, BIT(3))), + DEF_MOD("rsci0_tclk", CLK_PLLCLN_DIV16, 5, 14, 2, 30, +@@ -389,24 +407,6 @@ static const struct rzv2h_mod_clk r9a09g056_mod_clks[] __initconst = { + BUS_MSTOP(11, BIT(12))), + DEF_MOD("rsci9_ps_ps1_n", CLK_PLLCLN_DIV64, 8, 14, 4, 14, + BUS_MSTOP(11, BIT(12))), +- DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26, +- BUS_MSTOP(11, BIT(2))), +- DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27, +- BUS_MSTOP(11, BIT(2))), +- DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28, +- BUS_MSTOP(11, BIT(2))), + DEF_MOD("scif_0_clk_pck", CLK_PLLCM33_DIV16, 8, 15, 4, 15, + BUS_MSTOP(3, BIT(14))), + DEF_MOD("i3c_0_pclkrw", CLK_PLLCLN_DIV16, 9, 0, 4, 16, +-- +2.53.0 + diff --git a/queue-7.0/clk-renesas-r9a09g057-fix-ordering-of-module-clocks-.patch b/queue-7.0/clk-renesas-r9a09g057-fix-ordering-of-module-clocks-.patch new file mode 100644 index 0000000000..68459c250c --- /dev/null +++ b/queue-7.0/clk-renesas-r9a09g057-fix-ordering-of-module-clocks-.patch @@ -0,0 +1,84 @@ +From 1955be01c86eb1c5f7be785deda5a60f892d9635 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Jan 2026 19:03:14 +0000 +Subject: clk: renesas: r9a09g057: Fix ordering of module clocks array + +From: Ovidiu Panait + +[ Upstream commit 79cac2b8dc1d9f63fbf6c6793e423052118cc51a ] + +The r9a09g057_mod_clks array is sorted by CPG_CLKON register number and +bit position. Move the RTC and RSPI module clock entries to their +correct position to restore the array sort order. + +Fixes: 2efea3b35cc9 ("clk: renesas: r9a09g057: Add entries for RSCIs") +Signed-off-by: Ovidiu Panait +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260125190314.26729-1-ovidiu.panait.rb@renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a09g057-cpg.c | 40 ++++++++++++++--------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c +index 6943cad318b5d..b0e43e5e50dde 100644 +--- a/drivers/clk/renesas/r9a09g057-cpg.c ++++ b/drivers/clk/renesas/r9a09g057-cpg.c +@@ -296,6 +296,26 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + BUS_MSTOP(5, BIT(13))), + DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18, + BUS_MSTOP(5, BIT(13))), ++ DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19, ++ BUS_MSTOP(3, BIT(11) | BIT(12))), ++ DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22, ++ BUS_MSTOP(11, BIT(0))), ++ DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25, ++ BUS_MSTOP(11, BIT(1))), ++ DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26, ++ BUS_MSTOP(11, BIT(2))), ++ DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27, ++ BUS_MSTOP(11, BIT(2))), ++ DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28, ++ BUS_MSTOP(11, BIT(2))), + DEF_MOD("rsci0_pclk", CLK_PLLCLN_DIV16, 5, 13, 2, 29, + BUS_MSTOP(11, BIT(3))), + DEF_MOD("rsci0_tclk", CLK_PLLCLN_DIV16, 5, 14, 2, 30, +@@ -396,26 +416,6 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + BUS_MSTOP(11, BIT(12))), + DEF_MOD("rsci9_ps_ps1_n", CLK_PLLCLN_DIV64, 8, 14, 4, 14, + BUS_MSTOP(11, BIT(12))), +- DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19, +- BUS_MSTOP(3, BIT(11) | BIT(12))), +- DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_0_pclk_sfr", CLK_PLLCLN_DIV8, 5, 5, 2, 21, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_0_tclk", CLK_PLLCLN_DIV8, 5, 6, 2, 22, +- BUS_MSTOP(11, BIT(0))), +- DEF_MOD("rspi_1_pclk", CLK_PLLCLN_DIV8, 5, 7, 2, 23, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_1_pclk_sfr", CLK_PLLCLN_DIV8, 5, 8, 2, 24, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_1_tclk", CLK_PLLCLN_DIV8, 5, 9, 2, 25, +- BUS_MSTOP(11, BIT(1))), +- DEF_MOD("rspi_2_pclk", CLK_PLLCLN_DIV8, 5, 10, 2, 26, +- BUS_MSTOP(11, BIT(2))), +- DEF_MOD("rspi_2_pclk_sfr", CLK_PLLCLN_DIV8, 5, 11, 2, 27, +- BUS_MSTOP(11, BIT(2))), +- DEF_MOD("rspi_2_tclk", CLK_PLLCLN_DIV8, 5, 12, 2, 28, +- BUS_MSTOP(11, BIT(2))), + DEF_MOD("scif_0_clk_pck", CLK_PLLCM33_DIV16, 8, 15, 4, 15, + BUS_MSTOP(3, BIT(14))), + DEF_MOD("i3c_0_pclkrw", CLK_PLLCLN_DIV16, 9, 0, 4, 16, +-- +2.53.0 + diff --git a/queue-7.0/clk-renesas-r9a09g057-remove-entries-for-wdt-0-2-3.patch b/queue-7.0/clk-renesas-r9a09g057-remove-entries-for-wdt-0-2-3.patch new file mode 100644 index 0000000000..cb52e6b295 --- /dev/null +++ b/queue-7.0/clk-renesas-r9a09g057-remove-entries-for-wdt-0-2-3.patch @@ -0,0 +1,71 @@ +From 0fa75506cba4ff047eab7a9943f4302e3b3885da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 12:42:47 +0000 +Subject: clk: renesas: r9a09g057: Remove entries for WDT{0,2,3} + +From: Fabrizio Castro + +[ Upstream commit 1b4f047dc4010d51821694cc4ed73b52b3040a5c ] + +The HW user manual for the Renesas RZ/V2H(P) SoC specifies +that only the WDT1 IP is supposed to be used by Linux, +while the WDT{0,2,3} IPs are supposed to be used by the CM33 +and CR8 cores. + +Remove the clock and reset entries for WDT{0,2,3} to prevent +interfering with the CM33 and CR8 cores. + +This change is harmless as only WDT1 is used by Linux, there +are no users for the WDT{0,2,3} cores. + +Fixes: 3aeccbe08171 ("clk: renesas: r9a09g057: Add clock and reset entries for GTM/RIIC/SDHI/WDT") +Signed-off-by: Fabrizio Castro +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260203124247.7320-4-fabrizio.castro.jz@renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a09g057-cpg.c | 15 --------------- + 1 file changed, 15 deletions(-) + +diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c +index b0e43e5e50dde..c3174f40fdb40 100644 +--- a/drivers/clk/renesas/r9a09g057-cpg.c ++++ b/drivers/clk/renesas/r9a09g057-cpg.c +@@ -280,22 +280,10 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + BUS_MSTOP(11, BIT(15))), + DEF_MOD("gtm_7_pclk", CLK_PLLCLN_DIV16, 4, 10, 2, 10, + BUS_MSTOP(12, BIT(0))), +- DEF_MOD("wdt_0_clkp", CLK_PLLCM33_DIV16, 4, 11, 2, 11, +- BUS_MSTOP(3, BIT(10))), +- DEF_MOD("wdt_0_clk_loco", CLK_QEXTAL, 4, 12, 2, 12, +- BUS_MSTOP(3, BIT(10))), + DEF_MOD("wdt_1_clkp", CLK_PLLCLN_DIV16, 4, 13, 2, 13, + BUS_MSTOP(1, BIT(0))), + DEF_MOD("wdt_1_clk_loco", CLK_QEXTAL, 4, 14, 2, 14, + BUS_MSTOP(1, BIT(0))), +- DEF_MOD("wdt_2_clkp", CLK_PLLCLN_DIV16, 4, 15, 2, 15, +- BUS_MSTOP(5, BIT(12))), +- DEF_MOD("wdt_2_clk_loco", CLK_QEXTAL, 5, 0, 2, 16, +- BUS_MSTOP(5, BIT(12))), +- DEF_MOD("wdt_3_clkp", CLK_PLLCLN_DIV16, 5, 1, 2, 17, +- BUS_MSTOP(5, BIT(13))), +- DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18, +- BUS_MSTOP(5, BIT(13))), + DEF_MOD("rtc_0_clk_rtc", CLK_PLLCM33_DIV16, 5, 3, 2, 19, + BUS_MSTOP(3, BIT(11) | BIT(12))), + DEF_MOD("rspi_0_pclk", CLK_PLLCLN_DIV8, 5, 4, 2, 20, +@@ -598,10 +586,7 @@ static const struct rzv2h_reset r9a09g057_resets[] __initconst = { + DEF_RST(7, 2, 3, 3), /* GTM_5_PRESETZ */ + DEF_RST(7, 3, 3, 4), /* GTM_6_PRESETZ */ + DEF_RST(7, 4, 3, 5), /* GTM_7_PRESETZ */ +- DEF_RST(7, 5, 3, 6), /* WDT_0_RESET */ + DEF_RST(7, 6, 3, 7), /* WDT_1_RESET */ +- DEF_RST(7, 7, 3, 8), /* WDT_2_RESET */ +- DEF_RST(7, 8, 3, 9), /* WDT_3_RESET */ + DEF_RST(8, 1, 3, 18), /* RSCI0_PRESETN */ + DEF_RST(8, 2, 3, 19), /* RSCI0_TRESETN */ + DEF_RST(8, 3, 3, 20), /* RSCI1_PRESETN */ +-- +2.53.0 + diff --git a/queue-7.0/clk-spacemit-ccu_mix-fix-inverted-condition-in-ccu_m.patch b/queue-7.0/clk-spacemit-ccu_mix-fix-inverted-condition-in-ccu_m.patch new file mode 100644 index 0000000000..4a63030ab5 --- /dev/null +++ b/queue-7.0/clk-spacemit-ccu_mix-fix-inverted-condition-in-ccu_m.patch @@ -0,0 +1,39 @@ +From 0d333d50c3df783f0674f536d8da6eb508fd5cb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:46:08 +0800 +Subject: clk: spacemit: ccu_mix: fix inverted condition in + ccu_mix_trigger_fc() + +From: Shuwei Wu + +[ Upstream commit 54e97360b44bed6b4399dd3be3d65f392df940fa ] + +Fix inverted condition that skips frequency change trigger, +causing kernel panics during cpufreq scaling. + +Fixes: 1b72c59db0ad ("clk: spacemit: Add clock support for SpacemiT K1 SoC") +Signed-off-by: Shuwei Wu +Reviewed-by: Yixun Lan +Link: https://lore.kernel.org/r/20260305-k1-clk-fix-v1-1-abca85d6e266@mailbox.org +Signed-off-by: Yixun Lan +Signed-off-by: Sasha Levin +--- + drivers/clk/spacemit/ccu_mix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/spacemit/ccu_mix.c b/drivers/clk/spacemit/ccu_mix.c +index 9578366e97466..a8b407049bf4d 100644 +--- a/drivers/clk/spacemit/ccu_mix.c ++++ b/drivers/clk/spacemit/ccu_mix.c +@@ -73,7 +73,7 @@ static int ccu_mix_trigger_fc(struct clk_hw *hw) + struct ccu_common *common = hw_to_ccu_common(hw); + unsigned int val; + +- if (common->reg_fc) ++ if (!common->reg_fc) + return 0; + + ccu_update(common, fc, common->mask_fc, common->mask_fc); +-- +2.53.0 + diff --git a/queue-7.0/clk-sunxi-ng-sun55i-a523-r-add-missing-r-spi-module-.patch b/queue-7.0/clk-sunxi-ng-sun55i-a523-r-add-missing-r-spi-module-.patch new file mode 100644 index 0000000000..bcabbbee0d --- /dev/null +++ b/queue-7.0/clk-sunxi-ng-sun55i-a523-r-add-missing-r-spi-module-.patch @@ -0,0 +1,71 @@ +From a9e07ed12f9a3fc2cf248c79c79c7208c3f17905 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 17:30:03 +0800 +Subject: clk: sunxi-ng: sun55i-a523-r: Add missing r-spi module clock + +From: Chen-Yu Tsai + +[ Upstream commit fb20ccf70cf695f178d7c32e2d33b376560df0ff ] + +When the PRCM clk driver was added, somehow the r-spi module clock +was skipped over. + +Add it so that r-spi can actually work. + +Fixes: 8cea339cfb81 ("clk: sunxi-ng: add support for the A523/T527 PRCM CCU") +Reviewed-by: Andre Przywara +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260217093004.3239051-1-wens@kernel.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c +index 0339c4af0fe5b..db0e36d8838e7 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c ++++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-r.c +@@ -83,9 +83,22 @@ static SUNXI_CCU_MUX_DATA_WITH_GATE(r_pwmctrl_clk, "r-pwmctrl", + static SUNXI_CCU_GATE_HW(bus_r_pwmctrl_clk, "bus-r-pwmctrl", + &r_apb0_clk.common.hw, 0x13c, BIT(0), 0); + +-/* SPI clock is /M/N (same as new MMC?) */ ++static const struct clk_parent_data r_spi_parents[] = { ++ { .fw_name = "hosc" }, ++ { .fw_name = "pll-periph" }, ++ { .name = "pll-periph0-300M" }, ++ { .name = "pll-periph1-300M" }, ++ { .name = "pll-audio" }, ++}; ++static SUNXI_CCU_DUALDIV_MUX_GATE(r_spi_clk, "r-spi", r_spi_parents, 0x150, ++ 0, 5, /* M */ ++ 8, 5, /* P */ ++ 24, 3, /* mux */ ++ BIT(31), /* gate */ ++ 0); + static SUNXI_CCU_GATE_HW(bus_r_spi_clk, "bus-r-spi", + &r_ahb_clk.common.hw, 0x15c, BIT(0), 0); ++ + static SUNXI_CCU_GATE_HW(bus_r_spinlock_clk, "bus-r-spinlock", + &r_ahb_clk.common.hw, 0x16c, BIT(0), 0); + static SUNXI_CCU_GATE_HW(bus_r_msgbox_clk, "bus-r-msgbox", +@@ -138,6 +151,7 @@ static struct ccu_common *sun55i_a523_r_ccu_clks[] = { + &bus_r_twd_clk.common, + &r_pwmctrl_clk.common, + &bus_r_pwmctrl_clk.common, ++ &r_spi_clk.common, + &bus_r_spi_clk.common, + &bus_r_spinlock_clk.common, + &bus_r_msgbox_clk.common, +@@ -169,6 +183,7 @@ static struct clk_hw_onecell_data sun55i_a523_r_hw_clks = { + [CLK_BUS_R_TWD] = &bus_r_twd_clk.common.hw, + [CLK_R_PWMCTRL] = &r_pwmctrl_clk.common.hw, + [CLK_BUS_R_PWMCTRL] = &bus_r_pwmctrl_clk.common.hw, ++ [CLK_R_SPI] = &r_spi_clk.common.hw, + [CLK_BUS_R_SPI] = &bus_r_spi_clk.common.hw, + [CLK_BUS_R_SPINLOCK] = &bus_r_spinlock_clk.common.hw, + [CLK_BUS_R_MSGBOX] = &bus_r_msgbox_clk.common.hw, +-- +2.53.0 + diff --git a/queue-7.0/clk-visconti-pll-initialize-clk_init_data-to-zero.patch b/queue-7.0/clk-visconti-pll-initialize-clk_init_data-to-zero.patch new file mode 100644 index 0000000000..44b715b70c --- /dev/null +++ b/queue-7.0/clk-visconti-pll-initialize-clk_init_data-to-zero.patch @@ -0,0 +1,52 @@ +From f72417aacbca77cee4ff72406150a60979f78265 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 10:32:37 -0400 +Subject: clk: visconti: pll: initialize clk_init_data to zero +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 1603cbb64173a0e9fa7500f2a686f4aa011c58b9 ] + +Sashiko reported the following: + +> The struct clk_init_data init is declared on the stack without being +> fully zero-initialized. While fields like name, flags, parent_names, +> num_parents, and ops are explicitly assigned, the parent_data and +> parent_hws fields are left containing stack garbage. + +clk_core_populate_parent_map() currently prefers the parent names over +the parent data and hws, so this isn't a problem at the moment. If that +ordering ever changed in the future, then this could lead to some +unexpected crashes. Let's just go ahead and make sure that the struct +clk_init_data is initialized to zero as a good practice. + +Fixes: b4cbe606dc367 ("clk: visconti: Add support common clock driver and reset driver") +Link: https://sashiko.dev/#/patchset/20260326042317.122536-1-rosenp%40gmail.com +Signed-off-by: Brian Masney +Reviewed-by: Benoît Monin +Reviewed-by: Nobuhiro Iwamatsu +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/visconti/pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c +index 6fd02c4b641ed..805b954812817 100644 +--- a/drivers/clk/visconti/pll.c ++++ b/drivers/clk/visconti/pll.c +@@ -249,7 +249,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, + const struct visconti_pll_rate_table *rate_table, + spinlock_t *lock) + { +- struct clk_init_data init; ++ struct clk_init_data init = {}; + struct visconti_pll *pll; + struct clk_hw *pll_hw_clk; + size_t len; +-- +2.53.0 + diff --git a/queue-7.0/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch b/queue-7.0/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch new file mode 100644 index 0000000000..ac0fb79bb0 --- /dev/null +++ b/queue-7.0/clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch @@ -0,0 +1,37 @@ +From 3a1bef8ac8be24f44c00499b3fb93e7b00ec64ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:11:16 +0100 +Subject: clk: xgene: Fix mapping leak in xgene_pllclk_init() + +From: Geert Uytterhoeven + +[ Upstream commit f520a492e07bc6718e26cfb7543ab4cadd8bb0e2 ] + +If xgene_register_clk_pll() fails, the mapped register block is never +unmapped. + +Fixes: 308964caeebc45eb ("clk: Add APM X-Gene SoC clock driver") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Brian Masney +Signed-off-by: Stephen Boyd +Signed-off-by: Sasha Levin +--- + drivers/clk/clk-xgene.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c +index ba3b1057e4f0c..abb6c8fcdc91f 100644 +--- a/drivers/clk/clk-xgene.c ++++ b/drivers/clk/clk-xgene.c +@@ -188,6 +188,8 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); ++ } else { ++ iounmap(reg); + } + } + +-- +2.53.0 + diff --git a/queue-7.0/cpufreq-pass-the-policy-to-cpufreq_driver-adjust_per.patch b/queue-7.0/cpufreq-pass-the-policy-to-cpufreq_driver-adjust_per.patch new file mode 100644 index 0000000000..402d984aad --- /dev/null +++ b/queue-7.0/cpufreq-pass-the-policy-to-cpufreq_driver-adjust_per.patch @@ -0,0 +1,193 @@ +From ddbfdfc987cbff5661924788205ee25cdb56a799 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 08:18:49 +0000 +Subject: cpufreq: Pass the policy to cpufreq_driver->adjust_perf() + +From: K Prateek Nayak + +[ Upstream commit c03791085adcd61fa9b766ab303c7d0941d7378d ] + +cpufreq_cpu_get() can sleep on PREEMPT_RT in presence of concurrent +writer(s), however amd-pstate depends on fetching the cpudata via the +policy's driver data which necessitates grabbing the reference. + +Since schedutil governor can call "cpufreq_driver->update_perf()" +during sched_tick/enqueue/dequeue with rq_lock held and IRQs disabled, +fetching the policy object using the cpufreq_cpu_get() helper in the +scheduler fast-path leads to "BUG: scheduling while atomic" on +PREEMPT_RT [1]. + +Pass the cached cpufreq policy object in sg_policy to the update_perf() +instead of just the CPU. The CPU can be inferred using "policy->cpu". + +The lifetime of cpufreq_policy object outlasts that of the governor and +the cpufreq driver (allocated when the CPU is onlined and only reclaimed +when the CPU is offlined / the CPU device is removed) which makes it +safe to be referenced throughout the governor's lifetime. + +Closes:https://lore.kernel.org/all/20250731092316.3191-1-spasswolf@web.de/ [1] + +Fixes: 1d215f0319c2 ("cpufreq: amd-pstate: Add fast switch function for AMD P-State") +Reported-by: Bert Karwatzki +Acked-by: Viresh Kumar +Signed-off-by: K Prateek Nayak +Acked-by: Gary Guo # Rust +Reviewed-by: Gautham R. Shenoy +Reviewed-by: Zhongqiu Han +Link: https://lore.kernel.org/r/20260316081849.19368-3-kprateek.nayak@amd.com +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Sasha Levin +--- + drivers/cpufreq/amd-pstate.c | 3 +-- + drivers/cpufreq/cpufreq.c | 6 +++--- + drivers/cpufreq/intel_pstate.c | 4 ++-- + include/linux/cpufreq.h | 4 ++-- + kernel/sched/cpufreq_schedutil.c | 5 +++-- + rust/kernel/cpufreq.rs | 13 ++++++------- + 6 files changed, 17 insertions(+), 18 deletions(-) + +diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c +index 24cdeffbcd40e..78b70bdcb008f 100644 +--- a/drivers/cpufreq/amd-pstate.c ++++ b/drivers/cpufreq/amd-pstate.c +@@ -712,13 +712,12 @@ static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy, + return policy->cur; + } + +-static void amd_pstate_adjust_perf(unsigned int cpu, ++static void amd_pstate_adjust_perf(struct cpufreq_policy *policy, + unsigned long _min_perf, + unsigned long target_perf, + unsigned long capacity) + { + u8 max_perf, min_perf, des_perf, cap_perf; +- struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu); + struct amd_cpudata *cpudata; + union perf_cached perf; + +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 1f794524a1d92..44441ceedb768 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -2228,7 +2228,7 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch); + + /** + * cpufreq_driver_adjust_perf - Adjust CPU performance level in one go. +- * @cpu: Target CPU. ++ * @policy: cpufreq policy object of the target CPU. + * @min_perf: Minimum (required) performance level (units of @capacity). + * @target_perf: Target (desired) performance level (units of @capacity). + * @capacity: Capacity of the target CPU. +@@ -2247,12 +2247,12 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch); + * parallel with either ->target() or ->target_index() or ->fast_switch() for + * the same CPU. + */ +-void cpufreq_driver_adjust_perf(unsigned int cpu, ++void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy, + unsigned long min_perf, + unsigned long target_perf, + unsigned long capacity) + { +- cpufreq_driver->adjust_perf(cpu, min_perf, target_perf, capacity); ++ cpufreq_driver->adjust_perf(policy, min_perf, target_perf, capacity); + } + + /** +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index 11c58af419006..0f50034e4b680 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -3239,12 +3239,12 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, + return target_pstate * cpu->pstate.scaling; + } + +-static void intel_cpufreq_adjust_perf(unsigned int cpunum, ++static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy, + unsigned long min_perf, + unsigned long target_perf, + unsigned long capacity) + { +- struct cpudata *cpu = all_cpu_data[cpunum]; ++ struct cpudata *cpu = all_cpu_data[policy->cpu]; + u64 hwp_cap = READ_ONCE(cpu->hwp_cap_cached); + int old_pstate = cpu->pstate.current_pstate; + int cap_pstate, min_pstate, max_pstate, target_pstate; +diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h +index cc894fc389710..4317c5a312bd1 100644 +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -372,7 +372,7 @@ struct cpufreq_driver { + * conditions) scale invariance can be disabled, which causes the + * schedutil governor to fall back to the latter. + */ +- void (*adjust_perf)(unsigned int cpu, ++ void (*adjust_perf)(struct cpufreq_policy *policy, + unsigned long min_perf, + unsigned long target_perf, + unsigned long capacity); +@@ -617,7 +617,7 @@ struct cpufreq_governor { + /* Pass a target to the cpufreq driver */ + unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq); +-void cpufreq_driver_adjust_perf(unsigned int cpu, ++void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy, + unsigned long min_perf, + unsigned long target_perf, + unsigned long capacity); +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index 153232dd8276a..ae9fd211cec1f 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -461,6 +461,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time, + unsigned int flags) + { + struct sugov_cpu *sg_cpu = container_of(hook, struct sugov_cpu, update_util); ++ struct sugov_policy *sg_policy = sg_cpu->sg_policy; + unsigned long prev_util = sg_cpu->util; + unsigned long max_cap; + +@@ -482,10 +483,10 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time, + if (sugov_hold_freq(sg_cpu) && sg_cpu->util < prev_util) + sg_cpu->util = prev_util; + +- cpufreq_driver_adjust_perf(sg_cpu->cpu, sg_cpu->bw_min, ++ cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min, + sg_cpu->util, max_cap); + +- sg_cpu->sg_policy->last_freq_update_time = time; ++ sg_policy->last_freq_update_time = time; + } + + static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time) +diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs +index f5adee48d40cb..d8d26870bea2e 100644 +--- a/rust/kernel/cpufreq.rs ++++ b/rust/kernel/cpufreq.rs +@@ -1257,18 +1257,17 @@ impl Registration { + /// # Safety + /// + /// - This function may only be called from the cpufreq C infrastructure. ++ /// - The pointer arguments must be valid pointers. + unsafe extern "C" fn adjust_perf_callback( +- cpu: c_uint, ++ ptr: *mut bindings::cpufreq_policy, + min_perf: c_ulong, + target_perf: c_ulong, + capacity: c_ulong, + ) { +- // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. +- let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) }; +- +- if let Ok(mut policy) = PolicyCpu::from_cpu(cpu_id) { +- T::adjust_perf(&mut policy, min_perf, target_perf, capacity); +- } ++ // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the ++ // lifetime of `policy`. ++ let policy = unsafe { Policy::from_raw_mut(ptr) }; ++ T::adjust_perf(policy, min_perf, target_perf, capacity); + } + + /// Driver's `get_intermediate` callback. +-- +2.53.0 + diff --git a/queue-7.0/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch b/queue-7.0/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch new file mode 100644 index 0000000000..4e549a5963 --- /dev/null +++ b/queue-7.0/crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch @@ -0,0 +1,49 @@ +From 13d08d955945c7b29c6de42211ef1e07248287de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 12:39:28 +0100 +Subject: crypto: atmel-aes - guard unregister on error in + atmel_aes_register_algs + +From: Thorsten Blum + +[ Upstream commit 57a13941c0bb06ae24e3b34672d7b6f2172b253f ] + +Ensure the device supports XTS and GCM with 'has_xts' and 'has_gcm' +before unregistering algorithms when XTS or authenc registration fails, +which would trigger a WARN in crypto_unregister_alg(). + +Currently, with the capabilities defined in atmel_aes_get_cap(), this +bug cannot happen because all devices that support XTS and authenc also +support GCM, but the error handling should still be correct regardless +of hardware capabilities. + +Fixes: d52db5188a87 ("crypto: atmel-aes - add support to the XTS mode") +Signed-off-by: Thorsten Blum +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/atmel-aes.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c +index 9b0cb97055dc5..b393689400b4c 100644 +--- a/drivers/crypto/atmel-aes.c ++++ b/drivers/crypto/atmel-aes.c +@@ -2270,10 +2270,12 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) + /* i = ARRAY_SIZE(aes_authenc_algs); */ + err_aes_authenc_alg: + crypto_unregister_aeads(aes_authenc_algs, i); +- crypto_unregister_skcipher(&aes_xts_alg); ++ if (dd->caps.has_xts) ++ crypto_unregister_skcipher(&aes_xts_alg); + #endif + err_aes_xts_alg: +- crypto_unregister_aead(&aes_gcm_alg); ++ if (dd->caps.has_gcm) ++ crypto_unregister_aead(&aes_gcm_alg); + err_aes_gcm_alg: + i = ARRAY_SIZE(aes_algs); + err_aes_algs: +-- +2.53.0 + diff --git a/queue-7.0/crypto-ccp-copy-iv-using-skcipher-ivsize.patch b/queue-7.0/crypto-ccp-copy-iv-using-skcipher-ivsize.patch new file mode 100644 index 0000000000..cea9b8cb57 --- /dev/null +++ b/queue-7.0/crypto-ccp-copy-iv-using-skcipher-ivsize.patch @@ -0,0 +1,47 @@ +From 8121a8bb4fa8092a25ce684666b2a55473eaf7a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 03:07:49 -0500 +Subject: crypto: ccp - copy IV using skcipher ivsize + +From: Paul Moses + +[ Upstream commit a7a1f3cdd64d8a165d9b8c9e9ad7fb46ac19dfc4 ] + +AF_ALG rfc3686-ctr-aes-ccp requests pass an 8-byte IV to the driver. + +ccp_aes_complete() restores AES_BLOCK_SIZE bytes into the caller's IV +buffer while RFC3686 skciphers expose an 8-byte IV, so the restore +overruns the provided buffer. + +Use crypto_skcipher_ivsize() to copy only the algorithm's IV length. + +Fixes: 2b789435d7f3 ("crypto: ccp - CCP AES crypto API support") +Signed-off-by: Paul Moses +Reviewed-by: Tom Lendacky +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/ccp/ccp-crypto-aes.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c +index 01d298350b925..3ad6bb7666f62 100644 +--- a/drivers/crypto/ccp/ccp-crypto-aes.c ++++ b/drivers/crypto/ccp/ccp-crypto-aes.c +@@ -30,8 +30,11 @@ static int ccp_aes_complete(struct crypto_async_request *async_req, int ret) + if (ret) + return ret; + +- if (ctx->u.aes.mode != CCP_AES_MODE_ECB) +- memcpy(req->iv, rctx->iv, AES_BLOCK_SIZE); ++ if (ctx->u.aes.mode != CCP_AES_MODE_ECB) { ++ size_t ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); ++ ++ memcpy(req->iv, rctx->iv, ivsize); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/crypto-eip93-fix-hmac-setkey-algo-selection.patch b/queue-7.0/crypto-eip93-fix-hmac-setkey-algo-selection.patch new file mode 100644 index 0000000000..f4d8d94d8b --- /dev/null +++ b/queue-7.0/crypto-eip93-fix-hmac-setkey-algo-selection.patch @@ -0,0 +1,93 @@ +From b8e51255096477ff4cf60bcf350a8ccecfc57459 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 23:08:17 +0200 +Subject: crypto: eip93 - fix hmac setkey algo selection + +From: Aleksander Jan Bajkowski + +[ Upstream commit 3ba3b02f897b14e34977e1886d95ffe64d907204 ] + +eip93_hmac_setkey() allocates a temporary ahash transform for +computing HMAC ipad/opad key material. The allocation uses the +driver-specific cra_driver_name (e.g. "sha256-eip93") but passes +CRYPTO_ALG_ASYNC as the mask, which excludes async algorithms. + +Since the EIP93 hash algorithms are the only ones registered +under those driver names and they are inherently async, the +lookup is self-contradictory and always fails with -ENOENT. + +When called from the AEAD setkey path, this failure leaves the +SA record partially initialized with zeroed digest fields. A +subsequent crypto operation then dereferences a NULL pointer in +the request context, resulting in a kernel panic: + +``` + pc : eip93_aead_handle_result+0xc8c/0x1240 [crypto_hw_eip93] + lr : eip93_aead_handle_result+0xbec/0x1240 [crypto_hw_eip93] + sp : ffffffc082feb820 + x29: ffffffc082feb820 x28: ffffff8011043980 x27: 0000000000000000 + x26: 0000000000000000 x25: ffffffc078da0bc8 x24: 0000000091043980 + x23: ffffff8004d59e50 x22: ffffff8004d59410 x21: ffffff8004d593c0 + x20: ffffff8004d593c0 x19: ffffff8004d4f300 x18: 0000000000000000 + x17: 0000000000000000 x16: 0000000000000000 x15: 0000007fda7aa498 + x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 + x11: 0000000000000000 x10: fffffffff8127a80 x9 : 0000000000000000 + x8 : ffffff8004d4f380 x7 : 0000000000000000 x6 : 000000000000003f + x5 : 0000000000000040 x4 : 0000000000000008 x3 : 0000000000000009 + x2 : 0000000000000008 x1 : 0000000028000003 x0 : ffffff8004d388c0 + Code: 910142b6 f94012e0 f9002aa0 f90006d3 (f9400740) +``` + +The reported symbol eip93_aead_handle_result+0xc8c is a +resolution artifact from static functions being merged under +the nearest exported symbol. Decoding the faulting sequence: + +``` + 910142b6 ADD X22, X21, #0x50 + f94012e0 LDR X0, [X23, #0x20] + f9002aa0 STR X0, [X21, #0x50] + f90006d3 STR X19, [X22, #0x8] + f9400740 LDR X0, [X26, #0x8] +``` + +The faulting LDR at [X26, #0x8] is loading ctx->flags +(offset 8 in eip93_hash_ctx), where ctx has been resolved +to NULL from a partially initialized or unreachable +transform context following the failed setkey. + +Fix this by dropping the CRYPTO_ALG_ASYNC mask from the +crypto_alloc_ahash() call. The code already handles async +completion correctly via crypto_wait_req(), so there is no +requirement to restrict the lookup to synchronous algorithms. + +Note that hashing a single 64-byte block through the hardware +is likely slower than doing it in software due to the DMA +round-trip overhead, but offloading it may still spare CPU +cycles on the slower embedded cores where this IP is found. + +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +[Detailed investigation report of this bug] +Signed-off-by: Kenneth Kasilag +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/inside-secure/eip93/eip93-common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-common.c b/drivers/crypto/inside-secure/eip93/eip93-common.c +index f4ad6beff15e0..259714a4ee4d3 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-common.c ++++ b/drivers/crypto/inside-secure/eip93/eip93-common.c +@@ -731,7 +731,7 @@ int eip93_hmac_setkey(u32 ctx_flags, const u8 *key, unsigned int keylen, + return -EINVAL; + } + +- ahash_tfm = crypto_alloc_ahash(alg_name, 0, CRYPTO_ALG_ASYNC); ++ ahash_tfm = crypto_alloc_ahash(alg_name, 0, 0); + if (IS_ERR(ahash_tfm)) + return PTR_ERR(ahash_tfm); + +-- +2.53.0 + diff --git a/queue-7.0/crypto-hisilicon-sec2-prevent-req-used-after-free-fo.patch b/queue-7.0/crypto-hisilicon-sec2-prevent-req-used-after-free-fo.patch new file mode 100644 index 0000000000..42d83ce08a --- /dev/null +++ b/queue-7.0/crypto-hisilicon-sec2-prevent-req-used-after-free-fo.patch @@ -0,0 +1,41 @@ +From 9d70b7bec77dfed85f782edb9b5a8d1d3e55e945 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 15:00:38 +0800 +Subject: crypto: hisilicon/sec2 - prevent req used-after-free for sec + +From: Wenkai Lin + +[ Upstream commit 67b53a660e6bf0da2fa8d8872e897a14d8059eaf ] + +During packet transmission, if the system is under heavy load, +the hardware might complete processing the packet and free the +request memory (req) before the transmission function finishes. +If the software subsequently accesses this req, a use-after-free +error will occur. The qp_ctx memory exists throughout the packet +sending process, so replace the req with the qp_ctx. + +Fixes: f0ae287c5045 ("crypto: hisilicon/sec2 - implement full backlog mode for sec") +Signed-off-by: Wenkai Lin +Signed-off-by: Chenghai Huang +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/hisilicon/sec2/sec_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c +index 15174216d8c41..2471a4dd0b508 100644 +--- a/drivers/crypto/hisilicon/sec2/sec_crypto.c ++++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c +@@ -230,7 +230,7 @@ static int qp_send_message(struct sec_req *req) + + spin_unlock_bh(&qp_ctx->req_lock); + +- atomic64_inc(&req->ctx->sec->debug.dfx.send_cnt); ++ atomic64_inc(&qp_ctx->ctx->sec->debug.dfx.send_cnt); + return -EINPROGRESS; + } + +-- +2.53.0 + diff --git a/queue-7.0/crypto-iaa-fix-per-node-cpu-counter-reset-in-rebalan.patch b/queue-7.0/crypto-iaa-fix-per-node-cpu-counter-reset-in-rebalan.patch new file mode 100644 index 0000000000..246b81f8f0 --- /dev/null +++ b/queue-7.0/crypto-iaa-fix-per-node-cpu-counter-reset-in-rebalan.patch @@ -0,0 +1,46 @@ +From ec66da275bdf789d853cd98c1b8df79c873fb9c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 18:29:05 +0000 +Subject: crypto: iaa - fix per-node CPU counter reset in rebalance_wq_table() + +From: Giovanni Cabiddu + +[ Upstream commit 590fa5d69c27cfaecd2e8287aec78f902417c877 ] + +The cpu counter used to compute the IAA device index is reset to zero +at the start of each NUMA node iteration. This causes CPUs on every +node to map starting from IAA index 0 instead of continuing from the +previous node's last index. On multi-node systems, this results in all +nodes mapping their CPUs to the same initial set of IAA devices, +leaving higher-indexed devices unused. + +Move the cpu counter initialization before the for_each_node_with_cpus() +loop so that the IAA index computation accumulates correctly across all +nodes. + +Fixes: 714ca27e9bf4 ("crypto: iaa - Optimize rebalance_wq_table()") +Signed-off-by: Giovanni Cabiddu +Acked-by: Vinicius Costa Gomes +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/intel/iaa/iaa_crypto_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c +index 547abf453d4a2..f62b994e18e58 100644 +--- a/drivers/crypto/intel/iaa/iaa_crypto_main.c ++++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c +@@ -906,8 +906,8 @@ static void rebalance_wq_table(void) + return; + } + ++ cpu = 0; + for_each_node_with_cpus(node) { +- cpu = 0; + node_cpus = cpumask_of_node(node); + + for_each_cpu(node_cpu, node_cpus) { +-- +2.53.0 + diff --git a/queue-7.0/crypto-inside-secure-eip93-fix-register-definition.patch b/queue-7.0/crypto-inside-secure-eip93-fix-register-definition.patch new file mode 100644 index 0000000000..87e8ae3c4a --- /dev/null +++ b/queue-7.0/crypto-inside-secure-eip93-fix-register-definition.patch @@ -0,0 +1,39 @@ +From 11b99318d8a1a4ffd52957f19e92defc90baf8a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Feb 2026 11:35:53 +0100 +Subject: crypto: inside-secure/eip93 - fix register definition + +From: Aleksander Jan Bajkowski + +[ Upstream commit b7abbc8c7acaeb60c114b038f1fa91bbedb3d16a ] + +Checked the register definitions with the documentation[1]. Turns out +that the PKTE_INBUF_CNT register has a bad offset. It's used in Direct +Host Mode (DHM). The driver uses Autonomous Ring Mode (ARM), so it +causes no harm. + +1. ADSP-SC58x/ADSP-2158x SHARC+ Processor Hardware Reference +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/inside-secure/eip93/eip93-regs.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-regs.h b/drivers/crypto/inside-secure/eip93/eip93-regs.h +index 0490b8d151311..116b3fbb6ad79 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-regs.h ++++ b/drivers/crypto/inside-secure/eip93/eip93-regs.h +@@ -109,7 +109,7 @@ + #define EIP93_REG_PE_BUF_THRESH 0x10c + #define EIP93_PE_OUTBUF_THRESH GENMASK(23, 16) + #define EIP93_PE_INBUF_THRESH GENMASK(7, 0) +-#define EIP93_REG_PE_INBUF_COUNT 0x100 ++#define EIP93_REG_PE_INBUF_COUNT 0x110 + #define EIP93_REG_PE_OUTBUF_COUNT 0x114 + #define EIP93_REG_PE_BUF_RW_PNTR 0x118 /* BUF_PNTR */ + +-- +2.53.0 + diff --git a/queue-7.0/crypto-inside-secure-eip93-register-hash-before-auth.patch b/queue-7.0/crypto-inside-secure-eip93-register-hash-before-auth.patch new file mode 100644 index 0000000000..c55030fc91 --- /dev/null +++ b/queue-7.0/crypto-inside-secure-eip93-register-hash-before-auth.patch @@ -0,0 +1,67 @@ +From b091e73500c957cddd5f3e7126962aefb9f0d418 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 23:17:40 +0100 +Subject: crypto: inside-secure/eip93 - register hash before authenc algorithms + +From: Aleksander Jan Bajkowski + +[ Upstream commit 5377032914b29b4643adece0ff1dfc67e36700f4 ] + +Register hash before hmac and authenc algorithms. This will ensure +selftests pass at startup. Previously, selftests failed on the +crypto_alloc_ahash() function since the associated algorithm was +not yet registered. + +Fixes following error: +... +[ 18.375811] alg: self-tests for authenc(hmac(sha1),cbc(aes)) using authenc(hmac(sha1-eip93),cbc(aes-eip93)) failed (rc=-2) +[ 18.382140] alg: self-tests for authenc(hmac(sha224),rfc3686(ctr(aes))) using authenc(hmac(sha224-eip93),rfc3686(ctr(aes-eip93))) failed (rc=-2) +[ 18.395029] alg: aead: authenc(hmac(sha256-eip93),cbc(des-eip93)) setkey failed on test vector 0; expected_error=0, actual_error=-2, flags=0x1 +[ 18.409734] alg: aead: authenc(hmac(md5-eip93),cbc(des3_ede-eip93)) setkey failed on test vector 0; expected_error=0, actual_error=-2, flags=0x1 +... + +Fixes: 9739f5f93b78 ("crypto: eip93 - Add Inside Secure SafeXcel EIP-93 crypto engine support") +Signed-off-by: Aleksander Jan Bajkowski +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/inside-secure/eip93/eip93-main.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/crypto/inside-secure/eip93/eip93-main.c b/drivers/crypto/inside-secure/eip93/eip93-main.c +index b7fd9795062d4..76858bb4fcc22 100644 +--- a/drivers/crypto/inside-secure/eip93/eip93-main.c ++++ b/drivers/crypto/inside-secure/eip93/eip93-main.c +@@ -36,6 +36,14 @@ static struct eip93_alg_template *eip93_algs[] = { + &eip93_alg_cbc_aes, + &eip93_alg_ctr_aes, + &eip93_alg_rfc3686_aes, ++ &eip93_alg_md5, ++ &eip93_alg_sha1, ++ &eip93_alg_sha224, ++ &eip93_alg_sha256, ++ &eip93_alg_hmac_md5, ++ &eip93_alg_hmac_sha1, ++ &eip93_alg_hmac_sha224, ++ &eip93_alg_hmac_sha256, + &eip93_alg_authenc_hmac_md5_cbc_des, + &eip93_alg_authenc_hmac_sha1_cbc_des, + &eip93_alg_authenc_hmac_sha224_cbc_des, +@@ -52,14 +60,6 @@ static struct eip93_alg_template *eip93_algs[] = { + &eip93_alg_authenc_hmac_sha1_rfc3686_aes, + &eip93_alg_authenc_hmac_sha224_rfc3686_aes, + &eip93_alg_authenc_hmac_sha256_rfc3686_aes, +- &eip93_alg_md5, +- &eip93_alg_sha1, +- &eip93_alg_sha224, +- &eip93_alg_sha256, +- &eip93_alg_hmac_md5, +- &eip93_alg_hmac_sha1, +- &eip93_alg_hmac_sha224, +- &eip93_alg_hmac_sha256, + }; + + inline void eip93_irq_disable(struct eip93_device *eip93, u32 mask) +-- +2.53.0 + diff --git a/queue-7.0/crypto-jitterentropy-replace-long-held-spinlock-with.patch b/queue-7.0/crypto-jitterentropy-replace-long-held-spinlock-with.patch new file mode 100644 index 0000000000..c43e2534f5 --- /dev/null +++ b/queue-7.0/crypto-jitterentropy-replace-long-held-spinlock-with.patch @@ -0,0 +1,109 @@ +From 49b86a24f21a5a842922c4a380e2bf1554a1ec13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:23:46 +0800 +Subject: crypto: jitterentropy - replace long-held spinlock with mutex + +From: Haixin Xu + +[ Upstream commit 01d798e9feb30212952d4e992801ba6bd6a82351 ] + +jent_kcapi_random() serializes the shared jitterentropy state, but it +currently holds a spinlock across the jent_read_entropy() call. That +path performs expensive jitter collection and SHA3 conditioning, so +parallel readers can trigger stalls as contending waiters spin for +the same lock. + +To prevent non-preemptible lock hold, replace rng->jent_lock with a +mutex so contended readers sleep instead of spinning on a shared lock +held across expensive entropy generation. + +Fixes: bb5530e40824 ("crypto: jitterentropy - add jitterentropy RNG") +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Suggested-by: Xin Liu +Signed-off-by: Haixin Xu +Reviewed-by: Stephan Mueller +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/jitterentropy-kcapi.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c +index 7c880cf34c523..5edc6d285aa14 100644 +--- a/crypto/jitterentropy-kcapi.c ++++ b/crypto/jitterentropy-kcapi.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -193,7 +194,7 @@ int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len) + ***************************************************************************/ + + struct jitterentropy { +- spinlock_t jent_lock; ++ struct mutex jent_lock; + struct rand_data *entropy_collector; + struct crypto_shash *tfm; + struct shash_desc *sdesc; +@@ -203,7 +204,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) + { + struct jitterentropy *rng = crypto_tfm_ctx(tfm); + +- spin_lock(&rng->jent_lock); ++ mutex_lock(&rng->jent_lock); + + if (rng->sdesc) { + shash_desc_zero(rng->sdesc); +@@ -218,7 +219,7 @@ static void jent_kcapi_cleanup(struct crypto_tfm *tfm) + if (rng->entropy_collector) + jent_entropy_collector_free(rng->entropy_collector); + rng->entropy_collector = NULL; +- spin_unlock(&rng->jent_lock); ++ mutex_unlock(&rng->jent_lock); + } + + static int jent_kcapi_init(struct crypto_tfm *tfm) +@@ -228,7 +229,7 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) + struct shash_desc *sdesc; + int size, ret = 0; + +- spin_lock_init(&rng->jent_lock); ++ mutex_init(&rng->jent_lock); + + /* Use SHA3-256 as conditioner */ + hash = crypto_alloc_shash(JENT_CONDITIONING_HASH, 0, 0); +@@ -257,7 +258,6 @@ static int jent_kcapi_init(struct crypto_tfm *tfm) + goto err; + } + +- spin_lock_init(&rng->jent_lock); + return 0; + + err: +@@ -272,7 +272,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, + struct jitterentropy *rng = crypto_rng_ctx(tfm); + int ret = 0; + +- spin_lock(&rng->jent_lock); ++ mutex_lock(&rng->jent_lock); + + ret = jent_read_entropy(rng->entropy_collector, rdata, dlen); + +@@ -298,7 +298,7 @@ static int jent_kcapi_random(struct crypto_rng *tfm, + ret = -EINVAL; + } + +- spin_unlock(&rng->jent_lock); ++ mutex_unlock(&rng->jent_lock); + + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch b/queue-7.0/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch new file mode 100644 index 0000000000..b6e9d8e461 --- /dev/null +++ b/queue-7.0/crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch @@ -0,0 +1,62 @@ +From 321922202c7f539f9c81384ab240d07dd702aa21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:12:34 +0000 +Subject: crypto: qat - disable 420xx AE cluster when lead engine is fused off + +From: Ahsan Atta + +[ Upstream commit f216e0f2d1787e662bb6662c9c522185aa3b855a ] + +The get_ae_mask() function only disables individual engines based on +the fuse register, but engines are organized in clusters of 4. If the +lead engine of a cluster is fused off, the entire cluster must be +disabled. + +Replace the single bitmask inversion with explicit test_bit() checks +on the lead engine of each group, disabling the full ADF_AE_GROUP +when the lead bit is set. + +Signed-off-by: Ahsan Atta +Reviewed-by: Giovanni Cabiddu +Fixes: fcf60f4bcf54 ("crypto: qat - add support for 420xx devices") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../intel/qat/qat_420xx/adf_420xx_hw_data.c | 20 +++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +index 35105213d40c0..0002122219bcb 100644 +--- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +@@ -97,9 +97,25 @@ static struct adf_hw_device_class adf_420xx_class = { + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 me_disable = self->fuses[ADF_FUSECTL4]; ++ unsigned long fuses = self->fuses[ADF_FUSECTL4]; ++ u32 mask = ADF_420XX_ACCELENGINES_MASK; + +- return ~me_disable & ADF_420XX_ACCELENGINES_MASK; ++ if (test_bit(0, &fuses)) ++ mask &= ~ADF_AE_GROUP_0; ++ ++ if (test_bit(4, &fuses)) ++ mask &= ~ADF_AE_GROUP_1; ++ ++ if (test_bit(8, &fuses)) ++ mask &= ~ADF_AE_GROUP_2; ++ ++ if (test_bit(12, &fuses)) ++ mask &= ~ADF_AE_GROUP_3; ++ ++ if (test_bit(16, &fuses)) ++ mask &= ~ADF_AE_GROUP_4; ++ ++ return mask; + } + + static u32 uof_get_num_objs(struct adf_accel_dev *accel_dev) +-- +2.53.0 + diff --git a/queue-7.0/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch b/queue-7.0/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch new file mode 100644 index 0000000000..1cb3896da5 --- /dev/null +++ b/queue-7.0/crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch @@ -0,0 +1,56 @@ +From b2852e16711ac39a6499d04b8b261bbe402e2e0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:11:12 +0000 +Subject: crypto: qat - disable 4xxx AE cluster when lead engine is fused off + +From: Ahsan Atta + +[ Upstream commit b260d53561dd69b29505222ec44cf386ac2c2ca6 ] + +The get_ae_mask() function only disables individual engines based on +the fuse register, but engines are organized in clusters of 4. If the +lead engine of a cluster is fused off, the entire cluster must be +disabled. + +Replace the single bitmask inversion with explicit test_bit() checks +on the lead engine of each group, disabling the full ADF_AE_GROUP +when the lead bit is set. + +Signed-off-by: Ahsan Atta +Reviewed-by: Giovanni Cabiddu +Fixes: 8c8268166e834 ("crypto: qat - add qat_4xxx driver") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +index 740f68a36ac51..900f19b90b2dc 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +@@ -100,9 +100,19 @@ static struct adf_hw_device_class adf_4xxx_class = { + + static u32 get_ae_mask(struct adf_hw_device_data *self) + { +- u32 me_disable = self->fuses[ADF_FUSECTL4]; ++ unsigned long fuses = self->fuses[ADF_FUSECTL4]; ++ u32 mask = ADF_4XXX_ACCELENGINES_MASK; + +- return ~me_disable & ADF_4XXX_ACCELENGINES_MASK; ++ if (test_bit(0, &fuses)) ++ mask &= ~ADF_AE_GROUP_0; ++ ++ if (test_bit(4, &fuses)) ++ mask &= ~ADF_AE_GROUP_1; ++ ++ if (test_bit(8, &fuses)) ++ mask &= ~ADF_AE_GROUP_2; ++ ++ return mask; + } + + static u32 get_accel_cap(struct adf_accel_dev *accel_dev) +-- +2.53.0 + diff --git a/queue-7.0/crypto-qat-fix-compression-instance-leak.patch b/queue-7.0/crypto-qat-fix-compression-instance-leak.patch new file mode 100644 index 0000000000..28082a445c --- /dev/null +++ b/queue-7.0/crypto-qat-fix-compression-instance-leak.patch @@ -0,0 +1,65 @@ +From 44a1555d137e043c58a2e50df76898dab6e77af1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 17:59:40 +0000 +Subject: crypto: qat - fix compression instance leak + +From: Giovanni Cabiddu + +[ Upstream commit 795c24c677c7a1c12f5768daf22a874a2890662f ] + +qat_comp_alg_init_tfm() acquires a compression instance via +qat_compression_get_instance_node() before calling qat_comp_build_ctx() +to initialize the compression context. If qat_comp_build_ctx() fails, the +function returns an error without releasing the compression instance, +causing a resource leak. + +When qat_comp_build_ctx() fails, release the compression instance with +qat_compression_put_instance() and clear the context to avoid leaving a +stale reference to the released instance. + +The issue was introduced when build_deflate_ctx() (which always returned +void) was replaced by qat_comp_build_ctx() (which can return an error) +without adding error handling for the failure path. + +Fixes: cd0e7160f80f ("crypto: qat - refactor compression template logic") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Laurent M Coquerel +Reviewed-by: Ahsan Atta +Reviewed-by: Wojciech Drewek +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/intel/qat/qat_common/qat_comp_algs.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c +index 8b123472b71cc..4273a0ecb6c80 100644 +--- a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c ++++ b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c +@@ -133,7 +133,7 @@ static int qat_comp_alg_init_tfm(struct crypto_acomp *acomp_tfm) + struct crypto_tfm *tfm = crypto_acomp_tfm(acomp_tfm); + struct qat_compression_ctx *ctx = crypto_tfm_ctx(tfm); + struct qat_compression_instance *inst; +- int node; ++ int node, ret; + + if (tfm->node == NUMA_NO_NODE) + node = numa_node_id(); +@@ -146,7 +146,13 @@ static int qat_comp_alg_init_tfm(struct crypto_acomp *acomp_tfm) + return -EINVAL; + ctx->inst = inst; + +- return qat_comp_build_ctx(inst->accel_dev, ctx->comp_ctx, QAT_DEFLATE); ++ ret = qat_comp_build_ctx(inst->accel_dev, ctx->comp_ctx, QAT_DEFLATE); ++ if (ret) { ++ qat_compression_put_instance(inst); ++ memset(ctx, 0, sizeof(*ctx)); ++ } ++ ++ return ret; + } + + static void qat_comp_alg_exit_tfm(struct crypto_acomp *acomp_tfm) +-- +2.53.0 + diff --git a/queue-7.0/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch b/queue-7.0/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch new file mode 100644 index 0000000000..00c4d7d2ea --- /dev/null +++ b/queue-7.0/crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch @@ -0,0 +1,86 @@ +From e3e35b1fd4184d0127ef13acec5f0f11fb514086 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 18:17:23 +0000 +Subject: crypto: qat - fix type mismatch in RAS sysfs show functions + +From: Giovanni Cabiddu + +[ Upstream commit ec23d75c4b77ae42af0777ea59599b1d4f611371 ] + +ADF_RAS_ERR_CTR_READ() expands to atomic_read(), which returns int. +The local variable 'counter' was declared as 'unsigned long', causing +a type mismatch on the assignment. The format specifier '%ld' was +consequently wrong in two ways: wrong length modifier and wrong +signedness. + +Use int to match the return type of atomic_read() and update the +format specifier to '%d' accordingly. + +Fixes: 532d7f6bc458 ("crypto: qat - add error counters") +Signed-off-by: Giovanni Cabiddu +Reviewed-by: Ahsan Atta +Reviewed-by: Andy Shevchenko +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../intel/qat/qat_common/adf_sysfs_ras_counters.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c +index e97c67c87b3cf..6abb57bfd3285 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c +@@ -13,14 +13,14 @@ static ssize_t errors_correctable_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_CORR); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t errors_nonfatal_show(struct device *dev, +@@ -28,14 +28,14 @@ static ssize_t errors_nonfatal_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_UNCORR); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t errors_fatal_show(struct device *dev, +@@ -43,14 +43,14 @@ static ssize_t errors_fatal_show(struct device *dev, + char *buf) + { + struct adf_accel_dev *accel_dev; +- unsigned long counter; ++ int counter; + + accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + + counter = ADF_RAS_ERR_CTR_READ(accel_dev->ras_errors, ADF_RAS_FATAL); +- return scnprintf(buf, PAGE_SIZE, "%ld\n", counter); ++ return scnprintf(buf, PAGE_SIZE, "%d\n", counter); + } + + static ssize_t reset_error_counters_store(struct device *dev, +-- +2.53.0 + diff --git a/queue-7.0/crypto-qat-use-swab32-macro.patch b/queue-7.0/crypto-qat-use-swab32-macro.patch new file mode 100644 index 0000000000..e002effb6e --- /dev/null +++ b/queue-7.0/crypto-qat-use-swab32-macro.patch @@ -0,0 +1,82 @@ +From 6dd2afc4ed3469c4e403ab6a79672bc854ff188a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 22:29:46 +0000 +Subject: crypto: qat - use swab32 macro + +From: Giovanni Cabiddu + +[ Upstream commit 35ecb77ae0749a2f1b04872c9978d9d7ddbbeb79 ] + +Replace __builtin_bswap32() with swab32 in icp_qat_hw_20_comp.h to fix +the following build errors on architectures without native byte-swap +support: + + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.o: in function `adf_gen4_build_decomp_block': + drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:141:(.text+0xeec): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:141:(.text+0xef8): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.o: in function `adf_gen4_build_comp_block': + drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:57:(.text+0xf64): undefined reference to `__bswapsi2' + alpha-linux-ld: drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h:57:(.text+0xf7c): undefined reference to `__bswapsi2' + +Fixes: 5b14b2b307e4 ("crypto: qat - enable deflate for QAT GEN4") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202603290259.Ig9kDOmI-lkp@intel.com/ +Signed-off-by: Giovanni Cabiddu +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + .../crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +index 7ea8962272f2f..d28732225c9e0 100644 +--- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h ++++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw_20_comp.h +@@ -3,6 +3,8 @@ + #ifndef _ICP_QAT_HW_20_COMP_H_ + #define _ICP_QAT_HW_20_COMP_H_ + ++#include ++ + #include "icp_qat_hw_20_comp_defs.h" + #include "icp_qat_fw.h" + +@@ -54,7 +56,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_comp_20_config_csr_lower + QAT_FIELD_SET(val32, csr.abd, ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_ABD_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_comp_20_config_csr_upper { +@@ -106,7 +108,7 @@ ICP_QAT_FW_COMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_comp_20_config_csr_upper + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_BITPOS, + ICP_QAT_HW_COMP_20_CONFIG_CSR_NICE_PARAM_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_decomp_20_config_csr_lower { +@@ -138,7 +140,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_LOWER(struct icp_qat_hw_decomp_20_config_csr_l + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_LZ4_BLOCK_CHECKSUM_PRESENT_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + struct icp_qat_hw_decomp_20_config_csr_upper { +@@ -158,7 +160,7 @@ ICP_QAT_FW_DECOMP_20_BUILD_CONFIG_UPPER(struct icp_qat_hw_decomp_20_config_csr_u + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_BITPOS, + ICP_QAT_HW_DECOMP_20_CONFIG_CSR_MINI_CAM_CONTROL_MASK); + +- return __builtin_bswap32(val32); ++ return swab32(val32); + } + + #endif +-- +2.53.0 + diff --git a/queue-7.0/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch b/queue-7.0/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch new file mode 100644 index 0000000000..385e3cc684 --- /dev/null +++ b/queue-7.0/crypto-sa2ul-fix-aead-fallback-algorithm-names.patch @@ -0,0 +1,47 @@ +From e1b9a8da33fdfb105b1a0f889d5b31a691066b35 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 20:06:58 +0530 +Subject: crypto: sa2ul - Fix AEAD fallback algorithm names + +From: T Pratham + +[ Upstream commit 8451ab6ad686ffdcdf9ddadaa446a79ab48e5590 ] + +For authenc AEAD algorithms, sa2ul is trying to register very specific +-ce version as a fallback. This causes registration failure on SoCs +which do not have ARMv8-CE enabled/available. Change the fallback +algorithm from the specific driver name to generic algorithm name so +that the kernel can allocate any available fallback. + +Fixes: d2c8ac187fc92 ("crypto: sa2ul - Add AEAD algorithm support") +Signed-off-by: T Pratham +Reviewed-by: Manorit Chawdhry +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/sa2ul.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c +index df3defa1ef4b6..965a03d5b27ae 100644 +--- a/drivers/crypto/sa2ul.c ++++ b/drivers/crypto/sa2ul.c +@@ -1744,13 +1744,13 @@ static int sa_cra_init_aead(struct crypto_aead *tfm, const char *hash, + static int sa_cra_init_aead_sha1(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha1", +- "authenc(hmac(sha1-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha1),cbc(aes))"); + } + + static int sa_cra_init_aead_sha256(struct crypto_aead *tfm) + { + return sa_cra_init_aead(tfm, "sha256", +- "authenc(hmac(sha256-ce),cbc(aes-ce))"); ++ "authenc(hmac(sha256),cbc(aes))"); + } + + static void sa_exit_tfm_aead(struct crypto_aead *tfm) +-- +2.53.0 + diff --git a/queue-7.0/crypto-simd-reject-compat-registrations-without-__-p.patch b/queue-7.0/crypto-simd-reject-compat-registrations-without-__-p.patch new file mode 100644 index 0000000000..d87b48f114 --- /dev/null +++ b/queue-7.0/crypto-simd-reject-compat-registrations-without-__-p.patch @@ -0,0 +1,78 @@ +From 05281cb8bf2588d23fbddf35d2e74725e4103dcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 22:31:43 -0600 +Subject: crypto: simd - reject compat registrations without __ prefixes + +From: Wesley Atwell + +[ Upstream commit e0ce97f781c78b717b00493630a9e34caf04f79b ] + +simd_register_skciphers_compat() and simd_register_aeads_compat() +derive the wrapper algorithm names by stripping the __ prefix from the +internal algorithm names. + +Currently they only WARN if cra_name or cra_driver_name lacks that prefix, +but they still continue and unconditionally add 2 to both strings. That +registers wrapper algorithms with incorrectly truncated names after a +violated precondition. + +Reject such inputs with -EINVAL before registering anything, while keeping +the warning so invalid internal API usage is still visible. + +Fixes: d14f0a1fc488 ("crypto: simd - allow registering multiple algorithms at once") +Fixes: 1661131a0479 ("crypto: simd - support wrapping AEAD algorithms") +Assisted-by: Codex:GPT-5 +Signed-off-by: Wesley Atwell +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + crypto/simd.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/crypto/simd.c b/crypto/simd.c +index f71c4a334c7d0..4e6f437e9e778 100644 +--- a/crypto/simd.c ++++ b/crypto/simd.c +@@ -214,13 +214,17 @@ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count, + const char *basename; + struct simd_skcipher_alg *simd; + ++ for (i = 0; i < count; i++) { ++ if (WARN_ON(strncmp(algs[i].base.cra_name, "__", 2) || ++ strncmp(algs[i].base.cra_driver_name, "__", 2))) ++ return -EINVAL; ++ } ++ + err = crypto_register_skciphers(algs, count); + if (err) + return err; + + for (i = 0; i < count; i++) { +- WARN_ON(strncmp(algs[i].base.cra_name, "__", 2)); +- WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2)); + algname = algs[i].base.cra_name + 2; + drvname = algs[i].base.cra_driver_name + 2; + basename = algs[i].base.cra_driver_name; +@@ -437,13 +441,17 @@ int simd_register_aeads_compat(struct aead_alg *algs, int count, + const char *basename; + struct simd_aead_alg *simd; + ++ for (i = 0; i < count; i++) { ++ if (WARN_ON(strncmp(algs[i].base.cra_name, "__", 2) || ++ strncmp(algs[i].base.cra_driver_name, "__", 2))) ++ return -EINVAL; ++ } ++ + err = crypto_register_aeads(algs, count); + if (err) + return err; + + for (i = 0; i < count; i++) { +- WARN_ON(strncmp(algs[i].base.cra_name, "__", 2)); +- WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2)); + algname = algs[i].base.cra_name + 2; + drvname = algs[i].base.cra_driver_name + 2; + basename = algs[i].base.cra_driver_name; +-- +2.53.0 + diff --git a/queue-7.0/crypto-tegra-disable-softirqs-before-finalizing-requ.patch b/queue-7.0/crypto-tegra-disable-softirqs-before-finalizing-requ.patch new file mode 100644 index 0000000000..d597a45e85 --- /dev/null +++ b/queue-7.0/crypto-tegra-disable-softirqs-before-finalizing-requ.patch @@ -0,0 +1,98 @@ +From 9c97199d747fe845450a84f2548907c250b287dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 18:28:29 +0900 +Subject: crypto: tegra - Disable softirqs before finalizing request + +From: Herbert Xu + +[ Upstream commit 2aeec9af775fb53aa086419b953302c6f4ad4984 ] + +Softirqs must be disabled when calling the finalization fucntion on +a request. + +Reported-by: Guangwu Zhang +Fixes: 0880bb3b00c8 ("crypto: tegra - Add Tegra Security Engine driver") +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + drivers/crypto/tegra/tegra-se-aes.c | 9 +++++++++ + drivers/crypto/tegra/tegra-se-hash.c | 3 +++ + 2 files changed, 12 insertions(+) + +diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c +index 9210cceb4b7b2..30c78afe3dea6 100644 +--- a/drivers/crypto/tegra/tegra-se-aes.c ++++ b/drivers/crypto/tegra/tegra-se-aes.c +@@ -4,6 +4,7 @@ + * Crypto driver to handle block cipher algorithms using NVIDIA Security Engine. + */ + ++#include + #include + #include + #include +@@ -333,7 +334,9 @@ static int tegra_aes_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, key2_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_skcipher_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1262,7 +1265,9 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_aead_request(ctx->se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1348,7 +1353,9 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + + out_finalize: ++ local_bh_disable(); + crypto_finalize_aead_request(ctx->se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +@@ -1746,7 +1753,9 @@ static int tegra_cmac_do_one_req(struct crypto_engine *engine, void *areq) + if (tegra_key_is_reserved(rctx->key_id)) + tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + ++ local_bh_disable(); + crypto_finalize_hash_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c +index 06bb5bf0fa335..23d549801612e 100644 +--- a/drivers/crypto/tegra/tegra-se-hash.c ++++ b/drivers/crypto/tegra/tegra-se-hash.c +@@ -4,6 +4,7 @@ + * Crypto driver to handle HASH algorithms using NVIDIA Security Engine. + */ + ++#include + #include + #include + #include +@@ -546,7 +547,9 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq) + } + + out: ++ local_bh_disable(); + crypto_finalize_hash_request(se->engine, req, ret); ++ local_bh_enable(); + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch b/queue-7.0/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch new file mode 100644 index 0000000000..8618492990 --- /dev/null +++ b/queue-7.0/cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch @@ -0,0 +1,47 @@ +From 1399af3d62729e0af99009c436f7661cf41db245 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 15:06:33 +0800 +Subject: cxl/pci: Check memdev driver binding status in cxl_reset_done() + +From: Li Ming + +[ Upstream commit e8069c66d09309579e53567be8ddfa6ccb2f452a ] + +cxl_reset_done() accesses the endpoint of the corresponding CXL memdev +without endpoint validity checking. By default, cxlmd->endpoint is +initialized to -ENXIO, if cxl_reset_done() is triggered after the +corresponding CXL memdev probing failed, this results in access to an +invalid endpoint. + +CXL subsystem can always check CXL memdev driver binding status to +confirm its endpoint validity. So adding the CXL memdev driver checking +inside cxl_reset_done() to avoid accessing an invalid endpoint. + +Fixes: 934edcd436dc ("cxl: Add post-reset warning if reset results in loss of previously committed HDM decoders") +Reviewed-by: Dan Williams +Reviewed-by: Dave Jiang +Signed-off-by: Li Ming +Link: https://patch.msgid.link/20260314-fix_access_endpoint_without_drv_check-v2-4-4c09edf2e1db@zohomail.com +Signed-off-by: Dave Jiang +Signed-off-by: Sasha Levin +--- + drivers/cxl/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c +index fbb300a018302..a5922116db2a8 100644 +--- a/drivers/cxl/pci.c ++++ b/drivers/cxl/pci.c +@@ -1043,6 +1043,9 @@ static void cxl_reset_done(struct pci_dev *pdev) + * that no longer exists. + */ + guard(device)(&cxlmd->dev); ++ if (!cxlmd->dev.driver) ++ return; ++ + if (cxlmd->endpoint && + cxl_endpoint_decoder_reset_detected(cxlmd->endpoint)) { + dev_crit(dev, "SBR happened without memory regions removal.\n"); +-- +2.53.0 + diff --git a/queue-7.0/dcache-permit-dynamic_dname-s-up-to-name_max.patch b/queue-7.0/dcache-permit-dynamic_dname-s-up-to-name_max.patch new file mode 100644 index 0000000000..f0c34bcee6 --- /dev/null +++ b/queue-7.0/dcache-permit-dynamic_dname-s-up-to-name_max.patch @@ -0,0 +1,68 @@ +From 2f6bd3e97c377600e3cc21f15abbac2e5be4093f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 01:46:21 +1100 +Subject: dcache: permit dynamic_dname()s up to NAME_MAX + +From: Aleksa Sarai + +[ Upstream commit 97b67e64affb0e709eeecc50f6a9222fc20bd14b ] + +dynamic_dname() has had an implicit limit of 64 characters since it was +introduced in commit c23fbb6bcb3e ("VFS: delay the dentry name +generation on sockets and pipes"), however it seems that this was a +fairly arbitrary number (suspiciously it was double the previously +hardcoded buffer size). + +NAME_MAX seems like a more reasonable and consistent limit for d_name +lengths. While we're at it, we can also remove the unnecessary +stack-allocated array and just memmove() the formatted string to the end +of the buffer. + +It should also be noted that at least one driver (in particular, +liveupdate's usage of anon_inode for session files) already exceeded +this limit without noticing that readlink(/proc/self/fd/$n) always +returns -ENAMETOOLONG, so this fixes those drivers as well. + +Fixes: 0153094d03df ("liveupdate: luo_session: add sessions support") +Fixes: c23fbb6bcb3e ("VFS: delay the dentry name generation on sockets and pipes") +Signed-off-by: Aleksa Sarai +Link: https://patch.msgid.link/20260401-dynamic-dname-name_max-v1-1-8ca20ab2642e@amutable.com +Tested-by: Luca Boccassi +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/d_path.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/d_path.c b/fs/d_path.c +index bb365511066b2..a48957c0971ef 100644 +--- a/fs/d_path.c ++++ b/fs/d_path.c +@@ -301,18 +301,19 @@ EXPORT_SYMBOL(d_path); + char *dynamic_dname(char *buffer, int buflen, const char *fmt, ...) + { + va_list args; +- char temp[64]; ++ char *start; + int sz; + + va_start(args, fmt); +- sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1; ++ sz = vsnprintf(buffer, buflen, fmt, args) + 1; + va_end(args); + +- if (sz > sizeof(temp) || sz > buflen) ++ if (sz > NAME_MAX || sz > buflen) + return ERR_PTR(-ENAMETOOLONG); + +- buffer += buflen - sz; +- return memcpy(buffer, temp, sz); ++ /* Move the formatted d_name to the end of the buffer. */ ++ start = buffer + (buflen - sz); ++ return memmove(start, buffer, sz); + } + + char *simple_dname(struct dentry *dentry, char *buffer, int buflen) +-- +2.53.0 + diff --git a/queue-7.0/debugfs-check-for-null-pointer-in-debugfs_create_str.patch b/queue-7.0/debugfs-check-for-null-pointer-in-debugfs_create_str.patch new file mode 100644 index 0000000000..953ee323df --- /dev/null +++ b/queue-7.0/debugfs-check-for-null-pointer-in-debugfs_create_str.patch @@ -0,0 +1,52 @@ +From ef0936cd284301461d968832d3f7a4cb32547c33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:44 +0800 +Subject: debugfs: check for NULL pointer in debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 31de83980d3764d784f79ff1bc93c42b324f4013 ] + +Passing a NULL pointer to debugfs_create_str() leads to a NULL pointer +dereference when the debugfs file is read. Following upstream +discussions, forbid the creation of debugfs string files with NULL +pointers. Add a WARN_ON() to expose offending callers and return early. + +Fixes: 9af0440ec86e ("debugfs: Implement debugfs_create_str()") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/2025122221-gag-malt-75ba@gregkh/ +Suggested-by: Greg Kroah-Hartman +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-2-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index 3376ab6a519d1..a941d73251b06 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -1127,7 +1127,7 @@ static const struct file_operations fops_str_wo = { + * directory dentry if set. If this parameter is %NULL, then the + * file will be created in the root of the debugfs filesystem. + * @value: a pointer to the variable that the file should read to and write +- * from. ++ * from. This pointer and the string it points to must not be %NULL. + * + * This function creates a file in debugfs with the given name that + * contains the value of the variable @value. If the @mode variable is so +@@ -1136,6 +1136,9 @@ static const struct file_operations fops_str_wo = { + void debugfs_create_str(const char *name, umode_t mode, + struct dentry *parent, char **value) + { ++ if (WARN_ON(!value || !*value)) ++ return; ++ + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } +-- +2.53.0 + diff --git a/queue-7.0/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch b/queue-7.0/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch new file mode 100644 index 0000000000..f99174c004 --- /dev/null +++ b/queue-7.0/debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch @@ -0,0 +1,45 @@ +From 7b285279da32255f6b4f5e9916be82215059cfb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:45 +0800 +Subject: debugfs: fix placement of EXPORT_SYMBOL_GPL for debugfs_create_str() + +From: Gui-Dong Han + +[ Upstream commit 4afc929c0f74c4f22b055a82b371d50586da58ca ] + +The EXPORT_SYMBOL_GPL() for debugfs_create_str was placed incorrectly +away from the function definition. Move it immediately below the +debugfs_create_str() function where it belongs. + +Fixes: d60b59b96795 ("debugfs: Export debugfs_create_str symbol") +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-3-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + fs/debugfs/file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c +index a941d73251b06..edd6aafbfbaaf 100644 +--- a/fs/debugfs/file.c ++++ b/fs/debugfs/file.c +@@ -1047,7 +1047,6 @@ ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf, + + return ret; + } +-EXPORT_SYMBOL_GPL(debugfs_create_str); + + static ssize_t debugfs_write_file_str(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +@@ -1142,6 +1141,7 @@ void debugfs_create_str(const char *name, umode_t mode, + debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, + &fops_str_ro, &fops_str_wo); + } ++EXPORT_SYMBOL_GPL(debugfs_create_str); + + static ssize_t read_file_blob(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +-- +2.53.0 + diff --git a/queue-7.0/devres-fix-missing-node-debug-info-in-devm_krealloc.patch b/queue-7.0/devres-fix-missing-node-debug-info-in-devm_krealloc.patch new file mode 100644 index 0000000000..7e4ab24d91 --- /dev/null +++ b/queue-7.0/devres-fix-missing-node-debug-info-in-devm_krealloc.patch @@ -0,0 +1,37 @@ +From b6de064f86dca9a9c135aa59dd0d2d28e714d14e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 00:48:14 +0100 +Subject: devres: fix missing node debug info in devm_krealloc() + +From: Danilo Krummrich + +[ Upstream commit f813ec9e84b4d0ca81ec1da94ab07bfb4a29266c ] + +Fix missing call to set_node_dbginfo() for new devres nodes created by +devm_krealloc(). + +Fixes: f82485722e5d ("devres: provide devm_krealloc()") +Reviewed-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/20260202235210.55176-2-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/base/devres.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index 171750c1f6918..ce519b98a1898 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -940,6 +940,8 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) + if (!new_dr) + return NULL; + ++ set_node_dbginfo(&new_dr->node, "devm_krealloc_release", new_size); ++ + /* + * The spinlock protects the linked list against concurrent + * modifications but not the resource itself. +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-fix-concurrent-write-failure-in-passthrough.patch b/queue-7.0/dm-cache-fix-concurrent-write-failure-in-passthrough.patch new file mode 100644 index 0000000000..1053829099 --- /dev/null +++ b/queue-7.0/dm-cache-fix-concurrent-write-failure-in-passthrough.patch @@ -0,0 +1,84 @@ +From 9a240e8c146964293fc85bfd6f9cc9ab030f284c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:09 +0800 +Subject: dm cache: fix concurrent write failure in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit e4f66341779d0cf4c83c74793753a84094286d9e ] + +When bio prison cell lock acquisition fails due to concurrent writes to +the same block in passthrough mode, dm-cache incorrectly returns an I/O +error instead of properly handling the concurrency. This can occur in +both process and workqueue contexts when invalidate_lock() is called for +exclusive access to a data block. Fix this by deferring the write bios +to ensure proper block device behavior. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently. Sometimes one of the + processes will receive I/O errors. + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + + + fio-3.41 + fio: io_u error on file /dev/mapper/cache: Input/output error: write offset=4096, buflen=4096 + fio: pid=106, err=5/file:io_u.c:2008, func=io_u error, error=Input/output error + test: (groupid=0, jobs=1): err= 0: pid=105 + test: (groupid=0, jobs=1): err= 5 (file:io_u.c:2008, func=io_u error, error=Input/output error): pid=106 + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index d3ef88b859ab3..32d22c7b9a07d 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1561,6 +1561,15 @@ static int invalidate_lock(struct dm_cache_migration *mg) + READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell); + if (r < 0) { + free_prison_cell(cache, prealloc); ++ ++ /* Defer the bio for retrying the cell lock */ ++ if (mg->overwrite_bio) { ++ struct bio *bio = mg->overwrite_bio; ++ ++ mg->overwrite_bio = NULL; ++ defer_bio(cache, bio); ++ } ++ + invalidate_complete(mg, false); + return r; + } +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch b/queue-7.0/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch new file mode 100644 index 0000000000..fdb17de5ff --- /dev/null +++ b/queue-7.0/dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch @@ -0,0 +1,151 @@ +From 9c5a4c328a09391cf096599e087b86021e3c4a39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:10 +0800 +Subject: dm cache: fix dirty mapping checking in passthrough mode switching + +From: Ming-Hung Tsai + +[ Upstream commit 322586745bd1a0e5f3559fd1635fdeb4dbd1d6b8 ] + +As mentioned in commit 9b1cc9f251af ("dm cache: share cache-metadata +object across inactive and active DM tables"), dm-cache assumed table +reload occurs after suspension, while LVM's table preload breaks this +assumption. The dirty mapping check for passthrough mode was designed +around this assumption and is performed during table creation, causing +the check to fail with preload while metadata updates are ongoing. This +risks loading dirty mappings into passthrough mode, resulting in data +loss. + +Reproduce steps: + +1. Create a writeback cache with zero migration_threshold to produce + dirty mappings + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writeback smq \ +2 migration_threshold 0" + +2. Preload a table in passthrough mode + +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" + +3. Write to the first cache block to make it dirty + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +4. Resume the inactive table. Now it's possible to load the dirty block + into passthrough mode. + +dmsetup resume cache + +Fix by moving the checks to the preresume phase to support table +preloading. Also remove the unused function dm_cache_metadata_all_clean. + +Fixes: 2ee57d587357 ("dm cache: add passthrough mode") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 11 ----------- + drivers/md/dm-cache-metadata.h | 5 ----- + drivers/md/dm-cache-target.c | 25 ++++++++----------------- + 3 files changed, 8 insertions(+), 33 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 57158c02d096e..1b86e80c89cca 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1714,17 +1714,6 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy * + return r; + } + +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) +-{ +- int r; +- +- READ_LOCK(cmd); +- r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); +- READ_UNLOCK(cmd); +- +- return r; +-} +- + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) + { + WRITE_LOCK_VOID(cmd); +diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h +index 5f77890207fed..2f107e7c67d0a 100644 +--- a/drivers/md/dm-cache-metadata.h ++++ b/drivers/md/dm-cache-metadata.h +@@ -135,11 +135,6 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd, + */ + int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *p); + +-/* +- * Query method. Are all the blocks in the cache clean? +- */ +-int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result); +- + int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result); + int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd); + void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd); +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 32d22c7b9a07d..e479ac22b97cc 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2499,23 +2499,8 @@ static int cache_create(struct cache_args *ca, struct cache **result) + goto bad; + } + +- if (passthrough_mode(cache)) { +- bool all_clean; +- +- r = dm_cache_metadata_all_clean(cache->cmd, &all_clean); +- if (r) { +- *error = "dm_cache_metadata_all_clean() failed"; +- goto bad; +- } +- +- if (!all_clean) { +- *error = "Cannot enter passthrough mode unless all blocks are clean"; +- r = -EINVAL; +- goto bad; +- } +- ++ if (passthrough_mode(cache)) + policy_allow_migrations(cache->policy, false); +- } + + spin_lock_init(&cache->lock); + bio_list_init(&cache->deferred_bios); +@@ -2842,6 +2827,12 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock, + struct cache *cache = context; + + if (dirty) { ++ if (passthrough_mode(cache)) { ++ DMERR("%s: cannot enter passthrough mode unless all blocks are clean", ++ cache_device_name(cache)); ++ return -EBUSY; ++ } ++ + set_bit(from_cblock(cblock), cache->dirty_bitset); + atomic_inc(&cache->nr_dirty); + } else +@@ -3075,7 +3066,7 @@ static int cache_preresume(struct dm_target *ti) + load_filtered_mapping, cache); + if (r) { + DMERR("%s: could not load cache mappings", cache_device_name(cache)); +- if (r != -EFBIG) ++ if (r != -EFBIG && r != -EBUSY) + metadata_operation_failed(cache, "dm_cache_load_mappings", r); + return r; + } +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-fix-missing-return-in-invalidate_committed-.patch b/queue-7.0/dm-cache-fix-missing-return-in-invalidate_committed-.patch new file mode 100644 index 0000000000..58d1230cf5 --- /dev/null +++ b/queue-7.0/dm-cache-fix-missing-return-in-invalidate_committed-.patch @@ -0,0 +1,51 @@ +From 5232da76f086eb966fc27651eaba1314f992f99b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 21:08:01 +0800 +Subject: dm cache: fix missing return in invalidate_committed's error path + +From: Ming-Hung Tsai + +[ Upstream commit 8c0ee19db81f0fa1ff25fd75b22b17c0cc2acde3 ] + +In passthrough mode, dm-cache defers write submission until after +metadata commit completes via the invalidate_committed() continuation. +On commit error, invalidate_committed() calls invalidate_complete() to +end the bio and free the migration struct, after which it should return +immediately. + +The patch 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +omitted this early return, causing execution to fall through into the +success path on error. This results in use-after-free on the migration +struct in the subsequent calls. + +Fix by adding the missing return after the invalidate_complete() call. + +Fixes: 4ca8b8bd952d ("dm cache: fix write hang in passthrough mode") +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/dm-devel/adjMq6T5RRjv_uxM@stanley.mountain/ +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index e479ac22b97cc..af7a2571988b4 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1521,8 +1521,10 @@ static void invalidate_committed(struct work_struct *ws) + struct bio *bio = mg->overwrite_bio; + struct per_bio_data *pb = get_per_bio_data(bio); + +- if (mg->k.input) ++ if (mg->k.input) { + invalidate_complete(mg, false); ++ return; ++ } + + init_continuation(&mg->k, invalidate_completed); + remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch b/queue-7.0/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch new file mode 100644 index 0000000000..4e78b03f46 --- /dev/null +++ b/queue-7.0/dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch @@ -0,0 +1,86 @@ +From 6c3bedadb807327fcac1cf56493d8e4379e42115 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:05 +0800 +Subject: dm cache: fix null-deref with concurrent writes in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 7d1f98d668ee34c1d15bdc0420fdd062f24a27c0 ] + +In passthrough mode, when dm-cache starts to invalidate a cache +entry and bio prison cell lock fails due to concurrent write to +the same cached block, mg->cell remains NULL. The error path in +invalidate_complete() attempts to unlock and free the cell +unconditionally, causing a NULL pointer dereference: + +KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +CPU: 0 UID: 0 PID: 134 Comm: fio Not tainted 6.19.0-rc7 #3 PREEMPT +RIP: 0010:dm_cell_unlock_v2+0x3f/0x210 + +Call Trace: + invalidate_complete+0xef/0x430 + map_bio+0x130f/0x1a10 + cache_map+0x320/0x6b0 + __map_bio+0x458/0x510 + dm_submit_bio+0x40e/0x16d0 + __submit_bio+0x419/0x870 + + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first cached block concurrently + +fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \ +--randrepeat=0 --direct=1 --numjobs=2 --size 64k + +Fix by checking if mg->cell is valid before attempting to unlock it. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index 935ab79b1d0cd..ae1edffd14eaa 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1462,8 +1462,10 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + struct cache *cache = mg->cache; + + bio_list_init(&bios); +- if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) +- free_prison_cell(cache, mg->cell); ++ if (mg->cell) { ++ if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios)) ++ free_prison_cell(cache, mg->cell); ++ } + + if (!success && mg->overwrite_bio) + bio_io_error(mg->overwrite_bio); +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-fix-write-hang-in-passthrough-mode.patch b/queue-7.0/dm-cache-fix-write-hang-in-passthrough-mode.patch new file mode 100644 index 0000000000..fa71a6e6da --- /dev/null +++ b/queue-7.0/dm-cache-fix-write-hang-in-passthrough-mode.patch @@ -0,0 +1,88 @@ +From 6040f33086a726beac6d91dcafb8f11f1fcda392 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:07 +0800 +Subject: dm cache: fix write hang in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 4ca8b8bd952df7c3ccdc68af9bd3419d0839a04b ] + +The invalidate_remove() function has incomplete logic for handling write +hit bios after cache invalidation. It sets up the remapping for the +overwrite_bio but then drops it immediately without submission, causing +write operations to hang. + +Fix by adding a new invalidate_committed() continuation that submits +the remapped writes to the cache origin after metadata commit completes, +while using the overwrite_endio hook to ensure proper completion +sequencing. This maintains existing coherency. Also improve error +handling in invalidate_complete() to preserve the original error status +instead of using bio_io_error() unconditionally. + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index b608e88acd511..d3ef88b859ab3 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1467,8 +1467,14 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success) + free_prison_cell(cache, mg->cell); + } + +- if (!success && mg->overwrite_bio) +- bio_io_error(mg->overwrite_bio); ++ if (mg->overwrite_bio) { ++ // Set generic error if the bio hasn't been issued yet, ++ // e.g., invalidation or metadata commit failed before bio ++ // submission. Otherwise preserve the bio's own error status. ++ if (!success && !mg->overwrite_bio->bi_status) ++ mg->overwrite_bio->bi_status = BLK_STS_IOERR; ++ bio_endio(mg->overwrite_bio); ++ } + + free_migration(mg); + defer_bios(cache, &bios); +@@ -1508,6 +1514,22 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock) + return r; + } + ++static void invalidate_committed(struct work_struct *ws) ++{ ++ struct dm_cache_migration *mg = ws_to_mg(ws); ++ struct cache *cache = mg->cache; ++ struct bio *bio = mg->overwrite_bio; ++ struct per_bio_data *pb = get_per_bio_data(bio); ++ ++ if (mg->k.input) ++ invalidate_complete(mg, false); ++ ++ init_continuation(&mg->k, invalidate_completed); ++ remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock); ++ dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg); ++ dm_submit_bio_remap(bio, NULL); ++} ++ + static void invalidate_remove(struct work_struct *ws) + { + int r; +@@ -1520,10 +1542,8 @@ static void invalidate_remove(struct work_struct *ws) + return; + } + +- init_continuation(&mg->k, invalidate_completed); ++ init_continuation(&mg->k, invalidate_committed); + continue_after_commit(&cache->committer, &mg->k); +- remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock); +- mg->overwrite_bio = NULL; + schedule_commit(&cache->committer); + } + +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch b/queue-7.0/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch new file mode 100644 index 0000000000..329aa4acba --- /dev/null +++ b/queue-7.0/dm-cache-fix-write-path-cache-coherency-in-passthrou.patch @@ -0,0 +1,85 @@ +From 6105580a09fe61b21d20305863c66f279405f242 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:06 +0800 +Subject: dm cache: fix write path cache coherency in passthrough mode + +From: Ming-Hung Tsai + +[ Upstream commit 0c5eef0aad508231d8e43ff8392692925e131b68 ] + +In passthrough mode, dm-cache defers write bio submission until cache +invalidation completes to maintain existing coherency, requiring the +target map function to return DM_MAPIO_SUBMITTED. The current map_bio() +returns DM_MAPIO_REMAPPED, violating the required ordering constraint. + +Reproduce steps: + +1. Create a cache device + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Promote the first data block into the cache + +fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \ +--direct=1 --size=64k + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the first data block, and check io ordering using ftrace + +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_queue/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_bio_complete/enable +echo 1 > /sys/kernel/debug/tracing/events/block/block_rq_complete/enable +fio --filename=/dev/mapper/cache --name=test --rw=write --bs=64k \ +--direct=1 --size 64k + +5. ftrace logs show that write operations to the cache origin (252:2) + and metadata operations (252:0) are unsynchronized: the origin write + occurs before metadata commit. + + + fio-146 [000] ..... 420.139562: block_bio_queue: 252,3 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149395: block_bio_queue: 252,2 WS 0 + 128 [fio] + fio-146 [000] ..... 420.149763: block_bio_queue: 8,32 WS 262144 + 128 [fio] + fio-146 [000] dNh1. 420.151446: block_rq_complete: 8,32 WS () 262144 + 128 be,0,4 [0] + fio-146 [000] dNh1. 420.152731: block_bio_complete: 252,2 WS 0 + 128 [0] + fio-146 [000] dNh1. 420.154229: block_bio_complete: 252,3 WS 0 + 128 [0] + kworker/0:0-9 [000] ..... 420.160530: block_bio_queue: 252,0 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.161641: block_bio_queue: 8,32 W 408 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162533: block_bio_queue: 252,0 W 416 + 8 [kworker/0:0] + kworker/0:0-9 [000] ..... 420.162821: block_bio_queue: 8,32 W 416 + 8 [kworker/0:0] + + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-target.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c +index ae1edffd14eaa..b608e88acd511 100644 +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -1703,6 +1703,7 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block, + bio_drop_shared_lock(cache, bio); + atomic_inc(&cache->stats.demotion); + invalidate_start(cache, cblock, block, bio); ++ return DM_MAPIO_SUBMITTED; + } else + remap_to_origin_clear_discard(cache, bio, block); + } else { +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch b/queue-7.0/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch new file mode 100644 index 0000000000..fc6e01b9cd --- /dev/null +++ b/queue-7.0/dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch @@ -0,0 +1,121 @@ +From 9749276326b225766abf2def60a15536d44d8496 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:56:28 +0800 +Subject: dm cache metadata: fix memory leak on metadata abort retry + +From: Ming-Hung Tsai + +[ Upstream commit 044ca491d4086dc5bf233e9fcb71db52df32f633 ] + +When failing to acquire the root_lock in dm_cache_metadata_abort because +the block_manager is read-only, the temporary block_manager created +outside the root_lock is not properly released, causing a memory leak. + +Reproduce steps: + +This can be reproduced by reloading a new table while the metadata +is read-only. While the second call to dm_cache_metadata_abort is +caused by lack of support for table preload in dm-cache, mentioned +in commit 9b1cc9f251af ("dm cache: share cache-metadata object across +inactive and active DM tables"), it exposes the memory leak in +dm_cache_metadata_abort when the function is called multiple times. +Specifically, dm-cache fails to sync the new cache object's mode during +preresume, creating the reproducer condition. + +This issue could also occur through concurrent metadata_operation_failed +calls due to races in cache mode updates, but the table preload scenario +below provides a reliable reproducer. + +1. Create a cache device with some faulty trailing metadata blocks + +dmsetup create cmeta < +unreferenced object 0xffff8880080c2010 (size 16): + comm "dmsetup", pid 132, jiffies 4294982580 + hex dump (first 16 bytes): + 00 38 b9 07 80 88 ff ff 6a 6b 6b 6b 6b 6b 6b a5 ... + backtrace (crc 3118f31c): + kmemleak_alloc+0x28/0x40 + __kmalloc_cache_noprof+0x3d9/0x510 + dm_block_manager_create+0x51/0x140 + dm_cache_metadata_abort+0x85/0x320 + metadata_operation_failed+0x103/0x1e0 + cache_preresume+0xacd/0xe70 + dm_table_resume_targets+0xd3/0x320 + __dm_resume+0x1b/0xf0 + dm_resume+0x127/0x170 + + +Fixes: 352b837a5541 ("dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-metadata.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c +index 1b86e80c89cca..ddfc1a3cf2f53 100644 +--- a/drivers/md/dm-cache-metadata.c ++++ b/drivers/md/dm-cache-metadata.c +@@ -1023,6 +1023,12 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd) + return; \ + } while (0) + ++#define WRITE_LOCK_OR_GOTO(cmd, label) \ ++ do { \ ++ if (!cmd_write_lock((cmd))) \ ++ goto label; \ ++ } while (0) ++ + #define WRITE_UNLOCK(cmd) \ + up_write(&(cmd)->root_lock) + +@@ -1780,11 +1786,8 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd) + new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, + CACHE_MAX_CONCURRENT_LOCKS); + +- WRITE_LOCK(cmd); +- if (cmd->fail_io) { +- WRITE_UNLOCK(cmd); +- goto out; +- } ++ /* cmd_write_lock() already checks fail_io with cmd->root_lock held */ ++ WRITE_LOCK_OR_GOTO(cmd, out); + + __destroy_persistent_data_objects(cmd, false); + old_bm = cmd->bm; +-- +2.53.0 + diff --git a/queue-7.0/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch b/queue-7.0/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch new file mode 100644 index 0000000000..10d26321e5 --- /dev/null +++ b/queue-7.0/dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch @@ -0,0 +1,91 @@ +From dd7b25b4b1e882dc404607a5966ec03330449409 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 15:54:08 +0800 +Subject: dm cache policy smq: fix missing locks in invalidating cache blocks + +From: Ming-Hung Tsai + +[ Upstream commit 2d1f7b65f5deedd2e6b09fdc6ea27f8375f24b45 ] + +In passthrough mode, the policy invalidate_mapping operation is called +simultaneously from multiple workers, thus it should be protected by a +lock. Otherwise, we might end up with data races on the allocated blocks +counter, or even use-after-free issues with internal data structures +when doing concurrent writes. + +Note that the existing FIXME in smq_invalidate_mapping() doesn't affect +passthrough mode since migration tasks don't exist there, but would need +attention if supporting fast device shrinking via suspend/resume without +target reloading. + +Reproduce steps: + +1. Create a cache device consisting of 1024 cache entries + +dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" +dmsetup create cdata --table "0 131072 linear /dev/sdc 8192" +dmsetup create corig --table "0 262144 linear /dev/sdc 262144" +dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct +dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" + +2. Populate the cache, and record the number of cached blocks + +fio --name=populate --filename=/dev/mapper/cache --rw=randwrite --bs=4k \ +--size=64m --direct=1 +nr_cached=$(dmsetup status cache | awk '{split($7, a, "/"); print a[1]}') + +3. Reload the cache into passthrough mode + +dmsetup suspend cache +dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ +/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0" +dmsetup resume cache + +4. Write to the passthrough cache. By setting multiple jobs with I/O + size equal to the cache block size, cache blocks are invalidated + concurrently from different workers. + +fio --filename=/dev/mapper/cache --name=test --rw=randwrite --bs=64k \ +--direct=1 --numjobs=2 --randrepeat=0 --size=64m + +5. Check if demoted matches cached block count. These numbers should + match but may differ due to the data race. + +nr_demoted=$(dmsetup status cache | awk '{print $12}') +echo "$nr_cached, $nr_demoted" + +Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2") +Signed-off-by: Ming-Hung Tsai +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-cache-policy-smq.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c +index b328d9601046b..dd77a93fd68d2 100644 +--- a/drivers/md/dm-cache-policy-smq.c ++++ b/drivers/md/dm-cache-policy-smq.c +@@ -1589,14 +1589,18 @@ static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) + { + struct smq_policy *mq = to_smq_policy(p); + struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); ++ unsigned long flags; + + if (!e->allocated) + return -ENODATA; + ++ spin_lock_irqsave(&mq->lock, flags); + // FIXME: what if this block has pending background work? + del_queue(mq, e); + h_remove(&mq->table, e); + free_entry(&mq->cache_alloc, e); ++ spin_unlock_irqrestore(&mq->lock, flags); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch b/queue-7.0/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch new file mode 100644 index 0000000000..b62d6ac40f --- /dev/null +++ b/queue-7.0/dm-init-ensure-device-probing-has-finished-in-dm-mod.patch @@ -0,0 +1,58 @@ +From 844bca6718cc455426f877045ee03e0502f7e214 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 22:32:28 +0100 +Subject: dm init: ensure device probing has finished in dm-mod.waitfor= + +From: Guillaume Gonnet + +[ Upstream commit 99a2312f69805f4ba92d98a757625e0300a747ab ] + +The early_lookup_bdev() function returns successfully when the disk +device is present but not necessarily its partitions. In this situation, +dm_early_create() fails as the partition block device does not exist +yet. + +In my case, this phenomenon occurs quite often because the device is +an SD card with slow reading times, on which kernel takes time to +enumerate available partitions. + +Fortunately, the underlying device is back to "probing" state while +enumerating partitions. Waiting for all probing to end is enough to fix +this issue. + +That's also the reason why this problem never occurs with rootwait= +parameter: the while loop inside wait_for_root() explicitly waits for +probing to be done and then the function calls async_synchronize_full(). +These lines were omitted in 035641b, even though the commit says it's +based on the rootwait logic... + +Anyway, calling wait_for_device_probe() after our while loop does the +job (it both waits for probing and calls async_synchronize_full). + +Fixes: 035641b01e72 ("dm init: add dm-mod.waitfor to wait for asynchronously probed block devices") +Signed-off-by: Guillaume Gonnet +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-init.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c +index 7403823384c57..c1bacba92c65c 100644 +--- a/drivers/md/dm-init.c ++++ b/drivers/md/dm-init.c +@@ -303,8 +303,10 @@ static int __init dm_init_init(void) + } + } + +- if (waitfor[0]) ++ if (waitfor[0]) { ++ wait_for_device_probe(); + DMINFO("all devices available"); ++ } + + list_for_each_entry(dev, &devices, list) { + if (dm_early_create(&dev->dmi, dev->table, +-- +2.53.0 + diff --git a/queue-7.0/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch b/queue-7.0/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch new file mode 100644 index 0000000000..87b821f29b --- /dev/null +++ b/queue-7.0/dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch @@ -0,0 +1,81 @@ +From 9005bfe5801d65486e5fef7033bc073c362bdca7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:05:48 +0800 +Subject: dm log: fix out-of-bounds write due to region_count overflow + +From: Junrui Luo + +[ Upstream commit c20e36b7631d83e7535877f08af8b0af72c44b1a ] + +The local variable region_count in create_log_context() is declared as +unsigned int (32-bit), but dm_sector_div_up() returns sector_t (64-bit). +When a device-mapper target has a sufficiently large ti->len with a small +region_size, the division result can exceed UINT_MAX. The truncated +value is then used to calculate bitset_size, causing clean_bits, +sync_bits, and recovering_bits to be allocated far smaller than needed +for the actual number of regions. + +Subsequent log operations (log_set_bit, log_clear_bit, log_test_bit) use +region indices derived from the full untruncated region space, causing +out-of-bounds writes to kernel heap memory allocated by vmalloc. + +This can be reproduced by creating a mirror target whose region_count +overflows 32 bits: + + dmsetup create bigzero --table '0 8589934594 zero' + dmsetup create mymirror --table '0 8589934594 mirror \ + core 2 2 nosync 2 /dev/mapper/bigzero 0 \ + /dev/mapper/bigzero 0' + +The status output confirms the truncation (sync_count=1 instead of +4294967297, because 0x100000001 was truncated to 1): + + $ dmsetup status mymirror + 0 8589934594 mirror 2 254:1 254:1 1/4294967297 ... + +This leads to a kernel crash in core_in_sync: + + BUG: scheduling while atomic: (udev-worker)/9150/0x00000000 + RIP: 0010:core_in_sync+0x14/0x30 [dm_log] + CR2: 0000000000000008 + Fixing recursive fault but reboot is needed! + +Fix by widening the local region_count to sector_t and adding an +explicit overflow check before the value is assigned to lc->region_count. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-log.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c +index 1aa6a4a7d2323..d316757a328be 100644 +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -373,7 +373,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + + struct log_c *lc; + uint32_t region_size; +- unsigned int region_count; ++ sector_t region_count; + size_t bitset_size, buf_size; + int r; + char dummy; +@@ -401,6 +401,10 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, + } + + region_count = dm_sector_div_up(ti->len, region_size); ++ if (region_count > UINT_MAX) { ++ DMWARN("region count exceeds limit of %u", UINT_MAX); ++ return -EINVAL; ++ } + + lc = kmalloc_obj(*lc); + if (!lc) { +-- +2.53.0 + diff --git a/queue-7.0/dm-mpath-don-t-stop-probing-paths-at-presuspend.patch b/queue-7.0/dm-mpath-don-t-stop-probing-paths-at-presuspend.patch new file mode 100644 index 0000000000..1284c2e28e --- /dev/null +++ b/queue-7.0/dm-mpath-don-t-stop-probing-paths-at-presuspend.patch @@ -0,0 +1,102 @@ +From 73c37bea98383f6d49be6c322be695f912934920 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Feb 2026 13:05:41 -0500 +Subject: dm-mpath: don't stop probing paths at presuspend + +From: Benjamin Marzinski + +[ Upstream commit 51d81e14fe6788dc6463064c7517480f2acd2724 ] + +Commit 5c977f102315 ("dm-mpath: Don't grab work_mutex while probing +paths"), added code to make multipath quit probing paths early, if it +was trying to suspend. This isn't necessary. It was just an optimization +to try to keep path probing from delaying a suspend. However it causes +problems with the intended user of this code, qemu. The path probing +code was added because failed ioctls to multipath devices don't cause +paths to fail in cases where a regular IO failure would. + +If an ioctl to a path failed because the path was down, and the +multipath device had passed presuspend, the M_MPATH_PROBE_PATHS ioctl +would exit early, without probing the path. The caller would then retry +the original ioctl, hoping to use a different path. But if there was +only one path in the pathgroup, it would pick the same non-working path +again, even if there were working paths in other pathgroups. + +ioctls to a suspended dm device will return -EAGAIN, notifying the +caller that the device is suspended, but ioctls to a device that is just +preparing to suspend won't (and in general, shouldn't). This means that +the caller (qemu in this case) would get into a tight loop where it +would issue an ioctl that failed, skip probing the paths because the +device had already passed presuspend, and start over issuing the ioctl +again. This would continue until the multipath device finally fully +suspended, or the caller gave up and failed the ioctl. + +multipath's path probing code could return -EAGAIN in this case, and the +caller could delay a bit before retrying, but the whole purpose of +skipping the probe after presuspend was to speed things up, and that +would just slow them down. Instead, remove the is_suspending flag, and +check dm_suspended() instead to decide whether to exit the probing code +early. This means that when the probing code exits early, future ioctls +will also be delayed, because the device is fully suspended. + +Fixes: 5c977f102315 ("dm-mpath: Don't grab work_mutex while probing paths") +Signed-off-by: Benjamin Marzinski +Reviewed-by: Martin Wilck +Reviewed-by: Hanna Czenczek +Signed-off-by: Mikulas Patocka +Signed-off-by: Sasha Levin +--- + drivers/md/dm-mpath.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c +index 8f4ae2f515453..7cb7bb6233b64 100644 +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -102,7 +102,6 @@ struct multipath { + struct bio_list queued_bios; + + struct timer_list nopath_timer; /* Timeout for queue_if_no_path */ +- bool is_suspending; + }; + + /* +@@ -1749,9 +1748,6 @@ static void multipath_presuspend(struct dm_target *ti) + { + struct multipath *m = ti->private; + +- spin_lock_irq(&m->lock); +- m->is_suspending = true; +- spin_unlock_irq(&m->lock); + /* FIXME: bio-based shouldn't need to always disable queue_if_no_path */ + if (m->queue_mode == DM_TYPE_BIO_BASED || !dm_noflush_suspending(m->ti)) + queue_if_no_path(m, false, true, __func__); +@@ -1774,7 +1770,6 @@ static void multipath_resume(struct dm_target *ti) + struct multipath *m = ti->private; + + spin_lock_irq(&m->lock); +- m->is_suspending = false; + if (test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags)) { + set_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags); + clear_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags); +@@ -2098,7 +2093,7 @@ static int probe_active_paths(struct multipath *m) + if (m->current_pg == m->last_probed_pg) + goto skip_probe; + } +- if (!m->current_pg || m->is_suspending || ++ if (!m->current_pg || dm_suspended(m->ti) || + test_bit(MPATHF_QUEUE_IO, &m->flags)) + goto skip_probe; + set_bit(MPATHF_DELAY_PG_SWITCH, &m->flags); +@@ -2107,7 +2102,7 @@ static int probe_active_paths(struct multipath *m) + + list_for_each_entry(pgpath, &pg->pgpaths, list) { + if (pg != READ_ONCE(m->current_pg) || +- READ_ONCE(m->is_suspending)) ++ dm_suspended(m->ti)) + goto out; + if (!pgpath->is_active) + continue; +-- +2.53.0 + diff --git a/queue-7.0/dma-fence-fix-sparse-warnings-due-__rcu-annotations.patch b/queue-7.0/dma-fence-fix-sparse-warnings-due-__rcu-annotations.patch new file mode 100644 index 0000000000..effe902e70 --- /dev/null +++ b/queue-7.0/dma-fence-fix-sparse-warnings-due-__rcu-annotations.patch @@ -0,0 +1,143 @@ +From 90555d67044923a2ce28a3cb491b97732bc31e90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Jun 2025 16:59:52 +0100 +Subject: dma-fence: Fix sparse warnings due __rcu annotations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tvrtko Ursulin + +[ Upstream commit 62918542b7bf08860a60ebbde7654486e0ac0776 ] + +__rcu annotations on the return types from dma_fence_driver_name() and +dma_fence_timeline_name() cause sparse to complain because both the +constant signaled strings, and the strings return by the dma_fence_ops are +not __rcu annotated. + +For a simple fix it is easiest to cast them with __rcu added and undo the +smarts from the tracpoints side of things. There is no functional change +since the rest is left in place. Later we can consider changing the +dma_fence_ops return types too, and handle all the individual drivers +which define them. + +Signed-off-by: Tvrtko Ursulin +Fixes: 506aa8b02a8d ("dma-fence: Add safe access helpers and document the rules") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202506162214.1eA69hLe-lkp@intel.com/ +Reviewed-by: Christian König +Link: https://lore.kernel.org/r/20250616155952.24259-1-tvrtko.ursulin@igalia.com +Signed-off-by: Christian König +Signed-off-by: Sasha Levin +--- + drivers/dma-buf/dma-fence.c | 8 ++++---- + include/trace/events/dma_fence.h | 35 +++++--------------------------- + 2 files changed, 9 insertions(+), 34 deletions(-) + +diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c +index 35afcfcac5910..abb6d8f8f95d2 100644 +--- a/drivers/dma-buf/dma-fence.c ++++ b/drivers/dma-buf/dma-fence.c +@@ -1133,9 +1133,9 @@ const char __rcu *dma_fence_driver_name(struct dma_fence *fence) + "RCU protection is required for safe access to returned string"); + + if (!dma_fence_test_signaled_flag(fence)) +- return fence->ops->get_driver_name(fence); ++ return (const char __rcu *)fence->ops->get_driver_name(fence); + else +- return "detached-driver"; ++ return (const char __rcu *)"detached-driver"; + } + EXPORT_SYMBOL(dma_fence_driver_name); + +@@ -1165,8 +1165,8 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence) + "RCU protection is required for safe access to returned string"); + + if (!dma_fence_test_signaled_flag(fence)) +- return fence->ops->get_timeline_name(fence); ++ return (const char __rcu *)fence->ops->get_driver_name(fence); + else +- return "signaled-timeline"; ++ return (const char __rcu *)"signaled-timeline"; + } + EXPORT_SYMBOL(dma_fence_timeline_name); +diff --git a/include/trace/events/dma_fence.h b/include/trace/events/dma_fence.h +index 4814a65b68dcb..3abba45c0601a 100644 +--- a/include/trace/events/dma_fence.h ++++ b/include/trace/events/dma_fence.h +@@ -9,37 +9,12 @@ + + struct dma_fence; + +-DECLARE_EVENT_CLASS(dma_fence, +- +- TP_PROTO(struct dma_fence *fence), +- +- TP_ARGS(fence), +- +- TP_STRUCT__entry( +- __string(driver, dma_fence_driver_name(fence)) +- __string(timeline, dma_fence_timeline_name(fence)) +- __field(unsigned int, context) +- __field(unsigned int, seqno) +- ), +- +- TP_fast_assign( +- __assign_str(driver); +- __assign_str(timeline); +- __entry->context = fence->context; +- __entry->seqno = fence->seqno; +- ), +- +- TP_printk("driver=%s timeline=%s context=%u seqno=%u", +- __get_str(driver), __get_str(timeline), __entry->context, +- __entry->seqno) +-); +- + /* + * Safe only for call sites which are guaranteed to not race with fence + * signaling,holding the fence->lock and having checked for not signaled, or the + * signaling path itself. + */ +-DECLARE_EVENT_CLASS(dma_fence_unsignaled, ++DECLARE_EVENT_CLASS(dma_fence, + + TP_PROTO(struct dma_fence *fence), + +@@ -64,14 +39,14 @@ DECLARE_EVENT_CLASS(dma_fence_unsignaled, + __entry->seqno) + ); + +-DEFINE_EVENT(dma_fence_unsignaled, dma_fence_emit, ++DEFINE_EVENT(dma_fence, dma_fence_emit, + + TP_PROTO(struct dma_fence *fence), + + TP_ARGS(fence) + ); + +-DEFINE_EVENT(dma_fence_unsignaled, dma_fence_init, ++DEFINE_EVENT(dma_fence, dma_fence_init, + + TP_PROTO(struct dma_fence *fence), + +@@ -85,14 +60,14 @@ DEFINE_EVENT(dma_fence, dma_fence_destroy, + TP_ARGS(fence) + ); + +-DEFINE_EVENT(dma_fence_unsignaled, dma_fence_enable_signal, ++DEFINE_EVENT(dma_fence, dma_fence_enable_signal, + + TP_PROTO(struct dma_fence *fence), + + TP_ARGS(fence) + ); + +-DEFINE_EVENT(dma_fence_unsignaled, dma_fence_signaled, ++DEFINE_EVENT(dma_fence, dma_fence_signaled, + + TP_PROTO(struct dma_fence *fence), + +-- +2.53.0 + diff --git a/queue-7.0/dmaengine-dw-axi-dmac-fix-alignment-should-match-ope.patch b/queue-7.0/dmaengine-dw-axi-dmac-fix-alignment-should-match-ope.patch new file mode 100644 index 0000000000..4cd9f11e54 --- /dev/null +++ b/queue-7.0/dmaengine-dw-axi-dmac-fix-alignment-should-match-ope.patch @@ -0,0 +1,96 @@ +From 0dd05a01147e156e281788e8fb66f3c6b3307583 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 14:02:17 +0800 +Subject: dmaengine: dw-axi-dmac: fix Alignment should match open parenthesis + +From: Khairul Anuar Romli + +[ Upstream commit 6c5883a9ba296d2797437066592d15b2d202de7a ] + +checkpatch.pl --strict reports a CHECK warning in dw-axi-dmac-platform.c: + + CHECK: Alignment should match open parenthesis + +This warning occurs when multi-line function calls or expressions have +continuation lines that don't properly align with the opening parenthesis +position. + +This patch fixes all instances in dw-axi-dmac-platform.c where continuation +lines were indented with an inconsistent number of spaces/tabs that neither +matched the parenthesis column nor followed a standard indent pattern. +Proper alignment improves code readability and maintainability by making +parameter lists visually consistent across the kernel codebase. + +Fixes: 1fe20f1b8454 ("dmaengine: Introduce DW AXI DMAC driver") +Fixes: e32634f466a9 ("dma: dw-axi-dmac: support per channel interrupt") +Signed-off-by: Khairul Anuar Romli +Link: https://patch.msgid.link/20260202060224.12616-2-karom.9560@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index 5d74bc29cf896..b9fbfeb873e76 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -342,8 +342,8 @@ static void axi_desc_put(struct axi_dma_desc *desc) + kfree(desc); + atomic_sub(descs_put, &chan->descs_allocated); + dev_vdbg(chan2dev(chan), "%s: %d descs put, %d still allocated\n", +- axi_chan_name(chan), descs_put, +- atomic_read(&chan->descs_allocated)); ++ axi_chan_name(chan), descs_put, ++ atomic_read(&chan->descs_allocated)); + } + + static void vchan_desc_put(struct virt_dma_desc *vdesc) +@@ -353,7 +353,7 @@ static void vchan_desc_put(struct virt_dma_desc *vdesc) + + static enum dma_status + dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, +- struct dma_tx_state *txstate) ++ struct dma_tx_state *txstate) + { + struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan); + struct virt_dma_desc *vdesc; +@@ -491,7 +491,7 @@ static void axi_chan_start_first_queued(struct axi_dma_chan *chan) + + desc = vd_to_axi_desc(vd); + dev_vdbg(chan2dev(chan), "%s: started %u\n", axi_chan_name(chan), +- vd->tx.cookie); ++ vd->tx.cookie); + axi_chan_block_xfer_start(chan, desc); + } + +@@ -1162,7 +1162,7 @@ static irqreturn_t dw_axi_dma_interrupt(int irq, void *dev_id) + axi_chan_irq_clear(chan, status); + + dev_vdbg(chip->dev, "%s %u IRQ status: 0x%08x\n", +- axi_chan_name(chan), i, status); ++ axi_chan_name(chan), i, status); + + if (status & DWAXIDMAC_IRQ_ALL_ERR) + axi_chan_handle_err(chan, status); +@@ -1451,7 +1451,7 @@ static int axi_req_irqs(struct platform_device *pdev, struct axi_dma_chip *chip) + if (chip->irq[i] < 0) + return chip->irq[i]; + ret = devm_request_irq(chip->dev, chip->irq[i], dw_axi_dma_interrupt, +- IRQF_SHARED, KBUILD_MODNAME, chip); ++ IRQF_SHARED, KBUILD_MODNAME, chip); + if (ret < 0) + return ret; + } +@@ -1645,7 +1645,7 @@ static void dw_remove(struct platform_device *pdev) + of_dma_controller_free(chip->dev->of_node); + + list_for_each_entry_safe(chan, _chan, &dw->dma.channels, +- vc.chan.device_node) { ++ vc.chan.device_node) { + list_del(&chan->vc.chan.device_node); + tasklet_kill(&chan->vc.task); + } +-- +2.53.0 + diff --git a/queue-7.0/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch b/queue-7.0/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch new file mode 100644 index 0000000000..01685b9676 --- /dev/null +++ b/queue-7.0/dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch @@ -0,0 +1,50 @@ +From 21778c48696ada4e0ca170651b1747d6e5c73a3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 14:02:19 +0800 +Subject: dmaengine: dw-axi-dmac: Remove unnecessary return statement from void + function + +From: Khairul Anuar Romli + +[ Upstream commit 48278a72fce8a8d30efaedeb206c9c3f05c1eb3f ] + +checkpatch.pl --strict reports a WARNING in dw-axi-dmac-platform.c: + + WARNING: void function return statements are not generally useful + FILE: drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c + +According to Linux kernel coding style [Documentation/process/ +coding-style.rst], explicit "return;" statements at the end of void +functions are redundant and should be omitted. The function will +automatically return upon reaching the closing brace, so the extra +statement adds unnecessary clutter without functional benefit. + +This patch removes the superfluous "return;" statement in +dw_axi_dma_set_hw_channel() to comply with kernel coding standards and +eliminate the checkpatch warning. + +Fixes: 32286e279385 ("dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel") +Signed-off-by: Khairul Anuar Romli +Link: https://patch.msgid.link/20260202060224.12616-4-karom.9560@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +index b9fbfeb873e76..95e460422b2ad 100644 +--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c ++++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +@@ -592,8 +592,6 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) + (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0); +- +- return; + } + + /* +-- +2.53.0 + diff --git a/queue-7.0/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch b/queue-7.0/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch new file mode 100644 index 0000000000..ffd23b7c72 --- /dev/null +++ b/queue-7.0/dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch @@ -0,0 +1,37 @@ +From 146f1621bbb453cc87812c69dd14b5d4f2166908 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:41:38 -0500 +Subject: dmaengine: mxs-dma: Fix missing return value from + of_dma_controller_register() + +From: Frank Li + +[ Upstream commit ab2bf6d4c0a0152907b18d25c1b118ea5ea779df ] + +Propagate the return value of of_dma_controller_register() in probe() +instead of ignoring it. + +Fixes: a580b8c5429a6 ("dmaengine: mxs-dma: add dma support for i.MX23/28") +Signed-off-by: Frank Li +Link: https://patch.msgid.link/20260225-mxsdma-module-v3-2-8f798b13baa6@nxp.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/dma/mxs-dma.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c +index cfb9962417ef6..53f572b6b6fc6 100644 +--- a/drivers/dma/mxs-dma.c ++++ b/drivers/dma/mxs-dma.c +@@ -824,6 +824,7 @@ static int mxs_dma_probe(struct platform_device *pdev) + if (ret) { + dev_err(mxs_dma->dma_device.dev, + "failed to register controller\n"); ++ return ret; + } + + dev_info(mxs_dma->dma_device.dev, "initialized\n"); +-- +2.53.0 + diff --git a/queue-7.0/docs-admin-guide-mm-damn-lru_sort-fix-intervals-auto.patch b/queue-7.0/docs-admin-guide-mm-damn-lru_sort-fix-intervals-auto.patch new file mode 100644 index 0000000000..b41ddae11d --- /dev/null +++ b/queue-7.0/docs-admin-guide-mm-damn-lru_sort-fix-intervals-auto.patch @@ -0,0 +1,51 @@ +From 1b94b3fbff8058673d35793a82e6fcf5ea69a71e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 11:53:53 -0800 +Subject: Docs/admin-guide/mm/damn/lru_sort: fix intervals autotune parameter + name + +From: SeongJae Park + +[ Upstream commit d7f00084f6863a243b396200c81e83ae302c5a76 ] + +The section name should be the same as the parameter name. Fix it. + +Link: https://lkml.kernel.org/r/20260307195356.203753-6-sj@kernel.org +Fixes: ed581147a417 ("Docs/admin-guide/mm/damon/lru_sort: document intervals autotuning") +Signed-off-by: SeongJae Park +Acked-by: wang lian +Cc: Brendan Higgins +Cc: David Gow +Cc: David Hildenbrand +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/admin-guide/mm/damon/lru_sort.rst | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Documentation/admin-guide/mm/damon/lru_sort.rst b/Documentation/admin-guide/mm/damon/lru_sort.rst +index 63977a89025e5..5f38910c0ba7e 100644 +--- a/Documentation/admin-guide/mm/damon/lru_sort.rst ++++ b/Documentation/admin-guide/mm/damon/lru_sort.rst +@@ -95,8 +95,8 @@ increases and decreases the effective level of the quota aiming the LRU + + Disabled by default. + +-Auto-tune monitoring intervals +------------------------------- ++autotune_monitoring_intervals ++----------------------------- + + If this parameter is set as ``Y``, DAMON_LRU_SORT automatically tunes DAMON's + sampling and aggregation intervals. The auto-tuning aims to capture meaningful +-- +2.53.0 + diff --git a/queue-7.0/docs-mm-damon-index-fix-typo-autoamted-automated.patch b/queue-7.0/docs-mm-damon-index-fix-typo-autoamted-automated.patch new file mode 100644 index 0000000000..0277ea72b5 --- /dev/null +++ b/queue-7.0/docs-mm-damon-index-fix-typo-autoamted-automated.patch @@ -0,0 +1,48 @@ +From 11b2de9e1dae7e64d5b1e86d990907acb407eed2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 11:53:55 -0800 +Subject: Docs/mm/damon/index: fix typo: autoamted -> automated + +From: SeongJae Park + +[ Upstream commit a4e82de81fe59d5bfcc9450145e8e108561f2e07 ] + +There is an obvious typo. Fix it (s/autoamted/automated/). + +Link: https://lkml.kernel.org/r/20260307195356.203753-8-sj@kernel.org +Fixes: 32d11b320897 ("Docs/mm/damon/index: simplify the intro") +Signed-off-by: SeongJae Park +Acked-by: wang lian +Cc: Brendan Higgins +Cc: David Gow +Cc: David Hildenbrand +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/mm/damon/index.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/mm/damon/index.rst b/Documentation/mm/damon/index.rst +index 82f6c5eea49a7..318f6a7bfea47 100644 +--- a/Documentation/mm/damon/index.rst ++++ b/Documentation/mm/damon/index.rst +@@ -12,7 +12,7 @@ DAMON is a Linux kernel subsystem for efficient :ref:`data access monitoring + - *light-weight* (for production online usages), + - *scalable* (in terms of memory size), + - *tunable* (for flexible usages), and +- - *autoamted* (for production operation without manual tunings). ++ - *automated* (for production operation without manual tunings). + + .. toctree:: + :maxdepth: 2 +-- +2.53.0 + diff --git a/queue-7.0/documentation-fix-a-hugetlbfs-reservation-statement.patch b/queue-7.0/documentation-fix-a-hugetlbfs-reservation-statement.patch new file mode 100644 index 0000000000..a543be7544 --- /dev/null +++ b/queue-7.0/documentation-fix-a-hugetlbfs-reservation-statement.patch @@ -0,0 +1,63 @@ +From c492e2c6a022584a0b134951e4763bb011805e68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 13:10:15 -0700 +Subject: Documentation: fix a hugetlbfs reservation statement + +From: Jane Chu + +[ Upstream commit 7a197d346a44384a1a858a98ef03766840e561d4 ] + +Documentation/mm/hugetlbfs_reserv.rst has + if (resv_needed <= (resv_huge_pages - free_huge_pages)) + resv_huge_pages += resv_needed; +which describes this code in gather_surplus_pages() + needed = (h->resv_huge_pages + delta) - h->free_huge_pages; + if (needed <= 0) { + h->resv_huge_pages += delta; + return 0; + } +which means if there are enough free hugepages to account for the new +reservation, simply update the global reservation count without +further action. + +But the description is backwards, it should be + if (resv_needed <= (free_huge_pages - resv_huge_pages)) +instead. + +Link: https://lkml.kernel.org/r/20260302201015.1824798-1-jane.chu@oracle.com +Fixes: 70bc0dc578b3 ("Documentation: vm, add hugetlbfs reservation overview") +Signed-off-by: Jane Chu +Cc: David Hildenbrand +Cc: Hillf Danton +Cc: Jonathan Corbet +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Oscar Salvador +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + Documentation/mm/hugetlbfs_reserv.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/mm/hugetlbfs_reserv.rst b/Documentation/mm/hugetlbfs_reserv.rst +index 4914fbf07966c..a49115db18c76 100644 +--- a/Documentation/mm/hugetlbfs_reserv.rst ++++ b/Documentation/mm/hugetlbfs_reserv.rst +@@ -155,7 +155,7 @@ are enough free huge pages to accommodate the reservation. If there are, + the global reservation count resv_huge_pages is adjusted something like the + following:: + +- if (resv_needed <= (resv_huge_pages - free_huge_pages)) ++ if (resv_needed <= (free_huge_pages - resv_huge_pages) + resv_huge_pages += resv_needed; + + Note that the global lock hugetlb_lock is held when checking and adjusting +-- +2.53.0 + diff --git a/queue-7.0/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch b/queue-7.0/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch new file mode 100644 index 0000000000..7893158f57 --- /dev/null +++ b/queue-7.0/dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch @@ -0,0 +1,54 @@ +From 19b7014304116ba6d71a9f499ff8d1de60190552 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:06 +0000 +Subject: dpaa2: add independent dependencies for FSL_DPAA2_SWITCH + +From: Cai Xinchen + +[ Upstream commit 12589892f41c4c645c80ef9f036f7451a6045624 ] + +Since the commit 84cba72956fd ("dpaa2-switch: integrate +the MAC endpoint support") included dpaa2-mac.o in the driver, +but it didn't select PCS_LYNX, PHYLINK and FSL_XGMAC_MDIO. it +will lead to link error, such as +undefined reference to `phylink_ethtool_ksettings_set' +undefined reference to `lynx_pcs_create_fwnode' + +And the same reason as the commit d2624e70a2f53 ("dpaa2-eth: select +XGMAC_MDIO for MDIO bus support"), enable the FSL_XGMAC_MDIO Kconfig +option in order to have MDIO access to internal and external PHYs. + +Because dpaa2-switch uses fsl_mc_driver APIs, add depends on FSL_MC_BUS +&& FSL_MC_DPIO as FSL_DPAA2_SWITCH do. + +FSL_XGMAC_MDIO and FSL_MC_BUS depend on OF, thus the dependence of +FSL_MC_BUS can satisfy FSL_XGMAC_MDIO's OF requirement. + +Fixes: 84cba72956fd ("dpaa2-switch: integrate the MAC endpoint support") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-2-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/dpaa2/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig +index d029b69c3f183..36280e5d99e1f 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/Kconfig ++++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig +@@ -34,6 +34,10 @@ config FSL_DPAA2_SWITCH + tristate "Freescale DPAA2 Ethernet Switch" + depends on BRIDGE || BRIDGE=n + depends on NET_SWITCHDEV ++ depends on FSL_MC_BUS && FSL_MC_DPIO ++ select PHYLINK ++ select PCS_LYNX ++ select FSL_XGMAC_MDIO + help + Driver for Freescale DPAA2 Ethernet Switch. This driver manages + switch objects discovered on the Freeescale MC bus. +-- +2.53.0 + diff --git a/queue-7.0/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch b/queue-7.0/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch new file mode 100644 index 0000000000..0b1149f182 --- /dev/null +++ b/queue-7.0/dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch @@ -0,0 +1,42 @@ +From 4efa4a2ce0bf304e726cdad2dfcc5a05f41ae9e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 06:59:07 +0000 +Subject: dpaa2: compile dpaa2 even CONFIG_FSL_DPAA2_ETH=n + +From: Cai Xinchen + +[ Upstream commit 97daf00745f7f9f261b0e91418de6e79d7826c36 ] + +CONFIG_FSL_DPAA2_ETH and CONFIG_FSL_DPAA2_SWITCH are not +associated, but the compilation of FSL_DPAA2_SWITCH depends on +the compilation of the dpaa2 folder. The files controlled by +CONFIG_FSL_DPAA2_SWITCH in the dpaa2 folder are not controlled +by CONFIG_FSL_DPAA2_ETH, except for the files controlled by +CONFIG_FSL_DPAA2_SWITCH. Therefore, removing the restriction will +not affect the compilation of the files in the directory. + +Fixes: f48298d3fbfaa ("staging: dpaa2-switch: move the driver out of staging") +Suggested-by: Ioana Ciornei +Signed-off-by: Cai Xinchen +Link: https://patch.msgid.link/20260312065907.476663-3-caixinchen1@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/Makefile | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile +index de7b318422330..d0a259e47960f 100644 +--- a/drivers/net/ethernet/freescale/Makefile ++++ b/drivers/net/ethernet/freescale/Makefile +@@ -22,6 +22,5 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o + obj-$(CONFIG_FSL_FMAN) += fman/ + obj-$(CONFIG_FSL_DPAA_ETH) += dpaa/ + +-obj-$(CONFIG_FSL_DPAA2_ETH) += dpaa2/ +- ++obj-y += dpaa2/ + obj-y += enetc/ +-- +2.53.0 + diff --git a/queue-7.0/dpll-export-__dpll_pin_change_ntf-for-use-under-dpll.patch b/queue-7.0/dpll-export-__dpll_pin_change_ntf-for-use-under-dpll.patch new file mode 100644 index 0000000000..5279457de3 --- /dev/null +++ b/queue-7.0/dpll-export-__dpll_pin_change_ntf-for-use-under-dpll.patch @@ -0,0 +1,83 @@ +From 82f44aefa4db12dde1f0f96329936fdb130f7c2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:21 -0700 +Subject: dpll: export __dpll_pin_change_ntf() for use under dpll_lock + +From: Ivan Vecera + +[ Upstream commit 620055cb1036a6125fd912e7a14b47a6572b809b ] + +Export __dpll_pin_change_ntf() so that drivers can send pin change +notifications from within pin callbacks, which are already called +under dpll_lock. Using dpll_pin_change_ntf() in that context would +deadlock. + +Add lockdep_assert_held() to catch misuse without the lock held. + +Acked-by: Vadim Fedorenko +Signed-off-by: Ivan Vecera +Signed-off-by: Petr Oros +Tested-by: Alexander Nowlin +Reviewed-by: Arkadiusz Kubalewski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-9-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 9e5dead140af ("ice: add dpll peer notification for paired SMA and U.FL pins") +Signed-off-by: Sasha Levin +--- + drivers/dpll/dpll_netlink.c | 10 ++++++++++ + drivers/dpll/dpll_netlink.h | 2 -- + include/linux/dpll.h | 1 + + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c +index 83cbd64abf5a4..95ae786e98aab 100644 +--- a/drivers/dpll/dpll_netlink.c ++++ b/drivers/dpll/dpll_netlink.c +@@ -842,11 +842,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin) + return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); + } + ++/** ++ * __dpll_pin_change_ntf - notify that the pin has been changed ++ * @pin: registered pin pointer ++ * ++ * Context: caller must hold dpll_lock. Suitable for use inside pin ++ * callbacks which are already invoked under dpll_lock. ++ * Return: 0 if succeeds, error code otherwise. ++ */ + int __dpll_pin_change_ntf(struct dpll_pin *pin) + { ++ lockdep_assert_held(&dpll_lock); + dpll_pin_notify(pin, DPLL_PIN_CHANGED); + return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); + } ++EXPORT_SYMBOL_GPL(__dpll_pin_change_ntf); + + /** + * dpll_pin_change_ntf - notify that the pin has been changed +diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h +index dd28b56d27c56..a9cfd55f57fc4 100644 +--- a/drivers/dpll/dpll_netlink.h ++++ b/drivers/dpll/dpll_netlink.h +@@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll); + int dpll_pin_create_ntf(struct dpll_pin *pin); + + int dpll_pin_delete_ntf(struct dpll_pin *pin); +- +-int __dpll_pin_change_ntf(struct dpll_pin *pin); +diff --git a/include/linux/dpll.h b/include/linux/dpll.h +index 2ce295b46b8cd..8f97120ee7b37 100644 +--- a/include/linux/dpll.h ++++ b/include/linux/dpll.h +@@ -276,6 +276,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin, + + int dpll_device_change_ntf(struct dpll_device *dpll); + ++int __dpll_pin_change_ntf(struct dpll_pin *pin); + int dpll_pin_change_ntf(struct dpll_pin *pin); + + int register_dpll_notifier(struct notifier_block *nb); +-- +2.53.0 + diff --git a/queue-7.0/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch b/queue-7.0/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch new file mode 100644 index 0000000000..3821d6f735 --- /dev/null +++ b/queue-7.0/drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch @@ -0,0 +1,59 @@ +From 4721821786382a8ce6bfcdbec7d5faa654b75674 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:40:54 -0700 +Subject: drbd: Balance RCU calls in drbd_adm_dump_devices() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bart Van Assche + +[ Upstream commit 2b31e86387e60b3689339f0f0fbb4d3623d9d494 ] + +Make drbd_adm_dump_devices() call rcu_read_lock() before +rcu_read_unlock() is called. This has been detected by the Clang +thread-safety analyzer. + +Tested-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Cc: Andreas Gruenbacher +Fixes: a55bbd375d18 ("drbd: Backport the "status" command") +Signed-off-by: Bart Van Assche +Link: https://patch.msgid.link/20260326214054.284593-1-bvanassche@acm.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_nl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index e201f0087a0f7..728ecc431b38d 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -3378,8 +3378,10 @@ int drbd_adm_dump_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + cb->args[0] = (long)resource; + } + } +@@ -3628,8 +3630,10 @@ int drbd_adm_dump_peer_devices(struct sk_buff *skb, struct netlink_callback *cb) + if (resource_filter) { + retcode = ERR_RES_NOT_KNOWN; + resource = drbd_find_resource(nla_data(resource_filter)); +- if (!resource) ++ if (!resource) { ++ rcu_read_lock(); + goto put_result; ++ } + } + cb->args[0] = (long)resource; + } +-- +2.53.0 + diff --git a/queue-7.0/drivers-hv-vmbus-fix-hyperv_cpuhp_online-variable-sh.patch b/queue-7.0/drivers-hv-vmbus-fix-hyperv_cpuhp_online-variable-sh.patch new file mode 100644 index 0000000000..a9d086cf5f --- /dev/null +++ b/queue-7.0/drivers-hv-vmbus-fix-hyperv_cpuhp_online-variable-sh.patch @@ -0,0 +1,46 @@ +From d9faa0dc10a382be9e2e1fe090f13c343ef79f48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 18:36:38 -0700 +Subject: Drivers: hv: vmbus: fix hyperv_cpuhp_online variable shadowing + +From: Jork Loeser + +[ Upstream commit 3c42b33433796b73ddecd8f60bda419b1648d997 ] + +vmbus_alloc_synic_and_connect() declares a local 'int +hyperv_cpuhp_online' that shadows the file-scope global of the same +name. The cpuhp state returned by cpuhp_setup_state() is stored in +the local, leaving the global at 0 (CPUHP_OFFLINE). When +hv_kexec_handler() or hv_machine_shutdown() later call +cpuhp_remove_state(hyperv_cpuhp_online) they pass 0, which hits the +BUG_ON in __cpuhp_remove_state_cpuslocked(). + +Remove the local declaration so the cpuhp state is stored in the +file-scope global where hv_kexec_handler() and hv_machine_shutdown() +expect it. + +Fixes: 2647c96649ba ("Drivers: hv: Support establishing the confidential VMBus connection") +Signed-off-by: Jork Loeser +Reviewed-by: Stanislav Kinsburskii +Reviewed-by: Anirudh Rayabharam (Microsoft) +Signed-off-by: Wei Liu +Signed-off-by: Sasha Levin +--- + drivers/hv/vmbus_drv.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c +index bc4fc1951ae1c..3d2827477f0a5 100644 +--- a/drivers/hv/vmbus_drv.c ++++ b/drivers/hv/vmbus_drv.c +@@ -1430,7 +1430,6 @@ static int vmbus_alloc_synic_and_connect(void) + { + int ret, cpu; + struct work_struct __percpu *works; +- int hyperv_cpuhp_online; + + ret = hv_synic_alloc(); + if (ret < 0) +-- +2.53.0 + diff --git a/queue-7.0/drivers-vfio_pci_core-change-pxd_order-check-from-sw.patch b/queue-7.0/drivers-vfio_pci_core-change-pxd_order-check-from-sw.patch new file mode 100644 index 0000000000..62b66c4b78 --- /dev/null +++ b/queue-7.0/drivers-vfio_pci_core-change-pxd_order-check-from-sw.patch @@ -0,0 +1,93 @@ +From 1db79ad55d5e27f84f64b066fcbbb8aa574a817e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 18:08:37 +0530 +Subject: drivers/vfio_pci_core: Change PXD_ORDER check from switch case to + if/else block +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ritesh Harjani (IBM) + +[ Upstream commit 948b71aa81cd89b222942db6055e8d9c51c54e78 ] + +Architectures like PowerPC uses runtime defined values for +PMD_ORDER/PUD_ORDER. This is because it can use either RADIX or HASH MMU +at runtime using kernel cmdline. So the pXd_index_size is not known at +compile time. Without this fix, when we add huge pfn support on powerpc +in the next patch, vfio_pci_core driver compilation can fail with the +following errors. + + CC [M] drivers/vfio/vfio_main.o + CC [M] drivers/vfio/group.o + CC [M] drivers/vfio/container.o + CC [M] drivers/vfio/virqfd.o + CC [M] drivers/vfio/vfio_iommu_spapr_tce.o + CC [M] drivers/vfio/pci/vfio_pci_core.o + CC [M] drivers/vfio/pci/vfio_pci_intrs.o + CC [M] drivers/vfio/pci/vfio_pci_rdwr.o + CC [M] drivers/vfio/pci/vfio_pci_config.o + CC [M] drivers/vfio/pci/vfio_pci.o + AR kernel/built-in.a +../drivers/vfio/pci/vfio_pci_core.c: In function ‘vfio_pci_vmf_insert_pfn’: +../drivers/vfio/pci/vfio_pci_core.c:1678:9: error: case label does not reduce to an integer constant + 1678 | case PMD_ORDER: + | ^~~~ +../drivers/vfio/pci/vfio_pci_core.c:1682:9: error: case label does not reduce to an integer constant + 1682 | case PUD_ORDER: + | ^~~~ +make[6]: *** [../scripts/Makefile.build:289: drivers/vfio/pci/vfio_pci_core.o] Error 1 +make[6]: *** Waiting for unfinished jobs.... +make[5]: *** [../scripts/Makefile.build:546: drivers/vfio/pci] Error 2 +make[5]: *** Waiting for unfinished jobs.... +make[4]: *** [../scripts/Makefile.build:546: drivers/vfio] Error 2 +make[3]: *** [../scripts/Makefile.build:546: drivers] Error 2 + +Fixes: f9e54c3a2f5b7 ("vfio/pci: implement huge_fault support") +Signed-off-by: Ritesh Harjani (IBM) +Tested-by: Venkat Rao Bagalkote +Reviewed-by: Alex Williamson +Reviewed-by: Christophe Leroy (CS GROUP) +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/b155e19993ee1f5584c72050192eb468b31c5029.1773058761.git.ritesh.list@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/vfio/pci/vfio_pci_core.c | 19 +++++++------------ + 1 file changed, 7 insertions(+), 12 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index 460852f79f29b..3fea064d00de2 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -1670,21 +1670,16 @@ vm_fault_t vfio_pci_vmf_insert_pfn(struct vfio_pci_core_device *vdev, + if (vdev->pm_runtime_engaged || !__vfio_pci_memory_enabled(vdev)) + return VM_FAULT_SIGBUS; + +- switch (order) { +- case 0: ++ if (!order) + return vmf_insert_pfn(vmf->vma, vmf->address, pfn); +-#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP +- case PMD_ORDER: ++ ++ if (IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP) && order == PMD_ORDER) + return vmf_insert_pfn_pmd(vmf, pfn, false); +-#endif +-#ifdef CONFIG_ARCH_SUPPORTS_PUD_PFNMAP +- case PUD_ORDER: ++ ++ if (IS_ENABLED(CONFIG_ARCH_SUPPORTS_PUD_PFNMAP) && order == PUD_ORDER) + return vmf_insert_pfn_pud(vmf, pfn, false); +- break; +-#endif +- default: +- return VM_FAULT_FALLBACK; +- } ++ ++ return VM_FAULT_FALLBACK; + } + EXPORT_SYMBOL_GPL(vfio_pci_vmf_insert_pfn); + +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-allow-constructing-dce6-link-encoder.patch b/queue-7.0/drm-amd-display-allow-constructing-dce6-link-encoder.patch new file mode 100644 index 0000000000..fce025fc6b --- /dev/null +++ b/queue-7.0/drm-amd-display-allow-constructing-dce6-link-encoder.patch @@ -0,0 +1,44 @@ +From 01d5532da36fa05d76b6967159fbce773f0de3a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:42 +0200 +Subject: drm/amd/display: Allow constructing DCE6 link encoder without DDC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 880498a1943f865529819f778df3b9945ca57262 ] + +When the DDC channel ID is set to CHANNEL_ID_UNKNOWN, +pass NULL to the AUX regs array. + +This is necessary to support embedded connectors without DDC. + +Fixes: 7c15fd86aaec ("drm/amd/display: dc/dce: add initial DCE6 support (v10)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 38a70e50b22a188ff601740d64dd75f46213121f) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +index 3d52973dd7f20..15f220671fbed 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +@@ -753,7 +753,8 @@ static struct link_encoder *dce60_link_encoder_create( + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], +- &link_enc_aux_regs[enc_init_data->channel - 1], ++ enc_init_data->channel == CHANNEL_ID_UNKNOWN ? ++ NULL : &link_enc_aux_regs[enc_init_data->channel - 1], + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-allow-constructing-dce8-link-encoder.patch b/queue-7.0/drm-amd-display-allow-constructing-dce8-link-encoder.patch new file mode 100644 index 0000000000..68aee5c91d --- /dev/null +++ b/queue-7.0/drm-amd-display-allow-constructing-dce8-link-encoder.patch @@ -0,0 +1,44 @@ +From 50d12330cec04808b2a282c83bc273fcab21358a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:43 +0200 +Subject: drm/amd/display: Allow constructing DCE8 link encoder without DDC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 60af4605ef35ecb7ad649a8534b83a2f7c69576d ] + +When the DDC channel ID is set to CHANNEL_ID_UNKNOWN, +pass NULL to the AUX regs array. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 155baf3038c1af50b602723022ed869b38e86a99) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +index 89927727a0d9e..42d0bd656f793 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +@@ -759,7 +759,8 @@ static struct link_encoder *dce80_link_encoder_create( + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], +- &link_enc_aux_regs[enc_init_data->channel - 1], ++ enc_init_data->channel == CHANNEL_ID_UNKNOWN ? ++ NULL : &link_enc_aux_regs[enc_init_data->channel - 1], + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch b/queue-7.0/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch new file mode 100644 index 0000000000..242c7c3a25 --- /dev/null +++ b/queue-7.0/drm-amd-display-allow-dce-link-encoder-without-aux-r.patch @@ -0,0 +1,45 @@ +From 584f7f4b4c947ffbcf88529f71019bfac3c6cf3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:41 +0200 +Subject: drm/amd/display: Allow DCE link encoder without AUX registers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ] + +Allow constructing the DCE link encoder without DDC, +which means the AUX registers array will be NULL. + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 87f30b101af62590faf6020d106da07efdda199b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +index 2ba3d3a3aac58..d2b36cfb28c3d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c ++++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +@@ -1071,7 +1071,9 @@ void dce110_link_encoder_hw_init( + ASSERT(result == BP_RESULT_OK); + + } +- aux_initialize(enc110); ++ ++ if (enc110->aux_regs) ++ aux_initialize(enc110); + + /* reinitialize HPD. + * hpd_initialize() will pass DIG_FE id to HW context. +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-allow-embedded-connectors-without-dd.patch b/queue-7.0/drm-amd-display-allow-embedded-connectors-without-dd.patch new file mode 100644 index 0000000000..65126bedcc --- /dev/null +++ b/queue-7.0/drm-amd-display-allow-embedded-connectors-without-dd.patch @@ -0,0 +1,75 @@ +From 144a92e4dcb7fbdd8c59206abe333c71b37cc753 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:40 +0200 +Subject: drm/amd/display: Allow embedded connectors without DDC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 494941aa772dab79251543764db6cd14bd337e43 ] + +On some laptops, the embedded panel may not have +a DDC (display data channel) available. On these, +the EDID may be hardcoded in ACPI or the VBIOS. + +In this case, use GPIO_DDC_LINE_UNKNOWN and don't fail. + +Fixes: def3488eb0fd ("drm/amd/display: refactor HPD to increase flexibility") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 75b8a6ca0e8bc3ce24572f854e95f8721b321179) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dc.h | 2 +- + drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c | 3 +++ + drivers/gpu/drm/amd/display/dc/link/link_factory.c | 4 +++- + 3 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index 4c4239cac863d..8044c80971f04 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -1638,7 +1638,7 @@ struct dc_scratch_space { + struct dc_link_training_overrides preferred_training_settings; + struct dp_audio_test_data audio_test_data; + +- uint8_t ddc_hw_inst; ++ enum gpio_ddc_line ddc_hw_inst; + + uint8_t hpd_src; + +diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +index a2c46350e44e8..95f8b7c7d657a 100644 +--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c ++++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +@@ -646,6 +646,9 @@ enum gpio_result dal_ddc_change_mode( + enum gpio_ddc_line dal_ddc_get_line( + const struct ddc *ddc) + { ++ if (!ddc) ++ return GPIO_DDC_LINE_UNKNOWN; ++ + return (enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data); + } + +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +index 21815ad01a295..409cc6e6cd846 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c +@@ -549,7 +549,9 @@ static bool construct_phy(struct dc_link *link, + goto ddc_create_fail; + } + +- if (!link->ddc->ddc_pin) { ++ /* Embedded display connectors such as LVDS may not have DDC. */ ++ if (!link->ddc->ddc_pin && ++ !dc_is_embedded_signal(link->connector_signal)) { + DC_ERROR("Failed to get I2C info for connector!\n"); + goto ddc_create_fail; + } +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-avoid-null-dereference-in-dc_dmub_sr.patch b/queue-7.0/drm-amd-display-avoid-null-dereference-in-dc_dmub_sr.patch new file mode 100644 index 0000000000..a429586e73 --- /dev/null +++ b/queue-7.0/drm-amd-display-avoid-null-dereference-in-dc_dmub_sr.patch @@ -0,0 +1,78 @@ +From 5d3a385bb74710da54533960a6b3a9e851868649 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 13:02:09 +0530 +Subject: drm/amd/display: Avoid NULL dereference in dc_dmub_srv error paths + +From: Srinivasan Shanmugam + +[ Upstream commit 4ae3e16f4b3bf64140f773629b765d605ee079a9 ] + +In dc_dmub_srv_log_diagnostic_data() and +dc_dmub_srv_enable_dpia_trace(). + +Both functions check: + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + +and then call DC_LOG_ERROR() inside that block. + +DC_LOG_ERROR() uses dc_dmub_srv->ctx internally. So if +dc_dmub_srv is NULL, the logging itself can dereference a +NULL pointer and cause a crash. + +Fix this by splitting the checks. + +First check if dc_dmub_srv is NULL and return immediately. +Then check dc_dmub_srv->dmub and log the error only when +dc_dmub_srv is valid. + +Fixes the below: +../display/dc/dc_dmub_srv.c:962 dc_dmub_srv_log_diagnostic_data() error: we previously assumed 'dc_dmub_srv' could be null (see line 961) +../display/dc/dc_dmub_srv.c:1167 dc_dmub_srv_enable_dpia_trace() error: we previously assumed 'dc_dmub_srv' could be null (see line 1166) + +Fixes: 2631ac1ac328 ("drm/amd/display: add DMUB registers to crash dump diagnostic data.") +Fixes: 71ba6b577a35 ("drm/amd/display: Add interface to enable DPIA trace") +Cc: Roman Li +Cc: Alex Hung +Cc: Tom Chung +Cc: Dan Carpenter +Cc: Aurabindo Pillai +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Alex Hung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +index b15360bcdacf7..b3cedaa596c02 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c ++++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +@@ -958,7 +958,10 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv) + { + uint32_t i; + +- if (!dc_dmub_srv || !dc_dmub_srv->dmub) { ++ if (!dc_dmub_srv) ++ return; ++ ++ if (!dc_dmub_srv->dmub) { + DC_LOG_ERROR("%s: invalid parameters.", __func__); + return; + } +@@ -1163,7 +1166,10 @@ void dc_dmub_srv_enable_dpia_trace(const struct dc *dc) + { + struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; + +- if (!dc_dmub_srv || !dc_dmub_srv->dmub) { ++ if (!dc_dmub_srv) ++ return; ++ ++ if (!dc_dmub_srv->dmub) { + DC_LOG_ERROR("%s: invalid parameters.", __func__); + return; + } +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-fix-parameter-mismatch-in-panel-self.patch b/queue-7.0/drm-amd-display-fix-parameter-mismatch-in-panel-self.patch new file mode 100644 index 0000000000..8fce7adf38 --- /dev/null +++ b/queue-7.0/drm-amd-display-fix-parameter-mismatch-in-panel-self.patch @@ -0,0 +1,79 @@ +From 6a1d07fbdb943159d33c8cf894772480bba724e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 08:42:29 +0530 +Subject: drm/amd/display: Fix parameter mismatch in panel self-refresh helper + +From: Srinivasan Shanmugam + +[ Upstream commit f2483b3f39c8e20d2de0cc16e512a1b2aa14baf9 ] + +Align parameter names with function arguments. + +The function controls panel self-refresh enable/disable based on vblank +and VRR state. + +Fixes the below with gcc W=1: +../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'dm' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' +../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'acrtc' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' +../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'stream' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' +../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'dm' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' +../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'acrtc' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' +../display/amdgpu_dm/amdgpu_dm_crtc.c:131 function parameter 'stream' not described in 'amdgpu_dm_crtc_set_panel_sr_feature' + +Fixes: 754003486c3c ("drm/amd/display: Add Idle state manager(ISM)") +Cc: Ray Wu +Cc: Leo Li +Cc: Roman Li +Cc: Alex Hung +Cc: Tom Chung +Cc: Aurabindo Pillai +Cc: Mario Limonciello (AMD) +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Alex Hung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 21 +++++++++---------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +index 304437c2284d8..527d0ad69348e 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +@@ -101,23 +101,22 @@ bool amdgpu_dm_crtc_vrr_active(const struct dm_crtc_state *dm_state) + + /** + * amdgpu_dm_crtc_set_panel_sr_feature() - Manage panel self-refresh features. +- * +- * @vblank_work: is a pointer to a struct vblank_control_work object. +- * @vblank_enabled: indicates whether the DRM vblank counter is currently +- * enabled (true) or disabled (false). +- * @allow_sr_entry: represents whether entry into the self-refresh mode is +- * allowed (true) or not allowed (false). ++ * @dm: amdgpu display manager instance. ++ * @acrtc: CRTC whose panel self-refresh state is being updated. ++ * @stream: DC stream associated with @acrtc. ++ * @vblank_enabled: Whether the DRM vblank counter is currently enabled. ++ * @allow_sr_entry: Whether entry into self-refresh mode is allowed. + * + * The DRM vblank counter enable/disable action is used as the trigger to enable + * or disable various panel self-refresh features: + * + * Panel Replay and PSR SU + * - Enable when: +- * - VRR is disabled +- * - vblank counter is disabled +- * - entry is allowed: usermode demonstrates an adequate number of fast +- * commits) +- * - CRC capture window isn't active ++ * - VRR is disabled ++ * - vblank counter is disabled ++ * - entry is allowed: usermode demonstrates an adequate number of fast ++ * commits ++ * - CRC capture window isn't active + * - Keep enabled even when vblank counter gets enabled + * + * PSR1 +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-properly-handle-family-setting-for-e.patch b/queue-7.0/drm-amd-display-properly-handle-family-setting-for-e.patch new file mode 100644 index 0000000000..6d7b5d2382 --- /dev/null +++ b/queue-7.0/drm-amd-display-properly-handle-family-setting-for-e.patch @@ -0,0 +1,61 @@ +From 46dc06332277633f7f043b0c0f545a2e00429b6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 12:29:03 -0400 +Subject: drm/amd/display: properly handle family setting for early GC 11.5.4 + +From: Alex Deucher + +[ Upstream commit 31bc64e87f5f3d9ccbb7e625d570cfd8f52c77fc ] + +Early variants need an override. + +Fixes: 57d00816c6a9 ("drm/amdgpu: set family for GC 11.5.4") +Cc: Pratik Vishwakarma +Cc: Roman Li +Cc: Mario Limonciello +Reviewed-by: Mario Limonciello (AMD) +Tested-by: Mario Limonciello (AMD) +Signed-off-by: Alex Deucher +(cherry picked from commit 922fccc2d3f8186008c19ba08a49ae8a9463cb50) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 4 +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 +++++- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +index af3d2fd61cf3f..3459d356151ef 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +@@ -2986,10 +2986,8 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) + case IP_VERSION(11, 5, 1): + case IP_VERSION(11, 5, 2): + case IP_VERSION(11, 5, 3): +- adev->family = AMDGPU_FAMILY_GC_11_5_0; +- break; + case IP_VERSION(11, 5, 4): +- adev->family = AMDGPU_FAMILY_GC_11_5_4; ++ adev->family = AMDGPU_FAMILY_GC_11_5_0; + break; + case IP_VERSION(12, 0, 0): + case IP_VERSION(12, 0, 1): +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 2328c1aa0ead1..0aee65503642d 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -1891,7 +1891,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) + goto error; + } + +- init_data.asic_id.chip_family = adev->family; ++ /* special handling for early revisions of GC 11.5.4 */ ++ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 4)) ++ init_data.asic_id.chip_family = AMDGPU_FAMILY_GC_11_5_4; ++ else ++ init_data.asic_id.chip_family = adev->family; + + init_data.asic_id.pci_revision_id = adev->pdev->revision; + init_data.asic_id.hw_internal_rev = adev->external_rev_id; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch b/queue-7.0/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch new file mode 100644 index 0000000000..2c5da63126 --- /dev/null +++ b/queue-7.0/drm-amd-display-read-edid-from-vbios-embedded-panel-.patch @@ -0,0 +1,137 @@ +From 3927587432134fff2c55010a69b20dd67d4d0ad5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:44 +0200 +Subject: drm/amd/display: Read EDID from VBIOS embedded panel info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ] + +Some board manufacturers hardcode the EDID for the embedded +panel in the VBIOS. This EDID should be used when the panel +doesn't have a DDC. + +For reference, see the legacy non-DC display code: +amdgpu_atombios_encoder_get_lcd_info() + +This is necessary to support embedded connectors without DDC. + +Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364) +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ + .../display/include/grph_object_ctrl_defs.h | 4 ++ + 2 files changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +index 73e3c45eeeba6..bbd8d52330b55 100644 +--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +@@ -1295,6 +1295,60 @@ static enum bp_result bios_parser_get_embedded_panel_info( + return BP_RESULT_FAILURE; + } + ++static enum bp_result get_embedded_panel_extra_info( ++ struct bios_parser *bp, ++ struct embedded_panel_info *info, ++ const uint32_t table_offset) ++{ ++ uint8_t *record = bios_get_image(&bp->base, table_offset, 1); ++ ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; ++ ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ++ ++ while (*record != ATOM_RECORD_END_TYPE) { ++ switch (*record) { ++ case LCD_MODE_PATCH_RECORD_MODE_TYPE: ++ record += sizeof(ATOM_PATCH_RECORD_MODE); ++ break; ++ case LCD_RTS_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_RTS_RECORD); ++ break; ++ case LCD_CAP_RECORD_TYPE: ++ record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); ++ break; ++ case LCD_FAKE_EDID_PATCH_RECORD_TYPE: ++ fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; ++ if (fake_edid_record->ucFakeEDIDLength) { ++ if (fake_edid_record->ucFakeEDIDLength == 128) ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength; ++ else ++ info->fake_edid_size = ++ fake_edid_record->ucFakeEDIDLength * 128; ++ ++ info->fake_edid = fake_edid_record->ucFakeEDIDString; ++ ++ record += struct_size(fake_edid_record, ++ ucFakeEDIDString, ++ info->fake_edid_size); ++ } else { ++ /* empty fake edid record must be 3 bytes long */ ++ record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1; ++ } ++ break; ++ case LCD_PANEL_RESOLUTION_RECORD_TYPE: ++ panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; ++ info->panel_width_mm = panel_res_record->usHSize; ++ info->panel_height_mm = panel_res_record->usVSize; ++ record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); ++ break; ++ default: ++ return BP_RESULT_BADBIOSTABLE; ++ } ++ } ++ ++ return BP_RESULT_OK; ++} ++ + static enum bp_result get_embedded_panel_info_v1_2( + struct bios_parser *bp, + struct embedded_panel_info *info) +@@ -1411,6 +1465,10 @@ static enum bp_result get_embedded_panel_info_v1_2( + if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) + info->lcd_timing.misc_info.API_ENABLED = true; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +@@ -1536,6 +1594,10 @@ static enum bp_result get_embedded_panel_info_v1_3( + (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL & + lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT; + ++ if (lvds->usExtInfoTableOffset) ++ return get_embedded_panel_extra_info(bp, info, ++ le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info)); ++ + return BP_RESULT_OK; + } + +diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +index 38a77fa9b4afd..a0f03fb67605e 100644 +--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h ++++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +@@ -153,6 +153,10 @@ struct embedded_panel_info { + uint32_t drr_enabled; + uint32_t min_drr_refresh_rate; + bool realtek_eDPToLVDS; ++ uint16_t panel_width_mm; ++ uint16_t panel_height_mm; ++ uint16_t fake_edid_size; ++ const uint8_t *fake_edid; + }; + + struct dc_firmware_info { +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-display-use-edid-from-vbios-embedded-panel-i.patch b/queue-7.0/drm-amd-display-use-edid-from-vbios-embedded-panel-i.patch new file mode 100644 index 0000000000..e4e9f1a1ca --- /dev/null +++ b/queue-7.0/drm-amd-display-use-edid-from-vbios-embedded-panel-i.patch @@ -0,0 +1,97 @@ +From 8c22a7bc265e435f06fe47a829102c617ea41b58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 13:40:45 +0200 +Subject: drm/amd/display: Use EDID from VBIOS embedded panel info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 019155e2bd3e2cec425553195e9f9bc76bb0f848 ] + +When an embedded panel has no DDC, read the EDID from +the VBIOS embedded panel info and use that. + +Fixes: 7c7f5b15be65 ("drm/amd/display: Refactor edid read.") +Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192 +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +(cherry picked from commit 399b9abc353c62f6e37d38325edbdb6c2c00411c) +Signed-off-by: Sasha Levin +--- + .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 44 +++++++++++++++++++ + 1 file changed, 44 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +index a09761f9882d1..5b0245eb5fdb2 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +@@ -993,6 +993,45 @@ dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector) + return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector); + } + ++static const struct drm_edid * ++dm_helpers_read_vbios_hardcoded_edid(struct dc_link *link, struct amdgpu_dm_connector *aconnector) ++{ ++ struct dc_bios *bios = link->ctx->dc_bios; ++ struct embedded_panel_info info; ++ const struct drm_edid *edid; ++ enum bp_result r; ++ ++ if (!dc_is_embedded_signal(link->connector_signal) || ++ !bios->funcs->get_embedded_panel_info) ++ return NULL; ++ ++ memset(&info, 0, sizeof(info)); ++ r = bios->funcs->get_embedded_panel_info(bios, &info); ++ ++ if (r != BP_RESULT_OK) { ++ dm_error("Error when reading embedded panel info: %u\n", r); ++ return NULL; ++ } ++ ++ if (!info.fake_edid || !info.fake_edid_size) { ++ dm_error("Embedded panel info doesn't contain an EDID\n"); ++ return NULL; ++ } ++ ++ edid = drm_edid_alloc(info.fake_edid, info.fake_edid_size); ++ ++ if (!drm_edid_valid(edid)) { ++ dm_error("EDID from embedded panel info is invalid\n"); ++ drm_edid_free(edid); ++ return NULL; ++ } ++ ++ aconnector->base.display_info.width_mm = info.panel_width_mm; ++ aconnector->base.display_info.height_mm = info.panel_height_mm; ++ ++ return edid; ++} ++ + void populate_hdmi_info_from_connector(struct drm_hdmi_info *hdmi, struct dc_edid_caps *edid_caps) + { + edid_caps->scdc_present = hdmi->scdc.supported; +@@ -1013,6 +1052,9 @@ enum dc_edid_status dm_helpers_read_local_edid( + + if (link->aux_mode) + ddc = &aconnector->dm_dp_aux.aux.ddc; ++ else if (link->ddc_hw_inst == GPIO_DDC_LINE_UNKNOWN && ++ dc_is_embedded_signal(link->connector_signal)) ++ ddc = NULL; + else + ddc = &aconnector->i2c->base; + +@@ -1023,6 +1065,8 @@ enum dc_edid_status dm_helpers_read_local_edid( + drm_edid = dm_helpers_read_acpi_edid(aconnector); + if (drm_edid) + drm_info(connector->dev, "Using ACPI provided EDID for %s\n", connector->name); ++ else if (!ddc) ++ drm_edid = dm_helpers_read_vbios_hardcoded_edid(link, aconnector); + else + drm_edid = drm_edid_read_ddc(connector, ddc); + drm_edid_connector_update(connector, drm_edid); +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-add-fine-grained-flag-to-smu-v13.0.6.patch b/queue-7.0/drm-amd-pm-add-fine-grained-flag-to-smu-v13.0.6.patch new file mode 100644 index 0000000000..876e92d909 --- /dev/null +++ b/queue-7.0/drm-amd-pm-add-fine-grained-flag-to-smu-v13.0.6.patch @@ -0,0 +1,37 @@ +From 63300983750ceecfd1a04911e260d1a1c889523e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 12:53:30 +0530 +Subject: drm/amd/pm: Add fine grained flag to SMU v13.0.6 + +From: Lijo Lazar + +[ Upstream commit 47a5dfc8add4e60ff1ddc312f79998e70cbb0c09 ] + +Gfx clock is fine grained on SMU v13.0.6/12 SOCs. Add the flag to report +clock frequencies correctly. + +Fixes: 7380228401c4 ("drm/amd/pm: Use generic dpm table for SMUv13 SOCs") +Signed-off-by: Lijo Lazar +Reviewed-by: Asad Kamal +Signed-off-by: Alex Deucher +(cherry picked from commit d4871d837bbf70173f63426a84fa80b39e408b9e) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +index 870bcc86fd794..c62b12d672d48 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +@@ -1122,6 +1122,7 @@ static int smu_v13_0_6_set_default_dpm_table(struct smu_context *smu) + /* gfxclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + dpm_table->clk_type = SMU_GFXCLK; ++ dpm_table->flags = SMU_DPM_TABLE_FINE_GRAINED; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { + /* In the case of gfxclk, only fine-grained dpm is honored. + * Get min/max values from FW. +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch b/queue-7.0/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch new file mode 100644 index 0000000000..fe8bced923 --- /dev/null +++ b/queue-7.0/drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch @@ -0,0 +1,38 @@ +From 512d34681880cacfe526d497ccf036a18147b2ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:03 +0200 +Subject: drm/amd/pm/ci: Clear EnabledForActivity field for memory levels +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 5facfd4c4c67e8500116ffec0d9da35d92b9c787 ] + +Follow what radeon did and what amdgpu does for other GPUs with SMU7. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index b5f6a5da6549d..9898c846c78e2 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1217,7 +1217,7 @@ static int ci_populate_single_memory_level( + } + + memory_level->EnabledForThrottle = 1; +- memory_level->EnabledForActivity = 1; ++ memory_level->EnabledForActivity = 0; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; + memory_level->VoltageDownH = 0; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch b/queue-7.0/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch new file mode 100644 index 0000000000..2316fc62b5 --- /dev/null +++ b/queue-7.0/drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch @@ -0,0 +1,67 @@ +From 263f8cb2e86825861c2b7c1849fab1acffaf52dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:59 +0200 +Subject: drm/amd/pm/ci: Disable MCLK DPM on problematic CI ASICs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 9851f29cb06c09f7dad3867d8b0feec3fc71b6c8 ] + +There are two known cases where MCLK DPM can causes issues: + +Radeon R9 M380 found in iMac computers from 2015. +The SMU in this GPU just hangs as soon as we send it the +PPSMC_MSG_MCLKDPM_Enable command, even when MCLK switching is +disabled, and even when we only populate one MCLK DPM level. +Apply workaround to all devices with the same subsystem ID. + +Radeon R7 260X due to old memory controller microcode. +We only flash the MC ucode when it isn't set up by the VBIOS, +therefore there is no way to make sure that it has the correct +ucode version. + +I verified that this patch fixes the SMU hang on the R9 M380 +which would previously fail to boot. This also fixes the UVD +initialization error on that GPU which happened because the +SMU couldn't ungate the UVD after it hung. + +Fixes: 86457c3b21cb ("drm/amd/powerplay: Add support for CI asics to hwmgr") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +index 2b5ac21fee399..1d6e30269d567 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -104,6 +104,21 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) + PP_GFXOFF_MASK); + hwmgr->pp_table_version = PP_TABLE_V0; + hwmgr->od_enabled = false; ++ switch (hwmgr->chip_id) { ++ case CHIP_BONAIRE: ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM ++ * R7 260X cards with old MC ucode: MCLK DPM is unstable ++ */ ++ if (adev->pdev->subsystem_vendor == 0x106B || ++ adev->pdev->device == 0x6658) { ++ dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); ++ adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; ++ hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; ++ } ++ break; ++ default: ++ break; ++ } + smu7_init_function_pointers(hwmgr); + break; + case AMDGPU_FAMILY_CZ: +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch b/queue-7.0/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch new file mode 100644 index 0000000000..f7f4eb3d5d --- /dev/null +++ b/queue-7.0/drm-amd-pm-ci-fill-dw8-fields-from-smc.patch @@ -0,0 +1,48 @@ +From c3bace4c8ba1b2b6fd2f112fe848d3dec53d645d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:04 +0200 +Subject: drm/amd/pm/ci: Fill DW8 fields from SMC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit baf28ec5795c077406d6f52b8ad39e614153bce6 ] + +In ci_populate_dw8() we currently just read a value from the SMU +and then throw it away. Instead of throwing away the value, +we should use it to fill other fields in DW8 (like radeon). + +Otherwise the value of the other fiels is just cleared when +we copy this data to the SMU later. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 9898c846c78e2..3650e7beeb671 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -543,12 +543,11 @@ static int ci_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset) + { + struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); + const struct ci_pt_defaults *defaults = smu_data->power_tune_defaults; +- uint32_t temp; + + if (ci_read_smc_sram_dword(hwmgr, + fuse_table_offset + + offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl), +- (uint32_t *)&temp, SMC_RAM_END)) ++ (uint32_t *)&smu_data->power_tune_table.TdcWaterfallCtl, SMC_RAM_END)) + PP_ASSERT_WITH_CODE(false, + "Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!", + return -EINVAL); +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch b/queue-7.0/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch new file mode 100644 index 0000000000..57c10aadf2 --- /dev/null +++ b/queue-7.0/drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch @@ -0,0 +1,41 @@ +From 45131675b381103dfb1927a6c1577a75152b9ff8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:02 +0200 +Subject: drm/amd/pm/ci: Fix powertune defaults for Hawaii 0x67B0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit d784759c07924280f3c313f205fc48eb62d7cb71 ] + +There is no AMD GPU with the ID 0x66B0, this looks like a typo. +It should be 0x67B0 which is actually part of the PCI ID list, +and should use the Hawaii XT powertune defaults according to +the old radeon driver. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index c0a04fab3ceca..b5f6a5da6549d 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -245,7 +245,7 @@ static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) + smu_data->power_tune_defaults = &defaults_hawaii_pro; + break; + case 0x67B8: +- case 0x66B0: ++ case 0x67B0: + smu_data->power_tune_defaults = &defaults_hawaii_xt; + break; + case 0x6640: +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch b/queue-7.0/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch new file mode 100644 index 0000000000..1e1df3f755 --- /dev/null +++ b/queue-7.0/drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch @@ -0,0 +1,47 @@ +From 7b52cc67d186d6a9e0c5d2171f5c6f1569965c72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:02:58 +0200 +Subject: drm/amd/pm/ci: Use highest MCLK on CI when MCLK DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 894f0d34d66cb47fe718fe2ae5c18729d22c5218 ] + +When MCLK DPM is disabled for any reason, populate the MCLK +table with the highest MCLK DPM level, so that the ASIC can +use the highest possible memory clock to get good performance +even when MCLK DPM is disabled. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +index 7d5df18db8d26..c0a04fab3ceca 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +@@ -1322,6 +1322,14 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) + return result; + } + ++ if (data->mclk_dpm_key_disabled && dpm_table->mclk_table.count) { ++ /* Populate the table with the highest MCLK level when MCLK DPM is disabled */ ++ for (i = 0; i < dpm_table->mclk_table.count - 1; i++) { ++ levels[i] = levels[dpm_table->mclk_table.count - 1]; ++ levels[i].DisplayWatermark = PPSMC_DISPLAY_WATERMARK_HIGH; ++ } ++ } ++ + smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; + + dev_id = adev->pdev->device; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-fix-missing-fine-grained-dpm-table-flag-o.patch b/queue-7.0/drm-amd-pm-fix-missing-fine-grained-dpm-table-flag-o.patch new file mode 100644 index 0000000000..733e4de4a8 --- /dev/null +++ b/queue-7.0/drm-amd-pm-fix-missing-fine-grained-dpm-table-flag-o.patch @@ -0,0 +1,37 @@ +From 422f458aad2b53c429fe6e3f5fe0fbb48a99dc8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 18:41:42 +0800 +Subject: drm/amd/pm: fix missing fine-grained dpm table flag on aldebaran + +From: Yang Wang + +[ Upstream commit ccf8932ed8cf4fbfdcd4df2c6b524913691ee700 ] + +Add the missing SMU_DPM_TABLE_FINE_GRAINED flag to aldebaran DPM table. +This fixes the pp_dpm_sclk node issue caused by missing flag configuration. + +Fixes: 7ea1c722fe1d ("drm/amd/pm: Use common helper for aldebaran dpm table") +Signed-off-by: Yang Wang +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +(cherry picked from commit 3427dea3a48ebddb491a26093f3627384b3cb2c2) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +index 2b4faab376930..23c9f14bb2086 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +@@ -425,6 +425,7 @@ static int aldebaran_set_default_dpm_table(struct smu_context *smu) + dpm_table->dpm_levels[0].enabled = true; + dpm_table->dpm_levels[1].value = pptable->GfxclkFmax; + dpm_table->dpm_levels[1].enabled = true; ++ dpm_table->flags |= SMU_DPM_TABLE_FINE_GRAINED; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-fix-xgmi-max-speed-reporting.patch b/queue-7.0/drm-amd-pm-fix-xgmi-max-speed-reporting.patch new file mode 100644 index 0000000000..0d84946bba --- /dev/null +++ b/queue-7.0/drm-amd-pm-fix-xgmi-max-speed-reporting.patch @@ -0,0 +1,41 @@ +From 96ec6f635d1066800461a8bcc9944ec7cb6e1291 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 15:17:00 +0530 +Subject: drm/amd/pm: Fix xgmi max speed reporting + +From: Lijo Lazar + +[ Upstream commit da16822ce5c32b5aca848eaea521936d4410d48c ] + +Fix XGMI max bitrate/width reporting on SMUv13.0.12 SOCs. The data +format got changed when moved to static table from dynamic metrics +table. + +Fixes: 1bec2f270766 ("drm/amd/pm: Fetch SMUv13.0.12 xgmi max speed/width") +Signed-off-by: Lijo Lazar +Reviewed-by: Asad Kamal +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +index 32d5e2170d80a..aa9deb7cd9da6 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +@@ -262,8 +262,9 @@ static void smu_v13_0_12_init_xgmi_data(struct smu_context *smu, + int ret; + + if (smu_table->tables[SMU_TABLE_SMU_METRICS].version >= 0x13) { +- max_width = (uint8_t)static_metrics->MaxXgmiWidth; +- max_speed = (uint16_t)static_metrics->MaxXgmiBitrate; ++ max_width = (uint8_t)SMUQ10_ROUND(static_metrics->MaxXgmiWidth); ++ max_speed = ++ (uint16_t)SMUQ10_ROUND(static_metrics->MaxXgmiBitrate); + ret = 0; + } else { + MetricsTable_t *metrics = (MetricsTable_t *)smu_table->metrics_table; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch b/queue-7.0/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch new file mode 100644 index 0000000000..0e5edfd6a7 --- /dev/null +++ b/queue-7.0/drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch @@ -0,0 +1,129 @@ +From 0891f1295dc05b5a7aaa80c24cabcf81d6d3868d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:05 +0200 +Subject: drm/amd/pm/smu7: Add SCLK cap for quirky Hawaii board +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 4724bc5b8d78c34b993594f9406135408ccb312a ] + +On a specific Radeon R9 390X board, the GPU can "randomly" hang +while gaming. Initially I thought this was a RADV bug and tried +to work around this in Mesa: +commit 8ea08747b86b ("radv: Mitigate GPU hang on Hawaii in Dota 2 and RotTR") + +However, I got some feedback from other users who are reporting +that the above mitigation causes a significant performance +regression for them, and they didn't experience the hang on their +GPU in the first place. + +After some further investigation, it turns out that the problem +is that the highest SCLK DPM level on this board isn't stable. +Lowering SCLK to 1040 MHz (from 1070 MHz) works around the issue, +and has a negligible impact on performance compared to the Mesa +patch. (Note that increasing the voltage can also work around it, +but we felt that lowering the SCLK is the safer option.) + +To solve the above issue, add an "sclk_cap" field to smu7_hwmgr +and set this field for the affected board. The capped SCLK value +correctly appears on the sysfs interface and shows up in GUI +tools such as LACT. + +Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 30 ++++++++++++++++--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h | 1 + + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index 563482f5d35fd..bc6acdb52c269 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + hwmgr->dyn_state.vddc_dependency_on_mclk; + struct phm_cac_leakage_table *std_voltage_table = + hwmgr->dyn_state.cac_leakage_table; +- uint32_t i; ++ uint32_t i, clk; + + PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, + "SCLK dependency table is missing. This table is mandatory", return -EINVAL); +@@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) + data->dpm_table.sclk_table.count = 0; + + for (i = 0; i < allowed_vdd_sclk_table->count; i++) { ++ clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap); ++ + if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != +- allowed_vdd_sclk_table->entries[i].clk) { ++ clk) { + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = +- allowed_vdd_sclk_table->entries[i].clk; ++ clk; + data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; + data->dpm_table.sclk_table.count++; + } +@@ -3006,6 +3008,25 @@ static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr * + return 0; + } + ++static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr) ++{ ++ struct amdgpu_device *adev = hwmgr->adev; ++ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); ++ ++ data->sclk_cap = 0xffffffff; ++ ++ if (hwmgr->od_enabled) ++ return; ++ ++ /* R9 390X board: last sclk dpm level is unstable, use lower sclk */ ++ if (adev->pdev->device == 0x67B0 && ++ adev->pdev->subsystem_vendor == 0x1043) ++ data->sclk_cap = 104000; /* 1040 MHz */ ++ ++ if (data->sclk_cap != 0xffffffff) ++ dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10); ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -3017,6 +3038,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + return -ENOMEM; + + hwmgr->backend = data; ++ smu7_set_sclk_cap(hwmgr); + smu7_patch_voltage_workaround(hwmgr); + smu7_init_dpm_defaults(hwmgr); + +@@ -3903,7 +3925,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr, + + /* Performance levels are arranged from low to high. */ + performance_level->memory_clock = memory_clock; +- performance_level->engine_clock = engine_clock; ++ performance_level->engine_clock = min(engine_clock, data->sclk_cap); + + pcie_gen_from_bios = visland_clk_info->ucPCIEGen; + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +index d9e8b386bd4d3..66adabeab6a3a 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h +@@ -234,6 +234,7 @@ struct smu7_hwmgr { + uint32_t pcie_gen_cap; + uint32_t pcie_lane_cap; + uint32_t pcie_spc_cap; ++ uint32_t sclk_cap; + struct smu7_leakage_voltage vddc_leakage; + struct smu7_leakage_voltage vddci_leakage; + struct smu7_leakage_voltage vddcgfx_leakage; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch b/queue-7.0/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch new file mode 100644 index 0000000000..733b90cc1f --- /dev/null +++ b/queue-7.0/drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch @@ -0,0 +1,192 @@ +From 27dbb911a52cfe059771d286f6e83b5190982a05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:00 +0200 +Subject: drm/amd/pm/smu7: Fix SMU7 voltage dependency on display clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 0138610c14130425be53423b35336561829965e0 ] + +The DCE (display controller engine) requires a minimum voltage +in order to function correctly, depending on which clock level +it currently uses. + +Add a new table that contains display clock frequency levels +and the corresponding required voltages. The clock frequency +levels are taken from DC (and the old radeon driver's voltage +dependency table for CI in cases where its values were lower). +The voltage levels are taken from the following function: +phm_initializa_dynamic_state_adjustment_rule_settings(). +Furthermore, in case of CI, call smu7_patch_vddc() on the new +table to account for leakage voltage (like in radeon). + +Use the display clock value from amd_pp_display_configuration +to look up the voltage level needed by the DCE. Send the +voltage to the SMU via the PPSMC_MSG_VddC_Request command. + +The previous implementation of this feature was non-functional +because it relied on a "dal_power_level" field which was never +assigned; and it was not at all implemented for CI ASICs. + +I verified this on a Radeon R9 M380 which previously booted to +a black screen with DC enabled (default since Linux 6.19), but +now works correctly. + +Fixes: 599a7e9fe1b6 ("drm/amd/powerplay: implement smu7 hwmgr to manager asics with smu ip version 7.") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 88 ++++++++++++++++++- + drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h | 1 + + 2 files changed, 86 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +index e38222877f7ef..563482f5d35fd 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +@@ -2802,6 +2802,10 @@ static int smu7_patch_dependency_tables_with_leakage(struct pp_hwmgr *hwmgr) + if (tmp) + return -EINVAL; + ++ tmp = smu7_patch_vddc(hwmgr, hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ if (tmp) ++ return -EINVAL; ++ + tmp = smu7_patch_vce_vddc(hwmgr, hwmgr->dyn_state.vce_clock_voltage_dependency_table); + if (tmp) + return -EINVAL; +@@ -2885,6 +2889,8 @@ static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) + { + kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); + hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; ++ kfree(hwmgr->dyn_state.vddc_dependency_on_display_clock); ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = NULL; + kfree(hwmgr->backend); + hwmgr->backend = NULL; + +@@ -2955,6 +2961,51 @@ static int smu7_update_edc_leakage_table(struct pp_hwmgr *hwmgr) + return ret; + } + ++static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *hwmgr) ++{ ++ struct phm_clock_voltage_dependency_table *table; ++ ++ if (!amdgpu_device_ip_get_ip_block(hwmgr->adev, AMD_IP_BLOCK_TYPE_DCE)) ++ return 0; ++ ++ table = kzalloc(struct_size(table, entries, 4), GFP_KERNEL); ++ if (!table) ++ return -ENOMEM; ++ ++ if (hwmgr->chip_id >= CHIP_POLARIS10) { ++ table->entries[0].clk = 38918; ++ table->entries[1].clk = 45900; ++ table->entries[2].clk = 66700; ++ table->entries[3].clk = 113200; ++ ++ table->entries[0].v = 700; ++ table->entries[1].v = 740; ++ table->entries[2].v = 800; ++ table->entries[3].v = 900; ++ } else { ++ if (hwmgr->chip_family == AMDGPU_FAMILY_CZ) { ++ table->entries[0].clk = 35200; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 46700; ++ table->entries[3].clk = 64300; ++ } else { ++ table->entries[0].clk = 0; ++ table->entries[1].clk = 35200; ++ table->entries[2].clk = 54000; ++ table->entries[3].clk = 62500; ++ } ++ ++ table->entries[0].v = 0; ++ table->entries[1].v = 720; ++ table->entries[2].v = 810; ++ table->entries[3].v = 900; ++ } ++ ++ table->count = 4; ++ hwmgr->dyn_state.vddc_dependency_on_display_clock = table; ++ return 0; ++} ++ + static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + { + struct amdgpu_device *adev = hwmgr->adev; +@@ -2983,6 +3034,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) + smu7_get_elb_voltages(hwmgr); + } + ++ result = smu7_init_voltage_dependency_on_display_clock_table(hwmgr); ++ if (result) ++ goto fail; ++ + if (hwmgr->pp_table_version == PP_TABLE_V1) { + smu7_complete_dependency_tables(hwmgr); + smu7_set_private_data_based_on_pptable_v1(hwmgr); +@@ -3079,13 +3134,40 @@ static int smu7_force_dpm_highest(struct pp_hwmgr *hwmgr) + return 0; + } + ++static uint32_t smu7_lookup_vddc_from_dispclk(struct pp_hwmgr *hwmgr) ++{ ++ const struct amd_pp_display_configuration *cfg = hwmgr->display_config; ++ const struct phm_clock_voltage_dependency_table *vddc_dep_on_dispclk = ++ hwmgr->dyn_state.vddc_dependency_on_display_clock; ++ uint32_t i; ++ ++ if (!vddc_dep_on_dispclk || !vddc_dep_on_dispclk->count || ++ !cfg || !cfg->num_display || !cfg->display_clk) ++ return 0; ++ ++ /* Start from 1 because ClocksStateUltraLow should not be used according to DC. */ ++ for (i = 1; i < vddc_dep_on_dispclk->count; ++i) ++ if (vddc_dep_on_dispclk->entries[i].clk >= cfg->display_clk) ++ return vddc_dep_on_dispclk->entries[i].v; ++ ++ return vddc_dep_on_dispclk->entries[vddc_dep_on_dispclk->count - 1].v; ++} ++ ++static void smu7_apply_minimum_dce_voltage_request(struct pp_hwmgr *hwmgr) ++{ ++ uint32_t req_vddc = smu7_lookup_vddc_from_dispclk(hwmgr); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_VddC_Request, ++ req_vddc * VOLTAGE_SCALE, ++ NULL); ++} ++ + static int smu7_upload_dpm_level_enable_mask(struct pp_hwmgr *hwmgr) + { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + +- if (hwmgr->pp_table_version == PP_TABLE_V1) +- phm_apply_dal_min_voltage_request(hwmgr); +-/* TO DO for v0 iceland and Ci*/ ++ smu7_apply_minimum_dce_voltage_request(hwmgr); + + if (!data->sclk_dpm_key_disabled) { + if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) +diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +index c661185753b42..2f49c95342a14 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h ++++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +@@ -631,6 +631,7 @@ struct phm_dynamic_state_info { + struct phm_clock_voltage_dependency_table *vddci_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *vddc_dependency_on_mclk; + struct phm_clock_voltage_dependency_table *mvdd_dependency_on_mclk; ++ struct phm_clock_voltage_dependency_table *vddc_dependency_on_display_clock; + struct phm_clock_voltage_dependency_table *vddc_dep_on_dal_pwrl; + struct phm_clock_array *valid_sclk_values; + struct phm_clock_array *valid_mclk_values; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-ras-fix-null-deref-in-ras_core_get_utc_secon.patch b/queue-7.0/drm-amd-ras-fix-null-deref-in-ras_core_get_utc_secon.patch new file mode 100644 index 0000000000..ce115fab76 --- /dev/null +++ b/queue-7.0/drm-amd-ras-fix-null-deref-in-ras_core_get_utc_secon.patch @@ -0,0 +1,63 @@ +From ba855a6daeef872f7112709a06a03fd60004acf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 11:29:41 +0530 +Subject: drm/amd/ras: Fix NULL deref in ras_core_get_utc_second_timestamp() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit 2b8101cc3b34d4d80d799360d2744829d5964479 ] + +ras_core_get_utc_second_timestamp() retrieves the current UTC timestamp +(in seconds since the Unix epoch) through a platform-specific RAS system +callback and is used for timestamping RAS error events. + +The function checks ras_core in the conditional statement before calling +the sys_fn callback. However, when the condition fails, the function +prints an error message using ras_core->dev. + +If ras_core is NULL, this can lead to a potential NULL pointer +dereference when accessing ras_core->dev. + +Add an early NULL check for ras_core at the beginning of the function +and return 0 when the pointer is not valid. This prevents the +dereference and makes the control flow clearer. + +Fixes: 13c91b5b4378 ("drm/amd/ras: Add rascore unified interface function") +Cc: YiPeng Chai +Cc: Dan Carpenter +Cc: Tao Zhou +Cc: Hawking Zhang +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: YiPeng Chai +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/ras/rascore/ras_core.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_core.c b/drivers/gpu/drm/amd/ras/rascore/ras_core.c +index b81741a339b1b..1ad555eff5927 100644 +--- a/drivers/gpu/drm/amd/ras/rascore/ras_core.c ++++ b/drivers/gpu/drm/amd/ras/rascore/ras_core.c +@@ -507,8 +507,11 @@ bool ras_core_is_enabled(struct ras_core_context *ras_core) + + uint64_t ras_core_get_utc_second_timestamp(struct ras_core_context *ras_core) + { +- if (ras_core && ras_core->sys_fn && +- ras_core->sys_fn->get_utc_second_timestamp) ++ if (!ras_core) ++ return 0; ++ ++ if (ras_core->sys_fn && ++ ras_core->sys_fn->get_utc_second_timestamp) + return ras_core->sys_fn->get_utc_second_timestamp(ras_core); + + RAS_DEV_ERR(ras_core->dev, "Failed to get system timestamp!\n"); +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-ras-fix-null-deref-in-ras_core_ras_interrupt.patch b/queue-7.0/drm-amd-ras-fix-null-deref-in-ras_core_ras_interrupt.patch new file mode 100644 index 0000000000..b5567fee6d --- /dev/null +++ b/queue-7.0/drm-amd-ras-fix-null-deref-in-ras_core_ras_interrupt.patch @@ -0,0 +1,48 @@ +From 83c6bfc179bf5711d4ce59d3b70fd3f79634eef4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Oct 2025 18:16:51 +0530 +Subject: drm/amd/ras: Fix NULL deref in ras_core_ras_interrupt_detected() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit 6b606216e03fa2b53cc179d8383b683a140fe6e1 ] + +Fixes a NULL pointer dereference when ras_core is NULL and ras_core->dev +is accessed in the error path. + +Fixes: 13c91b5b4378 ("drm/amd/ras: Add rascore unified interface function") +Reported by: Dan Carpenter +Cc: YiPeng Chai +Cc: Tao Zhou +Cc: Hawking Zhang +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tao Zhou +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/ras/rascore/ras_core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_core.c b/drivers/gpu/drm/amd/ras/rascore/ras_core.c +index 9df05b3963edb..b81741a339b1b 100644 +--- a/drivers/gpu/drm/amd/ras/rascore/ras_core.c ++++ b/drivers/gpu/drm/amd/ras/rascore/ras_core.c +@@ -530,7 +530,9 @@ bool ras_core_ras_interrupt_detected(struct ras_core_context *ras_core) + ras_core->sys_fn->detect_ras_interrupt) + return ras_core->sys_fn->detect_ras_interrupt(ras_core); + +- RAS_DEV_ERR(ras_core->dev, "Failed to detect ras interrupt!\n"); ++ if (ras_core && ras_core->dev) ++ RAS_DEV_ERR(ras_core->dev, "Failed to detect ras interrupt!\n"); ++ + return false; + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-ras-fix-type-size-of-remainder-argument.patch b/queue-7.0/drm-amd-ras-fix-type-size-of-remainder-argument.patch new file mode 100644 index 0000000000..5576d28b77 --- /dev/null +++ b/queue-7.0/drm-amd-ras-fix-type-size-of-remainder-argument.patch @@ -0,0 +1,69 @@ +From 882bb9e99f230d36aa62dce62e9491e5ce9d04e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 09:47:03 -0800 +Subject: drm/amd/ras: Fix type size of remainder argument + +From: Kees Cook + +[ Upstream commit 9f3d543a9f7371622aff389e69010ac6bac69ef8 ] + +Forcing an int to be dereferenced at uint64_t for div64_u64_rem() runs +the risk of endian confusion and stack overflowing writes. Seen while +preparing to enable -Warray-bounds globally: + +In file included from ../arch/x86/include/asm/processor.h:35, + from ../include/linux/sched.h:13, + from ../include/linux/ratelimit.h:6, + from ../include/linux/dev_printk.h:16, + from ../drivers/gpu/drm/amd/amdgpu/../ras/ras_mgr/ras_sys.h:29, + from ../drivers/gpu/drm/amd/amdgpu/../ras/rascore/ras.h:27, + from ../drivers/gpu/drm/amd/amdgpu/../ras/rascore/ras_core.c:24: +In function 'div64_u64_rem', + inlined from 'ras_core_convert_timestamp_to_time' at ../drivers/gpu/drm/amd/amdgpu/../ras/rascore/ras_core.c:72:9: +../include/linux/math64.h:56:20: error: array subscript 'u64 {aka long long unsigned int}[0]' is partly outside array bounds of 'int[1]' [-Werror=array-bounds=] + 56 | *remainder = dividend % divisor; + | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ +../drivers/gpu/drm/amd/amdgpu/../ras/rascore/ras_core.c: In function 'ras_core_convert_timestamp_to_time': +../drivers/gpu/drm/amd/amdgpu/../ras/rascore/ras_core.c:70:19: note: object 'remaining_seconds' of size 4 + 70 | int days, remaining_seconds; + | ^~~~~~~~~~~~~~~~~ + +Use a 64-bit type for the remainder calculation, but leave +remaining_seconds as 32-bit to avoid 64-bit division later. The value of +remainder will always be less than seconds_per_day, so there's no +truncation risk. + +Fixes: ace232eff50e ("drm/amdgpu: Add ras module files into amdgpu") +Signed-off-by: Kees Cook +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/ras/rascore/ras_core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_core.c b/drivers/gpu/drm/amd/ras/rascore/ras_core.c +index 3f56f26abd6da..9df05b3963edb 100644 +--- a/drivers/gpu/drm/amd/ras/rascore/ras_core.c ++++ b/drivers/gpu/drm/amd/ras/rascore/ras_core.c +@@ -62,14 +62,16 @@ int ras_core_convert_timestamp_to_time(struct ras_core_context *ras_core, + uint64_t timestamp, struct ras_time *tm) + { + int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +- uint64_t month = 0, day = 0, hour = 0, minute = 0, second = 0; ++ uint64_t month = 0, day = 0, hour = 0, minute = 0, second = 0, remainder; + uint32_t year = 0; + int seconds_per_day = 24 * 60 * 60; + int seconds_per_hour = 60 * 60; + int seconds_per_minute = 60; + int days, remaining_seconds; + +- days = div64_u64_rem(timestamp, seconds_per_day, (uint64_t *)&remaining_seconds); ++ days = div64_u64_rem(timestamp, seconds_per_day, &remainder); ++ /* remainder will always be less than seconds_per_day. */ ++ remaining_seconds = remainder; + + /* utc_timestamp follows the Unix epoch */ + year = 1970; +-- +2.53.0 + diff --git a/queue-7.0/drm-amd-ras-remove-redundant-null-check-in-pending-b.patch b/queue-7.0/drm-amd-ras-remove-redundant-null-check-in-pending-b.patch new file mode 100644 index 0000000000..673ff82046 --- /dev/null +++ b/queue-7.0/drm-amd-ras-remove-redundant-null-check-in-pending-b.patch @@ -0,0 +1,61 @@ +From a17a6ca31605a755bd2ca29e93767885f0d541ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 11:53:31 +0530 +Subject: drm/amd/ras: Remove redundant NULL check in pending bad-bank list + iteration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit fd490bb9e1054705e1b35e6f321cdc713e0c7348 ] + +ras_umc_log_pending_bad_bank() walks through a list of pending ECC +bad-bank entries. These entries are saved when a bad-bank error cannot +be processed immediately, for example during a GPU reset. + +Later, this function iterates over the pending list and retries logging +each bad-bank error. If logging succeeds, the entry is removed from the +list and the memory for that node is freed. + +The loop uses list_for_each_entry_safe(), which already guarantees that +ecc_node points to a valid list entry while the loop body is executing. + +Checking "ecc_node &&" inside the loop is therefore unnecessary and +redundant. + +Fixes the below: +drivers/gpu/drm/amd/amdgpu/../ras/rascore/ras_umc.c:225 ras_umc_log_pending_bad_bank() warn: variable dereferenced before check 'ecc_node' (see line 223) + +Fixes: 7a3f9c0992c4 ("drm/amd/ras: Add umc common ras functions") +Cc: Dan Carpenter +Cc: YiPeng Chai +Cc: Tao Zhou +Cc: Hawking Zhang +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: YiPeng Chai +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/ras/rascore/ras_umc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_umc.c b/drivers/gpu/drm/amd/ras/rascore/ras_umc.c +index 2abe8553e479e..4fff0b3af75c1 100644 +--- a/drivers/gpu/drm/amd/ras/rascore/ras_umc.c ++++ b/drivers/gpu/drm/amd/ras/rascore/ras_umc.c +@@ -222,7 +222,7 @@ int ras_umc_log_pending_bad_bank(struct ras_core_context *ras_core) + mutex_lock(&ras_umc->pending_ecc_lock); + list_for_each_entry_safe(ecc_node, + tmp, &ras_umc->pending_ecc_list, node){ +- if (ecc_node && !ras_umc_log_bad_bank(ras_core, &ecc_node->ecc)) { ++ if (!ras_umc_log_bad_bank(ras_core, &ecc_node->ecc)) { + list_del(&ecc_node->node); + kfree(ecc_node); + } +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch b/queue-7.0/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch new file mode 100644 index 0000000000..2d6bea5711 --- /dev/null +++ b/queue-7.0/drm-amdgpu-add-default-case-in-dvi-mode-validation.patch @@ -0,0 +1,54 @@ +From d1f73607ac381377f5779c3b71a72ee978e87928 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 19:29:54 +0530 +Subject: drm/amdgpu: Add default case in DVI mode validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit e6020a55b8e364d15eac27f9c788e13114eec6b7 ] + +amdgpu_connector_dvi_mode_valid() assigns max_digital_pixel_clock_khz +based on connector_object_id using a switch statement that lacks a +default case. + +In practice this code path should never be hit because the existing +cases already cover all digital connector types that this function is +used for. This is also legacy display code which is not used for new +hardware. + +Add a default case returning MODE_BAD to make the switch exhaustive and +silence the static analyzer smatch error. The new branch is effectively +defensive and should never be reached during normal operation. + +Fixes: 585b2f685c56 ("drm/amdgpu: Respect max pixel clock for HDMI and DVI-D (v2)") +Cc: Dan Carpenter +Cc: Timur Kristóf +Cc: Alex Deucher +Cc: Christian König +Signed-off-by: Srinivasan Shanmugam +Acked-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +index d1bf2e150c1ad..780a0078c91a4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +@@ -1239,6 +1239,8 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector + case CONNECTOR_OBJECT_ID_HDMI_TYPE_B: + max_digital_pixel_clock_khz = max_dvi_single_link_pixel_clock * 2; + break; ++ default: ++ return MODE_BAD; + } + + /* When the display EDID claims that it's an HDMI display, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-avoid-double-drm_exec_fini-in-userq-valid.patch b/queue-7.0/drm-amdgpu-avoid-double-drm_exec_fini-in-userq-valid.patch new file mode 100644 index 0000000000..5632043241 --- /dev/null +++ b/queue-7.0/drm-amdgpu-avoid-double-drm_exec_fini-in-userq-valid.patch @@ -0,0 +1,62 @@ +From f39ea635fc6aa8ba73bd509de8a2dd3680f7904e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 20:38:17 +0800 +Subject: drm/amdgpu: avoid double drm_exec_fini() in userq validate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Hongyan Xu + +[ Upstream commit 508babf310365f1107a2e8831c267c292a286818 ] + +When new_addition is true, amdgpu_userq_vm_validate() calls +drm_exec_fini(&exec) before iterating over the collected HMM ranges and +calling amdgpu_ttm_tt_get_user_pages(). + +If amdgpu_ttm_tt_get_user_pages() fails in that path, the code jumps to +unlock_all and calls drm_exec_fini(&exec) a second time on the same +exec object. drm_exec_fini() is not idempotent: it frees exec->objects +and may also drop exec->contended and finalize the ww acquire context. + +Route that error path directly to the range cleanup once exec has +already been finalized. + +Fixes: 42f148788469 ("drm/amdgpu/userqueue: validate userptrs for userqueues") +Issue found using a prototype static analysis tool +and confirmed by code review. + +Reviewed-by: Christian König +Signed-off-by: Hongyan Xu +Signed-off-by: Slavin Liu <220245772@seu.edu.cn> +Signed-off-by: Alex Deucher +(cherry picked from commit 2802952e4a07306da6ebe813ff1acacc5691851a) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index caca0c4aeefe7..0e015741ab24e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -1231,7 +1231,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr) + bo = range->bo; + ret = amdgpu_ttm_tt_get_user_pages(bo, range); + if (ret) +- goto unlock_all; ++ goto free_ranges; + } + + invalidated = true; +@@ -1258,6 +1258,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr) + + unlock_all: + drm_exec_fini(&exec); ++free_ranges: + xa_for_each(&xa, tmp_key, range) { + if (!range) + continue; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-drop-redundant-queue-null-check-in-hang-d.patch b/queue-7.0/drm-amdgpu-drop-redundant-queue-null-check-in-hang-d.patch new file mode 100644 index 0000000000..5ab6d2b225 --- /dev/null +++ b/queue-7.0/drm-amdgpu-drop-redundant-queue-null-check-in-hang-d.patch @@ -0,0 +1,54 @@ +From c85b791ca6be51a709ee3c79cb32be449401b5e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Mar 2026 12:42:42 +0530 +Subject: drm/amdgpu: Drop redundant queue NULL check in hang detect worker +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit 9a62a097a7f8d223d722b9e9b557a792d30600ca ] + +amdgpu_userq_hang_detect_work() retrieves the queue pointer using +container_of() from the embedded work item. + +Since the work structure is part of struct amdgpu_usermode_queue, +the returned queue pointer cannot be NULL in normal execution. + +Remove the redundant !queue check and keep the validation for +queue->userq_mgr. + +Fixes the below: +drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c:159 amdgpu_userq_hang_detect_work() warn: can 'queue' even be NULL? + +Fixes: 290f46cf5726 ("drm/amdgpu: Implement user queue reset functionality") +Cc: Jesse Zhang +Cc: Dan Carpenter +Cc: Christian König +Cc: Alex Deucher +Signed-off-by: Srinivasan Shanmugam +Acked-by: Jesse Zhang +Reviewed-by: Lijo Lazar +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +index 0a1b93259887a..caca0c4aeefe7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +@@ -156,7 +156,7 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work) + struct dma_fence *fence; + struct amdgpu_userq_mgr *uq_mgr; + +- if (!queue || !queue->userq_mgr) ++ if (!queue->userq_mgr) + return; + + uq_mgr = queue->userq_mgr; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch b/queue-7.0/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch new file mode 100644 index 0000000000..4b9d0422c2 --- /dev/null +++ b/queue-7.0/drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch @@ -0,0 +1,133 @@ +From 2011e6005e16d617a8d265981066cd240b74e40c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 15:52:45 +0200 +Subject: drm/amdgpu: fix AMDGPU_INFO_READ_MMR_REG +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christian König + +[ Upstream commit 0ef196a208385b7d7da79f411c161b04e97283e2 ] + +There were multiple issues in that code. + +First of all the order between the reset semaphore and the mm_lock was +wrong (e.g. copy_to_user) was called while holding the lock. + +Then we allocated memory while holding the reset semaphore which is also +a pretty big bug and can deadlock. + +Then we used down_read_trylock() instead of waiting for the reset to +finish. + +Signed-off-by: Christian König +Fixes: 9e823f307074 ("drm/amdgpu: Block MMR_READ IOCTL in reset") +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +(cherry picked from commit 361b6e6b303d4b691f6c5974d3eaab67ca6dd90e) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 57 +++++++++++-------------- + 1 file changed, 24 insertions(+), 33 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +index 7f19554b9ad11..a50c3058f97f4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +@@ -873,68 +873,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + ? -EFAULT : 0; + } + case AMDGPU_INFO_READ_MMR_REG: { +- int ret = 0; +- unsigned int n, alloc_size; +- uint32_t *regs; + unsigned int se_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SE_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SE_INDEX_MASK; + unsigned int sh_num = (info->read_mmr_reg.instance >> + AMDGPU_INFO_MMR_SH_INDEX_SHIFT) & + AMDGPU_INFO_MMR_SH_INDEX_MASK; +- +- if (!down_read_trylock(&adev->reset_domain->sem)) +- return -ENOENT; ++ unsigned int alloc_size; ++ uint32_t *regs; ++ int ret; + + /* set full masks if the userspace set all bits + * in the bitfields + */ +- if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) { ++ if (se_num == AMDGPU_INFO_MMR_SE_INDEX_MASK) + se_num = 0xffffffff; +- } else if (se_num >= AMDGPU_GFX_MAX_SE) { +- ret = -EINVAL; +- goto out; +- } ++ else if (se_num >= AMDGPU_GFX_MAX_SE) ++ return -EINVAL; + +- if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) { ++ if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) + sh_num = 0xffffffff; +- } else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) { +- ret = -EINVAL; +- goto out; +- } ++ else if (sh_num >= AMDGPU_GFX_MAX_SH_PER_SE) ++ return -EINVAL; + +- if (info->read_mmr_reg.count > 128) { +- ret = -EINVAL; +- goto out; +- } ++ if (info->read_mmr_reg.count > 128) ++ return -EINVAL; + +- regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); +- if (!regs) { +- ret = -ENOMEM; +- goto out; +- } ++ regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), ++ GFP_KERNEL); ++ if (!regs) ++ return -ENOMEM; + ++ down_read(&adev->reset_domain->sem); + alloc_size = info->read_mmr_reg.count * sizeof(*regs); +- + amdgpu_gfx_off_ctrl(adev, false); ++ ret = 0; + for (i = 0; i < info->read_mmr_reg.count; i++) { + if (amdgpu_asic_read_register(adev, se_num, sh_num, + info->read_mmr_reg.dword_offset + i, + ®s[i])) { + DRM_DEBUG_KMS("unallowed offset %#x\n", + info->read_mmr_reg.dword_offset + i); +- kfree(regs); +- amdgpu_gfx_off_ctrl(adev, true); + ret = -EFAULT; +- goto out; ++ break; + } + } + amdgpu_gfx_off_ctrl(adev, true); +- n = copy_to_user(out, regs, min(size, alloc_size)); +- kfree(regs); +- ret = (n ? -EFAULT : 0); +-out: + up_read(&adev->reset_domain->sem); ++ ++ if (!ret) { ++ ret = copy_to_user(out, regs, min(size, alloc_size)) ++ ? -EFAULT : 0; ++ } ++ kfree(regs); + return ret; + } + case AMDGPU_INFO_DEV_INFO: { +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch b/queue-7.0/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch new file mode 100644 index 0000000000..2fb38b013d --- /dev/null +++ b/queue-7.0/drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch @@ -0,0 +1,40 @@ +From ee341d91d9a7ca9295cfbf9330535675126cc02f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:18:28 -0500 +Subject: drm/amdgpu/gfx10: look at the right prop for gfx queue priority +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit 355d96cdec5c61fd83f7eb54f1a28e38809645d6 ] + +Look at hqd_queue_priority rather than hqd_pipe_priority. +In practice, it didn't matter as both were always set for +kernel queues, but that will change in the future. + +Fixes: b07d1d73b09e ("drm/amd/amdgpu: Enable high priority gfx queue") +Reviewed-by:Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 1893ceeeb26c8..8b60299b73ef7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -6752,7 +6752,7 @@ static void gfx_v10_0_gfx_mqd_set_priority(struct amdgpu_device *adev, + /* set up default queue priority level + * 0x0 = low priority, 0x1 = high priority + */ +- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) ++ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) + priority = 1; + + tmp = RREG32_SOC15(GC, 0, mmCP_GFX_HQD_QUEUE_PRIORITY); +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch b/queue-7.0/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch new file mode 100644 index 0000000000..e21669eb0e --- /dev/null +++ b/queue-7.0/drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch @@ -0,0 +1,40 @@ +From 46808df73e741b0a5ce4c532b35314021d54f736 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 18:20:27 -0500 +Subject: drm/amdgpu/gfx11: look at the right prop for gfx queue priority +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit f9a4e81bcbd04e6f967d851f9fe69d8bb3cc08b3 ] + +Look at hqd_queue_priority rather than hqd_pipe_priority. +In practice, it didn't matter as both were always set for +kernel queues, but that will change in the future. + +Fixes: 2e216b1e6ba2 ("drm/amdgpu/gfx11: handle priority setup for gfx pipe1") +Reviewed-by:Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index 8d73193de06f7..0f783adb93351 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -4093,7 +4093,7 @@ static void gfx_v11_0_gfx_mqd_set_priority(struct amdgpu_device *adev, + /* set up default queue priority level + * 0x0 = low priority, 0x1 = high priority + */ +- if (prop->hqd_pipe_priority == AMDGPU_GFX_PIPE_PRIO_HIGH) ++ if (prop->hqd_queue_priority == AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM) + priority = 1; + + tmp = regCP_GFX_HQD_QUEUE_PRIORITY_DEFAULT; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-gfx12.1-scratch-memory-limit-up-to-57-bit.patch b/queue-7.0/drm-amdgpu-gfx12.1-scratch-memory-limit-up-to-57-bit.patch new file mode 100644 index 0000000000..5a12f91e84 --- /dev/null +++ b/queue-7.0/drm-amdgpu-gfx12.1-scratch-memory-limit-up-to-57-bit.patch @@ -0,0 +1,137 @@ +From 6ef688448de85788ab4e0facdba243ab28cad5ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 15:15:51 -0500 +Subject: drm/amdgpu: GFX12.1 scratch memory limit up to 57-bit + +From: Philip Yang + +[ Upstream commit b2d13a41da94008fdd3786b396a6375c12454522 ] + +The scratch aperture or gmc private aperture in flat memory contains +57 bits of data on gfx v12.1.0 compared to the 32 bits from previous. + +Add new helper kfd_init_apertures_v12 for gfx version >= v12.1.0 which +supports 57-bit VA space. + +v2: + - update pdd->scratch_limit (Yu, Lang) + - update fixes tag (Felix Kuehling) + - add helper kfd_init_apertures_v12 + +Fixes: db1882b3ff0c ("drm/amdkfd: Update LDS, Scratch base for 57bit address") +Signed-off-by: Philip Yang +Reviewed-by: Lang Yu +Acked-by: Felix Kuehling +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c | 2 +- + drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c | 10 ++++-- + drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c | 35 ++++++++++++++------ + 3 files changed, 34 insertions(+), 13 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +index eb9725ae1607a..557d15b90ad27 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +@@ -1405,7 +1405,7 @@ static void gfx_v12_1_xcc_init_compute_vmid(struct amdgpu_device *adev, + /* + * Configure apertures: + * LDS: 0x20000000'00000000 - 0x20000001'00000000 (4GB) +- * Scratch: 0x10000000'00000000 - 0x10000001'00000000 (4GB) ++ * Scratch: 0x10000000'00000000 - 0x11ffffff'ffffffff (128PB 57-bit) + */ + sh_mem_bases = REG_SET_FIELD(0, SH_MEM_BASES, PRIVATE_BASE, + (adev->gmc.private_aperture_start >> 58)); +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +index b9671fc39e2a8..da4a0cf4aad0c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +@@ -654,9 +654,15 @@ static int gmc_v12_0_early_init(struct amdgpu_ip_block *ip_block) + adev->gmc.shared_aperture_start = 0x2000000000000000ULL; + adev->gmc.shared_aperture_end = + adev->gmc.shared_aperture_start + (4ULL << 30) - 1; ++ + adev->gmc.private_aperture_start = 0x1000000000000000ULL; +- adev->gmc.private_aperture_end = +- adev->gmc.private_aperture_start + (4ULL << 30) - 1; ++ if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 1, 0)) ++ adev->gmc.private_aperture_end = ++ adev->gmc.private_aperture_start + (1ULL << 57) - 1; ++ else ++ adev->gmc.private_aperture_end = ++ adev->gmc.private_aperture_start + (4ULL << 30) - 1; ++ + adev->gmc.noretry_flags = AMDGPU_VM_NORETRY_FLAGS_TF; + + return 0; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +index e8da0b4527dc5..04c5e26f01ed9 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +@@ -342,20 +342,14 @@ static void kfd_init_apertures_vi(struct kfd_process_device *pdd, uint8_t id) + + static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id) + { +- if (KFD_GC_VERSION(pdd->dev) >= IP_VERSION(12, 1, 0)) +- pdd->lds_base = pdd->dev->adev->gmc.shared_aperture_start; +- else +- pdd->lds_base = MAKE_LDS_APP_BASE_V9(); ++ pdd->lds_base = MAKE_LDS_APP_BASE_V9(); + pdd->lds_limit = MAKE_LDS_APP_LIMIT(pdd->lds_base); + + pdd->gpuvm_base = AMDGPU_VA_RESERVED_BOTTOM; + pdd->gpuvm_limit = + pdd->dev->kfd->shared_resources.gpuvm_size - 1; + +- if (KFD_GC_VERSION(pdd->dev) >= IP_VERSION(12, 1, 0)) +- pdd->scratch_base = pdd->dev->adev->gmc.private_aperture_start; +- else +- pdd->scratch_base = MAKE_SCRATCH_APP_BASE_V9(); ++ pdd->scratch_base = MAKE_SCRATCH_APP_BASE_V9(); + pdd->scratch_limit = MAKE_SCRATCH_APP_LIMIT(pdd->scratch_base); + + /* +@@ -365,6 +359,25 @@ static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id) + pdd->qpd.cwsr_base = AMDGPU_VA_RESERVED_TRAP_START(pdd->dev->adev); + } + ++static void kfd_init_apertures_v12(struct kfd_process_device *pdd, uint8_t id) ++{ ++ pdd->lds_base = pdd->dev->adev->gmc.shared_aperture_start; ++ pdd->lds_limit = pdd->dev->adev->gmc.shared_aperture_end; ++ ++ pdd->gpuvm_base = AMDGPU_VA_RESERVED_BOTTOM; ++ pdd->gpuvm_limit = ++ pdd->dev->kfd->shared_resources.gpuvm_size - 1; ++ ++ pdd->scratch_base = pdd->dev->adev->gmc.private_aperture_start; ++ pdd->scratch_limit = pdd->dev->adev->gmc.private_aperture_end; ++ ++ /* ++ * Place TBA/TMA on opposite side of VM hole to prevent ++ * stray faults from triggering SVM on these pages. ++ */ ++ pdd->qpd.cwsr_base = AMDGPU_VA_RESERVED_TRAP_START(pdd->dev->adev); ++} ++ + int kfd_init_apertures(struct kfd_process *process) + { + uint8_t id = 0; +@@ -412,9 +425,11 @@ int kfd_init_apertures(struct kfd_process *process) + kfd_init_apertures_vi(pdd, id); + break; + default: +- if (KFD_GC_VERSION(dev) >= IP_VERSION(9, 0, 1)) ++ if (KFD_GC_VERSION(dev) >= IP_VERSION(12, 1, 0)) { ++ kfd_init_apertures_v12(pdd, id); ++ } else if (KFD_GC_VERSION(dev) >= IP_VERSION(9, 0, 1)) { + kfd_init_apertures_v9(pdd, id); +- else { ++ } else { + WARN(1, "Unexpected ASIC family %u", + dev->adev->asic_type); + return -EINVAL; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch b/queue-7.0/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch new file mode 100644 index 0000000000..194c7aa237 --- /dev/null +++ b/queue-7.0/drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch @@ -0,0 +1,146 @@ +From 33426c6fd7b86c2ee50d4fbac3bec8fe781780b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:33 +0200 +Subject: drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ] + +This commit fixes amdgpu to work on the Radeon HD 7870 XT +which has never worked with the Linux open source drivers before. + +Some boards have "harvested" chips, meaning that some parts of +the chip are disabled and fused, and it's sold for cheaper and +under a different marketing name. +On a harvested chip, any of the following can be disabled: +- CUs (Compute Units) +- RBs (Render Backend, aka. ROP) +- Memory channels (ie. the chip has a lower bandwidth) +- TCCs (ie. less L2 cache) + +Handle chips with harvested TCCs by patching the registers +that configure how TCCs are mapped. + +If some TCCs are disabled, we need to make sure that +the disabled TCCs are not used, and the remaining TCCs +are used optimally. + +TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. + +Note that the TCC configuration is highly relevant to performance. +Suboptimal configuration (eg. CHAN_STEER=0) can significantly +reduce gaming performance. + +For optimal performance: +- Rely on the CHAN_STEER from the golden registers table, + only skip disabled TCCs but keep the mapping order. +- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, + which performs better than using the same TCC twice. + +v2: +- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs. + +Link: https://bugs.freedesktop.org/show_bug.cgi?id=60879 +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2664 +Fixes: 2cd46ad22383 ("drm/amdgpu: add graphic pipeline implementation for si v8") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 00218d15528fab9f6b31241fe5904eea4fcaa30d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +index 73223d97a87f5..ac90d8e9d86a8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +@@ -1571,6 +1571,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev) + mutex_unlock(&adev->grbm_idx_mutex); + } + ++/** ++ * gfx_v6_0_setup_tcc() - setup which TCCs are used ++ * ++ * @adev: amdgpu_device pointer ++ * ++ * Verify whether the current GPU has any TCCs disabled, ++ * which can happen when the GPU is harvested and some ++ * memory channels are disabled, reducing the memory bus width. ++ * For example, on the Radeon HD 7870 XT (Tahiti LE). ++ * ++ * If some TCCs are disabled, we need to make sure that ++ * the disabled TCCs are not used, and the remaining TCCs ++ * are used optimally. ++ * ++ * TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. ++ * TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. ++ * ++ * For optimal performance: ++ * - Rely on the CHAN_STEER from the golden registers table, ++ * only skip disabled TCCs but keep the mapping order. ++ * - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, ++ * which performs better than using the same TCC twice. ++ */ ++static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev) ++{ ++ u32 i, tcc, tcp_addr_config, num_active_tcc = 0; ++ u64 chan_steer, patched_chan_steer = 0; ++ const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; ++ const u32 dis_tcc_mask = ++ amdgpu_gfx_create_bitmask(num_max_tcc) & ++ (REG_GET_FIELD(RREG32(mmCGTS_TCC_DISABLE), ++ CGTS_TCC_DISABLE, TCC_DISABLE) | ++ REG_GET_FIELD(RREG32(mmCGTS_USER_TCC_DISABLE), ++ CGTS_USER_TCC_DISABLE, TCC_DISABLE)); ++ ++ /* When no TCC is disabled, the golden registers table already has optimal TCC setup */ ++ if (!dis_tcc_mask) ++ return; ++ ++ /* Each 4-bit nibble contains the index of a TCC used by all TCPs */ ++ chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull); ++ ++ /* Patch the TCP to TCC mapping to skip disabled TCCs */ ++ for (i = 0; i < num_max_tcc; ++i) { ++ tcc = (chan_steer >> (u64)(4 * i)) & 0xf; ++ ++ if (!((1 << tcc) & dis_tcc_mask)) { ++ /* Copy enabled TCC indices to the patched register value. */ ++ patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc); ++ ++num_active_tcc; ++ } ++ } ++ ++ WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask)); ++ ++ /* Patch number of TCCs used by TCPs */ ++ tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG), ++ TCP_ADDR_CONFIG, NUM_TCC_BANKS, ++ num_active_tcc - 1); ++ ++ WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config); ++ WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer)); ++ WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer)); ++} ++ + static void gfx_v6_0_config_init(struct amdgpu_device *adev) + { + adev->gfx.config.double_offchip_lds_buf = 0; +@@ -1729,6 +1794,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev) + gfx_v6_0_tiling_mode_table_init(adev); + + gfx_v6_0_setup_rb(adev); ++ gfx_v6_0_setup_tcc(adev); + + gfx_v6_0_setup_spi(adev); + +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch b/queue-7.0/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch new file mode 100644 index 0000000000..2d56227b22 --- /dev/null +++ b/queue-7.0/drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch @@ -0,0 +1,54 @@ +From 176ed74c8f4902d4e7b3dfb0f48793726337cdf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:30 +0200 +Subject: drm/amdgpu/gmc: Fix AMDGPU_GART_PLACEMENT_LOW to not overlap with + VRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 36d65da7570bf72ce28504fa9a81abfc728e6d96 ] + +When the GART placement is set to AMDGPU_GART_PLACEMENT_LOW: +Make sure that GART does not overlap with VRAM when +VRAM is configured to be in the low address space. + +Solve this according to the following logic: +- When GART fits before VRAM, use zero address for GART +- Otherwise, put GART after the end of VRAM, aligned to 4 GiB + +Previously, I had assumed this was not possible +so it was OK to not handle it, but now we got a report +from a user who has a board that is configured this way. + +Fixes: 917f91d8d8e8 ("drm/amdgpu/gmc: add a way to force a particular placement for GART") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 3d9de5d86a1658cadb311461b001eb1df67263ad) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +index 5179fa008626e..19abb09f0e197 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +@@ -313,7 +313,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, + mc->gart_start = max_mc_address - mc->gart_size + 1; + break; + case AMDGPU_GART_PLACEMENT_LOW: +- mc->gart_start = 0; ++ if (size_bf >= mc->gart_size) ++ mc->gart_start = 0; ++ else ++ mc->gart_start = ALIGN(mc->fb_end, four_gb); + break; + case AMDGPU_GART_PLACEMENT_BEST_FIT: + default: +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch new file mode 100644 index 0000000000..4fe11363e5 --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch @@ -0,0 +1,41 @@ +From 3058815df68dfda4e5132d79e13882944ebfa6cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v2.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit e5f612dc91650561fe2b5b76dd6d2898ec9ad480 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 6ac27241106b ("drm/amdgpu: add JPEG v2.0 function supports") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 96179da0c6b059eb31706a0abe8dd6381c533143) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +index 9fe8d10ab2705..cffb1e6bab353 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +@@ -802,6 +802,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_0_dec_ring_get_rptr, + .get_wptr = jpeg_v2_0_dec_ring_get_wptr, + .set_wptr = jpeg_v2_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch new file mode 100644 index 0000000000..bb44277ee8 --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch @@ -0,0 +1,49 @@ +From 3f72404791aaf7d216be4c3163d81bc2d5b6cf1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v2.5 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 79405e774ede411c6b47ed41c651e40b92de64a2 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 14f43e8f88c5 ("drm/amdgpu: move JPEG2.5 out from VCN2.5") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 3216a7f4e2642bda5fd14f57586e835ae9202587) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +index 20983f126b490..13a6e24c624a2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +@@ -693,6 +693,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, +@@ -724,6 +725,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { + static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v2_5_dec_ring_get_rptr, + .get_wptr = jpeg_v2_5_dec_ring_get_wptr, + .set_wptr = jpeg_v2_5_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch new file mode 100644 index 0000000000..c45245c50b --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch @@ -0,0 +1,41 @@ +From 9c16663ae8117425fb0dbb225e454cfb442b24e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:10 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v3.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit a2baf12eec41f246689e6a3f8619af1200031576 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: dfd57dbf44dd ("drm/amdgpu: add JPEG3.0 support for Sienna_Cichlid") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 4d7d774f100efb5089c86a1fb8c5bf47c63fc9ef) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +index 98f5e0622bc58..d0445df39d2c0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +@@ -594,6 +594,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v3_0_dec_ring_get_rptr, + .get_wptr = jpeg_v3_0_dec_ring_get_wptr, + .set_wptr = jpeg_v3_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch new file mode 100644 index 0000000000..5e82b00192 --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch @@ -0,0 +1,41 @@ +From ac227adb09897e95cfab5a67e77fabfddbf8119d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit e7e90b5839aeb8805ec83bb4da610b8dab8e184d ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: b13111de32a9 ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_0") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 8d0cac9478a3f046279c657d6a2545de49ae675a) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +index 0bd83820dd20c..6fd4238a8471a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +@@ -759,6 +759,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch new file mode 100644 index 0000000000..5698d576fb --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch @@ -0,0 +1,41 @@ +From 31af3cf562eabdda849b5534448f42f0ae15835c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.3 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 83e37c0987ca92f9e87789b46dd311dcf5a4a6c8 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: e684e654eba9 ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_3") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 2f6afc97d259d530f4f86c7743efbc573a8da927) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +index 82abe181c7309..0c746580de113 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +@@ -1219,6 +1219,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch new file mode 100644 index 0000000000..c5daa9d61e --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch @@ -0,0 +1,41 @@ +From 837ce02171e7e7ddfda78dbfe07d3072d2042065 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.5 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit b65b7f3f3c18f797f81a2af7c97e2079900ad6db ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 8f98a715da8e ("drm/amdgpu/jpeg: add jpeg support for VCN4_0_5") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit f05d0a4f21fc720116d6e238f23308b199891058) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +index 54fd9c800c40a..a43582b9c876c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +@@ -804,6 +804,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, + .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, + .set_wptr = jpeg_v4_0_5_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch new file mode 100644 index 0000000000..070fc0e8f1 --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch @@ -0,0 +1,41 @@ +From efb44bf5c4244fa096673c446262f9529e064dc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit ea7c61c5f895e8f9ea0ffffa180498ef9c740152 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: dfad65c65728 ("drm/amdgpu: Add JPEG5 support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 0f43893d3cd478fa57836697525b338817c9c23d) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +index 46bf15dce2bd0..72a4b2d0676fa 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +@@ -680,6 +680,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, + .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, + .set_wptr = jpeg_v5_0_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.1-ri.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.1-ri.patch new file mode 100644 index 0000000000..3334af229a --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.1-ri.patch @@ -0,0 +1,41 @@ +From 8fa379ef0cee50378c30bfe9c257fe57e468baef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.1 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 2f8e3da71a1b469b6e157aa3972f1448b3157840 ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: b8f57b69942b ("drm/amdgpu: Add JPEG5_0_1 support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 742a98e2e81702df8fe1b1eccee5223220a03dc2) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +index edecbfe66c79a..250316704dfac 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +@@ -884,6 +884,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v5_0_1_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v5_0_1_dec_ring_get_rptr, + .get_wptr = jpeg_v5_0_1_dec_ring_get_wptr, + .set_wptr = jpeg_v5_0_1_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.3.0-ri.patch b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.3.0-ri.patch new file mode 100644 index 0000000000..d1b8678c94 --- /dev/null +++ b/queue-7.0/drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.3.0-ri.patch @@ -0,0 +1,41 @@ +From bcbce7437a04f65d40deb83b40f866345188fc65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:46:11 -0400 +Subject: drm/amdgpu/jpeg: set no_user_fence for JPEG v5.3.0 ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 3b0ea2021351b6b813b34fac940957f1f4fad85b ] + +JPEG rings do not support 64-bit user fence writes, reject CS +submissions with user fences. + +Fixes: 4aeaf3cbfa9f ("drm/amdgpu/jpeg: Add jpeg 5.3.0 support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 86ac011ae234c03fb872f4945913391ea1d8862e) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c +index 1821dced936fb..e7546816baba3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_3_0.c +@@ -661,6 +661,7 @@ static const struct amd_ip_funcs jpeg_v5_3_0_ip_funcs = { + static const struct amdgpu_ring_funcs jpeg_v5_3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, ++ .no_user_fence = true, + .get_rptr = jpeg_v5_3_0_dec_ring_get_rptr, + .get_wptr = jpeg_v5_3_0_dec_ring_get_wptr, + .set_wptr = jpeg_v5_3_0_dec_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-only-send-rma-cper-when-threshold-is-exce.patch b/queue-7.0/drm-amdgpu-only-send-rma-cper-when-threshold-is-exce.patch new file mode 100644 index 0000000000..fb9dceb067 --- /dev/null +++ b/queue-7.0/drm-amdgpu-only-send-rma-cper-when-threshold-is-exce.patch @@ -0,0 +1,38 @@ +From f75295e5d2b0db1abdfb977bf8b66270ad5326e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 09:34:04 -0400 +Subject: drm/amdgpu: Only send RMA CPER when threshold is exceeded + +From: Kent Russell + +[ Upstream commit b56922fc37454633b831a2a04a1537616742977d ] + +According to our documentation, the RMA should only occur when the +threshold has been exceeded, not met. + +Fixes: 5028a24aa89a ("drm/amdgpu: Send applicable RMA CPERs at end of RAS init") +Signed-off-by: Kent Russell +Reviewed-by: Tao Zhou +Signed-off-by: Alex Deucher +(cherry picked from commit 8bc09a7d0e90ec45a0b4865661cf45cbbce1c3d7) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +index 6fba9d5b29ea6..ee271f43d5ad0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +@@ -1939,7 +1939,7 @@ void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev) + if (!control || amdgpu_bad_page_threshold == 0) + return; + +- if (control->ras_num_bad_pages >= ras->bad_page_cnt_threshold) { ++ if (control->ras_num_bad_pages > ras->bad_page_cnt_threshold) { + if (amdgpu_dpm_send_rma_reason(adev)) + dev_warn(adev->dev, "Unable to send out-of-band RMA CPER"); + else +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-remove-dead-negative-offset-check-in-amdg.patch b/queue-7.0/drm-amdgpu-remove-dead-negative-offset-check-in-amdg.patch new file mode 100644 index 0000000000..4b08ccadbd --- /dev/null +++ b/queue-7.0/drm-amdgpu-remove-dead-negative-offset-check-in-amdg.patch @@ -0,0 +1,58 @@ +From 2fbb3f19376d3c67eb730bf4f07c8bf5fb628f9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 18:53:59 +0530 +Subject: drm/amdgpu: Remove dead negative offset check in + amdgpu_virt_init_critical_region() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Srinivasan Shanmugam + +[ Upstream commit 4fce3dfab54d60ebaff1c7a9020a730a0708b705 ] + +amdgpu_virt_init_critical_region() stores init_hdr_offset as u64. +The subsequent check for init_hdr_offset < 0 is therefore always false. + +Drop the unreachable validation and rely on the existing +check_add_overflow() and VRAM end bounds check for offset validation. + +This resolves the Smatch warning about comparing an unsigned value +against zero. + +drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c:953 amdgpu_virt_init_critical_region() warn: unsigned 'init_hdr_offset' is never less than zero. + +Fixes: 07009df6494d ("drm/amdgpu: Introduce SRIOV critical regions v2 during VF init") +Cc: Dan Carpenter +Cc: Ellen Pan +Cc: Lijo Lazar +Cc: Alex Deucher +Cc: Christian König +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Bokun Zhang +Reviewed-by: Ellen Pan +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +index 275745aa58292..1e284ecad2170 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +@@ -950,11 +950,6 @@ int amdgpu_virt_init_critical_region(struct amdgpu_device *adev) + if (adev->virt.req_init_data_ver != GPU_CRIT_REGION_V2) + return 0; + +- if (init_hdr_offset < 0) { +- dev_err(adev->dev, "Invalid init header offset\n"); +- return -EINVAL; +- } +- + vram_size = RREG32(mmRCC_CONFIG_MEMSIZE); + if (!vram_size || vram_size == U32_MAX) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch b/queue-7.0/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch new file mode 100644 index 0000000000..801637283d --- /dev/null +++ b/queue-7.0/drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch @@ -0,0 +1,65 @@ +From 9a8ff987698335aa11362d73924853704217c1c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 23:49:31 +0200 +Subject: drm/amdgpu/uvd3.1: Don't validate the firmware when already validated +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ] + +UVD 3.1 firmware validation seems to always fail after +attempting it when it had already been validated. +(This works similarly with the VCE 1.0 as well.) + +Don't attempt repeating the validation when it's already done. + +This caused issues in situations when the system isn't able +to suspend the GPU properly and so the GPU isn't actually +powered down. Then amdgpu would fail when calling the IP +block resume function. + +Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/2887 +Fixes: bb7978111dd3 ("drm/amdgpu: fix SI UVD firmware validate resume fail") +Signed-off-by: Timur Kristóf +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +(cherry picked from commit 889a2cfd889c4a4dd9d0c89ce9a8e60b78be71dd) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +index fea576a7f397f..efb3fde919ee3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev) + uint64_t addr; + uint32_t size; + ++ /* When the keyselect is already set, don't perturb it. */ ++ if (RREG32(mmUVD_FW_START)) ++ return; ++ + /* program the VCPU memory controller bits 0-27 */ + addr = (adev->uvd.inst->gpu_addr + AMDGPU_UVD_FIRMWARE_OFFSET) >> 3; + size = AMDGPU_UVD_FIRMWARE_SIZE(adev) >> 3; +@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev) + int i; + uint32_t keysel = adev->uvd.keyselect; + ++ if (RREG32(mmUVD_FW_START) & UVD_FW_STATUS__PASS_MASK) { ++ dev_dbg(adev->dev, "UVD keyselect already set: 0x%x (on CPU: 0x%x)\n", ++ RREG32(mmUVD_FW_START), adev->uvd.keyselect); ++ return 0; ++ } ++ + WREG32(mmUVD_FW_START, keysel); + + for (i = 0; i < 10; ++i) { +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch b/queue-7.0/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch new file mode 100644 index 0000000000..3b10cd2fc8 --- /dev/null +++ b/queue-7.0/drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch @@ -0,0 +1,49 @@ +From 1336a70f56cc6e02da00194fab26d877f55975d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 18:03:06 +0200 +Subject: drm/amdgpu/uvd4.2: Don't initialize UVD 4.2 when DPM is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +[ Upstream commit 8b3e8fa6d7bdab292447a43f70532db437d5d4f5 ] + +UVD 4.2 doesn't work at all when DPM is disabled because +the SMU is responsible for ungating it. So, Linux fails +to boot with CIK GPUs when using the amdgpu.dpm=0 parameter. + +Fix this by returning -ENOENT from uvd_v4_2_early_init() +when amdgpu_dpm isn't enabled. + +Note: amdgpu.dpm=0 is often suggested as a workaround +for issues and is useful for debugging. + +Fixes: a2e73f56fa62 ("drm/amdgpu: Add support for CIK parts") +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +index 73ce3d211ed64..8a9ba2276275c 100644 +--- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +@@ -93,6 +93,11 @@ static void uvd_v4_2_ring_set_wptr(struct amdgpu_ring *ring) + static int uvd_v4_2_early_init(struct amdgpu_ip_block *ip_block) + { + struct amdgpu_device *adev = ip_block->adev; ++ ++ /* UVD doesn't work without DPM, it needs DPM to ungate it. */ ++ if (!amdgpu_dpm) ++ return -ENOENT; ++ + adev->uvd.num_uvd_inst = 1; + + uvd_v4_2_set_ring_funcs(adev); +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch new file mode 100644 index 0000000000..b065b62ff3 --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch @@ -0,0 +1,49 @@ +From af76ac8907fa5c46321d12e049f2f43cce0d614d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v2.0 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8d80b293b41fcb5e9396db93e788b0f4ebcbafb7 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 1b61de45dfaf ("drm/amdgpu: add initial VCN2.0 support (v2)") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit e2b5499fca55f1a32960a311bbb62e35891eaf73) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +index e35fae9cdaf66..0442bfcfd384d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +@@ -2113,6 +2113,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = { + static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v2_0_dec_ring_get_rptr, + .get_wptr = vcn_v2_0_dec_ring_get_wptr, +@@ -2145,6 +2146,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v2_0_enc_ring_get_rptr, + .get_wptr = vcn_v2_0_enc_ring_get_wptr, + .set_wptr = vcn_v2_0_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch new file mode 100644 index 0000000000..df33bb5af7 --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch @@ -0,0 +1,49 @@ +From b1fd3ae57266cf1ff550d11304a8d2451bded3fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v2.5 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 4f317863a3ab212a027d8c8c3cc3af4e3fb95704 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 28c17d72072b ("drm/amdgpu: add VCN2.5 basic supports") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit efc9dd5590894109bce9a0bfe1fa5592dd6b20b1) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +index 006a154511971..8b8184fe6764b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +@@ -1778,6 +1778,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring) + static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v2_5_dec_ring_get_rptr, + .get_wptr = vcn_v2_5_dec_ring_get_wptr, +@@ -1879,6 +1880,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v2_5_enc_ring_get_rptr, + .get_wptr = vcn_v2_5_enc_ring_get_wptr, + .set_wptr = vcn_v2_5_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch new file mode 100644 index 0000000000..9d9b2aa5b6 --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch @@ -0,0 +1,57 @@ +From 68f21a520ffe912f4ac6e2072e1cb1a042ce4409 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:35 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v3.0 enc/dec rings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit f1e5a6660d7cbf006079126d9babbf0ccf538c6b ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: cf14826cdfb5 ("drm/amdgpu: add VCN3.0 support for Sienna_Cichlid") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 663bed3c7b8b9a7624b0d95d300ddae034ad0614) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +index 2fe5b3fe287f9..81bba3ec2a937 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +@@ -1856,6 +1856,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0x3f, + .nop = VCN_DEC_SW_CMD_NO_OP, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v3_0_dec_ring_get_rptr, + .get_wptr = vcn_v3_0_dec_ring_get_wptr, +@@ -2038,6 +2039,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_DEC, + .align_mask = 0xf, ++ .no_user_fence = true, + .secure_submission_supported = true, + .get_rptr = vcn_v3_0_dec_ring_get_rptr, + .get_wptr = vcn_v3_0_dec_ring_get_wptr, +@@ -2140,6 +2142,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v3_0_enc_ring_get_rptr, + .get_wptr = vcn_v3_0_enc_ring_get_wptr, + .set_wptr = vcn_v3_0_enc_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0-enc-ri.patch b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0-enc-ri.patch new file mode 100644 index 0000000000..9864c2c016 --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0-enc-ri.patch @@ -0,0 +1,41 @@ +From 8ca222b673df8d7f4cdb6f9c206ec61074357d82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 51f694221047c84fa185be98210eb2c354ffb8c6 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 8da1170a16e4 ("drm/amdgpu: add VCN4 ip block support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit fd852c048b46f9825e904a4f3f4538fe9d8827d9) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +index 63d37b475c2c3..ff7269bafae8e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +@@ -1996,6 +1996,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata), + .get_rptr = vcn_v4_0_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_unified_ring_get_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch new file mode 100644 index 0000000000..be2dc5ed04 --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch @@ -0,0 +1,41 @@ +From bd16540b86f7aaab3b7f1b6887d2cb35910802e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0.3 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 4532b52b34e4e4310386e6fdf6a643368599f522 ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: b889ef4ac988 ("drm/amdgpu/vcn: add vcn support for VCN4_0_3") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit ff1a5a125c5a70c328806b9bc01d7d942cf3f9aa) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +index e78526a4e521e..210e41cf29374 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +@@ -1758,6 +1758,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, + .set_wptr = vcn_v4_0_3_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch new file mode 100644 index 0000000000..62a7a63d85 --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch @@ -0,0 +1,41 @@ +From 338fe0c2fcd5b383f3dbb0cb8ba51d03fc290241 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v4.0.5 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 589a254bf3e88204c8402b9cbccd5e23a0af990f ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 547aad32edac ("drm/amdgpu: add VCN4 ip block support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 084d94ac93707bdda07efb5cee786f632de4219b) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +index 1f6a22983c0dd..1571cc5a148c8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +@@ -1483,6 +1483,7 @@ static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, + .set_wptr = vcn_v4_0_5_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch new file mode 100644 index 0000000000..20cf436ee8 --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch @@ -0,0 +1,41 @@ +From d24b85df4951521febc4db5339ccc46cad159500 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v5.0.0 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8cae0ce77de492d7c31c1532a2e80c0c6e7e58cb ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: b6d1a0632051 ("drm/amdgpu: add VCN_5_0_0 IP block support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit 49b1fbbb5a071197ee71e2d70959b1cb29bdc317) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +index 6109124f852e5..d5f49fa33bee4 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +@@ -1207,6 +1207,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, + .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, + .set_wptr = vcn_v5_0_0_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.1-enc-.patch b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.1-enc-.patch new file mode 100644 index 0000000000..42f00e7fca --- /dev/null +++ b/queue-7.0/drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.1-enc-.patch @@ -0,0 +1,41 @@ +From 251cdeabb44d62aabfff1210ea39ad8e80a3ba89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 11:45:36 -0400 +Subject: drm/amdgpu/vcn: set no_user_fence for VCN v5.0.1 enc ring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yinjie Yao + +[ Upstream commit 8f4954722eab88e10c4ea0c0d3b1269c31421d3a ] + +VCN encoder and decoder rings do not support 64-bit user fence writes, +reject CS submissions with user fences. + +Fixes: 346492f30ce3 ("drm/amdgpu: Add VCN_5_0_1 support") +Reviewed-by: Christian König +Reviewed-by: Alex Deucher +Signed-off-by: Yinjie Yao +Signed-off-by: Alex Deucher +(cherry picked from commit e16be95a2c3ee712b142cb27d2dca0b461181359) +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +index c28c6aff17aaa..54fbf8d73ca67 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +@@ -1419,6 +1419,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_1_unified_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, ++ .no_user_fence = true, + .get_rptr = vcn_v5_0_1_unified_ring_get_rptr, + .get_wptr = vcn_v5_0_1_unified_ring_get_wptr, + .set_wptr = vcn_v5_0_1_unified_ring_set_wptr, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdkfd-removed-commented-line-for-mqd-queue-prio.patch b/queue-7.0/drm-amdkfd-removed-commented-line-for-mqd-queue-prio.patch new file mode 100644 index 0000000000..0460c0f8f7 --- /dev/null +++ b/queue-7.0/drm-amdkfd-removed-commented-line-for-mqd-queue-prio.patch @@ -0,0 +1,113 @@ +From 6dd6cc326ab1baae699938251bcf965f3b1576a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:08:16 -0500 +Subject: drm/amdkfd: Removed commented line for MQD queue priority + +From: Andrew Martin + +[ Upstream commit bfe60e539cf7690a6739466b41fb6be250bb783e ] + +Missed deleting the commented line in the original patch. + +Fixes: 73463e26f7e2 ("drm/amdkfd: Disable MQD queue priority") +Signed-off-by: Andrew Martin +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 1 - + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c | 1 - + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c | 1 - + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c | 1 - + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c | 1 - + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 1 - + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 1 - + 7 files changed, 7 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +index 562d475cf4c99..bb70e57ae4d52 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +@@ -70,7 +70,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, + static void set_priority(struct cik_mqd *m, struct queue_properties *q) + { + m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; +- /* m->cp_hqd_queue_priority = q->priority; */ + } + + static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +index d6067316d7f49..77fb41e2486a4 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +@@ -70,7 +70,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, + static void set_priority(struct v10_compute_mqd *m, struct queue_properties *q) + { + m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; +- /* m->cp_hqd_queue_priority = q->priority; */ + } + + static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +index e3a7acb0ccbc8..a1e3cf2384dd3 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +@@ -96,7 +96,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, + static void set_priority(struct v11_compute_mqd *m, struct queue_properties *q) + { + m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; +- /* m->cp_hqd_queue_priority = q->priority; */ + } + + static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +index 0b97376fc6f9f..b3e122d7876e0 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +@@ -77,7 +77,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, + static void set_priority(struct v12_compute_mqd *m, struct queue_properties *q) + { + m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; +- /* m->cp_hqd_queue_priority = q->priority; */ + } + + static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c +index eef6bdce4be39..c90c0d99b1e3f 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c +@@ -131,7 +131,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, + static void set_priority(struct v12_1_compute_mqd *m, struct queue_properties *q) + { + m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; +- /* m->cp_hqd_queue_priority = q->priority; */ + } + + static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +index a535f151cb5fd..e856bee628058 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +@@ -113,7 +113,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, + static void set_priority(struct v9_mqd *m, struct queue_properties *q) + { + m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; +- /* m->cp_hqd_queue_priority = q->priority; */ + } + + static bool mqd_on_vram(struct amdgpu_device *adev) +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +index 69c1b8a690b86..f02ef2d44a07f 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +@@ -73,7 +73,6 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, + static void set_priority(struct vi_mqd *m, struct queue_properties *q) + { + m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; +- /* m->cp_hqd_queue_priority = q->priority; */ + } + + static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm, +-- +2.53.0 + diff --git a/queue-7.0/drm-amdkfd-update-queue-properties-for-metadata-ring.patch b/queue-7.0/drm-amdkfd-update-queue-properties-for-metadata-ring.patch new file mode 100644 index 0000000000..ea5e01a0fa --- /dev/null +++ b/queue-7.0/drm-amdkfd-update-queue-properties-for-metadata-ring.patch @@ -0,0 +1,39 @@ +From 6e4fc76c966709397c2ee4f11f1724b100df3e41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 16:01:10 -0500 +Subject: drm/amdkfd: Update queue properties for metadata ring + +From: Philip Yang + +[ Upstream commit 189208d3d503090d95a39e85433bd608a0d84511 ] + +Metadata ring and queue ring is allocated as one buffer and map +to GPU, so update queue peoperties should add the queue metadata +size and ring size as buffer size to validate queue ring buffer. + +Fixes: c51bb53d5c68 ("drm/amdkfd: Add metadata ring buffer for compute") +Signed-off-by: Philip Yang +Reviewed-by: Alex Sierra +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index f5d2847e1cbb4..3d172e35e57ce 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -590,7 +590,8 @@ int pqm_update_queue_properties(struct process_queue_manager *pqm, + return err; + + if (kfd_queue_buffer_get(vm, (void *)p->queue_address, &p->ring_bo, +- p->queue_size)) { ++ p->queue_size + ++ pqn->q->properties.metadata_queue_size)) { + pr_debug("ring buf 0x%llx size 0x%llx not mapped on GPU\n", + p->queue_address, p->queue_size); + amdgpu_bo_unreserve(vm->root.bo); +-- +2.53.0 + diff --git a/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch b/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch new file mode 100644 index 0000000000..38d5fda4f3 --- /dev/null +++ b/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch @@ -0,0 +1,75 @@ +From 9e0c16f1d177d7076095205d8ea50be7a5af839b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:28 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Add mode_valid hook to + drm_bridge_funcs + +From: Jayesh Choudhary + +[ Upstream commit 6dbff34016052b099558b76632e4983e2df13fed ] + +Add cdns_mhdp_bridge_mode_valid() to check if specific mode is valid for +this bridge or not. In the legacy usecase with +!DRM_BRIDGE_ATTACH_NO_CONNECTOR we were using the hook from +drm_connector_helper_funcs but with DRM_BRIDGE_ATTACH_NO_CONNECTOR +we need to have mode_valid() in drm_bridge_funcs. + +Without this patch, when using DRM_BRIDGE_ATTACH_NO_CONNECTOR +flag, the cdns_mhdp_bandwidth_ok() function would not be called +during mode validation, potentially allowing modes that exceed +the bridge's bandwidth capabilities to be incorrectly marked as +valid. + +Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") +Reviewed-by: Tomi Valkeinen +Signed-off-by: Jayesh Choudhary +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Link: https://patch.msgid.link/20251209120332.3559893-3-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 20 +++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 3379194e4ea6b..3f5cc4e90927d 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2162,6 +2162,25 @@ static const struct drm_edid *cdns_mhdp_bridge_edid_read(struct drm_bridge *brid + return cdns_mhdp_edid_read(mhdp, connector); + } + ++static enum drm_mode_status ++cdns_mhdp_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); ++ ++ mutex_lock(&mhdp->link_mutex); ++ ++ if (!cdns_mhdp_bandwidth_ok(mhdp, mode, mhdp->link.num_lanes, ++ mhdp->link.rate)) { ++ mutex_unlock(&mhdp->link_mutex); ++ return MODE_CLOCK_HIGH; ++ } ++ ++ mutex_unlock(&mhdp->link_mutex); ++ return MODE_OK; ++} ++ + static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { + .atomic_enable = cdns_mhdp_atomic_enable, + .atomic_disable = cdns_mhdp_atomic_disable, +@@ -2176,6 +2195,7 @@ static const struct drm_bridge_funcs cdns_mhdp_bridge_funcs = { + .edid_read = cdns_mhdp_bridge_edid_read, + .hpd_enable = cdns_mhdp_bridge_hpd_enable, + .hpd_disable = cdns_mhdp_bridge_hpd_disable, ++ .mode_valid = cdns_mhdp_bridge_mode_valid, + }; + + static bool cdns_mhdp_detect_hpd(struct cdns_mhdp_device *mhdp, bool *hpd_pulse) +-- +2.53.0 + diff --git a/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch b/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch new file mode 100644 index 0000000000..818cb1ee3f --- /dev/null +++ b/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch @@ -0,0 +1,75 @@ +From 72a369cbffdf8d07940514876c77195957a2cb03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:29 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Handle HDCP state in bridge + atomic check + +From: Harikrishna Shenoy + +[ Upstream commit 4a8edd658489ec2a3d7e20482fa9e8d366153d8d ] + +Now that we have DRM_BRIDGE_ATTACH_NO_CONNECTOR framework, handle the +HDCP state change in bridge atomic check as well to enable correct +functioning for HDCP in both DRM_BRIDGE_ATTACH_NO_CONNECTOR and +!DRM_BRIDGE_ATTACH_NO_CONNECTOR case. + +Without this patch, when using DRM_BRIDGE_ATTACH_NO_CONNECTOR flag, HDCP +state changes would not be properly handled during atomic commits, +potentially leading to HDCP authentication failures or incorrect +protection status for content requiring HDCP encryption. + +Fixes: 6a3608eae6d33 ("drm: bridge: cdns-mhdp8546: Enable HDCP") +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Reviewed-by: Tomi Valkeinen +Link: https://patch.msgid.link/20251209120332.3559893-4-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 3f5cc4e90927d..c7cd0234d1686 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -2123,6 +2123,10 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, + { + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; ++ struct drm_connector_state *old_state, *new_state; ++ struct drm_atomic_state *state = crtc_state->state; ++ struct drm_connector *conn = mhdp->connector_ptr; ++ u64 old_cp, new_cp; + + mutex_lock(&mhdp->link_mutex); + +@@ -2142,6 +2146,25 @@ static int cdns_mhdp_atomic_check(struct drm_bridge *bridge, + if (mhdp->info) + bridge_state->input_bus_cfg.flags = *mhdp->info->input_bus_flags; + ++ if (conn && mhdp->hdcp_supported) { ++ old_state = drm_atomic_get_old_connector_state(state, conn); ++ new_state = drm_atomic_get_new_connector_state(state, conn); ++ old_cp = old_state->content_protection; ++ new_cp = new_state->content_protection; ++ ++ if (old_state->hdcp_content_type != new_state->hdcp_content_type && ++ new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { ++ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; ++ crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); ++ crtc_state->mode_changed = true; ++ } ++ ++ if (!new_state->crtc) { ++ if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) ++ new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; ++ } ++ } ++ + mutex_unlock(&mhdp->link_mutex); + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch b/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch new file mode 100644 index 0000000000..cc8c97f40e --- /dev/null +++ b/queue-7.0/drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch @@ -0,0 +1,196 @@ +From 086aeabc945ec5cb4aa1d747193298fae9dcfb88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Dec 2025 17:33:27 +0530 +Subject: drm/bridge: cadence: cdns-mhdp8546-core: Set the mhdp connector + earlier in atomic_enable() + +From: Jayesh Choudhary + +[ Upstream commit 43d6508ddbf9fb974fbc359a033154f78c9d4c8b ] + +In case if we get errors in cdns_mhdp_link_up() or cdns_mhdp_reg_read() +in atomic_enable, we will go to cdns_mhdp_modeset_retry_fn() and will hit +NULL pointer while trying to access the mutex. We need the connector to +be set before that. Unlike in legacy cases with flag +!DRM_BRIDGE_ATTACH_NO_CONNECTOR, we do not have connector initialised +in bridge_attach(), so add the mhdp->connector_ptr in device structure +to handle both cases with DRM_BRIDGE_ATTACH_NO_CONNECTOR and +!DRM_BRIDGE_ATTACH_NO_CONNECTOR, set it in atomic_enable() earlier to +avoid possible NULL pointer dereference in recovery paths like +modeset_retry_fn() with the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag set. + +Fixes: c932ced6b585 ("drm/tidss: Update encoder/bridge chain connect model") +Signed-off-by: Jayesh Choudhary +Signed-off-by: Harikrishna Shenoy +Reviewed-by: Luca Ceresoli +Reviewed-by: Tomi Valkeinen +Link: https://patch.msgid.link/20251209120332.3559893-2-h-shenoy@ti.com +Signed-off-by: Luca Ceresoli +Signed-off-by: Sasha Levin +--- + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 29 ++++++++++--------- + .../drm/bridge/cadence/cdns-mhdp8546-core.h | 1 + + .../drm/bridge/cadence/cdns-mhdp8546-hdcp.c | 18 +++++++++--- + 3 files changed, 30 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 9392c226ff5b1..3379194e4ea6b 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -740,7 +740,7 @@ static void cdns_mhdp_fw_cb(const struct firmware *fw, void *context) + bridge_attached = mhdp->bridge_attached; + spin_unlock(&mhdp->start_lock); + if (bridge_attached) { +- if (mhdp->connector.dev) ++ if (mhdp->connector_ptr) + drm_kms_helper_hotplug_event(mhdp->bridge.dev); + else + drm_bridge_hpd_notify(&mhdp->bridge, cdns_mhdp_detect(mhdp)); +@@ -1636,6 +1636,7 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp) + return ret; + } + ++ mhdp->connector_ptr = conn; + drm_connector_helper_add(conn, &cdns_mhdp_conn_helper_funcs); + + ret = drm_display_info_set_bus_formats(&conn->display_info, +@@ -1915,17 +1916,25 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge); + struct cdns_mhdp_bridge_state *mhdp_state; + struct drm_crtc_state *crtc_state; +- struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_bridge_state *new_state; + const struct drm_display_mode *mode; + u32 resp; +- int ret; ++ int ret = 0; + + dev_dbg(mhdp->dev, "bridge enable\n"); + + mutex_lock(&mhdp->link_mutex); + ++ mhdp->connector_ptr = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); ++ if (WARN_ON(!mhdp->connector_ptr)) ++ goto out; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, mhdp->connector_ptr); ++ if (WARN_ON(!conn_state)) ++ goto out; ++ + if (mhdp->plugged && !mhdp->link_up) { + ret = cdns_mhdp_link_up(mhdp); + if (ret < 0) +@@ -1945,15 +1954,6 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, + resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN); + +- connector = drm_atomic_get_new_connector_for_encoder(state, +- bridge->encoder); +- if (WARN_ON(!connector)) +- goto out; +- +- conn_state = drm_atomic_get_new_connector_state(state, connector); +- if (WARN_ON(!conn_state)) +- goto out; +- + if (mhdp->hdcp_supported && + mhdp->hw_state == MHDP_HW_READY && + conn_state->content_protection == +@@ -2030,6 +2030,7 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, + if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable) + mhdp->info->ops->disable(mhdp); + ++ mhdp->connector_ptr = NULL; + mutex_unlock(&mhdp->link_mutex); + } + +@@ -2296,7 +2297,7 @@ static void cdns_mhdp_modeset_retry_fn(struct work_struct *work) + + mhdp = container_of(work, typeof(*mhdp), modeset_retry_work); + +- conn = &mhdp->connector; ++ conn = mhdp->connector_ptr; + + /* Grab the locks before changing connector property */ + mutex_lock(&conn->dev->mode_config.mutex); +@@ -2373,7 +2374,7 @@ static void cdns_mhdp_hpd_work(struct work_struct *work) + int ret; + + ret = cdns_mhdp_update_link_status(mhdp); +- if (mhdp->connector.dev) { ++ if (mhdp->connector_ptr) { + if (ret < 0) + schedule_work(&mhdp->modeset_retry_work); + else +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +index bad2fc0c73066..a76775c768956 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +@@ -376,6 +376,7 @@ struct cdns_mhdp_device { + struct mutex link_mutex; + + struct drm_connector connector; ++ struct drm_connector *connector_ptr; + struct drm_bridge bridge; + + struct cdns_mhdp_link link; +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +index 42248f179b69d..21a7d2fb266e4 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +@@ -394,7 +394,7 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) + int ret; + + dev_dbg(mhdp->dev, "[%s:%d] HDCP is being disabled...\n", +- mhdp->connector.name, mhdp->connector.base.id); ++ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); + + ret = cdns_mhdp_hdcp_set_config(mhdp, 0, false); + +@@ -436,6 +436,10 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) + int ret = 0; + + mutex_lock(&mhdp->hdcp.mutex); ++ ++ if (!mhdp->connector_ptr) ++ goto out; ++ + if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + goto out; + +@@ -445,7 +449,7 @@ static int cdns_mhdp_hdcp_check_link(struct cdns_mhdp_device *mhdp) + + dev_err(mhdp->dev, + "[%s:%d] HDCP link failed, retrying authentication\n", +- mhdp->connector.name, mhdp->connector.base.id); ++ mhdp->connector_ptr->name, mhdp->connector_ptr->base.id); + + ret = _cdns_mhdp_hdcp_disable(mhdp); + if (ret) { +@@ -487,13 +491,19 @@ static void cdns_mhdp_hdcp_prop_work(struct work_struct *work) + struct cdns_mhdp_device *mhdp = container_of(hdcp, + struct cdns_mhdp_device, + hdcp); +- struct drm_device *dev = mhdp->connector.dev; ++ struct drm_device *dev = NULL; + struct drm_connector_state *state; + ++ if (mhdp->connector_ptr) ++ dev = mhdp->connector_ptr->dev; ++ ++ if (!dev) ++ return; ++ + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + mutex_lock(&mhdp->hdcp.mutex); + if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { +- state = mhdp->connector.state; ++ state = mhdp->connector_ptr->state; + state->content_protection = mhdp->hdcp.value; + } + mutex_unlock(&mhdp->hdcp.mutex); +-- +2.53.0 + diff --git a/queue-7.0/drm-color-mgmt-typo-s-r332-rgb332.patch b/queue-7.0/drm-color-mgmt-typo-s-r332-rgb332.patch new file mode 100644 index 0000000000..4085a7b284 --- /dev/null +++ b/queue-7.0/drm-color-mgmt-typo-s-r332-rgb332.patch @@ -0,0 +1,39 @@ +From 5772c90dc2b73dc63c36ca1c27a18e8cf9af37a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 09:48:32 +0200 +Subject: drm/color-mgmt: Typo s/R332/RGB332/ + +From: Geert Uytterhoeven + +[ Upstream commit 9d5a2b8f6281f6090002517fb9272ea07038afe8 ] + +Fix a typo of "RGB332" in kerneldoc for the drm_crtc_fill_palette_332() +helper. + +Fixes: 7ff61177b7116825 ("drm/color-mgmt: Prepare for RGB332 palettes") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Javier Martinez Canillas +Reviewed-by: Thomas Zimmermann +Signed-off-by: Thomas Zimmermann +Link: https://patch.msgid.link/c413e45c8f752a532a4ff377f7a8b9eaab4a082a.1776757681.git.geert+renesas@glider.be +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_color_mgmt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c +index c598b99673fc1..e7db4e4ea700f 100644 +--- a/drivers/gpu/drm/drm_color_mgmt.c ++++ b/drivers/gpu/drm/drm_color_mgmt.c +@@ -831,7 +831,7 @@ static void fill_palette_332(struct drm_crtc *crtc, u16 r, u16 g, u16 b, + } + + /** +- * drm_crtc_fill_palette_332 - Programs a default palette for R332-like formats ++ * drm_crtc_fill_palette_332 - Programs a default palette for RGB332-like formats + * @crtc: The displaying CRTC + * @set_palette: Callback for programming the hardware gamma LUT + * +-- +2.53.0 + diff --git a/queue-7.0/drm-fb-helper-fix-a-locking-bug-in-an-error-path.patch b/queue-7.0/drm-fb-helper-fix-a-locking-bug-in-an-error-path.patch new file mode 100644 index 0000000000..cd17e6886f --- /dev/null +++ b/queue-7.0/drm-fb-helper-fix-a-locking-bug-in-an-error-path.patch @@ -0,0 +1,51 @@ +From 577930b597e21f7539f71e846af3c46de27059fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 13:53:54 -0700 +Subject: drm/fb-helper: Fix a locking bug in an error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Bart Van Assche + +[ Upstream commit bd64240dc88caaf7b96dd869f36f165f51b52039 ] + +The name of the function __drm_fb_helper_initial_config_and_unlock() and +also the comment above that function make it clear that all code paths +in this function should unlock fb_helper->lock before returning. Add a +mutex_unlock() call in the only code path where it is missing. This has +been detected by the Clang thread-safety analyzer. + +Cc: Thomas Zimmermann +Cc: Christian König # radeon +Cc: Dmitry Baryshkov # msm +Cc: Javier Martinez Canillas +Fixes: 63c971af4036 ("drm/fb-helper: Allocate and release fb_info in single place") +Signed-off-by: Bart Van Assche +Signed-off-by: Thomas Zimmermann +Reviewed-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260403205355.1181984-1-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_fb_helper.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c +index 05803169bed57..16bfbfb0af161 100644 +--- a/drivers/gpu/drm/drm_fb_helper.c ++++ b/drivers/gpu/drm/drm_fb_helper.c +@@ -1641,8 +1641,10 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper) + drm_client_modeset_probe(&fb_helper->client, width, height); + + info = drm_fb_helper_alloc_info(fb_helper); +- if (IS_ERR(info)) ++ if (IS_ERR(info)) { ++ mutex_unlock(&fb_helper->lock); + return PTR_ERR(info); ++ } + + ret = drm_fb_helper_single_fb_probe(fb_helper); + if (ret < 0) { +-- +2.53.0 + diff --git a/queue-7.0/drm-gpusvm-fix-unbalanced-unlock-in-drm_gpusvm_scan_.patch b/queue-7.0/drm-gpusvm-fix-unbalanced-unlock-in-drm_gpusvm_scan_.patch new file mode 100644 index 0000000000..cff0ccd499 --- /dev/null +++ b/queue-7.0/drm-gpusvm-fix-unbalanced-unlock-in-drm_gpusvm_scan_.patch @@ -0,0 +1,64 @@ +From e2a59e8bb3b3e8523f1109145fd73114f67f30af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 13:34:33 +0100 +Subject: drm/gpusvm: Fix unbalanced unlock in drm_gpusvm_scan_mm() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maciej Patelczyk + +[ Upstream commit d287dee565c3c32e1ed76ec1847af46809c29b90 ] + +There is a unbalanced lock/unlock to gpusvm notifier lock: +[ 931.045868] ===================================== +[ 931.046509] WARNING: bad unlock balance detected! +[ 931.047149] 6.19.0-rc6+xe-**************** #9 Tainted: G U +[ 931.048150] ------------------------------------- +[ 931.048790] kworker/u5:0/51 is trying to release lock (&gpusvm->notifier_lock) at: +[ 931.049801] [] drm_gpusvm_scan_mm+0x188/0x460 [drm_gpusvm_helper] +[ 931.050802] but there are no more locks to release! +[ 931.051463] + +The drm_gpusvm_notifier_unlock() sits under err_free label and the +first jump to err_free is just before calling the +drm_gpusvm_notifier_lock() causing unbalanced unlock. + +Fixes: f1d08a586482 ("drm/gpusvm: Introduce a function to scan the current migration state") +Signed-off-by: Maciej Patelczyk +Cc: Thomas Hellström +Reviewed-by: Matthew Brost +Signed-off-by: Matthew Brost +Link: https://patch.msgid.link/20260209123433.1271053-1-maciej.patelczyk@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_gpusvm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c +index 04bdc386c3fd8..35dd07297dd08 100644 +--- a/drivers/gpu/drm/drm_gpusvm.c ++++ b/drivers/gpu/drm/drm_gpusvm.c +@@ -819,7 +819,7 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range, + + if (!(pfns[i] & HMM_PFN_VALID)) { + state = DRM_GPUSVM_SCAN_UNPOPULATED; +- goto err_free; ++ break; + } + + page = hmm_pfn_to_page(pfns[i]); +@@ -856,9 +856,9 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range, + i += 1ul << drm_gpusvm_hmm_pfn_to_order(pfns[i], i, npages); + } + +-err_free: + drm_gpusvm_notifier_unlock(range->gpusvm); + ++err_free: + kvfree(pfns); + return state; + } +-- +2.53.0 + diff --git a/queue-7.0/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch b/queue-7.0/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch new file mode 100644 index 0000000000..9609862a31 --- /dev/null +++ b/queue-7.0/drm-i915-wm-verify-the-correct-plane-ddb-entry.patch @@ -0,0 +1,44 @@ +From b2f210cd024caba075b2e8bbf16ecd59eda4425a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:48:38 +0200 +Subject: drm/i915/wm: Verify the correct plane DDB entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit a97c88a176b6b8d116f4d3f508f3bd02bc77b462 ] + +Actually verify the DDB entry for the plane we're looking +at instead of always verifying the cursor DDB. + +Fixes: 7d4561722c3b ("drm/i915: Tweak plane ddb allocation tracking") +Signed-off-by: Ville Syrjälä +Link: https://patch.msgid.link/20260324134843.2364-5-ville.syrjala@linux.intel.com +Reviewed-by: Vinod Govindapillai +(cherry picked from commit f002f7c7439de18117a31ca84dc87a59719c3dd6) +Signed-off-by: Tvrtko Ursulin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/skl_watermark.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index f5a6fae815d1d..fa51f976ea725 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3980,8 +3980,8 @@ void intel_wm_state_verify(struct intel_atomic_state *state, + } + + /* DDB */ +- hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; +- sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; ++ hw_ddb_entry = &hw->ddb[plane->id]; ++ sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[plane->id]; + + if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { + drm_err(display->drm, +-- +2.53.0 + diff --git a/queue-7.0/drm-imagination-switch-reset_reason-fields-from-enum.patch b/queue-7.0/drm-imagination-switch-reset_reason-fields-from-enum.patch new file mode 100644 index 0000000000..bb5760a541 --- /dev/null +++ b/queue-7.0/drm-imagination-switch-reset_reason-fields-from-enum.patch @@ -0,0 +1,63 @@ +From dc7b72b66efce3d2400fd384bb4414d12b0c9440 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 20:31:29 +0200 +Subject: drm/imagination: Switch reset_reason fields from enum to u32 + +From: Alexandru Dadu + +[ Upstream commit d2f83a6cd598bf413f1acf34153bd1d71023fbab ] + +Update the reset_reason fwif structure fields from enum to u32 to remove +any ambiguity from the interface (enum is not a fixed size thus is unfit +for the purpose of the data type). + +Fixes: a26f067feac1f ("drm/imagination: Add FWIF headers") +Signed-off-by: Alexandru Dadu +Reviewed-by: Matt Coster +Link: https://patch.msgid.link/20260323-b4-firmware-context-reset-notification-handling-v3-2-1a66049a9a65@imgtec.com +Signed-off-by: Matt Coster +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imagination/pvr_rogue_fwif.h | 8 ++++++-- + drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h | 6 +++++- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h +index 172886be4c820..5d590c4c25663 100644 +--- a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h ++++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h +@@ -1347,8 +1347,12 @@ struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data { + struct rogue_fwif_fwccb_cmd_context_reset_data { + /* Context affected by the reset */ + u32 server_common_context_id; +- /* Reason for reset */ +- enum rogue_context_reset_reason reset_reason; ++ /* ++ * Reason for reset ++ * The valid values for reset_reason are the ones from ++ * enum rogue_context_reset_reason ++ */ ++ u32 reset_reason; + /* Data Master affected by the reset */ + u32 dm; + /* Job ref running at the time of reset */ +diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h +index 6c09c15bf9bd8..f95acd5a1f8e8 100644 +--- a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h ++++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h +@@ -249,7 +249,11 @@ enum rogue_context_reset_reason { + }; + + struct rogue_context_reset_reason_data { +- enum rogue_context_reset_reason reset_reason; ++ /* ++ * The valid values for reset_reason are the ones from ++ * enum rogue_context_reset_reason ++ */ ++ u32 reset_reason; + u32 reset_ext_job_ref; + }; + +-- +2.53.0 + diff --git a/queue-7.0/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch b/queue-7.0/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch new file mode 100644 index 0000000000..a5f7749e6e --- /dev/null +++ b/queue-7.0/drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch @@ -0,0 +1,60 @@ +From 1eaaa9d7f4fa442434f704984a3f6881d94ff7ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 16:48:46 +0300 +Subject: drm/komeda: fix integer overflow in AFBC framebuffer size check + +From: Alexander Konyukhov + +[ Upstream commit 779ec12c85c9e4547519e3903a371a3b26a289de ] + +The AFBC framebuffer size validation calculates the minimum required +buffer size by adding the AFBC payload size to the framebuffer offset. +This addition is performed without checking for integer overflow. + +If the addition oveflows, the size check may incorrectly succed and +allow userspace to provide an undersized drm_gem_object, potentially +leading to out-of-bounds memory access. + +Add usage of check_add_overflow() to safely compute the minimum +required size and reject the framebuffer if an overflow is detected. +This makes the AFBC size validation more robust against malformed. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 65ad2392dd6d ("drm/komeda: Added AFBC support for komeda driver") +Signed-off-by: Alexander Konyukhov +Acked-by: Liviu Dudau +Signed-off-by: Liviu Dudau +Link: https://lore.kernel.org/r/20260203134907.1587067-1-Alexander.Konyukhov@kaspersky.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +index 6ee909f8d5349..50e86f352838f 100644 +--- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c ++++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +@@ -4,6 +4,8 @@ + * Author: James.Qian.Wang + * + */ ++#include ++ + #include + #include + #include +@@ -93,7 +95,9 @@ komeda_fb_afbc_size_check(struct komeda_fb *kfb, struct drm_file *file, + kfb->afbc_size = kfb->offset_payload + n_blocks * + ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, + AFBC_SUPERBLK_ALIGNMENT); +- min_size = kfb->afbc_size + fb->offsets[0]; ++ if (check_add_overflow(kfb->afbc_size, fb->offsets[0], &min_size)) { ++ goto check_failed; ++ } + if (min_size > obj->size) { + DRM_DEBUG_KMS("afbc size check failed, obj_size: 0x%zx. min_size 0x%llx.\n", + obj->size, min_size); +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-a6xx-add-missing-aperture_lock-init.patch b/queue-7.0/drm-msm-a6xx-add-missing-aperture_lock-init.patch new file mode 100644 index 0000000000..0f5d22616e --- /dev/null +++ b/queue-7.0/drm-msm-a6xx-add-missing-aperture_lock-init.patch @@ -0,0 +1,38 @@ +From 36fb1d437bccabc89f5f742b4f4516feb3381a4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 09:16:02 -0700 +Subject: drm/msm/a6xx: Add missing aperture_lock init + +From: Rob Clark + +[ Upstream commit d4ef6d77bb1ef92bdbfb70c7a5d08072848357d8 ] + +Looks like this was somehow missed when introducing gen8 support. + +Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support") +Signed-off-by: Rob Clark +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Akhil P Oommen +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/713545/ +Message-ID: <20260323161603.1165108-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index d6dfe6337bc34..f17bb5e78e0b9 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -2656,6 +2656,7 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) + gpu = &adreno_gpu->base; + + mutex_init(&a6xx_gpu->gmu.lock); ++ spin_lock_init(&a6xx_gpu->aperture_lock); + + adreno_gpu->registers = NULL; + +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-a6xx-correct-oob-usage.patch b/queue-7.0/drm-msm-a6xx-correct-oob-usage.patch new file mode 100644 index 0000000000..d121569e6b --- /dev/null +++ b/queue-7.0/drm-msm-a6xx-correct-oob-usage.patch @@ -0,0 +1,79 @@ +From fb8f2b4c1ca725c9877eb53d6e6b4f41dbc51ef1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:53 +0530 +Subject: drm/msm/a6xx: Correct OOB usage + +From: Akhil P Oommen + +[ Upstream commit d34b6919798c1a8c93e1d7cca297d0e068146bd5 ] + +During the GMU resume sequence, using another OOB other than OOB_GPU may +confuse the internal state of GMU firmware. To align more strictly with +the downstream sequence, move the sysprof related OOB setup after the +OOB_GPU is cleared. + +Fixes: 62cd0fa6990b ("drm/msm/adreno: Disable IFPC when sysprof is active") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714659/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-4-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 5 ----- + drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 6 ++++++ + drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 6 ++++++ + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +index 9662201cd2e9d..690d3e53e2738 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +@@ -1236,11 +1236,6 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) + /* Set the GPU to the current freq */ + a6xx_gmu_set_initial_freq(gpu, gmu); + +- if (refcount_read(&gpu->sysprof_active) > 1) { +- ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET); +- if (!ret) +- set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status); +- } + out: + /* On failure, shut down the GMU to leave it in a good state */ + if (ret) { +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index eeecde88e549f..4e0d67e3acb7e 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -1605,6 +1605,12 @@ static int hw_init(struct msm_gpu *gpu) + a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_BOOT_SLUMBER); + } + ++ if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) { ++ ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET); ++ if (!ret) ++ set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status); ++ } ++ + return ret; + } + +diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c +index 840af9c4d718c..fafeac62aebf5 100644 +--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c +@@ -711,6 +711,12 @@ static int hw_init(struct msm_gpu *gpu) + */ + a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_GPU_SET); + ++ if (!ret && (refcount_read(&gpu->sysprof_active) > 1)) { ++ ret = a6xx_gmu_set_oob(gmu, GMU_OOB_PERFCOUNTER_SET); ++ if (!ret) ++ set_bit(GMU_STATUS_OOB_PERF_SET, &gmu->status); ++ } ++ + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch b/queue-7.0/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch new file mode 100644 index 0000000000..e30f034954 --- /dev/null +++ b/queue-7.0/drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch @@ -0,0 +1,70 @@ +From eafbd0ca7de0d8aa07b12b701d79b71c1af2a677 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 16:58:37 -0400 +Subject: drm/msm/a6xx: Fix dumping A650+ debugbus blocks + +From: Connor Abbott + +[ Upstream commit cc83f71c9be0715fe93b963ffa9767d5d84354ed ] + +These should be appended after the existing debugbus blocks, instead of +replacing them. + +Fixes: 1e05bba5e2b8 ("drm/msm/a6xx: Update a6xx gpu coredump") +Signed-off-by: Connor Abbott +Patchwork: https://patchwork.freedesktop.org/patch/714270/ +Message-ID: <20260325-drm-msm-a650-debugbus-v1-1-dfbf358890a7@gmail.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 72c4bb360acd5..e9a23d471f374 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -361,7 +361,7 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + sizeof(*a6xx_state->debugbus)); + + if (a6xx_state->debugbus) { +- int i; ++ int i, j; + + for (i = 0; i < ARRAY_SIZE(a6xx_debugbus_blocks); i++) + a6xx_get_debugbus_block(gpu, +@@ -369,8 +369,6 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + &a6xx_debugbus_blocks[i], + &a6xx_state->debugbus[i]); + +- a6xx_state->nr_debugbus = ARRAY_SIZE(a6xx_debugbus_blocks); +- + /* + * GBIF has same debugbus as of other GPU blocks, fall back to + * default path if GPU uses GBIF, also GBIF uses exactly same +@@ -381,17 +379,19 @@ static void a6xx_get_debugbus_blocks(struct msm_gpu *gpu, + &a6xx_gbif_debugbus_block, + &a6xx_state->debugbus[i]); + +- a6xx_state->nr_debugbus += 1; ++ i++; + } + + + if (adreno_is_a650_family(to_adreno_gpu(gpu))) { +- for (i = 0; i < ARRAY_SIZE(a650_debugbus_blocks); i++) ++ for (j = 0; j < ARRAY_SIZE(a650_debugbus_blocks); i++, j++) + a6xx_get_debugbus_block(gpu, + a6xx_state, +- &a650_debugbus_blocks[i], ++ &a650_debugbus_blocks[j], + &a6xx_state->debugbus[i]); + } ++ ++ a6xx_state->nr_debugbus = i; + } + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-a6xx-fix-gpu-init-from-secure-world.patch b/queue-7.0/drm-msm-a6xx-fix-gpu-init-from-secure-world.patch new file mode 100644 index 0000000000..d90d5fb069 --- /dev/null +++ b/queue-7.0/drm-msm-a6xx-fix-gpu-init-from-secure-world.patch @@ -0,0 +1,264 @@ +From fab6df7fc704374c61e159e7607a9386d4eb3669 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:55 +0530 +Subject: drm/msm/a6xx: Fix gpu init from secure world + +From: Akhil P Oommen + +[ Upstream commit bb9b1d6e945ea90459bda1aac7e2aa7179119887 ] + +A7XX_GEN2 and newer GPUs requires initialization of few configurations +related to features/power from secure world. The SCM call to do this +should be triggered after GDSC and clocks are enabled. So, keep this +sequence to a6xx_gmu_resume instead of the probe. + +Also, simplify the error handling in a6xx_gmu_resume() using 'goto' +labels. + +Fixes: 14b27d5df3ea ("drm/msm/a7xx: Initialize a750 "software fuse"") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714664/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-6-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 93 ++++++++++++++++++++++----- + drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 2 + + drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 59 ----------------- + 3 files changed, 80 insertions(+), 74 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +index b41dbca1ebc63..1b44b9e21ad86 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +@@ -3,6 +3,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -1191,6 +1192,65 @@ static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu) + dev_pm_opp_put(gpu_opp); + } + ++static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu) ++{ ++ struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; ++ struct msm_gpu *gpu = &adreno_gpu->base; ++ struct a6xx_gmu *gmu = &a6xx_gpu->gmu; ++ u32 fuse_val; ++ int ret; ++ ++ if (test_bit(GMU_STATUS_SECURE_INIT, &gmu->status)) ++ return 0; ++ ++ if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { ++ /* ++ * Assume that if qcom scm isn't available, that whatever ++ * replacement allows writing the fuse register ourselves. ++ * Users of alternative firmware need to make sure this ++ * register is writeable or indicate that it's not somehow. ++ * Print a warning because if you mess this up you're about to ++ * crash horribly. ++ */ ++ if (!qcom_scm_is_available()) { ++ dev_warn_once(gpu->dev->dev, ++ "SCM is not available, poking fuse register\n"); ++ a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE, ++ A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING | ++ A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND | ++ A7XX_CX_MISC_SW_FUSE_VALUE_LPAC); ++ adreno_gpu->has_ray_tracing = true; ++ goto done; ++ } ++ ++ ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ | ++ QCOM_SCM_GPU_TSENSE_EN_REQ); ++ if (ret) { ++ dev_warn_once(gpu->dev->dev, ++ "SCM call failed\n"); ++ return ret; ++ } ++ ++ /* ++ * On A7XX_GEN3 and newer, raytracing may be disabled by the ++ * firmware, find out whether that's the case. The scm call ++ * above sets the fuse register. ++ */ ++ fuse_val = a6xx_llc_read(a6xx_gpu, ++ REG_A7XX_CX_MISC_SW_FUSE_VALUE); ++ adreno_gpu->has_ray_tracing = ++ !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING); ++ } else if (adreno_is_a740(adreno_gpu)) { ++ /* Raytracing is always enabled on a740 */ ++ adreno_gpu->has_ray_tracing = true; ++ } ++ ++done: ++ set_bit(GMU_STATUS_SECURE_INIT, &gmu->status); ++ return 0; ++} ++ ++ + int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) + { + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; +@@ -1219,11 +1279,12 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) + clk_set_rate(gmu->hub_clk, adreno_is_a740_family(adreno_gpu) ? + 200000000 : 150000000); + ret = clk_bulk_prepare_enable(gmu->nr_clocks, gmu->clocks); +- if (ret) { +- pm_runtime_put(gmu->gxpd); +- pm_runtime_put(gmu->dev); +- return ret; +- } ++ if (ret) ++ goto rpm_put; ++ ++ ret = a6xx_gmu_secure_init(a6xx_gpu); ++ if (ret) ++ goto disable_clk; + + /* Read the slice info on A8x GPUs */ + a8xx_gpu_get_slice_info(gpu); +@@ -1253,11 +1314,11 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) + + ret = a6xx_gmu_fw_start(gmu, status); + if (ret) +- goto out; ++ goto disable_irq; + + ret = a6xx_hfi_start(gmu, status); + if (ret) +- goto out; ++ goto disable_irq; + + /* + * Turn on the GMU firmware fault interrupt after we know the boot +@@ -1270,14 +1331,16 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) + /* Set the GPU to the current freq */ + a6xx_gmu_set_initial_freq(gpu, gmu); + +-out: +- /* On failure, shut down the GMU to leave it in a good state */ +- if (ret) { +- disable_irq(gmu->gmu_irq); +- a6xx_rpmh_stop(gmu); +- pm_runtime_put(gmu->gxpd); +- pm_runtime_put(gmu->dev); +- } ++ return 0; ++ ++disable_irq: ++ disable_irq(gmu->gmu_irq); ++ a6xx_rpmh_stop(gmu); ++disable_clk: ++ clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); ++rpm_put: ++ pm_runtime_put(gmu->gxpd); ++ pm_runtime_put(gmu->dev); + + return ret; + } +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +index 9f09daf45ab2b..0cd8ae1b4f5c8 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +@@ -130,6 +130,8 @@ struct a6xx_gmu { + #define GMU_STATUS_PDC_SLEEP 1 + /* To track Perfcounter OOB set status */ + #define GMU_STATUS_OOB_PERF_SET 2 ++/* To track whether secure world init was done */ ++#define GMU_STATUS_SECURE_INIT 3 + unsigned long status; + }; + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index 9327ecf94386e..0e8a48ca816dd 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -10,7 +10,6 @@ + + #include + #include +-#include + #include + #include + +@@ -2160,56 +2159,6 @@ static void a6xx_llc_slices_init(struct platform_device *pdev, + a6xx_gpu->llc_mmio = ERR_PTR(-EINVAL); + } + +-static int a7xx_cx_mem_init(struct a6xx_gpu *a6xx_gpu) +-{ +- struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; +- struct msm_gpu *gpu = &adreno_gpu->base; +- u32 fuse_val; +- int ret; +- +- if (adreno_is_a750(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { +- /* +- * Assume that if qcom scm isn't available, that whatever +- * replacement allows writing the fuse register ourselves. +- * Users of alternative firmware need to make sure this +- * register is writeable or indicate that it's not somehow. +- * Print a warning because if you mess this up you're about to +- * crash horribly. +- */ +- if (!qcom_scm_is_available()) { +- dev_warn_once(gpu->dev->dev, +- "SCM is not available, poking fuse register\n"); +- a6xx_llc_write(a6xx_gpu, REG_A7XX_CX_MISC_SW_FUSE_VALUE, +- A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING | +- A7XX_CX_MISC_SW_FUSE_VALUE_FASTBLEND | +- A7XX_CX_MISC_SW_FUSE_VALUE_LPAC); +- adreno_gpu->has_ray_tracing = true; +- return 0; +- } +- +- ret = qcom_scm_gpu_init_regs(QCOM_SCM_GPU_ALWAYS_EN_REQ | +- QCOM_SCM_GPU_TSENSE_EN_REQ); +- if (ret) +- return ret; +- +- /* +- * On A7XX_GEN3 and newer, raytracing may be disabled by the +- * firmware, find out whether that's the case. The scm call +- * above sets the fuse register. +- */ +- fuse_val = a6xx_llc_read(a6xx_gpu, +- REG_A7XX_CX_MISC_SW_FUSE_VALUE); +- adreno_gpu->has_ray_tracing = +- !!(fuse_val & A7XX_CX_MISC_SW_FUSE_VALUE_RAYTRACING); +- } else if (adreno_is_a740(adreno_gpu)) { +- /* Raytracing is always enabled on a740 */ +- adreno_gpu->has_ray_tracing = true; +- } +- +- return 0; +-} +- +- + #define GBIF_CLIENT_HALT_MASK BIT(0) + #define GBIF_ARB_HALT_MASK BIT(1) + #define VBIF_XIN_HALT_CTRL0_MASK GENMASK(3, 0) +@@ -2706,14 +2655,6 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) + return ERR_PTR(ret); + } + +- if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) { +- ret = a7xx_cx_mem_init(a6xx_gpu); +- if (ret) { +- a6xx_destroy(&(a6xx_gpu->base.base)); +- return ERR_PTR(ret); +- } +- } +- + adreno_gpu->uche_trap_base = 0x1fffffffff000ull; + + msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu, +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-a6xx-fix-hlsq-register-dumping.patch b/queue-7.0/drm-msm-a6xx-fix-hlsq-register-dumping.patch new file mode 100644 index 0000000000..b93c34a848 --- /dev/null +++ b/queue-7.0/drm-msm-a6xx-fix-hlsq-register-dumping.patch @@ -0,0 +1,39 @@ +From 2e2bca06928fadef0b7a676bd9242a7c6f81ef4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:40:42 -0700 +Subject: drm/msm/a6xx: Fix HLSQ register dumping + +From: Rob Clark + +[ Upstream commit c289a6db9ba6cb974f0317da142e4f665d589566 ] + +Fix the bitfield offset of HLSQ_READ_SEL state-type bitfield. Otherwise +we are always reading TP state when we wanted SP or HLSQ state. + +Reported-by: Connor Abbott +Suggested-by: Connor Abbott +Fixes: 1707add81551 ("drm/msm/a6xx: Add a6xx gpu state") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714236/ +Message-ID: <20260325184043.1259312-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index 2d56fe0a65b7e..72c4bb360acd5 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -1013,7 +1013,7 @@ static void a6xx_get_crashdumper_hlsq_registers(struct msm_gpu *gpu, + u64 out = dumper->iova + A6XX_CD_DATA_OFFSET; + int i, regcount = 0; + +- in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, regs->val1); ++ in += CRASHDUMP_WRITE(in, REG_A6XX_HLSQ_DBG_READ_SEL, (regs->val1 & 0xff) << 8); + + for (i = 0; i < regs->count; i += 2) { + u32 count = RANGE(regs->registers, i); +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-a6xx-switch-to-preemption-safe-ao-counter.patch b/queue-7.0/drm-msm-a6xx-switch-to-preemption-safe-ao-counter.patch new file mode 100644 index 0000000000..283c9160cb --- /dev/null +++ b/queue-7.0/drm-msm-a6xx-switch-to-preemption-safe-ao-counter.patch @@ -0,0 +1,84 @@ +From 0c4c0a8f9dec9b5064ba1d31c0478b1615eb6484 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:52 +0530 +Subject: drm/msm/a6xx: Switch to preemption safe AO counter + +From: Akhil P Oommen + +[ Upstream commit 0c59f258ffd4c9c2a6bd37d71a0ade1db8bc03b7 ] + +CP_ALWAYS_ON_COUNTER is not save-restored during preemption, so it won't +provide accurate data about the 'submit' when preemption is enabled. +Switch to CP_ALWAYS_ON_CONTEXT which is preemption safe. + +Fixes: e7ae83da4a28 ("drm/msm/a6xx: Implement preemption for a7xx targets") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714657/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-3-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index 4fe2b86e7a839..eeecde88e549f 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -347,7 +347,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + * GPU registers so we need to add 0x1a800 to the register value on A630 + * to get the right value from PM4. + */ +- get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER, ++ get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT, + rbmemptr_stats(ring, index, alwayson_start)); + + /* Invalidate CCU depth and color */ +@@ -388,7 +388,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + + get_stats_counter(ring, REG_A6XX_RBBM_PERFCTR_CP(0), + rbmemptr_stats(ring, index, cpcycles_end)); +- get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_COUNTER, ++ get_stats_counter(ring, REG_A6XX_CP_ALWAYS_ON_CONTEXT, + rbmemptr_stats(ring, index, alwayson_end)); + + /* Write the fence to the scratch register */ +@@ -457,7 +457,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring = submit->ring; +- u32 rbbm_perfctr_cp0, cp_always_on_counter; ++ u32 rbbm_perfctr_cp0, cp_always_on_context; + unsigned int i, ibs = 0; + + adreno_check_and_reenable_stall(adreno_gpu); +@@ -480,14 +480,14 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + + if (adreno_is_a8xx(adreno_gpu)) { + rbbm_perfctr_cp0 = REG_A8XX_RBBM_PERFCTR_CP(0); +- cp_always_on_counter = REG_A8XX_CP_ALWAYS_ON_COUNTER; ++ cp_always_on_context = REG_A8XX_CP_ALWAYS_ON_CONTEXT; + } else { + rbbm_perfctr_cp0 = REG_A7XX_RBBM_PERFCTR_CP(0); +- cp_always_on_counter = REG_A6XX_CP_ALWAYS_ON_COUNTER; ++ cp_always_on_context = REG_A6XX_CP_ALWAYS_ON_CONTEXT; + } + + get_stats_counter(ring, rbbm_perfctr_cp0, rbmemptr_stats(ring, index, cpcycles_start)); +- get_stats_counter(ring, cp_always_on_counter, rbmemptr_stats(ring, index, alwayson_start)); ++ get_stats_counter(ring, cp_always_on_context, rbmemptr_stats(ring, index, alwayson_start)); + + OUT_PKT7(ring, CP_THREAD_CONTROL, 1); + OUT_RING(ring, CP_SET_THREAD_BOTH); +@@ -535,7 +535,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + } + + get_stats_counter(ring, rbbm_perfctr_cp0, rbmemptr_stats(ring, index, cpcycles_end)); +- get_stats_counter(ring, cp_always_on_counter, rbmemptr_stats(ring, index, alwayson_end)); ++ get_stats_counter(ring, cp_always_on_context, rbmemptr_stats(ring, index, alwayson_end)); + + /* Write the fence to the scratch register */ + if (adreno_is_a8xx(adreno_gpu)) { +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch b/queue-7.0/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch new file mode 100644 index 0000000000..2123f3cc23 --- /dev/null +++ b/queue-7.0/drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch @@ -0,0 +1,72 @@ +From e9db6b11e697b8b1a473be351e8da105ecd71bd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:50 +0530 +Subject: drm/msm/a6xx: Use barriers while updating HFI Q headers + +From: Akhil P Oommen + +[ Upstream commit dc78b35d5ec09d1b0b8a937e6e640d2c5a030915 ] + +To avoid harmful compiler optimizations and IO reordering in the HW, use +barriers and READ/WRITE_ONCE helpers as necessary while accessing the HFI +queue index variables. + +Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714653/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-1-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_hfi.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +index 53cfdf4e6c346..4f5dbf46132ba 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +@@ -34,7 +34,7 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + struct a6xx_hfi_queue_header *header = queue->header; + u32 i, hdr, index = header->read_index; + +- if (header->read_index == header->write_index) { ++ if (header->read_index == READ_ONCE(header->write_index)) { + header->rx_request = 1; + return 0; + } +@@ -62,7 +62,10 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, + if (!gmu->legacy) + index = ALIGN(index, 4) % header->size; + +- header->read_index = index; ++ /* Ensure all memory operations are complete before updating the read index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->read_index, index); + return HFI_HEADER_SIZE(hdr); + } + +@@ -74,7 +77,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + + spin_lock(&queue->lock); + +- space = CIRC_SPACE(header->write_index, header->read_index, ++ space = CIRC_SPACE(header->write_index, READ_ONCE(header->read_index), + header->size); + if (space < dwords) { + header->dropped++; +@@ -95,7 +98,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, + queue->data[index] = 0xfafafafa; + } + +- header->write_index = index; ++ /* Ensure all memory operations are complete before updating the write index */ ++ dma_mb(); ++ ++ WRITE_ONCE(header->write_index, index); + spin_unlock(&queue->lock); + + gmu_write(gmu, REG_A6XX_GMU_HOST2GMU_INTR_SET, 0x01); +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-a8xx-fix-the-ticks-used-in-submit-traces.patch b/queue-7.0/drm-msm-a8xx-fix-the-ticks-used-in-submit-traces.patch new file mode 100644 index 0000000000..8782150cb5 --- /dev/null +++ b/queue-7.0/drm-msm-a8xx-fix-the-ticks-used-in-submit-traces.patch @@ -0,0 +1,229 @@ +From 5c3c70d97c380236b1d4974d2f6cee9aaadfa217 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:51 +0530 +Subject: drm/msm/a8xx: Fix the ticks used in submit traces + +From: Akhil P Oommen + +[ Upstream commit cfc8b48649e159ff394fb4b7b08e5006c5c1c234 ] + +GMU_ALWAYS_ON_COUNTER_* registers got moved in A8x, but currently, A6x +register offsets are used in the submit traces instead of A8x offsets. +To fix this, refactor a bit and use adreno_gpu->funcs->get_timestamp() +everywhere. + +While we are at it, update a8xx_gmu_get_timestamp() to use the GMU AO +counter. + +Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support") +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714655/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-2-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 6 ++--- + drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 6 ++--- + drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 23 ++++++------------- + drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 2 +- + drivers/gpu/drm/msm/adreno/a8xx_gpu.c | 20 +++++++--------- + drivers/gpu/drm/msm/adreno/adreno_gpu.c | 6 ++--- + drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 +- + .../gpu/drm/msm/registers/adreno/a6xx_gmu.xml | 6 +++-- + 8 files changed, 27 insertions(+), 44 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +index 8464d89e37f31..e6ab731f8e9a3 100644 +--- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +@@ -604,11 +604,9 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) { + return 0; + } + +-static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) ++static u64 a4xx_get_timestamp(struct msm_gpu *gpu) + { +- *value = gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO); +- +- return 0; ++ return gpu_read64(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO); + } + + static u64 a4xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate) +diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +index ef9fd6171af71..e44302251de56 100644 +--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +@@ -1435,11 +1435,9 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu) + return 0; + } + +-static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) ++static u64 a5xx_get_timestamp(struct msm_gpu *gpu) + { +- *value = gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO); +- +- return 0; ++ return gpu_read64(gpu, REG_A5XX_RBBM_ALWAYSON_COUNTER_LO); + } + + struct a5xx_crashdumper { +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index f17bb5e78e0b9..4fe2b86e7a839 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -16,8 +16,10 @@ + + #define GPU_PAS_ID 13 + +-static u64 read_gmu_ao_counter(struct a6xx_gpu *a6xx_gpu) ++static u64 a6xx_gmu_get_timestamp(struct msm_gpu *gpu) + { ++ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); ++ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + u64 count_hi, count_lo, temp; + + do { +@@ -404,7 +406,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence))); + OUT_RING(ring, submit->seqno); + +- trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu)); ++ trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu)); + + a6xx_flush(gpu, ring); + } +@@ -614,7 +616,7 @@ static void a7xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) + } + + +- trace_msm_gpu_submit_flush(submit, read_gmu_ao_counter(a6xx_gpu)); ++ trace_msm_gpu_submit_flush(submit, adreno_gpu->funcs->get_timestamp(gpu)); + + a6xx_flush(gpu, ring); + +@@ -2414,20 +2416,9 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu) + return 0; + } + +-static int a6xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value) ++static u64 a6xx_get_timestamp(struct msm_gpu *gpu) + { +- struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); +- struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); +- +- *value = read_gmu_ao_counter(a6xx_gpu); +- +- return 0; +-} +- +-static int a6xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) +-{ +- *value = gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER); +- return 0; ++ return gpu_read64(gpu, REG_A6XX_CP_ALWAYS_ON_COUNTER); + } + + static struct msm_ringbuffer *a6xx_active_ring(struct msm_gpu *gpu) +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +index 4eaa047112460..a4434a6a56dd8 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +@@ -320,7 +320,7 @@ int a6xx_zap_shader_init(struct msm_gpu *gpu); + void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_off); + int a8xx_fault_handler(void *arg, unsigned long iova, int flags, void *data); + void a8xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring); +-int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value); ++u64 a8xx_gmu_get_timestamp(struct msm_gpu *gpu); + u64 a8xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate); + int a8xx_gpu_feature_probe(struct msm_gpu *gpu); + void a8xx_gpu_get_slice_info(struct msm_gpu *gpu); +diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c +index b1887e0cf6983..840af9c4d718c 100644 +--- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c +@@ -1174,23 +1174,19 @@ void a8xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu, bool gx_ + gpu_write(gpu, REG_A6XX_GBIF_HALT, 0x0); + } + +-int a8xx_gmu_get_timestamp(struct msm_gpu *gpu, uint64_t *value) ++u64 a8xx_gmu_get_timestamp(struct msm_gpu *gpu) + { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); ++ u64 count_hi, count_lo, temp; + +- mutex_lock(&a6xx_gpu->gmu.lock); +- +- /* Force the GPU power on so we can read this register */ +- a6xx_gmu_set_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET); +- +- *value = gpu_read64(gpu, REG_A8XX_CP_ALWAYS_ON_COUNTER); +- +- a6xx_gmu_clear_oob(&a6xx_gpu->gmu, GMU_OOB_PERFCOUNTER_SET); +- +- mutex_unlock(&a6xx_gpu->gmu.lock); ++ do { ++ count_hi = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H); ++ count_lo = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_L); ++ temp = gmu_read(&a6xx_gpu->gmu, REG_A8XX_GMU_ALWAYS_ON_COUNTER_H); ++ } while (unlikely(count_hi != temp)); + +- return 0; ++ return (count_hi << 32) | count_lo; + } + + u64 a8xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate) +diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +index d5fe6f6f0decc..785e99fb5bd5d 100644 +--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c +@@ -391,13 +391,11 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_context *ctx, + return 0; + case MSM_PARAM_TIMESTAMP: + if (adreno_gpu->funcs->get_timestamp) { +- int ret; +- + pm_runtime_get_sync(&gpu->pdev->dev); +- ret = adreno_gpu->funcs->get_timestamp(gpu, value); ++ *value = adreno_gpu->funcs->get_timestamp(gpu); + pm_runtime_put_autosuspend(&gpu->pdev->dev); + +- return ret; ++ return 0; + } + return -EINVAL; + case MSM_PARAM_PRIORITIES: +diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h +index 1d0145f8b3ecb..c08725ed54c4f 100644 +--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h ++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h +@@ -79,7 +79,7 @@ struct adreno_gpu; + struct adreno_gpu_funcs { + struct msm_gpu_funcs base; + struct msm_gpu *(*init)(struct drm_device *dev); +- int (*get_timestamp)(struct msm_gpu *gpu, uint64_t *value); ++ u64 (*get_timestamp)(struct msm_gpu *gpu); + void (*bus_halt)(struct adreno_gpu *adreno_gpu, bool gx_off); + int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data); + }; +diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml +index c4e00b1263cda..33404eb18fd02 100644 +--- a/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml ++++ b/drivers/gpu/drm/msm/registers/adreno/a6xx_gmu.xml +@@ -141,8 +141,10 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> + + + +- +- ++ ++ ++ ++ + + + +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-add-missing-module_device_id-definitions.patch b/queue-7.0/drm-msm-add-missing-module_device_id-definitions.patch new file mode 100644 index 0000000000..9181f17c1b --- /dev/null +++ b/queue-7.0/drm-msm-add-missing-module_device_id-definitions.patch @@ -0,0 +1,96 @@ +From afd8111cbd31114606bcae3227bbee578dac8541 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 19:20:37 +0200 +Subject: drm/msm: add missing MODULE_DEVICE_ID definitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dmitry Baryshkov + +[ Upstream commit b21e85400ce763f2c6ad913e03fea5cadc323c13 ] + +The drm/msm module bundles several drivers, each of them having a +separate OF match table, however only MDSS (subsystem), KMS devices and +GPU have corresponding MODULE_DEVICE_ID tables. + +Add MODULE_DEVICE_ID to the display-related driver and to all other +drivers in this module, simplifying userspace job. + +Fixes: 060530f1ea67 ("drm/msm: use componentised device support") +Reported-by: Loïc Minier +Patchwork: https://patchwork.freedesktop.org/patch/707960/ +Link: https://lore.kernel.org/r/20260228-msm-device-id-v2-1-24b085919444@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dp/dp_display.c | 1 + + drivers/gpu/drm/msm/dsi/dsi.c | 1 + + drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 1 + + drivers/gpu/drm/msm/hdmi/hdmi.c | 1 + + drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 1 + + 5 files changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c +index 476848bf8cd16..d2124d6254855 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.c ++++ b/drivers/gpu/drm/msm/dp/dp_display.c +@@ -210,6 +210,7 @@ static const struct of_device_id msm_dp_dt_match[] = { + { .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 }, + {} + }; ++MODULE_DEVICE_TABLE(of, msm_dp_dt_match); + + static struct msm_dp_display_private *dev_get_dp_display_private(struct device *dev) + { +diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c +index d8bb40ef820e2..3c9f01ed62713 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi.c ++++ b/drivers/gpu/drm/msm/dsi/dsi.c +@@ -198,6 +198,7 @@ static const struct of_device_id dt_match[] = { + { .compatible = "qcom,dsi-ctrl-6g-qcm2290" }, + {} + }; ++MODULE_DEVICE_TABLE(of, dt_match); + + static const struct dev_pm_ops dsi_pm_ops = { + SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL) +diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +index 7937266de1d28..c59375aaae197 100644 +--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c ++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +@@ -582,6 +582,7 @@ static const struct of_device_id dsi_phy_dt_match[] = { + #endif + {} + }; ++MODULE_DEVICE_TABLE(of, dsi_phy_dt_match); + + /* + * Currently, we only support one SoC for each PHY type. When we have multiple +diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c +index 5afac09c0d334..d5ef5089c9e9c 100644 +--- a/drivers/gpu/drm/msm/hdmi/hdmi.c ++++ b/drivers/gpu/drm/msm/hdmi/hdmi.c +@@ -441,6 +441,7 @@ static const struct of_device_id msm_hdmi_dt_match[] = { + { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8960_config }, + {} + }; ++MODULE_DEVICE_TABLE(of, msm_hdmi_dt_match); + + static struct platform_driver msm_hdmi_driver = { + .probe = msm_hdmi_dev_probe, +diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +index 667573f1db7c6..f726555bb6810 100644 +--- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c ++++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +@@ -204,6 +204,7 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = { + .data = &msm_hdmi_phy_8998_cfg }, + {} + }; ++MODULE_DEVICE_TABLE(of, msm_hdmi_phy_dt_match); + + static struct platform_driver msm_hdmi_phy_platform_driver = { + .probe = msm_hdmi_phy_probe, +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-adreno-implement-gx_is_on-for-a8x.patch b/queue-7.0/drm-msm-adreno-implement-gx_is_on-for-a8x.patch new file mode 100644 index 0000000000..054ce83c63 --- /dev/null +++ b/queue-7.0/drm-msm-adreno-implement-gx_is_on-for-a8x.patch @@ -0,0 +1,198 @@ +From b8d240d372469620ff12a127a28119507bbb9586 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 05:43:54 +0530 +Subject: drm/msm/adreno: Implement gx_is_on() for A8x + +From: Akhil P Oommen + +[ Upstream commit ae25e6e9cdcac4cfef102b9d6de8bff13ca4d13b ] + +A8x has a diverged enough for a separate implementation of gx_is_on() +check. Add that and move them to the adreno func table. + +Fixes: 288a93200892 ("drm/msm/adreno: Introduce A8x GPU Support") +Reviewed-by: Konrad Dybcio +Signed-off-by: Akhil P Oommen +Patchwork: https://patchwork.freedesktop.org/patch/714661/ +Message-ID: <20260327-a8xx-gpu-batch2-v2-5-2b53c38d2101@oss.qualcomm.com> +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 42 +++++++++++++++++++-- + drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 5 ++- + drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 6 ++- + drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c | 4 +- + drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 + + 5 files changed, 50 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +index 690d3e53e2738..b41dbca1ebc63 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +@@ -91,10 +91,10 @@ bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu) + } + + /* Check to see if the GX rail is still powered */ +-bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu) ++bool a6xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu) + { +- struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); +- struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; ++ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); ++ struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + u32 val; + + /* This can be called from gpu state code so make sure GMU is valid */ +@@ -117,6 +117,40 @@ bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu) + A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF)); + } + ++bool a7xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu) ++{ ++ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); ++ struct a6xx_gmu *gmu = &a6xx_gpu->gmu; ++ u32 val; ++ ++ /* This can be called from gpu state code so make sure GMU is valid */ ++ if (!gmu->initialized) ++ return false; ++ ++ val = gmu_read(gmu, REG_A6XX_GMU_SPTPRAC_PWR_CLK_STATUS); ++ ++ return !(val & ++ (A7XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF | ++ A7XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF)); ++} ++ ++bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu) ++{ ++ struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); ++ struct a6xx_gmu *gmu = &a6xx_gpu->gmu; ++ u32 val; ++ ++ /* This can be called from gpu state code so make sure GMU is valid */ ++ if (!gmu->initialized) ++ return false; ++ ++ val = gmu_read(gmu, REG_A8XX_GMU_PWR_CLK_STATUS); ++ ++ return !(val & ++ (A8XX_GMU_PWR_CLK_STATUS_GX_HM_GDSC_POWER_OFF | ++ A8XX_GMU_PWR_CLK_STATUS_GX_HM_CLK_OFF)); ++} ++ + void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp, + bool suspended) + { +@@ -240,7 +274,7 @@ static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu) + + if (val == local) { + if (gmu->idle_level != GMU_IDLE_STATE_IFPC || +- !a6xx_gmu_gx_is_on(gmu)) ++ !adreno_gpu->funcs->gx_is_on(adreno_gpu)) + return true; + } + +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +index 2af074c8e8cfa..9f09daf45ab2b 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +@@ -10,6 +10,7 @@ + #include + #include + #include "msm_drv.h" ++#include "adreno_gpu.h" + #include "a6xx_hfi.h" + + struct a6xx_gmu_bo { +@@ -231,7 +232,9 @@ void a6xx_hfi_stop(struct a6xx_gmu *gmu); + int a6xx_hfi_send_prep_slumber(struct a6xx_gmu *gmu); + int a6xx_hfi_set_freq(struct a6xx_gmu *gmu, u32 perf_index, u32 bw_index); + +-bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu); ++bool a6xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu); ++bool a7xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu); ++bool a8xx_gmu_gx_is_on(struct adreno_gpu *adreno_gpu); + bool a6xx_gmu_sptprac_is_on(struct a6xx_gmu *gmu); + void a6xx_sptprac_disable(struct a6xx_gmu *gmu); + int a6xx_sptprac_enable(struct a6xx_gmu *gmu); +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index 4e0d67e3acb7e..9327ecf94386e 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -1643,7 +1643,7 @@ static void a6xx_recover(struct msm_gpu *gpu) + + adreno_dump_info(gpu); + +- if (a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) { ++ if (adreno_gpu->funcs->gx_is_on(adreno_gpu)) { + /* Sometimes crashstate capture is skipped, so SQE should be halted here again */ + gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3); + +@@ -2763,6 +2763,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = { + .get_timestamp = a6xx_gmu_get_timestamp, + .bus_halt = a6xx_bus_clear_pending_transactions, + .mmu_fault_handler = a6xx_fault_handler, ++ .gx_is_on = a6xx_gmu_gx_is_on, + }; + + const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = { +@@ -2795,6 +2796,7 @@ const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = { + .get_timestamp = a6xx_get_timestamp, + .bus_halt = a6xx_bus_clear_pending_transactions, + .mmu_fault_handler = a6xx_fault_handler, ++ .gx_is_on = a6xx_gmu_gx_is_on, + }; + + const struct adreno_gpu_funcs a7xx_gpu_funcs = { +@@ -2829,6 +2831,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = { + .get_timestamp = a6xx_gmu_get_timestamp, + .bus_halt = a6xx_bus_clear_pending_transactions, + .mmu_fault_handler = a6xx_fault_handler, ++ .gx_is_on = a7xx_gmu_gx_is_on, + }; + + const struct adreno_gpu_funcs a8xx_gpu_funcs = { +@@ -2856,4 +2859,5 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = { + .get_timestamp = a8xx_gmu_get_timestamp, + .bus_halt = a8xx_bus_clear_pending_transactions, + .mmu_fault_handler = a8xx_fault_handler, ++ .gx_is_on = a8xx_gmu_gx_is_on, + }; +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +index e9a23d471f374..791623ddb67c9 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +@@ -1251,7 +1251,7 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu, + _a6xx_get_gmu_registers(gpu, a6xx_state, &a6xx_gpucc_reg, + &a6xx_state->gmu_registers[2], false); + +- if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) ++ if (!adreno_gpu->funcs->gx_is_on(adreno_gpu)) + return; + + /* Set the fence to ALLOW mode so we can access the registers */ +@@ -1607,7 +1607,7 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu) + } + + /* If GX isn't on the rest of the data isn't going to be accessible */ +- if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) ++ if (!adreno_gpu->funcs->gx_is_on(adreno_gpu)) + return &a6xx_state->base; + + /* Halt SQE first */ +diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h +index c08725ed54c4f..29097e6b42535 100644 +--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h ++++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h +@@ -82,6 +82,7 @@ struct adreno_gpu_funcs { + u64 (*get_timestamp)(struct msm_gpu *gpu); + void (*bus_halt)(struct adreno_gpu *adreno_gpu, bool gx_off); + int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data); ++ bool (*gx_is_on)(struct adreno_gpu *adreno_gpu); + }; + + struct adreno_reglist { +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-dpu-don-t-try-using-2-lms-if-only-one-dsc-is.patch b/queue-7.0/drm-msm-dpu-don-t-try-using-2-lms-if-only-one-dsc-is.patch new file mode 100644 index 0000000000..4f8730cde5 --- /dev/null +++ b/queue-7.0/drm-msm-dpu-don-t-try-using-2-lms-if-only-one-dsc-is.patch @@ -0,0 +1,42 @@ +From 0cc030c091d4195e3d5e12ceab7c7175adaf9c08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 17:30:05 +0200 +Subject: drm/msm/dpu: don't try using 2 LMs if only one DSC is available + +From: Dmitry Baryshkov + +[ Upstream commit b9699dd862760e642807a2bc226e4d127e35dcb7 ] + +Current topology code will try using 2 LMs with just one DSC, which +breaks cases like SC7280 / Fairphone5. Forbid using 2 LMs split in such +a case. + +Fixes: 1ce69c265a53 ("drm/msm/dpu: move resource allocation to CRTC") +Reported-by: Luca Weiss +Closes: https://lore.kernel.org/r/DH1IKLU0YZYU.2SW4WYO7H3H4R@fairphone.com/ +Tested-by: Luca Weiss # qcm6490-fairphone-fp5 +Patchwork: https://patchwork.freedesktop.org/patch/712386/ +Link: https://lore.kernel.org/r/20260317-fix-3d-dsc-v1-1-88b54f62f659@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +index 0f4921b1a8922..cbb7caa194c1e 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +@@ -1410,7 +1410,8 @@ static struct msm_display_topology dpu_crtc_get_topology( + topology.num_lm = 2; + else if (topology.num_dsc == 2) + topology.num_lm = 2; +- else if (dpu_kms->catalog->caps->has_3d_merge) ++ else if (dpu_kms->catalog->caps->has_3d_merge && ++ topology.num_dsc == 0) + topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; + else + topology.num_lm = 1; +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-dpu-drop-intf_0-on-msm8953.patch b/queue-7.0/drm-msm-dpu-drop-intf_0-on-msm8953.patch new file mode 100644 index 0000000000..70e2fd79a9 --- /dev/null +++ b/queue-7.0/drm-msm-dpu-drop-intf_0-on-msm8953.patch @@ -0,0 +1,43 @@ +From c6db02250273a4d5d3b938223a1e980f292c2ee5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 07:35:44 +0200 +Subject: drm/msm/dpu: drop INTF_0 on MSM8953 + +From: Dmitry Baryshkov + +[ Upstream commit 7090420420d5a7d7c88b21d16962f2a230be3ef3 ] + +There is no INTF_0 on MSM8953. Currently catalog lists dummy INTF_NONE +entry for it. Drop it from the catalog. + +Fixes: 7a6109ce1c2c ("drm/msm/dpu: Add support for MSM8953") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/713990/ +Link: https://lore.kernel.org/r/20260325-drop-8953-intf-v1-1-d80e214a1a75@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h +index b44d02b48418f..2162ff917b0f8 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h +@@ -121,13 +121,6 @@ static const struct dpu_dspp_cfg msm8953_dspp[] = { + + static const struct dpu_intf_cfg msm8953_intf[] = { + { +- .name = "intf_0", .id = INTF_0, +- .base = 0x6a000, .len = 0x268, +- .type = INTF_NONE, +- .prog_fetch_lines_worst_case = 14, +- .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), +- .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), +- }, { + .name = "intf_1", .id = INTF_1, + .base = 0x6a800, .len = 0x268, + .type = INTF_DSI, +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch b/queue-7.0/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch new file mode 100644 index 0000000000..b71bdf3348 --- /dev/null +++ b/queue-7.0/drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch @@ -0,0 +1,58 @@ +From fd77fd128a68d90c2f89d3e570bafebf2cee3aea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 14:37:20 +0800 +Subject: drm/msm/dpu: fix mismatch between power and frequency + +From: Yuanjie Yang + +[ Upstream commit bc1dccc518cc5ab5140fba06c27e7188e0ed342b ] + +During DPU runtime suspend, calling dev_pm_opp_set_rate(dev, 0) drops +the MMCX rail to MIN_SVS while the core clock frequency remains at its +original (highest) rate. When runtime resume re-enables the clock, this +may result in a mismatch between the rail voltage and the clock rate. + +For example, in the DPU bind path, the sequence could be: + cpu0: dev_sync_state -> rpmhpd_sync_state + cpu1: dpu_kms_hw_init +timeline 0 ------------------------------------------------> t + +After rpmhpd_sync_state, the voltage performance is no longer guaranteed +to stay at the highest level. During dpu_kms_hw_init, calling +dev_pm_opp_set_rate(dev, 0) drops the voltage, causing the MMCX rail to +fall to MIN_SVS while the core clock is still at its maximum frequency. +When the power is re-enabled, only the clock is enabled, leading to a +situation where the MMCX rail is at MIN_SVS but the core clock is at its +highest rate. In this state, the rail cannot sustain the clock rate, +which may cause instability or system crash. + +Remove the call to dev_pm_opp_set_rate(dev, 0) from dpu_runtime_suspend +to ensure the correct vote is restored when DPU resumes. + +Fixes: b0530eb11913 ("drm/msm/dpu: Use OPP API to set clk/perf state") +Signed-off-by: Yuanjie Yang +Reviewed-by: Konrad Dybcio +Patchwork: https://patchwork.freedesktop.org/patch/710077/ +Link: https://lore.kernel.org/r/20260309063720.13572-1-yuanjie.yang@oss.qualcomm.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +index 61d7e65469b3a..014b2c504eda6 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +@@ -1461,8 +1461,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); + +- /* Drop the performance state vote */ +- dev_pm_opp_set_rate(dev, 0); + clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks); + + for (i = 0; i < dpu_kms->num_paths; i++) +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-dsi-add-the-missing-parameter-description.patch b/queue-7.0/drm-msm-dsi-add-the-missing-parameter-description.patch new file mode 100644 index 0000000000..5fe22545fc --- /dev/null +++ b/queue-7.0/drm-msm-dsi-add-the-missing-parameter-description.patch @@ -0,0 +1,40 @@ +From 2c88ca2c4f3b2cc6b5a0a23d2bd7ff4bd6b40e0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 18:02:53 +0800 +Subject: drm/msm/dsi: add the missing parameter description + +From: Pengyu Luo + +[ Upstream commit 958adefc4c0fddee3b12269da5dd7cb49bac953f ] + +Add a description for is_bonded_dsi in dsi_adjust_pclk_for_compression +to match the existing kernel-doc comment. + +Fixes: e4eb11b34d6c ("drm/msm/dsi: fix pclk rate calculation for bonded dsi") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202603080314.XeqyRZ7A-lkp@intel.com/ +Signed-off-by: Pengyu Luo +Reviewed-by: Dmitry Baryshkov +Patchwork: https://patchwork.freedesktop.org/patch/710112/ +Link: https://lore.kernel.org/r/20260309100254.877801-1-mitltlatltl@gmail.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index db6da99375a18..6cb634590e7a7 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -569,6 +569,7 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) + * dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case + * @mode: The selected mode for the DSI output + * @dsc: DRM DSC configuration for this DSI output ++ * @is_bonded_dsi: True if two DSI controllers are bonded + * + * Adjust the pclk rate by calculating a new hdisplay proportional to + * the compression ratio such that: +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-dsi-fix-bits_per_pclk.patch b/queue-7.0/drm-msm-dsi-fix-bits_per_pclk.patch new file mode 100644 index 0000000000..ed389cc515 --- /dev/null +++ b/queue-7.0/drm-msm-dsi-fix-bits_per_pclk.patch @@ -0,0 +1,39 @@ +From 84c663b478b58cecf287f7e6dba4fd3497788a8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:12:48 +0800 +Subject: drm/msm/dsi: fix bits_per_pclk + +From: Pengyu Luo + +[ Upstream commit 2d51cfb77daa30b10bc68c403f8ace35783d2922 ] + +mipi_dsi_pixel_format_to_bpp return dst bpp not src bpp, dst bpp may +not be the uncompressed data size. use src bpc * 3 to get src bpp, +this aligns with pclk rate calculation. + +Fixes: ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when programming dsi registers") +Signed-off-by: Pengyu Luo +Patchwork: https://patchwork.freedesktop.org/patch/709916/ +Link: https://lore.kernel.org/r/20260307111250.105772-1-mitltlatltl@gmail.com +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 6cb634590e7a7..3efcc3f6c381c 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -1048,7 +1048,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + */ + h_total -= hdisplay; + if (wide_bus_enabled) +- bits_per_pclk = mipi_dsi_pixel_format_to_bpp(msm_host->format); ++ bits_per_pclk = dsc->bits_per_component * 3; + else + bits_per_pclk = 24; + +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch b/queue-7.0/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch new file mode 100644 index 0000000000..8b22559e8a --- /dev/null +++ b/queue-7.0/drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch @@ -0,0 +1,61 @@ +From 75e765b83f3b48b8e4335218339aa3e3aa5a0523 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:12:49 +0800 +Subject: drm/msm/dsi: fix hdisplay calculation for CMD mode panel + +From: Pengyu Luo + +[ Upstream commit 82159db4371f5cef56444ebd0b8f96e2a6d709ff ] + +Commit ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when +programming dsi registers") incorrecly broke hdisplay calculation for +CMD mode by specifying incorrect number of bytes per transfer, fix it. + +Fixes: ac47870fd795 ("drm/msm/dsi: fix hdisplay calculation when programming dsi registers") +Signed-off-by: Pengyu Luo +Patchwork: https://patchwork.freedesktop.org/patch/709917/ +Link: https://lore.kernel.org/r/20260307111250.105772-2-mitltlatltl@gmail.com +[DB: fixed commit message] +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_host.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c +index 3efcc3f6c381c..1c0841a1c1013 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_host.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_host.c +@@ -1034,8 +1034,9 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + /* + * DPU sends 3 bytes per pclk cycle to DSI. If widebus is + * enabled, MDP always sends out 48-bit compressed data per +- * pclk and on average, DSI consumes an amount of compressed +- * data equivalent to the uncompressed pixel depth per pclk. ++ * pclk and on average, for video mode, DSI consumes only an ++ * amount of compressed data equivalent to the uncompressed ++ * pixel depth per pclk. + * + * Calculate the number of pclks needed to transmit one line of + * the compressed data. +@@ -1047,10 +1048,14 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) + * unused anyway. + */ + h_total -= hdisplay; +- if (wide_bus_enabled) +- bits_per_pclk = dsc->bits_per_component * 3; +- else ++ if (wide_bus_enabled) { ++ if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) ++ bits_per_pclk = dsc->bits_per_component * 3; ++ else ++ bits_per_pclk = 48; ++ } else { + bits_per_pclk = 24; ++ } + + hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc) * 8, bits_per_pclk); + +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch b/queue-7.0/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch new file mode 100644 index 0000000000..c0436da091 --- /dev/null +++ b/queue-7.0/drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch @@ -0,0 +1,62 @@ +From 3980e6b3382d29ae13beef47edddf6c0842ab205 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 11:48:27 +0000 +Subject: drm/msm/dsi: rename MSM8998 DSI version from V2_2_0 to V2_0_0 + +From: Alexander Koskovich + +[ Upstream commit 913a709dea0eff9c7b2e9470f8c8594b9a0114ab ] + +The MSM8998 DSI controller is v2.0.0 as stated in commit 7b8c9e203039 +("drm/msm/dsi: Add support for MSM8998 DSI controller"). The value was +always correct just the name was wrong. + +Rename and reorder to maintain version sorting. + +Fixes: 7b8c9e203039 ("drm/msm/dsi: Add support for MSM8998 DSI controller") +Reviewed-by: Konrad Dybcio +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Alexander Koskovich +Patchwork: https://patchwork.freedesktop.org/patch/713717/ +Link: https://lore.kernel.org/r/20260324-dsi-rgb101010-support-v5-3-ff6afc904115@pm.me +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dsi/dsi_cfg.c | 4 ++-- + drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +index bd3c51c350e73..da3fe68244952 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c +@@ -317,10 +317,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { + &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_2, + &msm8976_dsi_cfg, &msm_dsi_6g_host_ops}, ++ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_0_0, ++ &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_1_0, + &sdm660_dsi_cfg, &msm_dsi_6g_v2_host_ops}, +- {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_0, +- &msm8998_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_3_0, +diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +index 5dc812028bd54..ccf06679608e0 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h ++++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h +@@ -19,8 +19,8 @@ + #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 + #define MSM_DSI_6G_VER_MINOR_V1_4_1 0x10040001 + #define MSM_DSI_6G_VER_MINOR_V1_4_2 0x10040002 ++#define MSM_DSI_6G_VER_MINOR_V2_0_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_1_0 0x20010000 +-#define MSM_DSI_6G_VER_MINOR_V2_2_0 0x20000000 + #define MSM_DSI_6G_VER_MINOR_V2_2_1 0x20020001 + #define MSM_DSI_6G_VER_MINOR_V2_3_0 0x20030000 + #define MSM_DSI_6G_VER_MINOR_V2_3_1 0x20030001 +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-fix-vm_bind-unmap-locking.patch b/queue-7.0/drm-msm-fix-vm_bind-unmap-locking.patch new file mode 100644 index 0000000000..48c049d545 --- /dev/null +++ b/queue-7.0/drm-msm-fix-vm_bind-unmap-locking.patch @@ -0,0 +1,42 @@ +From d1743dd3408706a72b4a109fc612650fb4ab9a2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:05:18 -0700 +Subject: drm/msm: Fix VM_BIND UNMAP locking + +From: Rob Clark + +[ Upstream commit 85042c2cd970a6b0e686329387096fe19989ae62 ] + +Wrong argument meant that the objs involved in UNMAP ops were not always +getting locked. + +Since _NO_SHARE objs share a common resv with the VM (which is always +locked) this would only show up with non-_NO_SHARE BOs. + +Reported-by: Victoria Brekenfeld +Fixes: 2e6a8a1fe2b2 ("drm/msm: Add VM_BIND ioctl") +Closes: https://gitlab.freedesktop.org/drm/msm/-/issues/94 +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/713898/ +Message-ID: <20260324220519.1221471-2-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem_vma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c +index 1c2f486302bcd..9e3632019bc92 100644 +--- a/drivers/gpu/drm/msm/msm_gem_vma.c ++++ b/drivers/gpu/drm/msm/msm_gem_vma.c +@@ -1245,7 +1245,7 @@ vm_bind_job_lock_objects(struct msm_vm_bind_job *job, struct drm_exec *exec) + case MSM_VM_BIND_OP_UNMAP: + ret = drm_gpuvm_sm_unmap_exec_lock(job->vm, exec, + op->iova, +- op->obj_offset); ++ op->range); + break; + case MSM_VM_BIND_OP_MAP: + case MSM_VM_BIND_OP_MAP_NULL: { +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-reject-fb-creation-from-_no_share-objs.patch b/queue-7.0/drm-msm-reject-fb-creation-from-_no_share-objs.patch new file mode 100644 index 0000000000..d584fd3c0c --- /dev/null +++ b/queue-7.0/drm-msm-reject-fb-creation-from-_no_share-objs.patch @@ -0,0 +1,42 @@ +From af4b4664f6e0164939ed13e745ac5a6e342f3fc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:59:26 -0700 +Subject: drm/msm: Reject fb creation from _NO_SHARE objs + +From: Rob Clark + +[ Upstream commit cf50ccdb765b3a6f1cd8e75642b0439fea0263a5 ] + +It would be an error to map these into kms->vm. So reject this as early +as possible, when creating an fb. + +Fixes: b58e12a66e47 ("drm/msm: Add _NO_SHARE flag") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/714264/ +Message-ID: <20260325185926.1265661-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_fb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c +index b3fdb83202ab8..9b681e144c07a 100644 +--- a/drivers/gpu/drm/msm/msm_fb.c ++++ b/drivers/gpu/drm/msm/msm_fb.c +@@ -219,7 +219,12 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, + + mode_cmd->offsets[i]; + + if (bos[i]->size < min_size) { +- ret = -EINVAL; ++ ret = UERR(EINVAL, dev, "plane %d too small", i); ++ goto fail; ++ } ++ ++ if (to_msm_bo(bos[i])->flags & MSM_BO_NO_SHARE) { ++ ret = UERR(EINVAL, dev, "Cannot map _NO_SHARE to kms vm"); + goto fail; + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-shrinker-fix-can_block-logic.patch b/queue-7.0/drm-msm-shrinker-fix-can_block-logic.patch new file mode 100644 index 0000000000..e285645f86 --- /dev/null +++ b/queue-7.0/drm-msm-shrinker-fix-can_block-logic.patch @@ -0,0 +1,44 @@ +From 839ea6d81c4e83106774fed3df8838e89a8d21f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:41:05 -0700 +Subject: drm/msm/shrinker: Fix can_block() logic + +From: Rob Clark + +[ Upstream commit df0f439e3926817cf577ca6272aad68468ff7624 ] + +The intention here was to allow blocking if DIRECT_RECLAIM or if called +from kswapd and KSWAPD_RECLAIM is set. + +Reported by Claude code review: https://lore.gitlab.freedesktop.org/drm-ai-reviews/review-patch9-20260309151119.290217-10-boris.brezillon@collabora.com/ on a panthor patch which had copied similar logic. + +Reported-by: Boris Brezillon +Fixes: 7860d720a84c ("drm/msm: Fix build break with recent mm tree") +Signed-off-by: Rob Clark +Reviewed-by: Boris Brezillon +Patchwork: https://patchwork.freedesktop.org/patch/714238/ +Message-ID: <20260325184106.1259528-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem_shrinker.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c +index 1039e3c0a47bf..31fa51a44f86e 100644 +--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c ++++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c +@@ -26,9 +26,8 @@ static bool can_swap(void) + + static bool can_block(struct shrink_control *sc) + { +- if (!(sc->gfp_mask & __GFP_DIRECT_RECLAIM)) +- return false; +- return current_is_kswapd() || (sc->gfp_mask & __GFP_RECLAIM); ++ return (sc->gfp_mask & __GFP_DIRECT_RECLAIM) || ++ (current_is_kswapd() && (sc->gfp_mask & __GFP_KSWAPD_RECLAIM)); + } + + static unsigned long +-- +2.53.0 + diff --git a/queue-7.0/drm-msm-vma-avoid-lock-in-vm_bind-fence-signaling-pa.patch b/queue-7.0/drm-msm-vma-avoid-lock-in-vm_bind-fence-signaling-pa.patch new file mode 100644 index 0000000000..7936e6c416 --- /dev/null +++ b/queue-7.0/drm-msm-vma-avoid-lock-in-vm_bind-fence-signaling-pa.patch @@ -0,0 +1,73 @@ +From 7ee4c3529911617979a2c219e9eef4b0b91e4c89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 11:44:42 -0700 +Subject: drm/msm/vma: Avoid lock in VM_BIND fence signaling path + +From: Rob Clark + +[ Upstream commit 8a7023b035355ef5bfa096bd323256fa8abbbc6a ] + +Use msm_gem_unpin_active(), similar to what is used in the GEM_SUBMIT +path. This avoids needing to hold the obj lock, and the end result is +the same. (As with GEM_SUBMIT, we know the fence isn't signaled yet.) + +Reported-by: Akhil P Oommen +Fixes: 2e6a8a1fe2b2 ("drm/msm: Add VM_BIND ioctl") +Signed-off-by: Rob Clark +Patchwork: https://patchwork.freedesktop.org/patch/712230/ +Message-ID: <20260316184442.673558-1-robin.clark@oss.qualcomm.com> +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/msm_gem.c | 3 +++ + drivers/gpu/drm/msm/msm_gem_vma.c | 9 ++++++--- + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c +index b27abaa13926d..2cb3ab04f1250 100644 +--- a/drivers/gpu/drm/msm/msm_gem.c ++++ b/drivers/gpu/drm/msm/msm_gem.c +@@ -507,8 +507,11 @@ void msm_gem_unpin_locked(struct drm_gem_object *obj) + */ + void msm_gem_unpin_active(struct drm_gem_object *obj) + { ++ struct msm_drm_private *priv = obj->dev->dev_private; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + ++ GEM_WARN_ON(!mutex_is_locked(&priv->lru.lock)); ++ + msm_obj->pin_count--; + GEM_WARN_ON(msm_obj->pin_count < 0); + update_lru_active(obj); +diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c +index adf88cf8f41aa..1c2f486302bcd 100644 +--- a/drivers/gpu/drm/msm/msm_gem_vma.c ++++ b/drivers/gpu/drm/msm/msm_gem_vma.c +@@ -696,6 +696,7 @@ static struct dma_fence * + msm_vma_job_run(struct drm_sched_job *_job) + { + struct msm_vm_bind_job *job = to_msm_vm_bind_job(_job); ++ struct msm_drm_private *priv = job->vm->drm->dev_private; + struct msm_gem_vm *vm = to_msm_vm(job->vm); + struct drm_gem_object *obj; + int ret = vm->unusable ? -EINVAL : 0; +@@ -738,12 +739,14 @@ msm_vma_job_run(struct drm_sched_job *_job) + if (ret) + msm_gem_vm_unusable(job->vm); + ++ mutex_lock(&priv->lru.lock); ++ + job_foreach_bo (obj, job) { +- msm_gem_lock(obj); +- msm_gem_unpin_locked(obj); +- msm_gem_unlock(obj); ++ msm_gem_unpin_active(obj); + } + ++ mutex_unlock(&priv->lru.lock); ++ + /* VM_BIND ops are synchronous, so no fence to wait on: */ + return NULL; + } +-- +2.53.0 + diff --git a/queue-7.0/drm-panel-ilitek-ili9882t-select-drm_display_dsc_hel.patch b/queue-7.0/drm-panel-ilitek-ili9882t-select-drm_display_dsc_hel.patch new file mode 100644 index 0000000000..1e3d42dd39 --- /dev/null +++ b/queue-7.0/drm-panel-ilitek-ili9882t-select-drm_display_dsc_hel.patch @@ -0,0 +1,44 @@ +From c1142f6717d6785d9900b9f3774feda687059f24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 09:50:48 -0300 +Subject: drm/panel: ilitek-ili9882t: Select DRM_DISPLAY_DSC_HELPER +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maíra Canal + +[ Upstream commit 68e28facbc8ab3e701e1814323d397a75b400865 ] + +The panel-ilitek-ili9882t driver uses drm_dsc_pps_payload_pack() which +is provided by the DRM_DISPLAY_DSC_HELPER. Add the missing Kconfig +select to fix the following build error: + + ERROR: modpost: "drm_dsc_pps_payload_pack" [drivers/gpu/drm/panel/panel-ilitek-ili9882t.ko] undefined! + +Fixes: 65ce1f5834e9 ("drm/panel: ilitek-ili9882t: Switch Tianma TL121BVMS07 to DSC 120Hz mode") +Reviewed-by: Neil Armstrong +Tested-by: Nicolas Frattaroli +Reviewed-by: Nicolas Frattaroli +Link: https://patch.msgid.link/20260115125136.64866-1-mcanal@igalia.com +Signed-off-by: Maíra Canal +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig +index 307152ad77591..79264f7bbd0e2 100644 +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -280,6 +280,7 @@ config DRM_PANEL_ILITEK_ILI9882T + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE ++ select DRM_DISPLAY_DSC_HELPER + help + Say Y if you want to enable support for panels based on the + Ilitek ILI9882t controller. +-- +2.53.0 + diff --git a/queue-7.0/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch b/queue-7.0/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch new file mode 100644 index 0000000000..1f823e081e --- /dev/null +++ b/queue-7.0/drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch @@ -0,0 +1,38 @@ +From 4cb2171c07330c86cb2049799c6137f06e3e217b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:21:49 +0200 +Subject: drm/panel: sharp-ls043t1le01: make use of prepare_prev_first + +From: Dmitry Baryshkov + +[ Upstream commit c222177d7c7e1b2e0433d9e47ec2da7015345d50 ] + +The DSI link must be powered up to let panel driver to talk to the panel +during prepare() callback execution. Set the prepare_prev_first flag to +guarantee this. + +Fixes: 9e15123eca79 ("drm/msm/dsi: Stop unconditionally powering up DSI hosts at modeset") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Douglas Anderson +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260323-panel-fix-v1-1-9f12b09161e8@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +index 36abfa2e65e96..dd1eaba23ad3c 100644 +--- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c ++++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +@@ -201,6 +201,7 @@ static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) + + drm_panel_init(&sharp_nt->base, &sharp_nt->dsi->dev, + &sharp_nt_panel_funcs, DRM_MODE_CONNECTOR_DSI); ++ sharp_nt->base.prepare_prev_first = true; + + ret = drm_panel_of_backlight(&sharp_nt->base); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/drm-panel-simple-correct-g190ean01-prepare-timing.patch b/queue-7.0/drm-panel-simple-correct-g190ean01-prepare-timing.patch new file mode 100644 index 0000000000..8be149f71b --- /dev/null +++ b/queue-7.0/drm-panel-simple-correct-g190ean01-prepare-timing.patch @@ -0,0 +1,41 @@ +From 1d5ca341b4da1d6ea40ca3a78515bf9e9101f42e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 16:25:26 +0200 +Subject: drm/panel: simple: Correct G190EAN01 prepare timing + +From: Sebastian Reichel + +[ Upstream commit f1080f82570b797598c1ba7e9c800ae9e94aafc6 ] + +The prepare timing specified by the G190EAN01 datasheet should be +between 30 and 50 ms. Considering it might take some time for the +LVDS encoder to enable the signal, we should only wait the min. +required time in the panel driver and not the max. allowed time. + +Fixes: 2f7b832fc992 ("drm/panel: simple: Add support for AUO G190EAN01 panel") +Signed-off-by: Sebastian Reichel +Signed-off-by: Ian Ray +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patch.msgid.link/20260217142528.68613-1-ian.ray@gehealthcare.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/panel/panel-simple.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index 91ab280869bac..a242ae284db5a 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -1295,7 +1295,7 @@ static const struct panel_desc auo_g190ean01 = { + .height = 301, + }, + .delay = { +- .prepare = 50, ++ .prepare = 30, + .enable = 200, + .disable = 110, + .unprepare = 1000, +-- +2.53.0 + diff --git a/queue-7.0/drm-sun4i-backend-fix-error-pointer-dereference.patch b/queue-7.0/drm-sun4i-backend-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..b3fae9e550 --- /dev/null +++ b/queue-7.0/drm-sun4i-backend-fix-error-pointer-dereference.patch @@ -0,0 +1,43 @@ +From e9ad0c8005d1a07741cb45412a14c3ca37470bfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 19:48:01 -0600 +Subject: drm/sun4i: backend: fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit 06277983eca4a31d3c2114fa33d99a6e82484b11 ] + +The function drm_atomic_get_plane_state() can return an error pointer +and is not checked for it. Add error pointer check. + +Detected by Smatch: +drivers/gpu/drm/sun4i/sun4i_backend.c:496 sun4i_backend_atomic_check() error: +'plane_state' dereferencing possible ERR_PTR() + +Fixes: 96180dde23b79 ("drm/sun4i: backend: Add a custom atomic_check for the frontend") +Signed-off-by: Ethan Tidmore +Reviewed-by: Chen-Yu Tsai +Link: https://patch.msgid.link/20260217014801.60760-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index 40405a52a073a..6391bdc94a5c2 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -491,6 +491,9 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, + drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_plane_state(state, plane); ++ if (IS_ERR(plane_state)) ++ return PTR_ERR(plane_state); ++ + struct sun4i_layer_state *layer_state = + state_to_sun4i_layer_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; +-- +2.53.0 + diff --git a/queue-7.0/drm-sun4i-fix-resource-leaks.patch b/queue-7.0/drm-sun4i-fix-resource-leaks.patch new file mode 100644 index 0000000000..9510b50a49 --- /dev/null +++ b/queue-7.0/drm-sun4i-fix-resource-leaks.patch @@ -0,0 +1,41 @@ +From e56c15b3c5ac83e8b6aaa4f12113142e5b8ef129 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:38:36 -0600 +Subject: drm/sun4i: Fix resource leaks + +From: Ethan Tidmore + +[ Upstream commit 127367ad2e0f4870de60c6d719ae82ecf68d674c ] + +Three clocks are not being released in devm_regmap_init_mmio() error +path. + +Add proper goto and set ret to the error code. + +Fixes: 8270249fbeaf0 ("drm/sun4i: backend: Create regmap after access is possible") +Signed-off-by: Ethan Tidmore +Reviewed-by: Jernej Skrabec +Link: https://patch.msgid.link/20260226163836.10335-1-ethantidmore06@gmail.com +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c +index 6391bdc94a5c2..e989f75c09b7d 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_backend.c ++++ b/drivers/gpu/drm/sun4i/sun4i_backend.c +@@ -881,7 +881,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, + &sun4i_backend_regmap_config); + if (IS_ERR(backend->engine.regs)) { + dev_err(dev, "Couldn't create the backend regmap\n"); +- return PTR_ERR(backend->engine.regs); ++ ret = PTR_ERR(backend->engine.regs); ++ goto err_disable_ram_clk; + } + + list_add_tail(&backend->engine.list, &drv->engine_list); +-- +2.53.0 + diff --git a/queue-7.0/drm-sun4i-mixer-fix-layer-init-code.patch b/queue-7.0/drm-sun4i-mixer-fix-layer-init-code.patch new file mode 100644 index 0000000000..4c5f1b5a10 --- /dev/null +++ b/queue-7.0/drm-sun4i-mixer-fix-layer-init-code.patch @@ -0,0 +1,43 @@ +From b4027bc5346a59ab17a8aa433b04b140cb3aaa05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 19:34:54 +0100 +Subject: drm/sun4i: mixer: Fix layer init code + +From: Jernej Skrabec + +[ Upstream commit 744629904c68bde847c31819f23482d09152f810 ] + +Code refactoring dropped extra NULL sentinel entry at the end of the drm +planes array. + +Add it back. + +Reported-by: Chen-Yu Tsai +Closes: https://lore.kernel.org/linux-sunxi/CAGb2v65wY2pF6sR+0JgnpLa4ysvjght5hAKDa1RUyo=zEKXreg@mail.gmail.com/ +Fixes: 4fa45b04a47d ("drm/sun4i: layer: move num of planes calc out of layer code") +Signed-off-by: Jernej Skrabec +Reviewed-by: Chen-Yu Tsai +Link: https://patch.msgid.link/20260218183454.7881-1-jernej.skrabec@gmail.com +[wens@kernel.org: Fix "Fixes" commit hash] +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sun4i/sun8i_mixer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c +index ce9c155bfad7f..02acc7cbdb979 100644 +--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c ++++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c +@@ -321,7 +321,7 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm, + unsigned int phy_index; + int i; + +- planes = devm_kcalloc(drm->dev, plane_cnt, sizeof(*planes), GFP_KERNEL); ++ planes = devm_kcalloc(drm->dev, plane_cnt + 1, sizeof(*planes), GFP_KERNEL); + if (!planes) + return ERR_PTR(-ENOMEM); + +-- +2.53.0 + diff --git a/queue-7.0/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch b/queue-7.0/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch new file mode 100644 index 0000000000..804ef96269 --- /dev/null +++ b/queue-7.0/drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch @@ -0,0 +1,55 @@ +From 8693795f3b5ec5598f0296521ea67e7e1d6f2cc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:25:13 -0400 +Subject: drm/sysfb: ofdrm: fix PCI device reference leaks + +From: Yuho Choi + +[ Upstream commit 4aa8110000b0d215deef8eed283565dd0c1def88 ] + +display_get_pci_dev_of() gets a referenced PCI device via +pci_get_device(). Drop that reference when pci_enable_device() fails and +release it during the managed teardown path after pci_disable_device(). + +Without that, ofdrm leaks the pci_dev reference on both the error path +and the normal cleanup path. + +Fixes: c8a17756c425 ("drm/ofdrm: Add ofdrm for Open Firmware framebuffers") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Reviewed-by: Thomas Zimmermann +Signed-off-by: Thomas Zimmermann +Link: https://patch.msgid.link/20260420002513.216-1-dbgh9129@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/sysfb/ofdrm.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/sysfb/ofdrm.c b/drivers/gpu/drm/sysfb/ofdrm.c +index d38ba70f4e0d3..247cf13c80a05 100644 +--- a/drivers/gpu/drm/sysfb/ofdrm.c ++++ b/drivers/gpu/drm/sysfb/ofdrm.c +@@ -350,6 +350,7 @@ static void ofdrm_pci_release(void *data) + struct pci_dev *pcidev = data; + + pci_disable_device(pcidev); ++ pci_dev_put(pcidev); + } + + static int ofdrm_device_init_pci(struct ofdrm_device *odev) +@@ -375,6 +376,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev) + if (ret) { + drm_err(dev, "pci_enable_device(%s) failed: %d\n", + dev_name(&pcidev->dev), ret); ++ pci_dev_put(pcidev); + return ret; + } + ret = devm_add_action_or_reset(&pdev->dev, ofdrm_pci_release, pcidev); +-- +2.53.0 + diff --git a/queue-7.0/drm-v3d-handle-error-from-drm_sched_entity_init.patch b/queue-7.0/drm-v3d-handle-error-from-drm_sched_entity_init.patch new file mode 100644 index 0000000000..c8e6bcf769 --- /dev/null +++ b/queue-7.0/drm-v3d-handle-error-from-drm_sched_entity_init.patch @@ -0,0 +1,69 @@ +From 146c8a316ec4d2ccf7162cdddb005e40429d48e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 08:30:33 -0300 +Subject: drm/v3d: Handle error from drm_sched_entity_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Maíra Canal + +[ Upstream commit 8cf1bec37b27846ad3169744c9f1a89a06dcb3fa ] + +drm_sched_entity_init() can fail but its return value is currently being +ignored in v3d_open(). Check the return value and properly unwind +on failure by destroying any already-initialized scheduler entities. + +Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+") +Reviewed-by: Iago Toral Quiroga +Link: https://patch.msgid.link/20260306-v3d-reset-locking-improv-v3-1-49864fe00692@igalia.com +Signed-off-by: Maíra Canal +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/v3d/v3d_drv.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c +index dd60acdf52c2b..86e05fcf6cf65 100644 +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -131,7 +131,7 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + struct v3d_dev *v3d = to_v3d_dev(dev); + struct v3d_file_priv *v3d_priv; + struct drm_gpu_scheduler *sched; +- int i; ++ int i, ret; + + v3d_priv = kzalloc_obj(*v3d_priv); + if (!v3d_priv) +@@ -141,9 +141,11 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + + for (i = 0; i < V3D_MAX_QUEUES; i++) { + sched = &v3d->queue[i].sched; +- drm_sched_entity_init(&v3d_priv->sched_entity[i], +- DRM_SCHED_PRIORITY_NORMAL, &sched, +- 1, NULL); ++ ret = drm_sched_entity_init(&v3d_priv->sched_entity[i], ++ DRM_SCHED_PRIORITY_NORMAL, &sched, ++ 1, NULL); ++ if (ret) ++ goto err_sched; + + memset(&v3d_priv->stats[i], 0, sizeof(v3d_priv->stats[i])); + seqcount_init(&v3d_priv->stats[i].lock); +@@ -153,6 +155,12 @@ v3d_open(struct drm_device *dev, struct drm_file *file) + file->driver_priv = v3d_priv; + + return 0; ++ ++err_sched: ++ for (i--; i >= 0; i--) ++ drm_sched_entity_destroy(&v3d_priv->sched_entity[i]); ++ kfree(v3d_priv); ++ return ret; + } + + static void +-- +2.53.0 + diff --git a/queue-7.0/drm-virtio-allow-importing-prime-buffers-when-3d-is-.patch b/queue-7.0/drm-virtio-allow-importing-prime-buffers-when-3d-is-.patch new file mode 100644 index 0000000000..d74566caab --- /dev/null +++ b/queue-7.0/drm-virtio-allow-importing-prime-buffers-when-3d-is-.patch @@ -0,0 +1,42 @@ +From a9c143bf23976c165f4f389bbc9e3ee24b9a7fd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Dec 2025 12:39:23 -0300 +Subject: drm/virtio: Allow importing prime buffers when 3D is enabled + +From: Val Packett + +[ Upstream commit df4dc947c46bb9f80038f52c6e38cb2d40c10e50 ] + +This functionality was added for using a KMS-only virtgpu with a physical +(or SR-IOV) headless GPU in passthrough, but it should not be restricted +to KMS-only mode. It can be used with cross-domain to pass guest memfds +to the host compositor with zero copies (using udmabuf on both sides). + +Drop the check for the absence of virgl_3d to allow for more use cases. + +Fixes: ca77f27a2665 ("drm/virtio: Import prime buffers from other devices as guest blobs") +Signed-off-by: Val Packett +Reviewed-by: Dmitry Osipenko +Signed-off-by: Dmitry Osipenko +Link: https://patch.msgid.link/20251210154755.1119861-2-val@invisiblethingslab.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/virtio/virtgpu_prime.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c +index 8adcf5c15d456..05756ed4f1dac 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_prime.c ++++ b/drivers/gpu/drm/virtio/virtgpu_prime.c +@@ -310,7 +310,7 @@ struct drm_gem_object *virtgpu_gem_prime_import(struct drm_device *dev, + } + } + +- if (!vgdev->has_resource_blob || vgdev->has_virgl_3d) ++ if (!vgdev->has_resource_blob) + return drm_gem_prime_import(dev, buf); + + bo = kzalloc_obj(*bo); +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-consolidate-workaround-entries-for-wa_1401938.patch b/queue-7.0/drm-xe-consolidate-workaround-entries-for-wa_1401938.patch new file mode 100644 index 0000000000..632a6484a5 --- /dev/null +++ b/queue-7.0/drm-xe-consolidate-workaround-entries-for-wa_1401938.patch @@ -0,0 +1,61 @@ +From e96cb0a55caec271807b9a255350f13460707c40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 09:27:39 -0800 +Subject: drm/xe: Consolidate workaround entries for Wa_14019386621 + +From: Matt Roper + +[ Upstream commit f0d6d356f8ac427d1f3eb8fb783a64ac3efd6fc7 ] + +Wa_14019386621 applies to all graphics versions from 20.01 through 20.04 +(inclusive). Consolidate the RTP entries into a single range-based entry. + +Reviewed-by: Shuicheng Lin +Link: https://patch.msgid.link/20260220-forupstream-wa_cleanup-v2-17-b12005a05af6@intel.com +Signed-off-by: Matt Roper +Stable-dep-of: 1046bc7b4168 ("drm/xe/xe2_hpg: Drop invalid workaround Wa_15010599737") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_wa.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c +index 6f92c0d0d8943..2ee08c068adbc 100644 +--- a/drivers/gpu/drm/xe/xe_wa.c ++++ b/drivers/gpu/drm/xe/xe_wa.c +@@ -712,6 +712,10 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1255, 2004), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) + }, ++ { XE_RTP_NAME("14019386621"), ++ XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2004), ENGINE_CLASS(RENDER)), ++ XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE)) ++ }, + + /* DG1 */ + +@@ -768,10 +772,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + + /* Xe2_LPG */ + +- { XE_RTP_NAME("14019386621"), +- XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), +- XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE)) +- }, + { XE_RTP_NAME("14019988906"), + XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD)) +@@ -809,10 +809,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN)) + }, +- { XE_RTP_NAME("14019386621"), +- XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)), +- XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE)) +- }, + { XE_RTP_NAME("14020756599"), + XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(WM_CHICKEN3, HIZ_PLANE_COMPRESSION_DIS)) +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-consolidate-workaround-entries-for-wa_1401987.patch b/queue-7.0/drm-xe-consolidate-workaround-entries-for-wa_1401987.patch new file mode 100644 index 0000000000..0a7641a9b8 --- /dev/null +++ b/queue-7.0/drm-xe-consolidate-workaround-entries-for-wa_1401987.patch @@ -0,0 +1,87 @@ +From c25b52177098c770756b91e3bdf322d21f46d703 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Feb 2026 09:27:38 -0800 +Subject: drm/xe: Consolidate workaround entries for Wa_14019877138 + +From: Matt Roper + +[ Upstream commit 55b19abb6c44db40fe1ebd01e9c16aa02c4cf663 ] + +Wa_14019877138 applies to all graphics versions from 12.55 through 20.04 +(inclusive) that have a render engine. Consolidate the RTP entries into +a single range-based entry. + +Note that the DG2 entry for this workaround was missing an +ENGINE_CLASS(RENDER) rule; that mistake is fixed by this consolidation. + +Reviewed-by: Shuicheng Lin +Link: https://patch.msgid.link/20260220-forupstream-wa_cleanup-v2-16-b12005a05af6@intel.com +Signed-off-by: Matt Roper +Stable-dep-of: 1046bc7b4168 ("drm/xe/xe2_hpg: Drop invalid workaround Wa_15010599737") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_wa.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c +index d7e309ad9abaf..6f92c0d0d8943 100644 +--- a/drivers/gpu/drm/xe/xe_wa.c ++++ b/drivers/gpu/drm/xe/xe_wa.c +@@ -708,6 +708,10 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + XE_RTP_RULES(GRAPHICS_VERSION(1200)), + XE_RTP_ACTIONS(SET(COMMON_SLICE_CHICKEN4, DISABLE_TDC_LOAD_BALANCING_CALC)) + }, ++ { XE_RTP_NAME("14019877138"), ++ XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1255, 2004), ENGINE_CLASS(RENDER)), ++ XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) ++ }, + + /* DG1 */ + +@@ -744,10 +748,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + XE_RTP_RULES(PLATFORM(DG2)), + XE_RTP_ACTIONS(SET(CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE)) + }, +- { XE_RTP_NAME("14019877138"), +- XE_RTP_RULES(PLATFORM(DG2)), +- XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) +- }, + + /* PVC */ + +@@ -765,10 +765,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1270, 1274)), + XE_RTP_ACTIONS(SET(CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE)) + }, +- { XE_RTP_NAME("14019877138"), +- XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1270, 1274), ENGINE_CLASS(RENDER)), +- XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) +- }, + + /* Xe2_LPG */ + +@@ -776,10 +772,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE)) + }, +- { XE_RTP_NAME("14019877138"), +- XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), +- XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) +- }, + { XE_RTP_NAME("14019988906"), + XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD)) +@@ -829,10 +821,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD)) + }, +- { XE_RTP_NAME("14019877138"), +- XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)), +- XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) +- }, + { XE_RTP_NAME("14021490052"), + XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(FF_MODE, +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-debugfs-correct-printing-of-register-whitelis.patch b/queue-7.0/drm-xe-debugfs-correct-printing-of-register-whitelis.patch new file mode 100644 index 0000000000..62be733765 --- /dev/null +++ b/queue-7.0/drm-xe-debugfs-correct-printing-of-register-whitelis.patch @@ -0,0 +1,58 @@ +From 2557cb46916b9e65e79a03c2f28d92a3c4524bf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 15:27:44 -0700 +Subject: drm/xe/debugfs: Correct printing of register whitelist ranges + +From: Matt Roper + +[ Upstream commit 03f2499c51dffce611b065b2894406beb9f2ebe0 ] + +The register-save-restore debugfs prints whitelist entries as offset +ranges. E.g., + + REG[0x39319c-0x39319f]: allow read access + +for a single dword-sized register. However the GENMASK value used to +set the lower bits to '1' for the upper bound of the whitelist range +incorrectly included one more bit than it should have, causing the +whitelist ranges to sometimes appear twice as large as they really were. +For example, + + REG[0x6210-0x6217]: allow rw access + +was also intended to be a single dword-sized register whitelist (with a +range 0x6210-0x6213) but was printed incorrectly as a qword-sized range +because one too many bits was flipped on. Similar 'off by one' logic +was applied when printing 4-dword register ranges and 64-dword register +ranges as well. + +Correct the GENMASK logic to print these ranges in debugfs correctly. +No impact outside of correcting the misleading debugfs output. + +Fixes: d855d2246ea6 ("drm/xe: Print whitelist while applying") +Reviewed-by: Stuart Summers +Link: https://patch.msgid.link/20260408-regsr_wl_range-v1-1-e9a28c8b4264@intel.com +Signed-off-by: Matt Roper +(cherry picked from commit 1a2a722ff96749734a5585dfe7f0bea7719caa8b) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c +index 1d36c09681aaa..fc4b6f835d4b3 100644 +--- a/drivers/gpu/drm/xe/xe_reg_whitelist.c ++++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c +@@ -218,7 +218,7 @@ void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, + } + + range_start = reg & REG_GENMASK(25, range_bit); +- range_end = range_start | REG_GENMASK(range_bit, 0); ++ range_end = range_start | REG_GENMASK(range_bit - 1, 0); + + switch (val & RING_FORCE_TO_NONPRIV_ACCESS_MASK) { + case RING_FORCE_TO_NONPRIV_ACCESS_RW: +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-drop-registration-of-guc_submit_wedged_fini-f.patch b/queue-7.0/drm-xe-drop-registration-of-guc_submit_wedged_fini-f.patch new file mode 100644 index 0000000000..a7397fc39c --- /dev/null +++ b/queue-7.0/drm-xe-drop-registration-of-guc_submit_wedged_fini-f.patch @@ -0,0 +1,105 @@ +From 854d6884badad4e96918bad7ee4466a9d938a681 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:01:16 -0700 +Subject: drm/xe: Drop registration of guc_submit_wedged_fini from + xe_guc_submit_wedge() + +From: Matthew Brost + +[ Upstream commit a0fc362f095330f7b3f68ac0c55ef8da18290c87 ] + +xe_guc_submit_wedge() runs in the DMA-fence signaling path, where +GFP_KERNEL memory allocations are not permitted. However, registering +guc_submit_wedged_fini via drmm_add_action_or_reset() triggers such an +allocation. + +Avoid this by moving the logic from guc_submit_wedged_fini() into +guc_submit_fini(), where wedged exec queue references are dropped during +normal teardown. + +Fixes: 8ed9aaae39f3 ("drm/xe: Force wedged state and block GT reset upon any GPU hang") +Signed-off-by: Matthew Brost +Reviewed-by: Rodrigo Vivi +Link: https://patch.msgid.link/20260326210116.202585-3-matthew.brost@intel.com +(cherry picked from commit 4a706bd93c4fb156a13477e26ffdf2e633edeb10) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_guc_submit.c | 33 ++++++++---------------------- + 1 file changed, 9 insertions(+), 24 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c +index 4867a97583903..82412c8dfd37d 100644 +--- a/drivers/gpu/drm/xe/xe_guc_submit.c ++++ b/drivers/gpu/drm/xe/xe_guc_submit.c +@@ -260,24 +260,12 @@ static void guc_submit_sw_fini(struct drm_device *drm, void *arg) + } + + static void guc_submit_fini(void *arg) +-{ +- struct xe_guc *guc = arg; +- +- /* Forcefully kill any remaining exec queues */ +- xe_guc_ct_stop(&guc->ct); +- guc_submit_reset_prepare(guc); +- xe_guc_softreset(guc); +- xe_guc_submit_stop(guc); +- xe_uc_fw_sanitize(&guc->fw); +- xe_guc_submit_pause_abort(guc); +-} +- +-static void guc_submit_wedged_fini(void *arg) + { + struct xe_guc *guc = arg; + struct xe_exec_queue *q; + unsigned long index; + ++ /* Drop any wedged queue refs */ + mutex_lock(&guc->submission_state.lock); + xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) { + if (exec_queue_wedged(q)) { +@@ -287,6 +275,14 @@ static void guc_submit_wedged_fini(void *arg) + } + } + mutex_unlock(&guc->submission_state.lock); ++ ++ /* Forcefully kill any remaining exec queues */ ++ xe_guc_ct_stop(&guc->ct); ++ guc_submit_reset_prepare(guc); ++ xe_guc_softreset(guc); ++ xe_guc_submit_stop(guc); ++ xe_uc_fw_sanitize(&guc->fw); ++ xe_guc_submit_pause_abort(guc); + } + + static const struct xe_exec_queue_ops guc_exec_queue_ops; +@@ -1272,10 +1268,8 @@ static void disable_scheduling_deregister(struct xe_guc *guc, + void xe_guc_submit_wedge(struct xe_guc *guc) + { + struct xe_device *xe = guc_to_xe(guc); +- struct xe_gt *gt = guc_to_gt(guc); + struct xe_exec_queue *q; + unsigned long index; +- int err; + + xe_gt_assert(guc_to_gt(guc), guc_to_xe(guc)->wedged.mode); + +@@ -1287,15 +1281,6 @@ void xe_guc_submit_wedge(struct xe_guc *guc) + return; + + if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { +- err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev, +- guc_submit_wedged_fini, guc); +- if (err) { +- xe_gt_err(gt, "Failed to register clean-up on wedged.mode=%s; " +- "Although device is wedged.\n", +- xe_wedged_mode_to_string(XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)); +- return; +- } +- + mutex_lock(&guc->submission_state.lock); + xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) + if (xe_exec_queue_get_unless_zero(q)) +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-eustall-fix-drm_dev_put-called-before-stream-.patch b/queue-7.0/drm-xe-eustall-fix-drm_dev_put-called-before-stream-.patch new file mode 100644 index 0000000000..6412939761 --- /dev/null +++ b/queue-7.0/drm-xe-eustall-fix-drm_dev_put-called-before-stream-.patch @@ -0,0 +1,56 @@ +From f6e02f42227916f814625c0bddc8cdae8a5e8bff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:54:28 +0000 +Subject: drm/xe/eustall: Fix drm_dev_put called before stream disable in close + +From: Shuicheng Lin + +[ Upstream commit dc2d9842c67d883d3200ae33b9c3859dd9492408 ] + +In xe_eu_stall_stream_close(), drm_dev_put() is called before the +stream is disabled and its resources are freed. If this drops the +last reference, the device structures could be freed while the +subsequent cleanup code still accesses them, leading to a +use-after-free. + +Fix this by moving drm_dev_put() after all device accesses are +complete. This matches the ordering in xe_oa_release(). + +Fixes: 9a0b11d4cf3b ("drm/xe/eustall: Add support to init, enable and disable EU stall sampling") +Cc: Harish Chegondi +Assisted-by: Claude:claude-opus-4.6 +Signed-off-by: Shuicheng Lin +Reviewed-by: Harish Chegondi +Link: https://patch.msgid.link/20260415225428.3399934-1-shuicheng.lin@intel.com +Signed-off-by: Matt Roper +(cherry picked from commit 35aff528f7297e949e5e19c9cd7fd748cf1cf21c) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_eu_stall.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c +index 39723928a0199..7da14854f688e 100644 +--- a/drivers/gpu/drm/xe/xe_eu_stall.c ++++ b/drivers/gpu/drm/xe/xe_eu_stall.c +@@ -869,14 +869,14 @@ static int xe_eu_stall_stream_close(struct inode *inode, struct file *file) + struct xe_eu_stall_data_stream *stream = file->private_data; + struct xe_gt *gt = stream->gt; + +- drm_dev_put(>->tile->xe->drm); +- + mutex_lock(>->eu_stall->stream_lock); + xe_eu_stall_disable_locked(stream); + xe_eu_stall_data_buf_destroy(stream); + xe_eu_stall_stream_free(stream); + mutex_unlock(>->eu_stall->stream_lock); + ++ drm_dev_put(>->tile->xe->drm); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch b/queue-7.0/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch new file mode 100644 index 0000000000..ca998dd4c6 --- /dev/null +++ b/queue-7.0/drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch @@ -0,0 +1,80 @@ +From 45b08291008dbe509cb066b0d9a5f4d474b5cd7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 02:06:47 +0000 +Subject: drm/xe: Fix error cleanup in xe_exec_queue_create_ioctl() + +From: Shuicheng Lin + +[ Upstream commit f3cc22d4df3ed58439ea7e21daa54c3608e03b78 ] + +Two error handling issues exist in xe_exec_queue_create_ioctl(): + +1. When xe_hw_engine_group_add_exec_queue() fails, the error path jumps + to put_exec_queue which skips xe_exec_queue_kill(). If the VM is in + preempt fence mode, xe_vm_add_compute_exec_queue() has already added + the queue to the VM's compute exec queue list. Skipping the kill + leaves the queue on that list, leading to a dangling pointer after + the queue is freed. + +2. When xa_alloc() fails after xe_hw_engine_group_add_exec_queue() has + succeeded, the error path does not call + xe_hw_engine_group_del_exec_queue() to remove the queue from the hw + engine group list. The queue is then freed while still linked into + the hw engine group, causing a use-after-free. + +Fix both by: +- Changing the xe_hw_engine_group_add_exec_queue() failure path to jump + to kill_exec_queue so that xe_exec_queue_kill() properly removes the + queue from the VM's compute list. +- Adding a del_hw_engine_group label before kill_exec_queue for the + xa_alloc() failure path, which removes the queue from the hw engine + group before proceeding with the rest of the cleanup. + +Fixes: 7970cb36966c ("'drm/xe/hw_engine_group: Register hw engine group's exec queues") +Cc: Francois Dugast +Cc: Matthew Brost +Cc: Niranjana Vishwanathapura +Assisted-by: Claude:claude-opus-4.6 +Reviewed-by: Matthew Brost +Link: https://patch.msgid.link/20260408020647.3397933-1-shuicheng.lin@intel.com +Signed-off-by: Shuicheng Lin +(cherry picked from commit 37c831f401746a45d510b312b0ed7a77b1e06ec8) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_exec_queue.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c +index 3a60a2fb9cf96..a49919da0eee6 100644 +--- a/drivers/gpu/drm/xe/xe_exec_queue.c ++++ b/drivers/gpu/drm/xe/xe_exec_queue.c +@@ -1227,7 +1227,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, + if (q->vm && q->hwe->hw_engine_group) { + err = xe_hw_engine_group_add_exec_queue(q->hwe->hw_engine_group, q); + if (err) +- goto put_exec_queue; ++ goto kill_exec_queue; + } + } + +@@ -1236,12 +1236,15 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, + /* user id alloc must always be last in ioctl to prevent UAF */ + err = xa_alloc(&xef->exec_queue.xa, &id, q, xa_limit_32b, GFP_KERNEL); + if (err) +- goto kill_exec_queue; ++ goto del_hw_engine_group; + + args->exec_queue_id = id; + + return 0; + ++del_hw_engine_group: ++ if (q->vm && q->hwe && q->hwe->hw_engine_group) ++ xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); + kill_exec_queue: + xe_exec_queue_kill(q); + delete_queue_group: +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-fix-potential-null-deref-in-xe_exec_queue_tlb.patch b/queue-7.0/drm-xe-fix-potential-null-deref-in-xe_exec_queue_tlb.patch new file mode 100644 index 0000000000..fd4aec1d29 --- /dev/null +++ b/queue-7.0/drm-xe-fix-potential-null-deref-in-xe_exec_queue_tlb.patch @@ -0,0 +1,54 @@ +From d6b07082e811978d5c292d6cf6d377755c560289 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 00:34:49 +0000 +Subject: drm/xe: Fix potential NULL deref in + xe_exec_queue_tlb_inval_last_fence_put_unlocked + +From: Shuicheng Lin + +[ Upstream commit f8c4151d50b12923b67819ebf03c1c6782c984c1 ] + +xe_exec_queue_tlb_inval_last_fence_put_unlocked() uses q->vm->xe as the +first argument to xe_assert(). This function is called unconditionally +from xe_exec_queue_destroy() for all queues, including kernel queues +that have q->vm == NULL (e.g., queues created during GT init in +xe_gt_record_default_lrcs() with vm=NULL). + +While current compilers optimize away the q->vm->xe dereference (even +in CONFIG_DRM_XE_DEBUG=y builds, the compiler pushes the dereference +into the WARN branch that is only taken when the assert condition is +false), the code is semantically incorrect and constitutes undefined +behavior in the C abstract machine for the NULL pointer case. + +Use gt_to_xe(q->gt) instead, which is always valid for any exec queue. +This is consistent with how xe_exec_queue_destroy() itself obtains the +xe_device pointer in its own xe_assert at the top of the function. + +Fixes: b2d7ec41f2a3 ("drm/xe: Attach last fence to TLB invalidation job queues") +Assisted-by: Claude:claude-opus-4.6 +Reviewed-by: Matthew Brost +Link: https://patch.msgid.link/20260409003449.3405767-1-shuicheng.lin@intel.com +Signed-off-by: Shuicheng Lin +(cherry picked from commit 96078a1c68bf97f17fd1d08c3f58f5c5cc9ccd65) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_exec_queue.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c +index 8ecdf949f9e4c..3a60a2fb9cf96 100644 +--- a/drivers/gpu/drm/xe/xe_exec_queue.c ++++ b/drivers/gpu/drm/xe/xe_exec_queue.c +@@ -1574,7 +1574,7 @@ void xe_exec_queue_tlb_inval_last_fence_put(struct xe_exec_queue *q, + void xe_exec_queue_tlb_inval_last_fence_put_unlocked(struct xe_exec_queue *q, + unsigned int type) + { +- xe_assert(q->vm->xe, type == XE_EXEC_QUEUE_TLB_INVAL_MEDIA_GT || ++ xe_assert(gt_to_xe(q->gt), type == XE_EXEC_QUEUE_TLB_INVAL_MEDIA_GT || + type == XE_EXEC_QUEUE_TLB_INVAL_PRIMARY_GT); + + dma_fence_put(q->tlb_inval[type].last_fence); +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch b/queue-7.0/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch new file mode 100644 index 0000000000..47c1d36df2 --- /dev/null +++ b/queue-7.0/drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch @@ -0,0 +1,45 @@ +From 678e6592a4d20c564affaf0e4b6d8c033803a1ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 16:33:08 +0000 +Subject: drm/xe/gsc: Fix BO leak on error in query_compatibility_version() + +From: Shuicheng Lin + +[ Upstream commit 3762d6c36549accea7068c4a175483fafdd03657 ] + +When xe_gsc_read_out_header() fails, query_compatibility_version() +returns directly instead of jumping to the out_bo label. This skips +the xe_bo_unpin_map_no_vm() call, leaving the BO pinned and mapped +with no remaining reference to free it. + +Fix by using goto out_bo so the error path properly cleans up the BO, +consistent with the other error handling in the same function. + +Fixes: 0881cbe04077 ("drm/xe/gsc: Query GSC compatibility version") +Cc: Daniele Ceraolo Spurio +Reviewed-by: Daniele Ceraolo Spurio +Link: https://patch.msgid.link/20260417163308.3416147-1-shuicheng.lin@intel.com +Signed-off-by: Shuicheng Lin +(cherry picked from commit 8de86d0a843c32ca9d36864bdb92f0376a830bce) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_gsc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c +index e5c234f3d795e..0d13e357fb43c 100644 +--- a/drivers/gpu/drm/xe/xe_gsc.c ++++ b/drivers/gpu/drm/xe/xe_gsc.c +@@ -166,7 +166,7 @@ static int query_compatibility_version(struct xe_gsc *gsc) + &rd_offset); + if (err) { + xe_gt_err(gt, "HuC: invalid GSC reply for version query (err=%d)\n", err); +- return err; ++ goto out_bo; + } + + compat->major = version_query_rd(xe, &bo->vmap, rd_offset, proj_major); +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-use-xe_wedged_mode_upon_any_hang_no_reset-enu.patch b/queue-7.0/drm-xe-use-xe_wedged_mode_upon_any_hang_no_reset-enu.patch new file mode 100644 index 0000000000..26d31e22e9 --- /dev/null +++ b/queue-7.0/drm-xe-use-xe_wedged_mode_upon_any_hang_no_reset-enu.patch @@ -0,0 +1,48 @@ +From c8d42841a3a67fc9a3281e4248c17245c70d922d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 18:50:36 -0400 +Subject: drm/xe: Use XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET enum instead of + magic number + +From: Zhanjun Dong + +[ Upstream commit a7f607610da721f77db358b09be8091e60bd8e89 ] + +Replace the magic number 2 with the proper enum value +XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET for better code readability +and maintainability. + +Signed-off-by: Zhanjun Dong +Reviewed-by: Matthew Brost +Signed-off-by: Matthew Brost +Link: https://patch.msgid.link/20260310225039.1320161-5-zhanjun.dong@intel.com +Stable-dep-of: a0fc362f0953 ("drm/xe: Drop registration of guc_submit_wedged_fini from xe_guc_submit_wedge()") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_guc_submit.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c +index fc4f99d467635..4867a97583903 100644 +--- a/drivers/gpu/drm/xe/xe_guc_submit.c ++++ b/drivers/gpu/drm/xe/xe_guc_submit.c +@@ -1286,12 +1286,13 @@ void xe_guc_submit_wedge(struct xe_guc *guc) + if (!guc->submission_state.initialized) + return; + +- if (xe->wedged.mode == 2) { ++ if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) { + err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev, + guc_submit_wedged_fini, guc); + if (err) { +- xe_gt_err(gt, "Failed to register clean-up on wedged.mode=2; " +- "Although device is wedged.\n"); ++ xe_gt_err(gt, "Failed to register clean-up on wedged.mode=%s; " ++ "Although device is wedged.\n", ++ xe_wedged_mode_to_string(XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)); + return; + } + +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-xe2_hpg-drop-invalid-workaround-wa_1501059973.patch b/queue-7.0/drm-xe-xe2_hpg-drop-invalid-workaround-wa_1501059973.patch new file mode 100644 index 0000000000..2a6fc6466c --- /dev/null +++ b/queue-7.0/drm-xe-xe2_hpg-drop-invalid-workaround-wa_1501059973.patch @@ -0,0 +1,49 @@ +From 105d8a20f71429f6a7ea1ad93d73e9cc51cdf681 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:11:33 -0800 +Subject: drm/xe/xe2_hpg: Drop invalid workaround Wa_15010599737 + +From: Matt Roper + +[ Upstream commit 1046bc7b416814833a43af8e66c52b0ea71c2021 ] + +Wa_15010599737 was a workaround originally proposed (and ultimately +rejected) for DG2-G10. There's no record of it ever being relevant or +even considered for any other platforms. + +The specific bit this workaround was setting is documented as "This bit +should be set to 1 for the DX9 API and 0 for all other APIs" which means +that it should almost always be left at the default value of 0 on Linux. +The register itself is directly accessible from userspace, so in the +special cases where it might be relevant (e.g., Wine/Proton running +Windows DX9 apps), the userspace drivers already have the ability to +change the setting without involvement of the kernel. + +Fixes: 7f3ee7d88058 ("drm/xe/xe2hpg: Add initial GT workarounds") +Reviewed-by: Balasubramani Vivekanandan +Link: https://patch.msgid.link/20260223-forupstream-wa_cleanup-v3-2-7f201eb2f172@intel.com +Signed-off-by: Matt Roper +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_wa.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c +index 2ee08c068adbc..9ddd21a21dcef 100644 +--- a/drivers/gpu/drm/xe/xe_wa.c ++++ b/drivers/gpu/drm/xe/xe_wa.c +@@ -805,10 +805,7 @@ static const struct xe_rtp_entry_sr lrc_was[] = { + }, + + /* Xe2_HPG */ +- { XE_RTP_NAME("15010599737"), +- XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), +- XE_RTP_ACTIONS(SET(CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN)) +- }, ++ + { XE_RTP_NAME("14020756599"), + XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(WM_CHICKEN3, HIZ_PLANE_COMPRESSION_DIS)) +-- +2.53.0 + diff --git a/queue-7.0/drm-xe-xelp-fix-wa_18022495364.patch b/queue-7.0/drm-xe-xelp-fix-wa_18022495364.patch new file mode 100644 index 0000000000..19a20f2930 --- /dev/null +++ b/queue-7.0/drm-xe-xelp-fix-wa_18022495364.patch @@ -0,0 +1,46 @@ +From 4a4fb9e25f15e761a511c0da4ee6734634d9ceaa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 14:16:03 +0100 +Subject: drm/xe/xelp: Fix Wa_18022495364 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tvrtko Ursulin + +[ Upstream commit 7fe6cae2f7fad2b5166b0fc096618629f9e2ebcb ] + +It looks I mistyped CS_DEBUG_MODE2 as CS_DEBUG_MODE1 when adding the +workaround. Fix it. + +Signed-off-by: Tvrtko Ursulin +Fixes: ca33cd271ef9 ("drm/xe/xelp: Add Wa_18022495364") +Cc: Matt Roper +Cc: "Thomas Hellström" +Cc: Rodrigo Vivi +Cc: # v6.18+ +Reviewed-by: Matt Roper +Signed-off-by: Thomas Hellström +Link: https://patch.msgid.link/20260116095040.49335-1-tvrtko.ursulin@igalia.com +Stable-dep-of: 0df99689eb79 ("drm/xe/xelp: Fix Wa_18022495364") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/xe/xe_lrc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c +index 7b70cc01fdb38..fc38cdcc37714 100644 +--- a/drivers/gpu/drm/xe/xe_lrc.c ++++ b/drivers/gpu/drm/xe/xe_lrc.c +@@ -1202,7 +1202,7 @@ static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc, + if (xe_gt_WARN_ON(lrc->gt, max_len < 3)) + return -ENOSPC; + +- *cmd++ = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(1); ++ *cmd++ = MI_LOAD_REGISTER_IMM | MI_LRI_LRM_CS_MMIO | MI_LRI_NUM_REGS(1); + *cmd++ = CS_DEBUG_MODE2(0).addr; + *cmd++ = _MASKED_BIT_ENABLE(INSTRUCTION_STATE_CACHE_INVALIDATE); + +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-clock-qcom-add-gcc-video-axi-reset-clock.patch b/queue-7.0/dt-bindings-clock-qcom-add-gcc-video-axi-reset-clock.patch new file mode 100644 index 0000000000..c7e93eee8d --- /dev/null +++ b/queue-7.0/dt-bindings-clock-qcom-add-gcc-video-axi-reset-clock.patch @@ -0,0 +1,36 @@ +From f38e05d04746ea7fafd5034522b263423298f9e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Feb 2026 16:26:50 +0530 +Subject: dt-bindings: clock: qcom: Add GCC video axi reset clock for Glymur + +From: Taniya Das + +[ Upstream commit 7c3260327fc874b7c89d7bb230cd569d2e78aff7 ] + +The global clock controller video axi reset clocks are required by +the video SW driver to assert and deassert the clock resets. + +Signed-off-by: Taniya Das +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20260202-glymur_videocc-v2-1-8f7d8b4d8edd@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Stable-dep-of: 1c8ce43e1e07 ("clk: qcom: gcc-glymur: Add video axi clock resets for glymur") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,glymur-gcc.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/dt-bindings/clock/qcom,glymur-gcc.h b/include/dt-bindings/clock/qcom,glymur-gcc.h +index 10c12b8c51c34..6907653c79927 100644 +--- a/include/dt-bindings/clock/qcom,glymur-gcc.h ++++ b/include/dt-bindings/clock/qcom,glymur-gcc.h +@@ -574,5 +574,6 @@ + #define GCC_VIDEO_AXI0_CLK_ARES 89 + #define GCC_VIDEO_AXI1_CLK_ARES 90 + #define GCC_VIDEO_BCR 91 ++#define GCC_VIDEO_AXI0C_CLK_ARES 92 + + #endif +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch b/queue-7.0/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch new file mode 100644 index 0000000000..27cb0f9967 --- /dev/null +++ b/queue-7.0/dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch @@ -0,0 +1,40 @@ +From d2a1ecb8460942104edb3729b0a635d578ad93b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 08:12:06 -0300 +Subject: dt-bindings: clock: qcom,gcc-sc8180x: Add missing GDSCs + +From: Val Packett + +[ Upstream commit 76404ffbf07f28a5ec04748e18fce3dac2e78ef6 ] + +There are 5 more GDSCs that we were ignoring and not putting to sleep, +which are listed in downstream DTS. Add them. + +Signed-off-by: Val Packett +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20260312112321.370983-2-val@packett.cool +Signed-off-by: Bjorn Andersson +Stable-dep-of: 3565741eb985 ("clk: qcom: gcc-sc8180x: Add missing GDSCs") +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/qcom,gcc-sc8180x.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/dt-bindings/clock/qcom,gcc-sc8180x.h b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +index b9d8438a15ffb..9ed7b794aacc4 100644 +--- a/include/dt-bindings/clock/qcom,gcc-sc8180x.h ++++ b/include/dt-bindings/clock/qcom,gcc-sc8180x.h +@@ -322,5 +322,10 @@ + #define USB30_MP_GDSC 8 + #define USB30_PRIM_GDSC 9 + #define USB30_SEC_GDSC 10 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 11 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 12 ++#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 13 ++#define HLOS1_VOTE_TURING_MMU_TBU0_GDSC 14 ++#define HLOS1_VOTE_TURING_MMU_TBU1_GDSC 15 + + #endif +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch b/queue-7.0/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch new file mode 100644 index 0000000000..2709519de0 --- /dev/null +++ b/queue-7.0/dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch @@ -0,0 +1,42 @@ +From 79fddf4da307fc93b136679807ecac9c4b074ec0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 11:26:20 +0100 +Subject: dt-bindings: interrupt-controller: arm,gic-v3: Fix EPPI range + +From: Geert Uytterhoeven + +[ Upstream commit 15cfc8984defc17e5e4de1f58db7b993240fcbda ] + +According to the "Arm Generic Interrupt Controller (GIC) Architecture +Specification, v3 and v4", revision H.b[1], there can be only 64 +Extended PPI interrupts. + +[1] https://developer.arm.com/documentation/ihi0069/hb/ + +Fixes: 4b049063e0bcbfd3 ("dt-bindings: interrupt-controller: arm,gic-v3: Describe EPPI range support") +Signed-off-by: Geert Uytterhoeven +Brain-farted-by: Marc Zyngier +Acked-by: Marc Zyngier +Link: https://patch.msgid.link/3e49a63c6b2b6ee48e3737adee87781f9c136c5f.1772792753.git.geert+renesas@glider.be +Signed-off-by: Rob Herring (Arm) +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/interrupt-controller/arm,gic-v3.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +index bfd30aae682bf..360a0643a0b56 100644 +--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml ++++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +@@ -50,7 +50,7 @@ properties: + The 2nd cell contains the interrupt number for the interrupt type. + SPI interrupts are in the range [0-987]. PPI interrupts are in the + range [0-15]. Extended SPI interrupts are in the range [0-1023]. +- Extended PPI interrupts are in the range [0-127]. ++ Extended PPI interrupts are in the range [0-63]. + + The 3rd cell is the flags, encoded as follows: + bits[3:0] trigger type and level flags. +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-mmc-dwcmshc-sdhci-fix-resets-array-valid.patch b/queue-7.0/dt-bindings-mmc-dwcmshc-sdhci-fix-resets-array-valid.patch new file mode 100644 index 0000000000..fae0190176 --- /dev/null +++ b/queue-7.0/dt-bindings-mmc-dwcmshc-sdhci-fix-resets-array-valid.patch @@ -0,0 +1,57 @@ +From 0a5415bcdaab144d62914e88b14e18b3e491e5c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 17:26:14 +0800 +Subject: dt-bindings: mmc: dwcmshc-sdhci: Fix resets array validation + +From: Huan He + +[ Upstream commit 5f7ac24ba232180caf77e9ddd6ccad61b9948706 ] + +The binding defines tuple-style reset-names items for some +compatibles, which implicitly enforces a fixed array length +via JSON Schema. + +Defining global maxItems for resets and reset-names causes these +constraints to be intersected via allOf, resulting in an effective +minItems equal to the global maxItems. This leads to dtbs_check +failures reporting reset arrays as too short, even when the DTS +provides the correct number of entries. + +Fixes: 30009a21f257 ("dt-bindings: mmc: sdhci-of-dwcmshc: Add Eswin EIC7700") +Co-developed-by: Pritesh Patel +Signed-off-by: Pritesh Patel +Signed-off-by: Huan He +Acked-by: Conor Dooley +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +index 7e7c55dc24403..5cebe5eb1efb8 100644 +--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml ++++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +@@ -50,9 +50,11 @@ properties: + maxItems: 1 + + resets: ++ minItems: 4 + maxItems: 5 + + reset-names: ++ minItems: 4 + maxItems: 5 + + rockchip,txclk-tapnum: +@@ -146,6 +148,7 @@ allOf: + else: + properties: + resets: ++ minItems: 5 + maxItems: 5 + reset-names: + items: +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch b/queue-7.0/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch new file mode 100644 index 0000000000..6435507e8f --- /dev/null +++ b/queue-7.0/dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch @@ -0,0 +1,47 @@ +From d6d2c47172182516ec61de8a4a10fe7cd9b4e287 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 14:34:33 +0200 +Subject: dt-bindings: net: dsa: nxp,sja1105: make spi-cpol optional for + sja1110 + +From: Josua Mayer + +[ Upstream commit 600f01dc4bd0c736b3ffea9f7976136d8bf1b136 ] + +Currently, the binding requires 'spi-cpha' for SJA1105 and 'spi-cpol' +for SJA1110. + +However, the SJA1110 supports both SPI modes 0 and 2. Mode 2 +(cpha=0, cpol=1) is used by the NXP LX2160 Bluebox 3. + +On the SolidRun i.MX8DXL HummingBoard Telematics, mode 0 is stable, +while forcing mode 2 introduces CRC errors especially during bursts. + +Drop the requirement on spi-cpol for SJA1110. + +Fixes: af2eab1a8243 ("dt-bindings: net: nxp,sja1105: document spi-cpol/cpha") +Signed-off-by: Josua Mayer +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260409-imx8dxl-sr-som-v2-1-83ff20629ba0@solid-run.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +index 607b7fe8d28ee..0486489114cd8 100644 +--- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml ++++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +@@ -143,8 +143,6 @@ allOf: + else: + properties: + spi-cpha: false +- required: +- - spi-cpol + + unevaluatedProperties: false + +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-pci-imx6q-pcie-fix-maxitems-of-clocks-an.patch b/queue-7.0/dt-bindings-pci-imx6q-pcie-fix-maxitems-of-clocks-an.patch new file mode 100644 index 0000000000..96b7313182 --- /dev/null +++ b/queue-7.0/dt-bindings-pci-imx6q-pcie-fix-maxitems-of-clocks-an.patch @@ -0,0 +1,63 @@ +From ea793c1524fe645162ad7ff1d4698a0c460e3ed5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:30:32 +0800 +Subject: dt-bindings: PCI: imx6q-pcie: Fix maxItems of clocks and clock-names + +From: Richard Zhu + +[ Upstream commit 401359ef44af43b6b775dc01bb7b31396db67aab ] + +Commit 1352f58d7c8d ("dt-bindings: PCI: pci-imx6: Add external reference +clock input") that added reference clock to the binding was incomplete. + +The constraints for "clocks" and "clock-names" still enforce an incorrect +number of items. Update maxItems for both properties to 6 to match the +actual hardware configuration. + +Fixes: 1352f58d7c8d ("dt-bindings: PCI: pci-imx6: Add external reference clock input") +Signed-off-by: Richard Zhu +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/20260324023036.784466-2-hongxing.zhu@nxp.com +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml | 4 ++-- + Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml | 3 ++- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml +index cddbe21f99f2b..0488c942092d6 100644 +--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml ++++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie-common.yaml +@@ -17,11 +17,11 @@ description: + properties: + clocks: + minItems: 3 +- maxItems: 5 ++ maxItems: 6 + + clock-names: + minItems: 3 +- maxItems: 5 ++ maxItems: 6 + + num-lanes: + const: 1 +diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml +index 12a01f7a57443..21dda80660147 100644 +--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml ++++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml +@@ -40,7 +40,8 @@ properties: + - description: PCIe PHY clock. + - description: Additional required clock entry for imx6sx-pcie, + imx6sx-pcie-ep, imx8mq-pcie, imx8mq-pcie-ep. +- - description: PCIe reference clock. ++ - description: PCIe internal reference clock. ++ - description: PCIe additional external reference clock. + + clock-names: + minItems: 3 +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-pci-renesas-r9a08g045s33-pcie-fix-naming.patch b/queue-7.0/dt-bindings-pci-renesas-r9a08g045s33-pcie-fix-naming.patch new file mode 100644 index 0000000000..1e42fad84c --- /dev/null +++ b/queue-7.0/dt-bindings-pci-renesas-r9a08g045s33-pcie-fix-naming.patch @@ -0,0 +1,107 @@ +From 7aa35e2bf08de4608f75bab0460b9d0841c87034 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 15:34:12 +0100 +Subject: dt-bindings: PCI: renesas,r9a08g045s33-pcie: Fix naming properties + +From: John Madieu + +[ Upstream commit bb1b0f47f6822864c1689f46348efa42c5d4074c ] + +Fix a typo in interrupt-names: "ser_cor" should be "serr_cor" (System +Error Correctable). + +Also convert interrupt-names, clock-names, and reset-names properties +from "description" to "const" to enable proper validation with +dtbs_check. + +Fixes: e7534e790557 ("dt-bindings: PCI: Add Renesas RZ/G3S PCIe controller binding") +Signed-off-by: John Madieu +Signed-off-by: Manivannan Sadhasivam +Tested-by: Lad Prabhakar # RZ/V2N EVK +Tested-by: Claudiu Beznea +Reviewed-by: Claudiu Beznea +Acked-by: Conor Dooley +Link: https://patch.msgid.link/20260306143423.19562-6-john.madieu.xa@bp.renesas.com +Signed-off-by: Sasha Levin +--- + .../bindings/pci/renesas,r9a08g045-pcie.yaml | 50 +++++++++---------- + 1 file changed, 25 insertions(+), 25 deletions(-) + +diff --git a/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml b/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml +index d668782546a23..d1eb92995e2c3 100644 +--- a/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml ++++ b/Documentation/devicetree/bindings/pci/renesas,r9a08g045-pcie.yaml +@@ -41,22 +41,22 @@ properties: + + interrupt-names: + items: +- - description: serr +- - description: ser_cor +- - description: serr_nonfatal +- - description: serr_fatal +- - description: axi_err +- - description: inta +- - description: intb +- - description: intc +- - description: intd +- - description: msi +- - description: link_bandwidth +- - description: pm_pme +- - description: dma +- - description: pcie_evt +- - description: msg +- - description: all ++ - const: serr ++ - const: serr_cor ++ - const: serr_nonfatal ++ - const: serr_fatal ++ - const: axi_err ++ - const: inta ++ - const: intb ++ - const: intc ++ - const: intd ++ - const: msi ++ - const: link_bandwidth ++ - const: pm_pme ++ - const: dma ++ - const: pcie_evt ++ - const: msg ++ - const: all + + interrupt-controller: true + +@@ -67,8 +67,8 @@ properties: + + clock-names: + items: +- - description: aclk +- - description: pm ++ - const: aclk ++ - const: pm + + resets: + items: +@@ -82,13 +82,13 @@ properties: + + reset-names: + items: +- - description: aresetn +- - description: rst_b +- - description: rst_gp_b +- - description: rst_ps_b +- - description: rst_rsm_b +- - description: rst_cfg_b +- - description: rst_load_b ++ - const: aresetn ++ - const: rst_b ++ - const: rst_gp_b ++ - const: rst_ps_b ++ - const: rst_rsm_b ++ - const: rst_cfg_b ++ - const: rst_load_b + + power-domains: + maxItems: 1 +-- +2.53.0 + diff --git a/queue-7.0/dt-bindings-pinctrl-marvell-armada3710-xb-pinctrl-ad.patch b/queue-7.0/dt-bindings-pinctrl-marvell-armada3710-xb-pinctrl-ad.patch new file mode 100644 index 0000000000..9bae0d9f12 --- /dev/null +++ b/queue-7.0/dt-bindings-pinctrl-marvell-armada3710-xb-pinctrl-ad.patch @@ -0,0 +1,72 @@ +From 2beb595c488fa7209e3798336f280c112641177a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:15:54 +0100 +Subject: dt-bindings: pinctrl: marvell,armada3710-xb-pinctrl: add missing + items keyword + +From: Gabor Juhos + +[ Upstream commit a92b75100826b1ea27e6b8a678e53970ad4736d7 ] + +Even though the type of the 'groups' property of a pinmux node is +specified as string-array in pinmux-node.yaml, but trying to use +multiple strings causes dtbs_check warnings. + +For example, checking the following dts ... + + $ cat arch/arm64/boot/dts/marvell/armada-3720-test.dts + /dts-v1/; + + #include "armada-372x.dtsi" + + &pinctrl_nb { + pwm-gpio-pins { + groups = "pwm0", "pwm1", "pwm2", "pwm3"; + function = "gpio"; + }; + }; + +... results in this warning: + + arch/arm64/boot/dts/marvell/armada-3720-test.dtb: pinctrl@13800 (marvell,armada3710-nb-pinctrl): pwm-gpio-pins:groups: ['pwm0', 'pwm1', 'pwm2', 'pwm3'] is too long + from schema $id: http://devicetree.org/schemas/pinctrl/marvell,armada3710-xb-pinctrl.yaml + +Add the missing 'items' keyword to the schema to allow using multiple +strings without such warnings. Also adjust the indentation of the next +statements accordingly. + +Signed-off-by: Gabor Juhos +Acked-by: Conor Dooley +Fixes: c1c9641a04e83 ("dt-bindings: pinctrl: Convert marvell,armada-3710-(sb|nb)-pinctrl to DT schema") +Reviewed-by: Miquel Raynal +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + .../pinctrl/marvell,armada3710-xb-pinctrl.yaml | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada3710-xb-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/marvell,armada3710-xb-pinctrl.yaml +index 4f9013d368749..727da7fb490ce 100644 +--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada3710-xb-pinctrl.yaml ++++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada3710-xb-pinctrl.yaml +@@ -84,11 +84,12 @@ patternProperties: + + properties: + groups: +- enum: [ emmc_nb, i2c1, i2c2, jtag, mii_col, onewire, pcie1, +- pcie1_clkreq, pcie1_wakeup, pmic0, pmic1, ptp, ptp_clk, +- ptp_trig, pwm0, pwm1, pwm2, pwm3, rgmii, sdio0, sdio_sb, smi, +- spi_cs1, spi_cs2, spi_cs3, spi_quad, uart1, uart2, +- usb2_drvvbus1, usb32_drvvbus0 ] ++ items: ++ enum: [ emmc_nb, i2c1, i2c2, jtag, mii_col, onewire, pcie1, ++ pcie1_clkreq, pcie1_wakeup, pmic0, pmic1, ptp, ptp_clk, ++ ptp_trig, pwm0, pwm1, pwm2, pwm3, rgmii, sdio0, sdio_sb, ++ smi, spi_cs1, spi_cs2, spi_cs3, spi_quad, uart1, uart2, ++ usb2_drvvbus1, usb32_drvvbus0 ] + + function: + enum: [ drvbus, emmc, gpio, i2c, jtag, led, mii, mii_err, onewire, +-- +2.53.0 + diff --git a/queue-7.0/e1000e-unroll-ptp-in-probe-error-handling.patch b/queue-7.0/e1000e-unroll-ptp-in-probe-error-handling.patch new file mode 100644 index 0000000000..ae414386d4 --- /dev/null +++ b/queue-7.0/e1000e-unroll-ptp-in-probe-error-handling.patch @@ -0,0 +1,41 @@ +From e33e78c39c165cdae60c717c7ac8ec70f72d33ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:36 -0700 +Subject: e1000e: Unroll PTP in probe error handling + +From: Matt Vollrath + +[ Upstream commit aa3f7fe409350857c25d050482a2eef2cfd69b58 ] + +If probe fails after registering the PTP clock and its delayed work, +these resources must be released. + +This was not an issue until a 2016 fix moved the e1000e_ptp_init() call +before the jump to err_register. + +Fixes: aa524b66c5ef ("e1000e: don't modify SYSTIM registers during SIOCSHWTSTAMP ioctl") +Signed-off-by: Matt Vollrath +Tested-by: Avigail Dahan +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-12-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 9befdacd67301..7ce0cc8ab8f4c 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -7706,6 +7706,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + err_register: + if (!(adapter->flags & FLAG_HAS_AMT)) + e1000e_release_hw_control(adapter); ++ e1000e_ptp_remove(adapter); + err_eeprom: + if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block(hw)) + e1000_phy_hw_reset(&adapter->hw); +-- +2.53.0 + diff --git a/queue-7.0/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch b/queue-7.0/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch new file mode 100644 index 0000000000..18fca6fb5f --- /dev/null +++ b/queue-7.0/efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch @@ -0,0 +1,52 @@ +From 73d57c77f9e59b620080e78ed4153e03078ed3fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:46:37 +0200 +Subject: efi/capsule-loader: fix incorrect sizeof in phys array reallocation + +From: Thomas Huth + +[ Upstream commit 48a428215782321b56956974f23593e40ce84b7a ] + +The krealloc() call for cap_info->phys in __efi_capsule_setup_info() uses +sizeof(phys_addr_t *) instead of sizeof(phys_addr_t), which might be +causing an undersized allocation. + +The allocation is also inconsistent with the initial array allocation in +efi_capsule_open() that allocates one entry with sizeof(phys_addr_t), +and the efi_capsule_write() function that stores phys_addr_t values (not +pointers) via page_to_phys(). + +On 64-bit systems where sizeof(phys_addr_t) == sizeof(phys_addr_t *), this +goes unnoticed. On 32-bit systems with PAE where phys_addr_t is 64-bit but +pointers are 32-bit, this allocates half the required space, which might +lead to a heap buffer overflow when storing physical addresses. + +This is similar to the bug fixed in commit fccfa646ef36 ("efi/capsule-loader: +fix incorrect allocation size") which fixed the same issue at the initial +allocation site. + +Fixes: f24c4d478013 ("efi/capsule-loader: Reinstate virtual capsule mapping") +Assisted-by: Claude:claude-sonnet-4-5 +Signed-off-by: Thomas Huth +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + drivers/firmware/efi/capsule-loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c +index 2c628a1270919..8e8f81f0a5a0a 100644 +--- a/drivers/firmware/efi/capsule-loader.c ++++ b/drivers/firmware/efi/capsule-loader.c +@@ -67,7 +67,7 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) + cap_info->pages = temp_page; + + temp_page = krealloc(cap_info->phys, +- pages_needed * sizeof(phys_addr_t *), ++ pages_needed * sizeof(phys_addr_t), + GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-7.0/erofs-fix-offset-truncation-when-shifting-pgoff-on-3.patch b/queue-7.0/erofs-fix-offset-truncation-when-shifting-pgoff-on-3.patch new file mode 100644 index 0000000000..4bd8bf8d4b --- /dev/null +++ b/queue-7.0/erofs-fix-offset-truncation-when-shifting-pgoff-on-3.patch @@ -0,0 +1,55 @@ +From 8a07cf20194525f10f6d694510d07f5baef0d4a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 11:46:12 +0800 +Subject: erofs: fix offset truncation when shifting pgoff on 32-bit platforms + +From: Gao Xiang + +[ Upstream commit c99493ce409c3b98fec1616dbcf24c102e006deb ] + +On 32-bit platforms, pgoff_t is 32 bits wide, so left-shifting +large arbitrary pgoff_t values by PAGE_SHIFT performs 32-bit arithmetic +and silently truncates the result for pages beyond the 4 GiB boundary. + +Cast the page index to loff_t before shifting to produce a correct +64-bit byte offset. + +Fixes: 386292919c25 ("erofs: introduce readmore decompression strategy") +Fixes: 307210c262a2 ("erofs: verify metadata accesses for file-backed mounts") +Reviewed-by: Chao Yu +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/data.c | 2 +- + fs/erofs/zdata.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/erofs/data.c b/fs/erofs/data.c +index 132a27deb2f3b..b2c12c5856acc 100644 +--- a/fs/erofs/data.c ++++ b/fs/erofs/data.c +@@ -39,7 +39,7 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap) + * However, the data access range must be verified here in advance. + */ + if (buf->file) { +- fpos = index << PAGE_SHIFT; ++ fpos = (loff_t)index << PAGE_SHIFT; + err = rw_verify_area(READ, buf->file, &fpos, PAGE_SIZE); + if (err < 0) + return ERR_PTR(err); +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index fe8121df9ef2f..624b83ff4ecb7 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -1874,7 +1874,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_frontend *f, + + if (cur < PAGE_SIZE) + break; +- cur = (index << PAGE_SHIFT) - 1; ++ cur = ((loff_t)index << PAGE_SHIFT) - 1; + } + } + +-- +2.53.0 + diff --git a/queue-7.0/erofs-handle-48-bit-blocks-uniaddr-for-extra-devices.patch b/queue-7.0/erofs-handle-48-bit-blocks-uniaddr-for-extra-devices.patch new file mode 100644 index 0000000000..d625a6a518 --- /dev/null +++ b/queue-7.0/erofs-handle-48-bit-blocks-uniaddr-for-extra-devices.patch @@ -0,0 +1,83 @@ +From 9fd3bdea44304e0a3cb756130c330ef09a676944 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 14:36:58 +0800 +Subject: erofs: handle 48-bit blocks/uniaddr for extra devices + +From: Zhan Xusheng + +[ Upstream commit 63c2f06198ca7513433f1c92f2c654869d72417e ] + +erofs_init_device() only reads blocks_lo and uniaddr_lo from the +on-disk device slot, ignoring blocks_hi and uniaddr_hi that were +introduced alongside the 48-bit block addressing feature. + +For the primary device (dif0), erofs_read_superblock() already handles +this correctly by combining blocks_lo with blocks_hi when 48-bit +layout is enabled. But the same logic was not applied to extra +devices. + +With a 48-bit EROFS image using extra devices whose uniaddr or blocks +exceed 32-bit range, the truncated values cause erofs_map_dev() to +compute wrong physical addresses, leading to silent data corruption. + +Fix this by reading blocks_hi and uniaddr_hi in erofs_init_device() +when 48-bit layout is enabled, consistent with the primary device +handling. Also fix the erofs_deviceslot on-disk definition where +blocks_hi was incorrectly declared as __le32 instead of __le16. + +Fixes: 61ba89b57905 ("erofs: add 48-bit block addressing on-disk support") +Suggested-by: Gao Xiang +Signed-off-by: Zhan Xusheng +Reviewed-by: Gao Xiang +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/erofs_fs.h | 4 ++-- + fs/erofs/super.c | 8 ++++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h +index b80c6bb33a58c..7871b16c1d333 100644 +--- a/fs/erofs/erofs_fs.h ++++ b/fs/erofs/erofs_fs.h +@@ -44,9 +44,9 @@ struct erofs_deviceslot { + u8 tag[64]; /* digest(sha256), etc. */ + __le32 blocks_lo; /* total blocks count of this device */ + __le32 uniaddr_lo; /* unified starting block of this device */ +- __le32 blocks_hi; /* total blocks count MSB */ ++ __le16 blocks_hi; /* total blocks count MSB */ + __le16 uniaddr_hi; /* unified starting block MSB */ +- u8 reserved[50]; ++ u8 reserved[52]; + }; + #define EROFS_DEVT_SLOT_SIZE sizeof(struct erofs_deviceslot) + +diff --git a/fs/erofs/super.c b/fs/erofs/super.c +index 972a0c82198d7..802add6652fda 100644 +--- a/fs/erofs/super.c ++++ b/fs/erofs/super.c +@@ -129,6 +129,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb, + struct erofs_fscache *fscache; + struct erofs_deviceslot *dis; + struct file *file; ++ bool _48bit; + + dis = erofs_read_metabuf(buf, sb, *pos, false); + if (IS_ERR(dis)) +@@ -175,8 +176,11 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb, + dif->file = file; + } + +- dif->blocks = le32_to_cpu(dis->blocks_lo); +- dif->uniaddr = le32_to_cpu(dis->uniaddr_lo); ++ _48bit = erofs_sb_has_48bit(sbi); ++ dif->blocks = le32_to_cpu(dis->blocks_lo) | ++ (_48bit ? (u64)le16_to_cpu(dis->blocks_hi) << 32 : 0); ++ dif->uniaddr = le32_to_cpu(dis->uniaddr_lo) | ++ (_48bit ? (u64)le16_to_cpu(dis->uniaddr_hi) << 32 : 0); + sbi->total_blocks += dif->blocks; + *pos += EROFS_DEVT_SLOT_SIZE; + return 0; +-- +2.53.0 + diff --git a/queue-7.0/erofs-include-the-trailing-nul-in-fs_ioc_getfslabel.patch b/queue-7.0/erofs-include-the-trailing-nul-in-fs_ioc_getfslabel.patch new file mode 100644 index 0000000000..c1a1e18742 --- /dev/null +++ b/queue-7.0/erofs-include-the-trailing-nul-in-fs_ioc_getfslabel.patch @@ -0,0 +1,45 @@ +From 5c702bf92882b40f30da68cb78f368a346ed8dbc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 14:13:42 +0800 +Subject: erofs: include the trailing NUL in FS_IOC_GETFSLABEL + +From: Zhan Xusheng + +[ Upstream commit d6250d49da4d8f11afc0d8991c84e0307949f92e ] + +erofs_ioctl_get_volume_label() passes strlen(sbi->volume_name) as +the length to copy_to_user(), which copies the label string without +the trailing NUL byte. Since FS_IOC_GETFSLABEL callers expect a +NUL-terminated string in the FSLABEL_MAX-sized buffer and may not +pre-zero the buffer, this can cause userspace to read past the label +into uninitialised stack memory. + +Fix this by using strlen() + 1 to include the NUL terminator, +consistent with how ext4 and xfs implement FS_IOC_GETFSLABEL. + +Signed-off-by: Zhan Xusheng +Fixes: 1cf12c717741 ("erofs: Add support for FS_IOC_GETFSLABEL") +Reviewed-by: Gao Xiang +Reviewed-by: Chunhai Guo +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c +index 4b3d21402e101..a188c570087ae 100644 +--- a/fs/erofs/inode.c ++++ b/fs/erofs/inode.c +@@ -351,7 +351,7 @@ static int erofs_ioctl_get_volume_label(struct inode *inode, void __user *arg) + ret = clear_user(arg, 1); + else + ret = copy_to_user(arg, sbi->volume_name, +- strlen(sbi->volume_name)); ++ strlen(sbi->volume_name) + 1); + return ret ? -EFAULT : 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch b/queue-7.0/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch new file mode 100644 index 0000000000..90176b3ad0 --- /dev/null +++ b/queue-7.0/erofs-unify-lcn-as-u64-for-32-bit-platforms.patch @@ -0,0 +1,115 @@ +From 8de3500607f1ffca7b9ab471c6348ea9e353e1e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 18:11:42 +0800 +Subject: erofs: unify lcn as u64 for 32-bit platforms + +From: Gao Xiang + +[ Upstream commit 2d8c7edcb661812249469f4a5b62e9339118846f ] + +As sashiko reported [1], `lcn` was typed as `unsigned long` (or +`unsigned int` sometimes), which is only 32 bits wide on 32-bit +platforms, which causes `(lcn << lclusterbits)` to be truncated +at 4 GiB. + +In order to consolidate the logic, just use `u64` consistently +around the codebase. + +[1] https://sashiko.dev/r/20260420034612.1899973-1-hsiangkao%40linux.alibaba.com + +Fixes: 152a333a5895 ("staging: erofs: add compacted compression indexes support") +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/zmap.c | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c +index 30775502b56da..abf7ddc64c63b 100644 +--- a/fs/erofs/zmap.c ++++ b/fs/erofs/zmap.c +@@ -10,7 +10,7 @@ + struct z_erofs_maprecorder { + struct inode *inode; + struct erofs_map_blocks *map; +- unsigned long lcn; ++ u64 lcn; + /* compression extent information gathered */ + u8 type, headtype; + u16 clusterofs; +@@ -20,8 +20,7 @@ struct z_erofs_maprecorder { + bool partialref, in_mbox; + }; + +-static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, +- unsigned long lcn) ++static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m, u64 lcn) + { + struct inode *const inode = m->inode; + struct erofs_inode *const vi = EROFS_I(inode); +@@ -94,7 +93,7 @@ static int get_compacted_la_distance(unsigned int lobits, + } + + static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, +- unsigned long lcn, bool lookahead) ++ u64 lcn, bool lookahead) + { + struct inode *const inode = m->inode; + struct erofs_inode *const vi = EROFS_I(inode); +@@ -234,7 +233,7 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m, + } + + static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m, +- unsigned int lcn, bool lookahead) ++ u64 lcn, bool lookahead) + { + struct erofs_inode *vi = EROFS_I(m->inode); + int err; +@@ -249,7 +248,7 @@ static int z_erofs_load_lcluster_from_disk(struct z_erofs_maprecorder *m, + return err; + + if (m->type >= Z_EROFS_LCLUSTER_TYPE_MAX) { +- erofs_err(m->inode->i_sb, "unknown type %u @ lcn %u of nid %llu", ++ erofs_err(m->inode->i_sb, "unknown type %u @ lcn %llu of nid %llu", + m->type, lcn, EROFS_I(m->inode)->nid); + DBG_BUGON(1); + return -EOPNOTSUPP; +@@ -269,7 +268,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, + const unsigned int lclusterbits = vi->z_lclusterbits; + + while (m->lcn >= lookback_distance) { +- unsigned long lcn = m->lcn - lookback_distance; ++ u64 lcn = m->lcn - lookback_distance; + int err; + + if (!lookback_distance) +@@ -286,7 +285,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, + m->map->m_la = (lcn << lclusterbits) | m->clusterofs; + return 0; + } +- erofs_err(sb, "bogus lookback distance %u @ lcn %lu of nid %llu", ++ erofs_err(sb, "bogus lookback distance %u @ lcn %llu of nid %llu", + lookback_distance, m->lcn, vi->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; +@@ -300,7 +299,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + struct erofs_inode *vi = EROFS_I(inode); + bool bigpcl1 = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1; + bool bigpcl2 = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2; +- unsigned long lcn = m->lcn + 1; ++ u64 lcn = m->lcn + 1; + int err; + + DBG_BUGON(m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD); +@@ -331,7 +330,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, + m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD); + + if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD && m->delta[0] != 1) { +- erofs_err(sb, "bogus CBLKCNT @ lcn %lu of nid %llu", lcn, vi->nid); ++ erofs_err(sb, "bogus CBLKCNT @ lcn %llu of nid %llu", lcn, vi->nid); + DBG_BUGON(1); + return -EFSCORRUPTED; + } +-- +2.53.0 + diff --git a/queue-7.0/erofs-verify-metadata-accesses-for-file-backed-mount.patch b/queue-7.0/erofs-verify-metadata-accesses-for-file-backed-mount.patch new file mode 100644 index 0000000000..b63c41ca6b --- /dev/null +++ b/queue-7.0/erofs-verify-metadata-accesses-for-file-backed-mount.patch @@ -0,0 +1,58 @@ +From 4c99f30a9b495a26c4a94db9f74cbe202eded2ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 10:29:29 +0800 +Subject: erofs: verify metadata accesses for file-backed mounts + +From: Gao Xiang + +[ Upstream commit 307210c262a29f41d7177851295ea1703bd04175 ] + +For file-backed mounts, metadata is fetched via the page cache of +backing inodes to avoid double caching and redundant copy ops out +of RO uptodate folios, which is used by Android APEXes, ComposeFS, +containerd. However, rw_verify_area() was missing prior to +metadata accesses. + +Similar to vfs_iocb_iter_read(), fix this by: + - Enabling fanotify pre-content hooks on metadata accesses; + - security_file_permission() for security modules. + +Verified that fanotify pre-content hooks now works correctly. + +Fixes: fb176750266a ("erofs: add file-backed mount support") +Acked-by: Amir Goldstein +Reviewed-by: Chunhai Guo +Signed-off-by: Gao Xiang +Signed-off-by: Sasha Levin +--- + fs/erofs/data.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/fs/erofs/data.c b/fs/erofs/data.c +index f79ee80627d95..132a27deb2f3b 100644 +--- a/fs/erofs/data.c ++++ b/fs/erofs/data.c +@@ -30,6 +30,20 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap) + { + pgoff_t index = (buf->off + offset) >> PAGE_SHIFT; + struct folio *folio = NULL; ++ loff_t fpos; ++ int err; ++ ++ /* ++ * Metadata access for file-backed mounts reuses page cache of backing ++ * fs inodes (only folio data will be needed) to prevent double caching. ++ * However, the data access range must be verified here in advance. ++ */ ++ if (buf->file) { ++ fpos = index << PAGE_SHIFT; ++ err = rw_verify_area(READ, buf->file, &fpos, PAGE_SIZE); ++ if (err < 0) ++ return ERR_PTR(err); ++ } + + if (buf->page) { + folio = page_folio(buf->page); +-- +2.53.0 + diff --git a/queue-7.0/eth-fbnic-use-wake-instead-of-start.patch b/queue-7.0/eth-fbnic-use-wake-instead-of-start.patch new file mode 100644 index 0000000000..75e3d2f884 --- /dev/null +++ b/queue-7.0/eth-fbnic-use-wake-instead-of-start.patch @@ -0,0 +1,44 @@ +From 048935c31867380d8c3f8274b227810c42faad58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:24:15 -0700 +Subject: eth: fbnic: Use wake instead of start + +From: Mohsin Bashir + +[ Upstream commit 12ff2a4aee6c86746623d5aed24389dbf6dffded ] + +fbnic_up() calls netif_tx_start_all_queues(), which only clears +__QUEUE_STATE_DRV_XOFF. If qdisc backlog has accumulated on any TX +queue before the reconfiguration (e.g. ring resize via ethtool -G), +start does not call __netif_schedule() to kick the qdisc, so the +pending backlog is never drained and the queue stalls. + +Switch to netif_tx_wake_all_queues(), which clears DRV_XOFF and also +calls __netif_schedule() on every queue, ensuring any backlog that +built up before the down/up cycle is promptly dequeued. + +Fixes: bc6107771bb4 ("eth: fbnic: Allocate a netdevice and napi vectors with queues") +Signed-off-by: Mohsin Bashir +Link: https://patch.msgid.link/20260408002415.2963915-1-mohsin.bashr@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/meta/fbnic/fbnic_pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +index 3fa9d1910daa1..8f331358c9725 100644 +--- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c ++++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +@@ -139,7 +139,7 @@ void fbnic_up(struct fbnic_net *fbn) + + /* Enable Tx/Rx processing */ + fbnic_napi_enable(fbn); +- netif_tx_start_all_queues(fbn->netdev); ++ netif_tx_wake_all_queues(fbn->netdev); + + fbnic_service_task_start(fbn); + +-- +2.53.0 + diff --git a/queue-7.0/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch b/queue-7.0/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch new file mode 100644 index 0000000000..3dafa3dab2 --- /dev/null +++ b/queue-7.0/eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch @@ -0,0 +1,69 @@ +From 28907a767e5a389eca18a9e1bf7c0425f8b4b8e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 00:23:18 +0200 +Subject: eventpoll: drop vestigial __ prefix from ep_remove_{file,epi}() + +From: Christian Brauner + +[ Upstream commit 0feaf644f7180c4a91b6b405a881afbfd958f1cf ] + +With __ep_remove() gone, the double-underscore on __ep_remove_file() +and __ep_remove_epi() no longer contrasts with a __-less parent and +just reads as noise. Rename both to ep_remove_file() and +ep_remove_epi(). No functional change. + +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index c45995e790cfb..14bc5b355f0e2 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -830,7 +830,7 @@ static void ep_free(struct eventpoll *ep) + * Called with &file->f_lock held, + * returns with it released + */ +-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, ++static void ep_remove_file(struct eventpoll *ep, struct epitem *epi, + struct file *file) + { + struct epitems_head *to_free = NULL; +@@ -854,7 +854,7 @@ static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, + free_ephead(to_free); + } + +-static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi) ++static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi) + { + lockdep_assert_held(&ep->mtx); + +@@ -900,9 +900,9 @@ static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi) + spin_unlock(&file->f_lock); + return; + } +- __ep_remove_file(ep, epi, file); ++ ep_remove_file(ep, epi, file); + +- if (__ep_remove_epi(ep, epi)) ++ if (ep_remove_epi(ep, epi)) + WARN_ON_ONCE(ep_refcount_dec_and_test(ep)); + } + +@@ -1147,8 +1147,8 @@ void eventpoll_release_file(struct file *file) + ep_unregister_pollwait(ep, epi); + + spin_lock(&file->f_lock); +- __ep_remove_file(ep, epi, file); +- dispose = __ep_remove_epi(ep, epi); ++ ep_remove_file(ep, epi, file); ++ dispose = ep_remove_epi(ep, epi); + + mutex_unlock(&ep->mtx); + +-- +2.53.0 + diff --git a/queue-7.0/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch b/queue-7.0/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch new file mode 100644 index 0000000000..d4582a88ed --- /dev/null +++ b/queue-7.0/eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch @@ -0,0 +1,99 @@ +From daa9d4f768d5a30f0c1650d53aa3a690cc569ca8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:09 +0200 +Subject: eventpoll: fix ep_remove struct eventpoll / struct file UAF + +From: Christian Brauner + +[ Upstream commit a6dc643c69311677c574a0f17a3f4d66a5f3744b ] + +ep_remove() (via ep_remove_file()) cleared file->f_ep under +file->f_lock but then kept using @file inside the critical section +(is_file_epoll(), hlist_del_rcu() through the head, spin_unlock). +A concurrent __fput() taking the eventpoll_release() fastpath in +that window observed the transient NULL, skipped +eventpoll_release_file() and ran to f_op->release / file_free(). + +For the epoll-watches-epoll case, f_op->release is +ep_eventpoll_release() -> ep_clear_and_put() -> ep_free(), which +kfree()s the watched struct eventpoll. Its embedded ->refs +hlist_head is exactly where epi->fllink.pprev points, so the +subsequent hlist_del_rcu()'s "*pprev = next" scribbles into freed +kmalloc-192 memory. + +In addition, struct file is SLAB_TYPESAFE_BY_RCU, so the slot +backing @file could be recycled by alloc_empty_file() -- +reinitializing f_lock and f_ep -- while ep_remove() is still +nominally inside that lock. The upshot is an attacker-controllable +kmem_cache_free() against the wrong slab cache. + +Pin @file via epi_fget() at the top of ep_remove() and gate the +critical section on the pin succeeding. With the pin held @file +cannot reach refcount zero, which holds __fput() off and +transitively keeps the watched struct eventpoll alive across the +hlist_del_rcu() and the f_lock use, closing both UAFs. + +If the pin fails @file has already reached refcount zero and its +__fput() is in flight. Because we bailed before clearing f_ep, +that path takes the eventpoll_release() slow path into +eventpoll_release_file() and blocks on ep->mtx until the waiter +side's ep_clear_and_put() drops it. The bailed epi's share of +ep->refcount stays intact, so the trailing ep_refcount_dec_and_test() +in ep_clear_and_put() cannot free the eventpoll out from under +eventpoll_release_file(); the orphaned epi is then cleaned up +there. + +A successful pin also proves we are not racing +eventpoll_release_file() on this epi, so drop the now-redundant +re-check of epi->dying under f_lock. The cheap lockless +READ_ONCE(epi->dying) fast-path bailout stays. + +Fixes: 58c9b016e128 ("epoll: use refcount to reduce ep_mutex contention") +Reported-by: Jaeyoung Chung +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-6-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 4971074ab476a..8c03de028c482 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -912,22 +912,26 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi) + */ + static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi) + { +- struct file *file = epi->ffd.file; ++ struct file *file __free(fput) = NULL; + + lockdep_assert_irqs_enabled(); + lockdep_assert_held(&ep->mtx); + + ep_unregister_pollwait(ep, epi); + +- /* sync with eventpoll_release_file() */ ++ /* cheap sync with eventpoll_release_file() */ + if (unlikely(READ_ONCE(epi->dying))) + return; + +- spin_lock(&file->f_lock); +- if (epi->dying) { +- spin_unlock(&file->f_lock); ++ /* ++ * If we manage to grab a reference it means we're not in ++ * eventpoll_release_file() and aren't going to be. ++ */ ++ file = epi_fget(epi); ++ if (!file) + return; +- } ++ ++ spin_lock(&file->f_lock); + ep_remove_file(ep, epi, file); + + if (ep_remove_epi(ep, epi)) +-- +2.53.0 + diff --git a/queue-7.0/eventpoll-kill-__ep_remove.patch b/queue-7.0/eventpoll-kill-__ep_remove.patch new file mode 100644 index 0000000000..d312004f29 --- /dev/null +++ b/queue-7.0/eventpoll-kill-__ep_remove.patch @@ -0,0 +1,132 @@ +From 33ca6f8d512784b17bbd84b5c6113c958f9c98be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:06 +0200 +Subject: eventpoll: kill __ep_remove() + +From: Christian Brauner + +[ Upstream commit e9e5cd40d7c403e19f21d0f7b8b8ba3a76b58330 ] + +Remove the boolean conditional in __ep_remove() and restructure the code +so the check for racing with eventpoll_release_file() are only done in +the ep_remove_safe() path where they belong. + +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-3-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 67 ++++++++++++++++++++++---------------------------- + 1 file changed, 30 insertions(+), 37 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 99188c30fe6c7..c45995e790cfb 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -826,49 +826,18 @@ static void ep_free(struct eventpoll *ep) + kfree_rcu(ep, rcu); + } + +-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file); +-static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi); +- +-/* +- * Removes a "struct epitem" from the eventpoll RB tree and deallocates +- * all the associated resources. Must be called with "mtx" held. +- * If the dying flag is set, do the removal only if force is true. +- * This prevents ep_clear_and_put() from dropping all the ep references +- * while running concurrently with eventpoll_release_file(). +- * Returns true if the eventpoll can be disposed. +- */ +-static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) +-{ +- struct file *file = epi->ffd.file; +- +- lockdep_assert_irqs_enabled(); +- +- /* +- * Removes poll wait queue hooks. +- */ +- ep_unregister_pollwait(ep, epi); +- +- /* Remove the current item from the list of epoll hooks */ +- spin_lock(&file->f_lock); +- if (epi->dying && !force) { +- spin_unlock(&file->f_lock); +- return false; +- } +- +- __ep_remove_file(ep, epi, file); +- return __ep_remove_epi(ep, epi); +-} +- + /* + * Called with &file->f_lock held, + * returns with it released + */ +-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file) ++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, ++ struct file *file) + { + struct epitems_head *to_free = NULL; + struct hlist_head *head = file->f_ep; + + lockdep_assert_held(&ep->mtx); ++ lockdep_assert_held(&file->f_lock); + + if (hlist_is_singular_node(&epi->fllink, head)) { + /* See eventpoll_release() for details. */ +@@ -915,7 +884,25 @@ static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi) + */ + static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi) + { +- if (__ep_remove(ep, epi, false)) ++ struct file *file = epi->ffd.file; ++ ++ lockdep_assert_irqs_enabled(); ++ lockdep_assert_held(&ep->mtx); ++ ++ ep_unregister_pollwait(ep, epi); ++ ++ /* sync with eventpoll_release_file() */ ++ if (unlikely(READ_ONCE(epi->dying))) ++ return; ++ ++ spin_lock(&file->f_lock); ++ if (epi->dying) { ++ spin_unlock(&file->f_lock); ++ return; ++ } ++ __ep_remove_file(ep, epi, file); ++ ++ if (__ep_remove_epi(ep, epi)) + WARN_ON_ONCE(ep_refcount_dec_and_test(ep)); + } + +@@ -1147,7 +1134,7 @@ void eventpoll_release_file(struct file *file) + spin_lock(&file->f_lock); + if (file->f_ep && file->f_ep->first) { + epi = hlist_entry(file->f_ep->first, struct epitem, fllink); +- epi->dying = true; ++ WRITE_ONCE(epi->dying, true); + spin_unlock(&file->f_lock); + + /* +@@ -1156,7 +1143,13 @@ void eventpoll_release_file(struct file *file) + */ + ep = epi->ep; + mutex_lock(&ep->mtx); +- dispose = __ep_remove(ep, epi, true); ++ ++ ep_unregister_pollwait(ep, epi); ++ ++ spin_lock(&file->f_lock); ++ __ep_remove_file(ep, epi, file); ++ dispose = __ep_remove_epi(ep, epi); ++ + mutex_unlock(&ep->mtx); + + if (dispose && ep_refcount_dec_and_test(ep)) +-- +2.53.0 + diff --git a/queue-7.0/eventpoll-move-epi_fget-up.patch b/queue-7.0/eventpoll-move-epi_fget-up.patch new file mode 100644 index 0000000000..35d6b9e01b --- /dev/null +++ b/queue-7.0/eventpoll-move-epi_fget-up.patch @@ -0,0 +1,96 @@ +From 59694f18153ca3d3cde5e6d44509915eb1c93b77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:08 +0200 +Subject: eventpoll: move epi_fget() up + +From: Christian Brauner + +[ Upstream commit 86e87059e6d1fd5115a31949726450ed03c1073b ] + +We'll need it when removing files so move it up. No functional change. + +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-5-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 56 +++++++++++++++++++++++++------------------------- + 1 file changed, 28 insertions(+), 28 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 14bc5b355f0e2..4971074ab476a 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -826,6 +826,34 @@ static void ep_free(struct eventpoll *ep) + kfree_rcu(ep, rcu); + } + ++/* ++ * The ffd.file pointer may be in the process of being torn down due to ++ * being closed, but we may not have finished eventpoll_release() yet. ++ * ++ * Normally, even with the atomic_long_inc_not_zero, the file may have ++ * been free'd and then gotten re-allocated to something else (since ++ * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). ++ * ++ * But for epoll, users hold the ep->mtx mutex, and as such any file in ++ * the process of being free'd will block in eventpoll_release_file() ++ * and thus the underlying file allocation will not be free'd, and the ++ * file re-use cannot happen. ++ * ++ * For the same reason we can avoid a rcu_read_lock() around the ++ * operation - 'ffd.file' cannot go away even if the refcount has ++ * reached zero (but we must still not call out to ->poll() functions ++ * etc). ++ */ ++static struct file *epi_fget(const struct epitem *epi) ++{ ++ struct file *file; ++ ++ file = epi->ffd.file; ++ if (!file_ref_get(&file->f_ref)) ++ file = NULL; ++ return file; ++} ++ + /* + * Called with &file->f_lock held, + * returns with it released +@@ -1018,34 +1046,6 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep + return res; + } + +-/* +- * The ffd.file pointer may be in the process of being torn down due to +- * being closed, but we may not have finished eventpoll_release() yet. +- * +- * Normally, even with the atomic_long_inc_not_zero, the file may have +- * been free'd and then gotten re-allocated to something else (since +- * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). +- * +- * But for epoll, users hold the ep->mtx mutex, and as such any file in +- * the process of being free'd will block in eventpoll_release_file() +- * and thus the underlying file allocation will not be free'd, and the +- * file re-use cannot happen. +- * +- * For the same reason we can avoid a rcu_read_lock() around the +- * operation - 'ffd.file' cannot go away even if the refcount has +- * reached zero (but we must still not call out to ->poll() functions +- * etc). +- */ +-static struct file *epi_fget(const struct epitem *epi) +-{ +- struct file *file; +- +- file = epi->ffd.file; +- if (!file_ref_get(&file->f_ref)) +- file = NULL; +- return file; +-} +- + /* + * Differs from ep_eventpoll_poll() in that internal callers already have + * the ep->mtx so we need to start from depth=1, such that mutex_lock_nested() +-- +2.53.0 + diff --git a/queue-7.0/eventpoll-split-__ep_remove.patch b/queue-7.0/eventpoll-split-__ep_remove.patch new file mode 100644 index 0000000000..bd0a47284c --- /dev/null +++ b/queue-7.0/eventpoll-split-__ep_remove.patch @@ -0,0 +1,82 @@ +From 14fd50de2ebde4b7687ff5fdd7051d0fcf4163bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:05 +0200 +Subject: eventpoll: split __ep_remove() + +From: Christian Brauner + +[ Upstream commit 0f7bdfd413000985de09fc39eb9efa1e091a3ce0 ] + +Split __ep_remove() to delineate file removal from epoll item removal. + +Suggested-by: Linus Torvalds +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-2-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 27 +++++++++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 3f960473840a6..99188c30fe6c7 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -826,6 +826,9 @@ static void ep_free(struct eventpoll *ep) + kfree_rcu(ep, rcu); + } + ++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file); ++static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi); ++ + /* + * Removes a "struct epitem" from the eventpoll RB tree and deallocates + * all the associated resources. Must be called with "mtx" held. +@@ -837,8 +840,6 @@ static void ep_free(struct eventpoll *ep) + static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) + { + struct file *file = epi->ffd.file; +- struct epitems_head *to_free; +- struct hlist_head *head; + + lockdep_assert_irqs_enabled(); + +@@ -854,8 +855,21 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) + return false; + } + +- to_free = NULL; +- head = file->f_ep; ++ __ep_remove_file(ep, epi, file); ++ return __ep_remove_epi(ep, epi); ++} ++ ++/* ++ * Called with &file->f_lock held, ++ * returns with it released ++ */ ++static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file) ++{ ++ struct epitems_head *to_free = NULL; ++ struct hlist_head *head = file->f_ep; ++ ++ lockdep_assert_held(&ep->mtx); ++ + if (hlist_is_singular_node(&epi->fllink, head)) { + /* See eventpoll_release() for details. */ + WRITE_ONCE(file->f_ep, NULL); +@@ -869,6 +883,11 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) + hlist_del_rcu(&epi->fllink); + spin_unlock(&file->f_lock); + free_ephead(to_free); ++} ++ ++static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi) ++{ ++ lockdep_assert_held(&ep->mtx); + + rb_erase_cached(&epi->rbn, &ep->rbr); + +-- +2.53.0 + diff --git a/queue-7.0/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch b/queue-7.0/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch new file mode 100644 index 0000000000..58f14e34b4 --- /dev/null +++ b/queue-7.0/eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch @@ -0,0 +1,37 @@ +From 19791db056774a4e6e3c9647df8fe5f21965bd03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 11:56:04 +0200 +Subject: eventpoll: use hlist_is_singular_node() in __ep_remove() + +From: Christian Brauner + +[ Upstream commit 3d9fd0abc94d8cd430cc7cd7d37ce5e5aae2cd2b ] + +Replace the open-coded "epi is the only entry in file->f_ep" check +with hlist_is_singular_node(). Same semantics, and the helper avoids +the head-cacheline access in the common false case. + +Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-1-2470f9eec0f5@kernel.org +Signed-off-by: Christian Brauner (Amutable) +Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") +Signed-off-by: Sasha Levin +--- + fs/eventpoll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/eventpoll.c b/fs/eventpoll.c +index 4b43bf41296d4..3f960473840a6 100644 +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -856,7 +856,7 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) + + to_free = NULL; + head = file->f_ep; +- if (head->first == &epi->fllink && !epi->fllink.next) { ++ if (hlist_is_singular_node(&epi->fllink, head)) { + /* See eventpoll_release() for details. */ + WRITE_ONCE(file->f_ep, NULL); + if (!is_file_epoll(file)) { +-- +2.53.0 + diff --git a/queue-7.0/ext4-call-deactivate_super-in-extents_kunit_exit.patch b/queue-7.0/ext4-call-deactivate_super-in-extents_kunit_exit.patch new file mode 100644 index 0000000000..370aae83da --- /dev/null +++ b/queue-7.0/ext4-call-deactivate_super-in-extents_kunit_exit.patch @@ -0,0 +1,38 @@ +From c23927a0509be0758953f0dc6f151f7cd394c2a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:30:32 +0800 +Subject: ext4: call deactivate_super() in extents_kunit_exit() + +From: Ye Bin + +[ Upstream commit f9c1f7647ac8fb70bebb1615ac112d1568abe339 ] + +Call deactivate_super() is called in extents_kunit_exit() to cleanup +the file system resource. + +Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion") +Signed-off-by: Ye Bin +Reviewed-by: Ritesh Harjani (IBM) +Reviewed-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20260330133035.287842-3-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/extents-test.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c +index 82c59291e0458..3d4663d99eb13 100644 +--- a/fs/ext4/extents-test.c ++++ b/fs/ext4/extents-test.c +@@ -146,6 +146,7 @@ static void extents_kunit_exit(struct kunit *test) + struct ext4_sb_info *sbi = sb->s_fs_info; + + ext4_es_unregister_shrinker(sbi); ++ deactivate_super(sbi->s_sb); + kfree(sbi); + kfree(k_ctx.k_ei); + kfree(k_ctx.k_data); +-- +2.53.0 + diff --git a/queue-7.0/ext4-fix-miss-unlock-sb-s_umount-in-extents_kunit_in.patch b/queue-7.0/ext4-fix-miss-unlock-sb-s_umount-in-extents_kunit_in.patch new file mode 100644 index 0000000000..624a6d1499 --- /dev/null +++ b/queue-7.0/ext4-fix-miss-unlock-sb-s_umount-in-extents_kunit_in.patch @@ -0,0 +1,54 @@ +From b68e37635d6fba456a850c86be22bb01a9446c2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:30:31 +0800 +Subject: ext4: fix miss unlock 'sb->s_umount' in extents_kunit_init() + +From: Ye Bin + +[ Upstream commit 5941a072d48841255005e3a5b5a620692d81d1a7 ] + +There's warning as follows when do ext4 kunit test: +WARNING: kunit_try_catch/15923 still has locks held! +7.0.0-rc3-next-20260309-00028-g73f965a1bbb1-dirty #281 Tainted: G E N +1 lock held by kunit_try_catch/15923: + #0: ffff888139f860e0 (&type->s_umount_key#70/1){+.+.}-{4:4}, at: alloc_super.constprop.0+0x172/0xa90 +Call Trace: + + dump_stack_lvl+0x180/0x1b0 + debug_check_no_locks_held+0xc8/0xd0 + do_exit+0x1502/0x2b20 + kthread+0x3a9/0x540 + ret_from_fork+0xa76/0xdf0 + ret_from_fork_asm+0x1a/0x30 + +As sget() will return 'sb' which holds 's->s_umount' lock. However, +"extents-test" miss unlock this lock. +So unlock 's->s_umount' in the end of extents_kunit_init(). + +Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion") +Signed-off-by: Ye Bin +Reviewed-by: Ritesh Harjani (IBM) +Reviewed-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20260330133035.287842-2-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/extents-test.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c +index 5496b2c8e2cd3..82c59291e0458 100644 +--- a/fs/ext4/extents-test.c ++++ b/fs/ext4/extents-test.c +@@ -309,6 +309,8 @@ static int extents_kunit_init(struct kunit *test) + kunit_activate_static_stub(test, ext4_ext_zeroout, ext4_ext_zeroout_stub); + kunit_activate_static_stub(test, ext4_issue_zeroout, + ext4_issue_zeroout_stub); ++ up_write(&sb->s_umount); ++ + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/ext4-fix-possible-null-ptr-deref-in-extents_kunit_ex.patch b/queue-7.0/ext4-fix-possible-null-ptr-deref-in-extents_kunit_ex.patch new file mode 100644 index 0000000000..e0e09649c1 --- /dev/null +++ b/queue-7.0/ext4-fix-possible-null-ptr-deref-in-extents_kunit_ex.patch @@ -0,0 +1,57 @@ +From 0dbc16824a33b9b1fb89d47f0b24ba9da49d8a4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:30:34 +0800 +Subject: ext4: fix possible null-ptr-deref in extents_kunit_exit() + +From: Ye Bin + +[ Upstream commit ca78c31af467ffe94b15f6a2e4e1cc1c164db19b ] + +There's issue as follows: +KASAN: null-ptr-deref in range [0x00000000000002c0-0x00000000000002c7] +Tainted: [E]=UNSIGNED_MODULE, [N]=TEST +RIP: 0010:extents_kunit_exit+0x2e/0xc0 [ext4_test] +Call Trace: + + kunit_try_run_case_cleanup+0xbc/0x100 [kunit] + kunit_generic_run_threadfn_adapter+0x89/0x100 [kunit] + kthread+0x408/0x540 + ret_from_fork+0xa76/0xdf0 + ret_from_fork_asm+0x1a/0x30 + +Above issue happens as extents_kunit_init() init testcase failed. +So test if testcase is inited success. + +Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion") +Signed-off-by: Ye Bin +Reviewed-by: Ojaswin Mujoo +Reviewed-by: Ritesh Harjani (IBM) +Link: https://patch.msgid.link/20260330133035.287842-5-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/extents-test.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c +index 4042bc8a95e2f..6b53a3f39fcd6 100644 +--- a/fs/ext4/extents-test.c ++++ b/fs/ext4/extents-test.c +@@ -142,9 +142,12 @@ static struct file_system_type ext_fs_type = { + + static void extents_kunit_exit(struct kunit *test) + { +- struct super_block *sb = k_ctx.k_ei->vfs_inode.i_sb; +- struct ext4_sb_info *sbi = sb->s_fs_info; ++ struct ext4_sb_info *sbi; + ++ if (!k_ctx.k_ei) ++ return; ++ ++ sbi = k_ctx.k_ei->vfs_inode.i_sb->s_fs_info; + ext4_es_unregister_shrinker(sbi); + deactivate_super(sbi->s_sb); + kfree(sbi); +-- +2.53.0 + diff --git a/queue-7.0/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch b/queue-7.0/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch new file mode 100644 index 0000000000..60487898b1 --- /dev/null +++ b/queue-7.0/ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch @@ -0,0 +1,70 @@ +From fb0f8b5506f368cf8fc139dee5cd9f03223322b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:30:35 +0800 +Subject: ext4: fix possible null-ptr-deref in mbt_kunit_exit() + +From: Ye Bin + +[ Upstream commit 22f53f08d9eb837ce69b1a07641d414aac8d045f ] + +There's issue as follows: + # test_new_blocks_simple: failed to initialize: -12 +KASAN: null-ptr-deref in range [0x0000000000000638-0x000000000000063f] +Tainted: [E]=UNSIGNED_MODULE, [N]=TEST +RIP: 0010:mbt_kunit_exit+0x5e/0x3e0 [ext4_test] +Call Trace: + + kunit_try_run_case_cleanup+0xbc/0x100 [kunit] + kunit_generic_run_threadfn_adapter+0x89/0x100 [kunit] + kthread+0x408/0x540 + ret_from_fork+0xa76/0xdf0 + ret_from_fork_asm+0x1a/0x30 + +If mbt_kunit_init() init testcase failed will lead to null-ptr-deref. +So add test if 'sb' is inited success in mbt_kunit_exit(). + +Fixes: 7c9fa399a369 ("ext4: add first unit test for ext4_mb_new_blocks_simple in mballoc") +Signed-off-by: Ye Bin +Reviewed-by: Ritesh Harjani (IBM) +Reviewed-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20260330133035.287842-6-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc-test.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/ext4/mballoc-test.c b/fs/ext4/mballoc-test.c +index 6f5bfbb0e8a42..95cb644cd32fa 100644 +--- a/fs/ext4/mballoc-test.c ++++ b/fs/ext4/mballoc-test.c +@@ -362,7 +362,6 @@ static int mbt_kunit_init(struct kunit *test) + return ret; + } + +- test->priv = sb; + kunit_activate_static_stub(test, + ext4_read_block_bitmap_nowait, + ext4_read_block_bitmap_nowait_stub); +@@ -383,6 +382,8 @@ static int mbt_kunit_init(struct kunit *test) + return -ENOMEM; + } + ++ test->priv = sb; ++ + return 0; + } + +@@ -390,6 +391,9 @@ static void mbt_kunit_exit(struct kunit *test) + { + struct super_block *sb = (struct super_block *)test->priv; + ++ if (!sb) ++ return; ++ + mbt_mb_release(sb); + mbt_ctx_release(sb); + mbt_ext4_free_super_block(sb); +-- +2.53.0 + diff --git a/queue-7.0/ext4-fix-the-error-handling-process-in-extents_kunit.patch b/queue-7.0/ext4-fix-the-error-handling-process-in-extents_kunit.patch new file mode 100644 index 0000000000..c0cd6ba300 --- /dev/null +++ b/queue-7.0/ext4-fix-the-error-handling-process-in-extents_kunit.patch @@ -0,0 +1,118 @@ +From 2884177232a0a1e54a62b87749ed12c3c54e97d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 21:30:33 +0800 +Subject: ext4: fix the error handling process in extents_kunit_init). + +From: Ye Bin + +[ Upstream commit 17f73c95d47325000ee68492be3ad76ae09f6f19 ] + +The error processing in extents_kunit_init() is improper, causing +resource leakage. +Reconstruct the error handling process to prevent potential resource +leaks + +Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion") +Signed-off-by: Ye Bin +Reviewed-by: Ritesh Harjani (IBM) +Reviewed-by: Ojaswin Mujoo +Link: https://patch.msgid.link/20260330133035.287842-4-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/extents-test.c | 50 +++++++++++++++++++++++++++++------------- + 1 file changed, 35 insertions(+), 15 deletions(-) + +diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c +index 3d4663d99eb13..4042bc8a95e2f 100644 +--- a/fs/ext4/extents-test.c ++++ b/fs/ext4/extents-test.c +@@ -225,34 +225,38 @@ static int extents_kunit_init(struct kunit *test) + (struct kunit_ext_test_param *)(test->param_value); + int err; + +- sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL); +- if (IS_ERR(sb)) +- return PTR_ERR(sb); +- +- sb->s_blocksize = 4096; +- sb->s_blocksize_bits = 12; +- + sbi = kzalloc_obj(struct ext4_sb_info); + if (sbi == NULL) + return -ENOMEM; + ++ sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL); ++ if (IS_ERR(sb)) { ++ kfree(sbi); ++ return PTR_ERR(sb); ++ } ++ + sbi->s_sb = sb; + sb->s_fs_info = sbi; + ++ sb->s_blocksize = 4096; ++ sb->s_blocksize_bits = 12; ++ + if (!param || !param->disable_zeroout) + sbi->s_extent_max_zeroout_kb = 32; + ++ err = ext4_es_register_shrinker(sbi); ++ if (err) ++ goto out_deactivate; ++ + /* setup the mock inode */ + k_ctx.k_ei = kzalloc_obj(struct ext4_inode_info); +- if (k_ctx.k_ei == NULL) +- return -ENOMEM; ++ if (k_ctx.k_ei == NULL) { ++ err = -ENOMEM; ++ goto out; ++ } + ei = k_ctx.k_ei; + inode = &ei->vfs_inode; + +- err = ext4_es_register_shrinker(sbi); +- if (err) +- return err; +- + ext4_es_init_tree(&ei->i_es_tree); + rwlock_init(&ei->i_es_lock); + INIT_LIST_HEAD(&ei->i_es_list); +@@ -267,8 +271,10 @@ static int extents_kunit_init(struct kunit *test) + inode->i_sb = sb; + + k_ctx.k_data = kzalloc(EXT_DATA_LEN * 4096, GFP_KERNEL); +- if (k_ctx.k_data == NULL) +- return -ENOMEM; ++ if (k_ctx.k_data == NULL) { ++ err = -ENOMEM; ++ goto out; ++ } + + /* + * set the data area to a junk value +@@ -313,6 +319,20 @@ static int extents_kunit_init(struct kunit *test) + up_write(&sb->s_umount); + + return 0; ++ ++out: ++ kfree(k_ctx.k_ei); ++ k_ctx.k_ei = NULL; ++ ++ kfree(k_ctx.k_data); ++ k_ctx.k_data = NULL; ++ ++ ext4_es_unregister_shrinker(sbi); ++out_deactivate: ++ deactivate_locked_super(sb); ++ kfree(sbi); ++ ++ return err; + } + + /* +-- +2.53.0 + diff --git a/queue-7.0/f2fs-allow-empty-mount-string-for-opt_usr-grp-projjq.patch b/queue-7.0/f2fs-allow-empty-mount-string-for-opt_usr-grp-projjq.patch new file mode 100644 index 0000000000..d3c2be187e --- /dev/null +++ b/queue-7.0/f2fs-allow-empty-mount-string-for-opt_usr-grp-projjq.patch @@ -0,0 +1,82 @@ +From 0cd7b6aa9786a90b3436e648f8b2bf8a12d1e932 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 23:40:59 +0000 +Subject: f2fs: allow empty mount string for Opt_usr|grp|projjquota + +From: Jaegeuk Kim + +[ Upstream commit 2a3db1e02ce08c14af04da70bb99e8a0a31eb9e8 ] + +The fsparam_string_empty() gives an error when mounting without string, since +its type is set to fsparam_flag in VFS. So, let's allow the flag as well. + +This addresses xfstests/f2fs/015 and f2fs/021. + +Fixes: d18535132523 ("f2fs: separate the options parsing and options checking") +Reviewed-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/super.c | 27 +++++++++++++++------------ + 1 file changed, 15 insertions(+), 12 deletions(-) + +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index f44e962b1ee7d..79cc7b39802f8 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -336,9 +336,12 @@ static const struct fs_parameter_spec f2fs_param_specs[] = { + fsparam_flag("usrquota", Opt_usrquota), + fsparam_flag("grpquota", Opt_grpquota), + fsparam_flag("prjquota", Opt_prjquota), +- fsparam_string_empty("usrjquota", Opt_usrjquota), +- fsparam_string_empty("grpjquota", Opt_grpjquota), +- fsparam_string_empty("prjjquota", Opt_prjjquota), ++ fsparam_string("usrjquota", Opt_usrjquota), ++ fsparam_flag("usrjquota", Opt_usrjquota), ++ fsparam_string("grpjquota", Opt_grpjquota), ++ fsparam_flag("grpjquota", Opt_grpjquota), ++ fsparam_string("prjjquota", Opt_prjjquota), ++ fsparam_flag("prjjquota", Opt_prjjquota), + fsparam_flag("nat_bits", Opt_nat_bits), + fsparam_enum("jqfmt", Opt_jqfmt, f2fs_param_jqfmt), + fsparam_enum("alloc_mode", Opt_alloc, f2fs_param_alloc_mode), +@@ -979,26 +982,26 @@ static int f2fs_parse_param(struct fs_context *fc, struct fs_parameter *param) + ctx_set_opt(ctx, F2FS_MOUNT_PRJQUOTA); + break; + case Opt_usrjquota: +- if (!*param->string) +- ret = f2fs_unnote_qf_name(fc, USRQUOTA); +- else ++ if (param->type == fs_value_is_string && *param->string) + ret = f2fs_note_qf_name(fc, USRQUOTA, param); ++ else ++ ret = f2fs_unnote_qf_name(fc, USRQUOTA); + if (ret) + return ret; + break; + case Opt_grpjquota: +- if (!*param->string) +- ret = f2fs_unnote_qf_name(fc, GRPQUOTA); +- else ++ if (param->type == fs_value_is_string && *param->string) + ret = f2fs_note_qf_name(fc, GRPQUOTA, param); ++ else ++ ret = f2fs_unnote_qf_name(fc, GRPQUOTA); + if (ret) + return ret; + break; + case Opt_prjjquota: +- if (!*param->string) +- ret = f2fs_unnote_qf_name(fc, PRJQUOTA); +- else ++ if (param->type == fs_value_is_string && *param->string) + ret = f2fs_note_qf_name(fc, PRJQUOTA, param); ++ else ++ ret = f2fs_unnote_qf_name(fc, PRJQUOTA); + if (ret) + return ret; + break; +-- +2.53.0 + diff --git a/queue-7.0/f2fs-avoid-reading-already-updated-pages-during-gc.patch b/queue-7.0/f2fs-avoid-reading-already-updated-pages-during-gc.patch new file mode 100644 index 0000000000..e4722a383b --- /dev/null +++ b/queue-7.0/f2fs-avoid-reading-already-updated-pages-during-gc.patch @@ -0,0 +1,95 @@ +From 0524500cb7dbeadd369c05e95dfa3a407a9f5c3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 09:18:10 +0800 +Subject: f2fs: avoid reading already updated pages during GC + +From: Jianan Huang + +[ Upstream commit 570e2ccc7cb35fe720106964e65060602d3d2ac4 ] + +We found the following issue during fuzz testing: + +page: refcount:3 mapcount:0 mapping:00000000b6e89c65 index:0x18b2dc pfn:0x161ba9 +memcg:f8ffff800e269c00 +aops:f2fs_meta_aops ino:2 +flags: 0x52880000000080a9(locked|waiters|uptodate|lru|private|zone=1|kasantag=0x4a) +raw: 52880000000080a9 fffffffec6e17588 fffffffec0ccc088 a7ffff8067063618 +raw: 000000000018b2dc 0000000000000009 00000003ffffffff f8ffff800e269c00 +page dumped because: VM_BUG_ON_FOLIO(folio_test_uptodate(folio)) +page_owner tracks the page as allocated + post_alloc_hook+0x58c/0x5ec + prep_new_page+0x34/0x284 + get_page_from_freelist+0x2dcc/0x2e8c + __alloc_pages_noprof+0x280/0x76c + __folio_alloc_noprof+0x18/0xac + __filemap_get_folio+0x6bc/0xdc4 + pagecache_get_page+0x3c/0x104 + do_garbage_collect+0x5c78/0x77a4 + f2fs_gc+0xd74/0x25f0 + gc_thread_func+0xb28/0x2930 + kthread+0x464/0x5d8 + ret_from_fork+0x10/0x20 +------------[ cut here ]------------ +kernel BUG at mm/filemap.c:1563! + folio_end_read+0x140/0x168 + f2fs_finish_read_bio+0x5c4/0xb80 + f2fs_read_end_io+0x64c/0x708 + bio_endio+0x85c/0x8c0 + blk_update_request+0x690/0x127c + scsi_end_request+0x9c/0xb8c + scsi_io_completion+0xf0/0x250 + scsi_finish_command+0x430/0x45c + scsi_complete+0x178/0x6d4 + blk_mq_complete_request+0xcc/0x104 + scsi_done_internal+0x214/0x454 + scsi_done+0x24/0x34 + +which is similar to the problem reported by syzbot: +https://syzkaller.appspot.com/bug?extid=3686758660f980b402dc + +This case is consistent with the description in commit 9bf1a3f +("f2fs: avoid GC causing encrypted file corrupted"): +Page 1 is moved from blkaddr A to blkaddr B by move_data_block, and after +being written it is marked as uptodate. Then, Page 1 is moved from blkaddr +B to blkaddr C, VM_BUG_ON_FOLIO was triggered in the endio initiated by +ra_data_block. + +There is no need to read Page 1 again from blkaddr B, since it has already +been updated. Therefore, avoid initiating I/O in this case. + +Fixes: 6aa58d8ad20a ("f2fs: readahead encrypted block during GC") +Signed-off-by: Jianan Huang +Signed-off-by: Sheng Yong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/gc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c +index f46b2673d31f5..ec0680187c0db 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1230,7 +1230,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index) + .encrypted_page = NULL, + .in_list = 0, + }; +- int err; ++ int err = 0; + + folio = f2fs_grab_cache_folio(mapping, index, true); + if (IS_ERR(folio)) +@@ -1283,6 +1283,9 @@ static int ra_data_block(struct inode *inode, pgoff_t index) + + fio.encrypted_page = &efolio->page; + ++ if (folio_test_uptodate(efolio)) ++ goto put_encrypted_page; ++ + err = f2fs_submit_page_bio(&fio); + if (err) + goto put_encrypted_page; +-- +2.53.0 + diff --git a/queue-7.0/f2fs-fix-data-loss-caused-by-incorrect-use-of-nat_en.patch b/queue-7.0/f2fs-fix-data-loss-caused-by-incorrect-use-of-nat_en.patch new file mode 100644 index 0000000000..ff513fafe4 --- /dev/null +++ b/queue-7.0/f2fs-fix-data-loss-caused-by-incorrect-use-of-nat_en.patch @@ -0,0 +1,73 @@ +From a873b03cc0f895779f4733898b1e38134d02a4e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 17:36:14 +0800 +Subject: f2fs: fix data loss caused by incorrect use of nat_entry flag + +From: Yongpeng Yang + +[ Upstream commit 238e14eb7226f883b72caccd2d37bf5707df066b ] + +Data loss can occur when fsync is performed on a newly created file +(before any checkpoint has been written) concurrently with a checkpoint +operation. The scenario is as follows: + +create & write & fsync 'file A' write checkpoint +- f2fs_do_sync_file // inline inode + - f2fs_write_inode // inode folio is dirty + - f2fs_write_checkpoint + - f2fs_flush_merged_writes + - f2fs_sync_node_pages + - f2fs_flush_nat_entries + - f2fs_fsync_node_pages // no dirty node + - f2fs_need_inode_block_update // return false + SPO and lost 'file A' + +f2fs_flush_nat_entries() sets the IS_CHECKPOINTED and HAS_LAST_FSYNC +flags for the nat_entry, but this does not mean that the checkpoint has +actually completed successfully. However, f2fs_need_inode_block_update() +checks these flags and incorrectly assumes that the checkpoint has +finished. + +The root cause is that the semantics of IS_CHECKPOINTED and +HAS_LAST_FSYNC are only guaranteed after the checkpoint write fully +completes. + +This patch modifies f2fs_need_inode_block_update() to acquire the +sbi->node_write lock before reading the nat_entry flags, ensuring that +once IS_CHECKPOINTED and HAS_LAST_FSYNC are observed to be set, the +checkpoint operation has already completed. + +Fixes: e05df3b115e7 ("f2fs: add node operations") +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/node.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c +index 9ff954952a151..a2ead811c3161 100644 +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -427,7 +427,9 @@ bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino) + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct nat_entry *e; + bool need_update = true; ++ struct f2fs_lock_context lc; + ++ f2fs_down_read_trace(&sbi->node_write, &lc); + f2fs_down_read(&nm_i->nat_tree_lock); + e = __lookup_nat_cache(nm_i, ino, false); + if (e && get_nat_flag(e, HAS_LAST_FSYNC) && +@@ -435,6 +437,7 @@ bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino) + get_nat_flag(e, HAS_FSYNCED_INODE))) + need_update = false; + f2fs_up_read(&nm_i->nat_tree_lock); ++ f2fs_up_read_trace(&sbi->node_write, &lc); + return need_update; + } + +-- +2.53.0 + diff --git a/queue-7.0/f2fs-fix-to-preserve-previous-reserve_-blocks-node-v.patch b/queue-7.0/f2fs-fix-to-preserve-previous-reserve_-blocks-node-v.patch new file mode 100644 index 0000000000..86f24bafd3 --- /dev/null +++ b/queue-7.0/f2fs-fix-to-preserve-previous-reserve_-blocks-node-v.patch @@ -0,0 +1,77 @@ +From 120a2b8e1e72c0b371eb4d00add75b4b81accb37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 11:22:46 +0800 +Subject: f2fs: fix to preserve previous reserve_{blocks,node} value when + remount + +From: Zhiguo Niu + +[ Upstream commit 01968164d94762db2f703647c5acfa28613844f1 ] + +The following steps will change previous value of reserve_{blocks,node}, +this dones not match the original intention. + +1.mount -t f2fs -o reserve_root=8192 imgfile test_mount/ +F2FS-fs (loop56): Mounted with checkpoint version = 1b69f8c7 +mount info: +/dev/block/loop56 on /data/test_mount type f2fs (xxx,reserve_root=8192,reserve_node=0,resuid=0,resgid=0,xxx) + +2.mount -t f2fs -o remount,reserve_root=4096 /data/test_mount +F2FS-fs (loop56): Preserve previous reserve_root=8192 +check mount info: reserve_root change to 4096 +/dev/block/loop56 on /data/test_mount type f2fs (xxx,reserve_root=4096,reserve_node=0,resuid=0,resgid=0,xxx) + +Prior to commit d18535132523 ("f2fs: separate the options parsing and options checking"), +the value of reserve_{blocks,node} was only set during the first mount, along with +the corresponding mount option F2FS_MOUNT_RESERVE_{ROOT,NODE} . If the mount option +F2FS_MOUNT_RESERVE_{ROOT,NODE} was found to have been set during the mount/remount, +the previously value of reserve_{blocks,node} would also be preserved, as shown in +the code below. + if (test_opt(sbi, RESERVE_ROOT)) { + f2fs_info(sbi, "Preserve previous reserve_root=%u", + F2FS_OPTION(sbi).root_reserved_blocks); + } else { + F2FS_OPTION(sbi).root_reserved_blocks = arg; + set_opt(sbi, RESERVE_ROOT); + } +But commit d18535132523 ("f2fs: separate the options parsing and options checking") +only preserved the previous mount option; it did not preserve the previous value of +reserve_{blocks,node}. Since value of reserve_{blocks,node} value is assigned +or not depends on ctx->spec_mask, ctx->spec_mask should be alos handled in +f2fs_check_opt_consistency. + +This patch will clear the corresponding ctx->spec_mask bits in f2fs_check_opt_consistency +to preserve the previously values of reserve_{blocks,node} if it already have a value. + +Fixes: d18535132523 ("f2fs: separate the options parsing and options checking") +Signed-off-by: Zhiguo Niu +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/super.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index 255db40c49ed9..f44e962b1ee7d 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1515,6 +1515,7 @@ static int f2fs_check_opt_consistency(struct fs_context *fc, + F2FS_OPTION(sbi).root_reserved_blocks); + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_ROOT); + ctx->opt_mask &= ~BIT(F2FS_MOUNT_RESERVE_ROOT); ++ ctx->spec_mask &= ~F2FS_SPEC_reserve_root; + } + if (test_opt(sbi, RESERVE_NODE) && + (ctx->opt_mask & BIT(F2FS_MOUNT_RESERVE_NODE)) && +@@ -1523,6 +1524,7 @@ static int f2fs_check_opt_consistency(struct fs_context *fc, + F2FS_OPTION(sbi).root_reserved_nodes); + ctx_clear_opt(ctx, F2FS_MOUNT_RESERVE_NODE); + ctx->opt_mask &= ~BIT(F2FS_MOUNT_RESERVE_NODE); ++ ctx->spec_mask &= ~F2FS_SPEC_reserve_node; + } + + err = f2fs_check_test_dummy_encryption(fc, sb); +-- +2.53.0 + diff --git a/queue-7.0/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch b/queue-7.0/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch new file mode 100644 index 0000000000..5d02840a20 --- /dev/null +++ b/queue-7.0/f2fs-protect-extension_list-reading-with-sb_lock-in-.patch @@ -0,0 +1,57 @@ +From 3967015dd08de90d05365b65b5c862729bf71eff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:05:39 +0800 +Subject: f2fs: protect extension_list reading with sb_lock in f2fs_sbi_show() + +From: Yongpeng Yang + +[ Upstream commit 5909bedbed38c558bee7cb6758ceedf9bc3a9194 ] + +In f2fs_sbi_show(), the extension_list, extension_count and +hot_ext_count are read without holding sbi->sb_lock. If a concurrent +sysfs store modifies the extension list via f2fs_update_extension_list(), +the show path may read inconsistent count and array contents, potentially +leading to out-of-bounds access or displaying stale data. + +Fix this by holding sb_lock around the entire extension list read +and format operation. + +Fixes: b6a06cbbb5f7 ("f2fs: support hot file extension") +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/sysfs.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index cd1921edb59ef..0d05ecd64ca03 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -379,10 +379,12 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + if (!strcmp(a->attr.name, "extension_list")) { + __u8 (*extlist)[F2FS_EXTENSION_LEN] = + sbi->raw_super->extension_list; +- int cold_count = le32_to_cpu(sbi->raw_super->extension_count); +- int hot_count = sbi->raw_super->hot_ext_count; ++ int cold_count, hot_count; + int len = 0, i; + ++ f2fs_down_read(&sbi->sb_lock); ++ cold_count = le32_to_cpu(sbi->raw_super->extension_count); ++ hot_count = sbi->raw_super->hot_ext_count; + len += sysfs_emit_at(buf, len, "cold file extension:\n"); + for (i = 0; i < cold_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); +@@ -390,6 +392,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + len += sysfs_emit_at(buf, len, "hot file extension:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) + len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); ++ f2fs_up_read(&sbi->sb_lock); + + return len; + } +-- +2.53.0 + diff --git a/queue-7.0/fanotify-avoid-silence-premature-lsm-capability-chec.patch b/queue-7.0/fanotify-avoid-silence-premature-lsm-capability-chec.patch new file mode 100644 index 0000000000..11adab52ef --- /dev/null +++ b/queue-7.0/fanotify-avoid-silence-premature-lsm-capability-chec.patch @@ -0,0 +1,76 @@ +From f44fd3f93da6e7c281e8d6abe0881364224f6526 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 16:06:24 +0100 +Subject: fanotify: avoid/silence premature LSM capability checks + +From: Ondrej Mosnacek + +[ Upstream commit 0d5ee3373426395478c355f3e93ba4b1118a04e9 ] + +Make sure calling capable()/ns_capable() actually leads to access denied +when false is returned, because these functions emit an audit record +when a Linux Security Module denies the capability, which makes it +difficult to avoid allowing/silencing unnecessary permissions in +security policies (namely with SELinux). + +Where the return value just used to set a flag, use the non-auditing +ns_capable_noaudit() instead. + +Fixes: 7cea2a3c505e ("fanotify: support limited functionality for unprivileged users") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Paul Moore +Reviewed-by: Amir Goldstein +Link: https://patch.msgid.link/20260216150625.793013-2-omosnace@redhat.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index c2dcb25151deb..5d030fbb2dffe 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1615,17 +1615,18 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + pr_debug("%s: flags=%x event_f_flags=%x\n", + __func__, flags, event_f_flags); + +- if (!capable(CAP_SYS_ADMIN)) { +- /* +- * An unprivileged user can setup an fanotify group with +- * limited functionality - an unprivileged group is limited to +- * notification events with file handles or mount ids and it +- * cannot use unlimited queue/marks. +- */ +- if ((flags & FANOTIFY_ADMIN_INIT_FLAGS) || +- !(flags & (FANOTIFY_FID_BITS | FAN_REPORT_MNT))) +- return -EPERM; ++ /* ++ * An unprivileged user can setup an fanotify group with limited ++ * functionality - an unprivileged group is limited to notification ++ * events with file handles or mount ids and it cannot use unlimited ++ * queue/marks. ++ */ ++ if (((flags & FANOTIFY_ADMIN_INIT_FLAGS) || ++ !(flags & (FANOTIFY_FID_BITS | FAN_REPORT_MNT))) && ++ !capable(CAP_SYS_ADMIN)) ++ return -EPERM; + ++ if (!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) { + /* + * Setting the internal flag FANOTIFY_UNPRIV on the group + * prevents setting mount/filesystem marks on this group and +@@ -1990,8 +1991,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + * A user is allowed to setup sb/mount/mntns marks only if it is + * capable in the user ns where the group was created. + */ +- if (!ns_capable(group->user_ns, CAP_SYS_ADMIN) && +- mark_type != FAN_MARK_INODE) ++ if (mark_type != FAN_MARK_INODE && ++ !ns_capable(group->user_ns, CAP_SYS_ADMIN)) + return -EPERM; + + /* +-- +2.53.0 + diff --git a/queue-7.0/fanotify-call-fanotify_events_supported-before-path_.patch b/queue-7.0/fanotify-call-fanotify_events_supported-before-path_.patch new file mode 100644 index 0000000000..b855a05ff5 --- /dev/null +++ b/queue-7.0/fanotify-call-fanotify_events_supported-before-path_.patch @@ -0,0 +1,79 @@ +From 774986b44e8ba1471acce4031910e0d82736ea61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 16:06:25 +0100 +Subject: fanotify: call fanotify_events_supported() before path_permission() + and security_path_notify() + +From: Ondrej Mosnacek + +[ Upstream commit 66052a768d4726a31e939b5ac902f2b0b452c8d5 ] + +The latter trigger LSM (e.g. SELinux) checks, which will log a denial +when permission is denied, so it's better to do them after validity +checks to avoid logging a denial when the operation would fail anyway. + +Fixes: 0b3b094ac9a7 ("fanotify: Disallow permission events for proc filesystem") +Signed-off-by: Ondrej Mosnacek +Reviewed-by: Amir Goldstein +Reviewed-by: Paul Moore +Link: https://patch.msgid.link/20260216150625.793013-3-omosnace@redhat.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 5d030fbb2dffe..ae904451dfc09 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1210,6 +1210,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, + + *path = fd_file(f)->f_path; + path_get(path); ++ ret = 0; + } else { + unsigned int lookup_flags = 0; + +@@ -1219,22 +1220,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, + lookup_flags |= LOOKUP_DIRECTORY; + + ret = user_path_at(dfd, filename, lookup_flags, path); +- if (ret) +- goto out; + } +- +- /* you can only watch an inode if you have read permissions on it */ +- ret = path_permission(path, MAY_READ); +- if (ret) { +- path_put(path); +- goto out; +- } +- +- ret = security_path_notify(path, mask, obj_type); +- if (ret) +- path_put(path); +- +-out: + return ret; + } + +@@ -2058,6 +2044,15 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + goto path_put_and_out; + } + ++ /* you can only watch an inode if you have read permissions on it */ ++ ret = path_permission(&path, MAY_READ); ++ if (ret) ++ goto path_put_and_out; ++ ++ ret = security_path_notify(&path, mask, obj_type); ++ if (ret) ++ goto path_put_and_out; ++ + if (fid_mode) { + ret = fanotify_test_fsid(path.dentry, flags, &__fsid); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch b/queue-7.0/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch new file mode 100644 index 0000000000..c8c7b03f92 --- /dev/null +++ b/queue-7.0/fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch @@ -0,0 +1,71 @@ +From a6bd0ea065731009fa7e7a1bec58aba58703c1ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 15:36:46 +0100 +Subject: fbdev: matroxfb: Mark variable with __maybe_unused to avoid W=1 build + break + +From: Andy Shevchenko + +[ Upstream commit caf6144053b4e1c815aa56afb54745a176f999df ] + +Clang is not happy about set but unused variable: + +drivers/video/fbdev/matrox/g450_pll.c:412:18: error: variable 'mnp' set but not used + 412 | unsigned int mnp; + | ^ +1 error generated. + +Since the commit 7b987887f97b ("video: fbdev: matroxfb: remove dead code +and set but not used variable") the 'mnp' became unused, but eliminating +that code might have side-effects. The question here is what should we do +with 'mnp'? The easiest way out is just mark it with __maybe_unused which +will shut the compiler up and won't change any possible IO flow. So does +this change. + +A dive into the history of the driver: + +The problem was revealed when the #if 0 guarded code along with unused +pixel_vco variable was removed. That code was introduced in the original +commit 213d22146d1f ("[PATCH] (1/3) matroxfb for 2.5.3"). And then guarded +in the commit 705e41f82988 ("matroxfb DVI updates: Handle DVI output on +G450/G550. Powerdown unused portions of G450/G550 DAC. Split G450/G550 DAC +from older DAC1064 handling. Modify PLL setting when both CRTCs use same +pixel clocks."). + +NOTE: The two commits mentioned above pre-date Git era and available in +history.git repository for archaeological purposes. + +Even without that guard the modern compilers may see that the pixel_vco +wasn't ever used and seems a leftover after some debug or review made +25 years ago. + +The g450_mnp2vco() doesn't have any IO and as Jason said doesn't seem +to have any side effects either than some unneeded CPU processing during +runtime. I agree that's unlikely that timeout (or heating up the CPU) has +any effect on the HW (GPU/display) functionality. + +Fixes: 7b987887f97b ("video: fbdev: matroxfb: remove dead code and set but not used variable") +Signed-off-by: Andy Shevchenko +Reviewed-by: Jason Yan +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/matrox/g450_pll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/matrox/g450_pll.c b/drivers/video/fbdev/matrox/g450_pll.c +index e2c1478aa47f9..6a08f78cd1acb 100644 +--- a/drivers/video/fbdev/matrox/g450_pll.c ++++ b/drivers/video/fbdev/matrox/g450_pll.c +@@ -409,7 +409,7 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, + case M_VIDEO_PLL: + { + u_int8_t tmp; +- unsigned int mnp; ++ unsigned int mnp __maybe_unused; + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); +-- +2.53.0 + diff --git a/queue-7.0/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch b/queue-7.0/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch new file mode 100644 index 0000000000..07c3cc3ce8 --- /dev/null +++ b/queue-7.0/fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch @@ -0,0 +1,52 @@ +From 6e9d4c1a187826750bc87bf1dd59a3f82fad673f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:01:18 -0400 +Subject: fbdev: offb: fix PCI device reference leak on probe failure + +From: Yuho Choi + +[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ] + +offb_init_nodriver() gets a referenced PCI device with pci_get_device(). +If pci_enable_device() fails, the function returns without dropping that +reference. + +Release the PCI device reference before returning from the +pci_enable_device() failure path. + +Fixes: 5bda8f7b5468 ("video: fbdev: offb: Call pci_enable_device() before using the PCI VGA device") +Co-developed-by: Myeonghun Pak +Signed-off-by: Myeonghun Pak +Co-developed-by: Ijae Kim +Signed-off-by: Ijae Kim +Co-developed-by: Taegyu Kim +Signed-off-by: Taegyu Kim +Signed-off-by: Yuho Choi +Signed-off-by: Helge Deller +Signed-off-by: Sasha Levin +--- + drivers/video/fbdev/offb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c +index f85428e13996b..166b2dff36f59 100644 +--- a/drivers/video/fbdev/offb.c ++++ b/drivers/video/fbdev/offb.c +@@ -640,8 +640,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod + vid = be32_to_cpup(vidp); + did = be32_to_cpup(didp); + pdev = pci_get_device(vid, did, NULL); +- if (!pdev || pci_enable_device(pdev)) ++ if (!pdev) + return; ++ ++ if (pci_enable_device(pdev)) { ++ pci_dev_put(pdev); ++ return; ++ } + } + #endif + /* kludge for valkyrie */ +-- +2.53.0 + diff --git a/queue-7.0/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch b/queue-7.0/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch new file mode 100644 index 0000000000..541ab59d91 --- /dev/null +++ b/queue-7.0/firmware-arm_ffa-use-the-correct-buffer-size-during-.patch @@ -0,0 +1,39 @@ +From 01c891e1890428bc2da4369549d628b10e1dd192 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 11:39:39 +0000 +Subject: firmware: arm_ffa: Use the correct buffer size during RXTX_MAP + +From: Sebastian Ene + +[ Upstream commit 83210251fd70d5f96bcdc8911e15f7411a6b2463 ] + +Don't use the discovered buffer size from an FFA_FEATURES call directly +since we can run on a system that has the PAGE_SIZE larger than the +returned size which makes the alloc_pages_exact for the buffer to be +rounded up. + +Fixes: 61824feae5c0 ("firmware: arm_ffa: Fetch the Rx/Tx buffer size using ffa_features()") +Signed-off-by: Sebastian Ene +Link: https://patch.msgid.link/20260402113939.930221-1-sebastianene@google.com +Signed-off-by: Sudeep Holla +Signed-off-by: Sasha Levin +--- + drivers/firmware/arm_ffa/driver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index f2f94d4d533e8..eb27828482837 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -2078,7 +2078,7 @@ static int __init ffa_init(void) + + ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), + virt_to_phys(drv_info->rx_buffer), +- rxtx_bufsz / FFA_PAGE_SIZE); ++ PAGE_ALIGN(rxtx_bufsz) / FFA_PAGE_SIZE); + if (ret) { + pr_err("failed to register FFA RxTx buffers\n"); + goto free_pages; +-- +2.53.0 + diff --git a/queue-7.0/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch b/queue-7.0/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch new file mode 100644 index 0000000000..34b33242e7 --- /dev/null +++ b/queue-7.0/firmware-dmi-correct-an-indexing-error-in-dmi.h.patch @@ -0,0 +1,63 @@ +From 3784ae570a75d37b2b995dd7b4bf975886dacc72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 08:10:20 -0600 +Subject: firmware: dmi: Correct an indexing error in dmi.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mario Limonciello (AMD) + +[ Upstream commit c064abc68e009d2cc18416e7132d9c25e03125b6 ] + +The entries later in enum dmi_entry_type don't match the SMBIOS +specification¹. + +The entry for type 33: `64-Bit Memory Error Information` is not present and +thus the index for all later entries is incorrect. + +Add it. + +Also, add missing entry types 43-46, while at it. + + ¹ Search for "System Management BIOS (SMBIOS) Reference Specification" + + [ bp: Drop the flaky SMBIOS spec URL. ] + +Fixes: 93c890dbe5287 ("firmware: Add DMI entry types to the headers") +Signed-off-by: Mario Limonciello (AMD) +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Jean Delvare +Reviewed-by: Yazen Ghannam +Link: https://patch.msgid.link/20260307141024.819807-2-superm1@kernel.org +Signed-off-by: Sasha Levin +--- + include/linux/dmi.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/dmi.h b/include/linux/dmi.h +index 927f8a8b7a1dd..2eedf44e68012 100644 +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -60,6 +60,7 @@ enum dmi_entry_type { + DMI_ENTRY_OOB_REMOTE_ACCESS, + DMI_ENTRY_BIS_ENTRY, + DMI_ENTRY_SYSTEM_BOOT, ++ DMI_ENTRY_64_MEM_ERROR, + DMI_ENTRY_MGMT_DEV, + DMI_ENTRY_MGMT_DEV_COMPONENT, + DMI_ENTRY_MGMT_DEV_THRES, +@@ -69,6 +70,10 @@ enum dmi_entry_type { + DMI_ENTRY_ADDITIONAL, + DMI_ENTRY_ONBOARD_DEV_EXT, + DMI_ENTRY_MGMT_CONTROLLER_HOST, ++ DMI_ENTRY_TPM_DEVICE, ++ DMI_ENTRY_PROCESSOR_ADDITIONAL, ++ DMI_ENTRY_FIRMWARE_INVENTORY, ++ DMI_ENTRY_STRING_PROPERTY, + DMI_ENTRY_INACTIVE = 126, + DMI_ENTRY_END_OF_TABLE = 127, + }; +-- +2.53.0 + diff --git a/queue-7.0/firmware-qcom_scm-don-t-opencode-kmemdup.patch b/queue-7.0/firmware-qcom_scm-don-t-opencode-kmemdup.patch new file mode 100644 index 0000000000..87657a2159 --- /dev/null +++ b/queue-7.0/firmware-qcom_scm-don-t-opencode-kmemdup.patch @@ -0,0 +1,50 @@ +From 4f4efa22597052739afa65c91a3e2af506e3cc6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 19:32:55 +0530 +Subject: firmware: qcom_scm: don't opencode kmemdup + +From: Mukesh Ojha + +[ Upstream commit e32701726c0e6312aabd83aa1c00f59b0d7df276 ] + +Lets not opencode kmemdup which is reported by coccinelle tool. +Fix it using kmemdup. + +cocci warnings: (new ones prefixed by >>) +>> drivers/firmware/qcom/qcom_scm.c:916:11-18: WARNING opportunity for kmemdup + +Fixes: 8b9d2050cfa0 ("firmware: qcom_scm: Add qcom_scm_pas_get_rsc_table() to get resource table") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202601142144.HvSlBSI9-lkp@intel.com/ +Reviewed-by: Konrad Dybcio +Signed-off-by: Mukesh Ojha +Link: https://lore.kernel.org/r/20260310140255.2520230-1-mukesh.ojha@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/firmware/qcom/qcom_scm.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c +index 8fbc96693a55f..d439a9f5b62b8 100644 +--- a/drivers/firmware/qcom/qcom_scm.c ++++ b/drivers/firmware/qcom/qcom_scm.c +@@ -923,14 +923,13 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c + goto free_input_rt; + } + +- tbl_ptr = kzalloc(size, GFP_KERNEL); ++ tbl_ptr = kmemdup(output_rt_tzm, size, GFP_KERNEL); + if (!tbl_ptr) { + qcom_tzmem_free(output_rt_tzm); + ret = -ENOMEM; + goto free_input_rt; + } + +- memcpy(tbl_ptr, output_rt_tzm, size); + *output_rt_size = size; + qcom_tzmem_free(output_rt_tzm); + +-- +2.53.0 + diff --git a/queue-7.0/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch b/queue-7.0/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch new file mode 100644 index 0000000000..467fe2fd29 --- /dev/null +++ b/queue-7.0/fs-adfs-validate-nzones-in-adfs_validate_bblk.patch @@ -0,0 +1,48 @@ +From 18b25d0e4ddf8bdae91f2b486aa7b90c015582d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 13:45:02 +0900 +Subject: fs/adfs: validate nzones in adfs_validate_bblk() + +From: Bae Yeonju + +[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ] + +Reject ADFS disc records with a zero zone count during boot block +validation, before the disc record is used. + +When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) +which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to +dm[-1], causing an out-of-bounds write before the allocated buffer. + +adfs_validate_dr0() already rejects nzones != 1 for old-format +images. Add the equivalent check to adfs_validate_bblk() for +new-format images so that a crafted image with nzones == 0 is +rejected at probe time. + +Found by syzkaller. + +Fixes: f6f14a0d71b0 ("fs/adfs: map: move map-specific sb initialisation to map.c") +Signed-off-by: Bae Yeonju +Signed-off-by: Russell King (Oracle) +Signed-off-by: Sasha Levin +--- + fs/adfs/super.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/adfs/super.c b/fs/adfs/super.c +index 2c5b2076acf9e..a4cd0a5159dd1 100644 +--- a/fs/adfs/super.c ++++ b/fs/adfs/super.c +@@ -317,6 +317,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh, + if (adfs_checkdiscrecord(dr)) + return -EILSEQ; + ++ if ((dr->nzones | dr->nzones_high << 8) == 0) ++ return -EILSEQ; ++ + *drp = dr; + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/fs-fix-archiecture-specific-compat_ftruncate64.patch b/queue-7.0/fs-fix-archiecture-specific-compat_ftruncate64.patch new file mode 100644 index 0000000000..96f570f7ba --- /dev/null +++ b/queue-7.0/fs-fix-archiecture-specific-compat_ftruncate64.patch @@ -0,0 +1,210 @@ +From 3d4240258d1923a0d798d0b67293145249bf9e97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 08:01:44 +0100 +Subject: fs: fix archiecture-specific compat_ftruncate64 + +From: Christoph Hellwig + +[ Upstream commit e43dce8a0bc09083ea1145a1a0c61d83cbe72d97 ] + +The "small" argument to do_sys_ftruncate indicates if > 32-bit size +should be reject, but all the arch-specific compat ftruncate64 +implementations get this wrong. Merge do_sys_ftruncate and +ksys_ftruncate, replace the integer as boolean small flag with a +descriptive one about LFS semantics, and use it correctly in the +architecture-specific ftruncate64 implementations. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Fixes: 3dd681d944f6 ("arm64: 32-bit (compat) applications support") +Signed-off-by: Christoph Hellwig +Link: https://patch.msgid.link/20260323070205.2939118-2-hch@lst.de +Reviewed-by: Jan Kara +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + arch/arm64/kernel/sys32.c | 2 +- + arch/mips/kernel/linux32.c | 2 +- + arch/parisc/kernel/sys_parisc.c | 4 ++-- + arch/powerpc/kernel/sys_ppc32.c | 2 +- + arch/sparc/kernel/sys_sparc32.c | 2 +- + arch/x86/kernel/sys_ia32.c | 3 ++- + fs/internal.h | 1 - + fs/open.c | 12 ++++++------ + include/linux/syscalls.h | 8 ++------ + 9 files changed, 16 insertions(+), 20 deletions(-) + +diff --git a/arch/arm64/kernel/sys32.c b/arch/arm64/kernel/sys32.c +index 96bcfb9074430..12a948f3a5043 100644 +--- a/arch/arm64/kernel/sys32.c ++++ b/arch/arm64/kernel/sys32.c +@@ -89,7 +89,7 @@ COMPAT_SYSCALL_DEFINE4(aarch32_truncate64, const char __user *, pathname, + COMPAT_SYSCALL_DEFINE4(aarch32_ftruncate64, unsigned int, fd, u32, __pad, + arg_u32p(length)) + { +- return ksys_ftruncate(fd, arg_u64(length)); ++ return ksys_ftruncate(fd, arg_u64(length), FTRUNCATE_LFS); + } + + COMPAT_SYSCALL_DEFINE5(aarch32_readahead, int, fd, u32, __pad, +diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c +index a0c0a7a654e94..fe9a787db5694 100644 +--- a/arch/mips/kernel/linux32.c ++++ b/arch/mips/kernel/linux32.c +@@ -60,7 +60,7 @@ SYSCALL_DEFINE4(32_truncate64, const char __user *, path, + SYSCALL_DEFINE4(32_ftruncate64, unsigned long, fd, unsigned long, __dummy, + unsigned long, a2, unsigned long, a3) + { +- return ksys_ftruncate(fd, merge_64(a2, a3)); ++ return ksys_ftruncate(fd, merge_64(a2, a3), FTRUNCATE_LFS); + } + + SYSCALL_DEFINE5(32_llseek, unsigned int, fd, unsigned int, offset_high, +diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c +index b2cdbb8a12b16..fcb0d80691392 100644 +--- a/arch/parisc/kernel/sys_parisc.c ++++ b/arch/parisc/kernel/sys_parisc.c +@@ -216,7 +216,7 @@ asmlinkage long parisc_truncate64(const char __user * path, + asmlinkage long parisc_ftruncate64(unsigned int fd, + unsigned int high, unsigned int low) + { +- return ksys_ftruncate(fd, (long)high << 32 | low); ++ return ksys_ftruncate(fd, (long)high << 32 | low, FTRUNCATE_LFS); + } + + /* stubs for the benefit of the syscall_table since truncate64 and truncate +@@ -227,7 +227,7 @@ asmlinkage long sys_truncate64(const char __user * path, unsigned long length) + } + asmlinkage long sys_ftruncate64(unsigned int fd, unsigned long length) + { +- return ksys_ftruncate(fd, length); ++ return ksys_ftruncate(fd, length, FTRUNCATE_LFS); + } + asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) + { +diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c +index d451a8229223a..03fa487f26147 100644 +--- a/arch/powerpc/kernel/sys_ppc32.c ++++ b/arch/powerpc/kernel/sys_ppc32.c +@@ -101,7 +101,7 @@ PPC32_SYSCALL_DEFINE4(ppc_ftruncate64, + unsigned int, fd, u32, reg4, + unsigned long, len1, unsigned long, len2) + { +- return ksys_ftruncate(fd, merge_64(len1, len2)); ++ return ksys_ftruncate(fd, merge_64(len1, len2), FTRUNCATE_LFS); + } + + PPC32_SYSCALL_DEFINE6(ppc32_fadvise64, +diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c +index f84a02ab6bf90..04432b82b9e3e 100644 +--- a/arch/sparc/kernel/sys_sparc32.c ++++ b/arch/sparc/kernel/sys_sparc32.c +@@ -58,7 +58,7 @@ COMPAT_SYSCALL_DEFINE3(truncate64, const char __user *, path, u32, high, u32, lo + + COMPAT_SYSCALL_DEFINE3(ftruncate64, unsigned int, fd, u32, high, u32, low) + { +- return ksys_ftruncate(fd, ((u64)high << 32) | low); ++ return ksys_ftruncate(fd, ((u64)high << 32) | low, FTRUNCATE_LFS); + } + + static int cp_compat_stat64(struct kstat *stat, +diff --git a/arch/x86/kernel/sys_ia32.c b/arch/x86/kernel/sys_ia32.c +index 6cf65397d2257..610a1c2f45191 100644 +--- a/arch/x86/kernel/sys_ia32.c ++++ b/arch/x86/kernel/sys_ia32.c +@@ -61,7 +61,8 @@ SYSCALL_DEFINE3(ia32_truncate64, const char __user *, filename, + SYSCALL_DEFINE3(ia32_ftruncate64, unsigned int, fd, + unsigned long, offset_low, unsigned long, offset_high) + { +- return ksys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low); ++ return ksys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low, ++ FTRUNCATE_LFS); + } + + /* warning: next two assume little endian */ +diff --git a/fs/internal.h b/fs/internal.h +index 77e90e4124e09..8c1f6c548dbfd 100644 +--- a/fs/internal.h ++++ b/fs/internal.h +@@ -200,7 +200,6 @@ extern int build_open_flags(const struct open_how *how, struct open_flags *op); + struct file *file_close_fd_locked(struct files_struct *files, unsigned fd); + + int do_ftruncate(struct file *file, loff_t length, int small); +-int do_sys_ftruncate(unsigned int fd, loff_t length, int small); + int chmod_common(const struct path *path, umode_t mode); + int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, + int flag); +diff --git a/fs/open.c b/fs/open.c +index 91f1139591abe..412d0d6fbaa75 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -197,7 +197,7 @@ int do_ftruncate(struct file *file, loff_t length, int small) + ATTR_MTIME | ATTR_CTIME, file); + } + +-int do_sys_ftruncate(unsigned int fd, loff_t length, int small) ++int ksys_ftruncate(unsigned int fd, loff_t length, unsigned int flags) + { + if (length < 0) + return -EINVAL; +@@ -205,18 +205,18 @@ int do_sys_ftruncate(unsigned int fd, loff_t length, int small) + if (fd_empty(f)) + return -EBADF; + +- return do_ftruncate(fd_file(f), length, small); ++ return do_ftruncate(fd_file(f), length, !(flags & FTRUNCATE_LFS)); + } + + SYSCALL_DEFINE2(ftruncate, unsigned int, fd, off_t, length) + { +- return do_sys_ftruncate(fd, length, 1); ++ return ksys_ftruncate(fd, length, 0); + } + + #ifdef CONFIG_COMPAT + COMPAT_SYSCALL_DEFINE2(ftruncate, unsigned int, fd, compat_off_t, length) + { +- return do_sys_ftruncate(fd, length, 1); ++ return ksys_ftruncate(fd, length, 0); + } + #endif + +@@ -229,7 +229,7 @@ SYSCALL_DEFINE2(truncate64, const char __user *, path, loff_t, length) + + SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length) + { +- return do_sys_ftruncate(fd, length, 0); ++ return ksys_ftruncate(fd, length, FTRUNCATE_LFS); + } + #endif /* BITS_PER_LONG == 32 */ + +@@ -245,7 +245,7 @@ COMPAT_SYSCALL_DEFINE3(truncate64, const char __user *, pathname, + COMPAT_SYSCALL_DEFINE3(ftruncate64, unsigned int, fd, + compat_arg_u64_dual(length)) + { +- return ksys_ftruncate(fd, compat_arg_u64_glue(length)); ++ return ksys_ftruncate(fd, compat_arg_u64_glue(length), FTRUNCATE_LFS); + } + #endif + +diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h +index 02bd6ddb62782..8787b3511c86c 100644 +--- a/include/linux/syscalls.h ++++ b/include/linux/syscalls.h +@@ -1283,12 +1283,8 @@ static inline long ksys_lchown(const char __user *filename, uid_t user, + AT_SYMLINK_NOFOLLOW); + } + +-int do_sys_ftruncate(unsigned int fd, loff_t length, int small); +- +-static inline long ksys_ftruncate(unsigned int fd, loff_t length) +-{ +- return do_sys_ftruncate(fd, length, 1); +-} ++#define FTRUNCATE_LFS (1u << 0) /* allow truncating > 32-bit */ ++int ksys_ftruncate(unsigned int fd, loff_t length, unsigned int flags); + + int do_sys_truncate(const char __user *pathname, loff_t length); + +-- +2.53.0 + diff --git a/queue-7.0/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch b/queue-7.0/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch new file mode 100644 index 0000000000..c5dca1fb1f --- /dev/null +++ b/queue-7.0/fs-mbcache-cancel-shrink-work-before-destroying-the-.patch @@ -0,0 +1,49 @@ +From 9e5817e230f792ccf98d880f69095356679a031d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:45:56 +0900 +Subject: fs/mbcache: cancel shrink work before destroying the cache + +From: HyungJung Joo + +[ Upstream commit d227786ab1119669df4dc333a61510c52047cce4 ] + +mb_cache_destroy() calls shrinker_free() and then frees all cache +entries and the cache itself, but it does not cancel the pending +c_shrink_work work item first. + +If mb_cache_entry_create() schedules c_shrink_work via schedule_work() +and the work item is still pending or running when mb_cache_destroy() +runs, mb_cache_shrink_worker() will access the cache after its memory +has been freed, causing a use-after-free. + +This is only reachable by a privileged user (root or CAP_SYS_ADMIN) +who can trigger the last put of a mounted ext2/ext4/ocfs2 filesystem. + +Cancel the work item with cancel_work_sync() before calling +shrinker_free(), ensuring the worker has finished and will not be +rescheduled before the cache is torn down. + +Fixes: c2f3140fe2ec ("mbcache2: limit cache size") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054556.1821600-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/mbcache.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/mbcache.c b/fs/mbcache.c +index 480d02d6ebf03..2a6319b4072cc 100644 +--- a/fs/mbcache.c ++++ b/fs/mbcache.c +@@ -406,6 +406,7 @@ void mb_cache_destroy(struct mb_cache *cache) + { + struct mb_cache_entry *entry, *next; + ++ cancel_work_sync(&cache->c_shrink_work); + shrinker_free(cache->c_shrink); + + /* +-- +2.53.0 + diff --git a/queue-7.0/fs-ntfs3-fix-missing-run-load-for-vcn0-in-attr_data_.patch b/queue-7.0/fs-ntfs3-fix-missing-run-load-for-vcn0-in-attr_data_.patch new file mode 100644 index 0000000000..fa4bdffa2d --- /dev/null +++ b/queue-7.0/fs-ntfs3-fix-missing-run-load-for-vcn0-in-attr_data_.patch @@ -0,0 +1,73 @@ +From caba54289b252670d9efd29d6ce0be2e5fbb4c54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:15:46 +0530 +Subject: fs/ntfs3: fix missing run load for vcn0 in + attr_data_get_block_locked() + +From: Deepanshu Kartikey + +[ Upstream commit d7ea8495fd307b58f8867acd81a1b40075b1d3ba ] + +When a compressed or sparse attribute has its clusters frame-aligned, +vcn is rounded down to the frame start using cmask, which can result +in vcn != vcn0. In this case, vcn and vcn0 may reside in different +attribute segments. + +The code already handles the case where vcn is in a different segment +by loading its runs before allocation. However, it fails to load runs +for vcn0 when vcn0 resides in a different segment than vcn. This causes +run_lookup_entry() to return SPARSE_LCN for vcn0 since its segment was +never loaded into the in-memory run list, triggering the WARN_ON(1). + +Fix this by adding a missing check for vcn0 after the existing vcn +segment check. If vcn0 falls outside the current segment range +[svcn, evcn1), find and load the attribute segment containing vcn0 +before performing the run lookup. + +The following scenario triggers the bug: + attr_data_get_block_locked() + vcn = vcn0 & cmask <- vcn != vcn0 after frame alignment + load runs for vcn segment <- vcn0 segment not loaded! + attr_allocate_clusters() <- allocation succeeds + run_lookup_entry(vcn0) <- vcn0 not in run -> SPARSE_LCN + WARN_ON(1) <- bug fires here! + +Reported-by: syzbot+c1e9aedbd913fadad617@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=c1e9aedbd913fadad617 +Fixes: c380b52f6c57 ("fs/ntfs3: Change new sparse cluster processing") +Signed-off-by: Deepanshu Kartikey +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/attrib.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c +index 6cb9bc5d605c2..76e581d3961d0 100644 +--- a/fs/ntfs3/attrib.c ++++ b/fs/ntfs3/attrib.c +@@ -1152,6 +1152,21 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen, + if (err) + goto out; + } ++ ++ if (vcn0 < svcn || evcn1 <= vcn0) { ++ struct ATTRIB *attr2; ++ ++ attr2 = ni_find_attr(ni, attr_b, &le_b, ATTR_DATA, NULL, ++ 0, &vcn0, &mi); ++ if (!attr2) { ++ err = -EINVAL; ++ goto out; ++ } ++ err = attr_load_runs(attr2, ni, run, NULL); ++ if (err) ++ goto out; ++ } ++ + da = false; /* no delalloc for compressed file. */ + } + +-- +2.53.0 + diff --git a/queue-7.0/fs-ntfs3-prevent-uninitialized-lcn-caused-by-zero-le.patch b/queue-7.0/fs-ntfs3-prevent-uninitialized-lcn-caused-by-zero-le.patch new file mode 100644 index 0000000000..00950d57e8 --- /dev/null +++ b/queue-7.0/fs-ntfs3-prevent-uninitialized-lcn-caused-by-zero-le.patch @@ -0,0 +1,70 @@ +From af70519d7646f24e47c8ca37419e847778ee45c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 16:01:13 +0800 +Subject: fs/ntfs3: prevent uninitialized lcn caused by zero len + +From: Edward Adam Davis + +[ Upstream commit e98266e823a1fa06fe6499df61aeaac2fd6f7a49 ] + +syzbot reported a uninit-value in ntfs_iomap_begin [1]. + +Since runs was not touched yet, run_lookup_entry() immediately fails +and returns false, which makes the value of "*len" 0. +Simultaneously, the new value and err value are also 0, causing the +logic in attr_data_get_block_locked() to jump directly to ok, ultimately +resulting in *lcn being triggered before it is set [1]. + +In ntfs_iomap_begin(), the check for a 0 value in clen is moved forward +to before updating lcn to avoid this [1]. + +[1] +BUG: KMSAN: uninit-value in ntfs_iomap_begin+0x8c0/0x1460 fs/ntfs3/inode.c:825 + ntfs_iomap_begin+0x8c0/0x1460 fs/ntfs3/inode.c:825 + iomap_iter+0x9b7/0x1540 fs/iomap/iter.c:110 + +Local variable lcn created at: + ntfs_iomap_begin+0x15d/0x1460 fs/ntfs3/inode.c:786 + +Fixes: 10d7c95af043 ("fs/ntfs3: add delayed-allocation (delalloc) support") +Reported-by: syzbot+7be88937363ac7ab7bb0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=7be88937363ac7ab7bb0 +Tested-by: syzbot+7be88937363ac7ab7bb0@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/inode.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c +index 6e65066ebcc1a..eac421cf98a87 100644 +--- a/fs/ntfs3/inode.c ++++ b/fs/ntfs3/inode.c +@@ -822,6 +822,11 @@ static int ntfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, + return err; + } + ++ if (!clen) { ++ /* broken file? */ ++ return -EINVAL; ++ } ++ + if (lcn == EOF_LCN) { + /* request out of file. */ + if (flags & IOMAP_REPORT) { +@@ -855,11 +860,6 @@ static int ntfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, + return 0; + } + +- if (!clen) { +- /* broken file? */ +- return -EINVAL; +- } +- + iomap->bdev = inode->i_sb->s_bdev; + iomap->offset = offset; + iomap->length = ((loff_t)clen << cluster_bits) - off; +-- +2.53.0 + diff --git a/queue-7.0/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch b/queue-7.0/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch new file mode 100644 index 0000000000..c9e6d2c4aa --- /dev/null +++ b/queue-7.0/fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch @@ -0,0 +1,51 @@ +From 175785246ccda4a1efa3a843a7ab0f150e0937ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:19:55 +0800 +Subject: fs/ntfs3: terminate the cached volume label after UTF-8 conversion + +From: Pengpeng Hou + +[ Upstream commit a6cd43fe9b083fa23fe1595666d5738856cb261a ] + +ntfs_fill_super() loads the on-disk volume label with utf16s_to_utf8s() +and stores the result in sbi->volume.label. The converted label is later +exposed through ntfs3_label_show() using %s, but utf16s_to_utf8s() only +returns the number of bytes written and does not add a trailing NUL. + +If the converted label fills the entire fixed buffer, +ntfs3_label_show() can read past the end of sbi->volume.label while +looking for a terminator. + +Terminate the cached label explicitly after a successful conversion and +clamp the exact-full case to the last byte of the buffer. + +Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block") +Signed-off-by: Pengpeng Hou +Signed-off-by: Konstantin Komarov +Signed-off-by: Sasha Levin +--- + fs/ntfs3/super.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c +index 174a7cb202a08..9ed485f9efbae 100644 +--- a/fs/ntfs3/super.c ++++ b/fs/ntfs3/super.c +@@ -1339,8 +1339,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) + le32_to_cpu(attr->res.data_size) >> 1, + UTF16_LITTLE_ENDIAN, sbi->volume.label, + sizeof(sbi->volume.label)); +- if (err < 0) ++ if (err < 0) { + sbi->volume.label[0] = 0; ++ } else if (err >= sizeof(sbi->volume.label)) { ++ sbi->volume.label[sizeof(sbi->volume.label) - 1] = 0; ++ } else { ++ sbi->volume.label[err] = 0; ++ } + } else { + /* Should we break mounting here? */ + //err = -EINVAL; +-- +2.53.0 + diff --git a/queue-7.0/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch b/queue-7.0/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch new file mode 100644 index 0000000000..f039d101b4 --- /dev/null +++ b/queue-7.0/fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch @@ -0,0 +1,55 @@ +From 8d625b240d8bbb111745a42727b6876ea42bc83b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 14:48:27 +0900 +Subject: fs/omfs: reject s_sys_blocksize smaller than OMFS_DIR_START + +From: HyungJung Joo + +[ Upstream commit 0621c385fda1376e967f37ccd534c26c3e511d14 ] + +omfs_fill_super() rejects oversized s_sys_blocksize values (> PAGE_SIZE), +but it does not reject values smaller than OMFS_DIR_START (0x1b8 = 440). + +Later, omfs_make_empty() uses + + sbi->s_sys_blocksize - OMFS_DIR_START + +as the length argument to memset(). Since s_sys_blocksize is u32, +a crafted filesystem image with s_sys_blocksize < OMFS_DIR_START causes +an unsigned underflow there, wrapping to a value near 2^32. That drives +a ~4 GiB memset() from bh->b_data + OMFS_DIR_START and overwrites kernel +memory far beyond the backing block buffer. + +Add the corresponding lower-bound check alongside the existing upper-bound +check in omfs_fill_super(), so that malformed images are rejected during +superblock validation before any filesystem data is processed. + +Fixes: a3ab7155ea21 ("omfs: add directory routines") +Signed-off-by: Hyungjung Joo +Link: https://patch.msgid.link/20260317054827.1822061-1-jhj140711@gmail.com +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/omfs/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c +index 90ae07c69349e..834cae1e62233 100644 +--- a/fs/omfs/inode.c ++++ b/fs/omfs/inode.c +@@ -513,6 +513,12 @@ static int omfs_fill_super(struct super_block *sb, struct fs_context *fc) + goto out_brelse_bh; + } + ++ if (sbi->s_sys_blocksize < OMFS_DIR_START) { ++ printk(KERN_ERR "omfs: sysblock size (%d) is too small\n", ++ sbi->s_sys_blocksize); ++ goto out_brelse_bh; ++ } ++ + if (sbi->s_blocksize < sbi->s_sys_blocksize || + sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { + printk(KERN_ERR "omfs: block size (%d) is out of range\n", +-- +2.53.0 + diff --git a/queue-7.0/fs-resctrl-report-invalid-domain-id-when-parsing-io_.patch b/queue-7.0/fs-resctrl-report-invalid-domain-id-when-parsing-io_.patch new file mode 100644 index 0000000000..1b9f1c35cc --- /dev/null +++ b/queue-7.0/fs-resctrl-report-invalid-domain-id-when-parsing-io_.patch @@ -0,0 +1,49 @@ +From b4a6e293e9059ac342c5a0a0603df9f95ad192a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 20:11:58 -0400 +Subject: fs/resctrl: Report invalid domain ID when parsing io_alloc_cbm + +From: Aaron Tomlin + +[ Upstream commit d06b8e7c97c3290e61006e30b32beb9e715fab82 ] + +The last_cmd_status file is intended to report details about the most recent +resctrl filesystem operation, specifically to aid in diagnosing failures. + +However, when parsing io_alloc_cbm, if a user provides a domain ID that does +not exist in the resource, the operation fails with -EINVAL without updating +last_cmd_status. This results in inconsistent behaviour where the system call +returns an error, but last_cmd_status misleadingly reports "ok", leaving the +user unaware that the failure was caused by an invalid domain ID. + +Write an error message to last_cmd_status when the target domain ID cannot +be found. + +Fixes: 28fa2cce7a83 ("fs/resctrl: Introduce interface to modify io_alloc capacity bitmasks") +Suggested-by: Reinette Chatre +Signed-off-by: Aaron Tomlin +Signed-off-by: Borislav Petkov (AMD) +Reviewed-by: Reinette Chatre +Reviewed-by: Babu Moger +Tested-by: Babu Moger +Link: https://patch.msgid.link/20260325001159.447075-2-atomlin@atomlin.com +Signed-off-by: Sasha Levin +--- + fs/resctrl/ctrlmondata.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c +index cc4237c57cbe4..2ef53161ce119 100644 +--- a/fs/resctrl/ctrlmondata.c ++++ b/fs/resctrl/ctrlmondata.c +@@ -992,6 +992,7 @@ static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r, + } + } + ++ rdt_last_cmd_printf("Invalid domain %lu\n", dom_id); + return -EINVAL; + } + +-- +2.53.0 + diff --git a/queue-7.0/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch b/queue-7.0/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch new file mode 100644 index 0000000000..8c91ea58ed --- /dev/null +++ b/queue-7.0/fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch @@ -0,0 +1,151 @@ +From 997418a3e60573180c083265e1c433f9e5e8e6b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 14:58:00 +0200 +Subject: fsnotify: fix inode reference leak in fsnotify_recalc_mask() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Amir Goldstein + +[ Upstream commit 4aca914ac152f5d055ddcb36704d1e539ac08977 ] + +fsnotify_recalc_mask() fails to handle the return value of +__fsnotify_recalc_mask(), which may return an inode pointer that needs +to be released via fsnotify_drop_object() when the connector's HAS_IREF +flag transitions from set to cleared. + +This manifests as a hung task with the following call trace: + + INFO: task umount:1234 blocked for more than 120 seconds. + Call Trace: + __schedule + schedule + fsnotify_sb_delete + generic_shutdown_super + kill_anon_super + cleanup_mnt + task_work_run + do_exit + do_group_exit + +The race window that triggers the iref leak: + + Thread A (adding mark) Thread B (removing mark) + ────────────────────── ──────────────────────── + fsnotify_add_mark_locked(): + fsnotify_add_mark_list(): + spin_lock(conn->lock) + add mark_B(evictable) to list + spin_unlock(conn->lock) + return + + /* ---- gap: no lock held ---- */ + + fsnotify_detach_mark(mark_A): + spin_lock(mark_A->lock) + clear ATTACHED flag on mark_A + spin_unlock(mark_A->lock) + fsnotify_put_mark(mark_A) + + fsnotify_recalc_mask(): + spin_lock(conn->lock) + __fsnotify_recalc_mask(): + /* mark_A skipped: ATTACHED cleared */ + /* only mark_B(evictable) remains */ + want_iref = false + has_iref = true /* not yet cleared */ + -> HAS_IREF transitions true -> false + -> returns inode pointer + spin_unlock(conn->lock) + /* BUG: return value discarded! + * iput() and fsnotify_put_sb_watched_objects() + * are never called */ + +Fix this by deferring the transition true -> false of HAS_IREF flag from +fsnotify_recalc_mask() (Thread A) to fsnotify_put_mark() (thread B). + +Fixes: c3638b5b1374 ("fsnotify: allow adding an inode mark without pinning inode") +Signed-off-by: Xin Yin +Signed-off-by: Amir Goldstein +Link: https://patch.msgid.link/CAOQ4uxiPsbHb0o5voUKyPFMvBsDkG914FYDcs4C5UpBMNm0Vcg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/notify/mark.c | 39 ++++++++++++++++++++++++++++++++++++--- + 1 file changed, 36 insertions(+), 3 deletions(-) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 622f05977f86a..e256b420100dc 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -238,7 +238,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn, + return inode; + } + +-static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) ++/* ++ * Calculate mask of events for a list of marks. ++ * ++ * Return true if any of the attached marks want to hold an inode reference. ++ */ ++static bool __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + { + u32 new_mask = 0; + bool want_iref = false; +@@ -262,6 +267,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + */ + WRITE_ONCE(*fsnotify_conn_mask_p(conn), new_mask); + ++ return want_iref; ++} ++ ++/* ++ * Calculate mask of events for a list of marks after attach/modify mark ++ * and get an inode reference for the connector if needed. ++ * ++ * A concurrent add of evictable mark and detach of non-evictable mark can ++ * lead to __fsnotify_recalc_mask() returning false want_iref, but in this ++ * case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called ++ * from fsnotify_put_mark(). ++ */ ++static void fsnotify_recalc_mask_set_iref(struct fsnotify_mark_connector *conn) ++{ ++ bool has_iref = conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF; ++ bool want_iref = __fsnotify_recalc_mask(conn) || has_iref; ++ ++ (void) fsnotify_update_iref(conn, want_iref); ++} ++ ++/* ++ * Calculate mask of events for a list of marks after detach mark ++ * and return the inode object if its reference is no longer needed. ++ */ ++static void *fsnotify_recalc_mask_clear_iref(struct fsnotify_mark_connector *conn) ++{ ++ bool want_iref = __fsnotify_recalc_mask(conn); ++ + return fsnotify_update_iref(conn, want_iref); + } + +@@ -298,7 +331,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + + spin_lock(&conn->lock); + update_children = !fsnotify_conn_watches_children(conn); +- __fsnotify_recalc_mask(conn); ++ fsnotify_recalc_mask_set_iref(conn); + update_children &= fsnotify_conn_watches_children(conn); + spin_unlock(&conn->lock); + /* +@@ -419,7 +452,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) + /* Update watched objects after detaching mark */ + if (sb) + fsnotify_update_sb_watchers(sb, conn); +- objp = __fsnotify_recalc_mask(conn); ++ objp = fsnotify_recalc_mask_clear_iref(conn); + type = conn->type; + } + WRITE_ONCE(mark->connector, NULL); +-- +2.53.0 + diff --git a/queue-7.0/fuse-fix-premature-writetrhough-request-for-large-fo.patch b/queue-7.0/fuse-fix-premature-writetrhough-request-for-large-fo.patch new file mode 100644 index 0000000000..652c218b43 --- /dev/null +++ b/queue-7.0/fuse-fix-premature-writetrhough-request-for-large-fo.patch @@ -0,0 +1,74 @@ +From 6a7afe462775cf3f4b52d24e4e17e04703591fd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jan 2026 10:36:07 +0800 +Subject: fuse: fix premature writetrhough request for large folio + +From: Jingbo Xu + +[ Upstream commit 5223e0470e7bb7910038fe3d31171490e00fbbb9 ] + +When large folio is enabled and the initial folio offset exceeds +PAGE_SIZE, e.g. the position resides in the second page of a large +folio, after the folio copying the offset (in the page) won't be updated +to 0 even though the expected range is successfully copied until the end +of the folio. In this case fuse_fill_write_pages() exits prematurelly +before the request has reached the max_write/max_pages limit. + +Fix this by eliminating page offset entirely and use folio offset +instead. + +Fixes: d60a6015e1a2 ("fuse: support large folios for writethrough writes") +Reviewed-by: Horst Birthelmer +Reviewed-by: Joanne Koong +Signed-off-by: Jingbo Xu +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/file.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 676fd9856bfbf..3939f90d1b4d2 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1242,7 +1242,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, + { + struct fuse_args_pages *ap = &ia->ap; + struct fuse_conn *fc = get_fuse_conn(mapping->host); +- unsigned offset = pos & (PAGE_SIZE - 1); + size_t count = 0; + unsigned int num; + int err = 0; +@@ -1269,7 +1268,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, + if (mapping_writably_mapped(mapping)) + flush_dcache_folio(folio); + +- folio_offset = ((index - folio->index) << PAGE_SHIFT) + offset; ++ folio_offset = offset_in_folio(folio, pos); + bytes = min(folio_size(folio) - folio_offset, num); + + tmp = copy_folio_from_iter_atomic(folio, folio_offset, bytes, ii); +@@ -1299,9 +1298,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, + count += tmp; + pos += tmp; + num -= tmp; +- offset += tmp; +- if (offset == folio_size(folio)) +- offset = 0; + + /* If we copied full folio, mark it uptodate */ + if (tmp == folio_size(folio)) +@@ -1313,7 +1309,9 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia, + ia->write.folio_locked = true; + break; + } +- if (!fc->big_writes || offset != 0) ++ if (!fc->big_writes) ++ break; ++ if (folio_offset + tmp != folio_size(folio)) + break; + } + +-- +2.53.0 + diff --git a/queue-7.0/fuse-fix-uninit-value-in-fuse_dentry_revalidate.patch b/queue-7.0/fuse-fix-uninit-value-in-fuse_dentry_revalidate.patch new file mode 100644 index 0000000000..ebe9c24174 --- /dev/null +++ b/queue-7.0/fuse-fix-uninit-value-in-fuse_dentry_revalidate.patch @@ -0,0 +1,65 @@ +From 8bf364773b428c1442324ea2e91afa34a60ac02f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 14:48:30 +0000 +Subject: fuse: fix uninit-value in fuse_dentry_revalidate() + +From: Luis Henriques + +[ Upstream commit 5a6baf204610589f8a5b5a1cd69d1fe661d9d3cd ] + +fuse_dentry_revalidate() may be called with a dentry that didn't had +->d_time initialised. The issue was found with KMSAN, where lookup_open() +calls __d_alloc(), followed by d_revalidate(), as shown below: + +===================================================== +BUG: KMSAN: uninit-value in fuse_dentry_revalidate+0x150/0x13d0 fs/fuse/dir.c:394 + fuse_dentry_revalidate+0x150/0x13d0 fs/fuse/dir.c:394 + d_revalidate fs/namei.c:1030 [inline] + lookup_open fs/namei.c:4405 [inline] + open_last_lookups fs/namei.c:4583 [inline] + path_openat+0x1614/0x64c0 fs/namei.c:4827 + do_file_open+0x2aa/0x680 fs/namei.c:4859 +[...] + +Uninit was created at: + slab_post_alloc_hook mm/slub.c:4466 [inline] + slab_alloc_node mm/slub.c:4788 [inline] + kmem_cache_alloc_lru_noprof+0x382/0x1280 mm/slub.c:4807 + __d_alloc+0x55/0xa00 fs/dcache.c:1740 + d_alloc_parallel+0x99/0x2740 fs/dcache.c:2604 + lookup_open fs/namei.c:4398 [inline] + open_last_lookups fs/namei.c:4583 [inline] + path_openat+0x135f/0x64c0 fs/namei.c:4827 + do_file_open+0x2aa/0x680 fs/namei.c:4859 +[...] +===================================================== + +Reported-by: syzbot+fdebb2dc960aa56c600a@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69917e0d.050a0220.340abe.02e2.GAE@google.com +Fixes: 2396356a945b ("fuse: add more control over cache invalidation behaviour") +Signed-off-by: Luis Henriques +Signed-off-by: Miklos Szeredi +Signed-off-by: Sasha Levin +--- + fs/fuse/dir.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c +index 7ac6b232ef123..d3acfd346ab52 100644 +--- a/fs/fuse/dir.c ++++ b/fs/fuse/dir.c +@@ -481,6 +481,11 @@ static int fuse_dentry_init(struct dentry *dentry) + fd->dentry = dentry; + RB_CLEAR_NODE(&fd->node); + dentry->d_fsdata = fd; ++ /* ++ * Initialising d_time (epoch) to '0' ensures the dentry is invalid ++ * if compared to fc->epoch, which is initialized to '1'. ++ */ ++ dentry->d_time = 0; + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/futex-drop-clone_thread-requirement-for-private-defa.patch b/queue-7.0/futex-drop-clone_thread-requirement-for-private-defa.patch new file mode 100644 index 0000000000..13967f293b --- /dev/null +++ b/queue-7.0/futex-drop-clone_thread-requirement-for-private-defa.patch @@ -0,0 +1,68 @@ +From 14f325dd770eb5dc8855901e7a8aee9dfc14cab1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 May 2026 12:41:23 -0700 +Subject: futex: Drop CLONE_THREAD requirement for private default hash alloc + +From: Davidlohr Bueso + +[ Upstream commit ee9dce44362b2d8132c32964656ab6dff7dfbc6a ] + +Currently need_futex_hash_allocate_default() depends on strict pthread +semantics, abusing CLONE_THREAD. This breaks the non-concurrency +assumptions when doing the mm->futex_ref pcpu allocations, leading to +bugs[0] when sharing the mm in other ways; ie: + + BUG: KASAN: slab-use-after-free in futex_hash_put + +... where the +1 bias can end up on a percpu counter that mm->futex_ref +no longer points at. + +Loosen the check to cover any CLONE_VM clone, except vfork(). Excluding +vfork keeps the existing paths untouched (no overhead), and we can't +race in the first place: either the parent is suspended and the child +runs alone, or mm->futex_ref is already allocated from an earlier +CLONE_VM. + +Link: https://lore.kernel.org/all/CAL_bE8LsmCQ-FAtYDuwbJhOkt9p2wwYQwAbMh=PifC=VsiBM6A@mail.gmail.com/ [0] +Fixes: d9b05321e21e ("futex: Move futex_hash_free() back to __mmput()") +Reported-by: Yiming Qian +Signed-off-by: Davidlohr Bueso +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 87f3b8d48c0db..73622ad0665a0 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -1949,9 +1949,11 @@ static void rv_task_fork(struct task_struct *p) + + static bool need_futex_hash_allocate_default(u64 clone_flags) + { +- if ((clone_flags & (CLONE_THREAD | CLONE_VM)) != (CLONE_THREAD | CLONE_VM)) +- return false; +- return true; ++ /* ++ * Allocate a default futex hash for any sibling that will ++ * share the parent's mm, except vfork. ++ */ ++ return (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM; + } + + /* +@@ -2338,10 +2340,6 @@ __latent_entropy struct task_struct *copy_process( + if (retval) + goto bad_fork_cancel_cgroup; + +- /* +- * Allocate a default futex hash for the user process once the first +- * thread spawns. +- */ + if (need_futex_hash_allocate_default(clone_flags)) { + retval = futex_hash_allocate_default(); + if (retval) +-- +2.53.0 + diff --git a/queue-7.0/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch b/queue-7.0/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch new file mode 100644 index 0000000000..701449a992 --- /dev/null +++ b/queue-7.0/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch @@ -0,0 +1,100 @@ +From fc9ff81ca3d0955819d5beabe45b441caf7813ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 12:34:25 +0200 +Subject: futex: Prevent lockup in requeue-PI during signal/ timeout wakeup + +From: Sebastian Andrzej Siewior + +[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ] + +During wait-requeue-pi (task A) and requeue-PI (task B) the following +race can happen: + + Task A Task B + futex_wait_requeue_pi() + futex_setup_timer() + futex_do_wait() + futex_requeue() + CLASS(hb, hb1)(&key1); + CLASS(hb, hb2)(&key2); + *timeout* + futex_requeue_pi_wakeup_sync() + requeue_state = Q_REQUEUE_PI_IGNORE + + *blocks on hb->lock* + + futex_proxy_trylock_atomic() + futex_requeue_pi_prepare() + Q_REQUEUE_PI_IGNORE => -EAGAIN + double_unlock_hb(hb1, hb2) + *retry* + +Task B acquires both hb locks and attempts to acquire the PI-lock of the +top most waiter (task B). Task A is leaving early due to a signal/ +timeout and started removing itself from the queue. It updates its +requeue_state but can not remove it from the list because this requires +the hb lock which is owned by task B. + +Usually task A is able to swoop the lock after task B unlocked it. +However if task B is of higher priority then task A may not be able to +wake up in time and acquire the lock before task B gets it again. +Especially on a UP system where A is never scheduled. + +As a result task A blocks on the lock and task B busy loops, trying to +make progress but live locks the system instead. Tragic. + +This can be fixed by removing the top most waiter from the list in this +case. This allows task B to grab the next top waiter (if any) in the +next iteration and make progress. + +Remove the top most waiter if futex_requeue_pi_prepare() fails. +Let the waiter conditionally remove itself from the list in +handle_early_requeue_pi_wakeup(). + +Fixes: 07d91ef510fb1 ("futex: Prevent requeue_pi() lock nesting issue on RT") +Reported-by: Moritz Klammler +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260428103425.dywXyPd3@linutronix.de +Closes: https://lore.kernel.org/all/VE1PR06MB6894BE61C173D802365BE19DFF4CA@VE1PR06MB6894.eurprd06.prod.outlook.com +Signed-off-by: Sasha Levin +--- + kernel/futex/requeue.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c +index d818b4d47f1ba..b597cb3d17fc1 100644 +--- a/kernel/futex/requeue.c ++++ b/kernel/futex/requeue.c +@@ -319,8 +319,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, + return -EINVAL; + + /* Ensure that this does not race against an early wakeup */ +- if (!futex_requeue_pi_prepare(top_waiter, NULL)) ++ if (!futex_requeue_pi_prepare(top_waiter, NULL)) { ++ plist_del(&top_waiter->list, &hb1->chain); ++ futex_hb_waiters_dec(hb1); + return -EAGAIN; ++ } + + /* + * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit +@@ -722,10 +725,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, + + /* + * We were woken prior to requeue by a timeout or a signal. +- * Unqueue the futex_q and determine which it was. ++ * Conditionally unqueue the futex_q and determine which it was. + */ +- plist_del(&q->list, &hb->chain); +- futex_hb_waiters_dec(hb); ++ if (!plist_node_empty(&q->list)) { ++ plist_del(&q->list, &hb->chain); ++ futex_hb_waiters_dec(hb); ++ } + + /* Handle spurious wakeups gracefully */ + ret = -EWOULDBLOCK; +-- +2.53.0 + diff --git a/queue-7.0/fwctl-fix-class-init-ordering-to-avoid-null-pointer-.patch b/queue-7.0/fwctl-fix-class-init-ordering-to-avoid-null-pointer-.patch new file mode 100644 index 0000000000..69c25ae7a8 --- /dev/null +++ b/queue-7.0/fwctl-fix-class-init-ordering-to-avoid-null-pointer-.patch @@ -0,0 +1,47 @@ +From 8b01e8e6791a9a4685dd742e5281bd47d6ac9600 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:19:02 +0800 +Subject: fwctl: Fix class init ordering to avoid NULL pointer dereference on + device removal + +From: Richard Cheng + +[ Upstream commit a55f80233f384dc89ef3425b2e1dd0e6d44bcf29 ] + +CXL is linked before fwctl in drivers/Makefile. Both use `module_init, so +`cxl_pci_driver_init()` runs first. When `cxl_pci_probe()` calls +`fwctl_register()` and then `device_add()`, fwctl_class is not yet +registered because fwctl_init() hasn't run, causing `class_to_subsys()` to +return NULL and skip knode_class initialization. + +On device removal, `class_to_subsys()` returns non-NULL, and +`device_del()` calls `klist_del()` on the uninitialized knode, triggering +a NULL pointer dereference. + +Fixes: 858ce2f56b52 ("cxl: Add FWCTL support to CXL") +Link: https://patch.msgid.link/r/20260409051902.40218-1-icheng@nvidia.com +Signed-off-by: Richard Cheng +Reviewed-by: Kai-Heng Feng +Reviewed-by: Dave Jiang +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/fwctl/main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c +index bc6378506296c..098c3824ad751 100644 +--- a/drivers/fwctl/main.c ++++ b/drivers/fwctl/main.c +@@ -415,7 +415,7 @@ static void __exit fwctl_exit(void) + unregister_chrdev_region(fwctl_dev, FWCTL_MAX_DEVICES); + } + +-module_init(fwctl_init); ++subsys_initcall(fwctl_init); + module_exit(fwctl_exit); + MODULE_DESCRIPTION("fwctl device firmware access framework"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-7.0/gfs2-add-some-missing-log-locking.patch b/queue-7.0/gfs2-add-some-missing-log-locking.patch new file mode 100644 index 0000000000..b85b05d138 --- /dev/null +++ b/queue-7.0/gfs2-add-some-missing-log-locking.patch @@ -0,0 +1,109 @@ +From 8b0ac6c6a650a30129bc2de6c43b79b53cd550f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 06:13:42 +0200 +Subject: gfs2: add some missing log locking + +From: Andreas Gruenbacher + +[ Upstream commit fe2c8d051150b90b3ccb85f89e3b1d636cb88ec8 ] + +Function gfs2_logd() calls the log flushing functions gfs2_ail1_start(), +gfs2_ail1_wait(), and gfs2_ail1_empty() without holding sdp->sd_log_flush_lock, +but these functions require exclusion against concurrent transactions. + +To fix that, add a non-locking __gfs2_log_flush() function. Then, in +gfs2_logd(), take sdp->sd_log_flush_lock before calling the above mentioned log +flushing functions and __gfs2_log_flush(). + +Fixes: 5e4c7632aae1c ("gfs2: Issue revokes more intelligently") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 347df29d610e6..41a70fbee82f4 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -1018,14 +1018,15 @@ static void trans_drain(struct gfs2_trans *tr) + } + + /** +- * gfs2_log_flush - flush incore transaction(s) ++ * __gfs2_log_flush - flush incore transaction(s) + * @sdp: The filesystem + * @gl: The glock structure to flush. If NULL, flush the whole incore log + * @flags: The log header flags: GFS2_LOG_HEAD_FLUSH_* and debug flags + * + */ + +-void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++static void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, ++ u32 flags) + { + struct gfs2_trans *tr = NULL; + unsigned int reserved_blocks = 0, used_blocks = 0; +@@ -1033,7 +1034,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + unsigned int first_log_head; + unsigned int reserved_revokes = 0; + +- down_write(&sdp->sd_log_flush_lock); + trace_gfs2_log_flush(sdp, 1, flags); + + repeat: +@@ -1145,7 +1145,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + gfs2_assert_withdraw(sdp, used_blocks < reserved_blocks); + gfs2_log_release(sdp, reserved_blocks - used_blocks); + } +- up_write(&sdp->sd_log_flush_lock); + gfs2_trans_free(sdp, tr); + trace_gfs2_log_flush(sdp, 0, flags); + return; +@@ -1166,6 +1165,13 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) + goto out_end; + } + ++void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags) ++{ ++ down_write(&sdp->sd_log_flush_lock); ++ __gfs2_log_flush(sdp, gl, flags); ++ up_write(&sdp->sd_log_flush_lock); ++} ++ + /** + * gfs2_merge_trans - Merge a new transaction into a cached transaction + * @sdp: the filesystem +@@ -1297,19 +1303,25 @@ int gfs2_logd(void *data) + break; + + if (gfs2_jrnl_flush_reqd(sdp) || t == 0) { ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_JFLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_JFLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + if (test_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags) || + gfs2_ail_flush_reqd(sdp)) { + clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); ++ down_write(&sdp->sd_log_flush_lock); + gfs2_ail1_start(sdp); + gfs2_ail1_wait(sdp); + gfs2_ail1_empty(sdp, 0); +- gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_NORMAL | +- GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ __gfs2_log_flush(sdp, NULL, ++ GFS2_LOG_HEAD_FLUSH_NORMAL | ++ GFS2_LFC_LOGD_AIL_FLUSH_REQD); ++ up_write(&sdp->sd_log_flush_lock); + } + + t = gfs2_tune_get(sdp, gt_logd_secs) * HZ; +-- +2.53.0 + diff --git a/queue-7.0/gfs2-call-unlock_new_inode-before-d_instantiate.patch b/queue-7.0/gfs2-call-unlock_new_inode-before-d_instantiate.patch new file mode 100644 index 0000000000..6ec2d72569 --- /dev/null +++ b/queue-7.0/gfs2-call-unlock_new_inode-before-d_instantiate.patch @@ -0,0 +1,48 @@ +From df1d5ac304d17ace438e4790c7e182f4eecdf909 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:04:05 +0100 +Subject: gfs2: Call unlock_new_inode before d_instantiate + +From: Andreas Gruenbacher + +[ Upstream commit 2ff7cf7e0640ff071ebc5c7e3dc2df024a7c91e6 ] + +As Neil Brown describes in detail in the link referenced below, new +inodes must be unlocked before they can be instantiated. + +An even better fix is to use d_instantiate_new(), which combines +d_instantiate() and unlock_new_inode(). + +Fixes: 3d36e57ff768 ("gfs2: gfs2_create_inode rework") +Reported-by: syzbot+0ea5108a1f5fb4fcc2d8@syzkaller.appspotmail.com +Link: https://lore.kernel.org/linux-fsdevel/177153754005.8396.8777398743501764194@noble.neil.brown.name/ +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/inode.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c +index 8344040ecaf79..e9bf4879c07f7 100644 +--- a/fs/gfs2/inode.c ++++ b/fs/gfs2/inode.c +@@ -892,7 +892,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + goto fail_gunlock4; + + mark_inode_dirty(inode); +- d_instantiate(dentry, inode); ++ d_instantiate_new(dentry, inode); + /* After instantiate, errors should result in evict which will destroy + * both inode and iopen glocks properly. */ + if (file) { +@@ -904,7 +904,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, + gfs2_glock_dq_uninit(&gh); + gfs2_glock_put(io_gl); + gfs2_qa_put(dip); +- unlock_new_inode(inode); + return error; + + fail_gunlock4: +-- +2.53.0 + diff --git a/queue-7.0/gfs2-less-aggressive-low-memory-log-flushing.patch b/queue-7.0/gfs2-less-aggressive-low-memory-log-flushing.patch new file mode 100644 index 0000000000..4554f8f35b --- /dev/null +++ b/queue-7.0/gfs2-less-aggressive-low-memory-log-flushing.patch @@ -0,0 +1,54 @@ +From 3a425fe961667fabcbe5952e3faaed4d46f88b0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 18:05:48 +0100 +Subject: gfs2: less aggressive low-memory log flushing + +From: Andreas Gruenbacher + +[ Upstream commit 7288185ce87ec70133b7bc3b694b0f74bf46a0ee ] + +It turns out that for some workloads, the fix in commit b74cd55aa9a9d +("gfs2: low-memory forced flush fixes") causes the number of forced log +flushes to increase to a degree that the overall filesystem performance +drops significantly. Address that by forcing a log flush only when +gfs2_writepages cannot make any progress rather than when it cannot make +"enough" progress. + +Fixes: b74cd55aa9a9d ("gfs2: low-memory forced flush fixes") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/aops.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c +index e79ad087512a0..6a6ded7a61d20 100644 +--- a/fs/gfs2/aops.c ++++ b/fs/gfs2/aops.c +@@ -158,6 +158,7 @@ static int gfs2_writepages(struct address_space *mapping, + struct writeback_control *wbc) + { + struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping); ++ long initial_nr_to_write = wbc->nr_to_write; + struct iomap_writepage_ctx wpc = { + .inode = mapping->host, + .wbc = wbc, +@@ -166,13 +167,13 @@ static int gfs2_writepages(struct address_space *mapping, + int ret; + + /* +- * Even if we didn't write enough pages here, we might still be holding ++ * Even if we didn't write any pages here, we might still be holding + * dirty pages in the ail. We forcibly flush the ail because we don't + * want balance_dirty_pages() to loop indefinitely trying to write out + * pages held in the ail that it can't find. + */ + ret = iomap_writepages(&wpc); +- if (ret == 0 && wbc->nr_to_write > 0) ++ if (ret == 0 && wbc->nr_to_write == initial_nr_to_write) + set_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags); + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/gfs2-prevent-null-pointer-dereference-during-unmount.patch b/queue-7.0/gfs2-prevent-null-pointer-dereference-during-unmount.patch new file mode 100644 index 0000000000..569ca0c14b --- /dev/null +++ b/queue-7.0/gfs2-prevent-null-pointer-dereference-during-unmount.patch @@ -0,0 +1,44 @@ +From 3114d9e7fad121c3d72d525dbd91fbc08a4b21cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 12:14:30 +0200 +Subject: gfs2: prevent NULL pointer dereference during unmount + +From: Andreas Gruenbacher + +[ Upstream commit 74b4dbb946060a3233604d91859a9abd3708141d ] + +When flushing out outstanding glock work during an unmount, gfs2_log_flush() +can be called when sdp->sd_jdesc has already been deallocated and sdp->sd_jdesc +is NULL. Commit 35264909e9d1 ("gfs2: Fix NULL pointer dereference in +gfs2_log_flush") added a check for that to gfs2_log_flush() itself, but it +missed the sdp->sd_jdesc dereference in gfs2_log_release(). Fix that. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202604071139.HNJiCaAi-lkp@intel.com/ +Fixes: 35264909e9d1 ("gfs2: Fix NULL pointer dereference in gfs2_log_flush") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/log.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c +index 41a70fbee82f4..c483d3c7be698 100644 +--- a/fs/gfs2/log.c ++++ b/fs/gfs2/log.c +@@ -467,8 +467,9 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks) + { + atomic_add(blks, &sdp->sd_log_blks_free); + trace_gfs2_log_blocks(sdp, blks); +- gfs2_assert_withdraw(sdp, atomic_read(&sdp->sd_log_blks_free) <= +- sdp->sd_jdesc->jd_blocks); ++ gfs2_assert_withdraw(sdp, !sdp->sd_jdesc || ++ atomic_read(&sdp->sd_log_blks_free) <= ++ sdp->sd_jdesc->jd_blocks); + if (atomic_read(&sdp->sd_log_blks_needed)) + wake_up(&sdp->sd_log_waitq); + } +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-bitfield-fix-broken-default-implementa.patch b/queue-7.0/gpu-nova-core-bitfield-fix-broken-default-implementa.patch new file mode 100644 index 0000000000..04dc90357d --- /dev/null +++ b/queue-7.0/gpu-nova-core-bitfield-fix-broken-default-implementa.patch @@ -0,0 +1,43 @@ +From 67b1187da6fa065e4f52bd4bf1f8eb790aaf5a47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:42:28 +0900 +Subject: gpu: nova-core: bitfield: fix broken Default implementation + +From: Eliot Courtney + +[ Upstream commit de0aca13509bf47a2d49bc7a26d56079c758c95f ] + +The current implementation does not actually set the default values for +the fields in the bitfield. + +Fixes: 3fa145bef533 ("gpu: nova-core: register: generate correct `Default` implementation") +Signed-off-by: Eliot Courtney +Link: https://patch.msgid.link/20260401-fix-bitfield-v2-1-2fa68c98114a@nvidia.com +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/bitfield.rs | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/nova-core/bitfield.rs b/drivers/gpu/nova-core/bitfield.rs +index 16e143658c511..02efdcf78d894 100644 +--- a/drivers/gpu/nova-core/bitfield.rs ++++ b/drivers/gpu/nova-core/bitfield.rs +@@ -314,12 +314,11 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { + /// Returns a value for the bitfield where all fields are set to their default value. + impl ::core::default::Default for $name { + fn default() -> Self { +- #[allow(unused_mut)] +- let mut value = Self(Default::default()); ++ let value = Self(Default::default()); + + ::kernel::macros::paste!( + $( +- value.[](Default::default()); ++ let value = value.[](Default::default()); + )* + ); + +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-create-falcon-firmware-dma-objects-laz.patch b/queue-7.0/gpu-nova-core-create-falcon-firmware-dma-objects-laz.patch new file mode 100644 index 0000000000..2fcd5a4e41 --- /dev/null +++ b/queue-7.0/gpu-nova-core-create-falcon-firmware-dma-objects-laz.patch @@ -0,0 +1,579 @@ +From c86630b37a28d085b3088184c1b0c1f6484e9fe9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 13:52:38 +0900 +Subject: gpu: nova-core: create falcon firmware DMA objects lazily + +From: Alexandre Courbot + +[ Upstream commit bc9de9e1af2f05461460e1b215a6d209ee62d65a ] + +When DMA was the only loading option for falcon firmwares, we decided to +store them in DMA objects as soon as they were loaded from disk and +patch them in-place to avoid having to do an extra copy. + +This decision complicates the PIO loading patch considerably, and +actually does not even stand on its own when put into perspective with +the fact that it requires 8 unsafe statements in the code that wouldn't +exist if we stored the firmware into a `KVVec` and copied it into a DMA +object at the last minute. + +The cost of the copy is, as can be expected, imperceptible at runtime. +Thus, switch to a lazy DMA object creation model and simplify our code +a bit. This will also have the nice side-effect of being more fit for +PIO loading. + +Reviewed-by: Eliot Courtney +Acked-by: Danilo Krummrich +Link: https://patch.msgid.link/20260306-turing_prep-v11-1-8f0042c5d026@nvidia.com +[acourbot@nvidia.com: add TODO item to switch back to a coherent +allocation when it becomes convenient to do so.] +Signed-off-by: Alexandre Courbot +Stable-dep-of: 17d7c97f73c7 ("gpu: nova-core: firmware: fix and explain v2 header offsets computations") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/falcon.rs | 57 ++++++++----- + drivers/gpu/nova-core/firmware.rs | 40 ++++----- + drivers/gpu/nova-core/firmware/booter.rs | 33 +++----- + drivers/gpu/nova-core/firmware/fwsec.rs | 103 ++++++++--------------- + drivers/gpu/nova-core/gsp/boot.rs | 2 +- + 5 files changed, 108 insertions(+), 127 deletions(-) + +diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs +index 37bfee1d09492..8d444cf9d55c1 100644 +--- a/drivers/gpu/nova-core/falcon.rs ++++ b/drivers/gpu/nova-core/falcon.rs +@@ -2,12 +2,13 @@ + + //! Falcon microprocessor base support + +-use core::ops::Deref; +- + use hal::FalconHal; + + use kernel::{ +- device, ++ device::{ ++ self, ++ Device, // ++ }, + dma::{ + DmaAddress, + DmaMask, // +@@ -15,9 +16,7 @@ + io::poll::read_poll_timeout, + prelude::*, + sync::aref::ARef, +- time::{ +- Delta, // +- }, ++ time::Delta, + }; + + use crate::{ +@@ -351,6 +350,9 @@ pub(crate) struct FalconBromParams { + + /// Trait for providing load parameters of falcon firmwares. + pub(crate) trait FalconLoadParams { ++ /// Returns the firmware data as a slice of bytes. ++ fn as_slice(&self) -> &[u8]; ++ + /// Returns the load parameters for Secure `IMEM`. + fn imem_sec_load_params(&self) -> FalconLoadTarget; + +@@ -370,9 +372,8 @@ pub(crate) trait FalconLoadParams { + + /// Trait for a falcon firmware. + /// +-/// A falcon firmware can be loaded on a given engine, and is presented in the form of a DMA +-/// object. +-pub(crate) trait FalconFirmware: FalconLoadParams + Deref { ++/// A falcon firmware can be loaded on a given engine. ++pub(crate) trait FalconFirmware: FalconLoadParams { + /// Engine on which this firmware is to be loaded. + type Target: FalconEngine; + } +@@ -415,10 +416,10 @@ pub(crate) fn reset(&self, bar: &Bar0) -> Result { + /// `target_mem`. + /// + /// `sec` is set if the loaded firmware is expected to run in secure mode. +- fn dma_wr>( ++ fn dma_wr( + &self, + bar: &Bar0, +- fw: &F, ++ dma_obj: &DmaObject, + target_mem: FalconMem, + load_offsets: FalconLoadTarget, + ) -> Result { +@@ -430,11 +431,11 @@ fn dma_wr>( + // For DMEM we can fold the start offset into the DMA handle. + let (src_start, dma_start) = match target_mem { + FalconMem::ImemSecure | FalconMem::ImemNonSecure => { +- (load_offsets.src_start, fw.dma_handle()) ++ (load_offsets.src_start, dma_obj.dma_handle()) + } + FalconMem::Dmem => ( + 0, +- fw.dma_handle_with_offset(load_offsets.src_start.into_safe_cast())?, ++ dma_obj.dma_handle_with_offset(load_offsets.src_start.into_safe_cast())?, + ), + }; + if dma_start % DmaAddress::from(DMA_LEN) > 0 { +@@ -466,7 +467,7 @@ fn dma_wr>( + dev_err!(self.dev, "DMA transfer length overflow\n"); + return Err(EOVERFLOW); + } +- Some(upper_bound) if usize::from_safe_cast(upper_bound) > fw.size() => { ++ Some(upper_bound) if usize::from_safe_cast(upper_bound) > dma_obj.size() => { + dev_err!(self.dev, "DMA transfer goes beyond range of DMA object\n"); + return Err(EINVAL); + } +@@ -515,7 +516,12 @@ fn dma_wr>( + } + + /// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it. +- fn dma_load>(&self, bar: &Bar0, fw: &F) -> Result { ++ fn dma_load>( ++ &self, ++ dev: &Device, ++ bar: &Bar0, ++ fw: &F, ++ ) -> Result { + // The Non-Secure section only exists on firmware used by Turing and GA100, and + // those platforms do not use DMA. + if fw.imem_ns_load_params().is_some() { +@@ -523,14 +529,22 @@ fn dma_load>(&self, bar: &Bar0, fw: &F) -> Result + return Err(EINVAL); + } + ++ // Create DMA object with firmware content as the source of the DMA engine. ++ let dma_obj = DmaObject::from_data(dev, fw.as_slice())?; ++ + self.dma_reset(bar); + regs::NV_PFALCON_FBIF_TRANSCFG::update(bar, &E::ID, 0, |v| { + v.set_target(FalconFbifTarget::CoherentSysmem) + .set_mem_type(FalconFbifMemType::Physical) + }); + +- self.dma_wr(bar, fw, FalconMem::ImemSecure, fw.imem_sec_load_params())?; +- self.dma_wr(bar, fw, FalconMem::Dmem, fw.dmem_load_params())?; ++ self.dma_wr( ++ bar, ++ &dma_obj, ++ FalconMem::ImemSecure, ++ fw.imem_sec_load_params(), ++ )?; ++ self.dma_wr(bar, &dma_obj, FalconMem::Dmem, fw.dmem_load_params())?; + + self.hal.program_brom(self, bar, &fw.brom_params())?; + +@@ -641,9 +655,14 @@ pub(crate) fn is_riscv_active(&self, bar: &Bar0) -> bool { + } + + // Load a firmware image into Falcon memory +- pub(crate) fn load>(&self, bar: &Bar0, fw: &F) -> Result { ++ pub(crate) fn load>( ++ &self, ++ dev: &Device, ++ bar: &Bar0, ++ fw: &F, ++ ) -> Result { + match self.hal.load_method() { +- LoadMethod::Dma => self.dma_load(bar, fw), ++ LoadMethod::Dma => self.dma_load(dev, bar, fw), + LoadMethod::Pio => Err(ENOTSUPP), + } + } +diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs +index 68779540aa284..be911d0a38276 100644 +--- a/drivers/gpu/nova-core/firmware.rs ++++ b/drivers/gpu/nova-core/firmware.rs +@@ -15,7 +15,6 @@ + }; + + use crate::{ +- dma::DmaObject, + falcon::{ + FalconFirmware, + FalconLoadTarget, // +@@ -292,7 +291,7 @@ impl SignedState for Unsigned {} + struct Signed; + impl SignedState for Signed {} + +-/// A [`DmaObject`] containing a specific microcode ready to be loaded into a falcon. ++/// Microcode to be loaded into a specific falcon. + /// + /// This is module-local and meant for sub-modules to use internally. + /// +@@ -300,34 +299,35 @@ impl SignedState for Signed {} + /// before it can be loaded (with an exception for development hardware). The + /// [`Self::patch_signature`] and [`Self::no_patch_signature`] methods are used to transition the + /// firmware to its [`Signed`] state. +-struct FirmwareDmaObject(DmaObject, PhantomData<(F, S)>); ++// TODO: Consider replacing this with a coherent memory object once `CoherentAllocation` supports ++// temporary CPU-exclusive access to the object without unsafe methods. ++struct FirmwareObject(KVVec, PhantomData<(F, S)>); + + /// Trait for signatures to be patched directly into a given firmware. + /// + /// This is module-local and meant for sub-modules to use internally. + trait FirmwareSignature: AsRef<[u8]> {} + +-impl FirmwareDmaObject { +- /// Patches the firmware at offset `sig_base_img` with `signature`. ++impl FirmwareObject { ++ /// Patches the firmware at offset `signature_start` with `signature`. + fn patch_signature>( + mut self, + signature: &S, +- sig_base_img: usize, +- ) -> Result> { ++ signature_start: usize, ++ ) -> Result> { + let signature_bytes = signature.as_ref(); +- if sig_base_img + signature_bytes.len() > self.0.size() { +- return Err(EINVAL); +- } +- +- // SAFETY: We are the only user of this object, so there cannot be any race. +- let dst = unsafe { self.0.start_ptr_mut().add(sig_base_img) }; ++ let signature_end = signature_start ++ .checked_add(signature_bytes.len()) ++ .ok_or(EOVERFLOW)?; ++ let dst = self ++ .0 ++ .get_mut(signature_start..signature_end) ++ .ok_or(EINVAL)?; + +- // SAFETY: `signature` and `dst` are valid, properly aligned, and do not overlap. +- unsafe { +- core::ptr::copy_nonoverlapping(signature_bytes.as_ptr(), dst, signature_bytes.len()) +- }; ++ // PANIC: `dst` and `signature_bytes` have the same length. ++ dst.copy_from_slice(signature_bytes); + +- Ok(FirmwareDmaObject(self.0, PhantomData)) ++ Ok(FirmwareObject(self.0, PhantomData)) + } + + /// Mark the firmware as signed without patching it. +@@ -335,8 +335,8 @@ fn patch_signature>( + /// This method is used to explicitly confirm that we do not need to sign the firmware, while + /// allowing us to continue as if it was. This is typically only needed for development + /// hardware. +- fn no_patch_signature(self) -> FirmwareDmaObject { +- FirmwareDmaObject(self.0, PhantomData) ++ fn no_patch_signature(self) -> FirmwareObject { ++ FirmwareObject(self.0, PhantomData) + } + } + +diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs +index 86556cee8e67b..ab7956602e758 100644 +--- a/drivers/gpu/nova-core/firmware/booter.rs ++++ b/drivers/gpu/nova-core/firmware/booter.rs +@@ -4,10 +4,7 @@ + //! running on [`Sec2`], that is used on Turing/Ampere to load the GSP firmware into the GSP falcon + //! (and optionally unload it through a separate firmware image). + +-use core::{ +- marker::PhantomData, +- ops::Deref, // +-}; ++use core::marker::PhantomData; + + use kernel::{ + device, +@@ -16,7 +13,6 @@ + }; + + use crate::{ +- dma::DmaObject, + driver::Bar0, + falcon::{ + sec2::Sec2, +@@ -28,7 +24,7 @@ + }, + firmware::{ + BinFirmware, +- FirmwareDmaObject, ++ FirmwareObject, + FirmwareSignature, + Signed, + Unsigned, // +@@ -261,12 +257,15 @@ pub(crate) struct BooterFirmware { + // BROM falcon parameters. + brom_params: FalconBromParams, + // Device-mapped firmware image. +- ucode: FirmwareDmaObject, ++ ucode: FirmwareObject, + } + +-impl FirmwareDmaObject { +- fn new_booter(dev: &device::Device, data: &[u8]) -> Result { +- DmaObject::from_data(dev, data).map(|ucode| Self(ucode, PhantomData)) ++impl FirmwareObject { ++ fn new_booter(data: &[u8]) -> Result { ++ let mut ucode = KVVec::new(); ++ ucode.extend_from_slice(data, GFP_KERNEL)?; ++ ++ Ok(Self(ucode, PhantomData)) + } + } + +@@ -320,7 +319,7 @@ pub(crate) fn new( + let ucode = bin_fw + .data() + .ok_or(EINVAL) +- .and_then(|data| FirmwareDmaObject::::new_booter(dev, data))?; ++ .and_then(FirmwareObject::::new_booter)?; + + let ucode_signed = { + let mut signatures = hs_fw.signatures_iter()?.peekable(); +@@ -392,6 +391,10 @@ pub(crate) fn new( + } + + impl FalconLoadParams for BooterFirmware { ++ fn as_slice(&self) -> &[u8] { ++ self.ucode.0.as_slice() ++ } ++ + fn imem_sec_load_params(&self) -> FalconLoadTarget { + self.imem_sec_load_target.clone() + } +@@ -417,14 +420,6 @@ fn boot_addr(&self) -> u32 { + } + } + +-impl Deref for BooterFirmware { +- type Target = DmaObject; +- +- fn deref(&self) -> &Self::Target { +- &self.ucode.0 +- } +-} +- + impl FalconFirmware for BooterFirmware { + type Target = Sec2; + } +diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs +index df3d8de14ca14..7fff3acdaa735 100644 +--- a/drivers/gpu/nova-core/firmware/fwsec.rs ++++ b/drivers/gpu/nova-core/firmware/fwsec.rs +@@ -10,10 +10,7 @@ + //! - The command to be run, as this firmware can perform several tasks ; + //! - The ucode signature, so the GSP falcon can run FWSEC in HS mode. + +-use core::{ +- marker::PhantomData, +- ops::Deref, // +-}; ++use core::marker::PhantomData; + + use kernel::{ + device::{ +@@ -28,7 +25,6 @@ + }; + + use crate::{ +- dma::DmaObject, + driver::Bar0, + falcon::{ + gsp::Gsp, +@@ -40,7 +36,7 @@ + }, + firmware::{ + FalconUCodeDesc, +- FirmwareDmaObject, ++ FirmwareObject, + FirmwareSignature, + Signed, + Unsigned, // +@@ -174,52 +170,21 @@ fn as_ref(&self) -> &[u8] { + + impl FirmwareSignature for Bcrt30Rsa3kSignature {} + +-/// Reinterpret the area starting from `offset` in `fw` as an instance of `T` (which must implement +-/// [`FromBytes`]) and return a reference to it. +-/// +-/// # Safety +-/// +-/// * Callers must ensure that the device does not read/write to/from memory while the returned +-/// reference is live. +-/// * Callers must ensure that this call does not race with a write to the same region while +-/// the returned reference is live. +-unsafe fn transmute(fw: &DmaObject, offset: usize) -> Result<&T> { +- // SAFETY: The safety requirements of the function guarantee the device won't read +- // or write to memory while the reference is alive and that this call won't race +- // with writes to the same memory region. +- T::from_bytes(unsafe { fw.as_slice(offset, size_of::())? }).ok_or(EINVAL) +-} +- +-/// Reinterpret the area starting from `offset` in `fw` as a mutable instance of `T` (which must +-/// implement [`FromBytes`]) and return a reference to it. +-/// +-/// # Safety +-/// +-/// * Callers must ensure that the device does not read/write to/from memory while the returned +-/// slice is live. +-/// * Callers must ensure that this call does not race with a read or write to the same region +-/// while the returned slice is live. +-unsafe fn transmute_mut( +- fw: &mut DmaObject, +- offset: usize, +-) -> Result<&mut T> { +- // SAFETY: The safety requirements of the function guarantee the device won't read +- // or write to memory while the reference is alive and that this call won't race +- // with writes or reads to the same memory region. +- T::from_bytes_mut(unsafe { fw.as_slice_mut(offset, size_of::())? }).ok_or(EINVAL) +-} +- + /// The FWSEC microcode, extracted from the BIOS and to be run on the GSP falcon. + /// + /// It is responsible for e.g. carving out the WPR2 region as the first step of the GSP bootflow. + pub(crate) struct FwsecFirmware { + /// Descriptor of the firmware. + desc: FalconUCodeDesc, +- /// GPU-accessible DMA object containing the firmware. +- ucode: FirmwareDmaObject, ++ /// Object containing the firmware binary. ++ ucode: FirmwareObject, + } + + impl FalconLoadParams for FwsecFirmware { ++ fn as_slice(&self) -> &[u8] { ++ self.ucode.0.as_slice() ++ } ++ + fn imem_sec_load_params(&self) -> FalconLoadTarget { + self.desc.imem_sec_load_params() + } +@@ -245,23 +210,15 @@ fn boot_addr(&self) -> u32 { + } + } + +-impl Deref for FwsecFirmware { +- type Target = DmaObject; +- +- fn deref(&self) -> &Self::Target { +- &self.ucode.0 +- } +-} +- + impl FalconFirmware for FwsecFirmware { + type Target = Gsp; + } + +-impl FirmwareDmaObject { +- fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Result { ++impl FirmwareObject { ++ fn new_fwsec(bios: &Vbios, cmd: FwsecCommand) -> Result { + let desc = bios.fwsec_image().header()?; +- let ucode = bios.fwsec_image().ucode(&desc)?; +- let mut dma_object = DmaObject::from_data(dev, ucode)?; ++ let mut ucode = KVVec::new(); ++ ucode.extend_from_slice(bios.fwsec_image().ucode(&desc)?, GFP_KERNEL)?; + + let hdr_offset = desc + .imem_load_size() +@@ -269,8 +226,11 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + .map(usize::from_safe_cast) + .ok_or(EINVAL)?; + +- // SAFETY: we have exclusive access to `dma_object`. +- let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?; ++ let hdr = ucode ++ .get(hdr_offset..) ++ .and_then(FalconAppifHdrV1::from_bytes_prefix) ++ .ok_or(EINVAL)? ++ .0; + + if hdr.version != 1 { + return Err(EINVAL); +@@ -284,8 +244,11 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + .and_then(|o| o.checked_add(i.checked_mul(usize::from(hdr.entry_size))?)) + .ok_or(EINVAL)?; + +- // SAFETY: we have exclusive access to `dma_object`. +- let app: &FalconAppifV1 = unsafe { transmute(&dma_object, entry_offset) }?; ++ let app = ucode ++ .get(entry_offset..) ++ .and_then(FalconAppifV1::from_bytes_prefix) ++ .ok_or(EINVAL)? ++ .0; + + if app.id != NVFW_FALCON_APPIF_ID_DMEMMAPPER { + continue; +@@ -298,9 +261,11 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + .map(usize::from_safe_cast) + .ok_or(EINVAL)?; + +- let dmem_mapper: &mut FalconAppifDmemmapperV3 = +- // SAFETY: we have exclusive access to `dma_object`. +- unsafe { transmute_mut(&mut dma_object, dmem_mapper_offset) }?; ++ let dmem_mapper = ucode ++ .get_mut(dmem_mapper_offset..) ++ .and_then(FalconAppifDmemmapperV3::from_bytes_mut_prefix) ++ .ok_or(EINVAL)? ++ .0; + + dmem_mapper.init_cmd = match cmd { + FwsecCommand::Frts { .. } => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS, +@@ -314,9 +279,11 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + .map(usize::from_safe_cast) + .ok_or(EINVAL)?; + +- let frts_cmd: &mut FrtsCmd = +- // SAFETY: we have exclusive access to `dma_object`. +- unsafe { transmute_mut(&mut dma_object, frts_cmd_offset) }?; ++ let frts_cmd = ucode ++ .get_mut(frts_cmd_offset..) ++ .and_then(FrtsCmd::from_bytes_mut_prefix) ++ .ok_or(EINVAL)? ++ .0; + + frts_cmd.read_vbios = ReadVbios { + ver: 1, +@@ -340,7 +307,7 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + } + + // Return early as we found and patched the DMEMMAPPER region. +- return Ok(Self(dma_object, PhantomData)); ++ return Ok(Self(ucode, PhantomData)); + } + + Err(ENOTSUPP) +@@ -357,7 +324,7 @@ pub(crate) fn new( + bios: &Vbios, + cmd: FwsecCommand, + ) -> Result { +- let ucode_dma = FirmwareDmaObject::::new_fwsec(dev, bios, cmd)?; ++ let ucode_dma = FirmwareObject::::new_fwsec(bios, cmd)?; + + // Patch signature if needed. + let desc = bios.fwsec_image().header()?; +@@ -429,7 +396,7 @@ pub(crate) fn run( + .reset(bar) + .inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?; + falcon +- .load(bar, self) ++ .load(dev, bar, self) + .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?; + let (mbox0, _) = falcon + .boot(bar, Some(0), None) +diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs +index 94833f7996e8a..62ffed5f25a15 100644 +--- a/drivers/gpu/nova-core/gsp/boot.rs ++++ b/drivers/gpu/nova-core/gsp/boot.rs +@@ -183,7 +183,7 @@ pub(crate) fn boot( + ); + + sec2_falcon.reset(bar)?; +- sec2_falcon.load(bar, &booter_loader)?; ++ sec2_falcon.load(dev, bar, &booter_loader)?; + let wpr_handle = wpr_meta.dma_handle(); + let (mbox0, mbox1) = sec2_falcon.boot( + bar, +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-falcon-rename-load-parameters-to-refle.patch b/queue-7.0/gpu-nova-core-falcon-rename-load-parameters-to-refle.patch new file mode 100644 index 0000000000..a3d979e07c --- /dev/null +++ b/queue-7.0/gpu-nova-core-falcon-rename-load-parameters-to-refle.patch @@ -0,0 +1,304 @@ +From 217091b14b8de67ceb3c5938e4415f568f6018a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 13:52:40 +0900 +Subject: gpu: nova-core: falcon: rename load parameters to reflect DMA + dependency + +From: Alexandre Courbot + +[ Upstream commit 8a623869b8269dbf52d52711cd7b9355044b6b53 ] + +The current `FalconLoadParams` and `FalconLoadTarget` types are fit for +DMA loading, but not so much for PIO loading which will require its own +types. Start by renaming them to something that indicates that they are +indeed DMA-related. + +Reviewed-by: Eliot Courtney +Acked-by: Danilo Krummrich +Link: https://patch.msgid.link/20260306-turing_prep-v11-3-8f0042c5d026@nvidia.com +[acourbot@nvidia.com: fixup order of import items.] +Signed-off-by: Alexandre Courbot +Stable-dep-of: 17d7c97f73c7 ("gpu: nova-core: firmware: fix and explain v2 header offsets computations") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/falcon.rs | 19 +++++++------- + drivers/gpu/nova-core/firmware.rs | 32 ++++++++++++------------ + drivers/gpu/nova-core/firmware/booter.rs | 26 +++++++++---------- + drivers/gpu/nova-core/firmware/fwsec.rs | 14 +++++------ + 4 files changed, 46 insertions(+), 45 deletions(-) + +diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs +index 8d444cf9d55c1..808c17e981d19 100644 +--- a/drivers/gpu/nova-core/falcon.rs ++++ b/drivers/gpu/nova-core/falcon.rs +@@ -326,9 +326,10 @@ pub(crate) trait FalconEngine: + const ID: Self; + } + +-/// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM). ++/// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM) ++/// using DMA. + #[derive(Debug, Clone)] +-pub(crate) struct FalconLoadTarget { ++pub(crate) struct FalconDmaLoadTarget { + /// Offset from the start of the source object to copy from. + pub(crate) src_start: u32, + /// Offset from the start of the destination memory to copy into. +@@ -348,20 +349,20 @@ pub(crate) struct FalconBromParams { + pub(crate) ucode_id: u8, + } + +-/// Trait for providing load parameters of falcon firmwares. +-pub(crate) trait FalconLoadParams { ++/// Trait implemented by falcon firmwares that can be loaded using DMA. ++pub(crate) trait FalconDmaLoadable { + /// Returns the firmware data as a slice of bytes. + fn as_slice(&self) -> &[u8]; + + /// Returns the load parameters for Secure `IMEM`. +- fn imem_sec_load_params(&self) -> FalconLoadTarget; ++ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget; + + /// Returns the load parameters for Non-Secure `IMEM`, + /// used only on Turing and GA100. +- fn imem_ns_load_params(&self) -> Option; ++ fn imem_ns_load_params(&self) -> Option; + + /// Returns the load parameters for `DMEM`. +- fn dmem_load_params(&self) -> FalconLoadTarget; ++ fn dmem_load_params(&self) -> FalconDmaLoadTarget; + + /// Returns the parameters to write into the BROM registers. + fn brom_params(&self) -> FalconBromParams; +@@ -373,7 +374,7 @@ pub(crate) trait FalconLoadParams { + /// Trait for a falcon firmware. + /// + /// A falcon firmware can be loaded on a given engine. +-pub(crate) trait FalconFirmware: FalconLoadParams { ++pub(crate) trait FalconFirmware: FalconDmaLoadable { + /// Engine on which this firmware is to be loaded. + type Target: FalconEngine; + } +@@ -421,7 +422,7 @@ fn dma_wr( + bar: &Bar0, + dma_obj: &DmaObject, + target_mem: FalconMem, +- load_offsets: FalconLoadTarget, ++ load_offsets: FalconDmaLoadTarget, + ) -> Result { + const DMA_LEN: u32 = 256; + +diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs +index be911d0a38276..186f166564651 100644 +--- a/drivers/gpu/nova-core/firmware.rs ++++ b/drivers/gpu/nova-core/firmware.rs +@@ -16,8 +16,8 @@ + + use crate::{ + falcon::{ +- FalconFirmware, +- FalconLoadTarget, // ++ FalconDmaLoadTarget, ++ FalconFirmware, // + }, + gpu, + num::{ +@@ -170,9 +170,9 @@ fn size(&self) -> usize { + ((hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT).into_safe_cast() + } + +- fn imem_sec_load_params(&self) -> FalconLoadTarget; +- fn imem_ns_load_params(&self) -> Option; +- fn dmem_load_params(&self) -> FalconLoadTarget; ++ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget; ++ fn imem_ns_load_params(&self) -> Option; ++ fn dmem_load_params(&self) -> FalconDmaLoadTarget; + } + + impl FalconUCodeDescriptor for FalconUCodeDescV2 { +@@ -204,24 +204,24 @@ fn signature_versions(&self) -> u16 { + 0 + } + +- fn imem_sec_load_params(&self) -> FalconLoadTarget { +- FalconLoadTarget { ++ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { ++ FalconDmaLoadTarget { + src_start: 0, + dst_start: self.imem_sec_base, + len: self.imem_sec_size, + } + } + +- fn imem_ns_load_params(&self) -> Option { +- Some(FalconLoadTarget { ++ fn imem_ns_load_params(&self) -> Option { ++ Some(FalconDmaLoadTarget { + src_start: 0, + dst_start: self.imem_phys_base, + len: self.imem_load_size.checked_sub(self.imem_sec_size)?, + }) + } + +- fn dmem_load_params(&self) -> FalconLoadTarget { +- FalconLoadTarget { ++ fn dmem_load_params(&self) -> FalconDmaLoadTarget { ++ FalconDmaLoadTarget { + src_start: self.dmem_offset, + dst_start: self.dmem_phys_base, + len: self.dmem_load_size, +@@ -258,21 +258,21 @@ fn signature_versions(&self) -> u16 { + self.signature_versions + } + +- fn imem_sec_load_params(&self) -> FalconLoadTarget { +- FalconLoadTarget { ++ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { ++ FalconDmaLoadTarget { + src_start: 0, + dst_start: self.imem_phys_base, + len: self.imem_load_size, + } + } + +- fn imem_ns_load_params(&self) -> Option { ++ fn imem_ns_load_params(&self) -> Option { + // Not used on V3 platforms + None + } + +- fn dmem_load_params(&self) -> FalconLoadTarget { +- FalconLoadTarget { ++ fn dmem_load_params(&self) -> FalconDmaLoadTarget { ++ FalconDmaLoadTarget { + src_start: self.imem_load_size, + dst_start: self.dmem_phys_base, + len: self.dmem_load_size, +diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs +index ab7956602e758..1a6b2a7e17906 100644 +--- a/drivers/gpu/nova-core/firmware/booter.rs ++++ b/drivers/gpu/nova-core/firmware/booter.rs +@@ -18,9 +18,9 @@ + sec2::Sec2, + Falcon, + FalconBromParams, +- FalconFirmware, +- FalconLoadParams, +- FalconLoadTarget, // ++ FalconDmaLoadTarget, ++ FalconDmaLoadable, ++ FalconFirmware, // + }, + firmware::{ + BinFirmware, +@@ -248,12 +248,12 @@ impl<'a> FirmwareSignature for BooterSignature<'a> {} + /// The `Booter` loader firmware, responsible for loading the GSP. + pub(crate) struct BooterFirmware { + // Load parameters for Secure `IMEM` falcon memory. +- imem_sec_load_target: FalconLoadTarget, ++ imem_sec_load_target: FalconDmaLoadTarget, + // Load parameters for Non-Secure `IMEM` falcon memory, + // used only on Turing and GA100 +- imem_ns_load_target: Option, ++ imem_ns_load_target: Option, + // Load parameters for `DMEM` falcon memory. +- dmem_load_target: FalconLoadTarget, ++ dmem_load_target: FalconDmaLoadTarget, + // BROM falcon parameters. + brom_params: FalconBromParams, + // Device-mapped firmware image. +@@ -362,7 +362,7 @@ pub(crate) fn new( + let (imem_sec_dst_start, imem_ns_load_target) = if chipset <= Chipset::GA100 { + ( + app0.offset, +- Some(FalconLoadTarget { ++ Some(FalconDmaLoadTarget { + src_start: 0, + dst_start: load_hdr.os_code_offset, + len: load_hdr.os_code_size, +@@ -373,13 +373,13 @@ pub(crate) fn new( + }; + + Ok(Self { +- imem_sec_load_target: FalconLoadTarget { ++ imem_sec_load_target: FalconDmaLoadTarget { + src_start: app0.offset, + dst_start: imem_sec_dst_start, + len: app0.len, + }, + imem_ns_load_target, +- dmem_load_target: FalconLoadTarget { ++ dmem_load_target: FalconDmaLoadTarget { + src_start: load_hdr.os_data_offset, + dst_start: 0, + len: load_hdr.os_data_size, +@@ -390,20 +390,20 @@ pub(crate) fn new( + } + } + +-impl FalconLoadParams for BooterFirmware { ++impl FalconDmaLoadable for BooterFirmware { + fn as_slice(&self) -> &[u8] { + self.ucode.0.as_slice() + } + +- fn imem_sec_load_params(&self) -> FalconLoadTarget { ++ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { + self.imem_sec_load_target.clone() + } + +- fn imem_ns_load_params(&self) -> Option { ++ fn imem_ns_load_params(&self) -> Option { + self.imem_ns_load_target.clone() + } + +- fn dmem_load_params(&self) -> FalconLoadTarget { ++ fn dmem_load_params(&self) -> FalconDmaLoadTarget { + self.dmem_load_target.clone() + } + +diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs +index 7fff3acdaa735..7ac5cfeb594d4 100644 +--- a/drivers/gpu/nova-core/firmware/fwsec.rs ++++ b/drivers/gpu/nova-core/firmware/fwsec.rs +@@ -30,9 +30,9 @@ + gsp::Gsp, + Falcon, + FalconBromParams, +- FalconFirmware, +- FalconLoadParams, +- FalconLoadTarget, // ++ FalconDmaLoadTarget, ++ FalconDmaLoadable, ++ FalconFirmware, // + }, + firmware::{ + FalconUCodeDesc, +@@ -180,20 +180,20 @@ pub(crate) struct FwsecFirmware { + ucode: FirmwareObject, + } + +-impl FalconLoadParams for FwsecFirmware { ++impl FalconDmaLoadable for FwsecFirmware { + fn as_slice(&self) -> &[u8] { + self.ucode.0.as_slice() + } + +- fn imem_sec_load_params(&self) -> FalconLoadTarget { ++ fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { + self.desc.imem_sec_load_params() + } + +- fn imem_ns_load_params(&self) -> Option { ++ fn imem_ns_load_params(&self) -> Option { + self.desc.imem_ns_load_params() + } + +- fn dmem_load_params(&self) -> FalconLoadTarget { ++ fn dmem_load_params(&self) -> FalconDmaLoadTarget { + self.desc.dmem_load_params() + } + +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-firmware-fix-and-explain-v2-header-off.patch b/queue-7.0/gpu-nova-core-firmware-fix-and-explain-v2-header-off.patch new file mode 100644 index 0000000000..dd39978962 --- /dev/null +++ b/queue-7.0/gpu-nova-core-firmware-fix-and-explain-v2-header-off.patch @@ -0,0 +1,78 @@ +From c9a94fb4371e9eaa68e6b36c77b9da9ea298bbeb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 13:52:46 +0900 +Subject: gpu: nova-core: firmware: fix and explain v2 header offsets + computations + +From: Alexandre Courbot + +[ Upstream commit 17d7c97f73c7a0bd90bd22cd7441269a6f8a1d72 ] + +There are no offsets in `FalconUCodeDescV2` to give the non-secure and +secure IMEM sections start offsets relative to the beginning of the +firmware object. + +The start offsets for both sections were set to `0`, but that is +obviously incorrect since two different sections cannot start at the +same offset. Since these offsets were not used by the bootloader, this +doesn't prevent proper function but is incorrect nonetheless. + +Fix this by computing the start of the secure IMEM section relatively to +the start of the firmware object and setting it properly. Also add and +improve comments to explain how the values are obtained. + +Fixes: dbfb5aa41f16 ("gpu: nova-core: add FalconUCodeDescV2 support") +Reviewed-by: Eliot Courtney +Link: https://patch.msgid.link/20260306-turing_prep-v11-9-8f0042c5d026@nvidia.com +Signed-off-by: Alexandre Courbot +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/firmware.rs | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs +index 186f166564651..6a58118648652 100644 +--- a/drivers/gpu/nova-core/firmware.rs ++++ b/drivers/gpu/nova-core/firmware.rs +@@ -63,7 +63,8 @@ pub(crate) struct FalconUCodeDescV2 { + pub(crate) interface_offset: u32, + /// Base address at which to load the code segment into 'IMEM'. + pub(crate) imem_phys_base: u32, +- /// Size in bytes of the code to copy into 'IMEM'. ++ /// Size in bytes of the code to copy into 'IMEM' (includes both secure and non-secure ++ /// segments). + pub(crate) imem_load_size: u32, + /// Virtual 'IMEM' address (i.e. 'tag') at which the code should start. + pub(crate) imem_virt_base: u32, +@@ -205,18 +206,25 @@ fn signature_versions(&self) -> u16 { + } + + fn imem_sec_load_params(&self) -> FalconDmaLoadTarget { ++ // `imem_sec_base` is the *virtual* start address of the secure IMEM segment, so subtract ++ // `imem_virt_base` to get its physical offset. ++ let imem_sec_start = self.imem_sec_base.saturating_sub(self.imem_virt_base); ++ + FalconDmaLoadTarget { +- src_start: 0, +- dst_start: self.imem_sec_base, ++ src_start: imem_sec_start, ++ dst_start: self.imem_phys_base.saturating_add(imem_sec_start), + len: self.imem_sec_size, + } + } + + fn imem_ns_load_params(&self) -> Option { + Some(FalconDmaLoadTarget { ++ // Non-secure code always starts at offset 0. + src_start: 0, + dst_start: self.imem_phys_base, +- len: self.imem_load_size.checked_sub(self.imem_sec_size)?, ++ // `imem_load_size` includes the size of the secure segment, so subtract it to ++ // get the correct amount of data to copy. ++ len: self.imem_load_size.saturating_sub(self.imem_sec_size), + }) + } + +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-fix-missing-colon-in-sec2-boot-debug-m.patch b/queue-7.0/gpu-nova-core-fix-missing-colon-in-sec2-boot-debug-m.patch new file mode 100644 index 0000000000..ba1390ab13 --- /dev/null +++ b/queue-7.0/gpu-nova-core-fix-missing-colon-in-sec2-boot-debug-m.patch @@ -0,0 +1,38 @@ +From a4bc50c1719383d9a732a39a8e803927bd737573 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 11:37:44 +0100 +Subject: gpu: nova-core: fix missing colon in SEC2 boot debug message + +From: David Carlier + +[ Upstream commit a7a080bb4236ebe577b6776d940d1717912ff6dd ] + +The SEC2 mailbox debug output formats MBOX1 without a colon separator, +producing "MBOX10xdead" instead of "MBOX1: 0xdead". The GSP debug +message a few lines above uses the correct format. + +Fixes: 5949d419c193 ("gpu: nova-core: gsp: Boot GSP") +Signed-off-by: David Carlier +Link: https://patch.msgid.link/20260331103744.605683-1-devnexen@gmail.com +Signed-off-by: Alexandre Courbot +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/gsp/boot.rs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs +index a13255c464bc3..99e7a0b7e3107 100644 +--- a/drivers/gpu/nova-core/gsp/boot.rs ++++ b/drivers/gpu/nova-core/gsp/boot.rs +@@ -185,7 +185,7 @@ pub(crate) fn boot( + Some(wpr_handle as u32), + Some((wpr_handle >> 32) as u32), + )?; +- dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", mbox0, mbox1); ++ dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1); + + if mbox0 != 0 { + dev_err!(pdev, "Booter-load failed with error {:#x}\n", mbox0); +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-gsp-fix-improper-handling-of-empty-slo.patch b/queue-7.0/gpu-nova-core-gsp-fix-improper-handling-of-empty-slo.patch new file mode 100644 index 0000000000..a77628752a --- /dev/null +++ b/queue-7.0/gpu-nova-core-gsp-fix-improper-handling-of-empty-slo.patch @@ -0,0 +1,75 @@ +From 923ee42df7fbfaf60e66018415f77e3e3e1f02a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 16:45:02 +0900 +Subject: gpu: nova-core: gsp: fix improper handling of empty slot in cmdq + +From: Eliot Courtney + +[ Upstream commit f64caf673cb5add9ac2065609a52049e2317c498 ] + +The current code hands out buffers that go all the way up to and +including `rx - 1`, but we need to maintain an empty slot to prevent the +ring buffer from wrapping around into having 'tx == rx', which means +empty. + +Also add more rigorous no-panic proofs. + +Fixes: 75f6b1de8133 ("gpu: nova-core: gsp: Add GSP command queue bindings and handling") +Signed-off-by: Eliot Courtney +Reviewed-by: Gary Guo +Link: https://patch.msgid.link/20260129-nova-core-cmdq1-v3-4-2ede85493a27@nvidia.com +Signed-off-by: Alexandre Courbot +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/gsp/cmdq.rs | 34 ++++++++++++++++++------------- + 1 file changed, 20 insertions(+), 14 deletions(-) + +diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs +index fc4e7b1074307..5da153c71800a 100644 +--- a/drivers/gpu/nova-core/gsp/cmdq.rs ++++ b/drivers/gpu/nova-core/gsp/cmdq.rs +@@ -237,21 +237,27 @@ fn new(dev: &device::Device) -> Result { + // PANIC: per the invariant of `cpu_write_ptr`, `tx` is `<= MSGQ_NUM_PAGES`. + let (before_tx, after_tx) = gsp_mem.cpuq.msgq.data.split_at_mut(tx); + +- if rx <= tx { +- // The area from `tx` up to the end of the ring, and from the beginning of the ring up +- // to `rx`, minus one unit, belongs to the driver. +- if rx == 0 { +- let last = after_tx.len() - 1; +- (&mut after_tx[..last], &mut []) +- } else { +- (after_tx, &mut before_tx[..rx]) +- } ++ // The area starting at `tx` and ending at `rx - 2` modulo MSGQ_NUM_PAGES, inclusive, ++ // belongs to the driver for writing. ++ ++ if rx == 0 { ++ // Since `rx` is zero, leave an empty slot at end of the buffer. ++ let last = after_tx.len() - 1; ++ (&mut after_tx[..last], &mut []) ++ } else if rx <= tx { ++ // The area is discontiguous and we leave an empty slot before `rx`. ++ // PANIC: ++ // - The index `rx - 1` is non-negative because `rx != 0` in this branch. ++ // - The index does not exceed `before_tx.len()` (which equals `tx`) because ++ // `rx <= tx` in this branch. ++ (after_tx, &mut before_tx[..(rx - 1)]) + } else { +- // The area from `tx` to `rx`, minus one unit, belongs to the driver. +- // +- // PANIC: per the invariants of `cpu_write_ptr` and `gsp_read_ptr`, `rx` and `tx` are +- // `<= MSGQ_NUM_PAGES`, and the test above ensured that `rx > tx`. +- (after_tx.split_at_mut(rx - tx).0, &mut []) ++ // The area is contiguous and we leave an empty slot before `rx`. ++ // PANIC: ++ // - The index `rx - tx - 1` is non-negative because `rx > tx` in this branch. ++ // - The index does not exceed `after_tx.len()` (which is `MSGQ_NUM_PAGES - tx`) ++ // because `rx < MSGQ_NUM_PAGES` by the `gsp_read_ptr` invariant. ++ (&mut after_tx[..(rx - tx - 1)], &mut []) + } + } + +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-gsp-use-empty-slices-instead-of-0.0-ra.patch b/queue-7.0/gpu-nova-core-gsp-use-empty-slices-instead-of-0.0-ra.patch new file mode 100644 index 0000000000..e6647b1224 --- /dev/null +++ b/queue-7.0/gpu-nova-core-gsp-use-empty-slices-instead-of-0.0-ra.patch @@ -0,0 +1,58 @@ +From efb9aa9ed99b2fe8ea7893208b91f9830e4754c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 16:45:01 +0900 +Subject: gpu: nova-core: gsp: use empty slices instead of [0..0] ranges + +From: Eliot Courtney + +[ Upstream commit f6f072d8ef06ff5d29a6bb1bade3da29a1aafeec ] + +The current code unnecessarily uses, for example, &before_rx[0..0] to +return an empty slice. Instead, just use an empty slice. + +Signed-off-by: Eliot Courtney +Reviewed-by: Gary Guo +Link: https://patch.msgid.link/20260129-nova-core-cmdq1-v3-3-2ede85493a27@nvidia.com +Signed-off-by: Alexandre Courbot +Stable-dep-of: f64caf673cb5 ("gpu: nova-core: gsp: fix improper handling of empty slot in cmdq") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/gsp/cmdq.rs | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs +index 03a4f35998498..fc4e7b1074307 100644 +--- a/drivers/gpu/nova-core/gsp/cmdq.rs ++++ b/drivers/gpu/nova-core/gsp/cmdq.rs +@@ -242,7 +242,7 @@ fn new(dev: &device::Device) -> Result { + // to `rx`, minus one unit, belongs to the driver. + if rx == 0 { + let last = after_tx.len() - 1; +- (&mut after_tx[..last], &mut before_tx[0..0]) ++ (&mut after_tx[..last], &mut []) + } else { + (after_tx, &mut before_tx[..rx]) + } +@@ -251,7 +251,7 @@ fn new(dev: &device::Device) -> Result { + // + // PANIC: per the invariants of `cpu_write_ptr` and `gsp_read_ptr`, `rx` and `tx` are + // `<= MSGQ_NUM_PAGES`, and the test above ensured that `rx > tx`. +- (after_tx.split_at_mut(rx - tx).0, &mut before_tx[0..0]) ++ (after_tx.split_at_mut(rx - tx).0, &mut []) + } + } + +@@ -273,8 +273,8 @@ fn new(dev: &device::Device) -> Result { + let (before_rx, after_rx) = gsp_mem.gspq.msgq.data.split_at(rx); + + match tx.cmp(&rx) { +- cmp::Ordering::Equal => (&after_rx[0..0], &after_rx[0..0]), +- cmp::Ordering::Greater => (&after_rx[..tx], &before_rx[0..0]), ++ cmp::Ordering::Equal => (&[], &[]), ++ cmp::Ordering::Greater => (&after_rx[..tx], &[]), + cmp::Ordering::Less => (after_rx, &before_rx[..tx]), + } + } +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-remove-redundant-.as_ref-for-dev_-prin.patch b/queue-7.0/gpu-nova-core-remove-redundant-.as_ref-for-dev_-prin.patch new file mode 100644 index 0000000000..d97ff074ab --- /dev/null +++ b/queue-7.0/gpu-nova-core-remove-redundant-.as_ref-for-dev_-prin.patch @@ -0,0 +1,126 @@ +From 0b967362d15585e51a94f2f5fb7cfb93a5074bfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jan 2026 17:58:44 +0000 +Subject: gpu: nova-core: remove redundant `.as_ref()` for `dev_*` print + +From: Gary Guo + +[ Upstream commit 8d1a65c2defdc4213a49008d0531bd35d26fdf35 ] + +This is now handled by the macro itself. + +Signed-off-by: Gary Guo +Link: https://patch.msgid.link/20260123175854.176735-7-gary@kernel.org +Signed-off-by: Danilo Krummrich +Stable-dep-of: a7a080bb4236 ("gpu: nova-core: fix missing colon in SEC2 boot debug message") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/driver.rs | 2 +- + drivers/gpu/nova-core/gpu.rs | 4 ++-- + drivers/gpu/nova-core/gsp/boot.rs | 32 +++++++------------------------ + 3 files changed, 10 insertions(+), 28 deletions(-) + +diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs +index 5a4cc047bcfc9..e39885c0d5ca5 100644 +--- a/drivers/gpu/nova-core/driver.rs ++++ b/drivers/gpu/nova-core/driver.rs +@@ -70,7 +70,7 @@ impl pci::Driver for NovaCore { + + fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinInit { + pin_init::pin_init_scope(move || { +- dev_dbg!(pdev.as_ref(), "Probe Nova Core GPU driver.\n"); ++ dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); + + pdev.enable_device_mem()?; + pdev.set_master(); +diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs +index 9b042ef1a3086..60c85fffaeafd 100644 +--- a/drivers/gpu/nova-core/gpu.rs ++++ b/drivers/gpu/nova-core/gpu.rs +@@ -262,13 +262,13 @@ pub(crate) fn new<'a>( + ) -> impl PinInit + 'a { + try_pin_init!(Self { + spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| { +- dev_info!(pdev.as_ref(),"NVIDIA ({})\n", spec); ++ dev_info!(pdev,"NVIDIA ({})\n", spec); + })?, + + // We must wait for GFW_BOOT completion before doing any significant setup on the GPU. + _: { + gfw::wait_gfw_boot_completion(bar) +- .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete\n"))?; ++ .inspect_err(|_| dev_err!(pdev, "GFW boot did not complete\n"))?; + }, + + sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?, +diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs +index 62ffed5f25a15..a13255c464bc3 100644 +--- a/drivers/gpu/nova-core/gsp/boot.rs ++++ b/drivers/gpu/nova-core/gsp/boot.rs +@@ -170,15 +170,10 @@ pub(crate) fn boot( + Some(libos_handle as u32), + Some((libos_handle >> 32) as u32), + )?; +- dev_dbg!( +- pdev.as_ref(), +- "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", +- mbox0, +- mbox1 +- ); ++ dev_dbg!(pdev, "GSP MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1); + + dev_dbg!( +- pdev.as_ref(), ++ pdev, + "Using SEC2 to load and run the booter_load firmware...\n" + ); + +@@ -190,19 +185,10 @@ pub(crate) fn boot( + Some(wpr_handle as u32), + Some((wpr_handle >> 32) as u32), + )?; +- dev_dbg!( +- pdev.as_ref(), +- "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", +- mbox0, +- mbox1 +- ); ++ dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", mbox0, mbox1); + + if mbox0 != 0 { +- dev_err!( +- pdev.as_ref(), +- "Booter-load failed with error {:#x}\n", +- mbox0 +- ); ++ dev_err!(pdev, "Booter-load failed with error {:#x}\n", mbox0); + return Err(ENODEV); + } + +@@ -216,11 +202,7 @@ pub(crate) fn boot( + Delta::from_secs(5), + )?; + +- dev_dbg!( +- pdev.as_ref(), +- "RISC-V active? {}\n", +- gsp_falcon.is_riscv_active(bar), +- ); ++ dev_dbg!(pdev, "RISC-V active? {}\n", gsp_falcon.is_riscv_active(bar),); + + // Create and run the GSP sequencer. + let seq_params = GspSequencerParams { +@@ -239,8 +221,8 @@ pub(crate) fn boot( + // Obtain and display basic GPU information. + let info = commands::get_gsp_info(&mut self.cmdq, bar)?; + match info.gpu_name() { +- Ok(name) => dev_info!(pdev.as_ref(), "GPU name: {}\n", name), +- Err(e) => dev_warn!(pdev.as_ref(), "GPU name unavailable: {:?}\n", e), ++ Ok(name) => dev_info!(pdev, "GPU name: {}\n", name), ++ Err(e) => dev_warn!(pdev, "GPU name unavailable: {:?}\n", e), + } + + Ok(()) +-- +2.53.0 + diff --git a/queue-7.0/gpu-nova-core-use-checked-arithmetic-in-fwsec-firmwa.patch b/queue-7.0/gpu-nova-core-use-checked-arithmetic-in-fwsec-firmwa.patch new file mode 100644 index 0000000000..0f187b285c --- /dev/null +++ b/queue-7.0/gpu-nova-core-use-checked-arithmetic-in-fwsec-firmwa.patch @@ -0,0 +1,148 @@ +From 0f49432447a4623a171e3190890370e724fc2098 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:23:01 -0500 +Subject: gpu: nova-core: use checked arithmetic in FWSEC firmware parsing + +From: Joel Fernandes + +[ Upstream commit 0568b376a0b13da6582bce1f2e2bbb2eae7fc266 ] + +Use checked_add() and checked_mul() when computing offsets from + +firmware-provided values in new_fwsec(). +Without checked arithmetic, corrupt firmware could cause integer +overflow. The danger is not just wrapping to a huge value, but +potentially wrapping to a small plausible offset that passes validation +yet accesses entirely wrong data, causing silent corruption or security +issues. + +Reviewed-by: Zhi Wang +Signed-off-by: Joel Fernandes +Reviewed-by: Gary Guo +Link: https://patch.msgid.link/20260126202305.2526618-2-joelagnelf@nvidia.com +[acourbot@nvidia.com: rewrap commit message to make checkpatch happy.] +[acourbot@nvidia.com: add missing empty lines after new code blocks.] +[acourbot@nvidia.com: move SAFETY comments to the unsafe statement they + describe.] +[acourbot@nvidia.com: remove obvious computation comments and use +`CALC:` for the remaining ones.] +Signed-off-by: Alexandre Courbot +Stable-dep-of: 17d7c97f73c7 ("gpu: nova-core: firmware: fix and explain v2 header offsets computations") +Signed-off-by: Sasha Levin +--- + drivers/gpu/nova-core/firmware/fwsec.rs | 64 ++++++++++++++----------- + 1 file changed, 37 insertions(+), 27 deletions(-) + +diff --git a/drivers/gpu/nova-core/firmware/fwsec.rs b/drivers/gpu/nova-core/firmware/fwsec.rs +index bfb7b06b13d15..df3d8de14ca14 100644 +--- a/drivers/gpu/nova-core/firmware/fwsec.rs ++++ b/drivers/gpu/nova-core/firmware/fwsec.rs +@@ -45,10 +45,7 @@ + Signed, + Unsigned, // + }, +- num::{ +- FromSafeCast, +- IntoSafeCast, // +- }, ++ num::FromSafeCast, + vbios::Vbios, + }; + +@@ -266,7 +263,12 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + let ucode = bios.fwsec_image().ucode(&desc)?; + let mut dma_object = DmaObject::from_data(dev, ucode)?; + +- let hdr_offset = usize::from_safe_cast(desc.imem_load_size() + desc.interface_offset()); ++ let hdr_offset = desc ++ .imem_load_size() ++ .checked_add(desc.interface_offset()) ++ .map(usize::from_safe_cast) ++ .ok_or(EINVAL)?; ++ + // SAFETY: we have exclusive access to `dma_object`. + let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?; + +@@ -276,26 +278,29 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + + // Find the DMEM mapper section in the firmware. + for i in 0..usize::from(hdr.entry_count) { ++ // CALC: hdr_offset + header_size + i * entry_size. ++ let entry_offset = hdr_offset ++ .checked_add(usize::from(hdr.header_size)) ++ .and_then(|o| o.checked_add(i.checked_mul(usize::from(hdr.entry_size))?)) ++ .ok_or(EINVAL)?; ++ + // SAFETY: we have exclusive access to `dma_object`. +- let app: &FalconAppifV1 = unsafe { +- transmute( +- &dma_object, +- hdr_offset + usize::from(hdr.header_size) + i * usize::from(hdr.entry_size), +- ) +- }?; ++ let app: &FalconAppifV1 = unsafe { transmute(&dma_object, entry_offset) }?; + + if app.id != NVFW_FALCON_APPIF_ID_DMEMMAPPER { + continue; + } + let dmem_base = app.dmem_base; + +- // SAFETY: we have exclusive access to `dma_object`. +- let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe { +- transmute_mut( +- &mut dma_object, +- (desc.imem_load_size() + dmem_base).into_safe_cast(), +- ) +- }?; ++ let dmem_mapper_offset = desc ++ .imem_load_size() ++ .checked_add(dmem_base) ++ .map(usize::from_safe_cast) ++ .ok_or(EINVAL)?; ++ ++ let dmem_mapper: &mut FalconAppifDmemmapperV3 = ++ // SAFETY: we have exclusive access to `dma_object`. ++ unsafe { transmute_mut(&mut dma_object, dmem_mapper_offset) }?; + + dmem_mapper.init_cmd = match cmd { + FwsecCommand::Frts { .. } => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS, +@@ -303,13 +308,15 @@ fn new_fwsec(dev: &Device, bios: &Vbios, cmd: FwsecCommand) -> Re + }; + let cmd_in_buffer_offset = dmem_mapper.cmd_in_buffer_offset; + +- // SAFETY: we have exclusive access to `dma_object`. +- let frts_cmd: &mut FrtsCmd = unsafe { +- transmute_mut( +- &mut dma_object, +- (desc.imem_load_size() + cmd_in_buffer_offset).into_safe_cast(), +- ) +- }?; ++ let frts_cmd_offset = desc ++ .imem_load_size() ++ .checked_add(cmd_in_buffer_offset) ++ .map(usize::from_safe_cast) ++ .ok_or(EINVAL)?; ++ ++ let frts_cmd: &mut FrtsCmd = ++ // SAFETY: we have exclusive access to `dma_object`. ++ unsafe { transmute_mut(&mut dma_object, frts_cmd_offset) }?; + + frts_cmd.read_vbios = ReadVbios { + ver: 1, +@@ -355,8 +362,11 @@ pub(crate) fn new( + // Patch signature if needed. + let desc = bios.fwsec_image().header()?; + let ucode_signed = if desc.signature_count() != 0 { +- let sig_base_img = +- usize::from_safe_cast(desc.imem_load_size() + desc.pkc_data_offset()); ++ let sig_base_img = desc ++ .imem_load_size() ++ .checked_add(desc.pkc_data_offset()) ++ .map(usize::from_safe_cast) ++ .ok_or(EINVAL)?; + let desc_sig_versions = u32::from(desc.signature_versions()); + let reg_fuse_version = + falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?; +-- +2.53.0 + diff --git a/queue-7.0/greybus-raw-fix-use-after-free-if-write-is-called-af.patch b/queue-7.0/greybus-raw-fix-use-after-free-if-write-is-called-af.patch new file mode 100644 index 0000000000..2cf0377d6d --- /dev/null +++ b/queue-7.0/greybus-raw-fix-use-after-free-if-write-is-called-af.patch @@ -0,0 +1,114 @@ +From 83d90ceea74babdae22430f82d89542289a22121 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:00:39 -0400 +Subject: greybus: raw: fix use-after-free if write is called after disconnect +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Damien Riégel + +[ Upstream commit 84265cbd96b97058ef67e3f8be3933667a000835 ] + +If a user writes to the chardev after disconnect has been called, the +kernel panics with the following trace (with +CONFIG_INIT_ON_FREE_DEFAULT_ON=y): + + BUG: kernel NULL pointer dereference, address: 0000000000000218 + ... + Call Trace: + + gb_operation_create_common+0x61/0x180 + gb_operation_create_flags+0x28/0xa0 + gb_operation_sync_timeout+0x6f/0x100 + raw_write+0x7b/0xc7 [gb_raw] + vfs_write+0xcf/0x420 + ? task_mm_cid_work+0x136/0x220 + ksys_write+0x63/0xe0 + do_syscall_64+0xa4/0x290 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Disconnect calls gb_connection_destroy, which ends up freeing the +connection object. When gb_operation_sync is called in the write file +operations, its gets a freed connection as parameter and the kernel +panics. + +The gb_connection_destroy cannot be moved out of the disconnect +function, as the Greybus subsystem expect all connections belonging to a +bundle to be destroyed when disconnect returns. + +To prevent this bug, use a rw lock to synchronize access between write +and disconnect. This guarantees that the write function doesn't try +to use a disconnected connection. + +Fixes: e806c7fb8e9b ("greybus: raw: add raw greybus kernel driver") +Reviewed-by: Johan Hovold +Signed-off-by: Damien Riégel +Link: https://patch.msgid.link/20260324140039.40001-2-damien.riegel@silabs.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/raw.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/greybus/raw.c b/drivers/staging/greybus/raw.c +index 47a9845546811..459aed0f12401 100644 +--- a/drivers/staging/greybus/raw.c ++++ b/drivers/staging/greybus/raw.c +@@ -21,6 +21,8 @@ struct gb_raw { + struct list_head list; + int list_data; + struct mutex list_lock; ++ struct rw_semaphore disconnect_lock; ++ bool disconnected; + struct cdev cdev; + struct device dev; + }; +@@ -200,6 +202,7 @@ static int gb_raw_probe(struct gb_bundle *bundle, + + INIT_LIST_HEAD(&raw->list); + mutex_init(&raw->list_lock); ++ init_rwsem(&raw->disconnect_lock); + + raw->connection = connection; + greybus_set_drvdata(bundle, raw); +@@ -235,6 +238,11 @@ static void gb_raw_disconnect(struct gb_bundle *bundle) + struct raw_data *temp; + + cdev_device_del(&raw->cdev, &raw->dev); ++ ++ down_write(&raw->disconnect_lock); ++ raw->disconnected = true; ++ up_write(&raw->disconnect_lock); ++ + gb_connection_disable(connection); + gb_connection_destroy(connection); + +@@ -277,11 +285,22 @@ static ssize_t raw_write(struct file *file, const char __user *buf, + if (count > MAX_PACKET_SIZE) + return -E2BIG; + ++ down_read(&raw->disconnect_lock); ++ ++ if (raw->disconnected) { ++ retval = -ENODEV; ++ goto exit; ++ } ++ + retval = gb_raw_send(raw, count, buf); + if (retval) +- return retval; ++ goto exit; + +- return count; ++ retval = count; ++exit: ++ up_read(&raw->disconnect_lock); ++ ++ return retval; + } + + static ssize_t raw_read(struct file *file, char __user *buf, size_t count, +-- +2.53.0 + diff --git a/queue-7.0/greybus-raw-fix-use-after-free-on-cdev-close.patch b/queue-7.0/greybus-raw-fix-use-after-free-on-cdev-close.patch new file mode 100644 index 0000000000..5e7f091267 --- /dev/null +++ b/queue-7.0/greybus-raw-fix-use-after-free-on-cdev-close.patch @@ -0,0 +1,191 @@ +From 718139fe5d10533d7c2e0496ed2acdee28221d08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 10:00:38 -0400 +Subject: greybus: raw: fix use-after-free on cdev close +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Damien Riégel + +[ Upstream commit 983cc2c7efbce04ecbf6328448d895044dd6ab31 ] + +This addresses a use-after-free bug when a raw bundle is disconnected +but its chardev is still opened by an application. When the application +releases the cdev, it causes the following panic when init on free is +enabled (CONFIG_INIT_ON_FREE_DEFAULT_ON=y): + + refcount_t: underflow; use-after-free. + WARNING: CPU: 0 PID: 139 at lib/refcount.c:28 refcount_warn_saturate+0xd0/0x130 + ... + Call Trace: + + cdev_put+0x18/0x30 + __fput+0x255/0x2a0 + __x64_sys_close+0x3d/0x80 + do_syscall_64+0xa4/0x290 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +The cdev is contained in the "gb_raw" structure, which is freed in the +disconnect operation. When the cdev is released at a later time, +cdev_put gets an address that points to freed memory. + +To fix this use-after-free, convert the struct device from a pointer to +being embedded, that makes the lifetime of the cdev and of this device +the same. Then, use cdev_device_add, which guarantees that the device +won't be released until all references to the cdev have been released. +Finally, delegate the freeing of the structure to the device release +function, instead of freeing immediately in the disconnect callback. + +Fixes: e806c7fb8e9b ("greybus: raw: add raw greybus kernel driver") +Reviewed-by: Johan Hovold +Signed-off-by: Damien Riégel +Link: https://patch.msgid.link/20260324140039.40001-1-damien.riegel@silabs.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/staging/greybus/raw.c | 69 +++++++++++++++++------------------ + 1 file changed, 34 insertions(+), 35 deletions(-) + +diff --git a/drivers/staging/greybus/raw.c b/drivers/staging/greybus/raw.c +index 3027a2c25bcde..47a9845546811 100644 +--- a/drivers/staging/greybus/raw.c ++++ b/drivers/staging/greybus/raw.c +@@ -21,9 +21,8 @@ struct gb_raw { + struct list_head list; + int list_data; + struct mutex list_lock; +- dev_t dev; + struct cdev cdev; +- struct device *device; ++ struct device dev; + }; + + struct raw_data { +@@ -148,6 +147,15 @@ static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data) + return retval; + } + ++static void raw_dev_release(struct device *dev) ++{ ++ struct gb_raw *raw = container_of(dev, struct gb_raw, dev); ++ ++ ida_free(&minors, MINOR(raw->dev.devt)); ++ ++ kfree(raw); ++} ++ + static int gb_raw_probe(struct gb_bundle *bundle, + const struct greybus_bundle_id *id) + { +@@ -164,15 +172,30 @@ static int gb_raw_probe(struct gb_bundle *bundle, + if (cport_desc->protocol_id != GREYBUS_PROTOCOL_RAW) + return -ENODEV; + +- raw = kzalloc_obj(*raw); +- if (!raw) ++ minor = ida_alloc(&minors, GFP_KERNEL); ++ if (minor < 0) ++ return minor; ++ ++ raw = kzalloc_obj(*raw, GFP_KERNEL); ++ if (!raw) { ++ ida_free(&minors, minor); + return -ENOMEM; ++ } ++ ++ device_initialize(&raw->dev); ++ raw->dev.devt = MKDEV(raw_major, minor); ++ raw->dev.class = &raw_class; ++ raw->dev.parent = &bundle->dev; ++ raw->dev.release = raw_dev_release; ++ retval = dev_set_name(&raw->dev, "gb!raw%d", minor); ++ if (retval) ++ goto error_put_device; + + connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), + gb_raw_request_handler); + if (IS_ERR(connection)) { + retval = PTR_ERR(connection); +- goto error_free; ++ goto error_put_device; + } + + INIT_LIST_HEAD(&raw->list); +@@ -181,46 +204,26 @@ static int gb_raw_probe(struct gb_bundle *bundle, + raw->connection = connection; + greybus_set_drvdata(bundle, raw); + +- minor = ida_alloc(&minors, GFP_KERNEL); +- if (minor < 0) { +- retval = minor; +- goto error_connection_destroy; +- } +- +- raw->dev = MKDEV(raw_major, minor); + cdev_init(&raw->cdev, &raw_fops); + + retval = gb_connection_enable(connection); + if (retval) +- goto error_remove_ida; ++ goto error_connection_destroy; + +- retval = cdev_add(&raw->cdev, raw->dev, 1); ++ retval = cdev_device_add(&raw->cdev, &raw->dev); + if (retval) + goto error_connection_disable; + +- raw->device = device_create(&raw_class, &connection->bundle->dev, +- raw->dev, raw, "gb!raw%d", minor); +- if (IS_ERR(raw->device)) { +- retval = PTR_ERR(raw->device); +- goto error_del_cdev; +- } +- + return 0; + +-error_del_cdev: +- cdev_del(&raw->cdev); +- + error_connection_disable: + gb_connection_disable(connection); + +-error_remove_ida: +- ida_free(&minors, minor); +- + error_connection_destroy: + gb_connection_destroy(connection); + +-error_free: +- kfree(raw); ++error_put_device: ++ put_device(&raw->dev); + return retval; + } + +@@ -231,11 +234,8 @@ static void gb_raw_disconnect(struct gb_bundle *bundle) + struct raw_data *raw_data; + struct raw_data *temp; + +- // FIXME - handle removing a connection when the char device node is open. +- device_destroy(&raw_class, raw->dev); +- cdev_del(&raw->cdev); ++ cdev_device_del(&raw->cdev, &raw->dev); + gb_connection_disable(connection); +- ida_free(&minors, MINOR(raw->dev)); + gb_connection_destroy(connection); + + mutex_lock(&raw->list_lock); +@@ -244,8 +244,7 @@ static void gb_raw_disconnect(struct gb_bundle *bundle) + kfree(raw_data); + } + mutex_unlock(&raw->list_lock); +- +- kfree(raw); ++ put_device(&raw->dev); + } + + /* +-- +2.53.0 + diff --git a/queue-7.0/hid-asus-do-not-abort-probe-when-not-necessary.patch b/queue-7.0/hid-asus-do-not-abort-probe-when-not-necessary.patch new file mode 100644 index 0000000000..7c4497a913 --- /dev/null +++ b/queue-7.0/hid-asus-do-not-abort-probe-when-not-necessary.patch @@ -0,0 +1,65 @@ +From b2949e06fdd998bd9447baf30efa37bd31add974 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:09 +0100 +Subject: HID: asus: do not abort probe when not necessary + +From: Denis Benato + +[ Upstream commit 7253091766ded0fd81fe8d8be9b8b835495b06e8 ] + +In order to avoid dereferencing a NULL pointer asus_probe is aborted early +and control of some asus devices is transferred over hid-generic after +erroring out even when such NULL dereference cannot happen: only early +abort when the NULL dereference can happen. + +Also make the code shorter and more adherent to coding standards +removing square brackets enclosing single-line if-else statements. + +Fixes: d3af6ca9a8c3 ("HID: asus: fix UAF via HID_CLAIMED_INPUT validation") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index d29e002c3af17..b2332efabeb57 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1312,22 +1312,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + * were freed during registration due to no usages being mapped, + * leaving drvdata->input pointing to freed memory. + */ +- if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { +- hid_err(hdev, "Asus input not registered\n"); +- ret = -ENOMEM; +- goto err_stop_hw; +- } +- +- if (drvdata->tp) { +- drvdata->input->name = "Asus TouchPad"; +- } else { +- drvdata->input->name = "Asus Keyboard"; +- } ++ if (drvdata->input && (hdev->claimed & HID_CLAIMED_INPUT)) { ++ if (drvdata->tp) ++ drvdata->input->name = "Asus TouchPad"; ++ else ++ drvdata->input->name = "Asus Keyboard"; + +- if (drvdata->tp) { +- ret = asus_start_multitouch(hdev); +- if (ret) +- goto err_stop_hw; ++ if (drvdata->tp) { ++ ret = asus_start_multitouch(hdev); ++ if (ret) ++ goto err_stop_hw; ++ } + } + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch b/queue-7.0/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch new file mode 100644 index 0000000000..43e34ac9a8 --- /dev/null +++ b/queue-7.0/hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch @@ -0,0 +1,37 @@ +From 388650632d8c25f91f89d0fda9c695213a6e6a50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:10:07 +0100 +Subject: HID: asus: make asus_resume adhere to linux kernel coding standards + +From: Denis Benato + +[ Upstream commit 51d33b42b8ae23da92819d28439fdd5636c45186 ] + +Linux kernel coding standars requires functions opening brackets to be in +a newline: move the opening bracket of asus_resume in its own line. + +Fixes: 546edbd26cff ("HID: hid-asus: reset the backlight brightness level on resume") +Signed-off-by: Denis Benato +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-asus.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index bc93b27f9b136..d29e002c3af17 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1163,7 +1163,8 @@ static int asus_start_multitouch(struct hid_device *hdev) + return 0; + } + +-static int __maybe_unused asus_resume(struct hid_device *hdev) { ++static int __maybe_unused asus_resume(struct hid_device *hdev) ++{ + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + int ret = 0; + +-- +2.53.0 + diff --git a/queue-7.0/hid-usbhid-fix-deadlock-in-hid_post_reset.patch b/queue-7.0/hid-usbhid-fix-deadlock-in-hid_post_reset.patch new file mode 100644 index 0000000000..5d5955deb4 --- /dev/null +++ b/queue-7.0/hid-usbhid-fix-deadlock-in-hid_post_reset.patch @@ -0,0 +1,42 @@ +From 18b05d8001a4204a5a71d4c4c2a9f55efaaae299 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 15:24:54 +0100 +Subject: HID: usbhid: fix deadlock in hid_post_reset() + +From: Oliver Neukum + +[ Upstream commit 8df2c1b47ee3cd50fd454f75c7a7e2ae8a6adf72 ] + +You can build a USB device that includes a HID component +and a storage or UAS component. The components can be reset +only together. That means that hid_pre_reset() and hid_post_reset() +are in the block IO error handling. Hence no memory allocation +used in them may do block IO because the IO can deadlock +on the mutex held while resetting a device and calling the +interface drivers. +Use GFP_NOIO for all allocations in them. + +Fixes: dc3c78e434690 ("HID: usbhid: Check HID report descriptor contents after device reset") +Signed-off-by: Oliver Neukum +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index ddd5d77fb5a5e..fd3e1aedc5cbc 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1552,7 +1552,7 @@ static int hid_post_reset(struct usb_interface *intf) + * configuration descriptors passed, we already know that + * the size of the HID report descriptor has not changed. + */ +- rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); ++ rdesc = kmalloc(hid->dev_rsize, GFP_NOIO); + if (!rdesc) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-7.0/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch b/queue-7.0/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch new file mode 100644 index 0000000000..8ed7200f49 --- /dev/null +++ b/queue-7.0/hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch @@ -0,0 +1,46 @@ +From 77fb595f8e2c8ad4610c7e2b14fd8662e1ec598c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:35:37 +0100 +Subject: hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns() + +From: Peter Zijlstra + +[ Upstream commit d19ff16c11db38f3ee179d72751fb9b340174330 ] + +Much like hrtimer_reprogram(), skip programming if the cpu_base is running +the hrtimer interrupt. + +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Juri Lelli +Reviewed-by: Thomas Gleixner +Link: https://patch.msgid.link/20260224163429.069535561@kernel.org +Stable-dep-of: f2e388a019e4 ("hrtimer: Reduce trace noise in hrtimer_start()") +Signed-off-by: Sasha Levin +--- + kernel/time/hrtimer.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 1e37142fe52f4..1bbb0a9ff3a23 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -1269,6 +1269,14 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + } + + first = enqueue_hrtimer(timer, new_base, mode); ++ ++ /* ++ * If the hrtimer interrupt is running, then it will reevaluate the ++ * clock bases and reprogram the clock event device. ++ */ ++ if (new_base->cpu_base->in_hrtirq) ++ return false; ++ + if (!force_local) { + /* + * If the current CPU base is online, then the timer is +-- +2.53.0 + diff --git a/queue-7.0/hrtimer-reduce-trace-noise-in-hrtimer_start.patch b/queue-7.0/hrtimer-reduce-trace-noise-in-hrtimer_start.patch new file mode 100644 index 0000000000..3c2afa0438 --- /dev/null +++ b/queue-7.0/hrtimer-reduce-trace-noise-in-hrtimer_start.patch @@ -0,0 +1,216 @@ +From 5d8ecaac9d4f597fcace3642e300b3bdaf0ac113 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 17:36:59 +0100 +Subject: hrtimer: Reduce trace noise in hrtimer_start() + +From: Thomas Gleixner + +[ Upstream commit f2e388a019e4cf83a15883a3d1f1384298e9a6aa ] + +hrtimer_start() when invoked with an already armed timer traces like: + + -.. [032] d.h2. 5.002263: hrtimer_cancel: hrtimer= .... + -.. [032] d.h1. 5.002263: hrtimer_start: hrtimer= .... + +Which is incorrect as the timer doesn't get canceled. Just the expiry time +changes. The internal dequeue operation which is required for that is not +really interesting for trace analysis. But it makes it tedious to keep real +cancellations and the above case apart. + +Remove the cancel tracing in hrtimer_start() and add a 'was_armed' +indicator to the hrtimer start tracepoint, which clearly indicates what the +state of the hrtimer is when hrtimer_start() is invoked: + +-.. [032] d.h1. 6.200103: hrtimer_start: hrtimer= .... was_armed=0 + -.. [032] d.h1. 6.200558: hrtimer_start: hrtimer= .... was_armed=1 + +Fixes: c6a2a1770245 ("hrtimer: Add tracepoint for hrtimers") +Signed-off-by: Thomas Gleixner +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260224163430.208491877@kernel.org +Signed-off-by: Sasha Levin +--- + include/trace/events/timer.h | 11 +++++---- + kernel/time/hrtimer.c | 43 +++++++++++++++++------------------- + 2 files changed, 27 insertions(+), 27 deletions(-) + +diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h +index 1641ae3e6ca06..ab9a9386f7b65 100644 +--- a/include/trace/events/timer.h ++++ b/include/trace/events/timer.h +@@ -218,12 +218,13 @@ TRACE_EVENT(hrtimer_setup, + * hrtimer_start - called when the hrtimer is started + * @hrtimer: pointer to struct hrtimer + * @mode: the hrtimers mode ++ * @was_armed: Was armed when hrtimer_start*() was invoked + */ + TRACE_EVENT(hrtimer_start, + +- TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode), ++ TP_PROTO(struct hrtimer *hrtimer, enum hrtimer_mode mode, bool was_armed), + +- TP_ARGS(hrtimer, mode), ++ TP_ARGS(hrtimer, mode, was_armed), + + TP_STRUCT__entry( + __field( void *, hrtimer ) +@@ -231,6 +232,7 @@ TRACE_EVENT(hrtimer_start, + __field( s64, expires ) + __field( s64, softexpires ) + __field( enum hrtimer_mode, mode ) ++ __field( bool, was_armed ) + ), + + TP_fast_assign( +@@ -239,13 +241,14 @@ TRACE_EVENT(hrtimer_start, + __entry->expires = hrtimer_get_expires(hrtimer); + __entry->softexpires = hrtimer_get_softexpires(hrtimer); + __entry->mode = mode; ++ __entry->was_armed = was_armed; + ), + + TP_printk("hrtimer=%p function=%ps expires=%llu softexpires=%llu " +- "mode=%s", __entry->hrtimer, __entry->function, ++ "mode=%s was_armed=%d", __entry->hrtimer, __entry->function, + (unsigned long long) __entry->expires, + (unsigned long long) __entry->softexpires, +- decode_hrtimer_mode(__entry->mode)) ++ decode_hrtimer_mode(__entry->mode), __entry->was_armed) + ); + + /** +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 1bbb0a9ff3a23..c450b41d4bb59 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -479,17 +479,10 @@ static inline void debug_setup_on_stack(struct hrtimer *timer, clockid_t clockid + trace_hrtimer_setup(timer, clockid, mode); + } + +-static inline void debug_activate(struct hrtimer *timer, +- enum hrtimer_mode mode) ++static inline void debug_activate(struct hrtimer *timer, enum hrtimer_mode mode, bool was_armed) + { + debug_hrtimer_activate(timer, mode); +- trace_hrtimer_start(timer, mode); +-} +- +-static inline void debug_deactivate(struct hrtimer *timer) +-{ +- debug_hrtimer_deactivate(timer); +- trace_hrtimer_cancel(timer); ++ trace_hrtimer_start(timer, mode, was_armed); + } + + static struct hrtimer_clock_base * +@@ -1084,9 +1077,9 @@ EXPORT_SYMBOL_GPL(hrtimer_forward); + * Returns true when the new timer is the leftmost timer in the tree. + */ + static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, +- enum hrtimer_mode mode) ++ enum hrtimer_mode mode, bool was_armed) + { +- debug_activate(timer, mode); ++ debug_activate(timer, mode, was_armed); + WARN_ON_ONCE(!base->cpu_base->online); + + base->cpu_base->active_bases |= 1 << base->index; +@@ -1146,6 +1139,8 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + if (state & HRTIMER_STATE_ENQUEUED) { + bool reprogram; + ++ debug_hrtimer_deactivate(timer); ++ + /* + * Remove the timer and force reprogramming when high + * resolution mode is active and the timer is on the current +@@ -1154,7 +1149,6 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, + * reprogramming happens in the interrupt handler. This is a + * rare case and less expensive than a smp call. + */ +- debug_deactivate(timer); + reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); + + /* +@@ -1221,15 +1215,15 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + { + struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases); + struct hrtimer_clock_base *new_base; +- bool force_local, first; ++ bool force_local, first, was_armed; + + /* + * If the timer is on the local cpu base and is the first expiring + * timer then this might end up reprogramming the hardware twice +- * (on removal and on enqueue). To avoid that by prevent the +- * reprogram on removal, keep the timer local to the current CPU +- * and enforce reprogramming after it is queued no matter whether +- * it is the new first expiring timer again or not. ++ * (on removal and on enqueue). To avoid that prevent the reprogram ++ * on removal, keep the timer local to the current CPU and enforce ++ * reprogramming after it is queued no matter whether it is the new ++ * first expiring timer again or not. + */ + force_local = base->cpu_base == this_cpu_base; + force_local &= base->cpu_base->next_timer == timer; +@@ -1251,7 +1245,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + * avoids programming the underlying clock event twice (once at + * removal and once after enqueue). + */ +- remove_hrtimer(timer, base, true, force_local); ++ was_armed = remove_hrtimer(timer, base, true, force_local); + + if (mode & HRTIMER_MODE_REL) + tim = ktime_add_safe(tim, __hrtimer_cb_get_time(base->clockid)); +@@ -1268,7 +1262,7 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + new_base = base; + } + +- first = enqueue_hrtimer(timer, new_base, mode); ++ first = enqueue_hrtimer(timer, new_base, mode, was_armed); + + /* + * If the hrtimer interrupt is running, then it will reevaluate the +@@ -1370,8 +1364,11 @@ int hrtimer_try_to_cancel(struct hrtimer *timer) + + base = lock_hrtimer_base(timer, &flags); + +- if (!hrtimer_callback_running(timer)) ++ if (!hrtimer_callback_running(timer)) { + ret = remove_hrtimer(timer, base, false, false); ++ if (ret) ++ trace_hrtimer_cancel(timer); ++ } + + unlock_hrtimer_base(timer, &flags); + +@@ -1807,7 +1804,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, + */ + if (restart != HRTIMER_NORESTART && + !(timer->state & HRTIMER_STATE_ENQUEUED)) +- enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, false); + + /* + * Separate the ->running assignment from the ->state assignment. +@@ -2287,7 +2284,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + while ((node = timerqueue_getnext(&old_base->active))) { + timer = container_of(node, struct hrtimer, node); + BUG_ON(hrtimer_callback_running(timer)); +- debug_deactivate(timer); ++ debug_hrtimer_deactivate(timer); + + /* + * Mark it as ENQUEUED not INACTIVE otherwise the +@@ -2304,7 +2301,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, + * sort out already expired timers and reprogram the + * event device. + */ +- enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); ++ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, true); + } + } + +-- +2.53.0 + diff --git a/queue-7.0/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch b/queue-7.0/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch new file mode 100644 index 0000000000..74e586d1f0 --- /dev/null +++ b/queue-7.0/hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch @@ -0,0 +1,47 @@ +From 057c8b08ac59a100c5d82d266d3525f2992ec49e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 11:46:18 +0100 +Subject: hte: tegra194: remove Kconfig dependency on Tegra194 SoC + +From: Francesco Lavra + +[ Upstream commit 92dfd92f747698352b256cd9ddd7497bb7ebe9c8 ] + +This driver runs also on other Tegra SoCs (e.g. Tegra234). +Replace Kconfig dependency on Tegra194 with more generic dependency on +Tegra, and amend the Kconfig help text to reflect the fact that this +driver works on SoCs other than Tegra194. + +Fixes: b003fb5c9df8 ("hte: Add Tegra234 provider") +Signed-off-by: Francesco Lavra +Acked-by: Dipen Patel +Signed-off-by: Dipen Patel +Signed-off-by: Sasha Levin +--- + drivers/hte/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/hte/Kconfig b/drivers/hte/Kconfig +index 641af722b555d..f57bad67deef0 100644 +--- a/drivers/hte/Kconfig ++++ b/drivers/hte/Kconfig +@@ -16,13 +16,13 @@ if HTE + + config HTE_TEGRA194 + tristate "NVIDIA Tegra194 HTE Support" +- depends on (ARCH_TEGRA_194_SOC || COMPILE_TEST) ++ depends on (ARCH_TEGRA || COMPILE_TEST) + depends on GPIOLIB + help + Enable this option for integrated hardware timestamping engine also + known as generic timestamping engine (GTE) support on NVIDIA Tegra194 +- systems-on-chip. The driver supports 352 LIC IRQs and 39 AON GPIOs +- lines for timestamping in realtime. ++ and later systems-on-chip. The driver supports 352 LIC IRQs and 39 ++ AON GPIOs lines for timestamping in realtime. + + config HTE_TEGRA194_TEST + tristate "NVIDIA Tegra194 HTE Test" +-- +2.53.0 + diff --git a/queue-7.0/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch b/queue-7.0/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch new file mode 100644 index 0000000000..1e392fe656 --- /dev/null +++ b/queue-7.0/hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch @@ -0,0 +1,51 @@ +From 3683336ca03f5b06f4323247c1dbb3856fe6a5a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 10:33:24 +0800 +Subject: hwmon: (aspeed-g6-pwm-tach): remove redundant driver remove callback + +From: Billy Tsai + +[ Upstream commit 46fef8583daa1bf78fda7eaa523c64d4440322ac ] + +Drops the remove callback as it only asserts reset and the probe already +registers a devres action (devm_add_action_or_reset()) to call +aspeed_pwm_tach_reset_assert(). + +Fixes: 7e1449cd15d1 ("hwmon: (aspeed-g6-pwm-tacho): Support for ASPEED g6 PWM/Fan tach") +Signed-off-by: Billy Tsai +Link: https://lore.kernel.org/r/20260309-pwm_fixes-v2-1-ca9768e70470@aspeedtech.com +Signed-off-by: Guenter Roeck +Signed-off-by: Sasha Levin +--- + drivers/hwmon/aspeed-g6-pwm-tach.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c +index 44e1ecba205d7..4f6e6d440dd40 100644 +--- a/drivers/hwmon/aspeed-g6-pwm-tach.c ++++ b/drivers/hwmon/aspeed-g6-pwm-tach.c +@@ -517,13 +517,6 @@ static int aspeed_pwm_tach_probe(struct platform_device *pdev) + return 0; + } + +-static void aspeed_pwm_tach_remove(struct platform_device *pdev) +-{ +- struct aspeed_pwm_tach_data *priv = platform_get_drvdata(pdev); +- +- reset_control_assert(priv->reset); +-} +- + static const struct of_device_id aspeed_pwm_tach_match[] = { + { + .compatible = "aspeed,ast2600-pwm-tach", +@@ -537,7 +530,6 @@ MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); + + static struct platform_driver aspeed_pwm_tach_driver = { + .probe = aspeed_pwm_tach_probe, +- .remove = aspeed_pwm_tach_remove, + .driver = { + .name = "aspeed-g6-pwm-tach", + .of_match_table = aspeed_pwm_tach_match, +-- +2.53.0 + diff --git a/queue-7.0/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch b/queue-7.0/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch new file mode 100644 index 0000000000..4d7f760ec0 --- /dev/null +++ b/queue-7.0/i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch @@ -0,0 +1,68 @@ +From b26853d5617a771d7bfefff3b6bb79b8860928a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 18:32:30 +0800 +Subject: i3c: dw: Fix memory leak in dw_i3c_master_i3c_xfers() + +From: Felix Gu + +[ Upstream commit 256cc1f1305a8e5dcadf8ca208d04a3acadd26f1 ] + +The dw_i3c_master_i3c_xfers() function allocates memory for the xfer +structure using dw_i3c_master_alloc_xfer(). If pm_runtime_resume_and_get() +fails, the function returns without freeing the allocated xfer, resulting +in a memory leak. + +Since dw_i3c_master_free_xfer() is a thin wrapper around kfree(), use +the __free(kfree) cleanup attribute to handle the free automatically on +all exit paths. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260404-dw-i3c-2-v3-1-8f7d146549c1@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index b87073d2f8afa..259e4f5276655 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -7,6 +7,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -924,7 +925,6 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct dw_i3c_master *master = to_dw_i3c_master(m); + unsigned int nrxwords = 0, ntxwords = 0; +- struct dw_i3c_xfer *xfer; + int i, ret = 0; + + if (!i3c_nxfers) +@@ -944,7 +944,7 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + nrxwords > master->caps.datafifodepth) + return -EOPNOTSUPP; + +- xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers); ++ struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, i3c_nxfers); + if (!xfer) + return -ENOMEM; + +@@ -995,7 +995,6 @@ static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, + } + + ret = xfer->ret; +- dw_i3c_master_free_xfer(xfer); + + pm_runtime_put_autosuspend(master->dev); + return ret; +-- +2.53.0 + diff --git a/queue-7.0/i3c-master-adi-fix-error-propagation-for-cccs.patch b/queue-7.0/i3c-master-adi-fix-error-propagation-for-cccs.patch new file mode 100644 index 0000000000..e6f7b0b8ec --- /dev/null +++ b/queue-7.0/i3c-master-adi-fix-error-propagation-for-cccs.patch @@ -0,0 +1,44 @@ +From 67881c371332a0b2635e8d8ce10969bf9159b30c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:33 +0100 +Subject: i3c: master: adi: Fix error propagation for CCCs + +From: Jorge Marques + +[ Upstream commit 0b73da96b6eb6b9354654f96a9d423ab22cb222d ] + +adi_i3c_master_send_ccc_cmd() always returned 0, ignoring the transfer +result populated in the completion path. As a consequence, CCC command +errors were silently dropped, including the default -ETIMEDOUT and +later overwritten by adi_i3c_master_end_xfer_locked(). + +Fix this by returning xfer->ret so that callers correctly receive any +transfer error codes. + +Fixes: a79ac2cdc91d ("i3c: master: Add driver for Analog Devices I3C Controller IP") +Reviewed-by: Adrian Hunter +Reviewed-by: Frank Li +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-5-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/adi-i3c-master.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/i3c/master/adi-i3c-master.c b/drivers/i3c/master/adi-i3c-master.c +index 6616f751075ae..545ddd79a45db 100644 +--- a/drivers/i3c/master/adi-i3c-master.c ++++ b/drivers/i3c/master/adi-i3c-master.c +@@ -361,7 +361,7 @@ static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, + + cmd->err = adi_i3c_cmd_get_err(&xfer->cmds[0]); + +- return 0; ++ return xfer->ret; + } + + static int adi_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, +-- +2.53.0 + diff --git a/queue-7.0/i3c-master-dw-i3c-balance-pm-runtime-usage-count-on-.patch b/queue-7.0/i3c-master-dw-i3c-balance-pm-runtime-usage-count-on-.patch new file mode 100644 index 0000000000..e119229a96 --- /dev/null +++ b/queue-7.0/i3c-master-dw-i3c-balance-pm-runtime-usage-count-on-.patch @@ -0,0 +1,43 @@ +From 5b9ee49339cd26ae28645e60cbb452d22b9c89e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 17:04:43 +0800 +Subject: i3c: master: dw-i3c: Balance PM runtime usage count on probe failure + +From: Felix Gu + +[ Upstream commit 19d6dd322c3f05550606dbfcbafb5f6989975c02 ] + +When DW_I3C_DISABLE_RUNTIME_PM_QUIRK is set, the probe function calls +pm_runtime_get_noresume() to prevent runtime suspend. However, if +i3c_master_register() fails, the error path does not balance this +call, leaving the usage count incremented. + +Add pm_runtime_put_noidle() in the error cleanup path to properly +balance the usage count. + +Fixes: fba0e56ee752 ("i3c: dw: Disable runtime PM on Agilex5 to avoid bus hang on IBI") +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260321-dw-i3c-1-v1-1-821623aac7bb@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index 3379cb16eeca5..b87073d2f8afa 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1667,6 +1667,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + return 0; + + err_disable_pm: ++ if (master->quirks & DW_I3C_DISABLE_RUNTIME_PM_QUIRK) ++ pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); +-- +2.53.0 + diff --git a/queue-7.0/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch b/queue-7.0/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch new file mode 100644 index 0000000000..854c88a5d8 --- /dev/null +++ b/queue-7.0/i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch @@ -0,0 +1,69 @@ +From 81052391e3fb57c31b693236080422a239074c2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 22:18:02 +0800 +Subject: i3c: master: dw-i3c: Fix missing reset assertion in remove() callback + +From: Felix Gu + +[ Upstream commit bef1eef667186cedb0bc6d152464acb3c97d5f72 ] + +The reset line acquired during probe is currently left deasserted when +the driver is unbound. + +Switch to devm_reset_control_get_optional_exclusive_deasserted() to +ensure the reset is automatically re-asserted by the devres core when +the driver is removed. + +Fixes: 62fe9d06f570 ("i3c: dw: Add power management support") +Reviewed-by: Philipp Zabel +Signed-off-by: Felix Gu +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260320-dw-i3c-v3-1-477040c2e3f5@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/dw-i3c-master.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index d6bdb32397fb9..3379cb16eeca5 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1606,13 +1606,11 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + if (IS_ERR(master->pclk)) + return PTR_ERR(master->pclk); + +- master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev, +- "core_rst"); ++ master->core_rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, ++ "core_rst"); + if (IS_ERR(master->core_rst)) + return PTR_ERR(master->core_rst); + +- reset_control_deassert(master->core_rst); +- + spin_lock_init(&master->xferqueue.lock); + INIT_LIST_HEAD(&master->xferqueue.list); + +@@ -1624,7 +1622,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + dw_i3c_master_irq_handler, 0, + dev_name(&pdev->dev), master); + if (ret) +- goto err_assert_rst; ++ return ret; + + platform_set_drvdata(pdev, master); + +@@ -1673,9 +1671,6 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + +-err_assert_rst: +- reset_control_assert(master->core_rst); +- + return ret; + } + EXPORT_SYMBOL_GPL(dw_i3c_common_probe); +-- +2.53.0 + diff --git a/queue-7.0/i3c-master-fix-error-codes-at-send_ccc_cmd.patch b/queue-7.0/i3c-master-fix-error-codes-at-send_ccc_cmd.patch new file mode 100644 index 0000000000..a45df6c793 --- /dev/null +++ b/queue-7.0/i3c-master-fix-error-codes-at-send_ccc_cmd.patch @@ -0,0 +1,126 @@ +From 256b9e4c002b59213567a31da5ef21e4bee3351a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:11:32 +0100 +Subject: i3c: master: Fix error codes at send_ccc_cmd + +From: Jorge Marques + +[ Upstream commit ef8b5229348f0719aca557c4ca5530630ae4d134 ] + +i3c_master_send_ccc_cmd_locked() would propagate cmd->err (positive, +Mx codes) to the ret variable, cascading down multiple methods until +reaching methods that explicitly stated they would return 0 on success +or negative error code. For example, the call chain: + + i3c_device_enable_ibi <- i3c_dev_enable_ibi_locked <- + master->ops.enable_ibi <- i3c_master_enec_locked <- + i3c_master_enec_disec_locked <- i3c_master_send_ccc_cmd_locked + +Fix this by returning the ret value, callers can still read the cmd->err +value if ret is negative. + +All corner cases where the Mx codes do need to be handled individually, +are resolved in previous commits. Those corner cases are all scenarios +when I3C_ERROR_M2 is expected and acceptable. +The prerequisite patches for the fix are: + + i3c: master: Move rstdaa error suppression + i3c: master: Move entdaa error suppression + i3c: master: Move bus_init error suppression + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/linux-iio/aYXvT5FW0hXQwhm_@stanley.mountain/ +Fixes: 3a379bbcea0a ("i3c: Add core I3C infrastructure") +Reviewed-by: Adrian Hunter +Signed-off-by: Jorge Marques +Link: https://patch.msgid.link/20260323-ad4062-positive-error-fix-v3-4-30bdc68004be@analog.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 32 +++++++++++++------------------- + 1 file changed, 13 insertions(+), 19 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 9e6be49bebb2c..930c4dad632fc 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -898,11 +898,17 @@ static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id, + cmd->err = I3C_ERROR_UNKNOWN; + } + ++/** ++ * i3c_master_send_ccc_cmd_locked() - send a CCC (Common Command Codes) ++ * @master: master used to send frames on the bus ++ * @cmd: command to send ++ * ++ * Return: 0 in case of success, or a negative error code otherwise. ++ * I3C Mx error codes are stored in cmd->err. ++ */ + static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + struct i3c_ccc_cmd *cmd) + { +- int ret; +- + if (!cmd || !master) + return -EINVAL; + +@@ -920,15 +926,7 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, + !master->ops->supports_ccc_cmd(master, cmd)) + return -EOPNOTSUPP; + +- ret = master->ops->send_ccc_cmd(master, cmd); +- if (ret) { +- if (cmd->err != I3C_ERROR_UNKNOWN) +- return cmd->err; +- +- return ret; +- } +- +- return 0; ++ return master->ops->send_ccc_cmd(master, cmd); + } + + static struct i2c_dev_desc * +@@ -1032,8 +1030,7 @@ static int i3c_master_rstdaa_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_entdaa_locked(struct i3c_master_controller *master) + { +@@ -1085,8 +1082,7 @@ static int i3c_master_enec_disec_locked(struct i3c_master_controller *master, + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1106,8 +1102,7 @@ EXPORT_SYMBOL_GPL(i3c_master_disec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, + u8 evts) +@@ -1132,8 +1127,7 @@ EXPORT_SYMBOL_GPL(i3c_master_enec_locked); + * + * This function must be called with the bus lock held in write mode. + * +- * Return: 0 in case of success, a positive I3C error code if the error is +- * one of the official Mx error codes, and a negative error code otherwise. ++ * Return: 0 in case of success, or a negative error code otherwise. + */ + int i3c_master_defslvs_locked(struct i3c_master_controller *master) + { +-- +2.53.0 + diff --git a/queue-7.0/i3c-master-renesas-fix-memory-leak-in-renesas_i3c_i3.patch b/queue-7.0/i3c-master-renesas-fix-memory-leak-in-renesas_i3c_i3.patch new file mode 100644 index 0000000000..8e78b0ce71 --- /dev/null +++ b/queue-7.0/i3c-master-renesas-fix-memory-leak-in-renesas_i3c_i3.patch @@ -0,0 +1,56 @@ +From 5065af781daa771119bcb5cd2090f4d8bb8b286e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 20:43:16 +0800 +Subject: i3c: master: renesas: Fix memory leak in renesas_i3c_i3c_xfers() + +From: Felix Gu + +[ Upstream commit d7665c3b4f575251e449e2656879392346ca612b ] + +The xfer structure allocated by renesas_i3c_alloc_xfer() was never freed +in the renesas_i3c_i3c_xfers() function. Use the __free(kfree) cleanup +attribute to automatically free the memory when the variable goes out of +scope. + +Fixes: d028219a9f14 ("i3c: master: Add basic driver for the Renesas I3C controller") +Tested-by: Tommaso Merciai +Reviewed-by: Tommaso Merciai +Reviewed-by: Frank Li +Signed-off-by: Felix Gu +Link: https://patch.msgid.link/20260406-renesas-v3-1-4b724d7708f4@gmail.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/renesas-i3c.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c +index d9f5b30a4b2f3..a8a9e89a9710a 100644 +--- a/drivers/i3c/master/renesas-i3c.c ++++ b/drivers/i3c/master/renesas-i3c.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -817,13 +818,12 @@ static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_ + struct i3c_master_controller *m = i3c_dev_get_master(dev); + struct renesas_i3c *i3c = to_renesas_i3c(m); + struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); +- struct renesas_i3c_xfer *xfer; + int i; + + /* Enable I3C bus. */ + renesas_i3c_bus_enable(m, true); + +- xfer = renesas_i3c_alloc_xfer(i3c, 1); ++ struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1); + if (!xfer) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-7.0/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch b/queue-7.0/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch new file mode 100644 index 0000000000..a8aed8c1ef --- /dev/null +++ b/queue-7.0/i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch @@ -0,0 +1,56 @@ +From 658880de810b249d03560a59a186892454a3a95f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 16:53:23 +0800 +Subject: i3c: mipi-i3c-hci: fix IBI payload length calculation for final + status + +From: Billy Tsai + +[ Upstream commit d35a6db887eeae7c57b719521e39d64f929c6dc3 ] + +In DMA mode, the IBI status descriptor encodes the payload using +CHUNKS (number of chunks) and DATA_LENGTH (valid bytes in the last +chunk). All preceding chunks are implicitly full-sized. + +The current code accumulates full chunk sizes for non-final status +descriptors, but for the final status descriptor it only adds +DATA_LENGTH. This ignores the contribution of the preceding full +chunks described by the same final status entry. + +As a result, the computed IBI payload length is truncated whenever +the final status spans multiple chunks. For example, with a chunk +size of 4 bytes, CHUNKS=2 and DATA_LENGTH=1 should result in a total +payload size of 5 bytes, but the current code reports only 1 byte. + +Fix the calculation by adding the size of (CHUNKS - 1) full chunks +plus DATA_LENGTH for the last chunk. + +Fixes: 9ad9a52cce28 ("i3c/master: introduce the mipi-i3c-hci driver") +Signed-off-by: Billy Tsai +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260407-i3c-hci-dma-v2-1-a583187b9d22@aspeedtech.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/mipi-i3c-hci/dma.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c +index e487ef52f6b4e..e4daaa6120550 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/dma.c ++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c +@@ -754,7 +754,10 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh) + if (!(ibi_status & IBI_LAST_STATUS)) { + ibi_size += chunks * rh->ibi_chunk_sz; + } else { +- ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ if (chunks) { ++ ibi_size += (chunks - 1) * rh->ibi_chunk_sz; ++ ibi_size += FIELD_GET(IBI_DATA_LENGTH, ibi_status); ++ } + last_ptr = ptr; + break; + } +-- +2.53.0 + diff --git a/queue-7.0/i40e-don-t-advertise-iff_supp_nofcs.patch b/queue-7.0/i40e-don-t-advertise-iff_supp_nofcs.patch new file mode 100644 index 0000000000..478e1820e7 --- /dev/null +++ b/queue-7.0/i40e-don-t-advertise-iff_supp_nofcs.patch @@ -0,0 +1,53 @@ +From 0a8cdc1b083fe199b109242f82ab36238d23634e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:33 -0700 +Subject: i40e: don't advertise IFF_SUPP_NOFCS + +From: Kohei Enju + +[ Upstream commit a24162f18825684ad04e3a5d0531f8a50d679347 ] + +i40e advertises IFF_SUPP_NOFCS, allowing users to use the SO_NOFCS +socket option. However, this option is silently ignored, as the driver +does not check skb->no_fcs, and always enables FCS insertion offload. + +Fix this by removing the advertisement of IFF_SUPP_NOFCS. + +This behavior can be reproduced with a simple AF_PACKET socket: + + import socket + s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) + s.setsockopt(socket.SOL_SOCKET, 43, 1) # SO_NOFCS + s.bind(("eth0", 0)) + s.send(b'\xff' * 64) + +Previously, send() succeeds but the driver ignores SO_NOFCS. +With this change, send() fails with -EPROTONOSUPPORT, as expected. + +Fixes: 41c445ff0f48 ("i40e: main driver core") +Signed-off-by: Kohei Enju +Reviewed-by: Aleksandr Loktionov +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-9-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index 926d001b21502..028bd500603a5 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -13783,7 +13783,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) + netdev->neigh_priv_len = sizeof(u32) * 4; + + netdev->priv_flags |= IFF_UNICAST_FLT; +- netdev->priv_flags |= IFF_SUPP_NOFCS; + /* Setup netdev TC information */ + i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); + +-- +2.53.0 + diff --git a/queue-7.0/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch b/queue-7.0/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch new file mode 100644 index 0000000000..09d21cb278 --- /dev/null +++ b/queue-7.0/iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch @@ -0,0 +1,58 @@ +From 30dbabe45281406c842eda35013c039741aa8e9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:16 -0700 +Subject: iavf: add VIRTCHNL_OP_ADD_VLAN to success completion handler + +From: Petr Oros + +[ Upstream commit 34d33313b52eeac3a97ad2e3176d523ec70d9283 ] + +The V1 ADD_VLAN opcode had no success handler; filters sent via V1 +stayed in ADDING state permanently. Add a fallthrough case so V1 +filters also transition ADDING -> ACTIVE on PF confirmation. + +Critically, add an `if (v_retval) break` guard: the error switch in +iavf_virtchnl_completion() does NOT return after handling errors, +it falls through to the success switch. Without this guard, a +PF-rejected ADD would incorrectly mark ADDING filters as ACTIVE, +creating a driver/HW mismatch where the driver believes the filter +is installed but the PF never accepted it. + +For V2, this is harmless: iavf_vlan_add_reject() in the error +block already kfree'd all ADDING filters, so the success handler +finds nothing to transition. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-4-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 93ca79c3e3b53..4f2defd2331b1 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -2876,9 +2876,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->adv_rss_lock); + } + break; ++ case VIRTCHNL_OP_ADD_VLAN: + case VIRTCHNL_OP_ADD_VLAN_V2: { + struct iavf_vlan_filter *f; + ++ if (v_retval) ++ break; ++ + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_ADDING) +-- +2.53.0 + diff --git a/queue-7.0/iavf-fix-wrong-vlan-mask-for-legacy-rx-descriptors-l.patch b/queue-7.0/iavf-fix-wrong-vlan-mask-for-legacy-rx-descriptors-l.patch new file mode 100644 index 0000000000..969fe1e030 --- /dev/null +++ b/queue-7.0/iavf-fix-wrong-vlan-mask-for-legacy-rx-descriptors-l.patch @@ -0,0 +1,86 @@ +From a077f8f11e63f8cabb62c20b74573d92e6e6c6fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:34 -0700 +Subject: iavf: fix wrong VLAN mask for legacy Rx descriptors L2TAG2 + +From: Petr Oros + +[ Upstream commit 496d9f91062fa07956702e0f234c5203f03a974d ] + +The IAVF_RXD_LEGACY_L2TAG2_M mask was incorrectly defined as +GENMASK_ULL(63, 32), extracting 32 bits from qw2 instead of the +16-bit VLAN tag. In the legacy Rx descriptor layout, the 2nd L2TAG2 +(VLAN tag) occupies bits 63:48 of qw2, not 63:32. + +The oversized mask causes FIELD_GET to return a 32-bit value where the +actual VLAN tag sits in bits 31:16. When this value is passed to +iavf_receive_skb() as a u16 parameter, it gets truncated to the lower +16 bits (which contain the 1st L2TAG2, typically zero). As a result, +__vlan_hwaccel_put_tag() is never called and software VLAN interfaces +on VFs receive no traffic. + +This affects VFs behind ice PF (VIRTCHNL VLAN v2) when the PF +advertises VLAN stripping into L2TAG2_2 and legacy descriptors are +used. + +The flex descriptor path already uses the correct mask +(IAVF_RXD_FLEX_L2TAG2_2_M = GENMASK_ULL(63, 48)). + +Reproducer: + 1. Create 2 VFs on ice PF (echo 2 > sriov_numvfs) + 2. Disable spoofchk on both VFs + 3. Move each VF into a separate network namespace + 4. On each VF: create VLAN interface (e.g. vlan 198), assign IP, + bring up + 5. Set rx-vlan-offload OFF on both VFs + 6. Ping between VLAN interfaces -> expect PASS + (VLAN tag stays in packet data, kernel matches in-band) + 7. Set rx-vlan-offload ON on both VFs + 8. Ping between VLAN interfaces -> expect FAIL if bug present + (HW strips VLAN tag into descriptor L2TAG2 field, wrong mask + extracts bits 47:32 instead of 63:48, truncated to u16 -> zero, + __vlan_hwaccel_put_tag() never called, packet delivered to parent + interface, not VLAN interface) + +The reproducer requires legacy Rx descriptors. On modern ice + iavf +with full PTP support, flex descriptors are always negotiated and the +buggy legacy path is never reached. Flex descriptors require all of: + - CONFIG_PTP_1588_CLOCK enabled + - VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC granted by PF + - PTP capabilities negotiated (VIRTCHNL_VF_CAP_PTP) + - VIRTCHNL_1588_PTP_CAP_RX_TSTAMP supported + - VIRTCHNL_RXDID_2_FLEX_SQ_NIC present in DDP profile + +If any condition is not met, iavf_select_rx_desc_format() falls back +to legacy descriptors (RXDID=1) and the wrong L2TAG2 mask is hit. + +Fixes: 2dc8e7c36d80 ("iavf: refactor iavf_clean_rx_irq to support legacy and flex descriptors") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Paul Menzel +Reviewed-by: Jacob Keller +Tested-by: Rafal Romanowski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-10-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf_type.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf_type.h b/drivers/net/ethernet/intel/iavf/iavf_type.h +index 1d8cf29cb65ac..5bb1de1cfd33b 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_type.h ++++ b/drivers/net/ethernet/intel/iavf/iavf_type.h +@@ -277,7 +277,7 @@ struct iavf_rx_desc { + /* L2 Tag 2 Presence */ + #define IAVF_RXD_LEGACY_L2TAG2P_M BIT(0) + /* Stripped S-TAG VLAN from the receive packet */ +-#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 32) ++#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 48) + /* Stripped S-TAG VLAN from the receive packet */ + #define IAVF_RXD_FLEX_L2TAG2_2_M GENMASK_ULL(63, 48) + /* The packet is a UDP tunneled packet */ +-- +2.53.0 + diff --git a/queue-7.0/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch b/queue-7.0/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch new file mode 100644 index 0000000000..9a33d0cb77 --- /dev/null +++ b/queue-7.0/iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch @@ -0,0 +1,87 @@ +From c0d02943c75ba9b8e0db1a254ded80335dc90f58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:13 -0700 +Subject: iavf: rename IAVF_VLAN_IS_NEW to IAVF_VLAN_ADDING + +From: Petr Oros + +[ Upstream commit 70d62b669f1f9080a25278fc90b64309f4ae8959 ] + +Rename the IAVF_VLAN_IS_NEW state to IAVF_VLAN_ADDING to better +describe what the state represents: an ADD request has been sent to +the PF and is waiting for a response. + +This is a pure rename with no behavioral change, preparing for a +cleanup of the VLAN filter state machine. + +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-1-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Stable-dep-of: f2ce65b9b917 ("iavf: stop removing VLAN filters from PF on interface down") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 2 +- + drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index e9fb0a0919e37..47a862ca5e2c3 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -158,7 +158,7 @@ struct iavf_vlan { + enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ +- IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ ++ IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ + IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ + IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index a52c100dcbc56..6b06ae872a0cd 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -746,7 +746,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) { ++ if (f->state == IAVF_VLAN_ADDING) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +@@ -812,7 +812,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + if (f->state == IAVF_VLAN_ADD) { + vvfl->vlan_id[i] = f->vlan.vid; + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + if (i == count) + break; + } +@@ -874,7 +874,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) + vlan->tpid = f->vlan.tpid; + + i++; +- f->state = IAVF_VLAN_IS_NEW; ++ f->state = IAVF_VLAN_ADDING; + } + } + +@@ -2910,7 +2910,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_IS_NEW) ++ if (f->state == IAVF_VLAN_ADDING) + f->state = IAVF_VLAN_ACTIVE; + } + spin_unlock_bh(&adapter->mac_vlan_list_lock); +-- +2.53.0 + diff --git a/queue-7.0/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch b/queue-7.0/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch new file mode 100644 index 0000000000..85c744fb6c --- /dev/null +++ b/queue-7.0/iavf-stop-removing-vlan-filters-from-pf-on-interface.patch @@ -0,0 +1,233 @@ +From c4c6ab177309c39c2109f77479b59a33ffb64dc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:14 -0700 +Subject: iavf: stop removing VLAN filters from PF on interface down + +From: Petr Oros + +[ Upstream commit f2ce65b9b917474a1a6ce68d357e15fac2aca0f2 ] + +When a VF goes down, the driver currently sends DEL_VLAN to the PF for +every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then +re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING -> +ACTIVE). This round-trip is unnecessary because: + + 1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES, + which already prevents all RX/TX traffic regardless of VLAN filter + state. + + 2. The VLAN filters remaining in PF HW while the VF is down is + harmless - packets matching those filters have nowhere to go with + queues disabled. + + 3. The DEL+ADD cycle during down/up creates race windows where the + VLAN filter list is incomplete. With spoofcheck enabled, the PF + enables TX VLAN filtering on the first non-zero VLAN add, blocking + traffic for any VLANs not yet re-added. + +Remove the entire DISABLE/INACTIVE state machinery: + - Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values + - Remove iavf_restore_filters() and its call from iavf_open() + - Remove VLAN filter handling from iavf_clear_mac_vlan_filters(), + rename it to iavf_clear_mac_filters() + - Remove DEL_VLAN_FILTER scheduling from iavf_down() + - Remove all DISABLE/INACTIVE handling from iavf_del_vlans() + +VLAN filters now stay ACTIVE across down/up cycles. Only explicit +user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN +filter deletion/re-addition. + +Fixes: ed1f5b58ea01 ("i40evf: remove VLAN filters on close") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Simon Horman +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-2-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 6 +-- + drivers/net/ethernet/intel/iavf/iavf_main.c | 39 ++----------------- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 33 +++------------- + 3 files changed, 12 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 47a862ca5e2c3..5765715914d6b 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -159,10 +159,8 @@ enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ +- IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ +- IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ +- IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ +- IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ ++ IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ ++ IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index dad001abc9086..12e102506011a 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -801,27 +801,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +-/** +- * iavf_restore_filters +- * @adapter: board private structure +- * +- * Restore existing non MAC filters when VF netdev comes back up +- **/ +-static void iavf_restore_filters(struct iavf_adapter *adapter) +-{ +- struct iavf_vlan_filter *f; +- +- /* re-add all VLAN filters */ +- spin_lock_bh(&adapter->mac_vlan_list_lock); +- +- list_for_each_entry(f, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_INACTIVE) +- f->state = IAVF_VLAN_ADD; +- } +- +- spin_unlock_bh(&adapter->mac_vlan_list_lock); +- adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; +-} + + /** + * iavf_get_num_vlans_added - get number of VLANs added +@@ -1240,13 +1219,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) + } + + /** +- * iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF +- * yet and mark other to be removed. ++ * iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark ++ * others to be removed. + * @adapter: board private structure + **/ +-static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) ++static void iavf_clear_mac_filters(struct iavf_adapter *adapter) + { +- struct iavf_vlan_filter *vlf, *vlftmp; + struct iavf_mac_filter *f, *ftmp; + + spin_lock_bh(&adapter->mac_vlan_list_lock); +@@ -1265,11 +1243,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) + } + } + +- /* disable all VLAN filters */ +- list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, +- list) +- vlf->state = IAVF_VLAN_DISABLE; +- + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + +@@ -1365,7 +1338,7 @@ void iavf_down(struct iavf_adapter *adapter) + iavf_napi_disable_all(adapter); + iavf_irq_disable(adapter); + +- iavf_clear_mac_vlan_filters(adapter); ++ iavf_clear_mac_filters(adapter); + iavf_clear_cloud_filters(adapter); + iavf_clear_fdir_filters(adapter); + iavf_clear_adv_rss_conf(adapter); +@@ -1382,8 +1355,6 @@ void iavf_down(struct iavf_adapter *adapter) + */ + if (!list_empty(&adapter->mac_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; +- if (!list_empty(&adapter->vlan_filter_list)) +- adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; + if (!list_empty(&adapter->cloud_filter_list)) + adapter->aq_required |= IAVF_FLAG_AQ_DEL_CLOUD_FILTER; + if (!list_empty(&adapter->fdir_list_head)) +@@ -4488,8 +4459,6 @@ static int iavf_open(struct net_device *netdev) + iavf_add_filter(adapter, adapter->hw.mac.addr); + spin_unlock_bh(&adapter->mac_vlan_list_lock); + +- /* Restore filters that were removed with IFF_DOWN */ +- iavf_restore_filters(adapter); + iavf_restore_fdir_filters(adapter); + + iavf_configure(adapter); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 6b06ae872a0cd..4f197d908124e 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -911,22 +911,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + spin_lock_bh(&adapter->mac_vlan_list_lock); + + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- /* since VLAN capabilities are not allowed, we dont want to send +- * a VLAN delete request because it will most likely fail and +- * create unnecessary errors/noise, so just free the VLAN +- * filters marked for removal to enable bailing out before +- * sending a virtchnl message +- */ + if (f->state == IAVF_VLAN_REMOVE && + !VLAN_FILTERING_ALLOWED(adapter)) { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else if (f->state == IAVF_VLAN_DISABLE && +- !VLAN_FILTERING_ALLOWED(adapter)) { +- f->state = IAVF_VLAN_INACTIVE; +- } else if (f->state == IAVF_VLAN_REMOVE || +- f->state == IAVF_VLAN_DISABLE) { ++ } else if (f->state == IAVF_VLAN_REMOVE) { + count++; + } + } +@@ -959,13 +949,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE) { +- vvfl->vlan_id[i] = f->vlan.vid; +- f->state = IAVF_VLAN_INACTIVE; +- i++; +- if (i == count) +- break; +- } else if (f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; + list_del(&f->list); + kfree(f); +@@ -1007,8 +991,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; + list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { +- if (f->state == IAVF_VLAN_DISABLE || +- f->state == IAVF_VLAN_REMOVE) { ++ if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; + struct virtchnl_vlan *vlan; +@@ -1022,13 +1005,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- if (f->state == IAVF_VLAN_DISABLE) { +- f->state = IAVF_VLAN_INACTIVE; +- } else { +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; +- } ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; + i++; + if (i == count) + break; +-- +2.53.0 + diff --git a/queue-7.0/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch b/queue-7.0/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch new file mode 100644 index 0000000000..65028e71e9 --- /dev/null +++ b/queue-7.0/iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch @@ -0,0 +1,189 @@ +From 01fa27ba86dd50c8de576decf1f2aa6ad1d0bb62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:15 -0700 +Subject: iavf: wait for PF confirmation before removing VLAN filters + +From: Petr Oros + +[ Upstream commit bbcbe4ed70dea948849549af7edf44bd42bbd695 ] + +The VLAN filter DELETE path was asymmetric with the ADD path: ADD +waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE +immediately frees the filter struct after sending the DEL message +without waiting for the PF response. + +This is problematic because: + - If the PF rejects the DEL, the filter remains in HW but the driver + has already freed the tracking structure, losing sync. + - Race conditions between DEL pending and other operations + (add, reset) cannot be properly resolved if the filter struct + is already gone. + +Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric: + + REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree + -> PF rejects -> ACTIVE + +In iavf_del_vlans(), transition filters from REMOVE to REMOVING +instead of immediately freeing them. The new DEL completion handler +in iavf_virtchnl_completion() frees filters on success or reverts +them to ACTIVE on error. + +Update iavf_add_vlan() to handle the REMOVING state: if a DEL is +pending and the user re-adds the same VLAN, queue it for ADD so +it gets re-programmed after the PF processes the DEL. + +The !VLAN_FILTERING_ALLOWED early-exit path still frees filters +directly since no PF message is sent in that case. + +Also update iavf_del_vlan() to skip filters already in REMOVING +state: DEL has been sent to PF and the completion handler will +free the filter when PF confirms. Without this guard, the sequence +DEL(pending) -> user-del -> second DEL could cause the PF to return +an error for the second DEL (filter already gone), causing the +completion handler to incorrectly revert a deleted filter back to +ACTIVE. + +Fixes: 968996c070ef ("iavf: Fix VLAN_V2 addition/rejection") +Signed-off-by: Petr Oros +Reviewed-by: Aleksandr Loktionov +Tested-by: Rafal Romanowski +Reviewed-by: Przemek Kitszel +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-3-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/iavf/iavf.h | 1 + + drivers/net/ethernet/intel/iavf/iavf_main.c | 13 ++++--- + .../net/ethernet/intel/iavf/iavf_virtchnl.c | 37 +++++++++++++------ + 3 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h +index 5765715914d6b..050f8241ef5e6 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf.h ++++ b/drivers/net/ethernet/intel/iavf/iavf.h +@@ -161,6 +161,7 @@ enum iavf_vlan_state_t { + IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */ + IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ ++ IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ + }; + + struct iavf_vlan_filter { +diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c +index 12e102506011a..d373feee4c7e9 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_main.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_main.c +@@ -757,10 +757,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, + adapter->num_vlan_filters++; + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); + } else if (f->state == IAVF_VLAN_REMOVE) { +- /* Re-add the filter since we cannot tell whether the +- * pending delete has already been processed by the PF. +- * A duplicate add is harmless. +- */ ++ /* DEL not yet sent to PF, cancel it */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else if (f->state == IAVF_VLAN_REMOVING) { ++ /* DEL already sent to PF, re-add after completion */ + f->state = IAVF_VLAN_ADD; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_ADD_VLAN_FILTER); +@@ -791,11 +791,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; +- } else { ++ } else if (f->state != IAVF_VLAN_REMOVING) { + f->state = IAVF_VLAN_REMOVE; + iavf_schedule_aq_request(adapter, + IAVF_FLAG_AQ_DEL_VLAN_FILTER); + } ++ /* If REMOVING, DEL is already sent to PF; completion ++ * handler will free the filter when PF confirms. ++ */ + } + + spin_unlock_bh(&adapter->mac_vlan_list_lock); +diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +index 4f197d908124e..93ca79c3e3b53 100644 +--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c ++++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +@@ -948,12 +948,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl->vsi_id = adapter->vsi_res->vsi_id; + vvfl->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -990,7 +988,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + + vvfl_v2->vport_id = adapter->vsi_res->vsi_id; + vvfl_v2->num_elements = count; +- list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { ++ list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_REMOVE) { + struct virtchnl_vlan_supported_caps *filtering_support = + &adapter->vlan_v2_caps.filtering.filtering_support; +@@ -1005,9 +1003,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) + vlan->tci = f->vlan.vid; + vlan->tpid = f->vlan.tpid; + +- list_del(&f->list); +- kfree(f); +- adapter->num_vlan_filters--; ++ f->state = IAVF_VLAN_REMOVING; + i++; + if (i == count) + break; +@@ -2370,10 +2366,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); + wake_up(&adapter->vc_waitqueue); + break; +- case VIRTCHNL_OP_DEL_VLAN: +- dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n", +- iavf_stat_str(&adapter->hw, v_retval)); +- break; + case VIRTCHNL_OP_DEL_ETH_ADDR: + dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n", + iavf_stat_str(&adapter->hw, v_retval)); +@@ -2895,6 +2887,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, + spin_unlock_bh(&adapter->mac_vlan_list_lock); + } + break; ++ case VIRTCHNL_OP_DEL_VLAN: ++ case VIRTCHNL_OP_DEL_VLAN_V2: { ++ struct iavf_vlan_filter *f, *ftmp; ++ ++ spin_lock_bh(&adapter->mac_vlan_list_lock); ++ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, ++ list) { ++ if (f->state == IAVF_VLAN_REMOVING) { ++ if (v_retval) { ++ /* PF rejected DEL, keep filter */ ++ f->state = IAVF_VLAN_ACTIVE; ++ } else { ++ list_del(&f->list); ++ kfree(f); ++ adapter->num_vlan_filters--; ++ } ++ } ++ } ++ spin_unlock_bh(&adapter->mac_vlan_list_lock); ++ } ++ break; + case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING: + /* PF enabled vlan strip on this VF. + * Update netdev->features if needed to be in sync with ethtool. +-- +2.53.0 + diff --git a/queue-7.0/ice-add-dpll-peer-notification-for-paired-sma-and-u..patch b/queue-7.0/ice-add-dpll-peer-notification-for-paired-sma-and-u..patch new file mode 100644 index 0000000000..9e86116f58 --- /dev/null +++ b/queue-7.0/ice-add-dpll-peer-notification-for-paired-sma-and-u..patch @@ -0,0 +1,101 @@ +From cce7d8ac2c4e0f1791017a8079a571fe685a2061 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:23 -0700 +Subject: ice: add dpll peer notification for paired SMA and U.FL pins + +From: Petr Oros + +[ Upstream commit 9e5dead140af10e8b5f975b8f04e46197d48d274 ] + +SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and +SMA2/U.FL2). When one pin's state changes via a PCA9575 GPIO write, +the paired pin's state also changes, but no notification is sent for +the peer pin. Userspace consumers monitoring the peer via dpll netlink +subscribe never learn about the update. + +Add ice_dpll_sw_pin_notify_peer() which sends a change notification for +the paired SW pin. Call it from ice_dpll_pin_sma_direction_set(), +ice_dpll_sma_pin_state_set(), and ice_dpll_ufl_pin_state_set() after +pf->dplls.lock is released. Use __dpll_pin_change_ntf() because +dpll_lock is still held by the dpll netlink layer (dpll_pin_pre_doit). + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Signed-off-by: Petr Oros +Tested-by: Alexander Nowlin +Reviewed-by: Arkadiusz Kubalewski +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-11-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 32 +++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 721a3f4d6a28f..27b460926bace 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -1154,6 +1154,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, + extack, ICE_DPLL_PIN_TYPE_INPUT); + } + ++/** ++ * ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change ++ * @d: pointer to dplls struct ++ * @changed: the SW pin that was explicitly changed (already notified by dpll core) ++ * ++ * SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and ++ * SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO ++ * expander, the paired pin's state may also change. Send a change ++ * notification for the peer pin so userspace consumers monitoring the ++ * peer via dpll netlink learn about the update. ++ * ++ * Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is ++ * released. Uses __dpll_pin_change_ntf() because dpll_lock is ++ * still held by the dpll netlink layer. ++ */ ++static void ice_dpll_sw_pin_notify_peer(struct ice_dplls *d, ++ struct ice_dpll_pin *changed) ++{ ++ struct ice_dpll_pin *peer; ++ ++ peer = (changed >= d->sma && changed < d->sma + ICE_DPLL_PIN_SW_NUM) ? ++ &d->ufl[changed->idx] : &d->sma[changed->idx]; ++ if (peer->pin) ++ __dpll_pin_change_ntf(peer->pin); ++} ++ + /** + * ice_dpll_sma_direction_set - set direction of SMA pin + * @p: pointer to a pin +@@ -1344,6 +1370,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + + unlock: + mutex_unlock(&pf->dplls.lock); ++ if (!ret) ++ ice_dpll_sw_pin_notify_peer(&pf->dplls, p); + + return ret; + } +@@ -1462,6 +1490,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + + unlock: + mutex_unlock(&pf->dplls.lock); ++ if (!ret) ++ ice_dpll_sw_pin_notify_peer(&pf->dplls, sma); + + return ret; + } +@@ -1657,6 +1687,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv, + mutex_lock(&pf->dplls.lock); + ret = ice_dpll_sma_direction_set(p, direction, extack); + mutex_unlock(&pf->dplls.lock); ++ if (!ret) ++ ice_dpll_sw_pin_notify_peer(&pf->dplls, p); + + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-adjust-timer-programming-for-e830-devices.patch b/queue-7.0/ice-fix-adjust-timer-programming-for-e830-devices.patch new file mode 100644 index 0000000000..605617f61a --- /dev/null +++ b/queue-7.0/ice-fix-adjust-timer-programming-for-e830-devices.patch @@ -0,0 +1,74 @@ +From 56900452452a6476de94b4ede18b88a2c2c75b26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:25 -0700 +Subject: ice: fix 'adjust' timer programming for E830 devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Grzegorz Nitka + +[ Upstream commit 885c5e57924dc040b23d0ad0d8388f0e35772159 ] + +Fix incorrect 'adjust the timer' programming sequence for E830 devices +series. Only shadow registers GLTSYN_SHADJ were programmed in the +current implementation. According to the specification [1], write to +command GLTSYN_CMD register is also required with CMD field set to +"Adjust the Time" value, for the timer adjustment to take the effect. + +The flow was broken for the adjustment less than S32_MAX/MIN range +(around +/- 2 seconds). For bigger adjustment, non-atomic programming +flow is used, involving set timer programming. Non-atomic flow is +implemented correctly. + +Testing hints: +Run command: + phc_ctl /dev/ptpX get adj 2 get +Expected result: + Returned timestamps differ at least by 2 seconds + +[1] Intel® Ethernet Controller E830 Datasheet rev 1.3, chapter 9.7.5.4 +https://cdrdv2.intel.com/v1/dl/getContent/787353?explicitVersion=true + +Fixes: f00307522786 ("ice: Implement PTP support for E830 devices") +Reviewed-by: Aleksandr Loktionov +Signed-off-by: Grzegorz Nitka +Reviewed-by: Simon Horman +Tested-by: Rinitha S +Reviewed-by: Jacob Keller +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-1-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 61c0a0d93ea89..5a5c511ccbb6e 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -5381,8 +5381,8 @@ int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval) + */ + int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) + { ++ int err = 0; + u8 tmr_idx; +- int err; + + tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; + +@@ -5399,8 +5399,8 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) + err = ice_ptp_prep_phy_adj_e810(hw, adj); + break; + case ICE_MAC_E830: +- /* E830 sync PHYs automatically after setting GLTSYN_SHADJ */ +- return 0; ++ /* E830 sync PHYs automatically after setting cmd register */ ++ break; + case ICE_MAC_GENERIC: + err = ice_ptp_prep_phy_adj_e82x(hw, adj); + break; +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-double-free-of-tx_buf-skb.patch b/queue-7.0/ice-fix-double-free-of-tx_buf-skb.patch new file mode 100644 index 0000000000..d35ecb1608 --- /dev/null +++ b/queue-7.0/ice-fix-double-free-of-tx_buf-skb.patch @@ -0,0 +1,76 @@ +From 62c7b3543f5ef159f1ae335a6c9a48a50e4fcde2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:28 -0700 +Subject: ice: fix double-free of tx_buf skb + +From: Michal Schmidt + +[ Upstream commit 1a303baa715e6b78d6a406aaf335f87ff35acfcd ] + +If ice_tso() or ice_tx_csum() fail, the error path in +ice_xmit_frame_ring() frees the skb, but the 'first' tx_buf still points +to it and is marked as valid (ICE_TX_BUF_SKB). +'next_to_use' remains unchanged, so the potential problem will +likely fix itself when the next packet is transmitted and the tx_buf +gets overwritten. But if there is no next packet and the interface is +brought down instead, ice_clean_tx_ring() -> ice_unmap_and_free_tx_buf() +will find the tx_buf and free the skb for the second time. + +The fix is to reset the tx_buf type to ICE_TX_BUF_EMPTY in the error +path, so that ice_unmap_and_free_tx_buf(). +Move the initialization of 'first' up, to ensure it's already valid in +case we hit the linearization error path. + +The bug was spotted by AI while I had it looking for something else. +It also proposed an initial version of the patch. + +I reproduced the bug and tested the fix by adding code to inject +failures, on a build with KASAN. + +I looked for similar bugs in related Intel drivers and did not find any. + +Fixes: d76a60ba7afb ("ice: Add support for VLANs and offloads") +Assisted-by: Claude:claude-4.6-opus-high Cursor +Signed-off-by: Michal Schmidt +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-4-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index a2cd4cf377348..7be9c062949b8 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -2158,6 +2158,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + ice_trace(xmit_frame_ring, tx_ring, skb); + ++ /* record the location of the first descriptor for this packet */ ++ first = &tx_ring->tx_buf[tx_ring->next_to_use]; ++ + count = ice_xmit_desc_count(skb); + if (ice_chk_linearize(skb, count)) { + if (__skb_linearize(skb)) +@@ -2183,8 +2186,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + + offload.tx_ring = tx_ring; + +- /* record the location of the first descriptor for this packet */ +- first = &tx_ring->tx_buf[tx_ring->next_to_use]; + first->skb = skb; + first->type = ICE_TX_BUF_SKB; + first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN); +@@ -2249,6 +2250,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) + out_drop: + ice_trace(xmit_frame_ring_drop, tx_ring, skb); + dev_kfree_skb_any(skb); ++ first->type = ICE_TX_BUF_EMPTY; + return NETDEV_TX_OK; + } + +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-ice_aq_link_speed_m-for-200g.patch b/queue-7.0/ice-fix-ice_aq_link_speed_m-for-200g.patch new file mode 100644 index 0000000000..8e0bd9abdd --- /dev/null +++ b/queue-7.0/ice-fix-ice_aq_link_speed_m-for-200g.patch @@ -0,0 +1,47 @@ +From 7867ea986934fe27ce1c9c549310561e3ce8120c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:30 -0700 +Subject: ice: fix ICE_AQ_LINK_SPEED_M for 200G + +From: Paul Greenwalt + +[ Upstream commit 4a3a940059e98539de293a6e36e464094c2e875b ] + +When setting PHY configuration during driver initialization, 200G link +speed is not being advertised even when the PHY is capable. This is +because the get PHY capabilities link speed response is being masked by +ICE_AQ_LINK_SPEED_M, which does not include the 200G link speed bit. + +ICE_AQ_LINK_SPEED_200GB is defined as BIT(11), but the mask 0x7FF only +covers bits 0-10. Fix ICE_AQ_LINK_SPEED_M to use GENMASK(11, 0) so +that it covers all defined link speed bits including 200G. + +Fixes: 24407a01e57c ("ice: Add 200G speed/phy type use") +Signed-off-by: Paul Greenwalt +Signed-off-by: Aleksandr Loktionov +Reviewed-by: Simon Horman +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-6-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +index 859e9c66f3e7e..3cbb1b0582e32 100644 +--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h ++++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +@@ -1252,7 +1252,7 @@ struct ice_aqc_get_link_status_data { + #define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2 + #define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3 + __le16 link_speed; +-#define ICE_AQ_LINK_SPEED_M 0x7FF ++#define ICE_AQ_LINK_SPEED_M GENMASK(11, 0) + #define ICE_AQ_LINK_SPEED_10MB BIT(0) + #define ICE_AQ_LINK_SPEED_100MB BIT(1) + #define ICE_AQ_LINK_SPEED_1000MB BIT(2) +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch b/queue-7.0/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch new file mode 100644 index 0000000000..da68d977de --- /dev/null +++ b/queue-7.0/ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch @@ -0,0 +1,63 @@ +From 52279a6e94ca750229e99fb89696a1c2a5ecca9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:28 -0700 +Subject: ice: fix ice_ptp_read_tx_hwtstamp_status_eth56g + +From: Jacob Keller + +[ Upstream commit 1f75dbc53f68f0fb2acd99f92315e426a3d0b446 ] + +The ice_ptp_read_tx_hwtstamp_status_eth56g function calls +ice_read_phy_eth56g with a PHY index. However the function actually expects +a port index. This causes the function to read the wrong PHY_PTP_INT_STATUS +registers, and effectively makes the status wrong for the second set of +ports from 4 to 7. + +The ice_read_phy_eth56g function uses the provided port index to determine +which PHY device to read. We could refactor the entire chain to take a PHY +index, but this would impact many code sites. Instead, multiply the PHY +index by the number of ports, so that we read from the first port of each +PHY. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-4-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 4795af06b983e..24fb7a3e14d63 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -2219,13 +2219,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) + *ts_status = 0; + + for (phy = 0; phy < params->num_phys; phy++) { ++ u8 port; + int err; + +- err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status); ++ /* ice_read_phy_eth56g expects a port index, so use the first ++ * port of the PHY ++ */ ++ port = phy * hw->ptp.ports_per_phy; ++ ++ err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status); + if (err) + return err; + +- *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy); ++ *ts_status |= (status & mask) << port; + } + + ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status); +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-infinite-recursion-in-ice_cfg_tx_topo-via-ic.patch b/queue-7.0/ice-fix-infinite-recursion-in-ice_cfg_tx_topo-via-ic.patch new file mode 100644 index 0000000000..aa60d70c2c --- /dev/null +++ b/queue-7.0/ice-fix-infinite-recursion-in-ice_cfg_tx_topo-via-ic.patch @@ -0,0 +1,105 @@ +From 6e12b14339c0d85573c0983b75133135f951cf52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:18 -0700 +Subject: ice: fix infinite recursion in ice_cfg_tx_topo via ice_init_dev_hw + +From: Petr Oros + +[ Upstream commit 70ad216411e030f67b1743774e245601194aee6a ] + +On certain E810 configurations where firmware supports Tx scheduler +topology switching (tx_sched_topo_comp_mode_en), ice_cfg_tx_topo() +may need to apply a new 5-layer or 9-layer topology from the DDP +package. If the AQ command to set the topology fails (e.g. due to +invalid DDP data or firmware limitations), the global configuration +lock must still be cleared via a CORER reset. + +Commit 86aae43f21cf ("ice: don't leave device non-functional if Tx +scheduler config fails") correctly fixed this by refactoring +ice_cfg_tx_topo() to always trigger CORER after acquiring the global +lock and re-initialize hardware via ice_init_hw() afterwards. + +However, commit 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end +of deinit paths") later moved ice_init_dev_hw() into ice_init_hw(), +breaking the reinit path introduced by 86aae43f21cf. This creates an +infinite recursive call chain: + + ice_init_hw() + ice_init_dev_hw() + ice_cfg_tx_topo() # topology change needed + ice_deinit_hw() + ice_init_hw() # reinit after CORER + ice_init_dev_hw() # recurse + ice_cfg_tx_topo() + ... # stack overflow + +Fix by moving ice_init_dev_hw() back out of ice_init_hw() and calling +it explicitly from ice_probe() and ice_devlink_reinit_up(). The third +caller, ice_cfg_tx_topo(), intentionally does not need ice_init_dev_hw() +during its reinit, it only needs the core HW reinitialization. This +breaks the recursion cleanly without adding flags or guards. + +The deinit ordering changes from commit 8a37f9e2ff40 ("ice: move +ice_deinit_dev() to the end of deinit paths") which fixed slow rmmod +are preserved, only the init-side placement of ice_init_dev_hw() is +reverted. + +Fixes: 8a37f9e2ff40 ("ice: move ice_deinit_dev() to the end of deinit paths") +Signed-off-by: Petr Oros +Reviewed-by: Paul Menzel +Reviewed-by: Jacob Keller +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Przemek Kitszel +Tested-by: Alexander Nowlin +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-6-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/devlink/devlink.c | 2 ++ + drivers/net/ethernet/intel/ice/ice_common.c | 2 -- + drivers/net/ethernet/intel/ice/ice_main.c | 2 ++ + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c +index 6144cee8034d7..641d6e289d5ce 100644 +--- a/drivers/net/ethernet/intel/ice/devlink/devlink.c ++++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c +@@ -1245,6 +1245,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) + return err; + } + ++ ice_init_dev_hw(pf); ++ + /* load MSI-X values */ + ice_set_min_max_msix(pf); + +diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c +index ce11fea122d03..b617a6bff8913 100644 +--- a/drivers/net/ethernet/intel/ice/ice_common.c ++++ b/drivers/net/ethernet/intel/ice/ice_common.c +@@ -1126,8 +1126,6 @@ int ice_init_hw(struct ice_hw *hw) + if (status) + goto err_unroll_fltr_mgmt_struct; + +- ice_init_dev_hw(hw->back); +- + mutex_init(&hw->tnl_lock); + ice_init_chk_recipe_reuse_support(hw); + +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index ce3a0afe302d2..055968485af6c 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -5245,6 +5245,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) + return err; + } + ++ ice_init_dev_hw(pf); ++ + adapter = ice_adapter_get(pdev); + if (IS_ERR(adapter)) { + err = PTR_ERR(adapter); +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-missing-dpll-notifications-for-sw-pins.patch b/queue-7.0/ice-fix-missing-dpll-notifications-for-sw-pins.patch new file mode 100644 index 0000000000..85297af350 --- /dev/null +++ b/queue-7.0/ice-fix-missing-dpll-notifications-for-sw-pins.patch @@ -0,0 +1,157 @@ +From a7c4572a5b8782bfd6bbd2adb7e5ac3e87572075 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:22 -0700 +Subject: ice: fix missing dpll notifications for SW pins + +From: Petr Oros + +[ Upstream commit 1a41b58fd4dc80dca16c717e6e77c88b9d4e83a7 ] + +The SMA/U.FL pin redesign (commit 2dd5d03c77e2 ("ice: redesign dpll +sma/u.fl pins control")) introduced software-controlled pins that wrap +backing CGU input/output pins, but never updated the notification and +data paths to propagate pin events to these SW wrappers. + +The periodic work sends dpll_pin_change_ntf() only for direct CGU input +pins. SW pins that wrap these inputs never receive change or phase +offset notifications, so userspace consumers such as synce4l monitoring +SMA pins via dpll netlink never learn about state transitions or phase +offset updates. Similarly, ice_dpll_phase_offset_get() reads the SW +pin's own phase_offset field which is never updated; the PPS monitor +writes to the backing CGU input's field instead. + +Fix by introducing ice_dpll_pin_ntf(), a wrapper around +dpll_pin_change_ntf() that also notifies any registered SMA/U.FL pin +whose backing CGU input matches. Replace all direct +dpll_pin_change_ntf() calls in the periodic notification paths with +this wrapper. Fix ice_dpll_phase_offset_get() to return the backing +CGU input's phase_offset for input-direction SW pins. + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Signed-off-by: Petr Oros +Tested-by: Alexander Nowlin +Reviewed-by: Arkadiusz Kubalewski +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Ivan Vecera +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-10-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 47 +++++++++++++++++------ + 1 file changed, 36 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 3f8cd5b8298b5..721a3f4d6a28f 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -1963,7 +1963,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, + d->active_input == p->input->pin)) + *phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; + else if (d->phase_offset_monitor_period) +- *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; ++ *phase_offset = (p->input && ++ p->direction == DPLL_PIN_DIRECTION_INPUT ? ++ p->input->phase_offset : ++ p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR; + else + *phase_offset = 0; + mutex_unlock(&pf->dplls.lock); +@@ -2657,6 +2660,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) + return pci_get_dsn(pf->pdev); + } + ++/** ++ * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers ++ * @dplls: pointer to dplls struct ++ * @pin: the dpll_pin that changed ++ * ++ * Send a change notification for @pin and for any registered SMA/U.FL pin ++ * whose backing CGU input matches @pin. ++ */ ++static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin) ++{ ++ dpll_pin_change_ntf(pin); ++ for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) { ++ if (dplls->sma[i].pin && dplls->sma[i].input && ++ dplls->sma[i].input->pin == pin) ++ dpll_pin_change_ntf(dplls->sma[i].pin); ++ if (dplls->ufl[i].pin && dplls->ufl[i].input && ++ dplls->ufl[i].input->pin == pin) ++ dpll_pin_change_ntf(dplls->ufl[i].pin); ++ } ++} ++ + /** + * ice_dpll_notify_changes - notify dpll subsystem about changes + * @d: pointer do dpll +@@ -2665,6 +2689,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) + */ + static void ice_dpll_notify_changes(struct ice_dpll *d) + { ++ struct ice_dplls *dplls = &d->pf->dplls; + bool pin_notified = false; + + if (d->prev_dpll_state != d->dpll_state) { +@@ -2673,17 +2698,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) + } + if (d->prev_input != d->active_input) { + if (d->prev_input) +- dpll_pin_change_ntf(d->prev_input); ++ ice_dpll_pin_ntf(dplls, d->prev_input); + d->prev_input = d->active_input; + if (d->active_input) { +- dpll_pin_change_ntf(d->active_input); ++ ice_dpll_pin_ntf(dplls, d->active_input); + pin_notified = true; + } + } + if (d->prev_phase_offset != d->phase_offset) { + d->prev_phase_offset = d->phase_offset; + if (!pin_notified && d->active_input) +- dpll_pin_change_ntf(d->active_input); ++ ice_dpll_pin_ntf(dplls, d->active_input); + } + } + +@@ -2712,6 +2737,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) + + /** + * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes ++ * @dplls: pointer to dplls struct + * @pins: array of ice_dpll_pin pointers registered within dpll subsystem + * @pin_num: number of pins + * @phase_offset_ntf_mask: bitmask of pin indexes to notify +@@ -2721,15 +2747,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) + * + * Context: Must be called while pf->dplls.lock is released. + */ +-static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins, ++static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls, ++ struct ice_dpll_pin *pins, + u8 pin_num, + u32 phase_offset_ntf_mask) + { +- int i = 0; +- +- for (i = 0; i < pin_num; i++) +- if (phase_offset_ntf_mask & (1 << i)) +- dpll_pin_change_ntf(pins[i].pin); ++ for (int i = 0; i < pin_num; i++) ++ if (phase_offset_ntf_mask & BIT(i)) ++ ice_dpll_pin_ntf(dplls, pins[i].pin); + } + + /** +@@ -2905,7 +2930,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work) + ice_dpll_notify_changes(de); + ice_dpll_notify_changes(dp); + if (phase_offset_ntf) +- ice_dpll_pins_notify_mask(d->inputs, d->num_inputs, ++ ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs, + phase_offset_ntf); + + resched: +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-missing-sma-pin-initialization-in-dpll-subsy.patch b/queue-7.0/ice-fix-missing-sma-pin-initialization-in-dpll-subsy.patch new file mode 100644 index 0000000000..5c9adaf788 --- /dev/null +++ b/queue-7.0/ice-fix-missing-sma-pin-initialization-in-dpll-subsy.patch @@ -0,0 +1,88 @@ +From ac271c41e837c2df47fcf22545b440eab4401ff0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:19 -0700 +Subject: ice: fix missing SMA pin initialization in DPLL subsystem +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Petr Oros + +[ Upstream commit 56a643aed0f0af5c29ebb4593d4917b78344dd48 ] + +The DPLL SMA/U.FL pin redesign introduced ice_dpll_sw_pin_frequency_get() +which gates frequency reporting on the pin's active flag. This flag is +determined by ice_dpll_sw_pins_update() from the PCA9575 GPIO expander +state. Before the redesign, SMA pins were exposed as direct HW +input/output pins and ice_dpll_frequency_get() returned the CGU +frequency unconditionally — the PCA9575 state was never consulted. + +The PCA9575 powers on with all outputs high, setting ICE_SMA1_DIR_EN, +ICE_SMA1_TX_EN, ICE_SMA2_DIR_EN and ICE_SMA2_TX_EN. Nothing in the +driver writes the register during initialization, so +ice_dpll_sw_pins_update() sees all pins as inactive and +ice_dpll_sw_pin_frequency_get() permanently returns 0 Hz for every +SW pin. + +Fix this by writing a default SMA configuration in +ice_dpll_init_info_sw_pins(): clear all SMA bits, then set SMA1 and +SMA2 as active inputs (DIR_EN=0) with U.FL1 output and U.FL2 input +disabled. Each SMA/U.FL pair shares a physical signal path so only +one pin per pair can be active at a time. U.FL pins still report +frequency 0 after this fix: U.FL1 (output-only) is disabled by +ICE_SMA1_TX_EN which keeps the TX output buffer off, and U.FL2 +(input-only) is disabled by ICE_SMA2_UFL2_RX_DIS. They can be +activated by changing the corresponding SMA pin direction via dpll +netlink. + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Signed-off-by: Petr Oros +Reviewed-by: Ivan Vecera +Reviewed-by: Arkadiusz Kubalewski +Tested-by: Alexander Nowlin +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-7-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 62f75701d6520..498ec2c045f38 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -4014,6 +4014,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) + struct ice_dpll_pin *pin; + u32 phase_adj_max, caps; + int i, ret; ++ u8 data; + + if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) + input_idx_offset = ICE_E810_RCLK_PINS_NUM; +@@ -4073,6 +4074,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) + } + ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max); + } ++ ++ /* Initialize the SMA control register to a known-good default state. ++ * Without this write the PCA9575 GPIO expander retains its power-on ++ * default (all outputs high) which makes all SW pins appear inactive. ++ * Set SMA1 and SMA2 as active inputs, disable U.FL1 output and ++ * U.FL2 input. ++ */ ++ ret = ice_read_sma_ctrl(&pf->hw, &data); ++ if (ret) ++ return ret; ++ data &= ~ICE_ALL_SMA_MASK; ++ data |= ICE_SMA1_TX_EN | ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS; ++ ret = ice_write_sma_ctrl(&pf->hw, data); ++ if (ret) ++ return ret; ++ + ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE, + NULL); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch b/queue-7.0/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch new file mode 100644 index 0000000000..b96aecbfa7 --- /dev/null +++ b/queue-7.0/ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch @@ -0,0 +1,130 @@ +From 2932f399d54f908f5d8650d9c2e9a8550463359c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:17 -0700 +Subject: ice: fix NULL pointer dereference in ice_reset_all_vfs() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Petr Oros + +[ Upstream commit 54ef02487914c24170c7e1c061e45212dc55365e ] + +ice_reset_all_vfs() ignores the return value of ice_vf_rebuild_vsi(). +When the VSI rebuild fails (e.g. during NVM firmware update via +nvmupdate64e), ice_vsi_rebuild() tears down the VSI on its error path, +leaving txq_map and rxq_map as NULL. The subsequent unconditional call +to ice_vf_post_vsi_rebuild() leads to a NULL pointer dereference in +ice_ena_vf_q_mappings() when it accesses vsi->txq_map[0]. + +The single-VF reset path in ice_reset_vf() already handles this +correctly by checking the return value of ice_vf_reconfig_vsi() and +skipping ice_vf_post_vsi_rebuild() on failure. + +Apply the same pattern to ice_reset_all_vfs(): check the return value +of ice_vf_rebuild_vsi() and skip ice_vf_post_vsi_rebuild() and +ice_eswitch_attach_vf() on failure. The VF is left safely disabled +(ICE_VF_STATE_INIT not set, VFGEN_RSTAT not set to VFACTIVE) and can +be recovered via a VFLR triggered by a PCI reset of the VF +(sysfs reset or driver rebind). + +Note that this patch does not prevent the VF VSI rebuild from failing +during NVM update — the underlying cause is firmware being in a +transitional state while the EMP reset is processed, which can cause +Admin Queue commands (ice_add_vsi, ice_cfg_vsi_lan) to fail. This +patch only prevents the subsequent NULL pointer dereference that +crashes the kernel when the rebuild does fail. + + crash> bt + PID: 50795 TASK: ff34c9ee708dc680 CPU: 1 COMMAND: "kworker/u512:5" + #0 [ff72159bcfe5bb50] machine_kexec at ffffffffaa8850ee + #1 [ff72159bcfe5bba8] __crash_kexec at ffffffffaaa15fba + #2 [ff72159bcfe5bc68] crash_kexec at ffffffffaaa16540 + #3 [ff72159bcfe5bc70] oops_end at ffffffffaa837eda + #4 [ff72159bcfe5bc90] page_fault_oops at ffffffffaa893997 + #5 [ff72159bcfe5bce8] exc_page_fault at ffffffffab528595 + #6 [ff72159bcfe5bd10] asm_exc_page_fault at ffffffffab600bb2 + [exception RIP: ice_ena_vf_q_mappings+0x79] + RIP: ffffffffc0a85b29 RSP: ff72159bcfe5bdc8 RFLAGS: 00010206 + RAX: 00000000000f0000 RBX: ff34c9efc9c00000 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: 0000000000000010 RDI: ff34c9efc9c00000 + RBP: ff34c9efc27d4828 R8: 0000000000000093 R9: 0000000000000040 + R10: ff34c9efc27d4828 R11: 0000000000000040 R12: 0000000000100000 + R13: 0000000000000010 R14: R15: + ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 + #7 [ff72159bcfe5bdf8] ice_sriov_post_vsi_rebuild at ffffffffc0a85e2e [ice] + #8 [ff72159bcfe5be08] ice_reset_all_vfs at ffffffffc0a920b4 [ice] + #9 [ff72159bcfe5be48] ice_service_task at ffffffffc0a31519 [ice] + #10 [ff72159bcfe5be88] process_one_work at ffffffffaa93dca4 + #11 [ff72159bcfe5bec8] worker_thread at ffffffffaa93e9de + #12 [ff72159bcfe5bf18] kthread at ffffffffaa946663 + #13 [ff72159bcfe5bf50] ret_from_fork at ffffffffaa8086b9 + + The panic occurs attempting to dereference the NULL pointer in RDX at + ice_sriov.c:294, which loads vsi->txq_map (offset 0x4b8 in ice_vsi). + + The faulting VSI is an allocated slab object but not fully initialized + after a failed ice_vsi_rebuild(): + + crash> struct ice_vsi 0xff34c9efc27d4828 + netdev = 0x0, + rx_rings = 0x0, + tx_rings = 0x0, + q_vectors = 0x0, + txq_map = 0x0, + rxq_map = 0x0, + alloc_txq = 0x10, + num_txq = 0x10, + alloc_rxq = 0x10, + num_rxq = 0x10, + + The nvmupdate64e process was performing NVM firmware update: + + crash> bt 0xff34c9edd1a30000 + PID: 49858 TASK: ff34c9edd1a30000 CPU: 1 COMMAND: "nvmupdate64e" + #0 [ff72159bcd617618] __schedule at ffffffffab5333f8 + #4 [ff72159bcd617750] ice_sq_send_cmd at ffffffffc0a35347 [ice] + #5 [ff72159bcd6177a8] ice_sq_send_cmd_retry at ffffffffc0a35b47 [ice] + #6 [ff72159bcd617810] ice_aq_send_cmd at ffffffffc0a38018 [ice] + #7 [ff72159bcd617848] ice_aq_read_nvm at ffffffffc0a40254 [ice] + #8 [ff72159bcd6178b8] ice_read_flat_nvm at ffffffffc0a4034c [ice] + #9 [ff72159bcd617918] ice_devlink_nvm_snapshot at ffffffffc0a6ffa5 [ice] + + dmesg: + ice 0000:13:00.0: firmware recommends not updating fw.mgmt, as it + may result in a downgrade. continuing anyways + ice 0000:13:00.1: ice_init_nvm failed -5 + ice 0000:13:00.1: Rebuild failed, unload and reload driver + +Fixes: 12bb018c538c ("ice: Refactor VF reset") +Signed-off-by: Petr Oros +Tested-by: Rafal Romanowski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-5-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +index c8bc952f05cdb..51259a4fdda4b 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +@@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) + ice_vf_ctrl_invalidate_vsi(vf); + + ice_vf_pre_vsi_rebuild(vf); +- ice_vf_rebuild_vsi(vf); ++ if (ice_vf_rebuild_vsi(vf)) { ++ dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", ++ vf->vf_id); ++ mutex_unlock(&vf->cfg_lock); ++ continue; ++ } + ice_vf_post_vsi_rebuild(vf); + + ice_eswitch_attach_vf(pf, vf); +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-phy-config-on-media-change-with-link-down-on.patch b/queue-7.0/ice-fix-phy-config-on-media-change-with-link-down-on.patch new file mode 100644 index 0000000000..1fe6f2e032 --- /dev/null +++ b/queue-7.0/ice-fix-phy-config-on-media-change-with-link-down-on.patch @@ -0,0 +1,237 @@ +From 084e96b0003fa06d7bb8194dadbb6800ef21243f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:29 -0700 +Subject: ice: fix PHY config on media change with link-down-on-close + +From: Paul Greenwalt + +[ Upstream commit 55e74f9ea7fea3d3da1cb6d5cacdaf8cf0fe3516 ] + +Commit 1a3571b5938c ("ice: restore PHY settings on media insertion") +introduced separate flows for setting PHY configuration on media +present: ice_configure_phy() when link-down-on-close is disabled, and +ice_force_phys_link_state() when enabled. The latter incorrectly uses +the previous configuration even after module change, causing link +issues such as wrong speed or no link. + +Unify PHY configuration into a single ice_phy_cfg() function with a +link_en parameter, ensuring PHY capabilities are always fetched fresh +from hardware. + +Fixes: 1a3571b5938c ("ice: restore PHY settings on media insertion") +Reviewed-by: Przemek Kitszel +Signed-off-by: Paul Greenwalt +Reviewed-by: Aleksandr Loktionov +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-5-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_main.c | 121 +++++----------------- + 1 file changed, 27 insertions(+), 94 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index 3c36e3641b9e9..ce3a0afe302d2 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -1922,82 +1922,6 @@ static void ice_handle_mdd_event(struct ice_pf *pf) + ice_print_vfs_mdd_events(pf); + } + +-/** +- * ice_force_phys_link_state - Force the physical link state +- * @vsi: VSI to force the physical link state to up/down +- * @link_up: true/false indicates to set the physical link to up/down +- * +- * Force the physical link state by getting the current PHY capabilities from +- * hardware and setting the PHY config based on the determined capabilities. If +- * link changes a link event will be triggered because both the Enable Automatic +- * Link Update and LESM Enable bits are set when setting the PHY capabilities. +- * +- * Returns 0 on success, negative on failure +- */ +-static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up) +-{ +- struct ice_aqc_get_phy_caps_data *pcaps; +- struct ice_aqc_set_phy_cfg_data *cfg; +- struct ice_port_info *pi; +- struct device *dev; +- int retcode; +- +- if (!vsi || !vsi->port_info || !vsi->back) +- return -EINVAL; +- if (vsi->type != ICE_VSI_PF) +- return 0; +- +- dev = ice_pf_to_dev(vsi->back); +- +- pi = vsi->port_info; +- +- pcaps = kzalloc_obj(*pcaps); +- if (!pcaps) +- return -ENOMEM; +- +- retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps, +- NULL); +- if (retcode) { +- dev_err(dev, "Failed to get phy capabilities, VSI %d error %d\n", +- vsi->vsi_num, retcode); +- retcode = -EIO; +- goto out; +- } +- +- /* No change in link */ +- if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) && +- link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP)) +- goto out; +- +- /* Use the current user PHY configuration. The current user PHY +- * configuration is initialized during probe from PHY capabilities +- * software mode, and updated on set PHY configuration. +- */ +- cfg = kmemdup(&pi->phy.curr_user_phy_cfg, sizeof(*cfg), GFP_KERNEL); +- if (!cfg) { +- retcode = -ENOMEM; +- goto out; +- } +- +- cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; +- if (link_up) +- cfg->caps |= ICE_AQ_PHY_ENA_LINK; +- else +- cfg->caps &= ~ICE_AQ_PHY_ENA_LINK; +- +- retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi, cfg, NULL); +- if (retcode) { +- dev_err(dev, "Failed to set phy config, VSI %d error %d\n", +- vsi->vsi_num, retcode); +- retcode = -EIO; +- } +- +- kfree(cfg); +-out: +- kfree(pcaps); +- return retcode; +-} +- + /** + * ice_init_nvm_phy_type - Initialize the NVM PHY type + * @pi: port info structure +@@ -2066,7 +1990,7 @@ static void ice_init_link_dflt_override(struct ice_port_info *pi) + * first time media is available. The ICE_LINK_DEFAULT_OVERRIDE_PENDING state + * is used to indicate that the user PHY cfg default override is initialized + * and the PHY has not been configured with the default override settings. The +- * state is set here, and cleared in ice_configure_phy the first time the PHY is ++ * state is set here, and cleared in ice_phy_cfg the first time the PHY is + * configured. + * + * This function should be called only if the FW doesn't support default +@@ -2172,14 +2096,18 @@ static int ice_init_phy_user_cfg(struct ice_port_info *pi) + } + + /** +- * ice_configure_phy - configure PHY ++ * ice_phy_cfg - configure PHY + * @vsi: VSI of PHY ++ * @link_en: true/false indicates to set link to enable/disable + * + * Set the PHY configuration. If the current PHY configuration is the same as +- * the curr_user_phy_cfg, then do nothing to avoid link flap. Otherwise +- * configure the based get PHY capabilities for topology with media. ++ * the curr_user_phy_cfg and link_en hasn't changed, then do nothing to avoid ++ * link flap. Otherwise configure the PHY based get PHY capabilities for ++ * topology with media and link_en. ++ * ++ * Return: 0 on success, negative on failure + */ +-static int ice_configure_phy(struct ice_vsi *vsi) ++static int ice_phy_cfg(struct ice_vsi *vsi, bool link_en) + { + struct device *dev = ice_pf_to_dev(vsi->back); + struct ice_port_info *pi = vsi->port_info; +@@ -2199,9 +2127,6 @@ static int ice_configure_phy(struct ice_vsi *vsi) + phy->link_info.topo_media_conflict == ICE_AQ_LINK_TOPO_UNSUPP_MEDIA) + return -EPERM; + +- if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags)) +- return ice_force_phys_link_state(vsi, true); +- + pcaps = kzalloc_obj(*pcaps); + if (!pcaps) + return -ENOMEM; +@@ -2215,10 +2140,8 @@ static int ice_configure_phy(struct ice_vsi *vsi) + goto done; + } + +- /* If PHY enable link is configured and configuration has not changed, +- * there's nothing to do +- */ +- if (pcaps->caps & ICE_AQC_PHY_EN_LINK && ++ /* Configuration has not changed. There's nothing to do. */ ++ if (link_en == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) && + ice_phy_caps_equals_cfg(pcaps, &phy->curr_user_phy_cfg)) + goto done; + +@@ -2282,8 +2205,12 @@ static int ice_configure_phy(struct ice_vsi *vsi) + */ + ice_cfg_phy_fc(pi, cfg, phy->curr_user_fc_req); + +- /* Enable link and link update */ +- cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK; ++ /* Enable/Disable link and link update */ ++ cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; ++ if (link_en) ++ cfg->caps |= ICE_AQ_PHY_ENA_LINK; ++ else ++ cfg->caps &= ~ICE_AQ_PHY_ENA_LINK; + + err = ice_aq_set_phy_cfg(&pf->hw, pi, cfg, NULL); + if (err) +@@ -2336,7 +2263,7 @@ static void ice_check_media_subtask(struct ice_pf *pf) + test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) + return; + +- err = ice_configure_phy(vsi); ++ err = ice_phy_cfg(vsi, true); + if (!err) + clear_bit(ICE_FLAG_NO_MEDIA, pf->flags); + +@@ -4892,9 +4819,15 @@ static int ice_init_link(struct ice_pf *pf) + + if (!test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags)) { + struct ice_vsi *vsi = ice_get_main_vsi(pf); ++ struct ice_link_default_override_tlv *ldo; ++ bool link_en; ++ ++ ldo = &pf->link_dflt_override; ++ link_en = !(ldo->options & ++ ICE_LINK_OVERRIDE_AUTO_LINK_DIS); + + if (vsi) +- ice_configure_phy(vsi); ++ ice_phy_cfg(vsi, link_en); + } + } else { + set_bit(ICE_FLAG_NO_MEDIA, pf->flags); +@@ -9707,7 +9640,7 @@ int ice_open_internal(struct net_device *netdev) + } + } + +- err = ice_configure_phy(vsi); ++ err = ice_phy_cfg(vsi, true); + if (err) { + netdev_err(netdev, "Failed to set physical link up, error %d\n", + err); +@@ -9748,7 +9681,7 @@ int ice_stop(struct net_device *netdev) + } + + if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) { +- int link_err = ice_force_phys_link_state(vsi, false); ++ int link_err = ice_phy_cfg(vsi, false); + + if (link_err) { + if (link_err == -ENOMEDIUM) +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-potential-null-pointer-deref-in-error-path-o.patch b/queue-7.0/ice-fix-potential-null-pointer-deref-in-error-path-o.patch new file mode 100644 index 0000000000..cec66247ac --- /dev/null +++ b/queue-7.0/ice-fix-potential-null-pointer-deref-in-error-path-o.patch @@ -0,0 +1,54 @@ +From 51a04ea1a615c160661271d7c4b3960dcd5c9872 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:32 -0700 +Subject: ice: fix potential NULL pointer deref in error path of + ice_set_ringparam() + +From: Kohei Enju + +[ Upstream commit fa28351f970fa5138c7c5dedfe5dea480a0ee065 ] + +ice_set_ringparam nullifies tstamp_ring of temporary tx_rings, without +clearing ICE_TX_RING_FLAGS_TXTIME bit. +When ICE_TX_RING_FLAGS_TXTIME is set and the subsequent +ice_setup_tx_ring() call fails, a NULL pointer dereference could happen +in the unwinding sequence: + +ice_clean_tx_ring() +-> ice_is_txtime_cfg() == true (ICE_TX_RING_FLAGS_TXTIME is set) +-> ice_free_tx_tstamp_ring() + -> ice_free_tstamp_ring() + -> tstamp_ring->desc (NULL deref) + +Clear ICE_TX_RING_FLAGS_TXTIME bit to avoid the potential issue. + +Note that this potential issue is found by manual code review. +Compile test only since unfortunately I don't have E830 devices. + +Fixes: ccde82e90946 ("ice: add E830 Earliest TxTime First Offload support") +Signed-off-by: Kohei Enju +Reviewed-by: Paul Greenwalt +Tested-by: Rinitha S +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-8-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ethtool.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c +index e6a20af6f63de..f28416a707d77 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c ++++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c +@@ -3290,6 +3290,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, + tx_rings[i].desc = NULL; + tx_rings[i].tx_buf = NULL; + tx_rings[i].tstamp_ring = NULL; ++ clear_bit(ICE_TX_RING_FLAGS_TXTIME, tx_rings[i].flags); + tx_rings[i].tx_tstamps = &pf->ptp.port.tx; + err = ice_setup_tx_ring(&tx_rings[i]); + if (err) { +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-race-condition-in-tx-timestamp-ring-cleanup.patch b/queue-7.0/ice-fix-race-condition-in-tx-timestamp-ring-cleanup.patch new file mode 100644 index 0000000000..07b9698f7f --- /dev/null +++ b/queue-7.0/ice-fix-race-condition-in-tx-timestamp-ring-cleanup.patch @@ -0,0 +1,217 @@ +From 98a5f411244d6a9c8b156ca7e6a06a5cf0b153e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:31 -0700 +Subject: ice: fix race condition in TX timestamp ring cleanup + +From: Keita Morisaki + +[ Upstream commit 7c72ec18c2a4111204c2e915f8e4f6d849ce9398 ] + +Fix a race condition between ice_free_tx_tstamp_ring() and ice_tx_map() +that can cause a NULL pointer dereference. + +ice_free_tx_tstamp_ring currently clears the ICE_TX_FLAGS_TXTIME flag +after NULLing the tstamp_ring. This could allow a concurrent ice_tx_map +call on another CPU to dereference the tstamp_ring, which could lead to +a NULL pointer dereference. + + CPU A:ice_free_tx_tstamp_ring() | CPU B:ice_tx_map() + --------------------------------|--------------------------------- + tx_ring->tstamp_ring = NULL | + | ice_is_txtime_cfg() -> true + | tstamp_ring = tx_ring->tstamp_ring + | tstamp_ring->count // NULL deref! + flags &= ~ICE_TX_FLAGS_TXTIME | + +Fix by: +1. Reordering ice_free_tx_tstamp_ring() to clear the flag before + NULLing the pointer, with smp_wmb() to ensure proper ordering. +2. Adding smp_rmb() in ice_tx_map() after the flag check to order the + flag read before the pointer read, using READ_ONCE() for the + pointer, and adding a NULL check as a safety net. +3. Converting tx_ring->flags from u8 to DECLARE_BITMAP() and using + atomic bitops (set_bit(), clear_bit(), test_bit()) for all flag + operations throughout the driver: + - ICE_TX_RING_FLAGS_XDP + - ICE_TX_RING_FLAGS_VLAN_L2TAG1 + - ICE_TX_RING_FLAGS_VLAN_L2TAG2 + - ICE_TX_RING_FLAGS_TXTIME + +Fixes: ccde82e909467 ("ice: add E830 Earliest TxTime First Offload support") +Signed-off-by: Keita Morisaki +Reviewed-by: Aleksandr Loktionov +Tested-by: Rinitha S +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-7-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice.h | 4 ++-- + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 2 +- + drivers/net/ethernet/intel/ice/ice_lib.c | 4 ++-- + drivers/net/ethernet/intel/ice/ice_txrx.c | 23 ++++++++++++++------ + drivers/net/ethernet/intel/ice/ice_txrx.h | 16 +++++++++----- + 5 files changed, 31 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h +index eb3a48330cc15..725b130dd3a2c 100644 +--- a/drivers/net/ethernet/intel/ice/ice.h ++++ b/drivers/net/ethernet/intel/ice/ice.h +@@ -753,7 +753,7 @@ static inline bool ice_is_xdp_ena_vsi(struct ice_vsi *vsi) + + static inline void ice_set_ring_xdp(struct ice_tx_ring *ring) + { +- ring->flags |= ICE_TX_FLAGS_RING_XDP; ++ set_bit(ICE_TX_RING_FLAGS_XDP, ring->flags); + } + + /** +@@ -778,7 +778,7 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring) + */ + static inline bool ice_is_txtime_cfg(const struct ice_tx_ring *ring) + { +- return !!(ring->flags & ICE_TX_FLAGS_TXTIME); ++ return test_bit(ICE_TX_RING_FLAGS_TXTIME, ring->flags); + } + + /** +diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +index bd77f1c001ee8..16aa255351523 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +@@ -943,7 +943,7 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_tx_ring *tx_ring, + /* if this is not already set it means a VLAN 0 + priority needs + * to be offloaded + */ +- if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2) ++ if (test_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, tx_ring->flags)) + first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN; + else + first->tx_flags |= ICE_TX_FLAGS_HW_VLAN; +diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c +index 689c6025ea82e..837b71b7b2b7c 100644 +--- a/drivers/net/ethernet/intel/ice/ice_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_lib.c +@@ -1412,9 +1412,9 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) + ring->count = vsi->num_tx_desc; + ring->txq_teid = ICE_INVAL_TEID; + if (dvm_ena) +- ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG2; ++ set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, ring->flags); + else +- ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG1; ++ set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG1, ring->flags); + WRITE_ONCE(vsi->tx_rings[i], ring); + } + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 7be9c062949b8..4ca1a0602307d 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -190,9 +190,10 @@ void ice_free_tstamp_ring(struct ice_tx_ring *tx_ring) + void ice_free_tx_tstamp_ring(struct ice_tx_ring *tx_ring) + { + ice_free_tstamp_ring(tx_ring); ++ clear_bit(ICE_TX_RING_FLAGS_TXTIME, tx_ring->flags); ++ smp_wmb(); /* order flag clear before pointer NULL */ + kfree_rcu(tx_ring->tstamp_ring, rcu); +- tx_ring->tstamp_ring = NULL; +- tx_ring->flags &= ~ICE_TX_FLAGS_TXTIME; ++ WRITE_ONCE(tx_ring->tstamp_ring, NULL); + } + + /** +@@ -405,7 +406,7 @@ static int ice_alloc_tstamp_ring(struct ice_tx_ring *tx_ring) + tx_ring->tstamp_ring = tstamp_ring; + tstamp_ring->desc = NULL; + tstamp_ring->count = ice_calc_ts_ring_count(tx_ring); +- tx_ring->flags |= ICE_TX_FLAGS_TXTIME; ++ set_bit(ICE_TX_RING_FLAGS_TXTIME, tx_ring->flags); + return 0; + } + +@@ -1521,13 +1522,20 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first, + return; + + if (ice_is_txtime_cfg(tx_ring)) { +- struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring; +- u32 tstamp_count = tstamp_ring->count; +- u32 j = tstamp_ring->next_to_use; ++ struct ice_tstamp_ring *tstamp_ring; ++ u32 tstamp_count, j; + struct ice_ts_desc *ts_desc; + struct timespec64 ts; + u32 tstamp; + ++ smp_rmb(); /* order flag read before pointer read */ ++ tstamp_ring = READ_ONCE(tx_ring->tstamp_ring); ++ if (unlikely(!tstamp_ring)) ++ goto ring_kick; ++ ++ tstamp_count = tstamp_ring->count; ++ j = tstamp_ring->next_to_use; ++ + ts = ktime_to_timespec64(first->skb->tstamp); + tstamp = ts.tv_nsec >> ICE_TXTIME_CTX_RESOLUTION_128NS; + +@@ -1555,6 +1563,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first, + tstamp_ring->next_to_use = j; + writel_relaxed(j, tstamp_ring->tail); + } else { ++ring_kick: + writel_relaxed(i, tx_ring->tail); + } + return; +@@ -1814,7 +1823,7 @@ ice_tx_prepare_vlan_flags(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first) + */ + if (skb_vlan_tag_present(skb)) { + first->vid = skb_vlan_tag_get(skb); +- if (tx_ring->flags & ICE_TX_FLAGS_RING_VLAN_L2TAG2) ++ if (test_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, tx_ring->flags)) + first->tx_flags |= ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN; + else + first->tx_flags |= ICE_TX_FLAGS_HW_VLAN; +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h +index b6547e1b7c423..5e517f2193798 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.h ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.h +@@ -212,6 +212,14 @@ enum ice_rx_dtype { + ICE_RX_DTYPE_SPLIT_ALWAYS = 2, + }; + ++enum ice_tx_ring_flags { ++ ICE_TX_RING_FLAGS_XDP, ++ ICE_TX_RING_FLAGS_VLAN_L2TAG1, ++ ICE_TX_RING_FLAGS_VLAN_L2TAG2, ++ ICE_TX_RING_FLAGS_TXTIME, ++ ICE_TX_RING_FLAGS_NBITS, ++}; ++ + struct ice_pkt_ctx { + u64 cached_phctime; + __be16 vlan_proto; +@@ -352,11 +360,7 @@ struct ice_tx_ring { + u16 count; /* Number of descriptors */ + u16 q_index; /* Queue number of ring */ + +- u8 flags; +-#define ICE_TX_FLAGS_RING_XDP BIT(0) +-#define ICE_TX_FLAGS_RING_VLAN_L2TAG1 BIT(1) +-#define ICE_TX_FLAGS_RING_VLAN_L2TAG2 BIT(2) +-#define ICE_TX_FLAGS_TXTIME BIT(3) ++ DECLARE_BITMAP(flags, ICE_TX_RING_FLAGS_NBITS); + + struct xsk_buff_pool *xsk_pool; + +@@ -398,7 +402,7 @@ static inline bool ice_ring_ch_enabled(struct ice_tx_ring *ring) + + static inline bool ice_ring_is_xdp(struct ice_tx_ring *ring) + { +- return !!(ring->flags & ICE_TX_FLAGS_RING_XDP); ++ return test_bit(ICE_TX_RING_FLAGS_XDP, ring->flags); + } + + enum ice_container_type { +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-ready-bitmap-check-for-non-e822-devices.patch b/queue-7.0/ice-fix-ready-bitmap-check-for-non-e822-devices.patch new file mode 100644 index 0000000000..dd49b34a0a --- /dev/null +++ b/queue-7.0/ice-fix-ready-bitmap-check-for-non-e822-devices.patch @@ -0,0 +1,343 @@ +From 46909c1018e0b445a4c19fab3c41bbb1a320fe01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:27 -0700 +Subject: ice: fix ready bitmap check for non-E822 devices + +From: Jacob Keller + +[ Upstream commit 359dc1d41358c88955eeff1b75aee55da7a415d3 ] + +The E800 hardware (apart from E810) has a ready bitmap for the PHY +indicating which timestamp slots currently have an outstanding timestamp +waiting to be read by software. + +This bitmap is checked in multiple places using the +ice_get_phy_tx_tstamp_ready(): + + * ice_ptp_process_tx_tstamp() calls it to determine which timestamps to + attempt reading from the PHY + * ice_ptp_tx_tstamps_pending() calls it in a loop at the end of the + miscellaneous IRQ to check if new timestamps came in while the interrupt + handler was executing. + * ice_ptp_maybe_trigger_tx_interrupt() calls it in the auxiliary work task + to trigger a software interrupt in the event that the hardware logic + gets stuck. + +For E82X devices, multiple PHYs share the same block, and the parameter +passed to the ready bitmap is a block number associated with the given +port. For E825-C devices, the PHYs have their own independent blocks and do +not share, so the parameter passed needs to be the port number. For E810 +devices, the ice_get_phy_tx_tstamp_ready() always returns all 1s regardless +of what port, since this hardware does not have a ready bitmap. Finally, +for E830 devices, each PF has its own ready bitmap accessible via register, +and the block parameter is unused. + +The first call correctly uses the Tx timestamp tracker block parameter to +check the appropriate timestamp block. This works because the tracker is +setup correctly for each timestamp device type. + +The second two callers behave incorrectly for all device types other than +the older E822 devices. They both iterate in a loop using +ICE_GET_QUAD_NUM() which is a macro only used by E822 devices. This logic +is incorrect for devices other than the E822 devices. + +For E810 the calls would always return true, causing E810 devices to always +attempt to trigger a software interrupt even when they have no reason to. +For E830, this results in duplicate work as the ready bitmap is checked +once per number of quads. Finally, for E825-C, this results in the pending +checks failing to detect timestamps on ports other than the first two. + +Fix this by introducing a new hardware API function to ice_ptp_hw.c, +ice_check_phy_tx_tstamp_ready(). This function will check if any timestamps +are available and returns a positive value if any timestamps are pending. +For E810, the function always returns false, so that the re-trigger checks +never happen. For E830, check the ready bitmap just once. For E82x +hardware, check each quad. Finally, for E825-C, check every port. + +The interface function returns an integer to enable reporting of error code +if the driver is unable read the ready bitmap. This enables callers to +handle this case properly. The previous implementation assumed that +timestamps are available if they failed to read the bitmap. This is +problematic as it could lead to continuous software IRQ triggering if the +PHY timestamp registers somehow become inaccessible. + +This change is especially important for E825-C devices, as the missing +checks could leave a window open where a new timestamp could arrive while +the existing timestamps aren't completed. As a result, the hardware +threshold logic would not trigger a new interrupt. Without the check, the +timestamp is left unhandled, and new timestamps will not cause an interrupt +again until the timestamp is handled. Since both the interrupt check and +the backup check in the auxiliary task do not function properly, the device +may have Tx timestamps permanently stuck failing on a given port. + +The faulty checks originate from commit d938a8cca88a ("ice: Auxbus devices +& driver for E822 TS") and commit 712e876371f8 ("ice: periodically kick Tx +timestamp interrupt"), however at the time of the original coding, both +functions only operated on E822 hardware. This is no longer the case, and +hasn't been since the introduction of the ETH56G PHY model in commit +7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-3-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp.c | 44 +++----- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 117 ++++++++++++++++++++ + drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 1 + + 3 files changed, 136 insertions(+), 26 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c +index 6cb0cf7a98912..36df742c326c7 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp.c +@@ -2710,7 +2710,7 @@ static bool ice_any_port_has_timestamps(struct ice_pf *pf) + bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) + { + struct ice_hw *hw = &pf->hw; +- unsigned int i; ++ int ret; + + /* Check software indicator */ + switch (pf->ptp.tx_interrupt_mode) { +@@ -2731,16 +2731,19 @@ bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) + } + + /* Check hardware indicator */ +- for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { +- u64 tstamp_ready = 0; +- int err; +- +- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); +- if (err || tstamp_ready) +- return true; ++ ret = ice_check_phy_tx_tstamp_ready(hw); ++ if (ret < 0) { ++ dev_dbg(ice_pf_to_dev(pf), "Unable to read PHY Tx timestamp ready bitmap, err %d\n", ++ ret); ++ /* Stop triggering IRQs if we're unable to read PHY */ ++ return false; + } + +- return false; ++ /* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps ++ * available, 0 if there are no waiting timestamps, and a negative ++ * value if there was an error (which we checked for above). ++ */ ++ return ret > 0; + } + + /** +@@ -2824,8 +2827,7 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) + { + struct device *dev = ice_pf_to_dev(pf); + struct ice_hw *hw = &pf->hw; +- bool trigger_oicr = false; +- unsigned int i; ++ int ret; + + if (!pf->ptp.port.tx.has_ready_bitmap) + return; +@@ -2833,21 +2835,11 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) + if (!ice_pf_src_tmr_owned(pf)) + return; + +- for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { +- u64 tstamp_ready; +- int err; +- +- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); +- if (!err && tstamp_ready) { +- trigger_oicr = true; +- break; +- } +- } +- +- if (trigger_oicr) { +- /* Trigger a software interrupt, to ensure this data +- * gets processed. +- */ ++ ret = ice_check_phy_tx_tstamp_ready(hw); ++ if (ret < 0) { ++ dev_dbg(dev, "PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n", ++ ret); ++ } else if (ret) { + dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n"); + + wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M); +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index d4c2bb084255d..4795af06b983e 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -2168,6 +2168,35 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port) + return 0; + } + ++/** ++ * ice_check_phy_tx_tstamp_ready_eth56g - Check Tx memory status for all ports ++ * @hw: pointer to the HW struct ++ * ++ * Check the PHY_REG_TX_MEMORY_STATUS for all ports. A set bit indicates ++ * a waiting timestamp. ++ * ++ * Return: 1 if any port has at least one timestamp ready bit set, ++ * 0 otherwise, and a negative error code if unable to read the bitmap. ++ */ ++static int ice_check_phy_tx_tstamp_ready_eth56g(struct ice_hw *hw) ++{ ++ int port; ++ ++ for (port = 0; port < hw->ptp.num_lports; port++) { ++ u64 tstamp_ready; ++ int err; ++ ++ err = ice_get_phy_tx_tstamp_ready(hw, port, &tstamp_ready); ++ if (err) ++ return err; ++ ++ if (tstamp_ready) ++ return 1; ++ } ++ ++ return 0; ++} ++ + /** + * ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status + * @hw: pointer to the HW struct +@@ -4318,6 +4347,35 @@ ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready) + return 0; + } + ++/** ++ * ice_check_phy_tx_tstamp_ready_e82x - Check Tx memory status for all quads ++ * @hw: pointer to the HW struct ++ * ++ * Check the Q_REG_TX_MEMORY_STATUS for all quads. A set bit indicates ++ * a waiting timestamp. ++ * ++ * Return: 1 if any quad has at least one timestamp ready bit set, ++ * 0 otherwise, and a negative error value if unable to read the bitmap. ++ */ ++static int ice_check_phy_tx_tstamp_ready_e82x(struct ice_hw *hw) ++{ ++ int quad; ++ ++ for (quad = 0; quad < ICE_GET_QUAD_NUM(hw->ptp.num_lports); quad++) { ++ u64 tstamp_ready; ++ int err; ++ ++ err = ice_get_phy_tx_tstamp_ready(hw, quad, &tstamp_ready); ++ if (err) ++ return err; ++ ++ if (tstamp_ready) ++ return 1; ++ } ++ ++ return 0; ++} ++ + /** + * ice_phy_cfg_intr_e82x - Configure TX timestamp interrupt + * @hw: pointer to the HW struct +@@ -4871,6 +4929,23 @@ ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready) + return 0; + } + ++/** ++ * ice_check_phy_tx_tstamp_ready_e810 - Check Tx memory status register ++ * @hw: pointer to the HW struct ++ * ++ * The E810 devices do not have a Tx memory status register. Note this is ++ * intentionally different behavior from ice_get_phy_tx_tstamp_ready_e810 ++ * which always says that all bits are ready. This function is called in cases ++ * where code will trigger interrupts if timestamps are waiting, and should ++ * not be called for E810 hardware. ++ * ++ * Return: 0. ++ */ ++static int ice_check_phy_tx_tstamp_ready_e810(struct ice_hw *hw) ++{ ++ return 0; ++} ++ + /* E810 SMA functions + * + * The following functions operate specifically on E810 hardware and are used +@@ -5125,6 +5200,21 @@ static void ice_get_phy_tx_tstamp_ready_e830(const struct ice_hw *hw, u8 port, + *tstamp_ready |= rd32(hw, E830_PRTMAC_TS_TX_MEM_VALID_L); + } + ++/** ++ * ice_check_phy_tx_tstamp_ready_e830 - Check Tx memory status register ++ * @hw: pointer to the HW struct ++ * ++ * Return: 1 if the device has waiting timestamps, 0 otherwise. ++ */ ++static int ice_check_phy_tx_tstamp_ready_e830(struct ice_hw *hw) ++{ ++ u64 tstamp_ready; ++ ++ ice_get_phy_tx_tstamp_ready_e830(hw, 0, &tstamp_ready); ++ ++ return !!tstamp_ready; ++} ++ + /** + * ice_ptp_init_phy_e830 - initialize PHY parameters + * @ptp: pointer to the PTP HW struct +@@ -5717,6 +5807,33 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) + } + } + ++/** ++ * ice_check_phy_tx_tstamp_ready - Check PHY Tx timestamp memory status ++ * @hw: pointer to the HW struct ++ * ++ * Check the PHY for Tx timestamp memory status on all ports. If you need to ++ * see individual timestamp status for each index, use ++ * ice_get_phy_tx_tstamp_ready() instead. ++ * ++ * Return: 1 if any port has timestamps available, 0 if there are no timestamps ++ * available, and a negative error code on failure. ++ */ ++int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw) ++{ ++ switch (hw->mac_type) { ++ case ICE_MAC_E810: ++ return ice_check_phy_tx_tstamp_ready_e810(hw); ++ case ICE_MAC_E830: ++ return ice_check_phy_tx_tstamp_ready_e830(hw); ++ case ICE_MAC_GENERIC: ++ return ice_check_phy_tx_tstamp_ready_e82x(hw); ++ case ICE_MAC_GENERIC_3K_E825: ++ return ice_check_phy_tx_tstamp_ready_eth56g(hw); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ + /** + * ice_cgu_get_pin_desc_e823 - get pin description array + * @hw: pointer to the hw struct +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +index 9d7acc7eb2ceb..1b58b054f4a5b 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +@@ -300,6 +300,7 @@ void ice_ptp_reset_ts_memory(struct ice_hw *hw); + int ice_ptp_init_phc(struct ice_hw *hw); + void ice_ptp_init_hw(struct ice_hw *hw); + int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready); ++int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw); + int ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, + enum ice_ptp_tmr_cmd configured_cmd); + +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-sma-and-u.fl-pin-state-changes-affecting-pai.patch b/queue-7.0/ice-fix-sma-and-u.fl-pin-state-changes-affecting-pai.patch new file mode 100644 index 0000000000..1cb389b0a2 --- /dev/null +++ b/queue-7.0/ice-fix-sma-and-u.fl-pin-state-changes-affecting-pai.patch @@ -0,0 +1,140 @@ +From 154ae3206e0d4cec69ce23af51aa221e01193493 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 22:22:20 -0700 +Subject: ice: fix SMA and U.FL pin state changes affecting paired pin + +From: Petr Oros + +[ Upstream commit 6f9d8393c9f50fbc68b9c9e99f78ca5a7b43ff44 ] + +SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and +SMA2/U.FL2) controlled by the PCA9575 GPIO expander. Each pair can +only have one active pin at a time: SMA1 output and U.FL1 output share +the same CGU output, SMA2 input and U.FL2 input share the same CGU +input. The PCA9575 register bits determine which connector in each +pair owns the signal path. + +The driver does not account for this pairing in two places: + +ice_dpll_ufl_pin_state_set() modifies PCA9575 bits and disables the +backing CGU pin without checking whether the U.FL pin is currently +active. Disconnecting an already inactive U.FL pin flips bits that +the paired SMA pin relies on, breaking its connection. + +ice_dpll_sma_direction_set() does not propagate direction changes to +the paired U.FL pin. For SMA2/U.FL2 the ICE_SMA2_UFL2_RX_DIS bit is +never managed, so U.FL2 stays disconnected after SMA2 switches to +output. For both pairs the backing CGU pin of the U.FL side is never +enabled when a direction change activates it, so userspace sees the +pin as disconnected even though the routing is correct. + +Fix by guarding the U.FL disconnect path against inactive pins and by +updating the paired U.FL pin fully on SMA direction changes: manage +ICE_SMA2_UFL2_RX_DIS for the SMA2/U.FL2 pair and enable the backing +CGU pin whenever the peer becomes active. + +Fixes: 2dd5d03c77e2 ("ice: redesign dpll sma/u.fl pins control") +Signed-off-by: Petr Oros +Tested-by: Alexander Nowlin +Reviewed-by: Arkadiusz Kubalewski +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260427-jk-iwl-net-petr-oros-fixes-v1-8-cdcb48303fd8@intel.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_dpll.c | 50 ++++++++++++++++++++++- + 1 file changed, 49 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c +index 498ec2c045f38..3f8cd5b8298b5 100644 +--- a/drivers/net/ethernet/intel/ice/ice_dpll.c ++++ b/drivers/net/ethernet/intel/ice/ice_dpll.c +@@ -1171,6 +1171,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, + enum dpll_pin_direction direction, + struct netlink_ext_ack *extack) + { ++ struct ice_dplls *d = &p->pf->dplls; ++ struct ice_dpll_pin *peer; + u8 data; + int ret; + +@@ -1189,8 +1191,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, + case ICE_DPLL_PIN_SW_2_IDX: + if (direction == DPLL_PIN_DIRECTION_INPUT) { + data &= ~ICE_SMA2_DIR_EN; ++ data |= ICE_SMA2_UFL2_RX_DIS; + } else { +- data &= ~ICE_SMA2_TX_EN; ++ data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS); + data |= ICE_SMA2_DIR_EN; + } + break; +@@ -1202,6 +1205,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, + ret = ice_dpll_pin_state_update(p->pf, p, + ICE_DPLL_PIN_TYPE_SOFTWARE, + extack); ++ if (ret) ++ return ret; ++ ++ /* When a direction change activates the paired U.FL pin, enable ++ * its backing CGU pin so the pin reports as connected. Without ++ * this the U.FL routing is correct but the CGU pin stays disabled ++ * and userspace sees the pin as disconnected. Do not disable the ++ * backing pin when U.FL becomes inactive because the SMA pin may ++ * still be using it. ++ */ ++ peer = &d->ufl[p->idx]; ++ if (peer->active) { ++ struct ice_dpll_pin *target; ++ enum ice_dpll_pin_type type; ++ ++ if (peer->output) { ++ target = peer->output; ++ type = ICE_DPLL_PIN_TYPE_OUTPUT; ++ } else { ++ target = peer->input; ++ type = ICE_DPLL_PIN_TYPE_INPUT; ++ } ++ ret = ice_dpll_pin_enable(&p->pf->hw, target, ++ d->eec.dpll_idx, type, extack); ++ if (!ret) ++ ret = ice_dpll_pin_state_update(p->pf, target, ++ type, extack); ++ } + + return ret; + } +@@ -1253,6 +1284,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + data &= ~ICE_SMA1_MASK; + enable = true; + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { ++ /* Skip if U.FL1 is not active, setting TX_EN ++ * while DIR_EN is set would also deactivate ++ * the paired SMA1 output. ++ */ ++ if (data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN)) { ++ ret = 0; ++ goto unlock; ++ } + data |= ICE_SMA1_TX_EN; + enable = false; + } else { +@@ -1267,6 +1306,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, + data &= ~ICE_SMA2_UFL2_RX_DIS; + enable = true; + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { ++ /* Skip if U.FL2 is not active, setting ++ * UFL2_RX_DIS could also disable the paired ++ * SMA2 input. ++ */ ++ if (!(data & ICE_SMA2_DIR_EN) || ++ (data & ICE_SMA2_UFL2_RX_DIS)) { ++ ret = 0; ++ goto unlock; ++ } + data |= ICE_SMA2_UFL2_RX_DIS; + enable = false; + } else { +-- +2.53.0 + diff --git a/queue-7.0/ice-fix-timestamp-interrupt-configuration-for-e825c.patch b/queue-7.0/ice-fix-timestamp-interrupt-configuration-for-e825c.patch new file mode 100644 index 0000000000..3caae5e932 --- /dev/null +++ b/queue-7.0/ice-fix-timestamp-interrupt-configuration-for-e825c.patch @@ -0,0 +1,144 @@ +From 6d1b53531d85bcc4da3e37996d272de7731584e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:25 -0700 +Subject: ice: fix timestamp interrupt configuration for E825C + +From: Grzegorz Nitka + +[ Upstream commit c0a575a801a2040eb1e0db54b488f8c548c8458a ] + +The E825C ice_phy_cfg_intr_eth56g() function is responsible for programming +the PHY interrupt for a given port. This function writes to the +PHY_REG_TS_INT_CONFIG register of the port. The register is responsible for +configuring whether the port interrupt logic is enabled, as well as +programming the threshold of waiting timestamps that will trigger an +interrupt from this port. + +This threshold value must not be programmed to zero while the interrupt is +enabled. Doing so puts the port in a misconfigured state where the PHY +timestamp interrupt for the quad of connected ports will become stuck. + +This occurs, because a threshold of zero results in the timestamp interrupt +status for the port becoming stuck high. The four ports in the connected +quad have their timestamp status indicators muxed together. A new interrupt +cannot be generated until the timestamp status indicators return low for +all four ports. + +Normally, the timestamp status for a port will clear once there are fewer +timestamps in that ports timestamp memory bank than the threshold. A +threshold of zero makes this impossible, so the timestamp status for the +port does not clear. + +The ice driver never intentionally programs the threshold to zero, indeed +the driver always programs it to a value of 1, intending to get an +interrupt immediately as soon as even a single packet is waiting for a +timestamp. + +However, there is a subtle flaw in the programming logic in the +ice_phy_cfg_intr_eth56g() function. Due to the way that the hardware +handles enabling the PHY interrupt. If the threshold value is modified at +the same time as the interrupt is enabled, the HW PHY state machine might +enable the interrupt before the new threshold value is actually updated. +This leaves a potential race condition caused by the hardware logic where +a PHY timestamp interrupt might be triggered before the non-zero threshold +is written, resulting in the PHY timestamp logic becoming stuck. + +Once the PHY timestamp status is stuck high, it will remain stuck even +after attempting to reprogram the PHY block by changing its threshold or +disabling the interrupt. Even a typical PF or CORE reset will not reset the +particular block of the PHY that becomes stuck. Even a warm power cycle is +not guaranteed to cause the PHY block to reset, and a cold power cycle is +required. + +Prevent this by always writing the PHY_REG_TS_INT_CONFIG in two stages. +First write the threshold value with the interrupt disabled, and only write +the enable bit after the threshold has been programmed. When disabling the +interrupt, leave the threshold unchanged. Additionally, re-read the +register after writing it to guarantee that the write to the PHY has been +flushed upon exit of the function. + +While we're modifying this function implementation, explicitly reject +programming a threshold of 0 when enabling the interrupt. No caller does +this today, but the consequences of doing so are significant. An explicit +rejection in the code makes this clear. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Signed-off-by: Grzegorz Nitka +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-1-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 36 ++++++++++++++++++--- + 1 file changed, 32 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 5a5c511ccbb6e..7f2f7440e705c 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -1847,6 +1847,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port) + * @ena: enable or disable interrupt + * @threshold: interrupt threshold + * ++ * The threshold cannot be 0 while the interrupt is enabled. ++ * + * Configure TX timestamp interrupt for the specified port + * + * Return: +@@ -1858,19 +1860,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold) + int err; + u32 val; + ++ if (ena && !threshold) ++ return -EINVAL; ++ + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); + if (err) + return err; + ++ val &= ~PHY_TS_INT_CONFIG_ENA_M; + if (ena) { +- val |= PHY_TS_INT_CONFIG_ENA_M; + val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M; + val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold); +- } else { +- val &= ~PHY_TS_INT_CONFIG_ENA_M; ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, ++ val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ val |= PHY_TS_INT_CONFIG_ENA_M; + } + +- return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ ++ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, ++ "Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", ++ port, !!ena, threshold); ++ return err; ++ } ++ ++ return 0; + } + + /** +-- +2.53.0 + diff --git a/queue-7.0/ice-perform-phy-soft-reset-for-e825c-ports-at-initia.patch b/queue-7.0/ice-perform-phy-soft-reset-for-e825c-ports-at-initia.patch new file mode 100644 index 0000000000..7cbdebd243 --- /dev/null +++ b/queue-7.0/ice-perform-phy-soft-reset-for-e825c-ports-at-initia.patch @@ -0,0 +1,201 @@ +From a792acd46120fc2fa5362739a01d24167c952301 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 17:51:26 -0700 +Subject: ice: perform PHY soft reset for E825C ports at initialization + +From: Grzegorz Nitka + +[ Upstream commit 3ec46e157c7fa420c77dfc23f7030e61f2f3fd55 ] + +In some cases the PHY timestamp block of the E825C can become stuck. This +is known to occur if the software writes 0 to the Tx timestamp threshold, +and with older versions of the ice driver the threshold configuration is +buggy and can race in such that hardware briefly operates with a zero +threshold enabled. There are no other known ways to trigger this behavior, +but once it occurs, the hardware is not recovered by normal reset, a driver +reload, or even a warm power cycle of the system. A cold power cycle is +sufficient to recover hardware, but this is extremely invasive and can +result in significant downtime on customer deployments. + +The PHY for each port has a timestamping block which has its own reset +functionality accessible by programming the PHY_REG_GLOBAL register. +Writing to the PHY_REG_GLOBAL_SOFT_RESET_BIT triggers the hardware to +perform a complete reset of the timestamping block of the PHY. This +includes clearing the timestamp status for the port, clearing all +outstanding timestamps in the memory bank, and resetting the PHY timer. + +The new ice_ptp_phy_soft_reset_eth56g() function toggles the +PHY_REG_GLOBAL soft reset bit with the required delays, ensuring the +PHY is properly reinitialized without requiring a full device reset. +The sequence clears the reset bit, asserts it, then clears it again, +with short waits between transitions to allow hardware stabilization. + +Call this function in the new ice_ptp_init_phc_e825c(), implementing the +E825C device specific variant of the ice_ptp_init_phc(). Note that if +ice_ptp_init_phc() fails, PTP functionality may be disabled, but the driver +will still load to allow basic functionality to continue. + +This causes the clock owning PF driver to perform a PHY soft reset for +every port during initialization. This ensures the driver begins life in a +known functional state regardless of how it was previously programmed. + +This ensures that we properly reconfigure the hardware after a device reset +or when loading the driver, even if it was previously misconfigured with an +out-of-date or modified driver. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Signed-off-by: Timothy Miskell +Signed-off-by: Grzegorz Nitka +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Petr Oros +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-2-bc2240f42251@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 90 ++++++++++++++++++++- + drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 4 + + 2 files changed, 93 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +index 7f2f7440e705c..d4c2bb084255d 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +@@ -377,6 +377,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay) + * The following functions operate on devices with the ETH 56G PHY. + */ + ++/** ++ * ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization ++ * @hw: pointer to HW struct ++ * ++ * Perform E825C-specific PTP hardware clock initialization steps. ++ * ++ * Return: 0 on success, or a negative error value on failure. ++ */ ++static int ice_ptp_init_phc_e825c(struct ice_hw *hw) ++{ ++ int err; ++ ++ /* Soft reset all ports, to ensure everything is at a clean state */ ++ for (int port = 0; port < hw->ptp.num_lports; port++) { ++ err = ice_ptp_phy_soft_reset_eth56g(hw, port); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, "Failed to soft reset port %d, err %d\n", ++ port, err); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ + /** + * ice_ptp_get_dest_dev_e825 - get destination PHY for given port number + * @hw: pointer to the HW struct +@@ -2179,6 +2204,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) + return 0; + } + ++/** ++ * ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G ++ * @hw: pointer to the HW structure ++ * @port: PHY port number ++ * ++ * Trigger a soft reset of the ETH56G PHY by toggling the soft reset ++ * bit in the PHY global register. The reset sequence consists of: ++ * 1. Clearing the soft reset bit ++ * 2. Asserting the soft reset bit ++ * 3. Clearing the soft reset bit again ++ * ++ * Short delays are inserted between each step to allow the hardware ++ * to settle. This provides a controlled way to reinitialize the PHY ++ * without requiring a full device reset. ++ * ++ * Return: 0 on success, or a negative error code on failure when ++ * reading or writing the PHY register. ++ */ ++int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port) ++{ ++ u32 global_val; ++ int err; ++ ++ err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n", ++ port, err); ++ return err; ++ } ++ ++ global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; ++ ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n", ++ port, global_val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", ++ port, err); ++ return err; ++ } ++ ++ usleep_range(5000, 6000); ++ ++ global_val |= PHY_REG_GLOBAL_SOFT_RESET_M; ++ ice_debug(hw, ICE_DBG_PTP, "Set soft reset bit for port %d, val: 0x%x\n", ++ port, global_val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); ++ if (err) { ++ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", ++ port, err); ++ return err; ++ } ++ usleep_range(5000, 6000); ++ ++ global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; ++ ice_debug(hw, ICE_DBG_PTP, "Clear soft reset bit for port %d, val: 0x%x\n", ++ port, global_val); ++ err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); ++ if (err) ++ ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", ++ port, err); ++ return err; ++} ++ + /** + * ice_get_phy_tx_tstamp_ready_eth56g - Read the Tx memory status register + * @hw: pointer to the HW struct +@@ -5592,7 +5680,7 @@ int ice_ptp_init_phc(struct ice_hw *hw) + case ICE_MAC_GENERIC: + return ice_ptp_init_phc_e82x(hw); + case ICE_MAC_GENERIC_3K_E825: +- return 0; ++ return ice_ptp_init_phc_e825c(hw); + default: + return -EOPNOTSUPP; + } +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +index 5896b346e5790..9d7acc7eb2ceb 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +@@ -374,6 +374,7 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset); + int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port); + int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold); + int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port); ++int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port); + + #define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL + #define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL +@@ -676,6 +677,9 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw) + #define ICE_P0_GNSS_PRSNT_N BIT(4) + + /* ETH56G PHY register addresses */ ++#define PHY_REG_GLOBAL 0x0 ++#define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11) ++ + /* Timestamp PHY incval registers */ + #define PHY_REG_TIMETUS_L 0x8 + #define PHY_REG_TIMETUS_U 0xC +-- +2.53.0 + diff --git a/queue-7.0/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch b/queue-7.0/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch new file mode 100644 index 0000000000..ea08545617 --- /dev/null +++ b/queue-7.0/ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch @@ -0,0 +1,86 @@ +From dd65c7e780cc176e1f25c6caf34ab6c4f5ca187c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 17:53:26 -0700 +Subject: ice: update PCS latency settings for E825 10G/25Gb modes + +From: Grzegorz Nitka + +[ Upstream commit 05567e4052732d70c7ff9655217b3d14d25f639a ] + +Update MAC Rx/Tx offset registers settings (PHY_MAC_[RX|TX]_OFFSET +registers) with the data obtained with the latest research. It applies +to PCS latency settings for the following speeds/modes: +* 10Gb NO-FEC + - TX latency changed from 71.25 ns to 73 ns + - RX latency changed from -25.6 ns to -28 ns +* 25Gb NO-FEC + - TX latency changed from 28.17 ns to 33 ns + - RX latency changed from -12.45 ns to -12 ns +* 25Gb RS-FEC + - TX latency changed from 64.5 ns to 69 ns + - RX latency changed from -3.6 ns to -3 ns + +The original data came from simulation and pre-production hardware. +The new data measures the actual delays and as such is more accurate. + +Fixes: 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products") +Co-developed-by: Zoltan Fodor +Signed-off-by: Zoltan Fodor +Reviewed-by: Aleksandr Loktionov +Reviewed-by: Jacob Keller +Signed-off-by: Grzegorz Nitka +Tested-by: Sunitha Mekala +Signed-off-by: Jacob Keller +Link: https://patch.msgid.link/20260416-iwl-net-submission-2026-04-14-v2-2-686c33c9828d@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ice/ice_ptp_consts.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +index 19dddd9b53ddd..4d298c27bfb27 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h ++++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +@@ -78,14 +78,14 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { + .blktime = 0x666, /* 3.2 */ + .tx_offset = { + .serdes = 0x234c, /* 17.6484848 */ +- .no_fec = 0x8e80, /* 71.25 */ ++ .no_fec = 0x93d9, /* 73 */ + .fc = 0xb4a4, /* 90.32 */ + .sfd = 0x4a4, /* 2.32 */ + .onestep = 0x4ccd /* 38.4 */ + }, + .rx_offset = { + .serdes = 0xffffeb27, /* -10.42424 */ +- .no_fec = 0xffffcccd, /* -25.6 */ ++ .no_fec = 0xffffc7b6, /* -28 */ + .fc = 0xfffc557b, /* -469.26 */ + .sfd = 0x4a4, /* 2.32 */ + .bs_ds = 0x32 /* 0.0969697 */ +@@ -118,17 +118,17 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { + .mktime = 0x147b, /* 10.24, only if RS-FEC enabled */ + .tx_offset = { + .serdes = 0xe1e, /* 7.0593939 */ +- .no_fec = 0x3857, /* 28.17 */ ++ .no_fec = 0x4266, /* 33 */ + .fc = 0x48c3, /* 36.38 */ +- .rs = 0x8100, /* 64.5 */ ++ .rs = 0x8a00, /* 69 */ + .sfd = 0x1dc, /* 0.93 */ + .onestep = 0x1eb8 /* 15.36 */ + }, + .rx_offset = { + .serdes = 0xfffff7a9, /* -4.1697 */ +- .no_fec = 0xffffe71a, /* -12.45 */ ++ .no_fec = 0xffffe700, /* -12 */ + .fc = 0xfffe894d, /* -187.35 */ +- .rs = 0xfffff8cd, /* -3.6 */ ++ .rs = 0xfffff8cc, /* -3 */ + .sfd = 0x1dc, /* 0.93 */ + .bs_ds = 0x14 /* 0.0387879, RS-FEC 0 */ + } +-- +2.53.0 + diff --git a/queue-7.0/ima-check-return-value-of-crypto_shash_final-in-boot.patch b/queue-7.0/ima-check-return-value-of-crypto_shash_final-in-boot.patch new file mode 100644 index 0000000000..3685111c49 --- /dev/null +++ b/queue-7.0/ima-check-return-value-of-crypto_shash_final-in-boot.patch @@ -0,0 +1,41 @@ +From f3fa665953d0126e8e267ef14f431d7920f82964 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 18:40:15 -0800 +Subject: ima: check return value of crypto_shash_final() in boot aggregate + +From: Daniel Hodges + +[ Upstream commit 870819434c8dfcc3158033b66e7851b81bb17e21 ] + +The return value of crypto_shash_final() is not checked in +ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the +function returns success and a corrupted boot aggregate digest could +be used for IMA measurements. + +Capture the return value and propagate any error to the caller. + +Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash") +Signed-off-by: Daniel Hodges +Reviewed-by: Roberto Sassu +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_crypto.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c +index aff61643415de..85c433e39c008 100644 +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -832,7 +832,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id, + } + } + if (!rc) +- crypto_shash_final(shash, digest); ++ rc = crypto_shash_final(shash, digest); + return rc; + } + +-- +2.53.0 + diff --git a/queue-7.0/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch b/queue-7.0/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch new file mode 100644 index 0000000000..2b5833bf23 --- /dev/null +++ b/queue-7.0/ima_fs-correctly-create-securityfs-files-for-unsuppo.patch @@ -0,0 +1,130 @@ +From 4fee928405331c0a273d93b54ca372f3e046b35a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 17:40:39 +0000 +Subject: ima_fs: Correctly create securityfs files for unsupported hash algos + +From: Dmitry Safonov + +[ Upstream commit d7bd8cf0b348d3edae7bee33e74a32b21668b181 ] + +ima_tpm_chip->allocated_banks[i].crypto_id is initialized to +HASH_ALGO__LAST if the TPM algorithm is not supported. However there +are places relying on the algorithm to be valid because it is accessed +by hash_algo_name[]. + +On 6.12.40 I observe the following read out-of-bounds in hash_algo_name: + ================================================================== + BUG: KASAN: global-out-of-bounds in create_securityfs_measurement_lists+0x396/0x440 + Read of size 8 at addr ffffffff83e18138 by task swapper/0/1 + + CPU: 4 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.40 #3 + Call Trace: + + dump_stack_lvl+0x61/0x90 + print_report+0xc4/0x580 + ? kasan_addr_to_slab+0x26/0x80 + ? create_securityfs_measurement_lists+0x396/0x440 + kasan_report+0xc2/0x100 + ? create_securityfs_measurement_lists+0x396/0x440 + create_securityfs_measurement_lists+0x396/0x440 + ima_fs_init+0xa3/0x300 + ima_init+0x7d/0xd0 + init_ima+0x28/0x100 + do_one_initcall+0xa6/0x3e0 + kernel_init_freeable+0x455/0x740 + kernel_init+0x24/0x1d0 + ret_from_fork+0x38/0x80 + ret_from_fork_asm+0x11/0x20 + + + The buggy address belongs to the variable: + hash_algo_name+0xb8/0x420 + + Memory state around the buggy address: + ffffffff83e18000: 00 01 f9 f9 f9 f9 f9 f9 00 01 f9 f9 f9 f9 f9 f9 + ffffffff83e18080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + >ffffffff83e18100: 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 00 05 f9 f9 + ^ + ffffffff83e18180: f9 f9 f9 f9 00 00 00 00 00 00 00 04 f9 f9 f9 f9 + ffffffff83e18200: 00 00 00 00 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9 + ================================================================== + +Seems like the TPM chip supports sha3_256, which isn't yet in +tpm_algorithms: + tpm tpm0: TPM with unsupported bank algorithm 0x0027 + +That's TPM_ALG_SHA3_256 == 0x0027 from "Trusted Platform Module 2.0 +Library Part 2: Structures", page 51 [1]. +See also the related U-Boot algorithms update [2]. + +Thus solve the problem by creating a file name with "_tpm_alg_" +postfix if the crypto algorithm isn't initialized. + +This is how it looks on the test machine (patch ported to v6.12 release): + # ls -1 /sys/kernel/security/ima/ + ascii_runtime_measurements + ascii_runtime_measurements_tpm_alg_27 + ascii_runtime_measurements_sha1 + ascii_runtime_measurements_sha256 + binary_runtime_measurements + binary_runtime_measurements_tpm_alg_27 + binary_runtime_measurements_sha1 + binary_runtime_measurements_sha256 + policy + runtime_measurements_count + violations + +[1]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-2-Version-184_pub.pdf +[2]: https://lists.denx.de/pipermail/u-boot/2024-July/558835.html + +Fixes: 9fa8e7625008 ("ima: add crypto agility support for template-hash algorithm") +Signed-off-by: Dmitry Safonov +Cc: Enrico Bravi +Cc: Silvia Sisinni +Cc: Roberto Sassu +Cc: Mimi Zohar +Reviewed-by: Roberto Sassu +Tested-by: Roberto Sassu +Link: https://github.com/linux-integrity/linux/issues/14 +Signed-off-by: Mimi Zohar +Signed-off-by: Sasha Levin +--- + security/integrity/ima/ima_fs.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c +index 012a58959ff02..f3c461ad7062b 100644 +--- a/security/integrity/ima/ima_fs.c ++++ b/security/integrity/ima/ima_fs.c +@@ -404,16 +404,24 @@ static int __init create_securityfs_measurement_lists(void) + char file_name[NAME_MAX + 1]; + struct dentry *dentry; + +- sprintf(file_name, "ascii_runtime_measurements_%s", +- hash_algo_name[algo]); ++ if (algo == HASH_ALGO__LAST) ++ sprintf(file_name, "ascii_runtime_measurements_tpm_alg_%x", ++ ima_tpm_chip->allocated_banks[i].alg_id); ++ else ++ sprintf(file_name, "ascii_runtime_measurements_%s", ++ hash_algo_name[algo]); + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP, + ima_dir, (void *)(uintptr_t)i, + &ima_ascii_measurements_ops); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + +- sprintf(file_name, "binary_runtime_measurements_%s", +- hash_algo_name[algo]); ++ if (algo == HASH_ALGO__LAST) ++ sprintf(file_name, "binary_runtime_measurements_tpm_alg_%x", ++ ima_tpm_chip->allocated_banks[i].alg_id); ++ else ++ sprintf(file_name, "binary_runtime_measurements_%s", ++ hash_algo_name[algo]); + dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP, + ima_dir, (void *)(uintptr_t)i, + &ima_measurements_ops); +-- +2.53.0 + diff --git a/queue-7.0/io_uring-napi-cap-busy_poll_to-10-msec.patch b/queue-7.0/io_uring-napi-cap-busy_poll_to-10-msec.patch new file mode 100644 index 0000000000..d22e74e808 --- /dev/null +++ b/queue-7.0/io_uring-napi-cap-busy_poll_to-10-msec.patch @@ -0,0 +1,41 @@ +From c72d2ab3194e71d5f89b88845b1b0795998bb910 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 14:42:18 -0600 +Subject: io_uring/napi: cap busy_poll_to 10 msec + +From: Jens Axboe + +[ Upstream commit df8599ee18c0e5fe343ffe0b4c379636b8bb839a ] + +Currently there's no cap on the maximum amount of time that napi is +allowed to poll if no events are found, which can lead to kernel +complaints on a task being stuck as there's no conditional rescheduling +done within that loop. + +Just cap it to 10 msec in total, that's already way above any kind of +sane value that will reap any benefits, yet low enough that it's +nowhere near being able to trigger preemption complaints. + +Fixes: 8d0c12a80cde ("io-uring: add napi busy poll support") +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/napi.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/io_uring/napi.c b/io_uring/napi.c +index 4a10de03e4269..8d68366a4b903 100644 +--- a/io_uring/napi.c ++++ b/io_uring/napi.c +@@ -276,6 +276,8 @@ static int io_napi_register_napi(struct io_ring_ctx *ctx, + /* clean the napi list for new settings */ + io_napi_free(ctx); + WRITE_ONCE(ctx->napi_track_mode, napi->op_param); ++ /* cap NAPI at 10 msec of spin time */ ++ napi->busy_poll_to = min(10000, napi->busy_poll_to); + WRITE_ONCE(ctx->napi_busy_poll_dt, napi->busy_poll_to * NSEC_PER_USEC); + WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi->prefer_busy_poll); + return 0; +-- +2.53.0 + diff --git a/queue-7.0/iommu-amd-fix-clone_alias-to-use-the-original-device.patch b/queue-7.0/iommu-amd-fix-clone_alias-to-use-the-original-device.patch new file mode 100644 index 0000000000..c5034393be --- /dev/null +++ b/queue-7.0/iommu-amd-fix-clone_alias-to-use-the-original-device.patch @@ -0,0 +1,64 @@ +From af51e3ac1d50d65ecf5269b0fc2cc6b3fb38babc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:00:17 +0000 +Subject: iommu/amd: Fix clone_alias() to use the original device's devid + +From: Vasant Hegde + +[ Upstream commit faad224fe0f0857a04ff2eb3c90f0de57f47d0f3 ] + +Currently clone_alias() assumes first argument (pdev) is always the +original device pointer. This function is called by +pci_for_each_dma_alias() which based on topology decides to send +original or alias device details in first argument. + +This meant that the source devid used to look up and copy the DTE +may be incorrect, leading to wrong or stale DTE entries being +propagated to alias device. + +Fix this by passing the original pdev as the opaque data argument to +both the direct clone_alias() call and pci_for_each_dma_alias(). Inside +clone_alias(), retrieve the original device from data and compute devid +from it. + +Fixes: 3332364e4ebc ("iommu/amd: Support multiple PCI DMA aliases in device table") +Signed-off-by: Vasant Hegde +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/iommu.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index 760d5f4623b55..6dfd942c76ce5 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -403,11 +403,12 @@ struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devid) + return NULL; + } + +-static int clone_alias(struct pci_dev *pdev, u16 alias, void *data) ++static int clone_alias(struct pci_dev *pdev_origin, u16 alias, void *data) + { + struct dev_table_entry new; + struct amd_iommu *iommu; + struct iommu_dev_data *dev_data, *alias_data; ++ struct pci_dev *pdev = data; + u16 devid = pci_dev_id(pdev); + int ret = 0; + +@@ -454,9 +455,9 @@ static void clone_aliases(struct amd_iommu *iommu, struct device *dev) + * part of the PCI DMA aliases if it's bus differs + * from the original device. + */ +- clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], NULL); ++ clone_alias(pdev, iommu->pci_seg->alias_table[pci_dev_id(pdev)], pdev); + +- pci_for_each_dma_alias(pdev, clone_alias, NULL); ++ pci_for_each_dma_alias(pdev, clone_alias, pdev); + } + + static void setup_aliases(struct amd_iommu *iommu, struct device *dev) +-- +2.53.0 + diff --git a/queue-7.0/iommu-riscv-add-iotinval-after-updating-ddt-pdt-entr.patch b/queue-7.0/iommu-riscv-add-iotinval-after-updating-ddt-pdt-entr.patch new file mode 100644 index 0000000000..7425da0af0 --- /dev/null +++ b/queue-7.0/iommu-riscv-add-iotinval-after-updating-ddt-pdt-entr.patch @@ -0,0 +1,121 @@ +From c7e15a0d336ad179c0ff621e55f01a460ffcaf1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 22:32:24 +0800 +Subject: iommu/riscv: Add IOTINVAL after updating DDT/PDT entries + +From: Fangyu Yu + +[ Upstream commit f5c262b544975e067ea265fc7403aefbbea8563e ] + +Add riscv_iommu_iodir_iotinval() to perform required TLB and context cache +invalidations after updating DDT or PDT entries, as mandated by the RISC-V +IOMMU specification (Section 6.3.1 and 6.3.2). + +Fixes: 488ffbf18171 ("iommu/riscv: Paging domain support") +Signed-off-by: Fangyu Yu +Reviewed-by: Andrew Jones +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu.c | 70 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 70 insertions(+) + +diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c +index fa2ebfd2f912e..aadfbc181138f 100644 +--- a/drivers/iommu/riscv/iommu.c ++++ b/drivers/iommu/riscv/iommu.c +@@ -996,7 +996,67 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain, + } + + #define RISCV_IOMMU_FSC_BARE 0 ++/* ++ * This function sends IOTINVAL commands as required by the RISC-V ++ * IOMMU specification (Section 6.3.1 and 6.3.2 in 1.0 spec version) ++ * after modifying DDT or PDT entries ++ */ ++static void riscv_iommu_iodir_iotinval(struct riscv_iommu_device *iommu, ++ bool inval_pdt, unsigned long iohgatp, ++ struct riscv_iommu_dc *dc, ++ struct riscv_iommu_pc *pc) ++{ ++ struct riscv_iommu_command cmd; ++ ++ riscv_iommu_cmd_inval_vma(&cmd); + ++ if (FIELD_GET(RISCV_IOMMU_DC_IOHGATP_MODE, iohgatp) == ++ RISCV_IOMMU_DC_IOHGATP_MODE_BARE) { ++ if (inval_pdt) { ++ /* ++ * IOTINVAL.VMA with GV=AV=0, and PSCV=1, and ++ * PSCID=PC.PSCID ++ */ ++ riscv_iommu_cmd_inval_set_pscid(&cmd, ++ FIELD_GET(RISCV_IOMMU_PC_TA_PSCID, pc->ta)); ++ } else { ++ if (!FIELD_GET(RISCV_IOMMU_DC_TC_PDTV, dc->tc) && ++ FIELD_GET(RISCV_IOMMU_DC_FSC_MODE, dc->fsc) != ++ RISCV_IOMMU_DC_FSC_MODE_BARE) { ++ /* ++ * DC.tc.PDTV == 0 && DC.fsc.MODE != Bare ++ * IOTINVAL.VMA with GV=AV=0, and PSCV=1, and ++ * PSCID=DC.ta.PSCID ++ */ ++ riscv_iommu_cmd_inval_set_pscid(&cmd, ++ FIELD_GET(RISCV_IOMMU_DC_TA_PSCID, dc->ta)); ++ } ++ /* else: IOTINVAL.VMA with GV=AV=PSCV=0 */ ++ } ++ } else { ++ riscv_iommu_cmd_inval_set_gscid(&cmd, ++ FIELD_GET(RISCV_IOMMU_DC_IOHGATP_GSCID, iohgatp)); ++ ++ if (inval_pdt) { ++ /* ++ * IOTINVAL.VMA with GV=1, AV=0, and PSCV=1, and ++ * GSCID=DC.iohgatp.GSCID, PSCID=PC.PSCID ++ */ ++ riscv_iommu_cmd_inval_set_pscid(&cmd, ++ FIELD_GET(RISCV_IOMMU_PC_TA_PSCID, pc->ta)); ++ } ++ /* ++ * else: IOTINVAL.VMA with GV=1,AV=PSCV=0,and ++ * GSCID=DC.iohgatp.GSCID ++ * ++ * IOTINVAL.GVMA with GV=1,AV=0,and ++ * GSCID=DC.iohgatp.GSCID ++ * TODO: For now, the Second-Stage feature have not yet been merged, ++ * also issue IOTINVAL.GVMA once second-stage support is merged. ++ */ ++ } ++ riscv_iommu_cmd_send(iommu, &cmd); ++} + /* + * Update IODIR for the device. + * +@@ -1031,6 +1091,11 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu, + riscv_iommu_cmd_iodir_inval_ddt(&cmd); + riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]); + riscv_iommu_cmd_send(iommu, &cmd); ++ /* ++ * For now, the SVA and PASID features have not yet been merged, the ++ * default configuration is inval_pdt=false and pc=NULL. ++ */ ++ riscv_iommu_iodir_iotinval(iommu, false, dc->iohgatp, dc, NULL); + sync_required = true; + } + +@@ -1056,6 +1121,11 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu, + riscv_iommu_cmd_iodir_inval_ddt(&cmd); + riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]); + riscv_iommu_cmd_send(iommu, &cmd); ++ /* ++ * For now, the SVA and PASID features have not yet been merged, the ++ * default configuration is inval_pdt=false and pc=NULL. ++ */ ++ riscv_iommu_iodir_iotinval(iommu, false, dc->iohgatp, dc, NULL); + } + + riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT); +-- +2.53.0 + diff --git a/queue-7.0/iommu-riscv-add-missing-generic_msi_irq.patch b/queue-7.0/iommu-riscv-add-missing-generic_msi_irq.patch new file mode 100644 index 0000000000..28dcee96a8 --- /dev/null +++ b/queue-7.0/iommu-riscv-add-missing-generic_msi_irq.patch @@ -0,0 +1,39 @@ +From 9aca56cc243eab6273b6bfb40d1b12547d6d058e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 11:25:40 -0400 +Subject: iommu/riscv: Add missing GENERIC_MSI_IRQ + +From: Jason Gunthorpe + +[ Upstream commit c70d20b25ca30d68b377b9363a2adca6eb2538e3 ] + +The commit below added MSI related calls to the driver that depends on +GENERIC_MSI_IRQ. It is possible to build RISC-V without this selected. + +This is also necessary to make the driver COMPILE_TEST. + +Fixes: d5f88acdd6ff ("iommu/riscv: Add support for platform msi") +Tested-by: Vincent Chen +Tested-by: Tomasz Jeznach +Signed-off-by: Jason Gunthorpe +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig +index c071816f59a67..fb8e217edc3d3 100644 +--- a/drivers/iommu/riscv/Kconfig ++++ b/drivers/iommu/riscv/Kconfig +@@ -4,6 +4,7 @@ + config RISCV_IOMMU + bool "RISC-V IOMMU Support" + depends on RISCV && 64BIT ++ depends on GENERIC_MSI_IRQ + default y + select IOMMU_API + help +-- +2.53.0 + diff --git a/queue-7.0/iommu-riscv-fix-signedness-bug.patch b/queue-7.0/iommu-riscv-fix-signedness-bug.patch new file mode 100644 index 0000000000..5038616254 --- /dev/null +++ b/queue-7.0/iommu-riscv-fix-signedness-bug.patch @@ -0,0 +1,52 @@ +From 2e66c171e763891ac0049450d0fe5e58bf1b3cc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 13:26:44 -0500 +Subject: iommu/riscv: Fix signedness bug + +From: Ethan Tidmore + +[ Upstream commit 553a127cb66523089bc10eb54640205495f4bb5b ] + +The function platform_irq_count() returns negative error codes and +iommu->irqs_count is an unsigned integer, so the check +(iommu->irqs_count <= 0) is always impossible. + +Make the return value of platform_irq_count() be assigned to ret, check +for error, and then assign iommu->irqs_count to ret. + +Detected by Smatch: +drivers/iommu/riscv/iommu-platform.c:119 riscv_iommu_platform_probe() warn: +'iommu->irqs_count' unsigned <= 0 + +Signed-off-by: Ethan Tidmore +Fixes: 5c0ebbd3c6c6 ("iommu/riscv: Add RISC-V IOMMU platform device driver") +Reviewed-by: Andrew Jones +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu-platform.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c +index 8f15b06e84997..399ba8fe1b3e5 100644 +--- a/drivers/iommu/riscv/iommu-platform.c ++++ b/drivers/iommu/riscv/iommu-platform.c +@@ -115,10 +115,13 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev) + fallthrough; + + case RISCV_IOMMU_CAPABILITIES_IGS_WSI: +- iommu->irqs_count = platform_irq_count(pdev); +- if (iommu->irqs_count <= 0) ++ ret = platform_irq_count(pdev); ++ if (ret <= 0) + return dev_err_probe(dev, -ENODEV, + "no IRQ resources provided\n"); ++ ++ iommu->irqs_count = ret; ++ + if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT) + iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; + +-- +2.53.0 + diff --git a/queue-7.0/iommu-riscv-remove-overflows-on-the-invalidation-pat.patch b/queue-7.0/iommu-riscv-remove-overflows-on-the-invalidation-pat.patch new file mode 100644 index 0000000000..2e56897516 --- /dev/null +++ b/queue-7.0/iommu-riscv-remove-overflows-on-the-invalidation-pat.patch @@ -0,0 +1,58 @@ +From f23d8358367bc92713834d4f728f3cb154e33478 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 12:22:10 -0300 +Subject: iommu/riscv: Remove overflows on the invalidation path + +From: Jason Gunthorpe + +[ Upstream commit 40a13b49957937427bc23e78eb50679df4396a47 ] + +Since RISC-V supports a sign extended page table it should support +a gather->end of ULONG_MAX, but if this happens it will infinite loop +because of the overflow. + +Also avoid overflow computing the length by moving the +1 to the other +side of the < + +Fixes: 488ffbf18171 ("iommu/riscv: Paging domain support") +Signed-off-by: Jason Gunthorpe +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c +index 6ac7e3edef8aa..3ec99c979d473 100644 +--- a/drivers/iommu/riscv/iommu.c ++++ b/drivers/iommu/riscv/iommu.c +@@ -931,8 +931,6 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain, + struct riscv_iommu_bond *bond; + struct riscv_iommu_device *iommu, *prev; + struct riscv_iommu_command cmd; +- unsigned long len = end - start + 1; +- unsigned long iova; + + /* + * For each IOMMU linked with this protection domain (via bonds->dev), +@@ -975,11 +973,14 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain, + + riscv_iommu_cmd_inval_vma(&cmd); + riscv_iommu_cmd_inval_set_pscid(&cmd, domain->pscid); +- if (len && len < RISCV_IOMMU_IOTLB_INVAL_LIMIT) { +- for (iova = start; iova < end; iova += PAGE_SIZE) { ++ if (end - start < RISCV_IOMMU_IOTLB_INVAL_LIMIT - 1) { ++ unsigned long iova = start; ++ ++ do { + riscv_iommu_cmd_inval_set_addr(&cmd, iova); + riscv_iommu_cmd_send(iommu, &cmd); +- } ++ } while (!check_add_overflow(iova, PAGE_SIZE, &iova) && ++ iova < end); + } else { + riscv_iommu_cmd_send(iommu, &cmd); + } +-- +2.53.0 + diff --git a/queue-7.0/iommu-riscv-skip-irq-count-check-when-using-msi-inte.patch b/queue-7.0/iommu-riscv-skip-irq-count-check-when-using-msi-inte.patch new file mode 100644 index 0000000000..910c26561c --- /dev/null +++ b/queue-7.0/iommu-riscv-skip-irq-count-check-when-using-msi-inte.patch @@ -0,0 +1,66 @@ +From ac9164640a4d2e3e668bd2815696a669fa38523b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 14:54:20 +0800 +Subject: iommu/riscv: Skip IRQ count check when using MSI interrupts + +From: Yaxing Guo + +[ Upstream commit 7217cee35aadbb07e12673bcf1dcf729e1b2f6c9 ] + +In RISC-V IOMMU platform devices that use MSI interrupts (indicated by the +presence of 'msi-parent' in the device tree), there are no wired interrupt +lines, so calling platform_get_irq_count() returns 0 or -ENXIO, causing the +driver to fail during probe. + +However, MSI interrupts are allocated dynamically via the MSI subsystem and +do not appear in the device tree 'interrupts' property. Therefore, the +driver should not require a non-zero IRQ count when 'msi-parent' is present. + +This patch fixes the bug where probe fails when using MSI interrupts + (which do not have an 'interrupts' property in the device tree).. + +Fixes: ("iommu/riscv: Add support for platform msi") + +Signed-off-by: Yaxing Guo +Reviewed-by: Andrew Jones +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu-platform.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c +index 83a28c83f9914..8f15b06e84997 100644 +--- a/drivers/iommu/riscv/iommu-platform.c ++++ b/drivers/iommu/riscv/iommu-platform.c +@@ -68,12 +68,7 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev) + iommu->caps = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_CAPABILITIES); + iommu->fctl = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_FCTL); + +- iommu->irqs_count = platform_irq_count(pdev); +- if (iommu->irqs_count <= 0) +- return dev_err_probe(dev, -ENODEV, +- "no IRQ resources provided\n"); +- if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT) +- iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; ++ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; + + igs = FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS, iommu->caps); + switch (igs) { +@@ -120,6 +115,13 @@ static int riscv_iommu_platform_probe(struct platform_device *pdev) + fallthrough; + + case RISCV_IOMMU_CAPABILITIES_IGS_WSI: ++ iommu->irqs_count = platform_irq_count(pdev); ++ if (iommu->irqs_count <= 0) ++ return dev_err_probe(dev, -ENODEV, ++ "no IRQ resources provided\n"); ++ if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT) ++ iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; ++ + for (vec = 0; vec < iommu->irqs_count; vec++) + iommu->irqs[vec] = platform_get_irq(pdev, vec); + +-- +2.53.0 + diff --git a/queue-7.0/iommu-riscv-stop-polling-when-cqcsr-reports-an-error.patch b/queue-7.0/iommu-riscv-stop-polling-when-cqcsr-reports-an-error.patch new file mode 100644 index 0000000000..bc2c193e20 --- /dev/null +++ b/queue-7.0/iommu-riscv-stop-polling-when-cqcsr-reports-an-error.patch @@ -0,0 +1,55 @@ +From 1a1ad5e312ef196377e2302dcc63ed871074acdf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 19:26:40 +0800 +Subject: iommu/riscv: Stop polling when CQCSR reports an error + +From: Fangyu Yu + +[ Upstream commit b2e5684558edf3e9bbe18d0e0043854994eab1be ] + +The cmdq wait loop busy-polls the consumer index until it advances +or the software timeout expires. If the IOMMU has already signaled +a command queue failure in CQCSR, continuing to poll for progress is +pointless. + +Make riscv_iommu_queue_wait() also terminate the poll when any of these +CQCSR error bits are observed. + +This helps the caller return earlier in failure cases and avoids +spinning until the full timeout interval when the hardware has already +reported an error. On single-core systems in particular, the current +busy-wait can delay servicing the command-timeout interrupt until the +software timeout expires (90s by default). + +Fixes: 856c0cfe5c5f ("iommu/riscv: Command and fault queue support") +Signed-off-by: Fangyu Yu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/riscv/iommu.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c +index aadfbc181138f..6ac7e3edef8aa 100644 +--- a/drivers/iommu/riscv/iommu.c ++++ b/drivers/iommu/riscv/iommu.c +@@ -368,6 +368,8 @@ static int riscv_iommu_queue_wait(struct riscv_iommu_queue *queue, + unsigned int timeout_us) + { + unsigned int cons = atomic_read(&queue->head); ++ unsigned int flags = RISCV_IOMMU_CQCSR_CQMF | RISCV_IOMMU_CQCSR_CMD_TO | ++ RISCV_IOMMU_CQCSR_CMD_ILL; + + /* Already processed by the consumer */ + if ((int)(cons - index) > 0) +@@ -375,6 +377,7 @@ static int riscv_iommu_queue_wait(struct riscv_iommu_queue *queue, + + /* Monitor consumer index */ + return readx_poll_timeout(riscv_iommu_queue_cons, queue, cons, ++ (riscv_iommu_readl(queue->iommu, queue->qcr) & flags) || + (int)(cons - index) > 0, 0, timeout_us); + } + +-- +2.53.0 + diff --git a/queue-7.0/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch b/queue-7.0/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch new file mode 100644 index 0000000000..fa3c89a16c --- /dev/null +++ b/queue-7.0/iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch @@ -0,0 +1,65 @@ +From 0385d0dbdd7e2dda88c85a25357b10271bc7886c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:36:34 -0700 +Subject: iommu/tegra241-cmdqv: Set supports_cmd op in tegra241_vcmdq_hw_init() + +From: Nicolin Chen + +[ Upstream commit 803e41f36d227022ab9bbe780c82283fd4713b2e ] + +vintf->hyp_own is finalized in tegra241_vintf_hw_init(). On the other hand, +tegra241_vcmdq_alloc_smmu_cmdq() is called via an init_structures callback, +which is earlier than tegra241_vintf_hw_init(). + +This results in the supports_cmd op always being set to the guest function, +although this doesn't break any functionality nor have some noticeable perf +impact since non-invalidation commands are not issued in the perf sensitive +context. + +Fix this by moving supports_cmd to tegra241_vcmdq_hw_init(). + +After this change, + - For a guest kernel, this will be a status quo + - For a host kernel, non-invalidation commands will be issued to VCMDQ(s) + +Fixes: a9d40285bdef ("iommu/tegra241-cmdqv: Limit CMDs for VCMDQs of a guest owned VINTF") +Reported-by: Eric Auger +Reported-by: Shameer Kolothum +Closes: https://lore.kernel.org/qemu-devel/CH3PR12MB754836BEE54E39B30C7210C0AB44A@CH3PR12MB7548.namprd12.prod.outlook.com/ +Signed-off-by: Nicolin Chen +Reviewed-by: Eric Auger +Tested-by: Shameer Kolothum +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +index 6fe5563eaf9eb..83f6e9f6c51d6 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c ++++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +@@ -479,6 +479,10 @@ static int tegra241_vcmdq_hw_init(struct tegra241_vcmdq *vcmdq) + /* Reset VCMDQ */ + tegra241_vcmdq_hw_deinit(vcmdq); + ++ /* vintf->hyp_own is a HW state finalized in tegra241_vintf_hw_init() */ ++ if (!vcmdq->vintf->hyp_own) ++ vcmdq->cmdq.supports_cmd = tegra241_guest_vcmdq_supports_cmd; ++ + /* Configure and enable VCMDQ */ + writeq_relaxed(vcmdq->cmdq.q.q_base, REG_VCMDQ_PAGE1(vcmdq, BASE)); + +@@ -639,9 +643,6 @@ static int tegra241_vcmdq_alloc_smmu_cmdq(struct tegra241_vcmdq *vcmdq) + q->q_base = q->base_dma & VCMDQ_ADDR; + q->q_base |= FIELD_PREP(VCMDQ_LOG2SIZE, q->llq.max_n_shift); + +- if (!vcmdq->vintf->hyp_own) +- cmdq->supports_cmd = tegra241_guest_vcmdq_supports_cmd; +- + return arm_smmu_cmdq_init(smmu, cmdq); + } + +-- +2.53.0 + diff --git a/queue-7.0/iommu-tegra241-cmdqv-update-uapi-to-clarify-hyp_own-.patch b/queue-7.0/iommu-tegra241-cmdqv-update-uapi-to-clarify-hyp_own-.patch new file mode 100644 index 0000000000..a041e25b73 --- /dev/null +++ b/queue-7.0/iommu-tegra241-cmdqv-update-uapi-to-clarify-hyp_own-.patch @@ -0,0 +1,48 @@ +From 94bc8a8624077e678db6706c06c86e96097bb564 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:36:35 -0700 +Subject: iommu/tegra241-cmdqv: Update uAPI to clarify HYP_OWN requirement + +From: Nicolin Chen + +[ Upstream commit 9dcef98dbee35b8ae784df04c041efffdd42a69c ] + +>From hardware implementation perspective, a guest tegra241-cmdqv hardware +is different than the host hardware: + - Host HW is backed by a VINTF (HYP_OWN=1) + - Guest HW is backed by a VINTF (HYP_OWN=0) + +The kernel driver has an implementation requirement of the HYP_OWN bit in +the VM. So, VMM must follow that to allow the same copy of Linux to work. + +Add this requirement to the uAPI, which is currently missing. + +Fixes: 4dc0d12474f9 ("iommu/tegra241-cmdqv: Add user-space use support") +Signed-off-by: Nicolin Chen +Reviewed-by: Eric Auger +Reviewed-by: Jason Gunthorpe +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + include/uapi/linux/iommufd.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h +index 1dafbc552d37d..f63edbe71d542 100644 +--- a/include/uapi/linux/iommufd.h ++++ b/include/uapi/linux/iommufd.h +@@ -1052,6 +1052,11 @@ struct iommu_fault_alloc { + enum iommu_viommu_type { + IOMMU_VIOMMU_TYPE_DEFAULT = 0, + IOMMU_VIOMMU_TYPE_ARM_SMMUV3 = 1, ++ /* ++ * TEGRA241_CMDQV requirements (otherwise, VCMDQs will not work) ++ * - Kernel will allocate a VINTF (HYP_OWN=0) to back this VIOMMU. So, ++ * VMM must wire the HYP_OWN bit to 0 in guest VINTF_CONFIG register ++ */ + IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2, + }; + +-- +2.53.0 + diff --git a/queue-7.0/iommufd-selftest-fix-page-leaks-in-mock_viommu_-init.patch b/queue-7.0/iommufd-selftest-fix-page-leaks-in-mock_viommu_-init.patch new file mode 100644 index 0000000000..a21e99b7c8 --- /dev/null +++ b/queue-7.0/iommufd-selftest-fix-page-leaks-in-mock_viommu_-init.patch @@ -0,0 +1,50 @@ +From 2220bfc68fd80ea14a0785eb7e0d37b1ed48dad7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:40:42 +0100 +Subject: iommufd/selftest: Fix page leaks in mock_viommu_{init,destroy} + +From: Thorsten Blum + +[ Upstream commit 09c091fddb0b93297ea659ab48ee64f54ebeeaa2 ] + +mock_viommu_init() allocates two pages using __get_free_pages(..., 1), +but its error path and mock_viommu_destroy() only release the first page +using free_page(), leaking the second page. Use free_pages() with the +matching order instead to avoid any page leaks. + +Fixes: 80478a2b450e ("iommufd/selftest: Add coverage for the new mmap interface") +Link: https://patch.msgid.link/r/20260312164040.457293-3-thorsten.blum@linux.dev +Signed-off-by: Thorsten Blum +Reviewed-by: Nicolin Chen +Reviewed-by: Pranjal Shrivastava +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommufd/selftest.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c +index 7823142097d47..83e2215e7800d 100644 +--- a/drivers/iommu/iommufd/selftest.c ++++ b/drivers/iommu/iommufd/selftest.c +@@ -636,7 +636,7 @@ static void mock_viommu_destroy(struct iommufd_viommu *viommu) + if (mock_viommu->mmap_offset) + iommufd_viommu_destroy_mmap(&mock_viommu->core, + mock_viommu->mmap_offset); +- free_page((unsigned long)mock_viommu->page); ++ free_pages((unsigned long)mock_viommu->page, 1); + mutex_destroy(&mock_viommu->queue_mutex); + + /* iommufd core frees mock_viommu and viommu */ +@@ -870,7 +870,7 @@ static int mock_viommu_init(struct iommufd_viommu *viommu, + iommufd_viommu_destroy_mmap(&mock_viommu->core, + mock_viommu->mmap_offset); + err_free_page: +- free_page((unsigned long)mock_viommu->page); ++ free_pages((unsigned long)mock_viommu->page, 1); + return rc; + } + +-- +2.53.0 + diff --git a/queue-7.0/iommufd-vfio-compatibility-extension-check-for-noiom.patch b/queue-7.0/iommufd-vfio-compatibility-extension-check-for-noiom.patch new file mode 100644 index 0000000000..ff5e999f2b --- /dev/null +++ b/queue-7.0/iommufd-vfio-compatibility-extension-check-for-noiom.patch @@ -0,0 +1,40 @@ +From efba7c56a54efb2b84ddb1e44529aaebc64c4e0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 10:36:36 -0800 +Subject: iommufd: vfio compatibility extension check for noiommu mode + +From: Jacob Pan + +[ Upstream commit 7147ec874ea08c322d779d8eba28946e294ed1f3 ] + +VFIO_CHECK_EXTENSION should return false for TYPE1_IOMMU variants when +in NO-IOMMU mode and IOMMUFD compat container is set. This change makes +the behavior match VFIO_CONTAINER in noiommu mode. It also prevents +userspace from incorrectly attempting to use TYPE1 IOMMU operations +in a no-iommu context. + +Fixes: d624d6652a65 ("iommufd: vfio container FD ioctl compatibility") +Link: https://patch.msgid.link/r/20260213183636.3340-1-jacob.pan@linux.microsoft.com +Signed-off-by: Jacob Pan +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommufd/vfio_compat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c +index a258ee2f4579f..acb48cdd3b005 100644 +--- a/drivers/iommu/iommufd/vfio_compat.c ++++ b/drivers/iommu/iommufd/vfio_compat.c +@@ -283,7 +283,7 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx, + case VFIO_TYPE1_IOMMU: + case VFIO_TYPE1v2_IOMMU: + case VFIO_UNMAP_ALL: +- return 1; ++ return !ictx->no_iommu_mode; + + case VFIO_NOIOMMU_IOMMU: + return IS_ENABLED(CONFIG_VFIO_NOIOMMU); +-- +2.53.0 + diff --git a/queue-7.0/iopoll-fix-function-parameter-names-in-read_poll_tim.patch b/queue-7.0/iopoll-fix-function-parameter-names-in-read_poll_tim.patch new file mode 100644 index 0000000000..c4bcebd1c9 --- /dev/null +++ b/queue-7.0/iopoll-fix-function-parameter-names-in-read_poll_tim.patch @@ -0,0 +1,56 @@ +From cf0cfebe8e911a2cad2b48e2a97d8b3cb27c7fc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 14:10:32 -0800 +Subject: iopoll: fix function parameter names in read_poll_timeout_atomic() + +From: Randy Dunlap + +[ Upstream commit 878004e2852bc22ce0687c5597d6fe3909fb59f3 ] + +Correct the function parameter names to avoid kernel-doc warnings +and to emphasize this function is atomic (non-sleeping). + +Warning: include/linux/iopoll.h:169 function parameter 'sleep_us' not + described in 'read_poll_timeout_atomic' +Warning: ../include/linux/iopoll.h:169 function parameter + 'sleep_before_read' not described in 'read_poll_timeout_atomic' + +Fixes: 9df8043a546d ("iopoll: Generalize read_poll_timeout() into poll_timeout_us()") +Signed-off-by: Randy Dunlap +Reviewed-by: Jani Nikula +Link: https://patch.msgid.link/20260306221033.2357305-1-rdunlap@infradead.org +Signed-off-by: Jani Nikula +Signed-off-by: Sasha Levin +--- + include/linux/iopoll.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h +index bdd2e0652bc30..53edd69acb9bd 100644 +--- a/include/linux/iopoll.h ++++ b/include/linux/iopoll.h +@@ -159,7 +159,7 @@ + * + * This macro does not rely on timekeeping. Hence it is safe to call even when + * timekeeping is suspended, at the expense of an underestimation of wall clock +- * time, which is rather minimal with a non-zero delay_us. ++ * time, which is rather minimal with a non-zero @delay_us. + * + * When available, you'll probably want to use one of the specialized + * macros defined below rather than this macro directly. +@@ -167,9 +167,9 @@ + * Returns: 0 on success and -ETIMEDOUT upon a timeout. In either + * case, the last read value at @args is stored in @val. + */ +-#define read_poll_timeout_atomic(op, val, cond, sleep_us, timeout_us, \ +- sleep_before_read, args...) \ +- poll_timeout_us_atomic((val) = op(args), cond, sleep_us, timeout_us, sleep_before_read) ++#define read_poll_timeout_atomic(op, val, cond, delay_us, timeout_us, \ ++ delay_before_read, args...) \ ++ poll_timeout_us_atomic((val) = op(args), cond, delay_us, timeout_us, delay_before_read) + + /** + * readx_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs +-- +2.53.0 + diff --git a/queue-7.0/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch b/queue-7.0/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch new file mode 100644 index 0000000000..76c0070a7b --- /dev/null +++ b/queue-7.0/ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch @@ -0,0 +1,114 @@ +From 32eb219d0995e1896ad94045dd1165dc2c5fded5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:06:01 +0800 +Subject: ipmi: ssif_bmc: change log level to dbg in irq callback + +From: Jian Zhang + +[ Upstream commit c9c99b7b7051eb7121b3224bfce181fb023b0269 ] + +Long-running tests indicate that this logging can occasionally disrupt +timing and lead to request/response corruption. + +Irq handler need to be executed as fast as possible, +most I2C slave IRQ implementations are byte-level, logging here +can significantly affect transfer behavior and timing. It is recommended +to use dev_dbg() for these messages. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-4-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index ca185793cf978..a45e80d13e10e 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -569,7 +569,7 @@ static void process_request_part(struct ssif_bmc_ctx *ssif_bmc) + len = ssif_bmc->request.len + part->length; + /* Do the bound check here, not allow the request len exceed 254 bytes */ + if (len > IPMI_SSIF_PAYLOAD_MAX) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: Request exceeded 254 bytes, aborting"); + /* Request too long, aborting */ + ssif_bmc->aborting = true; +@@ -615,7 +615,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected READ REQUESTED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -624,7 +624,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + if (!supported_read_cmd(ssif_bmc->part_buf.smbus_cmd)) { +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", + ssif_bmc->part_buf.smbus_cmd); + ssif_bmc->aborting = true; + } +@@ -659,7 +659,7 @@ static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_SMBUS_CMD) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected READ PROCESSED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -684,7 +684,7 @@ static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + } else if (ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE REQUEST in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -699,7 +699,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + { + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_RES_SENDING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_ABORTING; +@@ -709,7 +709,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + if (!supported_write_cmd(ssif_bmc->part_buf.smbus_cmd)) { +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", + ssif_bmc->part_buf.smbus_cmd); + ssif_bmc->aborting = true; + } +@@ -738,7 +738,7 @@ static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_SMBUS_CMD || + ssif_bmc->state == SSIF_ABORTING) { +- dev_warn(&ssif_bmc->client->dev, ++ dev_dbg(&ssif_bmc->client->dev, + "Warn: %s unexpected SLAVE STOP in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_READY; +@@ -805,7 +805,7 @@ static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 + break; + + default: +- dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); ++ dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); + break; + } + +-- +2.53.0 + diff --git a/queue-7.0/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch b/queue-7.0/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch new file mode 100644 index 0000000000..53fa41892e --- /dev/null +++ b/queue-7.0/ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch @@ -0,0 +1,88 @@ +From b0b631e996f1ca53347ce2d4abc363761df716e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:06:00 +0800 +Subject: ipmi: ssif_bmc: fix message desynchronization after truncated + response + +From: Jian Zhang + +[ Upstream commit 1d38e849adb6851ee280aa1a1d687b2181549a66 ] + +A truncated response, caused by host power-off, or other conditions, +can lead to message desynchronization. + +Raw trace data (STOP loss scenario, add state transition comment): + +1. T-1: Read response phase (SSIF_RES_SENDING) +8271.955342 WR_RCV [03] <- Read polling cmd +8271.955348 RD_REQ [04] <== SSIF_RES_SENDING <- start sending response +8271.955436 RD_PRO [b4] +8271.955527 RD_PRO [00] +8271.955618 RD_PRO [c1] +8271.955707 RD_PRO [00] +8271.955814 RD_PRO [ad] <== SSIF_RES_SENDING <- last byte + <- !! STOP lost (truncated response) + +2. T: New Write request arrives, BMC still in SSIF_RES_SENDING +8271.967973 WR_REQ [] <== SSIF_RES_SENDING >> SSIF_ABORTING <- log: unexpected WR_REQ in RES_SENDING +8271.968447 WR_RCV [02] <== SSIF_ABORTING <- do nothing +8271.968452 WR_RCV [02] <== SSIF_ABORTING <- do nothing +8271.968454 WR_RCV [18] <== SSIF_ABORTING <- do nothing +8271.968456 WR_RCV [01] <== SSIF_ABORTING <- do nothing +8271.968458 WR_RCV [66] <== SSIF_ABORTING <- do nothing +8271.978714 STOP [] <== SSIF_ABORTING >> SSIF_READY <- log: unexpected SLAVE STOP in state=SSIF_ABORTING + +3. T+1: Next Read polling, treated as a fresh transaction +8271.979125 WR_REQ [] <== SSIF_READY >> SSIF_START +8271.979326 WR_RCV [03] <== SSIF_START >> SSIF_SMBUS_CMD <- smbus_cmd=0x03 +8271.979331 RD_REQ [04] <== SSIF_RES_SENDING <- sending response +8271.979427 RD_PRO [b4] <- !! this is T's stale response -> desynchronization + +When in SSIF_ABORTING state, a newly arrived command should still be +handled to avoid dropping the request or causing message +desynchronization. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-3-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index 6cc5c210799ca..ca185793cf978 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -458,6 +458,15 @@ static bool supported_write_cmd(u8 cmd) + return false; + } + ++static bool supported_write_start_cmd(u8 cmd) ++{ ++ if (cmd == SSIF_IPMI_SINGLEPART_WRITE || ++ cmd == SSIF_IPMI_MULTIPART_WRITE_START) ++ return true; ++ ++ return false; ++} ++ + /* Process the IPMI response that will be read by master */ + static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + { +@@ -709,6 +718,11 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) + ssif_bmc->state = SSIF_ABORTING; + else + ssif_bmc->state = SSIF_REQ_RECVING; ++ } else if (ssif_bmc->state == SSIF_ABORTING) { ++ if (supported_write_start_cmd(*val)) { ++ ssif_bmc->state = SSIF_SMBUS_CMD; ++ ssif_bmc->aborting = false; ++ } + } + + /* This is response sending state */ +-- +2.53.0 + diff --git a/queue-7.0/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch b/queue-7.0/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch new file mode 100644 index 0000000000..dd6b849d30 --- /dev/null +++ b/queue-7.0/ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch @@ -0,0 +1,42 @@ +From 4497fac28b57b7f55ba0bde63a67e7bc15151412 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 17:05:59 +0800 +Subject: ipmi: ssif_bmc: fix missing check for copy_to_user() partial failure + +From: Jian Zhang + +[ Upstream commit ea641be7a4faee4351f9c5ed6b188e1bbf5586a6 ] + +copy_to_user() returns the number of bytes that could not be copied, +with a non-zero value indicating a partial or complete failure. The +current code only checks for negative return values and treats all +non-negative results as success. + +Treating any positive return value from copy_to_user() as +an error and returning -EFAULT. + +Fixes: dd2bc5cc9e25 ("ipmi: ssif_bmc: Add SSIF BMC driver") +Signed-off-by: Jian Zhang +Message-ID: <20260403090603.3988423-2-zhangjian.3032@bytedance.com> +Signed-off-by: Corey Minyard +Signed-off-by: Sasha Levin +--- + drivers/char/ipmi/ssif_bmc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c +index 7a52e3ea49ed8..6cc5c210799ca 100644 +--- a/drivers/char/ipmi/ssif_bmc.c ++++ b/drivers/char/ipmi/ssif_bmc.c +@@ -163,6 +163,8 @@ static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + ret = copy_to_user(buf, &msg, count); ++ if (ret > 0) ++ ret = -EFAULT; + } + + return (ret < 0) ? ret : count; +-- +2.53.0 + diff --git a/queue-7.0/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch b/queue-7.0/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch new file mode 100644 index 0000000000..0468c4e4f2 --- /dev/null +++ b/queue-7.0/ipv6-fix-possible-uaf-in-icmpv6_rcv.patch @@ -0,0 +1,71 @@ +From 2a90993c51bd8448bcca13e26e075c52e36fc0f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 10:35:05 +0000 +Subject: ipv6: fix possible UAF in icmpv6_rcv() + +From: Eric Dumazet + +[ Upstream commit f996edd7615e686ada141b7f3395025729ff8ccb ] + +Caching saddr and daddr before pskb_pull() is problematic +since skb->head can change. + +Remove these temporary variables: + +- We only access &ipv6_hdr(skb)->saddr and &ipv6_hdr(skb)->daddr + when net_dbg_ratelimited() is called in the slow path. + +- Avoid potential future misuse after pskb_pull() call. + +Fixes: 4b3418fba0fe ("ipv6: icmp: include addresses in debug messages") +Signed-off-by: Eric Dumazet +Reviewed-by: Fernando Fernandez Mancera +Reviewed-by: Joe Damato +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260416103505.2380753-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/icmp.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index d5d23a9296eac..88356cbfb68b1 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -1104,7 +1104,6 @@ static int icmpv6_rcv(struct sk_buff *skb) + struct net *net = dev_net_rcu(skb->dev); + struct net_device *dev = icmp6_dev(skb); + struct inet6_dev *idev = __in6_dev_get(dev); +- const struct in6_addr *saddr, *daddr; + struct icmp6hdr *hdr; + u8 type; + +@@ -1135,12 +1134,10 @@ static int icmpv6_rcv(struct sk_buff *skb) + + __ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS); + +- saddr = &ipv6_hdr(skb)->saddr; +- daddr = &ipv6_hdr(skb)->daddr; +- + if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { + net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + goto csum_error; + } + +@@ -1220,7 +1217,8 @@ static int icmpv6_rcv(struct sk_buff *skb) + break; + + net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", +- saddr, daddr); ++ &ipv6_hdr(skb)->saddr, ++ &ipv6_hdr(skb)->daddr); + + /* + * error of unknown type. +-- +2.53.0 + diff --git a/queue-7.0/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch b/queue-7.0/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch new file mode 100644 index 0000000000..8798bdbe3f --- /dev/null +++ b/queue-7.0/ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch @@ -0,0 +1,97 @@ +From 6d437638d5dc1d9410bae9861276b945f333b7bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:40:29 +0800 +Subject: ipvs: fix MTU check for GSO packets in tunnel mode + +From: Yingnan Zhang <342144303@qq.com> + +[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ] + +Currently, IPVS skips MTU checks for GSO packets by excluding them with +the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel +mode encapsulates GSO packets with IPIP headers. + +The issue manifests in two ways: + +1. MTU violation after encapsulation: + When a GSO packet passes through IPVS tunnel mode, the original MTU + check is bypassed. After adding the IPIP tunnel header, the packet + size may exceed the outgoing interface MTU, leading to unexpected + fragmentation at the IP layer. + +2. Fragmentation with problematic IP IDs: + When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments + is fragmented after encapsulation, each segment gets a sequentially + incremented IP ID (0, 1, 2, ...). This happens because: + + a) The GSO packet bypasses MTU check and gets encapsulated + b) At __ip_finish_output, the oversized GSO packet is split into + separate SKBs (one per segment), with IP IDs incrementing + c) Each SKB is then fragmented again based on the actual MTU + + This sequential IP ID allocation differs from the expected behavior + and can cause issues with fragment reassembly and packet tracking. + +Fix this by properly validating GSO packets using +skb_gso_validate_network_len(). This function correctly validates +whether the GSO segments will fit within the MTU after segmentation. If +validation fails, send an ICMP Fragmentation Needed message to enable +proper PMTU discovery. + +Fixes: 4cdd34084d53 ("netfilter: nf_conntrack_ipv6: improve fragmentation handling") +Signed-off-by: Yingnan Zhang <342144303@qq.com> +Acked-by: Julian Anastasov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index 3601eb86d0250..7c570f48ade28 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -102,6 +102,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest) + return dest_dst; + } + ++/* Based on ip_exceeds_mtu(). */ ++static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) ++{ ++ if (skb->len <= mtu) ++ return false; ++ ++ if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu)) ++ return false; ++ ++ return true; ++} ++ + static inline bool + __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + { +@@ -111,10 +123,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) + */ + if (IP6CB(skb)->frag_max_size > mtu) + return true; /* largest fragment violate MTU */ +- } +- else if (skb->len > mtu && !skb_is_gso(skb)) { ++ } else if (ip_vs_exceeds_mtu(skb, mtu)) + return true; /* Packet size violate MTU size */ +- } ++ + return false; + } + +@@ -232,7 +243,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, + return true; + + if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && +- skb->len > mtu && !skb_is_gso(skb) && ++ ip_vs_exceeds_mtu(skb, mtu) && + !ip_vs_iph_icmp(ipvsh))) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); +-- +2.53.0 + diff --git a/queue-7.0/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch b/queue-7.0/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch new file mode 100644 index 0000000000..fbbbd3d7ad --- /dev/null +++ b/queue-7.0/irqchip-irq-pic32-evic-address-warning-related-to-wr.patch @@ -0,0 +1,48 @@ +From 975ab3e6fa625c4e5626c058b212ef83857dc8cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Feb 2026 18:43:44 -0500 +Subject: irqchip/irq-pic32-evic: Address warning related to wrong printf() + formatter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Brian Masney + +[ Upstream commit 86be659415b0ddefebc3120e309091aa215a9064 ] + +This driver is currently only build on 32 bit MIPS systems. When building +it on x86_64, the following warning occurs: + + drivers/irqchip/irq-pic32-evic.c: In function ‘pic32_ext_irq_of_init’: + ./include/linux/kern_levels.h:5:25: error: format ‘%d’ expects argument of type + ‘int’, but argument 2 has type ‘long unsigned int’ [-Werror=format=] + +Update the printf() formatter in preparation for allowing this driver to +be compiled on all architectures. + +Fixes: aaa8666ada780 ("IRQCHIP: irq-pic32-evic: Add support for PIC32 interrupt controller") +Signed-off-by: Brian Masney +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260222-irqchip-pic32-v1-1-37f50d1f14af@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-pic32-evic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-pic32-evic.c b/drivers/irqchip/irq-pic32-evic.c +index e85c3e3007018..325b97a0287f6 100644 +--- a/drivers/irqchip/irq-pic32-evic.c ++++ b/drivers/irqchip/irq-pic32-evic.c +@@ -196,7 +196,7 @@ static void __init pic32_ext_irq_of_init(struct irq_domain *domain) + + of_property_for_each_u32(node, pname, hwirq) { + if (i >= ARRAY_SIZE(priv->ext_irqs)) { +- pr_warn("More than %d external irq, skip rest\n", ++ pr_warn("More than %zu external irq, skip rest\n", + ARRAY_SIZE(priv->ext_irqs)); + break; + } +-- +2.53.0 + diff --git a/queue-7.0/irqchip-renesas-rzg2l-fix-error-path-in-rzg2l_irqc_c.patch b/queue-7.0/irqchip-renesas-rzg2l-fix-error-path-in-rzg2l_irqc_c.patch new file mode 100644 index 0000000000..f9b9925652 --- /dev/null +++ b/queue-7.0/irqchip-renesas-rzg2l-fix-error-path-in-rzg2l_irqc_c.patch @@ -0,0 +1,41 @@ +From f19f26a9a30c946f67bfeb4aae124dadc879fbad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 19:24:18 +0000 +Subject: irqchip/renesas-rzg2l: Fix error path in rzg2l_irqc_common_probe() + +From: Biju Das + +[ Upstream commit fb74e35f78105efd8635c89b39f4389f567edbdc ] + +Replace pm_runtime_put() with pm_runtime_put_sync() when +irq_domain_create_hierarchy() fails to ensure the device suspends +synchronously before devres cleanup disables runtime PM via +pm_runtime_disable(). + +[ tglx: Fix up subject and change log to be precise ] + +Fixes: 7de11369ef30 ("irqchip/renesas-rzg2l: Use devm_pm_runtime_enable()") +Signed-off-by: Biju Das +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260325192451.172562-4-biju.das.jz@bp.renesas.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-renesas-rzg2l.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c +index e73d426cea6d3..eb01d4c5aca75 100644 +--- a/drivers/irqchip/irq-renesas-rzg2l.c ++++ b/drivers/irqchip/irq-renesas-rzg2l.c +@@ -577,7 +577,7 @@ static int rzg2l_irqc_common_probe(struct platform_device *pdev, struct device_n + irq_domain = irq_domain_create_hierarchy(parent_domain, 0, IRQC_NUM_IRQ, dev_fwnode(dev), + &rzg2l_irqc_domain_ops, rzg2l_irqc_data); + if (!irq_domain) { +- pm_runtime_put(dev); ++ pm_runtime_put_sync(dev); + return -ENOMEM; + } + +-- +2.53.0 + diff --git a/queue-7.0/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch b/queue-7.0/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch new file mode 100644 index 0000000000..fe74d40e73 --- /dev/null +++ b/queue-7.0/kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch @@ -0,0 +1,57 @@ +From 72bacc89e031c9e595cadecf73a616624c5ed786 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 16:51:16 +0200 +Subject: kbuild: builddeb - avoid recompiles for non-cross-compiles + +From: Mathias Krause + +[ Upstream commit 2452dcf4d740effff5aa71b7f6529ee8c04fd8f6 ] + +Commit e2c318225ac1 ("kbuild: deb-pkg: add +pkg.linux-upstream.nokernelheaders build profile") changed how +install-extmod-build gets called, making it always rebuild the host +programs below scripts/ if HOSTCC wasn't specified with its full triplet +on the make command line. That is, apparently, needed to fix up commit +f1d87664b82a ("kbuild: cross-compile linux-headers package when +possible") for cross-compiles. However, in the much more common case of +non-cross-compile builds this will lead to unnecessary rebuilding of +host tools including gcc plugins. This, in turn, will lead to a full +kernel rebuild on the next 'make bindeb-pkg' which is unfortunate. + +Avoid that by only triggering the rebuild of host tools for actual +cross-compile builds. + +Signed-off-by: Mathias Krause +Fixes: e2c318225ac1 ("kbuild: deb-pkg: add pkg.linux-upstream.nokernelheaders build profile") +Cc: Masahiro Yamada +Reviewed-by: Nathan Chancellor +Reviewed-by: Nicolas Schier +Link: https://patch.msgid.link/20260402145116.1010901-1-minipli@grsecurity.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + scripts/package/builddeb | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/scripts/package/builddeb b/scripts/package/builddeb +index 3627ca227e5a5..ba1defc616524 100755 +--- a/scripts/package/builddeb ++++ b/scripts/package/builddeb +@@ -139,7 +139,13 @@ install_kernel_headers () { + pdir=debian/$1 + version=${1#linux-headers-} + +- CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ # Override $CC only for cross-compiles, to not unnecessarily rebuild ++ # scripts/ including plugins, which may lead to a full kernel rebuild. ++ if [ -n "${CROSS_COMPILE}" ]; then ++ CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ else ++ "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" ++ fi + + mkdir -p $pdir/lib/modules/$version/ + ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build +-- +2.53.0 + diff --git a/queue-7.0/kbuild-never-respect-config_werror-w-e-to-fixdep.patch b/queue-7.0/kbuild-never-respect-config_werror-w-e-to-fixdep.patch new file mode 100644 index 0000000000..c97d43abfe --- /dev/null +++ b/queue-7.0/kbuild-never-respect-config_werror-w-e-to-fixdep.patch @@ -0,0 +1,60 @@ +From dc09a12cc5bf8b74e7e3aec8b8df8433655adceb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 17:10:27 +0200 +Subject: kbuild: Never respect CONFIG_WERROR / W=e to fixdep +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 75f7c47ccd78c947cf1b6ddb18ea453ff0555716 ] + +The fixdep hostprog may be built multiple times during a single build. +Once during the configuration phase and later during the regular phase. +As only the regular build phase respects CONFIG_WERROR / W=e, the +compiler flags might change between the phases, leading to rebuilds. + +Example, the rebuilds will happen twice on each invocation of the build: + + $ make allyesconfig prepare + make[1]: Entering directory '/tmp/deleteme' + HOSTCC scripts/basic/fixdep + # + # No change to .config + # + HOSTCC scripts/basic/fixdep + DESCEND objtool + INSTALL libsubcmd_headers + make[1]: Leaving directory '/tmp/deleteme' + +Fix the compilation flags used for scripts/basic/ before +scripts/Makefile.warn is evaluated to stop CONFIG_WERROR / W=e +influencing the fixdep build to avoid the spurious rebuilds. + +Fixes: 7ded7d37e5f5 ("scripts/Makefile.extrawarn: Respect CONFIG_WERROR / W=e for hostprogs") +Signed-off-by: Thomas Weißschuh +Reviewed-by: Nathan Chancellor +Link: https://patch.msgid.link/20260422-kbuild-scripts-basic-werror-v1-1-8c6912ff22e0@weissschuh.net +Signed-off-by: Nicolas Schier +Signed-off-by: Sasha Levin +--- + Makefile | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Makefile b/Makefile +index 9da9c1f3b2382..1e646735a8cc2 100644 +--- a/Makefile ++++ b/Makefile +@@ -658,6 +658,8 @@ export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ + + # Basic helpers built in scripts/basic/ + PHONY += scripts_basic ++scripts_basic: KBUILD_HOSTCFLAGS := $(KBUILD_HOSTCFLAGS) ++scripts_basic: KBUILD_HOSTLDFLAGS := $(KBUILD_HOSTLDFLAGS) + scripts_basic: + $(Q)$(MAKE) $(build)=scripts/basic + +-- +2.53.0 + diff --git a/queue-7.0/kho-fix-kasan-support-for-restored-vmalloc-regions.patch b/queue-7.0/kho-fix-kasan-support-for-restored-vmalloc-regions.patch new file mode 100644 index 0000000000..e0cbf77cfa --- /dev/null +++ b/queue-7.0/kho-fix-kasan-support-for-restored-vmalloc-regions.patch @@ -0,0 +1,84 @@ +From c92c186ff7ca8864404c7b488e8f0481cf27fbfb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 17:38:57 -0500 +Subject: kho: fix KASAN support for restored vmalloc regions + +From: Pasha Tatashin + +[ Upstream commit 019fc36872374db6fd35e118c9e935374404bfbf ] + +Restored vmalloc regions are currently not properly marked for KASAN, +causing KASAN to treat accesses to these regions as out-of-bounds. + +Fix this by properly unpoisoning the restored vmalloc area using +kasan_unpoison_vmalloc(). This requires setting the VM_UNINITIALIZED flag +during the initial area allocation and clearing it after the pages have +been mapped and unpoisoned, using the clear_vm_uninitialized_flag() +helper. + +Link: https://lkml.kernel.org/r/20260225223857.1714801-3-pasha.tatashin@soleen.com +Fixes: a667300bd53f ("kho: add support for preserving vmalloc allocations") +Signed-off-by: Pasha Tatashin +Reported-by: Pratyush Yadav +Reviewed-by: Pratyush Yadav (Google) +Tested-by: Pratyush Yadav (Google) +Cc: Alexander Graf +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Suren Baghdasaryan +Cc: "Uladzislau Rezki (Sony)" +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/liveupdate/kexec_handover.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c +index 479c42e08b74a..1ed8913c5e2c0 100644 +--- a/kernel/liveupdate/kexec_handover.c ++++ b/kernel/liveupdate/kexec_handover.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1082,6 +1083,7 @@ EXPORT_SYMBOL_GPL(kho_unpreserve_vmalloc); + void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) + { + struct kho_vmalloc_chunk *chunk = KHOSER_LOAD_PTR(preservation->first); ++ kasan_vmalloc_flags_t kasan_flags = KASAN_VMALLOC_PROT_NORMAL; + unsigned int align, order, shift, vm_flags; + unsigned long total_pages, contig_pages; + unsigned long addr, size; +@@ -1133,7 +1135,8 @@ void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) + goto err_free_pages_array; + + area = __get_vm_area_node(total_pages * PAGE_SIZE, align, shift, +- vm_flags, VMALLOC_START, VMALLOC_END, ++ vm_flags | VM_UNINITIALIZED, ++ VMALLOC_START, VMALLOC_END, + NUMA_NO_NODE, GFP_KERNEL, + __builtin_return_address(0)); + if (!area) +@@ -1148,6 +1151,13 @@ void *kho_restore_vmalloc(const struct kho_vmalloc *preservation) + area->nr_pages = total_pages; + area->pages = pages; + ++ if (vm_flags & VM_ALLOC) ++ kasan_flags |= KASAN_VMALLOC_VM_ALLOC; ++ ++ area->addr = kasan_unpoison_vmalloc(area->addr, total_pages * PAGE_SIZE, ++ kasan_flags); ++ clear_vm_uninitialized_flag(area); ++ + return area->addr; + + err_free_vm_area: +-- +2.53.0 + diff --git a/queue-7.0/kselftest-arm64-include-asm-ptrace.h-for-user_gcs-de.patch b/queue-7.0/kselftest-arm64-include-asm-ptrace.h-for-user_gcs-de.patch new file mode 100644 index 0000000000..d0ef7e440e --- /dev/null +++ b/queue-7.0/kselftest-arm64-include-asm-ptrace.h-for-user_gcs-de.patch @@ -0,0 +1,60 @@ +From c9a7dc11af59f475d0d7308a55e80079ab14e974 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 15:30:10 +0100 +Subject: kselftest/arm64: Include for user_gcs definition + +From: Leo Yan + +[ Upstream commit bb7235e226888607e6aac1288062fcb1ac105589 ] + +kselftest includes kernel uAPI headers with option: + + -isystem $(top_srcdir)/usr/include + +Include in libc-gcs.c for the definition of struct +user_gcs from the uAPI headers, and remove the redundant definition in +gcs-util.h. This fixes a compilation error on systems where the +toolchain defines NT_ARM_GCS. + +Fixes: a505a52b4e29 ("kselftest/arm64: Add a GCS test program built with the system libc") +Signed-off-by: Leo Yan +Reviewed-by: Mark Brown +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/arm64/gcs/gcs-util.h | 6 ------ + tools/testing/selftests/arm64/gcs/libc-gcs.c | 1 + + 2 files changed, 1 insertion(+), 6 deletions(-) + +diff --git a/tools/testing/selftests/arm64/gcs/gcs-util.h b/tools/testing/selftests/arm64/gcs/gcs-util.h +index c99a6b39ac147..7a81bb07ed4b8 100644 +--- a/tools/testing/selftests/arm64/gcs/gcs-util.h ++++ b/tools/testing/selftests/arm64/gcs/gcs-util.h +@@ -18,12 +18,6 @@ + + #ifndef NT_ARM_GCS + #define NT_ARM_GCS 0x410 +- +-struct user_gcs { +- __u64 features_enabled; +- __u64 features_locked; +- __u64 gcspr_el0; +-}; + #endif + + /* Shadow Stack/Guarded Control Stack interface */ +diff --git a/tools/testing/selftests/arm64/gcs/libc-gcs.c b/tools/testing/selftests/arm64/gcs/libc-gcs.c +index 17b2fabfec386..72e82bfbecc99 100644 +--- a/tools/testing/selftests/arm64/gcs/libc-gcs.c ++++ b/tools/testing/selftests/arm64/gcs/libc-gcs.c +@@ -16,6 +16,7 @@ + + #include + #include ++#include + + #include + +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch b/queue-7.0/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch new file mode 100644 index 0000000000..f60e28172e --- /dev/null +++ b/queue-7.0/ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch @@ -0,0 +1,54 @@ +From ec24312818772798f6149c409b197cb10ab21fe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:55 +0900 +Subject: ksmbd: destroy async_ida in ksmbd_conn_free() + +From: DaeMyung Kang + +[ Upstream commit b32c8db48212a34998c36d0bbc05b29d5c407ef5 ] + +When per-connection async_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from the connection teardown path but no matching +ida_destroy() was added. The connection is therefore freed with the +IDA's backing xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +connection is freed. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/connection.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c +index 9d7e8a0812721..fb9918e5d9871 100644 +--- a/fs/smb/server/connection.c ++++ b/fs/smb/server/connection.c +@@ -98,6 +98,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn) + kfree(conn->preauth_info); + kfree(conn->mechToken); + if (atomic_dec_and_test(&conn->refcnt)) { ++ /* ++ * async_ida is embedded in struct ksmbd_conn, so pair ++ * ida_destroy() with the final kfree() rather than with ++ * the unconditional field teardown above. This keeps ++ * the IDA valid for the entire lifetime of the struct, ++ * even while other refcount holders (oplock / vfs ++ * durable handles) still reference the connection. ++ */ ++ ida_destroy(&conn->async_ida); + conn->transport->ops->free_transport(conn->transport); + kfree(conn); + } +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch b/queue-7.0/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch new file mode 100644 index 0000000000..8e2d99dcda --- /dev/null +++ b/queue-7.0/ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch @@ -0,0 +1,71 @@ +From 1312200e628887c801047cdd7df1918235819c30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 20:02:54 +0900 +Subject: ksmbd: destroy tree_conn_ida in ksmbd_session_destroy() + +From: DaeMyung Kang + +[ Upstream commit c049ee14eb4343b69b6f7755563f961f5e153423 ] + +When per-session tree_conn_ida was converted from a dynamically +allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was +removed from ksmbd_session_destroy() but no matching ida_destroy() +was added. The session is therefore freed with the IDA's backing +xarray still intact. + +The kernel IDA API expects ida_init() and ida_destroy() to be paired +over an object's lifetime, so add the missing cleanup before the +enclosing session is freed. + +Also move ida_init() to right after the session is allocated so that +it is always paired with the destroy call even on the early error +paths of __session_create() (ksmbd_init_file_table() or +__init_smb2_session() failures), both of which jump to the error +label and invoke ksmbd_session_destroy() on a partially initialised +session. + +No leak has been observed in testing; this is a pairing fix to match +the IDA lifetime rules, not a response to a reproduced regression. + +Fixes: d40012a83f87 ("cifsd: declare ida statically") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index a86589408835b..0dd9e6c976ac0 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -391,6 +391,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) + free_channel_list(sess); + kfree(sess->Preauth_HashValue); + ksmbd_release_id(&session_ida, sess->id); ++ ida_destroy(&sess->tree_conn_ida); + kfree(sess); + } + +@@ -665,6 +666,8 @@ static struct ksmbd_session *__session_create(int protocol) + if (!sess) + return NULL; + ++ ida_init(&sess->tree_conn_ida); ++ + if (ksmbd_init_file_table(&sess->file_table)) + goto error; + +@@ -684,8 +687,6 @@ static struct ksmbd_session *__session_create(int protocol) + if (ret) + goto error; + +- ida_init(&sess->tree_conn_ida); +- + down_write(&sessions_table_lock); + hash_add(sessions_table, &sess->hlist, sess->id); + up_write(&sessions_table_lock); +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch b/queue-7.0/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch new file mode 100644 index 0000000000..5c7ba06b7b --- /dev/null +++ b/queue-7.0/ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch @@ -0,0 +1,64 @@ +From db045dd9975f0e20df08395a74adfe216152f1a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 03:45:11 +0900 +Subject: ksmbd: fix durable fd leak on ClientGUID mismatch in durable v2 open + +From: DaeMyung Kang + +[ Upstream commit 804054d19886ac6628883d82410f6ee42a818664 ] + +ksmbd_lookup_fd_cguid() returns a ksmbd_file with its refcount +incremented via ksmbd_fp_get(). parse_durable_handle_context() in +the DURABLE_REQ_V2 case properly releases this reference on every +path inside the ClientGUID-match branch, either by calling +ksmbd_put_durable_fd() or by transferring ownership to dh_info->fp +for a successful reconnect. However, when an entry exists in the +global file table with the same CreateGuid but a different +ClientGUID, the code simply falls through to the new-open path +without dropping the reference obtained from ksmbd_lookup_fd_cguid(). + +Per MS-SMB2 section 3.3.5.9.10 ("Handling the +SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context"), the server +MUST locate an Open whose Open.CreateGuid matches the request's +CreateGuid AND whose Open.ClientGuid matches the ClientGuid of the +connection that received the request. If no such Open is found, the +server MUST continue with the normal open execution phase. A +CreateGuid hit with a ClientGUID mismatch is therefore the +"Open not found" case: proceeding with a new open is correct, but +the reference obtained purely as a side effect of the lookup must +not be leaked. + +Repeated requests that hit this mismatch pin global_ft entries, +prevent __ksmbd_close_fd() from ever running for the corresponding +files, and defeat the durable scavenger, leading to long-lived +resource leaks. + +Release the reference in the mismatch path and clear dh_info->fp so +subsequent logic does not mistake a non-matching lookup result for +a reconnect target. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Signed-off-by: DaeMyung Kang +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index e3a120a2d0596..c3c7688f0fa80 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -2845,6 +2845,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work, + dh_info->reconnected = true; + goto out; + } ++ ksmbd_put_durable_fd(dh_info->fp); ++ dh_info->fp = NULL; + } + + if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch b/queue-7.0/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch new file mode 100644 index 0000000000..aa4c3d9c5b --- /dev/null +++ b/queue-7.0/ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch @@ -0,0 +1,73 @@ +From e9b6a9fb24be5608b8ddc52abf53fdd4e79e18ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 22:31:12 -0400 +Subject: ksmbd: fix use-after-free from async crypto on Qualcomm crypto engine + +From: Joshua Klinesmith + +[ Upstream commit 3e298897f41c61450c2e7a4f457e8b2485eb35b3 ] + +ksmbd_crypt_message() sets a NULL completion callback on AEAD requests +and does not handle the -EINPROGRESS return code from async hardware +crypto engines like the Qualcomm Crypto Engine (QCE). When QCE returns +-EINPROGRESS, ksmbd treats it as an error and immediately frees the +request while the hardware DMA operation is still in flight. The DMA +completion callback then dereferences freed memory, causing a NULL +pointer crash: + + pc : qce_skcipher_done+0x24/0x174 + lr : vchan_complete+0x230/0x27c + ... + el1h_64_irq+0x68/0x6c + ksmbd_free_work_struct+0x20/0x118 [ksmbd] + ksmbd_exit_file_cache+0x694/0xa4c [ksmbd] + +Use the standard crypto_wait_req() pattern with crypto_req_done() as +the completion callback, matching the approach used by the SMB client +in fs/smb/client/smb2ops.c. This properly handles both synchronous +engines (immediate return) and async engines (-EINPROGRESS followed +by callback notification). + +Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") +Link: https://github.com/openwrt/openwrt/issues/21822 +Signed-off-by: Joshua Klinesmith +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/auth.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c +index af5f403043317..7d0691f7263fe 100644 +--- a/fs/smb/server/auth.c ++++ b/fs/smb/server/auth.c +@@ -827,6 +827,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + struct smb2_transform_hdr *tr_hdr = smb_get_msg(iov[0].iov_base); + unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + int rc; ++ DECLARE_CRYPTO_WAIT(wait); + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] = {}; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; +@@ -913,12 +914,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, + + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); +- aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); ++ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | ++ CRYPTO_TFM_REQ_MAY_SLEEP, ++ crypto_req_done, &wait); + +- if (enc) +- rc = crypto_aead_encrypt(req); +- else +- rc = crypto_aead_decrypt(req); ++ rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : ++ crypto_aead_decrypt(req), &wait); + if (rc) + goto free_iv; + +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-fix-use-after-free-in-smb2_open-during-durable.patch b/queue-7.0/ksmbd-fix-use-after-free-in-smb2_open-during-durable.patch new file mode 100644 index 0000000000..718ee34c46 --- /dev/null +++ b/queue-7.0/ksmbd-fix-use-after-free-in-smb2_open-during-durable.patch @@ -0,0 +1,76 @@ +From 3ac14696f616e97250aac62082011ee9d3cd70e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 23:57:09 +0530 +Subject: ksmbd: fix use-after-free in smb2_open during durable reconnect + +From: Akif + +[ Upstream commit 1baff47b81f94f9231c91236aa511420d0e266b9 ] + +In smb2_open, the call to ksmbd_put_durable_fd(fp) drops the reference +to the durable file descriptor early during the durable reconnect +process. If an error occurs subsequently (eg, ksmbd_iov_pin_rsp fails) +or a scavenger accesses the file, it leads to a use-after-free when +accessing fp properties (eg fp->create_time). + +Move the single put to the end of the function below err_out2 so fp +stays valid until smb2_open returns. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Signed-off-by: Akif +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 135c74e6c4be6..e3a120a2d0596 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -3015,29 +3015,23 @@ int smb2_open(struct ksmbd_work *work) + if (dh_info.reconnected == true) { + rc = smb2_check_durable_oplock(conn, share, dh_info.fp, + lc, sess->user, name); +- if (rc) { +- ksmbd_put_durable_fd(dh_info.fp); ++ if (rc) + goto err_out2; +- } + + rc = ksmbd_reopen_durable_fd(work, dh_info.fp); +- if (rc) { +- ksmbd_put_durable_fd(dh_info.fp); ++ if (rc) + goto err_out2; +- } + + fp = dh_info.fp; + + if (ksmbd_override_fsids(work)) { + rc = -ENOMEM; +- ksmbd_put_durable_fd(dh_info.fp); + goto err_out2; + } + + file_info = FILE_OPENED; + + rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat); +- ksmbd_put_durable_fd(fp); + if (rc) + goto err_out2; + +@@ -3807,6 +3801,9 @@ int smb2_open(struct ksmbd_work *work) + ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status); + } + ++ if (dh_info.reconnected) ++ ksmbd_put_durable_fd(dh_info.fp); ++ + kfree(name); + kfree(lc); + +-- +2.53.0 + diff --git a/queue-7.0/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch b/queue-7.0/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch new file mode 100644 index 0000000000..9c2ad1c756 --- /dev/null +++ b/queue-7.0/ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch @@ -0,0 +1,59 @@ +From c016673365d5242af43cacefbb5c4fb45aa9f9a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 00:31:47 +0900 +Subject: ksmbd: scope conn->binding slowpath to bound sessions only + +From: Hyunwoo Kim + +[ Upstream commit b0da97c034b6107d14e537e212d4ce8b22109a58 ] + +When the binding SESSION_SETUP sets conn->binding = true, the flag stays +set after the call so that the global session lookup in +ksmbd_session_lookup_all() can find the session, which was not added to +conn->sessions. Because the flag is connection-wide, the global lookup +path will also resolve any other session by id if asked. + +Tighten the global lookup so that the returned session must have this +connection registered in its channel xarray (sess->ksmbd_chann_list). +The channel entry is installed by the existing binding_session path in +ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes +successfully, so this condition is a strict equivalent of "this +connection has been accepted as a channel of this session". Connections +that have not bound to a given session cannot reach it via the global +table. + +The existing conn->binding gate for entering the slowpath is preserved +so that non-binding connections keep the fast-path-only behavior, and +the session->state check is unchanged. + +Fixes: f5a544e3bab7 ("ksmbd: add support for SMB3 multichannel") +Signed-off-by: Hyunwoo Kim +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/mgmt/user_session.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c +index 0dd9e6c976ac0..de58aed76cb42 100644 +--- a/fs/smb/server/mgmt/user_session.c ++++ b/fs/smb/server/mgmt/user_session.c +@@ -548,8 +548,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, + struct ksmbd_session *sess; + + sess = ksmbd_session_lookup(conn, id); +- if (!sess && conn->binding) ++ if (!sess && conn->binding) { + sess = ksmbd_session_lookup_slowpath(id); ++ if (sess && !xa_load(&sess->ksmbd_chann_list, (long)conn)) { ++ ksmbd_user_session_put(sess); ++ sess = NULL; ++ } ++ } + if (sess && sess->state != SMB2_SESSION_VALID) { + ksmbd_user_session_put(sess); + sess = NULL; +-- +2.53.0 + diff --git a/queue-7.0/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch b/queue-7.0/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch new file mode 100644 index 0000000000..f682df0f6e --- /dev/null +++ b/queue-7.0/ktest-avoid-undef-warning-when-warnings_file-is-unse.patch @@ -0,0 +1,49 @@ +From 7ede96f9729e4eacaeed5644fee9b27925941214 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:56 -0300 +Subject: ktest: Avoid undef warning when WARNINGS_FILE is unset +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit 057854f8a595160656fe77ed7bf0d2403724b915 ] + +check_buildlog() probes $warnings_file with -f even when WARNINGS_FILE is +not configured. Perl warns about the uninitialized value and adds noise to +the test log, which can hide the output we actually care about. + +Check that WARNINGS_FILE is defined before testing whether the file exists. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-1-565d412f4925@suse.com +Fixes: 4283b169abfb ("ktest: Add make_warnings_file and process full warnings") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 88de775097fef..28643812184bc 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -2508,7 +2508,7 @@ sub check_buildlog { + my $save_no_reboot = $no_reboot; + $no_reboot = 1; + +- if (-f $warnings_file) { ++ if (defined($warnings_file) && -f $warnings_file) { + open(IN, $warnings_file) or + dodie "Error opening $warnings_file"; + +-- +2.53.0 + diff --git a/queue-7.0/ktest-honor-empty-per-test-option-overrides.patch b/queue-7.0/ktest-honor-empty-per-test-option-overrides.patch new file mode 100644 index 0000000000..35cc73f2ef --- /dev/null +++ b/queue-7.0/ktest-honor-empty-per-test-option-overrides.patch @@ -0,0 +1,79 @@ +From be2e5936c2ce3e749e5ea79dd3a90c7634ce5ade Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:07:59 -0300 +Subject: ktest: Honor empty per-test option overrides +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit a2de57a3c8192dcd67cccaff6c341b93748d799b ] + +A per-test override can clear an inherited default option by assigning an +empty value, but __set_test_option() still used option_defined() to decide +whether a per-test key existed. That turned an empty per-test assignment +back into "fall back to the default", so tests still could not clear +inherited settings. + +For example: + + DEFAULTS + (...) + LOG_FILE = /tmp/ktest-empty-override.log + CLEAR_LOG = 1 + ADD_CONFIG = /tmp/.config + + TEST_START + TEST_TYPE = build + BUILD_TYPE = nobuild + ADD_CONFIG = + +This would run the test with ADD_CONFIG[1] = /tmp/.config + +Fix by checking whether the per-test key exists before falling back. If it +does exist but is empty, treat it as unset for that test and stop the +fallback chain there. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-4-565d412f4925@suse.com +Fixes: 22c37a9ac49d ("ktest: Allow tests to undefine default options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 28643812184bc..924e17df56f74 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -4183,7 +4183,8 @@ sub __set_test_option { + + my $option = "$name\[$i\]"; + +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + +@@ -4191,7 +4192,8 @@ sub __set_test_option { + if ($i >= $test && + $i < $test + $repeat_tests{$test}) { + $option = "$name\[$test\]"; +- if (option_defined($option)) { ++ if (exists($opt{$option})) { ++ return undef if (!option_defined($option)); + return $opt{$option}; + } + } +-- +2.53.0 + diff --git a/queue-7.0/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch b/queue-7.0/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch new file mode 100644 index 0000000000..1d6978b8ec --- /dev/null +++ b/queue-7.0/ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch @@ -0,0 +1,105 @@ +From 5c11c61caf3ff0d7c161c34de7e6030d1e0bec97 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 19:08:03 -0300 +Subject: ktest: Run POST_KTEST hooks on failure and cancellation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ricardo B. Marlière + +[ Upstream commit bc6e165a452da909cef0efbc286e6695624db372 ] + +PRE_KTEST can be useful for setting up the environment and POST_KTEST to +tear it down, however POST_KTEST only runs on the normal end-of-run path. +It is skipped when ktest exits through dodie() or cancel_test(). Final +cleanup hooks are skipped. + +Factor the final hook execution into run_post_ktest(), call it from the +normal exit path and from the early exit paths, and guard it so the hook +runs at most once. + +Cc: John Hawley +Cc: Andrea Righi +Cc: Marcos Paulo de Souza +Cc: Matthieu Baerts +Cc: Fernando Fernandez Mancera +Cc: Pedro Falcato +Link: https://patch.msgid.link/20260307-ktest-fixes-v1-8-565d412f4925@suse.com +Fixes: 921ed4c7208e ("ktest: Add PRE/POST_KTEST and TEST options") +Signed-off-by: Ricardo B. Marlière +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + tools/testing/ktest/ktest.pl | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl +index 924e17df56f74..17bdce9cafac2 100755 +--- a/tools/testing/ktest/ktest.pl ++++ b/tools/testing/ktest/ktest.pl +@@ -100,6 +100,7 @@ my $test_type; + my $build_type; + my $build_options; + my $final_post_ktest; ++my $post_ktest_done = 0; + my $pre_ktest; + my $post_ktest; + my $pre_test; +@@ -1575,6 +1576,24 @@ sub get_test_name() { + return $name; + } + ++sub run_post_ktest { ++ my $cmd; ++ ++ return if ($post_ktest_done); ++ ++ if (defined($final_post_ktest)) { ++ $cmd = $final_post_ktest; ++ } elsif (defined($post_ktest)) { ++ $cmd = $post_ktest; ++ } else { ++ return; ++ } ++ ++ my $cp_post_ktest = eval_kernel_version($cmd); ++ run_command $cp_post_ktest; ++ $post_ktest_done = 1; ++} ++ + sub dodie { + # avoid recursion + return if ($in_die); +@@ -1634,6 +1653,7 @@ sub dodie { + if (defined($post_test)) { + run_command $post_test; + } ++ run_post_ktest; + + die @_, "\n"; + } +@@ -4300,6 +4320,7 @@ sub cancel_test { + send_email("KTEST: Your [$name] test was cancelled", + "Your test started at $script_start_time was cancelled: sig int"); + } ++ run_post_ktest; + die "\nCaught Sig Int, test interrupted: $!\n" + } + +@@ -4661,11 +4682,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { + success $i; + } + +-if (defined($final_post_ktest)) { +- +- my $cp_final_post_ktest = eval_kernel_version $final_post_ktest; +- run_command $cp_final_post_ktest; +-} ++run_post_ktest; + + if ($opt{"POWEROFF_ON_SUCCESS"}) { + halt; +-- +2.53.0 + diff --git a/queue-7.0/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch b/queue-7.0/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch new file mode 100644 index 0000000000..916203ec27 --- /dev/null +++ b/queue-7.0/leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch @@ -0,0 +1,36 @@ +From 444dd2210495b6ecc04955380c8e0327eb61466d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 11:30:48 +0800 +Subject: leds: lgm-sso: Remove duplicate assignments for priv->mmap + +From: Chen Ni + +[ Upstream commit 7186d0330c3f3e86de577687a82f4ebd96dcb5ac ] + +Remove duplicate assignment of priv->mmap in intel_sso_led_probe(). + +Fixes: fba8a6f2263b ("leds: lgm-sso: Fix clock handling") +Signed-off-by: Chen Ni +Link: https://patch.msgid.link/20260226033048.3715915-1-nichen@iscas.ac.cn +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/leds/blink/leds-lgm-sso.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c +index 8923d2df47049..3d9ef9a54805c 100644 +--- a/drivers/leds/blink/leds-lgm-sso.c ++++ b/drivers/leds/blink/leds-lgm-sso.c +@@ -808,8 +808,6 @@ static int intel_sso_led_probe(struct platform_device *pdev) + + priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk); + +- priv->mmap = syscon_node_to_regmap(dev->of_node); +- + priv->mmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(priv->mmap)) { + dev_err(dev, "Failed to map iomem!\n"); +-- +2.53.0 + diff --git a/queue-7.0/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch b/queue-7.0/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch new file mode 100644 index 0000000000..d7866e111a --- /dev/null +++ b/queue-7.0/lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch @@ -0,0 +1,51 @@ +From 91c2a7dd84c3371c139dad986e1a0ee081e15b18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 17:21:43 +0200 +Subject: lib/hexdump: print_hex_dump_bytes() calls print_hex_dump_debug() + +From: Geert Uytterhoeven + +[ Upstream commit 36776b7f8a8955b4e75b5d490a75fee0c7a2a7ef ] + +print_hex_dump_bytes() claims to be a simple wrapper around +print_hex_dump(), but it actally calls print_hex_dump_debug(), which +means no output is printed if (dynamic) DEBUG is disabled. + +Update the documentation to match the implementation. + +Fixes: 091cb0994edd20d6 ("lib/hexdump: make print_hex_dump_bytes() a nop on !DEBUG builds") +Signed-off-by: Geert Uytterhoeven +Reviewed-by: Petr Mladek +Link: https://patch.msgid.link/3d5c3069fd9102ecaf81d044b750cd613eb72a08.1774970392.git.geert+renesas@glider.be +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + include/linux/printk.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/linux/printk.h b/include/linux/printk.h +index 54e3c621fec37..f594c1266bfd4 100644 +--- a/include/linux/printk.h ++++ b/include/linux/printk.h +@@ -815,7 +815,8 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, + #endif + + /** +- * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params ++ * print_hex_dump_bytes - shorthand form of print_hex_dump_debug() with default ++ * params + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none +@@ -823,7 +824,7 @@ static inline void print_hex_dump_devel(const char *prefix_str, int prefix_type, + * @buf: data blob to dump + * @len: number of bytes in the @buf + * +- * Calls print_hex_dump(), with log level of KERN_DEBUG, ++ * Calls print_hex_dump_debug(), with log level of KERN_DEBUG, + * rowsize of 16, groupsize of 1, and ASCII output included. + */ + #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ +-- +2.53.0 + diff --git a/queue-7.0/lib-kunit_iov_iter-fix-memory-leaks.patch b/queue-7.0/lib-kunit_iov_iter-fix-memory-leaks.patch new file mode 100644 index 0000000000..ddc6afff54 --- /dev/null +++ b/queue-7.0/lib-kunit_iov_iter-fix-memory-leaks.patch @@ -0,0 +1,85 @@ +From 71866237fb6adf159a1a549fd576480eebdcb5dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 22:49:03 +0100 +Subject: lib: kunit_iov_iter: fix memory leaks + +From: Christian A. Ehrhardt + +[ Upstream commit 0b49c7d0ae697fcecd7377cb7dda220f7cd096ff ] + +Use vfree() instead of vunmap() to free the buffer allocated by +iov_kunit_create_buffer() because vunmap() does not honour +VM_MAP_PUT_PAGES. In order for this to work the page array itself must +not be managed by kunit. + +Remove the folio_put() when destroying a folioq. This is handled by +vfree(), now. + +Pointed out by sashiko.dev on a previous iteration of this series. + +Tested by running the kunit test 10000 times in a loop. + +Link: https://lkml.kernel.org/r/20260326214905.818170-4-lk@c--e.de +Fixes: 2d71340ff1d4 ("iov_iter: Kunit tests for copying to/from an iterator") +Signed-off-by: Christian A. Ehrhardt +Cc: David Howells +Cc: David Gow +Cc: Kees Cook +Cc: Petr Mladek +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + lib/tests/kunit_iov_iter.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c +index bb847e5010eb2..d16449bdb8334 100644 +--- a/lib/tests/kunit_iov_iter.c ++++ b/lib/tests/kunit_iov_iter.c +@@ -42,7 +42,7 @@ static inline u8 pattern(unsigned long x) + + static void iov_kunit_unmap(void *data) + { +- vunmap(data); ++ vfree(data); + } + + static void *__init iov_kunit_create_buffer(struct kunit *test, +@@ -53,17 +53,22 @@ static void *__init iov_kunit_create_buffer(struct kunit *test, + unsigned long got; + void *buffer; + +- pages = kunit_kcalloc(test, npages, sizeof(struct page *), GFP_KERNEL); +- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages); ++ pages = kzalloc_objs(struct page *, npages, GFP_KERNEL); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pages); + *ppages = pages; + + got = alloc_pages_bulk(GFP_KERNEL, npages, pages); + if (got != npages) { + release_pages(pages, got); ++ kvfree(pages); + KUNIT_ASSERT_EQ(test, got, npages); + } + + buffer = vmap(pages, npages, VM_MAP | VM_MAP_PUT_PAGES, PAGE_KERNEL); ++ if (buffer == NULL) { ++ release_pages(pages, got); ++ kvfree(pages); ++ } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer); + + kunit_add_action_or_reset(test, iov_kunit_unmap, buffer); +@@ -369,9 +374,6 @@ static void iov_kunit_destroy_folioq(void *data) + + for (folioq = data; folioq; folioq = next) { + next = folioq->next; +- for (int i = 0; i < folioq_nr_slots(folioq); i++) +- if (folioq_folio(folioq, i)) +- folio_put(folioq_folio(folioq, i)); + kfree(folioq); + } + } +-- +2.53.0 + diff --git a/queue-7.0/libbpf-prevent-double-close-and-leak-of-btf-objects.patch b/queue-7.0/libbpf-prevent-double-close-and-leak-of-btf-objects.patch new file mode 100644 index 0000000000..8034f60782 --- /dev/null +++ b/queue-7.0/libbpf-prevent-double-close-and-leak-of-btf-objects.patch @@ -0,0 +1,98 @@ +From f78231993d9ce66e23c50aeda86c5d3a48bde6e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 12:00:34 +0200 +Subject: libbpf: Prevent double close and leak of btf objects + +From: Jiri Olsa + +[ Upstream commit 380044c40b1636a72fd8f188b5806be6ae564279 ] + +Sashiko found possible double close of btf object fd [1], +which happens when strdup in load_module_btfs fails at which +point the obj->btf_module_cnt is already incremented. + +The error path close btf fd and so does later cleanup code in +bpf_object_post_load_cleanup function. + +Also libbpf_ensure_mem failure leaves btf object not assigned +and it's leaked. + +Replacing the err_out label with break to make the error path +less confusing as suggested by Alan. + +Incrementing obj->btf_module_cnt only if there's no failure +and releasing btf object in error path. + +Fixes: 91abb4a6d79d ("libbpf: Support attachment of BPF tracing programs to kernel modules") +[1] https://sashiko.dev/#/patchset/20260324081846.2334094-1-jolsa%40kernel.org +Signed-off-by: Jiri Olsa +Link: https://lore.kernel.org/r/20260416100034.1610852-1-jolsa@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/lib/bpf/libbpf.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index 0be7017800fee..ef7e7f3e31b75 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -5798,11 +5798,12 @@ static int load_module_btfs(struct bpf_object *obj) + info.name = ptr_to_u64(name); + info.name_len = sizeof(name); + ++ btf = NULL; + err = bpf_btf_get_info_by_fd(fd, &info, &len); + if (err) { + err = -errno; + pr_warn("failed to get BTF object #%d info: %s\n", id, errstr(err)); +- goto err_out; ++ break; + } + + /* ignore non-module BTFs */ +@@ -5816,15 +5817,15 @@ static int load_module_btfs(struct bpf_object *obj) + if (err) { + pr_warn("failed to load module [%s]'s BTF object #%d: %s\n", + name, id, errstr(err)); +- goto err_out; ++ break; + } + + err = libbpf_ensure_mem((void **)&obj->btf_modules, &obj->btf_module_cap, + sizeof(*obj->btf_modules), obj->btf_module_cnt + 1); + if (err) +- goto err_out; ++ break; + +- mod_btf = &obj->btf_modules[obj->btf_module_cnt++]; ++ mod_btf = &obj->btf_modules[obj->btf_module_cnt]; + + mod_btf->btf = btf; + mod_btf->id = id; +@@ -5832,16 +5833,16 @@ static int load_module_btfs(struct bpf_object *obj) + mod_btf->name = strdup(name); + if (!mod_btf->name) { + err = -ENOMEM; +- goto err_out; ++ break; + } +- continue; ++ obj->btf_module_cnt++; ++ } + +-err_out: ++ if (err) { ++ btf__free(btf); + close(fd); +- return err; + } +- +- return 0; ++ return err; + } + + static struct bpf_core_cand_list * +-- +2.53.0 + diff --git a/queue-7.0/locking-fix-rwlock-and-spinlock-lock-context-annotat.patch b/queue-7.0/locking-fix-rwlock-and-spinlock-lock-context-annotat.patch new file mode 100644 index 0000000000..9179ca6e5c --- /dev/null +++ b/queue-7.0/locking-fix-rwlock-and-spinlock-lock-context-annotat.patch @@ -0,0 +1,103 @@ +From 18cb1fbf663bac66c7ca12d94662bb0ac73825a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 10:32:41 -0800 +Subject: locking: Fix rwlock and spinlock lock context annotations + +From: Bart Van Assche + +[ Upstream commit 38e18d825f7281fdc16d3241df5115ce6eaeaf79 ] + +Fix two incorrect rwlock_t lock context annotations. Add the raw_spinlock_t +lock context annotations that are missing. + +Fixes: f16a802d402d ("locking/rwlock, spinlock: Support Clang's context analysis") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Marco Elver +Link: https://patch.msgid.link/20260225183244.4035378-2-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/rwlock.h | 4 ++-- + include/linux/rwlock_api_smp.h | 6 ++++-- + include/linux/spinlock.h | 3 ++- + 3 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/include/linux/rwlock.h b/include/linux/rwlock.h +index 3390d21c95dd1..21ceefc4a49f2 100644 +--- a/include/linux/rwlock.h ++++ b/include/linux/rwlock.h +@@ -30,10 +30,10 @@ do { \ + + #ifdef CONFIG_DEBUG_SPINLOCK + extern void do_raw_read_lock(rwlock_t *lock) __acquires_shared(lock); +- extern int do_raw_read_trylock(rwlock_t *lock); ++ extern int do_raw_read_trylock(rwlock_t *lock) __cond_acquires_shared(true, lock); + extern void do_raw_read_unlock(rwlock_t *lock) __releases_shared(lock); + extern void do_raw_write_lock(rwlock_t *lock) __acquires(lock); +- extern int do_raw_write_trylock(rwlock_t *lock); ++extern int do_raw_write_trylock(rwlock_t *lock) __cond_acquires(true, lock); + extern void do_raw_write_unlock(rwlock_t *lock) __releases(lock); + #else + # define do_raw_read_lock(rwlock) do {__acquire_shared(lock); arch_read_lock(&(rwlock)->raw_lock); } while (0) +diff --git a/include/linux/rwlock_api_smp.h b/include/linux/rwlock_api_smp.h +index 61a852609eab4..9e02a5f28cd1d 100644 +--- a/include/linux/rwlock_api_smp.h ++++ b/include/linux/rwlock_api_smp.h +@@ -23,7 +23,7 @@ void __lockfunc _raw_write_lock_bh(rwlock_t *lock) __acquires(lock); + void __lockfunc _raw_read_lock_irq(rwlock_t *lock) __acquires_shared(lock); + void __lockfunc _raw_write_lock_irq(rwlock_t *lock) __acquires(lock); + unsigned long __lockfunc _raw_read_lock_irqsave(rwlock_t *lock) +- __acquires(lock); ++ __acquires_shared(lock); + unsigned long __lockfunc _raw_write_lock_irqsave(rwlock_t *lock) + __acquires(lock); + int __lockfunc _raw_read_trylock(rwlock_t *lock) __cond_acquires_shared(true, lock); +@@ -36,7 +36,7 @@ void __lockfunc _raw_read_unlock_irq(rwlock_t *lock) __releases_shared(lock); + void __lockfunc _raw_write_unlock_irq(rwlock_t *lock) __releases(lock); + void __lockfunc + _raw_read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) +- __releases(lock); ++ __releases_shared(lock); + void __lockfunc + _raw_write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) + __releases(lock); +@@ -116,6 +116,7 @@ _raw_write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) + #endif + + static inline int __raw_read_trylock(rwlock_t *lock) ++ __cond_acquires_shared(true, lock) + { + preempt_disable(); + if (do_raw_read_trylock(lock)) { +@@ -127,6 +128,7 @@ static inline int __raw_read_trylock(rwlock_t *lock) + } + + static inline int __raw_write_trylock(rwlock_t *lock) ++ __cond_acquires(true, lock) + { + preempt_disable(); + if (do_raw_write_trylock(lock)) { +diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h +index e1e2f144af9b4..241277cd34cf3 100644 +--- a/include/linux/spinlock.h ++++ b/include/linux/spinlock.h +@@ -178,7 +178,7 @@ do { \ + + #ifdef CONFIG_DEBUG_SPINLOCK + extern void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock); +- extern int do_raw_spin_trylock(raw_spinlock_t *lock); ++ extern int do_raw_spin_trylock(raw_spinlock_t *lock) __cond_acquires(true, lock); + extern void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock); + #else + static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock) +@@ -189,6 +189,7 @@ static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock) + } + + static inline int do_raw_spin_trylock(raw_spinlock_t *lock) ++ __cond_acquires(true, lock) + { + int ret = arch_spin_trylock(&(lock)->raw_lock); + +-- +2.53.0 + diff --git a/queue-7.0/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch b/queue-7.0/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch new file mode 100644 index 0000000000..d99b8de56a --- /dev/null +++ b/queue-7.0/locking-fix-rwlock-support-in-linux-spinlock_up.h.patch @@ -0,0 +1,75 @@ +From 0cf39bad9b5f96afb8f3caf2f2cc2e71f84655cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:15:07 -0700 +Subject: locking: Fix rwlock support in + +From: Bart Van Assche + +[ Upstream commit 756a0e011cfca0b45a48464aa25b05d9a9c2fb0b ] + +Architecture support for rwlocks must be available whether or not +CONFIG_DEBUG_SPINLOCK has been defined. Move the definitions of the +arch_{read,write}_{lock,trylock,unlock}() macros such that these become +visbile if CONFIG_DEBUG_SPINLOCK=n. + +This patch prepares for converting do_raw_{read,write}_trylock() into +inline functions. Without this patch that conversion triggers a build +failure for UP architectures, e.g. arm-ep93xx. I used the following +kernel configuration to build the kernel for that architecture: + + CONFIG_ARCH_MULTIPLATFORM=y + CONFIG_ARCH_MULTI_V7=n + CONFIG_ATAGS=y + CONFIG_MMU=y + CONFIG_ARCH_MULTI_V4T=y + CONFIG_CPU_LITTLE_ENDIAN=y + CONFIG_ARCH_EP93XX=y + +Fixes: fb1c8f93d869 ("[PATCH] spinlock consolidation") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260313171510.230998-2-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/spinlock_up.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h +index 1e84e71ca495e..3a50976471d71 100644 +--- a/include/linux/spinlock_up.h ++++ b/include/linux/spinlock_up.h +@@ -48,16 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + lock->slock = 1; + } + +-/* +- * Read-write spinlocks. No debug version. +- */ +-#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) +-#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) +-#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) +- + #else /* DEBUG_SPINLOCK */ + #define arch_spin_is_locked(lock) ((void)(lock), 0) + /* for sched/core.c and kernel_lock.c: */ +@@ -68,4 +58,14 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) + + #define arch_spin_is_contended(lock) (((void)(lock), 0)) + ++/* ++ * Read-write spinlocks. No debug version. ++ */ ++#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) ++ + #endif /* __LINUX_SPINLOCK_UP_H */ +-- +2.53.0 + diff --git a/queue-7.0/locking-mutex-fix-wrong-comment-for-config_debug_loc.patch b/queue-7.0/locking-mutex-fix-wrong-comment-for-config_debug_loc.patch new file mode 100644 index 0000000000..e81abd4bbf --- /dev/null +++ b/queue-7.0/locking-mutex-fix-wrong-comment-for-config_debug_loc.patch @@ -0,0 +1,37 @@ +From 2c03048ac99fc8e5c11b7981c847ab6d6f3a17c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 11:15:11 -0800 +Subject: locking/mutex: Fix wrong comment for CONFIG_DEBUG_LOCK_ALLOC + +From: Davidlohr Bueso + +[ Upstream commit babcde3be8c9148aa60a14b17831e8f249854963 ] + +... that endif block should be CONFIG_DEBUG_LOCK_ALLOC, not +CONFIG_LOCKDEP. + +Fixes: 51d7a054521d ("locking/mutex: Redo __mutex_init() to reduce generated code size") +Signed-off-by: Davidlohr Bueso +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260217191512.1180151-3-dave@stgolabs.net +Signed-off-by: Sasha Levin +--- + include/linux/mutex.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mutex.h b/include/linux/mutex.h +index 8126da9590886..f57d2a97da57f 100644 +--- a/include/linux/mutex.h ++++ b/include/linux/mutex.h +@@ -146,7 +146,7 @@ static inline void __mutex_init(struct mutex *lock, const char *name, + { + mutex_rt_init_generic(lock); + } +-#endif /* !CONFIG_LOCKDEP */ ++#endif /* !CONFIG_DEBUG_LOCK_ALLOC */ + #endif /* CONFIG_PREEMPT_RT */ + + #ifdef CONFIG_DEBUG_MUTEXES +-- +2.53.0 + diff --git a/queue-7.0/locking-mutex-rename-mutex_init_lockep.patch b/queue-7.0/locking-mutex-rename-mutex_init_lockep.patch new file mode 100644 index 0000000000..a98804f091 --- /dev/null +++ b/queue-7.0/locking-mutex-rename-mutex_init_lockep.patch @@ -0,0 +1,65 @@ +From 6e7046f6a52e736e9f45bf6df424f949987aa02f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 11:15:10 -0800 +Subject: locking/mutex: Rename mutex_init_lockep() + +From: Davidlohr Bueso + +[ Upstream commit 8b65eb52d93e4e496bd26e6867152344554eb39e ] + +Typo, this wants to be _lockdep(). + +Fixes: 51d7a054521d ("locking/mutex: Redo __mutex_init() to reduce generated code size") +Signed-off-by: Davidlohr Bueso +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260217191512.1180151-2-dave@stgolabs.net +Signed-off-by: Sasha Levin +--- + include/linux/mutex.h | 4 ++-- + kernel/locking/mutex.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/include/linux/mutex.h b/include/linux/mutex.h +index ecaa0440f6ec4..8126da9590886 100644 +--- a/include/linux/mutex.h ++++ b/include/linux/mutex.h +@@ -87,12 +87,12 @@ do { \ + struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + + #ifdef CONFIG_DEBUG_LOCK_ALLOC +-void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key); ++void mutex_init_lockdep(struct mutex *lock, const char *name, struct lock_class_key *key); + + static inline void __mutex_init(struct mutex *lock, const char *name, + struct lock_class_key *key) + { +- mutex_init_lockep(lock, name, key); ++ mutex_init_lockdep(lock, name, key); + } + #else + extern void mutex_init_generic(struct mutex *lock); +diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c +index 2a1d165b3167e..c867f6c15530d 100644 +--- a/kernel/locking/mutex.c ++++ b/kernel/locking/mutex.c +@@ -171,7 +171,7 @@ static __always_inline bool __mutex_unlock_fast(struct mutex *lock) + + #else /* !CONFIG_DEBUG_LOCK_ALLOC */ + +-void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key) ++void mutex_init_lockdep(struct mutex *lock, const char *name, struct lock_class_key *key) + { + __mutex_init_generic(lock); + +@@ -181,7 +181,7 @@ void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_k + debug_check_no_locks_freed((void *)lock, sizeof(*lock)); + lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_SLEEP); + } +-EXPORT_SYMBOL(mutex_init_lockep); ++EXPORT_SYMBOL(mutex_init_lockdep); + #endif /* !CONFIG_DEBUG_LOCK_ALLOC */ + + static inline void __mutex_set_flag(struct mutex *lock, unsigned long flag) +-- +2.53.0 + diff --git a/queue-7.0/loop-fix-partition-scan-race-between-udev-and-loop_r.patch b/queue-7.0/loop-fix-partition-scan-race-between-udev-and-loop_r.patch new file mode 100644 index 0000000000..e569ca9d0e --- /dev/null +++ b/queue-7.0/loop-fix-partition-scan-race-between-udev-and-loop_r.patch @@ -0,0 +1,87 @@ +From 647342e7c40bdca1e0ce6fd7e0e24ca7a3d32780 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:51:28 +0000 +Subject: loop: fix partition scan race between udev and + loop_reread_partitions() + +From: Daan De Meyer + +[ Upstream commit 267ec4d7223a783f029a980f41b93c39b17996da ] + +When LOOP_CONFIGURE is called with LO_FLAGS_PARTSCAN, the following +sequence occurs: + + 1. disk_force_media_change() sets GD_NEED_PART_SCAN + 2. Uevent suppression is lifted and a KOBJ_CHANGE uevent is sent + 3. loop_global_unlock() releases the lock + 4. loop_reread_partitions() calls bdev_disk_changed() to scan + +There is a race between steps 2 and 4: when udev receives the uevent +and opens the device before loop_reread_partitions() runs, +blkdev_get_whole() in bdev.c sees GD_NEED_PART_SCAN set and calls +bdev_disk_changed() for a first scan. Then loop_reread_partitions() +does a second scan. The open_mutex serializes these two scans, but +does not prevent both from running. + +The second scan in bdev_disk_changed() drops all partition devices +from the first scan (via blk_drop_partitions()) before re-adding +them, causing partition block devices to briefly disappear. This +breaks any systemd unit with BindsTo= on the partition device: systemd +observes the device going dead, fails the dependent units, and does +not retry them when the device reappears. + +Fix this by removing the GD_NEED_PART_SCAN set from +disk_force_media_change() entirely. None of the current callers need +the lazy on-open partition scan triggered by this flag: + + - floppy: sets GENHD_FL_NO_PART, so disk_has_partscan() is always + false and GD_NEED_PART_SCAN has no effect. + - loop (loop_configure, loop_change_fd): when LO_FLAGS_PARTSCAN is + set, loop_reread_partitions() performs an explicit scan. When not + set, GD_SUPPRESS_PART_SCAN prevents the lazy scan path. + - loop (__loop_clr_fd): calls bdev_disk_changed() explicitly if + LO_FLAGS_PARTSCAN is set. + - nbd (nbd_clear_sock_ioctl): capacity is set to zero immediately + after; nbd manages GD_NEED_PART_SCAN explicitly elsewhere. + +With GD_NEED_PART_SCAN no longer set by disk_force_media_change(), +udev opening the loop device after the uevent no longer triggers a +redundant scan in blkdev_get_whole(), and only the single explicit +scan from loop_reread_partitions() runs. + +A regression test for this bug has been submitted to blktests: +https://github.com/linux-blktests/blktests/pull/240. + +Fixes: 9f65c489b68d ("loop: raise media_change event") +Signed-off-by: Daan De Meyer +Acked-by: Christian Brauner +Link: https://patch.msgid.link/20260331105130.1077599-1-daan@amutable.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/disk-events.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/block/disk-events.c b/block/disk-events.c +index 9f9f9f8a2d6b1..074731ecc3d25 100644 +--- a/block/disk-events.c ++++ b/block/disk-events.c +@@ -290,13 +290,14 @@ EXPORT_SYMBOL(disk_check_media_change); + * Should be called when the media changes for @disk. Generates a uevent + * and attempts to free all dentries and inodes and invalidates all block + * device page cache entries in that case. ++ * ++ * Callers that need a partition re-scan should arrange for one explicitly. + */ + void disk_force_media_change(struct gendisk *disk) + { + disk_event_uevent(disk, DISK_EVENT_MEDIA_CHANGE); + inc_diskseq(disk); + bdev_mark_dead(disk->part0, true); +- set_bit(GD_NEED_PART_SCAN, &disk->state); + } + EXPORT_SYMBOL_GPL(disk_force_media_change); + +-- +2.53.0 + diff --git a/queue-7.0/macsec-support-vlan-filtering-lower-devices.patch b/queue-7.0/macsec-support-vlan-filtering-lower-devices.patch new file mode 100644 index 0000000000..e179d53dd5 --- /dev/null +++ b/queue-7.0/macsec-support-vlan-filtering-lower-devices.patch @@ -0,0 +1,190 @@ +From d1d5456fecc12f3b3fab648195bd4d1c6d97ee4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:52:40 +0300 +Subject: macsec: Support VLAN-filtering lower devices + +From: Cosmin Ratiu + +[ Upstream commit a363b1c8be879c79a688eaf93ba01b63f8b0e63c ] + +VLAN-filtering is done through two netdev features +(NETIF_F_HW_VLAN_CTAG_FILTER and NETIF_F_HW_VLAN_STAG_FILTER) and two +netdev ops (ndo_vlan_rx_add_vid and ndo_vlan_rx_kill_vid). + +Implement these and advertise the features if the lower device supports +them. This allows proper VLAN filtering to work on top of MACsec +devices, when the lower device is capable of VLAN filtering. +As a concrete example, having this chain of interfaces now works: +vlan_filtering_capable_dev(1) -> macsec_dev(2) -> macsec_vlan_dev(3) + +Before the mentioned commit this used to accidentally work because the +MACsec device (and thus the lower device) was put in promiscuous mode +and the VLAN filter was not used. But after commit [1] correctly made +the macsec driver expose the IFF_UNICAST_FLT flag, promiscuous mode was +no longer used and VLAN filters on dev 1 kicked in. Without support in +dev 2 for propagating VLAN filters down, the register_vlan_dev -> +vlan_vid_add -> __vlan_vid_add -> vlan_add_rx_filter_info call from dev +3 is silently eaten (because vlan_hw_filter_capable returns false and +vlan_add_rx_filter_info silently succeeds). + +For MACsec, VLAN filters are only relevant for offload, otherwise +the VLANs are encrypted and the lower devices don't care about them. So +VLAN filters are only passed on to lower devices in offload mode. +Flipping between offload modes now needs to offload/unoffload the +filters with vlan_{get,drop}_rx_*_filter_info(). + +To avoid the back-and-forth filter updating during rollback, the setting +of macsec->offload is moved after the add/del secy ops. This is safe +since none of the code called from those requires macsec->offload. + +In case adding the filters fails, the added ones are rolled back and an +error is returned to the operation toggling the offload state. + +Fixes: 0349659fd72f ("macsec: set IFF_UNICAST_FLT priv flag") +Signed-off-by: Cosmin Ratiu +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260408115240.1636047-5-cratiu@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macsec.c | 71 +++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 63 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c +index f6cad0746a022..6147ee8b1d78b 100644 +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -2584,7 +2584,9 @@ static void macsec_inherit_tso_max(struct net_device *dev) + netif_inherit_tso_max(dev, macsec->real_dev); + } + +-static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload) ++static int macsec_update_offload(struct net_device *dev, ++ enum macsec_offload offload, ++ struct netlink_ext_ack *extack) + { + enum macsec_offload prev_offload; + const struct macsec_ops *ops; +@@ -2616,14 +2618,35 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off + if (!ops) + return -EOPNOTSUPP; + +- macsec->offload = offload; +- + ctx.secy = &macsec->secy; + ret = offload == MACSEC_OFFLOAD_OFF ? macsec_offload(ops->mdo_del_secy, &ctx) + : macsec_offload(ops->mdo_add_secy, &ctx); +- if (ret) { +- macsec->offload = prev_offload; ++ if (ret) + return ret; ++ ++ /* Remove VLAN filters when disabling offload. */ ++ if (offload == MACSEC_OFFLOAD_OFF) { ++ vlan_drop_rx_ctag_filter_info(dev); ++ vlan_drop_rx_stag_filter_info(dev); ++ } ++ macsec->offload = offload; ++ /* Add VLAN filters when enabling offload. */ ++ if (prev_offload == MACSEC_OFFLOAD_OFF) { ++ ret = vlan_get_rx_ctag_filter_info(dev); ++ if (ret) { ++ NL_SET_ERR_MSG_FMT(extack, ++ "adding ctag VLAN filters failed, err %d", ++ ret); ++ goto rollback_offload; ++ } ++ ret = vlan_get_rx_stag_filter_info(dev); ++ if (ret) { ++ NL_SET_ERR_MSG_FMT(extack, ++ "adding stag VLAN filters failed, err %d", ++ ret); ++ vlan_drop_rx_ctag_filter_info(dev); ++ goto rollback_offload; ++ } + } + + macsec_set_head_tail_room(dev); +@@ -2633,6 +2656,12 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off + + netdev_update_features(dev); + ++ return 0; ++ ++rollback_offload: ++ macsec->offload = prev_offload; ++ macsec_offload(ops->mdo_del_secy, &ctx); ++ + return ret; + } + +@@ -2673,7 +2702,7 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info) + offload = nla_get_u8(tb_offload[MACSEC_OFFLOAD_ATTR_TYPE]); + + if (macsec->offload != offload) +- ret = macsec_update_offload(dev, offload); ++ ret = macsec_update_offload(dev, offload, info->extack); + out: + rtnl_unlock(); + return ret; +@@ -3486,7 +3515,8 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb, + } + + #define MACSEC_FEATURES \ +- (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST) ++ (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ ++ NETIF_F_HW_VLAN_STAG_FILTER | NETIF_F_HW_VLAN_CTAG_FILTER) + + #define MACSEC_OFFLOAD_FEATURES \ + (MACSEC_FEATURES | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES | \ +@@ -3707,6 +3737,29 @@ static int macsec_set_mac_address(struct net_device *dev, void *p) + return err; + } + ++static int macsec_vlan_rx_add_vid(struct net_device *dev, ++ __be16 proto, u16 vid) ++{ ++ struct macsec_dev *macsec = netdev_priv(dev); ++ ++ if (!macsec_is_offloaded(macsec)) ++ return 0; ++ ++ return vlan_vid_add(macsec->real_dev, proto, vid); ++} ++ ++static int macsec_vlan_rx_kill_vid(struct net_device *dev, ++ __be16 proto, u16 vid) ++{ ++ struct macsec_dev *macsec = netdev_priv(dev); ++ ++ if (!macsec_is_offloaded(macsec)) ++ return 0; ++ ++ vlan_vid_del(macsec->real_dev, proto, vid); ++ return 0; ++} ++ + static int macsec_change_mtu(struct net_device *dev, int new_mtu) + { + struct macsec_dev *macsec = macsec_priv(dev); +@@ -3748,6 +3801,8 @@ static const struct net_device_ops macsec_netdev_ops = { + .ndo_set_rx_mode = macsec_dev_set_rx_mode, + .ndo_change_rx_flags = macsec_dev_change_rx_flags, + .ndo_set_mac_address = macsec_set_mac_address, ++ .ndo_vlan_rx_add_vid = macsec_vlan_rx_add_vid, ++ .ndo_vlan_rx_kill_vid = macsec_vlan_rx_kill_vid, + .ndo_start_xmit = macsec_start_xmit, + .ndo_get_stats64 = macsec_get_stats64, + .ndo_get_iflink = macsec_get_iflink, +@@ -3912,7 +3967,7 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[], + offload = nla_get_u8(data[IFLA_MACSEC_OFFLOAD]); + if (macsec->offload != offload) { + macsec_offload_state_change = true; +- ret = macsec_update_offload(dev, offload); ++ ret = macsec_update_offload(dev, offload, extack); + if (ret) + goto cleanup; + } +-- +2.53.0 + diff --git a/queue-7.0/macvlan-annotate-data-races-around-port-bc_queue_len.patch b/queue-7.0/macvlan-annotate-data-races-around-port-bc_queue_len.patch new file mode 100644 index 0000000000..209e8ed00e --- /dev/null +++ b/queue-7.0/macvlan-annotate-data-races-around-port-bc_queue_len.patch @@ -0,0 +1,67 @@ +From 86145d70605e4edc9690d2a5fa3aa56414c1665a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:38:08 +0000 +Subject: macvlan: annotate data-races around port->bc_queue_len_used + +From: Eric Dumazet + +[ Upstream commit 1ef5789d9906df3771c99b7f413caaf2bf473ca5 ] + +port->bc_queue_len_used is read and written locklessly, +add READ_ONCE()/WRITE_ONCE() annotations. + +While WRITE_ONCE() in macvlan_fill_info() is not yet needed, +it is a prereq for future RTNL avoidance. + +Fixes: d4bff72c8401 ("macvlan: Support for high multicast packet rate") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260401103809.3038139-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index a71f058eceef0..1bbb3868f51d2 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -352,6 +352,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + const struct macvlan_dev *src, + struct sk_buff *skb) + { ++ u32 bc_queue_len_used = READ_ONCE(port->bc_queue_len_used); + struct sk_buff *nskb; + int err = -ENOMEM; + +@@ -362,7 +363,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, + MACVLAN_SKB_CB(nskb)->src = src; + + spin_lock(&port->bc_queue.lock); +- if (skb_queue_len(&port->bc_queue) < port->bc_queue_len_used) { ++ if (skb_queue_len(&port->bc_queue) < bc_queue_len_used) { + if (src) + dev_hold(src->dev); + __skb_queue_tail(&port->bc_queue, nskb); +@@ -1727,7 +1728,8 @@ static int macvlan_fill_info(struct sk_buff *skb, + } + if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN, vlan->bc_queue_len_req)) + goto nla_put_failure; +- if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, port->bc_queue_len_used)) ++ if (nla_put_u32(skb, IFLA_MACVLAN_BC_QUEUE_LEN_USED, ++ READ_ONCE(port->bc_queue_len_used))) + goto nla_put_failure; + if (port->bc_cutoff != 1 && + nla_put_s32(skb, IFLA_MACVLAN_BC_CUTOFF, port->bc_cutoff)) +@@ -1787,7 +1789,7 @@ static void update_port_bc_queue_len(struct macvlan_port *port) + if (vlan->bc_queue_len_req > max_bc_queue_len_req) + max_bc_queue_len_req = vlan->bc_queue_len_req; + } +- port->bc_queue_len_used = max_bc_queue_len_req; ++ WRITE_ONCE(port->bc_queue_len_used, max_bc_queue_len_req); + } + + static int macvlan_device_event(struct notifier_block *unused, +-- +2.53.0 + diff --git a/queue-7.0/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch b/queue-7.0/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch new file mode 100644 index 0000000000..df7d8676ad --- /dev/null +++ b/queue-7.0/macvlan-fix-macvlan_get_size-not-reserving-space-for.patch @@ -0,0 +1,56 @@ +From e4740ce5fa51b16b58b37ce6be9b6721df2fb669 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:53:49 +0800 +Subject: macvlan: fix macvlan_get_size() not reserving space for + IFLA_MACVLAN_BC_CUTOFF + +From: Dudu Lu + +[ Upstream commit fa92a77b0ed4d5f11a71665a232ac5a54a4b055d ] + +macvlan_get_size() does not account for IFLA_MACVLAN_BC_CUTOFF, but +macvlan_fill_info() conditionally includes it when port->bc_cutoff != 1. +This causes nla_put_s32() to fail with -EMSGSIZE when the netlink skb +runs out of space, triggering a WARN_ON in rtnetlink and preventing the +interface from being dumped. + +The bug can be reproduced with: + + ip link add macvlan0 link eth0 type macvlan mode bridge + ip link set macvlan0 type macvlan bc_cutoff 0 + ip -d link show macvlan0 # fails with -EMSGSIZE + +The bc_cutoff feature was added in commit 954d1fa1ac93 ("macvlan: Add +netlink attribute for broadcast cutoff"), which added the nla_put_s32() +call in macvlan_fill_info() but missed adding the corresponding +nla_total_size(4) in macvlan_get_size(). A follow-up commit +55cef78c244d ("macvlan: add forgotten nla_policy for +IFLA_MACVLAN_BC_CUTOFF") fixed the missing nla_policy entry but still +did not fix the size calculation. + +Fixes: 954d1fa1ac93 ("macvlan: Add netlink attribute for broadcast cutoff") +Signed-off-by: Dudu Lu +Reviewed-by: Vadim Fedorenko +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260413085349.73977-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/macvlan.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index 1bbb3868f51d2..3073d67d0dffc 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -1682,6 +1682,7 @@ static size_t macvlan_get_size(const struct net_device *dev) + + macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN */ + + nla_total_size(4) /* IFLA_MACVLAN_BC_QUEUE_LEN_USED */ ++ + nla_total_size(4) /* IFLA_MACVLAN_BC_CUTOFF */ + ); + } + +-- +2.53.0 + diff --git a/queue-7.0/mailbox-add-sanity-check-for-channel-array.patch b/queue-7.0/mailbox-add-sanity-check-for-channel-array.patch new file mode 100644 index 0000000000..2aeae1fa53 --- /dev/null +++ b/queue-7.0/mailbox-add-sanity-check-for-channel-array.patch @@ -0,0 +1,40 @@ +From 046e3f9659624e11647869ecf2cc02140e9f9b22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 12:42:38 +0200 +Subject: mailbox: add sanity check for channel array + +From: Wolfram Sang + +[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ] + +Fail gracefully if there is no channel array attached to the mailbox +controller. Otherwise the later dereference will cause an OOPS which +might not be seen because mailbox controllers might instantiate very +early. Remove the comment explaining the obvious while here. + +Fixes: 2b6d83e2b8b7 ("mailbox: Introduce framework for mailbox") +Signed-off-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c +index 617ba505691d3..b77162db509f2 100644 +--- a/drivers/mailbox/mailbox.c ++++ b/drivers/mailbox/mailbox.c +@@ -505,8 +505,7 @@ int mbox_controller_register(struct mbox_controller *mbox) + { + int i, txdone; + +- /* Sanity check */ +- if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) ++ if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans) + return -EINVAL; + + if (mbox->txdone_irq) +-- +2.53.0 + diff --git a/queue-7.0/mailbox-mailbox-test-don-t-free-the-reused-channel.patch b/queue-7.0/mailbox-mailbox-test-don-t-free-the-reused-channel.patch new file mode 100644 index 0000000000..bac5e747b6 --- /dev/null +++ b/queue-7.0/mailbox-mailbox-test-don-t-free-the-reused-channel.patch @@ -0,0 +1,46 @@ +From 8f0d331ffecefff0ef89cba641fb48ebf3e2a424 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:34 +0200 +Subject: mailbox: mailbox-test: don't free the reused channel + +From: Wolfram Sang + +[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ] + +The RX channel can be aliased to the TX channel if it has a different +MMIO. This special case needs to be handled when freeing the channels +otherwise a double-free occurs. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 1ceb58994772a..95238edec68ab 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -422,7 +422,7 @@ static int mbox_test_probe(struct platform_device *pdev) + err_free_chans: + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + return ret; + } +@@ -435,7 +435,7 @@ static void mbox_test_remove(struct platform_device *pdev) + + if (tdev->tx_channel) + mbox_free_channel(tdev->tx_channel); +- if (tdev->rx_channel) ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) + mbox_free_channel(tdev->rx_channel); + } + +-- +2.53.0 + diff --git a/queue-7.0/mailbox-mailbox-test-free-channels-on-probe-error.patch b/queue-7.0/mailbox-mailbox-test-free-channels-on-probe-error.patch new file mode 100644 index 0000000000..231cc4cd1f --- /dev/null +++ b/queue-7.0/mailbox-mailbox-test-free-channels-on-probe-error.patch @@ -0,0 +1,60 @@ +From 8a5ac1d9a753dcf0ea8ee95a0d5d3ef456c2fdea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 14:53:00 +0200 +Subject: mailbox: mailbox-test: free channels on probe error + +From: Wolfram Sang + +[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ] + +On probe error, free the previously obtained channels. This not only +prevents a leak, but also UAF scenarios because the client structure +will be removed nonetheless because it was allocated with devm. + +Link: https://sashiko.dev/#/patchset/20260327151217.5327-2-wsa%2Brenesas%40sang-engineering.com +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 3a28ab5c42e57..197cad7b3d401 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -404,18 +404,27 @@ static int mbox_test_probe(struct platform_device *pdev) + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +- if (!tdev->rx_buffer) +- return -ENOMEM; ++ if (!tdev->rx_buffer) { ++ ret = -ENOMEM; ++ goto err_free_chans; ++ } + } + + ret = mbox_test_add_debugfs(pdev, tdev); + if (ret) +- return ret; ++ goto err_free_chans; + + init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; ++ ++err_free_chans: ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ if (tdev->rx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ return ret; + } + + static void mbox_test_remove(struct platform_device *pdev) +-- +2.53.0 + diff --git a/queue-7.0/mailbox-mailbox-test-handle-channel-errors-consisten.patch b/queue-7.0/mailbox-mailbox-test-handle-channel-errors-consisten.patch new file mode 100644 index 0000000000..a7a8f45fe0 --- /dev/null +++ b/queue-7.0/mailbox-mailbox-test-handle-channel-errors-consisten.patch @@ -0,0 +1,52 @@ +From c74c297062e0e9bf2629960166b76eb32d741fbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:33 +0200 +Subject: mailbox: mailbox-test: handle channel errors consistently + +From: Wolfram Sang + +[ Upstream commit dd9aa1f269000d679f4ec12b32abacfc8d921413 ] + +mbox_test_request_channel() returns either an ERR_PTR or NULL. The +callers, however, mostly checked for non-NULL which allows for bogus +code paths when an ERR_PTR is treated like a valid channel. A later +commit tried to fix it in one place but missed the other ones. Because +the ERR_PTR is only used for -ENOMEM once and is converted to +-EPROBE_DEFER anyhow, convert the callee to only return NULL which +simplifies handling a lot and makes it less error prone. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Fixes: 9b63a810c6f9 ("mailbox: mailbox-test: Fix an error check in mbox_test_probe()") +Signed-off-by: Wolfram Sang +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 197cad7b3d401..1ceb58994772a 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -336,7 +336,7 @@ mbox_test_request_channel(struct platform_device *pdev, const char *name) + + client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); + if (!client) +- return ERR_PTR(-ENOMEM); ++ return NULL; + + client->dev = &pdev->dev; + client->rx_callback = mbox_test_receive_message; +@@ -388,7 +388,7 @@ static int mbox_test_probe(struct platform_device *pdev) + tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); + tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); + +- if (IS_ERR_OR_NULL(tdev->tx_channel) && IS_ERR_OR_NULL(tdev->rx_channel)) ++ if (!tdev->tx_channel && !tdev->rx_channel) + return -EPROBE_DEFER; + + /* If Rx is not specified but has Rx MMIO, then Rx = Tx */ +-- +2.53.0 + diff --git a/queue-7.0/mailbox-mailbox-test-initialize-struct-earlier.patch b/queue-7.0/mailbox-mailbox-test-initialize-struct-earlier.patch new file mode 100644 index 0000000000..1e3269dd14 --- /dev/null +++ b/queue-7.0/mailbox-mailbox-test-initialize-struct-earlier.patch @@ -0,0 +1,64 @@ +From de52b7dea07ea3fca24cf886e3de46dc1a892c2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:35 +0200 +Subject: mailbox: mailbox-test: initialize struct earlier + +From: Wolfram Sang + +[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ] + +The waitqueue must be initialized before the debugfs files are created +because from that time, requests from userspace can already be made. +Similarily, drvdata and spinlock needs to be initialized before we +request the channel, otherwise dangling irqs might run into problems +like a NULL pointer exception. + +Fixes: 8ea4484d0c2b ("mailbox: Add generic mechanism for testing Mailbox Controllers") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index 95238edec68ab..b341a64a1e312 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -366,6 +366,12 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev) + return -ENOMEM; + ++ tdev->dev = &pdev->dev; ++ spin_lock_init(&tdev->lock); ++ mutex_init(&tdev->mutex); ++ init_waitqueue_head(&tdev->waitq); ++ platform_set_drvdata(pdev, tdev); ++ + /* It's okay for MMIO to be NULL */ + tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { +@@ -395,12 +401,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) + tdev->rx_channel = tdev->tx_channel; + +- tdev->dev = &pdev->dev; +- platform_set_drvdata(pdev, tdev); +- +- spin_lock_init(&tdev->lock); +- mutex_init(&tdev->mutex); +- + if (tdev->rx_channel) { + tdev->rx_buffer = devm_kzalloc(&pdev->dev, + MBOX_MAX_MSG_LEN, GFP_KERNEL); +@@ -414,7 +414,6 @@ static int mbox_test_probe(struct platform_device *pdev) + if (ret) + goto err_free_chans; + +- init_waitqueue_head(&tdev->waitq); + dev_info(&pdev->dev, "Successfully registered\n"); + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch b/queue-7.0/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch new file mode 100644 index 0000000000..a1f482c890 --- /dev/null +++ b/queue-7.0/mailbox-mailbox-test-make-data_ready-a-per-instance-.patch @@ -0,0 +1,73 @@ +From 90a28f6e88790e4e70b800b4579b97d580cd311f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 09:42:36 +0200 +Subject: mailbox: mailbox-test: make data_ready a per-instance variable + +From: Wolfram Sang + +[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ] + +While not the default case, multiple tests can be run simultaneously. +Then, data_ready being a global variable will be overwritten and the +per-instance lock will not help. Turn the global variable into a +per-instance one to avoid this problem. + +Fixes: e339c80af95e ("mailbox: mailbox-test: don't rely on rx_buffer content to signal data ready") +Signed-off-by: Wolfram Sang +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mailbox-test.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c +index b341a64a1e312..41c8c7f3da9d8 100644 +--- a/drivers/mailbox/mailbox-test.c ++++ b/drivers/mailbox/mailbox-test.c +@@ -28,8 +28,6 @@ + #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ + (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) + +-static bool mbox_data_ready; +- + struct mbox_test_device { + struct device *dev; + void __iomem *tx_mmio; +@@ -42,6 +40,7 @@ struct mbox_test_device { + spinlock_t lock; + struct mutex mutex; + wait_queue_head_t waitq; ++ bool data_ready; + struct fasync_struct *async_queue; + struct dentry *root_debugfs_dir; + }; +@@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); +- data_ready = mbox_data_ready; ++ data_ready = tdev->data_ready; + spin_unlock_irqrestore(&tdev->lock, flags); + + return data_ready; +@@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, + *(touser + l) = '\0'; + + memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); +- mbox_data_ready = false; ++ tdev->data_ready = false; + + spin_unlock_irqrestore(&tdev->lock, flags); + +@@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) + message, MBOX_MAX_MSG_LEN); + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); + } +- mbox_data_ready = true; ++ tdev->data_ready = true; + spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); +-- +2.53.0 + diff --git a/queue-7.0/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch b/queue-7.0/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch new file mode 100644 index 0000000000..c4b5a21ccd --- /dev/null +++ b/queue-7.0/mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch @@ -0,0 +1,48 @@ +From 4e090ba28b951b099c973c86a0bdb5398acbd4a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:07:11 +0800 +Subject: mailbox: mtk-cmdq: Fix CURR and END addr for task insert case + +From: Jason-JH Lin + +[ Upstream commit d2591db9c8ef19fbb4d24ed15e0c6edfa6bc7917 ] + +Fix CURR and END address calculation for inserting a cmdq task into the +task list by using cmdq_reg_shift_addr() for proper address converting. +This ensures both CURR and END addresses are set correctly when +enabling the thread. + +Fixes: a195c7ccfb7a ("mailbox: mtk-cmdq: Refine DMA address handling for the command buffer") +Signed-off-by: Jason-JH Lin +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mtk-cmdq-mailbox.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c +index d7c6b38888a37..547a10a8fad3a 100644 +--- a/drivers/mailbox/mtk-cmdq-mailbox.c ++++ b/drivers/mailbox/mtk-cmdq-mailbox.c +@@ -493,14 +493,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data) + if (curr_pa == end_pa - CMDQ_INST_SIZE || + curr_pa == end_pa) { + /* set to this task directly */ +- writel(task->pa_base >> cmdq->pdata->shift, +- thread->base + CMDQ_THR_CURR_ADDR); ++ gce_addr = cmdq_convert_gce_addr(task->pa_base, cmdq->pdata); ++ writel(gce_addr, thread->base + CMDQ_THR_CURR_ADDR); + } else { + cmdq_task_insert_into_thread(task); + smp_mb(); /* modify jump before enable thread */ + } +- writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift, +- thread->base + CMDQ_THR_END_ADDR); ++ gce_addr = cmdq_convert_gce_addr(task->pa_base + pkt->cmd_buf_size, cmdq->pdata); ++ writel(gce_addr, thread->base + CMDQ_THR_END_ADDR); + cmdq_thread_resume(thread); + } + list_move_tail(&task->list_entry, &thread->task_busy_list); +-- +2.53.0 + diff --git a/queue-7.0/mailbox-mtk-vcp-mailbox-fix-the-return-value-in-mtk_.patch b/queue-7.0/mailbox-mtk-vcp-mailbox-fix-the-return-value-in-mtk_.patch new file mode 100644 index 0000000000..362875f4a8 --- /dev/null +++ b/queue-7.0/mailbox-mtk-vcp-mailbox-fix-the-return-value-in-mtk_.patch @@ -0,0 +1,37 @@ +From ed1a36a8135e4497dca114b7f224d1e6b49f15c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 00:33:24 +0800 +Subject: mailbox: mtk-vcp-mailbox: Fix the return value in + mtk_vcp_mbox_xlate() + +From: Felix Gu + +[ Upstream commit 1e0ec9719f58d53da61adf830e81f4af892e4582 ] + +The return value of mtk_vcp_mbox_xlate() is checked by IS_ERR(), so +return NULL is incorrect and could lead to a NULL pointer dereference. + +Fixes: b562abd95672 ("mailbox: mediatek: Add mtk-vcp-mailbox driver") +Signed-off-by: Felix Gu +Signed-off-by: Jassi Brar +Signed-off-by: Sasha Levin +--- + drivers/mailbox/mtk-vcp-mailbox.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mailbox/mtk-vcp-mailbox.c b/drivers/mailbox/mtk-vcp-mailbox.c +index cedad575528fb..1b291b8ea15ac 100644 +--- a/drivers/mailbox/mtk-vcp-mailbox.c ++++ b/drivers/mailbox/mtk-vcp-mailbox.c +@@ -50,7 +50,7 @@ static struct mbox_chan *mtk_vcp_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *sp) + { + if (sp->args_count) +- return NULL; ++ return ERR_PTR(-EINVAL); + + return &mbox->chans[0]; + } +-- +2.53.0 + diff --git a/queue-7.0/md-add-fallback-to-correct-bitmap_ops-on-version-mis.patch b/queue-7.0/md-add-fallback-to-correct-bitmap_ops-on-version-mis.patch new file mode 100644 index 0000000000..2c75bbbe39 --- /dev/null +++ b/queue-7.0/md-add-fallback-to-correct-bitmap_ops-on-version-mis.patch @@ -0,0 +1,154 @@ +From ac04083ec12671a5ac4d09bd43bb9341275eea29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 13:46:42 +0800 +Subject: md: add fallback to correct bitmap_ops on version mismatch + +From: Yu Kuai + +[ Upstream commit 09af773650024279a60348e7319d599e6571b15c ] + +If default bitmap version and on-disk version doesn't match, and mdadm +is not the latest version to set bitmap_type, set bitmap_ops based on +the disk version. + +Link: https://lore.kernel.org/linux-raid/20260323054644.3351791-2-yukuai@fnnas.com/ +Signed-off-by: Yu Kuai +Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow") +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 110 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 9c552904a5ddc..99a5ba1485565 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -6465,15 +6465,124 @@ static void md_safemode_timeout(struct timer_list *t) + + static int start_dirty_degraded; + ++/* ++ * Read bitmap superblock and return the bitmap_id based on disk version. ++ * This is used as fallback when default bitmap version and on-disk version ++ * doesn't match, and mdadm is not the latest version to set bitmap_type. ++ */ ++static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev) ++{ ++ struct md_rdev *rdev; ++ struct page *sb_page; ++ bitmap_super_t *sb; ++ enum md_submodule_id id = ID_BITMAP_NONE; ++ sector_t sector; ++ u32 version; ++ ++ if (!mddev->bitmap_info.offset) ++ return ID_BITMAP_NONE; ++ ++ sb_page = alloc_page(GFP_KERNEL); ++ if (!sb_page) { ++ pr_warn("md: %s: failed to allocate memory for bitmap\n", ++ mdname(mddev)); ++ return ID_BITMAP_NONE; ++ } ++ ++ sector = mddev->bitmap_info.offset; ++ ++ rdev_for_each(rdev, mddev) { ++ u32 iosize; ++ ++ if (!test_bit(In_sync, &rdev->flags) || ++ test_bit(Faulty, &rdev->flags) || ++ test_bit(Bitmap_sync, &rdev->flags)) ++ continue; ++ ++ iosize = roundup(sizeof(bitmap_super_t), ++ bdev_logical_block_size(rdev->bdev)); ++ if (sync_page_io(rdev, sector, iosize, sb_page, REQ_OP_READ, ++ true)) ++ goto read_ok; ++ } ++ pr_warn("md: %s: failed to read bitmap from any device\n", ++ mdname(mddev)); ++ goto out; ++ ++read_ok: ++ sb = kmap_local_page(sb_page); ++ if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) { ++ pr_warn("md: %s: invalid bitmap magic 0x%x\n", ++ mdname(mddev), le32_to_cpu(sb->magic)); ++ goto out_unmap; ++ } ++ ++ version = le32_to_cpu(sb->version); ++ switch (version) { ++ case BITMAP_MAJOR_LO: ++ case BITMAP_MAJOR_HI: ++ case BITMAP_MAJOR_CLUSTERED: ++ id = ID_BITMAP; ++ break; ++ case BITMAP_MAJOR_LOCKLESS: ++ id = ID_LLBITMAP; ++ break; ++ default: ++ pr_warn("md: %s: unknown bitmap version %u\n", ++ mdname(mddev), version); ++ break; ++ } ++ ++out_unmap: ++ kunmap_local(sb); ++out: ++ __free_page(sb_page); ++ return id; ++} ++ + static int md_bitmap_create(struct mddev *mddev) + { ++ enum md_submodule_id orig_id = mddev->bitmap_id; ++ enum md_submodule_id sb_id; ++ int err; ++ + if (mddev->bitmap_id == ID_BITMAP_NONE) + return -EINVAL; + + if (!mddev_set_bitmap_ops(mddev)) + return -ENOENT; + +- return mddev->bitmap_ops->create(mddev); ++ err = mddev->bitmap_ops->create(mddev); ++ if (!err) ++ return 0; ++ ++ /* ++ * Create failed, if default bitmap version and on-disk version ++ * doesn't match, and mdadm is not the latest version to set ++ * bitmap_type, set bitmap_ops based on the disk version. ++ */ ++ mddev_clear_bitmap_ops(mddev); ++ ++ sb_id = md_bitmap_get_id_from_sb(mddev); ++ if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) ++ return err; ++ ++ pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n", ++ mdname(mddev), orig_id, sb_id); ++ ++ mddev->bitmap_id = sb_id; ++ if (!mddev_set_bitmap_ops(mddev)) { ++ mddev->bitmap_id = orig_id; ++ return -ENOENT; ++ } ++ ++ err = mddev->bitmap_ops->create(mddev); ++ if (err) { ++ mddev_clear_bitmap_ops(mddev); ++ mddev->bitmap_id = orig_id; ++ } ++ ++ return err; + } + + static void md_bitmap_destroy(struct mddev *mddev) +-- +2.53.0 + diff --git a/queue-7.0/md-factor-bitmap-creation-away-from-sysfs-handling.patch b/queue-7.0/md-factor-bitmap-creation-away-from-sysfs-handling.patch new file mode 100644 index 0000000000..b6ebd11423 --- /dev/null +++ b/queue-7.0/md-factor-bitmap-creation-away-from-sysfs-handling.patch @@ -0,0 +1,176 @@ +From 023130957628098446ba8ec263152be29e15b3df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:46:13 +0800 +Subject: md: factor bitmap creation away from sysfs handling + +From: Yu Kuai + +[ Upstream commit 8776d342cf8fa0b98ca5e6fb2d956966fb5ca364 ] + +Factor bitmap creation and destruction into helpers that do not touch +bitmap sysfs registration. + +This prepares the bitmap sysfs rework so callers such as the sysfs +bitmap location path can create or destroy a bitmap backend without +coupling that to sysfs group lifetime management. + +Reviewed-by: Su Yue +Link: https://lore.kernel.org/r/20260425024615.1696892-2-yukuai@fnnas.com +Signed-off-by: Yu Kuai +Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow") +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 78 +++++++++++++++++++++++++++++++------------------ + 1 file changed, 49 insertions(+), 29 deletions(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 99a5ba1485565..3b58d94c1c7aa 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -688,7 +688,25 @@ static void active_io_release(struct percpu_ref *ref) + + static void no_op(struct percpu_ref *r) {} + +-static bool mddev_set_bitmap_ops(struct mddev *mddev) ++static void md_bitmap_sysfs_add(struct mddev *mddev) ++{ ++ if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group)) ++ pr_warn("md: cannot register extra bitmap attributes for %s\n", ++ mdname(mddev)); ++ else ++ /* ++ * Inform user with KOBJ_CHANGE about new bitmap ++ * attributes. ++ */ ++ kobject_uevent(&mddev->kobj, KOBJ_CHANGE); ++} ++ ++static void md_bitmap_sysfs_del(struct mddev *mddev) ++{ ++ sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group); ++} ++ ++static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) + { + struct bitmap_operations *old = mddev->bitmap_ops; + struct md_submodule_head *head; +@@ -712,18 +730,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev) + + mddev->bitmap_ops = (void *)head; + xa_unlock(&md_submodule); +- +- if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) { +- if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group)) +- pr_warn("md: cannot register extra bitmap attributes for %s\n", +- mdname(mddev)); +- else +- /* +- * Inform user with KOBJ_CHANGE about new bitmap +- * attributes. +- */ +- kobject_uevent(&mddev->kobj, KOBJ_CHANGE); +- } + return true; + + err: +@@ -731,15 +737,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev) + return false; + } + +-static void mddev_clear_bitmap_ops(struct mddev *mddev) +-{ +- if (!mddev_is_dm(mddev) && mddev->bitmap_ops && +- mddev->bitmap_ops->group) +- sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group); +- +- mddev->bitmap_ops = NULL; +-} +- + int mddev_init(struct mddev *mddev) + { + int err = 0; +@@ -6540,7 +6537,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev) + return id; + } + +-static int md_bitmap_create(struct mddev *mddev) ++static int md_bitmap_create_nosysfs(struct mddev *mddev) + { + enum md_submodule_id orig_id = mddev->bitmap_id; + enum md_submodule_id sb_id; +@@ -6549,7 +6546,7 @@ static int md_bitmap_create(struct mddev *mddev) + if (mddev->bitmap_id == ID_BITMAP_NONE) + return -EINVAL; + +- if (!mddev_set_bitmap_ops(mddev)) ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) + return -ENOENT; + + err = mddev->bitmap_ops->create(mddev); +@@ -6561,7 +6558,7 @@ static int md_bitmap_create(struct mddev *mddev) + * doesn't match, and mdadm is not the latest version to set + * bitmap_type, set bitmap_ops based on the disk version. + */ +- mddev_clear_bitmap_ops(mddev); ++ mddev->bitmap_ops = NULL; + + sb_id = md_bitmap_get_id_from_sb(mddev); + if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) +@@ -6571,27 +6568,50 @@ static int md_bitmap_create(struct mddev *mddev) + mdname(mddev), orig_id, sb_id); + + mddev->bitmap_id = sb_id; +- if (!mddev_set_bitmap_ops(mddev)) { ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) { + mddev->bitmap_id = orig_id; + return -ENOENT; + } + + err = mddev->bitmap_ops->create(mddev); + if (err) { +- mddev_clear_bitmap_ops(mddev); ++ mddev->bitmap_ops = NULL; + mddev->bitmap_id = orig_id; + } + + return err; + } + +-static void md_bitmap_destroy(struct mddev *mddev) ++static int md_bitmap_create(struct mddev *mddev) ++{ ++ int err; ++ ++ err = md_bitmap_create_nosysfs(mddev); ++ if (err) ++ return err; ++ ++ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) ++ md_bitmap_sysfs_add(mddev); ++ ++ return 0; ++} ++ ++static void md_bitmap_destroy_nosysfs(struct mddev *mddev) + { + if (!md_bitmap_registered(mddev)) + return; + + mddev->bitmap_ops->destroy(mddev); +- mddev_clear_bitmap_ops(mddev); ++ mddev->bitmap_ops = NULL; ++} ++ ++static void md_bitmap_destroy(struct mddev *mddev) ++{ ++ if (!mddev_is_dm(mddev) && mddev->bitmap_ops && ++ mddev->bitmap_ops->group) ++ md_bitmap_sysfs_del(mddev); ++ ++ md_bitmap_destroy_nosysfs(mddev); + } + + int md_run(struct mddev *mddev) +-- +2.53.0 + diff --git a/queue-7.0/md-fix-array_state-clear-sysfs-deadlock.patch b/queue-7.0/md-fix-array_state-clear-sysfs-deadlock.patch new file mode 100644 index 0000000000..ee3e97e55d --- /dev/null +++ b/queue-7.0/md-fix-array_state-clear-sysfs-deadlock.patch @@ -0,0 +1,100 @@ +From 6e0d1018043b98f22d39d5ade6227d756590c662 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 13:52:13 +0800 +Subject: md: fix array_state=clear sysfs deadlock + +From: Yu Kuai + +[ Upstream commit 2aa72276fab9851dbd59c2daeb4b590c5a113908 ] + +When "clear" is written to array_state, md_attr_store() breaks sysfs +active protection so the array can delete itself from its own sysfs +store method. + +However, md_attr_store() currently drops the mddev reference before +calling sysfs_unbreak_active_protection(). Once do_md_stop(..., 0) +has made the mddev eligible for delayed deletion, the temporary +kobject reference taken by sysfs_break_active_protection() can become +the last kobject reference protecting the md kobject. + +That allows sysfs_unbreak_active_protection() to drop the last +kobject reference from the current sysfs writer context. kobject +teardown then recurses into kernfs removal while the current sysfs +node is still being unwound, and lockdep reports recursive locking on +kn->active with kernfs_drain() in the call chain. + +Reproducer on an existing level: +1. Create an md0 linear array and activate it: + mknod /dev/md0 b 9 0 + echo none > /sys/block/md0/md/metadata_version + echo linear > /sys/block/md0/md/level + echo 1 > /sys/block/md0/md/raid_disks + echo "$(cat /sys/class/block/sdb/dev)" > /sys/block/md0/md/new_dev + echo "$(($(cat /sys/class/block/sdb/size) / 2))" > \ + /sys/block/md0/md/dev-sdb/size + echo 0 > /sys/block/md0/md/dev-sdb/slot + echo active > /sys/block/md0/md/array_state +2. Wait briefly for the array to settle, then clear it: + sleep 2 + echo clear > /sys/block/md0/md/array_state + +The warning looks like: + + WARNING: possible recursive locking detected + bash/588 is trying to acquire lock: + (kn->active#65) at __kernfs_remove+0x157/0x1d0 + but task is already holding lock: + (kn->active#65) at sysfs_unbreak_active_protection+0x1f/0x40 + ... + Call Trace: + kernfs_drain + __kernfs_remove + kernfs_remove_by_name_ns + sysfs_remove_group + sysfs_remove_groups + __kobject_del + kobject_put + md_attr_store + kernfs_fop_write_iter + vfs_write + ksys_write + +Restore active protection before mddev_put() so the extra sysfs +kobject reference is dropped while the mddev is still held alive. The +actual md kobject deletion is then deferred until after the sysfs +write path has fully returned. + +Fixes: 9e59d609763f ("md: call del_gendisk in control path") +Reviewed-by: Xiao Ni +Link: https://lore.kernel.org/linux-raid/20260330055213.3976052-1-yukuai@fnnas.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index c2cc2302d727d..ecb9bd0e1b8f7 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -6130,10 +6130,16 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, + } + spin_unlock(&all_mddevs_lock); + rv = entry->store(mddev, page, length); +- mddev_put(mddev); + ++ /* ++ * For "array_state=clear", dropping the extra kobject reference from ++ * sysfs_break_active_protection() can trigger md kobject deletion. ++ * Restore active protection before mddev_put() so deletion happens ++ * after the sysfs write path fully unwinds. ++ */ + if (kn) + sysfs_unbreak_active_protection(kn); ++ mddev_put(mddev); + + return rv; + } +-- +2.53.0 + diff --git a/queue-7.0/md-md-bitmap-add-a-none-backend-for-bitmap-grow.patch b/queue-7.0/md-md-bitmap-add-a-none-backend-for-bitmap-grow.patch new file mode 100644 index 0000000000..7663f7d3a7 --- /dev/null +++ b/queue-7.0/md-md-bitmap-add-a-none-backend-for-bitmap-grow.patch @@ -0,0 +1,362 @@ +From d2c0bf4a5bb1bc905749e01d04201da7cc715241 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:46:15 +0800 +Subject: md/md-bitmap: add a none backend for bitmap grow + +From: Yu Kuai + +[ Upstream commit f2926a533d03fe70d753b512b713e06a2aa174af ] + +Add a real none bitmap backend that exposes the common bitmap sysfs +group and use it to keep bitmap/location available when an array has no +bitmap. + +Then switch the bitmap location sysfs path to move only between none +and the classic bitmap backend, using the no-sysfs bitmap helpers while +merging or unmerging the internal bitmap sysfs group. + +This restores mdadm --grow bitmap addition through bitmap/location. + +Fixes: fb8cc3b0d9db ("md/md-bitmap: delay registration of bitmap_ops until creating bitmap") +Reviewed-by: Su Yue +Link: https://lore.kernel.org/r/20260425024615.1696892-4-yukuai@fnnas.com +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md-bitmap.c | 108 ++++++++++++++++++++++++++++++++++++++--- + drivers/md/md.c | 42 +++++++++++++--- + drivers/md/md.h | 3 ++ + 3 files changed, 137 insertions(+), 16 deletions(-) + +diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c +index eba649703a1c0..028b9ca8ce52d 100644 +--- a/drivers/md/md-bitmap.c ++++ b/drivers/md/md-bitmap.c +@@ -216,6 +216,7 @@ struct bitmap { + }; + + static struct workqueue_struct *md_bitmap_wq; ++static struct attribute_group md_bitmap_internal_group; + + static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks, + int chunksize, bool init); +@@ -2580,6 +2581,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize) + return __bitmap_resize(bitmap, blocks, chunksize, false); + } + ++static bool bitmap_none_enabled(void *data, bool flush) ++{ ++ return false; ++} ++ ++static int bitmap_none_create(struct mddev *mddev) ++{ ++ return 0; ++} ++ ++static int bitmap_none_load(struct mddev *mddev) ++{ ++ return 0; ++} ++ ++static void bitmap_none_destroy(struct mddev *mddev) ++{ ++} ++ ++static int bitmap_none_get_stats(void *data, struct md_bitmap_stats *stats) ++{ ++ return -ENOENT; ++} ++ + static ssize_t + location_show(struct mddev *mddev, char *page) + { +@@ -2618,7 +2643,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len) + goto out; + } + +- bitmap_destroy(mddev); ++ sysfs_unmerge_group(&mddev->kobj, &md_bitmap_internal_group); ++ md_bitmap_destroy_nosysfs(mddev); ++ mddev->bitmap_id = ID_BITMAP_NONE; ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ goto none_err; + mddev->bitmap_info.offset = 0; + if (mddev->bitmap_info.file) { + struct file *f = mddev->bitmap_info.file; +@@ -2654,16 +2683,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len) + } + + mddev->bitmap_info.offset = offset; +- rv = bitmap_create(mddev); ++ md_bitmap_destroy_nosysfs(mddev); ++ mddev->bitmap_id = ID_BITMAP; ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ goto bitmap_err; ++ ++ rv = md_bitmap_create_nosysfs(mddev); + if (rv) +- goto out; ++ goto create_err; + +- rv = bitmap_load(mddev); ++ rv = mddev->bitmap_ops->load(mddev); + if (rv) { + mddev->bitmap_info.offset = 0; +- bitmap_destroy(mddev); +- goto out; ++ goto load_err; + } ++ ++ rv = sysfs_merge_group(&mddev->kobj, ++ &md_bitmap_internal_group); ++ if (rv) ++ goto merge_err; + } + } + if (!mddev->external) { +@@ -2679,6 +2717,22 @@ location_store(struct mddev *mddev, const char *buf, size_t len) + if (rv) + return rv; + return len; ++ ++merge_err: ++ mddev->bitmap_info.offset = 0; ++load_err: ++ md_bitmap_destroy_nosysfs(mddev); ++create_err: ++ mddev->bitmap_info.offset = 0; ++ mddev->bitmap_id = ID_BITMAP_NONE; ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ rv = -ENOENT; ++ goto out; ++bitmap_err: ++ rv = -ENOENT; ++none_err: ++ mddev->bitmap_info.offset = 0; ++ goto out; + } + + static struct md_sysfs_entry bitmap_location = +@@ -2987,6 +3041,27 @@ static const struct attribute_group *bitmap_groups[] = { + NULL, + }; + ++static const struct attribute_group *bitmap_none_groups[] = { ++ &md_bitmap_common_group, ++ NULL, ++}; ++ ++static struct bitmap_operations bitmap_none_ops = { ++ .head = { ++ .type = MD_BITMAP, ++ .id = ID_BITMAP_NONE, ++ .name = "none", ++ }, ++ ++ .enabled = bitmap_none_enabled, ++ .create = bitmap_none_create, ++ .load = bitmap_none_load, ++ .destroy = bitmap_none_destroy, ++ .get_stats = bitmap_none_get_stats, ++ ++ .groups = bitmap_none_groups, ++}; ++ + static struct bitmap_operations bitmap_ops = { + .head = { + .type = MD_BITMAP, +@@ -3033,16 +3108,33 @@ static struct bitmap_operations bitmap_ops = { + + int md_bitmap_init(void) + { ++ int err; ++ + md_bitmap_wq = alloc_workqueue("md_bitmap", WQ_MEM_RECLAIM | WQ_UNBOUND, + 0); + if (!md_bitmap_wq) + return -ENOMEM; + +- return register_md_submodule(&bitmap_ops.head); ++ err = register_md_submodule(&bitmap_none_ops.head); ++ if (err) ++ goto err_wq; ++ ++ err = register_md_submodule(&bitmap_ops.head); ++ if (err) ++ goto err_none; ++ ++ return 0; ++ ++err_none: ++ unregister_md_submodule(&bitmap_none_ops.head); ++err_wq: ++ destroy_workqueue(md_bitmap_wq); ++ return err; + } + + void md_bitmap_exit(void) + { +- destroy_workqueue(md_bitmap_wq); + unregister_md_submodule(&bitmap_ops.head); ++ unregister_md_submodule(&bitmap_none_ops.head); ++ destroy_workqueue(md_bitmap_wq); + } +diff --git a/drivers/md/md.c b/drivers/md/md.c +index f736aead193ba..32927c24ebf7c 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -714,7 +714,7 @@ static void md_bitmap_sysfs_del(struct mddev *mddev) + sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]); + } + +-static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) ++bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) + { + struct md_submodule_head *head; + +@@ -4284,7 +4284,7 @@ bitmap_type_show(struct mddev *mddev, char *page) + + xa_lock(&md_submodule); + xa_for_each(&md_submodule, i, head) { +- if (head->type != MD_BITMAP) ++ if (head->type != MD_BITMAP || head->id == ID_BITMAP_NONE) + continue; + + if (mddev->bitmap_id == head->id) +@@ -6544,7 +6544,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev) + return id; + } + +-static int md_bitmap_create_nosysfs(struct mddev *mddev) ++int md_bitmap_create_nosysfs(struct mddev *mddev) + { + enum md_submodule_id orig_id = mddev->bitmap_id; + enum md_submodule_id sb_id; +@@ -6553,8 +6553,10 @@ static int md_bitmap_create_nosysfs(struct mddev *mddev) + if (mddev->bitmap_id == ID_BITMAP_NONE) + return -EINVAL; + +- if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) { ++ mddev->bitmap_id = orig_id; + return -ENOENT; ++ } + + err = mddev->bitmap_ops->create(mddev); + if (!err) +@@ -6568,8 +6570,10 @@ static int md_bitmap_create_nosysfs(struct mddev *mddev) + mddev->bitmap_ops = NULL; + + sb_id = md_bitmap_get_id_from_sb(mddev); +- if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) ++ if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) { ++ mddev->bitmap_id = orig_id; + return err; ++ } + + pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n", + mdname(mddev), orig_id, sb_id); +@@ -6603,7 +6607,7 @@ static int md_bitmap_create(struct mddev *mddev) + return 0; + } + +-static void md_bitmap_destroy_nosysfs(struct mddev *mddev) ++void md_bitmap_destroy_nosysfs(struct mddev *mddev) + { + if (!md_bitmap_registered(mddev)) + return; +@@ -6621,6 +6625,16 @@ static void md_bitmap_destroy(struct mddev *mddev) + md_bitmap_destroy_nosysfs(mddev); + } + ++static void md_bitmap_set_none(struct mddev *mddev) ++{ ++ mddev->bitmap_id = ID_BITMAP_NONE; ++ if (!mddev_set_bitmap_ops_nosysfs(mddev)) ++ return; ++ ++ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups) ++ md_bitmap_sysfs_add(mddev); ++} ++ + int md_run(struct mddev *mddev) + { + int err; +@@ -6830,6 +6844,10 @@ int md_run(struct mddev *mddev) + if (mddev->sb_flags) + md_update_sb(mddev, 0); + ++ if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file && ++ !mddev->bitmap_info.offset) ++ md_bitmap_set_none(mddev); ++ + md_new_event(); + return 0; + +@@ -7775,7 +7793,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd) + { + int err = 0; + +- if (!md_bitmap_registered(mddev)) ++ if (!md_bitmap_registered(mddev) || ++ mddev->bitmap_id == ID_BITMAP_NONE) + return -EINVAL; + + if (mddev->pers) { +@@ -7840,10 +7859,12 @@ static int set_bitmap_file(struct mddev *mddev, int fd) + + if (err) { + md_bitmap_destroy(mddev); ++ md_bitmap_set_none(mddev); + fd = -1; + } + } else if (fd < 0) { + md_bitmap_destroy(mddev); ++ md_bitmap_set_none(mddev); + } + } + +@@ -8150,12 +8171,16 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) + mddev->bitmap_info.default_offset; + mddev->bitmap_info.space = + mddev->bitmap_info.default_space; ++ mddev->bitmap_id = ID_BITMAP; + rv = md_bitmap_create(mddev); + if (!rv) + rv = mddev->bitmap_ops->load(mddev); + +- if (rv) ++ if (rv) { + md_bitmap_destroy(mddev); ++ mddev->bitmap_info.offset = 0; ++ md_bitmap_set_none(mddev); ++ } + } else { + struct md_bitmap_stats stats; + +@@ -8183,6 +8208,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) + } + md_bitmap_destroy(mddev); + mddev->bitmap_info.offset = 0; ++ md_bitmap_set_none(mddev); + } + } + md_update_sb(mddev, 1); +diff --git a/drivers/md/md.h b/drivers/md/md.h +index ac84289664cd7..409c8f61695d3 100644 +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -932,6 +932,9 @@ extern void md_allow_write(struct mddev *mddev); + extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev); + extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors); + extern int md_check_no_bitmap(struct mddev *mddev); ++bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev); ++int md_bitmap_create_nosysfs(struct mddev *mddev); ++void md_bitmap_destroy_nosysfs(struct mddev *mddev); + extern int md_integrity_register(struct mddev *mddev); + extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); + +-- +2.53.0 + diff --git a/queue-7.0/md-md-bitmap-split-bitmap-sysfs-groups.patch b/queue-7.0/md-md-bitmap-split-bitmap-sysfs-groups.patch new file mode 100644 index 0000000000..e8c131e9da --- /dev/null +++ b/queue-7.0/md-md-bitmap-split-bitmap-sysfs-groups.patch @@ -0,0 +1,187 @@ +From 00b9a97c6a343161dd254f5e0eda7dc9cd038785 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 10:46:14 +0800 +Subject: md/md-bitmap: split bitmap sysfs groups + +From: Yu Kuai + +[ Upstream commit aba3d6d6cb55c6e1116d1215140559dd7ecdf9a9 ] + +Split the classic bitmap sysfs files into a common bitmap group with +the location attribute and a separate internal bitmap group for the +remaining files. + +At the same time, convert bitmap operations from a single sysfs group +to a sysfs group array so backends can share part of their sysfs +layout while adding backend-specific attributes separately. + +Switch the bitmap sysfs helpers to use sysfs_update_groups() for the +add and update path, and remove groups in reverse order so shared named +groups are unmerged before the last group removes the directory. + +Also make bitmap operation lookup depend only on the currently selected +bitmap id matching the installed backend. This prepares the lookup path +for a later registered none backend. + +Reviewed-by: Su Yue +Link: https://lore.kernel.org/r/20260425024615.1696892-3-yukuai@fnnas.com +Signed-off-by: Yu Kuai +Stable-dep-of: f2926a533d03 ("md/md-bitmap: add a none backend for bitmap grow") +Signed-off-by: Sasha Levin +--- + drivers/md/md-bitmap.c | 23 +++++++++++++++++++---- + drivers/md/md-bitmap.h | 2 +- + drivers/md/md-llbitmap.c | 7 ++++++- + drivers/md/md.c | 21 ++++++++++++++------- + 4 files changed, 40 insertions(+), 13 deletions(-) + +diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c +index 83378c033c728..eba649703a1c0 100644 +--- a/drivers/md/md-bitmap.c ++++ b/drivers/md/md-bitmap.c +@@ -2955,8 +2955,12 @@ static struct md_sysfs_entry max_backlog_used = + __ATTR(max_backlog_used, S_IRUGO | S_IWUSR, + behind_writes_used_show, behind_writes_used_reset); + +-static struct attribute *md_bitmap_attrs[] = { ++static struct attribute *md_bitmap_common_attrs[] = { + &bitmap_location.attr, ++ NULL ++}; ++ ++static struct attribute *md_bitmap_internal_attrs[] = { + &bitmap_space.attr, + &bitmap_timeout.attr, + &bitmap_backlog.attr, +@@ -2967,9 +2971,20 @@ static struct attribute *md_bitmap_attrs[] = { + NULL + }; + +-static struct attribute_group md_bitmap_group = { ++static struct attribute_group md_bitmap_common_group = { ++ .name = "bitmap", ++ .attrs = md_bitmap_common_attrs, ++}; ++ ++static struct attribute_group md_bitmap_internal_group = { + .name = "bitmap", +- .attrs = md_bitmap_attrs, ++ .attrs = md_bitmap_internal_attrs, ++}; ++ ++static const struct attribute_group *bitmap_groups[] = { ++ &md_bitmap_common_group, ++ &md_bitmap_internal_group, ++ NULL, + }; + + static struct bitmap_operations bitmap_ops = { +@@ -3013,7 +3028,7 @@ static struct bitmap_operations bitmap_ops = { + .set_pages = bitmap_set_pages, + .free = md_bitmap_free, + +- .group = &md_bitmap_group, ++ .groups = bitmap_groups, + }; + + int md_bitmap_init(void) +diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h +index b42a28fa83a0f..214f623c7e790 100644 +--- a/drivers/md/md-bitmap.h ++++ b/drivers/md/md-bitmap.h +@@ -125,7 +125,7 @@ struct bitmap_operations { + void (*set_pages)(void *data, unsigned long pages); + void (*free)(void *data); + +- struct attribute_group *group; ++ const struct attribute_group **groups; + }; + + /* the bitmap API */ +diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c +index cdfecaca216bf..aeb061166e732 100644 +--- a/drivers/md/md-llbitmap.c ++++ b/drivers/md/md-llbitmap.c +@@ -1562,6 +1562,11 @@ static struct attribute_group md_llbitmap_group = { + .attrs = md_llbitmap_attrs, + }; + ++static const struct attribute_group *md_llbitmap_groups[] = { ++ &md_llbitmap_group, ++ NULL, ++}; ++ + static struct bitmap_operations llbitmap_ops = { + .head = { + .type = MD_BITMAP, +@@ -1598,7 +1603,7 @@ static struct bitmap_operations llbitmap_ops = { + .dirty_bits = llbitmap_dirty_bits, + .write_all = llbitmap_write_all, + +- .group = &md_llbitmap_group, ++ .groups = md_llbitmap_groups, + }; + + int md_llbitmap_init(void) +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 3b58d94c1c7aa..f736aead193ba 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -690,7 +690,7 @@ static void no_op(struct percpu_ref *r) {} + + static void md_bitmap_sysfs_add(struct mddev *mddev) + { +- if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group)) ++ if (sysfs_update_groups(&mddev->kobj, mddev->bitmap_ops->groups)) + pr_warn("md: cannot register extra bitmap attributes for %s\n", + mdname(mddev)); + else +@@ -703,16 +703,23 @@ static void md_bitmap_sysfs_add(struct mddev *mddev) + + static void md_bitmap_sysfs_del(struct mddev *mddev) + { +- sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group); ++ int nr_groups = 0; ++ ++ for (nr_groups = 0; mddev->bitmap_ops->groups[nr_groups]; nr_groups++) ++ ; ++ ++ while (--nr_groups >= 1) ++ sysfs_unmerge_group(&mddev->kobj, ++ mddev->bitmap_ops->groups[nr_groups]); ++ sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]); + } + + static bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev) + { +- struct bitmap_operations *old = mddev->bitmap_ops; + struct md_submodule_head *head; + +- if (mddev->bitmap_id == ID_BITMAP_NONE || +- (old && old->head.id == mddev->bitmap_id)) ++ if (mddev->bitmap_ops && ++ mddev->bitmap_ops->head.id == mddev->bitmap_id) + return true; + + xa_lock(&md_submodule); +@@ -6590,7 +6597,7 @@ static int md_bitmap_create(struct mddev *mddev) + if (err) + return err; + +- if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) ++ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups) + md_bitmap_sysfs_add(mddev); + + return 0; +@@ -6608,7 +6615,7 @@ static void md_bitmap_destroy_nosysfs(struct mddev *mddev) + static void md_bitmap_destroy(struct mddev *mddev) + { + if (!mddev_is_dm(mddev) && mddev->bitmap_ops && +- mddev->bitmap_ops->group) ++ mddev->bitmap_ops->groups) + md_bitmap_sysfs_del(mddev); + + md_bitmap_destroy_nosysfs(mddev); +-- +2.53.0 + diff --git a/queue-7.0/md-raid1-fix-the-comparing-region-of-interval-tree.patch b/queue-7.0/md-raid1-fix-the-comparing-region-of-interval-tree.patch new file mode 100644 index 0000000000..aea659b39d --- /dev/null +++ b/queue-7.0/md-raid1-fix-the-comparing-region-of-interval-tree.patch @@ -0,0 +1,51 @@ +From 856b8770c3a3c5bce0bbdaf762a1dced56d41eef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 09:18:33 +0800 +Subject: md/raid1: fix the comparing region of interval tree + +From: Xiao Ni + +[ Upstream commit de3544d2e5ea99064498de3c21ba490155864657 ] + +Interval tree uses [start, end] as a region which stores in the tree. +In raid1, it uses the wrong end value. For example: +bio(A,B) is too big and needs to be split to bio1(A,C-1), bio2(C,B). +The region of bio1 is [A,C] and the region of bio2 is [C,B]. So bio1 and +bio2 overlap which is not right. + +Fix this problem by using right end value of the region. + +Fixes: d0d2d8ba0494 ("md/raid1: introduce wait_for_serialization") +Signed-off-by: Xiao Ni +Link: https://lore.kernel.org/linux-raid/20260305011839.5118-2-xni@redhat.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid1.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 181400e147c0d..be2565dee4202 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -62,7 +62,7 @@ static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio, + unsigned long flags; + int ret = 0; + sector_t lo = r1_bio->sector; +- sector_t hi = lo + r1_bio->sectors; ++ sector_t hi = lo + r1_bio->sectors - 1; + struct serial_in_rdev *serial = &rdev->serial[idx]; + + spin_lock_irqsave(&serial->serial_lock, flags); +@@ -452,7 +452,7 @@ static void raid1_end_write_request(struct bio *bio) + int mirror = find_bio_disk(r1_bio, bio); + struct md_rdev *rdev = conf->mirrors[mirror].rdev; + sector_t lo = r1_bio->sector; +- sector_t hi = r1_bio->sector + r1_bio->sectors; ++ sector_t hi = r1_bio->sector + r1_bio->sectors - 1; + bool ignore_error = !raid1_should_handle_error(bio) || + (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD); + +-- +2.53.0 + diff --git a/queue-7.0/md-raid1-raid10-don-t-fail-devices-for-invalid-io-er.patch b/queue-7.0/md-raid1-raid10-don-t-fail-devices-for-invalid-io-er.patch new file mode 100644 index 0000000000..93f3bb7de7 --- /dev/null +++ b/queue-7.0/md-raid1-raid10-don-t-fail-devices-for-invalid-io-er.patch @@ -0,0 +1,64 @@ +From d1c3ddfe7753534abec93c37e8b00cbb6905ede4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 07:03:45 -0700 +Subject: md/raid1,raid10: don't fail devices for invalid IO errors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Keith Busch + +[ Upstream commit f7b24c7b41f23b5f9caa8b913afe79cd4c397d39 ] + +BLK_STS_INVAL indicates the IO request itself was invalid, not that the +device has failed. When raid1 treats this as a device error, it retries +on alternate mirrors which fail the same way, eventually exceeding the +read error threshold and removing the device from the array. + +This happens when stacking configurations bypass bio_split_to_limits() +in the IO path: dm-raid calls md_handle_request() directly without going +through md_submit_bio(), skipping the alignment validation that would +otherwise reject invalid bios early. The invalid bio reaches the +lower block layers, which fail the bio with BLK_STS_INVAL, and raid1 +wrongly interprets this as a device failure. + +Add BLK_STS_INVAL to raid1_should_handle_error() so that invalid IO +errors are propagated back to the caller rather than triggering device +removal. This is consistent with the previous kernel behavior when +alignment checks were done earlier in the direct-io path. + +Fixes: 5ff3f74e145adc7 ("block: simplify direct io validity check") + +Reported-by: Tomáš Trnka +Closes: https://lore.kernel.org/linux-block/2982107.4sosBPzcNG@electra/ +Signed-off-by: Keith Busch +Tested-by: Tomáš Trnka +Link: https://lore.kernel.org/r/20260416140345.3872265-1-kbusch@meta.com +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/raid1-10.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c +index c33099925f230..56a56a4da4f83 100644 +--- a/drivers/md/raid1-10.c ++++ b/drivers/md/raid1-10.c +@@ -293,8 +293,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev, + * bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is + * submitted to the underlying disks, hence don't record badblocks or retry + * in this case. ++ * ++ * BLK_STS_INVAL means the bio was not valid for the underlying device. This ++ * is a user error, not a device failure, so retrying or recording bad blocks ++ * would be wrong. + */ + static inline bool raid1_should_handle_error(struct bio *bio) + { +- return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)); ++ return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)) && ++ bio->bi_status != BLK_STS_INVAL; + } +-- +2.53.0 + diff --git a/queue-7.0/md-remove-unused-static-md_wq-workqueue.patch b/queue-7.0/md-remove-unused-static-md_wq-workqueue.patch new file mode 100644 index 0000000000..2e47db4ed0 --- /dev/null +++ b/queue-7.0/md-remove-unused-static-md_wq-workqueue.patch @@ -0,0 +1,67 @@ +From 0a526d065421becaa1b25a2f16b3e39a9206edfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Mar 2026 22:35:22 +0300 +Subject: md: remove unused static md_wq workqueue + +From: Abd-Alrhman Masalkhi + +[ Upstream commit e4979f4fac4d6bbe757be50441b45e28e6bf7360 ] + +The md_wq workqueue is defined as static and initialized in md_init(), +but it is not used anywhere within md.c. + +All asynchronous and deferred work in this file is handled via +md_misc_wq or dedicated md threads. + +Fixes: b75197e86e6d3 ("md: Remove flush handling") +Signed-off-by: Abd-Alrhman Masalkhi +Link: https://lore.kernel.org/linux-raid/20260328193522.3624-1-abd.masalkhi@gmail.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index ecb9bd0e1b8f7..159af8d7ccf0b 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -84,7 +84,6 @@ static DEFINE_XARRAY(md_submodule); + static const struct kobj_type md_ktype; + + static DECLARE_WAIT_QUEUE_HEAD(resync_wait); +-static struct workqueue_struct *md_wq; + + /* + * This workqueue is used for sync_work to register new sync_thread, and for +@@ -10511,10 +10510,6 @@ static int __init md_init(void) + goto err_bitmap; + + ret = -ENOMEM; +- md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM | WQ_PERCPU, 0); +- if (!md_wq) +- goto err_wq; +- + md_misc_wq = alloc_workqueue("md_misc", WQ_PERCPU, 0); + if (!md_misc_wq) + goto err_misc_wq; +@@ -10539,8 +10534,6 @@ static int __init md_init(void) + err_md: + destroy_workqueue(md_misc_wq); + err_misc_wq: +- destroy_workqueue(md_wq); +-err_wq: + md_llbitmap_exit(); + err_bitmap: + md_bitmap_exit(); +@@ -10849,7 +10842,6 @@ static __exit void md_exit(void) + spin_unlock(&all_mddevs_lock); + + destroy_workqueue(md_misc_wq); +- destroy_workqueue(md_wq); + md_bitmap_exit(); + } + +-- +2.53.0 + diff --git a/queue-7.0/md-suppress-spurious-superblock-update-error-message.patch b/queue-7.0/md-suppress-spurious-superblock-update-error-message.patch new file mode 100644 index 0000000000..07409f6117 --- /dev/null +++ b/queue-7.0/md-suppress-spurious-superblock-update-error-message.patch @@ -0,0 +1,46 @@ +From cf349059e43ad4887443a4829cca730989b0321f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 21:38:47 +0800 +Subject: md: suppress spurious superblock update error message for dm-raid + +From: Chen Cheng + +[ Upstream commit eff0d74c6c8fd358bc9474c05002e51fa5aa56ad ] + +dm-raid has external metadata management (mddev->external = 1) and +no persistent superblock (mddev->persistent = 0). For these arrays, +there's no superblock to update, so the error message is spurious. + +The error appears as: +md_update_sb: can't update sb for read-only array md0 + +Fixes: 8c9e376b9d1a ("md: warn about updating super block failure") +Reported-by: Tj +Closes: https://lore.kernel.org/all/20260128082430.96788-1-tj.iam.tj@proton.me/ +Signed-off-by: Chen Cheng +Reviewed-by: Paul Menzel +Link: https://lore.kernel.org/linux-raid/20260210133847.269986-1-chencheng@fnnas.com +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 3ce6f9e9d38e6..c2cc2302d727d 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -2788,7 +2788,9 @@ void md_update_sb(struct mddev *mddev, int force_change) + if (!md_is_rdwr(mddev)) { + if (force_change) + set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags); +- pr_err("%s: can't update sb for read-only array %s\n", __func__, mdname(mddev)); ++ if (!mddev_is_dm(mddev)) ++ pr_err_ratelimited("%s: can't update sb for read-only array %s\n", ++ __func__, mdname(mddev)); + return; + } + +-- +2.53.0 + diff --git a/queue-7.0/md-wake-raid456-reshape-waiters-before-suspend.patch b/queue-7.0/md-wake-raid456-reshape-waiters-before-suspend.patch new file mode 100644 index 0000000000..4d430d2211 --- /dev/null +++ b/queue-7.0/md-wake-raid456-reshape-waiters-before-suspend.patch @@ -0,0 +1,59 @@ +From 8c113fbe3726261a0f312877a2b0213f7c36e361 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 22:07:29 +0800 +Subject: md: wake raid456 reshape waiters before suspend + +From: Yu Kuai + +[ Upstream commit cf86bb53b9c92354904a328e947a05ffbfdd1840 ] + +During raid456 reshape, direct IO across the reshape position can sleep +in raid5_make_request() waiting for reshape progress while still +holding an active_io reference. If userspace then freezes reshape and +writes md/suspend_lo or md/suspend_hi, mddev_suspend() kills active_io +and waits for all in-flight IO to drain. + +This can deadlock: the IO needs reshape progress to continue, but the +reshape thread is already frozen, so the active_io reference is never +dropped and suspend never completes. + +raid5_prepare_suspend() already wakes wait_for_reshape for dm-raid. Do +the same for normal md suspend when reshape is already interrupted, so +waiting raid456 IO can abort, drop its reference, and let suspend +finish. + +The mdadm test tests/25raid456-reshape-deadlock reproduces the hang. + +Fixes: 714d20150ed8 ("md: add new helpers to suspend/resume array") +Link: https://lore.kernel.org/linux-raid/20260327140729.2030564-1-yukuai@fnnas.com/ +Signed-off-by: Yu Kuai +Signed-off-by: Sasha Levin +--- + drivers/md/md.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 159af8d7ccf0b..9c552904a5ddc 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -488,6 +488,17 @@ int mddev_suspend(struct mddev *mddev, bool interruptible) + } + + percpu_ref_kill(&mddev->active_io); ++ ++ /* ++ * RAID456 IO can sleep in wait_for_reshape while still holding an ++ * active_io reference. If reshape is already interrupted or frozen, ++ * wake those waiters so they can abort and drop the reference instead ++ * of deadlocking suspend. ++ */ ++ if (mddev->pers && mddev->pers->prepare_suspend && ++ reshape_interrupted(mddev)) ++ mddev->pers->prepare_suspend(mddev); ++ + if (interruptible) + err = wait_event_interruptible(mddev->sb_wait, + percpu_ref_is_zero(&mddev->active_io)); +-- +2.53.0 + diff --git a/queue-7.0/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch b/queue-7.0/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch new file mode 100644 index 0000000000..b2f6b9dfb8 --- /dev/null +++ b/queue-7.0/media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch @@ -0,0 +1,72 @@ +From a1a5cb94135863355ba8d7c7de63ba30b8077476 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 15:37:34 +0200 +Subject: media: i2c: og01a1b: Fix V4L2 subdevice data initialization on probe + +From: Vladimir Zapolskiy + +[ Upstream commit 535b7f106991c7d8f0e5b8e1769bfb8b1ce9d3d6 ] + +It's necessary to finalize the camera sensor subdevice initialization on +driver probe and clean V4L2 subdevice data up on error paths and driver +removal. + +The change fixes a previously reported by v4l2-compliance issue of +the failed VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT test: + + fail: v4l2-test-controls.cpp(1104): subscribe event for control 'User Controls' failed + +Fixes: 472377febf84 ("media: Add a driver for the og01a1b camera sensor") +Signed-off-by: Vladimir Zapolskiy +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/i2c/og01a1b.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c +index c7184de6251ae..7b892b26203c0 100644 +--- a/drivers/media/i2c/og01a1b.c ++++ b/drivers/media/i2c/og01a1b.c +@@ -1042,6 +1042,7 @@ static void og01a1b_remove(struct i2c_client *client) + struct og01a1b *og01a1b = to_og01a1b(sd); + + v4l2_async_unregister_subdev(sd); ++ v4l2_subdev_cleanup(&og01a1b->sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(og01a1b->dev); +@@ -1153,11 +1154,18 @@ static int og01a1b_probe(struct i2c_client *client) + goto probe_error_v4l2_ctrl_handler_free; + } + ++ ret = v4l2_subdev_init_finalize(&og01a1b->sd); ++ if (ret < 0) { ++ dev_err_probe(og01a1b->dev, ret, ++ "failed to finalize subdevice init\n"); ++ goto probe_error_media_entity_cleanup; ++ } ++ + ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); + if (ret < 0) { + dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d", + ret); +- goto probe_error_media_entity_cleanup; ++ goto probe_error_v4l2_subdev_cleanup; + } + + /* Enable runtime PM and turn off the device */ +@@ -1167,6 +1175,9 @@ static int og01a1b_probe(struct i2c_client *client) + + return 0; + ++probe_error_v4l2_subdev_cleanup: ++ v4l2_subdev_cleanup(&og01a1b->sd); ++ + probe_error_media_entity_cleanup: + media_entity_cleanup(&og01a1b->sd.entity); + +-- +2.53.0 + diff --git a/queue-7.0/media-synopsys-video_dw_mipi_csi2rx-should-depend-on.patch b/queue-7.0/media-synopsys-video_dw_mipi_csi2rx-should-depend-on.patch new file mode 100644 index 0000000000..666003e7ff --- /dev/null +++ b/queue-7.0/media-synopsys-video_dw_mipi_csi2rx-should-depend-on.patch @@ -0,0 +1,43 @@ +From a102c372abd3667f7fb97e987f40b13db867e1f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 20:10:09 +0100 +Subject: media: synopsys: VIDEO_DW_MIPI_CSI2RX should depend on ARCH_ROCKCHIP + +From: Geert Uytterhoeven + +[ Upstream commit 942435a62d67035394340cfcbaa534145d638bf0 ] + +The Synopsys DesignWare MIPI CSI-2 Receiver is currently only supported +on Rockchip RK3568 SoCs. Hence add a dependency on ARCH_ROCKCHIP, to +prevent asking the user about this driver when configuring a kernel +without Rockchip platform support. + +The dependency can be relaxed later, when adding support for appropriate +SoCs from other vendors (if any). + +Fixes: 355a110040665e43 ("media: synopsys: add driver for the designware mipi csi-2 receiver") +Signed-off-by: Geert Uytterhoeven +Acked-by: Michael Riesch +Reviewed-by: Frank Li +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/synopsys/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/media/platform/synopsys/Kconfig b/drivers/media/platform/synopsys/Kconfig +index bf2ac092fbb39..b109de2c8111c 100644 +--- a/drivers/media/platform/synopsys/Kconfig ++++ b/drivers/media/platform/synopsys/Kconfig +@@ -4,6 +4,7 @@ source "drivers/media/platform/synopsys/hdmirx/Kconfig" + + config VIDEO_DW_MIPI_CSI2RX + tristate "Synopsys DesignWare MIPI CSI-2 Receiver" ++ depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on VIDEO_DEV + depends on V4L_PLATFORM_DRIVERS + depends on PM && COMMON_CLK +-- +2.53.0 + diff --git a/queue-7.0/memblock-reserve_mem-fix-end-caclulation-in-reserve_.patch b/queue-7.0/memblock-reserve_mem-fix-end-caclulation-in-reserve_.patch new file mode 100644 index 0000000000..efcfa697ba --- /dev/null +++ b/queue-7.0/memblock-reserve_mem-fix-end-caclulation-in-reserve_.patch @@ -0,0 +1,40 @@ +From edc5b6e49ba41510d0dd3d2eda5f3c84765eee63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 09:48:28 +0200 +Subject: memblock: reserve_mem: fix end caclulation in + reserve_mem_release_by_name() + +From: Mike Rapoport (Microsoft) + +[ Upstream commit c12c3e1507809ad1fc0448f51c933f52e17d13cd ] + +free_reserved_area() expects end parameter to point to the first address +after the area, but reserve_mem_release_by_name() passes it the last +address inside the area. + +Remove subtraction of one in calculation of the area end. + +Fixes: 74e2498ccf7b ("mm/memblock: Add reserved memory release function") +Link: https://patch.msgid.link/20260323074836.3653702-2-rppt@kernel.org +Signed-off-by: Mike Rapoport (Microsoft) +Signed-off-by: Sasha Levin +--- + mm/memblock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mm/memblock.c b/mm/memblock.c +index b3ddfdec7a809..d4a02f1750e91 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -2434,7 +2434,7 @@ int reserve_mem_release_by_name(const char *name) + return 0; + + start = phys_to_virt(map->start); +- end = start + map->size - 1; ++ end = start + map->size; + snprintf(buf, sizeof(buf), "reserve_mem:%s", name); + free_reserved_area(start, end, 0, buf); + map->size = 0; +-- +2.53.0 + diff --git a/queue-7.0/memory-tegra124-emc-fix-dll_change-check.patch b/queue-7.0/memory-tegra124-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..ec82c52d9b --- /dev/null +++ b/queue-7.0/memory-tegra124-emc-fix-dll_change-check.patch @@ -0,0 +1,38 @@ +From 9e6247d898a9f544c26b908e659b02867960c8f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:42 +0900 +Subject: memory: tegra124-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 9597ab9a8296ab337e6820f8a717ff621078b632 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: 73a7f0a90641 ("memory: tegra: Add EMC (external memory controller) driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-1-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra124-emc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c +index ff26815e51f17..5cfbc169c5f98 100644 +--- a/drivers/memory/tegra/tegra124-emc.c ++++ b/drivers/memory/tegra/tegra124-emc.c +@@ -608,7 +608,7 @@ static int tegra124_emc_prepare_timing_change(struct tegra_emc *emc, + + if ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; +-- +2.53.0 + diff --git a/queue-7.0/memory-tegra30-emc-fix-dll_change-check.patch b/queue-7.0/memory-tegra30-emc-fix-dll_change-check.patch new file mode 100644 index 0000000000..5016ee2230 --- /dev/null +++ b/queue-7.0/memory-tegra30-emc-fix-dll_change-check.patch @@ -0,0 +1,47 @@ +From 66c0c5edead86177db5e7af28546019aee4b78e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 15:50:43 +0900 +Subject: memory: tegra30-emc: Fix dll_change check + +From: Mikko Perttunen + +[ Upstream commit 0a93f2355cf4922ad2399dbef5ea1049fef116d4 ] + +The code checking whether the specified memory timing enables DLL +in the EMRS register was reversed. DLL is enabled if bit A0 is low. +Fix the check. + +Fixes: e34212c75a68 ("memory: tegra: Introduce Tegra30 EMC driver") +Signed-off-by: Mikko Perttunen +Link: https://patch.msgid.link/20260126-fix-emc-dllchange-v1-2-47ad3bb63262@nvidia.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/tegra/tegra30-emc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c +index 606106dd2b32e..5812c8cd6ce4f 100644 +--- a/drivers/memory/tegra/tegra30-emc.c ++++ b/drivers/memory/tegra/tegra30-emc.c +@@ -554,14 +554,14 @@ static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) + emc->emc_cfg = readl_relaxed(emc->regs + EMC_CFG); + emc_dbg = readl_relaxed(emc->regs + EMC_DBG); + +- if (emc->dll_on == !!(timing->emc_mode_1 & 0x1)) ++ if (emc->dll_on == !(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_NONE; +- else if (timing->emc_mode_1 & 0x1) ++ else if (!(timing->emc_mode_1 & 0x1)) + dll_change = DLL_CHANGE_ON; + else + dll_change = DLL_CHANGE_OFF; + +- emc->dll_on = !!(timing->emc_mode_1 & 0x1); ++ emc->dll_on = !(timing->emc_mode_1 & 0x1); + + if (timing->data[80] && !readl_relaxed(emc->regs + EMC_ZCAL_INTERVAL)) + emc->zcal_long = true; +-- +2.53.0 + diff --git a/queue-7.0/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch b/queue-7.0/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch new file mode 100644 index 0000000000..ff3e67829a --- /dev/null +++ b/queue-7.0/mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch @@ -0,0 +1,37 @@ +From 3234ef4473dbb817d530e5696998fe37c3b90149 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Jan 2026 15:56:20 +0530 +Subject: mfd: mc13xxx-core: Fix memory leak in mc13xxx_add_subdevice_pdata() + +From: Abdun Nihaal + +[ Upstream commit a5a65a7fb2f7796bbe492cd6be59c92cb64377d1 ] + +The memory allocated for cell.name using kmemdup() is not freed when +mfd_add_devices() fails. Fix that by using devm_kmemdup(). + +Fixes: 8e00593557c3 ("mfd: Add mc13892 support to mc13xxx") +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20260120102622.66921-1-nihaal@cse.iitm.ac.in +Signed-off-by: Lee Jones +Signed-off-by: Sasha Levin +--- + drivers/mfd/mc13xxx-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c +index 920797b806ced..786eab3b2d03c 100644 +--- a/drivers/mfd/mc13xxx-core.c ++++ b/drivers/mfd/mc13xxx-core.c +@@ -377,7 +377,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return -E2BIG; + +- cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); ++ cell.name = devm_kmemdup(mc13xxx->dev, buf, strlen(buf) + 1, GFP_KERNEL); + if (!cell.name) + return -ENOMEM; + +-- +2.53.0 + diff --git a/queue-7.0/module-fix-freeing-of-charp-module-parameters-when-c.patch b/queue-7.0/module-fix-freeing-of-charp-module-parameters-when-c.patch new file mode 100644 index 0000000000..c980ecc90d --- /dev/null +++ b/queue-7.0/module-fix-freeing-of-charp-module-parameters-when-c.patch @@ -0,0 +1,122 @@ +From 0fb34ef121f7da11517b3042385a11b08f9988ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:48:02 +0100 +Subject: module: Fix freeing of charp module parameters when CONFIG_SYSFS=n + +From: Petr Pavlu + +[ Upstream commit deffe1edba626d474fef38007c03646ca5876a0e ] + +When setting a charp module parameter, the param_set_charp() function +allocates memory to store a copy of the input value. Later, when the module +is potentially unloaded, the destroy_params() function is called to free +this allocated memory. + +However, destroy_params() is available only when CONFIG_SYSFS=y, otherwise +only a dummy variant is present. In the unlikely case that the kernel is +configured with CONFIG_MODULES=y and CONFIG_SYSFS=n, this results in +a memory leak of charp values when a module is unloaded. + +Fix this issue by making destroy_params() always available when +CONFIG_MODULES=y. Rename the function to module_destroy_params() to clarify +that it is intended for use by the module loader. + +Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs") +Signed-off-by: Petr Pavlu +Signed-off-by: Sami Tolvanen +Signed-off-by: Sasha Levin +--- + include/linux/moduleparam.h | 11 +++-------- + kernel/module/main.c | 4 ++-- + kernel/params.c | 27 ++++++++++++++++++--------- + 3 files changed, 23 insertions(+), 19 deletions(-) + +diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h +index 7d22d4c4ea2e7..8667f72503d95 100644 +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -426,14 +426,9 @@ extern char *parse_args(const char *name, + void *arg, parse_unknown_fn unknown); + + /* Called by module remove. */ +-#ifdef CONFIG_SYSFS +-extern void destroy_params(const struct kernel_param *params, unsigned num); +-#else +-static inline void destroy_params(const struct kernel_param *params, +- unsigned num) +-{ +-} +-#endif /* !CONFIG_SYSFS */ ++#ifdef CONFIG_MODULES ++void module_destroy_params(const struct kernel_param *params, unsigned int num); ++#endif + + /* All the helper functions */ + /* The macros to do compile-time type checking stolen from Jakub +diff --git a/kernel/module/main.c b/kernel/module/main.c +index c3ce106c70af1..ef2e2130972fe 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -1408,7 +1408,7 @@ static void free_module(struct module *mod) + module_unload_free(mod); + + /* Free any allocated parameters. */ +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + + if (is_livepatch_module(mod)) + free_module_elf(mod); +@@ -3519,7 +3519,7 @@ static int load_module(struct load_info *info, const char __user *uargs, + mod_sysfs_teardown(mod); + coming_cleanup: + mod->state = MODULE_STATE_GOING; +- destroy_params(mod->kp, mod->num_kp); ++ module_destroy_params(mod->kp, mod->num_kp); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_GOING, mod); + klp_module_going(mod); +diff --git a/kernel/params.c b/kernel/params.c +index 7188a12dbe864..c6a354d54213d 100644 +--- a/kernel/params.c ++++ b/kernel/params.c +@@ -745,15 +745,6 @@ void module_param_sysfs_remove(struct module *mod) + } + #endif + +-void destroy_params(const struct kernel_param *params, unsigned num) +-{ +- unsigned int i; +- +- for (i = 0; i < num; i++) +- if (params[i].ops->free) +- params[i].ops->free(params[i].arg); +-} +- + struct module_kobject * __init_or_module + lookup_or_create_module_kobject(const char *name) + { +@@ -985,3 +976,21 @@ static int __init param_sysfs_builtin_init(void) + late_initcall(param_sysfs_builtin_init); + + #endif /* CONFIG_SYSFS */ ++ ++#ifdef CONFIG_MODULES ++ ++/* ++ * module_destroy_params - free all parameters for one module ++ * @params: module parameters (array) ++ * @num: number of module parameters ++ */ ++void module_destroy_params(const struct kernel_param *params, unsigned int num) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < num; i++) ++ if (params[i].ops->free) ++ params[i].ops->free(params[i].arg); ++} ++ ++#endif /* CONFIG_MODULES */ +-- +2.53.0 + diff --git a/queue-7.0/mptcp-better-mptcp-level-rtt-estimator.patch b/queue-7.0/mptcp-better-mptcp-level-rtt-estimator.patch new file mode 100644 index 0000000000..38efb8a3bd --- /dev/null +++ b/queue-7.0/mptcp-better-mptcp-level-rtt-estimator.patch @@ -0,0 +1,268 @@ +From af2005ee56ec342c9a148bd9970274338d244a87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 10:45:17 +0200 +Subject: mptcp: better mptcp-level RTT estimator + +From: Paolo Abeni + +[ Upstream commit d2000361e4ddf5047d660a902a3b0ed7520be1e5 ] + +The current MPTCP-level RTT estimator has several issues. On high speed +links, the MPTCP-level receive buffer auto-tuning happens with a +frequency well above the TCP-level's one. That in turn can cause +excessive/unneeded receive buffer increase. + +On such links, the initial rtt_us value is considerably higher than the +actual delay, and the current mptcp_rcv_space_adjust() updates +msk->rcvq_space.rtt_us with a period equal to the such field previous +value. If the initial rtt_us is 40ms, its first update will happen after +40ms, even if the subflows see actual RTT orders of magnitude lower. + +Additionally: +- setting the msk RTT to the maximum among all the subflows RTTs makes + DRS constantly overshooting the rcvbuf size when a subflow has + considerable higher latency than the other(s). + +- during unidirectional bulk transfers with multiple active subflows, + the TCP-level RTT estimator occasionally sees considerably higher + value than the real link delay, i.e. when the packet scheduler reacts + to an incoming ACK on given subflow pushing data on a different + subflow. + +- currently inactive but still open subflows (i.e. switched to backup + mode) are always considered when computing the msk-level RTT. + +Address the all the issues above with a more accurate RTT estimation +strategy: the MPTCP-level RTT is set to the minimum of all the subflows +actually feeding data into the MPTCP receive buffer, using a small +sliding window. + +While at it, also use EWMA to compute the msk-level scaling_ratio, to +that MPTCP can avoid traversing the subflow list is +mptcp_rcv_space_adjust(). + +Use some care to avoid updating msk and ssk level fields too often. + +Fixes: a6b118febbab ("mptcp: add receive buffer auto-tuning") +Signed-off-by: Paolo Abeni +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260407-net-next-mptcp-reduce-rbuf-v2-1-0d1d135bf6f6@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/trace/events/mptcp.h | 2 +- + net/mptcp/protocol.c | 63 ++++++++++++++++++++---------------- + net/mptcp/protocol.h | 37 ++++++++++++++++++++- + 3 files changed, 72 insertions(+), 30 deletions(-) + +diff --git a/include/trace/events/mptcp.h b/include/trace/events/mptcp.h +index 269d949b20254..04521acba4832 100644 +--- a/include/trace/events/mptcp.h ++++ b/include/trace/events/mptcp.h +@@ -219,7 +219,7 @@ TRACE_EVENT(mptcp_rcvbuf_grow, + __be32 *p32; + + __entry->time = time; +- __entry->rtt_us = msk->rcvq_space.rtt_us >> 3; ++ __entry->rtt_us = mptcp_rtt_us_est(msk) >> 3; + __entry->copied = msk->rcvq_space.copied; + __entry->inq = mptcp_inq_hint(sk); + __entry->space = msk->rcvq_space.space; +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index 1a73d2461c7b9..8ef967aa80a0b 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -879,6 +879,32 @@ static bool move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk) + return moved; + } + ++static void mptcp_rcv_rtt_update(struct mptcp_sock *msk, ++ struct mptcp_subflow_context *subflow) ++{ ++ const struct tcp_sock *tp = tcp_sk(subflow->tcp_sock); ++ u32 rtt_us = tp->rcv_rtt_est.rtt_us; ++ int id; ++ ++ /* Update once per subflow per rcvwnd to avoid touching the msk ++ * too often. ++ */ ++ if (!rtt_us || tp->rcv_rtt_est.seq == subflow->prev_rtt_seq) ++ return; ++ ++ subflow->prev_rtt_seq = tp->rcv_rtt_est.seq; ++ ++ /* Pairs with READ_ONCE() in mptcp_rtt_us_est(). */ ++ id = msk->rcv_rtt_est.next_sample; ++ WRITE_ONCE(msk->rcv_rtt_est.samples[id], rtt_us); ++ if (++msk->rcv_rtt_est.next_sample == MPTCP_RTT_SAMPLES) ++ msk->rcv_rtt_est.next_sample = 0; ++ ++ /* EWMA among the incoming subflows */ ++ msk->scaling_ratio = ((msk->scaling_ratio << 3) - msk->scaling_ratio + ++ tp->scaling_ratio) >> 3; ++} ++ + void mptcp_data_ready(struct sock *sk, struct sock *ssk) + { + struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); +@@ -892,6 +918,7 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk) + return; + + mptcp_data_lock(sk); ++ mptcp_rcv_rtt_update(msk, subflow); + if (!sock_owned_by_user(sk)) { + /* Wake-up the reader only for in-sequence data */ + if (move_skbs_to_msk(msk, ssk) && mptcp_epollin_ready(sk)) +@@ -2077,7 +2104,6 @@ static void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) + + msk->rcvspace_init = 1; + msk->rcvq_space.copied = 0; +- msk->rcvq_space.rtt_us = 0; + + /* initial rcv_space offering made to peer */ + msk->rcvq_space.space = min_t(u32, tp->rcv_wnd, +@@ -2088,15 +2114,15 @@ static void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk) + + /* receive buffer autotuning. See tcp_rcv_space_adjust for more information. + * +- * Only difference: Use highest rtt estimate of the subflows in use. ++ * Only difference: Use lowest rtt estimate of the subflows in use, see ++ * mptcp_rcv_rtt_update() and mptcp_rtt_us_est(). + */ + static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) + { + struct mptcp_subflow_context *subflow; + struct sock *sk = (struct sock *)msk; +- u8 scaling_ratio = U8_MAX; +- u32 time, advmss = 1; +- u64 rtt_us, mstamp; ++ u32 time, rtt_us; ++ u64 mstamp; + + msk_owned_by_me(msk); + +@@ -2111,29 +2137,8 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) + mstamp = mptcp_stamp(); + time = tcp_stamp_us_delta(mstamp, READ_ONCE(msk->rcvq_space.time)); + +- rtt_us = msk->rcvq_space.rtt_us; +- if (rtt_us && time < (rtt_us >> 3)) +- return; +- +- rtt_us = 0; +- mptcp_for_each_subflow(msk, subflow) { +- const struct tcp_sock *tp; +- u64 sf_rtt_us; +- u32 sf_advmss; +- +- tp = tcp_sk(mptcp_subflow_tcp_sock(subflow)); +- +- sf_rtt_us = READ_ONCE(tp->rcv_rtt_est.rtt_us); +- sf_advmss = READ_ONCE(tp->advmss); +- +- rtt_us = max(sf_rtt_us, rtt_us); +- advmss = max(sf_advmss, advmss); +- scaling_ratio = min(tp->scaling_ratio, scaling_ratio); +- } +- +- msk->rcvq_space.rtt_us = rtt_us; +- msk->scaling_ratio = scaling_ratio; +- if (time < (rtt_us >> 3) || rtt_us == 0) ++ rtt_us = mptcp_rtt_us_est(msk); ++ if (rtt_us == U32_MAX || time < (rtt_us >> 3)) + return; + + if (msk->rcvq_space.copied <= msk->rcvq_space.space) +@@ -3000,6 +3005,7 @@ static void __mptcp_init_sock(struct sock *sk) + msk->timer_ival = TCP_RTO_MIN; + msk->scaling_ratio = TCP_DEFAULT_SCALING_RATIO; + msk->backlog_len = 0; ++ mptcp_init_rtt_est(msk); + + WRITE_ONCE(msk->first, NULL); + inet_csk(sk)->icsk_sync_mss = mptcp_sync_mss; +@@ -3446,6 +3452,7 @@ static int mptcp_disconnect(struct sock *sk, int flags) + msk->bytes_retrans = 0; + msk->rcvspace_init = 0; + msk->fastclosing = 0; ++ mptcp_init_rtt_est(msk); + + /* for fallback's sake */ + WRITE_ONCE(msk->ack_seq, 0); +diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h +index ec15e503da8b7..d19c54761c27a 100644 +--- a/net/mptcp/protocol.h ++++ b/net/mptcp/protocol.h +@@ -268,6 +268,13 @@ struct mptcp_data_frag { + struct page *page; + }; + ++/* Arbitrary compromise between as low as possible to react timely to subflow ++ * close event and as big as possible to avoid being fouled by biased large ++ * samples due to peer sending data on a different subflow WRT to the incoming ++ * ack. ++ */ ++#define MPTCP_RTT_SAMPLES 5 ++ + /* MPTCP connection sock */ + struct mptcp_sock { + /* inet_connection_sock must be the first member */ +@@ -340,11 +347,17 @@ struct mptcp_sock { + */ + struct mptcp_pm_data pm; + struct mptcp_sched_ops *sched; ++ ++ /* Most recent rtt_us observed by in use incoming subflows. */ ++ struct { ++ u32 samples[MPTCP_RTT_SAMPLES]; ++ u32 next_sample; ++ } rcv_rtt_est; ++ + struct { + int space; /* bytes copied in last measurement window */ + int copied; /* bytes copied in this measurement window */ + u64 time; /* start time of measurement window */ +- u64 rtt_us; /* last maximum rtt of subflows */ + } rcvq_space; + u8 scaling_ratio; + bool allow_subflows; +@@ -422,6 +435,27 @@ static inline struct mptcp_data_frag *mptcp_send_head(const struct sock *sk) + return msk->first_pending; + } + ++static inline void mptcp_init_rtt_est(struct mptcp_sock *msk) ++{ ++ int i; ++ ++ for (i = 0; i < MPTCP_RTT_SAMPLES; ++i) ++ msk->rcv_rtt_est.samples[i] = U32_MAX; ++ msk->rcv_rtt_est.next_sample = 0; ++ msk->scaling_ratio = TCP_DEFAULT_SCALING_RATIO; ++} ++ ++static inline u32 mptcp_rtt_us_est(const struct mptcp_sock *msk) ++{ ++ u32 rtt_us = READ_ONCE(msk->rcv_rtt_est.samples[0]); ++ int i; ++ ++ /* Lockless access of collected samples. */ ++ for (i = 1; i < MPTCP_RTT_SAMPLES; ++i) ++ rtt_us = min(rtt_us, READ_ONCE(msk->rcv_rtt_est.samples[i])); ++ return rtt_us; ++} ++ + static inline struct mptcp_data_frag *mptcp_send_next(struct sock *sk) + { + struct mptcp_sock *msk = mptcp_sk(sk); +@@ -523,6 +557,7 @@ struct mptcp_subflow_context { + u32 map_data_len; + __wsum map_data_csum; + u32 map_csum_len; ++ u32 prev_rtt_seq; + u32 request_mptcp : 1, /* send MP_CAPABLE */ + request_join : 1, /* send MP_JOIN */ + request_bkup : 1, +-- +2.53.0 + diff --git a/queue-7.0/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch b/queue-7.0/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch new file mode 100644 index 0000000000..0816fc4275 --- /dev/null +++ b/queue-7.0/mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch @@ -0,0 +1,59 @@ +From 8d4cc11905b3f1035b38bd637709f30226383fcc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:57 +0200 +Subject: mtd: parsers: ofpart: call of_node_get() for dedicated subpartitions + +From: Cosmin Tanislav + +[ Upstream commit e882626c1747653f1f01ea9d12e278e613b11d0f ] + +In order to parse sub-partitions, add_mtd_partitions() calls +parse_mtd_partitions() for all previously found partitions. + +Each partition will end up being passed to parse_fixed_partitions(), and +its of_node will be treated as the ofpart_node. + +Commit 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in +parse_fixed_partitions()") added of_node_put() calls for ofpart_node on +all exit paths. + +In the case where the partition passed to parse_fixed_partitions() has a +parent, it is treated as a dedicated partitions node, and of_node_put() +is wrongly called for it, even if of_node_get() was not called +explicitly. + +On repeated bind / unbinds of the MTD, the extra of_node_put() ends up +decrementing the refcount down to 0, which should never happen, +resulting in the following error: + +OF: ERROR: of_node_release() detected bad of_node_put() on +/soc/spi@80007000/flash@0/partitions/partition@0 + +Call of_node_get() to balance the call to of_node_put() done for +dedicated partitions nodes. + +Fixes: 7cce81df7d26 ("mtd: parsers: ofpart: fix OF node refcount leak in parse_fixed_partitions()") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 181ae9616b2e3..262c4221d23f7 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -75,7 +75,7 @@ static int parse_fixed_partitions(struct mtd_info *master, + dedicated = false; + } + } else { /* Partition */ +- ofpart_node = mtd_node; ++ ofpart_node = of_node_get(mtd_node); + } + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); +-- +2.53.0 + diff --git a/queue-7.0/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch b/queue-7.0/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch new file mode 100644 index 0000000000..86e4384fa0 --- /dev/null +++ b/queue-7.0/mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch @@ -0,0 +1,48 @@ +From 538a2c922482773761b529af899d0ae95266dfdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:39:56 +0200 +Subject: mtd: parsers: ofpart: call of_node_put() only in ofpart_fail path + +From: Cosmin Tanislav + +[ Upstream commit 0c87dea1aab86116211cb37387c404c9e9231c39 ] + +ofpart_none can only be reached after the for_each_child_of_node() loop +finishes. for_each_child_of_node() correctly calls of_node_put() for all +device nodes it iterates over as long as we don't break or jump out of +the loop. + +Calling of_node_put() inside the ofpart_none path will wrongly decrement +the ref count of the last node in the for_each_child_of_node() loop. + +Move the call to of_node_put() under the ofpart_fail label to fix this. + +Fixes: ebd5a74db74e ("mtd: ofpart: Check availability of reg property instead of name property") +Signed-off-by: Cosmin Tanislav +Tested-by: Tommaso Merciai +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c +index 0029bda165bde..181ae9616b2e3 100644 +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -195,11 +195,11 @@ static int parse_fixed_partitions(struct mtd_info *master, + ofpart_fail: + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", + master->name, pp, mtd_node); ++ of_node_put(pp); + ret = -EINVAL; + ofpart_none: + if (dedicated) + of_node_put(ofpart_node); +- of_node_put(pp); + kfree(parts); + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch b/queue-7.0/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch new file mode 100644 index 0000000000..ad18e30974 --- /dev/null +++ b/queue-7.0/mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch @@ -0,0 +1,41 @@ +From 45ac9e6dc57ad056c46dd2018c87e0b89c23f4cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 09:43:36 +0800 +Subject: mtd: physmap_of_gemini: Fix disabled pinctrl state check + +From: Chen Ni + +[ Upstream commit b7c0982184b0661f5b1b805f3a56f1bd3757b63e ] + +The condition for checking the disabled pinctrl state incorrectly checks +gf->enabled_state instead of gf->disabled_state. This causes misleading +error messages and could lead to incorrect behavior when only one of the +pinctrl states is defined. + +Fix the condition to properly check gf->disabled_state. + +Fixes: 9d3b5086f6d4 ("mtd: physmap_of_gemini: Handle pin control") +Signed-off-by: Chen Ni +Reviewed-by: Linus Walleij +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/maps/physmap-gemini.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c +index 9d3b4bf84a1ad..1c34b4ef77ea3 100644 +--- a/drivers/mtd/maps/physmap-gemini.c ++++ b/drivers/mtd/maps/physmap-gemini.c +@@ -181,7 +181,7 @@ int of_flash_probe_gemini(struct platform_device *pdev, + dev_err(dev, "no enabled pin control state\n"); + + gf->disabled_state = pinctrl_lookup_state(gf->p, "disabled"); +- if (IS_ERR(gf->enabled_state)) { ++ if (IS_ERR(gf->disabled_state)) { + dev_err(dev, "no disabled pin control state\n"); + } else { + ret = pinctrl_select_state(gf->p, gf->disabled_state); +-- +2.53.0 + diff --git a/queue-7.0/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch b/queue-7.0/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch new file mode 100644 index 0000000000..e9691ca03c --- /dev/null +++ b/queue-7.0/mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch @@ -0,0 +1,66 @@ +From 8fd5d994a06ff11f47649b95f1134ccef982b486 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 15:24:30 +0100 +Subject: mtd: rawnand: sunxi: fix sunxi_nfc_hw_ecc_read_extra_oob + +From: Richard Genoud + +[ Upstream commit 848c13996c55fe4ea6bf5acc3ce6c8c5c944b5f6 ] + +When dumping the OOB, the bytes at the end where actually copied from +the beginning of the OOB instead of current_offset. + +That leads to something like: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +instead of: +OOB: ff ff ff ff ff ff ff ff ea 19 00 3a 83 db aa 8d +OOB: 99 09 c8 9a 90 36 35 7d aa 15 13 07 3d 97 b2 a4 +OOB: a8 bb 19 b3 07 e9 f6 25 52 d7 1a 23 e2 7e 0a e4 +OOB: 52 8a 09 d2 1a 86 3d cf b4 99 43 13 d3 90 33 0b +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +OOB: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +(example with BCH16, user data [8,0], no scrambling) + +*cur_off (offset from the beginning of the page) was compared to offset +(offset from the beginning of the OOB), and then, the +nand_change_read_column_op() sets the current position to the beginning +of the OOB instead of OOB+offset + +Fixes: 15d6f118285f ("mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode") +Reviewed-by: Jernej Skrabec +Signed-off-by: Richard Genoud +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/raw/sunxi_nand.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c +index e66adfcca7cd6..85b869041a37f 100644 +--- a/drivers/mtd/nand/raw/sunxi_nand.c ++++ b/drivers/mtd/nand/raw/sunxi_nand.c +@@ -1048,9 +1048,9 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand, + if (len <= 0) + return; + +- if (!cur_off || *cur_off != offset) +- nand_change_read_column_op(nand, mtd->writesize, NULL, 0, +- false); ++ if (!cur_off || *cur_off != (offset + mtd->writesize)) ++ nand_change_read_column_op(nand, mtd->writesize + offset, ++ NULL, 0, false); + + if (!randomize) + sunxi_nfc_read_buf(nand, oob + offset, len); +-- +2.53.0 + diff --git a/queue-7.0/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch b/queue-7.0/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch new file mode 100644 index 0000000000..410518d408 --- /dev/null +++ b/queue-7.0/mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch @@ -0,0 +1,38 @@ +From e754f3274914bab1abef353223c991ba51c7c418 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 17:14:14 +0800 +Subject: mtd: spi-nor: core: correct the op.dummy.nbytes when check read + operations + +From: Haibo Chen + +[ Upstream commit 756564a536ecd8c9d33edd89f0647a91a0b03587 ] + +When check read operation, need to setting the op.dummy.nbytes based +on current read operation rather than the nor->read_proto. + +Fixes: 0e30f47232ab ("mtd: spi-nor: add support for DTR protocol") +Signed-off-by: Haibo Chen +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 1eee519c01e5c..5dd0b3cb52503 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -2393,7 +2393,7 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor, + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; +- if (spi_nor_protocol_is_dtr(nor->read_proto)) ++ if (spi_nor_protocol_is_dtr(read->proto)) + op.dummy.nbytes *= 2; + + return spi_nor_spimem_check_read_pp_op(nor, &op); +-- +2.53.0 + diff --git a/queue-7.0/mtd-spi-nor-micron-st-add-snor_cmd_pp_8_8_8_dtr-sfdp.patch b/queue-7.0/mtd-spi-nor-micron-st-add-snor_cmd_pp_8_8_8_dtr-sfdp.patch new file mode 100644 index 0000000000..5c889ab7a9 --- /dev/null +++ b/queue-7.0/mtd-spi-nor-micron-st-add-snor_cmd_pp_8_8_8_dtr-sfdp.patch @@ -0,0 +1,57 @@ +From a7454c6014a12862a4a154c5f570282d1b882c71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Dec 2025 11:01:02 +0800 +Subject: mtd: spi-nor: micron-st: add SNOR_CMD_PP_8_8_8_DTR sfdp fixup for + mt35xu512aba + +From: Haibo Chen + +[ Upstream commit 6d660fba6a32a34ad7d746d7f65317831daaf033 ] + +Find two batches mt35xu512aba has different SFDP but with same +jedec ID. The batch which use the new version of SFDP contain +all the necessary information to support OCT DTR mode. The batch +with old version do not contain the OCT DTR command information, +but in fact it did support OCT DTR mode. + +Current mt35xu512aba_post_sfdp_fixup() add some setting including +SNOR_CMD_READ_8_8_8_DTR, but still lack SNOR_CMD_PP_8_8_8_DTR. Meet +issue on the batch mt35xu512aba with old SFDP version. Because no +SNOR_CMD_PP_8_8_8_DTR, micron_st_nor_octal_dtr_en() will not be +called, then use SNOR_CMD_READ_8_8_8_DTR will meet issue. + +Fixes: 44dd635cd632 ("mtd: spi-nor: micron-st: use SFDP of mt35xu512aba") +Reviewed-by: Pratyush Yadav +Signed-off-by: Haibo Chen +Reviewed-by: Michael Walle +[pratyush@kernel.org: touch up the comment a bit] +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/micron-st.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c +index 88033384a71e5..b2b473501d023 100644 +--- a/drivers/mtd/spi-nor/micron-st.c ++++ b/drivers/mtd/spi-nor/micron-st.c +@@ -167,6 +167,16 @@ static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) + 0, 20, SPINOR_OP_MT_DTR_RD, + SNOR_PROTO_8_8_8_DTR); + ++ /* ++ * Some batches of mt35xu512aba do not contain the OCT DTR command ++ * information, but do support OCT DTR mode. Add the settings for ++ * SNOR_CMD_PP_8_8_8_DTR here. This also makes sure the flash can switch ++ * to OCT DTR mode. ++ */ ++ nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; ++ spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR], ++ SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR); ++ + nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; + nor->params->rdsr_dummy = 8; + nor->params->rdsr_addr_nbytes = 0; +-- +2.53.0 + diff --git a/queue-7.0/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch b/queue-7.0/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch new file mode 100644 index 0000000000..5d6599ee0d --- /dev/null +++ b/queue-7.0/mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch @@ -0,0 +1,41 @@ +From d1d26a7bb8e267bf0c24c7498d8f071b606b3aef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 20:42:56 +0800 +Subject: mtd: spi-nor: swp: check SR_TB flag when getting tb_mask + +From: Shiji Yang + +[ Upstream commit 94645aa41bf9ecb87c2ce78b1c3405bfb6074a37 ] + +When the chip does not support top/bottom block protect, the tb_mask +must be set to 0, otherwise SR1 bit5 will be unexpectedly modified. + +Signed-off-by: Shiji Yang +Fixes: 3dd8012a8eeb ("mtd: spi-nor: add TB (Top/Bottom) protect support") +Reviewed-by: Michael Walle +Reviewed-by: Miquel Raynal +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/swp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c +index 9b07f83aeac76..e67a81dbb6bf6 100644 +--- a/drivers/mtd/spi-nor/swp.c ++++ b/drivers/mtd/spi-nor/swp.c +@@ -28,8 +28,10 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) + { + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + return SR_TB_BIT6; +- else ++ else if (nor->flags & SNOR_F_HAS_SR_TB) + return SR_TB_BIT5; ++ else ++ return 0; + } + + static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) +-- +2.53.0 + diff --git a/queue-7.0/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch b/queue-7.0/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch new file mode 100644 index 0000000000..16e1453f98 --- /dev/null +++ b/queue-7.0/mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch @@ -0,0 +1,40 @@ +From a270328900b241261a126fc3e6648a8fcdb07a64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Dec 2025 10:54:30 +0100 +Subject: mtd: spi-nor: update spi_nor_fixups::post_sfdp() documentation + +From: Jonas Gorski + +[ Upstream commit 3620d67b48493c6252bbc873dc88dde81641d56b ] + +After commit 5273cc6df984 ("mtd: spi-nor: core: Call +spi_nor_post_sfdp_fixups() only when SFDP is defined") +spi_nor_post_sfdp_fixups() isn't called anymore if no SFDP is detected. + +Update the documentation accordingly. + +Fixes: 5273cc6df984 ("mtd: spi-nor: core: Call spi_nor_post_sfdp_fixups() only when SFDP is defined") +Signed-off-by: Jonas Gorski +Reviewed-by: Pratyush Yadav +Signed-off-by: Pratyush Yadav (Google) +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h +index 16b382d4f04f2..e838c40a25897 100644 +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -413,7 +413,7 @@ struct spi_nor_flash_parameter { + * number of dummy cycles in read register ops. + * @smpt_map_id: called after map ID in SMPT table has been determined for the + * case the map ID is wrong and needs to be fixed. +- * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs ++ * @post_sfdp: called after SFDP has been parsed (is not called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. + * when information provided by the SFDP/flash_info tables are +-- +2.53.0 + diff --git a/queue-7.0/mtd-spinand-add-support-for-packed-read-data-odtr-co.patch b/queue-7.0/mtd-spinand-add-support-for-packed-read-data-odtr-co.patch new file mode 100644 index 0000000000..e542b4df89 --- /dev/null +++ b/queue-7.0/mtd-spinand-add-support-for-packed-read-data-odtr-co.patch @@ -0,0 +1,102 @@ +From fb55f564de876867ab389b008d6da3dededf7734 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:41:03 +0200 +Subject: mtd: spinand: Add support for packed read data ODTR commands + +From: Miquel Raynal + +[ Upstream commit 5e25407b68f460142539536e31fa20338db6146f ] + +Some devices stuff address bits in the double byte opcode (in place of +the repeated byte) in order to be able to increase the size of the +devices, without adding extra address bytes. + +Create a flag to identify those devices. When the flag is set, use the +"packed" variant for the read data operation. + +Signed-off-by: Miquel Raynal +Stable-dep-of: 8d655748aba1 ("mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW") +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/core.c | 24 +++++++++++++++++++++--- + include/linux/mtd/spinand.h | 7 +++++++ + 2 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 8aa3753aaaa1d..0b076790bd9df 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -100,6 +100,17 @@ spinand_fill_page_read_op(struct spinand_device *spinand, u64 addr) + return op; + } + ++static struct spi_mem_op ++spinand_fill_page_read_packed_op(struct spinand_device *spinand, u64 addr) ++{ ++ struct spi_mem_op op = spinand->op_templates->page_read; ++ ++ op.cmd.opcode |= addr >> 16; ++ op.addr.val = addr & 0xFFFF; ++ ++ return op; ++} ++ + struct spi_mem_op + spinand_fill_prog_exec_op(struct spinand_device *spinand, u64 addr) + { +@@ -453,7 +464,10 @@ static int spinand_load_page_op(struct spinand_device *spinand, + { + struct nand_device *nand = spinand_to_nand(spinand); + unsigned int row = nanddev_pos_to_row(nand, &req->pos); +- struct spi_mem_op op = SPINAND_OP(spinand, page_read, row); ++ bool packed = spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ; ++ struct spi_mem_op op = packed ? ++ SPINAND_OP(spinand, page_read_packed, row) : ++ SPINAND_OP(spinand, page_read, row); + + return spi_mem_exec_op(spinand->spimem, &op); + } +@@ -1489,9 +1503,13 @@ static int spinand_init_odtr_instruction_set(struct spinand_device *spinand) + if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase)) + return -EOPNOTSUPP; + +- tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0); +- if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read)) ++ if (spinand->flags & SPINAND_ODTR_PACKED_PAGE_READ) ++ tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(0); ++ else ++ tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0); ++ if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read)) { + return -EOPNOTSUPP; ++ } + + tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0); + if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec)) +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 6a024cf1c53ac..f2f80103649d5 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -290,6 +290,12 @@ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_NO_DATA) + ++#define SPINAND_PAGE_READ_PACKED_8D_8D_0_OP(addr) \ ++ SPI_MEM_OP(SPI_MEM_DTR_OP_PACKED_CMD(0x13, addr >> 16, 8), \ ++ SPI_MEM_DTR_OP_ADDR(2, addr & 0xffff, 8), \ ++ SPI_MEM_OP_NO_DUMMY, \ ++ SPI_MEM_OP_NO_DATA) ++ + #define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ + SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ +@@ -482,6 +488,7 @@ struct spinand_ecc_info { + #define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2) + #define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3) + #define SPINAND_NO_RAW_ACCESS BIT(4) ++#define SPINAND_ODTR_PACKED_PAGE_READ BIT(5) + + /** + * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure +-- +2.53.0 + diff --git a/queue-7.0/mtd-spinand-winbond-clarify-when-to-enable-the-hs-bi.patch b/queue-7.0/mtd-spinand-winbond-clarify-when-to-enable-the-hs-bi.patch new file mode 100644 index 0000000000..ef28d43512 --- /dev/null +++ b/queue-7.0/mtd-spinand-winbond-clarify-when-to-enable-the-hs-bi.patch @@ -0,0 +1,54 @@ +From a3c4b8143784923f5f35c6890622bbd61dc9ea9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 11:47:50 +0100 +Subject: mtd: spinand: winbond: Clarify when to enable the HS bit + +From: Miquel Raynal + +[ Upstream commit 25a915fad503c2678902075565d47ddc2aa45db9 ] + +Above 104MHz when in fast dual or quad I/O reads, the delay between +address and data cycles is too short. It is possible to reach higher +frequencies, up to 166MHz, by adding a few more dummy cycles through the +setting of the HS bit. Improve the condition for enabling this bit, and +also make sure we set it at soon as we go over 104MHz. + +Fixes: f1a91175faaa ("mtd: spinand: winbond: Enable high-speed modes on w25n0xjw") +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/winbond.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index 4f9f1854e0cfe..ad22774096e61 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -337,16 +337,19 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spinand, + if (iface != SSDR) + return -EOPNOTSUPP; + ++ /* ++ * SDR dual and quad I/O operations over 104MHz require the HS bit to ++ * enable a few more dummy cycles. ++ */ + op = spinand->op_templates->read_cache; + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + hs = false; +- else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && +- op->dummy.buswidth == 1 && op->data.buswidth == 1) ++ else if (op->cmd.buswidth != 1 || op->addr.buswidth == 1) + hs = false; +- else if (!op->max_freq) +- hs = true; +- else ++ else if (op->max_freq && op->max_freq <= 104 * HZ_PER_MHZ) + hs = false; ++ else ++ hs = true; + + ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/mtd-spinand-winbond-fix-odtr-write-vcr-on-w35nxxjw.patch b/queue-7.0/mtd-spinand-winbond-fix-odtr-write-vcr-on-w35nxxjw.patch new file mode 100644 index 0000000000..27cfbf3c11 --- /dev/null +++ b/queue-7.0/mtd-spinand-winbond-fix-odtr-write-vcr-on-w35nxxjw.patch @@ -0,0 +1,41 @@ +From 789e3ffb25decea2f5577b68b0e8f7e285be5dff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:41:05 +0200 +Subject: mtd: spinand: winbond: Fix ODTR write VCR on W35NxxJW + +From: Miquel Raynal + +[ Upstream commit 135ac3b84bcedae1860e7a9512d63166f42b736e ] + +In most scenarios this variant is actually unused (VCR is written in +SSDR mode), but we need to provide an octal variant. The address is 24 +bits but is sent over 4 bytes MSB first. This means we need to shift the +register address by one extra byte for the address to be correct. + +I didn't catch this initially because the volatile register region is +256 bytes wide, so the write-then-read procedure did work with the small +register addresses I was using at that time: 0 and 1. + +Fixes: 44a2f49b9bdc ("mtd: spinand: winbond: W35N octal DTR support") +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/winbond.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index ea62fecea661d..7cc0f0091430c 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -99,7 +99,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants, + + #define SPINAND_WINBOND_WRITE_VCR_8D_8D_8D(reg, buf) \ + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x81, 8), \ +- SPI_MEM_DTR_OP_ADDR(4, reg, 8), \ ++ SPI_MEM_DTR_OP_ADDR(4, reg << 8, 8), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_DTR_OP_DATA_OUT(2, buf, 8)) + +-- +2.53.0 + diff --git a/queue-7.0/mtd-spinand-winbond-set-the-packed-page-read-flag-to.patch b/queue-7.0/mtd-spinand-winbond-set-the-packed-page-read-flag-to.patch new file mode 100644 index 0000000000..d4f0cc04ef --- /dev/null +++ b/queue-7.0/mtd-spinand-winbond-set-the-packed-page-read-flag-to.patch @@ -0,0 +1,46 @@ +From b0fa913b0bfbccbe2e15fc0e6d79c821969ad9bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:41:04 +0200 +Subject: mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW + +From: Miquel Raynal + +[ Upstream commit 8d655748aba1b603c54053a20322401dc1e5d782 ] + +Both W35N02JW and W35N04JW diverge from W35N01JW when it comes to the +"data read" operation in ODTR mode. In order to stuff more address +bits (up to 18), the second command byte is replaced by the most +significant address bits, keeping the number of address bytes to 2. + +Fixes: 44a2f49b9bdc ("mtd: spinand: winbond: W35N octal DTR support") +Signed-off-by: Miquel Raynal +Signed-off-by: Sasha Levin +--- + drivers/mtd/nand/spi/winbond.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c +index ad22774096e61..ea62fecea661d 100644 +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -518,7 +518,7 @@ static const struct spinand_info winbond_spinand_table[] = { + SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, + &write_cache_octal_variants, + &update_cache_octal_variants), +- 0, ++ SPINAND_ODTR_PACKED_PAGE_READ, + SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), + SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), +@@ -529,7 +529,7 @@ static const struct spinand_info winbond_spinand_table[] = { + SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, + &write_cache_octal_variants, + &update_cache_octal_variants), +- 0, ++ SPINAND_ODTR_PACKED_PAGE_READ, + SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), + SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), +-- +2.53.0 + diff --git a/queue-7.0/neigh-let-neigh_xmit-take-skb-ownership.patch b/queue-7.0/neigh-let-neigh_xmit-take-skb-ownership.patch new file mode 100644 index 0000000000..b6f860d9d1 --- /dev/null +++ b/queue-7.0/neigh-let-neigh_xmit-take-skb-ownership.patch @@ -0,0 +1,74 @@ +From 67e90b75184c7c68204b7941e833cab1425540cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 16:58:38 +0200 +Subject: neigh: let neigh_xmit take skb ownership + +From: Florian Westphal + +[ Upstream commit 4438113be604ee67a7bf4f81da6e1cca41332ce4 ] + +neigh_xmit always releases the skb, except when no neighbour table is +found. But even the first added user of neigh_xmit (mpls) relied on +neigh_xmit to release the skb (or queue it for tx). + +sashiko reported: + If neigh_xmit() is called with an uninitialized neighbor table (for + example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT + and bypasses its internal out_kfree_skb error path. Because the return + value of neigh_xmit() is ignored here, does this leak the SKB? + +Assume full ownership and remove the last code path that doesn't +xmit or free skb. + +Fixes: 4fd3d7d9e868 ("neigh: Add helper function neigh_xmit") +Signed-off-by: Florian Westphal +Reviewed-by: Kuniyuki Iwashima +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260424145843.74055-1-fw@strlen.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index c56a4e7bf790c..5a9cc7268521c 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -3211,8 +3211,10 @@ int neigh_xmit(int index, struct net_device *dev, + + rcu_read_lock(); + tbl = rcu_dereference(neigh_tables[index]); +- if (!tbl) +- goto out_unlock; ++ if (!tbl) { ++ rcu_read_unlock(); ++ goto out_kfree_skb; ++ } + if (index == NEIGH_ARP_TABLE) { + u32 key = *((u32 *)addr); + +@@ -3228,7 +3230,6 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + } + err = READ_ONCE(neigh->output)(neigh, skb); +-out_unlock: + rcu_read_unlock(); + } + else if (index == NEIGH_LINK_TABLE) { +@@ -3238,11 +3239,10 @@ int neigh_xmit(int index, struct net_device *dev, + goto out_kfree_skb; + err = dev_queue_xmit(skb); + } +-out: + return err; + out_kfree_skb: + kfree_skb(skb); +- goto out; ++ return err; + } + EXPORT_SYMBOL(neigh_xmit); + +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-add-dma_rmb-and-read_once-in-airoha_qdma_.patch b/queue-7.0/net-airoha-add-dma_rmb-and-read_once-in-airoha_qdma_.patch new file mode 100644 index 0000000000..71b7b8f162 --- /dev/null +++ b/queue-7.0/net-airoha-add-dma_rmb-and-read_once-in-airoha_qdma_.patch @@ -0,0 +1,88 @@ +From 8ce353f40826b6c2ae65c90e7b762e1cbe85d23c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 08:48:04 +0200 +Subject: net: airoha: Add dma_rmb() and READ_ONCE() in + airoha_qdma_rx_process() + +From: Lorenzo Bianconi + +[ Upstream commit 4ae0604a0673e11e2075b178387151fcad5111b5 ] + +Add missing dma_rmb() in airoha_qdma_rx_process routine to make sure the +DMA read operations are completed when the NIC reports the processing on +the current descriptor is done. Moreover, add missing READ_ONCE() in +airoha_qdma_rx_process() for DMA descriptor control fields in order to +avoid any compiler reordering. + +Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260407-airoha_qdma_rx_process-fix-reordering-v3-1-91c36e9da31f@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 91cb63a32d990..9285a68f435fe 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -584,7 +584,7 @@ static int airoha_qdma_fill_rx_queue(struct airoha_queue *q) + static int airoha_qdma_get_gdm_port(struct airoha_eth *eth, + struct airoha_qdma_desc *desc) + { +- u32 port, sport, msg1 = le32_to_cpu(desc->msg1); ++ u32 port, sport, msg1 = le32_to_cpu(READ_ONCE(desc->msg1)); + + sport = FIELD_GET(QDMA_ETH_RXMSG_SPORT_MASK, msg1); + switch (sport) { +@@ -612,21 +612,24 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) + while (done < budget) { + struct airoha_queue_entry *e = &q->entry[q->tail]; + struct airoha_qdma_desc *desc = &q->desc[q->tail]; +- u32 hash, reason, msg1 = le32_to_cpu(desc->msg1); +- struct page *page = virt_to_head_page(e->buf); +- u32 desc_ctrl = le32_to_cpu(desc->ctrl); ++ u32 hash, reason, msg1, desc_ctrl; + struct airoha_gdm_port *port; + int data_len, len, p; ++ struct page *page; + ++ desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); + if (!(desc_ctrl & QDMA_DESC_DONE_MASK)) + break; + ++ dma_rmb(); ++ + q->tail = (q->tail + 1) % q->ndesc; + q->queued--; + + dma_sync_single_for_cpu(eth->dev, e->dma_addr, + SKB_WITH_OVERHEAD(q->buf_size), dir); + ++ page = virt_to_head_page(e->buf); + len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl); + data_len = q->skb ? q->buf_size + : SKB_WITH_OVERHEAD(q->buf_size); +@@ -670,8 +673,8 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) + * DMA descriptor. Report DSA tag to the DSA stack + * via skb dst info. + */ +- u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG, +- le32_to_cpu(desc->msg0)); ++ u32 msg0 = le32_to_cpu(READ_ONCE(desc->msg0)); ++ u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG, msg0); + + if (sptag < ARRAY_SIZE(port->dsa_meta) && + port->dsa_meta[sptag]) +@@ -679,6 +682,7 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget) + &port->dsa_meta[sptag]->dst); + } + ++ msg1 = le32_to_cpu(READ_ONCE(desc->msg1)); + hash = FIELD_GET(AIROHA_RXD4_FOE_ENTRY, msg1); + if (hash != AIROHA_RXD4_FOE_ENTRY) + skb_set_hash(q->skb, jhash_1word(hash, 0), +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-add-missing-bits-in-airoha_qdma_cleanup_t.patch b/queue-7.0/net-airoha-add-missing-bits-in-airoha_qdma_cleanup_t.patch new file mode 100644 index 0000000000..a30184a5cd --- /dev/null +++ b/queue-7.0/net-airoha-add-missing-bits-in-airoha_qdma_cleanup_t.patch @@ -0,0 +1,82 @@ +From 0a5999cd9757a75f721cef766d6d05826a382795 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 08:36:32 +0200 +Subject: net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue() + +From: Lorenzo Bianconi + +[ Upstream commit 3309965fe44c00fd65af7cef5016e9e782c021a7 ] + +Similar to airoha_qdma_cleanup_rx_queue(), reset DMA TX descriptors in +airoha_qdma_cleanup_tx_queue routine. Moreover, reset TX_DMA_IDX to +TX_CPU_IDX to notify the NIC the QDMA TX ring is empty. + +Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260417-airoha_qdma_cleanup_tx_queue-fix-net-v4-2-e04bcc2c9642@kernel.org +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 32 ++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index ab166c1d04d30..be0fece69bc32 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1063,12 +1063,15 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma) + + static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) + { +- struct airoha_eth *eth = q->qdma->eth; +- int i; ++ struct airoha_qdma *qdma = q->qdma; ++ struct airoha_eth *eth = qdma->eth; ++ int i, qid = q - &qdma->q_tx[0]; ++ u16 index = 0; + + spin_lock_bh(&q->lock); + for (i = 0; i < q->ndesc; i++) { + struct airoha_queue_entry *e = &q->entry[i]; ++ struct airoha_qdma_desc *desc = &q->desc[i]; + + if (!e->dma_addr) + continue; +@@ -1079,8 +1082,33 @@ static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) + e->dma_addr = 0; + e->skb = NULL; + list_add_tail(&e->list, &q->tx_list); ++ ++ /* Reset DMA descriptor */ ++ WRITE_ONCE(desc->ctrl, 0); ++ WRITE_ONCE(desc->addr, 0); ++ WRITE_ONCE(desc->data, 0); ++ WRITE_ONCE(desc->msg0, 0); ++ WRITE_ONCE(desc->msg1, 0); ++ WRITE_ONCE(desc->msg2, 0); ++ + q->queued--; + } ++ ++ if (!list_empty(&q->tx_list)) { ++ struct airoha_queue_entry *e; ++ ++ e = list_first_entry(&q->tx_list, struct airoha_queue_entry, ++ list); ++ index = e - q->entry; ++ } ++ /* Set TX_DMA_IDX to TX_CPU_IDX to notify the hw the QDMA TX ring is ++ * empty. ++ */ ++ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, ++ FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); ++ airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK, ++ FIELD_PREP(TX_RING_DMA_IDX_MASK, index)); ++ + spin_unlock_bh(&q->lock); + } + +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-add-missing-ppe-configurations-in-airoha_.patch b/queue-7.0/net-airoha-add-missing-ppe-configurations-in-airoha_.patch new file mode 100644 index 0000000000..76bdbe07f9 --- /dev/null +++ b/queue-7.0/net-airoha-add-missing-ppe-configurations-in-airoha_.patch @@ -0,0 +1,71 @@ +From eda68c5fd2dae768295a205237f37edfab17f229 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 10:43:26 +0200 +Subject: net: airoha: Add missing PPE configurations in airoha_ppe_hw_init() + +From: Lorenzo Bianconi + +[ Upstream commit b9d8b856689d2b968495d79fe653d87fcb8ad98c ] + +Add the following PPE configuration in airoha_ppe_hw_init routine: +- 6RD hw offloading is currently not supported by Netfilter flowtable. + Disable explicitly PPE 6RD offloading in order to prevent PPE to learn + 6RD flows and eventually interrupt the traffic. +- Add missing PPE bind rate configuration for L3 and L2 traffic. + PPE bind rate configuration specifies the pps threshold to move a PPE + entry state from UNBIND to BIND. Without this configuration this value + is random. +- Set ageing thresholds to the values used in the vendor SDK in order to + improve connection stability under load and avoid packet loss caused by + fast aging. + +Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260412-airoha_ppe_hw_init-missing-bits-v1-1-06ac670819e3@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_ppe.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index c2c32b6833df9..62cfffb4f0e55 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -111,13 +111,13 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + airoha_fe_rmw(eth, REG_PPE_BND_AGE0(i), + PPE_BIND_AGE0_DELTA_NON_L4 | + PPE_BIND_AGE0_DELTA_UDP, +- FIELD_PREP(PPE_BIND_AGE0_DELTA_NON_L4, 1) | +- FIELD_PREP(PPE_BIND_AGE0_DELTA_UDP, 12)); ++ FIELD_PREP(PPE_BIND_AGE0_DELTA_NON_L4, 60) | ++ FIELD_PREP(PPE_BIND_AGE0_DELTA_UDP, 60)); + airoha_fe_rmw(eth, REG_PPE_BND_AGE1(i), + PPE_BIND_AGE1_DELTA_TCP_FIN | + PPE_BIND_AGE1_DELTA_TCP, + FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP_FIN, 1) | +- FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP, 7)); ++ FIELD_PREP(PPE_BIND_AGE1_DELTA_TCP, 60)); + + airoha_fe_rmw(eth, REG_PPE_TB_HASH_CFG(i), + PPE_SRAM_TABLE_EN_MASK | +@@ -145,7 +145,15 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) + FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, + dram_num_entries)); + ++ airoha_fe_rmw(eth, REG_PPE_BIND_RATE(i), ++ PPE_BIND_RATE_L2B_BIND_MASK | ++ PPE_BIND_RATE_BIND_MASK, ++ FIELD_PREP(PPE_BIND_RATE_L2B_BIND_MASK, 0x1e) | ++ FIELD_PREP(PPE_BIND_RATE_BIND_MASK, 0x1e)); ++ + airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED); ++ airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i), ++ PPE_FLOW_CFG_IP6_6RD_MASK); + + for (p = 0; p < ARRAY_SIZE(eth->ports); p++) + airoha_fe_rmw(eth, REG_PPE_MTU(i, p), +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch b/queue-7.0/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch new file mode 100644 index 0000000000..8963b28901 --- /dev/null +++ b/queue-7.0/net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch @@ -0,0 +1,44 @@ +From 4fa87c96f1028f70ea949b1401a9bfbf2c60e574 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 20:26:56 +0200 +Subject: net: airoha: Add missing RX_CPU_IDX() configuration in + airoha_qdma_cleanup_rx_queue() + +From: Lorenzo Bianconi + +[ Upstream commit 656121b155030086b01cfce9bd31b0c925ee6860 ] + +When the descriptor index written in REG_RX_CPU_IDX() is equal to the one +stored in REG_RX_DMA_IDX(), the hw will stop since the QDMA RX ring is +empty. +Add missing REG_RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue +routine during QDMA RX ring cleanup. + +Fixes: 514aac359987 ("net: airoha: Add missing cleanup bits in airoha_qdma_cleanup_rx_queue()") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260408-airoha-cpu-idx-airoha_qdma_cleanup_rx_queue-v1-1-8efa64844308@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index c14cdce588a7c..9e995094c32af 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -825,6 +825,11 @@ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q) + } + + q->head = q->tail; ++ /* Set RX_DMA_IDX to RX_CPU_IDX to notify the hw the QDMA RX ring is ++ * empty. ++ */ ++ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, ++ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head)); + airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, + FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail)); + } +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-add-size-check-for-tx-napis-in-airoha_qdm.patch b/queue-7.0/net-airoha-add-size-check-for-tx-napis-in-airoha_qdm.patch new file mode 100644 index 0000000000..203d9a785a --- /dev/null +++ b/queue-7.0/net-airoha-add-size-check-for-tx-napis-in-airoha_qdm.patch @@ -0,0 +1,66 @@ +From 7dd5c8e13c8e76ee0701e817885e45a170b692f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:07:48 +0200 +Subject: net: airoha: Add size check for TX NAPIs in airoha_qdma_cleanup() + +From: Lorenzo Bianconi + +[ Upstream commit 4b91cb65789b794bfc8d50554b8994f8e0f16309 ] + +If airoha_qdma_init routine fails before airoha_qdma_tx_irq_init() runs +successfully for all TX NAPIs, airoha_qdma_cleanup() will +unconditionally runs netif_napi_del() on TX NAPIs, triggering a NULL +pointer dereference. Fix the issue relying on q_tx_irq size value to +check if the TX NAPIs is properly initialized in airoha_qdma_cleanup(). +Moreover, run netif_napi_add_tx() just if irq_q queue is properly +allocated. + +Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260420-airoha_qdma_init_rx_queue-fix-v2-2-d99347e5c18d@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index adff897e9bfde..1bdf90b311060 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1020,8 +1020,6 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q, + struct airoha_eth *eth = qdma->eth; + dma_addr_t dma_addr; + +- netif_napi_add_tx(eth->napi_dev, &irq_q->napi, +- airoha_qdma_tx_napi_poll); + irq_q->q = dmam_alloc_coherent(eth->dev, size * sizeof(u32), + &dma_addr, GFP_KERNEL); + if (!irq_q->q) +@@ -1031,6 +1029,9 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q, + irq_q->size = size; + irq_q->qdma = qdma; + ++ netif_napi_add_tx(eth->napi_dev, &irq_q->napi, ++ airoha_qdma_tx_napi_poll); ++ + airoha_qdma_wr(qdma, REG_TX_IRQ_BASE(id), dma_addr); + airoha_qdma_rmw(qdma, REG_TX_IRQ_CFG(id), TX_IRQ_DEPTH_MASK, + FIELD_PREP(TX_IRQ_DEPTH_MASK, size)); +@@ -1450,8 +1451,12 @@ static void airoha_qdma_cleanup(struct airoha_qdma *qdma) + } + } + +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) ++ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) { ++ if (!qdma->q_tx_irq[i].size) ++ continue; ++ + netif_napi_del(&qdma->q_tx_irq[i].napi); ++ } + + for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { + if (!qdma->q_tx[i].ndesc) +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-do-not-read-uninitialized-fragment-addres.patch b/queue-7.0/net-airoha-do-not-read-uninitialized-fragment-addres.patch new file mode 100644 index 0000000000..3c5683195c --- /dev/null +++ b/queue-7.0/net-airoha-do-not-read-uninitialized-fragment-addres.patch @@ -0,0 +1,74 @@ +From 527a517c8ac38d5acbecc0f4cd9972197e391c53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 11:00:28 +0200 +Subject: net: airoha: Do not read uninitialized fragment address in + airoha_dev_xmit() + +From: Lorenzo Bianconi + +[ Upstream commit bde34e84edc8b5571fbde7e941e175a4293ee1eb ] + +The transmit loop in airoha_dev_xmit() reads fragment address and length +during its final iteration, when the loop index equals +skb_shinfo(skb)->nr_frags, at which point the fragment data is +uninitialized. While these values are never consumed, the read itself is +unsafe and may trigger a page fault. Fix this by avoiding the fragment +read on the last iteration. +Additionally, move the skb pointer from the first to the last used packet +descriptor, so that airoha_qdma_tx_napi_poll() defers freeing the skb +until the final descriptor is processed. + +Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260424-airoha-xmit-fix-read-frag-v1-1-fdc0a83c79e8@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index f9e6406ca55da..3e406d880c0cd 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2005,8 +2005,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + struct netdev_queue *txq; + struct airoha_queue *q; + LIST_HEAD(tx_list); ++ int i = 0, qid; + void *data; +- int i, qid; + u16 index; + u8 fport; + +@@ -2065,7 +2065,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + list); + index = e - q->entry; + +- for (i = 0; i < nr_frags; i++) { ++ while (true) { + struct airoha_qdma_desc *desc = &q->desc[index]; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + dma_addr_t addr; +@@ -2077,7 +2077,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + goto error_unmap; + + list_move_tail(&e->list, &tx_list); +- e->skb = i ? NULL : skb; ++ e->skb = i == nr_frags - 1 ? skb : NULL; + e->dma_addr = addr; + e->dma_len = len; + +@@ -2096,6 +2096,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + WRITE_ONCE(desc->msg1, cpu_to_le32(msg1)); + WRITE_ONCE(desc->msg2, cpu_to_le32(0xffff)); + ++ if (++i == nr_frags) ++ break; ++ + data = skb_frag_address(frag); + len = skb_frag_size(frag); + } +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-do-not-return-err-in-ndo_stop-callback.patch b/queue-7.0/net-airoha-do-not-return-err-in-ndo_stop-callback.patch new file mode 100644 index 0000000000..3e0954daf5 --- /dev/null +++ b/queue-7.0/net-airoha-do-not-return-err-in-ndo_stop-callback.patch @@ -0,0 +1,46 @@ +From 84524aa5fceb51eea8bac7f032145dfa427fc767 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 08:53:16 +0200 +Subject: net: airoha: Do not return err in ndo_stop() callback + +From: Lorenzo Bianconi + +[ Upstream commit 4ca01292ea2f2363660610a65ba0285d7c3309ed ] + +Always complete the airoha_dev_stop() routine regardless of the +airoha_set_vip_for_gdm_port() return value, since errors from +ndo_stop() are ignored by the networking stack and the interface is +always considered down after the call. + +Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260428-airoha-ndo-stop-not-err-v1-1-674506d29a91@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 3e406d880c0cd..83882a8953d25 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1738,13 +1738,10 @@ static int airoha_dev_stop(struct net_device *dev) + { + struct airoha_gdm_port *port = netdev_priv(dev); + struct airoha_qdma *qdma = port->qdma; +- int i, err; ++ int i; + + netif_tx_disable(dev); +- err = airoha_set_vip_for_gdm_port(port, false); +- if (err) +- return err; +- ++ airoha_set_vip_for_gdm_port(port, false); + for (i = 0; i < dev->num_tx_queues; i++) + netdev_tx_reset_subqueue(dev, i); + +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-do-not-wake-all-netdev-tx-queues-in-airoh.patch b/queue-7.0/net-airoha-do-not-wake-all-netdev-tx-queues-in-airoh.patch new file mode 100644 index 0000000000..5c92933e81 --- /dev/null +++ b/queue-7.0/net-airoha-do-not-wake-all-netdev-tx-queues-in-airoh.patch @@ -0,0 +1,87 @@ +From 2da805e3dd3c2b18d2f954a2a46ac31eaaa58e06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 10:53:33 +0200 +Subject: net: airoha: Do not wake all netdev TX queues in + airoha_qdma_wake_netdev_txqs() + +From: Lorenzo Bianconi + +[ Upstream commit e070aac63b42bf81f4dc565f9f841ff47e6c992f ] + +Do not wake every netdev TX queue across all ports sharing the QDMA +running netif_tx_wake_all_queues routine in airoha_qdma_wake_netdev_txqs() +but only the ones that are mapped the specific QDMA stopped hw TX queue. +This patch can potentially avoid waking already stopped netdev TX queues +that are mapped to a different QDMA hw TX queue. +Introduce airoha_qdma_get_txq utility routine. + +Fixes: b94769eb2f30 ("net: airoha: Fix possible TX queue stall in airoha_qdma_tx_napi_poll()") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260421-airoha-wake_netdev_txqs-optmization-v1-1-e0be95115d53@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 19 +++++++++++++++---- + drivers/net/ethernet/airoha/airoha_eth.h | 5 +++++ + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 8819e24283abc..f9e6406ca55da 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -847,13 +847,24 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) + { + struct airoha_qdma *qdma = q->qdma; + struct airoha_eth *eth = qdma->eth; +- int i; ++ int i, qid = q - &qdma->q_tx[0]; + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; ++ int j; ++ ++ if (!port) ++ continue; + +- if (port && port->qdma == qdma) +- netif_tx_wake_all_queues(port->dev); ++ if (port->qdma != qdma) ++ continue; ++ ++ for (j = 0; j < port->dev->num_tx_queues; j++) { ++ if (airoha_qdma_get_txq(qdma, j) != qid) ++ continue; ++ ++ netif_wake_subqueue(port->dev, j); ++ } + } + q->txq_stopped = false; + } +@@ -1999,7 +2010,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + u16 index; + u8 fport; + +- qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx); ++ qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb)); + tag = airoha_get_dsa_tag(skb, dev); + + msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK, +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 46f4197007074..7098e95f0067a 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -630,6 +630,11 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val); + #define airoha_qdma_clear(qdma, offset, val) \ + airoha_rmw((qdma)->regs, (offset), (val), 0) + ++static inline u16 airoha_qdma_get_txq(struct airoha_qdma *qdma, u16 qid) ++{ ++ return qid % ARRAY_SIZE(qdma->q_tx); ++} ++ + static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port) + { + /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-fix-bql-imbalance-in-tx-path.patch b/queue-7.0/net-airoha-fix-bql-imbalance-in-tx-path.patch new file mode 100644 index 0000000000..3786cc1734 --- /dev/null +++ b/queue-7.0/net-airoha-fix-bql-imbalance-in-tx-path.patch @@ -0,0 +1,69 @@ +From 3cfdeae53533a59fc71412e52e16b3a63aa2dd6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 08:35:11 +0200 +Subject: net: airoha: fix BQL imbalance in TX path + +From: Lorenzo Bianconi + +[ Upstream commit 2d9f5a118205da2683ffcec78b9347f1f01a820e ] + +Fix a possible BQL imbalance in airoha_dev_xmit(), where inflight +packets are accounted only for the AIROHA_NUM_TX_RING netdev TX +queues. The queue index is computed as: + + qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx) + txq = netdev_get_tx_queue(dev, qid); + +However, airoha_qdma_tx_napi_poll() accounts completions across all +netdev TX queues (num_tx_queues), leading to inconsistent BQL +accounting. + +Also reset all netdev TX queues in the ndo_stop callback. + +Fixes: 1d304174106c ("net: airoha: Implement BQL support") +Fixes: c9f947769b77 ("net: airoha: Reset BQL stopping the netdevice") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260421-airoha-fix-bql-v1-1-f135afe4275b@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 1bdf90b311060..a73c224d65755 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -929,10 +929,9 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) + q->queued--; + + if (skb) { +- u16 queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq; + +- txq = netdev_get_tx_queue(skb->dev, queue); ++ txq = skb_get_tx_queue(skb->dev, skb); + netdev_tx_completed_queue(txq, 1, skb->len); + dev_kfree_skb_any(skb); + } +@@ -1735,7 +1734,7 @@ static int airoha_dev_stop(struct net_device *dev) + if (err) + return err; + +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) ++ for (i = 0; i < dev->num_tx_queues; i++) + netdev_tx_reset_subqueue(dev, i); + + if (atomic_dec_and_test(&qdma->users)) { +@@ -2037,7 +2036,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + + spin_lock_bh(&q->lock); + +- txq = netdev_get_tx_queue(dev, qid); ++ txq = skb_get_tx_queue(dev, skb); + nr_frags = 1 + skb_shinfo(skb)->nr_frags; + + if (q->queued + nr_frags >= q->ndesc) { +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-fix-fe_pse_buf_set-configuration-if-ppe2-.patch b/queue-7.0/net-airoha-fix-fe_pse_buf_set-configuration-if-ppe2-.patch new file mode 100644 index 0000000000..be922b03e2 --- /dev/null +++ b/queue-7.0/net-airoha-fix-fe_pse_buf_set-configuration-if-ppe2-.patch @@ -0,0 +1,54 @@ +From f2a9da64833503a15e649dd4613cbe2c12126671 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 12:20:09 +0200 +Subject: net: airoha: Fix FE_PSE_BUF_SET configuration if PPE2 is available + +From: Lorenzo Bianconi + +[ Upstream commit 02f72964395911e7a09bb2ea2fe6f79eda4ea2c2 ] + +airoha_fe_set routine is used to set specified bits to 1 in the selected +register. In the FE_PSE_BUF_SET case this can due to a overestimation of +the required buffers for I/O queues since we can miss to set some bits +of PSE_ALLRSV_MASK subfield to 0. Fix the issue relying on airoha_fe_rmw +routine instead. + +Fixes: 8e38e08f2c560 ("net: airoha: fix PSE memory configuration in airoha_fe_pse_ports_init()") +Tested-by: Xuegang Lu +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260408-airoha-reg_fe_pse_buf_set-v1-1-0c4fa8f4d1d9@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 9285a68f435fe..c14cdce588a7c 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -293,16 +293,18 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth) + [FE_PSE_PORT_GDM4] = 2, + [FE_PSE_PORT_CDM5] = 2, + }; +- u32 all_rsv; + int q; + +- all_rsv = airoha_fe_get_pse_all_rsv(eth); + if (airoha_ppe_is_enabled(eth, 1)) { ++ u32 all_rsv; ++ + /* hw misses PPE2 oq rsv */ ++ all_rsv = airoha_fe_get_pse_all_rsv(eth); + all_rsv += PSE_RSV_PAGES * + pse_port_num_queues[FE_PSE_PORT_PPE2]; ++ airoha_fe_rmw(eth, REG_FE_PSE_BUF_SET, PSE_ALLRSV_MASK, ++ FIELD_PREP(PSE_ALLRSV_MASK, all_rsv)); + } +- airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv); + + /* CMD1 */ + for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_CDM1]; q++) +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-fix-possible-tx-queue-stall-in-airoha_qdm.patch b/queue-7.0/net-airoha-fix-possible-tx-queue-stall-in-airoha_qdm.patch new file mode 100644 index 0000000000..2ab985d7bd --- /dev/null +++ b/queue-7.0/net-airoha-fix-possible-tx-queue-stall-in-airoha_qdm.patch @@ -0,0 +1,116 @@ +From 473dd52a1bcee82a732411a2a6ee92f638d8db44 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 12:30:12 +0200 +Subject: net: airoha: Fix possible TX queue stall in + airoha_qdma_tx_napi_poll() + +From: Lorenzo Bianconi + +[ Upstream commit b94769eb2f30e61e86cd8551c084c34134290d89 ] + +Since multiple net_device TX queues can share the same hw QDMA TX queue, +there is no guarantee we have inflight packets queued in hw belonging to a +net_device TX queue stopped in the xmit path because hw QDMA TX queue +can be full. In this corner case the net_device TX queue will never be +re-activated. In order to avoid any potential net_device TX queue stall, +we need to wake all the net_device TX queues feeding the same hw QDMA TX +queue in airoha_qdma_tx_napi_poll routine. + +Fixes: 23020f0493270 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416-airoha-txq-potential-stall-v2-1-42c732074540@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 37 ++++++++++++++++++++---- + drivers/net/ethernet/airoha/airoha_eth.h | 1 + + 2 files changed, 33 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index f484835af703c..3deffc499bcb4 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -843,6 +843,21 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma) + return 0; + } + ++static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) ++{ ++ struct airoha_qdma *qdma = q->qdma; ++ struct airoha_eth *eth = qdma->eth; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { ++ struct airoha_gdm_port *port = eth->ports[i]; ++ ++ if (port && port->qdma == qdma) ++ netif_tx_wake_all_queues(port->dev); ++ } ++ q->txq_stopped = false; ++} ++ + static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) + { + struct airoha_tx_irq_queue *irq_q; +@@ -919,12 +934,21 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) + + txq = netdev_get_tx_queue(skb->dev, queue); + netdev_tx_completed_queue(txq, 1, skb->len); +- if (netif_tx_queue_stopped(txq) && +- q->ndesc - q->queued >= q->free_thr) +- netif_tx_wake_queue(txq); +- + dev_kfree_skb_any(skb); + } ++ ++ if (q->txq_stopped && q->ndesc - q->queued >= q->free_thr) { ++ /* Since multiple net_device TX queues can share the ++ * same hw QDMA TX queue, there is no guarantee we have ++ * inflight packets queued in hw belonging to a ++ * net_device TX queue stopped in the xmit path. ++ * In order to avoid any potential net_device TX queue ++ * stall, we need to wake all the net_device TX queues ++ * feeding the same hw QDMA TX queue. ++ */ ++ airoha_qdma_wake_netdev_txqs(q); ++ } ++ + unlock: + spin_unlock_bh(&q->lock); + } +@@ -1970,6 +1994,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + if (q->queued + nr_frags >= q->ndesc) { + /* not enough space in the queue */ + netif_tx_stop_queue(txq); ++ q->txq_stopped = true; + spin_unlock_bh(&q->lock); + return NETDEV_TX_BUSY; + } +@@ -2025,8 +2050,10 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + TX_RING_CPU_IDX_MASK, + FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); + +- if (q->ndesc - q->queued < q->free_thr) ++ if (q->ndesc - q->queued < q->free_thr) { + netif_tx_stop_queue(txq); ++ q->txq_stopped = true; ++ } + + spin_unlock_bh(&q->lock); + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index 8bcd809e6f53e..c9d1abda47768 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -193,6 +193,7 @@ struct airoha_queue { + int ndesc; + int free_thr; + int buf_size; ++ bool txq_stopped; + + struct napi_struct napi; + struct page_pool *page_pool; +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-fix-typo-in-function-name.patch b/queue-7.0/net-airoha-fix-typo-in-function-name.patch new file mode 100644 index 0000000000..fd57dd424d --- /dev/null +++ b/queue-7.0/net-airoha-fix-typo-in-function-name.patch @@ -0,0 +1,68 @@ +From c4a9bd1db57f179d4e8067e1a6b36316da87e0ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:37:08 +0800 +Subject: net: airoha: fix typo in function name + +From: Zhengping Zhang + +[ Upstream commit aebf15e8eb09b01e99f043e9f5d423798aac9d32 ] + +Corrected the typo in the function name from + `airhoa_is_lan_gdm_port` to `airoha_is_lan_gdm_port`. This change ensures + consistency in the API naming convention. + +Signed-off-by: Zhengping Zhang +Reviewed-by: Simon Horman +Acked-by: Lorenzo Bianconi +Link: https://patch.msgid.link/tencent_E4FD5D6BC0131E617D848896F5F9FCED6E0A@qq.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: e070aac63b42 ("net: airoha: Do not wake all netdev TX queues in airoha_qdma_wake_netdev_txqs()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 2 +- + drivers/net/ethernet/airoha/airoha_eth.h | 2 +- + drivers/net/ethernet/airoha/airoha_ppe.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 4b804ca927819..8819e24283abc 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -76,7 +76,7 @@ static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr) + struct airoha_eth *eth = port->qdma->eth; + u32 val, reg; + +- reg = airhoa_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H ++ reg = airoha_is_lan_gdm_port(port) ? REG_FE_LAN_MAC_H + : REG_FE_WAN_MAC_H; + val = (addr[0] << 16) | (addr[1] << 8) | addr[2]; + airoha_fe_wr(eth, reg, val); +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index c9d1abda47768..46f4197007074 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -630,7 +630,7 @@ u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val); + #define airoha_qdma_clear(qdma, offset, val) \ + airoha_rmw((qdma)->regs, (offset), (val), 0) + +-static inline bool airhoa_is_lan_gdm_port(struct airoha_gdm_port *port) ++static inline bool airoha_is_lan_gdm_port(struct airoha_gdm_port *port) + { + /* GDM1 port on EN7581 SoC is connected to the lan dsa switch. + * GDM{2,3,4} can be used as wan port connected to an external +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 684c8ae9576f1..f2af45f7d66d4 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -331,7 +331,7 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth, + /* For downlink traffic consume SRAM memory for hw + * forwarding descriptors queue. + */ +- if (airhoa_is_lan_gdm_port(port)) ++ if (airoha_is_lan_gdm_port(port)) + val |= AIROHA_FOE_IB2_FAST_PATH; + if (dsa_port >= 0) + val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-fix-vip-configuration-for-an7583-soc.patch b/queue-7.0/net-airoha-fix-vip-configuration-for-an7583-soc.patch new file mode 100644 index 0000000000..2d7f64be57 --- /dev/null +++ b/queue-7.0/net-airoha-fix-vip-configuration-for-an7583-soc.patch @@ -0,0 +1,176 @@ +From 3923b4961af693614ebe5603a0724053325740b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 09:57:29 +0200 +Subject: net: airoha: Fix VIP configuration for AN7583 SoC + +From: Lorenzo Bianconi + +[ Upstream commit 1acdfbdb516b32165a8ecd1d5f8c68e4eac64637 ] + +EN7581 and AN7583 SoCs have different VIP definitions. Introduce +get_vip_port callback in airoha_eth_soc_data struct in order to take +into account EN7581 and AN7583 VIP register layout and definition +differences. +Introduce nbq parameter in airoha_gdm_port struct. At the moment nbq +is set statically to value previously used in airhoha_set_gdm2_loopback +routine and it will be read from device tree in subsequent patches. + +Fixes: e4e5ce823bdd ("net: airoha: Add AN7583 SoC support") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260412-airoha-7583-vip-fix-v1-1-c35e02b054bb@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 66 ++++++++++++++++++------ + drivers/net/ethernet/airoha/airoha_eth.h | 2 + + 2 files changed, 51 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 9e995094c32af..f484835af703c 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -107,19 +107,7 @@ static int airoha_set_vip_for_gdm_port(struct airoha_gdm_port *port, + struct airoha_eth *eth = port->qdma->eth; + u32 vip_port; + +- switch (port->id) { +- case AIROHA_GDM3_IDX: +- /* FIXME: handle XSI_PCIE1_PORT */ +- vip_port = XSI_PCIE0_VIP_PORT_MASK; +- break; +- case AIROHA_GDM4_IDX: +- /* FIXME: handle XSI_USB_PORT */ +- vip_port = XSI_ETH_VIP_PORT_MASK; +- break; +- default: +- return 0; +- } +- ++ vip_port = eth->soc->ops.get_vip_port(port, port->nbq); + if (enable) { + airoha_fe_set(eth, REG_FE_VIP_PORT_EN, vip_port); + airoha_fe_set(eth, REG_FE_IFC_PORT_EN, vip_port); +@@ -1710,7 +1698,7 @@ static int airoha_dev_set_macaddr(struct net_device *dev, void *p) + static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) + { + struct airoha_eth *eth = port->qdma->eth; +- u32 val, pse_port, chan, nbq; ++ u32 val, pse_port, chan; + int src_port; + + /* Forward the traffic to the proper GDM port */ +@@ -1740,9 +1728,7 @@ static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) + airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(AIROHA_GDM2_IDX)); + airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(AIROHA_GDM2_IDX)); + +- /* XXX: handle XSI_USB_PORT and XSI_PCE1_PORT */ +- nbq = port->id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0; +- src_port = eth->soc->ops.get_src_port_id(port, nbq); ++ src_port = eth->soc->ops.get_src_port_id(port, port->nbq); + if (src_port < 0) + return src_port; + +@@ -2951,6 +2937,8 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth, + port->qdma = qdma; + port->dev = dev; + port->id = id; ++ /* XXX: Read nbq from DTS */ ++ port->nbq = id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0; + eth->ports[p] = port; + + return airoha_metadata_dst_alloc(port); +@@ -3152,6 +3140,28 @@ static int airoha_en7581_get_src_port_id(struct airoha_gdm_port *port, int nbq) + return -EINVAL; + } + ++static u32 airoha_en7581_get_vip_port(struct airoha_gdm_port *port, int nbq) ++{ ++ switch (port->id) { ++ case AIROHA_GDM3_IDX: ++ if (nbq == 4) ++ return XSI_PCIE0_VIP_PORT_MASK; ++ if (nbq == 5) ++ return XSI_PCIE1_VIP_PORT_MASK; ++ break; ++ case AIROHA_GDM4_IDX: ++ if (!nbq) ++ return XSI_ETH_VIP_PORT_MASK; ++ if (nbq == 1) ++ return XSI_USB_VIP_PORT_MASK; ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ + static const char * const an7583_xsi_rsts_names[] = { + "xsi-mac", + "hsi0-mac", +@@ -3181,6 +3191,26 @@ static int airoha_an7583_get_src_port_id(struct airoha_gdm_port *port, int nbq) + return -EINVAL; + } + ++static u32 airoha_an7583_get_vip_port(struct airoha_gdm_port *port, int nbq) ++{ ++ switch (port->id) { ++ case AIROHA_GDM3_IDX: ++ if (!nbq) ++ return XSI_ETH_VIP_PORT_MASK; ++ break; ++ case AIROHA_GDM4_IDX: ++ if (!nbq) ++ return XSI_PCIE0_VIP_PORT_MASK; ++ if (nbq == 1) ++ return XSI_USB_VIP_PORT_MASK; ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ + static const struct airoha_eth_soc_data en7581_soc_data = { + .version = 0x7581, + .xsi_rsts_names = en7581_xsi_rsts_names, +@@ -3188,6 +3218,7 @@ static const struct airoha_eth_soc_data en7581_soc_data = { + .num_ppe = 2, + .ops = { + .get_src_port_id = airoha_en7581_get_src_port_id, ++ .get_vip_port = airoha_en7581_get_vip_port, + }, + }; + +@@ -3198,6 +3229,7 @@ static const struct airoha_eth_soc_data an7583_soc_data = { + .num_ppe = 1, + .ops = { + .get_src_port_id = airoha_an7583_get_src_port_id, ++ .get_vip_port = airoha_an7583_get_vip_port, + }, + }; + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h +index a97903569335f..8bcd809e6f53e 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.h ++++ b/drivers/net/ethernet/airoha/airoha_eth.h +@@ -536,6 +536,7 @@ struct airoha_gdm_port { + struct airoha_qdma *qdma; + struct net_device *dev; + int id; ++ int nbq; + + struct airoha_hw_stats stats; + +@@ -576,6 +577,7 @@ struct airoha_eth_soc_data { + int num_ppe; + struct { + int (*get_src_port_id)(struct airoha_gdm_port *port, int nbq); ++ u32 (*get_vip_port)(struct airoha_gdm_port *port, int nbq); + } ops; + }; + +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch b/queue-7.0/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch new file mode 100644 index 0000000000..ae3891f866 --- /dev/null +++ b/queue-7.0/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch @@ -0,0 +1,65 @@ +From 63cda8e01b8bd851d108303279a17cd30b8cadd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 08:36:31 +0200 +Subject: net: airoha: Move ndesc initialization at end of + airoha_qdma_init_tx() + +From: Lorenzo Bianconi + +[ Upstream commit f329924bb49458c65297f1361f545816a5b90998 ] + +If queue entry list allocation fails in airoha_qdma_init_tx_queue routine, +airoha_qdma_cleanup_tx_queue() will trigger a NULL pointer dereference +accessing the queue entry array. The issue is due to the early ndesc +initialization in airoha_qdma_init_tx_queue(). Fix the issue moving ndesc +initialization at end of airoha_qdma_init_tx routine. + +Fixes: 3f47e67dff1f7 ("net: airoha: Add the capability to consume out-of-order DMA tx descriptors") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260417-airoha_qdma_cleanup_tx_queue-fix-net-v4-1-e04bcc2c9642@kernel.org +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 3deffc499bcb4..ab166c1d04d30 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -978,27 +978,27 @@ static int airoha_qdma_init_tx_queue(struct airoha_queue *q, + dma_addr_t dma_addr; + + spin_lock_init(&q->lock); +- q->ndesc = size; + q->qdma = qdma; + q->free_thr = 1 + MAX_SKB_FRAGS; + INIT_LIST_HEAD(&q->tx_list); + +- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry), ++ q->entry = devm_kzalloc(eth->dev, size * sizeof(*q->entry), + GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + +- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc), ++ q->desc = dmam_alloc_coherent(eth->dev, size * sizeof(*q->desc), + &dma_addr, GFP_KERNEL); + if (!q->desc) + return -ENOMEM; + +- for (i = 0; i < q->ndesc; i++) { ++ for (i = 0; i < size; i++) { + u32 val = FIELD_PREP(QDMA_DESC_DONE_MASK, 1); + + list_add_tail(&q->entry[i].list, &q->tx_list); + WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val)); + } ++ q->ndesc = size; + + /* xmit ring drop default setting */ + airoha_qdma_set(qdma, REG_TX_RING_BLOCKING(qid), +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch-16210 b/queue-7.0/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch-16210 new file mode 100644 index 0000000000..cc9c70f040 --- /dev/null +++ b/queue-7.0/net-airoha-move-ndesc-initialization-at-end-of-airoh.patch-16210 @@ -0,0 +1,71 @@ +From 548dc07296fa1e59cabb29da13097653f674e415 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:07:47 +0200 +Subject: net: airoha: Move ndesc initialization at end of + airoha_qdma_init_rx_queue() + +From: Lorenzo Bianconi + +[ Upstream commit 379050947a1828826ad7ea50c95245a56929b35a ] + +If queue entry or DMA descriptor list allocation fails in +airoha_qdma_init_rx_queue routine, airoha_qdma_cleanup() will trigger a +NULL pointer dereference running netif_napi_del() for RX queue NAPIs +since netif_napi_add() has never been executed to this particular RX NAPI. +The issue is due to the early ndesc initialization in +airoha_qdma_init_rx_queue() since airoha_qdma_cleanup() relies on ndesc +value to check if the queue is properly initialized. Fix the issue moving +ndesc initialization at end of airoha_qdma_init_tx routine. +Move page_pool allocation after descriptor list allocation in order to +avoid memory leaks if desc allocation fails. + +Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260420-airoha_qdma_init_rx_queue-fix-v2-1-d99347e5c18d@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index be0fece69bc32..3f0e795353372 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -745,14 +745,18 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, + dma_addr_t dma_addr; + + q->buf_size = PAGE_SIZE / 2; +- q->ndesc = ndesc; + q->qdma = qdma; + +- q->entry = devm_kzalloc(eth->dev, q->ndesc * sizeof(*q->entry), ++ q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry), + GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + ++ q->desc = dmam_alloc_coherent(eth->dev, ndesc * sizeof(*q->desc), ++ &dma_addr, GFP_KERNEL); ++ if (!q->desc) ++ return -ENOMEM; ++ + q->page_pool = page_pool_create(&pp_params); + if (IS_ERR(q->page_pool)) { + int err = PTR_ERR(q->page_pool); +@@ -761,11 +765,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, + return err; + } + +- q->desc = dmam_alloc_coherent(eth->dev, q->ndesc * sizeof(*q->desc), +- &dma_addr, GFP_KERNEL); +- if (!q->desc) +- return -ENOMEM; +- ++ q->ndesc = ndesc; + netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll); + + airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr); +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-rework-the-code-flow-in-airoha_remove-and.patch b/queue-7.0/net-airoha-rework-the-code-flow-in-airoha_remove-and.patch new file mode 100644 index 0000000000..d481e98a68 --- /dev/null +++ b/queue-7.0/net-airoha-rework-the-code-flow-in-airoha_remove-and.patch @@ -0,0 +1,176 @@ +From 8f97911bb6acddb27e31f5dd27cc82463a433d27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Mar 2026 15:41:44 +0100 +Subject: net: airoha: Rework the code flow in airoha_remove() and in + airoha_probe() error path + +From: Lorenzo Bianconi + +[ Upstream commit b1c803d5c8167026791abfaed96fd3e6a1fcd750 ] + +As suggested by Simon in [0], rework the code flow in airoha_remove() +and in the airoha_probe() error path in order to rely on a more common +approach un-registering configured net-devices first and destroying the +hw resources at the end of the code. +Introduce airoha_qdma_cleanup routine to release QDMA resources. + +[0] https://lore.kernel.org/netdev/20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org/ + +Suggested-by: Simon Horman +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260321-airoha-remove-rework-v2-1-16c7bade5fe5@kernel.org +Signed-off-by: Paolo Abeni +Stable-dep-of: 4b91cb65789b ("net: airoha: Add size check for TX NAPIs in airoha_qdma_cleanup()") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 76 ++++++++++++++---------- + 1 file changed, 44 insertions(+), 32 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 3f0e795353372..adff897e9bfde 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -1434,6 +1434,33 @@ static int airoha_qdma_init(struct platform_device *pdev, + return airoha_qdma_hw_init(qdma); + } + ++static void airoha_qdma_cleanup(struct airoha_qdma *qdma) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { ++ if (!qdma->q_rx[i].ndesc) ++ continue; ++ ++ netif_napi_del(&qdma->q_rx[i].napi); ++ airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]); ++ if (qdma->q_rx[i].page_pool) { ++ page_pool_destroy(qdma->q_rx[i].page_pool); ++ qdma->q_rx[i].page_pool = NULL; ++ } ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) ++ netif_napi_del(&qdma->q_tx_irq[i].napi); ++ ++ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { ++ if (!qdma->q_tx[i].ndesc) ++ continue; ++ ++ airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); ++ } ++} ++ + static int airoha_hw_init(struct platform_device *pdev, + struct airoha_eth *eth) + { +@@ -1461,41 +1488,30 @@ static int airoha_hw_init(struct platform_device *pdev, + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) { + err = airoha_qdma_init(pdev, eth, ð->qdma[i]); + if (err) +- return err; ++ goto error; + } + + err = airoha_ppe_init(eth); + if (err) +- return err; ++ goto error; + + set_bit(DEV_STATE_INITIALIZED, ð->state); + + return 0; ++error: ++ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) ++ airoha_qdma_cleanup(ð->qdma[i]); ++ ++ return err; + } + +-static void airoha_hw_cleanup(struct airoha_qdma *qdma) ++static void airoha_hw_cleanup(struct airoha_eth *eth) + { + int i; + +- for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { +- if (!qdma->q_rx[i].ndesc) +- continue; +- +- netif_napi_del(&qdma->q_rx[i].napi); +- airoha_qdma_cleanup_rx_queue(&qdma->q_rx[i]); +- if (qdma->q_rx[i].page_pool) +- page_pool_destroy(qdma->q_rx[i].page_pool); +- } +- +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) +- netif_napi_del(&qdma->q_tx_irq[i].napi); +- +- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { +- if (!qdma->q_tx[i].ndesc) +- continue; +- +- airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); +- } ++ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) ++ airoha_qdma_cleanup(ð->qdma[i]); ++ airoha_ppe_deinit(eth); + } + + static void airoha_qdma_start_napi(struct airoha_qdma *qdma) +@@ -3088,7 +3104,7 @@ static int airoha_probe(struct platform_device *pdev) + + err = airoha_hw_init(pdev, eth); + if (err) +- goto error_hw_cleanup; ++ goto error_netdev_free; + + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_qdma_start_napi(ð->qdma[i]); +@@ -3117,10 +3133,6 @@ static int airoha_probe(struct platform_device *pdev) + error_napi_stop: + for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_qdma_stop_napi(ð->qdma[i]); +- airoha_ppe_deinit(eth); +-error_hw_cleanup: +- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) +- airoha_hw_cleanup(ð->qdma[i]); + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; +@@ -3132,6 +3144,8 @@ static int airoha_probe(struct platform_device *pdev) + unregister_netdev(port->dev); + airoha_metadata_dst_free(port); + } ++ airoha_hw_cleanup(eth); ++error_netdev_free: + free_netdev(eth->napi_dev); + platform_set_drvdata(pdev, NULL); + +@@ -3143,10 +3157,8 @@ static void airoha_remove(struct platform_device *pdev) + struct airoha_eth *eth = platform_get_drvdata(pdev); + int i; + +- for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) { ++ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) + airoha_qdma_stop_napi(ð->qdma[i]); +- airoha_hw_cleanup(ð->qdma[i]); +- } + + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; +@@ -3157,9 +3169,9 @@ static void airoha_remove(struct platform_device *pdev) + unregister_netdev(port->dev); + airoha_metadata_dst_free(port); + } +- free_netdev(eth->napi_dev); ++ airoha_hw_cleanup(eth); + +- airoha_ppe_deinit(eth); ++ free_netdev(eth->napi_dev); + platform_set_drvdata(pdev, NULL); + } + +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-stop-net_device-tx-queue-before-updating-.patch b/queue-7.0/net-airoha-stop-net_device-tx-queue-before-updating-.patch new file mode 100644 index 0000000000..ae40ecda50 --- /dev/null +++ b/queue-7.0/net-airoha-stop-net_device-tx-queue-before-updating-.patch @@ -0,0 +1,55 @@ +From 649cdb11c7a950d1aac11877b5f407037c4d6a30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 08:43:07 +0200 +Subject: net: airoha: stop net_device TX queue before updating CPU index + +From: Lorenzo Bianconi + +[ Upstream commit 3854de7b38be742cf7558476956d12414cb274f2 ] + +Currently, airoha_eth driver updates the CPU index register prior of +verifying whether the number of free descriptors has fallen below the +threshold. +Move net_device TX queue length check before updating the TX CPU index +in order to update TX CPU index even if there are more packets to be +transmitted but the net_device TX queue is going to be stopped +accounting the inflight packets. + +Fixes: 1d304174106c ("net: airoha: Implement BQL support") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260421-airoha-xmit-stop-condition-v1-1-e670d6a48467@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index a73c224d65755..4b804ca927819 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2092,17 +2092,16 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, + + skb_tx_timestamp(skb); + netdev_tx_sent_queue(txq, skb->len); ++ if (q->ndesc - q->queued < q->free_thr) { ++ netif_tx_stop_queue(txq); ++ q->txq_stopped = true; ++ } + + if (netif_xmit_stopped(txq) || !netdev_xmit_more()) + airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), + TX_RING_CPU_IDX_MASK, + FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); + +- if (q->ndesc - q->queued < q->free_thr) { +- netif_tx_stop_queue(txq); +- q->txq_stopped = true; +- } +- + spin_unlock_bh(&q->lock); + + return NETDEV_TX_OK; +-- +2.53.0 + diff --git a/queue-7.0/net-airoha-wait-for-npu-ppe-configuration-to-complet.patch b/queue-7.0/net-airoha-wait-for-npu-ppe-configuration-to-complet.patch new file mode 100644 index 0000000000..59b659999f --- /dev/null +++ b/queue-7.0/net-airoha-wait-for-npu-ppe-configuration-to-complet.patch @@ -0,0 +1,73 @@ +From 59b2c406b04dea8f886c52a1bca00aec4bf87c05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:08:52 +0200 +Subject: net: airoha: Wait for NPU PPE configuration to complete in + airoha_ppe_offload_setup() + +From: Lorenzo Bianconi + +[ Upstream commit f3206328bb52c2787197d80d7cbd687946047d5f ] + +In order to properly enable flowtable hw offloading, poll +REG_PPE_FLOW_CFG register in airoha_ppe_offload_setup routine and +wait for NPU PPE configuration triggered by ppe_init callback to complete +before running airoha_ppe_hw_init(). + +Fixes: 00a7678310fe3 ("net: airoha: Introduce flowtable offload support") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260414-airoha-wait-for-npu-config-offload-setup-v2-1-5a9bf6d43aee@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_ppe.c | 28 ++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 62cfffb4f0e55..684c8ae9576f1 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -1335,6 +1335,29 @@ static struct airoha_npu *airoha_ppe_npu_get(struct airoha_eth *eth) + return npu; + } + ++static int airoha_ppe_wait_for_npu_init(struct airoha_eth *eth) ++{ ++ int err; ++ u32 val; ++ ++ /* PPE_FLOW_CFG default register value is 0. Since we reset FE ++ * during the device probe we can just check the configured value ++ * is not 0 here. ++ */ ++ err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC, ++ 100 * USEC_PER_MSEC, false, eth, ++ REG_PPE_PPE_FLOW_CFG(0)); ++ if (err) ++ return err; ++ ++ if (airoha_ppe_is_enabled(eth, 1)) ++ err = read_poll_timeout(airoha_fe_rr, val, val, USEC_PER_MSEC, ++ 100 * USEC_PER_MSEC, false, eth, ++ REG_PPE_PPE_FLOW_CFG(1)); ++ ++ return err; ++} ++ + static int airoha_ppe_offload_setup(struct airoha_eth *eth) + { + struct airoha_npu *npu = airoha_ppe_npu_get(eth); +@@ -1348,6 +1371,11 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth) + if (err) + goto error_npu_put; + ++ /* Wait for NPU PPE configuration to complete */ ++ err = airoha_ppe_wait_for_npu_init(eth); ++ if (err) ++ goto error_npu_put; ++ + ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); + if (ppe_num_stats_entries > 0) { + err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma, +-- +2.53.0 + diff --git a/queue-7.0/net-bcmgenet-fix-leaking-free_bds.patch b/queue-7.0/net-bcmgenet-fix-leaking-free_bds.patch new file mode 100644 index 0000000000..2b06bed32f --- /dev/null +++ b/queue-7.0/net-bcmgenet-fix-leaking-free_bds.patch @@ -0,0 +1,49 @@ +From 0fdb84b839a90186948ae4d25cfc1717bb462f6a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:55 -0700 +Subject: net: bcmgenet: fix leaking free_bds + +From: Justin Chen + +[ Upstream commit 3f3168300efb839028328d720ab3962f91d6a0d0 ] + +While reclaiming the tx queue we fast forward the write pointer to +drop any data in flight. These dropped frames are not added back +to the pool of free bds. We also need to tell the netdev that we +are dropping said data. + +Fixes: f1bacae8b655 ("net: bcmgenet: support reclaiming unsent Tx packets") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-3-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 0f6e4baba25b9..e89126a0c20ea 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1985,6 +1985,7 @@ static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, + drop = (ring->prod_index - ring->c_index) & DMA_C_INDEX_MASK; + released += drop; + ring->prod_index = ring->c_index & DMA_C_INDEX_MASK; ++ ring->free_bds += drop; + while (drop--) { + cb_ptr = bcmgenet_put_txcb(priv, ring); + skb = cb_ptr->skb; +@@ -1996,6 +1997,7 @@ static unsigned int bcmgenet_tx_reclaim(struct net_device *dev, + } + if (skb) + dev_consume_skb_any(skb); ++ netdev_tx_reset_queue(netdev_get_tx_queue(dev, ring->index)); + bcmgenet_tdma_ring_writel(priv, ring->index, + ring->prod_index, TDMA_PROD_INDEX); + wr_ptr = ring->write_ptr * WORDS_PER_BD(priv); +-- +2.53.0 + diff --git a/queue-7.0/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch b/queue-7.0/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch new file mode 100644 index 0000000000..d42fd70578 --- /dev/null +++ b/queue-7.0/net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch @@ -0,0 +1,50 @@ +From f1c7b252b956c4778e7ff6aa448c339b79272bd9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:54 -0700 +Subject: net: bcmgenet: fix off-by-one in bcmgenet_put_txcb + +From: Justin Chen + +[ Upstream commit 57f3f53d2c9c5a9e133596e2f7bc1c50688a6d38 ] + +The write_ptr points to the next open tx_cb. We want to return the +tx_cb that gets rewinded, so we must rewind the pointer first then +return the tx_cb that it points to. That way the txcb can be correctly +cleaned up. + +Fixes: 876dbadd53a7 ("net: bcmgenet: Fix unmapping of fragments in bcmgenet_xmit()") +Signed-off-by: Justin Chen +Reviewed-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-2-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index 482a31e7b72bc..0f6e4baba25b9 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1819,15 +1819,15 @@ static struct enet_cb *bcmgenet_put_txcb(struct bcmgenet_priv *priv, + { + struct enet_cb *tx_cb_ptr; + +- tx_cb_ptr = ring->cbs; +- tx_cb_ptr += ring->write_ptr - ring->cb_ptr; +- + /* Rewinding local write pointer */ + if (ring->write_ptr == ring->cb_ptr) + ring->write_ptr = ring->end_ptr; + else + ring->write_ptr--; + ++ tx_cb_ptr = ring->cbs; ++ tx_cb_ptr += ring->write_ptr - ring->cb_ptr; ++ + return tx_cb_ptr; + } + +-- +2.53.0 + diff --git a/queue-7.0/net-bcmgenet-fix-racing-timeout-handler.patch b/queue-7.0/net-bcmgenet-fix-racing-timeout-handler.patch new file mode 100644 index 0000000000..2c9cf21f1c --- /dev/null +++ b/queue-7.0/net-bcmgenet-fix-racing-timeout-handler.patch @@ -0,0 +1,70 @@ +From 89a25480d6a9e67748c8d78a304d46ff63fd9162 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Apr 2026 10:57:56 -0700 +Subject: net: bcmgenet: fix racing timeout handler + +From: Justin Chen + +[ Upstream commit 5393b2b5bee2ac51a0043dc7f4ac3475f053d08d ] + +The bcmgenet_timeout handler tries to take down all tx queues when +a single queue times out. This is over zealous and causes many race +conditions with queues that are still chugging along. Instead lets +only restart the timed out queue. + +Fixes: 13ea657806cf ("net: bcmgenet: improve TX timeout") +Signed-off-by: Justin Chen +Reviewed-by: Florian Fainelli +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260406175756.134567-4-justin.chen@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/broadcom/genet/bcmgenet.c | 22 ++++++++----------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +index e89126a0c20ea..54f71b1e85fc4 100644 +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -3477,27 +3477,23 @@ static void bcmgenet_dump_tx_queue(struct bcmgenet_tx_ring *ring) + static void bcmgenet_timeout(struct net_device *dev, unsigned int txqueue) + { + struct bcmgenet_priv *priv = netdev_priv(dev); +- u32 int1_enable = 0; +- unsigned int q; ++ struct bcmgenet_tx_ring *ring = &priv->tx_rings[txqueue]; ++ struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue); + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- bcmgenet_dump_tx_queue(&priv->tx_rings[q]); +- +- bcmgenet_tx_reclaim_all(dev); ++ bcmgenet_dump_tx_queue(ring); + +- for (q = 0; q <= priv->hw_params->tx_queues; q++) +- int1_enable |= (1 << q); ++ bcmgenet_tx_reclaim(dev, ring, true); + +- /* Re-enable TX interrupts if disabled */ +- bcmgenet_intrl2_1_writel(priv, int1_enable, INTRL2_CPU_MASK_CLEAR); ++ /* Re-enable the TX interrupt for this ring */ ++ bcmgenet_intrl2_1_writel(priv, 1 << txqueue, INTRL2_CPU_MASK_CLEAR); + +- netif_trans_update(dev); ++ txq_trans_cond_update(txq); + +- BCMGENET_STATS64_INC((&priv->tx_rings[txqueue].stats64), errors); ++ BCMGENET_STATS64_INC((&ring->stats64), errors); + +- netif_tx_wake_all_queues(dev); ++ netif_tx_wake_queue(txq); + } + + #define MAX_MDF_FILTER 17 +-- +2.53.0 + diff --git a/queue-7.0/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch b/queue-7.0/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch new file mode 100644 index 0000000000..5c667a5847 --- /dev/null +++ b/queue-7.0/net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch @@ -0,0 +1,66 @@ +From e31037a7149cd7a28968e1cf958d6cb6401f9c31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 08:55:19 +0800 +Subject: net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master + +From: Jiayuan Chen + +[ Upstream commit 1921f91298d1388a0bb9db8f83800c998b649cb3 ] + +syzkaller reported a kernel panic in bond_rr_gen_slave_id() reached via +xdp_master_redirect(). Full decoded trace: + + https://syzkaller.appspot.com/bug?extid=80e046b8da2820b6ba73 + +bond_rr_gen_slave_id() dereferences bond->rr_tx_counter, a per-CPU +counter that bonding only allocates in bond_open() when the mode is +round-robin. If the bond device was never brought up, rr_tx_counter +stays NULL. + +The XDP redirect path can still reach that code on a bond that was +never opened: bpf_master_redirect_enabled_key is a global static key, +so as soon as any bond device has native XDP attached, the +XDP_TX -> xdp_master_redirect() interception is enabled for every +slave system-wide. The path xdp_master_redirect() -> +bond_xdp_get_xmit_slave() -> bond_xdp_xmit_roundrobin_slave_get() -> +bond_rr_gen_slave_id() then runs against a bond that has no +rr_tx_counter and crashes. + +Fix this in the generic xdp_master_redirect() by refusing to call into +the master's ->ndo_xdp_get_xmit_slave() when the master device is not +up. IFF_UP is only set after ->ndo_open() has successfully returned, +so this reliably excludes masters whose XDP state has not been fully +initialized. Drop the frame with XDP_ABORTED so the exception is +visible via trace_xdp_exception() rather than silently falling through. +This is not specific to bonding: any current or future master that +defers XDP state allocation to ->ndo_open() is protected. + +Fixes: 879af96ffd72 ("net, core: Add support for XDP redirection to slave device") +Reported-by: syzbot+80e046b8da2820b6ba73@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/698f84c6.a70a0220.2c38d7.00cc.GAE@google.com/T/ +Suggested-by: Daniel Borkmann +Acked-by: Daniel Borkmann +Signed-off-by: Jiayuan Chen +Link: https://patch.msgid.link/20260411005524.201200-2-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/core/filter.c b/net/core/filter.c +index 53ce06ed4a88e..90ae4f314b6c3 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -4395,6 +4395,8 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) + struct net_device *master, *slave; + + master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); ++ if (unlikely(!(master->flags & IFF_UP))) ++ return XDP_ABORTED; + slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); + if (slave && slave != xdp->rxq->dev) { + /* The target device is different from the receiving device, so +-- +2.53.0 + diff --git a/queue-7.0/net-dropreason-add-skb_drop_reason_recursion_limit.patch b/queue-7.0/net-dropreason-add-skb_drop_reason_recursion_limit.patch new file mode 100644 index 0000000000..2fafaa7678 --- /dev/null +++ b/queue-7.0/net-dropreason-add-skb_drop_reason_recursion_limit.patch @@ -0,0 +1,78 @@ +From 57a33b51920c37e0891181ca42500ee3ac8ad76c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 20:18:23 +0000 +Subject: net: dropreason: add SKB_DROP_REASON_RECURSION_LIMIT + +From: Eric Dumazet + +[ Upstream commit d15d3de94a4766fb43d7fe7a72ed0479fb268131 ] + +ip[6]tunnel_xmit() can drop packets if a too deep recursion level +is detected. + +Add SKB_DROP_REASON_RECURSION_LIMIT drop reason. + +We will use this reason later in __dev_queue_xmit(). + +Signed-off-by: Eric Dumazet +Reviewed-by: Joe Damato +Link: https://patch.msgid.link/20260312201824.203093-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()") +Signed-off-by: Sasha Levin +--- + include/net/dropreason-core.h | 3 +++ + include/net/ip6_tunnel.h | 2 +- + net/ipv4/ip_tunnel_core.c | 2 +- + 3 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h +index a7b7abd66e215..8e498e8431cbb 100644 +--- a/include/net/dropreason-core.h ++++ b/include/net/dropreason-core.h +@@ -130,6 +130,7 @@ + FN(DUALPI2_STEP_DROP) \ + FN(PSP_INPUT) \ + FN(PSP_OUTPUT) \ ++ FN(RECURSION_LIMIT) \ + FNe(MAX) + + /** +@@ -622,6 +623,8 @@ enum skb_drop_reason { + SKB_DROP_REASON_PSP_INPUT, + /** @SKB_DROP_REASON_PSP_OUTPUT: PSP output checks failed */ + SKB_DROP_REASON_PSP_OUTPUT, ++ /** @SKB_DROP_REASON_RECURSION_LIMIT: Dead loop on virtual device. */ ++ SKB_DROP_REASON_RECURSION_LIMIT, + /** + * @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which + * shouldn't be used as a real 'reason' - only for tracing code gen +diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h +index 359b595f1df93..b99805ee2fd14 100644 +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -162,7 +162,7 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb, + dev->name); + DEV_STATS_INC(dev, tx_errors); + } +- kfree_skb(skb); ++ kfree_skb_reason(skb, SKB_DROP_REASON_RECURSION_LIMIT); + return; + } + +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 5683c328990f4..f430d6f0463e7 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -65,7 +65,7 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, + DEV_STATS_INC(dev, tx_errors); + } + ip_rt_put(rt); +- kfree_skb(skb); ++ kfree_skb_reason(skb, SKB_DROP_REASON_RECURSION_LIMIT); + return; + } + +-- +2.53.0 + diff --git a/queue-7.0/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch b/queue-7.0/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch new file mode 100644 index 0000000000..d14f84cb7c --- /dev/null +++ b/queue-7.0/net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch @@ -0,0 +1,44 @@ +From 0f142536ed81a71b70f0f10852f47cccef7a3c57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 21:37:07 +0200 +Subject: net: dsa: realtek: rtl8365mb: fix mode mask calculation + +From: Mieczyslaw Nalewaj + +[ Upstream commit 0c078021d3861966614d5e594ee03587f0c9e74d ] + +The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting +the 4-bit mask (0xF) by only (_extint % 2) bits instead of +(_extint % 2) * 4. This caused the mask to overlap with the adjacent +nibble when configuring odd-numbered external interfaces, selecting +the wrong bits entirely. + +Align the shift calculation with the existing ...MODE_OFFSET macro. + +Fixes: 4af2950c50c8 ("net: dsa: realtek-smi: add rtl8365mb subdriver for RTL8365MB-VC") +Signed-off-by: Abdulkader Alrezej +Signed-off-by: Mieczyslaw Nalewaj +Reviewed-by: Luiz Angelo Daros de Luca +Link: https://patch.msgid.link/400a6387-a444-4576-af6d-26be5410bce3@yahoo.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/realtek/rtl8365mb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c +index 31fa94dac627d..c35cef01ec265 100644 +--- a/drivers/net/dsa/realtek/rtl8365mb.c ++++ b/drivers/net/dsa/realtek/rtl8365mb.c +@@ -216,7 +216,7 @@ + (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ + 0x0) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(_extint) \ +- (0xF << (((_extint) % 2))) ++ (0xF << (((_extint) % 2) * 4)) + #define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \ + (((_extint) % 2) * 4) + +-- +2.53.0 + diff --git a/queue-7.0/net-dsa-remove-redundant-netdev_lock_ops-from-condui.patch b/queue-7.0/net-dsa-remove-redundant-netdev_lock_ops-from-condui.patch new file mode 100644 index 0000000000..e30834817e --- /dev/null +++ b/queue-7.0/net-dsa-remove-redundant-netdev_lock_ops-from-condui.patch @@ -0,0 +1,117 @@ +From 2b953f144a0454535bcbb197c7f3bc1da08f956a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 16:10:35 -0700 +Subject: net: dsa: remove redundant netdev_lock_ops() from conduit ethtool ops + +From: Stanislav Fomichev + +[ Upstream commit 0f99e0c3e19badaf3fdced0d3feba623e59eed41 ] + +DSA replaces the conduit (master) device's ethtool_ops with its own +wrappers that aggregate stats from both the conduit and DSA switch +ports. Taking the lock again inside the DSA wrappers causes a deadlock. + +Stumbled upon this when booting qemu with fbnic and CONFIG_NET_DSA_LOOP=y +(which looks like some kind of testing device that auto-populates the ports +of eth0). `ethtool -i` is enough to deadlock. This means we have basically zero +coverage for DSA stuff with real ops locked devs. + +Remove the redundant netdev_lock_ops()/netdev_unlock_ops() calls from +the DSA conduit ethtool wrappers. + +Fixes: 2bcf4772e45a ("net: ethtool: try to protect all callback with netdev instance lock") +Signed-off-by: Stanislav Fomichev +Reviewed-by: Maxime Chevallier +Link: https://patch.msgid.link/20260414231035.1917035-1-sdf@fomichev.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/dsa/conduit.c | 16 +--------------- + 1 file changed, 1 insertion(+), 15 deletions(-) + +diff --git a/net/dsa/conduit.c b/net/dsa/conduit.c +index a1b044467bd6f..8398d72d7e4d3 100644 +--- a/net/dsa/conduit.c ++++ b/net/dsa/conduit.c +@@ -27,9 +27,7 @@ static int dsa_conduit_get_regs_len(struct net_device *dev) + int len; + + if (ops && ops->get_regs_len) { +- netdev_lock_ops(dev); + len = ops->get_regs_len(dev); +- netdev_unlock_ops(dev); + if (len < 0) + return len; + ret += len; +@@ -60,15 +58,11 @@ static void dsa_conduit_get_regs(struct net_device *dev, + int len; + + if (ops && ops->get_regs_len && ops->get_regs) { +- netdev_lock_ops(dev); + len = ops->get_regs_len(dev); +- if (len < 0) { +- netdev_unlock_ops(dev); ++ if (len < 0) + return; +- } + regs->len = len; + ops->get_regs(dev, regs, data); +- netdev_unlock_ops(dev); + data += regs->len; + } + +@@ -115,10 +109,8 @@ static void dsa_conduit_get_ethtool_stats(struct net_device *dev, + int count, mcount = 0; + + if (ops && ops->get_sset_count && ops->get_ethtool_stats) { +- netdev_lock_ops(dev); + mcount = ops->get_sset_count(dev, ETH_SS_STATS); + ops->get_ethtool_stats(dev, stats, data); +- netdev_unlock_ops(dev); + } + + list_for_each_entry(dp, &dst->ports, list) { +@@ -149,10 +141,8 @@ static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev, + if (count >= 0) + phy_ethtool_get_stats(dev->phydev, stats, data); + } else if (ops && ops->get_sset_count && ops->get_ethtool_phy_stats) { +- netdev_lock_ops(dev); + count = ops->get_sset_count(dev, ETH_SS_PHY_STATS); + ops->get_ethtool_phy_stats(dev, stats, data); +- netdev_unlock_ops(dev); + } + + if (count < 0) +@@ -176,13 +166,11 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset) + struct dsa_switch_tree *dst = cpu_dp->dst; + int count = 0; + +- netdev_lock_ops(dev); + if (sset == ETH_SS_PHY_STATS && dev->phydev && + (!ops || !ops->get_ethtool_phy_stats)) + count = phy_ethtool_get_sset_count(dev->phydev); + else if (ops && ops->get_sset_count) + count = ops->get_sset_count(dev, sset); +- netdev_unlock_ops(dev); + + if (count < 0) + count = 0; +@@ -239,7 +227,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, + struct dsa_switch_tree *dst = cpu_dp->dst; + int count, mcount = 0; + +- netdev_lock_ops(dev); + if (stringset == ETH_SS_PHY_STATS && dev->phydev && + !ops->get_ethtool_phy_stats) { + mcount = phy_ethtool_get_sset_count(dev->phydev); +@@ -253,7 +240,6 @@ static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset, + mcount = 0; + ops->get_strings(dev, stringset, data); + } +- netdev_unlock_ops(dev); + + list_for_each_entry(dp, &dst->ports, list) { + if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp)) +-- +2.53.0 + diff --git a/queue-7.0/net-enetc-correct-the-command-bd-ring-consumer-index.patch b/queue-7.0/net-enetc-correct-the-command-bd-ring-consumer-index.patch new file mode 100644 index 0000000000..18677b18cb --- /dev/null +++ b/queue-7.0/net-enetc-correct-the-command-bd-ring-consumer-index.patch @@ -0,0 +1,92 @@ +From bdc59d6625dbdf04ead456945e4cda43d5bf6c4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:08:32 +0800 +Subject: net: enetc: correct the command BD ring consumer index + +From: Wei Fang + +[ Upstream commit 759a32900b6f3db3d0f34a3b61123742723b50b4 ] + +The command BD ring cousumer index register has the consumer index as +the lower 10 bits, and the bit 31 is SBE, which indicates whether a +system bus error occurred during execution of the CBD command. So if a +system bus error occurs, reading the register will get the SBE bit set. + +However, the current implementation directly uses the register value as +the consumer index without masking it. Therefore, if a system bus error +occurs, an incorrect consumer index will be obtained, causing errors in +the processing of the command BD ring. Thus, we need to mask out the +other bits to obtain the correct consumer index. + +In addition, this patch adds a check for the SBE bit after the polling +loop and returns an error if the bit is set. + +Fixes: 4701073c3deb ("net: enetc: add initial netc-lib driver to support NTMP") +Signed-off-by: Wei Fang +Link: https://patch.msgid.link/20260415060833.2303846-2-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/enetc/ntmp.c | 13 ++++++++++--- + drivers/net/ethernet/freescale/enetc/ntmp_private.h | 2 ++ + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c +index 0c1d343253bfb..b188eb2d40c0d 100644 +--- a/drivers/net/ethernet/freescale/enetc/ntmp.c ++++ b/drivers/net/ethernet/freescale/enetc/ntmp.c +@@ -55,7 +55,7 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev, + spin_lock_init(&cbdr->ring_lock); + + cbdr->next_to_use = netc_read(cbdr->regs.pir); +- cbdr->next_to_clean = netc_read(cbdr->regs.cir); ++ cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX; + + /* Step 1: Configure the base address of the Control BD Ring */ + netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align)); +@@ -98,7 +98,7 @@ static void ntmp_clean_cbdr(struct netc_cbdr *cbdr) + int i; + + i = cbdr->next_to_clean; +- while (netc_read(cbdr->regs.cir) != i) { ++ while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) { + cbd = ntmp_get_cbd(cbdr, i); + memset(cbd, 0, sizeof(*cbd)); + i = (i + 1) % cbdr->bd_num; +@@ -135,12 +135,19 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd) + cbdr->next_to_use = i; + netc_write(cbdr->regs.pir, i); + +- err = read_poll_timeout_atomic(netc_read, val, val == i, ++ err = read_poll_timeout_atomic(netc_read, val, ++ (val & NETC_CBDRCIR_INDEX) == i, + NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT, + true, cbdr->regs.cir); + if (unlikely(err)) + goto cbdr_unlock; + ++ if (unlikely(val & NETC_CBDRCIR_SBE)) { ++ dev_err(user->dev, "Command BD system bus error\n"); ++ err = -EIO; ++ goto cbdr_unlock; ++ } ++ + dma_rmb(); + /* Get the writeback command BD, because the caller may need + * to check some other fields of the response header. +diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h +index 34394e40fddd4..3459cc45b6103 100644 +--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h ++++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h +@@ -12,6 +12,8 @@ + + #define NTMP_EID_REQ_LEN 8 + #define NETC_CBDR_BD_NUM 256 ++#define NETC_CBDRCIR_INDEX GENMASK(9, 0) ++#define NETC_CBDRCIR_SBE BIT(31) + + union netc_cbd { + struct { +-- +2.53.0 + diff --git a/queue-7.0/net-enetc-fix-ntmp-dma-use-after-free-issue.patch b/queue-7.0/net-enetc-fix-ntmp-dma-use-after-free-issue.patch new file mode 100644 index 0000000000..1b2c718dbd --- /dev/null +++ b/queue-7.0/net-enetc-fix-ntmp-dma-use-after-free-issue.patch @@ -0,0 +1,577 @@ +From 3d6e85d0f540532faa8daa90b74ccee984318649 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 14:08:33 +0800 +Subject: net: enetc: fix NTMP DMA use-after-free issue + +From: Wei Fang + +[ Upstream commit 3cade698881eb238f88cbbfec82acc2110440a3f ] + +The AI-generated review reported a potential DMA use-after-free issue +[1]. If netc_xmit_ntmp_cmd() times out and returns an error, the pending +command is not explicitly aborted, while ntmp_free_data_mem() +unconditionally frees the DMA buffer. If the buffer has already been +reallocated elsewhere, this may lead to silent memory corruption. Because +the hardware eventually processes the pending command and perform a DMA +write of the response to the physical address of the freed buffer. + +To resolve this issue, this patch does the following modifications: + +1. Convert cbdr->ring_lock from a spinlock to a mutex + +The lock was originally a spinlock in case NTMP operations might be +invoked from atomic context. After downstream support for all NTMP +tables, no such usage has materialized. A mutex lock is now required +because the driver now needs to reclaim used BDs and release associated +DMA memory within the lock's context, while dma_free_coherent() might +sleep. + +2. Introduce software command BD (struct netc_swcbd) + +The hardware write-back overwrites the addr and len fields of the BD, +so the driver cannot rely on the hardware BD to free the associated DMA +memory. The driver now maintains a software shadow BD storing the DMA +buffer pointer, DMA address, and size. And netc_xmit_ntmp_cmd() only +reclaims older BDs when the number of used BDs reaches +NETC_CBDR_CLEAN_WORK (16). The software BD enables correct DMA memory +release. With this, struct ntmp_dma_buf and ntmp_free_data_mem() are no +longer needed and are removed. + +3. Require callers to hold ring_lock across netc_xmit_ntmp_cmd() + +netc_xmit_ntmp_cmd() releases the ring_lock before the caller finishes +consuming the response. At this point, if a concurrent thread submits +a new command, it may trigger ntmp_clean_cbdr() and free the DMA buffer +while it is still in use. Move ring_lock ownership to the caller to +ensure the response buffer cannot be reclaimed prematurely. So the +helpers ntmp_select_and_lock_cbdr() and ntmp_unlock_cbdr() are added. + +These changes eliminate the DMA use-after-free condition and ensure safe +and consistent BD reclamation and DMA buffer lifecycle management. + +Fixes: 4701073c3deb ("net: enetc: add initial netc-lib driver to support NTMP") +Link: https://lore.kernel.org/netdev/20260403011729.1795413-1-kuba@kernel.org/ # [1] +Signed-off-by: Wei Fang +Link: https://patch.msgid.link/20260415060833.2303846-3-wei.fang@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/enetc/ntmp.c | 214 ++++++++++-------- + .../ethernet/freescale/enetc/ntmp_private.h | 8 +- + include/linux/fsl/ntmp.h | 9 +- + 3 files changed, 134 insertions(+), 97 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c +index b188eb2d40c0d..70bbc5d2d5d42 100644 +--- a/drivers/net/ethernet/freescale/enetc/ntmp.c ++++ b/drivers/net/ethernet/freescale/enetc/ntmp.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #include "ntmp_private.h" + +@@ -42,6 +43,12 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev, + if (!cbdr->addr_base) + return -ENOMEM; + ++ cbdr->swcbd = vcalloc(cbd_num, sizeof(struct netc_swcbd)); ++ if (!cbdr->swcbd) { ++ dma_free_coherent(dev, size, cbdr->addr_base, cbdr->dma_base); ++ return -ENOMEM; ++ } ++ + cbdr->dma_size = size; + cbdr->bd_num = cbd_num; + cbdr->regs = *regs; +@@ -52,7 +59,7 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev, + cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base, + NTMP_BASE_ADDR_ALIGN); + +- spin_lock_init(&cbdr->ring_lock); ++ mutex_init(&cbdr->ring_lock); + + cbdr->next_to_use = netc_read(cbdr->regs.pir); + cbdr->next_to_clean = netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX; +@@ -71,10 +78,24 @@ int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev, + } + EXPORT_SYMBOL_GPL(ntmp_init_cbdr); + ++static void ntmp_free_data_mem(struct device *dev, struct netc_swcbd *swcbd) ++{ ++ if (unlikely(!swcbd->buf)) ++ return; ++ ++ dma_free_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN, ++ swcbd->buf, swcbd->dma); ++} ++ + void ntmp_free_cbdr(struct netc_cbdr *cbdr) + { + /* Disable the Control BD Ring */ + netc_write(cbdr->regs.mr, 0); ++ ++ for (int i = 0; i < cbdr->bd_num; i++) ++ ntmp_free_data_mem(cbdr->dev, &cbdr->swcbd[i]); ++ ++ vfree(cbdr->swcbd); + dma_free_coherent(cbdr->dev, cbdr->dma_size, cbdr->addr_base, + cbdr->dma_base); + memset(cbdr, 0, sizeof(*cbdr)); +@@ -94,40 +115,59 @@ static union netc_cbd *ntmp_get_cbd(struct netc_cbdr *cbdr, int index) + + static void ntmp_clean_cbdr(struct netc_cbdr *cbdr) + { +- union netc_cbd *cbd; +- int i; ++ int i = cbdr->next_to_clean; + +- i = cbdr->next_to_clean; + while ((netc_read(cbdr->regs.cir) & NETC_CBDRCIR_INDEX) != i) { +- cbd = ntmp_get_cbd(cbdr, i); ++ union netc_cbd *cbd = ntmp_get_cbd(cbdr, i); ++ struct netc_swcbd *swcbd = &cbdr->swcbd[i]; ++ ++ ntmp_free_data_mem(cbdr->dev, swcbd); ++ memset(swcbd, 0, sizeof(*swcbd)); + memset(cbd, 0, sizeof(*cbd)); + i = (i + 1) % cbdr->bd_num; + } + ++ dma_wmb(); + cbdr->next_to_clean = i; + } + +-static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd) ++static void ntmp_select_and_lock_cbdr(struct ntmp_user *user, ++ struct netc_cbdr **cbdr) ++{ ++ /* Currently only ENETC is supported, and it has only one command ++ * BD ring. ++ */ ++ *cbdr = &user->ring[0]; ++ ++ mutex_lock(&(*cbdr)->ring_lock); ++} ++ ++static void ntmp_unlock_cbdr(struct netc_cbdr *cbdr) ++{ ++ mutex_unlock(&cbdr->ring_lock); ++} ++ ++static int netc_xmit_ntmp_cmd(struct netc_cbdr *cbdr, union netc_cbd *cbd, ++ struct netc_swcbd *swcbd) + { + union netc_cbd *cur_cbd; +- struct netc_cbdr *cbdr; +- int i, err; ++ int i, err, used_bds; + u16 status; + u32 val; + +- /* Currently only i.MX95 ENETC is supported, and it only has one +- * command BD ring +- */ +- cbdr = &user->ring[0]; +- +- spin_lock_bh(&cbdr->ring_lock); +- +- if (unlikely(!ntmp_get_free_cbd_num(cbdr))) ++ used_bds = cbdr->bd_num - ntmp_get_free_cbd_num(cbdr); ++ if (unlikely(used_bds >= NETC_CBDR_CLEAN_WORK)) { + ntmp_clean_cbdr(cbdr); ++ if (unlikely(!ntmp_get_free_cbd_num(cbdr))) { ++ ntmp_free_data_mem(cbdr->dev, swcbd); ++ return -EBUSY; ++ } ++ } + + i = cbdr->next_to_use; + cur_cbd = ntmp_get_cbd(cbdr, i); + *cur_cbd = *cbd; ++ cbdr->swcbd[i] = *swcbd; + dma_wmb(); + + /* Update producer index of both software and hardware */ +@@ -135,17 +175,16 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd) + cbdr->next_to_use = i; + netc_write(cbdr->regs.pir, i); + +- err = read_poll_timeout_atomic(netc_read, val, +- (val & NETC_CBDRCIR_INDEX) == i, +- NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT, +- true, cbdr->regs.cir); ++ err = read_poll_timeout(netc_read, val, ++ (val & NETC_CBDRCIR_INDEX) == i, ++ NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT, ++ true, cbdr->regs.cir); + if (unlikely(err)) +- goto cbdr_unlock; ++ return err; + + if (unlikely(val & NETC_CBDRCIR_SBE)) { +- dev_err(user->dev, "Command BD system bus error\n"); +- err = -EIO; +- goto cbdr_unlock; ++ dev_err(cbdr->dev, "Command BD system bus error\n"); ++ return -EIO; + } + + dma_rmb(); +@@ -157,40 +196,29 @@ static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd) + /* Check the writeback error status */ + status = le16_to_cpu(cbd->resp_hdr.error_rr) & NTMP_RESP_ERROR; + if (unlikely(status)) { +- err = -EIO; +- dev_err(user->dev, "Command BD error: 0x%04x\n", status); ++ dev_err(cbdr->dev, "Command BD error: 0x%04x\n", status); ++ return -EIO; + } + +- ntmp_clean_cbdr(cbdr); +- dma_wmb(); +- +-cbdr_unlock: +- spin_unlock_bh(&cbdr->ring_lock); +- +- return err; ++ return 0; + } + +-static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align) ++static int ntmp_alloc_data_mem(struct device *dev, struct netc_swcbd *swcbd, ++ void **buf_align) + { + void *buf; + +- buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN, +- &data->dma, GFP_KERNEL); ++ buf = dma_alloc_coherent(dev, swcbd->size + NTMP_DATA_ADDR_ALIGN, ++ &swcbd->dma, GFP_KERNEL); + if (!buf) + return -ENOMEM; + +- data->buf = buf; ++ swcbd->buf = buf; + *buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN); + + return 0; + } + +-static void ntmp_free_data_mem(struct ntmp_dma_buf *data) +-{ +- dma_free_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN, +- data->buf, data->dma); +-} +- + static void ntmp_fill_request_hdr(union netc_cbd *cbd, dma_addr_t dma, + int len, int table_id, int cmd, + int access_method) +@@ -241,37 +269,39 @@ static int ntmp_delete_entry_by_id(struct ntmp_user *user, int tbl_id, + u8 tbl_ver, u32 entry_id, u32 req_len, + u32 resp_len) + { +- struct ntmp_dma_buf data = { +- .dev = user->dev, ++ struct netc_swcbd swcbd = { + .size = max(req_len, resp_len), + }; + struct ntmp_req_by_eid *req; ++ struct netc_cbdr *cbdr; + union netc_cbd cbd; + int err; + +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + + ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id); +- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(req_len, resp_len), ++ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(req_len, resp_len), + tbl_id, NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID); + +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd); + if (err) + dev_err(user->dev, + "Failed to delete entry 0x%x of %s, err: %pe", + entry_id, ntmp_table_name(tbl_id), ERR_PTR(err)); +- +- ntmp_free_data_mem(&data); ++ ntmp_unlock_cbdr(cbdr); + + return err; + } + +-static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id, +- u32 len, struct ntmp_req_by_eid *req, +- dma_addr_t dma, bool compare_eid) ++static int ntmp_query_entry_by_id(struct netc_cbdr *cbdr, int tbl_id, ++ struct ntmp_req_by_eid *req, ++ struct netc_swcbd *swcbd, ++ bool compare_eid) + { ++ u32 len = NTMP_LEN(sizeof(*req), swcbd->size); + struct ntmp_cmn_resp_query *resp; + int cmd = NTMP_CMD_QUERY; + union netc_cbd cbd; +@@ -283,10 +313,11 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id, + cmd = NTMP_CMD_QU; + + /* Request header */ +- ntmp_fill_request_hdr(&cbd, dma, len, tbl_id, cmd, NTMP_AM_ENTRY_ID); +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ntmp_fill_request_hdr(&cbd, swcbd->dma, len, tbl_id, cmd, ++ NTMP_AM_ENTRY_ID); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, swcbd); + if (err) { +- dev_err(user->dev, ++ dev_err(cbdr->dev, + "Failed to query entry 0x%x of %s, err: %pe\n", + entry_id, ntmp_table_name(tbl_id), ERR_PTR(err)); + return err; +@@ -300,7 +331,7 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id, + + resp = (struct ntmp_cmn_resp_query *)req; + if (unlikely(le32_to_cpu(resp->entry_id) != entry_id)) { +- dev_err(user->dev, ++ dev_err(cbdr->dev, + "%s: query EID 0x%x doesn't match response EID 0x%x\n", + ntmp_table_name(tbl_id), entry_id, le32_to_cpu(resp->entry_id)); + return -EIO; +@@ -312,15 +343,15 @@ static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id, + int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id, + struct maft_entry_data *maft) + { +- struct ntmp_dma_buf data = { +- .dev = user->dev, ++ struct netc_swcbd swcbd = { + .size = sizeof(struct maft_req_add), + }; + struct maft_req_add *req; ++ struct netc_cbdr *cbdr; + union netc_cbd cbd; + int err; + +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + +@@ -329,14 +360,15 @@ int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id, + req->keye = maft->keye; + req->cfge = maft->cfge; + +- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0), ++ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0), + NTMP_MAFT_ID, NTMP_CMD_ADD, NTMP_AM_ENTRY_ID); +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd); + if (err) + dev_err(user->dev, "Failed to add MAFT entry 0x%x, err: %pe\n", + entry_id, ERR_PTR(err)); +- +- ntmp_free_data_mem(&data); ++ ntmp_unlock_cbdr(cbdr); + + return err; + } +@@ -345,31 +377,31 @@ EXPORT_SYMBOL_GPL(ntmp_maft_add_entry); + int ntmp_maft_query_entry(struct ntmp_user *user, u32 entry_id, + struct maft_entry_data *maft) + { +- struct ntmp_dma_buf data = { +- .dev = user->dev, ++ struct netc_swcbd swcbd = { + .size = sizeof(struct maft_resp_query), + }; + struct maft_resp_query *resp; + struct ntmp_req_by_eid *req; ++ struct netc_cbdr *cbdr; + int err; + +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + + ntmp_fill_crd_eid(req, user->tbl.maft_ver, 0, 0, entry_id); +- err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID, +- NTMP_LEN(sizeof(*req), data.size), +- req, data.dma, true); ++ ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = ntmp_query_entry_by_id(cbdr, NTMP_MAFT_ID, req, &swcbd, true); + if (err) +- goto end; ++ goto unlock_cbdr; + + resp = (struct maft_resp_query *)req; + maft->keye = resp->keye; + maft->cfge = resp->cfge; + +-end: +- ntmp_free_data_mem(&data); ++unlock_cbdr: ++ ntmp_unlock_cbdr(cbdr); + + return err; + } +@@ -385,8 +417,9 @@ EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry); + int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table, + int count) + { +- struct ntmp_dma_buf data = {.dev = user->dev}; + struct rsst_req_update *req; ++ struct netc_swcbd swcbd; ++ struct netc_cbdr *cbdr; + union netc_cbd cbd; + int err, i; + +@@ -394,8 +427,8 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table, + /* HW only takes in a full 64 entry table */ + return -EINVAL; + +- data.size = struct_size(req, groups, count); +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ swcbd.size = struct_size(req, groups, count); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + +@@ -405,15 +438,15 @@ int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table, + for (i = 0; i < count; i++) + req->groups[i] = (u8)(table[i]); + +- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0), ++ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(swcbd.size, 0), + NTMP_RSST_ID, NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID); + +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd); + if (err) + dev_err(user->dev, "Failed to update RSST entry, err: %pe\n", + ERR_PTR(err)); +- +- ntmp_free_data_mem(&data); ++ ntmp_unlock_cbdr(cbdr); + + return err; + } +@@ -421,8 +454,9 @@ EXPORT_SYMBOL_GPL(ntmp_rsst_update_entry); + + int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count) + { +- struct ntmp_dma_buf data = {.dev = user->dev}; + struct ntmp_req_by_eid *req; ++ struct netc_swcbd swcbd; ++ struct netc_cbdr *cbdr; + union netc_cbd cbd; + int err, i; + u8 *group; +@@ -431,21 +465,23 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count) + /* HW only takes in a full 64 entry table */ + return -EINVAL; + +- data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) + +- RSST_CFGE_DATA_SIZE(count); +- err = ntmp_alloc_data_mem(&data, (void **)&req); ++ swcbd.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) + ++ RSST_CFGE_DATA_SIZE(count); ++ err = ntmp_alloc_data_mem(user->dev, &swcbd, (void **)&req); + if (err) + return err; + + /* Set the request data buffer */ + ntmp_fill_crd_eid(req, user->tbl.rsst_ver, 0, 0, 0); +- ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(sizeof(*req), data.size), ++ ntmp_fill_request_hdr(&cbd, swcbd.dma, NTMP_LEN(sizeof(*req), swcbd.size), + NTMP_RSST_ID, NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID); +- err = netc_xmit_ntmp_cmd(user, &cbd); ++ ++ ntmp_select_and_lock_cbdr(user, &cbdr); ++ err = netc_xmit_ntmp_cmd(cbdr, &cbd, &swcbd); + if (err) { + dev_err(user->dev, "Failed to query RSST entry, err: %pe\n", + ERR_PTR(err)); +- goto end; ++ goto unlock_cbdr; + } + + group = (u8 *)req; +@@ -453,8 +489,8 @@ int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count) + for (i = 0; i < count; i++) + table[i] = group[i]; + +-end: +- ntmp_free_data_mem(&data); ++unlock_cbdr: ++ ntmp_unlock_cbdr(cbdr); + + return err; + } +diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h +index 3459cc45b6103..f8dff3ba2c28a 100644 +--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h ++++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h +@@ -14,6 +14,7 @@ + #define NETC_CBDR_BD_NUM 256 + #define NETC_CBDRCIR_INDEX GENMASK(9, 0) + #define NETC_CBDRCIR_SBE BIT(31) ++#define NETC_CBDR_CLEAN_WORK 16 + + union netc_cbd { + struct { +@@ -56,13 +57,6 @@ union netc_cbd { + } resp_hdr; /* NTMP Response Message Header Format */ + }; + +-struct ntmp_dma_buf { +- struct device *dev; +- size_t size; +- void *buf; +- dma_addr_t dma; +-}; +- + struct ntmp_cmn_req_data { + __le16 update_act; + u8 dbg_opt; +diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h +index 916dc4fe7de3b..83a449b4d6ec4 100644 +--- a/include/linux/fsl/ntmp.h ++++ b/include/linux/fsl/ntmp.h +@@ -31,6 +31,12 @@ struct netc_tbl_vers { + u8 rsst_ver; + }; + ++struct netc_swcbd { ++ void *buf; ++ dma_addr_t dma; ++ size_t size; ++}; ++ + struct netc_cbdr { + struct device *dev; + struct netc_cbdr_regs regs; +@@ -44,9 +50,10 @@ struct netc_cbdr { + void *addr_base_align; + dma_addr_t dma_base; + dma_addr_t dma_base_align; ++ struct netc_swcbd *swcbd; + + /* Serialize the order of command BD ring */ +- spinlock_t ring_lock; ++ struct mutex ring_lock; + }; + + struct ntmp_user { +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-mtk_eth_soc-initialize-ppe-per-tag-laye.patch b/queue-7.0/net-ethernet-mtk_eth_soc-initialize-ppe-per-tag-laye.patch new file mode 100644 index 0000000000..13a935d13e --- /dev/null +++ b/queue-7.0/net-ethernet-mtk_eth_soc-initialize-ppe-per-tag-laye.patch @@ -0,0 +1,146 @@ +From db81370705c9ca7f5c6704ad4d2ad3460fb4ac8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 03:57:52 +0100 +Subject: net: ethernet: mtk_eth_soc: initialize PPE per-tag-layer MTU + registers + +From: Daniel Golle + +[ Upstream commit 2dddb34dd0d07b01fa770eca89480a4da4f13153 ] + +The PPE enforces output frame size limits via per-tag-layer VLAN_MTU +registers that the driver never initializes. The hardware defaults do +not account for PPPoE overhead, causing the PPE to punt encapsulated +frames back to the CPU instead of forwarding them. + +Initialize the registers at PPE start and on MTU changes using the +maximum GMAC MTU. This is a conservative approximation -- the actual +per-PPE requirement depends on egress path, but using the global +maximum ensures the limits are never too small. + +Fixes: ba37b7caf1ed2 ("net: ethernet: mtk_eth_soc: add support for initializing the PPE") +Signed-off-by: Daniel Golle +Link: https://patch.msgid.link/ec995ab8ce8be423267a1cc093147a74d2eb9d82.1775789829.git.daniel@makrotopia.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 ++++++++++++++- + drivers/net/ethernet/mediatek/mtk_ppe.c | 30 +++++++++++++++++++++ + drivers/net/ethernet/mediatek/mtk_ppe.h | 1 + + 3 files changed, 52 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index ddc321a02fdae..796f79088f366 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3566,12 +3566,23 @@ static int mtk_device_event(struct notifier_block *n, unsigned long event, void + return NOTIFY_DONE; + } + ++static int mtk_max_gmac_mtu(struct mtk_eth *eth) ++{ ++ int i, max_mtu = ETH_DATA_LEN; ++ ++ for (i = 0; i < ARRAY_SIZE(eth->netdev); i++) ++ if (eth->netdev[i] && eth->netdev[i]->mtu > max_mtu) ++ max_mtu = eth->netdev[i]->mtu; ++ ++ return max_mtu; ++} ++ + static int mtk_open(struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_mac *target_mac; +- int i, err, ppe_num; ++ int i, err, ppe_num, mtu; + + ppe_num = eth->soc->ppe_num; + +@@ -3618,6 +3629,10 @@ static int mtk_open(struct net_device *dev) + mtk_gdm_config(eth, target_mac->id, gdm_config); + } + ++ mtu = mtk_max_gmac_mtu(eth); ++ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) ++ mtk_ppe_update_mtu(eth->ppe[i], mtu); ++ + napi_enable(ð->tx_napi); + napi_enable(ð->rx_napi); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); +@@ -4311,6 +4326,7 @@ static int mtk_change_mtu(struct net_device *dev, int new_mtu) + int length = new_mtu + MTK_RX_ETH_HLEN; + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; ++ int max_mtu, i; + + if (rcu_access_pointer(eth->prog) && + length > MTK_PP_MAX_BUF_SIZE) { +@@ -4321,6 +4337,10 @@ static int mtk_change_mtu(struct net_device *dev, int new_mtu) + mtk_set_mcr_max_rx(mac, length); + WRITE_ONCE(dev->mtu, new_mtu); + ++ max_mtu = mtk_max_gmac_mtu(eth); ++ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) ++ mtk_ppe_update_mtu(eth->ppe[i], max_mtu); ++ + return 0; + } + +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c +index 75f7728fc7962..18279e2a7022e 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -973,6 +973,36 @@ static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe) + } + } + ++void mtk_ppe_update_mtu(struct mtk_ppe *ppe, int mtu) ++{ ++ int base; ++ u32 val; ++ ++ if (!ppe) ++ return; ++ ++ /* The PPE checks output frame size against per-tag-layer MTU limits, ++ * treating PPPoE and DSA tags just like 802.1Q VLAN tags. The Linux ++ * device MTU already accounts for PPPoE (PPPOE_SES_HLEN) and DSA tag ++ * overhead, but 802.1Q VLAN tags are handled transparently without ++ * being reflected by the lower device MTU being increased by 4. ++ * Use the maximum MTU across all GMAC interfaces so that PPE output ++ * frame limits are sufficiently high regardless of which port a flow ++ * egresses through. ++ */ ++ base = ETH_HLEN + mtu; ++ ++ val = FIELD_PREP(MTK_PPE_VLAN_MTU0_NONE, base) | ++ FIELD_PREP(MTK_PPE_VLAN_MTU0_1TAG, base + VLAN_HLEN); ++ ppe_w32(ppe, MTK_PPE_VLAN_MTU0, val); ++ ++ val = FIELD_PREP(MTK_PPE_VLAN_MTU1_2TAG, ++ base + 2 * VLAN_HLEN) | ++ FIELD_PREP(MTK_PPE_VLAN_MTU1_3TAG, ++ base + 3 * VLAN_HLEN); ++ ppe_w32(ppe, MTK_PPE_VLAN_MTU1, val); ++} ++ + void mtk_ppe_start(struct mtk_ppe *ppe) + { + u32 val; +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h +index 223f709e2704f..ba85e39a155bf 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -346,6 +346,7 @@ struct mtk_ppe { + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index); + + void mtk_ppe_deinit(struct mtk_eth *eth); ++void mtk_ppe_update_mtu(struct mtk_ppe *ppe, int mtu); + void mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-ti-cpsw-fix-linking-built-in-code-to-mo.patch b/queue-7.0/net-ethernet-ti-cpsw-fix-linking-built-in-code-to-mo.patch new file mode 100644 index 0000000000..639ebcedb4 --- /dev/null +++ b/queue-7.0/net-ethernet-ti-cpsw-fix-linking-built-in-code-to-mo.patch @@ -0,0 +1,1037 @@ +From 21c515a0ca95c487f74b0b8a01f7ebd53e936960 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:46:54 +0200 +Subject: net: ethernet: ti-cpsw: fix linking built-in code to modules + +From: Arnd Bergmann + +[ Upstream commit df75bd552a8790e83d4aeb5f112050cf3dc687bf ] + +There are six variants of the cpsw driver, sharing various parts of +the code: davinci-emac, cpsw, cpsw-switchdev, netcp, netcp_ethss and +am65-cpsw-nuss. + +I noticed that this means some files can be linked into more than +one loadable module, or even part of vmlinux but also linked into +a loadable module, both of which mess up assumptions of the build +system, and causes warnings: + +scripts/Makefile.build:279: cpsw_ale.o is added to multiple modules: ti-am65-cpsw-nuss ti_cpsw ti_cpsw_new +scripts/Makefile.build:279: cpsw_priv.o is added to multiple modules: ti_cpsw ti_cpsw_new +scripts/Makefile.build:279: cpsw_sl.o is added to multiple modules: ti-am65-cpsw-nuss ti_cpsw ti_cpsw_new +scripts/Makefile.build:279: cpsw_ethtool.o is added to multiple modules: ti_cpsw ti_cpsw_new +scripts/Makefile.build:279: davinci_cpdma.o is added to multiple modules: ti_cpsw ti_cpsw_new ti_davinci_emac + +Change this back to having separate modules for each portion that +can be linked standalone, exporting symbols as needed: + + - ti-cpsw-common.ko now contains both cpsw-common.o and + davinci_cpdma.o as they are always used together + + - ti-cpsw-priv.ko contains cpsw_priv.o, cpsw_sl.o and cpsw_ethtool.o, + which are the core of the cpsw and cpsw-new drivers. + + - ti-cpsw-sl.ko contains the cpsw-sl.o object and is used on + ti-am65-cpsw-nuss.ko in addition to the two other cpsw variants. + + - ti-cpsw-ale.o is the one standalone module that is used by all + except davinci_emac. + +Each of these will be built-in if any of its users are built-in, otherwise +it's a loadable module if there is at least one module using it. I did +not bring back the separate Kconfig symbols for this, but just handle +it using Makefile logic. + +Note: ideally this is something that Kbuild complains about, but usually +we just notice when something using THIS_MODULE misbehaves in a way that +a user notices. + +Fixes: 99f6297182729 ("net: ethernet: ti: cpsw: drop TI_DAVINCI_CPDMA config option") +Link: https://lore.kernel.org/lkml/20240417084400.3034104-1-arnd@kernel.org/ +Signed-off-by: Arnd Bergmann +Link: https://patch.msgid.link/20260402184726.3746487-2-arnd@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/Makefile | 30 ++++++++++---------- + drivers/net/ethernet/ti/cpsw_ale.c | 25 +++++++++++++++++ + drivers/net/ethernet/ti/cpsw_ethtool.c | 24 ++++++++++++++++ + drivers/net/ethernet/ti/cpsw_priv.c | 37 +++++++++++++++++++++++++ + drivers/net/ethernet/ti/cpsw_sl.c | 11 ++++++++ + drivers/net/ethernet/ti/davinci_cpdma.c | 27 ++++++++++++++++++ + 6 files changed, 139 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile +index 6da50f4b7c2ea..f4276c9a77620 100644 +--- a/drivers/net/ethernet/ti/Makefile ++++ b/drivers/net/ethernet/ti/Makefile +@@ -6,30 +6,30 @@ + obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o + icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_prueth_switch.o icssm/icssm_switchdev.o + +-obj-$(CONFIG_TI_CPSW) += cpsw-common.o +-obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o +-obj-$(CONFIG_TI_CPSW_SWITCHDEV) += cpsw-common.o ++ti-cpsw-common-y += cpsw-common.o davinci_cpdma.o ++ti-cpsw-priv-y += cpsw_priv.o cpsw_ethtool.o ++ti-cpsw-ale-y += cpsw_ale.o ++ti-cpsw-sl-y += cpsw_sl.o + + obj-$(CONFIG_TLAN) += tlan.o +-obj-$(CONFIG_TI_DAVINCI_EMAC) += ti_davinci_emac.o +-ti_davinci_emac-y := davinci_emac.o davinci_cpdma.o ++obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o ti-cpsw-common.o + obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o + obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o + obj-$(CONFIG_TI_CPTS) += cpts.o +-obj-$(CONFIG_TI_CPSW) += ti_cpsw.o +-ti_cpsw-y := cpsw.o davinci_cpdma.o cpsw_ale.o cpsw_priv.o cpsw_sl.o cpsw_ethtool.o +-obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o +-ti_cpsw_new-y := cpsw_switchdev.o cpsw_new.o davinci_cpdma.o cpsw_ale.o cpsw_sl.o cpsw_priv.o cpsw_ethtool.o ++obj-$(CONFIG_TI_CPSW) += ti_cpsw.o ti-cpsw-common.o ti-cpsw-priv.o ti-cpsw-ale.o ti-cpsw-sl.o ++ti_cpsw-y := cpsw.o ++obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o ti-cpsw-common.o ti-cpsw-priv.o ti-cpsw-ale.o ti-cpsw-sl.o ++ti_cpsw_new-y := cpsw_switchdev.o cpsw_new.o + +-obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o +-keystone_netcp-y := netcp_core.o cpsw_ale.o +-obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o +-keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.o ++obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o ti-cpsw-ale.o ++keystone_netcp-y := netcp_core.o ++obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o ti-cpsw-ale.o ++keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o + + obj-$(CONFIG_TI_K3_CPPI_DESC_POOL) += k3-cppi-desc-pool.o + +-obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o +-ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o ++obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o ti-cpsw-sl.o ti-cpsw-ale.o ++ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o am65-cpsw-ethtool.o + ti-am65-cpsw-nuss-$(CONFIG_TI_AM65_CPSW_QOS) += am65-cpsw-qos.o + ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o + obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o +diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c +index be7b693192216..e202bba494807 100644 +--- a/drivers/net/ethernet/ti/cpsw_ale.c ++++ b/drivers/net/ethernet/ti/cpsw_ale.c +@@ -493,6 +493,7 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid) + } + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast); + + static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, + int flags, u16 vid) +@@ -530,6 +531,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, const u8 *addr, int port, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast); + + int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port, + int flags, u16 vid) +@@ -545,6 +547,7 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, const u8 *addr, int port, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast); + + int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, + int flags, u16 vid, int mcast_state) +@@ -578,6 +581,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast); + + int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, + int flags, u16 vid) +@@ -607,6 +611,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast); + + /* ALE NetCP NU switch specific vlan functions */ + static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry, +@@ -676,6 +681,7 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag, + cpsw_ale_write(ale, idx, ale_entry); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan); + + static void cpsw_ale_vlan_del_modify_int(struct cpsw_ale *ale, u32 *ale_entry, + u16 vid, int port_mask) +@@ -733,6 +739,7 @@ int cpsw_ale_vlan_del_modify(struct cpsw_ale *ale, u16 vid, int port_mask) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_vlan_del_modify); + + int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) + { +@@ -767,6 +774,7 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan); + + int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, + int untag_mask, int reg_mask, int unreg_mask) +@@ -806,6 +814,7 @@ int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_vlan_add_modify); + + void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, + bool add) +@@ -833,6 +842,7 @@ void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, + cpsw_ale_write(ale, idx, ale_entry); + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_set_unreg_mcast); + + static void cpsw_ale_vlan_set_unreg_mcast(struct cpsw_ale *ale, u32 *ale_entry, + int allmulti) +@@ -898,6 +908,7 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port) + cpsw_ale_write(ale, idx, ale_entry); + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti); + + struct ale_control_info { + const char *name; +@@ -1155,6 +1166,7 @@ int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_control_set); + + int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) + { +@@ -1178,6 +1190,7 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) + tmp = readl_relaxed(ale->params.ale_regs + offset) >> shift; + return tmp & BITMASK(info->bits); + } ++EXPORT_SYMBOL_GPL(cpsw_ale_control_get); + + int cpsw_ale_rx_ratelimit_mc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps) + +@@ -1200,6 +1213,7 @@ int cpsw_ale_rx_ratelimit_mc(struct cpsw_ale *ale, int port, unsigned int rateli + port, val * ALE_RATE_LIMIT_MIN_PPS); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_rx_ratelimit_mc); + + int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int ratelimit_pps) + +@@ -1222,6 +1236,7 @@ int cpsw_ale_rx_ratelimit_bc(struct cpsw_ale *ale, int port, unsigned int rateli + port, val * ALE_RATE_LIMIT_MIN_PPS); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_rx_ratelimit_bc); + + static void cpsw_ale_timer(struct timer_list *t) + { +@@ -1311,6 +1326,7 @@ void cpsw_ale_start(struct cpsw_ale *ale) + + cpsw_ale_aging_start(ale); + } ++EXPORT_SYMBOL_GPL(cpsw_ale_start); + + void cpsw_ale_stop(struct cpsw_ale *ale) + { +@@ -1318,6 +1334,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale) + cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); + cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); + } ++EXPORT_SYMBOL_GPL(cpsw_ale_stop); + + static const struct reg_field ale_fields_cpsw[] = { + /* CPSW_ALE_IDVER_REG */ +@@ -1618,6 +1635,7 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) + cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); + return ale; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_create); + + void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) + { +@@ -1628,6 +1646,7 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) + data += ALE_ENTRY_WORDS; + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_dump); + + void cpsw_ale_restore(struct cpsw_ale *ale, u32 *data) + { +@@ -1638,11 +1657,13 @@ void cpsw_ale_restore(struct cpsw_ale *ale, u32 *data) + data += ALE_ENTRY_WORDS; + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_restore); + + u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale) + { + return ale ? ale->params.ale_entries : 0; + } ++EXPORT_SYMBOL_GPL(cpsw_ale_get_num_entries); + + /* Reads the specified policer index into ALE POLICER registers */ + static void cpsw_ale_policer_read_idx(struct cpsw_ale *ale, u32 idx) +@@ -1745,3 +1766,7 @@ void cpsw_ale_classifier_setup_default(struct cpsw_ale *ale, int num_rx_ch) + 1); + } + } ++EXPORT_SYMBOL_GPL(cpsw_ale_classifier_setup_default); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("TI N-Port Ethernet Switch Address Lookup Engine"); +diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c +index a43f75ee269ed..3f2682c461f9c 100644 +--- a/drivers/net/ethernet/ti/cpsw_ethtool.c ++++ b/drivers/net/ethernet/ti/cpsw_ethtool.c +@@ -144,6 +144,7 @@ u32 cpsw_get_msglevel(struct net_device *ndev) + + return priv->msg_enable; + } ++EXPORT_SYMBOL_GPL(cpsw_get_msglevel); + + void cpsw_set_msglevel(struct net_device *ndev, u32 value) + { +@@ -151,6 +152,7 @@ void cpsw_set_msglevel(struct net_device *ndev, u32 value) + + priv->msg_enable = value; + } ++EXPORT_SYMBOL_GPL(cpsw_set_msglevel); + + int cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, +@@ -161,6 +163,7 @@ int cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + coal->rx_coalesce_usecs = cpsw->coal_intvl; + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_coalesce); + + int cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + struct kernel_ethtool_coalesce *kernel_coal, +@@ -220,6 +223,7 @@ int cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal, + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_set_coalesce); + + int cpsw_get_sset_count(struct net_device *ndev, int sset) + { +@@ -234,6 +238,7 @@ int cpsw_get_sset_count(struct net_device *ndev, int sset) + return -EOPNOTSUPP; + } + } ++EXPORT_SYMBOL_GPL(cpsw_get_sset_count); + + static void cpsw_add_ch_strings(u8 **p, int ch_num, int rx_dir) + { +@@ -271,6 +276,7 @@ void cpsw_get_strings(struct net_device *ndev, u32 stringset, u8 *data) + break; + } + } ++EXPORT_SYMBOL_GPL(cpsw_get_strings); + + void cpsw_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +@@ -303,6 +309,7 @@ void cpsw_get_ethtool_stats(struct net_device *ndev, + } + } + } ++EXPORT_SYMBOL_GPL(cpsw_get_ethtool_stats); + + void cpsw_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pause) +@@ -313,6 +320,7 @@ void cpsw_get_pauseparam(struct net_device *ndev, + pause->rx_pause = priv->rx_pause ? true : false; + pause->tx_pause = priv->tx_pause ? true : false; + } ++EXPORT_SYMBOL_GPL(cpsw_get_pauseparam); + + void cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + { +@@ -326,6 +334,7 @@ void cpsw_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + if (cpsw->slaves[slave_no].phy) + phy_ethtool_get_wol(cpsw->slaves[slave_no].phy, wol); + } ++EXPORT_SYMBOL_GPL(cpsw_get_wol); + + int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + { +@@ -338,6 +347,7 @@ int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) + else + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_set_wol); + + int cpsw_get_regs_len(struct net_device *ndev) + { +@@ -346,6 +356,7 @@ int cpsw_get_regs_len(struct net_device *ndev) + return cpsw_ale_get_num_entries(cpsw->ale) * + ALE_ENTRY_WORDS * sizeof(u32); + } ++EXPORT_SYMBOL_GPL(cpsw_get_regs_len); + + void cpsw_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p) + { +@@ -357,6 +368,7 @@ void cpsw_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p) + + cpsw_ale_dump(cpsw->ale, reg); + } ++EXPORT_SYMBOL_GPL(cpsw_get_regs); + + int cpsw_ethtool_op_begin(struct net_device *ndev) + { +@@ -370,6 +382,7 @@ int cpsw_ethtool_op_begin(struct net_device *ndev) + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_ethtool_op_begin); + + void cpsw_ethtool_op_complete(struct net_device *ndev) + { +@@ -377,6 +390,7 @@ void cpsw_ethtool_op_complete(struct net_device *ndev) + + pm_runtime_put(priv->cpsw->dev); + } ++EXPORT_SYMBOL_GPL(cpsw_ethtool_op_complete); + + void cpsw_get_channels(struct net_device *ndev, struct ethtool_channels *ch) + { +@@ -391,6 +405,7 @@ void cpsw_get_channels(struct net_device *ndev, struct ethtool_channels *ch) + ch->tx_count = cpsw->tx_ch_num; + ch->combined_count = 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_channels); + + int cpsw_get_link_ksettings(struct net_device *ndev, + struct ethtool_link_ksettings *ecmd) +@@ -405,6 +420,7 @@ int cpsw_get_link_ksettings(struct net_device *ndev, + phy_ethtool_ksettings_get(cpsw->slaves[slave_no].phy, ecmd); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_link_ksettings); + + int cpsw_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *ecmd) +@@ -418,6 +434,7 @@ int cpsw_set_link_ksettings(struct net_device *ndev, + + return phy_ethtool_ksettings_set(cpsw->slaves[slave_no].phy, ecmd); + } ++EXPORT_SYMBOL_GPL(cpsw_set_link_ksettings); + + int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) + { +@@ -430,6 +447,7 @@ int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) + else + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_get_eee); + + int cpsw_nway_reset(struct net_device *ndev) + { +@@ -442,6 +460,7 @@ int cpsw_nway_reset(struct net_device *ndev) + else + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_nway_reset); + + static void cpsw_suspend_data_pass(struct net_device *ndev) + { +@@ -639,6 +658,7 @@ int cpsw_set_channels_common(struct net_device *ndev, + cpsw_fail(cpsw); + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_set_channels_common); + + void cpsw_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering, +@@ -654,6 +674,7 @@ void cpsw_get_ringparam(struct net_device *ndev, + ering->rx_max_pending = cpsw->descs_pool_size - CPSW_MAX_QUEUES; + ering->rx_pending = cpdma_get_num_rx_descs(cpsw->dma); + } ++EXPORT_SYMBOL_GPL(cpsw_get_ringparam); + + int cpsw_set_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering, +@@ -700,6 +721,7 @@ int cpsw_set_ringparam(struct net_device *ndev, + cpsw_fail(cpsw); + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_set_ringparam); + + #if IS_ENABLED(CONFIG_TI_CPTS) + int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *info) +@@ -720,6 +742,7 @@ int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *inf + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_ts_info); + #else + int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *info) + { +@@ -729,4 +752,5 @@ int cpsw_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *inf + info->rx_filters = 0; + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_get_ts_info); + #endif +diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c +index c6eb6b785b0b5..1f6f374551cb6 100644 +--- a/drivers/net/ethernet/ti/cpsw_priv.c ++++ b/drivers/net/ethernet/ti/cpsw_priv.c +@@ -32,6 +32,7 @@ + #define CPTS_N_ETX_TS 4 + + int (*cpsw_slave_index)(struct cpsw_common *cpsw, struct cpsw_priv *priv); ++EXPORT_SYMBOL_GPL(cpsw_slave_index); + + void cpsw_intr_enable(struct cpsw_common *cpsw) + { +@@ -40,6 +41,7 @@ void cpsw_intr_enable(struct cpsw_common *cpsw) + + cpdma_ctlr_int_ctrl(cpsw->dma, true); + } ++EXPORT_SYMBOL_GPL(cpsw_intr_enable); + + void cpsw_intr_disable(struct cpsw_common *cpsw) + { +@@ -48,6 +50,7 @@ void cpsw_intr_disable(struct cpsw_common *cpsw) + + cpdma_ctlr_int_ctrl(cpsw->dma, false); + } ++EXPORT_SYMBOL_GPL(cpsw_intr_disable); + + void cpsw_tx_handler(void *token, int len, int status) + { +@@ -82,6 +85,7 @@ void cpsw_tx_handler(void *token, int len, int status) + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += len; + } ++EXPORT_SYMBOL_GPL(cpsw_tx_handler); + + irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) + { +@@ -98,6 +102,7 @@ irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) + napi_schedule(&cpsw->napi_tx); + return IRQ_HANDLED; + } ++EXPORT_SYMBOL_GPL(cpsw_tx_interrupt); + + irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) + { +@@ -114,6 +119,7 @@ irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) + napi_schedule(&cpsw->napi_rx); + return IRQ_HANDLED; + } ++EXPORT_SYMBOL_GPL(cpsw_rx_interrupt); + + irqreturn_t cpsw_misc_interrupt(int irq, void *dev_id) + { +@@ -126,6 +132,7 @@ irqreturn_t cpsw_misc_interrupt(int irq, void *dev_id) + + return IRQ_HANDLED; + } ++EXPORT_SYMBOL_GPL(cpsw_misc_interrupt); + + int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget) + { +@@ -158,6 +165,7 @@ int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget) + + return num_tx; + } ++EXPORT_SYMBOL_GPL(cpsw_tx_mq_poll); + + int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) + { +@@ -176,6 +184,7 @@ int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) + + return num_tx; + } ++EXPORT_SYMBOL_GPL(cpsw_tx_poll); + + int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget) + { +@@ -208,6 +217,7 @@ int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget) + + return num_rx; + } ++EXPORT_SYMBOL_GPL(cpsw_rx_mq_poll); + + int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) + { +@@ -226,6 +236,7 @@ int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) + + return num_rx; + } ++EXPORT_SYMBOL_GPL(cpsw_rx_poll); + + void cpsw_rx_vlan_encap(struct sk_buff *skb) + { +@@ -268,12 +279,14 @@ void cpsw_rx_vlan_encap(struct sk_buff *skb) + skb_pull(skb, VLAN_HLEN); + } + } ++EXPORT_SYMBOL_GPL(cpsw_rx_vlan_encap); + + void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv) + { + slave_write(slave, mac_hi(priv->mac_addr), SA_HI); + slave_write(slave, mac_lo(priv->mac_addr), SA_LO); + } ++EXPORT_SYMBOL_GPL(cpsw_set_slave_mac); + + void cpsw_soft_reset(const char *module, void __iomem *reg) + { +@@ -286,6 +299,7 @@ void cpsw_soft_reset(const char *module, void __iomem *reg) + + WARN(readl_relaxed(reg) & 1, "failed to soft-reset %s\n", module); + } ++EXPORT_SYMBOL_GPL(cpsw_soft_reset); + + void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) + { +@@ -305,6 +319,7 @@ void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) + netif_trans_update(ndev); + netif_tx_wake_all_queues(ndev); + } ++EXPORT_SYMBOL_GPL(cpsw_ndo_tx_timeout); + + static int cpsw_get_common_speed(struct cpsw_common *cpsw) + { +@@ -343,6 +358,7 @@ int cpsw_need_resplit(struct cpsw_common *cpsw) + + return 1; + } ++EXPORT_SYMBOL_GPL(cpsw_need_resplit); + + void cpsw_split_res(struct cpsw_common *cpsw) + { +@@ -428,6 +444,7 @@ void cpsw_split_res(struct cpsw_common *cpsw) + if (budget) + cpsw->rxv[0].budget += budget; + } ++EXPORT_SYMBOL_GPL(cpsw_split_res); + + int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, + int ale_ageout, phys_addr_t desc_mem_phys, +@@ -548,6 +565,7 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_init_common); + + #if IS_ENABLED(CONFIG_TI_CPTS) + +@@ -678,6 +696,7 @@ int cpsw_hwtstamp_set(struct net_device *dev, + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_hwtstamp_set); + + int cpsw_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *cfg) +@@ -695,12 +714,14 @@ int cpsw_hwtstamp_get(struct net_device *dev, + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_hwtstamp_get); + #else + int cpsw_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *cfg) + { + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_hwtstamp_set); + + int cpsw_hwtstamp_set(struct net_device *dev, + struct kernel_hwtstamp_config *cfg, +@@ -708,6 +729,7 @@ int cpsw_hwtstamp_set(struct net_device *dev, + { + return -EOPNOTSUPP; + } ++EXPORT_SYMBOL_GPL(cpsw_hwtstamp_get); + #endif /*CONFIG_TI_CPTS*/ + + int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) +@@ -758,6 +780,7 @@ int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) + cpsw_split_res(cpsw); + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_ndo_set_tx_maxrate); + + static int cpsw_tc_to_fifo(int tc, int num_tc) + { +@@ -782,6 +805,7 @@ bool cpsw_shp_is_off(struct cpsw_priv *priv) + + return !val; + } ++EXPORT_SYMBOL_GPL(cpsw_shp_is_off); + + static void cpsw_fifo_shp_on(struct cpsw_priv *priv, int fifo, int on) + { +@@ -1043,6 +1067,7 @@ int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + return -EOPNOTSUPP; + } + } ++EXPORT_SYMBOL_GPL(cpsw_ndo_setup_tc); + + void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) + { +@@ -1056,6 +1081,7 @@ void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) + cpsw_set_fifo_rlimit(priv, fifo, bw); + } + } ++EXPORT_SYMBOL_GPL(cpsw_cbs_resume); + + void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) + { +@@ -1078,6 +1104,7 @@ void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) + + slave_write(slave, tx_prio_map, tx_prio_rg); + } ++EXPORT_SYMBOL_GPL(cpsw_mqprio_resume); + + int cpsw_fill_rx_channels(struct cpsw_priv *priv) + { +@@ -1123,6 +1150,7 @@ int cpsw_fill_rx_channels(struct cpsw_priv *priv) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_fill_rx_channels); + + static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw, + int size) +@@ -1208,6 +1236,7 @@ void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw) + cpsw->page_pool[ch] = NULL; + } + } ++EXPORT_SYMBOL_GPL(cpsw_destroy_xdp_rxqs); + + int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw) + { +@@ -1240,6 +1269,7 @@ int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw) + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_create_xdp_rxqs); + + static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf) + { +@@ -1267,6 +1297,7 @@ int cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf) + return -EINVAL; + } + } ++EXPORT_SYMBOL_GPL(cpsw_ndo_bpf); + + int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf, + struct page *page, int port) +@@ -1300,6 +1331,7 @@ int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf, + + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_xdp_tx_frame); + + int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp, + struct page *page, int port, int *len) +@@ -1362,6 +1394,7 @@ int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp, + page_pool_recycle_direct(cpsw->page_pool[ch], page); + return ret; + } ++EXPORT_SYMBOL_GPL(cpsw_run_xdp); + + static int cpsw_qos_clsflower_add_policer(struct cpsw_priv *priv, + struct netlink_ext_ack *extack, +@@ -1564,3 +1597,7 @@ void cpsw_qos_clsflower_resume(struct cpsw_priv *priv) + cpsw_ale_rx_ratelimit_mc(priv->cpsw->ale, port_id, + priv->ale_mc_ratelimit.rate_packet_ps); + } ++EXPORT_SYMBOL_GPL(cpsw_qos_clsflower_resume); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("TI CPSW Ethernet Switch Driver"); +diff --git a/drivers/net/ethernet/ti/cpsw_sl.c b/drivers/net/ethernet/ti/cpsw_sl.c +index 0c7531cb0f398..761719a348fa5 100644 +--- a/drivers/net/ethernet/ti/cpsw_sl.c ++++ b/drivers/net/ethernet/ti/cpsw_sl.c +@@ -200,6 +200,7 @@ u32 cpsw_sl_reg_read(struct cpsw_sl *sl, enum cpsw_sl_regs reg) + dev_dbg(sl->dev, "cpsw_sl: reg: %04X r 0x%08X\n", sl->regs[reg], val); + return val; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_reg_read); + + void cpsw_sl_reg_write(struct cpsw_sl *sl, enum cpsw_sl_regs reg, u32 val) + { +@@ -212,6 +213,7 @@ void cpsw_sl_reg_write(struct cpsw_sl *sl, enum cpsw_sl_regs reg, u32 val) + dev_dbg(sl->dev, "cpsw_sl: reg: %04X w 0x%08X\n", sl->regs[reg], val); + writel(val, sl->sl_base + sl->regs[reg]); + } ++EXPORT_SYMBOL_GPL(cpsw_sl_reg_write); + + static const struct cpsw_sl_dev_id *cpsw_sl_match_id( + const struct cpsw_sl_dev_id *id, +@@ -252,6 +254,7 @@ struct cpsw_sl *cpsw_sl_get(const char *device_id, struct device *dev, + + return sl; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_get); + + void cpsw_sl_reset(struct cpsw_sl *sl, unsigned long tmo) + { +@@ -270,6 +273,7 @@ void cpsw_sl_reset(struct cpsw_sl *sl, unsigned long tmo) + if (cpsw_sl_reg_read(sl, CPSW_SL_SOFT_RESET) & CPSW_SL_SOFT_RESET_BIT) + dev_err(sl->dev, "cpsw_sl failed to soft-reset.\n"); + } ++EXPORT_SYMBOL_GPL(cpsw_sl_reset); + + u32 cpsw_sl_ctl_set(struct cpsw_sl *sl, u32 ctl_funcs) + { +@@ -287,6 +291,7 @@ u32 cpsw_sl_ctl_set(struct cpsw_sl *sl, u32 ctl_funcs) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_ctl_set); + + u32 cpsw_sl_ctl_clr(struct cpsw_sl *sl, u32 ctl_funcs) + { +@@ -304,11 +309,13 @@ u32 cpsw_sl_ctl_clr(struct cpsw_sl *sl, u32 ctl_funcs) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_ctl_clr); + + void cpsw_sl_ctl_reset(struct cpsw_sl *sl) + { + cpsw_sl_reg_write(sl, CPSW_SL_MACCONTROL, 0); + } ++EXPORT_SYMBOL_GPL(cpsw_sl_ctl_reset); + + int cpsw_sl_wait_for_idle(struct cpsw_sl *sl, unsigned long tmo) + { +@@ -326,3 +333,7 @@ int cpsw_sl_wait_for_idle(struct cpsw_sl *sl, unsigned long tmo) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpsw_sl_wait_for_idle); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("TI Ethernet Switch media-access-controller (MAC) submodule"); +diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c +index d2eab5cd1e0c9..41e89a19be537 100644 +--- a/drivers/net/ethernet/ti/davinci_cpdma.c ++++ b/drivers/net/ethernet/ti/davinci_cpdma.c +@@ -531,6 +531,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params) + ctlr->num_chan = CPDMA_MAX_CHANNELS; + return ctlr; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_create); + + int cpdma_ctlr_start(struct cpdma_ctlr *ctlr) + { +@@ -591,6 +592,7 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr) + spin_unlock_irqrestore(&ctlr->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_start); + + int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) + { +@@ -623,6 +625,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) + spin_unlock_irqrestore(&ctlr->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_stop); + + int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) + { +@@ -640,6 +643,7 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) + cpdma_desc_pool_destroy(ctlr); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy); + + int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable) + { +@@ -660,21 +664,25 @@ int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable) + spin_unlock_irqrestore(&ctlr->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_int_ctrl); + + void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value) + { + dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, value); + } ++EXPORT_SYMBOL_GPL(cpdma_ctlr_eoi); + + u32 cpdma_ctrl_rxchs_state(struct cpdma_ctlr *ctlr) + { + return dma_reg_read(ctlr, CPDMA_RXINTSTATMASKED); + } ++EXPORT_SYMBOL_GPL(cpdma_ctrl_rxchs_state); + + u32 cpdma_ctrl_txchs_state(struct cpdma_ctlr *ctlr) + { + return dma_reg_read(ctlr, CPDMA_TXINTSTATMASKED); + } ++EXPORT_SYMBOL_GPL(cpdma_ctrl_txchs_state); + + static void cpdma_chan_set_descs(struct cpdma_ctlr *ctlr, + int rx, int desc_num, +@@ -802,6 +810,7 @@ int cpdma_chan_set_weight(struct cpdma_chan *ch, int weight) + spin_unlock_irqrestore(&ctlr->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_set_weight); + + /* cpdma_chan_get_min_rate - get minimum allowed rate for channel + * Should be called before cpdma_chan_set_rate. +@@ -816,6 +825,7 @@ u32 cpdma_chan_get_min_rate(struct cpdma_ctlr *ctlr) + + return DIV_ROUND_UP(divident, divisor); + } ++EXPORT_SYMBOL_GPL(cpdma_chan_get_min_rate); + + /* cpdma_chan_set_rate - limits bandwidth for transmit channel. + * The bandwidth * limited channels have to be in order beginning from lowest. +@@ -860,6 +870,7 @@ int cpdma_chan_set_rate(struct cpdma_chan *ch, u32 rate) + spin_unlock_irqrestore(&ctlr->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_set_rate); + + u32 cpdma_chan_get_rate(struct cpdma_chan *ch) + { +@@ -872,6 +883,7 @@ u32 cpdma_chan_get_rate(struct cpdma_chan *ch) + + return rate; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_get_rate); + + struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num, + cpdma_handler_fn handler, int rx_type) +@@ -931,6 +943,7 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num, + spin_unlock_irqrestore(&ctlr->lock, flags); + return chan; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_create); + + int cpdma_chan_get_rx_buf_num(struct cpdma_chan *chan) + { +@@ -943,6 +956,7 @@ int cpdma_chan_get_rx_buf_num(struct cpdma_chan *chan) + + return desc_num; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_get_rx_buf_num); + + int cpdma_chan_destroy(struct cpdma_chan *chan) + { +@@ -964,6 +978,7 @@ int cpdma_chan_destroy(struct cpdma_chan *chan) + spin_unlock_irqrestore(&ctlr->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_destroy); + + int cpdma_chan_get_stats(struct cpdma_chan *chan, + struct cpdma_chan_stats *stats) +@@ -976,6 +991,7 @@ int cpdma_chan_get_stats(struct cpdma_chan *chan, + spin_unlock_irqrestore(&chan->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_get_stats); + + static void __cpdma_chan_submit(struct cpdma_chan *chan, + struct cpdma_desc __iomem *desc) +@@ -1100,6 +1116,7 @@ int cpdma_chan_idle_submit(struct cpdma_chan *chan, void *token, void *data, + spin_unlock_irqrestore(&chan->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_idle_submit); + + int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token, + dma_addr_t data, int len, int directed) +@@ -1125,6 +1142,7 @@ int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token, + spin_unlock_irqrestore(&chan->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_idle_submit_mapped); + + int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, + int len, int directed) +@@ -1150,6 +1168,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, + spin_unlock_irqrestore(&chan->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_submit); + + int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token, + dma_addr_t data, int len, int directed) +@@ -1175,6 +1194,7 @@ int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token, + spin_unlock_irqrestore(&chan->lock, flags); + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_submit_mapped); + + bool cpdma_check_free_tx_desc(struct cpdma_chan *chan) + { +@@ -1189,6 +1209,7 @@ bool cpdma_check_free_tx_desc(struct cpdma_chan *chan) + spin_unlock_irqrestore(&chan->lock, flags); + return free_tx_desc; + } ++EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc); + + static void __cpdma_chan_free(struct cpdma_chan *chan, + struct cpdma_desc __iomem *desc, +@@ -1289,6 +1310,7 @@ int cpdma_chan_process(struct cpdma_chan *chan, int quota) + } + return used; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_process); + + int cpdma_chan_start(struct cpdma_chan *chan) + { +@@ -1308,6 +1330,7 @@ int cpdma_chan_start(struct cpdma_chan *chan) + + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_start); + + int cpdma_chan_stop(struct cpdma_chan *chan) + { +@@ -1370,6 +1393,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan) + spin_unlock_irqrestore(&chan->lock, flags); + return 0; + } ++EXPORT_SYMBOL_GPL(cpdma_chan_stop); + + int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable) + { +@@ -1416,11 +1440,13 @@ int cpdma_get_num_rx_descs(struct cpdma_ctlr *ctlr) + { + return ctlr->num_rx_desc; + } ++EXPORT_SYMBOL_GPL(cpdma_get_num_rx_descs); + + int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr) + { + return ctlr->num_tx_desc; + } ++EXPORT_SYMBOL_GPL(cpdma_get_num_tx_descs); + + int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc) + { +@@ -1442,3 +1468,4 @@ int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc) + + return ret; + } ++EXPORT_SYMBOL_GPL(cpdma_set_num_rx_descs); +-- +2.53.0 + diff --git a/queue-7.0/net-ethernet-ti-cpsw-rename-soft_reset-function.patch b/queue-7.0/net-ethernet-ti-cpsw-rename-soft_reset-function.patch new file mode 100644 index 0000000000..12261a86ee --- /dev/null +++ b/queue-7.0/net-ethernet-ti-cpsw-rename-soft_reset-function.patch @@ -0,0 +1,82 @@ +From 0c4c76477085278aadc282ab690d1026e082bee9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 20:46:53 +0200 +Subject: net: ethernet: ti-cpsw:: rename soft_reset() function + +From: Arnd Bergmann + +[ Upstream commit 961f3c535608df64553f61d64ca086aa9f371bdd ] + +While looking at the glob symbols shared between the cpsw drivers, +I noticed that soft_reset() is the only one that is missing a proper +namespace prefix, and will pollute the kernel namespace, so rename +it to be consistent with the other symbols. + +Reviewed-by: Alexander Sverdlin +Signed-off-by: Arnd Bergmann +Link: https://patch.msgid.link/20260402184726.3746487-1-arnd@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: df75bd552a87 ("net: ethernet: ti-cpsw: fix linking built-in code to modules") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ti/cpsw.c | 2 +- + drivers/net/ethernet/ti/cpsw_new.c | 2 +- + drivers/net/ethernet/ti/cpsw_priv.c | 2 +- + drivers/net/ethernet/ti/cpsw_priv.h | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c +index b0e18bdc2c851..aa3531e844e87 100644 +--- a/drivers/net/ethernet/ti/cpsw.c ++++ b/drivers/net/ethernet/ti/cpsw.c +@@ -706,7 +706,7 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) + struct cpsw_common *cpsw = priv->cpsw; + + /* soft reset the controller and initialize ale */ +- soft_reset("cpsw", &cpsw->regs->soft_reset); ++ cpsw_soft_reset("cpsw", &cpsw->regs->soft_reset); + cpsw_ale_start(cpsw->ale); + + /* switch to vlan aware mode */ +diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c +index 7f42f58a4b031..c5be359f3c663 100644 +--- a/drivers/net/ethernet/ti/cpsw_new.c ++++ b/drivers/net/ethernet/ti/cpsw_new.c +@@ -573,7 +573,7 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) + u32 control_reg; + + /* soft reset the controller and initialize ale */ +- soft_reset("cpsw", &cpsw->regs->soft_reset); ++ cpsw_soft_reset("cpsw", &cpsw->regs->soft_reset); + cpsw_ale_start(cpsw->ale); + + /* switch to vlan aware mode */ +diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c +index bc4fdf17a99ec..c6eb6b785b0b5 100644 +--- a/drivers/net/ethernet/ti/cpsw_priv.c ++++ b/drivers/net/ethernet/ti/cpsw_priv.c +@@ -275,7 +275,7 @@ void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv) + slave_write(slave, mac_lo(priv->mac_addr), SA_LO); + } + +-void soft_reset(const char *module, void __iomem *reg) ++void cpsw_soft_reset(const char *module, void __iomem *reg) + { + unsigned long timeout = jiffies + HZ; + +diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h +index acb6181c5c9e1..fddd7a79f4b0f 100644 +--- a/drivers/net/ethernet/ti/cpsw_priv.h ++++ b/drivers/net/ethernet/ti/cpsw_priv.h +@@ -458,7 +458,7 @@ int cpsw_tx_poll(struct napi_struct *napi_tx, int budget); + int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget); + int cpsw_rx_poll(struct napi_struct *napi_rx, int budget); + void cpsw_rx_vlan_encap(struct sk_buff *skb); +-void soft_reset(const char *module, void __iomem *reg); ++void cpsw_soft_reset(const char *module, void __iomem *reg); + void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv); + void cpsw_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue); + int cpsw_need_resplit(struct cpsw_common *cpsw); +-- +2.53.0 + diff --git a/queue-7.0/net-fix-skb_ext_total_length-build_bug_on-with-confi.patch b/queue-7.0/net-fix-skb_ext_total_length-build_bug_on-with-confi.patch new file mode 100644 index 0000000000..9e75ff35c8 --- /dev/null +++ b/queue-7.0/net-fix-skb_ext_total_length-build_bug_on-with-confi.patch @@ -0,0 +1,83 @@ +From 0fa03aa325704fe4aa7a5134aef647928df86cc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:21:49 +0300 +Subject: net: fix skb_ext_total_length() BUILD_BUG_ON with + CONFIG_GCOV_PROFILE_ALL + +From: Konstantin Khorenko + +[ Upstream commit c0b4382c86e3d92f79b71c9ed55654db520d7b36 ] + +When CONFIG_GCOV_PROFILE_ALL=y is enabled, the kernel fails to build: + + In file included from : + In function 'skb_extensions_init', + inlined from 'skb_init' at net/core/skbuff.c:5214:2: + ././include/linux/compiler_types.h:706:45: error: call to + '__compiletime_assert_1490' declared with attribute error: + BUILD_BUG_ON failed: skb_ext_total_length() > 255 + +CONFIG_GCOV_PROFILE_ALL adds -fprofile-arcs -ftest-coverage +-fno-tree-loop-im to CFLAGS globally. GCC inserts branch profiling +counters into the skb_ext_total_length() loop and, combined with +-fno-tree-loop-im (which disables loop invariant motion), cannot +constant-fold the result. +BUILD_BUG_ON requires a compile-time constant and fails. + +The issue manifests in kernels with 5+ SKB extension types enabled +(e.g., after addition of SKB_EXT_CAN, SKB_EXT_PSP). With 4 extensions +GCC can still unroll and fold the loop despite GCOV instrumentation; +with 5+ it gives up. + +Mark skb_ext_total_length() with __no_profile to prevent GCOV from +inserting counters into this function. Without counters the loop is +"clean" and GCC can constant-fold it even with -fno-tree-loop-im active. +This allows BUILD_BUG_ON to work correctly while keeping GCOV profiling +for the rest of the kernel. + +This also removes the CONFIG_KCOV_INSTRUMENT_ALL preprocessor guard +introduced by d6e5794b06c0. That guard was added as a precaution because +KCOV instrumentation was also suspected of inhibiting constant folding. +However, KCOV uses -fsanitize-coverage=trace-pc, which inserts +lightweight trace callbacks that do not interfere with GCC's constant +folding or loop optimization passes. Only GCOV's -fprofile-arcs combined +with -fno-tree-loop-im actually prevents the compiler from evaluating +the loop at compile time. The guard is therefore unnecessary and can be +safely removed. + +Fixes: 96ea3a1e2d31 ("can: add CAN skb extension infrastructure") +Signed-off-by: Konstantin Khorenko +Reviewed-by: Thomas Weissschuh +Link: https://patch.msgid.link/20260410162150.3105738-2-khorenko@virtuozzo.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/skbuff.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 43ee86dcf2eaf..59fb4b2bb8217 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -5142,7 +5142,7 @@ static const u8 skb_ext_type_len[] = { + #endif + }; + +-static __always_inline unsigned int skb_ext_total_length(void) ++static __always_inline __no_profile unsigned int skb_ext_total_length(void) + { + unsigned int l = SKB_EXT_CHUNKSIZEOF(struct skb_ext); + int i; +@@ -5156,9 +5156,7 @@ static __always_inline unsigned int skb_ext_total_length(void) + static void skb_extensions_init(void) + { + BUILD_BUG_ON(SKB_EXT_NUM > 8); +-#if !IS_ENABLED(CONFIG_KCOV_INSTRUMENT_ALL) + BUILD_BUG_ON(skb_ext_total_length() > 255); +-#endif + + skbuff_ext_cache = kmem_cache_create("skbuff_ext_cache", + SKB_EXT_ALIGN_VALUE * skb_ext_total_length(), +-- +2.53.0 + diff --git a/queue-7.0/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch b/queue-7.0/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch new file mode 100644 index 0000000000..280d799456 --- /dev/null +++ b/queue-7.0/net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch @@ -0,0 +1,71 @@ +From dcdb605e274ed1d459a4343f3b62defcc2198b0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:31:01 +0800 +Subject: net: hamradio: 6pack: fix uninit-value in sixpack_receive_buf + +From: Mashiro Chen + +[ Upstream commit bf9a38803b2626b01cc769aaf13485d8650f576f ] + +sixpack_receive_buf() does not properly skip bytes with TTY error flags. +The while loop iterates through the flags buffer but never advances the +data pointer (cp), and passes the original count (including error bytes) +to sixpack_decode(). This causes sixpack_decode() to process bytes that +should have been skipped due to TTY errors. The TTY layer does not +guarantee that cp[i] holds a meaningful value when fp[i] is set, so +passing those positions to sixpack_decode() results in KMSAN reporting +an uninit-value read. + +Fix this by processing bytes one at a time, advancing cp on each +iteration, and only passing valid (non-error) bytes to sixpack_decode(). +This matches the pattern used by slip_receive_buf() and +mkiss_receive_buf() for the same purpose. + +Reported-by: syzbot+ecdb8c9878a81eb21e54@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=ecdb8c9878a81eb21e54 +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Mashiro Chen +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260407173101.107352-1-mashiro.chen@mailbox.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/hamradio/6pack.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c +index 885992951e8a6..c8b2dc5c1becc 100644 +--- a/drivers/net/hamradio/6pack.c ++++ b/drivers/net/hamradio/6pack.c +@@ -391,7 +391,6 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + const u8 *fp, size_t count) + { + struct sixpack *sp; +- size_t count1; + + if (!count) + return; +@@ -401,16 +400,16 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp, + return; + + /* Read the characters out of the buffer */ +- count1 = count; +- while (count) { +- count--; ++ while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) + sp->dev->stats.rx_errors++; ++ cp++; + continue; + } ++ sixpack_decode(sp, cp, 1); ++ cp++; + } +- sixpack_decode(sp, cp, count1); + + tty_unthrottle(tty); + } +-- +2.53.0 + diff --git a/queue-7.0/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch b/queue-7.0/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch new file mode 100644 index 0000000000..049b60701f --- /dev/null +++ b/queue-7.0/net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch @@ -0,0 +1,42 @@ +From 4758af69f08f3a34c61f6e8aada6289db6e20002 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:13:32 +0200 +Subject: net: ipa: Fix decoding EV_PER_EE for IPA v5.0+ + +From: Luca Weiss + +[ Upstream commit 1335b903cf2e8aeaca87fd665683384c731ec941 ] + +Initially 'reg' and 'val' are assigned from HW_PARAM_2. + +But since IPA v5.0+ takes EV_PER_EE from HW_PARAM_4 (instead of +NUM_EV_PER_EE from HW_PARAM_2), we not only need to re-assign 'reg' but +also read the register value of that register into 'val' so that +reg_decode() works on the correct value. + +Fixes: f651334e1ef5 ("net: ipa: add HW_PARAM_4 GSI register") +Link: https://sashiko.dev/#/patchset/20260403-milos-ipa-v1-0-01e9e4e03d3e%40fairphone.com?part=2 +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260409-ipa-fixes-v1-2-a817c30678ac@fairphone.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ipa/gsi.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c +index 4c3227e77898c..624649484d627 100644 +--- a/drivers/net/ipa/gsi.c ++++ b/drivers/net/ipa/gsi.c +@@ -2044,6 +2044,7 @@ static int gsi_ring_setup(struct gsi *gsi) + count = reg_decode(reg, NUM_EV_PER_EE, val); + } else { + reg = gsi_reg(gsi, HW_PARAM_4); ++ val = ioread32(gsi->virt + reg_offset(reg)); + count = reg_decode(reg, EV_PER_EE, val); + } + if (!count) { +-- +2.53.0 + diff --git a/queue-7.0/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch b/queue-7.0/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch new file mode 100644 index 0000000000..0190b11b84 --- /dev/null +++ b/queue-7.0/net-ipa-fix-programming-of-qtime_timestamp_cfg.patch @@ -0,0 +1,51 @@ +From c11445a0d6a08d6bcd87f8a6b0ab8ddb92152887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 10:13:31 +0200 +Subject: net: ipa: Fix programming of QTIME_TIMESTAMP_CFG + +From: Luca Weiss + +[ Upstream commit de08f9585692813bd41ee654fca0487664c4de30 ] + +The 'val' variable gets overwritten multiple times, discarding previous +values. Looking at the git log shows these should be combined with |= +instead. + +Fixes: 9265a4f0f0b4 ("net: ipa: define even more IPA register fields") +Link: https://sashiko.dev/#/patchset/20260403-milos-ipa-v1-0-01e9e4e03d3e%40fairphone.com?part=4 +Signed-off-by: Luca Weiss +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260409-ipa-fixes-v1-1-a817c30678ac@fairphone.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ipa/ipa_main.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c +index edead9c48d1fe..216506eeef1fb 100644 +--- a/drivers/net/ipa/ipa_main.c ++++ b/drivers/net/ipa/ipa_main.c +@@ -361,7 +361,7 @@ static void ipa_qtime_config(struct ipa *ipa) + { + const struct reg *reg; + u32 offset; +- u32 val; ++ u32 val = 0; + + /* Timer clock divider must be disabled when we change the rate */ + reg = ipa_reg(ipa, TIMERS_XO_CLK_DIV_CFG); +@@ -374,8 +374,8 @@ static void ipa_qtime_config(struct ipa *ipa) + val |= reg_bit(reg, DPL_TIMESTAMP_SEL); + } + /* Configure tag and NAT Qtime timestamp resolution as well */ +- val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); +- val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); ++ val |= reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); ++ val |= reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); + + iowrite32(val, ipa->reg_virt + reg_offset(reg)); + +-- +2.53.0 + diff --git a/queue-7.0/net-mana-don-t-overwrite-port-probe-error-with-add_a.patch b/queue-7.0/net-mana-don-t-overwrite-port-probe-error-with-add_a.patch new file mode 100644 index 0000000000..0f85342eac --- /dev/null +++ b/queue-7.0/net-mana-don-t-overwrite-port-probe-error-with-add_a.patch @@ -0,0 +1,73 @@ +From 1264081cd15288e3e5526d97566c4aeacd6d3ed8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:38 -0700 +Subject: net: mana: Don't overwrite port probe error with add_adev result + +From: Erni Sri Satya Vennela + +[ Upstream commit a7fdaf069bd031fcc234581fa6a580be11bf2175 ] + +In mana_probe(), if mana_probe_port() fails for any port, the error +is stored in 'err' and the loop breaks. However, the subsequent +unconditional 'err = add_adev(gd, "eth")' overwrites this error. +If add_adev() succeeds, mana_probe() returns success despite ports +being left in a partially initialized state (ac->ports[i] == NULL). + +Only call add_adev() when there is no prior error, so the probe +correctly fails and triggers mana_remove() cleanup. + +Fixes: a69839d4327d ("net: mana: Add support for auxiliary device") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-5-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index e5b4f07e009bf..09d67617dfbbf 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3643,10 +3643,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + if (!resuming) { + for (i = 0; i < ac->num_ports; i++) { + err = mana_probe_port(ac, i, &ac->ports[i]); +- /* we log the port for which the probe failed and stop +- * probes for subsequent ports. +- * Note that we keep running ports, for which the probes +- * were successful, unless add_adev fails too ++ /* Log the port for which the probe failed, stop probing ++ * subsequent ports, and skip add_adev. ++ * mana_remove() will clean up already-probed ports. + */ + if (err) { + dev_err(dev, "Probe Failed for port %d\n", i); +@@ -3660,10 +3659,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + enable_work(&apc->queue_reset_work); + err = mana_attach(ac->ports[i]); + rtnl_unlock(); +- /* we log the port for which the attach failed and stop +- * attach for subsequent ports +- * Note that we keep running ports, for which the attach +- * were successful, unless add_adev fails too ++ /* Log the port for which the attach failed, stop ++ * attaching subsequent ports, and skip add_adev. ++ * mana_remove() will clean up already-attached ports. + */ + if (err) { + dev_err(dev, "Attach Failed for port %d\n", i); +@@ -3672,7 +3670,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + } + } + +- err = add_adev(gd, "eth"); ++ if (!err) ++ err = add_adev(gd, "eth"); + + schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD); + +-- +2.53.0 + diff --git a/queue-7.0/net-mana-fix-eq-leak-in-mana_remove-on-null-port.patch b/queue-7.0/net-mana-fix-eq-leak-in-mana_remove-on-null-port.patch new file mode 100644 index 0000000000..da5d69731b --- /dev/null +++ b/queue-7.0/net-mana-fix-eq-leak-in-mana_remove-on-null-port.patch @@ -0,0 +1,56 @@ +From 2f1ff57345cee865c5ec6d07aa2e83ba4376484f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:39 -0700 +Subject: net: mana: Fix EQ leak in mana_remove on NULL port + +From: Erni Sri Satya Vennela + +[ Upstream commit 65267c9c4f28199985505977bc2c628c82fc50ef ] + +In mana_remove(), when a NULL port is encountered in the port iteration +loop, 'goto out' skips the mana_destroy_eq(ac) call, leaking the event +queues allocated earlier by mana_create_eq(). + +This can happen when mana_probe_port() fails for port 0, leaving +ac->ports[0] as NULL. On driver unload or error cleanup, mana_remove() +hits the NULL entry and jumps past mana_destroy_eq(). + +Change 'goto out' to 'break' so the for-loop exits normally and +mana_destroy_eq() is always reached. Remove the now-unreferenced out: +label. + +Fixes: 1e2d0824a9c3 ("net: mana: Add support for EQ sharing") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-6-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 09d67617dfbbf..14d6f68eaa695 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3715,7 +3715,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + if (!ndev) { + if (i == 0) + dev_err(dev, "No net device to remove\n"); +- goto out; ++ break; + } + + apc = netdev_priv(ndev); +@@ -3746,7 +3746,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + } + + mana_destroy_eq(ac); +-out: ++ + if (ac->per_port_queue_reset_wq) { + destroy_workqueue(ac->per_port_queue_reset_wq); + ac->per_port_queue_reset_wq = NULL; +-- +2.53.0 + diff --git a/queue-7.0/net-mana-guard-mana_remove-against-double-invocation.patch b/queue-7.0/net-mana-guard-mana_remove-against-double-invocation.patch new file mode 100644 index 0000000000..bdc992e162 --- /dev/null +++ b/queue-7.0/net-mana-guard-mana_remove-against-double-invocation.patch @@ -0,0 +1,57 @@ +From d9dd8236adf443c42cd171055c248e0766062d18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:37 -0700 +Subject: net: mana: Guard mana_remove against double invocation + +From: Erni Sri Satya Vennela + +[ Upstream commit 50271d7ec95144d26808025b508f463780517d3c ] + +If PM resume fails (e.g., mana_attach() returns an error), mana_probe() +calls mana_remove(), which tears down the device and sets +gd->gdma_context = NULL and gd->driver_data = NULL. + +However, a failed resume callback does not automatically unbind the +driver. When the device is eventually unbound, mana_remove() is invoked +a second time. Without a NULL check, it dereferences gc->dev with +gc == NULL, causing a kernel panic. + +Add an early return if gdma_context or driver_data is NULL so the second +invocation is harmless. Move the dev = gc->dev assignment after the +guard so it cannot dereference NULL. + +Fixes: 635096a86edb ("net: mana: Support hibernation and kexec") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-4-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 974df81855d23..e5b4f07e009bf 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3694,11 +3694,16 @@ void mana_remove(struct gdma_dev *gd, bool suspending) + struct gdma_context *gc = gd->gdma_context; + struct mana_context *ac = gd->driver_data; + struct mana_port_context *apc; +- struct device *dev = gc->dev; ++ struct device *dev; + struct net_device *ndev; + int err; + int i; + ++ if (!gc || !ac) ++ return; ++ ++ dev = gc->dev; ++ + disable_work_sync(&ac->link_change_work); + cancel_delayed_work_sync(&ac->gf_stats_work); + +-- +2.53.0 + diff --git a/queue-7.0/net-mana-init-gf_stats_work-before-potential-error-p.patch b/queue-7.0/net-mana-init-gf_stats_work-before-potential-error-p.patch new file mode 100644 index 0000000000..95605b7cf9 --- /dev/null +++ b/queue-7.0/net-mana-init-gf_stats_work-before-potential-error-p.patch @@ -0,0 +1,52 @@ +From 92687e41cba0f962e8a89e9d7137ef8ea568caa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:36 -0700 +Subject: net: mana: Init gf_stats_work before potential error paths in probe + +From: Erni Sri Satya Vennela + +[ Upstream commit 6e8bc03349fe4f09567fa76235abf52bdaf83082 ] + +Move INIT_DELAYED_WORK(gf_stats_work) to before mana_create_eq(), +while keeping schedule_delayed_work() at its original location. + +Previously, if any function between mana_create_eq() and the +INIT_DELAYED_WORK call failed, mana_probe() would call mana_remove() +which unconditionally calls cancel_delayed_work_sync(gf_stats_work) +in __flush_work() or debug object warnings with +CONFIG_DEBUG_OBJECTS_WORK enabled. + +Fixes: be4f1d67ec56 ("net: mana: Add standard counter rx_missed_errors") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-3-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 2b3dd326a8e15..974df81855d23 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3598,6 +3598,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + INIT_WORK(&ac->link_change_work, mana_link_state_handle); + } + ++ INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler); ++ + err = mana_create_eq(ac); + if (err) { + dev_err(dev, "Failed to create EQs: %d\n", err); +@@ -3672,7 +3674,6 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + + err = add_adev(gd, "eth"); + +- INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler); + schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD); + + out: +-- +2.53.0 + diff --git a/queue-7.0/net-mana-init-link_change_work-before-potential-erro.patch b/queue-7.0/net-mana-init-link_change_work-before-potential-erro.patch new file mode 100644 index 0000000000..e90003ba7b --- /dev/null +++ b/queue-7.0/net-mana-init-link_change_work-before-potential-erro.patch @@ -0,0 +1,54 @@ +From b4c5447cd262b09751232daeb579d0bd2207055b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 05:47:35 -0700 +Subject: net: mana: Init link_change_work before potential error paths in + probe + +From: Erni Sri Satya Vennela + +[ Upstream commit cb4a90744bcd1adf12f0d0c7c4f0dd2647444ec5 ] + +Move INIT_WORK(link_change_work) to right after the mana_context +allocation, before any error path that could reach mana_remove(). + +Previously, if mana_create_eq() or mana_query_device_cfg() failed, +mana_probe() would jump to the error path which calls mana_remove(). +mana_remove() unconditionally calls disable_work_sync(link_change_work), +but the work struct had not been initialized yet. This can trigger +CONFIG_DEBUG_OBJECTS_WORK enabled. + +Fixes: 54133f9b4b53 ("net: mana: Support HW link state events") +Signed-off-by: Erni Sri Satya Vennela +Link: https://patch.msgid.link/20260420124741.1056179-2-ernis@linux.microsoft.com +Reviewed-by: Simon Horman +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 2ff19e1938f49..2b3dd326a8e15 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3594,6 +3594,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + + ac->gdma_dev = gd; + gd->driver_data = ac; ++ ++ INIT_WORK(&ac->link_change_work, mana_link_state_handle); + } + + err = mana_create_eq(ac); +@@ -3611,8 +3613,6 @@ int mana_probe(struct gdma_dev *gd, bool resuming) + + if (!resuming) { + ac->num_ports = num_ports; +- +- INIT_WORK(&ac->link_change_work, mana_link_state_handle); + } else { + if (ac->num_ports != num_ports) { + dev_err(dev, "The number of vPorts changed: %d->%d\n", +-- +2.53.0 + diff --git a/queue-7.0/net-mana-move-current_speed-debugfs-file-to-mana_ini.patch b/queue-7.0/net-mana-move-current_speed-debugfs-file-to-mana_ini.patch new file mode 100644 index 0000000000..92bc2323a5 --- /dev/null +++ b/queue-7.0/net-mana-move-current_speed-debugfs-file-to-mana_ini.patch @@ -0,0 +1,51 @@ +From 99ec87b0dec5b4a272f62c9810b2e10a0da053e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:12:20 -0700 +Subject: net: mana: Move current_speed debugfs file to mana_init_port() + +From: Erni Sri Satya Vennela + +[ Upstream commit 3b7c7fc97aea7b4048001d12f45777201c74a17f ] + +Move the current_speed debugfs file creation from mana_probe_port() to +mana_init_port(). The file was previously created only during initial +probe, but mana_cleanup_port_context() removes the entire vPort debugfs +directory during detach/attach cycles. Since mana_init_port() recreates +the directory on re-attach, moving current_speed here ensures it survives +these cycles. + +Fixes: 75cabb46935b ("net: mana: Add support for net_shaper_ops") +Signed-off-by: Erni Sri Satya Vennela +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260408081224.302308-3-ernis@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 6d87533924fa8..2ff19e1938f49 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -3124,6 +3124,8 @@ static int mana_init_port(struct net_device *ndev) + eth_hw_addr_set(ndev, apc->mac_addr); + sprintf(vport, "vport%d", port_idx); + apc->mana_port_debugfs = debugfs_create_dir(vport, gc->mana_pci_debugfs); ++ debugfs_create_u32("current_speed", 0400, apc->mana_port_debugfs, ++ &apc->speed); + return 0; + + reset_apc: +@@ -3402,8 +3404,6 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, + + netif_carrier_on(ndev); + +- debugfs_create_u32("current_speed", 0400, apc->mana_port_debugfs, &apc->speed); +- + return 0; + + free_indir: +-- +2.53.0 + diff --git a/queue-7.0/net-mana-use-pci_name-for-debugfs-directory-naming.patch b/queue-7.0/net-mana-use-pci_name-for-debugfs-directory-naming.patch new file mode 100644 index 0000000000..1ba2ac83c4 --- /dev/null +++ b/queue-7.0/net-mana-use-pci_name-for-debugfs-directory-naming.patch @@ -0,0 +1,55 @@ +From ffb28ef3d55e6ca51149269354129970d7861265 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:12:19 -0700 +Subject: net: mana: Use pci_name() for debugfs directory naming + +From: Erni Sri Satya Vennela + +[ Upstream commit c116f07ab9d22bb6f355f3cf9e44c1e6a47fe559 ] + +Use pci_name(pdev) for the per-device debugfs directory instead of +hardcoded "0" for PFs and pci_slot_name(pdev->slot) for VFs. The +previous approach had two issues: + +1. pci_slot_name() dereferences pdev->slot, which can be NULL for VFs + in environments like generic VFIO passthrough or nested KVM, + causing a NULL pointer dereference. + +2. Multiple PFs would all use "0", and VFs across different PCI + domains or buses could share the same slot name, leading to + -EEXIST errors from debugfs_create_dir(). + +pci_name(pdev) returns the unique BDF address, is always valid, and is +unique across the system. + +Fixes: 6607c17c6c5e ("net: mana: Enable debugfs files for MANA device") +Signed-off-by: Erni Sri Satya Vennela +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260408081224.302308-2-ernis@linux.microsoft.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/microsoft/mana/gdma_main.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c +index 786186c9a115f..c2e855ff3ca9a 100644 +--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c ++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c +@@ -2007,11 +2007,8 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + gc->dev = &pdev->dev; + xa_init(&gc->irq_contexts); + +- if (gc->is_pf) +- gc->mana_pci_debugfs = debugfs_create_dir("0", mana_debugfs_root); +- else +- gc->mana_pci_debugfs = debugfs_create_dir(pci_slot_name(pdev->slot), +- mana_debugfs_root); ++ gc->mana_pci_debugfs = debugfs_create_dir(pci_name(pdev), ++ mana_debugfs_root); + + err = mana_gd_setup(pdev); + if (err) +-- +2.53.0 + diff --git a/queue-7.0/net-mctp-i2c-check-length-before-marking-flow-active.patch b/queue-7.0/net-mctp-i2c-check-length-before-marking-flow-active.patch new file mode 100644 index 0000000000..fbe5f520d0 --- /dev/null +++ b/queue-7.0/net-mctp-i2c-check-length-before-marking-flow-active.patch @@ -0,0 +1,90 @@ +From d6ba4ce5f96a6e21b94dd9b6fda5258f0a137ec6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:46:52 -0700 +Subject: net: mctp i2c: check length before marking flow active + +From: William A. Kennington III + +[ Upstream commit 4ca07b9239bd0478ae586632a2ed72be37ed8407 ] + +Currently, mctp_i2c_get_tx_flow_state() is called before the packet length +sanity check. This function marks a new flow as active in the MCTP core. + +If the sanity check fails, mctp_i2c_xmit() returns early without calling +mctp_i2c_lock_nest(). This results in a mismatched locking state: the +flow is active, but the I2C bus lock was never acquired for it. + +When the flow is later released, mctp_i2c_release_flow() will see the +active state and queue an unlock marker. The TX thread will then +decrement midev->i2c_lock_count from 0, causing it to underflow to -1. + +This underflow permanently breaks the driver's locking logic, allowing +future transmissions to occur without holding the I2C bus lock, leading +to bus collisions and potential hardware hangs. + +Move the mctp_i2c_get_tx_flow_state() call to after the length sanity +check to ensure we only transition the flow state if we are actually +going to proceed with the transmission and locking. + +Fixes: f5b8abf9fc3d ("mctp i2c: MCTP I2C binding driver") +Signed-off-by: William A. Kennington III +Acked-by: Jeremy Kerr +Link: https://patch.msgid.link/20260423074741.201460-1-william@wkennington.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/mctp/mctp-i2c.c | 4 ++-- + net/sched/cls_flower.c | 4 +++- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c +index 15fe4d1163c1c..ee2913758e54e 100644 +--- a/drivers/net/mctp/mctp-i2c.c ++++ b/drivers/net/mctp/mctp-i2c.c +@@ -496,8 +496,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + u8 *pecp; + int rc; + +- fs = mctp_i2c_get_tx_flow_state(midev, skb); +- + hdr = (void *)skb_mac_header(skb); + /* Sanity check that packet contents matches skb length, + * and can't exceed MCTP_I2C_BUFSZ +@@ -509,6 +507,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb) + return; + } + ++ fs = mctp_i2c_get_tx_flow_state(midev, skb); ++ + if (skb_tailroom(skb) >= 1) { + /* Linear case with space, we can just append the PEC */ + skb_put(skb, 1); +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index 26070c892305d..dd6727691cff5 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -560,6 +560,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); ++ struct fl_flow_mask *mask; + + *last = false; + +@@ -576,11 +577,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- *last = fl_mask_put(head, f->mask); ++ mask = f->mask; + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); ++ *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch b/queue-7.0/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch new file mode 100644 index 0000000000..f795713e1f --- /dev/null +++ b/queue-7.0/net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch @@ -0,0 +1,53 @@ +From 8b86f2ef056301a9b636b08f28fb173604830787 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 01:49:37 +0100 +Subject: net/mlx5: Fix HCA caps leak on notifier init failure + +From: Prathamesh Deshpande + +[ Upstream commit d03fc81a57956248383efec99967d0ae627390a8 ] + +mlx5_mdev_init() allocates HCA caps via mlx5_hca_caps_alloc() before +calling mlx5_notifiers_init(). If notifier initialization fails, the +error path jumps to err_hca_caps and skips mlx5_hca_caps_free(), leaking +allocated caps. + +Add a dedicated unwind label for notifier-init failure that frees HCA +caps before continuing the existing cleanup sequence. + +Fixes: b6b03097f982 ("net/mlx5: Initialize events outside devlink lock") +Signed-off-by: Prathamesh Deshpande +Reviewed-by: Cosmin Ratiu +Reviewed-by: Tariq Toukan +Link: https://patch.msgid.link/20260415005022.34764-1-prathameshdeshpande7@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c +index 3f73d9b1115dd..fab80c79ff071 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c +@@ -1907,7 +1907,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) + + err = mlx5_notifiers_init(dev); + if (err) +- goto err_hca_caps; ++ goto err_notifiers_init; + + /* The conjunction of sw_vhca_id with sw_owner_id will be a global + * unique id per function which uses mlx5_core. +@@ -1923,6 +1923,8 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) + + return 0; + ++err_notifiers_init: ++ mlx5_hca_caps_free(dev); + err_hca_caps: + mlx5_adev_cleanup(dev); + err_adev_init: +-- +2.53.0 + diff --git a/queue-7.0/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch b/queue-7.0/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch new file mode 100644 index 0000000000..f5a00e1d40 --- /dev/null +++ b/queue-7.0/net-mlx5e-fix-features-not-applied-during-netdev-reg.patch @@ -0,0 +1,63 @@ +From 08a1e2db2e94bb15feb7d9acae2e237781724ca4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 23:28:51 +0300 +Subject: net/mlx5e: Fix features not applied during netdev registration + +From: Gal Pressman + +[ Upstream commit 9994ad4df82d64e57135c0f0906897685f5a9e87 ] + +mlx5e_fix_features() returns early when the netdevice is not present. +This is correct during profile transitions where priv is cleared, but it +also incorrectly blocks feature fixups during register_netdev(), when +the device is also not yet present. + +It is not trivial to distinguish between both cases as we cannot use +priv to carry state, and in both cases reg_state == NETREG_REGISTERED. + +Force a netdev features update after register_netdev() completes, where +the device is present and fix_features() can actually work. + +This is not a pretty solution, as it results in an additional features +update call (register_netdevice() already calls +__netdev_update_features() internally), but it is the simplest, +cleanest, and most robust way I found to fix this issue after multiple +attempts. + +This fixes an issue on systems where CQE compression is enabled by +default, RXHASH remains enabled after registration despite the two +features being mutually exclusive. + +Fixes: ab4b01bfdaa6 ("net/mlx5e: Verify dev is present for fix features ndo") +Signed-off-by: Gal Pressman +Reviewed-by: Dragos Tatulea +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260409202852.158059-2-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index b6c12460b54a9..0b8b44bbcb9ef 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -6756,6 +6756,14 @@ static int _mlx5e_probe(struct auxiliary_device *adev) + goto err_resume; + } + ++ /* mlx5e_fix_features() returns early when the device is not present ++ * to avoid dereferencing cleared priv during profile changes. ++ * This also causes it to be a no-op during register_netdev(), where ++ * the device is not yet present. ++ * Trigger an additional features update that will actually work. ++ */ ++ mlx5e_update_features(netdev); ++ + mlx5e_dcbnl_init_app(priv); + mlx5_core_uplink_netdev_set(mdev, netdev); + mlx5e_params_print_info(mdev, &priv->channels.params); +-- +2.53.0 + diff --git a/queue-7.0/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch b/queue-7.0/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch new file mode 100644 index 0000000000..fe374917fc --- /dev/null +++ b/queue-7.0/net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch @@ -0,0 +1,81 @@ +From 4fc91f2b367f09b17e0c117055b5991601a61999 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 23:28:52 +0300 +Subject: net/mlx5e: IPsec, fix ASO poll timeout with + read_poll_timeout_atomic() + +From: Gal Pressman + +[ Upstream commit edccdd1eb94712da97a6ce71123ec27890add754 ] + +The do-while poll loop uses jiffies for its timeout: + expires = jiffies + msecs_to_jiffies(10); + +jiffies is sampled at an arbitrary point within the current tick, so the +first partial tick contributes anywhere from a full tick down to nearly +zero real time. For small msecs_to_jiffies() results this is +significant, the effective poll window can be much shorter than the +requested 10ms, and in the worst case the loop exits after a single +iteration (e.g., when HZ=100), well before the device has delivered the +CQE. + +Replace the loop with read_poll_timeout_atomic(), which counts elapsed +time via udelay() accounting rather than jiffies, guaranteeing the full +poll window regardless of HZ. + +Additionally, read_poll_timeout_atomic() executes the poll operation one +more time after the timeout has expired, giving the CQE a final chance +to be detected. The old do-while loop could exit without a final poll if +the timeout expired during the udelay() between iterations. + +Fixes: 76e463f6508b ("net/mlx5e: Overcome slow response for first IPsec ASO WQE") +Signed-off-by: Gal Pressman +Reviewed-by: Jianbo Liu +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20260409202852.158059-3-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../mellanox/mlx5/core/en_accel/ipsec_offload.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +index 05faad5083d9d..145677ce96408 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +@@ -1,6 +1,8 @@ + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB + /* Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. */ + ++#include ++ + #include "mlx5_core.h" + #include "en.h" + #include "ipsec.h" +@@ -592,7 +594,6 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, + struct mlx5_wqe_aso_ctrl_seg *ctrl; + struct mlx5e_hw_objs *res; + struct mlx5_aso_wqe *wqe; +- unsigned long expires; + u8 ds_cnt; + int ret; + +@@ -614,13 +615,8 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry, + mlx5e_ipsec_aso_copy(ctrl, data); + + mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl); +- expires = jiffies + msecs_to_jiffies(10); +- do { +- ret = mlx5_aso_poll_cq(aso->aso, false); +- if (ret) +- /* We are in atomic context */ +- udelay(10); +- } while (ret && time_is_after_jiffies(expires)); ++ read_poll_timeout_atomic(mlx5_aso_poll_cq, ret, !ret, 10, ++ 10 * USEC_PER_MSEC, false, aso->aso, false); + if (!ret) + memcpy(sa_entry->ctx, aso->ctx, MLX5_ST_SZ_BYTES(ipsec_aso)); + spin_unlock_bh(&aso->lock); +-- +2.53.0 + diff --git a/queue-7.0/net-phonet-do-not-bug_on-in-pn_socket_autobind-on-fa.patch b/queue-7.0/net-phonet-do-not-bug_on-in-pn_socket_autobind-on-fa.patch new file mode 100644 index 0000000000..d3ab4618e2 --- /dev/null +++ b/queue-7.0/net-phonet-do-not-bug_on-in-pn_socket_autobind-on-fa.patch @@ -0,0 +1,84 @@ +From e843c668592173c29812526ab8923cea2bb890ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 09:05:57 +0800 +Subject: net: phonet: do not BUG_ON() in pn_socket_autobind() on failed bind +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Morduan Zang + +[ Upstream commit 5b0c911bcdbd982f7748d11c0b39ec5808eae2de ] + +syzbot reported a kernel BUG triggered from pn_socket_sendmsg() via +pn_socket_autobind(): + + kernel BUG at net/phonet/socket.c:213! + RIP: 0010:pn_socket_autobind net/phonet/socket.c:213 [inline] + RIP: 0010:pn_socket_sendmsg+0x240/0x250 net/phonet/socket.c:421 + Call Trace: + sock_sendmsg_nosec+0x112/0x150 net/socket.c:797 + __sock_sendmsg net/socket.c:812 [inline] + __sys_sendto+0x402/0x590 net/socket.c:2280 + ... + +pn_socket_autobind() calls pn_socket_bind() with port 0 and, on +-EINVAL, assumes the socket was already bound and asserts that the +port is non-zero: + + err = pn_socket_bind(sock, ..., sizeof(struct sockaddr_pn)); + if (err != -EINVAL) + return err; + BUG_ON(!pn_port(pn_sk(sock->sk)->sobject)); + return 0; /* socket was already bound */ + +However pn_socket_bind() also returns -EINVAL when sk->sk_state is not +TCP_CLOSE, even when the socket has never been bound and pn_port() is +still 0. In that case the BUG_ON() fires and panics the kernel from a +user-triggerable path. + +Treat the "bind returned -EINVAL but pn_port() is still 0" case as a +regular error and propagate -EINVAL to the caller instead of crashing. +Existing callers already translate a non-zero return from +pn_socket_autobind() into -ENOBUFS/-EAGAIN, so returning -EINVAL here +only changes behaviour from panic to a normal errno. + +Fixes: ba113a94b750 ("Phonet: common socket glue") +Reported-by: syzbot+706f5eb79044e686c794@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=706f5eb79044e686c794 +Suggested-by: Remi Denis-Courmont +Signed-off-by: Morduan Zang +Signed-off-by: zhanjun +Acked-by: Rémi Denis-Courmont +Link: https://patch.msgid.link/87A8960A2045AF3C+20260423010557.138124-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/phonet/socket.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/phonet/socket.c b/net/phonet/socket.c +index 4423d483c630a..bbd710d95b975 100644 +--- a/net/phonet/socket.c ++++ b/net/phonet/socket.c +@@ -208,9 +208,15 @@ static int pn_socket_autobind(struct socket *sock) + sa.spn_family = AF_PHONET; + err = pn_socket_bind(sock, (struct sockaddr_unsized *)&sa, + sizeof(struct sockaddr_pn)); +- if (err != -EINVAL) ++ /* ++ * pn_socket_bind() also returns -EINVAL when sk_state != TCP_CLOSE ++ * without a prior bind, so -EINVAL alone is not sufficient to infer ++ * that the socket was already bound. Only treat it as "already ++ * bound" when the port is non-zero; otherwise propagate the error ++ * instead of crashing the kernel. ++ */ ++ if (err != -EINVAL || unlikely(!pn_port(pn_sk(sock->sk)->sobject))) + return err; +- BUG_ON(!pn_port(pn_sk(sock->sk)->sobject)); + return 0; /* socket was already bound */ + } + +-- +2.53.0 + diff --git a/queue-7.0/net-phy-dp83869-fix-setting-clk_o_sel-field.patch b/queue-7.0/net-phy-dp83869-fix-setting-clk_o_sel-field.patch new file mode 100644 index 0000000000..c5f8e82902 --- /dev/null +++ b/queue-7.0/net-phy-dp83869-fix-setting-clk_o_sel-field.patch @@ -0,0 +1,64 @@ +From 7bf8ac525f7efb2080a51d7444cb8332901edd48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 05:13:39 +0200 +Subject: net: phy: dp83869: fix setting CLK_O_SEL field. + +From: Heiko Schocher + +[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ] + +Table 7-121 in datasheet says we have to set register 0xc6 +to value 0x10 before CLK_O_SEL can be modified. No more infos +about this field found in datasheet. With this fix, setting +of CLK_O_SEL field in IO_MUX_CFG register worked through dts +property "ti,clk-output-sel" on a DP83869HMRGZR. + +Signed-off-by: Heiko Schocher +Reviewed-by: Simon Horman +Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") +Link: https://patch.msgid.link/20260425031339.3318-1-hs@nabladev.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/phy/dp83869.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c +index 1f381d7b13ff3..96a7d255f50fd 100644 +--- a/drivers/net/phy/dp83869.c ++++ b/drivers/net/phy/dp83869.c +@@ -31,6 +31,7 @@ + #define DP83869_RGMIICTL 0x0032 + #define DP83869_STRAP_STS1 0x006e + #define DP83869_RGMIIDCTL 0x0086 ++#define DP83869_ANA_PLL_PROG_PI 0x00c6 + #define DP83869_RXFCFG 0x0134 + #define DP83869_RXFPMD1 0x0136 + #define DP83869_RXFPMD2 0x0137 +@@ -826,12 +827,22 @@ static int dp83869_config_init(struct phy_device *phydev) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ +- if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) ++ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) { ++ /* ++ * Table 7-121 in datasheet says we have to set register 0xc6 ++ * to value 0x10 before CLK_O_SEL can be modified. ++ */ ++ ret = phy_write_mmd(phydev, DP83869_DEVADDR, ++ DP83869_ANA_PLL_PROG_PI, 0x10); ++ if (ret) ++ return ret; ++ + ret = phy_modify_mmd(phydev, + DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); ++ } + + if (phy_interface_is_rgmii(phydev)) { + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL, +-- +2.53.0 + diff --git a/queue-7.0/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch b/queue-7.0/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch new file mode 100644 index 0000000000..0e3bbf8e1a --- /dev/null +++ b/queue-7.0/net-phy-fix-a-return-path-in-get_phy_c45_ids.patch @@ -0,0 +1,44 @@ +From e5dfb87248c6cc39abaa1b2c85c78e668eabf1f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 06:36:54 -0700 +Subject: net: phy: fix a return path in get_phy_c45_ids() + +From: Charles Perry + +[ Upstream commit 6f533abe7bbad2eef1e42c639b6bb9dad2b02362 ] + +The return value of phy_c45_probe_present() is stored in "ret", not +"phy_reg", fix this. "phy_reg" always has a positive value if we reach +this return path (since it would have returned earlier otherwise), which +means that the original goal of the patch of not considering -ENODEV +fatal wasn't achieved. + +Fixes: 17b447539408 ("net: phy: c45 scanning: Don't consider -ENODEV fatal") +Signed-off-by: Charles Perry +Reviewed-by: Andrew Lunn +Reviewed-by: Russell King (Oracle) +Link: https://patch.msgid.link/20260409133654.3203336-1-charles.perry@microchip.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/phy_device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 3bd415710bf3f..f3696d9819d35 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -927,8 +927,8 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr, + /* returning -ENODEV doesn't stop bus + * scanning + */ +- return (phy_reg == -EIO || +- phy_reg == -ENODEV) ? -ENODEV : -EIO; ++ return (ret == -EIO || ++ ret == -ENODEV) ? -ENODEV : -EIO; + + if (!ret) + continue; +-- +2.53.0 + diff --git a/queue-7.0/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch b/queue-7.0/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch new file mode 100644 index 0000000000..f08433acb2 --- /dev/null +++ b/queue-7.0/net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch @@ -0,0 +1,67 @@ +From 38eef92b952134f84fb39be8f242ac6087dbf5f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:10:20 +0200 +Subject: net: phy: qcom: at803x: Use the correct bit to disable extended next + page + +From: Maxime Chevallier + +[ Upstream commit e7a62edd34b1b4bc5f979988efc2f81c075733fd ] + +As noted in the blamed commit, the AR8035 and other PHYs from this +family advertise the Extended Next Page support by default, which may be +understood by some partners as this PHY being multi-gig capable. + +The fix is to disable XNP advertising, which is done by setting bit 12 +of the Auto-Negotiation Advertisement Register (MII_ADVERTISE). + +The blamed commit incorrectly uses MDIO_AN_CTRL1_XNP, which is bit 13 as per +802.3 : 45.2.7.1 AN control register (Register 7.0) + +BIT 12 in MII_ADVERTISE is wrapped by ADVERTISE_RESV, used by some +drivers such as the aquantia one. 802.3 Clause 28 defines bit 12 as +Extended Next Page ability, at least in recent versions of the standard. + +Let's add a define for it and use it in the at803x driver. + +Fixes: 3c51fa5d2afe ("net: phy: ar803x: disable extended next page bit") +Signed-off-by: Maxime Chevallier +Reviewed-by: Andrew Lunn +Link: https://patch.msgid.link/20260410171021.1277138-1-maxime.chevallier@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/phy/qcom/at803x.c | 2 +- + include/uapi/linux/mii.h | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c +index 2995b08bac963..63726cf98cd42 100644 +--- a/drivers/net/phy/qcom/at803x.c ++++ b/drivers/net/phy/qcom/at803x.c +@@ -524,7 +524,7 @@ static int at803x_config_init(struct phy_device *phydev) + * behaviour but we still need to accommodate it. XNP is only needed + * for 10Gbps support, so disable XNP. + */ +- return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); ++ return phy_modify(phydev, MII_ADVERTISE, ADVERTISE_XNP, 0); + } + + static void at803x_link_change_notify(struct phy_device *phydev) +diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h +index 39f7c44baf535..61d6edad4b94a 100644 +--- a/include/uapi/linux/mii.h ++++ b/include/uapi/linux/mii.h +@@ -82,7 +82,8 @@ + #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ + #define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ + #define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +-#define ADVERTISE_RESV 0x1000 /* Unused... */ ++#define ADVERTISE_XNP 0x1000 /* Extended Next Page */ ++#define ADVERTISE_RESV ADVERTISE_XNP /* Used to be reserved */ + #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ + #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ + #define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +-- +2.53.0 + diff --git a/queue-7.0/net-plumb-drop-reasons-to-__dev_queue_xmit.patch b/queue-7.0/net-plumb-drop-reasons-to-__dev_queue_xmit.patch new file mode 100644 index 0000000000..a29080d8aa --- /dev/null +++ b/queue-7.0/net-plumb-drop-reasons-to-__dev_queue_xmit.patch @@ -0,0 +1,148 @@ +From ea2bd793b92a4481e4a2094e392f29b915d138f3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 20:18:24 +0000 +Subject: net: plumb drop reasons to __dev_queue_xmit() + +From: Eric Dumazet + +[ Upstream commit 045f977dd4ebdd3ad8e96cf684917adfc5805adb ] + +Add drop reasons to __dev_queue_xmit(): + +- SKB_DROP_REASON_DEV_READY : device is not UP. + +- SKB_DROP_REASON_RECURSION_LIMIT : recursion limit on virtual device is hit. + +Also add an unlikely() for the SKB_DROP_REASON_DEV_READY case, +and reduce indentation level. + +Signed-off-by: Eric Dumazet +Reviewed-by: Joe Damato +Link: https://patch.msgid.link/20260312201824.203093-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()") +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 83 ++++++++++++++++++++++++++------------------------ + 1 file changed, 43 insertions(+), 40 deletions(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 831129f2a69b5..0f45825bbed2f 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4761,9 +4761,10 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev) + { + struct net_device *dev = skb->dev; + struct netdev_queue *txq = NULL; +- struct Qdisc *q; +- int rc = -ENOMEM; ++ enum skb_drop_reason reason; ++ int cpu, rc = -ENOMEM; + bool again = false; ++ struct Qdisc *q; + + skb_reset_mac_header(skb); + skb_assert_len(skb); +@@ -4832,59 +4833,61 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev) + * Check this and shot the lock. It is not prone from deadlocks. + *Either shot noqueue qdisc, it is even simpler 8) + */ +- if (dev->flags & IFF_UP) { +- int cpu = smp_processor_id(); /* ok because BHs are off */ ++ if (unlikely(!(dev->flags & IFF_UP))) { ++ reason = SKB_DROP_REASON_DEV_READY; ++ goto drop; ++ } + +- if (!netif_tx_owned(txq, cpu)) { +- bool is_list = false; ++ cpu = smp_processor_id(); /* ok because BHs are off */ + +- if (dev_xmit_recursion()) +- goto recursion_alert; ++ if (likely(!netif_tx_owned(txq, cpu))) { ++ bool is_list = false; + +- skb = validate_xmit_skb(skb, dev, &again); +- if (!skb) +- goto out; ++ if (dev_xmit_recursion()) ++ goto recursion_alert; + +- HARD_TX_LOCK(dev, txq, cpu); ++ skb = validate_xmit_skb(skb, dev, &again); ++ if (!skb) ++ goto out; + +- if (!netif_xmit_stopped(txq)) { +- is_list = !!skb->next; ++ HARD_TX_LOCK(dev, txq, cpu); + +- dev_xmit_recursion_inc(); +- skb = dev_hard_start_xmit(skb, dev, txq, &rc); +- dev_xmit_recursion_dec(); ++ if (!netif_xmit_stopped(txq)) { ++ is_list = !!skb->next; + +- /* GSO segments a single SKB into +- * a list of frames. TCP expects error +- * to mean none of the data was sent. +- */ +- if (is_list) +- rc = NETDEV_TX_OK; +- } +- HARD_TX_UNLOCK(dev, txq); +- if (!skb) /* xmit completed */ +- goto out; ++ dev_xmit_recursion_inc(); ++ skb = dev_hard_start_xmit(skb, dev, txq, &rc); ++ dev_xmit_recursion_dec(); + +- net_crit_ratelimited("Virtual device %s asks to queue packet!\n", +- dev->name); +- /* NETDEV_TX_BUSY or queue was stopped */ +- if (!is_list) +- rc = -ENETDOWN; +- } else { +- /* Recursion is detected! It is possible, +- * unfortunately ++ /* GSO segments a single SKB into a list of frames. ++ * TCP expects error to mean none of the data was sent. + */ +-recursion_alert: +- net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n", +- dev->name); +- rc = -ENETDOWN; ++ if (is_list) ++ rc = NETDEV_TX_OK; + } ++ HARD_TX_UNLOCK(dev, txq); ++ if (!skb) /* xmit completed */ ++ goto out; ++ ++ net_crit_ratelimited("Virtual device %s asks to queue packet!\n", ++ dev->name); ++ /* NETDEV_TX_BUSY or queue was stopped */ ++ if (!is_list) ++ rc = -ENETDOWN; ++ } else { ++ /* Recursion is detected! It is possible unfortunately. */ ++recursion_alert: ++ net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n", ++ dev->name); ++ rc = -ENETDOWN; + } + ++ reason = SKB_DROP_REASON_RECURSION_LIMIT; ++drop: + rcu_read_unlock_bh(); + + dev_core_stats_tx_dropped_inc(dev); +- kfree_skb_list(skb); ++ kfree_skb_list_reason(skb, reason); + return rc; + out: + rcu_read_unlock_bh(); +-- +2.53.0 + diff --git a/queue-7.0/net-psp-check-for-device-unregister-when-creating-as.patch b/queue-7.0/net-psp-check-for-device-unregister-when-creating-as.patch new file mode 100644 index 0000000000..1fcf654c19 --- /dev/null +++ b/queue-7.0/net-psp-check-for-device-unregister-when-creating-as.patch @@ -0,0 +1,64 @@ +From 163f6d733800a7950b6789fb41f81abdcfd967ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 12:06:06 -0700 +Subject: net: psp: check for device unregister when creating assoc + +From: Jakub Kicinski + +[ Upstream commit b89769f936a8fa9e66de72ddc1b71a9745a488e6 ] + +psp_assoc_device_get_locked() obtains a psp_dev reference via +psp_dev_get_for_sock() (which uses psp_dev_tryget() under RCU); +it then acquires psd->lock and drops the reference. Before +the lock is taken, psp_dev_unregister() can run to completion: +take psd->lock, clear out state, unlock, drop the registration +reference. + +The expectation is that the lock prevents device unregistration, +but much like with netdevs special care has to be taken when +"upgrading" a reference to a locked device. Add the missing +check if device is still alive. psp_dev_is_registered() exists +already but had no callers, which makes me wonder if I either +forgot to add this or lost the check during refactoring... + +Reported-by: Yiming Qian +Fixes: 6b46ca260e22 ("net: psp: add socket security association code") +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260427190606.366101-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/psp/psp_nl.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c +index 6afd7707ec12e..0cc744a6e1c9b 100644 +--- a/net/psp/psp_nl.c ++++ b/net/psp/psp_nl.c +@@ -305,8 +305,13 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, + + psd = psp_dev_get_for_sock(socket->sk); + if (psd) { +- err = psp_dev_check_access(psd, genl_info_net(info)); +- if (err) { ++ /* Extra care needed here, psp_dev_get_for_sock() only gives ++ * us access to struct psp_dev's memory, which is quite weak. ++ */ ++ mutex_lock(&psd->lock); ++ if (!psp_dev_is_registered(psd) || ++ psp_dev_check_access(psd, genl_info_net(info))) { ++ mutex_unlock(&psd->lock); + psp_dev_put(psd); + psd = NULL; + } +@@ -319,7 +324,6 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops, + + id = info->attrs[PSP_A_ASSOC_DEV_ID]; + if (psd) { +- mutex_lock(&psd->lock); + if (id && psd->id != nla_get_u32(id)) { + mutex_unlock(&psd->lock); + NL_SET_ERR_MSG_ATTR(info->extack, id, +-- +2.53.0 + diff --git a/queue-7.0/net-psp-require-admin-permission-for-dev-set-and-key.patch b/queue-7.0/net-psp-require-admin-permission-for-dev-set-and-key.patch new file mode 100644 index 0000000000..537f590e5b --- /dev/null +++ b/queue-7.0/net-psp-require-admin-permission-for-dev-set-and-key.patch @@ -0,0 +1,71 @@ +From 01e09ba98ad69dd4d6eb03e571338c8560d75757 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 12:58:56 -0700 +Subject: net: psp: require admin permission for dev-set and key-rotate + +From: Jakub Kicinski + +[ Upstream commit b718342a7fbaa2dff5fefc31988c07af8c6cbc21 ] + +The dev-set and key-rotate netlink operations modify shared device +state (PSP version configuration and cryptographic key material, +respectively) but do not require CAP_NET_ADMIN. The only access +control is psp_dev_check_access() which merely verifies netns +membership. + +Fixes: 00c94ca2b99e ("psp: base PSP device support") +Reviewed-by: Daniel Zahka +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20260427195856.401223-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + Documentation/netlink/specs/psp.yaml | 2 ++ + net/psp/psp-nl-gen.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Documentation/netlink/specs/psp.yaml b/Documentation/netlink/specs/psp.yaml +index f3a57782d2cf4..49b7563f705f1 100644 +--- a/Documentation/netlink/specs/psp.yaml ++++ b/Documentation/netlink/specs/psp.yaml +@@ -188,6 +188,7 @@ operations: + name: dev-set + doc: Set the configuration of a PSP device. + attribute-set: dev ++ flags: [admin-perm] + do: + request: + attributes: +@@ -207,6 +208,7 @@ operations: + name: key-rotate + doc: Rotate the device key. + attribute-set: dev ++ flags: [admin-perm] + do: + request: + attributes: +diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c +index 22a48d0fa378c..953309952cef7 100644 +--- a/net/psp/psp-nl-gen.c ++++ b/net/psp/psp-nl-gen.c +@@ -76,7 +76,7 @@ static const struct genl_split_ops psp_nl_ops[] = { + .post_doit = psp_device_unlock, + .policy = psp_dev_set_nl_policy, + .maxattr = PSP_A_DEV_PSP_VERSIONS_ENA, +- .flags = GENL_CMD_CAP_DO, ++ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = PSP_CMD_KEY_ROTATE, +@@ -85,7 +85,7 @@ static const struct genl_split_ops psp_nl_ops[] = { + .post_doit = psp_device_unlock, + .policy = psp_key_rotate_nl_policy, + .maxattr = PSP_A_DEV_ID, +- .flags = GENL_CMD_CAP_DO, ++ .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = PSP_CMD_RX_ASSOC, +-- +2.53.0 + diff --git a/queue-7.0/net-pull-headers-in-qdisc_pkt_len_segs_init.patch b/queue-7.0/net-pull-headers-in-qdisc_pkt_len_segs_init.patch new file mode 100644 index 0000000000..d5746e6962 --- /dev/null +++ b/queue-7.0/net-pull-headers-in-qdisc_pkt_len_segs_init.patch @@ -0,0 +1,169 @@ +From 2ef98da9f8dddd4ad4f6192279966dafb3a34059 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 22:15:40 +0000 +Subject: net: pull headers in qdisc_pkt_len_segs_init() + +From: Eric Dumazet + +[ Upstream commit 7fb4c19670110f052c04e1ec1d2b953b9f4f57e4 ] + +Most ndo_start_xmit() methods expects headers of gso packets +to be already in skb->head. + +net/core/tso.c users are particularly at risk, because tso_build_hdr() +does a memcpy(hdr, skb->data, hdr_len); + +qdisc_pkt_len_segs_init() already does a dissection of gso packets. + +Use pskb_may_pull() instead of skb_header_pointer() to make +sure drivers do not have to reimplement this. + +Some malicious packets could be fed, detect them so that we can +drop them sooner with a new SKB_DROP_REASON_SKB_BAD_GSO drop_reason. + +Fixes: e876f208af18 ("net: Add a software TSO helper API") +Signed-off-by: Eric Dumazet +Reviewed-by: Joe Damato +Link: https://patch.msgid.link/20260403221540.3297753-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/dropreason-core.h | 3 +++ + net/core/dev.c | 51 +++++++++++++++++++++-------------- + 2 files changed, 34 insertions(+), 20 deletions(-) + +diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h +index 8e498e8431cbb..880a5ec786cfe 100644 +--- a/include/net/dropreason-core.h ++++ b/include/net/dropreason-core.h +@@ -80,6 +80,7 @@ + FN(UNHANDLED_PROTO) \ + FN(SKB_CSUM) \ + FN(SKB_GSO_SEG) \ ++ FN(SKB_BAD_GSO) \ + FN(SKB_UCOPY_FAULT) \ + FN(DEV_HDR) \ + FN(DEV_READY) \ +@@ -427,6 +428,8 @@ enum skb_drop_reason { + SKB_DROP_REASON_SKB_CSUM, + /** @SKB_DROP_REASON_SKB_GSO_SEG: gso segmentation error */ + SKB_DROP_REASON_SKB_GSO_SEG, ++ /** @SKB_DROP_REASON_SKB_BAD_GSO: malicious gso packet. */ ++ SKB_DROP_REASON_SKB_BAD_GSO, + /** + * @SKB_DROP_REASON_SKB_UCOPY_FAULT: failed to copy data from user space, + * e.g., via zerocopy_sg_from_iter() or skb_orphan_frags_rx() +diff --git a/net/core/dev.c b/net/core/dev.c +index 44a712f777b79..e4fcf09ba2beb 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4103,16 +4103,16 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d + } + EXPORT_SYMBOL_GPL(validate_xmit_skb_list); + +-static void qdisc_pkt_len_segs_init(struct sk_buff *skb) ++static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); +- unsigned int hdr_len; ++ unsigned int hdr_len, tlen; + u16 gso_segs; + + qdisc_skb_cb(skb)->pkt_len = skb->len; + if (!shinfo->gso_size) { + qdisc_skb_cb(skb)->pkt_segs = 1; +- return; ++ return SKB_NOT_DROPPED_YET; + } + + qdisc_skb_cb(skb)->pkt_segs = gso_segs = shinfo->gso_segs; +@@ -4120,43 +4120,49 @@ static void qdisc_pkt_len_segs_init(struct sk_buff *skb) + /* To get more precise estimation of bytes sent on wire, + * we add to pkt_len the headers size of all segments + */ +- if (unlikely(!skb_transport_header_was_set(skb))) +- return; + + /* mac layer + network layer */ +- if (!skb->encapsulation) ++ if (!skb->encapsulation) { ++ if (unlikely(!skb_transport_header_was_set(skb))) ++ return SKB_NOT_DROPPED_YET; + hdr_len = skb_transport_offset(skb); +- else ++ } else { + hdr_len = skb_inner_transport_offset(skb); +- ++ } + /* + transport layer */ + if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { + const struct tcphdr *th; +- struct tcphdr _tcphdr; + +- th = skb_header_pointer(skb, hdr_len, +- sizeof(_tcphdr), &_tcphdr); +- if (likely(th)) +- hdr_len += __tcp_hdrlen(th); +- } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { +- struct udphdr _udphdr; ++ if (!pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr))) ++ return SKB_DROP_REASON_SKB_BAD_GSO; + +- if (skb_header_pointer(skb, hdr_len, +- sizeof(_udphdr), &_udphdr)) +- hdr_len += sizeof(struct udphdr); ++ th = (const struct tcphdr *)(skb->data + hdr_len); ++ tlen = __tcp_hdrlen(th); ++ if (tlen < sizeof(*th)) ++ return SKB_DROP_REASON_SKB_BAD_GSO; ++ hdr_len += tlen; ++ if (!pskb_may_pull(skb, hdr_len)) ++ return SKB_DROP_REASON_SKB_BAD_GSO; ++ } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { ++ if (!pskb_may_pull(skb, hdr_len + sizeof(struct udphdr))) ++ return SKB_DROP_REASON_SKB_BAD_GSO; ++ hdr_len += sizeof(struct udphdr); + } + ++ /* prior pskb_may_pull() might have changed skb->head. */ ++ shinfo = skb_shinfo(skb); + if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) { + int payload = skb->len - hdr_len; + + /* Malicious packet. */ + if (payload <= 0) +- return; ++ return SKB_DROP_REASON_SKB_BAD_GSO; + gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size); + shinfo->gso_segs = gso_segs; + qdisc_skb_cb(skb)->pkt_segs = gso_segs; + } + qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len; ++ return SKB_NOT_DROPPED_YET; + } + + static int dev_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *q, +@@ -4773,6 +4779,12 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev) + (SKBTX_SCHED_TSTAMP | SKBTX_BPF))) + __skb_tstamp_tx(skb, NULL, NULL, skb->sk, SCM_TSTAMP_SCHED); + ++ reason = qdisc_pkt_len_segs_init(skb); ++ if (unlikely(reason)) { ++ dev_core_stats_tx_dropped_inc(dev); ++ kfree_skb_reason(skb, reason); ++ return -EINVAL; ++ } + /* Disable soft irqs for various locks below. Also + * stops preemption for RCU. + */ +@@ -4780,7 +4792,6 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev) + + skb_update_prio(skb); + +- qdisc_pkt_len_segs_init(skb); + tcx_set_ingress(skb, false); + #ifdef CONFIG_NET_EGRESS + if (static_branch_unlikely(&egress_needed_key)) { +-- +2.53.0 + diff --git a/queue-7.0/net-qdisc_pkt_len_segs_init-cleanup.patch b/queue-7.0/net-qdisc_pkt_len_segs_init-cleanup.patch new file mode 100644 index 0000000000..d895e887db --- /dev/null +++ b/queue-7.0/net-qdisc_pkt_len_segs_init-cleanup.patch @@ -0,0 +1,116 @@ +From 430d44d11a69c26a811a4f6e77731834e8e0b258 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 22:15:39 +0000 +Subject: net: qdisc_pkt_len_segs_init() cleanup + +From: Eric Dumazet + +[ Upstream commit 30e02ec3b4b6bd429a4824f125eb843a291dcccf ] + +Reduce indentation level by returning early if the transport header +was not set. + +Add an unlikely() clause as this is not the common case. + +No functional change. + +Signed-off-by: Eric Dumazet +Reviewed-by: Joe Damato +Link: https://patch.msgid.link/20260403221540.3297753-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 7fb4c1967011 ("net: pull headers in qdisc_pkt_len_segs_init()") +Signed-off-by: Sasha Levin +--- + net/core/dev.c | 62 +++++++++++++++++++++++++------------------------- + 1 file changed, 31 insertions(+), 31 deletions(-) + +diff --git a/net/core/dev.c b/net/core/dev.c +index 0f45825bbed2f..44a712f777b79 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4106,6 +4106,7 @@ EXPORT_SYMBOL_GPL(validate_xmit_skb_list); + static void qdisc_pkt_len_segs_init(struct sk_buff *skb) + { + struct skb_shared_info *shinfo = skb_shinfo(skb); ++ unsigned int hdr_len; + u16 gso_segs; + + qdisc_skb_cb(skb)->pkt_len = skb->len; +@@ -4119,44 +4120,43 @@ static void qdisc_pkt_len_segs_init(struct sk_buff *skb) + /* To get more precise estimation of bytes sent on wire, + * we add to pkt_len the headers size of all segments + */ +- if (skb_transport_header_was_set(skb)) { +- unsigned int hdr_len; ++ if (unlikely(!skb_transport_header_was_set(skb))) ++ return; + +- /* mac layer + network layer */ +- if (!skb->encapsulation) +- hdr_len = skb_transport_offset(skb); +- else +- hdr_len = skb_inner_transport_offset(skb); ++ /* mac layer + network layer */ ++ if (!skb->encapsulation) ++ hdr_len = skb_transport_offset(skb); ++ else ++ hdr_len = skb_inner_transport_offset(skb); + +- /* + transport layer */ +- if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { +- const struct tcphdr *th; +- struct tcphdr _tcphdr; ++ /* + transport layer */ ++ if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { ++ const struct tcphdr *th; ++ struct tcphdr _tcphdr; + +- th = skb_header_pointer(skb, hdr_len, +- sizeof(_tcphdr), &_tcphdr); +- if (likely(th)) +- hdr_len += __tcp_hdrlen(th); +- } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { +- struct udphdr _udphdr; ++ th = skb_header_pointer(skb, hdr_len, ++ sizeof(_tcphdr), &_tcphdr); ++ if (likely(th)) ++ hdr_len += __tcp_hdrlen(th); ++ } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { ++ struct udphdr _udphdr; + +- if (skb_header_pointer(skb, hdr_len, +- sizeof(_udphdr), &_udphdr)) +- hdr_len += sizeof(struct udphdr); +- } ++ if (skb_header_pointer(skb, hdr_len, ++ sizeof(_udphdr), &_udphdr)) ++ hdr_len += sizeof(struct udphdr); ++ } + +- if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) { +- int payload = skb->len - hdr_len; ++ if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) { ++ int payload = skb->len - hdr_len; + +- /* Malicious packet. */ +- if (payload <= 0) +- return; +- gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size); +- shinfo->gso_segs = gso_segs; +- qdisc_skb_cb(skb)->pkt_segs = gso_segs; +- } +- qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len; ++ /* Malicious packet. */ ++ if (payload <= 0) ++ return; ++ gso_segs = DIV_ROUND_UP(payload, shinfo->gso_size); ++ shinfo->gso_segs = gso_segs; ++ qdisc_skb_cb(skb)->pkt_segs = gso_segs; + } ++ qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len; + } + + static int dev_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *q, +-- +2.53.0 + diff --git a/queue-7.0/net-rds-optimize-rds_ib_laddr_check.patch b/queue-7.0/net-rds-optimize-rds_ib_laddr_check.patch new file mode 100644 index 0000000000..72ba3793fb --- /dev/null +++ b/queue-7.0/net-rds-optimize-rds_ib_laddr_check.patch @@ -0,0 +1,189 @@ +From f23f54dfe3b6c8d33266f1473d7defb5b5d11b2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:19 -0700 +Subject: net/rds: Optimize rds_ib_laddr_check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: HÃ¥kon Bugge + +[ Upstream commit 236f718ac885965fa886440b9898dfae185c9733 ] + +rds_ib_laddr_check() creates a CM_ID and attempts to bind the address +in question to it. This in order to qualify the allegedly local +address as a usable IB/RoCE address. + +In the field, ExaWatcher runs rds-ping to all ports in the fabric from +all local ports. This using all active ToS'es. In a full rack system, +we have 14 cell servers and eight db servers. Typically, 6 ToS'es are +used. This implies 528 rds-ping invocations per ExaWatcher's "RDSinfo" +interval. + +Adding to this, each rds-ping invocation creates eight sockets and +binds the local address to them: + +socket(AF_RDS, SOCK_SEQPACKET, 0) = 3 +bind(3, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 4 +bind(4, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 5 +bind(5, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 6 +bind(6, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 7 +bind(7, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 8 +bind(8, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 9 +bind(9, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 +socket(AF_RDS, SOCK_SEQPACKET, 0) = 10 +bind(10, {sa_family=AF_INET, sin_port=htons(0), + sin_addr=inet_addr("192.168.36.2")}, 16) = 0 + +So, at every interval ExaWatcher executes rds-ping's, 4224 CM_IDs are +allocated, considering this full-rack system. After the a CM_ID has +been allocated, rdma_bind_addr() is called, with the port number being +zero. This implies that the CMA will attempt to search for an un-used +ephemeral port. Simplified, the algorithm is to start at a random +position in the available port space, and then if needed, iterate +until an un-used port is found. + +The book-keeping of used ports uses the idr system, which again uses +slab to allocate new struct idr_layer's. The size is 2092 bytes and +slab tries to reduce the wasted space. Hence, it chooses an order:3 +allocation, for which 15 idr_layer structs will fit and only 1388 +bytes are wasted per the 32KiB order:3 chunk. + +Although this order:3 allocation seems like a good space/speed +trade-off, it does not resonate well with how it used by the CMA. The +combination of the randomized starting point in the port space (which +has close to zero spatial locality) and the close proximity in time of +the 4224 invocations of the rds-ping's, creates a memory hog for +order:3 allocations. + +These costly allocations may need reclaims and/or compaction. At +worst, they may fail and produce a stack trace such as (from uek4): + +[] __inc_zone_page_state+0x35/0x40 +[] page_add_file_rmap+0x57/0x60 +[] remove_migration_pte+0x3f/0x3c0 [ksplice_6cn872bt_vmlinux_new] +[] rmap_walk+0xd8/0x340 +[] remove_migration_ptes+0x40/0x50 +[] migrate_pages+0x3ec/0x890 +[] compact_zone+0x32d/0x9a0 +[] compact_zone_order+0x6d/0x90 +[] try_to_compact_pages+0x102/0x270 +[] __alloc_pages_direct_compact+0x46/0x100 +[] __alloc_pages_nodemask+0x74b/0xaa0 +[] alloc_pages_current+0x91/0x110 +[] new_slab+0x38b/0x480 +[] __slab_alloc+0x3b7/0x4a0 [ksplice_s0dk66a8_vmlinux_new] +[] kmem_cache_alloc+0x1fb/0x250 +[] idr_layer_alloc+0x36/0x90 +[] idr_get_empty_slot+0x28c/0x3d0 +[] idr_alloc+0x4d/0xf0 +[] cma_alloc_port+0x4d/0xa0 [rdma_cm] +[] rdma_bind_addr+0x2ae/0x5b0 [rdma_cm] +[] rds_ib_laddr_check+0x83/0x2c0 [ksplice_6l2xst5i_rds_rdma_new] +[] rds_trans_get_preferred+0x5b/0xa0 [rds] +[] rds_bind+0x212/0x280 [rds] +[] SYSC_bind+0xe6/0x120 +[] SyS_bind+0xe/0x10 +[] system_call_fastpath+0x18/0xd4 + +To avoid these excessive calls to rdma_bind_addr(), we optimize +rds_ib_laddr_check() by simply checking if the address in question has +been used before. The rds_rdma module keeps track of addresses +associated with IB devices, and the function rds_ib_get_device() is +used to determine if the address already has been qualified as a valid +local address. If not found, we call the legacy rds_ib_laddr_check(), +now renamed to rds_ib_laddr_check_cm(). + +Signed-off-by: HÃ¥kon Bugge +Signed-off-by: Somasundaram Krishnasamy +Signed-off-by: Gerd Rausch +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-2-achender@kernel.org +Signed-off-by: Jakub Kicinski +Stable-dep-of: ebf71dd4aff4 ("net/rds: Restrict use of RDS/IB to the initial network namespace") +Signed-off-by: Sasha Levin +--- + net/rds/ib.c | 20 ++++++++++++++++++-- + net/rds/ib.h | 1 + + net/rds/ib_rdma.c | 2 +- + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/net/rds/ib.c b/net/rds/ib.c +index ac6affa33ce75..412ff61e74fac 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -401,8 +401,8 @@ static void rds6_ib_ic_info(struct socket *sock, unsigned int len, + * allowed to influence which paths have priority. We could call userspace + * asserting this policy "routing". + */ +-static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, +- __u32 scope_id) ++static int rds_ib_laddr_check_cm(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) + { + int ret; + struct rdma_cm_id *cm_id; +@@ -487,6 +487,22 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + return ret; + } + ++static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, ++ __u32 scope_id) ++{ ++ struct rds_ib_device *rds_ibdev = NULL; ++ ++ if (ipv6_addr_v4mapped(addr)) { ++ rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); ++ if (rds_ibdev) { ++ rds_ib_dev_put(rds_ibdev); ++ return 0; ++ } ++ } ++ ++ return rds_ib_laddr_check_cm(net, addr, scope_id); ++} ++ + static void rds_ib_unregister_client(void) + { + ib_unregister_client(&rds_ib_client); +diff --git a/net/rds/ib.h b/net/rds/ib.h +index 8ef3178ed4d61..5ff346a1e8baa 100644 +--- a/net/rds/ib.h ++++ b/net/rds/ib.h +@@ -381,6 +381,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, + __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt) + + /* ib_rdma.c */ ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr); + int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, + struct in6_addr *ipaddr); + void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); +diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c +index 2cfec252eeac2..9594ea245f7fe 100644 +--- a/net/rds/ib_rdma.c ++++ b/net/rds/ib_rdma.c +@@ -43,7 +43,7 @@ struct workqueue_struct *rds_ib_mr_wq; + + static void rds_ib_odp_mr_worker(struct work_struct *work); + +-static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) ++struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) + { + struct rds_ib_device *rds_ibdev; + struct rds_ib_ipaddr *i_ipaddr; +-- +2.53.0 + diff --git a/queue-7.0/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch b/queue-7.0/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch new file mode 100644 index 0000000000..e9a7ef1cf1 --- /dev/null +++ b/queue-7.0/net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch @@ -0,0 +1,86 @@ +From d8eb7569e53d993450f43896935b35fbe8a63442 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 01:04:20 -0700 +Subject: net/rds: Restrict use of RDS/IB to the initial network namespace + +From: Greg Jumper + +[ Upstream commit ebf71dd4aff46e8e421d455db3e231ba43d2fa8a ] + +Prevent using RDS/IB in network namespaces other than the initial one. +The existing RDS/IB code will not work properly in non-initial network +namespaces. + +Fixes: d5a8ac28a7ff ("RDS-TCP: Make RDS-TCP work correctly when it is set up in a netns other than init_net") +Reported-by: syzbot+da8e060735ae02c8f3d1@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=da8e060735ae02c8f3d1 +Signed-off-by: Greg Jumper +Signed-off-by: Allison Henderson +Link: https://patch.msgid.link/20260408080420.540032-3-achender@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/af_rds.c | 10 ++++++++-- + net/rds/ib.c | 4 ++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c +index b396c673dfaf6..76f625986a7f2 100644 +--- a/net/rds/af_rds.c ++++ b/net/rds/af_rds.c +@@ -357,7 +357,8 @@ static int rds_cong_monitor(struct rds_sock *rs, sockptr_t optval, int optlen) + return ret; + } + +-static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) ++static int rds_set_transport(struct net *net, struct rds_sock *rs, ++ sockptr_t optval, int optlen) + { + int t_type; + +@@ -373,6 +374,10 @@ static int rds_set_transport(struct rds_sock *rs, sockptr_t optval, int optlen) + if (t_type < 0 || t_type >= RDS_TRANS_COUNT) + return -EINVAL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (t_type != RDS_TRANS_TCP && !net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + rs->rs_transport = rds_trans_get(t_type); + + return rs->rs_transport ? 0 : -ENOPROTOOPT; +@@ -433,6 +438,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + sockptr_t optval, unsigned int optlen) + { + struct rds_sock *rs = rds_sk_to_rs(sock->sk); ++ struct net *net = sock_net(sock->sk); + int ret; + + if (level != SOL_RDS) { +@@ -461,7 +467,7 @@ static int rds_setsockopt(struct socket *sock, int level, int optname, + break; + case SO_RDS_TRANSPORT: + lock_sock(sock->sk); +- ret = rds_set_transport(rs, optval, optlen); ++ ret = rds_set_transport(net, rs, optval, optlen); + release_sock(sock->sk); + break; + case SO_TIMESTAMP_OLD: +diff --git a/net/rds/ib.c b/net/rds/ib.c +index 412ff61e74fac..39f87272e071b 100644 +--- a/net/rds/ib.c ++++ b/net/rds/ib.c +@@ -492,6 +492,10 @@ static int rds_ib_laddr_check(struct net *net, const struct in6_addr *addr, + { + struct rds_ib_device *rds_ibdev = NULL; + ++ /* RDS/IB is restricted to the initial network namespace */ ++ if (!net_eq(net, &init_net)) ++ return -EPROTOTYPE; ++ + if (ipv6_addr_v4mapped(addr)) { + rds_ibdev = rds_ib_get_device(addr->s6_addr32[3]); + if (rds_ibdev) { +-- +2.53.0 + diff --git a/queue-7.0/net-rds-zero-per-item-info-buffer-before-handing-it-.patch b/queue-7.0/net-rds-zero-per-item-info-buffer-before-handing-it-.patch new file mode 100644 index 0000000000..571bcf7a80 --- /dev/null +++ b/queue-7.0/net-rds-zero-per-item-info-buffer-before-handing-it-.patch @@ -0,0 +1,111 @@ +From 13e11df97d5fac2707732b055727f5abcb480956 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Apr 2026 10:10:47 -0400 +Subject: net/rds: zero per-item info buffer before handing it to visitors + +From: Michael Bommarito + +[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ] + +rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a +caller-allocated on-stack u64 buffer to a per-connection visitor and +then copy the full item_len bytes back to user space via +rds_info_copy() regardless of how much of the buffer the visitor +actually wrote. + +rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only +write a subset of their output struct when the underlying +rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl +and the two GIDs via explicit memsets). Several u32 fields +(max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, +cache_allocs) and the 2-byte alignment hole between sl and +cache_allocs remain as whatever stack contents preceded the visitor +call and are then memcpy_to_user()'d out to user space. + +struct rds_info_rdma_connection and struct rds6_info_rdma_connection +are the only rds_info_* structs in include/uapi/linux/rds.h that are +not marked __attribute__((packed)), so they have a real alignment +hole. The other info visitors (rds_conn_info_visitor, +rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of +their packed output struct today and are not known to be vulnerable, +but a future visitor that adds a conditional write-path would have +the same bug. + +Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y: +a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, +binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on +any netdev is sufficient), sendto()'s any peer on the same subnet +(fails cleanly but installs an rds_connection in the global hash in +RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, +RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 +bytes of stack garbage including kernel text/data pointers: + + 0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2 + 8..39 00 ... gids (memset-zeroed) + 40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr) + 48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max) + 56..59 01 00 08 00 rdma_mr_size (garbage) + 60..61 00 00 tos, sl + 62..63 00 00 alignment padding + 64..67 18 00 00 00 cache_allocs (garbage) + +Fix by zeroing the per-item buffer in both rds_for_each_conn_info() +and rds_walk_conn_path_info() before invoking the visitor. This +covers the IPv4/IPv6 IB visitors and hardens all current and future +visitors against the same class of bug. + +No functional change for visitors that fully populate their output. + +Changes in v2: +- retarget at the net tree (subject prefix "[PATCH net v2]", + net/rds: prefix in the title) +- pick up Reviewed-by tags from Sharath Srinivasan and + Allison Henderson + +Fixes: ec16227e1414 ("RDS/IB: Infiniband transport") +Signed-off-by: Michael Bommarito +Reviewed-by: Sharath Srinivasan +Reviewed-by: Allison Henderson +Assisted-by: Claude:claude-opus-4-7 +Link: https://patch.msgid.link/20260418141047.3398203-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/rds/connection.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/net/rds/connection.c b/net/rds/connection.c +index 412441aaa298e..c10b7ed06c49f 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -701,6 +701,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, + i++, head++) { + hlist_for_each_entry_rcu(conn, head, c_hash_node) { + ++ /* Zero the per-item buffer before handing it to the ++ * visitor so any field the visitor does not write - ++ * including implicit alignment padding - cannot leak ++ * stack contents to user space via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no c_lock usage.. */ + if (!visitor(conn, buffer)) + continue; +@@ -750,6 +757,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len, + */ + cp = conn->c_path; + ++ /* Zero the per-item buffer for the same reason as ++ * rds_for_each_conn_info(): any byte the visitor ++ * does not write (including alignment padding) must ++ * not leak stack contents via rds_info_copy(). ++ */ ++ memset(buffer, 0, item_len); ++ + /* XXX no cp_lock usage.. */ + if (!visitor(cp, buffer)) + continue; +-- +2.53.0 + diff --git a/queue-7.0/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch b/queue-7.0/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch new file mode 100644 index 0000000000..16fe6d034b --- /dev/null +++ b/queue-7.0/net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch @@ -0,0 +1,130 @@ +From d96e1ecc6f1e098b66664914a628164de98dbdad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:16:27 -0400 +Subject: net/sched: act_ct: Only release RCU read lock after ct_ft + +From: Jamal Hadi Salim + +[ Upstream commit f462dca0c8415bf0058d0ffa476354c4476d0f09 ] + +When looking up a flow table in act_ct in tcf_ct_flow_table_get(), +rhashtable_lookup_fast() internally opens and closes an RCU read critical +section before returning ct_ft. +The tcf_ct_flow_table_cleanup_work() can complete before refcount_inc_not_zero() +is invoked on the returned ct_ft resulting in a UAF on the already freed ct_ft +object. This vulnerability can lead to privilege escalation. + +Analysis from zdi-disclosures@trendmicro.com: +When initializing act_ct, tcf_ct_init() is called, which internally triggers +tcf_ct_flow_table_get(). + +static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + +{ + struct zones_ht_key key = { .net = net, .zone = params->zone }; + struct tcf_ct_flow_table *ct_ft; + int err = -ENOMEM; + + mutex_lock(&zones_mutex); + ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); // [1] + if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) // [2] + goto out_unlock; + ... +} + +static __always_inline void *rhashtable_lookup_fast( + struct rhashtable *ht, const void *key, + const struct rhashtable_params params) +{ + void *obj; + + rcu_read_lock(); + obj = rhashtable_lookup(ht, key, params); + rcu_read_unlock(); + + return obj; +} + +At [1], rhashtable_lookup_fast() looks up and returns the corresponding ct_ft +from zones_ht . The lookup is performed within an RCU read critical section +through rcu_read_lock() / rcu_read_unlock(), which prevents the object from +being freed. However, at the point of function return, rcu_read_unlock() has +already been called, and there is nothing preventing ct_ft from being freed +before reaching refcount_inc_not_zero(&ct_ft->ref) at [2]. This interval becomes +the race window, during which ct_ft can be freed. + +Free Process: + +tcf_ct_flow_table_put() is executed through the path tcf_ct_cleanup() call_rcu() +tcf_ct_params_free_rcu() tcf_ct_params_free() tcf_ct_flow_table_put(). + +static void tcf_ct_flow_table_put(struct tcf_ct_flow_table *ct_ft) +{ + if (refcount_dec_and_test(&ct_ft->ref)) { + rhashtable_remove_fast(&zones_ht, &ct_ft->node, zones_params); + INIT_RCU_WORK(&ct_ft->rwork, tcf_ct_flow_table_cleanup_work); // [3] + queue_rcu_work(act_ct_wq, &ct_ft->rwork); + } +} + +At [3], tcf_ct_flow_table_cleanup_work() is scheduled as RCU work + +static void tcf_ct_flow_table_cleanup_work(struct work_struct *work) + +{ + struct tcf_ct_flow_table *ct_ft; + struct flow_block *block; + + ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table, + rwork); + nf_flow_table_free(&ct_ft->nf_ft); + block = &ct_ft->nf_ft.flow_block; + down_write(&ct_ft->nf_ft.flow_block_lock); + WARN_ON(!list_empty(&block->cb_list)); + up_write(&ct_ft->nf_ft.flow_block_lock); + kfree(ct_ft); // [4] + + module_put(THIS_MODULE); +} + +tcf_ct_flow_table_cleanup_work() frees ct_ft at [4]. When this function executes +between [1] and [2], UAF occurs. + +This race condition has a very short race window, making it generally +difficult to trigger. Therefore, to trigger the vulnerability an msleep(100) was +inserted after[1] + +Fixes: 138470a9b2cc2 ("net/sched: act_ct: fix lockdep splat in tcf_ct_flow_table_get") +Reported-by: zdi-disclosures@trendmicro.com +Tested-by: Victor Nogueira +Signed-off-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260410111627.46611-1-jhs@mojatatu.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/act_ct.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index 7d5e50c921a07..6158e13c98d35 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -328,9 +328,13 @@ static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params) + int err = -ENOMEM; + + mutex_lock(&zones_mutex); +- ct_ft = rhashtable_lookup_fast(&zones_ht, &key, zones_params); +- if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) ++ rcu_read_lock(); ++ ct_ft = rhashtable_lookup(&zones_ht, &key, zones_params); ++ if (ct_ft && refcount_inc_not_zero(&ct_ft->ref)) { ++ rcu_read_unlock(); + goto out_unlock; ++ } ++ rcu_read_unlock(); + + ct_ft = kzalloc_obj(*ct_ft); + if (!ct_ft) +-- +2.53.0 + diff --git a/queue-7.0/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch b/queue-7.0/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch new file mode 100644 index 0000000000..4e70801866 --- /dev/null +++ b/queue-7.0/net-sched-act_mirred-fix-wrong-device-for-mac_header.patch @@ -0,0 +1,59 @@ +From db4b96e0523ed4a8ad5bcac53f079068f7017554 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 16:49:27 +0800 +Subject: net/sched: act_mirred: fix wrong device for mac_header_xmit check in + tcf_blockcast_redir +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit 4510d140524ca7d6e772db962e013f26f09a63b1 ] + +In tcf_blockcast_redir(), when iterating block ports to redirect +packets to multiple devices, the mac_header_xmit flag is queried +from the wrong device. The loop sends to dev_prev but queries +dev_is_mac_header_xmit(dev) — which is the NEXT device in the +iteration, not the one being sent to. + +This causes tcf_mirred_to_dev() to make incorrect decisions about +whether to push or pull the MAC header. When the block contains +mixed device types (e.g., an ethernet veth and a tunnel device), +intermediate devices get the wrong mac_header_xmit flag, leading to +skb header corruption. In the worst case, skb_push_rcsum with an +incorrect mac_len can exhaust headroom and panic. + +The last device in the loop is handled correctly (line 365-366 uses +dev_is_mac_header_xmit(dev_prev)), confirming this is a copy-paste +oversight for the intermediate devices. + +Fix by using dev_prev instead of dev for the mac_header_xmit query, +consistent with the device actually being sent to. + +Fixes: 42f39036cda8 ("net/sched: act_mirred: Allow mirred to block") +Signed-off-by: Dudu Lu +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260413084927.71353-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/act_mirred.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c +index 05e0b14b57731..2c5a7a321a943 100644 +--- a/net/sched/act_mirred.c ++++ b/net/sched/act_mirred.c +@@ -354,7 +354,7 @@ static int tcf_blockcast_redir(struct sk_buff *skb, struct tcf_mirred *m, + goto assign_prev; + + tcf_mirred_to_dev(skb, m, dev_prev, +- dev_is_mac_header_xmit(dev), ++ dev_is_mac_header_xmit(dev_prev), + mirred_eaction, retval); + assign_prev: + dev_prev = dev; +-- +2.53.0 + diff --git a/queue-7.0/net-sched-cls_flower-revert-unintended-changes.patch b/queue-7.0/net-sched-cls_flower-revert-unintended-changes.patch new file mode 100644 index 0000000000..050bd1dab0 --- /dev/null +++ b/queue-7.0/net-sched-cls_flower-revert-unintended-changes.patch @@ -0,0 +1,55 @@ +From 1e52c8e14a3d301e5c647ed8341348b38be1b78f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:39:11 +0200 +Subject: net/sched: cls_flower: revert unintended changes + +From: Paolo Abeni + +[ Upstream commit 1e01abec856593e02cd69fd95b784c10dd46880c ] + +While applying the blamed commit 4ca07b9239bd ("net: mctp i2c: check +length before marking flow active"), I unintentionally included +unrelated and unacceptable changes. + +Revert them. + +Fixes: 4ca07b9239bd ("net: mctp i2c: check length before marking flow active") +Reported-by: Jeremy Kerr +Closes: https://lore.kernel.org/netdev/bd8704fe0bd53e278add5cde4873256656623e2e.camel@codeconstruct.com.au/ +Signed-off-by: Paolo Abeni +Link: https://patch.msgid.link/043026a53ff84da88b17648c4b0d17f0331749cb.1777447863.git.pabeni@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/cls_flower.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index dd6727691cff5..26070c892305d 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -560,7 +560,6 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + struct netlink_ext_ack *extack) + { + struct cls_fl_head *head = fl_head_dereference(tp); +- struct fl_flow_mask *mask; + + *last = false; + +@@ -577,12 +576,11 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, + list_del_rcu(&f->list); + spin_unlock(&tp->lock); + +- mask = f->mask; ++ *last = fl_mask_put(head, f->mask); + if (!tc_skip_hw(f->flags)) + fl_hw_destroy_filter(tp, f, rtnl_held, extack); + tcf_unbind_filter(tp, &f->res); + __fl_put(f); +- *last = fl_mask_put(head, mask); + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch b/queue-7.0/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch new file mode 100644 index 0000000000..9695c87dda --- /dev/null +++ b/queue-7.0/net-sched-cls_fw-fix-null-dereference-of-old-filters.patch @@ -0,0 +1,122 @@ +From 142890a85e353ad6ade13c7d34f877fda96ec7eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 17:24:36 +0200 +Subject: net/sched: cls_fw: fix NULL dereference of "old" filters before + change() + +From: Davide Caratti + +[ Upstream commit 65782b2db7321d5f97c16718c4c7f6c7205a56be ] + +Like pointed out by Sashiko [1], since commit ed76f5edccc9 ("net: sched: +protect filter_chain list with filter_chain_lock mutex") TC filters are +added to a shared block and published to datapath before their ->change() +function is called. This is a problem for cls_fw: an invalid filter +created with the "old" method can still classify some packets before it +is destroyed by the validation logic added by Xiang. +Therefore, insisting with repeated runs of the following script: + + # ip link add dev crash0 type dummy + # ip link set dev crash0 up + # mausezahn crash0 -c 100000 -P 10 \ + > -A 4.3.2.1 -B 1.2.3.4 -t udp "dp=1234" -q & + # sleep 1 + # tc qdisc add dev crash0 egress_block 1 clsact + # tc filter add block 1 protocol ip prio 1 matchall \ + > action skbedit mark 65536 continue + # tc filter add block 1 protocol ip prio 2 fw + # ip link del dev crash0 + +can still make fw_classify() hit the WARN_ON() in [2]: + + WARNING: ./include/net/pkt_cls.h:88 at fw_classify+0x244/0x250 [cls_fw], CPU#18: mausezahn/1399 + Modules linked in: cls_fw(E) act_skbedit(E) + CPU: 18 UID: 0 PID: 1399 Comm: mausezahn Tainted: G E 7.0.0-rc6-virtme #17 PREEMPT(full) + Tainted: [E]=UNSIGNED_MODULE + Hardware name: Red Hat KVM, BIOS 1.16.3-2.el9 04/01/2014 + RIP: 0010:fw_classify+0x244/0x250 [cls_fw] + Code: 5c 49 c7 45 00 00 00 00 00 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 5b b8 ff ff ff ff 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 90 <0f> 0b 90 eb a0 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90 + RSP: 0018:ffffd1b7026bf8a8 EFLAGS: 00010202 + RAX: ffff8c5ac9c60800 RBX: ffff8c5ac99322c0 RCX: 0000000000000004 + RDX: 0000000000000001 RSI: ffff8c5b74d7a000 RDI: ffff8c5ac8284f40 + RBP: ffffd1b7026bf8d0 R08: 0000000000000000 R09: ffffd1b7026bf9b0 + R10: 00000000ffffffff R11: 0000000000000000 R12: 0000000000010000 + R13: ffffd1b7026bf930 R14: ffff8c5ac8284f40 R15: 0000000000000000 + FS: 00007fca40c37740(0000) GS:ffff8c5b74d7a000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007fca40e822a0 CR3: 0000000005ca0001 CR4: 0000000000172ef0 + Call Trace: + + tcf_classify+0x17d/0x5c0 + tc_run+0x9d/0x150 + __dev_queue_xmit+0x2ab/0x14d0 + ip_finish_output2+0x340/0x8f0 + ip_output+0xa4/0x250 + raw_sendmsg+0x147d/0x14b0 + __sys_sendto+0x1cc/0x1f0 + __x64_sys_sendto+0x24/0x30 + do_syscall_64+0x126/0xf80 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7fca40e822ba + Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89 + RSP: 002b:00007ffc248a42c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c + RAX: ffffffffffffffda RBX: 000055ef233289d0 RCX: 00007fca40e822ba + RDX: 000000000000001e RSI: 000055ef23328c30 RDI: 0000000000000003 + RBP: 000055ef233289d0 R08: 00007ffc248a42d0 R09: 0000000000000010 + R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000001e + R13: 00000000000186a0 R14: 0000000000000000 R15: 00007fca41043000 + + irq event stamp: 1045778 + hardirqs last enabled at (1045784): [] __up_console_sem+0x52/0x60 + hardirqs last disabled at (1045789): [] __up_console_sem+0x37/0x60 + softirqs last enabled at (1045426): [] __alloc_skb+0x207/0x260 + softirqs last disabled at (1045434): [] __dev_queue_xmit+0x78/0x14d0 + +Then, because of the value in the packet's mark, dereference on 'q->handle' +with NULL 'q' occurs: + + BUG: kernel NULL pointer dereference, address: 0000000000000038 + [...] + RIP: 0010:fw_classify+0x1fe/0x250 [cls_fw] + [...] + +Skip "old-style" classification on shared blocks, so that the NULL +dereference is fixed and WARN_ON() is not hit anymore in the short +lifetime of invalid cls_fw "old-style" filters. + +[1] https://sashiko.dev/#/patchset/20260331050217.504278-1-xmei5%40asu.edu +[2] https://elixir.bootlin.com/linux/v7.0-rc6/source/include/net/pkt_cls.h#L86 + +Fixes: faeea8bbf6e9 ("net/sched: cls_fw: fix NULL pointer dereference on shared blocks") +Fixes: ed76f5edccc9 ("net: sched: protect filter_chain list with filter_chain_lock mutex") +Acked-by: Jamal Hadi Salim +Signed-off-by: Davide Caratti +Link: https://patch.msgid.link/e39cbd3103a337f1e515d186fe697b4459d24757.1775661704.git.dcaratti@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/cls_fw.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c +index 23884ef8b80ce..646a730dca93c 100644 +--- a/net/sched/cls_fw.c ++++ b/net/sched/cls_fw.c +@@ -74,9 +74,13 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb, + } + } + } else { +- struct Qdisc *q = tcf_block_q(tp->chain->block); ++ struct Qdisc *q; + + /* Old method: classify the packet using its skb mark. */ ++ if (tcf_block_shared(tp->chain->block)) ++ return -1; ++ ++ q = tcf_block_q(tp->chain->block); + if (id && (TC_H_MAJ(id) == 0 || + !(TC_H_MAJ(id ^ q->handle)))) { + res->classid = id; +-- +2.53.0 + diff --git a/queue-7.0/net-sched-netem-check-for-negative-latency-and-jitte.patch b/queue-7.0/net-sched-netem-check-for-negative-latency-and-jitte.patch new file mode 100644 index 0000000000..1063e35e94 --- /dev/null +++ b/queue-7.0/net-sched-netem-check-for-negative-latency-and-jitte.patch @@ -0,0 +1,73 @@ +From ee356fb0da99a8cbb9561e0769f816772761dba6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:44 -0700 +Subject: net/sched: netem: check for negative latency and jitter + +From: Stephen Hemminger + +[ Upstream commit 90be9fedb218ee95a1cf59050d1306fbfb0e8b87 ] + +Reject requests with negative latency or jitter. +A negative value added to current timestamp (u64) wraps +to an enormous time_to_send, disabling dequeue. +The original UAPI used u32 for these values; the conversion to 64-bit +time values via TCA_NETEM_LATENCY64 and TCA_NETEM_JITTER64 +allowed signed values to reach the kernel without validation. + +Jitter is already silently clamped by an abs() in netem_change(); +that abs() can be removed in a follow-up once this rejection is in +place. + +Fixes: 99803171ef04 ("netem: add uapi to express delay and jitter in nanoseconds") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-7-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 475c14b3dbdbf..bc18e1976b6e0 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -826,6 +826,16 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_time(const struct nlattr *attr, const char *name, ++ struct netlink_ext_ack *extack) ++{ ++ if (nla_get_s64(attr) < 0) { ++ NL_SET_ERR_MSG_ATTR_FMT(extack, attr, "negative %s", name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1068,6 +1078,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_LATENCY64]) { ++ ret = validate_time(tb[TCA_NETEM_LATENCY64], "latency", extack); ++ if (ret) ++ goto table_free; ++ } ++ ++ if (tb[TCA_NETEM_JITTER64]) { ++ ret = validate_time(tb[TCA_NETEM_JITTER64], "jitter", extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-7.0/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch b/queue-7.0/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch new file mode 100644 index 0000000000..04678a03f1 --- /dev/null +++ b/queue-7.0/net-sched-netem-fix-probability-gaps-in-4-state-loss.patch @@ -0,0 +1,67 @@ +From 61042c2d6464577bab25a75e3bac390c17b41c68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:39 -0700 +Subject: net/sched: netem: fix probability gaps in 4-state loss model + +From: Stephen Hemminger + +[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ] + +The 4-state Markov chain in loss_4state() has gaps at the boundaries +between transition probability ranges. The comparisons use: + + if (rnd < a4) + else if (a4 < rnd && rnd < a1 + a4) + +When rnd equals a boundary value exactly, neither branch matches and +no state transition occurs. The redundant lower-bound check (a4 < rnd) +is already implied by being in the else branch. + +Remove the unnecessary lower-bound comparisons so the ranges are +contiguous and every random value produces a transition, matching +the GI (General and Intuitive) loss model specification. + +This bug goes back to original implementation of this model. + +Fixes: 661b79725fea ("netem: revised correlated loss generator") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-2-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 20df1c08b1e9d..8ee72cac1faf0 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -227,10 +227,10 @@ static bool loss_4state(struct netem_sched_data *q) + if (rnd < clg->a4) { + clg->state = LOST_IN_GAP_PERIOD; + return true; +- } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { ++ } else if (rnd < clg->a1 + clg->a4) { + clg->state = LOST_IN_BURST_PERIOD; + return true; +- } else if (clg->a1 + clg->a4 < rnd) { ++ } else { + clg->state = TX_IN_GAP_PERIOD; + } + +@@ -247,9 +247,9 @@ static bool loss_4state(struct netem_sched_data *q) + case LOST_IN_BURST_PERIOD: + if (rnd < clg->a3) + clg->state = TX_IN_BURST_PERIOD; +- else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { ++ else if (rnd < clg->a2 + clg->a3) { + clg->state = TX_IN_GAP_PERIOD; +- } else if (clg->a2 + clg->a3 < rnd) { ++ } else { + clg->state = LOST_IN_BURST_PERIOD; + return true; + } +-- +2.53.0 + diff --git a/queue-7.0/net-sched-netem-fix-queue-limit-check-to-include-reo.patch b/queue-7.0/net-sched-netem-fix-queue-limit-check-to-include-reo.patch new file mode 100644 index 0000000000..072a283bfb --- /dev/null +++ b/queue-7.0/net-sched-netem-fix-queue-limit-check-to-include-reo.patch @@ -0,0 +1,42 @@ +From 4038c74e697278898b82e01d042e379a437fb43d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:40 -0700 +Subject: net/sched: netem: fix queue limit check to include reordered packets + +From: Stephen Hemminger + +[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ] + +The queue limit check in netem_enqueue() uses q->t_len which only +counts packets in the internal tfifo. Packets placed in sch->q by +the reorder path (__qdisc_enqueue_head) are not counted, allowing +the total queue occupancy to exceed sch->limit under reordering. + +Include sch->q.qlen in the limit check. + +Fixes: f8d4bc455047 ("net/sched: netem: account for backlog updates from child qdisc") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-3-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 8ee72cac1faf0..d400a730eadd1 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -524,7 +524,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, + 1 << get_random_u32_below(8); + } + +- if (unlikely(q->t_len >= sch->limit)) { ++ if (unlikely(sch->q.qlen >= sch->limit)) { + /* re-link segs, so that qdisc_drop_all() frees them all */ + skb->next = segs; + qdisc_drop_all(skb, sch, to_free); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-netem-fix-slot-delay-calculation-overflow.patch b/queue-7.0/net-sched-netem-fix-slot-delay-calculation-overflow.patch new file mode 100644 index 0000000000..0f5a421294 --- /dev/null +++ b/queue-7.0/net-sched-netem-fix-slot-delay-calculation-overflow.patch @@ -0,0 +1,51 @@ +From ece3c4cf511946e1b936e746ba5acf80e7b2da95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:43 -0700 +Subject: net/sched: netem: fix slot delay calculation overflow + +From: Stephen Hemminger + +[ Upstream commit 51e94e1e2fef351c74d69eb53666df808d26af95 ] + +get_slot_next() computes a random delay between min_delay and +max_delay using: + + get_random_u32() * (max_delay - min_delay) >> 32 + +This overflows signed 64-bit arithmetic when the delay range exceeds +approximately 2.1 seconds (2^31 nanoseconds), producing a negative +result that effectively disables slot-based pacing. This is a +realistic configuration for WAN emulation (e.g., slot 1s 5s). + +Use mul_u64_u32_shr() which handles the widening multiply without +overflow. + +Fixes: 0a9fe5c375b5 ("netem: slotting with non-uniform distribution") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-6-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 640b51be807aa..475c14b3dbdbf 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -659,9 +659,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now) + + if (!q->slot_dist) + next_delay = q->slot_config.min_delay + +- (get_random_u32() * +- (q->slot_config.max_delay - +- q->slot_config.min_delay) >> 32); ++ mul_u64_u32_shr(q->slot_config.max_delay - q->slot_config.min_delay, ++ get_random_u32(), 32); + else + next_delay = tabledist(q->slot_config.dist_delay, + (s32)(q->slot_config.dist_jitter), +-- +2.53.0 + diff --git a/queue-7.0/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch b/queue-7.0/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch new file mode 100644 index 0000000000..4a89d30329 --- /dev/null +++ b/queue-7.0/net-sched-netem-only-reseed-prng-when-seed-is-explic.patch @@ -0,0 +1,60 @@ +From b466c579970a877d5b6417c1712c01f78367df66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:41 -0700 +Subject: net/sched: netem: only reseed PRNG when seed is explicitly provided + +From: Stephen Hemminger + +[ Upstream commit 986afaf809940577224a99c3a08d97a15eb37e93 ] + +netem_change() unconditionally reseeds the PRNG on every tc change +command. If TCA_NETEM_PRNG_SEED is not specified, a new random seed +is generated, destroying reproducibility for users who set a +deterministic seed on a previous change. + +Move the initial random seed generation to netem_init() and only +reseed in netem_change() when TCA_NETEM_PRNG_SEED is explicitly +provided by the user. + +Fixes: 4072d97ddc44 ("netem: add prng attribute to netem_sched_data") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-4-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index d400a730eadd1..556f9747f0e73 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -1112,11 +1112,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + /* capping jitter to the range acceptable by tabledist() */ + q->jitter = min_t(s64, abs(q->jitter), INT_MAX); + +- if (tb[TCA_NETEM_PRNG_SEED]) ++ if (tb[TCA_NETEM_PRNG_SEED]) { + q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]); +- else +- q->prng.seed = get_random_u64(); +- prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ } + + unlock: + sch_tree_unlock(sch); +@@ -1139,6 +1138,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt, + return -EINVAL; + + q->loss_model = CLG_RANDOM; ++ q->prng.seed = get_random_u64(); ++ prandom_seed_state(&q->prng.prng_state, q->prng.seed); ++ + ret = netem_change(sch, opt, extack); + if (ret) + pr_info("netem: change failed\n"); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-netem-validate-slot-configuration.patch b/queue-7.0/net-sched-netem-validate-slot-configuration.patch new file mode 100644 index 0000000000..bd0647f1f9 --- /dev/null +++ b/queue-7.0/net-sched-netem-validate-slot-configuration.patch @@ -0,0 +1,86 @@ +From fc1dfe2034099c62e1cc46599381f70656e9e76a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:19:42 -0700 +Subject: net/sched: netem: validate slot configuration + +From: Stephen Hemminger + +[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ] + +Reject slot configurations that have no defensible meaning: + + - negative min_delay or max_delay + - min_delay greater than max_delay + - negative dist_delay or dist_jitter + - negative max_packets or max_bytes + +Negative or out-of-order delays underflow in get_slot_next(), +producing garbage intervals. Negative limits trip the per-slot +accounting (packets_left/bytes_left <= 0) on the first packet of +every slot, defeating the rate-limiting half of the slot feature. + +Note that dist_jitter has been silently coerced to its absolute +value by get_slot() since the feature was introduced; rejecting +negatives here converts that silent coercion into -EINVAL. The +abs() can be removed in a follow-up. + +Fixes: 836af83b54e3 ("netem: support delivering packets in delayed time slots") +Signed-off-by: Stephen Hemminger +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260418032027.900913-5-stephen@networkplumber.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c +index 556f9747f0e73..640b51be807aa 100644 +--- a/net/sched/sch_netem.c ++++ b/net/sched/sch_netem.c +@@ -827,6 +827,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) + return 0; + } + ++static int validate_slot(const struct nlattr *attr, struct netlink_ext_ack *extack) ++{ ++ const struct tc_netem_slot *c = nla_data(attr); ++ ++ if (c->min_delay < 0 || c->max_delay < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot delay"); ++ return -EINVAL; ++ } ++ if (c->min_delay > c->max_delay) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "slot min delay greater than max delay"); ++ return -EINVAL; ++ } ++ if (c->dist_delay < 0 || c->dist_jitter < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative dist delay"); ++ return -EINVAL; ++ } ++ if (c->max_packets < 0 || c->max_bytes < 0) { ++ NL_SET_ERR_MSG_ATTR(extack, attr, "negative slot limit"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static void get_slot(struct netem_sched_data *q, const struct nlattr *attr) + { + const struct tc_netem_slot *c = nla_data(attr); +@@ -1040,6 +1063,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, + goto table_free; + } + ++ if (tb[TCA_NETEM_SLOT]) { ++ ret = validate_slot(tb[TCA_NETEM_SLOT], extack); ++ if (ret) ++ goto table_free; ++ } ++ + sch_tree_lock(sch); + /* backup q->clg and q->loss_model */ + old_clg = q->clg; +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch new file mode 100644 index 0000000000..491bb35317 --- /dev/null +++ b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch @@ -0,0 +1,156 @@ +From b23dfe01f0d68e70982ed60575746532abbaad77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:02 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (I) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit 44967ac3785ebef6442377708925181d4a0eb1c8 ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this first patch, I add READ_ONCE()/WRITE_ONCE() annotations +for the following fields: + +- way_hits +- way_misses +- way_collisions +- sparse_flow_count +- decaying_flow_count + +Other annotations are added in following patches, to ease code review. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 42 +++++++++++++++++++++--------------------- + 1 file changed, 21 insertions(+), 21 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 4ac6c36ca6e41..ac82fe7aafcb3 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -813,7 +813,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb, + i++, k = (k + 1) % CAKE_SET_WAYS) { + if (q->tags[outer_hash + k] == flow_hash) { + if (i) +- q->way_hits++; ++ WRITE_ONCE(q->way_hits, q->way_hits + 1); + + if (!q->flows[outer_hash + k].set) { + /* need to increment host refcnts */ +@@ -831,7 +831,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb, + for (i = 0; i < CAKE_SET_WAYS; + i++, k = (k + 1) % CAKE_SET_WAYS) { + if (!q->flows[outer_hash + k].set) { +- q->way_misses++; ++ WRITE_ONCE(q->way_misses, q->way_misses + 1); + allocate_src = cake_dsrc(flow_mode); + allocate_dst = cake_ddst(flow_mode); + goto found; +@@ -841,7 +841,7 @@ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb, + /* With no empty queues, default to the original + * queue, accept the collision, update the host tags. + */ +- q->way_collisions++; ++ WRITE_ONCE(q->way_collisions, q->way_collisions + 1); + allocate_src = cake_dsrc(flow_mode); + allocate_dst = cake_ddst(flow_mode); + +@@ -1917,11 +1917,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + if (!flow->set) { + list_add_tail(&flow->flowchain, &b->new_flows); + } else { +- b->decaying_flow_count--; ++ WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count - 1); + list_move_tail(&flow->flowchain, &b->new_flows); + } + flow->set = CAKE_SET_SPARSE; +- b->sparse_flow_count++; ++ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count + 1); + + flow->deficit = cake_get_flow_quantum(b, flow, q->config->flow_mode); + } else if (flow->set == CAKE_SET_SPARSE_WAIT) { +@@ -1929,7 +1929,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + * in the bulk rotation. + */ + flow->set = CAKE_SET_BULK; +- b->sparse_flow_count--; ++ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); + b->bulk_flow_count++; + + cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); +@@ -2149,7 +2149,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + */ + if (flow->set == CAKE_SET_SPARSE) { + if (flow->head) { +- b->sparse_flow_count--; ++ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); + b->bulk_flow_count++; + + cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); +@@ -2192,27 +2192,27 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); + cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); + +- b->decaying_flow_count++; ++ WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count + 1); + } else if (flow->set == CAKE_SET_SPARSE || + flow->set == CAKE_SET_SPARSE_WAIT) { +- b->sparse_flow_count--; +- b->decaying_flow_count++; ++ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); ++ WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count + 1); + } + flow->set = CAKE_SET_DECAYING; + } else { + /* remove empty queue from the flowchain */ + list_del_init(&flow->flowchain); + if (flow->set == CAKE_SET_SPARSE || +- flow->set == CAKE_SET_SPARSE_WAIT) +- b->sparse_flow_count--; +- else if (flow->set == CAKE_SET_BULK) { ++ flow->set == CAKE_SET_SPARSE_WAIT) { ++ WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); ++ } else if (flow->set == CAKE_SET_BULK) { + b->bulk_flow_count--; + + cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); + cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); +- } else +- b->decaying_flow_count--; +- ++ } else { ++ WRITE_ONCE(b->decaying_flow_count, b->decaying_flow_count - 1); ++ } + flow->set = CAKE_SET_NONE; + } + goto begin; +@@ -3050,12 +3050,12 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(BASE_DELAY_US, + ktime_to_us(ns_to_ktime(b->base_delay))); + +- PUT_TSTAT_U32(WAY_INDIRECT_HITS, b->way_hits); +- PUT_TSTAT_U32(WAY_MISSES, b->way_misses); +- PUT_TSTAT_U32(WAY_COLLISIONS, b->way_collisions); ++ PUT_TSTAT_U32(WAY_INDIRECT_HITS, READ_ONCE(b->way_hits)); ++ PUT_TSTAT_U32(WAY_MISSES, READ_ONCE(b->way_misses)); ++ PUT_TSTAT_U32(WAY_COLLISIONS, READ_ONCE(b->way_collisions)); + +- PUT_TSTAT_U32(SPARSE_FLOWS, b->sparse_flow_count + +- b->decaying_flow_count); ++ PUT_TSTAT_U32(SPARSE_FLOWS, READ_ONCE(b->sparse_flow_count) + ++ READ_ONCE(b->decaying_flow_count)); + PUT_TSTAT_U32(BULK_FLOWS, b->bulk_flow_count); + PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, b->unresponsive_flow_count); + PUT_TSTAT_U32(MAX_SKBLEN, b->max_skblen); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-1493 b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-1493 new file mode 100644 index 0000000000..5d66a38b92 --- /dev/null +++ b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-1493 @@ -0,0 +1,147 @@ +From 8c7adf84663f4b50493d137fffc665d6e1641027 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:03 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (II) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit 91a96427b93b9ba27413077b7e825d2fefbfa134 ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this second patch, I add READ_ONCE()/WRITE_ONCE() annotations +for the following fields: + +- bulk_flow_count +- unresponsive_flow_count +- max_skblen +- flow_quantum + +Other annotations are added in following patches, to ease code review. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 34 +++++++++++++++++++--------------- + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index ac82fe7aafcb3..a164464f63d18 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -1590,7 +1590,8 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) + } + + if (cobalt_queue_full(&flow->cvars, &b->cparams, now)) +- b->unresponsive_flow_count++; ++ WRITE_ONCE(b->unresponsive_flow_count, ++ b->unresponsive_flow_count + 1); + + len = qdisc_pkt_len(skb); + q->buffer_used -= skb->truesize; +@@ -1795,7 +1796,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + + if (unlikely(len > b->max_skblen)) +- b->max_skblen = len; ++ WRITE_ONCE(b->max_skblen, len); + + if (qdisc_pkt_segs(skb) > 1 && q->config->rate_flags & CAKE_FLAG_SPLIT_GSO) { + struct sk_buff *segs, *nskb; +@@ -1930,7 +1931,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + */ + flow->set = CAKE_SET_BULK; + WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); +- b->bulk_flow_count++; ++ WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count + 1); + + cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); + cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); +@@ -2150,7 +2151,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + if (flow->set == CAKE_SET_SPARSE) { + if (flow->head) { + WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); +- b->bulk_flow_count++; ++ WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count + 1); + + cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode); + cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); +@@ -2177,7 +2178,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + if (!skb) { + /* this queue was actually empty */ + if (cobalt_queue_empty(&flow->cvars, &b->cparams, now)) +- b->unresponsive_flow_count--; ++ WRITE_ONCE(b->unresponsive_flow_count, ++ b->unresponsive_flow_count - 1); + + if (flow->cvars.p_drop || flow->cvars.count || + ktime_before(now, flow->cvars.drop_next)) { +@@ -2187,7 +2189,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + list_move_tail(&flow->flowchain, + &b->decaying_flows); + if (flow->set == CAKE_SET_BULK) { +- b->bulk_flow_count--; ++ WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count - 1); + + cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); + cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); +@@ -2206,7 +2208,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + flow->set == CAKE_SET_SPARSE_WAIT) { + WRITE_ONCE(b->sparse_flow_count, b->sparse_flow_count - 1); + } else if (flow->set == CAKE_SET_BULK) { +- b->bulk_flow_count--; ++ WRITE_ONCE(b->bulk_flow_count, b->bulk_flow_count - 1); + + cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode); + cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode); +@@ -2329,9 +2331,9 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + u8 rate_shft = 0; + u64 rate_ns = 0; + +- b->flow_quantum = 1514; + if (rate) { +- b->flow_quantum = max(min(rate >> 12, 1514ULL), 300ULL); ++ WRITE_ONCE(b->flow_quantum, ++ max(min(rate >> 12, 1514ULL), 300ULL)); + rate_shft = 34; + rate_ns = ((u64)NSEC_PER_SEC) << rate_shft; + rate_ns = div64_u64(rate_ns, max(MIN_RATE, rate)); +@@ -2339,8 +2341,10 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + rate_ns >>= 1; + rate_shft--; + } +- } /* else unlimited, ie. zero delay */ +- ++ } else { ++ /* else unlimited, ie. zero delay */ ++ WRITE_ONCE(b->flow_quantum, 1514); ++ } + b->tin_rate_bps = rate; + b->tin_rate_ns = rate_ns; + b->tin_rate_shft = rate_shft; +@@ -3056,11 +3060,11 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + + PUT_TSTAT_U32(SPARSE_FLOWS, READ_ONCE(b->sparse_flow_count) + + READ_ONCE(b->decaying_flow_count)); +- PUT_TSTAT_U32(BULK_FLOWS, b->bulk_flow_count); +- PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, b->unresponsive_flow_count); +- PUT_TSTAT_U32(MAX_SKBLEN, b->max_skblen); ++ PUT_TSTAT_U32(BULK_FLOWS, READ_ONCE(b->bulk_flow_count)); ++ PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, READ_ONCE(b->unresponsive_flow_count)); ++ PUT_TSTAT_U32(MAX_SKBLEN, READ_ONCE(b->max_skblen)); + +- PUT_TSTAT_U32(FLOW_QUANTUM, b->flow_quantum); ++ PUT_TSTAT_U32(FLOW_QUANTUM, READ_ONCE(b->flow_quantum)); + nla_nest_end(d->skb, ts); + } + +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-21178 b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-21178 new file mode 100644 index 0000000000..3a9f1d28e9 --- /dev/null +++ b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-21178 @@ -0,0 +1,279 @@ +From 77de8fec0408f545cb13fc3ac1e97b03242cd3e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:05 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (IV) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit 8fab48d87745a6ab1cec594b8d5865d9ae2db879 ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this fourth patch, I add READ_ONCE()/WRITE_ONCE() annotations +for the following fields: + +- avg_peak_bandwidth +- buffer_limit +- buffer_max_used +- avg_netoff +- max_netlen +- max_adjlen +- min_netlen +- min_adjlen +- active_queues +- tin_rate_bps +- bytes +- tin_backlog + +Other annotations are added in following patch, to ease code review. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260427083606.459355-5-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 90 ++++++++++++++++++++++---------------------- + 1 file changed, 46 insertions(+), 44 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 3605f32ebf813..804e8f4c46f32 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -1379,9 +1379,9 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off) + len -= off; + + if (qd->max_netlen < len) +- qd->max_netlen = len; ++ WRITE_ONCE(qd->max_netlen, len); + if (qd->min_netlen > len) +- qd->min_netlen = len; ++ WRITE_ONCE(qd->min_netlen, len); + + len += q->rate_overhead; + +@@ -1401,9 +1401,9 @@ static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off) + } + + if (qd->max_adjlen < len) +- qd->max_adjlen = len; ++ WRITE_ONCE(qd->max_adjlen, len); + if (qd->min_adjlen > len) +- qd->min_adjlen = len; ++ WRITE_ONCE(qd->min_adjlen, len); + + return len; + } +@@ -1416,7 +1416,7 @@ static u32 cake_overhead(struct cake_sched_data *q, const struct sk_buff *skb) + u16 segs = qdisc_pkt_segs(skb); + u32 len = qdisc_pkt_len(skb); + +- q->avg_netoff = cake_ewma(q->avg_netoff, off << 16, 8); ++ WRITE_ONCE(q->avg_netoff, cake_ewma(q->avg_netoff, off << 16, 8)); + + if (segs == 1) + return cake_calc_overhead(q, len, off); +@@ -1596,7 +1596,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) + len = qdisc_pkt_len(skb); + q->buffer_used -= skb->truesize; + b->backlogs[idx] -= len; +- b->tin_backlog -= len; ++ WRITE_ONCE(b->tin_backlog, b->tin_backlog - len); + sch->qstats.backlog -= len; + + flow->dropped++; +@@ -1824,11 +1824,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + + /* stats */ +- b->bytes += slen; + b->backlogs[idx] += slen; +- b->tin_backlog += slen; + sch->qstats.backlog += slen; + q->avg_window_bytes += slen; ++ WRITE_ONCE(b->bytes, b->bytes + slen); ++ WRITE_ONCE(b->tin_backlog, b->tin_backlog + slen); + + qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); + consume_skb(skb); +@@ -1847,7 +1847,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + WRITE_ONCE(b->ack_drops, b->ack_drops + 1); + sch->qstats.drops++; + ack_pkt_len = qdisc_pkt_len(ack); +- b->bytes += ack_pkt_len; ++ WRITE_ONCE(b->bytes, b->bytes + ack_pkt_len); + q->buffer_used += skb->truesize - ack->truesize; + if (q->config->rate_flags & CAKE_FLAG_INGRESS) + cake_advance_shaper(q, b, ack, now, true); +@@ -1861,11 +1861,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + /* stats */ + WRITE_ONCE(b->packets, b->packets + 1); +- b->bytes += len - ack_pkt_len; + b->backlogs[idx] += len - ack_pkt_len; +- b->tin_backlog += len - ack_pkt_len; + sch->qstats.backlog += len - ack_pkt_len; + q->avg_window_bytes += len - ack_pkt_len; ++ WRITE_ONCE(b->bytes, b->bytes + len - ack_pkt_len); ++ WRITE_ONCE(b->tin_backlog, b->tin_backlog + len - ack_pkt_len); + } + + if (q->overflow_timeout) +@@ -1895,9 +1895,9 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + u64 b = q->avg_window_bytes * (u64)NSEC_PER_SEC; + + b = div64_u64(b, window_interval); +- q->avg_peak_bandwidth = +- cake_ewma(q->avg_peak_bandwidth, b, +- b > q->avg_peak_bandwidth ? 2 : 8); ++ WRITE_ONCE(q->avg_peak_bandwidth, ++ cake_ewma(q->avg_peak_bandwidth, b, ++ b > q->avg_peak_bandwidth ? 2 : 8)); + q->avg_window_bytes = 0; + q->avg_window_begin = now; + +@@ -1938,7 +1938,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + + if (q->buffer_used > q->buffer_max_used) +- q->buffer_max_used = q->buffer_used; ++ WRITE_ONCE(q->buffer_max_used, q->buffer_used); + + if (q->buffer_used <= q->buffer_limit) + return NET_XMIT_SUCCESS; +@@ -1978,7 +1978,7 @@ static struct sk_buff *cake_dequeue_one(struct Qdisc *sch) + skb = dequeue_head(flow); + len = qdisc_pkt_len(skb); + b->backlogs[q->cur_flow] -= len; +- b->tin_backlog -= len; ++ WRITE_ONCE(b->tin_backlog, b->tin_backlog - len); + sch->qstats.backlog -= len; + q->buffer_used -= skb->truesize; + sch->q.qlen--; +@@ -2043,7 +2043,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + + cake_configure_rates(sch, new_rate, true); + q->last_checked_active = now; +- q->active_queues = num_active_qs; ++ WRITE_ONCE(q->active_queues, num_active_qs); + } + + begin: +@@ -2347,7 +2347,7 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + /* else unlimited, ie. zero delay */ + WRITE_ONCE(b->flow_quantum, 1514); + } +- b->tin_rate_bps = rate; ++ WRITE_ONCE(b->tin_rate_bps, rate); + b->tin_rate_ns = rate_ns; + b->tin_rate_shft = rate_shft; + +@@ -2617,25 +2617,27 @@ static void cake_reconfigure(struct Qdisc *sch) + { + struct cake_sched_data *qd = qdisc_priv(sch); + struct cake_sched_config *q = qd->config; ++ u32 buffer_limit; + + cake_configure_rates(sch, qd->config->rate_bps, false); + + if (q->buffer_config_limit) { +- qd->buffer_limit = q->buffer_config_limit; ++ buffer_limit = q->buffer_config_limit; + } else if (q->rate_bps) { + u64 t = q->rate_bps * q->interval; + + do_div(t, USEC_PER_SEC / 4); +- qd->buffer_limit = max_t(u32, t, 4U << 20); ++ buffer_limit = max_t(u32, t, 4U << 20); + } else { +- qd->buffer_limit = ~0; ++ buffer_limit = ~0; + } + + sch->flags &= ~TCQ_F_CAN_BYPASS; + +- qd->buffer_limit = min(qd->buffer_limit, +- max(sch->limit * psched_mtu(qdisc_dev(sch)), +- q->buffer_config_limit)); ++ WRITE_ONCE(qd->buffer_limit, ++ min(buffer_limit, ++ max(sch->limit * psched_mtu(qdisc_dev(sch)), ++ q->buffer_config_limit))); + } + + static int cake_config_change(struct cake_sched_config *q, struct nlattr *opt, +@@ -2780,10 +2782,10 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt, + return ret; + + if (overhead_changed) { +- qd->max_netlen = 0; +- qd->max_adjlen = 0; +- qd->min_netlen = ~0; +- qd->min_adjlen = ~0; ++ WRITE_ONCE(qd->max_netlen, 0); ++ WRITE_ONCE(qd->max_adjlen, 0); ++ WRITE_ONCE(qd->min_netlen, ~0); ++ WRITE_ONCE(qd->min_adjlen, ~0); + } + + if (qd->tins) { +@@ -3001,15 +3003,15 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + goto nla_put_failure; \ + } while (0) + +- PUT_STAT_U64(CAPACITY_ESTIMATE64, q->avg_peak_bandwidth); +- PUT_STAT_U32(MEMORY_LIMIT, q->buffer_limit); +- PUT_STAT_U32(MEMORY_USED, q->buffer_max_used); +- PUT_STAT_U32(AVG_NETOFF, ((q->avg_netoff + 0x8000) >> 16)); +- PUT_STAT_U32(MAX_NETLEN, q->max_netlen); +- PUT_STAT_U32(MAX_ADJLEN, q->max_adjlen); +- PUT_STAT_U32(MIN_NETLEN, q->min_netlen); +- PUT_STAT_U32(MIN_ADJLEN, q->min_adjlen); +- PUT_STAT_U32(ACTIVE_QUEUES, q->active_queues); ++ PUT_STAT_U64(CAPACITY_ESTIMATE64, READ_ONCE(q->avg_peak_bandwidth)); ++ PUT_STAT_U32(MEMORY_LIMIT, READ_ONCE(q->buffer_limit)); ++ PUT_STAT_U32(MEMORY_USED, READ_ONCE(q->buffer_max_used)); ++ PUT_STAT_U32(AVG_NETOFF, ((READ_ONCE(q->avg_netoff) + 0x8000) >> 16)); ++ PUT_STAT_U32(MAX_NETLEN, READ_ONCE(q->max_netlen)); ++ PUT_STAT_U32(MAX_ADJLEN, READ_ONCE(q->max_adjlen)); ++ PUT_STAT_U32(MIN_NETLEN, READ_ONCE(q->min_netlen)); ++ PUT_STAT_U32(MIN_ADJLEN, READ_ONCE(q->min_adjlen)); ++ PUT_STAT_U32(ACTIVE_QUEUES, READ_ONCE(q->active_queues)); + + #undef PUT_STAT_U32 + #undef PUT_STAT_U64 +@@ -3035,9 +3037,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + if (!ts) + goto nla_put_failure; + +- PUT_TSTAT_U64(THRESHOLD_RATE64, b->tin_rate_bps); +- PUT_TSTAT_U64(SENT_BYTES64, b->bytes); +- PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); ++ PUT_TSTAT_U64(THRESHOLD_RATE64, READ_ONCE(b->tin_rate_bps)); ++ PUT_TSTAT_U64(SENT_BYTES64, READ_ONCE(b->bytes)); ++ PUT_TSTAT_U32(BACKLOG_BYTES, READ_ONCE(b->tin_backlog)); + + PUT_TSTAT_U32(TARGET_US, + ktime_to_us(ns_to_ktime(b->cparams.target))); +@@ -3304,10 +3306,10 @@ static int cake_mq_change(struct Qdisc *sch, struct nlattr *opt, + struct cake_sched_data *qd = qdisc_priv(chld); + + if (overhead_changed) { +- qd->max_netlen = 0; +- qd->max_adjlen = 0; +- qd->min_netlen = ~0; +- qd->min_adjlen = ~0; ++ WRITE_ONCE(qd->max_netlen, 0); ++ WRITE_ONCE(qd->max_adjlen, 0); ++ WRITE_ONCE(qd->min_netlen, ~0); ++ WRITE_ONCE(qd->min_adjlen, ~0); + } + + if (qd->tins) { +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-2205 b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-2205 new file mode 100644 index 0000000000..381b06dcb7 --- /dev/null +++ b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-2205 @@ -0,0 +1,140 @@ +From 1b8aa110181aaca51f051724f24ddf70405eb3ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:04 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (III) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit 276a98a434964088fccd4745db5b34d6e831e358 ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this third patch, I add READ_ONCE()/WRITE_ONCE() annotations +for the following fields: + +- packets +- tin_dropped +- tin_ecn_mark +- ack_drops +- peak_delay +- avge_delay +- base_delay + +Other annotations are added in following patches, to ease code review. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-4-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 38 ++++++++++++++++++++------------------ + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index a164464f63d18..3605f32ebf813 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -1600,7 +1600,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) + sch->qstats.backlog -= len; + + flow->dropped++; +- b->tin_dropped++; ++ WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1); + + if (q->config->rate_flags & CAKE_FLAG_INGRESS) + cake_advance_shaper(q, b, skb, now, true); +@@ -1820,7 +1820,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + numsegs++; + slen += segs->len; + q->buffer_used += segs->truesize; +- b->packets++; ++ WRITE_ONCE(b->packets, b->packets + 1); + } + + /* stats */ +@@ -1844,7 +1844,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + ack = cake_ack_filter(q, flow); + + if (ack) { +- b->ack_drops++; ++ WRITE_ONCE(b->ack_drops, b->ack_drops + 1); + sch->qstats.drops++; + ack_pkt_len = qdisc_pkt_len(ack); + b->bytes += ack_pkt_len; +@@ -1860,7 +1860,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + + /* stats */ +- b->packets++; ++ WRITE_ONCE(b->packets, b->packets + 1); + b->bytes += len - ack_pkt_len; + b->backlogs[idx] += len - ack_pkt_len; + b->tin_backlog += len - ack_pkt_len; +@@ -2236,7 +2236,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + b->tin_deficit -= len; + } + flow->dropped++; +- b->tin_dropped++; ++ WRITE_ONCE(b->tin_dropped, b->tin_dropped + 1); + qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb)); + qdisc_qstats_drop(sch); + qdisc_dequeue_drop(sch, skb, reason); +@@ -2244,17 +2244,19 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch) + goto retry; + } + +- b->tin_ecn_mark += !!flow->cvars.ecn_marked; ++ WRITE_ONCE(b->tin_ecn_mark, b->tin_ecn_mark + !!flow->cvars.ecn_marked); + qdisc_bstats_update(sch, skb); + WRITE_ONCE(q->last_active, now); + + /* collect delay stats */ + delay = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb))); +- b->avge_delay = cake_ewma(b->avge_delay, delay, 8); +- b->peak_delay = cake_ewma(b->peak_delay, delay, +- delay > b->peak_delay ? 2 : 8); +- b->base_delay = cake_ewma(b->base_delay, delay, +- delay < b->base_delay ? 2 : 8); ++ WRITE_ONCE(b->avge_delay, cake_ewma(b->avge_delay, delay, 8)); ++ WRITE_ONCE(b->peak_delay, ++ cake_ewma(b->peak_delay, delay, ++ delay > b->peak_delay ? 2 : 8)); ++ WRITE_ONCE(b->base_delay, ++ cake_ewma(b->base_delay, delay, ++ delay < b->base_delay ? 2 : 8)); + + len = cake_advance_shaper(q, b, skb, now, false); + flow->deficit -= len; +@@ -3042,17 +3044,17 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(INTERVAL_US, + ktime_to_us(ns_to_ktime(b->cparams.interval))); + +- PUT_TSTAT_U32(SENT_PACKETS, b->packets); +- PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); +- PUT_TSTAT_U32(ECN_MARKED_PACKETS, b->tin_ecn_mark); +- PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, b->ack_drops); ++ PUT_TSTAT_U32(SENT_PACKETS, READ_ONCE(b->packets)); ++ PUT_TSTAT_U32(DROPPED_PACKETS, READ_ONCE(b->tin_dropped)); ++ PUT_TSTAT_U32(ECN_MARKED_PACKETS, READ_ONCE(b->tin_ecn_mark)); ++ PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, READ_ONCE(b->ack_drops)); + + PUT_TSTAT_U32(PEAK_DELAY_US, +- ktime_to_us(ns_to_ktime(b->peak_delay))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->peak_delay)))); + PUT_TSTAT_U32(AVG_DELAY_US, +- ktime_to_us(ns_to_ktime(b->avge_delay))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->avge_delay)))); + PUT_TSTAT_U32(BASE_DELAY_US, +- ktime_to_us(ns_to_ktime(b->base_delay))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->base_delay)))); + + PUT_TSTAT_U32(WAY_INDIRECT_HITS, READ_ONCE(b->way_hits)); + PUT_TSTAT_U32(WAY_MISSES, READ_ONCE(b->way_misses)); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-22292 b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-22292 new file mode 100644 index 0000000000..3ca8634ccf --- /dev/null +++ b/queue-7.0/net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-22292 @@ -0,0 +1,62 @@ +From c6bc623af331555eae2d52a4101b59e093fca146 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 08:36:06 +0000 +Subject: net/sched: sch_cake: annotate data-races in cake_dump_stats() (V) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric Dumazet + +[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ] + +cake_dump_stats() runs without qdisc spinlock being held. + +In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations +for cparams.target and cparams.interval. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Eric Dumazet +Acked-by: "Toke Høiland-Jørgensen" +Link: https://patch.msgid.link/20260427083606.459355-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 804e8f4c46f32..7033f859a3948 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -2356,10 +2356,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, + + byte_target_ns = (byte_target * rate_ns) >> rate_shft; + +- b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); +- b->cparams.interval = max(rtt_est_ns + +- b->cparams.target - target_ns, +- b->cparams.target * 2); ++ WRITE_ONCE(b->cparams.target, ++ max((byte_target_ns * 3) / 2, target_ns)); ++ WRITE_ONCE(b->cparams.interval, ++ max(rtt_est_ns + b->cparams.target - target_ns, ++ b->cparams.target * 2)); + b->cparams.mtu_time = byte_target_ns; + b->cparams.p_inc = 1 << 24; /* 1/256 */ + b->cparams.p_dec = 1 << 20; /* 1/4096 */ +@@ -3042,9 +3043,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + PUT_TSTAT_U32(BACKLOG_BYTES, READ_ONCE(b->tin_backlog)); + + PUT_TSTAT_U32(TARGET_US, +- ktime_to_us(ns_to_ktime(b->cparams.target))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.target)))); + PUT_TSTAT_U32(INTERVAL_US, +- ktime_to_us(ns_to_ktime(b->cparams.interval))); ++ ktime_to_us(ns_to_ktime(READ_ONCE(b->cparams.interval)))); + + PUT_TSTAT_U32(SENT_PACKETS, READ_ONCE(b->packets)); + PUT_TSTAT_U32(DROPPED_PACKETS, READ_ONCE(b->tin_dropped)); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch b/queue-7.0/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch new file mode 100644 index 0000000000..0b19a7a24c --- /dev/null +++ b/queue-7.0/net-sched-sch_cake-fix-nat-destination-port-not-bein.patch @@ -0,0 +1,64 @@ +From 80cf83ea7d4e2907eae6c9c50d48694e6e0cf923 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:00:41 +0800 +Subject: net/sched: sch_cake: fix NAT destination port not being updated in + cake_update_flowkeys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dudu Lu + +[ Upstream commit f9e40664706927d7ae22a448a3383e23c38a4c0b ] + +cake_update_flowkeys() is supposed to update the flow dissector keys +with the NAT-translated addresses and ports from conntrack, so that +CAKE's per-flow fairness correctly identifies post-NAT flows as +belonging to the same connection. + +For the source port, this works correctly: + keys->ports.src = port; + +But for the destination port, the assignment is reversed: + port = keys->ports.dst; + +This means the NAT destination port is never updated in the flow keys. +As a result, when multiple connections are NATed to the same destination, +CAKE treats them as separate flows because the original (pre-NAT) +destination ports differ. This breaks CAKE's NAT-aware flow isolation +when using the "nat" mode. + +The bug was introduced in commit b0c19ed6088a ("sch_cake: Take advantage +of skb->hash where appropriate") which refactored the original direct +assignment into a compare-and-conditionally-update pattern, but wrote +the destination port update backwards. + +Fix by reversing the assignment direction to match the source port +pattern. + +Fixes: b0c19ed6088a ("sch_cake: Take advantage of skb->hash where appropriate") +Signed-off-by: Dudu Lu +Acked-by: Toke Høiland-Jørgensen +Link: https://patch.msgid.link/20260413110041.44704-1-phx0fer@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_cake.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c +index 9efe23f8371b3..4ac6c36ca6e41 100644 +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -619,7 +619,7 @@ static bool cake_update_flowkeys(struct flow_keys *keys, + } + port = rev ? tuple.src.u.all : tuple.dst.u.all; + if (port != keys->ports.dst) { +- port = keys->ports.dst; ++ keys->ports.dst = port; + upd = true; + } + } +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch b/queue-7.0/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch new file mode 100644 index 0000000000..8e607d9c6c --- /dev/null +++ b/queue-7.0/net-sched-sch_choke-annotate-data-races-in-choke_dum.patch @@ -0,0 +1,97 @@ +From 6fde7b93aa8fcafd5c555e2d46aa99e60deb6ba1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:28:39 +0000 +Subject: net/sched: sch_choke: annotate data-races in choke_dump_stats() + +From: Eric Dumazet + +[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ] + +choke_dump_stats() only runs with RTNL held. +It reads fields that can be changed in qdisc fast path. +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423062839.2524324-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_choke.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c +index 94df8e741a979..2875bcdb18a41 100644 +--- a/net/sched/sch_choke.c ++++ b/net/sched/sch_choke.c +@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + /* Draw a packet at random from queue and compare flow */ + if (choke_match_random(q, skb, &idx)) { +- q->stats.matched++; ++ WRITE_ONCE(q->stats.matched, q->stats.matched + 1); + choke_drop_by_idx(sch, idx, to_free); + goto congestion_drop; + } +@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + qdisc_qstats_overlimit(sch); + if (use_harddrop(q) || !use_ecn(q) || + !INET_ECN_set_ce(skb)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + } else if (++q->vars.qcount) { + if (red_mark_probability(p, &q->vars, q->vars.qavg)) { + q->vars.qcount = 0; +@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + qdisc_qstats_overlimit(sch); + if (!use_ecn(q) || !INET_ECN_set_ce(skb)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + } + } else + q->vars.qR = red_random(p); +@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + } + +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, q->stats.pdrop + 1); + return qdisc_drop(skb, sch, to_free); + + congestion_drop: +@@ -461,10 +465,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct choke_sched_data *q = qdisc_priv(sch); + struct tc_choke_xstats st = { +- .early = q->stats.prob_drop + q->stats.forced_drop, +- .marked = q->stats.prob_mark + q->stats.forced_mark, +- .pdrop = q->stats.pdrop, +- .matched = q->stats.matched, ++ .early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop), ++ .marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark), ++ .pdrop = READ_ONCE(q->stats.pdrop), ++ .matched = READ_ONCE(q->stats.matched), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_dualpi2-drain-both-c-queue-and-l-queue.patch b/queue-7.0/net-sched-sch_dualpi2-drain-both-c-queue-and-l-queue.patch new file mode 100644 index 0000000000..2a3f5a9618 --- /dev/null +++ b/queue-7.0/net-sched-sch_dualpi2-drain-both-c-queue-and-l-queue.patch @@ -0,0 +1,85 @@ +From 24cb7cd34ae14b878b0f5f12dd51b9c7b2f4f995 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 17:25:51 +0200 +Subject: net/sched: sch_dualpi2: drain both C-queue and L-queue in + dualpi2_change() + +From: Chia-Yu Chang + +[ Upstream commit 478ed6b7d2577439c610f91fa8759a4c878a4264 ] + +Fix dualpi2_change() to correctly enforce updated limit and memlimit +values after a configuration change of the dualpi2 qdisc. + +Before this patch, dualpi2_change() always attempted to dequeue packets +via the root qdisc (C-queue) when reducing backlog or memory usage, and +unconditionally assumed that a valid skb will be returned. When traffic +classification results in packets being queued in the L-queue while the +C-queue is empty, this leads to a NULL skb dereference during limit or +memlimit enforcement. + +This is fixed by first dequeuing from the C-queue path if it is +non-empty. Once the C-queue is empty, packets are dequeued directly from +the L-queue. Return values from qdisc_dequeue_internal() are checked for +both queues. When dequeuing from the L-queue, the parent qdisc qlen and +backlog counters are updated explicitly to keep overall qdisc statistics +consistent. + +Fixes: 320d031ad6e4 ("sched: Struct definition and parsing of dualpi2 qdisc") +Reported-by: "Kito Xu (veritas501)" +Closes: https://lore.kernel.org/netdev/20260413075740.2234828-1-hxzene@gmail.com/ +Signed-off-by: Chia-Yu Chang +Link: https://patch.msgid.link/20260417152551.71648-1-chia-yu.chang@nokia-bell-labs.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/sch_dualpi2.c | 32 ++++++++++++++++++++++++++++---- + 1 file changed, 28 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c +index 6d7e6389758dc..d200c08ce50a1 100644 +--- a/net/sched/sch_dualpi2.c ++++ b/net/sched/sch_dualpi2.c +@@ -872,11 +872,35 @@ static int dualpi2_change(struct Qdisc *sch, struct nlattr *opt, + old_backlog = sch->qstats.backlog; + while (qdisc_qlen(sch) > sch->limit || + q->memory_used > q->memory_limit) { +- struct sk_buff *skb = qdisc_dequeue_internal(sch, true); ++ struct sk_buff *skb = NULL; + +- q->memory_used -= skb->truesize; +- qdisc_qstats_backlog_dec(sch, skb); +- rtnl_qdisc_drop(skb, sch); ++ if (qdisc_qlen(sch) > qdisc_qlen(q->l_queue)) { ++ skb = qdisc_dequeue_internal(sch, true); ++ if (unlikely(!skb)) { ++ WARN_ON_ONCE(1); ++ break; ++ } ++ q->memory_used -= skb->truesize; ++ rtnl_qdisc_drop(skb, sch); ++ } else if (qdisc_qlen(q->l_queue)) { ++ skb = qdisc_dequeue_internal(q->l_queue, true); ++ if (unlikely(!skb)) { ++ WARN_ON_ONCE(1); ++ break; ++ } ++ /* L-queue packets are counted in both sch and ++ * l_queue on enqueue; qdisc_dequeue_internal() ++ * handled l_queue, so we further account for sch. ++ */ ++ --sch->q.qlen; ++ qdisc_qstats_backlog_dec(sch, skb); ++ q->memory_used -= skb->truesize; ++ rtnl_qdisc_drop(skb, q->l_queue); ++ qdisc_qstats_drop(sch); ++ } else { ++ WARN_ON_ONCE(1); ++ break; ++ } + } + qdisc_tree_reduce_backlog(sch, old_qlen - qdisc_qlen(sch), + old_backlog - sch->qstats.backlog); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch b/queue-7.0/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch new file mode 100644 index 0000000000..6c66c0e022 --- /dev/null +++ b/queue-7.0/net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch @@ -0,0 +1,47 @@ +From aa0144dcf27a149b1852901bfee75f751b49ea42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:25:09 +0000 +Subject: net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats() + +From: Eric Dumazet + +[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill st.qdisc_stats with live data. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142509.3967231-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_codel.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 8181b52dd9a8a..84b84e3ad80d6 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -585,6 +585,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + }; + struct list_head *pos; + ++ sch_tree_lock(sch); ++ + st.qdisc_stats.maxpacket = q->cstats.maxpacket; + st.qdisc_stats.drop_overlimit = q->drop_overlimit; + st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; +@@ -593,7 +595,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + st.qdisc_stats.memory_usage = q->memory_usage; + st.qdisc_stats.drop_overmemory = q->drop_overmemory; + +- sch_tree_lock(sch); + list_for_each(pos, &q->new_flows) + st.qdisc_stats.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch b/queue-7.0/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch new file mode 100644 index 0000000000..d0bf8d2e96 --- /dev/null +++ b/queue-7.0/net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch @@ -0,0 +1,62 @@ +From 56924a22b1d42e60a67b1494cfbe9f908b1e6eb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 06:35:27 +0000 +Subject: net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ] + +fq_codel_dump_stats() acquires the qdisc spinlock a bit too late. + +Move this acquisition before we fill tc_fq_pie_xstats with live data. + +Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, +but the spinlock is needed anyway to scan q->new_flows and q->old_flows. + +Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260423063527.2568262-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_fq_pie.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c +index d8ac3519e9379..66ec15998ce05 100644 +--- a/net/sched/sch_fq_pie.c ++++ b/net/sched/sch_fq_pie.c +@@ -509,18 +509,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb) + static int fq_pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct fq_pie_sched_data *q = qdisc_priv(sch); +- struct tc_fq_pie_xstats st = { +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .overmemory = q->overmemory, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, +- .new_flow_count = q->new_flow_count, +- .memory_usage = q->memory_usage, +- }; ++ struct tc_fq_pie_xstats st = { 0 }; + struct list_head *pos; + + sch_tree_lock(sch); ++ ++ st.packets_in = q->stats.packets_in; ++ st.overlimit = q->stats.overlimit; ++ st.overmemory = q->overmemory; ++ st.dropped = q->stats.dropped; ++ st.ecn_mark = q->stats.ecn_mark; ++ st.new_flow_count = q->new_flow_count; ++ st.memory_usage = q->memory_usage; ++ + list_for_each(pos, &q->new_flows) + st.new_flows_len++; + +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch b/queue-7.0/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch new file mode 100644 index 0000000000..d38be30fcd --- /dev/null +++ b/queue-7.0/net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch @@ -0,0 +1,160 @@ +From bed3fede601e88fcb734e760230cf149edd5a37a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:29:44 +0000 +Subject: net/sched: sch_pie: annotate data-races in pie_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ] + +pie_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_pie_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142944.4009941-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/pie.h | 2 +- + net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/include/net/pie.h b/include/net/pie.h +index 01cbc66825a40..1f3db0c355149 100644 +--- a/include/net/pie.h ++++ b/include/net/pie.h +@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) + vars->dq_tstamp = DTIME_INVALID; + vars->accu_prob = 0; + vars->dq_count = DQCOUNT_INVALID; +- vars->avg_dq_rate = 0; ++ WRITE_ONCE(vars->avg_dq_rate, 0); + } + + static inline struct pie_skb_cb *get_pie_cb(const struct sk_buff *skb) +diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c +index 0a377313b6a9d..73650200482f4 100644 +--- a/net/sched/sch_pie.c ++++ b/net/sched/sch_pie.c +@@ -90,7 +90,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + bool enqueue = false; + + if (unlikely(qdisc_qlen(sch) >= sch->limit)) { +- q->stats.overlimit++; ++ WRITE_ONCE(q->stats.overlimit, q->stats.overlimit + 1); + goto out; + } + +@@ -104,7 +104,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + /* If packet is ecn capable, mark it if drop probability + * is lower than 10%, else drop it. + */ +- q->stats.ecn_mark++; ++ WRITE_ONCE(q->stats.ecn_mark, q->stats.ecn_mark + 1); + enqueue = true; + } + +@@ -114,15 +114,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + if (!q->params.dq_rate_estimator) + pie_set_enqueue_time(skb); + +- q->stats.packets_in++; ++ WRITE_ONCE(q->stats.packets_in, q->stats.packets_in + 1); + if (qdisc_qlen(sch) > q->stats.maxq) +- q->stats.maxq = qdisc_qlen(sch); ++ WRITE_ONCE(q->stats.maxq, qdisc_qlen(sch)); + + return qdisc_enqueue_tail(skb, sch); + } + + out: +- q->stats.dropped++; ++ WRITE_ONCE(q->stats.dropped, q->stats.dropped + 1); + q->vars.accu_prob = 0; + return qdisc_drop_reason(skb, sch, to_free, reason); + } +@@ -267,11 +267,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, + count = count / dtime; + + if (vars->avg_dq_rate == 0) +- vars->avg_dq_rate = count; ++ WRITE_ONCE(vars->avg_dq_rate, count); + else +- vars->avg_dq_rate = ++ WRITE_ONCE(vars->avg_dq_rate, + (vars->avg_dq_rate - +- (vars->avg_dq_rate >> 3)) + (count >> 3); ++ (vars->avg_dq_rate >> 3)) + (count >> 3)); + + /* If the queue has receded below the threshold, we hold + * on to the last drain rate calculated, else we reset +@@ -381,7 +381,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + if (delta > 0) { + /* prevent overflow */ + if (vars->prob < oldprob) { +- vars->prob = MAX_PROB; ++ WRITE_ONCE(vars->prob, MAX_PROB); + /* Prevent normalization error. If probability is at + * maximum value already, we normalize it here, and + * skip the check to do a non-linear drop in the next +@@ -392,7 +392,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + } else { + /* prevent underflow */ + if (vars->prob > oldprob) +- vars->prob = 0; ++ WRITE_ONCE(vars->prob, 0); + } + + /* Non-linear drop in probability: Reduce drop probability quickly if +@@ -403,7 +403,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, + /* Reduce drop probability to 98.4% */ + vars->prob -= vars->prob / 64; + +- vars->qdelay = qdelay; ++ WRITE_ONCE(vars->qdelay, qdelay); + vars->backlog_old = backlog; + + /* We restart the measurement cycle if the following conditions are met +@@ -502,21 +502,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + struct pie_sched_data *q = qdisc_priv(sch); + struct tc_pie_xstats st = { + .prob = q->vars.prob << BITS_PER_BYTE, +- .delay = ((u32)PSCHED_TICKS2NS(q->vars.qdelay)) / ++ .delay = ((u32)PSCHED_TICKS2NS(READ_ONCE(q->vars.qdelay))) / + NSEC_PER_USEC, +- .packets_in = q->stats.packets_in, +- .overlimit = q->stats.overlimit, +- .maxq = q->stats.maxq, +- .dropped = q->stats.dropped, +- .ecn_mark = q->stats.ecn_mark, ++ .packets_in = READ_ONCE(q->stats.packets_in), ++ .overlimit = READ_ONCE(q->stats.overlimit), ++ .maxq = READ_ONCE(q->stats.maxq), ++ .dropped = READ_ONCE(q->stats.dropped), ++ .ecn_mark = READ_ONCE(q->stats.ecn_mark), + }; + + /* avg_dq_rate is only valid if dq_rate_estimator is enabled */ + st.dq_rate_estimating = q->params.dq_rate_estimator; + + /* unscale and return dq_rate in bytes per sec */ +- if (q->params.dq_rate_estimator) +- st.avg_dq_rate = q->vars.avg_dq_rate * ++ if (st.dq_rate_estimating) ++ st.avg_dq_rate = READ_ONCE(q->vars.avg_dq_rate) * + (PSCHED_TICKS_PER_SEC) >> PIE_SCALE; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch b/queue-7.0/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch new file mode 100644 index 0000000000..8a3c00260e --- /dev/null +++ b/queue-7.0/net-sched-sch_red-annotate-data-races-in-red_dump_st.patch @@ -0,0 +1,112 @@ +From 10410e5135ead767273f6cf451ca976f036d6d66 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:23:09 +0000 +Subject: net/sched: sch_red: annotate data-races in red_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ] + +red_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_red_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421142309.3964322-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_red.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c +index 68ee41ce78c50..86651a68d4015 100644 +--- a/net/sched/sch_red.c ++++ b/net/sched/sch_red.c +@@ -90,17 +90,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + case RED_PROB_MARK: + qdisc_qstats_overlimit(sch); + if (!red_use_ecn(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.prob_mark++; ++ WRITE_ONCE(q->stats.prob_mark, ++ q->stats.prob_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.prob_drop++; ++ WRITE_ONCE(q->stats.prob_drop, ++ q->stats.prob_drop + 1); + goto congestion_drop; + } + +@@ -111,17 +114,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + reason = SKB_DROP_REASON_QDISC_OVERLIMIT; + qdisc_qstats_overlimit(sch); + if (red_use_harddrop(q) || !red_use_ecn(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + + if (INET_ECN_set_ce(skb)) { +- q->stats.forced_mark++; ++ WRITE_ONCE(q->stats.forced_mark, ++ q->stats.forced_mark + 1); + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, to_free, &ret); + if (!skb) + return NET_XMIT_CN | ret; + } else if (!red_use_nodrop(q)) { +- q->stats.forced_drop++; ++ WRITE_ONCE(q->stats.forced_drop, ++ q->stats.forced_drop + 1); + goto congestion_drop; + } + +@@ -135,7 +141,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->qstats.backlog += len; + sch->q.qlen++; + } else if (net_xmit_drop_count(ret)) { +- q->stats.pdrop++; ++ WRITE_ONCE(q->stats.pdrop, ++ q->stats.pdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -463,9 +470,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, + &hw_stats_request); + } +- st.early = q->stats.prob_drop + q->stats.forced_drop; +- st.pdrop = q->stats.pdrop; +- st.marked = q->stats.prob_mark + q->stats.forced_mark; ++ st.early = READ_ONCE(q->stats.prob_drop) + ++ READ_ONCE(q->stats.forced_drop); ++ ++ st.pdrop = READ_ONCE(q->stats.pdrop); ++ ++ st.marked = READ_ONCE(q->stats.prob_mark) + ++ READ_ONCE(q->stats.forced_mark); + + return gnet_stats_copy_app(d, &st, sizeof(st)); + } +-- +2.53.0 + diff --git a/queue-7.0/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch b/queue-7.0/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch new file mode 100644 index 0000000000..5daa83a4ba --- /dev/null +++ b/queue-7.0/net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch @@ -0,0 +1,169 @@ +From 459839d606d14f64f59175b8d531c6d087aebdd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:16:55 +0000 +Subject: net/sched: sch_sfb: annotate data-races in sfb_dump_stats() + +From: Eric Dumazet + +[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ] + +sfb_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Alternative would be to acquire the qdisc spinlock, but our long-term +goal is to make qdisc dump operations lockless as much as we can. + +tc_sfb_xstats fields don't need to be latched atomically, +otherwise this bug would have been caught earlier. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260421141655.3953721-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ + 1 file changed, 32 insertions(+), 22 deletions(-) + +diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c +index d2835f1168e1d..00286c930b8de 100644 +--- a/net/sched/sch_sfb.c ++++ b/net/sched/sch_sfb.c +@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen < 0xFFFF) +- b[hash].qlen++; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen + 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, + + sfbhash >>= SFB_BUCKET_SHIFT; + if (b[hash].qlen > 0) +- b[hash].qlen--; ++ WRITE_ONCE(b[hash].qlen, b[hash].qlen - 1); + b += SFB_NUMBUCKETS; /* next level */ + } + } +@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q) + + static void decrement_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_minus(b->p_mark, q->decrement); ++ WRITE_ONCE(b->p_mark, prob_minus(b->p_mark, q->decrement)); + } + + static void increment_prob(struct sfb_bucket *b, struct sfb_sched_data *q) + { +- b->p_mark = prob_plus(b->p_mark, q->increment); ++ WRITE_ONCE(b->p_mark, prob_plus(b->p_mark, q->increment)); + } + + static void sfb_zero_all_buckets(struct sfb_sched_data *q) +@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da + const struct sfb_bucket *b = &q->bins[q->slot].bins[0][0]; + + for (i = 0; i < SFB_LEVELS * SFB_NUMBUCKETS; i++) { +- if (qlen < b->qlen) +- qlen = b->qlen; +- totalpm += b->p_mark; +- if (prob < b->p_mark) +- prob = b->p_mark; ++ u32 b_qlen = READ_ONCE(b->qlen); ++ u32 b_mark = READ_ONCE(b->p_mark); ++ ++ if (qlen < b_qlen) ++ qlen = b_qlen; ++ totalpm += b_mark; ++ if (prob < b_mark) ++ prob = b_mark; + b++; + } + *prob_r = prob; +@@ -295,7 +298,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(sch->q.qlen >= q->limit)) { + qdisc_qstats_overlimit(sch); +- q->stats.queuedrop++; ++ WRITE_ONCE(q->stats.queuedrop, ++ q->stats.queuedrop + 1); + goto drop; + } + +@@ -348,7 +352,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + + if (unlikely(minqlen >= q->max)) { + qdisc_qstats_overlimit(sch); +- q->stats.bucketdrop++; ++ WRITE_ONCE(q->stats.bucketdrop, ++ q->stats.bucketdrop + 1); + goto drop; + } + +@@ -374,7 +379,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + } + if (sfb_rate_limit(skb, q)) { + qdisc_qstats_overlimit(sch); +- q->stats.penaltydrop++; ++ WRITE_ONCE(q->stats.penaltydrop, ++ q->stats.penaltydrop + 1); + goto drop; + } + goto enqueue; +@@ -390,14 +396,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + * In either case, we want to start dropping packets. + */ + if (r < (p_min - SFB_MAX_PROB / 2) * 2) { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } + if (INET_ECN_set_ce(skb)) { +- q->stats.marked++; ++ WRITE_ONCE(q->stats.marked, ++ q->stats.marked + 1); + } else { +- q->stats.earlydrop++; ++ WRITE_ONCE(q->stats.earlydrop, ++ q->stats.earlydrop + 1); + goto drop; + } + } +@@ -410,7 +419,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, + sch->q.qlen++; + increment_qlen(&cb, q); + } else if (net_xmit_drop_count(ret)) { +- q->stats.childdrop++; ++ WRITE_ONCE(q->stats.childdrop, ++ q->stats.childdrop + 1); + qdisc_qstats_drop(sch); + } + return ret; +@@ -599,12 +609,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct sfb_sched_data *q = qdisc_priv(sch); + struct tc_sfb_xstats st = { +- .earlydrop = q->stats.earlydrop, +- .penaltydrop = q->stats.penaltydrop, +- .bucketdrop = q->stats.bucketdrop, +- .queuedrop = q->stats.queuedrop, +- .childdrop = q->stats.childdrop, +- .marked = q->stats.marked, ++ .earlydrop = READ_ONCE(q->stats.earlydrop), ++ .penaltydrop = READ_ONCE(q->stats.penaltydrop), ++ .bucketdrop = READ_ONCE(q->stats.bucketdrop), ++ .queuedrop = READ_ONCE(q->stats.queuedrop), ++ .childdrop = READ_ONCE(q->stats.childdrop), ++ .marked = READ_ONCE(q->stats.marked), + }; + + st.maxqlen = sfb_compute_qlen(&st.maxprob, &st.avgprob, q); +-- +2.53.0 + diff --git a/queue-7.0/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch b/queue-7.0/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch new file mode 100644 index 0000000000..9cad4dbe2a --- /dev/null +++ b/queue-7.0/net-sched-taprio-fix-null-pointer-dereference-in-cla.patch @@ -0,0 +1,123 @@ +From 59f41cba1bb6d64c648b751dfe7362bdba2bf0c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 00:19:58 +0800 +Subject: net/sched: taprio: fix NULL pointer dereference in class dump + +From: Weiming Shi + +[ Upstream commit 3d07ca5c0fae311226f737963984bd94bb159a87 ] + +When a TAPRIO child qdisc is deleted via RTM_DELQDISC, taprio_graft() +is called with new == NULL and stores NULL into q->qdiscs[cl - 1]. +Subsequent RTM_GETTCLASS dump operations walk all classes via +taprio_walk() and call taprio_dump_class(), which calls taprio_leaf() +returning the NULL pointer, then dereferences it to read child->handle, +causing a kernel NULL pointer dereference. + +The bug is reachable with namespace-scoped CAP_NET_ADMIN on any kernel +with CONFIG_NET_SCH_TAPRIO enabled. On systems with unprivileged user +namespaces enabled, an unprivileged local user can trigger a kernel +panic by creating a taprio qdisc inside a new network namespace, +grafting an explicit child qdisc, deleting it, and requesting a class +dump. The RTM_GETTCLASS dump itself requires no capability. + + Oops: general protection fault, probably for non-canonical address 0xdffffc0000000007: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f] + RIP: 0010:taprio_dump_class (net/sched/sch_taprio.c:2478) + Call Trace: + + tc_fill_tclass (net/sched/sch_api.c:1966) + qdisc_class_dump (net/sched/sch_api.c:2326) + taprio_walk (net/sched/sch_taprio.c:2514) + tc_dump_tclass_qdisc (net/sched/sch_api.c:2352) + tc_dump_tclass_root (net/sched/sch_api.c:2370) + tc_dump_tclass (net/sched/sch_api.c:2431) + rtnl_dumpit (net/core/rtnetlink.c:6864) + netlink_dump (net/netlink/af_netlink.c:2325) + rtnetlink_rcv_msg (net/core/rtnetlink.c:6959) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + + +Fix this by substituting &noop_qdisc when new is NULL in +taprio_graft(), a common pattern used by other qdiscs (e.g., +multiq_graft()) to ensure the q->qdiscs[] slots are never NULL. +This makes control-plane dump paths safe without requiring individual +NULL checks. + +Since the data-plane paths (taprio_enqueue and taprio_dequeue_from_txq) +previously had explicit NULL guards that would drop/skip the packet +cleanly, update those checks to test for &noop_qdisc instead. Without +this, packets would reach taprio_enqueue_one() which increments the root +qdisc's qlen and backlog before calling the child's enqueue; noop_qdisc +drops the packet but those counters are never rolled back, permanently +inflating the root qdisc's statistics. + +After this change *old can be a valid qdisc, NULL, or &noop_qdisc. +Only call qdisc_put(*old) in the first case to avoid decreasing +noop_qdisc's refcount, which was never increased. + +Fixes: 665338b2a7a0 ("net/sched: taprio: dump class stats for the actual q->qdiscs[]") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Acked-by: Jamal Hadi Salim +Tested-by: Weiming Shi +Link: https://patch.msgid.link/20260422161958.2517539-3-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 0316f2dee06ac..3c85ef1ef4818 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -634,7 +634,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, + queue = skb_get_queue_mapping(skb); + + child = q->qdiscs[queue]; +- if (unlikely(!child)) ++ if (unlikely(child == &noop_qdisc)) + return qdisc_drop(skb, sch, to_free); + + if (taprio_skb_exceeds_queue_max_sdu(sch, skb)) { +@@ -717,7 +717,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, + int len; + u8 tc; + +- if (unlikely(!child)) ++ if (unlikely(child == &noop_qdisc)) + return NULL; + + if (TXTIME_ASSIST_IS_ENABLED(q->flags)) +@@ -2184,6 +2184,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + if (!dev_queue) + return -EINVAL; + ++ if (!new) ++ new = &noop_qdisc; ++ + if (dev->flags & IFF_UP) + dev_deactivate(dev); + +@@ -2197,14 +2200,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, + *old = q->qdiscs[cl - 1]; + if (FULL_OFFLOAD_IS_ENABLED(q->flags)) { + WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old); +- if (new) ++ if (new != &noop_qdisc) + qdisc_refcount_inc(new); +- if (*old) ++ if (*old && *old != &noop_qdisc) + qdisc_put(*old); + } + + q->qdiscs[cl - 1] = new; +- if (new) ++ if (new != &noop_qdisc) + new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; + + if (dev->flags & IFF_UP) +-- +2.53.0 + diff --git a/queue-7.0/net-sched-taprio-fix-use-after-free-in-advance_sched.patch b/queue-7.0/net-sched-taprio-fix-use-after-free-in-advance_sched.patch new file mode 100644 index 0000000000..0b28a4990f --- /dev/null +++ b/queue-7.0/net-sched-taprio-fix-use-after-free-in-advance_sched.patch @@ -0,0 +1,60 @@ +From 031508f92b219e7a27771f38c8cacdd686834205 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 18:57:57 -0700 +Subject: net/sched: taprio: fix use-after-free in advance_sched() on schedule + switch + +From: Vinicius Costa Gomes + +[ Upstream commit 105425b1969c5affe532713cfac1c0b320d7ac2b ] + +In advance_sched(), when should_change_schedules() returns true, +switch_schedules() is called to promote the admin schedule to oper. +switch_schedules() queues the old oper schedule for RCU freeing via +call_rcu(), but 'next' still points into an entry of the old oper +schedule. The subsequent 'next->end_time = end_time' and +rcu_assign_pointer(q->current_entry, next) are use-after-free. + +Fix this by selecting 'next' from the new oper schedule immediately +after switch_schedules(), and using its pre-calculated end_time. +setup_first_end_time() sets the first entry's end_time to +base_time + interval when the schedule is installed, so the value +is already correct. + +The deleted 'end_time = sched_base_time(admin)' assignment was also +harmful independently: it would overwrite the new first entry's +pre-calculated end_time with just base_time. + +Fixes: a3d43c0d56f1 ("taprio: Add support adding an admin schedule") +Reported-by: Junxi Qian +Signed-off-by: Vinicius Costa Gomes +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_taprio.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index f721c03514f60..0316f2dee06ac 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -972,11 +972,12 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer) + } + + if (should_change_schedules(admin, oper, end_time)) { +- /* Set things so the next time this runs, the new +- * schedule runs. +- */ +- end_time = sched_base_time(admin); + switch_schedules(q, &admin, &oper); ++ /* After changing schedules, the next entry is the first one ++ * in the new schedule, with a pre-calculated end_time. ++ */ ++ next = list_first_entry(&oper->entries, struct sched_entry, list); ++ end_time = next->end_time; + } + + next->end_time = end_time; +-- +2.53.0 + diff --git a/queue-7.0/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch b/queue-7.0/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch new file mode 100644 index 0000000000..0c8aeda964 --- /dev/null +++ b/queue-7.0/net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch @@ -0,0 +1,90 @@ +From d81dab67535742bece88d180a7cc3f4a3b005ffe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 16:15:59 -0700 +Subject: net: tls: fix strparser anchor skb leak on offload RX setup failure + +From: Jakub Kicinski + +[ Upstream commit 58689498ca3384851145a754dbb1d8ed1cf9fb54 ] + +When tls_set_device_offload_rx() fails at tls_dev_add(), the error path +calls tls_sw_free_resources_rx() to clean up the SW context that was +initialized by tls_set_sw_offload(). This function calls +tls_sw_release_resources_rx() (which stops the strparser via +tls_strp_stop()) and tls_sw_free_ctx_rx() (which kfrees the context), +but never frees the anchor skb that was allocated by alloc_skb(0) in +tls_strp_init(). + +Note that tls_sw_free_resources_rx() is exclusively used for this +"failed to start offload" code path, there's no other caller. + +The leak did not exist before commit 84c61fe1a75b ("tls: rx: do not use +the standard strparser"), because the standard strparser doesn't try +to pre-allocate an skb. + +The normal close path in tls_sk_proto_close() handles cleanup by calling +tls_sw_strparser_done() (which calls tls_strp_done()) after dropping +the socket lock, because tls_strp_done() does cancel_work_sync() and +the strparser work handler takes the socket lock. + +Fixes: 84c61fe1a75b ("tls: rx: do not use the standard strparser") +Signed-off-by: Jakub Kicinski +Reviewed-by: Vadim Fedorenko +Link: https://patch.msgid.link/20260428231559.1358502-1-kuba@kernel.org +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tls/tls.h | 1 + + net/tls/tls_strp.c | 6 ++++++ + net/tls/tls_sw.c | 4 ++++ + 3 files changed, 11 insertions(+) + +diff --git a/net/tls/tls.h b/net/tls/tls.h +index 2f86baeb71fcb..a1d8467bece33 100644 +--- a/net/tls/tls.h ++++ b/net/tls/tls.h +@@ -188,6 +188,7 @@ int tls_strp_dev_init(void); + void tls_strp_dev_exit(void); + + void tls_strp_done(struct tls_strparser *strp); ++void __tls_strp_done(struct tls_strparser *strp); + void tls_strp_stop(struct tls_strparser *strp); + int tls_strp_init(struct tls_strparser *strp, struct sock *sk); + void tls_strp_data_ready(struct tls_strparser *strp); +diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c +index 98e12f0ff57e5..c72e883176273 100644 +--- a/net/tls/tls_strp.c ++++ b/net/tls/tls_strp.c +@@ -624,6 +624,12 @@ void tls_strp_done(struct tls_strparser *strp) + WARN_ON(!strp->stopped); + + cancel_work_sync(&strp->work); ++ __tls_strp_done(strp); ++} ++ ++/* For setup error paths where the strparser was initialized but never armed. */ ++void __tls_strp_done(struct tls_strparser *strp) ++{ + tls_strp_anchor_free(strp); + } + +diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c +index 83e78a3d1e651..23a31646d0387 100644 +--- a/net/tls/tls_sw.c ++++ b/net/tls/tls_sw.c +@@ -2625,8 +2625,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx) + void tls_sw_free_resources_rx(struct sock *sk) + { + struct tls_context *tls_ctx = tls_get_ctx(sk); ++ struct tls_sw_context_rx *ctx; ++ ++ ctx = tls_sw_ctx_rx(tls_ctx); + + tls_sw_release_resources_rx(sk); ++ __tls_strp_done(&ctx->strp); + tls_sw_free_ctx_rx(tls_ctx); + } + +-- +2.53.0 + diff --git a/queue-7.0/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch b/queue-7.0/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch new file mode 100644 index 0000000000..67b63c166a --- /dev/null +++ b/queue-7.0/net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch @@ -0,0 +1,89 @@ +From 37f9e8a4322e02f9bd5fdfabaa7f181f054b4ccd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 08:49:12 +0800 +Subject: net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit() + +From: Zhan Jun + +[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ] + +syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() +when accessing skb->len for tx statistics after usb_submit_urb() has +been called: + + BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760 + drivers/net/usb/rtl8150.c:712 + Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226 + +The URB completion handler write_bulk_callback() frees the skb via +dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU +in softirq context before usb_submit_urb() returns in the submitter, +so by the time the submitter reads skb->len the skb has already been +queued to the per-CPU completion_queue and freed by net_tx_action(): + + CPU A (xmit) CPU B (USB completion softirq) + ------------ ------------------------------ + dev->tx_skb = skb; + usb_submit_urb() --+ + |-------> write_bulk_callback() + | dev_kfree_skb_irq(dev->tx_skb) + | net_tx_action() + | napi_skb_cache_put() <-- free + netdev->stats.tx_bytes | + += skb->len; <-- UAF read + +Fix it by caching skb->len before submitting the URB and using the +cached value when updating the tx_bytes counter. + +The pre-existing tx_bytes semantics are preserved: the counter tracks +the original frame length (skb->len), not the ETH_ZLEN/USB-alignment +padded "count" value that is handed to the device. Changing that +would be a user-visible accounting change and is out of scope for +this UAF fix. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: syzbot+3f46c095ac0ca048cb71@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e69ee7.050a0220.24bfd3.002b.GAE@google.com/ +Closes: https://syzkaller.appspot.com/bug?extid=3f46c095ac0ca048cb71 +Reviewed-by: Andrew Lunn +Signed-off-by: Zhan Jun +Link: https://patch.msgid.link/809895186B866C10+20260423004913.136655-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 4cda0643afb6e..1bbfdeab4d624 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -683,6 +683,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + struct net_device *netdev) + { + rtl8150_t *dev = netdev_priv(netdev); ++ unsigned int skb_len; + int count, res; + + /* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */ +@@ -694,6 +695,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + ++ skb_len = skb->len; ++ + netif_stop_queue(netdev); + dev->tx_skb = skb; + usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), +@@ -709,7 +712,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + } + } else { + netdev->stats.tx_packets++; +- netdev->stats.tx_bytes += skb->len; ++ netdev->stats.tx_bytes += skb_len; + netif_trans_update(netdev); + } + +-- +2.53.0 + diff --git a/queue-7.0/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch b/queue-7.0/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch new file mode 100644 index 0000000000..6027d9abcb --- /dev/null +++ b/queue-7.0/net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch @@ -0,0 +1,61 @@ +From 30d0b7d58e3ab6f7114c9d4b9b9c2ec47d701588 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 09:55:17 +0800 +Subject: net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit + +From: Morduan Zang + +[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ] + +When rtl8150_start_xmit() fails to submit the tx URB, the URB is never +handed to the USB core and write_bulk_callback() will not run. The +driver returns NETDEV_TX_OK, which tells the networking stack that the +skb has been consumed, but nothing actually frees the skb on this +error path: + + dev->tx_skb = skb; + ... + if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { + ... + /* no kfree_skb here */ + } + return NETDEV_TX_OK; + +This leaks the skb on every submit failure and also leaves dev->tx_skb +pointing at memory that the driver itself may later free, which is +fragile. + +Free the skb with dev_kfree_skb_any() in the error path and clear +dev->tx_skb so no stale pointer is left behind. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reviewed-by: Andrew Lunn +Signed-off-by: Morduan Zang +Link: https://patch.msgid.link/E7D3E1C013C5A859+20260424015517.9574-1-zhangdandan@uniontech.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rtl8150.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c +index 1bbfdeab4d624..c880c95c41a5e 100644 +--- a/drivers/net/usb/rtl8150.c ++++ b/drivers/net/usb/rtl8150.c +@@ -710,6 +710,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, + netdev->stats.tx_errors++; + netif_start_queue(netdev); + } ++ /* ++ * The URB was not submitted, so write_bulk_callback() will ++ * never run to free dev->tx_skb. Drop the skb here and ++ * clear tx_skb to avoid leaving a stale pointer. ++ */ ++ dev->tx_skb = NULL; ++ dev_kfree_skb_any(skb); + } else { + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb_len; +-- +2.53.0 + diff --git a/queue-7.0/net-validate-skb-napi_id-in-rx-tracepoints.patch b/queue-7.0/net-validate-skb-napi_id-in-rx-tracepoints.patch new file mode 100644 index 0000000000..6e6064ebe3 --- /dev/null +++ b/queue-7.0/net-validate-skb-napi_id-in-rx-tracepoints.patch @@ -0,0 +1,58 @@ +From 1fef75b038c00a56bba0ad180b04dce49ff5043b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 10:54:23 +0000 +Subject: net: validate skb->napi_id in RX tracepoints + +From: Kohei Enju + +[ Upstream commit 3bfcf396081ace536733b454ff128d53116581e5 ] + +Since commit 2bd82484bb4c ("xps: fix xps for stacked devices"), +skb->napi_id shares storage with sender_cpu. RX tracepoints using +net_dev_rx_verbose_template read skb->napi_id directly and can therefore +report sender_cpu values as if they were NAPI IDs. + +For example, on the loopback path this can report 1 as napi_id, where 1 +comes from raw_smp_processor_id() + 1 in the XPS path: + + # bpftrace -e 'tracepoint:net:netif_rx_entry{ print(args->napi_id); }' + # taskset -c 0 ping -c 1 ::1 + +Report only valid NAPI IDs in these tracepoints and use 0 otherwise. + +Fixes: 2bd82484bb4c ("xps: fix xps for stacked devices") +Signed-off-by: Kohei Enju +Reviewed-by: Simon Horman +Reviewed-by: Jiayuan Chen +Link: https://patch.msgid.link/20260420105427.162816-1-kohei@enjuk.jp +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/trace/events/net.h | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/include/trace/events/net.h b/include/trace/events/net.h +index fdd9ad474ce3a..dbc2c5598e35a 100644 +--- a/include/trace/events/net.h ++++ b/include/trace/events/net.h +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + TRACE_EVENT(net_dev_start_xmit, + +@@ -208,7 +209,8 @@ DECLARE_EVENT_CLASS(net_dev_rx_verbose_template, + TP_fast_assign( + __assign_str(name); + #ifdef CONFIG_NET_RX_BUSY_POLL +- __entry->napi_id = skb->napi_id; ++ __entry->napi_id = napi_id_valid(skb->napi_id) ? ++ skb->napi_id : 0; + #else + __entry->napi_id = 0; + #endif +-- +2.53.0 + diff --git a/queue-7.0/net_sched-fix-skb-memory-leak-in-deferred-qdisc-drop.patch b/queue-7.0/net_sched-fix-skb-memory-leak-in-deferred-qdisc-drop.patch new file mode 100644 index 0000000000..dd55a10ca3 --- /dev/null +++ b/queue-7.0/net_sched-fix-skb-memory-leak-in-deferred-qdisc-drop.patch @@ -0,0 +1,65 @@ +From 17ff285096b434b5397ca80a31cd5c8d99a34165 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 12:00:44 +0200 +Subject: net_sched: fix skb memory leak in deferred qdisc drops + +From: Fernando Fernandez Mancera + +[ Upstream commit a6bd339dbb3514bce690fdcf252e788dfab4ee76 ] + +When the network stack cleans up the deferred list via qdisc_run_end(), +it operates on the root qdisc. If the root qdisc do not implement the +TCQ_F_DEQUEUE_DROPS flag the packets queue to free are never freed and +gets stranded on the child's local to_free list. + +Fix this by making qdisc_dequeue_drop() aware of the root qdisc. It +fetches the root qdisc and check for the TCQ_F_DEQUEUE_DROPS flag. If +the flag is present, the packet is appended directly to the root's +to_free list. Otherwise, drop it directly as it was done before the +optimization was implemented. + +Fixes: a6efc273ab82 ("net_sched: use qdisc_dequeue_drop() in cake, codel, fq_codel") +Reported-by: Damilola Bello +Closes: https://lore.kernel.org/netdev/CAPgFtOLaedBMU0f_BxV2bXftTJSmJr018Q5uozOo5vVo6b9tjw@mail.gmail.com/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260408100044.4530-1-fmancera@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/sch_generic.h | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h +index c3d657359a3d2..5fc0b1ebaf25c 100644 +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -1170,12 +1170,22 @@ static inline void tcf_kfree_skb_list(struct sk_buff *skb) + static inline void qdisc_dequeue_drop(struct Qdisc *q, struct sk_buff *skb, + enum skb_drop_reason reason) + { ++ struct Qdisc *root; ++ + DEBUG_NET_WARN_ON_ONCE(!(q->flags & TCQ_F_DEQUEUE_DROPS)); + DEBUG_NET_WARN_ON_ONCE(q->flags & TCQ_F_NOLOCK); + +- tcf_set_drop_reason(skb, reason); +- skb->next = q->to_free; +- q->to_free = skb; ++ rcu_read_lock(); ++ root = qdisc_root_sleeping(q); ++ ++ if (root->flags & TCQ_F_DEQUEUE_DROPS) { ++ tcf_set_drop_reason(skb, reason); ++ skb->next = root->to_free; ++ root->to_free = skb; ++ } else { ++ kfree_skb_reason(skb, reason); ++ } ++ rcu_read_unlock(); + } + + /* Instead of calling kfree_skb() while root qdisc lock is held, +-- +2.53.0 + diff --git a/queue-7.0/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch b/queue-7.0/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch new file mode 100644 index 0000000000..4838c7cd95 --- /dev/null +++ b/queue-7.0/net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch @@ -0,0 +1,92 @@ +From f9bab6a7069a909696683773156138fd65e37ddb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 14:33:49 +0000 +Subject: net_sched: sch_hhf: annotate data-races in hhf_dump_stats() + +From: Eric Dumazet + +[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ] + +hhf_dump_stats() only runs with RTNL held, +reading fields that can be changed in qdisc fast path. + +Add READ_ONCE()/WRITE_ONCE() annotations. + +Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") +Signed-off-by: Eric Dumazet +Reviewed-by: Jamal Hadi Salim +Link: https://patch.msgid.link/20260421143349.4052215-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_hhf.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c +index 95e5d9bfd9c8c..96021f52d835b 100644 +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash, + return NULL; + list_del(&flow->flowchain); + kfree(flow); +- q->hh_flows_current_cnt--; ++ WRITE_ONCE(q->hh_flows_current_cnt, ++ q->hh_flows_current_cnt - 1); + } else if (flow->hash_id == hash) { + return flow; + } +@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + } + + if (q->hh_flows_current_cnt >= q->hh_flows_limit) { +- q->hh_flows_overlimit++; ++ WRITE_ONCE(q->hh_flows_overlimit, q->hh_flows_overlimit + 1); + return NULL; + } + /* Create new entry. */ +@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, + if (!flow) + return NULL; + +- q->hh_flows_current_cnt++; ++ WRITE_ONCE(q->hh_flows_current_cnt, q->hh_flows_current_cnt + 1); + INIT_LIST_HEAD(&flow->flowchain); + list_add_tail(&flow->flowchain, head); + +@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch) + return WDRR_BUCKET_FOR_NON_HH; + flow->hash_id = hash; + flow->hit_timestamp = now; +- q->hh_flows_total_cnt++; ++ WRITE_ONCE(q->hh_flows_total_cnt, q->hh_flows_total_cnt + 1); + + /* By returning without updating counters in q->hhf_arrays, + * we implicitly implement "shielding" (see Optimization O1). +@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch, + return NET_XMIT_SUCCESS; + + prev_backlog = sch->qstats.backlog; +- q->drop_overlimit++; ++ WRITE_ONCE(q->drop_overlimit, q->drop_overlimit + 1); + /* Return Congestion Notification only if we dropped a packet from this + * bucket. + */ +@@ -686,10 +687,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + { + struct hhf_sched_data *q = qdisc_priv(sch); + struct tc_hhf_xstats st = { +- .drop_overlimit = q->drop_overlimit, +- .hh_overlimit = q->hh_flows_overlimit, +- .hh_tot_count = q->hh_flows_total_cnt, +- .hh_cur_count = q->hh_flows_current_cnt, ++ .drop_overlimit = READ_ONCE(q->drop_overlimit), ++ .hh_overlimit = READ_ONCE(q->hh_flows_overlimit), ++ .hh_tot_count = READ_ONCE(q->hh_flows_total_cnt), ++ .hh_cur_count = READ_ONCE(q->hh_flows_current_cnt), + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); +-- +2.53.0 + diff --git a/queue-7.0/netconsole-avoid-clobbering-userdatum-value-on-trunc.patch b/queue-7.0/netconsole-avoid-clobbering-userdatum-value-on-trunc.patch new file mode 100644 index 0000000000..d6b91f25df --- /dev/null +++ b/queue-7.0/netconsole-avoid-clobbering-userdatum-value-on-trunc.patch @@ -0,0 +1,72 @@ +From b49afeca64badd2735c6064ad258f54530dbb9de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 07:30:36 -0700 +Subject: netconsole: avoid clobbering userdatum value on truncated write + +From: Breno Leitao + +[ Upstream commit e6dd94252b0fa7b4fcc00577c6898432c5d97a08 ] + +userdatum_value_store() bounds count by MAX_EXTRADATA_VALUE_LEN (200) +and then copies straight into udm->value, which is itself 200 bytes: + + if (count > MAX_EXTRADATA_VALUE_LEN) + return -EMSGSIZE; + ... + ret = strscpy(udm->value, buf, sizeof(udm->value)); + if (ret < 0) + goto out_unlock; + +If userspace writes exactly MAX_EXTRADATA_VALUE_LEN bytes with no NUL +within them, strscpy() copies 199 bytes plus a NUL into udm->value and +returns -E2BIG. The function jumps to out_unlock and reports the error +to userspace, but udm->value has already been overwritten with the +truncated string and update_userdata() is skipped, so the corruption +is not yet visible on the wire. + +The next successful write to any userdatum entry under the same target +calls update_userdata(), which packs udm->value into the active +netconsole payload. From that point on, every netconsole message +carries the silently truncated value, and userspace has no indication +that a previous, error-returning write left state behind. + +Tighten the entry check from "count > MAX_EXTRADATA_VALUE_LEN" to +"count >= MAX_EXTRADATA_VALUE_LEN". With count strictly less than +sizeof(udm->value), strscpy() can no longer return -E2BIG here, so +the corrupting truncation path is removed entirely. + +Fixes: 8a6d5fec6c7f ("net: netconsole: add a userdata config_group member to netconsole_target") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-2-59965f29d9cc@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 76d7fbf9e1883..595e09bd1ccfc 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -1076,15 +1076,13 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, + struct userdata *ud; + ssize_t ret; + +- if (count > MAX_EXTRADATA_VALUE_LEN) ++ if (count >= MAX_EXTRADATA_VALUE_LEN) + return -EMSGSIZE; + + mutex_lock(&netconsole_subsys.su_mutex); + dynamic_netconsole_mutex_lock(); +- +- ret = strscpy(udm->value, buf, sizeof(udm->value)); +- if (ret < 0) +- goto out_unlock; ++ /* count is bounded above, so strscpy() cannot truncate here */ ++ strscpy(udm->value, buf, sizeof(udm->value)); + trim_newline(udm->value, sizeof(udm->value)); + + ud = to_userdata(item->ci_parent); +-- +2.53.0 + diff --git a/queue-7.0/netconsole-propagate-device-name-truncation-in-dev_n.patch b/queue-7.0/netconsole-propagate-device-name-truncation-in-dev_n.patch new file mode 100644 index 0000000000..b50c7b2878 --- /dev/null +++ b/queue-7.0/netconsole-propagate-device-name-truncation-in-dev_n.patch @@ -0,0 +1,58 @@ +From db23688dc39f2a2e9d5ebc48eb8c339a657996a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 07:30:37 -0700 +Subject: netconsole: propagate device name truncation in dev_name_store() + +From: Breno Leitao + +[ Upstream commit 92ceb7bff62c2606f664c204750eca0b85d44112 ] + +dev_name_store() calls strscpy(nt->np.dev_name, buf, IFNAMSIZ) without +checking the return value. If userspace writes an interface name longer +than IFNAMSIZ - 1, strscpy() silently truncates and returns -E2BIG, but +the function ignores it and reports a fully successful write back to +userspace. + +If a real interface happens to match the truncated name, netconsole will +bind to the wrong device on the next enable, sending kernel logs and +panic output to an unintended network segment with no indication to +userspace that anything was rewritten. + +Reject writes whose length cannot fit in nt->np.dev_name up front: + + if (count >= IFNAMSIZ) + return -ENAMETOOLONG; + +This is not a big deal of a problem, but, it is still the correct +approach. + +Fixes: 0bcc1816188e57 ("[NET] netconsole: Support dynamic reconfiguration using configfs") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-3-59965f29d9cc@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 595e09bd1ccfc..b3b36e3ddd03d 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -817,6 +817,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + size_t count) + { + struct netconsole_target *nt = to_target(item); ++ size_t len = count; ++ ++ /* Account for a trailing newline appended by tools like echo */ ++ if (len && buf[len - 1] == '\n') ++ len--; ++ if (len >= IFNAMSIZ) ++ return -ENAMETOOLONG; + + dynamic_netconsole_mutex_lock(); + if (nt->state == STATE_ENABLED) { +-- +2.53.0 + diff --git a/queue-7.0/netconsole-restore-userdatum-value-on-update_userdat.patch b/queue-7.0/netconsole-restore-userdatum-value-on-update_userdat.patch new file mode 100644 index 0000000000..89ab5b3b2e --- /dev/null +++ b/queue-7.0/netconsole-restore-userdatum-value-on-update_userdat.patch @@ -0,0 +1,71 @@ +From 3e3e4efb24c0710b33190cbd68d4cc86b5937a88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 07:30:38 -0700 +Subject: netconsole: restore userdatum value on update_userdata() failure + +From: Breno Leitao + +[ Upstream commit 869cd6490fafe09c89a15d01610e8a03932d79f0 ] + +userdatum_value_store() updates udm->value first and only then calls +update_userdata() to rebuild the on-the-wire payload. If +update_userdata() fails (e.g. -ENOMEM from kmalloc), the function +returns the error to userspace, but udm->value already holds the new +string while the live nt->userdata buffer still reflects the old one. + +The next successful write to any sibling userdatum on the same target +will call update_userdata() again, which walks every entry and packs +the now-stale udm->value into the payload. The failed write is thus +silently activated later, with no indication to userspace that the +value it tried to set was rejected. + +Snapshot the previous value before overwriting udm->value and restore +it if update_userdata() fails so the visible state and the active +payload stay consistent. + +Fixes: eb83801af2dc ("netconsole: Dynamic allocation of userdata buffer") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-4-59965f29d9cc@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index b3b36e3ddd03d..57dd6821a8aa9 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -1079,6 +1079,7 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, + size_t count) + { + struct userdatum *udm = to_userdatum(item); ++ char old_value[MAX_EXTRADATA_VALUE_LEN]; + struct netconsole_target *nt; + struct userdata *ud; + ssize_t ret; +@@ -1088,6 +1089,8 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, + + mutex_lock(&netconsole_subsys.su_mutex); + dynamic_netconsole_mutex_lock(); ++ /* Snapshot for rollback if update_userdata() fails below */ ++ strscpy(old_value, udm->value, sizeof(old_value)); + /* count is bounded above, so strscpy() cannot truncate here */ + strscpy(udm->value, buf, sizeof(udm->value)); + trim_newline(udm->value, sizeof(udm->value)); +@@ -1095,8 +1098,11 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, + ud = to_userdata(item->ci_parent); + nt = userdata_to_target(ud); + ret = update_userdata(nt); +- if (ret < 0) ++ if (ret < 0) { ++ /* Restore the previous value so it matches the live payload */ ++ strscpy(udm->value, old_value, sizeof(udm->value)); + goto out_unlock; ++ } + ret = count; + out_unlock: + dynamic_netconsole_mutex_unlock(); +-- +2.53.0 + diff --git a/queue-7.0/netconsole-return-count-instead-of-strnlen-buf-count.patch b/queue-7.0/netconsole-return-count-instead-of-strnlen-buf-count.patch new file mode 100644 index 0000000000..fbeaa3fd0e --- /dev/null +++ b/queue-7.0/netconsole-return-count-instead-of-strnlen-buf-count.patch @@ -0,0 +1,170 @@ +From 6b7557337b44c1ac98f12e57746f12d836b3f2cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Apr 2026 07:30:35 -0700 +Subject: netconsole: return count instead of strnlen(buf, count) from store + callbacks + +From: Breno Leitao + +[ Upstream commit d62c6f2df5c0e1390b9a1f45b1b52689e3f234f0 ] + +Several configfs store callbacks in netconsole end with: + + ret = strnlen(buf, count); + +This under-reports the number of bytes consumed when the input +contains an embedded NUL within count, telling the VFS that fewer +bytes were written than userspace actually handed in. A conformant +partial-write loop would then retry the trailing bytes against a +callback that has already accepted them. + +Every other configfs driver in the tree returns count directly from +its store callbacks once parsing has succeeded, including +drivers/nvme/target/configfs.c, drivers/gpio/gpio-sim.c, +drivers/most/configfs.c, drivers/block/null_blk/main.c, +drivers/pci/endpoint/pci-ep-cfs.c, and the rest of the configfs +users. netconsole was the outlier (along with +drivers/infiniband/core/cma_configfs.c, which has the same latent +issue). + +Align netconsole with the rest of the configfs ecosystem: return +count once the parser/validator has accepted the input. The numeric +and boolean parsers (kstrtobool, kstrtou16, mac_pton, +netpoll_parse_ip_addr) have already validated the meaningful prefix; +any trailing bytes are padding and should simply be reported as +consumed. + +Fixes: 0bcc1816188e ("[NET] netconsole: Support dynamic reconfiguration using configfs") +Reviewed-by: Simon Horman +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260427-netconsole_ai_fixes-v2-1-59965f29d9cc@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netconsole.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c +index 205384dab89a6..76d7fbf9e1883 100644 +--- a/drivers/net/netconsole.c ++++ b/drivers/net/netconsole.c +@@ -752,7 +752,7 @@ static ssize_t enabled_store(struct config_item *item, + unregister_netcons_consoles(); + } + +- ret = strnlen(buf, count); ++ ret = count; + /* Deferred cleanup */ + netconsole_process_cleanups(); + out_unlock: +@@ -781,7 +781,7 @@ static ssize_t release_store(struct config_item *item, const char *buf, + + nt->release = release; + +- ret = strnlen(buf, count); ++ ret = count; + out_unlock: + dynamic_netconsole_mutex_unlock(); + return ret; +@@ -807,7 +807,7 @@ static ssize_t extended_store(struct config_item *item, const char *buf, + goto out_unlock; + + nt->extended = extended; +- ret = strnlen(buf, count); ++ ret = count; + out_unlock: + dynamic_netconsole_mutex_unlock(); + return ret; +@@ -830,7 +830,7 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, + trim_newline(nt->np.dev_name, IFNAMSIZ); + + dynamic_netconsole_mutex_unlock(); +- return strnlen(buf, count); ++ return count; + } + + static ssize_t local_port_store(struct config_item *item, const char *buf, +@@ -849,7 +849,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf, + ret = kstrtou16(buf, 10, &nt->np.local_port); + if (ret < 0) + goto out_unlock; +- ret = strnlen(buf, count); ++ ret = count; + out_unlock: + dynamic_netconsole_mutex_unlock(); + return ret; +@@ -871,7 +871,7 @@ static ssize_t remote_port_store(struct config_item *item, + ret = kstrtou16(buf, 10, &nt->np.remote_port); + if (ret < 0) + goto out_unlock; +- ret = strnlen(buf, count); ++ ret = count; + out_unlock: + dynamic_netconsole_mutex_unlock(); + return ret; +@@ -896,7 +896,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, + goto out_unlock; + nt->np.ipv6 = !!ipv6; + +- ret = strnlen(buf, count); ++ ret = count; + out_unlock: + dynamic_netconsole_mutex_unlock(); + return ret; +@@ -921,7 +921,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, + goto out_unlock; + nt->np.ipv6 = !!ipv6; + +- ret = strnlen(buf, count); ++ ret = count; + out_unlock: + dynamic_netconsole_mutex_unlock(); + return ret; +@@ -957,7 +957,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf, + goto out_unlock; + memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); + +- ret = strnlen(buf, count); ++ ret = count; + out_unlock: + dynamic_netconsole_mutex_unlock(); + return ret; +@@ -1133,7 +1133,7 @@ static ssize_t sysdata_msgid_enabled_store(struct config_item *item, + disable_sysdata_feature(nt, SYSDATA_MSGID); + + unlock_ok: +- ret = strnlen(buf, count); ++ ret = count; + dynamic_netconsole_mutex_unlock(); + mutex_unlock(&netconsole_subsys.su_mutex); + return ret; +@@ -1162,7 +1162,7 @@ static ssize_t sysdata_release_enabled_store(struct config_item *item, + disable_sysdata_feature(nt, SYSDATA_RELEASE); + + unlock_ok: +- ret = strnlen(buf, count); ++ ret = count; + dynamic_netconsole_mutex_unlock(); + mutex_unlock(&netconsole_subsys.su_mutex); + return ret; +@@ -1191,7 +1191,7 @@ static ssize_t sysdata_taskname_enabled_store(struct config_item *item, + disable_sysdata_feature(nt, SYSDATA_TASKNAME); + + unlock_ok: +- ret = strnlen(buf, count); ++ ret = count; + dynamic_netconsole_mutex_unlock(); + mutex_unlock(&netconsole_subsys.su_mutex); + return ret; +@@ -1225,7 +1225,7 @@ static ssize_t sysdata_cpu_nr_enabled_store(struct config_item *item, + disable_sysdata_feature(nt, SYSDATA_CPU_NR); + + unlock_ok: +- ret = strnlen(buf, count); ++ ret = count; + dynamic_netconsole_mutex_unlock(); + mutex_unlock(&netconsole_subsys.su_mutex); + return ret; +-- +2.53.0 + diff --git a/queue-7.0/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch b/queue-7.0/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch new file mode 100644 index 0000000000..855925ba61 --- /dev/null +++ b/queue-7.0/netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch @@ -0,0 +1,43 @@ +From a03b8603065a26c937e4a42a4c60b65b043a4686 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 23:14:34 +0300 +Subject: netdevsim: zero initialize struct iphdr in dummy sk_buff + +From: Nikola Z. Ivanov + +[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ] + +Syzbot reports a KMSAN uninit-value originating from +nsim_dev_trap_skb_build, with the allocation also +being performed in the same function. + +Fix this by calling skb_put_zero instead of skb_put to +guarantee zero initialization of the whole IP header. + +Closes: https://syzkaller.appspot.com/bug?extid=23d7fcd204e3837866ff +Fixes: da58f90f11f5 ("netdevsim: Add devlink-trap support") +Signed-off-by: Nikola Z. Ivanov +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260426201434.742030-1-zlatistiv@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/netdevsim/dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c +index e82de0fd31579..8f6d0a09e1761 100644 +--- a/drivers/net/netdevsim/dev.c ++++ b/drivers/net/netdevsim/dev.c +@@ -829,7 +829,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) + skb->protocol = htons(ETH_P_IP); + + skb_set_network_header(skb, skb->len); +- iph = skb_put(skb, sizeof(struct iphdr)); ++ iph = skb_put_zero(skb, sizeof(struct iphdr)); + iph->protocol = IPPROTO_UDP; + iph->saddr = in_aton("192.0.2.1"); + iph->daddr = in_aton("198.51.100.1"); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch b/queue-7.0/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch new file mode 100644 index 0000000000..b5dc7456de --- /dev/null +++ b/queue-7.0/netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch @@ -0,0 +1,126 @@ +From 1ad5ce80e355e7fce7afdd57dc194808547a5705 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 23:15:32 +0200 +Subject: netfilter: arp_tables: fix IEEE1394 ARP payload parsing + +From: Pablo Neira Ayuso + +[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ] + +Weiming Shi says: + +"arp_packet_match() unconditionally parses the ARP payload assuming two +hardware addresses are present (source and target). However, +IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address +field, and arp_hdr_len() already accounts for this by returning a +shorter length for ARPHRD_IEEE1394 devices. + +As a result, on IEEE1394 interfaces arp_packet_match() advances past a +nonexistent target hardware address and reads the wrong bytes for both +the target device address comparison and the target IP address. This +causes arptables rules to match against garbage data, leading to +incorrect filtering decisions: packets that should be accepted may be +dropped and vice versa. + +The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already +handles this correctly by skipping the target hardware address for +ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()." + +Mangle the original patch to always return 0 (no match) in case user +matches on the target hardware address which is never present in +IEEE1394. + +Note that this returns 0 (no match) for either normal and inverse match +because matching in the target hardware address in ARPHRD_IEEE1394 has +never been supported by arptables. This is intentional, matching on the +target hardware address should never evaluate true for ARPHRD_IEEE1394. + +Moreover, adjust arpt_mangle to drop the packet too as AI suggests: + +In arpt_mangle, the logic assumes a standard ARP layout. Because +IEEE1394 (FireWire) omits the target hardware address, the linear +pointer arithmetic miscalculates the offset for the target IP address. +This causes mangling operations to write to the wrong location, leading +to packet corruption. To ensure safety, this patch drops packets +(NF_DROP) when mangling is requested for these fields on IEEE1394 +devices, as the current implementation cannot correctly map the FireWire +ARP payload. + +This omits both mangling target hardware and IP address. Even if IP +address mangling should be possible in IEEE1394, this would require +to adjust arpt_mangle offset calculation, which has never been +supported. + +Based on patch from Weiming Shi . + +Fixes: 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection.") +Reported-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- + net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c +index 1cdd9c28ab2da..97ead883e4a13 100644 +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, + arpptr += dev->addr_len; + memcpy(&src_ipaddr, arpptr, sizeof(u32)); + arpptr += sizeof(u32); +- tgt_devaddr = arpptr; +- arpptr += dev->addr_len; ++ ++ if (IS_ENABLED(CONFIG_FIREWIRE_NET) && dev->type == ARPHRD_IEEE1394) { ++ if (unlikely(memchr_inv(arpinfo->tgt_devaddr.mask, 0, ++ sizeof(arpinfo->tgt_devaddr.mask)))) ++ return 0; ++ ++ tgt_devaddr = NULL; ++ } else { ++ tgt_devaddr = arpptr; ++ arpptr += dev->addr_len; ++ } + memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); + + if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, + arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, +- dev->addr_len)) || ++ dev->addr_len))) ++ return 0; ++ ++ if (tgt_devaddr && + NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, + arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, + dev->addr_len))) +diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c +index a4e07e5e9c118..f65dd339208e8 100644 +--- a/net/ipv4/netfilter/arpt_mangle.c ++++ b/net/ipv4/netfilter/arpt_mangle.c +@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += pln; + if (mangle->flags & ARPT_MANGLE_TDEV) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_DEV_ADDR_LEN_MAX < hln || + (arpptr + hln > skb_tail_pointer(skb))) + return NF_DROP; +@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) + } + arpptr += hln; + if (mangle->flags & ARPT_MANGLE_TIP) { ++ if (unlikely(IS_ENABLED(CONFIG_FIREWIRE_NET) && ++ skb->dev->type == ARPHRD_IEEE1394)) ++ return NF_DROP; ++ + if (ARPT_MANGLE_ADDR_LEN_MAX < pln || + (arpptr + pln > skb_tail_pointer(skb))) + return NF_DROP; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-conntrack-remove-sprintf-usage.patch b/queue-7.0/netfilter-conntrack-remove-sprintf-usage.patch new file mode 100644 index 0000000000..7b846f2ac3 --- /dev/null +++ b/queue-7.0/netfilter-conntrack-remove-sprintf-usage.patch @@ -0,0 +1,182 @@ +From 8f5296af54d81724e3c57edde6a117bf86d22236 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 19:13:46 +0200 +Subject: netfilter: conntrack: remove sprintf usage + +From: Florian Westphal + +[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ] + +Replace it with scnprintf, the buffer sizes are expected to be large enough +to hold the result, no need for snprintf+overflow check. + +Increase buffer size in mangle_content_len() while at it. + +BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 +Write of size 1 at addr [..] + vsnprintf+0xea5/0x1270 + sprintf+0xb1/0xe0 + mangle_content_len+0x1ac/0x280 + nf_nat_sdp_session+0x1cc/0x240 + process_sdp+0x8f8/0xb80 + process_invite_request+0x108/0x2b0 + process_sip_msg+0x5da/0xf50 + sip_help_tcp+0x45e/0x780 + nf_confirm+0x34d/0x990 + [..] + +Fixes: 9fafcd7b2032 ("[NETFILTER]: nf_conntrack/nf_nat: add SIP helper port") +Reported-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_nat_amanda.c | 2 +- + net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c +index 98deef6cde694..8f1054920a857 100644 +--- a/net/netfilter/nf_nat_amanda.c ++++ b/net/netfilter/nf_nat_amanda.c +@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb, + return NF_DROP; + } + +- sprintf(buffer, "%u", port); ++ snprintf(buffer, sizeof(buffer), "%u", port); + if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, + protoff, matchoff, matchlen, + buffer, strlen(buffer))) { +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index cf4aeb299bdef..c845b6d1a2bdf 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, + } + + static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, bool delim) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4", &addr->ip); ++ return scnprintf(buffer, size, "%pI4", &addr->ip); + else { + if (delim) +- return sprintf(buffer, "[%pI6c]", &addr->ip6); ++ return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); + else +- return sprintf(buffer, "%pI6c", &addr->ip6); ++ return scnprintf(buffer, size, "%pI6c", &addr->ip6); + } + } + + static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, ++ size_t size, + const union nf_inet_addr *addr, u16 port) + { + if (nf_ct_l3num(ct) == NFPROTO_IPV4) +- return sprintf(buffer, "%pI4:%u", &addr->ip, port); ++ return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port); + else +- return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); ++ return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); + } + + static int map_addr(struct sk_buff *skb, unsigned int protoff, +@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, + if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) + return 1; + +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, true) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.dst.u3, + true); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + &addr, false) > 0 && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && + !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { +- buflen = sip_sprintf_addr(ct, buffer, ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), + &ct->tuplehash[!dir].tuple.src.u3, + false); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, +@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +- buflen = sprintf(buffer, "%u", ntohs(p)); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + poff, plen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle rport"); +@@ -418,7 +420,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, + + if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { +- buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); ++ buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), ++ &newaddr, port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) { + nf_ct_helper_log(skb, ct, "cannot mangle packet"); +@@ -438,8 +441,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++ char buffer[sizeof("4294967295")]; + unsigned int matchoff, matchlen; +- char buffer[sizeof("65536")]; + int buflen, c_len; + + /* Get actual SDP length */ +@@ -454,7 +457,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + return 0; + +- buflen = sprintf(buffer, "%u", c_len); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); + return mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen); + } +@@ -491,7 +494,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, + char buffer[INET6_ADDRSTRLEN]; + unsigned int buflen; + +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, + sdpoff, type, term, buffer, buflen)) + return 0; +@@ -509,7 +512,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + +- buflen = sprintf(buffer, "%u", port); ++ buflen = scnprintf(buffer, sizeof(buffer), "%u", port); + if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, + matchoff, matchlen, buffer, buflen)) + return 0; +@@ -529,7 +532,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ +- buflen = sip_sprintf_addr(ct, buffer, addr, false); ++ buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); + if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, + SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) + return 0; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nat-use-kfree_rcu-to-release-ops.patch b/queue-7.0/netfilter-nat-use-kfree_rcu-to-release-ops.patch new file mode 100644 index 0000000000..c15fdf0816 --- /dev/null +++ b/queue-7.0/netfilter-nat-use-kfree_rcu-to-release-ops.patch @@ -0,0 +1,114 @@ +From e31c5bbc42f77a9e3891f2a41eb6d069ab86b23d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:29:45 +0200 +Subject: netfilter: nat: use kfree_rcu to release ops + +From: Pablo Neira Ayuso + +[ Upstream commit 6eda0d771f94267f73f57c94630aa47e90957915 ] + +Florian Westphal says: + +"Historically this is not an issue, even for normal base hooks: the data +path doesn't use the original nf_hook_ops that are used to register the +callbacks. + +However, in v5.14 I added the ability to dump the active netfilter +hooks from userspace. + +This code will peek back into the nf_hook_ops that are available +at the tail of the pointer-array blob used by the datapath. + +The nat hooks are special, because they are called indirectly from +the central nat dispatcher hook. They are currently invisible to +the nfnl hook dump subsystem though. + +But once that changes the nat ops structures have to be deferred too." + +Update nf_nat_register_fn() to deal with partial exposition of the hooks +from error path which can be also an issue for nfnetlink_hook. + +Fixes: e2cf17d3774c ("netfilter: add new hook nfnl subsystem") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/ipv4/netfilter/iptable_nat.c | 4 ++-- + net/ipv6/netfilter/ip6table_nat.c | 4 ++-- + net/netfilter/nf_nat_core.c | 10 ++++++---- + 3 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index a5db7c67d61be..625a1ca13b1ba 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -79,7 +79,7 @@ static int ipt_nat_register_lookups(struct net *net) + while (i) + nf_nat_ipv4_unregister_fn(net, &ops[--i]); + +- kfree(ops); ++ kfree_rcu(ops, rcu); + return ret; + } + } +@@ -100,7 +100,7 @@ static void ipt_nat_unregister_lookups(struct net *net) + for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) + nf_nat_ipv4_unregister_fn(net, &ops[i]); + +- kfree(ops); ++ kfree_rcu(ops, rcu); + } + + static int iptable_nat_table_init(struct net *net) +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index e119d4f090cc8..5be723232df8f 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -81,7 +81,7 @@ static int ip6t_nat_register_lookups(struct net *net) + while (i) + nf_nat_ipv6_unregister_fn(net, &ops[--i]); + +- kfree(ops); ++ kfree_rcu(ops, rcu); + return ret; + } + } +@@ -102,7 +102,7 @@ static void ip6t_nat_unregister_lookups(struct net *net) + for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) + nf_nat_ipv6_unregister_fn(net, &ops[i]); + +- kfree(ops); ++ kfree_rcu(ops, rcu); + } + + static int ip6table_nat_table_init(struct net *net) +diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c +index 3b5434e4ec9c1..b30ca94c2bb7f 100644 +--- a/net/netfilter/nf_nat_core.c ++++ b/net/netfilter/nf_nat_core.c +@@ -1228,9 +1228,11 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, + ret = nf_register_net_hooks(net, nat_ops, ops_count); + if (ret < 0) { + mutex_unlock(&nf_nat_proto_mutex); +- for (i = 0; i < ops_count; i++) +- kfree(nat_ops[i].priv); +- kfree(nat_ops); ++ for (i = 0; i < ops_count; i++) { ++ priv = nat_ops[i].priv; ++ kfree_rcu(priv, rcu_head); ++ } ++ kfree_rcu(nat_ops, rcu); + return ret; + } + +@@ -1294,7 +1296,7 @@ void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, + } + + nat_proto_net->nat_hook_ops = NULL; +- kfree(nat_ops); ++ kfree_rcu(nat_ops, rcu); + } + unlock: + mutex_unlock(&nf_nat_proto_mutex); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch b/queue-7.0/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch new file mode 100644 index 0000000000..f6c30683f9 --- /dev/null +++ b/queue-7.0/netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch @@ -0,0 +1,352 @@ +From fb1a86afe54db89161bc76243be45cd9f22c1893 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 02:19:11 +0200 +Subject: netfilter: nf_conntrack_sip: don't use simple_strtoul +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Florian Westphal + +[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ] + +Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), +and ct_sip_parse_request() with a new sip_parse_port() helper that +validates each digit against the buffer limit, eliminating the use of +simple_strtoul() which assumes NUL-terminated strings. + +The previous code dereferenced pointers without bounds checks after +sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated +skb data. A port that reaches the buffer limit without a trailing +character is also rejected as malformed. + +Also get rid of all simple_strtoul() usage in conntrack, prefer a +stricter version instead. There are intentional changes: + +- Bail out if number is > UINT_MAX and indicate a failure, same for + too long sequences. + While we do accept 05535 as port 5535, we will not accept e.g. + 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, + we should restrict this to not waste cycles when presented with + malformed packets with 64k '0' characters. + +- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch + 'expire=' and 'rports='; both are expected to use base-10. + +- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k + range. + +- epaddr_len now returns 0 if the port is invalid, as it already does + for invalid ip addresses. This is intentional. nf_conntrack_sip + performs lots of guesswork to find the right parts of the message + to parse. Being stricter could break existing setups. + Connection tracking helpers are designed to allow traffic to + pass, not to block it. + +Based on an earlier patch from Jenny Guanni Qu . + +Fixes: 05e3ced297fe ("[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper") +Reported-by: Klaudia Kloc +Reported-by: Dawid Moczadło +Reported-by: Jenny Guanni Qu . +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- + net/netfilter/nf_nat_sip.c | 1 + + 2 files changed, 119 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index 939502ff7c871..6eb39285fbd6c 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp, + return 1; + } + ++/* Parse optional port number after IP address. ++ * Returns false on malformed input, true otherwise. ++ * If port is non-NULL, stores parsed port in network byte order. ++ * If no port is present, sets *port to default SIP port. ++ */ ++static bool sip_parse_port(const char *dptr, const char **endp, ++ const char *limit, __be16 *port) ++{ ++ unsigned int p = 0; ++ int len = 0; ++ ++ if (dptr >= limit) ++ return false; ++ ++ if (*dptr != ':') { ++ if (port) ++ *port = htons(SIP_PORT); ++ if (endp) ++ *endp = dptr; ++ return true; ++ } ++ ++ dptr++; /* skip ':' */ ++ ++ while (dptr < limit && isdigit(*dptr)) { ++ p = p * 10 + (*dptr - '0'); ++ dptr++; ++ len++; ++ if (len > 5) /* max "65535" */ ++ return false; ++ } ++ ++ if (len == 0) ++ return false; ++ ++ /* reached limit while parsing port */ ++ if (dptr >= limit) ++ return false; ++ ++ if (p < 1024 || p > 65535) ++ return false; ++ ++ if (port) ++ *port = htons(p); ++ ++ if (endp) ++ *endp = dptr; ++ ++ return true; ++} ++ + /* skip ip address. returns its length. */ + static int epaddr_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, + return 0; + } + +- /* Port number */ +- if (*dptr == ':') { +- dptr++; +- dptr += digits_len(ct, dptr, limit, shift); +- } ++ if (!sip_parse_port(dptr, &dptr, limit, NULL)) ++ return 0; + return dptr - aux; + } + +@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, + return epaddr_len(ct, dptr, limit, shift); + } + ++/* simple_strtoul stops after first non-number character. ++ * But as we're not dealing with c-strings, we can't rely on ++ * hitting \r,\n,\0 etc. before moving past end of buffer. ++ * ++ * This is a variant of simple_strtoul, but doesn't require ++ * a c-string. ++ * ++ * If value exceeds UINT_MAX, 0 is returned. ++ */ ++static unsigned int sip_strtouint(const char *cp, unsigned int len, char **endp) ++{ ++ const unsigned int max = sizeof("4294967295"); ++ unsigned int olen = len; ++ const char *s = cp; ++ u64 result = 0; ++ ++ if (len > max) ++ len = max; ++ ++ while (olen > 0 && isdigit(*s)) { ++ unsigned int value; ++ ++ if (len == 0) ++ goto err; ++ ++ value = *s - '0'; ++ result = result * 10 + value; ++ ++ if (result > UINT_MAX) ++ goto err; ++ s++; ++ len--; ++ olen--; ++ } ++ ++ if (endp) ++ *endp = (char *)s; ++ ++ return result; ++err: ++ if (endp) ++ *endp = (char *)cp; ++ return 0; ++} ++ + /* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF +@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, + { + const char *start = dptr, *limit = dptr + datalen, *end; + unsigned int mlen; +- unsigned int p; + int shift = 0; + + /* Skip method and following whitespace */ +@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct, + + if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) + return -1; +- if (end < limit && *end == ':') { +- end++; +- p = simple_strtoul(end, (char **)&end, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(end, &end, limit, port)) ++ return -1; + + if (end == dptr) + return 0; +@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + union nf_inet_addr *addr, __be16 *port) + { + const char *c, *limit = dptr + datalen; +- unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, +@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + + if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) + return -1; +- if (*c == ':') { +- c++; +- p = simple_strtoul(c, (char **)&c, 10); +- if (p < 1024 || p > 65535) +- return -1; +- *port = htons(p); +- } else +- *port = htons(SIP_PORT); ++ if (!sip_parse_port(c, &c, limit, port)) ++ return -1; + + if (dataoff) + *dataoff = c - dptr; +@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + return 0; + + start += strlen(name); +- *val = simple_strtoul(start, &end, 0); ++ *val = sip_strtouint(start, limit - start, (char **)&end); + if (start == end) + return -1; + if (matchoff && matchlen) { +@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { ++ char *end; ++ + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) +@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, + mediaoff += t->len; + medialen -= t->len; + +- port = simple_strtoul(*dptr + mediaoff, NULL, 10); +- if (port == 0) ++ port = sip_strtouint(*dptr + mediaoff, *datalen - mediaoff, (char **)&end); ++ if (port == 0 || *dptr + mediaoff == end) + continue; + if (port < 1024 || port > 65535) { + nf_ct_helper_log(skb, ct, "wrong port %u", port); +@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, +@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff, + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) +- expires = simple_strtoul(*dptr + matchoff, NULL, 10); ++ expires = sip_strtouint(*dptr + matchoff, *datalen - matchoff, NULL); + + while (1) { + unsigned int c_expires = expires; +@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen, matchend; + unsigned int code, cseq, i; ++ char *end; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; +- code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); ++ code = sip_strtouint(*dptr + strlen("SIP/2.0 "), ++ *datalen - strlen("SIP/2.0 "), NULL); + if (!code) { + nf_ct_helper_log(skb, ct, "cannot get code"); + return NF_DROP; +@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + const struct sip_handler *handler; ++ char *end; + + handler = &sip_handlers[i]; + if (handler->request == NULL) +@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_helper_log(skb, ct, "cannot parse cseq"); + return NF_DROP; + } +- cseq = simple_strtoul(*dptr + matchoff, NULL, 10); +- if (!cseq && *(*dptr + matchoff) != '0') { ++ cseq = sip_strtouint(*dptr + matchoff, *datalen - matchoff, (char **)&end); ++ if (*dptr + matchoff == end) { + nf_ct_helper_log(skb, ct, "cannot get cseq"); + return NF_DROP; + } +@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, + &matchoff, &matchlen) <= 0) + break; + +- clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); ++ clen = sip_strtouint(dptr + matchoff, datalen - matchoff, (char **)&end); + if (dptr + matchoff == end) + break; + +diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c +index c845b6d1a2bdf..9fbfc6bff0c22 100644 +--- a/net/netfilter/nf_nat_sip.c ++++ b/net/netfilter/nf_nat_sip.c +@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, + if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, + "rport=", &poff, &plen, + &n) > 0 && ++ n >= 1024 && n <= 65535 && + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nf_tables-add-hook-transactions-for-device.patch b/queue-7.0/netfilter-nf_tables-add-hook-transactions-for-device.patch new file mode 100644 index 0000000000..a1b94a87a1 --- /dev/null +++ b/queue-7.0/netfilter-nf_tables-add-hook-transactions-for-device.patch @@ -0,0 +1,612 @@ +From ecec6f8daa9c2e116a7d557bb042835da93eb562 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 22:58:23 +0200 +Subject: netfilter: nf_tables: add hook transactions for device deletions + +From: Pablo Neira Ayuso + +[ Upstream commit 10f79dbd7719d1da9f5884d13060322d8729f091 ] + +Restore the flag that indicates that the hook is going away, ie. +NFT_HOOK_REMOVE, but add a new transaction object to track deletion +of hooks without altering the basechain/flowtable hook_list during +the preparation phase. + +The existing approach that moves the hook from the basechain/flowtable +hook_list to transaction hook_list breaks netlink dump path readers +of this RCU-protected list. + +It should be possible use an array for nft_trans_hook to store the +deleted hooks to compact the representation but I am not expecting +many hook object, specially now that wildcard support for devices +is in place. + +Note that the nft_trans_chain_hooks() list contains a list of struct +nft_trans_hook objects for DELCHAIN and DELFLOWTABLE commands, while +this list stores struct nft_hook objects for NEWCHAIN and NEWFLOWTABLE. +Note that new commands can be updated to use nft_trans_hook for +consistency. + +This patch also adapts the event notification path to deal with the list +of hook transactions. + +Fixes: 7d937b107108 ("netfilter: nf_tables: support for deleting devices in an existing netdev chain") +Fixes: b6d9014a3335 ("netfilter: nf_tables: delete flowtable hooks via transaction list") +Reported-by: Xiang Mei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables.h | 13 ++ + net/netfilter/nf_tables_api.c | 264 +++++++++++++++++++++++------- + 2 files changed, 217 insertions(+), 60 deletions(-) + +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index ec8a8ec9c0aa6..3ec41574af776 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -1216,12 +1216,15 @@ struct nft_stats { + struct u64_stats_sync syncp; + }; + ++#define NFT_HOOK_REMOVE (1 << 0) ++ + struct nft_hook { + struct list_head list; + struct list_head ops_list; + struct rcu_head rcu; + char ifname[IFNAMSIZ]; + u8 ifnamelen; ++ u8 flags; + }; + + struct nf_hook_ops *nft_hook_find_ops(const struct nft_hook *hook, +@@ -1676,6 +1679,16 @@ struct nft_trans { + u8 put_net:1; + }; + ++/** ++ * struct nft_trans_hook - nf_tables hook update in transaction ++ * @list: used internally ++ * @hook: struct nft_hook with the device hook ++ */ ++struct nft_trans_hook { ++ struct list_head list; ++ struct nft_hook *hook; ++}; ++ + /** + * struct nft_trans_binding - nf_tables object with binding support in transaction + * @nft_trans: base structure, MUST be first member +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 8c0706d6d8873..7927cd48798bf 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -380,6 +380,32 @@ static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook) + nft_netdev_hook_free_rcu(hook); + } + ++static void nft_trans_hook_destroy(struct nft_trans_hook *trans_hook) ++{ ++ list_del(&trans_hook->list); ++ kfree(trans_hook); ++} ++ ++static void nft_netdev_unregister_trans_hook(struct net *net, ++ const struct nft_table *table, ++ struct list_head *hook_list) ++{ ++ struct nft_trans_hook *trans_hook, *next; ++ struct nf_hook_ops *ops; ++ struct nft_hook *hook; ++ ++ list_for_each_entry_safe(trans_hook, next, hook_list, list) { ++ hook = trans_hook->hook; ++ ++ if (!(table->flags & NFT_TABLE_F_DORMANT)) { ++ list_for_each_entry(ops, &hook->ops_list, list) ++ nf_unregister_net_hook(net, ops); ++ } ++ nft_netdev_hook_unlink_free_rcu(hook); ++ nft_trans_hook_destroy(trans_hook); ++ } ++} ++ + static void nft_netdev_unregister_hooks(struct net *net, + struct list_head *hook_list, + bool release_netdev) +@@ -1998,15 +2024,69 @@ static int nft_nla_put_hook_dev(struct sk_buff *skb, struct nft_hook *hook) + return nla_put_string(skb, attr, hook->ifname); + } + ++struct nft_hook_dump_ctx { ++ struct nft_hook *first; ++ int n; ++}; ++ ++static int nft_dump_basechain_hook_one(struct sk_buff *skb, ++ struct nft_hook *hook, ++ struct nft_hook_dump_ctx *dump_ctx) ++{ ++ if (!dump_ctx->first) ++ dump_ctx->first = hook; ++ ++ if (nft_nla_put_hook_dev(skb, hook)) ++ return -1; ++ ++ dump_ctx->n++; ++ ++ return 0; ++} ++ ++static int nft_dump_basechain_hook_list(struct sk_buff *skb, ++ const struct net *net, ++ const struct list_head *hook_list, ++ struct nft_hook_dump_ctx *dump_ctx) ++{ ++ struct nft_hook *hook; ++ int err; ++ ++ list_for_each_entry_rcu(hook, hook_list, list, ++ lockdep_commit_lock_is_held(net)) { ++ err = nft_dump_basechain_hook_one(skb, hook, dump_ctx); ++ if (err < 0) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int nft_dump_basechain_trans_hook_list(struct sk_buff *skb, ++ const struct list_head *trans_hook_list, ++ struct nft_hook_dump_ctx *dump_ctx) ++{ ++ struct nft_trans_hook *trans_hook; ++ int err; ++ ++ list_for_each_entry(trans_hook, trans_hook_list, list) { ++ err = nft_dump_basechain_hook_one(skb, trans_hook->hook, dump_ctx); ++ if (err < 0) ++ return err; ++ } ++ ++ return 0; ++} ++ + static int nft_dump_basechain_hook(struct sk_buff *skb, + const struct net *net, int family, + const struct nft_base_chain *basechain, +- const struct list_head *hook_list) ++ const struct list_head *hook_list, ++ const struct list_head *trans_hook_list) + { + const struct nf_hook_ops *ops = &basechain->ops; +- struct nft_hook *hook, *first = NULL; ++ struct nft_hook_dump_ctx dump_hook_ctx = {}; + struct nlattr *nest, *nest_devs; +- int n = 0; + + nest = nla_nest_start_noflag(skb, NFTA_CHAIN_HOOK); + if (nest == NULL) +@@ -2021,23 +2101,23 @@ static int nft_dump_basechain_hook(struct sk_buff *skb, + if (!nest_devs) + goto nla_put_failure; + +- if (!hook_list) ++ if (!hook_list && !trans_hook_list) + hook_list = &basechain->hook_list; + +- list_for_each_entry_rcu(hook, hook_list, list, +- lockdep_commit_lock_is_held(net)) { +- if (!first) +- first = hook; +- +- if (nft_nla_put_hook_dev(skb, hook)) +- goto nla_put_failure; +- n++; ++ if (hook_list && ++ nft_dump_basechain_hook_list(skb, net, hook_list, &dump_hook_ctx)) { ++ goto nla_put_failure; ++ } else if (trans_hook_list && ++ nft_dump_basechain_trans_hook_list(skb, trans_hook_list, ++ &dump_hook_ctx)) { ++ goto nla_put_failure; + } ++ + nla_nest_end(skb, nest_devs); + +- if (n == 1 && +- !hook_is_prefix(first) && +- nla_put_string(skb, NFTA_HOOK_DEV, first->ifname)) ++ if (dump_hook_ctx.n == 1 && ++ !hook_is_prefix(dump_hook_ctx.first) && ++ nla_put_string(skb, NFTA_HOOK_DEV, dump_hook_ctx.first->ifname)) + goto nla_put_failure; + } + nla_nest_end(skb, nest); +@@ -2051,7 +2131,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net, + u32 portid, u32 seq, int event, u32 flags, + int family, const struct nft_table *table, + const struct nft_chain *chain, +- const struct list_head *hook_list) ++ const struct list_head *hook_list, ++ const struct list_head *trans_hook_list) + { + struct nlmsghdr *nlh; + +@@ -2067,7 +2148,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net, + NFTA_CHAIN_PAD)) + goto nla_put_failure; + +- if (!hook_list && ++ if (!hook_list && !trans_hook_list && + (event == NFT_MSG_DELCHAIN || + event == NFT_MSG_DESTROYCHAIN)) { + nlmsg_end(skb, nlh); +@@ -2078,7 +2159,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net, + const struct nft_base_chain *basechain = nft_base_chain(chain); + struct nft_stats __percpu *stats; + +- if (nft_dump_basechain_hook(skb, net, family, basechain, hook_list)) ++ if (nft_dump_basechain_hook(skb, net, family, basechain, ++ hook_list, trans_hook_list)) + goto nla_put_failure; + + if (nla_put_be32(skb, NFTA_CHAIN_POLICY, +@@ -2114,7 +2196,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net, + } + + static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event, +- const struct list_head *hook_list) ++ const struct list_head *hook_list, ++ const struct list_head *trans_hook_list) + { + struct nftables_pernet *nft_net; + struct sk_buff *skb; +@@ -2134,7 +2217,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event, + + err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq, + event, flags, ctx->family, ctx->table, +- ctx->chain, hook_list); ++ ctx->chain, hook_list, trans_hook_list); + if (err < 0) { + kfree_skb(skb); + goto err; +@@ -2180,7 +2263,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb, + NFT_MSG_NEWCHAIN, + NLM_F_MULTI, + table->family, table, +- chain, NULL) < 0) ++ chain, NULL, NULL) < 0) + goto done; + + nl_dump_check_consistent(cb, nlmsg_hdr(skb)); +@@ -2234,7 +2317,7 @@ static int nf_tables_getchain(struct sk_buff *skb, const struct nfnl_info *info, + + err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid, + info->nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, +- 0, family, table, chain, NULL); ++ 0, family, table, chain, NULL, NULL); + if (err < 0) + goto err_fill_chain_info; + +@@ -2397,8 +2480,12 @@ static struct nft_hook *nft_hook_list_find(struct list_head *hook_list, + + list_for_each_entry(hook, hook_list, list) { + if (!strncmp(hook->ifname, this->ifname, +- min(hook->ifnamelen, this->ifnamelen))) ++ min(hook->ifnamelen, this->ifnamelen))) { ++ if (hook->flags & NFT_HOOK_REMOVE) ++ continue; ++ + return hook; ++ } + } + + return NULL; +@@ -3157,6 +3244,32 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info, + return nf_tables_addchain(&ctx, family, policy, flags, extack); + } + ++static int nft_trans_delhook(struct nft_hook *hook, ++ struct list_head *del_list) ++{ ++ struct nft_trans_hook *trans_hook; ++ ++ trans_hook = kmalloc_obj(*trans_hook, GFP_KERNEL); ++ if (!trans_hook) ++ return -ENOMEM; ++ ++ trans_hook->hook = hook; ++ list_add_tail(&trans_hook->list, del_list); ++ hook->flags |= NFT_HOOK_REMOVE; ++ ++ return 0; ++} ++ ++static void nft_trans_delhook_abort(struct list_head *del_list) ++{ ++ struct nft_trans_hook *trans_hook, *next; ++ ++ list_for_each_entry_safe(trans_hook, next, del_list, list) { ++ trans_hook->hook->flags &= ~NFT_HOOK_REMOVE; ++ nft_trans_hook_destroy(trans_hook); ++ } ++} ++ + static int nft_delchain_hook(struct nft_ctx *ctx, + struct nft_base_chain *basechain, + struct netlink_ext_ack *extack) +@@ -3183,7 +3296,10 @@ static int nft_delchain_hook(struct nft_ctx *ctx, + err = -ENOENT; + goto err_chain_del_hook; + } +- list_move(&hook->list, &chain_del_list); ++ if (nft_trans_delhook(hook, &chain_del_list) < 0) { ++ err = -ENOMEM; ++ goto err_chain_del_hook; ++ } + } + + trans = nft_trans_alloc_chain(ctx, NFT_MSG_DELCHAIN); +@@ -3203,7 +3319,7 @@ static int nft_delchain_hook(struct nft_ctx *ctx, + return 0; + + err_chain_del_hook: +- list_splice(&chain_del_list, &basechain->hook_list); ++ nft_trans_delhook_abort(&chain_del_list); + nft_chain_release_hook(&chain_hook); + + return err; +@@ -8992,6 +9108,24 @@ static void nft_hooks_destroy(struct list_head *hook_list) + nft_netdev_hook_unlink_free_rcu(hook); + } + ++static void nft_flowtable_unregister_trans_hook(struct net *net, ++ struct nft_flowtable *flowtable, ++ struct list_head *hook_list) ++{ ++ struct nft_trans_hook *trans_hook, *next; ++ struct nf_hook_ops *ops; ++ struct nft_hook *hook; ++ ++ list_for_each_entry_safe(trans_hook, next, hook_list, list) { ++ hook = trans_hook->hook; ++ list_for_each_entry(ops, &hook->ops_list, list) ++ nft_unregister_flowtable_ops(net, flowtable, ops); ++ ++ nft_netdev_hook_unlink_free_rcu(hook); ++ nft_trans_hook_destroy(trans_hook); ++ } ++} ++ + static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, + struct nft_flowtable *flowtable, + struct netlink_ext_ack *extack) +@@ -9250,7 +9384,10 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx, + err = -ENOENT; + goto err_flowtable_del_hook; + } +- list_move(&hook->list, &flowtable_del_list); ++ if (nft_trans_delhook(hook, &flowtable_del_list) < 0) { ++ err = -ENOMEM; ++ goto err_flowtable_del_hook; ++ } + } + + trans = nft_trans_alloc(ctx, NFT_MSG_DELFLOWTABLE, +@@ -9271,7 +9408,7 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx, + return 0; + + err_flowtable_del_hook: +- list_splice(&flowtable_del_list, &flowtable->hook_list); ++ nft_trans_delhook_abort(&flowtable_del_list); + nft_flowtable_hook_release(&flowtable_hook); + + return err; +@@ -9336,8 +9473,10 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, + u32 portid, u32 seq, int event, + u32 flags, int family, + struct nft_flowtable *flowtable, +- struct list_head *hook_list) ++ struct list_head *hook_list, ++ struct list_head *trans_hook_list) + { ++ struct nft_trans_hook *trans_hook; + struct nlattr *nest, *nest_devs; + struct nft_hook *hook; + struct nlmsghdr *nlh; +@@ -9354,7 +9493,7 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, + NFTA_FLOWTABLE_PAD)) + goto nla_put_failure; + +- if (!hook_list && ++ if (!hook_list && !trans_hook_list && + (event == NFT_MSG_DELFLOWTABLE || + event == NFT_MSG_DESTROYFLOWTABLE)) { + nlmsg_end(skb, nlh); +@@ -9376,13 +9515,20 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net, + if (!nest_devs) + goto nla_put_failure; + +- if (!hook_list) ++ if (!hook_list && !trans_hook_list) + hook_list = &flowtable->hook_list; + +- list_for_each_entry_rcu(hook, hook_list, list, +- lockdep_commit_lock_is_held(net)) { +- if (nft_nla_put_hook_dev(skb, hook)) +- goto nla_put_failure; ++ if (hook_list) { ++ list_for_each_entry_rcu(hook, hook_list, list, ++ lockdep_commit_lock_is_held(net)) { ++ if (nft_nla_put_hook_dev(skb, hook)) ++ goto nla_put_failure; ++ } ++ } else if (trans_hook_list) { ++ list_for_each_entry(trans_hook, trans_hook_list, list) { ++ if (nft_nla_put_hook_dev(skb, trans_hook->hook)) ++ goto nla_put_failure; ++ } + } + nla_nest_end(skb, nest_devs); + nla_nest_end(skb, nest); +@@ -9436,7 +9582,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb, + NFT_MSG_NEWFLOWTABLE, + NLM_F_MULTI | NLM_F_APPEND, + table->family, +- flowtable, NULL) < 0) ++ flowtable, NULL, NULL) < 0) + goto done; + + nl_dump_check_consistent(cb, nlmsg_hdr(skb)); +@@ -9536,7 +9682,7 @@ static int nf_tables_getflowtable(struct sk_buff *skb, + err = nf_tables_fill_flowtable_info(skb2, net, NETLINK_CB(skb).portid, + info->nlh->nlmsg_seq, + NFT_MSG_NEWFLOWTABLE, 0, family, +- flowtable, NULL); ++ flowtable, NULL, NULL); + if (err < 0) + goto err_fill_flowtable_info; + +@@ -9549,7 +9695,9 @@ static int nf_tables_getflowtable(struct sk_buff *skb, + + static void nf_tables_flowtable_notify(struct nft_ctx *ctx, + struct nft_flowtable *flowtable, +- struct list_head *hook_list, int event) ++ struct list_head *hook_list, ++ struct list_head *trans_hook_list, ++ int event) + { + struct nftables_pernet *nft_net = nft_pernet(ctx->net); + struct sk_buff *skb; +@@ -9569,7 +9717,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx, + + err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid, + ctx->seq, event, flags, +- ctx->family, flowtable, hook_list); ++ ctx->family, flowtable, ++ hook_list, trans_hook_list); + if (err < 0) { + kfree_skb(skb); + goto err; +@@ -10103,9 +10252,7 @@ static void nft_commit_release(struct nft_trans *trans) + break; + case NFT_MSG_DELCHAIN: + case NFT_MSG_DESTROYCHAIN: +- if (nft_trans_chain_update(trans)) +- nft_hooks_destroy(&nft_trans_chain_hooks(trans)); +- else ++ if (!nft_trans_chain_update(trans)) + nf_tables_chain_destroy(nft_trans_chain(trans)); + break; + case NFT_MSG_DELRULE: +@@ -10126,9 +10273,7 @@ static void nft_commit_release(struct nft_trans *trans) + break; + case NFT_MSG_DELFLOWTABLE: + case NFT_MSG_DESTROYFLOWTABLE: +- if (nft_trans_flowtable_update(trans)) +- nft_hooks_destroy(&nft_trans_flowtable_hooks(trans)); +- else ++ if (!nft_trans_flowtable_update(trans)) + nf_tables_flowtable_destroy(nft_trans_flowtable(trans)); + break; + } +@@ -10903,31 +11048,28 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) + if (nft_trans_chain_update(trans)) { + nft_chain_commit_update(nft_trans_container_chain(trans)); + nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, +- &nft_trans_chain_hooks(trans)); ++ &nft_trans_chain_hooks(trans), NULL); + list_splice_rcu(&nft_trans_chain_hooks(trans), + &nft_trans_basechain(trans)->hook_list); + /* trans destroyed after rcu grace period */ + } else { + nft_chain_commit_drop_policy(nft_trans_container_chain(trans)); + nft_clear(net, nft_trans_chain(trans)); +- nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL); ++ nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, NULL, NULL); + nft_trans_destroy(trans); + } + break; + case NFT_MSG_DELCHAIN: + case NFT_MSG_DESTROYCHAIN: + if (nft_trans_chain_update(trans)) { +- nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, ++ nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, NULL, + &nft_trans_chain_hooks(trans)); +- if (!(table->flags & NFT_TABLE_F_DORMANT)) { +- nft_netdev_unregister_hooks(net, +- &nft_trans_chain_hooks(trans), +- true); +- } ++ nft_netdev_unregister_trans_hook(net, table, ++ &nft_trans_chain_hooks(trans)); + } else { + nft_chain_del(nft_trans_chain(trans)); + nf_tables_chain_notify(&ctx, NFT_MSG_DELCHAIN, +- NULL); ++ NULL, NULL); + nf_tables_unregister_hook(ctx.net, ctx.table, + nft_trans_chain(trans)); + } +@@ -11033,6 +11175,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) + nf_tables_flowtable_notify(&ctx, + nft_trans_flowtable(trans), + &nft_trans_flowtable_hooks(trans), ++ NULL, + NFT_MSG_NEWFLOWTABLE); + list_splice_rcu(&nft_trans_flowtable_hooks(trans), + &nft_trans_flowtable(trans)->hook_list); +@@ -11041,6 +11184,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) + nf_tables_flowtable_notify(&ctx, + nft_trans_flowtable(trans), + NULL, ++ NULL, + NFT_MSG_NEWFLOWTABLE); + } + nft_trans_destroy(trans); +@@ -11050,16 +11194,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) + if (nft_trans_flowtable_update(trans)) { + nf_tables_flowtable_notify(&ctx, + nft_trans_flowtable(trans), ++ NULL, + &nft_trans_flowtable_hooks(trans), + trans->msg_type); +- nft_unregister_flowtable_net_hooks(net, +- nft_trans_flowtable(trans), +- &nft_trans_flowtable_hooks(trans)); ++ nft_flowtable_unregister_trans_hook(net, ++ nft_trans_flowtable(trans), ++ &nft_trans_flowtable_hooks(trans)); + } else { + list_del_rcu(&nft_trans_flowtable(trans)->list); + nf_tables_flowtable_notify(&ctx, + nft_trans_flowtable(trans), + NULL, ++ NULL, + trans->msg_type); + nft_unregister_flowtable_net_hooks(net, + nft_trans_flowtable(trans), +@@ -11223,8 +11369,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) + case NFT_MSG_DELCHAIN: + case NFT_MSG_DESTROYCHAIN: + if (nft_trans_chain_update(trans)) { +- list_splice(&nft_trans_chain_hooks(trans), +- &nft_trans_basechain(trans)->hook_list); ++ nft_trans_delhook_abort(&nft_trans_chain_hooks(trans)); + } else { + nft_use_inc_restore(&table->use); + nft_clear(trans->net, nft_trans_chain(trans)); +@@ -11338,8 +11483,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) + case NFT_MSG_DELFLOWTABLE: + case NFT_MSG_DESTROYFLOWTABLE: + if (nft_trans_flowtable_update(trans)) { +- list_splice(&nft_trans_flowtable_hooks(trans), +- &nft_trans_flowtable(trans)->hook_list); ++ nft_trans_delhook_abort(&nft_trans_flowtable_hooks(trans)); + } else { + nft_use_inc_restore(&table->use); + nft_clear(trans->net, nft_trans_flowtable(trans)); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nf_tables-join-hook-list-via-splice_list_r.patch b/queue-7.0/netfilter-nf_tables-join-hook-list-via-splice_list_r.patch new file mode 100644 index 0000000000..6d41807b40 --- /dev/null +++ b/queue-7.0/netfilter-nf_tables-join-hook-list-via-splice_list_r.patch @@ -0,0 +1,51 @@ +From 41589c02ac8b79a63cb9586e76c49b24238bc379 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:56:14 +0200 +Subject: netfilter: nf_tables: join hook list via splice_list_rcu() in commit + phase + +From: Pablo Neira Ayuso + +[ Upstream commit a6134e62dba2ea4f760b29d5226907f447c92400 ] + +Publish new hooks in the list into the basechain/flowtable using +splice_list_rcu() to ensure netlink dump list traversal via rcu is safe +while concurrent ruleset update is going on. + +Fixes: 78d9f48f7f44 ("netfilter: nf_tables: add devices to existing flowtable") +Fixes: b9703ed44ffb ("netfilter: nf_tables: support for adding new devices to an existing netdev chain") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 090d4d688a333..8c0706d6d8873 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -10904,8 +10904,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) + nft_chain_commit_update(nft_trans_container_chain(trans)); + nf_tables_chain_notify(&ctx, NFT_MSG_NEWCHAIN, + &nft_trans_chain_hooks(trans)); +- list_splice(&nft_trans_chain_hooks(trans), +- &nft_trans_basechain(trans)->hook_list); ++ list_splice_rcu(&nft_trans_chain_hooks(trans), ++ &nft_trans_basechain(trans)->hook_list); + /* trans destroyed after rcu grace period */ + } else { + nft_chain_commit_drop_policy(nft_trans_container_chain(trans)); +@@ -11034,8 +11034,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) + nft_trans_flowtable(trans), + &nft_trans_flowtable_hooks(trans), + NFT_MSG_NEWFLOWTABLE); +- list_splice(&nft_trans_flowtable_hooks(trans), +- &nft_trans_flowtable(trans)->hook_list); ++ list_splice_rcu(&nft_trans_flowtable_hooks(trans), ++ &nft_trans_flowtable(trans)->hook_list); + } else { + nft_clear(net, nft_trans_flowtable(trans)); + nf_tables_flowtable_notify(&ctx, +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nf_tables-use-list_del_rcu-for-netlink-hoo.patch b/queue-7.0/netfilter-nf_tables-use-list_del_rcu-for-netlink-hoo.patch new file mode 100644 index 0000000000..90300057ba --- /dev/null +++ b/queue-7.0/netfilter-nf_tables-use-list_del_rcu-for-netlink-hoo.patch @@ -0,0 +1,137 @@ +From 5f79229edb16a598276357db2547133a9e4121ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 15:14:51 +0200 +Subject: netfilter: nf_tables: use list_del_rcu for netlink hooks + +From: Florian Westphal + +[ Upstream commit f3224ee463f8f6f6ced7dcdf6081add4f8128527 ] + +nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks need +to use list_del_rcu(), this list can be walked by concurrent dumpers. + +Add a new helper and use it consistently. + +Fixes: f9a43007d3f7 ("netfilter: nf_tables: double hook unregistration in netns path") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 44 ++++++++++++++--------------------- + 1 file changed, 18 insertions(+), 26 deletions(-) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 8c42247a176c7..090d4d688a333 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -374,6 +374,12 @@ static void nft_netdev_hook_free_rcu(struct nft_hook *hook) + call_rcu(&hook->rcu, __nft_netdev_hook_free_rcu); + } + ++static void nft_netdev_hook_unlink_free_rcu(struct nft_hook *hook) ++{ ++ list_del_rcu(&hook->list); ++ nft_netdev_hook_free_rcu(hook); ++} ++ + static void nft_netdev_unregister_hooks(struct net *net, + struct list_head *hook_list, + bool release_netdev) +@@ -384,10 +390,8 @@ static void nft_netdev_unregister_hooks(struct net *net, + list_for_each_entry_safe(hook, next, hook_list, list) { + list_for_each_entry(ops, &hook->ops_list, list) + nf_unregister_net_hook(net, ops); +- if (release_netdev) { +- list_del(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ if (release_netdev) ++ nft_netdev_hook_unlink_free_rcu(hook); + } + } + +@@ -2323,10 +2327,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain) + + if (nft_base_chain_netdev(table->family, basechain->ops.hooknum)) { + list_for_each_entry_safe(hook, next, +- &basechain->hook_list, list) { +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ &basechain->hook_list, list) ++ nft_netdev_hook_unlink_free_rcu(hook); + } + module_put(basechain->type->owner); + if (rcu_access_pointer(basechain->stats)) { +@@ -3026,6 +3028,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, + list_for_each_entry(ops, &h->ops_list, list) + nf_unregister_net_hook(ctx->net, ops); + } ++ /* hook.list is on stack, no need for list_del_rcu() */ + list_del(&h->list); + nft_netdev_hook_free_rcu(h); + } +@@ -8903,10 +8906,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net, + list_for_each_entry_safe(hook, next, hook_list, list) { + list_for_each_entry(ops, &hook->ops_list, list) + nft_unregister_flowtable_ops(net, flowtable, ops); +- if (release_netdev) { +- list_del(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ if (release_netdev) ++ nft_netdev_hook_unlink_free_rcu(hook); + } + } + +@@ -8977,8 +8978,7 @@ static int nft_register_flowtable_net_hooks(struct net *net, + + nft_unregister_flowtable_ops(net, flowtable, ops); + } +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); ++ nft_netdev_hook_unlink_free_rcu(hook); + } + + return err; +@@ -8988,10 +8988,8 @@ static void nft_hooks_destroy(struct list_head *hook_list) + { + struct nft_hook *hook, *next; + +- list_for_each_entry_safe(hook, next, hook_list, list) { +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ list_for_each_entry_safe(hook, next, hook_list, list) ++ nft_netdev_hook_unlink_free_rcu(hook); + } + + static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, +@@ -9079,8 +9077,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, + nft_unregister_flowtable_ops(ctx->net, + flowtable, ops); + } +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); ++ nft_netdev_hook_unlink_free_rcu(hook); + } + + return err; +@@ -9586,13 +9583,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx, + + static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable) + { +- struct nft_hook *hook, *next; +- + flowtable->data.type->free(&flowtable->data); +- list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) { +- list_del_rcu(&hook->list); +- nft_netdev_hook_free_rcu(hook); +- } ++ nft_hooks_destroy(&flowtable->hook_list); + kfree(flowtable->name); + module_put(flowtable->data.type->owner); + kfree(flowtable); +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch b/queue-7.0/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch new file mode 100644 index 0000000000..68023d6af1 --- /dev/null +++ b/queue-7.0/netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch @@ -0,0 +1,67 @@ +From 08da967e89027e90fdac295b86d4f3664e3b82cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 15:14:01 -0700 +Subject: netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO + +From: Xiang Mei + +[ Upstream commit 2195574dc6d9017d32ac346987e12659f931d932 ] + +nf_osf_match_one() computes ctx->window % f->wss.val in the +OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A +CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a +subsequent matching TCP SYN divides by zero and panics the kernel. + +Reject the bogus fingerprint in nfnl_osf_add_callback() above the +per-option for-loop. f->wss is per-fingerprint, not per-option, so +the check must run regardless of f->opt_num (including 0). Also +reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that +as "should not happen". + +Crash: + Oops: divide error: 0000 [#1] SMP KASAN NOPTI + RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) + Call Trace: + + nf_osf_match (net/netfilter/nfnetlink_osf.c:220) + xt_osf_match_packet (net/netfilter/xt_osf.c:32) + ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) + nf_hook_slow (net/netfilter/core.c:622) + ip_local_deliver (net/ipv4/ip_input.c:265) + ip_rcv (include/linux/skbuff.h:1162) + __netif_receive_skb_one_core (net/core/dev.c:6181) + process_backlog (net/core/dev.c:6642) + __napi_poll (net/core/dev.c:7710) + net_rx_action (net/core/dev.c:7945) + handle_softirqs (kernel/softirq.c:622) + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Weiming Shi +Suggested-by: Florian Westphal +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Xiang Mei +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 45d9ad231a920..70172ca078585 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb, + if (f->opt_num > ARRAY_SIZE(f->opt)) + return -EINVAL; + ++ if (f->wss.wc >= OSF_WSS_MAX || ++ (f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0)) ++ return -EINVAL; ++ + for (i = 0; i < f->opt_num; i++) { + if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch b/queue-7.0/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch new file mode 100644 index 0000000000..5ce44c5934 --- /dev/null +++ b/queue-7.0/netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch @@ -0,0 +1,100 @@ +From 17380c48592d003f36ebd6f9429068dab788432c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:56 +0200 +Subject: netfilter: nfnetlink_osf: fix out-of-bounds read on option matching + +From: Fernando Fernandez Mancera + +[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ] + +In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once +and passed by reference to nf_osf_match_one() for each fingerprint +checked. During TCP option parsing, nf_osf_match_one() advances the +shared ctx->optp pointer. + +If a fingerprint perfectly matches, the function returns early without +restoring ctx->optp to its initial state. If the user has configured +NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. +However, because ctx->optp was not restored, the next call to +nf_osf_match_one() starts parsing from the end of the options buffer. +This causes subsequent matches to read garbage data and fail +immediately, making it impossible to log more than one match or logging +incorrect matches. + +Instead of using a shared ctx->optp pointer, pass the context as a +constant pointer and use a local pointer (optp) for TCP option +traversal. This makes nf_osf_match_one() strictly stateless from the +caller's perspective, ensuring every fingerprint check starts at the +correct option offset. + +Fixes: 1a6a0951fc00 ("netfilter: nfnetlink_osf: add missing fmatch check") +Suggested-by: Florian Westphal +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 70172ca078585..3e0ccb6d9dc7e 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx { + static bool nf_osf_match_one(const struct sk_buff *skb, + const struct nf_osf_user_finger *f, + int ttl_check, +- struct nf_osf_hdr_ctx *ctx) ++ const struct nf_osf_hdr_ctx *ctx) + { +- const __u8 *optpinit = ctx->optp; ++ const __u8 *optp = ctx->optp; + unsigned int check_WSS = 0; + int fmatch = FMATCH_WRONG; + int foptsize, optnum; +@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + check_WSS = f->wss.wc; + + for (optnum = 0; optnum < f->opt_num; ++optnum) { +- if (f->opt[optnum].kind == *ctx->optp) { ++ if (f->opt[optnum].kind == *optp) { + __u32 len = f->opt[optnum].length; +- const __u8 *optend = ctx->optp + len; ++ const __u8 *optend = optp + len; + + fmatch = FMATCH_OK; + +- switch (*ctx->optp) { ++ switch (*optp) { + case OSFOPT_MSS: +- mss = ctx->optp[3]; ++ mss = optp[3]; + mss <<= 8; +- mss |= ctx->optp[2]; ++ mss |= optp[2]; + + mss = ntohs((__force __be16)mss); + break; +@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + break; + } + +- ctx->optp = optend; ++ optp = optend; + } else + fmatch = FMATCH_OPT_WRONG; + +@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, + } + } + +- if (fmatch != FMATCH_OK) +- ctx->optp = optpinit; +- + return fmatch == FMATCH_OK; + } + +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch b/queue-7.0/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch new file mode 100644 index 0000000000..16c786e132 --- /dev/null +++ b/queue-7.0/netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch @@ -0,0 +1,74 @@ +From ebe53f49c3a354eb6a29c81d657adc1d0c981c6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 18:20:57 +0200 +Subject: netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check + +From: Fernando Fernandez Mancera + +[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ] + +The nf_osf_ttl() function accessed skb->dev to perform a local interface +address lookup without verifying that the device pointer was valid. + +Additionally, the implementation utilized an in_dev_for_each_ifa_rcu +loop to match the packet source address against local interface +addresses. It assumed that packets from the same subnet should not see a +decrement on the initial TTL. A packet might appear it is from the same +subnet but it actually isn't especially in modern environments with +containers and virtual switching. + +Remove the device dereference and interface loop. Replace the logic with +a switch statement that evaluates the TTL according to the ttl_check. + +Fixes: 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match") +Reported-by: Kito Xu (veritas501) +Closes: https://lore.kernel.org/netfilter-devel/20260414074556.2512750-1-hxzene@gmail.com/ +Signed-off-by: Fernando Fernandez Mancera +Reviewed-by: Pablo Neira Ayuso +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- + 1 file changed, 7 insertions(+), 15 deletions(-) + +diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c +index 3e0ccb6d9dc7e..426b85fca8f75 100644 +--- a/net/netfilter/nfnetlink_osf.c ++++ b/net/netfilter/nfnetlink_osf.c +@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers); + static inline int nf_osf_ttl(const struct sk_buff *skb, + int ttl_check, unsigned char f_ttl) + { +- struct in_device *in_dev = __in_dev_get_rcu(skb->dev); + const struct iphdr *ip = ip_hdr(skb); +- const struct in_ifaddr *ifa; +- int ret = 0; + +- if (ttl_check == NF_OSF_TTL_TRUE) ++ switch (ttl_check) { ++ case NF_OSF_TTL_TRUE: + return ip->ttl == f_ttl; +- if (ttl_check == NF_OSF_TTL_NOCHECK) +- return 1; +- else if (ip->ttl <= f_ttl) ++ break; ++ case NF_OSF_TTL_NOCHECK: + return 1; +- +- in_dev_for_each_ifa_rcu(ifa, in_dev) { +- if (inet_ifa_match(ip->saddr, ifa)) { +- ret = (ip->ttl == f_ttl); +- break; +- } ++ case NF_OSF_TTL_LESS: ++ default: ++ return ip->ttl <= f_ttl; + } +- +- return ret; + } + + struct nf_osf_hdr_ctx { +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch b/queue-7.0/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch new file mode 100644 index 0000000000..5aadef71dc --- /dev/null +++ b/queue-7.0/netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch @@ -0,0 +1,49 @@ +From e68cecf4a79019f0ad67dae82312ef4db2cc3b36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 13:30:41 +0200 +Subject: netfilter: nft_fwd_netdev: check ttl/hl before forwarding + +From: Florian Westphal + +[ Upstream commit 1dfd95bdf4d18d263aa8fad06bfb9f4d9c992b18 ] + +Drop packets if their ttl/hl is too small for forwarding. + +Fixes: d32de98ea70f ("netfilter: nft_fwd_netdev: allow to forward packets via neighbour layer") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_fwd_netdev.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c +index 152a9fb4d23af..256e832f1bb99 100644 +--- a/net/netfilter/nft_fwd_netdev.c ++++ b/net/netfilter/nft_fwd_netdev.c +@@ -116,6 +116,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + iph = ip_hdr(skb); ++ if (iph->ttl <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip_decrease_ttl(iph); + neigh_table = NEIGH_ARP_TABLE; + break; +@@ -132,6 +137,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, + goto out; + } + ip6h = ipv6_hdr(skb); ++ if (ip6h->hop_limit <= 1) { ++ verdict = NF_DROP; ++ goto out; ++ } ++ + ip6h->hop_limit--; + neigh_table = NEIGH_ND_TABLE; + break; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-nft_osf-restrict-it-to-ipv4.patch b/queue-7.0/netfilter-nft_osf-restrict-it-to-ipv4.patch new file mode 100644 index 0000000000..4e873878b5 --- /dev/null +++ b/queue-7.0/netfilter-nft_osf-restrict-it-to-ipv4.patch @@ -0,0 +1,47 @@ +From 48cc93efb3ec878004bed4ed9c8699d57d654eb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 13:06:38 +0200 +Subject: netfilter: nft_osf: restrict it to ipv4 + +From: Pablo Neira Ayuso + +[ Upstream commit b336fdbb7103fb1484e1dcb6741151d4b5a41e35 ] + +This expression only supports for ipv4, restrict it. + +Fixes: b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf") +Acked-by: Florian Westphal +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_osf.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c +index 1c0b493ef0a99..bdc2f6c90e2f7 100644 +--- a/net/netfilter/nft_osf.c ++++ b/net/netfilter/nft_osf.c +@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, + struct nf_osf_data data; + struct tcphdr _tcph; + ++ if (nft_pf(pkt) != NFPROTO_IPV4) { ++ regs->verdict.code = NFT_BREAK; ++ return; ++ } ++ + if (pkt->tprot != IPPROTO_TCP) { + regs->verdict.code = NFT_BREAK; + return; +@@ -114,7 +119,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx, + + switch (ctx->family) { + case NFPROTO_IPV4: +- case NFPROTO_IPV6: + case NFPROTO_INET: + hooks = (1 << NF_INET_LOCAL_IN) | + (1 << NF_INET_PRE_ROUTING) | +-- +2.53.0 + diff --git a/queue-7.0/netfilter-skip-recording-stale-or-retransmitted-init.patch b/queue-7.0/netfilter-skip-recording-stale-or-retransmitted-init.patch new file mode 100644 index 0000000000..2b7959975e --- /dev/null +++ b/queue-7.0/netfilter-skip-recording-stale-or-retransmitted-init.patch @@ -0,0 +1,63 @@ +From adfa70275a970fdea29b49472b5a626f0dd852f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:40 -0400 +Subject: netfilter: skip recording stale or retransmitted INIT + +From: Xin Long + +[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ] + +An INIT whose init_tag matches the peer's vtag does not provide new state +information. It indicates either: + +- a stale INIT (after INIT-ACK has already been seen on the same side), or +- a retransmitted INIT (after INIT has already been recorded on the same + side). + +In both cases, the INIT must not update ct->proto.sctp.init[] state, since +it does not advance the handshake tracking and may otherwise corrupt +INIT/INIT-ACK validation logic. + +Allow INIT processing only when the conntrack entry is newly created +(SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer +vtag. + +Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in +nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it +set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag. + +Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") +Signed-off-by: Xin Long +Reviewed-by: Marcelo Ricardo Leitner +Acked-by: Florian Westphal +Link: https://patch.msgid.link/ee56c3e416452b2a40589a2a85245ac2ad5e9f4b.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c +index 645d2c43ebf7a..7e10fa65cbdd3 100644 +--- a/net/netfilter/nf_conntrack_proto_sctp.c ++++ b/net/netfilter/nf_conntrack_proto_sctp.c +@@ -466,9 +466,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, + if (!ih) + goto out_unlock; + +- if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) +- ct->proto.sctp.init[!dir] = 0; +- ct->proto.sctp.init[dir] = 1; ++ /* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ ++ if (old_state == SCTP_CONNTRACK_NONE || ++ ct->proto.sctp.vtag[!dir] != ih->init_tag) { ++ if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) ++ ct->proto.sctp.init[!dir] = 0; ++ ct->proto.sctp.init[dir] = 1; ++ } + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); + ct->proto.sctp.vtag[!dir] = ih->init_tag; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch b/queue-7.0/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch new file mode 100644 index 0000000000..d708838d88 --- /dev/null +++ b/queue-7.0/netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch @@ -0,0 +1,47 @@ +From 48bb681efdf265f379fdb9bab806bf7a87f564e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 20:25:06 +0800 +Subject: netfilter: xt_policy: fix strict mode inbound policy matching + +From: Jiexun Wang + +[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ] + +match_policy_in() walks sec_path entries from the last transform to the +first one, but strict policy matching needs to consume info->pol[] in +the same forward order as the rule layout. + +Derive the strict-match policy position from the number of transforms +already consumed so that multi-element inbound rules are matched +consistently. + +Fixes: c4b885139203 ("[NETFILTER]: x_tables: replace IPv4/IPv6 policy match by address family independant version") +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Acked-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_policy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c +index cb6e8279010a4..b5fa65558318f 100644 +--- a/net/netfilter/xt_policy.c ++++ b/net/netfilter/xt_policy.c +@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, + return 0; + + for (i = sp->len - 1; i >= 0; i--) { +- pos = strict ? i - sp->len + 1 : 0; ++ pos = strict ? sp->len - i - 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; +-- +2.53.0 + diff --git a/queue-7.0/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch b/queue-7.0/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch new file mode 100644 index 0000000000..c1e7ebc39c --- /dev/null +++ b/queue-7.0/netfilter-xt_socket-enable-defrag-after-all-other-ch.patch @@ -0,0 +1,86 @@ +From 79942af5b9d33d7eb088b30ba2afa2c9b92e12ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Apr 2026 12:12:59 +0200 +Subject: netfilter: xt_socket: enable defrag after all other checks + +From: Florian Westphal + +[ Upstream commit 542be3fa5aff54210a02954c38f07e53ea9bdafd ] + +Originally this did not matter because defrag was enabled once per netns +and only disabled again on netns dismantle. When this got changed I should +have adjusted checkentry to not leave defrag enabled on error. + +Fixes: de8c12110a13 ("netfilter: disable defrag once its no longer needed") +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_socket.c | 23 ++++++----------------- + 1 file changed, 6 insertions(+), 17 deletions(-) + +diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c +index 76e01f292aaff..811e53bee4085 100644 +--- a/net/netfilter/xt_socket.c ++++ b/net/netfilter/xt_socket.c +@@ -168,52 +168,41 @@ static int socket_mt_enable_defrag(struct net *net, int family) + static int socket_mt_v1_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V1) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V1); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v2_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; +- int err; +- +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + + if (info->flags & ~XT_SOCKET_FLAGS_V2) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V2); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static int socket_mt_v3_check(const struct xt_mtchk_param *par) + { + const struct xt_socket_mtinfo3 *info = + (struct xt_socket_mtinfo3 *)par->matchinfo; +- int err; + +- err = socket_mt_enable_defrag(par->net, par->family); +- if (err) +- return err; + if (info->flags & ~XT_SOCKET_FLAGS_V3) { + pr_info_ratelimited("unknown flags 0x%x\n", + info->flags & ~XT_SOCKET_FLAGS_V3); + return -EINVAL; + } +- return 0; ++ ++ return socket_mt_enable_defrag(par->net, par->family); + } + + static void socket_mt_destroy(const struct xt_mtdtor_param *par) +-- +2.53.0 + diff --git a/queue-7.0/netfilter-xtables-restrict-several-matches-to-inet-f.patch b/queue-7.0/netfilter-xtables-restrict-several-matches-to-inet-f.patch new file mode 100644 index 0000000000..97052c94b5 --- /dev/null +++ b/queue-7.0/netfilter-xtables-restrict-several-matches-to-inet-f.patch @@ -0,0 +1,208 @@ +From f1d3e69b482b3b932b33c33d50f3361dc34f8186 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 12:21:00 +0200 +Subject: netfilter: xtables: restrict several matches to inet family + +From: Pablo Neira Ayuso + +[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ] + +This is a partial revert of: + + commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") + +to allow ipv4 and ipv6 only. + +- xt_mac +- xt_owner +- xt_physdev + +These extensions are not used by ebtables in userspace. + +Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 +specific. + +Fixes: ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions") +Reported-by: "Kito Xu (veritas501)" +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- + net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ + net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- + net/netfilter/xt_realm.c | 2 +- + 4 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c +index 81649da57ba5d..bd2354760895d 100644 +--- a/net/netfilter/xt_mac.c ++++ b/net/netfilter/xt_mac.c +@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) + return ret; + } + +-static struct xt_match mac_mt_reg __read_mostly = { +- .name = "mac", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .match = mac_mt, +- .matchsize = sizeof(struct xt_mac_info), +- .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | +- (1 << NF_INET_FORWARD), +- .me = THIS_MODULE, ++static struct xt_match mac_mt_reg[] __read_mostly = { ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV4, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "mac", ++ .family = NFPROTO_IPV6, ++ .match = mac_mt, ++ .matchsize = sizeof(struct xt_mac_info), ++ .hooks = (1 << NF_INET_PRE_ROUTING) | ++ (1 << NF_INET_LOCAL_IN) | ++ (1 << NF_INET_FORWARD), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init mac_mt_init(void) + { +- return xt_register_match(&mac_mt_reg); ++ return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + static void __exit mac_mt_exit(void) + { +- xt_unregister_match(&mac_mt_reg); ++ xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); + } + + module_init(mac_mt_init); +diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c +index 50332888c8d23..7be2fe22b067e 100644 +--- a/net/netfilter/xt_owner.c ++++ b/net/netfilter/xt_owner.c +@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) + return true; + } + +-static struct xt_match owner_mt_reg __read_mostly = { +- .name = "owner", +- .revision = 1, +- .family = NFPROTO_UNSPEC, +- .checkentry = owner_check, +- .match = owner_mt, +- .matchsize = sizeof(struct xt_owner_match_info), +- .hooks = (1 << NF_INET_LOCAL_OUT) | +- (1 << NF_INET_POST_ROUTING), +- .me = THIS_MODULE, ++static struct xt_match owner_mt_reg[] __read_mostly = { ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV4, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "owner", ++ .revision = 1, ++ .family = NFPROTO_IPV6, ++ .checkentry = owner_check, ++ .match = owner_mt, ++ .matchsize = sizeof(struct xt_owner_match_info), ++ .hooks = (1 << NF_INET_LOCAL_OUT) | ++ (1 << NF_INET_POST_ROUTING), ++ .me = THIS_MODULE, ++ } + }; + + static int __init owner_mt_init(void) + { +- return xt_register_match(&owner_mt_reg); ++ return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + static void __exit owner_mt_exit(void) + { +- xt_unregister_match(&owner_mt_reg); ++ xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); + } + + module_init(owner_mt_init); +diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c +index 343e65f377d44..130842c35c6fa 100644 +--- a/net/netfilter/xt_physdev.c ++++ b/net/netfilter/xt_physdev.c +@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par) + return 0; + } + +-static struct xt_match physdev_mt_reg __read_mostly = { +- .name = "physdev", +- .revision = 0, +- .family = NFPROTO_UNSPEC, +- .checkentry = physdev_mt_check, +- .match = physdev_mt, +- .matchsize = sizeof(struct xt_physdev_info), +- .me = THIS_MODULE, ++static struct xt_match physdev_mt_reg[] __read_mostly = { ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV4, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, ++ { ++ .name = "physdev", ++ .family = NFPROTO_IPV6, ++ .checkentry = physdev_mt_check, ++ .match = physdev_mt, ++ .matchsize = sizeof(struct xt_physdev_info), ++ .me = THIS_MODULE, ++ }, + }; + + static int __init physdev_mt_init(void) + { +- return xt_register_match(&physdev_mt_reg); ++ return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + static void __exit physdev_mt_exit(void) + { +- xt_unregister_match(&physdev_mt_reg); ++ xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); + } + + module_init(physdev_mt_init); +diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c +index 6df485f4403d0..61b2f1e58d150 100644 +--- a/net/netfilter/xt_realm.c ++++ b/net/netfilter/xt_realm.c +@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { + .matchsize = sizeof(struct xt_realm_info), + .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | + (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), +- .family = NFPROTO_UNSPEC, ++ .family = NFPROTO_IPV4, + .me = THIS_MODULE + }; + +-- +2.53.0 + diff --git a/queue-7.0/netpoll-fix-ipv6-local-address-corruption.patch b/queue-7.0/netpoll-fix-ipv6-local-address-corruption.patch new file mode 100644 index 0000000000..d1d2fbc23c --- /dev/null +++ b/queue-7.0/netpoll-fix-ipv6-local-address-corruption.patch @@ -0,0 +1,81 @@ +From b9d09d0ae10c59897ff3d34dde7c57cc2002c698 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 08:31:16 -0700 +Subject: netpoll: fix IPv6 local-address corruption + +From: Breno Leitao + +[ Upstream commit 3bc179bc7146c26c9dff75d2943d10528274e301 ] + +netpoll_setup() decides whether to auto-populate the local source +address by testing np->local_ip.ip, which only inspects the first 4 +bytes of the union inet_addr storage. + +For an IPv6 netpoll whose caller-supplied local address has a zero +high-32 bits (::1, ::, IPv4-mapped ::ffff:a.b.c.d, etc.), this +misdetects the address as unset (which they are not, but the first +4 bytes are empty), calls netpoll_take_ipv6() and overwrites it with +whatever matching link-local/global address the device happens to expose +first. + +Introduce a helper netpoll_local_ip_unset() that picks the correct +family-aware test (ipv6_addr_any() for IPv6, !.ip for IPv4) and use it +from netpoll_setup(). + +Reproducer is something like: + + echo "::2" > local_ip + echo 1 > enabled + cat local_ip + # before this fix: 2001:db8::1 (caller-supplied ::2 was clobbered) + # after this fix: ::2 + +Fixes: b7394d2429c1 ("netpoll: prepare for ipv6") +Signed-off-by: Breno Leitao +Link: https://patch.msgid.link/20260424-netpoll_fix-v1-1-3a55348c625f@debian.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/netpoll.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/net/core/netpoll.c b/net/core/netpoll.c +index 5ae90c14ba493..84faace50ac28 100644 +--- a/net/core/netpoll.c ++++ b/net/core/netpoll.c +@@ -706,6 +706,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev) + return 0; + } + ++/* ++ * Test whether the caller left np->local_ip unset, so that ++ * netpoll_setup() should auto-populate it from the egress device. ++ * ++ * np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6), ++ * so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2, ++ * IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm — ++ * doing so would misclassify a caller-supplied address as unset and ++ * silently overwrite it with whatever address the device exposes. ++ */ ++static bool netpoll_local_ip_unset(const struct netpoll *np) ++{ ++ if (np->ipv6) ++ return ipv6_addr_any(&np->local_ip.in6); ++ return !np->local_ip.ip; ++} ++ + int netpoll_setup(struct netpoll *np) + { + struct net *net = current->nsproxy->net_ns; +@@ -750,7 +767,7 @@ int netpoll_setup(struct netpoll *np) + rtnl_lock(); + } + +- if (!np->local_ip.ip) { ++ if (netpoll_local_ip_unset(np)) { + if (!np->ipv6) { + err = netpoll_take_ipv4(np, ndev); + if (err) +-- +2.53.0 + diff --git a/queue-7.0/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch b/queue-7.0/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch new file mode 100644 index 0000000000..fca76d10dd --- /dev/null +++ b/queue-7.0/nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch @@ -0,0 +1,69 @@ +From c8e6b88aa0948ce11b71a851fba410ff9331f52b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Apr 2026 19:45:19 +0800 +Subject: nexthop: fix IPv6 route referencing IPv4 nexthop + +From: Jiayuan Chen + +[ Upstream commit 29c95185ba32b621fbc3800fb86e7dc3edf5c2be ] + +syzbot reported a panic [1] [2]. + +When an IPv6 nexthop is replaced with an IPv4 nexthop, the has_v4 flag +of all groups containing this nexthop is not updated. This is because +nh_group_v4_update is only called when replacing AF_INET to AF_INET6, +but the reverse direction (AF_INET6 to AF_INET) is missed. + +This allows a stale has_v4=false to bypass fib6_check_nexthop, causing +IPv6 routes to be attached to groups that effectively contain only AF_INET +members. Subsequent route lookups then call nexthop_fib6_nh() which +returns NULL for the AF_INET member, leading to a NULL pointer +dereference. + +Fix by calling nh_group_v4_update whenever the family changes, not just +AF_INET to AF_INET6. + +Reproducer: + # AF_INET6 blackhole + ip -6 nexthop add id 1 blackhole + # group with has_v4=false + ip nexthop add id 100 group 1 + # replace with AF_INET (no -6), has_v4 stays false + ip nexthop replace id 1 blackhole + # pass stale has_v4 check + ip -6 route add 2001:db8::/64 nhid 100 + # panic + ping -6 2001:db8::1 + +[1] https://syzkaller.appspot.com/bug?id=e17283eb2f8dcf3dd9b47fe6f67a95f71faadad0 +[2] https://syzkaller.appspot.com/bug?id=8699b6ae54c9f35837d925686208402949e12ef3 +Fixes: 7bf4796dd099 ("nexthops: add support for replace") +Signed-off-by: Jiayuan Chen +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260413114522.147784-1-jiayuan.chen@linux.dev +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/ipv4/nexthop.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c +index 2c9036c719b68..11a763cbc8482 100644 +--- a/net/ipv4/nexthop.c ++++ b/net/ipv4/nexthop.c +@@ -2466,10 +2466,10 @@ static int replace_nexthop_single(struct net *net, struct nexthop *old, + goto err_notify; + } + +- /* When replacing an IPv4 nexthop with an IPv6 nexthop, potentially ++ /* When replacing a nexthop with one of a different family, potentially + * update IPv4 indication in all the groups using the nexthop. + */ +- if (oldi->family == AF_INET && newi->family == AF_INET6) { ++ if (oldi->family != newi->family) { + list_for_each_entry(nhge, &old->grp_list, nh_list) { + struct nexthop *nhp = nhge->nh_parent; + struct nh_group *nhg; +-- +2.53.0 + diff --git a/queue-7.0/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch b/queue-7.0/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch new file mode 100644 index 0000000000..bbd4ad266a --- /dev/null +++ b/queue-7.0/nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch @@ -0,0 +1,53 @@ +From c77cb609fc5ee181b26797eda8db40e657ed29aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 12:09:30 +0200 +Subject: NFC: trf7970a: Ignore antenna noise when checking for RF field + +From: Paul Geurts + +[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ] + +The main channel Received Signal Strength Indicator (RSSI) measurement +is used to determine whether an RF field is present or not. RSSI != 0 +is interpreted as an RF Field is present. This does not take RF noise +and measurement inaccuracy into account, and results in false positives +in the field. + +Define a noise level and make sure the RF field is only interpreted as +present when the RSSI is above the noise level. + +Fixes: 851ee3cbf850 ("NFC: trf7970a: Don't turn on RF if there is already an RF field") +Signed-off-by: Paul Geurts +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Mark Greer +Link: https://patch.msgid.link/20260422100930.581237-1-paul.geurts@prodrive-technologies.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/trf7970a.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c +index d17c701c7888b..08c27bb438b59 100644 +--- a/drivers/nfc/trf7970a.c ++++ b/drivers/nfc/trf7970a.c +@@ -317,6 +317,7 @@ + #define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3)) + #define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) ++#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1 + + #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) + #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +@@ -1300,7 +1301,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field) + if (ret) + return ret; + +- if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) ++ if ((rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK) > TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL) + *is_rf_field = true; + else + *is_rf_field = false; +-- +2.53.0 + diff --git a/queue-7.0/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch b/queue-7.0/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch new file mode 100644 index 0000000000..3e8054aa9d --- /dev/null +++ b/queue-7.0/nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch @@ -0,0 +1,107 @@ +From ceff9ec02af1f8a16779b2d74d0f118a9783d44e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 16:05:36 +0000 +Subject: nfp: fix swapped arguments in nfp_encode_basic_qdr() calls + +From: Alexey Kodanev + +[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ] + +There is a mismatch between the passed arguments and the actual +nfp_encode_basic_qdr() function parameter names: + + static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + int mode, bool addr40, int isld1, + int isld0) + { + ... + +But "dest_island" and "cpp_tgt" are swapped at every call-site. +For example: + + return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, + mode, addr40, isld1, isld0); + +As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target +type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" +as the destination island ID, which can accidentally match or be outside +the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination). + +Since code already worked for years, also add extra pr_warn() to error +paths in nfp_encode_basic_qdr() to help identify any potential address +verification failures. + +Detected using the static analysis tool - Svace. + +Fixes: 4cb584e0ee7d ("nfp: add CPP access core") +Signed-off-by: Alexey Kodanev +Link: https://patch.msgid.link/20260422160536.61855-1-aleksei.kodanev@bell-sw.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +index 79470f198a62a..9cf19446657c6 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt, + + /* Full Island ID and channel bits overlap? */ + ret = nfp_decode_basic(addr, &v, cpp_tgt, mode, addr40, isld1, isld0); +- if (ret) ++ if (ret) { ++ pr_warn("%s: decode dest_island failed: %d\n", __func__, ret); + return ret; ++ } + + /* The current address won't go where expected? */ +- if (dest_island != -1 && dest_island != v) ++ if (dest_island != -1 && dest_island != v) { ++ pr_warn("%s: dest_island mismatch: current (%d) != decoded (%d)\n", ++ __func__, dest_island, v); + return -EINVAL; ++ } + + /* If dest_island was -1, we don't care where it goes. */ + return 0; +@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * the address but we can verify if the existing + * contents will point to a valid island. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + iid_lsb = addr40 ? 34 : 26; +@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + return 0; + case 1: + if (cpp_tgt == NFP_CPP_TARGET_QDR && !addr40) +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + idx_lsb = addr40 ? 39 : 31; +@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * be set before hand and with them select an island. + * So we need to confirm that it's at least plausible. + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + /* Make sure we compare against isldN values +@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt, + * iid<1> = addr<30> = channel<0> + * channel<1> = addr<31> = Index + */ +- return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island, ++ return nfp_encode_basic_qdr(*addr, dest_island, cpp_tgt, + mode, addr40, isld1, isld0); + + isld[0] &= ~3; +-- +2.53.0 + diff --git a/queue-7.0/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch b/queue-7.0/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch new file mode 100644 index 0000000000..6596c7da26 --- /dev/null +++ b/queue-7.0/nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch @@ -0,0 +1,58 @@ +From 80b90e069e0cca9a39caa5c9f0ce37649d02ad65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:49 +0100 +Subject: nfs/blocklayout: Fix compilation error (`make W=1`) in + bl_write_pagelist() + +From: Andy Shevchenko + +[ Upstream commit f83c8dda456ce4863f346aa26d88efa276eda35d ] + +Clang compiler is not happy about set but unused variable +(when dprintk() is no-op): + +.../blocklayout/blocklayout.c:384:9: error: variable 'count' set but not used [-Werror,-Wunused-but-set-variable] + +Remove a leftover from the previous cleanup. + +Fixes: 3a6fd1f004fc ("pnfs/blocklayout: remove read-modify-write handling in bl_write_pagelist") +Acked-by: Anna Schumaker +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/blocklayout/blocklayout.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c +index cb0a645aeb501..94e85ad9067e5 100644 +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -381,14 +381,13 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + sector_t isect, extent_length = 0; + struct parallel_io *par = NULL; + loff_t offset = header->args.offset; +- size_t count = header->args.count; + struct page **pages = header->args.pages; + int pg_index = header->args.pgbase >> PAGE_SHIFT; + unsigned int pg_len; + struct blk_plug plug; + int i; + +- dprintk("%s enter, %zu@%lld\n", __func__, count, offset); ++ dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); + + /* At this point, header->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error +@@ -429,7 +428,6 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) + } + + offset += pg_len; +- count -= pg_len; + isect += (pg_len >> SECTOR_SHIFT); + extent_length -= (pg_len >> SECTOR_SHIFT); + } +-- +2.53.0 + diff --git a/queue-7.0/nfsd-fix-nfs4_file-access-extra-count-in-nfsd4_add_r.patch b/queue-7.0/nfsd-fix-nfs4_file-access-extra-count-in-nfsd4_add_r.patch new file mode 100644 index 0000000000..1bf2da97ec --- /dev/null +++ b/queue-7.0/nfsd-fix-nfs4_file-access-extra-count-in-nfsd4_add_r.patch @@ -0,0 +1,55 @@ +From ce2fd574dc4f1e896c63851a3b53bdd8c3399a29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 13:07:43 -0800 +Subject: NFSD: fix nfs4_file access extra count in + nfsd4_add_rdaccess_to_wrdeleg + +From: Dai Ngo + +[ Upstream commit b48f44f36e6607b2f818560f19deb86b4a9c717b ] + +In nfsd4_add_rdaccess_to_wrdeleg, if fp->fi_fds[O_RDONLY] is already +set by another thread, __nfs4_file_get_access should not be called +to increment the nfs4_file access count since that was already done +by the thread that added READ access to the file. The extra fi_access +count in nfs4_file can prevent the corresponding nfsd_file from being +freed. + +When stopping nfs-server service, these extra access counts trigger a +BUG in kmem_cache_destroy() that shows nfsd_file object remaining on +__kmem_cache_shutdown. + +This problem can be reproduced by running the Git project's test +suite over NFS. + +Fixes: 8072e34e1387 ("nfsd: fix nfsd_file reference leak in nfsd4_add_rdaccess_to_wrdeleg()") +Signed-off-by: Dai Ngo +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 6b9c399b89dfb..1f49637dfc96f 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6257,12 +6257,12 @@ nfsd4_add_rdaccess_to_wrdeleg(struct svc_rqst *rqstp, struct nfsd4_open *open, + return (false); + fp = stp->st_stid.sc_file; + spin_lock(&fp->fi_lock); +- __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ); + if (!fp->fi_fds[O_RDONLY]) { ++ __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ); + fp->fi_fds[O_RDONLY] = nf; ++ fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]); + nf = NULL; + } +- fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]); + spin_unlock(&fp->fi_lock); + if (nf) + nfsd_file_put(nf); +-- +2.53.0 + diff --git a/queue-7.0/nfsd-use-dynamic-allocation-for-oversized-nfsv4.0-re.patch b/queue-7.0/nfsd-use-dynamic-allocation-for-oversized-nfsv4.0-re.patch new file mode 100644 index 0000000000..d206ab668f --- /dev/null +++ b/queue-7.0/nfsd-use-dynamic-allocation-for-oversized-nfsv4.0-re.patch @@ -0,0 +1,133 @@ +From 13acdcdf1a6ab1376c7aafc39c32874796b3585c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 12:10:34 -0500 +Subject: nfsd: use dynamic allocation for oversized NFSv4.0 replay cache + +From: Chuck Lever + +[ Upstream commit 116b6b7acdd82605ed530232cd7509d1b5282f5c ] + +Commit 1e8e9913672a ("nfsd: fix heap overflow in NFSv4.0 LOCK +replay cache") capped the replay cache copy at NFSD4_REPLAY_ISIZE +to prevent a heap overflow, but set rp_buflen to zero when the +encoded response exceeded the inline buffer. A retransmitted LOCK +reaching the replay path then produced only a status code with no +operation body, resulting in a malformed XDR response. + +When the encoded response exceeds the 112-byte inline rp_ibuf, a +buffer is kmalloc'd to hold it. If the allocation fails, rp_buflen +remains zero, preserving the behavior from the capped-copy fix. +The buffer is freed when the stateowner is released or when a +subsequent operation's response fits in the inline buffer. + +Fixes: 1e8e9913672a ("nfsd: fix heap overflow in NFSv4.0 LOCK replay cache") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 16 ++++++++++++++++ + fs/nfsd/nfs4xdr.c | 23 ++++++++++++++++------- + fs/nfsd/state.h | 12 +++++++----- + 3 files changed, 39 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 1f49637dfc96f..f932a165f5b9b 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1495,8 +1495,24 @@ release_all_access(struct nfs4_ol_stateid *stp) + } + } + ++/** ++ * nfs4_replay_free_cache - release dynamically allocated replay buffer ++ * @rp: replay cache to reset ++ * ++ * If @rp->rp_buf points to a kmalloc'd buffer, free it and reset ++ * rp_buf to the inline rp_ibuf. Always zeroes rp_buflen. ++ */ ++void nfs4_replay_free_cache(struct nfs4_replay *rp) ++{ ++ if (rp->rp_buf != rp->rp_ibuf) ++ kfree(rp->rp_buf); ++ rp->rp_buf = rp->rp_ibuf; ++ rp->rp_buflen = 0; ++} ++ + static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) + { ++ nfs4_replay_free_cache(&sop->so_replay); + kfree(sop->so_owner.data); + sop->so_ops->so_free(sop); + } +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 9d234913100b9..ef663331063b1 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -6281,14 +6281,23 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) + int len = xdr->buf->len - (op_status_offset + XDR_UNIT); + + so->so_replay.rp_status = op->status; +- if (len <= NFSD4_REPLAY_ISIZE) { +- so->so_replay.rp_buflen = len; +- read_bytes_from_xdr_buf(xdr->buf, +- op_status_offset + XDR_UNIT, +- so->so_replay.rp_buf, len); +- } else { +- so->so_replay.rp_buflen = 0; ++ if (len > NFSD4_REPLAY_ISIZE) { ++ char *buf = kmalloc(len, GFP_KERNEL); ++ ++ nfs4_replay_free_cache(&so->so_replay); ++ if (buf) { ++ so->so_replay.rp_buf = buf; ++ } else { ++ /* rp_buflen already zeroed; skip caching */ ++ goto status; ++ } ++ } else if (so->so_replay.rp_buf != so->so_replay.rp_ibuf) { ++ nfs4_replay_free_cache(&so->so_replay); + } ++ so->so_replay.rp_buflen = len; ++ read_bytes_from_xdr_buf(xdr->buf, ++ op_status_offset + XDR_UNIT, ++ so->so_replay.rp_buf, len); + } + status: + op->status = nfsd4_map_status(op->status, +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index c0ca115c3b74b..2c836984ad0f1 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -549,10 +549,10 @@ struct nfs4_client_reclaim { + * ~32(deleg. ace) = 112 bytes + * + * Some responses can exceed this. A LOCK denial includes the conflicting +- * lock owner, which can be up to 1024 bytes (NFS4_OPAQUE_LIMIT). Responses +- * larger than REPLAY_ISIZE are not cached in rp_ibuf; only rp_status is +- * saved. Enlarging this constant increases the size of every +- * nfs4_stateowner. ++ * lock owner, which can be up to 1024 bytes (NFS4_OPAQUE_LIMIT). When a ++ * response exceeds REPLAY_ISIZE, a buffer is dynamically allocated. If ++ * that allocation fails, only rp_status is saved. Enlarging this constant ++ * increases the size of every nfs4_stateowner. + */ + + #define NFSD4_REPLAY_ISIZE 112 +@@ -564,12 +564,14 @@ struct nfs4_client_reclaim { + struct nfs4_replay { + __be32 rp_status; + unsigned int rp_buflen; +- char *rp_buf; ++ char *rp_buf; /* rp_ibuf or kmalloc'd */ + struct knfsd_fh rp_openfh; + int rp_locked; + char rp_ibuf[NFSD4_REPLAY_ISIZE]; + }; + ++extern void nfs4_replay_free_cache(struct nfs4_replay *rp); ++ + struct nfs4_stateowner; + + struct nfs4_stateowner_operations { +-- +2.53.0 + diff --git a/queue-7.0/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch b/queue-7.0/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch new file mode 100644 index 0000000000..eeffbae412 --- /dev/null +++ b/queue-7.0/nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch @@ -0,0 +1,61 @@ +From 253b1832e1250d26739b38feeb60306d7787a9ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 02:52:09 +0900 +Subject: nilfs2: reject zero bd_oblocknr in nilfs_ioctl_mark_blocks_dirty() + +From: Deepanshu Kartikey + +[ Upstream commit be3e5d10643d3be1cbac9d9939f220a99253f980 ] + +nilfs_ioctl_mark_blocks_dirty() uses bd_oblocknr to detect dead blocks +by comparing it with the current block number bd_blocknr. If they differ, +the block is considered dead and skipped. + +However, bd_oblocknr should never be 0 since block 0 typically stores the +primary superblock and is never a valid GC target block. A corrupted ioctl +request with bd_oblocknr set to 0 causes the comparison to incorrectly +match when the lookup returns -ENOENT and sets bd_blocknr to 0, bypassing +the dead block check and calling nilfs_bmap_mark() on a non-existent +block. This causes nilfs_btree_do_lookup() to return -ENOENT, triggering +the WARN_ON(ret == -ENOENT). + +Fix this by rejecting ioctl requests with bd_oblocknr set to 0 at the +beginning of each iteration. + +[ryusuke: slightly modified the commit message and comments for accuracy] + +Fixes: 7942b919f732 ("nilfs2: ioctl operations") +Reported-by: syzbot+98a040252119df0506f8@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=98a040252119df0506f8 +Suggested-by: Ryusuke Konishi +Signed-off-by: Deepanshu Kartikey +Reported-by: syzbot+466a45fcfb0562f5b9a0@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=466a45fcfb0562f5b9a0 +Cc: Junjie Cao +Signed-off-by: Ryusuke Konishi +Signed-off-by: Viacheslav Dubeyko +Signed-off-by: Sasha Levin +--- + fs/nilfs2/ioctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c +index e17b8da664913..e0a606643e879 100644 +--- a/fs/nilfs2/ioctl.c ++++ b/fs/nilfs2/ioctl.c +@@ -736,6 +736,12 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, + int ret, i; + + for (i = 0; i < nmembs; i++) { ++ /* ++ * bd_oblocknr must never be 0 as block 0 ++ * is never a valid GC target block ++ */ ++ if (unlikely(!bdescs[i].bd_oblocknr)) ++ return -EINVAL; + /* XXX: use macro or inline func to check liveness */ + ret = nilfs_bmap_lookup_at_level(bmap, + bdescs[i].bd_offset, +-- +2.53.0 + diff --git a/queue-7.0/nstree-fix-func.-parameter-kernel-doc-warnings.patch b/queue-7.0/nstree-fix-func.-parameter-kernel-doc-warnings.patch new file mode 100644 index 0000000000..6725842f3a --- /dev/null +++ b/queue-7.0/nstree-fix-func.-parameter-kernel-doc-warnings.patch @@ -0,0 +1,59 @@ +From 7176a0bc95af747f66c1e333f89e996739ea7f06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:54:29 -0700 +Subject: nstree: fix func. parameter kernel-doc warnings + +From: Randy Dunlap + +[ Upstream commit 43eb354ecb471426e97b0ce6a0c922ec20f82027 ] + +Use the correct parameter name ("__ns") for function parameter kernel-doc +to avoid 3 warnings: + +Warning: include/linux/nstree.h:68 function parameter '__ns' not described in 'ns_tree_add_raw' +Warning: include/linux/nstree.h:77 function parameter '__ns' not described in 'ns_tree_add' +Warning: include/linux/nstree.h:88 function parameter '__ns' not described in 'ns_tree_remove' + +Fixes: 885fc8ac0a4d ("nstree: make iterator generic") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260416215429.948898-1-rdunlap@infradead.org +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + include/linux/nstree.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/include/linux/nstree.h b/include/linux/nstree.h +index 175e4625bfa6d..5b64d45728819 100644 +--- a/include/linux/nstree.h ++++ b/include/linux/nstree.h +@@ -61,7 +61,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t + + /** + * ns_tree_add_raw - Add a namespace to a namespace +- * @ns: Namespace to add ++ * @__ns: Namespace to add + * + * This function adds a namespace to the appropriate namespace tree + * without assigning a id. +@@ -70,7 +70,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t + + /** + * ns_tree_add - Add a namespace to a namespace tree +- * @ns: Namespace to add ++ * @__ns: Namespace to add + * + * This function assigns a new id to the namespace and adds it to the + * appropriate namespace tree and list. +@@ -81,7 +81,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t + + /** + * ns_tree_remove - Remove a namespace from a namespace tree +- * @ns: Namespace to remove ++ * @__ns: Namespace to remove + * + * This function removes a namespace from the appropriate namespace + * tree and list. +-- +2.53.0 + diff --git a/queue-7.0/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch b/queue-7.0/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch new file mode 100644 index 0000000000..01e29eeec1 --- /dev/null +++ b/queue-7.0/nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch @@ -0,0 +1,39 @@ +From da3342ae721bc6e2b2939b4d9c746ab0b71ed06b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 09:14:02 -0700 +Subject: nvme-pci: fix missed admin queue sq doorbell write + +From: Keith Busch + +[ Upstream commit 1cc4cdae2a3b7730d462d69e30f213fd2efe7807 ] + +We can batch admin commands submitted through io_uring_cmd passthrough, +which means bd->last may be false and skips the doorbell write to +aggregate multiple commands per write. If a subsequent command can't be +dispatched for whatever reason, we have to provide the blk-mq ops' +commit_rqs callback in order to ensure we properly update the doorbell. + +Fixes: 58e5bdeb9c2b ("nvme: enable uring-passthrough for admin commands") +Reviewed-by: Christoph Hellwig +Reviewed-by: Kanchan Joshi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index db5fc9bf66272..4c052ed18cb8d 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2241,6 +2241,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled) + static const struct blk_mq_ops nvme_mq_admin_ops = { + .queue_rq = nvme_queue_rq, + .complete = nvme_pci_complete_rq, ++ .commit_rqs = nvme_commit_rqs, + .init_hctx = nvme_admin_init_hctx, + .init_request = nvme_pci_init_request, + .timeout = nvme_timeout, +-- +2.53.0 + diff --git a/queue-7.0/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch b/queue-7.0/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch new file mode 100644 index 0000000000..e2598a868e --- /dev/null +++ b/queue-7.0/nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch @@ -0,0 +1,162 @@ +From 6851b78e09a0b4ba880bfa24af685a725f269883 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Mar 2026 15:39:35 +0100 +Subject: nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its + callers + +From: Maurizio Lombardi + +[ Upstream commit ea8e356acb165cb1fd75537a52e1f66e5e76c538 ] + +Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds +PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) +and returns early. However, because the function returns void, the +callers are entirely unaware that a fatal error has occurred and +that the cmd->recv_msg.msg_iter was left uninitialized. + +Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly +overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA +Consequently, the socket receiving loop may attempt to read incoming +network data into the uninitialized iterator. + +Fix this by shifting the error handling responsibility to the callers. + +Fixes: 52a0a9854934 ("nvmet-tcp: add bounds checks in nvmet_tcp_build_pdu_iovec") +Reviewed-by: Hannes Reinecke +Reviewed-by: Yunje Shin +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Maurizio Lombardi +Signed-off-by: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/nvme/target/tcp.c | 51 ++++++++++++++++++++++----------------- + 1 file changed, 29 insertions(+), 22 deletions(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 255ebd948dfe1..dc65894696ad9 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -351,7 +351,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd) + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue); + +-static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) ++static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + { + struct bio_vec *iov = cmd->iov; + struct scatterlist *sg; +@@ -364,22 +364,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + offset = cmd->rbytes_done; + cmd->sg_idx = offset / PAGE_SIZE; + sg_offset = offset % PAGE_SIZE; +- if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) ++ return -EPROTO; ++ + sg = &cmd->req.sg[cmd->sg_idx]; + sg_remaining = cmd->req.sg_cnt - cmd->sg_idx; + + while (length) { +- if (!sg_remaining) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } +- if (!sg->length || sg->length <= sg_offset) { +- nvmet_tcp_fatal_error(cmd->queue); +- return; +- } ++ if (!sg_remaining) ++ return -EPROTO; ++ ++ if (!sg->length || sg->length <= sg_offset) ++ return -EPROTO; ++ + u32 iov_len = min_t(u32, length, sg->length - sg_offset); + + bvec_set_page(iov, sg_page(sg), iov_len, +@@ -394,6 +391,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) + + iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov, + nr_pages, cmd->pdu_len); ++ return 0; + } + + static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue) +@@ -957,7 +955,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) + return 0; + } + +-static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, ++static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) + { + size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); +@@ -973,19 +971,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + if (!nvme_is_write(cmd->req.cmd) || !data_len || + data_len > cmd->req.port->inline_data_size) { + nvmet_prepare_receive_pdu(queue); +- return; ++ return 0; + } + + ret = nvmet_tcp_map_data(cmd); + if (unlikely(ret)) { + pr_err("queue %d: failed to map data\n", queue->idx); + nvmet_tcp_fatal_error(queue); +- return; ++ return -EPROTO; + } + + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(cmd); + cmd->flags |= NVMET_TCP_F_INIT_FAILED; ++ ret = nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ ++ return ret; + } + + static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) +@@ -1037,7 +1039,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) + goto err_proto; + } + cmd->pdu_recv = 0; +- nvmet_tcp_build_pdu_iovec(cmd); ++ if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) { ++ pr_err("queue %d: failed to build PDU iovec\n", queue->idx); ++ goto err_proto; ++ } + queue->cmd = cmd; + queue->rcv_state = NVMET_TCP_RECV_DATA; + +@@ -1100,8 +1105,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + le32_to_cpu(req->cmd->common.dptr.sgl.length), + le16_to_cpu(req->cqe->status)); + +- nvmet_tcp_handle_req_failure(queue, queue->cmd, req); +- return 0; ++ return nvmet_tcp_handle_req_failure(queue, queue->cmd, req); + } + + ret = nvmet_tcp_map_data(queue->cmd); +@@ -1118,8 +1122,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + if (nvmet_tcp_need_data_in(queue->cmd)) { + if (nvmet_tcp_has_inline_data(queue->cmd)) { + queue->rcv_state = NVMET_TCP_RECV_DATA; +- nvmet_tcp_build_pdu_iovec(queue->cmd); +- return 0; ++ ret = nvmet_tcp_build_pdu_iovec(queue->cmd); ++ if (unlikely(ret)) ++ pr_err("queue %d: failed to build PDU iovec\n", ++ queue->idx); ++ return ret; + } + /* send back R2T */ + nvmet_tcp_queue_response(&queue->cmd->req); +-- +2.53.0 + diff --git a/queue-7.0/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch b/queue-7.0/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch new file mode 100644 index 0000000000..dd86d34c15 --- /dev/null +++ b/queue-7.0/ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch @@ -0,0 +1,48 @@ +From 410549986d08db0f3778760053655dd627225b12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:09 +0800 +Subject: ocfs2/dlm: fix off-by-one in dlm_match_regions() region comparison + +From: Junrui Luo + +[ Upstream commit 01b61e8dda9b0fdb0d4cda43de25f4e390554d7b ] + +The local-vs-remote region comparison loop uses '<=' instead of '<', +causing it to read one entry past the valid range of qr_regions. The +other loops in the same function correctly use '<'. + +Fix the loop condition to use '<' for consistency and correctness. + +Link: https://lkml.kernel.org/r/SYBPR01MB78813DA26B50EC5E01F00566AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 0a28cb5ded2ab..dc9da9133c8ee 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1002,7 +1002,7 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + for (i = 0; i < localnr; ++i) { + foundit = 0; + r = remote; +- for (j = 0; j <= qr->qr_numregions; ++j) { ++ for (j = 0; j < qr->qr_numregions; ++j) { + if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) { + foundit = 1; + break; +-- +2.53.0 + diff --git a/queue-7.0/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch b/queue-7.0/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch new file mode 100644 index 0000000000..0e0c7b78fb --- /dev/null +++ b/queue-7.0/ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch @@ -0,0 +1,75 @@ +From c18340ba40095c72a550b27844064b2ef087c41f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:21:08 +0800 +Subject: ocfs2/dlm: validate qr_numregions in dlm_match_regions() + +From: Junrui Luo + +[ Upstream commit 7ab3fbb01bc6d79091bc375e5235d360cd9b78be ] + +Patch series "ocfs2/dlm: fix two bugs in dlm_match_regions()". + +In dlm_match_regions(), the qr_numregions field from a DLM_QUERY_REGION +network message is used to drive loops over the qr_regions buffer without +sufficient validation. This series fixes two issues: + +- Patch 1 adds a bounds check to reject messages where qr_numregions + exceeds O2NM_MAX_REGIONS. The o2net layer only validates message + byte length; it does not constrain field values, so a crafted message + can set qr_numregions up to 255 and trigger out-of-bounds reads past + the 1024-byte qr_regions buffer. + +- Patch 2 fixes an off-by-one in the local-vs-remote comparison loop, + which uses '<=' instead of '<', reading one entry past the valid range + even when qr_numregions is within bounds. + +This patch (of 2): + +The qr_numregions field from a DLM_QUERY_REGION network message is used +directly as loop bounds in dlm_match_regions() without checking against +O2NM_MAX_REGIONS. Since qr_regions is sized for at most O2NM_MAX_REGIONS +(32) entries, a crafted message with qr_numregions > 32 causes +out-of-bounds reads past the qr_regions buffer. + +Add a bounds check for qr_numregions before entering the loops. + +Link: https://lkml.kernel.org/r/SYBPR01MB7881A334D02ACEE5E0645801AF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Link: https://lkml.kernel.org/r/SYBPR01MB788166F524AD04E262E174BEAF7BA@SYBPR01MB7881.ausprd01.prod.outlook.com +Fixes: ea2034416b54 ("ocfs2/dlm: Add message DLM_QUERY_REGION") +Signed-off-by: Junrui Luo +Reported-by: Yuhao Jiang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/dlm/dlmdomain.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 70ca79e4bdc3f..0a28cb5ded2ab 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -980,6 +980,14 @@ static int dlm_match_regions(struct dlm_ctxt *dlm, + goto bail; + } + ++ if (qr->qr_numregions > O2NM_MAX_REGIONS) { ++ mlog(ML_ERROR, "Domain %s: Joining node %d has invalid " ++ "number of heartbeat regions %u\n", ++ qr->qr_domain, qr->qr_node, qr->qr_numregions); ++ status = -EINVAL; ++ goto bail; ++ } ++ + r = remote; + for (i = 0; i < qr->qr_numregions; ++i) { + mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r); +-- +2.53.0 + diff --git a/queue-7.0/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch b/queue-7.0/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch new file mode 100644 index 0000000000..93dfba4cb8 --- /dev/null +++ b/queue-7.0/ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch @@ -0,0 +1,89 @@ +From 42852c18aff0381bbb697654a828e3b30ff0ecc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 12:03:39 +0800 +Subject: ocfs2: fix listxattr handling when the buffer is full + +From: ZhengYuan Huang + +[ Upstream commit d12f558e6200b3f47dbef9331ed6d115d2410e59 ] + +[BUG] +If an OCFS2 inode has both inline and block-based xattrs, listxattr() +can return a size larger than the caller's buffer when the inline names +consume that buffer exactly. + +kernel BUG at mm/usercopy.c:102! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:usercopy_abort+0xb7/0xd0 mm/usercopy.c:102 +Call Trace: + __check_heap_object+0xe3/0x120 mm/slub.c:8243 + check_heap_object mm/usercopy.c:196 [inline] + __check_object_size mm/usercopy.c:250 [inline] + __check_object_size+0x5c5/0x780 mm/usercopy.c:215 + check_object_size include/linux/ucopysize.h:22 [inline] + check_copy_size include/linux/ucopysize.h:59 [inline] + copy_to_user include/linux/uaccess.h:219 [inline] + listxattr+0xb0/0x170 fs/xattr.c:926 + filename_listxattr fs/xattr.c:958 [inline] + path_listxattrat+0x137/0x320 fs/xattr.c:988 + __do_sys_listxattr fs/xattr.c:1001 [inline] + __se_sys_listxattr fs/xattr.c:998 [inline] + __x64_sys_listxattr+0x7f/0xd0 fs/xattr.c:998 + ... + +[CAUSE] +Commit 936b8834366e ("ocfs2: Refactor xattr list and remove +ocfs2_xattr_handler().") replaced the old per-handler list accounting +with ocfs2_xattr_list_entry(), but it kept using size == 0 to detect +probe mode. + +That assumption stops being true once ocfs2_listxattr() finishes the +inline-xattr pass. If the inline names fill the caller buffer exactly, +the block-xattr pass runs with a non-NULL buffer and a remaining size of +zero. ocfs2_xattr_list_entry() then skips the bounds check, keeps +counting block names, and returns a positive size larger than the +supplied buffer. + +[FIX] +Detect probe mode by testing whether the destination buffer pointer is +NULL instead of whether the remaining size is zero. + +That restores the pre-refactor behavior and matches the OCFS2 getxattr +helpers. Once the remaining buffer reaches zero while more names are +left, the block-xattr pass now returns -ERANGE instead of reporting a +size larger than the allocated list buffer. + +Link: https://lkml.kernel.org/r/20260410040339.3837162-1-gality369@gmail.com +Fixes: 936b8834366e ("ocfs2: Refactor xattr list and remove ocfs2_xattr_handler().") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 42ee5db362d3e..b9a6bdbf596c2 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -911,8 +911,8 @@ static int ocfs2_xattr_list_entry(struct super_block *sb, + total_len = prefix_len + name_len + 1; + *result += total_len; + +- /* we are just looking for how big our buffer needs to be */ +- if (!size) ++ /* No buffer means we are only looking for the required size. */ ++ if (!buffer) + return 0; + + if (*result > size) +-- +2.53.0 + diff --git a/queue-7.0/ocfs2-validate-bg_bits-during-freefrag-scan.patch b/queue-7.0/ocfs2-validate-bg_bits-during-freefrag-scan.patch new file mode 100644 index 0000000000..dd65fd40b9 --- /dev/null +++ b/queue-7.0/ocfs2-validate-bg_bits-during-freefrag-scan.patch @@ -0,0 +1,121 @@ +From 4d163105f2a5f6f206c0dade585635572ddc44ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:42:20 +0800 +Subject: ocfs2: validate bg_bits during freefrag scan + +From: ZhengYuan Huang + +[ Upstream commit 8f687eeed3da3012152b0f9473f578869de0cd7b ] + +[BUG] +A crafted filesystem can trigger an out-of-bounds bitmap walk when +OCFS2_IOC_INFO is issued with OCFS2_INFO_FL_NON_COHERENT. + +BUG: KASAN: use-after-free in instrument_atomic_read include/linux/instrumented.h:68 [inline] +BUG: KASAN: use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] +BUG: KASAN: use-after-free in test_bit_le include/asm-generic/bitops/le.h:21 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] +BUG: KASAN: use-after-free in ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] +BUG: KASAN: use-after-free in ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 +Read of size 8 at addr ffff888031bce000 by task syz.0.636/1435 +Call Trace: + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0xd1/0x650 mm/kasan/report.c:482 + kasan_report+0xfb/0x140 mm/kasan/report.c:595 + check_region_inline mm/kasan/generic.c:186 [inline] + kasan_check_range+0x11c/0x200 mm/kasan/generic.c:200 + __kasan_check_read+0x11/0x20 mm/kasan/shadow.c:31 + instrument_atomic_read include/linux/instrumented.h:68 [inline] + _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] + test_bit_le include/asm-generic/bitops/le.h:21 [inline] + ocfs2_info_freefrag_scan_chain fs/ocfs2/ioctl.c:495 [inline] + ocfs2_info_freefrag_scan_bitmap fs/ocfs2/ioctl.c:588 [inline] + ocfs2_info_handle_freefrag fs/ocfs2/ioctl.c:662 [inline] + ocfs2_info_handle_request+0x1c66/0x3370 fs/ocfs2/ioctl.c:754 + ocfs2_info_handle+0x18d/0x2a0 fs/ocfs2/ioctl.c:828 + ocfs2_ioctl+0x632/0x6e0 fs/ocfs2/ioctl.c:913 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + ... + +[CAUSE] +ocfs2_info_freefrag_scan_chain() uses on-disk bg_bits directly as the +bitmap scan limit. The coherent path reads group descriptors through +ocfs2_read_group_descriptor(), which validates the descriptor before +use. The non-coherent path uses ocfs2_read_blocks_sync() instead and +skips that validation, so an impossible bg_bits value can drive the +bitmap walk past the end of the block. + +[FIX] +Compute the bitmap capacity from the filesystem format with +ocfs2_group_bitmap_size(), report descriptors whose bg_bits exceeds +that limit, and clamp the scan to the computed capacity. This keeps the +freefrag report going while avoiding reads beyond the buffer. + +Link: https://lkml.kernel.org/r/20260410034220.3825769-1-gality369@gmail.com +Fixes: d24a10b9f8ed ("Ocfs2: Add a new code 'OCFS2_INFO_FREEFRAG' for o2info ioctl.") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Heming Zhao +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/ioctl.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c +index bfed0fb35f9bd..cbe59d2316663 100644 +--- a/fs/ocfs2/ioctl.c ++++ b/fs/ocfs2/ioctl.c +@@ -441,13 +441,16 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + struct buffer_head *bh = NULL; + struct ocfs2_group_desc *bg = NULL; + +- unsigned int max_bits, num_clusters; ++ unsigned int max_bits, max_bitmap_bits, num_clusters; + unsigned int offset = 0, cluster, chunk; + unsigned int chunk_free, last_chunksize = 0; + + if (!le32_to_cpu(rec->c_free)) + goto bail; + ++ max_bitmap_bits = 8 * ocfs2_group_bitmap_size(osb->sb, 0, ++ osb->s_feature_incompat); ++ + do { + if (!bg) + blkno = le64_to_cpu(rec->c_blkno); +@@ -479,6 +482,19 @@ static int ocfs2_info_freefrag_scan_chain(struct ocfs2_super *osb, + continue; + + max_bits = le16_to_cpu(bg->bg_bits); ++ ++ /* ++ * Non-coherent scans read raw blocks and do not get the ++ * bg_bits validation from ++ * ocfs2_read_group_descriptor(). ++ */ ++ if (max_bits > max_bitmap_bits) { ++ mlog(ML_ERROR, ++ "Group desc #%llu has %u bits, max bitmap bits %u\n", ++ (unsigned long long)blkno, max_bits, max_bitmap_bits); ++ max_bits = max_bitmap_bits; ++ } ++ + offset = 0; + + for (chunk = 0; chunk < chunks_in_group; chunk++) { +-- +2.53.0 + diff --git a/queue-7.0/ocfs2-validate-group-add-input-before-caching.patch b/queue-7.0/ocfs2-validate-group-add-input-before-caching.patch new file mode 100644 index 0000000000..369f226754 --- /dev/null +++ b/queue-7.0/ocfs2-validate-group-add-input-before-caching.patch @@ -0,0 +1,110 @@ +From f006703acb8f7e48f7a86a89dc83afca23522e48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 10:02:08 +0800 +Subject: ocfs2: validate group add input before caching + +From: ZhengYuan Huang + +[ Upstream commit 70b672833f4025341c11b22c7f83778a5cd611bc ] + +[BUG] +OCFS2_IOC_GROUP_ADD can trigger a BUG_ON in +ocfs2_set_new_buffer_uptodate(): + +kernel BUG at fs/ocfs2/uptodate.c:509! +Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI +RIP: 0010:ocfs2_set_new_buffer_uptodate+0x194/0x1e0 fs/ocfs2/uptodate.c:509 +Code: ffffe88f 42b9fe4c 89e64889 dfe8b4df +Call Trace: + ocfs2_group_add+0x3f1/0x1510 fs/ocfs2/resize.c:507 + ocfs2_ioctl+0x309/0x6e0 fs/ocfs2/ioctl.c:887 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:597 [inline] + __se_sys_ioctl fs/ioctl.c:583 [inline] + __x64_sys_ioctl+0x197/0x1e0 fs/ioctl.c:583 + x64_sys_call+0x1144/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:17 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x76/0x7e +RIP: 0033:0x7bbfb55a966d + +[CAUSE] +ocfs2_group_add() calls ocfs2_set_new_buffer_uptodate() on a +user-controlled group block before ocfs2_verify_group_and_input() +validates that block number. That helper is only valid for newly +allocated metadata and asserts that the block is not already present in +the chosen metadata cache. The code also uses INODE_CACHE(inode) even +though the group descriptor belongs to main_bm_inode and later journal +accesses use that cache context instead. + +[FIX] +Validate the on-disk group descriptor before caching it, then add it to +the metadata cache tracked by INODE_CACHE(main_bm_inode). Keep the +validation failure path separate from the later cleanup path so we only +remove the buffer from that cache after it has actually been inserted. +This keeps the group buffer lifetime consistent across validation, +journaling, and cleanup. + +Link: https://lkml.kernel.org/r/20260410020209.3786348-1-gality369@gmail.com +Fixes: 7909f2bf8353 ("[PATCH 2/2] ocfs2: Implement group add for online resize") +Signed-off-by: ZhengYuan Huang +Reviewed-by: Joseph Qi +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Junxiao Bi +Cc: Changwei Ge +Cc: Jun Piao +Cc: Heming Zhao +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + fs/ocfs2/resize.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c +index 09724e7dc01ba..6375d50359725 100644 +--- a/fs/ocfs2/resize.c ++++ b/fs/ocfs2/resize.c +@@ -508,14 +508,14 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + goto out_unlock; + } + +- ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), group_bh); +- + ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); + if (ret) { + mlog_errno(ret); + goto out_free_group_bh; + } + ++ ocfs2_set_new_buffer_uptodate(INODE_CACHE(main_bm_inode), group_bh); ++ + trace_ocfs2_group_add((unsigned long long)input->group, + input->chain, input->clusters, input->frees); + +@@ -523,7 +523,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + if (IS_ERR(handle)) { + mlog_errno(PTR_ERR(handle)); + ret = -EINVAL; +- goto out_free_group_bh; ++ goto out_remove_cache; + } + + cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); +@@ -577,9 +577,11 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) + out_commit: + ocfs2_commit_trans(osb, handle); + +-out_free_group_bh: ++out_remove_cache: + if (ret < 0) +- ocfs2_remove_from_cache(INODE_CACHE(inode), group_bh); ++ ocfs2_remove_from_cache(INODE_CACHE(main_bm_inode), group_bh); ++ ++out_free_group_bh: + brelse(group_bh); + + out_unlock: +-- +2.53.0 + diff --git a/queue-7.0/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch b/queue-7.0/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch new file mode 100644 index 0000000000..b9f05eba8e --- /dev/null +++ b/queue-7.0/openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch @@ -0,0 +1,132 @@ +From f009ad57dad5cdb14be51dc6da61a7c4efb553e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 19:46:54 -0700 +Subject: openvswitch: cap upcall PID array size and pre-size vport replies + +From: Weiming Shi + +[ Upstream commit 2091c6aa0df6aba47deb5c8ab232b1cb60af3519 ] + +The vport netlink reply helpers allocate a fixed-size skb with +nlmsg_new(NLMSG_DEFAULT_SIZE, ...) but serialize the full upcall PID +array via ovs_vport_get_upcall_portids(). Since +ovs_vport_set_upcall_portids() accepts any non-zero multiple of +sizeof(u32) with no upper bound, a CAP_NET_ADMIN user can install a PID +array large enough to overflow the reply buffer, causing nla_put() to +fail with -EMSGSIZE and hitting BUG_ON(err < 0). On systems with +unprivileged user namespaces enabled (e.g., Ubuntu default), this is +reachable via unshare -Urn since OVS vport mutation operations use +GENL_UNS_ADMIN_PERM. + + kernel BUG at net/openvswitch/datapath.c:2414! + Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI + CPU: 1 UID: 0 PID: 65 Comm: poc Not tainted 7.0.0-rc7-00195-geb216e422044 #1 + RIP: 0010:ovs_vport_cmd_set+0x34c/0x400 + Call Trace: + + genl_family_rcv_msg_doit (net/netlink/genetlink.c:1116) + genl_rcv_msg (net/netlink/genetlink.c:1194) + netlink_rcv_skb (net/netlink/af_netlink.c:2550) + genl_rcv (net/netlink/genetlink.c:1219) + netlink_unicast (net/netlink/af_netlink.c:1344) + netlink_sendmsg (net/netlink/af_netlink.c:1894) + __sys_sendto (net/socket.c:2206) + __x64_sys_sendto (net/socket.c:2209) + do_syscall_64 (arch/x86/entry/syscall_64.c:63) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + + Kernel panic - not syncing: Fatal exception + +Reject attempts to set more PIDs than nr_cpu_ids in +ovs_vport_set_upcall_portids(), and pre-compute the worst-case reply +size in ovs_vport_cmd_msg_size() based on that bound, similar to the +existing ovs_dp_cmd_msg_size(). nr_cpu_ids matches the cap already +used by the per-CPU dispatch configuration on the datapath side +(ovs_dp_cmd_fill_info() serialises at most nr_cpu_ids PIDs), so the +two sides stay consistent. + +Fixes: 5cd667b0a456 ("openvswitch: Allow each vport to have an array of 'port_id's.") +Reported-by: Xiang Mei +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Weiming Shi +Reviewed-by: Ilya Maximets +Link: https://patch.msgid.link/20260416024653.153456-2-bestswngs@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 35 +++++++++++++++++++++++++++++++++-- + net/openvswitch/vport.c | 3 +++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index e209099218b41..bbbde50fc6498 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -2184,9 +2184,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + return err; + } + ++static size_t ovs_vport_cmd_msg_size(void) ++{ ++ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header)); ++ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_PORT_NO */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_TYPE */ ++ msgsize += nla_total_size(IFNAMSIZ); /* OVS_VPORT_ATTR_NAME */ ++ msgsize += nla_total_size(sizeof(u32)); /* OVS_VPORT_ATTR_IFINDEX */ ++ msgsize += nla_total_size(sizeof(s32)); /* OVS_VPORT_ATTR_NETNSID */ ++ ++ /* OVS_VPORT_ATTR_STATS */ ++ msgsize += nla_total_size_64bit(sizeof(struct ovs_vport_stats)); ++ ++ /* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + ++ * OVS_VPORT_UPCALL_ATTR_FAIL) ++ */ ++ msgsize += nla_total_size(nla_total_size_64bit(sizeof(u64)) + ++ nla_total_size_64bit(sizeof(u64))); ++ ++ /* OVS_VPORT_ATTR_UPCALL_PID */ ++ msgsize += nla_total_size(nr_cpu_ids * sizeof(u32)); ++ ++ /* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + ++ * OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) ++ */ ++ msgsize += nla_total_size(nla_total_size(sizeof(u16)) + ++ nla_total_size(nla_total_size(0))); ++ ++ return msgsize; ++} ++ + static struct sk_buff *ovs_vport_cmd_alloc_info(void) + { +- return nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ return genlmsg_new(ovs_vport_cmd_msg_size(), GFP_KERNEL); + } + + /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */ +@@ -2196,7 +2227,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net, + struct sk_buff *skb; + int retval; + +- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ skb = ovs_vport_cmd_alloc_info(); + if (!skb) + return ERR_PTR(-ENOMEM); + +diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c +index 23f629e94a36a..56b2e2d1a749f 100644 +--- a/net/openvswitch/vport.c ++++ b/net/openvswitch/vport.c +@@ -406,6 +406,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids) + if (!nla_len(ids) || nla_len(ids) % sizeof(u32)) + return -EINVAL; + ++ if (nla_len(ids) / sizeof(u32) > nr_cpu_ids) ++ return -EINVAL; ++ + old = ovsl_dereference(vport->upcall_portids); + + vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids), +-- +2.53.0 + diff --git a/queue-7.0/opp-debugfs-use-performance-level-if-available-to-di.patch b/queue-7.0/opp-debugfs-use-performance-level-if-available-to-di.patch new file mode 100644 index 0000000000..104a88b1d9 --- /dev/null +++ b/queue-7.0/opp-debugfs-use-performance-level-if-available-to-di.patch @@ -0,0 +1,69 @@ +From 3be073b1d20060478e9eba68bc5b3f3dd0e74b28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 12:49:40 +0530 +Subject: OPP: debugfs: Use performance level if available to distinguish + between rates + +From: Manivannan Sadhasivam + +[ Upstream commit e560083c0467f86b72aecac377b27bd1e7d16c49 ] + +Some OPP tables have entries with same rate and different performance +level. For these entries, using only the rate as the debugfs directory name +causes below error: + +debugfs: 'opp:5000000' already exists in 'soc@0-1c00000.pci' + +Fix it by appending the performance level to the dir name if available. + +Reported-by: Bjorn Andersson +Closes: https://lore.kernel.org/linux-arm-msm/75lzykd37zdvrks5i2bb4zb2yzjtm25kv3hegmikndkbr772mz@w2ykff3ny45u/ +Fixes: 05db35963eef ("OPP: Add support to find OPP for a set of keys") +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/opp/debugfs.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c +index 8fc6238b17284..61506d30d5ff0 100644 +--- a/drivers/opp/debugfs.c ++++ b/drivers/opp/debugfs.c +@@ -130,22 +130,24 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) + { + struct dentry *pdentry = opp_table->dentry; + struct dentry *d; +- unsigned long id; +- char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */ ++ char name[36]; /* "opp:"(4) + u64(20) + "-" (1) + u32(10) + NULL(1) */ + + /* + * Get directory name for OPP. + * +- * - Normally rate is unique to each OPP, use it to get unique opp-name. ++ * - Normally rate is unique to each OPP, use it to get unique opp-name, ++ * together with performance level if available. + * - For some devices rate isn't available or there are multiple, use + * index instead for them. + */ +- if (likely(opp_table->clk_count == 1 && opp->rates[0])) +- id = opp->rates[0]; +- else +- id = _get_opp_count(opp_table); +- +- snprintf(name, sizeof(name), "opp:%lu", id); ++ if (likely(opp_table->clk_count == 1 && opp->rates[0])) { ++ if (opp->level == OPP_LEVEL_UNSET) ++ snprintf(name, sizeof(name), "opp:%lu", opp->rates[0]); ++ else ++ snprintf(name, sizeof(name), "opp:%lu-%u", opp->rates[0], opp->level); ++ } else { ++ snprintf(name, sizeof(name), "opp:%u", _get_opp_count(opp_table)); ++ } + + /* Create per-opp directory */ + d = debugfs_create_dir(name, pdentry); +-- +2.53.0 + diff --git a/queue-7.0/opp-move-break-out-of-scoped_guard-in-dev_pm_opp_xla.patch b/queue-7.0/opp-move-break-out-of-scoped_guard-in-dev_pm_opp_xla.patch new file mode 100644 index 0000000000..d3ab3ff473 --- /dev/null +++ b/queue-7.0/opp-move-break-out-of-scoped_guard-in-dev_pm_opp_xla.patch @@ -0,0 +1,44 @@ +From 58fa83ff43e1a92da9e63375915a889afb5f8604 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 11:05:59 +0530 +Subject: OPP: Move break out of scoped_guard in + dev_pm_opp_xlate_required_opp() + +From: Viresh Kumar + +[ Upstream commit 3d2398f44a2d48fb1c575a6e0bc6b38f3e689e22 ] + +The commit ff9c512041f2 ("OPP: Use mutex locking guards") +unintentionally made the for loop run longer than required. + +scoped_guard() is implemented as a for loop. The break statement now +breaks out out the scoped_guard() and not out of the outer for loop. +The outer loop always iterates to completion. + +Fix it. + +Fixes: ff9c512041f2 ("OPP: Use mutex locking guards") +Reported-by: David Lechner +Signed-off-by: Viresh Kumar +Signed-off-by: Sasha Levin +--- + drivers/opp/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index 866641666e410..da3f5eba43419 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -2742,8 +2742,8 @@ struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, + break; + } + } +- break; + } ++ break; + } + + if (IS_ERR(dest_opp)) { +-- +2.53.0 + diff --git a/queue-7.0/padata-put-cpu-offline-callback-in-online-section-to.patch b/queue-7.0/padata-put-cpu-offline-callback-in-online-section-to.patch new file mode 100644 index 0000000000..383004233c --- /dev/null +++ b/queue-7.0/padata-put-cpu-offline-callback-in-online-section-to.patch @@ -0,0 +1,371 @@ +From 4aea105c69631bc671fb3536d5f241b7012f4936 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 11:24:33 -0400 +Subject: padata: Put CPU offline callback in ONLINE section to allow failure + +From: Daniel Jordan + +[ Upstream commit c8c4a2972f83c8b68ff03b43cecdb898939ff851 ] + +syzbot reported the following warning: + + DEAD callback error for CPU1 + WARNING: kernel/cpu.c:1463 at _cpu_down+0x759/0x1020 kernel/cpu.c:1463, CPU#0: syz.0.1960/14614 + +at commit 4ae12d8bd9a8 ("Merge tag 'kbuild-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux") +which tglx traced to padata_cpu_dead() given it's the only +sub-CPUHP_TEARDOWN_CPU callback that returns an error. + +Failure isn't allowed in hotplug states before CPUHP_TEARDOWN_CPU +so move the CPU offline callback to the ONLINE section where failure is +possible. + +Fixes: 894c9ef9780c ("padata: validate cpumask without removed CPU during offline") +Reported-by: syzbot+123e1b70473ce213f3af@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69af0a05.050a0220.310d8.002f.GAE@google.com/ +Debugged-by: Thomas Gleixner +Signed-off-by: Daniel Jordan +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + include/linux/cpuhotplug.h | 1 - + include/linux/padata.h | 8 +-- + kernel/padata.c | 120 +++++++++++++++++++------------------ + 3 files changed, 65 insertions(+), 64 deletions(-) + +diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h +index 62cd7b35a29c9..22ba327ec2278 100644 +--- a/include/linux/cpuhotplug.h ++++ b/include/linux/cpuhotplug.h +@@ -92,7 +92,6 @@ enum cpuhp_state { + CPUHP_NET_DEV_DEAD, + CPUHP_IOMMU_IOVA_DEAD, + CPUHP_AP_ARM_CACHE_B15_RAC_DEAD, +- CPUHP_PADATA_DEAD, + CPUHP_AP_DTPM_CPU_DEAD, + CPUHP_RANDOM_PREPARE, + CPUHP_WORKQUEUE_PREP, +diff --git a/include/linux/padata.h b/include/linux/padata.h +index 765f2778e264a..b6232bea6edf5 100644 +--- a/include/linux/padata.h ++++ b/include/linux/padata.h +@@ -149,23 +149,23 @@ struct padata_mt_job { + /** + * struct padata_instance - The overall control structure. + * +- * @cpu_online_node: Linkage for CPU online callback. +- * @cpu_dead_node: Linkage for CPU offline callback. ++ * @cpuhp_node: Linkage for CPU hotplug callbacks. + * @parallel_wq: The workqueue used for parallel work. + * @serial_wq: The workqueue used for serial work. + * @pslist: List of padata_shell objects attached to this instance. + * @cpumask: User supplied cpumasks for parallel and serial works. ++ * @validate_cpumask: Internal cpumask used to validate @cpumask during hotplug. + * @kobj: padata instance kernel object. + * @lock: padata instance lock. + * @flags: padata flags. + */ + struct padata_instance { +- struct hlist_node cpu_online_node; +- struct hlist_node cpu_dead_node; ++ struct hlist_node cpuhp_node; + struct workqueue_struct *parallel_wq; + struct workqueue_struct *serial_wq; + struct list_head pslist; + struct padata_cpumask cpumask; ++ cpumask_var_t validate_cpumask; + struct kobject kobj; + struct mutex lock; + u8 flags; +diff --git a/kernel/padata.c b/kernel/padata.c +index 9e7cfa5ed55bc..0d3ea1b68b1f7 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -535,7 +535,8 @@ static void padata_init_reorder_list(struct parallel_data *pd) + } + + /* Allocate and initialize the internal cpumask dependend resources. */ +-static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) ++static struct parallel_data *padata_alloc_pd(struct padata_shell *ps, ++ int offlining_cpu) + { + struct padata_instance *pinst = ps->pinst; + struct parallel_data *pd; +@@ -561,6 +562,10 @@ static struct parallel_data *padata_alloc_pd(struct padata_shell *ps) + + cpumask_and(pd->cpumask.pcpu, pinst->cpumask.pcpu, cpu_online_mask); + cpumask_and(pd->cpumask.cbcpu, pinst->cpumask.cbcpu, cpu_online_mask); ++ if (offlining_cpu >= 0) { ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.pcpu); ++ __cpumask_clear_cpu(offlining_cpu, pd->cpumask.cbcpu); ++ } + + padata_init_reorder_list(pd); + padata_init_squeues(pd); +@@ -607,11 +612,11 @@ static void __padata_stop(struct padata_instance *pinst) + } + + /* Replace the internal control structure with a new one. */ +-static int padata_replace_one(struct padata_shell *ps) ++static int padata_replace_one(struct padata_shell *ps, int offlining_cpu) + { + struct parallel_data *pd_new; + +- pd_new = padata_alloc_pd(ps); ++ pd_new = padata_alloc_pd(ps, offlining_cpu); + if (!pd_new) + return -ENOMEM; + +@@ -621,7 +626,7 @@ static int padata_replace_one(struct padata_shell *ps) + return 0; + } + +-static int padata_replace(struct padata_instance *pinst) ++static int padata_replace(struct padata_instance *pinst, int offlining_cpu) + { + struct padata_shell *ps; + int err = 0; +@@ -629,7 +634,7 @@ static int padata_replace(struct padata_instance *pinst) + pinst->flags |= PADATA_RESET; + + list_for_each_entry(ps, &pinst->pslist, list) { +- err = padata_replace_one(ps); ++ err = padata_replace_one(ps, offlining_cpu); + if (err) + break; + } +@@ -646,9 +651,21 @@ static int padata_replace(struct padata_instance *pinst) + + /* If cpumask contains no active cpu, we mark the instance as invalid. */ + static bool padata_validate_cpumask(struct padata_instance *pinst, +- const struct cpumask *cpumask) ++ const struct cpumask *cpumask, ++ int offlining_cpu) + { +- if (!cpumask_intersects(cpumask, cpu_online_mask)) { ++ cpumask_copy(pinst->validate_cpumask, cpu_online_mask); ++ ++ /* ++ * @offlining_cpu is still in cpu_online_mask, so remove it here for ++ * validation. Using a sub-CPUHP_TEARDOWN_CPU hotplug state where ++ * @offlining_cpu wouldn't be in the online mask doesn't work because ++ * padata_cpu_offline() can fail but such a state doesn't allow failure. ++ */ ++ if (offlining_cpu >= 0) ++ __cpumask_clear_cpu(offlining_cpu, pinst->validate_cpumask); ++ ++ if (!cpumask_intersects(cpumask, pinst->validate_cpumask)) { + pinst->flags |= PADATA_INVALID; + return false; + } +@@ -664,13 +681,13 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + int valid; + int err; + +- valid = padata_validate_cpumask(pinst, pcpumask); ++ valid = padata_validate_cpumask(pinst, pcpumask, -1); + if (!valid) { + __padata_stop(pinst); + goto out_replace; + } + +- valid = padata_validate_cpumask(pinst, cbcpumask); ++ valid = padata_validate_cpumask(pinst, cbcpumask, -1); + if (!valid) + __padata_stop(pinst); + +@@ -678,7 +695,7 @@ static int __padata_set_cpumasks(struct padata_instance *pinst, + cpumask_copy(pinst->cpumask.pcpu, pcpumask); + cpumask_copy(pinst->cpumask.cbcpu, cbcpumask); + +- err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst); ++ err = padata_setup_cpumasks(pinst) ?: padata_replace(pinst, -1); + + if (valid) + __padata_start(pinst); +@@ -730,26 +747,6 @@ EXPORT_SYMBOL(padata_set_cpumask); + + #ifdef CONFIG_HOTPLUG_CPU + +-static int __padata_add_cpu(struct padata_instance *pinst, int cpu) +-{ +- int err = padata_replace(pinst); +- +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- +- return err; +-} +- +-static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) +-{ +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- return padata_replace(pinst); +-} +- + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) + { + return cpumask_test_cpu(cpu, pinst->cpumask.pcpu) || +@@ -761,27 +758,39 @@ static int padata_cpu_online(unsigned int cpu, struct hlist_node *node) + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_online_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_add_cpu(pinst, cpu); ++ ++ ret = padata_replace(pinst, -1); ++ ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu, -1) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, -1)) ++ __padata_start(pinst); ++ + mutex_unlock(&pinst->lock); + return ret; + } + +-static int padata_cpu_dead(unsigned int cpu, struct hlist_node *node) ++static int padata_cpu_offline(unsigned int cpu, struct hlist_node *node) + { + struct padata_instance *pinst; + int ret; + +- pinst = hlist_entry_safe(node, struct padata_instance, cpu_dead_node); ++ pinst = hlist_entry_safe(node, struct padata_instance, cpuhp_node); + if (!pinst_has_cpu(pinst, cpu)) + return 0; + + mutex_lock(&pinst->lock); +- ret = __padata_remove_cpu(pinst, cpu); ++ ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu, cpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu, cpu)) ++ __padata_stop(pinst); ++ ++ ret = padata_replace(pinst, cpu); ++ + mutex_unlock(&pinst->lock); + return ret; + } +@@ -792,15 +801,14 @@ static enum cpuhp_state hp_online; + static void __padata_free(struct padata_instance *pinst) + { + #ifdef CONFIG_HOTPLUG_CPU +- cpuhp_state_remove_instance_nocalls(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); +- cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpu_online_node); ++ cpuhp_state_remove_instance_nocalls(hp_online, &pinst->cpuhp_node); + #endif + + WARN_ON(!list_empty(&pinst->pslist)); + + free_cpumask_var(pinst->cpumask.pcpu); + free_cpumask_var(pinst->cpumask.cbcpu); ++ free_cpumask_var(pinst->validate_cpumask); + destroy_workqueue(pinst->serial_wq); + destroy_workqueue(pinst->parallel_wq); + kfree(pinst); +@@ -961,10 +969,10 @@ struct padata_instance *padata_alloc(const char *name) + + if (!alloc_cpumask_var(&pinst->cpumask.pcpu, GFP_KERNEL)) + goto err_free_serial_wq; +- if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) { +- free_cpumask_var(pinst->cpumask.pcpu); +- goto err_free_serial_wq; +- } ++ if (!alloc_cpumask_var(&pinst->cpumask.cbcpu, GFP_KERNEL)) ++ goto err_free_p_mask; ++ if (!alloc_cpumask_var(&pinst->validate_cpumask, GFP_KERNEL)) ++ goto err_free_cb_mask; + + INIT_LIST_HEAD(&pinst->pslist); + +@@ -972,7 +980,7 @@ struct padata_instance *padata_alloc(const char *name) + cpumask_copy(pinst->cpumask.cbcpu, cpu_possible_mask); + + if (padata_setup_cpumasks(pinst)) +- goto err_free_masks; ++ goto err_free_v_mask; + + __padata_start(pinst); + +@@ -981,18 +989,19 @@ struct padata_instance *padata_alloc(const char *name) + + #ifdef CONFIG_HOTPLUG_CPU + cpuhp_state_add_instance_nocalls_cpuslocked(hp_online, +- &pinst->cpu_online_node); +- cpuhp_state_add_instance_nocalls_cpuslocked(CPUHP_PADATA_DEAD, +- &pinst->cpu_dead_node); ++ &pinst->cpuhp_node); + #endif + + cpus_read_unlock(); + + return pinst; + +-err_free_masks: +- free_cpumask_var(pinst->cpumask.pcpu); ++err_free_v_mask: ++ free_cpumask_var(pinst->validate_cpumask); ++err_free_cb_mask: + free_cpumask_var(pinst->cpumask.cbcpu); ++err_free_p_mask: ++ free_cpumask_var(pinst->cpumask.pcpu); + err_free_serial_wq: + destroy_workqueue(pinst->serial_wq); + err_put_cpus: +@@ -1035,7 +1044,7 @@ struct padata_shell *padata_alloc_shell(struct padata_instance *pinst) + ps->pinst = pinst; + + cpus_read_lock(); +- pd = padata_alloc_pd(ps); ++ pd = padata_alloc_pd(ps, -1); + cpus_read_unlock(); + + if (!pd) +@@ -1084,31 +1093,24 @@ void __init padata_init(void) + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "padata:online", +- padata_cpu_online, NULL); ++ padata_cpu_online, padata_cpu_offline); + if (ret < 0) + goto err; + hp_online = ret; +- +- ret = cpuhp_setup_state_multi(CPUHP_PADATA_DEAD, "padata:dead", +- NULL, padata_cpu_dead); +- if (ret < 0) +- goto remove_online_state; + #endif + + possible_cpus = num_possible_cpus(); + padata_works = kmalloc_objs(struct padata_work, possible_cpus); + if (!padata_works) +- goto remove_dead_state; ++ goto remove_online_state; + + for (i = 0; i < possible_cpus; ++i) + list_add(&padata_works[i].pw_list, &padata_free_works); + + return; + +-remove_dead_state: +-#ifdef CONFIG_HOTPLUG_CPU +- cpuhp_remove_multi_state(CPUHP_PADATA_DEAD); + remove_online_state: ++#ifdef CONFIG_HOTPLUG_CPU + cpuhp_remove_multi_state(hp_online); + err: + #endif +-- +2.53.0 + diff --git a/queue-7.0/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch b/queue-7.0/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch new file mode 100644 index 0000000000..f4a5693484 --- /dev/null +++ b/queue-7.0/padata-remove-cpu-online-check-from-cpu-add-and-remo.patch @@ -0,0 +1,79 @@ +From c8cde11d8895924879158b9e25109640de3fb5b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 16:07:03 +0800 +Subject: padata: Remove cpu online check from cpu add and removal + +From: Chuyi Zhou + +[ Upstream commit 73117ea6470dca787f70f33c001f9faf437a1c0b ] + +During the CPU offline process, the dying CPU is cleared from the +cpu_online_mask in takedown_cpu(). After this step, various CPUHP_*_DEAD +callbacks are executed to perform cleanup jobs for the dead CPU, so this +cpu online check in padata_cpu_dead() is unnecessary. + +Similarly, when executing padata_cpu_online() during the +CPUHP_AP_ONLINE_DYN phase, the CPU has already been set in the +cpu_online_mask, the action even occurs earlier than the +CPUHP_AP_ONLINE_IDLE stage. + +Remove this unnecessary cpu online check in __padata_add_cpu() and +__padata_remove_cpu(). + +Signed-off-by: Chuyi Zhou +Acked-by: Daniel Jordan +Signed-off-by: Herbert Xu +Stable-dep-of: c8c4a2972f83 ("padata: Put CPU offline callback in ONLINE section to allow failure") +Signed-off-by: Sasha Levin +--- + kernel/padata.c | 26 ++++++++------------------ + 1 file changed, 8 insertions(+), 18 deletions(-) + +diff --git a/kernel/padata.c b/kernel/padata.c +index 8657e6e0c224a..9e7cfa5ed55bc 100644 +--- a/kernel/padata.c ++++ b/kernel/padata.c +@@ -732,32 +732,22 @@ EXPORT_SYMBOL(padata_set_cpumask); + + static int __padata_add_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (cpumask_test_cpu(cpu, cpu_online_mask)) { +- err = padata_replace(pinst); ++ int err = padata_replace(pinst); + +- if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && +- padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_start(pinst); +- } ++ if (padata_validate_cpumask(pinst, pinst->cpumask.pcpu) && ++ padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_start(pinst); + + return err; + } + + static int __padata_remove_cpu(struct padata_instance *pinst, int cpu) + { +- int err = 0; +- +- if (!cpumask_test_cpu(cpu, cpu_online_mask)) { +- if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || +- !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) +- __padata_stop(pinst); +- +- err = padata_replace(pinst); +- } ++ if (!padata_validate_cpumask(pinst, pinst->cpumask.pcpu) || ++ !padata_validate_cpumask(pinst, pinst->cpumask.cbcpu)) ++ __padata_stop(pinst); + +- return err; ++ return padata_replace(pinst); + } + + static inline int pinst_has_cpu(struct padata_instance *pinst, int cpu) +-- +2.53.0 + diff --git a/queue-7.0/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch b/queue-7.0/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch new file mode 100644 index 0000000000..c0191ec3b8 --- /dev/null +++ b/queue-7.0/page_pool-fix-memory-provider-leak-in-page_pool_crea.patch @@ -0,0 +1,109 @@ +From 238013d6fadeeb4292dc5fde8184ffa0e43e6aa0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 19:07:39 +0200 +Subject: page_pool: fix memory-provider leak in page_pool_create_percpu() + error path + +From: Hasan Basbunar + +[ Upstream commit 5ef343614db766acdc01c56d66e780a1b43c6ac6 ] + +When page_pool_create_percpu() fails on page_pool_list(), it falls +through to its err_uninit: label, which calls page_pool_uninit(). +At that point page_pool_init() has already taken two references +when the user requested PP_FLAG_ALLOW_UNREADABLE_NETMEM: + + pool->mp_ops->init(pool) + static_branch_inc(&page_pool_mem_providers); + +Neither is undone by page_pool_uninit(); both are only undone by +__page_pool_destroy() (success-side teardown). The error path +therefore leaks the per-provider reference taken by mp_ops->init +(io_zcrx_ifq->refs in the io_uring zcrx provider, the dmabuf +binding refcount in the devmem provider) plus one increment of +the page_pool_mem_providers static branch on every failure of +xa_alloc_cyclic() inside page_pool_list(). + +The leaked io_zcrx_ifq->refs in turn pins everything +io_zcrx_ifq_free() would release on cleanup: ifq->user (uid), +ifq->mm_account (mmdrop), ifq->dev (device refcount), +ifq->netdev_tracker (netdev refcount), and the rbuf region. +The leaked static branch increment forces all subsequent +page_pool_alloc_netmems() and page_pool_return_page() callers to +take the slow mp_ops branch for the lifetime of the kernel. + +Reachable via the io_uring zcrx path: + + io_uring_register(IORING_REGISTER_ZCRX_IFQ) /* CAP_NET_ADMIN */ + -> __io_uring_register + -> io_register_zcrx + -> zcrx_register_netdev + -> netif_mp_open_rxq + -> driver ndo_queue_mem_alloc + -> page_pool_create_percpu + -> page_pool_init succeeds (mp_ops->init runs, branch++) + -> page_pool_list fails (xa_alloc_cyclic -ENOMEM) + -> goto err_uninit <-- leak + +The same shape applies to the devmem dmabuf provider via +mp_dmabuf_devmem_init()/mp_dmabuf_devmem_destroy(). + +Restore the cleanup symmetry by moving the mp_ops->destroy() and +static_branch_dec() calls out of __page_pool_destroy() and into +page_pool_uninit(), so page_pool_uninit() is again the strict +inverse of page_pool_init(). page_pool_uninit() has only two +callers (the err_uninit: path and __page_pool_destroy()), so this +preserves the single-call invariant on the success path while +fixing the err path. The error path of page_pool_init() itself +still skips the mp_ops cleanup correctly: mp_ops->init is the +last action that takes a reference before page_pool_init() returns +0, so when it returns an error neither the refcount nor the static +branch has been touched. + +Triggering the bug requires xa_alloc_cyclic() to fail with -ENOMEM, +which under normal GFP_KERNEL retry behaviour is rare. It is +deterministic under CONFIG_FAULT_INJECTION with fail_page_alloc / +xa fault injection, or under sustained memory pressure. The leak +is silent: there is no warning, and the released kernel build +continues running with a permanently-incremented static branch. + +Fixes: 0f9214046893 ("memory-provider: dmabuf devmem memory provider") +Signed-off-by: Hasan Basbunar +Link: https://patch.msgid.link/20260428170739.34881-1-basbunarhasan@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/page_pool.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/net/core/page_pool.c b/net/core/page_pool.c +index 265a729431bb7..8171d1173221b 100644 +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -327,6 +327,11 @@ static void page_pool_uninit(struct page_pool *pool) + if (!pool->system) + free_percpu(pool->recycle_stats); + #endif ++ ++ if (pool->mp_ops) { ++ pool->mp_ops->destroy(pool); ++ static_branch_dec(&page_pool_mem_providers); ++ } + } + + /** +@@ -1126,11 +1131,6 @@ static void __page_pool_destroy(struct page_pool *pool) + page_pool_unlist(pool); + page_pool_uninit(pool); + +- if (pool->mp_ops) { +- pool->mp_ops->destroy(pool); +- static_branch_dec(&page_pool_mem_providers); +- } +- + kfree(pool); + } + +-- +2.53.0 + diff --git a/queue-7.0/pci-aspeed-fix-irq-domain-leak-on-platform_get_irq-f.patch b/queue-7.0/pci-aspeed-fix-irq-domain-leak-on-platform_get_irq-f.patch new file mode 100644 index 0000000000..21ecf8f037 --- /dev/null +++ b/queue-7.0/pci-aspeed-fix-irq-domain-leak-on-platform_get_irq-f.patch @@ -0,0 +1,56 @@ +From a6feefbe6791143f0f42cd0aafa061631def9d5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:57:59 +0800 +Subject: PCI: aspeed: Fix IRQ domain leak on platform_get_irq() failure + +From: Felix Gu + +[ Upstream commit c54d5f5b33990f2649c20f35407f340bcadb8a53 ] + +The aspeed_pcie_probe() function calls aspeed_pcie_init_irq_domain() +which allocates pcie->intx_domain and initializes MSI. However, if +platform_get_irq() fails afterwards, the cleanup action was not yet +registered via devm_add_action_or_reset(), causing the IRQ domain +resources to leak. + +Fix this by registering the devm cleanup action immediately after +aspeed_pcie_init_irq_domain() succeeds, before calling +platform_get_irq(). This ensures proper cleanup on any subsequent +failure. + +Fixes: 9aa0cb68fcc1 ("PCI: aspeed: Add ASPEED PCIe RC driver") +Signed-off-by: Felix Gu +Signed-off-by: Manivannan Sadhasivam +Tested-by: Jacky Chou +Link: https://patch.msgid.link/20260324-aspeed-v1-1-354181624c00@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-aspeed.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/pcie-aspeed.c b/drivers/pci/controller/pcie-aspeed.c +index 3e1a39d1e6484..6acfae7d026e4 100644 +--- a/drivers/pci/controller/pcie-aspeed.c ++++ b/drivers/pci/controller/pcie-aspeed.c +@@ -1052,14 +1052,14 @@ static int aspeed_pcie_probe(struct platform_device *pdev) + if (ret) + return ret; + +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) +- return irq; +- + ret = devm_add_action_or_reset(dev, aspeed_pcie_irq_domain_free, pcie); + if (ret) + return ret; + ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ + ret = devm_request_irq(dev, irq, aspeed_pcie_intr_handler, IRQF_SHARED, + dev_name(dev), pcie); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/pci-cadence-add-flags-for-disabling-aspm-capability-.patch b/queue-7.0/pci-cadence-add-flags-for-disabling-aspm-capability-.patch new file mode 100644 index 0000000000..f166918fb0 --- /dev/null +++ b/queue-7.0/pci-cadence-add-flags-for-disabling-aspm-capability-.patch @@ -0,0 +1,94 @@ +From acca4384755c90c1215f5e73f808dbaa77d8ead3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 15:41:53 +0000 +Subject: PCI: cadence: Add flags for disabling ASPM capability for broken Root + Ports + +From: Yao Zi + +[ Upstream commit 5ccc76a87f1ec2422811e61be44165bfc9e7cf54 ] + +Add flags for disabling the ASPM L0s/L1 capability for broken Root Ports +by clearing the corresponding bits in Link Capabilities Register through +the local management bus. This allows ASPM to be disabled on platforms +which don't support it. + +Signed-off-by: Yao Zi +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Han Gao +Tested-by: Chen Wang # Pioneerbox +Reviewed-by: Chen Wang +Link: https://patch.msgid.link/20260405154154.46829-2-me@ziyao.cc +Stable-dep-of: 988ef706cdd8 ("PCI: sg2042: Avoid L0s and L1 on Sophgo 2042 PCIe Root Ports") +Signed-off-by: Sasha Levin +--- + .../controller/cadence/pcie-cadence-host.c | 7 +++++++ + drivers/pci/controller/cadence/pcie-cadence.h | 19 +++++++++++++++++++ + 2 files changed, 26 insertions(+) + +diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c +index db3154c1eccbf..0bc9e6e90e0e0 100644 +--- a/drivers/pci/controller/cadence/pcie-cadence-host.c ++++ b/drivers/pci/controller/cadence/pcie-cadence-host.c +@@ -147,6 +147,13 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc) + cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0); + cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); + ++ value = cdns_pcie_rp_readl(pcie, CDNS_PCIE_RP_CAP_OFFSET + PCI_EXP_LNKCAP); ++ if (rc->quirk_broken_aspm_l0s) ++ value &= ~PCI_EXP_LNKCAP_ASPM_L0S; ++ if (rc->quirk_broken_aspm_l1) ++ value &= ~PCI_EXP_LNKCAP_ASPM_L1; ++ cdns_pcie_rp_writel(pcie, CDNS_PCIE_RP_CAP_OFFSET + PCI_EXP_LNKCAP, value); ++ + return 0; + } + +diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h +index 277f3706a4f47..574e9cf4d003f 100644 +--- a/drivers/pci/controller/cadence/pcie-cadence.h ++++ b/drivers/pci/controller/cadence/pcie-cadence.h +@@ -115,6 +115,8 @@ struct cdns_pcie { + * @quirk_detect_quiet_flag: LTSSM Detect Quiet min delay set as quirk + * @ecam_supported: Whether the ECAM is supported + * @no_inbound_map: Whether inbound mapping is supported ++ * @quirk_broken_aspm_l0s: Disable ASPM L0s support as quirk ++ * @quirk_broken_aspm_l1: Disable ASPM L1 support as quirk + */ + struct cdns_pcie_rc { + struct cdns_pcie pcie; +@@ -127,6 +129,8 @@ struct cdns_pcie_rc { + unsigned int quirk_detect_quiet_flag:1; + unsigned int ecam_supported:1; + unsigned int no_inbound_map:1; ++ unsigned int quirk_broken_aspm_l0s:1; ++ unsigned int quirk_broken_aspm_l1:1; + }; + + /** +@@ -338,6 +342,21 @@ static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg) + return cdns_pcie_read_sz(addr, 0x2); + } + ++static inline void cdns_pcie_rp_writel(struct cdns_pcie *pcie, ++ u32 reg, u32 value) ++{ ++ void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg; ++ ++ cdns_pcie_write_sz(addr, 0x4, value); ++} ++ ++static inline u32 cdns_pcie_rp_readl(struct cdns_pcie *pcie, u32 reg) ++{ ++ void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg; ++ ++ return cdns_pcie_read_sz(addr, 0x4); ++} ++ + static inline void cdns_pcie_hpa_rp_writeb(struct cdns_pcie *pcie, + u32 reg, u8 value) + { +-- +2.53.0 + diff --git a/queue-7.0/pci-dpc-log-aer-error-info-for-dpc-edr-uncorrectable.patch b/queue-7.0/pci-dpc-log-aer-error-info-for-dpc-edr-uncorrectable.patch new file mode 100644 index 0000000000..22104c25f7 --- /dev/null +++ b/queue-7.0/pci-dpc-log-aer-error-info-for-dpc-edr-uncorrectable.patch @@ -0,0 +1,51 @@ +From 4e3483e63b4140afbeb96399951acb64d76cbb7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:04:49 -0700 +Subject: PCI/DPC: Log AER error info for DPC/EDR uncorrectable errors + +From: Kuppuswamy Sathyanarayanan + +[ Upstream commit 97970e7c694356e3386a10e3b936d61eafd06bce ] + +aer_print_error() skips printing if ratelimit_print[i] is not set. In the +native AER path, ratelimit_print is initialized by add_error_device() +during source device discovery, and is set to 1 for fatal errors to bypass +rate limiting since fatal errors should always be logged. + +The DPC/EDR path uses the DPC-capable port as the error source and reads +its AER uncorrectable error status registers directly in +dpc_get_aer_uncorrect_severity(). Since it does not go through +add_error_device(), ratelimit_print[0] is left uninitialized and zero. As +a result, aer_print_error() silently drops all AER error messages for +DPC/EDR triggered events. + +Set ratelimit_print[0] to 1 to bypass rate limiting and always print AER +logs for uncorrectable errors detected by the DPC port. + +Fixes: a57f2bfb4a58 ("PCI/AER: Ratelimit correctable and non-fatal error logging") +Co-developed-by: Goudar Manjunath Ramanagouda +Signed-off-by: Goudar Manjunath Ramanagouda +Signed-off-by: Kuppuswamy Sathyanarayanan +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260318170449.2733581-1-sathyanarayanan.kuppuswamy@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/dpc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c +index fc18349614d7c..7605ddd9f0ba8 100644 +--- a/drivers/pci/pcie/dpc.c ++++ b/drivers/pci/pcie/dpc.c +@@ -256,6 +256,7 @@ static int dpc_get_aer_uncorrect_severity(struct pci_dev *dev, + + info->dev[0] = dev; + info->error_dev_num = 1; ++ info->ratelimit_print[0] = 1; + + return 1; + } +-- +2.53.0 + diff --git a/queue-7.0/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch b/queue-7.0/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch new file mode 100644 index 0000000000..e36000eca8 --- /dev/null +++ b/queue-7.0/pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch @@ -0,0 +1,63 @@ +From b626649b07618dd27be72b32b32f9325e1a63656 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:53 +0530 +Subject: PCI: dwc: Apply ECRC workaround to DesignWare 5.00a as well + +From: Manikanta Maddireddy + +[ Upstream commit 40805f32dceadebb7381d911003100bec7b8cd51 ] + +The ECRC (TLP digest) workaround was originally added for DesignWare +version 4.90a. Tegra234 SoC has 5.00a DWC HW version, which has the same +ATU TD override behaviour, so apply the workaround for 5.00a too. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-13-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c +index 5741c09dde7f4..bb4e82fbfd5c8 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.c ++++ b/drivers/pci/controller/dwc/pcie-designware.c +@@ -487,13 +487,13 @@ static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 index, u32 reg + static inline u32 dw_pcie_enable_ecrc(u32 val) + { + /* +- * DesignWare core version 4.90A has a design issue where the 'TD' +- * bit in the Control register-1 of the ATU outbound region acts +- * like an override for the ECRC setting, i.e., the presence of TLP +- * Digest (ECRC) in the outgoing TLPs is solely determined by this +- * bit. This is contrary to the PCIe spec which says that the +- * enablement of the ECRC is solely determined by the AER +- * registers. ++ * DWC versions 0x3530302a and 0x3536322a have a design issue where ++ * the 'TD' bit in the Control register-1 of the ATU outbound ++ * region acts like an override for the ECRC setting, i.e., the ++ * presence of TLP Digest (ECRC) in the outgoing TLPs is solely ++ * determined by this bit. This is contrary to the PCIe spec which ++ * says that the enablement of the ECRC is solely determined by the ++ * AER registers. + * + * Because of this, even when the ECRC is enabled through AER + * registers, the transactions going through ATU won't have TLP +@@ -563,7 +563,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, + if (upper_32_bits(limit_addr) > upper_32_bits(parent_bus_addr) && + dw_pcie_ver_is_ge(pci, 460A)) + val |= PCIE_ATU_INCREASE_REGION_SIZE; +- if (dw_pcie_ver_is(pci, 490A)) ++ if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A)) + val = dw_pcie_enable_ecrc(val); + dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val); + +-- +2.53.0 + diff --git a/queue-7.0/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch b/queue-7.0/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch new file mode 100644 index 0000000000..d90a35f8a2 --- /dev/null +++ b/queue-7.0/pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch @@ -0,0 +1,47 @@ +From f2e0ddf8ac28f684fa3139e21d5143003a01ad9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 14:08:16 +0530 +Subject: PCI: dwc: ep: Fix MSI-X Table Size configuration in + dw_pcie_ep_set_msix() + +From: Aksh Garg + +[ Upstream commit 271d0b1f058ae9815e75233d04b23e3558c3e4f4 ] + +In dw_pcie_ep_set_msix(), while updating the MSI-X Table Size value for +individual functions, Message Control register is read from the passed +function number register space using dw_pcie_ep_readw_dbi(), but always +written back to the Function 0's register space using dw_pcie_writew_dbi(). +This causes incorrect MSI-X configuration for the rest of the functions, +other than Function 0. + +Fix this by using dw_pcie_ep_writew_dbi() to write to the correct +function's register space, matching the read operation. + +Fixes: 70fa02ca1446 ("PCI: dwc: Add dw_pcie_ep_{read,write}_dbi[2] helpers") +Signed-off-by: Aksh Garg +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260224083817.916782-2-a-garg7@ti.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index c57ae4d6c5c0e..10d6f53cf7bad 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -754,7 +754,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + val = dw_pcie_ep_readw_dbi(ep, func_no, reg); + val &= ~PCI_MSIX_FLAGS_QSIZE; + val |= nr_irqs - 1; /* encoded as N-1 */ +- dw_pcie_writew_dbi(pci, reg, val); ++ dw_pcie_ep_writew_dbi(ep, func_no, reg, val); + + reg = ep_func->msix_cap + PCI_MSIX_TABLE; + val = offset | bir; +-- +2.53.0 + diff --git a/queue-7.0/pci-dwc-ep-mirror-the-max-link-width-and-speed-field.patch b/queue-7.0/pci-dwc-ep-mirror-the-max-link-width-and-speed-field.patch new file mode 100644 index 0000000000..3131550e62 --- /dev/null +++ b/queue-7.0/pci-dwc-ep-mirror-the-max-link-width-and-speed-field.patch @@ -0,0 +1,84 @@ +From 9b68e619a752abcf79d7c10f0186c35853cad054 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Feb 2026 14:08:17 +0530 +Subject: PCI: dwc: ep: Mirror the max link width and speed fields to all + functions + +From: Aksh Garg + +[ Upstream commit 94cbea0f636b55602a9a10583670976680ecea67 ] + +PCIe r7.0, section 7.5.3.6 states that for multi-function devices, the +Max Link Width and Max Link Speed fields in the Link Capabilities +Register must report the same values for all functions. + +Currently, dw_pcie_setup() programs these fields only for Function 0 +via dw_pcie_link_set_max_speed() and dw_pcie_link_set_max_link_width(). +For multi-function endpoint configurations, Function 1 and beyond retain +their default values, violating the PCIe specification. + +Fix this by reading the Max Link Width and Max Link Speed fields from +Link Capabilities Register of Function 0 after dw_pcie_setup() completes, +then mirroring these values to all other functions. + +Fixes: 24ede430fa49 ("PCI: designware-ep: Add multiple PFs support for DWC") +Fixes: 89db0793c9f2 ("PCI: dwc: Add missing PCI_EXP_LNKCAP_MLW handling") +Signed-off-by: Aksh Garg +[mani: renamed ref_lnkcap to func0_lnkcap] +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260224083817.916782-3-a-garg7@ti.com +Signed-off-by: Sasha Levin +--- + .../pci/controller/dwc/pcie-designware-ep.c | 29 ++++++++++++++++++- + 1 file changed, 28 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c +index 10d6f53cf7bad..ab2e7de5c55eb 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-ep.c ++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c +@@ -1110,7 +1110,8 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) + { + struct dw_pcie_ep *ep = &pci->ep; + u8 funcs = ep->epc->max_functions; +- u8 func_no; ++ u32 func0_lnkcap, lnkcap; ++ u8 func_no, offset; + + dw_pcie_dbi_ro_wr_en(pci); + +@@ -1118,6 +1119,32 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) + dw_pcie_ep_init_rebar_registers(ep, func_no); + + dw_pcie_setup(pci); ++ ++ /* ++ * PCIe r7.0, section 7.5.3.6 states that for multi-function ++ * endpoints, max link width and speed fields must report same ++ * values for all functions. However, dw_pcie_setup() programs ++ * these fields only for function 0. Hence, mirror these fields ++ * to all other functions as well. ++ */ ++ if (funcs > 1) { ++ offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); ++ func0_lnkcap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); ++ func0_lnkcap = FIELD_GET(PCI_EXP_LNKCAP_MLW | ++ PCI_EXP_LNKCAP_SLS, func0_lnkcap); ++ ++ for (func_no = 1; func_no < funcs; func_no++) { ++ offset = dw_pcie_ep_find_capability(ep, func_no, ++ PCI_CAP_ID_EXP); ++ lnkcap = dw_pcie_ep_readl_dbi(ep, func_no, ++ offset + PCI_EXP_LNKCAP); ++ FIELD_MODIFY(PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS, ++ &lnkcap, func0_lnkcap); ++ dw_pcie_ep_writel_dbi(ep, func_no, ++ offset + PCI_EXP_LNKCAP, lnkcap); ++ } ++ } ++ + dw_pcie_dbi_ro_wr_dis(pci); + } + +-- +2.53.0 + diff --git a/queue-7.0/pci-dwc-fix-type-mismatch-for-kstrtou32_from_user-re.patch b/queue-7.0/pci-dwc-fix-type-mismatch-for-kstrtou32_from_user-re.patch new file mode 100644 index 0000000000..cbb74e6311 --- /dev/null +++ b/queue-7.0/pci-dwc-fix-type-mismatch-for-kstrtou32_from_user-re.patch @@ -0,0 +1,74 @@ +From 2ca76e9b6010ca614a2997fe2d032f5e8dd083f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 10:30:48 +0800 +Subject: PCI: dwc: Fix type mismatch for kstrtou32_from_user() return value + +From: Hans Zhang <18255117159@163.com> + +[ Upstream commit 445588a3b18bb0702d746cb61f7a443639027651 ] + +kstrtou32_from_user() returns int, but the return value was stored in +a u32 variable 'val', risking sign loss. Use a dedicated int variable +to correctly handle the return code. + +Fixes: 4fbfa17f9a07 ("PCI: dwc: Add debugfs based Silicon Debug support for DWC") +Signed-off-by: Hans Zhang <18255117159@163.com> +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260401023048.4182452-1-18255117159@163.com +Signed-off-by: Sasha Levin +--- + .../controller/dwc/pcie-designware-debugfs.c | 21 +++++++++++-------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c +index 0d1340c9b3642..9461be0744907 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c ++++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c +@@ -208,10 +208,11 @@ static ssize_t lane_detect_write(struct file *file, const char __user *buf, + struct dw_pcie *pci = file->private_data; + struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info; + u32 lane, val; ++ int ret; + +- val = kstrtou32_from_user(buf, count, 0, &lane); +- if (val) +- return val; ++ ret = kstrtou32_from_user(buf, count, 0, &lane); ++ if (ret) ++ return ret; + + val = dw_pcie_readl_dbi(pci, rinfo->ras_cap_offset + SD_STATUS_L1LANE_REG); + val &= ~(LANE_SELECT); +@@ -347,10 +348,11 @@ static ssize_t counter_enable_write(struct file *file, const char __user *buf, + struct dw_pcie *pci = pdata->pci; + struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info; + u32 val, enable; ++ int ret; + +- val = kstrtou32_from_user(buf, count, 0, &enable); +- if (val) +- return val; ++ ret = kstrtou32_from_user(buf, count, 0, &enable); ++ if (ret) ++ return ret; + + mutex_lock(&rinfo->reg_event_lock); + set_event_number(pdata, pci, rinfo); +@@ -408,10 +410,11 @@ static ssize_t counter_lane_write(struct file *file, const char __user *buf, + struct dw_pcie *pci = pdata->pci; + struct dwc_pcie_rasdes_info *rinfo = pci->debugfs->rasdes_info; + u32 val, lane; ++ int ret; + +- val = kstrtou32_from_user(buf, count, 0, &lane); +- if (val) +- return val; ++ ret = kstrtou32_from_user(buf, count, 0, &lane); ++ if (ret) ++ return ret; + + mutex_lock(&rinfo->reg_event_lock); + set_event_number(pdata, pci, rinfo); +-- +2.53.0 + diff --git a/queue-7.0/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch b/queue-7.0/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch new file mode 100644 index 0000000000..7868ed6ab0 --- /dev/null +++ b/queue-7.0/pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch @@ -0,0 +1,60 @@ +From f72e4ccada6e89c1c3960389d797aab369ee3ba0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 19:09:51 +0530 +Subject: PCI: dwc: Perform cleanup in the error path of dw_pcie_resume_noirq() + +From: Manivannan Sadhasivam + +[ Upstream commit edb5ca3262e2255cf938a5948709d3472d4871ad ] + +If the dw_pcie_resume_noirq() API fails, it just returns the errno without +doing cleanup in the error path, leading to resource leak. + +So perform cleanup in the error path. + +Fixes: 4774faf854f5 ("PCI: dwc: Implement generic suspend/resume functionality") +Reported-by: Senchuan Zhang +Closes: https://lore.kernel.org/linux-pci/78296255.3869.19c8eb694d6.Coremail.zhangsenchuan@eswincomputing.com +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Manivannan Sadhasivam +Link: https://patch.msgid.link/20260226133951.296743-1-mani@kernel.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware-host.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c +index 6ae6189e9b8a9..c3c2dec728eea 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -1300,15 +1300,24 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci) + + ret = dw_pcie_start_link(pci); + if (ret) +- return ret; ++ goto err_deinit; + + ret = dw_pcie_wait_for_link(pci); +- if (ret) +- return ret; ++ if (ret == -ETIMEDOUT) ++ goto err_stop_link; + + if (pci->pp.ops->post_init) + pci->pp.ops->post_init(&pci->pp); + ++ return 0; ++ ++err_stop_link: ++ dw_pcie_stop_link(pci); ++ ++err_deinit: ++ if (pci->pp.ops->deinit) ++ pci->pp.ops->deinit(&pci->pp); ++ + return ret; + } + EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq); +-- +2.53.0 + diff --git a/queue-7.0/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch b/queue-7.0/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch new file mode 100644 index 0000000000..ae4baeb097 --- /dev/null +++ b/queue-7.0/pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch @@ -0,0 +1,48 @@ +From f68b549853962f10d8e7f7b46cd532e3fd9ff891 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 00:10:50 +0900 +Subject: PCI: dwc: rcar-gen4: Change EPC BAR alignment to 4K as per the + documentation + +From: Koichiro Den + +[ Upstream commit 13f55a7ca773c731a1e645934c1ae48577f48785 ] + +R-Car S4 Series (R8A779F[4-7]*) EP controller uses a 4K minimum iATU region +size (CX_ATU_MIN_REGION_SIZE = 4K) as per R19UH0161EJ0130 Rev.1.30. Also, +the controller itself can only be configured in the range 4 KB to 64 KB, so +the current 1 MB alignment requirement is incorrect. + +Hence, change the alignment to the min size 4K as per the documentation. + +This also fixes needless unusability of BAR4 on this platform when the +target address is fixed, such as for doorbell targets. + +Fixes: e311b3834dfa ("PCI: rcar-gen4: Add endpoint mode support") +Signed-off-by: Koichiro Den +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260305151050.1834007-1-den@valinux.co.jp +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c +index a6912e85e4ddc..8c7bc0691e52c 100644 +--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c ++++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c +@@ -426,7 +426,7 @@ static const struct pci_epc_features rcar_gen4_pcie_epc_features = { + .bar[BAR_3] = { .type = BAR_RESERVED, }, + .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256 }, + .bar[BAR_5] = { .type = BAR_RESERVED, }, +- .align = SZ_1M, ++ .align = SZ_4K, + }; + + static const struct pci_epc_features* +-- +2.53.0 + diff --git a/queue-7.0/pci-enable-atomicops-only-if-root-port-supports-them.patch b/queue-7.0/pci-enable-atomicops-only-if-root-port-supports-them.patch new file mode 100644 index 0000000000..b7f9065ae2 --- /dev/null +++ b/queue-7.0/pci-enable-atomicops-only-if-root-port-supports-them.patch @@ -0,0 +1,110 @@ +From 54e405e4ceed08c58fdae51ae7bf47a05302be93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 15:09:45 +0200 +Subject: PCI: Enable AtomicOps only if Root Port supports them + +From: Gerd Bayer + +[ Upstream commit 1ae8c4ce157037e266184064a182af9ef9af278b ] + +When inspecting the config space of a Connect-X physical function in an +s390 system after it was initialized by the mlx5_core device driver, we +found the function to be enabled to request AtomicOps despite the Root Port +lacking support for completing them: + + 00:00.1 Ethernet controller: Mellanox Technologies MT2894 Family [ConnectX-6 Lx] + Subsystem: Mellanox Technologies Device 0002 + DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis- + AtomicOpsCtl: ReqEn+ + +On s390 and many virtualized guests, the Endpoint is visible but the Root +Port is not. In this case, pci_enable_atomic_ops_to_root() previously +enabled AtomicOps in the Endpoint even though it can't tell whether the +Root Port supports them as a completer. + +Change pci_enable_atomic_ops_to_root() to fail if there's no Root Port or +the Root Port doesn't support AtomicOps. + +Fixes: 430a23689dea ("PCI: Add pci_enable_atomic_ops_to_root()") +Reported-by: Alexander Schmidt +Signed-off-by: Gerd Bayer +[bhelgaas: commit log, check RP first to simplify flow] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260330-fix_pciatops-v7-2-f601818417e8@linux.ibm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/pci.c | 41 ++++++++++++++++++++--------------------- + 1 file changed, 20 insertions(+), 21 deletions(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 8e3e4e24c9096..9298a461bd302 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -3674,8 +3674,7 @@ void pci_acs_init(struct pci_dev *dev) + */ + int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + { +- struct pci_bus *bus = dev->bus; +- struct pci_dev *bridge; ++ struct pci_dev *root, *bridge; + u32 cap, ctl2; + + /* +@@ -3705,35 +3704,35 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) + return -EINVAL; + } + +- while (bus->parent) { +- bridge = bus->self; ++ root = pcie_find_root_port(dev); ++ if (!root) ++ return -EINVAL; + +- pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap); ++ pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); ++ if ((cap & cap_mask) != cap_mask) ++ return -EINVAL; + ++ bridge = pci_upstream_bridge(dev); ++ while (bridge != root) { + switch (pci_pcie_type(bridge)) { +- /* Ensure switch ports support AtomicOp routing */ + case PCI_EXP_TYPE_UPSTREAM: +- case PCI_EXP_TYPE_DOWNSTREAM: +- if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) +- return -EINVAL; +- break; +- +- /* Ensure root port supports all the sizes we care about */ +- case PCI_EXP_TYPE_ROOT_PORT: +- if ((cap & cap_mask) != cap_mask) +- return -EINVAL; +- break; +- } +- +- /* Ensure upstream ports don't block AtomicOps on egress */ +- if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) { ++ /* Upstream ports must not block AtomicOps on egress */ + pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, + &ctl2); + if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK) + return -EINVAL; ++ fallthrough; ++ ++ /* All switch ports need to route AtomicOps */ ++ case PCI_EXP_TYPE_DOWNSTREAM: ++ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, ++ &cap); ++ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) ++ return -EINVAL; ++ break; + } + +- bus = bus->parent; ++ bridge = pci_upstream_bridge(bridge); + } + + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, +-- +2.53.0 + diff --git a/queue-7.0/pci-endpoint-pci-ep-msi-fix-error-unwind-and-prevent.patch b/queue-7.0/pci-endpoint-pci-ep-msi-fix-error-unwind-and-prevent.patch new file mode 100644 index 0000000000..ae08242513 --- /dev/null +++ b/queue-7.0/pci-endpoint-pci-ep-msi-fix-error-unwind-and-prevent.patch @@ -0,0 +1,58 @@ +From ea4cd848c7b6e2a771262a5490cba59e20c3e962 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 15:38:56 +0900 +Subject: PCI: endpoint: pci-ep-msi: Fix error unwind and prevent double alloc + +From: Koichiro Den + +[ Upstream commit 1cba96c0a795124c3229293ed7b5b5765e66f259 ] + +pci_epf_alloc_doorbell() stores the allocated doorbell message array in +epf->db_msg/epf->num_db before requesting MSI vectors. If MSI allocation +fails, the array is freed but the EPF state may still point to freed +memory. + +Clear epf->db_msg and epf->num_db on the MSI allocation failure path so +that later cleanup cannot double-free the array and callers can retry +allocation. + +Also return -EBUSY when doorbells have already been allocated to prevent +leaking or overwriting an existing allocation. + +Fixes: 1c3b002c6bf6 ("PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller") +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260217063856.3759713-4-den@valinux.co.jp +Signed-off-by: Sasha Levin +--- + drivers/pci/endpoint/pci-ep-msi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/pci/endpoint/pci-ep-msi.c b/drivers/pci/endpoint/pci-ep-msi.c +index 51c19942a81ef..1395919571f83 100644 +--- a/drivers/pci/endpoint/pci-ep-msi.c ++++ b/drivers/pci/endpoint/pci-ep-msi.c +@@ -50,6 +50,9 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db) + return -EINVAL; + } + ++ if (epf->db_msg) ++ return -EBUSY; ++ + domain = of_msi_map_get_device_domain(epc->dev.parent, 0, + DOMAIN_BUS_PLATFORM_MSI); + if (!domain) { +@@ -79,6 +82,8 @@ int pci_epf_alloc_doorbell(struct pci_epf *epf, u16 num_db) + if (ret) { + dev_err(dev, "Failed to allocate MSI\n"); + kfree(msg); ++ epf->db_msg = NULL; ++ epf->num_db = 0; + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/pci-endpoint-pci-epf-test-don-t-free-doorbell-irq-un.patch b/queue-7.0/pci-endpoint-pci-epf-test-don-t-free-doorbell-irq-un.patch new file mode 100644 index 0000000000..0785300a71 --- /dev/null +++ b/queue-7.0/pci-endpoint-pci-epf-test-don-t-free-doorbell-irq-un.patch @@ -0,0 +1,77 @@ +From a1b8c31b3aefc5e53e63fb9a478ca844850dadbe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 15:38:55 +0900 +Subject: PCI: endpoint: pci-epf-test: Don't free doorbell IRQ unless requested + +From: Koichiro Den + +[ Upstream commit e81fa70179aac6ac3a6636565d5d35968dca3900 ] + +pci_epf_test_doorbell_cleanup() unconditionally calls free_irq() for the +doorbell virq, which can trigger "Trying to free already-free IRQ" +warnings when the IRQ was never requested or when request_threaded_irq() +failed. + +Move free_irq() out of pci_epf_test_doorbell_cleanup() and invoke it +only after a successful request, so that free_irq() is not called for +an unrequested IRQ. + +Fixes: eff0c286aa91 ("PCI: endpoint: pci-epf-test: Add doorbell test support") +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260217063856.3759713-3-den@valinux.co.jp +Signed-off-by: Sasha Levin +--- + drivers/pci/endpoint/functions/pci-epf-test.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c +index 33548935765e3..0e7cbcbebf0b4 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-test.c ++++ b/drivers/pci/endpoint/functions/pci-epf-test.c +@@ -715,7 +715,6 @@ static void pci_epf_test_doorbell_cleanup(struct pci_epf_test *epf_test) + struct pci_epf_test_reg *reg = epf_test->reg[epf_test->test_reg_bar]; + struct pci_epf *epf = epf_test->epf; + +- free_irq(epf->db_msg[0].virq, epf_test); + reg->doorbell_bar = cpu_to_le32(NO_BAR); + + pci_epf_free_doorbell(epf); +@@ -759,7 +758,7 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test, + &epf_test->db_bar.phys_addr, &offset); + + if (ret) +- goto err_doorbell_cleanup; ++ goto err_free_irq; + + reg->doorbell_offset = cpu_to_le32(offset); + +@@ -769,12 +768,14 @@ static void pci_epf_test_enable_doorbell(struct pci_epf_test *epf_test, + + ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, &epf_test->db_bar); + if (ret) +- goto err_doorbell_cleanup; ++ goto err_free_irq; + + status |= STATUS_DOORBELL_ENABLE_SUCCESS; + reg->status = cpu_to_le32(status); + return; + ++err_free_irq: ++ free_irq(epf->db_msg[0].virq, epf_test); + err_doorbell_cleanup: + pci_epf_test_doorbell_cleanup(epf_test); + set_status_err: +@@ -794,6 +795,7 @@ static void pci_epf_test_disable_doorbell(struct pci_epf_test *epf_test, + if (bar < BAR_0) + goto set_status_err; + ++ free_irq(epf->db_msg[0].virq, epf_test); + pci_epf_test_doorbell_cleanup(epf_test); + + /* +-- +2.53.0 + diff --git a/queue-7.0/pci-endpoint-pci-epf-vntb-fix-msi-doorbell-irq-unwin.patch b/queue-7.0/pci-endpoint-pci-epf-vntb-fix-msi-doorbell-irq-unwin.patch new file mode 100644 index 0000000000..fb66464f3b --- /dev/null +++ b/queue-7.0/pci-endpoint-pci-epf-vntb-fix-msi-doorbell-irq-unwin.patch @@ -0,0 +1,74 @@ +From 4b44e85e19fc6662e37ac69ffec3e5f8e2937265 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 15:38:54 +0900 +Subject: PCI: endpoint: pci-epf-vntb: Fix MSI doorbell IRQ unwind + +From: Koichiro Den + +[ Upstream commit cc04f2bfb9dae60b6e34d6bff75c26d4ec3237ce ] + +epf_ntb_db_bar_init_msi_doorbell() requests ntb->db_count doorbell IRQs +and then performs additional MSI doorbell setup that may still fail. +The error path unwinds the requested IRQs, but it uses a loop variable +that is reused later in the function. When a later step fails, the +unwind can run with an unexpected index value and leave some IRQs +requested. + +Track the number of successfully requested IRQs separately and use that +counter for the unwind so all previously requested IRQs are freed on +failure. + +Fixes: dc693d606644 ("PCI: endpoint: pci-epf-vntb: Add MSI doorbell support") +Signed-off-by: Koichiro Den +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Reviewed-by: Niklas Cassel +Link: https://patch.msgid.link/20260217063856.3759713-2-den@valinux.co.jp +Signed-off-by: Sasha Levin +--- + drivers/pci/endpoint/functions/pci-epf-vntb.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c +index 65f5bbf28480d..c9c7b50587dd2 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c ++++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c +@@ -527,20 +527,20 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb, + struct msi_msg *msg; + size_t sz; + int ret; +- int i; ++ int i, req; + + ret = pci_epf_alloc_doorbell(epf, ntb->db_count); + if (ret) + return ret; + +- for (i = 0; i < ntb->db_count; i++) { +- ret = request_irq(epf->db_msg[i].virq, epf_ntb_doorbell_handler, ++ for (req = 0; req < ntb->db_count; req++) { ++ ret = request_irq(epf->db_msg[req].virq, epf_ntb_doorbell_handler, + 0, "pci_epf_vntb_db", ntb); + + if (ret) { + dev_err(&epf->dev, + "Failed to request doorbell IRQ: %d\n", +- epf->db_msg[i].virq); ++ epf->db_msg[req].virq); + goto err_free_irq; + } + } +@@ -598,8 +598,8 @@ static int epf_ntb_db_bar_init_msi_doorbell(struct epf_ntb *ntb, + return 0; + + err_free_irq: +- for (i--; i >= 0; i--) +- free_irq(epf->db_msg[i].virq, ntb); ++ for (req--; req >= 0; req--) ++ free_irq(epf->db_msg[req].virq, ntb); + + pci_epf_free_doorbell(ntb->epf); + return ret; +-- +2.53.0 + diff --git a/queue-7.0/pci-fix-alignment-calculation-for-resource-size-larg.patch b/queue-7.0/pci-fix-alignment-calculation-for-resource-size-larg.patch new file mode 100644 index 0000000000..f3b6e45d48 --- /dev/null +++ b/queue-7.0/pci-fix-alignment-calculation-for-resource-size-larg.patch @@ -0,0 +1,59 @@ +From 8284d2971842678495fb85be93261edd09ccc787 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 18:56:33 +0200 +Subject: PCI: Fix alignment calculation for resource size larger than align +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit 8cb081667377709f4924ab6b3a88a0d7a761fe91 ] + +The commit bc75c8e50711 ("PCI: Rewrite bridge window head alignment +function") did not use if (r_size <= align) check from pbus_size_mem() for +the new head alignment bookkeeping structure (aligns2[]). In some +configurations, this can result in producing a gap into the bridge window +which the resource larger than its alignment cannot fill. + +The old alignment calculation algorithm was removed by the subsequent +commit 3958bf16e2fe ("PCI: Stop over-estimating bridge window size") which +renamed the aligns2[] array leaving only aligns[] array. + +Add the if (r_size <= align) check back to avoid this problem. + +Fixes: bc75c8e50711 ("PCI: Rewrite bridge window head alignment function") +Reported-by: Guenter Roeck +Closes: https://lore.kernel.org/all/b05a6f14-979d-42c9-924c-d8408cb12ae7@roeck-us.net/ +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Tested-by: Xifer +Link: https://patch.msgid.link/20260324165633.4583-11-ilpo.jarvinen@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 9506845c112c4..8f2830c6d34f7 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1333,7 +1333,14 @@ static void pbus_size_mem(struct pci_bus *bus, struct resource *b_res, + r_size = resource_size(r); + size += max(r_size, align); + +- aligns[order] += align; ++ /* ++ * If resource's size is larger than its alignment, ++ * some configurations result in an unwanted gap in ++ * the head space that the larger resource cannot ++ * fill. ++ */ ++ if (r_size <= align) ++ aligns[order] += align; + if (order > max_order) + max_order = order; + } +-- +2.53.0 + diff --git a/queue-7.0/pci-fix-premature-removal-from-realloc_head-list-dur.patch b/queue-7.0/pci-fix-premature-removal-from-realloc_head-list-dur.patch new file mode 100644 index 0000000000..0cb16c9986 --- /dev/null +++ b/queue-7.0/pci-fix-premature-removal-from-realloc_head-list-dur.patch @@ -0,0 +1,92 @@ +From c0aed4ab58372be1375793e4865b2f8458b7f20c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:45:50 +0200 +Subject: PCI: Fix premature removal from realloc_head list during resource + assignment +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit 1ee4716a5a28eaef81ae1f280d983258bee49623 ] + +reassign_resources_sorted() checks for two things: + +a) Resource assignment failures for mandatory resources by checking if the + resource remains unassigned, which are known to always repeat, and does + not attempt to assign them again. + +b) That resource is not among the ones being processed/assigned at this + stage, leading to skip processing such resources in + reassign_resources_sorted() as well (resource assignment progresses + one PCI hierarchy level at a time). + +The problem here is that a) is checked before b), but b) also implies the +resource is not being assigned yet, making also a) true. As a) only skips +resource assignment but still removes the resource from realloc_head, the +later stages that would need to process the information in realloc_head +cannot obtain the optional size information anymore. This leads to +considering only non-optional part for bridge windows deeper in the PCI +hierarchy. + +This problem has been observed during rescan (add_size is not considered +while attempting assignment for 0000:e2:00.0 indicating the corresponding +entry was removed from realloc_head while processing resource assignments +for 0000:e1): + + pci_bus 0000:e1: scanning bus + ... + pci 0000:e3:01.0: bridge window [mem 0x800000000-0x1000ffffff 64bit pref] to [bus e4] add_size 60c000000 add_align 800000000 + pci 0000:e3:01.0: bridge window [mem 0x00100000-0x000fffff] to [bus e4] add_size 200000 add_align 200000 + pci 0000:e3:02.0: disabling bridge window [mem 0x00000000-0x000fffff 64bit pref] to [bus e5] (unused) + pci 0000:e2:00.0: bridge window [mem 0x800000000-0x1000ffffff 64bit pref] to [bus e3-e5] add_size 60c000000 add_align 800000000 + pci 0000:e2:00.0: bridge window [mem 0x00100000-0x001fffff] to [bus e3-e5] add_size 200000 add_align 200000 + pcieport 0000:e1:02.0: bridge window [io size 0x2000]: can't assign; no space + pcieport 0000:e1:02.0: bridge window [io size 0x2000]: failed to assign + pcieport 0000:e1:02.0: bridge window [io 0x1000-0x2fff]: resource restored + pcieport 0000:e1:02.0: bridge window [io 0x1000-0x2fff]: resource restored + pcieport 0000:e1:02.0: bridge window [io size 0x2000]: can't assign; no space + pcieport 0000:e1:02.0: bridge window [io size 0x2000]: failed to assign + pci 0000:e2:00.0: bridge window [mem 0x28f000000000-0x28f800ffffff 64bit pref]: assigned + +Fixes: 96336ec70264 ("PCI: Perform reset_resource() and build fail list in sync") +Reported-by: Peter Nisbet +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Tested-by: Peter Nisbet +Link: https://patch.msgid.link/20260313084551.1934-1-ilpo.jarvinen@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 1f87b018799f9..9506845c112c4 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -434,6 +434,10 @@ static void reassign_resources_sorted(struct list_head *realloc_head, + dev = add_res->dev; + idx = pci_resource_num(dev, res); + ++ /* Skip this resource if not found in head list */ ++ if (!res_to_dev_res(head, res)) ++ continue; ++ + /* + * Skip resource that failed the earlier assignment and is + * not optional as it would just fail again. +@@ -442,10 +446,6 @@ static void reassign_resources_sorted(struct list_head *realloc_head, + !pci_resource_is_optional(dev, idx)) + goto out; + +- /* Skip this resource if not found in head list */ +- if (!res_to_dev_res(head, res)) +- continue; +- + res_name = pci_resource_name(dev, idx); + add_size = add_res->add_size; + align = add_res->min_align; +-- +2.53.0 + diff --git a/queue-7.0/pci-imx6-fix-device-node-reference-leak-in-imx_pcie_.patch b/queue-7.0/pci-imx6-fix-device-node-reference-leak-in-imx_pcie_.patch new file mode 100644 index 0000000000..3e968d10bd --- /dev/null +++ b/queue-7.0/pci-imx6-fix-device-node-reference-leak-in-imx_pcie_.patch @@ -0,0 +1,54 @@ +From d2f1776d5e871b493dcdf029ba3c26a161eb11bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jan 2026 23:42:45 +0800 +Subject: PCI: imx6: Fix device node reference leak in imx_pcie_probe() + +From: Felix Gu + +[ Upstream commit 3b55079d6387805ede687e234d84669aeb0f7e98 ] + +In imx_pcie_probe(), of_parse_phandle() returns the device node pointer +with increased refcount. The pointer reference must be dropped by the +caller when it's no longer needed. However, imx_pcie_probe() doesn't drop +the reference, causing reference leak. + +Fix this by using the __free(device_node) cleanup handler to drop the +reference when the function goes out of scope. + +Fixes: 1df82ec46600 ("PCI: imx: Add workaround for e10728, IMX7d PCIe PLL failure") +Signed-off-by: Felix Gu +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Frank Li +Acked-by: Richard Zhu +Link: https://patch.msgid.link/20260124-pci_imx6-v2-1-acb8d5187683@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pci-imx6.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c +index e01a225cf3ab6..2aa5467d5400a 100644 +--- a/drivers/pci/controller/dwc/pci-imx6.c ++++ b/drivers/pci/controller/dwc/pci-imx6.c +@@ -1647,7 +1647,6 @@ static int imx_pcie_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct dw_pcie *pci; + struct imx_pcie *imx_pcie; +- struct device_node *np; + struct device_node *node = dev->of_node; + int i, ret, domain; + u16 val; +@@ -1674,7 +1673,8 @@ static int imx_pcie_probe(struct platform_device *pdev) + pci->pp.ops = &imx_pcie_host_dw_pme_ops; + + /* Find the PHY if one is defined, only imx7d uses it */ +- np = of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0); ++ struct device_node *np __free(device_node) = ++ of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0); + if (np) { + struct resource res; + +-- +2.53.0 + diff --git a/queue-7.0/pci-imx6-keep-root-port-msi-capability-with-imsi-rx-.patch b/queue-7.0/pci-imx6-keep-root-port-msi-capability-with-imsi-rx-.patch new file mode 100644 index 0000000000..8271b58d9b --- /dev/null +++ b/queue-7.0/pci-imx6-keep-root-port-msi-capability-with-imsi-rx-.patch @@ -0,0 +1,117 @@ +From 94420cdc1c9997229cc102c7b6e112f62987948d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:52:52 +0800 +Subject: PCI: imx6: Keep Root Port MSI capability with iMSI-RX to work around + hardware bug + +From: Richard Zhu + +[ Upstream commit 3a4e8302e72f83fd5cc8a916fc6f5c8fe5c8690e ] + +On NXP i.MX7D, i.MX8MM, and i.MX8MQ chipsets, MSIs from the endpoints won't +be received by the iMSI-RX MSI controller if the Root Port MSI capability +is disabled. + +Even though the Root Port MSIs won't be received by the iMSI-RX controller +due to design, these chipsets have some weird hardware bug that prevents +the endpoint MSIs from reaching when the Root Port MSI capability is +disabled. + +Hence, introduce a new flag, 'dw_pcie_rp::keep_rp_msi_en', set it for the +above mentioned SoCs, and always keep the Root Port MSI capability when +this flag is set. + +Note that by keeping Root Port MSI capability, Root Port MSIs such as AER, +PME and others won't be received by default. So users need to use +workarounds such as passing 'pcie_pme=nomsi' cmdline param. + +Fixes: f5cd8a929c825 ("PCI: dwc: Remove MSI/MSIX capability for Root Port if iMSI-RX is used as MSI controller") +Suggested-by: Manivannan Sadhasivam +Signed-off-by: Richard Zhu +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +[bhelgaas: fix typos] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Frank Li +Link: https://patch.msgid.link/20260331085252.1243108-1-hongxing.zhu@nxp.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pci-imx6.c | 7 +++++++ + drivers/pci/controller/dwc/pcie-designware-host.c | 2 +- + drivers/pci/controller/dwc/pcie-designware.h | 1 + + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c +index 2aa5467d5400a..0a494c9dd6aa1 100644 +--- a/drivers/pci/controller/dwc/pci-imx6.c ++++ b/drivers/pci/controller/dwc/pci-imx6.c +@@ -117,6 +117,8 @@ enum imx_pcie_variants { + #define IMX_PCIE_FLAG_HAS_LUT BIT(10) + #define IMX_PCIE_FLAG_8GT_ECN_ERR051586 BIT(11) + #define IMX_PCIE_FLAG_SKIP_L23_READY BIT(12) ++/* Preserve MSI capability for platforms that require it */ ++#define IMX_PCIE_FLAG_KEEP_MSI_CAP BIT(13) + + #define imx_check_flag(pci, val) (pci->drvdata->flags & val) + +@@ -1830,6 +1832,8 @@ static int imx_pcie_probe(struct platform_device *pdev) + } else { + if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_SKIP_L23_READY)) + pci->pp.skip_l23_ready = true; ++ if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_KEEP_MSI_CAP)) ++ pci->pp.keep_rp_msi_en = true; + pci->pp.use_atu_msg = true; + ret = dw_pcie_host_init(&pci->pp); + if (ret < 0) +@@ -1908,6 +1912,7 @@ static const struct imx_pcie_drvdata drvdata[] = { + [IMX7D] = { + .variant = IMX7D, + .flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND | ++ IMX_PCIE_FLAG_KEEP_MSI_CAP | + IMX_PCIE_FLAG_HAS_APP_RESET | + IMX_PCIE_FLAG_SKIP_L23_READY | + IMX_PCIE_FLAG_HAS_PHY_RESET, +@@ -1920,6 +1925,7 @@ static const struct imx_pcie_drvdata drvdata[] = { + [IMX8MQ] = { + .variant = IMX8MQ, + .flags = IMX_PCIE_FLAG_HAS_APP_RESET | ++ IMX_PCIE_FLAG_KEEP_MSI_CAP | + IMX_PCIE_FLAG_HAS_PHY_RESET | + IMX_PCIE_FLAG_SUPPORTS_SUSPEND, + .gpr = "fsl,imx8mq-iomuxc-gpr", +@@ -1934,6 +1940,7 @@ static const struct imx_pcie_drvdata drvdata[] = { + [IMX8MM] = { + .variant = IMX8MM, + .flags = IMX_PCIE_FLAG_SUPPORTS_SUSPEND | ++ IMX_PCIE_FLAG_KEEP_MSI_CAP | + IMX_PCIE_FLAG_HAS_PHYDRV | + IMX_PCIE_FLAG_HAS_APP_RESET, + .gpr = "fsl,imx8mm-iomuxc-gpr", +diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c +index c3c2dec728eea..6adde3fc32be9 100644 +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -1171,7 +1171,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) + * the MSI and MSI-X capabilities of the Root Port to allow the drivers + * to fall back to INTx instead. + */ +- if (pp->use_imsi_rx) { ++ if (pp->use_imsi_rx && !pp->keep_rp_msi_en) { + dw_pcie_remove_capability(pci, PCI_CAP_ID_MSI); + dw_pcie_remove_capability(pci, PCI_CAP_ID_MSIX); + } +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index ae6389dd9caa5..b12c5334552c7 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -421,6 +421,7 @@ struct dw_pcie_host_ops { + + struct dw_pcie_rp { + bool use_imsi_rx:1; ++ bool keep_rp_msi_en:1; + bool cfg0_io_shared:1; + u64 cfg0_base; + void __iomem *va_cfg0_base; +-- +2.53.0 + diff --git a/queue-7.0/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch b/queue-7.0/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch new file mode 100644 index 0000000000..8c09ddb787 --- /dev/null +++ b/queue-7.0/pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch @@ -0,0 +1,55 @@ +From 6ba85af23a8b3086819c2d66b8667a4381c7588d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 17:35:41 +0800 +Subject: PCI: mediatek-gen3: Prevent leaking IRQ domains when IRQ not found + +From: Chen-Yu Tsai + +[ Upstream commit 5573c44cb3fd01a9f62d569ae9ac870ef5f0e0ba ] + +In mtk_pcie_setup_irq(), the IRQ domains are allocated before the +controller's IRQ is fetched. If the latter fails, the function +directly returns an error, without cleaning up the allocated domains. + +Hence, reverse the order so that the IRQ domains are allocated after the +controller's IRQ is found. + +This was flagged by Sashiko during a review of "[PATCH v6 0/7] PCI: +mediatek-gen3: add power control support". + +Fixes: 814cceebba9b ("PCI: mediatek-gen3: Add INTx support") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Manivannan Sadhasivam +Link: https://sashiko.dev/#/patchset/20260324052002.4072430-1-wenst%40chromium.org +Link: https://patch.msgid.link/20260324093542.18523-1-wenst@chromium.org +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-mediatek-gen3.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c +index 75ddb8bee168f..e45c43ccc84c2 100644 +--- a/drivers/pci/controller/pcie-mediatek-gen3.c ++++ b/drivers/pci/controller/pcie-mediatek-gen3.c +@@ -851,14 +851,14 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie) + struct platform_device *pdev = to_platform_device(dev); + int err; + +- err = mtk_pcie_init_irq_domains(pcie); +- if (err) +- return err; +- + pcie->irq = platform_get_irq(pdev, 0); + if (pcie->irq < 0) + return pcie->irq; + ++ err = mtk_pcie_init_irq_domains(pcie); ++ if (err) ++ return err; ++ + irq_set_chained_handler_and_data(pcie->irq, mtk_pcie_irq_handler, pcie); + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch b/queue-7.0/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch new file mode 100644 index 0000000000..57e88c0315 --- /dev/null +++ b/queue-7.0/pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch @@ -0,0 +1,48 @@ +From 797e563f657488685319046115cf2dbae6eacb90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:38:50 +0800 +Subject: PCI/NPEM: Set LED_HW_PLUGGABLE for hotplug-capable ports + +From: Richard Cheng + +[ Upstream commit 16d021c878dca22532c984668c9e8cf4722d6a49 ] + +NPEM registers LED classdevs on PCI endpoint that may be behind +hotplug-capable ports. During hot-removal, led_classdev_unregister() calls +led_set_brightness(LED_OFF) which leads to a PCI config read to a +disconnected device, which fails and returns -ENODEV (topology details in +msgid.link below): + + leds 0003:01:00.0:enclosure:ok: Setting an LED's brightness failed (-19) + +The LED core already suppresses this for devices with LED_HW_PLUGGABLE set, +but NPEM never sets it. Add the flag since NPEM LEDs are on hot-pluggable +hardware by nature. + +Fixes: 4e893545ef87 ("PCI/NPEM: Add Native PCIe Enclosure Management support") +Signed-off-by: Richard Cheng +Signed-off-by: Bjorn Helgaas +Reviewed-by: Lukas Wunner +Acked-by: Kai-Heng Feng +Link: https://patch.msgid.link/20260402093850.23075-1-icheng@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/npem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/npem.c b/drivers/pci/npem.c +index ffeeedf6e3112..c51879fcd4386 100644 +--- a/drivers/pci/npem.c ++++ b/drivers/pci/npem.c +@@ -504,7 +504,7 @@ static int pci_npem_set_led_classdev(struct npem *npem, struct npem_led *nled) + led->brightness_get = brightness_get; + led->max_brightness = 1; + led->default_trigger = "none"; +- led->flags = 0; ++ led->flags = LED_HW_PLUGGABLE; + + ret = led_classdev_register(&npem->dev->dev, led); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/pci-prevent-shrinking-bridge-window-from-its-require.patch b/queue-7.0/pci-prevent-shrinking-bridge-window-from-its-require.patch new file mode 100644 index 0000000000..221e041b03 --- /dev/null +++ b/queue-7.0/pci-prevent-shrinking-bridge-window-from-its-require.patch @@ -0,0 +1,210 @@ +From 2207b7f5bbbbbced1871f854bcfa5b3e03c97289 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Feb 2026 17:39:51 +0200 +Subject: PCI: Prevent shrinking bridge window from its required size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ilpo Järvinen + +[ Upstream commit dc4b4d04e1caa3552f000d84d832779ebe51b093 ] + +Steve reported an eGPU (either Radeon Instinct MI50 32GB or NVIDIA 3080 +10GB) connected via Thunderbolt was not assigned sufficient BAR space in +v6.11, so the amdgpu and nvidia drivers were unable to initialize the +device. + +pci_bridge_distribute_available_resources() -> ... -> +adjust_bridge_window() is called between __pci_bus_size_bridges() +and assigning the resources. Since the commit 948675736a77 ("PCI: Allow +adjust_bridge_window() to shrink resource if necessary") +adjust_bridge_window() can also shrink the bridge window. The shrunken +size, however, conflicts with what __pci_bus_size_bridges() -> +pbus_size_mem() calculated as the required bridge window size. By shrinking +the size, adjust_bridge_window() prevents the rest of the resource fitting +algorithm from working as intended. Resource fitting logic is expecting +assignment failures when bridge windows need resizing, but there are cases +where failures are no longer happening after the commit 948675736a77 ("PCI: +Allow adjust_bridge_window() to shrink resource if necessary"). + +The commit 948675736a77 ("PCI: Allow adjust_bridge_window() to shrink +resource if necessary") justifies the change by the extra reservation +made due to hpmemsize parameter, however, the kernel code contradicts +that statement. (For simplicity, finer-grained hpmmiosize and hpmmiopref +parameters that can be used to the same effect as hpmemsize are ignored in +this description.) + +pbus_size_mem() calls calculate_memsize() twice. First with add_size=0 +to find out the minimal required resource size. The second call occurs +with add_size=hpmemsize (effectively) but the result does not directly +affect the resource size only resulting in an entry on the realloc_head +list (a.k.a. add_list). Yet, adjust_bridge_window() directly changes +the resource size which does not include what is reserved due to +hpmemsize. Also, if the required size for the bridge window exceeds +hpmemsize, the parameter does not have any effect even on the second +size calculation made by pbus_size_mem(); from calculate_memsize(): + + size = max(size, add_size) + children_add_size; + +The commit ae4611f1d7e9 ("PCI: Set resource size directly in +adjust_bridge_window()") that precedes the commit 948675736a77 ("PCI: +Allow adjust_bridge_window() to shrink resource if necessary") is also +related to causing this problem. Its changelog explicitly states +adjust_bridge_window() wants to "guarantee" allocation success. +Guaranteed allocations, however, are incompatible with how the other +parts of the resource fitting algorithm work. The given justification +fails to explain why guaranteed allocations at this stage are required +nor why forcing window to a smaller value than what was calculated by +pbus_size_mem() is correct. While the change might have worked by chance +in some test scenario, too small bridge window does not "guarantee" +success from the point of view of the endpoint device resource +assignments. No issue is mentioned within the changelog so it's unclear +if the change was made to fix some observed issue nor and what that +issue was. + +The unwanted shrinking of a bridge window occurs, e.g., when a device with +large BARs such as eGPU is attached using Thunderbolt and the Root Port +holds less than enough resource space for the eGPU. The GPU resources are +in order of GBs and the default hotplug allocation is a mere 2MB +(DEFAULT_HOTPLUG_MMIO_PREF_SIZE). The problem is illustrated by this log +(filtered to the relevant content only): + + pci 0000:00:07.0: PCI bridge to [bus 03-2c] + pci 0000:00:07.0: bridge window [mem 0x6000000000-0x601bffffff 64bit pref] + pci 0000:03:00.0: PCI bridge to [bus 00] + pci 0000:03:00.0: bridge window [mem 0x00000000-0x000fffff 64bit pref] + pci 0000:03:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring + pci 0000:03:00.0: PCI bridge to [bus 04-2c] + pcieport 0000:00:07.0: Assigned bridge window [mem 0x6000000000-0x601bffffff 64bit pref] to [bus 03-2c] cannot fit 0xc00000000 required for 0000:03:00.0 bridging to [bus 04-2c] + pci 0000:03:00.0: bridge window [mem 0x800000000-0x10003fffff 64bit pref] to [bus 04-2c] add_size 100000 add_align 100000 + pcieport 0000:00:07.0: distributing available resources + pci 0000:03:00.0: bridge window [mem 0x800000000-0x10003fffff 64bit pref] shrunken by 0x00000007e4400000 + pci 0000:03:00.0: bridge window [mem 0x6000000000-0x601bffffff 64bit pref]: assigned + +The initial size of the Root Port's window is 448MB (0x601bffffff - +0x6000000000). __pci_bus_size_bridges() -> pbus_size_mem() calculates the +required size to be 32772 MB (0x10003fffff - 0x800000000) which would fit +the eGPU resources. adjust_bridge_window() then shrinks the bridge window +down to what is guaranteed to fit into the Root Port's bridge window. The +bridge window for 03:00.0 is also eliminated from the add_list (a.k.a. +realloc_head) list by adjust_bridge_window(). + +After adjustment, the resources are assigned and as the bridge window for +03:00.0 is assigned successfully, no failure is recorded. Without a +failure, no attempt to resize the window of the Root Port is required. The +end result is eGPU not having large enough resources to work. + +The commit 948675736a77 ("PCI: Allow adjust_bridge_window() to shrink +resource if necessary") also claims nested bridge windows are sized the +same, which is false. pbus_size_mem() calculates the size for the parent +bridge window by summing all the downstream resources so the resource +fitting calculates larger bridge window for the parent to accommodate the +childen. That is, hpmemsize does not result the same size for the case +where there are nested bridge windows. + +In order to fix the most immediate problem, don't shrink the resource size +in adjust_bridge_window() as hpmemsize had nothing to do with it. When +considering add_size, only reduce it up to what is added due to hpmemsize +(if required size is larger than hpmemsize, the parameter has no impact, +see calculate_memsize()). Unfortunately, if the tail of the bridge window +was aligned in calculate_memsize() from below hpmemsize to above it, the +size check will falsely match but the check at least errs to the side of +caution. There's not enough information available in adjust_bridge_window() +to know the calculated size precisely. + +This is not exactly a revert of the commits e4611f1d7e9 ("PCI: Set resource +size directly in adjust_bridge_window()") and 948675736a77 ("PCI: Allow +adjust_bridge_window() to shrink resource if necessary") as shrinking still +remains in place but is implemented differently, and the end result behaves +very differently. + +It is possible that those two commits fixed some other issue that is not +described with enough detail in the changelog and undoing parts of them +results in another regression due to behavioral change. Nonetheless, as +described above, the solution by those two commits was flawed and the +issue, if one exists, should be solved in a way that is compatible with the +rest of the resource fitting algorithm instead of working against it. + +Besides shrinking, the case where adjust_bridge_window() expands the bridge +window is likely somewhat wrong as well because it removes the entry from +add_list (a.k.a. realloc_head), but it is less damaging as that only +impacts optional resources and may have no impact if expanding by hpmemsize +is larger than what add_size was. Fixing it is left as further work. + +Fixes: 948675736a77 ("PCI: Allow adjust_bridge_window() to shrink resource if necessary") +Fixes: ae4611f1d7e9 ("PCI: Set resource size directly in adjust_bridge_window()") +Reported-by: Steve Oswald +Closes: https://lore.kernel.org/linux-pci/CAN95MYEaO8QYYL=5cN19nv_qDGuuP5QOD17pD_ed6a7UqFVZ-g@mail.gmail.com/ +Signed-off-by: Ilpo Järvinen +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260219153951.68869-1-ilpo.jarvinen@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/setup-bus.c | 42 +++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 40 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 61f769aaa2f6c..1f87b018799f9 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -1837,6 +1837,7 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res, + resource_size_t new_size) + { + resource_size_t add_size, size = resource_size(res); ++ struct pci_dev_resource *dev_res; + + if (resource_assigned(res)) + return; +@@ -1849,9 +1850,46 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res, + pci_dbg(bridge, "bridge window %pR extended by %pa\n", res, + &add_size); + } else if (new_size < size) { ++ int idx = pci_resource_num(bridge, res); ++ ++ /* ++ * hpio/mmio/mmioprefsize hasn't been included at all? See the ++ * add_size param at the callsites of calculate_memsize(). ++ */ ++ if (!add_list) ++ return; ++ ++ /* Only shrink if the hotplug extra relates to window size. */ ++ switch (idx) { ++ case PCI_BRIDGE_IO_WINDOW: ++ if (size > pci_hotplug_io_size) ++ return; ++ break; ++ case PCI_BRIDGE_MEM_WINDOW: ++ if (size > pci_hotplug_mmio_size) ++ return; ++ break; ++ case PCI_BRIDGE_PREF_MEM_WINDOW: ++ if (size > pci_hotplug_mmio_pref_size) ++ return; ++ break; ++ default: ++ break; ++ } ++ ++ dev_res = res_to_dev_res(add_list, res); + add_size = size - new_size; +- pci_dbg(bridge, "bridge window %pR shrunken by %pa\n", res, +- &add_size); ++ if (add_size < dev_res->add_size) { ++ dev_res->add_size -= add_size; ++ pci_dbg(bridge, "bridge window %pR optional size shrunken by %pa\n", ++ res, &add_size); ++ } else { ++ pci_dbg(bridge, "bridge window %pR optional size removed\n", ++ res); ++ pci_dev_res_remove_from_list(add_list, res); ++ } ++ return; ++ + } else { + return; + } +-- +2.53.0 + diff --git a/queue-7.0/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch b/queue-7.0/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch new file mode 100644 index 0000000000..34efa7667c --- /dev/null +++ b/queue-7.0/pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch @@ -0,0 +1,104 @@ +From 0566174b667e2f3714cee93429432a5a985962ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Mar 2026 07:26:34 +0530 +Subject: PCI: qcom: Advertise Hotplug Slot Capability with no Command + Completion support + +From: Krishna Chaitanya Chundru + +[ Upstream commit 33a76fc3c3e61386524479b99f35423bd3d9a895 ] + +Qcom PCIe Root Ports advertise hotplug capability in hardware, but do not +support hotplug command completion. As a result, the hotplug commands +issued by the pciehp driver never gets completion notification, leading to +repeated timeout warnings and multi-second delays during boot and +suspend/resume. + +Commit a54db86ddc153 ("PCI: qcom: Do not advertise hotplug capability for +IPs v2.7.0 and v1.9.0") mistakenly assumed that the Root Ports doesn't +support Hotplug due to timeouts and disabled the Hotplug functionality +altogether. But the Root Ports does support reporting Hotplug events like +DL_Up/Down events. + +So to fix the command completion timeout issues, just set the No Command +Completed Support (NCCS) bit and enable Hotplug in Slot Capability field +back. + +Fixes: a54db86ddc153 ("PCI: qcom: Do not advertise hotplug capability for IPs v2.7.0 and v1.9.0") +Signed-off-by: Krishna Chaitanya Chundru +[mani: renamed function, commit log and added comment] +Signed-off-by: Manivannan Sadhasivam +Tested-by: Konrad Dybcio # Hamoa CRD, tunneled link +Reviewed-by: Konrad Dybcio +Link: https://patch.msgid.link/20260314-hotplug-v1-1-96ac87d93867@oss.qualcomm.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-qcom.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c +index 67a16af69ddc7..9fdfc88ac1512 100644 +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -350,15 +350,20 @@ static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci) + dw_pcie_dbi_ro_wr_dis(pci); + } + +-static void qcom_pcie_clear_hpc(struct dw_pcie *pci) ++static void qcom_pcie_set_slot_nccs(struct dw_pcie *pci) + { + u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 val; + + dw_pcie_dbi_ro_wr_en(pci); + ++ /* ++ * Qcom PCIe Root Ports do not support generating command completion ++ * notifications for the Hot-Plug commands. So set the NCCS field to ++ * avoid waiting for the completions. ++ */ + val = readl(pci->dbi_base + offset + PCI_EXP_SLTCAP); +- val &= ~PCI_EXP_SLTCAP_HPC; ++ val |= PCI_EXP_SLTCAP_NCCS; + writel(val, pci->dbi_base + offset + PCI_EXP_SLTCAP); + + dw_pcie_dbi_ro_wr_dis(pci); +@@ -558,7 +563,7 @@ static int qcom_pcie_post_init_2_1_0(struct qcom_pcie *pcie) + writel(CFG_BRIDGE_SB_INIT, + pci->dbi_base + AXI_MSTR_RESP_COMP_CTRL1); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -638,7 +643,7 @@ static int qcom_pcie_post_init_1_0_0(struct qcom_pcie *pcie) + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT); + } + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -731,7 +736,7 @@ static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie) + val |= EN; + writel(val, pcie->parf + PARF_AXI_MSTR_WR_ADDR_HALT_V2); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +@@ -1037,7 +1042,7 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) + writel(WR_NO_SNOOP_OVERRIDE_EN | RD_NO_SNOOP_OVERRIDE_EN, + pcie->parf + PARF_NO_SNOOP_OVERRIDE); + +- qcom_pcie_clear_hpc(pcie->pci); ++ qcom_pcie_set_slot_nccs(pcie->pci); + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/pci-rzg3s-host-fix-reset-handling-in-probe-error-pat.patch b/queue-7.0/pci-rzg3s-host-fix-reset-handling-in-probe-error-pat.patch new file mode 100644 index 0000000000..76ef641949 --- /dev/null +++ b/queue-7.0/pci-rzg3s-host-fix-reset-handling-in-probe-error-pat.patch @@ -0,0 +1,43 @@ +From 9ea06620765133a0e455bea2dc3ef3e4bcc9f146 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 15:34:08 +0100 +Subject: PCI: rzg3s-host: Fix reset handling in probe error path + +From: John Madieu + +[ Upstream commit d284389d4576e7c8040dc4cbb66876e539c6d064 ] + +Fix incorrect reset_control_bulk_deassert() call in the probe error +path. When unwinding from a failed pci_host_probe(), the configuration +resets should be asserted to restore the hardware to its initial state, +not deasserted again. + +Fixes: 7ef502fb35b2 ("PCI: Add Renesas RZ/G3S host controller driver") +Signed-off-by: John Madieu +Signed-off-by: Manivannan Sadhasivam +Tested-by: Lad Prabhakar # RZ/V2N EVK +Tested-by: Claudiu Beznea +Reviewed-by: Claudiu Beznea +Link: https://patch.msgid.link/20260306143423.19562-2-john.madieu.xa@bp.renesas.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-rzg3s-host.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c +index 2809112e63171..7a80455aad366 100644 +--- a/drivers/pci/controller/pcie-rzg3s-host.c ++++ b/drivers/pci/controller/pcie-rzg3s-host.c +@@ -1589,8 +1589,7 @@ static int rzg3s_pcie_probe(struct platform_device *pdev) + + host_probe_teardown: + rzg3s_pcie_teardown_irqdomain(host); +- reset_control_bulk_deassert(host->data->num_cfg_resets, +- host->cfg_resets); ++ reset_control_bulk_assert(host->data->num_cfg_resets, host->cfg_resets); + rpm_put: + pm_runtime_put_sync(dev); + rpm_disable: +-- +2.53.0 + diff --git a/queue-7.0/pci-rzg3s-host-reorder-reset-assertion-during-suspen.patch b/queue-7.0/pci-rzg3s-host-reorder-reset-assertion-during-suspen.patch new file mode 100644 index 0000000000..3492a19c9a --- /dev/null +++ b/queue-7.0/pci-rzg3s-host-reorder-reset-assertion-during-suspen.patch @@ -0,0 +1,83 @@ +From 5cc80f9b66b00f6ad2554fc7f6335b620dd205aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 15:34:09 +0100 +Subject: PCI: rzg3s-host: Reorder reset assertion during suspend + +From: John Madieu + +[ Upstream commit 34735f63748daa2ea27544259c3042b4948376bf ] + +Reorder the reset assertion sequence during suspend from +power_resets -> cfg_resets to cfg_resets -> power_resets. +This change ensures the suspend sequence follows the reverse order +of the probe/init sequence, where power_resets are deasserted first +followed by cfg_resets. + +Additionally, this ordering is required for RZ/G3E support where +cfg resets are controlled through PCIe AXI registers (offset 0x310h). +According to the RZ/G3E hardware manual (Rev.1.15, section 6.6.6.1.1 +"Changing the Initial Values of the Registers"), AXI register access +requires ARESETn to be de-asserted and the clock to be supplied. +Since ARESETn is part of power_resets, cfg_resets must be asserted +before power_resets, otherwise the AXI registers become inaccessible. + +Fixes: 7ef502fb35b2 ("PCI: Add Renesas RZ/G3S host controller driver") +Signed-off-by: John Madieu +Signed-off-by: Manivannan Sadhasivam +Tested-by: Lad Prabhakar # RZ/V2N EVK +Tested-by: Claudiu Beznea +Reviewed-by: Claudiu Beznea +Link: https://patch.msgid.link/20260306143423.19562-3-john.madieu.xa@bp.renesas.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/pcie-rzg3s-host.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/controller/pcie-rzg3s-host.c b/drivers/pci/controller/pcie-rzg3s-host.c +index 7a80455aad366..986f0a319b3ce 100644 +--- a/drivers/pci/controller/pcie-rzg3s-host.c ++++ b/drivers/pci/controller/pcie-rzg3s-host.c +@@ -1624,31 +1624,31 @@ static int rzg3s_pcie_suspend_noirq(struct device *dev) + + clk_disable_unprepare(port->refclk); + +- ret = reset_control_bulk_assert(data->num_power_resets, +- host->power_resets); ++ ret = reset_control_bulk_assert(data->num_cfg_resets, ++ host->cfg_resets); + if (ret) + goto refclk_restore; + +- ret = reset_control_bulk_assert(data->num_cfg_resets, +- host->cfg_resets); ++ ret = reset_control_bulk_assert(data->num_power_resets, ++ host->power_resets); + if (ret) +- goto power_resets_restore; ++ goto cfg_resets_restore; + + ret = regmap_update_bits(sysc, RZG3S_SYS_PCIE_RST_RSM_B, + RZG3S_SYS_PCIE_RST_RSM_B_MASK, + FIELD_PREP(RZG3S_SYS_PCIE_RST_RSM_B_MASK, 0)); + if (ret) +- goto cfg_resets_restore; ++ goto power_resets_restore; + + return 0; + + /* Restore the previous state if any error happens */ +-cfg_resets_restore: +- reset_control_bulk_deassert(data->num_cfg_resets, +- host->cfg_resets); + power_resets_restore: + reset_control_bulk_deassert(data->num_power_resets, + host->power_resets); ++cfg_resets_restore: ++ reset_control_bulk_deassert(data->num_cfg_resets, ++ host->cfg_resets); + refclk_restore: + clk_prepare_enable(port->refclk); + pm_runtime_resume_and_get(dev); +-- +2.53.0 + diff --git a/queue-7.0/pci-sg2042-avoid-l0s-and-l1-on-sophgo-2042-pcie-root.patch b/queue-7.0/pci-sg2042-avoid-l0s-and-l1-on-sophgo-2042-pcie-root.patch new file mode 100644 index 0000000000..7fd0b4f690 --- /dev/null +++ b/queue-7.0/pci-sg2042-avoid-l0s-and-l1-on-sophgo-2042-pcie-root.patch @@ -0,0 +1,49 @@ +From 6ce1ea4c263f2cacbed562d0194108ec3fabacfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 15:41:54 +0000 +Subject: PCI: sg2042: Avoid L0s and L1 on Sophgo 2042 PCIe Root Ports + +From: Yao Zi + +[ Upstream commit 988ef706cdd8a72e61dd90c0d0554eec4df7594a ] + +Since commit f3ac2ff14834 ("PCI/ASPM: Enable all ClockPM and ASPM states +for devicetree platforms") force enables ASPM on all device tree platforms, +the SG2042 Root Ports are breaking as they advertise L0s and L1 +capabilities without supporting them. + +Set ASPM quirks to disable the L0s and L1 capabilities for the Root Ports +so that these broken link states won't be enabled. + +Fixes: 4e27aca4881a ("riscv: sophgo: dts: add PCIe controllers for SG2042") +Co-developed-by: Inochi Amaoto +Signed-off-by: Inochi Amaoto +Signed-off-by: Yao Zi +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Han Gao +Tested-by: Chen Wang # Pioneerbox +Reviewed-by: Chen Wang +Link: https://patch.msgid.link/20260405154154.46829-3-me@ziyao.cc +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/cadence/pcie-sg2042.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/cadence/pcie-sg2042.c b/drivers/pci/controller/cadence/pcie-sg2042.c +index 0c50c74d03eeb..4a2af4d0713e6 100644 +--- a/drivers/pci/controller/cadence/pcie-sg2042.c ++++ b/drivers/pci/controller/cadence/pcie-sg2042.c +@@ -48,6 +48,8 @@ static int sg2042_pcie_probe(struct platform_device *pdev) + bridge->child_ops = &sg2042_pcie_child_ops; + + rc = pci_host_bridge_priv(bridge); ++ rc->quirk_broken_aspm_l0s = 1; ++ rc->quirk_broken_aspm_l1 = 1; + pcie = &rc->pcie; + pcie->dev = dev; + +-- +2.53.0 + diff --git a/queue-7.0/pci-sky1-fix-missing-cleanup-of-ecam-config-on-probe.patch b/queue-7.0/pci-sky1-fix-missing-cleanup-of-ecam-config-on-probe.patch new file mode 100644 index 0000000000..8a49e51978 --- /dev/null +++ b/queue-7.0/pci-sky1-fix-missing-cleanup-of-ecam-config-on-probe.patch @@ -0,0 +1,44 @@ +From c30e4d95a37c11e6f598270a17992203b7650e13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 00:41:28 +0800 +Subject: PCI: sky1: Fix missing cleanup of ECAM config on probe failure + +From: Felix Gu + +[ Upstream commit 72e76b63d6ff6d1f96acccbfc6c118656f63e66a ] + +When devm_kzalloc() for reg_off fails, the code returns -ENOMEM without +freeing pcie->cfg, which was allocated earlier by pci_ecam_create(). + +Add the missing pci_ecam_free() call to properly release the allocated ECAM +configuration window on this error path. + +Fixes: a0d9f2c08f45 ("PCI: sky1: Add PCIe host support for CIX Sky1") +Signed-off-by: Felix Gu +Signed-off-by: Manivannan Sadhasivam +Reviewed-by: Hans Zhang <18255117159@163.com> +Link: https://patch.msgid.link/20260324-sky1-v1-1-6a00cb2776b6@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/cadence/pci-sky1.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/cadence/pci-sky1.c b/drivers/pci/controller/cadence/pci-sky1.c +index d8c216dc120d6..9853a9c82c0e6 100644 +--- a/drivers/pci/controller/cadence/pci-sky1.c ++++ b/drivers/pci/controller/cadence/pci-sky1.c +@@ -176,8 +176,10 @@ static int sky1_pcie_probe(struct platform_device *pdev) + cdns_pcie->is_rc = 1; + + reg_off = devm_kzalloc(dev, sizeof(*reg_off), GFP_KERNEL); +- if (!reg_off) ++ if (!reg_off) { ++ pci_ecam_free(pcie->cfg); + return -ENOMEM; ++ } + + reg_off->ip_reg_bank_offset = SKY1_IP_REG_BANK; + reg_off->ip_cfg_ctrl_reg_offset = SKY1_IP_CFG_CTRL_REG_BANK; +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch b/queue-7.0/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch new file mode 100644 index 0000000000..4e8525ec30 --- /dev/null +++ b/queue-7.0/pci-tegra194-allow-system-suspend-when-the-endpoint-.patch @@ -0,0 +1,108 @@ +From d476a3c87dbaafe7f3ffe710a5fde2272a8787e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:50 +0530 +Subject: PCI: tegra194: Allow system suspend when the Endpoint link is not up + +From: Vidya Sagar + +[ Upstream commit c76f8eae7d4695b1176c4ea5eb93c17e16a20272 ] + +Host software initiates the L2 sequence. PCIe link is kept in L2 state +during suspend. If Endpoint mode is enabled and the link is up, the +software cannot proceed with suspend. However, when the PCIe Endpoint +driver is probed, but the PCIe link is not up, Tegra can go into suspend +state. So, allow system to suspend in this case. + +Fixes: de2bbf2b71bb ("PCI: tegra194: Don't allow suspend when Tegra PCIe is in EP mode") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-10-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 31 +++++++++++++++++----- + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 95dbf2102c898..06742796c332f 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2270,16 +2270,28 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev) + gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0); + } + +-static int tegra_pcie_dw_suspend_late(struct device *dev) ++static int tegra_pcie_dw_suspend(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); +- u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n"); +- return -EPERM; ++ if (pcie->ep_state == EP_STATE_ENABLED) { ++ dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n"); ++ return -EPERM; ++ } ++ ++ disable_irq(pcie->pex_rst_irq); ++ return 0; + } + ++ return 0; ++} ++ ++static int tegra_pcie_dw_suspend_late(struct device *dev) ++{ ++ struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); ++ u32 val; ++ + if (!pcie->link_state) + return 0; + +@@ -2299,6 +2311,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + { + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2313,6 +2328,9 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); + int ret; + ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ return 0; ++ + if (!pcie->link_state) + return 0; + +@@ -2345,8 +2363,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev) + u32 val; + + if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { +- dev_err(dev, "Suspend is not supported in EP mode"); +- return -ENOTSUPP; ++ enable_irq(pcie->pex_rst_irq); ++ return 0; + } + + if (!pcie->link_state) +@@ -2451,6 +2469,7 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = { + }; + + static const struct dev_pm_ops tegra_pcie_dw_pm_ops = { ++ .suspend = tegra_pcie_dw_suspend, + .suspend_late = tegra_pcie_dw_suspend_late, + .suspend_noirq = tegra_pcie_dw_suspend_noirq, + .resume_noirq = tegra_pcie_dw_resume_noirq, +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-disable-direct-speed-change-for-endpoin.patch b/queue-7.0/pci-tegra194-disable-direct-speed-change-for-endpoin.patch new file mode 100644 index 0000000000..3ec8598b52 --- /dev/null +++ b/queue-7.0/pci-tegra194-disable-direct-speed-change-for-endpoin.patch @@ -0,0 +1,52 @@ +From d8c0cc01947300d8fe0361aeb76491a1c0d49303 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:48 +0530 +Subject: PCI: tegra194: Disable direct speed change for Endpoint mode + +From: Vidya Sagar + +[ Upstream commit 976f6763f57970388bcd7118931f33f447916927 ] + +Pre-silicon simulation showed the controller operating in Endpoint mode +initiating link speed change after completing Secondary Bus Reset. Ideally, +the Root Port or the Switch Downstream Port should initiate the link speed +change post SBR, not the Endpoint. + +So, as per the hardware team recommendation, disable direct speed change +for the Endpoint mode to prevent it from initiating speed change after the +physical layer link is up at Gen1, leaving speed change ownership with the +host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-8-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 71b80edd10c8c..4d8bfd3e34ece 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1805,6 +1805,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); ++ val &= ~PORT_LOGIC_SPEED_CHANGE; ++ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); ++ + if (pcie->update_fc_fixup) { + val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); + val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-disable-l1.2-capability-of-tegra234-ep.patch b/queue-7.0/pci-tegra194-disable-l1.2-capability-of-tegra234-ep.patch new file mode 100644 index 0000000000..ababeca556 --- /dev/null +++ b/queue-7.0/pci-tegra194-disable-l1.2-capability-of-tegra234-ep.patch @@ -0,0 +1,78 @@ +From 18ea203947d21f904f801fbfcb719bc353f45633 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:54 +0530 +Subject: PCI: tegra194: Disable L1.2 capability of Tegra234 EP + +From: Vidya Sagar + +[ Upstream commit f59df1d9e6bdb6bd7ef65fb5d200900ac40c20ba ] + +When Tegra234 is operating in the Endpoint mode with L1.2 enabled, PCIe +link goes down during L1.2 exit. This is because Tegra234 powers up UPHY +PLL immediately without making sure that the REFCLK is stable. + +This causes UPHY PLL to fail to lock to the correct frequency and leads to +link going down. There is no hardware fix for this, hence do not advertise +the L1.2 capability in the Endpoint mode. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-14-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 688da5a73d02e..eb24f88e0175b 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -234,6 +234,7 @@ struct tegra_pcie_dw_of_data { + bool has_sbr_reset_fix; + bool has_l1ss_exit_fix; + bool has_ltr_req_fix; ++ bool disable_l1_2; + u32 cdm_chk_int_en_bit; + u32 gen4_preset_vec; + u8 n_fts[2]; +@@ -679,6 +680,23 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie) + if (pcie->supports_clkreq) + pci->l1ss_support = true; + ++ /* ++ * Disable L1.2 capability advertisement for Tegra234 Endpoint mode. ++ * Tegra234 has a hardware bug where during L1.2 exit, the UPHY PLL is ++ * powered up immediately without waiting for REFCLK to stabilize. This ++ * causes the PLL to fail to lock to the correct frequency, resulting in ++ * PCIe link loss. Since there is no hardware fix available, we prevent ++ * the Endpoint from advertising L1.2 support by clearing the L1.2 bits ++ * in the L1 PM Substates Capabilities register. This ensures the host ++ * will not attempt to enter L1.2 state with this Endpoint. ++ */ ++ if (pcie->of_data->disable_l1_2 && ++ pcie->of_data->mode == DW_PCIE_EP_TYPE) { ++ val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP); ++ val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2); ++ dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val); ++ } ++ + /* Program L0s and L1 entrance latencies */ + val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); + val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK; +@@ -2444,6 +2462,7 @@ static const struct tegra_pcie_dw_of_data tegra234_pcie_dw_ep_of_data = { + .mode = DW_PCIE_EP_TYPE, + .has_l1ss_exit_fix = true, + .has_ltr_req_fix = true, ++ .disable_l1_2 = true, + .cdm_chk_int_en_bit = BIT(18), + /* Gen4 - 6, 8 and 9 presets enabled */ + .gen4_preset_vec = 0x340, +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-disable-ltssm-after-transition-to-detec.patch b/queue-7.0/pci-tegra194-disable-ltssm-after-transition-to-detec.patch new file mode 100644 index 0000000000..de77aafcea --- /dev/null +++ b/queue-7.0/pci-tegra194-disable-ltssm-after-transition-to-detec.patch @@ -0,0 +1,92 @@ +From e61649c4fa8f84f6ce2ee1a648fdde23ff6314ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:44 +0530 +Subject: PCI: tegra194: Disable LTSSM after transition to Detect on surprise + link down + +From: Manikanta Maddireddy + +[ Upstream commit 9fa0c242f8d7acf1b124d4462d18f4023573ac1c ] + +After the link reaches a Detect-related LTSSM state, disable LTSSM so it +does not keep toggling between Polling and Detect. Do this by polling for +the Detect state first, then clearing APPL_CTRL_LTSSM_EN in both +tegra_pcie_dw_pme_turnoff() and pex_ep_event_pex_rst_assert(). + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-4-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 29 ++++++++++++---------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 94113b2e33080..b38dbd02214b9 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1594,14 +1594,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_PINMUX_PEX_RST; + appl_writel(pcie, data, APPL_PINMUX); + +- /* +- * Some cards do not go to detect state even after de-asserting +- * PERST#. So, de-assert LTSSM to bring link to detect state. +- */ +- data = readl(pcie->appl_base + APPL_CTRL); +- data &= ~APPL_CTRL_LTSSM_EN; +- writel(data, pcie->appl_base + APPL_CTRL); +- + err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1610,6 +1602,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); ++ ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ data = readl(pcie->appl_base + APPL_CTRL); ++ data &= ~APPL_CTRL_LTSSM_EN; ++ writel(data, pcie->appl_base + APPL_CTRL); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1683,11 +1683,6 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (pcie->ep_state == EP_STATE_DISABLED) + return; + +- /* Disable LTSSM */ +- val = appl_readl(pcie, APPL_CTRL); +- val &= ~APPL_CTRL_LTSSM_EN; +- appl_writel(pcie, val, APPL_CTRL); +- + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || + ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || +@@ -1698,6 +1693,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + if (ret) + dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + ++ /* ++ * Deassert LTSSM state to stop the state toggling between ++ * Polling and Detect. ++ */ ++ val = appl_readl(pcie, APPL_CTRL); ++ val &= ~APPL_CTRL_LTSSM_EN; ++ appl_writel(pcie, val, APPL_CTRL); ++ + reset_control_assert(pcie->core_rst); + + tegra_pcie_disable_phy(pcie); +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch b/queue-7.0/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch new file mode 100644 index 0000000000..3f99b33cc0 --- /dev/null +++ b/queue-7.0/pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch @@ -0,0 +1,52 @@ +From ed734d28f867d0639dc29bf40e322c994d277538 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:46 +0530 +Subject: PCI: tegra194: Disable PERST# IRQ only in Endpoint mode + +From: Manikanta Maddireddy + +[ Upstream commit 40658a31b6e134169c648041efc84944c4c71dcd ] + +The PERST# GPIO interrupt is only registered when the controller is +operating in Endpoint mode. In Root Port mode, the PERST# GPIO is +configured as an output to control downstream devices, and no interrupt is +registered for it. + +Currently, tegra_pcie_dw_stop_link() unconditionally calls disable_irq() +on pex_rst_irq, which causes issues in Root Port mode where this IRQ is +not registered. + +Fix this by only disabling the PERST# IRQ when operating in Endpoint mode, +where the interrupt is actually registered and used to detect PERST# +assertion/deassertion from the host. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-6-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index c84eb1ba3a11c..ceb34110a50b3 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1025,7 +1025,8 @@ static void tegra_pcie_dw_stop_link(struct dw_pcie *pci) + { + struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); + +- disable_irq(pcie->pex_rst_irq); ++ if (pcie->of_data->mode == DW_PCIE_EP_TYPE) ++ disable_irq(pcie->pex_rst_irq); + } + + static const struct dw_pcie_ops tegra_dw_pcie_ops = { +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch b/queue-7.0/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch new file mode 100644 index 0000000000..d89bdc9faf --- /dev/null +++ b/queue-7.0/pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch @@ -0,0 +1,111 @@ +From 4538fb1cc50c8a1010b16495cbdd187dbc21a21b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:45 +0530 +Subject: PCI: tegra194: Don't force the device into the D0 state before L2 + +From: Vidya Sagar + +[ Upstream commit 71d9f67701e1affc82d18ca88ae798c5361beddf ] + +As per PCIe CEM r6.0, sec 2.3, the PCIe Endpoint device should be in D3cold +to assert WAKE# pin. The previous workaround that forced downstream devices +to D0 before taking the link to L2 cited PCIe r4.0, sec 5.2, "Link State +Power Management"; however, that spec does not explicitly require putting +the device into D0 and only indicates that power removal may be initiated +without transitioning to D3hot. + +Remove the D0 workaround so that Endpoint devices can use wake +functionality (WAKE# from D3). With some Endpoints the link may not enter +L2 when they remain in D3, but the Root Port continues with the usual flow +after PME timeout, so there is no functional issue. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Vidya Sagar +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-5-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 41 ---------------------- + 1 file changed, 41 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index b38dbd02214b9..c84eb1ba3a11c 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1258,44 +1258,6 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, + return 0; + } + +-static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) +-{ +- struct dw_pcie_rp *pp = &pcie->pci.pp; +- struct pci_bus *child, *root_port_bus = NULL; +- struct pci_dev *pdev; +- +- /* +- * link doesn't go into L2 state with some of the endpoints with Tegra +- * if they are not in D0 state. So, need to make sure that immediate +- * downstream devices are in D0 state before sending PME_TurnOff to put +- * link into L2 state. +- * This is as per PCI Express Base r4.0 v1.0 September 27-2017, +- * 5.2 Link State Power Management (Page #428). +- */ +- +- list_for_each_entry(child, &pp->bridge->bus->children, node) { +- if (child->parent == pp->bridge->bus) { +- root_port_bus = child; +- break; +- } +- } +- +- if (!root_port_bus) { +- dev_err(pcie->dev, "Failed to find downstream bus of Root Port\n"); +- return; +- } +- +- /* Bring downstream devices to D0 if they are not already in */ +- list_for_each_entry(pdev, &root_port_bus->devices, bus_list) { +- if (PCI_SLOT(pdev->devfn) == 0) { +- if (pci_set_power_state(pdev, PCI_D0)) +- dev_err(pcie->dev, +- "Failed to transition %s to D0 state\n", +- dev_name(&pdev->dev)); +- } +- } +-} +- + static int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie) + { + pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3"); +@@ -1625,7 +1587,6 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + + static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) + { +- tegra_pcie_downstream_dev_to_D0(pcie); + dw_pcie_host_deinit(&pcie->pci.pp); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); +@@ -2336,7 +2297,6 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) + if (!pcie->link_state) + return 0; + +- tegra_pcie_downstream_dev_to_D0(pcie); + tegra_pcie_dw_pme_turnoff(pcie); + tegra_pcie_unconfig_controller(pcie); + +@@ -2410,7 +2370,6 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev) + return; + + debugfs_remove_recursive(pcie->debugfs); +- tegra_pcie_downstream_dev_to_D0(pcie); + + disable_irq(pcie->pci.pp.irq); + if (IS_ENABLED(CONFIG_PCI_MSI)) +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch b/queue-7.0/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch new file mode 100644 index 0000000000..127ebf14c9 --- /dev/null +++ b/queue-7.0/pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch @@ -0,0 +1,79 @@ +From 095b917e199b9f2cacb03229ce739c5bd573f2fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:55 +0530 +Subject: PCI: tegra194: Fix CBB timeout caused by DBI access before core + power-on + +From: Manikanta Maddireddy + +[ Upstream commit 34b3eef48d980cd37b876e128bbf314f69fb5d70 ] + +When PERST# is deasserted twice (assert -> deassert -> assert -> deassert), +a CBB (Control Backbone) timeout occurs at DBI register offset 0x8bc +(PCIE_MISC_CONTROL_1_OFF). This happens because pci_epc_deinit_notify() +and dw_pcie_ep_cleanup() are called before reset_control_deassert() powers +on the controller core. + +The call chain that causes the timeout: + + pex_ep_event_pex_rst_deassert() + pci_epc_deinit_notify() + pci_epf_test_epc_deinit() + pci_epf_test_clear_bar() + pci_epc_clear_bar() + dw_pcie_ep_clear_bar() + __dw_pcie_ep_reset_bar() + dw_pcie_dbi_ro_wr_en() <- Accesses 0x8bc DBI register + reset_control_deassert(pcie->core_rst) <- Core powered on HERE + +The DBI registers, including PCIE_MISC_CONTROL_1_OFF (0x8bc), are only +accessible after the controller core is powered on via +reset_control_deassert(pcie->core_rst). Accessing them before this point +results in a CBB timeout because the hardware is not yet operational. + +Fix this by moving pci_epc_deinit_notify() and dw_pcie_ep_cleanup() to +after reset_control_deassert(pcie->core_rst), ensuring the controller is +fully powered on before any DBI register accesses occur. + +Fixes: 40e2125381dc ("PCI: tegra194: Move controller cleanups to pex_ep_event_pex_rst_deassert()") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-15-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index eb24f88e0175b..336d3c759547a 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1750,10 +1750,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + goto fail_phy; + } + +- /* Perform cleanup that requires refclk */ +- pci_epc_deinit_notify(pcie->pci.ep.epc); +- dw_pcie_ep_cleanup(&pcie->pci.ep); +- + /* Clear any stale interrupt statuses */ + appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0); + appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0); +@@ -1823,6 +1819,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + + reset_control_deassert(pcie->core_rst); + ++ /* Perform cleanup that requires refclk and core reset deasserted */ ++ pci_epc_deinit_notify(pcie->pci.ep.epc); ++ dw_pcie_ep_cleanup(&pcie->pci.ep); ++ + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + val &= ~PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-fix-polling-delay-for-l2-state.patch b/queue-7.0/pci-tegra194-fix-polling-delay-for-l2-state.patch new file mode 100644 index 0000000000..9e2c475dd0 --- /dev/null +++ b/queue-7.0/pci-tegra194-fix-polling-delay-for-l2-state.patch @@ -0,0 +1,59 @@ +From e7038470e038b18472188345ce12e44ad7e60064 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:42 +0530 +Subject: PCI: tegra194: Fix polling delay for L2 state + +From: Vidya Sagar + +[ Upstream commit adaffed907f14f954096555665ad6af2ae724d83 ] + +As per PCIe r7.0, sec 5.3.3.2.1, after sending PME_Turn_Off message, Root +Port should wait for 1-10 msec for PME_TO_Ack message. Currently, driver is +polling for 10 msec with 1 usec delay which is aggressive. Use existing +macro PCIE_PME_TO_L2_TIMEOUT_US to poll for 10 msec with 1 msec delay. +Since this function is used in non-atomic context only, use non-atomic poll +function. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-2-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 06571d806ab31..13949f6f7d5be 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -198,8 +198,6 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define PME_ACK_TIMEOUT 10000 +- + #define LTSSM_TIMEOUT 50000 /* 50ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 +@@ -1553,9 +1551,10 @@ static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) + val |= APPL_PM_XMT_TURNOFF_STATE; + appl_writel(pcie, val, APPL_RADM_STATUS); + +- return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val, +- val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, +- 1, PME_ACK_TIMEOUT); ++ return readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, ++ val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, ++ PCIE_PME_TO_L2_TIMEOUT_US/10, ++ PCIE_PME_TO_L2_TIMEOUT_US); + } + + static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-free-up-endpoint-resources-during-remov.patch b/queue-7.0/pci-tegra194-free-up-endpoint-resources-during-remov.patch new file mode 100644 index 0000000000..1065605891 --- /dev/null +++ b/queue-7.0/pci-tegra194-free-up-endpoint-resources-during-remov.patch @@ -0,0 +1,49 @@ +From 3471b0635ba210aa44d3ed12af784dfef8df71b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:51 +0530 +Subject: PCI: tegra194: Free up Endpoint resources during remove() + +From: Vidya Sagar + +[ Upstream commit 8870f02f7868209eb9bdc5dc53540a6262cf9227 ] + +Free up the resources during remove() that were acquired by the DesignWare +driver for the Endpoint mode during probe(). + +Fixes: bb617cbd8151 ("PCI: tegra194: Clean up the exit path for Endpoint mode") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-11-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 06742796c332f..3527a4e82bac8 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -2251,6 +2251,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) + static void tegra_pcie_dw_remove(struct platform_device *pdev) + { + struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev); ++ struct dw_pcie_ep *ep = &pcie->pci.ep; + + if (pcie->of_data->mode == DW_PCIE_RC_TYPE) { + if (!pcie->link_state) +@@ -2262,6 +2263,7 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev) + } else { + disable_irq(pcie->pex_rst_irq); + pex_ep_event_pex_rst_assert(pcie); ++ dw_pcie_ep_deinit(ep); + } + + pm_runtime_disable(pcie->dev); +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch b/queue-7.0/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch new file mode 100644 index 0000000000..a10aaf27f5 --- /dev/null +++ b/queue-7.0/pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch @@ -0,0 +1,106 @@ +From d7ee4db857c4493fe71f9db2fe7cb1d147d54404 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:43 +0530 +Subject: PCI: tegra194: Increase LTSSM poll time on surprise link down + +From: Manikanta Maddireddy + +[ Upstream commit 74dd8efe4d6cead433162147333af989a568aac7 ] + +On surprise link down, LTSSM state transits from L0 -> Recovery.RcvrLock -> +Recovery.RcvrSpeed -> Gen1 Recovery.RcvrLock -> Detect. Recovery.RcvrLock +and Recovery.RcvrSpeed transit times are 24 ms and 48 ms respectively, so +the total time from L0 to Detect is ~96 ms. Increase the poll timeout to +120 ms to account for this. + +While at it, add LTSSM state defines for Detect-related states and use them +in the poll condition. Use readl_poll_timeout() instead of +readl_poll_timeout_atomic() in tegra_pcie_dw_pme_turnoff() since that path +runs in non-atomic context. + +Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-3-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 36 +++++++++++++--------- + 1 file changed, 21 insertions(+), 15 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 13949f6f7d5be..94113b2e33080 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -137,7 +137,11 @@ + #define APPL_DEBUG_PM_LINKST_IN_L0 0x11 + #define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) + #define APPL_DEBUG_LTSSM_STATE_SHIFT 3 +-#define LTSSM_STATE_PRE_DETECT 5 ++#define LTSSM_STATE_DETECT_QUIET 0x00 ++#define LTSSM_STATE_DETECT_ACT 0x08 ++#define LTSSM_STATE_PRE_DETECT_QUIET 0x28 ++#define LTSSM_STATE_DETECT_WAIT 0x30 ++#define LTSSM_STATE_L2_IDLE 0xa8 + + #define APPL_RADM_STATUS 0xE4 + #define APPL_PM_XMT_TURNOFF_STATE BIT(0) +@@ -198,7 +202,8 @@ + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) + #define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 + +-#define LTSSM_TIMEOUT 50000 /* 50ms */ ++#define LTSSM_DELAY_US 10000 /* 10 ms */ ++#define LTSSM_TIMEOUT_US 120000 /* 120 ms */ + + #define GEN3_GEN4_EQ_PRESET_INIT 5 + +@@ -1597,15 +1602,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) + data &= ~APPL_CTRL_LTSSM_EN; + writel(data, pcie->appl_base + APPL_CTRL); + +- err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, +- data, +- ((data & +- APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ err = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, data, ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((data & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (err) +- dev_info(pcie->dev, "Link didn't go to detect state\n"); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", data, err); + } + /* + * DBI registers may not be accessible after this as PLL-E would be +@@ -1685,12 +1689,14 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) + appl_writel(pcie, val, APPL_CTRL); + + ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, +- ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> +- APPL_DEBUG_LTSSM_STATE_SHIFT) == +- LTSSM_STATE_PRE_DETECT, +- 1, LTSSM_TIMEOUT); ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_ACT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_PRE_DETECT_QUIET) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_DETECT_WAIT) || ++ ((val & APPL_DEBUG_LTSSM_STATE_MASK) == LTSSM_STATE_L2_IDLE), ++ LTSSM_DELAY_US, LTSSM_TIMEOUT_US); + if (ret) +- dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); ++ dev_info(pcie->dev, "LTSSM state: 0x%x detect timeout: %d\n", val, ret); + + reset_control_assert(pcie->core_rst); + +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch b/queue-7.0/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch new file mode 100644 index 0000000000..ec6bfe0340 --- /dev/null +++ b/queue-7.0/pci-tegra194-set-ltr-message-request-before-pcie-lin.patch @@ -0,0 +1,71 @@ +From 04437727713ebc38958805ae0b9dae352e46b759 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:49 +0530 +Subject: PCI: tegra194: Set LTR message request before PCIe link up in + Endpoint mode + +From: Vidya Sagar + +[ Upstream commit b256493bf8cacf0e524bf4c10b5c4901d0c6cefe ] + +LTR message should be sent as soon as the Root Port enables LTR in the +Endpoint mode. So set snoop and no-snoop LTR timing and LTR message request +before the PCIe link comes up, so that the LTR message is sent upstream as +soon as LTR is enabled. + +Without programming these values, the Endpoint would send latencies of 0 to +the host, which will be inaccurate. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +[mani: commit log] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Reviewed-by: Jon Hunter +Tested-by: Jon Hunter +Link: https://patch.msgid.link/20260324190755.1094879-9-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 4d8bfd3e34ece..95dbf2102c898 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -485,15 +485,6 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg) + if (val & PCI_COMMAND_MASTER) { + ktime_t timeout; + +- /* 110us for both snoop and no-snoop */ +- val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) | +- FIELD_PREP(PCI_LTR_SCALE_MASK, 2) | +- LTR_MSG_REQ | +- FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) | +- FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) | +- LTR_NOSNOOP_MSG_REQ; +- appl_writel(pcie, val, APPL_LTR_MSG_1); +- + /* Send LTR upstream */ + val = appl_readl(pcie, APPL_LTR_MSG_2); + val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE; +@@ -1803,6 +1794,15 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) + val |= APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN; + appl_writel(pcie, val, APPL_INTR_EN_L1_0_0); + ++ /* 110us for both snoop and no-snoop */ ++ val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) | ++ FIELD_PREP(PCI_LTR_SCALE_MASK, 2) | ++ LTR_MSG_REQ | ++ FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) | ++ FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) | ++ LTR_NOSNOOP_MSG_REQ; ++ appl_writel(pcie, val, APPL_LTR_MSG_1); ++ + reset_control_deassert(pcie->core_rst); + + val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch b/queue-7.0/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch new file mode 100644 index 0000000000..3b629a5fd8 --- /dev/null +++ b/queue-7.0/pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch @@ -0,0 +1,47 @@ +From 9c980d17507993f40fe87419c6e723c57f9328e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:47 +0530 +Subject: PCI: tegra194: Use devm_gpiod_get_optional() to parse + "nvidia,refclk-select" + +From: Vidya Sagar + +[ Upstream commit f62bc7917de1374dce86a852ffba8baf9cb7a56a ] + +The GPIO DT property "nvidia,refclk-select", to select the PCIe reference +clock is optional. Use devm_gpiod_get_optional() to get it. + +Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") +Signed-off-by: Vidya Sagar +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-7-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-tegra194.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index ceb34110a50b3..71b80edd10c8c 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -1167,9 +1167,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) + return err; + } + +- pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, +- "nvidia,refclk-select", +- GPIOD_OUT_HIGH); ++ pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev, ++ "nvidia,refclk-select", ++ GPIOD_OUT_HIGH); + if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { + int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); + const char *level = KERN_ERR; +-- +2.53.0 + diff --git a/queue-7.0/pci-tegra194-use-dwc-ip-core-version.patch b/queue-7.0/pci-tegra194-use-dwc-ip-core-version.patch new file mode 100644 index 0000000000..b8db96df9e --- /dev/null +++ b/queue-7.0/pci-tegra194-use-dwc-ip-core-version.patch @@ -0,0 +1,65 @@ +From f53354ab2e475e4221be38e3503ddd0726fffd91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 00:37:52 +0530 +Subject: PCI: tegra194: Use DWC IP core version + +From: Manikanta Maddireddy + +[ Upstream commit ea60ca067f0f098043610c96a915d162113c1aac ] + +Tegra194 PCIe driver used custom version numbers to detect Tegra194 and +Tegra234 IPs. With version detect logic added, version check results in +mismatch warnings: + + tegra194-pcie 14100000.pcie: Versions don't match (0000562a != 3536322a) + +Use HW version numbers which match to PORT_LOGIC.PCIE_VERSION_OFF in +Tegra194 driver to avoid these kernel warnings. + +Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support") +Signed-off-by: Manikanta Maddireddy +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Bjorn Helgaas +Tested-by: Jon Hunter +Reviewed-by: Jon Hunter +Reviewed-by: Vidya Sagar +Link: https://patch.msgid.link/20260324190755.1094879-12-mmaddireddy@nvidia.com +Signed-off-by: Sasha Levin +--- + drivers/pci/controller/dwc/pcie-designware.h | 2 ++ + drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h +index b12c5334552c7..3e69ef60165b0 100644 +--- a/drivers/pci/controller/dwc/pcie-designware.h ++++ b/drivers/pci/controller/dwc/pcie-designware.h +@@ -34,8 +34,10 @@ + #define DW_PCIE_VER_470A 0x3437302a + #define DW_PCIE_VER_480A 0x3438302a + #define DW_PCIE_VER_490A 0x3439302a ++#define DW_PCIE_VER_500A 0x3530302a + #define DW_PCIE_VER_520A 0x3532302a + #define DW_PCIE_VER_540A 0x3534302a ++#define DW_PCIE_VER_562A 0x3536322a + + #define __dw_pcie_ver_cmp(_pci, _ver, _op) \ + ((_pci)->version _op DW_PCIE_VER_ ## _ver) +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 3527a4e82bac8..688da5a73d02e 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -35,8 +35,8 @@ + #include + #include "../../pci.h" + +-#define TEGRA194_DWC_IP_VER 0x490A +-#define TEGRA234_DWC_IP_VER 0x562A ++#define TEGRA194_DWC_IP_VER DW_PCIE_VER_500A ++#define TEGRA234_DWC_IP_VER DW_PCIE_VER_562A + + #define APPL_PINMUX 0x0 + #define APPL_PINMUX_PEX_RST BIT(0) +-- +2.53.0 + diff --git a/queue-7.0/pci-tph-allow-tph-enable-for-rcieps.patch b/queue-7.0/pci-tph-allow-tph-enable-for-rcieps.patch new file mode 100644 index 0000000000..7dbda13b2d --- /dev/null +++ b/queue-7.0/pci-tph-allow-tph-enable-for-rcieps.patch @@ -0,0 +1,62 @@ +From 33f32031239d208a37c3622a87b843225fe0b715 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Jan 2026 10:59:23 +0530 +Subject: PCI/TPH: Allow TPH enable for RCiEPs + +From: George Abraham P + +[ Upstream commit d3e996a596967a62c8a13a279221513461f6ab97 ] + +Previously, pcie_enable_tph() only enabled TLP Processing Hints (TPH) if +both the Endpoint and its Root Port advertised TPH support. + +Root Complex Integrated Endpoints (RCiEPs) are directly integrated into a +Root Complex and do not have an associated Root Port, so pcie_enable_tph() +never enabled TPH for RCiEPs. + +PCIe r7.0 doesn't seem to include a way to learn whether a Root Complex +supports TPH, but sec 2.2.7.1.1 says Functions that lack TPH support should +ignore TPH, and maybe the same is true for Root Complexes: + + A Function that does not support the TPH Completer or Routing capability + and receives a transaction with the TH bit [which indicates the presence + of TPH in the TLP header] Set is required to ignore the TH bit and handle + the Request in the same way as Requests of the same transaction type + without the TH bit Set. + +Allow drivers to enable TPH for any RCiEP with a TPH Requester Capability. + +Fixes: f69767a1ada3 ("PCI: Add TLP Processing Hints (TPH) support") +Signed-off-by: George Abraham P +[bhelgaas: commit log] +Signed-off-by: Bjorn Helgaas +Link: https://patch.msgid.link/20260109052923.1170070-1-george.abraham.p@intel.com +Signed-off-by: Sasha Levin +--- + drivers/pci/tph.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/tph.c b/drivers/pci/tph.c +index ca4f97be75389..e896b39582818 100644 +--- a/drivers/pci/tph.c ++++ b/drivers/pci/tph.c +@@ -407,10 +407,13 @@ int pcie_enable_tph(struct pci_dev *pdev, int mode) + else + pdev->tph_req_type = PCI_TPH_REQ_TPH_ONLY; + +- rp_req_type = get_rp_completer_type(pdev); ++ /* Check if the device is behind a Root Port */ ++ if (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END) { ++ rp_req_type = get_rp_completer_type(pdev); + +- /* Final req_type is the smallest value of two */ +- pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type); ++ /* Final req_type is the smallest value of two */ ++ pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type); ++ } + + if (pdev->tph_req_type == PCI_TPH_REQ_DISABLE) + return -EINVAL; +-- +2.53.0 + diff --git a/queue-7.0/pci-use-generic-driver_override-infrastructure.patch b/queue-7.0/pci-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..7235b8c77a --- /dev/null +++ b/queue-7.0/pci-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,209 @@ +From 14b0ad197a87d732f5f8aff1b15b7e7538ea48bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:09 +0100 +Subject: PCI: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit 10a4206a24013be4d558d476010cbf2eb4c9fa64 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 782a985d7af2 ("PCI: Introduce new device binding path using pci_dev.driver_override") +Acked-by: Bjorn Helgaas +Acked-by: Alex Williamson +Tested-by: Gui-Dong Han +Reviewed-by: Gui-Dong Han +Link: https://patch.msgid.link/20260324005919.2408620-6-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/pci/pci-driver.c | 11 +++++++---- + drivers/pci/pci-sysfs.c | 28 ---------------------------- + drivers/pci/probe.c | 1 - + drivers/vfio/pci/vfio_pci_core.c | 5 ++--- + drivers/xen/xen-pciback/pci_stub.c | 6 ++++-- + include/linux/pci.h | 6 ------ + 6 files changed, 13 insertions(+), 44 deletions(-) + +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index dd9075403987d..d10ece0889f0f 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -138,9 +138,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + { + struct pci_dynid *dynid; + const struct pci_device_id *found_id = NULL, *ids; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (dev->driver_override && strcmp(dev->driver_override, drv->name)) ++ ret = device_match_driver_override(&dev->dev, &drv->driver); ++ if (ret == 0) + return NULL; + + /* Look at the dynamic ids first, before the static ones */ +@@ -164,7 +166,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + * matching. + */ + if (found_id->override_only) { +- if (dev->driver_override) ++ if (ret > 0) + return found_id; + } else { + return found_id; +@@ -172,7 +174,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + } + + /* driver_override will always match, send a dummy id */ +- if (dev->driver_override) ++ if (ret > 0) + return &pci_device_id_any; + return NULL; + } +@@ -452,7 +454,7 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) + static inline bool pci_device_can_probe(struct pci_dev *pdev) + { + return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe || +- pdev->driver_override); ++ device_has_driver_override(&pdev->dev)); + } + #else + static inline bool pci_device_can_probe(struct pci_dev *pdev) +@@ -1722,6 +1724,7 @@ static const struct cpumask *pci_device_irq_get_affinity(struct device *dev, + + const struct bus_type pci_bus_type = { + .name = "pci", ++ .driver_override = true, + .match = pci_bus_match, + .uevent = pci_uevent, + .probe = pci_device_probe, +diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c +index 16eaaf749ba97..a9006cf4e9c85 100644 +--- a/drivers/pci/pci-sysfs.c ++++ b/drivers/pci/pci-sysfs.c +@@ -615,33 +615,6 @@ static ssize_t devspec_show(struct device *dev, + static DEVICE_ATTR_RO(devspec); + #endif + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct pci_dev *pdev = to_pci_dev(dev); +- int ret; +- +- ret = driver_set_override(dev, &pdev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct pci_dev *pdev = to_pci_dev(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", pdev->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *pci_dev_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_resource.attr, +@@ -669,7 +642,6 @@ static struct attribute *pci_dev_attrs[] = { + #ifdef CONFIG_OF + &dev_attr_devspec.attr, + #endif +- &dev_attr_driver_override.attr, + &dev_attr_ari_enabled.attr, + NULL, + }; +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index bccc7a4bdd794..b4707640e1021 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -2488,7 +2488,6 @@ static void pci_release_dev(struct device *dev) + pci_release_of_node(pci_dev); + pcibios_release_device(pci_dev); + pci_bus_put(pci_dev->bus); +- kfree(pci_dev->driver_override); + bitmap_free(pci_dev->dma_alias_mask); + dev_dbg(dev, "device released\n"); + kfree(pci_dev); +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index d43745fe4c843..460852f79f29b 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -1987,9 +1987,8 @@ static int vfio_pci_bus_notifier(struct notifier_block *nb, + pdev->is_virtfn && physfn == vdev->pdev) { + pci_info(vdev->pdev, "Captured SR-IOV VF %s driver_override\n", + pci_name(pdev)); +- pdev->driver_override = kasprintf(GFP_KERNEL, "%s", +- vdev->vdev.ops->name); +- WARN_ON(!pdev->driver_override); ++ WARN_ON(device_set_driver_override(&pdev->dev, ++ vdev->vdev.ops->name)); + } else if (action == BUS_NOTIFY_BOUND_DRIVER && + pdev->is_virtfn && physfn == vdev->pdev) { + struct pci_driver *drv = pci_dev_driver(pdev); +diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c +index e4b27aecbf059..79a2b5dfd6941 100644 +--- a/drivers/xen/xen-pciback/pci_stub.c ++++ b/drivers/xen/xen-pciback/pci_stub.c +@@ -598,6 +598,8 @@ static int pcistub_seize(struct pci_dev *dev, + return err; + } + ++static struct pci_driver xen_pcibk_pci_driver; ++ + /* Called when 'bind'. This means we must _NOT_ call pci_reset_function or + * other functions that take the sysfs lock. */ + static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) +@@ -609,8 +611,8 @@ static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) + + match = pcistub_match(dev); + +- if ((dev->driver_override && +- !strcmp(dev->driver_override, PCISTUB_DRIVER_NAME)) || ++ if (device_match_driver_override(&dev->dev, ++ &xen_pcibk_pci_driver.driver) > 0 || + match) { + + if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 1c270f1d51230..57e9463e4347b 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -575,12 +575,6 @@ struct pci_dev { + u8 supported_speeds; /* Supported Link Speeds Vector */ + phys_addr_t rom; /* Physical address if not from BAR */ + size_t romlen; /* Length if not from BAR */ +- /* +- * Driver name to force a match. Do not set directly, because core +- * frees it. Use driver_set_override() to set or clear it. +- */ +- const char *driver_override; +- + unsigned long priv_flags; /* Private flags for the PCI driver */ + + /* These methods index pci_reset_fn_methods[] */ +-- +2.53.0 + diff --git a/queue-7.0/pcmcia-fix-garbled-log-messages-for-kern_cont.patch b/queue-7.0/pcmcia-fix-garbled-log-messages-for-kern_cont.patch new file mode 100644 index 0000000000..f95671f3ab --- /dev/null +++ b/queue-7.0/pcmcia-fix-garbled-log-messages-for-kern_cont.patch @@ -0,0 +1,55 @@ +From e529ac55ac84ebce013f4274c35a6d9c95818ec7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Nov 2025 17:42:56 +0100 +Subject: PCMCIA: Fix garbled log messages for KERN_CONT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: René Rebe + +[ Upstream commit bfeaa6814bd3f9a1f6d525b3b35a03b9a0368961 ] + +For years the PCMCIA info messages are messed up by superfluous +newlines. While f2e6cf76751d ("pcmcia: Convert dev_printk to +dev_") converted the code to pr_cont(), dev_info enforces a \n +via vprintk_store setting LOG_NEWLINE, breaking subsequent pr_cont. + +Fix by logging the device name manually to allow pr_cont to work for +more readable and not \n distorted logs. + +Fixes: f2e6cf76751d ("pcmcia: Convert dev_printk to dev_") +Signed-off-by: René Rebe +Signed-off-by: Dominik Brodowski +Signed-off-by: Sasha Levin +--- + drivers/pcmcia/rsrc_nonstatic.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c +index 0679dd434719d..b28d754ba414f 100644 +--- a/drivers/pcmcia/rsrc_nonstatic.c ++++ b/drivers/pcmcia/rsrc_nonstatic.c +@@ -187,7 +187,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, + int any; + u_char *b, hole, most; + +- dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1); ++ pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1); + + /* First, what does a floating port look like? */ + b = kzalloc(256, GFP_KERNEL); +@@ -409,8 +409,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num, + struct socket_data *s_data = s->resource_data; + u_long i, j, bad, fail, step; + +- dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:", +- base, base+num-1); ++ pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:", ++ dev_name(&s->dev), base, base+num-1); + bad = fail = 0; + step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + /* don't allow too large steps */ +-- +2.53.0 + diff --git a/queue-7.0/perf-amd-ibs-account-interrupt-for-discarded-samples.patch b/queue-7.0/perf-amd-ibs-account-interrupt-for-discarded-samples.patch new file mode 100644 index 0000000000..4f3ba895aa --- /dev/null +++ b/queue-7.0/perf-amd-ibs-account-interrupt-for-discarded-samples.patch @@ -0,0 +1,62 @@ +From 7f3bafb8d1b77d95ebc8fae9d647d297a7cc03da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:12 +0000 +Subject: perf/amd/ibs: Account interrupt for discarded samples + +From: Ravi Bangoria + +[ Upstream commit 01336b5559785a136de1cac49705f63a70a755bc ] + +Add interrupt throttling accounting for below cases: + + o IBS Op PMU: A software filter (in addition to the hardware filter) + drops samples whose load latency is below the user-specified + threshold. + + o IBS Fetch PMU: Samples discarded due to the zero-RIP erratum (#1197). + +Although these samples are discarded, the NMI cost is still incurred, so +they should be counted for interrupt throttling. + +Fixes: 26db2e0c51fe83e1dd852c1321407835b481806e ("perf/x86/amd/ibs: Work around erratum #1197") +Fixes: d20610c19b4a22bc69085b7eb7a02741d51de30e ("perf/amd/ibs: Add support for OP Load Latency Filtering") +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-2-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index aca89f23d2e00..705ef43325be3 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -1293,8 +1293,10 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) + * within [128, 2048] range. + */ + if (!op_data3.ld_op || !op_data3.dc_miss || +- op_data3.dc_miss_lat <= (event->attr.config1 & 0xFFF)) ++ op_data3.dc_miss_lat <= (event->attr.config1 & 0xFFF)) { ++ throttle = perf_event_account_interrupt(event); + goto out; ++ } + } + + /* +@@ -1326,8 +1328,10 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) + regs.flags &= ~PERF_EFLAGS_EXACT; + } else { + /* Workaround for erratum #1197 */ +- if (perf_ibs->fetch_ignore_if_zero_rip && !(ibs_data.regs[1])) ++ if (perf_ibs->fetch_ignore_if_zero_rip && !(ibs_data.regs[1])) { ++ throttle = perf_event_account_interrupt(event); + goto out; ++ } + + set_linear_ip(®s, ibs_data.regs[1]); + regs.flags |= PERF_EFLAGS_EXACT; +-- +2.53.0 + diff --git a/queue-7.0/perf-amd-ibs-avoid-calling-perf_allow_kernel-from-th.patch b/queue-7.0/perf-amd-ibs-avoid-calling-perf_allow_kernel-from-th.patch new file mode 100644 index 0000000000..0662c0d510 --- /dev/null +++ b/queue-7.0/perf-amd-ibs-avoid-calling-perf_allow_kernel-from-th.patch @@ -0,0 +1,62 @@ +From 876f75132d387aec0e12b15449834f98e9f64945 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:15 +0000 +Subject: perf/amd/ibs: Avoid calling perf_allow_kernel() from the IBS NMI + handler + +From: Ravi Bangoria + +[ Upstream commit b0a09142622a994c4f4088c3f61db5da87cfc711 ] + +Calling perf_allow_kernel() from the NMI context is unsafe and could be +fatal. Capture the permission at event-initialization time by storing it +in event->hw.flags, and have the NMI handler rely on that cached flag +instead of making the call directly. + +Fixes: 50a53b60e141d ("perf/amd/ibs: Prevent leaking sensitive data to userspace") +Reported-by: Sadasivan Shaiju +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-5-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 5 ++++- + arch/x86/events/perf_event_flags.h | 1 + + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index ddd74eff3faef..7b8eea1d75c10 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -313,6 +313,9 @@ static int perf_ibs_init(struct perf_event *event) + if (ret) + return ret; + ++ if (perf_allow_kernel()) ++ hwc->flags |= PERF_X86_EVENT_UNPRIVILEGED; ++ + if (hwc->sample_period) { + if (config & perf_ibs->cnt_mask) + /* raw max_cnt may not be set */ +@@ -1346,7 +1349,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) + * unprivileged users. + */ + if ((event->attr.sample_type & PERF_SAMPLE_RAW) && +- perf_allow_kernel()) { ++ (hwc->flags & PERF_X86_EVENT_UNPRIVILEGED)) { + perf_ibs_phyaddr_clear(perf_ibs, &ibs_data); + } + +diff --git a/arch/x86/events/perf_event_flags.h b/arch/x86/events/perf_event_flags.h +index 70078334e4a33..47f84ee8f5409 100644 +--- a/arch/x86/events/perf_event_flags.h ++++ b/arch/x86/events/perf_event_flags.h +@@ -23,3 +23,4 @@ PERF_ARCH(PEBS_LAT_HYBRID, 0x0020000) /* ld and st lat for hybrid */ + PERF_ARCH(NEEDS_BRANCH_STACK, 0x0040000) /* require branch stack setup */ + PERF_ARCH(BRANCH_COUNTERS, 0x0080000) /* logs the counters in the extra space of each branch */ + PERF_ARCH(ACR, 0x0100000) /* Auto counter reload */ ++PERF_ARCH(UNPRIVILEGED, 0x0200000) /* Unprivileged event (wrt perf_allow_kernel()) */ +-- +2.53.0 + diff --git a/queue-7.0/perf-amd-ibs-preserve-phyaddrval-bit-when-clearing-p.patch b/queue-7.0/perf-amd-ibs-preserve-phyaddrval-bit-when-clearing-p.patch new file mode 100644 index 0000000000..783bfb7c86 --- /dev/null +++ b/queue-7.0/perf-amd-ibs-preserve-phyaddrval-bit-when-clearing-p.patch @@ -0,0 +1,53 @@ +From efb564320b14771f2566e94844303b1895870bfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 04:22:14 +0000 +Subject: perf/amd/ibs: Preserve PhyAddrVal bit when clearing PhyAddr MSR + +From: Ravi Bangoria + +[ Upstream commit 723a290326e015b07931eabc603d3735999377be ] + +Commit 50a53b60e141 ("perf/amd/ibs: Prevent leaking sensitive data to +userspace") zeroed the physical address and also cleared the PhyAddrVal +flag before copying the value into a perf sample to avoid exposing +physical addresses to unprivileged users. + +Clearing PhyAddrVal, however, has an unintended side-effect: several +other IBS fields are considered valid only when this bit is set. As a +result, those otherwise correct fields are discarded, reducing IBS +functionality. + +Continue to zero the physical address, but keep the PhyAddrVal bit +intact so the related fields remain usable while still preventing any +address leak. + +Fixes: 50a53b60e141 ("perf/amd/ibs: Prevent leaking sensitive data to userspace") +Signed-off-by: Ravi Bangoria +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Namhyung Kim +Link: https://patch.msgid.link/20260216042216.1440-4-ravi.bangoria@amd.com +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/ibs.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c +index 705ef43325be3..ddd74eff3faef 100644 +--- a/arch/x86/events/amd/ibs.c ++++ b/arch/x86/events/amd/ibs.c +@@ -1214,12 +1214,10 @@ static void perf_ibs_phyaddr_clear(struct perf_ibs *perf_ibs, + struct perf_ibs_data *ibs_data) + { + if (perf_ibs == &perf_ibs_op) { +- ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSOPDATA3)] &= ~(1ULL << 18); + ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSDCPHYSAD)] = 0; + return; + } + +- ibs_data->regs[ibs_fetch_msr_idx(MSR_AMD64_IBSFETCHCTL)] &= ~(1ULL << 52); + ibs_data->regs[ibs_fetch_msr_idx(MSR_AMD64_IBSFETCHPHYSAD)] = 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/perf-branch-avoid-incrementing-null.patch b/queue-7.0/perf-branch-avoid-incrementing-null.patch new file mode 100644 index 0000000000..62f5e13806 --- /dev/null +++ b/queue-7.0/perf-branch-avoid-incrementing-null.patch @@ -0,0 +1,39 @@ +From 8f9f0f9e380d993d738339c6380dac0d5812d868 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:31:31 -0700 +Subject: perf branch: Avoid incrementing NULL + +From: Ian Rogers + +[ Upstream commit c969a9d7bbf46f983c4a48566b3b2f7340b02296 ] + +If the entry is NULL the value is meaningless so early return NULL to +avoid an increment of NULL. This was happening in calls from +has_stitched_lbr when running the "perf record LBR tests". The return +value isn't used in that case, so returning NULL as no effect. + +Fixes: 42bbabed09ce ("perf tools: Add hw_idx in struct branch_stack") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/branch.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h +index 7429530fa7749..a1d4736497c40 100644 +--- a/tools/perf/util/branch.h ++++ b/tools/perf/util/branch.h +@@ -66,6 +66,9 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl + { + u64 *entry = (u64 *)sample->branch_stack; + ++ if (entry == NULL) ++ return NULL; ++ + entry++; + if (sample->no_hw_idx) + return (struct branch_entry *)entry; +-- +2.53.0 + diff --git a/queue-7.0/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch b/queue-7.0/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch new file mode 100644 index 0000000000..d8c4f9937f --- /dev/null +++ b/queue-7.0/perf-cgroup-update-metric-leader-in-evlist__expand_c.patch @@ -0,0 +1,94 @@ +From 6275dde9b2bbf0701c1ce44041bc0abf41a7a0ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 23:05:52 -0700 +Subject: perf cgroup: Update metric leader in evlist__expand_cgroup + +From: Ian Rogers + +[ Upstream commit c9ef786c0970991578397043f1c819229e2b7197 ] + +When the evlist is expanded the metric leader wasn't being updated. As +the original evsel is deleted this creates a use-after-free in +stat-shadow's prepare_metric. This was detected running the "perf stat +--bpf-counters --for-each-cgroup test" with sanitizers. + +The change itself puts the copied evsel into the priv field (known +unused because of evsel__clone use) and then in a second pass over the +list updates the copied values using the priv pointer. + +Fixes: d1c5a0e86a4e ("perf stat: Add --for-each-cgroup option") +Signed-off-by: Ian Rogers +Acked-by: Sun Jian +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/cgroup.c | 30 +++++++++++++++++++++++------- + 1 file changed, 23 insertions(+), 7 deletions(-) + +diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c +index 040eb75f08048..1b5664d1481f5 100644 +--- a/tools/perf/util/cgroup.c ++++ b/tools/perf/util/cgroup.c +@@ -417,7 +417,6 @@ static bool has_pattern_string(const char *str) + int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgroup) + { + struct evlist *orig_list, *tmp_list; +- struct evsel *pos, *evsel, *leader; + struct rblist orig_metric_events; + struct cgroup *cgrp = NULL; + struct cgroup_name *cn; +@@ -452,6 +451,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro + goto out_err; + + list_for_each_entry(cn, &cgroup_list, list) { ++ struct evsel *pos; + char *name; + + if (!cn->used) +@@ -467,21 +467,37 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro + if (cgrp == NULL) + continue; + +- leader = NULL; ++ /* copy the list and set to the new cgroup. */ + evlist__for_each_entry(orig_list, pos) { +- evsel = evsel__clone(/*dest=*/NULL, pos); ++ struct evsel *evsel = evsel__clone(/*dest=*/NULL, pos); ++ + if (evsel == NULL) + goto out_err; + ++ /* stash the copy during the copying. */ ++ pos->priv = evsel; + cgroup__put(evsel->cgrp); + evsel->cgrp = cgroup__get(cgrp); + +- if (evsel__is_group_leader(pos)) +- leader = evsel; +- evsel__set_leader(evsel, leader); +- + evlist__add(tmp_list, evsel); + } ++ /* update leader information using stashed pointer to copy. */ ++ evlist__for_each_entry(orig_list, pos) { ++ struct evsel *evsel = pos->priv; ++ ++ if (evsel__leader(pos)) ++ evsel__set_leader(evsel, evsel__leader(pos)->priv); ++ ++ if (pos->metric_leader) ++ evsel->metric_leader = pos->metric_leader->priv; ++ ++ if (pos->first_wildcard_match) ++ evsel->first_wildcard_match = pos->first_wildcard_match->priv; ++ } ++ /* the stashed copy is no longer used. */ ++ evlist__for_each_entry(orig_list, pos) ++ pos->priv = NULL; ++ + /* cgroup__new() has a refcount, release it here */ + cgroup__put(cgrp); + nr_cgroups++; +-- +2.53.0 + diff --git a/queue-7.0/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch b/queue-7.0/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch new file mode 100644 index 0000000000..a57dd0cc30 --- /dev/null +++ b/queue-7.0/perf-expr-return-einval-for-syntax-error-in-expr__fi.patch @@ -0,0 +1,57 @@ +From 7faeaa5f074b3c25b7003af74304dcf11d17ab52 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 17:04:47 +0100 +Subject: perf expr: Return -EINVAL for syntax error in expr__find_ids() + +From: Leo Yan + +[ Upstream commit 3a61fd866ef9aaa1d3158b460f852b74a2df07f4 ] + +expr__find_ids() propagates the parser return value directly. For syntax +errors, the parser can return a positive value, but callers treat it as +success, e.g., for below case on Arm64 platform: + + metric expr 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) for backend_bound + parsing metric: 100 * (STALL_SLOT_BACKEND / (CPU_CYCLES * #slots) - BR_MIS_PRED * 3 / CPU_CYCLES) + Failure to read '#slots' literal: #slots = nan + syntax error + +Convert positive parser returns in expr__find_ids() to -EINVAL, as a +result, the error value will be respected by callers. + +Before: + + perf stat -C 5 + Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Failure to read '#slots'Segmentation fault + +After: + + perf stat -C 5 + Failure to read '#slots'Cannot find metric or group `Default' + +Fixes: ded80bda8bc9 ("perf expr: Migrate expr ids table to a hashmap") +Signed-off-by: Leo Yan +Reviewed-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/expr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index 465fe2e9bbbef..b7664cb68554b 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -376,7 +376,8 @@ int expr__find_ids(const char *expr, const char *one, + if (one) + expr__del_id(ctx, one); + +- return ret; ++ /* A positive value means syntax error, convert to -EINVAL */ ++ return ret > 0 ? -EINVAL : ret; + } + + double expr_id_data__value(const struct expr_id_data *data) +-- +2.53.0 + diff --git a/queue-7.0/perf-lock-fix-option-value-type-in-parse_max_stack.patch b/queue-7.0/perf-lock-fix-option-value-type-in-parse_max_stack.patch new file mode 100644 index 0000000000..b849ca54fc --- /dev/null +++ b/queue-7.0/perf-lock-fix-option-value-type-in-parse_max_stack.patch @@ -0,0 +1,38 @@ +From b35f70c16562d219edc4aaecfd9e5ea4ac30ea1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 16:33:48 -0700 +Subject: perf lock: Fix option value type in parse_max_stack + +From: Ian Rogers + +[ Upstream commit cfaade34b52aa1ec553044255702c4b31b57c005 ] + +The value is a void* and the address of an int, max_stack_depth, is +set up in the perf lock options. The parse_max_stack function treats +the int* as a long*, make this more correct by declaring the value to +be an int*. + +Fixes: 0a277b622670 ("perf lock contention: Check --max-stack option") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-lock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c +index e8962c985d34a..5585aeb97684d 100644 +--- a/tools/perf/builtin-lock.c ++++ b/tools/perf/builtin-lock.c +@@ -2250,7 +2250,7 @@ static int parse_map_entry(const struct option *opt, const char *str, + static int parse_max_stack(const struct option *opt, const char *str, + int unset __maybe_unused) + { +- unsigned long *len = (unsigned long *)opt->value; ++ int *len = opt->value; + long val; + char *endptr; + +-- +2.53.0 + diff --git a/queue-7.0/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch b/queue-7.0/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch new file mode 100644 index 0000000000..78bf942ea7 --- /dev/null +++ b/queue-7.0/perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch @@ -0,0 +1,47 @@ +From cdc1c23b8b9ea175e21ea8cc3632d8918645148f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 19:08:38 -0700 +Subject: perf maps: Fix copy_from that can break sorted by name order + +From: Ian Rogers + +[ Upstream commit f552b132e4d5248715828e7e5c2bf7889bf05b2e ] + +When an parent is copied into a child the name array is populated in +address not name order. Make sure the name array isn't flagged as sorted. + +Fixes: 659ad3492b91 ("perf maps: Switch from rbtree to lazily sorted array for addresses") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/maps.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c +index c8b8081b7b31a..75b399a20b262 100644 +--- a/tools/perf/util/maps.c ++++ b/tools/perf/util/maps.c +@@ -1082,16 +1082,9 @@ int maps__copy_from(struct maps *dest, struct maps *parent) + map__put(new); + } + maps__set_maps_by_address_sorted(dest, maps__maps_by_address_sorted(parent)); +- if (!err) { +- RC_CHK_ACCESS(dest)->last_search_by_name_idx = +- RC_CHK_ACCESS(parent)->last_search_by_name_idx; +- maps__set_maps_by_name_sorted(dest, +- dest_maps_by_name && +- maps__maps_by_name_sorted(parent)); +- } else { +- RC_CHK_ACCESS(dest)->last_search_by_name_idx = 0; +- maps__set_maps_by_name_sorted(dest, false); +- } ++ RC_CHK_ACCESS(dest)->last_search_by_name_idx = 0; ++ /* Values were copied into the name array in address order. */ ++ maps__set_maps_by_name_sorted(dest, false); + } else { + /* Unexpected copying to a maps containing entries. */ + for (unsigned int i = 0; !err && i < n; i++) { +-- +2.53.0 + diff --git a/queue-7.0/perf-maps-fix-fixup_overlap_and_insert-that-can-brea.patch b/queue-7.0/perf-maps-fix-fixup_overlap_and_insert-that-can-brea.patch new file mode 100644 index 0000000000..1d68ebae9f --- /dev/null +++ b/queue-7.0/perf-maps-fix-fixup_overlap_and_insert-that-can-brea.patch @@ -0,0 +1,45 @@ +From 601708332fb2f5e7257d60485c81829b9aa11523 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 19:08:37 -0700 +Subject: perf maps: Fix fixup_overlap_and_insert that can break sorted by name + order + +From: Ian Rogers + +[ Upstream commit c4f3ff3289380437d26177e8f2fe4b7507816ee3 ] + +When an entry in the address array is replaced, the corresponding name +entry is replaced. The entries names may sort differently and so it is +important that the sorted by name property be cleared on the maps. + +Fixes: 0d11fab32714 ("perf maps: Fixup maps_by_name when modifying maps_by_address") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/maps.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c +index 4092211cff62b..c8b8081b7b31a 100644 +--- a/tools/perf/util/maps.c ++++ b/tools/perf/util/maps.c +@@ -956,6 +956,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) + if (maps_by_name) { + map__put(maps_by_name[ni]); + maps_by_name[ni] = map__get(new); ++ maps__set_maps_by_name_sorted(maps, false); + } + + err = __maps__insert_sorted(maps, i + 1, after, NULL); +@@ -982,6 +983,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new) + if (maps_by_name) { + map__put(maps_by_name[ni]); + maps_by_name[ni] = map__get(new); ++ maps__set_maps_by_name_sorted(maps, false); + } + + check_invariants(maps); +-- +2.53.0 + diff --git a/queue-7.0/perf-metrics-make-common-stalled-metrics-conditional.patch b/queue-7.0/perf-metrics-make-common-stalled-metrics-conditional.patch new file mode 100644 index 0000000000..3cec651133 --- /dev/null +++ b/queue-7.0/perf-metrics-make-common-stalled-metrics-conditional.patch @@ -0,0 +1,215 @@ +From 17edbadcca0b258ed15d0b8f745fbc89fdf8e736 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:01:03 -0700 +Subject: perf metrics: Make common stalled metrics conditional on having the + event + +From: Ian Rogers + +[ Upstream commit 210259987d9a7bb8506f3e93c2ddbece15c13b15 ] + +The metric code uses the event parsing code but it generally assumes +all events are supported. Arnaldo reported AMD supporting +stalled-cycles-frontend but not stalled-cycles-backend [1]. An issue +with this is that before parsing happens the metric code tries to +share events within groups to reduce the number of events and +multiplexing. If the group has some supported and not supported +events, the whole group will become broken. To avoid this situation +add has_event tests to the metrics for stalled-cycles-frontend and +stalled-cycles-backend. has_events is evaluated when parsing the +metric and its result constant propagated (with if-elses) to reduce +the number of events. This means when the metric code considers +sharing the events, only supported events will be shared. + +Note for backporting. This change updates +tools/perf/pmu-events/empty-pmu-events.c a convenience file for builds +on systems without python present. While the metrics.json code should +backport easily there can be conflicts on empty-pmu-events.c. In this +case the build will have left a file test-empty-pmu-events.c that can +be copied over empty-pmu-events.c to resolve issues and make an +appropriate empty-pmu-events.c for the json in the source tree at the +time of the build. + +[1] https://lore.kernel.org/lkml/abm1nR-2xjOUBroD@x1/ + +Reported-by: Arnaldo Carvalho de Melo +Closes: https://lore.kernel.org/lkml/abm1nR-2xjOUBroD@x1/ +Fixes: c7adeb0974f1 ("perf jevents: Add set of common metrics based on default ones") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + .../arch/common/common/metrics.json | 6 +- + tools/perf/pmu-events/empty-pmu-events.c | 108 +++++++++--------- + 2 files changed, 57 insertions(+), 57 deletions(-) + +diff --git a/tools/perf/pmu-events/arch/common/common/metrics.json b/tools/perf/pmu-events/arch/common/common/metrics.json +index 0d010b3ebc6d6..cefc8bfe78302 100644 +--- a/tools/perf/pmu-events/arch/common/common/metrics.json ++++ b/tools/perf/pmu-events/arch/common/common/metrics.json +@@ -46,14 +46,14 @@ + }, + { + "BriefDescription": "Max front or backend stalls per instruction", +- "MetricExpr": "max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions", ++ "MetricExpr": "(max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions) if (has_event(stalled\\-cycles\\-frontend) & has_event(stalled\\-cycles\\-backend)) else ((stalled\\-cycles\\-frontend / instructions) if has_event(stalled\\-cycles\\-frontend) else ((stalled\\-cycles\\-backend / instructions) if has_event(stalled\\-cycles\\-backend) else 0))", + "MetricGroup": "Default", + "MetricName": "stalled_cycles_per_instruction", + "DefaultShowEvents": "1" + }, + { + "BriefDescription": "Frontend stalls per cycle", +- "MetricExpr": "stalled\\-cycles\\-frontend / cpu\\-cycles", ++ "MetricExpr": "(stalled\\-cycles\\-frontend / cpu\\-cycles) if has_event(stalled\\-cycles\\-frontend) else 0", + "MetricGroup": "Default", + "MetricName": "frontend_cycles_idle", + "MetricThreshold": "frontend_cycles_idle > 0.1", +@@ -61,7 +61,7 @@ + }, + { + "BriefDescription": "Backend stalls per cycle", +- "MetricExpr": "stalled\\-cycles\\-backend / cpu\\-cycles", ++ "MetricExpr": "(stalled\\-cycles\\-backend / cpu\\-cycles) if has_event(stalled\\-cycles\\-backend) else 0", + "MetricGroup": "Default", + "MetricName": "backend_cycles_idle", + "MetricThreshold": "backend_cycles_idle > 0.2", +diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c +index 76c395cf513cb..a92dd0424f790 100644 +--- a/tools/perf/pmu-events/empty-pmu-events.c ++++ b/tools/perf/pmu-events/empty-pmu-events.c +@@ -1310,33 +1310,33 @@ static const char *const big_c_string = + /* offset=128375 */ "migrations_per_second\000Default\000software@cpu\\-migrations\\,name\\=cpu\\-migrations@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Process migrations to a new CPU per CPU second\000\0001migrations/sec\000\000\000\000011" + /* offset=128635 */ "page_faults_per_second\000Default\000software@page\\-faults\\,name\\=page\\-faults@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Page faults per CPU second\000\0001faults/sec\000\000\000\000011" + /* offset=128866 */ "insn_per_cycle\000Default\000instructions / cpu\\-cycles\000insn_per_cycle < 1\000Instructions Per Cycle\000\0001instructions\000\000\000\000001" +-/* offset=128979 */ "stalled_cycles_per_instruction\000Default\000max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001" +-/* offset=129143 */ "frontend_cycles_idle\000Default\000stalled\\-cycles\\-frontend / cpu\\-cycles\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001" +-/* offset=129273 */ "backend_cycles_idle\000Default\000stalled\\-cycles\\-backend / cpu\\-cycles\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001" +-/* offset=129399 */ "cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011" +-/* offset=129575 */ "branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011" +-/* offset=129755 */ "branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001" +-/* offset=129859 */ "l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D miss rate\000\000100%\000\000\000\000001" +-/* offset=129975 */ "llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001" +-/* offset=130076 */ "l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001" +-/* offset=130191 */ "dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001" +-/* offset=130297 */ "itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001" +-/* offset=130403 */ "l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001" +-/* offset=130551 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000" +-/* offset=130574 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000" +-/* offset=130638 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000" +-/* offset=130805 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000" +-/* offset=130870 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000" +-/* offset=130938 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000" +-/* offset=131010 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000" +-/* offset=131105 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000" +-/* offset=131240 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000" +-/* offset=131305 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000" +-/* offset=131374 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000" +-/* offset=131445 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\000000" +-/* offset=131468 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\000000" +-/* offset=131491 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\000000" +-/* offset=131512 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000" ++/* offset=128979 */ "stalled_cycles_per_instruction\000Default\000(max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions if has_event(stalled\\-cycles\\-frontend) & has_event(stalled\\-cycles\\-backend) else (stalled\\-cycles\\-frontend / instructions if has_event(stalled\\-cycles\\-frontend) else (stalled\\-cycles\\-backend / instructions if has_event(stalled\\-cycles\\-backend) else 0)))\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001" ++/* offset=129404 */ "frontend_cycles_idle\000Default\000(stalled\\-cycles\\-frontend / cpu\\-cycles if has_event(stalled\\-cycles\\-frontend) else 0)\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001" ++/* offset=129583 */ "backend_cycles_idle\000Default\000(stalled\\-cycles\\-backend / cpu\\-cycles if has_event(stalled\\-cycles\\-backend) else 0)\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001" ++/* offset=129757 */ "cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011" ++/* offset=129933 */ "branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011" ++/* offset=130113 */ "branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001" ++/* offset=130217 */ "l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D miss rate\000\000100%\000\000\000\000001" ++/* offset=130333 */ "llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001" ++/* offset=130434 */ "l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001" ++/* offset=130549 */ "dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001" ++/* offset=130655 */ "itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001" ++/* offset=130761 */ "l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001" ++/* offset=130909 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000" ++/* offset=130932 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000" ++/* offset=130996 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000" ++/* offset=131163 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000" ++/* offset=131228 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000" ++/* offset=131296 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000" ++/* offset=131368 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000" ++/* offset=131463 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000" ++/* offset=131598 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000" ++/* offset=131663 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000" ++/* offset=131732 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000" ++/* offset=131803 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\000000" ++/* offset=131826 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\000000" ++/* offset=131849 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\000000" ++/* offset=131870 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000" + ; + + static const struct compact_pmu_event pmu_events__common_default_core[] = { +@@ -2626,22 +2626,22 @@ static const struct pmu_table_entry pmu_events__common[] = { + + static const struct compact_pmu_event pmu_metrics__common_default_core[] = { + { 127956 }, /* CPUs_utilized\000Default\000(software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@) / (duration_time * 1e9)\000\000Average CPU utilization\000\0001CPUs\000\000\000\000011 */ +-{ 129273 }, /* backend_cycles_idle\000Default\000stalled\\-cycles\\-backend / cpu\\-cycles\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001 */ +-{ 129575 }, /* branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011 */ +-{ 129755 }, /* branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001 */ ++{ 129583 }, /* backend_cycles_idle\000Default\000(stalled\\-cycles\\-backend / cpu\\-cycles if has_event(stalled\\-cycles\\-backend) else 0)\000backend_cycles_idle > 0.2\000Backend stalls per cycle\000\000\000\000\000\000001 */ ++{ 129933 }, /* branch_frequency\000Default\000branches / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Branches per CPU second\000\0001000M/sec\000\000\000\000011 */ ++{ 130113 }, /* branch_miss_rate\000Default\000branch\\-misses / branches\000branch_miss_rate > 0.05\000Branch miss rate\000\000100%\000\000\000\000001 */ + { 128142 }, /* cs_per_second\000Default\000software@context\\-switches\\,name\\=context\\-switches@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Context switches per CPU second\000\0001cs/sec\000\000\000\000011 */ +-{ 129399 }, /* cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011 */ +-{ 130191 }, /* dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001 */ +-{ 129143 }, /* frontend_cycles_idle\000Default\000stalled\\-cycles\\-frontend / cpu\\-cycles\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001 */ ++{ 129757 }, /* cycles_frequency\000Default\000cpu\\-cycles / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Cycles per CPU second\000\0001GHz\000\000\000\000011 */ ++{ 130549 }, /* dtlb_miss_rate\000Default3\000dTLB\\-load\\-misses / dTLB\\-loads\000dtlb_miss_rate > 0.05\000dTLB miss rate\000\000100%\000\000\000\000001 */ ++{ 129404 }, /* frontend_cycles_idle\000Default\000(stalled\\-cycles\\-frontend / cpu\\-cycles if has_event(stalled\\-cycles\\-frontend) else 0)\000frontend_cycles_idle > 0.1\000Frontend stalls per cycle\000\000\000\000\000\000001 */ + { 128866 }, /* insn_per_cycle\000Default\000instructions / cpu\\-cycles\000insn_per_cycle < 1\000Instructions Per Cycle\000\0001instructions\000\000\000\000001 */ +-{ 130297 }, /* itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001 */ +-{ 130403 }, /* l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001 */ +-{ 129859 }, /* l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D miss rate\000\000100%\000\000\000\000001 */ +-{ 130076 }, /* l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001 */ +-{ 129975 }, /* llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001 */ ++{ 130655 }, /* itlb_miss_rate\000Default3\000iTLB\\-load\\-misses / iTLB\\-loads\000itlb_miss_rate > 0.05\000iTLB miss rate\000\000100%\000\000\000\000001 */ ++{ 130761 }, /* l1_prefetch_miss_rate\000Default4\000L1\\-dcache\\-prefetch\\-misses / L1\\-dcache\\-prefetches\000l1_prefetch_miss_rate > 0.05\000L1 prefetch miss rate\000\000100%\000\000\000\000001 */ ++{ 130217 }, /* l1d_miss_rate\000Default2\000L1\\-dcache\\-load\\-misses / L1\\-dcache\\-loads\000l1d_miss_rate > 0.05\000L1D miss rate\000\000100%\000\000\000\000001 */ ++{ 130434 }, /* l1i_miss_rate\000Default3\000L1\\-icache\\-load\\-misses / L1\\-icache\\-loads\000l1i_miss_rate > 0.05\000L1I miss rate\000\000100%\000\000\000\000001 */ ++{ 130333 }, /* llc_miss_rate\000Default2\000LLC\\-load\\-misses / LLC\\-loads\000llc_miss_rate > 0.05\000LLC miss rate\000\000100%\000\000\000\000001 */ + { 128375 }, /* migrations_per_second\000Default\000software@cpu\\-migrations\\,name\\=cpu\\-migrations@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Process migrations to a new CPU per CPU second\000\0001migrations/sec\000\000\000\000011 */ + { 128635 }, /* page_faults_per_second\000Default\000software@page\\-faults\\,name\\=page\\-faults@ * 1e9 / (software@cpu\\-clock\\,name\\=cpu\\-clock@ if #target_cpu else software@task\\-clock\\,name\\=task\\-clock@)\000\000Page faults per CPU second\000\0001faults/sec\000\000\000\000011 */ +-{ 128979 }, /* stalled_cycles_per_instruction\000Default\000max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001 */ ++{ 128979 }, /* stalled_cycles_per_instruction\000Default\000(max(stalled\\-cycles\\-frontend, stalled\\-cycles\\-backend) / instructions if has_event(stalled\\-cycles\\-frontend) & has_event(stalled\\-cycles\\-backend) else (stalled\\-cycles\\-frontend / instructions if has_event(stalled\\-cycles\\-frontend) else (stalled\\-cycles\\-backend / instructions if has_event(stalled\\-cycles\\-backend) else 0)))\000\000Max front or backend stalls per instruction\000\000\000\000\000\000001 */ + + }; + +@@ -2714,21 +2714,21 @@ static const struct pmu_table_entry pmu_events__test_soc_cpu[] = { + }; + + static const struct compact_pmu_event pmu_metrics__test_soc_cpu_default_core[] = { +-{ 130551 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000 */ +-{ 131240 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000 */ +-{ 131010 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000 */ +-{ 131105 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000 */ +-{ 131305 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000 */ +-{ 131374 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000 */ +-{ 130638 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000 */ +-{ 130574 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000 */ +-{ 131512 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000 */ +-{ 131445 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\000000 */ +-{ 131468 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\000000 */ +-{ 131491 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\000000 */ +-{ 130938 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000 */ +-{ 130805 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000 */ +-{ 130870 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000 */ ++{ 130909 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\000000 */ ++{ 131598 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\000000 */ ++{ 131368 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\000000 */ ++{ 131463 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\000000 */ ++{ 131663 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\000000 */ ++{ 131732 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\000000 */ ++{ 130996 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\000000 */ ++{ 130932 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\000000 */ ++{ 131870 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\000000 */ ++{ 131803 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\000000 */ ++{ 131826 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\000000 */ ++{ 131849 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\000000 */ ++{ 131296 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\000000 */ ++{ 131163 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000 */ ++{ 131228 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\000000 */ + + }; + +-- +2.53.0 + diff --git a/queue-7.0/perf-stat-fix-crash-on-arm64.patch b/queue-7.0/perf-stat-fix-crash-on-arm64.patch new file mode 100644 index 0000000000..dabc7f704c --- /dev/null +++ b/queue-7.0/perf-stat-fix-crash-on-arm64.patch @@ -0,0 +1,96 @@ +From a119493b07ee8d79e038fde072982a9099690c19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 03:24:30 -0700 +Subject: perf stat: Fix crash on arm64 + +From: Breno Leitao + +[ Upstream commit b5708a308a5602d4a3caf0720dce452082d443ec ] + +Perf stat is crashing on arm64 hosts with the following issue: + + # make -C tools/perf DEBUG=1 + # perf stat sleep 1 + perf: util/evsel.c:2034: get_group_fd: Assertion `!(!leader->core.fd)' failed. + [1] 1220794 IOT instruction (core dumped) ./perf stat + +The sorting function introduced by commit a745c0831c15c ("perf stat: +Sort default events/metrics") compares events based on their individual +properties. This can cause events from different groups to be +interleaved, resulting in group members appearing before their leaders +in the sorted evlist. + +When the iterator opens events in list order, a group member may be +processed before its leader has been opened. + +For example, CPU_CYCLES (idx=32) with leader STALL_SLOT_BACKEND (idx=37) +could be sorted before its leader, causing the crash when CPU_CYCLES +tries to get its group fd from the not-yet-opened leader. + +Fix this by comparing events based on their leader's attributes instead +of their own attributes when the events are in different groups. This +ensures all members of a group share the same sort key as their leader, +keeping groups together and guaranteeing leaders are opened before their +members. + +Fixes: a745c0831c15c ("perf stat: Sort default events/metrics") +Reported-by: Denis Yaroshevskiy +Tested-by: Dmitry Ilvokhin +Tested-by: Ian Rogers +Signed-off-by: Breno Leitao +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-stat.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index 2eb76d7476b7f..6a12c1068d8a0 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -1917,25 +1917,33 @@ static int default_evlist_evsel_cmp(void *priv __maybe_unused, + const struct evsel *lhs = container_of(lhs_core, struct evsel, core); + const struct perf_evsel *rhs_core = container_of(r, struct perf_evsel, node); + const struct evsel *rhs = container_of(rhs_core, struct evsel, core); ++ const struct evsel *lhs_leader = evsel__leader(lhs); ++ const struct evsel *rhs_leader = evsel__leader(rhs); + +- if (evsel__leader(lhs) == evsel__leader(rhs)) { ++ if (lhs_leader == rhs_leader) { + /* Within the same group, respect the original order. */ + return lhs_core->idx - rhs_core->idx; + } + ++ /* ++ * Compare using leader's attributes so that all members of a group ++ * stay together. This ensures leaders are opened before their members. ++ */ ++ + /* Sort default metrics evsels first, and default show events before those. */ +- if (lhs->default_metricgroup != rhs->default_metricgroup) +- return lhs->default_metricgroup ? -1 : 1; ++ if (lhs_leader->default_metricgroup != rhs_leader->default_metricgroup) ++ return lhs_leader->default_metricgroup ? -1 : 1; + +- if (lhs->default_show_events != rhs->default_show_events) +- return lhs->default_show_events ? -1 : 1; ++ if (lhs_leader->default_show_events != rhs_leader->default_show_events) ++ return lhs_leader->default_show_events ? -1 : 1; + + /* Sort by PMU type (prefers legacy types first). */ +- if (lhs->pmu != rhs->pmu) +- return lhs->pmu->type - rhs->pmu->type; ++ if (lhs_leader->pmu != rhs_leader->pmu) ++ return lhs_leader->pmu->type - rhs_leader->pmu->type; + +- /* Sort by name. */ +- return strcmp(evsel__name((struct evsel *)lhs), evsel__name((struct evsel *)rhs)); ++ /* Sort by leader's name. */ ++ return strcmp(evsel__name((struct evsel *)lhs_leader), ++ evsel__name((struct evsel *)rhs_leader)); + } + + /* +-- +2.53.0 + diff --git a/queue-7.0/perf-stat-fix-opt-value-type-for-parse_cache_level.patch b/queue-7.0/perf-stat-fix-opt-value-type-for-parse_cache_level.patch new file mode 100644 index 0000000000..7d50efd24c --- /dev/null +++ b/queue-7.0/perf-stat-fix-opt-value-type-for-parse_cache_level.patch @@ -0,0 +1,120 @@ +From 1232a5b389f9d1e294ed23dd1b8f210846672ec2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 16:33:49 -0700 +Subject: perf stat: Fix opt->value type for parse_cache_level + +From: Ian Rogers + +[ Upstream commit 44311ae84ad9177fb311aee856027861c22f17b2 ] + +Commit f5803651b4a4 ("perf stat: Choose the most disaggregate command +line option") changed aggregation option handling for `perf stat` but +not `perf stat report` leading to parse_cache_level being passed a +struct in the `perf stat` case but erroneously an aggr_mode enum value +for `perf stat report`. Change the `perf stat report` aggregation +handling to use the same opt_aggr_mode as `perf stat`. Also, just pass +the boolean for consistency with other boolean argument handling. + +Fixes: f5803651b4a4 ("perf stat: Choose the most disaggregate command line option") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-stat.c | 43 +++++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 20 deletions(-) + +diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c +index 73c2ba7e30760..2eb76d7476b7f 100644 +--- a/tools/perf/builtin-stat.c ++++ b/tools/perf/builtin-stat.c +@@ -164,7 +164,7 @@ struct opt_aggr_mode { + }; + + /* Turn command line option into most generic aggregation mode setting. */ +-static enum aggr_mode opt_aggr_mode_to_aggr_mode(struct opt_aggr_mode *opt_mode) ++static enum aggr_mode opt_aggr_mode_to_aggr_mode(const struct opt_aggr_mode *opt_mode) + { + enum aggr_mode mode = AGGR_GLOBAL; + +@@ -1219,8 +1219,8 @@ static int parse_cache_level(const struct option *opt, + int unset __maybe_unused) + { + int level; +- struct opt_aggr_mode *opt_aggr_mode = (struct opt_aggr_mode *)opt->value; +- u32 *aggr_level = (u32 *)opt->data; ++ bool *per_cache = opt->value; ++ u32 *aggr_level = opt->data; + + /* + * If no string is specified, aggregate based on the topology of +@@ -1258,7 +1258,7 @@ static int parse_cache_level(const struct option *opt, + return -EINVAL; + } + out: +- opt_aggr_mode->cache = true; ++ *per_cache = true; + *aggr_level = level; + return 0; + } +@@ -2305,24 +2305,23 @@ static struct perf_stat perf_stat = { + static int __cmd_report(int argc, const char **argv) + { + struct perf_session *session; ++ struct opt_aggr_mode opt_mode = {}; + const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", "input file name"), +- OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode, +- "aggregate counts per processor socket", AGGR_SOCKET), +- OPT_SET_UINT(0, "per-die", &perf_stat.aggr_mode, +- "aggregate counts per processor die", AGGR_DIE), +- OPT_SET_UINT(0, "per-cluster", &perf_stat.aggr_mode, +- "aggregate counts perf processor cluster", AGGR_CLUSTER), +- OPT_CALLBACK_OPTARG(0, "per-cache", &perf_stat.aggr_mode, &perf_stat.aggr_level, +- "cache level", +- "aggregate count at this cache level (Default: LLC)", ++ OPT_BOOLEAN(0, "per-thread", &opt_mode.thread, "aggregate counts per thread"), ++ OPT_BOOLEAN(0, "per-socket", &opt_mode.socket, ++ "aggregate counts per processor socket"), ++ OPT_BOOLEAN(0, "per-die", &opt_mode.die, "aggregate counts per processor die"), ++ OPT_BOOLEAN(0, "per-cluster", &opt_mode.cluster, ++ "aggregate counts per processor cluster"), ++ OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode.cache, &perf_stat.aggr_level, ++ "cache level", "aggregate count at this cache level (Default: LLC)", + parse_cache_level), +- OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode, +- "aggregate counts per physical processor core", AGGR_CORE), +- OPT_SET_UINT(0, "per-node", &perf_stat.aggr_mode, +- "aggregate counts per numa node", AGGR_NODE), +- OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode, +- "disable CPU count aggregation", AGGR_NONE), ++ OPT_BOOLEAN(0, "per-core", &opt_mode.core, ++ "aggregate counts per physical processor core"), ++ OPT_BOOLEAN(0, "per-node", &opt_mode.node, "aggregate counts per numa node"), ++ OPT_BOOLEAN('A', "no-aggr", &opt_mode.no_aggr, ++ "disable aggregation across CPUs or PMUs"), + OPT_END() + }; + struct stat st; +@@ -2330,6 +2329,10 @@ static int __cmd_report(int argc, const char **argv) + + argc = parse_options(argc, argv, options, stat_report_usage, 0); + ++ perf_stat.aggr_mode = opt_aggr_mode_to_aggr_mode(&opt_mode); ++ if (perf_stat.aggr_mode == AGGR_GLOBAL) ++ perf_stat.aggr_mode = AGGR_UNSET; /* No option found so leave unset. */ ++ + if (!input_name || !strlen(input_name)) { + if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) + input_name = "-"; +@@ -2506,7 +2509,7 @@ int cmd_stat(int argc, const char **argv) + OPT_BOOLEAN(0, "per-die", &opt_mode.die, "aggregate counts per processor die"), + OPT_BOOLEAN(0, "per-cluster", &opt_mode.cluster, + "aggregate counts per processor cluster"), +- OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode, &stat_config.aggr_level, ++ OPT_CALLBACK_OPTARG(0, "per-cache", &opt_mode.cache, &stat_config.aggr_level, + "cache level", "aggregate count at this cache level (Default: LLC)", + parse_cache_level), + OPT_BOOLEAN(0, "per-core", &opt_mode.core, +-- +2.53.0 + diff --git a/queue-7.0/perf-test-fix-ratio_to_prev-event-parsing-test.patch b/queue-7.0/perf-test-fix-ratio_to_prev-event-parsing-test.patch new file mode 100644 index 0000000000..c0cbdd3baa --- /dev/null +++ b/queue-7.0/perf-test-fix-ratio_to_prev-event-parsing-test.patch @@ -0,0 +1,94 @@ +From bcfc6ed704288546f705c91877e97febc2878ff8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 20:59:27 -0500 +Subject: perf test: Fix ratio_to_prev event parsing test + +From: Thomas Falcon + +[ Upstream commit 77cb9b443b7fff2a93d78cd2e309db030046772f ] + +test__ratio_to_prev() assumed the first event in a group is the leader, +which is not the case when the event is expanded into two event groups +on hybrid PMU's with auto counter reload support. Instead, iterate over the +event group generated for each core PMU. Also update "wrong leader" test to +check that the subordinate event has the correct leader instead of checking +that it is not the group leader. Finally, do not exit immediately if a PMU +without auto counter reload support is found. + +Signed-off-by: Thomas Falcon +Reviewed-by: Dapeng Mi +Reviewed-by: Ian Rogers +Fixes: 56be0fe5f62c ("perf record: Add auto counter reload parse and regression tests") +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/tests/parse-events.c | 49 +++++++++++++++++++-------------- + 1 file changed, 28 insertions(+), 21 deletions(-) + +diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c +index 1d3cc224fbc27..05c3e899b4251 100644 +--- a/tools/perf/tests/parse-events.c ++++ b/tools/perf/tests/parse-events.c +@@ -1796,31 +1796,38 @@ static bool test__acr_valid(void) + + static int test__ratio_to_prev(struct evlist *evlist) + { +- struct evsel *evsel; ++ struct evsel *evsel, *leader; + + TEST_ASSERT_VAL("wrong number of entries", 2 * perf_pmus__num_core_pmus() == evlist->core.nr_entries); + +- evlist__for_each_entry(evlist, evsel) { +- if (!perf_pmu__has_format(evsel->pmu, "acr_mask")) +- return TEST_OK; +- +- if (evsel == evlist__first(evlist)) { +- TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); +- TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); +- TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); +- TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); +- TEST_ASSERT_EVSEL("unexpected event", +- evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), +- evsel); +- } else { +- TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); +- TEST_ASSERT_VAL("wrong leader", !evsel__is_group_leader(evsel)); +- TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 0); +- TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); +- TEST_ASSERT_EVSEL("unexpected event", +- evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), +- evsel); ++ evlist__for_each_entry(evlist, evsel) { ++ if (evsel != evsel__leader(evsel) || ++ !perf_pmu__has_format(evsel->pmu, "acr_mask")) { ++ continue; + } ++ leader = evsel; ++ /* cycles */ ++ TEST_ASSERT_VAL("wrong config2", 0 == leader->core.attr.config2); ++ TEST_ASSERT_VAL("wrong core.nr_members", leader->core.nr_members == 2); ++ TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(leader) == 0); ++ TEST_ASSERT_EVSEL("unexpected event", ++ evsel__match(leader, HARDWARE, HW_CPU_CYCLES), ++ leader); ++ /* ++ * The period value gets configured within evlist__config, ++ * while this test executes only parse events method. ++ */ ++ TEST_ASSERT_VAL("wrong period", 0 == leader->core.attr.sample_period); ++ ++ /* instructions/period=200000,ratio-to-prev=2.0/ */ ++ evsel = evsel__next(evsel); ++ TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); ++ TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); ++ TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 0); ++ TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); ++ TEST_ASSERT_EVSEL("unexpected event", ++ evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), ++ evsel); + /* + * The period value gets configured within evlist__config, + * while this test executes only parse events method. +-- +2.53.0 + diff --git a/queue-7.0/perf-test-skip-perf-data-type-profiling-tests-for-s3.patch b/queue-7.0/perf-test-skip-perf-data-type-profiling-tests-for-s3.patch new file mode 100644 index 0000000000..874800d195 --- /dev/null +++ b/queue-7.0/perf-test-skip-perf-data-type-profiling-tests-for-s3.patch @@ -0,0 +1,61 @@ +From a5c0824c4ca2035502e805d3019d78a80d88ca43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 14:21:01 +0200 +Subject: perf test: Skip perf data type profiling tests for s390 + +From: Thomas Richter + +[ Upstream commit eb27e1c885ea75c1661188a548d100c8bce5970a ] + +Test case 'perf data type profiling tests' fails on s390 with this +error: + + # ./perf mem record -- ./perf test -w code_with_type + failed: no PMU supports the memory events + # echo $? + 255 + # + +because s390 does not support memory events at all. According to the +man page, perf annotate --code-with-type only works with memory +instructions only. As command 'perf mem record ...' is not supported +on s390, skip this test for s390. + +Output before: + # ./perf test 'perf data type profiling tests' + 77: perf data type profiling tests : FAILED! + +Output after: + # ./perf test 'perf data type profiling tests' + 77: perf data type profiling tests : Skip + +Fixes: f60a5c22967b8 ("perf tests: Test annotate with data type profiling and rust") +Signed-off-by: Thomas Richter +Reviewed-by: Ian Rogers +Cc: Dmitrii Dolgov <9erthalion6@gmail.com> +Suggested-by: Namhyung Kim +Suggested-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/tests/shell/data_type_profiling.sh | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tools/perf/tests/shell/data_type_profiling.sh b/tools/perf/tests/shell/data_type_profiling.sh +index fb47b7213b335..eca694600a047 100755 +--- a/tools/perf/tests/shell/data_type_profiling.sh ++++ b/tools/perf/tests/shell/data_type_profiling.sh +@@ -15,6 +15,10 @@ err=0 + perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) + perfout=$(mktemp /tmp/__perf_test.perf.out.XXXXX) + ++# Check for support of perf mem before trap handler ++perf mem record -o /dev/null -- true 2>&1 | \ ++ grep -q "failed: no PMU supports the memory events" && exit 2 ++ + cleanup() { + rm -rf "${perfdata}" "${perfout}" + rm -rf "${perfdata}".old +-- +2.53.0 + diff --git a/queue-7.0/perf-test-type-profiling-remote-typedef-on-struct.patch b/queue-7.0/perf-test-type-profiling-remote-typedef-on-struct.patch new file mode 100644 index 0000000000..7e9c2da677 --- /dev/null +++ b/queue-7.0/perf-test-type-profiling-remote-typedef-on-struct.patch @@ -0,0 +1,60 @@ +From c26dacbc7f67bc5d86d1a633add679324431c2aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:58:21 -0800 +Subject: perf test type profiling: Remote typedef on struct + +From: Ian Rogers + +[ Upstream commit 6910944bf0b92fea63d5a7aeed69e4b9c14fd01b ] + +The typedef creates an issue where the struct or the typedef may +appear in the output and cause the "perf data type profiling tests" to +fail. Let's remove the typedef to keep the test passing. + +Fixes: 335047109d7d ("perf tests: Test annotate with data type profiling and C") +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/tests/shell/data_type_profiling.sh | 2 +- + tools/perf/tests/workloads/datasym.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/tools/perf/tests/shell/data_type_profiling.sh b/tools/perf/tests/shell/data_type_profiling.sh +index 2a7f8f7c42d09..fb47b7213b335 100755 +--- a/tools/perf/tests/shell/data_type_profiling.sh ++++ b/tools/perf/tests/shell/data_type_profiling.sh +@@ -8,7 +8,7 @@ set -e + # data type profiling manifestation + + # Values in testtypes and testprogs should match +-testtypes=("# data-type: struct Buf" "# data-type: struct _buf") ++testtypes=("# data-type: struct Buf" "# data-type: struct buf") + testprogs=("perf test -w code_with_type" "perf test -w datasym") + + err=0 +diff --git a/tools/perf/tests/workloads/datasym.c b/tools/perf/tests/workloads/datasym.c +index 1d0b7d64e1ba1..19242c7255c0c 100644 +--- a/tools/perf/tests/workloads/datasym.c ++++ b/tools/perf/tests/workloads/datasym.c +@@ -4,14 +4,14 @@ + #include + #include "../tests.h" + +-typedef struct _buf { ++struct buf { + char data1; + char reserved[55]; + char data2; +-} buf __attribute__((aligned(64))); ++} __attribute__((aligned(64))); + + /* volatile to try to avoid the compiler seeing reserved as unused. */ +-static volatile buf workload_datasym_buf1 = { ++static volatile struct buf workload_datasym_buf1 = { + /* to have this in the data section */ + .reserved[0] = 1, + }; +-- +2.53.0 + diff --git a/queue-7.0/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch b/queue-7.0/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch new file mode 100644 index 0000000000..2021c7f79c --- /dev/null +++ b/queue-7.0/perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch @@ -0,0 +1,115 @@ +From dd8134130933a2be7f10f862326c72b8c6e371c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 10:36:39 +0000 +Subject: perf: tools: cs-etm: Fix print issue for Coresight debug in ETE/TRBE + trace + +From: Mike Leach + +[ Upstream commit 6c478e7b3eba3f387a2d6c749e3e3ee0f8ad1c53 ] + +Building perf with CORESIGHT=1 and the optional CSTRACE_RAW=1 enables +additional debug printing of raw trace data when using command:- +perf report --dump. + +This raw trace prints the CoreSight formatted trace frames, which may be +used to investigate suspected issues with trace quality / corruption / +decode. + +These frames are not present in ETE + TRBE trace. +This fix removes the unnecessary call to print these frames. + +This fix also rationalises implementation - original code had helper +function that unnecessarily repeated initialisation calls that had +already been made. + +Due to an addtional fault with the OpenCSD library, this call when ETE/TRBE +are being decoded will cause a segfault in perf. This fix also prevents +that problem for perf using older (<= 1.8.0 version) OpenCSD libraries. + +Fixes: 68ffe3902898 ("perf tools: Add decoder mechanic to support dumping trace data") +Reported-by: Leo Yan +Signed-off-by: Mike Leach +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 51 +++++-------------- + 1 file changed, 13 insertions(+), 38 deletions(-) + +diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +index 212f17a3dc72d..310af40751103 100644 +--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c ++++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +@@ -237,46 +237,24 @@ cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, + (void *)decoder, + cs_etm_decoder__print_str_cb); + if (ret != 0) +- ret = -1; +- +- return 0; +-} ++ return -1; + + #ifdef CS_LOG_RAW_FRAMES +-static void +-cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params, +- struct cs_etm_decoder *decoder) +-{ +- /* Only log these during a --dump operation */ +- if (d_params->operation == CS_ETM_OPERATION_PRINT) { +- /* set up a library default logger to process the +- * raw frame printer we add later +- */ +- ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1); +- +- /* no stdout / err / file output */ +- ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL); +- +- /* set the string CB for the default logger, +- * passes strings to perf print logger. +- */ +- ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree, +- (void *)decoder, +- cs_etm_decoder__print_str_cb); +- ++ /* ++ * Only log raw frames if --dump operation and hardware is actually ++ * generating formatted CoreSight trace frames ++ */ ++ if ((d_params->operation == CS_ETM_OPERATION_PRINT) && ++ (d_params->formatted == true)) { + /* use the built in library printer for the raw frames */ +- ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, +- CS_RAW_DEBUG_FLAGS); ++ ret = ocsd_dt_set_raw_frame_printer(decoder->dcd_tree, ++ CS_RAW_DEBUG_FLAGS); ++ if (ret != 0) ++ return -1; + } +-} +-#else +-static void +-cs_etm_decoder__init_raw_frame_logging( +- struct cs_etm_decoder_params *d_params __maybe_unused, +- struct cs_etm_decoder *decoder __maybe_unused) +-{ +-} + #endif ++ return 0; ++} + + static ocsd_datapath_resp_t + cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *etmq, +@@ -738,9 +716,6 @@ cs_etm_decoder__new(int decoders, struct cs_etm_decoder_params *d_params, + if (ret != 0) + goto err_free_decoder; + +- /* init raw frame logging if required */ +- cs_etm_decoder__init_raw_frame_logging(d_params, decoder); +- + for (i = 0; i < decoders; i++) { + ret = cs_etm_decoder__create_etm_decoder(d_params, + &t_params[i], +-- +2.53.0 + diff --git a/queue-7.0/perf-tools-fix-module-symbol-resolution-for-non-zero.patch b/queue-7.0/perf-tools-fix-module-symbol-resolution-for-non-zero.patch new file mode 100644 index 0000000000..1da63cc48c --- /dev/null +++ b/queue-7.0/perf-tools-fix-module-symbol-resolution-for-non-zero.patch @@ -0,0 +1,77 @@ +From 1c3f0b6b1f292cff89d7fbbb3fb5228136100a76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 11:58:04 -0400 +Subject: perf tools: Fix module symbol resolution for non-zero .text sh_addr + +From: Chuck Lever + +[ Upstream commit 9a82bfde4775b7a87cd1a7e791f46f83ae442848 ] + +When perf resolves symbols from kernel module ELF files (ET_REL), +it converts symbol addresses to file offsets so that sample IPs +can be matched to the correct symbol. The conversion adjusts each +symbol's st_value: + + sym->st_value -= shdr->sh_addr - shdr->sh_offset; + +For vmlinux (ET_EXEC), st_value is a virtual address and sh_addr +is the section's virtual base, so subtracting sh_addr and adding +sh_offset correctly yields a file offset. + +For kernel modules (ET_REL), st_value is a section-relative +offset. The module loader ignores sh_addr entirely and places +symbols at module_base + st_value. Converting to file offset +requires only adding sh_offset; subtracting sh_addr introduces an +error equal to sh_addr bytes. + +When .text has sh_addr == 0 -- the historical norm for simple +modules -- both formulas produce the same result and the bug is +latent. As modules gain more metadata sections before .text (.note, +.static_call.text, etc.), the linker assigns .text a non-zero +sh_addr, exposing the defect. For example, nfsd.ko on this kernel +has sh_addr=0xa80, kvm-intel.ko has sh_addr=0x1e90. + +The effect is that all .text symbols in affected modules +shift by sh_addr bytes relative to sample IPs, causing perf +report to attribute samples to incorrect, nearby symbols. This +was observed as 13% of LLC-load-miss samples misattributed +to nfsd_file_get_dio_attrs when the actual hot function was +nfsd_cache_lookup, approximately 0xa80 bytes away in the symbol +table. + +Use the existing dso__rel() flag (already set for ET_REL modules) +to select the correct adjustment: add sh_offset for ET_REL, +subtract (sh_addr - sh_offset) for ET_EXEC/ET_DYN. + +Fixes: 0131c4ec794a ("perf tools: Make it possible to read object code from kernel modules") +Signed-off-by: Chuck Lever +Reviewed-by: Ian Rogers +Tested-by: Thomas Richter +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/symbol-elf.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c +index 76912c62b6a07..968e269d9be1f 100644 +--- a/tools/perf/util/symbol-elf.c ++++ b/tools/perf/util/symbol-elf.c +@@ -1356,8 +1356,12 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, + char dso_name[PATH_MAX]; + + /* Adjust symbol to map to file offset */ +- if (adjust_kernel_syms) +- sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ if (adjust_kernel_syms) { ++ if (dso__rel(dso)) ++ sym->st_value += shdr->sh_offset; ++ else ++ sym->st_value -= shdr->sh_addr - shdr->sh_offset; ++ } + + if (strcmp(section_name, (dso__short_name(curr_dso) + dso__short_name_len(dso))) == 0) + return 0; +-- +2.53.0 + diff --git a/queue-7.0/perf-trace-avoid-an-err_ptr-in-syscall_stats.patch b/queue-7.0/perf-trace-avoid-an-err_ptr-in-syscall_stats.patch new file mode 100644 index 0000000000..f56fbcbbe9 --- /dev/null +++ b/queue-7.0/perf-trace-avoid-an-err_ptr-in-syscall_stats.patch @@ -0,0 +1,78 @@ +From 39c3dcb31f6aa9eac46a2107e99aec206f78ca46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 15:45:15 -0800 +Subject: perf trace: Avoid an ERR_PTR in syscall_stats + +From: Ian Rogers + +[ Upstream commit d05073adda0f047e9b2115a2932bcb2797eab238 ] + +hashmap__new may return an ERR_PTR and previously this would be +assigned to syscall_stats meaning all use of syscall_stats needs to +test for NULL (uninitialized) or an ERR_PTR. Given the only reason +hashmap__new can fail is ENOMEM, just use NULL to indicate the +allocation failure and avoid the code having to test for NULL and +IS_ERR. + +Fixes: 96f202eab813 (perf trace: Fix IS_ERR() vs NULL check bug) +Signed-off-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-trace.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c +index 295b272c6c299..7ff85fa90d988 100644 +--- a/tools/perf/builtin-trace.c ++++ b/tools/perf/builtin-trace.c +@@ -1565,7 +1565,9 @@ static bool syscall_id_equal(long key1, long key2, void *ctx __maybe_unused) + + static struct hashmap *alloc_syscall_stats(void) + { +- return hashmap__new(syscall_id_hash, syscall_id_equal, NULL); ++ struct hashmap *result = hashmap__new(syscall_id_hash, syscall_id_equal, NULL); ++ ++ return IS_ERR(result) ? NULL : result; + } + + static void delete_syscall_stats(struct hashmap *syscall_stats) +@@ -1573,7 +1575,7 @@ static void delete_syscall_stats(struct hashmap *syscall_stats) + struct hashmap_entry *pos; + size_t bkt; + +- if (IS_ERR(syscall_stats)) ++ if (!syscall_stats) + return; + + hashmap__for_each_entry(syscall_stats, pos, bkt) +@@ -1589,7 +1591,7 @@ static struct thread_trace *thread_trace__new(struct trace *trace) + ttrace->files.max = -1; + if (trace->summary) { + ttrace->syscall_stats = alloc_syscall_stats(); +- if (IS_ERR(ttrace->syscall_stats)) ++ if (!ttrace->syscall_stats) + zfree(&ttrace); + } + } +@@ -4464,7 +4466,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) + + if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) { + trace->syscall_stats = alloc_syscall_stats(); +- if (IS_ERR(trace->syscall_stats)) ++ if (!trace->syscall_stats) + goto out_delete_evlist; + } + +@@ -4771,7 +4773,7 @@ static int trace__replay(struct trace *trace) + + if (trace->summary_mode == SUMMARY__BY_TOTAL) { + trace->syscall_stats = alloc_syscall_stats(); +- if (IS_ERR(trace->syscall_stats)) ++ if (!trace->syscall_stats) + goto out; + } + +-- +2.53.0 + diff --git a/queue-7.0/perf-trace-fix-is_err-vs-null-check-bug.patch b/queue-7.0/perf-trace-fix-is_err-vs-null-check-bug.patch new file mode 100644 index 0000000000..233d89217f --- /dev/null +++ b/queue-7.0/perf-trace-fix-is_err-vs-null-check-bug.patch @@ -0,0 +1,41 @@ +From 6a82ecce868b9cf21a41c90498a08bfee522ca80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 20:22:08 +0800 +Subject: perf trace: Fix IS_ERR() vs NULL check bug + +From: wangguangju + +[ Upstream commit 96f202eab8133f94479b14a32902c636e9bdf6af ] + +The alloc_syscall_stats() function always returns an error pointer +(ERR_PTR) on failure. + +So replace NULL check with IS_ERR() check after calling +delete_syscall_stats() function. + +Fixes: ef2da619b132c6f74 ("perf trace: Convert syscall_stats to hashmap") +Signed-off-by: wangguangju +Reviewed-by: Howard Chu +Acked-by: Ian Rogers +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/builtin-trace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c +index 311d9da9896a4..295b272c6c299 100644 +--- a/tools/perf/builtin-trace.c ++++ b/tools/perf/builtin-trace.c +@@ -1573,7 +1573,7 @@ static void delete_syscall_stats(struct hashmap *syscall_stats) + struct hashmap_entry *pos; + size_t bkt; + +- if (syscall_stats == NULL) ++ if (IS_ERR(syscall_stats)) + return; + + hashmap__for_each_entry(syscall_stats, pos, bkt) +-- +2.53.0 + diff --git a/queue-7.0/perf-util-kill-die-prototype-dead-for-a-long-time.patch b/queue-7.0/perf-util-kill-die-prototype-dead-for-a-long-time.patch new file mode 100644 index 0000000000..4b31efc090 --- /dev/null +++ b/queue-7.0/perf-util-kill-die-prototype-dead-for-a-long-time.patch @@ -0,0 +1,39 @@ +From 33cc252ab2d7b984875a8ada222af2f9205ba07e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 14:31:57 -0300 +Subject: perf util: Kill die() prototype, dead for a long time + +From: Arnaldo Carvalho de Melo + +[ Upstream commit e5cce1b9c82fbd48e2f1f7a25a9fad8ee228176f ] + +In fef2a735167a827a ("perf tools: Kill die()") the die() function was +removed, but not the prototype in util.h, now when building with +LIBPERL=1, during a 'make -C tools/perf build-test' routine test, it is +failing as perl likes die() calls and then this clashes with this +remnant, remove it. + +Fixes: fef2a735167a827a ("perf tools: Kill die()") +Reviewed-by: Ian Rogers +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/perf/util/util.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h +index 394dbfa944ac7..e935438451b81 100644 +--- a/tools/perf/util/util.h ++++ b/tools/perf/util/util.h +@@ -30,7 +30,6 @@ extern bool perf_guest; + + /* General helper functions */ + void usage(const char *err) __noreturn; +-void die(const char *err, ...) __noreturn __printf(1, 2); + + struct dirent; + struct strlist; +-- +2.53.0 + diff --git a/queue-7.0/phy-apple-apple-use-local-variable-for-ioremap-retur.patch b/queue-7.0/phy-apple-apple-use-local-variable-for-ioremap-retur.patch new file mode 100644 index 0000000000..a747aad4ef --- /dev/null +++ b/queue-7.0/phy-apple-apple-use-local-variable-for-ioremap-retur.patch @@ -0,0 +1,55 @@ +From 499515f60c2cb7ca4754c639d6436e8b92c4a87d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Feb 2026 09:02:51 +0100 +Subject: phy: apple: apple: Use local variable for ioremap return value + +From: Janne Grunau + +[ Upstream commit 290a35756aaef85bbe0527eaf451f533a61b5f6c ] + +The indirection through the resources array is unnecessarily complicated +and resuling in using IS_ERR() and PTR_ERR() on a valid address. A local +variable for the devm_ioremap_resource() return value is both easier to +read and matches expectations when reading code. + +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/asahi/aYXvX1bYOXtYCgfC@stanley.mountain/ +Suggested-by: Vladimir Oltean +Fixes: 8e98ca1e74db ("phy: apple: Add Apple Type-C PHY") +Signed-off-by: Janne Grunau +Reviewed-by: Sven Peter +Reviewed-by: Vladimir Oltean +Link: https://patch.msgid.link/20260215-phy-apple-resource-err-ptr-v2-1-e43c22453682@jannau.net +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/phy/apple/atc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/phy/apple/atc.c b/drivers/phy/apple/atc.c +index dc867f368b687..64d0c3dba1cbb 100644 +--- a/drivers/phy/apple/atc.c ++++ b/drivers/phy/apple/atc.c +@@ -2202,14 +2202,16 @@ static int atcphy_map_resources(struct platform_device *pdev, struct apple_atcph + { "pipehandler", &atcphy->regs.pipehandler, NULL }, + }; + struct resource *res; ++ void __iomem *addr; + + for (int i = 0; i < ARRAY_SIZE(resources); i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, resources[i].name); +- *resources[i].addr = devm_ioremap_resource(&pdev->dev, res); +- if (IS_ERR(resources[i].addr)) +- return dev_err_probe(atcphy->dev, PTR_ERR(resources[i].addr), ++ addr = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(addr)) ++ return dev_err_probe(atcphy->dev, PTR_ERR(addr), + "Unable to map %s regs", resources[i].name); + ++ *resources[i].addr = addr; + if (resources[i].res) + *resources[i].res = res; + } +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-abx500-fix-type-of-argument-variable.patch b/queue-7.0/pinctrl-abx500-fix-type-of-argument-variable.patch new file mode 100644 index 0000000000..18175444c6 --- /dev/null +++ b/queue-7.0/pinctrl-abx500-fix-type-of-argument-variable.patch @@ -0,0 +1,38 @@ +From 0a2ffa671f6cdac21357a3cd5e5464313c67d489 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 23:15:06 +0800 +Subject: pinctrl: abx500: Fix type of 'argument' variable + +From: Yu-Chun Lin + +[ Upstream commit 34006f77890d050e6d80cbee365b5d703c1140b4 ] + +The argument variable is assigned the return value of +pinconf_to_config_argument(), which returns a u32. Change its type from +enum pin_config_param to unsigned int to correctly store the configuration +argument. + +Fixes: 03b054e9696c ("pinctrl: Pass all configs to driver on pin_config_set()") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/nomadik/pinctrl-abx500.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c +index fc7ebeda8440e..858fbaebcf8e5 100644 +--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c ++++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c +@@ -852,7 +852,7 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev, + int ret = -EINVAL; + int i; + enum pin_config_param param; +- enum pin_config_param argument; ++ unsigned int argument; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch b/queue-7.0/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch new file mode 100644 index 0000000000..76b6080515 --- /dev/null +++ b/queue-7.0/pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch @@ -0,0 +1,39 @@ +From 1e82cad19f31e0fa4a2e900e1e5fe9cb6674d778 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 17:43:35 +0100 +Subject: pinctrl: cy8c95x0: Avoid returning positive values to user space + +From: Andy Shevchenko + +[ Upstream commit 5ad32c3607cf241a1a2680cabd64cbcd757227aa ] + +When probe fails due to unclear interrupt status register, it returns +a positive number instead of the proper error code. Fix this accordingly. + +Fixes: e6cbbe42944d ("pinctrl: Add Cypress cy8c95x0 support") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202602271847.vVWkqLBD-lkp@intel.com/ +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index 14d927035bc0f..54b117f32f0ea 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1320,7 +1320,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); + if (ret) +- return dev_err_probe(dev, ret, "failed to clear irq status register\n"); ++ return dev_err_probe(dev, -EBUSY, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-cy8c95x0-remove-duplicate-error-message.patch b/queue-7.0/pinctrl-cy8c95x0-remove-duplicate-error-message.patch new file mode 100644 index 0000000000..017ab4651d --- /dev/null +++ b/queue-7.0/pinctrl-cy8c95x0-remove-duplicate-error-message.patch @@ -0,0 +1,73 @@ +From 7de66feca8be251aa287b9fa01841e5b79b65cc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:53 +0100 +Subject: pinctrl: cy8c95x0: remove duplicate error message + +From: Andy Shevchenko + +[ Upstream commit 970dacb3b9f0fedbbbcfd7dbf1f4f22340b3f359 ] + +The pin control core is covered to report any error via message. +The devm_request_threaded_irq() already prints an error message. +Remove the duplicates. + +While at it, drop the info message as the same information about +an IRQ in use can be retrieved differently. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 21 +++++---------------- + 1 file changed, 5 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index 5c055d344ac9d..c0f1d964f8397 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1310,6 +1310,7 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + { + struct gpio_irq_chip *girq = &chip->gpio_chip.irq; + DECLARE_BITMAP(pending_irqs, MAX_LINE); ++ struct device *dev = chip->dev; + int ret; + + mutex_init(&chip->irq_lock); +@@ -1336,17 +1337,9 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + girq->handler = handle_simple_irq; + girq->threaded = true; + +- ret = devm_request_threaded_irq(chip->dev, irq, +- NULL, cy8c95x0_irq_handler, +- IRQF_ONESHOT | IRQF_SHARED, +- dev_name(chip->dev), chip); +- if (ret) { +- dev_err(chip->dev, "failed to request irq %d\n", irq); +- return ret; +- } +- dev_info(chip->dev, "Registered threaded IRQ\n"); +- +- return 0; ++ return devm_request_threaded_irq(dev, irq, NULL, cy8c95x0_irq_handler, ++ IRQF_ONESHOT | IRQF_SHARED, ++ dev_name(chip->dev), chip); + } + + static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) +@@ -1362,11 +1355,7 @@ static int cy8c95x0_setup_pinctrl(struct cy8c95x0_pinctrl *chip) + pd->owner = THIS_MODULE; + + chip->pctldev = devm_pinctrl_register(chip->dev, pd, chip); +- if (IS_ERR(chip->pctldev)) +- return dev_err_probe(chip->dev, PTR_ERR(chip->pctldev), +- "can't register controller\n"); +- +- return 0; ++ return PTR_ERR_OR_ZERO(chip->pctldev); + } + + static int cy8c95x0_detect(struct i2c_client *client, +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch b/queue-7.0/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch new file mode 100644 index 0000000000..5e5082d8f6 --- /dev/null +++ b/queue-7.0/pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch @@ -0,0 +1,40 @@ +From 7872382afa9aad72bde93d570db26bcdc81eee45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 19:06:54 +0100 +Subject: pinctrl: cy8c95x0: Unify messages with help of dev_err_probe() + +From: Andy Shevchenko + +[ Upstream commit 014884732095b982412d13d3220c3fe8483b9b3e ] + +Unify error messages that might appear during probe phase by +switching to use dev_err_probe(). + +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Stable-dep-of: 5ad32c3607cf ("pinctrl: cy8c95x0: Avoid returning positive values to user space") +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-cy8c95x0.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c +index c0f1d964f8397..14d927035bc0f 100644 +--- a/drivers/pinctrl/pinctrl-cy8c95x0.c ++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c +@@ -1319,10 +1319,8 @@ static int cy8c95x0_irq_setup(struct cy8c95x0_pinctrl *chip, int irq) + + /* Read IRQ status register to clear all pending interrupts */ + ret = cy8c95x0_irq_pending(chip, pending_irqs); +- if (ret) { +- dev_err(chip->dev, "failed to clear irq status register\n"); +- return ret; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to clear irq status register\n"); + + /* Mask all interrupts */ + bitmap_fill(chip->irq_mask, MAX_LINE); +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-microchip-mssio-fix-missing-return-in-probe.patch b/queue-7.0/pinctrl-microchip-mssio-fix-missing-return-in-probe.patch new file mode 100644 index 0000000000..e69a6099d6 --- /dev/null +++ b/queue-7.0/pinctrl-microchip-mssio-fix-missing-return-in-probe.patch @@ -0,0 +1,37 @@ +From dd099f804a7e4d4ac86a2156a675d3010b345532 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 02:13:17 +0800 +Subject: pinctrl: microchip-mssio: Fix missing return in probe + +From: Felix Gu + +[ Upstream commit 8f72335002db29fb593f8c2c25761feb3b947eb3 ] + +In mpfs_pinctrl_probe(), when pctrl->regmap fails, it just print out an +error message without return, which could lead serious errors. + +Fixes: 488d704ed7b7 ("pinctrl: add polarfire soc mssio pinctrl driver") +Signed-off-by: Felix Gu +Reviewed-by: Conor Dooley +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c b/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c +index 3d5ffd6cb14b6..15d73ea1028cf 100644 +--- a/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c ++++ b/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c +@@ -686,7 +686,7 @@ static int mpfs_pinctrl_probe(struct platform_device *pdev) + + pctrl->regmap = device_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(pctrl->regmap)) +- dev_err_probe(dev, PTR_ERR(pctrl->regmap), "Failed to find syscon regmap\n"); ++ return dev_err_probe(dev, PTR_ERR(pctrl->regmap), "Failed to find syscon regmap\n"); + + pctrl->sysreg_regmap = syscon_regmap_lookup_by_compatible("microchip,mpfs-sysreg-scb"); + if (IS_ERR(pctrl->sysreg_regmap)) +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-pinconf-generic-fully-validate-pinmux-proper.patch b/queue-7.0/pinctrl-pinconf-generic-fully-validate-pinmux-proper.patch new file mode 100644 index 0000000000..082dce34c3 --- /dev/null +++ b/queue-7.0/pinctrl-pinconf-generic-fully-validate-pinmux-proper.patch @@ -0,0 +1,49 @@ +From 20b4f369ff418dbfb0f36d871ce742503ae3b3a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 11:36:11 +0100 +Subject: pinctrl: pinconf-generic: Fully validate 'pinmux' property + +From: Andy Shevchenko + +[ Upstream commit c98324ea7849b6e5baa1774f71709b375a2c2f9e ] + +The pinconf_generic_parse_dt_pinmux() assumes that the 'pinmux' property +is not empty when present. This might be not true. With that, the allocator +will give a special value in return and not NULL which lead to the crash +when trying to access that (invalid) memory. Fix that by fully validating +'pinmux' value, including its length. + +Fixes: 7112c05fff83 ("pinctrl: pinconf-generic: Add API for pinmux propertity in DTS file") +Signed-off-by: Andy Shevchenko +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinconf-generic.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c +index 2b030bd0e6adc..6b4a794a362c0 100644 +--- a/drivers/pinctrl/pinconf-generic.c ++++ b/drivers/pinctrl/pinconf-generic.c +@@ -287,12 +287,17 @@ int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, + return -ENOENT; + } + ++ npins_t = prop->length / sizeof(u32); ++ if (npins_t == 0) { ++ dev_info(dev, "pinmux property doesn't have entries\n"); ++ return -ENODATA; ++ } ++ + if (!pid || !pmux || !npins) { + dev_err(dev, "parameters error\n"); + return -EINVAL; + } + +- npins_t = prop->length / sizeof(u32); + pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL); + pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL); + if (!pid_t || !pmux_t) { +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-pinctrl-pic32-fix-resource-leak.patch b/queue-7.0/pinctrl-pinctrl-pic32-fix-resource-leak.patch new file mode 100644 index 0000000000..74b69c523e --- /dev/null +++ b/queue-7.0/pinctrl-pinctrl-pic32-fix-resource-leak.patch @@ -0,0 +1,72 @@ +From 041587e8af06661e73fd681c60fa525197d49697 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 15:56:23 -0600 +Subject: pinctrl: pinctrl-pic32: Fix resource leak + +From: Ethan Tidmore + +[ Upstream commit fe5560688f3ba98364c7de7b4f8dc240ffd1ff75 ] + +Fix three possible resource leaks by using the devres version of +clk_prepare_enable(). Also, update error message accordingly. + +Detected by Smatch: +drivers/pinctrl/pinctrl-pic32.c:2211 pic32_pinctrl_probe() warn: +'pctl->clk' from clk_prepare_enable() not released on lines: 2208. + +drivers/pinctrl/pinctrl-pic32.c:2274 pic32_gpio_probe() warn: +'bank->clk' from clk_prepare_enable() not released on lines: 2264,2272. + +Fixes: 2ba384e6c3810 ("pinctrl: pinctrl-pic32: Add PIC32 pin control driver") +Signed-off-by: Ethan Tidmore +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/pinctrl-pic32.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c +index 16bbbcf720628..f61ab89bc0f7b 100644 +--- a/drivers/pinctrl/pinctrl-pic32.c ++++ b/drivers/pinctrl/pinctrl-pic32.c +@@ -2174,16 +2174,10 @@ static int pic32_pinctrl_probe(struct platform_device *pdev) + if (IS_ERR(pctl->reg_base)) + return PTR_ERR(pctl->reg_base); + +- pctl->clk = devm_clk_get(&pdev->dev, NULL); ++ pctl->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(pctl->clk)) { + ret = PTR_ERR(pctl->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(pctl->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +@@ -2239,16 +2233,10 @@ static int pic32_gpio_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- bank->clk = devm_clk_get(&pdev->dev, NULL); ++ bank->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(bank->clk)) { + ret = PTR_ERR(bank->clk); +- dev_err(&pdev->dev, "clk get failed\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(bank->clk); +- if (ret) { +- dev_err(&pdev->dev, "clk enable failed\n"); ++ dev_err(&pdev->dev, "Failed to get and enable clock\n"); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-realtek-fix-function-signature-for-config-ar.patch b/queue-7.0/pinctrl-realtek-fix-function-signature-for-config-ar.patch new file mode 100644 index 0000000000..0ea9029526 --- /dev/null +++ b/queue-7.0/pinctrl-realtek-fix-function-signature-for-config-ar.patch @@ -0,0 +1,37 @@ +From b1566da051180536f2e7e75ec3e0702100038f8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 19:54:03 +0800 +Subject: pinctrl: realtek: Fix function signature for config argument + +From: Yu-Chun Lin + +[ Upstream commit 1f5451844786ed203605528dca9e5d84ed378160 ] + +The argument originates from pinconf_to_config_argument(), which returns a +u32. Therefore, the arg parameter should be an unsigned int instead of enum +pin_config_param. + +Fixes: e99ce78030db ("pinctrl: realtek: Add common pinctrl driver for Realtek DHC RTD SoCs") +Signed-off-by: Yu-Chun Lin +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/realtek/pinctrl-rtd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/realtek/pinctrl-rtd.c b/drivers/pinctrl/realtek/pinctrl-rtd.c +index 2440604863327..4c876d1f6ad59 100644 +--- a/drivers/pinctrl/realtek/pinctrl-rtd.c ++++ b/drivers/pinctrl/realtek/pinctrl-rtd.c +@@ -279,7 +279,7 @@ static const struct rtd_pin_sconfig_desc *rtd_pinctrl_find_sconfig(struct rtd_pi + static int rtd_pconf_parse_conf(struct rtd_pinctrl *data, + unsigned int pinnr, + enum pin_config_param param, +- enum pin_config_param arg) ++ unsigned int arg) + { + const struct rtd_pin_config_desc *config_desc; + const struct rtd_pin_sconfig_desc *sconfig_desc; +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch b/queue-7.0/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch new file mode 100644 index 0000000000..1beafc7ba3 --- /dev/null +++ b/queue-7.0/pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch @@ -0,0 +1,47 @@ +From 5a64f1b3f00cb22a359e62a150dd54cb445e5316 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 16:24:51 +0000 +Subject: pinctrl: renesas: rzg2l: Fix save/restore of {IOLH,IEN,PUPD,SMT} + registers + +From: Biju Das + +[ Upstream commit d9a60e367919752a1d398ebeba667f1e200fae1e ] + +The rzg2l_pinctrl_pm_setup_regs() handles save/restore of +{IOLH,IEN,PUPD,SMT} registers during s2ram, but only for ports where all +pins share the same pincfg. Extend the code to also support ports with +variable pincfg per pin, so that {IOLH,IEN,PUPD,SMT} registers are +correctly saved and restored for all pins. + +Fixes: 254203f9a94c ("pinctrl: renesas: rzg2l: Add suspend/resume support") +Signed-off-by: Biju Das +Reviewed-by: Geert Uytterhoeven +Link: https://patch.msgid.link/20260326162459.101414-1-biju.das.jz@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/renesas/pinctrl-rzg2l.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +index 863e779dda028..55e35f63343c7 100644 +--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c ++++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +@@ -3012,6 +3012,13 @@ static void rzg2l_pinctrl_pm_setup_regs(struct rzg2l_pinctrl *pctrl, bool suspen + off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg); + pincnt = hweight8(FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg)); + ++ if (cfg & RZG2L_VARIABLE_CFG) { ++ unsigned int pin = port * RZG2L_PINS_PER_PORT; ++ ++ for (unsigned int i = 0; i < RZG2L_PINS_PER_PORT; i++) ++ cfg |= *(u64 *)pctrl->desc.pins[pin + i].drv_data; ++ } ++ + caps = FIELD_GET(PIN_CFG_MASK, cfg); + has_iolh = !!(caps & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)); + has_ien = !!(caps & PIN_CFG_IEN); +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-sophgo-pinctrl-sg2042-fix-wrong-module-descr.patch b/queue-7.0/pinctrl-sophgo-pinctrl-sg2042-fix-wrong-module-descr.patch new file mode 100644 index 0000000000..7c4768511f --- /dev/null +++ b/queue-7.0/pinctrl-sophgo-pinctrl-sg2042-fix-wrong-module-descr.patch @@ -0,0 +1,35 @@ +From 7401fcd4e00a698942ea19717e934ed6b11958f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:35:49 +0800 +Subject: pinctrl: sophgo: pinctrl-sg2042: Fix wrong module description + +From: Inochi Amaoto + +[ Upstream commit ca1c2ddff00480c213903a1479b56203536e92de ] + +Fix the SoC model in module description string, it should be +sg2042 instead of sg2002. + +Fixes: 1e67465d3b74 ("pinctrl: sophgo: add support for SG2042 SoC") +Signed-off-by: Inochi Amaoto +Reviewed-by: Chen Wang +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/sophgo/pinctrl-sg2042.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2042.c b/drivers/pinctrl/sophgo/pinctrl-sg2042.c +index 185305ac897d9..8dba12e122a45 100644 +--- a/drivers/pinctrl/sophgo/pinctrl-sg2042.c ++++ b/drivers/pinctrl/sophgo/pinctrl-sg2042.c +@@ -651,5 +651,5 @@ static struct platform_driver sg2042_pinctrl_driver = { + }; + module_platform_driver(sg2042_pinctrl_driver); + +-MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC"); ++MODULE_DESCRIPTION("Pinctrl driver for the SG2042 series SoC"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-7.0/pinctrl-sophgo-pinctrl-sg2044-fix-wrong-module-descr.patch b/queue-7.0/pinctrl-sophgo-pinctrl-sg2044-fix-wrong-module-descr.patch new file mode 100644 index 0000000000..b808033901 --- /dev/null +++ b/queue-7.0/pinctrl-sophgo-pinctrl-sg2044-fix-wrong-module-descr.patch @@ -0,0 +1,35 @@ +From 91ce9ee3f687de1ae812fd545e5dfc2a1b25c22a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 08:35:50 +0800 +Subject: pinctrl: sophgo: pinctrl-sg2044: Fix wrong module description + +From: Inochi Amaoto + +[ Upstream commit 7648112358a4207916d3e38bfee49f85552fe95f ] + +Fix the SoC model in module description string, it should be +sg2044 instead of sg2002. + +Fixes: 614a54cb5ac3 ("pinctrl: sophgo: add support for SG2044 SoC") +Signed-off-by: Inochi Amaoto +Reviewed-by: Chen Wang +Signed-off-by: Linus Walleij +Signed-off-by: Sasha Levin +--- + drivers/pinctrl/sophgo/pinctrl-sg2044.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/sophgo/pinctrl-sg2044.c b/drivers/pinctrl/sophgo/pinctrl-sg2044.c +index b0c46d8954ca1..cf0b674c038f0 100644 +--- a/drivers/pinctrl/sophgo/pinctrl-sg2044.c ++++ b/drivers/pinctrl/sophgo/pinctrl-sg2044.c +@@ -714,5 +714,5 @@ static struct platform_driver sg2044_pinctrl_driver = { + }; + module_platform_driver(sg2044_pinctrl_driver); + +-MODULE_DESCRIPTION("Pinctrl driver for the SG2002 series SoC"); ++MODULE_DESCRIPTION("Pinctrl driver for the SG2044 series SoC"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-7.0/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch b/queue-7.0/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch new file mode 100644 index 0000000000..865f2b614e --- /dev/null +++ b/queue-7.0/platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch @@ -0,0 +1,49 @@ +From 4344fb6cd54de34a10044a66a8e1d449222929f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 20:47:03 +0100 +Subject: platform/chrome: chromeos_tbmc: Drop wakeup source on remove + +From: Rafael J. Wysocki + +[ Upstream commit 5d441a4bc93642ed6f41da87327a39946b4e1455 ] + +The wakeup source added by device_init_wakeup() in chromeos_tbmc_add() +needs to be dropped during driver removal, so add a .remove() callback +to the driver for this purpose. + +Fixes: 0144c00ed86b ("platform/chrome: chromeos_tbmc: Report wake events") +Signed-off-by: Rafael J. Wysocki +Link: https://lore.kernel.org/r/6151957.MhkbZ0Pkbq@rafael.j.wysocki +Signed-off-by: Tzung-Bi Shih +Signed-off-by: Sasha Levin +--- + drivers/platform/chrome/chromeos_tbmc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/platform/chrome/chromeos_tbmc.c b/drivers/platform/chrome/chromeos_tbmc.c +index d1cf8f3463ce3..e248567c0a182 100644 +--- a/drivers/platform/chrome/chromeos_tbmc.c ++++ b/drivers/platform/chrome/chromeos_tbmc.c +@@ -95,6 +95,11 @@ static int chromeos_tbmc_add(struct acpi_device *adev) + return 0; + } + ++static void chromeos_tbmc_remove(struct acpi_device *adev) ++{ ++ device_init_wakeup(&adev->dev, false); ++} ++ + static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = { + { ACPI_DRV_NAME, 0 }, + { } +@@ -110,6 +115,7 @@ static struct acpi_driver chromeos_tbmc_driver = { + .ids = chromeos_tbmc_acpi_device_ids, + .ops = { + .add = chromeos_tbmc_add, ++ .remove = chromeos_tbmc_remove, + .notify = chromeos_tbmc_notify, + }, + .drv.pm = &chromeos_tbmc_pm_ops, +-- +2.53.0 + diff --git a/queue-7.0/platform-surface-surfacepro3_button-drop-wakeup-sour.patch b/queue-7.0/platform-surface-surfacepro3_button-drop-wakeup-sour.patch new file mode 100644 index 0000000000..1316203441 --- /dev/null +++ b/queue-7.0/platform-surface-surfacepro3_button-drop-wakeup-sour.patch @@ -0,0 +1,41 @@ +From bf0d0f78e5ae1d4a34f269bd4f5107159a9f6c16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 19:54:08 +0100 +Subject: platform/surface: surfacepro3_button: Drop wakeup source on remove +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 1410a228ab2d36fe2b383415a632ae12048d4f3a ] + +The wakeup source added by device_init_wakeup() in surface_button_add() +needs to be dropped during driver removal, so update the driver to do +that. + +Fixes: 19351f340765 ("platform/x86: surfacepro3: Support for wakeup from suspend-to-idle") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/4368848.1IzOArtZ34@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/surface/surfacepro3_button.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 9bd39f09c7db4..a6c9d4d370bec 100644 +--- a/drivers/platform/surface/surfacepro3_button.c ++++ b/drivers/platform/surface/surfacepro3_button.c +@@ -242,6 +242,7 @@ static void surface_button_remove(struct acpi_device *device) + { + struct surface_button *button = acpi_driver_data(device); + ++ device_init_wakeup(&device->dev, false); + input_unregister_device(button->input); + kfree(button); + } +-- +2.53.0 + diff --git a/queue-7.0/platform-wmi-use-generic-driver_override-infrastruct.patch b/queue-7.0/platform-wmi-use-generic-driver_override-infrastruct.patch new file mode 100644 index 0000000000..844124ec11 --- /dev/null +++ b/queue-7.0/platform-wmi-use-generic-driver_override-infrastruct.patch @@ -0,0 +1,135 @@ +From efc31270f75ee19e4a14d7b842d7c7e82c78167b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:10 +0100 +Subject: platform/wmi: use generic driver_override infrastructure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Danilo Krummrich + +[ Upstream commit 8a700b1fc94df4d847a04f14ebc7f8532592b367 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 12046f8c77e0 ("platform/x86: wmi: Add driver_override support") +Reviewed-by: Armin Wolf +Acked-by: Ilpo Järvinen +Link: https://patch.msgid.link/20260324005919.2408620-7-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/platform/wmi/core.c | 36 +++++------------------------------- + include/linux/wmi.h | 4 ---- + 2 files changed, 5 insertions(+), 35 deletions(-) + +diff --git a/drivers/platform/wmi/core.c b/drivers/platform/wmi/core.c +index b8e6b9a421c62..750e3619724e0 100644 +--- a/drivers/platform/wmi/core.c ++++ b/drivers/platform/wmi/core.c +@@ -842,39 +842,11 @@ static ssize_t expensive_show(struct device *dev, + } + static DEVICE_ATTR_RO(expensive); + +-static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr, +- char *buf) +-{ +- struct wmi_device *wdev = to_wmi_device(dev); +- ssize_t ret; +- +- device_lock(dev); +- ret = sysfs_emit(buf, "%s\n", wdev->driver_override); +- device_unlock(dev); +- +- return ret; +-} +- +-static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct wmi_device *wdev = to_wmi_device(dev); +- int ret; +- +- ret = driver_set_override(dev, &wdev->driver_override, buf, count); +- if (ret < 0) +- return ret; +- +- return count; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *wmi_attrs[] = { + &dev_attr_modalias.attr, + &dev_attr_guid.attr, + &dev_attr_instance_count.attr, + &dev_attr_expensive.attr, +- &dev_attr_driver_override.attr, + NULL + }; + ATTRIBUTE_GROUPS(wmi); +@@ -943,7 +915,6 @@ static void wmi_dev_release(struct device *dev) + { + struct wmi_block *wblock = dev_to_wblock(dev); + +- kfree(wblock->dev.driver_override); + kfree(wblock); + } + +@@ -952,10 +923,12 @@ static int wmi_dev_match(struct device *dev, const struct device_driver *driver) + const struct wmi_driver *wmi_driver = to_wmi_driver(driver); + struct wmi_block *wblock = dev_to_wblock(dev); + const struct wmi_device_id *id = wmi_driver->id_table; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (wblock->dev.driver_override) +- return !strcmp(wblock->dev.driver_override, driver->name); ++ ret = device_match_driver_override(dev, driver); ++ if (ret >= 0) ++ return ret; + + if (id == NULL) + return 0; +@@ -1076,6 +1049,7 @@ static struct class wmi_bus_class = { + static const struct bus_type wmi_bus_type = { + .name = "wmi", + .dev_groups = wmi_groups, ++ .driver_override = true, + .match = wmi_dev_match, + .uevent = wmi_dev_uevent, + .probe = wmi_dev_probe, +diff --git a/include/linux/wmi.h b/include/linux/wmi.h +index 75cb0c7cfe571..14fb644e1701c 100644 +--- a/include/linux/wmi.h ++++ b/include/linux/wmi.h +@@ -18,16 +18,12 @@ + * struct wmi_device - WMI device structure + * @dev: Device associated with this WMI device + * @setable: True for devices implementing the Set Control Method +- * @driver_override: Driver name to force a match; do not set directly, +- * because core frees it; use driver_set_override() to +- * set or clear it. + * + * This represents WMI devices discovered by the WMI driver core. + */ + struct wmi_device { + struct device dev; + bool setable; +- const char *driver_override; + }; + + /** +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch b/queue-7.0/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch new file mode 100644 index 0000000000..af3748b55e --- /dev/null +++ b/queue-7.0/platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch @@ -0,0 +1,81 @@ +From 86dbd2b5b0d7f6d7e54e5110f216124079fb4619 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 18:44:30 +0100 +Subject: platform/x86: asus-wmi: adjust screenpad power/brightness handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Denis Benato + +[ Upstream commit 130d29c5627cd50e786e926ad7ef66322c5a0c09 ] + +Fix illogical screen off control by hardcoding 0 and 1 depending on the +requested brightness and also do not rely on the last screenpad power +state to issue screen brightness commands. + +Fixes: 2c97d3e55b70 ("platform/x86: asus-wmi: add support for ASUS screenpad") +Signed-off-by: Denis Benato +Signed-off-by: Luke Jones +Link: https://patch.msgid.link/20260302174431.349816-2-denis.benato@linux.dev +Link: https://patch.msgid.link/20260326231154.856729-2-ethantidmore06@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 34 +++++++++++++-------------------- + 1 file changed, 13 insertions(+), 21 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 7c0915e097bae..f3c54290c58d2 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -4419,32 +4419,24 @@ static int read_screenpad_brightness(struct backlight_device *bd) + + static int update_screenpad_bl_status(struct backlight_device *bd) + { +- struct asus_wmi *asus = bl_get_data(bd); +- int power, err = 0; +- u32 ctrl_param; ++ u32 ctrl_param = bd->props.brightness; ++ int err = 0; + +- power = read_screenpad_backlight_power(asus); +- if (power < 0) +- return power; ++ if (bd->props.power) { ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL); ++ if (err < 0) ++ return err; + +- if (bd->props.power != power) { +- if (power != BACKLIGHT_POWER_ON) { +- /* Only brightness > 0 can power it back on */ +- ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; +- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, +- ctrl_param, NULL); +- } else { +- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); +- } +- } else if (power == BACKLIGHT_POWER_ON) { +- /* Only set brightness if powered on or we get invalid/unsync state */ +- ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); ++ if (err < 0) ++ return err; + } + +- /* Ensure brightness is stored to turn back on with */ +- if (err == 0) +- asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; ++ if (!bd->props.power) { ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); ++ if (err < 0) ++ return err; ++ } + + return err; + } +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch b/queue-7.0/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch new file mode 100644 index 0000000000..97a14a962b --- /dev/null +++ b/queue-7.0/platform-x86-asus-wmi-fix-screenpad-brightness-range.patch @@ -0,0 +1,94 @@ +From 2ba1b88083aa1b5b56c541f1e377121b9ec0e667 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 18:44:31 +0100 +Subject: platform/x86: asus-wmi: fix screenpad brightness range +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Denis Benato + +[ Upstream commit 8d95d1f4aa5c76202b0833a70998769384612488 ] + +Fix screenpad brightness range being too limited without reason: +testing this patch on a Zenbook Duo showed the hardware minimum not being +too low, therefore allow the user to configure the entire range, and +expose to userspace the hardware brightness range and value. + +Fixes: 2c97d3e55b70 ("platform/x86: asus-wmi: add support for ASUS screenpad") +Signed-off-by: Denis Benato +Signed-off-by: Luke Jones +Link: https://patch.msgid.link/20260302174431.349816-3-denis.benato@linux.dev +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index f3c54290c58d2..0f8eb5be7c7a1 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -125,7 +125,6 @@ module_param(fnlock_default, bool, 0444); + #define NVIDIA_TEMP_MIN 75 + #define NVIDIA_TEMP_MAX 87 + +-#define ASUS_SCREENPAD_BRIGHT_MIN 20 + #define ASUS_SCREENPAD_BRIGHT_MAX 255 + #define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 + +@@ -4408,13 +4407,13 @@ static int read_screenpad_brightness(struct backlight_device *bd) + return err; + /* The device brightness can only be read if powered, so return stored */ + if (err == BACKLIGHT_POWER_OFF) +- return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; ++ return bd->props.brightness; + + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); + if (err < 0) + return err; + +- return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN; ++ return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; + } + + static int update_screenpad_bl_status(struct backlight_device *bd) +@@ -4454,22 +4453,19 @@ static int asus_screenpad_init(struct asus_wmi *asus) + int err, power; + int brightness = 0; + +- power = read_screenpad_backlight_power(asus); ++ power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); + if (power < 0) + return power; + +- if (power != BACKLIGHT_POWER_OFF) { ++ if (power) { + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); + if (err < 0) + return err; + } +- /* default to an acceptable min brightness on boot if too low */ +- if (brightness < ASUS_SCREENPAD_BRIGHT_MIN) +- brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ +- props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN; ++ props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX; + bd = backlight_device_register("asus_screenpad", + &asus->platform_device->dev, asus, + &asus_screenpad_bl_ops, &props); +@@ -4480,7 +4476,7 @@ static int asus_screenpad_init(struct asus_wmi *asus) + + asus->screenpad_backlight_device = bd; + asus->driver->screenpad_brightness = brightness; +- bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN; ++ bd->props.brightness = brightness; + bd->props.power = power; + backlight_update_status(bd); + +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-barco-p50-gpio-normalize-return-value-o.patch b/queue-7.0/platform-x86-barco-p50-gpio-normalize-return-value-o.patch new file mode 100644 index 0000000000..2671f4fbac --- /dev/null +++ b/queue-7.0/platform-x86-barco-p50-gpio-normalize-return-value-o.patch @@ -0,0 +1,48 @@ +From 8008195bf5079ab827b34d1f31193500e432ea51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 19:56:17 -0700 +Subject: platform/x86: barco-p50-gpio: normalize return value of gpio_get +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dmitry Torokhov + +[ Upstream commit 1c9d30d37aaffe3454d70b89a77f8aaecda257bf ] + +The GPIO get callback is expected to return 0 or 1 (or a negative error +code). Ensure that the value returned by p50_gpio_get() is normalized +to the [0, 1] range. + +Fixes: 86ef402d805d606a ("gpiolib: sanitize the return value of gpio_chip::get()") +Reviewed-by: Linus Walleij +Signed-off-by: Dmitry Torokhov +Reviewed-by: Bartosz Golaszewski +Link: https://patch.msgid.link/20260318-barco-p50-gpio-set-v2-1-c0a4a6416163@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/barco-p50-gpio.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c +index 6f13e81f98fbb..360ffd8505d6c 100644 +--- a/drivers/platform/x86/barco-p50-gpio.c ++++ b/drivers/platform/x86/barco-p50-gpio.c +@@ -275,8 +275,11 @@ static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset) + mutex_lock(&p50->lock); + + ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0); +- if (ret == 0) ++ if (ret == 0) { + ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA); ++ if (ret >= 0) ++ ret = !!ret; ++ } + + mutex_unlock(&p50->lock); + +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch b/queue-7.0/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch new file mode 100644 index 0000000000..dc0c9e20dc --- /dev/null +++ b/queue-7.0/platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch @@ -0,0 +1,99 @@ +From a5b73ac7536c69651f1b61b80b531d33dd180502 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 08:38:21 +0800 +Subject: platform/x86: dell-wmi-sysman: bound enumeration string aggregation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pengpeng Hou + +[ Upstream commit 3c34471c26abc52a37f5ad90949e2e4b8027eb14 ] + +populate_enum_data() aggregates firmware-provided value-modifier +and possible-value strings into fixed 512-byte struct members. +The current code bounds each individual source string but then +appends every string and separator with raw strcat() and no +remaining-space check. + +Switch the aggregation loops to a bounded append helper and +reject enumeration packages whose combined strings do not fit +in the destination buffers. + +Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems") +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260408084501.1-dell-wmi-sysman-v2-pengpeng@iscas.ac.cn +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + .../dell/dell-wmi-sysman/enum-attributes.c | 34 +++++++++++++++---- + 1 file changed, 28 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +index 09996fbdc7074..a85639d8a076f 100644 +--- a/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c ++++ b/drivers/platform/x86/dell/dell-wmi-sysman/enum-attributes.c +@@ -6,10 +6,32 @@ + * Copyright (c) 2020 Dell Inc. + */ + ++#include ++ + #include "dell-wmi-sysman.h" + + get_instance_id(enumeration); + ++static int append_enum_string(char *dest, const char *src) ++{ ++ size_t dest_len = strlen(dest); ++ ssize_t copied; ++ ++ if (WARN_ON_ONCE(dest_len >= MAX_BUFF)) ++ return -EINVAL; ++ ++ copied = strscpy(dest + dest_len, src, MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ dest_len += copied; ++ copied = strscpy(dest + dest_len, ";", MAX_BUFF - dest_len); ++ if (copied < 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { + int instance_id = get_enumeration_instance_id(kobj); +@@ -176,9 +198,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + if (next_obj >= enum_property_count) +@@ -193,9 +215,9 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id, + return -EINVAL; + if (check_property_type(enumeration, next_obj, ACPI_TYPE_STRING)) + return -EINVAL; +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, +- enumeration_obj[next_obj++].string.pointer); +- strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";"); ++ if (append_enum_string(wmi_priv.enumeration_data[instance_id].possible_values, ++ enumeration_obj[next_obj++].string.pointer)) ++ return -EINVAL; + } + + return sysfs_create_group(attr_name_kobj, &enumeration_attr_group); +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch b/queue-7.0/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch new file mode 100644 index 0000000000..049efb8875 --- /dev/null +++ b/queue-7.0/platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch @@ -0,0 +1,60 @@ +From de88cd84252803848efe3b9f0e353a87e91fb840 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Apr 2026 16:42:39 +0300 +Subject: platform/x86: dell_rbu: avoid uninit value usage in + packet_size_write() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fedor Pchelkin + +[ Upstream commit f8fd138c2363c0e2d3235c32bfb4fb5c6474e4ae ] + +Ensure the temp value has been properly parsed from the user-provided +buffer and initialized to be used in later operations. While at it, +prefer a convenient kstrtoul() helper. + +Found by Linux Verification Center (linuxtesting.org) with Svace static +analysis tool. + +Fixes: ad6ce87e5bd4 ("[PATCH] dell_rbu: changes in packet update mechanism") +Signed-off-by: Fedor Pchelkin +Link: https://patch.msgid.link/20260403134240.604837-1-pchelkin@ispras.ru +[ij: add include] +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/dell/dell_rbu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/dell/dell_rbu.c b/drivers/platform/x86/dell/dell_rbu.c +index eb50f1d75d0c1..3fa9de9aa47b8 100644 +--- a/drivers/platform/x86/dell/dell_rbu.c ++++ b/drivers/platform/x86/dell/dell_rbu.c +@@ -30,6 +30,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -619,9 +620,12 @@ static ssize_t packet_size_write(struct file *filp, struct kobject *kobj, + char *buffer, loff_t pos, size_t count) + { + unsigned long temp; ++ ++ if (kstrtoul(buffer, 10, &temp)) ++ return -EINVAL; ++ + spin_lock(&rbu_data.lock); + packet_empty_list(); +- sscanf(buffer, "%lu", &temp); + if (temp < 0xffffffff) + rbu_data.packetsize = temp; + +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-hp-wmi-add-locking-for-concurrent-hwmon.patch b/queue-7.0/platform-x86-hp-wmi-add-locking-for-concurrent-hwmon.patch new file mode 100644 index 0000000000..0f36d86fb1 --- /dev/null +++ b/queue-7.0/platform-x86-hp-wmi-add-locking-for-concurrent-hwmon.patch @@ -0,0 +1,103 @@ +From 68316b5a4103676fefd90d5e1e2b4c18ff23557d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:25:14 +0300 +Subject: platform/x86: hp-wmi: add locking for concurrent hwmon access +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Emre Cecanpunar + +[ Upstream commit 5969c55e2145368254194edbe0e64880314be69f ] + +hp_wmi_hwmon_priv.mode and .pwm are written by hp_wmi_hwmon_write() in +sysfs context and read by hp_wmi_hwmon_keep_alive_handler() in a +workqueue. A concurrent write and keep-alive expiry can observe an +inconsistent mode/pwm pair (e.g. mode=MANUAL with a stale pwm). + +Add a mutex to hp_wmi_hwmon_priv protecting mode and pwm. Hold it in +hp_wmi_hwmon_write() across the field update and apply call, and in +hp_wmi_hwmon_keep_alive_handler() before calling apply. + +In hp_wmi_hwmon_read(), only the pwm_enable path reads priv->mode; use +scoped_guard() there to avoid holding the lock across unrelated WMI +calls. + +Fixes: c203c59fb5de ("platform/x86: hp-wmi: implement fan keep-alive") +Suggested-by: Ilpo Järvinen +Signed-off-by: Emre Cecanpunar +Link: https://patch.msgid.link/20260407142515.20683-6-emreleno@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index dd0f86b8807fa..851056bee6146 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -458,6 +458,7 @@ enum pwm_modes { + }; + + struct hp_wmi_hwmon_priv { ++ struct mutex lock; /* protects mode, pwm */ + u8 min_rpm; + u8 max_rpm; + int gpu_delta; +@@ -2427,6 +2428,7 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + { + struct hp_wmi_hwmon_priv *priv; + int rpm, ret; ++ u8 mode; + + priv = dev_get_drvdata(dev); + switch (type) { +@@ -2450,11 +2452,13 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + *val = rpm_to_pwm(rpm / 100, priv); + return 0; + } +- switch (priv->mode) { ++ scoped_guard(mutex, &priv->lock) ++ mode = priv->mode; ++ switch (mode) { + case PWM_MODE_MAX: + case PWM_MODE_MANUAL: + case PWM_MODE_AUTO: +- *val = priv->mode; ++ *val = mode; + return 0; + default: + /* shouldn't happen */ +@@ -2472,6 +2476,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + int rpm; + + priv = dev_get_drvdata(dev); ++ guard(mutex)(&priv->lock); + switch (type) { + case hwmon_pwm: + if (attr == hwmon_pwm_input) { +@@ -2540,6 +2545,8 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work) + + dwork = to_delayed_work(work); + priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork); ++ ++ guard(mutex)(&priv->lock); + /* + * Re-apply the current hwmon context settings. + * NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling. +@@ -2596,6 +2603,10 @@ static int hp_wmi_hwmon_init(void) + if (!priv) + return -ENOMEM; + ++ ret = devm_mutex_init(dev, &priv->lock); ++ if (ret) ++ return ret; ++ + ret = hp_wmi_setup_fan_settings(priv); + if (ret) + return ret; +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-hp-wmi-avoid-cancel_delayed_work_sync-f.patch b/queue-7.0/platform-x86-hp-wmi-avoid-cancel_delayed_work_sync-f.patch new file mode 100644 index 0000000000..bc6b4517cf --- /dev/null +++ b/queue-7.0/platform-x86-hp-wmi-avoid-cancel_delayed_work_sync-f.patch @@ -0,0 +1,48 @@ +From 88fe79d058af3aa673f4226e45110ef2a58a03a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:25:11 +0300 +Subject: platform/x86: hp-wmi: avoid cancel_delayed_work_sync from work + handler +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Emre Cecanpunar + +[ Upstream commit 249ddba9c0ba4453c0a6bc0e3626e7864751d940 ] + +hp_wmi_apply_fan_settings() uses cancel_delayed_work_sync() to stop +the keep-alive timer in AUTO mode. However, since +hp_wmi_apply_fan_settings() is also called from the keep-alive +handler, a race condition with a sysfs write can cause the handler to +wait on itself, leading to a deadlock. + +Replace cancel_delayed_work_sync() with cancel_delayed_work() in +hp_wmi_apply_fan_settings() to avoid the self-flush deadlock. + +Fixes: c203c59fb5de ("platform/x86: hp-wmi: implement fan keep-alive") +Signed-off-by: Emre Cecanpunar +Link: https://patch.msgid.link/20260407142515.20683-3-emreleno@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index c9fe740d8933e..4dd7e4a118ea4 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -2389,7 +2389,7 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) + } + if (ret < 0) + return ret; +- cancel_delayed_work_sync(&priv->keep_alive_dwork); ++ cancel_delayed_work(&priv->keep_alive_dwork); + return 0; + default: + /* shouldn't happen */ +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-hp-wmi-fix-fan-table-parsing.patch b/queue-7.0/platform-x86-hp-wmi-fix-fan-table-parsing.patch new file mode 100644 index 0000000000..605f66fc13 --- /dev/null +++ b/queue-7.0/platform-x86-hp-wmi-fix-fan-table-parsing.patch @@ -0,0 +1,115 @@ +From 70c7d1a13ec847de298486a07188ff49e1d53e94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 00:40:36 +0530 +Subject: platform/x86: hp-wmi: fix fan table parsing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Krishna Chomal + +[ Upstream commit 9d317a54e46d3b6420567dc5b63e9d7ff5c064a3 ] + +For Victus S devices, the BIOS fan table header was being incorrectly +parsed as: +struct { + u8 unknown; + u8 num_entries; +} + +The first field should be num_fans and the second should be unknown. It +is pure coincidence that interpreting an "unknown" field as "num_entries" +worked on multiple device, however for board 8D87 (in an upcoming patch), +this assumption fails, and the hp-wmi driver fails to load. + +We fix this by correcting the header definition and compensating for +num_entries by parsing each entry of the fan table until an all-NULL row +is obtained, mirroring the behavior of OMEN Gaming Hub on Windows. + +Fixes: 46be1453e6e6 ("platform/x86: hp-wmi: add manual fan control for Victus S models") +Signed-off-by: Krishna Chomal +Link: https://patch.msgid.link/20260410191039.125659-2-krishna.chomal108@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 41 +++++++++++++++++++++++++------- + 1 file changed, 33 insertions(+), 8 deletions(-) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index 851056bee6146..75682bb4cc52a 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -468,14 +468,14 @@ struct hp_wmi_hwmon_priv { + }; + + struct victus_s_fan_table_header { ++ u8 num_fans; + u8 unknown; +- u8 num_entries; + } __packed; + + struct victus_s_fan_table_entry { + u8 cpu_rpm; + u8 gpu_rpm; +- u8 unknown; ++ u8 noise_db; + } __packed; + + struct victus_s_fan_table { +@@ -2562,7 +2562,9 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) + u8 fan_data[128] = { 0 }; + struct victus_s_fan_table *fan_table; + u8 min_rpm, max_rpm; +- int gpu_delta, ret; ++ u8 cpu_rpm, gpu_rpm, noise_db; ++ int gpu_delta, i, num_entries, ret; ++ size_t header_size, entry_size; + + /* Default behaviour on hwmon init is automatic mode */ + priv->mode = PWM_MODE_AUTO; +@@ -2577,13 +2579,36 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) + return ret; + + fan_table = (struct victus_s_fan_table *)fan_data; +- if (fan_table->header.num_entries == 0 || +- sizeof(struct victus_s_fan_table_header) + +- sizeof(struct victus_s_fan_table_entry) * fan_table->header.num_entries > sizeof(fan_data)) ++ if (fan_table->header.num_fans == 0) ++ return -EINVAL; ++ ++ header_size = sizeof(struct victus_s_fan_table_header); ++ entry_size = sizeof(struct victus_s_fan_table_entry); ++ num_entries = (sizeof(fan_data) - header_size) / entry_size; ++ min_rpm = U8_MAX; ++ max_rpm = 0; ++ ++ for (i = 0 ; i < num_entries ; i++) { ++ cpu_rpm = fan_table->entries[i].cpu_rpm; ++ gpu_rpm = fan_table->entries[i].gpu_rpm; ++ noise_db = fan_table->entries[i].noise_db; ++ ++ /* ++ * On some devices, the fan table is truncated with an all-zero row, ++ * hence we stop parsing here. ++ */ ++ if (cpu_rpm == 0 && gpu_rpm == 0 && noise_db == 0) ++ break; ++ ++ if (cpu_rpm < min_rpm) ++ min_rpm = cpu_rpm; ++ if (cpu_rpm > max_rpm) ++ max_rpm = cpu_rpm; ++ } ++ ++ if (min_rpm == U8_MAX || max_rpm == 0) + return -EINVAL; + +- min_rpm = fan_table->entries[0].cpu_rpm; +- max_rpm = fan_table->entries[fan_table->header.num_entries - 1].cpu_rpm; + gpu_delta = fan_table->entries[0].gpu_rpm - fan_table->entries[0].cpu_rpm; + priv->min_rpm = min_rpm; + priv->max_rpm = max_rpm; +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-hp-wmi-fix-ignored-return-values-in-fan.patch b/queue-7.0/platform-x86-hp-wmi-fix-ignored-return-values-in-fan.patch new file mode 100644 index 0000000000..b40d4d45b2 --- /dev/null +++ b/queue-7.0/platform-x86-hp-wmi-fix-ignored-return-values-in-fan.patch @@ -0,0 +1,102 @@ +From d1796c2bdd9a2537d94f2f717a1592fd6642b4ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:25:10 +0300 +Subject: platform/x86: hp-wmi: fix ignored return values in fan settings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Emre Cecanpunar + +[ Upstream commit 7265b57fbc32782d02bdb8d865ba0d8efa209c8c ] + +hp_wmi_get_fan_count_userdefine_trigger() can fail, but its return +value was silently ignored in hp_wmi_apply_fan_settings() for +PWM_MODE_MAX/AUTO. Propagate these errors consistently. + +Additionally, handle the return value of hp_wmi_apply_fan_settings() +in its callers by adding appropriate warnings on failure, and remove an +unreachable "return 0" at the end of the function. + +Fixes: 46be1453e6e6 ("platform/x86: hp-wmi: add manual fan control for Victus S models") +Signed-off-by: Emre Cecanpunar +Link: https://patch.msgid.link/20260407142515.20683-2-emreleno@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index 62fd2fe0d8d0e..c9fe740d8933e 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -2358,8 +2358,11 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) + + switch (priv->mode) { + case PWM_MODE_MAX: +- if (is_victus_s_thermal_profile()) +- hp_wmi_get_fan_count_userdefine_trigger(); ++ if (is_victus_s_thermal_profile()) { ++ ret = hp_wmi_get_fan_count_userdefine_trigger(); ++ if (ret < 0) ++ return ret; ++ } + ret = hp_wmi_fan_speed_max_set(1); + if (ret < 0) + return ret; +@@ -2377,7 +2380,9 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) + return 0; + case PWM_MODE_AUTO: + if (is_victus_s_thermal_profile()) { +- hp_wmi_get_fan_count_userdefine_trigger(); ++ ret = hp_wmi_get_fan_count_userdefine_trigger(); ++ if (ret < 0) ++ return ret; + ret = hp_wmi_fan_speed_max_reset(priv); + } else { + ret = hp_wmi_fan_speed_max_set(0); +@@ -2390,8 +2395,6 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) + /* shouldn't happen */ + return -EINVAL; + } +- +- return 0; + } + + static umode_t hp_wmi_hwmon_is_visible(const void *data, +@@ -2533,6 +2536,7 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work) + { + struct delayed_work *dwork; + struct hp_wmi_hwmon_priv *priv; ++ int ret; + + dwork = to_delayed_work(work); + priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork); +@@ -2540,7 +2544,10 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work) + * Re-apply the current hwmon context settings. + * NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling. + */ +- hp_wmi_apply_fan_settings(priv); ++ ret = hp_wmi_apply_fan_settings(priv); ++ if (ret) ++ pr_warn_ratelimited("keep-alive failed to refresh fan settings: %d\n", ++ ret); + } + + static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) +@@ -2602,7 +2609,9 @@ static int hp_wmi_hwmon_init(void) + + INIT_DELAYED_WORK(&priv->keep_alive_dwork, hp_wmi_hwmon_keep_alive_handler); + platform_set_drvdata(hp_wmi_platform_dev, priv); +- hp_wmi_apply_fan_settings(priv); ++ ret = hp_wmi_apply_fan_settings(priv); ++ if (ret) ++ dev_warn(dev, "Failed to apply initial fan settings: %d\n", ret); + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-hp-wmi-fix-u8-underflow-in-gpu_delta-ca.patch b/queue-7.0/platform-x86-hp-wmi-fix-u8-underflow-in-gpu_delta-ca.patch new file mode 100644 index 0000000000..9eb5c9362f --- /dev/null +++ b/queue-7.0/platform-x86-hp-wmi-fix-u8-underflow-in-gpu_delta-ca.patch @@ -0,0 +1,58 @@ +From 2104f9a5457c8f9a7b9a2ebcc5364a2c5a315f16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:25:13 +0300 +Subject: platform/x86: hp-wmi: fix u8 underflow in gpu_delta calculation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Emre Cecanpunar + +[ Upstream commit cb4daa450f05447c1f914eaef75b2577c25a0fcd ] + +gpu_delta was declared as u8. If the firmware specifies a GPU RPM +lower than the CPU RPM, subtracting them causes an underflow +(e.g. 10 - 20 = 246), which forces the GPU fan to remain clamped at +U8_MAX (100% speed) during operation. + +Change gpu_delta to int and use signed arithmetic. Existing signed logic +in hp_wmi_fan_speed_set() correctly handles negative deltas. + +Fixes: 46be1453e6e6 ("platform/x86: hp-wmi: add manual fan control for Victus S models") +Suggested-by: Ilpo Järvinen +Signed-off-by: Emre Cecanpunar +Link: https://patch.msgid.link/20260407142515.20683-5-emreleno@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index 273fa95bc9bab..dd0f86b8807fa 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -460,7 +460,7 @@ enum pwm_modes { + struct hp_wmi_hwmon_priv { + u8 min_rpm; + u8 max_rpm; +- u8 gpu_delta; ++ int gpu_delta; + u8 mode; + u8 pwm; + struct delayed_work keep_alive_dwork; +@@ -2554,8 +2554,8 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) + { + u8 fan_data[128] = { 0 }; + struct victus_s_fan_table *fan_table; +- u8 min_rpm, max_rpm, gpu_delta; +- int ret; ++ u8 min_rpm, max_rpm; ++ int gpu_delta, ret; + + /* Default behaviour on hwmon init is automatic mode */ + priv->mode = PWM_MODE_AUTO; +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-hp-wmi-use-mod_delayed_work-to-reset-ke.patch b/queue-7.0/platform-x86-hp-wmi-use-mod_delayed_work-to-reset-ke.patch new file mode 100644 index 0000000000..989b9117e1 --- /dev/null +++ b/queue-7.0/platform-x86-hp-wmi-use-mod_delayed_work-to-reset-ke.patch @@ -0,0 +1,63 @@ +From f3335526a68d56029adebb106c979e58de4418ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 17:25:12 +0300 +Subject: platform/x86: hp-wmi: use mod_delayed_work to reset keep-alive timer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Emre Cecanpunar + +[ Upstream commit 6297443beb0c5606399ec7d4f4b335e2e7379147 ] + +Currently, schedule_delayed_work() is used to queue the 90s keep-alive +timer. If a user manually changes the fan speed at T=85s, +schedule_delayed_work() leaves the existing timer in place as it is a +no-op if the work is already pending. This results in the keep-alive +timer firing unnecessarily at T=90s, just 5 seconds after the user +action. + +Replace schedule_delayed_work() with mod_delayed_work() to reset the +90s timer whenever fan settings are applied. This guarantees a full 90s +delay after every user interaction, preventing redundant keep-alive +executions and improving efficiency. + +Fixes: c203c59fb5de ("platform/x86: hp-wmi: implement fan keep-alive") +Signed-off-by: Emre Cecanpunar +Link: https://patch.msgid.link/20260407142515.20683-4-emreleno@gmail.com +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/hp/hp-wmi.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c +index 4dd7e4a118ea4..273fa95bc9bab 100644 +--- a/drivers/platform/x86/hp/hp-wmi.c ++++ b/drivers/platform/x86/hp/hp-wmi.c +@@ -2366,8 +2366,8 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) + ret = hp_wmi_fan_speed_max_set(1); + if (ret < 0) + return ret; +- schedule_delayed_work(&priv->keep_alive_dwork, +- secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); ++ mod_delayed_work(system_wq, &priv->keep_alive_dwork, ++ secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); + return 0; + case PWM_MODE_MANUAL: + if (!is_victus_s_thermal_profile()) +@@ -2375,8 +2375,8 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) + ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv)); + if (ret < 0) + return ret; +- schedule_delayed_work(&priv->keep_alive_dwork, +- secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); ++ mod_delayed_work(system_wq, &priv->keep_alive_dwork, ++ secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); + return 0; + case PWM_MODE_AUTO: + if (is_victus_s_thermal_profile()) { +-- +2.53.0 + diff --git a/queue-7.0/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch b/queue-7.0/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch new file mode 100644 index 0000000000..a8ecac57ce --- /dev/null +++ b/queue-7.0/platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch @@ -0,0 +1,67 @@ +From 51df6f7f3a13f81bc76ee250114a1792b361f405 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Mar 2026 11:31:54 +0100 +Subject: platform/x86: panasonic-laptop: Fix OPTD notifier registration and + cleanup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Rafael J. Wysocki + +[ Upstream commit 8baeff2c1d33dad8572216c6ad3a7425852507d4 ] + +An ACPI notify handler is leaked if device_create_file() returns an +error in acpi_pcc_hotkey_add(). + +Also, it is pointless to call pcc_unregister_optd_notifier() in +acpi_pcc_hotkey_remove() if pcc->platform is NULL and it is better +to arrange the cleanup code in that function in the same order as +the rollback code in acpi_pcc_hotkey_add(). + +Address the above by placing the pcc_register_optd_notifier() call in +acpi_pcc_hotkey_add() after the device_create_file() return value +check and placing the pcc_unregister_optd_notifier() call in +acpi_pcc_hotkey_remove() right before the device_remove_file() call. + +Fixes: d5a81d8e864b ("platform/x86: panasonic-laptop: Add support for optical driver power in Y and W series") +Signed-off-by: Rafael J. Wysocki +Link: https://patch.msgid.link/2411055.ElGaqSPkdT@rafael.j.wysocki +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/panasonic-laptop.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c +index d923ddaa48496..97c0c51b5a4c3 100644 +--- a/drivers/platform/x86/panasonic-laptop.c ++++ b/drivers/platform/x86/panasonic-laptop.c +@@ -1093,9 +1093,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) + } + result = device_create_file(&pcc->platform->dev, + &dev_attr_cdpower); +- pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + if (result) + goto out_platform; ++ ++ pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + } else { + pcc->platform = NULL; + } +@@ -1129,10 +1130,10 @@ static void acpi_pcc_hotkey_remove(struct acpi_device *device) + i8042_remove_filter(panasonic_i8042_filter); + + if (pcc->platform) { ++ pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); + platform_device_unregister(pcc->platform); + } +- pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD"); + + sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); + +-- +2.53.0 + diff --git a/queue-7.0/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch b/queue-7.0/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch new file mode 100644 index 0000000000..b09af3badb --- /dev/null +++ b/queue-7.0/pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch @@ -0,0 +1,39 @@ +From feaae28e00bc428f6a9c0b700cf6cf8b7d356f04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Feb 2026 12:48:59 +0200 +Subject: PM: domains: De-constify fields in struct dev_pm_domain_attach_data + +From: Dmitry Baryshkov + +[ Upstream commit 1877d3f258cbb57d64e275754fb9b18b089ce72d ] + +It doesn't really make sense to keep u32 fields to be marked as const. +Having the const fields prevents their modification in the driver. Instead +the whole struct can be defined as const, if it is constant. + +Fixes: 161e16a5e50a ("PM: domains: Add helper functions to attach/detach multiple PM domains") +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + include/linux/pm_domain.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h +index 93ba0143ca476..38d1814ab8a5e 100644 +--- a/include/linux/pm_domain.h ++++ b/include/linux/pm_domain.h +@@ -49,8 +49,8 @@ + + struct dev_pm_domain_attach_data { + const char * const *pd_names; +- const u32 num_pd_names; +- const u32 pd_flags; ++ u32 num_pd_names; ++ u32 pd_flags; + }; + + struct dev_pm_domain_list { +-- +2.53.0 + diff --git a/queue-7.0/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch b/queue-7.0/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch new file mode 100644 index 0000000000..9c17c458e0 --- /dev/null +++ b/queue-7.0/pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch @@ -0,0 +1,38 @@ +From 095e41aaad97bbe379ae6b6b559cc4bfe2ef4807 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 22:17:17 +0800 +Subject: pmdomain: imx: scu-pd: Fix device_node reference leak during + ->probe() + +From: Felix Gu + +[ Upstream commit c8e9b6a55702be6c6d034e973d519c52c3848415 ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In imx_sc_pd_get_console_rsrc(), it does not release the reference. + +Fixes: 893cfb99734f ("firmware: imx: scu-pd: do not power off console domain") +Signed-off-by: Felix Gu +Reviewed-by: Peng Fan +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/pmdomain/imx/scu-pd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pmdomain/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c +index 01d465d88f60d..3ec33667a308c 100644 +--- a/drivers/pmdomain/imx/scu-pd.c ++++ b/drivers/pmdomain/imx/scu-pd.c +@@ -326,6 +326,7 @@ static void imx_sc_pd_get_console_rsrc(void) + return; + + imx_con_rsrc = specs.args[0]; ++ of_node_put(specs.np); + } + + static int imx_sc_get_pd_power(struct device *dev, u32 rsrc) +-- +2.53.0 + diff --git a/queue-7.0/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch b/queue-7.0/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch new file mode 100644 index 0000000000..09df0c3dfb --- /dev/null +++ b/queue-7.0/pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch @@ -0,0 +1,36 @@ +From eed56d977be81cd8f69830ec194374914cd88034 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 20:27:47 +0800 +Subject: pmdomain: ti: omap_prm: Fix a reference leak on device node + +From: Felix Gu + +[ Upstream commit 44c28e1c52764fef6dd1c1ada3a248728812e67f ] + +When calling of_parse_phandle_with_args(), the caller is responsible +to call of_node_put() to release the reference of device node. +In omap_prm_domain_attach_dev, it does not release the reference. + +Fixes: 58cbff023bfa ("soc: ti: omap-prm: Add basic power domain support") +Signed-off-by: Felix Gu +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/pmdomain/ti/omap_prm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pmdomain/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c +index 5142f064bf5cd..64a187f79a1a7 100644 +--- a/drivers/pmdomain/ti/omap_prm.c ++++ b/drivers/pmdomain/ti/omap_prm.c +@@ -655,6 +655,7 @@ static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, + if (pd_args.args_count != 0) + dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", + prmd->pd.name, pd_args.args_count); ++ of_node_put(pd_args.np); + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; +-- +2.53.0 + diff --git a/queue-7.0/power-supply-max77705-drop-duplicated-irq-error-mess.patch b/queue-7.0/power-supply-max77705-drop-duplicated-irq-error-mess.patch new file mode 100644 index 0000000000..f3e52c6fff --- /dev/null +++ b/queue-7.0/power-supply-max77705-drop-duplicated-irq-error-mess.patch @@ -0,0 +1,52 @@ +From dbf6ff4a4a0606c544436c3f6e9335ffa97ebe1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 22:45:42 +0100 +Subject: power: supply: max77705: Drop duplicated IRQ error message + +From: Krzysztof Kozlowski + +[ Upstream commit 2064c64ceb1996ee02a6bbb1de05fd6e8028e3e4 ] + +Core already prints error message on devm_request_threaded_irq() +failure, so no need to do that second time. + +Suggested-by: Andy Shevchenko +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260305-workqueue-devm-v2-3-66a38741c652@oss.qualcomm.com +Signed-off-by: Sebastian Reichel +Stable-dep-of: 1e668baadefb ("power: supply: max77705: Free allocated workqueue and fix removal order") +Signed-off-by: Sasha Levin +--- + drivers/power/supply/max77705_charger.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c +index 5dd02f658f5bd..0dfe4ab10919f 100644 +--- a/drivers/power/supply/max77705_charger.c ++++ b/drivers/power/supply/max77705_charger.c +@@ -666,19 +666,15 @@ static int max77705_charger_probe(struct i2c_client *i2c) + NULL, max77705_chgin_irq, + IRQF_TRIGGER_NONE, + "chgin-irq", chg); +- if (ret) { +- dev_err_probe(dev, ret, "Failed to Request chgin IRQ\n"); ++ if (ret) + goto destroy_wq; +- } + + ret = devm_request_threaded_irq(dev, regmap_irq_get_virq(irq_data, MAX77705_AICL_I), + NULL, max77705_aicl_irq, + IRQF_TRIGGER_NONE, + "aicl-irq", chg); +- if (ret) { +- dev_err_probe(dev, ret, "Failed to Request aicl IRQ\n"); ++ if (ret) + goto destroy_wq; +- } + + ret = max77705_charger_enable(chg); + if (ret) { +-- +2.53.0 + diff --git a/queue-7.0/power-supply-max77705-free-allocated-workqueue-and-f.patch b/queue-7.0/power-supply-max77705-free-allocated-workqueue-and-f.patch new file mode 100644 index 0000000000..c767a6955d --- /dev/null +++ b/queue-7.0/power-supply-max77705-free-allocated-workqueue-and-f.patch @@ -0,0 +1,108 @@ +From 5d7eb67af42e0e9aaa81fd6300846e7804717d1c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 22:45:43 +0100 +Subject: power: supply: max77705: Free allocated workqueue and fix removal + order + +From: Krzysztof Kozlowski + +[ Upstream commit 1e668baadefb16e81269dbfebf3ffc2672e3a3bb ] + +Use devm interface for allocating workqueue to fix two bugs at the same +time: + +1. Driver leaks the memory on remove(), because the workqueue is not + destroyed. + +2. Driver allocates workqueue and then registers interrupt handlers + with devm interface. This means that probe error paths will not use a + reversed order, but first destroy the workqueue and then, via devm + release handlers, free the interrupt. + + The interrupt handler schedules work on this exact workqueue, thus if + interrupt is hit in this short time window - after destroying + workqueue, but before devm() frees the interrupt - the schedulled + work will lead to use of freed memory. + +Change is not equivalent in the workqueue itself: use non-legacy API +which does not set (__WQ_LEGACY | WQ_MEM_RECLAIM). The workqueue is +used to update power supply (power_supply_changed()) status, thus there +is no point to run it for memory reclaim. Note that dev_name() is not +directly used in second argument to prevent possible unlikely parsing +any "%" character in device name as format. + +Fixes: 11741b8e382d ("power: supply: max77705: Fix workqueue error handling in probe") +Fixes: a6a494c8e3ce ("power: supply: max77705: Add charger driver for Maxim 77705") +Signed-off-by: Krzysztof Kozlowski +Reviewed-by: Andy Shevchenko +Link: https://patch.msgid.link/20260305-workqueue-devm-v2-4-66a38741c652@oss.qualcomm.com +Signed-off-by: Sebastian Reichel +Signed-off-by: Sasha Levin +--- + drivers/power/supply/max77705_charger.c | 28 ++++++++----------------- + 1 file changed, 9 insertions(+), 19 deletions(-) + +diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c +index 0dfe4ab10919f..63b0b4f0cd217 100644 +--- a/drivers/power/supply/max77705_charger.c ++++ b/drivers/power/supply/max77705_charger.c +@@ -646,47 +646,37 @@ static int max77705_charger_probe(struct i2c_client *i2c) + if (ret) + return dev_err_probe(dev, ret, "failed to add irq chip\n"); + +- chg->wqueue = create_singlethread_workqueue(dev_name(dev)); ++ chg->wqueue = devm_alloc_ordered_workqueue(dev, "%s", 0, dev_name(dev)); + if (!chg->wqueue) + return -ENOMEM; + + ret = devm_work_autocancel(dev, &chg->chgin_work, max77705_chgin_isr_work); +- if (ret) { +- dev_err_probe(dev, ret, "failed to initialize interrupt work\n"); +- goto destroy_wq; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to initialize interrupt work\n"); + + ret = max77705_charger_initialize(chg); +- if (ret) { +- dev_err_probe(dev, ret, "failed to initialize charger IC\n"); +- goto destroy_wq; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to initialize charger IC\n"); + + ret = devm_request_threaded_irq(dev, regmap_irq_get_virq(irq_data, MAX77705_CHGIN_I), + NULL, max77705_chgin_irq, + IRQF_TRIGGER_NONE, + "chgin-irq", chg); + if (ret) +- goto destroy_wq; ++ return ret; + + ret = devm_request_threaded_irq(dev, regmap_irq_get_virq(irq_data, MAX77705_AICL_I), + NULL, max77705_aicl_irq, + IRQF_TRIGGER_NONE, + "aicl-irq", chg); + if (ret) +- goto destroy_wq; ++ return ret; + + ret = max77705_charger_enable(chg); +- if (ret) { +- dev_err_probe(dev, ret, "failed to enable charge\n"); +- goto destroy_wq; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to enable charge\n"); + + return devm_add_action_or_reset(dev, max77705_charger_disable, chg); +- +-destroy_wq: +- destroy_workqueue(chg->wqueue); +- return ret; + } + + static const struct of_device_id max77705_charger_of_match[] = { +-- +2.53.0 + diff --git a/queue-7.0/powerpc-64s-fix-unmap-race-with-pmd-migration-entrie.patch b/queue-7.0/powerpc-64s-fix-unmap-race-with-pmd-migration-entrie.patch new file mode 100644 index 0000000000..df6440e81e --- /dev/null +++ b/queue-7.0/powerpc-64s-fix-unmap-race-with-pmd-migration-entrie.patch @@ -0,0 +1,178 @@ +From 89dfc7d12df0f0a8bde0786938bcb9229d168fc5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 23:44:25 +0530 +Subject: powerpc/64s: Fix unmap race with PMD migration entries + +From: Ritesh Harjani (IBM) + +[ Upstream commit bbcbf045d6c778e82b47a35fc8728387708e9a3d ] + +The following race is possible with migration swap entries or +device-private THP entries. e.g. when move_pages is called on a PMD THP +page, then there maybe an intermediate state, where PMD entry acts as +a migration swap entry (pmd_present() is true). Then if an munmap +happens at the same time, then this VM_BUG_ON() can happen in +pmdp_huge_get_and_clear_full(). + +This patch fixes that. + +Thread A: move_pages() syscall + add_folio_for_migration() + mmap_read_lock(mm) + folio_isolate_lru(folio) + mmap_read_unlock(mm) + + do_move_pages_to_node() + migrate_pages() + try_to_migrate_one() + spin_lock(ptl) + set_pmd_migration_entry() + pmdp_invalidate() # PMD: _PAGE_INVALID | _PAGE_PTE | pfn + set_pmd_at() # PMD: migration swap entry (pmd_present=0) + spin_unlock(ptl) + [page copy phase] # <--- RACE WINDOW --> + +Thread B: munmap() + mmap_write_downgrade(mm) + unmap_vmas() -> zap_pmd_range() + zap_huge_pmd() + __pmd_trans_huge_lock() + pmd_is_huge(): # !pmd_present && !pmd_none -> TRUE (swap entry) + pmd_lock() -> # spin_lock(ptl), waits for Thread A to release ptl + pmdp_huge_get_and_clear_full() + VM_BUG_ON(!pmd_present(*pmdp)) # HITS! + +[ 287.738700][ T1867] ------------[ cut here ]------------ +[ 287.743843][ T1867] kernel BUG at arch/powerpc/mm/book3s64/pgtable.c:187! +cpu 0x0: Vector: 700 (Program Check) at [c00000044037f4f0] + pc: c000000000094ca4: pmdp_huge_get_and_clear_full+0x6c/0x23c + lr: c000000000645dec: zap_huge_pmd+0xb0/0x868 + sp: c00000044037f790 + msr: 800000000282b033 + current = 0xc0000004032c1a00 + paca = 0xc000000004fe0000 irqmask: 0x03 irq_happened: 0x09 + pid = 1867, comm = a.out +kernel BUG at :187! +Linux version 6.19.0-12136-g14360d4f917c-dirty (powerpc64le-linux-gnu-gcc (Debian 12.2.0-14) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #27 SMP PREEMPT Sun Feb 22 10:38:56 IST 2026 +enter ? for help +[link register ] c000000000645dec zap_huge_pmd+0xb0/0x868 +[c00000044037f790] c00000044037f7d0 (unreliable) +[c00000044037f7d0] c000000000645dcc zap_huge_pmd+0x90/0x868 +[c00000044037f840] c0000000005724cc unmap_page_range+0x176c/0x1f40 +[c00000044037fa00] c000000000572ea0 unmap_vmas+0xb0/0x1d8 +[c00000044037fa90] c0000000005af254 unmap_region+0xb4/0x128 +[c00000044037fb50] c0000000005af400 vms_complete_munmap_vmas+0x138/0x310 +[c00000044037fbe0] c0000000005b0f1c do_vmi_align_munmap+0x1ec/0x238 +[c00000044037fd30] c0000000005b3688 __vm_munmap+0x170/0x1f8 +[c00000044037fdf0] c000000000587f74 sys_munmap+0x2c/0x40 +[c00000044037fe10] c000000000032668 system_call_exception+0x128/0x350 +[c00000044037fe50] c00000000000d05c system_call_vectored_common+0x15c/0x2ec +---- Exception: 3000 (System Call Vectored) at 0000000010064a2c +SP (7fff9b1ee9c0) is in userspace +0:mon> zh + +commit a30b48bf1b24 ("mm/migrate_device: implement THP migration of zone device pages"), +enabled migration for device-private PMD entries. Hence this is one +other path where this warning could get trigger from. + + ------------[ cut here ]------------ + WARNING: arch/powerpc/mm/book3s64/hash_pgtable.c:199 at hash__pmd_hugepage_update+0x48/0x284, CPU#3: hmm-tests/1905 + Modules linked in: test_hmm + CPU: 3 UID: 0 PID: 1905 Comm: hmm-tests Tainted: G B W L N 7.0.0-rc1-01438-g7e2f0ee7581c #21 PREEMPT + Tainted: [B]=BAD_PAGE, [W]=WARN, [L]=SOFTLOCKUP, [N]=TEST + Hardware name: IBM pSeries (emulated by qemu) POWER10 (architected) 0x801200 0xf000006 of:SLOF,git-ee03ae pSeries + NIP [c000000000096b70] hash__pmd_hugepage_update+0x48/0x284 + LR [c000000000096e7c] hash__pmdp_huge_get_and_clear+0xd0/0xd4 + Call Trace: + [c000000604707670] [c000000004e102b8] 0xc000000004e102b8 (unreliable) + [c000000604707700] [c00000000064ec3c] set_pmd_migration_entry+0x414/0x498 + [c000000604707760] [c00000000063e5a4] migrate_vma_collect_pmd+0x12e8/0x16c4 + [c000000604707890] [c00000000059282c] walk_pgd_range+0x7fc/0xd2c + [c000000604707990] [c000000000592e40] __walk_page_range+0xe4/0x2ac + [c000000604707a10] [c000000000593534] walk_page_range_mm_unsafe+0x204/0x2a4 + [c000000604707ab0] [c00000000063af10] migrate_vma_setup+0x1dc/0x2e8 + [c000000604707b10] [c008000006a21838] dmirror_migrate_to_system.constprop.0+0x210/0x4b0 [test_hmm] + [c000000604707c30] [c008000006a245b0] dmirror_fops_unlocked_ioctl+0x454/0xa5c [test_hmm] + [c000000604707d20] [c0000000006aab84] sys_ioctl+0x4ec/0x1178 + [c000000604707e10] [c0000000000326a8] system_call_exception+0x128/0x350 + [c000000604707e50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec + ---- interrupt: 3000 at 0x7fffbe44f50c + +Fixes: 75358ea359e7c ("powerpc/mm/book3s64: Fix MADV_DONTNEED and parallel page fault race") +Fixes: a30b48bf1b24 ("mm/migrate_device: implement THP migration of zone device pages") +Reported-by: Pavithra Prakash +Signed-off-by: Ritesh Harjani (IBM) +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/9437e5ef28d1e2f5cbdd7f8286350ce93c1d43c5.1773078178.git.ritesh.list@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/book3s/64/pgtable.h | 15 +++++++++++++++ + arch/powerpc/mm/book3s64/pgtable.c | 13 +++++++++---- + 2 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h +index 1a91762b455d9..66a953046a49a 100644 +--- a/arch/powerpc/include/asm/book3s/64/pgtable.h ++++ b/arch/powerpc/include/asm/book3s/64/pgtable.h +@@ -1313,12 +1313,27 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, + { + pmd_t old_pmd; + ++ /* ++ * Non-present PMDs can be migration entries or device-private THP ++ * entries. This can happen at 2 places: ++ * - When the address space is being unmapped zap_huge_pmd(), and we ++ * encounter non-present pmds. ++ * - migrate_vma_collect_huge_pmd() could calls this during migration ++ * of device-private pmd entries. ++ */ ++ if (!pmd_present(*pmdp)) { ++ old_pmd = READ_ONCE(*pmdp); ++ pmd_clear(pmdp); ++ goto out; ++ } ++ + if (radix_enabled()) { + old_pmd = radix__pmdp_huge_get_and_clear(mm, addr, pmdp); + } else { + old_pmd = hash__pmdp_huge_get_and_clear(mm, addr, pmdp); + } + ++out: + page_table_check_pmd_clear(mm, addr, old_pmd); + + return old_pmd; +diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c +index 4b09c04654a8f..42c7906d0e436 100644 +--- a/arch/powerpc/mm/book3s64/pgtable.c ++++ b/arch/powerpc/mm/book3s64/pgtable.c +@@ -209,16 +209,21 @@ pmd_t pmdp_huge_get_and_clear_full(struct vm_area_struct *vma, + unsigned long addr, pmd_t *pmdp, int full) + { + pmd_t pmd; ++ bool was_present = pmd_present(*pmdp); ++ + VM_BUG_ON(addr & ~HPAGE_PMD_MASK); +- VM_BUG_ON((pmd_present(*pmdp) && !pmd_trans_huge(*pmdp)) || +- !pmd_present(*pmdp)); ++ VM_BUG_ON(was_present && !pmd_trans_huge(*pmdp)); ++ /* ++ * Check pmdp_huge_get_and_clear() for non-present pmd case. ++ */ + pmd = pmdp_huge_get_and_clear(vma->vm_mm, addr, pmdp); + /* + * if it not a fullmm flush, then we can possibly end up converting + * this PMD pte entry to a regular level 0 PTE by a parallel page fault. +- * Make sure we flush the tlb in this case. ++ * Make sure we flush the tlb in this case. TLB flush not needed for ++ * non-present case. + */ +- if (!full) ++ if (was_present && !full) + flush_pmd_tlb_range(vma, addr, addr + HPAGE_PMD_SIZE); + return pmd; + } +-- +2.53.0 + diff --git a/queue-7.0/powerpc-crash-fix-backup-region-offset-update-to-elf.patch b/queue-7.0/powerpc-crash-fix-backup-region-offset-update-to-elf.patch new file mode 100644 index 0000000000..b461bb5671 --- /dev/null +++ b/queue-7.0/powerpc-crash-fix-backup-region-offset-update-to-elf.patch @@ -0,0 +1,63 @@ +From 0cbad758310d734b3e5414e463a97bd07d4bef93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:49 +0530 +Subject: powerpc/crash: fix backup region offset update to elfcorehdr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sourabh Jain + +[ Upstream commit 789335cacdf37da93bb7c70322dff8c7e82881df ] + +update_backup_region_phdr() in file_load_64.c iterates over all the +program headers in the kdump kernel’s elfcorehdr and updates the +p_offset of the program header whose physical address starts at 0. + +However, the loop logic is incorrect because the program header pointer +is not updated during iteration. Since elfcorehdr typically contains +PT_NOTE entries first, the PT_LOAD program header with physical address +0 is never reached. As a result, its p_offset is not updated to point to +the backup region. + +Because of this behavior, the capture kernel exports the first 64 KB of +the crashed kernel’s memory at offset 0, even though that memory +actually lives in the backup region. When a crash happens, purgatory +copies the first 64 KB of the crashed kernel’s memory into the backup +region so the capture kernel can safely use it. + +This has not caused problems so far because the first 64 KB is usually +identical in both the crashed and capture kernels. However, this is +just an assumption and is not guaranteed to always hold true. + +Fix update_backup_region_phdr() to correctly update the p_offset of the +program header with a starting physical address of 0 by correcting the +logic used to iterate over the program headers. + +Fixes: cb350c1f1f86 ("powerpc/kexec_file: Prepare elfcore header for crashing kernel") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Reviewed-by: Hari Bathini +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-2-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kexec/file_load_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index 5f6d50e4c3d45..a7db7eca0481b 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -391,7 +391,7 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) + unsigned int i; + + phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++) { ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { + if (phdr->p_paddr == BACKUP_SRC_START) { + phdr->p_offset = image->arch.backup_start; + kexec_dprintk("Backup region offset updated to 0x%lx\n", +-- +2.53.0 + diff --git a/queue-7.0/powerpc-crash-update-backup-region-offset-in-elfcore.patch b/queue-7.0/powerpc-crash-update-backup-region-offset-in-elfcore.patch new file mode 100644 index 0000000000..147f1af554 --- /dev/null +++ b/queue-7.0/powerpc-crash-update-backup-region-offset-in-elfcore.patch @@ -0,0 +1,245 @@ +From 0a92a6d9066ddace334692281c5c7513fe5884c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 14:00:50 +0530 +Subject: powerpc/crash: Update backup region offset in elfcorehdr on memory + hotplug + +From: Sourabh Jain + +[ Upstream commit f53b24d1fa263f56155213eabab734c18d884aff ] + +When elfcorehdr is prepared for kdump, the program header representing +the first 64 KB of memory is expected to have its offset point to the +backup region. This is required because purgatory copies the first 64 KB +of the crashed kernel memory to this backup region following a kernel +crash. This allows the capture kernel to use the first 64 KB of memory +to place the exception vectors and other required data. + +When elfcorehdr is recreated due to memory hotplug, the offset of +the program header representing the first 64 KB is not updated. +As a result, the capture kernel exports the first 64 KB at offset +0, even though the data actually resides in the backup region. + +Fix this by calling sync_backup_region_phdr() to update the program +header offset in the elfcorehdr created during memory hotplug. + +sync_backup_region_phdr() works for images loaded via the +kexec_file_load syscall. However, it does not work for kexec_load, +because image->arch.backup_start is not initialized in that case. +So introduce machine_kexec_post_load() to process the elfcorehdr +prepared by kexec-tools and initialize image->arch.backup_start for +kdump images loaded via kexec_load syscall. + +Rename update_backup_region_phdr() to sync_backup_region_phdr() and +extend it to synchronize the backup region offset between the kdump +image and the ELF core header. The helper now supports updating either +the kdump image from the ELF program header or updating the ELF program +header from the kdump image, avoiding code duplication. + +Define ARCH_HAS_KIMAGE_ARCH and struct kimage_arch when +CONFIG_KEXEC_FILE or CONFIG_CRASH_DUMP is enabled so that +kimage->arch.backup_start is available with the kexec_load system call. + +This patch depends on the patch titled +"powerpc/crash: fix backup region offset update to elfcorehdr". + +Fixes: 849599b702ef ("powerpc/crash: add crash memory hotplug support") +Reviewed-by: Aditya Gupta +Signed-off-by: Sourabh Jain +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260312083051.1935737-3-sourabhjain@linux.ibm.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/kexec.h | 14 +++++-- + arch/powerpc/kexec/crash.c | 64 +++++++++++++++++++++++++++++++ + arch/powerpc/kexec/file_load_64.c | 29 +------------- + 3 files changed, 76 insertions(+), 31 deletions(-) + +diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h +index bd4a6c42a5f38..e02710d6a2e1a 100644 +--- a/arch/powerpc/include/asm/kexec.h ++++ b/arch/powerpc/include/asm/kexec.h +@@ -66,11 +66,9 @@ void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_co + unsigned long start_address) __noreturn; + void kexec_copy_flush(struct kimage *image); + +-#ifdef CONFIG_KEXEC_FILE +-extern const struct kexec_file_ops kexec_elf64_ops; + ++#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP) + #define ARCH_HAS_KIMAGE_ARCH +- + struct kimage_arch { + struct crash_mem *exclude_ranges; + +@@ -78,6 +76,10 @@ struct kimage_arch { + void *backup_buf; + void *fdt; + }; ++#endif ++ ++#ifdef CONFIG_KEXEC_FILE ++extern const struct kexec_file_ops kexec_elf64_ops; + + char *setup_kdump_cmdline(struct kimage *image, char *cmdline, + unsigned long cmdline_len); +@@ -145,6 +147,10 @@ int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags); + + unsigned int arch_crash_get_elfcorehdr_size(void); + #define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size ++ ++int machine_kexec_post_load(struct kimage *image); ++#define machine_kexec_post_load machine_kexec_post_load ++ + #endif /* CONFIG_CRASH_HOTPLUG */ + + extern int crashing_cpu; +@@ -159,6 +165,8 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs); + extern void crash_kexec_prepare(void); + extern void crash_kexec_secondary(struct pt_regs *regs); + ++extern void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, ++ bool phdr_to_kimage); + static inline bool kdump_in_progress(void) + { + return crashing_cpu >= 0; +diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c +index a325c1c02f96d..e6539f213b3d1 100644 +--- a/arch/powerpc/kexec/crash.c ++++ b/arch/powerpc/kexec/crash.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + /* + * The primary CPU waits a while for all secondary CPUs to enter. This is to +@@ -399,7 +400,68 @@ void default_machine_crash_shutdown(struct pt_regs *regs) + ppc_md.kexec_cpu_down(1, 0); + } + ++#ifdef CONFIG_CRASH_DUMP ++/** ++ * sync_backup_region_phdr - synchronize backup region offset between ++ * kexec image and ELF core header. ++ * @image: Kexec image. ++ * @ehdr: ELF core header. ++ * @phdr_to_kimage: If true, read the offset from the ELF program header ++ * and update the kimage backup region. If false, update ++ * the ELF program header offset from the kimage backup ++ * region. ++ * ++ * Note: During kexec_load, this is called with phdr_to_kimage = true. For ++ * kexec_file_load and ELF core header recreation during memory hotplug ++ * events, it is called with phdr_to_kimage = false. ++ * ++ * Returns nothing. ++ */ ++void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, bool phdr_to_kimage) ++{ ++ Elf64_Phdr *phdr; ++ unsigned int i; ++ ++ phdr = (Elf64_Phdr *)(ehdr + 1); ++ for (i = 0; i < ehdr->e_phnum; i++, phdr++) { ++ if (phdr->p_paddr == BACKUP_SRC_START) { ++ if (phdr_to_kimage) ++ image->arch.backup_start = phdr->p_offset; ++ else ++ phdr->p_offset = image->arch.backup_start; ++ ++ kexec_dprintk("Backup region offset updated to 0x%lx\n", ++ image->arch.backup_start); ++ return; ++ } ++ } ++} ++#endif /* CONFIG_CRASH_DUMP */ ++ + #ifdef CONFIG_CRASH_HOTPLUG ++ ++int machine_kexec_post_load(struct kimage *image) ++{ ++ int i; ++ unsigned long mem; ++ unsigned char *ptr; ++ ++ if (image->type != KEXEC_TYPE_CRASH) ++ return 0; ++ ++ if (image->file_mode) ++ return 0; ++ ++ for (i = 0; i < image->nr_segments; i++) { ++ mem = image->segment[i].mem; ++ ptr = (char *)__va(mem); ++ ++ if (ptr && memcmp(ptr, ELFMAG, SELFMAG) == 0) ++ sync_backup_region_phdr(image, (Elf64_Ehdr *) ptr, true); ++ } ++ return 0; ++} ++ + #undef pr_fmt + #define pr_fmt(fmt) "crash hp: " fmt + +@@ -474,6 +536,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify * + goto out; + } + ++ sync_backup_region_phdr(image, (Elf64_Ehdr *) elfbuf, false); ++ + ptr = __va(mem); + if (ptr) { + /* Temporarily invalidate the crash image while it is replaced */ +diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c +index a7db7eca0481b..8c72e12ea44e5 100644 +--- a/arch/powerpc/kexec/file_load_64.c ++++ b/arch/powerpc/kexec/file_load_64.c +@@ -374,33 +374,6 @@ static int load_backup_segment(struct kimage *image, struct kexec_buf *kbuf) + return 0; + } + +-/** +- * update_backup_region_phdr - Update backup region's offset for the core to +- * export the region appropriately. +- * @image: Kexec image. +- * @ehdr: ELF core header. +- * +- * Assumes an exclusive program header is setup for the backup region +- * in the ELF headers +- * +- * Returns nothing. +- */ +-static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) +-{ +- Elf64_Phdr *phdr; +- unsigned int i; +- +- phdr = (Elf64_Phdr *)(ehdr + 1); +- for (i = 0; i < ehdr->e_phnum; i++, phdr++) { +- if (phdr->p_paddr == BACKUP_SRC_START) { +- phdr->p_offset = image->arch.backup_start; +- kexec_dprintk("Backup region offset updated to 0x%lx\n", +- image->arch.backup_start); +- return; +- } +- } +-} +- + static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem) + { + #if defined(CONFIG_CRASH_HOTPLUG) && defined(CONFIG_MEMORY_HOTPLUG) +@@ -445,7 +418,7 @@ static int load_elfcorehdr_segment(struct kimage *image, struct kexec_buf *kbuf) + } + + /* Fix the offset for backup region in the ELF header */ +- update_backup_region_phdr(image, headers); ++ sync_backup_region_phdr(image, headers, false); + + kbuf->buffer = headers; + kbuf->mem = KEXEC_BUF_MEM_UNKNOWN; +-- +2.53.0 + diff --git a/queue-7.0/powerpc-pgtable-frag-fix-bad-page-state-in-pte_frag_.patch b/queue-7.0/powerpc-pgtable-frag-fix-bad-page-state-in-pte_frag_.patch new file mode 100644 index 0000000000..379283f384 --- /dev/null +++ b/queue-7.0/powerpc-pgtable-frag-fix-bad-page-state-in-pte_frag_.patch @@ -0,0 +1,89 @@ +From 30bcf758d5cded0e215c444bc329c5aa7d627e6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 23:44:24 +0530 +Subject: powerpc/pgtable-frag: Fix bad page state in pte_frag_destroy + +From: Ritesh Harjani (IBM) + +[ Upstream commit fda4d71651f71c44b35829d13f3c8bf920032f77 ] + +powerpc uses pt_frag_refcount as a reference counter for tracking it's +pte and pmd page table fragments. For PTE table, in case of Hash with +64K pagesize, we have 16 fragments of 4K size in one 64K page. + +Patch series [1] "mm: free retracted page table by RCU" +added pte_free_defer() to defer the freeing of PTE tables when +retract_page_tables() is called for madvise MADV_COLLAPSE on shmem +range. +[1]: https://lore.kernel.org/all/7cd843a9-aa80-14f-5eb2-33427363c20@google.com/ + +pte_free_defer() sets the active flag on the corresponding fragment's +folio & calls pte_fragment_free(), which reduces the pt_frag_refcount. +When pt_frag_refcount reaches 0 (no active fragment using the folio), it +checks if the folio active flag is set, if set, it calls call_rcu to +free the folio, it the active flag is unset then it calls pte_free_now(). + +Now, this can lead to following problem in a corner case... + +[ 265.351553][ T183] BUG: Bad page state in process a.out pfn:20d62 +[ 265.353555][ T183] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x20d62 +[ 265.355457][ T183] flags: 0x3ffff800000100(active|node=0|zone=0|lastcpupid=0x7ffff) +[ 265.358719][ T183] raw: 003ffff800000100 0000000000000000 5deadbeef0000122 0000000000000000 +[ 265.360177][ T183] raw: 0000000000000000 c0000000119caf58 00000000ffffffff 0000000000000000 +[ 265.361438][ T183] page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set +[ 265.362572][ T183] Modules linked in: +[ 265.364622][ T183] CPU: 0 UID: 0 PID: 183 Comm: a.out Not tainted 6.18.0-rc3-00141-g1ddeaaace7ff-dirty #53 VOLUNTARY +[ 265.364785][ T183] Hardware name: IBM pSeries (emulated by qemu) POWER10 (architected) 0x801200 0xf000006 of:SLOF,git-ee03ae pSeries +[ 265.364908][ T183] Call Trace: +[ 265.364955][ T183] [c000000011e6f7c0] [c000000001cfaa18] dump_stack_lvl+0x130/0x148 (unreliable) +[ 265.365202][ T183] [c000000011e6f7f0] [c000000000794758] bad_page+0xb4/0x1c8 +[ 265.365384][ T183] [c000000011e6f890] [c00000000079c020] __free_frozen_pages+0x838/0xd08 +[ 265.365554][ T183] [c000000011e6f980] [c0000000000a70ac] pte_frag_destroy+0x298/0x310 +[ 265.365729][ T183] [c000000011e6fa30] [c0000000000aa764] arch_exit_mmap+0x34/0x218 +[ 265.365912][ T183] [c000000011e6fa80] [c000000000751698] exit_mmap+0xb8/0x820 +[ 265.366080][ T183] [c000000011e6fc30] [c0000000001b1258] __mmput+0x98/0x300 +[ 265.366244][ T183] [c000000011e6fc80] [c0000000001c81f8] do_exit+0x470/0x1508 +[ 265.366421][ T183] [c000000011e6fd70] [c0000000001c95e4] do_group_exit+0x88/0x148 +[ 265.366602][ T183] [c000000011e6fdc0] [c0000000001c96ec] pid_child_should_wake+0x0/0x178 +[ 265.366780][ T183] [c000000011e6fdf0] [c00000000003a270] system_call_exception+0x1b0/0x4e0 +[ 265.366958][ T183] [c000000011e6fe50] [c00000000000d05c] system_call_vectored_common+0x15c/0x2ec + +The bad page state error occurs when such a folio gets freed (with +active flag set), from do_exit() path in parallel. + +... this can happen when the pte fragment was allocated from this folio, +but when all the fragments get freed, the pte_frag_refcount still had some +unused fragments. Now, if this process exits, with such folio as it's cached +pte_frag in mm->context, then during pte_frag_destroy(), we simply call +pagetable_dtor() and pagetable_free(), meaning it doesn't clear the +active flag. This, can lead to the above bug. Since we are anyway in +do_exit() path, then if the refcount is 0, then I guess it should be +ok to simply clear the folio active flag before calling pagetable_dtor() +& pagetable_free(). + +Fixes: 32cc0b7c9d50 ("powerpc: add pte_free_defer() for pgtables sharing page") +Reviewed-by: Christophe Leroy (CS GROUP) +Signed-off-by: Ritesh Harjani (IBM) +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/ee13e7f99b8f258019da2b37655b998e73e5ef8b.1773078178.git.ritesh.list@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/mm/pgtable-frag.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/powerpc/mm/pgtable-frag.c b/arch/powerpc/mm/pgtable-frag.c +index 77e55eac16e42..ae742564a3d56 100644 +--- a/arch/powerpc/mm/pgtable-frag.c ++++ b/arch/powerpc/mm/pgtable-frag.c +@@ -25,6 +25,7 @@ void pte_frag_destroy(void *pte_frag) + count = ((unsigned long)pte_frag & ~PAGE_MASK) >> PTE_FRAG_SIZE_SHIFT; + /* We allow PTE_FRAG_NR fragments from a PTE page */ + if (atomic_sub_and_test(PTE_FRAG_NR - count, &ptdesc->pt_frag_refcount)) { ++ folio_clear_active(ptdesc_folio(ptdesc)); + pagetable_dtor(ptdesc); + pagetable_free(ptdesc); + } +-- +2.53.0 + diff --git a/queue-7.0/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch b/queue-7.0/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch new file mode 100644 index 0000000000..a99162f6c6 --- /dev/null +++ b/queue-7.0/ppp-require-cap_net_admin-in-target-netns-for-unatta.patch @@ -0,0 +1,50 @@ +From e50d4a86b18fac2bbc74e41ff416903da4702b5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 16:11:15 +0900 +Subject: ppp: require CAP_NET_ADMIN in target netns for unattached ioctls + +From: Taegu Ha + +[ Upstream commit 2bb6379416fd19f44c3423a00bfd8626259f6067 ] + +/dev/ppp open is currently authorized against file->f_cred->user_ns, +while unattached administrative ioctls operate on current->nsproxy->net_ns. + +As a result, a local unprivileged user can create a new user namespace +with CLONE_NEWUSER, gain CAP_NET_ADMIN only in that new user namespace, +and still issue PPPIOCNEWUNIT, PPPIOCATTACH, or PPPIOCATTCHAN against +an inherited network namespace. + +Require CAP_NET_ADMIN in the user namespace that owns the target network +namespace before handling unattached PPP administrative ioctls. + +This preserves normal pppd operation in the network namespace it is +actually privileged in, while rejecting the userns-only inherited-netns +case. + +Fixes: 273ec51dd7ce ("net: ppp_generic - introduce net-namespace functionality v2") +Signed-off-by: Taegu Ha +Link: https://patch.msgid.link/20260409071117.4354-1-hataegu0826@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index e9b41777be809..c2024684b10d5 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1057,6 +1057,9 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct ppp_net *pn; + int __user *p = (int __user *)arg; + ++ if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ + switch (cmd) { + case PPPIOCNEWUNIT: + /* Create a new ppp unit */ +-- +2.53.0 + diff --git a/queue-7.0/pppoe-drop-pfc-frames.patch b/queue-7.0/pppoe-drop-pfc-frames.patch new file mode 100644 index 0000000000..2280cc2365 --- /dev/null +++ b/queue-7.0/pppoe-drop-pfc-frames.patch @@ -0,0 +1,112 @@ +From 056634018b89ced7ffdb2d48431e83b4b00a7e69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 10:24:51 +0800 +Subject: pppoe: drop PFC frames + +From: Qingfang Deng + +[ Upstream commit cc1ff87bce1ccd38410ab10960f576dcd17db679 ] + +RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT +RECOMMENDED for PPPoE. In practice, pppd does not support negotiating +PFC for PPPoE sessions, and the current PPPoE driver assumes an +uncompressed (2-byte) protocol field. However, the generic PPP layer +function ppp_input() is not aware of the negotiation result, and still +accepts PFC frames. + +If a peer with a broken implementation or an attacker sends a frame with +a compressed (1-byte) protocol field, the subsequent PPP payload is +shifted by one byte. This causes the network header to be 4-byte +misaligned, which may trigger unaligned access exceptions on some +architectures. + +To reduce the attack surface, drop PPPoE PFC frames. Introduce +ppp_skb_is_compressed_proto() helper function to be used in both +ppp_generic.c and pppoe.c to avoid open-coding. + +Fixes: 7fb1b8ca8fa1 ("ppp: Move PFC decompression to PPP generic layer") +Signed-off-by: Qingfang Deng +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415022456.141758-2-qingfang.deng@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ppp/ppp_generic.c | 2 +- + drivers/net/ppp/pppoe.c | 8 +++++++- + include/linux/ppp_defs.h | 16 ++++++++++++++++ + 3 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index c2024684b10d5..192a5b94783e3 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -2260,7 +2260,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + */ + static void __ppp_decompress_proto(struct sk_buff *skb) + { +- if (skb->data[0] & 0x01) ++ if (ppp_skb_is_compressed_proto(skb)) + *(u8 *)skb_push(skb, 1) = 0x00; + } + +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index 4275b393a4544..6992b3f647819 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -424,7 +424,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb_mac_header_len(skb) < ETH_HLEN) + goto drop; + +- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) ++ if (!pskb_may_pull(skb, PPPOE_SES_HLEN)) + goto drop; + + ph = pppoe_hdr(skb); +@@ -434,6 +434,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + if (skb->len < len) + goto drop; + ++ /* skb->data points to the PPP protocol header after skb_pull_rcsum. ++ * Drop PFC frames. ++ */ ++ if (ppp_skb_is_compressed_proto(skb)) ++ goto drop; ++ + if (pskb_trim_rcsum(skb, len)) + goto drop; + +diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h +index b7e57fdbd4139..b1d1f46d7d3be 100644 +--- a/include/linux/ppp_defs.h ++++ b/include/linux/ppp_defs.h +@@ -8,6 +8,7 @@ + #define _PPP_DEFS_H_ + + #include ++#include + #include + + #define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) +@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) + return !!((proto & 0x0101) == 0x0001); + } + ++/** ++ * ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed ++ * @skb: skb to check ++ * ++ * Check if the PPP protocol field is compressed (the least significant ++ * bit of the most significant octet is 1). skb->data must point to the PPP ++ * protocol header. ++ * ++ * Return: Whether the PPP protocol field is compressed. ++ */ ++static inline bool ppp_skb_is_compressed_proto(const struct sk_buff *skb) ++{ ++ return unlikely(skb->data[0] & 0x01); ++} ++ + #endif /* _PPP_DEFS_H_ */ +-- +2.53.0 + diff --git a/queue-7.0/printk_ringbuffer-fix-get_data-size-sanity-check.patch b/queue-7.0/printk_ringbuffer-fix-get_data-size-sanity-check.patch new file mode 100644 index 0000000000..83812d5973 --- /dev/null +++ b/queue-7.0/printk_ringbuffer-fix-get_data-size-sanity-check.patch @@ -0,0 +1,74 @@ +From 3ebc12100dcf1a3c6678cdfd639dcc64725b6498 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 14:44:01 +0106 +Subject: printk_ringbuffer: Fix get_data() size sanity check + +From: John Ogness + +[ Upstream commit 8e81ecbf1cb46b8d2d13e772d5924b09bd60169a ] + +Commit cc3bad11de6e ("printk_ringbuffer: Fix check of valid data +size when blk_lpos overflows") added sanity checking to get_data() +to avoid returning data of illegal sizes (too large or too small). +It uses the helper function data_check_size() for the check. +However, data_check_size() expects the size of the data, not the +size of the data block. get_data() is providing the size of the +data block. This means that if the data size (text_buf_size) is +at or near the maximum legal size: + +sizeof(prb_data_block) + text_buf_size == DATA_SIZE(data_ring) / 2 + +data_check_size() will report failure because it adds +sizeof(prb_data_block) to the provided size. The sanity check in +get_data() is counting the data block header twice. The result is +that the reader fails to read the legal record. + +Since get_data() subtracts the data block header size before returning, +move the sanity check to after the subtraction. + +Luckily printk() is not vulnerable to this problem because +truncate_msg() limits printk-messages to 1/4 of the ringbuffer. +Indeed, by adjusting the printk_ringbuffer KUnit test, which does not +use printk() and its truncate_msg() check, it is easy to see that the +reader fails and the WARN_ON is triggered. + +Fixes: cc3bad11de6e ("printk_ringbuffer: Fix check of valid data size when blk_lpos overflows") +Signed-off-by: John Ogness +Reviewed-by: Petr Mladek +Tested-by: Petr Mladek +Link: https://patch.msgid.link/20260326133809.8045-1-john.ogness@linutronix.de +Signed-off-by: Petr Mladek +Signed-off-by: Sasha Levin +--- + kernel/printk/printk_ringbuffer.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index 56c8e3d031f49..a3526bdd4e10d 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -1302,10 +1302,6 @@ static const char *get_data(struct prb_data_ring *data_ring, + return NULL; + } + +- /* Sanity check. Data-less blocks were handled earlier. */ +- if (WARN_ON_ONCE(!data_check_size(data_ring, *data_size) || !*data_size)) +- return NULL; +- + /* A valid data block will always be aligned to the ID size. */ + if (WARN_ON_ONCE(blk_lpos->begin != ALIGN(blk_lpos->begin, sizeof(db->id))) || + WARN_ON_ONCE(blk_lpos->next != ALIGN(blk_lpos->next, sizeof(db->id)))) { +@@ -1319,6 +1315,10 @@ static const char *get_data(struct prb_data_ring *data_ring, + /* Subtract block ID space from size to reflect data size. */ + *data_size -= sizeof(db->id); + ++ /* Sanity check the max size of the regular data block. */ ++ if (WARN_ON_ONCE(!data_check_size(data_ring, *data_size))) ++ return NULL; ++ + return &db->data[0]; + } + +-- +2.53.0 + diff --git a/queue-7.0/pstore-ram-fix-resource-leak-when-ioremap-fails.patch b/queue-7.0/pstore-ram-fix-resource-leak-when-ioremap-fails.patch new file mode 100644 index 0000000000..e9b12aca33 --- /dev/null +++ b/queue-7.0/pstore-ram-fix-resource-leak-when-ioremap-fails.patch @@ -0,0 +1,52 @@ +From 403c2a714cebb4cfb6fe2ad888b5e163003a2756 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 16:54:06 -0700 +Subject: pstore/ram: fix resource leak when ioremap() fails + +From: Cole Leavitt + +[ Upstream commit 2ddb69f686ef7a621645e97fc7329c50edf5d0e5 ] + +In persistent_ram_iomap(), ioremap() or ioremap_wc() may return NULL on +failure. Currently, if this happens, the function returns NULL without +releasing the memory region acquired by request_mem_region(). + +This leads to a resource leak where the memory region remains reserved +but unusable. + +Additionally, the caller persistent_ram_buffer_map() handles NULL +correctly by returning -ENOMEM, but without this check, a NULL return +combined with request_mem_region() succeeding leaves resources in an +inconsistent state. + +This is the ioremap() counterpart to commit 05363abc7625 ("pstore: +ram_core: fix incorrect success return when vmap() fails") which fixed +a similar issue in the vmap() path. + +Fixes: 404a6043385d ("staging: android: persistent_ram: handle reserving and mapping memory") +Signed-off-by: Cole Leavitt +Link: https://patch.msgid.link/20260225235406.11790-1-cole@unwrap.rs +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + fs/pstore/ram_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c +index ed97494abf60f..0713ef986c204 100644 +--- a/fs/pstore/ram_core.c ++++ b/fs/pstore/ram_core.c +@@ -488,6 +488,10 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, + else + va = ioremap_wc(start, size); + ++ /* We must release the mem region if ioremap fails. */ ++ if (!va) ++ release_mem_region(start, size); ++ + /* + * Since request_mem_region() and ioremap() are byte-granularity + * there is no need handle anything special like we do when the +-- +2.53.0 + diff --git a/queue-7.0/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch b/queue-7.0/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch new file mode 100644 index 0000000000..39426617bd --- /dev/null +++ b/queue-7.0/pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch @@ -0,0 +1,139 @@ +From cef1a511eb76301158bc11786a365bb33b7adcca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Apr 2026 17:08:38 +0900 +Subject: pwm: atmel-tcb: Cache clock rates and mark chip as atomic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sangyun Kim + +[ Upstream commit 68637b68afcc3cb4d56aca14a3a1d1b47b879369 ] + +atmel_tcb_pwm_apply() holds tcbpwmc->lock as a spinlock via +guard(spinlock)() and then calls atmel_tcb_pwm_config(), which calls +clk_get_rate() twice. clk_get_rate() acquires clk_prepare_lock (a +mutex), so this is a sleep-in-atomic-context violation. + +On CONFIG_DEBUG_ATOMIC_SLEEP kernels every pwm_apply_state() that +enables or reconfigures the PWM triggers a "BUG: sleeping function +called from invalid context" warning. + +Acquire exclusive control over the clock rates with +clk_rate_exclusive_get() at probe time and cache the rates in struct +atmel_tcb_pwm_chip, then read the cached rates from +atmel_tcb_pwm_config(). This keeps the spinlock-based mutual exclusion +introduced in commit 37f7707077f5 ("pwm: atmel-tcb: Fix race condition +and convert to guards") and removes the sleeping calls from the atomic +section. + +With no sleeping calls left in .apply() and the regmap-mmio bus already +running with fast_io=true, also mark the chip as atomic so consumers +can use pwm_apply_atomic() from atomic context. + +Fixes: 37f7707077f5 ("pwm: atmel-tcb: Fix race condition and convert to guards") +Signed-off-by: Sangyun Kim +Link: https://patch.msgid.link/20260419080838.3192357-1-sangyun.kim@snu.ac.kr +[ukleinek: Ensure .clk is enabled before calling clk_get_rate on it.] +Signed-off-by: Uwe Kleine-König +Signed-off-by: Sasha Levin +--- + drivers/pwm/pwm-atmel-tcb.c | 38 +++++++++++++++++++++++++++++++++---- + 1 file changed, 34 insertions(+), 4 deletions(-) + +diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c +index f9ff78ba122d4..3d30aeab507e0 100644 +--- a/drivers/pwm/pwm-atmel-tcb.c ++++ b/drivers/pwm/pwm-atmel-tcb.c +@@ -50,6 +50,8 @@ struct atmel_tcb_pwm_chip { + spinlock_t lock; + u8 channel; + u8 width; ++ unsigned long rate; ++ unsigned long slow_rate; + struct regmap *regmap; + struct clk *clk; + struct clk *gclk; +@@ -266,7 +268,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int slowclk = 0; + unsigned period; + unsigned duty; +- unsigned rate = clk_get_rate(tcbpwmc->clk); ++ unsigned long rate = tcbpwmc->rate; + unsigned long long min; + unsigned long long max; + +@@ -294,7 +296,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + */ + if (i == ARRAY_SIZE(atmel_tcb_divisors)) { + i = slowclk; +- rate = clk_get_rate(tcbpwmc->slow_clk); ++ rate = tcbpwmc->slow_rate; + min = div_u64(NSEC_PER_SEC, rate); + max = min << tcbpwmc->width; + +@@ -431,24 +433,49 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) + } + + chip->ops = &atmel_tcb_pwm_ops; ++ chip->atomic = true; + tcbpwmc->channel = channel; + tcbpwmc->width = config->counter_width; + +- err = clk_prepare_enable(tcbpwmc->slow_clk); ++ err = clk_prepare_enable(tcbpwmc->clk); + if (err) + goto err_gclk; + ++ err = clk_prepare_enable(tcbpwmc->slow_clk); ++ if (err) ++ goto err_disable_clk;; ++ ++ err = clk_rate_exclusive_get(tcbpwmc->clk); ++ if (err) ++ goto err_disable_slow_clk; ++ ++ err = clk_rate_exclusive_get(tcbpwmc->slow_clk); ++ if (err) ++ goto err_clk_unlock; ++ ++ tcbpwmc->rate = clk_get_rate(tcbpwmc->clk); ++ tcbpwmc->slow_rate = clk_get_rate(tcbpwmc->slow_clk); ++ + spin_lock_init(&tcbpwmc->lock); + + err = pwmchip_add(chip); + if (err < 0) +- goto err_disable_clk; ++ goto err_slow_clk_unlock; + + platform_set_drvdata(pdev, chip); + + return 0; + ++err_slow_clk_unlock: ++ clk_rate_exclusive_put(tcbpwmc->slow_clk); ++ ++err_clk_unlock: ++ clk_rate_exclusive_put(tcbpwmc->clk); ++ + err_disable_clk: ++ clk_disable_unprepare(tcbpwmc->clk); ++ ++err_disable_slow_clk: + clk_disable_unprepare(tcbpwmc->slow_clk); + + err_gclk: +@@ -470,6 +497,9 @@ static void atmel_tcb_pwm_remove(struct platform_device *pdev) + + pwmchip_remove(chip); + ++ clk_rate_exclusive_put(tcbpwmc->slow_clk); ++ clk_rate_exclusive_put(tcbpwmc->clk); ++ clk_disable_unprepare(tcbpwmc->clk); + clk_disable_unprepare(tcbpwmc->slow_clk); + clk_put(tcbpwmc->gclk); + clk_put(tcbpwmc->clk); +-- +2.53.0 + diff --git a/queue-7.0/pwm-stm32-fix-rounding-issue-for-requests-with-inver.patch b/queue-7.0/pwm-stm32-fix-rounding-issue-for-requests-with-inver.patch new file mode 100644 index 0000000000..7fea42a0a3 --- /dev/null +++ b/queue-7.0/pwm-stm32-fix-rounding-issue-for-requests-with-inver.patch @@ -0,0 +1,103 @@ +From d50d9730c8a5e89455ea83e92298d63d6e57869f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 16:50:12 +0200 +Subject: pwm: stm32: Fix rounding issue for requests with inverted polarity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 5d087c485b6ecf200a9ebb2a032bf8571d330250 ] + +The calculation of the number of pwm clk ticks from a time length in +nanoseconds involves a division and thus some rounding. That might +result in + + duty_ticks + offset_ticks < period_ticks + +despite + + duty_length_ns + duty_offset_ns >= period_length_ns + +. The stm32 PWM cannot configure offset_ticks freely, it can only select +0 or period_length_ns - duty_length_ns---that is the classic normal and +inverted polarity. The decision to select the hardware polarity must be +done using the ticks values and not the nanoseconds times to adhere to +the rounding rules by the pwm core. + +With the pwm clk running at 208900 kHz on my test machine +(stm32mp135f-dk), a test case that was handled wrong is: + + # pwmround -P 9999962 -O 24970 -D 9974992 + period_length = 9999962 + duty_length = 9974840 + duty_offset = 25123 + +With this change applied the rounding is done correctly: + + # pwmround -P 9999962 -O 24970 -D 9974992 + period_length = 9999962 + duty_length = 9974840 + duty_offset = 0 + +Fixes: deaba9cff809 ("pwm: stm32: Implementation of the waveform callbacks") +Signed-off-by: Uwe Kleine-König +Link: https://patch.msgid.link/c5e7767cee821b5f6e00f95bd14a5e13015646fb.1776264104.git.u.kleine-koenig@baylibre.com +Signed-off-by: Uwe Kleine-König +Signed-off-by: Sasha Levin +--- + drivers/pwm/pwm-stm32.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c +index 2594fb771b04a..935257a890b06 100644 +--- a/drivers/pwm/pwm-stm32.c ++++ b/drivers/pwm/pwm-stm32.c +@@ -68,7 +68,7 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip, + struct stm32_pwm *priv = to_stm32_pwm_dev(chip); + unsigned int ch = pwm->hwpwm; + unsigned long rate; +- u64 ccr, duty; ++ u64 duty_ticks, offset_ticks; + int ret; + + if (wf->period_length_ns == 0) { +@@ -164,23 +164,25 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip, + wfhw->arr = min_t(u64, arr, priv->max_arr) - 1; + } + +- duty = mul_u64_u64_div_u64(wf->duty_length_ns, rate, +- (u64)NSEC_PER_SEC * (wfhw->psc + 1)); +- duty = min_t(u64, duty, wfhw->arr + 1); ++ duty_ticks = mul_u64_u64_div_u64(wf->duty_length_ns, rate, ++ (u64)NSEC_PER_SEC * (wfhw->psc + 1)); ++ duty_ticks = min_t(u64, duty_ticks, wfhw->arr + 1); + +- if (wf->duty_length_ns && wf->duty_offset_ns && +- wf->duty_length_ns + wf->duty_offset_ns >= wf->period_length_ns) { ++ offset_ticks = mul_u64_u64_div_u64(wf->duty_offset_ns, rate, ++ (u64)NSEC_PER_SEC * (wfhw->psc + 1)); ++ offset_ticks = min_t(u64, offset_ticks, wfhw->arr + 1); ++ ++ if (duty_ticks && offset_ticks && ++ duty_ticks + offset_ticks >= wfhw->arr + 1) { + wfhw->ccer |= TIM_CCER_CCxP(ch + 1); + if (priv->have_complementary_output) + wfhw->ccer |= TIM_CCER_CCxNP(ch + 1); + +- ccr = wfhw->arr + 1 - duty; ++ wfhw->ccr = wfhw->arr + 1 - duty_ticks; + } else { +- ccr = duty; ++ wfhw->ccr = duty_ticks; + } + +- wfhw->ccr = min_t(u64, ccr, wfhw->arr + 1); +- + out: + dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> CCER: %08x, PSC: %08x, ARR: %08x, CCR: %08x\n", + pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, +-- +2.53.0 + diff --git a/queue-7.0/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch b/queue-7.0/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch new file mode 100644 index 0000000000..e651f5629d --- /dev/null +++ b/queue-7.0/quota-fix-race-of-dquot_scan_active-with-quota-deact.patch @@ -0,0 +1,148 @@ +From d1ffc831b85321fa8b823f6839a6d9af7656ee9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 14:22:16 +0100 +Subject: quota: Fix race of dquot_scan_active() with quota deactivation + +From: Jan Kara + +[ Upstream commit e93ab401da4b2e2c1b8ef2424de2f238d51c8b2d ] + +dquot_scan_active() can race with quota deactivation in +quota_release_workfn() like: + + CPU0 (quota_release_workfn) CPU1 (dquot_scan_active) + ============================== ============================== + spin_lock(&dq_list_lock); + list_replace_init( + &releasing_dquots, &rls_head); + /* dquot X on rls_head, + dq_count == 0, + DQ_ACTIVE_B still set */ + spin_unlock(&dq_list_lock); + synchronize_srcu(&dquot_srcu); + spin_lock(&dq_list_lock); + list_for_each_entry(dquot, + &inuse_list, dq_inuse) { + /* finds dquot X */ + dquot_active(X) -> true + atomic_inc(&X->dq_count); + } + spin_unlock(&dq_list_lock); + spin_lock(&dq_list_lock); + dquot = list_first_entry(&rls_head); + WARN_ON_ONCE(atomic_read(&dquot->dq_count)); + +The problem is not only a cosmetic one as under memory pressure the +caller of dquot_scan_active() can end up working on freed dquot. + +Fix the problem by making sure the dquot is removed from releasing list +when we acquire a reference to it. + +Fixes: 869b6ea1609f ("quota: Fix slow quotaoff") +Reported-by: Sam Sun +Link: https://lore.kernel.org/all/CAEkJfYPTt3uP1vAYnQ5V2ZWn5O9PLhhGi5HbOcAzyP9vbXyjeg@mail.gmail.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/dquot.c | 38 ++++++++++++++++++++++++++++++-------- + include/linux/quotaops.h | 9 +-------- + 2 files changed, 31 insertions(+), 16 deletions(-) + +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 376739f6420ed..64cf427214965 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -363,6 +363,31 @@ static inline int dquot_active(struct dquot *dquot) + return test_bit(DQ_ACTIVE_B, &dquot->dq_flags); + } + ++static struct dquot *__dqgrab(struct dquot *dquot) ++{ ++ lockdep_assert_held(&dq_list_lock); ++ if (!atomic_read(&dquot->dq_count)) ++ remove_free_dquot(dquot); ++ atomic_inc(&dquot->dq_count); ++ return dquot; ++} ++ ++/* ++ * Get reference to dquot when we got pointer to it by some other means. The ++ * dquot has to be active and the caller has to make sure it cannot get ++ * deactivated under our hands. ++ */ ++struct dquot *dqgrab(struct dquot *dquot) ++{ ++ spin_lock(&dq_list_lock); ++ WARN_ON_ONCE(!dquot_active(dquot)); ++ dquot = __dqgrab(dquot); ++ spin_unlock(&dq_list_lock); ++ ++ return dquot; ++} ++EXPORT_SYMBOL_GPL(dqgrab); ++ + static inline int dquot_dirty(struct dquot *dquot) + { + return test_bit(DQ_MOD_B, &dquot->dq_flags); +@@ -641,15 +666,14 @@ int dquot_scan_active(struct super_block *sb, + continue; + if (dquot->dq_sb != sb) + continue; +- /* Now we have active dquot so we can just increase use count */ +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqput(old_dquot); + old_dquot = dquot; + /* + * ->release_dquot() can be racing with us. Our reference +- * protects us from new calls to it so just wait for any +- * outstanding call and recheck the DQ_ACTIVE_B after that. ++ * protects us from dquot_release() proceeding so just wait for ++ * any outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (dquot_active(dquot)) { +@@ -717,7 +741,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type) + /* Now we have active dquot from which someone is + * holding reference so we can safely just increase + * use count */ +- dqgrab(dquot); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + err = dquot_write_dquot(dquot); + if (err && !ret) +@@ -963,9 +987,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_LOOKUPS); + } else { +- if (!atomic_read(&dquot->dq_count)) +- remove_free_dquot(dquot); +- atomic_inc(&dquot->dq_count); ++ __dqgrab(dquot); + spin_unlock(&dq_list_lock); + dqstats_inc(DQST_CACHE_HITS); + dqstats_inc(DQST_LOOKUPS); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index c334f82ed385a..f9c0f9d7c9d93 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -44,14 +44,7 @@ int dquot_initialize(struct inode *inode); + bool dquot_initialize_needed(struct inode *inode); + void dquot_drop(struct inode *inode); + struct dquot *dqget(struct super_block *sb, struct kqid qid); +-static inline struct dquot *dqgrab(struct dquot *dquot) +-{ +- /* Make sure someone else has active reference to dquot */ +- WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); +- WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); +- atomic_inc(&dquot->dq_count); +- return dquot; +-} ++struct dquot *dqgrab(struct dquot *dquot); + + static inline bool dquot_is_busy(struct dquot *dquot) + { +-- +2.53.0 + diff --git a/queue-7.0/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch b/queue-7.0/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch new file mode 100644 index 0000000000..5ade9ea19c --- /dev/null +++ b/queue-7.0/r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch @@ -0,0 +1,41 @@ +From 8acdc36b1d0773f93863d7f6cf17e49c121495ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 15:39:23 +0800 +Subject: r8152: fix incorrect register write to USB_UPHY_XTAL + +From: Chih Kai Hsu + +[ Upstream commit 48afd5124fd6129c46fd12cb06155384b1c4a0c4 ] + +The old code used ocp_write_byte() to clear the OOBS_POLLING bit +(BIT(8)) in the USB_UPHY_XTAL register, but this doesn't correctly +clear a bit in the upper byte of the 16-bit register. + +Fix this by using ocp_write_word() instead. + +Fixes: 195aae321c82 ("r8152: support new chips") +Signed-off-by: Chih Kai Hsu +Reviewed-by: Hayes Wang +Link: https://patch.msgid.link/20260326073925.32976-454-nic_swsd@realtek.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/usb/r8152.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 0c83bbbea2e7c..f69e7e1ab7788 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -3890,7 +3890,7 @@ static void r8156_ups_en(struct r8152 *tp, bool enable) + case RTL_VER_15: + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL); + ocp_data &= ~OOBS_POLLING; +- ocp_write_byte(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); ++ ocp_write_word(tp, MCU_TYPE_USB, USB_UPHY_XTAL, ocp_data); + break; + default: + break; +-- +2.53.0 + diff --git a/queue-7.0/rculist-add-list_splice_rcu-for-private-lists.patch b/queue-7.0/rculist-add-list_splice_rcu-for-private-lists.patch new file mode 100644 index 0000000000..ba1df2f9c7 --- /dev/null +++ b/queue-7.0/rculist-add-list_splice_rcu-for-private-lists.patch @@ -0,0 +1,79 @@ +From ab7c56939a780cf4df4c454522ec290644d546c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 17:56:02 +0200 +Subject: rculist: add list_splice_rcu() for private lists + +From: Pablo Neira Ayuso + +[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ] + +This patch adds a helper function, list_splice_rcu(), to safely splice +a private (non-RCU-protected) list into an RCU-protected list. + +The function ensures that only the pointer visible to RCU readers +(prev->next) is updated using rcu_assign_pointer(), while the rest of +the list manipulations are performed with regular assignments, as the +source list is private and not visible to concurrent RCU readers. + +This is useful for moving elements from a private list into a global +RCU-protected list, ensuring safe publication for RCU readers. +Subsystems with some sort of batching mechanism from userspace can +benefit from this new function. + +The function __list_splice_rcu() has been added for clarity and to +follow the same pattern as in the existing list_splice*() interfaces, +where there is a check to ensure that the list to splice is not +empty. Note that __list_splice_rcu() has no documentation for this +reason. + +Reviewed-by: Paul E. McKenney +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: a6134e62dba2 ("netfilter: nf_tables: join hook list via splice_list_rcu() in commit phase") +Signed-off-by: Sasha Levin +--- + include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/include/linux/rculist.h b/include/linux/rculist.h +index 2abba7552605c..e3bc442256922 100644 +--- a/include/linux/rculist.h ++++ b/include/linux/rculist.h +@@ -261,6 +261,35 @@ static inline void list_replace_rcu(struct list_head *old, + old->prev = LIST_POISON2; + } + ++static inline void __list_splice_rcu(struct list_head *list, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ struct list_head *first = list->next; ++ struct list_head *last = list->prev; ++ ++ last->next = next; ++ first->prev = prev; ++ next->prev = last; ++ rcu_assign_pointer(list_next_rcu(prev), first); ++} ++ ++/** ++ * list_splice_rcu - splice a non-RCU list into an RCU-protected list, ++ * designed for stacks. ++ * @list: the non RCU-protected list to splice ++ * @head: the place in the existing RCU-protected list to splice ++ * ++ * The list pointed to by @head can be RCU-read traversed concurrently with ++ * this function. ++ */ ++static inline void list_splice_rcu(struct list_head *list, ++ struct list_head *head) ++{ ++ if (!list_empty(list)) ++ __list_splice_rcu(list, head, head->next); ++} ++ + /** + * __list_splice_init_rcu - join an RCU-protected list into an existing list. + * @list: the RCU-protected list to splice +-- +2.53.0 + diff --git a/queue-7.0/rdma-core-prefer-nla_nul_string.patch b/queue-7.0/rdma-core-prefer-nla_nul_string.patch new file mode 100644 index 0000000000..c25be7b000 --- /dev/null +++ b/queue-7.0/rdma-core-prefer-nla_nul_string.patch @@ -0,0 +1,56 @@ +From aa5765634a9318724f711b2d33932b43b84d0303 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:27:39 +0200 +Subject: RDMA/core: Prefer NLA_NUL_STRING + +From: Florian Westphal + +[ Upstream commit 6ed3d14fc45d3da6025e7fe4a6a09066856698e2 ] + +These attributes are evaluated as c-string (passed to strcmp), but +NLA_STRING doesn't check for the presence of a \0 terminator. + +Either this needs to switch to nla_strcmp() and needs to adjust printf fmt +specifier to not use plain %s, or this needs to use NLA_NUL_STRING. + +As the code has been this way for long time, it seems to me that userspace +does include the terminating nul, even tough its not enforced so far, and +thus NLA_NUL_STRING use is the simpler solution. + +Fixes: 30dc5e63d6a5 ("RDMA/core: Add support for iWARP Port Mapper user space service") +Link: https://patch.msgid.link/r/20260330122742.13315-1-fw@strlen.de +Signed-off-by: Florian Westphal +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/iwpm_msg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c +index 69c85249b4650..4625abd29ac06 100644 +--- a/drivers/infiniband/core/iwpm_msg.c ++++ b/drivers/infiniband/core/iwpm_msg.c +@@ -365,9 +365,9 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) + /* netlink attribute policy for the received response to register pid request */ + static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { + [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, +- [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_DEVNAME_SIZE - 1 }, +- [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, + [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } +@@ -677,7 +677,7 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) + + /* netlink attribute policy for the received request for mapping info */ + static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { +- [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, ++ [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } + }; +-- +2.53.0 + diff --git a/queue-7.0/rdma-umem-use-consistent-dma-attributes-when-unmappi.patch b/queue-7.0/rdma-umem-use-consistent-dma-attributes-when-unmappi.patch new file mode 100644 index 0000000000..a116e975f2 --- /dev/null +++ b/queue-7.0/rdma-umem-use-consistent-dma-attributes-when-unmappi.patch @@ -0,0 +1,82 @@ +From cc9cc7e2bd626e168da2fa9a6a02fc19e42588cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 22:10:18 +0200 +Subject: RDMA/umem: Use consistent DMA attributes when unmapping entries + +From: Leon Romanovsky + +[ Upstream commit 179b32095854d44749dd535502f05d95bbf43775 ] + +The DMA API expects that mapping and unmapping use the same DMA +attributes. The RDMA umem code did not meet this requirement, so fix +the mismatch. + +Fixes: f03d9fadfe13 ("RDMA/core: Add weak ordering dma attr to dma mapping") +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/umem.c | 13 ++++++------- + include/rdma/ib_umem.h | 1 + + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c +index edc34c69f0f23..acf4ce2891b76 100644 +--- a/drivers/infiniband/core/umem.c ++++ b/drivers/infiniband/core/umem.c +@@ -55,8 +55,7 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d + + if (dirty) + ib_dma_unmap_sgtable_attrs(dev, &umem->sgt_append.sgt, +- DMA_BIDIRECTIONAL, +- DMA_ATTR_REQUIRE_COHERENT); ++ DMA_BIDIRECTIONAL, umem->dma_attrs); + + for_each_sgtable_sg(&umem->sgt_append.sgt, sg, i) { + unpin_user_page_range_dirty_lock(sg_page(sg), +@@ -170,7 +169,6 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr, + unsigned long lock_limit; + unsigned long new_pinned; + unsigned long cur_base; +- unsigned long dma_attr = DMA_ATTR_REQUIRE_COHERENT; + struct mm_struct *mm; + unsigned long npages; + int pinned, ret; +@@ -203,6 +201,10 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr, + umem->iova = addr; + umem->writable = ib_access_writable(access); + umem->owning_mm = mm = current->mm; ++ umem->dma_attrs = DMA_ATTR_REQUIRE_COHERENT; ++ if (access & IB_ACCESS_RELAXED_ORDERING) ++ umem->dma_attrs |= DMA_ATTR_WEAK_ORDERING; ++ + mmgrab(mm); + + page_list = (struct page **) __get_free_page(GFP_KERNEL); +@@ -255,11 +257,8 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr, + } + } + +- if (access & IB_ACCESS_RELAXED_ORDERING) +- dma_attr |= DMA_ATTR_WEAK_ORDERING; +- + ret = ib_dma_map_sgtable_attrs(device, &umem->sgt_append.sgt, +- DMA_BIDIRECTIONAL, dma_attr); ++ DMA_BIDIRECTIONAL, umem->dma_attrs); + if (ret) + goto umem_release; + goto out; +diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h +index 0a8e092c0ea87..e426d451b8932 100644 +--- a/include/rdma/ib_umem.h ++++ b/include/rdma/ib_umem.h +@@ -22,6 +22,7 @@ struct ib_umem { + u64 iova; + size_t length; + unsigned long address; ++ unsigned long dma_attrs; + u32 writable : 1; + u32 is_odp : 1; + u32 is_dmabuf : 1; +-- +2.53.0 + diff --git a/queue-7.0/regulator-dt-bindings-fp9931-make-vin-supply-propert.patch b/queue-7.0/regulator-dt-bindings-fp9931-make-vin-supply-propert.patch new file mode 100644 index 0000000000..475aa3bfdb --- /dev/null +++ b/queue-7.0/regulator-dt-bindings-fp9931-make-vin-supply-propert.patch @@ -0,0 +1,36 @@ +From d01907876c59b5450d601302654ce2e3bb87619b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 21:31:01 +0800 +Subject: regulator: dt-bindings: fp9931: Make vin-supply property as required + +From: Robby Cai + +[ Upstream commit d342f5e355aaa4ff4fb5bd4a4aab70ed3a4f3c35 ] + +The FP9931 requires a vin power supply to operate, so mark vin-supply as +a required property in the binding. + +Fixes: 80bbdefdfb417 ("dt-bindings: regulator: Add Fitipower FP9931/JD9930") +Signed-off-by: Robby Cai +Link: https://patch.msgid.link/20260313133102.2749890-2-robby.cai@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/regulator/fitipower,fp9931.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml b/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml +index c6585e3bacbec..00d66b9230475 100644 +--- a/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml ++++ b/Documentation/devicetree/bindings/regulator/fitipower,fp9931.yaml +@@ -66,6 +66,7 @@ properties: + required: + - compatible + - reg ++ - vin-supply + - pg-gpios + - enable-gpios + +-- +2.53.0 + diff --git a/queue-7.0/regulator-fp9931-fix-handling-of-mandatory-vin-suppl.patch b/queue-7.0/regulator-fp9931-fix-handling-of-mandatory-vin-suppl.patch new file mode 100644 index 0000000000..52061983c2 --- /dev/null +++ b/queue-7.0/regulator-fp9931-fix-handling-of-mandatory-vin-suppl.patch @@ -0,0 +1,38 @@ +From fee5ccef5b4b8be4d1ea31a70af842b83fc0c5ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 21:31:02 +0800 +Subject: regulator: fp9931: Fix handling of mandatory "vin" supply + +From: Robby Cai + +[ Upstream commit 58068932402c7f5bf26489e01ae8e8bb89802d1e ] + +The FP9931 requires a mandatory "vin" power supply to operate. +Replace devm_regulator_get_optional() with devm_regulator_get() to +enforce this mandatory dependency. + +Fixes: 12d821bd13d42 ("regulator: Add FP9931/JD9930 driver") +Signed-off-by: Robby Cai +Link: https://patch.msgid.link/20260313133102.2749890-3-robby.cai@nxp.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/fp9931.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c +index abea3b69d8a08..002b41f53eff8 100644 +--- a/drivers/regulator/fp9931.c ++++ b/drivers/regulator/fp9931.c +@@ -446,7 +446,7 @@ static int fp9931_probe(struct i2c_client *client) + return dev_err_probe(&client->dev, PTR_ERR(data->regmap), + "failed to allocate regmap!\n"); + +- data->vin_reg = devm_regulator_get_optional(&client->dev, "vin"); ++ data->vin_reg = devm_regulator_get(&client->dev, "vin"); + if (IS_ERR(data->vin_reg)) + return dev_err_probe(&client->dev, PTR_ERR(data->vin_reg), + "failed to get vin regulator\n"); +-- +2.53.0 + diff --git a/queue-7.0/remoteproc-imx_rproc-check-return-value-of-regmap_at.patch b/queue-7.0/remoteproc-imx_rproc-check-return-value-of-regmap_at.patch new file mode 100644 index 0000000000..9d312cfb10 --- /dev/null +++ b/queue-7.0/remoteproc-imx_rproc-check-return-value-of-regmap_at.patch @@ -0,0 +1,47 @@ +From 64fa200113874ca6cf21481fddf98aa6227b11c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 13:14:07 +0800 +Subject: remoteproc: imx_rproc: Check return value of regmap_attach_dev() in + imx_rproc_mmio_detect_mode() + +From: Chen Ni + +[ Upstream commit a48c6676912fb808d2af1b8344d8656815a3e108 ] + +Add error checking for regmap_attach_dev() call in +imx_rproc_mmio_detect_mode() function to ensure proper error +propagation. + +Return the value of regmap_attach_dev() if it fails to prevent +proceeding with an incomplete regmap setup. + +Suggested-by: Peng Fan +Signed-off-by: Chen Ni +Fixes: e14168bf3493 ("remoteproc: imx_rproc: Simplify IMX_RPROC_MMIO switch case") +Link: https://lore.kernel.org/r/20260209051407.1467660-1-nichen@iscas.ac.cn +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/imx_rproc.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c +index 23126bc227059..0dd80e688b0ea 100644 +--- a/drivers/remoteproc/imx_rproc.c ++++ b/drivers/remoteproc/imx_rproc.c +@@ -1007,7 +1007,11 @@ static int imx_rproc_mmio_detect_mode(struct rproc *rproc) + } + + priv->regmap = regmap; +- regmap_attach_dev(dev, regmap, &config); ++ ret = regmap_attach_dev(dev, regmap, &config); ++ if (ret) { ++ dev_err(dev, "regmap attach failed\n"); ++ return ret; ++ } + + if (priv->gpr) { + ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val); +-- +2.53.0 + diff --git a/queue-7.0/remoteproc-xlnx-fix-sram-property-parsing.patch b/queue-7.0/remoteproc-xlnx-fix-sram-property-parsing.patch new file mode 100644 index 0000000000..43c3aa435a --- /dev/null +++ b/queue-7.0/remoteproc-xlnx-fix-sram-property-parsing.patch @@ -0,0 +1,42 @@ +From 5b4bc4058e778f384cffe9ded2c958c9ce3d5d39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 12:27:30 -0800 +Subject: remoteproc: xlnx: Fix sram property parsing + +From: Tim Michals + +[ Upstream commit d116bccf6f1c199b27c9ebdf07cc3cfe868f919c ] + +As per sram bindings, "sram" property can be list of phandles. +When more than one sram phandles are listed, driver can't parse second +phandle's address correctly. Because, phandle index is passed to the API +instead of offset of address from reg property which is always 0 as per +sram.yaml bindings. Fix it by passing 0 to the API instead of sram +phandle index. + +Fixes: 77fcdf51b8ca ("remoteproc: xlnx: Add sram support") +Signed-off-by: Tim Michals +Signed-off-by: Tanmay Shah +Link: https://lore.kernel.org/r/20260204202730.3729984-1-tanmay.shah@amd.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Sasha Levin +--- + drivers/remoteproc/xlnx_r5_remoteproc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c +index f949749e50b0c..eb5f714de2bff 100644 +--- a/drivers/remoteproc/xlnx_r5_remoteproc.c ++++ b/drivers/remoteproc/xlnx_r5_remoteproc.c +@@ -1007,7 +1007,7 @@ static int zynqmp_r5_get_sram_banks(struct zynqmp_r5_core *r5_core) + } + + /* Get SRAM device address */ +- ret = of_property_read_reg(sram_np, i, &abs_addr, &size); ++ ret = of_property_read_reg(sram_np, 0, &abs_addr, &size); + if (ret) { + dev_err(dev, "failed to get reg property\n"); + goto fail_sram_get; +-- +2.53.0 + diff --git a/queue-7.0/reset-amlogic-t7-fix-null-reset-ops.patch b/queue-7.0/reset-amlogic-t7-fix-null-reset-ops.patch new file mode 100644 index 0000000000..55fed60f4a --- /dev/null +++ b/queue-7.0/reset-amlogic-t7-fix-null-reset-ops.patch @@ -0,0 +1,36 @@ +From 35794506729d9c8257671d462214b5774f46f479 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 16:24:04 +0200 +Subject: reset: amlogic: t7: Fix null reset ops + +From: Ronald Claveau + +[ Upstream commit 9797524ef2b69c6b187b55bd844eb72a8c1cbd99 ] + +Fix missing reset ops causing kernel null pointer dereference. +This SOC's reset is currently not used yet. + +Signed-off-by: Ronald Claveau +Fixes: fb4c31587adf ("reset: amlogic: add auxiliary reset driver support") +Reviewed-by: Philipp Zabel +Signed-off-by: Philipp Zabel +Signed-off-by: Sasha Levin +--- + drivers/reset/amlogic/reset-meson.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/reset/amlogic/reset-meson.c b/drivers/reset/amlogic/reset-meson.c +index 84610365a823c..c303e8590dd68 100644 +--- a/drivers/reset/amlogic/reset-meson.c ++++ b/drivers/reset/amlogic/reset-meson.c +@@ -42,6 +42,7 @@ static const struct meson_reset_param meson_s4_param = { + }; + + static const struct meson_reset_param t7_param = { ++ .reset_ops = &meson_reset_ops, + .reset_num = 224, + .reset_offset = 0x0, + .level_offset = 0x40, +-- +2.53.0 + diff --git a/queue-7.0/revert-arm64-dts-rockchip-add-spdif-audio-to-beelink.patch b/queue-7.0/revert-arm64-dts-rockchip-add-spdif-audio-to-beelink.patch new file mode 100644 index 0000000000..98446383a1 --- /dev/null +++ b/queue-7.0/revert-arm64-dts-rockchip-add-spdif-audio-to-beelink.patch @@ -0,0 +1,71 @@ +From 28a89cb2cd7ee1025b043a21ad9b8f7c96013e4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 12:32:04 +0000 +Subject: Revert "arm64: dts: rockchip: add SPDIF audio to Beelink A1" + +From: Robin Murphy + +[ Upstream commit 03978cb18059ecd27e3d955508b18cf2a1196142 ] + +This reverts commit bdc4d388c6452498ab62ef2564589f40e0c8c262. + +While Beelink A1 mostly follows the high-end RK3328 reference design, +it does not in fact have the S/PDIF connector, only HDMI and a 3.5mm +jack for the analog audio/TV codecs - the tiny form factor literally +doesn't have room to fit more! + +Cc: Christian Hewitt +Cc: Alex Bee +Fixes: bdc4d388c645 ("arm64: dts: rockchip: add SPDIF audio to Beelink A1") +Signed-off-by: Robin Murphy +Link: https://patch.msgid.link/0af77a02c2b0806d4ca72066392a5453fcc89a8f.1767111968.git.robin.murphy@arm.com +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3328-a1.dts | 23 ---------------------- + 1 file changed, 23 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts +index 30bdb38f0727a..e810ed146451c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts +@@ -58,24 +58,6 @@ ir-receiver { + gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>; + linux,rc-map-name = "rc-beelink-gs1"; + }; +- +- spdif_dit: spdif-dit { +- compatible = "linux,spdif-dit"; +- #sound-dai-cells = <0>; +- }; +- +- spdif_sound: spdif-sound { +- compatible = "simple-audio-card"; +- simple-audio-card,name = "SPDIF"; +- +- simple-audio-card,cpu { +- sound-dai = <&spdif>; +- }; +- +- simple-audio-card,codec { +- sound-dai = <&spdif_dit>; +- }; +- }; + }; + + &analog_sound { +@@ -343,11 +325,6 @@ &sdmmc { + status = "okay"; + }; + +-&spdif { +- pinctrl-0 = <&spdifm0_tx>; +- status = "okay"; +-}; +- + &tsadc { + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; +-- +2.53.0 + diff --git a/queue-7.0/riscv-dts-spacemit-drop-incorrect-pinctrl-for-combo-.patch b/queue-7.0/riscv-dts-spacemit-drop-incorrect-pinctrl-for-combo-.patch new file mode 100644 index 0000000000..b0beaf99ba --- /dev/null +++ b/queue-7.0/riscv-dts-spacemit-drop-incorrect-pinctrl-for-combo-.patch @@ -0,0 +1,44 @@ +From c51ea25ba6c44fef381eb76433f1449782d80ec4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Mar 2026 21:25:01 +0100 +Subject: riscv: dts: spacemit: drop incorrect pinctrl for combo PHY + +From: Aurelien Jarno + +[ Upstream commit c68360c0d636dae71f766b7b296ddfcf2827ccc7 ] + +The combo PHY on the Banana Pi F3 is used for the USB 3.0 port. The high +speed differential lanes are always configured as such, and do not +require a pinctrl entry. + +The existing pinctrl entry only configures PCIe secondary pins, which +are unused for USB and instead routed to the MIPI CSI1 connector. + +Remove this incorrect pinctrl entry. + +Fixes: 0be016a4b5d1b9 ("riscv: dts: spacemit: PCIe and PHY-related updates") +Signed-off-by: Aurelien Jarno +Reviewed-by: Yixun Lan +Link: https://lore.kernel.org/r/20260322202502.2205755-1-aurelien@aurel32.net +Signed-off-by: Yixun Lan +Signed-off-by: Sasha Levin +--- + arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts +index 51f6c6a774b0d..48c034736aa5a 100644 +--- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts ++++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts +@@ -81,8 +81,6 @@ usb3_hub_5v: usb3-hub-5v { + }; + + &combo_phy { +- pinctrl-names = "default"; +- pinctrl-0 = <&pcie0_3_cfg>; + status = "okay"; + }; + +-- +2.53.0 + diff --git a/queue-7.0/riscv-dts-spacemit-pcie-fix-missing-power-regulator.patch b/queue-7.0/riscv-dts-spacemit-pcie-fix-missing-power-regulator.patch new file mode 100644 index 0000000000..30d1a7a3a0 --- /dev/null +++ b/queue-7.0/riscv-dts-spacemit-pcie-fix-missing-power-regulator.patch @@ -0,0 +1,47 @@ +From 5428d394c3262813f3f22b1c23259fa40e8b3e7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 08:17:55 +0000 +Subject: riscv: dts: spacemit: pcie: fix missing power regulator + +From: Yixun Lan + +[ Upstream commit 8a9071299dec817a544c0fb48f7302396fafdc4b ] + +The PCIe port require 3.3v power regulator for device to work properly, So +explicitly add it to fix the DT warning: + +arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dtb: pcie@ca400000 (spacemit,k1-pcie): pcie@0: 'vpcie3v3-supply' is a required property + from schema $id: http://devicetree.org/schemas/pci/spacemit,k1-pcie-host.yaml + +Fixes: 0be016a4b5d1 ("riscv: dts: spacemit: PCIe and PHY-related updates") +Reported-by: Conor Dooley +Link: https://lore.kernel.org/r/20260226-k1-pcie-fix-pwr-v1-1-94b493cd27e5@kernel.org +Signed-off-by: Yixun Lan +Signed-off-by: Sasha Levin +--- + arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts +index 5971605754b35..51f6c6a774b0d 100644 +--- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts ++++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts +@@ -305,6 +305,7 @@ &pcie1_phy { + + &pcie1_port { + phys = <&pcie1_phy>; ++ vpcie3v3-supply = <&pcie_vcc_3v3>; + }; + + &pcie1 { +@@ -320,6 +321,7 @@ &pcie2_phy { + + &pcie2_port { + phys = <&pcie2_phy>; ++ vpcie3v3-supply = <&pcie_vcc_3v3>; + }; + + &pcie2 { +-- +2.53.0 + diff --git a/queue-7.0/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch b/queue-7.0/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch new file mode 100644 index 0000000000..b538a720b2 --- /dev/null +++ b/queue-7.0/rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch @@ -0,0 +1,51 @@ +From 66e0167d8f91a384f378048efddd6374c24620c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Nov 2025 18:00:10 +0000 +Subject: rtc: abx80x: Disable alarm feature if no interrupt attached + +From: Anthony Pighin (Nokia) + +[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ] + +Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting +alarm") exposed an issue where the rtc-abx80x driver does not clear the +alarm feature bit, but instead relies on the set_alarm operation to return +invalid. + +For example, when a RTC_UIE_ON ioctl is handled, it should abort at the +feature validation. Instead, it proceeds to the rtc_timer_enqueue(), +which used to return an error from the set_alarm call. However, +following the race condition handling, which likely should not be +discarding predecing errors, a success condition is returned to the +ioctl() caller. This results in (for example): + hwclock: select() to /dev/rtc0 to wait for clock tick timed out + +Notwithstanding the validity of the race condition handling, if an interrupt +wasn't specified, or could not be attached, the driver should clear the +alarm feature bit. + +Fixes: 718a820a303c ("rtc: abx80x: add alarm support") +Signed-off-by: Anthony Pighin +Link: https://patch.msgid.link/BN0PR08MB69510928028C933749F4139383D1A@BN0PR08MB6951.namprd08.prod.outlook.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/rtc/rtc-abx80x.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c +index 3fee27914ba80..5f3a3e60a19d0 100644 +--- a/drivers/rtc/rtc-abx80x.c ++++ b/drivers/rtc/rtc-abx80x.c +@@ -933,6 +933,8 @@ static int abx80x_probe(struct i2c_client *client) + client->irq = 0; + } + } ++ if (client->irq <= 0) ++ clear_bit(RTC_FEATURE_ALARM, priv->rtc->features); + + err = rtc_add_group(priv->rtc, &rtc_calib_attr_group); + if (err) { +-- +2.53.0 + diff --git a/queue-7.0/rtla-fix-segfault-on-multiple-sigints.patch b/queue-7.0/rtla-fix-segfault-on-multiple-sigints.patch new file mode 100644 index 0000000000..dd700901c7 --- /dev/null +++ b/queue-7.0/rtla-fix-segfault-on-multiple-sigints.patch @@ -0,0 +1,68 @@ +From 54dc84c735565d912e7f0edb30167c3158a7d328 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 17:07:25 +0100 +Subject: rtla: Fix segfault on multiple SIGINTs + +From: Tomas Glozar + +[ Upstream commit be8058f31b4e237604e4ce7599593ab68dc69ae7 ] + +Detach stop_trace() from SIGINT/SIGALRM on tool clean-up to prevent it +from crashing RTLA by accessing freed memory. + +This prevents a crash when multiple SIGINTs are received. + +Fixes: d6899e560366 ("rtla/timerlat_hist: Abort event processing on second signal") +Fixes: 80967b354a76 ("rtla/timerlat_top: Abort event processing on second signal") +Reviewed-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260310160725.144443-1-tglozar@redhat.com +Signed-off-by: Tomas Glozar +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/common.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c +index f310b0d59ad3e..839c78c065e12 100644 +--- a/tools/tracing/rtla/src/common.c ++++ b/tools/tracing/rtla/src/common.c +@@ -39,6 +39,18 @@ static void set_signals(struct common_params *params) + } + } + ++/* ++ * unset_signals - unsets the signals to stop the tool ++ */ ++static void unset_signals(struct common_params *params) ++{ ++ signal(SIGINT, SIG_DFL); ++ if (params->duration) { ++ alarm(0); ++ signal(SIGALRM, SIG_DFL); ++ } ++} ++ + /* + * getopt_auto - auto-generates optstring from long_options + */ +@@ -314,7 +326,7 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[]) + + retval = ops->main(tool); + if (retval) +- goto out_trace; ++ goto out_signals; + + if (params->user_workload && !params->user.stopped_running) { + params->user.should_run = 0; +@@ -336,6 +348,8 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[]) + if (ops->analyze) + ops->analyze(tool, stopped); + ++out_signals: ++ unset_signals(params); + out_trace: + trace_events_destroy(&tool->record->trace, params->events); + params->events = NULL; +-- +2.53.0 + diff --git a/queue-7.0/rtla-simplify-code-by-caching-string-lengths.patch b/queue-7.0/rtla-simplify-code-by-caching-string-lengths.patch new file mode 100644 index 0000000000..19e6737ed9 --- /dev/null +++ b/queue-7.0/rtla-simplify-code-by-caching-string-lengths.patch @@ -0,0 +1,99 @@ +From df6f4e3f3b73686a2f6cf3fe383138a094d360a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 16:46:19 -0300 +Subject: rtla: Simplify code by caching string lengths + +From: Wander Lairson Costa + +[ Upstream commit f79720e25b793691dcc46e1f1cd64d01578075c2 ] + +Simplify trace_event_save_hist() and set_comm_cgroup() by computing +string lengths once and storing them in local variables, rather than +calling strlen() multiple times on the same unchanged strings. This +makes the code clearer by eliminating redundant function calls and +improving readability. + +In trace_event_save_hist(), the write loop previously called strlen() +on the hist buffer twice per iteration for both the size calculation +and loop condition. Store the length in hist_len before entering the +loop. In set_comm_cgroup(), strlen() was called on cgroup_path up to +three times in succession. Store the result in cg_path_len to use in +both the offset calculation and size parameter for subsequent append +operations. + +This simplification makes the code easier to read and maintain without +changing program behavior. + +Signed-off-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260309195040.1019085-7-wander@redhat.com +Signed-off-by: Tomas Glozar +Stable-dep-of: 4bf4ef5292b9 ("rtla/trace: Fix write loop in trace_event_save_hist()") +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/trace.c | 6 ++++-- + tools/tracing/rtla/src/utils.c | 11 +++++++---- + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c +index b8be3e28680ee..073ec1b567798 100644 +--- a/tools/tracing/rtla/src/trace.c ++++ b/tools/tracing/rtla/src/trace.c +@@ -362,6 +362,7 @@ static void trace_event_save_hist(struct trace_instance *instance, + mode_t mode = 0644; + char path[1024]; + char *hist; ++ size_t hist_len; + + if (!tevent) + return; +@@ -392,9 +393,10 @@ static void trace_event_save_hist(struct trace_instance *instance, + } + + index = 0; ++ hist_len = strlen(hist); + do { +- index += write(out_fd, &hist[index], strlen(hist) - index); +- } while (index < strlen(hist)); ++ index += write(out_fd, &hist[index], hist_len - index); ++ } while (index < hist_len); + + free(hist); + out_close: +diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c +index 0da3b2470c317..fb067220566a4 100644 +--- a/tools/tracing/rtla/src/utils.c ++++ b/tools/tracing/rtla/src/utils.c +@@ -809,6 +809,7 @@ static int open_cgroup_procs(const char *cgroup) + char cgroup_procs[MAX_PATH]; + int retval; + int cg_fd; ++ size_t cg_path_len; + + retval = find_mount("cgroup2", cgroup_path, sizeof(cgroup_path)); + if (!retval) { +@@ -816,16 +817,18 @@ static int open_cgroup_procs(const char *cgroup) + return -1; + } + ++ cg_path_len = strlen(cgroup_path); ++ + if (!cgroup) { +- retval = get_self_cgroup(&cgroup_path[strlen(cgroup_path)], +- sizeof(cgroup_path) - strlen(cgroup_path)); ++ retval = get_self_cgroup(&cgroup_path[cg_path_len], ++ sizeof(cgroup_path) - cg_path_len); + if (!retval) { + err_msg("Did not find self cgroup\n"); + return -1; + } + } else { +- snprintf(&cgroup_path[strlen(cgroup_path)], +- sizeof(cgroup_path) - strlen(cgroup_path), "%s/", cgroup); ++ snprintf(&cgroup_path[cg_path_len], ++ sizeof(cgroup_path) - cg_path_len, "%s/", cgroup); + } + + snprintf(cgroup_procs, MAX_PATH, "%s/cgroup.procs", cgroup_path); +-- +2.53.0 + diff --git a/queue-7.0/rtla-trace-fix-write-loop-in-trace_event_save_hist.patch b/queue-7.0/rtla-trace-fix-write-loop-in-trace_event_save_hist.patch new file mode 100644 index 0000000000..cf8c048acf --- /dev/null +++ b/queue-7.0/rtla-trace-fix-write-loop-in-trace_event_save_hist.patch @@ -0,0 +1,71 @@ +From c2b239d303b94940f6dda911ef20767b75ec3d14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 16:46:28 -0300 +Subject: rtla/trace: Fix write loop in trace_event_save_hist() + +From: Wander Lairson Costa + +[ Upstream commit 4bf4ef5292b9253d8607c61a875d9f6b14129976 ] + +The write loop in trace_event_save_hist() does not correctly handle +errors from the write() system call. If write() returns -1, this value +is added to the loop index, leading to an incorrect memory access on +the next iteration and potentially an infinite loop. The loop also +fails to handle EINTR. + +Fix the write loop by introducing proper error handling. The return +value of write() is now stored in a ssize_t variable and checked for +errors. The loop retries the call if interrupted by a signal and breaks +on any other error after logging it with strerror(). + +Additionally, change the index variable type from int to size_t to +match the type used for buffer sizes and by strlen(), improving type +safety. + +Fixes: 761916fd02c2 ("rtla/trace: Save event histogram output to a file") +Signed-off-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260309195040.1019085-16-wander@redhat.com +Signed-off-by: Tomas Glozar +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/trace.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c +index d5a6a7351d40f..a4912aaa10eb9 100644 +--- a/tools/tracing/rtla/src/trace.c ++++ b/tools/tracing/rtla/src/trace.c +@@ -358,11 +358,11 @@ static void trace_event_disable_filter(struct trace_instance *instance, + static void trace_event_save_hist(struct trace_instance *instance, + struct trace_events *tevent) + { +- int index, out_fd; ++ size_t index, hist_len; + mode_t mode = 0644; + char path[1024]; + char *hist; +- size_t hist_len; ++ int out_fd; + + if (!tevent) + return; +@@ -394,7 +394,15 @@ static void trace_event_save_hist(struct trace_instance *instance, + index = 0; + hist_len = strlen(hist); + do { +- index += write(out_fd, &hist[index], hist_len - index); ++ const ssize_t written = write(out_fd, &hist[index], hist_len - index); ++ ++ if (written < 0) { ++ if (errno == EINTR) ++ continue; ++ err_msg(" Error writing hist file: %s\n", strerror(errno)); ++ break; ++ } ++ index += written; + } while (index < hist_len); + + free(hist); +-- +2.53.0 + diff --git a/queue-7.0/rtla-use-str_has_prefix-for-prefix-checks.patch b/queue-7.0/rtla-use-str_has_prefix-for-prefix-checks.patch new file mode 100644 index 0000000000..b9fd4d1d46 --- /dev/null +++ b/queue-7.0/rtla-use-str_has_prefix-for-prefix-checks.patch @@ -0,0 +1,71 @@ +From 9aff98691c751cfaa179e18f84693789ac5486fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 16:46:24 -0300 +Subject: rtla: Use str_has_prefix() for prefix checks + +From: Wander Lairson Costa + +[ Upstream commit 265905df83a4c1e78c1a912e1699d7c81d9540e6 ] + +The code currently uses strncmp() combined with strlen() to check if a +string starts with a specific prefix. This pattern is verbose and prone +to errors if the length does not match the prefix string. + +Replace this pattern with the str_has_prefix() helper function in both +trace.c and utils.c. This improves code readability and safety by +handling the prefix length calculation automatically. + +In addition, remove the unused retval variable from +trace_event_save_hist() in trace.c to clean up the function and +silence potential compiler warnings. + +Signed-off-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260309195040.1019085-12-wander@redhat.com +Signed-off-by: Tomas Glozar +Stable-dep-of: 4bf4ef5292b9 ("rtla/trace: Fix write loop in trace_event_save_hist()") +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/trace.c | 5 ++--- + tools/tracing/rtla/src/utils.c | 3 +-- + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c +index 073ec1b567798..d5a6a7351d40f 100644 +--- a/tools/tracing/rtla/src/trace.c ++++ b/tools/tracing/rtla/src/trace.c +@@ -358,7 +358,7 @@ static void trace_event_disable_filter(struct trace_instance *instance, + static void trace_event_save_hist(struct trace_instance *instance, + struct trace_events *tevent) + { +- int retval, index, out_fd; ++ int index, out_fd; + mode_t mode = 0644; + char path[1024]; + char *hist; +@@ -372,8 +372,7 @@ static void trace_event_save_hist(struct trace_instance *instance, + return; + + /* is this a hist: trigger? */ +- retval = strncmp(tevent->trigger, "hist:", strlen("hist:")); +- if (retval) ++ if (!str_has_prefix(tevent->trigger, "hist:")) + return; + + snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event); +diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c +index fb067220566a4..22d2182c729e5 100644 +--- a/tools/tracing/rtla/src/utils.c ++++ b/tools/tracing/rtla/src/utils.c +@@ -316,8 +316,7 @@ static int procfs_is_workload_pid(const char *comm_prefix, struct dirent *proc_e + return 0; + + buffer[MAX_PATH-1] = '\0'; +- retval = strncmp(comm_prefix, buffer, strlen(comm_prefix)); +- if (retval) ++ if (!str_has_prefix(buffer, comm_prefix)) + return 0; + + /* comm already have \n */ +-- +2.53.0 + diff --git a/queue-7.0/rtla-utils-fix-resource-leak-in-set_comm_sched_attr.patch b/queue-7.0/rtla-utils-fix-resource-leak-in-set_comm_sched_attr.patch new file mode 100644 index 0000000000..2e417199c2 --- /dev/null +++ b/queue-7.0/rtla-utils-fix-resource-leak-in-set_comm_sched_attr.patch @@ -0,0 +1,64 @@ +From 971498e32ca7d878435be75060675ec80eef2838 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 16:46:30 -0300 +Subject: rtla/utils: Fix resource leak in set_comm_sched_attr() + +From: Wander Lairson Costa + +[ Upstream commit 5b6dc659ad792c72b3ff1be8039ae2945e030928 ] + +The set_comm_sched_attr() function opens the /proc directory via +opendir() but fails to call closedir() on its successful exit path. +If the function iterates through all processes without error, it +returns 0 directly, leaking the DIR stream pointer. + +Fix this by refactoring the function to use a single exit path. A +retval variable is introduced to track the success or failure status. +All exit points now jump to a unified out label that calls closedir() +before the function returns, ensuring the resource is always freed. + +Fixes: dada03db9bb19 ("rtla: Remove procps-ng dependency") +Signed-off-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260309195040.1019085-18-wander@redhat.com +Signed-off-by: Tomas Glozar +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/utils.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c +index 22d2182c729e5..53e45eabae03c 100644 +--- a/tools/tracing/rtla/src/utils.c ++++ b/tools/tracing/rtla/src/utils.c +@@ -360,22 +360,23 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr) + + if (strtoi(proc_entry->d_name, &pid)) { + err_msg("'%s' is not a valid pid", proc_entry->d_name); +- goto out_err; ++ retval = 1; ++ goto out; + } + /* procfs_is_workload_pid confirmed it is a pid */ + retval = __set_sched_attr(pid, attr); + if (retval) { + err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name); +- goto out_err; ++ goto out; + } + + debug_msg("Set sched attributes for pid:%s\n", proc_entry->d_name); + } +- return 0; + +-out_err: ++ retval = 0; ++out: + closedir(procfs); +- return 1; ++ return retval; + } + + #define INVALID_VAL (~0L) +-- +2.53.0 + diff --git a/queue-7.0/rust-sync-atomic-remove-bound-t-sync-for-atomic-from.patch b/queue-7.0/rust-sync-atomic-remove-bound-t-sync-for-atomic-from.patch new file mode 100644 index 0000000000..c1a39962bc --- /dev/null +++ b/queue-7.0/rust-sync-atomic-remove-bound-t-sync-for-atomic-from.patch @@ -0,0 +1,51 @@ +From 1f8b43dd0040d7da4a80c71aca01d66347b1f60c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 12:16:49 -0800 +Subject: rust: sync: atomic: Remove bound `T: Sync` for `Atomic::from_ptr()` + +From: Boqun Feng + +[ Upstream commit 4a5dc632e0b603ec1cbbf87b78de86b4b6359cff ] + +Originally, `Atomic::from_ptr()` requires `T` being a `Sync` because I +thought having the ability to do `from_ptr()` meant multiplle +`&Atomic`s shared by different threads, which was identical (or +similar) to multiple `&T`s shared by different threads. Hence `T` was +required to be `Sync`. However this is not true, since `&Atomic` is +not the same at `&T`. Moreover, having this bound makes `Atomic::<*mut +T>::from_ptr()` impossible, which is definitely not intended. Therefore +remove the `T: Sync` bound. + +[boqun: Fix title typo spotted by Alice & Gary] + +Fixes: 29c32c405e53 ("rust: sync: atomic: Add generic atomics") +Signed-off-by: Boqun Feng +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Alice Ryhl +Reviewed-by: Gary Guo +Link: https://patch.msgid.link/20260120115207.55318-2-boqun.feng@gmail.com +Link: https://patch.msgid.link/20260303201701.12204-2-boqun@kernel.org +Signed-off-by: Sasha Levin +--- + rust/kernel/sync/atomic.rs | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs +index 4aebeacb961a2..296b25e83bbb9 100644 +--- a/rust/kernel/sync/atomic.rs ++++ b/rust/kernel/sync/atomic.rs +@@ -204,10 +204,7 @@ pub const fn new(v: T) -> Self { + /// // no data race. + /// unsafe { Atomic::from_ptr(foo_a_ptr) }.store(2, Release); + /// ``` +- pub unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self +- where +- T: Sync, +- { ++ pub unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a Self { + // CAST: `T` and `Atomic` have the same size, alignment and bit validity. + // SAFETY: Per function safety requirement, `ptr` is a valid pointer and the object will + // live long enough. It's safe to return a `&Atomic` because function safety requirement +-- +2.53.0 + diff --git a/queue-7.0/s390-ap-use-generic-driver_override-infrastructure.patch b/queue-7.0/s390-ap-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..fbc9aaa4ed --- /dev/null +++ b/queue-7.0/s390-ap-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,186 @@ +From 9fc4fb3cc28af5a1bad79879ec3b3b4b36908db4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:14 +0100 +Subject: s390/ap: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit 81d6f7c3a70b10ff757ee8b5f8114a190871cf1e ] + +When the AP masks are updated via apmask_store() or aqmask_store(), +ap_bus_revise_bindings() is called after ap_attr_mutex has been +released. + +This calls __ap_revise_reserved(), which accesses the driver_override +field without holding any lock, racing against a concurrent +driver_override_store() that may free the old string, resulting in a +potential UAF. + +Fix this by using the driver-core driver_override infrastructure, which +protects all accesses with an internal spinlock. + +Note that unlike most other buses, the AP bus does not check +driver_override in its match() callback; the override is checked in +ap_device_probe() and __ap_revise_reserved() instead. + +Also note that we do not enable the driver_override feature of struct +bus_type, as AP - in contrast to most other buses - passes "" to +sysfs_emit() when the driver_override pointer is NULL. Thus, printing +"\n" instead of "(null)\n". + +Additionally, AP has a custom counter that is modified in the +corresponding custom driver_override_store(). + +Fixes: d38a87d7c064 ("s390/ap: Support driver_override for AP queue devices") +Tested-by: Holger Dengler +Reviewed-by: Holger Dengler +Reviewed-by: Harald Freudenberger +Link: https://patch.msgid.link/20260324005919.2408620-11-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/s390/crypto/ap_bus.c | 34 +++++++++++++++++----------------- + drivers/s390/crypto/ap_bus.h | 1 - + drivers/s390/crypto/ap_queue.c | 24 ++++++------------------ + 3 files changed, 23 insertions(+), 36 deletions(-) + +diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c +index d652df96a5078..f24e27add721d 100644 +--- a/drivers/s390/crypto/ap_bus.c ++++ b/drivers/s390/crypto/ap_bus.c +@@ -859,25 +859,24 @@ static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data) + + static int __ap_revise_reserved(struct device *dev, void *dummy) + { +- int rc, card, queue, devres, drvres; ++ int rc, card, queue, devres, drvres, ovrd; + + if (is_queue_dev(dev)) { + struct ap_driver *ap_drv = to_ap_drv(dev->driver); + struct ap_queue *aq = to_ap_queue(dev); +- struct ap_device *ap_dev = &aq->ap_dev; + + card = AP_QID_CARD(aq->qid); + queue = AP_QID_QUEUE(aq->qid); + +- if (ap_dev->driver_override) { +- if (strcmp(ap_dev->driver_override, +- ap_drv->driver.name)) { +- pr_debug("reprobing queue=%02x.%04x\n", card, queue); +- rc = device_reprobe(dev); +- if (rc) { +- AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n", +- __func__, card, queue); +- } ++ ovrd = device_match_driver_override(dev, &ap_drv->driver); ++ if (ovrd > 0) { ++ /* override set and matches, nothing to do */ ++ } else if (ovrd == 0) { ++ pr_debug("reprobing queue=%02x.%04x\n", card, queue); ++ rc = device_reprobe(dev); ++ if (rc) { ++ AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n", ++ __func__, card, queue); + } + } else { + mutex_lock(&ap_attr_mutex); +@@ -928,7 +927,7 @@ int ap_owned_by_def_drv(int card, int queue) + if (aq) { + const struct device_driver *drv = aq->ap_dev.device.driver; + const struct ap_driver *ap_drv = to_ap_drv(drv); +- bool override = !!aq->ap_dev.driver_override; ++ bool override = device_has_driver_override(&aq->ap_dev.device); + + if (override && drv && ap_drv->flags & AP_DRIVER_FLAG_DEFAULT) + rc = 1; +@@ -977,7 +976,7 @@ static int ap_device_probe(struct device *dev) + { + struct ap_device *ap_dev = to_ap_dev(dev); + struct ap_driver *ap_drv = to_ap_drv(dev->driver); +- int card, queue, devres, drvres, rc = -ENODEV; ++ int card, queue, devres, drvres, rc = -ENODEV, ovrd; + + if (!get_device(dev)) + return rc; +@@ -991,10 +990,11 @@ static int ap_device_probe(struct device *dev) + */ + card = AP_QID_CARD(to_ap_queue(dev)->qid); + queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); +- if (ap_dev->driver_override) { +- if (strcmp(ap_dev->driver_override, +- ap_drv->driver.name)) +- goto out; ++ ovrd = device_match_driver_override(dev, &ap_drv->driver); ++ if (ovrd > 0) { ++ /* override set and matches, nothing to do */ ++ } else if (ovrd == 0) { ++ goto out; + } else { + mutex_lock(&ap_attr_mutex); + devres = test_bit_inv(card, ap_perms.apm) && +diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h +index 51e08f27bd75e..04ea256ecf919 100644 +--- a/drivers/s390/crypto/ap_bus.h ++++ b/drivers/s390/crypto/ap_bus.h +@@ -166,7 +166,6 @@ void ap_driver_unregister(struct ap_driver *); + struct ap_device { + struct device device; + int device_type; /* AP device type. */ +- const char *driver_override; + }; + + #define to_ap_dev(x) container_of((x), struct ap_device, device) +diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c +index 3fe2e41c5c6b1..ca9819e6f7e76 100644 +--- a/drivers/s390/crypto/ap_queue.c ++++ b/drivers/s390/crypto/ap_queue.c +@@ -734,26 +734,14 @@ static ssize_t driver_override_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct ap_queue *aq = to_ap_queue(dev); +- struct ap_device *ap_dev = &aq->ap_dev; +- int rc; +- +- device_lock(dev); +- if (ap_dev->driver_override) +- rc = sysfs_emit(buf, "%s\n", ap_dev->driver_override); +- else +- rc = sysfs_emit(buf, "\n"); +- device_unlock(dev); +- +- return rc; ++ guard(spinlock)(&dev->driver_override.lock); ++ return sysfs_emit(buf, "%s\n", dev->driver_override.name ?: ""); + } + + static ssize_t driver_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) + { +- struct ap_queue *aq = to_ap_queue(dev); +- struct ap_device *ap_dev = &aq->ap_dev; + int rc = -EINVAL; + bool old_value; + +@@ -764,13 +752,13 @@ static ssize_t driver_override_store(struct device *dev, + if (ap_apmask_aqmask_in_use) + goto out; + +- old_value = ap_dev->driver_override ? true : false; +- rc = driver_set_override(dev, &ap_dev->driver_override, buf, count); ++ old_value = device_has_driver_override(dev); ++ rc = __device_set_driver_override(dev, buf, count); + if (rc) + goto out; +- if (old_value && !ap_dev->driver_override) ++ if (old_value && !device_has_driver_override(dev)) + --ap_driver_override_ctr; +- else if (!old_value && ap_dev->driver_override) ++ else if (!old_value && device_has_driver_override(dev)) + ++ap_driver_override_ctr; + + rc = count; +-- +2.53.0 + diff --git a/queue-7.0/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch b/queue-7.0/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch new file mode 100644 index 0000000000..5db52b5314 --- /dev/null +++ b/queue-7.0/s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch @@ -0,0 +1,103 @@ +From 70f1fc500860780bc5ce001bc51277cfa6d5f089 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 18:46:25 +0100 +Subject: s390/bpf: Zero-extend bpf prog return values and kfunc arguments + +From: Ilya Leoshkevich + +[ Upstream commit 202e42e4aa890172366354b233c42c73107a3f59 ] + +s390x ABI requires callers to zero-extend unsigned arguments and +sign-extend signed arguments, and callees to zero-extend unsigned +return values and sign-extend signed return values. + +s390 BPF JIT currently implements only sign extension. Fix this +omission and implement zero extension too. + +Fixes: 528eb2cb87bc ("s390/bpf: Implement arch_prepare_bpf_trampoline()") +Reported-by: Hari Bathini +Closes: https://lore.kernel.org/bpf/20260312080113.843408-1-hbathini@linux.ibm.com/ +Signed-off-by: Ilya Leoshkevich +Tested-by: Ihor Solodrai +Link: https://lore.kernel.org/r/20260313174807.581826-1-iii@linux.ibm.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + arch/s390/net/bpf_jit_comp.c | 39 ++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 15 deletions(-) + +diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c +index bf92964246eb1..10ab247e1994c 100644 +--- a/arch/s390/net/bpf_jit_comp.c ++++ b/arch/s390/net/bpf_jit_comp.c +@@ -830,25 +830,34 @@ static int bpf_jit_probe_post(struct bpf_jit *jit, struct bpf_prog *fp, + } + + /* +- * Sign-extend the register if necessary ++ * Sign- or zero-extend the register if necessary + */ +-static int sign_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) ++static int sign_zero_extend(struct bpf_jit *jit, int r, u8 size, u8 flags) + { +- if (!(flags & BTF_FMODEL_SIGNED_ARG)) +- return 0; +- + switch (size) { + case 1: +- /* lgbr %r,%r */ +- EMIT4(0xb9060000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lgbr %r,%r */ ++ EMIT4(0xb9060000, r, r); ++ else ++ /* llgcr %r,%r */ ++ EMIT4(0xb9840000, r, r); + return 0; + case 2: +- /* lghr %r,%r */ +- EMIT4(0xb9070000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lghr %r,%r */ ++ EMIT4(0xb9070000, r, r); ++ else ++ /* llghr %r,%r */ ++ EMIT4(0xb9850000, r, r); + return 0; + case 4: +- /* lgfr %r,%r */ +- EMIT4(0xb9140000, r, r); ++ if (flags & BTF_FMODEL_SIGNED_ARG) ++ /* lgfr %r,%r */ ++ EMIT4(0xb9140000, r, r); ++ else ++ /* llgfr %r,%r */ ++ EMIT4(0xb9160000, r, r); + return 0; + case 8: + return 0; +@@ -1798,9 +1807,9 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, + return -1; + + for (j = 0; j < m->nr_args; j++) { +- if (sign_extend(jit, BPF_REG_1 + j, +- m->arg_size[j], +- m->arg_flags[j])) ++ if (sign_zero_extend(jit, BPF_REG_1 + j, ++ m->arg_size[j], ++ m->arg_flags[j])) + return -1; + } + } +@@ -2555,7 +2564,7 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit, + EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, p->bpf_func); + /* stg %r2,retval_off(%r15) */ + if (save_ret) { +- if (sign_extend(jit, REG_2, m->ret_size, m->ret_flags)) ++ if (sign_zero_extend(jit, REG_2, m->ret_size, m->ret_flags)) + return -1; + EMIT6_DISP_LH(0xe3000000, 0x0024, REG_2, REG_0, REG_15, + tjit->retval_off); +-- +2.53.0 + diff --git a/queue-7.0/s390-cio-use-generic-driver_override-infrastructure.patch b/queue-7.0/s390-cio-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..0deba944b8 --- /dev/null +++ b/queue-7.0/s390-cio-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,122 @@ +From ac6be311342a759be2e65aa0dc15a57a3efa67be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:13 +0100 +Subject: s390/cio: use generic driver_override infrastructure + +From: Danilo Krummrich + +[ Upstream commit ac4d8bb6e2e13e8684a76ea48d13ebaaaf5c24c4 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: ebc3d1791503 ("s390/cio: introduce driver_override on the css bus") +Reviewed-by: Vineeth Vijayan +Link: https://patch.msgid.link/20260324005919.2408620-10-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/s390/cio/cio.h | 5 ----- + drivers/s390/cio/css.c | 34 ++++------------------------------ + 2 files changed, 4 insertions(+), 35 deletions(-) + +diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h +index 08a5e9380e75a..bad142c536e1e 100644 +--- a/drivers/s390/cio/cio.h ++++ b/drivers/s390/cio/cio.h +@@ -103,11 +103,6 @@ struct subchannel { + struct work_struct todo_work; + struct schib_config config; + u64 dma_mask; +- /* +- * Driver name to force a match. Do not set directly, because core +- * frees it. Use driver_set_override() to set or clear it. +- */ +- const char *driver_override; + } __attribute__ ((aligned(8))); + + DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb); +diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c +index 5ab239f38588f..e5a0ec6b4e3e7 100644 +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -159,7 +159,6 @@ static void css_subchannel_release(struct device *dev) + + sch->config.intparm = 0; + cio_commit_config(sch); +- kfree(sch->driver_override); + kfree(sch); + } + +@@ -323,37 +322,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + + static DEVICE_ATTR_RO(modalias); + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct subchannel *sch = to_subchannel(dev); +- int ret; +- +- ret = driver_set_override(dev, &sch->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct subchannel *sch = to_subchannel(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", sch->driver_override); +- device_unlock(dev); +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- + static struct attribute *subch_attrs[] = { + &dev_attr_type.attr, + &dev_attr_modalias.attr, +- &dev_attr_driver_override.attr, + NULL, + }; + +@@ -1356,9 +1327,11 @@ static int css_bus_match(struct device *dev, const struct device_driver *drv) + struct subchannel *sch = to_subchannel(dev); + const struct css_driver *driver = to_cssdriver(drv); + struct css_device_id *id; ++ int ret; + + /* When driver_override is set, only bind to the matching driver */ +- if (sch->driver_override && strcmp(sch->driver_override, drv->name)) ++ ret = device_match_driver_override(dev, drv); ++ if (ret == 0) + return 0; + + for (id = driver->subchannel_type; id->match_flags; id++) { +@@ -1415,6 +1388,7 @@ static int css_uevent(const struct device *dev, struct kobj_uevent_env *env) + + static const struct bus_type css_bus_type = { + .name = "css", ++ .driver_override = true, + .match = css_bus_match, + .probe = css_probe, + .remove = css_remove, +-- +2.53.0 + diff --git a/queue-7.0/s390-mm-fix-phys_to_folio-usage-in-do_secure_storage.patch b/queue-7.0/s390-mm-fix-phys_to_folio-usage-in-do_secure_storage.patch new file mode 100644 index 0000000000..0932895a4d --- /dev/null +++ b/queue-7.0/s390-mm-fix-phys_to_folio-usage-in-do_secure_storage.patch @@ -0,0 +1,44 @@ +From d2e86c270f7f9d593fa57929054c105a4e65a1d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 07:52:44 +0200 +Subject: s390/mm: Fix phys_to_folio() usage in do_secure_storage_access() + +From: Heiko Carstens + +[ Upstream commit b95e0e792822bad8fc9eb33ea3a90005e29e75e9 ] + +In case of a Secure-Storage-Access exception the effective aka virtual +address which caused the exception is contained within the TEID. + +do_secure_storage_access() incorrectly uses phys_to_folio() instead of +virt_to_folio() to translate the virtual address to the corresponding +folio. + +Fix this by using virt_to_folio() instead of phys_to_folio(). + +Fixes: 084ea4d611a3 ("s390/mm: add (non)secure page access exceptions handlers") +Reviewed-by: Christian Borntraeger +Reviewed-by: Claudio Imbrenda +Signed-off-by: Heiko Carstens +Signed-off-by: Alexander Gordeev +Signed-off-by: Sasha Levin +--- + arch/s390/mm/fault.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c +index 191cc53caead3..028aeb9c48d6f 100644 +--- a/arch/s390/mm/fault.c ++++ b/arch/s390/mm/fault.c +@@ -438,7 +438,7 @@ void do_secure_storage_access(struct pt_regs *regs) + panic("Unexpected PGM 0x3d with TEID bit 61=0"); + } + if (is_kernel_fault(regs)) { +- folio = phys_to_folio(addr); ++ folio = virt_to_folio((void *)addr); + if (unlikely(!folio_try_get(folio))) + return; + rc = uv_convert_from_secure(folio_to_phys(folio)); +-- +2.53.0 + diff --git a/queue-7.0/sched-fair-clear-rel_deadline-when-initializing-fork.patch b/queue-7.0/sched-fair-clear-rel_deadline-when-initializing-fork.patch new file mode 100644 index 0000000000..4616f23c29 --- /dev/null +++ b/queue-7.0/sched-fair-clear-rel_deadline-when-initializing-fork.patch @@ -0,0 +1,87 @@ +From 6ec4ee30b65afb0c8b13892510d28e41b486860d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Apr 2026 07:11:13 +0000 +Subject: sched/fair: Clear rel_deadline when initializing forked entities + +From: Zicheng Qu + +[ Upstream commit 3da56dc063cd77b9c0b40add930767fab4e389f3 ] + +A yield-triggered crash can happen when a newly forked sched_entity +enters the fair class with se->rel_deadline unexpectedly set. + +The failing sequence is: + + 1. A task is forked while se->rel_deadline is still set. + 2. __sched_fork() initializes vruntime, vlag and other sched_entity + state, but does not clear rel_deadline. + 3. On the first enqueue, enqueue_entity() calls place_entity(). + 4. Because se->rel_deadline is set, place_entity() treats se->deadline + as a relative deadline and converts it to an absolute deadline by + adding the current vruntime. + 5. However, the forked entity's deadline is not a valid inherited + relative deadline for this new scheduling instance, so the conversion + produces an abnormally large deadline. + 6. If the task later calls sched_yield(), yield_task_fair() advances + se->vruntime to se->deadline. + 7. The inflated vruntime is then used by the following enqueue path, + where the vruntime-derived key can overflow when multiplied by the + entity weight. + 8. This corrupts cfs_rq->sum_w_vruntime, breaks EEVDF eligibility + calculation, and can eventually make all entities appear ineligible. + pick_next_entity() may then return NULL unexpectedly, leading to a + later NULL dereference. + +A captured trace shows the effect clearly. Before yield, the entity's +vruntime was around: + + 9834017729983308 + +After yield_task_fair() executed: + + se->vruntime = se->deadline + +the vruntime jumped to: + + 19668035460670230 + +and the deadline was later advanced further to: + + 19668035463470230 + +This shows that the deadline had already become abnormally large before +yield_task_fair() copied it into vruntime. + +rel_deadline is only meaningful when se->deadline really carries a +relative deadline that still needs to be placed against vruntime. A +freshly forked sched_entity should not inherit or retain this state. +Clear se->rel_deadline in __sched_fork(), together with the other +sched_entity runtime state, so that the first enqueue does not interpret +the new entity's deadline as a stale relative deadline. + +Fixes: 82e9d0456e06 ("sched/fair: Avoid re-setting virtual deadline on 'migrations'") +Analyzed-by: Hui Tang +Analyzed-by: Zhang Qiao +Signed-off-by: Zicheng Qu +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260424071113.1199600-1-quzicheng@huawei.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index d5d0099d5ebf9..567b1b1efdb58 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -4398,6 +4398,7 @@ static void __sched_fork(u64 clone_flags, struct task_struct *p) + p->se.nr_migrations = 0; + p->se.vruntime = 0; + p->se.vlag = 0; ++ p->se.rel_deadline = 0; + INIT_LIST_HEAD(&p->se.group_node); + + /* A delayed task cannot be in clone(). */ +-- +2.53.0 + diff --git a/queue-7.0/sched-fair-fix-wakeup_preempt_fair-vs-delayed-dequeu.patch b/queue-7.0/sched-fair-fix-wakeup_preempt_fair-vs-delayed-dequeu.patch new file mode 100644 index 0000000000..5d2989a47b --- /dev/null +++ b/queue-7.0/sched-fair-fix-wakeup_preempt_fair-vs-delayed-dequeu.patch @@ -0,0 +1,118 @@ +From b3cf6480bf5e13ca146e7b2139872d4a2c572a51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 11:34:00 +0200 +Subject: sched/fair: Fix wakeup_preempt_fair() vs delayed dequeue + +From: Vincent Guittot + +[ Upstream commit ac8e69e693631689d74d8f1ebee6f84f737f797f ] + +Similar to how pick_next_entity() must dequeue delayed entities, so too must +wakeup_preempt_fair(). Any delayed task being found means it is eligible and +hence past the 0-lag point, ready for removal. + +Worse, by not removing delayed entities from consideration, it can skew the +preemption decision, with the end result that a short slice wakeup will not +result in a preemption. + + tip/sched/core tip/sched/core +this patch +cyclictest slice (ms) (default)2.8 8 8 +hackbench slice (ms) (default)2.8 20 20 +Total Samples | 22559 22595 22683 +Average (us) | 157 64( 59%) 59( 8%) +Median (P50) (us) | 57 57( 0%) 58(- 2%) +90th Percentile (us) | 64 60( 6%) 60( 0%) +99th Percentile (us) | 2407 67( 97%) 67( 0%) +99.9th Percentile (us) | 3400 2288( 33%) 727( 68%) +Maximum (us) | 5037 9252(-84%) 7461( 19%) + +Fixes: f12e148892ed ("sched/fair: Prepare pick_next_task() for delayed dequeue") +Signed-off-by: Vincent Guittot +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260422093400.319251-1-vincent.guittot@linaro.org +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index ab4114712be74..87200a22b3169 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -1007,7 +1007,7 @@ static inline void cancel_protect_slice(struct sched_entity *se) + * + * Which allows tree pruning through eligibility. + */ +-static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect) ++static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect) + { + struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node; + struct sched_entity *se = __pick_first_entity(cfs_rq); +@@ -1078,11 +1078,6 @@ static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq, bool protect) + return best; + } + +-static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq) +-{ +- return __pick_eevdf(cfs_rq, true); +-} +- + struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) + { + struct rb_node *last = rb_last(&cfs_rq->tasks_timeline.rb_root); +@@ -5540,11 +5535,11 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags); + * 4) do not run the "skip" process, if something else is available + */ + static struct sched_entity * +-pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq) ++pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq, bool protect) + { + struct sched_entity *se; + +- se = pick_eevdf(cfs_rq); ++ se = pick_eevdf(cfs_rq, protect); + if (se->sched_delayed) { + dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED); + /* +@@ -8809,7 +8804,7 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f + { + enum preempt_wakeup_action preempt_action = PREEMPT_WAKEUP_PICK; + struct task_struct *donor = rq->donor; +- struct sched_entity *se = &donor->se, *pse = &p->se; ++ struct sched_entity *nse, *se = &donor->se, *pse = &p->se; + struct cfs_rq *cfs_rq = task_cfs_rq(donor); + int cse_is_idle, pse_is_idle; + +@@ -8920,11 +8915,17 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f + } + + pick: ++ nse = pick_next_entity(rq, cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT); ++ /* If @p has become the most eligible task, force preemption */ ++ if (nse == pse) ++ goto preempt; ++ + /* +- * If @p has become the most eligible task, force preemption. ++ * Because p is enqueued, nse being null can only mean that we ++ * dequeued a delayed task. + */ +- if (__pick_eevdf(cfs_rq, preempt_action != PREEMPT_WAKEUP_SHORT) == pse) +- goto preempt; ++ if (!nse) ++ goto pick; + + if (sched_feat(RUN_TO_PARITY)) + update_protect_slice(cfs_rq, se); +@@ -8959,7 +8960,7 @@ static struct task_struct *pick_task_fair(struct rq *rq, struct rq_flags *rf) + + throttled |= check_cfs_rq_runtime(cfs_rq); + +- se = pick_next_entity(rq, cfs_rq); ++ se = pick_next_entity(rq, cfs_rq, true); + if (!se) + goto again; + cfs_rq = group_cfs_rq(se); +-- +2.53.0 + diff --git a/queue-7.0/sched-make-class_schedulers-avoid-pushing-current-an.patch b/queue-7.0/sched-make-class_schedulers-avoid-pushing-current-an.patch new file mode 100644 index 0000000000..8ccd916d26 --- /dev/null +++ b/queue-7.0/sched-make-class_schedulers-avoid-pushing-current-an.patch @@ -0,0 +1,168 @@ +From 3ac8cec3ec395d19d1543a0ca40bc68f991eebad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 19:13:16 +0000 +Subject: sched: Make class_schedulers avoid pushing current, and get rid of + proxy_tag_curr() + +From: John Stultz + +[ Upstream commit e0ca8991b2de6c9dfe6fcd8a0364951b2bd56797 ] + +With proxy-execution, the scheduler selects the donor, but for +blocked donors, we end up running the lock owner. + +This caused some complexity, because the class schedulers make +sure to remove the task they pick from their pushable task +lists, which prevents the donor from being migrated, but there +wasn't then anything to prevent rq->curr from being migrated +if rq->curr != rq->donor. + +This was sort of hacked around by calling proxy_tag_curr() on +the rq->curr task if we were running something other then the +donor. proxy_tag_curr() did a dequeue/enqueue pair on the +rq->curr task, allowing the class schedulers to remove it from +their pushable list. + +The dequeue/enqueue pair was wasteful, and additonally K Prateek +highlighted that we didn't properly undo things when we stopped +proxying, leaving the lock owner off the pushable list. + +After some alternative approaches were considered, Peter +suggested just having the RT/DL classes just avoid migrating +when task_on_cpu(). + +So rework pick_next_pushable_dl_task() and the rt +pick_next_pushable_task() functions so that they skip over the +first pushable task if it is on_cpu. + +Then just drop all of the proxy_tag_curr() logic. + +Fixes: be39617e38e0 ("sched: Fix proxy/current (push,pull)ability") +Closes: https://lore.kernel.org/lkml/e735cae0-2cc9-4bae-b761-fcb082ed3e94@amd.com/ +Reported-by: K Prateek Nayak +Suggested-by: Peter Zijlstra +Signed-off-by: John Stultz +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260324191337.1841376-2-jstultz@google.com +Signed-off-by: Sasha Levin +--- + kernel/sched/core.c | 24 ------------------------ + kernel/sched/deadline.c | 18 ++++++++++++++++-- + kernel/sched/rt.c | 15 ++++++++++++--- + 3 files changed, 28 insertions(+), 29 deletions(-) + +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 14e947bcb3e5c..d5d0099d5ebf9 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -6705,23 +6705,6 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf) + } + #endif /* SCHED_PROXY_EXEC */ + +-static inline void proxy_tag_curr(struct rq *rq, struct task_struct *owner) +-{ +- if (!sched_proxy_exec()) +- return; +- /* +- * pick_next_task() calls set_next_task() on the chosen task +- * at some point, which ensures it is not push/pullable. +- * However, the chosen/donor task *and* the mutex owner form an +- * atomic pair wrt push/pull. +- * +- * Make sure owner we run is not pushable. Unfortunately we can +- * only deal with that by means of a dequeue/enqueue cycle. :-/ +- */ +- dequeue_task(rq, owner, DEQUEUE_NOCLOCK | DEQUEUE_SAVE); +- enqueue_task(rq, owner, ENQUEUE_NOCLOCK | ENQUEUE_RESTORE); +-} +- + /* + * __schedule() is the main scheduler function. + * +@@ -6874,9 +6857,6 @@ static void __sched notrace __schedule(int sched_mode) + */ + RCU_INIT_POINTER(rq->curr, next); + +- if (!task_current_donor(rq, next)) +- proxy_tag_curr(rq, next); +- + /* + * The membarrier system call requires each architecture + * to have a full memory barrier after updating +@@ -6910,10 +6890,6 @@ static void __sched notrace __schedule(int sched_mode) + /* Also unlocks the rq: */ + rq = context_switch(rq, prev, next, &rf); + } else { +- /* In case next was already curr but just got blocked_donor */ +- if (!task_current_donor(rq, next)) +- proxy_tag_curr(rq, next); +- + rq_unpin_lock(rq, &rf); + __balance_callbacks(rq, NULL); + raw_spin_rq_unlock_irq(rq); +diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c +index 674de6a48551b..b8145ccd94daf 100644 +--- a/kernel/sched/deadline.c ++++ b/kernel/sched/deadline.c +@@ -2801,12 +2801,26 @@ static int find_later_rq(struct task_struct *task) + + static struct task_struct *pick_next_pushable_dl_task(struct rq *rq) + { +- struct task_struct *p; ++ struct task_struct *i, *p = NULL; ++ struct rb_node *next_node; + + if (!has_pushable_dl_tasks(rq)) + return NULL; + +- p = __node_2_pdl(rb_first_cached(&rq->dl.pushable_dl_tasks_root)); ++ next_node = rb_first_cached(&rq->dl.pushable_dl_tasks_root); ++ while (next_node) { ++ i = __node_2_pdl(next_node); ++ /* make sure task isn't on_cpu (possible with proxy-exec) */ ++ if (!task_on_cpu(rq, i)) { ++ p = i; ++ break; ++ } ++ ++ next_node = rb_next(next_node); ++ } ++ ++ if (!p) ++ return NULL; + + WARN_ON_ONCE(rq->cpu != task_cpu(p)); + WARN_ON_ONCE(task_current(rq, p)); +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 906f6c656c2e9..87462d889f199 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -1853,13 +1853,22 @@ static int find_lowest_rq(struct task_struct *task) + + static struct task_struct *pick_next_pushable_task(struct rq *rq) + { +- struct task_struct *p; ++ struct plist_head *head = &rq->rt.pushable_tasks; ++ struct task_struct *i, *p = NULL; + + if (!has_pushable_tasks(rq)) + return NULL; + +- p = plist_first_entry(&rq->rt.pushable_tasks, +- struct task_struct, pushable_tasks); ++ plist_for_each_entry(i, head, pushable_tasks) { ++ /* make sure task isn't on_cpu (possible with proxy-exec) */ ++ if (!task_on_cpu(rq, i)) { ++ p = i; ++ break; ++ } ++ } ++ ++ if (!p) ++ return NULL; + + BUG_ON(rq->cpu != task_cpu(p)); + BUG_ON(task_current(rq, p)); +-- +2.53.0 + diff --git a/queue-7.0/sched-psi-fix-race-between-file-release-and-pressure.patch b/queue-7.0/sched-psi-fix-race-between-file-release-and-pressure.patch new file mode 100644 index 0000000000..8d75473856 --- /dev/null +++ b/queue-7.0/sched-psi-fix-race-between-file-release-and-pressure.patch @@ -0,0 +1,184 @@ +From e21437a67a47e72df1dff6868d8ce8928fdc8b01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Apr 2026 14:15:43 +0800 +Subject: sched/psi: fix race between file release and pressure write + +From: Edward Adam Davis + +[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ] + +A potential race condition exists between pressure write and cgroup file +release regarding the priv member of struct kernfs_open_file, which +triggers the uaf reported in [1]. + +Consider the following scenario involving execution on two separate CPUs: + + CPU0 CPU1 + ==== ==== + vfs_rmdir() + kernfs_iop_rmdir() + cgroup_rmdir() + cgroup_kn_lock_live() + cgroup_destroy_locked() + cgroup_addrm_files() + cgroup_rm_file() + kernfs_remove_by_name() + kernfs_remove_by_name_ns() + vfs_write() __kernfs_remove() + new_sync_write() kernfs_drain() + kernfs_fop_write_iter() kernfs_drain_open_files() + cgroup_file_write() kernfs_release_file() + pressure_write() cgroup_file_release() + ctx = of->priv; + kfree(ctx); + of->priv = NULL; + cgroup_kn_unlock() + cgroup_kn_lock_live() + cgroup_get(cgrp) + cgroup_kn_unlock() + if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv + +The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards +the memory deallocation of of->priv performed within cgroup_file_release(). +However, the operations involving of->priv executed within pressure_write() +are not entirely covered by the protection of cgroup_mutex. Consequently, +if the code in pressure_write(), specifically the section handling the +ctx variable executes after cgroup_file_release() has completed, a uaf +vulnerability involving of->priv is triggered. + +Therefore, the issue can be resolved by extending the scope of the +cgroup_mutex lock within pressure_write() to encompass all code paths +involving of->priv, thereby properly synchronizing the race condition +occurring between cgroup_file_release() and pressure_write(). + +And, if an live kn lock can be successfully acquired while executing +the pressure write operation, it indicates that the cgroup deletion +process has not yet reached its final stage; consequently, the priv +pointer within open_file cannot be NULL. Therefore, the operation to +retrieve the ctx value must be moved to a point *after* the live kn +lock has been successfully acquired. + +In another situation, specifically after entering cgroup_kn_lock_live() +but before acquiring cgroup_mutex, there exists a different class of +race condition: + +CPU0: write memory.pressure CPU1: write cgroup.pressure=0 +=========================== ============================= + +kernfs_fop_write_iter() + kernfs_get_active_of(of) + pressure_write() + cgroup_kn_lock_live(memory.pressure) + cgroup_tryget(cgrp) + kernfs_break_active_protection(kn) + ... blocks on cgroup_mutex + + cgroup_pressure_write() + cgroup_kn_lock_live(cgroup.pressure) + cgroup_file_show(memory.pressure, false) + kernfs_show(false) + kernfs_drain_open_files() + cgroup_file_release(of) + kfree(ctx) + of->priv = NULL + cgroup_kn_unlock() + + ... acquires cgroup_mutex + ctx = of->priv; // may now be NULL + if (ctx->psi.trigger) // NULL dereference + +Consequently, there is a possibility that of->priv is NULL, the pressure +write needs to check for this. + +Now that the scope of the cgroup_mutex has been expanded, the original +explicit cgroup_get/put operations are no longer necessary, this is +because acquiring/releasing the live kn lock inherently executes a +cgroup get/put operation. + +[1] +BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 +Call Trace: + pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 + cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 + kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 + +Allocated by task 9352: + cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 + kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 + do_dentry_open+0x83d/0x13e0 fs/open.c:949 + +Freed by task 9353: + cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 + kernfs_release_file fs/kernfs/file.c:764 [inline] + kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 + kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525 + +Fixes: 0e94682b73bf ("psi: introduce psi monitor") +Reported-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=33e571025d88efd1312c +Tested-by: syzbot+33e571025d88efd1312c@syzkaller.appspotmail.com +Signed-off-by: Edward Adam Davis +Reviewed-by: Chen Ridong +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c +index 6b2ee75c63ebc..8789ba613ea16 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -4018,33 +4018,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) + static ssize_t pressure_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, enum psi_res res) + { +- struct cgroup_file_ctx *ctx = of->priv; ++ struct cgroup_file_ctx *ctx; + struct psi_trigger *new; + struct cgroup *cgrp; + struct psi_group *psi; ++ ssize_t ret = 0; + + cgrp = cgroup_kn_lock_live(of->kn, false); + if (!cgrp) + return -ENODEV; + +- cgroup_get(cgrp); +- cgroup_kn_unlock(of->kn); ++ ctx = of->priv; ++ if (!ctx) { ++ ret = -ENODEV; ++ goto out_unlock; ++ } + + /* Allow only one trigger per file descriptor */ + if (ctx->psi.trigger) { +- cgroup_put(cgrp); +- return -EBUSY; ++ ret = -EBUSY; ++ goto out_unlock; + } + + psi = cgroup_psi(cgrp); + new = psi_trigger_create(psi, buf, res, of->file, of); + if (IS_ERR(new)) { +- cgroup_put(cgrp); +- return PTR_ERR(new); ++ ret = PTR_ERR(new); ++ goto out_unlock; + } + + smp_store_release(&ctx->psi.trigger, new); +- cgroup_put(cgrp); ++ ++out_unlock: ++ cgroup_kn_unlock(of->kn); ++ if (ret) ++ return ret; + + return nbytes; + } +-- +2.53.0 + diff --git a/queue-7.0/sched-rt-skip-group-schedulable-check-with-rt_group_.patch b/queue-7.0/sched-rt-skip-group-schedulable-check-with-rt_group_.patch new file mode 100644 index 0000000000..e460c3af5c --- /dev/null +++ b/queue-7.0/sched-rt-skip-group-schedulable-check-with-rt_group_.patch @@ -0,0 +1,63 @@ +From 38d70c3af480b3b16437bb37033d14b8e04d7e13 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 13:39:37 +0100 +Subject: sched/rt: Skip group schedulable check with rt_group_sched=0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Koutný + +[ Upstream commit 8b016dcec9365675be81d26be88f2c09cf983bd4 ] + +The warning from the commit 87f1fb77d87a6 ("sched: Add RT_GROUP WARN +checks for non-root task_groups") is wrong -- it assumes that only +task_groups with rt_rq are traversed, however, the schedulability check +would iterate all task_groups even when rt_group_sched=0 is disabled at +boot time but some non-root task_groups exist. + +The schedulability check is supposed to validate: + a) that children don't overcommit its parent, + b) no RT task group overcommits global RT limit. +but with rt_group_sched=0 there is no (non-trivial) hierarchy of RT groups, +therefore skip the validation altogether. Otherwise, writes to the +global sched_rt_runtime_us knob will be rejected with incorrect +validation error. + +This fix is immaterial with CONFIG_RT_GROUP_SCHED=n. + +Fixes: 87f1fb77d87a6 ("sched: Add RT_GROUP WARN checks for non-root task_groups") +Signed-off-by: Michal Koutný +Signed-off-by: Peter Zijlstra (Intel) +Link: https://patch.msgid.link/20260323-sched-rert_groups-v3-1-1e7d5ed6b249@suse.com +Signed-off-by: Sasha Levin +--- + kernel/sched/rt.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c +index 87462d889f199..0cbee031858a5 100644 +--- a/kernel/sched/rt.c ++++ b/kernel/sched/rt.c +@@ -2685,9 +2685,6 @@ static int tg_rt_schedulable(struct task_group *tg, void *data) + tg->rt_bandwidth.rt_runtime && tg_has_rt_tasks(tg)) + return -EBUSY; + +- if (WARN_ON(!rt_group_sched_enabled() && tg != &root_task_group)) +- return -EBUSY; +- + total = to_ratio(period, runtime); + + /* +@@ -2831,6 +2828,8 @@ long sched_group_rt_period(struct task_group *tg) + static int sched_rt_global_constraints(void) + { + int ret = 0; ++ if (!rt_group_sched_enabled()) ++ return ret; + + mutex_lock(&rt_constraints_mutex); + ret = __rt_schedulable(NULL, 0, 0); +-- +2.53.0 + diff --git a/queue-7.0/sched-topology-compute-sd_weight-considering-cpuset-.patch b/queue-7.0/sched-topology-compute-sd_weight-considering-cpuset-.patch new file mode 100644 index 0000000000..0ee79683c9 --- /dev/null +++ b/queue-7.0/sched-topology-compute-sd_weight-considering-cpuset-.patch @@ -0,0 +1,94 @@ +From a78758d38d592945284e0eaede4dd0f895f27f38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 04:44:26 +0000 +Subject: sched/topology: Compute sd_weight considering cpuset partitions + +From: K Prateek Nayak + +[ Upstream commit 8e8e23dea43e64ddafbd1246644c3219209be113 ] + +The "sd_weight" used for calculating the load balancing interval, and +its limits, considers the span weight of the entire topology level +without accounting for cpuset partitions. + +For example, consider a large system of 128CPUs divided into 8 * 16CPUs +partition which is typical when deploying virtual machines: + + [ PKG Domain: 128CPUs ] + + [Partition0: 16CPUs][Partition1: 16CPUs] ... [Partition7: 16CPUs] + +Although each partition only contains 16CPUs, the load balancing +interval is set to a minimum of 128 jiffies considering the span of the +entire domain with 128CPUs which can lead to longer imbalances within +the partition although balancing within is cheaper with 16CPUs. + +Compute the "sd_weight" after computing the "sd_span" considering the +cpu_map covered by the partition, and set the load balancing interval, +and its limits accordingly. + +For the above example, the balancing intervals for the partitions PKG +domain changes as follows: + + before after +balance_interval 128 16 +min_interval 128 16 +max_interval 256 32 + +Intervals are now proportional to the CPUs in the partitioned domain as +was intended by the original formula. + +Fixes: cb83b629bae03 ("sched/numa: Rewrite the CONFIG_NUMA sched domain support") +Signed-off-by: K Prateek Nayak +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Shrikanth Hegde +Reviewed-by: Chen Yu +Reviewed-by: Valentin Schneider +Reviewed-by: Dietmar Eggemann +Tested-by: Dietmar Eggemann +Link: https://patch.msgid.link/20260312044434.1974-2-kprateek.nayak@amd.com +Signed-off-by: Sasha Levin +--- + kernel/sched/topology.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c +index 32dcddaead82d..2864f43bff6df 100644 +--- a/kernel/sched/topology.c ++++ b/kernel/sched/topology.c +@@ -1643,13 +1643,17 @@ sd_init(struct sched_domain_topology_level *tl, + int sd_id, sd_weight, sd_flags = 0; + struct cpumask *sd_span; + +- sd_weight = cpumask_weight(tl->mask(tl, cpu)); ++ sd_span = sched_domain_span(sd); ++ cpumask_and(sd_span, cpu_map, tl->mask(tl, cpu)); ++ sd_weight = cpumask_weight(sd_span); ++ sd_id = cpumask_first(sd_span); + + if (tl->sd_flags) + sd_flags = (*tl->sd_flags)(); + if (WARN_ONCE(sd_flags & ~TOPOLOGY_SD_FLAGS, +- "wrong sd_flags in topology description\n")) ++ "wrong sd_flags in topology description\n")) + sd_flags &= TOPOLOGY_SD_FLAGS; ++ sd_flags |= asym_cpu_capacity_classify(sd_span, cpu_map); + + *sd = (struct sched_domain){ + .min_interval = sd_weight, +@@ -1686,12 +1690,6 @@ sd_init(struct sched_domain_topology_level *tl, + .name = tl->name, + }; + +- sd_span = sched_domain_span(sd); +- cpumask_and(sd_span, cpu_map, tl->mask(tl, cpu)); +- sd_id = cpumask_first(sd_span); +- +- sd->flags |= asym_cpu_capacity_classify(sd_span, cpu_map); +- + WARN_ONCE((sd->flags & (SD_SHARE_CPUCAPACITY | SD_ASYM_CPUCAPACITY)) == + (SD_SHARE_CPUCAPACITY | SD_ASYM_CPUCAPACITY), + "CPU capacity asymmetry not supported on SMT\n"); +-- +2.53.0 + diff --git a/queue-7.0/sched-topology-fix-sched_domain_span.patch b/queue-7.0/sched-topology-fix-sched_domain_span.patch new file mode 100644 index 0000000000..dead269993 --- /dev/null +++ b/queue-7.0/sched-topology-fix-sched_domain_span.patch @@ -0,0 +1,92 @@ +From 5a238b385e0bf63ebe2cef0706d4031f5e3d292f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 10:36:27 +0100 +Subject: sched/topology: Fix sched_domain_span() + +From: Peter Zijlstra + +[ Upstream commit e379dce8af11d8d6040b4348316a499bfd174bfb ] + +Commit 8e8e23dea43e ("sched/topology: Compute sd_weight considering +cpuset partitions") ends up relying on the fact that structure +initialization should not touch the flexible array. + +However, the official GCC specification for "Arrays of Length Zero" +[*] says: + + Although the size of a zero-length array is zero, an array member of + this kind may increase the size of the enclosing type as a result of + tail padding. + +Additionally, structure initialization will zero tail padding. With +the end result that since offsetof(*type, member) < sizeof(*type), +array initialization will clobber the flex array. + +Luckily, the way flexible array sizes are calculated is: + + sizeof(*type) + count * sizeof(*type->member) + +This means we have the complete size of the flex array *outside* of +sizeof(*type), so use that instead of relying on the broken flex array +definition. + +[*] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html + +Fixes: 8e8e23dea43e ("sched/topology: Compute sd_weight considering cpuset partitions") +Reported-by: Nathan Chancellor +Debugged-by: K Prateek Nayak +Signed-off-by: Peter Zijlstra (Intel) +Tested-by: Jon Hunter +Tested-by: Chen Yu +Tested-by: K Prateek Nayak +Tested-by: Nathan Chancellor +Link: https://patch.msgid.link/20260323093627.GY3738010@noisy.programming.kicks-ass.net +Signed-off-by: Sasha Levin +--- + include/linux/sched/topology.h | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/include/linux/sched/topology.h b/include/linux/sched/topology.h +index 45c0022b91ced..6f8a4ae860da8 100644 +--- a/include/linux/sched/topology.h ++++ b/include/linux/sched/topology.h +@@ -141,18 +141,30 @@ struct sched_domain { + + unsigned int span_weight; + /* +- * Span of all CPUs in this domain. ++ * See sched_domain_span(), on why flex arrays are broken. + * +- * NOTE: this field is variable length. (Allocated dynamically +- * by attaching extra space to the end of the structure, +- * depending on how many CPUs the kernel has booted up with) +- */ + unsigned long span[]; ++ */ + }; + + static inline struct cpumask *sched_domain_span(struct sched_domain *sd) + { +- return to_cpumask(sd->span); ++ /* ++ * Turns out that C flexible arrays are fundamentally broken since it ++ * is allowed for offsetof(*sd, span) < sizeof(*sd), this means that ++ * structure initialzation *sd = { ... }; which writes every byte ++ * inside sizeof(*type), will over-write the start of the flexible ++ * array. ++ * ++ * Luckily, the way we allocate sched_domain is by: ++ * ++ * sizeof(*sd) + cpumask_size() ++ * ++ * this means that we have sufficient space for the whole flex array ++ * *outside* of sizeof(*sd). So use that, and avoid using sd->span. ++ */ ++ unsigned long *bitmap = (void *)sd + sizeof(*sd); ++ return to_cpumask(bitmap); + } + + extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], +-- +2.53.0 + diff --git a/queue-7.0/sched_ext-fix-ops.cgroup_move-invocation-kf_mask-and.patch b/queue-7.0/sched_ext-fix-ops.cgroup_move-invocation-kf_mask-and.patch new file mode 100644 index 0000000000..b30d42e6a7 --- /dev/null +++ b/queue-7.0/sched_ext-fix-ops.cgroup_move-invocation-kf_mask-and.patch @@ -0,0 +1,63 @@ +From f1a80e119c16e4e7107936b4c76cee02ef73fdfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:54:06 -1000 +Subject: sched_ext: Fix ops.cgroup_move() invocation kf_mask and rq tracking + +From: Tejun Heo + +[ Upstream commit b470e37c1fad72731be6f437e233cb6b16618f41 ] + +sched_move_task() invokes ops.cgroup_move() inside task_rq_lock(tsk), so +@p's rq lock is held. The SCX_CALL_OP_TASK invocation mislabels this: + + - kf_mask = SCX_KF_UNLOCKED (== 0), claiming no lock is held. + - rq = NULL, so update_locked_rq() doesn't run and scx_locked_rq() + returns NULL. + +Switch to SCX_KF_REST and pass task_rq(p), matching ops.set_cpumask() +from set_cpus_allowed_scx(). + +Three effects: + + - scx_bpf_task_cgroup() becomes callable (was rejected by + scx_kf_allowed(__SCX_KF_RQ_LOCKED)). Safe; rq lock is held. + + - scx_bpf_dsq_move() is now rejected (was allowed via the unlocked + branch). Calling it while holding an unrelated task's rq lock is + risky; rejection is correct. + + - scx_bpf_select_cpu_*() previously took the unlocked branch in + select_cpu_from_kfunc() and called task_rq_lock(p, &rf), which + would deadlock against the already-held pi_lock. Now it takes the + locked-rq branch and is rejected with -EPERM via the existing + kf_allowed(SCX_KF_SELECT_CPU | SCX_KF_ENQUEUE) check. Latent + deadlock fix. + +No in-tree scheduler is known to call any of these from ops.cgroup_move(). + +v2: Add Fixes: tag (Andrea Righi). + +Fixes: 18853ba782be ("sched_ext: Track currently locked rq") +Signed-off-by: Tejun Heo +Reviewed-by: Andrea Righi +Signed-off-by: Sasha Levin +--- + kernel/sched/ext.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index 29ee463ec9bc4..3ac01ea9bfb1a 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -3406,7 +3406,7 @@ void scx_cgroup_move_task(struct task_struct *p) + */ + if (SCX_HAS_OP(sch, cgroup_move) && + !WARN_ON_ONCE(!p->scx.cgrp_moving_from)) +- SCX_CALL_OP_TASK(sch, SCX_KF_UNLOCKED, cgroup_move, NULL, ++ SCX_CALL_OP_TASK(sch, SCX_KF_REST, cgroup_move, task_rq(p), + p, p->scx.cgrp_moving_from, + tg_cgrp(task_group(p))); + p->scx.cgrp_moving_from = NULL; +-- +2.53.0 + diff --git a/queue-7.0/sched_ext-track-p-s-rq-lock-across-set_cpus_allowed_.patch b/queue-7.0/sched_ext-track-p-s-rq-lock-across-set_cpus_allowed_.patch new file mode 100644 index 0000000000..b44c902282 --- /dev/null +++ b/queue-7.0/sched_ext-track-p-s-rq-lock-across-set_cpus_allowed_.patch @@ -0,0 +1,40 @@ +From 419bb6c655e93476d0108bd77ba4ce1ed2dd4769 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 07:54:06 -1000 +Subject: sched_ext: Track @p's rq lock across set_cpus_allowed_scx -> + ops.set_cpumask + +From: Tejun Heo + +[ Upstream commit 9fb457074f6d118b30458624223abef985725a88 ] + +The SCX_CALL_OP_TASK call site passes rq=NULL incorrectly, leaving +scx_locked_rq() unset. Pass task_rq(p) instead so update_locked_rq() +reflects reality. + +v2: Add Fixes: tag (Andrea Righi). + +Fixes: 18853ba782be ("sched_ext: Track currently locked rq") +Signed-off-by: Tejun Heo +Reviewed-by: Andrea Righi +Signed-off-by: Sasha Levin +--- + kernel/sched/ext.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index 9c7ff5179e4f1..29ee463ec9bc4 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -2742,7 +2742,7 @@ static void set_cpus_allowed_scx(struct task_struct *p, + * designation pointless. Cast it away when calling the operation. + */ + if (SCX_HAS_OP(sch, set_cpumask)) +- SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_cpumask, NULL, ++ SCX_CALL_OP_TASK(sch, SCX_KF_REST, set_cpumask, task_rq(p), + p, (struct cpumask *)p->cpus_ptr); + } + +-- +2.53.0 + diff --git a/queue-7.0/scripts-gdb-timerlist-adapt-to-move-of-tk_core.patch b/queue-7.0/scripts-gdb-timerlist-adapt-to-move-of-tk_core.patch new file mode 100644 index 0000000000..9f8e52dd83 --- /dev/null +++ b/queue-7.0/scripts-gdb-timerlist-adapt-to-move-of-tk_core.patch @@ -0,0 +1,41 @@ +From 4ffb8dbbbb5c63f859fe569ce2fe4385b16ad7f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 11:15:10 +0100 +Subject: scripts/gdb: timerlist: Adapt to move of tk_core +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh (Schneider Electric) + +[ Upstream commit 5aa9383813aca45b914d4a7481ca417ef13114df ] + +tk_core is a macro today which cannot be resolved by gdb. + +Use the correct symbol expression to reference tk_core. + +Fixes: 22c62b9a84b8 ("timekeeping: Introduce auxiliary timekeepers") +Signed-off-by: Thomas Weißschuh (Schneider Electric) +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260311-hrtimer-cleanups-v1-1-095357392669@linutronix.de +Signed-off-by: Sasha Levin +--- + scripts/gdb/linux/timerlist.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py +index ccc24d30de806..9fb3436a217cc 100644 +--- a/scripts/gdb/linux/timerlist.py ++++ b/scripts/gdb/linux/timerlist.py +@@ -20,7 +20,7 @@ def ktime_get(): + We can't read the hardware timer itself to add any nanoseconds + that need to be added since we last stored the time in the + timekeeper. But this is probably good enough for debug purposes.""" +- tk_core = gdb.parse_and_eval("&tk_core") ++ tk_core = gdb.parse_and_eval("&timekeeper_data[TIMEKEEPER_CORE]") + + return tk_core['timekeeper']['tkr_mono']['base'] + +-- +2.53.0 + diff --git a/queue-7.0/scsi-hpsa-enlarge-controller-and-irq-name-buffers.patch b/queue-7.0/scsi-hpsa-enlarge-controller-and-irq-name-buffers.patch new file mode 100644 index 0000000000..afc3ad6495 --- /dev/null +++ b/queue-7.0/scsi-hpsa-enlarge-controller-and-irq-name-buffers.patch @@ -0,0 +1,55 @@ +From 02b7af9c16e9a6ae82ceb16de96a185a226d7a46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 20:05:52 +0800 +Subject: scsi: hpsa: Enlarge controller and IRQ name buffers + +From: Pengpeng Hou + +[ Upstream commit 8e8cb6f39930e836144f51cdb6d409c9e4cb71fe ] + +hpsa formats the controller name into h->devname[8] and derives +interrupt names from it in h->intrname[][16]. Once host_no reaches four +digits, "hpsa%d" no longer fits in devname, and the derived IRQ names +can then overrun the interrupt-name buffers as well. + +The previous fix switched these builders to bounded formatting, but that +would truncate user-visible controller and IRQ names. Keep the existing +names intact instead by enlarging the fixed buffers to cover the current +formatted strings. + +Fixes: 2946e82bdd76 ("hpsa: use scsi host_no as hpsa controller number") +Fixes: 8b47004a5512 ("hpsa: add interrupt number to /proc/interrupts interrupt name") +Acked-by: Don Brace +Signed-off-by: Pengpeng Hou +Link: https://patch.msgid.link/20260401120552.78541-1-pengpeng@iscas.ac.cn +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/hpsa.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h +index 99b0750850b2b..f6bfe75dd696d 100644 +--- a/drivers/scsi/hpsa.h ++++ b/drivers/scsi/hpsa.h +@@ -164,7 +164,7 @@ struct bmic_controller_parameters { + struct ctlr_info { + unsigned int *reply_map; + int ctlr; +- char devname[8]; ++ char devname[16]; + char *product_name; + struct pci_dev *pdev; + u32 board_id; +@@ -255,7 +255,7 @@ struct ctlr_info { + int remove_in_progress; + /* Address of h->q[x] is passed to intr handler to know which queue */ + u8 q[MAX_REPLY_QUEUES]; +- char intrname[MAX_REPLY_QUEUES][16]; /* "hpsa0-msix00" names */ ++ char intrname[MAX_REPLY_QUEUES][32]; /* controller and IRQ names */ + u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ + #define HPSATMF_BITS_SUPPORTED (1 << 0) + #define HPSATMF_PHYS_LUN_RESET (1 << 1) +-- +2.53.0 + diff --git a/queue-7.0/scsi-qla2xxx-add-support-to-report-mpi-fw-state.patch b/queue-7.0/scsi-qla2xxx-add-support-to-report-mpi-fw-state.patch new file mode 100644 index 0000000000..319a5f5bfd --- /dev/null +++ b/queue-7.0/scsi-qla2xxx-add-support-to-report-mpi-fw-state.patch @@ -0,0 +1,164 @@ +From e73f523ddb8f646f27bf61b7bcc1db458bc45192 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 15:03:37 +0530 +Subject: scsi: qla2xxx: Add support to report MPI FW state + +From: Nilesh Javali + +[ Upstream commit 0e124af675ebabddacfeb0958abd443265dddf13 ] + +MPI firmware state was returned as 0. Get MPI FW state to proceed with +flash image validation. + +A new sysfs node 'mpi_fw_state' is added to report MPI firmware state: + + /sys/class/scsi_host/hostXX/mpi_fw_state + +Fixes: d74181ca110e ("scsi: qla2xxx: Add bsg interface to support firmware img validation") +Signed-off-by: Nilesh Javali +Link: https://patch.msgid.link/20260305093337.2007205-1-njavali@marvell.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/qla2xxx/qla_attr.c | 62 ++++++++++++++++++++++++++++++++- + drivers/scsi/qla2xxx/qla_init.c | 2 +- + drivers/scsi/qla2xxx/qla_mbx.c | 9 +++++ + 3 files changed, 71 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c +index 2e584a8bf66b2..6a05ce195aa05 100644 +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -1638,7 +1638,7 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, + { + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int rval = QLA_FUNCTION_FAILED; +- uint16_t state[6]; ++ uint16_t state[16]; + uint32_t pstate; + + if (IS_QLAFX00(vha->hw)) { +@@ -2402,6 +2402,63 @@ qla2x00_dport_diagnostics_show(struct device *dev, + vha->dport_data[0], vha->dport_data[1], + vha->dport_data[2], vha->dport_data[3]); + } ++ ++static ssize_t ++qla2x00_mpi_fw_state_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); ++ int rval = QLA_FUNCTION_FAILED; ++ u16 state[16]; ++ u16 mpi_state; ++ struct qla_hw_data *ha = vha->hw; ++ ++ if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha))) ++ return scnprintf(buf, PAGE_SIZE, ++ "MPI state reporting is not supported for this HBA.\n"); ++ ++ memset(state, 0, sizeof(state)); ++ ++ mutex_lock(&vha->hw->optrom_mutex); ++ if (qla2x00_chip_is_down(vha)) { ++ mutex_unlock(&vha->hw->optrom_mutex); ++ ql_dbg(ql_dbg_user, vha, 0x70df, ++ "ISP reset is in progress, failing mpi_fw_state.\n"); ++ return -EBUSY; ++ } else if (vha->hw->flags.eeh_busy) { ++ mutex_unlock(&vha->hw->optrom_mutex); ++ ql_dbg(ql_dbg_user, vha, 0x70ea, ++ "HBA in PCI error state, failing mpi_fw_state.\n"); ++ return -EBUSY; ++ } ++ ++ rval = qla2x00_get_firmware_state(vha, state); ++ mutex_unlock(&vha->hw->optrom_mutex); ++ if (rval != QLA_SUCCESS) { ++ ql_dbg(ql_dbg_user, vha, 0x70eb, ++ "MB Command to retrieve MPI state failed (%d), failing mpi_fw_state.\n", ++ rval); ++ return -EIO; ++ } ++ ++ mpi_state = state[11]; ++ ++ if (!(mpi_state & BIT_15)) ++ return scnprintf(buf, PAGE_SIZE, ++ "MPI firmware state reporting is not supported by this firmware. (0x%02x)\n", ++ mpi_state); ++ ++ if (!(mpi_state & BIT_8)) ++ return scnprintf(buf, PAGE_SIZE, ++ "MPI firmware is disabled. (0x%02x)\n", ++ mpi_state); ++ ++ return scnprintf(buf, PAGE_SIZE, ++ "MPI firmware is enabled, state is %s. (0x%02x)\n", ++ mpi_state & BIT_9 ? "active" : "inactive", ++ mpi_state); ++} ++ + static DEVICE_ATTR(dport_diagnostics, 0444, + qla2x00_dport_diagnostics_show, NULL); + +@@ -2469,6 +2526,8 @@ static DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show, + qla2x00_port_speed_store); + static DEVICE_ATTR(port_no, 0444, qla2x00_port_no_show, NULL); + static DEVICE_ATTR(fw_attr, 0444, qla2x00_fw_attr_show, NULL); ++static DEVICE_ATTR(mpi_fw_state, 0444, qla2x00_mpi_fw_state_show, NULL); ++ + + static struct attribute *qla2x00_host_attrs[] = { + &dev_attr_driver_version.attr.attr, +@@ -2517,6 +2576,7 @@ static struct attribute *qla2x00_host_attrs[] = { + &dev_attr_qlini_mode.attr, + &dev_attr_ql2xiniexchg.attr, + &dev_attr_ql2xexchoffld.attr, ++ &dev_attr_mpi_fw_state.attr, + NULL, + }; + +diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c +index 730c42b1a7b9d..e746c9274cded 100644 +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -4914,7 +4914,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) + unsigned long wtime, mtime, cs84xx_time; + uint16_t min_wait; /* Minimum wait time if loop is down */ + uint16_t wait_time; /* Wait time if loop is coming ready */ +- uint16_t state[6]; ++ uint16_t state[16]; + struct qla_hw_data *ha = vha->hw; + + if (IS_QLAFX00(vha->hw)) +diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c +index 0d598be6f3eab..44e310f1a3708 100644 +--- a/drivers/scsi/qla2xxx/qla_mbx.c ++++ b/drivers/scsi/qla2xxx/qla_mbx.c +@@ -2268,6 +2268,13 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) + mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + else + mcp->in_mb = MBX_1|MBX_0; ++ ++ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { ++ mcp->mb[12] = 0; ++ mcp->out_mb |= MBX_12; ++ mcp->in_mb |= MBX_12; ++ } ++ + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); +@@ -2280,6 +2287,8 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) + states[3] = mcp->mb[4]; + states[4] = mcp->mb[5]; + states[5] = mcp->mb[6]; /* DPORT status */ ++ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) ++ states[11] = mcp->mb[12]; /* MPI state. */ + } + + if (rval != QLA_SUCCESS) { +-- +2.53.0 + diff --git a/queue-7.0/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch b/queue-7.0/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch new file mode 100644 index 0000000000..e250c2701f --- /dev/null +++ b/queue-7.0/scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch @@ -0,0 +1,45 @@ +From f418ba52dd42e716b9c88b3326038a3350c9da5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:42 +0800 +Subject: scsi: sg: Fix sysctl sg-big-buff register during sg_init() + +From: Yang Erkun + +[ Upstream commit 3033c471aaf675254efaa0da431e95d91a104b41 ] + +Commit 26d1c80fd61e ("scsi/sg: move sg-big-buff sysctl to scsi/sg.c") made +a mistake. sysctl sg-big-buff was not created because the call to +register_sg_sysctls() was placed on the wrong code path. + +Fixes: 26d1c80fd61e ("scsi/sg: move sg-big-buff sysctl to scsi/sg.c") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-2-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 37bac49f30f0d..71d34186dec93 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1691,13 +1691,13 @@ init_sg(void) + sg_sysfs_valid = 1; + rc = scsi_register_interface(&sg_interface); + if (0 == rc) { ++ register_sg_sysctls(); + #ifdef CONFIG_SCSI_PROC_FS + sg_proc_init(); + #endif /* CONFIG_SCSI_PROC_FS */ + return 0; + } + class_unregister(&sg_sysfs_class); +- register_sg_sysctls(); + err_out: + unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); + return rc; +-- +2.53.0 + diff --git a/queue-7.0/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch b/queue-7.0/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch new file mode 100644 index 0000000000..e068e1dfa1 --- /dev/null +++ b/queue-7.0/scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch @@ -0,0 +1,100 @@ +From 86c5be329f69638774aac42294762f1736c253b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jan 2026 14:20:43 +0800 +Subject: scsi: sg: Resolve soft lockup issue when opening /dev/sgX + +From: Yang Erkun + +[ Upstream commit d06a310b45e153872033dd0cf19d5a2279121099 ] + +The parameter def_reserved_size defines the default buffer size reserved +for each Sg_fd and should be restricted to a range between 0 and 1,048,576 +(see https://tldp.org/HOWTO/SCSI-Generic-HOWTO/proc.html). Although the +function sg_proc_write_dressz enforces this limit, it is possible to bypass +it by directly modifying the module parameter as shown below, which then +causes a soft lockup: + +echo -1 > /sys/module/sg/parameters/def_reserved_size +exec 4<> /dev/sg0 + +watchdog: BUG: soft lockup - CPU#5 stuck for 26 seconds! [bash:537] +Modules loaded: +CPU: 5 UID: 0 PID: 537 Command: bash, kernel version 6.19.0-rc3+ #134, +PREEMPT disabled +Hardware: QEMU Standard PC (i440FX + PIIX, 1996), BIOS version +1.16.1-2.fc37 dated 04/01/2014 +... +Call Trace: + + sg_build_reserve+0x5c/0xa0 + sg_add_sfp+0x168/0x270 + sg_open+0x16e/0x340 + chrdev_open+0xbe/0x230 + do_dentry_open+0x175/0x480 + vfs_open+0x34/0xf0 + do_open+0x265/0x3d0 + path_openat+0x110/0x290 + do_filp_open+0xc3/0x170 + do_sys_openat2+0x71/0xe0 + __x64_sys_openat+0x6d/0xa0 + do_syscall_64+0x62/0x310 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +The fix is to use module_param_cb to validate and reject invalid values +assigned to def_reserved_size. + +Fixes: 6460e75a104d ("[SCSI] sg: fixes for large page_size") +Signed-off-by: Yang Erkun +Reviewed-by: Bart Van Assche +Link: https://patch.msgid.link/20260127062044.3034148-3-yangerkun@huawei.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/sg.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 71d34186dec93..f38d36fbeef37 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1623,10 +1623,35 @@ sg_remove_device(struct device *cl_dev) + } + + module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); +-module_param_named(def_reserved_size, def_reserved_size, int, +- S_IRUGO | S_IWUSR); + module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); + ++static int def_reserved_size_set(const char *val, const struct kernel_param *kp) ++{ ++ int size, ret; ++ ++ if (!val) ++ return -EINVAL; ++ ++ ret = kstrtoint(val, 0, &size); ++ if (ret) ++ return ret; ++ ++ /* limit to 1 MB */ ++ if (size < 0 || size > 1048576) ++ return -ERANGE; ++ ++ def_reserved_size = size; ++ return 0; ++} ++ ++static const struct kernel_param_ops def_reserved_size_ops = { ++ .set = def_reserved_size_set, ++ .get = param_get_int, ++}; ++ ++module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size, ++ S_IRUGO | S_IWUSR); ++ + MODULE_AUTHOR("Douglas Gilbert"); + MODULE_DESCRIPTION("SCSI generic (sg) driver"); + MODULE_LICENSE("GPL"); +-- +2.53.0 + diff --git a/queue-7.0/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch b/queue-7.0/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch new file mode 100644 index 0000000000..09c99d24ff --- /dev/null +++ b/queue-7.0/scsi-target-core-fix-integer-overflow-in-unmap-bound.patch @@ -0,0 +1,42 @@ +From c60af021261dd6917191b58a2521db53092709e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 23:42:58 +0800 +Subject: scsi: target: core: Fix integer overflow in UNMAP bounds check + +From: Junrui Luo + +[ Upstream commit 2bf2d65f76697820dbc4227d13866293576dd90a ] + +sbc_execute_unmap() checks LBA + range does not exceed the device capacity, +but does not guard against LBA + range wrapping around on 64-bit overflow. + +Add an overflow check matching the pattern already used for WRITE_SAME in +the same file. + +Fixes: 86d7182985d2 ("target: Add sbc_execute_unmap() helper") +Reported-by: Yuhao Jiang +Signed-off-by: Junrui Luo +Link: https://patch.msgid.link/SYBPR01MB7881593C61AD52C69FBDB0BDAF7CA@SYBPR01MB7881.ausprd01.prod.outlook.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/target/target_core_sbc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c +index abe91dc8722e4..21f5cb86d70c0 100644 +--- a/drivers/target/target_core_sbc.c ++++ b/drivers/target/target_core_sbc.c +@@ -1187,7 +1187,8 @@ sbc_execute_unmap(struct se_cmd *cmd) + goto err; + } + +- if (lba + range > dev->transport->get_blocks(dev) + 1) { ++ if (lba + range < lba || ++ lba + range > dev->transport->get_blocks(dev) + 1) { + ret = TCM_ADDRESS_OUT_OF_RANGE; + goto err; + } +-- +2.53.0 + diff --git a/queue-7.0/scsi-ufs-rockchip-rk3576-ufshc-dt-bindings-add-new-m.patch b/queue-7.0/scsi-ufs-rockchip-rk3576-ufshc-dt-bindings-add-new-m.patch new file mode 100644 index 0000000000..f2a6e9fc02 --- /dev/null +++ b/queue-7.0/scsi-ufs-rockchip-rk3576-ufshc-dt-bindings-add-new-m.patch @@ -0,0 +1,74 @@ +From 7004136276cf06557620eebdbe85acd24cf951b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 10:21:07 +0800 +Subject: scsi: ufs: rockchip,rk3576-ufshc: dt-bindings: Add new mphy reset + item + +From: Shawn Lin + +[ Upstream commit bdce3a69c578090dd5e3c77bcdaaca10c3a41e34 ] + +Add the mphy reset property to the devicetree bindings for the Rockchip +RK3576 UFS host controller. The mphy reset signal is used to reset the +physical adapter. Resetting other components while leaving the mphy unreset +may occasionally prevent the UFS controller from successfully linking up +with the device. + +This addresses an intermittent hardware bug where the UFS link fails to +establish under specific timing conditions with certain chips. While +difficult to reproduce initially, this issue was consistently observed in +downstream testing and requires explicit mphy reset control for full +stability. + +Although this change increases the maxItems for resets and adds a new entry +(which technically alters the binding ABI), it does not break compatibility +for existing Linux systems. The driver uses +devm_reset_control_array_get_exclusive() to manage resets, allowing it to +function correctly with both older Device Trees (without the mphy entry) +and newer ones. + +Fixes: d90e92023771 ("scsi: ufs: dt-bindings: Document Rockchip UFS host controller") +Signed-off-by: Shawn Lin +Reviewed-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/1773368467-109650-1-git-send-email-shawn.lin@rock-chips.com +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + .../devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml b/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml +index c7d17cf4dc42b..e738153a309c8 100644 +--- a/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml ++++ b/Documentation/devicetree/bindings/ufs/rockchip,rk3576-ufshc.yaml +@@ -41,7 +41,7 @@ properties: + maxItems: 1 + + resets: +- maxItems: 4 ++ maxItems: 5 + + reset-names: + items: +@@ -49,6 +49,7 @@ properties: + - const: sys + - const: ufs + - const: grf ++ - const: mphy + + reset-gpios: + maxItems: 1 +@@ -98,8 +99,8 @@ examples: + interrupts = ; + power-domains = <&power RK3576_PD_USB>; + resets = <&cru SRST_A_UFS_BIU>, <&cru SRST_A_UFS_SYS>, <&cru SRST_A_UFS>, +- <&cru SRST_P_UFS_GRF>; +- reset-names = "biu", "sys", "ufs", "grf"; ++ <&cru SRST_P_UFS_GRF>, <&cru SRST_MPHY_INIT>; ++ reset-names = "biu", "sys", "ufs", "grf", "mphy"; + reset-gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_LOW>; + }; + }; +-- +2.53.0 + diff --git a/queue-7.0/sctp-disable-bh-before-calling-udp_tunnel_xmit_skb.patch b/queue-7.0/sctp-disable-bh-before-calling-udp_tunnel_xmit_skb.patch new file mode 100644 index 0000000000..91a92ceb5f --- /dev/null +++ b/queue-7.0/sctp-disable-bh-before-calling-udp_tunnel_xmit_skb.patch @@ -0,0 +1,93 @@ +From 1dfb84a69c5d2ce391ba428ead055bdbebbb310e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 14:15:27 -0400 +Subject: sctp: disable BH before calling udp_tunnel_xmit_skb() + +From: Xin Long + +[ Upstream commit 2cd7e6971fc2787408ceef17906ea152791448cf ] + +udp_tunnel_xmit_skb() / udp_tunnel6_xmit_skb() are expected to run with +BH disabled. After commit 6f1a9140ecda ("add xmit recursion limit to +tunnel xmit functions"), on the path: + + udp(6)_tunnel_xmit_skb() -> ip(6)tunnel_xmit() + +dev_xmit_recursion_inc()/dec() must stay balanced on the same CPU. + +Without local_bh_disable(), the context may move between CPUs, which can +break the inc/dec pairing. This may lead to incorrect recursion level +detection and cause packets to be dropped in ip(6)_tunnel_xmit() or +__dev_queue_xmit(). + +Fix it by disabling BH around both IPv4 and IPv6 SCTP UDP xmit paths. + +In my testing, after enabling the SCTP over UDP: + + # ip net exec ha sysctl -w net.sctp.udp_port=9899 + # ip net exec ha sysctl -w net.sctp.encap_port=9899 + # ip net exec hb sysctl -w net.sctp.udp_port=9899 + # ip net exec hb sysctl -w net.sctp.encap_port=9899 + + # ip net exec ha iperf3 -s + +- without this patch: + + # ip net exec hb iperf3 -c 192.168.0.1 --sctp + [ 5] 0.00-10.00 sec 37.2 MBytes 31.2 Mbits/sec sender + [ 5] 0.00-10.00 sec 37.1 MBytes 31.1 Mbits/sec receiver + +- with this patch: + + # ip net exec hb iperf3 -c 192.168.0.1 --sctp + [ 5] 0.00-10.00 sec 3.14 GBytes 2.69 Gbits/sec sender + [ 5] 0.00-10.00 sec 3.14 GBytes 2.69 Gbits/sec receiver + +Fixes: 6f1a9140ecda ("net: add xmit recursion limit to tunnel xmit functions") +Fixes: 046c052b475e ("sctp: enable udp tunneling socks") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/c874a8548221dcd56ff03c65ba75a74e6cf99119.1776017727.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/ipv6.c | 2 ++ + net/sctp/protocol.c | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c +index 53a5c027f8e31..cd15b695607eb 100644 +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -261,9 +261,11 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t) + skb_set_inner_ipproto(skb, IPPROTO_SCTP); + label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6); + ++ local_bh_disable(); + udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, &fl6->daddr, + tclass, ip6_dst_hoplimit(dst), label, + sctp_sk(sk)->udp_port, t->encap_port, false, 0); ++ local_bh_enable(); + return 0; + } + +diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c +index 828a59b8e7bf8..5800e7ee7ea02 100644 +--- a/net/sctp/protocol.c ++++ b/net/sctp/protocol.c +@@ -1070,10 +1070,12 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t) + skb_reset_inner_mac_header(skb); + skb_reset_inner_transport_header(skb); + skb_set_inner_ipproto(skb, IPPROTO_SCTP); ++ local_bh_disable(); + udp_tunnel_xmit_skb(dst_rtable(dst), sk, skb, fl4->saddr, + fl4->daddr, dscp, ip4_dst_hoplimit(dst), df, + sctp_sk(sk)->udp_port, t->encap_port, false, false, + 0); ++ local_bh_enable(); + return 0; + } + +-- +2.53.0 + diff --git a/queue-7.0/sctp-discard-stale-init-after-handshake-completion.patch b/queue-7.0/sctp-discard-stale-init-after-handshake-completion.patch new file mode 100644 index 0000000000..85b4c7df3e --- /dev/null +++ b/queue-7.0/sctp-discard-stale-init-after-handshake-completion.patch @@ -0,0 +1,49 @@ +From 2652b5b8d73c7593d56f87f4ac7c23d3b0962d1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 26 Apr 2026 10:46:41 -0400 +Subject: sctp: discard stale INIT after handshake completion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Xin Long + +[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ] + +After an association reaches ESTABLISHED, the peer’s init_tag is already +known from the handshake. Any subsequent INIT with the same init_tag is +not a valid restart, but a delayed or duplicate INIT. + +Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of +processing them as new association attempts. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/5788c76c1ee122a3ed00189e88dcf9df1fba226c.1777214801.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/sm_statefuns.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 7b823d7591419..8e89a870780c4 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( + /* Tag the variable length parameters. */ + chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(struct sctp_inithdr)); + ++ if (asoc->state >= SCTP_STATE_ESTABLISHED) { ++ /* Discard INIT matching peer vtag after handshake completion (stale INIT). */ ++ if (ntohl(chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) ++ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); ++ } ++ + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type, +-- +2.53.0 + diff --git a/queue-7.0/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch b/queue-7.0/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch new file mode 100644 index 0000000000..ec3bde0b5d --- /dev/null +++ b/queue-7.0/sctp-fix-missing-encap_port-propagation-for-gso-frag.patch @@ -0,0 +1,44 @@ +From 39e4eb31303897fa1dbfc097c298b989c8e6c944 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 12 Apr 2026 14:13:51 -0400 +Subject: sctp: fix missing encap_port propagation for GSO fragments + +From: Xin Long + +[ Upstream commit bf6f95ae3b8b2638c0e1d6d802d50983ce5d0f45 ] + +encap_port in SCTP_INPUT_CB(skb) is used by sctp_vtag_verify() for +SCTP-over-UDP processing. In the GSO case, it is only set on the head +skb, while fragment skbs leave it 0. + +This results in fragment skbs seeing encap_port == 0, breaking +SCTP-over-UDP connections. + +Fix it by propagating encap_port from the head skb cb when initializing +fragment skbs in sctp_inq_pop(). + +Fixes: 046c052b475e ("sctp: enable udp tunneling socks") +Signed-off-by: Xin Long +Acked-by: Marcelo Ricardo Leitner +Link: https://patch.msgid.link/ea65ed61b3598d8b4940f0170b9aa1762307e6c3.1776017631.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/inqueue.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c +index f5a7d5a387555..a024c08432471 100644 +--- a/net/sctp/inqueue.c ++++ b/net/sctp/inqueue.c +@@ -201,6 +201,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + + cb->chunk = head_cb->chunk; + cb->af = head_cb->af; ++ cb->encap_port = head_cb->encap_port; + } + } + +-- +2.53.0 + diff --git a/queue-7.0/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch b/queue-7.0/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch new file mode 100644 index 0000000000..74f6369ad2 --- /dev/null +++ b/queue-7.0/sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch @@ -0,0 +1,68 @@ +From 8bf01da7e35dff2c7a59af3c1efa4c21c017ab5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 23:19:03 -0400 +Subject: sctp: fix OOB write to userspace in sctp_getsockopt_peer_auth_chunks + +From: Michael Bommarito + +[ Upstream commit 0cf004ffb61cd32d140531c3a84afe975f9fc7ea ] + +sctp_getsockopt_peer_auth_chunks() checks that the caller's optval +buffer is large enough for the peer AUTH chunk list with + + if (len < num_chunks) + return -EINVAL; + +but then writes num_chunks bytes to p->gauth_chunks, which lives +at offset offsetof(struct sctp_authchunks, gauth_chunks) == 8 +inside optval. The check is missing the sizeof(struct +sctp_authchunks) = 8-byte header. When the caller supplies +len == num_chunks (for any num_chunks > 0) the test passes but +copy_to_user() writes sizeof(struct sctp_authchunks) = 8 bytes +past the declared buffer. + +The sibling function sctp_getsockopt_local_auth_chunks() at the +next line already has the correct check: + + if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + +Align the peer variant with its sibling. + +Reproducer confirms on v7.0-13-generic: an unprivileged userspace +caller that opens a loopback SCTP association with AUTH enabled, +queries num_chunks with a short optval, then issues the real +getsockopt with len == num_chunks and sentinel bytes painted past +the buffer observes those sentinel bytes overwritten with the +peer's AUTH chunk type. The bytes written are under the peer's +control but land in the caller's own userspace; this is not a +kernel memory corruption, but it is a kernel-side contract +violation that can silently corrupt adjacent userspace data. + +Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") +Assisted-by: Claude:claude-opus-4-6 +Signed-off-by: Michael Bommarito +Acked-by: Xin Long +Link: https://patch.msgid.link/20260416031903.1447072-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 48759da0a0261..6c58ad092e512 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -7042,7 +7042,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, + + /* See if the user provided enough room for all the data */ + num_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr); +- if (len < num_chunks) ++ if (len < sizeof(struct sctp_authchunks) + num_chunks) + return -EINVAL; + + if (copy_to_user(to, ch->chunks, num_chunks)) +-- +2.53.0 + diff --git a/queue-7.0/sctp-fix-sockets_allocated-imbalance-after-sk_clone.patch b/queue-7.0/sctp-fix-sockets_allocated-imbalance-after-sk_clone.patch new file mode 100644 index 0000000000..08ee789aa5 --- /dev/null +++ b/queue-7.0/sctp-fix-sockets_allocated-imbalance-after-sk_clone.patch @@ -0,0 +1,46 @@ +From 65889c8d7ad8bbdb123c9195c2d9f65f4145cc64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Apr 2026 17:09:40 -0400 +Subject: sctp: fix sockets_allocated imbalance after sk_clone() + +From: Xin Long + +[ Upstream commit 7c9b012d6367a335f1e91da28401a7c612305a46 ] + +sk_clone() increments sockets_allocated and sets the socket refcount to 2. +SCTP performs additional accounting in sctp_clone_sock(), so the clone-time +increment must be undone to avoid double counting. + +Note we cannot simply remove the SCTP-side increment, because the SCTP +destroy path in sctp_destroy_sock() only decrements sockets_allocated when +sp->ep is set, which may not be true for all failure paths in +sctp_clone_sock(). + +Fixes: 16942cf4d3e3 ("sctp: Use sk_clone() in sctp_accept().") +Signed-off-by: Xin Long +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/af8d66f928dec3e9fcbee8d4a85b7d5a6b86f515.1776460180.git.lucien.xin@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sctp/socket.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/sctp/socket.c b/net/sctp/socket.c +index 6c58ad092e512..aeffa10ff2d34 100644 +--- a/net/sctp/socket.c ++++ b/net/sctp/socket.c +@@ -4864,8 +4864,9 @@ static struct sock *sctp_clone_sock(struct sock *sk, + if (!newsk) + return ERR_PTR(err); + +- /* sk_clone() sets refcnt to 2 */ ++ /* sk_clone() sets refcnt to 2 and increments sockets_allocated */ + sock_put(newsk); ++ sk_sockets_allocated_dec(newsk); + + newinet = inet_sk(newsk); + newsp = sctp_sk(newsk); +-- +2.53.0 + diff --git a/queue-7.0/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch b/queue-7.0/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch new file mode 100644 index 0000000000..95b840fda2 --- /dev/null +++ b/queue-7.0/selftest-memcg-skip-memcg_sock-test-if-address-famil.patch @@ -0,0 +1,75 @@ +From bd9b236371444d4eeddf0446962183d2f90e7129 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 16:05:26 -0400 +Subject: selftest: memcg: skip memcg_sock test if address family not supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Waiman Long + +[ Upstream commit 2d028f3e4bbbfd448928a8d3d2814b0b04c214f4 ] + +The test_memcg_sock test in memcontrol.c sets up an IPv6 socket and send +data over it to consume memory and verify that memory.stat.sock and +memory.current values are close. + +On systems where IPv6 isn't enabled or not configured to support +SOCK_STREAM, the test_memcg_sock test always fails. When the socket() +call fails, there is no way we can test the memory consumption and verify +the above claim. I believe it is better to just skip the test in this +case instead of reporting a test failure hinting that there may be +something wrong with the memcg code. + +Link: https://lkml.kernel.org/r/20260311200526.885899-1-longman@redhat.com +Fixes: 5f8f019380b8 ("selftests: cgroup/memcontrol: add basic test for socket accounting") +Signed-off-by: Waiman Long +Acked-by: Michal Koutný +Acked-by: Shakeel Butt +Cc: Johannes Weiner +Cc: Michal Hocko +Cc: Michal Koutný +Cc: Mike Rapoport +Cc: Muchun Song +Cc: Roman Gushchin +Cc: Shuah Khan +Cc: Tejun Heo +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/cgroup/test_memcontrol.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c +index 2fb096a2a9f92..a25eb097b31c1 100644 +--- a/tools/testing/selftests/cgroup/test_memcontrol.c ++++ b/tools/testing/selftests/cgroup/test_memcontrol.c +@@ -1280,8 +1280,11 @@ static int tcp_server(const char *cgroup, void *arg) + saddr.sin6_port = htons(srv_args->port); + + sk = socket(AF_INET6, SOCK_STREAM, 0); +- if (sk < 0) ++ if (sk < 0) { ++ /* Pass back errno to the ctl_fd */ ++ write(ctl_fd, &errno, sizeof(errno)); + return ret; ++ } + + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) + goto cleanup; +@@ -1412,6 +1415,12 @@ static int test_memcg_sock(const char *root) + goto cleanup; + close(args.ctl[0]); + ++ /* Skip if address family not supported by protocol */ ++ if (err == EAFNOSUPPORT) { ++ ret = KSFT_SKIP; ++ goto cleanup; ++ } ++ + if (!err) + break; + if (err != EADDRINUSE) +-- +2.53.0 + diff --git a/queue-7.0/selftests-bpf-fix-__jited_unpriv-tag-name.patch b/queue-7.0/selftests-bpf-fix-__jited_unpriv-tag-name.patch new file mode 100644 index 0000000000..0bc15962af --- /dev/null +++ b/queue-7.0/selftests-bpf-fix-__jited_unpriv-tag-name.patch @@ -0,0 +1,39 @@ +From 7aa05b5f2d1c3c7c74c8624d360e6e7df4534dd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Apr 2026 00:33:44 -0700 +Subject: selftests/bpf: fix __jited_unpriv tag name + +From: Eduard Zingerman + +[ Upstream commit cdd54fe98c00549264a92613af6bb0e9a5fd0d1c ] + +__jited_unpriv was using "test_jited=" as its tag name, same as the +priv variant __jited. Fix by using "test_jited_unpriv=". + +Fixes: 7d743e4c759c ("selftests/bpf: __jited test tag to check disassembly after jit") +Acked-by: Ihor Solodrai +Reviewed-by: Puranjay Mohan +Signed-off-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260410-selftests-global-tags-ordering-v2-1-c566ec9781bf@gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/progs/bpf_misc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h +index c9bfbe1bafc12..1cd783aec11ad 100644 +--- a/tools/testing/selftests/bpf/progs/bpf_misc.h ++++ b/tools/testing/selftests/bpf/progs/bpf_misc.h +@@ -140,7 +140,7 @@ + #define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" XSTR(__COUNTER__) "=" msg))) + #define __not_msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_not_msg_unpriv=" XSTR(__COUNTER__) "=" msg))) + #define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" XSTR(__COUNTER__) "=" msg))) +-#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited=" XSTR(__COUNTER__) "=" msg))) ++#define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited_unpriv=" XSTR(__COUNTER__) "=" msg))) + #define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv"))) + #define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv"))) + #define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl))) +-- +2.53.0 + diff --git a/queue-7.0/selftests-bpf-fix-reg_bounds-to-match-new-tnum-based.patch b/queue-7.0/selftests-bpf-fix-reg_bounds-to-match-new-tnum-based.patch new file mode 100644 index 0000000000..10fda079ce --- /dev/null +++ b/queue-7.0/selftests-bpf-fix-reg_bounds-to-match-new-tnum-based.patch @@ -0,0 +1,153 @@ +From 5f4fd53cf14781c1797ebdbba9109d18e29ba5b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Apr 2026 22:40:50 +0200 +Subject: selftests/bpf: Fix reg_bounds to match new tnum-based refinement + +From: Paul Chaignon + +[ Upstream commit 2fefa9c81a25534464911447d51ddb44b04a8e5b ] + +Commit efc11a667878 ("bpf: Improve bounds when tnum has a single +possible value") improved the bounds refinement to detect when the tnum +and u64 range overlap in a single value (and the bounds can thus be set +to that value). + +Eduard then noticed that it broke the slow-mode reg_bounds selftests +because they don't have an equivalent logic and are therefore unable to +refine the bounds as much as the verifier. The following test case +illustrates this. + + ACTUAL TRUE1: scalar(u64=0xffffffff00000000,u32=0,s64=0xffffffff00000000,s32=0) + EXPECTED TRUE1: scalar(u64=[0xfffffffe00000001; 0xffffffff00000000],u32=0,s64=[0xfffffffe00000001; 0xffffffff00000000],s32=0) + [...] + #323/1007 reg_bounds_gen_consts_s64_s32/(s64)[0xfffffffe00000001; 0xffffffff00000000] (s32) S64_MIN:FAIL + +with the verifier logs: + + [...] + 19: w0 = w6 ; R0=scalar(smin=0,smax=umax=0xffffffff, + var_off=(0x0; 0xffffffff)) + R6=scalar(smin=0xfffffffe00000001,smax=0xffffffff00000000, + umin=0xfffffffe00000001,umax=0xffffffff00000000, + var_off=(0xfffffffe00000000; 0x1ffffffff)) + 20: w0 = w7 ; R0=0 R7=0x8000000000000000 + 21: if w6 == w7 goto pc+3 + [...] + from 21 to 25: [...] + 25: w0 = w6 ; R0=0 R6=0xffffffff00000000 + ; ^ + ; unexpected refined value + 26: w0 = w7 ; R0=0 R7=0x8000000000000000 + 27: exit + +When w6 == w7 is true, the verifier can deduce that the R6's tnum is +equal to (0xfffffffe00000000; 0x100000000) and then use that information +to refine the bounds: the tnum only overlap with the u64 range in +0xffffffff00000000. The reg_bounds selftest doesn't know about tnums +and therefore fails to perform the same refinement. + +This issue happens when the tnum carries information that cannot be +represented in the ranges, as otherwise the selftest could reach the +same refined value using just the ranges. The tnum thus needs to +represent non-contiguous values (ex., R6's tnum above, after the +condition). The only way this can happen in the reg_bounds selftest is +at the boundary between the 32 and 64bit ranges. We therefore only need +to handle that case. + +This patch fixes the selftest refinement logic by checking if the u32 +and u64 ranges overlap in a single value. If so, the ranges can be set +to that value. We need to handle two cases: either they overlap in +umin64... + + u64 values + matching u32 range: xxx xxx xxx xxx + |--------------------------------------| + u64 range: 0 xxxxx UMAX64 + +or in umax64: + + u64 values + matching u32 range: xxx xxx xxx xxx + |--------------------------------------| + u64 range: 0 xxxxx UMAX64 + +To detect the first case, we decrease umax64 to the maximum value that +matches the u32 range. If that happens to be umin64, then umin64 is the +only overlap. We proceed similarly for the second case, increasing +umin64 to the minimum value that matches the u32 range. + +Note this is similar to how the verifier handles the general case using +tnum, but we don't need to care about a single-value overlap in the +middle of the range. That case is not possible when comparing two +ranges. + +This patch also adds two test cases reproducing this bug as part of the +normal test runs (without SLOW_TESTS=1). + +Fixes: efc11a667878 ("bpf: Improve bounds when tnum has a single possible value") +Reported-by: Eduard Zingerman +Closes: https://lore.kernel.org/bpf/4e6dd64a162b3cab3635706ae6abfdd0be4db5db.camel@gmail.com/ +Signed-off-by: Paul Chaignon +Link: https://lore.kernel.org/r/ada9UuSQi2SE2IfB@mail.gmail.com +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/prog_tests/reg_bounds.c | 35 +++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +index cb8dd2f63296b..05fc9a7cf7c92 100644 +--- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c ++++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c +@@ -500,6 +500,39 @@ static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t, + (s64)x.a >= S32_MIN && (s64)x.b <= S32_MAX) + return range_intersection(x_t, x, y_cast); + ++ if (y_t == U32 && x_t == U64) { ++ u64 xmin_swap, xmax_swap, xmin_lower32, xmax_lower32; ++ ++ xmin_lower32 = x.a & 0xffffffff; ++ xmax_lower32 = x.b & 0xffffffff; ++ if (xmin_lower32 < y.a || xmin_lower32 > y.b) { ++ /* The 32 lower bits of the umin64 are outside the u32 ++ * range. Let's update umin64 to match the u32 range. ++ * We want to *increase* the umin64 to the *minimum* ++ * value that matches the u32 range. ++ */ ++ xmin_swap = swap_low32(x.a, y.a); ++ /* We should always only increase the minimum, so if ++ * the new value is lower than before, we need to ++ * increase the 32 upper bits by 1. ++ */ ++ if (xmin_swap < x.a) ++ xmin_swap += 0x100000000; ++ if (xmin_swap == x.b) ++ return range(x_t, x.b, x.b); ++ } else if (xmax_lower32 < y.a || xmax_lower32 > y.b) { ++ /* Same for the umax64, but we want to *decrease* ++ * umax64 to the *maximum* value that matches the u32 ++ * range. ++ */ ++ xmax_swap = swap_low32(x.b, y.b); ++ if (xmax_swap > x.b) ++ xmax_swap -= 0x100000000; ++ if (xmax_swap == x.a) ++ return range(x_t, x.a, x.a); ++ } ++ } ++ + /* the case when new range knowledge, *y*, is a 32-bit subregister + * range, while previous range knowledge, *x*, is a full register + * 64-bit range, needs special treatment to take into account upper 32 +@@ -2129,6 +2162,8 @@ static struct subtest_case crafted_cases[] = { + {U64, S64, {0x7fffffff00000001ULL, 0xffffffff00000000ULL}, {0, 0}}, + {U64, S64, {0, 0xffffffffULL}, {1, 1}}, + {U64, S64, {0, 0xffffffffULL}, {0x7fffffff, 0x7fffffff}}, ++ {U64, S32, {0xfffffffe00000001, 0xffffffff00000000}, {S64_MIN, S64_MIN}}, ++ {U64, U32, {0xfffffffe00000000, U64_MAX - 1}, {U64_MAX, U64_MAX}}, + + {U64, U32, {0, 0x100000000}, {0, 0}}, + {U64, U32, {0xfffffffe, 0x300000000}, {0x80000000, 0x80000000}}, +-- +2.53.0 + diff --git a/queue-7.0/selftests-bpf-fix-sockmap_multi_channels-reliability.patch b/queue-7.0/selftests-bpf-fix-sockmap_multi_channels-reliability.patch new file mode 100644 index 0000000000..3593359ef2 --- /dev/null +++ b/queue-7.0/selftests-bpf-fix-sockmap_multi_channels-reliability.patch @@ -0,0 +1,75 @@ +From 4683367ec0f0a9463de983259655ad5a48a608c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 15:25:44 +0800 +Subject: selftests/bpf: Fix sockmap_multi_channels reliability + +From: Jiayuan Chen + +[ Upstream commit d9d7125e445dc06c2d9bd3dbd070dcbcd41a540f ] + +Previously I added a FIONREAD test for sockmap, but it can occasionally +fail in CI [1]. + +The test sends 10 bytes in two segments (2 + 8). For UDP, FIONREAD only +reports the length of the first datagram, not the total queued data. +The original code used recv_timeout() expecting all 10 bytes, but under +high system load, the second datagram may not yet be processed by the +protocol stack, so recv would only return the first 2-byte datagram, +causing a size mismatch failure. + +Fix this by receiving exactly the expected bytes (matching FIONREAD) in +the first recv. The remaining datagram is then consumed in a second recv +block, which is only reachable for UDP since TCP's expected already +equals sizeof(buf). + +Test: +./test_progs -a sockmap_basic +410/1 sockmap_basic/sockmap create_update_free:OK +... +Summary: 1/35 PASSED, 0 SKIPPED, 0 FAILED + +[1] https://github.com/kernel-patches/bpf/actions/runs/22919385910/job/66515395423 + +Cc: Jiayuan Chen +Fixes: 17e2ce02bf56 ("selftests/bpf: Add tests for FIONREAD and copied_seq") +Signed-off-by: Jiayuan Chen +Link: https://lore.kernel.org/r/20260312072549.6766-1-jiayuan.chen@linux.dev +Signed-off-by: Alexei Starovoitov +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/prog_tests/sockmap_basic.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +index dd3c757859f6b..d2846579285f2 100644 +--- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c ++++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +@@ -1298,10 +1298,23 @@ static void test_sockmap_multi_channels(int sotype) + avail = wait_for_fionread(p1, expected, IO_TIMEOUT_SEC); + ASSERT_EQ(avail, expected, "ioctl(FIONREAD) full return"); + +- recvd = recv_timeout(p1, rcv, sizeof(rcv), MSG_DONTWAIT, 1); +- if (!ASSERT_EQ(recvd, sizeof(buf), "recv_timeout(p1)") || ++ recvd = recv_timeout(p1, rcv, expected, MSG_DONTWAIT, 1); ++ if (!ASSERT_EQ(recvd, expected, "recv_timeout(p1)") || + !ASSERT_OK(memcmp(buf, rcv, recvd), "data mismatch")) + goto end; ++ ++ /* process remaining data for udp if secondary data is available */ ++ expected = sizeof(buf) - expected; ++ if (expected) { ++ avail = wait_for_fionread(p1, expected, IO_TIMEOUT_SEC); ++ ASSERT_EQ(avail, expected, "second ioctl(FIONREAD) full return"); ++ ++ recvd = recv_timeout(p1, rcv, expected, MSG_DONTWAIT, 1); ++ if (!ASSERT_EQ(recvd, expected, "second recv_timeout(p1)") || ++ !ASSERT_OK(memcmp(buf + sizeof(buf) - expected, rcv, recvd), ++ "second data mismatch")) ++ goto end; ++ } + end: + if (c0 >= 0) + close(c0); +-- +2.53.0 + diff --git a/queue-7.0/selftests-bpf-handle-config_smc-in-bpf_smc.c.patch b/queue-7.0/selftests-bpf-handle-config_smc-in-bpf_smc.c.patch new file mode 100644 index 0000000000..f36cc1be93 --- /dev/null +++ b/queue-7.0/selftests-bpf-handle-config_smc-in-bpf_smc.c.patch @@ -0,0 +1,125 @@ +From d602cdc74a95d70031bc0ed2f0e21bc8e9ccec94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 11:13:29 +0000 +Subject: selftests/bpf: Handle !CONFIG_SMC in bpf_smc.c + +From: Alan Maguire + +[ Upstream commit e95e85b8914be1c951a1ead34b1353592719e26e ] + +Currently BPF selftests will fail to compile if CONFIG_SMC +is not set. + +Use BPF CO-RE to work around the case where CONFIG_SMC is +not set; use ___local variants of relevant structures and +utilize bpf_core_field_exists() for net->smc. + +The test continues to pass where + + CONFIG_SMC=y + CONFIG_SMC_HS_CTRL_BPF=y + +but these changes allow the selftests to build in the absence +of CONFIG_SMC=y. + +Also ensure that we get a pure skip rather than a skip+fail +by removing the SMC is unsupported part from the ASSERT_FALSE() +in get_smc_nl_family(); doing this means we get a skip without +a fail when CONFIG_SMC is not set: + +$ sudo ./test_progs -t bpf_smc +Summary: 1/0 PASSED, 1 SKIPPED, 0 FAILED + +Fixes: beb3c67297d9 ("bpf/selftests: Add selftest for bpf_smc_hs_ctrl") +Reported-by: Colm Harrington +Signed-off-by: Alan Maguire +Signed-off-by: Martin KaFai Lau +Tested-by: Kumar Kartikeya Dwivedi +Link: https://patch.msgid.link/20260310111330.601765-1-alan.maguire@oracle.com +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/prog_tests/test_bpf_smc.c | 6 ++-- + tools/testing/selftests/bpf/progs/bpf_smc.c | 28 +++++++++++++++++-- + 2 files changed, 30 insertions(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/test_bpf_smc.c b/tools/testing/selftests/bpf/prog_tests/test_bpf_smc.c +index de22734abc4d2..40d38280c091e 100644 +--- a/tools/testing/selftests/bpf/prog_tests/test_bpf_smc.c ++++ b/tools/testing/selftests/bpf/prog_tests/test_bpf_smc.c +@@ -131,8 +131,10 @@ static bool get_smc_nl_family_id(void) + goto fail; + + ret = recv(fd, &msg, sizeof(msg), 0); +- if (!ASSERT_FALSE(msg.n.nlmsg_type == NLMSG_ERROR || ret < 0 || +- !NLMSG_OK(&msg.n, ret), "nl_family response")) ++ if (msg.n.nlmsg_type == NLMSG_ERROR) ++ goto fail; ++ if (!ASSERT_FALSE(ret < 0 || !NLMSG_OK(&msg.n, ret), ++ "nl_family response")) + goto fail; + + nl = (struct nlattr *)GENLMSG_DATA(&msg); +diff --git a/tools/testing/selftests/bpf/progs/bpf_smc.c b/tools/testing/selftests/bpf/progs/bpf_smc.c +index 70d8b08f59140..6263a45bf0066 100644 +--- a/tools/testing/selftests/bpf/progs/bpf_smc.c ++++ b/tools/testing/selftests/bpf/progs/bpf_smc.c +@@ -8,6 +8,10 @@ + + char _license[] SEC("license") = "GPL"; + ++#ifndef SMC_HS_CTRL_NAME_MAX ++#define SMC_HS_CTRL_NAME_MAX 16 ++#endif ++ + enum { + BPF_SMC_LISTEN = 10, + }; +@@ -18,6 +22,20 @@ struct smc_sock___local { + bool use_fallback; + } __attribute__((preserve_access_index)); + ++struct smc_hs_ctrl___local { ++ char name[SMC_HS_CTRL_NAME_MAX]; ++ int (*syn_option)(struct tcp_sock *); ++ int (*synack_option)(const struct tcp_sock *, struct inet_request_sock *); ++} __attribute__((preserve_access_index)); ++ ++struct netns_smc___local { ++ struct smc_hs_ctrl___local *hs_ctrl; ++} __attribute__((preserve_access_index)); ++ ++struct net___local { ++ struct netns_smc___local smc; ++} __attribute__((preserve_access_index)); ++ + int smc_cnt = 0; + int fallback_cnt = 0; + +@@ -88,8 +106,14 @@ int BPF_PROG(smc_run, int family, int type, int protocol) + + task = bpf_get_current_task_btf(); + /* Prevent from affecting other tests */ +- if (!task || !task->nsproxy->net_ns->smc.hs_ctrl) ++ if (!task) { + return protocol; ++ } else { ++ struct net___local *net = (struct net___local *)task->nsproxy->net_ns; ++ ++ if (!bpf_core_field_exists(struct net___local, smc) || !net->smc.hs_ctrl) ++ return protocol; ++ } + + return IPPROTO_SMC; + } +@@ -110,7 +134,7 @@ int BPF_PROG(bpf_smc_set_tcp_option, struct tcp_sock *tp) + } + + SEC(".struct_ops") +-struct smc_hs_ctrl linkcheck = { ++struct smc_hs_ctrl___local linkcheck = { + .name = "linkcheck", + .syn_option = (void *)bpf_smc_set_tcp_option, + .synack_option = (void *)bpf_smc_set_tcp_option_cond, +-- +2.53.0 + diff --git a/queue-7.0/selftests-futex-fix-incorrect-result-reporting-of-fu.patch b/queue-7.0/selftests-futex-fix-incorrect-result-reporting-of-fu.patch new file mode 100644 index 0000000000..f66d46b317 --- /dev/null +++ b/queue-7.0/selftests-futex-fix-incorrect-result-reporting-of-fu.patch @@ -0,0 +1,120 @@ +From 0d00b8a986c7ad576eba783919d6d90fa729eafb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jan 2026 10:03:10 +0800 +Subject: selftests/futex: Fix incorrect result reporting of futex_requeue test + item + +From: Yuwen Chen + +[ Upstream commit d317e2ef9dcf673c9f37cda784284af7c6812757 ] + +When using the TEST_HARNESS_MAIN macro definition to declare the main +function, it is required to use the EXPECT*() and ASSERT*() macros in +conjunction and not ksft_test_result_*(). Otherwise, even if a test item +fails, the test will still return a success result because +ksft_test_result_*() does not affect the test harness state. + +Convert the code to use EXPECT/ASSERT() variants, which ensures that the +overall test result is fail if one of the EXPECT()s fails. + +[ tglx: Massaged change log to explain _why_ ksft_test_result*() is the wrong + choice ] + +Fixes: f341a20f6d7e ("selftests/futex: Refactor futex_requeue with kselftest_harness.h") +Signed-off-by: Yuwen Chen +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/tencent_51851B741CC4B5EC9C22AFF70BA82BB60805@qq.com +Signed-off-by: Sasha Levin +--- + .../futex/functional/futex_requeue.c | 49 +++---------------- + 1 file changed, 8 insertions(+), 41 deletions(-) + +diff --git a/tools/testing/selftests/futex/functional/futex_requeue.c b/tools/testing/selftests/futex/functional/futex_requeue.c +index 35d4be23db5da..dcf0d5f2f3122 100644 +--- a/tools/testing/selftests/futex/functional/futex_requeue.c ++++ b/tools/testing/selftests/futex/functional/futex_requeue.c +@@ -34,34 +34,18 @@ TEST(requeue_single) + volatile futex_t _f1 = 0; + volatile futex_t f2 = 0; + pthread_t waiter[10]; +- int res; + + f1 = &_f1; + + /* + * Requeue a waiter from f1 to f2, and wake f2. + */ +- if (pthread_create(&waiter[0], NULL, waiterfn, NULL)) +- ksft_exit_fail_msg("pthread_create failed\n"); ++ ASSERT_EQ(0, pthread_create(&waiter[0], NULL, waiterfn, NULL)); + + usleep(WAKE_WAIT_US); + +- ksft_print_dbg_msg("Requeuing 1 futex from f1 to f2\n"); +- res = futex_cmp_requeue(f1, 0, &f2, 0, 1, 0); +- if (res != 1) +- ksft_test_result_fail("futex_requeue simple returned: %d %s\n", +- res ? errno : res, +- res ? strerror(errno) : ""); +- +- ksft_print_dbg_msg("Waking 1 futex at f2\n"); +- res = futex_wake(&f2, 1, 0); +- if (res != 1) { +- ksft_test_result_fail("futex_requeue simple returned: %d %s\n", +- res ? errno : res, +- res ? strerror(errno) : ""); +- } else { +- ksft_test_result_pass("futex_requeue simple succeeds\n"); +- } ++ EXPECT_EQ(1, futex_cmp_requeue(f1, 0, &f2, 0, 1, 0)); ++ EXPECT_EQ(1, futex_wake(&f2, 1, 0)); + } + + TEST(requeue_multiple) +@@ -69,7 +53,7 @@ TEST(requeue_multiple) + volatile futex_t _f1 = 0; + volatile futex_t f2 = 0; + pthread_t waiter[10]; +- int res, i; ++ int i; + + f1 = &_f1; + +@@ -77,30 +61,13 @@ TEST(requeue_multiple) + * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7. + * At futex_wake, wake INT_MAX (should be exactly 7). + */ +- for (i = 0; i < 10; i++) { +- if (pthread_create(&waiter[i], NULL, waiterfn, NULL)) +- ksft_exit_fail_msg("pthread_create failed\n"); +- } ++ for (i = 0; i < 10; i++) ++ ASSERT_EQ(0, pthread_create(&waiter[i], NULL, waiterfn, NULL)); + + usleep(WAKE_WAIT_US); + +- ksft_print_dbg_msg("Waking 3 futexes at f1 and requeuing 7 futexes from f1 to f2\n"); +- res = futex_cmp_requeue(f1, 0, &f2, 3, 7, 0); +- if (res != 10) { +- ksft_test_result_fail("futex_requeue many returned: %d %s\n", +- res ? errno : res, +- res ? strerror(errno) : ""); +- } +- +- ksft_print_dbg_msg("Waking INT_MAX futexes at f2\n"); +- res = futex_wake(&f2, INT_MAX, 0); +- if (res != 7) { +- ksft_test_result_fail("futex_requeue many returned: %d %s\n", +- res ? errno : res, +- res ? strerror(errno) : ""); +- } else { +- ksft_test_result_pass("futex_requeue many succeeds\n"); +- } ++ EXPECT_EQ(10, futex_cmp_requeue(f1, 0, &f2, 3, 7, 0)); ++ EXPECT_EQ(7, futex_wake(&f2, INT_MAX, 0)); + } + + TEST_HARNESS_MAIN +-- +2.53.0 + diff --git a/queue-7.0/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch b/queue-7.0/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch new file mode 100644 index 0000000000..a19f4a3f96 --- /dev/null +++ b/queue-7.0/selftests-mm-skip-migration-tests-if-numa-is-unavail.patch @@ -0,0 +1,58 @@ +From 7371d4567beaf7a17ca7535ec91f0020e535d458 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:39:41 -0500 +Subject: selftests/mm: skip migration tests if NUMA is unavailable + +From: AnishMulay + +[ Upstream commit 54218f10dfbe88c8e41c744fd45a756cde60b8c4 ] + +Currently, the migration test asserts that numa_available() returns 0. On +systems where NUMA is not available (returning -1), such as certain ARM64 +configurations or single-node systems, this assertion fails and crashes +the test. + +Update the test to check the return value of numa_available(). If it is +less than 0, skip the test gracefully instead of failing. + +This aligns the behavior with other MM selftests (like rmap) that skip +when NUMA support is missing. + +Link: https://lkml.kernel.org/r/20260218163941.13499-1-anishm7030@gmail.com +Fixes: 0c2d08728470 ("mm: add selftests for migration entries") +Signed-off-by: AnishMulay +Reviewed-by: SeongJae Park +Reviewed-by: Dev Jain +Reviewed-by: Anshuman Khandual +Tested-by: Sayali Patil +Acked-by: David Hildenbrand (Arm) +Cc: Liam Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/mm/migration.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c +index ee24b88c2b248..60e78bbfc0e3e 100644 +--- a/tools/testing/selftests/mm/migration.c ++++ b/tools/testing/selftests/mm/migration.c +@@ -36,7 +36,8 @@ FIXTURE_SETUP(migration) + { + int n; + +- ASSERT_EQ(numa_available(), 0); ++ if (numa_available() < 0) ++ SKIP(return, "NUMA not available"); + self->nthreads = numa_num_task_cpus() - 1; + self->n1 = -1; + self->n2 = -1; +-- +2.53.0 + diff --git a/queue-7.0/selftests-namespaces-remove-unused-utils.h-include-f.patch b/queue-7.0/selftests-namespaces-remove-unused-utils.h-include-f.patch new file mode 100644 index 0000000000..d828b31cc3 --- /dev/null +++ b/queue-7.0/selftests-namespaces-remove-unused-utils.h-include-f.patch @@ -0,0 +1,45 @@ +From fa27e34da1a76e34bc57f5432c170f3e5ca2ae4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:58:58 +0200 +Subject: selftests/namespaces: remove unused utils.h include from + listns_efault_test + +From: Christian Brauner + +[ Upstream commit cad3bf1c330274d11f25f1b7afae9b9dba13fbd3 ] + +Remove the inclusion of ../filesystems/utils.h from listns_efault_test.c. +The test doesn't use any symbols from that header. Including it alongside +../pidfd/pidfd.h causes a build failure because both headers define +wait_for_pid() with conflicting linkage: + + ../filesystems/utils.h: extern int wait_for_pid(pid_t pid); + ../pidfd/pidfd.h: static inline int wait_for_pid(pid_t pid) + +All symbols the test actually uses (create_child, read_nointr, +write_nointr, sys_pidfd_send_signal) come from pidfd.h. + +Reported-by: Mark Brown +Link: https://lore.kernel.org/all/acPV19IY3Gna6Ira@sirena.org.uk +Fixes: 07d7ad46dad4 ("selftests/namespaces: test for efault") +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/namespaces/listns_efault_test.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/testing/selftests/namespaces/listns_efault_test.c b/tools/testing/selftests/namespaces/listns_efault_test.c +index c7ed4023d7a85..b570746e917c1 100644 +--- a/tools/testing/selftests/namespaces/listns_efault_test.c ++++ b/tools/testing/selftests/namespaces/listns_efault_test.c +@@ -19,7 +19,6 @@ + #include + #include + #include "../kselftest_harness.h" +-#include "../filesystems/utils.h" + #include "../pidfd/pidfd.h" + #include "wrappers.h" + +-- +2.53.0 + diff --git a/queue-7.0/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch b/queue-7.0/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch new file mode 100644 index 0000000000..1cda8feb20 --- /dev/null +++ b/queue-7.0/selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch @@ -0,0 +1,86 @@ +From 8a1c36fe1fe16548c4116ffcfcdd3fcefb42b871 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 00:45:02 +0200 +Subject: selftests: netfilter: nft_tproxy.sh: adjust to socat changes + +From: Florian Westphal + +[ Upstream commit 61119542663cac70898aef532eb57ee41ea9b477 ] + +Like e65d8b6f3092 ("selftests: drv-net: adjust to socat changes") we +need to add shut-none for this test too. + +The extra 0-packet can trigger a second (unexpected) reply from the server. + +Fixes: 7e37e0eacd22 ("selftests: netfilter: nft_tproxy.sh: add tcp tests") +Reported-by: Jakub Kicinski +Closes: https://lore.kernel.org/netdev/20260408152432.24b8ad0d@kernel.org/ +Suggested-by: Jakub Kicinski +Signed-off-by: Florian Westphal +Link: https://patch.msgid.link/20260409224506.27072-1-fw@strlen.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../selftests/net/netfilter/nft_tproxy_udp.sh | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh b/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh +index d16de13fe5a75..1dc7b04501459 100755 +--- a/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh ++++ b/tools/testing/selftests/net/netfilter/nft_tproxy_udp.sh +@@ -190,13 +190,13 @@ table inet filter { + } + EOF + +- timeout "$timeout" ip netns exec "$nsrouter" socat -u "$socat_ipproto" udp-listen:12345,fork,ip-transparent,reuseport udp:"$ns1_ip_port",ip-transparent,reuseport,bind="$ns2_ip_port" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$nsrouter" socat -u "$socat_ipproto" udp-listen:12345,fork,ip-transparent,reuseport,shut-none udp:"$ns1_ip_port",ip-transparent,reuseport,bind="$ns2_ip_port",shut-none 2>/dev/null & + local tproxy_pid=$! + +- timeout "$timeout" ip netns exec "$ns2" socat "$socat_ipproto" udp-listen:8080,fork SYSTEM:"echo PONG_NS2" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$ns2" socat "$socat_ipproto" udp-listen:8080,fork,shut-none SYSTEM:"echo PONG_NS2" 2>/dev/null & + local server2_pid=$! + +- timeout "$timeout" ip netns exec "$ns3" socat "$socat_ipproto" udp-listen:8080,fork SYSTEM:"echo PONG_NS3" 2>/dev/null & ++ timeout "$timeout" ip netns exec "$ns3" socat "$socat_ipproto" udp-listen:8080,fork,shut-none SYSTEM:"echo PONG_NS3" 2>/dev/null & + local server3_pid=$! + + busywait "$BUSYWAIT_TIMEOUT" listener_ready "$nsrouter" 12345 "-u" +@@ -205,7 +205,7 @@ EOF + + local result + # request from ns1 to ns2 (forwarded traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",sourceport=18888) ++ result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",sourceport=18888,shut-none) + if [ "$result" == "$expect_ns1_ns2" ] ;then + echo "PASS: tproxy test $testname: ns1 got reply \"$result\" connecting to ns2" + else +@@ -214,7 +214,7 @@ EOF + fi + + # request from ns1 to ns3 (forwarded traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$ns1" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port",shut-none) + if [ "$result" = "$expect_ns1_ns3" ] ;then + echo "PASS: tproxy test $testname: ns1 got reply \"$result\" connecting to ns3" + else +@@ -223,7 +223,7 @@ EOF + fi + + # request from nsrouter to ns2 (localy originated traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns2_ip_port",shut-none) + if [ "$result" == "$expect_nsrouter_ns2" ] ;then + echo "PASS: tproxy test $testname: nsrouter got reply \"$result\" connecting to ns2" + else +@@ -232,7 +232,7 @@ EOF + fi + + # request from nsrouter to ns3 (localy originated traffic) +- result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port") ++ result=$(echo I_M_PROXIED | ip netns exec "$nsrouter" socat -t 2 -T 2 STDIO udp:"$ns3_ip_port",shut-none) + if [ "$result" = "$expect_nsrouter_ns3" ] ;then + echo "PASS: tproxy test $testname: nsrouter got reply \"$result\" connecting to ns3" + else +-- +2.53.0 + diff --git a/queue-7.0/selftests-nolibc-fix-build-with-host-headers-and-lib.patch b/queue-7.0/selftests-nolibc-fix-build-with-host-headers-and-lib.patch new file mode 100644 index 0000000000..1089b2fb37 --- /dev/null +++ b/queue-7.0/selftests-nolibc-fix-build-with-host-headers-and-lib.patch @@ -0,0 +1,63 @@ +From bbe59952a1e90a276f3cce7f316967bcc81c8819 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 10:17:21 +0000 +Subject: selftests/nolibc: Fix build with host headers and libc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: David Laight + +[ Upstream commit 27532c645e61da541173d43fbe03d234f68232f9 ] + +Many systems don't have strlcpy() or strlcat() and readdir_r() is +deprecated. This makes the tests fail to build with the host headers. +Disable the 'directories' test and define strlcpy(), strlcat() and +readdir_r() using #defines so that the code compiles. + +Fixes: 6fe8360b16acb ("selftests/nolibc: also test libc-test through regular selftest framework") +Signed-off-by: David Laight +Link: https://patch.msgid.link/20260223101735.2922-4-david.laight.linux@gmail.com +Signed-off-by: Thomas Weißschuh +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/nolibc/nolibc-test.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c +index 1aca8468eac4b..801b2ad188537 100644 +--- a/tools/testing/selftests/nolibc/nolibc-test.c ++++ b/tools/testing/selftests/nolibc/nolibc-test.c +@@ -82,6 +82,20 @@ static const int is_glibc = + #endif + ; + ++#if !defined(NOLIBC) ++/* Some disabled tests may not compile. */ ++ ++/* strlcat() and strlcpy() may not be in the system headers. */ ++#undef strlcat ++#undef strlcpy ++#define strlcat(d, s, l) 0 ++#define strlcpy(d, s, l) 0 ++ ++/* readdir_r() is likely to be marked deprecated */ ++#undef readdir_r ++#define readdir_r(dir, dirent, result) ((errno = EINVAL), -1) ++#endif ++ + /* definition of a series of tests */ + struct test { + const char *name; /* test name */ +@@ -1416,7 +1430,7 @@ int run_syscall(int min, int max) + CASE_TEST(fork); EXPECT_SYSZR(1, test_fork(FORK_STANDARD)); break; + CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; + CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; +- CASE_TEST(directories); EXPECT_SYSZR(proc, test_dirent()); break; ++ CASE_TEST(directories); EXPECT_SYSZR(is_nolibc && proc, test_dirent()); break; + CASE_TEST(getrandom); EXPECT_SYSZR(1, test_getrandom()); break; + CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break; + CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break; +-- +2.53.0 + diff --git a/queue-7.0/selftests-nolibc-fix-test_file_stream-on-musl-libc.patch b/queue-7.0/selftests-nolibc-fix-test_file_stream-on-musl-libc.patch new file mode 100644 index 0000000000..74f75f797c --- /dev/null +++ b/queue-7.0/selftests-nolibc-fix-test_file_stream-on-musl-libc.patch @@ -0,0 +1,55 @@ +From 94278b3c6bf8f2a78d09fee0fdf611890425ccd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 18:00:33 +0100 +Subject: selftests/nolibc: fix test_file_stream() on musl libc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 8ba600aa577f73cc551747fdf121afc7d04afcea ] + +fwrite() modifying errno is non-standard. + +Only validate this behavior on those libc implementations which +implement it. + +Fixes: a5f00be9b3b0 ("tools/nolibc: Add a simple test for writing to a FILE and reading it back") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/nolibc/nolibc-test.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c +index 1b9d3b2e2491c..1aca8468eac4b 100644 +--- a/tools/testing/selftests/nolibc/nolibc-test.c ++++ b/tools/testing/selftests/nolibc/nolibc-test.c +@@ -74,6 +74,14 @@ static const int is_nolibc = + #endif + ; + ++static const int is_glibc = ++#ifdef __GLIBC__ ++ 1 ++#else ++ 0 ++#endif ++; ++ + /* definition of a series of tests */ + struct test { + const char *name; /* test name */ +@@ -866,7 +874,7 @@ int test_file_stream(void) + + errno = 0; + r = fwrite("foo", 1, 3, f); +- if (r != 0 || errno != EBADF) { ++ if (r != 0 || ((is_nolibc || is_glibc) && errno != EBADF)) { + fclose(f); + return -1; + } +-- +2.53.0 + diff --git a/queue-7.0/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch b/queue-7.0/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch new file mode 100644 index 0000000000..86775c7169 --- /dev/null +++ b/queue-7.0/selftests-powerpc-suppress-wmaybe-uninitialized-with.patch @@ -0,0 +1,87 @@ +From 3536a2af313e96101697d4f52148fd1f5120ab70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 22:24:26 +0530 +Subject: selftests/powerpc: Suppress -Wmaybe-uninitialized with GCC 15 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Amit Machhiwal + +[ Upstream commit 6e65886fceb23605eff952d6b1975737b4c4b154 ] + +GCC 15 reports the below false positive '-Wmaybe-uninitialized' warning +in vphn_unpack_associativity() when building the powerpc selftests. + + # make -C tools/testing/selftests TARGETS="powerpc" + [...] + CC test-vphn + In file included from test-vphn.c:3: + In function ‘vphn_unpack_associativity’, + inlined from ‘test_one’ at test-vphn.c:371:2, + inlined from ‘test_vphn’ at test-vphn.c:399:9: + test-vphn.c:10:33: error: ‘be_packed’ may be used uninitialized [-Werror=maybe-uninitialized] + 10 | #define be16_to_cpup(x) bswap_16(*x) + | ^~~~~~~~ + vphn.c:42:27: note: in expansion of macro ‘be16_to_cpup’ + 42 | u16 new = be16_to_cpup(field++); + | ^~~~~~~~~~~~ + In file included from test-vphn.c:19: + vphn.c: In function ‘test_vphn’: + vphn.c:27:16: note: ‘be_packed’ declared here + 27 | __be64 be_packed[VPHN_REGISTER_COUNT]; + | ^~~~~~~~~ + cc1: all warnings being treated as errors + +When vphn_unpack_associativity() is called from hcall_vphn() in kernel +the error is not seen while building vphn.c during kernel compilation. +This is because the top level Makefile includes '-fno-strict-aliasing' +flag always. + +The issue here is that GCC 15 emits '-Wmaybe-uninitialized' due to type +punning between __be64[] and __b16* when accessing the buffer via +be16_to_cpup(). The underlying object is fully initialized but GCC 15 +fails to track the aliasing due to the strict aliasing violation here. +Please refer [1] and [2]. This results in a false positive warning which +is promoted to an error under '-Werror'. This problem is not seen when +the compilation is performed with GCC 13 and 14. An issue [1] has also +been created on GCC bugzilla. + +The selftest compiles fine with '-fno-strict-aliasing'. Since this GCC +flag is used to compile vphn.c in kernel too, the same flag should be +used to build vphn tests when compiling vphn.c in the selftest as well. + +Fix this by including '-fno-strict-aliasing' during vphn.c compilation +in the selftest. This keeps the build working while limiting the scope +of the suppression to building vphn tests. + +[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124427 +[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99768 + +Fixes: 58dae82843f5 ("selftests/powerpc: Add test for VPHN") +Reviewed-by: Vaibhav Jain +Signed-off-by: Amit Machhiwal +Tested-by: Venkat Rao Bagalkote +Signed-off-by: Madhavan Srinivasan +Link: https://patch.msgid.link/20260313165426.43259-1-amachhiw@linux.ibm.com +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/powerpc/vphn/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/powerpc/vphn/Makefile b/tools/testing/selftests/powerpc/vphn/Makefile +index 61d519a076c6f..778fc396340db 100644 +--- a/tools/testing/selftests/powerpc/vphn/Makefile ++++ b/tools/testing/selftests/powerpc/vphn/Makefile +@@ -5,7 +5,7 @@ top_srcdir = ../../../../.. + include ../../lib.mk + include ../flags.mk + +-CFLAGS += -m64 -I$(CURDIR) ++CFLAGS += -m64 -I$(CURDIR) -fno-strict-aliasing + + $(TEST_GEN_PROGS): ../harness.c + +-- +2.53.0 + diff --git a/queue-7.0/selftests-sched_ext-add-missing-error-check-for-exit.patch b/queue-7.0/selftests-sched_ext-add-missing-error-check-for-exit.patch new file mode 100644 index 0000000000..74284c799a --- /dev/null +++ b/queue-7.0/selftests-sched_ext-add-missing-error-check-for-exit.patch @@ -0,0 +1,38 @@ +From 3b328306fd00e4c542bc00e77a4b5b76bbcdf22c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 05:17:55 +0000 +Subject: selftests/sched_ext: Add missing error check for exit__load() + +From: David Carlier + +[ Upstream commit 1d02346fec8d13b05e54296ddc6ae29b7e1067df ] + +exit__load(skel) was called without checking its return value. +Every other test in the suite wraps the load call with +SCX_FAIL_IF(). Add the missing check to be consistent with the +rest of the test suite. + +Fixes: a5db7817af78 ("sched_ext: Add selftests") +Signed-off-by: David Carlier +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/sched_ext/exit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/sched_ext/exit.c b/tools/testing/selftests/sched_ext/exit.c +index ee25824b1cbe6..b987611789d16 100644 +--- a/tools/testing/selftests/sched_ext/exit.c ++++ b/tools/testing/selftests/sched_ext/exit.c +@@ -33,7 +33,7 @@ static enum scx_test_status run(void *ctx) + skel = exit__open(); + SCX_ENUM_INIT(skel); + skel->rodata->exit_point = tc; +- exit__load(skel); ++ SCX_FAIL_IF(exit__load(skel), "Failed to load skel"); + link = bpf_map__attach_struct_ops(skel->maps.exit_ops); + if (!link) { + SCX_ERR("Failed to attach scheduler"); +-- +2.53.0 + diff --git a/queue-7.0/selftests-tracing-fix-to-check-awk-supports-non-posi.patch b/queue-7.0/selftests-tracing-fix-to-check-awk-supports-non-posi.patch new file mode 100644 index 0000000000..8e0536ec0c --- /dev/null +++ b/queue-7.0/selftests-tracing-fix-to-check-awk-supports-non-posi.patch @@ -0,0 +1,53 @@ +From 18d91c1bbd740a4dac9c240ff3171c1a6ac8d91b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 18:54:22 +0900 +Subject: selftests/tracing: Fix to check awk supports non POSIX strtonum() + +From: Masami Hiramatsu (Google) + +[ Upstream commit 3d0b8e45075d398369eb07e11f529c17a63cf5e1 ] + +Check the awk command supports non POSIX strtonum() function in +the trace_marker_raw test case. + +Fixes: 37f46601383a ("selftests/tracing: Add basic test for trace_marker_raw file") +Signed-off-by: Masami Hiramatsu (Google) +Link: https://lore.kernel.org/r/177071726229.2369897.11506524546451139051.stgit@mhiramat.tok.corp.google.com +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + .../selftests/ftrace/test.d/00basic/trace_marker_raw.tc | 2 ++ + tools/testing/selftests/ftrace/test.d/functions | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc b/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc +index a2c42e13f614b..8e905d4fe6dd2 100644 +--- a/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc ++++ b/tools/testing/selftests/ftrace/test.d/00basic/trace_marker_raw.tc +@@ -4,6 +4,8 @@ + # requires: trace_marker_raw + # flags: instance + ++check_awk_strtonum || exit_unresolved ++ + is_little_endian() { + if lscpu | grep -q 'Little Endian'; then + echo 1; +diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions +index e8e718139294d..41325f387ee7a 100644 +--- a/tools/testing/selftests/ftrace/test.d/functions ++++ b/tools/testing/selftests/ftrace/test.d/functions +@@ -173,6 +173,10 @@ check_requires() { # Check required files and tracers + done + } + ++check_awk_strtonum() { # strtonum is GNU awk extension ++ awk 'BEGIN{strtonum("0x1")}' ++} ++ + LOCALHOST=127.0.0.1 + + yield() { +-- +2.53.0 + diff --git a/queue-7.0/selftests-tracing-fix-to-make-logdir-option-work-aga.patch b/queue-7.0/selftests-tracing-fix-to-make-logdir-option-work-aga.patch new file mode 100644 index 0000000000..d66125cca7 --- /dev/null +++ b/queue-7.0/selftests-tracing-fix-to-make-logdir-option-work-aga.patch @@ -0,0 +1,73 @@ +From 9e821b7e7d781c4673b0fe797c266625b8e1cd2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Feb 2026 18:54:12 +0900 +Subject: selftests/tracing: Fix to make --logdir option work again + +From: Masami Hiramatsu (Google) + +[ Upstream commit e011853dd78f97898ae8e0b0b949603987e24c4b ] + +Since commit a0aa283c53a7 ("selftest/ftrace: Generalise ftracetest to +use with RV") moved the default LOG_DIR setting after --logdir option +parser, it overwrites the user given LOG_DIR. +This fixes it to check the --logdir option parameter when setting new +default LOG_DIR with a new TOP_DIR. + +Fixes: a0aa283c53a7 ("selftest/ftrace: Generalise ftracetest to use with RV") +Signed-off-by: Masami Hiramatsu (Google) +Tested-by: Gabriele Monaco +Link: https://lore.kernel.org/r/177071725191.2369897.14781037901532893911.stgit@mhiramat.tok.corp.google.com +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/ftrace/ftracetest | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest +index 3230bd54dba84..0a56bf209f6c0 100755 +--- a/tools/testing/selftests/ftrace/ftracetest ++++ b/tools/testing/selftests/ftrace/ftracetest +@@ -130,8 +130,7 @@ parse_opts() { # opts + shift 1 + ;; + --logdir|-l) +- LOG_DIR=$2 +- LINK_PTR= ++ USER_LOG_DIR=$2 + shift 2 + ;; + --rv) +@@ -199,6 +198,7 @@ fi + TOP_DIR=`absdir $0` + TEST_DIR=$TOP_DIR/test.d + TEST_CASES=`find_testcases $TEST_DIR` ++USER_LOG_DIR= + KEEP_LOG=0 + KTAP=0 + DEBUG=0 +@@ -210,12 +210,18 @@ RV_TEST=0 + # Parse command-line options + parse_opts $* + ++[ $DEBUG -ne 0 ] && set -x ++ ++# TOP_DIR can be changed for rv. Setting log directory. + LOG_TOP_DIR=$TOP_DIR/logs + LOG_DATE=`date +%Y%m%d-%H%M%S` +-LOG_DIR=$LOG_TOP_DIR/$LOG_DATE/ +-LINK_PTR=$LOG_TOP_DIR/latest +- +-[ $DEBUG -ne 0 ] && set -x ++if [ -n "$USER_LOG_DIR" ]; then ++ LOG_DIR=$USER_LOG_DIR ++ LINK_PTR= ++else ++ LOG_DIR=$LOG_TOP_DIR/$LOG_DATE/ ++ LINK_PTR=$LOG_TOP_DIR/latest ++fi + + if [ $RV_TEST -ne 0 ]; then + TRACING_DIR=$TRACING_DIR/rv +-- +2.53.0 + diff --git a/queue-7.0/series b/queue-7.0/series new file mode 100644 index 0000000000..b0a89a91ea --- /dev/null +++ b/queue-7.0/series @@ -0,0 +1,1037 @@ +blk-cgroup-wait-for-blkcg-cleanup-before-initializin.patch +md-suppress-spurious-superblock-update-error-message.patch +fs-omfs-reject-s_sys_blocksize-smaller-than-omfs_dir.patch +fs-mbcache-cancel-shrink-work-before-destroying-the-.patch +md-raid1-fix-the-comparing-region-of-interval-tree.patch +fs-fix-archiecture-specific-compat_ftruncate64.patch +drbd-balance-rcu-calls-in-drbd_adm_dump_devices.patch +loop-fix-partition-scan-race-between-udev-and-loop_r.patch +block-fix-zones_cond-memory-leak-on-zone-revalidatio.patch +nilfs2-reject-zero-bd_oblocknr-in-nilfs_ioctl_mark_b.patch +blk-cgroup-fix-disk-reference-leak-in-blkcg_maybe_th.patch +pstore-ram-fix-resource-leak-when-ioremap-fails.patch +erofs-verify-metadata-accesses-for-file-backed-mount.patch +erofs-include-the-trailing-nul-in-fs_ioc_getfslabel.patch +md-fix-array_state-clear-sysfs-deadlock.patch +ublk-reset-per-io-canceled-flag-on-each-fetch.patch +blk-wbt-remove-warn_on_once-from-wbt_init_enable_def.patch +erofs-handle-48-bit-blocks-uniaddr-for-extra-devices.patch +md-remove-unused-static-md_wq-workqueue.patch +md-wake-raid456-reshape-waiters-before-suspend.patch +dcache-permit-dynamic_dname-s-up-to-name_max.patch +btrfs-fix-the-inline-compressed-extent-check-in-inod.patch +btrfs-fix-deadlock-between-reflink-and-transaction-c.patch +btrfs-do-not-reject-a-valid-running-dev-replace.patch +opp-debugfs-use-performance-level-if-available-to-di.patch +opp-move-break-out-of-scoped_guard-in-dev_pm_opp_xla.patch +acpi-x86-cmos_rtc-clean-up-address-space-handler-dri.patch +acpi-x86-cmos_rtc-improve-coordination-with-acpi-tad.patch +devres-fix-missing-node-debug-info-in-devm_krealloc.patch +thermal-drivers-spear-fix-error-condition-for-readin.patch +debugfs-check-for-null-pointer-in-debugfs_create_str.patch +debugfs-fix-placement-of-export_symbol_gpl-for-debug.patch +soundwire-debugfs-initialize-firmware_file-to-empty-.patch +amd-pstate-fix-memory-leak-in-amd_pstate_epp_cpu_ini.patch +amd-pstate-update-cppc_req_cached-in-fast_switch-cas.patch +cpufreq-pass-the-policy-to-cpufreq_driver-adjust_per.patch +pci-use-generic-driver_override-infrastructure.patch +platform-wmi-use-generic-driver_override-infrastruct.patch +vdpa-use-generic-driver_override-infrastructure.patch +s390-cio-use-generic-driver_override-infrastructure.patch +s390-ap-use-generic-driver_override-infrastructure.patch +bus-fsl-mc-use-generic-driver_override-infrastructur.patch +locking-mutex-rename-mutex_init_lockep.patch +locking-mutex-fix-wrong-comment-for-config_debug_loc.patch +irqchip-irq-pic32-evic-address-warning-related-to-wr.patch +hrtimer-avoid-pointless-reprogramming-in-__hrtimer_s.patch +hrtimer-reduce-trace-noise-in-hrtimer_start.patch +locking-fix-rwlock-and-spinlock-lock-context-annotat.patch +signal-fix-the-lock_task_sighand-annotation.patch +ww-mutex-fix-the-ww_acquire_ctx-function-annotations.patch +perf-amd-ibs-account-interrupt-for-discarded-samples.patch +perf-amd-ibs-preserve-phyaddrval-bit-when-clearing-p.patch +perf-amd-ibs-avoid-calling-perf_allow_kernel-from-th.patch +x86-tdx-fix-the-typo-in-tdx_attr_migrtable.patch +rust-sync-atomic-remove-bound-t-sync-for-atomic-from.patch +sparc64-vdso-link-with-z-noexecstack.patch +scripts-gdb-timerlist-adapt-to-move-of-tk_core.patch +locking-fix-rwlock-support-in-linux-spinlock_up.h.patch +sched-topology-compute-sd_weight-considering-cpuset-.patch +x86-irqflags-preemptively-move-include-paravirt.h-di.patch +sched-topology-fix-sched_domain_span.patch +irqchip-renesas-rzg2l-fix-error-path-in-rzg2l_irqc_c.patch +asoc-intel-avs-check-maximum-valid-cpuid-leaf.patch +asoc-intel-avs-include-cpuid-header-at-file-scope.patch +x86-vdso-clean-up-remnants-of-vdso32_note_mask.patch +firmware-dmi-correct-an-indexing-error-in-dmi.h.patch +fs-resctrl-report-invalid-domain-id-when-parsing-io_.patch +sched-make-class_schedulers-avoid-pushing-current-an.patch +sched-rt-skip-group-schedulable-check-with-rt_group_.patch +wifi-ath11k-fix-memory-leaks-in-beacon-template-setu.patch +wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch +wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch +bpf-test_run-fix-the-null-pointer-dereference-issue-.patch +wifi-ath12k-account-tx-stats-only-when-ack-ba-status.patch +wifi-ath12k-fix-legacy-rate-mapping-for-monitor-mode.patch +selftests-bpf-handle-config_smc-in-bpf_smc.c.patch +wifi-ieee80211-fix-definition-of-eht-mcs-15-in-mru.patch +dpaa2-add-independent-dependencies-for-fsl_dpaa2_swi.patch +dpaa2-compile-dpaa2-even-config_fsl_dpaa2_eth-n.patch +s390-bpf-zero-extend-bpf-prog-return-values-and-kfun.patch +powerpc-pgtable-frag-fix-bad-page-state-in-pte_frag_.patch +powerpc-64s-fix-unmap-race-with-pmd-migration-entrie.patch +module-fix-freeing-of-charp-module-parameters-when-c.patch +wifi-libertas-use-usb-anchors-for-tracking-in-flight.patch +wifi-libertas-don-t-kill-urbs-in-interrupt-context.patch +bpf-do-not-allow-deleting-local-storage-in-nmi.patch +selftests-nolibc-fix-test_file_stream-on-musl-libc.patch +selftests-nolibc-fix-build-with-host-headers-and-lib.patch +tools-nolibc-printf-change-variables-c-to-ch-and-tmp.patch +tools-nolibc-printf-move-snprintf-length-check-to-ca.patch +tools-nolibc-mips-fix-clobbers-of-lo-and-hi-register.patch +tools-nolibc-avoid-wundef-warning-for-__stdc_version.patch +wifi-mt76-mt7996-fix-the-behavior-of-radar-detection.patch +wifi-mt76-mt7996-fix-iface-combination-for-different.patch +wifi-mt76-mt7996-set-mtxq-wcid-just-for-primary-link.patch +wifi-mt76-mt7996-reset-mtxq-idx-if-primary-link-is-r.patch +wifi-mt76-mt7996-switch-to-the-secondary-link-if-the.patch +wifi-mt76-mt7996-clear-wcid-pointer-in-mt7996_mac_st.patch +wifi-mt76-mt7996-reset-ampdu_state-state-in-case-of-.patch +wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch +wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch +wifi-mt76-mt7615-fix-use_cts_prot-support.patch +wifi-mt76-mt7915-fix-use_cts_prot-support.patch +wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch +wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch +wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch +wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch +wifi-mt76-fix-memory-leak-destroying-device.patch +wifi-mt76-mt7996-fix-npu-stop-procedure.patch +wifi-mt76-npu-add-missing-rx_token_size-initializati.patch +wifi-mt76-mt7925-drop-puncturing-handling-from-bss-c.patch +wifi-mt76-mt7925-fix-potential-deadlock-in-mt7925_ro.patch +wifi-mt76-fix-memory-leak-after-mt76_connac_mcu_allo.patch +wifi-mt76-mt7925-fix-tx-power-setting-failure-after-.patch +wifi-mt76-mt7921-fix-potential-deadlock-in-mt7921_ro.patch +wifi-mt76-fix-deadlock-in-remain-on-channel.patch +wifi-mt76-fix-backoff-fields-and-max_power-calculati.patch +arm64-cpufeature-make-pmuver-and-perfmon-unsigned.patch +bpf-switch-config_cfi_clang-to-config_cfi.patch +wifi-mt76-mt7996-fix-wrong-dmad-length-when-using-ma.patch +wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch +wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch +wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch +wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch +wifi-mt76-mt7996-add-missing-chanctx_sta_csa-propert.patch +wifi-mt76-mt7996-remove-link-pointer-dependency-in-m.patch +wifi-mt76-mt7996-decrement-sta-counter-removing-the-.patch +wifi-mt76-fix-multi-radio-on-channel-scanning.patch +wifi-mt76-support-upgrading-passive-scans-to-active.patch +wifi-mt76-mt7996-fix-rro-emu-configuration.patch +bpf-fix-refcount-check-in-check_struct_ops_btf_id.patch +selftests-bpf-fix-sockmap_multi_channels-reliability.patch +bpf-use-rcu-safe-iteration-in-dev_map_redirect_multi.patch +bpf-fix-variable-length-stack-write-over-spilled-poi.patch +arm_mpam-ensure-in_reset_state-is-false-after-applyi.patch +arm_mpam-reset-when-feature-configuration-bit-unset.patch +bpf-arc_jit-fix-missing-newline-in-pr_err-messages.patch +wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch +drivers-vfio_pci_core-change-pxd_order-check-from-sw.patch +r8152-fix-incorrect-register-write-to-usb_uphy_xtal.patch +selftests-tracing-fix-to-make-logdir-option-work-aga.patch +selftests-tracing-fix-to-check-awk-supports-non-posi.patch +powerpc-crash-fix-backup-region-offset-update-to-elf.patch +powerpc-crash-update-backup-region-offset-in-elfcore.patch +selftests-powerpc-suppress-wmaybe-uninitialized-with.patch +bpf-fix-abuse-of-kprobe_write_ctx-via-freplace.patch +macvlan-annotate-data-races-around-port-bc_queue_len.patch +bpf-use-copy_map_value_locked-in-alloc_htab_elem-for.patch +bpf-fix-end-of-list-detection-in-cgroup_storage_get_.patch +bpf-fix-stale-offload-prog-pointer-after-constant-bl.patch +net-ethernet-ti-cpsw-rename-soft_reset-function.patch +net-ethernet-ti-cpsw-fix-linking-built-in-code-to-mo.patch +wifi-brcmfmac-fix-error-pointer-dereference.patch +wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch +bpf-drop-task_to_inode-and-inet_conn_established-fro.patch +bpf-reject-negative-co-re-accessor-indices-in-bpf_co.patch +bpf-prefer-vmlinux-symbols-over-module-symbols-for-u.patch +wifi-ath10k-fix-station-lookup-failure-during-discon.patch +bpf-fix-linked-reg-delta-tracking-when-src_reg-dst_r.patch +net-dropreason-add-skb_drop_reason_recursion_limit.patch +net-plumb-drop-reasons-to-__dev_queue_xmit.patch +net-qdisc_pkt_len_segs_init-cleanup.patch +net-pull-headers-in-qdisc_pkt_len_segs_init.patch +arm64-entry-don-t-preempt-with-serror-or-debug-maske.patch +acpi-agdi-fix-missing-newline-in-error-message.patch +arm64-kexec-remove-duplicate-allocation-for-trans_pg.patch +bpf-propagate-error-from-visit_tailcall_insn.patch +bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch +bpf-remove-static-qualifier-from-local-subprog-point.patch +mptcp-better-mptcp-level-rtt-estimator.patch +bpf-fix-use-after-free-in-offloaded-map-prog-info-fi.patch +macsec-support-vlan-filtering-lower-devices.patch +net-bcmgenet-fix-off-by-one-in-bcmgenet_put_txcb.patch +net-bcmgenet-fix-leaking-free_bds.patch +net-bcmgenet-fix-racing-timeout-handler.patch +net-airoha-add-dma_rmb-and-read_once-in-airoha_qdma_.patch +eth-fbnic-use-wake-instead-of-start.patch +netfilter-xt_socket-enable-defrag-after-all-other-ch.patch +netfilter-nft_fwd_netdev-check-ttl-hl-before-forward.patch +bpf-fix-mm-lifecycle-in-open-coded-task_vma-iterator.patch +bpf-switch-task_vma-iterator-from-mmap_lock-to-per-v.patch +bpf-return-vma-snapshot-from-task_vma-iterator.patch +bpf-fix-rcu-stall-in-bpf_fd_array_map_clear.patch +net-hamradio-6pack-fix-uninit-value-in-sixpack_recei.patch +net-airoha-fix-fe_pse_buf_set-configuration-if-ppe2-.patch +bpf-enforce-regsafe-base-id-consistency-for-bpf_add_.patch +selftests-bpf-fix-__jited_unpriv-tag-name.patch +net-sched-cls_fw-fix-null-dereference-of-old-filters.patch +net-sched-act_ct-only-release-rcu-read-lock-after-ct.patch +selftests-netfilter-nft_tproxy.sh-adjust-to-socat-ch.patch +net-mana-use-pci_name-for-debugfs-directory-naming.patch +net-mana-move-current_speed-debugfs-file-to-mana_ini.patch +net-airoha-add-missing-rx_cpu_idx-configuration-in-a.patch +net_sched-fix-skb-memory-leak-in-deferred-qdisc-drop.patch +bpf-fix-same-register-dst-src-oob-read-and-pointer-l.patch +bpf-allow-instructions-with-arena-source-and-non-are.patch +selftests-bpf-fix-reg_bounds-to-match-new-tnum-based.patch +net-rds-optimize-rds_ib_laddr_check.patch +net-rds-restrict-use-of-rds-ib-to-the-initial-networ.patch +bpf-fix-oob-in-pcpu_init_value.patch +ppp-require-cap_net_admin-in-target-netns-for-unatta.patch +net-ipa-fix-programming-of-qtime_timestamp_cfg.patch +net-ipa-fix-decoding-ev_per_ee-for-ipa-v5.0.patch +dt-bindings-net-dsa-nxp-sja1105-make-spi-cpol-option.patch +net-phy-fix-a-return-path-in-get_phy_c45_ids.patch +net-mlx5e-fix-features-not-applied-during-netdev-reg.patch +net-mlx5e-ipsec-fix-aso-poll-timeout-with-read_poll_.patch +net-ethernet-mtk_eth_soc-initialize-ppe-per-tag-laye.patch +net-fix-skb_ext_total_length-build_bug_on-with-confi.patch +bpf-reject-short-ipv4-ipv6-inputs-in-bpf_prog_test_r.patch +bluetooth-l2cap-fix-printing-wrong-information-if-sd.patch +bluetooth-hci_ldisc-clear-hci_uart_proto_init-on-err.patch +bluetooth-fix-locking-in-hci_conn_request_evt-with-h.patch +bluetooth-l2cap-add-missing-chan-lock-in-l2cap_ecred.patch +bluetooth-sco-check-for-codecs-num_codecs-1-before-a.patch +net-phy-qcom-at803x-use-the-correct-bit-to-disable-e.patch +udp-force-compute_score-to-always-inline.patch +tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch +sctp-fix-missing-encap_port-propagation-for-gso-frag.patch +sctp-disable-bh-before-calling-udp_tunnel_xmit_skb.patch +selftests-namespaces-remove-unused-utils.h-include-f.patch +net-bpf-fix-null-ptr-deref-in-xdp_master_redirect-fo.patch +net-airoha-fix-vip-configuration-for-an7583-soc.patch +net-airoha-add-missing-ppe-configurations-in-airoha_.patch +drm-panel-ilitek-ili9882t-select-drm_display_dsc_hel.patch +selftests-futex-fix-incorrect-result-reporting-of-fu.patch +drm-komeda-fix-integer-overflow-in-afbc-framebuffer-.patch +dma-fence-fix-sparse-warnings-due-__rcu-annotations.patch +drm-gpusvm-fix-unbalanced-unlock-in-drm_gpusvm_scan_.patch +drm-virtio-allow-importing-prime-buffers-when-3d-is-.patch +asoc-soc-compress-use-function-to-clear-symmetric-pa.patch +pci-tph-allow-tph-enable-for-rcieps.patch +pci-endpoint-pci-epf-vntb-fix-msi-doorbell-irq-unwin.patch +pci-endpoint-pci-epf-test-don-t-free-doorbell-irq-un.patch +pci-endpoint-pci-ep-msi-fix-error-unwind-and-prevent.patch +drm-sun4i-mixer-fix-layer-init-code.patch +drm-sun4i-backend-fix-error-pointer-dereference.patch +drm-xe-consolidate-workaround-entries-for-wa_1401987.patch +drm-xe-consolidate-workaround-entries-for-wa_1401938.patch +drm-xe-xe2_hpg-drop-invalid-workaround-wa_1501059973.patch +gpu-nova-core-gsp-use-empty-slices-instead-of-0.0-ra.patch +gpu-nova-core-gsp-fix-improper-handling-of-empty-slo.patch +drm-amdkfd-removed-commented-line-for-mqd-queue-prio.patch +pci-imx6-fix-device-node-reference-leak-in-imx_pcie_.patch +asoc-sdca-add-default-value-for-mipi-sdca-function-r.patch +asoc-sdca-update-counting-of-su-ge-dapm-routes.patch +crypto-inside-secure-eip93-fix-register-definition.patch +asoc-sti-return-errors-from-regmap_field_alloc.patch +asoc-sti-use-managed-regmap_field-allocations.patch +dm-cache-fix-null-deref-with-concurrent-writes-in-pa.patch +dm-cache-fix-write-path-cache-coherency-in-passthrou.patch +dm-cache-fix-write-hang-in-passthrough-mode.patch +dm-cache-policy-smq-fix-missing-locks-in-invalidatin.patch +dm-cache-fix-concurrent-write-failure-in-passthrough.patch +dm-cache-fix-dirty-mapping-checking-in-passthrough-m.patch +dm-mpath-don-t-stop-probing-paths-at-presuspend.patch +drm-amd-ras-fix-type-size-of-remainder-argument.patch +dt-bindings-mmc-dwcmshc-sdhci-fix-resets-array-valid.patch +drm-amdgpu-gfx12.1-scratch-memory-limit-up-to-57-bit.patch +platform-chrome-chromeos_tbmc-drop-wakeup-source-on-.patch +gpu-nova-core-use-checked-arithmetic-in-fwsec-firmwa.patch +gpu-nova-core-create-falcon-firmware-dma-objects-laz.patch +gpu-nova-core-falcon-rename-load-parameters-to-refle.patch +gpu-nova-core-firmware-fix-and-explain-v2-header-off.patch +pci-dwc-ep-fix-msi-x-table-size-configuration-in-dw_.patch +pci-dwc-ep-mirror-the-max-link-width-and-speed-field.patch +pci-dwc-perform-cleanup-in-the-error-path-of-dw_pcie.patch +dm-cache-metadata-fix-memory-leak-on-metadata-abort-.patch +dm-log-fix-out-of-bounds-write-due-to-region_count-o.patch +iopoll-fix-function-parameter-names-in-read_poll_tim.patch +drm-bridge-cadence-cdns-mhdp8546-core-set-the-mhdp-c.patch +drm-bridge-cadence-cdns-mhdp8546-core-add-mode_valid.patch +drm-bridge-cadence-cdns-mhdp8546-core-handle-hdcp-st.patch +spi-nxp-xspi-use-reinit_completion-for-repeated-oper.patch +spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch +spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch +spi-axiado-remove-redundant-pm_runtime_mark_last_bus.patch +media-i2c-og01a1b-fix-v4l2-subdevice-data-initializa.patch +media-synopsys-video_dw_mipi_csi2rx-should-depend-on.patch +drm-amd-pm-fix-xgmi-max-speed-reporting.patch +spi-atcspi200-fix-mutex-initialization-order.patch +selftests-sched_ext-add-missing-error-check-for-exit.patch +drm-v3d-handle-error-from-drm_sched_entity_init.patch +drm-sun4i-fix-resource-leaks.patch +crypto-inside-secure-eip93-register-hash-before-auth.patch +pci-rzg3s-host-fix-reset-handling-in-probe-error-pat.patch +pci-rzg3s-host-reorder-reset-assertion-during-suspen.patch +dt-bindings-pci-renesas-r9a08g045s33-pcie-fix-naming.patch +iommu-riscv-add-iotinval-after-updating-ddt-pdt-entr.patch +iommu-riscv-skip-irq-count-check-when-using-msi-inte.patch +iommu-riscv-add-missing-generic_msi_irq.patch +iommu-riscv-stop-polling-when-cqcsr-reports-an-error.patch +drm-amdkfd-update-queue-properties-for-metadata-ring.patch +drm-amd-ras-fix-null-deref-in-ras_core_ras_interrupt.patch +drm-amdgpu-add-default-case-in-dvi-mode-validation.patch +regulator-dt-bindings-fp9931-make-vin-supply-propert.patch +regulator-fp9931-fix-handling-of-mandatory-vin-suppl.patch +drm-amd-ras-fix-null-deref-in-ras_core_get_utc_secon.patch +drm-amdgpu-drop-redundant-queue-null-check-in-hang-d.patch +drm-amdgpu-remove-dead-negative-offset-check-in-amdg.patch +dm-init-ensure-device-probing-has-finished-in-dm-mod.patch +fbdev-matroxfb-mark-variable-with-__maybe_unused-to-.patch +crypto-simd-reject-compat-registrations-without-__-p.patch +crypto-tegra-disable-softirqs-before-finalizing-requ.patch +crypto-atmel-aes-guard-unregister-on-error-in-atmel_.patch +padata-remove-cpu-online-check-from-cpu-add-and-remo.patch +padata-put-cpu-offline-callback-in-online-section-to.patch +pci-dwc-rcar-gen4-change-epc-bar-alignment-to-4k-as-.patch +accel-amdxdna-fix-missing-newline-in-pr_err-message.patch +drm-amd-ras-remove-redundant-null-check-in-pending-b.patch +drm-amdgpu-gfx10-look-at-the-right-prop-for-gfx-queu.patch +drm-amdgpu-gfx11-look-at-the-right-prop-for-gfx-queu.patch +spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch +pci-sky1-fix-missing-cleanup-of-ecam-config-on-probe.patch +drm-imagination-switch-reset_reason-fields-from-enum.patch +iommu-tegra241-cmdqv-set-supports_cmd-op-in-tegra241.patch +iommu-tegra241-cmdqv-update-uapi-to-clarify-hyp_own-.patch +drm-msm-add-missing-module_device_id-definitions.patch +drm-msm-dpu-fix-mismatch-between-power-and-frequency.patch +drm-msm-dsi-add-the-missing-parameter-description.patch +drm-msm-dpu-don-t-try-using-2-lms-if-only-one-dsc-is.patch +drm-msm-dsi-fix-bits_per_pclk.patch +drm-msm-dsi-fix-hdisplay-calculation-for-cmd-mode-pa.patch +drm-msm-dsi-rename-msm8998-dsi-version-from-v2_2_0-t.patch +asoc-rockchip-rockchip_sai-set-slot-width-for-non-td.patch +tools-sched_ext-scx_pair-fix-pair_ctx-indexing-for-c.patch +drm-panel-sharp-ls043t1le01-make-use-of-prepare_prev.patch +drm-panel-simple-correct-g190ean01-prepare-timing.patch +pci-qcom-advertise-hotplug-slot-capability-with-no-c.patch +pci-prevent-shrinking-bridge-window-from-its-require.patch +pci-fix-premature-removal-from-realloc_head-list-dur.patch +crypto-hisilicon-sec2-prevent-req-used-after-free-fo.patch +pci-fix-alignment-calculation-for-resource-size-larg.patch +iommu-riscv-fix-signedness-bug.patch +alsa-core-validate-compress-device-numbers-without-d.patch +drm-amd-display-avoid-null-dereference-in-dc_dmub_sr.patch +asoc-amd-acp-update-dmic_num-logic-for-acp-pdm-dmic.patch +drm-amd-pm-ci-use-highest-mclk-on-ci-when-mclk-dpm-i.patch +drm-amd-pm-ci-disable-mclk-dpm-on-problematic-ci-asi.patch +drm-amd-pm-smu7-fix-smu7-voltage-dependency-on-displ.patch +drm-amd-pm-ci-fix-powertune-defaults-for-hawaii-0x67.patch +drm-amd-pm-ci-clear-enabledforactivity-field-for-mem.patch +drm-amd-pm-ci-fill-dw8-fields-from-smc.patch +drm-amd-pm-smu7-add-sclk-cap-for-quirky-hawaii-board.patch +drm-amdgpu-uvd4.2-don-t-initialize-uvd-4.2-when-dpm-.patch +pci-dpc-log-aer-error-info-for-dpc-edr-uncorrectable.patch +hwmon-aspeed-g6-pwm-tach-remove-redundant-driver-rem.patch +alsa-hda-realtek-fix-bad-indentation-for-alc269.patch +alsa-hda-realtek-fix-code-style-error-else-should-fo.patch +asoc-sof-intel-hda-place-check-before-dereference.patch +drm-msm-vma-avoid-lock-in-vm_bind-fence-signaling-pa.patch +drm-msm-a6xx-add-missing-aperture_lock-init.patch +drm-msm-reject-fb-creation-from-_no_share-objs.patch +drm-msm-fix-vm_bind-unmap-locking.patch +drm-msm-a6xx-fix-hlsq-register-dumping.patch +drm-msm-shrinker-fix-can_block-logic.patch +drm-msm-a6xx-fix-dumping-a650-debugbus-blocks.patch +drm-msm-a6xx-use-barriers-while-updating-hfi-q-heade.patch +drm-msm-a8xx-fix-the-ticks-used-in-submit-traces.patch +drm-msm-a6xx-switch-to-preemption-safe-ao-counter.patch +drm-msm-a6xx-correct-oob-usage.patch +drm-msm-adreno-implement-gx_is_on-for-a8x.patch +drm-msm-a6xx-fix-gpu-init-from-secure-world.patch +alsa-hda-cmedia-remove-duplicate-pin-configuration-p.patch +pmdomain-ti-omap_prm-fix-a-reference-leak-on-device-.patch +pmdomain-imx-scu-pd-fix-device_node-reference-leak-d.patch +pm-domains-de-constify-fields-in-struct-dev_pm_domai.patch +drm-msm-dpu-drop-intf_0-on-msm8953.patch +asoc-fsl_micfil-add-access-property-for-vad-detected.patch +asoc-fsl_micfil-fix-event-generation-in-hwvad_put_en.patch +asoc-fsl_micfil-fix-event-generation-in-hwvad_put_in.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_range.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_put_d.patch +asoc-fsl_micfil-fix-event-generation-in-micfil_quali.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_arc_m.patch +asoc-fsl_xcvr-fix-event-generation-in-fsl_xcvr_mode_.patch +asoc-fsl_easrc-check-the-variable-range-in-fsl_easrc.patch +asoc-fsl_easrc-fix-value-type-in-fsl_easrc_iec958_ge.patch +asoc-fsl_easrc-change-the-type-for-iec958-channel-st.patch +iommu-amd-fix-clone_alias-to-use-the-original-device.patch +iommu-riscv-remove-overflows-on-the-invalidation-pat.patch +asoc-qcom-qdsp6-topology-check-widget-type-before-ac.patch +pci-dwc-fix-type-mismatch-for-kstrtou32_from_user-re.patch +crypto-qat-disable-4xxx-ae-cluster-when-lead-engine-.patch +crypto-qat-disable-420xx-ae-cluster-when-lead-engine.patch +crypto-qat-fix-compression-instance-leak.patch +crypto-qat-fix-type-mismatch-in-ras-sysfs-show-funct.patch +crypto-iaa-fix-per-node-cpu-counter-reset-in-rebalan.patch +crypto-qat-use-swab32-macro.patch +alsa-hda-notify-iec958-default-pcm-switch-state-chan.patch +asoc-rsnd-fix-potential-out-of-bounds-access-of-comp.patch +pci-enable-atomicops-only-if-root-port-supports-them.patch +pci-imx6-keep-root-port-msi-capability-with-imsi-rx-.patch +pci-aspeed-fix-irq-domain-leak-on-platform_get_irq-f.patch +dt-bindings-pci-imx6q-pcie-fix-maxitems-of-clocks-an.patch +pci-mediatek-gen3-prevent-leaking-irq-domains-when-i.patch +gpu-nova-core-bitfield-fix-broken-default-implementa.patch +selftests-mm-skip-migration-tests-if-numa-is-unavail.patch +kho-fix-kasan-support-for-restored-vmalloc-regions.patch +documentation-fix-a-hugetlbfs-reservation-statement.patch +docs-admin-guide-mm-damn-lru_sort-fix-intervals-auto.patch +docs-mm-damon-index-fix-typo-autoamted-automated.patch +zram-do-not-permit-params-change-after-init.patch +selftest-memcg-skip-memcg_sock-test-if-address-famil.patch +gpu-nova-core-remove-redundant-.as_ref-for-dev_-prin.patch +gpu-nova-core-fix-missing-colon-in-sec2-boot-debug-m.patch +alsa-scarlett2-add-missing-sentinel-initializer-fiel.patch +asoc-qcom-audioreach-explicitly-enable-speaker-prote.patch +asoc-sof-compress-return-the-configured-codec-from-g.patch +pci-npem-set-led_hw_pluggable-for-hotplug-capable-po.patch +tools-sched_ext-fix-off-by-one-in-scx_sdt-payload-ze.patch +asoc-soc-component-re-add-pcm_new-pcm_free.patch +asoc-amd-name-back-to-pcm_new-pcm_free.patch +asoc-amd-ps-fix-the-pcm-device-numbering-for-acp-pdm.patch +alsa-usb-audio-qcom-fix-incorrect-type-in-enable_aud.patch +pci-tegra194-fix-polling-delay-for-l2-state.patch +pci-tegra194-increase-ltssm-poll-time-on-surprise-li.patch +pci-tegra194-disable-ltssm-after-transition-to-detec.patch +pci-tegra194-don-t-force-the-device-into-the-d0-stat.patch +pci-tegra194-disable-perst-irq-only-in-endpoint-mode.patch +pci-tegra194-use-devm_gpiod_get_optional-to-parse-nv.patch +pci-tegra194-disable-direct-speed-change-for-endpoin.patch +pci-tegra194-set-ltr-message-request-before-pcie-lin.patch +pci-tegra194-allow-system-suspend-when-the-endpoint-.patch +pci-tegra194-free-up-endpoint-resources-during-remov.patch +pci-tegra194-use-dwc-ip-core-version.patch +pci-dwc-apply-ecrc-workaround-to-designware-5.00a-as.patch +pci-tegra194-disable-l1.2-capability-of-tegra234-ep.patch +pci-tegra194-fix-cbb-timeout-caused-by-dbi-access-be.patch +drm-fb-helper-fix-a-locking-bug-in-an-error-path.patch +pci-cadence-add-flags-for-disabling-aspm-capability-.patch +pci-sg2042-avoid-l0s-and-l1-on-sophgo-2042-pcie-root.patch +asoc-sdca-fix-cleanup-inversion-in-class-driver.patch +spi-rzv2h-rspi-fix-invalid-spr-0-brdv-0-clock-config.patch +spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch +alsa-sc6000-keep-the-programmed-board-state-in-card-.patch +dm-cache-fix-missing-return-in-invalidate_committed-.patch +sched_ext-track-p-s-rq-lock-across-set_cpus_allowed_.patch +sched_ext-fix-ops.cgroup_move-invocation-kf_mask-and.patch +spi-cadence-qspi-revert-the-filtering-of-certain-opc.patch +crypto-jitterentropy-replace-long-held-spinlock-with.patch +alsa-usb-audio-exclude-scarlett-18i20-1st-gen-from-s.patch +alsa-hda-realtek-fixed-speaker-no-sound-update.patch +gfs2-call-unlock_new_inode-before-d_instantiate.patch +fanotify-avoid-silence-premature-lsm-capability-chec.patch +fanotify-call-fanotify_events_supported-before-path_.patch +fuse-fix-premature-writetrhough-request-for-large-fo.patch +fuse-fix-uninit-value-in-fuse_dentry_revalidate.patch +ktest-avoid-undef-warning-when-warnings_file-is-unse.patch +ktest-honor-empty-per-test-option-overrides.patch +ktest-run-post_ktest-hooks-on-failure-and-cancellati.patch +vfio-selftests-fix-crash-in-vfio_dma_mapping_mmio_te.patch +rtla-simplify-code-by-caching-string-lengths.patch +rtla-use-str_has_prefix-for-prefix-checks.patch +rtla-trace-fix-write-loop-in-trace_event_save_hist.patch +rtla-utils-fix-resource-leak-in-set_comm_sched_attr.patch +tools-rtla-generate-optstring-from-long-options.patch +rtla-fix-segfault-on-multiple-sigints.patch +vfio-selftests-build-tests-on-aarch64.patch +gfs2-less-aggressive-low-memory-log-flushing.patch +quota-fix-race-of-dquot_scan_active-with-quota-deact.patch +vfio-unhide-vdev-debug_root.patch +gfs2-add-some-missing-log-locking.patch +gfs2-prevent-null-pointer-dereference-during-unmount.patch +efi-capsule-loader-fix-incorrect-sizeof-in-phys-arra.patch +ksmbd-fix-use-after-free-from-async-crypto-on-qualco.patch +arm64-dts-mediatek-mt8365-describe-infracfg-nao-as-a.patch +arm-dts-mediatek-mt7623-fix-efuse-fallback-compatibl.patch +memory-tegra124-emc-fix-dll_change-check.patch +memory-tegra30-emc-fix-dll_change-check.patch +arm64-dts-imx8-apalis-fix-leds-name-collision.patch +arm64-dts-imx91-11x11-evk-change-usdhc-tuning-step-f.patch +riscv-dts-spacemit-pcie-fix-missing-power-regulator.patch +arm64-dts-mediatek-mt7988a-bpi-r4pro-fix-model-strin.patch +arm64-dts-rockchip-make-jaguar-pcie-refclk-pin-use-p.patch +arm64-dts-imx8mp-evk-enable-pull-select-bit-for-pcie.patch +iommufd-vfio-compatibility-extension-check-for-noiom.patch +arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-board-id.patch +arm64-dts-qcom-sm6125-xiaomi-ginkgo-correct-reserved.patch +arm64-dts-qcom-sm6125-xiaomi-ginkgo-remove-extcon.patch +arm64-dts-qcom-sm6125-xiaomi-ginkgo-fix-reserved-gpi.patch +arm64-dts-qcom-qcs6490-rubikpi3-use-lt9611-dsi-port-.patch +arm64-dts-qcom-talos-add-missing-clock-names-to-gcc.patch +arm64-dts-ti-k3-am62l-include-wkup_uart0-in-wakeup-p.patch +arm64-dts-mediatek-mt6795-fix-gpio-ranges-pin-count.patch +arm64-dts-mediatek-mt7981b-fix-gpio-ranges-pin-count.patch +arm64-dts-mediatek-mt7986a-fix-gpio-ranges-pin-count.patch +iommufd-selftest-fix-page-leaks-in-mock_viommu_-init.patch +arm64-dts-imx8mp-kontron-fix-touch-reset-configurati.patch +arm64-dts-imx8mp-kontron-drop-vmmc-supply-to-fix-sd-.patch +arm64-dts-imx8mp-hummingboard-pulse-cubox-m-fix-vmmc.patch +arm64-dts-imx8mp-hummingboard-pulse-fix-mini-hdmi-ds.patch +arm-dts-bcm5301x-drop-extra-nand-controller-compatib.patch +arm64-dts-qcom-msm8953-xiaomi-vince-correct-wled-ovp.patch +arm64-dts-qcom-msm8937-xiaomi-land-correct-wled-ovp-.patch +arm64-dts-qcom-msm8953-xiaomi-daisy-fix-backlight.patch +firmware-qcom_scm-don-t-opencode-kmemdup.patch +soc-qcom-ubwc-disable-bank-swizzling-for-glymur-plat.patch +arm64-dts-rockchip-fix-bluetooth-stability-on-lckfb-.patch +revert-arm64-dts-rockchip-add-spdif-audio-to-beelink.patch +arm64-dts-rockchip-correct-fan-supply-for-gameforce-.patch +arm64-dts-rockchip-correct-joystick-axes-on-gameforc.patch +soc-qcom-ocmem-make-the-core-clock-optional.patch +soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch +soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch +riscv-dts-spacemit-drop-incorrect-pinctrl-for-combo-.patch +arm64-dts-rockchip-fix-rk3562-evb2-model-name.patch +arm64-dts-rockchip-add-mphy-reset-to-ufshc-node.patch +bus-rifsc-fix-rif-configuration-check-for-peripheral.patch +arm64-dts-qcom-arduino-imola-fix-faulty-spidev-node.patch +arm64-dts-qcom-add-missing-denali-oled.dtb-to-makefi.patch +arm64-dts-qcom-hamoa-correct-iris-corners-for-the-mx.patch +arm64-dts-qcom-lemans-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-monaco-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-sm8550-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-sm8650-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-sm8750-correct-iris-corners-for-the-m.patch +arm64-dts-qcom-kaanapali-fix-gic_its-range-length.patch +arm64-dts-qcom-milos-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8450-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8550-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8650-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8750-fix-gic_its-range-length.patch +arm64-dts-qcom-sm8550-fix-xo-clock-supply-of-platfor.patch +arm64-dts-qcom-sm8650-fix-xo-clock-supply-of-sd-host.patch +arm64-dts-qcom-hamoa-fix-xo-clock-supply-of-platform.patch +arm64-dts-qcom-sm8450-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm8550-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm8650-enable-uhs-i-sdr50-and-sdr104-.patch +arm64-dts-qcom-sm7225-fairphone-fp4-fix-conflicting-.patch +arm64-dts-qcom-sdm845-xiaomi-beryllium-mark-l1a-regu.patch +arm64-dts-qcom-msm8917-xiaomi-riva-fix-board-id-for-.patch +arm64-dts-ti-k3-am62p5-sk-disable-mmc1-internal-pull.patch +arm64-dts-ti-k3-am62l3-evm-disable-mmc1-internal-pul.patch +arm64-dts-ti-k3-am62-lp-sk-enable-internal-pulls-for.patch +arm64-dts-ti-k3-am62-verdin-fix-spi_1-gpio-cs-pinctr.patch +arm64-dts-freescale-imx8mp-tqma8mpql-mba8mp-ras314-f.patch +arm64-dts-imx91-remove-tmu-s-superfluous-sensor-id.patch +arm64-dts-imx8mp-kontron-fix-boot-order-for-pmic-and.patch +arm64-dts-imx8dxl-evk-use-audio-graph-card2-for-wm89.patch +arm64-dts-imx8mp-evk-specify-adv7535-register-addres.patch +arm64-dts-lx2160a-change-i2c0-iic1-pinmux-mask-to-on.patch +arm64-dts-lx2160a-remove-duplicate-pinmux-nodes.patch +arm64-dts-lx2160a-rename-pinmux-nodes-for-readabilit.patch +arm64-dts-lx2160a-add-sda-gpio-references-for-i2c-bu.patch +arm64-dts-lx2160a-change-zeros-to-hexadecimal-in-pin.patch +arm64-dts-lx2160a-complete-pinmux-for-rcwsr12-config.patch +arm64-dts-imx8qm-mek-switch-type-c-connector-power-r.patch +arm64-dts-imx8qxp-mek-switch-type-c-connector-power-.patch +soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch +soc-tegra-cbb-fix-incorrect-array_size-in-fabric-loo.patch +soc-tegra-cbb-fix-cross-fabric-target-timeout-lookup.patch +arm64-tegra-fix-rtc-aliases.patch +soc-tegra-pmc-add-kerneldoc-for-reboot-notifier.patch +soc-tegra-pmc-correct-function-names-in-kerneldoc.patch +soc-tegra-pmc-add-kerneldoc-for-wake-up-variables.patch +unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch +ocfs2-dlm-validate-qr_numregions-in-dlm_match_region.patch +ocfs2-dlm-fix-off-by-one-in-dlm_match_regions-region.patch +soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch +soc-qcom-aoss-compare-against-normalized-cooling-sta.patch +arm64-dts-qcom-milos-add-missing-cx-power-domain-to-.patch +arm64-dts-qcom-sm8250-add-missing-cpu7-3.09ghz-opp.patch +arm-omap1-fix-debug_ll-and-earlyprintk-on-omap16xx.patch +arm64-xor-fix-conflicting-attributes-for-xor_block_t.patch +lib-kunit_iov_iter-fix-memory-leaks.patch +arm-dts-imx27-eukrea-replace-interrupts-with-interru.patch +firmware-arm_ffa-use-the-correct-buffer-size-during-.patch +fwctl-fix-class-init-ordering-to-avoid-null-pointer-.patch +ocfs2-fix-listxattr-handling-when-the-buffer-is-full.patch +ocfs2-validate-bg_bits-during-freefrag-scan.patch +ocfs2-validate-group-add-input-before-caching.patch +dmaengine-dw-axi-dmac-fix-alignment-should-match-ope.patch +dmaengine-dw-axi-dmac-remove-unnecessary-return-stat.patch +phy-apple-apple-use-local-variable-for-ioremap-retur.patch +soundwire-bus-demote-unattached-state-warnings-to-de.patch +soundwire-intel-test-bus.bpt_stream-before-assigning.patch +dmaengine-mxs-dma-fix-missing-return-value-from-of_d.patch +soundwire-cadence-clear-message-complete-before-sign.patch +tracing-move-__printf-attribute-on-__ftrace_vbprintk.patch +tracing-rebuild-full_name-on-each-hist_field_name-ca.patch +hte-tegra194-remove-kconfig-dependency-on-tegra194-s.patch +remoteproc-xlnx-fix-sram-property-parsing.patch +stop_machine-fix-the-documentation-for-a-null-cpus-a.patch +remoteproc-imx_rproc-check-return-value-of-regmap_at.patch +ima-check-return-value-of-crypto_shash_final-in-boot.patch +hid-asus-make-asus_resume-adhere-to-linux-kernel-cod.patch +hid-asus-do-not-abort-probe-when-not-necessary.patch +workqueue-devres-add-device-managed-allocate-workque.patch +power-supply-max77705-drop-duplicated-irq-error-mess.patch +power-supply-max77705-free-allocated-workqueue-and-f.patch +mtd-physmap_of_gemini-fix-disabled-pinctrl-state-che.patch +ima_fs-correctly-create-securityfs-files-for-unsuppo.patch +dt-bindings-interrupt-controller-arm-gic-v3-fix-eppi.patch +mtd-spi-nor-core-correct-the-op.dummy.nbytes-when-ch.patch +mtd-spi-nor-update-spi_nor_fixups-post_sfdp-document.patch +mtd-spi-nor-micron-st-add-snor_cmd_pp_8_8_8_dtr-sfdp.patch +mtd-spi-nor-swp-check-sr_tb-flag-when-getting-tb_mas.patch +mtd-parsers-ofpart-call-of_node_put-only-in-ofpart_f.patch +mtd-parsers-ofpart-call-of_node_get-for-dedicated-su.patch +cxl-pci-check-memdev-driver-binding-status-in-cxl_re.patch +mtd-rawnand-sunxi-fix-sunxi_nfc_hw_ecc_read_extra_oo.patch +mtd-spinand-winbond-clarify-when-to-enable-the-hs-bi.patch +hid-usbhid-fix-deadlock-in-hid_post_reset.patch +ext4-fix-miss-unlock-sb-s_umount-in-extents_kunit_in.patch +ext4-call-deactivate_super-in-extents_kunit_exit.patch +ext4-fix-the-error-handling-process-in-extents_kunit.patch +ext4-fix-possible-null-ptr-deref-in-extents_kunit_ex.patch +ext4-fix-possible-null-ptr-deref-in-mbt_kunit_exit.patch +bpf-arm64-reject-out-of-range-b.cond-targets.patch +bpf-arm64-fix-off-by-one-in-check_imm-signed-range-c.patch +bpf-arm64-remove-redundant-bpf_flush_icache-after-pa.patch +bpf-riscv-remove-redundant-bpf_flush_icache-after-pa.patch +bpf-sockmap-fix-af_unix-iter-deadlock.patch +bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-upda.patch +bpf-sockmap-take-state-lock-for-af_unix-iter.patch +bpf-fix-precedence-bug-in-convert_bpf_ld_abs-alignme.patch +bpf-fix-null-deref-in-map_kptr_match_type-for-scalar.patch +bpf-allow-utf-8-literals-in-bpf_bprintf_prepare.patch +libbpf-prevent-double-close-and-leak-of-btf-objects.patch +bpf-validate-node_id-in-arena_alloc_pages.patch +bpf-arm32-reject-bpf-to-bpf-calls-and-callbacks-in-t.patch +perf-trace-fix-is_err-vs-null-check-bug.patch +dt-bindings-pinctrl-marvell-armada3710-xb-pinctrl-ad.patch +pinctrl-pinctrl-pic32-fix-resource-leak.patch +perf-trace-avoid-an-err_ptr-in-syscall_stats.patch +pinctrl-microchip-mssio-fix-missing-return-in-probe.patch +perf-test-type-profiling-remote-typedef-on-struct.patch +pinctrl-cy8c95x0-remove-duplicate-error-message.patch +pinctrl-cy8c95x0-unify-messages-with-help-of-dev_err.patch +pinctrl-cy8c95x0-avoid-returning-positive-values-to-.patch +perf-branch-avoid-incrementing-null.patch +perf-tools-cs-etm-fix-print-issue-for-coresight-debu.patch +pinctrl-pinconf-generic-fully-validate-pinmux-proper.patch +pinctrl-realtek-fix-function-signature-for-config-ar.patch +pinctrl-abx500-fix-type-of-argument-variable.patch +pinctrl-renesas-rzg2l-fix-save-restore-of-iolh-ien-p.patch +tools-build-correct-link-flags-for-libopenssl.patch +perf-lock-fix-option-value-type-in-parse_max_stack.patch +perf-stat-fix-opt-value-type-for-parse_cache_level.patch +memblock-reserve_mem-fix-end-caclulation-in-reserve_.patch +perf-stat-fix-crash-on-arm64.patch +perf-tools-fix-module-symbol-resolution-for-non-zero.patch +perf-test-fix-ratio_to_prev-event-parsing-test.patch +perf-test-skip-perf-data-type-profiling-tests-for-s3.patch +perf-expr-return-einval-for-syntax-error-in-expr__fi.patch +perf-metrics-make-common-stalled-metrics-conditional.patch +ipmi-ssif_bmc-fix-missing-check-for-copy_to_user-par.patch +ipmi-ssif_bmc-fix-message-desynchronization-after-tr.patch +ipmi-ssif_bmc-change-log-level-to-dbg-in-irq-callbac.patch +perf-cgroup-update-metric-leader-in-evlist__expand_c.patch +pinctrl-sophgo-pinctrl-sg2042-fix-wrong-module-descr.patch +pinctrl-sophgo-pinctrl-sg2044-fix-wrong-module-descr.patch +perf-maps-fix-fixup_overlap_and_insert-that-can-brea.patch +perf-maps-fix-copy_from-that-can-break-sorted-by-nam.patch +perf-util-kill-die-prototype-dead-for-a-long-time.patch +i3c-master-dw-i3c-fix-missing-reset-assertion-in-rem.patch +i3c-master-dw-i3c-balance-pm-runtime-usage-count-on-.patch +i3c-master-renesas-fix-memory-leak-in-renesas_i3c_i3.patch +i3c-dw-fix-memory-leak-in-dw_i3c_master_i3c_xfers.patch +i3c-master-fix-error-codes-at-send_ccc_cmd.patch +i3c-master-adi-fix-error-propagation-for-cccs.patch +i3c-mipi-i3c-hci-fix-ibi-payload-length-calculation-.patch +fs-ntfs3-prevent-uninitialized-lcn-caused-by-zero-le.patch +backlight-sky81452-backlight-check-return-value-of-d.patch +platform-surface-surfacepro3_button-drop-wakeup-sour.patch +leds-lgm-sso-remove-duplicate-assignments-for-priv-m.patch +usb-typec-fix-error-pointer-dereference.patch +tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch +usb-typec-ps883x-fix-oops-at-unbind.patch +platform-x86-panasonic-laptop-fix-optd-notifier-regi.patch +platform-x86-barco-p50-gpio-normalize-return-value-o.patch +fs-ntfs3-fix-missing-run-load-for-vcn0-in-attr_data_.patch +mfd-mc13xxx-core-fix-memory-leak-in-mc13xxx_add_subd.patch +nfs-blocklayout-fix-compilation-error-make-w-1-in-bl.patch +sunrpc-kill-rpc_ifdebug.patch +sunrpc-fix-compilation-error-make-w-1-when-dprintk-i.patch +nfsd-fix-nfs4_file-access-extra-count-in-nfsd4_add_r.patch +nfsd-use-dynamic-allocation-for-oversized-nfsv4.0-re.patch +rdma-umem-use-consistent-dma-attributes-when-unmappi.patch +greybus-raw-fix-use-after-free-on-cdev-close.patch +greybus-raw-fix-use-after-free-if-write-is-called-af.patch +platform-x86-asus-wmi-adjust-screenpad-power-brightn.patch +platform-x86-asus-wmi-fix-screenpad-brightness-range.patch +tty-serial-ip22zilog-fix-section-mispatch-warning.patch +fs-ntfs3-terminate-the-cached-volume-label-after-utf.patch +platform-x86-hp-wmi-fix-ignored-return-values-in-fan.patch +platform-x86-hp-wmi-avoid-cancel_delayed_work_sync-f.patch +platform-x86-hp-wmi-use-mod_delayed_work-to-reset-ke.patch +platform-x86-hp-wmi-fix-u8-underflow-in-gpu_delta-ca.patch +platform-x86-hp-wmi-add-locking-for-concurrent-hwmon.patch +platform-x86-dell_rbu-avoid-uninit-value-usage-in-pa.patch +platform-x86-dell-wmi-sysman-bound-enumeration-strin.patch +rdma-core-prefer-nla_nul_string.patch +platform-x86-hp-wmi-fix-fan-table-parsing.patch +dt-bindings-clock-qcom-add-gcc-video-axi-reset-clock.patch +clk-qcom-gcc-glymur-add-video-axi-clock-resets-for-g.patch +clk-qcom-dispcc-glymur-use-rcg2-ops-for-dptx1-aux-cl.patch +clk-qcom-dispcc-sm8450-use-rcg2-ops-for-dptx1-aux-cl.patch +clk-renesas-r9a09g057-fix-ordering-of-module-clocks-.patch +clk-renesas-r9a09g056-fix-ordering-of-module-clocks-.patch +clk-sunxi-ng-sun55i-a523-r-add-missing-r-spi-module-.patch +scsi-sg-fix-sysctl-sg-big-buff-register-during-sg_in.patch +scsi-sg-resolve-soft-lockup-issue-when-opening-dev-s.patch +clk-qcom-dispcc-sc8280xp-remove-clk_set_rate_parent-.patch +clk-qcom-dispcc-glymur-fix-dsi-byte-clock-rate-setti.patch +clk-qcom-dispcc-kaanapali-fix-dsi-byte-clock-rate-se.patch +clk-qcom-dispcc-milos-fix-dsi-byte-clock-rate-settin.patch +clk-qcom-dispcc-sm4450-fix-dsi-byte-clock-rate-setti.patch +clk-qcom-dispcc-01-sa8775p-fix-dsi-byte-clock-rate-s.patch +clk-renesas-r9a09g057-remove-entries-for-wdt-0-2-3.patch +scsi-qla2xxx-add-support-to-report-mpi-fw-state.patch +scsi-target-core-fix-integer-overflow-in-unmap-bound.patch +scsi-ufs-rockchip-rk3576-ufshc-dt-bindings-add-new-m.patch +dt-bindings-clock-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-add-missing-gdscs.patch +clk-qcom-gcc-sc8180x-use-retention-for-usb-power-dom.patch +clk-qcom-gcc-sc8180x-use-retention-for-pcie-power-do.patch +clk-qcom-dispcc-sm8250-use-shared-ops-on-the-mdss-vs.patch +clk-qcom-dispcc-sm8250-enable-parents-for-pixel-cloc.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-pll6.patch +clk-imx-imx6q-fix-device-node-reference-leak-in-of_a.patch +clk-imx8mq-correct-the-csi-phy-sels.patch +um-fix-potential-race-condition-in-tlb-sync.patch +x86-um-fix-vdso-installation.patch +clk-qoriq-avoid-format-string-warning.patch +clk-xgene-fix-mapping-leak-in-xgene_pllclk_init.patch +clk-spacemit-ccu_mix-fix-inverted-condition-in-ccu_m.patch +f2fs-avoid-reading-already-updated-pages-during-gc.patch +printk_ringbuffer-fix-get_data-size-sanity-check.patch +clk-qcom-gdsc-fix-error-path-on-registration-of-mult.patch +lib-hexdump-print_hex_dump_bytes-calls-print_hex_dum.patch +f2fs-fix-data-loss-caused-by-incorrect-use-of-nat_en.patch +f2fs-fix-to-preserve-previous-reserve_-blocks-node-v.patch +scsi-hpsa-enlarge-controller-and-irq-name-buffers.patch +drm-amd-display-fix-parameter-mismatch-in-panel-self.patch +clk-qcom-gcc-x1e80100-keep-gcc-usb-qtb-clock-always-.patch +clk-visconti-pll-initialize-clk_init_data-to-zero.patch +f2fs-allow-empty-mount-string-for-opt_usr-grp-projjq.patch +f2fs-protect-extension_list-reading-with-sb_lock-in-.patch +drm-i915-wm-verify-the-correct-plane-ddb-entry.patch +virt-arm-cca-guest-fix-error-check-for-rsi_incomplet.patch +crypto-eip93-fix-hmac-setkey-algo-selection.patch +crypto-sa2ul-fix-aead-fallback-algorithm-names.patch +crypto-ccp-copy-iv-using-skcipher-ivsize.patch +sh-include-linux-io.h-in-dac.h.patch +erofs-fix-offset-truncation-when-shifting-pgoff-on-3.patch +erofs-unify-lcn-as-u64-for-32-bit-platforms.patch +tools-hv-fix-cross-compilation.patch +drivers-hv-vmbus-fix-hyperv_cpuhp_online-variable-sh.patch +arm64-dts-imx8mp-debix-model-a-correct-pad-settings-.patch +arm64-dts-imx8mp-debix-som-a-correct-pad-settings-fo.patch +arm64-dts-imx8mp-navqp-correct-pad-settings-for-pmic.patch +arm64-dts-imx8mp-icore-mx8mp-correct-pad-settings-fo.patch +arm64-dts-imx8mp-edm-g-correct-pad-settings-for-pmic.patch +arm64-dts-imx8mp-aristainetos3a-som-v1-correct-pad-s.patch +arm64-dts-imx8mp-nitrogen-som-correct-pad-settings-f.patch +arm64-dts-imx8mp-sr-som-correct-pad-settings-for-pmi.patch +arm64-dts-imx8mp-ultra-mach-sbc-correct-pad-settings.patch +arm64-dts-imx8mp-dhcom-som-correct-pad-settings-for-.patch +arm64-dts-imx8mp-data-modul-edm-sbc-correct-pad-sett.patch +pcmcia-fix-garbled-log-messages-for-kern_cont.patch +reset-amlogic-t7-fix-null-reset-ops.patch +arm64-dts-imx8mm-emtop-som-correct-pad-settings-for-.patch +arm64-dts-imx8mn-tqma8mqnl-correct-pad-settings-for-.patch +arm64-dts-imx8mm-tqma8mqml-correct-pad-settings-for-.patch +arm64-dts-marvell-armada-37xx-use-usb2-phy-in-usb3-c.patch +pwm-stm32-fix-rounding-issue-for-requests-with-inver.patch +net-sched-act_mirred-fix-wrong-device-for-mac_header.patch +macvlan-fix-macvlan_get_size-not-reserving-space-for.patch +net-sched-sch_cake-fix-nat-destination-port-not-bein.patch +nexthop-fix-ipv6-route-referencing-ipv4-nexthop.patch +net-airoha-wait-for-npu-ppe-configuration-to-complet.patch +net-sched-taprio-fix-use-after-free-in-advance_sched.patch +net-dsa-remove-redundant-netdev_lock_ops-from-condui.patch +net-enetc-correct-the-command-bd-ring-consumer-index.patch +net-enetc-fix-ntmp-dma-use-after-free-issue.patch +ksmbd-fix-use-after-free-in-smb2_open-during-durable.patch +tcp-move-tp-chrono_type-next-tp-chrono_stat.patch +tcp-inline-tcp_chrono_start.patch +tcp-annotate-data-races-in-tcp_get_info_chrono_stats.patch +tcp-add-data-race-annotations-around-tp-data_segs_ou.patch +tcp-add-data-races-annotations-around-tp-reordering-.patch +tcp-annotate-data-races-around-tp-snd_ssthresh.patch +tcp-annotate-data-races-around-tp-delivered-and-tp-d.patch +tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch +tcp-annotate-data-races-around-tp-bytes_sent.patch +tcp-annotate-data-races-around-tp-bytes_retrans.patch +tcp-annotate-data-races-around-tp-dsack_dups.patch +tcp-annotate-data-races-around-tp-reord_seen.patch +tcp-annotate-data-races-around-tp-srtt_us.patch +tcp-annotate-data-races-around-tp-timeout_rehash.patch +tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch +tcp-annotate-data-races-around-tp-plb_rehash.patch +ice-fix-adjust-timer-programming-for-e830-devices.patch +ice-update-pcs-latency-settings-for-e825-10g-25gb-mo.patch +ice-fix-double-free-of-tx_buf-skb.patch +ice-fix-phy-config-on-media-change-with-link-down-on.patch +ice-fix-ice_aq_link_speed_m-for-200g.patch +ice-fix-race-condition-in-tx-timestamp-ring-cleanup.patch +ice-fix-potential-null-pointer-deref-in-error-path-o.patch +i40e-don-t-advertise-iff_supp_nofcs.patch +iavf-fix-wrong-vlan-mask-for-legacy-rx-descriptors-l.patch +e1000e-unroll-ptp-in-probe-error-handling.patch +ipv6-fix-possible-uaf-in-icmpv6_rcv.patch +af_unix-drop-all-scm-attributes-for-sockmap.patch +sctp-fix-oob-write-to-userspace-in-sctp_getsockopt_p.patch +pppoe-drop-pfc-frames.patch +net-mlx5-fix-hca-caps-leak-on-notifier-init-failure.patch +openvswitch-cap-upcall-pid-array-size-and-pre-size-v.patch +net-airoha-fix-possible-tx-queue-stall-in-airoha_qdm.patch +netfilter-nft_osf-restrict-it-to-ipv4.patch +netfilter-nfnetlink_osf-fix-divide-by-zero-in-osf_ws.patch +netfilter-conntrack-remove-sprintf-usage.patch +netfilter-xtables-restrict-several-matches-to-inet-f.patch +netfilter-nat-use-kfree_rcu-to-release-ops.patch +ipvs-fix-mtu-check-for-gso-packets-in-tunnel-mode.patch +netfilter-nfnetlink_osf-fix-out-of-bounds-read-on-op.patch +netfilter-nfnetlink_osf-fix-potential-null-dereferen.patch +slip-reject-vj-receive-packets-on-instances-with-no-.patch +slip-bound-decode-reads-against-the-compressed-packe.patch +net-sched-sch_dualpi2-drain-both-c-queue-and-l-queue.patch +arm64-dts-amlogic-meson-axg-add-missing-cache-inform.patch +arm64-dts-meson-gxl-p230-fix-ethernet-phy-interrupt-.patch +vfio-pci-clean-up-dmabufs-before-disabling-function.patch +pwm-atmel-tcb-cache-clock-rates-and-mark-chip-as-ato.patch +ksmbd-destroy-tree_conn_ida-in-ksmbd_session_destroy.patch +ksmbd-destroy-async_ida-in-ksmbd_conn_free.patch +ksmbd-fix-durable-fd-leak-on-clientguid-mismatch-in-.patch +ksmbd-scope-conn-binding-slowpath-to-bound-sessions-.patch +net-validate-skb-napi_id-in-rx-tracepoints.patch +bnge-fix-initial-hwrm-sequence.patch +bnge-remove-unsupported-backing-store-type.patch +sctp-fix-sockets_allocated-imbalance-after-sk_clone.patch +net-rds-zero-per-item-info-buffer-before-handing-it-.patch +ice-fix-timestamp-interrupt-configuration-for-e825c.patch +ice-perform-phy-soft-reset-for-e825c-ports-at-initia.patch +ice-fix-ready-bitmap-check-for-non-e822-devices.patch +ice-fix-ice_ptp_read_tx_hwtstamp_status_eth56g.patch +net_sched-sch_hhf-annotate-data-races-in-hhf_dump_st.patch +net-sched-sch_pie-annotate-data-races-in-pie_dump_st.patch +net-sched-sch_fq_codel-remove-data-races-from-fq_cod.patch +net-sched-sch_red-annotate-data-races-in-red_dump_st.patch +net-sched-sch_sfb-annotate-data-races-in-sfb_dump_st.patch +net-airoha-move-ndesc-initialization-at-end-of-airoh.patch +net-airoha-add-missing-bits-in-airoha_qdma_cleanup_t.patch +net-dsa-realtek-rtl8365mb-fix-mode-mask-calculation.patch +net-airoha-move-ndesc-initialization-at-end-of-airoh.patch-16210 +net-airoha-rework-the-code-flow-in-airoha_remove-and.patch +net-airoha-add-size-check-for-tx-napis-in-airoha_qdm.patch +net-mana-init-link_change_work-before-potential-erro.patch +net-mana-init-gf_stats_work-before-potential-error-p.patch +net-mana-guard-mana_remove-against-double-invocation.patch +net-mana-don-t-overwrite-port-probe-error-with-add_a.patch +net-mana-fix-eq-leak-in-mana_remove-on-null-port.patch +vsock-virtio-fix-msg_zerocopy-pinned-pages-accountin.patch +virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch +nfp-fix-swapped-arguments-in-nfp_encode_basic_qdr-ca.patch +tcp-send-a-challenge-ack-on-seg.ack-snd.nxt.patch +tipc-fix-double-free-in-tipc_buf_append.patch +vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch +nstree-fix-func.-parameter-kernel-doc-warnings.patch +eventpoll-use-hlist_is_singular_node-in-__ep_remove.patch +eventpoll-split-__ep_remove.patch +eventpoll-kill-__ep_remove.patch +eventpoll-drop-vestigial-__-prefix-from-ep_remove_-f.patch +eventpoll-move-epi_fget-up.patch +eventpoll-fix-ep_remove-struct-eventpoll-struct-file.patch +fs-adfs-validate-nzones-in-adfs_validate_bblk.patch +rtc-abx80x-disable-alarm-feature-if-no-interrupt-att.patch +kbuild-builddeb-avoid-recompiles-for-non-cross-compi.patch +tools-power-turbostat-fix-amd-rapl-regression-on-big.patch +fbdev-offb-fix-pci-device-reference-leak-on-probe-fa.patch +tools-power-turbostat-fix-unrecognized-option-p.patch +tools-power-turbostat-fix-cpu-set-0-regression-on-ht.patch +tools-power-turbostat-fix-cpu-set-1-regression-on-ht.patch +kbuild-never-respect-config_werror-w-e-to-fixdep.patch +mailbox-mtk-vcp-mailbox-fix-the-return-value-in-mtk_.patch +mailbox-mtk-cmdq-fix-curr-and-end-addr-for-task-inse.patch +mailbox-mailbox-test-free-channels-on-probe-error.patch +sched-psi-fix-race-between-file-release-and-pressure.patch +cgroup-rdma-fix-integer-overflow-in-rdmacg_try_charg.patch +cgroup-cpuset-record-dl-bw-alloc-cpu-for-attach-roll.patch +mailbox-add-sanity-check-for-channel-array.patch +mailbox-mailbox-test-handle-channel-errors-consisten.patch +mailbox-mailbox-test-don-t-free-the-reused-channel.patch +mailbox-mailbox-test-initialize-struct-earlier.patch +mailbox-mailbox-test-make-data_ready-a-per-instance-.patch +fsnotify-fix-inode-reference-leak-in-fsnotify_recalc.patch +btrfs-fix-bytes_may_use-leak-in-move_existing_remap.patch +btrfs-fix-bytes_may_use-leak-in-do_remap_reloc_trans.patch +btrfs-don-t-clobber-errors-in-add_remap_tree_entries.patch +btrfs-fix-double-decrement-of-bytes_may_use-in-submi.patch +tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch +nvmet-tcp-propagate-nvmet_tcp_build_pdu_iovec-errors.patch +netfilter-arp_tables-fix-ieee1394-arp-payload-parsin.patch +netfilter-nf_tables-use-list_del_rcu-for-netlink-hoo.patch +rculist-add-list_splice_rcu-for-private-lists.patch +netfilter-nf_tables-join-hook-list-via-splice_list_r.patch +netfilter-nf_tables-add-hook-transactions-for-device.patch +nvme-pci-fix-missed-admin-queue-sq-doorbell-write.patch +drm-amdgpu-avoid-double-drm_exec_fini-in-userq-valid.patch +drm-amdgpu-gmc-fix-amdgpu_gart_placement_low-to-not-.patch +drm-amd-pm-fix-missing-fine-grained-dpm-table-flag-o.patch +drm-amdgpu-fix-amdgpu_info_read_mmr_reg.patch +drm-amdgpu-uvd3.1-don-t-validate-the-firmware-when-a.patch +drm-amdgpu-gfx6-support-harvested-si-chips-with-disa.patch +drm-amdgpu-only-send-rma-cper-when-threshold-is-exce.patch +netfilter-xt_policy-fix-strict-mode-inbound-policy-m.patch +netfilter-nf_conntrack_sip-don-t-use-simple_strtoul.patch +spi-rzv2h-rspi-fix-silent-failure-in-clock-setup-err.patch +asoc-amd-acp-add-dmi-quirk-for-valve-steam-deck-oled.patch +asoc-sof-intel-add-an-empty-adr_link.patch +spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch +asoc-tas2764-mark-die-temp-register-as-volatile.patch +asoc-tas2770-fix-order-of-operations-for-temperature.patch +drm-sysfb-ofdrm-fix-pci-device-reference-leaks.patch +drm-color-mgmt-typo-s-r332-rgb332.patch +arm64-scs-fix-potential-sign-extension-issue-of-adva.patch +spi-spi-mem-add-a-packed-command-operation.patch +mtd-spinand-add-support-for-packed-read-data-odtr-co.patch +mtd-spinand-winbond-set-the-packed-page-read-flag-to.patch +mtd-spinand-winbond-fix-odtr-write-vcr-on-w35nxxjw.patch +acpica-provide-defines-for-einjv2-error-types.patch +acpi-apei-einj-fix-einjv2-memory-error-injection.patch +cdrom-scsi-sr-propagate-read-only-status-to-block-la.patch +spi-axiado-replace-usleep_range-with-udelay-in-irq-p.patch +netdevsim-zero-initialize-struct-iphdr-in-dummy-sk_b.patch +net-sched-netem-fix-probability-gaps-in-4-state-loss.patch +net-sched-netem-fix-queue-limit-check-to-include-reo.patch +net-sched-netem-only-reseed-prng-when-seed-is-explic.patch +net-sched-netem-validate-slot-configuration.patch +net-sched-netem-fix-slot-delay-calculation-overflow.patch +net-sched-netem-check-for-negative-latency-and-jitte.patch +net-airoha-fix-bql-imbalance-in-tx-path.patch +net-airoha-stop-net_device-tx-queue-before-updating-.patch +net-airoha-fix-typo-in-function-name.patch +net-airoha-do-not-wake-all-netdev-tx-queues-in-airoh.patch +net-airoha-do-not-read-uninitialized-fragment-addres.patch +net-sched-sch_choke-annotate-data-races-in-choke_dum.patch +net-sched-sch_fq_pie-annotate-data-races-in-fq_pie_d.patch +vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch +net-usb-rtl8150-fix-use-after-free-in-rtl8150_start_.patch +net-usb-rtl8150-free-skb-on-usb_submit_urb-failure-i.patch +spi-amlogic-spisg-initialize-completion-before-reque.patch +nfc-trf7970a-ignore-antenna-noise-when-checking-for-.patch +net-sched-taprio-fix-null-pointer-dereference-in-cla.patch +net-phonet-do-not-bug_on-in-pn_socket_autobind-on-fa.patch +neigh-let-neigh_xmit-take-skb-ownership.patch +tcp-make-probe0-timer-handle-expired-user-timeout.patch +netpoll-fix-ipv6-local-address-corruption.patch +alsa-usb-audio-fix-potential-leak-of-pd-at-parsing-u.patch +sched-fair-fix-wakeup_preempt_fair-vs-delayed-dequeu.patch +sched-fair-clear-rel_deadline-when-initializing-fork.patch +net-mctp-i2c-check-length-before-marking-flow-active.patch +md-raid1-raid10-don-t-fail-devices-for-invalid-io-er.patch +md-add-fallback-to-correct-bitmap_ops-on-version-mis.patch +md-factor-bitmap-creation-away-from-sysfs-handling.patch +md-md-bitmap-split-bitmap-sysfs-groups.patch +md-md-bitmap-add-a-none-backend-for-bitmap-grow.patch +s390-mm-fix-phys_to_folio-usage-in-do_secure_storage.patch +net-phy-dp83869-fix-setting-clk_o_sel-field.patch +drm-amd-display-properly-handle-family-setting-for-e.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.0-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v2.5-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v3.0-enc-de.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0-enc-ri.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.3-enc-.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v4.0.5-enc-.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.0-enc-.patch +drm-amdgpu-vcn-set-no_user_fence-for-vcn-v5.0.1-enc-.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v2.5-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v3.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0-ring.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.3-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v4.0.5-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.0-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.0.1-ri.patch +drm-amdgpu-jpeg-set-no_user_fence-for-jpeg-v5.3.0-ri.patch +drm-amd-pm-add-fine-grained-flag-to-smu-v13.0.6.patch +io_uring-napi-cap-busy_poll_to-10-msec.patch +asoc-cs35l56-fix-illegal-writes-to-otp_mem-registers.patch +net-psp-check-for-device-unregister-when-creating-as.patch +net-psp-require-admin-permission-for-dev-set-and-key.patch +asoc-codecs-ab8500-fix-casting-of-private-data.patch +netfilter-skip-recording-stale-or-retransmitted-init.patch +sctp-discard-stale-init-after-handshake-completion.patch +bareudp-fix-null-pointer-dereference-in-bareudp_fill.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-1493 +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-2205 +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-21178 +net-sched-sch_cake-annotate-data-races-in-cake_dump_.patch-22292 +netconsole-return-count-instead-of-strnlen-buf-count.patch +netconsole-avoid-clobbering-userdatum-value-on-trunc.patch +netconsole-propagate-device-name-truncation-in-dev_n.patch +netconsole-restore-userdatum-value-on-update_userdat.patch +alsa-hda-conexant-fix-missing-error-check-for-jack-d.patch +alsa-hda-cs35l56-fix-uninitialized-value-in-cs35l56_.patch +alsa-hda-tas2781-fix-incorrect-bit-update-for-non-bo.patch +futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch +drm-amd-display-allow-embedded-connectors-without-dd.patch +drm-amd-display-allow-dce-link-encoder-without-aux-r.patch +drm-amd-display-allow-constructing-dce6-link-encoder.patch +drm-amd-display-allow-constructing-dce8-link-encoder.patch +drm-amd-display-read-edid-from-vbios-embedded-panel-.patch +drm-amd-display-use-edid-from-vbios-embedded-panel-i.patch +drm-xe-use-xe_wedged_mode_upon_any_hang_no_reset-enu.patch +drm-xe-drop-registration-of-guc_submit_wedged_fini-f.patch +drm-xe-debugfs-correct-printing-of-register-whitelis.patch +drm-xe-fix-potential-null-deref-in-xe_exec_queue_tlb.patch +drm-xe-fix-error-cleanup-in-xe_exec_queue_create_ioc.patch +drm-xe-eustall-fix-drm_dev_put-called-before-stream-.patch +drm-xe-gsc-fix-bo-leak-on-error-in-query_compatibili.patch +drm-xe-xelp-fix-wa_18022495364.patch +net-airoha-do-not-return-err-in-ndo_stop-callback.patch +bonding-print-churn-state-via-netlink.patch +bonding-3ad-implement-proper-rcu-rules-for-port-aggr.patch +page_pool-fix-memory-provider-leak-in-page_pool_crea.patch +iavf-rename-iavf_vlan_is_new-to-iavf_vlan_adding.patch +iavf-stop-removing-vlan-filters-from-pf-on-interface.patch +iavf-wait-for-pf-confirmation-before-removing-vlan-f.patch +iavf-add-virtchnl_op_add_vlan-to-success-completion-.patch +ice-fix-null-pointer-dereference-in-ice_reset_all_vf.patch +ice-fix-infinite-recursion-in-ice_cfg_tx_topo-via-ic.patch +ice-fix-missing-sma-pin-initialization-in-dpll-subsy.patch +ice-fix-sma-and-u.fl-pin-state-changes-affecting-pai.patch +ice-fix-missing-dpll-notifications-for-sw-pins.patch +dpll-export-__dpll_pin_change_ntf-for-use-under-dpll.patch +ice-add-dpll-peer-notification-for-paired-sma-and-u..patch +net-tls-fix-strparser-anchor-skb-leak-on-offload-rx-.patch +sfc-fix-error-code-in-efx_devlink_info_running_versi.patch +net-sched-cls_flower-revert-unintended-changes.patch +kselftest-arm64-include-asm-ptrace.h-for-user_gcs-de.patch +arm64-reserve-an-extra-page-for-early-kernel-mapping.patch +futex-drop-clone_thread-requirement-for-private-defa.patch diff --git a/queue-7.0/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch b/queue-7.0/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch new file mode 100644 index 0000000000..e4fe138df3 --- /dev/null +++ b/queue-7.0/sfc-fix-error-code-in-efx_devlink_info_running_versi.patch @@ -0,0 +1,37 @@ +From 2d7226c8bc90aaef01581e6eef3dcef600224086 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Apr 2026 09:48:17 +0300 +Subject: sfc: fix error code in efx_devlink_info_running_versions() + +From: Dan Carpenter + +[ Upstream commit 051ffb001b8a232cfa6e72f38bb5f51c4270a60b ] + +Return -EIO if efx_mcdi_rpc() doesn't return enough space. + +Fixes: 14743ddd2495 ("sfc: add devlink info support for ef100") +Signed-off-by: Dan Carpenter +Reviewed-by: Edward Cree +Link: https://patch.msgid.link/afGpsbLRHL4_H0KS@stanley.mountain +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sfc/efx_devlink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c +index d842c60dfc100..e5c6f81af48be 100644 +--- a/drivers/net/ethernet/sfc/efx_devlink.c ++++ b/drivers/net/ethernet/sfc/efx_devlink.c +@@ -531,7 +531,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx, + if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) { + netif_err(efx, drv, efx->net_dev, + "mcdi MC_CMD_GET_VERSION failed\n"); +- return rc; ++ return rc ?: -EIO; + } + + /* Handle previous output */ +-- +2.53.0 + diff --git a/queue-7.0/sh-include-linux-io.h-in-dac.h.patch b/queue-7.0/sh-include-linux-io.h-in-dac.h.patch new file mode 100644 index 0000000000..f2057534f6 --- /dev/null +++ b/queue-7.0/sh-include-linux-io.h-in-dac.h.patch @@ -0,0 +1,47 @@ +From 601f08ae4404f2136b920bee6cd4f4c0e49cfd79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Oct 2025 18:07:55 +0100 +Subject: sh: Include in dac.h + +From: Thomas Zimmermann + +[ Upstream commit 57b3ec396dd898aadc073bb16f3d05ee64b2c8af ] + +Include to avoid depending on +for including it. Declares __raw_readb() and __raw_writeb(). + +Signed-off-by: Thomas Zimmermann +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202510282206.wI0HrqcK-lkp@intel.com/ +Fixes: 243ce64b2b37 ("backlight: Do not include in header file") +Cc: Thomas Zimmermann +Cc: Daniel Thompson (RISCstar) +Cc: Simona Vetter +Cc: Lee Jones +Cc: Daniel Thompson +Cc: Jingoo Han +Cc: dri-devel@lists.freedesktop.org +Reviewed-by: John Paul Adrian Glaubitz +Reviewed-by: Daniel Thompson (RISCstar) +Signed-off-by: John Paul Adrian Glaubitz +Signed-off-by: Sasha Levin +--- + arch/sh/include/cpu-sh3/cpu/dac.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/sh/include/cpu-sh3/cpu/dac.h b/arch/sh/include/cpu-sh3/cpu/dac.h +index fd02331608a8d..323ec8570bcd1 100644 +--- a/arch/sh/include/cpu-sh3/cpu/dac.h ++++ b/arch/sh/include/cpu-sh3/cpu/dac.h +@@ -2,6 +2,8 @@ + #ifndef __ASM_CPU_SH3_DAC_H + #define __ASM_CPU_SH3_DAC_H + ++#include ++ + /* + * Copyright (C) 2003 Andriy Skulysh + */ +-- +2.53.0 + diff --git a/queue-7.0/signal-fix-the-lock_task_sighand-annotation.patch b/queue-7.0/signal-fix-the-lock_task_sighand-annotation.patch new file mode 100644 index 0000000000..d816015bd1 --- /dev/null +++ b/queue-7.0/signal-fix-the-lock_task_sighand-annotation.patch @@ -0,0 +1,38 @@ +From 0eb9fe61b8c23350851e7079c73419fe77a32d55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 10:32:42 -0800 +Subject: signal: Fix the lock_task_sighand() annotation + +From: Bart Van Assche + +[ Upstream commit 39be7b21af24d1d2ed3b18caac57dd219fef226e ] + +lock_task_sighand() may return NULL. Make this clear in its lock context +annotation. + +Fixes: 04e49d926f43 ("sched: Enable context analysis for core.c and fair.c") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Marco Elver +Link: https://patch.msgid.link/20260225183244.4035378-3-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/sched/signal.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h +index a22248aebcf90..a4835a7de07ee 100644 +--- a/include/linux/sched/signal.h ++++ b/include/linux/sched/signal.h +@@ -739,7 +739,7 @@ static inline int thread_group_empty(struct task_struct *p) + + extern struct sighand_struct *lock_task_sighand(struct task_struct *task, + unsigned long *flags) +- __acquires(&task->sighand->siglock); ++ __cond_acquires(nonnull, &task->sighand->siglock); + + static inline void unlock_task_sighand(struct task_struct *task, + unsigned long *flags) +-- +2.53.0 + diff --git a/queue-7.0/slip-bound-decode-reads-against-the-compressed-packe.patch b/queue-7.0/slip-bound-decode-reads-against-the-compressed-packe.patch new file mode 100644 index 0000000000..71dfefbbd3 --- /dev/null +++ b/queue-7.0/slip-bound-decode-reads-against-the-compressed-packe.patch @@ -0,0 +1,158 @@ +From b29ad80e5208e8961f07534adb431707dcd4d55d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 18:01:51 +0800 +Subject: slip: bound decode() reads against the compressed packet length + +From: Weiming Shi + +[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ] + +slhc_uncompress() parses a VJ-compressed TCP header by advancing a +pointer through the packet via decode() and pull16(). Neither helper +bounds-checks against isize, and decode() masks its return with +& 0xffff so it can never return the -1 that callers test for -- those +error paths are dead code. + +A short compressed frame whose change byte requests optional fields +lets decode() read past the end of the packet. The over-read bytes +are folded into the cached cstate and reflected into subsequent +reconstructed packets. + +Make decode() and pull16() take the packet end pointer and return -1 +when exhausted. Add a bounds check before the TCP-checksum read. +The existing == -1 tests now do what they were always meant to. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Simon Horman +Closes: https://lore.kernel.org/netdev/20260414134126.758795-2-horms@kernel.org/ +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260416100147.531855-5-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index e18a4213d10ce..1a9b27d5e256b 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -80,9 +80,9 @@ + #include + + static unsigned char *encode(unsigned char *cp, unsigned short n); +-static long decode(unsigned char **cpp); ++static long decode(unsigned char **cpp, const unsigned char *end); + static unsigned char * put16(unsigned char *cp, unsigned short x); +-static unsigned short pull16(unsigned char **cpp); ++static long pull16(unsigned char **cpp, const unsigned char *end); + + /* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) +@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n) + return cp; + } + +-/* Pull a 16-bit integer in host order from buffer in network byte order */ +-static unsigned short +-pull16(unsigned char **cpp) ++/* Pull a 16-bit integer in host order from buffer in network byte order. ++ * Returns -1 if the buffer is exhausted, otherwise the 16-bit value. ++ */ ++static long ++pull16(unsigned char **cpp, const unsigned char *end) + { +- short rval; ++ long rval; + ++ if (*cpp + 2 > end) ++ return -1; + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; + } + +-/* Decode a number */ ++/* Decode a number. Returns -1 if the buffer is exhausted. */ + static long +-decode(unsigned char **cpp) ++decode(unsigned char **cpp, const unsigned char *end) + { + int x; + ++ if (*cpp >= end) ++ return -1; + x = *(*cpp)++; +- if(x == 0){ +- return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ +- } else { +- return x & 0xff; /* -1 if PULLCHAR returned error */ +- } ++ if (x == 0) ++ return pull16(cpp, end); ++ return x & 0xff; + } + + /* +@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; ++ const unsigned char *end = icp + isize; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; +@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + ++ if (cp + 2 > end) ++ goto bad; + thp->check = *(__sum16 *)cp; + cp += 2; + +@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + default: + if(changes & NEW_U){ + thp->urg = 1; +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); +@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + break; + } + if(changes & NEW_I){ +- if((x = decode(&cp)) == -1) { ++ if((x = decode(&cp, end)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); +-- +2.53.0 + diff --git a/queue-7.0/slip-reject-vj-receive-packets-on-instances-with-no-.patch b/queue-7.0/slip-reject-vj-receive-packets-on-instances-with-no-.patch new file mode 100644 index 0000000000..dade2de985 --- /dev/null +++ b/queue-7.0/slip-reject-vj-receive-packets-on-instances-with-no-.patch @@ -0,0 +1,98 @@ +From 46957ad0e582007d1c25919e9d5e706e6708e4f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 04:41:31 +0800 +Subject: slip: reject VJ receive packets on instances with no rstate array + +From: Weiming Shi + +[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ] + +slhc_init() accepts rslots == 0 as a valid configuration, with the +documented meaning of 'no receive compression'. In that case the +allocation loop in slhc_init() is skipped, so comp->rstate stays +NULL and comp->rslot_limit stays 0 (from the kzalloc of struct +slcompress). + +The receive helpers do not defend against that configuration. +slhc_uncompress() dereferences comp->rstate[x] when the VJ header +carries an explicit connection ID, and slhc_remember() later assigns +cs = &comp->rstate[...] after only comparing the packet's slot number +to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the +range check, and the code dereferences a NULL rstate. + +The configuration is reachable in-tree through PPP. PPPIOCSMAXCID +stores its argument in a signed int, and (val >> 16) uses arithmetic +shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 +is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because +/dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path +is reachable from an unprivileged user namespace. Once the malformed +VJ state is installed, any inbound VJ-compressed or VJ-uncompressed +frame that selects slot 0 crashes the kernel in softirq context: + + Oops: general protection fault, probably for non-canonical + address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519) + Call Trace: + + ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466) + ppp_input (drivers/net/ppp/ppp_generic.c:2359) + ppp_async_process (drivers/net/ppp/ppp_async.c:492) + tasklet_action_common (kernel/softirq.c:926) + handle_softirqs (kernel/softirq.c:623) + run_ksoftirqd (kernel/softirq.c:1055) + smpboot_thread_fn (kernel/smpboot.c:160) + kthread (kernel/kthread.c:436) + ret_from_fork (arch/x86/kernel/process.c:164) + + +Reject the receive side on such instances instead of touching rstate. +slhc_uncompress() falls through to its existing 'bad' label, which +bumps sls_i_error and enters the toss state. slhc_remember() mirrors +that with an explicit sls_i_error increment followed by slhc_toss(); +the sls_i_runt counter is not used here because a missing rstate is +an internal configuration state, not a runt packet. + +The transmit path is unaffected: the only in-tree caller that picks +rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and +slip.c always calls slhc_init(16, 16), so comp->tstate remains valid +and slhc_compress() continues to work. + +Fixes: 4ab42d78e37a ("ppp, slip: Validate VJ compression slot parameters completely") +Reported-by: Xiang Mei +Signed-off-by: Weiming Shi +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260415204130.258866-2-bestswngs@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/slip/slhc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c +index e3c785da3eef3..e18a4213d10ce 100644 +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) + comp->sls_i_error++; + return 0; + } ++ if (!comp->rstate) ++ goto bad; + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. +@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) + struct cstate *cs; + unsigned int ihl; + ++ if (!comp->rstate) { ++ comp->sls_i_error++; ++ return slhc_toss(comp); ++ } + /* The packet is shorter than a legal IP header. + * Also make sure isize is positive. + */ +-- +2.53.0 + diff --git a/queue-7.0/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch b/queue-7.0/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch new file mode 100644 index 0000000000..62e89f77f4 --- /dev/null +++ b/queue-7.0/soc-qcom-aoss-compare-against-normalized-cooling-sta.patch @@ -0,0 +1,41 @@ +From bd126189803787dc74de53b7f9467a46d315aa46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 29 Mar 2026 12:53:23 -0700 +Subject: soc: qcom: aoss: compare against normalized cooling state + +From: Alok Tiwari + +[ Upstream commit cd3c4670db3ffe997be9548c7a9db3952563cf14 ] + +qmp_cdev_set_cur_state() normalizes the requested state to a boolean +(cdev_state = !!state). The existing early-return check compares +qmp_cdev->state == state, which can be wrong if state is non-boolean +(any non-zero value). Compare qmp_cdev->state against cdev_state instead, +so the check matches the effective state and avoids redundant updates. + +Signed-off-by: Alok Tiwari +Fixes: 05589b30b21a ("soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.") +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260329195333.1478090-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/qcom_aoss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c +index a543ab9bee6c4..c255662b8fc3d 100644 +--- a/drivers/soc/qcom/qcom_aoss.c ++++ b/drivers/soc/qcom/qcom_aoss.c +@@ -355,7 +355,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, + /* Normalize state */ + cdev_state = !!state; + +- if (qmp_cdev->state == state) ++ if (qmp_cdev->state == cdev_state) + return 0; + + ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}", +-- +2.53.0 + diff --git a/queue-7.0/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch b/queue-7.0/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch new file mode 100644 index 0000000000..10c8fea5f7 --- /dev/null +++ b/queue-7.0/soc-qcom-llcc-fix-v1-sb-syndrome-register-offset.patch @@ -0,0 +1,45 @@ +From 2f2b0a79301b38cd2879b20a6acfef9e8b93137b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 02:51:11 -0700 +Subject: soc: qcom: llcc: fix v1 SB syndrome register offset + +From: Alok Tiwari + +[ Upstream commit 24e7625df5ce065393249b78930781be593bc381 ] + +The llcc_v1_edac_reg_offset table uses 0x2304c for trp_ecc_sb_err_syn0, +which is inconsistent with the surrounding TRP ECC registers (0x2034x) +and with llcc_v2_1_edac_reg_offset, where trp_ecc_sb_err_syn0 is 0x2034c +adjacent to trp_ecc_error_status0/1 at 0x20344/0x20348. + +Use 0x2034c for llcc v1 so the SB syndrome register follows the expected ++0x4 progression from trp_ecc_error_status1. This fixes EDAC reading the +wrong register for SB syndrome reporting. + +Fixes: c13d7d261e36 ("soc: qcom: llcc: Pass LLCC version based register offsets to EDAC driver") +Signed-off-by: Alok Tiwari +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260330095118.2657362-1-alok.a.tiwari@oracle.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/llcc-qcom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c +index ad5899d083f3f..b80d3f9cff641 100644 +--- a/drivers/soc/qcom/llcc-qcom.c ++++ b/drivers/soc/qcom/llcc-qcom.c +@@ -3943,7 +3943,7 @@ static const struct llcc_slice_config x1e80100_data[] = { + static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { + .trp_ecc_error_status0 = 0x20344, + .trp_ecc_error_status1 = 0x20348, +- .trp_ecc_sb_err_syn0 = 0x2304c, ++ .trp_ecc_sb_err_syn0 = 0x2034c, + .trp_ecc_db_err_syn0 = 0x20370, + .trp_ecc_error_cntr_clear = 0x20440, + .trp_interrupt_0_status = 0x20480, +-- +2.53.0 + diff --git a/queue-7.0/soc-qcom-ocmem-make-the-core-clock-optional.patch b/queue-7.0/soc-qcom-ocmem-make-the-core-clock-optional.patch new file mode 100644 index 0000000000..eebed62e1f --- /dev/null +++ b/queue-7.0/soc-qcom-ocmem-make-the-core-clock-optional.patch @@ -0,0 +1,41 @@ +From 4dbc77b738e402364cddcfd4c2b9de4c3aff75e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:57 +0200 +Subject: soc: qcom: ocmem: make the core clock optional + +From: Dmitry Baryshkov + +[ Upstream commit e8a61c51417c679d1a599fb36695e9d3b8d95514 ] + +OCMEM's core clock (aka RPM bus 2 clock) is being handled internally by +the interconnect driver. Corresponding clock has been dropped from the +SMD RPM clock driver. The users of the ocmem will vote on the ocmemnoc +interconnect paths, making sure that ocmem is on. Make the clock +optional, keeping it for compatibility with older DT. + +Fixes: d6edc31f3a68 ("clk: qcom: smd-rpm: Separate out interconnect bus clocks") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-1-ad9bcae44763@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index 6a23f18b02812..dd46bb14b7be3 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -308,7 +308,7 @@ static int ocmem_dev_probe(struct platform_device *pdev) + ocmem->dev = dev; + ocmem->config = device_get_match_data(dev); + +- ocmem->core_clk = devm_clk_get(dev, "core"); ++ ocmem->core_clk = devm_clk_get_optional(dev, "core"); + if (IS_ERR(ocmem->core_clk)) + return dev_err_probe(dev, PTR_ERR(ocmem->core_clk), + "Unable to get core clock\n"); +-- +2.53.0 + diff --git a/queue-7.0/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch b/queue-7.0/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch new file mode 100644 index 0000000000..6f37b9578c --- /dev/null +++ b/queue-7.0/soc-qcom-ocmem-register-reasons-for-probe-deferrals.patch @@ -0,0 +1,46 @@ +From 8bc3a526a0a9ba0c0ee2c71135c4a3cc0f1536ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:58 +0200 +Subject: soc: qcom: ocmem: register reasons for probe deferrals + +From: Dmitry Baryshkov + +[ Upstream commit 9dfd69cd89cd6afa4723be9098979abeef3bb8c6 ] + +Instead of printing messages to the dmesg, let the message be recorded +as a reason for the OCMEM client deferral. + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Brian Masney +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-2-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index dd46bb14b7be3..d47ce5707fd88 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -196,10 +196,10 @@ struct ocmem *of_get_ocmem(struct device *dev) + } + + pdev = of_find_device_by_node(devnode->parent); +- if (!pdev) { +- dev_err(dev, "Cannot find device node %s\n", devnode->name); +- return ERR_PTR(-EPROBE_DEFER); +- } ++ if (!pdev) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, ++ "Cannot find device node %s\n", ++ devnode->name); + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +-- +2.53.0 + diff --git a/queue-7.0/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch b/queue-7.0/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch new file mode 100644 index 0000000000..55cc90d8b7 --- /dev/null +++ b/queue-7.0/soc-qcom-ocmem-return-eprobe_defer-is-ocmem-is-not-a.patch @@ -0,0 +1,46 @@ +From c3c83847749f3dcda32e293fd85f7aedc879c41a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 03:20:59 +0200 +Subject: soc: qcom: ocmem: return -EPROBE_DEFER is ocmem is not available + +From: Dmitry Baryshkov + +[ Upstream commit 91b59009c7d48b58dbc50fecb27f2ad20749a05a ] + +If OCMEM is declared in DT, it is expected that it is present and +handled by the driver. The GPU driver will ignore -ENODEV error, which +typically means that OCMEM isn't defined in DT. Let ocmem return +-EPROBE_DEFER if it supposed to be used, but it is not probed (yet). + +Fixes: 88c1e9404f1d ("soc: qcom: add OCMEM driver") +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Konrad Dybcio +Link: https://lore.kernel.org/r/20260323-ocmem-v1-3-ad9bcae44763@oss.qualcomm.com +[bjorn: s/ERR_PTR(dev_err_probe)/dev_err_ptr_probe/ +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ocmem.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c +index d47ce5707fd88..96ca0b87bfc48 100644 +--- a/drivers/soc/qcom/ocmem.c ++++ b/drivers/soc/qcom/ocmem.c +@@ -203,10 +203,9 @@ struct ocmem *of_get_ocmem(struct device *dev) + + ocmem = platform_get_drvdata(pdev); + put_device(&pdev->dev); +- if (!ocmem) { +- dev_err(dev, "Cannot get ocmem\n"); +- return ERR_PTR(-ENODEV); +- } ++ if (!ocmem) ++ return dev_err_ptr_probe(dev, -EPROBE_DEFER, "Cannot get ocmem\n"); ++ + return ocmem; + } + EXPORT_SYMBOL_GPL(of_get_ocmem); +-- +2.53.0 + diff --git a/queue-7.0/soc-qcom-ubwc-disable-bank-swizzling-for-glymur-plat.patch b/queue-7.0/soc-qcom-ubwc-disable-bank-swizzling-for-glymur-plat.patch new file mode 100644 index 0000000000..911f6bb808 --- /dev/null +++ b/queue-7.0/soc-qcom-ubwc-disable-bank-swizzling-for-glymur-plat.patch @@ -0,0 +1,44 @@ +From 11575518881551fb9a7cf529dd7a877b14eb9889 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 20:34:27 +0200 +Subject: soc: qcom: ubwc: disable bank swizzling for Glymur platform + +From: Dmitry Baryshkov + +[ Upstream commit e031e7ceac4ee04973bd77362c363734e79dd08c ] + +Due to the way the DDR controller is organized on Glymur, hardware +engineers strongly recommended disabling UBWC bank swizzling on Glymur. +Follow that recommendation. + +Fixes: 9b21c3bd2480 ("soc: qcom: ubwc: Add configuration Glymur platform") +Signed-off-by: Dmitry Baryshkov +Acked-by: Rob Clark +Reviewed-by: Konrad Dybcio +Reviewed-by: Abel Vesa +Reviewed-by: Akhil P Oommen +Reviewed-by: Akhil P Oommen +Link: https://lore.kernel.org/r/20260228-fix-glymur-ubwc-v2-1-70819bd6a6b4@oss.qualcomm.com +Signed-off-by: Bjorn Andersson +Signed-off-by: Sasha Levin +--- + drivers/soc/qcom/ubwc_config.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c +index 1c25aaf55e523..8304463f238a6 100644 +--- a/drivers/soc/qcom/ubwc_config.c ++++ b/drivers/soc/qcom/ubwc_config.c +@@ -231,8 +231,7 @@ static const struct qcom_ubwc_cfg_data x1e80100_data = { + static const struct qcom_ubwc_cfg_data glymur_data = { + .ubwc_enc_version = UBWC_5_0, + .ubwc_dec_version = UBWC_5_0, +- .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | +- UBWC_SWIZZLE_ENABLE_LVL3, ++ .ubwc_swizzle = 0, + .ubwc_bank_spread = true, + /* TODO: highest_bank_bit = 15 for LP_DDR4 */ + .highest_bank_bit = 16, +-- +2.53.0 + diff --git a/queue-7.0/soc-tegra-cbb-fix-cross-fabric-target-timeout-lookup.patch b/queue-7.0/soc-tegra-cbb-fix-cross-fabric-target-timeout-lookup.patch new file mode 100644 index 0000000000..423a09f8a1 --- /dev/null +++ b/queue-7.0/soc-tegra-cbb-fix-cross-fabric-target-timeout-lookup.patch @@ -0,0 +1,87 @@ +From e2229b8042879a36bff9e406698d8a7bd956bb7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:05 +0530 +Subject: soc/tegra: cbb: Fix cross-fabric target timeout lookup + +From: Sumit Gupta + +[ Upstream commit a5f51b04cbb3ae0f9cb2c4488952b775ebb0ccbf ] + +When a fabric receives an error interrupt, the error may have +occurred on a different fabric. The target timeout lookup was using +the wrong base address (cbb->regs) with offsets from a different +fabric's target map, causing a kernel page fault. + + Unable to handle kernel paging request at virtual address ffff80000954cc00 + pc : tegra234_cbb_get_tmo_slv+0xc/0x28 + Call trace: + tegra234_cbb_get_tmo_slv+0xc/0x28 + print_err_notifier+0x6c0/0x7d0 + tegra234_cbb_isr+0xe4/0x1b4 + +Add tegra234_cbb_get_fabric() to look up the correct fabric device +using fab_id, and use its base address for accessing target timeout +registers. + +Fixes: 25de5c8fe0801 ("soc/tegra: cbb: Improve handling for per SoC fabric data") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index 626e0e820329b..7e387fc54c6b1 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -313,12 +313,37 @@ static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *target + } + } + ++static struct tegra234_cbb *tegra234_cbb_get_fabric(u8 fab_id) ++{ ++ struct tegra_cbb *entry; ++ ++ list_for_each_entry(entry, &cbb_list, node) { ++ struct tegra234_cbb *priv = to_tegra234_cbb(entry); ++ ++ if (priv->fabric->fab_id == fab_id) ++ return priv; ++ } ++ ++ return NULL; ++} ++ + static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegra234_cbb *cbb, + u8 target_id, u8 fab_id) + { + const struct tegra234_target_lookup *map = cbb->fabric->fab_list[fab_id].target_map; ++ struct tegra234_cbb *target_cbb = NULL; + void __iomem *addr; + ++ if (fab_id == cbb->fabric->fab_id) ++ target_cbb = cbb; ++ else ++ target_cbb = tegra234_cbb_get_fabric(fab_id); ++ ++ if (!target_cbb) { ++ dev_err(cbb->base.dev, "could not find fabric for fab_id:%d\n", fab_id); ++ return; ++ } ++ + if (target_id >= cbb->fabric->fab_list[fab_id].max_targets) { + tegra_cbb_print_err(file, "\t Invalid target_id:%d\n", target_id); + return; +@@ -341,7 +366,7 @@ static void tegra234_sw_lookup_target_timeout(struct seq_file *file, struct tegr + * e) Goto step-a till all bits are set. + */ + +- addr = cbb->regs + map[target_id].offset; ++ addr = target_cbb->regs + map[target_id].offset; + + if (strstr(map[target_id].name, "AXI2APB")) { + addr += APB_BLOCK_TMO_STATUS_0; +-- +2.53.0 + diff --git a/queue-7.0/soc-tegra-cbb-fix-incorrect-array_size-in-fabric-loo.patch b/queue-7.0/soc-tegra-cbb-fix-incorrect-array_size-in-fabric-loo.patch new file mode 100644 index 0000000000..82322c4c9d --- /dev/null +++ b/queue-7.0/soc-tegra-cbb-fix-incorrect-array_size-in-fabric-loo.patch @@ -0,0 +1,45 @@ +From 97a5d531e608a6a814f789d3d24b2c694daa7007 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:04 +0530 +Subject: soc/tegra: cbb: Fix incorrect ARRAY_SIZE in fabric lookup tables + +From: Sumit Gupta + +[ Upstream commit 499f7e5ebbdd9ff0c4d532b1c432f8a61ff585b3 ] + +Fix incorrect ARRAY_SIZE usage in fabric lookup tables which could +cause out-of-bounds access during target timeout lookup. + +Fixes: 25de5c8fe0801 ("soc/tegra: cbb: Improve handling for per SoC fabric data") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index 518733a066588..626e0e820329b 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -881,7 +881,7 @@ static const struct tegra234_fabric_lookup tegra234_cbb_fab_list[] = { + ARRAY_SIZE(tegra234_common_target_map) }, + [T234_AON_FABRIC_ID] = { "aon-fabric", true, + tegra234_aon_target_map, +- ARRAY_SIZE(tegra234_bpmp_target_map) }, ++ ARRAY_SIZE(tegra234_aon_target_map) }, + [T234_PSC_FABRIC_ID] = { "psc-fabric" }, + [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true, + tegra234_bpmp_target_map, +@@ -1160,7 +1160,7 @@ static const struct tegra234_fabric_lookup tegra241_cbb_fab_list[] = { + [T234_CBB_FABRIC_ID] = { "cbb-fabric", true, + tegra241_cbb_target_map, ARRAY_SIZE(tegra241_cbb_target_map) }, + [T234_BPMP_FABRIC_ID] = { "bpmp-fabric", true, +- tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_cbb_target_map) }, ++ tegra241_bpmp_target_map, ARRAY_SIZE(tegra241_bpmp_target_map) }, + }; + static const struct tegra234_cbb_fabric tegra241_cbb_fabric = { + .fab_id = T234_CBB_FABRIC_ID, +-- +2.53.0 + diff --git a/queue-7.0/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch b/queue-7.0/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch new file mode 100644 index 0000000000..a7df47ea79 --- /dev/null +++ b/queue-7.0/soc-tegra-cbb-set-erd-on-resume-for-err-interrupt.patch @@ -0,0 +1,43 @@ +From 25f0029db12c6c60a462117b337c37391771f518 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 15:42:03 +0530 +Subject: soc/tegra: cbb: Set ERD on resume for err interrupt + +From: Sumit Gupta + +[ Upstream commit b6ff71c5d1d4ad858ddf6f39394d169c96689596 ] + +Set the Error Response Disable (ERD) bit to mask SError responses +and use interrupt-based error reporting. When the ERD bit is set, +inband error responses to the initiator via SError are suppressed, +and fabric errors are reported via an interrupt instead. + +The register is set during boot but the info is lost during system +suspend and needs to be set again on resume. + +Fixes: fc2f151d2314 ("soc/tegra: cbb: Add driver for Tegra234 CBB 2.0") +Signed-off-by: Sumit Gupta +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/cbb/tegra234-cbb.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c +index a9adbcecd47cc..518733a066588 100644 +--- a/drivers/soc/tegra/cbb/tegra234-cbb.c ++++ b/drivers/soc/tegra/cbb/tegra234-cbb.c +@@ -1586,6 +1586,10 @@ static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) + { + struct tegra234_cbb *cbb = dev_get_drvdata(dev); + ++ /* set ERD bit to mask SError and generate interrupt to report error */ ++ if (cbb->fabric->off_mask_erd) ++ tegra234_cbb_mask_serror(cbb); ++ + tegra234_cbb_error_enable(&cbb->base); + + dev_dbg(dev, "%s resumed\n", cbb->fabric->fab_list[cbb->fabric->fab_id].name); +-- +2.53.0 + diff --git a/queue-7.0/soc-tegra-pmc-add-kerneldoc-for-reboot-notifier.patch b/queue-7.0/soc-tegra-pmc-add-kerneldoc-for-reboot-notifier.patch new file mode 100644 index 0000000000..a886ac16d2 --- /dev/null +++ b/queue-7.0/soc-tegra-pmc-add-kerneldoc-for-reboot-notifier.patch @@ -0,0 +1,37 @@ +From 7a802c3cf223f8d6fb65be2977c4e7b0da23b656 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 19:25:51 +0000 +Subject: soc/tegra: pmc: Add kerneldoc for reboot notifier + +From: Jon Hunter + +[ Upstream commit 21669619e4c17a5f097e0415bc64b1d400c54fcb ] + +Commit 48b7f802fb78 ("soc/tegra: pmc: Embed reboot notifier in PMC +context") added the reboot_notifier structure to the PMC SoC structure +but did not update the kerneldoc accordingly. Add this missing kerneldoc +description to fix this. + +Fixes: 48b7f802fb78 ("soc/tegra: pmc: Embed reboot notifier in PMC context") +Signed-off-by: Jon Hunter +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/pmc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c +index a1a2966512d1a..8268a41c471a9 100644 +--- a/drivers/soc/tegra/pmc.c ++++ b/drivers/soc/tegra/pmc.c +@@ -437,6 +437,7 @@ struct tegra_pmc_soc { + * @wake_sw_status_map: Bitmap to hold raw status of wakes without mask + * @wake_cntrl_level_map: Bitmap to hold wake levels to be programmed in + * cntrl register associated with each wake during system suspend. ++ * @reboot_notifier: PMC reboot notifier handler + * @syscore: syscore suspend/resume callbacks + */ + struct tegra_pmc { +-- +2.53.0 + diff --git a/queue-7.0/soc-tegra-pmc-add-kerneldoc-for-wake-up-variables.patch b/queue-7.0/soc-tegra-pmc-add-kerneldoc-for-wake-up-variables.patch new file mode 100644 index 0000000000..e9476f6307 --- /dev/null +++ b/queue-7.0/soc-tegra-pmc-add-kerneldoc-for-wake-up-variables.patch @@ -0,0 +1,38 @@ +From 401cac049658056f1be12aa0e7de50f19dd56cbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 19:25:53 +0000 +Subject: soc/tegra: pmc: Add kerneldoc for wake-up variables + +From: Jon Hunter + +[ Upstream commit e6ad1988e56834d641ba4aa0d58970723c1c9c9b ] + +Commit e6d96073af68 ("soc/tegra: pmc: Fix unsafe generic_handle_irq() +call") added the variables 'wake_work' and 'wake_status' to the +'tegra_pmc' structure but did not add the associated kerneldoc for these +new variables. Add the kerneldoc for these variables. + +Fixes: e6d96073af68 ("soc/tegra: pmc: Fix unsafe generic_handle_irq() call") +Signed-off-by: Jon Hunter +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/pmc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c +index b889c44f8fddf..6debaabdaa36a 100644 +--- a/drivers/soc/tegra/pmc.c ++++ b/drivers/soc/tegra/pmc.c +@@ -439,6 +439,8 @@ struct tegra_pmc_soc { + * cntrl register associated with each wake during system suspend. + * @reboot_notifier: PMC reboot notifier handler + * @syscore: syscore suspend/resume callbacks ++ * @wake_work: IRQ work handler for processing wake-up events. ++ * @wake_status: Status of wake-up events. + */ + struct tegra_pmc { + struct device *dev; +-- +2.53.0 + diff --git a/queue-7.0/soc-tegra-pmc-correct-function-names-in-kerneldoc.patch b/queue-7.0/soc-tegra-pmc-correct-function-names-in-kerneldoc.patch new file mode 100644 index 0000000000..4d27a02dad --- /dev/null +++ b/queue-7.0/soc-tegra-pmc-correct-function-names-in-kerneldoc.patch @@ -0,0 +1,48 @@ +From fa84f118c6aeb4cce8b84d773ecd345238b74d21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 19:25:52 +0000 +Subject: soc/tegra: pmc: Correct function names in kerneldoc + +From: Jon Hunter + +[ Upstream commit ec0e4da5d679f9da1cc198927951f70fdf28f001 ] + +Commit 70f752ebb08c ("soc/tegra: pmc: Add PMC contextual functions") +added the functions devm_tegra_pmc_get() and +tegra_pmc_io_pad_power_enable(), but the names of the functions in the +associated kerneldoc is incorrect. Update the kerneldoc for these +functions to correct their names. + +Fixes: 70f752ebb08c ("soc/tegra: pmc: Add PMC contextual functions") +Signed-off-by: Jon Hunter +Signed-off-by: Thierry Reding +Signed-off-by: Sasha Levin +--- + drivers/soc/tegra/pmc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c +index 8268a41c471a9..b889c44f8fddf 100644 +--- a/drivers/soc/tegra/pmc.c ++++ b/drivers/soc/tegra/pmc.c +@@ -1005,7 +1005,7 @@ static struct tegra_pmc *tegra_pmc_get(struct device *dev) + } + + /** +- * tegra_pmc_get() - find the PMC for a given device ++ * devm_tegra_pmc_get() - find the PMC for a given device + * @dev: device for which to find the PMC + * + * Returns a pointer to the PMC on success or an ERR_PTR()-encoded error code +@@ -1747,7 +1747,7 @@ static void tegra_io_pad_unprepare(struct tegra_pmc *pmc) + } + + /** +- * tegra_io_pad_power_enable() - enable power to I/O pad ++ * tegra_pmc_io_pad_power_enable() - enable power to I/O pad + * @pmc: power management controller + * @id: Tegra I/O pad ID for which to enable power + * +-- +2.53.0 + diff --git a/queue-7.0/soundwire-bus-demote-unattached-state-warnings-to-de.patch b/queue-7.0/soundwire-bus-demote-unattached-state-warnings-to-de.patch new file mode 100644 index 0000000000..8203e56e5a --- /dev/null +++ b/queue-7.0/soundwire-bus-demote-unattached-state-warnings-to-de.patch @@ -0,0 +1,62 @@ +From 827ea144c7868872ee8710f1c8faafed74d8e359 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 11:02:10 -0700 +Subject: soundwire: bus: demote UNATTACHED state warnings to dev_dbg() + +From: Cole Leavitt + +[ Upstream commit 2c96956fe764f8224f9ec93b2a9160a578949a7a ] + +The dev_warn() messages in sdw_handle_slave_status() for UNATTACHED +transitions were added in commit d1b328557058 ("soundwire: bus: add +dev_warn() messages to track UNATTACHED devices") to debug attachment +failures with dynamic debug enabled. + +These warnings fire during normal operation -- for example when a codec +driver triggers a hardware reset after firmware download, causing the +device to momentarily go UNATTACHED before re-attaching -- producing +misleading noise on every boot. + +Demote the messages to dev_dbg() so they remain available via dynamic +debug for diagnosing real attachment failures without alarming users +during expected initialization sequences. + +Fixes: d1b328557058 ("soundwire: bus: add dev_warn() messages to track UNATTACHED devices") +Signed-off-by: Cole Leavitt +Reviewed-by: Richard Fitzgerald +Link: https://patch.msgid.link/20260218180210.9263-1-cole@unwrap.rs +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/bus.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c +index fb68738dfb9b8..fe5316d93fefe 100644 +--- a/drivers/soundwire/bus.c ++++ b/drivers/soundwire/bus.c +@@ -1899,8 +1899,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + + if (status[i] == SDW_SLAVE_UNATTACHED && + slave->status != SDW_SLAVE_UNATTACHED) { +- dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", ++ i, slave->status); + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + + /* Ensure driver knows that peripheral unattached */ +@@ -1951,8 +1951,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, + if (slave->status == SDW_SLAVE_UNATTACHED) + break; + +- dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", +- i, slave->status); ++ dev_dbg(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n", ++ i, slave->status); + + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + break; +-- +2.53.0 + diff --git a/queue-7.0/soundwire-cadence-clear-message-complete-before-sign.patch b/queue-7.0/soundwire-cadence-clear-message-complete-before-sign.patch new file mode 100644 index 0000000000..669651cb2e --- /dev/null +++ b/queue-7.0/soundwire-cadence-clear-message-complete-before-sign.patch @@ -0,0 +1,89 @@ +From 7624f72ff9776a582aaf756c8a1c80fa62661c30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Mar 2026 11:31:33 +0000 +Subject: soundwire: cadence: Clear message complete before signaling waiting + thread + +From: Richard Fitzgerald + +[ Upstream commit cbfea84f820962c3c5394ff06e7e9344c96bf761 ] + +Clear the CDNS_MCP_INT_RX_WL interrupt before signaling completion. + +This is to prevent the potential race where: +- The main thread is scheduled immediately the completion is signaled, + and starts a new message +- The RX_WL IRQ for this new message happens before sdw_cdns_irq() has + been re-scheduled. +- When sdw_cdns_irq() is re-scheduled it clears the new RX_WL interrupt. + +MAIN THREAD | IRQ THREAD + | + _cdns_xfer_msg() | + { | + write data to FIFO | + wait_for_completion_timeout() | + | <---- RX_WL IRQ + | sdw_cdns_irq() + | { + | signal completion + <== RESCHEDULE <== + Handle message completion | + } | + | +Start new message | + _cdns_xfer_msg() | + { | + write data to FIFO | + wait_for_completion_timeout() | + | <---- RX_WL IRQ + ==> RESCHEDULE ==> + | // New RX_WL IRQ is cleared before + | // it has been handled. + | clear CDNS_MCP_INTSTAT + + | return IRQ_HANDLED; + | } + +Before this change, this error message was sometimes seen on kernels +that have large amounts of debugging enabled: + + SCP Msg trf timed out + +This error indicates that the completion has not been signalled after +500ms. + +Signed-off-by: Richard Fitzgerald +Fixes: 956baa1992f9 ("soundwire: cdns: Add sdw_master_ops and IO transfer support") +Reported-by: Norman Bintang +Closes: https://issuetracker.google.com/issues/477099834 +Reviewed-by: Pierre-Louis Bossart +Link: https://patch.msgid.link/20260310113133.1707288-1-rf@opensource.cirrus.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/cadence_master.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c +index f245c3ffb9e97..b8b62735c8938 100644 +--- a/drivers/soundwire/cadence_master.c ++++ b/drivers/soundwire/cadence_master.c +@@ -933,6 +933,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) + + cdns_read_response(cdns); + ++ /* ++ * Clear interrupt before signalling the completion to avoid ++ * a race between this thread and the main thread starting ++ * another TX. ++ */ ++ cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_RX_WL); ++ int_status &= ~CDNS_MCP_INT_RX_WL; ++ + if (defer && defer->msg) { + cdns_fill_msg_resp(cdns, defer->msg, + defer->length, 0); +-- +2.53.0 + diff --git a/queue-7.0/soundwire-debugfs-initialize-firmware_file-to-empty-.patch b/queue-7.0/soundwire-debugfs-initialize-firmware_file-to-empty-.patch new file mode 100644 index 0000000000..ebf498b235 --- /dev/null +++ b/queue-7.0/soundwire-debugfs-initialize-firmware_file-to-empty-.patch @@ -0,0 +1,66 @@ +From 20ef749e4ee5a4dc38897d56451122a979813aca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 16:58:46 +0800 +Subject: soundwire: debugfs: initialize firmware_file to empty string + +From: Gui-Dong Han + +[ Upstream commit 7215e4552f31e53595eae56a834f7e286beecccc ] + +Passing NULL to debugfs_create_str() causes a NULL pointer dereference, +and creating debugfs nodes with NULL string pointers is no longer +permitted. + +Additionally, firmware_file is a global pointer. Previously, adding every +new slave blindly overwrote it with NULL. + +Fix these issues by initializing firmware_file to an allocated empty +string once in the subsystem init path (sdw_debugfs_init), and freeing +it in the exit path. Existing driver code handles empty strings +correctly. + +Fixes: fe46d2a4301d ("soundwire: debugfs: add interface to read/write commands") +Reported-by: yangshiguang +Closes: https://lore.kernel.org/lkml/17647e4c.d461.19b46144a4e.Coremail.yangshiguang1011@163.com/ +Signed-off-by: Gui-Dong Han +Link: https://patch.msgid.link/20260323085930.88894-4-hanguidong02@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/soundwire/debugfs.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c +index ccc9670ef77ce..2905ec19b8384 100644 +--- a/drivers/soundwire/debugfs.c ++++ b/drivers/soundwire/debugfs.c +@@ -358,8 +358,8 @@ void sdw_slave_debugfs_init(struct sdw_slave *slave) + debugfs_create_file("go", 0200, d, slave, &cmd_go_fops); + + debugfs_create_file("read_buffer", 0400, d, slave, &read_buffer_fops); +- firmware_file = NULL; +- debugfs_create_str("firmware_file", 0200, d, &firmware_file); ++ if (firmware_file) ++ debugfs_create_str("firmware_file", 0200, d, &firmware_file); + + slave->debugfs = d; + } +@@ -371,10 +371,15 @@ void sdw_slave_debugfs_exit(struct sdw_slave *slave) + + void sdw_debugfs_init(void) + { ++ if (!firmware_file) ++ firmware_file = kstrdup("", GFP_KERNEL); ++ + sdw_debugfs_root = debugfs_create_dir("soundwire", NULL); + } + + void sdw_debugfs_exit(void) + { + debugfs_remove_recursive(sdw_debugfs_root); ++ kfree(firmware_file); ++ firmware_file = NULL; + } +-- +2.53.0 + diff --git a/queue-7.0/soundwire-intel-test-bus.bpt_stream-before-assigning.patch b/queue-7.0/soundwire-intel-test-bus.bpt_stream-before-assigning.patch new file mode 100644 index 0000000000..8042eaa3fc --- /dev/null +++ b/queue-7.0/soundwire-intel-test-bus.bpt_stream-before-assigning.patch @@ -0,0 +1,50 @@ +From 889fe2faaba9219759bdff4527c343eec7c0683b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 13:40:45 +0800 +Subject: soundwire: Intel: test bus.bpt_stream before assigning it + +From: Bard Liao + +[ Upstream commit b2c9f1d5a7eb50bcdda607afef1378e552bbb490 ] + +We only allow up to 1 bpt stream running on a SoundWire bus. +bus.bpt_stream will be assigned when it is opened and will be set to +NULL when it is closed. We do check bus->bpt_stream_refcount if the +stream type is SDW_STREAM_BPT in sdw_master_rt_alloc(), but at that +moment the bpt stream is allocated and set to bus.bpt_stream. It will +lead to the original bus.bpt_stream be changed to the new and not used +bpt stream. And it will be released and set to NULL when +sdw_slave_bpt_stream_add() return error as it supposed to. Then the +original stream will try to use the NULL bus.bpt_stream. + +Fixes: 4c1ce9f37d8a ("soundwire: intel_ace2x: add BPT send_async/wait callbacks") +Reported-by: Simon Trimmer +Signed-off-by: Bard Liao +Reviewed-by: Simon Trimmer +Reviewed-by: Ranjani Sridharan +Link: https://patch.msgid.link/20260126054045.2504103-1-yung-chuan.liao@linux.intel.com +Signed-off-by: Vinod Koul +Signed-off-by: Sasha Levin +--- + drivers/soundwire/intel_ace2x.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c +index 7f01e43ae978a..20422534baf19 100644 +--- a/drivers/soundwire/intel_ace2x.c ++++ b/drivers/soundwire/intel_ace2x.c +@@ -82,6 +82,11 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * + int len; + int i; + ++ if (cdns->bus.bpt_stream) { ++ dev_err(cdns->dev, "%s: BPT stream already exists\n", __func__); ++ return -EAGAIN; ++ } ++ + stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT); + if (!stream) + return -ENOMEM; +-- +2.53.0 + diff --git a/queue-7.0/sparc64-vdso-link-with-z-noexecstack.patch b/queue-7.0/sparc64-vdso-link-with-z-noexecstack.patch new file mode 100644 index 0000000000..6a7738f539 --- /dev/null +++ b/queue-7.0/sparc64-vdso-link-with-z-noexecstack.patch @@ -0,0 +1,47 @@ +From 3d42ddb5372fa40b9e6de3202424cdfbd804b38f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 08:49:01 +0100 +Subject: sparc64: vdso: Link with -z noexecstack +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit acc4f131d5d57c2aa89db914aeb6f7bb0ab4eb4a ] + +The vDSO stack does not need to be executable. Prevent the linker from +creating executable. For more background see commit ffcf9c5700e4 ("x86: +link vdso and boot with -z noexecstack --no-warn-rwx-segments"). + +Also prevent the following warning from the linker: +sparc64-linux-ld: warning: arch/sparc/vdso/vdso-note.o: missing .note.GNU-stack section implies executable stack +sparc64-linux-ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker + +Fixes: 9a08862a5d2e ("vDSO for sparc") +Suggested-by: Arnd Bergmann +Signed-off-by: Thomas Weißschuh +Signed-off-by: Thomas Gleixner +Tested-by: Andreas Larsson +Reviewed-by: Andreas Larsson +Acked-by: Andreas Larsson +Link: https://lore.kernel.org/lkml/20250707144726.4008707-1-arnd@kernel.org/ +Link: https://patch.msgid.link/20260304-vdso-sparc64-generic-2-v6-4-d8eb3b0e1410@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/sparc/vdso/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile +index 683b2d4082244..400529acd1c10 100644 +--- a/arch/sparc/vdso/Makefile ++++ b/arch/sparc/vdso/Makefile +@@ -104,4 +104,4 @@ quiet_cmd_vdso = VDSO $@ + $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ + -T $(filter %.lds,$^) $(filter %.o,$^) + +-VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined ++VDSO_LDFLAGS = -shared --hash-style=both --build-id=sha1 -Bsymbolic --no-undefined -z noexecstack +-- +2.53.0 + diff --git a/queue-7.0/spi-amlogic-spisg-initialize-completion-before-reque.patch b/queue-7.0/spi-amlogic-spisg-initialize-completion-before-reque.patch new file mode 100644 index 0000000000..9188825beb --- /dev/null +++ b/queue-7.0/spi-amlogic-spisg-initialize-completion-before-reque.patch @@ -0,0 +1,46 @@ +From 47da69b7382c99d0ddfd6d5af82110878fc510fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 01:42:00 +0800 +Subject: spi: amlogic-spisg: initialize completion before requesting IRQ + +From: Felix Gu + +[ Upstream commit 8d0189c1ea98b56481eb809e3d1bdbf85557e819 ] + +Move init_completion(&spisg->completion) to before devm_request_irq() +to avoid a potential race condition where an interrupt could fire +before the completion structure is initialized. + +Fixes: cef9991e04ae ("spi: Add Amlogic SPISG driver") +Signed-off-by: Felix Gu +Link: https://patch.msgid.link/20260428-amlogic-spisg-v1-1-8eecc3b446d6@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-amlogic-spisg.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c +index e15d7112bb55c..0280868f7edf5 100644 +--- a/drivers/spi/spi-amlogic-spisg.c ++++ b/drivers/spi/spi-amlogic-spisg.c +@@ -794,6 +794,7 @@ static int aml_spisg_probe(struct platform_device *pdev) + + dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX); + ++ init_completion(&spisg->completion); + ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg); + if (ret) { + dev_err(&pdev->dev, "irq request failed\n"); +@@ -806,8 +807,6 @@ static int aml_spisg_probe(struct platform_device *pdev) + goto out_clk; + } + +- init_completion(&spisg->completion); +- + pm_runtime_put(&spisg->pdev->dev); + + return 0; +-- +2.53.0 + diff --git a/queue-7.0/spi-atcspi200-fix-mutex-initialization-order.patch b/queue-7.0/spi-atcspi200-fix-mutex-initialization-order.patch new file mode 100644 index 0000000000..bb04d5d7cd --- /dev/null +++ b/queue-7.0/spi-atcspi200-fix-mutex-initialization-order.patch @@ -0,0 +1,60 @@ +From 3081610a3a33f8f721168f282d628dfc1c3f6502 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 10:47:55 +0800 +Subject: spi: atcspi200: fix mutex initialization order + +From: Pei Xiao + +[ Upstream commit 869d5b4b2a8012f6ef6058a1055cac6922c2cb55 ] + +The atcspi_exec_mem_op() function may call mutex_lock() on the +driver's mutex before it is properly initialized if a SPI memory +operation is initiated immediately after devm_spi_register_controller() +is called. The mutex initialization currently occurs after the +controller registration, which leaves a window where the mutex could +be used uninitialized. + +Move the mutex initialization to the beginning of the probe function, +before any registration or resource allocation. + +Fixes: 34e3815ea459 ("spi: atcspi200: Add ATCSPI200 SPI controller driver") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/15a71241affc25108a97d40d9d3dd1bc3d2d69ed.1773282905.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-atcspi200.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-atcspi200.c b/drivers/spi/spi-atcspi200.c +index 2665f31a49ceb..02517af9e3987 100644 +--- a/drivers/spi/spi-atcspi200.c ++++ b/drivers/spi/spi-atcspi200.c +@@ -567,6 +567,8 @@ static int atcspi_probe(struct platform_device *pdev) + spi->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, host); + ++ mutex_init(&spi->mutex_lock); ++ + ret = atcspi_init_resources(pdev, spi, &mem_res); + if (ret) + goto free_controller; +@@ -597,7 +599,6 @@ static int atcspi_probe(struct platform_device *pdev) + else + spi->use_dma = true; + } +- mutex_init(&spi->mutex_lock); + + return 0; + +@@ -605,6 +606,7 @@ static int atcspi_probe(struct platform_device *pdev) + clk_disable_unprepare(spi->clk); + + free_controller: ++ mutex_destroy(&spi->mutex_lock); + spi_controller_put(host); + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/spi-axiado-remove-redundant-pm_runtime_mark_last_bus.patch b/queue-7.0/spi-axiado-remove-redundant-pm_runtime_mark_last_bus.patch new file mode 100644 index 0000000000..a2e6dea240 --- /dev/null +++ b/queue-7.0/spi-axiado-remove-redundant-pm_runtime_mark_last_bus.patch @@ -0,0 +1,38 @@ +From 324c5c2d89cb366bc60f358e45ac227f62c4e423 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Mar 2026 15:47:15 +0800 +Subject: spi: axiado: Remove redundant pm_runtime_mark_last_busy() call + +From: Felix Gu + +[ Upstream commit ec6c2e15a42fc8fb63baadee0e8a3257e37fa90c ] + +The pm_runtime_mark_last_busy() call is redundant in the probe function +as pm_runtime_put_autosuspend() already calls pm_runtime_mark_last_busy() +internally to update the last access time of the device before queuing +autosuspend. + +Fixes: e75a6b00ad79 ("spi: axiado: Add driver for Axiado SPI DB controller") +Signed-off-by: Felix Gu +Signed-off-by: Mark Brown +Link: https://patch.msgid.link/20260307-axiado-1-v1-1-e90aa1b6dd9b@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-axiado.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/spi/spi-axiado.c b/drivers/spi/spi-axiado.c +index 8ddcd27def22b..dc55c55ae63c8 100644 +--- a/drivers/spi/spi-axiado.c ++++ b/drivers/spi/spi-axiado.c +@@ -842,7 +842,6 @@ static int ax_spi_probe(struct platform_device *pdev) + + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + +- pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + + ctlr->mem_ops = &ax_spi_mem_ops; +-- +2.53.0 + diff --git a/queue-7.0/spi-axiado-replace-usleep_range-with-udelay-in-irq-p.patch b/queue-7.0/spi-axiado-replace-usleep_range-with-udelay-in-irq-p.patch new file mode 100644 index 0000000000..31a3f7b5d7 --- /dev/null +++ b/queue-7.0/spi-axiado-replace-usleep_range-with-udelay-in-irq-p.patch @@ -0,0 +1,38 @@ +From 83d92df8240b625e704ed8bf18ee2918673d3868 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Apr 2026 00:33:04 +0800 +Subject: spi: axiado: replace usleep_range() with udelay() in IRQ path + +From: Felix Gu + +[ Upstream commit f5c6a272b699b9a0698535e1a56e683207e50030 ] + +ax_spi_fill_tx_fifo() can be called from ax_spi_irq() which is a hard +irq handler. Replace usleep_range(10, 10) with udelay(10) in atomic +context. + +Fixes: e75a6b00ad79 ("spi: axiado: Add driver for Axiado SPI DB controller") +Signed-off-by: Felix Gu +Link: https://patch.msgid.link/20260428-axiado-v1-1-cd767500af72@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-axiado.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-axiado.c b/drivers/spi/spi-axiado.c +index dc55c55ae63c8..2cefc8917b710 100644 +--- a/drivers/spi/spi-axiado.c ++++ b/drivers/spi/spi-axiado.c +@@ -201,7 +201,7 @@ static void ax_spi_fill_tx_fifo(struct ax_spi *xspi) + * then spi control did't work thoroughly, add one byte delay + */ + if (ax_spi_read(xspi, AX_SPI_IVR) & AX_SPI_IVR_TFOV) +- usleep_range(10, 10); ++ udelay(10); + if (xspi->tx_buf) + ax_spi_write_b(xspi, AX_SPI_TXFIFO, *xspi->tx_buf++); + else +-- +2.53.0 + diff --git a/queue-7.0/spi-cadence-qspi-revert-the-filtering-of-certain-opc.patch b/queue-7.0/spi-cadence-qspi-revert-the-filtering-of-certain-opc.patch new file mode 100644 index 0000000000..c30d27a944 --- /dev/null +++ b/queue-7.0/spi-cadence-qspi-revert-the-filtering-of-certain-opc.patch @@ -0,0 +1,51 @@ +From ec3cb9e9f4859141cd09c2364639f470f9ee4415 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:41:01 +0200 +Subject: spi: cadence-qspi: Revert the filtering of certain opcodes in ODTR + +From: Miquel Raynal + +[ Upstream commit 5e75c1d4d386fb7d64e2b19355e4d38dd4fd8845 ] + +I got mislead while analyzing the driver by the fact that the second +opcode byte was in all cases smashed: + + if (op->cmd.dtr) + opcode = op->cmd.opcode >> 8; + else + opcode = op->cmd.opcode; + +While at a first glance this doesn't let a chance to the second byte to +be shifted out on the bus, this is actually the second step of an +initialization, where the byte being apparently "ignored" in DTR mode +has already been written in a dedicated "extended opcode" register. As +such, the comment and the extra check that I proposed were entirely +wrong, remove them. + +Fixes: bee085476d27 ("spi: cadence-qspi: Make sure we filter out unsupported ops") +Signed-off-by: Miquel Raynal +Link: https://patch.msgid.link/20260410-winbond-6-19-rc1-oddr-v1-1-2ac4827a3868@bootlin.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-cadence-quadspi.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c +index 1b0d6186c7efa..057381e56a7fd 100644 +--- a/drivers/spi/spi-cadence-quadspi.c ++++ b/drivers/spi/spi-cadence-quadspi.c +@@ -1544,10 +1544,6 @@ static bool cqspi_supports_mem_op(struct spi_mem *mem, + if (op->data.nbytes && op->data.buswidth != 8) + return false; + +- /* A single opcode is supported, it will be repeated */ +- if ((op->cmd.opcode >> 8) != (op->cmd.opcode & 0xFF)) +- return false; +- + if (cqspi->is_rzn1) + return false; + } else if (!all_false) { +-- +2.53.0 + diff --git a/queue-7.0/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch b/queue-7.0/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..7798a0d05d --- /dev/null +++ b/queue-7.0/spi-fsl-qspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 425f10a902833a4da071abcdc4c372fdb8a823e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:21 +0800 +Subject: spi: fsl-qspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 981b080a79724738882b0af1c5bb7ade30d94f24 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks could +get "lost" - use reinit_completion() in that case, but be aware of +other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: 84d043185dbe ("spi: Add a driver for the Freescale/NXP QuadSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-3-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-fsl-qspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c +index a223b4bc6e637..57358851029ba 100644 +--- a/drivers/spi/spi-fsl-qspi.c ++++ b/drivers/spi/spi-fsl-qspi.c +@@ -633,7 +633,7 @@ static int fsl_qspi_do_op(struct fsl_qspi *q, const struct spi_mem_op *op) + void __iomem *base = q->iobase; + int err = 0; + +- init_completion(&q->c); ++ reinit_completion(&q->c); + + /* + * Always start the sequence at the same index since we update +@@ -965,6 +965,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) + if (ret < 0) + return ret; + ++ init_completion(&q->c); + ret = devm_request_irq(dev, ret, + fsl_qspi_irq_handler, 0, pdev->name, q); + if (ret) { +-- +2.53.0 + diff --git a/queue-7.0/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch b/queue-7.0/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch new file mode 100644 index 0000000000..74660c1c8a --- /dev/null +++ b/queue-7.0/spi-hisi-kunpeng-prevent-infinite-while-loop-in-hisi.patch @@ -0,0 +1,55 @@ +From 5a188d1c750fa4f340a33419935992187d1732d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 11:06:41 +0800 +Subject: spi: hisi-kunpeng: prevent infinite while() loop in + hisi_spi_flush_fifo + +From: Pei Xiao + +[ Upstream commit 9f61daf2c2debe9f5cf4e1a4471e56a89a6fe45a ] + +The hisi_spi_flush_fifo()'s inner while loop that lacks any timeout +mechanism. Maybe the hardware never becomes empty, the loop will spin +forever, causing the CPU to hang. + +Fix this by adding a inner_limit based on loops_per_jiffy. The inner loop +now exits after approximately one jiffy if the FIFO remains non-empty, logs +a ratelimited warning, and breaks out of the outer loop. Additionally, add +a cpu_relax() inside the busy loop to improve power efficiency. + +Fixes: c770d8631e18 ("spi: Add HiSilicon SPI Controller Driver for Kunpeng SoCs") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/d834ce28172886bfaeb9c8ca00cfd9bf1c65d5a1.1773889292.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-hisi-kunpeng.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c +index 216a0a91fc47d..c42d2a2cdf1e4 100644 +--- a/drivers/spi/spi-hisi-kunpeng.c ++++ b/drivers/spi/spi-hisi-kunpeng.c +@@ -196,8 +196,18 @@ static void hisi_spi_flush_fifo(struct hisi_spi *hs) + unsigned long limit = loops_per_jiffy << 1; + + do { +- while (hisi_spi_rx_not_empty(hs)) ++ unsigned long inner_limit = loops_per_jiffy; ++ ++ while (hisi_spi_rx_not_empty(hs) && --inner_limit) { + readl(hs->regs + HISI_SPI_DOUT); ++ cpu_relax(); ++ } ++ ++ if (!inner_limit) { ++ dev_warn_ratelimited(hs->dev, "RX FIFO flush timeout\n"); ++ break; ++ } ++ + } while (hisi_spi_busy(hs) && limit--); + } + +-- +2.53.0 + diff --git a/queue-7.0/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch b/queue-7.0/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch new file mode 100644 index 0000000000..7af7e491a0 --- /dev/null +++ b/queue-7.0/spi-mtk-snfi-unregister-ecc-engine-on-probe-failure-.patch @@ -0,0 +1,60 @@ +From c955f8922a99a015a54a4aeaa165c974dafe031f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Apr 2026 15:26:59 +0800 +Subject: spi: mtk-snfi: unregister ECC engine on probe failure and remove() + callback + +From: Pei Xiao + +[ Upstream commit ab00febad191d7a4400aa1c3468279fb508258d4 ] + +mtk_snand_probe() registers the on-host NAND ECC engine, but teardown was +missing from both probe unwind and remove-time cleanup. Add a devm cleanup +action after successful registration so +nand_ecc_unregister_on_host_hw_engine() runs automatically on probe +failures and during device removal. + +Fixes: 764f1b748164 ("spi: add driver for MTK SPI NAND Flash Interface") +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/20263f885f1a9c9d559f95275298cd6de4b11ed5.1775546401.git.xiaopei01@kylinos.cn +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-mtk-snfi.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c +index 437edbd658aa2..73fa84475f0e4 100644 +--- a/drivers/spi/spi-mtk-snfi.c ++++ b/drivers/spi/spi-mtk-snfi.c +@@ -1303,6 +1303,13 @@ static const struct spi_controller_mem_caps mtk_snand_mem_caps = { + .ecc = true, + }; + ++static void mtk_unregister_ecc_engine(void *data) ++{ ++ struct nand_ecc_engine *eng = data; ++ ++ nand_ecc_unregister_on_host_hw_engine(eng); ++} ++ + static irqreturn_t mtk_snand_irq(int irq, void *id) + { + struct mtk_snand *snf = id; +@@ -1443,6 +1450,13 @@ static int mtk_snand_probe(struct platform_device *pdev) + goto release_ecc; + } + ++ ret = devm_add_action_or_reset(&pdev->dev, mtk_unregister_ecc_engine, ++ &ms->ecc_eng); ++ if (ret) { ++ dev_err_probe(&pdev->dev, ret, "failed to add ECC unregister action\n"); ++ goto release_ecc; ++ } ++ + ctlr->num_chipselect = 1; + ctlr->mem_ops = &mtk_snand_mem_ops; + ctlr->mem_caps = &mtk_snand_mem_caps; +-- +2.53.0 + diff --git a/queue-7.0/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch b/queue-7.0/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..b989a1fd92 --- /dev/null +++ b/queue-7.0/spi-nxp-fspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 3b6237de29c15a4111b707289601286341a66398 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:20 +0800 +Subject: spi: nxp-fspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 68c8c93fdb0de7e528dc3dfb1d17eb0f652259b8 ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks +could get "lost" - use reinit_completion() in that case, but be +aware of other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: a5356aef6a90 ("spi: spi-mem: Add driver for NXP FlexSPI controller") +Signed-off-by: Felix Gu +Reviewed-by: Haibo Chen +Link: https://patch.msgid.link/20260304-spi-nxp-v2-2-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-nxp-fspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c +index 320b3d93df571..1e36ae084dd86 100644 +--- a/drivers/spi/spi-nxp-fspi.c ++++ b/drivers/spi/spi-nxp-fspi.c +@@ -996,7 +996,7 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op) + reg = reg | FSPI_IPRXFCR_CLR; + fspi_writel(f, reg, base + FSPI_IPRXFCR); + +- init_completion(&f->c); ++ reinit_completion(&f->c); + + fspi_writel(f, op->addr.val, base + FSPI_IPCR0); + /* +@@ -1365,6 +1365,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to disable clock"); + ++ init_completion(&f->c); + ret = devm_request_irq(dev, irq, + nxp_fspi_irq_handler, 0, pdev->name, f); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/spi-nxp-xspi-use-reinit_completion-for-repeated-oper.patch b/queue-7.0/spi-nxp-xspi-use-reinit_completion-for-repeated-oper.patch new file mode 100644 index 0000000000..5c7e681559 --- /dev/null +++ b/queue-7.0/spi-nxp-xspi-use-reinit_completion-for-repeated-oper.patch @@ -0,0 +1,55 @@ +From 09cdc9b4ce036db0b303bff3844b336769e5f878 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Mar 2026 20:47:19 +0800 +Subject: spi: nxp-xspi: Use reinit_completion() for repeated operations + +From: Felix Gu + +[ Upstream commit 40f9bc646db5aa89fb85f2cda1e55a2bf9d6a30c ] + +The driver currently calls init_completion() during every spi_mem_op. +Tchnically it may work, but it's not the recommended pattern. + +According to the kernel documentation: Calling init_completion() on +the same completion object twice is most likely a bug as it +re-initializes the queue to an empty queue and enqueued tasks +could get "lost" - use reinit_completion() in that case, but be +aware of other races. + +So moves the initial initialization to probe function and uses +reinit_completion() for subsequent operations. + +Fixes: 29c8c00d9f9d ("spi: add driver for NXP XSPI controller") +Reviewed-by: Haibo Chen +Signed-off-by: Felix Gu +Link: https://patch.msgid.link/20260304-spi-nxp-v2-1-cd7d7726a27e@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-nxp-xspi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-nxp-xspi.c b/drivers/spi/spi-nxp-xspi.c +index 06fcdf22990b8..385302a6e62f2 100644 +--- a/drivers/spi/spi-nxp-xspi.c ++++ b/drivers/spi/spi-nxp-xspi.c +@@ -958,7 +958,7 @@ static int nxp_xspi_do_op(struct nxp_xspi *xspi, const struct spi_mem_op *op) + writel(reg, base + XSPI_RBCT); + } + +- init_completion(&xspi->c); ++ reinit_completion(&xspi->c); + + /* Config the data address */ + writel(op->addr.val + xspi->memmap_phy, base + XSPI_SFP_TG_SFAR); +@@ -1273,6 +1273,7 @@ static int nxp_xspi_probe(struct platform_device *pdev) + + nxp_xspi_default_setup(xspi); + ++ init_completion(&xspi->c); + ret = devm_request_irq(dev, irq, + nxp_xspi_irq_handler, 0, pdev->name, xspi); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch b/queue-7.0/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch new file mode 100644 index 0000000000..1894160987 --- /dev/null +++ b/queue-7.0/spi-rockchip-read-isr-not-imr-to-detect-cs-inactive-.patch @@ -0,0 +1,61 @@ +From e105cb857364577868d8d443d787ce8e9bb0a1a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 09:29:34 +0000 +Subject: spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ + +From: John Madieu + +[ Upstream commit b4683a239a409d65f88052f5630c748a8ba070cd ] + +rockchip_spi_isr() decides whether the current interrupt was the +cs-inactive event by reading IMR: + + if (rs->cs_inactive && + readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) + ctlr->target_abort(ctlr); + +IMR is the interrupt mask register: it tells which sources are enabled, +not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables +both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true: + + if (rs->cs_inactive) + writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, + rs->regs + ROCKCHIP_SPI_IMR); + +so the IMR check is always true once cs_inactive is enabled, and every +PIO interrupt - including normal RF_FULL completions - is dispatched to +ctlr->target_abort(), aborting the transfer. The bug is reachable on +ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller +when the transfer is short enough to fall back to PIO +(rockchip_spi_can_dma() returns false below fifo_len). + +Read ISR (which is RISR masked by IMR) so the check actually reflects +which interrupt fired, and parenthesise the expression for clarity while +at it. + +Fixes: 869f2c94db92 ("spi: rockchip: Stop spi slave dma receiver when cs inactive") +Signed-off-by: John Madieu +Link: https://patch.msgid.link/20260425092936.2590132-2-john.madieu@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rockchip.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c +index eb1992b4178e2..2eb9ede8cc909 100644 +--- a/drivers/spi/spi-rockchip.c ++++ b/drivers/spi/spi-rockchip.c +@@ -357,7 +357,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id) + struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); + + /* When int_cs_inactive comes, spi target abort */ +- if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) { ++ if (rs->cs_inactive && ++ (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) { + ctlr->target_abort(ctlr); + writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR); + writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR); +-- +2.53.0 + diff --git a/queue-7.0/spi-rzv2h-rspi-fix-invalid-spr-0-brdv-0-clock-config.patch b/queue-7.0/spi-rzv2h-rspi-fix-invalid-spr-0-brdv-0-clock-config.patch new file mode 100644 index 0000000000..cec5690b7e --- /dev/null +++ b/queue-7.0/spi-rzv2h-rspi-fix-invalid-spr-0-brdv-0-clock-config.patch @@ -0,0 +1,89 @@ +From 2ef8868edea8a440cf536654bbb59f90c1d38c2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 09:05:16 +0100 +Subject: spi: rzv2h-rspi: Fix invalid SPR=0/BRDV=0 clock configuration + +From: Lad Prabhakar + +[ Upstream commit 0335767dd8e7ade8a8e3028d08c4621515d47388 ] + +The combination of SPR=0 and BRDV=0 results in the minimum division +ratio of 2, producing the maximum possible bit rate for a given clock +source. This combination is not supported in two cases: + +- On RZ/G3E, RZ/G3L, RZ/V2H(P) and RZ/V2N, RSPI_n_TCLK is fixed at + 200MHz, which would yield 100Mbps. The next hardware manual update + will explicitly state that since the maximum frequency of the + RSPICKn clock signal is 50MHz, settings with N=0 and n=0 resulting + in 100Mbps are prohibited. + +- On RZ/T2H and RZ/N2H, when PCLK (125MHz) is used as the clock + source, SPR=0 and BRDV=0 is explicitly listed as unsupported in + the hardware manual (Table 36.7). + +Skip the SPR=0/BRDV=0 combination in rzv2h_rspi_find_rate_fixed() to +prevent the driver from selecting an invalid clock configuration on the +affected SoCs. + +Additionally, remove the now redundant RSPI_SPBR_SPR_PCLK_MIN define +which was previously set to 1 to work around the PCLK restriction, but +was overly broad as it incorrectly blocked valid combinations such as +SPR=0/BRDV=1 (31.25Mbps on PCLK=125MHz). + +Fixes: 8b61c8919dff ("spi: Add driver for the RZ/V2H(P) RSPI IP") +Fixes: 1ce3e8adc7d0 ("spi: rzv2h-rspi: add support for using PCLK for transfer clock") +Signed-off-by: Lad Prabhakar +Link: https://patch.msgid.link/20260410080517.2405700-3-prabhakar.mahadev-lad.rj@bp.renesas.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rzv2h-rspi.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c +index 23f0e92ae208e..d6b9b558932dd 100644 +--- a/drivers/spi/spi-rzv2h-rspi.c ++++ b/drivers/spi/spi-rzv2h-rspi.c +@@ -50,7 +50,6 @@ + + /* Register SPBR */ + #define RSPI_SPBR_SPR_MIN 0 +-#define RSPI_SPBR_SPR_PCLK_MIN 1 + #define RSPI_SPBR_SPR_MAX 255 + + /* Register SPCMD */ +@@ -533,6 +532,17 @@ static void rzv2h_rspi_find_rate_fixed(struct clk *clk, u32 hz, + for (brdv = RSPI_SPCMD_BRDV_MIN; brdv <= RSPI_SPCMD_BRDV_MAX; brdv++) { + spr = DIV_ROUND_UP(clk_rate, hz * (1 << (brdv + 1))); + spr--; ++ /* ++ * Skip SPR=0 and BRDV=0 as it is not a valid combination: ++ * - On RZ/G3E, RZ/G3L, RZ/V2H(P) and RZ/V2N, RSPI_n_TCLK is ++ * fixed at 200MHz and SPR=0 and BRDV=0 results in the maximum ++ * bit rate of 100Mbps which is prohibited. ++ * - On RZ/T2H and RZ/N2H, when PCLK (125MHz) is used as ++ * the clock source, SPR=0 and BRDV=0 is explicitly listed ++ * as unsupported in the hardware manual (Table 36.7). ++ */ ++ if (!spr && !brdv) ++ continue; + if (spr >= spr_min && spr <= spr_max) + goto clock_found; + } +@@ -566,12 +576,8 @@ static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz) + rspi->info->find_tclk_rate(rspi->tclk, hz, RSPI_SPBR_SPR_MIN, + RSPI_SPBR_SPR_MAX, &best_clock); + +- /* +- * T2H and N2H can also use PCLK as a source, which is 125MHz, but not +- * when both SPR and BRDV are 0. +- */ + if (best_clock.error && rspi->info->find_pclk_rate) +- rspi->info->find_pclk_rate(rspi->pclk, hz, RSPI_SPBR_SPR_PCLK_MIN, ++ rspi->info->find_pclk_rate(rspi->pclk, hz, RSPI_SPBR_SPR_MIN, + RSPI_SPBR_SPR_MAX, &best_clock); + + if (!best_clock.clk_rate) +-- +2.53.0 + diff --git a/queue-7.0/spi-rzv2h-rspi-fix-silent-failure-in-clock-setup-err.patch b/queue-7.0/spi-rzv2h-rspi-fix-silent-failure-in-clock-setup-err.patch new file mode 100644 index 0000000000..e70d05e34f --- /dev/null +++ b/queue-7.0/spi-rzv2h-rspi-fix-silent-failure-in-clock-setup-err.patch @@ -0,0 +1,52 @@ +From 5641914b5e63a9b4c3024d099c41a62dabe8131d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Apr 2026 02:47:25 +0000 +Subject: spi: rzv2h-rspi: Fix silent failure in clock setup error path + +From: John Madieu + +[ Upstream commit 54900126ae0a2671f8790a7f95706b9ea95fac4e ] + +rzv2h_rspi_setup_clock() is declared to return u32 but returns -EINVAL +when no valid clock parameters are found. Cast to u32, -EINVAL becomes +0xffffffea, which is a non-zero value. The caller in +rzv2h_rspi_prepare_message() guards against failure with: + + rspi->freq = rzv2h_rspi_setup_clock(rspi, speed_hz); + if (!rspi->freq) + return -EINVAL; + +Because 0xffffffea is non-zero, the check is bypassed and the controller +proceeds to program SPBR/SPCMD with stale values, leading to an unknown +bit rate. + +Return 0 on the failed-search path, consistent with the existing +clk_set_rate() failure path which already returns 0. + +Fixes: 77d931584dd3 ("spi: rzv2h-rspi: make transfer clock rate finding chip-specific") +Signed-off-by: John Madieu +Reviewed-by: Biju Das +Reviewed-by: Cosmin Tanislav +Link: https://patch.msgid.link/20260425024725.2393632-1-john.madieu.xa@bp.renesas.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-rzv2h-rspi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c +index d6b9b558932dd..53c44799fab71 100644 +--- a/drivers/spi/spi-rzv2h-rspi.c ++++ b/drivers/spi/spi-rzv2h-rspi.c +@@ -581,7 +581,7 @@ static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz) + RSPI_SPBR_SPR_MAX, &best_clock); + + if (!best_clock.clk_rate) +- return -EINVAL; ++ return 0; + + ret = clk_set_rate(best_clock.clk, best_clock.clk_rate); + if (ret) +-- +2.53.0 + diff --git a/queue-7.0/spi-spi-mem-add-a-packed-command-operation.patch b/queue-7.0/spi-spi-mem-add-a-packed-command-operation.patch new file mode 100644 index 0000000000..be7133fea5 --- /dev/null +++ b/queue-7.0/spi-spi-mem-add-a-packed-command-operation.patch @@ -0,0 +1,45 @@ +From 95ee0841a0726ed7a5d1446e65f4a135302c5167 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 19:41:02 +0200 +Subject: spi: spi-mem: Add a packed command operation + +From: Miquel Raynal + +[ Upstream commit f79ee9e4b23244e77b28d176ce99a2d84d813ac5 ] + +Instead of repeating the command opcode twice, some flash devices try to +pack command and address bits. In this case, the second opcode byte +being sent (LSB) is free to be used. The input data must be ANDed to +only provide the relevant bits. + +Signed-off-by: Miquel Raynal +Link: https://patch.msgid.link/20260410-winbond-6-19-rc1-oddr-v1-2-2ac4827a3868@bootlin.com +Signed-off-by: Mark Brown +Stable-dep-of: 8d655748aba1 ("mtd: spinand: winbond: Set the packed page read flag to W35N02/04JW") +Signed-off-by: Sasha Levin +--- + include/linux/spi/spi-mem.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h +index 5774e554c0f02..f54c708f4c506 100644 +--- a/include/linux/spi/spi-mem.h ++++ b/include/linux/spi/spi-mem.h +@@ -28,6 +28,14 @@ + .dtr = true, \ + } + ++#define SPI_MEM_DTR_OP_PACKED_CMD(__opcode, __addr, __buswidth) \ ++ { \ ++ .nbytes = 2, \ ++ .opcode = __opcode << 8 | __addr, \ ++ .buswidth = __buswidth, \ ++ .dtr = true, \ ++ } ++ + #define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth) \ + { \ + .nbytes = __nbytes, \ +-- +2.53.0 + diff --git a/queue-7.0/stop_machine-fix-the-documentation-for-a-null-cpus-a.patch b/queue-7.0/stop_machine-fix-the-documentation-for-a-null-cpus-a.patch new file mode 100644 index 0000000000..31c1bb1c74 --- /dev/null +++ b/queue-7.0/stop_machine-fix-the-documentation-for-a-null-cpus-a.patch @@ -0,0 +1,55 @@ +From d23a8ddfe029ffad49ae2a22ebde8b392d041f1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Feb 2026 14:11:11 +0100 +Subject: stop_machine: Fix the documentation for a NULL cpus argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 48f7a50c027dd2abb9e7b8a6ecc8e531d87f2c21 ] + +A recent refactoring of the kernel-docs for stop machine changed the +description of the cpus parameter from "NULL = any online cpu" +to "NULL = run on each online CPU". + +However the callback is only executed on a single CPU, not all of them. +The old wording was a bit ambiguous and could have been read both ways. + +Reword the documentation to be correct again and hopefully also clearer. + +Fixes: fc6f89dc7078 ("stop_machine: Improve kernel-doc function-header comments") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Paul E. McKenney +Reviewed-by: Sebastian Andrzej Siewior +Signed-off-by: Sasha Levin +--- + include/linux/stop_machine.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h +index 72820503514cc..01011113d2263 100644 +--- a/include/linux/stop_machine.h ++++ b/include/linux/stop_machine.h +@@ -99,7 +99,7 @@ static inline void print_stop_info(const char *log_lvl, struct task_struct *task + * stop_machine: freeze the machine on all CPUs and run this function + * @fn: the function to run + * @data: the data ptr to pass to @fn() +- * @cpus: the cpus to run @fn() on (NULL = run on each online CPU) ++ * @cpus: the cpus to run @fn() on (NULL = one unspecified online CPU) + * + * Description: This causes a thread to be scheduled on every CPU, which + * will run with interrupts disabled. Each CPU specified by @cpus will +@@ -133,7 +133,7 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); + * stop_machine_cpuslocked: freeze the machine on all CPUs and run this function + * @fn: the function to run + * @data: the data ptr to pass to @fn() +- * @cpus: the cpus to run @fn() on (NULL = run on each online CPU) ++ * @cpus: the cpus to run @fn() on (NULL = one unspecified online CPU) + * + * Same as above. Avoids nested calls to cpus_read_lock(). + * +-- +2.53.0 + diff --git a/queue-7.0/sunrpc-fix-compilation-error-make-w-1-when-dprintk-i.patch b/queue-7.0/sunrpc-fix-compilation-error-make-w-1-when-dprintk-i.patch new file mode 100644 index 0000000000..df171022b5 --- /dev/null +++ b/queue-7.0/sunrpc-fix-compilation-error-make-w-1-when-dprintk-i.patch @@ -0,0 +1,97 @@ +From 37d3b3cd16061f3a2e645d5205553fcacc01ee88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:51 +0100 +Subject: sunrpc: Fix compilation error (`make W=1`) when dprintk() is no-op + +From: Andy Shevchenko + +[ Upstream commit 6f57293abb8d087de830dd3f02e66d94b3e59973 ] + +Clang compiler is not happy about set but unused variables: + +.../flexfilelayout/flexfilelayoutdev.c:56:9: error: variable 'ret' set but not used [-Werror,-Wunused-but-set-variable] +.../flexfilelayout/flexfilelayout.c:1505:6: error: variable 'err' set but not used [-Werror,-Wunused-but-set-variable] +.../nfs4proc.c:9244:12: error: variable 'ptr' set but not used [-Werror,-Wunused-but-set-variable] + +Fix these by forwarding parameters of dprintk() to no_printk(). +The positive side-effect is a format-string checker enabled even for the cases +when dprintk() is no-op. + +Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver") +Fixes: fc931582c260 ("nfs41: create_session operation") +Acked-by: Geert Uytterhoeven +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svclock.c | 5 +++++ + include/linux/sunrpc/debug.h | 8 ++++++-- + include/linux/sunrpc/sched.h | 3 --- + 3 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index 255a847ca0b6b..abc65dc79f854 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -80,6 +80,11 @@ static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) + + return buf; + } ++#else ++static inline const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) ++{ ++ return "???"; ++} + #endif + + /* +diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h +index 93d1a11ffbfb3..ab61bed2f7afc 100644 +--- a/include/linux/sunrpc/debug.h ++++ b/include/linux/sunrpc/debug.h +@@ -38,6 +38,8 @@ extern unsigned int nlm_debug; + do { \ + ifdebug(fac) \ + __sunrpc_printk(fmt, ##__VA_ARGS__); \ ++ else \ ++ no_printk(fmt, ##__VA_ARGS__); \ + } while (0) + + # define dfprintk_rcu(fac, fmt, ...) \ +@@ -46,13 +48,15 @@ do { \ + rcu_read_lock(); \ + __sunrpc_printk(fmt, ##__VA_ARGS__); \ + rcu_read_unlock(); \ ++ } else { \ ++ no_printk(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + + #else + # define ifdebug(fac) if (0) +-# define dfprintk(fac, fmt, ...) do {} while (0) +-# define dfprintk_rcu(fac, fmt, ...) do {} while (0) ++# define dfprintk(fac, fmt, ...) no_printk(fmt, ##__VA_ARGS__) ++# define dfprintk_rcu(fac, fmt, ...) no_printk(fmt, ##__VA_ARGS__) + #endif + + /* +diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h +index ccba79ebf8932..0dbdf3722537f 100644 +--- a/include/linux/sunrpc/sched.h ++++ b/include/linux/sunrpc/sched.h +@@ -95,10 +95,7 @@ struct rpc_task { + int tk_rpc_status; /* Result of last RPC operation */ + unsigned short tk_flags; /* misc flags */ + unsigned short tk_timeouts; /* maj timeouts */ +- +-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) + unsigned short tk_pid; /* debugging aid */ +-#endif + unsigned char tk_priority : 2,/* Task priority */ + tk_garb_retry : 2, + tk_cred_retry : 2; +-- +2.53.0 + diff --git a/queue-7.0/sunrpc-kill-rpc_ifdebug.patch b/queue-7.0/sunrpc-kill-rpc_ifdebug.patch new file mode 100644 index 0000000000..f65e6692cf --- /dev/null +++ b/queue-7.0/sunrpc-kill-rpc_ifdebug.patch @@ -0,0 +1,112 @@ +From 3e4ccf6294022071315f6e9e66c7b53fd8dfacd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 21:21:50 +0100 +Subject: sunrpc: Kill RPC_IFDEBUG() + +From: Andy Shevchenko + +[ Upstream commit adcc59114ccd402259c089b0fea24da5e4974563 ] + +RPC_IFDEBUG() is used in only two places. In one the user of +the definition is guarded by ifdeffery, in the second one +it's implied due to dprintk() usage. Kill the macro and move +the ifdeffery to the regular condition with the variable defined +inside, while in the second case add the same conditional and +move the respective code there. + +Reviewed-by: Jeff Layton +Signed-off-by: Andy Shevchenko +Signed-off-by: Chuck Lever +Stable-dep-of: 6f57293abb8d ("sunrpc: Fix compilation error (`make W=1`) when dprintk() is no-op") +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsfh.c | 9 +++++--- + include/linux/sunrpc/debug.h | 2 -- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 27 ++++++++++++------------ + 3 files changed, 20 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index ed85dd43da18e..68b629fbaaeb9 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -105,9 +105,12 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, + { + /* Check if the request originated from a secure port. */ + if (rqstp && !nfsd_originating_port_ok(rqstp, cred, exp)) { +- RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); +- dprintk("nfsd: request from insecure port %s!\n", +- svc_print_addr(rqstp, buf, sizeof(buf))); ++ if (IS_ENABLED(CONFIG_SUNRPC_DEBUG)) { ++ char buf[RPC_MAX_ADDRBUFLEN]; ++ ++ dprintk("nfsd: request from insecure port %s!\n", ++ svc_print_addr(rqstp, buf, sizeof(buf))); ++ } + return nfserr_perm; + } + +diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h +index eb4bd62df3190..93d1a11ffbfb3 100644 +--- a/include/linux/sunrpc/debug.h ++++ b/include/linux/sunrpc/debug.h +@@ -49,12 +49,10 @@ do { \ + } \ + } while (0) + +-# define RPC_IFDEBUG(x) x + #else + # define ifdebug(fac) if (0) + # define dfprintk(fac, fmt, ...) do {} while (0) + # define dfprintk_rcu(fac, fmt, ...) do {} while (0) +-# define RPC_IFDEBUG(x) + #endif + + /* +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 9b623849723ed..f2d72181a6fe8 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -414,7 +414,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + struct ib_qp_init_attr qp_attr; + struct ib_device *dev; + int ret = 0; +- RPC_IFDEBUG(struct sockaddr *sap); + + listen_rdma = container_of(xprt, struct svcxprt_rdma, sc_xprt); + clear_bit(XPT_CONN, &xprt->xpt_flags); +@@ -560,18 +559,20 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) + goto errout; + } + +-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) +- dprintk("svcrdma: new connection accepted on device %s:\n", dev->name); +- sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr; +- dprintk(" local address : %pIS:%u\n", sap, rpc_get_port(sap)); +- sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr; +- dprintk(" remote address : %pIS:%u\n", sap, rpc_get_port(sap)); +- dprintk(" max_sge : %d\n", newxprt->sc_max_send_sges); +- dprintk(" sq_depth : %d\n", newxprt->sc_sq_depth); +- dprintk(" rdma_rw_ctxs : %d\n", ctxts); +- dprintk(" max_requests : %d\n", newxprt->sc_max_requests); +- dprintk(" ord : %d\n", conn_param.initiator_depth); +-#endif ++ if (IS_ENABLED(CONFIG_SUNRPC_DEBUG)) { ++ struct sockaddr *sap; ++ ++ dprintk("svcrdma: new connection accepted on device %s:\n", dev->name); ++ sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr; ++ dprintk(" local address : %pIS:%u\n", sap, rpc_get_port(sap)); ++ sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr; ++ dprintk(" remote address : %pIS:%u\n", sap, rpc_get_port(sap)); ++ dprintk(" max_sge : %d\n", newxprt->sc_max_send_sges); ++ dprintk(" sq_depth : %d\n", newxprt->sc_sq_depth); ++ dprintk(" rdma_rw_ctxs : %d\n", ctxts); ++ dprintk(" max_requests : %d\n", newxprt->sc_max_requests); ++ dprintk(" ord : %d\n", conn_param.initiator_depth); ++ } + + return &newxprt->sc_xprt; + +-- +2.53.0 + diff --git a/queue-7.0/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch b/queue-7.0/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch new file mode 100644 index 0000000000..72cdb8fd7d --- /dev/null +++ b/queue-7.0/tcp-add-data-race-annotations-around-tp-data_segs_ou.patch @@ -0,0 +1,75 @@ +From e294ca04ec4de11016f54bfd0f160d3bb6135962 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:07 +0000 +Subject: tcp: add data-race annotations around tp->data_segs_out and + tp->total_retrans + +From: Eric Dumazet + +[ Upstream commit 21e92a38cfd891538598ba8f805e0165a820d532 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e98102f4897 ("tcp: record pkts sent and retransmistted") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 8 +++++--- + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index a8ff76c40f79b..d1953c6376f8b 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4468,9 +4468,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u64_64bit(stats, TCP_NLA_SNDBUF_LIMITED, + info.tcpi_sndbuf_limited, TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_DATA_SEGS_OUT, +- tp->data_segs_out, TCP_NLA_PAD); ++ READ_ONCE(tp->data_segs_out), TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_TOTAL_RETRANS, +- tp->total_retrans, TCP_NLA_PAD); ++ READ_ONCE(tp->total_retrans), TCP_NLA_PAD); + + rate = READ_ONCE(sk->sk_pacing_rate); + rate64 = (rate != ~0UL) ? rate : ~0ULL; +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 7b8a2c8213e18..87fa26603276c 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1668,7 +1668,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + + if (skb->len != tcp_header_size) { + tcp_event_data_sent(tp, sk); +- tp->data_segs_out += tcp_skb_pcount(skb); ++ WRITE_ONCE(tp->data_segs_out, ++ tp->data_segs_out + tcp_skb_pcount(skb)); + tp->bytes_sent += skb->len - tcp_header_size; + } + +@@ -3624,7 +3625,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs); + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); +- tp->total_retrans += segs; ++ WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); + tp->bytes_retrans += skb->len; + + /* make sure skb->data is aligned on arches that require it +@@ -4628,7 +4629,8 @@ int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) + * However in this case, we are dealing with a passive fastopen + * socket thus we can change total_retrans value. + */ +- tcp_sk_rw(sk)->total_retrans++; ++ WRITE_ONCE(tcp_sk_rw(sk)->total_retrans, ++ tcp_sk_rw(sk)->total_retrans + 1); + } + trace_tcp_retransmit_synack(sk, req); + WRITE_ONCE(req->num_retrans, req->num_retrans + 1); +-- +2.53.0 + diff --git a/queue-7.0/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch b/queue-7.0/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch new file mode 100644 index 0000000000..f0bd4bb187 --- /dev/null +++ b/queue-7.0/tcp-add-data-race-annotations-for-tcp_nla_sndq_size.patch @@ -0,0 +1,76 @@ +From e39a5ab44ac67d460b3138a94970521b178043fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:11 +0000 +Subject: tcp: add data-race annotations for TCP_NLA_SNDQ_SIZE + +From: Eric Dumazet + +[ Upstream commit 124199444de467767175a9004e1574dc42523e62 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 87ecc95d81d9 ("tcp: add send queue size stat in SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-7-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 +++- + net/ipv4/tcp_input.c | 4 ++-- + net/ipv4/tcp_output.c | 2 +- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index ee50b2d3ed976..75164510b4232 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4490,7 +4490,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_DELIVERED, READ_ONCE(tp->delivered)); + nla_put_u32(stats, TCP_NLA_DELIVERED_CE, READ_ONCE(tp->delivered_ce)); + +- nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); ++ nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una))); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); + + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index f1bb0ad2eead1..b9bd42f9d08b5 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3914,7 +3914,7 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) + sock_owned_by_me((struct sock *)tp); + tp->bytes_acked += delta; + tcp_snd_sne_update(tp, ack); +- tp->snd_una = ack; ++ WRITE_ONCE(tp->snd_una, ack); + } + + static void tcp_rcv_sne_update(struct tcp_sock *tp, u32 seq) +@@ -7297,7 +7297,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) + if (sk->sk_socket) + sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); + +- tp->snd_una = TCP_SKB_CB(skb)->ack_seq; ++ WRITE_ONCE(tp->snd_una, TCP_SKB_CB(skb)->ack_seq); + tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale; + tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); + +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 6603331ec589e..1bb46aafe4049 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -4136,7 +4136,7 @@ static void tcp_connect_init(struct sock *sk) + tp->snd_wnd = 0; + tcp_init_wl(tp, 0); + tcp_write_queue_purge(sk); +- tp->snd_una = tp->write_seq; ++ WRITE_ONCE(tp->snd_una, tp->write_seq); + tp->snd_sml = tp->write_seq; + tp->snd_up = tp->write_seq; + WRITE_ONCE(tp->snd_nxt, tp->write_seq); +-- +2.53.0 + diff --git a/queue-7.0/tcp-add-data-races-annotations-around-tp-reordering-.patch b/queue-7.0/tcp-add-data-races-annotations-around-tp-reordering-.patch new file mode 100644 index 0000000000..568414ca44 --- /dev/null +++ b/queue-7.0/tcp-add-data-races-annotations-around-tp-reordering-.patch @@ -0,0 +1,114 @@ +From 9a1cbfe137aa1cda5ef904b92f1898118b1cc69e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:08 +0000 +Subject: tcp: add data-races annotations around tp->reordering, tp->snd_cwnd + +From: Eric Dumazet + +[ Upstream commit 829ba1f329cb7cbd56d599a6d225997fba66dc32 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE(), WRITE_ONCE() data_race() annotations to keep KCSAN happy. + +Fixes: bb7c19f96012 ("tcp: add related fields into SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-4-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 2 +- + net/ipv4/tcp.c | 8 ++++---- + net/ipv4/tcp_input.c | 14 ++++++++------ + net/ipv4/tcp_metrics.c | 2 +- + 4 files changed, 14 insertions(+), 12 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 1946935388be6..ebc72dce4134d 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1465,7 +1465,7 @@ static inline u32 tcp_snd_cwnd(const struct tcp_sock *tp) + static inline void tcp_snd_cwnd_set(struct tcp_sock *tp, u32 val) + { + WARN_ON_ONCE((int)val <= 0); +- tp->snd_cwnd = val; ++ WRITE_ONCE(tp->snd_cwnd, val); + } + + static inline bool tcp_in_slow_start(const struct tcp_sock *tp) +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index d1953c6376f8b..c3253a810ea6e 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4479,13 +4479,13 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + rate64 = tcp_compute_delivery_rate(tp); + nla_put_u64_64bit(stats, TCP_NLA_DELIVERY_RATE, rate64, TCP_NLA_PAD); + +- nla_put_u32(stats, TCP_NLA_SND_CWND, tcp_snd_cwnd(tp)); +- nla_put_u32(stats, TCP_NLA_REORDERING, tp->reordering); +- nla_put_u32(stats, TCP_NLA_MIN_RTT, tcp_min_rtt(tp)); ++ nla_put_u32(stats, TCP_NLA_SND_CWND, READ_ONCE(tp->snd_cwnd)); ++ nla_put_u32(stats, TCP_NLA_REORDERING, READ_ONCE(tp->reordering)); ++ nla_put_u32(stats, TCP_NLA_MIN_RTT, data_race(tcp_min_rtt(tp))); + + nla_put_u8(stats, TCP_NLA_RECUR_RETRANS, + READ_ONCE(inet_csk(sk)->icsk_retransmits)); +- nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, !!tp->rate_app_limited); ++ nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, data_race(!!tp->rate_app_limited)); + nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, tp->snd_ssthresh); + nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered); + nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index cba89733d1216..891a7f74432bb 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1294,8 +1294,9 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq, + tp->sacked_out, + tp->undo_marker ? tp->undo_retrans : 0); + #endif +- tp->reordering = min_t(u32, (metric + mss - 1) / mss, +- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering)); ++ WRITE_ONCE(tp->reordering, ++ min_t(u32, (metric + mss - 1) / mss, ++ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering))); + } + + /* This exciting event is worth to be remembered. 8) */ +@@ -2440,8 +2441,9 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend) + if (!tcp_limit_reno_sacked(tp)) + return; + +- tp->reordering = min_t(u32, tp->packets_out + addend, +- READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering)); ++ WRITE_ONCE(tp->reordering, ++ min_t(u32, tp->packets_out + addend, ++ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering))); + tp->reord_seen++; + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER); + } +@@ -2580,8 +2582,8 @@ void tcp_enter_loss(struct sock *sk) + reordering = READ_ONCE(net->ipv4.sysctl_tcp_reordering); + if (icsk->icsk_ca_state <= TCP_CA_Disorder && + tp->sacked_out >= reordering) +- tp->reordering = min_t(unsigned int, tp->reordering, +- reordering); ++ WRITE_ONCE(tp->reordering, ++ min_t(unsigned int, tp->reordering, reordering)); + + tcp_set_ca_state(sk, TCP_CA_Loss); + tp->high_seq = tp->snd_nxt; +diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c +index 06b1d5d3b6df7..7a9d6d9006f65 100644 +--- a/net/ipv4/tcp_metrics.c ++++ b/net/ipv4/tcp_metrics.c +@@ -496,7 +496,7 @@ void tcp_init_metrics(struct sock *sk) + } + val = tcp_metric_get(tm, TCP_METRIC_REORDERING); + if (val && tp->reordering != val) +- tp->reordering = val; ++ WRITE_ONCE(tp->reordering, val); + + crtt = tcp_metric_get(tm, TCP_METRIC_RTT); + rcu_read_unlock(); +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-bytes_retrans.patch b/queue-7.0/tcp-annotate-data-races-around-tp-bytes_retrans.patch new file mode 100644 index 0000000000..1a5df2f14a --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-bytes_retrans.patch @@ -0,0 +1,53 @@ +From b1034e1b372ad832c53de869ec58e559956a64bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:13 +0000 +Subject: tcp: annotate data-races around tp->bytes_retrans + +From: Eric Dumazet + +[ Upstream commit 5efc7b9f7cbd43401f1af81d3d7f2be00f93390d ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: fb31c9b9f6c8 ("tcp: add data bytes retransmitted stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-9-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_output.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 10c36a68de4b1..368b576cfe369 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4497,8 +4497,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + + nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, +- TCP_NLA_PAD); ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, ++ READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 2c9ca89aa9e50..51e7f40e7e313 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -3627,7 +3627,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); + WRITE_ONCE(tp->total_retrans, tp->total_retrans + segs); +- tp->bytes_retrans += skb->len; ++ WRITE_ONCE(tp->bytes_retrans, tp->bytes_retrans + skb->len); + + /* make sure skb->data is aligned on arches that require it + * and check if ack-trimming & collapsing extended the headroom +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-bytes_sent.patch b/queue-7.0/tcp-annotate-data-races-around-tp-bytes_sent.patch new file mode 100644 index 0000000000..3672a8dc1c --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-bytes_sent.patch @@ -0,0 +1,52 @@ +From 494ed1dacf29457012153b4fdf95bf529d31820e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:12 +0000 +Subject: tcp: annotate data-races around tp->bytes_sent + +From: Eric Dumazet + +[ Upstream commit ee43e957ce2ec77b2ec47fef28f3c0df6ab01a31 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: ba113c3aa79a ("tcp: add data bytes sent stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-8-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_output.c | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 75164510b4232..10c36a68de4b1 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4495,7 +4495,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una))); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); + +- nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, ++ nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, READ_ONCE(tp->bytes_sent), + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, + TCP_NLA_PAD); +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 1bb46aafe4049..2c9ca89aa9e50 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1670,7 +1670,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, + tcp_event_data_sent(tp, sk); + WRITE_ONCE(tp->data_segs_out, + tp->data_segs_out + tcp_skb_pcount(skb)); +- tp->bytes_sent += skb->len - tcp_header_size; ++ WRITE_ONCE(tp->bytes_sent, ++ tp->bytes_sent + skb->len - tcp_header_size); + } + + if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-delivered-and-tp-d.patch b/queue-7.0/tcp-annotate-data-races-around-tp-delivered-and-tp-d.patch new file mode 100644 index 0000000000..60ef899e26 --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-delivered-and-tp-d.patch @@ -0,0 +1,93 @@ +From 8d9ce41eec76c824a5b3c7acc12609f62c55fb80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:10 +0000 +Subject: tcp: annotate data-races around tp->delivered and tp->delivered_ce + +From: Eric Dumazet + +[ Upstream commit faa886ad3ce5fc8f5156493491fe189b2b726bc9 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: feb5f2ec6464 ("tcp: export packets delivery info") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tcp_ecn.h | 2 +- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_input.c | 8 ++++---- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h +index e9a933641636e..865d5c5a7718d 100644 +--- a/include/net/tcp_ecn.h ++++ b/include/net/tcp_ecn.h +@@ -181,7 +181,7 @@ static inline void tcp_accecn_third_ack(struct sock *sk, + tcp_accecn_validate_syn_feedback(sk, ace, sent_ect)) { + if ((tcp_accecn_extract_syn_ect(ace) == INET_ECN_CE) && + !tp->delivered_ce) +- tp->delivered_ce++; ++ WRITE_ONCE(tp->delivered_ce, 1); + } + break; + } +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 3eaaebc69eed7..ee50b2d3ed976 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4487,8 +4487,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + READ_ONCE(inet_csk(sk)->icsk_retransmits)); + nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, data_race(!!tp->rate_app_limited)); + nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, READ_ONCE(tp->snd_ssthresh)); +- nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered); +- nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce); ++ nla_put_u32(stats, TCP_NLA_DELIVERED, READ_ONCE(tp->delivered)); ++ nla_put_u32(stats, TCP_NLA_DELIVERED_CE, READ_ONCE(tp->delivered_ce)); + + nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una); + nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 177f87f2b7885..f1bb0ad2eead1 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -476,14 +476,14 @@ static bool tcp_accecn_process_option(struct tcp_sock *tp, + + static void tcp_count_delivered_ce(struct tcp_sock *tp, u32 ecn_count) + { +- tp->delivered_ce += ecn_count; ++ WRITE_ONCE(tp->delivered_ce, tp->delivered_ce + ecn_count); + } + + /* Updates the delivered and delivered_ce counts */ + static void tcp_count_delivered(struct tcp_sock *tp, u32 delivered, + bool ece_ack) + { +- tp->delivered += delivered; ++ WRITE_ONCE(tp->delivered, tp->delivered + delivered); + if (tcp_ecn_mode_rfc3168(tp) && ece_ack) + tcp_count_delivered_ce(tp, delivered); + } +@@ -6838,7 +6838,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVE); + /* SYN-data is counted as two separate packets in tcp_ack() */ + if (tp->delivered > 1) +- --tp->delivered; ++ WRITE_ONCE(tp->delivered, tp->delivered - 1); + } + + tcp_fastopen_add_skb(sk, synack); +@@ -7269,7 +7269,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) + SKB_DR_SET(reason, NOT_SPECIFIED); + switch (sk->sk_state) { + case TCP_SYN_RECV: +- tp->delivered++; /* SYN-ACK delivery isn't tracked in tcp_ack */ ++ WRITE_ONCE(tp->delivered, tp->delivered + 1); /* SYN-ACK delivery isn't tracked in tcp_ack */ + if (!tp->srtt_us) + tcp_synack_rtt_meas(sk, req); + +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-dsack_dups.patch b/queue-7.0/tcp-annotate-data-races-around-tp-dsack_dups.patch new file mode 100644 index 0000000000..c04a678506 --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-dsack_dups.patch @@ -0,0 +1,51 @@ +From ed862125a94f2c09b019091c79b8276657177b3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:14 +0000 +Subject: tcp: annotate data-races around tp->dsack_dups + +From: Eric Dumazet + +[ Upstream commit a984705ca88b976bf1087978fd98b7f3993da88c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7e10b6554ff2 ("tcp: add dsack blocks received stats") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-10-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_input.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 368b576cfe369..a5231c685f90b 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4499,7 +4499,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + TCP_NLA_PAD); + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); +- nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); ++ nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index b9bd42f9d08b5..285baeb060a06 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1247,7 +1247,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq, + else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq) + state->flag |= FLAG_DSACK_TLP; + +- tp->dsack_dups += dup_segs; ++ WRITE_ONCE(tp->dsack_dups, tp->dsack_dups + dup_segs); + /* Skip the DSACK if dup segs weren't retransmitted by sender */ + if (tp->dsack_dups > tp->total_retrans) + return 0; +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-plb_rehash.patch b/queue-7.0/tcp-annotate-data-races-around-tp-plb_rehash.patch new file mode 100644 index 0000000000..effa8b6e55 --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-plb_rehash.patch @@ -0,0 +1,52 @@ +From 1333fbd60a6cef4d43d1b6edb6c3fdc643300855 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:19 +0000 +Subject: tcp: annotate data-races around tp->plb_rehash + +From: Eric Dumazet + +[ Upstream commit 9e89b9d03a2d2e30dcca166d5af52f9a8eceab25 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 29c1c44646ae ("tcp: add u32 counter in tcp_sock and an SNMP counter for PLB") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-15-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + net/ipv4/tcp_plb.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index c27bee7b31146..cee51749df16c 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4514,7 +4514,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u8(stats, TCP_NLA_TTL, + tcp_skb_ttl_or_hop_limit(ack_skb)); + +- nla_put_u32(stats, TCP_NLA_REHASH, tp->plb_rehash + tp->timeout_rehash); ++ nla_put_u32(stats, TCP_NLA_REHASH, ++ READ_ONCE(tp->plb_rehash) + READ_ONCE(tp->timeout_rehash)); + return stats; + } + +diff --git a/net/ipv4/tcp_plb.c b/net/ipv4/tcp_plb.c +index 4bcf7eff95e39..b7f9b60d8991f 100644 +--- a/net/ipv4/tcp_plb.c ++++ b/net/ipv4/tcp_plb.c +@@ -79,7 +79,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb) + + sk_rethink_txhash(sk); + plb->consec_cong_rounds = 0; +- tcp_sk(sk)->plb_rehash++; ++ WRITE_ONCE(tcp_sk(sk)->plb_rehash, tcp_sk(sk)->plb_rehash + 1); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPLBREHASH); + } + EXPORT_SYMBOL_GPL(tcp_plb_check_rehash); +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-reord_seen.patch b/queue-7.0/tcp-annotate-data-races-around-tp-reord_seen.patch new file mode 100644 index 0000000000..3061120b95 --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-reord_seen.patch @@ -0,0 +1,60 @@ +From f447caa6ff626a2178a0974953c026038d3edb37 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:15 +0000 +Subject: tcp: annotate data-races around tp->reord_seen + +From: Eric Dumazet + +[ Upstream commit 62585690e6b2a112c408fe25f142b246ac833c42 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7ec65372ca53 ("tcp: add stat of data packet reordering events") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-11-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_input.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index a5231c685f90b..80274554eaa12 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4500,7 +4500,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); +- nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); ++ nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen)); + nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 285baeb060a06..eee460d19e254 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1300,7 +1300,7 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq, + } + + /* This exciting event is worth to be remembered. 8) */ +- tp->reord_seen++; ++ WRITE_ONCE(tp->reord_seen, tp->reord_seen + 1); + NET_INC_STATS(sock_net(sk), + ts ? LINUX_MIB_TCPTSREORDER : LINUX_MIB_TCPSACKREORDER); + } +@@ -2444,7 +2444,7 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend) + WRITE_ONCE(tp->reordering, + min_t(u32, tp->packets_out + addend, + READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering))); +- tp->reord_seen++; ++ WRITE_ONCE(tp->reord_seen, tp->reord_seen + 1); + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER); + } + +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-snd_ssthresh.patch b/queue-7.0/tcp-annotate-data-races-around-tp-snd_ssthresh.patch new file mode 100644 index 0000000000..6445c99d55 --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-snd_ssthresh.patch @@ -0,0 +1,334 @@ +From b2f5ec3b2dd0e363a5a3955c79d3962b418a160c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:09 +0000 +Subject: tcp: annotate data-races around tp->snd_ssthresh + +From: Eric Dumazet + +[ Upstream commit fd571afb05ebaeac5d8f09460a0640d4cf6755f8 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 7156d194a077 ("tcp: add snd_ssthresh stat in SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-5-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 2 +- + net/ipv4/tcp.c | 4 ++-- + net/ipv4/tcp_bbr.c | 6 +++--- + net/ipv4/tcp_bic.c | 2 +- + net/ipv4/tcp_cdg.c | 4 ++-- + net/ipv4/tcp_cubic.c | 6 +++--- + net/ipv4/tcp_dctcp.c | 2 +- + net/ipv4/tcp_input.c | 8 ++++---- + net/ipv4/tcp_metrics.c | 4 ++-- + net/ipv4/tcp_nv.c | 4 ++-- + net/ipv4/tcp_output.c | 4 ++-- + net/ipv4/tcp_vegas.c | 9 +++++---- + net/ipv4/tcp_westwood.c | 4 ++-- + net/ipv4/tcp_yeah.c | 3 ++- + 14 files changed, 32 insertions(+), 30 deletions(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index d4fe9e4a45d11..d8a853a61b53f 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -5397,7 +5397,7 @@ static int bpf_sol_tcp_setsockopt(struct sock *sk, int optname, + if (val <= 0) + return -EINVAL; + tp->snd_cwnd_clamp = val; +- tp->snd_ssthresh = val; ++ WRITE_ONCE(tp->snd_ssthresh, val); + break; + case TCP_BPF_DELACK_MAX: + timeout = usecs_to_jiffies(val); +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index c3253a810ea6e..3eaaebc69eed7 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3458,7 +3458,7 @@ int tcp_disconnect(struct sock *sk, int flags) + icsk->icsk_rto = TCP_TIMEOUT_INIT; + WRITE_ONCE(icsk->icsk_rto_min, TCP_RTO_MIN); + WRITE_ONCE(icsk->icsk_delack_max, TCP_DELACK_MAX); +- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; ++ WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH); + tcp_snd_cwnd_set(tp, TCP_INIT_CWND); + tp->snd_cwnd_cnt = 0; + tp->is_cwnd_limited = 0; +@@ -4486,7 +4486,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u8(stats, TCP_NLA_RECUR_RETRANS, + READ_ONCE(inet_csk(sk)->icsk_retransmits)); + nla_put_u8(stats, TCP_NLA_DELIVERY_RATE_APP_LMT, data_race(!!tp->rate_app_limited)); +- nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, tp->snd_ssthresh); ++ nla_put_u32(stats, TCP_NLA_SND_SSTHRESH, READ_ONCE(tp->snd_ssthresh)); + nla_put_u32(stats, TCP_NLA_DELIVERED, tp->delivered); + nla_put_u32(stats, TCP_NLA_DELIVERED_CE, tp->delivered_ce); + +diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c +index 760941e55153e..3df6160f51567 100644 +--- a/net/ipv4/tcp_bbr.c ++++ b/net/ipv4/tcp_bbr.c +@@ -896,8 +896,8 @@ static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs) + + if (bbr->mode == BBR_STARTUP && bbr_full_bw_reached(sk)) { + bbr->mode = BBR_DRAIN; /* drain queue we created */ +- tcp_sk(sk)->snd_ssthresh = +- bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT); ++ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, ++ bbr_inflight(sk, bbr_max_bw(sk), BBR_UNIT)); + } /* fall through to check if in-flight is already small: */ + if (bbr->mode == BBR_DRAIN && + bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <= +@@ -1042,7 +1042,7 @@ __bpf_kfunc static void bbr_init(struct sock *sk) + struct bbr *bbr = inet_csk_ca(sk); + + bbr->prior_cwnd = 0; +- tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; ++ WRITE_ONCE(tp->snd_ssthresh, TCP_INFINITE_SSTHRESH); + bbr->rtt_cnt = 0; + bbr->next_rtt_delivered = tp->delivered; + bbr->prev_ca_state = TCP_CA_Open; +diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c +index 58358bf92e1b8..65444ff142413 100644 +--- a/net/ipv4/tcp_bic.c ++++ b/net/ipv4/tcp_bic.c +@@ -74,7 +74,7 @@ static void bictcp_init(struct sock *sk) + bictcp_reset(ca); + + if (initial_ssthresh) +- tcp_sk(sk)->snd_ssthresh = initial_ssthresh; ++ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, initial_ssthresh); + } + + /* +diff --git a/net/ipv4/tcp_cdg.c b/net/ipv4/tcp_cdg.c +index ceabfd690a296..0812c390aee56 100644 +--- a/net/ipv4/tcp_cdg.c ++++ b/net/ipv4/tcp_cdg.c +@@ -162,7 +162,7 @@ static void tcp_cdg_hystart_update(struct sock *sk) + NET_ADD_STATS(sock_net(sk), + LINUX_MIB_TCPHYSTARTTRAINCWND, + tcp_snd_cwnd(tp)); +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp)); + return; + } + } +@@ -181,7 +181,7 @@ static void tcp_cdg_hystart_update(struct sock *sk) + NET_ADD_STATS(sock_net(sk), + LINUX_MIB_TCPHYSTARTDELAYCWND, + tcp_snd_cwnd(tp)); +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp)); + } + } + } +diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c +index 76c23675ae50a..f891e8d1e5458 100644 +--- a/net/ipv4/tcp_cubic.c ++++ b/net/ipv4/tcp_cubic.c +@@ -136,7 +136,7 @@ __bpf_kfunc static void cubictcp_init(struct sock *sk) + bictcp_hystart_reset(sk); + + if (!hystart && initial_ssthresh) +- tcp_sk(sk)->snd_ssthresh = initial_ssthresh; ++ WRITE_ONCE(tcp_sk(sk)->snd_ssthresh, initial_ssthresh); + } + + __bpf_kfunc static void cubictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) +@@ -423,7 +423,7 @@ static void hystart_update(struct sock *sk, u32 delay) + NET_ADD_STATS(sock_net(sk), + LINUX_MIB_TCPHYSTARTTRAINCWND, + tcp_snd_cwnd(tp)); +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp)); + } + } + } +@@ -443,7 +443,7 @@ static void hystart_update(struct sock *sk, u32 delay) + NET_ADD_STATS(sock_net(sk), + LINUX_MIB_TCPHYSTARTDELAYCWND, + tcp_snd_cwnd(tp)); +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_snd_cwnd(tp)); + } + } + } +diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c +index 03abe0848420d..6f103038b0152 100644 +--- a/net/ipv4/tcp_dctcp.c ++++ b/net/ipv4/tcp_dctcp.c +@@ -177,7 +177,7 @@ static void dctcp_react_to_loss(struct sock *sk) + struct tcp_sock *tp = tcp_sk(sk); + + ca->loss_cwnd = tcp_snd_cwnd(tp); +- tp->snd_ssthresh = max(tcp_snd_cwnd(tp) >> 1U, 2U); ++ WRITE_ONCE(tp->snd_ssthresh, max(tcp_snd_cwnd(tp) >> 1U, 2U)); + } + + __bpf_kfunc static void dctcp_state(struct sock *sk, u8 new_state) +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index 891a7f74432bb..177f87f2b7885 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -2568,7 +2568,7 @@ void tcp_enter_loss(struct sock *sk) + (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) { + tp->prior_ssthresh = tcp_current_ssthresh(sk); + tp->prior_cwnd = tcp_snd_cwnd(tp); +- tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, icsk->icsk_ca_ops->ssthresh(sk)); + tcp_ca_event(sk, CA_EVENT_LOSS); + tcp_init_undo(tp); + } +@@ -2861,7 +2861,7 @@ static void tcp_undo_cwnd_reduction(struct sock *sk, bool unmark_loss) + tcp_snd_cwnd_set(tp, icsk->icsk_ca_ops->undo_cwnd(sk)); + + if (tp->prior_ssthresh > tp->snd_ssthresh) { +- tp->snd_ssthresh = tp->prior_ssthresh; ++ WRITE_ONCE(tp->snd_ssthresh, tp->prior_ssthresh); + tcp_ecn_withdraw_cwr(tp); + } + } +@@ -2979,7 +2979,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk) + tp->prior_cwnd = tcp_snd_cwnd(tp); + tp->prr_delivered = 0; + tp->prr_out = 0; +- tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, inet_csk(sk)->icsk_ca_ops->ssthresh(sk)); + tcp_ecn_queue_cwr(tp); + } + +@@ -3121,7 +3121,7 @@ static void tcp_non_congestion_loss_retransmit(struct sock *sk) + + if (icsk->icsk_ca_state != TCP_CA_Loss) { + tp->high_seq = tp->snd_nxt; +- tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk)); + tp->prior_ssthresh = 0; + tp->undo_marker = 0; + tcp_set_ca_state(sk, TCP_CA_Loss); +diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c +index 7a9d6d9006f65..dc0c081fc1f33 100644 +--- a/net/ipv4/tcp_metrics.c ++++ b/net/ipv4/tcp_metrics.c +@@ -490,9 +490,9 @@ void tcp_init_metrics(struct sock *sk) + val = READ_ONCE(net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) ? + 0 : tcp_metric_get(tm, TCP_METRIC_SSTHRESH); + if (val) { +- tp->snd_ssthresh = val; ++ WRITE_ONCE(tp->snd_ssthresh, val); + if (tp->snd_ssthresh > tp->snd_cwnd_clamp) +- tp->snd_ssthresh = tp->snd_cwnd_clamp; ++ WRITE_ONCE(tp->snd_ssthresh, tp->snd_cwnd_clamp); + } + val = tcp_metric_get(tm, TCP_METRIC_REORDERING); + if (val && tp->reordering != val) +diff --git a/net/ipv4/tcp_nv.c b/net/ipv4/tcp_nv.c +index a60662f4bdf92..f345897a68dfc 100644 +--- a/net/ipv4/tcp_nv.c ++++ b/net/ipv4/tcp_nv.c +@@ -396,8 +396,8 @@ static void tcpnv_acked(struct sock *sk, const struct ack_sample *sample) + + /* We have enough data to determine we are congested */ + ca->nv_allow_cwnd_growth = 0; +- tp->snd_ssthresh = +- (nv_ssthresh_factor * max_win) >> 3; ++ WRITE_ONCE(tp->snd_ssthresh, ++ (nv_ssthresh_factor * max_win) >> 3); + if (tcp_snd_cwnd(tp) - max_win > 2) { + /* gap > 2, we do exponential cwnd decrease */ + int dec; +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 87fa26603276c..6603331ec589e 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -171,7 +171,7 @@ void tcp_cwnd_restart(struct sock *sk, s32 delta) + + tcp_ca_event(sk, CA_EVENT_CWND_RESTART); + +- tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk)); + restart_cwnd = min(restart_cwnd, cwnd); + + while ((delta -= inet_csk(sk)->icsk_rto) > 0 && cwnd > restart_cwnd) +@@ -2125,7 +2125,7 @@ static void tcp_cwnd_application_limited(struct sock *sk) + u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk)); + u32 win_used = max(tp->snd_cwnd_used, init_win); + if (win_used < tcp_snd_cwnd(tp)) { +- tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk)); + tcp_snd_cwnd_set(tp, (tcp_snd_cwnd(tp) + win_used) >> 1); + } + tp->snd_cwnd_used = 0; +diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c +index 786848ad37ea8..3ec7308441a78 100644 +--- a/net/ipv4/tcp_vegas.c ++++ b/net/ipv4/tcp_vegas.c +@@ -240,7 +240,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) + */ + tcp_snd_cwnd_set(tp, min(tcp_snd_cwnd(tp), + (u32)target_cwnd + 1)); +- tp->snd_ssthresh = tcp_vegas_ssthresh(tp); ++ WRITE_ONCE(tp->snd_ssthresh, ++ tcp_vegas_ssthresh(tp)); + + } else if (tcp_in_slow_start(tp)) { + /* Slow start. */ +@@ -256,8 +257,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) + * we slow down. + */ + tcp_snd_cwnd_set(tp, tcp_snd_cwnd(tp) - 1); +- tp->snd_ssthresh +- = tcp_vegas_ssthresh(tp); ++ WRITE_ONCE(tp->snd_ssthresh, ++ tcp_vegas_ssthresh(tp)); + } else if (diff < alpha) { + /* We don't have enough extra packets + * in the network, so speed up. +@@ -275,7 +276,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) + else if (tcp_snd_cwnd(tp) > tp->snd_cwnd_clamp) + tcp_snd_cwnd_set(tp, tp->snd_cwnd_clamp); + +- tp->snd_ssthresh = tcp_current_ssthresh(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_current_ssthresh(sk)); + } + + /* Wipe the slate clean for the next RTT. */ +diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c +index c6e97141eef25..b5a42adfd6ca1 100644 +--- a/net/ipv4/tcp_westwood.c ++++ b/net/ipv4/tcp_westwood.c +@@ -244,11 +244,11 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event) + + switch (event) { + case CA_EVENT_COMPLETE_CWR: +- tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_westwood_bw_rttmin(sk)); + tcp_snd_cwnd_set(tp, tp->snd_ssthresh); + break; + case CA_EVENT_LOSS: +- tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk); ++ WRITE_ONCE(tp->snd_ssthresh, tcp_westwood_bw_rttmin(sk)); + /* Update RTT_min when next ack arrives */ + w->reset_rtt_min = 1; + break; +diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c +index 18b07ff5d20e6..74a2538e79e06 100644 +--- a/net/ipv4/tcp_yeah.c ++++ b/net/ipv4/tcp_yeah.c +@@ -147,7 +147,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked) + tcp_snd_cwnd_set(tp, max(tcp_snd_cwnd(tp), + yeah->reno_count)); + +- tp->snd_ssthresh = tcp_snd_cwnd(tp); ++ WRITE_ONCE(tp->snd_ssthresh, ++ tcp_snd_cwnd(tp)); + } + + if (yeah->reno_count <= 2) +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-srtt_us.patch b/queue-7.0/tcp-annotate-data-races-around-tp-srtt_us.patch new file mode 100644 index 0000000000..ebc13affa6 --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-srtt_us.patch @@ -0,0 +1,61 @@ +From 4263a9b8bca509cc194e7258f348e7d40b7bb880 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:16 +0000 +Subject: tcp: annotate data-races around tp->srtt_us + +From: Eric Dumazet + +[ Upstream commit 290b693ce7c9d48588d88b15a782a3efc6fa036b ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: e8bd8fca6773 ("tcp: add SRTT to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-12-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 5 +++-- + net/ipv4/tcp_input.c | 2 +- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 80274554eaa12..566a04088fdc5 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3656,7 +3656,8 @@ static void tcp_enable_tx_delay(struct sock *sk, int val) + if (delta && sk->sk_state == TCP_ESTABLISHED) { + s64 srtt = (s64)tp->srtt_us + delta; + +- tp->srtt_us = clamp_t(s64, srtt, 1, ~0U); ++ WRITE_ONCE(tp->srtt_us, ++ clamp_t(s64, srtt, 1, ~0U)); + + /* Note: does not deal with non zero icsk_backoff */ + tcp_set_rto(sk); +@@ -4501,7 +4502,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD); + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen)); +- nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3); ++ nla_put_u32(stats, TCP_NLA_SRTT, READ_ONCE(tp->srtt_us) >> 3); + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, + max_t(int, 0, tp->write_seq - tp->snd_nxt)); +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index eee460d19e254..c6c55c51a6409 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1133,7 +1133,7 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us) + + tcp_bpf_rtt(sk, mrtt_us, srtt); + } +- tp->srtt_us = max(1U, srtt); ++ WRITE_ONCE(tp->srtt_us, max(1U, srtt)); + } + + void tcp_update_pacing_rate(struct sock *sk) +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-timeout_rehash.patch b/queue-7.0/tcp-annotate-data-races-around-tp-timeout_rehash.patch new file mode 100644 index 0000000000..49bc55ce94 --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-timeout_rehash.patch @@ -0,0 +1,52 @@ +From b264bee9a28453130618980b9871eacde9f6ac33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:17 +0000 +Subject: tcp: annotate data-races around tp->timeout_rehash + +From: Eric Dumazet + +[ Upstream commit 71c675358b711bbfd8528949249419dc2dfa4ce1 ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy. + +Fixes: 32efcc06d2a1 ("tcp: export count for rehash attempts") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-13-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + net/ipv4/tcp_timer.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 566a04088fdc5..60ca350fb5341 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4503,7 +4503,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups)); + nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen)); + nla_put_u32(stats, TCP_NLA_SRTT, READ_ONCE(tp->srtt_us) >> 3); +- nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash); ++ nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, ++ READ_ONCE(tp->timeout_rehash)); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, + max_t(int, 0, tp->write_seq - tp->snd_nxt)); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, +diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c +index 5a14a53a3c9ef..153c5888580ca 100644 +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -297,7 +297,7 @@ static int tcp_write_timeout(struct sock *sk) + } + + if (sk_rethink_txhash(sk)) { +- tp->timeout_rehash++; ++ WRITE_ONCE(tp->timeout_rehash, tp->timeout_rehash + 1); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEOUTREHASH); + } + +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch b/queue-7.0/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch new file mode 100644 index 0000000000..506e6a9e9f --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-around-tp-write_seq-tp-snd_n.patch @@ -0,0 +1,40 @@ +From 1327129762b47eb7ed59ff75dc50902f494114a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:18 +0000 +Subject: tcp: annotate data-races around (tp->write_seq - tp->snd_nxt) + +From: Eric Dumazet + +[ Upstream commit 3a63b3d160560ef51e43fb4c880a5cde8078053c ] + +tcp_get_timestamping_opt_stats() intentionally runs lockless, we must +add READ_ONCE() annotations to keep KCSAN happy. + +WRITE_ONCE() annotations are already present. + +Fixes: e08ab0b377a1 ("tcp: add bytes not sent to SCM_TIMESTAMPING_OPT_STATS") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-14-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 60ca350fb5341..c27bee7b31146 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4506,7 +4506,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, + nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, + READ_ONCE(tp->timeout_rehash)); + nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT, +- max_t(int, 0, tp->write_seq - tp->snd_nxt)); ++ max_t(int, 0, ++ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt))); + nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns, + TCP_NLA_PAD); + if (ack_skb) +-- +2.53.0 + diff --git a/queue-7.0/tcp-annotate-data-races-in-tcp_get_info_chrono_stats.patch b/queue-7.0/tcp-annotate-data-races-in-tcp_get_info_chrono_stats.patch new file mode 100644 index 0000000000..de143c1b23 --- /dev/null +++ b/queue-7.0/tcp-annotate-data-races-in-tcp_get_info_chrono_stats.patch @@ -0,0 +1,81 @@ +From 42a9d9037bb4e1d8ec029432a374b6856827d51b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 20:03:06 +0000 +Subject: tcp: annotate data-races in tcp_get_info_chrono_stats() + +From: Eric Dumazet + +[ Upstream commit 267bf3cf9a6f0ffb98b8afd983c1950e835f07c9 ] + +tcp_get_timestamping_opt_stats() does not own the socket lock, +this is intentional. + +It calls tcp_get_info_chrono_stats() while other threads could +change chrono fields in tcp_chrono_set(). + +I do not think we need coherent TCP socket state snapshot +in tcp_get_timestamping_opt_stats(), I chose to only +add annotations to keep KCSAN happy. + +Fixes: 1c885808e456 ("tcp: SOF_TIMESTAMPING_OPT_STATS option for SO_TIMESTAMPING") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20260416200319.3608680-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 10 +++++++--- + net/ipv4/tcp.c | 14 ++++++++++---- + 2 files changed, 17 insertions(+), 7 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 905587114d444..1946935388be6 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -2161,10 +2161,14 @@ static inline void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new + const u32 now = tcp_jiffies32; + enum tcp_chrono old = tp->chrono_type; + ++ /* Following WRITE_ONCE()s pair with READ_ONCE()s in ++ * tcp_get_info_chrono_stats(). ++ */ + if (old > TCP_CHRONO_UNSPEC) +- tp->chrono_stat[old - 1] += now - tp->chrono_start; +- tp->chrono_start = now; +- tp->chrono_type = new; ++ WRITE_ONCE(tp->chrono_stat[old - 1], ++ tp->chrono_stat[old - 1] + now - tp->chrono_start); ++ WRITE_ONCE(tp->chrono_start, now); ++ WRITE_ONCE(tp->chrono_type, new); + } + + static inline void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type) +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 202a4e57a2188..a8ff76c40f79b 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4225,12 +4225,18 @@ static void tcp_get_info_chrono_stats(const struct tcp_sock *tp, + struct tcp_info *info) + { + u64 stats[__TCP_CHRONO_MAX], total = 0; +- enum tcp_chrono i; ++ enum tcp_chrono i, cur; + ++ /* Following READ_ONCE()s pair with WRITE_ONCE()s in tcp_chrono_set(). ++ * This is because socket lock might not be owned by us at this point. ++ * This is best effort, tcp_get_timestamping_opt_stats() can ++ * see wrong values. A real fix would be too costly for TCP fast path. ++ */ ++ cur = READ_ONCE(tp->chrono_type); + for (i = TCP_CHRONO_BUSY; i < __TCP_CHRONO_MAX; ++i) { +- stats[i] = tp->chrono_stat[i - 1]; +- if (i == tp->chrono_type) +- stats[i] += tcp_jiffies32 - tp->chrono_start; ++ stats[i] = READ_ONCE(tp->chrono_stat[i - 1]); ++ if (i == cur) ++ stats[i] += tcp_jiffies32 - READ_ONCE(tp->chrono_start); + stats[i] *= USEC_PER_SEC / HZ; + total += stats[i]; + } +-- +2.53.0 + diff --git a/queue-7.0/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch b/queue-7.0/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch new file mode 100644 index 0000000000..f85cf796ef --- /dev/null +++ b/queue-7.0/tcp-don-t-set-treq-req_usec_ts-in-cookie_tcp_reqsk_i.patch @@ -0,0 +1,54 @@ +From a8fd275d09a6ab8fd7d926924142eb332351130d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 23:53:27 +0000 +Subject: tcp: Don't set treq->req_usec_ts in cookie_tcp_reqsk_init(). + +From: Kuniyuki Iwashima + +[ Upstream commit c058bbf05b1197c33df7204842665bd8bc70b3a8 ] + +Commit de5626b95e13 ("tcp: Factorise cookie-independent fields +initialisation in cookie_v[46]_check().") miscategorised +tcp_rsk(req)->req_usec_ts init to cookie_tcp_reqsk_init(), +which is used by both BPF/non-BPF SYN cookie reqsk. + +Rather, it should have been moved to cookie_tcp_reqsk_alloc() by +commit 8e7bab6b9652 ("tcp: Factorise cookie-dependent fields +initialisation in cookie_v[46]_check()") so that only non-BPF SYN +cookie sets tcp_rsk(req)->req_usec_ts to false. + +Let's move the initialisation to cookie_tcp_reqsk_alloc() to +respect bpf_tcp_req_attrs.usec_ts_ok. + +Fixes: e472f88891ab ("bpf: tcp: Support arbitrary SYN Cookie.") +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260410235328.1773449-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/syncookies.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c +index fc3affd9c8014..b5f0a65c67864 100644 +--- a/net/ipv4/syncookies.c ++++ b/net/ipv4/syncookies.c +@@ -286,7 +286,6 @@ static int cookie_tcp_reqsk_init(struct sock *sk, struct sk_buff *skb, + treq->rcv_isn = ntohl(th->seq) - 1; + treq->snt_isn = ntohl(th->ack_seq) - 1; + treq->syn_tos = TCP_SKB_CB(skb)->ip_dsfield; +- treq->req_usec_ts = false; + + #if IS_ENABLED(CONFIG_MPTCP) + treq->is_mptcp = sk_is_mptcp(sk); +@@ -349,6 +348,7 @@ struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, + ireq->wscale_ok = tcp_opt->wscale_ok; + ireq->ecn_ok = !!(tcp_opt->rcv_tsecr & TS_OPT_ECN); + ++ treq->req_usec_ts = false; + treq->ts_off = tsoff; + + return req; +-- +2.53.0 + diff --git a/queue-7.0/tcp-inline-tcp_chrono_start.patch b/queue-7.0/tcp-inline-tcp_chrono_start.patch new file mode 100644 index 0000000000..ac32236f18 --- /dev/null +++ b/queue-7.0/tcp-inline-tcp_chrono_start.patch @@ -0,0 +1,111 @@ +From 8435f3a5cab4dd35ed7436b58059cfa1b66f27f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 12:35:49 +0000 +Subject: tcp: inline tcp_chrono_start() + +From: Eric Dumazet + +[ Upstream commit d6d4ff335db2d9242937ca474d292010acd35c38 ] + +tcp_chrono_start() is small enough, and used in TCP sendmsg() +fast path (from tcp_skb_entail()). + +Note clang is already inlining it from functions in tcp_output.c. + +Inlining it improves performance and reduces bloat : + +$ scripts/bloat-o-meter -t vmlinux.old vmlinux.new +add/remove: 0/2 grow/shrink: 1/0 up/down: 1/-84 (-83) +Function old new delta +tcp_skb_entail 280 281 +1 +__pfx_tcp_chrono_start 16 - -16 +tcp_chrono_start 68 - -68 +Total: Before=25192434, After=25192351, chg -0.00% + +Note that tcp_chrono_stop() is too big. + +Signed-off-by: Eric Dumazet +Reviewed-by: Neal Cardwell +Link: https://patch.msgid.link/20260308123549.2924460-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 267bf3cf9a6f ("tcp: annotate data-races in tcp_get_info_chrono_stats()") +Signed-off-by: Sasha Levin +--- + include/net/tcp.h | 25 ++++++++++++++++++++++++- + net/ipv4/tcp_output.c | 24 ------------------------ + 2 files changed, 24 insertions(+), 25 deletions(-) + +diff --git a/include/net/tcp.h b/include/net/tcp.h +index 978eea2d5df04..905587114d444 100644 +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -2156,7 +2156,30 @@ enum tcp_chrono { + __TCP_CHRONO_MAX, + }; + +-void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type); ++static inline void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new) ++{ ++ const u32 now = tcp_jiffies32; ++ enum tcp_chrono old = tp->chrono_type; ++ ++ if (old > TCP_CHRONO_UNSPEC) ++ tp->chrono_stat[old - 1] += now - tp->chrono_start; ++ tp->chrono_start = now; ++ tp->chrono_type = new; ++} ++ ++static inline void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ ++ /* If there are multiple conditions worthy of tracking in a ++ * chronograph then the highest priority enum takes precedence ++ * over the other conditions. So that if something "more interesting" ++ * starts happening, stop the previous chrono and start a new one. ++ */ ++ if (type > tp->chrono_type) ++ tcp_chrono_set(tp, type); ++} ++ + void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type); + + /* This helper is needed, because skb->tcp_tsorted_anchor uses +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 326b58ff1118d..7b8a2c8213e18 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -2878,30 +2878,6 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb, + return false; + } + +-static void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new) +-{ +- const u32 now = tcp_jiffies32; +- enum tcp_chrono old = tp->chrono_type; +- +- if (old > TCP_CHRONO_UNSPEC) +- tp->chrono_stat[old - 1] += now - tp->chrono_start; +- tp->chrono_start = now; +- tp->chrono_type = new; +-} +- +-void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type) +-{ +- struct tcp_sock *tp = tcp_sk(sk); +- +- /* If there are multiple conditions worthy of tracking in a +- * chronograph then the highest priority enum takes precedence +- * over the other conditions. So that if something "more interesting" +- * starts happening, stop the previous chrono and start a new one. +- */ +- if (type > tp->chrono_type) +- tcp_chrono_set(tp, type); +-} +- + void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type) + { + struct tcp_sock *tp = tcp_sk(sk); +-- +2.53.0 + diff --git a/queue-7.0/tcp-make-probe0-timer-handle-expired-user-timeout.patch b/queue-7.0/tcp-make-probe0-timer-handle-expired-user-timeout.patch new file mode 100644 index 0000000000..1cf4d1e089 --- /dev/null +++ b/queue-7.0/tcp-make-probe0-timer-handle-expired-user-timeout.patch @@ -0,0 +1,58 @@ +From e8ba762f45db253c4e3d318d6e8c00b6a03a3979 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 18:46:38 -0700 +Subject: tcp: make probe0 timer handle expired user timeout + +From: Altan Hacigumus + +[ Upstream commit 2b9f6f7065d4cfb65ba19126e0b35ac4544c3f3a ] + +tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies +using subtraction with an unsigned lvalue. If elapsed probing time +exceeds the configured TCP_USER_TIMEOUT, the underflow yields a large +value. + +This ends up re-arming the probe timer for a full backoff interval +instead of expiring immediately, delaying connection teardown beyond +the configured timeout. + +Fix this by preventing underflow so user-set timeout expiration is +handled correctly without extending the probe timer. + +Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes") +Link: https://lore.kernel.org/r/20260414013634.43997-1-ahacigu.linux@gmail.com +Signed-off-by: Altan Hacigumus +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260424014639.54110-1-ahacigu.linux@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp_timer.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c +index 153c5888580ca..61631a2dcea7f 100644 +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk) + u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) + { + const struct inet_connection_sock *icsk = inet_csk(sk); +- u32 remaining, user_timeout; ++ u32 user_timeout; ++ s32 remaining; + s32 elapsed; + + user_timeout = READ_ONCE(icsk->icsk_user_timeout); +@@ -61,7 +62,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when) + if (unlikely(elapsed < 0)) + elapsed = 0; + remaining = msecs_to_jiffies(user_timeout) - elapsed; +- remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN); ++ remaining = max_t(int, remaining, TCP_TIMEOUT_MIN); + + return min_t(u32, remaining, when); + } +-- +2.53.0 + diff --git a/queue-7.0/tcp-move-tp-chrono_type-next-tp-chrono_stat.patch b/queue-7.0/tcp-move-tp-chrono_type-next-tp-chrono_stat.patch new file mode 100644 index 0000000000..ed15f8b7e9 --- /dev/null +++ b/queue-7.0/tcp-move-tp-chrono_type-next-tp-chrono_stat.patch @@ -0,0 +1,56 @@ +From 56daaba30cc4b474c321713ccf60c14769a83b62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 12:23:02 +0000 +Subject: tcp: move tp->chrono_type next tp->chrono_stat[] + +From: Eric Dumazet + +[ Upstream commit 4b78c9cbd8f1fbb9517aee48b372646f4cf05442 ] + +chrono_type is currently in tcp_sock_read_txrx group, which +is supposed to hold read-mostly fields. + +But chrono_type is mostly written in tx path, it should +be moved to tcp_sock_write_tx group, close to other +chrono fields (chrono_stat[], chrono_start). + +Note this adds holes, but data locality is far more important. + +Use a full u8 for the time being, compiler can generate +more efficient code. + +Signed-off-by: Eric Dumazet +Reviewed-by: Neal Cardwell +Link: https://patch.msgid.link/20260308122302.2895067-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 267bf3cf9a6f ("tcp: annotate data-races in tcp_get_info_chrono_stats()") +Signed-off-by: Sasha Levin +--- + include/linux/tcp.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/tcp.h b/include/linux/tcp.h +index f72eef31fa23c..c44cf9ae8d16f 100644 +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -228,8 +228,7 @@ struct tcp_sock { + u32 sacked_out; /* SACK'd packets */ + u16 tcp_header_len; /* Bytes of tcp header to send */ + u8 scaling_ratio; /* see tcp_win_from_space() */ +- u8 chrono_type : 2, /* current chronograph type */ +- repair : 1, ++ u8 repair : 1, + tcp_usec_ts : 1, /* TSval values in usec */ + is_sack_reneg:1, /* in recovery from loss with SACK reneg? */ + is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */ +@@ -264,6 +263,7 @@ struct tcp_sock { + * total number of data bytes sent. + */ + u32 snd_sml; /* Last byte of the most recently transmitted small packet */ ++ u8 chrono_type; /* current chronograph type */ + u32 chrono_start; /* Start time in jiffies of a TCP chrono */ + u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ + u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ +-- +2.53.0 + diff --git a/queue-7.0/tcp-send-a-challenge-ack-on-seg.ack-snd.nxt.patch b/queue-7.0/tcp-send-a-challenge-ack-on-seg.ack-snd.nxt.patch new file mode 100644 index 0000000000..a46a7d909f --- /dev/null +++ b/queue-7.0/tcp-send-a-challenge-ack-on-seg.ack-snd.nxt.patch @@ -0,0 +1,87 @@ +From a5b40b5041c9278ffb9cf83d9a880bb95f9412f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 20:35:38 +0800 +Subject: tcp: send a challenge ACK on SEG.ACK > SND.NXT + +From: Jiayuan Chen + +[ Upstream commit 42726ec644cbdde0035c3e0417fee8ed9547e120 ] + +RFC 5961 Section 5.2 validates an incoming segment's ACK value +against the range [SND.UNA - MAX.SND.WND, SND.NXT] and states: + + "All incoming segments whose ACK value doesn't satisfy the above + condition MUST be discarded and an ACK sent back." + +Commit 354e4aa391ed ("tcp: RFC 5961 5.2 Blind Data Injection Attack +Mitigation") opted Linux into this mitigation and implements the +challenge ACK on the lower side (SEG.ACK < SND.UNA - MAX.SND.WND), +but the symmetric upper side (SEG.ACK > SND.NXT) still takes the +pre-RFC-5961 path and silently returns +SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, even though RFC 793 Section 3.9 +(now RFC 9293 Section 3.10.7.4) has always required: + + "If the ACK acknowledges something not yet sent (SEG.ACK > SND.NXT) + then send an ACK, drop the segment, and return." + +Complete the mitigation by sending a challenge ACK on that branch, +reusing the existing tcp_send_challenge_ack() path which already +enforces the per-socket RFC 5961 Section 7 rate limit via +__tcp_oow_rate_limited(). FLAG_NO_CHALLENGE_ACK is honoured for +symmetry with the lower-edge case. + +Update the existing tcp_ts_recent_invalid_ack.pkt selftest, which +drives this exact path, to consume the new challenge ACK. + +Fixes: 354e4aa391ed ("tcp: RFC 5961 5.2 Blind Data Injection Attack Mitigation") +Signed-off-by: Jiayuan Chen +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260422123605.320000-2-jiayuan.chen@linux.dev +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/tcp_input.c | 10 +++++++--- + .../net/packetdrill/tcp_ts_recent_invalid_ack.pkt | 4 +++- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index c6c55c51a6409..cb4bcc5a85787 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -4288,11 +4288,15 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) + goto old_ack; + } + +- /* If the ack includes data we haven't sent yet, discard +- * this segment (RFC793 Section 3.9). ++ /* If the ack includes data we haven't sent yet, drop the ++ * segment. RFC 793 Section 3.9 and RFC 5961 Section 5.2 ++ * require us to send an ACK back in that case. + */ +- if (after(ack, tp->snd_nxt)) ++ if (after(ack, tp->snd_nxt)) { ++ if (!(flag & FLAG_NO_CHALLENGE_ACK)) ++ tcp_send_challenge_ack(sk, false); + return -SKB_DROP_REASON_TCP_ACK_UNSENT_DATA; ++ } + + if (after(ack, prior_snd_una)) { + flag |= FLAG_SND_UNA_ADVANCED; +diff --git a/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt b/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt +index 174ce9a1bfc07..ee6baf7c36cfa 100644 +--- a/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt ++++ b/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt +@@ -19,7 +19,9 @@ + + // bad packet with high tsval (its ACK sequence is above our sndnxt) + +0 < F. 1:1(0) ack 9999 win 20000 +- ++// Challenge ACK for SEG.ACK > SND.NXT (RFC 5961 5.2 / RFC 793 3.9). ++// ecr=200 (not 200000) proves ts_recent was not updated from the bad packet. ++ +0 > . 1:1(0) ack 1 + + +0 < . 1:1001(1000) ack 1 win 20000 + +0 > . 1:1(0) ack 1001 +-- +2.53.0 + diff --git a/queue-7.0/thermal-drivers-spear-fix-error-condition-for-readin.patch b/queue-7.0/thermal-drivers-spear-fix-error-condition-for-readin.patch new file mode 100644 index 0000000000..c41944f605 --- /dev/null +++ b/queue-7.0/thermal-drivers-spear-fix-error-condition-for-readin.patch @@ -0,0 +1,42 @@ +From 10a9fa8069db1c5d9764f778625516c8e0afe3ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 14:35:24 +0530 +Subject: thermal/drivers/spear: Fix error condition for reading + st,thermal-flags + +From: Gopi Krishna Menon + +[ Upstream commit da2c4f332a0504d9c284e7626a561d343c8d6f57 ] + +of_property_read_u32 returns 0 on success. The current check returns +-EINVAL if the property is read successfully. + +Fix the check by removing ! from of_property_read_u32 + +Fixes: b9c7aff481f1 ("drivers/thermal/spear_thermal.c: add Device Tree probing capability") +Signed-off-by: Gopi Krishna Menon +Signed-off-by: Daniel Lezcano +Suggested-by: Daniel Baluta +Reviewed-by: Lukasz Luba +Link: https://patch.msgid.link/20260327090526.59330-1-krishnagopi487@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/thermal/spear_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c +index 603dadcd3df58..5e3e9c1f32f8e 100644 +--- a/drivers/thermal/spear_thermal.c ++++ b/drivers/thermal/spear_thermal.c +@@ -93,7 +93,7 @@ static int spear_thermal_probe(struct platform_device *pdev) + struct device_node *np = pdev->dev.of_node; + int ret = 0, val; + +- if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) { ++ if (!np || of_property_read_u32(np, "st,thermal-flags", &val)) { + dev_err(&pdev->dev, "Failed: DT Pdata not passed\n"); + return -EINVAL; + } +-- +2.53.0 + diff --git a/queue-7.0/tipc-fix-double-free-in-tipc_buf_append.patch b/queue-7.0/tipc-fix-double-free-in-tipc_buf_append.patch new file mode 100644 index 0000000000..9836837eb8 --- /dev/null +++ b/queue-7.0/tipc-fix-double-free-in-tipc_buf_append.patch @@ -0,0 +1,60 @@ +From 4c8f3ab3c90d2162a26654c703c89d1eba7f68ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 13:45:26 +0100 +Subject: tipc: fix double-free in tipc_buf_append() + +From: Lee Jones + +[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ] + +tipc_msg_validate() can potentially reallocate the skb it is validating, +freeing the old one. In tipc_buf_append(), it was being called with a +pointer to a local variable which was a copy of the caller's skb +pointer. + +If the skb was reallocated and validation subsequently failed, the error +handling path would free the original skb pointer, which had already +been freed, leading to double-free. + +Fix this by checking if head now points to a newly allocated reassembled +skb. If it does, reassign *headbuf for later freeing operations. + +Fixes: d618d09a68e4 ("tipc: enforce valid ratio between skb truesize and contents") +Suggested-by: Tung Nguyen +Signed-off-by: Lee Jones +Reviewed-by: Tung Nguyen +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/msg.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/net/tipc/msg.c b/net/tipc/msg.c +index 76284fc538ebd..b0bba0feef564 100644 +--- a/net/tipc/msg.c ++++ b/net/tipc/msg.c +@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) + + if (fragid == LAST_FRAGMENT) { + TIPC_SKB_CB(head)->validated = 0; +- if (unlikely(!tipc_msg_validate(&head))) ++ ++ /* If the reassembled skb has been freed in ++ * tipc_msg_validate() because of an invalid truesize, ++ * then head will point to a newly allocated reassembled ++ * skb, while *headbuf points to freed reassembled skb. ++ * In such cases, correct *headbuf for freeing the newly ++ * allocated reassembled skb later. ++ */ ++ if (unlikely(!tipc_msg_validate(&head))) { ++ if (head != *headbuf) ++ *headbuf = head; + goto err; ++ } ++ + *buf = head; + TIPC_SKB_CB(head)->tail = NULL; + *headbuf = NULL; +-- +2.53.0 + diff --git a/queue-7.0/tools-build-correct-link-flags-for-libopenssl.patch b/queue-7.0/tools-build-correct-link-flags-for-libopenssl.patch new file mode 100644 index 0000000000..5ba866adfc --- /dev/null +++ b/queue-7.0/tools-build-correct-link-flags-for-libopenssl.patch @@ -0,0 +1,59 @@ +From 3da75a06b42e8f66fe320feb40b6b36c4c7fa7c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 18:58:00 +0000 +Subject: tools build: Correct link flags for libopenssl + +From: Leo Yan + +[ Upstream commit 5c980ab238c8a9e2b24221603f11eadc98a7f45e ] + +The perf static build reports that the BPF skeleton is disabled due to +the missing libopenssl feature. + +Use PKG_CONFIG to determine the link flags for libopenssl. Add +"--static" to the PKG_CONFIG command for static linking. + +Fixes: 7678523109d1 ("tools/build: Add a feature test for libopenssl") +Signed-off-by: Leo Yan +Signed-off-by: Namhyung Kim +Signed-off-by: Sasha Levin +--- + tools/build/feature/Makefile | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile +index 1fbcb3ce74d21..f163a245837a6 100644 +--- a/tools/build/feature/Makefile ++++ b/tools/build/feature/Makefile +@@ -103,12 +103,18 @@ else + endif + endif + ++ifeq ($(findstring -static,${LDFLAGS}),-static) ++ PKG_CONFIG += --static ++endif ++ + all: $(FILES) + + __BUILD = $(CC) $(CFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS) + BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1 + BUILD_BFD = $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl +- BUILD_ALL = $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -lslang $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -ldl -lz -llzma -lzstd -lssl ++ BUILD_ALL = $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -lslang \ ++ $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -ldl -lz -llzma -lzstd \ ++ $(shell $(PKG_CONFIG) --libs --cflags openssl 2>/dev/null) + + __BUILDXX = $(CXX) $(CXXFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS) + BUILDXX = $(__BUILDXX) > $(@:.bin=.make.output) 2>&1 +@@ -384,7 +390,7 @@ $(OUTPUT)test-libpfm4.bin: + $(BUILD) -lpfm + + $(OUTPUT)test-libopenssl.bin: +- $(BUILD) -lssl ++ $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags openssl 2>/dev/null) + + $(OUTPUT)test-bpftool-skeletons.bin: + $(SYSTEM_BPFTOOL) version | grep '^features:.*skeletons' \ +-- +2.53.0 + diff --git a/queue-7.0/tools-hv-fix-cross-compilation.patch b/queue-7.0/tools-hv-fix-cross-compilation.patch new file mode 100644 index 0000000000..39f6023972 --- /dev/null +++ b/queue-7.0/tools-hv-fix-cross-compilation.patch @@ -0,0 +1,53 @@ +From d67d5a40657335ede39eb59e05e934152f2da610 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Apr 2026 03:32:18 -0700 +Subject: tools: hv: Fix cross-compilation + +From: Aditya Garg + +[ Upstream commit ca5ee0e918115fb5cf626d75461d9fca06e06caf ] + +Use the native ARCH only in case it is not set, this will allow the +cross-compilation where ARCH is explicitly set. + +Additionally, simplify the ARCH check to build the fcopy daemon only +for x86 and x86_64. + +Fixes: 82b0945ce2c2 ("tools: hv: Add new fcopy application based on uio driver") +Reported-by: Adrian Vladu +Closes: https://lore.kernel.org/linux-hyperv/PR3PR09MB54119DB2FD76977C62D8DD6AB04D2@PR3PR09MB5411.eurprd09.prod.outlook.com/ +Co-developed-by: Saurabh Sengar +Signed-off-by: Saurabh Sengar +Signed-off-by: Aditya Garg +Reviewed-by: Roman Kisel +Signed-off-by: Wei Liu +Signed-off-by: Sasha Levin +--- + tools/hv/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/hv/Makefile b/tools/hv/Makefile +index 34ffcec264ab0..016753f3dd7f6 100644 +--- a/tools/hv/Makefile ++++ b/tools/hv/Makefile +@@ -2,7 +2,7 @@ + # Makefile for Hyper-V tools + include ../scripts/Makefile.include + +-ARCH := $(shell uname -m 2>/dev/null) ++ARCH ?= $(shell uname -m 2>/dev/null) + sbindir ?= /usr/sbin + libexecdir ?= /usr/libexec + sharedstatedir ?= /var/lib +@@ -20,7 +20,7 @@ override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include + override CFLAGS += -Wno-address-of-packed-member + + ALL_TARGETS := hv_kvp_daemon hv_vss_daemon +-ifneq ($(ARCH), aarch64) ++ifneq ($(filter x86_64 x86,$(ARCH)),) + ALL_TARGETS += hv_fcopy_uio_daemon + endif + ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) +-- +2.53.0 + diff --git a/queue-7.0/tools-nolibc-avoid-wundef-warning-for-__stdc_version.patch b/queue-7.0/tools-nolibc-avoid-wundef-warning-for-__stdc_version.patch new file mode 100644 index 0000000000..63735dc9ed --- /dev/null +++ b/queue-7.0/tools-nolibc-avoid-wundef-warning-for-__stdc_version.patch @@ -0,0 +1,57 @@ +From d05c714f34424ec3561fd0c49fb505b1f36059d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 17:12:42 +0100 +Subject: tools/nolibc: avoid -Wundef warning for __STDC_VERSION__ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 3eb97c4cbd4d874e7e327ec512f6169934e12b8a ] + +With -std=c89 the macro __STDC_VERSION__ is not defined. +While undefined identifiers in '#if' directives are assumed to be '0', +with -Wundef a warning is emitted. + +Avoid the warning by explicitly falling back to '0' if __STDC_VERSION__ +is not provided by the preprocessor. + +Fixes: 37219aa5b123 ("tools/nolibc: add __nolibc_static_assert()") +Signed-off-by: Thomas Weißschuh +Acked-by: Willy Tarreau +Link: https://patch.msgid.link/20260318-nolibc-wundef-v1-1-fcb7f9ac7298@weissschuh.net +Signed-off-by: Sasha Levin +--- + tools/include/nolibc/compiler.h | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h +index a8c7619dcdde2..a8d5ca58dd632 100644 +--- a/tools/include/nolibc/compiler.h ++++ b/tools/include/nolibc/compiler.h +@@ -47,6 +47,12 @@ + # define __nolibc_fallthrough do { } while (0) + #endif /* __nolibc_has_attribute(fallthrough) */ + ++#if defined(__STDC_VERSION__) ++# define __nolibc_stdc_version __STDC_VERSION__ ++#else ++# define __nolibc_stdc_version 0 ++#endif ++ + #define __nolibc_version(_major, _minor, _patch) ((_major) * 10000 + (_minor) * 100 + (_patch)) + + #ifdef __GNUC__ +@@ -63,7 +69,7 @@ + # define __nolibc_clang_version 0 + #endif /* __clang__ */ + +-#if __STDC_VERSION__ >= 201112L || \ ++#if __nolibc_stdc_version >= 201112L || \ + __nolibc_gnuc_version >= __nolibc_version(4, 6, 0) || \ + __nolibc_clang_version >= __nolibc_version(3, 0, 0) + # define __nolibc_static_assert(_t) _Static_assert(_t, "") +-- +2.53.0 + diff --git a/queue-7.0/tools-nolibc-mips-fix-clobbers-of-lo-and-hi-register.patch b/queue-7.0/tools-nolibc-mips-fix-clobbers-of-lo-and-hi-register.patch new file mode 100644 index 0000000000..32702a2cd4 --- /dev/null +++ b/queue-7.0/tools-nolibc-mips-fix-clobbers-of-lo-and-hi-register.patch @@ -0,0 +1,72 @@ +From 0496aa5ed71d1855186e58eaa1a7bf45bf0a313f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Mar 2026 09:40:36 +0100 +Subject: tools/nolibc: MIPS: fix clobbers of 'lo' and 'hi' registers on + different ISAs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit e83b07dc8c05a55d02057b1484724a0b188f6f8d ] + +All MIPS ISAs before r6 use the 'lo' and 'hi' special registers. +These are clobbered by system calls and need to be marked as such to +avoid miscompilations. Currently nolibc ties the clobbers to the ABI. +But this is wrong and leads to ISA<->ABI combinations which are not +handled correctly, leading to compiler errors or miscompilations. + +Handle all different combinations of ABI and ISA. + +Fixes: a6a2a8a42972 ("tools/nolibc: MIPS: add support for N64 and N32 ABIs") +Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") +Suggested-by: Maciej W. Rozycki +Link: https://lore.kernel.org/lkml/alpine.DEB.2.21.2603141744240.55200@angie.orcam.me.uk/ +Signed-off-by: Thomas Weißschuh +Link: https://patch.msgid.link/20260317-nolibc-mips-clobber-v2-1-5b9a97761a9e@linutronix.de +Signed-off-by: Thomas Weißschuh +Signed-off-by: Sasha Levin +--- + tools/include/nolibc/arch-mips.h | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h +index a72506ceec6bd..0c5818149f17e 100644 +--- a/tools/include/nolibc/arch-mips.h ++++ b/tools/include/nolibc/arch-mips.h +@@ -39,11 +39,19 @@ + * - stack is 16-byte aligned + */ + ++#if !defined(__mips_isa_rev) || __mips_isa_rev < 6 ++#define _NOLIBC_SYSCALL_CLOBBER_HI_LO "hi", "lo" ++#else ++#define _NOLIBC_SYSCALL_CLOBBER_HI_LO "$0" ++#endif ++ + #if defined(_ABIO32) + + #define _NOLIBC_SYSCALL_CLOBBERLIST \ +- "memory", "cc", "at", "v1", "hi", "lo", \ +- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" ++ "memory", "cc", "at", "v1", \ ++ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", \ ++ _NOLIBC_SYSCALL_CLOBBER_HI_LO ++ + #define _NOLIBC_SYSCALL_STACK_RESERVE "addiu $sp, $sp, -32\n" + #define _NOLIBC_SYSCALL_STACK_UNRESERVE "addiu $sp, $sp, 32\n" + +@@ -52,7 +60,8 @@ + /* binutils, GCC and clang disagree about register aliases, use numbers instead. */ + #define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "cc", "at", "v1", \ +- "10", "11", "12", "13", "14", "15", "24", "25" ++ "10", "11", "12", "13", "14", "15", "24", "25", \ ++ _NOLIBC_SYSCALL_CLOBBER_HI_LO + + #define _NOLIBC_SYSCALL_STACK_RESERVE + #define _NOLIBC_SYSCALL_STACK_UNRESERVE +-- +2.53.0 + diff --git a/queue-7.0/tools-nolibc-printf-change-variables-c-to-ch-and-tmp.patch b/queue-7.0/tools-nolibc-printf-change-variables-c-to-ch-and-tmp.patch new file mode 100644 index 0000000000..907534369b --- /dev/null +++ b/queue-7.0/tools-nolibc-printf-change-variables-c-to-ch-and-tmp.patch @@ -0,0 +1,155 @@ +From 0cf24f39c55bf95fb0dcbbbb87b1eef6a40cca7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 10:17:24 +0000 +Subject: tools/nolibc/printf: Change variables 'c' to 'ch' and 'tmpbuf[]' to + 'outbuf[]' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: David Laight + +[ Upstream commit f675ae28fcdf7db93a8c1a6964f062725b1e06a0 ] + +Changing 'c' makes the code slightly easier to read because the variable +stands out from the single character literals (especially 'c'). + +Change tmpbuf[] to outbuf[] because 'out' points into it. + +The following patches pretty much rewrite the function so the +churn is limited. + +Signed-off-by: David Laight +Acked-by: Willy Tarreau +Link: https://patch.msgid.link/20260223101735.2922-7-david.laight.linux@gmail.com +Signed-off-by: Thomas Weißschuh +Stable-dep-of: 4045e7b19bbf ("tools/nolibc/printf: Move snprintf length check to callback") +Signed-off-by: Sasha Levin +--- + tools/include/nolibc/stdio.h | 38 ++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 19 deletions(-) + +diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h +index 233318b0d0f01..77d7669cdb806 100644 +--- a/tools/include/nolibc/stdio.h ++++ b/tools/include/nolibc/stdio.h +@@ -301,16 +301,16 @@ typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size); + static __attribute__((unused, format(printf, 4, 0))) + int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args) + { +- char escape, lpref, c; ++ char escape, lpref, ch; + unsigned long long v; + unsigned int written, width; + size_t len, ofs, w; +- char tmpbuf[21]; ++ char outbuf[21]; + const char *outstr; + + written = ofs = escape = lpref = 0; + while (1) { +- c = fmt[ofs++]; ++ ch = fmt[ofs++]; + width = 0; + + if (escape) { +@@ -318,17 +318,17 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + escape = 0; + + /* width */ +- while (c >= '0' && c <= '9') { ++ while (ch >= '0' && ch <= '9') { + width *= 10; +- width += c - '0'; ++ width += ch - '0'; + +- c = fmt[ofs++]; ++ ch = fmt[ofs++]; + } + +- if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') { +- char *out = tmpbuf; ++ if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') { ++ char *out = outbuf; + +- if (c == 'p') ++ if (ch == 'p') + v = va_arg(args, unsigned long); + else if (lpref) { + if (lpref > 1) +@@ -338,7 +338,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + } else + v = va_arg(args, unsigned int); + +- if (c == 'd') { ++ if (ch == 'd') { + /* sign-extend the value */ + if (lpref == 0) + v = (long long)(int)v; +@@ -346,7 +346,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + v = (long long)(long)v; + } + +- switch (c) { ++ switch (ch) { + case 'c': + out[0] = v; + out[1] = 0; +@@ -365,30 +365,30 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + u64toh_r(v, out); + break; + } +- outstr = tmpbuf; ++ outstr = outbuf; + } +- else if (c == 's') { ++ else if (ch == 's') { + outstr = va_arg(args, char *); + if (!outstr) + outstr="(null)"; + } +- else if (c == 'm') { ++ else if (ch == 'm') { + #ifdef NOLIBC_IGNORE_ERRNO + outstr = "unknown error"; + #else + outstr = strerror(errno); + #endif /* NOLIBC_IGNORE_ERRNO */ + } +- else if (c == '%') { ++ else if (ch == '%') { + /* queue it verbatim */ + continue; + } + else { + /* modifiers or final 0 */ +- if (c == 'l') { ++ if (ch == 'l') { + /* long format prefix, maintain the escape */ + lpref++; +- } else if (c == 'j') { ++ } else if (ch == 'j') { + lpref = 2; + } + escape = 1; +@@ -399,7 +399,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + } + + /* not an escape sequence */ +- if (c == 0 || c == '%') { ++ if (ch == 0 || ch == '%') { + /* flush pending data on escape or end */ + escape = 1; + lpref = 0; +@@ -420,7 +420,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + + written += len; + do_escape: +- if (c == 0) ++ if (ch == 0) + break; + fmt += ofs; + ofs = 0; +-- +2.53.0 + diff --git a/queue-7.0/tools-nolibc-printf-move-snprintf-length-check-to-ca.patch b/queue-7.0/tools-nolibc-printf-move-snprintf-length-check-to-ca.patch new file mode 100644 index 0000000000..b0f748c0d1 --- /dev/null +++ b/queue-7.0/tools-nolibc-printf-move-snprintf-length-check-to-ca.patch @@ -0,0 +1,184 @@ +From 383888d0406ea1a6081f2ad617210eb9f60748ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Mar 2026 10:17:54 +0000 +Subject: tools/nolibc/printf: Move snprintf length check to callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: David Laight + +[ Upstream commit 4045e7b19bbf7338452cda11e64cfe7ae3361964 ] + +Move output truncation to the snprintf() callback. +This simplifies the main code and fixes truncation of padded fields. + +Add a zero length callback to 'finalise' the buffer rather than +doing it in snprintf() itself. + +Fixes: e90ce42e81381 ("tools/nolibc: implement width padding in printf()") +Signed-off-by: David Laight +Acked-by: Willy Tarreau +Link: https://patch.msgid.link/20260302101815.3043-3-david.laight.linux@gmail.com +[Thomas: clean up Fixes trailer] +Signed-off-by: Thomas Weißschuh +Signed-off-by: Sasha Levin +--- + tools/include/nolibc/stdio.h | 94 +++++++++++++++++++++++++----------- + 1 file changed, 67 insertions(+), 27 deletions(-) + +diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h +index 77d7669cdb806..a4df72d9a2d37 100644 +--- a/tools/include/nolibc/stdio.h ++++ b/tools/include/nolibc/stdio.h +@@ -295,16 +295,25 @@ int fseek(FILE *stream, long offset, int whence) + * - %[l*]{d,u,c,x,p} + * - %s + * - unknown modifiers are ignored. ++ * ++ * Called by vfprintf() and snprintf() to do the actual formatting. ++ * The callers provide a callback function to save the formatted data. ++ * The callback function is called multiple times: ++ * - for each group of literal characters in the format string. ++ * - for field padding. ++ * - for each conversion specifier. ++ * - with (NULL, 0) at the end of the __nolibc_printf. ++ * If the callback returns non-zero __nolibc_printf() immediately returns -1. + */ +-typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size); ++typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size); + +-static __attribute__((unused, format(printf, 4, 0))) +-int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args) ++static __attribute__((unused, format(printf, 3, 0))) ++int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args) + { + char escape, lpref, ch; + unsigned long long v; + unsigned int written, width; +- size_t len, ofs, w; ++ size_t len, ofs; + char outbuf[21]; + const char *outstr; + +@@ -406,17 +415,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + outstr = fmt; + len = ofs - 1; + flush_str: +- if (n) { +- w = len < n ? len : n; +- n -= w; +- while (width-- > w) { +- if (cb(state, " ", 1) != 0) +- return -1; +- written += 1; +- } +- if (cb(state, outstr, w) != 0) ++ while (width-- > len) { ++ if (cb(state, " ", 1) != 0) + return -1; ++ written += 1; + } ++ if (cb(state, outstr, len) != 0) ++ return -1; + + written += len; + do_escape: +@@ -429,18 +434,25 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char + + /* literal char, just queue it */ + } ++ ++ /* Request a final '\0' be added to the snprintf() output. ++ * This may be the only call of the cb() function. ++ */ ++ if (cb(state, NULL, 0) != 0) ++ return -1; ++ + return written; + } + +-static int __nolibc_fprintf_cb(intptr_t state, const char *buf, size_t size) ++static int __nolibc_fprintf_cb(void *stream, const char *buf, size_t size) + { +- return _fwrite(buf, size, (FILE *)state); ++ return _fwrite(buf, size, stream); + } + + static __attribute__((unused, format(printf, 2, 0))) + int vfprintf(FILE *stream, const char *fmt, va_list args) + { +- return __nolibc_printf(__nolibc_fprintf_cb, (intptr_t)stream, SIZE_MAX, fmt, args); ++ return __nolibc_printf(__nolibc_fprintf_cb, stream, fmt, args); + } + + static __attribute__((unused, format(printf, 1, 0))) +@@ -498,26 +510,54 @@ int dprintf(int fd, const char *fmt, ...) + return ret; + } + +-static int __nolibc_sprintf_cb(intptr_t _state, const char *buf, size_t size) ++struct __nolibc_sprintf_cb_state { ++ char *buf; ++ size_t space; ++}; ++ ++static int __nolibc_sprintf_cb(void *v_state, const char *buf, size_t size) + { +- char **state = (char **)_state; ++ struct __nolibc_sprintf_cb_state *state = v_state; ++ size_t space = state->space; ++ char *tgt; ++ ++ /* Truncate the request to fit in the output buffer space. ++ * The last byte is reserved for the terminating '\0'. ++ * state->space can only be zero for snprintf(NULL, 0, fmt, args) ++ * so this normally lets through calls with 'size == 0'. ++ */ ++ if (size >= space) { ++ if (space <= 1) ++ return 0; ++ size = space - 1; ++ } ++ tgt = state->buf; ++ ++ /* __nolibc_printf() ends with cb(state, NULL, 0) to request the output ++ * buffer be '\0' terminated. ++ * That will be the only cb() call for, eg, snprintf(buf, sz, ""). ++ * Zero lengths can occur at other times (eg "%s" for an empty string). ++ * Unconditionally write the '\0' byte to reduce code size, it is ++ * normally overwritten by the data being output. ++ * There is no point adding a '\0' after copied data - there is always ++ * another call. ++ */ ++ *tgt = '\0'; ++ if (size) { ++ state->space = space - size; ++ state->buf = tgt + size; ++ memcpy(tgt, buf, size); ++ } + +- memcpy(*state, buf, size); +- *state += size; + return 0; + } + + static __attribute__((unused, format(printf, 3, 0))) + int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) + { +- char *state = buf; +- int ret; ++ struct __nolibc_sprintf_cb_state state = { .buf = buf, .space = size }; + +- ret = __nolibc_printf(__nolibc_sprintf_cb, (intptr_t)&state, size, fmt, args); +- if (ret < 0) +- return ret; +- buf[(size_t)ret < size ? (size_t)ret : size - 1] = '\0'; +- return ret; ++ return __nolibc_printf(__nolibc_sprintf_cb, &state, fmt, args); + } + + static __attribute__((unused, format(printf, 3, 4))) +-- +2.53.0 + diff --git a/queue-7.0/tools-power-turbostat-fix-amd-rapl-regression-on-big.patch b/queue-7.0/tools-power-turbostat-fix-amd-rapl-regression-on-big.patch new file mode 100644 index 0000000000..8af80710d2 --- /dev/null +++ b/queue-7.0/tools-power-turbostat-fix-amd-rapl-regression-on-big.patch @@ -0,0 +1,37 @@ +From 13db7cf98d3f39547af3cbbd372fdcfe4674494c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 17:26:33 -0400 +Subject: tools/power turbostat: Fix AMD RAPL regression on big systems + +From: Len Brown + +[ Upstream commit 3ae6bafa104d93ddc525b8de547bf66b43fcaf10 ] + +turbostat.c:8688: rapl_perf_init: Assertion `next_domain < num_domains' failed. + +The initial fix for this regression was incomplete, as it did not +handle multi-package systems with sparse core ids. + +Fixes: ef0e60083f76 ("tools/power turbostat: Fix AMD RAPL regression") +Signed-off-by: Len Brown +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index e9e8ef72395a9..bea574d7aa68a 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -5155,7 +5155,7 @@ static inline int get_rapl_num_domains(void) + if (!platform->has_per_core_rapl) + return topo.num_packages; + +- return topo.num_cores; ++ return GLOBAL_CORE_ID(topo.max_core_id, topo.num_packages) + 1; + } + + static inline int get_rapl_domain_id(int cpu) +-- +2.53.0 + diff --git a/queue-7.0/tools-power-turbostat-fix-cpu-set-0-regression-on-ht.patch b/queue-7.0/tools-power-turbostat-fix-cpu-set-0-regression-on-ht.patch new file mode 100644 index 0000000000..0a77597eb2 --- /dev/null +++ b/queue-7.0/tools-power-turbostat-fix-cpu-set-0-regression-on-ht.patch @@ -0,0 +1,83 @@ +From 97399f91bdaa19b024a0f8510f82d28f0ef1e712 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 16:17:31 -0400 +Subject: tools/power turbostat: Fix --cpu-set 0 regression on HT systems + +From: Len Brown + +[ Upstream commit 2c52f942fcf21c8e09c7dac669fca591cec2692b ] + +"turbostat --cpu-set 0" appears to hang if cpu0 has an HT sibling. + +This is because the initialization code recognizes that it does not +have to open perf files for the HT sibling, but the HT support +in the collection code sees the HT sibling and tries to read +from an uninitialized file descriptor, 0 (standard input). + +Access HT siblings only when they are in the allowed set. + +Fixes: a2b4d0f8bf07 ("tools/power turbostat: Favor cpu# over core#") +Signed-off-by: Len Brown +Reported-by: Artem Bityutskiy +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.c | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index d6b4fd17c5f37..7f61f07ceb314 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -2427,11 +2427,17 @@ char *sys_lpi_file_debugfs = "/sys/kernel/debug/pmc_core/slp_s0_residency_usec"; + + int cpu_is_not_present(int cpu) + { ++ if (cpu < 0) ++ return 1; ++ + return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set); + } + + int cpu_is_not_allowed(int cpu) + { ++ if (cpu < 0) ++ return 1; ++ + return !CPU_ISSET_S(cpu, cpu_allowed_setsize, cpu_allowed_set); + } + +@@ -2473,9 +2479,12 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk + int i; + + for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */ +- if (cpus[cpu].ht_sibling_cpu_id[i] <= 0) ++ int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; ++ ++ if (cpu_is_not_allowed(sibling_cpu_id)) + continue; +- t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]]; ++ ++ t = &thread_base[sibling_cpu_id]; + + retval |= func(t, c, p); + } +@@ -6252,10 +6261,13 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *, + int i; + + for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */ +- if (cpus[cpu].ht_sibling_cpu_id[i] <= 0) ++ int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; ++ ++ if (cpu_is_not_allowed(sibling_cpu_id)) + continue; +- t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]]; +- t2 = &thread_base2[cpus[cpu].ht_sibling_cpu_id[i]]; ++ ++ t = &thread_base[sibling_cpu_id]; ++ t2 = &thread_base2[sibling_cpu_id]; + + retval |= func(t, c, p, t2, c2, p2); + } +-- +2.53.0 + diff --git a/queue-7.0/tools-power-turbostat-fix-cpu-set-1-regression-on-ht.patch b/queue-7.0/tools-power-turbostat-fix-cpu-set-1-regression-on-ht.patch new file mode 100644 index 0000000000..7707b256a1 --- /dev/null +++ b/queue-7.0/tools-power-turbostat-fix-cpu-set-1-regression-on-ht.patch @@ -0,0 +1,211 @@ +From 34c6e72d248c4098c1134cd1253aa8bccd262482 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 18:35:15 -0400 +Subject: tools/power turbostat: Fix --cpu-set 1 regression on HT systems + +From: Len Brown + +[ Upstream commit 08e11edd0e63b72651ed5eb9142430d1ca764923 ] + +When the "--cpu-set" option limits turbostat to run on +a higher numbered HT sibling, it exits upon dividing by zero. + +This is because the HT support handles higher numbered siblings +at the same time as lower numbered siblings. But when that lower +number sibling is dis-allowed, the higher numbered sibling is +never processed. The result is a time delta of 0, which results +in a divide by 0 for any of the "per-second" metrics. + +Enhance the HT enumeration code to record all siblings (up to SMT4). +Consult this complete HT sibling list to determine when +to process an HT sibling, and when to skip it. + +Fixes: a2b4d0f8bf07 ("tools/power turbostat: Favor cpu# over core#") +Signed-off-by: Len Brown +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.c | 70 +++++++++++++++++++++------ + 1 file changed, 55 insertions(+), 15 deletions(-) + +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index 7f61f07ceb314..e609272ed80b5 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -2449,6 +2449,22 @@ int cpu_is_not_allowed(int cpu) + + #define PER_THREAD_PARAMS struct thread_data *t, struct core_data *c, struct pkg_data *p + ++int has_allowed_lower_ht_sibling(int cpu) ++{ ++ int i; ++ ++ for (i = 0; i <= cpus[cpu].ht_id; ++i) { ++ int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; ++ ++ if (sibling_cpu_id == cpu) ++ return 0; ++ ++ if (!cpu_is_not_allowed(sibling_cpu_id)) ++ return 1; ++ } ++ return 0; ++} ++ + int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pkg_data *), + struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base) + { +@@ -2466,7 +2482,7 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk + if (cpu_is_not_allowed(cpu)) + continue; + +- if (cpus[cpu].ht_id > 0) /* skip HT sibling */ ++ if (has_allowed_lower_ht_sibling(cpu)) /* skip HT sibling */ + continue; + + t = &thread_base[cpu]; +@@ -2475,12 +2491,18 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk + + retval |= func(t, c, p); + +- /* Handle HT sibling now */ ++ /* Handle other HT siblings now */ + int i; + +- for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */ ++ for (i = 0; i <= MAX_HT_ID; ++i) { + int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + ++ if (sibling_cpu_id < 0) ++ break; ++ ++ if (sibling_cpu_id == cpu) ++ continue; ++ + if (cpu_is_not_allowed(sibling_cpu_id)) + continue; + +@@ -6178,11 +6200,11 @@ int set_thread_siblings(struct cpu_topology *thiscpu) + int cpu = thiscpu->cpu_id; + int offset = topo.max_cpu_num + 1; + size_t size; +- int thread_id = 0; ++ int ht_id = 0; + + thiscpu->put_ids = CPU_ALLOC((topo.max_cpu_num + 1)); + if (thiscpu->ht_id < 0) +- thiscpu->ht_id = thread_id++; ++ thiscpu->ht_id = 0; /* first CPU in core */ + if (!thiscpu->put_ids) + return -1; + +@@ -6206,13 +6228,9 @@ int set_thread_siblings(struct cpu_topology *thiscpu) + sib_core = get_core_id(so); + if (sib_core == thiscpu->core_id) { + CPU_SET_S(so, size, thiscpu->put_ids); +- if ((so != cpu) && (cpus[so].ht_id < 0)) { +- cpus[so].ht_id = thread_id; +- cpus[cpu].ht_sibling_cpu_id[thread_id] = so; +- if (debug) +- fprintf(stderr, "%s: cpu%d.ht_sibling_cpu_id[%d] = %d\n", __func__, cpu, thread_id, so); +- thread_id += 1; +- } ++ cpus[so].ht_id = ht_id; ++ cpus[cpu].ht_sibling_cpu_id[ht_id] = so; ++ ht_id += 1; + } + } + } +@@ -6245,7 +6263,7 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *, + if (cpu_is_not_allowed(cpu)) + continue; + +- if (cpus[cpu].ht_id > 0) /* skip HT sibling */ ++ if (has_allowed_lower_ht_sibling(cpu)) /* skip HT sibling */ + continue; + + t = &thread_base[cpu]; +@@ -6260,9 +6278,15 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *, + /* Handle HT sibling now */ + int i; + +- for (i = MAX_HT_ID; i > 0; --i) { /* ht_id 0 is self */ ++ for (i = 0; i <= MAX_HT_ID; ++i) { + int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + ++ if (sibling_cpu_id < 0) ++ break; ++ ++ if (sibling_cpu_id == cpu) ++ continue; ++ + if (cpu_is_not_allowed(sibling_cpu_id)) + continue; + +@@ -9517,6 +9541,8 @@ void topology_probe(bool startup) + cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); + CPU_ZERO_S(cpu_present_setsize, cpu_present_set); + for_all_proc_cpus(mark_cpu_present); ++ if (debug) ++ print_cpu_set("present set", cpu_present_set); + + /* + * Allocate and initialize cpu_possible_set +@@ -9527,6 +9553,8 @@ void topology_probe(bool startup) + cpu_possible_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); + CPU_ZERO_S(cpu_possible_setsize, cpu_possible_set); + initialize_cpu_set_from_sysfs(cpu_possible_set, "/sys/devices/system/cpu", "possible"); ++ if (debug) ++ print_cpu_set("possible set", cpu_possible_set); + + /* + * Allocate and initialize cpu_effective_set +@@ -9537,6 +9565,8 @@ void topology_probe(bool startup) + cpu_effective_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); + CPU_ZERO_S(cpu_effective_setsize, cpu_effective_set); + update_effective_set(startup); ++ if (debug) ++ print_cpu_set("effective set", cpu_effective_set); + + /* + * Allocate and initialize cpu_allowed_set +@@ -9580,6 +9610,8 @@ void topology_probe(bool startup) + + CPU_SET_S(i, cpu_allowed_setsize, cpu_allowed_set); + } ++ if (debug) ++ print_cpu_set("allowed set", cpu_allowed_set); + + if (!CPU_COUNT_S(cpu_allowed_setsize, cpu_allowed_set)) + err(-ENODEV, "No valid cpus found"); +@@ -9683,12 +9715,18 @@ void topology_probe(bool startup) + return; + + for (i = 0; i <= topo.max_cpu_num; ++i) { ++ int ht_id; ++ + if (cpu_is_not_present(i)) + continue; + fprintf(outf, +- "cpu %d pkg %d die %d l3 %d node %d lnode %d core %d thread %d\n", ++ "cpu %d pkg %d die %d l3 %d node %d lnode %d core %d ht_id %d", + i, cpus[i].package_id, cpus[i].die_id, cpus[i].l3_id, + cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].core_id, cpus[i].ht_id); ++ fprintf(outf, " siblings"); ++ for (ht_id = 0; ht_id <= MAX_HT_ID; ++ht_id) ++ fprintf(outf, " %d", cpus[i].ht_sibling_cpu_id[ht_id]); ++ fprintf(outf, "\n"); + } + + } +@@ -9829,6 +9867,8 @@ void topology_update(void) + topo.allowed_cores = 0; + topo.allowed_packages = 0; + for_all_cpus(update_topo, ODD_COUNTERS); ++ if (debug) ++ fprintf(stderr, "allowed_cpus %d allowed_cores %d allowed_packages %d\n", topo.allowed_cpus, topo.allowed_cores, topo.allowed_packages); + } + + void setup_all_buffers(bool startup) +-- +2.53.0 + diff --git a/queue-7.0/tools-power-turbostat-fix-unrecognized-option-p.patch b/queue-7.0/tools-power-turbostat-fix-unrecognized-option-p.patch new file mode 100644 index 0000000000..0c08dd86db --- /dev/null +++ b/queue-7.0/tools-power-turbostat-fix-unrecognized-option-p.patch @@ -0,0 +1,41 @@ +From df887dbb5f8c1b09900c681081df73e62ea80f7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Apr 2026 10:32:17 -0400 +Subject: tools/power turbostat: Fix unrecognized option '-P' + +From: David Arcari + +[ Upstream commit ce012c966b518c53475ba9a4e979242d7322d819 ] + +The '-P' short option (shorthand for --no-perf) is not present in the +optstring of the second call to getopt_long_only(). This results in +the "unrecognized option" error when the tool reaches the main parsing +loop. + +Add 'P' to the second getopt_long_only() call to ensure it is +consistently recognized. + +Fixes: a0e86c90b83c ("tools/power turbostat: Add --no-perf option") +Signed-off-by: David Arcari +Signed-off-by: Len Brown +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index bea574d7aa68a..d6b4fd17c5f37 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -11449,7 +11449,7 @@ void cmdline(int argc, char **argv) + } + optind = 0; + +- while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMST:v", long_options, &option_index)) != -1) { ++ while ((opt = getopt_long_only(argc, argv, "+C:c:Dde:hi:Jn:N:o:qMPST:v", long_options, &option_index)) != -1) { + switch (opt) { + case 'a': + parse_add_command(optarg); +-- +2.53.0 + diff --git a/queue-7.0/tools-rtla-generate-optstring-from-long-options.patch b/queue-7.0/tools-rtla-generate-optstring-from-long-options.patch new file mode 100644 index 0000000000..40c3d0a5c1 --- /dev/null +++ b/queue-7.0/tools-rtla-generate-optstring-from-long-options.patch @@ -0,0 +1,164 @@ +From 5e330ed3beb7d9210dd7f9ccff32e143038a30b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Jan 2026 11:49:55 +0200 +Subject: tools/rtla: Generate optstring from long options + +From: Costa Shulyupin + +[ Upstream commit 4a1cec7450b7159a0ee57403f44460ac4d618b4f ] + +getopt_long() processes short and long options independently. +RTLA, like the majority of applications, uses both short and long +variants for each logical option. + +Since the val member of struct option holds the letter of the short +variant, the string of short options can be reconstructed from the +array of long options. + +Add getopt_auto() to generate optstring from an array of long options, +eliminating the need to maintain separate short option strings. + +Signed-off-by: Costa Shulyupin +Reviewed-by: Wander Lairson Costa +Link: https://lore.kernel.org/r/20260108095011.2115719-1-costa.shul@redhat.com +Signed-off-by: Tomas Glozar +Stable-dep-of: be8058f31b4e ("rtla: Fix segfault on multiple SIGINTs") +Signed-off-by: Sasha Levin +--- + tools/tracing/rtla/src/common.c | 32 +++++++++++++++++++++++++- + tools/tracing/rtla/src/common.h | 2 ++ + tools/tracing/rtla/src/osnoise_hist.c | 3 +-- + tools/tracing/rtla/src/osnoise_top.c | 3 +-- + tools/tracing/rtla/src/timerlat_hist.c | 3 +-- + tools/tracing/rtla/src/timerlat_top.c | 3 +-- + 6 files changed, 37 insertions(+), 9 deletions(-) + +diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c +index ceff76a62a30b..f310b0d59ad3e 100644 +--- a/tools/tracing/rtla/src/common.c ++++ b/tools/tracing/rtla/src/common.c +@@ -39,6 +39,36 @@ static void set_signals(struct common_params *params) + } + } + ++/* ++ * getopt_auto - auto-generates optstring from long_options ++ */ ++int getopt_auto(int argc, char **argv, const struct option *long_opts) ++{ ++ char opts[256]; ++ int n = 0; ++ ++ for (int i = 0; long_opts[i].name; i++) { ++ if (long_opts[i].val < 32 || long_opts[i].val > 127) ++ continue; ++ ++ if (n + 4 >= sizeof(opts)) ++ fatal("optstring buffer overflow"); ++ ++ opts[n++] = long_opts[i].val; ++ ++ if (long_opts[i].has_arg == required_argument) ++ opts[n++] = ':'; ++ else if (long_opts[i].has_arg == optional_argument) { ++ opts[n++] = ':'; ++ opts[n++] = ':'; ++ } ++ } ++ ++ opts[n] = '\0'; ++ ++ return getopt_long(argc, argv, opts, long_opts, NULL); ++} ++ + /* + * common_parse_options - parse common command line options + * +@@ -69,7 +99,7 @@ int common_parse_options(int argc, char **argv, struct common_params *common) + }; + + opterr = 0; +- c = getopt_long(argc, argv, "c:C::Dd:e:H:P:", long_options, NULL); ++ c = getopt_auto(argc, argv, long_options); + opterr = 1; + + switch (c) { +diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h +index 7602c5593ef5d..d4b3715700be7 100644 +--- a/tools/tracing/rtla/src/common.h ++++ b/tools/tracing/rtla/src/common.h +@@ -1,6 +1,7 @@ + /* SPDX-License-Identifier: GPL-2.0 */ + #pragma once + ++#include + #include "actions.h" + #include "timerlat_u.h" + #include "trace.h" +@@ -156,6 +157,7 @@ int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us); + int osnoise_set_stop_total_us(struct osnoise_context *context, + long long stop_total_us); + ++int getopt_auto(int argc, char **argv, const struct option *long_opts); + int common_parse_options(int argc, char **argv, struct common_params *common); + int common_apply_config(struct osnoise_tool *tool, struct common_params *params); + int top_main_loop(struct osnoise_tool *tool); +diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c +index 9d70ea34807ff..5c863e7aad28b 100644 +--- a/tools/tracing/rtla/src/osnoise_hist.c ++++ b/tools/tracing/rtla/src/osnoise_hist.c +@@ -506,8 +506,7 @@ static struct common_params + if (common_parse_options(argc, argv, ¶ms->common)) + continue; + +- c = getopt_long(argc, argv, "a:b:E:hp:r:s:S:t::T:01234:5:6:7:", +- long_options, NULL); ++ c = getopt_auto(argc, argv, long_options); + + /* detect the end of the options. */ + if (c == -1) +diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c +index d54d47947fb44..b7aed40fd2164 100644 +--- a/tools/tracing/rtla/src/osnoise_top.c ++++ b/tools/tracing/rtla/src/osnoise_top.c +@@ -358,8 +358,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) + if (common_parse_options(argc, argv, ¶ms->common)) + continue; + +- c = getopt_long(argc, argv, "a:hp:qr:s:S:t::T:0:1:2:3:", +- long_options, NULL); ++ c = getopt_auto(argc, argv, long_options); + + /* Detect the end of the options. */ + if (c == -1) +diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c +index 4e8c38a61197c..096de8ba3efbb 100644 +--- a/tools/tracing/rtla/src/timerlat_hist.c ++++ b/tools/tracing/rtla/src/timerlat_hist.c +@@ -825,8 +825,7 @@ static struct common_params + if (common_parse_options(argc, argv, ¶ms->common)) + continue; + +- c = getopt_long(argc, argv, "a:b:E:hi:knp:s:t::T:uU0123456:7:8:9\1\2:\3:", +- long_options, NULL); ++ c = getopt_auto(argc, argv, long_options); + + /* detect the end of the options. */ + if (c == -1) +diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c +index 284b74773c2b5..27c14aa71a8bc 100644 +--- a/tools/tracing/rtla/src/timerlat_top.c ++++ b/tools/tracing/rtla/src/timerlat_top.c +@@ -588,8 +588,7 @@ static struct common_params + if (common_parse_options(argc, argv, ¶ms->common)) + continue; + +- c = getopt_long(argc, argv, "a:hi:knp:qs:t::T:uU0:1:2:345:6:7:", +- long_options, NULL); ++ c = getopt_auto(argc, argv, long_options); + + /* detect the end of the options. */ + if (c == -1) +-- +2.53.0 + diff --git a/queue-7.0/tools-sched_ext-fix-off-by-one-in-scx_sdt-payload-ze.patch b/queue-7.0/tools-sched_ext-fix-off-by-one-in-scx_sdt-payload-ze.patch new file mode 100644 index 0000000000..06825e3680 --- /dev/null +++ b/queue-7.0/tools-sched_ext-fix-off-by-one-in-scx_sdt-payload-ze.patch @@ -0,0 +1,57 @@ +From aba206593159d75ae4cfdc18c035c61de0d010ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Mar 2026 17:18:33 +0800 +Subject: tools/sched_ext: Fix off-by-one in scx_sdt payload zeroing + +From: Cheng-Yang Chou + +[ Upstream commit a3c3fb2f86f8a1f266747622037f90eab58186ad ] + +scx_alloc_free_idx() zeroes the payload of a freed arena allocation +one word at a time. The loop bound was alloc->pool.elem_size / 8, but +elem_size includes sizeof(struct sdt_data) (the 8-byte union sdt_id +header). This caused the loop to write one extra u64 past the +allocation, corrupting the tid field of the adjacent pool element. + +Fix the loop bound to (elem_size - sizeof(struct sdt_data)) / 8 so +only the payload portion is zeroed. + +Test plan: +- Add a temporary sanity check in scx_task_free() before the free call: + + if (mval->data->tid.idx != mval->tid.idx) + scx_bpf_error("tid corruption: arena=%d storage=%d", + mval->data->tid.idx, (int)mval->tid.idx); + +- stress-ng --fork 100 -t 10 & sudo ./build/bin/scx_sdt + +Without this fix, running scx_sdt under fork-heavy load triggers the +corruption error. With the fix applied, the same workload completes +without error. + +Fixes: 36929ebd17ae ("tools/sched_ext: add arena based scheduler") +Signed-off-by: Cheng-Yang Chou +Reviewed-by: Emil Tsalapatis +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + tools/sched_ext/scx_sdt.bpf.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/sched_ext/scx_sdt.bpf.c b/tools/sched_ext/scx_sdt.bpf.c +index 31b09958e8d5f..2e2179d0f509e 100644 +--- a/tools/sched_ext/scx_sdt.bpf.c ++++ b/tools/sched_ext/scx_sdt.bpf.c +@@ -317,7 +317,8 @@ int scx_alloc_free_idx(struct scx_allocator *alloc, __u64 idx) + }; + + /* Zero out one word at a time. */ +- for (i = zero; i < alloc->pool.elem_size / 8 && can_loop; i++) { ++ for (i = zero; i < (alloc->pool.elem_size - sizeof(struct sdt_data)) / 8 ++ && can_loop; i++) { + data->payload[i] = 0; + } + } +-- +2.53.0 + diff --git a/queue-7.0/tools-sched_ext-scx_pair-fix-pair_ctx-indexing-for-c.patch b/queue-7.0/tools-sched_ext-scx_pair-fix-pair_ctx-indexing-for-c.patch new file mode 100644 index 0000000000..25a383043d --- /dev/null +++ b/queue-7.0/tools-sched_ext-scx_pair-fix-pair_ctx-indexing-for-c.patch @@ -0,0 +1,77 @@ +From cf2dc02e8970fdf78139ae3b5fab774cd06d7431 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Mar 2026 10:51:55 +0800 +Subject: tools/sched_ext: scx_pair: fix pair_ctx indexing for CPU pairs + +From: Zhao Mengmeng + +[ Upstream commit f546c77038ab898726e7344255217fbec382b97f ] + +scx_pair sizes pair_ctx to nr_cpu_ids / 2, so valid pair_ctx keys are +dense pair indexes in the range [0, nr_cpu_ids / 2). + +However, the userspace setup code stores pair_id as the first CPU number +in each pair. On an 8-CPU system with "-S 1", that produces pair IDs +0, 2, 4 and 6 for pairs [0,1], [2,3], [4,5] and [6,7]. CPUs in the +latter half then look up pair_ctx with out-of-range keys and the BPF +scheduler aborts with: + +EXIT: scx_bpf_error (scx_pair.bpf.c:328: failed to lookup pairc and +in_pair_mask for cpu[5]) + +Assign pair_id using a dense pair counter instead so that each CPU pair +maps to a valid pair_ctx entry. Besides, reject odd CPU configuration, as +scx_pair requires all CPUs to be paired. + +Fixes: f0262b102c7c ("tools/sched_ext: add scx_pair scheduler") +Signed-off-by: Zhao Mengmeng +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + tools/sched_ext/scx_pair.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/tools/sched_ext/scx_pair.c b/tools/sched_ext/scx_pair.c +index 2e509391f3dab..eb1bea2dd0ccc 100644 +--- a/tools/sched_ext/scx_pair.c ++++ b/tools/sched_ext/scx_pair.c +@@ -48,6 +48,7 @@ int main(int argc, char **argv) + struct bpf_link *link; + __u64 seq = 0, ecode; + __s32 stride, i, opt, outer_fd; ++ __u32 pair_id = 0; + + libbpf_set_print(libbpf_print_fn); + signal(SIGINT, sigint_handler); +@@ -82,6 +83,14 @@ int main(int argc, char **argv) + scx_pair__destroy(skel); + return -1; + } ++ ++ if (skel->rodata->nr_cpu_ids & 1) { ++ fprintf(stderr, "scx_pair requires an even CPU count, got %u\n", ++ skel->rodata->nr_cpu_ids); ++ scx_pair__destroy(skel); ++ return -1; ++ } ++ + bpf_map__set_max_entries(skel->maps.pair_ctx, skel->rodata->nr_cpu_ids / 2); + + /* Resize arrays so their element count is equal to cpu count. */ +@@ -109,10 +118,11 @@ int main(int argc, char **argv) + + skel->rodata_pair_cpu->pair_cpu[i] = j; + skel->rodata_pair_cpu->pair_cpu[j] = i; +- skel->rodata_pair_id->pair_id[i] = i; +- skel->rodata_pair_id->pair_id[j] = i; ++ skel->rodata_pair_id->pair_id[i] = pair_id; ++ skel->rodata_pair_id->pair_id[j] = pair_id; + skel->rodata_in_pair_idx->in_pair_idx[i] = 0; + skel->rodata_in_pair_idx->in_pair_idx[j] = 1; ++ pair_id++; + + printf("[%d, %d] ", i, j); + } +-- +2.53.0 + diff --git a/queue-7.0/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch b/queue-7.0/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch new file mode 100644 index 0000000000..0a88f4cb99 --- /dev/null +++ b/queue-7.0/tracing-branch-fix-inverted-check-on-stat-tracer-reg.patch @@ -0,0 +1,69 @@ +From 1a8959d48b0fa28eabc92b5f9e36890ba8cc4d76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 06:25:09 -0700 +Subject: tracing: branch: Fix inverted check on stat tracer registration + +From: Breno Leitao + +[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ] + +init_annotated_branch_stats() and all_annotated_branch_stats() check the +return value of register_stat_tracer() with "if (!ret)", but +register_stat_tracer() returns 0 on success and a negative errno on +failure. The inverted check causes the warning to be printed on every +successful registration, e.g.: + + Warning: could not register annotated branches stats + +while leaving real failures silent. The initcall also returned a +hard-coded 1 instead of the actual error. + +Invert the check and propagate ret so that the warning fires on real +errors and the initcall reports the correct status. + +Cc: Mathieu Desnoyers +Cc: Ingo Molnar +Cc: Frederic Weisbecker +Link: https://patch.msgid.link/20260420-tracing-v1-1-d8f4cd0d6af1@debian.org +Fixes: 002bb86d8d42 ("tracing/ftrace: separate events tracing and stats tracing engine") +Signed-off-by: Breno Leitao +Acked-by: Masami Hiramatsu (Google) +Signed-off-by: Steven Rostedt +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_branch.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c +index 6809b370e991d..d1564db95a8f5 100644 +--- a/kernel/trace/trace_branch.c ++++ b/kernel/trace/trace_branch.c +@@ -373,10 +373,10 @@ __init static int init_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&annotated_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "annotated branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +@@ -438,10 +438,10 @@ __init static int all_annotated_branch_stats(void) + int ret; + + ret = register_stat_tracer(&all_branch_stats); +- if (!ret) { ++ if (ret) { + printk(KERN_WARNING "Warning: could not register " + "all branches stats\n"); +- return 1; ++ return ret; + } + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/tracing-move-__printf-attribute-on-__ftrace_vbprintk.patch b/queue-7.0/tracing-move-__printf-attribute-on-__ftrace_vbprintk.patch new file mode 100644 index 0000000000..df1b78de8f --- /dev/null +++ b/queue-7.0/tracing-move-__printf-attribute-on-__ftrace_vbprintk.patch @@ -0,0 +1,81 @@ +From 575f06e70ab3f739627f3d825bdf28f4e90dac57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 17:45:29 +0100 +Subject: tracing: move __printf() attribute on __ftrace_vbprintk() + +From: Arnd Bergmann + +[ Upstream commit 473e470f16f98569d59adc11c4a318780fb68fe9 ] + +The sunrpc change to use trace_printk() for debugging caused +a new warning for every instance of dprintk() in some configurations, +when -Wformat-security is enabled: + +fs/nfs/getroot.c: In function 'nfs_get_root': +fs/nfs/getroot.c:90:17: error: format not a string literal and no format arguments [-Werror=format-security] + 90 | nfs_errorf(fc, "NFS: Couldn't getattr on root"); + +I've been slowly chipping away at those warnings over time with the +intention of enabling them by default in the future. While I could not +figure out why this only happens for this one instance, I see that the +__trace_bprintk() function is always called with a local variable as +the format string, rather than a literal. + +Move the __printf(2,3) annotation on this function from the declaration +to the caller. As this is can only be validated for literals, the +attribute on the declaration causes the warnings every time, but +removing it entirely introduces a new warning on the __ftrace_vbprintk() +definition. + +The format strings still get checked because the underlying literal keeps +getting passed into __trace_printk() in the "else" branch, which is not +taken but still evaluated for compile-time warnings. + +Cc: Masami Hiramatsu +Cc: Anna Schumaker +Cc: Chuck Lever +Cc: Simon Horman +Cc: Mathieu Desnoyers +Cc: Andrew Morton +Cc: Yury Norov +Cc: Randy Dunlap +Link: https://patch.msgid.link/20260203164545.3174910-1-arnd@kernel.org +Fixes: ec7d8e68ef0e ("sunrpc: add a Kconfig option to redirect dfprintk() output to trace buffer") +Acked-by: Jeff Layton +Acked-by: Steven Rostedt (Google) +Signed-off-by: Arnd Bergmann +Acked-by: Andy Shevchenko +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + include/linux/trace_printk.h | 1 - + kernel/trace/trace_printk.c | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/trace_printk.h b/include/linux/trace_printk.h +index bb5874097f24e..2670ec7f42629 100644 +--- a/include/linux/trace_printk.h ++++ b/include/linux/trace_printk.h +@@ -107,7 +107,6 @@ do { \ + __trace_printk(_THIS_IP_, fmt, ##args); \ + } while (0) + +-extern __printf(2, 3) + int __trace_bprintk(unsigned long ip, const char *fmt, ...); + + extern __printf(2, 3) +diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c +index 5ea5e0d76f00b..3ea17af601695 100644 +--- a/kernel/trace/trace_printk.c ++++ b/kernel/trace/trace_printk.c +@@ -197,6 +197,7 @@ struct notifier_block module_trace_bprintk_format_nb = { + .notifier_call = module_trace_bprintk_format_notify, + }; + ++__printf(2, 3) + int __trace_bprintk(unsigned long ip, const char *fmt, ...) + { + int ret; +-- +2.53.0 + diff --git a/queue-7.0/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch b/queue-7.0/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch new file mode 100644 index 0000000000..a4db7d7e01 --- /dev/null +++ b/queue-7.0/tracing-rebuild-full_name-on-each-hist_field_name-ca.patch @@ -0,0 +1,56 @@ +From 7130db8cce7d46ae4f4601cf15fb830206bce9ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Apr 2026 19:22:23 +0800 +Subject: tracing: Rebuild full_name on each hist_field_name() call + +From: Pengpeng Hou + +[ Upstream commit 5ec1d1e97de134beed3a5b08235a60fc1c51af96 ] + +hist_field_name() uses a static MAX_FILTER_STR_VAL buffer for fully +qualified variable-reference names, but it currently appends into that +buffer with strcat() without rebuilding it first. As a result, repeated +calls append a new "system.event.field" name onto the previous one, +which can eventually run past the end of full_name. + +Build the name with snprintf() on each call and return NULL if the fully +qualified name does not fit in MAX_FILTER_STR_VAL. + +Link: https://patch.msgid.link/20260401112224.85582-1-pengpeng@iscas.ac.cn +Fixes: 067fe038e70f ("tracing: Add variable reference handling to hist triggers") +Reviewed-by: Tom Zanussi +Tested-by: Tom Zanussi +Signed-off-by: Pengpeng Hou +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 73ea180cad555..f9c8a4f078ea0 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -1361,12 +1361,14 @@ static const char *hist_field_name(struct hist_field *field, + field->flags & HIST_FIELD_FL_VAR_REF) { + if (field->system) { + static char full_name[MAX_FILTER_STR_VAL]; ++ int len; ++ ++ len = snprintf(full_name, sizeof(full_name), "%s.%s.%s", ++ field->system, field->event_name, ++ field->name); ++ if (len >= sizeof(full_name)) ++ return NULL; + +- strcat(full_name, field->system); +- strcat(full_name, "."); +- strcat(full_name, field->event_name); +- strcat(full_name, "."); +- strcat(full_name, field->name); + field_name = full_name; + } else + field_name = field->name; +-- +2.53.0 + diff --git a/queue-7.0/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch b/queue-7.0/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch new file mode 100644 index 0000000000..185f5d62b5 --- /dev/null +++ b/queue-7.0/tty-hvc_iucv-fix-off-by-one-in-number-of-supported-d.patch @@ -0,0 +1,50 @@ +From fabebae4ec8bb9c104e3093b06c7617a23a4ed58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Jan 2026 23:29:37 -0800 +Subject: tty: hvc_iucv: fix off-by-one in number of supported devices + +From: Randy Dunlap + +[ Upstream commit f2a880e802ad12d1e38039d1334fb1475d0f5241 ] + +MAX_HVC_IUCV_LINES == HVC_ALLOC_TTY_ADAPTERS == 8. +This is the number of entries in: + static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; + +Sometimes hvc_iucv_table[] is limited by: +(a) if (num > hvc_iucv_devices) // for error detection +or +(b) for (i = 0; i < hvc_iucv_devices; i++) // in 2 places +(so these 2 don't agree; second one appears to be correct to me.) + +hvc_iucv_devices can be 0..8. This is a counter. +(c) if (hvc_iucv_devices > MAX_HVC_IUCV_LINES) + +If hvc_iucv_devices == 8, (a) allows the code to access hvc_iucv_table[8]. +Oops. + +Fixes: 44a01d5ba8a4 ("[S390] s390/hvc_console: z/VM IUCV hypervisor console support") +Signed-off-by: Randy Dunlap +Link: https://patch.msgid.link/20260130072939.1535869-1-rdunlap@infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/hvc/hvc_iucv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c +index 1dcdb9e99bd8a..37db8a3e5158e 100644 +--- a/drivers/tty/hvc/hvc_iucv.c ++++ b/drivers/tty/hvc/hvc_iucv.c +@@ -130,7 +130,7 @@ static struct iucv_handler hvc_iucv_handler = { + */ + static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) + { +- if (num > hvc_iucv_devices) ++ if (num >= hvc_iucv_devices) + return NULL; + return hvc_iucv_table[num]; + } +-- +2.53.0 + diff --git a/queue-7.0/tty-serial-ip22zilog-fix-section-mispatch-warning.patch b/queue-7.0/tty-serial-ip22zilog-fix-section-mispatch-warning.patch new file mode 100644 index 0000000000..c567f33671 --- /dev/null +++ b/queue-7.0/tty-serial-ip22zilog-fix-section-mispatch-warning.patch @@ -0,0 +1,39 @@ +From 628314792b7dee7272aeafdcb5e369f7f1ad3283 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Apr 2026 12:21:53 +0200 +Subject: tty: serial: ip22zilog: Fix section mispatch warning + +From: Thomas Bogendoerfer + +[ Upstream commit a1a81aef99e853dec84241d701fbf587d713eb5b ] + +ip22zilog_prepare() is now called by driver probe routine, so it +shouldn't be in the __init section any longer. + +Fixes: 3fc36ae6abd2 ("tty: serial: ip22zilog: Use platform device for probing") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202604020945.c9jAvCPs-lkp@intel.com/ +Signed-off-by: Thomas Bogendoerfer +Link: https://patch.msgid.link/20260402102154.136620-1-tbogendoerfer@suse.de +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/ip22zilog.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c +index 6e19c6713849a..a12101dc05546 100644 +--- a/drivers/tty/serial/ip22zilog.c ++++ b/drivers/tty/serial/ip22zilog.c +@@ -1025,7 +1025,7 @@ static struct uart_driver ip22zilog_reg = { + #endif + }; + +-static void __init ip22zilog_prepare(struct uart_ip22zilog_port *up) ++static void ip22zilog_prepare(struct uart_ip22zilog_port *up) + { + unsigned char sysrq_on = IS_ENABLED(CONFIG_SERIAL_IP22_ZILOG_CONSOLE); + int brg; +-- +2.53.0 + diff --git a/queue-7.0/ublk-reset-per-io-canceled-flag-on-each-fetch.patch b/queue-7.0/ublk-reset-per-io-canceled-flag-on-each-fetch.patch new file mode 100644 index 0000000000..cf715b99dd --- /dev/null +++ b/queue-7.0/ublk-reset-per-io-canceled-flag-on-each-fetch.patch @@ -0,0 +1,102 @@ +From 194434799d35dd5f4d6d5108beead1e548174b42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Apr 2026 22:25:30 -0600 +Subject: ublk: reset per-IO canceled flag on each fetch + +From: Uday Shankar + +[ Upstream commit 0842186d2c4e67d2f8c8c2d1d779e8acffd41b5b ] + +If a ublk server starts recovering devices but dies before issuing fetch +commands for all IOs, cancellation of the fetch commands that were +successfully issued may never complete. This is because the per-IO +canceled flag can remain set even after the fetch for that IO has been +submitted - the per-IO canceled flags for all IOs in a queue are reset +together only once all IOs for that queue have been fetched. So if a +nonempty proper subset of the IOs for a queue are fetched when the ublk +server dies, the IOs in that subset will never successfully be canceled, +as their canceled flags remain set, and this prevents ublk_cancel_cmd +from actually calling io_uring_cmd_done on the commands, despite the +fact that they are outstanding. + +Fix this by resetting the per-IO cancel flags immediately when each IO +is fetched instead of waiting for all IOs for the queue (which may never +happen). + +Signed-off-by: Uday Shankar +Fixes: 728cbac5fe21 ("ublk: move device reset into ublk_ch_release()") +Reviewed-by: Ming Lei +Reviewed-by: zhang, the-essence-of-life +Link: https://patch.msgid.link/20260405-cancel-v2-1-02d711e643c2@purestorage.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/ublk_drv.c | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index 63aeb7a76a8c9..0bdb804fca839 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -2910,22 +2910,26 @@ static void ublk_stop_dev(struct ublk_device *ub) + ublk_cancel_dev(ub); + } + ++static void ublk_reset_io_flags(struct ublk_queue *ubq, struct ublk_io *io) ++{ ++ /* UBLK_IO_FLAG_CANCELED can be cleared now */ ++ spin_lock(&ubq->cancel_lock); ++ io->flags &= ~UBLK_IO_FLAG_CANCELED; ++ spin_unlock(&ubq->cancel_lock); ++} ++ + /* reset per-queue io flags */ + static void ublk_queue_reset_io_flags(struct ublk_queue *ubq) + { +- int j; +- +- /* UBLK_IO_FLAG_CANCELED can be cleared now */ + spin_lock(&ubq->cancel_lock); +- for (j = 0; j < ubq->q_depth; j++) +- ubq->ios[j].flags &= ~UBLK_IO_FLAG_CANCELED; + ubq->canceling = false; + spin_unlock(&ubq->cancel_lock); + ubq->fail_io = false; + } + + /* device can only be started after all IOs are ready */ +-static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id) ++static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id, ++ struct ublk_io *io) + __must_hold(&ub->mutex) + { + struct ublk_queue *ubq = ublk_get_queue(ub, q_id); +@@ -2934,6 +2938,7 @@ static void ublk_mark_io_ready(struct ublk_device *ub, u16 q_id) + ub->unprivileged_daemons = true; + + ubq->nr_io_ready++; ++ ublk_reset_io_flags(ubq, io); + + /* Check if this specific queue is now fully ready */ + if (ublk_queue_ready(ubq)) { +@@ -3196,7 +3201,7 @@ static int ublk_fetch(struct io_uring_cmd *cmd, struct ublk_device *ub, + if (!ret) + ret = ublk_config_io_buf(ub, io, cmd, buf_addr, NULL); + if (!ret) +- ublk_mark_io_ready(ub, q_id); ++ ublk_mark_io_ready(ub, q_id, io); + mutex_unlock(&ub->mutex); + return ret; + } +@@ -3604,7 +3609,7 @@ static int ublk_batch_prep_io(struct ublk_queue *ubq, + ublk_io_unlock(io); + + if (!ret) +- ublk_mark_io_ready(data->ub, ubq->q_id); ++ ublk_mark_io_ready(data->ub, ubq->q_id, io); + + return ret; + } +-- +2.53.0 + diff --git a/queue-7.0/udp-force-compute_score-to-always-inline.patch b/queue-7.0/udp-force-compute_score-to-always-inline.patch new file mode 100644 index 0000000000..ecca724e94 --- /dev/null +++ b/queue-7.0/udp-force-compute_score-to-always-inline.patch @@ -0,0 +1,125 @@ +From 1388baf78a85a9d1419ec43cdc3c5d14088a3747 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 11:59:36 -0400 +Subject: udp: Force compute_score to always inline + +From: Gabriel Krisman Bertazi + +[ Upstream commit b80a95ccf1604a882bb153c45ccb4056e44c8edb ] + +Back in 2024 I reported a 7-12% regression on an iperf3 UDP loopback +thoughput test that we traced to the extra overhead of calling +compute_score on two places, introduced by commit f0ea27e7bfe1 ("udp: +re-score reuseport groups when connected sockets are present"). At the +time, I pointed out the overhead was caused by the multiple calls, +associated with cpu-specific mitigations, and merged commit +50aee97d1511 ("udp: Avoid call to compute_score on multiple sites") to +jump back explicitly, to force the rescore call in a single place. + +Recently though, we got another regression report against a newer distro +version, which a team colleague traced back to the same root-cause. +Turns out that once we updated to gcc-13, the compiler got smart enough +to unroll the loop, undoing my previous mitigation. Let's bite the +bullet and __always_inline compute_score on both ipv4 and ipv6 to +prevent gcc from de-optimizing it again in the future. These functions +are only called in two places each, udpX_lib_lookup1 and +udpX_lib_lookup2, so the extra size shouldn't be a problem and it is hot +enough to be very visible in profilings. In fact, with gcc13, forcing +the inline will prevent gcc from unrolling the fix from commit +50aee97d1511, so we don't end up increasing udpX_lib_lookup2 at all. + +I haven't recollected the results myself, as I don't have access to the +machine at the moment. But the same colleague reported 4.67% +inprovement with this patch in the loopback benchmark, solving the +regression report within noise margins. + +Eric Dumazet reported no size change to vmlinux when built with clang. +I report the same also with gcc-13: + +scripts/bloat-o-meter vmlinux vmlinux-inline +add/remove: 0/2 grow/shrink: 4/0 up/down: 616/-416 (200) +Function old new delta +udp6_lib_lookup2 762 949 +187 +__udp6_lib_lookup 810 975 +165 +udp4_lib_lookup2 757 906 +149 +__udp4_lib_lookup 871 986 +115 +__pfx_compute_score 32 - -32 +compute_score 384 - -384 +Total: Before=35011784, After=35011984, chg +0.00% + +Fixes: 50aee97d1511 ("udp: Avoid call to compute_score on multiple sites") +Reviewed-by: Eric Dumazet +Acked-by: Willem de Bruijn +Signed-off-by: Gabriel Krisman Bertazi +Link: https://patch.msgid.link/20260410155936.654915-1-krisman@suse.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/udp.c | 12 ++++++------ + net/ipv6/udp.c | 13 +++++++------ + 2 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index cb99a3c27053e..2551bfaa26810 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -365,10 +365,10 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum) + return udp_lib_get_port(sk, snum, hash2_nulladdr); + } + +-static int compute_score(struct sock *sk, const struct net *net, +- __be32 saddr, __be16 sport, +- __be32 daddr, unsigned short hnum, +- int dif, int sdif) ++static __always_inline int ++compute_score(struct sock *sk, const struct net *net, ++ __be32 saddr, __be16 sport, __be32 daddr, ++ unsigned short hnum, int dif, int sdif) + { + int score; + struct inet_sock *inet; +@@ -508,8 +508,8 @@ static struct sock *udp4_lib_lookup2(const struct net *net, + continue; + + /* compute_score is too long of a function to be +- * inlined, and calling it again here yields +- * measurable overhead for some ++ * inlined twice here, and calling it uninlined ++ * here yields measurable overhead for some + * workloads. Work around it by jumping + * backwards to rescore 'result'. + */ +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index 010b909275dd0..301649a63e8a3 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -127,10 +127,11 @@ void udp_v6_rehash(struct sock *sk) + udp_lib_rehash(sk, new_hash, new_hash4); + } + +-static int compute_score(struct sock *sk, const struct net *net, +- const struct in6_addr *saddr, __be16 sport, +- const struct in6_addr *daddr, unsigned short hnum, +- int dif, int sdif) ++static __always_inline int ++compute_score(struct sock *sk, const struct net *net, ++ const struct in6_addr *saddr, __be16 sport, ++ const struct in6_addr *daddr, unsigned short hnum, ++ int dif, int sdif) + { + int bound_dev_if, score; + struct inet_sock *inet; +@@ -260,8 +261,8 @@ static struct sock *udp6_lib_lookup2(const struct net *net, + continue; + + /* compute_score is too long of a function to be +- * inlined, and calling it again here yields +- * measurable overhead for some ++ * inlined twice here, and calling it uninlined ++ * here yields measurable overhead for some + * workloads. Work around it by jumping + * backwards to rescore 'result'. + */ +-- +2.53.0 + diff --git a/queue-7.0/um-fix-potential-race-condition-in-tlb-sync.patch b/queue-7.0/um-fix-potential-race-condition-in-tlb-sync.patch new file mode 100644 index 0000000000..1ec3c062b1 --- /dev/null +++ b/queue-7.0/um-fix-potential-race-condition-in-tlb-sync.patch @@ -0,0 +1,51 @@ +From 540dbb1caf991aa364582a976ea1b21efc7c8efa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 07:52:23 +0800 +Subject: um: Fix potential race condition in TLB sync + +From: Tiwei Bie + +[ Upstream commit 102331b66bcaf1f41f50b9c4cd5c36e46bafa9f3 ] + +During the TLB sync, we need to traverse and modify the page table, +so we should hold the page table lock. Since full SMP support for +threads within the same process is still missing, let's disable the +split page table lock for simplicity. + +Fixes: 1e4ee5135d81 ("um: Add initial SMP support") +Signed-off-by: Tiwei Bie +Link: https://patch.msgid.link/20260302235224.1915380-2-tiwei.btw@antgroup.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/um/kernel/tlb.c | 1 + + mm/Kconfig | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c +index 39608cccf2c69..5386ab2d0da50 100644 +--- a/arch/um/kernel/tlb.c ++++ b/arch/um/kernel/tlb.c +@@ -165,6 +165,7 @@ int um_tlb_sync(struct mm_struct *mm) + unsigned long addr, next; + int ret = 0; + ++ guard(spinlock_irqsave)(&mm->page_table_lock); + guard(spinlock_irqsave)(&mm->context.sync_tlb_lock); + + if (mm->context.sync_tlb_range_to == 0) +diff --git a/mm/Kconfig b/mm/Kconfig +index ebd8ea353687e..befa8909ae29d 100644 +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -572,6 +572,7 @@ config SPLIT_PTE_PTLOCKS + depends on !ARM || CPU_CACHE_VIPT + depends on !PARISC || PA20 + depends on !SPARC32 ++ depends on !UML + + config ARCH_ENABLE_SPLIT_PMD_PTLOCK + bool +-- +2.53.0 + diff --git a/queue-7.0/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch b/queue-7.0/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch new file mode 100644 index 0000000000..23a37b40d7 --- /dev/null +++ b/queue-7.0/unshare-fix-nsproxy-leak-in-ksys_unshare-on-set_cred.patch @@ -0,0 +1,91 @@ +From 1503b90290f5c0a23429c449dae191f469fbc61f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Feb 2026 11:39:59 -0800 +Subject: unshare: fix nsproxy leak in ksys_unshare() on set_cred_ucounts() + failure + +From: Michal Grzedzicki + +[ Upstream commit a98621a0f187a934c115dcfe79a49520ae892111 ] + +When set_cred_ucounts() fails in ksys_unshare() new_nsproxy is leaked. + +Let's call put_nsproxy() if that happens. + +Link: https://lkml.kernel.org/r/20260213193959.2556730-1-mge@meta.com +Fixes: 905ae01c4ae2 ("Add a reference to ucounts for each cred") +Signed-off-by: Michal Grzedzicki +Reviewed-by: Andrew Morton +Cc: Alexey Gladkov (Intel) +Cc: Ben Segall +Cc: David Hildenbrand +Cc: Dietmar Eggemann +Cc: Ingo Molnar +Cc: Juri Lelli +Cc: Kees Cook +Cc: "Liam R. Howlett" +Cc: Lorenzo Stoakes (Oracle) +Cc: Mel Gorman +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Steven Rostedt +Cc: Suren Baghdasaryan +Cc: Valentin Schneider +Cc: Vincent Guittot +Cc: Vlastimil Babka +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + kernel/fork.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 2383c25b9fd49..87f3b8d48c0db 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -3176,11 +3176,10 @@ int ksys_unshare(unsigned long unshare_flags) + new_cred, new_fs); + if (err) + goto bad_unshare_cleanup_cred; +- + if (new_cred) { + err = set_cred_ucounts(new_cred); + if (err) +- goto bad_unshare_cleanup_cred; ++ goto bad_unshare_cleanup_nsproxy; + } + + if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { +@@ -3196,8 +3195,10 @@ int ksys_unshare(unsigned long unshare_flags) + shm_init_task(current); + } + +- if (new_nsproxy) ++ if (new_nsproxy) { + switch_task_namespaces(current, new_nsproxy); ++ new_nsproxy = NULL; ++ } + + task_lock(current); + +@@ -3226,13 +3227,15 @@ int ksys_unshare(unsigned long unshare_flags) + + perf_event_namespaces(current); + ++bad_unshare_cleanup_nsproxy: ++ if (new_nsproxy) ++ put_nsproxy(new_nsproxy); + bad_unshare_cleanup_cred: + if (new_cred) + put_cred(new_cred); + bad_unshare_cleanup_fd: + if (new_fd) + put_files_struct(new_fd); +- + bad_unshare_cleanup_fs: + if (new_fs) + free_fs_struct(new_fs); +-- +2.53.0 + diff --git a/queue-7.0/usb-typec-fix-error-pointer-dereference.patch b/queue-7.0/usb-typec-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..b16667f290 --- /dev/null +++ b/queue-7.0/usb-typec-fix-error-pointer-dereference.patch @@ -0,0 +1,58 @@ +From 610d5f39b0e10f614b01be9feff304d95ab9c9bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 15:46:21 -0600 +Subject: usb: typec: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit f2529d08fcb429ea01bb87c326342f41483f8b2f ] + +The variable tps->partner is checked for an error pointer and then if it +is, it sends an error message but does not return and then immediately +dereferenced a few lines below: + +tps->partner = typec_register_partner(tps->port, &desc); +if (IS_ERR(tps->partner)) + dev_warn(tps->dev, "%s: failed to register partnet\n", __func__); + +if (desc.identity) { + typec_partner_set_identity(tps->partner); + cd321x->cur_partner_identity = st.partner_identity; +} + +Add early return and fix spelling mistake in error message. + +Detected by Smatch: +drivers/usb/typec/tipd/core.c:827 cd321x_update_work() error: +'tps->partner' dereferencing possible ERR_PTR() + +Fixes: 82432bbfb9e83 ("usb: typec: tipd: Handle mode transitions for CD321x") +Signed-off-by: Ethan Tidmore +Reviewed-by: Heikki Krogerus +Link: https://patch.msgid.link/20260218214621.38154-1-ethantidmore06@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/tipd/core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c +index e2b26af2b84a8..43faec794b95a 100644 +--- a/drivers/usb/typec/tipd/core.c ++++ b/drivers/usb/typec/tipd/core.c +@@ -820,8 +820,10 @@ static void cd321x_update_work(struct work_struct *work) + desc.identity = &st.partner_identity; + + tps->partner = typec_register_partner(tps->port, &desc); +- if (IS_ERR(tps->partner)) +- dev_warn(tps->dev, "%s: failed to register partnet\n", __func__); ++ if (IS_ERR(tps->partner)) { ++ dev_warn(tps->dev, "%s: failed to register partner\n", __func__); ++ return; ++ } + + if (desc.identity) { + typec_partner_set_identity(tps->partner); +-- +2.53.0 + diff --git a/queue-7.0/usb-typec-ps883x-fix-oops-at-unbind.patch b/queue-7.0/usb-typec-ps883x-fix-oops-at-unbind.patch new file mode 100644 index 0000000000..f860d27981 --- /dev/null +++ b/queue-7.0/usb-typec-ps883x-fix-oops-at-unbind.patch @@ -0,0 +1,67 @@ +From 52ead91e8920b1265c025d0c88d6f59a5755e1a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 15:55:34 +0000 +Subject: usb: typec: ps883x: Fix Oops at unbind + +From: Mostafa Saleh + +[ Upstream commit 381133848a033c2086cf9cafb226f425bd0414ff ] + +When trying to unbind a device in order to bind to it vfio-platform as: + + echo bc0000.geniqup > /sys/bus/platform/devices/bc0000.geniqup/driver/unbind + +I get the following Oops: + +[ 436.478639] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020 +[ 436.487762] Mem abort info: +[ 436.490716] ESR = 0x0000000096000004 +[ 436.494595] EC = 0x25: DABT (current EL), IL = 32 bits +[ 436.500071] SET = 0, FnV = 0 +[ 436.503250] EA = 0, S1PTW = 0 +[ 436.506505] FSC = 0x04: level 0 translation fault +[ 436.511533] Data abort info: +[ 436.514558] ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 +[ 436.520215] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 +[ 436.525436] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 436.530918] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008861a9000 +[ 436.537554] [0000000000000020] pgd=0000000000000000, p4d=0000000000000000 +[ 436.544548] Internal error: Oops: 0000000096000004 [#1] SMP +[ 436.550374] Modules linked in: +[ 436.553542] CPU: 2 UID: 0 PID: 671 Comm: bash Tainted: G W 7.0.0-rc3-g56fcdd0911a5-dirty #2 PREEMPT +[ 436.564440] Tainted: [W]=WARN +[ 436.567515] Hardware name: LENOVO 91B6CTO1WW/3796, BIOS O6NKT3BA 05/02/2025 +[ 436.574675] pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) +[ 436.581841] pc : ps883x_retimer_remove+0x14/0x94 +[ 436.586605] lr : i2c_device_remove+0x28/0x84 +[ 436.591017] sp : ffff8000847137c0 + +That's because the ps883x_retimer_remove() retrieves the driver data +from i2c_get_clientdata() which was never set at probe. So, add +i2c_set_clientdata() at the end of the probe. + +Signed-off-by: Mostafa Saleh +Reviewed-by: Konrad Dybcio +Fixes: 257a087c8b52 ("usb: typec: Add support for Parade PS8830 Type-C Retimer") +Link: https://patch.msgid.link/20260313155534.1916773-1-smostafa@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/mux/ps883x.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/usb/typec/mux/ps883x.c b/drivers/usb/typec/mux/ps883x.c +index 5f2879749769e..1256252eceedc 100644 +--- a/drivers/usb/typec/mux/ps883x.c ++++ b/drivers/usb/typec/mux/ps883x.c +@@ -444,6 +444,7 @@ static int ps883x_retimer_probe(struct i2c_client *client) + goto err_switch_unregister; + } + ++ i2c_set_clientdata(client, retimer); + return 0; + + err_switch_unregister: +-- +2.53.0 + diff --git a/queue-7.0/vdpa-use-generic-driver_override-infrastructure.patch b/queue-7.0/vdpa-use-generic-driver_override-infrastructure.patch new file mode 100644 index 0000000000..99f724330e --- /dev/null +++ b/queue-7.0/vdpa-use-generic-driver_override-infrastructure.patch @@ -0,0 +1,136 @@ +From f93b17daa35ce53420d925e039edcfaf8b1bcd40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 24 Mar 2026 01:59:12 +0100 +Subject: vdpa: use generic driver_override infrastructure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Danilo Krummrich + +[ Upstream commit 85bb534ff12aab6916058897b39c748940a7a4c6 ] + +When a driver is probed through __driver_attach(), the bus' match() +callback is called without the device lock held, thus accessing the +driver_override field without a lock, which can cause a UAF. + +Fix this by using the driver-core driver_override infrastructure taking +care of proper locking internally. + +Note that calling match() from __driver_attach() without the device lock +held is intentional. [1] + +Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] +Reported-by: Gui-Dong Han +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 +Fixes: 539fec78edb4 ("vdpa: add driver_override support") +Acked-by: Eugenio Pérez +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260324005919.2408620-9-dakr@kernel.org +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +--- + drivers/vdpa/vdpa.c | 48 +++++--------------------------------------- + include/linux/vdpa.h | 4 ---- + 2 files changed, 5 insertions(+), 47 deletions(-) + +diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c +index 34874beb0152e..caf0ee5d6856c 100644 +--- a/drivers/vdpa/vdpa.c ++++ b/drivers/vdpa/vdpa.c +@@ -67,57 +67,20 @@ static void vdpa_dev_remove(struct device *d) + + static int vdpa_dev_match(struct device *dev, const struct device_driver *drv) + { +- struct vdpa_device *vdev = dev_to_vdpa(dev); ++ int ret; + + /* Check override first, and if set, only use the named driver */ +- if (vdev->driver_override) +- return strcmp(vdev->driver_override, drv->name) == 0; ++ ret = device_match_driver_override(dev, drv); ++ if (ret >= 0) ++ return ret; + + /* Currently devices must be supported by all vDPA bus drivers */ + return 1; + } + +-static ssize_t driver_override_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct vdpa_device *vdev = dev_to_vdpa(dev); +- int ret; +- +- ret = driver_set_override(dev, &vdev->driver_override, buf, count); +- if (ret) +- return ret; +- +- return count; +-} +- +-static ssize_t driver_override_show(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct vdpa_device *vdev = dev_to_vdpa(dev); +- ssize_t len; +- +- device_lock(dev); +- len = sysfs_emit(buf, "%s\n", vdev->driver_override); +- device_unlock(dev); +- +- return len; +-} +-static DEVICE_ATTR_RW(driver_override); +- +-static struct attribute *vdpa_dev_attrs[] = { +- &dev_attr_driver_override.attr, +- NULL, +-}; +- +-static const struct attribute_group vdpa_dev_group = { +- .attrs = vdpa_dev_attrs, +-}; +-__ATTRIBUTE_GROUPS(vdpa_dev); +- + static const struct bus_type vdpa_bus = { + .name = "vdpa", +- .dev_groups = vdpa_dev_groups, ++ .driver_override = true, + .match = vdpa_dev_match, + .probe = vdpa_dev_probe, + .remove = vdpa_dev_remove, +@@ -132,7 +95,6 @@ static void vdpa_release_dev(struct device *d) + ops->free(vdev); + + ida_free(&vdpa_index_ida, vdev->index); +- kfree(vdev->driver_override); + kfree(vdev); + } + +diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h +index 2bfe3baa63f42..782c42d25db16 100644 +--- a/include/linux/vdpa.h ++++ b/include/linux/vdpa.h +@@ -72,9 +72,6 @@ struct vdpa_mgmt_dev; + * struct vdpa_device - representation of a vDPA device + * @dev: underlying device + * @vmap: the metadata passed to upper layer to be used for mapping +- * @driver_override: driver name to force a match; do not set directly, +- * because core frees it; use driver_set_override() to +- * set or clear it. + * @config: the configuration ops for this device. + * @map: the map ops for this device + * @cf_lock: Protects get and set access to configuration layout. +@@ -90,7 +87,6 @@ struct vdpa_mgmt_dev; + struct vdpa_device { + struct device dev; + union virtio_map vmap; +- const char *driver_override; + const struct vdpa_config_ops *config; + const struct virtio_map_ops *map; + struct rw_semaphore cf_lock; /* Protects get/set config */ +-- +2.53.0 + diff --git a/queue-7.0/vfio-pci-clean-up-dmabufs-before-disabling-function.patch b/queue-7.0/vfio-pci-clean-up-dmabufs-before-disabling-function.patch new file mode 100644 index 0000000000..342f9759b2 --- /dev/null +++ b/queue-7.0/vfio-pci-clean-up-dmabufs-before-disabling-function.patch @@ -0,0 +1,51 @@ +From 99aa907f057534b9e53db779e8e37bc35f775316 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 11:17:52 -0700 +Subject: vfio/pci: Clean up DMABUFs before disabling function + +From: Matt Evans + +[ Upstream commit d97708701434ce72968e771976aaf9d3438fcafd ] + +On device shutdown, make vfio_pci_core_close_device() call +vfio_pci_dma_buf_cleanup() before the function is disabled via +vfio_pci_core_disable(). This ensures that all access via DMABUFs is +revoked before the function's BARs become inaccessible. + +This fixes an issue where, if the function is disabled first, a tiny +window exists in which the function's MSE is cleared and yet BARs +could still be accessed via the DMABUF. The resources would also be +freed and up for grabs by a different driver. + +Fixes: 5d74781ebc86c ("vfio/pci: Add dma-buf export support for MMIO regions") +Signed-off-by: Matt Evans +Reviewed-by: Jason Gunthorpe +Reviewed-by: Kevin Tian +Reviewed-by: Leon Romanovsky +Link: https://lore.kernel.org/r/20260415181752.1027604-1-mattev@meta.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + drivers/vfio/pci/vfio_pci_core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c +index 3fea064d00de2..e34c7e1ba1c81 100644 +--- a/drivers/vfio/pci/vfio_pci_core.c ++++ b/drivers/vfio/pci/vfio_pci_core.c +@@ -734,10 +734,10 @@ void vfio_pci_core_close_device(struct vfio_device *core_vdev) + #if IS_ENABLED(CONFIG_EEH) + eeh_dev_release(vdev->pdev); + #endif +- vfio_pci_core_disable(vdev); +- + vfio_pci_dma_buf_cleanup(vdev); + ++ vfio_pci_core_disable(vdev); ++ + mutex_lock(&vdev->igate); + vfio_pci_eventfd_replace_locked(vdev, &vdev->err_trigger, NULL); + vfio_pci_eventfd_replace_locked(vdev, &vdev->req_trigger, NULL); +-- +2.53.0 + diff --git a/queue-7.0/vfio-selftests-build-tests-on-aarch64.patch b/queue-7.0/vfio-selftests-build-tests-on-aarch64.patch new file mode 100644 index 0000000000..56f3968df1 --- /dev/null +++ b/queue-7.0/vfio-selftests-build-tests-on-aarch64.patch @@ -0,0 +1,38 @@ +From dbab55a7338aebcaf137d7dab37a4a463d0dcdb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Mar 2026 15:58:47 -0700 +Subject: vfio: selftests: Build tests on aarch64 + +From: Ted Logan + +[ Upstream commit 1347a742a1e1b080e2e8d200312ae45b8d6ac859 ] + +Fix vfio selftests on aarch64, allowing native builds on aarch64 hosts. + +Reported-by: Matt Evans +Closes: https://lore.kernel.org/all/e51b4ff2-13c4-47d4-b781-3dcbd740d274@meta.com/ +Fixes: a55d4bbbe644 ("vfio: selftests: only build tests on arm64 and x86_64") +Signed-off-by: Ted Logan +Reviewed-by: David Matlack +Link: https://lore.kernel.org/r/20260319-vfio-selftests-aarch64-v2-1-bb2621c24dc4@fb.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/vfio/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile +index 8e90e409e91d8..0684932d91bfc 100644 +--- a/tools/testing/selftests/vfio/Makefile ++++ b/tools/testing/selftests/vfio/Makefile +@@ -1,6 +1,6 @@ + ARCH ?= $(shell uname -m) + +-ifeq (,$(filter $(ARCH),arm64 x86_64)) ++ifeq (,$(filter $(ARCH),aarch64 arm64 x86_64)) + # Do nothing on unsupported architectures + include ../lib.mk + else +-- +2.53.0 + diff --git a/queue-7.0/vfio-selftests-fix-crash-in-vfio_dma_mapping_mmio_te.patch b/queue-7.0/vfio-selftests-fix-crash-in-vfio_dma_mapping_mmio_te.patch new file mode 100644 index 0000000000..1c7dfb02bf --- /dev/null +++ b/queue-7.0/vfio-selftests-fix-crash-in-vfio_dma_mapping_mmio_te.patch @@ -0,0 +1,44 @@ +From c6b40630f09bebde4c00fc792e9dd9b451960c32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:46:24 -0800 +Subject: vfio: selftests: fix crash in vfio_dma_mapping_mmio_test + +From: Alex Mastro + +[ Upstream commit f183963891b4b0126f19aa0993ed931f3f3f9520 ] + +Remove the __iommu_unmap() call on a region that was never mapped. +When __iommu_map() fails (expected for MMIO vaddrs in non-VFIO +modes), the region is not added to the dma_regions list, leaving its +list_head zero-initialized. If the unmap ioctl returns success, +__iommu_unmap() calls list_del_init() on this zeroed node and crashes. + +This fixes the iommufd_compat_type1 and iommufd_compat_type1v2 +test variants. + +Fixes: 080723f4d4c3 ("vfio: selftests: Add vfio_dma_mapping_mmio_test") +Signed-off-by: Alex Mastro +Reviewed-by: David Matlack +Reviewed-by: Yuan Yao +Link: https://lore.kernel.org/r/20260303-fix-mmio-test-v1-1-78b4a9e46a4e@fb.com +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c +index 957a89ce7b3a0..d7f25ef776715 100644 +--- a/tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c ++++ b/tools/testing/selftests/vfio/vfio_dma_mapping_mmio_test.c +@@ -100,7 +100,6 @@ static void do_mmio_map_test(struct iommu *iommu, + iommu_unmap(iommu, ®ion); + } else { + VFIO_ASSERT_NE(__iommu_map(iommu, ®ion), 0); +- VFIO_ASSERT_NE(__iommu_unmap(iommu, ®ion, NULL), 0); + } + } + +-- +2.53.0 + diff --git a/queue-7.0/vfio-unhide-vdev-debug_root.patch b/queue-7.0/vfio-unhide-vdev-debug_root.patch new file mode 100644 index 0000000000..ab41341d38 --- /dev/null +++ b/queue-7.0/vfio-unhide-vdev-debug_root.patch @@ -0,0 +1,50 @@ +From 54d9a6b5902ef1a181934e645ae9c6deabf18b3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 17:55:08 +0100 +Subject: vfio: unhide vdev->debug_root + +From: Arnd Bergmann + +[ Upstream commit 555aa178f8d22261d71da74df6267e6e6e97f95a ] + +When debugfs is disabled, the hisilicon driver now fails to build: + +drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c: In function 'hisi_acc_vfio_debug_init': +drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1671:62: error: 'struct vfio_device' has no member named 'debug_root' + 1671 | vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root); + | ^~ + +The driver otherwise relies on dead-code elimination, but this reference +fails. The single struct member is not going to make much of a difference +for memory consumption, so just keep this visible unconditionally. + +Signed-off-by: Arnd Bergmann +Fixes: b398f91779b8 ("hisi_acc_vfio_pci: register debugfs for hisilicon migration driver") +Link: https://lore.kernel.org/r/20260327165521.3779707-1-arnd@kernel.org +Signed-off-by: Alex Williamson +Signed-off-by: Sasha Levin +--- + include/linux/vfio.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/include/linux/vfio.h b/include/linux/vfio.h +index e90859956514a..ef02a4996d451 100644 +--- a/include/linux/vfio.h ++++ b/include/linux/vfio.h +@@ -72,13 +72,11 @@ struct vfio_device { + u8 iommufd_attached:1; + #endif + u8 cdev_opened:1; +-#ifdef CONFIG_DEBUG_FS + /* + * debug_root is a static property of the vfio_device + * which must be set prior to registering the vfio_device. + */ + struct dentry *debug_root; +-#endif + }; + + /** +-- +2.53.0 + diff --git a/queue-7.0/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch b/queue-7.0/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch new file mode 100644 index 0000000000..76ea19ff16 --- /dev/null +++ b/queue-7.0/vhost_net-fix-sleeping-with-preempt-disabled-in-vhos.patch @@ -0,0 +1,64 @@ +From b38041278c775e74efe38e7da4c248b459b2a5df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Apr 2026 02:30:24 +0000 +Subject: vhost_net: fix sleeping with preempt-disabled in + vhost_net_busy_poll() + +From: Kohei Enju + +[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ] + +syzbot reported "sleeping function called from invalid context" in +vhost_net_busy_poll(). + +Commit 030881372460 ("vhost_net: basic polling support") introduced a +busy-poll loop and preempt_{disable,enable}() around it, where each +iteration calls a sleepable function inside the loop. + +The purpose of disabling preemption was to keep local_clock()-based +timeout accounting on a single CPU, rather than as a requirement of +busy-poll itself: + +https://lore.kernel.org/1448435489-5949-4-git-send-email-jasowang@redhat.com + +From this perspective, migrate_disable() is sufficient here, so replace +preempt_disable() with migrate_disable(), avoiding sleepable accesses +from a preempt-disabled context. + +Fixes: 030881372460 ("vhost_net: basic polling support") +Tested-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Reported-by: syzbot+6985cb8e543ea90ba8ee@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/69e6a414.050a0220.24bfd3.002d.GAE@google.com/T/ +Signed-off-by: Kohei Enju +Acked-by: Michael S. Tsirkin +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/vhost/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index 80965181920c3..c6536cad9c4f9 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -560,7 +560,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + busyloop_timeout = poll_rx ? rvq->busyloop_timeout: + tvq->busyloop_timeout; + +- preempt_disable(); ++ migrate_disable(); + endtime = busy_clock() + busyloop_timeout; + + while (vhost_can_busy_poll(endtime)) { +@@ -577,7 +577,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, + cpu_relax(); + } + +- preempt_enable(); ++ migrate_enable(); + + if (poll_rx || sock_has_rx_data(sock)) + vhost_net_busy_poll_try_queue(net, vq); +-- +2.53.0 + diff --git a/queue-7.0/virt-arm-cca-guest-fix-error-check-for-rsi_incomplet.patch b/queue-7.0/virt-arm-cca-guest-fix-error-check-for-rsi_incomplet.patch new file mode 100644 index 0000000000..2d069bd200 --- /dev/null +++ b/queue-7.0/virt-arm-cca-guest-fix-error-check-for-rsi_incomplet.patch @@ -0,0 +1,51 @@ +From a547942fc36135178d0674004fa5c23bc36d40c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Apr 2026 17:36:36 +0100 +Subject: virt: arm-cca-guest: fix error check for RSI_INCOMPLETE + +From: Sami Mujawar + +[ Upstream commit e534e9d13d0b7bdbb2cccdace7b96b769a10540e ] + +The RSI interface can return RSI_INCOMPLETE when a report spans +multiple granules. This is an expected condition and should not be +treated as a fatal error. + +Currently, arm_cca_report_new() checks for `info.result != RSI_SUCCESS` +and bails out, which incorrectly flags RSI_INCOMPLETE as a failure. +Fix the check to only break out on results other than RSI_SUCCESS or +RSI_INCOMPLETE. + +This ensures partial reports are handled correctly and avoids spurious +-ENXIO errors when generating attestation reports. + +Fixes: 7999edc484ca ("virt: arm-cca-guest: TSM_REPORT support for realms") +Signed-off-by: Sami Mujawar +Reported-by: Jagdish Gediya +Reviewed-by: Steven Price +Reviewed-by: Gavin Shan +Reviewed-by: Suzuki K Poulose +Reviewed-by: Yeoreum Yun +Signed-off-by: Catalin Marinas +Signed-off-by: Sasha Levin +--- + drivers/virt/coco/arm-cca-guest/arm-cca-guest.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c +index 0c9ea24a200c9..66d00b6ceb789 100644 +--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c ++++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c +@@ -157,7 +157,8 @@ static int arm_cca_report_new(struct tsm_report *report, void *data) + } while (info.result == RSI_INCOMPLETE && + info.offset < RSI_GRANULE_SIZE); + +- if (info.result != RSI_SUCCESS) { ++ /* Break out in case of failure */ ++ if (info.result != RSI_SUCCESS && info.result != RSI_INCOMPLETE) { + ret = -ENXIO; + token_size = 0; + goto exit_free_granule_page; +-- +2.53.0 + diff --git a/queue-7.0/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch b/queue-7.0/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch new file mode 100644 index 0000000000..8d0273bb9c --- /dev/null +++ b/queue-7.0/virtio_net-sync-rss_trailer.max_tx_vq-on-queue_pairs.patch @@ -0,0 +1,63 @@ +From a48e3da81719bfde70aa39c1dbd0425969f27ece Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Apr 2026 14:21:21 -0700 +Subject: virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via + VQ_PAIRS_SET + +From: Brett Creeley + +[ Upstream commit 3bc06da858ef17cfe94b49efc0d9713727012835 ] + +When netif_is_rxfh_configured() is true (i.e., the user has explicitly +configured the RSS indirection table), virtnet_set_queues() skips the +RSS update path and falls through to the VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET +command to change the number of queue pairs. However, it does not update +vi->rss_trailer.max_tx_vq to reflect the new queue_pairs value. + +This causes a mismatch between vi->curr_queue_pairs and +vi->rss_trailer.max_tx_vq. Any subsequent RSS reconfiguration (e.g., +via ethtool -X) calls virtnet_commit_rss_command(), which sends the +stale max_tx_vq to the device, silently reverting the queue count. + +Reproduction: +1. User configured RSS + ethtool -X eth0 equal 8 +2. VQ_PAIRS_SET path; max_tx_vq stays 16 + ethtool -L eth0 combined 12 +3. RSS commit uses max_tx_vq=16 instead of 12 + ethtool -X eth0 equal 4 + +Fix this by updating vi->rss_trailer.max_tx_vq after a successful +VQ_PAIRS_SET command when RSS is enabled, keeping it in sync with +curr_queue_pairs. + +Fixes: 50bfcaedd78e ("virtio_net: Update rss when set queue") +Signed-off-by: Brett Creeley +Acked-by: Michael S. Tsirkin +Link: https://patch.msgid.link/20260416212121.29073-1-brett.creeley@amd.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/virtio_net.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index c0b9bc5574e23..67b913218144b 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -3748,6 +3748,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) + queue_pairs); + return -EINVAL; + } ++ ++ /* Keep max_tx_vq in sync so that a later RSS command does not ++ * revert queue_pairs to a stale value. ++ */ ++ if (vi->has_rss) ++ vi->rss_trailer.max_tx_vq = cpu_to_le16(queue_pairs); + succ: + vi->curr_queue_pairs = queue_pairs; + if (dev->flags & IFF_UP) { +-- +2.53.0 + diff --git a/queue-7.0/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch b/queue-7.0/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch new file mode 100644 index 0000000000..e6925a318c --- /dev/null +++ b/queue-7.0/vrf-fix-a-potential-npd-when-removing-a-port-from-a-.patch @@ -0,0 +1,115 @@ +From 4528b2f7b962a2f787013b103fd58fad3b6a997e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Apr 2026 09:36:07 +0300 +Subject: vrf: Fix a potential NPD when removing a port from a VRF + +From: Ido Schimmel + +[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ] + +RCU readers that identified a net device as a VRF port using +netif_is_l3_slave() assume that a subsequent call to +netdev_master_upper_dev_get_rcu() will return a VRF device. They then +continue to dereference its l3mdev operations. + +This assumption is not always correct and can result in a NPD [1]. There +is no RCU synchronization when removing a port from a VRF, so it is +possible for an RCU reader to see a new master device (e.g., a bridge) +that does not have l3mdev operations. + +Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE +flag. Skip this synchronization when a net device is removed from a VRF +as part of its deletion and when the VRF device itself is deleted. In +the latter case an RCU grace period will pass by the time RTNL is +released. + +[1] +BUG: kernel NULL pointer dereference, address: 0000000000000000 +[...] +RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) +[...] +Call Trace: + +l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) +__inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) +inet_bind_sk (net/ipv4/af_inet.c:469) +__sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) +__x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) +do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) +entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Fixes: fdeea7be88b1 ("net: vrf: Set slave's private flag before linking") +Reported-by: Haoze Xie +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/netdev/20260419145332.3988923-1-n05ec@lzu.edu.cn/ +Signed-off-by: Ido Schimmel +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20260423063607.1208202-1-idosch@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/vrf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index 8c009bcaa8e77..91a97c3f46c4f 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -1084,6 +1084,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + + err: + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ synchronize_net(); + return ret; + } + +@@ -1103,10 +1104,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, + } + + /* inverse of do_vrf_add_slave */ +-static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) ++static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev, ++ bool needs_sync) + { + netdev_upper_dev_unlink(port_dev, dev); + port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE; ++ /* Make sure that concurrent RCU readers that identified the device ++ * as a VRF port see a VRF master or no master at all. ++ */ ++ if (needs_sync) ++ synchronize_net(); + + cycle_netdev(port_dev, NULL); + +@@ -1115,7 +1122,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + + static int vrf_del_slave(struct net_device *dev, struct net_device *port_dev) + { +- return do_vrf_del_slave(dev, port_dev); ++ return do_vrf_del_slave(dev, port_dev, true); + } + + static void vrf_dev_uninit(struct net_device *dev) +@@ -1669,7 +1676,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head) + struct list_head *iter; + + netdev_for_each_lower_dev(dev, port_dev, iter) +- vrf_del_slave(dev, port_dev); ++ do_vrf_del_slave(dev, port_dev, false); + + vrf_map_unregister_dev(dev); + +@@ -1801,7 +1808,7 @@ static int vrf_device_event(struct notifier_block *unused, + goto out; + + vrf_dev = netdev_master_upper_dev_get(dev); +- vrf_del_slave(vrf_dev, dev); ++ do_vrf_del_slave(vrf_dev, dev, false); + } + out: + return NOTIFY_DONE; +-- +2.53.0 + diff --git a/queue-7.0/vsock-virtio-fix-msg_zerocopy-pinned-pages-accountin.patch b/queue-7.0/vsock-virtio-fix-msg_zerocopy-pinned-pages-accountin.patch new file mode 100644 index 0000000000..5ac308b324 --- /dev/null +++ b/queue-7.0/vsock-virtio-fix-msg_zerocopy-pinned-pages-accountin.patch @@ -0,0 +1,81 @@ +From 99a3f0e54e2c43a32dd2124180c67975eeeedf2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Apr 2026 15:20:51 +0200 +Subject: vsock/virtio: fix MSG_ZEROCOPY pinned-pages accounting + +From: Stefano Garzarella + +[ Upstream commit 1cb36e252211506f51095fe7ced8286cc77b4c80 ] + +virtio_transport_init_zcopy_skb() uses iter->count as the size argument +for msg_zerocopy_realloc(), which in turn passes it to +mm_account_pinned_pages() for RLIMIT_MEMLOCK accounting. However, this +function is called after virtio_transport_fill_skb() has already consumed +the iterator via __zerocopy_sg_from_iter(), so on the last skb, iter->count +will be 0, skipping the RLIMIT_MEMLOCK enforcement. + +Pass pkt_len (the total bytes being sent) as an explicit parameter to +virtio_transport_init_zcopy_skb() instead of reading the already-consumed +iter->count. + +This matches TCP and UDP, which both call msg_zerocopy_realloc() with +the original message size. + +Fixes: 581512a6dc93 ("vsock/virtio: MSG_ZEROCOPY flag support") +Reported-by: Yiming Qian +Signed-off-by: Stefano Garzarella +Reviewed-by: Bobby Eshleman +Link: https://patch.msgid.link/20260420132051.217589-1-sgarzare@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/vmw_vsock/virtio_transport_common.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c +index 6547e199ea5b1..0d0265f770ada 100644 +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -75,6 +75,7 @@ static bool virtio_transport_can_zcopy(const struct virtio_transport *t_ops, + static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk, + struct sk_buff *skb, + struct msghdr *msg, ++ size_t pkt_len, + bool zerocopy) + { + struct ubuf_info *uarg; +@@ -83,12 +84,10 @@ static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk, + uarg = msg->msg_ubuf; + net_zcopy_get(uarg); + } else { +- struct iov_iter *iter = &msg->msg_iter; + struct ubuf_info_msgzc *uarg_zc; + + uarg = msg_zerocopy_realloc(sk_vsock(vsk), +- iter->count, +- NULL, false); ++ pkt_len, NULL, false); + if (!uarg) + return -1; + +@@ -385,11 +384,17 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, + * each iteration. If this is last skb for this buffer + * and MSG_ZEROCOPY mode is in use - we must allocate + * completion for the current syscall. ++ * ++ * Pass pkt_len because msg iter is already consumed ++ * by virtio_transport_fill_skb(), so iter->count ++ * can not be used for RLIMIT_MEMLOCK pinned-pages ++ * accounting done by msg_zerocopy_realloc(). + */ + if (info->msg && info->msg->msg_flags & MSG_ZEROCOPY && + skb_len == rest_len && info->op == VIRTIO_VSOCK_OP_RW) { + if (virtio_transport_init_zcopy_skb(vsk, skb, + info->msg, ++ pkt_len, + can_zcopy)) { + kfree_skb(skb); + ret = -ENOMEM; +-- +2.53.0 + diff --git a/queue-7.0/wifi-ath10k-fix-station-lookup-failure-during-discon.patch b/queue-7.0/wifi-ath10k-fix-station-lookup-failure-during-discon.patch new file mode 100644 index 0000000000..2992da3c93 --- /dev/null +++ b/queue-7.0/wifi-ath10k-fix-station-lookup-failure-during-discon.patch @@ -0,0 +1,140 @@ +From b4051f686b3bf4ba36da560ba42789b9c961aae7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Mar 2026 11:05:01 +0800 +Subject: wifi: ath10k: fix station lookup failure during disconnect + +From: Baochen Qiang + +[ Upstream commit 9a34a59c6086ae731a06b3e61b0951feef758648 ] + +Recent commit [1] moved station statistics collection to an earlier stage +of the disconnect flow. With this change in place, ath10k fails to resolve +the station entry when handling a peer stats event triggered during +disconnect, resulting in log messages such as: + +wlp58s0: deauthenticating from 74:1a:e0:e7:b4:c8 by local choice (Reason: 3=DEAUTH_LEAVING) +ath10k_pci 0000:3a:00.0: not found station for peer stats +ath10k_pci 0000:3a:00.0: failed to parse stats info tlv: -22 + +The failure occurs because ath10k relies on ieee80211_find_sta_by_ifaddr() +for station lookup. That function uses local->sta_hash, but by the time +the peer stats request is triggered during disconnect, mac80211 has +already removed the station from that hash table, leading to lookup +failure. + +Before commit [1], this issue was not visible because the transition from +IEEE80211_STA_NONE to IEEE80211_STA_NOTEXIST prevented ath10k from sending +a peer stats request at all: ath10k_mac_sta_get_peer_stats_info() would +fail early to find the peer and skip requesting statistics. + +Fix this by switching the lookup path to ath10k_peer_find(), which queries +ath10k's internal peer table. At the point where the firmware emits the +peer stats event, the peer entry is still present in the driver's list, +ensuring lookup succeeds. + +Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00309-QCARMSWPZ-1 + +Fixes: a203dbeeca15 ("wifi: mac80211: collect station statistics earlier when disconnect") # [1] +Reported-by: Paul Menzel +Closes: https://lore.kernel.org/ath10k/57671b89-ec9f-4e6c-992c-45eb8e75929c@molgen.mpg.de +Signed-off-by: Baochen Qiang +Reviewed-by: Rameshkumar Sundaram +Reviewed-by: Paul Menzel +Tested-by: Paul Menzel +Link: https://patch.msgid.link/20260325-ath10k-station-lookup-failure-v1-1-2e0c970f25d5@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath10k/wmi-tlv.c | 26 +++++++++++++---------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +index ec8e91707f84a..01f2d1fa9d7d9 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +@@ -3,7 +3,7 @@ + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +- * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + #include "core.h" + #include "debug.h" +@@ -14,6 +14,7 @@ + #include "wmi-tlv.h" + #include "p2p.h" + #include "testmode.h" ++#include "txrx.h" + #include + + /***************/ +@@ -224,8 +225,9 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 + const void *ptr, void *data) + { + const struct wmi_tlv_peer_stats_info *stat = ptr; +- struct ieee80211_sta *sta; ++ u32 vdev_id = *(u32 *)data; + struct ath10k_sta *arsta; ++ struct ath10k_peer *peer; + + if (tag != WMI_TLV_TAG_STRUCT_PEER_STATS_INFO) + return -EPROTO; +@@ -241,20 +243,20 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16 + __le32_to_cpu(stat->last_tx_rate_code), + __le32_to_cpu(stat->last_tx_bitrate_kbps)); + +- rcu_read_lock(); +- sta = ieee80211_find_sta_by_ifaddr(ar->hw, stat->peer_macaddr.addr, NULL); +- if (!sta) { +- rcu_read_unlock(); +- ath10k_warn(ar, "not found station for peer stats\n"); ++ guard(spinlock_bh)(&ar->data_lock); ++ ++ peer = ath10k_peer_find(ar, vdev_id, stat->peer_macaddr.addr); ++ if (!peer || !peer->sta) { ++ ath10k_warn(ar, "not found %s with vdev id %u mac addr %pM for peer stats\n", ++ peer ? "sta" : "peer", vdev_id, stat->peer_macaddr.addr); + return -EINVAL; + } + +- arsta = (struct ath10k_sta *)sta->drv_priv; ++ arsta = (struct ath10k_sta *)peer->sta->drv_priv; + arsta->rx_rate_code = __le32_to_cpu(stat->last_rx_rate_code); + arsta->rx_bitrate_kbps = __le32_to_cpu(stat->last_rx_bitrate_kbps); + arsta->tx_rate_code = __le32_to_cpu(stat->last_tx_rate_code); + arsta->tx_bitrate_kbps = __le32_to_cpu(stat->last_tx_bitrate_kbps); +- rcu_read_unlock(); + + return 0; + } +@@ -266,6 +268,7 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar, + const struct wmi_tlv_peer_stats_info_ev *ev; + const void *data; + u32 num_peer_stats; ++ u32 vdev_id; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); +@@ -284,15 +287,16 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar, + } + + num_peer_stats = __le32_to_cpu(ev->num_peers); ++ vdev_id = __le32_to_cpu(ev->vdev_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tlv peer stats info update peer vdev id %d peers %i more data %d\n", +- __le32_to_cpu(ev->vdev_id), ++ vdev_id, + num_peer_stats, + __le32_to_cpu(ev->more_data)); + + ret = ath10k_wmi_tlv_iter(ar, data, ath10k_wmi_tlv_len(data), +- ath10k_wmi_tlv_parse_peer_stats_info, NULL); ++ ath10k_wmi_tlv_parse_peer_stats_info, &vdev_id); + if (ret) + ath10k_warn(ar, "failed to parse stats info tlv: %d\n", ret); + +-- +2.53.0 + diff --git a/queue-7.0/wifi-ath11k-fix-memory-leaks-in-beacon-template-setu.patch b/queue-7.0/wifi-ath11k-fix-memory-leaks-in-beacon-template-setu.patch new file mode 100644 index 0000000000..c1292a6904 --- /dev/null +++ b/queue-7.0/wifi-ath11k-fix-memory-leaks-in-beacon-template-setu.patch @@ -0,0 +1,105 @@ +From a2c379fa8bab05d23f57fdeb3c2243d12a3de835 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 08:44:51 +0000 +Subject: wifi: ath11k: fix memory leaks in beacon template setup + +From: Zilin Guan + +[ Upstream commit ff49eba595df500e4ddccc593088c8a4ab5f2c27 ] + +The functions ath11k_mac_setup_bcn_tmpl_ema() and +ath11k_mac_setup_bcn_tmpl_mbssid() allocate memory for beacon templates +but fail to free it when parameter setup returns an error. + +Since beacon templates must be released during normal execution, they +must also be released in the error handling paths to prevent memory +leaks. + +Fix this by using unified exit paths with proper cleanup in the respective +error paths. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 3a415daa3e8b ("wifi: ath11k: add P2P IE in beacon template") +Fixes: 335a92765d30 ("wifi: ath11k: MBSSID beacon support") +Suggested-by: Baochen Qiang +Signed-off-by: Zilin Guan +Reviewed-by: Vasanthakumar Thiagarajan +Reviewed-by: Baochen Qiang +Link: https://patch.msgid.link/20260130084451.110768-1-zilin@seu.edu.cn +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath11k/mac.c | 28 ++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c +index e4ee2ba1f669e..c06ee110a90f0 100644 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1557,12 +1557,15 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif, + if (!beacons || !beacons->cnt) { + ath11k_warn(arvif->ar->ab, + "failed to get ema beacon templates from mac80211\n"); +- return -EPERM; ++ ret = -EPERM; ++ goto free; + } + + if (tx_arvif == arvif) { +- if (ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb)) +- return -EINVAL; ++ if (ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb)) { ++ ret = -EINVAL; ++ goto free; ++ } + } else { + arvif->wpaie_present = tx_arvif->wpaie_present; + } +@@ -1589,11 +1592,11 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif, + } + } + +- ieee80211_beacon_free_ema_list(beacons); +- + if (tx_arvif != arvif && !nontx_vif_params_set) +- return -EINVAL; /* Profile not found in the beacons */ ++ ret = -EINVAL; /* Profile not found in the beacons */ + ++free: ++ ieee80211_beacon_free_ema_list(beacons); + return ret; + } + +@@ -1622,19 +1625,22 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif, + } + + if (tx_arvif == arvif) { +- if (ath11k_mac_set_vif_params(tx_arvif, bcn)) +- return -EINVAL; ++ if (ath11k_mac_set_vif_params(tx_arvif, bcn)) { ++ ret = -EINVAL; ++ goto free; ++ } + } else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) { +- return -EINVAL; ++ ret = -EINVAL; ++ goto free; + } + + ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, 0); +- kfree_skb(bcn); +- + if (ret) + ath11k_warn(ab, "failed to submit beacon template command: %d\n", + ret); + ++free: ++ kfree_skb(bcn); + return ret; + } + +-- +2.53.0 + diff --git a/queue-7.0/wifi-ath12k-account-tx-stats-only-when-ack-ba-status.patch b/queue-7.0/wifi-ath12k-account-tx-stats-only-when-ack-ba-status.patch new file mode 100644 index 0000000000..435897079c --- /dev/null +++ b/queue-7.0/wifi-ath12k-account-tx-stats-only-when-ack-ba-status.patch @@ -0,0 +1,84 @@ +From 1362eebff1cddddfca3879902f7b0b31e2986ca2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Feb 2026 10:49:47 +0530 +Subject: wifi: ath12k: account TX stats only when ACK/BA status is present + +From: Sarika Sharma + +[ Upstream commit 1635ecc61a24597f893d057d004051a535c1c643 ] + +The fields tx_retry_failed, tx_retry_count, and tx_duration are +currently updated outside the HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS +flag check. In certain scenarios, firmware delivers multiple PPDU +statistics for the same PPDU, first without BA/ACK information, and +later with BA/ACK status once it becomes available. As the same PPDU +is processed again, these counters are updated a second time, +resulting in duplicate TX statistics. + +To address this, move the accounting of tx_retry_failed and +tx_retry_count under the ACK/BA status flag check, and similarly gate +tx_duration on the same path. This ensures that each PPDU contributes +to these counters exactly once, avoids double counting, and provides +consistent reporting in userspace tools such as station dump. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 + +Fixes: a0b963e1da5b ("wifi: ath12k: fetch tx_retry and tx_failed from htt_ppdu_stats_user_cmpltn_common_tlv") +Signed-off-by: Sarika Sharma +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260226051947.1379716-1-sarika.sharma@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/dp_htt.c | 24 +++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.c b/drivers/net/wireless/ath/ath12k/dp_htt.c +index e71bb71a6020e..9c19d9707abfb 100644 +--- a/drivers/net/wireless/ath/ath12k/dp_htt.c ++++ b/drivers/net/wireless/ath/ath12k/dp_htt.c +@@ -205,16 +205,9 @@ ath12k_update_per_peer_tx_stats(struct ath12k_pdev_dp *dp_pdev, + if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) + return; + +- if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) { ++ if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) + is_ampdu = + HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags); +- tx_retry_failed = +- __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) - +- __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success); +- tx_retry_count = +- HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + +- HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); +- } + + if (usr_stats->tlv_flags & + BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) { +@@ -223,10 +216,19 @@ ath12k_update_per_peer_tx_stats(struct ath12k_pdev_dp *dp_pdev, + HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M); + tid = le32_get_bits(usr_stats->ack_ba.info, + HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM); +- } + +- if (common->fes_duration_us) +- tx_duration = le32_to_cpu(common->fes_duration_us); ++ if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) { ++ tx_retry_failed = ++ __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) - ++ __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success); ++ tx_retry_count = ++ HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + ++ HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); ++ } ++ ++ if (common->fes_duration_us) ++ tx_duration = le32_to_cpu(common->fes_duration_us); ++ } + + user_rate = &usr_stats->rate; + flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags); +-- +2.53.0 + diff --git a/queue-7.0/wifi-ath12k-fix-legacy-rate-mapping-for-monitor-mode.patch b/queue-7.0/wifi-ath12k-fix-legacy-rate-mapping-for-monitor-mode.patch new file mode 100644 index 0000000000..39e37e9737 --- /dev/null +++ b/queue-7.0/wifi-ath12k-fix-legacy-rate-mapping-for-monitor-mode.patch @@ -0,0 +1,334 @@ +From 2b47e104cdd0c671447c5b8832e5b670bdf36534 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Feb 2026 11:19:24 +0530 +Subject: wifi: ath12k: Fix legacy rate mapping for monitor mode capture + +From: P Praneesh + +[ Upstream commit 616217a989e09c55398db8555e5ef0c64504cb66 ] + +The current implementation incorrectly reports legacy CCK and OFDM rates +in monitor mode radiotap headers. The rate field displays wrong values, +for example showing 11 Mbps when the actual rate is 1 Mbps. This occurs +because the HAL layer uses a unified enum for both CCK and OFDM rates +without distinguishing between long/short preamble variants and proper +rate mapping to hardware rate indices. + +The root cause is threefold: + +1. The hal_rx_legacy_rate enum conflates CCK and OFDM rates into a + single enumeration, making it impossible to differentiate between + 802.11b CCK rates (with long/short preamble variants) and 802.11a/g + OFDM rates. + +2. The L-SIG-B parsing function maps hardware rate values to the wrong + enum values. For CCK rates, it incorrectly combines long and short + preamble cases (e.g., cases 2 and 5 both map to 2 Mbps), losing + preamble information critical for proper rate identification. + +3. The mac layer's rate-to-index conversion function does not properly + handle the precedence between long preamble, short preamble, and + OFDM rates when matching hardware rate values. + +Split the hal_rx_legacy_rate enum into two separate enumerations: +hal_rx_legacy_rate for CCK rates with explicit long preamble (LP) and +short preamble (SP) variants, and hal_rx_legacy_rates_ofdm for OFDM +rates. This separation allows proper identification of rate types and +preamble modes. + +Introduce a new mapping ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate() +that converts HAL CCK rate enums to hardware rate indices defined in +ath12k_hw_rate_cck. This ensures the rate field in ppdu_info contains +the correct hardware rate index that matches the mac layer's expectations. + +Update the L-SIG-B parsing to map each hardware rate value (1-7) to its +corresponding CCK rate enum with proper preamble designation: +- Cases 1-4: Long preamble (1, 2, 5.5, 11 Mbps) +- Cases 5-7: Short preamble (2, 5.5, 11 Mbps) + +Update the L-SIG-A parsing to use the new OFDM-specific enum values, +maintaining the existing rate mapping for 802.11a/g OFDM rates. + +Refactor the mac layer's ath12k_mac_hw_rate_to_idx() function to +implement proper matching precedence: +1. First match OFDM rates using the IEEE80211_RATE_MANDATORY_A flag +2. Then match CCK short preamble rates +3. Finally match CCK long preamble rates as fallback + +Add helper macros ATH12K_MAC_RATE_A_M and ATH12K_MAC_RATE_B to improve +readability of the rate table initialization and ensure the mandatory +flag is set for OFDM rates. + +This fix ensures monitor mode captures display accurate rate information +in the radiotap header, correctly distinguishing between 1 Mbps and +11 Mbps, and properly identifying preamble types for CCK rates. + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01181-QCAHKSWPL_SILICONZ-1 + +Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") +Signed-off-by: P Praneesh +Signed-off-by: Thiraviyam Mariyappan +Reviewed-by: Baochen Qiang +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260209054924.2713072-1-thiraviyam.mariyappan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath12k/hal.h | 31 +++++--- + drivers/net/wireless/ath/ath12k/mac.c | 51 +++++++------ + .../net/wireless/ath/ath12k/wifi7/dp_mon.c | 76 +++++++++++++++---- + 3 files changed, 108 insertions(+), 50 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h +index 43e3880f82579..bf4f7dbae8669 100644 +--- a/drivers/net/wireless/ath/ath12k/hal.h ++++ b/drivers/net/wireless/ath/ath12k/hal.h +@@ -268,21 +268,28 @@ enum hal_rx_reception_type { + }; + + enum hal_rx_legacy_rate { +- HAL_RX_LEGACY_RATE_1_MBPS, +- HAL_RX_LEGACY_RATE_2_MBPS, +- HAL_RX_LEGACY_RATE_5_5_MBPS, +- HAL_RX_LEGACY_RATE_6_MBPS, +- HAL_RX_LEGACY_RATE_9_MBPS, +- HAL_RX_LEGACY_RATE_11_MBPS, +- HAL_RX_LEGACY_RATE_12_MBPS, +- HAL_RX_LEGACY_RATE_18_MBPS, +- HAL_RX_LEGACY_RATE_24_MBPS, +- HAL_RX_LEGACY_RATE_36_MBPS, +- HAL_RX_LEGACY_RATE_48_MBPS, +- HAL_RX_LEGACY_RATE_54_MBPS, ++ HAL_RX_LEGACY_RATE_LP_1_MBPS, ++ HAL_RX_LEGACY_RATE_LP_2_MBPS, ++ HAL_RX_LEGACY_RATE_LP_5_5_MBPS, ++ HAL_RX_LEGACY_RATE_LP_11_MBPS, ++ HAL_RX_LEGACY_RATE_SP_2_MBPS, ++ HAL_RX_LEGACY_RATE_SP_5_5_MBPS, ++ HAL_RX_LEGACY_RATE_SP_11_MBPS, + HAL_RX_LEGACY_RATE_INVALID, + }; + ++enum hal_rx_legacy_rates_ofdm { ++ HAL_RX_LEGACY_RATE_OFDM_48_MBPS, ++ HAL_RX_LEGACY_RATE_OFDM_24_MBPS, ++ HAL_RX_LEGACY_RATE_OFDM_12_MBPS, ++ HAL_RX_LEGACY_RATE_OFDM_6_MBPS, ++ HAL_RX_LEGACY_RATE_OFDM_54_MBPS, ++ HAL_RX_LEGACY_RATE_OFDM_36_MBPS, ++ HAL_RX_LEGACY_RATE_OFDM_18_MBPS, ++ HAL_RX_LEGACY_RATE_OFDM_9_MBPS, ++ HAL_RX_LEGACY_RATE_OFDM_INVALID, ++}; ++ + enum hal_ring_type { + HAL_REO_DST, + HAL_REO_EXCEPTION, +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index b253d1e3f4052..fa36e984c74b2 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -164,30 +164,31 @@ static const struct ieee80211_channel ath12k_6ghz_channels[] = { + CHAN6G(233, 7115, 0), + }; + ++#define ATH12K_MAC_RATE_A_M(bps, code) \ ++ { .bitrate = (bps), .hw_value = (code),\ ++ .flags = IEEE80211_RATE_MANDATORY_A } ++ ++#define ATH12K_MAC_RATE_B(bps, code, code_short) \ ++ { .bitrate = (bps), .hw_value = (code), .hw_value_short = (code_short),\ ++ .flags = IEEE80211_RATE_SHORT_PREAMBLE } ++ + static struct ieee80211_rate ath12k_legacy_rates[] = { + { .bitrate = 10, + .hw_value = ATH12K_HW_RATE_CCK_LP_1M }, +- { .bitrate = 20, +- .hw_value = ATH12K_HW_RATE_CCK_LP_2M, +- .hw_value_short = ATH12K_HW_RATE_CCK_SP_2M, +- .flags = IEEE80211_RATE_SHORT_PREAMBLE }, +- { .bitrate = 55, +- .hw_value = ATH12K_HW_RATE_CCK_LP_5_5M, +- .hw_value_short = ATH12K_HW_RATE_CCK_SP_5_5M, +- .flags = IEEE80211_RATE_SHORT_PREAMBLE }, +- { .bitrate = 110, +- .hw_value = ATH12K_HW_RATE_CCK_LP_11M, +- .hw_value_short = ATH12K_HW_RATE_CCK_SP_11M, +- .flags = IEEE80211_RATE_SHORT_PREAMBLE }, +- +- { .bitrate = 60, .hw_value = ATH12K_HW_RATE_OFDM_6M }, +- { .bitrate = 90, .hw_value = ATH12K_HW_RATE_OFDM_9M }, +- { .bitrate = 120, .hw_value = ATH12K_HW_RATE_OFDM_12M }, +- { .bitrate = 180, .hw_value = ATH12K_HW_RATE_OFDM_18M }, +- { .bitrate = 240, .hw_value = ATH12K_HW_RATE_OFDM_24M }, +- { .bitrate = 360, .hw_value = ATH12K_HW_RATE_OFDM_36M }, +- { .bitrate = 480, .hw_value = ATH12K_HW_RATE_OFDM_48M }, +- { .bitrate = 540, .hw_value = ATH12K_HW_RATE_OFDM_54M }, ++ ATH12K_MAC_RATE_B(20, ATH12K_HW_RATE_CCK_LP_2M, ++ ATH12K_HW_RATE_CCK_SP_2M), ++ ATH12K_MAC_RATE_B(55, ATH12K_HW_RATE_CCK_LP_5_5M, ++ ATH12K_HW_RATE_CCK_SP_5_5M), ++ ATH12K_MAC_RATE_B(110, ATH12K_HW_RATE_CCK_LP_11M, ++ ATH12K_HW_RATE_CCK_SP_11M), ++ ATH12K_MAC_RATE_A_M(60, ATH12K_HW_RATE_OFDM_6M), ++ ATH12K_MAC_RATE_A_M(90, ATH12K_HW_RATE_OFDM_9M), ++ ATH12K_MAC_RATE_A_M(120, ATH12K_HW_RATE_OFDM_12M), ++ ATH12K_MAC_RATE_A_M(180, ATH12K_HW_RATE_OFDM_18M), ++ ATH12K_MAC_RATE_A_M(240, ATH12K_HW_RATE_OFDM_24M), ++ ATH12K_MAC_RATE_A_M(360, ATH12K_HW_RATE_OFDM_36M), ++ ATH12K_MAC_RATE_A_M(480, ATH12K_HW_RATE_OFDM_48M), ++ ATH12K_MAC_RATE_A_M(540, ATH12K_HW_RATE_OFDM_54M), + }; + + static const int +@@ -732,11 +733,17 @@ u8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, + if (ath12k_mac_bitrate_is_cck(rate->bitrate) != cck) + continue; + +- if (rate->hw_value == hw_rate) ++ /* To handle 802.11a PPDU type */ ++ if ((!cck) && (rate->hw_value == hw_rate) && ++ (rate->flags & IEEE80211_RATE_MANDATORY_A)) + return i; ++ /* To handle 802.11b short PPDU type */ + else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE && + rate->hw_value_short == hw_rate) + return i; ++ /* To handle 802.11b long PPDU type */ ++ else if (rate->hw_value == hw_rate) ++ return i; + } + + return 0; +diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c +index c9cea597a92eb..77f5d23be78d6 100644 +--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c ++++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c +@@ -405,6 +405,42 @@ ath12k_wifi7_dp_mon_hal_rx_parse_user_info(const struct hal_receive_user_info *r + } + } + ++static __always_inline u8 ++ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate(u8 rate) ++{ ++ u8 ath12k_rate; ++ ++ /* Map hal_rx_legacy_rate to ath12k_hw_rate_cck */ ++ switch (rate) { ++ case HAL_RX_LEGACY_RATE_LP_1_MBPS: ++ ath12k_rate = ATH12K_HW_RATE_CCK_LP_1M; ++ break; ++ case HAL_RX_LEGACY_RATE_LP_2_MBPS: ++ ath12k_rate = ATH12K_HW_RATE_CCK_LP_2M; ++ break; ++ case HAL_RX_LEGACY_RATE_LP_5_5_MBPS: ++ ath12k_rate = ATH12K_HW_RATE_CCK_LP_5_5M; ++ break; ++ case HAL_RX_LEGACY_RATE_LP_11_MBPS: ++ ath12k_rate = ATH12K_HW_RATE_CCK_LP_11M; ++ break; ++ case HAL_RX_LEGACY_RATE_SP_2_MBPS: ++ ath12k_rate = ATH12K_HW_RATE_CCK_SP_2M; ++ break; ++ case HAL_RX_LEGACY_RATE_SP_5_5_MBPS: ++ ath12k_rate = ATH12K_HW_RATE_CCK_SP_5_5M; ++ break; ++ case HAL_RX_LEGACY_RATE_SP_11_MBPS: ++ ath12k_rate = ATH12K_HW_RATE_CCK_SP_11M; ++ break; ++ default: ++ ath12k_rate = rate; ++ break; ++ } ++ ++ return ath12k_rate; ++} ++ + static void + ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb, + struct hal_rx_mon_ppdu_info *ppdu_info) +@@ -415,25 +451,32 @@ ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb, + rate = u32_get_bits(info0, HAL_RX_LSIG_B_INFO_INFO0_RATE); + switch (rate) { + case 1: +- rate = HAL_RX_LEGACY_RATE_1_MBPS; ++ rate = HAL_RX_LEGACY_RATE_LP_1_MBPS; + break; + case 2: +- case 5: +- rate = HAL_RX_LEGACY_RATE_2_MBPS; ++ rate = HAL_RX_LEGACY_RATE_LP_2_MBPS; + break; + case 3: +- case 6: +- rate = HAL_RX_LEGACY_RATE_5_5_MBPS; ++ rate = HAL_RX_LEGACY_RATE_LP_5_5_MBPS; + break; + case 4: ++ rate = HAL_RX_LEGACY_RATE_LP_11_MBPS; ++ break; ++ case 5: ++ rate = HAL_RX_LEGACY_RATE_SP_2_MBPS; ++ break; ++ case 6: ++ rate = HAL_RX_LEGACY_RATE_SP_5_5_MBPS; ++ break; + case 7: +- rate = HAL_RX_LEGACY_RATE_11_MBPS; ++ rate = HAL_RX_LEGACY_RATE_SP_11_MBPS; + break; + default: + rate = HAL_RX_LEGACY_RATE_INVALID; ++ break; + } + +- ppdu_info->rate = rate; ++ ppdu_info->rate = ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate(rate); + ppdu_info->cck_flag = 1; + } + +@@ -447,31 +490,32 @@ ath12k_wifi7_dp_mon_parse_l_sig_a(const struct hal_rx_lsig_a_info *lsiga, + rate = u32_get_bits(info0, HAL_RX_LSIG_A_INFO_INFO0_RATE); + switch (rate) { + case 8: +- rate = HAL_RX_LEGACY_RATE_48_MBPS; ++ rate = HAL_RX_LEGACY_RATE_OFDM_48_MBPS; + break; + case 9: +- rate = HAL_RX_LEGACY_RATE_24_MBPS; ++ rate = HAL_RX_LEGACY_RATE_OFDM_24_MBPS; + break; + case 10: +- rate = HAL_RX_LEGACY_RATE_12_MBPS; ++ rate = HAL_RX_LEGACY_RATE_OFDM_12_MBPS; + break; + case 11: +- rate = HAL_RX_LEGACY_RATE_6_MBPS; ++ rate = HAL_RX_LEGACY_RATE_OFDM_6_MBPS; + break; + case 12: +- rate = HAL_RX_LEGACY_RATE_54_MBPS; ++ rate = HAL_RX_LEGACY_RATE_OFDM_54_MBPS; + break; + case 13: +- rate = HAL_RX_LEGACY_RATE_36_MBPS; ++ rate = HAL_RX_LEGACY_RATE_OFDM_36_MBPS; + break; + case 14: +- rate = HAL_RX_LEGACY_RATE_18_MBPS; ++ rate = HAL_RX_LEGACY_RATE_OFDM_18_MBPS; + break; + case 15: +- rate = HAL_RX_LEGACY_RATE_9_MBPS; ++ rate = HAL_RX_LEGACY_RATE_OFDM_9_MBPS; + break; + default: +- rate = HAL_RX_LEGACY_RATE_INVALID; ++ rate = HAL_RX_LEGACY_RATE_OFDM_INVALID; ++ break; + } + + ppdu_info->rate = rate; +-- +2.53.0 + diff --git a/queue-7.0/wifi-brcmfmac-fix-error-pointer-dereference.patch b/queue-7.0/wifi-brcmfmac-fix-error-pointer-dereference.patch new file mode 100644 index 0000000000..6683822e07 --- /dev/null +++ b/queue-7.0/wifi-brcmfmac-fix-error-pointer-dereference.patch @@ -0,0 +1,80 @@ +From b032f2597765bcb4da75cfa9ab8b1f3d0e2eee45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Feb 2026 20:30:43 -0600 +Subject: wifi: brcmfmac: Fix error pointer dereference + +From: Ethan Tidmore + +[ Upstream commit dd8592fc6007a451c3e4b9025de365e39de8178a ] + +The function brcmf_chip_add_core() can return an error pointer and is +not checked. Add checks for error pointer. + +Detected by Smatch: +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1010 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1013 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1016 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1019 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:1022 brcmf_chip_recognition() error: +'core' dereferencing possible ERR_PTR() + +Fixes: cb7cf7be9eba7 ("brcmfmac: make chip related functions host interface independent") +Signed-off-by: Ethan Tidmore +Acked-by: Arend van Spriel +Link: https://patch.msgid.link/20260217023043.73631-1-ethantidmore06@gmail.com +[add missing wifi: prefix] +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +index a790f1693b82e..4adc0d0e4251b 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +@@ -1007,18 +1007,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) + + core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, + SI_ENUM_BASE_DEFAULT, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, + BCM4329_CORE_BUS_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, + BCM4329_CORE_SOCRAM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, + BCM4329_CORE_ARM_BASE, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + + core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); ++ if (IS_ERR(core)) ++ return PTR_ERR(core); ++ + brcmf_chip_sb_corerev(ci, core); + } else if (socitype == SOCI_AI) { + ci->iscoreup = brcmf_chip_ai_iscoreup; +-- +2.53.0 + diff --git a/queue-7.0/wifi-ieee80211-fix-definition-of-eht-mcs-15-in-mru.patch b/queue-7.0/wifi-ieee80211-fix-definition-of-eht-mcs-15-in-mru.patch new file mode 100644 index 0000000000..ad3e3e20a5 --- /dev/null +++ b/queue-7.0/wifi-ieee80211-fix-definition-of-eht-mcs-15-in-mru.patch @@ -0,0 +1,47 @@ +From fbc45f2cc7603c9ae363252abc497cbbf7099537 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 14:21:49 +0800 +Subject: wifi: ieee80211: fix definition of EHT-MCS 15 in MRU +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Shayne Chen + +[ Upstream commit cb0caadb64ca0894c4a24e1a34841f260d462f90 ] + +According to the definition in IEEE Std 802.11be-2024, Table 9-417r, each +bit indicates support for the transmission and reception of EHT-MCS 15 in: +- B0: 52+26-tone and 106+26-tone MRUs. +- B1: a 484+242-tone MRU if 80 MHz is supported. +- B2: a 996+484-tone MRU and a 996+484+242-tone MRU if 160 MHz is + supported. +- B3: a 3×996-tone MRU if 320 MHz is supported. + +Fixes: 6239da18d2f9 ("wifi: mac80211: adjust EHT capa when lowering bandwidth") +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260313062150.3165433-1-shayne.chen@mediatek.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + include/linux/ieee80211-eht.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/ieee80211-eht.h b/include/linux/ieee80211-eht.h +index f8e9f5d36d2a2..a97b1d01f3acf 100644 +--- a/include/linux/ieee80211-eht.h ++++ b/include/linux/ieee80211-eht.h +@@ -251,8 +251,8 @@ struct ieee80211_eht_operation_info { + #define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x40 + #define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x07 + +-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x08 +-#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x30 ++#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ 0x10 ++#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ 0x20 + #define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ 0x40 + #define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x78 + #define IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP 0x80 +-- +2.53.0 + diff --git a/queue-7.0/wifi-libertas-don-t-kill-urbs-in-interrupt-context.patch b/queue-7.0/wifi-libertas-don-t-kill-urbs-in-interrupt-context.patch new file mode 100644 index 0000000000..bf16d2fc87 --- /dev/null +++ b/queue-7.0/wifi-libertas-don-t-kill-urbs-in-interrupt-context.patch @@ -0,0 +1,51 @@ +From edf5f21b136d6e59ebf39ac4d3b1fa23bcb85290 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 18:27:58 -0300 +Subject: wifi: libertas: don't kill URBs in interrupt context + +From: Heitor Alves de Siqueira + +[ Upstream commit 7c5c2b661bdb78c1472b8833265c9ed1ee880039 ] + +Serialization for the TX path was enforced by calling +usb_kill_urb()/usb_kill_anchored_urbs(), to prevent transmission before +a previous URB was completed. usb_tx_block() can be called from +interrupt context (e.g. in the HCD giveback path), so we can't always +use it to kill in-flight URBs. + +Prevent sleeping during interrupt context by checking the tx_submitted +anchor for existing URBs. We now return -EBUSY, to indicate there's +a pending request. + +Reported-by: syzbot+74afbb6355826ffc2239@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=74afbb6355826ffc2239 +Fixes: d66676e6ca96 ("wifi: libertas: fix WARNING in usb_tx_block") +Signed-off-by: Heitor Alves de Siqueira +Link: https://patch.msgid.link/20260313-libertas-usb-anchors-v1-2-915afbe988d7@igalia.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/libertas/if_usb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c +index 11cd1422f46a3..d3b9f7619a1a0 100644 +--- a/drivers/net/wireless/marvell/libertas/if_usb.c ++++ b/drivers/net/wireless/marvell/libertas/if_usb.c +@@ -429,7 +429,12 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb + goto tx_ret; + } + +- usb_kill_anchored_urbs(&cardp->tx_submitted); ++ /* check if there are pending URBs */ ++ if (!usb_anchor_empty(&cardp->tx_submitted)) { ++ lbs_deb_usbd(&cardp->udev->dev, "%s failed: pending URB\n", __func__); ++ ret = -EBUSY; ++ goto tx_ret; ++ } + + usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, + usb_sndbulkpipe(cardp->udev, +-- +2.53.0 + diff --git a/queue-7.0/wifi-libertas-use-usb-anchors-for-tracking-in-flight.patch b/queue-7.0/wifi-libertas-use-usb-anchors-for-tracking-in-flight.patch new file mode 100644 index 0000000000..0a65562b69 --- /dev/null +++ b/queue-7.0/wifi-libertas-use-usb-anchors-for-tracking-in-flight.patch @@ -0,0 +1,138 @@ +From 34ba0e056fc1d3bb965b194a6344f028602df296 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Mar 2026 18:27:57 -0300 +Subject: wifi: libertas: use USB anchors for tracking in-flight URBs + +From: Heitor Alves de Siqueira + +[ Upstream commit a57f35fc19add4dfe33703af575a2c19c2cef9c7 ] + +The libertas driver currently handles URB lifecycles manually, which +makes it non-trivial to check if specific URBs are pending or not. Add +anchors for TX/RX URBs, and use those to track in-flight requests. + +Signed-off-by: Heitor Alves de Siqueira +Link: https://patch.msgid.link/20260313-libertas-usb-anchors-v1-1-915afbe988d7@igalia.com +Signed-off-by: Johannes Berg +Stable-dep-of: 7c5c2b661bdb ("wifi: libertas: don't kill URBs in interrupt context") +Signed-off-by: Sasha Levin +--- + .../net/wireless/marvell/libertas/if_usb.c | 27 ++++++++++++------- + .../net/wireless/marvell/libertas/if_usb.h | 3 +++ + 2 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c +index 8a6bf1365cfab..11cd1422f46a3 100644 +--- a/drivers/net/wireless/marvell/libertas/if_usb.c ++++ b/drivers/net/wireless/marvell/libertas/if_usb.c +@@ -114,8 +114,8 @@ static void if_usb_write_bulk_callback(struct urb *urb) + static void if_usb_free(struct if_usb_card *cardp) + { + /* Unlink tx & rx urb */ +- usb_kill_urb(cardp->tx_urb); +- usb_kill_urb(cardp->rx_urb); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); + + usb_free_urb(cardp->tx_urb); + cardp->tx_urb = NULL; +@@ -221,6 +221,9 @@ static int if_usb_probe(struct usb_interface *intf, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol); + ++ init_usb_anchor(&cardp->rx_submitted); ++ init_usb_anchor(&cardp->tx_submitted); ++ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if (usb_endpoint_is_bulk_in(endpoint)) { +@@ -426,7 +429,7 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb + goto tx_ret; + } + +- usb_kill_urb(cardp->tx_urb); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); + + usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, + usb_sndbulkpipe(cardp->udev, +@@ -435,8 +438,10 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb + + cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; + ++ usb_anchor_urb(cardp->tx_urb, &cardp->tx_submitted); + if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { + lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret); ++ usb_unanchor_urb(cardp->tx_urb); + } else { + lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n"); + ret = 0; +@@ -467,8 +472,10 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, + cardp); + + lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); ++ usb_anchor_urb(cardp->rx_urb, &cardp->rx_submitted); + if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { + lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret); ++ usb_unanchor_urb(cardp->rx_urb); + kfree_skb(skb); + cardp->rx_skb = NULL; + ret = -1; +@@ -838,8 +845,8 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret, + } + + /* Cancel any pending usb business */ +- usb_kill_urb(cardp->rx_urb); +- usb_kill_urb(cardp->tx_urb); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); + + cardp->fwlastblksent = 0; + cardp->fwdnldover = 0; +@@ -869,8 +876,8 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret, + if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) { + /* Return to normal operation */ + ret = -EOPNOTSUPP; +- usb_kill_urb(cardp->rx_urb); +- usb_kill_urb(cardp->tx_urb); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); + if (if_usb_submit_rx_urb(cardp) < 0) + ret = -EIO; + goto done; +@@ -900,7 +907,7 @@ static void if_usb_prog_firmware(struct lbs_private *priv, int ret, + wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover); + + timer_delete_sync(&cardp->fw_timeout); +- usb_kill_urb(cardp->rx_urb); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); + + if (!cardp->fwdnldover) { + pr_info("failed to load fw, resetting device!\n"); +@@ -960,8 +967,8 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) + goto out; + + /* Unlink tx & rx urb */ +- usb_kill_urb(cardp->tx_urb); +- usb_kill_urb(cardp->rx_urb); ++ usb_kill_anchored_urbs(&cardp->tx_submitted); ++ usb_kill_anchored_urbs(&cardp->rx_submitted); + + out: + return ret; +diff --git a/drivers/net/wireless/marvell/libertas/if_usb.h b/drivers/net/wireless/marvell/libertas/if_usb.h +index 7d0daeb33c3f7..a0cd36197c2b0 100644 +--- a/drivers/net/wireless/marvell/libertas/if_usb.h ++++ b/drivers/net/wireless/marvell/libertas/if_usb.h +@@ -48,6 +48,9 @@ struct if_usb_card { + struct urb *rx_urb, *tx_urb; + struct lbs_private *priv; + ++ struct usb_anchor rx_submitted; ++ struct usb_anchor tx_submitted; ++ + struct sk_buff *rx_skb; + + uint8_t ep_in; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch b/queue-7.0/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch new file mode 100644 index 0000000000..79cd2e54b4 --- /dev/null +++ b/queue-7.0/wifi-mac80211-handle-vht-ext-nss-in-ieee80211_determ.patch @@ -0,0 +1,46 @@ +From e361851b56ad9a1bff516d27db5736153fcf3d8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Mar 2026 11:02:56 +0100 +Subject: wifi: mac80211: handle VHT EXT NSS in + ieee80211_determine_our_sta_mode() + +From: Nicolas Escande + +[ Upstream commit b5b8e295973083abf823fb66647a7c702a8db8a7 ] + +A station which has a NSS ratio on the number of streams it is capable of +in 160MHz VHT operation is supposed to use the 'Extended NSS BW Support' +as defined by section '9.4.2.156.2 VHT Capabilities Information field'. + +This was missing in ieee80211_determine_our_sta_mode() and so we would +wrongfully downgrade our bandwidth when connecting to an AP that supported +160MHz with messages such as: + + [ 37.638346] wlan1: AP XX:XX:XX:XX:XX:XX changed bandwidth in assoc response, new used config is 5280.000 MHz, width 3 (5290.000/0 MHz) + +Fixes: 310c8387c638 ("wifi: mac80211: clean up connection process") +Signed-off-by: Nicolas Escande +Link: https://patch.msgid.link/20260327100256.3101348-1-nico.escande@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/mlme.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 6a0e2896b54c7..53bd98646e33e 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -6009,7 +6009,8 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata, + + if (is_5ghz && + !(vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | +- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { ++ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | ++ IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))) { + conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80; + mlme_link_id_dbg(sdata, link_id, + "no VHT 160 MHz capability on 5 GHz, limiting to 80 MHz"); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-fix-backoff-fields-and-max_power-calculati.patch b/queue-7.0/wifi-mt76-fix-backoff-fields-and-max_power-calculati.patch new file mode 100644 index 0000000000..d2b6c1ce2d --- /dev/null +++ b/queue-7.0/wifi-mt76-fix-backoff-fields-and-max_power-calculati.patch @@ -0,0 +1,284 @@ +From 7cef02f863e2aa4bac841db41a275352880b0553 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Feb 2026 16:30:27 -0800 +Subject: wifi: mt76: fix backoff fields and max_power calculation + +From: Allen Ye + +[ Upstream commit 37d5b68ab57c5b4fb1c40e62c6b32376c6a2ca2c ] + +The maximum power value may exist in either the data or backoff field. +Previously, backoff power limits were not considered in txpower reporting. +This patch ensures mt76 also considers backoff values in the SKU table. + +Also, each RU entry (RU26, RU52, RU106, BW20, ...) in the DTS corresponds +to 10 stream combinations (1T1ss, 2T1ss, 3T1ss, 4T1ss, 2T2ss, 3T2ss, +4T2ss, 3T3ss, 4T3ss, 4T4ss). + +For beamforming tables: +- In connac2, beamforming entries for BW20~BW160, and OFDM do not include + 1T1ss. +- In connac3, beamforming entries for BW20~BW160, and RU include 1T1ss, + but OFDM beamforming does not include 1T1ss. + +Non-beamforming and RU entries for both connac2 and connac3 include 1T1ss. + +Fixes: b05ab4be9fd7 ("wifi: mt76: mt7915: add bf backoff limit table support") +Signed-off-by: Allen Ye +Co-developed-by: Ryder Lee +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/8fa8ec500b3d4de7b1966c6887f1dfbe5c46a54c.1771205424.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/eeprom.c | 154 ++++++++++++++------ + drivers/net/wireless/mediatek/mt76/mt76.h | 1 - + 2 files changed, 109 insertions(+), 46 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c +index 573400d57ce72..afdb73661866e 100644 +--- a/drivers/net/wireless/mediatek/mt76/eeprom.c ++++ b/drivers/net/wireless/mediatek/mt76/eeprom.c +@@ -9,6 +9,13 @@ + #include + #include + #include "mt76.h" ++#include "mt76_connac.h" ++ ++enum mt76_sku_type { ++ MT76_SKU_RATE, ++ MT76_SKU_BACKOFF, ++ MT76_SKU_BACKOFF_BF_OFFSET, ++}; + + static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len) + { +@@ -292,7 +299,6 @@ mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan) + } + EXPORT_SYMBOL_GPL(mt76_find_channel_node); + +- + static s8 + mt76_get_txs_delta(struct device_node *np, u8 nss) + { +@@ -306,9 +312,24 @@ mt76_get_txs_delta(struct device_node *np, u8 nss) + return be32_to_cpu(val[nss - 1]); + } + ++static inline u8 mt76_backoff_n_chains(struct mt76_dev *dev, u8 idx) ++{ ++ /* 0:1T1ss, 1:2T1ss, ..., 14:5T5ss */ ++ static const u8 connac3_table[] = { ++ 1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5}; ++ static const u8 connac2_table[] = { ++ 1, 2, 3, 4, 2, 3, 4, 3, 4, 4, 0, 0, 0, 0, 0}; ++ ++ if (idx >= ARRAY_SIZE(connac3_table)) ++ return 0; ++ ++ return is_mt799x(dev) ? connac3_table[idx] : connac2_table[idx]; ++} ++ + static void +-mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, +- s8 target_power, s8 nss_delta, s8 *max_power) ++mt76_apply_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len, ++ const s8 *data, s8 target_power, s8 nss_delta, ++ s8 *max_power, int n_chains, enum mt76_sku_type type) + { + int i; + +@@ -316,18 +337,51 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, + return; + + for (i = 0; i < pwr_len; i++) { +- pwr[i] = min_t(s8, target_power, data[i] + nss_delta); ++ u8 backoff_chain_idx = i; ++ int backoff_n_chains; ++ s8 backoff_delta; ++ s8 delta; ++ ++ switch (type) { ++ case MT76_SKU_RATE: ++ delta = 0; ++ backoff_delta = 0; ++ backoff_n_chains = 0; ++ break; ++ case MT76_SKU_BACKOFF_BF_OFFSET: ++ backoff_chain_idx += 1; ++ fallthrough; ++ case MT76_SKU_BACKOFF: ++ delta = mt76_tx_power_path_delta(n_chains); ++ backoff_n_chains = mt76_backoff_n_chains(dev, backoff_chain_idx); ++ backoff_delta = mt76_tx_power_path_delta(backoff_n_chains); ++ break; ++ default: ++ return; ++ } ++ ++ pwr[i] = min_t(s8, target_power + delta - backoff_delta, data[i] + nss_delta); ++ ++ /* used for padding, doesn't need to be considered */ ++ if (data[i] >= S8_MAX - 1) ++ continue; ++ ++ /* only consider backoff value for the configured chain number */ ++ if (type != MT76_SKU_RATE && n_chains != backoff_n_chains) ++ continue; ++ + *max_power = max(*max_power, pwr[i]); + } + } + + static void +-mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, +- const s8 *data, size_t len, s8 target_power, +- s8 nss_delta) ++mt76_apply_multi_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len, ++ s8 pwr_num, const s8 *data, size_t len, ++ s8 target_power, s8 nss_delta, s8 *max_power, ++ int n_chains, enum mt76_sku_type type) + { ++ static const int connac2_backoff_ru_idx = 2; + int i, cur; +- s8 max_power = -128; + + if (!data) + return; +@@ -337,8 +391,26 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, + if (len < pwr_len + 1) + break; + +- mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1, +- target_power, nss_delta, &max_power); ++ /* Each RU entry (RU26, RU52, RU106, BW20, ...) in the DTS ++ * corresponds to 10 stream combinations (1T1ss, 2T1ss, 3T1ss, ++ * 4T1ss, 2T2ss, 3T2ss, 4T2ss, 3T3ss, 4T3ss, 4T4ss). ++ * ++ * For beamforming tables: ++ * - In connac2, beamforming entries for BW20~BW160 and OFDM ++ * do not include 1T1ss. ++ * - In connac3, beamforming entries for BW20~BW160 and RU ++ * include 1T1ss, but OFDM beamforming does not include 1T1ss. ++ * ++ * Non-beamforming and RU entries for both connac2 and connac3 ++ * include 1T1ss. ++ */ ++ if (!is_mt799x(dev) && type == MT76_SKU_BACKOFF && ++ i > connac2_backoff_ru_idx) ++ type = MT76_SKU_BACKOFF_BF_OFFSET; ++ ++ mt76_apply_array_limit(dev, pwr + pwr_len * i, pwr_len, data + 1, ++ target_power, nss_delta, max_power, ++ n_chains, type); + if (--cur > 0) + continue; + +@@ -360,18 +432,11 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, + struct device_node *np; + const s8 *val; + char name[16]; +- u32 mcs_rates = dev->drv->mcs_rates; +- u32 ru_rates = ARRAY_SIZE(dest->ru[0]); + char band; + size_t len; +- s8 max_power = 0; +- s8 max_power_backoff = -127; ++ s8 max_power = -127; + s8 txs_delta; + int n_chains = hweight16(phy->chainmask); +- s8 target_power_combine = target_power + mt76_tx_power_path_delta(n_chains); +- +- if (!mcs_rates) +- mcs_rates = 10; + + memset(dest, target_power, sizeof(*dest) - sizeof(dest->path)); + memset(&dest->path, 0, sizeof(dest->path)); +@@ -409,46 +474,45 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, + txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); + + val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); +- mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, +- target_power, txs_delta, &max_power); ++ mt76_apply_array_limit(dev, dest->cck, ARRAY_SIZE(dest->cck), val, ++ target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE); + +- val = mt76_get_of_array_s8(np, "rates-ofdm", +- &len, ARRAY_SIZE(dest->ofdm)); +- mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val, +- target_power, txs_delta, &max_power); ++ val = mt76_get_of_array_s8(np, "rates-ofdm", &len, ARRAY_SIZE(dest->ofdm)); ++ mt76_apply_array_limit(dev, dest->ofdm, ARRAY_SIZE(dest->ofdm), val, ++ target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE); + +- val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1); +- mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), +- ARRAY_SIZE(dest->mcs), val, len, +- target_power, txs_delta); ++ val = mt76_get_of_array_s8(np, "rates-mcs", &len, ARRAY_SIZE(dest->mcs[0]) + 1); ++ mt76_apply_multi_array_limit(dev, dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), ++ ARRAY_SIZE(dest->mcs), val, len, target_power, ++ txs_delta, &max_power, n_chains, MT76_SKU_RATE); + +- val = mt76_get_of_array_s8(np, "rates-ru", &len, ru_rates + 1); +- mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]), +- ARRAY_SIZE(dest->ru), val, len, +- target_power, txs_delta); ++ val = mt76_get_of_array_s8(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1); ++ mt76_apply_multi_array_limit(dev, dest->ru[0], ARRAY_SIZE(dest->ru[0]), ++ ARRAY_SIZE(dest->ru), val, len, target_power, ++ txs_delta, &max_power, n_chains, MT76_SKU_RATE); + +- max_power_backoff = max_power; + val = mt76_get_of_array_s8(np, "paths-cck", &len, ARRAY_SIZE(dest->path.cck)); +- mt76_apply_array_limit(dest->path.cck, ARRAY_SIZE(dest->path.cck), val, +- target_power_combine, txs_delta, &max_power_backoff); ++ mt76_apply_array_limit(dev, dest->path.cck, ARRAY_SIZE(dest->path.cck), val, ++ target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); + + val = mt76_get_of_array_s8(np, "paths-ofdm", &len, ARRAY_SIZE(dest->path.ofdm)); +- mt76_apply_array_limit(dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val, +- target_power_combine, txs_delta, &max_power_backoff); ++ mt76_apply_array_limit(dev, dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val, ++ target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); + + val = mt76_get_of_array_s8(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest->path.ofdm_bf)); +- mt76_apply_array_limit(dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val, +- target_power_combine, txs_delta, &max_power_backoff); ++ mt76_apply_array_limit(dev, dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val, ++ target_power, txs_delta, &max_power, n_chains, ++ MT76_SKU_BACKOFF_BF_OFFSET); + + val = mt76_get_of_array_s8(np, "paths-ru", &len, ARRAY_SIZE(dest->path.ru[0]) + 1); +- mt76_apply_multi_array_limit(dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]), +- ARRAY_SIZE(dest->path.ru), val, len, +- target_power_combine, txs_delta); ++ mt76_apply_multi_array_limit(dev, dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]), ++ ARRAY_SIZE(dest->path.ru), val, len, target_power, ++ txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); + + val = mt76_get_of_array_s8(np, "paths-ru-bf", &len, ARRAY_SIZE(dest->path.ru_bf[0]) + 1); +- mt76_apply_multi_array_limit(dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]), +- ARRAY_SIZE(dest->path.ru_bf), val, len, +- target_power_combine, txs_delta); ++ mt76_apply_multi_array_limit(dev, dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]), ++ ARRAY_SIZE(dest->path.ru_bf), val, len, target_power, ++ txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); + + return max_power; + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h +index d05e83ea1cacc..32876eab23a84 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -540,7 +540,6 @@ struct mt76_driver_ops { + u32 survey_flags; + u16 txwi_size; + u16 token_size; +- u8 mcs_rates; + + unsigned int link_data_size; + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-fix-deadlock-in-remain-on-channel.patch b/queue-7.0/wifi-mt76-fix-deadlock-in-remain-on-channel.patch new file mode 100644 index 0000000000..c434b3bf72 --- /dev/null +++ b/queue-7.0/wifi-mt76-fix-deadlock-in-remain-on-channel.patch @@ -0,0 +1,68 @@ +From 2ce80714544bd1ae99c530a53108082009f79127 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 14:31:32 +0000 +Subject: wifi: mt76: fix deadlock in remain-on-channel + +From: Chad Monroe + +[ Upstream commit 6939b97ddad3cf3dfbb3b5a0a12ef79cb886747e ] + +mt76_remain_on_channel() and mt76_roc_complete() call mt76_set_channel() +while already holding dev->mutex. Since mt76_set_channel() also acquires +dev->mutex, this results in a deadlock. + +Use __mt76_set_channel() instead of mt76_set_channel(). +Add cancel_delayed_work_sync() for mac_work before acquiring the mutex +in mt76_remain_on_channel() to prevent a secondary deadlock with the +mac_work workqueue. + +Fixes: a8f424c1287c ("wifi: mt76: add multi-radio remain_on_channel functions") +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/ace737e7b621af7c2adb33b0188011a5c1de2166.1765204256.git.chad@monroe.io +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/channel.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c +index 2b705bdb7993c..d9f8529db7ed4 100644 +--- a/drivers/net/wireless/mediatek/mt76/channel.c ++++ b/drivers/net/wireless/mediatek/mt76/channel.c +@@ -326,7 +326,7 @@ void mt76_roc_complete(struct mt76_phy *phy) + mlink->mvif->roc_phy = NULL; + if (phy->main_chandef.chan && + !test_bit(MT76_MCU_RESET, &dev->phy.state)) +- mt76_set_channel(phy, &phy->main_chandef, false); ++ __mt76_set_channel(phy, &phy->main_chandef, false); + mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); + phy->roc_vif = NULL; + phy->roc_link = NULL; +@@ -370,6 +370,8 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + if (!phy) + return -EINVAL; + ++ cancel_delayed_work_sync(&phy->mac_work); ++ + mutex_lock(&dev->mutex); + + if (phy->roc_vif || dev->scan.phy == phy || +@@ -388,7 +390,14 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + phy->roc_vif = vif; + phy->roc_link = mlink; + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); +- mt76_set_channel(phy, &chandef, true); ++ ret = __mt76_set_channel(phy, &chandef, true); ++ if (ret) { ++ mlink->mvif->roc_phy = NULL; ++ phy->roc_vif = NULL; ++ phy->roc_link = NULL; ++ mt76_put_vif_phy_link(phy, vif, mlink); ++ goto out; ++ } + ieee80211_ready_on_channel(hw); + ieee80211_queue_delayed_work(phy->hw, &phy->roc_work, + msecs_to_jiffies(duration)); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-fix-memory-leak-after-mt76_connac_mcu_allo.patch b/queue-7.0/wifi-mt76-fix-memory-leak-after-mt76_connac_mcu_allo.patch new file mode 100644 index 0000000000..61f1891d78 --- /dev/null +++ b/queue-7.0/wifi-mt76-fix-memory-leak-after-mt76_connac_mcu_allo.patch @@ -0,0 +1,121 @@ +From f72ce00d836c9b2c8dcfb0231100f80be5248099 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jan 2026 14:49:19 +0000 +Subject: wifi: mt76: Fix memory leak after mt76_connac_mcu_alloc_sta_req() + +From: Zilin Guan + +[ Upstream commit c41075ce8cf05ed8c0e7b7efef000dce548ffc42 ] + +mt76_connac_mcu_alloc_sta_req() allocates an skb which is expected to +be freed eventually by mt76_mcu_skb_send_msg(). However, currently if +an intermediate function fails before sending, the allocated skb is +leaked. + +Specifically, mt76_connac_mcu_sta_wed_update() and +mt76_connac_mcu_sta_key_tlv() may fail, leading to an immediate memory +leak in the error path. + +Fix this by explicitly freeing the skb in these error paths. +Commit 7c0f63fe37a5 ("wifi: mt76: mt7996: fix memory leak on +mt7996_mcu_sta_key_tlv error") made a similar change. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: d1369e515efe ("wifi: mt76: connac: introduce mt76_connac_mcu_sta_wed_update utility routine") +Fixes: 6683d988089c ("mt76: connac: move mt76_connac_mcu_add_key in connac module") +Fixes: 4f831d18d12d ("wifi: mt76: mt7915: enable WED RX support") +Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") +Signed-off-by: Zilin Guan +Link: https://patch.msgid.link/20260116144919.1482558-1-zilin@seu.edu.cn +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 16 ++++++++++++---- + drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 4 +++- + drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 4 +++- + 3 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +index 0457712286d55..3f583e2a1dc12 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +@@ -1295,8 +1295,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, + wtbl_hdr); + + ret = mt76_connac_mcu_sta_wed_update(dev, skb); +- if (ret) ++ if (ret) { ++ dev_kfree_skb(skb); + return ret; ++ } + + ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true); + if (ret) +@@ -1309,8 +1311,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, + mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); + + ret = mt76_connac_mcu_sta_wed_update(dev, skb); +- if (ret) ++ if (ret) { ++ dev_kfree_skb(skb); + return ret; ++ } + + return mt76_mcu_skb_send_msg(dev, skb, cmd, true); + } +@@ -2764,12 +2768,16 @@ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, + return PTR_ERR(skb); + + ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd); +- if (ret) ++ if (ret) { ++ dev_kfree_skb(skb); + return ret; ++ } + + ret = mt76_connac_mcu_sta_wed_update(dev, skb); +- if (ret) ++ if (ret) { ++ dev_kfree_skb(skb); + return ret; ++ } + + return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); + } +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +index 95b8f34a7b1df..023c92dac0648 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -1765,8 +1765,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, + } + out: + ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb); +- if (ret) ++ if (ret) { ++ dev_kfree_skb(skb); + return ret; ++ } + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(STA_REC_UPDATE), true); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +index dec8e2de86b69..abcdd0e0b3b5a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +@@ -1288,8 +1288,10 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, + return PTR_ERR(skb); + + ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta); +- if (ret) ++ if (ret) { ++ dev_kfree_skb(skb); + return ret; ++ } + + return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); + } +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-fix-memory-leak-destroying-device.patch b/queue-7.0/wifi-mt76-fix-memory-leak-destroying-device.patch new file mode 100644 index 0000000000..485f08ed60 --- /dev/null +++ b/queue-7.0/wifi-mt76-fix-memory-leak-destroying-device.patch @@ -0,0 +1,56 @@ +From 00df6199ffbf43919d03b357adc32e5da6bfd548 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 8 Dec 2025 19:54:08 +0100 +Subject: wifi: mt76: Fix memory leak destroying device + +From: Lorenzo Bianconi + +[ Upstream commit 6b470f36616e3448d44b0ef4b1de2a3e3a31b5be ] + +All MT76 rx queues have an associated page_pool even if the queue is not +associated to a NAPI (e.g. WED RRO queues with WED enabled). Destroy the +page_pool running mt76_dma_cleanup routine during module unload. +Moreover returns pages to the page pool if WED is not enabled for WED RRO +queues. + +Fixes: 950d0abb5cd94 ("wifi: mt76: mt7996: add wed rx support") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251208-mt76-fix-memory-leak-v1-1-cba813fc62b8@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/dma.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c +index f240016ed9f0e..893ac14285cab 100644 +--- a/drivers/net/wireless/mediatek/mt76/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/dma.c +@@ -874,7 +874,12 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) + if (!buf) + break; + +- if (!mt76_queue_is_wed_rro(q)) ++ if (mtk_wed_device_active(&dev->mmio.wed) && ++ mt76_queue_is_wed_rro(q)) ++ continue; ++ ++ if (!mt76_queue_is_wed_rro_rxdmad_c(q) && ++ !mt76_queue_is_wed_rro_ind(q)) + mt76_put_page_pool_buf(buf, false); + } while (1); + +@@ -1168,10 +1173,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev) + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + +- if (mtk_wed_device_active(&dev->mmio.wed) && +- mt76_queue_is_wed_rro(q)) +- continue; +- + netif_napi_del(&dev->napi[i]); + mt76_dma_rx_cleanup(dev, q); + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-fix-multi-radio-on-channel-scanning.patch b/queue-7.0/wifi-mt76-fix-multi-radio-on-channel-scanning.patch new file mode 100644 index 0000000000..c9b5c02cff --- /dev/null +++ b/queue-7.0/wifi-mt76-fix-multi-radio-on-channel-scanning.patch @@ -0,0 +1,85 @@ +From ce7f886e5c46ae03d07139fff3e5637af15e1cda Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 06:07:20 +0000 +Subject: wifi: mt76: fix multi-radio on-channel scanning + +From: Chad Monroe + +[ Upstream commit 0420180df092419a96351fb2afec1e2a74d385c3 ] + +avoid unnecessary channel switch when performing an on-channel scan +using a multi-radio device. + +Fixes: c56d6edebc1f ("wifi: mt76: mt7996: use emulated hardware scan support") +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/20251118102723.47997-1-nbd@nbd.name +Link: https://patch.msgid.link/20260309060730.87840-1-nbd@nbd.name +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/scan.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c +index 63b0447e55c15..fec79a5cd03bf 100644 +--- a/drivers/net/wireless/mediatek/mt76/scan.c ++++ b/drivers/net/wireless/mediatek/mt76/scan.c +@@ -16,7 +16,7 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) + + clear_bit(MT76_SCANNING, &phy->state); + +- if (dev->scan.chan && phy->main_chandef.chan && ++ if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel && + !test_bit(MT76_MCU_RESET, &dev->phy.state)) + mt76_set_channel(phy, &phy->main_chandef, false); + mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); +@@ -85,6 +85,7 @@ void mt76_scan_work(struct work_struct *work) + struct cfg80211_chan_def chandef = {}; + struct mt76_phy *phy = dev->scan.phy; + int duration = HZ / 9; /* ~110 ms */ ++ bool offchannel = true; + int i; + + if (dev->scan.chan_idx >= req->n_channels) { +@@ -92,7 +93,7 @@ void mt76_scan_work(struct work_struct *work) + return; + } + +- if (dev->scan.chan && phy->num_sta) { ++ if (dev->scan.chan && phy->num_sta && phy->offchannel) { + dev->scan.chan = NULL; + mt76_set_channel(phy, &phy->main_chandef, false); + goto out; +@@ -100,20 +101,26 @@ void mt76_scan_work(struct work_struct *work) + + dev->scan.chan = req->channels[dev->scan.chan_idx++]; + cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20); +- mt76_set_channel(phy, &chandef, true); ++ if (phy->main_chandef.chan == dev->scan.chan) { ++ chandef = phy->main_chandef; ++ offchannel = false; ++ } ++ ++ mt76_set_channel(phy, &chandef, offchannel); + + if (!req->n_ssids || + chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) + goto out; + +- duration = HZ / 16; /* ~60 ms */ ++ if (phy->offchannel) ++ duration = HZ / 16; /* ~60 ms */ + local_bh_disable(); + for (i = 0; i < req->n_ssids; i++) + mt76_scan_send_probe(dev, &req->ssids[i]); + local_bh_enable(); + + out: +- if (dev->scan.chan) ++ if (dev->scan.chan && phy->offchannel) + duration = max_t(int, duration, + msecs_to_jiffies(req->duration + + (req->duration >> 5))); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7615-fix-use_cts_prot-support.patch b/queue-7.0/wifi-mt76-mt7615-fix-use_cts_prot-support.patch new file mode 100644 index 0000000000..73fb21d0fc --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7615-fix-use_cts_prot-support.patch @@ -0,0 +1,173 @@ +From 895e2ba6e5a1a274d2894a328cbbbbaab9e0c59a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 09:41:56 -0800 +Subject: wifi: mt76: mt7615: fix use_cts_prot support + +From: Ryder Lee + +[ Upstream commit 1974a67d9b65c29a0a9426e32e8cd8c056de48b7 ] + +Driver should not directly write WTBL to prevent overwritten issues. + +With this fix, when driver needs to adjust its behavior for compatibility, +especially concerning older 11g/n devices, by enabling or disabling CTS +protection frames, often for hidden SSIDs or to manage legacy clients. + +Fixes: e34235ccc5e3 ("wifi: mt76: mt7615: enable use_cts_prot support") +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/edb87088b0111b32fafc6c4179f54a5286dd37d8.1768879119.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7615/mac.c | 15 ------ + .../net/wireless/mediatek/mt76/mt7615/main.c | 7 +-- + .../net/wireless/mediatek/mt76/mt7615/mcu.c | 47 +++++++++++++++++++ + .../wireless/mediatek/mt76/mt7615/mt7615.h | 5 +- + .../net/wireless/mediatek/mt76/mt7615/regs.h | 2 - + 5 files changed, 53 insertions(+), 23 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +index 45992fdcec60c..ce00514685016 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +@@ -1167,21 +1167,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, + } + EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); + +-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, +- struct ieee80211_vif *vif, bool enable) +-{ +- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; +- u32 addr; +- +- addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4; +- +- if (enable) +- mt76_set(dev, addr, MT_WTBL_W3_RTS); +- else +- mt76_clear(dev, addr, MT_WTBL_W3_RTS); +-} +-EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); +- + static int + mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c +index 727266892c3df..fc619acbb40d0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c +@@ -583,9 +583,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, + } + } + +- if (changed & BSS_CHANGED_ERP_CTS_PROT) +- mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot); +- + if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { + mt7615_mcu_add_bss_info(phy, vif, NULL, true); + mt7615_mcu_sta_add(phy, vif, NULL, true); +@@ -598,6 +595,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, + BSS_CHANGED_BEACON_ENABLED)) + mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); + ++ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) ++ mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode, ++ info->use_cts_prot); ++ + if (changed & BSS_CHANGED_PS) + mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +index fc0054f8bd602..ff57ede87f717 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +@@ -2564,3 +2564,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, + return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), + &req, sizeof(req), false); + } ++ ++int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot) ++{ ++ struct mt7615_dev *dev = phy->dev; ++ struct { ++ u8 prot_idx; ++ u8 band; ++ u8 rsv[2]; ++ ++ bool long_nav; ++ bool prot_mm; ++ bool prot_gf; ++ bool prot_bw40; ++ bool prot_rifs; ++ bool prot_bw80; ++ bool prot_bw160; ++ u8 prot_erp_mask; ++ } __packed req = { ++ .prot_idx = 0x2, ++ .band = phy != &dev->phy, ++ }; ++ ++ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: ++ req.prot_mm = true; ++ req.prot_gf = true; ++ fallthrough; ++ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: ++ req.prot_bw40 = true; ++ break; ++ } ++ ++ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) ++ req.prot_gf = true; ++ ++ if (use_cts_prot) { ++ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; ++ u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; ++ ++ req.prot_erp_mask = BIT(i); ++ } ++ ++ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req, ++ sizeof(req), true); ++} +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +index c93fd245c90fb..391928405f322 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +@@ -467,8 +467,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy); + void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); + void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); + void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); +-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, +- struct ieee80211_vif *vif, bool enable); + void mt7615_mac_sta_poll(struct mt7615_dev *dev); + int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, +@@ -523,7 +521,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); + int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); + int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); + int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); +- ++int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot); + int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +index eb3c24d51987d..e4133e9181d0f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +@@ -455,8 +455,6 @@ enum mt7615_reg_base { + #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) + #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) + +-#define MT_WTBL_W3_RTS BIT(22) +- + #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) + #define MT_WTBL_W5_SHORT_GI_20 BIT(8) + #define MT_WTBL_W5_SHORT_GI_40 BIT(9) +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch b/queue-7.0/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch new file mode 100644 index 0000000000..f3176f8341 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7915-fix-use-after-free-bugs-in-mt7915_m.patch @@ -0,0 +1,53 @@ +From 189c9abef34d7568ae3dc3f2c769764761034210 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Jan 2026 22:57:59 +0800 +Subject: wifi: mt76: mt7915: fix use-after-free bugs in mt7915_mac_dump_work() + +From: Duoming Zhou + +[ Upstream commit 1146d0946b5358fad24812bd39d68f31cd40cc34 ] + +When the mt7915 pci chip is detaching, the mt7915_crash_data is +released in mt7915_coredump_unregister(). However, the work item +dump_work may still be running or pending, leading to UAF bugs +when the already freed crash_data is dereferenced again in +mt7915_mac_dump_work(). + +The race condition can occur as follows: + +CPU 0 (removal path) | CPU 1 (workqueue) +mt7915_pci_remove() | mt7915_sys_recovery_set() + mt7915_unregister_device() | mt7915_reset() + mt7915_coredump_unregister() | queue_work() + vfree(dev->coredump.crash_data) | mt7915_mac_dump_work() + | crash_data-> // UAF + +Fix this by ensuring dump_work is properly canceled before +the crash_data is deallocated. Add cancel_work_sync() in +mt7915_unregister_device() to synchronize with any pending +or executing dump work. + +Fixes: 4dbcb9125cc3 ("wifi: mt76: mt7915: enable coredump support") +Signed-off-by: Duoming Zhou +Link: https://patch.msgid.link/20260130145759.84272-1-duoming@zju.edu.cn +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7915/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +index 22443cbc74adc..250c2d2479b0c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -1294,6 +1294,7 @@ int mt7915_register_device(struct mt7915_dev *dev) + + void mt7915_unregister_device(struct mt7915_dev *dev) + { ++ cancel_work_sync(&dev->dump_work); + mt7915_unregister_ext_phy(dev); + mt7915_coredump_unregister(dev); + mt7915_unregister_thermal(&dev->phy); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7915-fix-use_cts_prot-support.patch b/queue-7.0/wifi-mt76-mt7915-fix-use_cts_prot-support.patch new file mode 100644 index 0000000000..0bfdf2eb85 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7915-fix-use_cts_prot-support.patch @@ -0,0 +1,195 @@ +From 1bb24eff6b76cfb78402e655dd1e5bb0146e19d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 09:41:57 -0800 +Subject: wifi: mt76: mt7915: fix use_cts_prot support + +From: Ryder Lee + +[ Upstream commit 8b2c26562b95c6397e132d21f2bd3d73aaee0c0a ] + +With this fix, when driver needs to adjust its behavior for compatibility, +especially concerning older 11g/n devices, by enabling or disabling CTS +protection frames, often for hidden SSIDs or to manage legacy clients. + +Fixes: 150b91419d3d ("wifi: mt76: mt7915: enable use_cts_prot support") +Signed-off-by: Ryder Lee +Link: https://patch.msgid.link/eb8db4d0bf1c89b7486e89facb788ae3e510dd8b.1768879119.git.ryder.lee@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7915/mac.c | 13 ---- + .../net/wireless/mediatek/mt76/mt7915/main.c | 7 ++- + .../net/wireless/mediatek/mt76/mt7915/mcu.c | 62 +++++++++++++++++++ + .../net/wireless/mediatek/mt76/mt7915/mcu.h | 11 ++++ + .../wireless/mediatek/mt76/mt7915/mt7915.h | 4 ++ + 5 files changed, 81 insertions(+), 16 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +index cefe56c05731d..cec2c4208255f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +@@ -232,19 +232,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) + rcu_read_unlock(); + } + +-void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, +- struct ieee80211_vif *vif, bool enable) +-{ +- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; +- u32 addr; +- +- addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); +- if (enable) +- mt76_set(dev, addr, BIT(5)); +- else +- mt76_clear(dev, addr, BIT(5)); +-} +- + static void + mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, + struct mt7915_sta *msta, struct sk_buff *skb, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +index 90d5e79fbf74d..0892291616ead 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c +@@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw) + if (ret) + goto out; + +- ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, ++ ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES, + phy->mt76->band_idx); + if (ret) + goto out; +@@ -633,8 +633,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + if (set_sta == 1) + mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); + +- if (changed & BSS_CHANGED_ERP_CTS_PROT) +- mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); ++ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) ++ mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode, ++ info->use_cts_prot); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = 9; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +index 00bff4d3aab80..95b8f34a7b1df 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -3954,6 +3954,68 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, + return ret; + } + ++int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot) ++{ ++ struct mt7915_dev *dev = phy->dev; ++ int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot); ++ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; ++ struct bss_info_prot *prot; ++ struct sk_buff *skb; ++ struct tlv *tlv; ++ enum { ++ PROT_NONMEMBER = BIT(1), ++ PROT_20MHZ = BIT(2), ++ PROT_NONHT_MIXED = BIT(3), ++ PROT_LEGACY_ERP = BIT(5), ++ PROT_NONGF_STA = BIT(7), ++ }; ++ u32 rts_threshold; ++ ++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, ++ NULL, len); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO, ++ sizeof(*prot)); ++ prot = (struct bss_info_prot *)tlv; ++ ++ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: ++ prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); ++ break; ++ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: ++ prot->prot_mode = cpu_to_le32(PROT_20MHZ); ++ break; ++ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: ++ prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); ++ break; ++ } ++ ++ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) ++ prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); ++ ++ if (use_cts_prot) ++ prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); ++ ++ /* reuse current RTS setting */ ++ rts_threshold = phy->mt76->hw->wiphy->rts_threshold; ++ if (rts_threshold == (u32)-1) ++ prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES); ++ else ++ prot->rts_len_thres = cpu_to_le32(rts_threshold); ++ ++ prot->rts_pkt_thres = 0x2; ++ ++ prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); ++ if (!prot->he_rts_thres) ++ prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); ++ ++ return mt76_mcu_skb_send_msg(&dev->mt76, skb, ++ MCU_EXT_CMD(BSS_INFO_UPDATE), true); ++} ++ + int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct cfg80211_he_bss_color *he_bss_color) + { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +index 3af11a075a2f4..22f73a5ed4259 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +@@ -399,6 +399,17 @@ struct bss_info_inband_discovery { + __le16 prob_rsp_len; + } __packed __aligned(4); + ++struct bss_info_prot { ++ __le16 tag; ++ __le16 len; ++ __le32 prot_type; ++ __le32 prot_mode; ++ __le32 rts_len_thres; ++ __le16 he_rts_thres; ++ u8 rts_pkt_thres; ++ u8 rsv[5]; ++} __packed; ++ + enum { + BSS_INFO_BCN_CSA, + BSS_INFO_BCN_BCC, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +index b5c06201b7078..bf1d915a3ca23 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +@@ -84,6 +84,8 @@ + #define MT7915_CRIT_TEMP 110 + #define MT7915_MAX_TEMP 120 + ++#define MT7915_RTS_LEN_THRES 0x92b ++ + struct mt7915_vif; + struct mt7915_sta; + struct mt7915_dfs_pulse; +@@ -473,6 +475,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v + u32 changed); + int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int enable, u32 changed); ++int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, ++ u8 ht_mode, bool use_cts_prot); + int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd); + int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch b/queue-7.0/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch new file mode 100644 index 0000000000..be4117da56 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7921-fix-6ghz-regulatory-update-on-conne.patch @@ -0,0 +1,39 @@ +From c0bee1f6ddc6e9efddceeb5c3a48505d840a34cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Feb 2026 17:50:25 +0800 +Subject: wifi: mt76: mt7921: fix 6GHz regulatory update on connection + +From: Michael Lo + +[ Upstream commit 3dc0c40d7806c72cfe88cf4e1e2650c1673f9db4 ] + +Call mt7921_regd_update() instead of mt7921_mcu_set_clc() when setting +the 6GHz power type after connection, so that regulatory limits and SAR +power are also applied. + +Fixes: 51ba0e3a15eb ("wifi: mt76: mt7921: add 6GHz power type support for clc") +Signed-off-by: Michael Lo +Link: https://patch.msgid.link/20260211095025.2415624-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index 42b9514e04e71..3d74fabe74085 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -800,7 +800,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) + } + + out: +- mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env); ++ if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ) ++ mt7921_regd_update(dev); + } + + int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7921-fix-potential-deadlock-in-mt7921_ro.patch b/queue-7.0/wifi-mt76-mt7921-fix-potential-deadlock-in-mt7921_ro.patch new file mode 100644 index 0000000000..d55dc0b6f1 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7921-fix-potential-deadlock-in-mt7921_ro.patch @@ -0,0 +1,61 @@ +From 963e696b67b6c30dca1117fb65f709f7af25fc27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Jan 2026 12:00:13 -0600 +Subject: wifi: mt76: mt7921: fix potential deadlock in mt7921_roc_abort_sync + +From: Sean Wang + +[ Upstream commit d5059e52fd8bc624ec4255c9fa01a266513d126b ] + +roc_abort_sync() can deadlock with roc_work(). roc_work() holds +dev->mt76.mutex, while cancel_work_sync() waits for roc_work() +to finish. If the caller already owns the same mutex, both +sides block and no progress is possible. + +This deadlock can occur during station removal when +mt76_sta_state() -> mt76_sta_remove() -> mt7921_mac_sta_remove() -> +mt7921_roc_abort_sync() invokes cancel_work_sync() while +roc_work() is still running and holding dev->mt76.mutex. + +This avoids the mutex deadlock and preserves exactly-once +work ownership. + +Fixes: 352d966126e6 ("wifi: mt76: mt7921: fix a potential association failure upon resuming") +Co-developed-by: Quan Zhou +Signed-off-by: Quan Zhou +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20260126180013.8167-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index f42e40f9663d8..42b9514e04e71 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -371,12 +371,15 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev) + { + struct mt792x_phy *phy = &dev->phy; + ++ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) ++ return; ++ + timer_delete_sync(&phy->roc_timer); +- cancel_work_sync(&phy->roc_work); +- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) +- ieee80211_iterate_interfaces(mt76_hw(dev), +- IEEE80211_IFACE_ITER_RESUME_ALL, +- mt7921_roc_iter, (void *)phy); ++ cancel_work(&phy->roc_work); ++ ++ ieee80211_iterate_interfaces(mt76_hw(dev), ++ IEEE80211_IFACE_ITER_RESUME_ALL, ++ mt7921_roc_iter, (void *)phy); + } + EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync); + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch b/queue-7.0/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch new file mode 100644 index 0000000000..b7b2cb9ec2 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7921-place-upper-limit-on-station-aid.patch @@ -0,0 +1,73 @@ +From df202dda520a0d7cc19415bd961dd17ac5f2b97f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Sep 2025 17:07:11 -0700 +Subject: wifi: mt76: mt7921: Place upper limit on station AID + +From: Rory Little + +[ Upstream commit 4d0bf21e3e20619d51d06c0c36207aabab8b712c ] + +Any station configured with an AID over 20 causes a firmware crash. +This situation occurred in our testing using an AP interface on 7922 +hardware, with a modified hostapd, sourced from Mediatek's OpenWRT +feeds. + +In stock hostapd, station AIDs begin counting at 1, and this +configuration is prevented with an upper limit on associated stations. +However, the modified hostapd began allocation at 65, which caused the +firmware to crash. This fix does not allow these AIDs to work, but will +prevent the firmware crash. + +This crash was only seen on IFTYPE_AP interfaces, and the fix does not +appear to have an effect on IFTYPE_STATION behavior. + +Fixes: 5c14a5f944b9 ("mt76: mt7921: introduce mt7921e support") +Signed-off-by: Rory Little +Link: https://patch.msgid.link/20250904000711.3033860-1-rory@candelatech.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 6 ++++++ + drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 2 ++ + 2 files changed, 8 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index 021335805acb3..f42e40f9663d8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -808,6 +808,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + int ret, idx; + ++ if (sta->aid > MT7921_MAX_AID) ++ return -ENOENT; ++ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); + if (idx < 0) + return -ENOSPC; +@@ -851,6 +854,9 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + ++ if (sta->aid > MT7921_MAX_AID) ++ return -ENOENT; ++ + if (ev != MT76_STA_EVENT_ASSOC) + return 0; + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +index 83fc7f49ff848..ad92af98e3145 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +@@ -7,6 +7,8 @@ + #include "../mt792x.h" + #include "regs.h" + ++#define MT7921_MAX_AID 20 ++ + #define MT7921_TX_RING_SIZE 2048 + #define MT7921_TX_MCU_RING_SIZE 256 + #define MT7921_TX_FWDL_RING_SIZE 128 +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch b/queue-7.0/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch new file mode 100644 index 0000000000..8c22a81363 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7921-reset-ampdu_state-state-in-case-of-.patch @@ -0,0 +1,43 @@ +From 933127d2b700fbce38eb3ebe79d16eb6f8cab881 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 18:59:30 -0600 +Subject: wifi: mt76: mt7921: Reset ampdu_state state in case of failure in + mt76_connac2_tx_check_aggr() + +From: Sean Wang + +[ Upstream commit 53ffffeb9624ffab6d9a3b1da8635a23f1172b5e ] + +Reset ampdu_state if ieee80211_start_tx_ba_session() fails in +mt76_connac2_tx_check_aggr(), otherwise the driver may incorrectly +assume aggregation is active and skip future BA setup attempts. + +Fixes: 163f4d22c118 ("mt76: mt7921: add MAC support") +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20251216005930.9412-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +index b41ca1410da92..aab4630570093 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +@@ -1153,8 +1153,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) + return; + + wcid = (struct mt76_wcid *)sta->drv_priv; +- if (!test_and_set_bit(tid, &wcid->ampdu_state)) +- ieee80211_start_tx_ba_session(sta, tid, 0); ++ if (!test_and_set_bit(tid, &wcid->ampdu_state)) { ++ if (ieee80211_start_tx_ba_session(sta, tid, 0)) ++ clear_bit(tid, &wcid->ampdu_state); ++ } + } + EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7925-drop-puncturing-handling-from-bss-c.patch b/queue-7.0/wifi-mt76-mt7925-drop-puncturing-handling-from-bss-c.patch new file mode 100644 index 0000000000..56b8499113 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7925-drop-puncturing-handling-from-bss-c.patch @@ -0,0 +1,54 @@ +From 7271a4eeb625c53ec9d12d0bb5436620701173a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 20:20:17 -0600 +Subject: wifi: mt76: mt7925: drop puncturing handling from BSS change path + +From: Sean Wang + +[ Upstream commit 59a1864509d084a4b34117e693951c06b846b00a ] + +IEEE80211_CHANCTX_CHANGE_PUNCTURING is a channel context change +flag and should not be checked in the BSS change handler, where +the changed mask represents enum ieee80211_bss_change. + +Remove the puncturing handling from the BSS path and rely on +mt7925_change_chanctx() to update puncturing configuration. + +Fixes: cadebdad959b ("wifi: mt76: mt7925: add EHT preamble puncturing") +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20251216022017.23870-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index d99a60ae063e8..3d622c066ac76 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1894,10 +1894,8 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; +- struct ieee80211_bss_conf *link_conf; + + mconf = mt792x_vif_to_link(mvif, info->link_id); +- link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); + + mt792x_mutex_acquire(dev); + +@@ -1939,10 +1937,6 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, + mvif->mlo_pm_state = MT792x_MLO_CHANGED_PS; + } + +- if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) +- mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76, +- link_conf, NULL); +- + if (changed & BSS_CHANGED_CQM) + mt7925_mcu_set_rssimonitor(dev, vif); + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch b/queue-7.0/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch new file mode 100644 index 0000000000..c98383337f --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7925-fix-incorrect-mlo-mode-in-firmware-.patch @@ -0,0 +1,89 @@ +From 8b3463ff9772b12eab794e866382606602fe6eca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 11 Dec 2025 20:38:36 +0800 +Subject: wifi: mt76: mt7925: Fix incorrect MLO mode in firmware control + +From: Leon Yen + +[ Upstream commit 1695f662329faa07c860c73453c097823852df28 ] + +The selection of MLO mode should depend on the capabilities of the STA +rather than those of the peer AP to avoid compatibility issues with +certain APs, such as Xiaomi BE5000 WiFi7 router. + +Fixes: 69acd6d910b0c ("wifi: mt76: mt7925: add mt7925_change_vif_links") +Signed-off-by: Leon Yen +Link: https://patch.msgid.link/20251211123836.4169436-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 2 +- + drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 9 ++++++--- + drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h | 4 ++-- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 2d358a96640c9..d99a60ae063e8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -541,7 +541,7 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy, + + phy->roc_grant = false; + +- err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id); ++ err = mt7925_mcu_set_mlo_roc(phy, mconf, sel_links, 5, ++phy->roc_token_id); + if (err < 0) { + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + goto out; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +index 47f91b9f1b95b..dec8e2de86b69 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +@@ -1294,8 +1294,8 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, + return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); + } + +-int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, +- int duration, u8 token_id) ++int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, ++ u16 sel_links, int duration, u8 token_id) + { + struct mt792x_vif *mvif = mconf->vif; + struct ieee80211_vif *vif = container_of((void *)mvif, +@@ -1330,6 +1330,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + .roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)) + }; + ++ struct wiphy *wiphy = phy->mt76->hw->wiphy; ++ + if (!mconf || hweight16(vif->valid_links) < 2 || + hweight16(sel_links) != 2) + return -EPERM; +@@ -1352,7 +1354,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ; + } + +- if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) ++ if (!(wiphy->iftype_ext_capab[0].mld_capa_and_ops & ++ IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS)) + type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : + MT7925_ROC_REQ_MLSR_AA; + else +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +index 6b9bf1b890320..a1d902ccce6d2 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +@@ -349,8 +349,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, + int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); + int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap env_cap); +-int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, +- int duration, u8 token_id); ++int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, ++ u16 sel_links, int duration, u8 token_id); + int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + struct ieee80211_channel *chan, int duration, + enum mt7925_roc_req type, u8 token_id); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7925-fix-potential-deadlock-in-mt7925_ro.patch b/queue-7.0/wifi-mt76-mt7925-fix-potential-deadlock-in-mt7925_ro.patch new file mode 100644 index 0000000000..63c61ba21e --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7925-fix-potential-deadlock-in-mt7925_ro.patch @@ -0,0 +1,63 @@ +From b3d0fd3527a19d18fcd1da60359dafc2b1c34e84 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 19:38:49 -0600 +Subject: wifi: mt76: mt7925: fix potential deadlock in mt7925_roc_abort_sync + +From: Sean Wang + +[ Upstream commit dd08ca3f092f4185ece69ce2a835c23198b1628a ] + +roc_abort_sync() can deadlock with roc_work(). roc_work() holds +dev->mt76.mutex, while cancel_work_sync() waits for roc_work() +to finish. If the caller already owns the same mutex, both +sides block and no progress is possible. + +This deadlock can occur during station removal when +mt76_sta_state() -> mt76_sta_remove() -> +mt7925_mac_sta_remove_link() -> mt7925_mac_link_sta_remove() -> +mt7925_roc_abort_sync() invokes cancel_work_sync() while +roc_work() is still running and holding dev->mt76.mutex. + +This avoids the mutex deadlock and preserves exactly-once +work ownership. + +Fixes: 45064d19fd3a ("wifi: mt76: mt7925: fix a potential association failure upon resuming") +Co-developed-by: Quan Zhou +Signed-off-by: Quan Zhou +Signed-off-by: Sean Wang +Link: https://patch.msgid.link/20251216013849.17976-1-sean.wang@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/main.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 3d622c066ac76..fec54d5f4eaf1 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -457,12 +457,16 @@ void mt7925_roc_abort_sync(struct mt792x_dev *dev) + { + struct mt792x_phy *phy = &dev->phy; + ++ if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) ++ return; ++ + timer_delete_sync(&phy->roc_timer); +- cancel_work_sync(&phy->roc_work); +- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) +- ieee80211_iterate_interfaces(mt76_hw(dev), +- IEEE80211_IFACE_ITER_RESUME_ALL, +- mt7925_roc_iter, (void *)phy); ++ ++ cancel_work(&phy->roc_work); ++ ++ ieee80211_iterate_interfaces(mt76_hw(dev), ++ IEEE80211_IFACE_ITER_RESUME_ALL, ++ mt7925_roc_iter, (void *)phy); + } + EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync); + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7925-fix-tx-power-setting-failure-after-.patch b/queue-7.0/wifi-mt76-mt7925-fix-tx-power-setting-failure-after-.patch new file mode 100644 index 0000000000..7839260757 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7925-fix-tx-power-setting-failure-after-.patch @@ -0,0 +1,54 @@ +From 536e264be924d8f9452cc0ff23c274400da272a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Jan 2026 00:31:52 +0800 +Subject: wifi: mt76: mt7925: fix tx power setting failure after chip reset + +From: Leon Yen + +[ Upstream commit aae89dc4a1608da9060bada757f650ac94b7f184 ] + +After the chip reset, the procedure to set the tx power will not be +successful because the previous region setting is still remains. +Clear the region setting during MAC initialization and allow it to be +reset to finalize the TX power setting. + +Fixes: 3bc62aa4484d ("wifi: mt76: mt7925: add auto regdomain switch support") +Signed-off-by: Leon Yen +Link: https://patch.msgid.link/20260120163152.3694116-1-leon.yen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/init.c | 2 ++ + drivers/net/wireless/mediatek/mt76/mt7925/regd.c | 3 ++- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c +index 3ce5d6fcc69df..c0c5cb9aff75a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c +@@ -91,6 +91,8 @@ int mt7925_mac_init(struct mt792x_dev *dev) + + mt7925_mac_init_basic_rates(dev); + ++ memzero_explicit(&dev->mt76.alpha2, sizeof(dev->mt76.alpha2)); ++ + return 0; + } + EXPORT_SYMBOL_GPL(mt7925_mac_init); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c +index 292087e882d1f..16f56ee879d45 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c +@@ -232,7 +232,8 @@ int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2) + dev->regd_user) + return -EINVAL; + +- if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0') ++ if ((mdev->alpha2[0] && mdev->alpha2[0] != '0') && ++ (mdev->alpha2[1] && mdev->alpha2[1] != '0')) + return 0; + + /* do not need to update the same country twice */ +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch b/queue-7.0/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch new file mode 100644 index 0000000000..36621c241e --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7925-prevent-null-pointer-dereference-in.patch @@ -0,0 +1,45 @@ +From ed2489adb34221310486b115c9da40ed2e772af6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 11:06:48 +0800 +Subject: wifi: mt76: mt7925: prevent NULL pointer dereference in + mt7925_tx_check_aggr() + +From: Ming Yen Hsieh + +[ Upstream commit 83ae3a18ba957257b4c406273d2da2caeea2b439 ] + +Move the NULL check for 'sta' before dereferencing it to prevent a +possible crash. + +Fixes: 44eb173bdd4f ("wifi: mt76: mt7925: add link handling in mt7925_txwi_free") +Signed-off-by: Ming Yen Hsieh +Link: https://patch.msgid.link/20250904030649.655436-4-mingyen.hsieh@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +index ebe872f58c88f..711daa5f07fab 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +@@ -846,11 +846,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, + bool is_8023; + u16 fc, tid; + ++ if (!sta) ++ return; ++ + link_sta = rcu_dereference(sta->link[wcid->link_id]); + if (!link_sta) + return; + +- if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) ++ if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) + return; + + tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch b/queue-7.0/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch new file mode 100644 index 0000000000..3b685b5d8e --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7925-prevent-null-vif-dereference-in-mt7.patch @@ -0,0 +1,41 @@ +From d092ee856299e438ad24169410158a0ef9c5e1dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Sep 2025 11:06:47 +0800 +Subject: wifi: mt76: mt7925: prevent NULL vif dereference in + mt7925_mac_write_txwi + +From: Ming Yen Hsieh + +[ Upstream commit 962eb04e67552be406c906c83099c1d736aae3b6 ] + +Check for a NULL `vif` before accessing `ieee80211_vif_is_mld(vif)` to +avoid a potential kernel panic in scenarios where `vif` might not be +initialized. + +Fixes: ebb1406813c6 ("wifi: mt76: mt7925: add link handling to txwi") +Signed-off-by: Ming Yen Hsieh +Link: https://patch.msgid.link/20250904030649.655436-3-mingyen.hsieh@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +index 711daa5f07fab..82eedd80f694d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +@@ -804,8 +804,8 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, + txwi[5] = cpu_to_le32(val); + + val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); +- if (!ieee80211_vif_is_mld(vif) || +- (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)) ++ if (vif && (!ieee80211_vif_is_mld(vif) || ++ (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))) + val |= MT_TXD6_DIS_MAT; + txwi[6] = cpu_to_le32(val); + txwi[7] = 0; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-add-missing-chanctx_sta_csa-propert.patch b/queue-7.0/wifi-mt76-mt7996-add-missing-chanctx_sta_csa-propert.patch new file mode 100644 index 0000000000..ddbedec10a --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-add-missing-chanctx_sta_csa-propert.patch @@ -0,0 +1,36 @@ +From b575dd319041133f7169bf19348d2b20e766e039 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Sep 2025 18:27:01 +0200 +Subject: wifi: mt76: mt7996: Add missing CHANCTX_STA_CSA property + +From: Lorenzo Bianconi + +[ Upstream commit c0a47ffc4caaf5161955add553322112c3a211b0 ] + +Enable missing CHANCTX_STA_CSA property required for MLO. + +Fixes: f5160304d57c ("wifi: mt76: mt7996: Enable MLO support for client interfaces") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20250928-mt7996_chanctx_sta_csa-v1-1-82e455185990@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index 6a0c199ce3622..ca671dabf00ab 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -536,6 +536,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) + ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); + ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ++ ieee80211_hw_set(hw, CHANCTX_STA_CSA); + + hw->max_tx_fragments = 4; + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-clear-wcid-pointer-in-mt7996_mac_st.patch b/queue-7.0/wifi-mt76-mt7996-clear-wcid-pointer-in-mt7996_mac_st.patch new file mode 100644 index 0000000000..5f3bccf7fd --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-clear-wcid-pointer-in-mt7996_mac_st.patch @@ -0,0 +1,37 @@ +From 13363177425c3ab64df2b48fe228978cc0f7d6e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:24:39 +0100 +Subject: wifi: mt76: mt7996: Clear wcid pointer in + mt7996_mac_sta_deinit_link() + +From: Lorenzo Bianconi + +[ Upstream commit 88973240dc7c976dd320b36a9e6d925c9be083ae ] + +Clear WCID pointer removing the sta link in mt7996_mac_sta_deinit_link +routine. + +Fixes: dd82a9e02c054 ("wifi: mt76: mt7996: Rely on mt7996_sta_link in sta_add/sta_remove callbacks") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251205-mt76-txq-wicd-fix-v2-4-f19ba48af7c1@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index 50ccfe3e10bad..6b98835269353 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -1043,6 +1043,7 @@ void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, + list_del_init(&msta_link->rc_list); + spin_unlock_bh(&dev->mt76.sta_poll_lock); + ++ rcu_assign_pointer(dev->mt76.wcid[msta_link->wcid.idx], NULL); + mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); + mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx); + } +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-decrement-sta-counter-removing-the-.patch b/queue-7.0/wifi-mt76-mt7996-decrement-sta-counter-removing-the-.patch new file mode 100644 index 0000000000..25e82326fc --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-decrement-sta-counter-removing-the-.patch @@ -0,0 +1,47 @@ +From 623c2ec43ed3925fbb0f6109b1f9a546cfefdabd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Mar 2026 14:25:20 +0100 +Subject: wifi: mt76: mt7996: Decrement sta counter removing the link in + mt7996_mac_reset_sta_iter() + +From: Lorenzo Bianconi + +[ Upstream commit e648051d52afbdb360bd586218961f5fffff63e8 ] + +Fixes tracking per-phy stations for offchannel switching. + +Fixes: ace5d3b6b49e8 ("wifi: mt76: mt7996: improve hardware restart reliability") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260308-mt7996_mac_reset_vif_iter-fix-v1-1-57f640aa2dcf@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 5797412962b85..7f0d7c797a531 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2400,6 +2400,7 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) + + for (i = 0; i < ARRAY_SIZE(msta->link); i++) { + struct mt7996_sta_link *msta_link = NULL; ++ struct mt7996_phy *phy; + + msta_link = rcu_replace_pointer(msta->link[i], msta_link, + lockdep_is_held(&dev->mt76.mutex)); +@@ -2407,6 +2408,10 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) + continue; + + mt7996_mac_sta_deinit_link(dev, msta_link); ++ phy = __mt7996_phy(dev, msta_link->wcid.phy_idx); ++ if (phy) ++ phy->mt76->num_sta--; ++ + if (msta_link != &msta->deflink) + kfree_rcu(msta_link, rcu_head); + } +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch b/queue-7.0/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch new file mode 100644 index 0000000000..cfaa1f32e1 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-fcs-error-flag-check-in-rx-desc.patch @@ -0,0 +1,44 @@ +From 9a817aa9ccad456e62521aff82ef48132facd1e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Oct 2025 02:08:24 -0700 +Subject: wifi: mt76: mt7996: fix FCS error flag check in RX descriptor + +From: Alok Tiwari + +[ Upstream commit d8db56142e531f060c938fa0b5175ed6c8cabb11 ] + +The mt7996 driver currently checks the MT_RXD3_NORMAL_FCS_ERR bit in +rxd1 whereas other Connac3-based drivers(mt7925) correctly check this +bit in rxd3. + +Since the MT_RXD3_NORMAL_FCS_ERR bit is defined in the fourth RX +descriptor word (rxd3), update mt7996 to use the proper descriptor +field. This change aligns mt7996 with mt7925 and the rest of the +Connac3 family. + +Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: Alok Tiwari +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251013090826.753992-1-alok.a.tiwari@oracle.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index d6ef2f8003269..ac7f2343076b1 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -527,7 +527,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + +- if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) ++ if (rxd3 & MT_RXD3_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-iface-combination-for-different.patch b/queue-7.0/wifi-mt76-mt7996-fix-iface-combination-for-different.patch new file mode 100644 index 0000000000..384fda4346 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-iface-combination-for-different.patch @@ -0,0 +1,58 @@ +From d3f2daad03a89fac28e99102b880b168b90a1041 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 14:37:28 +0800 +Subject: wifi: mt76: mt7996: fix iface combination for different chipsets + +From: Shayne Chen + +[ Upstream commit 5ef0e8e2653b1ba325eb883ffb94073f19cb669a ] + +MT7992 and MT7990 support up to 19 interfaces per band and 32 in total. + +Fixes: 8df63a4bbe3d ("wifi: mt76: mt7996: adjust interface num and wtbl size for mt7992") +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20251215063728.3013365-7-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/init.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index 00a8286bd1368..20d4c8d5b3e89 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -34,6 +34,20 @@ static const struct ieee80211_iface_combination if_comb_global = { + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), ++ .beacon_int_min_gcd = 100, ++}; ++ ++static const struct ieee80211_iface_combination if_comb_global_7992 = { ++ .limits = &if_limits_global, ++ .n_limits = 1, ++ .max_interfaces = 32, ++ .num_different_channels = MT7996_MAX_RADIOS - 1, ++ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | ++ BIT(NL80211_CHAN_WIDTH_20) | ++ BIT(NL80211_CHAN_WIDTH_40) | ++ BIT(NL80211_CHAN_WIDTH_80) | ++ BIT(NL80211_CHAN_WIDTH_160), ++ .beacon_int_min_gcd = 100, + }; + + static const struct ieee80211_iface_limit if_limits[] = { +@@ -485,7 +499,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) + hw->vif_data_size = sizeof(struct mt7996_vif); + hw->chanctx_data_size = sizeof(struct mt76_chanctx); + +- wiphy->iface_combinations = &if_comb_global; ++ wiphy->iface_combinations = is_mt7996(&dev->mt76) ? &if_comb_global : ++ &if_comb_global_7992; + wiphy->n_iface_combinations = 1; + + wiphy->radio = dev->radios; +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-npu-stop-procedure.patch b/queue-7.0/wifi-mt76-mt7996-fix-npu-stop-procedure.patch new file mode 100644 index 0000000000..200da650e6 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-npu-stop-procedure.patch @@ -0,0 +1,100 @@ +From 0ee751ffd6b8c3580449d8384600c44d3daa08c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 11:39:45 +0100 +Subject: wifi: mt76: mt7996: Fix NPU stop procedure + +From: Lorenzo Bianconi + +[ Upstream commit 7aed20bd9fe427b192cce80a164429584b298bbe ] + +Move mt7996_npu_hw_stop routine before disabling rx NAPIs in order to +fix NPU stop procedure used during device L1 SER recovery. +Add missing usleep_range in mt7996_npu_hw_stop(). + +Fixes: 377aa17d2aedc ("wifi: mt76: mt7996: Add NPU offload support to MT7996 driver") +Tested-by: Kang Yang +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260122-mt76-npu-eagle-offload-v2-1-2374614c0de6@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/mac.c | 3 +-- + .../net/wireless/mediatek/mt76/mt7996/npu.c | 23 +++++++++++-------- + 2 files changed, 15 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index ac7f2343076b1..7fa15b374ed49 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2543,6 +2543,7 @@ void mt7996_mac_reset_work(struct work_struct *work) + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_stop(&dev->mt76.mmio.wed); + ++ mt7996_npu_hw_stop(dev); + ieee80211_stop_queues(mt76_hw(dev)); + + set_bit(MT76_RESET, &dev->mphy.state); +@@ -2569,8 +2570,6 @@ void mt7996_mac_reset_work(struct work_struct *work) + + mutex_lock(&dev->mt76.mutex); + +- mt7996_npu_hw_stop(dev); +- + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); + + if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c +index 29bb735da4cb8..067ef647e4040 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c +@@ -320,33 +320,38 @@ int mt7996_npu_hw_init(struct mt7996_dev *dev) + int mt7996_npu_hw_stop(struct mt7996_dev *dev) + { + struct airoha_npu *npu; +- int i, err; ++ int i, err = 0; + u32 info; + ++ mutex_lock(&dev->mt76.mutex); ++ + npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); + if (!npu) +- return 0; ++ goto unlock; + + err = mt76_npu_send_msg(npu, 4, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, + 0, GFP_KERNEL); + if (err) +- return err; ++ goto unlock; + + for (i = 0; i < 10; i++) { + err = mt76_npu_get_msg(npu, 3, WLAN_FUNC_GET_WAIT_NPU_INFO, + &info, GFP_KERNEL); +- if (err) +- continue; ++ if (!err && !info) ++ break; + +- if (info) { +- err = -ETIMEDOUT; +- continue; +- } ++ err = -ETIMEDOUT; ++ usleep_range(10000, 15000); + } + + if (!err) + err = mt76_npu_send_msg(npu, 6, + WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, + 0, GFP_KERNEL); ++ else ++ dev_err(dev->mt76.dev, "npu stop failed\n"); ++unlock: ++ mutex_unlock(&dev->mt76.mutex); ++ + return err; + } +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-rro-emu-configuration.patch b/queue-7.0/wifi-mt76-mt7996-fix-rro-emu-configuration.patch new file mode 100644 index 0000000000..10ed1e6a07 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-rro-emu-configuration.patch @@ -0,0 +1,54 @@ +From 9ce1381d61c12023eb5bb7eaf798be9f1d086ec9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Mar 2026 17:57:19 +0800 +Subject: wifi: mt76: mt7996: fix RRO EMU configuration + +From: Peter Chiu + +[ Upstream commit 73b46379e5231138025b271ce8e158d2a8aa0768 ] + +Use the correct helper to update specific bitfields instead of +overwriting the entire register. + +Fixes: eedb427eb260 ("wifi: mt76: mt7996: Enable HW RRO for MT7992 chipset") +Signed-off-by: Peter Chiu +Signed-off-by: Shayne Chen +Acked-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260312095724.2117448-1-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +-- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index ca671dabf00ab..fca2d84493b9b 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -858,8 +858,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev) + } + } else { + /* set emul 3.0 function */ +- mt76_wr(dev, MT_RRO_3_0_EMU_CONF, +- MT_RRO_3_0_EMU_CONF_EN_MASK); ++ mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); + + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0, + dev->wed_rro.addr_elem[0].phy_addr); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index bf3fb9b734e85..fc08ef94df637 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2599,7 +2599,7 @@ void mt7996_mac_reset_work(struct work_struct *work) + mt7996_dma_start(dev, false, false); + + if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3) +- mt76_wr(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); ++ mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 | +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch b/queue-7.0/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch new file mode 100644 index 0000000000..228386130c --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-struct-mt7996_mcu_uni_event.patch @@ -0,0 +1,53 @@ +From 3a6245b306e17ebc6b102c1b8ee9654c5e7f5489 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:30 +0800 +Subject: wifi: mt76: mt7996: fix struct mt7996_mcu_uni_event + +From: StanleyYP Wang + +[ Upstream commit efbd5bf395f4e6b45a87f3835d4c2e28170c77c5 ] + +The cid field is defined as a two-byte value in the firmware. + +Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: StanleyYP Wang +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-2-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- + drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 81893ef944aef..20ade7ae7da95 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -233,7 +233,7 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, + event = (struct mt7996_mcu_uni_event *)skb->data; + ret = le32_to_cpu(event->status); + /* skip invalid event */ +- if (mcu_cmd != event->cid) ++ if (mcu_cmd != le16_to_cpu(event->cid)) + ret = -EAGAIN; + } else { + skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +index 647f39b7dab52..f87a8d316f17d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +@@ -25,8 +25,8 @@ struct mt7996_mcu_rxd { + }; + + struct mt7996_mcu_uni_event { +- u8 cid; +- u8 __rsv[3]; ++ __le16 cid; ++ u8 __rsv[2]; + __le32 status; /* 0: success, others: fail */ + } __packed; + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-the-behavior-of-radar-detection.patch b/queue-7.0/wifi-mt76-mt7996-fix-the-behavior-of-radar-detection.patch new file mode 100644 index 0000000000..0b812f8a7f --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-the-behavior-of-radar-detection.patch @@ -0,0 +1,214 @@ +From 7c7924ab995bbdf5b9bcc9ca5d9b01270a91672a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Dec 2025 14:37:23 +0800 +Subject: wifi: mt76: mt7996: fix the behavior of radar detection + +From: StanleyYP Wang + +[ Upstream commit 45a09251d610f3b8a1fb02039146e42f1f4efe90 ] + +RDD_DET_MODE is a firmware command intended for testing and does not +pause TX after radar detection, so remove it from the normal flow; +instead, use the MAC_ENABLE_CTRL firmware command to resume TX after +the radar-triggered channel switch completes. + +Fixes: 1529e335f93d ("wifi: mt76: mt7996: rework radar HWRDD idx") +Co-developed-by: Shayne Chen +Signed-off-by: Shayne Chen +Signed-off-by: StanleyYP Wang +Link: https://patch.msgid.link/20251215063728.3013365-2-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/mac.c | 8 +-- + .../net/wireless/mediatek/mt76/mt7996/main.c | 20 ++++++++ + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 49 ++++++++++++++++--- + .../net/wireless/mediatek/mt76/mt7996/mcu.h | 1 + + .../wireless/mediatek/mt76/mt7996/mt7996.h | 2 + + 5 files changed, 68 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index d4f3ee943b472..2fc4513388ab7 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2974,7 +2974,7 @@ static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy) + + static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) + { +- int err, region; ++ int region; + + switch (dev->mt76.region) { + case NL80211_DFS_ETSI: +@@ -2989,11 +2989,7 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) + break; + } + +- err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); +- if (err < 0) +- return err; +- +- return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1); ++ return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); + } + + static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index f16135f0b7f94..dfac3b9b28fe9 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -79,6 +79,7 @@ static void mt7996_stop_phy(struct mt7996_phy *phy) + + mutex_lock(&dev->mt76.mutex); + ++ mt7996_mcu_rdd_resume_tx(phy); + mt7996_mcu_set_radio_en(phy, false); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); +@@ -933,6 +934,24 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw, + mutex_unlock(&dev->mt76.mutex); + } + ++static int ++mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ struct ieee80211_bss_conf *link_conf) ++{ ++ struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; ++ struct mt7996_dev *dev = mt7996_hw_dev(hw); ++ struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band); ++ int ret; ++ ++ mutex_lock(&dev->mt76.mutex); ++ ++ ret = mt7996_mcu_rdd_resume_tx(phy); ++ ++ mutex_unlock(&dev->mt76.mutex); ++ ++ return ret; ++} ++ + static int + mt7996_mac_sta_init_link(struct mt7996_dev *dev, + struct ieee80211_bss_conf *link_conf, +@@ -2306,6 +2325,7 @@ const struct ieee80211_ops mt7996_ops = { + .release_buffered_frames = mt76_release_buffered_frames, + .get_txpower = mt7996_get_txpower, + .channel_switch_beacon = mt7996_channel_switch_beacon, ++ .post_channel_switch = mt7996_post_channel_switch, + .get_stats = mt7996_get_stats, + .get_et_sset_count = mt7996_get_et_sset_count, + .get_et_stats = mt7996_get_et_stats, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index c0c042de477b8..81893ef944aef 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -416,24 +416,32 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) + break; + case MT_RDD_IDX_BACKGROUND: + if (!dev->rdd2_phy) +- return; ++ goto err; + mphy = dev->rdd2_phy->mt76; + break; + default: +- dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx); +- return; ++ goto err; + } + + if (!mphy) +- return; ++ goto err; + +- if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) ++ if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) { + cfg80211_background_radar_event(mphy->hw->wiphy, + &dev->rdd2_chandef, + GFP_ATOMIC); +- else ++ } else { ++ struct mt7996_phy *phy = mphy->priv; ++ ++ phy->rdd_tx_paused = true; + ieee80211_radar_detected(mphy->hw, NULL); ++ } + dev->hw_pattern++; ++ ++ return; ++ ++err: ++ dev_err(dev->mt76.dev, "Invalid RDD idx %d\n", r->rdd_idx); + } + + static void +@@ -4557,6 +4565,35 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable) + &req, sizeof(req), true); + } + ++int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy) ++{ ++ struct { ++ u8 band_idx; ++ u8 _rsv[3]; ++ ++ __le16 tag; ++ __le16 len; ++ u8 mac_enable; ++ u8 _rsv2[3]; ++ } __packed req = { ++ .band_idx = phy->mt76->band_idx, ++ .tag = cpu_to_le16(UNI_BAND_CONFIG_MAC_ENABLE_CTRL), ++ .len = cpu_to_le16(sizeof(req) - 4), ++ .mac_enable = 2, ++ }; ++ int ret; ++ ++ if (!phy->rdd_tx_paused) ++ return 0; ++ ++ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG), ++ &req, sizeof(req), true); ++ if (!ret) ++ phy->rdd_tx_paused = false; ++ ++ return ret; ++} ++ + int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val) + { + struct { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +index e0b83ac9f5e2a..647f39b7dab52 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +@@ -837,6 +837,7 @@ enum { + enum { + UNI_BAND_CONFIG_RADIO_ENABLE, + UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, ++ UNI_BAND_CONFIG_MAC_ENABLE_CTRL = 0x0c, + }; + + enum { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +index 7a884311800ea..d31864f973cce 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +@@ -377,6 +377,7 @@ struct mt7996_phy { + + bool has_aux_rx; + bool counter_reset; ++ bool rdd_tx_paused; + }; + + struct mt7996_dev { +@@ -726,6 +727,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy); + int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); + int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); + int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); ++int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy); + int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val); + int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, + struct cfg80211_chan_def *chandef); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch b/queue-7.0/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch new file mode 100644 index 0000000000..b6ab282595 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-use-after-free-bugs-in-mt7996_m.patch @@ -0,0 +1,53 @@ +From 95c78eac6f080f821b02c0922e3d6e5bad3b354b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jan 2026 10:47:31 +0800 +Subject: wifi: mt76: mt7996: fix use-after-free bugs in mt7996_mac_dump_work() + +From: Duoming Zhou + +[ Upstream commit c8f62f73bbced3a79894655bdb0b625462d956fc ] + +When the mt7996 pci chip is detaching, the mt7996_crash_data is +released in mt7996_coredump_unregister(). However, the work item +dump_work may still be running or pending, leading to UAF bugs +when the already freed crash_data is dereferenced again in +mt7996_mac_dump_work(). + +The race condition can occur as follows: + +CPU 0 (removal path) | CPU 1 (workqueue) +mt7996_pci_remove() | mt7996_sys_recovery_set() + mt7996_unregister_device() | mt7996_reset() + mt7996_coredump_unregister() | queue_work() + vfree(dev->coredump.crash_data) | mt7996_mac_dump_work() + | crash_data-> // UAF + +Fix this by ensuring dump_work is properly canceled before +the crash_data is deallocated. Add cancel_work_sync() in +mt7996_unregister_device() to synchronize with any pending +or executing dump work. + +Fixes: 878161d5d4a4 ("wifi: mt76: mt7996: enable coredump support") +Signed-off-by: Duoming Zhou +Link: https://patch.msgid.link/20260131024731.18741-1-duoming@zju.edu.cn +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index 20d4c8d5b3e89..6a0c199ce3622 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -1741,6 +1741,7 @@ int mt7996_register_device(struct mt7996_dev *dev) + + void mt7996_unregister_device(struct mt7996_dev *dev) + { ++ cancel_work_sync(&dev->dump_work); + cancel_work_sync(&dev->wed_rro.work); + mt7996_unregister_phy(mt7996_phy3(dev)); + mt7996_unregister_phy(mt7996_phy2(dev)); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-fix-wrong-dmad-length-when-using-ma.patch b/queue-7.0/wifi-mt76-mt7996-fix-wrong-dmad-length-when-using-ma.patch new file mode 100644 index 0000000000..963ae3d32a --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-fix-wrong-dmad-length-when-using-ma.patch @@ -0,0 +1,50 @@ +From 465d7a032752b7087e9ded8d75fa4342635e467a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Feb 2026 23:55:29 +0800 +Subject: wifi: mt76: mt7996: fix wrong DMAD length when using MAC TXP + +From: Shayne Chen + +[ Upstream commit 97b9f9831bf297f3ffa62018721601ed2736f2c3 ] + +The struct mt76_connac_fw_txp is used for HIF TXP. Change to use the +struct mt76_connac_hw_txp to fix the wrong DMAD length for MAC TXP. + +Fixes: cb6ebbdffef2 ("wifi: mt76: mt7996: support writing MAC TXD for AddBA Request") +Signed-off-by: Shayne Chen +Link: https://patch.msgid.link/20260203155532.1098290-1-shayne.chen@mediatek.com +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 7fa15b374ed49..5797412962b85 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -1139,10 +1139,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + * req + */ + if (le32_to_cpu(ptr[7]) & MT_TXD7_MAC_TXD) { +- u32 val; ++ u32 val, mac_txp_size = sizeof(struct mt76_connac_hw_txp); + + ptr = (__le32 *)(txwi + MT_TXD_SIZE); +- memset((void *)ptr, 0, sizeof(struct mt76_connac_fw_txp)); ++ memset((void *)ptr, 0, mac_txp_size); + + val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) | + MT_TXP0_TOKEN_ID0_VALID_MASK; +@@ -1161,6 +1161,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + tx_info->buf[1].addr >> 32); + #endif + ptr[3] = cpu_to_le32(val); ++ ++ tx_info->buf[0].len = MT_TXD_SIZE + mac_txp_size; + } else { + struct mt76_connac_txp_common *txp; + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-remove-link-pointer-dependency-in-m.patch b/queue-7.0/wifi-mt76-mt7996-remove-link-pointer-dependency-in-m.patch new file mode 100644 index 0000000000..63fe2fbf6f --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-remove-link-pointer-dependency-in-m.patch @@ -0,0 +1,62 @@ +From 346001125abef64c8607555d953c4f3ce62b8c73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Mar 2026 11:27:52 +0100 +Subject: wifi: mt76: mt7996: Remove link pointer dependency in + mt7996_mac_sta_remove_links() + +From: Lorenzo Bianconi + +[ Upstream commit 569ce4340268915911fc356ec9ad27e92fb82289 ] + +Remove link pointer dependency in mt7996_mac_sta_remove_links routine to +get the mt7996_phy pointer since the link can be already offchannel +running mt7996_mac_sta_remove_links(). Rely on __mt7996_phy routine +instead. + +Fixes: 344dd6a4c919 ("wifi: mt76: mt7996: Move num_sta accounting in mt7996_mac_sta_{add,remove}_links") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260306-mt7996-deflink-lookup-link-remove-v1-1-7162b332873c@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 14 ++++---------- + 1 file changed, 4 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index 6b98835269353..ff3050c2344ab 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -1058,8 +1058,7 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_sta_link *msta_link = NULL; +- struct mt7996_vif_link *link; +- struct mt76_phy *mphy; ++ struct mt7996_phy *phy; + + msta_link = rcu_replace_pointer(msta->link[link_id], msta_link, + lockdep_is_held(&mdev->mutex)); +@@ -1068,17 +1067,12 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + + mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); +- + mt7996_mac_sta_deinit_link(dev, msta_link); +- link = mt7996_vif_link(dev, vif, link_id); +- if (!link) +- continue; + +- mphy = mt76_vif_link_phy(&link->mt76); +- if (!mphy) +- continue; ++ phy = __mt7996_phy(dev, msta_link->wcid.phy_idx); ++ if (phy) ++ phy->mt76->num_sta--; + +- mphy->num_sta--; + if (msta->deflink_id == link_id) { + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + if (msta->seclink_id == link_id) { +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-reset-ampdu_state-state-in-case-of-.patch b/queue-7.0/wifi-mt76-mt7996-reset-ampdu_state-state-in-case-of-.patch new file mode 100644 index 0000000000..49b7b5d82b --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-reset-ampdu_state-state-in-case-of-.patch @@ -0,0 +1,41 @@ +From a0a51e177c18ae9562c543bb46782bb9c918e079 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Dec 2025 10:55:30 +0100 +Subject: wifi: mt76: mt7996: Reset ampdu_state state in case of failure in + mt7996_tx_check_aggr() + +From: Lorenzo Bianconi + +[ Upstream commit c0747db7c10c2dfbdcff0e8e97021e3df1f1e362 ] + +Reset the ampdu_state configured state if ieee80211_start_tx_ba_session +routine fails in mt7996_tx_check_aggr() + +Fixes: 98686cd21624c ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251214-mt7996-aggr-check-fix-v1-1-33a8b62ec0fc@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 5e0c85066803d..d6ef2f8003269 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -1270,8 +1270,9 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta, + if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) + return; + +- if (!test_and_set_bit(tid, &wcid->ampdu_state)) +- ieee80211_start_tx_ba_session(link_sta->sta, tid, 0); ++ if (!test_and_set_bit(tid, &wcid->ampdu_state) && ++ ieee80211_start_tx_ba_session(link_sta->sta, tid, 0)) ++ clear_bit(tid, &wcid->ampdu_state); + } + + static void +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-reset-mtxq-idx-if-primary-link-is-r.patch b/queue-7.0/wifi-mt76-mt7996-reset-mtxq-idx-if-primary-link-is-r.patch new file mode 100644 index 0000000000..fda6328aae --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-reset-mtxq-idx-if-primary-link-is-r.patch @@ -0,0 +1,63 @@ +From 091a977264aad1e6950bf5a580a7bbbab451cf21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:24:37 +0100 +Subject: wifi: mt76: mt7996: Reset mtxq->idx if primary link is removed in + mt7996_vif_link_remove() + +From: Lorenzo Bianconi + +[ Upstream commit 751a2679b15e3a0fa8fc9175862f0ec40643db68 ] + +Reset WCID index in mt76_txq struct if primary link is removed in +mt7996_vif_link_remove routine. + +Fixes: a3316d2fc669f ("wifi: mt76: mt7996: set vif default link_id adding/removing vif links") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251205-mt76-txq-wicd-fix-v2-2-f19ba48af7c1@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/main.c | 21 ++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index d75f48c61ce0f..c6204a8673ee7 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -402,17 +402,28 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, + + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + +- if (!mlink->wcid->offchannel && ++ if (vif->txq && !mlink->wcid->offchannel && + mvif->mt76.deflink_id == link_conf->link_id) { + struct ieee80211_bss_conf *iter; ++ struct mt76_txq *mtxq; + unsigned int link_id; + + mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED; ++ mtxq = (struct mt76_txq *)vif->txq->drv_priv; ++ /* Primary link will be removed, look for a new one */ + for_each_vif_active_link(vif, iter, link_id) { +- if (link_id != IEEE80211_LINK_UNSPECIFIED) { +- mvif->mt76.deflink_id = link_id; +- break; +- } ++ struct mt7996_vif_link *link; ++ ++ if (link_id == link_conf->link_id) ++ continue; ++ ++ link = mt7996_vif_link(dev, vif, link_id); ++ if (!link) ++ continue; ++ ++ mtxq->wcid = link->msta_link.wcid.idx; ++ mvif->mt76.deflink_id = link_id; ++ break; + } + } + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-set-mtxq-wcid-just-for-primary-link.patch b/queue-7.0/wifi-mt76-mt7996-set-mtxq-wcid-just-for-primary-link.patch new file mode 100644 index 0000000000..dfba0a7953 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-set-mtxq-wcid-just-for-primary-link.patch @@ -0,0 +1,64 @@ +From 5749476ee41069e59a10eaa6b4b9699bcb7432af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:24:36 +0100 +Subject: wifi: mt76: mt7996: Set mtxq->wcid just for primary link + +From: Lorenzo Bianconi + +[ Upstream commit 654abcbe4528f74428b69292fad5c4224414fa1b ] + +Set WCID index in mt76_txq struct just for the primary link in +mt7996_vif_link_add routine. + +Fixes: 69d54ce7491d0 ("wifi: mt76: mt7996: switch to single multi-radio wiphy") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251205-mt76-txq-wicd-fix-v2-1-f19ba48af7c1@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index dfac3b9b28fe9..d75f48c61ce0f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -301,7 +301,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + .cmd = SET_KEY, + .link_id = link_conf->link_id, + }; +- struct mt76_txq *mtxq; + int mld_idx, idx, ret; + + mlink->idx = __ffs64(~dev->mt76.vif_mask); +@@ -344,11 +343,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + mt7996_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + +- if (vif->txq) { +- mtxq = (struct mt76_txq *)vif->txq->drv_priv; +- mtxq->wcid = idx; +- } +- + if (vif->type != NL80211_IFTYPE_AP && + (!mlink->omac_idx || mlink->omac_idx > 3)) + vif->offload_flags = 0; +@@ -371,9 +365,13 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + + ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); + +- if (!mlink->wcid->offchannel && +- mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) ++ if (vif->txq && !mlink->wcid->offchannel && ++ mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) { ++ struct mt76_txq *mtxq = (struct mt76_txq *)vif->txq->drv_priv; ++ + mvif->mt76.deflink_id = link_conf->link_id; ++ mtxq->wcid = idx; ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-mt7996-switch-to-the-secondary-link-if-the.patch b/queue-7.0/wifi-mt76-mt7996-switch-to-the-secondary-link-if-the.patch new file mode 100644 index 0000000000..ec2ecd63d2 --- /dev/null +++ b/queue-7.0/wifi-mt76-mt7996-switch-to-the-secondary-link-if-the.patch @@ -0,0 +1,133 @@ +From 77dc27fb9f84d25ae470fbad9bf9924af1ec7901 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Dec 2025 11:24:38 +0100 +Subject: wifi: mt76: mt7996: Switch to the secondary link if the default one + is removed + +From: Lorenzo Bianconi + +[ Upstream commit 5ef44c200618430b004233cbfc1b0929a13d5ac8 ] + +Switch to the secondary link if available in mt7996_mac_sta_remove_links +routine if the primary one is removed. +Moreover reset secondary link index for single link scenario. + +Fixes: 85cd5534a3f2e ("wifi: mt76: mt7996: use correct link_id when filling TXD and TXP") +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251205-mt76-txq-wicd-fix-v2-3-f19ba48af7c1@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7996/mac.c | 12 ++--- + .../net/wireless/mediatek/mt76/mt7996/main.c | 51 +++++++++++++------ + 2 files changed, 41 insertions(+), 22 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 2fc4513388ab7..5e0c85066803d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -2404,14 +2404,12 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) + continue; + + mt7996_mac_sta_deinit_link(dev, msta_link); +- +- if (msta->deflink_id == i) { +- msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; +- continue; +- } +- +- kfree_rcu(msta_link, rcu_head); ++ if (msta_link != &msta->deflink) ++ kfree_rcu(msta_link, rcu_head); + } ++ ++ msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; ++ msta->seclink_id = msta->deflink_id; + } + + static void +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +index c6204a8673ee7..50ccfe3e10bad 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c +@@ -961,6 +961,22 @@ mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + return ret; + } + ++static void ++mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { ++ struct mt76_txq *mtxq; ++ ++ if (!sta->txq[i]) ++ continue; ++ ++ mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; ++ mtxq->wcid = idx; ++ } ++} ++ + static int + mt7996_mac_sta_init_link(struct mt7996_dev *dev, + struct ieee80211_bss_conf *link_conf, +@@ -978,21 +994,10 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, + return -ENOSPC; + + if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { +- int i; +- + msta_link = &msta->deflink; + msta->deflink_id = link_id; + msta->seclink_id = msta->deflink_id; +- +- for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { +- struct mt76_txq *mtxq; +- +- if (!sta->txq[i]) +- continue; +- +- mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; +- mtxq->wcid = idx; +- } ++ mt7996_sta_init_txq_wcid(sta, idx); + } else { + msta_link = kzalloc_obj(*msta_link); + if (!msta_link) +@@ -1075,12 +1080,28 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + mphy->num_sta--; + if (msta->deflink_id == link_id) { + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; +- continue; ++ if (msta->seclink_id == link_id) { ++ /* no secondary link available */ ++ msta->seclink_id = msta->deflink_id; ++ } else { ++ struct mt7996_sta_link *msta_seclink; ++ ++ /* switch to the secondary link */ ++ msta_seclink = mt76_dereference( ++ msta->link[msta->seclink_id], ++ mdev); ++ if (msta_seclink) { ++ msta->deflink_id = msta->seclink_id; ++ mt7996_sta_init_txq_wcid(sta, ++ msta_seclink->wcid.idx); ++ } ++ } + } else if (msta->seclink_id == link_id) { +- msta->seclink_id = IEEE80211_LINK_UNSPECIFIED; ++ msta->seclink_id = msta->deflink_id; + } + +- kfree_rcu(msta_link, rcu_head); ++ if (msta_link != &msta->deflink) ++ kfree_rcu(msta_link, rcu_head); + } + } + +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-npu-add-missing-rx_token_size-initializati.patch b/queue-7.0/wifi-mt76-npu-add-missing-rx_token_size-initializati.patch new file mode 100644 index 0000000000..bc5b822645 --- /dev/null +++ b/queue-7.0/wifi-mt76-npu-add-missing-rx_token_size-initializati.patch @@ -0,0 +1,36 @@ +From 8f544fe04953ff5ab2556cdd38e9db457c0b23a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Jan 2026 11:39:46 +0100 +Subject: wifi: mt76: npu: Add missing rx_token_size initialization + +From: Lorenzo Bianconi + +[ Upstream commit 25e3203a2192f2b0d697b2410126bad87e62d4f0 ] + +Add missing rx_token_size initialization for NPU offloading. + +Fixes: 7fb554b1b623 ("wifi: mt76: Introduce the NPU generic layer") +Tested-by: Kang Yang +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260122-mt76-npu-eagle-offload-v2-2-2374614c0de6@kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/npu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/mediatek/mt76/npu.c b/drivers/net/wireless/mediatek/mt76/npu.c +index ec36975f6dc94..9679237f73984 100644 +--- a/drivers/net/wireless/mediatek/mt76/npu.c ++++ b/drivers/net/wireless/mediatek/mt76/npu.c +@@ -457,6 +457,7 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type) + dev->mmio.npu_type = type; + /* NPU offloading requires HW-RRO for RX packet reordering. */ + dev->hwrro_mode = MT76_HWRRO_V3_1; ++ dev->rx_token_size = 32768; + + rcu_assign_pointer(dev->mmio.npu, npu); + rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mt76-support-upgrading-passive-scans-to-active.patch b/queue-7.0/wifi-mt76-support-upgrading-passive-scans-to-active.patch new file mode 100644 index 0000000000..0d298b0d68 --- /dev/null +++ b/queue-7.0/wifi-mt76-support-upgrading-passive-scans-to-active.patch @@ -0,0 +1,172 @@ +From 84ed4b459a122b73ebc882c6d73b30f330acbbf0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Mar 2026 06:07:21 +0000 +Subject: wifi: mt76: support upgrading passive scans to active + +From: Chad Monroe + +[ Upstream commit 360552c8592dab3c69e0bbff786b55137f1a81bb ] + +On channels with NO_IR or RADAR flags, wait for beacon before sending +probe requests. Allows active scanning and WPS on restricted channels +if another AP is already present. + +Fixes: c56d6edebc1f ("wifi: mt76: mt7996: use emulated hardware scan support") +Tested-by: Piotr Kubik +Signed-off-by: Chad Monroe +Link: https://patch.msgid.link/20251118102723.47997-2-nbd@nbd.name +Link: https://patch.msgid.link/20260309060730.87840-2-nbd@nbd.name +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + + drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++ + .../net/wireless/mediatek/mt76/mt7996/mac.c | 3 ++ + drivers/net/wireless/mediatek/mt76/scan.c | 51 +++++++++++++++++-- + 4 files changed, 56 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c +index 75772979f438e..4d041f88155c2 100644 +--- a/drivers/net/wireless/mediatek/mt76/mac80211.c ++++ b/drivers/net/wireless/mediatek/mt76/mac80211.c +@@ -726,6 +726,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size, + INIT_LIST_HEAD(&dev->rxwi_cache); + dev->token_size = dev->drv->token_size; + INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work); ++ spin_lock_init(&dev->scan_lock); + + for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) + skb_queue_head_init(&dev->rx_skb[i]); +diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h +index 32876eab23a84..df93ab79c5b48 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -1001,6 +1001,7 @@ struct mt76_dev { + u32 rxfilter; + + struct delayed_work scan_work; ++ spinlock_t scan_lock; + struct { + struct cfg80211_scan_request *req; + struct ieee80211_channel *chan; +@@ -1008,6 +1009,8 @@ struct mt76_dev { + struct mt76_vif_link *mlink; + struct mt76_phy *phy; + int chan_idx; ++ bool beacon_wait; ++ bool beacon_received; + } scan; + + #ifdef CONFIG_NL80211_TESTMODE +@@ -1595,6 +1598,7 @@ int mt76_get_rate(struct mt76_dev *dev, + int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req); + void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); ++void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan); + void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac); + void mt76_sw_scan_complete(struct ieee80211_hw *hw, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 7f0d7c797a531..bf3fb9b734e85 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -554,6 +554,9 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2); + seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2); + ++ if (ieee80211_is_beacon(fc)) ++ mt76_scan_rx_beacon(&dev->mt76, mphy->chandef.chan); ++ + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; +diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c +index fec79a5cd03bf..ab153b4df0479 100644 +--- a/drivers/net/wireless/mediatek/mt76/scan.c ++++ b/drivers/net/wireless/mediatek/mt76/scan.c +@@ -27,6 +27,10 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) + + void mt76_abort_scan(struct mt76_dev *dev) + { ++ spin_lock_bh(&dev->scan_lock); ++ dev->scan.beacon_wait = false; ++ spin_unlock_bh(&dev->scan_lock); ++ + cancel_delayed_work_sync(&dev->scan_work); + mt76_scan_complete(dev, true); + } +@@ -77,6 +81,28 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) + rcu_read_unlock(); + } + ++void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan) ++{ ++ struct mt76_phy *phy; ++ ++ spin_lock(&dev->scan_lock); ++ ++ if (!dev->scan.beacon_wait || dev->scan.beacon_received || ++ dev->scan.chan != chan) ++ goto out; ++ ++ phy = dev->scan.phy; ++ if (!phy) ++ goto out; ++ ++ dev->scan.beacon_received = true; ++ ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0); ++ ++out: ++ spin_unlock(&dev->scan_lock); ++} ++EXPORT_SYMBOL_GPL(mt76_scan_rx_beacon); ++ + void mt76_scan_work(struct work_struct *work) + { + struct mt76_dev *dev = container_of(work, struct mt76_dev, +@@ -85,9 +111,20 @@ void mt76_scan_work(struct work_struct *work) + struct cfg80211_chan_def chandef = {}; + struct mt76_phy *phy = dev->scan.phy; + int duration = HZ / 9; /* ~110 ms */ +- bool offchannel = true; ++ bool beacon_rx, offchannel = true; + int i; + ++ if (!phy || !req) ++ return; ++ ++ spin_lock_bh(&dev->scan_lock); ++ beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received; ++ dev->scan.beacon_wait = false; ++ spin_unlock_bh(&dev->scan_lock); ++ ++ if (beacon_rx) ++ goto probe; ++ + if (dev->scan.chan_idx >= req->n_channels) { + mt76_scan_complete(dev, false); + return; +@@ -108,10 +145,18 @@ void mt76_scan_work(struct work_struct *work) + + mt76_set_channel(phy, &chandef, offchannel); + +- if (!req->n_ssids || +- chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) ++ if (!req->n_ssids) + goto out; + ++ if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) { ++ spin_lock_bh(&dev->scan_lock); ++ dev->scan.beacon_received = false; ++ dev->scan.beacon_wait = true; ++ spin_unlock_bh(&dev->scan_lock); ++ goto out; ++ } ++ ++probe: + if (phy->offchannel) + duration = HZ / 16; /* ~60 ms */ + local_bh_disable(); +-- +2.53.0 + diff --git a/queue-7.0/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch b/queue-7.0/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch new file mode 100644 index 0000000000..52d3caf3fc --- /dev/null +++ b/queue-7.0/wifi-mwifiex-fix-memory-leak-in-mwifiex_11n_aggregat.patch @@ -0,0 +1,49 @@ +From 1d355a704d806cf4da8e253f21851707831c4a31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 09:26:25 +0000 +Subject: wifi: mwifiex: Fix memory leak in mwifiex_11n_aggregate_pkt() + +From: Zilin Guan + +[ Upstream commit 990a73dec3fdc145fef6c827c29205437d533ece ] + +In mwifiex_11n_aggregate_pkt(), skb_aggr is allocated via +mwifiex_alloc_dma_align_buf(). If mwifiex_is_ralist_valid() returns false, +the function currently returns -1 immediately without freeing the +previously allocated skb_aggr, causing a memory leak. + +Since skb_aggr has not yet been queued via skb_queue_tail(), no other +references to this memory exist. Therefore, it has to be freed locally +before returning the error. + +Fix this by calling mwifiex_write_data_complete() to free skb_aggr before +returning the error status. + +Compile tested only. Issue found using a prototype static analysis tool +and code review. + +Fixes: 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver") +Signed-off-by: Zilin Guan +Reviewed-by: Jeff Chen +Link: https://patch.msgid.link/20260119092625.1349934-1-zilin@seu.edu.cn +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/marvell/mwifiex/11n_aggr.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +index 34b4b34276d6d..042b1fe5f0d67 100644 +--- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c ++++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +@@ -203,6 +203,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, + + if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) { + spin_unlock_bh(&priv->wmm.ra_list_spinlock); ++ mwifiex_write_data_complete(adapter, skb_aggr, 1, -1); + return -1; + } + +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch b/queue-7.0/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch new file mode 100644 index 0000000000..9cbee02976 --- /dev/null +++ b/queue-7.0/wifi-rtlwifi-pci-fix-possible-use-after-free-caused-.patch @@ -0,0 +1,49 @@ +From 9985b791221a80338557c40435d7ebabbc4829ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Feb 2026 12:55:22 +0800 +Subject: wifi: rtlwifi: pci: fix possible use-after-free caused by unfinished + irq_prepare_bcn_tasklet + +From: Duoming Zhou + +[ Upstream commit 039cd522dc70151da13329a5e3ae19b1736f468a ] + +The irq_prepare_bcn_tasklet is initialized in rtl_pci_init() and +scheduled when RTL_IMR_BCNINT interrupt is triggered by hardware. +But it is never killed in rtl_pci_deinit(). When the rtlwifi card +probe fails or is being detached, the ieee80211_hw is deallocated. +However, irq_prepare_bcn_tasklet may still be running or pending, +leading to use-after-free when the freed ieee80211_hw is accessed +in _rtl_pci_prepare_bcn_tasklet(). + +Similar to irq_tasklet, add tasklet_kill() in rtl_pci_deinit() to +ensure that irq_prepare_bcn_tasklet is properly terminated before +the ieee80211_hw is released. + +The issue was identified through static analysis. + +Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") +Signed-off-by: Duoming Zhou +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260223045522.48377-1-duoming@zju.edu.cn +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtlwifi/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c +index d080469264cf8..f0010336e78c1 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -1674,6 +1674,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) + + synchronize_irq(rtlpci->pdev->irq); + tasklet_kill(&rtlpriv->works.irq_tasklet); ++ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet); + cancel_work_sync(&rtlpriv->works.lps_change_work); + } + +-- +2.53.0 + diff --git a/queue-7.0/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch b/queue-7.0/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch new file mode 100644 index 0000000000..8b4ae80e1e --- /dev/null +++ b/queue-7.0/wifi-rtw89-phy-fix-uninitialized-variable-access-in-.patch @@ -0,0 +1,48 @@ +From 7856f2f0905413b5382a231d85bdedf0f8e19735 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Mar 2026 17:05:53 +0300 +Subject: wifi: rtw89: phy: fix uninitialized variable access in + rtw89_phy_cfo_set_crystal_cap() + +From: Alexey Velichayshiy + +[ Upstream commit 047cddf88c611e616d49a00311d4722e46286234 ] + +In the rtw89_phy_cfo_set_crystal_cap() function, for chips other than +RTL8852A/RTL8851B, the values read by rtw89_mac_read_xtal_si() are +stored into the local variables sc_xi_val and sc_xo_val. If either +read fails, these variables remain uninitialized, they are later +used to update cfo->crystal_cap and in debug print statements. This +can lead to undefined behavior. + +Fix the issue by initializing sc_xi_val and sc_xo_val to zero, +like is implemented in vendor driver. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: 8379fa611536 ("rtw89: 8852c: add write/read crystal function in CFO tracking") +Signed-off-by: Alexey Velichayshiy +Acked-by: Ping-Ke Shih +Signed-off-by: Ping-Ke Shih +Link: https://patch.msgid.link/20260323140613.1615574-1-a.velichayshiy@ispras.ru +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/realtek/rtw89/phy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c +index ee6ab2136b9a7..ee8a36003e5da 100644 +--- a/drivers/net/wireless/realtek/rtw89/phy.c ++++ b/drivers/net/wireless/realtek/rtw89/phy.c +@@ -4860,7 +4860,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, + { + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + const struct rtw89_chip_info *chip = rtwdev->chip; +- u8 sc_xi_val, sc_xo_val; ++ u8 sc_xi_val = 0, sc_xo_val = 0; + + if (!force && cfo->crystal_cap == crystal_cap) + return; +-- +2.53.0 + diff --git a/queue-7.0/workqueue-devres-add-device-managed-allocate-workque.patch b/queue-7.0/workqueue-devres-add-device-managed-allocate-workque.patch new file mode 100644 index 0000000000..7ec7e17fc8 --- /dev/null +++ b/queue-7.0/workqueue-devres-add-device-managed-allocate-workque.patch @@ -0,0 +1,146 @@ +From a116b3277f0603701a9b6738691d8247fe2bcecc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Mar 2026 22:45:40 +0100 +Subject: workqueue: devres: Add device-managed allocate workqueue + +From: Krzysztof Kozlowski + +[ Upstream commit 1dfc9d60a69ec148e1cb709256617d86e5f0e8f8 ] + +Add a Resource-managed version of alloc_workqueue() to fix common +problem of drivers mixing devm() calls with destroy_workqueue. Such +naive and discouraged driver approach leads to difficult to debug bugs +when the driver: + +1. Allocates workqueue in standard way and destroys it in driver + remove() callback, +2. Sets work struct with devm_work_autocancel(), +3. Registers interrupt handler with devm_request_threaded_irq(). + +Which leads to following unbind/removal path: + +1. destroy_workqueue() via driver remove(), + Any interrupt coming now would still execute the interrupt handler, + which queues work on destroyed workqueue. +2. devm_irq_release(), +3. devm_work_drop() -> cancel_work_sync() on destroyed workqueue. + +devm_alloc_workqueue() has two benefits: +1. Solves above problem of mix-and-match devres and non-devres code in + driver, +2. Simplify any sane drivers which were correctly using + alloc_workqueue() + devm_add_action_or_reset(). + +Signed-off-by: Krzysztof Kozlowski +Acked-by: Tejun Heo +Reviewed-by: Andy Shevchenko +Signed-off-by: Tejun Heo +Stable-dep-of: 1e668baadefb ("power: supply: max77705: Free allocated workqueue and fix removal order") +Signed-off-by: Sasha Levin +--- + .../driver-api/driver-model/devres.rst | 4 +++ + include/linux/workqueue.h | 22 +++++++++++++++ + kernel/workqueue.c | 28 +++++++++++++++++++ + 3 files changed, 54 insertions(+) + +diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst +index 7d2b897d66fa9..017fb155a5bc2 100644 +--- a/Documentation/driver-api/driver-model/devres.rst ++++ b/Documentation/driver-api/driver-model/devres.rst +@@ -464,3 +464,7 @@ SPI + + WATCHDOG + devm_watchdog_register_device() ++ ++WORKQUEUE ++ devm_alloc_workqueue() ++ devm_alloc_ordered_workqueue() +diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h +index a4749f56398fd..f8d235aef10dd 100644 +--- a/include/linux/workqueue.h ++++ b/include/linux/workqueue.h +@@ -512,6 +512,26 @@ __printf(1, 4) struct workqueue_struct * + alloc_workqueue_noprof(const char *fmt, unsigned int flags, int max_active, ...); + #define alloc_workqueue(...) alloc_hooks(alloc_workqueue_noprof(__VA_ARGS__)) + ++/** ++ * devm_alloc_workqueue - Resource-managed allocate a workqueue ++ * @dev: Device to allocate workqueue for ++ * @fmt: printf format for the name of the workqueue ++ * @flags: WQ_* flags ++ * @max_active: max in-flight work items, 0 for default ++ * @...: args for @fmt ++ * ++ * Resource managed workqueue, see alloc_workqueue() for details. ++ * ++ * The workqueue will be automatically destroyed on driver detach. Typically ++ * this should be used in drivers already relying on devm interafaces. ++ * ++ * RETURNS: ++ * Pointer to the allocated workqueue on success, %NULL on failure. ++ */ ++__printf(2, 5) struct workqueue_struct * ++devm_alloc_workqueue(struct device *dev, const char *fmt, unsigned int flags, ++ int max_active, ...); ++ + #ifdef CONFIG_LOCKDEP + /** + * alloc_workqueue_lockdep_map - allocate a workqueue with user-defined lockdep_map +@@ -568,6 +588,8 @@ alloc_workqueue_lockdep_map(const char *fmt, unsigned int flags, int max_active, + */ + #define alloc_ordered_workqueue(fmt, flags, args...) \ + alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args) ++#define devm_alloc_ordered_workqueue(dev, fmt, flags, args...) \ ++ devm_alloc_workqueue(dev, fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args) + + #define create_workqueue(name) \ + alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_PERCPU, 1, (name)) +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index c6ea96d5b7167..e57040931d8b7 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -5904,6 +5905,33 @@ struct workqueue_struct *alloc_workqueue_noprof(const char *fmt, + } + EXPORT_SYMBOL_GPL(alloc_workqueue_noprof); + ++static void devm_workqueue_release(void *res) ++{ ++ destroy_workqueue(res); ++} ++ ++__printf(2, 5) struct workqueue_struct * ++devm_alloc_workqueue(struct device *dev, const char *fmt, unsigned int flags, ++ int max_active, ...) ++{ ++ struct workqueue_struct *wq; ++ va_list args; ++ int ret; ++ ++ va_start(args, max_active); ++ wq = alloc_workqueue(fmt, flags, max_active, args); ++ va_end(args); ++ if (!wq) ++ return NULL; ++ ++ ret = devm_add_action_or_reset(dev, devm_workqueue_release, wq); ++ if (ret) ++ return NULL; ++ ++ return wq; ++} ++EXPORT_SYMBOL_GPL(devm_alloc_workqueue); ++ + #ifdef CONFIG_LOCKDEP + __printf(1, 5) + struct workqueue_struct * +-- +2.53.0 + diff --git a/queue-7.0/ww-mutex-fix-the-ww_acquire_ctx-function-annotations.patch b/queue-7.0/ww-mutex-fix-the-ww_acquire_ctx-function-annotations.patch new file mode 100644 index 0000000000..db59d327c2 --- /dev/null +++ b/queue-7.0/ww-mutex-fix-the-ww_acquire_ctx-function-annotations.patch @@ -0,0 +1,48 @@ +From 7f65c053b0ad12c48741ef4f644a5dade44a3632 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Feb 2026 10:32:43 -0800 +Subject: ww-mutex: Fix the ww_acquire_ctx function annotations + +From: Bart Van Assche + +[ Upstream commit 3dcef70e41ab13483803c536ddea8d5f1803ee25 ] + +The ww_acquire_done() call is optional. Reflect this in the annotations of +ww_acquire_done(). + +Fixes: 47907461e4f6 ("locking/ww_mutex: Support Clang's context analysis") +Signed-off-by: Bart Van Assche +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Maarten Lankhorst +Acked-by: Marco Elver +Link: https://patch.msgid.link/20260225183244.4035378-4-bvanassche@acm.org +Signed-off-by: Sasha Levin +--- + include/linux/ww_mutex.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/ww_mutex.h b/include/linux/ww_mutex.h +index 85b1fff02fde9..0c95ead5a2977 100644 +--- a/include/linux/ww_mutex.h ++++ b/include/linux/ww_mutex.h +@@ -181,7 +181,7 @@ static inline void ww_acquire_init(struct ww_acquire_ctx *ctx, + * data structures. + */ + static inline void ww_acquire_done(struct ww_acquire_ctx *ctx) +- __releases(ctx) __acquires_shared(ctx) __no_context_analysis ++ __must_hold(ctx) + { + #ifdef DEBUG_WW_MUTEXES + lockdep_assert_held(ctx); +@@ -199,7 +199,7 @@ static inline void ww_acquire_done(struct ww_acquire_ctx *ctx) + * mutexes have been released with ww_mutex_unlock. + */ + static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx) +- __releases_shared(ctx) __no_context_analysis ++ __releases(ctx) __no_context_analysis + { + #ifdef CONFIG_DEBUG_LOCK_ALLOC + mutex_release(&ctx->first_lock_dep_map, _THIS_IP_); +-- +2.53.0 + diff --git a/queue-7.0/x86-irqflags-preemptively-move-include-paravirt.h-di.patch b/queue-7.0/x86-irqflags-preemptively-move-include-paravirt.h-di.patch new file mode 100644 index 0000000000..7b187b2dcd --- /dev/null +++ b/queue-7.0/x86-irqflags-preemptively-move-include-paravirt.h-di.patch @@ -0,0 +1,62 @@ +From fdd65ac938db728f493e7e77be1ed7ad8ce915f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Jan 2026 19:26:27 +0100 +Subject: x86/irqflags: Preemptively move include paravirt.h directive where it + belongs + +From: Juergen Gross + +[ Upstream commit 36c1eb9531e0c9bdcb3494142123f1c1e128367b ] + +Commit + + 22cc5ca5de52 ("x86/paravirt: Move halt paravirt calls under CONFIG_PARAVIRT") + +moved some paravirt hooks from the CONFIG_PARAVIRT_XXL umbrella to +CONFIG_PARAVIRT, but missed to move the associated "#include " +in irqflags.h from CONFIG_PARAVIRT_XXL to CONFIG_PARAVIRT. + +This hasn't resulted in build failures yet, as all use cases of irqflags.h had +paravirt.h included via other header files, even without CONFIG_PARAVIRT_XXL +being set. + +In order to allow changing those other header files, e.g. by no longer +including paravirt.h, fix irqflags.h by moving inclusion of paravirt.h under +the CONFIG_PARAVIRT umbrella. + + [ bp: Massage commit message. ] + +Fixes: 22cc5ca5de52 ("x86/paravirt: Move halt paravirt calls under CONFIG_PARAVIRT") +Closes: https://lore.kernel.org/oe-kbuild-all/202601152203.plJOoOEF-lkp@intel.com/ +Reported-by: kernel test robot +Signed-off-by: Juergen Gross +Signed-off-by: Borislav Petkov (AMD) +Signed-off-by: Ingo Molnar +Link: https://patch.msgid.link/20260119182632.596369-2-jgross@suse.com +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/irqflags.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h +index 462754b0bf8ac..6f25de05ed58f 100644 +--- a/arch/x86/include/asm/irqflags.h ++++ b/arch/x86/include/asm/irqflags.h +@@ -96,11 +96,11 @@ static __always_inline void halt(void) + native_halt(); + } + #endif /* __ASSEMBLER__ */ ++#else ++#include + #endif /* CONFIG_PARAVIRT */ + +-#ifdef CONFIG_PARAVIRT_XXL +-#include +-#else ++#ifndef CONFIG_PARAVIRT_XXL + #ifndef __ASSEMBLER__ + #include + +-- +2.53.0 + diff --git a/queue-7.0/x86-tdx-fix-the-typo-in-tdx_attr_migrtable.patch b/queue-7.0/x86-tdx-fix-the-typo-in-tdx_attr_migrtable.patch new file mode 100644 index 0000000000..16326c169e --- /dev/null +++ b/queue-7.0/x86-tdx-fix-the-typo-in-tdx_attr_migrtable.patch @@ -0,0 +1,67 @@ +From cb49c80937d0ce00042eb65fb04b19ef639f1842 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Mar 2026 11:03:32 +0800 +Subject: x86/tdx: Fix the typo in TDX_ATTR_MIGRTABLE + +From: Xiaoyao Li + +[ Upstream commit 3aecb2e7b948400354399b26f3f1653bd2c1bae0 ] + +The TD scoped TDCS attributes are defined by bit positions. In the guest +side of the TDX code, the 'tdx_attributes' string array holds pretty +print names for these attributes, which are generated via macros and +defines. Today these pretty print names are only used to print the +attribute names to dmesg. + +Unfortunately there is a typo in the define for the migratable bit. +Change the defines TDX_ATTR_MIGRTABLE* to TDX_ATTR_MIGRATABLE*. Update +the sole user, the tdx_attributes array, to use the fixed name. + +Since these defines control the string printed to dmesg, the change is +user visible. But the risk of breakage is almost zero since it is not +exposed in any interface expected to be consumed programmatically. + +Fixes: 564ea84c8c14 ("x86/tdx: Dump attributes and TD_CTLS on boot") +Signed-off-by: Xiaoyao Li +Signed-off-by: Dave Hansen +Reviewed-by: Kirill A. Shutemov +Reviewed-by: Kai Huang +Acked-by: Sean Christopherson +Link: https://patch.msgid.link/20260303030335.766779-2-xiaoyao.li@intel.com +Signed-off-by: Sasha Levin +--- + arch/x86/coco/tdx/debug.c | 2 +- + arch/x86/include/asm/shared/tdx.h | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/x86/coco/tdx/debug.c b/arch/x86/coco/tdx/debug.c +index cef847c8bb67f..28990c2ab0a14 100644 +--- a/arch/x86/coco/tdx/debug.c ++++ b/arch/x86/coco/tdx/debug.c +@@ -17,7 +17,7 @@ static __initdata const char *tdx_attributes[] = { + DEF_TDX_ATTR_NAME(ICSSD), + DEF_TDX_ATTR_NAME(LASS), + DEF_TDX_ATTR_NAME(SEPT_VE_DISABLE), +- DEF_TDX_ATTR_NAME(MIGRTABLE), ++ DEF_TDX_ATTR_NAME(MIGRATABLE), + DEF_TDX_ATTR_NAME(PKS), + DEF_TDX_ATTR_NAME(KL), + DEF_TDX_ATTR_NAME(TPA), +diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h +index 8bc074c8d7c6a..11f3cf30b1ac8 100644 +--- a/arch/x86/include/asm/shared/tdx.h ++++ b/arch/x86/include/asm/shared/tdx.h +@@ -35,8 +35,8 @@ + #define TDX_ATTR_LASS BIT_ULL(TDX_ATTR_LASS_BIT) + #define TDX_ATTR_SEPT_VE_DISABLE_BIT 28 + #define TDX_ATTR_SEPT_VE_DISABLE BIT_ULL(TDX_ATTR_SEPT_VE_DISABLE_BIT) +-#define TDX_ATTR_MIGRTABLE_BIT 29 +-#define TDX_ATTR_MIGRTABLE BIT_ULL(TDX_ATTR_MIGRTABLE_BIT) ++#define TDX_ATTR_MIGRATABLE_BIT 29 ++#define TDX_ATTR_MIGRATABLE BIT_ULL(TDX_ATTR_MIGRATABLE_BIT) + #define TDX_ATTR_PKS_BIT 30 + #define TDX_ATTR_PKS BIT_ULL(TDX_ATTR_PKS_BIT) + #define TDX_ATTR_KL_BIT 31 +-- +2.53.0 + diff --git a/queue-7.0/x86-um-fix-vdso-installation.patch b/queue-7.0/x86-um-fix-vdso-installation.patch new file mode 100644 index 0000000000..06129a9d60 --- /dev/null +++ b/queue-7.0/x86-um-fix-vdso-installation.patch @@ -0,0 +1,57 @@ +From e720a14b5e11663d80b40116c8ea5a6c702a1a72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Mar 2026 22:03:26 +0100 +Subject: x86/um: fix vDSO installation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit d1895c15fc7d90a615bc8c455feb02acaf08ef1e ] + +The generic vDSO installation logic used by 'make vdso_install' requires +that $(vdso-install-y) is defined by the top-level architecture Makefile +and that it contains a path relative to the root of the tree. +For UML neither of these is satisfied. + +Move the definition of $(vdso-install-y) to a place which is included by +the arch/um/Makefile and use the full relative path. + +Fixes: f1c2bb8b9964 ("um: implement a x86_64 vDSO") +Signed-off-by: Thomas Weißschuh +Link: https://patch.msgid.link/20260318-um-vdso-install-v1-1-26a4ca5c4210@weissschuh.net +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + arch/x86/Makefile.um | 2 ++ + arch/x86/um/vdso/Makefile | 2 -- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/Makefile.um b/arch/x86/Makefile.um +index c86cbd9cbba38..19c13afa474e9 100644 +--- a/arch/x86/Makefile.um ++++ b/arch/x86/Makefile.um +@@ -60,4 +60,6 @@ ELF_FORMAT := elf64-x86-64 + LINK-$(CONFIG_LD_SCRIPT_DYN_RPATH) += -Wl,-rpath,/lib64 + LINK-y += -m64 + ++vdso-install-y += arch/x86/um/vdso/vdso.so.dbg ++ + endif +diff --git a/arch/x86/um/vdso/Makefile b/arch/x86/um/vdso/Makefile +index 8a7c8b37cb6eb..7664cbedbe30f 100644 +--- a/arch/x86/um/vdso/Makefile ++++ b/arch/x86/um/vdso/Makefile +@@ -3,8 +3,6 @@ + # Building vDSO images for x86. + # + +-vdso-install-y += vdso.so +- + # files to link into the vdso + vobjs-y := vdso-note.o um_vdso.o + +-- +2.53.0 + diff --git a/queue-7.0/x86-vdso-clean-up-remnants-of-vdso32_note_mask.patch b/queue-7.0/x86-vdso-clean-up-remnants-of-vdso32_note_mask.patch new file mode 100644 index 0000000000..5d9f2418fb --- /dev/null +++ b/queue-7.0/x86-vdso-clean-up-remnants-of-vdso32_note_mask.patch @@ -0,0 +1,54 @@ +From 0f328ae0683d88d7f9ef67a96b9d13dc05f1b799 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Mar 2026 14:07:55 +0200 +Subject: x86/vdso: Clean up remnants of VDSO32_NOTE_MASK +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Weißschuh + +[ Upstream commit 6517f293b2c6774d21b6e7e26a55fae60c6ec4cf ] + +VDSO32_NOTE_MASK is not used or provided anymore, remove it. + +Fixes: a13f2ef168cb ("x86/xen: remove 32-bit Xen PV guest support") +Signed-off-by: Thomas Weißschuh +Signed-off-by: Ingo Molnar +Cc: H. Peter Anvin +Cc: Boris Ostrovsky +Cc: Juergen Gross +Link: https://patch.msgid.link/20260330-vdso-x86-vdso32_note_mask-v1-1-2f5c473327bf@linutronix.de +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/vdso.h | 1 - + arch/x86/tools/vdso2c.c | 1 - + 2 files changed, 2 deletions(-) + +diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h +index e8afbe9faa5b9..f2d49212ae902 100644 +--- a/arch/x86/include/asm/vdso.h ++++ b/arch/x86/include/asm/vdso.h +@@ -18,7 +18,6 @@ struct vdso_image { + unsigned long extable_base, extable_len; + const void *extable; + +- long sym_VDSO32_NOTE_MASK; + long sym___kernel_sigreturn; + long sym___kernel_rt_sigreturn; + long sym___kernel_vsyscall; +diff --git a/arch/x86/tools/vdso2c.c b/arch/x86/tools/vdso2c.c +index f84e8f8fa5fe6..b8a555763f437 100644 +--- a/arch/x86/tools/vdso2c.c ++++ b/arch/x86/tools/vdso2c.c +@@ -75,7 +75,6 @@ struct vdso_sym { + }; + + struct vdso_sym required_syms[] = { +- {"VDSO32_NOTE_MASK", true}, + {"__kernel_vsyscall", true}, + {"__kernel_sigreturn", true}, + {"__kernel_rt_sigreturn", true}, +-- +2.53.0 + diff --git a/queue-7.0/zram-do-not-permit-params-change-after-init.patch b/queue-7.0/zram-do-not-permit-params-change-after-init.patch new file mode 100644 index 0000000000..5cd33724ed --- /dev/null +++ b/queue-7.0/zram-do-not-permit-params-change-after-init.patch @@ -0,0 +1,69 @@ +From 271bd4fff6b7ceb18c6d36b2792ac93c7cedc264 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Mar 2026 17:42:44 +0900 +Subject: zram: do not permit params change after init + +From: Sergey Senozhatsky + +[ Upstream commit 241f9005b1c81c2637eef2c836a03c83b4f3eeb9 ] + +Patch series "zram: recompression cleanups and tweaks", v2. + +This series is a somewhat random mix of fixups, recompression cleanups and +improvements partly based on internal conversations. A few patches in the +series remove unexpected or confusing behaviour, e.g. auto correction of +bad priority= param for recompression, which should have always been just +an error. Then it also removes "chain recompression" which has a tricky, +unexpected and confusing behaviour at times. We also unify and harden the +handling of algo/priority params. There is also an addition of missing +device lock in algorithm_params_store() which previously permitted +modification of algo params while the device is active. + +This patch (of 6): + +First, algorithm_params_store(), like any sysfs handler, should grab +device lock. + +Second, like any write() sysfs handler, it should grab device lock in +exclusive mode. + +Third, it should not permit change of algos' parameters after device init, +as this doesn't make sense - we cannot compress with one C/D dict and then +just change C/D dict to a different one, for example. + +Another thing to notice is that algorithm_params_store() accesses device's +->comp_algs for algo priority lookup, which should be protected by device +lock in exclusive mode in general. + +Link: https://lkml.kernel.org/r/20260311084312.1766036-1-senozhatsky@chromium.org +Link: https://lkml.kernel.org/r/20260311084312.1766036-2-senozhatsky@chromium.org +Fixes: 4eac932103a5 ("zram: introduce algorithm_params device attribute") +Signed-off-by: Sergey Senozhatsky +Acked-by: Brian Geffon +Cc: gao xu +Cc: Jens Axboe +Cc: Minchan Kim +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +--- + drivers/block/zram/zram_drv.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +index 85943da0cdca8..aaaef8dd82538 100644 +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -1748,6 +1748,10 @@ static ssize_t algorithm_params_store(struct device *dev, + } + } + ++ guard(rwsem_write)(&zram->dev_lock); ++ if (init_done(zram)) ++ return -EBUSY; ++ + /* Lookup priority by algorithm name */ + if (algo) { + s32 p; +-- +2.53.0 +